diff --git a/.gitignore b/.gitignore
index 61d970a274b8dc1a573bf8fd31083ab984197bff..1dc24183ad30092742a351bd094b4ae5573052be 100644
--- a/.gitignore
+++ b/.gitignore
@@ -47,3 +47,4 @@ atlassian*
 /var/*
 !/var/.htaccess
 /vendor
+!/vendor/.htaccess
diff --git a/.htaccess b/.htaccess
index bef5869dd2fdf6a38d9769fee0c8e7ab8d683a2d..13564585ac2274e074728c844aa119b8df9d61a6 100644
--- a/.htaccess
+++ b/.htaccess
@@ -171,13 +171,83 @@
 </IfModule>
 
 ###########################################
-## Deny access to release notes to prevent disclosure of the installed Magento version
+## Deny access to root files to hide sensitive application information
+    RedirectMatch 404 /\.git
 
-    <Files RELEASE_NOTES.txt>
-        Order allow,deny
-        Deny from all
+    <Files composer.json>
+        order allow,deny
+        deny from all
     </Files>
-############################################
+    <Files composer.lock>
+        order allow,deny
+        deny from all
+    </Files>
+    <Files .gitignore>
+        order allow,deny
+        deny from all
+    </Files>
+    <Files .htaccess>
+        order allow,deny
+        deny from all
+    </Files>
+    <Files .htaccess.sample>
+        order allow,deny
+        deny from all
+    </Files>
+    <Files .php_cs>
+        order allow,deny
+        deny from all
+    </Files>
+    <Files .travis.yml>
+        order allow,deny
+        deny from all
+    </Files>
+    <Files CHANGELOG.md>
+        order allow,deny
+        deny from all
+    </Files>
+    <Files CONTRIBUTING.md>
+        order allow,deny
+        deny from all
+    </Files>
+    <Files CONTRIBUTOR_LICENSE_AGREEMENT.html>
+        order allow,deny
+        deny from all
+    </Files>
+    <Files COPYING.txt>
+        order allow,deny
+        deny from all
+    </Files>
+    <Files Gruntfile.js>
+        order allow,deny
+        deny from all
+    </Files>
+    <Files LICENSE.txt>
+        order allow,deny
+        deny from all
+    </Files>
+    <Files LICENSE_AFL.txt>
+        order allow,deny
+        deny from all
+    </Files>
+    <Files nginx.conf.sample>
+        order allow,deny
+        deny from all
+    </Files>
+    <Files package.json>
+        order allow,deny
+        deny from all
+    </Files>
+    <Files php.ini.sample>
+        order allow,deny
+        deny from all
+    </Files>
+    <Files README.md>
+        order allow,deny
+        deny from all
+    </Files>
+
+################################
 ## If running in cluster environment, uncomment this
 ## http://developer.yahoo.com/performance/rules.html#etags
 
diff --git a/.htaccess.sample b/.htaccess.sample
index 133ce7de2c59badd5df4a159bb921e8a99f05eb7..891dad19d642b5f958c9c33c71476dd4d39247c8 100644
--- a/.htaccess.sample
+++ b/.htaccess.sample
@@ -36,7 +36,7 @@
 ############################################
 ## adjust memory limit
 
-    php_value memory_limit 256M
+    php_value memory_limit 768M
     php_value max_execution_time 18000
 
 ############################################
@@ -65,13 +65,6 @@
     SecFilterScanPOST Off
 </IfModule>
 
-<IfModule mod_headers.c>
-############################################
-## prevent clickjacking
-
-    Header set X-Frame-Options SAMEORIGIN
-</IfModule>
-
 <IfModule mod_deflate.c>
 
 ############################################
@@ -136,9 +129,11 @@
     RewriteRule .* - [L,R=405]
 
 ############################################
-## always send 404 on missing files in these folders
+## redirect for mobile user agents
 
-    RewriteCond %{REQUEST_URI} !^/pub/(media|js)/
+    #RewriteCond %{REQUEST_URI} !^/mobiledirectoryhere/.*$
+    #RewriteCond %{HTTP_USER_AGENT} "android|blackberry|ipad|iphone|ipod|iemobile|opera mobile|palmos|webos|googlebot-mobile" [NC]
+    #RewriteRule ^(.*)$ /mobiledirectoryhere/ [L,R=302]
 
 ############################################
 ## never rewrite for existing files, directories and links
@@ -175,16 +170,84 @@
 </IfModule>
 
 ###########################################
-## Deny access to release notes to prevent disclosure of the installed Magento version
+## Deny access to root files to hide sensitive application information
+    RedirectMatch 404 /\.git
 
-    <Files RELEASE_NOTES.txt>
-        Order allow,deny
-        Deny from all
+    <Files composer.json>
+        order allow,deny
+        deny from all
+    </Files>
+    <Files composer.lock>
+        order allow,deny
+        deny from all
+    </Files>
+    <Files .gitignore>
+        order allow,deny
+        deny from all
+    </Files>
+    <Files .htaccess>
+        order allow,deny
+        deny from all
+    </Files>
+    <Files .htaccess.sample>
+        order allow,deny
+        deny from all
+    </Files>
+    <Files .php_cs>
+        order allow,deny
+        deny from all
+    </Files>
+    <Files .travis.yml>
+        order allow,deny
+        deny from all
+    </Files>
+    <Files CHANGELOG.md>
+        order allow,deny
+        deny from all
+    </Files>
+    <Files CONTRIBUTING.md>
+        order allow,deny
+        deny from all
+    </Files>
+    <Files CONTRIBUTOR_LICENSE_AGREEMENT.html>
+        order allow,deny
+        deny from all
+    </Files>
+    <Files COPYING.txt>
+        order allow,deny
+        deny from all
+    </Files>
+    <Files Gruntfile.js>
+        order allow,deny
+        deny from all
+    </Files>
+    <Files LICENSE.txt>
+        order allow,deny
+        deny from all
+    </Files>
+    <Files LICENSE_AFL.txt>
+        order allow,deny
+        deny from all
+    </Files>
+    <Files nginx.conf.sample>
+        order allow,deny
+        deny from all
+    </Files>
+    <Files package.json>
+        order allow,deny
+        deny from all
+    </Files>
+    <Files php.ini.sample>
+        order allow,deny
+        deny from all
+    </Files>
+    <Files README.md>
+        order allow,deny
+        deny from all
     </Files>
 
-############################################
+################################
 ## If running in cluster environment, uncomment this
 ## http://developer.yahoo.com/performance/rules.html#etags
 
     #FileETag none
-
diff --git a/app/code/Magento/Authorizenet/Model/Authorizenet.php b/app/code/Magento/Authorizenet/Model/Authorizenet.php
index 745d3b048125514eaa0c5f8965da0ef2ad98642c..f7ec2778ad5054815043c0608317690baff2845d 100644
--- a/app/code/Magento/Authorizenet/Model/Authorizenet.php
+++ b/app/code/Magento/Authorizenet/Model/Authorizenet.php
@@ -5,6 +5,8 @@
  */
 namespace Magento\Authorizenet\Model;
 
+use Magento\Payment\Model\Method\Logger;
+
 /**
  * @SuppressWarnings(PHPMD.TooManyFields)
  * @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
@@ -54,6 +56,8 @@ abstract class Authorizenet extends \Magento\Payment\Model\Method\Cc
 
     const RESPONSE_REASON_CODE_PENDING_REVIEW_DECLINED = 254;
 
+    const PAYMENT_UPDATE_STATUS_CODE_SUCCESS = 'Ok';
+
     /**
      * Transaction fraud state key
      */
@@ -95,6 +99,11 @@ abstract class Authorizenet extends \Magento\Payment\Model\Method\Cc
      */
     protected $transactionDetails = [];
 
+    /**
+     * {@inheritdoc}
+     */
+    protected $_debugReplacePrivateDataKeys = ['merchantAuthentication', 'x_login'];
+
     /**
      * @param \Magento\Framework\Model\Context $context
      * @param \Magento\Framework\Registry $registry
@@ -364,11 +373,11 @@ abstract class Authorizenet extends \Magento\Payment\Model\Method\Cc
      */
     protected function postRequest(\Magento\Authorizenet\Model\Request $request)
     {
-        $debugData = ['request' => $request->getData()];
         $result = $this->responseFactory->create();
         $client = new \Magento\Framework\HTTP\ZendClient();
-        $uri = $this->getConfigData('cgi_url');
-        $client->setUri($uri ? $uri : self::CGI_URL);
+        $url = $this->getConfigData('cgi_url') ?: self::CGI_URL;
+        $debugData = ['url' => $url, 'request' => $request->getData()];
+        $client->setUri($url);
         $client->setConfig(['maxredirects' => 0, 'timeout' => 30]);
 
         foreach ($request->getData() as $key => $value) {
@@ -381,21 +390,21 @@ abstract class Authorizenet extends \Magento\Payment\Model\Method\Cc
 
         try {
             $response = $client->request();
+            $responseBody = $response->getBody();
+            $debugData['response'] = $responseBody;
         } catch (\Exception $e) {
             $result->setXResponseCode(-1)
                 ->setXResponseReasonCode($e->getCode())
                 ->setXResponseReasonText($e->getMessage());
 
-            $debugData['result'] = $result->getData();
-            $this->_debug($debugData);
             throw new \Magento\Framework\Exception\LocalizedException(
                 $this->dataHelper->wrapGatewayError($e->getMessage())
             );
+        } finally {
+            $this->_debug($debugData);
         }
 
-        $responseBody = $response->getBody();
         $r = explode(self::RESPONSE_DELIM_CHAR, $responseBody);
-
         if ($r) {
             $result->setXResponseCode((int)str_replace('"', '', $r[0]))
                 ->setXResponseReasonCode((int)str_replace('"', '', $r[2]))
@@ -413,10 +422,6 @@ abstract class Authorizenet extends \Magento\Payment\Model\Method\Cc
                 __('Something went wrong in the payment gateway.')
             );
         }
-
-        $debugData['result'] = $result->getData();
-        $this->_debug($debugData);
-
         return $result;
     }
 
@@ -473,24 +478,35 @@ abstract class Authorizenet extends \Magento\Payment\Model\Method\Cc
         );
 
         $client = new \Magento\Framework\HTTP\ZendClient();
-        $uri = $this->getConfigData('cgi_url_td');
-        $client->setUri($uri ? $uri : self::CGI_URL_TD);
+        $url = $this->getConfigData('cgi_url_td') ?: self::CGI_URL_TD;
+        $client->setUri($url);
         $client->setConfig(['timeout' => 45]);
         $client->setHeaders(['Content-Type: text/xml']);
         $client->setMethod(\Zend_Http_Client::POST);
         $client->setRawData($requestBody);
 
-        $debugData = ['request' => $requestBody];
+        $debugData = ['url' => $url, 'request' => $this->removePrivateDataFromXml($requestBody)];
 
         try {
             $responseBody = $client->request()->getBody();
-            $debugData['result'] = $responseBody;
-            $this->_debug($debugData);
+            $debugData['response'] = $responseBody;
             libxml_use_internal_errors(true);
             $responseXmlDocument = new \Magento\Framework\Simplexml\Element($responseBody);
             libxml_use_internal_errors(false);
         } catch (\Exception $e) {
-            throw new \Magento\Framework\Exception\LocalizedException(__('Payment updating error.'));
+            throw new \Magento\Framework\Exception\LocalizedException(
+                __('Unable to get transaction details. Try again later.')
+            );
+        } finally {
+            $this->_debug($debugData);
+        }
+
+        if (!isset($responseXmlDocument->messages->resultCode)
+            || $responseXmlDocument->messages->resultCode != static::PAYMENT_UPDATE_STATUS_CODE_SUCCESS
+        ) {
+            throw new \Magento\Framework\Exception\LocalizedException(
+                __('Unable to get transaction details. Try again later.')
+            );
         }
 
         $this->transactionDetails[$transactionId] = $responseXmlDocument;
@@ -509,4 +525,20 @@ abstract class Authorizenet extends \Magento\Payment\Model\Method\Cc
             ? $this->transactionDetails[$transactionId]
             : $this->loadTransactionDetails($transactionId);
     }
+
+    /**
+     * Remove nodes with private data from XML string
+     *
+     * Uses values from $_debugReplacePrivateDataKeys property
+     *
+     * @param string $xml
+     * @return string
+     */
+    protected function removePrivateDataFromXml($xml)
+    {
+        foreach ($this->getDebugReplacePrivateDataKeys() as $key) {
+            $xml = preg_replace(sprintf('~(?<=<%s>).*?(?=</%s>)~', $key, $key), Logger::DEBUG_KEYS_MASK, $xml);
+        }
+        return $xml;
+    }
 }
diff --git a/app/code/Magento/Authorizenet/Model/Directpost.php b/app/code/Magento/Authorizenet/Model/Directpost.php
index 71e81e1727e8b24259510278b2ae6bb1e737293b..7b8c6f10df3ae465556228c26c819a8c46cddc28 100644
--- a/app/code/Magento/Authorizenet/Model/Directpost.php
+++ b/app/code/Magento/Authorizenet/Model/Directpost.php
@@ -726,17 +726,21 @@ class Directpost extends \Magento\Authorizenet\Model\Authorizenet implements Tra
      */
     protected function processPaymentFraudStatus(\Magento\Sales\Model\Order\Payment $payment)
     {
-        $fraudDetailsResponse = $payment->getMethodInstance()
-            ->fetchTransactionFraudDetails($this->getResponse()->getXTransId());
-        $fraudData = $fraudDetailsResponse->getData();
+        try {
+            $fraudDetailsResponse = $payment->getMethodInstance()
+                ->fetchTransactionFraudDetails($this->getResponse()->getXTransId());
+            $fraudData = $fraudDetailsResponse->getData();
 
-        if (empty($fraudData)) {
-            $payment->setIsFraudDetected(false);
-            return $this;
-        }
+            if (empty($fraudData)) {
+                $payment->setIsFraudDetected(false);
+                return $this;
+            }
 
-        $payment->setIsFraudDetected(true);
-        $payment->setAdditionalInformation('fraud_details', $fraudData);
+            $payment->setIsFraudDetected(true);
+            $payment->setAdditionalInformation('fraud_details', $fraudData);
+        } catch (\Exception $e) {
+            //this request is optional
+        }
 
         return $this;
     }
@@ -749,23 +753,27 @@ class Directpost extends \Magento\Authorizenet\Model\Authorizenet implements Tra
      */
     protected function addStatusComment(\Magento\Sales\Model\Order\Payment $payment)
     {
-        $transactionId = $this->getResponse()->getXTransId();
-        $data = $payment->getMethodInstance()->getTransactionDetails($transactionId);
-        $transactionStatus = (string)$data->transaction->transactionStatus;
-        $fdsFilterAction = (string)$data->transaction->FDSFilterAction;
-
-        if ($payment->getIsTransactionPending()) {
-            $message = 'Amount of %1 is pending approval on the gateway.<br/>'
-                . 'Transaction "%2" status is "%3".<br/>'
-                . 'Transaction FDS Filter Action is "%4"';
-            $message = __(
-                $message,
-                $payment->getOrder()->getBaseCurrency()->formatTxt($this->getResponse()->getXAmount()),
-                $transactionId,
-                $this->dataHelper->getTransactionStatusLabel($transactionStatus),
-                $this->dataHelper->getFdsFilterActionLabel($fdsFilterAction)
-            );
-            $payment->getOrder()->addStatusHistoryComment($message);
+        try {
+            $transactionId = $this->getResponse()->getXTransId();
+            $data = $payment->getMethodInstance()->getTransactionDetails($transactionId);
+            $transactionStatus = (string)$data->transaction->transactionStatus;
+            $fdsFilterAction = (string)$data->transaction->FDSFilterAction;
+
+            if ($payment->getIsTransactionPending()) {
+                $message = 'Amount of %1 is pending approval on the gateway.<br/>'
+                    . 'Transaction "%2" status is "%3".<br/>'
+                    . 'Transaction FDS Filter Action is "%4"';
+                $message = __(
+                    $message,
+                    $payment->getOrder()->getBaseCurrency()->formatTxt($this->getResponse()->getXAmount()),
+                    $transactionId,
+                    $this->dataHelper->getTransactionStatusLabel($transactionStatus),
+                    $this->dataHelper->getFdsFilterActionLabel($fdsFilterAction)
+                );
+                $payment->getOrder()->addStatusHistoryComment($message);
+            }
+        } catch (\Exception $e) {
+            //this request is optional
         }
         return $this;
     }
diff --git a/app/code/Magento/Backend/Block/Widget/Grid.php b/app/code/Magento/Backend/Block/Widget/Grid.php
index ee8b36cdea847789cdde5e7876e7d5609a586848..66bc193719784b684d6b7b212790aa49686b831e 100644
--- a/app/code/Magento/Backend/Block/Widget/Grid.php
+++ b/app/code/Magento/Backend/Block/Widget/Grid.php
@@ -760,7 +760,7 @@ class Grid extends \Magento\Backend\Block\Widget
      */
     public function getJsObjectName()
     {
-        return $this->getId() . 'JsObject';
+        return preg_replace("~[^a-z0-9_]*~i", '', $this->getId()) . 'JsObject';
     }
 
     /**
diff --git a/app/code/Magento/Backend/Block/Widget/Grid/Column/Filter/AbstractFilter.php b/app/code/Magento/Backend/Block/Widget/Grid/Column/Filter/AbstractFilter.php
index 0a0e612eab9ced6d7cdcaa0715cc28a9f4b6f535..a512da3522c4229e7b41114a2559879f4f5993a7 100644
--- a/app/code/Magento/Backend/Block/Widget/Grid/Column/Filter/AbstractFilter.php
+++ b/app/code/Magento/Backend/Block/Widget/Grid/Column/Filter/AbstractFilter.php
@@ -67,7 +67,7 @@ class AbstractFilter extends \Magento\Backend\Block\AbstractBlock implements
      */
     protected function _getHtmlName()
     {
-        return $this->getColumn()->getId();
+        return $this->escapeHtml($this->getColumn()->getId());
     }
 
     /**
@@ -77,7 +77,7 @@ class AbstractFilter extends \Magento\Backend\Block\AbstractBlock implements
      */
     protected function _getHtmlId()
     {
-        return $this->getColumn()->getHtmlId();
+        return $this->escapeHtml($this->getColumn()->getHtmlId());
     }
 
     /**
@@ -88,7 +88,7 @@ class AbstractFilter extends \Magento\Backend\Block\AbstractBlock implements
      */
     public function getEscapedValue($index = null)
     {
-        return htmlspecialchars((string)$this->getValue($index));
+        return $this->escapeHtml((string)$this->getValue($index));
     }
 
     /**
diff --git a/app/code/Magento/Backend/Test/Unit/Block/Widget/Grid/Column/Filter/TextTest.php b/app/code/Magento/Backend/Test/Unit/Block/Widget/Grid/Column/Filter/TextTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..a59b23f8d3ca722854983f16833b773dd432f87a
--- /dev/null
+++ b/app/code/Magento/Backend/Test/Unit/Block/Widget/Grid/Column/Filter/TextTest.php
@@ -0,0 +1,68 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Backend\Test\Unit\Block\Widget\Grid\Column\Filter;
+
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper;
+
+class TextTest extends \PHPUnit_Framework_TestCase
+{
+    /** @var \Magento\Backend\Block\Widget\Grid\Column\Filter\Text*/
+    protected $block;
+
+    /** @var ObjectManagerHelper */
+    protected $objectManagerHelper;
+
+    /** @var \Magento\Backend\Block\Context|\PHPUnit_Framework_MockObject_MockObject */
+    protected $context;
+
+    /** @var \Magento\Framework\DB\Helper|\PHPUnit_Framework_MockObject_MockObject */
+    protected $helper;
+
+    /** @var \Magento\Framework\Escaper|\PHPUnit_Framework_MockObject_MockObject */
+    protected $escaper;
+
+    protected function setUp()
+    {
+        $this->context = $this->getMockBuilder('Magento\Backend\Block\Context')
+            ->setMethods(['getEscaper'])
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->escaper = $this->getMock('Magento\Framework\Escaper', ['escapeHtml'], [], '', false);
+        $this->helper = $this->getMock('Magento\Framework\DB\Helper', [], [], '', false);
+
+        $this->context->expects($this->once())->method('getEscaper')->willReturn($this->escaper);
+
+        $this->objectManagerHelper = new ObjectManagerHelper($this);
+        $this->block = $this->objectManagerHelper->getObject(
+            'Magento\Backend\Block\Widget\Grid\Column\Filter\Text',
+            [
+                'context' => $this->context,
+                'resourceHelper' => $this->helper
+            ]
+        );
+    }
+
+    public function testGetHtml()
+    {
+        $resultHtml = '<input type="text" name="escapedHtml" ' .
+            'id="escapedHtml" value="escapedHtml" ' .
+            'class="input-text admin__control-text no-changes" data-ui-id="filter-escapedhtml"  />';
+
+        $column = $this->getMockBuilder('Magento\Backend\Block\Widget\Grid\Column')
+            ->setMethods(['getId', 'getHtmlId'])
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->block->setColumn($column);
+
+        $this->escaper->expects($this->any())->method('escapeHtml')->willReturn('escapedHtml');
+        $column->expects($this->any())->method('getId')->willReturn('id');
+        $column->expects($this->once())->method('getHtmlId')->willReturn('htmlId');
+
+        $this->assertEquals($resultHtml, $this->block->getHtml());
+    }
+}
diff --git a/app/code/Magento/Backend/view/adminhtml/templates/widget/grid.phtml b/app/code/Magento/Backend/view/adminhtml/templates/widget/grid.phtml
index 12dcacd1a035648d05e278c7da386e971d7686a6..6e32f5eed660512ef634b71aceb5443e08ee48a1 100644
--- a/app/code/Magento/Backend/view/adminhtml/templates/widget/grid.phtml
+++ b/app/code/Magento/Backend/view/adminhtml/templates/widget/grid.phtml
@@ -24,7 +24,7 @@ $numColumns = sizeof($block->getColumns());
 <?php if ($block->getCollection()): ?>
 
 <?php if ($block->canDisplayContainer()): ?>
-<div id="<?php /* @escapeNotVerified */ echo $block->getId() ?>" data-grid-id="<?php /* @escapeNotVerified */ echo $block->getId() ?>">
+<div id="<?php echo $block->escapeHtml($block->getId()) ?>" data-grid-id="<?php echo $block->escapeHtml($block->getId()) ?>">
 <?php else: ?>
 <?php echo $block->getLayout()->getMessagesBlock()->getGroupedHtml() ?>
 <?php endif; ?>
@@ -50,17 +50,17 @@ $numColumns = sizeof($block->getColumns());
                 <?php endif; ?>
                     <?php $countRecords = $block->getCollection()->getSize(); ?>
                     <div class="admin__control-support-text">
-                        <span id="<?php echo $block->getHtmlId() ?>-total-count" <?php /* @escapeNotVerified */ echo $block->getUiId('total-count') ?>>
+                        <span id="<?php echo $block->escapeHtml($block->getHtmlId()) ?>-total-count" <?php /* @escapeNotVerified */ echo $block->getUiId('total-count') ?>>
                             <?php /* @escapeNotVerified */ echo $countRecords ?>
                         </span>
                         <?php /* @escapeNotVerified */ echo __('records found') ?>
-                        <span id="<?php echo $block->getHtmlId() ?>_massaction-count"
+                        <span id="<?php echo $block->escapeHtml($block->getHtmlId()) ?>_massaction-count"
                               class="mass-select-info _empty"><strong data-role="counter">0</strong> <span><?php /* @escapeNotVerified */ echo __('selected') ?></span></span>
                     </div>
                 <?php if ($block->getPagerVisibility()): ?>
                     <div class="admin__data-grid-pager-wrap">
                         <select name="<?php /* @escapeNotVerified */ echo $block->getVarNameLimit() ?>"
-                                id="<?php echo $block->getHtmlId()?>_page-limit"
+                                id="<?php echo $block->escapeHtml($block->getHtmlId())?>_page-limit"
                                 onchange="<?php /* @escapeNotVerified */ echo $block->getJsObjectName() ?>.loadByElement(this)" <?php /* @escapeNotVerified */ echo $block->getUiId('per-page') ?>
                                 class="admin__control-select">
                             <option value="20"<?php if ($block->getCollection()->getPageSize() == 20): ?>
@@ -79,7 +79,7 @@ $numColumns = sizeof($block->getColumns());
                                 selected="selected"<?php endif; ?>>200
                             </option>
                         </select>
-                        <label for="<?php echo $block->getHtmlId()?>_page-limit"
+                        <label for="<?php echo $block->escapeHtml($block->getHtmlId())?>_page-limit"
                             class="admin__control-support-text"><?php /* @escapeNotVerified */ echo __('per page') ?></label>
                         <div class="admin__data-grid-pager">
                             <?php $_curPage = $block->getCollection()->getCurPage() ?>
@@ -96,13 +96,13 @@ $numColumns = sizeof($block->getColumns());
                             <?php endif; ?>
 
                             <input type="text"
-                                   id="<?php echo $block->getHtmlId()?>_page-current"
+                                   id="<?php echo $block->escapeHtml($block->getHtmlId())?>_page-current"
                                    name="<?php /* @escapeNotVerified */ echo $block->getVarNamePage() ?>"
                                    value="<?php /* @escapeNotVerified */ echo $_curPage ?>"
                                    class="admin__control-text"
                                    onkeypress="<?php /* @escapeNotVerified */ echo $block->getJsObjectName() ?>.inputPage(event, '<?php /* @escapeNotVerified */ echo $_lastPage ?>')" <?php /* @escapeNotVerified */ echo $block->getUiId('current-page') ?> />
 
-                            <label class="admin__control-support-text" for="<?php echo $block->getHtmlId()
+                            <label class="admin__control-support-text" for="<?php echo $block->escapeHtml($block->getHtmlId())
                             ?>_page-current">
                                 <?php /* @escapeNotVerified */ echo __('of %1', '<span>' . $block->getCollection()->getLastPageNumber() . '</span>') ?>
                             </label>
@@ -122,13 +122,13 @@ $numColumns = sizeof($block->getColumns());
         </div>
         <div class="admin__data-grid-wrap admin__data-grid-wrap-static">
         <?php if ($block->getGridCssClass()): ?>
-            <table class="<?php /* @escapeNotVerified */ echo $block->getGridCssClass() ?> data-grid" id="<?php /* @escapeNotVerified */ echo $block->getId() ?>_table">
+            <table class="<?php /* @escapeNotVerified */ echo $block->getGridCssClass() ?> data-grid" id="<?php echo $block->escapeHtml($block->getId()) ?>_table">
                 <!-- Rendering column set -->
                 <?php echo $block->getChildHtml('grid.columnSet'); ?>
             </table>
         <?php else: ?>
 
-            <table class="data-grid" id="<?php /* @escapeNotVerified */ echo $block->getId() ?>_table">
+            <table class="data-grid" id="<?php echo $block->escapeHtml($block->getId()) ?>_table">
                 <!-- Rendering column set -->
                 <?php echo $block->getChildHtml('grid.columnSet'); ?>
             </table>
@@ -161,7 +161,7 @@ $numColumns = sizeof($block->getColumns());
             registry.get('<?php /* @escapeNotVerified */ echo $block->getDependencyJsObject() ?>', function (<?php /* @escapeNotVerified */ echo $block->getDependencyJsObject() ?>) {
         <?php endif; ?>
 
-        <?php /* @escapeNotVerified */ echo $block->getJsObjectName() ?> = new varienGrid('<?php /* @escapeNotVerified */ echo $block->getId() ?>', '<?php /* @escapeNotVerified */ echo $block->getGridUrl() ?>', '<?php /* @escapeNotVerified */ echo $block->getVarNamePage() ?>', '<?php /* @escapeNotVerified */ echo $block->getVarNameSort() ?>', '<?php /* @escapeNotVerified */ echo $block->getVarNameDir() ?>', '<?php /* @escapeNotVerified */ echo $block->getVarNameFilter() ?>');
+        <?php /* @escapeNotVerified */ echo $block->getJsObjectName() ?> = new varienGrid('<?php echo $block->escapeHtml($block->getId()) ?>', '<?php /* @escapeNotVerified */ echo $block->getGridUrl() ?>', '<?php /* @escapeNotVerified */ echo $block->getVarNamePage() ?>', '<?php /* @escapeNotVerified */ echo $block->getVarNameSort() ?>', '<?php /* @escapeNotVerified */ echo $block->getVarNameDir() ?>', '<?php /* @escapeNotVerified */ echo $block->getVarNameFilter() ?>');
         <?php /* @escapeNotVerified */ echo $block->getJsObjectName() ?>.useAjax = <?php /* @escapeNotVerified */ echo $block->getUseAjax() ? 'true' : 'false' ?>;
         <?php if ($block->getRowClickCallback()): ?>
         <?php /* @escapeNotVerified */ echo $block->getJsObjectName() ?>.rowClickCallback = <?php /* @escapeNotVerified */ echo $block->getRowClickCallback() ?>;
diff --git a/app/code/Magento/Backend/view/adminhtml/templates/widget/grid/extended.phtml b/app/code/Magento/Backend/view/adminhtml/templates/widget/grid/extended.phtml
index 385a5a1393c16698ed543ce292d3e18c398ca8ec..ddd9fa5f2f18ae565d365c090d2ad2c8dd35f55a 100644
--- a/app/code/Magento/Backend/view/adminhtml/templates/widget/grid/extended.phtml
+++ b/app/code/Magento/Backend/view/adminhtml/templates/widget/grid/extended.phtml
@@ -26,7 +26,7 @@ $numColumns = sizeof($block->getColumns());
 <?php if ($block->getCollection()): ?>
     <?php if ($block->canDisplayContainer()): ?>
 
-    <div id="<?php /* @escapeNotVerified */ echo $block->getId() ?>" data-grid-id="<?php /* @escapeNotVerified */ echo $block->getId() ?>">
+    <div id="<?php echo $block->escapeHtml($block->getId()) ?>" data-grid-id="<?php echo $block->escapeHtml($block->getId()) ?>">
     <?php else: ?>
         <?php echo $block->getLayout()->getMessagesBlock()->getGroupedHtml() ?>
     <?php endif; ?>
@@ -41,8 +41,8 @@ $numColumns = sizeof($block->getColumns());
                 <div class="admin__data-grid-export">
                     <label
                         class="admin__control-support-text"
-                        for="<?php /* @escapeNotVerified */ echo $block->getId() ?>_export"><?php /* @escapeNotVerified */ echo __('Export to:') ?></label>
-                    <select name="<?php /* @escapeNotVerified */ echo $block->getId() ?>_export" id="<?php /* @escapeNotVerified */ echo $block->getId() ?>_export"
+                        for="<?php echo $block->escapeHtml($block->getId()) ?>_export"><?php /* @escapeNotVerified */ echo __('Export to:') ?></label>
+                    <select name="<?php echo $block->escapeHtml($block->getId()) ?>_export" id="<?php echo $block->escapeHtml($block->getId()) ?>_export"
                             class="admin__control-select">
                         <?php foreach ($block->getExportTypes() as $_type): ?>
                             <option value="<?php /* @escapeNotVerified */ echo $_type->getUrl() ?>"><?php /* @escapeNotVerified */ echo $_type->getLabel() ?></option>
@@ -61,18 +61,18 @@ $numColumns = sizeof($block->getColumns());
                 <?php endif; ?>
                 <?php $countRecords = $block->getCollection()->getSize(); ?>
                 <div class="admin__control-support-text">
-                        <span id="<?php echo $block->getHtmlId() ?>-total-count" <?php /* @escapeNotVerified */ echo $block->getUiId('total-count') ?>>
+                        <span id="<?php echo $block->escapeHtml($block->getHtmlId()) ?>-total-count" <?php /* @escapeNotVerified */ echo $block->getUiId('total-count') ?>>
                             <?php /* @escapeNotVerified */ echo $countRecords ?>
                         </span>
                     <?php /* @escapeNotVerified */ echo __('records found') ?>
-                    <span id="<?php echo $block->getHtmlId() ?>_massaction-count"
+                    <span id="<?php echo $block->escapeHtml($block->getHtmlId()) ?>_massaction-count"
                           class="mass-select-info _empty"><strong data-role="counter">0</strong> <span><?php /* @escapeNotVerified */ echo __('selected') ?></span></span>
                 </div>
 
             <?php if ($block->getPagerVisibility()): ?>
                 <div class="admin__data-grid-pager-wrap">
                     <select name="<?php /* @escapeNotVerified */ echo $block->getVarNameLimit() ?>"
-                            id="<?php echo $block->getHtmlId()?>_page-limit"
+                            id="<?php echo $block->escapeHTML($block->getHtmlId())?>_page-limit"
                             onchange="<?php /* @escapeNotVerified */ echo $block->getJsObjectName() ?>.loadByElement(this)"
                             class="admin__control-select">
                         <option value="20"<?php if ($block->getCollection()->getPageSize() == 20): ?>
@@ -91,7 +91,7 @@ $numColumns = sizeof($block->getColumns());
                             selected="selected"<?php endif; ?>>200
                         </option>
                     </select>
-                    <label for="<?php echo $block->getHtmlId()?><?php echo $block->getHtmlId()?>_page-limit"
+                    <label for="<?php echo $block->escapeHTML($block->getHtmlId())?><?php echo $block->escapeHTML($block->getHtmlId())?>_page-limit"
                         class="admin__control-support-text"><?php /* @escapeNotVerified */ echo __('per page') ?></label>
 
                     <div class="admin__data-grid-pager">
@@ -107,12 +107,12 @@ $numColumns = sizeof($block->getColumns());
                             <button type="button" class="action-previous disabled"><span><?php /* @escapeNotVerified */ echo __('Previous page') ?></span></button>
                         <?php endif; ?>
                         <input type="text"
-                               id="<?php echo $block->getHtmlId()?>_page-current"
+                               id="<?php echo $block->escapeHTML($block->getHtmlId())?>_page-current"
                                name="<?php /* @escapeNotVerified */ echo $block->getVarNamePage() ?>"
                                value="<?php /* @escapeNotVerified */ echo $_curPage ?>"
                                class="admin__control-text"
                                onkeypress="<?php /* @escapeNotVerified */ echo $block->getJsObjectName() ?>.inputPage(event, '<?php /* @escapeNotVerified */ echo $_lastPage ?>')" <?php /* @escapeNotVerified */ echo $block->getUiId('current-page') ?> />
-                        <label class="admin__control-support-text" for="<?php echo $block->getHtmlId()?>_page-current">
+                        <label class="admin__control-support-text" for="<?php echo $block->escapeHTML($block->getHtmlId())?>_page-current">
                             <?php /* @escapeNotVerified */ echo __('of %1', '<span>' . $block->getCollection()->getLastPageNumber() . '</span>') ?>
                         </label>
                         <?php if ($_curPage < $_lastPage): ?>
@@ -133,7 +133,7 @@ $numColumns = sizeof($block->getColumns());
     <?php endif; ?>
 
     <div class="admin__data-grid-wrap admin__data-grid-wrap-static">
-        <table class="data-grid" id="<?php /* @escapeNotVerified */ echo $block->getId() ?>_table">
+        <table class="data-grid" id="<?php echo $block->escapeHtml($block->getId()) ?>_table">
             <?php
             /* This part is commented to remove all <col> tags from the code. */
             /* foreach ($block->getColumns() as $_column): ?>
@@ -263,7 +263,7 @@ $numColumns = sizeof($block->getColumns());
         registry.get('<?php /* @escapeNotVerified */ echo $block->getDependencyJsObject() ?>', function (<?php /* @escapeNotVerified */ echo $block->getDependencyJsObject() ?>) {
     <?php endif; ?>
 
-    <?php /* @escapeNotVerified */ echo $block->getJsObjectName() ?> = new varienGrid('<?php /* @escapeNotVerified */ echo $block->getId() ?>', '<?php /* @escapeNotVerified */ echo $block->getGridUrl() ?>', '<?php /* @escapeNotVerified */ echo $block->getVarNamePage() ?>', '<?php /* @escapeNotVerified */ echo $block->getVarNameSort() ?>', '<?php /* @escapeNotVerified */ echo $block->getVarNameDir() ?>', '<?php /* @escapeNotVerified */ echo $block->getVarNameFilter() ?>');
+    <?php /* @escapeNotVerified */ echo $block->getJsObjectName() ?> = new varienGrid(<?php /* @noEscape */ echo $this->helper('Magento\Framework\Json\Helper\Data')->jsonEncode($block->getId()) ?>, '<?php /* @escapeNotVerified */ echo $block->getGridUrl() ?>', '<?php /* @escapeNotVerified */ echo $block->getVarNamePage() ?>', '<?php /* @escapeNotVerified */ echo $block->getVarNameSort() ?>', '<?php /* @escapeNotVerified */ echo $block->getVarNameDir() ?>', '<?php /* @escapeNotVerified */ echo $block->getVarNameFilter() ?>');
     <?php /* @escapeNotVerified */ echo $block->getJsObjectName() ?>.useAjax = '<?php /* @escapeNotVerified */ echo $block->getUseAjax() ?>';
     <?php if ($block->getRowClickCallback()): ?>
     <?php /* @escapeNotVerified */ echo $block->getJsObjectName() ?>.rowClickCallback = <?php /* @escapeNotVerified */ echo $block->getRowClickCallback() ?>;
diff --git a/app/code/Magento/Bundle/Controller/Adminhtml/Bundle/Selection/Grid.php b/app/code/Magento/Bundle/Controller/Adminhtml/Bundle/Selection/Grid.php
index 85ce181f5eb1957de3c5c205593d496931caf82e..684eb43e4ad6019b28243f9ef932f74d4e7f16e9 100644
--- a/app/code/Magento/Bundle/Controller/Adminhtml/Bundle/Selection/Grid.php
+++ b/app/code/Magento/Bundle/Controller/Adminhtml/Bundle/Selection/Grid.php
@@ -13,13 +13,16 @@ class Grid extends \Magento\Backend\App\Action
      */
     public function execute()
     {
+        $index = $this->getRequest()->getParam('index');
+        if (!preg_match('/^[a-z0-9_.]*$/i', $index)) {
+            throw new \InvalidArgumentException('Invalid parameter "index"');
+        }
+
         return $this->getResponse()->setBody(
             $this->_view->getLayout()->createBlock(
                 'Magento\Bundle\Block\Adminhtml\Catalog\Product\Edit\Tab\Bundle\Option\Search\Grid',
                 'adminhtml.catalog.product.edit.tab.bundle.option.search.grid'
-            )->setIndex(
-                $this->getRequest()->getParam('index')
-            )->toHtml()
+            )->setIndex($index)->toHtml()
         );
     }
 }
diff --git a/app/code/Magento/Bundle/Test/Unit/Controller/Adminhtml/Bundle/Selection/GridTest.php b/app/code/Magento/Bundle/Test/Unit/Controller/Adminhtml/Bundle/Selection/GridTest.php
index 267dade65be131b972fdaa5e9254603cc8ef9bc6..c0a7342f8249fe51452f5b762116455f814a9581 100644
--- a/app/code/Magento/Bundle/Test/Unit/Controller/Adminhtml/Bundle/Selection/GridTest.php
+++ b/app/code/Magento/Bundle/Test/Unit/Controller/Adminhtml/Bundle/Selection/GridTest.php
@@ -90,4 +90,15 @@ class GridTest extends \PHPUnit_Framework_TestCase
 
         $this->assertEquals($this->response, $this->controller->execute());
     }
+
+    /**
+     * @expectedException \InvalidArgumentException
+     * @expectedExceptionMessage Invalid parameter "index"
+     */
+    public function testExecuteWithException()
+    {
+        $this->request->expects($this->once())->method('getParam')->with('index')->willReturn('<index"');
+
+        $this->controller->execute();
+    }
 }
diff --git a/app/code/Magento/Bundle/view/frontend/templates/catalog/product/view/type/bundle/options.phtml b/app/code/Magento/Bundle/view/frontend/templates/catalog/product/view/type/bundle/options.phtml
index 40f152cf2581d7a3cd05841f0aca24eb1e7a4941..717bf12da25a03ac35628b16738660bfa929e344 100644
--- a/app/code/Magento/Bundle/view/frontend/templates/catalog/product/view/type/bundle/options.phtml
+++ b/app/code/Magento/Bundle/view/frontend/templates/catalog/product/view/type/bundle/options.phtml
@@ -25,7 +25,7 @@ $helper = $this->helper('Magento\Catalog\Helper\Output');
         }
     }
 </script>
-        <fieldset class="fieldset bundle options">
+        <fieldset class="fieldset fieldset-bundle-options">
             <legend id="customizeTitle" class="legend title">
                 <span><?php /* @escapeNotVerified */ echo __('Customize %1', $helper->productAttribute($product, $product->getName(), 'name')) ?></span>
             </legend><br />
diff --git a/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Tab/Inventory.php b/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Tab/Inventory.php
index 72ad16576f1ca238d01a068f5cf53be714755b30..5cf7b922ac980d1a20c5be02b284b946dc109d22 100644
--- a/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Tab/Inventory.php
+++ b/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Tab/Inventory.php
@@ -134,13 +134,14 @@ class Inventory extends \Magento\Backend\Block\Widget
     public function getFieldValue($field)
     {
         $stockItem = $this->getStockItem();
+        $value = null;
         if ($stockItem->getItemId()) {
             $method = 'get' . SimpleDataObjectConverter::snakeCaseToUpperCamelCase($field);
-            if (method_exists($stockItem, $method)) {
-                return $stockItem->{$method}();
+            if (is_callable([$stockItem, $method])) {
+                $value = $stockItem->{$method}();
             }
         }
-        return $this->stockConfiguration->getDefaultConfigValue($field);
+        return $value === null ? $this->stockConfiguration->getDefaultConfigValue($field) : $value;
     }
 
     /**
diff --git a/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Tab/Options/Type/AbstractType.php b/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Tab/Options/Type/AbstractType.php
index b4c8d96bbdc11a4d47cafb77d8121a9c46d40e52..734fe6bc0db2b7d667c742cf2753d8e868f2255a 100644
--- a/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Tab/Options/Type/AbstractType.php
+++ b/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Tab/Options/Type/AbstractType.php
@@ -70,13 +70,17 @@ class AbstractType extends \Magento\Backend\Block\Widget
     /**
      * Get html of Price Type select element
      *
+     * @param string $extraParams
      * @return string
      */
-    public function getPriceTypeSelectHtml()
+    public function getPriceTypeSelectHtml($extraParams = '')
     {
         if ($this->getCanEditPrice() === false) {
-            $this->getChildBlock('option_price_type')->setExtraParams('disabled="disabled"');
+            $extraParams .= ' disabled="disabled"';
+            $this->getChildBlock('option_price_type');
         }
+        $this->getChildBlock('option_price_type')->setExtraParams($extraParams);
+
         return $this->getChildHtml('option_price_type');
     }
 }
diff --git a/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Tab/Options/Type/Select.php b/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Tab/Options/Type/Select.php
index c91c09dcb9f15fe552930a1bd7a4e03bd3350deb..621420cfecec31e64c9d3b5a0ef8565c57bf8cac 100644
--- a/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Tab/Options/Type/Select.php
+++ b/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Tab/Options/Type/Select.php
@@ -90,8 +90,8 @@ class Select extends \Magento\Catalog\Block\Adminhtml\Product\Edit\Tab\Options\T
             'product_option_<%- data.id %>_select_<%- data.select_id %>_price_type'
         )->setName(
             'product[options][<%- data.id %>][values][<%- data.select_id %>][price_type]'
-        )->setExtraParams($extraParams);
+        );
 
-        return parent::getPriceTypeSelectHtml();
+        return parent::getPriceTypeSelectHtml($extraParams);
     }
 }
diff --git a/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Tabs.php b/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Tabs.php
index 2f99d45e092e8458fd1c6d6c38eb9cd26becd14c..4276ab20af7d39f4abd3fc5da3d2728de6683045 100644
--- a/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Tabs.php
+++ b/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Tabs.php
@@ -189,15 +189,15 @@ class Tabs extends \Magento\Backend\Block\Widget\Tabs
                 unset($advancedGroups['advanced-pricing']);
             }
 
-            if ($this->_moduleManager->isEnabled('Magento_CatalogInventory')) {
+            if ($this->_moduleManager->isEnabled('Magento_CatalogInventory')
+                && $this->getChildBlock('advanced-inventory')
+            ) {
                 $this->addTab(
                     'advanced-inventory',
                     [
                         'label' => __('Advanced Inventory'),
                         'content' => $this->_translateHtml(
-                            $this->getLayout()->createBlock(
-                                'Magento\Catalog\Block\Adminhtml\Product\Edit\Tab\Inventory'
-                            )->toHtml()
+                            $this->getChildHtml('advanced-inventory')
                         ),
                         'group_code' => self::ADVANCED_TAB_GROUP_CODE
                     ]
diff --git a/app/code/Magento/Catalog/Block/Product/View/Options/Type/Select.php b/app/code/Magento/Catalog/Block/Product/View/Options/Type/Select.php
index bfaba7215694333216076f799e490a09a34b14e6..f07a069b38daea127b38797a5564ec1e6ab8207a 100644
--- a/app/code/Magento/Catalog/Block/Product/View/Options/Type/Select.php
+++ b/app/code/Magento/Catalog/Block/Product/View/Options/Type/Select.php
@@ -160,7 +160,7 @@ class Select extends \Magento\Catalog\Block\Product\View\Options\AbstractOptions
                     $count .
                     '"><span>' .
                     $_value->getTitle() .
-                    '</span>' .
+                    '</span> ' .
                     $priceStr .
                     '</label>';
                 $selectHtml .= '</div>';
diff --git a/app/code/Magento/Catalog/Model/Product.php b/app/code/Magento/Catalog/Model/Product.php
index dd0f5ec4ead4f93ae5a12313ada595359471ef03..2453c4395345b2b20bbfc1ee09ab3a7e29c5171d 100644
--- a/app/code/Magento/Catalog/Model/Product.php
+++ b/app/code/Magento/Catalog/Model/Product.php
@@ -2504,6 +2504,9 @@ class Product extends \Magento\Catalog\Model\AbstractModel implements
      */
     public function setTypeId($typeId)
     {
+        if ($typeId !== $this->_getData('type_id')) {
+            $this->_typeInstance = null;
+        }
         return $this->setData(self::TYPE_ID, $typeId);
     }
 
diff --git a/app/code/Magento/Catalog/Model/Product/Link.php b/app/code/Magento/Catalog/Model/Product/Link.php
index 7ca13f75821ec5872e76e0292ad92105f18f3cb8..a088df34cf7dfe0b6c87487b6516425b939cddb5 100644
--- a/app/code/Magento/Catalog/Model/Product/Link.php
+++ b/app/code/Magento/Catalog/Model/Product/Link.php
@@ -49,11 +49,17 @@ class Link extends \Magento\Framework\Model\AbstractModel
      */
     protected $_linkCollectionFactory;
 
+    /**
+     * @var \Magento\CatalogInventory\Helper\Stock
+     */
+    protected $stockHelper;
+
     /**
      * @param \Magento\Framework\Model\Context $context
      * @param \Magento\Framework\Registry $registry
      * @param \Magento\Catalog\Model\Resource\Product\Link\CollectionFactory $linkCollectionFactory
      * @param \Magento\Catalog\Model\Resource\Product\Link\Product\CollectionFactory $productCollectionFactory
+     * @param \Magento\CatalogInventory\Helper\Stock $stockHelper
      * @param \Magento\Framework\Model\Resource\AbstractResource $resource
      * @param \Magento\Framework\Data\Collection\AbstractDb $resourceCollection
      * @param array $data
@@ -63,12 +69,14 @@ class Link extends \Magento\Framework\Model\AbstractModel
         \Magento\Framework\Registry $registry,
         \Magento\Catalog\Model\Resource\Product\Link\CollectionFactory $linkCollectionFactory,
         \Magento\Catalog\Model\Resource\Product\Link\Product\CollectionFactory $productCollectionFactory,
+        \Magento\CatalogInventory\Helper\Stock $stockHelper,
         \Magento\Framework\Model\Resource\AbstractResource $resource = null,
         \Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null,
         array $data = []
     ) {
         $this->_linkCollectionFactory = $linkCollectionFactory;
         $this->_productCollectionFactory = $productCollectionFactory;
+        $this->stockHelper = $stockHelper;
         parent::__construct($context, $registry, $resource, $resourceCollection, $data);
     }
 
@@ -128,6 +136,7 @@ class Link extends \Magento\Framework\Model\AbstractModel
     public function getProductCollection()
     {
         $collection = $this->_productCollectionFactory->create()->setLinkModel($this);
+        $this->stockHelper->addInStockFilterToCollection($collection);
         return $collection;
     }
 
diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Product/LinkTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Product/LinkTest.php
index e081f7229468c27f54c578499ccb38e6a1c1f44f..29c855255c00b79cf413785d3aac401e694c435b 100644
--- a/app/code/Magento/Catalog/Test/Unit/Model/Product/LinkTest.php
+++ b/app/code/Magento/Catalog/Test/Unit/Model/Product/LinkTest.php
@@ -19,6 +19,16 @@ class LinkTest extends \PHPUnit_Framework_TestCase
      */
     protected $resource;
 
+    /**
+     * @var \Magento\CatalogInventory\Helper\Stock|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $stockHelperMock;
+
+    /**
+     * @var \Magento\Catalog\Model\Resource\Product\Link\Product\Collection|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $productCollection;
+
     protected function setUp()
     {
         $linkCollection = $this->getMockBuilder(
@@ -35,12 +45,12 @@ class LinkTest extends \PHPUnit_Framework_TestCase
         $linkCollectionFactory->expects($this->any())
             ->method('create')
             ->will($this->returnValue($linkCollection));
-        $productCollection = $this->getMockBuilder(
+        $this->productCollection = $this->getMockBuilder(
             'Magento\Catalog\Model\Resource\Product\Link\Product\Collection'
         )->disableOriginalConstructor()->setMethods(
             ['setLinkModel']
         )->getMock();
-        $productCollection->expects($this->any())->method('setLinkModel')->will($this->returnSelf());
+        $this->productCollection->expects($this->any())->method('setLinkModel')->will($this->returnSelf());
         $productCollectionFactory = $this->getMockBuilder(
             'Magento\Catalog\Model\Resource\Product\Link\Product\CollectionFactory'
         )->disableOriginalConstructor()->setMethods(
@@ -48,7 +58,7 @@ class LinkTest extends \PHPUnit_Framework_TestCase
         )->getMock();
         $productCollectionFactory->expects($this->any())
             ->method('create')
-            ->will($this->returnValue($productCollection));
+            ->will($this->returnValue($this->productCollection));
 
         $this->resource = $this->getMock(
             'Magento\Framework\Model\Resource\AbstractResource',
@@ -63,11 +73,19 @@ class LinkTest extends \PHPUnit_Framework_TestCase
             ]
         );
 
+        $this->stockHelperMock = $this->getMockBuilder('Magento\CatalogInventory\Helper\Stock')
+            ->disableOriginalConstructor()
+            ->getMock();
+
         $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
         $this->model = $objectManager->getObject(
             'Magento\Catalog\Model\Product\Link',
-            ['linkCollectionFactory' => $linkCollectionFactory, 'productCollectionFactory' => $productCollectionFactory,
-                'resource' => $this->resource]
+            [
+                'linkCollectionFactory' => $linkCollectionFactory,
+                'productCollectionFactory' => $productCollectionFactory,
+                'resource' => $this->resource,
+                'stockHelper' => $this->stockHelperMock
+            ]
         );
     }
 
@@ -109,6 +127,10 @@ class LinkTest extends \PHPUnit_Framework_TestCase
 
     public function testGetProductCollection()
     {
+        $this->stockHelperMock
+            ->expects($this->once())
+            ->method('addInStockFilterToCollection')
+            ->with($this->productCollection);
         $this->assertInstanceOf(
             'Magento\Catalog\Model\Resource\Product\Link\Product\Collection',
             $this->model->getProductCollection()
diff --git a/app/code/Magento/Catalog/Test/Unit/Model/ProductTest.php b/app/code/Magento/Catalog/Test/Unit/Model/ProductTest.php
index 97f42ea1d09ab40dba23ae24684f516fb520b74d..9cbc587f0cb84a8f347e3feb9c35553969bb5272 100644
--- a/app/code/Magento/Catalog/Test/Unit/Model/ProductTest.php
+++ b/app/code/Magento/Catalog/Test/Unit/Model/ProductTest.php
@@ -1407,4 +1407,19 @@ class ProductTest extends \PHPUnit_Framework_TestCase
         $this->productTypeInstanceMock->expects($this->never())->method('priceFactory');
         $this->assertEquals($finalPrice, $this->model->getFinalPrice($qty));
     }
+
+    public function testGetTypeId()
+    {
+        $productType = $this->getMockBuilder('Magento\Catalog\Model\Product\Type\Virtual')
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+
+        $this->productTypeInstanceMock->expects($this->exactly(2))->method('factory')->will(
+            $this->returnValue($productType)
+        );
+
+        $this->model->getTypeInstance();
+        $this->model->setTypeId('typeId');
+        $this->model->getTypeInstance();
+    }
 }
diff --git a/app/code/Magento/Catalog/Ui/Component/FilterFactory.php b/app/code/Magento/Catalog/Ui/Component/FilterFactory.php
index a32daf19149a530ad1b685b5ac9b200dc8fca28f..0cd46daccf81ceeef50d513d55dff83f2a35b68d 100644
--- a/app/code/Magento/Catalog/Ui/Component/FilterFactory.php
+++ b/app/code/Magento/Catalog/Ui/Component/FilterFactory.php
@@ -34,15 +34,19 @@ class FilterFactory
     /**
      * @param \Magento\Catalog\Api\Data\ProductAttributeInterface $attribute
      * @param \Magento\Framework\View\Element\UiComponent\ContextInterface $context
+     * @param array $config
      * @return \Magento\Ui\Component\Listing\Columns\ColumnInterface
      */
-    public function create($attribute, $context)
+    public function create($attribute, $context, $config = [])
     {
         $columnName = $attribute->getAttributeCode();
-        $config = [
-            'dataScope' => $columnName,
-            'label' => __($attribute->getDefaultFrontendLabel()),
-        ];
+        $config = array_merge(
+            [
+                'dataScope' => $columnName,
+                'label' => __($attribute->getDefaultFrontendLabel()),
+            ],
+            $config
+        );
         if ($attribute->usesSource() && $attribute->getSourceModel()) {
             $config['options'] = $attribute->getSource()->getAllOptions();
             $config['caption'] = __('Select...');
diff --git a/app/code/Magento/Catalog/Ui/Component/Listing/Attribute/AbstractRepository.php b/app/code/Magento/Catalog/Ui/Component/Listing/Attribute/AbstractRepository.php
new file mode 100644
index 0000000000000000000000000000000000000000..aff12f7aed976812a062ceba2c64be85aab18b6e
--- /dev/null
+++ b/app/code/Magento/Catalog/Ui/Component/Listing/Attribute/AbstractRepository.php
@@ -0,0 +1,47 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Catalog\Ui\Component\Listing\Attribute;
+
+abstract class AbstractRepository implements RepositoryInterface
+{
+    /**
+     * @var null|\Magento\Catalog\Api\Data\ProductAttributeInterface[]
+     */
+    protected $attributes;
+
+    /** @var \Magento\Framework\Api\SearchCriteriaBuilder */
+    protected $searchCriteriaBuilder;
+
+    /**
+     * @param \Magento\Catalog\Api\ProductAttributeRepositoryInterface $productAttributeRepository
+     * @param \Magento\Framework\Api\SearchCriteriaBuilder $searchCriteriaBuilder
+     */
+    public function __construct(
+        \Magento\Catalog\Api\ProductAttributeRepositoryInterface $productAttributeRepository,
+        \Magento\Framework\Api\SearchCriteriaBuilder $searchCriteriaBuilder
+    ) {
+        $this->productAttributeRepository = $productAttributeRepository;
+        $this->searchCriteriaBuilder = $searchCriteriaBuilder;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    abstract protected function buildSearchCriteria();
+
+    /**
+     * @return \Magento\Catalog\Api\Data\ProductAttributeInterface[]
+     */
+    public function getList()
+    {
+        if (null == $this->attributes) {
+            $this->attributes = $this->productAttributeRepository
+                ->getList($this->buildSearchCriteria())
+                ->getItems();
+        }
+        return $this->attributes;
+    }
+}
diff --git a/app/code/Magento/Catalog/Ui/Component/Listing/Attribute/Repository.php b/app/code/Magento/Catalog/Ui/Component/Listing/Attribute/Repository.php
new file mode 100644
index 0000000000000000000000000000000000000000..c954ec8b636df3f864961d48d3e03cd320680a95
--- /dev/null
+++ b/app/code/Magento/Catalog/Ui/Component/Listing/Attribute/Repository.php
@@ -0,0 +1,17 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Catalog\Ui\Component\Listing\Attribute;
+
+class Repository extends AbstractRepository
+{
+    /**
+     * {@inheritdoc}
+     */
+    protected function buildSearchCriteria()
+    {
+        return $this->searchCriteriaBuilder->addFilter('additional_table.is_used_in_grid', 1)->create();
+    }
+}
diff --git a/app/code/Magento/Catalog/Ui/Component/Listing/Attribute/RepositoryInterface.php b/app/code/Magento/Catalog/Ui/Component/Listing/Attribute/RepositoryInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..b65cce8055c69d079c8638c192a75fabcfc6eb39
--- /dev/null
+++ b/app/code/Magento/Catalog/Ui/Component/Listing/Attribute/RepositoryInterface.php
@@ -0,0 +1,16 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Catalog\Ui\Component\Listing\Attribute;
+
+interface RepositoryInterface
+{
+    /**
+     * Get attributes
+     *
+     * @return \Magento\Catalog\Api\Data\ProductAttributeInterface[]
+     */
+    public function getList();
+}
diff --git a/app/code/Magento/Catalog/Ui/Component/Listing/AttributeRepository.php b/app/code/Magento/Catalog/Ui/Component/Listing/AttributeRepository.php
deleted file mode 100644
index 4f7351a3222fb1dc87ce9152c881653b2d17c962..0000000000000000000000000000000000000000
--- a/app/code/Magento/Catalog/Ui/Component/Listing/AttributeRepository.php
+++ /dev/null
@@ -1,42 +0,0 @@
-<?php
-/**
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-namespace Magento\Catalog\Ui\Component\Listing;
-
-class AttributeRepository extends \Magento\Ui\Component\Listing\Columns
-{
-    /**
-     * @var null|\Magento\Catalog\Api\Data\ProductAttributeInterface[]
-     */
-    private $attributes;
-
-    /**
-     * @param \Magento\Catalog\Model\Resource\Product\Attribute\Collection $attributeCollection
-     * @param \Magento\Catalog\Api\ProductAttributeRepositoryInterface $productAttributeRepository
-     */
-    public function __construct(
-        \Magento\Catalog\Model\Resource\Product\Attribute\Collection $attributeCollection,
-        \Magento\Catalog\Api\ProductAttributeRepositoryInterface $productAttributeRepository
-    ) {
-        $this->attributeCollection = $attributeCollection;
-        $this->productAttributeRepository = $productAttributeRepository;
-    }
-
-    /**
-     * @return \Magento\Catalog\Api\Data\ProductAttributeInterface[]
-     */
-    public function getList()
-    {
-        if (null == $this->attributes) {
-            $this->attributes = [];
-            $this->attributeCollection->addIsUsedInGridFilter();
-            foreach ($this->attributeCollection as $attribute) {
-                $attribute = $this->productAttributeRepository->get($attribute->getAttributeId());
-                $this->attributes[] = $attribute;
-            }
-        }
-        return $this->attributes;
-    }
-}
diff --git a/app/code/Magento/Catalog/Ui/Component/Listing/Columns.php b/app/code/Magento/Catalog/Ui/Component/Listing/Columns.php
index 47b621b0bfceffec2188cbae6264d6b80d32d969..2e0243e5875aaba35f44914ba5eebc908d7d1470 100644
--- a/app/code/Magento/Catalog/Ui/Component/Listing/Columns.php
+++ b/app/code/Magento/Catalog/Ui/Component/Listing/Columns.php
@@ -12,17 +12,20 @@ class Columns extends \Magento\Ui\Component\Listing\Columns
      */
     const DEFAULT_COLUMNS_MAX_ORDER = 100;
 
+    /** @var \Magento\Catalog\Ui\Component\Listing\Attribute\RepositoryInterface */
+    protected $attributeRepository;
+
     /**
      * @param \Magento\Framework\View\Element\UiComponent\ContextInterface $context
      * @param \Magento\Catalog\Ui\Component\ColumnFactory $columnFactory
-     * @param AttributeRepository $attributeRepository
+     * @param \Magento\Catalog\Ui\Component\Listing\Attribute\RepositoryInterface $attributeRepository
      * @param array $components
      * @param array $data
      */
     public function __construct(
         \Magento\Framework\View\Element\UiComponent\ContextInterface $context,
         \Magento\Catalog\Ui\Component\ColumnFactory $columnFactory,
-        \Magento\Catalog\Ui\Component\Listing\AttributeRepository $attributeRepository,
+        \Magento\Catalog\Ui\Component\Listing\Attribute\RepositoryInterface $attributeRepository,
         array $components = [],
         array $data = []
     ) {
diff --git a/app/code/Magento/Catalog/Ui/Component/Listing/Filters.php b/app/code/Magento/Catalog/Ui/Component/Listing/Filters.php
index 9c2950a596bca51b0c183efce2708bd9a19ecc27..ba70b679b5e4e4e44781ad1a8363b07e7ce05ad6 100644
--- a/app/code/Magento/Catalog/Ui/Component/Listing/Filters.php
+++ b/app/code/Magento/Catalog/Ui/Component/Listing/Filters.php
@@ -8,21 +8,21 @@ namespace Magento\Catalog\Ui\Component\Listing;
 class Filters extends \Magento\Ui\Component\Filters
 {
     /**
-     * @var AttributeRepository
+     * @var \Magento\Catalog\Ui\Component\Listing\Attribute\RepositoryInterface
      */
     protected $attributeRepository;
 
     /**
      * @param \Magento\Framework\View\Element\UiComponent\ContextInterface $context
      * @param \Magento\Catalog\Ui\Component\FilterFactory $filterFactory
-     * @param AttributeRepository $attributeRepository
+     * @param \Magento\Catalog\Ui\Component\Listing\Attribute\RepositoryInterface $attributeRepository
      * @param array $components
      * @param array $data
      */
     public function __construct(
         \Magento\Framework\View\Element\UiComponent\ContextInterface $context,
         \Magento\Catalog\Ui\Component\FilterFactory $filterFactory,
-        \Magento\Catalog\Ui\Component\Listing\AttributeRepository $attributeRepository,
+        \Magento\Catalog\Ui\Component\Listing\Attribute\RepositoryInterface $attributeRepository,
         array $components = [],
         array $data = []
     ) {
diff --git a/app/code/Magento/Catalog/etc/adminhtml/di.xml b/app/code/Magento/Catalog/etc/adminhtml/di.xml
index 5cf13196cbd26779ea6c7619a34636e9aef6163b..295f42a5b19495d8a1548cb840c1ba06e3de6a17 100644
--- a/app/code/Magento/Catalog/etc/adminhtml/di.xml
+++ b/app/code/Magento/Catalog/etc/adminhtml/di.xml
@@ -79,4 +79,5 @@
     <type name="Magento\Catalog\Model\Product\Action">
         <plugin name="invalidate_pagecache_after_update_product_attributes" type="Magento\Catalog\Plugin\Model\Product\Action\UpdateAttributesFlushCache"/>
     </type>
+    <preference for="Magento\Catalog\Ui\Component\Listing\Attribute\RepositoryInterface" type="Magento\Catalog\Ui\Component\Listing\Attribute\Repository"/>
 </config>
diff --git a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_new.xml b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_new.xml
index 55e9ebee91f5bcbbcc6b77c4d81fd3638dec7592..4377b74674bd39520293cbab250d994fe33be3e6 100644
--- a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_new.xml
+++ b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_new.xml
@@ -37,6 +37,12 @@
                         <argument name="class" xsi:type="string">ajax</argument>
                     </arguments>
                 </block>
+                <block class="Magento\Catalog\Block\Adminhtml\Product\Edit\Tab\Inventory" name="product_tabs.advanced-inventory" as="advanced-inventory">
+                    <arguments>
+                        <argument name="label" xsi:type="string" translate="true">Advanced Inventory</argument>
+                        <argument name="group_code" xsi:type="string">advanced</argument>
+                    </arguments>
+                </block>
                 <block class="Magento\Catalog\Block\Adminhtml\Product\Edit\Tab\Alerts" name="product_tabs.product-alerts" as="product-alerts">
                     <arguments>
                         <argument name="label" xsi:type="string" translate="true">Product Alerts</argument>
diff --git a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/edit/options.phtml b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/edit/options.phtml
index aa49671e94509083573c814575a38a9e9af69140..67b1e95e3084663f375efad98714f295ac897c41 100644
--- a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/edit/options.phtml
+++ b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/edit/options.phtml
@@ -15,7 +15,7 @@
             <span><?php /* @escapeNotVerified */ echo __('Custom Options') ?></span>
         </strong>
     </div>
-    <div class="fieldset-wrapper-content" id="product-custom-options-content">
+    <div class="fieldset-wrapper-content" id="product-custom-options-content" data-role="product-custom-options-content">
         <fieldset class="fieldset">
             <div class="messages">
                 <div class="message message-error" id="dynamic-price-warning" style="display: none;">
diff --git a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/edit/options/type/date.phtml b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/edit/options/type/date.phtml
index dc8c8f8ce1990920d70ddf8c4d2f10753863b3e3..d8d09c8ff7758705783c1486110a99c0a50abdde 100644
--- a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/edit/options/type/date.phtml
+++ b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/edit/options/type/date.phtml
@@ -31,7 +31,9 @@
                            disabled="disabled"
                         <?php endif; ?>>
                 </td>
-                <td class="opt-price-type"><?php echo $block->getPriceTypeSelectHtml() ?><%- data.checkboxScopePrice %></td>
+                <td class="opt-price-type">
+                    <?php echo $block->getPriceTypeSelectHtml('data-attr="price-type"') ?><%- data.checkboxScopePrice %>
+                </td>
                 <?php else : ?>
                 <input id="product_option_<%- data.option_id %>_price" name="product[options][<%- data.option_id %>][price]" type="hidden">
                 <input id="product_option_<%- data.option_id %>_price_type" name="product[options][<%- data.option_id %>][price_type]" type="hidden">
diff --git a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/edit/options/type/file.phtml b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/edit/options/type/file.phtml
index afe552f4ab82954c90fd8e00df8982f2661858e8..7be294debacf1406de7cb4ecb41db66dd0e386e5 100644
--- a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/edit/options/type/file.phtml
+++ b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/edit/options/type/file.phtml
@@ -31,7 +31,7 @@
                            disabled="disabled"
                         <?php endif; ?>>
                 </td>
-                <td class="opt-price-type"><?php echo $block->getPriceTypeSelectHtml() ?><%- data.checkboxScopePrice %></td>
+                <td class="opt-price-type"><?php echo $block->getPriceTypeSelectHtml('data-attr="price-type"') ?><%- data.checkboxScopePrice %></td>
                 <?php else : ?>
                 <input name="product[options][<%- data.option_id %>][price]" type="hidden">
                 <input id="product_option_<%- data.option_id %>_price_type" name="product[options][<%- data.option_id %>][price_type]" type="hidden">
diff --git a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/edit/options/type/select.phtml b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/edit/options/type/select.phtml
index eae5c113215ce90382fc023da67943e5a64290de..da7b6eef24963254ac343ef300037157b25ba00b 100644
--- a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/edit/options/type/select.phtml
+++ b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/edit/options/type/select.phtml
@@ -57,7 +57,9 @@
                    disabled="disabled"
                 <?php endif; ?>>
         </td>
-        <td class="col-price-type select-opt-price-type"><?php /* @escapeNotVerified */ echo $block->getPriceTypeSelectHtml('<% if (typeof data.scopePriceDisabled != "undefined" && data.scopePriceDisabled != null) { %> disabled="disabled" <% } %>') ?><%- data.checkboxScopePrice %></td>
+        <td class="col-price-type select-opt-price-type">
+            <?php /* @escapeNotVerified */ echo $block->getPriceTypeSelectHtml('data-attr="price-type" <% if (typeof data.scopePriceDisabled != "undefined" && data.scopePriceDisabled != null) { %> disabled="disabled" <% } %>') ?><%- data.checkboxScopePrice %>
+        </td>
         <?php else : ?>
         <input id="product_option_<%- data.id %>_select_<%- data.select_id %>_price" name="product[options][<%- data.id %>][values][<%- data.select_id %>][price]" type="hidden">
         <input id="product_option_<%- data.id %>_select_<%- data.select_id %>_price_type" name="product[options][<%- data.id %>][values][<%- data.select_id %>][price_type]" type="hidden">
diff --git a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/edit/options/type/text.phtml b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/edit/options/type/text.phtml
index bcc6f5171dc64be5563e181f1f230f6ff58b6fe1..769c6c1749ed3fbb2611441567d717b1852c8f6f 100644
--- a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/edit/options/type/text.phtml
+++ b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/edit/options/type/text.phtml
@@ -32,7 +32,7 @@
                            disabled="disabled"
                         <?php endif; ?>>
                 </td>
-                <td class="opt-price-type"><?php echo $block->getPriceTypeSelectHtml() ?><%- data.checkboxScopePrice %></td>
+                <td class="opt-price-type"><?php echo $block->getPriceTypeSelectHtml('data-attr="price-type"') ?><%- data.checkboxScopePrice %></td>
                 <?php else : ?>
                 <input id="product_option_<%- data.option_id %>_price" name="product[options][<%- data.option_id %>][price]" type="hidden">
                 <input id="product_option_<%- data.option_id %>_price_type" name="product[options][<%- data.option_id %>][price_type]" type="hidden">
diff --git a/app/code/Magento/Catalog/view/adminhtml/templates/product/edit/attribute/search.phtml b/app/code/Magento/Catalog/view/adminhtml/templates/product/edit/attribute/search.phtml
index 3f6215626ad827c7a2791828b4886b958ce4bfc4..d3c382f9276b8a2d9df9ec1473fbe1707779fc42 100644
--- a/app/code/Magento/Catalog/view/adminhtml/templates/product/edit/attribute/search.phtml
+++ b/app/code/Magento/Catalog/view/adminhtml/templates/product/edit/attribute/search.phtml
@@ -63,7 +63,7 @@
                         data: {attribute_id: ui.item.id, template_id: templateId, group: $(this).data('group')},
                         showLoader: true
                     }).done(function() {
-                        setTimeout(function() { //do defered
+                        setTimeout(function() { //do deferred
                             $('[data-form=edit-product]').trigger('changeAttributeSet', {id: templateId});
                         }, 10);
                     });
diff --git a/app/code/Magento/CatalogInventory/Model/Resource/QtyCounterInterface.php b/app/code/Magento/CatalogInventory/Model/Resource/QtyCounterInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..e36a04a2b3d40630ee819410f7f86aa4c283f6dd
--- /dev/null
+++ b/app/code/Magento/CatalogInventory/Model/Resource/QtyCounterInterface.php
@@ -0,0 +1,22 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\CatalogInventory\Model\Resource;
+
+/**
+ * Correct particular stock products qty
+ */
+interface QtyCounterInterface
+{
+    /**
+     * Correct particular stock products qty based on operator
+     *
+     * @param int[] $items
+     * @param int $websiteId
+     * @param string $operator +/-
+     * @return void
+     */
+    public function correctItemsQty(array $items, $websiteId, $operator);
+}
diff --git a/app/code/Magento/CatalogInventory/Model/Resource/Stock.php b/app/code/Magento/CatalogInventory/Model/Resource/Stock.php
index e5c9c696404fb1dcd6b1a096be6190f09b16822f..6948b642136d19844f92273987dcf9c8ee3b299d 100644
--- a/app/code/Magento/CatalogInventory/Model/Resource/Stock.php
+++ b/app/code/Magento/CatalogInventory/Model/Resource/Stock.php
@@ -12,7 +12,7 @@ use Magento\Store\Model\StoreManagerInterface;
 /**
  * Stock resource model
  */
-class Stock extends \Magento\Framework\Model\Resource\Db\AbstractDb
+class Stock extends \Magento\Framework\Model\Resource\Db\AbstractDb implements QtyCounterInterface
 {
     /**
      * @var StockConfigurationInterface
@@ -134,14 +134,9 @@ class Stock extends \Magento\Framework\Model\Resource\Db\AbstractDb
     }
 
     /**
-     * Correct particular stock products qty based on operator
-     *
-     * @param array $items
-     * @param int $websiteId
-     * @param string $operator +/-
-     * @return $this
+     * {@inheritdoc}
      */
-    public function correctItemsQty(array $items, $websiteId, $operator = '-')
+    public function correctItemsQty(array $items, $websiteId, $operator)
     {
         if (empty($items)) {
             return $this;
@@ -161,8 +156,6 @@ class Stock extends \Magento\Framework\Model\Resource\Db\AbstractDb
         $connection->beginTransaction();
         $connection->update($this->getTable('cataloginventory_stock_item'), ['qty' => $value], $where);
         $connection->commit();
-
-        return $this;
     }
 
     /**
diff --git a/app/code/Magento/CatalogInventory/Model/StockManagement.php b/app/code/Magento/CatalogInventory/Model/StockManagement.php
index 3d5fee6d9cef90eb8bfcf98d78b6c45e68c0bca2..c487ab15394e79dce91848c9fa45dafddef19161 100644
--- a/app/code/Magento/CatalogInventory/Model/StockManagement.php
+++ b/app/code/Magento/CatalogInventory/Model/StockManagement.php
@@ -9,6 +9,7 @@ use Magento\Catalog\Model\ProductFactory;
 use Magento\CatalogInventory\Api\Data\StockItemInterface;
 use Magento\CatalogInventory\Api\StockConfigurationInterface;
 use Magento\CatalogInventory\Api\StockManagementInterface;
+use Magento\CatalogInventory\Model\Resource\QtyCounterInterface;
 use Magento\CatalogInventory\Model\Spi\StockRegistryProviderInterface;
 use Magento\Catalog\Api\ProductRepositoryInterface;
 
@@ -38,26 +39,37 @@ class StockManagement implements StockManagementInterface
     protected $productRepository;
 
     /**
-     * @var \Magento\CatalogInventory\Model\Resource\Stock
+     * @var Resource\Stock
      */
     protected $resource;
 
     /**
+     * @var QtyCounterInterface
+     */
+    private $qtyCounter;
+
+    /**
+     * @param Resource\Stock $stockResource
      * @param StockRegistryProviderInterface $stockRegistryProvider
      * @param StockState $stockState
      * @param StockConfigurationInterface $stockConfiguration
      * @param ProductRepositoryInterface $productRepository
+     * @param Resource\QtyCounterInterface $qtyCounter
      */
     public function __construct(
+        Resource\Stock $stockResource,
         StockRegistryProviderInterface $stockRegistryProvider,
         StockState $stockState,
         StockConfigurationInterface $stockConfiguration,
-        ProductRepositoryInterface $productRepository
+        ProductRepositoryInterface $productRepository,
+        QtyCounterInterface $qtyCounter
     ) {
         $this->stockRegistryProvider = $stockRegistryProvider;
         $this->stockState = $stockState;
         $this->stockConfiguration = $stockConfiguration;
         $this->productRepository = $productRepository;
+        $this->qtyCounter = $qtyCounter;
+        $this->resource = $stockResource;
     }
 
     /**
@@ -108,7 +120,7 @@ class StockManagement implements StockManagementInterface
                 $fullSaveItems[] = $stockItem;
             }
         }
-        $this->getResource()->correctItemsQty($registeredItems, $websiteId, '-');
+        $this->qtyCounter->correctItemsQty($registeredItems, $websiteId, '-');
         $this->getResource()->commit();
         return $fullSaveItems;
     }
@@ -123,7 +135,7 @@ class StockManagement implements StockManagementInterface
         //if (!$websiteId) {
         $websiteId = $this->stockConfiguration->getDefaultWebsiteId();
         //}
-        $this->getResource()->correctItemsQty($items, $websiteId, '+');
+        $this->qtyCounter->correctItemsQty($items, $websiteId, '+');
         return true;
     }
 
@@ -168,15 +180,10 @@ class StockManagement implements StockManagementInterface
     }
 
     /**
-     * @return \Magento\CatalogInventory\Model\Resource\Stock
+     * @return Stock
      */
     protected function getResource()
     {
-        if (empty($this->resource)) {
-            $this->resource = \Magento\Framework\App\ObjectManager::getInstance()->get(
-                'Magento\CatalogInventory\Model\Resource\Stock'
-            );
-        }
         return $this->resource;
     }
 
diff --git a/app/code/Magento/CatalogInventory/Observer/SaveInventoryDataObserver.php b/app/code/Magento/CatalogInventory/Observer/SaveInventoryDataObserver.php
index 789fc3748dcd9a32b78b5cd3333020992c4d0e71..653f77000c8c45be8f4333f02d42b0501b5f9f3d 100644
--- a/app/code/Magento/CatalogInventory/Observer/SaveInventoryDataObserver.php
+++ b/app/code/Magento/CatalogInventory/Observer/SaveInventoryDataObserver.php
@@ -8,6 +8,7 @@ namespace Magento\CatalogInventory\Observer;
 
 use Magento\CatalogInventory\Api\StockConfigurationInterface;
 use Magento\CatalogInventory\Api\StockIndexInterface;
+use Magento\CatalogInventory\Api\StockItemRepositoryInterface;
 use Magento\CatalogInventory\Api\StockRegistryInterface;
 use Magento\Framework\Event\Observer as EventObserver;
 
@@ -32,7 +33,7 @@ class SaveInventoryDataObserver
     protected $stockRegistry;
 
     /**
-     * @var \Magento\CatalogInventory\Api\StockItemRepositoryInterface
+     * @var StockItemRepositoryInterface
      */
     protected $stockItemRepository;
 
@@ -74,13 +75,13 @@ class SaveInventoryDataObserver
      * @param StockIndexInterface $stockIndex
      * @param StockConfigurationInterface $stockConfiguration
      * @param StockRegistryInterface $stockRegistry
-     * @param \Magento\CatalogInventory\Api\StockItemRepositoryInterface $stockItemRepository
+     * @param StockItemRepositoryInterface $stockItemRepository
      */
     public function __construct(
         StockIndexInterface $stockIndex,
         StockConfigurationInterface $stockConfiguration,
         StockRegistryInterface $stockRegistry,
-        \Magento\CatalogInventory\Api\StockItemRepositoryInterface $stockItemRepository
+        StockItemRepositoryInterface $stockItemRepository
     ) {
         $this->stockIndex = $stockIndex;
         $this->stockConfiguration = $stockConfiguration;
diff --git a/app/code/Magento/CatalogInventory/etc/di.xml b/app/code/Magento/CatalogInventory/etc/di.xml
index a57b542a0b12cf390a47524aaedd62f1100041bb..4332e525c3260619830f2e5f2102759edf2e346e 100644
--- a/app/code/Magento/CatalogInventory/etc/di.xml
+++ b/app/code/Magento/CatalogInventory/etc/di.xml
@@ -30,6 +30,8 @@
 
     <preference for="Magento\CatalogInventory\Model\Spi\StockRegistryProviderInterface" type="Magento\CatalogInventory\Model\StockRegistryProvider" />
     <preference for="Magento\CatalogInventory\Model\Spi\StockStateProviderInterface" type="Magento\CatalogInventory\Model\StockStateProvider" />
+    
+    <preference for="Magento\CatalogInventory\Model\Resource\QtyCounterInterface" type="\Magento\CatalogInventory\Model\Resource\Stock" />
 
     <type name="Magento\CatalogInventory\Observer\UpdateItemsStockUponConfigChangeObserver">
         <arguments>
diff --git a/app/code/Magento/CatalogRule/Model/Indexer/IndexBuilder.php b/app/code/Magento/CatalogRule/Model/Indexer/IndexBuilder.php
index 3f7477dbd79c7ee9ecb6c6f2153ca7e022ebc895..b156879d0f96ad98d1ee02345287f5a1ed842a57 100644
--- a/app/code/Magento/CatalogRule/Model/Indexer/IndexBuilder.php
+++ b/app/code/Magento/CatalogRule/Model/Indexer/IndexBuilder.php
@@ -248,7 +248,7 @@ class IndexBuilder
             ]
         );
 
-        if (!$rule->getConditions()->validate($product)) {
+        if (!$rule->validate($product)) {
             $this->connection->delete(
                 $this->resource->getTableName('catalogrule_product_price'),
                 [$this->connection->quoteInto('product_id = ?', $productId)]
diff --git a/app/code/Magento/CatalogRule/Model/Rule.php b/app/code/Magento/CatalogRule/Model/Rule.php
index 859dbb110dec4a5962ab2e7fa8a5c1914b53166a..ff05ab857f3be04a6769137d3a6d89cf184b26c3 100644
--- a/app/code/Magento/CatalogRule/Model/Rule.php
+++ b/app/code/Magento/CatalogRule/Model/Rule.php
@@ -347,6 +347,58 @@ class Rule extends \Magento\Rule\Model\AbstractModel
         return $map;
     }
 
+    /**
+     * {@inheritdoc}
+     */
+    public function validateData(\Magento\Framework\DataObject $dataObject)
+    {
+        $result = parent::validateData($dataObject);
+        if ($result === true) {
+            $result = [];
+        }
+
+        $action = $dataObject->getData('simple_action');
+        $discount = $dataObject->getData('discount_amount');
+        $result = array_merge($result, $this->validateDiscount($action, $discount));
+        if ($dataObject->getData('sub_is_enable') == 1) {
+            $action = $dataObject->getData('sub_simple_action');
+            $discount = $dataObject->getData('sub_discount_amount');
+            $result = array_merge($result, $this->validateDiscount($action, $discount));
+        }
+
+        return !empty($result) ? $result : true;
+    }
+
+    /**
+     * Validate discount based on action
+     *
+     * @param string $action
+     * @param string|int|float $discount
+     *
+     * @return array Validation errors
+     */
+    protected function validateDiscount($action, $discount)
+    {
+        $result = [];
+        switch ($action) {
+            case 'by_percent':
+            case 'to_percent':
+                if ($discount < 0 || $discount > 100) {
+                    $result[] = __('Percentage discount should be between 0 and 100.');
+                };
+                break;
+            case 'by_fixed':
+            case 'to_fixed':
+                if ($discount < 0) {
+                    $result[] = __('Discount value should be 0 or greater.');
+                };
+                break;
+            default:
+                $result[] = __('Unknown action.');
+        }
+        return $result;
+    }
+
     /**
      * Calculate price using catalog price rule of product
      *
diff --git a/app/code/Magento/CatalogRule/Test/Unit/Model/Indexer/IndexBuilderTest.php b/app/code/Magento/CatalogRule/Test/Unit/Model/Indexer/IndexBuilderTest.php
index 3687d55d4710fba30b24b144e14c0691e972730f..b043c6078d21130f0709d8297d8851437742363f 100644
--- a/app/code/Magento/CatalogRule/Test/Unit/Model/Indexer/IndexBuilderTest.php
+++ b/app/code/Magento/CatalogRule/Test/Unit/Model/Indexer/IndexBuilderTest.php
@@ -168,7 +168,6 @@ class IndexBuilderTest extends \PHPUnit_Framework_TestCase
 
         $this->rules->expects($this->any())->method('getId')->will($this->returnValue(1));
         $this->rules->expects($this->any())->method('getWebsiteIds')->will($this->returnValue([1]));
-        $this->rules->expects($this->any())->method('getConditions')->will($this->returnValue($this->combine));
         $this->rules->expects($this->any())->method('getCustomerGroupIds')->will($this->returnValue([1]));
 
         $this->ruleCollectionFactory->expects($this->any())->method('create')->will($this->returnSelf());
@@ -180,7 +179,7 @@ class IndexBuilderTest extends \PHPUnit_Framework_TestCase
         $this->product->expects($this->any())->method('getId')->will($this->returnValue(1));
         $this->product->expects($this->any())->method('getWebsiteIds')->will($this->returnValue([1]));
 
-        $this->combine->expects($this->any())->method('validate')->will($this->returnValue(true));
+        $this->rules->expects($this->any())->method('validate')->with($this->product)->willReturn(true);
         $this->attribute->expects($this->any())->method('getBackend')->will($this->returnValue($this->backend));
         $this->productFactory->expects($this->any())->method('create')->will($this->returnValue($this->product));
 
diff --git a/app/code/Magento/CatalogRule/Test/Unit/Model/RuleTest.php b/app/code/Magento/CatalogRule/Test/Unit/Model/RuleTest.php
index dbf6958530ac87af19504c393fc8fae0765b7d08..80f4ef5eed5ece794faef9fdc4b19f22ca4bb9af 100644
--- a/app/code/Magento/CatalogRule/Test/Unit/Model/RuleTest.php
+++ b/app/code/Magento/CatalogRule/Test/Unit/Model/RuleTest.php
@@ -8,6 +8,11 @@ namespace Magento\CatalogRule\Test\Unit\Model;
 
 use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper;
 
+/**
+ * Class RuleTest
+ * @package Magento\CatalogRule\Test\Unit\Model
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ */
 class RuleTest extends \PHPUnit_Framework_TestCase
 {
     /** @var \Magento\CatalogRule\Model\Rule */
@@ -200,6 +205,110 @@ class RuleTest extends \PHPUnit_Framework_TestCase
         ];
     }
 
+    /**
+     * Test validateData action
+     *
+     * @dataProvider validateDataDataProvider
+     * @param array $data Data for the rule actions
+     * @param bool|array $expected True or an array of errors
+     *
+     * @return void
+     */
+    public function testValidateData($data, $expected)
+    {
+        $result = $this->rule->validateData(new \Magento\Framework\DataObject($data));
+        $this->assertEquals($result, $expected);
+    }
+
+    /**
+     * Data provider for testValidateData test
+     *
+     * @return array
+     */
+    public function validateDataDataProvider()
+    {
+        return [
+            [
+                [
+                    'simple_action' => 'by_fixed',
+                    'discount_amount' => '123',
+                    'sub_is_enable' => '0',
+                    'sub_simple_action' => 'by_percent',
+                    'sub_discount_amount' => '123',
+                ],
+                true
+            ],
+            [
+                [
+                    'simple_action' => 'by_percent',
+                    'discount_amount' => '9,99',
+                    'sub_is_enable' => '0',
+                ],
+                true
+            ],
+            [
+                [
+                    'simple_action' => 'by_fixed',
+                    'discount_amount' => '123',
+                    'sub_is_enable' => '1',
+                    'sub_simple_action' => 'by_percent',
+                    'sub_discount_amount' => '123',
+                ],
+                [
+                    'Percentage discount should be between 0 and 100.',
+                ]
+            ],
+            [
+                [
+                    'simple_action' => 'by_percent',
+                    'discount_amount' => '123.12',
+                    'sub_is_enable' => '1',
+                    'sub_simple_action' => 'to_percent',
+                    'sub_discount_amount' => '123.001',
+                ],
+                [
+                    'Percentage discount should be between 0 and 100.',
+                    'Percentage discount should be between 0 and 100.',
+                ]
+            ],
+            [
+                [
+                    'simple_action' => 'to_percent',
+                    'discount_amount' => '-12',
+                    'sub_is_enable' => '1',
+                    'sub_simple_action' => 'to_fixed',
+                    'sub_discount_amount' => '567.8901',
+                ],
+                [
+                    'Percentage discount should be between 0 and 100.',
+                ]
+            ],
+            [
+                [
+                    'simple_action' => 'to_fixed',
+                    'discount_amount' => '-1234567890',
+                    'sub_is_enable' => '1',
+                    'sub_simple_action' => 'by_fixed',
+                    'sub_discount_amount' => '-5',
+                ],
+                [
+                    'Discount value should be 0 or greater.',
+                    'Discount value should be 0 or greater.',
+                ]
+            ],
+            [
+                [
+                    'simple_action' => 'invalid action',
+                    'discount_amount' => '12',
+                    'sub_is_enable' => '0',
+                ],
+                [
+                    'Unknown action.',
+                ]
+            ],
+        ];
+    }
+
     /**
      * Test after delete action
      *
@@ -228,9 +337,10 @@ class RuleTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test IsRuleBehaviorChanged action
+     * Test isRuleBehaviorChanged action
+     *
+     * @dataProvider isRuleBehaviorChangedDataProvider
      *
-     * @dataProvider ruleData
      * @param array $dataArray
      * @param array $originDataArray
      * @param bool $isObjectNew
@@ -258,11 +368,11 @@ class RuleTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Data provider for isRuleBehaviorChanged test
+     * Data provider for testIsRuleBehaviorChanged test
      *
      * @return array
      */
-    public function ruleData()
+    public function isRuleBehaviorChangedDataProvider()
     {
         return [
             [['new name', 'new description'], ['name', 'description'], false, false],
diff --git a/app/code/Magento/CatalogRule/composer.json b/app/code/Magento/CatalogRule/composer.json
index 8abce05a972830229256bd5475aad5b4452b38ad..887ed8b40e83cf9513fb518be418a16b42bc284e 100644
--- a/app/code/Magento/CatalogRule/composer.json
+++ b/app/code/Magento/CatalogRule/composer.json
@@ -9,10 +9,12 @@
         "magento/module-customer": "1.0.0-beta",
         "magento/module-backend": "1.0.0-beta",
         "magento/module-eav": "1.0.0-beta",
-        "magento/module-import-export": "1.0.0-beta",
         "magento/framework": "1.0.0-beta",
         "magento/magento-composer-installer": "*"
     },
+    "suggest": {
+        "magento/module-import-export": "1.0.0-beta"
+    },
     "type": "magento2-module",
     "version": "1.0.0-beta",
     "license": [
diff --git a/app/code/Magento/CatalogRule/i18n/de_DE.csv b/app/code/Magento/CatalogRule/i18n/de_DE.csv
index e5ac9c2fcdef8bfac205f90ab801001bc731ec19..2cfceb25ae29b3c8535b66e5a14384de4ee0a623 100644
--- a/app/code/Magento/CatalogRule/i18n/de_DE.csv
+++ b/app/code/Magento/CatalogRule/i18n/de_DE.csv
@@ -68,3 +68,6 @@ Promo,Promo
 "Conditions Combination",Bedingungenkombination
 "Product Attribute",Produktattribut
 "The rules have been applied.","Die Regeln wurden angewendet."
+"Percentage discount should be between 0 and 100.","Percentage discount should be between 0 and 100."
+"Discount value should be 0 or greater.","Discount value should be 0 or greater."
+"Unknown action.","Unknown action."
diff --git a/app/code/Magento/CatalogRule/i18n/en_US.csv b/app/code/Magento/CatalogRule/i18n/en_US.csv
index aab29051ead73af95b6155cd2734ec5621db5de7..2a931e8b33161f90787eaca154c140360a6aeac1 100644
--- a/app/code/Magento/CatalogRule/i18n/en_US.csv
+++ b/app/code/Magento/CatalogRule/i18n/en_US.csv
@@ -68,3 +68,6 @@ Promo,Promo
 "Conditions Combination","Conditions Combination"
 "Product Attribute","Product Attribute"
 "The rules have been applied.","The rules have been applied."
+"Percentage discount should be between 0 and 100.","Percentage discount should be between 0 and 100."
+"Discount value should be 0 or greater.","Discount value should be 0 or greater."
+"Unknown action.","Unknown action."
diff --git a/app/code/Magento/CatalogRule/i18n/es_ES.csv b/app/code/Magento/CatalogRule/i18n/es_ES.csv
index f49ec6eddb9d3f9645b141d375657d399f18ab7e..acd65c67ccdb2b5e26b074cc87412e51835fed7f 100644
--- a/app/code/Magento/CatalogRule/i18n/es_ES.csv
+++ b/app/code/Magento/CatalogRule/i18n/es_ES.csv
@@ -68,3 +68,6 @@ Promo,Promo
 "Conditions Combination","Combinación de condiciones"
 "Product Attribute","Atributos del producto"
 "The rules have been applied.","Las reglas han sido aplicadas."
+"Percentage discount should be between 0 and 100.","Percentage discount should be between 0 and 100."
+"Discount value should be 0 or greater.","Discount value should be 0 or greater."
+"Unknown action.","Unknown action."
diff --git a/app/code/Magento/CatalogRule/i18n/fr_FR.csv b/app/code/Magento/CatalogRule/i18n/fr_FR.csv
index f003629331ba8db57eff2ab85cb70a5a8c1f8b3e..5349ab2025341e751ea891d5601a411d55d94c40 100644
--- a/app/code/Magento/CatalogRule/i18n/fr_FR.csv
+++ b/app/code/Magento/CatalogRule/i18n/fr_FR.csv
@@ -68,3 +68,6 @@ Promo,Promo
 "Conditions Combination","Combinaison de conditions"
 "Product Attribute","Attribut de produit"
 "The rules have been applied.","Les règles ont été appliquées."
+"Percentage discount should be between 0 and 100.","Percentage discount should be between 0 and 100."
+"Discount value should be 0 or greater.","Discount value should be 0 or greater."
+"Unknown action.","Unknown action."
diff --git a/app/code/Magento/CatalogRule/i18n/nl_NL.csv b/app/code/Magento/CatalogRule/i18n/nl_NL.csv
index 5c21f95f6eabba150428a7c51edb4102bb6ad582..6bc287b3c44cea7d6d72af7aaf9882652d415197 100644
--- a/app/code/Magento/CatalogRule/i18n/nl_NL.csv
+++ b/app/code/Magento/CatalogRule/i18n/nl_NL.csv
@@ -68,3 +68,6 @@ Promo,Promo
 "Conditions Combination",Voorwaardencombinaties
 "Product Attribute","Product attribuut"
 "The rules have been applied.","De regels zijn ingesteld."
+"Percentage discount should be between 0 and 100.","Percentage discount should be between 0 and 100."
+"Discount value should be 0 or greater.","Discount value should be 0 or greater."
+"Unknown action.","Unknown action."
diff --git a/app/code/Magento/CatalogRule/i18n/pt_BR.csv b/app/code/Magento/CatalogRule/i18n/pt_BR.csv
index 39db9b3f737aa1b8037bc0967117f1c7ced1ef3f..77c2c40996739516e7fd8849a8e246462bd59b1a 100644
--- a/app/code/Magento/CatalogRule/i18n/pt_BR.csv
+++ b/app/code/Magento/CatalogRule/i18n/pt_BR.csv
@@ -68,3 +68,6 @@ Promo,Promo
 "Conditions Combination","Combinação de condições"
 "Product Attribute","Atributo de Produto"
 "The rules have been applied.","As regras foram aplicadas."
+"Percentage discount should be between 0 and 100.","Percentage discount should be between 0 and 100."
+"Discount value should be 0 or greater.","Discount value should be 0 or greater."
+"Unknown action.","Unknown action."
diff --git a/app/code/Magento/CatalogRule/i18n/zh_CN.csv b/app/code/Magento/CatalogRule/i18n/zh_CN.csv
index 4d291b895c161b9428069c891c095eea0d5933bb..e1fe27f48fbf548174ad16348e1f547747c26cf8 100644
--- a/app/code/Magento/CatalogRule/i18n/zh_CN.csv
+++ b/app/code/Magento/CatalogRule/i18n/zh_CN.csv
@@ -68,3 +68,6 @@ Promo,Promo
 "Conditions Combination",条件组合
 "Product Attribute",产品属性
 "The rules have been applied.",规则已应用。
+"Percentage discount should be between 0 and 100.","Percentage discount should be between 0 and 100."
+"Discount value should be 0 or greater.","Discount value should be 0 or greater."
+"Unknown action.","Unknown action."
diff --git a/app/code/Magento/CatalogRule/view/adminhtml/templates/promo/js.phtml b/app/code/Magento/CatalogRule/view/adminhtml/templates/promo/js.phtml
index 8e87adac441dbf88047073fbf9044fbe4c2ecdd1..a3604faa6d38ccf46a41fa16145bc1a8b5fea6c3 100644
--- a/app/code/Magento/CatalogRule/view/adminhtml/templates/promo/js.phtml
+++ b/app/code/Magento/CatalogRule/view/adminhtml/templates/promo/js.phtml
@@ -13,15 +13,53 @@ function hideShowSubproductOptions()
         $('rule_sub_simple_action').up('div.field').show();
         $('rule_sub_discount_amount').up('div.field').show();
         $('rule_sub_discount_amount').addClassName('required-entry validate-not-negative-number');
+        changeValidationForSubDiscountPercent();
     } else {
+        $('rule_sub_discount_amount').
+            removeClassName('required-entry').
+            removeClassName('validate-not-negative-number').
+            removeClassName('validate-number-range').
+            removeClassName('number-range-0.00-100.00');
         $('rule_sub_simple_action').up('div.field').hide();
         $('rule_sub_discount_amount').up('div.field').hide();
-        $('rule_sub_discount_amount').removeClassName('required-entry').removeClassName('validate-not-negative-number');
     }
 
     return true;
 }
+
+function changeValidationForDiscountPercent()
+{
+    if ($('rule_simple_action').value == 'by_percent' || $('rule_simple_action').value == 'to_percent') {
+        $('rule_discount_amount').addClassName('validate-number-range number-range-0.00-100.00');
+    } else {
+        $('rule_discount_amount').removeClassName('validate-number-range').removeClassName('number-range-0.00-100.00');
+    }
+
+    return true;
+}
+
+function changeValidationForSubDiscountPercent()
+{
+    if ($('rule_sub_is_enable').value == 1) {
+        if ($('rule_sub_simple_action').value == 'by_percent' || $('rule_sub_simple_action').value == 'to_percent') {
+            $('rule_sub_discount_amount').addClassName('validate-number-range number-range-0.00-100.00');
+        } else {
+            $('rule_sub_discount_amount').
+                removeClassName('validate-number-range').
+                removeClassName('number-range-0.00-100.00');
+        }
+    }
+
+    return true;
+}
+
 jQuery(document).ready(hideShowSubproductOptions);
+jQuery(document).ready(changeValidationForDiscountPercent);
+jQuery(document).on('change', '#rule_sub_is_enable', hideShowSubproductOptions);
+jQuery(document).on('change', '#rule_simple_action', changeValidationForDiscountPercent);
+jQuery(document).on('change', '#rule_sub_simple_action', changeValidationForSubDiscountPercent);
 window.hideShowSubproductOptions = hideShowSubproductOptions;
+window.changeValidationForDiscountPercent = changeValidationForDiscountPercent;
+window.changeValidationForSubDiscountPercent = changeValidationForSubDiscountPercent;
 });
 </script>
diff --git a/app/code/Magento/CatalogRuleConfigurable/LICENSE.txt b/app/code/Magento/CatalogRuleConfigurable/LICENSE.txt
new file mode 100644
index 0000000000000000000000000000000000000000..49525fd99da9c51e6d85420266d41cb3d6b7a648
--- /dev/null
+++ b/app/code/Magento/CatalogRuleConfigurable/LICENSE.txt
@@ -0,0 +1,48 @@
+
+Open Software License ("OSL") v. 3.0
+
+This Open Software License (the "License") applies to any original work of authorship (the "Original Work") whose owner (the "Licensor") has placed the following licensing notice adjacent to the copyright notice for the Original Work:
+
+Licensed under the Open Software License version 3.0
+
+   1. Grant of Copyright License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, for the duration of the copyright, to do the following:
+
+         1. to reproduce the Original Work in copies, either alone or as part of a collective work;
+
+         2. to translate, adapt, alter, transform, modify, or arrange the Original Work, thereby creating derivative works ("Derivative Works") based upon the Original Work;
+
+         3. to distribute or communicate copies of the Original Work and Derivative Works to the public, with the proviso that copies of Original Work or Derivative Works that You distribute or communicate shall be licensed under this Open Software License;
+
+         4. to perform the Original Work publicly; and
+
+         5. to display the Original Work publicly. 
+
+   2. Grant of Patent License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, under patent claims owned or controlled by the Licensor that are embodied in the Original Work as furnished by the Licensor, for the duration of the patents, to make, use, sell, offer for sale, have made, and import the Original Work and Derivative Works.
+
+   3. Grant of Source Code License. The term "Source Code" means the preferred form of the Original Work for making modifications to it and all available documentation describing how to modify the Original Work. Licensor agrees to provide a machine-readable copy of the Source Code of the Original Work along with each copy of the Original Work that Licensor distributes. Licensor reserves the right to satisfy this obligation by placing a machine-readable copy of the Source Code in an information repository reasonably calculated to permit inexpensive and convenient access by You for as long as Licensor continues to distribute the Original Work.
+
+   4. Exclusions From License Grant. Neither the names of Licensor, nor the names of any contributors to the Original Work, nor any of their trademarks or service marks, may be used to endorse or promote products derived from this Original Work without express prior permission of the Licensor. Except as expressly stated herein, nothing in this License grants any license to Licensor's trademarks, copyrights, patents, trade secrets or any other intellectual property. No patent license is granted to make, use, sell, offer for sale, have made, or import embodiments of any patent claims other than the licensed claims defined in Section 2. No license is granted to the trademarks of Licensor even if such marks are included in the Original Work. Nothing in this License shall be interpreted to prohibit Licensor from licensing under terms different from this License any Original Work that Licensor otherwise would have a right to license.
+
+   5. External Deployment. The term "External Deployment" means the use, distribution, or communication of the Original Work or Derivative Works in any way such that the Original Work or Derivative Works may be used by anyone other than You, whether those works are distributed or communicated to those persons or made available as an application intended for use over a network. As an express condition for the grants of license hereunder, You must treat any External Deployment by You of the Original Work or a Derivative Work as a distribution under section 1(c).
+
+   6. Attribution Rights. You must retain, in the Source Code of any Derivative Works that You create, all copyright, patent, or trademark notices from the Source Code of the Original Work, as well as any notices of licensing and any descriptive text identified therein as an "Attribution Notice." You must cause the Source Code for any Derivative Works that You create to carry a prominent Attribution Notice reasonably calculated to inform recipients that You have modified the Original Work.
+
+   7. Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that the copyright in and to the Original Work and the patent rights granted herein by Licensor are owned by the Licensor or are sublicensed to You under the terms of this License with the permission of the contributor(s) of those copyrights and patent rights. Except as expressly stated in the immediately preceding sentence, the Original Work is provided under this License on an "AS IS" BASIS and WITHOUT WARRANTY, either express or implied, including, without limitation, the warranties of non-infringement, merchantability or fitness for a particular purpose. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No license to the Original Work is granted by this License except under this disclaimer.
+
+   8. Limitation of Liability. Under no circumstances and under no legal theory, whether in tort (including negligence), contract, or otherwise, shall the Licensor be liable to anyone for any indirect, special, incidental, or consequential damages of any character arising as a result of this License or the use of the Original Work including, without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses. This limitation of liability shall not apply to the extent applicable law prohibits such limitation.
+
+   9. Acceptance and Termination. If, at any time, You expressly assented to this License, that assent indicates your clear and irrevocable acceptance of this License and all of its terms and conditions. If You distribute or communicate copies of the Original Work or a Derivative Work, You must make a reasonable effort under the circumstances to obtain the express assent of recipients to the terms of this License. This License conditions your rights to undertake the activities listed in Section 1, including your right to create Derivative Works based upon the Original Work, and doing so without honoring these terms and conditions is prohibited by copyright law and international treaty. Nothing in this License is intended to affect copyright exceptions and limitations (including 'fair use' or 'fair dealing'). This License shall terminate immediately and You may no longer exercise any of the rights granted to You by this License upon your failure to honor the conditions in Section 1(c).
+
+  10. Termination for Patent Action. This License shall terminate automatically and You may no longer exercise any of the rights granted to You by this License as of the date You commence an action, including a cross-claim or counterclaim, against Licensor or any licensee alleging that the Original Work infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of the Original Work with other software or hardware.
+
+  11. Jurisdiction, Venue and Governing Law. Any action or suit relating to this License may be brought only in the courts of a jurisdiction wherein the Licensor resides or in which Licensor conducts its primary business, and under the laws of that jurisdiction excluding its conflict-of-law provisions. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any use of the Original Work outside the scope of this License or after its termination shall be subject to the requirements and penalties of copyright or patent law in the appropriate jurisdiction. This section shall survive the termination of this License.
+
+  12. Attorneys' Fees. In any action to enforce the terms of this License or seeking damages relating thereto, the prevailing party shall be entitled to recover its costs and expenses, including, without limitation, reasonable attorneys' fees and costs incurred in connection with such action, including any appeal of such action. This section shall survive the termination of this License.
+
+  13. Miscellaneous. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable.
+
+  14. Definition of "You" in This License. "You" throughout this License, whether in upper or lower case, means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with you. For purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
+
+  15. Right to Use. You may use the Original Work in all ways not otherwise restricted or conditioned by this License or by law, and Licensor promises not to interfere with or be responsible for such uses by You.
+
+  16. Modification of This License. This License is Copyright (C) 2005 Lawrence Rosen. Permission is granted to copy, distribute, or communicate this License without modification. Nothing in this License permits You to modify this License as applied to the Original Work or to Derivative Works. However, You may modify the text of this License and copy, distribute or communicate your modified version (the "Modified License") and apply it to other original works of authorship subject to the following conditions: (i) You may not indicate in any way that your Modified License is the "Open Software License" or "OSL" and you may not use those names in the name of your Modified License; (ii) You must replace the notice specified in the first paragraph above with the notice "Licensed under <insert your license name here>" or with a notice of your own that is not confusingly similar to the notice in this License; and (iii) You may not claim that your original works are open source software unless your Modified License has been approved by Open Source Initiative (OSI) and You comply with its license review and certification process.
\ No newline at end of file
diff --git a/app/code/Magento/CatalogRuleConfigurable/LICENSE_AFL.txt b/app/code/Magento/CatalogRuleConfigurable/LICENSE_AFL.txt
new file mode 100644
index 0000000000000000000000000000000000000000..87943b95d43a5bb8736093275afe3cb8e1d93d26
--- /dev/null
+++ b/app/code/Magento/CatalogRuleConfigurable/LICENSE_AFL.txt
@@ -0,0 +1,48 @@
+
+Academic Free License ("AFL") v. 3.0
+
+This Academic Free License (the "License") applies to any original work of authorship (the "Original Work") whose owner (the "Licensor") has placed the following licensing notice adjacent to the copyright notice for the Original Work:
+
+Licensed under the Academic Free License version 3.0
+
+   1. Grant of Copyright License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, for the duration of the copyright, to do the following:
+
+         1. to reproduce the Original Work in copies, either alone or as part of a collective work;
+
+         2. to translate, adapt, alter, transform, modify, or arrange the Original Work, thereby creating derivative works ("Derivative Works") based upon the Original Work;
+
+         3. to distribute or communicate copies of the Original Work and Derivative Works to the public, under any license of your choice that does not contradict the terms and conditions, including Licensor's reserved rights and remedies, in this Academic Free License;
+
+         4. to perform the Original Work publicly; and
+
+         5. to display the Original Work publicly.
+
+   2. Grant of Patent License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, under patent claims owned or controlled by the Licensor that are embodied in the Original Work as furnished by the Licensor, for the duration of the patents, to make, use, sell, offer for sale, have made, and import the Original Work and Derivative Works.
+
+   3. Grant of Source Code License. The term "Source Code" means the preferred form of the Original Work for making modifications to it and all available documentation describing how to modify the Original Work. Licensor agrees to provide a machine-readable copy of the Source Code of the Original Work along with each copy of the Original Work that Licensor distributes. Licensor reserves the right to satisfy this obligation by placing a machine-readable copy of the Source Code in an information repository reasonably calculated to permit inexpensive and convenient access by You for as long as Licensor continues to distribute the Original Work.
+
+   4. Exclusions From License Grant. Neither the names of Licensor, nor the names of any contributors to the Original Work, nor any of their trademarks or service marks, may be used to endorse or promote products derived from this Original Work without express prior permission of the Licensor. Except as expressly stated herein, nothing in this License grants any license to Licensor's trademarks, copyrights, patents, trade secrets or any other intellectual property. No patent license is granted to make, use, sell, offer for sale, have made, or import embodiments of any patent claims other than the licensed claims defined in Section 2. No license is granted to the trademarks of Licensor even if such marks are included in the Original Work. Nothing in this License shall be interpreted to prohibit Licensor from licensing under terms different from this License any Original Work that Licensor otherwise would have a right to license.
+
+   5. External Deployment. The term "External Deployment" means the use, distribution, or communication of the Original Work or Derivative Works in any way such that the Original Work or Derivative Works may be used by anyone other than You, whether those works are distributed or communicated to those persons or made available as an application intended for use over a network. As an express condition for the grants of license hereunder, You must treat any External Deployment by You of the Original Work or a Derivative Work as a distribution under section 1(c).
+
+   6. Attribution Rights. You must retain, in the Source Code of any Derivative Works that You create, all copyright, patent, or trademark notices from the Source Code of the Original Work, as well as any notices of licensing and any descriptive text identified therein as an "Attribution Notice." You must cause the Source Code for any Derivative Works that You create to carry a prominent Attribution Notice reasonably calculated to inform recipients that You have modified the Original Work.
+
+   7. Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that the copyright in and to the Original Work and the patent rights granted herein by Licensor are owned by the Licensor or are sublicensed to You under the terms of this License with the permission of the contributor(s) of those copyrights and patent rights. Except as expressly stated in the immediately preceding sentence, the Original Work is provided under this License on an "AS IS" BASIS and WITHOUT WARRANTY, either express or implied, including, without limitation, the warranties of non-infringement, merchantability or fitness for a particular purpose. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No license to the Original Work is granted by this License except under this disclaimer.
+
+   8. Limitation of Liability. Under no circumstances and under no legal theory, whether in tort (including negligence), contract, or otherwise, shall the Licensor be liable to anyone for any indirect, special, incidental, or consequential damages of any character arising as a result of this License or the use of the Original Work including, without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses. This limitation of liability shall not apply to the extent applicable law prohibits such limitation.
+
+   9. Acceptance and Termination. If, at any time, You expressly assented to this License, that assent indicates your clear and irrevocable acceptance of this License and all of its terms and conditions. If You distribute or communicate copies of the Original Work or a Derivative Work, You must make a reasonable effort under the circumstances to obtain the express assent of recipients to the terms of this License. This License conditions your rights to undertake the activities listed in Section 1, including your right to create Derivative Works based upon the Original Work, and doing so without honoring these terms and conditions is prohibited by copyright law and international treaty. Nothing in this License is intended to affect copyright exceptions and limitations (including "fair use" or "fair dealing"). This License shall terminate immediately and You may no longer exercise any of the rights granted to You by this License upon your failure to honor the conditions in Section 1(c).
+
+  10. Termination for Patent Action. This License shall terminate automatically and You may no longer exercise any of the rights granted to You by this License as of the date You commence an action, including a cross-claim or counterclaim, against Licensor or any licensee alleging that the Original Work infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of the Original Work with other software or hardware.
+
+  11. Jurisdiction, Venue and Governing Law. Any action or suit relating to this License may be brought only in the courts of a jurisdiction wherein the Licensor resides or in which Licensor conducts its primary business, and under the laws of that jurisdiction excluding its conflict-of-law provisions. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any use of the Original Work outside the scope of this License or after its termination shall be subject to the requirements and penalties of copyright or patent law in the appropriate jurisdiction. This section shall survive the termination of this License.
+
+  12. Attorneys' Fees. In any action to enforce the terms of this License or seeking damages relating thereto, the prevailing party shall be entitled to recover its costs and expenses, including, without limitation, reasonable attorneys' fees and costs incurred in connection with such action, including any appeal of such action. This section shall survive the termination of this License.
+
+  13. Miscellaneous. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable.
+
+  14. Definition of "You" in This License. "You" throughout this License, whether in upper or lower case, means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with you. For purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
+
+  15. Right to Use. You may use the Original Work in all ways not otherwise restricted or conditioned by this License or by law, and Licensor promises not to interfere with or be responsible for such uses by You.
+
+  16. Modification of This License. This License is Copyright © 2005 Lawrence Rosen. Permission is granted to copy, distribute, or communicate this License without modification. Nothing in this License permits You to modify this License as applied to the Original Work or to Derivative Works. However, You may modify the text of this License and copy, distribute or communicate your modified version (the "Modified License") and apply it to other original works of authorship subject to the following conditions: (i) You may not indicate in any way that your Modified License is the "Academic Free License" or "AFL" and you may not use those names in the name of your Modified License; (ii) You must replace the notice specified in the first paragraph above with the notice "Licensed under <insert your license name here>" or with a notice of your own that is not confusingly similar to the notice in this License; and (iii) You may not claim that your original works are open source software unless your Modified License has been approved by Open Source Initiative (OSI) and You comply with its license review and certification process.
\ No newline at end of file
diff --git a/app/code/Magento/CatalogRuleConfigurable/Plugin/CatalogRule/Model/ConfigurableProductsProvider.php b/app/code/Magento/CatalogRuleConfigurable/Plugin/CatalogRule/Model/ConfigurableProductsProvider.php
new file mode 100644
index 0000000000000000000000000000000000000000..c9a049eac678545bc27a8265aa6693e32b2f8966
--- /dev/null
+++ b/app/code/Magento/CatalogRuleConfigurable/Plugin/CatalogRule/Model/ConfigurableProductsProvider.php
@@ -0,0 +1,37 @@
+<?php
+/**
+ *
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\CatalogRuleConfigurable\Plugin\CatalogRule\Model;
+
+class ConfigurableProductsProvider
+{
+    /** @var \Magento\Framework\App\Resource */
+    private $resource;
+
+    /**
+     * @param \Magento\Framework\App\Resource $resource
+     */
+    public function __construct(\Magento\Framework\App\Resource $resource)
+    {
+        $this->resource = $resource;
+    }
+
+    /**
+     * @param array $ids
+     * @return array
+     */
+    public function getIds(array $ids)
+    {
+        $connection = $this->resource->getConnection();
+        return $connection->fetchCol(
+            $connection
+                ->select()
+                ->from(['e' => $this->resource->getTableName('catalog_product_entity')], ['e.entity_id'])
+                ->where('e.type_id = ?', \Magento\ConfigurableProduct\Model\Product\Type\Configurable::TYPE_CODE)
+                ->where('e.entity_id IN (?)', $ids)
+        );
+    }
+}
diff --git a/app/code/Magento/CatalogRuleConfigurable/Plugin/CatalogRule/Model/Indexer/ProductRuleReindex.php b/app/code/Magento/CatalogRuleConfigurable/Plugin/CatalogRule/Model/Indexer/ProductRuleReindex.php
new file mode 100644
index 0000000000000000000000000000000000000000..642736cff51c735a74201e91b5fbbc0d8245040a
--- /dev/null
+++ b/app/code/Magento/CatalogRuleConfigurable/Plugin/CatalogRule/Model/Indexer/ProductRuleReindex.php
@@ -0,0 +1,93 @@
+<?php
+/**
+ *
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\CatalogRuleConfigurable\Plugin\CatalogRule\Model\Indexer;
+
+use Magento\ConfigurableProduct\Model\Product\Type\Configurable;
+use Magento\CatalogRuleConfigurable\Plugin\CatalogRule\Model\ConfigurableProductsProvider;
+
+/**
+ * Class ReindexProduct. Add configurable sub-products to reindex
+ */
+class ProductRuleReindex
+{
+    /** @var Configurable */
+    private $configurable;
+
+    /** @var ConfigurableProductsProvider */
+    private $configurableProductsProvider;
+
+    /**
+     * @param Configurable $configurable
+     * @param ConfigurableProductsProvider $configurableProductsProvider
+     */
+    public function __construct(
+        Configurable $configurable,
+        ConfigurableProductsProvider $configurableProductsProvider
+    ) {
+        $this->configurable = $configurable;
+        $this->configurableProductsProvider = $configurableProductsProvider;
+    }
+
+    /**
+     * @param \Magento\CatalogRule\Model\Indexer\Product\ProductRuleIndexer $subject
+     * @param \Closure $proceed
+     * @param int $id
+     *
+     * @return void
+     */
+    public function aroundExecuteRow(
+        \Magento\CatalogRule\Model\Indexer\Product\ProductRuleIndexer $subject,
+        \Closure $proceed,
+        $id
+    ) {
+        $configurableProductIds = $this->configurableProductsProvider->getIds([$id]);
+        $this->reindexSubProducts($configurableProductIds, $subject);
+        if (!$configurableProductIds) {
+            $proceed($id);
+        }
+    }
+
+    /**
+     * @param \Magento\CatalogRule\Model\Indexer\Product\ProductRuleIndexer $subject
+     * @param \Closure $proceed
+     * @param array $ids
+     *
+     * @return void
+     */
+    public function aroundExecuteList(
+        \Magento\CatalogRule\Model\Indexer\Product\ProductRuleIndexer $subject,
+        \Closure $proceed,
+        array $ids
+    ) {
+        $configurableProductIds = $this->configurableProductsProvider->getIds($ids);
+        $subProducts = $this->reindexSubProducts($configurableProductIds, $subject);
+        $ids = array_diff($ids, $configurableProductIds, $subProducts);
+        if ($ids) {
+            $proceed($ids);
+        }
+    }
+
+    /**
+     * @param array $configurableIds
+     * @param \Magento\CatalogRule\Model\Indexer\Product\ProductRuleIndexer $subject
+     *
+     * @return array
+     */
+    private function reindexSubProducts(
+        array $configurableIds,
+        \Magento\CatalogRule\Model\Indexer\Product\ProductRuleIndexer $subject
+    ) {
+        $subProducts = [];
+        if ($configurableIds) {
+            $subProducts = array_values($this->configurable->getChildrenIds($configurableIds)[0]);
+            if ($subProducts) {
+                $subject->executeList($subProducts);
+            }
+        }
+        return $subProducts;
+    }
+}
diff --git a/app/code/Magento/CatalogRuleConfigurable/Plugin/CatalogRule/Model/Rule/ConfigurableProductHandler.php b/app/code/Magento/CatalogRuleConfigurable/Plugin/CatalogRule/Model/Rule/ConfigurableProductHandler.php
new file mode 100644
index 0000000000000000000000000000000000000000..156ec7edd7ef743117ce6b61bd6259e92473b51c
--- /dev/null
+++ b/app/code/Magento/CatalogRuleConfigurable/Plugin/CatalogRule/Model/Rule/ConfigurableProductHandler.php
@@ -0,0 +1,83 @@
+<?php
+/**
+ *
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\CatalogRuleConfigurable\Plugin\CatalogRule\Model\Rule;
+
+use Magento\ConfigurableProduct\Model\Product\Type\Configurable;
+use Magento\CatalogRuleConfigurable\Plugin\CatalogRule\Model\ConfigurableProductsProvider;
+
+/**
+ * Add configurable sub products to catalog rule indexer on full reindex
+ */
+class ConfigurableProductHandler
+{
+    /** @var \Magento\ConfigurableProduct\Model\Resource\Product\Type\Configurable */
+    private $configurable;
+
+    /** @var ConfigurableProductsProvider */
+    private $configurableProductsProvider;
+
+    /** @var array */
+    private $subProductsValidationResults = [];
+
+    /**
+     * @param \Magento\ConfigurableProduct\Model\Resource\Product\Type\Configurable $configurable
+     * @param ConfigurableProductsProvider $configurableProductsProvider
+     */
+    public function __construct(
+        \Magento\ConfigurableProduct\Model\Resource\Product\Type\Configurable $configurable,
+        ConfigurableProductsProvider $configurableProductsProvider
+    ) {
+        $this->configurable = $configurable;
+        $this->configurableProductsProvider = $configurableProductsProvider;
+    }
+
+    /**
+     * @param \Magento\CatalogRule\Model\Rule $rule
+     * @param array $productIds
+     * @return array
+     */
+    public function afterGetMatchingProductIds(\Magento\CatalogRule\Model\Rule $rule, array $productIds)
+    {
+        $configurableProductIds = $this->configurableProductsProvider->getIds(array_keys($productIds));
+        foreach ($configurableProductIds as $productId) {
+            $subProductsIds = $this->configurable->getChildrenIds($productId)[0];
+            $parentValidationResult = $productIds[$productId];
+            foreach ($subProductsIds as $subProductsId) {
+                $productIds[$subProductsId] = $this->getSubProductValidationResult(
+                    $rule->getId(),
+                    $subProductsId,
+                    $parentValidationResult
+                );
+            }
+            unset($productIds[$productId]);
+        }
+        return $productIds;
+    }
+
+    /**
+     * Return validation result for sub-product.
+     * If any of configurable product is valid for current rule, then their sub-product must be valid too
+     *
+     * @param int $urlId
+     * @param int $subProductsId
+     * @param array $parentValidationResult
+     * @return array
+     */
+    private function getSubProductValidationResult($urlId, $subProductsId, $parentValidationResult)
+    {
+        if (!isset($this->subProductsValidationResults[$urlId][$subProductsId])) {
+            $this->subProductsValidationResults[$urlId][$subProductsId] = array_filter($parentValidationResult);
+        } else {
+            $parentValidationResult = array_intersect_key(
+                $this->subProductsValidationResults[$urlId][$subProductsId] + $parentValidationResult,
+                $parentValidationResult
+            );
+            $this->subProductsValidationResults[$urlId][$subProductsId] = $parentValidationResult;
+        }
+        return $parentValidationResult;
+    }
+}
diff --git a/app/code/Magento/CatalogRuleConfigurable/Plugin/CatalogRule/Model/Rule/Validation.php b/app/code/Magento/CatalogRuleConfigurable/Plugin/CatalogRule/Model/Rule/Validation.php
new file mode 100644
index 0000000000000000000000000000000000000000..0419af2307d710f0a42c1fa13498be23cca148b9
--- /dev/null
+++ b/app/code/Magento/CatalogRuleConfigurable/Plugin/CatalogRule/Model/Rule/Validation.php
@@ -0,0 +1,50 @@
+<?php
+/**
+ *
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\CatalogRuleConfigurable\Plugin\CatalogRule\Model\Rule;
+
+use \Magento\ConfigurableProduct\Model\Product\Type\Configurable;
+
+/**
+ * Class Validation. Call validate method for configurable product instead simple product
+ */
+class Validation
+{
+    /** @var Configurable */
+    private $configurable;
+
+    /**
+     * @param \Magento\ConfigurableProduct\Model\Product\Type\Configurable $configurableType
+     */
+    public function __construct(Configurable $configurableType)
+    {
+        $this->configurable = $configurableType;
+    }
+
+    /**
+     * @param \Magento\CatalogRule\Model\Rule $rule
+     * @param \Closure $proceed
+     * @param \Magento\Framework\DataObject|\Magento\Catalog\Model\Product $product
+     * @return bool
+     */
+    public function aroundValidate(
+        \Magento\CatalogRule\Model\Rule $rule,
+        \Closure $proceed,
+        \Magento\Framework\DataObject $product
+    ) {
+        $validateResult = $proceed($product);
+        if (!$validateResult && ($configurableProducts = $this->configurable->getParentIdsByChild($product->getId()))) {
+            foreach ($configurableProducts as $configurableProductId) {
+                $validateResult = $rule->getConditions()->validateByEntityId($configurableProductId);
+                // If any of configurable product is valid for current rule, then their sub-product must be valid too
+                if ($validateResult) {
+                    break;
+                }
+            }
+        }
+        return $validateResult;
+    }
+}
diff --git a/app/code/Magento/CatalogRuleConfigurable/README.md b/app/code/Magento/CatalogRuleConfigurable/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..35c3244db5a134d5f7efe13c45698fdbf77ea0e9
--- /dev/null
+++ b/app/code/Magento/CatalogRuleConfigurable/README.md
@@ -0,0 +1 @@
+Magento_CatalogRuleConfigurable module is an extension of Magento_CatalogRule and Magento_ConfigurableProduct modules that handle catalog rule indexer for configurable product
diff --git a/app/code/Magento/CatalogRuleConfigurable/Test/Unit/Plugin/CatalogRule/Model/Rule/ConfigurableProductHandlerTest.php b/app/code/Magento/CatalogRuleConfigurable/Test/Unit/Plugin/CatalogRule/Model/Rule/ConfigurableProductHandlerTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..54ced70d8e033151a87f5afed9de8a7eea947652
--- /dev/null
+++ b/app/code/Magento/CatalogRuleConfigurable/Test/Unit/Plugin/CatalogRule/Model/Rule/ConfigurableProductHandlerTest.php
@@ -0,0 +1,122 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\CatalogRuleConfigurable\Test\Unit\Plugin\CatalogRule\Model\Rule;
+
+use Magento\CatalogRuleConfigurable\Plugin\CatalogRule\Model\Rule\ConfigurableProductHandler;
+use Magento\ConfigurableProduct\Model\Resource\Product\Type\Configurable;
+use Magento\CatalogRuleConfigurable\Plugin\CatalogRule\Model\ConfigurableProductsProvider;
+
+/**
+ * Unit test for Magento\CatalogRuleConfigurable\Plugin\CatalogRule\Model\Rule\ConfigurableProductHandler
+ */
+class ConfigurableProductHandlerTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\CatalogRuleConfigurable\Plugin\CatalogRule\Model\Rule\ConfigurableProductHandler
+     */
+    private $configurableProductHandler;
+
+    /**
+     * @var Configurable|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $configurableMock;
+
+    /**
+     * @var ConfigurableProductsProvider|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $configurableProductsProviderMock;
+
+    /** @var \Magento\CatalogRule\Model\Rule||\PHPUnit_Framework_MockObject_MockObject */
+    private $ruleMock;
+
+    /**
+     * {@inheritDoc}
+     */
+    protected function setUp()
+    {
+        $this->configurableMock = $this->getMock(
+            'Magento\ConfigurableProduct\Model\Resource\Product\Type\Configurable',
+            ['getChildrenIds'],
+            [],
+            '',
+            false
+        );
+        $this->configurableProductsProviderMock = $this->getMock(
+            'Magento\CatalogRuleConfigurable\Plugin\CatalogRule\Model\ConfigurableProductsProvider',
+            ['getIds'],
+            [],
+            '',
+            false
+        );
+        $this->ruleMock = $this->getMock('Magento\CatalogRule\Model\Rule', [], [], '', false);
+
+        $this->configurableProductHandler = new ConfigurableProductHandler(
+            $this->configurableMock,
+            $this->configurableProductsProviderMock
+        );
+    }
+
+    /**
+     * @return void
+     */
+    public function testAfterGetMatchingProductIdsWithSimpleProduct()
+    {
+        $this->configurableProductsProviderMock->expects($this->once())->method('getIds')->willReturn([]);
+        $this->configurableMock->expects($this->never())->method('getChildrenIds');
+
+        $productIds = ['product' => 'valid results'];
+        $this->assertEquals(
+            $productIds,
+            $this->configurableProductHandler->afterGetMatchingProductIds($this->ruleMock, $productIds)
+        );
+    }
+
+    /**
+     * @return void
+     */
+    public function testAfterGetMatchingProductIdsWithConfigurableProduct()
+    {
+        $this->configurableProductsProviderMock->expects($this->once())->method('getIds')
+            ->willReturn(['conf1', 'conf2']);
+        $this->configurableMock->expects($this->any())->method('getChildrenIds')->willReturnMap([
+            ['conf1', true, [ 0 => ['simple1']]],
+            ['conf2', true, [ 0 => ['simple1', 'simple2']]],
+        ]);
+
+        $this->assertEquals(
+            [
+                'simple1' => [
+                    0 => true,
+                    1 => true,
+                    3 => true,
+                    4 => false,
+                ],
+                'simple2' => [
+                    0 => false,
+                    1 => false,
+                    3 => true,
+                    4 => false,
+                ]
+            ],
+            $this->configurableProductHandler->afterGetMatchingProductIds(
+                $this->ruleMock,
+                [
+                    'conf1' => [
+                        0 => true,
+                        1 => true,
+                    ],
+                    'conf2' => [
+                        0 => false,
+                        1 => false,
+                        3 => true,
+                        4 => false,
+                    ],
+                ]
+            )
+        );
+    }
+}
diff --git a/app/code/Magento/CatalogRuleConfigurable/Test/Unit/Plugin/CatalogRule/Model/Rule/ValidationTest.php b/app/code/Magento/CatalogRuleConfigurable/Test/Unit/Plugin/CatalogRule/Model/Rule/ValidationTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..a91a4b88f7fd4579516b19db4c871f4472294e84
--- /dev/null
+++ b/app/code/Magento/CatalogRuleConfigurable/Test/Unit/Plugin/CatalogRule/Model/Rule/ValidationTest.php
@@ -0,0 +1,128 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\CatalogRuleConfigurable\Test\Unit\Plugin\CatalogRule\Model\Rule;
+
+use Magento\CatalogRuleConfigurable\Plugin\CatalogRule\Model\Rule\Validation;
+
+/**
+ * Unit test for Magento\CatalogRuleConfigurable\Plugin\CatalogRule\Model\Rule\Validation
+ */
+class ValidationTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\CatalogRuleConfigurable\Plugin\CatalogRule\Model\Rule\Validation
+     */
+    private $validation;
+
+    /**
+     * @var \Magento\ConfigurableProduct\Model\Product\Type\Configurable|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $configurableMock;
+
+    /** @var \Magento\CatalogRule\Model\Rule|\PHPUnit_Framework_MockObject_MockObject */
+    private $ruleMock;
+
+    /** @var \Magento\Rule\Model\Condition\Combine|\PHPUnit_Framework_MockObject_MockObject */
+    private $ruleConditionsMock;
+
+    /** @var \Magento\Framework\DataObject|\PHPUnit_Framework_MockObject_MockObject */
+    private $productMock;
+
+    /**
+     * {@inheritDoc}
+     */
+    protected function setUp()
+    {
+        $this->configurableMock = $this->getMock(
+            'Magento\ConfigurableProduct\Model\Product\Type\Configurable',
+            ['getParentIdsByChild'],
+            [],
+            '',
+            false
+        );
+
+
+        $this->ruleMock = $this->getMock('Magento\CatalogRule\Model\Rule', [], [], '', false);
+        $this->ruleConditionsMock = $this->getMock('Magento\Rule\Model\Condition\Combine', [], [], '', false);
+        $this->productMock = $this->getMock('Magento\Framework\DataObject', ['getId']);
+
+        $this->validation = new Validation(
+            $this->configurableMock
+        );
+    }
+
+    /**
+     * @param $parentsIds
+     * @param $validationResult
+     * @param $runValidateAmount
+     * @param $result
+     * @dataProvider dataProviderForValidateWithValidConfigurableProduct
+     * @return void
+     */
+    public function testAroundValidateWithValidConfigurableProduct(
+        $parentsIds,
+        $validationResult,
+        $runValidateAmount,
+        $result
+    ) {
+        $closureMock = function () {
+            return false;
+        };
+
+        $this->productMock->expects($this->once())->method('getId')->willReturn('product_id');
+        $this->configurableMock->expects($this->once())->method('getParentIdsByChild')->with('product_id')
+            ->willReturn($parentsIds);
+        $this->ruleMock->expects($this->exactly($runValidateAmount))->method('getConditions')
+            ->willReturn($this->ruleConditionsMock);
+        $this->ruleConditionsMock->expects($this->exactly($runValidateAmount))->method('validateByEntityId')
+            ->willReturnMap($validationResult);
+
+        $this->assertEquals(
+            $result,
+            $this->validation->aroundValidate($this->ruleMock, $closureMock, $this->productMock)
+        );
+    }
+
+    /**
+     * @return array
+     */
+    public function dataProviderForValidateWithValidConfigurableProduct()
+    {
+        return [
+            [
+                [1, 2, 3],
+                [
+                    [1, false],
+                    [2, true],
+                    [3, true],
+                ],
+                2,
+                true,
+            ],
+            [
+                [1, 2, 3],
+                [
+                    [1, true],
+                    [2, false],
+                    [3, true],
+                ],
+                1,
+                true,
+            ],
+            [
+                [1, 2, 3],
+                [
+                    [1, false],
+                    [2, false],
+                    [3, false],
+                ],
+                3,
+                false,
+            ],
+        ];
+    }
+}
diff --git a/app/code/Magento/CatalogRuleConfigurable/composer.json b/app/code/Magento/CatalogRuleConfigurable/composer.json
new file mode 100644
index 0000000000000000000000000000000000000000..fc6bea322d3c59aacb561c8b166823a5d3ea0720
--- /dev/null
+++ b/app/code/Magento/CatalogRuleConfigurable/composer.json
@@ -0,0 +1,27 @@
+{
+    "name": "magento/module-catalog-rule-configurable",
+    "description": "N/A",
+    "require": {
+        "php": "~5.5.0|~5.6.0|~7.0.0",
+        "magento/module-configurable-product": "1.0.0-beta",
+        "magento/framework": "1.0.0-beta",
+        "magento/magento-composer-installer": "*"
+    },
+    "suggest": {
+        "magento/module-catalog-rule": "1.0.0-beta"
+    },
+    "type": "magento2-module",
+    "version": "1.0.0-beta",
+    "license": [
+        "OSL-3.0",
+        "AFL-3.0"
+    ],
+    "extra": {
+        "map": [
+            [
+                "*",
+                "Magento/CatalogRuleConfigurable"
+            ]
+        ]
+    }
+}
diff --git a/app/code/Magento/CatalogRuleConfigurable/etc/adminhtml/di.xml b/app/code/Magento/CatalogRuleConfigurable/etc/adminhtml/di.xml
new file mode 100644
index 0000000000000000000000000000000000000000..051dd103f5d62c20ad7315ab075ed3ee7b7cd22c
--- /dev/null
+++ b/app/code/Magento/CatalogRuleConfigurable/etc/adminhtml/di.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0"?>
+<!--
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+-->
+<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+        xsi:noNamespaceSchemaLocation="../../../../../../lib/internal/Magento/Framework/ObjectManager/etc/config.xsd">
+    <type name="Magento\CatalogRule\Model\Rule">
+        <plugin name="addVariationsToProductRule" type="Magento\CatalogRuleConfigurable\Plugin\CatalogRule\Model\Rule\ConfigurableProductHandler"/>
+        <plugin name="configurableChildValidation" type="Magento\CatalogRuleConfigurable\Plugin\CatalogRule\Model\Rule\Validation"/>
+    </type>
+    <type name="Magento\CatalogRule\Model\Indexer\Product\ProductRuleIndexer">
+        <plugin name="productRuleReindex" type="Magento\CatalogRuleConfigurable\Plugin\CatalogRule\Model\Indexer\ProductRuleReindex"/>
+    </type>
+</config>
diff --git a/app/code/Magento/CatalogRuleConfigurable/etc/module.xml b/app/code/Magento/CatalogRuleConfigurable/etc/module.xml
new file mode 100644
index 0000000000000000000000000000000000000000..ed99399ed8cc75369164307727b3e4be7b303625
--- /dev/null
+++ b/app/code/Magento/CatalogRuleConfigurable/etc/module.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0"?>
+<!--
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+-->
+<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../lib/internal/Magento/Framework/Module/etc/module.xsd">
+    <module name="Magento_CatalogRuleConfigurable" setup_version="2.0.0">
+        <sequence>
+            <module name="Magento_CatalogRule"/>
+            <module name="Magento_ConfigurableProduct"/>
+        </sequence>
+    </module>
+</config>
diff --git a/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Filter/Preprocessor.php b/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Filter/Preprocessor.php
index 037e4c3629e034b6ef57564abbcf8daa025f8644..8f8fb11c19d8513f40427af224ee2fe6921cb783 100644
--- a/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Filter/Preprocessor.php
+++ b/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Filter/Preprocessor.php
@@ -97,29 +97,26 @@ class Preprocessor implements PreprocessorInterface
      */
     private function processQueryWithField(FilterInterface $filter, $isNegation, $query)
     {
-        $currentStoreId = $this->scopeResolver->getScope()->getId();
-        $select = null;
         /** @var \Magento\Catalog\Model\Resource\Eav\Attribute $attribute */
         $attribute = $this->config->getAttribute(Product::ENTITY, $filter->getField());
-        $table = $attribute->getBackendTable();
         if ($filter->getField() === 'price') {
-            $filterQuery = str_replace(
+            $resultQuery = str_replace(
                 $this->connection->quoteIdentifier('price'),
                 $this->connection->quoteIdentifier('price_index.min_price'),
                 $query
             );
-            return $filterQuery;
         } elseif ($filter->getField() === 'category_ids') {
             return 'category_ids_index.category_id = ' . $filter->getValue();
         } elseif ($attribute->isStatic()) {
             $alias = $this->tableMapper->getMappingAlias($filter);
-            $filterQuery = str_replace(
+            $resultQuery = str_replace(
                 $this->connection->quoteIdentifier($attribute->getAttributeCode()),
                 $this->connection->quoteIdentifier($alias . '.' . $attribute->getAttributeCode()),
                 $query
             );
-            return $filterQuery;
-        } elseif ($filter->getType() === FilterInterface::TYPE_TERM) {
+        } elseif ($filter->getType() === FilterInterface::TYPE_TERM
+            && in_array($attribute->getFrontendInput(), ['select', 'multiselect'], true)
+        ) {
             $alias = $this->tableMapper->getMappingAlias($filter);
             if (is_array($filter->getValue())) {
                 $value = sprintf(
@@ -130,16 +127,18 @@ class Preprocessor implements PreprocessorInterface
             } else {
                 $value = ($isNegation ? '!' : '') . '= ' . $filter->getValue();
             }
-            $filterQuery = sprintf(
+            $resultQuery = sprintf(
                 '%1$s.value %2$s',
                 $alias,
                 $value
             );
-            return $filterQuery;
         } else {
+            $table = $attribute->getBackendTable();
             $select = $this->connection->select();
             $ifNullCondition = $this->connection->getIfNullSql('current_store.value', 'main_table.value');
 
+            $currentStoreId = $this->scopeResolver->getScope()->getId();
+
             $select->from(['main_table' => $table], 'entity_id')
                 ->joinLeft(
                     ['current_store' => $table],
@@ -154,10 +153,12 @@ class Preprocessor implements PreprocessorInterface
                 )
                 ->where('main_table.store_id = ?', Store::DEFAULT_STORE_ID)
                 ->having($query);
-        }
 
-        return 'search_index.entity_id IN (
-            select entity_id from  ' . $this->conditionManager->wrapBrackets($select) . ' as filter
+            $resultQuery = 'search_index.entity_id IN (
+                select entity_id from  ' . $this->conditionManager->wrapBrackets($select) . ' as filter
             )';
+        }
+
+        return $resultQuery;
     }
 }
diff --git a/app/code/Magento/CatalogSearch/Model/Search/TableMapper.php b/app/code/Magento/CatalogSearch/Model/Search/TableMapper.php
index c951e9b538f12e22367e682ce335742c3c2cccdf..5dd7633026068b4dea7253e9d5d36e1611a265c0 100644
--- a/app/code/Magento/CatalogSearch/Model/Search/TableMapper.php
+++ b/app/code/Magento/CatalogSearch/Model/Search/TableMapper.php
@@ -103,9 +103,10 @@ class TableMapper
         if ($fieldToTableMap) {
             list($alias, $table, $mapOn, $mappedFields) = $fieldToTableMap;
             $table = $this->resource->getTableName($table);
-        } elseif ($filter->getType() === FilterInterface::TYPE_TERM) {
-            $attribute = $this->getAttributeByCode($field);
-            if ($attribute) {
+        } elseif ($attribute = $this->getAttributeByCode($field)) {
+            if ($filter->getType() === FilterInterface::TYPE_TERM
+                && in_array($attribute->getFrontendInput(), ['select', 'multiselect'], true)
+            ) {
                 $table = $this->resource->getTableName('catalog_product_index_eav');
                 $alias = $field . '_filter';
                 $mapOn = sprintf(
@@ -115,21 +116,14 @@ class TableMapper
                     $this->getStoreId()
                 );
                 $mappedFields = [];
-            }
-        } else {
-            $attribute = $this->getAttributeByCode($field);
-            if ($attribute && $attribute->getBackendType() === AbstractAttribute::TYPE_STATIC) {
+            } elseif ($attribute->getBackendType() === AbstractAttribute::TYPE_STATIC) {
                 $table = $attribute->getBackendTable();
-                $alias = $this->getTableAlias($table);
+                $alias = $field . '_filter';
                 $mapOn = 'search_index.entity_id = ' . $alias . '.entity_id';
                 $mappedFields = null;
             }
         }
 
-        if (!$alias && $table) {
-            $alias = $this->getTableAlias($table);
-        }
-
         return [$alias, $table, $mapOn, $mappedFields];
     }
 
@@ -242,15 +236,6 @@ class TableMapper
         return array_key_exists($field, $fieldToTableMap) ? $fieldToTableMap[$field] : null;
     }
 
-    /**
-     * @param string $table
-     * @return string
-     */
-    private function getTableAlias($table)
-    {
-        return md5($table);
-    }
-
     /**
      * @param string $field
      * @return \Magento\Catalog\Model\Resource\Eav\Attribute
diff --git a/app/code/Magento/CatalogSearch/Test/Unit/Model/Adapter/Mysql/Filter/PreprocessorTest.php b/app/code/Magento/CatalogSearch/Test/Unit/Model/Adapter/Mysql/Filter/PreprocessorTest.php
index 2e5241e8e91f028334a05d333f623bc7981b473f..1208bf32c77a01fe1c692b7142660570be305b38 100644
--- a/app/code/Magento/CatalogSearch/Test/Unit/Model/Adapter/Mysql/Filter/PreprocessorTest.php
+++ b/app/code/Magento/CatalogSearch/Test/Unit/Model/Adapter/Mysql/Filter/PreprocessorTest.php
@@ -7,6 +7,7 @@
 namespace Magento\CatalogSearch\Test\Unit\Model\Adapter\Mysql\Filter;
 
 use Magento\Framework\DB\Select;
+use Magento\Framework\Search\Request\FilterInterface;
 use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper;
 use PHPUnit_Framework_MockObject_MockObject as MockObject;
 
@@ -46,7 +47,7 @@ class PreprocessorTest extends \PHPUnit_Framework_TestCase
     private $select;
 
     /**
-     * @var \Magento\Framework\Search\Request\FilterInterface|MockObject
+     * @var FilterInterface|MockObject
      */
     private $filter;
 
@@ -86,7 +87,7 @@ class PreprocessorTest extends \PHPUnit_Framework_TestCase
             ->disableOriginalConstructor()
             ->setMethods(['getId'])
             ->getMockForAbstractClass();
-        $this->scopeResolver->expects($this->once())
+        $this->scopeResolver->expects($this->any())
             ->method('getScope')
             ->will($this->returnValue($this->scope));
         $this->config = $this->getMockBuilder('\Magento\Eav\Model\Config')
@@ -95,7 +96,7 @@ class PreprocessorTest extends \PHPUnit_Framework_TestCase
             ->getMock();
         $this->attribute = $this->getMockBuilder('\Magento\Eav\Model\Entity\Attribute\AbstractAttribute')
             ->disableOriginalConstructor()
-            ->setMethods(['getBackendTable', 'isStatic', 'getAttributeId', 'getAttributeCode'])
+            ->setMethods(['getBackendTable', 'isStatic', 'getAttributeId', 'getAttributeCode', 'getFrontendInput'])
             ->getMockForAbstractClass();
         $this->resource = $resource = $this->getMockBuilder('\Magento\Framework\App\Resource')
             ->disableOriginalConstructor()
@@ -120,7 +121,7 @@ class PreprocessorTest extends \PHPUnit_Framework_TestCase
             ->will($this->returnValue($this->connection));
         $this->filter = $this->getMockBuilder('\Magento\Framework\Search\Request\FilterInterface')
             ->disableOriginalConstructor()
-            ->setMethods(['getField', 'getValue'])
+            ->setMethods(['getField', 'getValue', 'getType'])
             ->getMockForAbstractClass();
 
         $this->conditionManager->expects($this->any())
@@ -154,11 +155,9 @@ class PreprocessorTest extends \PHPUnit_Framework_TestCase
     public function testProcessPrice()
     {
         $expectedResult = 'price_index.min_price = 23';
-        $scopeId = 0;
         $isNegation = false;
         $query = 'price = 23';
 
-        $this->scope->expects($this->once())->method('getId')->will($this->returnValue($scopeId));
         $this->filter->expects($this->exactly(2))
             ->method('getField')
             ->will($this->returnValue('price'));
@@ -174,11 +173,9 @@ class PreprocessorTest extends \PHPUnit_Framework_TestCase
     public function testProcessCategoryIds()
     {
         $expectedResult = 'category_ids_index.category_id = FilterValue';
-        $scopeId = 0;
         $isNegation = false;
         $query = 'SELECT category_ids FROM catalog_product_entity';
 
-        $this->scope->expects($this->once())->method('getId')->will($this->returnValue($scopeId));
         $this->filter->expects($this->exactly(3))
             ->method('getField')
             ->will($this->returnValue('category_ids'));
@@ -199,7 +196,6 @@ class PreprocessorTest extends \PHPUnit_Framework_TestCase
     public function testProcessStaticAttribute()
     {
         $expectedResult = 'attr_table_alias.static_attribute LIKE %name%';
-        $scopeId = 0;
         $isNegation = false;
         $query = 'static_attribute LIKE %name%';
 
@@ -207,7 +203,6 @@ class PreprocessorTest extends \PHPUnit_Framework_TestCase
             ->willReturn('static_attribute');
         $this->tableMapper->expects($this->once())->method('getMappingAlias')
             ->willReturn('attr_table_alias');
-        $this->scope->expects($this->once())->method('getId')->will($this->returnValue($scopeId));
         $this->filter->expects($this->exactly(3))
             ->method('getField')
             ->will($this->returnValue('static_attribute'));
@@ -218,14 +213,100 @@ class PreprocessorTest extends \PHPUnit_Framework_TestCase
         $this->attribute->expects($this->once())
             ->method('isStatic')
             ->will($this->returnValue(true));
-        $this->attribute->expects($this->once())
-            ->method('getBackendTable')
-            ->will($this->returnValue('backend_table'));
 
         $actualResult = $this->target->process($this->filter, $isNegation, $query);
         $this->assertSame($expectedResult, $this->removeWhitespaces($actualResult));
     }
 
+    /**
+     * @dataProvider testTermFilterDataProvider
+     */
+    public function testProcessTermFilter($frontendInput, $fieldValue, $isNegation, $expected)
+    {
+        $this->config->expects($this->exactly(1))
+            ->method('getAttribute')
+            ->with(\Magento\Catalog\Model\Product::ENTITY, 'termField')
+            ->will($this->returnValue($this->attribute));
+
+        $this->attribute->expects($this->once())
+            ->method('isStatic')
+            ->will($this->returnValue(false));
+
+        $this->filter->expects($this->once())
+            ->method('getType')
+            ->willReturn(FilterInterface::TYPE_TERM);
+        $this->attribute->expects($this->once())
+            ->method('getFrontendInput')
+            ->willReturn($frontendInput);
+
+        $this->tableMapper->expects($this->once())->method('getMappingAlias')
+            ->willReturn('termAttrAlias');
+
+        $this->filter->expects($this->exactly(3))
+            ->method('getField')
+            ->willReturn('termField');
+        $this->filter->expects($this->exactly(2))
+            ->method('getValue')
+        ->willReturn($fieldValue);
+
+        $actualResult = $this->target->process($this->filter, $isNegation, 'This filter is not depends on used query');
+        $this->assertSame($expected, $this->removeWhitespaces($actualResult));
+    }
+
+    public function testTermFilterDataProvider()
+    {
+        return [
+            'selectPositiveEqual' => [
+                'frontendInput' => 'select',
+                'fieldValue' => 'positiveValue',
+                'isNegation' => false,
+                'expected' => 'termAttrAlias.value = positiveValue',
+            ],
+            'selectPositiveArray' => [
+                'frontendInput' => 'select',
+                'fieldValue' => [2, 3, 15],
+                'isNegation' => false,
+                'expected' => 'termAttrAlias.value IN (2,3,15)',
+            ],
+            'selectNegativeEqual' => [
+                'frontendInput' => 'select',
+                'fieldValue' => 'positiveValue',
+                'isNegation' => true,
+                'expected' => 'termAttrAlias.value != positiveValue',
+            ],
+            'selectNegativeArray' => [
+                'frontendInput' => 'select',
+                'fieldValue' => [4, 3, 42],
+                'isNegation' => true,
+                'expected' => 'termAttrAlias.value NOT IN (4,3,42)',
+            ],
+            'multiSelectPositiveEqual' => [
+                'frontendInput' => 'multiselect',
+                'fieldValue' => 'positiveValue',
+                'isNegation' => false,
+                'expected' => 'termAttrAlias.value = positiveValue',
+            ],
+            'multiSelectPositiveArray' => [
+                'frontendInput' => 'multiselect',
+                'fieldValue' => [2, 3, 15],
+                'isNegation' => false,
+                'expected' => 'termAttrAlias.value IN (2,3,15)',
+            ],
+            'multiSelectNegativeEqual' => [
+                'frontendInput' => 'multiselect',
+                'fieldValue' => 'negativeValue',
+                'isNegation' => true,
+                'expected' => 'termAttrAlias.value != negativeValue',
+            ],
+            'multiSelectNegativeArray' => [
+                'frontendInput' => 'multiselect',
+                'fieldValue' => [4, 3, 42],
+                'isNegation' => true,
+                'expected' => 'termAttrAlias.value NOT IN (4,3,42)',
+            ],
+        ];
+    }
+
     public function testProcessNotStaticAttribute()
     {
         $expectedResult = 'search_index.entity_id IN (select entity_id from (TEST QUERY PART) as filter)';
diff --git a/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/TableMapperTest.php b/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/TableMapperTest.php
index 60a8bbbd47b827d32b4dc7c0994cb4422e66742b..f888803a1db621e6c9af3c07da658a9a8d32b5ee 100644
--- a/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/TableMapperTest.php
+++ b/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/TableMapperTest.php
@@ -167,15 +167,15 @@ class TableMapperTest extends \PHPUnit_Framework_TestCase
     {
         $priceFilter = $this->createRangeFilter('static');
         $query = $this->createFilterQuery($priceFilter);
-        $this->createAttributeMock('static', 'static', 'backend_table', 0);
+        $this->createAttributeMock('static', 'static', 'backend_table', 0, 'select');
         $this->request->expects($this->once())
             ->method('getQuery')
             ->willReturn($query);
         $this->select->expects($this->once())
             ->method('joinLeft')
             ->with(
-                ['4111c4a3daddb5c5dba31cdac705114b' => 'backend_table'],
-                'search_index.entity_id = 4111c4a3daddb5c5dba31cdac705114b.entity_id',
+                ['static_filter' => 'backend_table'],
+                'search_index.entity_id = static_filter.entity_id',
                 null
             )
             ->willReturnSelf();
@@ -204,7 +204,7 @@ class TableMapperTest extends \PHPUnit_Framework_TestCase
 
     public function testAddTermFilter()
     {
-        $this->createAttributeMock('color', null, null, 132, 0);
+        $this->createAttributeMock('color', null, null, 132, 'select', 0);
         $categoryIdsFilter = $this->createTermFilter('color');
         $query = $this->createFilterQuery($categoryIdsFilter);
         $this->request->expects($this->once())
@@ -226,9 +226,9 @@ class TableMapperTest extends \PHPUnit_Framework_TestCase
 
     public function testAddBoolQueryWithTermFiltersInside()
     {
-        $this->createAttributeMock('must1', null, null, 101, 0);
-        $this->createAttributeMock('should1', null, null, 102, 1);
-        $this->createAttributeMock('mustNot1', null, null, 103, 2);
+        $this->createAttributeMock('must1', null, null, 101, 'select', 0);
+        $this->createAttributeMock('should1', null, null, 102, 'select', 1);
+        $this->createAttributeMock('mustNot1', null, null, 103, 'select', 2);
 
         $query = $this->createBoolQuery(
             [
@@ -280,9 +280,9 @@ class TableMapperTest extends \PHPUnit_Framework_TestCase
 
     public function testAddBoolQueryWithTermAndPriceFiltersInside()
     {
-        $this->createAttributeMock('must1', null, null, 101, 0);
-        $this->createAttributeMock('should1', null, null, 102, 1);
-        $this->createAttributeMock('mustNot1', null, null, 103, 2);
+        $this->createAttributeMock('must1', null, null, 101, 'select', 0);
+        $this->createAttributeMock('should1', null, null, 102, 'select', 1);
+        $this->createAttributeMock('mustNot1', null, null, 103, 'select', 2);
         $query = $this->createBoolQuery(
             [
                 $this->createFilterQuery($this->createTermFilter('must1')),
@@ -342,9 +342,9 @@ class TableMapperTest extends \PHPUnit_Framework_TestCase
 
     public function testAddBoolFilterWithTermFiltersInside()
     {
-        $this->createAttributeMock('must1', null, null, 101, 0);
-        $this->createAttributeMock('should1', null, null, 102, 1);
-        $this->createAttributeMock('mustNot1', null, null, 103, 2);
+        $this->createAttributeMock('must1', null, null, 101, 'select', 0);
+        $this->createAttributeMock('should1', null, null, 102, 'select', 1);
+        $this->createAttributeMock('mustNot1', null, null, 103, 'select', 2);
         $query = $this->createFilterQuery(
             $this->createBoolFilter(
                 [
@@ -397,9 +397,9 @@ class TableMapperTest extends \PHPUnit_Framework_TestCase
 
     public function testAddBoolFilterWithBoolFiltersInside()
     {
-        $this->createAttributeMock('must1', null, null, 101, 0);
-        $this->createAttributeMock('should1', null, null, 102, 1);
-        $this->createAttributeMock('mustNot1', null, null, 103, 2);
+        $this->createAttributeMock('must1', null, null, 101, 'select', 0);
+        $this->createAttributeMock('should1', null, null, 102, 'select', 1);
+        $this->createAttributeMock('mustNot1', null, null, 103, 'select', 2);
         $query = $this->createFilterQuery(
             $this->createBoolFilter(
                 [
@@ -563,6 +563,7 @@ class TableMapperTest extends \PHPUnit_Framework_TestCase
      * @param string $backendType
      * @param string $backendTable
      * @param int $attributeId
+     * @param string $frontendInput
      * @param int $positionInCollection
      */
     private function createAttributeMock(
@@ -570,10 +571,11 @@ class TableMapperTest extends \PHPUnit_Framework_TestCase
         $backendType = null,
         $backendTable = null,
         $attributeId = 120,
+        $frontendInput = 'select',
         $positionInCollection = 0
     ) {
         $attribute = $this->getMockBuilder('\Magento\Catalog\Model\Resource\Eav\Attribute')
-            ->setMethods(['getBackendType', 'getBackendTable', 'getId'])
+            ->setMethods(['getBackendType', 'getBackendTable', 'getId', 'getFrontendInput'])
             ->disableOriginalConstructor()
             ->getMock();
         $attribute->method('getId')
@@ -582,6 +584,8 @@ class TableMapperTest extends \PHPUnit_Framework_TestCase
             ->willReturn($backendType);
         $attribute->method('getBackendTable')
             ->willReturn($backendTable);
+        $attribute->method('getFrontendInput')
+            ->willReturn($frontendInput);
         $this->attributeCollection->expects($this->at($positionInCollection))
             ->method('getItemByColumnValue')
             ->with('attribute_code', $code)
diff --git a/app/code/Magento/CatalogSearch/view/frontend/layout/default.xml b/app/code/Magento/CatalogSearch/view/frontend/layout/default.xml
index c04fedb21f0f325e1a96e05c03610ba5e0746325..892395ec75e3ec1735901258972bc4a589ca97eb 100644
--- a/app/code/Magento/CatalogSearch/view/frontend/layout/default.xml
+++ b/app/code/Magento/CatalogSearch/view/frontend/layout/default.xml
@@ -15,6 +15,9 @@
                 <arguments>
                     <argument name="label" xsi:type="string">Advanced Search</argument>
                     <argument name="path" xsi:type="string">catalogsearch/advanced</argument>
+                    <argument name="attributes" xsi:type="array">
+                        <item name="data-action" xsi:type="string">advanced-search</item>
+                    </argument>
                 </arguments>
             </block>
         </referenceBlock>
diff --git a/app/code/Magento/CatalogSearch/view/frontend/templates/advanced/link.phtml b/app/code/Magento/CatalogSearch/view/frontend/templates/advanced/link.phtml
index d2558ea32ae0a181fc5895594e21de6acb6a1451..4b84bb7c6e7d1d3a878f992e3c60e2d18f7fe6ee 100644
--- a/app/code/Magento/CatalogSearch/view/frontend/templates/advanced/link.phtml
+++ b/app/code/Magento/CatalogSearch/view/frontend/templates/advanced/link.phtml
@@ -10,7 +10,7 @@
 $helper = $this->helper('Magento\CatalogSearch\Helper\Data');
 ?>
 <div class="nested">
-    <a class="action advanced" href="<?php /* @escapeNotVerified */ echo $helper->getAdvancedSearchUrl(); ?>">
+    <a class="action advanced" href="<?php /* @escapeNotVerified */ echo $helper->getAdvancedSearchUrl(); ?>" data-action="advanced-search">
         <?php /* @escapeNotVerified */ echo __('Advanced Search'); ?>
     </a>
 </div>
diff --git a/app/code/Magento/CatalogUrlRewrite/Model/Product/Plugin/Import.php b/app/code/Magento/CatalogUrlRewrite/Model/Product/Plugin/Import.php
index d83d347f4b65ea687b61254cb8195b3e0c6fa739..45ac3244d56e2757656c499951124707a40f2a4d 100644
--- a/app/code/Magento/CatalogUrlRewrite/Model/Product/Plugin/Import.php
+++ b/app/code/Magento/CatalogUrlRewrite/Model/Product/Plugin/Import.php
@@ -320,12 +320,14 @@ class Import
         $urls = [];
         foreach ($this->products as $productId => $productsByStores) {
             foreach ($productsByStores as $storeId => $product) {
-                $urls[] = $this->urlRewriteFactory->create()
-                    ->setEntityType(ProductUrlRewriteGenerator::ENTITY_TYPE)
-                    ->setEntityId($productId)
-                    ->setRequestPath($this->productUrlPathGenerator->getUrlPathWithSuffix($product, $storeId))
-                    ->setTargetPath($this->productUrlPathGenerator->getCanonicalUrlPath($product))
-                    ->setStoreId($storeId);
+                if ($this->productUrlPathGenerator->getUrlPath($product)) {
+                    $urls[] = $this->urlRewriteFactory->create()
+                        ->setEntityType(ProductUrlRewriteGenerator::ENTITY_TYPE)
+                        ->setEntityId($productId)
+                        ->setRequestPath($this->productUrlPathGenerator->getUrlPathWithSuffix($product, $storeId))
+                        ->setTargetPath($this->productUrlPathGenerator->getCanonicalUrlPath($product))
+                        ->setStoreId($storeId);
+                }
             }
         }
 
diff --git a/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/Product/Plugin/ImportTest.php b/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/Product/Plugin/ImportTest.php
index 296a19e9374dac89b3c39fef8ab6c8f2df8275b4..b462b7b658031d59211567a0ee31d0d6166f2d27 100644
--- a/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/Product/Plugin/ImportTest.php
+++ b/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/Product/Plugin/ImportTest.php
@@ -670,7 +670,7 @@ class ImportTest extends \PHPUnit_Framework_TestCase
     /**
      * Cover canonicalUrlRewriteGenerate().
      */
-    public function testCanonicalUrlRewriteGenerate()
+    public function testCanonicalUrlRewriteGenerateWithUrlPath()
     {
         $productId = 'product_id';
         $requestPath = 'simple-product.html';
@@ -691,6 +691,10 @@ class ImportTest extends \PHPUnit_Framework_TestCase
             ->expects($this->once())
             ->method('getUrlPathWithSuffix')
             ->will($this->returnValue($requestPath));
+        $this->productUrlPathGenerator
+            ->expects($this->once())
+            ->method('getUrlPath')
+            ->will($this->returnValue('urlPath'));
         $this->productUrlPathGenerator
             ->expects($this->once())
             ->method('getCanonicalUrlPath')
@@ -734,6 +738,36 @@ class ImportTest extends \PHPUnit_Framework_TestCase
         );
     }
 
+    /**
+     * Cover canonicalUrlRewriteGenerate().
+     */
+    public function testCanonicalUrlRewriteGenerateWithEmptyUrlPath()
+    {
+        $productId = 'product_id';
+        $storeId = 10;
+        $product = $this
+            ->getMockBuilder('Magento\Catalog\Model\Product')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $productsByStores = [$storeId => $product];
+        $products = [
+            $productId => $productsByStores,
+        ];
+
+        $this->setPropertyValue($this->import, 'products', $products);
+
+        $this->productUrlPathGenerator
+            ->expects($this->once())
+            ->method('getUrlPath')
+            ->will($this->returnValue(''));
+        $this->urlRewriteFactory
+            ->expects($this->never())
+            ->method('create');
+
+        $actualResult = $this->invokeMethod($this->import, 'canonicalUrlRewriteGenerate');
+        $this->assertEquals([], $actualResult);
+    }
+
     /**
      * Cover categoriesUrlRewriteGenerate().
      */
diff --git a/app/code/Magento/Checkout/Block/Cart/Crosssell.php b/app/code/Magento/Checkout/Block/Cart/Crosssell.php
index 2eb54a9bbddd1f97bd53816b149833a7b8e350a8..ba11d5c4aad2a22dd40d45f17b68ffe044af8445 100644
--- a/app/code/Magento/Checkout/Block/Cart/Crosssell.php
+++ b/app/code/Magento/Checkout/Block/Cart/Crosssell.php
@@ -199,8 +199,6 @@ class Crosssell extends \Magento\Catalog\Block\Product\AbstractProduct
         );
         $this->_addProductAttributesAndPrices($collection);
 
-        $this->stockHelper->addInStockFilterToCollection($collection);
-
         return $collection;
     }
 }
diff --git a/app/code/Magento/Config/Model/Config/Backend/Admin/Custom.php b/app/code/Magento/Config/Model/Config/Backend/Admin/Custom.php
index 300b9bd89f898fb92bf574df310b9a1858cd6b88..21549a5862ae9420010f50d906cf26d9029cccf7 100644
--- a/app/code/Magento/Config/Model/Config/Backend/Admin/Custom.php
+++ b/app/code/Magento/Config/Model/Config/Backend/Admin/Custom.php
@@ -18,12 +18,37 @@ class Custom extends \Magento\Framework\App\Config\Value
     const CONFIG_SCOPE_ID = 0;
 
     const XML_PATH_UNSECURE_BASE_URL = 'web/unsecure/base_url';
-
     const XML_PATH_SECURE_BASE_URL = 'web/secure/base_url';
-
     const XML_PATH_UNSECURE_BASE_LINK_URL = 'web/unsecure/base_link_url';
-
     const XML_PATH_SECURE_BASE_LINK_URL = 'web/secure/base_link_url';
+    const XML_PATH_CURRENCY_OPTIONS_BASE = 'currency/options/base';
+    const XML_PATH_ADMIN_SECURITY_USEFORMKEY = 'admin/security/use_form_key';
+    const XML_PATH_MAINTENANCE_MODE = 'maintenance_mode';
+    const XML_PATH_WEB_COOKIE_COOKIE_LIFETIME = 'web/cookie/cookie_lifetime';
+    const XML_PATH_WEB_COOKIE_COOKE_PATH = 'web/cookie/cookie_path';
+    const XML_PATH_WEB_COOKIE_COOKIE_DOMAIN = 'web/cookie/cookie_domain';
+    const XML_PATH_WEB_COOKIE_HTTPONLY = 'web/cookie/cookie_httponly';
+    const XML_PATH_WEB_COOKIE_RESTRICTION = 'web/cookie/cookie_restriction';
+    const XML_PATH_GENERAL_LOCALE_TIMEZONE = 'general/locale/timezone';
+    const XML_PATH_GENERAL_LOCALE_CODE = 'general/locale/code';
+    const XML_PATH_GENERAL_COUNTRY_DEFAULT = 'general/country/default';
+    const XML_PATH_SYSTEM_BACKUP_ENABLED = 'system/backup/enabled';
+    const XML_PATH_DEV_JS_MERGE_FILES = 'dev/js/merge_files';
+    const XML_PATH_DEV_JS_MINIFY_FILES = 'dev/js/minify_files';
+    const XML_PATH_DEV_CSS_MERGE_CSS_FILES = 'dev/css/merge_css_files';
+    const XML_PATH_DEV_CSS_MINIFY_FILES = 'dev/css/minify_files';
+    const XML_PATH_DEV_IMAGE_DEFAULT_ADAPTER = 'dev/image/default_adapter';
+    const XML_PATH_WEB_SESSION_USE_FRONTEND_SID = 'web/session/use_frontend_sid';
+    const XML_PATH_WEB_SESSION_USE_HTTP_X_FORWARDED_FOR = 'web/session/use_http_x_forwarded_for';
+    const XML_PATH_WEB_SESSION_USE_HTTP_VIA = 'web/session/use_http_via';
+    const XML_PATH_WEB_SESSION_USE_REMOTE_ADDR = 'web/session/use_remote_addr';
+    const XML_PATH_WEB_SESSION_USE_HTTP_USER_AGENT = 'web/session/use_http_user_agent';
+    const XML_PATH_CATALOG_FRONTEND_FLAT_CATALOG_CATEGORY = 'catalog/frontend/flat_catalog_category';
+    const XML_PATH_CATALOG_FRONTEND_FLAT_CATALOG_PRODUCT = 'catalog/frontend/flat_catalog_product';
+    const XML_PATH_TAX_WEEE_ENABLE = 'tax/weee/enable';
+    const XML_PATH_CATALOG_SEARCH_ENGINE = 'catalog/search/engine';
+    const XML_PATH_CARRIERS = 'carriers';
+    const XML_PATH_PAYMENT = 'payment';
 
     /* @var \Magento\Framework\App\Config\Storage\WriterInterface */
     protected $_configWriter;
diff --git a/app/code/Magento/Config/Model/Config/Structure/Mapper/Sorting.php b/app/code/Magento/Config/Model/Config/Structure/Mapper/Sorting.php
index 118108189fd5f6052a607e85b7824f38e72a7a56..a7271b7441e2609acb4c54e5f1a0fe9aa0c989df 100644
--- a/app/code/Magento/Config/Model/Config/Structure/Mapper/Sorting.php
+++ b/app/code/Magento/Config/Model/Config/Structure/Mapper/Sorting.php
@@ -51,11 +51,11 @@ class Sorting extends \Magento\Config\Model\Config\Structure\AbstractMapper
     {
         $sortIndexA = 0;
         if ($this->_hasValue('sortOrder', $elementA)) {
-            $sortIndexA = intval($elementA['sortOrder']);
+            $sortIndexA = floatval($elementA['sortOrder']);
         }
         $sortIndexB = 0;
         if ($this->_hasValue('sortOrder', $elementB)) {
-            $sortIndexB = intval($elementB['sortOrder']);
+            $sortIndexB = floatval($elementB['sortOrder']);
         }
 
         if ($sortIndexA == $sortIndexB) {
diff --git a/app/code/Magento/Config/etc/system.xsd b/app/code/Magento/Config/etc/system.xsd
index 4703d178f1a9e5c0c18df0eb67063d5bc9b310c5..3585f499ddc2429197369c0babbb8de74927ba40 100644
--- a/app/code/Magento/Config/etc/system.xsd
+++ b/app/code/Magento/Config/etc/system.xsd
@@ -48,7 +48,7 @@
     <xs:attributeGroup name="tabAttributeGroup">
         <xs:attribute name="id" type="typeId" use="required" />
         <xs:attribute name="translate" type="xs:string" use="optional" />
-        <xs:attribute name="sortOrder" type="xs:int" use="optional" />
+        <xs:attribute name="sortOrder" type="xs:float" use="optional" />
         <xs:attribute name="class" type="xs:string" use="optional" />
     </xs:attributeGroup>
 
@@ -56,7 +56,7 @@
         <xs:attribute name="id" type="typeId" use="required" />
         <xs:attribute name="translate" type="xs:string" use="optional" />
         <xs:attribute name="type" type="xs:string" use="optional" />
-        <xs:attribute name="sortOrder" type="xs:int" use="optional" />
+        <xs:attribute name="sortOrder" type="xs:float" use="optional" />
         <xs:attribute name="showInDefault" type="xs:int" use="optional" />
         <xs:attribute name="showInStore" type="xs:int" use="optional" />
         <xs:attribute name="showInWebsite" type="xs:int" use="optional" />
diff --git a/app/code/Magento/Config/etc/system_file.xsd b/app/code/Magento/Config/etc/system_file.xsd
index 89c8f2db61d9d649255c44d261a128cb98ee384f..0bbc99c6a07f7da7e44237e4f8bc716bf47bde92 100644
--- a/app/code/Magento/Config/etc/system_file.xsd
+++ b/app/code/Magento/Config/etc/system_file.xsd
@@ -49,7 +49,7 @@
     <xs:attributeGroup name="tabAttributeGroup">
         <xs:attribute name="id" type="typeId" use="required" />
         <xs:attribute name="translate" type="xs:string" use="optional" />
-        <xs:attribute name="sortOrder" type="xs:int" use="optional" />
+        <xs:attribute name="sortOrder" type="xs:float" use="optional" />
         <xs:attribute name="class" type="xs:string" use="optional" />
     </xs:attributeGroup>
 
@@ -57,7 +57,7 @@
         <xs:attribute name="id" type="typeId" use="required" />
         <xs:attribute name="translate" type="xs:string" use="optional" />
         <xs:attribute name="type" type="xs:string" use="optional" />
-        <xs:attribute name="sortOrder" type="xs:int" use="optional" />
+        <xs:attribute name="sortOrder" type="xs:float" use="optional" />
         <xs:attribute name="showInDefault" type="xs:int" use="optional" />
         <xs:attribute name="showInStore" type="xs:int" use="optional" />
         <xs:attribute name="showInWebsite" type="xs:int" use="optional" />
diff --git a/app/code/Magento/ConfigurableProduct/Block/Adminhtml/Product/Edit/Tab/Super/Config.php b/app/code/Magento/ConfigurableProduct/Block/Adminhtml/Product/Edit/Tab/Super/Config.php
index 500f85db85299e9b140690f3bb2911c9df46c445..456972bd31ddcfee71413f8ed0f6f4494459c11c 100644
--- a/app/code/Magento/ConfigurableProduct/Block/Adminhtml/Product/Edit/Tab/Super/Config.php
+++ b/app/code/Magento/ConfigurableProduct/Block/Adminhtml/Product/Edit/Tab/Super/Config.php
@@ -200,26 +200,6 @@ class Config extends Widget implements TabInterface
         return $data;
     }
 
-    /**
-     * Retrieve Grid child HTML
-     *
-     * @return string
-     */
-    public function getGridHtml()
-    {
-        return $this->getChildHtml('grid');
-    }
-
-    /**
-     * Retrieve Grid JavaScript object name
-     *
-     * @return string
-     */
-    public function getGridJsObject()
-    {
-        return $this->getChildBlock('grid')->getJsObjectName();
-    }
-
     /**
      * Retrieve Tab label
      *
@@ -301,4 +281,12 @@ class Config extends Widget implements TabInterface
     {
         return $this->image->getDefaultPlaceholderUrl('thumbnail');
     }
+
+    /**
+     * @return bool
+     */
+    public function isConfigurableProduct()
+    {
+        return $this->getProduct()->getTypeId() === Configurable::TYPE_CODE || $this->getRequest()->has('attributes');
+    }
 }
diff --git a/app/code/Magento/ConfigurableProduct/Block/Adminhtml/Product/Edit/Tab/Super/Config/Grid/AssociatedProduct.php b/app/code/Magento/ConfigurableProduct/Block/Adminhtml/Product/Edit/Tab/Super/Config/Grid/AssociatedProduct.php
deleted file mode 100644
index 0ba0e6577966b42359de35eda17b232358a8f3f4..0000000000000000000000000000000000000000
--- a/app/code/Magento/ConfigurableProduct/Block/Adminhtml/Product/Edit/Tab/Super/Config/Grid/AssociatedProduct.php
+++ /dev/null
@@ -1,23 +0,0 @@
-<?php
-/**
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-
-namespace Magento\ConfigurableProduct\Block\Adminhtml\Product\Edit\Tab\Super\Config\Grid;
-
-/**
- * Associated Product Grid
- */
-class AssociatedProduct extends \Magento\Backend\Block\Widget\Grid\Container
-{
-    /**
-     * @return bool
-     */
-    public function isHasRows()
-    {
-        /** @var $grid \Magento\Backend\Block\Widget\Grid */
-        $grid = $this->getChildBlock('grid');
-        return (bool)$grid->getPreparedCollection()->getSize();
-    }
-}
diff --git a/app/code/Magento/ConfigurableProduct/Block/Adminhtml/Product/Edit/Tab/Super/Config/Grid/Filter/Inventory.php b/app/code/Magento/ConfigurableProduct/Block/Adminhtml/Product/Edit/Tab/Super/Config/Grid/Filter/Inventory.php
deleted file mode 100644
index 5a426635880c60f2bb4937b56af4921c96f58615..0000000000000000000000000000000000000000
--- a/app/code/Magento/ConfigurableProduct/Block/Adminhtml/Product/Edit/Tab/Super/Config/Grid/Filter/Inventory.php
+++ /dev/null
@@ -1,27 +0,0 @@
-<?php
-/**
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-
-/**
- * Configurable product associated products in stock filter
- */
-namespace Magento\ConfigurableProduct\Block\Adminhtml\Product\Edit\Tab\Super\Config\Grid\Filter;
-
-use Magento\Backend\Block\Widget\Grid\Column\Filter\Select;
-
-class Inventory extends Select
-{
-    /**
-     * @return array
-     */
-    protected function _getOptions()
-    {
-        return [
-            ['value' => '', 'label' => ''],
-            ['value' => 1, 'label' => __('In Stock')],
-            ['value' => 0, 'label' => __('Out of Stock')]
-        ];
-    }
-}
diff --git a/app/code/Magento/ConfigurableProduct/Block/Adminhtml/Product/Edit/Tab/Super/Config/Grid/Renderer/Checkbox.php b/app/code/Magento/ConfigurableProduct/Block/Adminhtml/Product/Edit/Tab/Super/Config/Grid/Renderer/Checkbox.php
deleted file mode 100644
index c95d0f2359d0fc11cfd80d2b2e36c5c34f6a1e2b..0000000000000000000000000000000000000000
--- a/app/code/Magento/ConfigurableProduct/Block/Adminhtml/Product/Edit/Tab/Super/Config/Grid/Renderer/Checkbox.php
+++ /dev/null
@@ -1,78 +0,0 @@
-<?php
-/**
- * Adminhtml catalog super product link grid checkbox renderer
- *
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-namespace Magento\ConfigurableProduct\Block\Adminhtml\Product\Edit\Tab\Super\Config\Grid\Renderer;
-
-class Checkbox extends \Magento\Backend\Block\Widget\Grid\Column\Renderer\Checkbox
-{
-    /**
-     * @var \Magento\Framework\Json\EncoderInterface
-     */
-    protected $_jsonEncoder;
-
-    /**
-     * @param \Magento\Backend\Block\Context $context
-     * @param \Magento\Backend\Block\Widget\Grid\Column\Renderer\Options\Converter $converter
-     * @param \Magento\Framework\Json\EncoderInterface $jsonEncoder
-     * @param array $data
-     */
-    public function __construct(
-        \Magento\Backend\Block\Context $context,
-        \Magento\Backend\Block\Widget\Grid\Column\Renderer\Options\Converter $converter,
-        \Magento\Framework\Json\EncoderInterface $jsonEncoder,
-        array $data = []
-    ) {
-        $this->_jsonEncoder = $jsonEncoder;
-        parent::__construct($context, $converter, $data);
-    }
-
-    /**
-     * Renders grid column
-     *
-     * @param \Magento\Framework\DataObject $row
-     * @return string
-     */
-    public function render(\Magento\Framework\DataObject $row)
-    {
-        $result = parent::render($row);
-        return $result . '<input type="hidden" class="value-json" value="' . htmlspecialchars(
-            $this->getAttributesJson($row)
-        ) . '" />';
-    }
-
-    /**
-     * Get attributes json
-     *
-     * @param \Magento\Framework\DataObject $row
-     * @return string
-     */
-    public function getAttributesJson(\Magento\Framework\DataObject $row)
-    {
-        if (!$this->getColumn()->getAttributes()) {
-            return '[]';
-        }
-
-        $result = [];
-        foreach ($this->getColumn()->getAttributes() as $attribute) {
-            $productAttribute = $attribute->getProductAttribute();
-            if ($productAttribute->getSourceModel()) {
-                $label = $productAttribute->getSource()->getOptionText(
-                    $row->getData($productAttribute->getAttributeCode())
-                );
-            } else {
-                $label = $row->getData($productAttribute->getAttributeCode());
-            }
-            $item = [];
-            $item['label'] = $label;
-            $item['attribute_id'] = $productAttribute->getId();
-            $item['value_index'] = $row->getData($productAttribute->getAttributeCode());
-            $result[] = $item;
-        }
-
-        return $this->_jsonEncoder->encode($result);
-    }
-}
diff --git a/app/code/Magento/ConfigurableProduct/Block/Adminhtml/Product/Edit/Tab/Super/Config/Grid/Renderer/Inventory.php b/app/code/Magento/ConfigurableProduct/Block/Adminhtml/Product/Edit/Tab/Super/Config/Grid/Renderer/Inventory.php
deleted file mode 100644
index 8a3668cf9ac525d8bbea118d50e20fc801a89856..0000000000000000000000000000000000000000
--- a/app/code/Magento/ConfigurableProduct/Block/Adminhtml/Product/Edit/Tab/Super/Config/Grid/Renderer/Inventory.php
+++ /dev/null
@@ -1,25 +0,0 @@
-<?php
-/**
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-
-/**
- * Configurable product assocciated products grid in stock renderer
- */
-namespace Magento\ConfigurableProduct\Block\Adminhtml\Product\Edit\Tab\Super\Config\Grid\Renderer;
-
-class Inventory extends \Magento\Backend\Block\Widget\Grid\Column\Renderer\AbstractRenderer
-{
-    /**
-     * Renders grid column value
-     *
-     * @param \Magento\Framework\DataObject $row
-     * @return string
-     */
-    public function render(\Magento\Framework\DataObject $row)
-    {
-        $inStock = $this->_getValue($row);
-        return $inStock ? __('In Stock') : __('Out of Stock');
-    }
-}
diff --git a/app/code/Magento/ConfigurableProduct/Block/Product/Configurable/AssociatedSelector/Backend/Grid/ColumnSet.php b/app/code/Magento/ConfigurableProduct/Block/Product/Configurable/AssociatedSelector/Backend/Grid/ColumnSet.php
deleted file mode 100644
index bf4a93a77a0890ce1305a25bb39745348b167949..0000000000000000000000000000000000000000
--- a/app/code/Magento/ConfigurableProduct/Block/Product/Configurable/AssociatedSelector/Backend/Grid/ColumnSet.php
+++ /dev/null
@@ -1,109 +0,0 @@
-<?php
-/**
- * Block representing set of columns in product grid
- *
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-namespace Magento\ConfigurableProduct\Block\Product\Configurable\AssociatedSelector\Backend\Grid;
-
-/**
- * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
- */
-class ColumnSet extends \Magento\Backend\Block\Widget\Grid\ColumnSet
-{
-    /**
-     * Registry instance
-     *
-     * @var \Magento\Framework\Registry
-     */
-    protected $_registryManager;
-
-    /**
-     * Product type configurable instance
-     *
-     * @var \Magento\ConfigurableProduct\Model\Product\Type\Configurable
-     */
-    protected $_productType;
-
-    /**
-     * @param \Magento\Framework\View\Element\Template\Context $context
-     * @param \Magento\Backend\Model\Widget\Grid\Row\UrlGeneratorFactory $generatorFactory
-     * @param \Magento\Backend\Model\Widget\Grid\SubTotals $subtotals
-     * @param \Magento\Backend\Model\Widget\Grid\Totals $totals
-     * @param \Magento\ConfigurableProduct\Model\Product\Type\Configurable $productType
-     * @param \Magento\Framework\Registry $registryManager
-     * @param array $data
-     */
-    public function __construct(
-        \Magento\Framework\View\Element\Template\Context $context,
-        \Magento\Backend\Model\Widget\Grid\Row\UrlGeneratorFactory $generatorFactory,
-        \Magento\Backend\Model\Widget\Grid\SubTotals $subtotals,
-        \Magento\Backend\Model\Widget\Grid\Totals $totals,
-        \Magento\ConfigurableProduct\Model\Product\Type\Configurable $productType,
-        \Magento\Framework\Registry $registryManager,
-        array $data = []
-    ) {
-        parent::__construct($context, $generatorFactory, $subtotals, $totals, $data);
-
-        $this->_registryManager = $registryManager;
-        $this->_productType = $productType;
-    }
-
-    /**
-     * Retrieve currently edited product object
-     *
-     * @return \Magento\Catalog\Model\Product
-     */
-    public function getProduct()
-    {
-        return $this->_registryManager->registry('current_product');
-    }
-
-    /**
-     * Preparing layout
-     *
-     * @return \Magento\ConfigurableProduct\Block\Product\Configurable\AssociatedSelector\Backend\Grid\ColumnSet
-     */
-    protected function _prepareLayout()
-    {
-        parent::_prepareLayout();
-
-        $product = $this->getProduct();
-        $attributes = $this->_productType->getUsedProductAttributes($product);
-        foreach ($attributes as $attribute) {
-            /** @var $attribute \Magento\Catalog\Model\Entity\Attribute */
-            /** @var $block \Magento\Backend\Block\Widget\Grid\Column */
-            $block = $this->addChild(
-                $attribute->getAttributeCode(),
-                'Magento\Backend\Block\Widget\Grid\Column',
-                [
-                    'header' => $attribute->getStoreLabel(),
-                    'index' => $attribute->getAttributeCode(),
-                    'type' => 'options',
-                    'options' => $this->getOptions($attribute->getSource()),
-                    'sortable' => false
-                ]
-            );
-            $block->setId($attribute->getAttributeCode())->setGrid($this);
-        }
-        return $this;
-    }
-
-    /**
-     * Get option as hash
-     *
-     * @param \Magento\Eav\Model\Entity\Attribute\Source\AbstractSource $sourceModel
-     * @return array
-     */
-    private function getOptions(\Magento\Eav\Model\Entity\Attribute\Source\AbstractSource $sourceModel)
-    {
-        $result = [];
-        foreach ($sourceModel->getAllOptions() as $option) {
-            if ($option['value'] != '') {
-                $result[] = $option;
-            }
-        }
-        return $result;
-    }
-}
diff --git a/app/code/Magento/ConfigurableProduct/Block/Product/View/Type/Configurable.php b/app/code/Magento/ConfigurableProduct/Block/Product/View/Type/Configurable.php
index b67361c4fcc8a740dddceeadaed4fe4b4e3429a5..e2ba278cbc84bc83995ea7c44df653a7880b8670 100644
--- a/app/code/Magento/ConfigurableProduct/Block/Product/View/Type/Configurable.php
+++ b/app/code/Magento/ConfigurableProduct/Block/Product/View/Type/Configurable.php
@@ -216,9 +216,7 @@ class Configurable extends \Magento\Catalog\Block\Product\View\AbstractView
     {
         $prices = [];
         foreach ($this->getAllowProducts() as $product) {
-            $priceInfo = $this->getProduct()
-                ->setSelectedConfigurableOption($product)
-                ->getPriceInfo();
+            $priceInfo = $product->getPriceInfo();
 
             $prices[$product->getId()] =
                 [
diff --git a/app/code/Magento/ConfigurableProduct/Controller/Adminhtml/Product/Associated/Grid.php b/app/code/Magento/ConfigurableProduct/Controller/Adminhtml/Product/Associated/Grid.php
new file mode 100644
index 0000000000000000000000000000000000000000..6eb4facfee9c36125e9da543cfe8565732cdd9e8
--- /dev/null
+++ b/app/code/Magento/ConfigurableProduct/Controller/Adminhtml/Product/Associated/Grid.php
@@ -0,0 +1,42 @@
+<?php
+/**
+ *
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\ConfigurableProduct\Controller\Adminhtml\Product\Associated;
+
+use Magento\Backend\App\Action;
+use Magento\Backend\App\Action\Context;
+use Magento\Framework\View\Result\LayoutFactory;
+
+class Grid extends Action
+{
+    /**
+     * @var LayoutFactory
+     */
+    protected $resultPageFactory;
+
+    /**
+     * @param Context $context
+     * @param LayoutFactory $resultPageFactory
+     */
+    public function __construct(
+        Context $context,
+        LayoutFactory $resultPageFactory
+    ) {
+        parent::__construct($context);
+        $this->resultPageFactory = $resultPageFactory;
+    }
+    /**
+     * Index action
+     *
+     * @return \Magento\Backend\Model\View\Result\Page
+     */
+    public function execute()
+    {
+        /** @var \Magento\Framework\View\Result\Layout $resultPage */
+        $resultPage = $this->resultPageFactory->create();
+        return $resultPage;
+    }
+}
diff --git a/app/code/Magento/ConfigurableProduct/Controller/Adminhtml/Product/SuperConfig/Index.php b/app/code/Magento/ConfigurableProduct/Controller/Adminhtml/Product/SuperConfig/Index.php
deleted file mode 100644
index cd5021712d0d7411d491a77a2349c1cd0e8fa147..0000000000000000000000000000000000000000
--- a/app/code/Magento/ConfigurableProduct/Controller/Adminhtml/Product/SuperConfig/Index.php
+++ /dev/null
@@ -1,38 +0,0 @@
-<?php
-/**
- *
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-namespace Magento\ConfigurableProduct\Controller\Adminhtml\Product\SuperConfig;
-
-use Magento\Backend\App\Action;
-use Magento\Catalog\Controller\Adminhtml\Product;
-
-class Index extends Action
-{
-    /**
-     * @var \Magento\Catalog\Controller\Adminhtml\Product\Builder
-     */
-    protected $productBuilder;
-
-    /**
-     * @param Action\Context $context
-     * @param Product\Builder $productBuilder
-     */
-    public function __construct(Action\Context $context, Product\Builder $productBuilder)
-    {
-        $this->productBuilder = $productBuilder;
-        parent::__construct($context);
-    }
-
-    /**
-     * @return void
-     */
-    public function execute()
-    {
-        $this->productBuilder->build($this->getRequest());
-        $this->_view->loadLayout(false);
-        $this->_view->renderLayout();
-    }
-}
diff --git a/app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable.php b/app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable.php
index 4c8c10f01476eedaf6b49701fab2dd9bd4493691..46db91ca3564b3121fd87f39669eb9a4a0e7f997 100644
--- a/app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable.php
+++ b/app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable.php
@@ -220,7 +220,7 @@ class Configurable extends \Magento\Catalog\Model\Product\Type\AbstractType
      *   group => array(ids)
      * )
      *
-     * @param  int $parentId
+     * @param  array|int $parentId
      * @param  bool $required
      * @return array
      */
diff --git a/app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable/Price.php b/app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable/Price.php
index 68c5cb91c5aa8a6ce83ba418bad122064c254459..bd74b867c86103a67177628d8bef0e30609261cb 100644
--- a/app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable/Price.php
+++ b/app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable/Price.php
@@ -24,10 +24,13 @@ class Price extends \Magento\Catalog\Model\Product\Type\Price
             return $product->getCalculatedFinalPrice();
         }
         if ($product->getCustomOption('simple_product')) {
-            $product->setSelectedConfigurableOption($product->getCustomOption('simple_product')->getProduct());
+            $simpleProduct = $product->getCustomOption('simple_product')->getProduct();
+            $product->setSelectedConfigurableOption($simpleProduct);
+            $priceInfo = $simpleProduct->getPriceInfo();
+        } else {
+            $priceInfo = $product->getPriceInfo();
         }
-        //TODO: MAGETWO-23739 catalogrule price must get from simple product.
-        $finalPrice = $product->getPriceInfo()->getPrice('final_price')->getAmount()->getValue();
+        $finalPrice = $priceInfo->getPrice('final_price')->getAmount()->getValue();
         $finalPrice = $this->_applyOptionsPrice($product, $qty, $finalPrice);
         $finalPrice = max(0, $finalPrice);
         $product->setFinalPrice($finalPrice);
diff --git a/app/code/Magento/ConfigurableProduct/Model/Resource/Product/Collection/AssociatedProduct.php b/app/code/Magento/ConfigurableProduct/Model/Resource/Product/Collection/AssociatedProduct.php
deleted file mode 100644
index 1859c32a207bf6e1d5486e5e7f50124aeb600c1d..0000000000000000000000000000000000000000
--- a/app/code/Magento/ConfigurableProduct/Model/Resource/Product/Collection/AssociatedProduct.php
+++ /dev/null
@@ -1,184 +0,0 @@
-<?php
-/**
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-
-/**
- * Catalog compare item resource model
- */
-namespace Magento\ConfigurableProduct\Model\Resource\Product\Collection;
-
-use Magento\Customer\Api\GroupManagementInterface;
-
-/**
- * Catalog compare item resource model
- *
- * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
- */
-class AssociatedProduct extends \Magento\Catalog\Model\Resource\Product\Collection
-{
-    /**
-     * Registry instance
-     *
-     * @var \Magento\Framework\Registry
-     */
-    protected $_registryManager;
-
-    /**
-     * Product type configurable instance
-     *
-     * @var \Magento\ConfigurableProduct\Model\Product\Type\Configurable
-     */
-    protected $_productType;
-
-    /**
-     * Product type configuration
-     *
-     * @var \Magento\Catalog\Model\ProductTypes\ConfigInterface
-     */
-    protected $_productTypeConfig;
-
-    /**
-     * @param \Magento\Framework\Data\Collection\EntityFactory $entityFactory
-     * @param \Psr\Log\LoggerInterface $logger
-     * @param \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy
-     * @param \Magento\Framework\Event\ManagerInterface $eventManager
-     * @param \Magento\Eav\Model\Config $eavConfig
-     * @param \Magento\Framework\App\Resource $resource
-     * @param \Magento\Eav\Model\EntityFactory $eavEntityFactory
-     * @param \Magento\Catalog\Model\Resource\Helper $resourceHelper
-     * @param \Magento\Framework\Validator\UniversalFactory $universalFactory
-     * @param \Magento\Store\Model\StoreManagerInterface $storeManager
-     * @param \Magento\Framework\Module\Manager $moduleManager
-     * @param \Magento\Catalog\Model\Indexer\Product\Flat\State $catalogProductFlatState
-     * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
-     * @param \Magento\Catalog\Model\Product\OptionFactory $productOptionFactory
-     * @param \Magento\Catalog\Model\Resource\Url $catalogUrl
-     * @param \Magento\Framework\Stdlib\DateTime\TimezoneInterface $localeDate
-     * @param \Magento\Customer\Model\Session $customerSession
-     * @param \Magento\Framework\Stdlib\DateTime $dateTime
-     * @param GroupManagementInterface $groupManagement
-     * @param \Magento\Framework\Registry $registryManager
-     * @param \Magento\ConfigurableProduct\Model\Product\Type\Configurable $productType
-     * @param \Magento\Catalog\Model\ProductTypes\ConfigInterface $productTypeConfig
-     * @param \Magento\Framework\DB\Adapter\AdapterInterface $connection
-     *
-     * @SuppressWarnings(PHPMD.ExcessiveParameterList)
-     */
-    public function __construct(
-        \Magento\Framework\Data\Collection\EntityFactory $entityFactory,
-        \Psr\Log\LoggerInterface $logger,
-        \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy,
-        \Magento\Framework\Event\ManagerInterface $eventManager,
-        \Magento\Eav\Model\Config $eavConfig,
-        \Magento\Framework\App\Resource $resource,
-        \Magento\Eav\Model\EntityFactory $eavEntityFactory,
-        \Magento\Catalog\Model\Resource\Helper $resourceHelper,
-        \Magento\Framework\Validator\UniversalFactory $universalFactory,
-        \Magento\Store\Model\StoreManagerInterface $storeManager,
-        \Magento\Framework\Module\Manager $moduleManager,
-        \Magento\Catalog\Model\Indexer\Product\Flat\State $catalogProductFlatState,
-        \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
-        \Magento\Catalog\Model\Product\OptionFactory $productOptionFactory,
-        \Magento\Catalog\Model\Resource\Url $catalogUrl,
-        \Magento\Framework\Stdlib\DateTime\TimezoneInterface $localeDate,
-        \Magento\Customer\Model\Session $customerSession,
-        \Magento\Framework\Stdlib\DateTime $dateTime,
-        GroupManagementInterface $groupManagement,
-        \Magento\Framework\Registry $registryManager,
-        \Magento\ConfigurableProduct\Model\Product\Type\Configurable $productType,
-        \Magento\Catalog\Model\ProductTypes\ConfigInterface $productTypeConfig,
-        \Magento\Framework\DB\Adapter\AdapterInterface $connection = null
-    ) {
-        $this->_registryManager = $registryManager;
-        $this->_productType = $productType;
-        $this->_productTypeConfig = $productTypeConfig;
-        parent::__construct(
-            $entityFactory,
-            $logger,
-            $fetchStrategy,
-            $eventManager,
-            $eavConfig,
-            $resource,
-            $eavEntityFactory,
-            $resourceHelper,
-            $universalFactory,
-            $storeManager,
-            $moduleManager,
-            $catalogProductFlatState,
-            $scopeConfig,
-            $productOptionFactory,
-            $catalogUrl,
-            $localeDate,
-            $customerSession,
-            $dateTime,
-            $groupManagement,
-            $connection
-        );
-    }
-
-    /**
-     * Get product type
-     *
-     * @return \Magento\ConfigurableProduct\Model\Product\Type\Configurable
-     */
-    public function getProductType()
-    {
-        return $this->_productType;
-    }
-
-    /**
-     * Retrieve currently edited product object
-     *
-     * @return mixed
-     */
-    private function getProduct()
-    {
-        return $this->_registryManager->registry('current_product');
-    }
-
-    /**
-     * Add attributes to select
-     *
-     * @return $this
-     */
-    public function _initSelect()
-    {
-        parent::_initSelect();
-
-        $allowedProductTypes = $this->_productTypeConfig->getComposableTypes();
-
-        $this->addAttributeToSelect(
-            'name'
-        )->addAttributeToSelect(
-            'price'
-        )->addAttributeToSelect(
-            'sku'
-        )->addAttributeToSelect(
-            'weight'
-        )->addAttributeToSelect(
-            'image'
-        )->addFieldToFilter(
-            'type_id',
-            $allowedProductTypes
-        )->addFieldToFilter(
-            'entity_id',
-            ['neq' => $this->getProduct()->getId()]
-        )->addFilterByRequiredOptions()->joinAttribute(
-            'name',
-            'catalog_product/name',
-            'entity_id',
-            null,
-            'inner'
-        )->joinTable(
-            ['cisi' => 'cataloginventory_stock_item'],
-            'product_id=entity_id',
-            ['qty' => 'qty', 'inventory_in_stock' => 'is_in_stock'],
-            null,
-            'left'
-        );
-
-        return $this;
-    }
-}
diff --git a/app/code/Magento/ConfigurableProduct/Model/Resource/Product/Type/Configurable.php b/app/code/Magento/ConfigurableProduct/Model/Resource/Product/Type/Configurable.php
index 2b2d6e392bb2287f22e417e2924cafca9efd9238..c90b20f34acbb78266b5fe803a6d1c1e376994d1 100644
--- a/app/code/Magento/ConfigurableProduct/Model/Resource/Product/Type/Configurable.php
+++ b/app/code/Magento/ConfigurableProduct/Model/Resource/Product/Type/Configurable.php
@@ -90,14 +90,13 @@ class Configurable extends \Magento\Framework\Model\Resource\Db\AbstractDb
      *   group => array(ids)
      * )
      *
-     * @param int $parentId
+     * @param int|array $parentId
      * @param bool $required
      * @return array
      * @SuppressWarnings(PHPMD.UnusedFormalParameter)
      */
     public function getChildrenIds($parentId, $required = true)
     {
-        $childrenIds = [];
         $select = $this->getConnection()->select()->from(
             ['l' => $this->getMainTable()],
             ['product_id', 'parent_id']
@@ -106,7 +105,7 @@ class Configurable extends \Magento\Framework\Model\Resource\Db\AbstractDb
             'e.entity_id = l.product_id AND e.required_options = 0',
             []
         )->where(
-            'parent_id = ?',
+            'parent_id IN (?)',
             $parentId
         );
 
diff --git a/app/code/Magento/ConfigurableProduct/Pricing/Price/ConfigurablePriceResolver.php b/app/code/Magento/ConfigurableProduct/Pricing/Price/ConfigurablePriceResolver.php
new file mode 100644
index 0000000000000000000000000000000000000000..8a3a54d17f45b04fc586cca4033f13b2da176c04
--- /dev/null
+++ b/app/code/Magento/ConfigurableProduct/Pricing/Price/ConfigurablePriceResolver.php
@@ -0,0 +1,58 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\ConfigurableProduct\Pricing\Price;
+
+use Magento\Catalog\Model\Product;
+use Magento\ConfigurableProduct\Model\Product\Type\Configurable;
+use Magento\Framework\Pricing\PriceCurrencyInterface;
+
+class ConfigurablePriceResolver implements PriceResolverInterface
+{
+    /** @var PriceResolverInterface */
+    protected $priceResolver;
+
+    /** @var PriceCurrencyInterface */
+    protected $priceCurrency;
+
+    /** @var Configurable */
+    protected $configurable;
+
+    /**
+     * @param PriceResolverInterface $priceResolver
+     * @param Configurable $configurable
+     * @param PriceCurrencyInterface $priceCurrency
+     */
+    public function __construct(
+        PriceResolverInterface $priceResolver,
+        Configurable $configurable,
+        PriceCurrencyInterface $priceCurrency
+    ) {
+        $this->priceResolver = $priceResolver;
+        $this->configurable = $configurable;
+        $this->priceCurrency = $priceCurrency;
+    }
+
+    /**
+     * @param \Magento\Framework\Pricing\Object\SaleableInterface $product
+     * @return float
+     */
+    public function resolvePrice(\Magento\Framework\Pricing\Object\SaleableInterface $product)
+    {
+        $selectedConfigurableOption = $product->getSelectedConfigurableOption();
+        if ($selectedConfigurableOption) {
+            $price = $this->priceResolver->resolvePrice($selectedConfigurableOption);
+        } else {
+            $price = null;
+            foreach ($this->configurable->getUsedProducts($product) as $subProduct) {
+                $productPrice = $this->priceResolver->resolvePrice($subProduct);
+                $price = $price ? min($price, $productPrice) : $productPrice;
+            }
+        }
+        $priceInCurrentCurrency = $this->priceCurrency->convertAndRound($price);
+        return $priceInCurrentCurrency ? (float)$priceInCurrentCurrency : false;
+    }
+}
diff --git a/app/code/Magento/ConfigurableProduct/Pricing/Price/ConfigurableRegularPrice.php b/app/code/Magento/ConfigurableProduct/Pricing/Price/ConfigurableRegularPrice.php
index efb7d45698271f2ca26aa4c1161e8fbcf8958240..704005ef38b8c6aecbc18ffb797f109363907358 100644
--- a/app/code/Magento/ConfigurableProduct/Pricing/Price/ConfigurableRegularPrice.php
+++ b/app/code/Magento/ConfigurableProduct/Pricing/Price/ConfigurableRegularPrice.php
@@ -8,9 +8,7 @@ namespace Magento\ConfigurableProduct\Pricing\Price;
 
 use Magento\Catalog\Model\Product;
 use Magento\ConfigurableProduct\Model\Product\Type\Configurable;
-use Magento\Framework\Pricing\Adjustment\CalculatorInterface;
 use Magento\Framework\Pricing\Price\AbstractPrice;
-use Magento\Framework\Pricing\PriceCurrencyInterface;
 
 /**
  * Class RegularPrice
@@ -37,6 +35,27 @@ class ConfigurableRegularPrice extends AbstractPrice implements ConfigurableRegu
      */
     protected $values = [];
 
+    /** @var PriceResolverInterface */
+    protected $priceResolver;
+
+    /**
+     * @param \Magento\Framework\Pricing\Object\SaleableInterface $saleableItem
+     * @param float $quantity
+     * @param \Magento\Framework\Pricing\Adjustment\CalculatorInterface $calculator
+     * @param \Magento\Framework\Pricing\PriceCurrencyInterface $priceCurrency
+     * @param PriceResolverInterface $priceResolver
+     */
+    public function __construct(
+        \Magento\Framework\Pricing\Object\SaleableInterface $saleableItem,
+        $quantity,
+        \Magento\Framework\Pricing\Adjustment\CalculatorInterface $calculator,
+        \Magento\Framework\Pricing\PriceCurrencyInterface $priceCurrency,
+        PriceResolverInterface $priceResolver
+    ) {
+        parent::__construct($saleableItem, $quantity, $calculator, $priceCurrency);
+        $this->priceResolver = $priceResolver;
+    }
+
     /**
      * {@inheritdoc}
      */
@@ -45,19 +64,7 @@ class ConfigurableRegularPrice extends AbstractPrice implements ConfigurableRegu
         $selectedConfigurableOption = $this->product->getSelectedConfigurableOption();
         $productId = $selectedConfigurableOption ? $selectedConfigurableOption->getId() : $this->product->getId();
         if (!isset($this->values[$productId])) {
-            $price = null;
-            if (!$selectedConfigurableOption) {
-                foreach ($this->getUsedProducts() as $product) {
-                    if ($price === null || $price > $product->getPrice()) {
-                        $price = $product->getPrice();
-                    }
-                }
-            } else {
-                $price = $selectedConfigurableOption->getPrice();
-            }
-
-            $priceInCurrentCurrency = $this->priceCurrency->convertAndRound($price);
-            $this->values[$productId] = $priceInCurrentCurrency ? floatval($priceInCurrentCurrency) : false;
+            $this->values[$productId] = $this->priceResolver->resolvePrice($this->product);
         }
 
         return $this->values[$productId];
@@ -67,12 +74,7 @@ class ConfigurableRegularPrice extends AbstractPrice implements ConfigurableRegu
      */
     public function getAmount()
     {
-        if (false) {
-            // TODO: need to check simple product assignment
-        } else {
-            $amount = $this->getMinRegularAmount($this->product);
-        }
-        return $amount;
+        return $this->getMinRegularAmount($this->product);
     }
 
     /**
@@ -95,7 +97,6 @@ class ConfigurableRegularPrice extends AbstractPrice implements ConfigurableRegu
      */
     protected function doGetMaxRegularAmount()
     {
-        // TODO: think about quantity
         $maxAmount = null;
         foreach ($this->getUsedProducts() as $product) {
             $childPriceAmount = $product->getPriceInfo()->getPrice(self::PRICE_CODE)->getAmount();
@@ -125,7 +126,6 @@ class ConfigurableRegularPrice extends AbstractPrice implements ConfigurableRegu
      */
     protected function doGetMinRegularAmount()
     {
-        // TODO: think about quantity
         $minAmount = null;
         foreach ($this->getUsedProducts() as $product) {
             $childPriceAmount = $product->getPriceInfo()->getPrice(self::PRICE_CODE)->getAmount();
diff --git a/app/code/Magento/ConfigurableProduct/Pricing/Price/FinalPrice.php b/app/code/Magento/ConfigurableProduct/Pricing/Price/FinalPrice.php
index 093de8327567283d0652789d9e1e499ebfd5e263..8a448ac045bd38be1151a935c8f79fcd2a6de8fe 100644
--- a/app/code/Magento/ConfigurableProduct/Pricing/Price/FinalPrice.php
+++ b/app/code/Magento/ConfigurableProduct/Pricing/Price/FinalPrice.php
@@ -8,6 +8,32 @@ namespace Magento\ConfigurableProduct\Pricing\Price;
 
 class FinalPrice extends \Magento\Catalog\Pricing\Price\FinalPrice
 {
+    /** @var PriceResolverInterface */
+    protected $priceResolver;
+
+    /**
+     * @var array
+     */
+    protected $values = [];
+
+    /**
+     * @param \Magento\Framework\Pricing\Object\SaleableInterface $saleableItem
+     * @param float $quantity
+     * @param \Magento\Framework\Pricing\Adjustment\CalculatorInterface $calculator
+     * @param \Magento\Framework\Pricing\PriceCurrencyInterface $priceCurrency
+     * @param PriceResolverInterface $priceResolver
+     */
+    public function __construct(
+        \Magento\Framework\Pricing\Object\SaleableInterface $saleableItem,
+        $quantity,
+        \Magento\Framework\Pricing\Adjustment\CalculatorInterface $calculator,
+        \Magento\Framework\Pricing\PriceCurrencyInterface $priceCurrency,
+        PriceResolverInterface $priceResolver
+    ) {
+        parent::__construct($saleableItem, $quantity, $calculator, $priceCurrency);
+        $this->priceResolver = $priceResolver;
+    }
+
     /**
      * {@inheritdoc}
      */
@@ -18,4 +44,18 @@ class FinalPrice extends \Magento\Catalog\Pricing\Price\FinalPrice
         }
         return parent::getAmount();
     }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getValue()
+    {
+        $selectedConfigurableOption = $this->product->getSelectedConfigurableOption();
+        $productId = $selectedConfigurableOption ? $selectedConfigurableOption->getId() : $this->product->getId();
+        if (!isset($this->values[$productId])) {
+            $this->values[$productId] = $this->priceResolver->resolvePrice($this->product);
+        }
+
+        return $this->values[$productId];
+    }
 }
diff --git a/app/code/Magento/ConfigurableProduct/Pricing/Price/FinalPriceResolver.php b/app/code/Magento/ConfigurableProduct/Pricing/Price/FinalPriceResolver.php
new file mode 100644
index 0000000000000000000000000000000000000000..c55dd7cd1b2b56d54c56636b8c746fa8352269e6
--- /dev/null
+++ b/app/code/Magento/ConfigurableProduct/Pricing/Price/FinalPriceResolver.php
@@ -0,0 +1,20 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\ConfigurableProduct\Pricing\Price;
+
+class FinalPriceResolver implements PriceResolverInterface
+{
+    /**
+     * @param \Magento\Framework\Pricing\Object\SaleableInterface $product
+     * @return float
+     */
+    public function resolvePrice(\Magento\Framework\Pricing\Object\SaleableInterface $product)
+    {
+        return $product->getPriceInfo()->getPrice(\Magento\Catalog\Pricing\Price\FinalPrice::PRICE_CODE)
+            ->getAmount()->getValue();
+    }
+}
diff --git a/app/code/Magento/ConfigurableProduct/Pricing/Price/PriceResolverInterface.php b/app/code/Magento/ConfigurableProduct/Pricing/Price/PriceResolverInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..5aff5c12e16804f8d2b967833aea7eaea24a2a16
--- /dev/null
+++ b/app/code/Magento/ConfigurableProduct/Pricing/Price/PriceResolverInterface.php
@@ -0,0 +1,16 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\ConfigurableProduct\Pricing\Price;
+
+interface PriceResolverInterface
+{
+    /**
+     * @param \Magento\Framework\Pricing\Object\SaleableInterface $product
+     * @return float
+     */
+    public function resolvePrice(\Magento\Framework\Pricing\Object\SaleableInterface $product);
+}
diff --git a/app/code/Magento/ConfigurableProduct/Pricing/Price/RegularPriceResolver.php b/app/code/Magento/ConfigurableProduct/Pricing/Price/RegularPriceResolver.php
new file mode 100644
index 0000000000000000000000000000000000000000..a8ac2e6d84bf3ad7da02a8db8bbab683c8e3aa90
--- /dev/null
+++ b/app/code/Magento/ConfigurableProduct/Pricing/Price/RegularPriceResolver.php
@@ -0,0 +1,19 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\ConfigurableProduct\Pricing\Price;
+
+class RegularPriceResolver implements PriceResolverInterface
+{
+    /**
+     * @param \Magento\Framework\Pricing\Object\SaleableInterface $product
+     * @return float
+     */
+    public function resolvePrice(\Magento\Framework\Pricing\Object\SaleableInterface $product)
+    {
+        return $product->getPrice();
+    }
+}
diff --git a/app/code/Magento/ConfigurableProduct/Ui/Component/Listing/AssociatedProduct/Attribute/Repository.php b/app/code/Magento/ConfigurableProduct/Ui/Component/Listing/AssociatedProduct/Attribute/Repository.php
new file mode 100644
index 0000000000000000000000000000000000000000..d52708b06b95557c0b661aac603585a75912158e
--- /dev/null
+++ b/app/code/Magento/ConfigurableProduct/Ui/Component/Listing/AssociatedProduct/Attribute/Repository.php
@@ -0,0 +1,36 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\ConfigurableProduct\Ui\Component\Listing\AssociatedProduct\Attribute;
+
+class Repository extends \Magento\Catalog\Ui\Component\Listing\Attribute\AbstractRepository
+{
+    /** @var \Magento\Framework\App\RequestInterface */
+    protected $request;
+
+    /**
+     * @param \Magento\Catalog\Api\ProductAttributeRepositoryInterface $productAttributeRepository
+     * @param \Magento\Framework\Api\SearchCriteriaBuilder $searchCriteriaBuilder
+     * @param \Magento\Framework\App\RequestInterface $request
+     */
+    public function __construct(
+        \Magento\Catalog\Api\ProductAttributeRepositoryInterface $productAttributeRepository,
+        \Magento\Framework\Api\SearchCriteriaBuilder $searchCriteriaBuilder,
+        \Magento\Framework\App\RequestInterface $request
+    ) {
+        parent::__construct($productAttributeRepository, $searchCriteriaBuilder);
+        $this->request = $request;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function buildSearchCriteria()
+    {
+        return $this->searchCriteriaBuilder
+            ->addFilter('attribute_code', $this->request->getParam('attributes_codes', []), 'in')
+            ->create();
+    }
+}
diff --git a/app/code/Magento/ConfigurableProduct/Ui/Component/Listing/AssociatedProduct/Columns.php b/app/code/Magento/ConfigurableProduct/Ui/Component/Listing/AssociatedProduct/Columns.php
new file mode 100644
index 0000000000000000000000000000000000000000..90acb7e467a960fec5ea72089c4b4d2e78664a1d
--- /dev/null
+++ b/app/code/Magento/ConfigurableProduct/Ui/Component/Listing/AssociatedProduct/Columns.php
@@ -0,0 +1,44 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\ConfigurableProduct\Ui\Component\Listing\AssociatedProduct;
+
+class Columns extends \Magento\Ui\Component\Listing\Columns
+{
+    /** @var \Magento\Catalog\Ui\Component\Listing\Attribute\RepositoryInterface */
+    protected $attributeRepository;
+
+    /**
+     * @param \Magento\Framework\View\Element\UiComponent\ContextInterface $context
+     * @param \Magento\Catalog\Ui\Component\ColumnFactory $columnFactory
+     * @param \Magento\Catalog\Ui\Component\Listing\Attribute\RepositoryInterface $attributeRepository
+     * @param array $components
+     * @param array $data
+     */
+    public function __construct(
+        \Magento\Framework\View\Element\UiComponent\ContextInterface $context,
+        \Magento\Catalog\Ui\Component\ColumnFactory $columnFactory,
+        \Magento\Catalog\Ui\Component\Listing\Attribute\RepositoryInterface $attributeRepository,
+        array $components = [],
+        array $data = []
+    ) {
+        parent::__construct($context, $components, $data);
+        $this->columnFactory = $columnFactory;
+        $this->attributeRepository = $attributeRepository;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function prepare()
+    {
+        foreach ($this->attributeRepository->getList() as $attribute) {
+            $column = $this->columnFactory->create($attribute, $this->getContext());
+                $column->prepare();
+                $this->addComponent($attribute->getAttributeCode(), $column);
+        }
+        parent::prepare();
+    }
+}
diff --git a/app/code/Magento/ConfigurableProduct/Ui/Component/Listing/AssociatedProduct/Filters.php b/app/code/Magento/ConfigurableProduct/Ui/Component/Listing/AssociatedProduct/Filters.php
index af27ebc05c328ce4aeaf78e787fabf88abd248bf..8ed9f3d718e21f27955c53048d57721f89f61229 100644
--- a/app/code/Magento/ConfigurableProduct/Ui/Component/Listing/AssociatedProduct/Filters.php
+++ b/app/code/Magento/ConfigurableProduct/Ui/Component/Listing/AssociatedProduct/Filters.php
@@ -7,28 +7,26 @@ namespace Magento\ConfigurableProduct\Ui\Component\Listing\AssociatedProduct;
 
 class Filters extends \Magento\Ui\Component\Filters
 {
-    /**
-     * @var \Magento\Eav\Model\Resource\Entity\Attribute\CollectionFactory
-     */
-    protected $attributeCollectionFactory;
+    /** @var \Magento\Catalog\Ui\Component\Listing\Attribute\RepositoryInterface */
+    protected $attributeRepository;
 
     /**
      * @param \Magento\Framework\View\Element\UiComponent\ContextInterface $context
      * @param \Magento\Catalog\Ui\Component\FilterFactory $filterFactory
-     * @param \Magento\Eav\Model\Resource\Entity\Attribute\CollectionFactory $attributeCollectionFactory
+     * @param \Magento\Catalog\Ui\Component\Listing\Attribute\RepositoryInterface $attributeRepository
      * @param array $components
      * @param array $data
      */
     public function __construct(
         \Magento\Framework\View\Element\UiComponent\ContextInterface $context,
         \Magento\Catalog\Ui\Component\FilterFactory $filterFactory,
-        \Magento\Eav\Model\Resource\Entity\Attribute\CollectionFactory $attributeCollectionFactory,
+        \Magento\Catalog\Ui\Component\Listing\Attribute\RepositoryInterface $attributeRepository,
         array $components = [],
         array $data = []
     ) {
         parent::__construct($context, $components, $data);
         $this->filterFactory = $filterFactory;
-        $this->attributeCollectionFactory = $attributeCollectionFactory;
+        $this->attributeRepository = $attributeRepository;
     }
 
     /**
@@ -36,24 +34,14 @@ class Filters extends \Magento\Ui\Component\Filters
      */
     public function prepare()
     {
-        $attributeIds = $this->context->getRequestParam('attribute_ids');
+        $attributeIds = $this->getContext()->getRequestParam('attributes_codes');
         if ($attributeIds) {
-            foreach ($this->getAttributes($attributeIds) as $attribute) {
-                $filter = $this->filterFactory->create($attribute, $this->getContext());
+            foreach ($this->attributeRepository->getList() as $attribute) {
+                $filter = $this->filterFactory->create($attribute, $this->getContext(), ['component' => '']);
                 $filter->prepare();
                 $this->addComponent($attribute->getAttributeCode(), $filter);
             }
         }
         parent::prepare();
     }
-
-    /**
-     * @param array $attributeIds
-     * @return mixed
-     */
-    protected function getAttributes($attributeIds)
-    {
-        $attributeCollection = $this->attributeCollectionFactory->create();
-        return $attributeCollection->addFieldToFilter('attribute_code', ['in' => $attributeIds]);
-    }
 }
diff --git a/app/code/Magento/ConfigurableProduct/composer.json b/app/code/Magento/ConfigurableProduct/composer.json
index 1b6f0a5a8aea66ae6ccae51733bb3e4edac036fb..a90d56be9beb6ef47032c0d38dc8b6f22e724d28 100644
--- a/app/code/Magento/ConfigurableProduct/composer.json
+++ b/app/code/Magento/ConfigurableProduct/composer.json
@@ -6,7 +6,6 @@
         "magento/module-store": "1.0.0-beta",
         "magento/module-catalog": "1.0.0-beta",
         "magento/module-catalog-inventory": "1.0.0-beta",
-        "magento/module-sales": "1.0.0-beta",
         "magento/module-checkout": "1.0.0-beta",
         "magento/module-msrp": "1.0.0-beta",
         "magento/module-backend": "1.0.0-beta",
@@ -20,7 +19,8 @@
         "magento/magento-composer-installer": "*"
     },
     "suggest": {
-      "magento/module-webapi": "1.0.0-beta"
+      "magento/module-webapi": "1.0.0-beta",
+      "magento/module-sales": "1.0.0-beta"
     },
     "type": "magento2-module",
     "version": "1.0.0-beta",
diff --git a/app/code/Magento/ConfigurableProduct/etc/adminhtml/di.xml b/app/code/Magento/ConfigurableProduct/etc/adminhtml/di.xml
index 10ffde3a203407b971fdae1ce6775763ed6464ba..226e2f9f2a2eaf852ee09b522578925dd77870c5 100644
--- a/app/code/Magento/ConfigurableProduct/etc/adminhtml/di.xml
+++ b/app/code/Magento/ConfigurableProduct/etc/adminhtml/di.xml
@@ -24,4 +24,14 @@
     <type name="Magento\Catalog\Model\Resource\Product">
         <plugin name="reload_attributes" type="Magento\ConfigurableProduct\Plugin\Model\Resource\Product" />
     </type>
+    <type name="Magento\ConfigurableProduct\Ui\Component\Listing\AssociatedProduct\Columns">
+        <arguments>
+            <argument name="attributeRepository" xsi:type="object">Magento\ConfigurableProduct\Ui\Component\Listing\AssociatedProduct\Attribute\Repository</argument>
+        </arguments>
+    </type>
+    <type name="Magento\ConfigurableProduct\Ui\Component\Listing\AssociatedProduct\Filters">
+        <arguments>
+            <argument name="attributeRepository" xsi:type="object">Magento\ConfigurableProduct\Ui\Component\Listing\AssociatedProduct\Attribute\Repository</argument>
+        </arguments>
+    </type>
 </config>
diff --git a/app/code/Magento/ConfigurableProduct/etc/di.xml b/app/code/Magento/ConfigurableProduct/etc/di.xml
index 7f3f4dda6d5745674bc7cebb863e9fc43e2906aa..67c0448affe6685ab131c5313787776bf3492cb6 100644
--- a/app/code/Magento/ConfigurableProduct/etc/di.xml
+++ b/app/code/Magento/ConfigurableProduct/etc/di.xml
@@ -89,4 +89,24 @@
             </argument>
         </arguments>
     </type>
+    <virtualType name="ConfigurableFinalPriceResolver" type="Magento\ConfigurableProduct\Pricing\Price\ConfigurablePriceResolver">
+        <arguments>
+            <argument name="priceResolver" xsi:type="object">Magento\ConfigurableProduct\Pricing\Price\FinalPriceResolver</argument>
+        </arguments>
+    </virtualType>
+    <type name="Magento\ConfigurableProduct\Pricing\Price\FinalPrice">
+        <arguments>
+            <argument name="priceResolver" xsi:type="object">ConfigurableFinalPriceResolver</argument>
+        </arguments>
+    </type>
+    <virtualType name="ConfigurableRegularPriceResolver" type="Magento\ConfigurableProduct\Pricing\Price\ConfigurablePriceResolver">
+        <arguments>
+            <argument name="priceResolver" xsi:type="object">Magento\ConfigurableProduct\Pricing\Price\RegularPriceResolver</argument>
+        </arguments>
+    </virtualType>
+    <type name="Magento\ConfigurableProduct\Pricing\Price\ConfigurableRegularPrice">
+        <arguments>
+            <argument name="priceResolver" xsi:type="object">ConfigurableRegularPriceResolver</argument>
+        </arguments>
+    </type>
 </config>
diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/layout/catalog_product_superconfig_index.xml b/app/code/Magento/ConfigurableProduct/view/adminhtml/layout/catalog_product_associated_grid.xml
similarity index 52%
rename from app/code/Magento/ConfigurableProduct/view/adminhtml/layout/catalog_product_superconfig_index.xml
rename to app/code/Magento/ConfigurableProduct/view/adminhtml/layout/catalog_product_associated_grid.xml
index 7cc24820b426f9662631b12a351bcd0f50180b21..d9dc4c65e3331f03d50db1f22b96b3dff8a71513 100644
--- a/app/code/Magento/ConfigurableProduct/view/adminhtml/layout/catalog_product_superconfig_index.xml
+++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/layout/catalog_product_associated_grid.xml
@@ -6,8 +6,7 @@
  */
 -->
 <layout xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../lib/internal/Magento/Framework/View/Layout/etc/layout_generic.xsd">
-    <update handle="catalog_product_superconfig_config"/>
     <container name="root">
-        <block class="Magento\ConfigurableProduct\Block\Adminhtml\Product\Edit\Tab\Super\Config\Grid\AssociatedProduct" name="admin.product.edit.tab.super.config.grid.container"  template="Magento_ConfigurableProduct::catalog/product/edit/super/associated-product-grid.phtml"/>
+        <uiComponent name="configurable_associated_product_listing"/>
     </container>
 </layout>
diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/layout/catalog_product_configurable.xml b/app/code/Magento/ConfigurableProduct/view/adminhtml/layout/catalog_product_configurable.xml
index 5cd281b5b426b97d7b1579170b61d74d7db59f68..2a361a45de36c62309abd33455a61e65355e376f 100644
--- a/app/code/Magento/ConfigurableProduct/view/adminhtml/layout/catalog_product_configurable.xml
+++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/layout/catalog_product_configurable.xml
@@ -10,4 +10,11 @@
         <css src="Magento_ConfigurableProduct::css/configurable-product.css"/>
     </head>
     <update handle="catalog_product_superconfig_config"/>
+    <body>
+        <referenceBlock name="product_tabs">
+            <action method="removeTab">
+                <argument name="name" xsi:type="string">advanced-pricing</argument>
+            </action>
+        </referenceBlock>
+    </body>
 </page>
diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/layout/catalog_product_superconfig_config.xml b/app/code/Magento/ConfigurableProduct/view/adminhtml/layout/catalog_product_superconfig_config.xml
index 9ed318d2b3379065b44f4f7ef78c6266ad1e6f42..f7a4f779bcc314bb33fb0270c0d861d0f24b2d88 100644
--- a/app/code/Magento/ConfigurableProduct/view/adminhtml/layout/catalog_product_superconfig_config.xml
+++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/layout/catalog_product_superconfig_config.xml
@@ -7,11 +7,6 @@
 -->
 <page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../lib/internal/Magento/Framework/View/Layout/etc/page_configuration.xsd">
     <body>
-        <referenceBlock name="admin.product.edit.tab.super.config.grid.container">
-            <block class="Magento\Backend\Block\Template" name="manual.product.grid" template="Magento_ConfigurableProduct::catalog/product/edit/super/manual-product-grid.phtml" as="grid">
-                <uiComponent name="configurable_associated_product_listing"/>
-            </block>
-        </referenceBlock>
         <referenceBlock name="product_tabs">
             <block class="Magento\ConfigurableProduct\Block\Adminhtml\Product\Edit\Tab\Super\Config" name="admin.product.edit.tab.super.config.grid.container">
                 <block class="Magento\ConfigurableProduct\Block\Adminhtml\Product\Edit\Tab\Super\Config" template="Magento_ConfigurableProduct::catalog/product/edit/super/generator.phtml" name="product-variations-generator" as="generator">
diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/templates/catalog/product/edit/super/associated-product-grid.phtml b/app/code/Magento/ConfigurableProduct/view/adminhtml/templates/catalog/product/edit/super/associated-product-grid.phtml
deleted file mode 100644
index d6c1154113a3dfe1d072cda58436657177408191..0000000000000000000000000000000000000000
--- a/app/code/Magento/ConfigurableProduct/view/adminhtml/templates/catalog/product/edit/super/associated-product-grid.phtml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?php
-/**
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-
-// @codingStandardsIgnoreFile
-
-/* @var $block \Magento\ConfigurableProduct\Block\Adminhtml\Product\Edit\Tab\Super\Config\Grid\AssociatedProduct */
-
-?>
-<div data-role="configurable-attribute">
-    <div data-role="messages" class="messages">
-        <div class="message ">
-            <div>
-                <?php if ($block->isHasRows()): ?>
-                    <?= /* @escapeNotVerified */  __('Choose a new product to delete and replace the current product configuration.') ?>
-                <?php else: ?>
-                    <?= /* @escapeNotVerified */   __('For better results, add attributes and attribute values to your products.') ?>
-                <?php endif ?>
-            </div>
-        </div>
-    </div>
-    <?php echo $block->getGridHtml() ?>
-</div>
diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/templates/catalog/product/edit/super/config.phtml b/app/code/Magento/ConfigurableProduct/view/adminhtml/templates/catalog/product/edit/super/config.phtml
index ec212367581008e27e8e3bf63107b0b67e0a9ef4..634f06de8c4aa20eadfde6943770451f3a0a446b 100644
--- a/app/code/Magento/ConfigurableProduct/view/adminhtml/templates/catalog/product/edit/super/config.phtml
+++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/templates/catalog/product/edit/super/config.phtml
@@ -7,8 +7,6 @@
 // @codingStandardsIgnoreFile
 
  /** @var $block \Magento\ConfigurableProduct\Block\Adminhtml\Product\Edit\Tab\Super\Config */
-
-use Magento\ConfigurableProduct\Model\Product\Type\Configurable;
 ?>
 <div class="entry-edit form-inline" id="<?php /* @escapeNotVerified */ echo $block->getId() ?>">
     <div class="fieldset-wrapper admin__collapsible-block-wrapper" id="<?php /* @escapeNotVerified */ echo $block->getId() ?>-wrapper" data-panel="product-variations">
@@ -26,11 +24,6 @@ use Magento\ConfigurableProduct\Model\Product\Type\Configurable;
                     You need to create a simple product for each configuration (Ex: a product for each color).');?>
                     </div>
                 </div>
-                <!--<div class="product-create-configuration-actions">
-                    <a class="action-menu-item" data-action="choose" onclick="jQuery('#associated-products-container').trigger('openModal');" href="#">
-                        <?/*= __('Add Products Manually');*/?>
-                    </a>
-                </div>-->
                 <div class="product-create-configuration-actions">
                     <button data-action="open-steps-wizard" title="Create Product Configurations"
                             class="action-secondary" data-bind="click: open">
@@ -43,13 +36,26 @@ use Magento\ConfigurableProduct\Model\Product\Type\Configurable;
                         </span>
                     </button>
                 </div>
+                <div class="product-create-configuration-actions" data-bind="scope: 'configurableProductGrid'">
+                    <a class="action-menu-item" data-action="choose" data-bind="click: showManuallyGrid, visible: button">
+                        <?= /* @noEscape */ __('Add Products Manually');?>
+                    </a>
+                </div>
             </div>
             <fieldset class="fieldset">
                 <?php echo $block->getChildHtml('generator'); ?>
 
                 <!-- Select Associated Product popup -->
-                <div id="associated-products-container">
-                    <?php echo $block->getGridHtml(); ?>
+                <div data-grid-id="associated-products-container">
+                    <div class="admin__data-grid-outer-wrap" data-bind="scope: 'configurable_associated_product_listing.configurable_associated_product_listing'">
+                        <div data-role="spinner" data-component="configurable_associated_product_listing.configurable_associated_product_listing.product_columns" class="admin__data-grid-loading-mask">
+                            <div class="spinner">
+                                <span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span>
+                            </div>
+                        </div>
+                        <!-- ko template: getTemplate() --><!-- /ko -->
+
+                    </div>
                 </div>
 
                 <input type="hidden" name="affect_configurable_product_attributes" value="1" />
@@ -60,75 +66,76 @@ use Magento\ConfigurableProduct\Model\Product\Type\Configurable;
 <script>
 require([
     'jquery',
-    'mage/template',
-    'jquery/ui',
-    'jquery/jquery.tabs',
+    'Magento_ConfigurableProduct/js/advanced-pricing-handler',
+    'Magento_ConfigurableProduct/js/options/price-type-handler',
     'mage/mage',
-    'mage/backend/menu',
     'Magento_Ui/js/modal/modal',
     'mage/translate',
     'domReady!'
-], function($, mageTemplate){
+], function($, advancedPricingHandler, priceTypeHandler){
     'use strict';
 
-    var variationsContainer = $("#<?php /* @escapeNotVerified */ echo $block->getId()?>"),
-        collapsableWrapper = $("#<?php /* @escapeNotVerified */ echo $block->getId()?>-wrapper"),
-        collapsableArea = $('> .collapse', collapsableWrapper),
-        stockAvailabilityField = $('#quantity_and_stock_status'),
-        qtyField = $('#qty'),
-        inventoryQty = $('#inventory_qty'),
-        inventoryAvailabilityField = $('#inventory_stock_availability'),
-        currentProductTemplateControl = $('#product-template-suggest-container .action-dropdown > .action-toggle'),
-        attributesInput = $("input[name='attributes[]']", variationsContainer),
-        hasVariations = <?php /* @escapeNotVerified */ echo($block->getProduct()->getTypeId() === Configurable::TYPE_CODE || $block->getRequest()->has('attributes')) ? 'true' : 'false' ?>,
-        noImageUrl = '<?= /* @escapeNotVerified */  $block->getNoImageUrl() ?>',
-        isLocked = function (element) {
-            return element.is('[data-locked]');
-        },
-        setElementDisabled = function (element, state, triggerEvent) {
-            if (!isLocked(element)) {
-                element.prop('disabled', state);
+    advancedPricingHandler.init();
+    priceTypeHandler.init();
+
+    var blockId = '#<?= /* @noEscape */ $block->getId()?>',
+        hasVariations = <?= /* @noEscape */ $block->isConfigurableProduct() ? 'true' : 'false' ?>,
+        setElementDisabled = function ($element, state, triggerEvent) {
+            if (!$element.is('[data-locked]')) {
+                $element.prop('disabled', state);
+    
                 if (triggerEvent) {
-                    element.trigger('change')
+                    $element.trigger('change');
                 }
             }
+        },
+        configurableTypeHandler = function (isConfigurable) {
+            isConfigurable = hasVariations ? true : isConfigurable;
+            $('[data-form=edit-product]').trigger("change_configurable_type", isConfigurable);
         };
 
-    collapsableArea
+
+    $(blockId + '-wrapper > .collapse')
         .on('show', function() {
-            currentProductTemplateControl
+            $('#product-template-suggest-container .action-dropdown > .action-toggle')
                 .addClass('disabled')
                 .prop('disabled', true);
-
-            attributesInput.prop('disabled', false);
-
-            inventoryQty.prop('disabled', true);
-            inventoryAvailabilityField.removeProp('disabled');
-            setElementDisabled(qtyField, true, true);
-            setElementDisabled(stockAvailabilityField, false, false);
+            $(blockId + ' input[name="attributes[]"]').prop('disabled', false);
+            $('#inventory_qty').prop('disabled', true);
+            $('#inventory_stock_availability').removeProp('disabled');
+            setElementDisabled($('#qty'), true, true);
+            setElementDisabled($('#quantity_and_stock_status'), false, false);
+            configurableTypeHandler(true);
         })
         .on('hide', function() {
-            currentProductTemplateControl
+            $('#product-template-suggest-container .action-dropdown > .action-toggle')
                 .removeClass('disabled')
                 .removeProp('disabled');
-            inventoryQty.removeProp('disabled');
-            inventoryAvailabilityField.prop('disabled', true);
-            setElementDisabled(stockAvailabilityField, true, false);
-            setElementDisabled(qtyField, false, true);
+            $('#inventory_qty').removeProp('disabled');
+            $('#inventory_stock_availability').prop('disabled', true);
+            setElementDisabled($('#quantity_and_stock_status'), true, false);
+            setElementDisabled($('#qty'), false, true);
+            configurableTypeHandler(false);
         })
         .collapse(hasVariations ? 'show' : 'hide');
-
-    var $gridDialog = $('#associated-products-container').modal({
-        title: $.mage.__('Select Associated Product'),
-        type: 'popup'
-    });
-
-    $('[data-panel=product-variations]')
-        .on('disable', '[data-role=product-variations-matrix]', function() {
-            $(this).html('');
-        })
-        .on('click', '[data-action=choose]', function(event) {
-            $gridDialog.trigger('openModal');
-        });
 });
 </script>
+<script type="text/x-magento-init">
+    {
+        "*": {
+            "Magento_Ui/js/core/app": {
+                "components": {
+                    "configurableProductGrid": {
+                        "component": "Magento_ConfigurableProduct/js/variations/product-grid",
+                        "productsFilter": "configurable_associated_product_listing.configurable_associated_product_listing.listing_top.listing_filters",
+                        "productsProvider": "configurable_associated_product_listing.data_source",
+                        "productsMassAction": "configurable_associated_product_listing.configurable_associated_product_listing.product_columns.ids",
+                        "productsColumns": "configurable_associated_product_listing.configurable_associated_product_listing.product_columns",
+                        "productsGridUrl": "<?= /* @noEscape */ $block->getUrl('catalog/product/associated_grid', ['componentJson' => true])?>",
+                        "configurableVariations": "configurableVariations"
+                    }
+                }
+            }
+        }
+    }
+</script>
diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/templates/catalog/product/edit/super/manual-product-grid.phtml b/app/code/Magento/ConfigurableProduct/view/adminhtml/templates/catalog/product/edit/super/manual-product-grid.phtml
deleted file mode 100644
index 41c67a6f96a3e3bb04eb2e5fdaa56919808c77cf..0000000000000000000000000000000000000000
--- a/app/code/Magento/ConfigurableProduct/view/adminhtml/templates/catalog/product/edit/super/manual-product-grid.phtml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?php
-/**
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-
-// @codingStandardsIgnoreFile
-
-/* @var $block \Magento\ConfigurableProduct\Block\Adminhtml\Product\Edit\Tab\Super\Config\Grid\ManualProduct */
-
-?>
-<div>
-    <div data-role="messages" class="messages">
-        <div class="message ">
-            <div>
-                <?= /* @escapeNotVerified */  __('Choose a new product to delete and replace the current product configuration.') ?>
-                <?= /* @escapeNotVerified */  __('For better results, add attributes and attribute values to your products.') ?>
-            </div>
-        </div>
-    </div>
-    <?= $block->getChildHtml(); ?>
-</div>
diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/templates/catalog/product/edit/super/matrix.phtml b/app/code/Magento/ConfigurableProduct/view/adminhtml/templates/catalog/product/edit/super/matrix.phtml
index 9d66be34c0d79a94e889a3d506c88d95e1c502bd..7f33ce7274d9b955716e756a69a87a491be216ad 100644
--- a/app/code/Magento/ConfigurableProduct/view/adminhtml/templates/catalog/product/edit/super/matrix.phtml
+++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/templates/catalog/product/edit/super/matrix.phtml
@@ -12,6 +12,7 @@
 $variations = $block->getVariations();
 $productMatrix = [];
 $attributes = [];
+$fullAttributes = [];
 if ($variations) {
     $usedProductAttributes = $block->getUsedAttributes();
     $productByUsedAttributes = $block->getAssociatedProducts();
@@ -36,6 +37,17 @@ if ($variations) {
                         'position' => $attribute->getPosition(),
                         'chosen' => [],
                     ];
+                    foreach ($attribute->getOptions() as $option) {
+                        if (!empty($option->getValue())) {
+                            $attributes[$attribute->getAttributeId()]['options'][$option->getValue()] = [
+                                'attribute_code' => $attribute->getAttributeCode(),
+                                'attribute_label' => $attribute->getStoreLabel(0),
+                                'id' => $option->getValue(),
+                                'label' => $option->getLabel(),
+                                'value' => $option->getValue(),
+                            ];
+                        }
+                    }
                 }
                 $optionId = $variation[$attribute->getId()]['value'];
                 $variationOption = [
@@ -320,16 +332,13 @@ if ($variations) {
                 "components": {
                     "configurableVariations": {
                         "component": "Magento_ConfigurableProduct/js/variations/variations",
-                        "variations": <?= /* @escapeNotVerified */  $this->helper('Magento\Framework\Json\Helper\Data')->jsonEncode($productMatrix) ?>,
-                        "productAttributes": <?= /* @escapeNotVerified */  $this->helper('Magento\Framework\Json\Helper\Data')->jsonEncode($attributes) ?>,
-                        "productUrl": "<?= /* @escapeNotVerified */  $block->getUrl('catalog/product/edit', ['id' => '%id%']) ?>",
-                        "associatedProductsFilter": "configurable_associated_product_listing.configurable_associated_product_listing.listing_top.listing_filters",
-                        "associatedProductsProvider": "configurable_associated_product_listing.data_source"
-
+                        "variations": <?= /* @noEscape */ $this->helper('Magento\Framework\Json\Helper\Data')->jsonEncode($productMatrix) ?>,
+                        "productAttributes": <?= /* @noEscape */ $this->helper('Magento\Framework\Json\Helper\Data')->jsonEncode($attributes) ?>,
+                        "productUrl": "<?= /* @noEscape */ $block->getUrl('catalog/product/edit', ['id' => '%id%']) ?>",
+                        "configurableProductGrid": "configurableProductGrid"
                     }
                 }
             }
         }
     }
-
 </script>
diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/ui_component/configurable_associated_product_listing.xml b/app/code/Magento/ConfigurableProduct/view/adminhtml/ui_component/configurable_associated_product_listing.xml
index aee041d2b5bb8e7e6198b807e51738f5c9f67e81..f8ff2b7872c7cac2898d4e1baa2c12bc03520db4 100644
--- a/app/code/Magento/ConfigurableProduct/view/adminhtml/ui_component/configurable_associated_product_listing.xml
+++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/ui_component/configurable_associated_product_listing.xml
@@ -40,43 +40,33 @@
         <filters name="listing_filters" class="Magento\ConfigurableProduct\Ui\Component\Listing\AssociatedProduct\Filters">
             <argument name="data" xsi:type="array">
                 <item name="config" xsi:type="array">
-                    <item name="links" xsi:type="array">
-                        <item name="applied" xsi:type="string">not-save-filter</item>
+                    <item name="params" xsi:type="array">
+                        <item name="filters_modifier" xsi:type="array" />
                     </item>
                     <item name="displayArea" xsi:type="string">dataGridFilters</item>
                     <item name="dataScope" xsi:type="string">filters</item>
-                    <item name="storageConfig" xsi:type="array">
-                        <item name="provider" xsi:type="string">configurable_associated_product_listing.configurable_associated_product_listing.listing_top.bookmarks</item>
-                        <item name="namespace" xsi:type="string">current.filters</item>
-                    </item>
                     <item name="childDefaults" xsi:type="array">
                         <item name="provider" xsi:type="string">configurable_associated_product_listing.configurable_associated_product_listing.listing_top.listing_filters</item>
-                        <item name="imports" xsi:type="array">
-                            <item name="visible" xsi:type="string">configurable_associated_product_listing.configurable_associated_product_listing.listing_top.bookmarks:current.columns.${ $.index }.visible</item>
-                        </item>
                     </item>
                 </item>
             </argument>
-            <filterInput name="name">
+            <filterInput name="entity_id">
                 <argument name="data" xsi:type="array">
                     <item name="config" xsi:type="array">
-                        <item name="dataScope" xsi:type="string">name</item>
+                        <item name="component" xsi:type="string" />
+                        <item name="dataScope" xsi:type="string">entity_id</item>
                         <item name="label" xsi:type="string" translate="true">Name</item>
                     </item>
                 </argument>
             </filterInput>
-            <filterSelect name="attribute_set_id">
-                <argument name="optionsProvider" xsi:type="configurableObject">
-                    <argument name="class" xsi:type="string">Magento\Catalog\Model\Product\AttributeSet\Options</argument>
-                </argument>
+            <filterInput name="name">
                 <argument name="data" xsi:type="array">
                     <item name="config" xsi:type="array">
-                        <item name="dataScope" xsi:type="string">attribute_set_id</item>
-                        <item name="caption" xsi:type="string" translate="true">Select...</item>
-                        <item name="label" xsi:type="string" translate="true">Attribute Set</item>
+                        <item name="dataScope" xsi:type="string">name</item>
+                        <item name="label" xsi:type="string" translate="true">Name</item>
                     </item>
                 </argument>
-            </filterSelect>
+            </filterInput>
             <filterInput name="sku">
                 <argument name="data" xsi:type="array">
                     <item name="config" xsi:type="array">
@@ -131,10 +121,6 @@
             <argument name="data" xsi:type="array">
                 <item name="config" xsi:type="array">
                     <item name="selectProvider" xsi:type="string">configurable_associated_product_listing.configurable_associated_product_listing.product_columns.ids</item>
-                    <item name="storageConfig" xsi:type="array">
-                        <item name="provider" xsi:type="string">configurable_associated_product_listing.configurable_associated_product_listing.listing_top.bookmarks</item>
-                        <item name="namespace" xsi:type="string">current.paging</item>
-                    </item>
                     <item name="displayArea" xsi:type="string">bottom</item>
                     <item name="options" xsi:type="array">
                         <item name="20" xsi:type="array">
@@ -162,27 +148,18 @@
             </argument>
         </paging>
     </container>
-    <columns name="product_columns" class="Magento\Catalog\Ui\Component\Listing\Columns">
+    <columns name="product_columns" class="Magento\ConfigurableProduct\Ui\Component\Listing\AssociatedProduct\Columns">
         <argument name="data" xsi:type="array">
             <item name="config" xsi:type="array">
-                <item name="storageConfig" xsi:type="array">
-                    <item name="provider" xsi:type="string">configurable_associated_product_listing.configurable_associated_product_listing.listing_top.bookmarks</item>
-                    <item name="namespace" xsi:type="string">current</item>
-                </item>
                 <item name="childDefaults" xsi:type="array">
                     <item name="fieldAction" xsi:type="array">
-                        <item name="provider" xsi:type="string">configurableVariations</item>
+                        <item name="provider" xsi:type="string">configurableProductGrid</item>
                         <item name="target" xsi:type="string">selectProduct</item>
                         <item name="params" xsi:type="array">
                             <item name="0" xsi:type="string">${ $.$data.rowIndex }</item>
                         </item>
                     </item>
                     <item name="controlVisibility" xsi:type="boolean">true</item>
-                    <item name="storageConfig" xsi:type="array">
-                        <item name="provider" xsi:type="string">configurable_associated_product_listing.configurable_associated_product_listing.listing_top.bookmarks</item>
-                        <item name="root" xsi:type="string">columns.${ $.index }</item>
-                        <item name="namespace" xsi:type="string">current.${ $.storageConfig.root}</item>
-                    </item>
                 </item>
             </item>
         </argument>
diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/advanced-pricing-handler.js b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/advanced-pricing-handler.js
new file mode 100644
index 0000000000000000000000000000000000000000..3943ac39574018ce7b10a6b4c4912d99b540e434
--- /dev/null
+++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/advanced-pricing-handler.js
@@ -0,0 +1,31 @@
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+define([
+    'jquery'
+], function ($) {
+    'use strict';
+
+    return {
+        init: function () {
+            $('[data-form=edit-product]')
+                .on('change_configurable_type', function (event, isConfigurable) {
+                    var toggleDisabledAttribute = function (disabled) {
+                        $('[data-tab-panel=advanced-pricing]').find('input,select').each(
+                            function (event, element) {
+                                $(element).attr('disabled', disabled);
+                            }
+                        );
+                    };
+                    if (isConfigurable) {
+                        $('[data-ui-id=product-tabs-tab-link-advanced-pricing]').hide();
+                    } else {
+                        $('[data-ui-id=product-tabs-tab-link-advanced-pricing]').show();
+                    }
+                    toggleDisabledAttribute(isConfigurable);
+                });
+        }
+    };
+});
diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/options/price-type-handler.js b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/options/price-type-handler.js
new file mode 100644
index 0000000000000000000000000000000000000000..fbee8e2b47873b78e6d2cc6d4c8acab5fefe2e26
--- /dev/null
+++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/options/price-type-handler.js
@@ -0,0 +1,79 @@
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+define([
+    'jquery',
+    'notification',
+    'mage/translate'
+], function ($) {
+    'use strict';
+
+    return {
+        isConfigurable: false,
+        messageInited: false,
+        messageSelector: '[data-role=product-custom-options-content]',
+        isPercentPriceTypeExist: function () {
+            var productOptionsContainer = $('#product_options_container_top');
+
+            return !!productOptionsContainer.length;
+        },
+        showWarning: function () {
+            if (!this.messageInited) {
+                $(this.messageSelector).notification();
+                this.messageInited = true;
+            }
+            this.hideWarning();
+            $(this.messageSelector).notification('add', {
+                message: $.mage.__('We can\'t save custom-defined options with price type "percent" for ' +
+                    'configurable product.'),
+                error: true,
+                messageContainer: this.messageSelector
+            });
+        },
+        hideWarning: function () {
+            $(this.messageSelector).notification('clear');
+        },
+        init: function () {
+            $('[data-form=edit-product]')
+                .on('change_configurable_type', function (event, isConfigurable) {
+                    this.isConfigurable = isConfigurable;
+                    if (this.isPercentPriceTypeExist()) {
+                        this.percentPriceTypeHandler();
+                    }
+                }.bind(this));
+
+            $('#product-edit-form-tabs').on('change', '.opt-type > select', function () {
+                var selected = $('.opt-type > select :selected'),
+                    optGroup = selected.parent().attr('label');
+
+                if (optGroup === 'Select') {
+                    $('#product-edit-form-tabs').on(
+                        'click',
+                        '[data-ui-id="admin-product-options-options-box-select-option-type-add-select-row-button"]',
+                        function () {
+                            this.percentPriceTypeHandler();
+                        }.bind(this)
+                    );
+                } else {
+                    this.percentPriceTypeHandler();
+                }
+            }.bind(this));
+        },
+        percentPriceTypeHandler: function () {
+            var priceType = $('[data-attr="price-type"]'),
+                optionPercentPriceType = priceType.find('option[value="percent"]');
+
+            if (this.isConfigurable) {
+                this.showWarning();
+                optionPercentPriceType.hide();
+                optionPercentPriceType.parent().val() === 'percent' ? optionPercentPriceType.parent().val('fixed') : '';
+            } else {
+                $(this.messageSelector).notification();
+                optionPercentPriceType.show();
+                this.hideWarning();
+            }
+        }
+    };
+});
\ No newline at end of file
diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/product-grid.js b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/product-grid.js
new file mode 100644
index 0000000000000000000000000000000000000000..39267f93a149ee3247773d529e7ac8cd293e2860
--- /dev/null
+++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/product-grid.js
@@ -0,0 +1,344 @@
+// jscs:disable requireDotNotation
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+define([
+    'uiComponent',
+    'jquery',
+    'Magento_Ui/js/core/app',
+    'underscore',
+    'notification'
+], function (Component, $, bootstrap, _) {
+    'use strict';
+
+    return Component.extend({
+        defaults: {
+            productsGridUrl: null,
+            productAttributes: [],
+            productsModal: null,
+            button: '',
+            gridSelector: '[data-grid-id=associated-products-container]',
+            modules: {
+                productsFilter: '${ $.productsFilter }',
+                productsProvider: '${ $.productsProvider }',
+                productsMassAction: '${ $.productsMassAction }',
+                productsColumns: '${ $.productsColumns }',
+                variationsComponent: '${ $.configurableVariations }'
+            },
+            listens: {
+                '${ $.productsProvider }:data': '_showMessageAssociatedGrid _handleManualGridOpening',
+                '${ $.productsMassAction }:selected': '_handleManualGridSelect',
+                '${ $.configurableVariations }:productMatrix': '_showButtonAddManual'
+            }
+        },
+
+        /**
+         * Initialize
+         * @param {Array} options
+         */
+        initialize: function (options) {
+            this._super(options);
+            this.productsModal = $(this.gridSelector).modal({
+                title: $.mage.__('Select Associated Product'),
+                type: 'slide',
+                buttons: [
+                    {
+                        text: $.mage.__('Cancel'),
+
+                        /**
+                         * Close modal
+                         * @event
+                         */
+                        click: function () {
+                            this.closeModal();
+                        }
+                    }, {
+                        text: $.mage.__('Done'),
+                        click: this.close.bind(this, null)
+                    }
+                ]
+            });
+
+            this.productsProvider(function () {
+                this.productsModal.notification();
+            }.bind(this));
+            this.variationsComponent(function (variation) {
+                this._showButtonAddManual(variation.productMatrix());
+            }.bind(this));
+
+            this._initGrid = _.once(this._initGrid);
+        },
+
+        /**
+         * Initial observerable
+         * @returns {*}
+         */
+        initObservable: function () {
+            this._super().observe('button');
+
+            return this;
+        },
+
+        /**
+         * init Grid
+         * @private
+         */
+        _initGrid: function (filterData) {
+            $.ajax({
+                type: 'GET',
+                url: this._buildGridUrl(filterData),
+                context: $('body')
+            }).success(function (data) {
+                bootstrap(JSON.parse(data));
+            });
+        },
+
+        /**
+         * Select different product in configurations section
+         * @see configurable_associated_product_listing.xml
+         * @param {Integer} rowIndex
+         */
+        selectProduct: function (rowIndex) {
+            this.close(rowIndex);
+        },
+
+        /**
+         * Open
+         * @param {Object} filterData - filter data
+         * @param {Object|*} filterData.filters - attribute name
+         * @param {Object|*} filterData.filters_modifier - modifier value
+         * @param {String} callbackName
+         * @param {Boolean} showMassActionColumn
+         */
+        open: function (filterData, callbackName, showMassActionColumn) {
+            this.callbackName = callbackName;
+            this.productsMassAction(function (massActionComponent) {
+                this.productsColumns().elems().each(function (rowElement) {
+                    rowElement.disableAction(showMassActionColumn);
+                });
+                massActionComponent.visible(showMassActionColumn);
+            }.bind(this));
+            this._setFilter(filterData);
+            this._initGrid(filterData);
+            this.productsModal.trigger('openModal');
+        },
+
+        /**
+         * Close
+         */
+        close: function (rowIndex) {
+            try {
+                if (this.productsMassAction().selected().length) {
+                    this.variationsComponent()[this.callbackName](this.productsMassAction()
+                        .selected.map(this.getProductById.bind(this)));
+                    this.productsMassAction().selected([]);
+                } else if (!_.isNull(rowIndex)) {
+                    this.variationsComponent()[this.callbackName]([this.getProductByIndex(rowIndex)]);
+                }
+                this.productsModal.trigger('closeModal');
+            } catch (e) {
+                if (e.name === 'UserException') {
+                    this.productsModal.notification('clear');
+                    this.productsModal.notification('add', {
+                        message: e.message,
+                        messageContainer: this.gridSelector
+                    });
+                } else {
+                    throw e;
+                }
+            }
+        },
+
+        /**
+         * Get product by id
+         * @param {Integer} productId
+         * @returns {*}
+         */
+        getProductById: function (productId) {
+            return _.findWhere(this.productsProvider().data.items, {
+                'entity_id': productId
+            });
+        },
+
+        /**
+         * Get product
+         * @param {Integer} rowIndex
+         * @returns {*}
+         */
+        getProductByIndex: function (rowIndex) {
+            return this.productsProvider().data.items[rowIndex];
+        },
+
+        /**
+         * Build grid url
+         * @private
+         */
+        _buildGridUrl: function (filterData) {
+            var params = '?' + $.param({
+                'filters': filterData.filters,
+                'attributes_codes': this._getAttributesCodes(),
+                'filters_modifier': filterData['filters_modifier']
+            });
+
+            return this.productsGridUrl + params;
+        },
+
+        /**
+         * Show button add manual
+         * @param {Array} variations
+         * @returns {*}
+         * @private
+         */
+        _showButtonAddManual: function (variations) {
+            return this.button(variations.length);
+        },
+
+        /**
+         * Get attributes codes used for configurable
+         * @private
+         */
+        _getAttributesCodes: function () {
+            return this.variationsComponent().attributes.pluck('code');
+        },
+
+        /**
+         * Show data associated grid
+         * @private
+         */
+        _showMessageAssociatedGrid: function (data) {
+            this.productsModal.notification('clear');
+
+            if (data.items.length) {
+                this.productsModal.notification('add', {
+                    message: $.mage.__(
+                        'Choose a new product to delete and replace the current product configuration.'
+                    ),
+                    messageContainer: this.gridSelector
+                });
+            } else {
+                this.productsModal.notification('add', {
+                    message: $.mage.__('For better results, add attributes and attribute values to your products.'),
+                    messageContainer: this.gridSelector
+                });
+            }
+        },
+
+        /**
+         * Show manually grid
+         */
+        showManuallyGrid: function () {
+            var filterModifier = _.mapObject(_.object(this._getAttributesCodes(), []), function () {
+                    return {
+                        'condition_type': 'notnull'
+                    };
+                }),
+                usedProductIds = _.values(this.variationsComponent().productAttributesMap);
+
+            if (usedProductIds) {
+                filterModifier['entity_id'] = {
+                    'condition_type': 'nin', value: usedProductIds
+                };
+            }
+
+            this.open(
+                {
+                    'filters_modifier': filterModifier
+                },
+                'appendProducts',
+                true
+            );
+        },
+
+        /**
+         * Handle manual grid after opening
+         * @private
+         */
+        _handleManualGridOpening: function (data) {
+            if (data.items.length && this.callbackName == 'appendProducts') {
+                this.productsColumns().elems().each(function (rowElement) {
+                    rowElement.disableAction(true);
+                });
+
+                this._disableRows(data.items);
+            }
+        },
+
+        /**
+         * Disable rows in grid for products with the same variation key
+         *
+         * @param {Array} items
+         * @param {Array} selectedVariationKeys
+         * @param {Array} selected
+         * @private
+         */
+        _disableRows: function (items, selectedVariationKeys, selected) {
+            selectedVariationKeys = selectedVariationKeys === undefined ? [] : selectedVariationKeys;
+            selected = selected === undefined ? [] : selected;
+            this.productsMassAction(function (massaction) {
+                var configurableVariationKeys = _.union(
+                        selectedVariationKeys,
+                        _.pluck(this.variationsComponent().productMatrix(), 'variationKey')
+                    ),
+                    variationKeyMap = this._getVariationKeyMap(items),
+                    rowsForDisable = _.keys(_.pick(
+                        variationKeyMap,
+                        function (variationKey) {
+                            return configurableVariationKeys.indexOf(variationKey) != -1;
+                        }
+                    ));
+
+                massaction.disabled(_.difference(rowsForDisable, selected));
+            }.bind(this));
+        },
+
+        /**
+         * @private
+         */
+        _handleManualGridSelect: function (selected) {
+            if (this.callbackName == 'appendProducts') {
+                var selectedRows = _.filter(this.productsProvider().data.items, function (row) {
+                        return selected.indexOf(row['entity_id']) != -1;
+                    }),
+                    selectedVariationKeys = _.values(this._getVariationKeyMap(selectedRows));
+                this._disableRows(this.productsProvider().data.items, selectedVariationKeys, selected);
+            }
+        },
+
+        /**
+         * Get variation key map used in manual grid.
+         *
+         * @param items
+         * @returns {Array} [{entity_id: variation-key}, ...]
+         * @private
+         */
+        _getVariationKeyMap: function (items) {
+            this._variationKeyMap = {};
+            _.each(items, function (row) {
+                this._variationKeyMap[row['entity_id']] = _.values(
+                    _.pick(row, this._getAttributesCodes())
+                ).sort().join('-');
+
+            }.bind(this));
+            return this._variationKeyMap;
+        },
+
+        /**
+         * Set filter
+         * @private
+         */
+        _setFilter: function (filterData) {
+            this.productsProvider(function (provider) {
+                provider.params['filters_modifier'] = filterData['filters_modifier'];
+                provider.params['attributes_codes'] = this._getAttributesCodes();
+            }.bind(this));
+
+            this.productsFilter(function (filter) {
+                filter.set('filters', _.extend({
+                    'filters_modifier': filterData['filters_modifier']
+                }, filterData.filters))
+                    .apply();
+            });
+        }
+    });
+});
diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/steps/attributes_values.js b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/steps/attributes_values.js
index fd928ca0f777904475b554dc3923e7eff93a1ee0..78eac86cb658f129ff6836571a5e19c5eff6ec42 100644
--- a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/steps/attributes_values.js
+++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/steps/attributes_values.js
@@ -2,6 +2,7 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
+// jscs:disable jsDoc
 define([
     'uiComponent',
     'jquery',
@@ -15,16 +16,17 @@ define([
 
     //connect items with observableArrays
     ko.bindingHandlers.sortableList = {
-        init: function(element, valueAccessor) {
+        init: function (element, valueAccessor) {
             var list = valueAccessor();
 
             $(element).sortable({
                 axis: 'y',
                 handle: '[data-role="draggable"]',
                 tolerance: 'pointer',
-                update: function(event, ui) {
-                    var item = ko.contextFor(ui.item[0]).$data;
-                    var position = ko.utils.arrayIndexOf(ui.item.parent().children(), ui.item[0]);
+                update: function (event, ui) {
+                    var item = ko.contextFor(ui.item[0]).$data,
+                        position = ko.utils.arrayIndexOf(ui.item.parent().children(), ui.item[0]);
+
                     if (ko.contextFor(ui.item[0]).$index() != position) {
                         if (position >= 0) {
                             list.remove(item);
@@ -38,25 +40,35 @@ define([
     };
 
     return Collapsible.extend({
-        stepInitialized: false,
-        attributes: ko.observableArray([]),
         defaults: {
             notificationMessage: {
                 text: null,
                 error: null
-            }
+            },
+            createOptionsUrl: null,
+            attributes: [],
+            stepInitialized: false
         },
         initialize: function () {
             this._super();
-            this.createAttribute = _.wrap(this.createAttribute.bind(this), function () {
-                var args = Array.prototype.slice.call(arguments);
-                return this.doInitSavedOptions.call(this, args.shift().apply(this, args));
+            this.createAttribute = _.wrap(this.createAttribute, function () {
+                var args = _.toArray(arguments),
+                    createAttribute = args.shift();
+
+                return this.doInitSavedOptions(createAttribute.apply(this, args));
             });
             this.createAttribute = _.memoize(this.createAttribute.bind(this), _.property('id'));
         },
+        initObservable: function () {
+            this._super().observe(['attributes']);
+
+            return this;
+        },
         createOption: function () {
             // this - current attribute
-            this.options.push({value: 0, label: '', id: utils.uniqueid(), attribute_id: this.id, is_new: true});
+            this.options.push({
+                value: 0, label: '', id: utils.uniqueid(), attribute_id: this.id, is_new: true
+            });
         },
         saveOption: function (option) {
             if (!_.isEmpty(option.label)) {
@@ -78,6 +90,7 @@ define([
             attribute.chosenOptions = ko.observableArray([]);
             attribute.options = ko.observableArray(_.map(attribute.options, function (option) {
                 option.id = utils.uniqueid();
+
                 return option;
             }));
             attribute.opened = ko.observable(this.initialOpened(index));
@@ -91,15 +104,19 @@ define([
         },
         saveAttribute: function () {
             var errorMessage = $.mage.__('Select options for all attributes or remove unused attributes.');
-            this.attributes.each(function(attribute) {
+            this.attributes.each(function (attribute) {
                 attribute.chosen = [];
+
                 if (!attribute.chosenOptions.getLength()) {
                     throw new Error(errorMessage);
                 }
-                attribute.chosenOptions.each(function(id) {
-                    attribute.chosen.push(attribute.options.findWhere({id:id}));
+                attribute.chosenOptions.each(function (id) {
+                    attribute.chosen.push(attribute.options.findWhere({
+                        id: id
+                    }));
                 });
             });
+
             if (!this.attributes().length) {
                 throw new Error(errorMessage);
             }
@@ -110,30 +127,37 @@ define([
         deSelectAllAttributes: function (attribute) {
             attribute.chosenOptions.removeAll();
         },
-        saveOptions: function() {
+        saveOptions: function () {
             var options = [];
 
-            this.attributes.each(function(attribute) {
-                attribute.chosenOptions.each(function(id) {
-                    var option = attribute.options.findWhere({id:id, is_new: true});
+            this.attributes.each(function (attribute) {
+                attribute.chosenOptions.each(function (id) {
+                    var option = attribute.options.findWhere({
+                        id: id, is_new: true
+                    });
 
                     if (option) {
                         options.push(option);
                     }
                 });
             });
+
             if (!options.length) {
                 return false;
             }
             $.ajax({
-                type: "POST",
+                type: 'POST',
                 url: this.createOptionsUrl,
-                data: {options: options},
+                data: {
+                    options: options
+                },
                 showLoader: true
-            }).done(function(options) {
-                this.attributes.each(function(attribute) {
-                    _.each(options, function(newOptionId, oldOptionId) {
-                        var option = attribute.options.findWhere({id:oldOptionId});
+            }).done(function (savedOptions) {
+                this.attributes.each(function (attribute) {
+                    _.each(savedOptions, function (newOptionId, oldOptionId) {
+                        var option = attribute.options.findWhere({
+                            id: oldOptionId
+                        });
 
                         if (option) {
                             attribute.options.remove(option);
@@ -148,41 +172,46 @@ define([
         },
         requestAttributes: function (attributeIds) {
             $.ajax({
-                type: "POST",
+                type: 'POST',
                 url: this.optionsUrl,
-                data: {attributes: attributeIds},
+                data: {
+                    attributes: attributeIds
+                },
                 showLoader: true
-            }).done(function(attributes){
-                attributes = _.sortBy(attributes, function(attribute) {
+            }).done(function (attributes) {
+                attributes = _.sortBy(attributes, function (attribute) {
                     return this.wizard.data.attributesIds.indexOf(attribute.id);
                 }.bind(this));
                 this.attributes(_.map(attributes, this.createAttribute));
             }.bind(this));
         },
-        doInitSavedOptions: function(attribute) {
-            var selectedAttribute = _.findWhere(this.initData.attributes, {id: attribute.id});
+        doInitSavedOptions: function (attribute) {
+            var selectedOptions, selectedOptionsIds, selectedAttribute = _.findWhere(this.initData.attributes, {
+                id: attribute.id
+            });
 
             if (selectedAttribute) {
-                var selectedOptions = _.pluck(selectedAttribute.chosen, 'value');
-                var selectedOptionsIds = _.pluck(_.filter(attribute.options(), function (option) {
+                selectedOptions = _.pluck(selectedAttribute.chosen, 'value');
+                selectedOptionsIds = _.pluck(_.filter(attribute.options(), function (option) {
                     return _.contains(selectedOptions, option.value);
                 }), 'id');
                 attribute.chosenOptions(selectedOptionsIds);
                 this.initData.attributes = _.without(this.initData.attributes, selectedAttribute);
             }
+
             return attribute;
         },
-        render: function(wizard) {
+        render: function (wizard) {
             this.wizard = wizard;
             this.requestAttributes(wizard.data.attributesIds());
         },
-        force: function(wizard) {
+        force: function (wizard) {
             this.saveOptions();
             this.saveAttribute(wizard);
 
             wizard.data.attributes = this.attributes;
         },
-        back: function(wizard) {
+        back: function (wizard) {
             wizard.data.attributesIds(this.attributes().pluck('id'));
         }
     });
diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/steps/bulk.js b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/steps/bulk.js
index bf58fc27d47a4c8a17698fc1177688392edbf124..435a7ace21418d35de1bf96cf4b24b490315258b 100644
--- a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/steps/bulk.js
+++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/steps/bulk.js
@@ -4,6 +4,7 @@
  */
 /*jshint browser:true jquery:true*/
 /*global FORM_KEY*/
+// jscs:disable jsDoc
 define([
     'uiComponent',
     'jquery',
@@ -25,8 +26,8 @@ define([
             attributes: [],
             sections: {},
             images: null,
-            price: "",
-            quantity: "",
+            price: '',
+            quantity: '',
             notificationMessage: {
                 text: null,
                 error: null
@@ -34,6 +35,7 @@ define([
         },
         initObservable: function () {
             this._super().observe('countVariations attributes sections');
+
             return this;
         },
         initialize: function () {
@@ -67,13 +69,15 @@ define([
                 this.quantity = self.quantity;
             };
             this.makeImages = function (images, typePreview) {
+                var preview;
+
                 if (!images) {
                     this.images = [];
                     this.preview = self.noImage;
                     this.file = null;
                 } else {
                     this.images = images;
-                    var preview = _.find(this.images, function (image) {
+                    preview = _.find(this.images, function (image) {
                         return _.contains(image.galleryTypes, typePreview);
                     });
 
@@ -87,25 +91,27 @@ define([
                 }
             };
             this.images = new this.makeImages();
-            _.each(this.sections(), function(section) {
-                section.type.subscribe(function(newValue) {
-                   this.setWizardNotifyMessageDependOnSectionType()
+            _.each(this.sections(), function (section) {
+                section.type.subscribe(function () {
+                    this.setWizardNotifyMessageDependOnSectionType();
                 }.bind(this));
             }, this);
         },
         types: ['each', 'single', 'none'],
-        setWizardNotifyMessageDependOnSectionType: function() {
+        setWizardNotifyMessageDependOnSectionType: function () {
             var flag = false;
 
-            _.each(this.sections(), function(section) {
+            _.each(this.sections(), function (section) {
                 if (section.type() !== 'none') {
                     flag = true;
                 }
             }, this);
 
             if (flag) {
-                this.wizard.setNotificationMessage($.mage.__('Choose this option to delete and replace extension data '+
-                    'for all past configurations.'));
+                this.wizard.setNotificationMessage(
+                    $.mage.__('Choose this option to delete and replace extension data ' +
+                    'for all past configurations.')
+                );
             } else {
                 this.wizard.cleanNotificationMessage();
             }
@@ -113,7 +119,8 @@ define([
         render: function (wizard) {
             this.wizard = wizard;
             this.attributes(wizard.data.attributes());
-            if (this.mode == 'edit') {
+
+            if (this.mode === 'edit') {
                 this.setWizardNotifyMessageDependOnSectionType();
             }
             //fill option section data
@@ -130,35 +137,39 @@ define([
             this.initCountVariations();
             this.bindGalleries();
         },
-        initCountVariations: function() {
-            var variations = this.generateVariation(this.attributes());
-            var newVariations = _.map(variations, function(options) {
-                return this.variationsComponent().getVariationKey(options)
-            }.bind(this));
-            var existingVariations = _.keys(this.variationsComponent().productAttributesMap);
+        initCountVariations: function () {
+            var variations = this.generateVariation(this.attributes()),
+                newVariations = _.map(variations, function (options) {
+                    return this.variationsComponent().getVariationKey(options);
+                }.bind(this)),
+                existingVariations = _.keys(this.variationsComponent().productAttributesMap);
             this.countVariations(_.difference(newVariations, existingVariations).length);
-        } ,
+        },
+
         /**
          * @param attributes example [['b1', 'b2'],['a1', 'a2', 'a3'],['c1', 'c2', 'c3'],['d1']]
          * @returns {*} example [['b1','a1','c1','d1'],['b1','a1','c2','d1']...]
          */
         generateVariation: function (attributes) {
-            return _.reduce(attributes, function(matrix, attribute) {
+            return _.reduce(attributes, function (matrix, attribute) {
                 var tmp = [];
-                _.each(matrix, function(variations){
-                    _.each(attribute.chosen, function(option){
+                _.each(matrix, function (variations) {
+                    _.each(attribute.chosen, function (option) {
                         option.attribute_code = attribute.code;
                         option.attribute_label = attribute.label;
                         tmp.push(_.union(variations, [option]));
                     });
                 });
+
                 if (!tmp.length) {
-                    return _.map(attribute.chosen, function(option){
+                    return _.map(attribute.chosen, function (option) {
                         option.attribute_code = attribute.code;
                         option.attribute_label = attribute.label;
+
                         return [option];
                     });
                 }
+
                 return tmp;
             }, []);
         },
@@ -170,18 +181,20 @@ define([
                             return chosen.id == option.id;
                         });
                     }).sections()[section];
+
                 case 'single':
                     return this.sections()[section].value();
+
                 case 'none':
                     return this[section];
             }
         },
         getImageProperty: function (node) {
-            var types = node.find('[data-role=gallery]').productGallery('option').types;
-            var images = _.map(node.find('[data-role=image]'), function (image) {
+            var types = node.find('[data-role=gallery]').productGallery('option').types,
+                images = _.map(node.find('[data-role=image]'), function (image) {
                 var imageData = $(image).data('imageData');
                 imageData.galleryTypes = _.pluck(_.filter(types, function (type) {
-                    return type.value == imageData.file;
+                    return type.value === imageData.file;
                 }), 'code');
 
                 return imageData;
@@ -197,18 +210,20 @@ define([
                     if (this.sections().images.attribute()) {
                         this.sections().images.attribute().chosen.each(function (option) {
                             option.sections().images = new this.makeImages(
-                                this.getImageProperty($('[data-role=step-gallery-option-'+option.id+']')),
+                                this.getImageProperty($('[data-role=step-gallery-option-' + option.id + ']')),
                                 'thumbnail'
                             );
                         }, this);
                     }
                     break;
+
                 case 'single':
                     this.sections().images.value(new this.makeImages(
                         this.getImageProperty($('[data-role=step-gallery-single]')),
                         'thumbnail'
                     ));
                     break;
+
                 default:
                     this.sections().images.value(new this.makeImages());
                     break;
@@ -223,6 +238,7 @@ define([
             wizard.data.variations = this.generateVariation(this.attributes());
         },
         validate: function () {
+            var formValid;
             _.each(this.sections(), function (section) {
                 switch (section.type()) {
                     case 'each':
@@ -230,6 +246,7 @@ define([
                             throw new Error($.mage.__('Please, select attribute for the section ' + section.label));
                         }
                         break;
+
                     case 'single':
                         if (!section.value()) {
                             throw new Error($.mage.__('Please fill in the values for the section ' + section.label));
@@ -237,23 +254,25 @@ define([
                         break;
                 }
             }, this);
-            var formValid = true;
-            _.each($('[data-role=attributes-values-form]'), function(form) {
+            formValid = true;
+            _.each($('[data-role=attributes-values-form]'), function (form) {
                 formValid = $(form).valid() && formValid;
             });
+
             if (!formValid) {
                 throw new Error($.mage.__('Please, fill correct values'));
             }
         },
-        validateImage: function() {
+        validateImage: function () {
             switch (this.sections().images.type()) {
                 case 'each':
-                    _.each(this.sections()['images'].attribute().chosen, function(option) {
+                    _.each(this.sections()['images'].attribute().chosen, function (option) {
                         if (!option.sections().images.images.length) {
                             throw new Error($.mage.__('Please, select image(s) for your attribute'));
                         }
                     });
                     break;
+
                 case 'single':
                     if (this.sections().images.value().file == null) {
                         throw new Error($.mage.__('Please choose image(s)'));
diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/steps/select_attributes.js b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/steps/select_attributes.js
index b80e8332ed282b942ae870b6171e114e0c604fc0..ab242b267d7eb4c9325392e33a90714f088f0983 100644
--- a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/steps/select_attributes.js
+++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/steps/select_attributes.js
@@ -2,16 +2,17 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
+// jscs:disable jsDoc
 define([
     'uiComponent',
     'jquery',
     'underscore',
     'mage/translate'
 ], function (Component, $, _) {
-    "use strict";
+    'use strict';
 
     var initNewAttributeListener = function (provider) {
-        $('[data-role=product-variations-generator]').on('add', function() {
+        $('[data-role=product-variations-generator]').on('add', function () {
             provider().reload();
         });
     };
@@ -31,7 +32,8 @@ define([
             notificationMessage: {
                 text: null,
                 error: null
-            }
+            },
+            selectedAttributes: []
         },
         initialize: function () {
             this._super();
@@ -41,6 +43,7 @@ define([
         },
         initObservable: function () {
             this._super().observe(['selectedAttributes']);
+
             return this;
         },
         render: function (wizard) {
@@ -48,28 +51,33 @@ define([
             this.setNotificationMessage();
         },
         setNotificationMessage: function () {
-            if (this.mode == 'edit') {
+            if (this.mode === 'edit') {
                 this.wizard.setNotificationMessage($.mage.__('When you remove or add an attribute, we automatically ' +
                 'update all configurations and you will need to manually recreate the current configurations.'));
             }
         },
-        doSelectSavedAttributes: function() {
-            if (false === this.stepInitialized) {
+        doSelectSavedAttributes: function () {
+            if (this.stepInitialized === false) {
                 this.stepInitialized = true;
                 //cache attributes labels, which can be present on the 2nd page
-                _.each(this.initData.attributes, function(attribute) {
+                _.each(this.initData.attributes, function (attribute) {
                     this.attributesLabels[attribute.id] = attribute.label;
                 }.bind(this));
                 this.multiselect().selected(_.pluck(this.initData.attributes, 'id'));
             }
         },
-        doSelectedAttributesLabels: function(selected) {
+        doSelectedAttributesLabels: function (selected) {
             var labels = [];
 
             this.selected = selected;
-            _.each(selected, function(attributeId) {
+            _.each(selected, function (attributeId) {
+                var attribute;
+
                 if (!this.attributesLabels[attributeId]) {
-                    var attribute = _.findWhere(this.multiselect().rows(), {attribute_id: attributeId});
+                    attribute = _.findWhere(this.multiselect().rows(), {
+                        attribute_id: attributeId
+                    });
+
                     if (attribute) {
                         this.attributesLabels[attribute.attribute_id] = attribute.frontend_label;
                     }
diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/steps/summary.js b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/steps/summary.js
index c04b2e9931c7c5b9804ab3ab9c63d7ce34f80ae7..0da35357808085b8fe91792cd7bdac8e523a3e37 100644
--- a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/steps/summary.js
+++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/steps/summary.js
@@ -2,6 +2,7 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
+// jscs:disable jsDoc
 define([
     'uiComponent',
     'jquery',
@@ -33,42 +34,49 @@ define([
             this.gridExisting.columns = ko.observableArray();
             this.gridNew.columns = ko.observableArray();
             this.gridDeleted.columns = ko.observableArray();
+
             return this;
         },
         nextLabelText: $.mage.__('Generate Products'),
         variations: [],
         generateGrid: function (variations, getSectionValue) {
-            var productName = this.variationsComponent().getProductValue('name');
-            var productPrice = this.variationsComponent().getProductValue('price');
-            var productWeight = this.variationsComponent().getProductValue('weight');
-            var variationsKeys = [];
-            var gridExisting = [];
-            var gridNew = [];
-            var gridDeleted = [];
+            var productName = this.variationsComponent().getProductValue('name'),
+                productPrice = this.variationsComponent().getProductValue('price'),
+                productWeight = this.variationsComponent().getProductValue('weight'),
+                variationsKeys = [],
+                gridExisting = [],
+                gridNew = [],
+                gridDeleted = [];
             this.variations = [];
 
             _.each(variations, function (options) {
-                var images, sku, quantity, price;
-                var productId = this.variationsComponent().getProductIdByOptions(options);
+                var product, images, sku, quantity, price, variation,
+                    productId = this.variationsComponent().getProductIdByOptions(options);
+
                 if (productId) {
-                    var product = _.findWhere(this.variationsComponent().variations, {productId: productId});
+                    product = _.findWhere(this.variationsComponent().variations, {
+                        productId: productId
+                    });
                 }
                 images = getSectionValue('images', options);
                 sku = productName + _.reduce(options, function (memo, option) {
                     return memo + '-' + option.label;
                 }, '');
                 quantity = getSectionValue('quantity', options);
+
                 if (!quantity && productId) {
                     quantity = product.quantity;
                 }
                 price = getSectionValue('price', options);
+
                 if (!price) {
                     price = productId ? product.price : productPrice;
                 }
+
                 if (productId && !images.file) {
                     images = product.images;
                 }
-                var variation = {
+                variation = {
                     options: options,
                     images: images,
                     sku: sku,
@@ -78,6 +86,7 @@ define([
                     weight: productWeight,
                     editable: true
                 };
+
                 if (productId) {
                     variation.sku = product.sku;
                     variation.weight = product.weight;
@@ -99,7 +108,9 @@ define([
 
             _.each(_.omit(this.variationsComponent().productAttributesMap, variationsKeys), function (productId) {
                 gridDeleted.push(this.prepareRowForGrid(
-                    _.findWhere(this.variationsComponent().variations, {productId: productId})
+                    _.findWhere(this.variationsComponent().variations, {
+                        productId: productId
+                    })
                 ));
             }.bind(this));
 
@@ -108,9 +119,11 @@ define([
                 this.gridDeleted.columns(this.getColumnsName(this.variationsComponent().productAttributes));
             }
         },
-        prepareRowForGrid: function(variation) {
+        prepareRowForGrid: function (variation) {
             var row = [];
-            row.push(_.extend({images: []}, variation.images));
+            row.push(_.extend({
+                images: []
+            }, variation.images));
             row.push(variation.sku);
             row.push(variation.quantity);
             _.each(variation.options, function (option) {
@@ -120,10 +133,10 @@ define([
 
             return row;
         },
-        getGridTemplate: function() {
+        getGridTemplate: function () {
             return this.gridTemplate;
         },
-        getGridId: function() {
+        getGridId: function () {
             return _.uniqueId('grid_');
         },
         getColumnsName: function (attributes) {
@@ -144,11 +157,11 @@ define([
             this.gridDeleted([]);
             this.generateGrid(wizard.data.variations, wizard.data.sectionHelper);
         },
-        force: function (wizard) {
+        force: function () {
             this.variationsComponent().render(this.variations, this.attributes());
             $('[data-role=step-wizard-dialog]').trigger('closeModal');
         },
-        back: function (wizard) {
+        back: function () {
         }
     });
 });
diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/variations.js b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/variations.js
index dea945abb299764a3ec86592abbf89d049e220ca..9688fb2bb08c33a6ad5327e59a24a8e3889a8739 100644
--- a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/variations.js
+++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/variations.js
@@ -1,7 +1,9 @@
+// jscs:disable requireDotNotation
 /**
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
+// jscs:disable jsDoc
 define([
     'uiComponent',
     'jquery',
@@ -10,6 +12,12 @@ define([
 ], function (Component, $, ko, _) {
     'use strict';
 
+    function UserException(message) {
+        this.message = message;
+        this.name = 'UserException';
+    }
+    UserException.prototype = Object.create(Error.prototype);
+
     return Component.extend({
         defaults: {
             opened: false,
@@ -17,62 +25,132 @@ define([
             productMatrix: [],
             variations: [],
             productAttributes: [],
+            fullAttributes: [],
             rowIndexToEdit: false,
             productAttributesMap: null,
             modules: {
-                associatedProductsFilter: '${ $.associatedProductsFilter }',
-                associatedProductsProvider: '${ $.associatedProductsProvider }'
+                associatedProductGrid: '${ $.configurableProductGrid }'
             }
         },
         initialize: function () {
             this._super();
+
             if (this.variations.length) {
                 this.render(this.variations, this.productAttributes);
             }
             this.initProductAttributesMap();
         },
-        /**
-         * Select different product in configurations section
-         * @param rowIndex
-         */
-        selectProduct: function (rowIndex) {
-            var productToEdit = this.productMatrix.splice(this.rowIndexToEdit, 1)[0],
-                newProduct = this.associatedProductsProvider().data.items[rowIndex];
-
-            newProduct = _.extend(productToEdit, newProduct);
-            newProduct.productId = productToEdit.entity_id;
-            newProduct.productUrl = this.buildProductUrl(newProduct.entity_id);
-            newProduct.editable = false;
-            newProduct.images = {preview: newProduct.thumbnail_src};
-            this.productAttributesMap[this.getVariationKey(newProduct.options)] = newProduct.productId;
-            this.productMatrix.splice(this.rowIndexToEdit, 0, newProduct);
-            $('#associated-products-container').trigger('closeModal');
-        },
         initObservable: function () {
             this._super().observe('actions opened attributes productMatrix');
+
             return this;
         },
+        showGrid: function (rowIndex) {
+            var product = this.productMatrix()[rowIndex],
+                attributes = JSON.parse(product.attribute);
+            this.rowIndexToEdit = rowIndex;
+
+            this.associatedProductGrid().open(
+                {
+                    'filters': attributes,
+                    'filters_modifier': product.productId ? {
+                        'entity_id': {
+                            'condition_type': 'neq', value: product.productId
+                        }
+                    } : {}
+                },
+                'changeProduct',
+                false
+            );
+        },
+        changeProduct: function (newProducts) {
+            var oldProduct = this.productMatrix()[this.rowIndexToEdit],
+                newProduct = this._makeProduct(_.extend(oldProduct, newProducts[0]));
+            this.productAttributesMap[this.getVariationKey(newProduct.options)] = newProduct.productId;
+            this.productMatrix.splice(this.rowIndexToEdit, 1, newProduct);
+        },
+        appendProducts: function (newProducts) {
+            this.productMatrix.push.apply(
+                this.productMatrix,
+                _.map(
+                    newProducts,
+                    _.wrap(
+                        this._makeProduct.bind(this),
+                        function (func, product) {
+                            var newProduct = func(product);
+                            this.productAttributesMap[this.getVariationKey(newProduct.options)] = newProduct.productId;
+
+                            return newProduct;
+                        }.bind(this)
+                    )
+                )
+            );
+        },
+        _makeProduct: function (product) {
+            var productId = product['entity_id'] || product.productId || null,
+                attributes = _.pick(product, this.attributes.pluck('code')),
+                options = _.map(attributes, function (option, attribute) {
+                    var oldOptions = _.findWhere(this.attributes(), {
+                            code: attribute
+                        }).options,
+                        result;
+
+                    if (_.isFunction(oldOptions)) {
+                        result = oldOptions.findWhere({
+                            value: option
+                        });
+                    } else {
+                        result = _.findWhere(oldOptions, {
+                            value: option
+                        });
+                    }
+
+                    return result;
+                }.bind(this));
+
+            return {
+                attribute: JSON.stringify(attributes),
+                editable: false,
+                images: {
+                    preview: product['thumbnail_src']
+                },
+                name: product.name || product.sku,
+                options: options,
+                price: parseFloat(product.price.replace(/[^\d.]+/g, '')).toFixed(4),
+                productId: productId,
+                productUrl: this.buildProductUrl(productId),
+                quantity: product.quantity || null,
+                sku: product.sku,
+                status: product.status === undefined ? 1 : parseInt(product.status, 10),
+                variationKey: this.getVariationKey(options),
+                weight: product.weight || null
+            };
+        },
         getProductValue: function (name) {
             return $('[name="product[' + name.split('/').join('][') + ']"]', this.productForm).val();
         },
         getRowId: function (data, field) {
             var key = data.variationKey;
+
             return 'variations-matrix-' + key + '-' + field;
         },
-        getVariationRowName: function(variation, field) {
+        getVariationRowName: function (variation, field) {
+            var result;
+
             if (variation.productId) {
-                return 'configurations[' + variation.productId + '][' + field.split('/').join('][') + ']';
+                result = 'configurations[' + variation.productId + '][' + field.split('/').join('][') + ']';
             } else {
-                var key = variation.variationKey;
-                return 'variations-matrix[' + key + '][' + field.split('/').join('][') + ']';
+                result = 'variations-matrix[' + variation.variationKey + '][' + field.split('/').join('][') + ']';
             }
+
+            return result;
         },
         getAttributeRowName: function (attribute, field) {
             return 'product[configurable_attributes_data][' + attribute.id + '][' + field + ']';
         },
         getOptionRowName: function (attribute, option, field) {
-            return 'product[configurable_attributes_data][' + attribute.id + '][values][' + option.value + ']['
-                + field + ']';
+            return 'product[configurable_attributes_data][' + attribute.id + '][values][' +
+                option.value + '][' + field + ']';
         },
         render: function (variations, attributes) {
             this.changeButtonWizard();
@@ -85,6 +163,14 @@ define([
             var $button = $('[data-action=open-steps-wizard] [data-role=button-label]');
             $button.text($button.attr('data-edit-label'));
         },
+
+        /**
+         * Get attributes options
+         * @see use in matrix.phtml
+         * @function
+         * @event
+         * @returns {array}
+         */
         getAttributesOptions: function () {
             return this.showVariations() ? this.productMatrix()[0].options : [];
         },
@@ -96,7 +182,8 @@ define([
             _.each(variations, function (variation) {
                 var attributes = _.reduce(variation.options, function (memo, option) {
                     var attribute = {};
-                    attribute[option.attribute_code] = option.value;
+                    attribute[option['attribute_code']] = option.value;
+
                     return _.extend(memo, attribute);
                 }, {});
                 this.productMatrix.push(_.extend(variation, {
@@ -104,10 +191,10 @@ define([
                     name: variation.name || variation.sku,
                     weight: variation.weight,
                     attribute: JSON.stringify(attributes),
-                    variationKey: _.values(attributes).join('-'),
+                    variationKey: this.getVariationKey(variation.options),
                     editable: variation.editable === undefined ? !variation.productId : variation.editable,
                     productUrl: this.buildProductUrl(variation.productId),
-                    status: variation.status === undefined ? 1 : parseInt(variation.status)
+                    status: variation.status === undefined ? 1 : parseInt(variation.status, 10)
                 }));
             }, this);
         },
@@ -116,38 +203,35 @@ define([
         },
         removeProduct: function (rowIndex) {
             this.opened(false);
-            this.productMatrix.splice(rowIndex, 1);
+            var removedProduct = this.productMatrix.splice(rowIndex, 1);
+            delete this.productAttributesMap[this.getVariationKey(removedProduct[0].options)];
+
             if (this.productMatrix().length === 0) {
-                this.attributes.each(function(attribute) {
+                this.attributes.each(function (attribute) {
                     $('[data-attribute-code="' + attribute.code + '"] select').removeProp('disabled');
                 });
             }
         },
-        showGrid: function (rowIndex) {
-            var attributes = JSON.parse(this.productMatrix()[rowIndex].attribute);
-            this.rowIndexToEdit = rowIndex;
-            this.associatedProductsProvider().params.attribute_ids = _.keys(attributes);
-            this.associatedProductsFilter().set('filters', attributes).apply();
-            $('#associated-products-container').trigger('openModal');
-        },
         toggleProduct: function (rowIndex) {
-            var productChanged = {};
+            var product, row, productChanged = {};
+
             if (this.productMatrix()[rowIndex].editable) {
-                var row = $('[data-row-number=' + rowIndex + ']');
-                _.each('name,sku,qty,weight,price'.split(','), function (column) {
+                row = $('[data-row-number=' + rowIndex + ']');
+                _.each(['name','sku','qty','weight','price'], function (column) {
                     productChanged[column] = $(
                         'input[type=text]',
                         row.find($('[data-column="%s"]'.replace('%s', column)))
                     ).val();
                 });
             }
-            var product = this.productMatrix.splice(rowIndex, 1)[0];
+            product = this.productMatrix.splice(rowIndex, 1)[0];
             product = _.extend(product, productChanged);
-            product.status = !product.status * 1;
+            product.status = +!product.status;
             this.productMatrix.splice(rowIndex, 0, product);
         },
         toggleList: function (rowIndex) {
             var state = false;
+
             if (rowIndex !== this.opened()) {
                 state = rowIndex;
             }
@@ -169,100 +253,110 @@ define([
             return this.productAttributesMap[this.getVariationKey(options)] || null;
         },
         initProductAttributesMap: function () {
-            if (null === this.productAttributesMap) {
+            if (this.productAttributesMap === null) {
                 this.productAttributesMap = {};
-                _.each(this.variations, function(product) {
+                _.each(this.variations, function (product) {
                     this.productAttributesMap[this.getVariationKey(product.options)] = product.productId;
                 }.bind(this));
             }
         },
+
+        /**
+         * Is show preview image
+         * @see use in matrix.phtml
+         * @function
+         * @event
+         * @param {object} variation
+         * @returns {*|boolean}
+         */
         isShowPreviewImage: function (variation) {
             return variation.images.preview && (!variation.editable || variation.images.file);
         },
         generateImageGallery: function (variation) {
-            var gallery = [];
-            var imageFields = ['position', 'file', 'disabled', 'label'];
+            var gallery = [],
+                imageFields = ['position', 'file', 'disabled', 'label'];
             _.each(variation.images.images, function (image) {
                 _.each(imageFields, function (field) {
                     gallery.push(
-                        '<input type="hidden" name="'
-                        + this.getVariationRowName(variation, 'media_gallery/images/' + image.file_id + '/' + field)
-                        + '" value="' + (image[field] || '') + '" />'
+                        '<input type="hidden" name="' +
+                        this.getVariationRowName(variation, 'media_gallery/images/' + image['file_id'] + '/' + field) +
+                        '" value="' + (image[field] || '') + '" />'
                     );
                 }, this);
                 _.each(image.galleryTypes, function (imageType) {
                     gallery.push(
-                        '<input type="hidden" name="' + this.getVariationRowName(variation, imageType)
-                        + '" value="' + image.file + '" />'
+                        '<input type="hidden" name="' + this.getVariationRowName(variation, imageType) +
+                        '" value="' + image.file + '" />'
                     );
                 }, this);
             }, this);
+
             return gallery.join('\n');
         },
         initImageUpload: function () {
             require([
-                "jquery",
-                "mage/template",
-                "jquery/file-uploader",
-                "mage/mage",
-                "mage/translate"
-            ], function (jQuery, mageTemplate) {
+                'mage/template',
+                'jquery/file-uploader',
+                'mage/mage',
+                'mage/translate',
+                'domReady!'
+            ], function (mageTemplate) {
 
-                jQuery(function ($) {
-                    var matrix = $('[data-role=product-variations-matrix]');
-                    matrix.find('[data-action=upload-image]').find('[name=image]').each(function () {
-                        var imageColumn = $(this).closest('[data-column=image]');
-                        if (imageColumn.find('[data-role=image]').length) {
-                            imageColumn.find('[data-toggle=dropdown]').dropdown().show();
-                        }
-                        $(this).fileupload({
-                            dataType: 'json',
-                            dropZone: $(this).closest('[data-role=row]'),
-                            acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i,
-                            done: function (event, data) {
-                                var tmpl;
+                var matrix = $('[data-role=product-variations-matrix]');
+                matrix.find('[data-action=upload-image]').find('[name=image]').each(function () {
+                    var imageColumn = $(this).closest('[data-column=image]');
 
-                                if (!data.result) {
-                                    return;
-                                }
-                                if (!data.result.error) {
-                                    var parentElement = $(event.target).closest('[data-column=image]'),
-                                        uploaderControl = parentElement.find('[data-action=upload-image]'),
-                                        imageElement = parentElement.find('[data-role=image]');
+                    if (imageColumn.find('[data-role=image]').length) {
+                        imageColumn.find('[data-toggle=dropdown]').dropdown().show();
+                    }
+                    $(this).fileupload({
+                        dataType: 'json',
+                        dropZone: $(this).closest('[data-role=row]'),
+                        acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i,
+                        done: function (event, data) {
+                            var tmpl, parentElement, uploaderControl, imageElement;
+
+                            if (!data.result) {
+                                return;
+                            }
 
-                                    if (imageElement.length) {
-                                        imageElement.attr('src', data.result.url);
-                                    } else {
-                                        tmpl = mageTemplate(matrix.find('[data-template-for=variation-image]').html());
+                            if (!data.result.error) {
+                                parentElement = $(event.target).closest('[data-column=image]');
+                                uploaderControl = parentElement.find('[data-action=upload-image]');
+                                imageElement = parentElement.find('[data-role=image]');
 
-                                        $(tmpl({
-                                            data: data.result
-                                        })).prependTo(uploaderControl);
-                                    }
-                                    parentElement.find('[name$="[image]"]').val(data.result.file);
-                                    parentElement.find('[data-toggle=dropdown]').dropdown().show();
+                                if (imageElement.length) {
+                                    imageElement.attr('src', data.result.url);
                                 } else {
-                                    alert($.mage.__('We don\'t recognize or support this file extension type.'));
+                                    tmpl = mageTemplate(matrix.find('[data-template-for=variation-image]').html());
+
+                                    $(tmpl({
+                                        data: data.result
+                                    })).prependTo(uploaderControl);
                                 }
-                            },
-                            start: function (event) {
-                                $(event.target).closest('[data-action=upload-image]').addClass('loading');
-                            },
-                            stop: function (event) {
-                                $(event.target).closest('[data-action=upload-image]').removeClass('loading');
+                                parentElement.find('[name$="[image]"]').val(data.result.file);
+                                parentElement.find('[data-toggle=dropdown]').dropdown().show();
+                            } else {
+                                alert($.mage.__('We don\'t recognize or support this file extension type.'));
                             }
-                        });
-                    });
-                    matrix.find('[data-action=no-image]').click(function (event) {
-                        var parentElement = $(event.target).closest('[data-column=image]');
-                        parentElement.find('[data-role=image]').remove();
-                        parentElement.find('[name$="[image]"]').val('');
-                        parentElement.find('[data-toggle=dropdown]').trigger('close.dropdown').hide();
+                        },
+                        start: function (event) {
+                            $(event.target).closest('[data-action=upload-image]').addClass('loading');
+                        },
+                        stop: function (event) {
+                            $(event.target).closest('[data-action=upload-image]').removeClass('loading');
+                        }
                     });
                 });
+                matrix.find('[data-action=no-image]').click(function (event) {
+                    var parentElement = $(event.target).closest('[data-column=image]');
+                    parentElement.find('[data-role=image]').remove();
+                    parentElement.find('[name$="[image]"]').val('');
+                    parentElement.find('[data-toggle=dropdown]').trigger('close.dropdown').hide();
+                });
             });
         },
-        disableConfigurableAttributes: function(attributes) {
+        disableConfigurableAttributes: function (attributes) {
             _.each(attributes, function (attribute) {
                 $('[data-attribute-code="' + attribute.code + '"] select').prop('disabled', true);
             });
diff --git a/app/code/Magento/Cron/composer.json b/app/code/Magento/Cron/composer.json
index b1afc6a19518bbc523a02f2c0db4f669510a0e67..653e1f8443cbba8f049eb397c299bde7ec9ac3f6 100644
--- a/app/code/Magento/Cron/composer.json
+++ b/app/code/Magento/Cron/composer.json
@@ -3,11 +3,13 @@
     "description": "N/A",
     "require": {
         "php": "~5.5.0|~5.6.0|~7.0.0",
-        "magento/module-config": "1.0.0-beta",
         "magento/module-store": "1.0.0-beta",
         "magento/framework": "1.0.0-beta",
         "magento/magento-composer-installer": "*"
     },
+    "suggest": {
+        "magento/module-config": "1.0.0-beta"
+    },
     "type": "magento2-module",
     "version": "1.0.0-beta",
     "license": [
diff --git a/app/code/Magento/Customer/Model/AccountManagement.php b/app/code/Magento/Customer/Model/AccountManagement.php
old mode 100644
new mode 100755
diff --git a/app/code/Magento/Customer/Model/Resource/CustomerRepository.php b/app/code/Magento/Customer/Model/Resource/CustomerRepository.php
index 45bca42044092acc519258e045ebcdd864e70782..429210512de90ab81b93290918b34e533ba1d879 100644
--- a/app/code/Magento/Customer/Model/Resource/CustomerRepository.php
+++ b/app/code/Magento/Customer/Model/Resource/CustomerRepository.php
@@ -340,8 +340,7 @@ class CustomerRepository implements \Magento\Customer\Api\CustomerRepositoryInte
 
         $isEmailAddress = \Zend_Validate::is(
             $customer->getEmail(),
-            'EmailAddress',
-            ['allow' => ['allow' => \Zend_Validate_Hostname::ALLOW_ALL, 'tld' => false]]
+            'EmailAddress'
         );
 
         if (!$isEmailAddress) {
diff --git a/app/code/Magento/Customer/Test/Unit/Model/AccountManagementTest.php b/app/code/Magento/Customer/Test/Unit/Model/AccountManagementTest.php
old mode 100644
new mode 100755
diff --git a/app/code/Magento/Customer/view/frontend/templates/account/customer.phtml b/app/code/Magento/Customer/view/frontend/templates/account/customer.phtml
index 4d208d4136c981d6204278a72dd19139d3afb926..8bc96494817b8a969c280243a6248a190b7b38dc 100644
--- a/app/code/Magento/Customer/view/frontend/templates/account/customer.phtml
+++ b/app/code/Magento/Customer/view/frontend/templates/account/customer.phtml
@@ -19,7 +19,8 @@
             <span data-bind="text: customer().fullname"></span>
             <button type="button"
                     class="action switch"
-                    tabindex="-1">
+                    tabindex="-1"
+                    data-action="customer-menu-toggle">
                 <span><?php /* @escapeNotVerified */ echo __('Change')?></span>
             </button>
         </span>
diff --git a/app/code/Magento/Dhl/composer.json b/app/code/Magento/Dhl/composer.json
index 033291581ecafaa67d0cb60d76d38aa6f75b3c85..1f577af21d55cb1100238b9b8ce5a9bfc43ab029 100644
--- a/app/code/Magento/Dhl/composer.json
+++ b/app/code/Magento/Dhl/composer.json
@@ -9,7 +9,6 @@
         "magento/module-backend": "1.0.0-beta",
         "magento/module-directory": "1.0.0-beta",
         "magento/module-sales": "1.0.0-beta",
-        "magento/module-checkout": "1.0.0-beta",
         "magento/module-catalog": "1.0.0-beta",
         "magento/module-catalog-inventory": "1.0.0-beta",
         "magento/module-quote": "1.0.0-beta",
@@ -17,6 +16,9 @@
         "lib-libxml": "*",
         "magento/magento-composer-installer": "*"
     },
+    "suggest": {
+        "magento/module-checkout": "1.0.0-beta"
+    },
     "type": "magento2-module",
     "version": "1.0.0-beta",
     "license": [
diff --git a/app/code/Magento/GiftMessage/composer.json b/app/code/Magento/GiftMessage/composer.json
index c3662869435b747e9c1ebbfc828ed2e2316f1dc9..6230e36ff13e4051816047af7c4960e4b94dc0e5 100644
--- a/app/code/Magento/GiftMessage/composer.json
+++ b/app/code/Magento/GiftMessage/composer.json
@@ -6,7 +6,6 @@
         "magento/module-store": "1.0.0-beta",
         "magento/module-catalog": "1.0.0-beta",
         "magento/module-checkout": "1.0.0-beta",
-        "magento/module-multishipping": "1.0.0-beta",
         "magento/module-sales": "1.0.0-beta",
         "magento/module-backend": "1.0.0-beta",
         "magento/module-customer": "1.0.0-beta",
@@ -15,6 +14,9 @@
         "magento/framework": "1.0.0-beta",
         "magento/magento-composer-installer": "*"
     },
+    "suggest": {
+      "magento/module-multishipping": "1.0.0-beta"
+    },
     "type": "magento2-module",
     "version": "1.0.0-beta",
     "license": [
diff --git a/app/code/Magento/Msrp/composer.json b/app/code/Magento/Msrp/composer.json
index 14446581255e6b3fd52a7c5dce2fe32077a34a63..b5d603e700e321f17c6233a065f913d76782285c 100644
--- a/app/code/Magento/Msrp/composer.json
+++ b/app/code/Magento/Msrp/composer.json
@@ -4,7 +4,6 @@
     "require": {
         "php": "~5.5.0|~5.6.0|~7.0.0",
         "magento/module-store": "1.0.0-beta",
-        "magento/module-bundle": "1.0.0-beta",
         "magento/module-catalog": "1.0.0-beta",
         "magento/module-downloadable": "1.0.0-beta",
         "magento/module-eav": "1.0.0-beta",
@@ -14,6 +13,9 @@
         "magento/framework": "1.0.0-beta",
         "magento/magento-composer-installer": "*"
     },
+    "suggest": {
+        "magento/module-bundle": "1.0.0-beta"
+    },
     "type": "magento2-module",
     "version": "1.0.0-beta",
     "license": [
diff --git a/app/code/Magento/OfflineShipping/composer.json b/app/code/Magento/OfflineShipping/composer.json
index 8a0287dd1dc6496b18ae5742406cec7799c2a05b..88ac36533cbf5bd62183cb8722ef2613e241dd49 100644
--- a/app/code/Magento/OfflineShipping/composer.json
+++ b/app/code/Magento/OfflineShipping/composer.json
@@ -11,11 +11,13 @@
         "magento/module-sales": "1.0.0-beta",
         "magento/module-sales-rule": "1.0.0-beta",
         "magento/module-directory": "1.0.0-beta",
-        "magento/module-checkout": "1.0.0-beta",
         "magento/module-quote": "1.0.0-beta",
         "magento/framework": "1.0.0-beta",
         "magento/magento-composer-installer": "*"
     },
+    "suggest": {
+        "magento/module-checkout": "1.0.0-beta"
+    },
     "type": "magento2-module",
     "version": "1.0.0-beta",
     "license": [
diff --git a/app/code/Magento/Payment/Model/Method/AbstractMethod.php b/app/code/Magento/Payment/Model/Method/AbstractMethod.php
index 81d0afc88763fe9a1f7ed09a049770ccbfc55767..9d8ba1fffd62c5239ea8735c38a28916d4e67a5f 100644
--- a/app/code/Magento/Payment/Model/Method/AbstractMethod.php
+++ b/app/code/Magento/Payment/Model/Method/AbstractMethod.php
@@ -58,6 +58,8 @@ abstract class AbstractMethod extends \Magento\Framework\Model\AbstractExtensibl
 
     const CHECK_ZERO_TOTAL = 'zero_total';
 
+    const GROUP_OFFLINE = 'offline';
+
     /**
      * @var string
      */
diff --git a/app/code/Magento/Rule/Model/AbstractModel.php b/app/code/Magento/Rule/Model/AbstractModel.php
index 988a9e2beca59c3b12da13a0123e2b7b858778a6..20bb67ca0632c708946d9961f22099b1f810128a 100644
--- a/app/code/Magento/Rule/Model/AbstractModel.php
+++ b/app/code/Magento/Rule/Model/AbstractModel.php
@@ -350,19 +350,19 @@ abstract class AbstractModel extends \Magento\Framework\Model\AbstractModel
     /**
      * Validate rule data
      *
-     * @param \Magento\Framework\DataObject $object
+     * @param \Magento\Framework\DataObject $dataObject
      * @return bool|string[] - return true if validation passed successfully. Array with errors description otherwise
      * @SuppressWarnings(PHPMD.CyclomaticComplexity)
      * @SuppressWarnings(PHPMD.NPathComplexity)
      */
-    public function validateData(\Magento\Framework\DataObject $object)
+    public function validateData(\Magento\Framework\DataObject $dataObject)
     {
         $result = [];
         $fromDate = $toDate = null;
 
-        if ($object->hasFromDate() && $object->hasToDate()) {
-            $fromDate = $object->getFromDate();
-            $toDate = $object->getToDate();
+        if ($dataObject->hasFromDate() && $dataObject->hasToDate()) {
+            $fromDate = $dataObject->getFromDate();
+            $toDate = $dataObject->getToDate();
         }
 
         if ($fromDate && $toDate) {
@@ -374,14 +374,14 @@ abstract class AbstractModel extends \Magento\Framework\Model\AbstractModel
             }
         }
 
-        if ($object->hasWebsiteIds()) {
-            $websiteIds = $object->getWebsiteIds();
+        if ($dataObject->hasWebsiteIds()) {
+            $websiteIds = $dataObject->getWebsiteIds();
             if (empty($websiteIds)) {
                 $result[] = __('Please specify a website.');
             }
         }
-        if ($object->hasCustomerGroupIds()) {
-            $customerGroupIds = $object->getCustomerGroupIds();
+        if ($dataObject->hasCustomerGroupIds()) {
+            $customerGroupIds = $dataObject->getCustomerGroupIds();
             if (empty($customerGroupIds)) {
                 $result[] = __('Please specify Customer Groups.');
             }
diff --git a/app/code/Magento/Sales/Block/Adminhtml/Report/Filter/Form.php b/app/code/Magento/Sales/Block/Adminhtml/Report/Filter/Form.php
index b7aefa2d344ef1d56b5a9797092e1542bb43a382..340a9501ef57b7eed9fe68e2024cb98ec9421f78 100644
--- a/app/code/Magento/Sales/Block/Adminhtml/Report/Filter/Form.php
+++ b/app/code/Magento/Sales/Block/Adminhtml/Report/Filter/Form.php
@@ -67,7 +67,7 @@ class Form extends \Magento\Reports\Block\Adminhtml\Filter\Form
                     'name' => 'show_order_statuses',
                     'label' => __('Order Status'),
                     'options' => ['0' => __('Any'), '1' => __('Specified')],
-                    'note' => __('Applies to Any of the Specified Order Statuses')
+                    'note' => __('Applies to Any of the Specified Order Statuses except canceled orders')
                 ],
                 'to'
             );
diff --git a/app/code/Magento/Store/App/Response/Redirect.php b/app/code/Magento/Store/App/Response/Redirect.php
index 96e46e47432a126dc78b8af324733ebe16dbc64e..1b041e6f05e487ad93c88c6d95da8c9ce1bf98cf 100644
--- a/app/code/Magento/Store/App/Response/Redirect.php
+++ b/app/code/Magento/Store/App/Response/Redirect.php
@@ -7,6 +7,8 @@
  */
 namespace Magento\Store\App\Response;
 
+use Magento\Store\Api\StoreResolverInterface;
+
 class Redirect implements \Magento\Framework\App\Response\RedirectInterface
 {
     /**
@@ -94,6 +96,8 @@ class Redirect implements \Magento\Framework\App\Response\RedirectInterface
 
         if (!$this->_isUrlInternal($refererUrl)) {
             $refererUrl = $this->_storeManager->getStore()->getBaseUrl();
+        } else {
+            $refererUrl = $this->normalizeRefererUrl($refererUrl);
         }
         return $refererUrl;
     }
@@ -210,4 +214,57 @@ class Redirect implements \Magento\Framework\App\Response\RedirectInterface
         }
         return false;
     }
+
+    /**
+     * Normalize path to avoid wrong store change
+     *
+     * @param string $refererUrl
+     * @return string
+     */
+    protected function normalizeRefererUrl($refererUrl)
+    {
+        if (!$refererUrl || !filter_var($refererUrl, FILTER_VALIDATE_URL)) {
+            return $refererUrl;
+        }
+
+        $redirectParsedUrl = parse_url($refererUrl);
+        $refererQuery = [];
+
+        if (!isset($redirectParsedUrl['query'])) {
+            return $refererUrl;
+        }
+
+        parse_str($redirectParsedUrl['query'], $refererQuery);
+
+        $refererQuery = $this->normalizeRefererQueryParts($refererQuery);
+        $normalizedUrl = $redirectParsedUrl['scheme']
+            . '://'
+            . $redirectParsedUrl['host']
+            . (isset($redirectParsedUrl['port']) ? ':' . $redirectParsedUrl['port'] : '')
+            . $redirectParsedUrl['path']
+            . ($refererQuery ? '?' . http_build_query($refererQuery) : '');
+
+        return $normalizedUrl;
+    }
+
+    /**
+     * Normalize special parts of referer query
+     *
+     * @param array $refererQuery
+     * @return array
+     */
+    protected function normalizeRefererQueryParts($refererQuery)
+    {
+        $store = $this->_storeManager->getStore();
+
+        if (
+            $store
+            && !empty($refererQuery[StoreResolverInterface::PARAM_NAME])
+            && ($refererQuery[StoreResolverInterface::PARAM_NAME] !== $store->getCode())
+        ) {
+            $refererQuery[StoreResolverInterface::PARAM_NAME] = $store->getCode();
+        }
+
+        return $refererQuery;
+    }
 }
diff --git a/app/code/Magento/Store/etc/cache.xml b/app/code/Magento/Store/etc/cache.xml
index 6dae6b683b09121e6bc3820d0d797fda2d7877bc..715a5a12e55b2534294eb688907d3522cbfa5e5e 100644
--- a/app/code/Magento/Store/etc/cache.xml
+++ b/app/code/Magento/Store/etc/cache.xml
@@ -22,6 +22,10 @@
         <label>Collections Data</label>
         <description>Collection data files.</description>
     </type>
+    <type name="reflection" translate="label,description" instance="Magento\Framework\App\Cache\Type\Reflection">
+        <label>Reflection Data</label>
+        <description>API interfaces reflection data.</description>
+    </type>
     <type name="db_ddl" translate="label,description" instance="Magento\Framework\DB\Adapter\DdlCache">
         <label>Database DDL operations</label>
         <description>Results of DDL queries, such as describing tables or indexes.</description>
diff --git a/app/code/Magento/Store/etc/di.xml b/app/code/Magento/Store/etc/di.xml
index c8bc755197c49bb0f7aa5e0351784fe7a8b04ef9..617fefa4091297f0d0ef9cd76b8a3f97d309b2bc 100644
--- a/app/code/Magento/Store/etc/di.xml
+++ b/app/code/Magento/Store/etc/di.xml
@@ -225,6 +225,11 @@
             </argument>
         </arguments>
     </type>
+    <type name="Magento\Framework\Reflection\MethodsMap">
+        <arguments>
+            <argument name="cache" xsi:type="object">Magento\Framework\App\Cache\Type\Reflection</argument>
+        </arguments>
+    </type>
     <type name="Magento\Framework\Url">
         <arguments>
             <argument name="scopeType" xsi:type="const">Magento\Store\Model\ScopeInterface::SCOPE_STORE</argument>
diff --git a/app/code/Magento/Swagger/view/frontend/layout/swagger_index_index.xml b/app/code/Magento/Swagger/view/frontend/layout/swagger_index_index.xml
index a43a5c7885a96a19534c859bf0051cb225044c18..8ce4c95f94275746b0df6182cbf15052c4ff1934 100644
--- a/app/code/Magento/Swagger/view/frontend/layout/swagger_index_index.xml
+++ b/app/code/Magento/Swagger/view/frontend/layout/swagger_index_index.xml
@@ -37,9 +37,8 @@
     </head>
     <body>
         <!--Remove Magento page content-->
-        <remove name="page.wrapper"/>
-        <remove name="after.body.start"/>
-        <remove name="page.bottom"/>
+        <referenceContainer name="page.wrapper" remove="true"/>
+        <referenceBlock name="requirejs-config" remove="true"/>
         <referenceContainer name="root">
             <block name="swaggerUiContent" class="Magento\Framework\View\Element\Template" template="Magento_Swagger::swagger-ui/index.phtml"/>
         </referenceContainer>
diff --git a/app/code/Magento/Swagger/view/frontend/templates/swagger-ui/index.phtml b/app/code/Magento/Swagger/view/frontend/templates/swagger-ui/index.phtml
index b9c6e924b3dc9575ea6ed19f867810402f6bf4bc..16f25fd80861cd9e2918969aaa9036507a36de22 100644
--- a/app/code/Magento/Swagger/view/frontend/templates/swagger-ui/index.phtml
+++ b/app/code/Magento/Swagger/view/frontend/templates/swagger-ui/index.phtml
@@ -18,7 +18,7 @@ $schemaUrl = rtrim($block->getBaseUrl(), '/') . '/rest/default/schema?services=a
 ?>
 
 <!DOCTYPE html>
-<script language="text/javascript">
+<script>
     $(function () {
         var url = window.location.search.match(/url=([^&]+)/);
         if (url && url.length > 1) {
diff --git a/app/code/Magento/Swatches/composer.json b/app/code/Magento/Swatches/composer.json
index da38b6169f45d180cc72f4716ee5eae31b51a5d3..6cc94c567d3e8195cf6e7ded5d1d162b3fc193dc 100644
--- a/app/code/Magento/Swatches/composer.json
+++ b/app/code/Magento/Swatches/composer.json
@@ -11,11 +11,13 @@
         "magento/module-backend": "1.0.0-beta",
         "magento/module-media-storage": "1.0.0-beta",
         "magento/module-config": "1.0.0-beta",
-        "magento/module-layered-navigation": "1.0.0-beta",
         "magento/module-theme": "1.0.0-beta",
         "magento/framework": "1.0.0-beta",
         "magento/magento-composer-installer": "*"
     },
+    "suggest": {
+        "magento/module-layered-navigation": "1.0.0-beta"
+    },
     "type": "magento2-module",
     "version": "1.0.0-beta",
     "license": [
diff --git a/app/code/Magento/Theme/etc/di.xml b/app/code/Magento/Theme/etc/di.xml
index e8da51653dbcbd691b2fe595c9fd3c8a525089db..6b32e65b7ec19a9caa7b1af6ae4029b3b4ca9f11 100644
--- a/app/code/Magento/Theme/etc/di.xml
+++ b/app/code/Magento/Theme/etc/di.xml
@@ -82,7 +82,7 @@
     <type name="Magento\Theme\Model\View\Design">
         <arguments>
             <argument name="themes" xsi:type="array">
-                <item name="frontend" xsi:type="string">Magento/blank</item>
+                <item name="frontend" xsi:type="string">Magento/luma</item>
                 <item name="adminhtml" xsi:type="string">Magento/backend</item>
             </argument>
         </arguments>
diff --git a/app/code/Magento/Theme/view/adminhtml/page_layout/admin-login.xml b/app/code/Magento/Theme/view/adminhtml/page_layout/admin-login.xml
index 5c7c757a560dfd7ec48b78f5701e373d0a85674f..bba3e8c3cc482d1c4bd6975edc579ed3714a1571 100644
--- a/app/code/Magento/Theme/view/adminhtml/page_layout/admin-login.xml
+++ b/app/code/Magento/Theme/view/adminhtml/page_layout/admin-login.xml
@@ -7,6 +7,7 @@
 -->
 <layout xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../lib/internal/Magento/Framework/View/Layout/etc/page_layout.xsd">
     <container name="root" htmlTag="section" htmlClass="page-wrapper">
+        <container name="after.body.start" as="after.body.start" label="Page Top" before="-"/>
         <container name="login.header" htmlTag="header" htmlClass="login-header"/>
         <container name="login.content" htmlTag="div" htmlClass="login-content"/>
         <container name="login.footer" htmlTag="footer" htmlClass="login-footer"/>
diff --git a/app/code/Magento/Ui/Component/Filters/FilterModifier.php b/app/code/Magento/Ui/Component/Filters/FilterModifier.php
new file mode 100644
index 0000000000000000000000000000000000000000..d1db57a2ac49488c5f43cb516fab85de1c910185
--- /dev/null
+++ b/app/code/Magento/Ui/Component/Filters/FilterModifier.php
@@ -0,0 +1,74 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Ui\Component\Filters;
+
+use Magento\Framework\View\Element\UiComponent\DataProvider\DataProviderInterface;
+use Magento\Framework\App\RequestInterface;
+use Magento\Framework\Api\FilterBuilder;
+
+/**
+ * Apply modifiers to filter
+ */
+class FilterModifier
+{
+    /**
+     * Filter modifier variable name
+     */
+    const FILTER_MODIFIER = 'filters_modifier';
+
+    /** @var RequestInterface */
+    protected $request;
+
+    /** @var FilterBuilder */
+    protected $filterBuilder;
+
+    /** @var array */
+    protected $allowedConditionTypes;
+
+    /**
+     * @param RequestInterface $request
+     * @param FilterBuilder $filterBuilder
+     * @param array $allowedConditionTypes
+     */
+    public function __construct(RequestInterface $request, FilterBuilder $filterBuilder, $allowedConditionTypes = [])
+    {
+        $this->request = $request;
+        $this->filterBuilder = $filterBuilder;
+        $this->allowedConditionTypes = array_merge(
+            ['eq', 'neq', 'in', 'nin', 'null', 'notnull'],
+            $allowedConditionTypes
+        );
+    }
+
+    /**
+     * Apply modifiers for filters
+     *
+     * @param DataProviderInterface $dataProvider
+     * @param string $filterName
+     * @return void
+     * @throws \Magento\Framework\Exception\LocalizedException
+     */
+    public function applyFilterModifier(DataProviderInterface $dataProvider, $filterName)
+    {
+        $filterModifier = $this->request->getParam(self::FILTER_MODIFIER);
+        if (isset($filterModifier[$filterName]['condition_type'])) {
+            $conditionType = $filterModifier[$filterName]['condition_type'];
+            if (!in_array($conditionType, $this->allowedConditionTypes)) {
+                throw new \Magento\Framework\Exception\LocalizedException(
+                    __('Condition type "%1" is not allowed', $conditionType)
+                );
+            }
+            $value = isset($filterModifier[$filterName]['value'])
+                ? $filterModifier[$filterName]['value']
+                : null;
+            $filter = $this->filterBuilder->setConditionType($conditionType)
+                ->setField($filterName)
+                ->setValue($value)
+                ->create();
+            $dataProvider->addFilter($filter);
+        }
+    }
+}
diff --git a/app/code/Magento/Ui/Component/Filters/Type/AbstractFilter.php b/app/code/Magento/Ui/Component/Filters/Type/AbstractFilter.php
index 02b8767c3e263d3d03d27e34441be4d58fdad407..d5642acc8666b9651ea419d57b72d5b40a72e29c 100644
--- a/app/code/Magento/Ui/Component/Filters/Type/AbstractFilter.php
+++ b/app/code/Magento/Ui/Component/Filters/Type/AbstractFilter.php
@@ -9,6 +9,7 @@ use Magento\Ui\Component\AbstractComponent;
 use Magento\Framework\View\Element\UiComponentFactory;
 use Magento\Framework\View\Element\UiComponent\ContextInterface;
 use Magento\Framework\Api\FilterBuilder;
+use Magento\Ui\Component\Filters\FilterModifier;
 
 /**
  * Abstract class AbstractFilter
@@ -42,10 +43,16 @@ abstract class AbstractFilter extends AbstractComponent
      */
     protected $filterBuilder;
 
+    /**
+     * @var FilterModifier
+     */
+    protected $filterModifier;
+
     /**
      * @param ContextInterface $context
      * @param UiComponentFactory $uiComponentFactory
      * @param FilterBuilder $filterBuilder
+     * @param FilterModifier $filterModifier
      * @param array $components
      * @param array $data
      */
@@ -53,6 +60,7 @@ abstract class AbstractFilter extends AbstractComponent
         ContextInterface $context,
         UiComponentFactory $uiComponentFactory,
         FilterBuilder $filterBuilder,
+        FilterModifier $filterModifier,
         array $components = [],
         array $data = []
     ) {
@@ -60,6 +68,7 @@ abstract class AbstractFilter extends AbstractComponent
         $this->filterBuilder = $filterBuilder;
         parent::__construct($context, $components, $data);
         $this->filterData = $this->getContext()->getFiltersParams();
+        $this->filterModifier = $filterModifier;
     }
 
     /**
@@ -71,4 +80,13 @@ abstract class AbstractFilter extends AbstractComponent
     {
         return static::NAME;
     }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function prepare()
+    {
+        $this->filterModifier->applyFilterModifier($this->getContext()->getDataProvider(), $this->getName());
+        parent::prepare();
+    }
 }
diff --git a/app/code/Magento/Ui/Component/Filters/Type/Select.php b/app/code/Magento/Ui/Component/Filters/Type/Select.php
index 5b26dfc57daa514600aee606e2db588dfd46f816..8b826799993e988b673fce88702035f48042c9e8 100644
--- a/app/code/Magento/Ui/Component/Filters/Type/Select.php
+++ b/app/code/Magento/Ui/Component/Filters/Type/Select.php
@@ -9,6 +9,7 @@ use Magento\Framework\Data\OptionSourceInterface;
 use Magento\Framework\View\Element\UiComponentFactory;
 use Magento\Framework\View\Element\UiComponent\ContextInterface;
 use Magento\Ui\Component\Form\Element\Select as ElementSelect;
+use Magento\Ui\Component\Filters\FilterModifier;
 
 /**
  * Class Select
@@ -35,6 +36,7 @@ class Select extends AbstractFilter
      * @param ContextInterface $context
      * @param UiComponentFactory $uiComponentFactory
      * @param \Magento\Framework\Api\FilterBuilder $filterBuilder
+     * @param FilterModifier $filterModifier
      * @param OptionSourceInterface|null $optionsProvider
      * @param array $components
      * @param array $data
@@ -43,12 +45,13 @@ class Select extends AbstractFilter
         ContextInterface $context,
         UiComponentFactory $uiComponentFactory,
         \Magento\Framework\Api\FilterBuilder $filterBuilder,
+        FilterModifier $filterModifier,
         OptionSourceInterface $optionsProvider = null,
         array $components = [],
         array $data = []
     ) {
         $this->optionsProvider = $optionsProvider;
-        parent::__construct($context, $uiComponentFactory, $filterBuilder, $components, $data);
+        parent::__construct($context, $uiComponentFactory, $filterBuilder, $filterModifier, $components, $data);
     }
 
     /**
diff --git a/app/code/Magento/Ui/Component/Layout.php b/app/code/Magento/Ui/Component/Layout.php
index 2dd070f4f2d5445e9d8b46583a35a2b0b6ed511f..ab2a4b53a735001b5adaa8b8ee054390b48562e6 100644
--- a/app/code/Magento/Ui/Component/Layout.php
+++ b/app/code/Magento/Ui/Component/Layout.php
@@ -5,7 +5,7 @@
  */
 namespace Magento\Ui\Component;
 
-use Magento\Ui\Component\Layout\LayoutPool;
+use Magento\Framework\View\Layout\Pool as LayoutPool;
 use Magento\Framework\View\Element\Template;
 use Magento\Framework\View\Element\UiComponent\LayoutInterface;
 use Magento\Framework\View\Element\UiComponent\ContextInterface;
diff --git a/app/code/Magento/Ui/Component/Layout/Tabs.php b/app/code/Magento/Ui/Component/Layout/Tabs.php
index cd36ed90824792cdf68aaf97201d356f31a1741a..34021f0d8782d49a31647f87d92f114591304491 100644
--- a/app/code/Magento/Ui/Component/Layout/Tabs.php
+++ b/app/code/Magento/Ui/Component/Layout/Tabs.php
@@ -5,7 +5,6 @@
  */
 namespace Magento\Ui\Component\Layout;
 
-use Magento\Framework\Exception\LocalizedException;
 use Magento\Framework\View\Element\Template;
 use Magento\Framework\View\Element\UiComponent\DataSourceInterface;
 use Magento\Ui\Component\Layout\Tabs\TabInterface;
@@ -16,7 +15,7 @@ use Magento\Framework\View\Element\UiComponent\LayoutInterface;
 /**
  * Class Tabs
  */
-class Tabs extends Generic implements LayoutInterface
+class Tabs extends \Magento\Framework\View\Layout\Generic implements LayoutInterface
 {
     /**
      * @var string
diff --git a/app/code/Magento/Ui/TemplateEngine/Xhtml/Result.php b/app/code/Magento/Ui/TemplateEngine/Xhtml/Result.php
index 8060896296318c65ead5875a90b36e04ac6cdc0c..e2138de2221a918ceeeb17f25665d6d140cc1d13 100644
--- a/app/code/Magento/Ui/TemplateEngine/Xhtml/Result.php
+++ b/app/code/Magento/Ui/TemplateEngine/Xhtml/Result.php
@@ -5,7 +5,7 @@
  */
 namespace Magento\Ui\TemplateEngine\Xhtml;
 
-use Magento\Ui\Component\Layout\Generator\Structure;
+use Magento\Framework\View\Layout\Generator\Structure;
 use Magento\Framework\View\Element\UiComponentInterface;
 use Magento\Framework\View\TemplateEngine\Xhtml\Template;
 use Magento\Framework\View\TemplateEngine\Xhtml\ResultInterface;
diff --git a/app/code/Magento/Ui/Test/Unit/Component/Filters/FilterModifierTest.php b/app/code/Magento/Ui/Test/Unit/Component/Filters/FilterModifierTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..a7f954bac61396b1fe69198cab98816234f29d0f
--- /dev/null
+++ b/app/code/Magento/Ui/Test/Unit/Component/Filters/FilterModifierTest.php
@@ -0,0 +1,139 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Ui\Test\Unit\Component\Filters;
+
+use Magento\Framework\View\Element\UiComponent\DataProvider\DataProviderInterface;
+
+/**
+ * Class DateRangeTest
+ */
+class FilterModifierTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\Framework\App\RequestInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $request;
+
+    /**
+     * @var DataProviderInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $dataProvider;
+
+    /**
+     * @var \Magento\Framework\Api\FilterBuilder|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $filterBuilder;
+
+    /**
+     * @var \Magento\Ui\Component\Filters\FilterModifier
+     */
+    protected $unit;
+
+    /**
+     * Set up
+     */
+    public function setUp()
+    {
+        $this->request = $this->getMockForAbstractClass('Magento\Framework\App\RequestInterface');
+        $this->dataProvider = $this->getMockForAbstractClass(
+            'Magento\Framework\View\Element\UiComponent\DataProvider\DataProviderInterface'
+        );
+        $this->filterBuilder = $this->getMock(
+            'Magento\Framework\Api\FilterBuilder',
+            [],
+            [],
+            '',
+            false
+        );
+        $this->unit = (new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this))
+            ->getObject(
+                'Magento\Ui\Component\Filters\FilterModifier',
+                [
+                    'request' => $this->request,
+                    'filterBuilder' => $this->filterBuilder,
+                ]
+            );
+    }
+
+    /**
+     * @return void
+     */
+    public function testNotApplyFilterModifier()
+    {
+        $this->request->expects($this->once())->method('getParam')
+            ->with(\Magento\Ui\Component\Filters\FilterModifier::FILTER_MODIFIER)
+            ->willReturn([]);
+        $this->dataProvider->expects($this->never())->method('addFilter');
+        $this->unit->applyFilterModifier($this->dataProvider, 'test');
+    }
+
+    /**
+     * @return void
+     * @assertException \Magento\Framework\Exception\LocalizedException
+     */
+    public function testApplyFilterModifierWithNotAllowedCondition()
+    {
+        $this->request->expects($this->once())->method('getParam')
+            ->with(\Magento\Ui\Component\Filters\FilterModifier::FILTER_MODIFIER)
+            ->willReturn([
+                'filter' => [
+                    'condition_type' => 'not_allowed'
+                ]
+            ]);
+        $this->dataProvider->expects($this->never())->method('addFilter');
+        $this->unit->applyFilterModifier($this->dataProvider, 'test');
+    }
+
+    /**
+     * @param $filterModifier
+     * @param $filterName
+     * @param $conditionType
+     * @param $value
+     * @return void
+     * @dataProvider getApplyFilterModifierDataProvider
+     */
+    public function testApplyFilterModifierWith($filterModifier, $filterName, $conditionType, $value)
+    {
+        $filter = $this->getMock('Magento\Framework\Api\Filter');
+
+        $this->request->expects($this->once())->method('getParam')
+            ->with(\Magento\Ui\Component\Filters\FilterModifier::FILTER_MODIFIER)
+            ->willReturn($filterModifier);
+        $this->filterBuilder->expects($this->once())->method('setConditionType')->with($conditionType)
+            ->willReturnSelf();
+        $this->filterBuilder->expects($this->once())->method('setField')->with($filterName)->willReturnSelf();
+        $this->filterBuilder->expects($this->once())->method('setValue')->with($value)->willReturnSelf();
+        $this->filterBuilder->expects($this->once())->method('create')->with()->willReturn($filter);
+        $this->dataProvider->expects($this->once())->method('addFilter')->with($filter);
+
+        $this->unit->applyFilterModifier($this->dataProvider, $filterName);
+    }
+
+    /**
+     * @return array
+     */
+    public function getApplyFilterModifierDataProvider()
+    {
+        return [
+            [
+                [
+                    'filter1' => ['condition_type' => 'eq', 'value' => '5',]
+                ],
+                'filter1',
+                'eq',
+                '5'
+            ],
+            [
+                [
+                    'filter2' => ['condition_type' => 'notnull']
+                ],
+                'filter2',
+                'notnull',
+                null
+            ],
+        ];
+    }
+}
diff --git a/app/code/Magento/Ui/Test/Unit/Component/Filters/Type/DateRangeTest.php b/app/code/Magento/Ui/Test/Unit/Component/Filters/Type/DateRangeTest.php
index 36bc19158e9701bbeacaf0d642d569a29658d630..6a2a0b545678dc66181b408795e15be8bebbba4d 100644
--- a/app/code/Magento/Ui/Test/Unit/Component/Filters/Type/DateRangeTest.php
+++ b/app/code/Magento/Ui/Test/Unit/Component/Filters/Type/DateRangeTest.php
@@ -32,6 +32,11 @@ class DateRangeTest extends \PHPUnit_Framework_TestCase
      */
     protected $filterBuilderMock;
 
+    /**
+     * @var \Magento\Ui\Component\Filters\FilterModifier|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $filterModifierMock;
+
     /**
      * Set up
      */
@@ -57,6 +62,13 @@ class DateRangeTest extends \PHPUnit_Framework_TestCase
             '',
             false
         );
+        $this->filterModifierMock = $this->getMock(
+            'Magento\Ui\Component\Filters\FilterModifier',
+            ['applyFilterModifier'],
+            [],
+            '',
+            false
+        );
     }
 
     /**
@@ -70,6 +82,7 @@ class DateRangeTest extends \PHPUnit_Framework_TestCase
             $this->contextMock,
             $this->uiComponentFactory,
             $this->filterBuilderMock,
+            $this->filterModifierMock,
             []
         );
         $this->assertTrue($dateRange->getComponentName() === DateRange::NAME);
@@ -109,22 +122,22 @@ class DateRangeTest extends \PHPUnit_Framework_TestCase
             ->method('getRequestParam')
             ->with(UiContext::FILTER_VAR)
             ->willReturn($filterData);
+        $dataProvider = $this->getMockForAbstractClass(
+            'Magento\Framework\View\Element\UiComponent\DataProvider\DataProviderInterface',
+            [],
+            '',
+            false
+        );
+        $this->contextMock->expects($this->any())
+            ->method('getDataProvider')
+            ->willReturn($dataProvider);
 
         if ($expectedCondition !== null) {
             /** @var DataProviderInterface $dataProvider */
-            $dataProvider = $this->getMockForAbstractClass(
-                'Magento\Framework\View\Element\UiComponent\DataProvider\DataProviderInterface',
-                [],
-                '',
-                false
-            );
             $dataProvider->expects($this->any())
                 ->method('addFilter')
                 ->with($expectedCondition, $name);
 
-            $this->contextMock->expects($this->any())
-                ->method('getDataProvider')
-                ->willReturn($dataProvider);
 
             $uiComponent->expects($this->any())
                 ->method('getLocale')
@@ -143,6 +156,7 @@ class DateRangeTest extends \PHPUnit_Framework_TestCase
             $this->contextMock,
             $this->uiComponentFactory,
             $this->filterBuilderMock,
+            $this->filterModifierMock,
             [],
             ['name' => $name]
         );
diff --git a/app/code/Magento/Ui/Test/Unit/Component/Filters/Type/DateTest.php b/app/code/Magento/Ui/Test/Unit/Component/Filters/Type/DateTest.php
index 3e76608a50743cf1e6a6f4e54f601e7b819c7d76..79af8056579f644d965f348b20302f9c8dd122b6 100644
--- a/app/code/Magento/Ui/Test/Unit/Component/Filters/Type/DateTest.php
+++ b/app/code/Magento/Ui/Test/Unit/Component/Filters/Type/DateTest.php
@@ -32,6 +32,11 @@ class DateTest extends \PHPUnit_Framework_TestCase
      */
     protected $filterBuilderMock;
 
+    /**
+     * @var \Magento\Ui\Component\Filters\FilterModifier|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $filterModifierMock;
+
     /**
      * Set up
      */
@@ -57,6 +62,15 @@ class DateTest extends \PHPUnit_Framework_TestCase
             '',
             false
         );
+
+        $this->filterModifierMock = $this->getMock(
+            'Magento\Ui\Component\Filters\FilterModifier',
+            ['applyFilterModifier'],
+            [],
+            '',
+            false
+        );
+
     }
 
     /**
@@ -70,6 +84,7 @@ class DateTest extends \PHPUnit_Framework_TestCase
             $this->contextMock,
             $this->uiComponentFactory,
             $this->filterBuilderMock,
+            $this->filterModifierMock,
             []
         );
 
@@ -110,23 +125,20 @@ class DateTest extends \PHPUnit_Framework_TestCase
             ->method('getRequestParam')
             ->with(UiContext::FILTER_VAR)
             ->willReturn($filterData);
-
+        $dataProvider = $this->getMockForAbstractClass(
+            'Magento\Framework\View\Element\UiComponent\DataProvider\DataProviderInterface',
+            [],
+            '',
+            false
+        );
+        $this->contextMock->expects($this->any())
+            ->method('getDataProvider')
+            ->willReturn($dataProvider);
         if ($expectedCondition !== null) {
-            /** @var DataProviderInterface $dataProvider */
-            $dataProvider = $this->getMockForAbstractClass(
-                'Magento\Framework\View\Element\UiComponent\DataProvider\DataProviderInterface',
-                [],
-                '',
-                false
-            );
             $dataProvider->expects($this->any())
                 ->method('addFilter')
                 ->with($expectedCondition, $name);
 
-            $this->contextMock->expects($this->any())
-                ->method('getDataProvider')
-                ->willReturn($dataProvider);
-
             $uiComponent->expects($this->any())
                 ->method('getLocale')
                 ->willReturn($expectedCondition['locale']);
@@ -144,6 +156,7 @@ class DateTest extends \PHPUnit_Framework_TestCase
             $this->contextMock,
             $this->uiComponentFactory,
             $this->filterBuilderMock,
+            $this->filterModifierMock,
             [],
             ['name' => $name]
         );
diff --git a/app/code/Magento/Ui/Test/Unit/Component/Filters/Type/InputTest.php b/app/code/Magento/Ui/Test/Unit/Component/Filters/Type/InputTest.php
index cf33a86653fd73caa96f8c58934f65582c7abd53..a3736ad6bd5028bbfc4e2201253a6aaa4043a59c 100644
--- a/app/code/Magento/Ui/Test/Unit/Component/Filters/Type/InputTest.php
+++ b/app/code/Magento/Ui/Test/Unit/Component/Filters/Type/InputTest.php
@@ -32,6 +32,11 @@ class InputTest extends \PHPUnit_Framework_TestCase
      */
     protected $filterBuilderMock;
 
+    /**
+     * @var \Magento\Ui\Component\Filters\FilterModifier|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $filterModifierMock;
+
     /**
      * Set up
      */
@@ -57,6 +62,13 @@ class InputTest extends \PHPUnit_Framework_TestCase
             '',
             false
         );
+        $this->filterModifierMock = $this->getMock(
+            'Magento\Ui\Component\Filters\FilterModifier',
+            ['applyFilterModifier'],
+            [],
+            '',
+            false
+        );
     }
 
     /**
@@ -70,6 +82,7 @@ class InputTest extends \PHPUnit_Framework_TestCase
             $this->contextMock,
             $this->uiComponentFactory,
             $this->filterBuilderMock,
+            $this->filterModifierMock,
             []
         );
 
@@ -109,22 +122,19 @@ class InputTest extends \PHPUnit_Framework_TestCase
             ->method('getRequestParam')
             ->with(UiContext::FILTER_VAR)
             ->willReturn($filterData);
-
+        $dataProvider = $this->getMockForAbstractClass(
+            'Magento\Framework\View\Element\UiComponent\DataProvider\DataProviderInterface',
+            [],
+            '',
+            false
+        );
+        $this->contextMock->expects($this->any())
+            ->method('getDataProvider')
+            ->willReturn($dataProvider);
         if ($expectedCondition !== null) {
-            /** @var DataProviderInterface $dataProvider */
-            $dataProvider = $this->getMockForAbstractClass(
-                'Magento\Framework\View\Element\UiComponent\DataProvider\DataProviderInterface',
-                [],
-                '',
-                false
-            );
             $dataProvider->expects($this->any())
                 ->method('addFilter')
                 ->with($expectedCondition, $name);
-
-            $this->contextMock->expects($this->any())
-                ->method('getDataProvider')
-                ->willReturn($dataProvider);
         }
 
         $this->uiComponentFactory->expects($this->any())
@@ -136,6 +146,7 @@ class InputTest extends \PHPUnit_Framework_TestCase
             $this->contextMock,
             $this->uiComponentFactory,
             $this->filterBuilderMock,
+            $this->filterModifierMock,
             [],
             ['name' => $name]
         );
diff --git a/app/code/Magento/Ui/Test/Unit/Component/Filters/Type/RangeTest.php b/app/code/Magento/Ui/Test/Unit/Component/Filters/Type/RangeTest.php
index b3da88e49eb4bddc5519d184bd67d4ced2446aa0..d28cb78ee21c9e8dd2535003786193975c1e9f45 100644
--- a/app/code/Magento/Ui/Test/Unit/Component/Filters/Type/RangeTest.php
+++ b/app/code/Magento/Ui/Test/Unit/Component/Filters/Type/RangeTest.php
@@ -31,6 +31,11 @@ class RangeTest extends \PHPUnit_Framework_TestCase
      */
     protected $filterBuilderMock;
 
+    /**
+     * @var \Magento\Ui\Component\Filters\FilterModifier|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $filterModifierMock;
+
     /**
      * Set up
      */
@@ -57,6 +62,13 @@ class RangeTest extends \PHPUnit_Framework_TestCase
             '',
             false
         );
+        $this->filterModifierMock = $this->getMock(
+            'Magento\Ui\Component\Filters\FilterModifier',
+            ['applyFilterModifier'],
+            [],
+            '',
+            false
+        );
     }
 
     /**
@@ -70,6 +82,7 @@ class RangeTest extends \PHPUnit_Framework_TestCase
             $this->contextMock,
             $this->uiComponentFactory,
             $this->filterBuilderMock,
+            $this->filterModifierMock,
             []
         );
 
@@ -97,28 +110,27 @@ class RangeTest extends \PHPUnit_Framework_TestCase
             ->method('getRequestParam')
             ->with(UiContext::FILTER_VAR)
             ->willReturn($filterData);
-
+        /** @var DataProviderInterface $dataProvider */
+        $dataProvider = $this->getMockForAbstractClass(
+            'Magento\Framework\View\Element\UiComponent\DataProvider\DataProviderInterface',
+            [],
+            '',
+            false
+        );
+        $this->contextMock->expects($this->any())
+            ->method('getDataProvider')
+            ->willReturn($dataProvider);
         if ($expectedCondition !== null) {
-            /** @var DataProviderInterface $dataProvider */
-            $dataProvider = $this->getMockForAbstractClass(
-                'Magento\Framework\View\Element\UiComponent\DataProvider\DataProviderInterface',
-                [],
-                '',
-                false
-            );
             $dataProvider->expects($this->any())
                 ->method('addFilter')
                 ->with($expectedCondition, $name);
-
-            $this->contextMock->expects($this->any())
-                ->method('getDataProvider')
-                ->willReturn($dataProvider);
         }
 
         $range = new Range(
             $this->contextMock,
             $this->uiComponentFactory,
             $this->filterBuilderMock,
+            $this->filterModifierMock,
             [],
             ['name' => $name]
         );
diff --git a/app/code/Magento/Ui/Test/Unit/Component/Filters/Type/SelectTest.php b/app/code/Magento/Ui/Test/Unit/Component/Filters/Type/SelectTest.php
index 24237520a321ba1552216d01f8c4cb0dd43f56a2..45b200fc58494f0964058447e5fe04cb97a5de94 100644
--- a/app/code/Magento/Ui/Test/Unit/Component/Filters/Type/SelectTest.php
+++ b/app/code/Magento/Ui/Test/Unit/Component/Filters/Type/SelectTest.php
@@ -32,6 +32,11 @@ class SelectTest extends \PHPUnit_Framework_TestCase
      */
     protected $filterBuilderMock;
 
+    /**
+     * @var \Magento\Ui\Component\Filters\FilterModifier|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $filterModifierMock;
+
     /**
      * Set up
      */
@@ -57,6 +62,13 @@ class SelectTest extends \PHPUnit_Framework_TestCase
             '',
             false
         );
+        $this->filterModifierMock = $this->getMock(
+            'Magento\Ui\Component\Filters\FilterModifier',
+            ['applyFilterModifier'],
+            [],
+            '',
+            false
+        );
     }
 
     /**
@@ -70,6 +82,7 @@ class SelectTest extends \PHPUnit_Framework_TestCase
             $this->contextMock,
             $this->uiComponentFactory,
             $this->filterBuilderMock,
+            $this->filterModifierMock,
             null,
             []
         );
@@ -110,22 +123,21 @@ class SelectTest extends \PHPUnit_Framework_TestCase
             ->method('getRequestParam')
             ->with(AbstractFilter::FILTER_VAR)
             ->willReturn($filterData);
+        /** @var DataProviderInterface $dataProvider */
+        $dataProvider = $this->getMockForAbstractClass(
+            'Magento\Framework\View\Element\UiComponent\DataProvider\DataProviderInterface',
+            [],
+            '',
+            false
+        );
+        $this->contextMock->expects($this->any())
+            ->method('getDataProvider')
+            ->willReturn($dataProvider);
 
         if ($expectedCondition !== null) {
-            /** @var DataProviderInterface $dataProvider */
-            $dataProvider = $this->getMockForAbstractClass(
-                'Magento\Framework\View\Element\UiComponent\DataProvider\DataProviderInterface',
-                [],
-                '',
-                false
-            );
             $dataProvider->expects($this->any())
                 ->method('addFilter')
                 ->with($expectedCondition, $name);
-
-            $this->contextMock->expects($this->any())
-                ->method('getDataProvider')
-                ->willReturn($dataProvider);
         }
 
         /** @var \Magento\Framework\Data\OptionSourceInterface $selectOptions */
@@ -145,6 +157,7 @@ class SelectTest extends \PHPUnit_Framework_TestCase
             $this->contextMock,
             $this->uiComponentFactory,
             $this->filterBuilderMock,
+            $this->filterModifierMock,
             $selectOptions,
             [],
             ['name' => $name]
diff --git a/app/code/Magento/Ui/etc/di.xml b/app/code/Magento/Ui/etc/di.xml
index a29e842f3eaab3f48a9eca422b6f474d416e7ea4..a96eecf8ad05e1481ee9a7e1313809f7a2ffa3a4 100644
--- a/app/code/Magento/Ui/etc/di.xml
+++ b/app/code/Magento/Ui/etc/di.xml
@@ -12,7 +12,7 @@
     <preference for="Magento\Framework\Config\ConverterInterface" type="Magento\Framework\View\Element\UiComponent\Config\Converter" />
     <preference for="Magento\Framework\View\Element\UiComponent\Config\ManagerInterface" type="Magento\Ui\Model\Manager" />
     <preference for="Magento\Framework\View\Element\UiComponent\ContextInterface" type="Magento\Framework\View\Element\UiComponent\Context" />
-    <preference for="Magento\Framework\View\Element\UiComponent\LayoutInterface" type="Magento\Ui\Component\Layout\Generic"/>
+    <preference for="Magento\Framework\View\Element\UiComponent\LayoutInterface" type="Magento\Framework\View\Layout\Generic"/>
     <preference for="Magento\Authorization\Model\UserContextInterface" type="Magento\User\Model\Authorization\AdminSessionUserContext"/>
     <preference for="Magento\Ui\Api\Data\BookmarkSearchResultsInterface" type="Magento\Framework\Api\SearchResults" />
     <preference for="Magento\Ui\Api\BookmarkRepositoryInterface" type="Magento\Ui\Model\Resource\BookmarkRepository"/>
@@ -153,11 +153,11 @@
             </argument>
         </arguments>
     </type>
-    <type name="Magento\Ui\Component\Layout\LayoutPool">
+    <type name="Magento\Framework\View\Layout\Pool">
         <arguments>
             <argument name="types" xsi:type="array">
                 <item name="generic" xsi:type="array">
-                    <item name="class" xsi:type="string">Magento\Ui\Component\Layout\Generic</item>
+                    <item name="class" xsi:type="string">Magento\Framework\View\Layout\Generic</item>
                     <item name="template" xsi:type="string">templates/layout/generic</item>
                 </item>
                 <item name="tabs" xsi:type="array">
diff --git a/app/code/Magento/Ui/view/base/web/js/grid/columns/multiselect.js b/app/code/Magento/Ui/view/base/web/js/grid/columns/multiselect.js
index b8b13990c752354162f7d813b2745ef194e378b2..b48f1c9ed8a35adc457b2f03b0190a2cb4d7c3d2 100644
--- a/app/code/Magento/Ui/view/base/web/js/grid/columns/multiselect.js
+++ b/app/code/Magento/Ui/view/base/web/js/grid/columns/multiselect.js
@@ -19,6 +19,7 @@ define([
             allSelected: false,
             indetermine: false,
             selected: [],
+            disabled: [],
             excluded: [],
             actions: [{
                 value: 'selectAll',
@@ -58,6 +59,7 @@ define([
         initObservable: function () {
             this._super()
                 .observe([
+                    'disabled',
                     'selected',
                     'excluded',
                     'excludeMode',
@@ -193,7 +195,10 @@ define([
          * @returns {Multiselect} Chainable.
          */
         selectPage: function () {
-            var selected = _.union(this.selected(), this.getIds());
+            var selected = _.difference(
+                _.union(this.selected(), this.getIds()),
+                this.disabled()
+            );
 
             this.selected(selected);
 
diff --git a/app/code/Magento/Ui/view/base/web/js/lib/step-wizard.js b/app/code/Magento/Ui/view/base/web/js/lib/step-wizard.js
index 020f1353c17564c29ea00b95509dd08c7abefd6d..af68997cdf95d217ccdb35590db951f0a5314233 100644
--- a/app/code/Magento/Ui/view/base/web/js/lib/step-wizard.js
+++ b/app/code/Magento/Ui/view/base/web/js/lib/step-wizard.js
@@ -2,24 +2,29 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
+// jscs:disable jsDoc
 define([
-    "uiRegistry",
-    "uiComponent",
-    "jquery",
-    "underscore",
-    "ko",
-    "mage/backend/notification"
+    'uiRegistry',
+    'uiComponent',
+    'jquery',
+    'underscore',
+    'ko',
+    'mage/backend/notification'
 ], function (uiRegistry, Component, $, _, ko) {
-    "use strict";
+    'use strict';
 
-    ko.utils.domNodeDisposal.cleanExternalData = _.wrap(ko.utils.domNodeDisposal.cleanExternalData,
-        function(func, node) {
+    var Wizard;
+
+    ko.utils.domNodeDisposal.cleanExternalData = _.wrap(
+        ko.utils.domNodeDisposal.cleanExternalData,
+        function (func, node) {
             if (!$(node).closest('[data-type=skipKO]').length) {
                 func(node);
             }
-    });
+        }
+    );
 
-    var Wizard = function (steps) {
+    Wizard = function (steps) {
         this.steps = steps;
         this.index = 0;
         this.data = {};
@@ -44,19 +49,23 @@ define([
         };
         this.next = function () {
             this.move(this.index + 1);
+
             return this.getStep().name;
         };
         this.prev = function () {
             this.move(this.index - 1);
+
             return this.getStep().name;
         };
-        this.preventSwitch = function(newIndex) {
+        this.preventSwitch = function (newIndex) {
             return newIndex < 0 || (newIndex - this.index) > 1;
         };
         this._next = function (newIndex) {
             newIndex = _.isNumber(newIndex) ? newIndex : this.index + 1;
+
             try {
                 this.getStep().force(this);
+
                 if (newIndex >= steps.length) {
                     return false;
                 }
@@ -91,6 +100,7 @@ define([
         this.showNotificationMessage = function () {
             if (!_.isEmpty(this.getStep())) {
                 this.hideNotificationMessage();
+
                 if (this.getStep().notificationMessage.text !== null) {
                     this.notifyMessage(
                         this.getStep().notificationMessage.text,
@@ -109,7 +119,8 @@ define([
             }
         };
         this.setNotificationMessage = function (text, error) {
-            error = typeof error !== 'undefined';
+            error = error !== undefined;
+
             if (!_.isEmpty(this.getStep())) {
                 this.getStep().notificationMessage.text = text;
                 this.getStep().notificationMessage.error = error;
@@ -189,7 +200,7 @@ define([
         showSpecificStep: function () {
             var index = _.indexOf(this.stepsNames, event.target.hash.substr(1)),
                 stepName = this.wizard.move(index);
-            
+
             this.selectedStep(stepName);
         }
     });
diff --git a/app/code/Magento/Ui/view/base/web/templates/grid/cells/multiselect.html b/app/code/Magento/Ui/view/base/web/templates/grid/cells/multiselect.html
index 4028c2210a5a16c7edb922cd0e4302984367774a..242c651f006d16896d55dcb52d0d8332bab9eb71 100644
--- a/app/code/Magento/Ui/view/base/web/templates/grid/cells/multiselect.html
+++ b/app/code/Magento/Ui/view/base/web/templates/grid/cells/multiselect.html
@@ -5,13 +5,14 @@
  */
 -->
 
-<td class="data-grid-checkbox-cell">
+<td class="data-grid-checkbox-cell" data-bind="visible: visible">
     <label class="data-grid-checkbox-cell-inner">
         <input
             class="admin__control-checkbox"
             type="checkbox"
             data-action="select-row"
             data-bind="
+                disable: disabled.indexOf(row[indexField]) != -1,
                 checked: selected,
                 value: row[indexField],
                 attr: {
diff --git a/app/code/Magento/Ui/view/base/web/templates/grid/columns/multiselect.html b/app/code/Magento/Ui/view/base/web/templates/grid/columns/multiselect.html
index bb9f13955c0a77cbea3fb1d0e9171180eec22e82..4606d8e27b9a19e5236f6b7f28d66076805b43d1 100644
--- a/app/code/Magento/Ui/view/base/web/templates/grid/columns/multiselect.html
+++ b/app/code/Magento/Ui/view/base/web/templates/grid/columns/multiselect.html
@@ -5,7 +5,7 @@
  */
 -->
 
-<th class="data-grid-multicheck-cell">
+<th class="data-grid-multicheck-cell" data-bind="visible: visible">
     <div
         class="action-multicheck-wrap"
         data-bind="css: {'_disabled': !totalRecords()},
diff --git a/app/code/Magento/User/Model/Resource/User.php b/app/code/Magento/User/Model/Resource/User.php
index 9f2bf7f3d36599da3d9a48a0e6cd7291f89ef5dd..dc2f9c55f35ec5bcec961f881d6ed42c1129424e 100644
--- a/app/code/Magento/User/Model/Resource/User.php
+++ b/app/code/Magento/User/Model/Resource/User.php
@@ -522,8 +522,8 @@ class User extends \Magento\Framework\Model\Resource\Db\AbstractDb
      * Increment failures count along with updating lock expire and first failure dates
      *
      * @param ModelUser $user
-     * @param int|false $setLockExpires
-     * @param int|false $setFirstFailure
+     * @param int|bool $setLockExpires
+     * @param int|bool $setFirstFailure
      * @return void
      */
     public function updateFailure($user, $setLockExpires = false, $setFirstFailure = false)
diff --git a/app/code/Magento/User/Test/Unit/Model/Resource/UserTest.php b/app/code/Magento/User/Test/Unit/Model/Resource/UserTest.php
new file mode 100755
index 0000000000000000000000000000000000000000..961cc40d5f3304599b2610c780d2d2774424af3b
--- /dev/null
+++ b/app/code/Magento/User/Test/Unit/Model/Resource/UserTest.php
@@ -0,0 +1,442 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\User\Test\Unit\Model\Resource;
+
+/**
+ * Test class for \Magento\User\Model\Resource\User testing
+ */
+class UserTest extends \PHPUnit_Framework_TestCase
+{
+    /** @var \Magento\User\Model\Resource\User */
+    protected $model;
+
+    /** @var \Magento\User\Model\User|\PHPUnit_framework_MockObject_MockObject */
+    protected $userMock;
+
+    /** @var \Magento\Framework\Acl\CacheInterface|\PHPUnit_Framework_MockObject_MockObject */
+    protected $aclCacheMock;
+
+    /** @var \Magento\Framework\Model\Resource\Db\Context|\PHPUnit_Framework_MockObject_MockObject */
+    protected $contextMock;
+
+    /** @var \Magento\Authorization\Model\RoleFactory|\PHPUnit_Framework_MockObject_MockObject */
+    protected $roleFactoryMock;
+
+    /** @var \Magento\Framework\Stdlib\DateTime|\PHPUnit_Framework_MockObject_MockObject */
+    protected $dateTimeMock;
+
+    /** @var \Magento\Framework\App\Resource|\PHPUnit_Framework_MockObject_MockObject */
+    protected $resourceMock;
+
+    /** @var \Magento\Framework\DB\Adapter\AdapterInterface|\PHPUnit_Framework_MockObject_MockObject */
+    protected $dbAdapterMock;
+
+    /** @var \Magento\Framework\DB\Select|\PHPUnit_Framework_MockObject_MockObject */
+    protected $selectMock;
+
+    /** @var \Magento\Authorization\Model\Role|\PHPUnit_Framework_MockObject_MockObject */
+    protected $roleMock;
+
+    protected function setUp()
+    {
+        $this->userMock = $this->getMockBuilder('Magento\User\Model\User')
+            ->disableOriginalConstructor()
+            ->setMethods([])
+            ->getMock();
+
+        $this->resourceMock = $this->getMockBuilder('Magento\Framework\App\Resource')
+            ->disableOriginalConstructor()
+            ->setMethods([])
+            ->getMock();
+
+        $this->aclCacheMock = $this->getMockBuilder('Magento\Framework\Acl\CacheInterface')
+            ->disableOriginalConstructor()
+            ->setMethods([])
+            ->getMock();
+
+        $this->roleFactoryMock = $this->getMockBuilder('Magento\Authorization\Model\RoleFactory')
+            ->disableOriginalConstructor()
+            ->setMethods(['create'])
+            ->getMock();
+
+        $this->roleMock = $this->getMockBuilder('Magento\Authorization\Model\Role')
+            ->disableOriginalConstructor()
+            ->setMethods([])
+            ->getMock();
+
+
+        $this->dateTimeMock = $this->getMockBuilder('Magento\Framework\Stdlib\DateTime')
+            ->disableOriginalConstructor()
+            ->setMethods([])
+            ->getMock();
+
+        $this->selectMock = $this->getMockBuilder('Magento\Framework\DB\Select')
+            ->disableOriginalConstructor()
+            ->setMethods([])
+            ->getMock();
+
+        $this->dbAdapterMock = $this->getMockBuilder('Magento\Framework\DB\Adapter\AdapterInterface')
+            ->disableOriginalConstructor()
+            ->setMethods([])
+            ->getMock();
+
+        $helper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
+        $this->model = $helper->getObject(
+            'Magento\User\Model\Resource\User',
+            [
+                'resource' => $this->resourceMock,
+                'aclCache' => $this->aclCacheMock,
+                'roleFactory' => $this->roleFactoryMock,
+                'dateTime' => $this->dateTimeMock
+            ]
+        );
+    }
+
+    public function testIsUserUnique()
+    {
+        $this->resourceMock->expects($this->once())->method('getConnection')->willReturn($this->dbAdapterMock);
+        $this->dbAdapterMock->expects($this->once())->method('select')->willReturn($this->selectMock);
+        $this->selectMock->expects($this->once())->method('from')->willReturn($this->selectMock);
+        $this->selectMock->expects($this->atLeastOnce())->method('where')->willReturn($this->selectMock);
+        $this->dbAdapterMock->expects($this->once())->method('fetchRow')->willReturn([true]);
+
+        $this->assertFalse($this->model->isUserUnique($this->userMock));
+    }
+
+    public function testRecordLogin()
+    {
+        $this->resourceMock->expects($this->once())->method('getConnection')->willReturn($this->dbAdapterMock);
+        $this->dbAdapterMock->expects($this->once())->method('update');
+
+        $this->assertInstanceOf('Magento\User\Model\Resource\User', $this->model->recordLogin($this->userMock));
+    }
+
+    public function testLoadByUsername()
+    {
+        $returnData = [1, 2, 3];
+        $this->resourceMock->expects($this->once())->method('getConnection')->willReturn($this->dbAdapterMock);
+        $this->dbAdapterMock->expects($this->once())->method('select')->willReturn($this->selectMock);
+        $this->selectMock->expects($this->once())->method('from')->willReturn($this->selectMock);
+        $this->selectMock->expects($this->atLeastOnce())->method('where')->willReturn($this->selectMock);
+        $this->dbAdapterMock->expects($this->once())->method('fetchRow')->willReturn($returnData);
+
+        $this->assertEquals($returnData, $this->model->loadByUsername('user1'));
+    }
+
+
+    public function testHasAssigned2Role()
+    {
+        $returnData = [1, 2, 3];
+        $uid = 1234;
+        $this->resourceMock->expects($this->once())->method('getConnection')->willReturn($this->dbAdapterMock);
+        $this->selectMock->expects($this->once())->method('from')->willReturn($this->selectMock);
+        $this->dbAdapterMock->expects($this->once())->method('select')->willReturn($this->selectMock);
+        $this->selectMock->expects($this->atLeastOnce())->method('where')->willReturn($this->selectMock);
+        $this->dbAdapterMock->expects($this->once())->method('fetchAll')->willReturn($returnData);
+
+        $this->assertEquals($returnData, $this->model->hasAssigned2Role($uid));
+        $this->assertNull($this->model->hasAssigned2Role(0));
+    }
+
+    public function testHasAssigned2RolePassAnObject()
+    {
+        $methodUserMock = $this->getMockBuilder('\Magento\Framework\Model\AbstractModel')
+            ->disableOriginalConstructor()
+            ->setMethods(['getUserId'])
+            ->getMock();
+        $returnData = [1, 2, 3];
+        $uid = 1234;
+        $methodUserMock->expects($this->once())->method('getUserId')->willReturn($uid);
+        $this->resourceMock->expects($this->once())->method('getConnection')->willReturn($this->dbAdapterMock);
+        $this->dbAdapterMock->expects($this->once())->method('select')->willReturn($this->selectMock);
+        $this->selectMock->expects($this->once())->method('from')->willReturn($this->selectMock);
+        $this->selectMock->expects($this->atLeastOnce())->method('where')->willReturn($this->selectMock);
+        $this->dbAdapterMock->expects($this->once())->method('fetchAll')->willReturn($returnData);
+
+        $this->assertEquals($returnData, $this->model->hasAssigned2Role($methodUserMock));
+    }
+
+    public function testClearUserRoles()
+    {
+        $uid = 123;
+        $this->userMock->expects($this->once())->method('getId')->willReturn($uid);
+        $this->resourceMock->expects($this->once())->method('getConnection')->willReturn($this->dbAdapterMock);
+        $this->dbAdapterMock->expects($this->once())->method('delete');
+        $this->model->_clearUserRoles($this->userMock);
+    }
+
+    public function testDeleteSucess()
+    {
+        $uid = 123;
+        $this->resourceMock->expects($this->once())->method('getConnection')->willReturn($this->dbAdapterMock);
+        $this->dbAdapterMock->expects($this->once())->method('beginTransaction');
+        $this->userMock->expects($this->once())->method('getId')->willReturn($uid);
+        $this->dbAdapterMock->expects($this->atLeastOnce())->method('delete');
+
+        $this->assertTrue($this->model->delete($this->userMock));
+    }
+
+    public function testGetRolesEmptyId()
+    {
+        $this->assertEquals([], $this->model->getRoles($this->userMock));
+    }
+
+    public function testGetRolesReturnFilledArray()
+    {
+        $uid = 123;
+        $this->userMock->expects($this->atLeastOnce())->method('getId')->willReturn($uid);
+        $this->resourceMock->expects($this->once())->method('getConnection')->willReturn($this->dbAdapterMock);
+        $this->dbAdapterMock->expects($this->once())->method('select')->willReturn($this->selectMock);
+        $this->selectMock->expects($this->once())->method('from')->willReturn($this->selectMock);
+        $this->selectMock->expects($this->once())->method('joinLeft')->willReturn($this->selectMock);
+        $this->selectMock->expects($this->once())->method('where')->willReturn($this->selectMock);
+        $this->dbAdapterMock->expects($this->once())->method('fetchCol')->willReturn([1, 2, 3]);
+        $this->assertEquals([1, 2, 3], $this->model->getRoles($this->userMock));
+    }
+
+    public function testGetRolesFetchRowFailure()
+    {
+        $uid = 123;
+        $this->resourceMock->expects($this->once())->method('getConnection')->willReturn($this->dbAdapterMock);
+        $this->userMock->expects($this->atLeastOnce())->method('getId')->willReturn($uid);
+        $this->dbAdapterMock->expects($this->once())->method('select')->willReturn($this->selectMock);
+        $this->selectMock->expects($this->once())->method('from')->willReturn($this->selectMock);
+        $this->selectMock->expects($this->once())->method('joinLeft')->willReturn($this->selectMock);
+        $this->selectMock->expects($this->once())->method('where')->willReturn($this->selectMock);
+        $this->dbAdapterMock->expects($this->once())->method('fetchCol')->willReturn(false);
+        $this->assertEquals([], $this->model->getRoles($this->userMock));
+    }
+
+    public function testSaveExtraEmptyId()
+    {
+        $this->resourceMock->expects($this->never())->method('getConnection');
+        $this->assertInstanceOf(
+            'Magento\User\Model\Resource\User',
+            $this->model->saveExtra($this->userMock, [1, 2, 3])
+        );
+    }
+
+    public function testSaveExtraFilledId()
+    {
+        $uid = 123;
+        $this->userMock->expects($this->atLeastOnce())->method('getId')->willReturn($uid);
+        $this->resourceMock->expects($this->once())->method('getConnection')->willReturn($this->dbAdapterMock);
+        $this->dbAdapterMock->expects($this->once())->method('update');
+        $this->assertInstanceOf(
+            'Magento\User\Model\Resource\User',
+            $this->model->saveExtra($this->userMock, [1, 2, 3])
+        );
+    }
+
+    public function testCountAll()
+    {
+        $returnData = 123;
+        $this->resourceMock->expects($this->once())->method('getConnection')->willReturn($this->dbAdapterMock);
+        $this->dbAdapterMock->expects($this->once())->method('select')->willReturn($this->selectMock);
+        $this->dbAdapterMock->expects($this->once())->method('fetchOne')->willReturn($returnData);
+        $this->assertEquals($returnData, $this->model->countAll());
+    }
+
+    public function testUpdateRoleUsersAclWithUsers()
+    {
+        $this->resourceMock->expects($this->once())->method('getConnection')->willReturn($this->dbAdapterMock);
+        $this->roleMock->expects($this->once())->method('getRoleUsers')->willReturn(['user1', 'user2']);
+        $this->dbAdapterMock->expects($this->once())->method('update')->willReturn(1);
+        $this->assertTrue($this->model->updateRoleUsersAcl($this->roleMock));
+    }
+
+    public function testUpdateRoleUsersAclNoUsers()
+    {
+        $this->resourceMock->expects($this->once())->method('getConnection')->willReturn($this->dbAdapterMock);
+        $this->roleMock->expects($this->once())->method('getRoleUsers')->willReturn([]);
+        $this->dbAdapterMock->expects($this->never())->method('update');
+        $this->assertFalse($this->model->updateRoleUsersAcl($this->roleMock));
+    }
+
+    public function testUpdateRoleUsersAclUpdateFail()
+    {
+        $this->resourceMock->expects($this->once())->method('getConnection')->willReturn($this->dbAdapterMock);
+        $this->roleMock->expects($this->once())->method('getRoleUsers')->willReturn(['user1', 'user2']);
+        $this->dbAdapterMock->expects($this->once())->method('update')->willReturn(0);
+        $this->assertFalse($this->model->updateRoleUsersAcl($this->roleMock));
+    }
+
+    public function testUnlock()
+    {
+        $inputData = [1, 2, 3];
+        $returnData = 5;
+        $this->resourceMock->expects($this->atLeastOnce())->method('getConnection')->willReturn($this->dbAdapterMock);
+        $this->dbAdapterMock->expects($this->once())->method('update')->willReturn($returnData);
+        $this->assertEquals($returnData, $this->model->unlock($inputData));
+    }
+
+    public function testUnlockWithInteger()
+    {
+        $inputData = 123;
+        $returnData = 5;
+        $this->resourceMock->expects($this->atLeastOnce())->method('getConnection')->willReturn($this->dbAdapterMock);
+        $this->dbAdapterMock->expects($this->once())->method('update')->willReturn($returnData);
+        $this->assertEquals($returnData, $this->model->unlock($inputData));
+    }
+
+    public function testLock()
+    {
+        $inputData = [1, 2, 3];
+        $returnData = 5;
+        $this->resourceMock->expects($this->atLeastOnce())->method('getConnection')->willReturn($this->dbAdapterMock);
+        $this->dbAdapterMock->expects($this->once())->method('update')->willReturn($returnData);
+        $this->assertEquals($returnData, $this->model->lock($inputData, 1, 1));
+    }
+
+    public function testLockWithInteger()
+    {
+        $inputData = 123;
+        $returnData = 5;
+        $this->resourceMock->expects($this->atLeastOnce())->method('getConnection')->willReturn($this->dbAdapterMock);
+        $this->dbAdapterMock->expects($this->once())->method('update')->willReturn($returnData);
+        $this->assertEquals($returnData, $this->model->lock($inputData, 1, 1));
+    }
+
+    public function testGetOldPassword()
+    {
+        $returnData = ['password1', 'password2'];
+        $this->resourceMock->expects($this->atLeastOnce())->method('getConnection')->willReturn($this->dbAdapterMock);
+        $this->dbAdapterMock->expects($this->atLeastOnce())->method('select')->willReturn($this->selectMock);
+        $this->selectMock->expects($this->atLeastOnce())->method('from')->willReturn($this->selectMock);
+        $this->selectMock->expects($this->atLeastOnce())->method('order')->willReturn($this->selectMock);
+        $this->selectMock->expects($this->atLeastOnce())->method('where')->willReturn($this->selectMock);
+        $this->dbAdapterMock->expects($this->atLeastOnce())->method('fetchCol')->willReturn($returnData);
+        $this->assertEquals($returnData, $this->model->getOldPasswords($this->userMock));
+    }
+
+    public function testDeleteFromRole()
+    {
+        $methodUserMock = $this->getMockBuilder('\Magento\Framework\Model\AbstractModel')
+            ->disableOriginalConstructor()
+            ->setMethods(['getUserId', 'getRoleId'])
+            ->getMock();
+        $uid = 1234;
+        $roleId = 44;
+        $methodUserMock->expects($this->once())->method('getUserId')->willReturn($uid);
+        $this->resourceMock->expects($this->atLeastOnce())->method('getConnection')->willReturn($this->dbAdapterMock);
+        $methodUserMock->expects($this->atleastOnce())->method('getRoleId')->willReturn($roleId);
+        $this->dbAdapterMock->expects($this->once())->method('delete');
+
+        $this->assertInstanceOf('\Magento\User\Model\Resource\User', $this->model->deleteFromRole($methodUserMock));
+    }
+
+    public function testRoleUserExists()
+    {
+        $methodUserMock = $this->getMockBuilder('\Magento\Framework\Model\AbstractModel')
+            ->disableOriginalConstructor()
+            ->setMethods(['getUserId', 'getRoleId'])
+            ->getMock();
+        $uid = 1234;
+        $roleId = 44;
+        $returnData = [1, 2, 3];
+        $methodUserMock->expects($this->atLeastOnce())->method('getUserId')->willReturn($uid);
+        $this->resourceMock->expects($this->atLeastOnce())->method('getConnection')->willReturn($this->dbAdapterMock);
+        $methodUserMock->expects($this->once())->method('getRoleId')->willReturn($roleId);
+        $this->dbAdapterMock->expects($this->once())->method('select')->willReturn($this->selectMock);
+        $this->selectMock->expects($this->atLeastOnce())->method('from')->willReturn($this->selectMock);
+        $this->selectMock->expects($this->atLeastOnce())->method('where')->willReturn($this->selectMock);
+        $this->dbAdapterMock->expects($this->once())->method('fetchCol')->willReturn($returnData);
+
+        $this->assertEquals($returnData, $this->model->roleUserExists($methodUserMock));
+        $this->assertEquals([], $this->model->roleUserExists($this->userMock));
+    }
+
+    public function testGetValidationBeforeSave()
+    {
+        $this->assertInstanceOf('\Zend_Validate_Callback', $this->model->getValidationRulesBeforeSave());
+    }
+
+    public function testUpdateFailure()
+    {
+        $this->resourceMock->expects($this->atLeastOnce())->method('getConnection')->willReturn($this->dbAdapterMock);
+        $this->dbAdapterMock->expects($this->once())->method('update')->willReturn($this->selectMock);
+        $this->dbAdapterMock->expects($this->once())->method('quoteInto')->willReturn($this->selectMock);
+        $this->model->updateFailure($this->userMock, 1, 1);
+    }
+
+    public function testTrackPassword()
+    {
+        $this->resourceMock->expects($this->atLeastOnce())->method('getConnection')->willReturn($this->dbAdapterMock);
+        $this->dbAdapterMock->expects($this->once())->method('insert')->willReturn($this->selectMock);
+        $this->model->trackPassword($this->userMock, "myPas#w0rd", 1);
+    }
+
+    public function testGetLatestPassword()
+    {
+        $uid = 123;
+        $returnData = ['password1', 'password2'];
+        $this->resourceMock->expects($this->atLeastOnce())->method('getConnection')->willReturn($this->dbAdapterMock);
+        $this->dbAdapterMock->expects($this->once())->method('fetchRow')->willReturn($returnData);
+        $this->dbAdapterMock->expects($this->once())->method('select')->willReturn($this->selectMock);
+        $this->selectMock->expects($this->atLeastOnce())->method('from')->willReturn($this->selectMock);
+        $this->selectMock->expects($this->atLeastOnce())->method('where')->willReturn($this->selectMock);
+        $this->selectMock->expects($this->atLeastOnce())->method('order')->willReturn($this->selectMock);
+        $this->selectMock->expects($this->atLeastOnce())->method('limit')->willReturn($this->selectMock);
+        $this->assertEquals($returnData, $this->model->getLatestPassword($uid));
+    }
+
+    public function testInitUniqueFields()
+    {
+        $this->assertInstanceOf(
+            '\Magento\User\Model\Resource\User',
+            $this->invokeMethod($this->model, '_initUniqueFields', [])
+        );
+    }
+
+    public function testBeforeSave()
+    {
+        $this->userMock->expects($this->once())->method('isObjectNew')->willReturn(true);
+
+        $this->assertInstanceOf(
+            '\Magento\User\Model\Resource\User',
+            $this->invokeMethod($this->model, '_beforeSave', [$this->userMock])
+        );
+    }
+
+    public function testAfterSave()
+    {
+        $roleId = 123;
+        $methodUserMock = $this->getMockBuilder('\Magento\User\Model\User')
+            ->disableOriginalConstructor()
+            ->setMethods(['hasRoleId', 'getRoleId'])
+            ->getMock();
+        $methodUserMock->expects($this->once())->method('hasRoleId')->willReturn(true);
+        $methodUserMock->expects($this->once())->method('getRoleId')->willReturn($roleId);
+        $this->resourceMock->expects($this->atLeastOnce())->method('getConnection')->willReturn($this->dbAdapterMock);
+        $this->roleFactoryMock->expects($this->once())->method('create')->willReturn($this->roleMock);
+        $this->roleMock->expects($this->once())->method('load')->willReturn($this->roleMock);
+        $this->roleMock->expects($this->atLeastOnce())->method('getId')->willReturn($roleId);
+        $this->dbAdapterMock->expects($this->once())->method('describeTable')->willReturn([1, 2, 3]);
+
+        $this->assertInstanceOf(
+            '\Magento\User\Model\Resource\User',
+            $this->invokeMethod($this->model, '_afterSave', [$methodUserMock])
+        );
+    }
+
+    /**
+     * Call protected/private method of a class.
+     *
+     * @param $object
+     * @param $methodName
+     * @param array $parameters
+     * @return mixed
+     */
+    public function invokeMethod(&$object, $methodName, array $parameters = [])
+    {
+        $reflection = new \ReflectionClass(get_class($object));
+        $method = $reflection->getMethod($methodName);
+        $method->setAccessible(true);
+
+        return $method->invokeArgs($object, $parameters);
+    }
+}
diff --git a/app/code/Magento/Webapi/etc/di.xml b/app/code/Magento/Webapi/etc/di.xml
index 28d00c467ea83ed0f8973860c67544efaef81294..593ef6427082d1d149c84a4d761567e28a7594e4 100644
--- a/app/code/Magento/Webapi/etc/di.xml
+++ b/app/code/Magento/Webapi/etc/di.xml
@@ -21,18 +21,6 @@
     <type name="Magento\Framework\Xml\Generator" shared="false" />
     <type name="Magento\Framework\Xml\Parser" shared="false" />
     <type name="Magento\Framework\Code\Scanner\DirectoryScanner" shared="false" />
-    <type name="Magento\Server\Reflection" shared="false" />
-    <type name="Magento\Framework\Reflection\MethodsMap">
-        <arguments>
-            <argument name="cache" xsi:type="object">Magento\Framework\App\Cache\Type\Webapi</argument>
-        </arguments>
-    </type>
-    <type name="Magento\Framework\Reflection\DataObjectProcessor">
-        <arguments>
-            <argument name="extensionAttributesProcessor" xsi:type="object">Magento\Framework\Reflection\ExtensionAttributesProcessor\Proxy</argument>
-            <argument name="customAttributesProcessor" xsi:type="object">Magento\Framework\Reflection\CustomAttributesProcessor\Proxy</argument>
-        </arguments>
-    </type>
     <type name="Magento\Integration\Model\ConfigBasedIntegrationManager">
         <plugin name="webapiSetup" type="Magento\Webapi\Model\Plugin\Manager" />
     </type>
diff --git a/app/code/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Chooser/Container.php b/app/code/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Chooser/Container.php
index 1b1d5a6cf68f9e53cd87bfa66b7f164ccbf32102..2a56d336ef8ab1fd7614e15d54eef3c796f0438f 100644
--- a/app/code/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Chooser/Container.php
+++ b/app/code/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Chooser/Container.php
@@ -15,6 +15,15 @@ namespace Magento\Widget\Block\Adminhtml\Widget\Instance\Edit\Chooser;
  */
 class Container extends \Magento\Framework\View\Element\Html\Select
 {
+    /**#@+
+     * Frontend page layouts
+     */
+    const PAGE_LAYOUT_1COLUMN = '1column-center';
+    const PAGE_LAYOUT_2COLUMNS_LEFT = '2columns-left';
+    const PAGE_LAYOUT_2COLUMNS_RIGHT = '2columns-right';
+    const PAGE_LAYOUT_3COLUMNS = '3columns';
+    /**#@-*/
+
     /**
      * @var \Magento\Framework\View\Layout\ProcessorFactory
      */
@@ -73,7 +82,10 @@ class Container extends \Magento\Framework\View\Element\Html\Select
             $layoutProcessor->load();
 
             $pageLayoutProcessor = $this->_layoutProcessorFactory->create($layoutMergeParams);
-            $pageLayoutProcessor->addHandle($layoutProcessor->getPageLayout());
+            $pageLayouts = $this->getPageLayouts();
+            foreach ($pageLayouts as $pageLayout) {
+                $pageLayoutProcessor->addHandle($pageLayout);
+            }
             $pageLayoutProcessor->load();
 
             $containers = array_merge($pageLayoutProcessor->getContainers(), $layoutProcessor->getContainers());
@@ -106,4 +118,19 @@ class Container extends \Magento\Framework\View\Element\Html\Select
         $themeCollection = $this->_themesFactory->create();
         return $themeCollection->getItemById($themeId);
     }
+
+    /**
+     * Retrieve page layouts
+     *
+     * @return array
+     */
+    protected function getPageLayouts()
+    {
+        return [
+            self::PAGE_LAYOUT_1COLUMN,
+            self::PAGE_LAYOUT_2COLUMNS_LEFT,
+            self::PAGE_LAYOUT_2COLUMNS_RIGHT,
+            self::PAGE_LAYOUT_3COLUMNS,
+        ];
+    }
 }
diff --git a/app/code/Magento/Widget/Test/Unit/Block/Adminhtml/Widget/Instance/Edit/Chooser/AbstractContainerTest.php b/app/code/Magento/Widget/Test/Unit/Block/Adminhtml/Widget/Instance/Edit/Chooser/AbstractContainerTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..1553a9654b41a57e8da202335de598f9df99bd7c
--- /dev/null
+++ b/app/code/Magento/Widget/Test/Unit/Block/Adminhtml/Widget/Instance/Edit/Chooser/AbstractContainerTest.php
@@ -0,0 +1,114 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Widget\Test\Unit\Block\Adminhtml\Widget\Instance\Edit\Chooser;
+
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper;
+
+abstract class AbstractContainerTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\Framework\Event\Manager|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $eventManagerMock;
+
+    /**
+     * @var \Magento\Framework\App\Config\ScopeConfigInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $scopeConfigMock;
+
+    /**
+     * @var \Magento\Backend\Block\Context|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $contextMock;
+
+    /**
+     * @var \Magento\Theme\Model\Resource\Theme\Collection|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $themeCollectionMock;
+
+    /**
+     * @var \Magento\Theme\Model\Resource\Theme\CollectionFactory|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $themeCollectionFactoryMock;
+
+    /**
+     * @var \Magento\Theme\Model\Theme|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $themeMock;
+
+    /**
+     * @var \Magento\Framework\View\Layout\ProcessorFactory|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $layoutProcessorFactoryMock;
+
+    /**
+     * @var \Magento\Framework\View\Model\Layout\Merge|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $layoutMergeMock;
+
+    /**
+     * @var \Magento\Framework\Escaper|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $escaperMock;
+
+    /**
+     * @var ObjectManagerHelper
+     */
+    protected $objectManagerHelper;
+
+    /**
+     * @return void
+     */
+    protected function setUp()
+    {
+        $this->objectManagerHelper = new ObjectManagerHelper($this);
+
+        $this->eventManagerMock = $this->getMockBuilder('Magento\Framework\Event\Manager')
+            ->setMethods(['dispatch'])
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->scopeConfigMock = $this->getMockBuilder('Magento\Framework\App\Config')
+            ->setMethods(['getValue'])
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->themeCollectionFactoryMock = $this->getMock(
+            'Magento\Theme\Model\Resource\Theme\CollectionFactory',
+            ['create'],
+            [],
+            '',
+            false
+        );
+        $this->themeCollectionMock = $this->getMockBuilder('Magento\Theme\Model\Resource\Theme\Collection')
+            ->disableOriginalConstructor()
+            ->setMethods(['getItemById'])
+            ->getMock();
+        $this->themeMock = $this->getMockBuilder('Magento\Theme\Model\Theme')->disableOriginalConstructor()->getMock();
+
+        $this->layoutProcessorFactoryMock = $this->getMock(
+            'Magento\Framework\View\Layout\ProcessorFactory',
+            ['create'],
+            [],
+            '',
+            false
+        );
+
+        $this->layoutMergeMock = $this->getMockBuilder('Magento\Framework\View\Model\Layout\Merge')
+            ->setMethods(['addPageHandles', 'load', 'getContainers'])
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->escaperMock = $this->getMock('Magento\Framework\Escaper', ['escapeHtml'], [], '', false);
+
+        $this->contextMock = $this->getMockBuilder('Magento\Backend\Block\Context')
+            ->setMethods(['getEventManager', 'getScopeConfig', 'getEscaper'])
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->contextMock->expects($this->once())->method('getEventManager')->willReturn($this->eventManagerMock);
+        $this->contextMock->expects($this->once())->method('getScopeConfig')->willReturn($this->scopeConfigMock);
+        $this->contextMock->expects($this->once())->method('getEscaper')->willReturn($this->escaperMock);
+    }
+}
diff --git a/app/code/Magento/Widget/Test/Unit/Block/Adminhtml/Widget/Instance/Edit/Chooser/ContainerTest.php b/app/code/Magento/Widget/Test/Unit/Block/Adminhtml/Widget/Instance/Edit/Chooser/ContainerTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..9316be68fa739718568cf0dcc874fc881c6da6fa
--- /dev/null
+++ b/app/code/Magento/Widget/Test/Unit/Block/Adminhtml/Widget/Instance/Edit/Chooser/ContainerTest.php
@@ -0,0 +1,440 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Widget\Test\Unit\Block\Adminhtml\Widget\Instance\Edit\Chooser;
+
+class ContainerTest extends AbstractContainerTest
+{
+    /**
+     * @var \Magento\Widget\Block\Adminhtml\Widget\Instance\Edit\Chooser\Container
+     */
+    protected $containerBlock;
+
+    /**
+     * @return void
+     */
+    protected function setUp()
+    {
+        parent::setUp();
+
+        $this->containerBlock = $this->objectManagerHelper->getObject(
+            'Magento\Widget\Block\Adminhtml\Widget\Instance\Edit\Chooser\Container',
+            [
+                'context' => $this->contextMock,
+                'themesFactory' => $this->themeCollectionFactoryMock,
+                'layoutProcessorFactory' => $this->layoutProcessorFactoryMock
+            ]
+        );
+    }
+
+    /**
+     * @return void
+     */
+    public function testToHtmlCatalogProductsListGroupedProduct()
+    {
+        $pageLayoutProcessorContainers = [
+            'after.body.start' => 'Page Top',
+            'columns.top' => 'Before Main Columns',
+            'main' => 'Main Content Container',
+            'page.bottom' => 'Before Page Footer Container',
+            'before.body.end' => 'Page Bottom',
+            'header.container' => 'Page Header Container',
+            'page.top' => 'After Page Header',
+            'footer-container' => 'Page Footer Container',
+            'sidebar.main' => 'Sidebar Main',
+            'sidebar.additional' => 'Sidebar Additional'
+        ];
+        $layoutProcessorContainers = [
+            'product.info.virtual.extra' => 'Product Extra Info',
+            'header.panel' => 'Page Header Panel',
+            'header-wrapper' => 'Page Header',
+            'top.container' => 'After Page Header Top',
+            'content.top' => 'Main Content Top',
+            'content' => 'Main Content Area',
+            'content.aside' => 'Main Content Aside',
+            'content.bottom' => 'Main Content Bottom',
+            'page.bottom' => 'Before Page Footer',
+            'footer' => 'Page Footer',
+            'cms_footer_links_container' => 'CMS Footer Links'
+        ];
+        $allowedContainers = ['content', 'content.top', 'content.bottom'];
+        $expectedHtml = '<select name="block" id="" class="required-entry select" title="" '
+            . 'onchange="WidgetInstance.loadSelectBoxByType(\'block_template\', this.up(\'div.group_container\'), '
+            . 'this.value)"><option value="" selected="selected" >-- Please Select --</option><option value="content" >'
+            . 'Main Content Area</option><option value="content.bottom" >Main Content Bottom</option>'
+            . '<option value="content.top" >Main Content Top</option></select>';
+
+        $this->eventManagerMock->expects($this->once())->method('dispatch')->willReturn(true);
+        $this->scopeConfigMock->expects($this->once())->method('getValue')->willReturn(false);
+
+        $this->themeCollectionFactoryMock->expects($this->once())
+            ->method('create')
+            ->willReturn($this->themeCollectionMock);
+        $this->themeCollectionMock->expects($this->once())->method('getItemById')->willReturn($this->themeMock);
+
+        $this->layoutProcessorFactoryMock->expects($this->exactly(2))
+            ->method('create')
+            ->willReturn($this->layoutMergeMock);
+        $this->layoutMergeMock->expects($this->exactly(2))->method('addPageHandles')->willReturn(true);
+        $this->layoutMergeMock->expects($this->exactly(2))->method('load')->willReturnSelf();
+        $this->layoutMergeMock->expects($this->any())->method('addHandle')->willReturnSelf();
+        $this->layoutMergeMock->expects($this->any())->method('getContainers')->willReturnOnConsecutiveCalls(
+            $pageLayoutProcessorContainers,
+            $layoutProcessorContainers
+        );
+
+        $this->containerBlock->setAllowedContainers($allowedContainers);
+        $this->containerBlock->setValue('');
+
+        $this->escaperMock->expects($this->any())->method('escapeHtml')->willReturnMap(
+            [
+                ['', null, ''],
+                ['-- Please Select --', null, '-- Please Select --'],
+                ['content', null, 'content'],
+                ['Main Content Area', null, 'Main Content Area'],
+                ['content.bottom', null, 'content.bottom'],
+                ['Main Content Bottom', null, 'Main Content Bottom'],
+                ['content.top', null, 'content.top'],
+                ['Main Content Top', null, 'Main Content Top']
+            ]
+        );
+
+        $this->assertEquals($expectedHtml, $this->containerBlock->toHtml());
+    }
+
+    /**
+     * @return void
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+     */
+    public function testToHtmlCatalogCategoryLinkSimpleProduct()
+    {
+        $pageLayoutProcessorContainers = [
+            'after.body.start' => 'Page Top',
+            'columns.top' => 'Before Main Columns',
+            'main' => 'Main Content Container',
+            'page.bottom' => 'Before Page Footer Container',
+            'before.body.end' => 'Page Bottom',
+            'header.container' => 'Page Header Container',
+            'page.top' => 'After Page Header',
+            'footer-container' => 'Page Footer Container',
+            'sidebar.main' => 'Sidebar Main',
+            'sidebar.additional' => 'Sidebar Additional'
+        ];
+        $layoutProcessorContainers = [
+            'product.info.simple.extra' => 'Product Extra Info',
+            'header.panel' => 'Page Header Panel',
+            'header-wrapper' => 'Page Header',
+            'top.container' => 'After Page Header Top',
+            'content.top' => 'Main Content Top',
+            'content' => 'Main Content Area',
+            'content.aside' => 'Main Content Aside',
+            'content.bottom' => 'Main Content Bottom',
+            'page.bottom' => 'Before Page Footer',
+            'footer' => 'Page Footer',
+            'cms_footer_links_container' => 'CMS Footer Links'
+        ];
+        $allowedContainers = [];
+        $expectedHtml = '<select name="block" id="" class="required-entry select" title="" '
+            . 'onchange="WidgetInstance.loadSelectBoxByType(\'block_template\', this.up(\'div.group_container\'), '
+            . 'this.value)"><option value="" selected="selected" >-- Please Select --</option>'
+            . '<option value="page.top" >After Page Header</option><option value="top.container" >After Page Header Top'
+            . '</option><option value="columns.top" >Before Main Columns</option><option value="page.bottom" >'
+            . 'Before Page Footer</option><option value="cms_footer_links_container" >CMS Footer Links</option>'
+            . '<option value="content" >Main Content Area</option><option value="content.aside" >Main Content Aside'
+            . '</option><option value="content.bottom" >Main Content Bottom</option><option value="main" >'
+            . 'Main Content Container</option><option value="content.top" >Main Content Top</option>'
+            . '<option value="before.body.end" >Page Bottom</option><option value="footer" >Page Footer</option>'
+            . '<option value="footer-container" >Page Footer Container</option><option value="header-wrapper" >'
+            . 'Page Header</option><option value="header.container" >Page Header Container</option>'
+            . '<option value="header.panel" >Page Header Panel</option><option value="after.body.start" >'
+            . 'Page Top</option><option value="product.info.simple.extra" >Product Extra Info</option>'
+            . '<option value="sidebar.additional" >Sidebar Additional</option>'
+            . '<option value="sidebar.main" >Sidebar Main</option></select>';
+
+        $this->eventManagerMock->expects($this->once())->method('dispatch')->willReturn(true);
+        $this->scopeConfigMock->expects($this->once())->method('getValue')->willReturn(false);
+
+        $this->themeCollectionFactoryMock->expects($this->once())
+            ->method('create')
+            ->willReturn($this->themeCollectionMock);
+        $this->themeCollectionMock->expects($this->once())->method('getItemById')->willReturn($this->themeMock);
+
+        $this->layoutProcessorFactoryMock->expects($this->exactly(2))
+            ->method('create')
+            ->willReturn($this->layoutMergeMock);
+        $this->layoutMergeMock->expects($this->exactly(2))->method('addPageHandles')->willReturn(true);
+        $this->layoutMergeMock->expects($this->exactly(2))->method('load')->willReturnSelf();
+        $this->layoutMergeMock->expects($this->any())->method('addHandle')->willReturnSelf();
+        $this->layoutMergeMock->expects($this->any())->method('getContainers')->willReturnOnConsecutiveCalls(
+            $pageLayoutProcessorContainers,
+            $layoutProcessorContainers
+        );
+
+        $this->containerBlock->setAllowedContainers($allowedContainers);
+        $this->containerBlock->setValue('');
+
+        $this->escaperMock->expects($this->any())->method('escapeHtml')->willReturnMap(
+            [
+                ['', null, ''],
+                ['-- Please Select --', null, '-- Please Select --'],
+                ['page.top', null, 'page.top'],
+                ['After Page Header', null, 'After Page Header'],
+                ['top.container', null, 'top.container'],
+                ['After Page Header Top', null, 'After Page Header Top'],
+                ['columns.top', null, 'columns.top'],
+                ['Before Main Columns', null, 'Before Main Columns'],
+                ['page.bottom', null, 'page.bottom'],
+                ['Before Page Footer', null, 'Before Page Footer'],
+                ['cms_footer_links_container', null, 'cms_footer_links_container'],
+                ['CMS Footer Links', null, 'CMS Footer Links'],
+                ['content', null, 'content'],
+                ['Main Content Area', null, 'Main Content Area'],
+                ['content.aside', null, 'content.aside'],
+                ['Main Content Aside', null, 'Main Content Aside'],
+                ['content.bottom', null, 'content.bottom'],
+                ['Main Content Bottom', null, 'Main Content Bottom'],
+                ['main', null, 'main'],
+                ['Main Content Container', null, 'Main Content Container'],
+                ['content.top', null, 'content.top'],
+                ['Main Content Top', null, 'Main Content Top'],
+                ['before.body.end', null, 'before.body.end'],
+                ['Page Bottom', null, 'Page Bottom'],
+                ['footer', null, 'footer'],
+                ['Page Footer', null, 'Page Footer'],
+                ['footer-container', null, 'footer-container'],
+                ['Page Footer Container', null, 'Page Footer Container'],
+                ['header-wrapper', null, 'header-wrapper'],
+                ['Page Header', null, 'Page Header'],
+                ['header.container', null, 'header.container'],
+                ['Page Header Container', null, 'Page Header Container'],
+                ['header.panel', null, 'header.panel'],
+                ['Page Header Panel', null, 'Page Header Panel'],
+                ['after.body.start', null, 'after.body.start'],
+                ['Page Top', null, 'Page Top'],
+                ['product.info.simple.extra', null, 'product.info.simple.extra'],
+                ['Product Extra Info', null, 'Product Extra Info'],
+                ['sidebar.additional', null, 'sidebar.additional'],
+                ['Sidebar Additional', null, 'Sidebar Additional'],
+                ['sidebar.main', null, 'sidebar.main'],
+                ['Sidebar Main', null, 'Sidebar Main']
+            ]
+        );
+
+        $this->assertEquals($expectedHtml, $this->containerBlock->toHtml());
+    }
+
+    /**
+     * @return void
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+     */
+    public function testToHtmlCmsStaticBlockAllProductTypes()
+    {
+        $pageLayoutProcessorContainers = [
+            'after.body.start' => 'Page Top',
+            'columns.top' => 'Before Main Columns',
+            'main' => 'Main Content Container',
+            'page.bottom' => 'Before Page Footer Container',
+            'before.body.end' => 'Page Bottom',
+            'header.container' => 'Page Header Container',
+            'page.top' => 'After Page Header',
+            'footer-container' => 'Page Footer Container',
+            'sidebar.main' => 'Sidebar Main',
+            'sidebar.additional' => 'Sidebar Additional'
+        ];
+        $layoutProcessorContainers = [
+            'product.info.price' => 'Product info auxiliary container',
+            'product.info.stock.sku' => 'Product auxiliary info',
+            'alert.urls' => 'Alert Urls',
+            'product.info.extrahint' => 'Product View Extra Hint',
+            'product.info.social' => 'Product social links container',
+            'product.review.form.fields.before' => 'Review Form Fields Before',
+            'header.panel' => 'Page Header Panel',
+            'header-wrapper' => 'Page Header',
+            'top.container' => 'After Page Header Top',
+            'content.top' => 'Main Content Top',
+            'content' => 'Main Content Area',
+            'content.aside' => 'Main Content Aside',
+            'content.bottom' => 'Main Content Bottom',
+            'page.bottom' => 'Before Page Footer',
+            'footer' => 'Page Footer',
+            'cms_footer_links_container' => 'CMS Footer Links'
+        ];
+        $allowedContainers = [];
+        $expectedHtml = '<select name="block" id="" class="required-entry select" title="" '
+            . 'onchange="WidgetInstance.loadSelectBoxByType(\'block_template\', this.up(\'div.group_container\'), '
+            . 'this.value)"><option value="" selected="selected" >-- Please Select --</option>'
+            . '<option value="page.top" >After Page Header</option><option value="top.container" >After Page Header Top'
+            . '</option><option value="alert.urls" >Alert Urls</option><option value="columns.top" >Before Main Columns'
+            . '</option><option value="page.bottom" >Before Page Footer</option><option '
+            . 'value="cms_footer_links_container" >CMS Footer Links</option><option value="content" >'
+            . 'Main Content Area</option><option value="content.aside" >Main Content Aside</option>'
+            . '<option value="content.bottom" >Main Content Bottom</option><option value="main" >Main Content Container'
+            . '</option><option value="content.top" >Main Content Top</option><option value="before.body.end" >'
+            . 'Page Bottom</option><option value="footer" >Page Footer</option><option value="footer-container" >'
+            . 'Page Footer Container</option><option value="header-wrapper" >Page Header</option>'
+            . '<option value="header.container" >Page Header Container</option><option value="header.panel" >'
+            . 'Page Header Panel</option><option value="after.body.start" >Page Top</option>'
+            . '<option value="product.info.extrahint" >Product View Extra Hint</option>'
+            . '<option value="product.info.stock.sku" >Product auxiliary info</option>'
+            . '<option value="product.info.price" >Product info auxiliary container</option>'
+            . '<option value="product.info.social" >Product social links container</option>'
+            . '<option value="product.review.form.fields.before" >Review Form Fields Before</option>'
+            . '<option value="sidebar.additional" >Sidebar Additional</option>'
+            . '<option value="sidebar.main" >Sidebar Main</option></select>';
+
+        $this->eventManagerMock->expects($this->once())->method('dispatch')->willReturn(true);
+        $this->scopeConfigMock->expects($this->once())->method('getValue')->willReturn(false);
+
+        $this->themeCollectionFactoryMock->expects($this->once())
+            ->method('create')
+            ->willReturn($this->themeCollectionMock);
+        $this->themeCollectionMock->expects($this->once())->method('getItemById')->willReturn($this->themeMock);
+
+        $this->layoutProcessorFactoryMock->expects($this->exactly(2))
+            ->method('create')
+            ->willReturn($this->layoutMergeMock);
+        $this->layoutMergeMock->expects($this->exactly(2))->method('addPageHandles')->willReturn(true);
+        $this->layoutMergeMock->expects($this->exactly(2))->method('load')->willReturnSelf();
+        $this->layoutMergeMock->expects($this->any())->method('addHandle')->willReturnSelf();
+        $this->layoutMergeMock->expects($this->any())->method('getContainers')->willReturnOnConsecutiveCalls(
+            $pageLayoutProcessorContainers,
+            $layoutProcessorContainers
+        );
+
+        $this->containerBlock->setAllowedContainers($allowedContainers);
+        $this->containerBlock->setValue('');
+
+        $this->escaperMock->expects($this->any())->method('escapeHtml')->willReturnMap(
+            [
+                ['', null, ''],
+                ['-- Please Select --', null, '-- Please Select --'],
+                ['page.top', null, 'page.top'],
+                ['After Page Header', null, 'After Page Header'],
+                ['top.container', null, 'top.container'],
+                ['After Page Header Top', null, 'After Page Header Top'],
+                ['alert.urls', null, 'alert.urls'],
+                ['Alert Urls', null, 'Alert Urls'],
+                ['columns.top', null, 'columns.top'],
+                ['Before Main Columns', null, 'Before Main Columns'],
+                ['page.bottom', null, 'page.bottom'],
+                ['Before Page Footer', null, 'Before Page Footer'],
+                ['cms_footer_links_container', null, 'cms_footer_links_container'],
+                ['CMS Footer Links', null, 'CMS Footer Links'],
+                ['content', null, 'content'],
+                ['Main Content Area', null, 'Main Content Area'],
+                ['content.aside', null, 'content.aside'],
+                ['Main Content Aside', null, 'Main Content Aside'],
+                ['content.bottom', null, 'content.bottom'],
+                ['Main Content Bottom', null, 'Main Content Bottom'],
+                ['main', null, 'main'],
+                ['Main Content Container', null, 'Main Content Container'],
+                ['content.top', null, 'content.top'],
+                ['Main Content Top', null, 'Main Content Top'],
+                ['before.body.end', null, 'before.body.end'],
+                ['Page Bottom', null, 'Page Bottom'],
+                ['footer', null, 'footer'],
+                ['Page Footer', null, 'Page Footer'],
+                ['footer-container', null, 'footer-container'],
+                ['Page Footer Container', null, 'Page Footer Container'],
+                ['header-wrapper', null, 'header-wrapper'],
+                ['Page Header', null, 'Page Header'],
+                ['header.container', null, 'header.container'],
+                ['Page Header Container', null, 'Page Header Container'],
+                ['header.panel', null, 'header.panel'],
+                ['Page Header Panel', null, 'Page Header Panel'],
+                ['after.body.start', null, 'after.body.start'],
+                ['Page Top', null, 'Page Top'],
+                ['product.info.extrahint', null, 'product.info.extrahint'],
+                ['Product View Extra Hint', null, 'Product View Extra Hint'],
+                ['product.info.stock.sku', null, 'product.info.stock.sku'],
+                ['Product auxiliary info', null, 'Product auxiliary info'],
+                ['product.info.price', null, 'product.info.price'],
+                ['Product info auxiliary container', null, 'Product info auxiliary container'],
+                ['product.info.social', null, 'product.info.social'],
+                ['Product social links container', null, 'Product social links container'],
+                ['product.review.form.fields.before', null, 'product.review.form.fields.before'],
+                ['Review Form Fields Before', null, 'Review Form Fields Before'],
+                ['sidebar.additional', null, 'sidebar.additional'],
+                ['Sidebar Additional', null, 'Sidebar Additional'],
+                ['sidebar.main', null, 'sidebar.main'],
+                ['Sidebar Main', null, 'Sidebar Main']
+            ]
+        );
+
+        $this->assertEquals($expectedHtml, $this->containerBlock->toHtml());
+    }
+
+    /**
+     * @return void
+     */
+    public function testToHtmlOrderBySkuAllPages()
+    {
+        $pageLayoutProcessorContainers = [
+            'after.body.start' => 'Page Top',
+            'columns.top' => 'Before Main Columns',
+            'main' => 'Main Content Container',
+            'page.bottom' => 'Before Page Footer Container',
+            'before.body.end' => 'Page Bottom',
+            'header.container' => 'Page Header Container',
+            'page.top' => 'After Page Header',
+            'footer-container' => 'Page Footer Container',
+            'sidebar.main' => 'Sidebar Main',
+            'sidebar.additional' => 'Sidebar Additional'
+        ];
+        $layoutProcessorContainers = [
+            'header.panel' => 'Page Header Panel',
+            'header-wrapper' => 'Page Header',
+            'top.container' => 'After Page Header Top',
+            'content.top' => 'Main Content Top',
+            'content' => 'Main Content Area',
+            'content.aside' => 'Main Content Aside',
+            'content.bottom' => 'Main Content Bottom',
+            'page.bottom' => 'Before Page Footer',
+            'footer' => 'Page Footer',
+            'cms_footer_links_container' => 'CMS Footer Links'
+        ];
+        $allowedContainers = ['sidebar.main', 'sidebar.additional'];
+        $expectedHtml = '<select name="block" id="" class="required-entry select" title="" '
+            . 'onchange="WidgetInstance.loadSelectBoxByType(\'block_template\', this.up(\'div.group_container\'), '
+            . 'this.value)"><option value="" selected="selected" >-- Please Select --</option>'
+            . '<option value="sidebar.additional" >Sidebar Additional</option><option value="sidebar.main" >'
+            . 'Sidebar Main</option></select>';
+
+        $this->eventManagerMock->expects($this->once())->method('dispatch')->willReturn(true);
+        $this->scopeConfigMock->expects($this->once())->method('getValue')->willReturn(false);
+
+        $this->themeCollectionFactoryMock->expects($this->once())
+            ->method('create')
+            ->willReturn($this->themeCollectionMock);
+        $this->themeCollectionMock->expects($this->once())->method('getItemById')->willReturn($this->themeMock);
+
+        $this->layoutProcessorFactoryMock->expects($this->exactly(2))
+            ->method('create')
+            ->willReturn($this->layoutMergeMock);
+        $this->layoutMergeMock->expects($this->exactly(2))->method('addPageHandles')->willReturn(true);
+        $this->layoutMergeMock->expects($this->exactly(2))->method('load')->willReturnSelf();
+        $this->layoutMergeMock->expects($this->any())->method('addHandle')->willReturnSelf();
+        $this->layoutMergeMock->expects($this->any())->method('getContainers')->willReturnOnConsecutiveCalls(
+            $pageLayoutProcessorContainers,
+            $layoutProcessorContainers
+        );
+
+        $this->containerBlock->setAllowedContainers($allowedContainers);
+        $this->containerBlock->setValue('');
+
+        $this->escaperMock->expects($this->any())->method('escapeHtml')->willReturnMap(
+            [
+                ['', null, ''],
+                ['-- Please Select --', null, '-- Please Select --'],
+                ['sidebar.additional', null, 'sidebar.additional'],
+                ['Sidebar Additional', null, 'Sidebar Additional'],
+                ['sidebar.main', null, 'sidebar.main'],
+                ['Sidebar Main', null, 'Sidebar Main']
+            ]
+        );
+
+        $this->assertEquals($expectedHtml, $this->containerBlock->toHtml());
+    }
+}
diff --git a/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/module/components/_steps-wizard.less b/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/module/components/_steps-wizard.less
index d4d0f23d07a1b77b8f962ddafe2a011dd85181e6..ce66c1ae77264e8f76f84e17d7888963b7262ba0 100644
--- a/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/module/components/_steps-wizard.less
+++ b/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/module/components/_steps-wizard.less
@@ -24,7 +24,7 @@
     .product-create-configuration-actions {
         float: right;
         text-align: right;
-        width: 50%;
+        width: 25%;
     }
 }
 
diff --git a/app/design/frontend/Magento/blank/Magento_Bundle/web/css/source/_module.less b/app/design/frontend/Magento/blank/Magento_Bundle/web/css/source/_module.less
index 41f09cede4543914e6897aade0c0f088270c0537..cbc2b02bcb7c749a5a4ec1be568ef462101dd212 100644
--- a/app/design/frontend/Magento/blank/Magento_Bundle/web/css/source/_module.less
+++ b/app/design/frontend/Magento/blank/Magento_Bundle/web/css/source/_module.less
@@ -4,120 +4,121 @@
 //  */
 
 //
-//    Common
-//--------------------------------------
+//  Common
+//  _____________________________________________
 
 & when (@media-common = true) {
 
-.bundle-actions {
-    &:extend(.abs-box-tocart all);
-    .action.primary {
-        &:extend(.abs-button-l all);
-    }
-}
-
-.bundle-options-container {
-    clear: both;
-    margin-bottom: @indent__xl;
-
-    .legend.title {
-        .lib-heading(h2);
+    .bundle-actions {
+        &:extend(.abs-box-tocart all);
+        .action.primary {
+            &:extend(.abs-button-l all);
+        }
     }
 
-    .product-add-form {
-        display: none;
-    }
+    .bundle-options-container {
+        clear: both;
+        margin-bottom: @indent__xl;
 
-    .input-text.qty {
-        &:extend(.abs-input-qty all);
-    }
+        .legend.title {
+            .lib-heading(h2);
+        }
 
-    .product-options-wrapper {
-        margin-bottom: @indent__l;
-    }
+        .product-add-form {
+            display: none;
+        }
 
-    .action.back {
-        margin-bottom: @indent__l;
-    }
+        .input-text.qty {
+            &:extend(.abs-input-qty all);
+        }
 
-    .price-box {
-        .price {
-            font-weight: @font-weight__bold;
-            font-size: @font-size__l;
+        .product-options-wrapper {
+            margin-bottom: @indent__l;
         }
-    }
 
-    .price-notice {
-        &:extend(.abs-adjustment-incl-excl-tax all);
-    }
+        .action.back {
+            margin-bottom: @indent__l;
+        }
 
-    .block-bundle-summary {
-        &:extend(.abs-add-box-sizing all);
-        .lib-css(background, @secondary__color);
-        padding: @indent__s @indent__base;
+        .price-box {
+            .price {
+                font-size: @font-size__l;
+                font-weight: @font-weight__bold;
+            }
+        }
 
-        > .title > strong {
-            .lib-heading(h2);
+        .price-notice {
+            &:extend(.abs-adjustment-incl-excl-tax all);
         }
 
-        .bundle-summary {
-            margin-top: @indent__l;
-            &.empty {
-                display: none;
+        .block-bundle-summary {
+            &:extend(.abs-add-box-sizing all);
+            .lib-css(background, @secondary__color);
+            padding: @indent__s @indent__base;
+
+            > .title > strong {
+                .lib-heading(h2);
             }
-            > .subtitle {
-                .lib-heading(h3);
-                display: block;
+
+            .bundle-summary {
+                margin-top: @indent__l;
+                &.empty {
+                    display: none;
+                }
+                > .subtitle {
+                    .lib-heading(h3);
+                    display: block;
+                }
             }
-        }
 
-        .bundle.items {
-            &:extend(.abs-reset-list all);
-            > li {
-                margin-bottom: @indent__s;
+            .bundle.items {
+                &:extend(.abs-reset-list all);
+                > li {
+                    margin-bottom: @indent__s;
+                }
             }
-        }
 
-        .box-tocart {
-            .actions {
-                margin-bottom: @indent__s;
-                display: inline-block;
+            .box-tocart {
+                .actions {
+                    display: inline-block;
+                    margin-bottom: @indent__s;
+                }
+                .action.primary {
+                    &:extend(.abs-button-l all);
+                }
             }
-            .action.primary {
-                &:extend(.abs-button-l all);
+            .product-addto-links {
+                > .action {
+                    &:extend(.abs-action-addto-product all);
+                    vertical-align: top;
+                }
             }
         }
-        .product-addto-links {
-            > .action {
-                &:extend(.abs-action-addto-product all);
-                vertical-align: top;
+        .nested {
+            .field.qty {
+                .label {
+                    .lib-css(font-weight, @form-field-label__font-weight);
+                    .lib-css(margin, 0 0 @indent__xs);
+                    display: inline-block;
+                }
+                .lib-css(margin-top, @form-field__vertical-indent);
             }
         }
-    }
-    .nested {
-        .field.qty {
-            .label {
-                .lib-css(font-weight, @form-field-label__font-weight);
-                .lib-css(margin, 0 0 @indent__xs);
-                display: inline-block;
-            }
-            .lib-css(margin-top, @form-field__vertical-indent);
+        p.required {
+            .lib-css(color, @form-field-label-asterisk__color);
         }
     }
-    p.required {
-        .lib-css(color, @form-field-label-asterisk__color);
-    }
-}
 
 }
 
 //
-//    Desktop
-//--------------------------------------
+//  Desktop
+//  _____________________________________________
+
 .media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__m) {
     .bundle-options-container {
         .legend.title {
-            &:extend(.abs-reset-left-margin all);
+            &:extend(.abs-reset-left-margin-desktop all);
         }
         .bundle-options-wrapper,
         .product-options-wrapper {
@@ -126,8 +127,8 @@
         }
         .block-bundle-summary {
             float: right;
-            width: 40%;
             position: relative;
+            width: 40%;
         }
         .bundle-options-wrapper,
         .block-bundle-summary {
diff --git a/app/design/frontend/Magento/luma/Magento_Bundle/web/css/source/_module.less b/app/design/frontend/Magento/luma/Magento_Bundle/web/css/source/_module.less
index 4f2e1f6e2f20acaf528afd647c3c78ad62b6fe69..1d595ccb3fe48229cf67a0053761c1718c82ac21 100644
--- a/app/design/frontend/Magento/luma/Magento_Bundle/web/css/source/_module.less
+++ b/app/design/frontend/Magento/luma/Magento_Bundle/web/css/source/_module.less
@@ -4,168 +4,171 @@
 //  */
 
 //
-//    Common
-//--------------------------------------
+//  Common
+//  _____________________________________________
 
 & when (@media-common = true) {
 
-.bundle-actions {
-    margin: 0 0 @indent__l;
-    .action.primary.customize {
-        &:extend(.abs-button-l all);
-        &:extend(.abs-button-responsive all);
+    .bundle-actions {
+        margin: 0 0 @indent__l;
+        .action.primary.customize {
+            &:extend(.abs-button-l all);
+            &:extend(.abs-button-responsive all);
+        }
     }
-}
-
-.bundle-options-container {
-    clear: both;
-    margin-bottom: @indent__xl;
 
-    .legend.title {
-        .lib-heading(h1);
-        border: 0;
-        padding: 0;
-    }
+    .bundle-options-container {
+        clear: both;
+        margin-bottom: @indent__xl;
 
-    .product-add-form {
-        display: none;
-    }
+        .legend.title {
+            .lib-heading(h1);
+            border: 0;
+            padding: 0;
+        }
 
-    .input-text.qty {
-        &:extend(.abs-input-qty all);
-    }
+        .product-add-form {
+            display: none;
+        }
 
-    .product-options-wrapper {
-        margin-bottom: @indent__l;
-        .fieldset > .field {
-            padding-top: @form-field__vertical-indent;
-            border-top: 1px @color-gray-middle1 solid;
-            &:first-of-type {
-                border-top: 0;
-                padding-top: 0;
-            }
+        .input-text.qty {
+            &:extend(.abs-input-qty all);
         }
-        .field.choice {
-            input {
-                float: left;
-            }
-            .label {
-                margin-left: 24px;
-                display: block;
-            }
-            .product-name {
-                display: block;
-            }
-            .label {
-                &:extend(.abs-add-clearfix all);
+
+        .product-options-wrapper {
+            margin-bottom: @indent__l;
+            .fieldset > .field {
+                border-top: 1px @color-gray-middle1 solid;
+                padding-top: @form-field__vertical-indent;
+                &:first-of-type {
+                    border-top: 0;
+                    padding-top: 0;
+                }
             }
-            .price-notice {
-                float: left;
-                &:extend(.abs-adjustment-incl-excl-tax all);
+            .fieldset-bundle-options {
+                .field.choice {
+                    .price-notice {
+                        float: left;
+                        &:extend(.abs-adjustment-incl-excl-tax all);
+                    }
+                }
             }
-            .price-excluding-tax {
-                display: inline-block;
+            .field.choice {
+                input {
+                    float: left;
+                }
+                .label {
+                    display: block;
+                    margin-left: 24px;
+                }
+                .product-name {
+                    display: block;
+                }
+                .label {
+                    &:extend(.abs-add-clearfix all);
+                }
+                .price-excluding-tax {
+                    display: inline-block;
+                }
             }
         }
-    }
-
-    .action.back {
-        &:extend(.abs-action-button-as-link all);
-        margin-bottom: @indent__l;
-    }
 
-    .block-bundle-summary {
-        > .title {
-            margin-bottom: 15px;
-            > strong {
-                .lib-heading(h2);
-            }
-        }
-        > .title,
-        .bundle-summary .subtitle {
-            border-bottom: 1px @color-gray-middle1 solid;
-            padding-bottom: 16px;
-            margin-bottom: @indent__m;
-        }
-        .price-box {
-            margin-bottom: @indent__base;
-            .price-label {
-                display: block;
-                margin-bottom: @indent__xs;
-            }
+        .action.back {
+            &:extend(.abs-action-button-as-link all);
+            margin-bottom: @indent__l;
         }
 
-        .bundle-summary {
-            margin-top: @indent__l;
-            &.empty {
-                display: none;
+        .block-bundle-summary {
+            > .title {
+                margin-bottom: 15px;
+                > strong {
+                    .lib-heading(h2);
+                }
             }
-            > .subtitle {
-                .lib-heading(h2);
-                display: block;
+            > .title,
+            .bundle-summary .subtitle {
+                border-bottom: 1px @color-gray-middle1 solid;
+                margin-bottom: @indent__m;
+                padding-bottom: 16px;
             }
-        }
-
-        .bundle.items {
-            &:extend(.abs-reset-list all);
-            > li {
+            .price-box {
                 margin-bottom: @indent__base;
+                .price-label {
+                    display: block;
+                    margin-bottom: @indent__xs;
+                }
             }
-        }
 
-        .box-tocart {
-            &:extend(.abs-box-tocart all);
-            .action.primary {
-                &:extend(.abs-button-l all);
-                &:extend(.abs-button-responsive all);
+            .bundle-summary {
+                margin-top: @indent__l;
+                &.empty {
+                    display: none;
+                }
+                > .subtitle {
+                    .lib-heading(h2);
+                    display: block;
+                }
             }
-        }
-        .product-addto-links {
-            text-align: center;
-            > .action {
-                &:extend(.abs-actions-addto all);
-                margin-right: 5%;
-                &.tocompare {
-                    .lib-icon-font-symbol(
-                        @_icon-font-content: @icon-compare-full,
-                        @_icon-font-position: before
-                    );
+
+            .bundle.items {
+                &:extend(.abs-reset-list all);
+                > li {
+                    margin-bottom: @indent__base;
                 }
+            }
 
+            .box-tocart {
+                &:extend(.abs-box-tocart all);
+                .action.primary {
+                    &:extend(.abs-button-l all);
+                    &:extend(.abs-button-responsive all);
+                }
+            }
+            .product-addto-links {
+                text-align: center;
+                > .action {
+                    &:extend(.abs-actions-addto all);
+                    margin-right: 5%;
+                    &.tocompare {
+                        .lib-icon-font-symbol(
+                            @_icon-font-content: @icon-compare-full,
+                            @_icon-font-position: before
+                        );
+                    }
+                }
             }
 
+            .product-image-container,
+            .product.name,
+            .stock {
+                &:extend(.abs-visually-hidden all);
+            }
         }
-        .product-image-container,
-        .product.name,
-        .stock {
-            &:extend(.abs-visually-hidden all);
+        p.required {
+            .lib-css(color, @form-field-label-asterisk__color);
         }
-    }
-    p.required {
-        .lib-css(color, @form-field-label-asterisk__color);
-    }
-    .nested {
-        .field.qty {
-            .lib-form-field-type(@_type: block);
-            .label {
-                font-weight: @form-field-label__font-weight;
-            }
-            &:last-child {
-                margin-bottom: 0;
+        .nested {
+            .field.qty {
+                .lib-form-field-type(@_type: block);
+                .label {
+                    font-weight: @form-field-label__font-weight;
+                }
+                &:last-child {
+                    margin-bottom: 0;
+                }
+                margin-top: @form-field__vertical-indent;
             }
-            margin-top: @form-field__vertical-indent;
+        }
+        .price {
+            font-weight: @font-weight__semibold;
         }
     }
-    .price {
-        font-weight: @font-weight__semibold;
-    }
-}
-
 }
 
 //
-//    Desktop
-//--------------------------------------
+//  Desktop
+//  _____________________________________________
+
 .media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__m) {
     .bundle-actions {
         .action.primary.customize {
@@ -182,19 +185,19 @@
             width: 57%;
         }
         .block-bundle-summary {
-            margin-top: 66px;
-            padding: @indent__s @indent__base;
             &:extend(.abs-add-box-sizing-desktop all);
             float: right;
-            width: 40%;
+            margin-top: 66px;
+            padding: @indent__s @indent__base;
             position: relative;
+            width: 40%;
             .price-box {
                 .price-wrapper,
                 .price-wrapper > .price {
+                    .lib-css(color, @price-color);
                     font-size: @price-size-desktop;
-                    line-height: @price-size-desktop;
                     font-weight: @font-weight__semibold;
-                    .lib-css(color, @price-color);
+                    line-height: @price-size-desktop;
                 }
             }
             .price-container {
@@ -214,8 +217,8 @@
             }
             .box-tocart {
                 .action.primary {
-                    width: 49%;
                     margin-right: 1%;
+                    width: 49%;
                 }
             }
             .product-addto-links {
diff --git a/app/etc/di.xml b/app/etc/di.xml
index fbb7c6946ce3cb006f2be5c1d76476b3e5f05f53..e26240c8b6c8cb6200191e0c245d5f371e1b90c9 100755
--- a/app/etc/di.xml
+++ b/app/etc/di.xml
@@ -1048,6 +1048,13 @@
             </argument>
         </arguments>
     </type>
+    <type name="Magento\Server\Reflection" shared="false" />
+    <type name="Magento\Framework\Reflection\DataObjectProcessor">
+        <arguments>
+            <argument name="extensionAttributesProcessor" xsi:type="object">Magento\Framework\Reflection\ExtensionAttributesProcessor\Proxy</argument>
+            <argument name="customAttributesProcessor" xsi:type="object">Magento\Framework\Reflection\CustomAttributesProcessor\Proxy</argument>
+        </arguments>
+    </type>
     <type name="Magento\Framework\Url\Decoder">
         <arguments>
             <argument name="urlBuilder" xsi:type="object">Magento\Framework\UrlInterface</argument>
diff --git a/composer.json b/composer.json
index 0889646cdd9c7635d753b3f62a77a6ca8c75f96a..aaee3a68a7e769aa2e1eb874ae7166d9e5c2ae91 100644
--- a/composer.json
+++ b/composer.json
@@ -89,6 +89,7 @@
         "magento/module-catalog-import-export": "self.version",
         "magento/module-catalog-inventory": "self.version",
         "magento/module-catalog-rule": "self.version",
+        "magento/module-catalog-rule-configurable": "self.version",
         "magento/module-catalog-search": "self.version",
         "magento/module-catalog-url-rewrite": "self.version",
         "magento/module-catalog-widget": "self.version",
diff --git a/composer.lock b/composer.lock
index 5f638af51713461dbdf2da2e6ad428b7b827ab1b..7a535537728f48501df92ac8949dc4abdccb6454 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,8 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
         "This file is @generated automatically"
     ],
-    "hash": "ba8186cbc63f5db144177d64249726e6",
+    "hash": "e0a48d8c3c8b3c4282676fee9dc9abbc",
+    "content-hash": "5354ef6633dacbab5d7c144ca116624c",
     "packages": [
         {
             "name": "braintree/braintree_php",
@@ -216,20 +217,20 @@
         },
         {
             "name": "magento/magento-composer-installer",
-            "version": "0.1.4",
+            "version": "0.1.5",
             "source": {
                 "type": "git",
                 "url": "https://github.com/magento/magento-composer-installer.git",
-                "reference": "7f03451f71e55d52c2bb07325d56a4e6df322f30"
+                "reference": "1b33917bfc3f4a0856276dcbe46ce35362f50fc3"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/magento/magento-composer-installer/zipball/7f03451f71e55d52c2bb07325d56a4e6df322f30",
-                "reference": "7f03451f71e55d52c2bb07325d56a4e6df322f30",
+                "url": "https://api.github.com/repos/magento/magento-composer-installer/zipball/1b33917bfc3f4a0856276dcbe46ce35362f50fc3",
+                "reference": "1b33917bfc3f4a0856276dcbe46ce35362f50fc3",
                 "shasum": ""
             },
             "require": {
-                "composer-plugin-api": "1.0.0"
+                "composer-plugin-api": "^1.0"
             },
             "require-dev": {
                 "composer/composer": "*@dev",
@@ -288,7 +289,7 @@
                 "composer-installer",
                 "magento"
             ],
-            "time": "2015-03-05 21:40:30"
+            "time": "2015-09-14 19:59:55"
         },
         {
             "name": "magento/zendframework1",
@@ -2663,16 +2664,16 @@
         },
         {
             "name": "lusitanian/oauth",
-            "version": "v0.4.1",
+            "version": "v0.5.5",
             "source": {
                 "type": "git",
                 "url": "https://github.com/Lusitanian/PHPoAuthLib.git",
-                "reference": "b617831ffe58564c3ae06772a8b20310929af2ea"
+                "reference": "916cff8e02df5d52e67aaddd57aa618205dd93c2"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/Lusitanian/PHPoAuthLib/zipball/b617831ffe58564c3ae06772a8b20310929af2ea",
-                "reference": "b617831ffe58564c3ae06772a8b20310929af2ea",
+                "url": "https://api.github.com/repos/Lusitanian/PHPoAuthLib/zipball/916cff8e02df5d52e67aaddd57aa618205dd93c2",
+                "reference": "916cff8e02df5d52e67aaddd57aa618205dd93c2",
                 "shasum": ""
             },
             "require": {
@@ -2726,7 +2727,7 @@
                 "oauth",
                 "security"
             ],
-            "time": "2015-09-09 23:42:55"
+            "time": "2015-09-20 00:14:11"
         },
         {
             "name": "pdepend/pdepend",
@@ -2769,28 +2770,28 @@
         },
         {
             "name": "phpmd/phpmd",
-            "version": "2.2.3",
+            "version": "2.3.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/phpmd/phpmd.git",
-                "reference": "5eeb5a4d39c8304910b33ae49f8813905346cc35"
+                "reference": "246b254505951508bea08db5dde44322264f75fe"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/phpmd/phpmd/zipball/5eeb5a4d39c8304910b33ae49f8813905346cc35",
-                "reference": "5eeb5a4d39c8304910b33ae49f8813905346cc35",
+                "url": "https://api.github.com/repos/phpmd/phpmd/zipball/246b254505951508bea08db5dde44322264f75fe",
+                "reference": "246b254505951508bea08db5dde44322264f75fe",
                 "shasum": ""
             },
             "require": {
                 "pdepend/pdepend": "~2.0",
                 "php": ">=5.3.0",
-                "symfony/config": ">=2.4",
-                "symfony/dependency-injection": ">=2.4",
-                "symfony/filesystem": ">=2.4"
+                "symfony/config": "^2.4",
+                "symfony/dependency-injection": "^2.4",
+                "symfony/filesystem": "^2.4"
             },
             "require-dev": {
-                "phpunit/phpunit": "*",
-                "squizlabs/php_codesniffer": "*"
+                "phpunit/phpunit": "^4.0",
+                "squizlabs/php_codesniffer": "^2.0"
             },
             "bin": [
                 "src/bin/phpmd"
@@ -2810,12 +2811,18 @@
                     "name": "Manuel Pichler",
                     "email": "github@manuel-pichler.de",
                     "homepage": "https://github.com/manuelpichler",
-                    "role": "Project founder"
+                    "role": "Project Founder"
                 },
                 {
                     "name": "Other contributors",
                     "homepage": "https://github.com/phpmd/phpmd/graphs/contributors",
                     "role": "Contributors"
+                },
+                {
+                    "name": "Marc Würth",
+                    "email": "ravage@bluewin.ch",
+                    "homepage": "https://github.com/ravage84",
+                    "role": "Project Maintainer"
                 }
             ],
             "description": "PHPMD is a spin-off project of PHP Depend and aims to be a PHP equivalent of the well known Java tool PMD.",
@@ -2827,20 +2834,20 @@
                 "phpmd",
                 "pmd"
             ],
-            "time": "2015-05-27 18:16:57"
+            "time": "2015-09-22 05:16:44"
         },
         {
             "name": "phpunit/php-code-coverage",
-            "version": "2.2.2",
+            "version": "2.2.3",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
-                "reference": "2d7c03c0e4e080901b8f33b2897b0577be18a13c"
+                "reference": "ef1ca6835468857944d5c3b48fa503d5554cff2f"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/2d7c03c0e4e080901b8f33b2897b0577be18a13c",
-                "reference": "2d7c03c0e4e080901b8f33b2897b0577be18a13c",
+                "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ef1ca6835468857944d5c3b48fa503d5554cff2f",
+                "reference": "ef1ca6835468857944d5c3b48fa503d5554cff2f",
                 "shasum": ""
             },
             "require": {
@@ -2889,7 +2896,7 @@
                 "testing",
                 "xunit"
             ],
-            "time": "2015-08-04 03:42:39"
+            "time": "2015-09-14 06:51:16"
         },
         {
             "name": "phpunit/php-file-iterator",
@@ -3020,16 +3027,16 @@
         },
         {
             "name": "phpunit/php-token-stream",
-            "version": "1.4.6",
+            "version": "1.4.8",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/php-token-stream.git",
-                "reference": "3ab72c62e550370a6cd5dc873e1a04ab57562f5b"
+                "reference": "3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/3ab72c62e550370a6cd5dc873e1a04ab57562f5b",
-                "reference": "3ab72c62e550370a6cd5dc873e1a04ab57562f5b",
+                "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da",
+                "reference": "3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da",
                 "shasum": ""
             },
             "require": {
@@ -3065,7 +3072,7 @@
             "keywords": [
                 "tokenizer"
             ],
-            "time": "2015-08-16 08:51:00"
+            "time": "2015-09-15 10:49:45"
         },
         {
             "name": "phpunit/phpunit",
diff --git a/dev/tests/api-functional/framework/Magento/TestFramework/Bootstrap/WebapiDocBlock.php b/dev/tests/api-functional/framework/Magento/TestFramework/Bootstrap/WebapiDocBlock.php
index b8f7c54ad70f11f951c24391b0efedb099ca198e..831becca6f3d2e645e9908f29bd7485fd339c50a 100644
--- a/dev/tests/api-functional/framework/Magento/TestFramework/Bootstrap/WebapiDocBlock.php
+++ b/dev/tests/api-functional/framework/Magento/TestFramework/Bootstrap/WebapiDocBlock.php
@@ -18,7 +18,7 @@ class WebapiDocBlock extends \Magento\TestFramework\Bootstrap\DocBlock
     protected function _getSubscribers(\Magento\TestFramework\Application $application)
     {
         $subscribers = parent::_getSubscribers($application);
-        array_unshift($subscribers, new \Magento\TestFramework\Annotation\ApiDataFixture($this->_fixturesBaseDir));
+        $subscribers[] = new \Magento\TestFramework\Annotation\ApiDataFixture($this->_fixturesBaseDir);
         return $subscribers;
     }
 }
diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductLinkManagementInterfaceTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductLinkManagementInterfaceTest.php
index 3aa38f8cdb53f505a5f2b7b530b176c47fac6a69..ff7e2abfbe54f57d705ad65da425bab15b5521ff 100644
--- a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductLinkManagementInterfaceTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductLinkManagementInterfaceTest.php
@@ -9,6 +9,9 @@ namespace Magento\Catalog\Api;
 use Magento\TestFramework\Helper\Bootstrap;
 use Magento\TestFramework\TestCase\WebapiAbstract;
 
+/**
+ * @magentoAppIsolation enabled
+ */
 class ProductLinkManagementInterfaceTest extends WebapiAbstract
 {
     const SERVICE_NAME = 'catalogProductLinkManagementV1';
@@ -85,7 +88,7 @@ class ProductLinkManagementInterfaceTest extends WebapiAbstract
 
     /**
      * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
-     * @magentoApiDataFixture Magento/Catalog/_files/product_virtual.php
+     * @magentoApiDataFixture Magento/Catalog/_files/product_virtual_in_stock.php
      */
     public function testAssign()
     {
diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductRepositoryInterfaceTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductRepositoryInterfaceTest.php
index d33e1456bc363e80830d3d1a32229fbccaaebc69..4cbfcf59b2c538d32f78819a903fff2b31c3d2aa 100644
--- a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductRepositoryInterfaceTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductRepositoryInterfaceTest.php
@@ -6,9 +6,13 @@
 namespace Magento\Catalog\Api;
 
 use Magento\Catalog\Api\Data\ProductInterface;
+use Magento\CatalogInventory\Api\Data\StockItemInterface;
 use Magento\TestFramework\TestCase\WebapiAbstract;
 use Magento\Framework\Webapi\Exception as HTTPExceptionCodes;
 
+/**
+ * @magentoAppIsolation enabled
+ */
 class ProductRepositoryInterfaceTest extends WebapiAbstract
 {
     const SERVICE_NAME = 'catalogProductRepositoryV1';
@@ -139,6 +143,9 @@ class ProductRepositoryInterfaceTest extends WebapiAbstract
             ProductInterface::STATUS => 1,
             ProductInterface::TYPE_ID => 'simple',
             ProductInterface::ATTRIBUTE_SET_ID => 4,
+            ProductInterface::EXTENSION_ATTRIBUTES_KEY => [
+                'stock_item' => $this->getStockItemData()
+            ]
         ];
 
         $this->saveProduct($productData);
@@ -778,4 +785,36 @@ class ProductRepositoryInterfaceTest extends WebapiAbstract
         $response = $this->deleteProduct($productData[ProductInterface::SKU]);
         $this->assertTrue($response);
     }
+
+    /**
+     * @return array
+     */
+    private function getStockItemData()
+    {
+        return [
+            StockItemInterface::IS_IN_STOCK => 1,
+            StockItemInterface::QTY => 100500,
+            StockItemInterface::IS_QTY_DECIMAL => 1,
+            StockItemInterface::SHOW_DEFAULT_NOTIFICATION_MESSAGE => 0,
+            StockItemInterface::USE_CONFIG_MIN_QTY => 0,
+            StockItemInterface::USE_CONFIG_MIN_SALE_QTY => 0,
+            StockItemInterface::MIN_QTY => 1,
+            StockItemInterface::MIN_SALE_QTY => 1,
+            StockItemInterface::MAX_SALE_QTY => 100,
+            StockItemInterface::USE_CONFIG_MAX_SALE_QTY => 0,
+            StockItemInterface::USE_CONFIG_BACKORDERS => 0,
+            StockItemInterface::BACKORDERS => 0,
+            StockItemInterface::USE_CONFIG_NOTIFY_STOCK_QTY => 0,
+            StockItemInterface::NOTIFY_STOCK_QTY => 0,
+            StockItemInterface::USE_CONFIG_QTY_INCREMENTS => 0,
+            StockItemInterface::QTY_INCREMENTS => 0,
+            StockItemInterface::USE_CONFIG_ENABLE_QTY_INC => 0,
+            StockItemInterface::ENABLE_QTY_INCREMENTS => 0,
+            StockItemInterface::USE_CONFIG_MANAGE_STOCK => 1,
+            StockItemInterface::MANAGE_STOCK => 1,
+            StockItemInterface::LOW_STOCK_DATE => null,
+            StockItemInterface::IS_DECIMAL_DIVIDED => 0,
+            StockItemInterface::STOCK_STATUS_CHANGED_AUTO => 0,
+        ];
+    }
 }
diff --git a/dev/tests/api-functional/testsuite/Magento/CatalogInventory/Api/StockItemTest.php b/dev/tests/api-functional/testsuite/Magento/CatalogInventory/Api/StockItemTest.php
index 0f49b8bef0ae3f56dfff91db4c9ae8cc25f371c4..606c42e6b1269fa16cd5fc1c279fb7f561232425 100644
--- a/dev/tests/api-functional/testsuite/Magento/CatalogInventory/Api/StockItemTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/CatalogInventory/Api/StockItemTest.php
@@ -90,7 +90,7 @@ class StockItemTest extends WebapiAbstract
         $arguments = ['productSku' => $productSku];
         $apiResult = $this->_webApiCall($serviceInfo, $arguments);
         $result['item_id'] = $apiResult['item_id'];
-        $this->assertEquals($result, $apiResult, 'The stock data does not match.');
+        $this->assertEquals($result, array_intersect_key($apiResult, $result), 'The stock data does not match.');
         return $apiResult;
     }
 
@@ -140,7 +140,7 @@ class StockItemTest extends WebapiAbstract
         $stockItemResource = $this->objectManager->get('Magento\CatalogInventory\Model\Resource\Stock\Item');
         $stockItemResource->loadByProductId($stockItem, $stockItemOld['product_id'], $stockItemOld['website_id']);
         $expectedResult['item_id'] = $stockItem->getItemId();
-        $this->assertEquals($expectedResult, $stockItem->getData());
+        $this->assertEquals($expectedResult, array_intersect_key($stockItem->getData(), $expectedResult));
     }
 
     /**
@@ -234,7 +234,7 @@ class StockItemTest extends WebapiAbstract
                     'manage_stock' => 1,
                     'low_stock_date' => '',
                     'is_decimal_divided' => '',
-                    'stock_status_changed_auto' => 0
+                    'stock_status_changed_auto' => 0,
                 ],
             ],
         ];
diff --git a/dev/tests/api-functional/testsuite/Magento/GroupedProduct/Api/ProductLinkManagementTest.php b/dev/tests/api-functional/testsuite/Magento/GroupedProduct/Api/ProductLinkManagementTest.php
index 88160057b07004339713b92e36d1fc93be910cae..5522d62bd0259d260e6d7132f641bfedda6cbeca 100644
--- a/dev/tests/api-functional/testsuite/Magento/GroupedProduct/Api/ProductLinkManagementTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/GroupedProduct/Api/ProductLinkManagementTest.php
@@ -6,6 +6,9 @@
  */
 namespace Magento\GroupedProduct\Api;
 
+/**
+ * @magentoAppIsolation enabled
+ */
 class ProductLinkManagementTest extends \Magento\TestFramework\TestCase\WebapiAbstract
 {
     const SERVICE_NAME = 'catalogProductLinkManagementV1';
diff --git a/dev/tests/api-functional/testsuite/Magento/GroupedProduct/Api/ProductRepositoryInterfaceTest.php b/dev/tests/api-functional/testsuite/Magento/GroupedProduct/Api/ProductRepositoryInterfaceTest.php
index 8adffb82f70547d69249fde8e57dcfcce1643a13..f4a8bab17e58d6f475677c6bdb70c062b478502d 100644
--- a/dev/tests/api-functional/testsuite/Magento/GroupedProduct/Api/ProductRepositoryInterfaceTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/GroupedProduct/Api/ProductRepositoryInterfaceTest.php
@@ -6,6 +6,7 @@
 namespace Magento\GroupedProduct\Api;
 
 use Magento\Catalog\Api\Data\ProductInterface;
+use Magento\CatalogInventory\Api\Data\StockItemInterface;
 use Magento\TestFramework\TestCase\WebapiAbstract;
 
 class ProductRepositoryInterfaceTest extends WebapiAbstract
@@ -126,6 +127,9 @@ class ProductRepositoryInterfaceTest extends WebapiAbstract
             ProductInterface::STATUS => 1,
             ProductInterface::TYPE_ID => 'simple',
             ProductInterface::ATTRIBUTE_SET_ID => 4,
+            ProductInterface::EXTENSION_ATTRIBUTES_KEY => [
+                'stock_item' => $this->getStockItemData()
+            ]
         ];
 
         $this->saveProduct($productData);
@@ -200,4 +204,36 @@ class ProductRepositoryInterfaceTest extends WebapiAbstract
         $this->deleteProduct("product_simple_500");
         $this->deleteProduct("group_product_500");
     }
+
+    /**
+     * @return array
+     */
+    private function getStockItemData()
+    {
+        return [
+            StockItemInterface::IS_IN_STOCK => 1,
+            StockItemInterface::QTY => 100500,
+            StockItemInterface::IS_QTY_DECIMAL => 1,
+            StockItemInterface::SHOW_DEFAULT_NOTIFICATION_MESSAGE => 0,
+            StockItemInterface::USE_CONFIG_MIN_QTY => 0,
+            StockItemInterface::USE_CONFIG_MIN_SALE_QTY => 0,
+            StockItemInterface::MIN_QTY => 1,
+            StockItemInterface::MIN_SALE_QTY => 1,
+            StockItemInterface::MAX_SALE_QTY => 100,
+            StockItemInterface::USE_CONFIG_MAX_SALE_QTY => 0,
+            StockItemInterface::USE_CONFIG_BACKORDERS => 0,
+            StockItemInterface::BACKORDERS => 0,
+            StockItemInterface::USE_CONFIG_NOTIFY_STOCK_QTY => 0,
+            StockItemInterface::NOTIFY_STOCK_QTY => 0,
+            StockItemInterface::USE_CONFIG_QTY_INCREMENTS => 0,
+            StockItemInterface::QTY_INCREMENTS => 0,
+            StockItemInterface::USE_CONFIG_ENABLE_QTY_INC => 0,
+            StockItemInterface::ENABLE_QTY_INCREMENTS => 0,
+            StockItemInterface::USE_CONFIG_MANAGE_STOCK => 1,
+            StockItemInterface::MANAGE_STOCK => 1,
+            StockItemInterface::LOW_STOCK_DATE => null,
+            StockItemInterface::IS_DECIMAL_DIVIDED => 0,
+            StockItemInterface::STOCK_STATUS_CHANGED_AUTO => 0,
+        ];
+    }
 }
diff --git a/dev/tests/functional/composer.json b/dev/tests/functional/composer.json
index 1287f8a2f00f08d893cd3171baa9cb44eefa72bf..6514ced02709b700ad494d85a0b8dced6a798737 100644
--- a/dev/tests/functional/composer.json
+++ b/dev/tests/functional/composer.json
@@ -1,6 +1,6 @@
 {
     "require": {
-        "magento/mtf": "1.0.0-rc32",
+        "magento/mtf": "1.0.0-rc33",
         "php": "~5.5.0|~5.6.0|~7.0.0",
         "phpunit/phpunit": "4.1.0",
         "phpunit/phpunit-selenium": ">=1.2"
diff --git a/dev/tests/functional/phpunit.xml.dist b/dev/tests/functional/phpunit.xml.dist
index ec1748e20b13556da45e875c29870dcdd70f72b1..f5f293ffa39f5099974a754655166834d26eb9a2 100644
--- a/dev/tests/functional/phpunit.xml.dist
+++ b/dev/tests/functional/phpunit.xml.dist
@@ -38,6 +38,7 @@
         <env name="module_whitelist" value="Magento_Install" />
         <env name="basedir" value="var/log" />
         <env name="credentials_file_path" value="./credentials.xml.dist" />
+        <env name="mage_mode" value="developer" />
     </php>
 
 </phpunit>
diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Block/Cache/Additional.php b/dev/tests/functional/tests/app/Magento/Backend/Test/Block/Cache/Additional.php
index 30f7194a98fe6ee74c2949c5adad9df2bf472160..605afd986421b6a62248c9c0719f59fd47d41402 100644
--- a/dev/tests/functional/tests/app/Magento/Backend/Test/Block/Cache/Additional.php
+++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Block/Cache/Additional.php
@@ -31,4 +31,16 @@ class Additional extends Block
     {
         $this->_rootElement->find(sprintf($this->flushButton, $flushButtonName), Locator::SELECTOR_XPATH)->click();
     }
+
+    /**
+     * Check if button is visible in 'Additional Cache Management'.
+     *
+     * @param string $flushButtonName
+     * @return bool
+     */
+    public function isFlushCacheButtonVisible($flushButtonName)
+    {
+        return $this->_rootElement->find(sprintf($this->flushButton, $flushButtonName), Locator::SELECTOR_XPATH)
+            ->isVisible();
+    }
 }
diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertCacheFlushStaticFilesInProductionMode.php b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertCacheFlushStaticFilesInProductionMode.php
new file mode 100644
index 0000000000000000000000000000000000000000..dce65ed1bc54ab6d74b46962809f9a40c85e7681
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertCacheFlushStaticFilesInProductionMode.php
@@ -0,0 +1,42 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Backend\Test\Constraint;
+
+use Magento\Backend\Test\Page\Adminhtml\AdminCache;
+use Magento\Mtf\Constraint\AbstractConstraint;
+
+/**
+ * Assert Flush Static Files Cache button not visible in production mode.
+ */
+class AssertCacheFlushStaticFilesInProductionMode extends AbstractConstraint
+{
+    const FLUSH_STATIC_FILES_CACHE = 'Flush Static Files Cache';
+
+    /**
+     * Assert Flush Static Files Cache button not visible in production mode.
+     *
+     * @param AdminCache $adminCache
+     * @return void
+     */
+    public function processAssert(AdminCache $adminCache)
+    {
+        \PHPUnit_Framework_Assert::assertFalse(
+            $adminCache->getAdditionalBlock()->isFlushCacheButtonVisible(self::FLUSH_STATIC_FILES_CACHE),
+            self::FLUSH_STATIC_FILES_CACHE . ' button should not be visible in production mode.'
+        );
+    }
+
+    /**
+     * Returns a string representation of the object.
+     *
+     * @return string
+     */
+    public function toString()
+    {
+        return self::FLUSH_STATIC_FILES_CACHE . ' button is not visible in production mode.';
+    }
+}
diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertCacheManagementAction.php b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertCacheManagementAction.php
index 30e7a986ba8e8f361f0d7d75517053777a5156e5..5ca1e4e677bbf7f3fa1ecf19f25114a19e547a2e 100644
--- a/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertCacheManagementAction.php
+++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertCacheManagementAction.php
@@ -6,7 +6,6 @@
 
 namespace Magento\Backend\Test\Constraint;
 
-use Magento\Backend\Test\Fixture\GlobalSearch;
 use Magento\Backend\Test\Page\Adminhtml\AdminCache;
 use Magento\Mtf\Constraint\AbstractConstraint;
 
@@ -16,7 +15,7 @@ use Magento\Mtf\Constraint\AbstractConstraint;
 class AssertCacheManagementAction extends AbstractConstraint
 {
     /**
-     * Assert that backend page has correct title and 404 Error is absent on the page.
+     * Assert success message for cache flush.
      *
      * @param AdminCache $adminCache
      * @param string $successMessage
diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/CacheFlushStaticFilesInProductionModeTest.php b/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/CacheFlushStaticFilesInProductionModeTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..9777614e554e1c5eee2a6b6538a84ff00f62bfa7
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/CacheFlushStaticFilesInProductionModeTest.php
@@ -0,0 +1,50 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Backend\Test\TestCase;
+
+use Magento\Mtf\TestCase\Injectable;
+use Magento\Backend\Test\Page\Adminhtml\AdminCache;
+
+/**
+ * Steps:
+ * 1. Log in to backend.
+ * 2. Navigate through menu to cache management page.
+ * 3. Perform asserts.
+ *
+ * @ZephyrId MAGETWO-39934
+ */
+class CacheFlushStaticFilesInProductionModeTest extends Injectable
+{
+    /* tags */
+    const MVP = 'no';
+    const DOMAIN = 'PS';
+    /* end tags */
+
+    /**
+     * Test only for 'Flush Static Files Cache' in production mode.
+     *
+     * @return void
+     */
+    public function __prepare()
+    {
+        if ($_ENV['mage_mode'] !== 'production') {
+            $this->markTestSkipped('Skip "Flush Static Files Cache" button absence test when not in production mode.');
+        }
+    }
+
+    /**
+     * Check 'Flush Static Files Cache' not visible in production mode.
+     *
+     *
+     * @param AdminCache $adminCache
+     * @return void
+     */
+    public function test(AdminCache $adminCache)
+    {
+        $adminCache->open();
+    }
+}
diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/CacheFlushStaticFilesInProductionModeTest.xml b/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/CacheFlushStaticFilesInProductionModeTest.xml
new file mode 100644
index 0000000000000000000000000000000000000000..7417721c749fb1f6accd5cda5c98375500a4e15c
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/CacheFlushStaticFilesInProductionModeTest.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+ -->
+<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/etc/variations.xsd">
+    <testCase name="Magento\Backend\Test\TestCase\CacheFlushStaticFilesInProductionModeTest" summary="Flush Static Files Cache button not in production mode" ticketId="MAGETWO-39934">
+        <variation name="FlushStaticFilesCacheInProductionTest">
+            <constraint name="Magento\Backend\Test\Constraint\AssertCacheFlushStaticFilesInProductionMode" />
+        </variation>
+    </testCase>
+</config>
diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/CacheManagementTest.php b/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/CacheManagementTest.php
index 6817abe742c6d4917f8b80963f67df4d06b75e50..c25b3d8922e9f6f2e6c265ad00650634a7fdb779 100644
--- a/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/CacheManagementTest.php
+++ b/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/CacheManagementTest.php
@@ -12,11 +12,11 @@ use Magento\Backend\Test\Page\Adminhtml\AdminCache;
 /**
  * Steps:
  * 1. Log in to backend.
- * 2. Navigate throught menu to cache management page.
+ * 2. Navigate through menu to cache management page.
  * 3. Click a button.
  * 4. Perform asserts.
  *
- * @ZephyrId MAGETWO-34502, MAGETWO-34503, MAGETWO-39934
+ * @ZephyrId MAGETWO-34052, MAGETWO-34053, MAGETWO-39934
  */
 class CacheManagementTest extends Injectable
 {
@@ -26,7 +26,7 @@ class CacheManagementTest extends Injectable
     /* end tags */
 
     /**
-     * Open admin cache management page.
+     * Open admin cache management page and click button to flush cache.
      *
      * @param AdminCache $adminCache
      * @param string $flushButtonName
@@ -34,6 +34,12 @@ class CacheManagementTest extends Injectable
      */
     public function test(AdminCache $adminCache, $flushButtonName)
     {
+        /**
+         * Skip test for 'Flush Static Files Cache' in production mode.
+         */
+        if (($flushButtonName === 'Flush Static Files Cache') && $_ENV['mage_mode'] === 'production') {
+            $this->markTestSkipped('Skip flushing static files cache test when in production mode.');
+        }
         $adminCache->open();
         $adminCache->getAdditionalBlock()->clickFlushCache($flushButtonName);
     }
diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/CacheManagementTest.xml b/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/CacheManagementTest.xml
index e970b3f71fa5484226e5c222e599bce7f4dd00f8..f575bedde68835011423a03a3e9ffa5af0683607 100644
--- a/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/CacheManagementTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/CacheManagementTest.xml
@@ -6,7 +6,7 @@
  */
  -->
 <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/etc/variations.xsd">
-    <testCase name="Magento\Backend\Test\TestCase\CacheManagementTest" summary="Configuration option on backend for singleQuery mode" ticketId="MAGETWO-34502">
+    <testCase name="Magento\Backend\Test\TestCase\CacheManagementTest" summary="Additional Cache Management" ticketId="MAGETWO-34052">
         <variation name="FlushCatalogImagesCacheTest">
             <data name="flushButtonName" xsi:type="string">Flush Catalog Images Cache</data>
             <data name="successMessage" xsi:type="string">The image cache was cleaned.</data>
diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/NavigateMenuTest.php b/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/NavigateMenuTest.php
index 2e4509a1e66eab3cb43acfd0a9f0407c7bf50ffc..332f6e6dbb2ca40725b7d638445eda2f74bc4aae 100644
--- a/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/NavigateMenuTest.php
+++ b/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/NavigateMenuTest.php
@@ -12,7 +12,7 @@ use Magento\Backend\Test\Page\Adminhtml\Dashboard;
 /**
  * Steps:
  * 1. Log in to backend.
- * 2. Navigate throught menu to the page.
+ * 2. Navigate through menu to the page.
  * 3. Perform asserts.
  *
  * @ZephyrId MAGETWO-34874
diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View/Type/Bundle.php b/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View/Type/Bundle.php
index 696395534ddaa2f185490278de90689416efbe80..90e586768e40c27e697f32984fcf908b03730d97 100644
--- a/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View/Type/Bundle.php
+++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View/Type/Bundle.php
@@ -243,7 +243,7 @@ class Bundle extends Block
      */
     protected function parseOptionText($optionText)
     {
-        preg_match('`^(.*?)\+ ?\$(\d.*?)$`', $optionText, $match);
+        preg_match('`^(.*?)\+ ?\$(\d.*?)$`sim', $optionText, $match);
         $optionPrice = isset($match[2]) ? str_replace(',', '', $match[2]) : 0;
         $optionTitle = isset($match[1]) ? trim($match[1]) : $optionText;
 
diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Links/CompareLink.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Links/CompareLink.php
new file mode 100644
index 0000000000000000000000000000000000000000..6be91bbcecd43e037e2387a2029f2e8f26282e1a
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Links/CompareLink.php
@@ -0,0 +1,35 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Catalog\Test\Block\Links;
+
+use Magento\Mtf\Block\Block;
+
+/**
+ * Products compare link block.
+ */
+class CompareLink extends Block
+{
+    /**
+     * Locator value for qty of Products in Compare list.
+     *
+     * @var string
+     */
+    protected $qtyCompareProducts = '.compare .counter.qty';
+
+    /**
+     * Get qty of Products in Compare list.
+     *
+     * @return string
+     */
+    public function getQtyInCompareList()
+    {
+        $this->waitForElementVisible($this->qtyCompareProducts);
+        $compareProductLink = $this->_rootElement->find($this->qtyCompareProducts);
+        preg_match_all('/^\d+/', $compareProductLink->getText(), $matches);
+        return $matches[0][0];
+    }
+}
diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Search.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Search.php
index dd2265411c098a6e4998c25ffde26a82e069e61e..72b8853c3ad809dec0245ce6863d6d25e561c15f 100644
--- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Search.php
+++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Search.php
@@ -11,54 +11,47 @@ use Magento\Mtf\Client\Locator;
 
 /**
  * Class Search
- * Block for search field
+ * Block for "Search" section
  */
 class Search extends Block
 {
     /**
-     * Selector matches found - "Suggest Search"
+     * Locator value for matches found - "Suggest Search".
      *
      * @var string
      */
     protected $searchAutocomplete = './/div[@id="search_autocomplete"]//li[span[text()[normalize-space()="%s"]]]';
 
     /**
-     * Selector number of matches for a given row
+     * Locator value for given row matches amount.
      *
      * @var string
      */
     protected $searchItemAmount = '/span[contains(@class,"amount") and text()="%d"]';
 
     /**
-     * Search field
+     * Locator value for "Search" field.
      *
      * @var string
      */
     protected $searchInput = '#search';
 
     /**
-     * Search button
+     * Locator value for "Search" button.
      *
      * @var string
      */
     private $searchButton = '[title="Search"]';
 
     /**
-     * Search button
+     * Locator value for "Search" button placeholder.
      *
      * @var string
      */
     protected $placeholder = '//input[@id="search" and contains(@placeholder, "%s")]';
 
     /**
-     * Css selector advanced search button
-     *
-     * @var string
-     */
-    protected $advancedSearchSelector = '.action.advanced';
-
-    /**
-     * Search products by a keyword
+     * Perform search by a keyword.
      *
      * @param string $keyword
      * @return void
@@ -68,37 +61,34 @@ class Search extends Block
     public function search($keyword)
     {
         $this->fillSearch($keyword);
-        $this->_rootElement->find($this->searchButton, Locator::SELECTOR_CSS)->click();
+        $this->_rootElement->find($this->searchButton)->click();
     }
 
     /**
-     * Fills the search field
+     * Fill "Search" field with correspondent text.
      *
      * @param string $text
      * @return void
      */
     public function fillSearch($text)
     {
-        $this->_rootElement->find($this->searchInput, Locator::SELECTOR_CSS)->setValue($text);
+        $this->_rootElement->find($this->searchInput)->setValue($text);
     }
 
     /**
-     * Check that placeholder contains text
+     * Check if placeholder contains correspondent text or not.
      *
      * @param string $placeholderText
      * @return bool
      */
     public function isPlaceholderContains($placeholderText)
     {
-        $field = $this->_rootElement->find(
-            sprintf($this->placeholder, $placeholderText),
-            Locator::SELECTOR_XPATH
-        );
+        $field = $this->_rootElement->find(sprintf($this->placeholder, $placeholderText), Locator::SELECTOR_XPATH);
         return $field->isVisible();
     }
 
     /**
-     * Checking block visibility "Suggest Search"
+     * Check if "Suggest Search" block visible or not.
      *
      * @param string $text
      * @param int|null $amount
@@ -118,14 +108,4 @@ class Search extends Block
             }
         );
     }
-
-    /**
-     * Click advanced search button
-     *
-     * @return void
-     */
-    public function clickAdvancedSearchButton()
-    {
-        $this->_rootElement->find($this->advancedSearchSelector)->click();
-    }
 }
diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeIsFilterable.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeIsFilterable.php
index 1f355049a172ea7b076feb749db30b33bb33fa64..3314878854c52bcd8eeae25bc1b1b17e88656753 100644
--- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeIsFilterable.php
+++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeIsFilterable.php
@@ -53,7 +53,7 @@ class AssertProductAttributeIsFilterable extends AbstractConstraint
             ? $attribute->getManageFrontendLabel()
             : $attribute->getFrontendLabel();
         \PHPUnit_Framework_Assert::assertTrue(
-            in_array($label, $catalogCategoryView->getLayeredNavigationBlock()->getFilters()),
+            in_array(strtoupper($label), $catalogCategoryView->getLayeredNavigationBlock()->getFilters()),
             'Attribute is absent in layered navigation on category page.'
         );
     }
diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeIsFilterableInSearch.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeIsFilterableInSearch.php
index a19a5f881b4373848827007b190329c8eb58731f..8e3b69699f827127448d04610653bafb8dbf83b4 100644
--- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeIsFilterableInSearch.php
+++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeIsFilterableInSearch.php
@@ -37,7 +37,7 @@ class AssertProductAttributeIsFilterableInSearch extends AbstractConstraint
             ? $attribute->getManageFrontendLabel()
             : $attribute->getFrontendLabel();
         \PHPUnit_Framework_Assert::assertTrue(
-            in_array($label, $catalogCategoryView->getLayeredNavigationBlock()->getFilters()),
+            in_array(strtoupper($label), $catalogCategoryView->getLayeredNavigationBlock()->getFilters()),
             'Attribute is absent in layered navigation on search page.'
         );
     }
diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductCompareItemsLink.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductCompareItemsLink.php
index 9dd4d24c9df1570a95297dae6c03fe46d2e3ffd8..b511bcd8968fbe8fd8c45c05f51a4b6c9aa1bc9a 100644
--- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductCompareItemsLink.php
+++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductCompareItemsLink.php
@@ -24,7 +24,7 @@ class AssertProductCompareItemsLink extends AbstractConstraint
     public function processAssert(array $products, CmsIndex $cmsIndex)
     {
         $productQty = count($products);
-        $qtyOnPage = $cmsIndex->getLinksBlock()->getQtyInCompareList();
+        $qtyOnPage = $cmsIndex->getCompareLinkBlock()->getQtyInCompareList();
 
         \PHPUnit_Framework_Assert::assertEquals(
             $productQty,
diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Page/CmsIndex.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Page/CmsIndex.xml
new file mode 100644
index 0000000000000000000000000000000000000000..c820d9985e3210b6dd8f70bbaf49db0de3cc7625
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Page/CmsIndex.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+ -->
+<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/etc/pages.xsd">
+    <page name="CmsIndex" mca="cms/index/index">
+        <block name="compareProductsBlock" class="Magento\Catalog\Test\Block\Product\Compare\Sidebar" locator=".sidebar.sidebar-additional" strategy="css selector" />
+        <block name="compareLinkBlock" class="Magento\Catalog\Test\Block\Links\CompareLink" locator="[data-role='compare-products-link']" strategy="css selector" />
+    </page>
+</config>
diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/AbstractCompareProductsTest.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/AbstractCompareProductsTest.php
index e3940285daa737f105639664a6c4498075dd75a2..5fadf342d10eab9dbf5c643c6e745c225d99e54c 100644
--- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/AbstractCompareProductsTest.php
+++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/AbstractCompareProductsTest.php
@@ -10,7 +10,6 @@ use Magento\Catalog\Test\Page\Product\CatalogProductCompare;
 use Magento\Catalog\Test\Page\Product\CatalogProductView;
 use Magento\Cms\Test\Page\CmsIndex;
 use Magento\Customer\Test\Fixture\Customer;
-use Magento\Customer\Test\Page\CustomerAccountLogin;
 use Magento\Mtf\Client\BrowserInterface;
 use Magento\Mtf\Constraint\AbstractConstraint;
 use Magento\Mtf\Fixture\FixtureFactory;
@@ -59,13 +58,6 @@ abstract class AbstractCompareProductsTest extends Injectable
      */
     protected $catalogProductView;
 
-    /**
-     * Customer login page.
-     *
-     * @var CustomerAccountLogin
-     */
-    protected $customerAccountLogin;
-
     /**
      * Fixture factory.
      *
@@ -100,18 +92,15 @@ abstract class AbstractCompareProductsTest extends Injectable
      * @param CmsIndex $cmsIndex
      * @param CatalogProductView $catalogProductView
      * @param BrowserInterface $browser
-     * @param CustomerAccountLogin $customerAccountLogin
      * @return void
      */
     public function __inject(
         CmsIndex $cmsIndex,
         CatalogProductView $catalogProductView,
-        BrowserInterface $browser,
-        CustomerAccountLogin $customerAccountLogin
+        BrowserInterface $browser
     ) {
         $this->cmsIndex = $cmsIndex;
         $this->catalogProductView = $catalogProductView;
-        $this->customerAccountLogin = $customerAccountLogin;
         $this->browser = $browser;
     }
 
diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/AddCompareProductsTest.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/AddCompareProductsTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..dc239565c49d01471c82b5b1a62c17ae0244605e
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/AddCompareProductsTest.php
@@ -0,0 +1,83 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Catalog\Test\TestCase\Product;
+
+use Magento\Catalog\Test\Constraint\AssertProductCompareSuccessAddMessage;
+use Magento\Catalog\Test\Page\Product\CatalogProductCompare;
+
+/**
+ * Preconditions:
+ * 1. All product types are created.
+ * 2. Customer created.
+ *
+ * Steps:
+ * 1. Navigate to front-end.
+ * 1.1 If present data for customer, login as test customer.
+ * 2. Open product page of test product(s) and click "Add to Compare" button.
+ * 3. Assert success message is present on page.
+ * 4. Navigate to compare page(click "compare product" link at the top of the page).
+ * 5. Perform all asserts.
+ *
+ * @group Compare_Products_(MX)
+ * @ZephyrId MAGETWO-25843
+ */
+class AddCompareProductsTest extends AbstractCompareProductsTest
+{
+    /* tags */
+    const MVP = 'yes';
+    const DOMAIN = 'MX';
+    /* end tags */
+
+    /**
+     * Catalog product compare page.
+     *
+     * @var CatalogProductCompare
+     */
+    protected $catalogProductCompare;
+
+    /**
+     * Test creation for adding compare products.
+     *
+     * @param string $products
+     * @param string $requireCustomerLogin
+     * @param AssertProductCompareSuccessAddMessage $assertProductCompareSuccessAddMessage
+     * @param CatalogProductCompare $catalogProductCompare
+     * @return array
+     */
+    public function test(
+        $products,
+        $requireCustomerLogin,
+        AssertProductCompareSuccessAddMessage $assertProductCompareSuccessAddMessage,
+        CatalogProductCompare $catalogProductCompare
+    ) {
+        //Steps
+        $this->catalogProductCompare = $catalogProductCompare;
+        $this->cmsIndex->open();
+        if ($requireCustomerLogin == 'Yes') {
+            $this->loginCustomer();
+        }
+        $this->products = $this->createProducts($products);
+        $this->addProducts($this->products, $assertProductCompareSuccessAddMessage);
+        $this->cmsIndex->getLinksBlock()->openLink("Compare Products");
+
+        return ['products' => $this->products];
+    }
+
+    /**
+     * Clear data after test.
+     *
+     * @return void
+     */
+    public function tearDown()
+    {
+        $this->cmsIndex->open();
+        $this->cmsIndex->getLinksBlock()->openLink("Compare Products");
+        for ($i = 1; $i <= count($this->products); $i++) {
+            $this->catalogProductCompare->getCompareProductsBlock()->removeProduct();
+        }
+    }
+}
diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/AddCompareProductsTest.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/AddCompareProductsTest.xml
new file mode 100644
index 0000000000000000000000000000000000000000..de2da8b34bbf2b06162b4a41f0ea30a95d571dbb
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/AddCompareProductsTest.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+ -->
+<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../vendor/magento/mtf/etc/variations.xsd">
+    <testCase name="Magento\Catalog\Test\TestCase\Product\AddCompareProductsTest" summary="Add Products to Compare" ticketId="MAGETWO-25843">
+        <variation name="AddCompareProductsTestVariation1">
+            <data name="products" xsi:type="string">catalogProductSimple::simple_for_composite_products</data>
+            <data name="requireCustomerLogin" xsi:type="string">No</data>
+            <constraint name="Magento\Catalog\Test\Constraint\AssertProductCompareItemsLink" />
+            <constraint name="Magento\Catalog\Test\Constraint\AssertProductComparePage" />
+            <constraint name="Magento\Catalog\Test\Constraint\AssertProductCompareBlockOnCmsPage" />
+        </variation>
+        <variation name="AddCompareProductsTestVariation2">
+            <data name="products" xsi:type="string">catalogProductSimple::simple_for_composite_products,bundleProduct::bundle_dynamic_product</data>
+            <data name="requireCustomerLogin" xsi:type="string">No</data>
+            <constraint name="Magento\Catalog\Test\Constraint\AssertProductCompareItemsLink" />
+            <constraint name="Magento\Catalog\Test\Constraint\AssertProductComparePage" />
+        </variation>
+        <variation name="AddCompareProductsTestVariation3">
+            <data name="products" xsi:type="string">configurableProduct::default</data>
+            <data name="requireCustomerLogin" xsi:type="string">Yes</data>
+            <constraint name="Magento\Catalog\Test\Constraint\AssertProductCompareItemsLink" />
+            <constraint name="Magento\Catalog\Test\Constraint\AssertProductComparePage" />
+            <constraint name="Magento\Catalog\Test\Constraint\AssertProductCompareBlockOnCmsPage" />
+        </variation>
+        <variation name="AddCompareProductsTestVariation4">
+            <data name="products" xsi:type="string">catalogProductSimple::simple_for_composite_products,catalogProductVirtual::default,downloadableProduct::default,groupedProduct::grouped_product_with_price,configurableProduct::default,bundleProduct::bundle_dynamic_product,bundleProduct::bundle_fixed_product</data>
+            <data name="requireCustomerLogin" xsi:type="string">Yes</data>
+            <constraint name="Magento\Catalog\Test\Constraint\AssertProductCompareItemsLink" />
+            <constraint name="Magento\Catalog\Test\Constraint\AssertProductComparePage" />
+        </variation>
+    </testCase>
+</config>
diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ClearAllCompareProductsTest.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ClearAllCompareProductsTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..3556fa00a838820d65e20d642037d4260e344bc3
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ClearAllCompareProductsTest.php
@@ -0,0 +1,55 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Catalog\Test\TestCase\Product;
+
+use Magento\Config\Test\Fixture\ConfigData;
+use Magento\Customer\Test\Page\CustomerAccountIndex;
+
+/**
+ * Preconditions:
+ * 1. All product types are created.
+ * 2. Customer created.
+ *
+ * Steps:
+ * 1. Login to frontend.
+ * 2. Add to Compare Product $products.
+ * 3. Navigate to My Account page.
+ * 4. Click "Clear All" icon under the left menu tabs.
+ * 5. Perform assertions.
+ *
+ * @group Compare_Products_(MX)
+ * @ZephyrId MAGETWO-25961
+ */
+class ClearAllCompareProductsTest extends AbstractCompareProductsTest
+{
+    /* tags */
+    const MVP = 'yes';
+    const DOMAIN = 'MX';
+    /* end tags */
+
+    /**
+     * Test creation for clear all compare products.
+     *
+     * @param string $products
+     * @param ConfigData $config
+     * @param CustomerAccountIndex $customerAccountIndex
+     * @return void
+     */
+    public function test($products, ConfigData $config, CustomerAccountIndex $customerAccountIndex)
+    {
+        // Preconditions
+        $config->persist();
+        $products = $this->createProducts($products);
+
+        //Steps
+        $this->cmsIndex->open();
+        $this->loginCustomer();
+        $this->addProducts($products);
+        $this->cmsIndex->getLinksBlock()->openLink("My Account");
+        $customerAccountIndex->getCompareProductsBlock()->clickClearAll();
+    }
+}
diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ClearAllCompareProductsTest.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ClearAllCompareProductsTest.xml
new file mode 100644
index 0000000000000000000000000000000000000000..e9fa3f36b002f74ec2d77bc1b2a0b53fc6e611bd
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ClearAllCompareProductsTest.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+ -->
+<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../vendor/magento/mtf/etc/variations.xsd">
+    <testCase name="Magento\Catalog\Test\TestCase\Product\ClearAllCompareProductsTest" summary="Clear All Compare Products" ticketId="MAGETWO-25961">
+        <variation name="ClearAllCompareProductsTestVariation1">
+            <data name="config/dataset" xsi:type="string">compare_products</data>
+            <data name="products" xsi:type="string">catalogProductSimple::simple_for_composite_products,catalogProductVirtual::default,downloadableProduct::default,groupedProduct::grouped_product_with_price,configurableProduct::default,bundleProduct::bundle_dynamic_product,bundleProduct::bundle_fixed_product</data>
+            <constraint name="Magento\Catalog\Test\Constraint\AssertProductCompareSuccessRemoveAllProductsMessage" />
+            <constraint name="Magento\Catalog\Test\Constraint\AssertProductCompareItemsLinkIsAbsent" />
+            <constraint name="Magento\Catalog\Test\Constraint\AssertProductCompareRemoveLastProductMessage" />
+            <constraint name="Magento\Catalog\Test\Constraint\AssertProductIsNotVisibleInCompareBlock" />
+        </variation>
+    </testCase>
+</config>
diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/CreateVirtualProductEntityTest.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/CreateVirtualProductEntityTest.xml
index df25c659478dd74b2a51cf6310de409821728db5..eebe1b345306abff05d6cbf2be3babc694bc0a7c 100644
--- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/CreateVirtualProductEntityTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/CreateVirtualProductEntityTest.xml
@@ -40,16 +40,14 @@
             <data name="description" xsi:type="string">Create product with out of stock</data>
             <data name="product/data/url_key" xsi:type="string">virtual-product-%isolation%</data>
             <data name="product/data/name" xsi:type="string">VirtualProduct %isolation%</data>
-            <data name="product/data/sku" xsi:type="string">virtual_sku_%isolation%</data>
             <data name="product/data/price/value" xsi:type="string">10</data>
             <data name="product/data/tax_class_id/dataset" xsi:type="string">taxable_goods</data>
             <data name="product/data/quantity_and_stock_status/qty" xsi:type="string">999</data>
+            <data name="product/data/quantity_and_stock_status/is_in_stock" xsi:type="string">In Stock</data>
             <data name="product/data/is_virtual" xsi:type="string">Yes</data>
             <data name="product/data/price/dataset" xsi:type="string">MAGETWO-23030</data>
-            <data name="product/data/quantity_and_stock_status/is_in_stock" xsi:type="string">Out of Stock</data>
             <data name="product/data/visibility" xsi:type="string">Search</data>
             <constraint name="Magento\Catalog\Test\Constraint\AssertProductSaveMessage" />
-            <constraint name="Magento\Catalog\Test\Constraint\AssertProductForm" />
             <constraint name="Magento\Catalog\Test\Constraint\AssertProductSkuAutoGenerated" />
             <constraint name="Magento\Catalog\Test\Constraint\AssertProductSearchableBySku" />
         </variation>
diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/DeleteCompareProductsTest.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/DeleteCompareProductsTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..c4771496cc0883bd64a33cce1f967517ae23babd
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/DeleteCompareProductsTest.php
@@ -0,0 +1,97 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Catalog\Test\TestCase\Product;
+
+use Magento\Catalog\Test\Page\Product\CatalogProductCompare;
+use Magento\Customer\Test\Fixture\Customer;
+use Magento\Mtf\Fixture\FixtureFactory;
+
+/**
+ * Preconditions:
+ * 1. All product types are created.
+ * 2. Customer created.
+ *
+ * Steps:
+ * 1. Add to Compare Product $products.
+ * 2. Navigate to Compare Product page.
+ * 3. Click (X) icon near the $product from dataset.
+ * 4. Perform assertions.
+ *
+ * @group Compare_Products_(MX)
+ * @ZephyrId MAGETWO-26161
+ */
+class DeleteCompareProductsTest extends AbstractCompareProductsTest
+{
+    /* tags */
+    const MVP = 'yes';
+    const DOMAIN = 'MX';
+    /* end tags */
+
+    /**
+     * Catalog product compare page.
+     *
+     * @var CatalogProductCompare
+     */
+    protected $catalogProductCompare;
+
+    /**
+     * Prepare data.
+     *
+     * @param FixtureFactory $fixtureFactory
+     * @param Customer $customer
+     * @return void
+     */
+    public function __prepare(FixtureFactory $fixtureFactory, Customer $customer)
+    {
+        parent::__prepare($fixtureFactory, $customer);
+        $config = $this->fixtureFactory->createByCode('configData', ['dataset' => 'compare_products']);
+        $config->persist();
+    }
+
+    /**
+     * Test creation for delete product from compare products list.
+     *
+     * @param string $products
+     * @param string $removeProductIndex
+     * @param string $requireCustomerLogin
+     * @param CatalogProductCompare $catalogProductCompare
+     * @return array
+     */
+    public function test(
+        $products,
+        $removeProductIndex,
+        $requireCustomerLogin,
+        CatalogProductCompare $catalogProductCompare
+    ) {
+        //Steps
+        $this->catalogProductCompare = $catalogProductCompare;
+        $this->cmsIndex->open();
+        if ($requireCustomerLogin == 'Yes') {
+            $this->loginCustomer();
+        }
+        $this->products = $this->createProducts($products);
+        $this->addProducts($this->products);
+        $this->cmsIndex->getLinksBlock()->openLink("Compare Products");
+        $this->catalogProductCompare->getCompareProductsBlock()->removeProduct($removeProductIndex);
+
+        return ['product' => $this->products[$removeProductIndex - 1], 'countProducts' => count($this->products)];
+    }
+
+    /**
+     * Clear data after test.
+     *
+     * @return void
+     */
+    public function tearDown()
+    {
+        if (count($this->products) > 1) {
+            $this->cmsIndex->open();
+            $this->cmsIndex->getLinksBlock()->openLink("Compare Products");
+            $this->catalogProductCompare->getCompareProductsBlock()->removeAllProducts();
+        }
+    }
+}
diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/DeleteCompareProductsTest.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/DeleteCompareProductsTest.xml
new file mode 100644
index 0000000000000000000000000000000000000000..78a9e6af18713cfeb28a365f8926257bbc8b002c
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/DeleteCompareProductsTest.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+ -->
+<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../vendor/magento/mtf/etc/variations.xsd">
+    <testCase name="Magento\Catalog\Test\TestCase\Product\DeleteCompareProductsTest" summary="Delete Compare Products" ticketId="MAGETWO-26161">
+        <variation name="DeleteCompareProductsTestVariation1">
+            <data name="products" xsi:type="string">catalogProductSimple::simple_for_composite_products,catalogProductVirtual::default,downloadableProduct::default,groupedProduct::grouped_product_with_price,configurableProduct::default,bundleProduct::bundle_dynamic_product,bundleProduct::bundle_fixed_product</data>
+            <data name="removeProductIndex" xsi:type="string">1</data>
+            <data name="requireCustomerLogin" xsi:type="string">No</data>
+            <constraint name="Magento\Catalog\Test\Constraint\AssertProductCompareSuccessRemoveMessage" />
+            <constraint name="Magento\Catalog\Test\Constraint\AssertProductIsNotVisibleInComparePage" />
+        </variation>
+        <variation name="DeleteCompareProductsTestVariation2">
+            <data name="products" xsi:type="string">catalogProductSimple::simple_for_composite_products,catalogProductVirtual::default,downloadableProduct::default,groupedProduct::grouped_product_with_price,configurableProduct::default,bundleProduct::bundle_dynamic_product,bundleProduct::bundle_fixed_product</data>
+            <data name="removeProductIndex" xsi:type="string">6</data>
+            <data name="requireCustomerLogin" xsi:type="string">Yes</data>
+            <constraint name="Magento\Catalog\Test\Constraint\AssertProductCompareSuccessRemoveMessage" />
+            <constraint name="Magento\Catalog\Test\Constraint\AssertProductIsNotVisibleInComparePage" />
+            <constraint name="Magento\Catalog\Test\Constraint\AssertProductIsNotVisibleInCompareBlock" />
+        </variation>
+        <variation name="DeleteCompareProductsTestVariation3">
+            <data name="products" xsi:type="string">bundleProduct::bundle_dynamic_product</data>
+            <data name="removeProductIndex" xsi:type="string">1</data>
+            <data name="requireCustomerLogin" xsi:type="string">Yes</data>
+            <constraint name="Magento\Catalog\Test\Constraint\AssertProductCompareSuccessRemoveMessage" />
+            <constraint name="Magento\Catalog\Test\Constraint\AssertProductCompareRemoveLastProductMessage" />
+            <constraint name="Magento\Catalog\Test\Constraint\AssertProductIsNotVisibleInCompareBlock" />
+            <constraint name="Magento\Catalog\Test\Constraint\AssertProductCompareItemsLinkIsAbsent" />
+        </variation>
+    </testCase>
+</config>
diff --git a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/TestCase/AdvancedSearchEntityTest.php b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/TestCase/AdvancedSearchEntityTest.php
index 740497bffb148aea85ca2c32ffe264e9e33cc4e4..b2773dc7964231e523110427a6afac9a22920e1b 100644
--- a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/TestCase/AdvancedSearchEntityTest.php
+++ b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/TestCase/AdvancedSearchEntityTest.php
@@ -78,7 +78,7 @@ class AdvancedSearchEntityTest extends Injectable
         AdvancedSearch $searchPage
     ) {
         $cmsIndex->open();
-        $cmsIndex->getSearchBlock()->clickAdvancedSearchButton();
+        $cmsIndex->getFooterBlock()->openAdvancedSearch();
         $searchForm = $searchPage->getForm();
         $searchForm->fill($productSearch);
         $searchForm->submit();
diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Cart.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Cart.php
index 5d12b4575d9adc26f53cb67398eb84941db42375..22256fed04b100e1cf8f89ccc6f3f6b2ac850194 100644
--- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Cart.php
+++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Cart.php
@@ -16,13 +16,13 @@ use Magento\Mtf\Fixture\FixtureInterface;
 
 /**
  * Class Cart
- * Shopping cart block
+ * Shopping Cart block
  */
 class Cart extends Block
 {
     // @codingStandardsIgnoreStart
     /**
-     * Selector for cart item block
+     * Locator value for correspondent "Shopping Cart item" block.
      *
      * @var string
      */
@@ -30,42 +30,56 @@ class Cart extends Block
     // @codingStandardsIgnoreEnd
 
     /**
-     * Proceed to checkout block
+     * Locator value for "Proceed to One Page Checkout" block.
      *
      * @var string
      */
     protected $onepageLinkBlock = '.action.primary.checkout';
 
     /**
-     * 'Clear Shopping Cart' button
+     * Locator value for "Clear Shopping Cart" button.
      *
      * @var string
      */
     protected $clearShoppingCart = '#empty_cart_button';
 
     /**
-     * 'Update Shopping Cart' button
+     * Locator value for "Update Shopping Cart" button.
      *
      * @var string
      */
     protected $updateShoppingCart = '.update[name="update_cart_action"]';
 
     /**
-     * Cart empty block selector
+     * Locator value for "Check out with PayPal" button.
+     *
+     * @var string
+     */
+    protected $paypalCheckoutButton = '[data-action=checkout-form-submit]';
+
+    /**
+     * Locator value for "empty Shopping Cart" block.
      *
      * @var string
      */
     protected $cartEmpty = '.cart-empty';
 
     /**
-     * Cart container selector
+     * Locator value for "Shopping Cart" container.
      *
      * @var string
      */
     protected $cartContainer = '.cart-container';
 
     /**
-     * Get cart item block
+     * Locator value for "Remove Product" button.
+     *
+     * @var string
+     */
+    protected $deleteItemButton = '.action.action-delete';
+
+    /**
+     * Get Shopping Cart item.
      *
      * @param FixtureInterface $product
      * @return CartItem
@@ -93,7 +107,7 @@ class Cart extends Block
     }
 
     /**
-     * Get proceed to checkout block
+     * Get "Proceed to One Page Checkout" block.
      *
      * @return Link
      */
@@ -105,17 +119,17 @@ class Cart extends Block
     }
 
     /**
-     * Press 'Check out with PayPal' button
+     * Click "Check out with PayPal" button.
      *
      * @return void
      */
     public function paypalCheckout()
     {
-        $this->_rootElement->find('[data-action=checkout-form-submit]', Locator::SELECTOR_CSS)->click();
+        $this->_rootElement->find($this->paypalCheckoutButton)->click();
     }
 
     /**
-     * Returns the total discount price
+     * Get total discount Price value.
      *
      * @return string
      * @throws Exception
@@ -135,20 +149,19 @@ class Cart extends Block
     }
 
     /**
-     * Clear shopping cart
+     * Clear Shopping Cart.
      *
      * @return void
      */
     public function clearShoppingCart()
     {
-        $clearShoppingCart = $this->_rootElement->find($this->clearShoppingCart);
-        if ($clearShoppingCart->isVisible()) {
-            $clearShoppingCart->click();
+        while (!$this->cartIsEmpty()) {
+            $this->_rootElement->find($this->deleteItemButton)->click();
         }
     }
 
     /**
-     * Check if a product has been successfully added to the cart
+     * Check if Product is present in Shopping Cart or not.
      *
      * @param FixtureInterface $product
      * @return boolean
@@ -159,27 +172,29 @@ class Cart extends Block
     }
 
     /**
-     * Update shopping cart
+     * Update Shopping Cart.
      *
      * @return void
      */
     public function updateShoppingCart()
     {
-        $this->_rootElement->find($this->updateShoppingCart, Locator::SELECTOR_CSS)->click();
+        $this->_rootElement->find($this->updateShoppingCart)->click();
     }
 
     /**
-     * Check that cart is empty
+     * Check if Shopping Cart is empty or not.
      *
      * @return bool
      */
     public function cartIsEmpty()
     {
-        return $this->_rootElement->find($this->cartEmpty, Locator::SELECTOR_CSS)->isVisible();
+        return $this->_rootElement->find($this->cartEmpty)->isVisible();
     }
 
     /**
-     * Wait while cart container is loaded
+     * Wait while Shopping Cart container is loaded.
+     *
+     * @return void
      */
     public function waitCartContainerLoading()
     {
diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Cart/Sidebar.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Cart/Sidebar.php
index f0d771fff09c7378b78e9e647f1313c4e22ffb5c..04f4d4569f94a3ab3b44d6f0015d6c92d9848167 100644
--- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Cart/Sidebar.php
+++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Cart/Sidebar.php
@@ -58,18 +58,11 @@ class Sidebar extends Block
     protected $counterQty = '.minicart-wrapper .counter.qty';
 
     /**
-     * Count product in cart block.
+     * Locator value for Mini Shopping Cart wrapper.
      *
      * @var string
      */
-    protected $counterNumberBlock = '//*[@class="counter-number" and normalize-space(text()) != ""]';
-
-    /**
-     * Count product in cart wrapper.
-     *
-     * @var string
-     */
-    protected $counterNumberWrapper = '/ancestor::*[@class="minicart-wrapper"]';
+    protected $counterNumberWrapper = '.minicart-wrapper';
 
     /**
      * Loading masc.
@@ -157,10 +150,10 @@ class Sidebar extends Block
     public function waitInit()
     {
         $browser = $this->browser;
-        $selector = $this->counterNumberBlock . $this->counterNumberWrapper;
+        $selector = $this->counterNumberWrapper;
         $browser->waitUntil(
             function () use ($browser, $selector) {
-                $counterQty = $browser->find($selector, Locator::SELECTOR_XPATH);
+                $counterQty = $browser->find($selector);
                 return $counterQty->isVisible() ? true : null;
             }
         );
diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/AddProductsToShoppingCartEntityTest.xml b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/AddProductsToShoppingCartEntityTest.xml
index 9e388b13f7aade6faf292d3dbd5ef0f26ca789f0..69ab253de55c0f0b4b797b3eaf5c61488a57cf4d 100644
--- a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/AddProductsToShoppingCartEntityTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/AddProductsToShoppingCartEntityTest.xml
@@ -45,7 +45,7 @@
         </variation>
         <variation name="AddProductsToShoppingCartEntityTestVariation5">
             <data name="productsData" xsi:type="string">configurableProduct::default</data>
-            <data name="cart/data/grand_total" xsi:type="string">360</data>
+            <data name="cart/data/grand_total" xsi:type="string">120</data>
             <constraint name="Magento\Checkout\Test\Constraint\AssertPriceInShoppingCart" />
             <constraint name="Magento\Checkout\Test\Constraint\AssertProductQtyInShoppingCart" />
             <constraint name="Magento\Checkout\Test\Constraint\AssertSubtotalInShoppingCart" />
@@ -72,7 +72,7 @@
         </variation>
         <variation name="AddProductsToShoppingCartEntityTestVariation8">
             <data name="productsData" xsi:type="string">catalogProductSimple::with_two_custom_option, catalogProductVirtual::product_50_dollar, downloadableProduct::with_two_separately_links, groupedProduct::three_simple_products, configurableProduct::default, bundleProduct::bundle_dynamic_product, bundleProduct::bundle_dynamic_product</data>
-            <data name="cart/data/grand_total" xsi:type="string">3092.43</data>
+            <data name="cart/data/grand_total" xsi:type="string">2852.43</data>
             <constraint name="Magento\Checkout\Test\Constraint\AssertPriceInShoppingCart" />
             <constraint name="Magento\Checkout\Test\Constraint\AssertProductQtyInShoppingCart" />
             <constraint name="Magento\Checkout\Test\Constraint\AssertSubtotalInShoppingCart" />
diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/UpdateShoppingCartTest.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/UpdateShoppingCartTest.php
index 39951aa818cde6da5d54b8735e6a16bf044357a7..57963c6e28ce6e3696e0472b1e945d42a2b67bc3 100644
--- a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/UpdateShoppingCartTest.php
+++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/UpdateShoppingCartTest.php
@@ -102,6 +102,7 @@ class UpdateShoppingCartTest extends Injectable
     {
         // Preconditions
         $product->persist();
+        $this->checkoutCart->open();
         $this->checkoutCart->getCartBlock()->clearShoppingCart();
 
         // Steps
diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/Page/CmsIndex.xml b/dev/tests/functional/tests/app/Magento/Cms/Test/Page/CmsIndex.xml
index f6d62c1f0ffc7d482cd135ad9c94b095ba407d30..94be490f81adc65a229701a7794ae5747679b139 100644
--- a/dev/tests/functional/tests/app/Magento/Cms/Test/Page/CmsIndex.xml
+++ b/dev/tests/functional/tests/app/Magento/Cms/Test/Page/CmsIndex.xml
@@ -14,7 +14,6 @@
         <block name="linksBlock" class="Magento\Theme\Test\Block\Links" locator=".header .links" strategy="css selector" />
         <block name="storeSwitcherBlock" class="Magento\Store\Test\Block\Switcher" locator="[data-ui-id='language-switcher']" strategy="css selector" />
         <block name="cartSidebarBlock" class="Magento\Checkout\Test\Block\Cart\Sidebar" locator="[data-block='minicart']" strategy="css selector" />
-        <block name="compareProductsBlock" class="Magento\Catalog\Test\Block\Product\Compare\Sidebar" locator=".sidebar.sidebar-additional" strategy="css selector" />
         <block name="currencyBlock" class="Magento\Directory\Test\Block\Currency\Switcher" locator=".switcher.currency" strategy="css selector" />
         <block name="cmsPageBlock" class="Magento\Cms\Test\Block\Page" locator=".page-main" strategy="css selector" />
         <block name="widgetView" class="Magento\Widget\Test\Block\WidgetView" locator=".widget" strategy="css selector" />
diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigurableProduct/CheckoutData.xml b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigurableProduct/CheckoutData.xml
index 2579101e6dfd3a790e54d407ac965309a7436956..4f058ad0611c0f5eff12d181acb7607d920361a5 100644
--- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigurableProduct/CheckoutData.xml
+++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigurableProduct/CheckoutData.xml
@@ -22,9 +22,9 @@
             </field>
             <field name="qty" xsi:type="string">3</field>
             <field name="cartItem" xsi:type="array">
-                <item name="price" xsi:type="string">120</item>
+                <item name="price" xsi:type="string">40</item>
                 <item name="qty" xsi:type="string">3</item>
-                <item name="subtotal" xsi:type="string">360</item>
+                <item name="subtotal" xsi:type="string">120</item>
             </field>
         </dataset>
 
@@ -142,9 +142,9 @@
             </field>
             <field name="qty" xsi:type="string">1</field>
             <field name="cartItem" xsi:type="array">
-                <item name="price" xsi:type="string">9</item>
+                <item name="price" xsi:type="string">1</item>
                 <item name="qty" xsi:type="string">1</item>
-                <item name="subtotal" xsi:type="string">9</item>
+                <item name="subtotal" xsi:type="string">1</item>
             </field>
         </dataset>
 
diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/RegisterCustomerFrontendEntityTest.php b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/RegisterCustomerFrontendEntityTest.php
index fe690d7c18ca71cc0b370ae05952bbb7ae71a341..8d89091816aa5a217f385b50ce31bbd0fb205ac7 100644
--- a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/RegisterCustomerFrontendEntityTest.php
+++ b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/RegisterCustomerFrontendEntityTest.php
@@ -63,13 +63,13 @@ class RegisterCustomerFrontendEntityTest extends Injectable
     }
 
     /**
-     * Create Customer account on frontend
+     * Create Customer account on Storefront.
      *
      * @param Customer $customer
      */
     public function test(Customer $customer)
     {
-        //Steps
+        // Steps
         $this->cmsIndex->open();
         $this->cmsIndex->getLinksBlock()->openLink('Create an Account');
         $this->customerAccountCreate->getRegisterForm()->registerCustomer($customer);
diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/TestStep/LogoutCustomerOnFrontendStep.php b/dev/tests/functional/tests/app/Magento/Customer/Test/TestStep/LogoutCustomerOnFrontendStep.php
index 1ff30b1dcdf030fedef0e289d4b4d6c8076fc2f3..63399666bbc44a8ccd21371b6df5c5813bb2cf3e 100644
--- a/dev/tests/functional/tests/app/Magento/Customer/Test/TestStep/LogoutCustomerOnFrontendStep.php
+++ b/dev/tests/functional/tests/app/Magento/Customer/Test/TestStep/LogoutCustomerOnFrontendStep.php
@@ -54,7 +54,7 @@ class LogoutCustomerOnFrontendStep implements TestStepInterface
     {
         $this->customerAccount->open();
         $this->cmsIndex->getCmsPageBlock()->waitPageInit();
-        if ($this->cmsIndex->getLinksBlock()->isLinkVisible('Sign Out')) {
+        if ($this->cmsIndex->getTitleBlock()->getTitle() != 'Customer Login') {
             $this->cmsIndex->getLinksBlock()->openLink('Sign Out');
             $this->cmsIndex->getCmsPageBlock()->waitUntilTextIsVisible('Home Page');
             $this->cmsIndex->getCmsPageBlock()->waitPageInit();
diff --git a/dev/tests/functional/tests/app/Magento/Install/Test/Constraint/AssertLanguageSelected.php b/dev/tests/functional/tests/app/Magento/Install/Test/Constraint/AssertLanguageSelected.php
index e6de2178a4eeb04931bdebd038cf099513be41dd..100e32be0b442bb783891793ab88d2eb7725cda9 100644
--- a/dev/tests/functional/tests/app/Magento/Install/Test/Constraint/AssertLanguageSelected.php
+++ b/dev/tests/functional/tests/app/Magento/Install/Test/Constraint/AssertLanguageSelected.php
@@ -25,7 +25,7 @@ class AssertLanguageSelected extends AbstractConstraint
     {
         $indexPage->open();
         \PHPUnit_Framework_Assert::assertTrue(
-            $indexPage->getLinksBlock()->isLinkVisible($languageTemplate),
+            $indexPage->getFooterBlock()->isLinkVisible($languageTemplate),
             'Selected language not displays on frontend.'
         );
     }
diff --git a/dev/tests/functional/tests/app/Magento/LayeredNavigation/Test/Block/Navigation.php b/dev/tests/functional/tests/app/Magento/LayeredNavigation/Test/Block/Navigation.php
index 4dfa6dd2122c10aa6a7344210cd47d10985551c0..602316510e825dda680c14eb39eaff5f18a04f45 100644
--- a/dev/tests/functional/tests/app/Magento/LayeredNavigation/Test/Block/Navigation.php
+++ b/dev/tests/functional/tests/app/Magento/LayeredNavigation/Test/Block/Navigation.php
@@ -15,63 +15,76 @@ use Magento\Mtf\Client\Locator;
 class Navigation extends Block
 {
     /**
-     * 'Clear All' link.
+     * Locator value for "Clear All" link.
      *
      * @var string
      */
     protected $clearAll = '.action.clear';
 
     /**
-     * Attribute option title selector.
+     * Locator value for correspondent Attribute filter option.
      *
      * @var string
      */
-    protected $optionTitle = '.filter-options-title';
+    protected $optionTitle = './/div[@class="filter-options-title" and contains(text(),"%s")]';
 
     /**
-     * Filter link locator.
+     * Locator value for correspondent "Filter" link.
      *
      * @var string
      */
-    protected $filterLink = './/dt[contains(text(),"%s")]/following-sibling::dd//a';
+    protected $filterLink = './/div[@class="filter-options-title" and contains(text(),"%s")]/following-sibling::div//a';
 
     /**
-     * Click on 'Clear All' link.
+     * Locator value for "Expand Filter" button.
+     *
+     * @var string
+     */
+    protected $expandFilterButton = '[data]';
+
+    /**
+     * Remove all applied filters.
      *
      * @return void
      */
     public function clearAll()
     {
-        $this->_rootElement->find($this->clearAll, locator::SELECTOR_CSS)->click();
+        $this->_rootElement->find($this->clearAll)->click();
     }
 
     /**
-     * Get array of available filters.
+     * Get all available filters.
      *
      * @return array
      */
     public function getFilters()
     {
-        $options = $this->_rootElement->getElements($this->optionTitle);
+        $options = $this->_rootElement->getElements(sprintf($this->optionTitle, ''), Locator::SELECTOR_XPATH);
         $data = [];
         foreach ($options as $option) {
-            $data[] = $option->getText();
+            $data[] = strtoupper($option->getText());
         }
         return $data;
     }
 
     /**
-     * Click filter link.
+     * Apply Layerd Navigation filter.
      *
      * @param string $filter
      * @param string $linkPattern
      * @return void
      * @throws \Exception
      */
-    public function clickFilterLink($filter, $linkPattern)
+    public function applyFilter($filter, $linkPattern)
     {
-        $links = $this->_rootElement->getElements(sprintf($this->filterLink, $filter), Locator::SELECTOR_XPATH);
+        $expandFilterButton = sprintf($this->optionTitle, $filter);
+        $links = sprintf($this->filterLink, $filter);
+
+        if (!$this->_rootElement->find($links, Locator::SELECTOR_XPATH)->isVisible()) {
+            $this->_rootElement->find($expandFilterButton, Locator::SELECTOR_XPATH)->click();
+        }
 
+        $links = $this->_rootElement->getElements($links, Locator::SELECTOR_XPATH);
         foreach ($links as $link) {
             if (preg_match($linkPattern, trim($link->getText()))) {
                 $link->click();
diff --git a/dev/tests/functional/tests/app/Magento/LayeredNavigation/Test/Constraint/AssertFilterProductList.php b/dev/tests/functional/tests/app/Magento/LayeredNavigation/Test/Constraint/AssertFilterProductList.php
index e2b384a26611026f3c353fd7d8f7185ecab99143..9d840ff45dd61853c222e5b107f4ecc5febe5466 100644
--- a/dev/tests/functional/tests/app/Magento/LayeredNavigation/Test/Constraint/AssertFilterProductList.php
+++ b/dev/tests/functional/tests/app/Magento/LayeredNavigation/Test/Constraint/AssertFilterProductList.php
@@ -44,7 +44,7 @@ class AssertFilterProductList extends AbstractConstraint
 
         foreach ($layeredNavigation as $filters) {
             foreach ($filters as $filter) {
-                $catalogCategoryView->getLayeredNavigationBlock()->clickFilterLink(
+                $catalogCategoryView->getLayeredNavigationBlock()->applyFilter(
                     $filter['title'],
                     $filter['linkPattern']
                 );
diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/Tab/CreditMemos.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/Tab/CreditMemos.php
index 2ebb040791cdcecaa3a26ee06e26494ce04919ce..01a177c91ccad192574b772fd1ccda355d2ab285 100644
--- a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/Tab/CreditMemos.php
+++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/Tab/CreditMemos.php
@@ -10,20 +10,19 @@ use Magento\Backend\Test\Block\Widget\Tab;
 use Magento\Sales\Test\Block\Adminhtml\Order\View\Tab\CreditMemos\Grid;
 
 /**
- * Class CreditMemos
- * CreditMemos tab
+ * CreditMemos tab.
  */
 class CreditMemos extends Tab
 {
     /**
-     * Grid block css selector
+     * Grid block css selector.
      *
      * @var string
      */
     protected $grid = '#sales_order_view_tabs_order_creditmemos_content';
 
     /**
-     * Get grid block
+     * Get grid block.
      *
      * @return Grid
      */
diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/Tab/Shipments.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/Tab/Shipments.php
index 38b4e2344fd4b0701b29b9a519d8280090ca5155..9e5725bcf5c0582afbb0ec09fb460052d8cafcf6 100644
--- a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/Tab/Shipments.php
+++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/Tab/Shipments.php
@@ -10,20 +10,19 @@ use Magento\Backend\Test\Block\Widget\Tab;
 use Magento\Sales\Test\Block\Adminhtml\Order\View\Tab\Shipments\Grid;
 
 /**
- * Class Shipments
- * Shipments tab
+ * Shipments tab.
  */
 class Shipments extends Tab
 {
     /**
-     * Grid block css selector
+     * Grid block css selector.
      *
      * @var string
      */
     protected $grid = '#sales_order_view_tabs_order_shipments_content';
 
     /**
-     * Get grid block
+     * Get grid block.
      *
      * @return Grid
      */
diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/TestStep/PrintOrderOnFrontendStep.php b/dev/tests/functional/tests/app/Magento/Sales/Test/TestStep/PrintOrderOnFrontendStep.php
index a810a3ca608a2cd7927e12316d731b3b4ce47d4a..e520d538cc7570b669fe2d936fe783acc45d1e31 100644
--- a/dev/tests/functional/tests/app/Magento/Sales/Test/TestStep/PrintOrderOnFrontendStep.php
+++ b/dev/tests/functional/tests/app/Magento/Sales/Test/TestStep/PrintOrderOnFrontendStep.php
@@ -47,7 +47,7 @@ class PrintOrderOnFrontendStep implements TestStepInterface
      */
     public function run()
     {
-        $this->salesGuestView->getActionsToolbar()->clickLink('Print Order');
+        $this->salesGuestView->getActionsToolbar()->clickLink('Print');
         $this->browser->selectWindow();
     }
 }
diff --git a/dev/tests/functional/tests/app/Magento/Theme/Test/Block/Html/Footer.php b/dev/tests/functional/tests/app/Magento/Theme/Test/Block/Html/Footer.php
index 4781f506ae0c8482e49c7aaf1ab5113acb5c54c6..6af2b23db6f578deadf9942fa1221008d02c5f70 100644
--- a/dev/tests/functional/tests/app/Magento/Theme/Test/Block/Html/Footer.php
+++ b/dev/tests/functional/tests/app/Magento/Theme/Test/Block/Html/Footer.php
@@ -12,47 +12,54 @@ use Magento\Store\Test\Fixture\Store;
 
 /**
  * Footer block
- * CmsIndex page footer block
+ * CmsIndex page Footer block
  */
 class Footer extends Block
 {
     /**
-     * Link selector
+     * Locator value for correspondent link.
      *
      * @var string
      */
     protected $linkSelector = '//*[contains(@class, "links")]//a[contains(text(), "%s")]';
 
     /**
-     * Variable selector
+     * Locator value for variable.
      *
      * @var string
      */
     protected $variableSelector = './/ul[contains(@class, "links")]/*[text()="%s"]';
 
     /**
-     * Store group dropdown selector
+     * Locator value for "Store group" dropdown.
      *
      * @var string
      */
     protected $storeGroupDropdown = '.switcher.store';
 
     /**
-     * Store Group switch selector
+     * Locator value for "Store group" switcher.
      *
      * @var string
      */
     protected $storeGroupSwitch = '[data-toggle="dropdown"]';
 
     /**
-     * Store group selector
+     * Locator value for correspondent Store group.
      *
      * @var string
      */
     protected $storeGroupSelector = './/a[contains(.,"%s")]';
 
     /**
-     * Click on link by name
+     * Locator value for "Advanced Search" link.
+     *
+     * @var string
+     */
+    protected $advancedSearchSelector = '[data-action="advanced-search"]';
+
+    /**
+     * Click on link by its title.
      *
      * @param string $linkName
      * @return void
@@ -68,7 +75,18 @@ class Footer extends Block
     }
 
     /**
-     * Check Variable visibility by html value
+     * Check is link is visible.
+     *
+     * @param string $linkName
+     * @return bool
+     */
+    public function isLinkVisible($linkName)
+    {
+        return $this->_rootElement->find(sprintf($this->linkSelector, $linkName), Locator::SELECTOR_XPATH)->isVisible();
+    }
+
+    /**
+     * Check Variable visibility by html value.
      *
      * @param string $htmlValue
      * @return bool
@@ -82,7 +100,7 @@ class Footer extends Block
     }
 
     /**
-     * Select store group
+     * Select Store group.
      *
      * @param Store $store
      * @return void
@@ -102,7 +120,7 @@ class Footer extends Block
     }
 
     /**
-     * Check if store visible in dropdown
+     * Check if correspondent "Store" is present in "Store" swither or not.
      *
      * @param Store $store
      * @return bool
@@ -118,7 +136,7 @@ class Footer extends Block
     }
 
     /**
-     * Check if store group switcher is visible
+     * Check if "Store" switcher is visible or not.
      *
      * @return bool
      */
@@ -126,4 +144,14 @@ class Footer extends Block
     {
         return $this->_rootElement->find($this->storeGroupSwitch)->isVisible();
     }
+
+    /**
+     * Open Advanced Search.
+     *
+     * @return void
+     */
+    public function openAdvancedSearch()
+    {
+        $this->_rootElement->find($this->advancedSearchSelector)->click();
+    }
 }
diff --git a/dev/tests/functional/tests/app/Magento/Theme/Test/Block/Links.php b/dev/tests/functional/tests/app/Magento/Theme/Test/Block/Links.php
index 027b1ca6ec7fff352865e5d0a001e059f4044372..3375541068cb1264e5054958cc449dc7871bc8b9 100644
--- a/dev/tests/functional/tests/app/Magento/Theme/Test/Block/Links.php
+++ b/dev/tests/functional/tests/app/Magento/Theme/Test/Block/Links.php
@@ -15,50 +15,72 @@ use Magento\Mtf\Client\Locator;
 class Links extends Block
 {
     /**
-     * Selector for qty products on compare.
+     * Locator value for correspondent link.
      *
      * @var string
      */
-    protected $qtyCompareProducts = '.compare .counter.qty';
+    protected $link = '//a[contains(text(), "%s")]';
 
     /**
-     * Link selector.
+     * Locator value for welcome message.
      *
      * @var string
      */
-    protected $link = '//a[contains(text(), "%s")]';
+    protected $welcomeMessage = '.greet.welcome';
 
     /**
-     * Welcome message on frontend.
+     * Locator value for "Expand/Collapse Customer Menu" button.
      *
      * @var string
      */
-    protected $welcomeMessage = '.greet.welcome';
+    protected $toggleButton = '[data-action="customer-menu-toggle"]';
+
+    /**
+     * Locator value for Customer Menu.
+     *
+     * @var string
+     */
+    protected $customerMenu = '.customer-menu > ul';
 
     /**
-     * Open Link by title.
+     * Expand Customer Menu (located in page Header) if it was collapsed.
+     *
+     * @return void
+     */
+    protected function expandCustomerMenu()
+    {
+        $this->_rootElement->find($this->toggleButton)->click();
+    }
+
+    /**
+     * Open link by its title.
      *
      * @param string $linkTitle
      * @return void
      */
     public function openLink($linkTitle)
     {
-        $this->_rootElement->find(sprintf($this->link, $linkTitle), Locator::SELECTOR_XPATH)->click();
+        $link = $this->_rootElement->find(sprintf($this->link, $linkTitle), Locator::SELECTOR_XPATH);
+        if (!$link->isVisible()) {
+            $this->expandCustomerMenu();
+        }
+        $link->click();
     }
 
     /**
-     * Is visible Link by title.
+     * Verify if correspondent link is present or not.
      *
      * @param string $linkTitle
      * @return bool
      */
     public function isLinkVisible($linkTitle)
     {
+        $this->expandCustomerMenu();
         return $this->_rootElement->find(sprintf($this->link, $linkTitle), Locator::SELECTOR_XPATH)->isVisible();
     }
 
     /**
-     * Wait for link is visible.
+     * Wait until correspondent link appears.
      *
      * @param string $linkTitle
      * @return void
@@ -75,19 +97,6 @@ class Links extends Block
         );
     }
 
-    /**
-     * Get the number of products added to compare list.
-     *
-     * @return string
-     */
-    public function getQtyInCompareList()
-    {
-        $this->waitForElementVisible($this->qtyCompareProducts);
-        $compareProductLink = $this->_rootElement->find($this->qtyCompareProducts);
-        preg_match_all('/^\d+/', $compareProductLink->getText(), $matches);
-        return $matches[0][0];
-    }
-
     /**
      * Get url from link.
      *
@@ -103,7 +112,7 @@ class Links extends Block
     }
 
     /**
-     * Waiter for welcome message.
+     * Wait until welcome message appears.
      *
      * @return void
      */
diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetCatalogCategoryLink.php b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetCatalogCategoryLink.php
index e887766535ed3492f5838b291c96f8c8ce0f111a..a624d4f71de5f06a941703060b9d07e08e4a9885 100644
--- a/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetCatalogCategoryLink.php
+++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetCatalogCategoryLink.php
@@ -59,7 +59,7 @@ class AssertWidgetCatalogCategoryLink extends AbstractConstraint
             'Wrong category title.'
         );
 
-        $cmsIndex->getSearchBlock()->clickAdvancedSearchButton();
+        $cmsIndex->getFooterBlock()->openAdvancedSearch();
         \PHPUnit_Framework_Assert::assertTrue(
             $cmsIndex->getWidgetView()->isWidgetVisible($widget, $widgetText),
             'Widget with type catalog category link is absent on Advanced Search page.'
diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetCmsPageLink.php b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetCmsPageLink.php
index 3cce4ea17193c0e3e17694a1f1062b8a4dfe0c4a..8d3170aebc9046cde9879841275c062b75b8f646 100644
--- a/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetCmsPageLink.php
+++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetCmsPageLink.php
@@ -54,7 +54,7 @@ class AssertWidgetCmsPageLink extends AbstractConstraint
             'Wrong page title on Cms page.'
         );
 
-        $cmsIndex->getSearchBlock()->clickAdvancedSearchButton();
+        $cmsIndex->getFooterBlock()->openAdvancedSearch();
         \PHPUnit_Framework_Assert::assertTrue(
             $cmsIndex->getWidgetView()->isWidgetVisible($widget, $widgetText),
             'Widget with type CmsPageLink is absent on Advanced Search page.'
diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Repository/Widget.xml b/dev/tests/functional/tests/app/Magento/Widget/Test/Repository/Widget.xml
index c7c75cfb643531869c405862af0b92733dca5b56..a43376e87102219babd18a568469a8c36bd3526a 100644
--- a/dev/tests/functional/tests/app/Magento/Widget/Test/Repository/Widget.xml
+++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Repository/Widget.xml
@@ -10,7 +10,7 @@
         <dataset name="default">
             <field name="code" xsi:type="string">CMS Page Link</field>
             <field name="title" xsi:type="string">Cms Page Link %isolation%</field>
-            <field name="theme_id" xsi:type="string">Magento Blank</field>
+            <field name="theme_id" xsi:type="string">Magento Luma</field>
             <field name="store_ids" xsi:type="array">
                 <item name="dataset" xsi:type="string">all_store_views</item>
             </field>
diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/TestCase/CreateWidgetEntityTest.xml b/dev/tests/functional/tests/app/Magento/Widget/Test/TestCase/CreateWidgetEntityTest.xml
index fdebafbc3af35b95f6dfacff69338fd25d56b4d0..c46bc78fda62b210b168c22b4d9c1b02dee53779 100644
--- a/dev/tests/functional/tests/app/Magento/Widget/Test/TestCase/CreateWidgetEntityTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Widget/Test/TestCase/CreateWidgetEntityTest.xml
@@ -9,7 +9,7 @@
     <testCase name="Magento\Widget\Test\TestCase\CreateWidgetEntityTest" summary="Create Widget (Frontend Apps)" ticketId="MAGETWO-27916">
         <variation name="CreateWidgetEntityTestVariation1">
             <data name="widget/data/code" xsi:type="string">CMS Static Block</data>
-            <data name="widget/data/theme_id" xsi:type="string">Magento Blank</data>
+            <data name="widget/data/theme_id" xsi:type="string">Magento Luma</data>
             <data name="widget/data/title" xsi:type="string">Title_%isolation%</data>
             <data name="widget/data/store_ids/dataset" xsi:type="string">all_store_views</data>
             <data name="widget/data/widget_instance/dataset" xsi:type="string">on_category</data>
@@ -20,7 +20,7 @@
         </variation>
         <variation name="CreateWidgetEntityTestVariation2">
             <data name="widget/data/code" xsi:type="string">CMS Page Link</data>
-            <data name="widget/data/theme_id" xsi:type="string">Magento Blank</data>
+            <data name="widget/data/theme_id" xsi:type="string">Magento Luma</data>
             <data name="widget/data/title" xsi:type="string">Title_%isolation%</data>
             <data name="widget/data/store_ids/dataset" xsi:type="string">all_store_views</data>
             <data name="widget/data/widget_instance/dataset" xsi:type="string">for_cms_page_link</data>
@@ -31,7 +31,7 @@
         </variation>
         <variation name="CreateWidgetEntityTestVariation3">
             <data name="widget/data/code" xsi:type="string">Recently Viewed Products</data>
-            <data name="widget/data/theme_id" xsi:type="string">Magento Blank</data>
+            <data name="widget/data/theme_id" xsi:type="string">Magento Luma</data>
             <data name="widget/data/title" xsi:type="string">Title_%isolation%</data>
             <data name="widget/data/store_ids/dataset" xsi:type="string">all_store_views</data>
             <data name="widget/data/widget_instance/dataset" xsi:type="string">for_viewed_products</data>
@@ -42,7 +42,7 @@
         </variation>
         <variation name="CreateWidgetEntityTestVariation4">
             <data name="widget/data/code" xsi:type="string">Recently Compared Products</data>
-            <data name="widget/data/theme_id" xsi:type="string">Magento Blank</data>
+            <data name="widget/data/theme_id" xsi:type="string">Magento Luma</data>
             <data name="widget/data/title" xsi:type="string">Title_%isolation%</data>
             <data name="widget/data/store_ids/dataset" xsi:type="string">all_store_views</data>
             <data name="widget/data/widget_instance/dataset" xsi:type="string">for_compared_products</data>
@@ -53,7 +53,7 @@
         </variation>
         <variation name="CreateWidgetEntityTestVariation5">
             <data name="widget/data/code" xsi:type="string">Catalog Category Link</data>
-            <data name="widget/data/theme_id" xsi:type="string">Magento Blank</data>
+            <data name="widget/data/theme_id" xsi:type="string">Magento Luma</data>
             <data name="widget/data/title" xsi:type="string">Title_%isolation%</data>
             <data name="widget/data/store_ids/dataset" xsi:type="string">all_store_views</data>
             <data name="widget/data/widget_instance/dataset" xsi:type="string">for_category_link</data>
@@ -64,7 +64,7 @@
         </variation>
         <variation name="CreateWidgetEntityTestVariation6">
             <data name="widget/data/code" xsi:type="string">Catalog Product Link</data>
-            <data name="widget/data/theme_id" xsi:type="string">Magento Blank</data>
+            <data name="widget/data/theme_id" xsi:type="string">Magento Luma</data>
             <data name="widget/data/title" xsi:type="string">Title_%isolation%</data>
             <data name="widget/data/store_ids/dataset" xsi:type="string">all_store_views</data>
             <data name="widget/data/widget_instance/dataset" xsi:type="string">on_product_link</data>
diff --git a/dev/tests/functional/tests/app/Magento/Wishlist/Test/Block/Customer/Wishlist/Items/Product.php b/dev/tests/functional/tests/app/Magento/Wishlist/Test/Block/Customer/Wishlist/Items/Product.php
index df69f321c511977efb61b47e81358b03ec6888d7..0bc0507d993637ffe221abafbe2c508964fdfee6 100644
--- a/dev/tests/functional/tests/app/Magento/Wishlist/Test/Block/Customer/Wishlist/Items/Product.php
+++ b/dev/tests/functional/tests/app/Magento/Wishlist/Test/Block/Customer/Wishlist/Items/Product.php
@@ -11,19 +11,19 @@ use Magento\Mtf\Client\Locator;
 
 /**
  * Class Product
- * Wishlist item product form
+ * Wish List item Product form
  */
 class Product extends Form
 {
     /**
-     * Selector for 'Add to Cart' button
+     * Locator value for "Add to Cart" button.
      *
      * @var string
      */
     protected $addToCart = '.action.tocart';
 
     /**
-     * Selector for 'Remove item' button
+     * Locator value for "Remove item" button.
      *
      * @var string
      */
@@ -37,74 +37,84 @@ class Product extends Form
     protected $viewDetails = '.details.tooltip';
 
     /**
-     * Selector for 'Details block' element
+     * Locator value for "Details" block.
      *
      * @var string
      */
     protected $detailsBlock = '.product-item-tooltip';
 
     /**
-     * Edit button css selector
+     * Locator value for "Edit" button.
      *
      * @var string
      */
     protected $edit = '.action.edit';
 
     /**
-     * Selector for option's label
+     * Locator value for option's label.
      *
      * @var string
      */
     protected $optionLabel = '.tooltip.content .label';
 
     /**
-     * Selector for option's value
+     * Locator value for option's value.
      *
      * @var string
      */
     protected $optionValue = '.tooltip.content .values';
 
     /**
-     * Selector for click on footer block
+     * Locator value for Footer block.
      *
      * @var string
      */
     protected $footer = './ancestor::body//footer';
 
     /**
-     * Fill item product details
+     * Locator value for item Price.
+     *
+     * @var string
+     */
+    protected $price = '.price';
+
+    /**
+     * Fill item with details.
      *
      * @param array $fields
      * @return void
      */
     public function fillProduct(array $fields)
     {
+        $this->hoverProductBlock();
         $mapping = $this->dataMapping($fields);
         $this->_fill($mapping);
     }
 
     /**
-     * Click button 'Add To Cart'
+     * Click "Add to Cart" button.
      *
      * @return void
      */
     public function clickAddToCart()
     {
+        $this->hoverProductBlock();
         $this->_rootElement->find($this->addToCart)->click();
     }
 
     /**
-     * Remove product from wish list
+     * Remove item from Wish List.
      *
      * @return void
      */
     public function remove()
     {
+        $this->hoverProductBlock();
         $this->_rootElement->find($this->remove)->click();
     }
 
     /**
-     * Get product options
+     * Get Product options.
      *
      * @return array|null
      */
@@ -134,17 +144,28 @@ class Product extends Form
     }
 
     /**
-     * Click edit button
+     * Click "Edit" button.
      *
      * @return void
      */
     public function clickEdit()
     {
+        $this->hoverProductBlock();
         $this->_rootElement->find($this->edit)->click();
     }
 
     /**
-     * Get wishlist data for the product.
+     * Hover Product block so that possible actions appear.
+     *
+     * @return void
+     */
+    public function hoverProductBlock()
+    {
+        $this->_rootElement->find($this->price)->click();
+    }
+
+    /**
+     * Get Wish List data for the Product.
      *
      * @param mixed $qty
      * @return array
diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Layer/Filter/_files/attribute_with_option_rollback.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Layer/Filter/_files/attribute_with_option_rollback.php
index 1f31bde19a817f5c4888d8fe3faee5edbf6d67be..172ba1389b391a03d3d0da01d79f83e321eb5c29 100644
--- a/dev/tests/integration/testsuite/Magento/Catalog/Model/Layer/Filter/_files/attribute_with_option_rollback.php
+++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Layer/Filter/_files/attribute_with_option_rollback.php
@@ -11,7 +11,31 @@ $installer = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create
 $attribute = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
     'Magento\Catalog\Model\Resource\Eav\Attribute'
 );
-$attribute->loadByCode($installer->getEntityTypeId('catalog_product'), 'attribute_with_option');
+$attribute->loadByCode(\Magento\Catalog\Model\Product::ENTITY, 'attribute_with_option');
+
+/* Delete simple products per each option */
+/** @var $options \Magento\Eav\Model\Resource\Entity\Attribute\Option\Collection */
+$options = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
+    'Magento\Eav\Model\Resource\Entity\Attribute\Option\Collection'
+);
+$registry = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get('Magento\Framework\Registry');
+
+$registry->unregister('isSecureArea');
+$registry->register('isSecureArea', true);
+$options->setAttributeFilter($attribute->getId());
+
+foreach ($options as $option) {
+    /** @var $product \Magento\Catalog\Model\Product */
+    $product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create('Magento\Catalog\Model\Product');
+    $product = $product->loadByAttribute('sku', 'simple_product_' . $option->getId());
+    if ($product->getId()) {
+        $product->delete();
+    }
+}
+
 if ($attribute->getId()) {
     $attribute->delete();
 }
+
+$registry->unregister('isSecureArea');
+$registry->register('isSecureArea', false);
diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_virtual_in_stock.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_virtual_in_stock.php
new file mode 100644
index 0000000000000000000000000000000000000000..9f5be07e7658d2f67a265dca5408150db7773d4e
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_virtual_in_stock.php
@@ -0,0 +1,20 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+/** @var $product \Magento\Catalog\Model\Product */
+$product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create('Magento\Catalog\Model\Product');
+$product->setTypeId(\Magento\Catalog\Model\Product\Type::TYPE_VIRTUAL)
+    ->setId(21)
+    ->setAttributeSetId(4)
+    ->setWebsiteIds([1])
+    ->setName('Virtual Product')
+    ->setSku('virtual-product')
+    ->setPrice(10)
+    ->setTaxClassId(0)
+    ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH)
+    ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED)
+    ->setStockData(['is_in_stock' => 1])
+    ->save();
diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_virtual_in_stock_rollback.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_virtual_in_stock_rollback.php
new file mode 100644
index 0000000000000000000000000000000000000000..bed07e6d07bdde76fc362f6f7eb3df351d0d2a1a
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_virtual_in_stock_rollback.php
@@ -0,0 +1,21 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+/** @var \Magento\Framework\Registry $registry */
+$registry = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get('Magento\Framework\Registry');
+
+$registry->unregister('isSecureArea');
+$registry->register('isSecureArea', true);
+
+/** @var $product \Magento\Catalog\Model\Product */
+$product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create('Magento\Catalog\Model\Product');
+$product->load(21);
+if ($product->getId()) {
+    $product->delete();
+}
+
+$registry->unregister('isSecureArea');
+$registry->register('isSecureArea', false);
diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Block/Product/Configurable/AssociatedSelector/Backend/Grid/ColumnSetTest.php b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Block/Product/Configurable/AssociatedSelector/Backend/Grid/ColumnSetTest.php
deleted file mode 100644
index c3f810b5034b8c4cd4c91f76284e7a788eb50396..0000000000000000000000000000000000000000
--- a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Block/Product/Configurable/AssociatedSelector/Backend/Grid/ColumnSetTest.php
+++ /dev/null
@@ -1,41 +0,0 @@
-<?php
-/**
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-namespace Magento\ConfigurableProduct\Block\Product\Configurable\AssociatedSelector\Backend\Grid;
-
-class ColumnSetTest extends \PHPUnit_Framework_TestCase
-{
-    /**
-     * Testing adding column with configurable attribute to column set
-     *
-     * @magentoAppArea adminhtml
-     * @magentoAppIsolation enabled
-     * @magentoDataFixture Magento/ConfigurableProduct/_files/product_configurable.php
-     */
-    public function testPrepareSelect()
-    {
-        $product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
-            'Magento\Catalog\Model\Product'
-        );
-        $product->load(1);
-        // fixture
-        /** @var $objectManager \Magento\TestFramework\ObjectManager */
-        $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
-        $objectManager->get('Magento\Framework\Registry')->register('current_product', $product);
-
-        /** @var $layout \Magento\Framework\View\Layout */
-        $layout = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get(
-            'Magento\Framework\View\LayoutInterface'
-        );
-        /** @var $block ColumnSet */
-        $block = $layout->createBlock(
-            'Magento\ConfigurableProduct\Block\Product\Configurable\AssociatedSelector\Backend\Grid\ColumnSet',
-            'block'
-        );
-        $assertBlock = $block->getLayout()->getBlock('block.test_configurable');
-        $this->assertEquals('Test Configurable', $assertBlock->getHeader());
-        $this->assertEquals('test_configurable', $assertBlock->getId());
-    }
-}
diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/Resource/Product/Collection/AssociatedProductTest.php b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/Resource/Product/Collection/AssociatedProductTest.php
deleted file mode 100644
index 20e4e21e4061ce7fc7911e0c2d6ab14bd56cec01..0000000000000000000000000000000000000000
--- a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/Resource/Product/Collection/AssociatedProductTest.php
+++ /dev/null
@@ -1,56 +0,0 @@
-<?php
-/**
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-namespace Magento\ConfigurableProduct\Model\Resource\Product\Collection;
-
-class AssociatedProductTest extends \PHPUnit_Framework_TestCase
-{
-    /**
-     * @magentoAppIsolation enabled
-     * @magentoDataFixture Magento/Catalog/_files/product_associated.php
-     */
-    public function testPrepareSelect()
-    {
-        $product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
-            'Magento\Catalog\Model\Product'
-        );
-        $product->load(1);
-        // fixture
-        $product->setId(10);
-        /** @var $objectManager \Magento\TestFramework\ObjectManager */
-        $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
-        $objectManager->get('Magento\Framework\Registry')->register('current_product', $product);
-        $collection = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
-            'Magento\ConfigurableProduct\Model\Resource\Product\Collection\AssociatedProduct'
-        );
-        $collectionProduct = $collection->getFirstItem();
-        $this->assertEquals($product->getName(), $collectionProduct->getName());
-        $this->assertEquals($product->getSku(), $collectionProduct->getSku());
-        $this->assertEquals($product->getPrice(), $collectionProduct->getPrice());
-        $this->assertEquals($product->getWeight(), $collectionProduct->getWeight());
-        $this->assertEquals($product->getTypeId(), $collectionProduct->getTypeId());
-        $this->assertEquals($product->getAttributeSetId(), $collectionProduct->getAttributeSetId());
-    }
-
-    /**
-     * @magentoAppIsolation enabled
-     * @magentoDataFixture Magento/Catalog/_files/product_associated.php
-     */
-    public function testPrepareSelectForSameProduct()
-    {
-        $product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
-            'Magento\Catalog\Model\Product'
-        );
-        $product->load(1);
-        // fixture
-        /** @var $objectManager \Magento\TestFramework\ObjectManager */
-        $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
-        $objectManager->get('Magento\Framework\Registry')->register('current_product', $product);
-        $collection = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
-            'Magento\ConfigurableProduct\Model\Resource\Product\Collection\AssociatedProduct'
-        );
-        $this->assertEmpty($collection->count());
-    }
-}
diff --git a/dev/tests/integration/testsuite/Magento/Customer/Block/Adminhtml/Edit/Tab/CartTest.php b/dev/tests/integration/testsuite/Magento/Customer/Block/Adminhtml/Edit/Tab/CartTest.php
index d719463f60ad96888d041073905bc7092420ed74..01b7f93ad982137e8d62277d45d8eb86919275cf 100644
--- a/dev/tests/integration/testsuite/Magento/Customer/Block/Adminhtml/Edit/Tab/CartTest.php
+++ b/dev/tests/integration/testsuite/Magento/Customer/Block/Adminhtml/Edit/Tab/CartTest.php
@@ -99,7 +99,7 @@ class CartTest extends \PHPUnit_Framework_TestCase
         $html = $this->_block->toHtml();
         $this->assertContains("<div id=\"customer_cart_grid\"", $html);
         $this->assertContains("<div class=\"admin__data-grid-header admin__data-grid-toolbar\"", $html);
-        $this->assertContains("customer_cart_gridJsObject = new varienGrid('customer_cart_grid',", $html);
+        $this->assertContains("customer_cart_gridJsObject = new varienGrid(\"customer_cart_grid\",", $html);
         $this->assertContains(
             "backend/customer/cart_product_composite_cart/configure/customer_id/" . self::CUSTOMER_ID_VALUE,
             $html
diff --git a/dev/tests/integration/testsuite/Magento/Customer/Block/Adminhtml/Edit/Tab/CartsTest.php b/dev/tests/integration/testsuite/Magento/Customer/Block/Adminhtml/Edit/Tab/CartsTest.php
index 5bbdca87782a224ea4e59558e12e1231b5c26ddd..5e7361b26cfda79f70348f48503466e9d9f0b390 100644
--- a/dev/tests/integration/testsuite/Magento/Customer/Block/Adminhtml/Edit/Tab/CartsTest.php
+++ b/dev/tests/integration/testsuite/Magento/Customer/Block/Adminhtml/Edit/Tab/CartsTest.php
@@ -61,7 +61,7 @@ class CartsTest extends \PHPUnit_Framework_TestCase
             '/<div class=".*admin__data-grid-toolbar"/',
             $html
         );
-        $this->assertContains("customer_cart_grid1JsObject = new varienGrid('customer_cart_grid1',", $html);
+        $this->assertContains("customer_cart_grid1JsObject = new varienGrid(\"customer_cart_grid1\",", $html);
         $this->assertContains("backend/customer/cart_product_composite_cart/configure/website_id/1", $html);
     }
 
@@ -84,7 +84,7 @@ class CartsTest extends \PHPUnit_Framework_TestCase
             '/<div class=".*admin__data-grid-toolbar"/',
             $html
         );
-        $this->assertContains("customer_cart_gridJsObject = new varienGrid('customer_cart_grid',", $html);
+        $this->assertContains("customer_cart_gridJsObject = new varienGrid(\"customer_cart_grid\",", $html);
         $this->assertContains("backend/customer/cart_product_composite_cart/configure/key/", $html);
     }
 }
diff --git a/dev/tests/integration/testsuite/Magento/Email/Model/TemplateTest.php b/dev/tests/integration/testsuite/Magento/Email/Model/TemplateTest.php
index ad3393695ad1babf0698758d786422f9613f73a7..d66a3ebcc0a64a6c134987f2bc8ea6f751671b26 100644
--- a/dev/tests/integration/testsuite/Magento/Email/Model/TemplateTest.php
+++ b/dev/tests/integration/testsuite/Magento/Email/Model/TemplateTest.php
@@ -123,7 +123,7 @@ class TemplateTest extends \PHPUnit_Framework_TestCase
             ->load();
 
         $this->setNotDefaultThemeForFixtureStore();
-        $expectedViewUrl = 'static/frontend/Magento/luma/en_US/Magento_Theme/favicon.ico';
+        $expectedViewUrl = 'static/frontend/Magento/blank/en_US/Magento_Theme/favicon.ico';
         $this->model->setTemplateText('{{view url="Magento_Theme::favicon.ico"}}');
         $this->assertStringEndsNotWith($expectedViewUrl, $this->model->getProcessedTemplate());
         $this->model->setDesignConfig([
@@ -513,15 +513,18 @@ class TemplateTest extends \PHPUnit_Framework_TestCase
      */
     protected function setNotDefaultThemeForFixtureStore()
     {
-        $theme = $this->objectManager->create('Magento\Framework\View\Design\ThemeInterface');
-        $theme->load('Magento/luma', 'theme_path');
-        $this->objectManager->get('Magento\Framework\App\Config\MutableScopeConfigInterface')
-            ->setValue(
-                DesignInterface::XML_PATH_THEME_ID,
-                $theme->getId(),
-                ScopeInterface::SCOPE_STORE,
-                'fixturestore'
-            );
+        $theme = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
+            'Magento\Framework\View\Design\ThemeInterface'
+        );
+        $theme->load('Magento/blank', 'theme_path');
+        \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get(
+            'Magento\Framework\App\Config\MutableScopeConfigInterface'
+        )->setValue(
+            \Magento\Framework\View\DesignInterface::XML_PATH_THEME_ID,
+            $theme->getId(),
+            \Magento\Store\Model\ScopeInterface::SCOPE_STORE,
+            'fixturestore'
+        );
     }
 
     /**
@@ -536,7 +539,7 @@ class TemplateTest extends \PHPUnit_Framework_TestCase
             ->load();
 
         $this->setNotDefaultThemeForFixtureStore();
-        $expectedViewUrl = 'static/frontend/Magento/luma/en_US/Magento_Theme/favicon.ico';
+        $expectedViewUrl = 'static/frontend/Magento/blank/en_US/Magento_Theme/favicon.ico';
         $this->model->setTemplateSubject('{{view url="Magento_Theme::favicon.ico"}}');
         $this->assertStringEndsNotWith($expectedViewUrl, $this->model->getProcessedTemplateSubject([]));
         $this->model->setDesignConfig([
@@ -560,7 +563,7 @@ class TemplateTest extends \PHPUnit_Framework_TestCase
             ->load();
 
         $this->assertStringEndsWith(
-            'static/frontend/Magento/blank/en_US/Magento_Email/logo_email.png',
+            'static/frontend/Magento/luma/en_US/Magento_Email/logo_email.png',
             $this->model->getDefaultEmailLogo()
         );
     }
diff --git a/dev/tests/integration/testsuite/Magento/Framework/Search/_files/filterable_attribute_rollback.php b/dev/tests/integration/testsuite/Magento/Framework/Search/_files/filterable_attribute_rollback.php
index 04a82aafb8219f3114aa0266fe6ef2ec24f147bb..24cf533ddf5ca4517b325491545b4a0026bb9561 100644
--- a/dev/tests/integration/testsuite/Magento/Framework/Search/_files/filterable_attribute_rollback.php
+++ b/dev/tests/integration/testsuite/Magento/Framework/Search/_files/filterable_attribute_rollback.php
@@ -14,7 +14,27 @@ $installer = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create
 $attribute = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
     'Magento\Catalog\Model\Resource\Eav\Attribute'
 );
-$attribute->loadByCode($installer->getEntityTypeId('catalog_product'), 'select_attribute');
+$attribute->loadByCode(\Magento\Catalog\Model\Product::ENTITY, 'select_attribute');
+
+/** @var $selectOptions \Magento\Eav\Model\Resource\Entity\Attribute\Option\Collection */
+$selectOptions = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
+    'Magento\Eav\Model\Resource\Entity\Attribute\Option\Collection'
+);
+$registry = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get('Magento\Framework\Registry');
+
+$registry->unregister('isSecureArea');
+$registry->register('isSecureArea', true);
+
+$selectOptions->setAttributeFilter($attribute->getId());
+/* Delete simple products per each select(dropdown) option */
+foreach ($selectOptions as $option) {
+    /** @var $product \Magento\Catalog\Model\Product */
+    $product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create('Magento\Catalog\Model\Product');
+    $product = $product->loadByAttribute('sku', 'simple_product_' . $option->getId());
+    if ($product->getId()) {
+        $product->delete();
+    }
+}
 if ($attribute->getId()) {
     $attribute->delete();
 }
@@ -23,3 +43,6 @@ $attribute->loadByCode($installer->getEntityTypeId('catalog_product'), 'multisel
 if ($attribute->getId()) {
     $attribute->delete();
 }
+
+$registry->unregister('isSecureArea');
+$registry->register('isSecureArea', false);
diff --git a/dev/tests/integration/testsuite/Magento/GroupedProduct/Model/Resource/Product/Type/Grouped/AssociatedProductsCollectionTest.php b/dev/tests/integration/testsuite/Magento/GroupedProduct/Model/Resource/Product/Type/Grouped/AssociatedProductsCollectionTest.php
index 416e72ed185bd35179b80ab8699a8c343899bd7d..bee5e691d76d85b59bedb2c0e8df0b5b8c62368d 100644
--- a/dev/tests/integration/testsuite/Magento/GroupedProduct/Model/Resource/Product/Type/Grouped/AssociatedProductsCollectionTest.php
+++ b/dev/tests/integration/testsuite/Magento/GroupedProduct/Model/Resource/Product/Type/Grouped/AssociatedProductsCollectionTest.php
@@ -10,6 +10,7 @@ class AssociatedProductsCollectionTest extends \PHPUnit_Framework_TestCase
     /**
      * @magentoDataFixture Magento/GroupedProduct/_files/product_grouped.php
      * @magentoAppIsolation enabled
+     * @magentoDbIsolation disabled
      */
     public function testGetColumnValues()
     {
diff --git a/dev/tests/integration/testsuite/Magento/GroupedProduct/_files/product_grouped.php b/dev/tests/integration/testsuite/Magento/GroupedProduct/_files/product_grouped.php
index d8ac7ad7a8ce3d5b75a0a6e2e2a25fa47f06afb7..eb9f71d2f896f1f341d5351fa030fd3c759ec072 100644
--- a/dev/tests/integration/testsuite/Magento/GroupedProduct/_files/product_grouped.php
+++ b/dev/tests/integration/testsuite/Magento/GroupedProduct/_files/product_grouped.php
@@ -5,7 +5,7 @@
  */
 
 require realpath(__DIR__ . '/../../') . '/Catalog/_files/product_simple_duplicated.php';
-require realpath(__DIR__ . '/../../') . '/Catalog/_files/product_virtual.php';
+require realpath(__DIR__ . '/../../') . '/Catalog/_files/product_virtual_in_stock.php';
 
 /** @var $product \Magento\Catalog\Model\Product */
 $product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create('Magento\Catalog\Model\Product');
diff --git a/dev/tests/integration/testsuite/Magento/Newsletter/Model/TemplateTest.php b/dev/tests/integration/testsuite/Magento/Newsletter/Model/TemplateTest.php
index d501af84c4c26266dff6331a627d6ab1aad6dd30..20a8c4fb5599d23ac409d513d1d2269f86ac1a80 100644
--- a/dev/tests/integration/testsuite/Magento/Newsletter/Model/TemplateTest.php
+++ b/dev/tests/integration/testsuite/Magento/Newsletter/Model/TemplateTest.php
@@ -24,8 +24,8 @@ class TemplateTest extends \PHPUnit_Framework_TestCase
 
     /**
      * This test expects next themes for areas:
-     * current_store design/theme/full_name Magento/blank
-     * fixturestore_store design/theme/full_name Magento/luma
+     * current_store design/theme/full_name Magento/luma
+     * fixturestore_store design/theme/full_name Magento/blank
      *
      * @magentoAppIsolation  enabled
      * @magentoAppArea adminhtml
@@ -62,8 +62,8 @@ class TemplateTest extends \PHPUnit_Framework_TestCase
     public function getProcessedTemplateFrontendDataProvider()
     {
         return [
-            'frontend' => ['default', 'Magento/blank'],
-            'frontend store' => ['fixturestore', 'Magento/luma']
+            'frontend' => ['default', 'Magento/luma'],
+            'frontend store' => ['fixturestore', 'Magento/blank']
         ];
     }
 
diff --git a/dev/tests/integration/testsuite/Magento/Test/Integrity/Modular/LayoutFilesTest.php b/dev/tests/integration/testsuite/Magento/Test/Integrity/Modular/LayoutFilesTest.php
index 38c0d46aae2e4971ab47f0026e6b5df0447bc868..1c8ed4acb2d3bd9359147653798f0177f5d60379 100644
--- a/dev/tests/integration/testsuite/Magento/Test/Integrity/Modular/LayoutFilesTest.php
+++ b/dev/tests/integration/testsuite/Magento/Test/Integrity/Modular/LayoutFilesTest.php
@@ -88,10 +88,6 @@ class LayoutFilesTest extends \PHPUnit_Framework_TestCase
                 $typeAttr => 'object',
                 'value' => 'Magento\GroupedProduct\Model\Resource\Product\Type\Grouped\AssociatedProductsCollection',
             ],
-            [
-                $typeAttr => 'object',
-                'value' => 'Magento\ConfigurableProduct\Model\Resource\Product\Collection\AssociatedProduct'
-            ],
             [$typeAttr => 'object', 'value' => 'Magento\Solr\Model\Resource\Search\Grid\Collection'],
             [$typeAttr => 'object', 'value' => 'Magento\Wishlist\Model\Resource\Item\Collection\Grid'],
             [
diff --git a/dev/tests/integration/testsuite/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Chooser/ContainerTest.php b/dev/tests/integration/testsuite/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Chooser/ContainerTest.php
index 895132b55846cecf1abd3357ebe5b88fdabee1e5..5b8e110b28ecf72d05343ff7c71e5ea0d1617f24 100644
--- a/dev/tests/integration/testsuite/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Chooser/ContainerTest.php
+++ b/dev/tests/integration/testsuite/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Chooser/ContainerTest.php
@@ -39,10 +39,8 @@ class ContainerTest extends \PHPUnit_Framework_TestCase
      */
     public function testAvailableContainers()
     {
-        $design = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get(
-            'Magento\Framework\View\DesignInterface'
-        );
-        $this->block->setTheme($design->getDesignTheme()->getId());
+        $themeId = '3';
+        $this->block->setTheme($themeId);
         $this->assertContains('<option value="before.body.end" >', $this->block->toHtml());
     }
 }
diff --git a/dev/tests/static/framework/Magento/TestFramework/Dependency/PhpRule.php b/dev/tests/static/framework/Magento/TestFramework/Dependency/PhpRule.php
index 163b4ab3cd019ec4410edaebf94492a10e38e05b..99cb701eec3f576499260a2fce7ab75acdcc3797 100644
--- a/dev/tests/static/framework/Magento/TestFramework/Dependency/PhpRule.php
+++ b/dev/tests/static/framework/Magento/TestFramework/Dependency/PhpRule.php
@@ -7,8 +7,25 @@
  */
 namespace Magento\TestFramework\Dependency;
 
-class PhpRule implements \Magento\TestFramework\Dependency\RuleInterface
+use Magento\Framework\App\Utility\Files;
+use Magento\TestFramework\Dependency\RuleInterface;
+
+class PhpRule implements RuleInterface
 {
+    /**
+     * List of filepaths for DI files
+     *
+     * @var array
+     */
+    private $diFiles;
+
+    /**
+     * Map from plugin classes to the subjects they modify
+     *
+     * @var array
+     */
+    private $pluginMap;
+
     /**
      * List of routers
      *
@@ -47,12 +64,14 @@ class PhpRule implements \Magento\TestFramework\Dependency\RuleInterface
      *
      * @param array $mapRouters
      * @param array $mapLayoutBlocks
+     * @param array $pluginMap
      */
-    public function __construct(array $mapRouters, array $mapLayoutBlocks)
+    public function __construct(array $mapRouters, array $mapLayoutBlocks, array $pluginMap = [])
     {
         $this->_mapRouters = $mapRouters;
         $this->_mapLayoutBlocks = $mapLayoutBlocks;
         $this->_namespaces = implode('|', \Magento\Framework\App\Utility\Files::init()->getNamespaces());
+        $this->pluginMap = $pluginMap ?: null;
     }
 
     /**
@@ -72,7 +91,7 @@ class PhpRule implements \Magento\TestFramework\Dependency\RuleInterface
 
         $pattern = '~\b(?<class>(?<module>(' . implode(
             '_|',
-            \Magento\Framework\App\Utility\Files::init()->getNamespaces()
+            Files::init()->getNamespaces()
         ) . '[_\\\\])[a-zA-Z0-9]+)[a-zA-Z0-9_\\\\]*)\b~';
 
         $dependenciesInfo = [];
@@ -83,10 +102,16 @@ class PhpRule implements \Magento\TestFramework\Dependency\RuleInterface
                 if ($currentModule == $referenceModule) {
                     continue;
                 }
+                $dependencyClass = trim($matches['class'][$i]);
+                $currentClass = $this->getClassFromFilepath($file, $currentModule);
+                $dependencyType = $this->isPluginDependency($currentClass, $dependencyClass)
+                    ? RuleInterface::TYPE_SOFT
+                    : RuleInterface::TYPE_HARD;
+
                 $dependenciesInfo[] = [
                     'module' => $referenceModule,
-                    'type' => \Magento\TestFramework\Dependency\RuleInterface::TYPE_HARD,
-                    'source' => trim($matches['class'][$i]),
+                    'type' => $dependencyType,
+                    'source' => $dependencyClass,
                 ];
             }
         }
@@ -102,6 +127,84 @@ class PhpRule implements \Magento\TestFramework\Dependency\RuleInterface
         return $dependenciesInfo;
     }
 
+    /**
+     * Get class name from filename based on class/file naming conventions
+     *
+     * @param string $filepath
+     * @param string $module
+     * @return string
+     */
+    private function getClassFromFilepath($filepath, $module)
+    {
+        $class = strstr($filepath, str_replace(['_', '\\', '/'], DIRECTORY_SEPARATOR, $module));
+        $class = str_replace(DIRECTORY_SEPARATOR, '\\', strstr($class, '.php', true));
+        return $class;
+    }
+
+    /**
+     * @return array
+     * @throws \Exception
+     */
+    private function loadDiFiles()
+    {
+        if (!$this->diFiles) {
+            $this->diFiles = Files::init()->getDiConfigs();
+        }
+        return $this->diFiles;
+    }
+
+    /**
+     * Generate an array of plugin info
+     *
+     * @return array
+     */
+    private function loadPluginMap()
+    {
+        if (!$this->pluginMap) {
+            foreach ($this->loadDiFiles() as $filepath) {
+                $dom = new \DOMDocument();
+                $dom->loadXML(file_get_contents($filepath));
+                $typeNodes = $dom->getElementsByTagName('type');
+                /** @var \DOMElement $type */
+                foreach ($typeNodes as $type) {
+                    /** @var \DOMElement $plugin */
+                    foreach ($type->getElementsByTagName('plugin') as $plugin) {
+                        $subject = $type->getAttribute('name');
+                        $pluginType = $plugin->getAttribute('type');
+                        $this->pluginMap[$pluginType] = $subject;
+                    }
+                }
+            }
+        }
+        return $this->pluginMap;
+    }
+
+    /**
+     * Determine whether a the dependency relation is because of a plugin
+     *
+     * True IFF the dependent is a plugin for some class in the same module as the dependency.
+     *
+     * @param string $dependent
+     * @param string $dependency
+     * @return bool
+     */
+    private function isPluginDependency($dependent, $dependency)
+    {
+        $pluginMap = $this->loadPluginMap();
+        $subject = isset($pluginMap[$dependent])
+            ? $pluginMap[$dependent]
+            : null;
+        if ($subject === $dependency) {
+            return true;
+        } else if ($subject) {
+            $subjectModule = substr($subject, 0, strpos($subject, '\\', 9)); // (strlen('Magento\\') + 1) === 9
+            return strpos($dependency, $subjectModule) === 0;
+        } else {
+            return false;
+        }
+    }
+
+
     /**
      * Check get URL method
      *
@@ -128,7 +231,7 @@ class PhpRule implements \Magento\TestFramework\Dependency\RuleInterface
                     foreach ($modules as $module) {
                         $dependencies[] = [
                             'module' => $module,
-                            'type' => \Magento\TestFramework\Dependency\RuleInterface::TYPE_HARD,
+                            'type' => RuleInterface::TYPE_HARD,
                             'source' => $item['source'],
                         ];
                     }
@@ -166,7 +269,7 @@ class PhpRule implements \Magento\TestFramework\Dependency\RuleInterface
             $module = isset($check['module']) ? $check['module'] : null;
             if ($module) {
                 $result[$module] = [
-                    'type' => \Magento\TestFramework\Dependency\RuleInterface::TYPE_HARD,
+                    'type' => RuleInterface::TYPE_HARD,
                     'source' => $match['source'],
                 ];
             }
diff --git a/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Dependency/PhpRuleTest.php b/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Dependency/PhpRuleTest.php
index ed8660694377b51f79320972d79b3f50d4662adc..aa92d6ba72e0097ba2476ca0bbde8a9c2421d61a 100644
--- a/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Dependency/PhpRuleTest.php
+++ b/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Dependency/PhpRuleTest.php
@@ -16,7 +16,11 @@ class PhpRuleTest extends \PHPUnit_Framework_TestCase
     {
         $mapRoutes = ['someModule' => ['Magento\SomeModule'], 'anotherModule' => ['Magento\OneModule']];
         $mapLayoutBlocks = ['area' => ['block.name' => ['Magento\SomeModule' => 'Magento\SomeModule']]];
-        $this->model = new PhpRule($mapRoutes, $mapLayoutBlocks);
+        $pluginMap = [
+            'Magento\Module1\Plugin1' => 'Magento\Module1\Subject',
+            'Magento\Module1\Plugin2' => 'Magento\Module2\Subject',
+        ];
+        $this->model = new PhpRule($mapRoutes, $mapLayoutBlocks, $pluginMap);
     }
 
     public function testNonPhpGetDependencyInfo()
@@ -26,22 +30,31 @@ class PhpRuleTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * @param string $module
+     * @param string $class
      * @param string $content
      * @param array $expected
      * @dataProvider getDependencyInfoDataProvider
      */
-    public function testGetDependencyInfo($module, $content, array $expected)
+    public function testGetDependencyInfo($class, $content, array $expected)
     {
-        $this->assertEquals($expected, $this->model->getDependencyInfo($module, 'php', 'any', $content));
+        $file = $this->makeMockFilepath($class);
+        $module = $this->getModuleFromClass($class);
+        $this->assertEquals($expected, $this->model->getDependencyInfo($module, 'php', $file, $content));
     }
 
+    /**
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+     */
     public function getDependencyInfoDataProvider()
     {
         return [
-            ['Magento\SomeModule', 'something extends \Magento\SomeModule\Any\ClassName {', []], //1
-            [
-                'Magento\AnotherModule',
+            'Extend class in same module' => [
+                'Magento\SomeModule\SomeClass',
+                'something extends \Magento\SomeModule\Any\ClassName {',
+                []
+            ],
+            'Extend class in different module' => [
+                'Magento\AnotherModule\SomeClass',
                 'something extends \Magento\SomeModule\Any\ClassName {',
                 [
                     [
@@ -50,14 +63,14 @@ class PhpRuleTest extends \PHPUnit_Framework_TestCase
                         'source' => 'Magento\SomeModule\Any\ClassName',
                     ]
                 ]
-            ], // 2
-            [
-                'Magento\SomeModule',
+            ],
+            'getViewFileUrl in same module' => [
+                'Magento\SomeModule\SomeClass',
                 '$this->getViewFileUrl("Magento_SomeModule::js/order-by-sku-failure.js")',
                 []
-            ], // 3
-            [
-                'Magento\AnotherModule',
+            ],
+            'getViewFileUrl in different module' => [
+                'Magento\AnotherModule\SomeClass',
                 '$this->getViewFileUrl("Magento_SomeModule::js/order-by-sku-failure.js")',
                 [
                     [
@@ -66,10 +79,14 @@ class PhpRuleTest extends \PHPUnit_Framework_TestCase
                         'source' => 'Magento_SomeModule',
                     ]
                 ]
-            ], //4
-            ['Magento\SomeModule', '$this->helper("Magento\SomeModule\Any\ClassName")', []], //5
-            [
-                'Magento\AnotherModule',
+            ],
+            'Helper class from same module' => [
+                'Magento\SomeModule\SomeClass',
+                '$this->helper("Magento\SomeModule\Any\ClassName")',
+                []
+            ],
+            'Helper class from another module' => [
+                'Magento\AnotherModule\SomeClass',
                 '$this->helper("Magento\SomeModule\Any\ClassName")',
                 [
                     [
@@ -78,10 +95,14 @@ class PhpRuleTest extends \PHPUnit_Framework_TestCase
                         'source' => 'Magento\SomeModule\Any\ClassName',
                     ]
                 ]
-            ], //6
-            ['Magento\SomeModule', '$this->getUrl("someModule")', []], // 7
-            [
-                'Magento\AnotherModule',
+            ],
+            'getUrl from same module' => [
+                'Magento\SomeModule\SomeClass',
+                '$this->getUrl("someModule")',
+                []
+            ],
+            'getUrl from another module' => [
+                'Magento\SomeModule\SomeClass',
                 '$this->getUrl("anotherModule")',
                 [
                     [
@@ -90,10 +111,13 @@ class PhpRuleTest extends \PHPUnit_Framework_TestCase
                         'source' => 'getUrl("anotherModule"',
                     ]
                 ]
-            ], //8
-            ['Magento\SomeModule', '$this->getLayout()->getBlock(\'block.name\');', []], // 9
-            [
-                'Magento\AnotherModule',
+            ],
+            'getBlock from same module' => [
+                'Magento\SomeModule\SomeClass',
+                '$this->getLayout()->getBlock(\'block.name\');', []
+            ],
+            'getBlock from another module' => [
+                'Magento\AnotherModule\SomeClass',
                 '$this->getLayout()->getBlock(\'block.name\');',
                 [
                     [
@@ -102,7 +126,50 @@ class PhpRuleTest extends \PHPUnit_Framework_TestCase
                         'source' => 'getBlock(\'block.name\')',
                     ]
                 ]
-            ] // 10
+            ],
+            'Plugin on class in same module' => [
+                'Magento\Module1\Plugin1',
+                ', \Magento\Module1\Subject $variable',
+                []
+            ],
+            'Plugin depends on arbitrary class in same module' => [
+                'Magento\Module1\Plugin1',
+                ', \Magento\Module1\NotSubject $variable',
+                []
+            ],
+            'Plugin on class in different module' => [
+                'Magento\Module1\Plugin2',
+                'Magento\Module2\Subject',
+                [
+                    [
+                        'module' => 'Magento\Module2',
+                        'type' => \Magento\TestFramework\Dependency\RuleInterface::TYPE_SOFT,
+                        'source' => 'Magento\Module2\Subject',
+                    ]
+                ],
+            ],
+            'Plugin depends on arbitrary class in same module as subject' => [
+                'Magento\Module1\Plugin2',
+                'Magento\Module2\NotSubject',
+                [
+                    [
+                        'module' => 'Magento\Module2',
+                        'type' => \Magento\TestFramework\Dependency\RuleInterface::TYPE_SOFT,
+                        'source' => 'Magento\Module2\NotSubject',
+                    ]
+                ]
+            ],
+            'Plugin depends on arbitrary class in arbitrary module' => [
+                'Magento\Module1\Plugin2',
+                'Magento\OtherModule\NotSubject',
+                [
+                    [
+                        'module' => 'Magento\OtherModule',
+                        'type' => \Magento\TestFramework\Dependency\RuleInterface::TYPE_HARD,
+                        'source' => 'Magento\OtherModule\NotSubject',
+                    ]
+                ]
+            ],
         ];
     }
 
@@ -141,4 +208,28 @@ class PhpRuleTest extends \PHPUnit_Framework_TestCase
             ]
         ];
     }
+
+
+    /**
+     * Make some fake filepath to correspond to the class name
+     *
+     * @param string $class
+     * @return string
+     */
+    private function makeMockFilepath($class)
+    {
+        return 'ClassRoot' . DIRECTORY_SEPARATOR . str_replace('\\', DIRECTORY_SEPARATOR, $class) . '.php';
+    }
+
+    /**
+     * Get the module name like Magento\Module out of a classname, assuming for test purpose that
+     * all modules are from "Magento" vendor
+     *
+     * @param string $class
+     * @return string
+     */
+    private function getModuleFromClass($class)
+    {
+        return substr($class, 0, strpos($class, '\\', 9)); // (strlen('Magento\\') + 1) === 9
+    }
 }
diff --git a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_classes.php b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_classes.php
index 137c50c4765e6b60cea535f4bcd5a006a8926dbe..6bea00df5021f30e174e41125635d5c524d199aa 100755
--- a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_classes.php
+++ b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_classes.php
@@ -3847,4 +3847,9 @@ return [
     ['Magento\Setup\Model\SampleData', 'Magento\SampleData\Model\SampleData'],
     ['Magento\Customer\Controller\Account\ResetPassword'],
     ['Magento\Customer\Controller\Account'],
+    ['Magento\ConfigurableProduct\Block\Product\Configurable\AssociatedSelector\Backend\Grid\ColumnSet'],
+    ['Magento\ConfigurableProduct\Model\Resource\Product\Collection\AssociatedProduct'],
+    ['Magento\ConfigurableProduct\Block\Adminhtml\Product\Edit\Tab\Super\Config\Grid\Renderer\Inventory'],
+    ['Magento\ConfigurableProduct\Block\Adminhtml\Product\Edit\Tab\Super\Config\Grid\Renderer\Checkbox'],
+    ['Magento\ConfigurableProduct\Block\Adminhtml\Product\Edit\Tab\Super\Config\Grid\Filter\Inventory'],
 ];
diff --git a/lib/internal/Magento/Framework/Api/SearchCriteriaBuilder.php b/lib/internal/Magento/Framework/Api/SearchCriteriaBuilder.php
index 82c08f3e5cf8fb0be701535d5207018d7c2c2045..8d078203c0d2c87fb687aafb5c6e3fd065a7a55e 100644
--- a/lib/internal/Magento/Framework/Api/SearchCriteriaBuilder.php
+++ b/lib/internal/Magento/Framework/Api/SearchCriteriaBuilder.php
@@ -18,18 +18,26 @@ class SearchCriteriaBuilder extends AbstractSimpleObjectBuilder
      */
     protected $_filterGroupBuilder;
 
+    /**
+     * @var \Magento\Framework\Api\FilterBuilder
+     */
+    protected $filterBuilder;
+
     /**
      * @param ObjectFactory $objectFactory
      * @param FilterGroupBuilder $filterGroupBuilder
+     * @param FilterBuilder $filterBuilder
      */
     public function __construct(
         ObjectFactory $objectFactory,
-        FilterGroupBuilder $filterGroupBuilder
+        FilterGroupBuilder $filterGroupBuilder,
+        FilterBuilder $filterBuilder
     ) {
         parent::__construct(
             $objectFactory
         );
         $this->_filterGroupBuilder = $filterGroupBuilder;
+        $this->filterBuilder = $filterBuilder;
     }
 
     /**
@@ -58,6 +66,23 @@ class SearchCriteriaBuilder extends AbstractSimpleObjectBuilder
         return $this;
     }
 
+    /**
+     * @param string $field
+     * @param mixed $value
+     * @param string $conditionType
+     * @return $this
+     */
+    public function addFilter($field, $value, $conditionType = 'eq')
+    {
+        $this->addFilters([
+            $this->filterBuilder->setField($field)
+                ->setValue($value)
+                ->setConditionType($conditionType)
+                ->create()
+        ]);
+        return $this;
+    }
+
     /**
      * Set filter groups
      *
diff --git a/lib/internal/Magento/Framework/App/Cache/Type/Reflection.php b/lib/internal/Magento/Framework/App/Cache/Type/Reflection.php
new file mode 100644
index 0000000000000000000000000000000000000000..5ad5d1e30a8cc7e9a2b4543199db7570ec50e30c
--- /dev/null
+++ b/lib/internal/Magento/Framework/App/Cache/Type/Reflection.php
@@ -0,0 +1,30 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Framework\App\Cache\Type;
+
+/**
+ * System / Cache Management / Cache type "Reflection Data"
+ */
+class Reflection extends \Magento\Framework\Cache\Frontend\Decorator\TagScope
+{
+    /**
+     * Cache type code unique among all cache types
+     */
+    const TYPE_IDENTIFIER = 'reflection';
+
+    /**
+     * Cache tag used to distinguish the cache type from all other cache
+     */
+    const CACHE_TAG = 'REFLECTION';
+
+    /**
+     * @param \Magento\Framework\App\Cache\Type\FrontendPool $cacheFrontendPool
+     */
+    public function __construct(\Magento\Framework\App\Cache\Type\FrontendPool $cacheFrontendPool)
+    {
+        parent::__construct($cacheFrontendPool->get(self::TYPE_IDENTIFIER), self::CACHE_TAG);
+    }
+}
diff --git a/lib/internal/Magento/Framework/Config/ConfigOptionsListConstants.php b/lib/internal/Magento/Framework/Config/ConfigOptionsListConstants.php
index 16bb120e24707e422e55880cb8482427cecaa40e..6608cb60426d4f4a735f9ccf27f3d7f5be65c1a7 100644
--- a/lib/internal/Magento/Framework/Config/ConfigOptionsListConstants.php
+++ b/lib/internal/Magento/Framework/Config/ConfigOptionsListConstants.php
@@ -23,6 +23,13 @@ class ConfigOptionsListConstants
     const CONFIG_PATH_DB_PREFIX = 'db/table_prefix';
     const CONFIG_PATH_X_FRAME_OPT = 'x-frame-options';
     const CONFIG_PATH_CACHE_HOSTS = 'http_cache_hosts';
+    const CONFIG_PATH_BACKEND = 'backend';
+    const CONFIG_PATH_INSTALL = 'install';
+    const CONFIG_PATH_CRYPT = 'crypt';
+    const CONFIG_PATH_SESSION = 'session';
+    const CONFIG_PATH_DB = 'db';
+    const CONFIG_PATH_RESOURCE = 'resource';
+    const CONFIG_PATH_CACHE_TYPES = 'cache_types';
     /**#@-*/
 
     /**#@+
diff --git a/lib/internal/Magento/Framework/View/Element/Html/Link/Current.php b/lib/internal/Magento/Framework/View/Element/Html/Link/Current.php
index 7c971eaf437f13a4b301b4b210affbea20ce35d8..f1daf86f782395e831a804a55369554acd28e29f 100644
--- a/lib/internal/Magento/Framework/View/Element/Html/Link/Current.php
+++ b/lib/internal/Magento/Framework/View/Element/Html/Link/Current.php
@@ -12,6 +12,7 @@ namespace Magento\Framework\View\Element\Html\Link;
  * @method string                          getLabel()
  * @method string                          getPath()
  * @method string                          getTitle()
+ * @method null|array                      getAttributes()
  * @method null|bool                       getCurrent()
  * @method \Magento\Framework\View\Element\Html\Link\Current setCurrent(bool $value)
  */
@@ -110,7 +111,7 @@ class Current extends \Magento\Framework\View\Element\Template
             $html .= $this->getTitle()
                 ? ' title="' . $this->escapeHtml((string)new \Magento\Framework\Phrase($this->getTitle())) . '"'
                 : '';
-            $html .= '>';
+            $html .= $this->getAttributesHtml() . '>';
 
             if ($this->getIsHighlighted()) {
                 $html .= '<strong>';
@@ -127,4 +128,22 @@ class Current extends \Magento\Framework\View\Element\Template
 
         return $html;
     }
+
+    /**
+     * Generate attributes' HTML code
+     *
+     * @return string
+     */
+    private function getAttributesHtml()
+    {
+        $attributesHtml = '';
+        $attributes = $this->getAttributes();
+        if ($attributes) {
+            foreach ($attributes as $attribute => $value) {
+                $attributesHtml .= ' ' . $attribute . '="' . $this->escapeHtml($value) . '"';
+            }
+        }
+
+        return $attributesHtml;
+    }
 }
diff --git a/lib/internal/Magento/Framework/View/Element/UiComponent/ContentType/Json.php b/lib/internal/Magento/Framework/View/Element/UiComponent/ContentType/Json.php
index 6af04342a3a6c7e37af552809ae0348d7820e6d0..abcd9be5823f5c8a8635271ebdb6b6d071c4b07b 100644
--- a/lib/internal/Magento/Framework/View/Element/UiComponent/ContentType/Json.php
+++ b/lib/internal/Magento/Framework/View/Element/UiComponent/ContentType/Json.php
@@ -9,6 +9,7 @@ use Magento\Framework\Json\Encoder;
 use Magento\Framework\View\FileSystem;
 use Magento\Framework\View\TemplateEnginePool;
 use Magento\Framework\View\Element\UiComponentInterface;
+use Magento\Framework\View\Layout\Generator\Structure;
 
 /**
  * Class Json
@@ -16,6 +17,15 @@ use Magento\Framework\View\Element\UiComponentInterface;
 class Json extends AbstractContentType
 {
     /**
+     * Generator structure instance
+     *
+     * @var Structure
+     */
+    private $structure;
+
+    /**
+     * Encoder
+     *
      * @var Encoder
      */
     private $encoder;
@@ -26,14 +36,17 @@ class Json extends AbstractContentType
      * @param FileSystem $filesystem
      * @param TemplateEnginePool $templateEnginePool
      * @param Encoder $encoder
+     * @param Structure $structure
      */
     public function __construct(
         FileSystem $filesystem,
         TemplateEnginePool $templateEnginePool,
-        Encoder $encoder
+        Encoder $encoder,
+        Structure $structure
     ) {
         parent::__construct($filesystem, $templateEnginePool);
         $this->encoder = $encoder;
+        $this->structure = $structure;
     }
 
     /**
@@ -47,9 +60,15 @@ class Json extends AbstractContentType
      */
     public function render(UiComponentInterface $component, $template = '')
     {
-        $data = $component->getContext()->getDataSourceData($component);
-        $data = reset($data);
-
-        return $this->encoder->encode($data['config']['data']);
+        $context = $component->getContext();
+        $isComponent = $context->getRequestParam('componentJson');
+        if ($isComponent) {
+            $data = $this->structure->generate($component);
+            return $this->encoder->encode($data);
+        } else {
+            $data = $component->getContext()->getDataSourceData($component);
+            $data = reset($data);
+            return $this->encoder->encode($data['config']['data']);
+        }
     }
 }
diff --git a/app/code/Magento/Ui/Component/Layout/Generator/Structure.php b/lib/internal/Magento/Framework/View/Layout/Generator/Structure.php
similarity index 90%
rename from app/code/Magento/Ui/Component/Layout/Generator/Structure.php
rename to lib/internal/Magento/Framework/View/Layout/Generator/Structure.php
index c26b9c40664a3bd93122a7f6bee509264fcb8049..49431962a86b2a46568771d437cedd46aef016ef 100644
--- a/app/code/Magento/Ui/Component/Layout/Generator/Structure.php
+++ b/lib/internal/Magento/Framework/View/Layout/Generator/Structure.php
@@ -3,9 +3,9 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Ui\Component\Layout\Generator;
+namespace Magento\Framework\View\Layout\Generator;
 
-use Magento\Ui\Component\Layout\LayoutPool;
+use Magento\Framework\View\Layout\Pool as LayoutPool;
 use Magento\Framework\View\Element\UiComponentInterface;
 use Magento\Framework\View\Element\UiComponent\LayoutInterface;
 
diff --git a/lib/internal/Magento/Framework/View/Layout/Generator/UiComponent.php b/lib/internal/Magento/Framework/View/Layout/Generator/UiComponent.php
index d5a8fcda61c2a164f1da15f4f9f3482112d18fe1..a1d81de2f22f6b8a3f63b2deca2d333714c9a754 100644
--- a/lib/internal/Magento/Framework/View/Layout/Generator/UiComponent.php
+++ b/lib/internal/Magento/Framework/View/Layout/Generator/UiComponent.php
@@ -7,7 +7,7 @@ namespace Magento\Framework\View\Layout\Generator;
 
 use Magento\Framework\View\Layout;
 use Magento\Framework\View\Element\BlockFactory;
-use Magento\Framework\View\Layout\Data\Structure;
+use Magento\Framework\View\Layout\Data\Structure as DataStructure;
 use Magento\Framework\View\Layout\GeneratorInterface;
 use Magento\Framework\View\Element\UiComponentFactory;
 use Magento\Framework\View\Element\UiComponentInterface;
@@ -102,13 +102,13 @@ class UiComponent implements GeneratorInterface
     /**
      * Create component object
      *
-     * @param Structure $structure
+     * @param DataStructure $structure
      * @param string $elementName
      * @param string $data
      * @param LayoutInterface $layout
      * @return ContainerInterface
      */
-    protected function generateComponent(Structure $structure, $elementName, $data, LayoutInterface $layout)
+    protected function generateComponent(DataStructure $structure, $elementName, $data, LayoutInterface $layout)
     {
         $attributes = $data['attributes'];
         if (!empty($attributes['group'])) {
diff --git a/app/code/Magento/Ui/Component/Layout/Generic.php b/lib/internal/Magento/Framework/View/Layout/Generic.php
similarity index 98%
rename from app/code/Magento/Ui/Component/Layout/Generic.php
rename to lib/internal/Magento/Framework/View/Layout/Generic.php
index 92d0a406f38e067fd5fc189ae3e1821fd788eeac..a64af6ec44b46ccc2eb0324f51a2c600995fb1e3 100644
--- a/app/code/Magento/Ui/Component/Layout/Generic.php
+++ b/lib/internal/Magento/Framework/View/Layout/Generic.php
@@ -3,7 +3,7 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Ui\Component\Layout;
+namespace Magento\Framework\View\Layout;
 
 use Magento\Framework\View\Element\UiComponent\DataSourceInterface;
 use Magento\Framework\View\Element\UiComponent\LayoutInterface;
diff --git a/app/code/Magento/Ui/Component/Layout/LayoutPool.php b/lib/internal/Magento/Framework/View/Layout/Pool.php
similarity index 90%
rename from app/code/Magento/Ui/Component/Layout/LayoutPool.php
rename to lib/internal/Magento/Framework/View/Layout/Pool.php
index b15a513ff42c604797718731bb16798f670b95a4..d9d785a85884ed15879f37e3961f3211b156c2e3 100644
--- a/app/code/Magento/Ui/Component/Layout/LayoutPool.php
+++ b/lib/internal/Magento/Framework/View/Layout/Pool.php
@@ -3,17 +3,17 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Ui\Component\Layout;
+namespace Magento\Framework\View\Layout;
 
 use Magento\Framework\ObjectManagerInterface;
 use Magento\Framework\View\Element\UiComponent\LayoutInterface;
 
 /**
- * Class LayoutPool
+ * Class Pool
  */
-class LayoutPool
+class Pool
 {
-    const DEFAULT_CLASS = 'Magento\Ui\Component\Layout\Generic';
+    const DEFAULT_CLASS = 'Magento\Framework\View\Layout\Generic';
 
     /**
      * Layouts pool
diff --git a/nginx.conf.sample b/nginx.conf.sample
index cab0b839ffe10f8c87a46dc97baccafa50f93a64..01b163498156956cb37f9ea99a5f5f9c9817981c 100644
--- a/nginx.conf.sample
+++ b/nginx.conf.sample
@@ -26,13 +26,32 @@ charset off;
 
 location /setup {
     root $MAGE_ROOT;
-
     location ~ ^/setup/index.php {
         fastcgi_pass   fastcgi_backend;
         fastcgi_index  index.php;
         fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
         include        fastcgi_params;
     }
+
+    location ~ /setup/(?!pub/). {
+        deny all;
+    }
+}
+
+location /update {
+    root $MAGE_ROOT;
+
+    location ~ /update/index.php {
+        fastcgi_pass   fastcgi_backend;
+        fastcgi_index  index.php;
+        fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
+        include        fastcgi_params;
+    }
+
+    # deny everything but index.php
+    location ~ /update/(?!pub/). {
+        deny all;
+    }
 }
 
 location / {
@@ -40,6 +59,9 @@ location / {
 }
 
 location /pub {
+    location ~ ^/pub/media/(downloadable|customer|import|theme_customization/.*\.xml) {
+        deny all;
+    }
     alias $MAGE_ROOT/pub;
 }
 
@@ -70,6 +92,11 @@ location /static/ {
 
 location /media/ {
     try_files $uri $uri/ /get.php?$args;
+
+    location ~ ^/media/theme_customization/.*\.xml {
+        deny all;
+    }
+
     location ~* \.(ico|jpg|jpeg|png|gif|svg|js|css|swf|eot|ttf|otf|woff|woff2)$ {
         add_header Cache-Control "public";
         expires +1y;
@@ -90,15 +117,7 @@ location /media/downloadable/ {
     deny all;
 }
 
-location ~ /media/theme_customization/.*\.xml$ {
-    deny all;
-}
-
-location /errors/ {
-    try_files $uri =404;
-}
-
-location ~ ^/errors/.*\.(xml|phtml)$ {
+location /media/import/ {
     deny all;
 }
 
diff --git a/pub/errors/.htaccess b/pub/errors/.htaccess
index 5a3f0a15d124ed9f66b3fd0e97ad4d6ae7cce0f7..3692dd439e2ff90b141f4e2c362518e359e7079e 100644
--- a/pub/errors/.htaccess
+++ b/pub/errors/.htaccess
@@ -2,6 +2,3 @@ Options None
 <IfModule mod_rewrite.c>
     RewriteEngine Off
 </IfModule>
-<FilesMatch "\.(xml|phtml)$">
-    Deny from all
-</FilesMatch>
\ No newline at end of file
diff --git a/setup/config/.htaccess b/setup/config/.htaccess
new file mode 100644
index 0000000000000000000000000000000000000000..281d5c33db37cd1cc887dbb2d36897b897835071
--- /dev/null
+++ b/setup/config/.htaccess
@@ -0,0 +1,2 @@
+order allow,deny
+deny from all
diff --git a/setup/performance-toolkit/.htaccess b/setup/performance-toolkit/.htaccess
new file mode 100644
index 0000000000000000000000000000000000000000..281d5c33db37cd1cc887dbb2d36897b897835071
--- /dev/null
+++ b/setup/performance-toolkit/.htaccess
@@ -0,0 +1,2 @@
+order allow,deny
+deny from all
diff --git a/setup/src/.htaccess b/setup/src/.htaccess
new file mode 100644
index 0000000000000000000000000000000000000000..281d5c33db37cd1cc887dbb2d36897b897835071
--- /dev/null
+++ b/setup/src/.htaccess
@@ -0,0 +1,2 @@
+order allow,deny
+deny from all
diff --git a/setup/src/Magento/Setup/Console/Command/DiCompileCommand.php b/setup/src/Magento/Setup/Console/Command/DiCompileCommand.php
index 707c8ee9dae3296836b2a16a000298fded1c9359..05a46aac47dade5b0a8f9b40ad7eeb16ea175388 100644
--- a/setup/src/Magento/Setup/Console/Command/DiCompileCommand.php
+++ b/setup/src/Magento/Setup/Console/Command/DiCompileCommand.php
@@ -8,6 +8,7 @@ namespace Magento\Setup\Console\Command;
 
 use Magento\Framework\Filesystem;
 use Magento\Framework\App\Filesystem\DirectoryList;
+use Magento\Framework\Filesystem\DriverInterface;
 use Magento\Framework\ObjectManagerInterface;
 use Magento\Framework\App\DeploymentConfig;
 use Magento\Setup\Model\ObjectManagerProvider;
@@ -44,6 +45,9 @@ class DiCompileCommand extends Command
     /** @var array */
     private $excludedPathsList;
 
+    /** @var DriverInterface */
+    private $fileDriver;
+
     /**
      * Constructor
      *
@@ -52,19 +56,22 @@ class DiCompileCommand extends Command
      * @param Manager $taskManager
      * @param ObjectManagerProvider $objectManagerProvider
      * @param Filesystem $filesystem
+     * @param DriverInterface $fileDriver
      */
     public function __construct(
         DeploymentConfig $deploymentConfig,
         DirectoryList $directoryList,
         Manager $taskManager,
         ObjectManagerProvider $objectManagerProvider,
-        Filesystem $filesystem
+        Filesystem $filesystem,
+        DriverInterface $fileDriver
     ) {
         $this->deploymentConfig = $deploymentConfig;
         $this->directoryList    = $directoryList;
         $this->objectManager    = $objectManagerProvider->get();
         $this->taskManager      = $taskManager;
         $this->filesystem       = $filesystem;
+        $this->fileDriver       = $fileDriver;
         parent::__construct();
     }
 
@@ -80,18 +87,50 @@ class DiCompileCommand extends Command
         parent::configure();
     }
 
+    /**
+     * Checks that application is installed and DI resources are cleared
+     *
+     * @return string[]
+     */
+    private function checkEnvironment()
+    {
+        $messages = [];
+        if (!$this->deploymentConfig->isAvailable()) {
+            $messages[] = 'You cannot run this command because the Magento application is not installed.';
+        }
+
+        /**
+         * By the time the command is able to execute, the Object Management configuration is already contaminated
+         * by old config info, and it's too late to just clear the files in code.
+         *
+         * TODO: reconfigure OM in runtime so DI resources can be cleared after command launches
+         *
+         */
+        $path = $this->directoryList->getPath(DirectoryList::DI);
+        if ($this->fileDriver->isExists($path)) {
+            $messages[] = "DI configuration must be cleared before running compiler. Please delete '$path'.";
+        }
+
+        return $messages;
+    }
+
     /**
      * {@inheritdoc}
      */
     protected function execute(InputInterface $input, OutputInterface $output)
     {
+        $errors = $this->checkEnvironment();
+        if ($errors) {
+            foreach ($errors as $line) {
+                $output->writeln($line);
+            }
+            return;
+        }
+
         $appCodePath = $this->directoryList->getPath(DirectoryList::MODULES);
         $libraryPath = $this->directoryList->getPath(DirectoryList::LIB_INTERNAL);
         $generationPath = $this->directoryList->getPath(DirectoryList::GENERATION);
-        if (!$this->deploymentConfig->isAvailable()) {
-            $output->writeln('You cannot run this command because the Magento application is not installed.');
-            return;
-        }
+
         $this->objectManager->get('Magento\Framework\App\Cache')->clean();
         $compiledPathsList = [
             'application' => $appCodePath,
diff --git a/setup/src/Magento/Setup/Test/Unit/Console/Command/DiCompileCommandTest.php b/setup/src/Magento/Setup/Test/Unit/Console/Command/DiCompileCommandTest.php
index 2b9381b4783a495e0a179e6221734c0ac34e5895..205e0799436bb77e81fcda0bfed630df89874c55 100644
--- a/setup/src/Magento/Setup/Test/Unit/Console/Command/DiCompileCommandTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Console/Command/DiCompileCommandTest.php
@@ -28,6 +28,12 @@ class DiCompileCommandTest extends \PHPUnit_Framework_TestCase
     /** @var  \Magento\Framework\Filesystem|\PHPUnit_Framework_MockObject_MockObject */
     private $filesystem;
 
+    /** @var  \Magento\Framework\Filesystem\Driver\File | \PHPUnit_Framework_MockObject_MockObject*/
+    private $fileDriver;
+
+    /** @var  \Magento\Framework\App\Filesystem\DirectoryList | \PHPUnit_Framework_MockObject_MockObject*/
+    private $directoryList;
+
     public function setUp()
     {
         $this->deploymentConfig = $this->getMock('Magento\Framework\App\DeploymentConfig', [], [], '', false);
@@ -52,23 +58,39 @@ class DiCompileCommandTest extends \PHPUnit_Framework_TestCase
             ->method('get')
             ->willReturn($this->objectManager);
         $this->manager = $this->getMock('Magento\Setup\Module\Di\App\Task\Manager', [], [], '', false);
-        $directoryList = $this->getMock('Magento\Framework\App\Filesystem\DirectoryList', [], [], '', false);
+        $this->directoryList = $this->getMock('Magento\Framework\App\Filesystem\DirectoryList', [], [], '', false);
         $this->filesystem = $this->getMockBuilder('Magento\Framework\Filesystem')
             ->disableOriginalConstructor()
             ->getMock();
 
-        $directoryList->expects($this->exactly(3))->method('getPath');
+        $this->fileDriver = $this->getMockBuilder('Magento\Framework\Filesystem\Driver\File')
+            ->disableOriginalConstructor()
+            ->getMock();
+
         $this->command = new DiCompileCommand(
             $this->deploymentConfig,
-            $directoryList,
+            $this->directoryList,
             $this->manager,
             $objectManagerProvider,
-            $this->filesystem
+            $this->filesystem,
+            $this->fileDriver
         );
     }
 
+    public function testExecuteDiExists()
+    {
+        $diPath = '/root/magento/var/di';
+        $this->deploymentConfig->expects($this->once())->method('isAvailable')->willReturn(true);
+        $this->fileDriver->expects($this->atLeastOnce())->method('isExists')->with($diPath)->willReturn(true);
+        $this->directoryList->expects($this->atLeastOnce())->method('getPath')->willReturn($diPath);
+        $tester = new CommandTester($this->command);
+        $tester->execute([]);
+        $this->assertContains("delete '/root/magento/var/di'", $tester->getDisplay());
+    }
+
     public function testExecuteNotInstalled()
     {
+        $this->directoryList->expects($this->atLeastOnce())->method('getPath')->willReturn(null);
         $this->deploymentConfig->expects($this->once())->method('isAvailable')->willReturn(false);
         $tester = new CommandTester($this->command);
         $tester->execute([]);
@@ -80,6 +102,7 @@ class DiCompileCommandTest extends \PHPUnit_Framework_TestCase
 
     public function testExecute()
     {
+        $this->directoryList->expects($this->atLeastOnce())->method('getPath')->willReturn(null);
         $this->objectManager->expects($this->once())
             ->method('get')
             ->with('Magento\Framework\App\Cache')
diff --git a/setup/view/.htaccess b/setup/view/.htaccess
new file mode 100644
index 0000000000000000000000000000000000000000..281d5c33db37cd1cc887dbb2d36897b897835071
--- /dev/null
+++ b/setup/view/.htaccess
@@ -0,0 +1,2 @@
+order allow,deny
+deny from all
diff --git a/vendor/.htaccess b/vendor/.htaccess
new file mode 100644
index 0000000000000000000000000000000000000000..cb24fd7fc0b3a0e46f6cad19e834117476bd0341
--- /dev/null
+++ b/vendor/.htaccess
@@ -0,0 +1,2 @@
+Order allow,deny
+Deny from all