diff --git a/.gitignore b/.gitignore
index 9269cefc51fa0178e49324a776bef8b575d7ac08..a5b85031db205be7a5ccdf34fbfb4ead11787617 100644
--- a/.gitignore
+++ b/.gitignore
@@ -23,6 +23,8 @@ atlassian*
 /lib/internal/flex/varien/.settings
 /node_modules
 /.grunt
+/Gruntfile.js
+/package.json
 
 /pub/media/*.*
 !/pub/media/.htaccess
diff --git a/app/bootstrap.php b/app/bootstrap.php
index ec60a1708dacc3d2238960e5b1c9e7c0da05cc92..c8e676cb69cffd5cf32de8f12f9f83987cc6619a 100644
--- a/app/bootstrap.php
+++ b/app/bootstrap.php
@@ -11,14 +11,14 @@ error_reporting(E_ALL);
 #ini_set('display_errors', 1);
 
 /* PHP version validation */
-if (!defined('PHP_VERSION_ID') || !(PHP_VERSION_ID >= 50600 && PHP_VERSION_ID < 50700 || PHP_VERSION_ID === 70002 || PHP_VERSION_ID === 70004 || PHP_VERSION_ID >= 70006)) {
+if (!defined('PHP_VERSION_ID') || !(PHP_VERSION_ID >= 50605 && PHP_VERSION_ID < 50700 || PHP_VERSION_ID === 70002 || PHP_VERSION_ID === 70004 || PHP_VERSION_ID >= 70006)) {
     if (PHP_SAPI == 'cli') {
-        echo 'Magento supports PHP 5.6, 7.0.2, 7.0.4, and 7.0.6 or later. ' .
+        echo 'Magento supports PHP 5.6.5, 7.0.2, 7.0.4, and 7.0.6 or later. ' .
             'Please read http://devdocs.magento.com/guides/v1.0/install-gde/system-requirements.html';
     } else {
         echo <<<HTML
 <div style="font:12px/1.35em arial, helvetica, sans-serif;">
-    <p>Magento supports PHP 5.6, 7.0.2, 7.0.4, and 7.0.6 or later. Please read
+    <p>Magento supports PHP 5.6.5, 7.0.2, 7.0.4, and 7.0.6 or later. Please read
     <a target="_blank" href="http://devdocs.magento.com/guides/v1.0/install-gde/system-requirements.html">
     Magento System Requirements</a>.
 </div>
@@ -35,6 +35,17 @@ $umaskFile = BP . '/magento_umask';
 $mask = file_exists($umaskFile) ? octdec(file_get_contents($umaskFile)) : 002;
 umask($mask);
 
+if (empty($_SERVER['ENABLE_IIS_REWRITES']) || ($_SERVER['ENABLE_IIS_REWRITES'] != 1)) {
+    /*
+     * Unset headers used by IIS URL rewrites.
+     */
+    unset($_SERVER['HTTP_X_REWRITE_URL']);
+    unset($_SERVER['HTTP_X_ORIGINAL_URL']);
+    unset($_SERVER['IIS_WasUrlRewritten']);
+    unset($_SERVER['UNENCODED_URL']);
+    unset($_SERVER['ORIG_PATH_INFO']);
+}
+
 if (!empty($_SERVER['MAGE_PROFILER'])
     && isset($_SERVER['HTTP_ACCEPT'])
     && strpos($_SERVER['HTTP_ACCEPT'], 'text/html') !== false
diff --git a/app/code/Magento/AdminNotification/composer.json b/app/code/Magento/AdminNotification/composer.json
index 527268df36b41efe5078528138342a03fa33745d..09d8ce41bbb03607a2f8cd16831454c8565a5204 100644
--- a/app/code/Magento/AdminNotification/composer.json
+++ b/app/code/Magento/AdminNotification/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-admin-notification",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-store": "100.2.*",
         "magento/module-backend": "100.2.*",
         "magento/module-media-storage": "100.2.*",
diff --git a/app/code/Magento/AdvancedPricingImportExport/composer.json b/app/code/Magento/AdvancedPricingImportExport/composer.json
index 65ea7524dffff5bb778aaf5ec7658302072cfaf9..2fc465fa3c3dfd7a51abdd713f0c5c6dfd6843c6 100644
--- a/app/code/Magento/AdvancedPricingImportExport/composer.json
+++ b/app/code/Magento/AdvancedPricingImportExport/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-advanced-pricing-import-export",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-catalog": "101.1.*",
         "magento/module-catalog-inventory": "100.2.*",
         "magento/module-eav": "100.2.*",
diff --git a/app/code/Magento/Authorization/composer.json b/app/code/Magento/Authorization/composer.json
index 0ca367d4854dfe5c35811d15aee4d718c0a4edb7..af88e8376dc756cb9e1f6180848df41e6fd8b5f3 100644
--- a/app/code/Magento/Authorization/composer.json
+++ b/app/code/Magento/Authorization/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-authorization",
     "description": "Authorization module provides access to Magento ACL functionality.",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-backend": "100.2.*",
         "magento/framework": "100.2.*"
     },
diff --git a/app/code/Magento/Authorizenet/composer.json b/app/code/Magento/Authorizenet/composer.json
index 0c9e9641b6076850310edd75a2a4ea5ed3ccd094..b93cb6688f56d826a8d981518612897aae6f1ac8 100644
--- a/app/code/Magento/Authorizenet/composer.json
+++ b/app/code/Magento/Authorizenet/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-authorizenet",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-sales": "100.2.*",
         "magento/module-store": "100.2.*",
         "magento/module-quote": "100.2.*",
diff --git a/app/code/Magento/Authorizenet/i18n/en_US.csv b/app/code/Magento/Authorizenet/i18n/en_US.csv
index 7183c706dc0a2ed264e7e73d0e11743cbf450b40..45025304c4e4423d77f60e1e26af4f2da6a8a569 100644
--- a/app/code/Magento/Authorizenet/i18n/en_US.csv
+++ b/app/code/Magento/Authorizenet/i18n/en_US.csv
@@ -64,3 +64,4 @@ Debug,Debug
 "Minimum Order Total","Minimum Order Total"
 "Maximum Order Total","Maximum Order Total"
 "Sort Order","Sort Order"
+"Sorry, but something went wrong. Please contact the seller.","Sorry, but something went wrong. Please contact the seller."
diff --git a/app/code/Magento/Authorizenet/view/frontend/web/js/view/payment/method-renderer/authorizenet-directpost.js b/app/code/Magento/Authorizenet/view/frontend/web/js/view/payment/method-renderer/authorizenet-directpost.js
index cd05960c17633844fb1c57e92794066186a45965..86ec8e0c3922109170e19f4191fdbf7e27dc43d5 100644
--- a/app/code/Magento/Authorizenet/view/frontend/web/js/view/payment/method-renderer/authorizenet-directpost.js
+++ b/app/code/Magento/Authorizenet/view/frontend/web/js/view/payment/method-renderer/authorizenet-directpost.js
@@ -5,15 +5,16 @@
 define(
     [
         'jquery',
-        'Magento_Payment/js/view/payment/iframe'
+        'Magento_Payment/js/view/payment/iframe',
+        'mage/translate'
     ],
-    function ($, Component) {
+    function ($, Component, $t) {
         'use strict';
 
         return Component.extend({
             defaults: {
                 template: 'Magento_Authorizenet/payment/authorizenet-directpost',
-                timeoutMessage: 'Sorry, but something went wrong. Please contact the seller.'
+                timeoutMessage: $t('Sorry, but something went wrong. Please contact the seller.')
             },
             placeOrderHandler: null,
             validateHandler: null,
diff --git a/app/code/Magento/Backend/composer.json b/app/code/Magento/Backend/composer.json
index 7d428636a1f45e23d81879c99baaeef6744518fc..5cfe6955b46bb99f6dd8c76cd58e3ba9bb6f28ad 100644
--- a/app/code/Magento/Backend/composer.json
+++ b/app/code/Magento/Backend/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-backend",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-store": "100.2.*",
         "magento/module-directory": "100.2.*",
         "magento/module-developer": "100.2.*",
diff --git a/app/code/Magento/Backup/composer.json b/app/code/Magento/Backup/composer.json
index 21ed6f1780a41348c5bb26556c14fcaa02c08770..ee05d6726db4c3bea7460893242d546a511fe0cc 100644
--- a/app/code/Magento/Backup/composer.json
+++ b/app/code/Magento/Backup/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-backup",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-store": "100.2.*",
         "magento/module-backend": "100.2.*",
         "magento/module-cron": "100.2.*",
diff --git a/app/code/Magento/Braintree/Model/Ui/Adminhtml/PayPal/TokenUiComponentProvider.php b/app/code/Magento/Braintree/Model/Ui/Adminhtml/PayPal/TokenUiComponentProvider.php
new file mode 100644
index 0000000000000000000000000000000000000000..fd94e18e2cd94b4e4abca81c28d5dcf90c56ff92
--- /dev/null
+++ b/app/code/Magento/Braintree/Model/Ui/Adminhtml/PayPal/TokenUiComponentProvider.php
@@ -0,0 +1,84 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Braintree\Model\Ui\Adminhtml\PayPal;
+
+use Magento\Braintree\Gateway\Config\PayPal\Config;
+use Magento\Braintree\Model\Ui\ConfigProvider;
+use Magento\Braintree\Model\Ui\PayPal\ConfigProvider as PayPalConfigProvider;
+use Magento\Framework\UrlInterface;
+use Magento\Framework\View\Element\Template;
+use Magento\Vault\Api\Data\PaymentTokenInterface;
+use Magento\Vault\Model\Ui\TokenUiComponentInterfaceFactory;
+use Magento\Vault\Model\Ui\TokenUiComponentProviderInterface;
+
+/**
+ * Gets Ui component configuration for Braintree PayPal Vault
+ */
+class TokenUiComponentProvider implements TokenUiComponentProviderInterface
+{
+
+    /**
+     * @var TokenUiComponentInterfaceFactory
+     */
+    private $componentFactory;
+
+    /**
+     * @var UrlInterface
+     */
+    private $urlBuilder;
+
+    /**
+     * @var Config
+     */
+    private $config;
+
+    /**
+     * @param TokenUiComponentInterfaceFactory $componentFactory
+     * @param UrlInterface $urlBuilder
+     * @param Config $config
+     */
+    public function __construct(
+        TokenUiComponentInterfaceFactory $componentFactory,
+        UrlInterface $urlBuilder,
+        Config $config
+    ) {
+        $this->componentFactory = $componentFactory;
+        $this->urlBuilder = $urlBuilder;
+        $this->config = $config;
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function getComponentForToken(PaymentTokenInterface $paymentToken)
+    {
+        $data = json_decode($paymentToken->getTokenDetails() ?: '{}', true);
+        $data['icon'] = $this->config->getPayPalIcon();
+        $component = $this->componentFactory->create(
+            [
+                'config' => [
+                    'code' => PayPalConfigProvider::PAYPAL_VAULT_CODE,
+                    'nonceUrl' => $this->getNonceRetrieveUrl(),
+                    TokenUiComponentProviderInterface::COMPONENT_DETAILS => $data,
+                    TokenUiComponentProviderInterface::COMPONENT_PUBLIC_HASH => $paymentToken->getPublicHash(),
+                    'template' => 'Magento_Braintree::form/paypal/vault.phtml'
+                ],
+                'name' => Template::class
+            ]
+        );
+
+        return $component;
+    }
+
+    /**
+     * Get url to retrieve payment method nonce
+     * @return string
+     */
+    private function getNonceRetrieveUrl()
+    {
+        return $this->urlBuilder->getUrl(ConfigProvider::CODE . '/payment/getnonce', ['_secure' => true]);
+    }
+}
diff --git a/app/code/Magento/Braintree/Model/Ui/Adminhtml/TokenUiComponentProvider.php b/app/code/Magento/Braintree/Model/Ui/Adminhtml/TokenUiComponentProvider.php
index 6cfc96ea23d0d158646c4e30be4f63aeb8ca2cd0..420b8365b3ea4f64de1ad6008238c4a706aaa4b6 100644
--- a/app/code/Magento/Braintree/Model/Ui/Adminhtml/TokenUiComponentProvider.php
+++ b/app/code/Magento/Braintree/Model/Ui/Adminhtml/TokenUiComponentProvider.php
@@ -49,6 +49,7 @@ class TokenUiComponentProvider implements TokenUiComponentProviderInterface
         $component = $this->componentFactory->create(
             [
                 'config' => [
+                    'code' => ConfigProvider::CC_VAULT_CODE,
                     'nonceUrl' => $this->getNonceRetrieveUrl(),
                     TokenUiComponentProviderInterface::COMPONENT_DETAILS => $data,
                     TokenUiComponentProviderInterface::COMPONENT_PUBLIC_HASH => $paymentToken->getPublicHash(),
diff --git a/app/code/Magento/Braintree/Test/Unit/Model/Ui/Adminhtml/PayPal/TokenUiComponentProviderTest.php b/app/code/Magento/Braintree/Test/Unit/Model/Ui/Adminhtml/PayPal/TokenUiComponentProviderTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..bdc39cbc5b868b52484cd550c833cfa147e68407
--- /dev/null
+++ b/app/code/Magento/Braintree/Test/Unit/Model/Ui/Adminhtml/PayPal/TokenUiComponentProviderTest.php
@@ -0,0 +1,114 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Braintree\Test\Unit\Model\Ui\Adminhtml\PayPal;
+
+use Magento\Braintree\Gateway\Config\PayPal\Config;
+use Magento\Braintree\Model\Ui\Adminhtml\PayPal\TokenUiComponentProvider;
+use Magento\Framework\UrlInterface;
+use Magento\Vault\Api\Data\PaymentTokenInterface;
+use Magento\Vault\Model\Ui\TokenUiComponentInterface;
+use Magento\Vault\Model\Ui\TokenUiComponentInterfaceFactory;
+use PHPUnit_Framework_MockObject_MockObject as MockObject;
+
+/**
+ * Contains methods to test PayPal token Ui component provider
+ */
+class TokenUiComponentProviderTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var TokenUiComponentInterfaceFactory|MockObject
+     */
+    private $componentFactory;
+
+    /**
+     * @var UrlInterface|MockObject
+     */
+    private $urlBuilder;
+
+    /**
+     * @var Config|MockObject
+     */
+    private $config;
+
+    /**
+     * @var TokenUiComponentProvider
+     */
+    private $tokenUiComponentProvider;
+
+    protected function setUp()
+    {
+        $this->componentFactory = $this->getMockBuilder(TokenUiComponentInterfaceFactory::class)
+            ->disableOriginalConstructor()
+            ->setMethods(['create'])
+            ->getMock();
+
+        $this->urlBuilder = $this->getMock(UrlInterface::class);
+
+        $this->config = $this->getMockBuilder(Config::class)
+            ->disableOriginalConstructor()
+            ->setMethods(['getPayPalIcon'])
+            ->getMock();
+
+        $this->tokenUiComponentProvider = new TokenUiComponentProvider(
+            $this->componentFactory,
+            $this->urlBuilder,
+            $this->config
+        );
+    }
+
+    /**
+     * @covers \Magento\Braintree\Model\Ui\Adminhtml\PayPal\TokenUiComponentProvider::getComponentForToken
+     */
+    public function testGetComponentForToken()
+    {
+        $nonceUrl = 'https://payment/adminhtml/nonce/url';
+        $payerEmail = 'john.doe@test.com';
+        $icon = [
+            'url' => 'https://payment/adminhtml/icon.png',
+            'width' => 48,
+            'height' => 32
+        ];
+
+        $expected = [
+            'code' => 'vault',
+            'nonceUrl' => $nonceUrl,
+            'details' => [
+                'payerEmail' => $payerEmail,
+                'icon' => $icon
+            ],
+            'template' => 'vault.phtml'
+        ];
+
+        $this->config->expects(static::once())
+            ->method('getPayPalIcon')
+            ->willReturn($icon);
+
+        $paymentToken = $this->getMock(PaymentTokenInterface::class);
+        $paymentToken->expects(static::once())
+            ->method('getTokenDetails')
+            ->willReturn('{"payerEmail":" ' . $payerEmail . '"}');
+        $paymentToken->expects(static::once())
+            ->method('getPublicHash')
+            ->willReturn('cmk32dl21l');
+
+        $this->urlBuilder->expects(static::once())
+            ->method('getUrl')
+            ->willReturn($nonceUrl);
+
+        $tokenComponent = $this->getMock(TokenUiComponentInterface::class);
+        $tokenComponent->expects(static::once())
+            ->method('getConfig')
+            ->willReturn($expected);
+
+        $this->componentFactory->expects(static::once())
+            ->method('create')
+            ->willReturn($tokenComponent);
+
+        $component = $this->tokenUiComponentProvider->getComponentForToken($paymentToken);
+        static::assertEquals($tokenComponent, $component);
+        static::assertEquals($expected, $component->getConfig());
+    }
+}
diff --git a/app/code/Magento/Braintree/Test/Unit/Model/Ui/Adminhtml/TokenUiComponentProviderTest.php b/app/code/Magento/Braintree/Test/Unit/Model/Ui/Adminhtml/TokenUiComponentProviderTest.php
index d1665c71804cfa0c4ce8d1a6d2db96e09afd932c..f159136cf4c460d43b9191b58b536ff646da8b9c 100644
--- a/app/code/Magento/Braintree/Test/Unit/Model/Ui/Adminhtml/TokenUiComponentProviderTest.php
+++ b/app/code/Magento/Braintree/Test/Unit/Model/Ui/Adminhtml/TokenUiComponentProviderTest.php
@@ -7,10 +7,10 @@ namespace Magento\Braintree\Test\Unit\Model\Ui\Adminhtml;
 
 use Magento\Braintree\Model\Ui\Adminhtml\TokenUiComponentProvider;
 use Magento\Framework\UrlInterface;
-use Magento\Framework\View\Element\Template;
 use Magento\Vault\Api\Data\PaymentTokenInterface;
 use Magento\Vault\Model\Ui\TokenUiComponentInterface;
 use Magento\Vault\Model\Ui\TokenUiComponentInterfaceFactory;
+use PHPUnit_Framework_MockObject_MockObject as MockObject;
 
 /**
  * Class TokenUiComponentProviderTest
@@ -19,12 +19,12 @@ class TokenUiComponentProviderTest extends \PHPUnit_Framework_TestCase
 {
 
     /**
-     * @var TokenUiComponentInterfaceFactory|\PHPUnit_Framework_MockObject_MockObject
+     * @var TokenUiComponentInterfaceFactory|MockObject
      */
     private $componentFactory;
 
     /**
-     * @var UrlInterface|\PHPUnit_Framework_MockObject_MockObject
+     * @var UrlInterface|MockObject
      */
     private $urlBuilder;
 
@@ -59,6 +59,7 @@ class TokenUiComponentProviderTest extends \PHPUnit_Framework_TestCase
         $expirationDate = '12/2015';
 
         $expected = [
+            'code' => 'vault',
             'nonceUrl' => $nonceUrl,
             'details' => [
                 'type' => $type,
diff --git a/app/code/Magento/Braintree/composer.json b/app/code/Magento/Braintree/composer.json
index 3b77e208837a4a4341baabbae615b7e35b266500..91cacf6add2b891dc4ad759cb6b1e9a6990cb397 100644
--- a/app/code/Magento/Braintree/composer.json
+++ b/app/code/Magento/Braintree/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-braintree",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/framework": "100.2.*",
         "magento/magento-composer-installer": "*",
         "magento/module-config": "100.2.*",
diff --git a/app/code/Magento/Braintree/etc/adminhtml/di.xml b/app/code/Magento/Braintree/etc/adminhtml/di.xml
index f252b977f20bd8b8616c7ddd90c08dd7ad0c5435..d154aabbb01b5cdd9db9beba05481c167fbec65d 100644
--- a/app/code/Magento/Braintree/etc/adminhtml/di.xml
+++ b/app/code/Magento/Braintree/etc/adminhtml/di.xml
@@ -47,6 +47,7 @@
         <arguments>
             <argument name="tokenUiComponentProviders" xsi:type="array">
                 <item name="braintree" xsi:type="object">Magento\Braintree\Model\Ui\Adminhtml\TokenUiComponentProvider</item>
+                <item name="braintree_paypal" xsi:type="object">Magento\Braintree\Model\Ui\Adminhtml\PayPal\TokenUiComponentProvider</item>
             </argument>
         </arguments>
     </type>
diff --git a/app/code/Magento/Braintree/etc/config.xml b/app/code/Magento/Braintree/etc/config.xml
index 095a8419c8529f20beb5f9a2be4499bade1f1301..bf19324ae7a0225b82106f26f291462b9d1e0b12 100644
--- a/app/code/Magento/Braintree/etc/config.xml
+++ b/app/code/Magento/Braintree/etc/config.xml
@@ -71,7 +71,8 @@
             </braintree_cc_vault>
             <braintree_paypal_vault>
                 <model>BraintreePayPalVaultFacade</model>
-                <title>Vault Token (Braintree PayPal)</title>
+                <title>Stored Accounts (Braintree PayPal)</title>
+                <can_use_internal>1</can_use_internal>
             </braintree_paypal_vault>
         </payment>
     </default>
diff --git a/app/code/Magento/Braintree/view/adminhtml/layout/sales_order_create_index.xml b/app/code/Magento/Braintree/view/adminhtml/layout/sales_order_create_index.xml
index 571c5ededeb993fd0e45d91cc2d1512d531179de..5e4f36e1c1fb4d4916e620cb440829357b1071ea 100644
--- a/app/code/Magento/Braintree/view/adminhtml/layout/sales_order_create_index.xml
+++ b/app/code/Magento/Braintree/view/adminhtml/layout/sales_order_create_index.xml
@@ -18,6 +18,10 @@
                 <argument name="method" xsi:type="string">braintree_cc_vault</argument>
                 <argument name="template" xsi:type="string">Magento_Vault::form/vault.phtml</argument>
             </action>
+            <action method="setMethodFormTemplate">
+                <argument name="method" xsi:type="string">braintree_paypal_vault</argument>
+                <argument name="template" xsi:type="string">Magento_Vault::form/vault.phtml</argument>
+            </action>
         </referenceBlock>
         <referenceBlock name="content">
             <block name="braintree_payment_script"
diff --git a/app/code/Magento/Braintree/view/adminhtml/layout/sales_order_create_load_block_billing_method.xml b/app/code/Magento/Braintree/view/adminhtml/layout/sales_order_create_load_block_billing_method.xml
index 68e0abc0cd009d9c2a30dff4cb545aa1b85f151c..579b82c61f690ed59bf94423e4aab00348a1546e 100644
--- a/app/code/Magento/Braintree/view/adminhtml/layout/sales_order_create_load_block_billing_method.xml
+++ b/app/code/Magento/Braintree/view/adminhtml/layout/sales_order_create_load_block_billing_method.xml
@@ -18,6 +18,10 @@
                 <argument name="method" xsi:type="string">braintree_cc_vault</argument>
                 <argument name="template" xsi:type="string">Magento_Vault::form/vault.phtml</argument>
             </action>
+            <action method="setMethodFormTemplate">
+                <argument name="method" xsi:type="string">braintree_paypal_vault</argument>
+                <argument name="template" xsi:type="string">Magento_Vault::form/vault.phtml</argument>
+            </action>
         </referenceBlock>
     </body>
 </page>
\ No newline at end of file
diff --git a/app/code/Magento/Braintree/view/adminhtml/templates/form/paypal/vault.phtml b/app/code/Magento/Braintree/view/adminhtml/templates/form/paypal/vault.phtml
new file mode 100644
index 0000000000000000000000000000000000000000..22930bbc656660efb6f5981fd2fb8e137ac591df
--- /dev/null
+++ b/app/code/Magento/Braintree/view/adminhtml/templates/form/paypal/vault.phtml
@@ -0,0 +1,30 @@
+<?php
+use Magento\Vault\Model\Ui\TokenUiComponentProviderInterface;
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+// @codingStandardsIgnoreFile
+
+/** @var \Magento\Framework\View\Element\Template $block */
+$details = $block->getData(TokenUiComponentProviderInterface::COMPONENT_DETAILS);
+$icon = $details['icon'];
+$id = $block->escapeHtml($block->getData('id'));
+?>
+<div data-mage-init='{
+        "Magento_Braintree/js/vault": {
+            "container": "payment_<?php /* @noEscape */ echo $id; ?>",
+            "publicHash": "<?php echo $block->escapeHtml($block->getData(TokenUiComponentProviderInterface::COMPONENT_PUBLIC_HASH)); ?>",
+            "code": "<?php echo $block->escapeHtml($block->getData('code')); ?>",
+            "nonceUrl": "<?php echo $block->escapeUrl($block->getData('nonceUrl')); ?>"
+        }
+    }' id="payment_<?php /* @noEscape */ echo $id;?>" class="admin__field">
+    <div class="admin__field-control control">
+        <input type="radio" id="token_switcher_<?php /* @noEscape */ echo $id; ?>" name="payment[token_switcher]"/>
+        <img src="<?php echo $block->escapeUrl($icon['url']); ?>"
+             width="<?php echo $block->escapeHtml($icon['width']); ?>"
+             height="<?php echo $block->escapeHtml($icon['height']); ?>"
+             class="payment-icon" >
+        <span><?php echo $block->escapeHtml($details['payerEmail']); ?></span>
+    </div>
+</div>
diff --git a/app/code/Magento/Braintree/view/adminhtml/templates/form/vault.phtml b/app/code/Magento/Braintree/view/adminhtml/templates/form/vault.phtml
index 38114618847259c143ec2794d13ccaf5a5ff1349..001422d4bf911a40094d2174f9bb346866175c59 100644
--- a/app/code/Magento/Braintree/view/adminhtml/templates/form/vault.phtml
+++ b/app/code/Magento/Braintree/view/adminhtml/templates/form/vault.phtml
@@ -7,7 +7,7 @@ use Magento\Vault\Model\Ui\TokenUiComponentProviderInterface;
 // @codingStandardsIgnoreFile
 
 /** @var \Magento\Framework\View\Element\Template $block */
-$details = $block->getData('details');
+$details = $block->getData(TokenUiComponentProviderInterface::COMPONENT_DETAILS);
 $icon = $block->getData('icons')[$details['type']];
 $id = $block->escapeHtml($block->getData('id'));
 ?>
@@ -15,6 +15,7 @@ $id = $block->escapeHtml($block->getData('id'));
         "Magento_Braintree/js/vault": {
             "container": "payment_<?php /* @noEscape */ echo $id; ?>",
             "publicHash": "<?php echo $block->escapeHtml($block->getData(TokenUiComponentProviderInterface::COMPONENT_PUBLIC_HASH)); ?>",
+            "code": "<?php echo $block->escapeHtml($block->getData('code')); ?>",
             "nonceUrl": "<?php echo $block->escapeUrl($block->getData('nonceUrl')); ?>"
         }
     }' id="payment_<?php /* @noEscape */ echo $id;?>" class="admin__field">
diff --git a/app/code/Magento/Braintree/view/adminhtml/web/js/vault.js b/app/code/Magento/Braintree/view/adminhtml/web/js/vault.js
index fcff173e7fcd44f714a6ec9f4282f838b04654aa..ea832acb537e0051e34f976c050c9b8bd7d289b7 100644
--- a/app/code/Magento/Braintree/view/adminhtml/web/js/vault.js
+++ b/app/code/Magento/Braintree/view/adminhtml/web/js/vault.js
@@ -14,7 +14,8 @@ define([
     return Class.extend({
         defaults: {
             $selector: null,
-            selector: 'edit_form'
+            selector: 'edit_form',
+            $container: null
         },
 
         /**
@@ -25,17 +26,18 @@ define([
             var self = this;
 
             self.$selector = $('#' + self.selector);
+            self.$container =  $('#' + self.container);
             self.$selector.on(
                 'setVaultNotActive',
                 function () {
-                    self.$selector.off('submitOrder.braintree_vault');
+                    self.$selector.off('submitOrder.' + self.getCode());
                 }
             );
-            this._super();
+            self._super();
 
-            this.initEventHandlers();
+            self.initEventHandlers();
 
-            return this;
+            return self;
         },
 
         /**
@@ -43,14 +45,14 @@ define([
          * @returns {String}
          */
         getCode: function () {
-            return 'braintree';
+            return this.code;
         },
 
         /**
          * Init event handlers
          */
         initEventHandlers: function () {
-            $('#' + this.container).find('[name="payment[token_switcher]"]')
+            $(this.$container).find('[name="payment[token_switcher]"]')
                 .on('click', this.selectPaymentMethod.bind(this));
         },
 
@@ -66,7 +68,7 @@ define([
          * Enable form event listeners
          */
         enableEventListeners: function () {
-            this.$selector.on('submitOrder.braintree_vault', this.submitOrder.bind(this));
+            this.$selector.on('submitOrder.' + this.getCode(), this.submitOrder.bind(this));
         },
 
         /**
@@ -129,7 +131,7 @@ define([
             this.createPublicHashSelector();
 
             this.$selector.find('[name="payment[public_hash]"]').val(this.publicHash);
-            this.$selector.find('#braintree_nonce').val(nonce);
+            this.$container.find('#' + this.getNonceSelectorName()).val(nonce);
         },
 
         /**
@@ -138,16 +140,16 @@ define([
         createPublicHashSelector: function () {
             var $input;
 
-            if (this.$selector.find('#braintree_nonce').size() === 0) {
+            if (this.$container.find('#' + this.getNonceSelectorName()).size() === 0) {
                 $input = $('<input>').attr(
                     {
                         type: 'hidden',
-                        id: 'braintree_nonce',
+                        id: this.getNonceSelectorName(),
                         name: 'payment[payment_method_nonce]'
                     }
                 );
 
-                $input.appendTo(this.$selector);
+                $input.appendTo(this.$container);
                 $input.prop('disabled', false);
             }
         },
@@ -160,6 +162,14 @@ define([
             alert({
                 content: message
             });
+        },
+
+        /**
+         * Get selector name for nonce input
+         * @returns {String}
+         */
+        getNonceSelectorName: function () {
+            return 'nonce_' + this.getCode();
         }
     });
 });
diff --git a/app/code/Magento/Braintree/view/frontend/web/js/view/payment/method-renderer/paypal.js b/app/code/Magento/Braintree/view/frontend/web/js/view/payment/method-renderer/paypal.js
index 184260c39e954d1c5a1fd6d45b34f09fcab9daa7..075a1fdaf1fc118f42832fa438762715420a585a 100644
--- a/app/code/Magento/Braintree/view/frontend/web/js/view/payment/method-renderer/paypal.js
+++ b/app/code/Magento/Braintree/view/frontend/web/js/view/payment/method-renderer/paypal.js
@@ -98,7 +98,6 @@ define([
             quote.totals.subscribe(function () {
                 if (self.grandTotalAmount !== quote.totals()['base_grand_total']) {
                     self.grandTotalAmount = quote.totals()['base_grand_total'];
-                    self.reInitPayPal();
                 }
             });
 
diff --git a/app/code/Magento/Bundle/Block/Catalog/Product/View/Type/Bundle.php b/app/code/Magento/Bundle/Block/Catalog/Product/View/Type/Bundle.php
index b349d7da577a4056c86e04e7293cc53a7406a4d8..30b0d6f2ac72cff0062ed5dec33dd8498c696200 100644
--- a/app/code/Magento/Bundle/Block/Catalog/Product/View/Type/Bundle.php
+++ b/app/code/Magento/Bundle/Block/Catalog/Product/View/Type/Bundle.php
@@ -78,9 +78,14 @@ class Bundle extends \Magento\Catalog\Block\Product\View\AbstractView
     }
 
     /**
+     * Returns the bundle product options
+     * Will return cached options data if the product options are already initialized
+     * In a case when $stripSelection parameter is true will reload stored bundle selections collection from DB
+     *
+     * @param bool $stripSelection
      * @return array
      */
-    public function getOptions()
+    public function getOptions($stripSelection = false)
     {
         if (!$this->options) {
             $product = $this->getProduct();
@@ -96,7 +101,7 @@ class Bundle extends \Magento\Catalog\Block\Product\View\AbstractView
 
             $this->options = $optionCollection->appendSelections(
                 $selectionCollection,
-                false,
+                $stripSelection,
                 $this->catalogProduct->getSkipSaleableCheck()
             );
         }
diff --git a/app/code/Magento/Bundle/Setup/InstallSchema.php b/app/code/Magento/Bundle/Setup/InstallSchema.php
index 6f98cd386327a182243b4348fa6dc0d02f56cd4e..5c7d5a47da616e801a3dc0e2fc05ab3d0eb69c04 100644
--- a/app/code/Magento/Bundle/Setup/InstallSchema.php
+++ b/app/code/Magento/Bundle/Setup/InstallSchema.php
@@ -24,7 +24,9 @@ class InstallSchema implements InstallSchemaInterface
         $installer = $setup;
 
         $installer->startSetup();
-
+        $customerGroupTable = $setup->getConnection()->describeTable($setup->getTable('customer_group'));
+        $customerGroupIdType = $customerGroupTable['customer_group_id']['DATA_TYPE'] == 'int'
+            ? \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER : $customerGroupTable['customer_group_id']['DATA_TYPE'];
         /**
          * Create table 'catalog_product_bundle_option'
          */
@@ -340,7 +342,7 @@ class InstallSchema implements InstallSchemaInterface
             )
             ->addColumn(
                 'customer_group_id',
-                \Magento\Framework\DB\Ddl\Table::TYPE_SMALLINT,
+                $customerGroupIdType,
                 null,
                 ['unsigned' => true, 'nullable' => false, 'primary' => true],
                 'Customer Group Id'
diff --git a/app/code/Magento/Bundle/Setup/UpgradeSchema.php b/app/code/Magento/Bundle/Setup/UpgradeSchema.php
old mode 100644
new mode 100755
index e48ad97922dc99540f8e4d9b0fb8450d2d023365..ced66a03a3a865cc14e1050d2df94df5c1762ad0
--- a/app/code/Magento/Bundle/Setup/UpgradeSchema.php
+++ b/app/code/Magento/Bundle/Setup/UpgradeSchema.php
@@ -44,6 +44,24 @@ class UpgradeSchema implements UpgradeSchemaInterface
             }
         }
 
+        if (version_compare($context->getVersion(), '2.0.3', '<')) {
+            $tables = [
+                'catalog_product_index_price_bundle_idx',
+                'catalog_product_index_price_bundle_opt_idx',
+                'catalog_product_index_price_bundle_opt_tmp',
+                'catalog_product_index_price_bundle_sel_idx',
+                'catalog_product_index_price_bundle_sel_tmp',
+                'catalog_product_index_price_bundle_tmp',
+            ];
+            foreach ($tables as $table) {
+                $setup->getConnection()->modifyColumn(
+                    $setup->getTable($table),
+                    'customer_group_id',
+                    ['type' => 'integer', 'nullable' => false]
+                );
+            }
+        }
+
         $setup->endSetup();
     }
 }
diff --git a/app/code/Magento/Bundle/Test/Unit/Block/Catalog/Product/View/Type/BundleTest.php b/app/code/Magento/Bundle/Test/Unit/Block/Catalog/Product/View/Type/BundleTest.php
index 362394ccd8bd1ddb245f17d27047fddb094f107d..f11fc30f5b28f90ec7f1a2c13a9b40b714f7cebe 100644
--- a/app/code/Magento/Bundle/Test/Unit/Block/Catalog/Product/View/Type/BundleTest.php
+++ b/app/code/Magento/Bundle/Test/Unit/Block/Catalog/Product/View/Type/BundleTest.php
@@ -19,32 +19,34 @@ class BundleTest extends \PHPUnit_Framework_TestCase
     /** @var  \Magento\Bundle\Model\Product\PriceFactory|\PHPUnit_Framework_MockObject_MockObject */
     private $bundleProductPriceFactory;
 
-    /**
-     * @var \Magento\Framework\TestFramework\Unit\Helper\ObjectManager
-     */
-    protected $_objectHelper;
+    /** @var \Magento\Framework\Json\Encoder|\PHPUnit_Framework_MockObject_MockObject */
+    private $jsonEncoder;
+
+    /** @var \Magento\Catalog\Helper\Product|\PHPUnit_Framework_MockObject_MockObject */
+    private $catalogProduct;
 
     /**
-     * @var \Magento\Bundle\Block\Catalog\Product\View\Type\Bundle
+     * @var \Magento\Framework\Event\ManagerInterface|\PHPUnit_Framework_MockObject_MockObject
      */
-    protected $_bundleBlock;
+    private $eventManager;
 
     /** @var  \Magento\Catalog\Model\Product|\PHPUnit_Framework_MockObject_MockObject */
     private $product;
 
+    /**
+     * @var \Magento\Bundle\Block\Catalog\Product\View\Type\Bundle
+     */
+    private $bundleBlock;
+
     protected function setUp()
     {
         $objectHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
+
         $this->bundleProductPriceFactory = $this->getMockBuilder(\Magento\Bundle\Model\Product\PriceFactory::class)
             ->disableOriginalConstructor()
             ->setMethods(['create'])
             ->getMock();
-        $this->_bundleBlock = $objectHelper->getObject(
-            \Magento\Bundle\Block\Catalog\Product\View\Type\Bundle::class,
-            [
-                'productPrice' => $this->bundleProductPriceFactory
-            ]
-        );
+
         $this->product = $this->getMockBuilder(\Magento\Catalog\Model\Product::class)
             ->disableOriginalConstructor()
             ->setMethods(
@@ -57,45 +59,78 @@ class BundleTest extends \PHPUnit_Framework_TestCase
                     'getPreconfiguredValues'
                 ]
             )->getMock();
+        $registry = $this->getMockBuilder(\Magento\Framework\Registry::class)
+            ->disableOriginalConstructor()
+            ->setMethods(['registry'])
+            ->getMock();
+        $registry->expects($this->any())
+            ->method('registry')
+            ->willReturn($this->product);
+        $this->eventManager = $this->getMockBuilder(\Magento\Framework\Event\ManagerInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->jsonEncoder = $this->getMockBuilder(\Magento\Framework\Json\Encoder::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->catalogProduct = $this->getMockBuilder(\Magento\Catalog\Helper\Product::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        /** @var $bundleBlock BundleBlock */
+        $this->bundleBlock = $objectHelper->getObject(
+            \Magento\Bundle\Block\Catalog\Product\View\Type\Bundle::class,
+            [
+                'registry' => $registry,
+                'eventManager' => $this->eventManager,
+                'jsonEncoder' => $this->jsonEncoder,
+                'productPrice' => $this->bundleProductPriceFactory,
+                'catalogProduct' => $this->catalogProduct
+            ]
+        );
     }
 
     public function testGetOptionHtmlNoRenderer()
     {
-        $option = $this->getMock(\Magento\Bundle\Model\Option::class, ['getType', '__wakeup'], [], '', false);
-        $option->expects($this->exactly(2))->method('getType')->will($this->returnValue('checkbox'));
+        $option = $this->getMockBuilder(\Magento\Bundle\Model\Option::class)
+            ->setMethods(['getType'])
+            ->disableOriginalConstructor()
+            ->getMock();
+        $option->expects($this->any())->method('getType')->willReturn('checkbox');
+
+        $layout = $this->getMockBuilder(\Magento\Framework\View\Layout::class)
+            ->setMethods(['getChildName', 'getBlock'])
+            ->disableOriginalConstructor()
+            ->getMock();
+        $layout->expects($this->any())->method('getChildName')->willReturn(false);
+        $this->bundleBlock->setLayout($layout);
 
         $this->assertEquals(
             'There is no defined renderer for "checkbox" option type.',
-            $this->_bundleBlock->getOptionHtml($option)
+            $this->bundleBlock->getOptionHtml($option)
         );
     }
 
     public function testGetOptionHtml()
     {
-        $option = $this->getMock(\Magento\Bundle\Model\Option::class, ['getType', '__wakeup'], [], '', false);
-        $option->expects($this->exactly(1))->method('getType')->will($this->returnValue('checkbox'));
-
-        $optionBlock = $this->getMock(
-            \Magento\Bundle\Block\Catalog\Product\View\Type\Bundle\Option\Checkbox::class,
-            ['setOption', 'toHtml'],
-            [],
-            '',
-            false
-        );
-        $optionBlock->expects($this->any())->method('setOption')->will($this->returnValue($optionBlock));
-        $optionBlock->expects($this->any())->method('toHtml')->will($this->returnValue('option html'));
-        $layout = $this->getMock(
-            \Magento\Framework\View\Layout::class,
-            ['getChildName', 'getBlock'],
-            [],
-            '',
-            false
-        );
-        $layout->expects($this->any())->method('getChildName')->will($this->returnValue('name'));
-        $layout->expects($this->any())->method('getBlock')->will($this->returnValue($optionBlock));
-        $this->_bundleBlock->setLayout($layout);
+        $option = $this->getMockBuilder(\Magento\Bundle\Model\Option::class)
+            ->setMethods(['getType'])
+            ->disableOriginalConstructor()
+            ->getMock();
+        $option->expects($this->once())->method('getType')->willReturn('checkbox');
+
+        $optionBlock = $this->getMockBuilder(
+            \Magento\Bundle\Block\Catalog\Product\View\Type\Bundle\Option\Checkbox::class
+        )->setMethods(['setOption', 'toHtml'])->disableOriginalConstructor()->getMock();
+        $optionBlock->expects($this->any())->method('setOption')->willReturnSelf();
+        $optionBlock->expects($this->any())->method('toHtml')->willReturn('option html');
+        $layout = $this->getMockBuilder(\Magento\Framework\View\Layout::class)
+            ->setMethods(['getChildName', 'getBlock'])
+            ->disableOriginalConstructor()
+            ->getMock();
+        $layout->expects($this->any())->method('getChildName')->willReturn('name');
+        $layout->expects($this->any())->method('getBlock')->willReturn($optionBlock);
+        $this->bundleBlock->setLayout($layout);
 
-        $this->assertEquals('option html', $this->_bundleBlock->getOptionHtml($option));
+        $this->assertEquals('option html', $this->bundleBlock->getOptionHtml($option));
     }
 
     public function testGetJsonConfigFixedPriceBundleNoOption()
@@ -127,12 +162,12 @@ class BundleTest extends \PHPUnit_Framework_TestCase
         ];
         $priceInfo = $this->getPriceInfoMock($prices);
 
-        $this->_bundleBlock = $this->setupBundleBlock(
+        $this->updateBundleBlock(
             $options,
             $priceInfo,
             \Magento\Bundle\Model\Product\Price::PRICE_TYPE_FIXED
         );
-        $jsonConfig = $this->_bundleBlock->getJsonConfig();
+        $jsonConfig = $this->bundleBlock->getJsonConfig();
         $this->assertEquals(110, $jsonConfig['prices']['oldPrice']['amount']);
         $this->assertEquals(100, $jsonConfig['prices']['basePrice']['amount']);
         $this->assertEquals(100, $jsonConfig['prices']['finalPrice']['amount']);
@@ -162,14 +197,14 @@ class BundleTest extends \PHPUnit_Framework_TestCase
         $bundleProductPrice->expects($this->at(0))
             ->method('getLowestPrice')
             ->with($this->product, $baseAmount)
-            ->will($this->returnValue(999));
+            ->willReturn(999);
         $bundleProductPrice->expects($this->at(1))
             ->method('getLowestPrice')
             ->with($this->product, $basePriceValue)
-            ->will($this->returnValue(888));
+            ->willReturn(888);
         $this->bundleProductPriceFactory->expects($this->once())
             ->method('create')
-            ->will($this->returnValue($bundleProductPrice));
+            ->willReturn($bundleProductPrice);
 
         $options = [
             $this->createOption(1, 'Title `1', $selections),
@@ -207,7 +242,7 @@ class BundleTest extends \PHPUnit_Framework_TestCase
 
         $this->product->expects($this->once())
             ->method('hasPreconfiguredValues')
-            ->will($this->returnValue(true));
+            ->willReturn(true);
         $preconfiguredValues = new \Magento\Framework\DataObject(
             [
                 'bundle_option' => [
@@ -217,14 +252,14 @@ class BundleTest extends \PHPUnit_Framework_TestCase
         );
         $this->product->expects($this->once())
             ->method('getPreconfiguredValues')
-            ->will($this->returnValue($preconfiguredValues));
+            ->willReturn($preconfiguredValues);
 
-        $this->_bundleBlock = $this->setupBundleBlock(
+        $this->updateBundleBlock(
             $options,
             $priceInfo,
             \Magento\Bundle\Model\Product\Price::PRICE_TYPE_FIXED
         );
-        $jsonConfig = $this->_bundleBlock->getJsonConfig();
+        $jsonConfig = $this->bundleBlock->getJsonConfig();
         $this->assertEquals(110, $jsonConfig['prices']['oldPrice']['amount']);
         $this->assertEquals(100, $jsonConfig['prices']['basePrice']['amount']);
         $this->assertEquals(100, $jsonConfig['prices']['finalPrice']['amount']);
@@ -236,86 +271,38 @@ class BundleTest extends \PHPUnit_Framework_TestCase
      * @param string $priceType
      * @return BundleBlock
      */
-    private function setupBundleBlock($options, $priceInfo, $priceType)
+    private function updateBundleBlock($options, $priceInfo, $priceType)
     {
-        $objectHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
-
-
-        $eventManager = $this->getMockBuilder(\Magento\Framework\Event\Manager::class)
-            ->disableOriginalConstructor()
-            ->getMock();
-        $eventManager->expects($this->any())->method('dispatch')->will($this->returnValue(true));
-
+        $this->eventManager->expects($this->any())->method('dispatch')->willReturn(true);
         $optionCollection = $this->getMockBuilder(\Magento\Bundle\Model\ResourceModel\Option\Collection::class)
             ->disableOriginalConstructor()
             ->getMock();
         $optionCollection->expects($this->any())
             ->method('appendSelections')
-            ->will($this->returnValue($options));
+            ->willReturn($options);
 
         $typeInstance = $this->getMockBuilder(\Magento\Bundle\Model\Product\Type::class)
             ->disableOriginalConstructor()
             ->getMock();
         $typeInstance->expects($this->any())
             ->method('getOptionsCollection')
-            ->will($this->returnValue($optionCollection));
+            ->willReturn($optionCollection);
         $typeInstance->expects($this->any())
             ->method('getStoreFilter')
-            ->will($this->returnValue(true));
+            ->willReturn(true);
 
         $this->product->expects($this->any())
             ->method('getTypeInstance')
-            ->will($this->returnValue($typeInstance));
+            ->willReturn($typeInstance);
         $this->product->expects($this->any())
             ->method('getPriceInfo')
-            ->will($this->returnValue($priceInfo));
+            ->willReturn($priceInfo);
         $this->product->expects($this->any())
             ->method('getPriceType')
-            ->will($this->returnValue($priceType));
-
-        $registry = $this->getMockBuilder(\Magento\Framework\Registry::class)
-            ->disableOriginalConstructor()
-            ->setMethods(['registry'])
-            ->getMock();
-        $registry->expects($this->once())
-            ->method('registry')
-            ->will($this->returnValue($this->product));
-
-        $taxHelperMock = $this->getMockBuilder(\Magento\Tax\Helper\Data::class)
-            ->disableOriginalConstructor()
-            ->getMock();
-
-        $context = $this->getMockBuilder(\Magento\Catalog\Block\Product\Context::class)
-            ->disableOriginalConstructor()
-            ->getMock();
-        $context->expects($this->any())
-            ->method('getRegistry')
-            ->will($this->returnValue($registry));
-        $context->expects($this->any())
-            ->method('getTaxData')
-            ->will($this->returnValue($taxHelperMock));
-        $context->expects($this->any())
-            ->method('getEventManager')
-            ->will($this->returnValue($eventManager));
-
-        $jsonEncoderMock = $this->getMockBuilder(\Magento\Framework\Json\Encoder::class)
-            ->disableOriginalConstructor()
-            ->getMock();
-        $jsonEncoderMock->expects($this->any())
+            ->willReturn($priceType);
+        $this->jsonEncoder->expects($this->any())
             ->method('encode')
             ->will($this->returnArgument(0));
-
-        /** @var $bundleBlock BundleBlock */
-        $bundleBlock = $objectHelper->getObject(
-            \Magento\Bundle\Block\Catalog\Product\View\Type\Bundle::class,
-            [
-                'context' => $context,
-                'jsonEncoder' => $jsonEncoderMock,
-                'productPrice' => $this->bundleProductPriceFactory
-            ]
-        );
-
-        return $bundleBlock;
     }
 
     private function getPriceInfoMock($price)
@@ -331,13 +318,13 @@ class BundleTest extends \PHPUnit_Framework_TestCase
                 $priceInfoMock->expects($this->at($counter))
                     ->method('getPrice')
                     ->with($priceType)
-                    ->will($this->returnValue($priceValue));
+                    ->willReturn($priceValue);
                 $counter++;
             }
         } else {
             $priceInfoMock->expects($this->any())
                 ->method('getPrice')
-                ->will($this->returnValue($price));
+                ->willReturn($price);
         }
         return $priceInfoMock;
     }
@@ -355,7 +342,7 @@ class BundleTest extends \PHPUnit_Framework_TestCase
         foreach ($prices as $methodName => $amount) {
             $priceMock->expects($this->any())
                 ->method($methodName)
-                ->will($this->returnValue($amount));
+                ->willReturn($amount);
         }
 
         return $priceMock;
@@ -373,8 +360,8 @@ class BundleTest extends \PHPUnit_Framework_TestCase
             ->disableOriginalConstructor()
             ->setMethods(['getValue', 'getBaseAmount', 'getOptionSelectionAmount'])
             ->getMockForAbstractClass();
-        $amountPrice->expects($this->any())->method('getValue')->will($this->returnValue($value));
-        $amountPrice->expects($this->any())->method('getBaseAmount')->will($this->returnValue($baseAmount));
+        $amountPrice->expects($this->any())->method('getValue')->willReturn($value);
+        $amountPrice->expects($this->any())->method('getBaseAmount')->willReturn($baseAmount);
         foreach ($selectionAmounts as $selectionAmount) {
             $amountPrice->expects($this->any())
                 ->method('getOptionSelectionAmount')
@@ -414,7 +401,6 @@ class BundleTest extends \PHPUnit_Framework_TestCase
             ->disableOriginalConstructor()
             ->setMethods(
                 [
-                    '__wakeup',
                     'getId',
                     'getTitle',
                     'getSelections',
@@ -423,12 +409,12 @@ class BundleTest extends \PHPUnit_Framework_TestCase
                     'getIsDefault',
                 ]
             )
-            ->getMock();
-        $option->expects($this->any())->method('getId')->will($this->returnValue($id));
-        $option->expects($this->any())->method('getTitle')->will($this->returnValue($title));
-        $option->expects($this->any())->method('getSelections')->will($this->returnValue($selections));
-        $option->expects($this->any())->method('getType')->will($this->returnValue($type));
-        $option->expects($this->any())->method('getRequired')->will($this->returnValue($isRequired));
+            ->getMockForAbstractClass();
+        $option->expects($this->any())->method('getId')->willReturn($id);
+        $option->expects($this->any())->method('getTitle')->willReturn($title);
+        $option->expects($this->any())->method('getSelections')->willReturn($selections);
+        $option->expects($this->any())->method('getType')->willReturn($type);
+        $option->expects($this->any())->method('getRequired')->willReturn($isRequired);
         return $option;
     }
 
@@ -453,42 +439,72 @@ class BundleTest extends \PHPUnit_Framework_TestCase
     ) {
         $selection = $this->getMockBuilder(\Magento\Catalog\Model\Product::class)
             ->disableOriginalConstructor()
-            ->setMethods(
-                [
-                    'getSelectionId',
-                    'getSelectionQty',
-                    'getPriceInfo',
-                    'getSelectionCanChangeQty',
-                    'getName',
-                    'getIsDefault',
-                    'isSalable',
-                ]
-            )->getMock();
+            ->getMock();
         $tierPrice = $this->getMockBuilder(\Magento\Bundle\Pricing\Price\TierPrice::class)
             ->disableOriginalConstructor()
             ->setMethods(['getTierPriceList'])
             ->getMock();
-        $tierPrice->expects($this->any())
-            ->method('getTierPriceList')
-            ->will($this->returnValue($tierPriceList));
+        $tierPrice->expects($this->any())->method('getTierPriceList')->willReturn($tierPriceList);
         $priceInfo = $this->getMockBuilder(\Magento\Framework\Pricing\PriceInfo\Base::class)
             ->disableOriginalConstructor()
             ->setMethods(['getPrice'])
             ->getMock();
-        $priceInfo->expects($this->any())
-            ->method('getPrice')
-            ->will($this->returnValue($tierPrice));
-
-        $selection->expects($this->any())->method('getSelectionId')->will($this->returnValue($id));
-        $selection->expects($this->any())->method('getName')->will($this->returnValue($name));
-        $selection->expects($this->any())->method('getSelectionQty')->will($this->returnValue($qty));
-        $selection->expects($this->any())->method('getPriceInfo')->will($this->returnValue($priceInfo));
-        $selection->expects($this->any())->method('getSelectionCanChangeQty')->will(
-            $this->returnValue($isCanChangeQty)
-        );
-        $selection->expects($this->any())->method('getIsDefault')->will($this->returnValue($isDefault));
-        $selection->expects($this->any())->method('isSalable')->will($this->returnValue($isSalable));
+        $priceInfo->expects($this->any())->method('getPrice')->willReturn($tierPrice);
+        $selection->expects($this->any())->method('getSelectionId')->willReturn($id);
+        $selection->expects($this->any())->method('getName')->willReturn($name);
+        $selection->expects($this->any())->method('getSelectionQty')->willReturn($qty);
+        $selection->expects($this->any())->method('getPriceInfo')->willReturn($priceInfo);
+        $selection->expects($this->any())->method('getSelectionCanChangeQty')->willReturn($isCanChangeQty);
+        $selection->expects($this->any())->method('getIsDefault')->willReturn($isDefault);
+        $selection->expects($this->any())->method('isSalable')->willReturn($isSalable);
 
         return $selection;
     }
+
+    /**
+     * @dataProvider getOptionsDataProvider
+     * @param bool $stripSelection
+     */
+    public function testGetOptions($stripSelection)
+    {
+        $newOptions = ['option_1', 'option_2'];
+
+        $optionCollection = $this->getMockBuilder(\Magento\Bundle\Model\ResourceModel\Option\Collection::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $selectionConnection = $this->getMockBuilder(\Magento\Bundle\Model\ResourceModel\Selection\Collection::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $typeInstance = $this->getMockBuilder(\Magento\Bundle\Model\Product\Type::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $optionCollection->expects($this->any())->method('appendSelections')
+            ->with($selectionConnection, $stripSelection, true)
+            ->willReturn($newOptions);
+        $typeInstance->expects($this->any())->method('setStoreFilter')->with(0, $this->product)
+            ->willReturn($optionCollection);
+        $typeInstance->expects($this->any())->method('getStoreFilter')->willReturn(true);
+        $typeInstance->expects($this->any())->method('getOptionsCollection')->willReturn($optionCollection);
+        $typeInstance->expects($this->any())->method('getOptionsIds')->willReturn([1,2]);
+        $typeInstance->expects($this->once())->method('getSelectionsCollection')->with([1,2], $this->product)
+            ->willReturn($selectionConnection);
+        $this->product->expects($this->any())
+            ->method('getTypeInstance')->willReturn($typeInstance);
+        $this->product->expects($this->any())->method('getStoreId')  ->willReturn(0);
+        $this->catalogProduct->expects($this->once())->method('getSkipSaleableCheck')->willReturn(true);
+
+        $this->assertEquals($newOptions, $this->bundleBlock->getOptions($stripSelection));
+    }
+
+    /**
+     * @return array
+     */
+    public function getOptionsDataProvider()
+    {
+        return [
+            [true],
+            [false]
+        ];
+    }
 }
diff --git a/app/code/Magento/Bundle/Ui/DataProvider/Product/Form/Modifier/BundlePanel.php b/app/code/Magento/Bundle/Ui/DataProvider/Product/Form/Modifier/BundlePanel.php
index 50a3caaf68b3bd39ce1458e4883b4c1dd35c0525..538c80d9b1cf27af4ba14c911b0d0a6913c403c7 100644
--- a/app/code/Magento/Bundle/Ui/DataProvider/Product/Form/Modifier/BundlePanel.php
+++ b/app/code/Magento/Bundle/Ui/DataProvider/Product/Form/Modifier/BundlePanel.php
@@ -268,15 +268,12 @@ class BundlePanel extends AbstractModifier
             'arguments' => [
                 'data' => [
                     'config' => [
-                        'componentType' => 'dynamicRows',
+                        'componentType' => Container::NAME,
+                        'component' => 'Magento_Bundle/js/components/bundle-dynamic-rows',
                         'template' => 'ui/dynamic-rows/templates/collapsible',
-                        'label' => '',
                         'additionalClasses' => 'admin__field-wide',
-                        'collapsibleHeader' => true,
-                        'columnsHeader' => false,
-                        'deleteProperty' => false,
-                        'addButton' => false,
                         'dataScope' => 'data.bundle_options',
+                        'bundleSelectionsName' => 'product_bundle_container.bundle_selections'
                     ],
                 ],
             ],
@@ -318,14 +315,11 @@ class BundlePanel extends AbstractModifier
                                     'arguments' => [
                                         'data' => [
                                             'config' => [
-                                                'componentType' => DynamicRows::NAME,
-                                                'label' => '',
+                                                'componentType' => Container::NAME,
+                                                'component' => 'Magento_Bundle/js/components/bundle-dynamic-rows-grid',
                                                 'sortOrder' => 50,
                                                 'additionalClasses' => 'admin__field-wide',
-                                                'component' => 'Magento_Ui/js/dynamic-rows/dynamic-rows-grid',
                                                 'template' => 'ui/dynamic-rows/templates/default',
-                                                'columnsHeader' => false,
-                                                'columnsHeaderAfterRender' => true,
                                                 'provider' => 'product_form.product_form_data_source',
                                                 'dataProvider' => '${ $.dataScope }' . '.bundle_button_proxy',
                                                 'identificationDRProperty' => 'product_id',
@@ -343,8 +337,7 @@ class BundlePanel extends AbstractModifier
                                                     'selection_qty' => '',
                                                 ],
                                                 'links' => ['insertData' => '${ $.provider }:${ $.dataProvider }'],
-                                                'source' => 'product',
-                                                'addButton' => false,
+                                                'source' => 'product'
                                             ],
                                         ],
                                     ],
@@ -561,7 +554,7 @@ class BundlePanel extends AbstractModifier
                         'componentType' => Container::NAME,
                         'isTemplate' => true,
                         'component' => 'Magento_Ui/js/dynamic-rows/record',
-                        'is_collection' => true,
+                        'is_collection' => true
                     ],
                 ],
             ],
diff --git a/app/code/Magento/Bundle/composer.json b/app/code/Magento/Bundle/composer.json
index ab587044476db47c0a824cfdb130988f22591971..24756bdf950a7a42431e31cbc08090ca0141eb27 100644
--- a/app/code/Magento/Bundle/composer.json
+++ b/app/code/Magento/Bundle/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-bundle",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-store": "100.2.*",
         "magento/module-catalog": "101.1.*",
         "magento/module-tax": "100.2.*",
diff --git a/app/code/Magento/Bundle/etc/module.xml b/app/code/Magento/Bundle/etc/module.xml
index 982a33d00bc6b9dd94f57a5b3b2e4dbd41d719b9..34a88d4447cc3648a94f52c473831959111f5aed 100644
--- a/app/code/Magento/Bundle/etc/module.xml
+++ b/app/code/Magento/Bundle/etc/module.xml
@@ -6,7 +6,7 @@
  */
 -->
 <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
-    <module name="Magento_Bundle" setup_version="2.0.2">
+    <module name="Magento_Bundle" setup_version="2.0.3">
         <sequence>
             <module name="Magento_Catalog"/>
         </sequence>
diff --git a/app/code/Magento/Bundle/view/adminhtml/templates/product/composite/fieldset/options/bundle.phtml b/app/code/Magento/Bundle/view/adminhtml/templates/product/composite/fieldset/options/bundle.phtml
index f0cb656843bcac4075a0df0659d97c8c349d2c00..1272e13e42526f1849e0e61695338ef107172428 100644
--- a/app/code/Magento/Bundle/view/adminhtml/templates/product/composite/fieldset/options/bundle.phtml
+++ b/app/code/Magento/Bundle/view/adminhtml/templates/product/composite/fieldset/options/bundle.phtml
@@ -9,7 +9,7 @@
 ?>
 
 <?php /* @var $block \Magento\Bundle\Block\Adminhtml\Catalog\Product\Composite\Fieldset\Bundle */ ?>
-<?php $options = $block->decorateArray($block->getOptions()); ?>
+<?php $options = $block->decorateArray($block->getOptions(true)); ?>
 <?php if (count($options)): ?>
 <fieldset id="catalog_product_composite_configure_fields_bundle"
           class="fieldset admin__fieldset composite-bundle<?php echo $block->getIsLastFieldset() ? ' last-fieldset' : '' ?>">
diff --git a/app/code/Magento/Bundle/view/adminhtml/web/js/components/bundle-dynamic-rows-grid.js b/app/code/Magento/Bundle/view/adminhtml/web/js/components/bundle-dynamic-rows-grid.js
new file mode 100644
index 0000000000000000000000000000000000000000..e9a924e1cffe696688fed502bc715347c8afb8d2
--- /dev/null
+++ b/app/code/Magento/Bundle/view/adminhtml/web/js/components/bundle-dynamic-rows-grid.js
@@ -0,0 +1,59 @@
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+define([
+    'underscore',
+    'Magento_Ui/js/dynamic-rows/dynamic-rows-grid'
+], function (_, dynamicRowsGrid) {
+    'use strict';
+
+    return dynamicRowsGrid.extend({
+        defaults: {
+            label: '',
+            columnsHeader: false,
+            columnsHeaderAfterRender: true,
+            addButton: false
+        },
+
+        /**
+         * Initialize elements from grid
+         *
+         * @param {Array} data
+         *
+         * @returns {Object} Chainable.
+         */
+        initElements: function (data) {
+            var newData = this.getNewData(data),
+                recordIndex;
+
+            this.parsePagesData(data);
+
+            if (newData.length) {
+                if (this.insertData().length) {
+                    recordIndex = data.length - newData.length - 1;
+
+                    _.each(newData, function (newRecord) {
+                        this.processingAddChild(newRecord, ++recordIndex, newRecord[this.identificationProperty]);
+                    }, this);
+                }
+            }
+
+            return this;
+        },
+
+        /**
+         * Mapping value from grid
+         *
+         * @param {Array} data
+         */
+        mappingValue: function (data) {
+            if (_.isEmpty(data)) {
+                return;
+            }
+
+            this._super();
+        }
+    });
+});
diff --git a/app/code/Magento/Bundle/view/adminhtml/web/js/components/bundle-dynamic-rows.js b/app/code/Magento/Bundle/view/adminhtml/web/js/components/bundle-dynamic-rows.js
new file mode 100644
index 0000000000000000000000000000000000000000..b36d8003a399fb4af88d3e3cfab34559e2e80bea
--- /dev/null
+++ b/app/code/Magento/Bundle/view/adminhtml/web/js/components/bundle-dynamic-rows.js
@@ -0,0 +1,98 @@
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+define([
+    'underscore',
+    'mageUtils',
+    'uiRegistry',
+    'Magento_Ui/js/dynamic-rows/dynamic-rows'
+], function (_, utils, registry, dynamicRows) {
+    'use strict';
+
+    return dynamicRows.extend({
+        defaults: {
+            label: '',
+            collapsibleHeader: true,
+            columnsHeader: false,
+            deleteProperty: false,
+            addButton: false
+        },
+
+        /**
+         * Set new data to dataSource,
+         * delete element
+         *
+         * @param {Array} data - record data
+         */
+        _updateData: function (data) {
+            var elems = _.clone(this.elems()),
+                path,
+                dataArr,
+                optionBaseData;
+
+            dataArr = this.recordData.splice(this.startIndex, this.recordData().length - this.startIndex);
+            dataArr.splice(0, this.pageSize);
+            elems = _.sortBy(this.elems(), function (elem) {
+                return ~~elem.index;
+            });
+
+            data.concat(dataArr).forEach(function (rec, idx) {
+                if (elems[idx]) {
+                    elems[idx].recordId = rec[this.identificationProperty];
+                }
+
+                if (!rec.position) {
+                    rec.position = this.maxPosition;
+                    this.setMaxPosition();
+                }
+
+                path = this.dataScope + '.' + this.index + '.' + (this.startIndex + idx);
+                optionBaseData = _.pick(rec, function (value) {
+                    return !_.isObject(value);
+                });
+                this.source.set(path, optionBaseData);
+                this.source.set(path + '.bundle_button_proxy', []);
+                this.source.set(path + '.bundle_selections', []);
+                this.removeBundleItemsFromOption(idx);
+                _.each(rec['bundle_selections'], function (obj, index) {
+                    this.source.set(path + '.bundle_button_proxy' + '.' + index, rec['bundle_button_proxy'][index]);
+                    this.source.set(path + '.bundle_selections' + '.' + index, obj);
+                }, this);
+            }, this);
+
+            this.elems(elems);
+        },
+
+        /**
+         *  Removes nested dynamic-rows-grid rendered records from option
+         *
+         * @param {Number|String} index - element index
+         */
+        removeBundleItemsFromOption: function (index) {
+            var bundleSelections = registry.get(this.name + '.' + index + '.' + this.bundleSelectionsName),
+                bundleSelectionsLength = (bundleSelections.elems() || []).length,
+                i;
+
+            if (bundleSelectionsLength) {
+                for (i = 0; i < bundleSelectionsLength; i++) {
+                    bundleSelections.elems()[0].destroy();
+                }
+            }
+        },
+
+        /**
+        * {@inheritdoc}
+        */
+        processingAddChild: function (ctx, index, prop) {
+            var recordIds = _.map(this.recordData(), function (rec) {
+                return parseInt(rec['record_id'], 10);
+            }),
+            maxRecordId = _.max(recordIds);
+
+            prop = maxRecordId > -1 ? maxRecordId + 1 : prop;
+            this._super(ctx, index, prop);
+        }
+    });
+});
diff --git a/app/code/Magento/BundleImportExport/composer.json b/app/code/Magento/BundleImportExport/composer.json
index 3d7900d98287c1eba32a5badd2d5b2fdc1857f25..2f5e3afdbff86ded9c88161ebea832c29b37f229 100644
--- a/app/code/Magento/BundleImportExport/composer.json
+++ b/app/code/Magento/BundleImportExport/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-bundle-import-export",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-catalog": "101.1.*",
         "magento/module-import-export": "100.2.*",
         "magento/module-catalog-import-export": "100.2.*",
diff --git a/app/code/Magento/CacheInvalidate/composer.json b/app/code/Magento/CacheInvalidate/composer.json
index cafccadb41ad869ff87ee8eb154c747f569a4c79..c886e069b66e37d3b0c7a12af377a250cfc75192 100644
--- a/app/code/Magento/CacheInvalidate/composer.json
+++ b/app/code/Magento/CacheInvalidate/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-cache-invalidate",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-page-cache": "100.2.*",
         "magento/framework": "100.2.*"
     },
diff --git a/app/code/Magento/Captcha/composer.json b/app/code/Magento/Captcha/composer.json
index 9d0ce3db92aa402a7c247fed21185953c4707342..45ecd32464e9cc3f647264420961d6848b0445e9 100644
--- a/app/code/Magento/Captcha/composer.json
+++ b/app/code/Magento/Captcha/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-captcha",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-store": "100.2.*",
         "magento/module-customer": "100.2.*",
         "magento/module-checkout": "100.2.*",
diff --git a/app/code/Magento/Catalog/Block/Adminhtml/Helper/Form/Wysiwyg/Content.php b/app/code/Magento/Catalog/Block/Adminhtml/Helper/Form/Wysiwyg/Content.php
index d5488ecc5d085ee4a5d4b535ccf24040dbaee2a6..ac8cb91222fba47c7c686c10b45d6b81e87db2eb 100644
--- a/app/code/Magento/Catalog/Block/Adminhtml/Helper/Form/Wysiwyg/Content.php
+++ b/app/code/Magento/Catalog/Block/Adminhtml/Helper/Form/Wysiwyg/Content.php
@@ -14,6 +14,12 @@ namespace Magento\Catalog\Block\Adminhtml\Helper\Form\Wysiwyg;
 use Magento\Backend\Block\Widget\Form;
 use Magento\Backend\Block\Widget\Form\Generic;
 
+/**
+ * Class Content
+ *
+ * @deprecated
+ * @see \Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\Eav
+ */
 class Content extends Generic
 {
     /**
diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Category/Image/Upload.php b/app/code/Magento/Catalog/Controller/Adminhtml/Category/Image/Upload.php
index 285f4f1e3ffade4875266c634a241768b36215e9..25bd24ef70b9492d2da5b32e2a4146e3b1a0ab07 100644
--- a/app/code/Magento/Catalog/Controller/Adminhtml/Category/Image/Upload.php
+++ b/app/code/Magento/Catalog/Controller/Adminhtml/Category/Image/Upload.php
@@ -50,8 +50,10 @@ class Upload extends \Magento\Backend\App\Action
      */
     public function execute()
     {
+        $imageId = $this->_request->getParam('param_name', 'image');
+
         try {
-            $result = $this->imageUploader->saveFileToTmpDir('image');
+            $result = $this->imageUploader->saveFileToTmpDir($imageId);
 
             $result['cookie'] = [
                 'name' => $this->_getSession()->getName(),
diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Category/Save.php b/app/code/Magento/Catalog/Controller/Adminhtml/Category/Save.php
index 55ae96faeb7e6424f51ec3d5a22054844ea5a812..fa29d46c615939533111d3f62c540f848f06710b 100644
--- a/app/code/Magento/Catalog/Controller/Adminhtml/Category/Save.php
+++ b/app/code/Magento/Catalog/Controller/Adminhtml/Category/Save.php
@@ -6,6 +6,7 @@
 namespace Magento\Catalog\Controller\Adminhtml\Category;
 
 use Magento\Store\Model\StoreManagerInterface;
+use Magento\Catalog\Api\Data\CategoryAttributeInterface;
 
 /**
  * Class Save
@@ -48,6 +49,11 @@ class Save extends \Magento\Catalog\Controller\Adminhtml\Category
      */
     private $storeManager;
 
+    /**
+     * @var \Magento\Eav\Model\Config
+     */
+    private $eavConfig;
+
     /**
      * Constructor
      *
@@ -56,31 +62,35 @@ class Save extends \Magento\Catalog\Controller\Adminhtml\Category
      * @param \Magento\Framework\Controller\Result\JsonFactory $resultJsonFactory
      * @param \Magento\Framework\View\LayoutFactory $layoutFactory
      * @param StoreManagerInterface $storeManager
+     * @param \Magento\Eav\Model\Config $eavConfig
      */
     public function __construct(
         \Magento\Backend\App\Action\Context $context,
         \Magento\Framework\Controller\Result\RawFactory $resultRawFactory,
         \Magento\Framework\Controller\Result\JsonFactory $resultJsonFactory,
         \Magento\Framework\View\LayoutFactory $layoutFactory,
-        StoreManagerInterface $storeManager
+        StoreManagerInterface $storeManager,
+        \Magento\Eav\Model\Config $eavConfig = null
     ) {
         parent::__construct($context);
         $this->resultRawFactory = $resultRawFactory;
         $this->resultJsonFactory = $resultJsonFactory;
         $this->layoutFactory = $layoutFactory;
         $this->storeManager = $storeManager;
+        $this->eavConfig = $eavConfig
+            ?: \Magento\Framework\App\ObjectManager::getInstance()->get(\Magento\Eav\Model\Config::class);
     }
 
     /**
      * Filter category data
      *
+     * @deprecated
      * @param array $rawData
      * @return array
      */
     protected function _filterCategoryPostData(array $rawData)
     {
         $data = $rawData;
-        // @todo It is a workaround to prevent saving this data in category model and it has to be refactored in future
         if (isset($data['image']) && is_array($data['image'])) {
             if (!empty($data['image']['delete'])) {
                 $data['image'] = null;
@@ -126,7 +136,7 @@ class Save extends \Magento\Catalog\Controller\Adminhtml\Category
         $this->storeManager->setCurrentStore($store->getCode());
         $parentId = isset($categoryPostData['parent']) ? $categoryPostData['parent'] : null;
         if ($categoryPostData) {
-            $category->addData($this->_filterCategoryPostData($categoryPostData));
+            $category->addData($categoryPostData);
             if ($isNewCategory) {
                 $parentCategory = $this->getParentCategory($parentId, $storeId);
                 $category->setPath($parentCategory->getPath());
@@ -248,18 +258,30 @@ class Save extends \Magento\Catalog\Controller\Adminhtml\Category
     }
 
     /**
-     * Image data preprocessing
+     * Sets image attribute data to false if image was removed
      *
      * @param array $data
-     *
      * @return array
      */
     public function imagePreprocessing($data)
     {
-        if (empty($data['image'])) {
-            unset($data['image']);
-            $data['image']['delete'] = true;
+        $entityType = $this->eavConfig->getEntityType(CategoryAttributeInterface::ENTITY_TYPE_CODE);
+
+        foreach ($entityType->getAttributeCollection() as $attributeModel) {
+            $attributeCode = $attributeModel->getAttributeCode();
+            $backendModel = $attributeModel->getBackend();
+
+            if (isset($data[$attributeCode])) {
+                continue;
+            }
+
+            if (!$backendModel instanceof \Magento\Catalog\Model\Category\Attribute\Backend\Image) {
+                continue;
+            }
+
+            $data[$attributeCode] = false;
         }
+
         return $data;
     }
 
diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/AddAttributeToTemplate.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/AddAttributeToTemplate.php
index 8a2b76b1bbd56212f27cb45db587e38fc2bb57c8..c338937ae1be1df330d32c4992f3cb5839ebad05 100644
--- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/AddAttributeToTemplate.php
+++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/AddAttributeToTemplate.php
@@ -16,7 +16,6 @@ use Magento\Eav\Api\Data\AttributeGroupInterfaceFactory;
 use Magento\Eav\Api\Data\AttributeInterface;
 use Magento\Eav\Api\Data\AttributeSetInterface;
 use Magento\Framework\Api\SearchCriteriaBuilder;
-use Magento\Framework\Api\SortOrderBuilder;
 use Magento\Framework\Exception\LocalizedException;
 use Psr\Log\LoggerInterface;
 use Magento\Framework\Api\ExtensionAttributesFactory;
@@ -53,11 +52,6 @@ class AddAttributeToTemplate extends \Magento\Catalog\Controller\Adminhtml\Produ
      */
     protected $searchCriteriaBuilder;
 
-    /**
-     * @var SortOrderBuilder
-     */
-    protected $sortOrderBuilder;
-
     /**
      * @var AttributeGroupInterfaceFactory
      */
@@ -115,7 +109,6 @@ class AddAttributeToTemplate extends \Magento\Catalog\Controller\Adminhtml\Produ
             $attributeGroupSearchCriteria = $this->getSearchCriteriaBuilder()
                 ->addFilter('attribute_set_id', $attributeSet->getAttributeSetId())
                 ->addFilter('attribute_group_code', $groupCode)
-                ->addSortOrder($this->getSortOrderBuilder()->setAscendingDirection()->create())
                 ->setPageSize(1)
                 ->create();
 
@@ -252,18 +245,6 @@ class AddAttributeToTemplate extends \Magento\Catalog\Controller\Adminhtml\Produ
         return $this->searchCriteriaBuilder;
     }
 
-    /**
-     * @return SortOrderBuilder
-     */
-    private function getSortOrderBuilder()
-    {
-        if (null === $this->sortOrderBuilder) {
-            $this->sortOrderBuilder = \Magento\Framework\App\ObjectManager::getInstance()
-                ->get(\Magento\Framework\Api\SortOrderBuilder::class);
-        }
-        return $this->sortOrderBuilder;
-    }
-
     /**
      * @return AttributeManagementInterface
      */
diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Initialization/Helper.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Initialization/Helper.php
index d59492c4065e72706f8c1a168e4a33b1c2c9e825..4eed888b3cb08b18f07e403bc172ec9615108a09 100644
--- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Initialization/Helper.php
+++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Initialization/Helper.php
@@ -131,12 +131,7 @@ class Helper
                 $productData[$field] = [];
             }
         }
-
-        foreach ($productData['website_ids'] as $websiteId => $checkboxValue) {
-            if (!$checkboxValue) {
-                unset($productData['website_ids'][$websiteId]);
-            }
-        }
+        $productData['website_ids'] = $this->filterWebsiteIds($productData['website_ids']);
 
         $wasLockedMedia = false;
         if ($product->isLockedAttribute('media')) {
@@ -422,4 +417,23 @@ class Helper
         }
         return $this->dateTimeFilter;
     }
+
+    /**
+     * Remove ids of non selected websites from $websiteIds array and return filtered data
+     * $websiteIds parameter expects array with website ids as keys and 1 (selected) or 0 (non selected) as values
+     * Only one id (default website ID) will be set to $websiteIds array when the single store mode is turned on
+     *
+     * @param array $websiteIds
+     * @return array
+     */
+    private function filterWebsiteIds($websiteIds)
+    {
+        if (!$this->storeManager->isSingleStoreMode()) {
+            $websiteIds = array_filter((array)$websiteIds);
+        } else {
+            $websiteIds[$this->storeManager->getWebsite(true)->getId()] = 1;
+        }
+
+        return $websiteIds;
+    }
 }
diff --git a/app/code/Magento/Catalog/Model/Category.php b/app/code/Magento/Catalog/Model/Category.php
index 9e855e05c7ce388dd52c11829882d5b46f634d02..906718c64c6e0bf814bda973c81168d067d887ed 100644
--- a/app/code/Magento/Catalog/Model/Category.php
+++ b/app/code/Magento/Catalog/Model/Category.php
@@ -652,14 +652,14 @@ class Category extends \Magento\Catalog\Model\AbstractModel implements
     }
 
     /**
-     * Retrieve image URL
-     *
-     * @return string
+     * @param string $attributeCode
+     * @return bool|string
+     * @throws \Magento\Framework\Exception\LocalizedException
      */
-    public function getImageUrl()
+    public function getImageUrl($attributeCode = 'image')
     {
         $url = false;
-        $image = $this->getImage();
+        $image = $this->getData($attributeCode);
         if ($image) {
             if (is_string($image)) {
                 $url = $this->_storeManager->getStore()->getBaseUrl(
diff --git a/app/code/Magento/Catalog/Model/Category/Attribute/Backend/Image.php b/app/code/Magento/Catalog/Model/Category/Attribute/Backend/Image.php
index 5eb4461ace5f0e88583337a9b8c2efe2c71bad64..5e8589428fad1d17abe4480abf1d16a8b727abcb 100644
--- a/app/code/Magento/Catalog/Model/Category/Attribute/Backend/Image.php
+++ b/app/code/Magento/Catalog/Model/Category/Attribute/Backend/Image.php
@@ -21,8 +21,6 @@ class Image extends \Magento\Eav\Model\Entity\Attribute\Backend\AbstractBackend
     protected $_uploaderFactory;
 
     /**
-     * Filesystem facade
-     *
      * @var \Magento\Framework\Filesystem
      *
      * @deprecated
@@ -30,8 +28,6 @@ class Image extends \Magento\Eav\Model\Entity\Attribute\Backend\AbstractBackend
     protected $_filesystem;
 
     /**
-     * File Uploader factory
-     *
      * @var \Magento\MediaStorage\Model\File\UploaderFactory
      *
      * @deprecated
@@ -46,15 +42,16 @@ class Image extends \Magento\Eav\Model\Entity\Attribute\Backend\AbstractBackend
     protected $_logger;
 
     /**
-     * Image uploader
-     *
      * @var \Magento\Catalog\Model\ImageUploader
      */
     private $imageUploader;
 
     /**
-     * Image constructor.
-     *
+     * @var string
+     */
+    private $additionalData = '_additional_data_';
+
+    /**
      * @param \Psr\Log\LoggerInterface $logger
      * @param \Magento\Framework\Filesystem $filesystem
      * @param \Magento\MediaStorage\Model\File\UploaderFactory $fileUploaderFactory
@@ -70,8 +67,44 @@ class Image extends \Magento\Eav\Model\Entity\Attribute\Backend\AbstractBackend
     }
 
     /**
-     * Get image uploader
+     * Gets image name from $value array.
+     * Will return empty string in a case when $value is not an array
+     *
+     * @param array $value Attribute value
+     * @return string
+     */
+    private function getUploadedImageName($value)
+    {
+        if (is_array($value) && isset($value[0]['name'])) {
+            return $value[0]['name'];
+        }
+
+        return '';
+    }
+
+    /**
+     * Avoiding saving potential upload data to DB
+     * Will set empty image attribute value if image was not uploaded
      *
+     * @param \Magento\Framework\DataObject $object
+     * @return $this
+     */
+    public function beforeSave($object)
+    {
+        $attributeName = $this->getAttribute()->getName();
+        $value = $object->getData($attributeName);
+
+        if ($imageName = $this->getUploadedImageName($value)) {
+            $object->setData($this->additionalData . $attributeName, $value);
+            $object->setData($attributeName, $imageName);
+        } else if (!is_string($value)) {
+            $object->setData($attributeName, '');
+        }
+
+        return parent::beforeSave($object);
+    }
+
+    /**
      * @return \Magento\Catalog\Model\ImageUploader
      *
      * @deprecated
@@ -79,10 +112,10 @@ class Image extends \Magento\Eav\Model\Entity\Attribute\Backend\AbstractBackend
     private function getImageUploader()
     {
         if ($this->imageUploader === null) {
-            $this->imageUploader = \Magento\Framework\App\ObjectManager::getInstance()->get(
-                \Magento\Catalog\CategoryImageUpload::class
-            );
+            $this->imageUploader = \Magento\Framework\App\ObjectManager::getInstance()
+                ->get(\Magento\Catalog\CategoryImageUpload::class);
         }
+
         return $this->imageUploader;
     }
 
@@ -94,15 +127,16 @@ class Image extends \Magento\Eav\Model\Entity\Attribute\Backend\AbstractBackend
      */
     public function afterSave($object)
     {
-        $image = $object->getData($this->getAttribute()->getName(), null);
+        $value = $object->getData($this->additionalData . $this->getAttribute()->getName());
 
-        if ($image !== null) {
+        if ($imageName = $this->getUploadedImageName($value)) {
             try {
-                $this->getImageUploader()->moveFileFromTmp($image);
+                $this->getImageUploader()->moveFileFromTmp($imageName);
             } catch (\Exception $e) {
                 $this->_logger->critical($e);
             }
         }
+
         return $this;
     }
 }
diff --git a/app/code/Magento/Catalog/Model/Category/DataProvider.php b/app/code/Magento/Catalog/Model/Category/DataProvider.php
index 8626d183e2fac36e2b2fb194c418384d9ff87d82..aefd31e21ad62f8469837a801581170581555c6a 100644
--- a/app/code/Magento/Catalog/Model/Category/DataProvider.php
+++ b/app/code/Magento/Catalog/Model/Category/DataProvider.php
@@ -17,6 +17,7 @@ use Magento\Ui\Component\Form\Field;
 use Magento\Ui\DataProvider\EavValidationRules;
 use Magento\Catalog\Model\CategoryFactory;
 use Magento\Framework\Exception\NoSuchEntityException;
+use Magento\Catalog\Model\Category\Attribute\Backend\Image as ImageBackendModel;
 
 /**
  * Class DataProvider
@@ -206,11 +207,8 @@ class DataProvider extends \Magento\Ui\DataProvider\AbstractDataProvider
             $categoryData = $this->addUseDefaultSettings($category, $categoryData);
             $categoryData = $this->addUseConfigSettings($categoryData);
             $categoryData = $this->filterFields($categoryData);
-            if (isset($categoryData['image'])) {
-                unset($categoryData['image']);
-                $categoryData['image'][0]['name'] = $category->getData('image');
-                $categoryData['image'][0]['url'] = $category->getImageUrl();
-            }
+            $categoryData = $this->convertValues($category, $categoryData);
+
             $this->loadedData[$category->getId()] = $categoryData;
         }
         return $this->loadedData;
@@ -371,6 +369,31 @@ class DataProvider extends \Magento\Ui\DataProvider\AbstractDataProvider
         return array_diff_key($categoryData, array_flip($this->ignoreFields));
     }
 
+    /**
+     * Converts category image data to acceptable for rendering format
+     *
+     * @param \Magento\Catalog\Model\Category $category
+     * @param array $categoryData
+     * @return array
+     */
+    private function convertValues($category, $categoryData)
+    {
+        foreach ($category->getAttributes() as $attributeCode => $attribute) {
+            if (!isset($categoryData[$attributeCode])) {
+                continue;
+            }
+
+            if ($attribute->getBackend() instanceof ImageBackendModel) {
+                unset($categoryData[$attributeCode]);
+
+                $categoryData[$attributeCode][0]['name'] = $category->getData($attributeCode);
+                $categoryData[$attributeCode][0]['url'] = $category->getImageUrl($attributeCode);
+            }
+        }
+
+        return $categoryData;
+    }
+
     /**
      * Category's fields default values
      *
diff --git a/app/code/Magento/Catalog/Model/Product.php b/app/code/Magento/Catalog/Model/Product.php
index 9e9f18e0113717ad6853ea5d4512661a897e926c..c913c82de1acdecbf3328c37fe7529dfbab193ba 100644
--- a/app/code/Magento/Catalog/Model/Product.php
+++ b/app/code/Magento/Catalog/Model/Product.php
@@ -22,7 +22,6 @@ use Magento\Catalog\Api\Data\ProductAttributeMediaGalleryEntryExtensionFactory;
  * @method Product setHasError(bool $value)
  * @method \Magento\Catalog\Model\ResourceModel\Product getResource()
  * @method null|bool getHasError()
- * @method Product setAssociatedProductIds(array $productIds)
  * @method array getAssociatedProductIds()
  * @method Product setNewVariationsAttributeSetId(int $value)
  * @method int getNewVariationsAttributeSetId()
@@ -2614,4 +2613,16 @@ class Product extends \Magento\Catalog\Model\AbstractModel implements
         }
         return $this->mediaGalleryProcessor;
     }
+
+    /**
+     * Set the associated products
+     *
+     * @param array $productIds
+     * @return $this
+     */
+    public function setAssociatedProductIds(array $productIds)
+    {
+        $this->getExtensionAttributes()->setConfigurableProductLinks($productIds);
+        return $this;
+    }
 }
diff --git a/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Stock.php b/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Stock.php
index 5c3fd4730aaed4907cbf197f6a5298060ad12acf..0bb468b77ee6ea18df11e7fd349e8315c6f74318 100644
--- a/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Stock.php
+++ b/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Stock.php
@@ -59,7 +59,7 @@ class Stock extends \Magento\Eav\Model\Entity\Attribute\Backend\AbstractBackend
         if (isset($stockData['qty']) && $stockData['qty'] === '') {
             $stockData['qty'] = null;
         }
-        if ($object->getStockData() !== null || $stockData !== null) {
+        if ($object->getStockData() !== null && $stockData !== null) {
             $object->setStockData(array_replace((array)$object->getStockData(), (array)$stockData));
         }
         $object->unsetData($this->getAttribute()->getAttributeCode());
diff --git a/app/code/Magento/Catalog/Model/Product/Image.php b/app/code/Magento/Catalog/Model/Product/Image.php
index 7d8b464db3b34cd116d2c8c7adae86113040e67f..34e1ad30ad434add33508bb63c7b8b1a78ddc9fb 100644
--- a/app/code/Magento/Catalog/Model/Product/Image.php
+++ b/app/code/Magento/Catalog/Model/Product/Image.php
@@ -498,8 +498,7 @@ class Image extends \Magento\Framework\Model\AbstractModel
         $path = [
             $this->_catalogProductMediaConfig->getBaseMediaPath(),
             'cache',
-            $this->_storeManager->getStore()->getId(),
-            $path[] = $this->getDestinationSubdir(),
+            $this->getDestinationSubdir(),
         ];
         if (!empty($this->_width) || !empty($this->_height)) {
             $path[] = "{$this->_width}x{$this->_height}";
diff --git a/app/code/Magento/Catalog/Model/ProductRepository.php b/app/code/Magento/Catalog/Model/ProductRepository.php
index 4385c8add37aef25dc52a888d2ff839b49e734db..27796e1cda2a167848c2a3b8fb0d096f40c172d6 100644
--- a/app/code/Magento/Catalog/Model/ProductRepository.php
+++ b/app/code/Magento/Catalog/Model/ProductRepository.php
@@ -640,6 +640,7 @@ class ProductRepository implements \Magento\Catalog\Api\ProductRepositoryInterfa
 
         $collection->load();
 
+        $collection->addCategoryIds();
         $searchResult = $this->searchResultsFactory->create();
         $searchResult->setSearchCriteria($searchCriteria);
         $searchResult->setItems($collection->getItems());
diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/BaseSelectProcessorInterface.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/BaseSelectProcessorInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..e6a995b654703402175f79ccc6e50b5172db5fd4
--- /dev/null
+++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/BaseSelectProcessorInterface.php
@@ -0,0 +1,26 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Catalog\Model\ResourceModel\Product;
+
+use Magento\Framework\DB\Select;
+
+/**
+ * Interface BaseSelectProcessorInterface
+ * @api
+ */
+interface BaseSelectProcessorInterface
+{
+    /**
+     * Product table alias
+     */
+    const PRODUCT_TABLE_ALIAS = 'child';
+
+    /**
+     * @param Select $select
+     * @return Select
+     */
+    public function process(Select $select);
+}
diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/Collection.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/Collection.php
index b2b20b9d223e223a093d7f6ae222e19631084528..c24460981afbf8d6c6cccb79255031d8320b726f 100644
--- a/app/code/Magento/Catalog/Model/ResourceModel/Product/Collection.php
+++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/Collection.php
@@ -2182,12 +2182,17 @@ class Collection extends \Magento\Catalog\Model\ResourceModel\Collection\Abstrac
 
         $mediaGalleries = [];
         $linkField = $this->getMetadataPool()->getMetadata(ProductInterface::class)->getLinkField();
+        $items = $this->getItems();
+
+        $select->where('entity.' . $linkField . ' IN (?)', array_map(function ($item) {
+            return $item->getId();
+        }, $items));
 
         foreach ($this->getConnection()->fetchAll($select) as $row) {
             $mediaGalleries[$row[$linkField]][] = $row;
         }
 
-        foreach ($this->getItems() as $item) {
+        foreach ($items as $item) {
             $mediaEntries = isset($mediaGalleries[$item->getId()]) ? $mediaGalleries[$item->getId()] : [];
             $this->getGalleryReadHandler()->addMediaDataToProduct($item, $mediaEntries);
         }
diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/CompositeBaseSelectProcessor.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/CompositeBaseSelectProcessor.php
new file mode 100644
index 0000000000000000000000000000000000000000..86f5a23708400ef40a58677f07e57552a39bd6bd
--- /dev/null
+++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/CompositeBaseSelectProcessor.php
@@ -0,0 +1,49 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Catalog\Model\ResourceModel\Product;
+
+use Magento\Framework\DB\Select;
+use Magento\Framework\Exception\InputException;
+
+/**
+ * Class CompositeBaseSelectProcessor
+ */
+class CompositeBaseSelectProcessor implements BaseSelectProcessorInterface
+{
+    /**
+     * @var BaseSelectProcessorInterface[]
+     */
+    private $baseSelectProcessors;
+
+    /**
+     * @param BaseSelectProcessorInterface[] $baseSelectProcessors
+     * @throws InputException
+     */
+    public function __construct(
+        array $baseSelectProcessors
+    ) {
+        foreach ($baseSelectProcessors as $baseSelectProcessor) {
+            if (!$baseSelectProcessor instanceof BaseSelectProcessorInterface) {
+                throw new InputException(
+                    __('Processor %1 doesn\'t implement BaseSelectProcessorInterface', get_class($baseSelectProcessor))
+                );
+            }
+        }
+        $this->baseSelectProcessors = $baseSelectProcessors;
+    }
+
+    /**
+     * @param Select $select
+     * @return Select
+     */
+    public function process(Select $select)
+    {
+        foreach ($this->baseSelectProcessors as $baseSelectProcessor) {
+            $select = $baseSelectProcessor->process($select);
+        }
+        return $select;
+    }
+}
diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Eav/AbstractEav.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Eav/AbstractEav.php
index d9612f18c9111df4634e18cb8b9abf523643f2e5..432bc696ef7cecd822b5168e7da70a9ed1cd4fc5 100644
--- a/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Eav/AbstractEav.php
+++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Eav/AbstractEav.php
@@ -197,7 +197,7 @@ abstract class AbstractEav extends \Magento\Catalog\Model\ResourceModel\Product\
         )->joinLeft(
             ['e' => $this->getTable('catalog_product_entity')],
             'e.' . $linkField .' = l.parent_id',
-            ['e.entity_id as parent_id']
+            []
         )->join(
             ['cs' => $this->getTable('store')],
             '',
@@ -205,9 +205,17 @@ abstract class AbstractEav extends \Magento\Catalog\Model\ResourceModel\Product\
         )->join(
             ['i' => $idxTable],
             'l.child_id = i.entity_id AND cs.store_id = i.store_id',
-            ['attribute_id', 'store_id', 'value']
+            []
         )->group(
-            ['parent_id', 'i.attribute_id', 'i.store_id', 'i.value']
+            ['parent_id', 'i.attribute_id', 'i.store_id', 'i.value', 'l.child_id']
+        )->columns(
+            [
+                'parent_id' => 'e.entity_id',
+                'attribute_id' => 'i.attribute_id',
+                'store_id' => 'i.store_id',
+                'value' => 'i.value',
+                'source_id' => 'l.child_id'
+            ]
         );
         if ($parentIds !== null) {
             $select->where('e.entity_id IN(?)', $parentIds);
@@ -222,7 +230,7 @@ abstract class AbstractEav extends \Magento\Catalog\Model\ResourceModel\Product\
                 'select' => $select,
                 'entity_field' => new \Zend_Db_Expr('l.parent_id'),
                 'website_field' => new \Zend_Db_Expr('cs.website_id'),
-                'store_field' => new \Zend_Db_Expr('cs.store_id')
+                'store_field' => new \Zend_Db_Expr('cs.store_id'),
             ]
         );
 
diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Eav/Decimal.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Eav/Decimal.php
index e8d9889e68d59384e74cfb3fc0491a2edb8f3edb..a45d4f13a1a9a811fffb6269bf94575675c60d80 100644
--- a/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Eav/Decimal.php
+++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Eav/Decimal.php
@@ -85,6 +85,7 @@ class Decimal extends AbstractEav
                 'pdd.attribute_id',
                 'cs.store_id',
                 'value' => $productValueExpression,
+                'source_id' => 'cpe.entity_id',
             ]
         );
 
@@ -116,7 +117,7 @@ class Decimal extends AbstractEav
                 'select' => $select,
                 'entity_field' => new \Zend_Db_Expr('cpe.entity_id'),
                 'website_field' => new \Zend_Db_Expr('cs.website_id'),
-                'store_field' => new \Zend_Db_Expr('cs.store_id')
+                'store_field' => new \Zend_Db_Expr('cs.store_id'),
             ]
         );
 
diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Eav/Source.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Eav/Source.php
index c4eda1c987192acb5dd7e5ce003fe8b9cff0bdc6..1d37c57aa8b251bc73edf6e4a06aed1789cdc476 100644
--- a/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Eav/Source.php
+++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Eav/Source.php
@@ -178,6 +178,7 @@ class Source extends AbstractEav
                 'pid.attribute_id',
                 'pid.store_id',
                 'value' => $ifNullSql,
+                'pid.entity_id',
             ]
         )->where(
             'pid.attribute_id IN(?)',
@@ -200,7 +201,7 @@ class Source extends AbstractEav
                 'select' => $select,
                 'entity_field' => new \Zend_Db_Expr('pid.entity_id'),
                 'website_field' => new \Zend_Db_Expr('pid.website_id'),
-                'store_field' => new \Zend_Db_Expr('pid.store_id')
+                'store_field' => new \Zend_Db_Expr('pid.store_id'),
             ]
         );
         $query = $select->insertFromSelect($idxTable);
@@ -221,11 +222,7 @@ class Source extends AbstractEav
         $connection = $this->getConnection();
 
         // prepare multiselect attributes
-        if ($attributeId === null) {
-            $attrIds = $this->_getIndexableAttributes(true);
-        } else {
-            $attrIds = [$attributeId];
-        }
+        $attrIds = $attributeId === null ? $this->_getIndexableAttributes(true) : [$attributeId];
 
         if (!$attrIds) {
             return $this;
@@ -247,20 +244,20 @@ class Source extends AbstractEav
         $productValueExpression = $connection->getCheckSql('pvs.value_id > 0', 'pvs.value', 'pvd.value');
         $select = $connection->select()->from(
             ['pvd' => $this->getTable('catalog_product_entity_varchar')],
-            [$productIdField, 'attribute_id']
+            []
         )->join(
             ['cs' => $this->getTable('store')],
             '',
-            ['store_id']
+            []
         )->joinLeft(
             ['pvs' => $this->getTable('catalog_product_entity_varchar')],
             "pvs.{$productIdField} = pvd.{$productIdField} AND pvs.attribute_id = pvd.attribute_id"
             . ' AND pvs.store_id=cs.store_id',
-            ['value' => $productValueExpression]
+            []
         )->joinLeft(
             ['cpe' => $this->getTable('catalog_product_entity')],
             "cpe.{$productIdField} = pvd.{$productIdField}",
-            ['entity_id']
+            []
         )->where(
             'pvd.store_id=?',
             $connection->getIfNullSql('pvs.store_id', \Magento\Store\Model\Store::DEFAULT_STORE_ID)
@@ -272,6 +269,14 @@ class Source extends AbstractEav
             $attrIds
         )->where(
             'cpe.entity_id IS NOT NULL'
+        )->columns(
+            [
+                'entity_id' => 'cpe.entity_id',
+                'attribute_id' => 'attribute_id',
+                'store_id' => 'cs.store_id',
+                'value' => $productValueExpression,
+                'source_id' => 'cpe.entity_id',
+            ]
         );
 
         $statusCond = $connection->quoteInto('=?', ProductStatus::STATUS_ENABLED);
@@ -289,30 +294,11 @@ class Source extends AbstractEav
                 'select' => $select,
                 'entity_field' => new \Zend_Db_Expr('cpe.entity_id'),
                 'website_field' => new \Zend_Db_Expr('cs.website_id'),
-                'store_field' => new \Zend_Db_Expr('cs.store_id')
+                'store_field' => new \Zend_Db_Expr('cs.store_id'),
             ]
         );
 
-        $i = 0;
-        $data = [];
-        $query = $select->query();
-        while ($row = $query->fetch()) {
-            $values = explode(',', $row['value']);
-            foreach ($values as $valueId) {
-                if (isset($options[$row['attribute_id']][$valueId])) {
-                    $data[] = [$row['entity_id'], $row['attribute_id'], $row['store_id'], $valueId];
-                    $i++;
-                    if ($i % 10000 == 0) {
-                        $this->_saveIndexData($data);
-                        $data = [];
-                    }
-                }
-            }
-        }
-
-        $this->_saveIndexData($data);
-        unset($options);
-        unset($data);
+        $this->saveDataFromSelect($select, $options);
 
         return $this;
     }
@@ -331,7 +317,7 @@ class Source extends AbstractEav
         $connection = $this->getConnection();
         $connection->insertArray(
             $this->getIdxTable(),
-            ['entity_id', 'attribute_id', 'store_id', 'value'],
+            ['entity_id', 'attribute_id', 'store_id', 'value', 'source_id'],
             $data
         );
         return $this;
@@ -348,4 +334,31 @@ class Source extends AbstractEav
     {
         return $this->tableStrategy->getTableName('catalog_product_index_eav');
     }
+
+    /**
+     * @param \Magento\Framework\DB\Select $select
+     * @param array $options
+     * @return void
+     */
+    private function saveDataFromSelect(\Magento\Framework\DB\Select $select, array $options)
+    {
+        $i = 0;
+        $data = [];
+        $query = $select->query();
+        while ($row = $query->fetch()) {
+            $values = explode(',', $row['value']);
+            foreach ($values as $valueId) {
+                if (isset($options[$row['attribute_id']][$valueId])) {
+                    $data[] = [$row['entity_id'], $row['attribute_id'], $row['store_id'], $valueId, $row['source_id']];
+                    $i++;
+                    if ($i % 10000 == 0) {
+                        $this->_saveIndexData($data);
+                        $data = [];
+                    }
+                }
+            }
+        }
+
+        $this->_saveIndexData($data);
+    }
 }
diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/LinkedProductSelectBuilderByIndexPrice.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/LinkedProductSelectBuilderByIndexPrice.php
index ea72691ea003939fc277299bee214da316f4f757..3aa6642c82d845eb6ca1143f9c82484c53c659f9 100644
--- a/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/LinkedProductSelectBuilderByIndexPrice.php
+++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/LinkedProductSelectBuilderByIndexPrice.php
@@ -6,7 +6,8 @@
 namespace Magento\Catalog\Model\ResourceModel\Product\Indexer;
 
 use Magento\Catalog\Api\Data\ProductInterface;
-use Magento\Catalog\Model\Product;
+use Magento\Catalog\Model\ResourceModel\Product\BaseSelectProcessorInterface;
+use Magento\Framework\App\ObjectManager;
 use Magento\Framework\DB\Select;
 use Magento\Catalog\Model\ResourceModel\Product\LinkedProductSelectBuilderInterface;
 
@@ -32,22 +33,31 @@ class LinkedProductSelectBuilderByIndexPrice implements LinkedProductSelectBuild
      */
     private $metadataPool;
 
+    /**
+     * @var BaseSelectProcessorInterface
+     */
+    private $baseSelectProcessor;
+
     /**
      * @param \Magento\Store\Model\StoreManagerInterface $storeManager
      * @param \Magento\Framework\App\ResourceConnection $resourceConnection
      * @param \Magento\Customer\Model\Session $customerSession
      * @param \Magento\Framework\EntityManager\MetadataPool $metadataPool
+     * @param BaseSelectProcessorInterface $baseSelectProcessor
      */
     public function __construct(
         \Magento\Store\Model\StoreManagerInterface $storeManager,
         \Magento\Framework\App\ResourceConnection $resourceConnection,
         \Magento\Customer\Model\Session $customerSession,
-        \Magento\Framework\EntityManager\MetadataPool $metadataPool
+        \Magento\Framework\EntityManager\MetadataPool $metadataPool,
+        BaseSelectProcessorInterface $baseSelectProcessor = null
     ) {
         $this->storeManager = $storeManager;
         $this->resource = $resourceConnection;
         $this->customerSession = $customerSession;
         $this->metadataPool = $metadataPool;
+        $this->baseSelectProcessor = (null !== $baseSelectProcessor)
+            ? $baseSelectProcessor : ObjectManager::getInstance()->get(BaseSelectProcessorInterface::class);
     }
 
     /**
@@ -58,24 +68,27 @@ class LinkedProductSelectBuilderByIndexPrice implements LinkedProductSelectBuild
         $linkField = $this->metadataPool->getMetadata(ProductInterface::class)->getLinkField();
         $productTable = $this->resource->getTableName('catalog_product_entity');
 
-        return [$this->resource->getConnection()->select()
+        $priceSelect = $this->resource->getConnection()->select()
             ->from(['parent' => $productTable], '')
             ->joinInner(
                 ['link' => $this->resource->getTableName('catalog_product_relation')],
                 "link.parent_id = parent.$linkField",
                 []
             )->joinInner(
-                ['child' => $productTable],
-                "child.entity_id = link.child_id",
+                [BaseSelectProcessorInterface::PRODUCT_TABLE_ALIAS => $productTable],
+                sprintf('%s.entity_id = link.child_id', BaseSelectProcessorInterface::PRODUCT_TABLE_ALIAS),
                 ['entity_id']
             )->joinInner(
                 ['t' => $this->resource->getTableName('catalog_product_index_price')],
-                't.entity_id = child.entity_id',
+                sprintf('t.entity_id = %s.entity_id', BaseSelectProcessorInterface::PRODUCT_TABLE_ALIAS),
                 []
-            )->where('parent.entity_id = ? ', $productId)
+            )->where('parent.entity_id = ?', $productId)
             ->where('t.website_id = ?', $this->storeManager->getStore()->getWebsiteId())
             ->where('t.customer_group_id = ?', $this->customerSession->getCustomerGroupId())
             ->order('t.min_price ' . Select::SQL_ASC)
-            ->limit(1)];
+            ->limit(1);
+        $priceSelect = $this->baseSelectProcessor->process($priceSelect);
+
+        return [$priceSelect];
     }
 }
diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/DefaultPrice.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/DefaultPrice.php
index 289445ae2daf07c4132f6d69372c84fcfb36a066..2b979ff79fe5c498215b6b144e71897b9ca2c913 100644
--- a/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/DefaultPrice.php
+++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/DefaultPrice.php
@@ -368,7 +368,7 @@ class DefaultPrice extends AbstractIndexer implements PriceInterface
                 'select' => $select,
                 'entity_field' => new \Zend_Db_Expr('e.entity_id'),
                 'website_field' => new \Zend_Db_Expr('cw.website_id'),
-                'store_field' => new \Zend_Db_Expr('cs.store_id')
+                'store_field' => new \Zend_Db_Expr('cs.store_id'),
             ]
         );
 
diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/LinkedProductSelectBuilderByBasePrice.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/LinkedProductSelectBuilderByBasePrice.php
index d325ab1a9a08d1175c0fedb2a94c10ac5d7dc3c2..7caa72b367979bc4ecbded5641490a59f7835928 100644
--- a/app/code/Magento/Catalog/Model/ResourceModel/Product/LinkedProductSelectBuilderByBasePrice.php
+++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/LinkedProductSelectBuilderByBasePrice.php
@@ -7,6 +7,7 @@ namespace Magento\Catalog\Model\ResourceModel\Product;
 
 use Magento\Catalog\Api\Data\ProductInterface;
 use Magento\Catalog\Model\Product;
+use Magento\Framework\App\ObjectManager;
 use Magento\Framework\DB\Select;
 use Magento\Store\Model\Store;
 
@@ -37,25 +38,34 @@ class LinkedProductSelectBuilderByBasePrice implements LinkedProductSelectBuilde
      */
     private $metadataPool;
 
+    /**
+     * @var BaseSelectProcessorInterface
+     */
+    private $baseSelectProcessor;
+
     /**
      * @param \Magento\Store\Model\StoreManagerInterface $storeManager
      * @param \Magento\Framework\App\ResourceConnection $resourceConnection
      * @param \Magento\Eav\Model\Config $eavConfig
      * @param \Magento\Catalog\Helper\Data $catalogHelper
      * @param \Magento\Framework\EntityManager\MetadataPool $metadataPool
+     * @param BaseSelectProcessorInterface $baseSelectProcessor
      */
     public function __construct(
         \Magento\Store\Model\StoreManagerInterface $storeManager,
         \Magento\Framework\App\ResourceConnection $resourceConnection,
         \Magento\Eav\Model\Config $eavConfig,
         \Magento\Catalog\Helper\Data $catalogHelper,
-        \Magento\Framework\EntityManager\MetadataPool $metadataPool
+        \Magento\Framework\EntityManager\MetadataPool $metadataPool,
+        BaseSelectProcessorInterface $baseSelectProcessor = null
     ) {
         $this->storeManager = $storeManager;
         $this->resource = $resourceConnection;
         $this->eavConfig = $eavConfig;
         $this->catalogHelper = $catalogHelper;
         $this->metadataPool = $metadataPool;
+        $this->baseSelectProcessor = (null !== $baseSelectProcessor)
+            ? $baseSelectProcessor : ObjectManager::getInstance()->get(BaseSelectProcessorInterface::class);
     }
 
     /**
@@ -74,18 +84,19 @@ class LinkedProductSelectBuilderByBasePrice implements LinkedProductSelectBuilde
                 "link.parent_id = parent.$linkField",
                 []
             )->joinInner(
-                ['child' => $productTable],
-                "child.entity_id = link.child_id",
+                [BaseSelectProcessorInterface::PRODUCT_TABLE_ALIAS => $productTable],
+                sprintf('%s.entity_id = link.child_id', BaseSelectProcessorInterface::PRODUCT_TABLE_ALIAS, $linkField),
                 ['entity_id']
             )->joinInner(
                 ['t' => $priceAttribute->getBackendTable()],
-                "t.$linkField = child.$linkField",
+                sprintf('t.%s = %s.%1$s', $linkField, BaseSelectProcessorInterface::PRODUCT_TABLE_ALIAS),
                 []
-            )->where('parent.entity_id = ? ', $productId)
+            )->where('parent.entity_id = ?', $productId)
             ->where('t.attribute_id = ?', $priceAttribute->getAttributeId())
             ->where('t.value IS NOT NULL')
             ->order('t.value ' . Select::SQL_ASC)
             ->limit(1);
+        $priceSelect = $this->baseSelectProcessor->process($priceSelect);
 
         $priceSelectDefault = clone $priceSelect;
         $priceSelectDefault->where('t.store_id = ?', Store::DEFAULT_STORE_ID);
diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/LinkedProductSelectBuilderBySpecialPrice.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/LinkedProductSelectBuilderBySpecialPrice.php
index 792a8f5b86d102204a93491c0413ae2839b16a73..68eaf206e293fea3e90c04e9dfb7bc0329704162 100644
--- a/app/code/Magento/Catalog/Model/ResourceModel/Product/LinkedProductSelectBuilderBySpecialPrice.php
+++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/LinkedProductSelectBuilderBySpecialPrice.php
@@ -7,9 +7,13 @@ namespace Magento\Catalog\Model\ResourceModel\Product;
 
 use Magento\Catalog\Api\Data\ProductInterface;
 use Magento\Catalog\Model\Product;
+use Magento\Framework\App\ObjectManager;
 use Magento\Framework\DB\Select;
 use Magento\Store\Model\Store;
 
+/**
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ */
 class LinkedProductSelectBuilderBySpecialPrice implements LinkedProductSelectBuilderInterface
 {
     /**
@@ -47,6 +51,11 @@ class LinkedProductSelectBuilderBySpecialPrice implements LinkedProductSelectBui
      */
     private $metadataPool;
 
+    /**
+     * @var BaseSelectProcessorInterface
+     */
+    private $baseSelectProcessor;
+
     /**
      * @param \Magento\Store\Model\StoreManagerInterface $storeManager
      * @param \Magento\Framework\App\ResourceConnection $resourceConnection
@@ -55,6 +64,7 @@ class LinkedProductSelectBuilderBySpecialPrice implements LinkedProductSelectBui
      * @param \Magento\Framework\Stdlib\DateTime $dateTime
      * @param \Magento\Framework\Stdlib\DateTime\TimezoneInterface $localeDate
      * @param \Magento\Framework\EntityManager\MetadataPool $metadataPool
+     * @param BaseSelectProcessorInterface $baseSelectProcessor
      */
     public function __construct(
         \Magento\Store\Model\StoreManagerInterface $storeManager,
@@ -63,7 +73,8 @@ class LinkedProductSelectBuilderBySpecialPrice implements LinkedProductSelectBui
         \Magento\Catalog\Helper\Data $catalogHelper,
         \Magento\Framework\Stdlib\DateTime $dateTime,
         \Magento\Framework\Stdlib\DateTime\TimezoneInterface $localeDate,
-        \Magento\Framework\EntityManager\MetadataPool $metadataPool
+        \Magento\Framework\EntityManager\MetadataPool $metadataPool,
+        BaseSelectProcessorInterface $baseSelectProcessor = null
     ) {
         $this->storeManager = $storeManager;
         $this->resource = $resourceConnection;
@@ -72,6 +83,8 @@ class LinkedProductSelectBuilderBySpecialPrice implements LinkedProductSelectBui
         $this->dateTime = $dateTime;
         $this->localeDate = $localeDate;
         $this->metadataPool = $metadataPool;
+        $this->baseSelectProcessor = (null !== $baseSelectProcessor)
+            ? $baseSelectProcessor : ObjectManager::getInstance()->get(BaseSelectProcessorInterface::class);
     }
 
     /**
@@ -95,12 +108,12 @@ class LinkedProductSelectBuilderBySpecialPrice implements LinkedProductSelectBui
                 "link.parent_id = parent.$linkField",
                 []
             )->joinInner(
-                ['child' => $productTable],
-                "child.entity_id = link.child_id",
+                [BaseSelectProcessorInterface::PRODUCT_TABLE_ALIAS => $productTable],
+                sprintf('%s.entity_id = link.child_id', BaseSelectProcessorInterface::PRODUCT_TABLE_ALIAS),
                 ['entity_id']
             )->joinInner(
                 ['t' => $specialPriceAttribute->getBackendTable()],
-                "t.$linkField = child.$linkField",
+                sprintf('t.%s = %s.%1$s', $linkField, BaseSelectProcessorInterface::PRODUCT_TABLE_ALIAS),
                 []
             )->joinLeft(
                 ['special_from' => $specialPriceFromDate->getBackendTable()],
@@ -116,7 +129,7 @@ class LinkedProductSelectBuilderBySpecialPrice implements LinkedProductSelectBui
                     $specialPriceToDate->getAttributeId()
                 ),
                 ''
-            )->where('parent.entity_id = ? ', $productId)
+            )->where('parent.entity_id = ?', $productId)
             ->where('t.attribute_id = ?', $specialPriceAttribute->getAttributeId())
             ->where('t.value IS NOT NULL')
             ->where(
@@ -127,6 +140,7 @@ class LinkedProductSelectBuilderBySpecialPrice implements LinkedProductSelectBui
                 $currentDate
             )->order('t.value ' . Select::SQL_ASC)
             ->limit(1);
+        $specialPrice = $this->baseSelectProcessor->process($specialPrice);
 
         $specialPriceDefault = clone $specialPrice;
         $specialPriceDefault->where('t.store_id = ?', Store::DEFAULT_STORE_ID);
diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/LinkedProductSelectBuilderByTierPrice.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/LinkedProductSelectBuilderByTierPrice.php
index d2d6d89c0a2a5828290e1191147451e4f6d20b7b..25bf83f837de72cec501379378e6960084d6b1fd 100644
--- a/app/code/Magento/Catalog/Model/ResourceModel/Product/LinkedProductSelectBuilderByTierPrice.php
+++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/LinkedProductSelectBuilderByTierPrice.php
@@ -6,7 +6,7 @@
 namespace Magento\Catalog\Model\ResourceModel\Product;
 
 use Magento\Catalog\Api\Data\ProductInterface;
-use Magento\Catalog\Model\Product;
+use Magento\Framework\App\ObjectManager;
 use Magento\Framework\DB\Select;
 
 class LinkedProductSelectBuilderByTierPrice implements LinkedProductSelectBuilderInterface
@@ -41,25 +41,34 @@ class LinkedProductSelectBuilderByTierPrice implements LinkedProductSelectBuilde
      */
     private $metadataPool;
 
+    /**
+     * @var BaseSelectProcessorInterface
+     */
+    private $baseSelectProcessor;
+
     /**
      * @param \Magento\Store\Model\StoreManagerInterface $storeManager
      * @param \Magento\Framework\App\ResourceConnection $resourceConnection
      * @param \Magento\Customer\Model\Session $customerSession
      * @param \Magento\Catalog\Helper\Data $catalogHelper
      * @param \Magento\Framework\EntityManager\MetadataPool $metadataPool
+     * @param BaseSelectProcessorInterface $baseSelectProcessor
      */
     public function __construct(
         \Magento\Store\Model\StoreManagerInterface $storeManager,
         \Magento\Framework\App\ResourceConnection $resourceConnection,
         \Magento\Customer\Model\Session $customerSession,
         \Magento\Catalog\Helper\Data $catalogHelper,
-        \Magento\Framework\EntityManager\MetadataPool $metadataPool
+        \Magento\Framework\EntityManager\MetadataPool $metadataPool,
+        BaseSelectProcessorInterface $baseSelectProcessor = null
     ) {
         $this->storeManager = $storeManager;
         $this->resource = $resourceConnection;
         $this->customerSession = $customerSession;
         $this->catalogHelper = $catalogHelper;
         $this->metadataPool = $metadataPool;
+        $this->baseSelectProcessor = (null !== $baseSelectProcessor)
+            ? $baseSelectProcessor : ObjectManager::getInstance()->get(BaseSelectProcessorInterface::class);
     }
 
     /**
@@ -77,18 +86,19 @@ class LinkedProductSelectBuilderByTierPrice implements LinkedProductSelectBuilde
                 "link.parent_id = parent.$linkField",
                 []
             )->joinInner(
-                ['child' => $productTable],
-                "child.entity_id = link.child_id",
+                [BaseSelectProcessorInterface::PRODUCT_TABLE_ALIAS => $productTable],
+                sprintf('%s.entity_id = link.child_id', BaseSelectProcessorInterface::PRODUCT_TABLE_ALIAS),
                 ['entity_id']
             )->joinInner(
                 ['t' => $this->resource->getTableName('catalog_product_entity_tier_price')],
-                "t.$linkField = child.$linkField",
+                sprintf('t.%s = %s.%1$s', $linkField, BaseSelectProcessorInterface::PRODUCT_TABLE_ALIAS),
                 []
-            )->where('parent.entity_id = ? ', $productId)
+            )->where('parent.entity_id = ?', $productId)
             ->where('t.all_groups = 1 OR customer_group_id = ?', $this->customerSession->getCustomerGroupId())
             ->where('t.qty = ?', 1)
             ->order('t.value ' . Select::SQL_ASC)
             ->limit(1);
+        $priceSelect = $this->baseSelectProcessor->process($priceSelect);
 
         $priceSelectDefault = clone $priceSelect;
         $priceSelectDefault->where('t.website_id = ?', self::DEFAULT_WEBSITE_ID);
diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/StatusBaseSelectProcessor.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/StatusBaseSelectProcessor.php
new file mode 100644
index 0000000000000000000000000000000000000000..656998113fdb92e50e5177db4876651cfcd2023a
--- /dev/null
+++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/StatusBaseSelectProcessor.php
@@ -0,0 +1,61 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Catalog\Model\ResourceModel\Product;
+
+use Magento\Catalog\Api\Data\ProductInterface;
+use Magento\Catalog\Model\Product;
+use Magento\Catalog\Model\Product\Attribute\Source\Status;
+use Magento\Eav\Model\Config;
+use Magento\Framework\DB\Select;
+use Magento\Framework\EntityManager\MetadataPool;
+
+/**
+ * Class StatusBaseSelectProcessor
+ */
+class StatusBaseSelectProcessor implements BaseSelectProcessorInterface
+{
+    /**
+     * @var Config
+     */
+    private $eavConfig;
+
+    /**
+     * @var MetadataPool
+     */
+    private $metadataPool;
+
+    /**
+     * @param Config $eavConfig
+     * @param MetadataPool $metadataPool
+     */
+    public function __construct(
+        Config $eavConfig,
+        MetadataPool $metadataPool
+    ) {
+        $this->eavConfig = $eavConfig;
+        $this->metadataPool = $metadataPool;
+    }
+
+    /**
+     * @param Select $select
+     * @return Select
+     */
+    public function process(Select $select)
+    {
+        $linkField = $this->metadataPool->getMetadata(ProductInterface::class)->getLinkField();
+        $statusAttribute = $this->eavConfig->getAttribute(Product::ENTITY, ProductInterface::STATUS);
+
+        $select->join(
+            ['status_attr' => $statusAttribute->getBackendTable()],
+            sprintf('status_attr.%s = %s.%1$s', $linkField, self::PRODUCT_TABLE_ALIAS),
+            []
+        )
+            ->where('status_attr.attribute_id = ?', $statusAttribute->getAttributeId())
+            ->where('status_attr.value = ?', Status::STATUS_ENABLED);
+
+        return $select;
+    }
+}
diff --git a/app/code/Magento/Catalog/Model/System/Config/Backend/Catalog/Url/Rewrite/Suffix.php b/app/code/Magento/Catalog/Model/System/Config/Backend/Catalog/Url/Rewrite/Suffix.php
index 5ed18d15b2f304cdc9ca6e89a7bcc09e2a5c3590..c1f37eca1c55c7b81cf4b14a034738c5211b7085 100644
--- a/app/code/Magento/Catalog/Model/System/Config/Backend/Catalog/Url/Rewrite/Suffix.php
+++ b/app/code/Magento/Catalog/Model/System/Config/Backend/Catalog/Url/Rewrite/Suffix.php
@@ -40,6 +40,11 @@ class Suffix extends \Magento\Framework\App\Config\Value
      */
     protected $resource;
 
+    /**
+     * @var \Magento\Framework\App\Config\ScopePool
+     */
+    private $scopePool;
+
     /**
      * @param \Magento\Framework\Model\Context $context
      * @param \Magento\Framework\Registry $registry
@@ -75,6 +80,22 @@ class Suffix extends \Magento\Framework\App\Config\Value
         $this->resource = $appResource;
     }
 
+    /**
+     * Get instance of ScopePool
+     *
+     * @return \Magento\Framework\App\Config\ScopePool
+     * @deprecated
+     */
+    private function getScopePool()
+    {
+        if ($this->scopePool === null) {
+            $this->scopePool = \Magento\Framework\App\ObjectManager::getInstance()->get(
+                \Magento\Framework\App\Config\ScopePool::class
+            );
+        }
+        return $this->scopePool;
+    }
+
     /**
      * Check url rewrite suffix - whether we can support it
      *
@@ -103,6 +124,24 @@ class Suffix extends \Magento\Framework\App\Config\Value
         return parent::afterSave();
     }
 
+    /**
+     * {@inheritdoc}
+     */
+    public function afterDeleteCommit()
+    {
+        if ($this->isValueChanged()) {
+            $this->updateSuffixForUrlRewrites();
+            if ($this->isCategorySuffixChanged()) {
+                $this->cacheTypeList->invalidate([
+                    \Magento\Framework\App\Cache\Type\Block::TYPE_IDENTIFIER,
+                    \Magento\Framework\App\Cache\Type\Collection::TYPE_IDENTIFIER
+                ]);
+            }
+        }
+
+        return parent::afterDeleteCommit();
+    }
+
     /**
      * Check is category suffix changed
      *
@@ -135,7 +174,12 @@ class Suffix extends \Magento\Framework\App\Config\Value
         }
         $entities = $this->urlFinder->findAllByData($dataFilter);
         $oldSuffixPattern = '~' . preg_quote($this->getOldValue()) . '$~';
-        $suffix = $this->getValue();
+        if ($this->getValue() !== null) {
+            $suffix = $this->getValue();
+        } else {
+            $this->getScopePool()->clean();
+            $suffix = $this->_config->getValue($this->getPath());
+        }
         foreach ($entities as $urlRewrite) {
             $bind = $urlRewrite->getIsAutogenerated()
                 ? [UrlRewrite::REQUEST_PATH => preg_replace($oldSuffixPattern, $suffix, $urlRewrite->getRequestPath())]
diff --git a/app/code/Magento/Catalog/Setup/InstallSchema.php b/app/code/Magento/Catalog/Setup/InstallSchema.php
index 2ccd8af79a5da7eb51f43aeabfa19a9de14c81c1..a2ba6aa283f6516021f0baffaafd6e6470c060f0 100644
--- a/app/code/Magento/Catalog/Setup/InstallSchema.php
+++ b/app/code/Magento/Catalog/Setup/InstallSchema.php
@@ -18,6 +18,7 @@ class InstallSchema implements InstallSchemaInterface
     /**
      * {@inheritdoc}
      * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+     * @throws \Zend_Db_Exception
      */
     public function install(SchemaSetupInterface $setup, ModuleContextInterface $context)
     {
@@ -1853,6 +1854,9 @@ class InstallSchema implements InstallSchemaInterface
         $installer->getConnection()
             ->createTable($table);
 
+        $customerGroupTable = $setup->getConnection()->describeTable($setup->getTable('customer_group'));
+        $customerGroupIdType = $customerGroupTable['customer_group_id']['DATA_TYPE'] == 'int'
+            ? \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER : $customerGroupTable['customer_group_id']['DATA_TYPE'];
         /**
          * Create table 'catalog_product_entity_tier_price'
          */
@@ -1883,7 +1887,7 @@ class InstallSchema implements InstallSchemaInterface
             )
             ->addColumn(
                 'customer_group_id',
-                \Magento\Framework\DB\Ddl\Table::TYPE_SMALLINT,
+                $customerGroupIdType,
                 null,
                 ['unsigned' => true, 'nullable' => false, 'default' => '0'],
                 'Customer Group ID'
@@ -2426,7 +2430,6 @@ class InstallSchema implements InstallSchemaInterface
                 'option_id',
                 $installer->getTable('catalog_product_option'),
                 'option_id',
-                \Magento\Framework\DB\Ddl\Table::ACTION_CASCADE,
                 \Magento\Framework\DB\Ddl\Table::ACTION_CASCADE
             )
             ->setComment(
@@ -2937,7 +2940,7 @@ class InstallSchema implements InstallSchemaInterface
             )
             ->addColumn(
                 'customer_group_id',
-                \Magento\Framework\DB\Ddl\Table::TYPE_SMALLINT,
+                $customerGroupIdType,
                 null,
                 ['unsigned' => true, 'nullable' => false, 'primary' => true],
                 'Customer Group ID'
@@ -3056,7 +3059,7 @@ class InstallSchema implements InstallSchemaInterface
             )
             ->addColumn(
                 'customer_group_id',
-                \Magento\Framework\DB\Ddl\Table::TYPE_SMALLINT,
+                $customerGroupIdType,
                 null,
                 ['unsigned' => true, 'nullable' => false, 'primary' => true],
                 'Customer Group ID'
diff --git a/app/code/Magento/Catalog/Setup/UpgradeSchema.php b/app/code/Magento/Catalog/Setup/UpgradeSchema.php
old mode 100644
new mode 100755
index 9683632f121b6af18a3397e53bac2943521683c9..7fc2ef7d219ba917aa59c9887749a9024bda49ce
--- a/app/code/Magento/Catalog/Setup/UpgradeSchema.php
+++ b/app/code/Magento/Catalog/Setup/UpgradeSchema.php
@@ -36,9 +36,81 @@ class UpgradeSchema implements UpgradeSchemaInterface
         if (version_compare($context->getVersion(), '2.1.0', '<')) {
             $this->addPercentageValueColumn($setup);
         }
+
+        if (version_compare($context->getVersion(), '2.1.1', '<')) {
+            $tables = [
+                'catalog_product_index_price_cfg_opt_agr_idx',
+                'catalog_product_index_price_cfg_opt_agr_tmp',
+                'catalog_product_index_price_cfg_opt_idx',
+                'catalog_product_index_price_cfg_opt_tmp',
+                'catalog_product_index_price_final_idx',
+                'catalog_product_index_price_final_tmp',
+                'catalog_product_index_price_idx',
+                'catalog_product_index_price_opt_agr_idx',
+                'catalog_product_index_price_opt_agr_tmp',
+                'catalog_product_index_price_opt_idx',
+                'catalog_product_index_price_opt_tmp',
+                'catalog_product_index_price_tmp',
+            ];
+            foreach ($tables as $table) {
+                $setup->getConnection()->modifyColumn(
+                    $setup->getTable($table),
+                    'customer_group_id',
+                    ['type' => 'integer', 'nullable' => false]
+                );
+            }
+        }
+
+        if (version_compare($context->getVersion(), '2.1.2', '<')) {
+            $this->addSourceEntityIdToProductEavIndex($setup);
+        }
+
         $setup->endSetup();
     }
 
+    /**
+     * Add the column 'source_id' to the Product EAV index tables.
+     * It allows to identify which entity was used to create value in the index.
+     * It is useful to identify original entity in a composite products.
+     *
+     * @param SchemaSetupInterface $setup
+     * @return void
+     */
+    private function addSourceEntityIdToProductEavIndex(SchemaSetupInterface $setup)
+    {
+        $tables = [
+            'catalog_product_index_eav',
+            'catalog_product_index_eav_idx',
+            'catalog_product_index_eav_tmp',
+            'catalog_product_index_eav_decimal',
+            'catalog_product_index_eav_decimal_idx',
+            'catalog_product_index_eav_decimal_tmp',
+        ];
+        $connection = $setup->getConnection();
+        foreach ($tables as $tableName) {
+            $tableName = $setup->getTable($tableName);
+            $connection->addColumn(
+                $tableName,
+                'source_id',
+                [
+                    'type' => \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER,
+                    'unsigned' => true,
+                    'nullable' => false,
+                    'default' => 0,
+                    'comment' => 'Original entity Id for attribute value',
+                ]
+            );
+            $connection->dropIndex($tableName, $connection->getPrimaryKeyName($tableName));
+            $primaryKeyFields = ['entity_id', 'attribute_id', 'store_id', 'value', 'source_id'];
+            $setup->getConnection()->addIndex(
+                $tableName,
+                $connection->getIndexName($tableName, $primaryKeyFields),
+                $primaryKeyFields,
+                \Magento\Framework\DB\Adapter\AdapterInterface::INDEX_TYPE_PRIMARY
+            );
+        }
+    }
+
     /**
      * @param SchemaSetupInterface $setup
      * @return void
diff --git a/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Category/Image/UploadTest.php b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Category/Image/UploadTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..387e9a8a6a891b305170253befcd5cedb046feeb
--- /dev/null
+++ b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Category/Image/UploadTest.php
@@ -0,0 +1,68 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Catalog\Test\Unit\Controller\Adminhtml\Category\Image;
+
+use Magento\Catalog\Controller\Adminhtml\Category\Image\Upload as Model;
+use Magento\Framework\App\Request\Http as Request;
+use Magento\Catalog\Model\ImageUploader;
+use Magento\Framework\Controller\ResultFactory;
+use Magento\Framework\DataObject;
+
+/**
+ * Class UploadTest
+ */
+class UploadTest extends \PHPUnit_Framework_TestCase
+{
+    private $objectManager;
+
+    protected function setUp()
+    {
+        $this->objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
+    }
+
+    public function executeDataProvider()
+    {
+        return [
+            ['image1', 'image1'],
+            ['image2', 'image2'],
+            [null, 'image'],
+        ];
+    }
+
+    /**
+     * @param string $name
+     * @param string $savedName
+     *
+     * @dataProvider executeDataProvider
+     */
+    public function testExecute($name, $savedName)
+    {
+        $request = $this->objectManager->getObject(Request::class);
+
+        $uploader = $this->getMock(ImageUploader::class, ['saveFileToTmpDir'], [], '', false);
+
+        $resultFactory = $this->getMock(ResultFactory::class, ['create'], [], '', false);
+
+        $resultFactory->expects($this->once())
+            ->method('create')
+            ->will($this->returnValue(new DataObject()));
+
+        $model = $this->objectManager->getObject(Model::class, [
+            'request' => $request,
+            'resultFactory' => $resultFactory,
+            'imageUploader' => $uploader
+        ]);
+
+        $uploader->expects($this->once())
+            ->method('saveFileToTmpDir')
+            ->with($savedName)
+            ->will($this->returnValue([]));
+
+        $request->setParam('param_name', $name);
+
+        $model->execute();
+    }
+}
diff --git a/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Category/SaveTest.php b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Category/SaveTest.php
index 51d99f7219575c205b61de6e5d93727633874f79..745d46710053a7c877e1bf05db47a715175b2bcb 100644
--- a/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Category/SaveTest.php
+++ b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Category/SaveTest.php
@@ -5,6 +5,8 @@
  */
 namespace Magento\Catalog\Test\Unit\Controller\Adminhtml\Category;
 
+use \Magento\Catalog\Controller\Adminhtml\Category\Save as Model;
+
 /**
  * Class SaveTest
  * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
@@ -14,67 +16,47 @@ class SaveTest extends \PHPUnit_Framework_TestCase
     /**
      * @var \Magento\Backend\Model\View\Result\RedirectFactory|\PHPUnit_Framework_MockObject_MockObject
      */
-    protected $resultRedirectFactoryMock;
-
-    /**
-     * @var \Magento\Framework\Controller\Result\RawFactory|\PHPUnit_Framework_MockObject_MockObject
-     */
-    protected $resultRawFactoryMock;
+    private $resultRedirectFactoryMock;
 
     /**
      * @var \Magento\Framework\Controller\Result\JsonFactory|\PHPUnit_Framework_MockObject_MockObject
      */
-    protected $resultJsonFactoryMock;
+    private $resultJsonFactoryMock;
 
     /**
      * @var \Magento\Framework\View\LayoutFactory|\PHPUnit_Framework_MockObject_MockObject
      */
-    protected $layoutFactoryMock;
-
-    /**
-     * @var \Magento\Backend\App\Action\Context|\PHPUnit_Framework_MockObject_MockObject
-     */
-    protected $contextMock;
-
-    /**
-     * @var \Magento\Framework\View\Page\Title|\PHPUnit_Framework_MockObject_MockObject
-     */
-    protected $titleMock;
+    private $layoutFactoryMock;
 
     /**
      * @var \Magento\Framework\App\RequestInterface|\PHPUnit_Framework_MockObject_MockObject
      */
-    protected $requestMock;
+    private $requestMock;
 
     /**
      * @var \Magento\Framework\ObjectManagerInterface|\PHPUnit_Framework_MockObject_MockObject
      */
-    protected $objectManagerMock;
+    private $objectManagerMock;
 
     /**
      * @var \Magento\Framework\Event\ManagerInterface|\PHPUnit_Framework_MockObject_MockObject
      */
-    protected $eventManagerMock;
-
-    /**
-     * @var \Magento\Framework\App\ResponseInterface|\PHPUnit_Framework_MockObject_MockObject
-     */
-    protected $responseMock;
+    private $eventManagerMock;
 
     /**
      * @var \Magento\Framework\Message\ManagerInterface|\PHPUnit_Framework_MockObject_MockObject
      */
-    protected $messageManagerMock;
+    private $messageManagerMock;
 
     /**
      * @var \Magento\Framework\TestFramework\Unit\Helper\ObjectManager
      */
-    protected $objectManager;
+    private $objectManager;
 
     /**
      * @var \Magento\Catalog\Controller\Adminhtml\Category\Save
      */
-    protected $save;
+    private $save;
 
     /**
      * Set up
@@ -84,24 +66,7 @@ class SaveTest extends \PHPUnit_Framework_TestCase
      */
     protected function setUp()
     {
-        $this->markTestSkipped('Due to MAGETWO-48956');
         $this->objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
-
-        $this->contextMock = $this->getMock(
-            \Magento\Backend\App\Action\Context::class,
-            [
-                'getTitle',
-                'getRequest',
-                'getObjectManager',
-                'getEventManager',
-                'getResponse',
-                'getMessageManager',
-                'getResultRedirectFactory'
-            ],
-            [],
-            '',
-            false
-        );
         $this->resultRedirectFactoryMock = $this->getMock(
             \Magento\Backend\Model\View\Result\RedirectFactory::class,
             ['create'],
@@ -109,13 +74,6 @@ class SaveTest extends \PHPUnit_Framework_TestCase
             '',
             false
         );
-        $this->resultRawFactoryMock = $this->getMock(
-            \Magento\Framework\Controller\Result\RawFactory::class,
-            [],
-            [],
-            '',
-            false
-        );
         $this->resultJsonFactoryMock = $this->getMock(
             \Magento\Framework\Controller\Result\JsonFactory::class,
             ['create'],
@@ -151,12 +109,6 @@ class SaveTest extends \PHPUnit_Framework_TestCase
             true,
             ['dispatch']
         );
-        $this->responseMock = $this->getMockForAbstractClass(
-            \Magento\Framework\App\ResponseInterface::class,
-            [],
-            '',
-            false
-        );
         $this->messageManagerMock = $this->getMockForAbstractClass(
             \Magento\Framework\Message\ManagerInterface::class,
             [],
@@ -167,23 +119,15 @@ class SaveTest extends \PHPUnit_Framework_TestCase
             ['addSuccess', 'getMessages']
         );
 
-        $this->contextMock->expects($this->any())->method('getTitle')->willReturn($this->titleMock);
-        $this->contextMock->expects($this->any())->method('getRequest')->willReturn($this->requestMock);
-        $this->contextMock->expects($this->any())->method('getObjectManager')->willReturn($this->objectManagerMock);
-        $this->contextMock->expects($this->any())->method('getEventManager')->willReturn($this->eventManagerMock);
-        $this->contextMock->expects($this->any())->method('getResponse')->willReturn($this->responseMock);
-        $this->contextMock->expects($this->any())->method('getMessageManager')->willReturn($this->messageManagerMock);
-        $this->contextMock->expects($this->any())
-            ->method('getResultRedirectFactory')
-            ->willReturn($this->resultRedirectFactoryMock);
-
         $this->save = $this->objectManager->getObject(
             \Magento\Catalog\Controller\Adminhtml\Category\Save::class,
             [
-                'context' => $this->contextMock,
-                'resultRawFactory' => $this->resultRawFactoryMock,
+                'request' => $this->requestMock,
+                'eventManager' => $this->eventManagerMock,
+                'messageManager' => $this->messageManagerMock,
                 'resultJsonFactory' => $this->resultJsonFactoryMock,
-                'layoutFactory' => $this->layoutFactoryMock
+                'layoutFactory' => $this->layoutFactoryMock,
+                'resultRedirectFactory' => $this->resultRedirectFactoryMock
             ]
         );
     }
@@ -201,6 +145,8 @@ class SaveTest extends \PHPUnit_Framework_TestCase
      */
     public function testExecute($categoryId, $storeId, $parentId)
     {
+        $this->markTestSkipped('Due to MAGETWO-48956');
+
         $rootCategoryId = \Magento\Catalog\Model\Category::TREE_ROOT_ID;
         $products = [['any_product']];
         $postData = [
@@ -577,4 +523,95 @@ class SaveTest extends \PHPUnit_Framework_TestCase
             ]
         ];
     }
+
+    /**
+     * @return array
+     */
+    public function imagePreprocessingDataProvider()
+    {
+        return [
+            [['attribute1' => null, 'attribute2' => 123]],
+            [['attribute2' => 123]]
+        ];
+    }
+
+    /**
+     * @dataProvider imagePreprocessingDataProvider
+     *
+     * @param array $data
+     */
+    public function testImagePreprocessingWithoutValue($data)
+    {
+        $eavConfig = $this->getMock(\Magento\Eav\Model\Config::class, ['getEntityType'], [], '', false);
+
+        $imageBackendModel = $this->objectManager->getObject(
+            \Magento\Catalog\Model\Category\Attribute\Backend\Image::class
+        );
+
+        $collection = new \Magento\Framework\DataObject(['attribute_collection' => [
+            new \Magento\Framework\DataObject([
+                'attribute_code' => 'attribute1',
+                'backend' => $imageBackendModel
+            ]),
+            new \Magento\Framework\DataObject([
+                'attribute_code' => 'attribute2',
+                'backend' => new \Magento\Framework\DataObject()
+            ])
+        ]]);
+
+        $eavConfig->expects($this->once())
+            ->method('getEntityType')
+            ->with(\Magento\Catalog\Api\Data\CategoryAttributeInterface::ENTITY_TYPE_CODE)
+            ->will($this->returnValue($collection));
+
+        $model = $this->objectManager->getObject(\Magento\Catalog\Controller\Adminhtml\Category\Save::class, [
+            'eavConfig' => $eavConfig
+        ]);
+
+        $result = $model->imagePreprocessing($data);
+
+        $this->assertEquals([
+            'attribute1' => false,
+            'attribute2' => 123
+        ], $result);
+    }
+
+    public function testImagePreprocessingWithValue()
+    {
+        $eavConfig = $this->getMock(\Magento\Eav\Model\Config::class, ['getEntityType'], [], '', false);
+
+        $imageBackendModel = $this->objectManager->getObject(
+            \Magento\Catalog\Model\Category\Attribute\Backend\Image::class
+        );
+
+        $collection = new \Magento\Framework\DataObject(['attribute_collection' => [
+            new \Magento\Framework\DataObject([
+                'attribute_code' => 'attribute1',
+                'backend' => $imageBackendModel
+            ]),
+            new \Magento\Framework\DataObject([
+                'attribute_code' => 'attribute2',
+                'backend' => new \Magento\Framework\DataObject()
+            ])
+        ]]);
+
+        $eavConfig->expects($this->once())
+            ->method('getEntityType')
+            ->with(\Magento\Catalog\Api\Data\CategoryAttributeInterface::ENTITY_TYPE_CODE)
+            ->will($this->returnValue($collection));
+
+        $model = $this->objectManager->getObject(Model::class, [
+            'eavConfig' => $eavConfig
+        ]);
+
+        $result = $model->imagePreprocessing([
+            'attribute1' => 'somevalue',
+            'attribute2' => null
+        ]);
+
+        $this->assertEquals([
+            'attribute1' => 'somevalue',
+            'attribute2' => null
+        ], $result);
+    }
 }
diff --git a/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/AddAttributeToTemplateTest.php b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/AddAttributeToTemplateTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..a55766f895b62511ced21eedaacc67f6c29811ae
--- /dev/null
+++ b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/AddAttributeToTemplateTest.php
@@ -0,0 +1,247 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Catalog\Test\Unit\Controller\Adminhtml\Product;
+
+use Magento\Catalog\Controller\Adminhtml\Product\AddAttributeToTemplate;
+use Magento\Framework\Exception\LocalizedException;
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
+use Magento\Backend\App\Action\Context;
+use Magento\Catalog\Controller\Adminhtml\Product\Builder as ProductBuilder;
+use Magento\Framework\Controller\Result\JsonFactory;
+use Magento\Framework\App\RequestInterface;
+use Magento\Catalog\Api\AttributeSetRepositoryInterface;
+use Magento\Eav\Api\Data\AttributeSetInterface;
+use Magento\Framework\Api\SearchCriteriaBuilder;
+use Magento\Framework\Api\SearchCriteria;
+use Magento\Eav\Api\AttributeGroupRepositoryInterface;
+use Magento\Eav\Api\Data\AttributeGroupSearchResultsInterface;
+use Magento\Eav\Api\Data\AttributeGroupInterfaceFactory;
+use Magento\Eav\Api\Data\AttributeGroupInterface;
+use Magento\Framework\Controller\Result\Json;
+
+/**
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ */
+class AddAttributeToTemplateTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var ObjectManager
+     */
+    private $objectManager;
+
+    /**
+     * @var AddAttributeToTemplate
+     */
+    private $controller;
+
+    /**
+     * @var Context|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $contextMock;
+
+    /**
+     * @var ProductBuilder|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $productBuilderMock;
+
+    /**
+     * @var JsonFactory|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $resultJsonFactoryMock;
+
+    /**
+     * @var RequestInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $requestMock;
+
+    /**
+     * @var AttributeSetRepositoryInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $attributeSetRepositoryMock;
+
+    /**
+     * @var AttributeSetInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $attributeSetInterfaceMock;
+
+    /**
+     * @var SearchCriteriaBuilder|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $searchCriteriaBuilderMock;
+
+    /**
+     * @var SearchCriteria|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $searchCriteriaMock;
+
+    /**
+     * @var AttributeGroupRepositoryInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $attributeGroupRepositoryMock;
+
+    /**
+     * @var AttributeGroupSearchResultsInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $attributeGroupSearchResultsMock;
+
+    /**
+     * @var AttributeGroupInterfaceFactory|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $attributeGroupInterfaceFactoryMock;
+
+    /**
+     * @var AttributeGroupInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $attributeGroupInterfaceMock;
+
+    /**
+     * @var Json|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $jsonMock;
+
+    protected function setUp()
+    {
+        $this->objectManager = new ObjectManager($this);
+        $this->contextMock = $this->getMockBuilder(Context::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->productBuilderMock = $this->getMockBuilder(ProductBuilder::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->resultJsonFactoryMock = $this->getMockBuilder(JsonFactory::class)
+            ->disableOriginalConstructor()
+            ->setMethods(['create'])
+            ->getMock();
+        $this->requestMock = $this->getMockBuilder(\Magento\Framework\App\RequestInterface::class)
+            ->setMethods(['getParam', 'setParam'])
+            ->getMockForAbstractClass();
+        $this->contextMock->expects($this->once())
+            ->method('getRequest')
+            ->willReturn($this->requestMock);
+        $this->attributeSetRepositoryMock = $this->getMockBuilder(AttributeSetRepositoryInterface::class)
+            ->setMethods(['get'])
+            ->getMockForAbstractClass();
+        $this->attributeSetInterfaceMock = $this->getMockBuilder(AttributeSetInterface::class)
+            ->getMockForAbstractClass();
+        $this->searchCriteriaBuilderMock = $this->getMockBuilder(SearchCriteriaBuilder::class)
+            ->disableOriginalConstructor()
+            ->setMethods(['addFilter', 'create', 'setPageSize'])
+            ->getMockForAbstractClass();
+        $this->searchCriteriaMock = $this->getMockBuilder(SearchCriteria::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->attributeGroupRepositoryMock = $this->getMockBuilder(AttributeGroupRepositoryInterface::class)
+            ->setMethods(['getList'])
+            ->getMockForAbstractClass();
+        $this->attributeGroupSearchResultsMock = $this->getMockBuilder(AttributeGroupSearchResultsInterface::class)
+            ->setMethods(['getItems'])
+            ->getMockForAbstractClass();
+        $this->attributeGroupInterfaceFactoryMock = $this->getMockBuilder(AttributeGroupInterfaceFactory::class)
+            ->setMethods(['create'])
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->attributeGroupInterfaceMock = $this->getMockBuilder(AttributeGroupInterface::class)
+            ->setMethods(['getExtensionAttributes'])
+            ->getMockForAbstractClass();
+        $this->jsonMock = $this->getMockBuilder(Json::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->controller = $this->objectManager->getObject(
+            AddAttributeToTemplate::class,
+            [
+                'context' => $this->contextMock,
+                'productBuilder' => $this->productBuilderMock,
+                'resultJsonFactory' => $this->resultJsonFactoryMock,
+            ]
+        );
+
+        $this->objectManager->setBackwardCompatibleProperty(
+            $this->controller,
+            'attributeSetRepository',
+            $this->attributeSetRepositoryMock
+        );
+        $this->objectManager->setBackwardCompatibleProperty(
+            $this->controller,
+            'searchCriteriaBuilder',
+            $this->searchCriteriaBuilderMock
+        );
+        $this->objectManager->setBackwardCompatibleProperty(
+            $this->controller,
+            'attributeGroupRepository',
+            $this->attributeGroupRepositoryMock
+        );
+        $this->objectManager->setBackwardCompatibleProperty(
+            $this->controller,
+            'attributeGroupFactory',
+            $this->attributeGroupInterfaceFactoryMock
+        );
+    }
+
+    public function testExecuteWithoutAttributeGroupItems()
+    {
+        $groupCode = 'attributes';
+        $groupName = 'Attributes';
+        $groupSortOrder = '15';
+        $templateId = '4';
+        $attributeIds = [
+            'selected' => ["178"],
+            'total' => '1'
+        ];
+
+        $this->requestMock
+            ->expects($this->any())
+            ->method('getParam')
+            ->willReturnMap(
+                [
+                    ['groupCode', null, $groupCode],
+                    ['groupName', null, $groupName],
+                    ['groupSortOrder', null, $groupSortOrder],
+                    ['templateId', null, $templateId],
+                    ['attributeIds', [], $attributeIds]
+                ]
+            );
+
+        $this->attributeSetRepositoryMock->expects($this->once())
+            ->method('get')
+            ->willReturn($this->attributeSetInterfaceMock);
+
+        $this->searchCriteriaBuilderMock->expects($this->any())
+            ->method('addFilter')
+            ->willReturnSelf();
+        $this->searchCriteriaBuilderMock->expects($this->any())
+            ->method('create')
+            ->willReturn($this->searchCriteriaMock);
+        $this->searchCriteriaBuilderMock->expects($this->once())
+            ->method('setPageSize')
+            ->willReturnSelf();
+        $this->searchCriteriaBuilderMock->expects($this->never())
+            ->method('addSortOrder')
+            ->willReturnSelf();
+
+        $this->attributeGroupRepositoryMock->expects($this->once())
+            ->method('getList')
+            ->willReturn($this->attributeGroupSearchResultsMock);
+        $this->attributeGroupSearchResultsMock->expects($this->once())
+            ->method('getItems')
+            ->willReturn(null);
+
+        $this->attributeGroupInterfaceFactoryMock->expects($this->once())
+            ->method('create')
+            ->willReturn($this->attributeGroupInterfaceMock);
+        $this->attributeGroupInterfaceMock->expects($this->once())
+            ->method('getExtensionAttributes')
+            ->willThrowException(new LocalizedException(__('Could not get extension attributes')));
+
+        $this->resultJsonFactoryMock->expects($this->once())
+            ->method('create')
+            ->willReturn($this->jsonMock);
+        $this->jsonMock->expects($this->once())->method('setJsonData')
+            ->willReturnSelf();
+
+        $this->controller->execute();
+    }
+}
diff --git a/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Initialization/HelperTest.php b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Initialization/HelperTest.php
index a4218e92b3486db76afc61254553b914610d99c3..c67ed25d9c6665901beaeae6d7c2835b3bb20bc1 100644
--- a/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Initialization/HelperTest.php
+++ b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Initialization/HelperTest.php
@@ -5,18 +5,14 @@
  */
 namespace Magento\Catalog\Test\Unit\Controller\Adminhtml\Product\Initialization;
 
-use Magento\Catalog\Api\Data\ProductLinkInterfaceFactory;
 use Magento\Catalog\Controller\Adminhtml\Product\Initialization\Helper;
 use Magento\Catalog\Controller\Adminhtml\Product\Initialization\StockDataFilter;
 use Magento\Catalog\Model\Product;
 use Magento\Catalog\Model\Product\Option;
-use Magento\Catalog\Model\ProductRepository;
 use Magento\Framework\App\RequestInterface;
 use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
-use Magento\Store\Api\Data\StoreInterface;
 use Magento\Store\Api\Data\WebsiteInterface;
 use Magento\Store\Model\StoreManagerInterface;
-use Magento\Framework\Stdlib\DateTime\Filter\Date as DateFilter;
 use Magento\Catalog\Api\Data\ProductCustomOptionInterfaceFactory;
 use Magento\Catalog\Model\Product\Initialization\Helper\ProductLinks;
 
@@ -34,11 +30,6 @@ class HelperTest extends \PHPUnit_Framework_TestCase
      */
     protected $objectManager;
 
-    /**
-     * @var int
-     */
-    protected $websiteId = 1;
-
     /**
      * @var Helper
      */
@@ -64,106 +55,54 @@ class HelperTest extends \PHPUnit_Framework_TestCase
      */
     protected $productMock;
 
-    /**
-     * @var StoreInterface|\PHPUnit_Framework_MockObject_MockObject
-     */
-    protected $storeMock;
-
-    /**
-     * @var WebsiteInterface|\PHPUnit_Framework_MockObject_MockObject
-     */
-    protected $websiteMock;
-
-    /**
-     * @var DateFilter|\PHPUnit_Framework_MockObject_MockObject
-     */
-    protected $dateFilterMock;
-
-    /**
-     * @var ProductLinkInterfaceFactory|\PHPUnit_Framework_MockObject_MockObject
-     */
-    protected $productLinkFactoryMock;
-
-    /**
-     * @var ProductRepository|\PHPUnit_Framework_MockObject_MockObject
-     */
-    protected $productRepositoryMock;
-
     /**
      * @var ProductCustomOptionInterfaceFactory|\PHPUnit_Framework_MockObject_MockObject
      */
     protected $customOptionFactoryMock;
 
     /**
-     * @var Option|\PHPUnit_Framework_MockObject_MockObject
-     */
-    protected $customOptionMock;
-
-    /**
-     * @var \PHPUnit_Framework_MockObject_MockObject
+     * @var \Magento\Catalog\Model\Product\Link\Resolver|\PHPUnit_Framework_MockObject_MockObject
      */
     protected $linkResolverMock;
 
     /**
-     * @var ProductLinks
+     * @var ProductLinks|\PHPUnit_Framework_MockObject_MockObject
      */
     protected $productLinksMock;
 
     protected function setUp()
     {
         $this->objectManager = new ObjectManager($this);
-        $this->productLinkFactoryMock = $this->getMockBuilder(ProductLinkInterfaceFactory::class)
-            ->disableOriginalConstructor()
-            ->getMock();
-        $this->productRepositoryMock = $this->getMockBuilder(ProductRepository::class)
-            ->disableOriginalConstructor()
-            ->getMock();
         $this->requestMock = $this->getMockBuilder(RequestInterface::class)
             ->setMethods(['getPost'])
             ->getMockForAbstractClass();
-        $this->storeMock = $this->getMockBuilder(StoreInterface::class)
-            ->setMethods(['getWebsite'])
-            ->getMockForAbstractClass();
-        $this->websiteMock = $this->getMockBuilder(WebsiteInterface::class)
-            ->getMockForAbstractClass();
         $this->storeManagerMock = $this->getMockBuilder(StoreManagerInterface::class)
             ->getMockForAbstractClass();
-        $this->dateFilterMock = $this->getMockBuilder(DateFilter::class)
-            ->disableOriginalConstructor()
-            ->getMock();
         $this->stockFilterMock = $this->getMockBuilder(StockDataFilter::class)
             ->disableOriginalConstructor()
             ->getMock();
         $this->productMock = $this->getMockBuilder(Product::class)
-            ->setMethods([
-                'getId',
-                'setWebsiteIds',
-                'isLockedAttribute',
-                'lockAttribute',
-                'getAttributes',
-                'unlockAttribute',
-                'getOptionsReadOnly',
-                'setCanSaveCustomOptions',
-                '__sleep',
-                '__wakeup',
-                'getSku',
-                'getProductLinks',
-                'getWebsiteIds'
-            ])
+            ->setMethods(
+                [
+                    'getId',
+                    'isLockedAttribute',
+                    'lockAttribute',
+                    'getAttributes',
+                    'unlockAttribute',
+                    'getOptionsReadOnly',
+                    'getSku',
+                    'getProductLinks',
+                ]
+            )
             ->disableOriginalConstructor()
-            ->getMock();
+            ->getMockForAbstractClass();
         $this->customOptionFactoryMock = $this->getMockBuilder(ProductCustomOptionInterfaceFactory::class)
             ->disableOriginalConstructor()
             ->setMethods(['create'])
             ->getMock();
-        $this->customOptionMock = $this->getMockBuilder(Option::class)
-            ->disableOriginalConstructor()
-            ->setMethods(null)
-            ->getMock();
         $this->productLinksMock = $this->getMockBuilder(ProductLinks::class)
             ->disableOriginalConstructor()
             ->getMock();
-
         $this->productLinksMock->expects($this->any())
             ->method('initializeLinks')
             ->willReturn($this->productMock);
@@ -173,10 +112,7 @@ class HelperTest extends \PHPUnit_Framework_TestCase
             'storeManager' => $this->storeManagerMock,
             'stockFilter' => $this->stockFilterMock,
             'productLinks' => $this->productLinksMock,
-            'dateFilter' => $this->dateFilterMock,
             'customOptionFactory' => $this->customOptionFactoryMock,
-            'productLinkFactory' => $this->productLinkFactoryMock,
-            'productRepository' => $this->productRepositoryMock,
         ]);
 
         $this->linkResolverMock = $this->getMockBuilder(\Magento\Catalog\Model\Product\Link\Resolver::class)
@@ -190,9 +126,13 @@ class HelperTest extends \PHPUnit_Framework_TestCase
 
     /**
      * @covers \Magento\Catalog\Controller\Adminhtml\Product\Initialization\Helper::initialize
-     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+     * @param bool $isSingleStore
+     * @param array $websiteIds
+     * @param array $expWebsiteIds
+     *
+     * @dataProvider initializeDataProvider
      */
-    public function testInitialize()
+    public function testInitialize($isSingleStore, $websiteIds, $expWebsiteIds)
     {
         $optionsData = [
             'option1' => ['is_delete' => true, 'name' => 'name1', 'price' => 'price1', 'option_id' => ''],
@@ -202,6 +142,7 @@ class HelperTest extends \PHPUnit_Framework_TestCase
         $productData = [
             'stock_data' => ['stock_data'],
             'options' => $optionsData,
+            'website_ids' => $websiteIds
         ];
         $attributeNonDate = $this->getMockBuilder(\Magento\Catalog\Model\ResourceModel\Eav\Attribute::class)
             ->disableOriginalConstructor()
@@ -218,69 +159,39 @@ class HelperTest extends \PHPUnit_Framework_TestCase
             ->disableOriginalConstructor()
             ->getMock();
 
-        $attributeNonDate->expects($this->any())
-            ->method('getBackend')
-            ->willReturn($attributeNonDateBackEnd);
-        $attributeDate->expects($this->any())
-            ->method('getBackend')
-            ->willReturn($attributeDateBackEnd);
-        $this->productMock->expects($this->any())
-            ->method('getProductLinks')
-            ->willReturn([]);
-        $attributeNonDateBackEnd->expects($this->any())
-            ->method('getType')
-            ->willReturn('non-datetime');
-        $attributeDateBackEnd->expects($this->any())
-            ->method('getType')
-            ->willReturn('datetime');
-
-        $attributesArray = [
-            $attributeNonDate,
-            $attributeDate
-        ];
+        $attributeNonDate->expects($this->any())->method('getBackend')->willReturn($attributeNonDateBackEnd);
+        $attributeDate->expects($this->any())->method('getBackend')->willReturn($attributeDateBackEnd);
+        $this->productMock->expects($this->any())->method('getProductLinks')->willReturn([]);
+        $attributeNonDateBackEnd->expects($this->any())->method('getType')->willReturn('non-datetime');
+        $attributeDateBackEnd->expects($this->any())->method('getType')->willReturn('datetime');
 
         $useDefaults = ['attributeCode1', 'attributeCode2'];
 
-        $this->requestMock->expects($this->at(0))
-            ->method('getPost')
-            ->with('product')
-            ->willReturn($productData);
-        $this->requestMock->expects($this->at(1))
-            ->method('getPost')
-            ->with('use_default')
-            ->willReturn($useDefaults);
+        $this->requestMock->expects($this->any())->method('getPost')->willReturnMap(
+            [
+                ['product', [], $productData],
+                ['use_default', null, $useDefaults]
+            ]
+        );
         $this->linkResolverMock->expects($this->once())->method('getLinks')->willReturn([]);
-        $this->stockFilterMock->expects($this->once())
-            ->method('filter')
-            ->with(['stock_data'])
+        $this->stockFilterMock->expects($this->once())->method('filter')->with(['stock_data'])
             ->willReturn(['stock_data']);
-        $this->productMock->expects($this->once())
-            ->method('isLockedAttribute')
-            ->with('media')
-            ->willReturn(true);
-        $this->productMock->expects($this->once())
-            ->method('unlockAttribute')
-            ->with('media');
-        $this->productMock->expects($this->any())
-            ->method('getProductLinks')
-            ->willReturn([]);
-        $this->productMock->expects($this->once())
-            ->method('lockAttribute')
-            ->with('media');
-        $this->productMock->expects($this->once())
-            ->method('getAttributes')
-            ->willReturn($attributesArray);
-
-        $this->productMock->expects($this->any())
-            ->method('getSku')
-            ->willReturn('sku');
-        $this->productMock->expects($this->any())
-            ->method('getOptionsReadOnly')
-            ->willReturn(false);
-
-        $firstExpectedCustomOption = clone $this->customOptionMock;
+        $this->productMock->expects($this->once())->method('isLockedAttribute')->with('media')->willReturn(true);
+        $this->productMock->expects($this->once())->method('unlockAttribute')->with('media');
+        $this->productMock->expects($this->any())->method('getProductLinks')->willReturn([]);
+        $this->productMock->expects($this->once())->method('lockAttribute')->with('media');
+        $this->productMock->expects($this->once())->method('getAttributes')
+            ->willReturn([$attributeNonDate, $attributeDate]);
+        $this->productMock->expects($this->any())->method('getSku')->willReturn('sku');
+        $this->productMock->expects($this->any())->method('getOptionsReadOnly')->willReturn(false);
+
+        $customOptionMock = $this->getMockBuilder(Option::class)
+            ->disableOriginalConstructor()
+            ->setMethods(null)
+            ->getMock();
+        $firstExpectedCustomOption = clone $customOptionMock;
         $firstExpectedCustomOption->setData($optionsData['option2']);
-        $secondExpectedCustomOption = clone $this->customOptionMock;
+        $secondExpectedCustomOption = clone $customOptionMock;
         $secondExpectedCustomOption->setData($optionsData['option3']);
         $this->customOptionFactoryMock->expects($this->any())
             ->method('create')
@@ -293,8 +204,13 @@ class HelperTest extends \PHPUnit_Framework_TestCase
                     $secondExpectedCustomOption
                 ]
             ]);
+        $website = $this->getMockBuilder(WebsiteInterface::class)->getMockForAbstractClass();
+        $website->expects($this->any())->method('getId')->willReturn(1);
+        $this->storeManagerMock->expects($this->once())->method('isSingleStoreMode')->willReturn($isSingleStore);
+        $this->storeManagerMock->expects($this->any())->method('getWebsite')->willReturn($website);
 
         $this->assertEquals($this->productMock, $this->helper->initialize($this->productMock));
+        $this->assertEquals($expWebsiteIds, $this->productMock->getDataByKey('website_ids'));
 
         $productOptions = $this->productMock->getOptions();
         $this->assertTrue(2 == count($productOptions));
@@ -305,6 +221,35 @@ class HelperTest extends \PHPUnit_Framework_TestCase
         $this->assertTrue('sku' == $option2->getData('product_sku'));
     }
 
+    /**
+     * @return array
+     */
+    public function initializeDataProvider()
+    {
+        return [
+            [
+                'single_store' => false,
+                'website_ids' => ['1' => 1, '2' => 1],
+                'expected_website_ids' => ['1' => 1, '2' => 1]
+            ],
+            [
+                'single_store' => false,
+                'website_ids' => ['1' => 1, '2' => 0],
+                'expected_website_ids' => ['1' => 1]
+            ],
+            [
+                'single_store' => false,
+                'website_ids' => ['1' => 0, '2' => 0],
+                'expected_website_ids' => []
+            ],
+            [
+                'single_store' => true,
+                'website_ids' => [],
+                'expected_website_ids' => ['1' => 1]
+            ],
+        ];
+    }
+
     /**
      * Data provider for testMergeProductOptions
      *
diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Category/Attribute/Backend/ImageTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Category/Attribute/Backend/ImageTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..aa78fea89668773a2864741526d07c3e76aae1d1
--- /dev/null
+++ b/app/code/Magento/Catalog/Test/Unit/Model/Category/Attribute/Backend/ImageTest.php
@@ -0,0 +1,293 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Catalog\Test\Unit\Model\Category\Attribute\Backend;
+
+class ImageTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\Eav\Model\Entity\Attribute\AbstractAttribute
+     */
+    private $attribute;
+
+    /**
+     * @var \Magento\Framework\TestFramework\Unit\Helper\ObjectManager
+     */
+    private $objectManager;
+
+    /**
+     * @var \Magento\Catalog\Model\ImageUploader
+     */
+    private $imageUploader;
+
+    /**
+     * @var \Psr\Log\LoggerInterface
+     */
+    private $logger;
+
+    protected function setUp()
+    {
+        $this->objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
+
+        $this->attribute = $this->getMockForAbstractClass(
+            \Magento\Eav\Model\Entity\Attribute\AbstractAttribute::class,
+            [],
+            'TestAttribute',
+            false,
+            false,
+            true,
+            ['getName']
+        );
+
+        $this->attribute->expects($this->once())
+            ->method('getName')
+            ->will($this->returnValue('test_attribute'));
+
+        $this->logger = $this->getMockForAbstractClass(
+            \Psr\Log\LoggerInterface::class,
+            [],
+            'TestLogger',
+            false,
+            false,
+            true,
+            ['critical']
+        );
+
+        $this->imageUploader = $this->getMock(
+            \Magento\Catalog\Model\ImageUploader::class,
+            ['moveFileFromTmp'],
+            [],
+            '',
+            false
+        );
+    }
+
+    /**
+     * @return array
+     */
+    public function deletedValueDataProvider()
+    {
+        return [
+            [false],
+            [['delete' => true]]
+        ];
+    }
+
+    /**
+     * @dataProvider deletedValueDataProvider
+     *
+     * @param array $value
+     */
+    public function testBeforeSaveValueDeletion($value)
+    {
+        $model = $this->objectManager->getObject(\Magento\Catalog\Model\Category\Attribute\Backend\Image::class);
+        $model->setAttribute($this->attribute);
+
+        $object = new \Magento\Framework\DataObject([
+            'test_attribute' => $value
+        ]);
+
+        $model->beforeSave($object);
+
+        $this->assertEquals('', $object->getTestAttribute());
+    }
+
+    /**
+     * @return array
+     */
+    public function invalidValueDataProvider()
+    {
+        $closure = function () {
+            return false;
+        };
+
+        return [
+            [1234],
+            [true],
+            [new \stdClass()],
+            [$closure],
+            [['a' => 1, 'b' => 2]]
+        ];
+    }
+
+    /**
+     * @dataProvider invalidValueDataProvider
+     *
+     * @param array $value
+     */
+    public function testBeforeSaveValueInvalid($value)
+    {
+        $model = $this->objectManager->getObject(\Magento\Catalog\Model\Category\Attribute\Backend\Image::class);
+        $model->setAttribute($this->attribute);
+
+        $object = new \Magento\Framework\DataObject([
+            'test_attribute' => $value
+        ]);
+
+        $model->beforeSave($object);
+
+        $this->assertEquals('', $object->getTestAttribute());
+    }
+
+    public function testBeforeSaveAttributeFileName()
+    {
+        $model = $this->objectManager->getObject(\Magento\Catalog\Model\Category\Attribute\Backend\Image::class);
+        $model->setAttribute($this->attribute);
+
+        $object = new \Magento\Framework\DataObject([
+            'test_attribute' => [
+                ['name' => 'test123.jpg']
+            ]
+        ]);
+
+        $model->beforeSave($object);
+
+        $this->assertEquals('test123.jpg', $object->getTestAttribute());
+    }
+
+    public function testBeforeSaveTemporaryAttribute()
+    {
+        $model = $this->objectManager->getObject(\Magento\Catalog\Model\Category\Attribute\Backend\Image::class);
+        $model->setAttribute($this->attribute);
+
+        $object = new \Magento\Framework\DataObject([
+            'test_attribute' => [
+                ['name' => 'test123.jpg', 'tmp_name' => 'abc123', 'url' => 'http://www.example.com/test123.jpg']
+            ]
+        ]);
+
+        $model->beforeSave($object);
+
+        $this->assertEquals([
+            ['name' => 'test123.jpg', 'tmp_name' => 'abc123', 'url' => 'http://www.example.com/test123.jpg']
+        ], $object->getData('_additional_data_test_attribute'));
+    }
+
+    public function testBeforeSaveAttributeStringValue()
+    {
+        $model = $this->objectManager->getObject(\Magento\Catalog\Model\Category\Attribute\Backend\Image::class);
+        $model->setAttribute($this->attribute);
+
+        $object = new \Magento\Framework\DataObject([
+            'test_attribute' => 'test123.jpg'
+        ]);
+
+        $model->beforeSave($object);
+
+        $this->assertEquals('test123.jpg', $object->getTestAttribute());
+        $this->assertNull($object->getData('_additional_data_test_attribute'));
+    }
+
+    /**
+     * @return \Magento\Catalog\Model\Category\Attribute\Backend\Image
+     */
+    private function setUpModelForAfterSave()
+    {
+        $objectManagerMock = $this->getMock(
+            \Magento\Framework\App\ObjectManager::class,
+            ['get'],
+            [],
+            '',
+            false
+        );
+
+        $imageUploaderMock = $this->imageUploader;
+
+        $objectManagerMock->expects($this->any())
+            ->method('get')
+            ->will($this->returnCallback(function ($class, $params = []) use ($imageUploaderMock) {
+                if ($class == \Magento\Catalog\CategoryImageUpload::class) {
+                    return $imageUploaderMock;
+                }
+
+                return $this->objectManager->get($class, $params);
+            }));
+
+        $model = $this->objectManager->getObject(\Magento\Catalog\Model\Category\Attribute\Backend\Image::class, [
+            'objectManager' => $objectManagerMock,
+            'logger' => $this->logger
+        ]);
+        $this->objectManager->setBackwardCompatibleProperty($model, 'imageUploader', $this->imageUploader);
+
+        return $model->setAttribute($this->attribute);
+    }
+
+    public function attributeValueDataProvider()
+    {
+        return [
+            [[['name' => 'test1234.jpg']]],
+            ['test1234.jpg'],
+            [''],
+            [false]
+        ];
+    }
+
+    /**
+     * @dataProvider attributeValueDataProvider
+     *
+     * @param array $value
+     */
+    public function testAfterSaveWithAdditionalData($value)
+    {
+        $model = $this->setUpModelForAfterSave();
+
+        $this->imageUploader->expects($this->once())
+            ->method('moveFileFromTmp')
+            ->with($this->equalTo('test1234.jpg'));
+
+        $object = new \Magento\Framework\DataObject(
+            [
+                'test_attribute' => $value,
+                '_additional_data_test_attribute' => [['name' => 'test1234.jpg']]
+            ]
+        );
+
+        $model->afterSave($object);
+    }
+
+    /**
+     * @dataProvider attributeValueDataProvider
+     *
+     * @param array $value
+     */
+    public function testAfterSaveWithoutAdditionalData($value)
+    {
+        $model = $this->setUpModelForAfterSave();
+
+        $this->imageUploader->expects($this->never())
+            ->method('moveFileFromTmp');
+
+        $object = new \Magento\Framework\DataObject(
+            [
+                'test_attribute' => $value
+            ]
+        );
+
+        $model->afterSave($object);
+    }
+
+    public function testAfterSaveWithExceptions()
+    {
+        $model = $this->setUpModelForAfterSave();
+
+        $exception = new \Exception();
+
+        $this->imageUploader->expects($this->any())
+            ->method('moveFileFromTmp')
+            ->will($this->throwException($exception));
+
+        $this->logger->expects($this->once())
+            ->method('critical')
+            ->with($this->equalTo($exception));
+
+        $object = new \Magento\Framework\DataObject(
+            [
+                '_additional_data_test_attribute' => [['name' => 'test1234.jpg']]
+            ]
+        );
+
+        $model->afterSave($object);
+    }
+}
diff --git a/app/code/Magento/Catalog/Test/Unit/Model/CategoryTest.php b/app/code/Magento/Catalog/Test/Unit/Model/CategoryTest.php
index 471037f1d3f450c1b2281e06f823222e7f7e28b6..37d0751a81bc06cfb4672874fff20dfefab6cb72 100644
--- a/app/code/Magento/Catalog/Test/Unit/Model/CategoryTest.php
+++ b/app/code/Magento/Catalog/Test/Unit/Model/CategoryTest.php
@@ -9,6 +9,7 @@
 namespace Magento\Catalog\Test\Unit\Model;
 
 use Magento\Catalog\Model\Indexer;
+use Magento\Catalog\Model\Category;
 
 /**
  * @SuppressWarnings(PHPMD.TooManyFields)
@@ -16,113 +17,131 @@ use Magento\Catalog\Model\Indexer;
  */
 class CategoryTest extends \PHPUnit_Framework_TestCase
 {
-    /** @var \Magento\Catalog\Model\Category */
-    protected $category;
-
-    /** @var \Magento\Framework\Model\Context|\PHPUnit_Framework_MockObject_MockObject */
-    protected $context;
-
-    /** @var \Magento\Framework\Event\ManagerInterface|\PHPUnit_Framework_MockObject_MockObject */
-    protected $eventManager;
+    /**
+     * @var \Magento\Catalog\Model\Category
+     */
+    private $category;
 
-    /** @var \Magento\Framework\App\CacheInterface|\PHPUnit_Framework_MockObject_MockObject */
-    protected $cacheManager;
+    /**
+     * @var \Magento\Framework\Registry|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $registry;
 
-    /** @var \Magento\Framework\Registry|\PHPUnit_Framework_MockObject_MockObject */
-    protected $registry;
+    /**
+     * @var \Magento\Store\Model\StoreManagerInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $storeManager;
 
-    /** @var \Magento\Store\Model\StoreManagerInterface|\PHPUnit_Framework_MockObject_MockObject */
-    protected $storeManager;
+    /**
+     * @var \Magento\Catalog\Model\ResourceModel\Category\Tree|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $categoryTreeResource;
 
-    /** @var \Magento\Catalog\Model\ResourceModel\Category\Tree|\PHPUnit_Framework_MockObject_MockObject */
-    protected $categoryTreeResource;
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    private $categoryTreeFactory;
 
-    /** @var \PHPUnit_Framework_MockObject_MockObject */
-    protected $categoryTreeFactory;
+    /**
+     * @var \Magento\Catalog\Api\CategoryRepositoryInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $categoryRepository;
 
-    /** @var \Magento\Catalog\Api\CategoryRepositoryInterface|\PHPUnit_Framework_MockObject_MockObject */
-    protected $categoryRepository;
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    private $storeCollectionFactory;
 
-    /** @var \PHPUnit_Framework_MockObject_MockObject */
-    protected $storeCollectionFactory;
+    /**
+     * @var \Magento\Framework\UrlInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $url;
 
-    /** @var \Magento\Framework\UrlInterface|\PHPUnit_Framework_MockObject_MockObject */
-    protected $url;
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    private $productCollectionFactory;
 
-    /** @var \PHPUnit_Framework_MockObject_MockObject */
-    protected $productCollectionFactory;
+    /**
+     * @var \Magento\Catalog\Model\Config|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $catalogConfig;
 
-    /** @var \Magento\Catalog\Model\Config|\PHPUnit_Framework_MockObject_MockObject */
-    protected $catalogConfig;
+    /**
+     * @var \Magento\Framework\Filter\FilterManager|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $filterManager;
 
-    /** @var \Magento\Framework\Filter\FilterManager|\PHPUnit_Framework_MockObject_MockObject */
-    protected $filterManager;
+    /**
+     * @var \Magento\Catalog\Model\Indexer\Category\Flat\State|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $flatState;
 
-    /** @var \Magento\Catalog\Model\Indexer\Category\Flat\State|\PHPUnit_Framework_MockObject_MockObject */
-    protected $flatState;
+    /**
+     * @var \Magento\Framework\Indexer\IndexerInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $flatIndexer;
 
-    /** @var \Magento\Framework\Indexer\IndexerInterface|\PHPUnit_Framework_MockObject_MockObject */
-    protected $flatIndexer;
+    /**
+     * @var \Magento\Framework\Indexer\IndexerInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $productIndexer;
 
-    /** @var \Magento\Framework\Indexer\IndexerInterface|\PHPUnit_Framework_MockObject_MockObject */
-    protected $productIndexer;
+    /**
+     * @var \Magento\CatalogUrlRewrite\Model\CategoryUrlPathGenerator|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $categoryUrlPathGenerator;
 
-    /** @var \Magento\CatalogUrlRewrite\Model\CategoryUrlPathGenerator|\PHPUnit_Framework_MockObject_MockObject */
-    protected $categoryUrlPathGenerator;
+    /**
+     * @var \Magento\UrlRewrite\Model\UrlFinderInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $urlFinder;
 
-    /** @var \Magento\UrlRewrite\Model\UrlFinderInterface|\PHPUnit_Framework_MockObject_MockObject */
-    protected $urlFinder;
+    /**
+     * @var \Magento\Framework\Model\ResourceModel\AbstractResource|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $resource;
 
-    /** @var \Magento\Framework\Model\ResourceModel\AbstractResource|\PHPUnit_Framework_MockObject_MockObject */
-    protected $resource;
+    /**
+     * @var \Magento\Framework\Indexer\IndexerRegistry|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $indexerRegistry;
 
-    /** @var \Magento\Framework\Indexer\IndexerRegistry|\PHPUnit_Framework_MockObject_MockObject */
-    protected $indexerRegistry;
+    /**
+     * @var \Magento\Catalog\Api\CategoryAttributeRepositoryInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $metadataServiceMock;
 
     /**
      * @var \PHPUnit_Framework_MockObject_MockObject
      */
-    protected $metadataServiceMock;
+    private $attributeValueFactory;
 
     /**
-     * @var \PHPUnit_Framework_MockObject_MockObject
+     * @var \Magento\Framework\TestFramework\Unit\Helper\ObjectManager
      */
-    protected $attributeValueFactory;
+    private $objectManager;
 
     protected function setUp()
     {
-        $this->context = $this->getMock(
-            \Magento\Framework\Model\Context::class,
-            ['getEventDispatcher', 'getCacheManager'],
+        $this->objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
+        $this->registry = $this->getMock(\Magento\Framework\Registry::class);
+        $this->storeManager = $this->getMock(\Magento\Store\Model\StoreManagerInterface::class);
+        $this->categoryTreeResource = $this->getMock(
+            \Magento\Catalog\Model\ResourceModel\Category\Tree::class,
+            [],
             [],
             '',
             false
         );
-
-        $this->eventManager = $this->getMock(\Magento\Framework\Event\ManagerInterface::class);
-        $this->context->expects($this->any())->method('getEventDispatcher')
-            ->will($this->returnValue($this->eventManager));
-        $this->cacheManager = $this->getMock(\Magento\Framework\App\CacheInterface::class);
-        $this->context->expects($this->any())->method('getCacheManager')
-            ->will($this->returnValue($this->cacheManager));
-
-        $this->registry = $this->getMock(\Magento\Framework\Registry::class);
-        $this->storeManager = $this->getMock(\Magento\Store\Model\StoreManagerInterface::class);
-        $this->categoryTreeResource = $this->getMock(
-            \Magento\Catalog\Model\ResourceModel\Category\Tree::class,
-            [],
-            [],
-            '',
-            false
-        );
-        $this->categoryTreeFactory = $this->getMock(
+        $this->categoryTreeFactory = $this->getMock(
             \Magento\Catalog\Model\ResourceModel\Category\TreeFactory::class,
             ['create'],
             [],
             '',
             false);
         $this->categoryRepository = $this->getMock(\Magento\Catalog\Api\CategoryRepositoryInterface::class);
-        $this->storeCollectionFactory = $this->getMock(
+        $this->storeCollectionFactory = $this->getMock(
             \Magento\Store\Model\ResourceModel\Store\CollectionFactory::class,
             ['create'],
             [],
@@ -130,7 +149,7 @@ class CategoryTest extends \PHPUnit_Framework_TestCase
             false
         );
         $this->url = $this->getMock(\Magento\Framework\UrlInterface::class);
-        $this->productCollectionFactory = $this->getMock(
+        $this->productCollectionFactory = $this->getMock(
             \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory::class,
             ['create'],
             [],
@@ -138,7 +157,7 @@ class CategoryTest extends \PHPUnit_Framework_TestCase
             false
         );
         $this->catalogConfig = $this->getMock(\Magento\Catalog\Model\Config::class, [], [], '', false);
-        $this->filterManager = $this->getMock(
+        $this->filterManager = $this->getMock(
             \Magento\Framework\Filter\FilterManager::class,
             ['translitUrl'],
             [],
@@ -148,7 +167,7 @@ class CategoryTest extends \PHPUnit_Framework_TestCase
         $this->flatState = $this->getMock(\Magento\Catalog\Model\Indexer\Category\Flat\State::class, [], [], '', false);
         $this->flatIndexer = $this->getMock(\Magento\Framework\Indexer\IndexerInterface::class);
         $this->productIndexer = $this->getMock(\Magento\Framework\Indexer\IndexerInterface::class);
-        $this->categoryUrlPathGenerator = $this->getMock(
+        $this->categoryUrlPathGenerator = $this->getMock(
             \Magento\CatalogUrlRewrite\Model\CategoryUrlPathGenerator::class,
             [],
             [],
@@ -156,19 +175,19 @@ class CategoryTest extends \PHPUnit_Framework_TestCase
             false
         );
         $this->urlFinder = $this->getMock(\Magento\UrlRewrite\Model\UrlFinderInterface::class);
-        $this->resource = $this->getMock(
+        $this->resource = $this->getMock(
             \Magento\Catalog\Model\ResourceModel\Category::class,
             [],
             [],
             '',
             false
         );
-        $this->indexerRegistry = $this->getMock(
-            \Magento\Framework\Indexer\IndexerRegistry::class,
-            ['get'],
-            [],
-            '',
-            false
+        $this->indexerRegistry = $this->getMock(
+            \Magento\Framework\Indexer\IndexerRegistry::class,
+            ['get'],
+            [],
+            '',
+            false
         );
 
         $this->metadataServiceMock = $this->getMock(\Magento\Catalog\Api\CategoryAttributeRepositoryInterface::class);
@@ -198,7 +217,7 @@ class CategoryTest extends \PHPUnit_Framework_TestCase
     public function testMoveWhenCannotFindParentCategory()
     {
         $this->markTestIncomplete('MAGETWO-31165');
-        $parentCategory = $this->getMock(
+        $parentCategory = $this->getMock(
             \Magento\Catalog\Model\Category::class,
             ['getId', 'setStoreId', 'load'],
             [],
@@ -223,7 +242,7 @@ class CategoryTest extends \PHPUnit_Framework_TestCase
      */
     public function testMoveWhenCannotFindNewCategory()
     {
-        $parentCategory = $this->getMock(
+        $parentCategory = $this->getMock(
             \Magento\Catalog\Model\Category::class,
             ['getId', 'setStoreId', 'load'],
             [],
@@ -250,7 +269,7 @@ class CategoryTest extends \PHPUnit_Framework_TestCase
     public function testMoveWhenParentCategoryIsSameAsChildCategory()
     {
         $this->markTestIncomplete('MAGETWO-31165');
-        $parentCategory = $this->getMock(
+        $parentCategory = $this->getMock(
             \Magento\Catalog\Model\Category::class,
             ['getId', 'setStoreId', 'load'],
             [],
@@ -277,7 +296,7 @@ class CategoryTest extends \PHPUnit_Framework_TestCase
             ->method('get')
             ->with('catalog_category_product')
             ->will($this->returnValue($indexer));
-        $parentCategory = $this->getMock(
+        $parentCategory = $this->getMock(
             \Magento\Catalog\Model\Category::class,
             ['getId', 'setStoreId', 'load'],
             [],
@@ -313,10 +332,9 @@ class CategoryTest extends \PHPUnit_Framework_TestCase
 
     protected function getCategoryModel()
     {
-        return (new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this))->getObject(
+        return $this->objectManager->getObject(
             \Magento\Catalog\Model\Category::class,
             [
-                'context' => $this->context,
                 'registry' => $this->registry,
                 'storeManager' => $this->storeManager,
                 'categoryTreeResource' => $this->categoryTreeResource,
@@ -487,4 +505,76 @@ class CategoryTest extends \PHPUnit_Framework_TestCase
             $this->category->getCustomAttribute($descriptionAttributeCode)->getValue()
         );
     }
+
+    /**
+     * @return array
+     */
+    public function getImageWithAttributeCodeDataProvider()
+    {
+        return [
+            ['testimage', 'http://www.example.com/catalog/category/testimage'],
+            [false, false]
+        ];
+    }
+
+    /**
+     * @param string|bool $value
+     * @param string|bool $url
+     *
+     * @dataProvider getImageWithAttributeCodeDataProvider
+     */
+    public function testGetImageWithAttributeCode($value, $url)
+    {
+        $storeManager = $this->getMock(\Magento\Store\Model\StoreManager::class, ['getStore'], [], '', false);
+        $store = $this->getMock(\Magento\Store\Model\Store::class, ['getBaseUrl'], [], '', false);
+
+        $storeManager->expects($this->any())
+            ->method('getStore')
+            ->will($this->returnValue($store));
+
+        $store->expects($this->any())
+            ->method('getBaseUrl')
+            ->with(\Magento\Framework\UrlInterface::URL_TYPE_MEDIA)
+            ->will($this->returnValue('http://www.example.com/'));
+
+        /** @var \Magento\Catalog\Model\Category $model */
+        $model = $this->objectManager->getObject(
+            \Magento\Catalog\Model\Category::class,
+            [
+                'storeManager' => $storeManager
+            ]
+        );
+
+        $model->setData('attribute1', $value);
+
+        $result = $model->getImageUrl('attribute1');
+
+        $this->assertEquals($url, $result);
+    }
+
+    public function testGetImageWithoutAttributeCode()
+    {
+        $storeManager = $this->getMock(\Magento\Store\Model\StoreManager::class, ['getStore'], [], '', false);
+        $store = $this->getMock(\Magento\Store\Model\Store::class, ['getBaseUrl'], [], '', false);
+
+        $storeManager->expects($this->any())
+            ->method('getStore')
+            ->will($this->returnValue($store));
+
+        $store->expects($this->any())
+            ->method('getBaseUrl')
+            ->with(\Magento\Framework\UrlInterface::URL_TYPE_MEDIA)
+            ->will($this->returnValue('http://www.example.com/'));
+
+        /** @var \Magento\Catalog\Model\Category $model */
+        $model = $this->objectManager->getObject(\Magento\Catalog\Model\Category::class, [
+            'storeManager' => $storeManager
+        ]);
+
+        $model->setData('image', 'myimage');
+
+        $result = $model->getImageUrl();
+
+        $this->assertEquals('http://www.example.com/catalog/category/myimage', $result);
+    }
 }
diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Product/Attribute/Backend/StockTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Product/Attribute/Backend/StockTest.php
index ec9cb624db79af510c2625ffee2680ede7653a19..32d62fd7a998e7bf820b7b0c26b6a7202350c26a 100644
--- a/app/code/Magento/Catalog/Test/Unit/Model/Product/Attribute/Backend/StockTest.php
+++ b/app/code/Magento/Catalog/Test/Unit/Model/Product/Attribute/Backend/StockTest.php
@@ -125,4 +125,17 @@ class StockTest extends \PHPUnit_Framework_TestCase
         $stockData = $object->getStockData();
         $this->assertEquals(0, $stockData['qty']);
     }
+
+    public function testBeforeSaveNoStockData()
+    {
+        $object = new \Magento\Framework\DataObject(
+            [
+                self::ATTRIBUTE_NAME => ['is_in_stock' => 1, 'qty' => 0]
+            ]
+        );
+
+        $this->model->beforeSave($object);
+        $this->assertNull($object->getStockData());
+        $this->assertNull($object->getData(self::ATTRIBUTE_NAME));
+    }
 }
diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Product/ImageTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Product/ImageTest.php
index a032ffa33b37561117fac3f6e603cb77dd34152d..44f7f87cc2c62afc2c09d262bbd2721683fcfea3 100644
--- a/app/code/Magento/Catalog/Test/Unit/Model/Product/ImageTest.php
+++ b/app/code/Magento/Catalog/Test/Unit/Model/Product/ImageTest.php
@@ -180,7 +180,7 @@ class ImageTest extends \PHPUnit_Framework_TestCase
         $this->image->setBaseFile('/somefile.png');
         $this->assertEquals('catalog/product/somefile.png', $this->image->getBaseFile());
         $this->assertEquals(
-            'catalog/product/cache/1//beff4985b56e3afdbeabfc89641a4582/somefile.png',
+            'catalog/product/cache//beff4985b56e3afdbeabfc89641a4582/somefile.png',
             $this->image->getNewFile()
         );
     }
@@ -302,7 +302,7 @@ class ImageTest extends \PHPUnit_Framework_TestCase
         $this->testSetGetBaseFile();
         $url = $this->image->getUrl();
         $this->assertEquals(
-            'http://magento.com/media/catalog/product/cache/1//beff4985b56e3afdbeabfc89641a4582/somefile.png',
+            'http://magento.com/media/catalog/product/cache//beff4985b56e3afdbeabfc89641a4582/somefile.png',
             $url
         );
     }
diff --git a/app/code/Magento/Catalog/Test/Unit/Model/ProductRepositoryTest.php b/app/code/Magento/Catalog/Test/Unit/Model/ProductRepositoryTest.php
index e91bb469eb112d4de70cba92bff5b93ca069ca58..8c08d0c63bc5e93c7ab690f6441eaa02281b3255 100644
--- a/app/code/Magento/Catalog/Test/Unit/Model/ProductRepositoryTest.php
+++ b/app/code/Magento/Catalog/Test/Unit/Model/ProductRepositoryTest.php
@@ -715,6 +715,7 @@ class ProductRepositoryTest extends \PHPUnit_Framework_TestCase
             ->method('process')
             ->with($searchCriteriaMock, $collectionMock);
         $collectionMock->expects($this->once())->method('load');
+        $collectionMock->expects($this->once())->method('addCategoryIds');
         $collectionMock->expects($this->once())->method('getItems')->willReturn([$itemsMock]);
         $collectionMock->expects($this->once())->method('getSize')->willReturn(128);
         $searchResultsMock = $this->getMock(
diff --git a/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/CollectionTest.php b/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/CollectionTest.php
index 332e775b019b238b9ba1aec83f0f42302aafa68a..b97b7d2f9842355af1195b7b0ce7ed1d4aa7e4e8 100644
--- a/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/CollectionTest.php
+++ b/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/CollectionTest.php
@@ -30,6 +30,26 @@ class CollectionTest extends \PHPUnit_Framework_TestCase
      */
     protected $collection;
 
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    private $galleryResourceMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    private $entityMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    private $metadataPoolMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    private $galleryReadHandlerMock;
+
     /**
      * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
      */
@@ -100,24 +120,49 @@ class CollectionTest extends \PHPUnit_Framework_TestCase
             ->disableOriginalConstructor()
             ->getMock();
 
-        $entityMock = $this->getMockBuilder(\Magento\Eav\Model\Entity\AbstractEntity::class)
+        $this->entityMock = $this->getMockBuilder(\Magento\Eav\Model\Entity\AbstractEntity::class)
             ->disableOriginalConstructor()
             ->getMock();
 
+        $this->galleryResourceMock = $this->getMockBuilder(
+            \Magento\Catalog\Model\ResourceModel\Product\Gallery::class
+        )->disableOriginalConstructor()->getMock();
+
+        $this->metadataPoolMock = $this->getMockBuilder(
+            \Magento\Framework\EntityManager\MetadataPool::class
+        )->disableOriginalConstructor()->getMock();
+
+        $this->galleryReadHandlerMock = $this->getMockBuilder(
+            \Magento\Catalog\Model\Product\Gallery\ReadHandler::class
+        )->disableOriginalConstructor()->getMock();
+
         $storeManager->expects($this->any())->method('getId')->willReturn(1);
         $storeManager->expects($this->any())->method('getStore')->willReturnSelf();
         $universalFactory->expects($this->exactly(1))->method('create')->willReturnOnConsecutiveCalls(
-            $entityMock
+            $this->entityMock
         );
-        $entityMock->expects($this->once())->method('getConnection')->willReturn($this->connectionMock);
-        $entityMock->expects($this->once())->method('getDefaultAttributes')->willReturn([]);
-        $entityMock->expects($this->any())->method('getTable')->willReturnArgument(0);
+        $this->entityMock->expects($this->once())->method('getConnection')->willReturn($this->connectionMock);
+        $this->entityMock->expects($this->once())->method('getDefaultAttributes')->willReturn([]);
+        $this->entityMock->expects($this->any())->method('getTable')->willReturnArgument(0);
         $this->connectionMock->expects($this->atLeastOnce())->method('select')->willReturn($this->selectMock);
         $helper = new ObjectManager($this);
 
         $this->prepareObjectManager([
-            [\Magento\Catalog\Model\ResourceModel\Product\Collection\ProductLimitation::class,
+            [
+                \Magento\Catalog\Model\ResourceModel\Product\Collection\ProductLimitation::class,
                 $this->getMock(\Magento\Catalog\Model\ResourceModel\Product\Collection\ProductLimitation::class)
+            ],
+            [
+                \Magento\Catalog\Model\ResourceModel\Product\Gallery::class,
+                $this->galleryResourceMock
+            ],
+            [
+                \Magento\Framework\EntityManager\MetadataPool::class,
+                $this->metadataPoolMock
+            ],
+            [
+                \Magento\Catalog\Model\Product\Gallery\ReadHandler::class,
+                $this->galleryReadHandlerMock
             ]
         ]);
         $this->collection = $helper->getObject(
@@ -150,8 +195,8 @@ class CollectionTest extends \PHPUnit_Framework_TestCase
 
     public function testAddProductCategoriesFilter()
     {
-        $condition = ['in' => [1,2]];
-        $values = [1,2];
+        $condition = ['in' => [1, 2]];
+        $values = [1, 2];
         $conditionType = 'nin';
         $preparedSql = "category_id IN(1,2)";
         $tableName = "catalog_category_product";
@@ -174,6 +219,47 @@ class CollectionTest extends \PHPUnit_Framework_TestCase
         $this->collection->addCategoriesFilter([$conditionType => $values]);
     }
 
+    public function testAddMediaGalleryData()
+    {
+        $attributeId = 42;
+        $itemId = 4242;
+        $linkField = 'entity_id';
+        $mediaGalleriesMock = [[$linkField => $itemId]];
+        $itemMock = $this->getMockBuilder(\Magento\Catalog\Model\Product::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $attributeMock = $this->getMockBuilder(\Magento\Eav\Model\Entity\Attribute\AbstractAttribute::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $selectMock = $this->getMockBuilder(\Magento\Framework\DB\Select::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $metadataMock = $this->getMockBuilder(\Magento\Framework\EntityManager\EntityMetadataInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->collection->addItem($itemMock);
+        $reflection = new \ReflectionClass(get_class($this->collection));
+        $reflectionProperty = $reflection->getProperty('_isCollectionLoaded');
+        $reflectionProperty->setAccessible(true);
+        $reflectionProperty->setValue($this->collection, true);
+
+        $this->galleryResourceMock->expects($this->once())->method('createBatchBaseSelect')->willReturn($selectMock);
+        $attributeMock->expects($this->once())->method('getAttributeId')->willReturn($attributeId);
+        $this->entityMock->expects($this->once())->method('getAttribute')->willReturn($attributeMock);
+        $itemMock->expects($this->atLeastOnce())->method('getId')->willReturn($itemId);
+        $selectMock->expects($this->once())->method('where')->with('entity.' . $linkField . ' IN (?)', [$itemId]);
+        $this->metadataPoolMock->expects($this->once())->method('getMetadata')->willReturn($metadataMock);
+        $metadataMock->expects($this->once())->method('getLinkField')->willReturn($linkField);
+
+        $this->connectionMock->expects($this->once())->method('fetchAll')->with($selectMock)->willReturn(
+            [['entity_id' => $itemId]]
+        );
+        $this->galleryReadHandlerMock->expects($this->once())->method('addMediaDataToProduct')
+            ->with($itemMock, $mediaGalleriesMock);
+
+        $this->assertSame($this->collection, $this->collection->addMediaGalleryData());
+    }
+
     /**
      * @param $map
      */
diff --git a/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/CompositeBaseSelectProcessorTest.php b/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/CompositeBaseSelectProcessorTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..d296474c202f091b4c1435453ec7941007e10885
--- /dev/null
+++ b/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/CompositeBaseSelectProcessorTest.php
@@ -0,0 +1,54 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Catalog\Test\Unit\Model\ResourceModel\Product;
+
+use Magento\Catalog\Model\ResourceModel\Product\BaseSelectProcessorInterface;
+use Magento\Catalog\Model\ResourceModel\Product\CompositeBaseSelectProcessor;
+use Magento\Framework\DB\Select;
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
+
+class CompositeBaseSelectProcessorTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var ObjectManager
+     */
+    private $objectManager;
+
+    protected function setUp()
+    {
+        $this->objectManager =  new ObjectManager($this);
+    }
+
+    /**
+     * @expectedException \Magento\Framework\Exception\InputException
+     */
+    public function testInitializeWithWrongProcessorInstance()
+    {
+        $processorValid = $this->getMock(BaseSelectProcessorInterface::class);
+        $processorInvalid = $this->getMock(\stdClass::class);
+
+        $this->objectManager->getObject(CompositeBaseSelectProcessor::class, [
+            'baseSelectProcessors' => [$processorValid, $processorInvalid],
+        ]);
+    }
+
+    public function testProcess()
+    {
+        $select = $this->getMockBuilder(Select::class)->disableOriginalConstructor()->getMock();
+
+        $processorFirst = $this->getMock(BaseSelectProcessorInterface::class);
+        $processorFirst->expects($this->once())->method('process')->with($select)->willReturn($select);
+
+        $processorSecond = $this->getMock(BaseSelectProcessorInterface::class);
+        $processorSecond->expects($this->once())->method('process')->with($select)->willReturn($select);
+
+        /** @var CompositeBaseSelectProcessor $baseSelectProcessors */
+        $baseSelectProcessors = $this->objectManager->getObject(CompositeBaseSelectProcessor::class, [
+            'baseSelectProcessors' => [$processorFirst, $processorSecond],
+        ]);
+        $this->assertEquals($select, $baseSelectProcessors->process($select));
+    }
+}
diff --git a/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/StatusBaseSelectProcessorTest.php b/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/StatusBaseSelectProcessorTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..0909f754a01c2c937e8c3692c52b1a256a27b0c3
--- /dev/null
+++ b/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/StatusBaseSelectProcessorTest.php
@@ -0,0 +1,102 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Catalog\Test\Unit\Model\ResourceModel\Product;
+
+use Magento\Catalog\Api\Data\ProductInterface;
+use Magento\Catalog\Model\Product;
+use Magento\Catalog\Model\Product\Attribute\Source\Status;
+use Magento\Catalog\Model\ResourceModel\Product\BaseSelectProcessorInterface;
+use Magento\Catalog\Model\ResourceModel\Product\StatusBaseSelectProcessor;
+use Magento\Eav\Model\Config;
+use Magento\Eav\Model\Entity\Attribute\AttributeInterface;
+use Magento\Framework\DB\Select;
+use Magento\Framework\EntityManager\EntityMetadataInterface;
+use Magento\Framework\EntityManager\MetadataPool;
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
+
+class StatusBaseSelectProcessorTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var Config|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $eavConfig;
+
+    /**
+     * @var MetadataPool|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $metadataPool;
+
+    /**
+     * @var Select|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $select;
+
+    /**
+     * @var StatusBaseSelectProcessor
+     */
+    private $statusBaseSelectProcessor;
+
+    protected function setUp()
+    {
+        $this->eavConfig = $this->getMockBuilder(Config::class)->disableOriginalConstructor()->getMock();
+        $this->metadataPool = $this->getMockBuilder(MetadataPool::class)->disableOriginalConstructor()->getMock();
+        $this->select = $this->getMockBuilder(Select::class)->disableOriginalConstructor()->getMock();
+
+        $this->statusBaseSelectProcessor =  (new ObjectManager($this))->getObject(StatusBaseSelectProcessor::class, [
+            'eavConfig' => $this->eavConfig,
+            'metadataPool' => $this->metadataPool,
+        ]);
+    }
+
+    public function testProcess()
+    {
+        $linkField = 'link_field';
+        $backendTable = 'backend_table';
+        $attributeId = 'attribute_id';
+
+        $metadata = $this->getMock(EntityMetadataInterface::class);
+        $metadata->expects($this->once())
+            ->method('getLinkField')
+            ->willReturn($linkField);
+        $this->metadataPool->expects($this->once())
+            ->method('getMetadata')
+            ->with(ProductInterface::class)
+            ->willReturn($metadata);
+
+        $statusAttribute = $this->getMockBuilder(AttributeInterface::class)
+            ->setMethods(['getBackendTable', 'getAttributeId'])
+            ->getMock();
+        $statusAttribute->expects($this->once())
+            ->method('getBackendTable')
+            ->willReturn($backendTable);
+        $statusAttribute->expects($this->once())
+            ->method('getAttributeId')
+            ->willReturn($attributeId);
+        $this->eavConfig->expects($this->once())
+            ->method('getAttribute')
+            ->with(Product::ENTITY, ProductInterface::STATUS)
+            ->willReturn($statusAttribute);
+
+        $this->select->expects($this->once())
+            ->method('join')
+            ->with(
+                ['status_attr' => $backendTable],
+                sprintf('status_attr.%s = %s.%1$s', $linkField, BaseSelectProcessorInterface::PRODUCT_TABLE_ALIAS),
+                []
+            )
+            ->willReturnSelf();
+        $this->select->expects($this->at(1))
+            ->method('where')
+            ->with('status_attr.attribute_id = ?', $attributeId)
+            ->willReturnSelf();
+        $this->select->expects($this->at(2))
+            ->method('where')
+            ->with('status_attr.value = ?', Status::STATUS_ENABLED)
+            ->willReturnSelf();
+
+        $this->assertEquals($this->select, $this->statusBaseSelectProcessor->process($this->select));
+    }
+}
diff --git a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Eav.php b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Eav.php
index 1419c17e11b298d1fcdc554a3131d7b8c9b8ffe8..e1680ab5a4081946b73b375a85c0b53cf916afd4 100755
--- a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Eav.php
+++ b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Eav.php
@@ -754,7 +754,10 @@ class Eav extends AbstractModifier
         $meta['arguments']['data']['config']['wysiwyg'] = true;
         $meta['arguments']['data']['config']['wysiwygConfigData'] = [
             'add_variables' => false,
-            'add_widgets' => false
+            'add_widgets' => false,
+            'add_directives' => true,
+            'use_container' => true,
+            'container_class' => 'hor-scroll',
         ];
 
         return $meta;
diff --git a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/General.php b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/General.php
index 0fbba264f7e93383f07434a7fe2ebf4586d54516..886c7a070adf93b68ec54f45813ba80911029e44 100755
--- a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/General.php
+++ b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/General.php
@@ -315,17 +315,6 @@ class General extends AbstractModifier
             $importsConfig = [
                 'mask' => $this->locator->getStore()->getConfig('catalog/fields_masks/' . $listener),
                 'component' => 'Magento_Catalog/js/components/import-handler',
-                'imports' => [
-                    'handleNameChanges' => '${$.provider}:data.product.name',
-                    'handleDescriptionChanges' => '${$.provider}:data.product.description',
-                    'handleSkuChanges' => '${$.provider}:data.product.sku',
-                    'handleColorChanges' => '${$.provider}:data.product.color',
-                    'handleCountryChanges' => '${$.provider}:data.product.country_of_manufacture',
-                    'handleGenderChanges' => '${$.provider}:data.product.gender',
-                    'handleMaterialChanges' => '${$.provider}:data.product.material',
-                    'handleShortDescriptionChanges' => '${$.provider}:data.product.short_description',
-                    'handleSizeChanges' => '${$.provider}:data.product.size'
-                ],
                 'allowImport' => !$this->locator->getProduct()->getId(),
             ];
 
diff --git a/app/code/Magento/Catalog/composer.json b/app/code/Magento/Catalog/composer.json
index 64157f6bc8af74e82975668e43a62ef583227908..8c77dd77f98b74a53ee1124a16c473d843d21d60 100644
--- a/app/code/Magento/Catalog/composer.json
+++ b/app/code/Magento/Catalog/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-catalog",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-store": "100.2.*",
         "magento/module-eav": "100.2.*",
         "magento/module-cms": "101.1.*",
diff --git a/app/code/Magento/Catalog/etc/di.xml b/app/code/Magento/Catalog/etc/di.xml
index d191f0332f5f28d28f22e981f8ebc74f0c0c8b98..6b39520ae021e9eb3bfafa20bda03e42c7db907a 100644
--- a/app/code/Magento/Catalog/etc/di.xml
+++ b/app/code/Magento/Catalog/etc/di.xml
@@ -837,4 +837,12 @@
     <type name="Magento\Quote\Model\Quote\Item\ToOrderItem">
         <plugin name="copy_quote_files_to_order" type="Magento\Catalog\Model\Plugin\QuoteItemProductOption"/>
     </type>
+    <preference for="Magento\Catalog\Model\ResourceModel\Product\BaseSelectProcessorInterface" type="Magento\Catalog\Model\ResourceModel\Product\CompositeBaseSelectProcessor" />
+    <type name="Magento\Catalog\Model\ResourceModel\Product\CompositeBaseSelectProcessor">
+        <arguments>
+            <argument name="baseSelectProcessors" xsi:type="array">
+                <item name="status" xsi:type="object">Magento\Catalog\Model\ResourceModel\Product\StatusBaseSelectProcessor</item>
+            </argument>
+        </arguments>
+    </type>
 </config>
diff --git a/app/code/Magento/Catalog/etc/module.xml b/app/code/Magento/Catalog/etc/module.xml
index 1250b55b968480bf9c1d9f9952da6d864048d98f..0c9e6bb356fe14101d467a04aa91b23fb6873f09 100644
--- a/app/code/Magento/Catalog/etc/module.xml
+++ b/app/code/Magento/Catalog/etc/module.xml
@@ -6,7 +6,7 @@
  */
 -->
 <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
-    <module name="Magento_Catalog" setup_version="2.1.0">
+    <module name="Magento_Catalog" setup_version="2.1.2">
         <sequence>
             <module name="Magento_Eav"/>
             <module name="Magento_Cms"/>
diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/components/import-handler.js b/app/code/Magento/Catalog/view/adminhtml/web/js/components/import-handler.js
index e67bde152475f62769d6eaff73548893f98ed7d0..a0aec918ccda24f1ae05486bc5d9ec59522f0ca7 100644
--- a/app/code/Magento/Catalog/view/adminhtml/web/js/components/import-handler.js
+++ b/app/code/Magento/Catalog/view/adminhtml/web/js/components/import-handler.js
@@ -4,148 +4,78 @@
  */
 
 define([
+    'Magento_Ui/js/form/element/abstract',
     'underscore',
-    'Magento_Ui/js/form/element/textarea'
-], function (_, Textarea) {
+    'uiRegistry'
+], function (Abstract, _, registry) {
     'use strict';
 
-    return Textarea.extend({
+    return Abstract.extend({
         defaults: {
             allowImport: true,
             autoImportIfEmpty: false,
-            values: {
-                'name': '',
-                'description': '',
-                'sku': '',
-                'color': '',
-                'country_of_manufacture': '',
-                'gender': '',
-                'material': '',
-                'short_description': '',
-                'size': ''
-            },
-            valueUpdate: 'input',
-            mask: ''
+            values: {},
+            mask: '',
+            queryTemplate: 'ns = ${ $.ns }, index = '
         },
 
-        /**
-         * Handle name value changes, if it's allowed
-         *
-         * @param {String} newValue
-         */
-        handleNameChanges: function (newValue) {
-            this.values.name = newValue;
-            this.updateValue();
-        },
-
-        /**
-         * Handle description value changes, if it's allowed
-         *
-         * @param {String} newValue
-         */
-        handleDescriptionChanges: function (newValue) {
-            this.values.description = newValue;
-            this.updateValue();
-        },
+        /** @inheritdoc */
+        initialize: function () {
+            this._super();
 
-        /**
-         * Handle sku value changes, if it's allowed
-         *
-         * @param {String} newValue
-         */
-        handleSkuChanges: function (newValue) {
-            if (this.code !== 'sku') {
-                this.values.sku = newValue;
-                this.updateValue();
+            if (this.allowImport) {
+                this.setHandlers();
             }
         },
 
         /**
-         * Handle color value changes, if it's allowed
-         *
-         * @param {String} newValue
-         */
-        handleColorChanges: function (newValue) {
-            this.values.color = newValue;
-            this.updateValue();
-        },
-
-        /**
-         * Handle country value changes, if it's allowed
-         *
-         * @param {String} newValue
+         * Split mask placeholder and attach events to placeholder fields.
          */
-        handleCountryChanges: function (newValue) {
-            this.values.country = newValue;
-            this.updateValue();
-        },
+        setHandlers: function () {
+            var str = this.mask || '',
+                placeholders;
 
-        /**
-         * Handle gender value changes, if it's allowed
-         *
-         * @param {String} newValue
-         */
-        handleGenderChanges: function (newValue) {
-            this.values.gender = newValue;
-            this.updateValue();
-        },
+            placeholders = str.match(/{{(.*?)}}/g); // Get placeholders
 
-        /**
-         * Handle material value changes, if it's allowed
-         *
-         * @param {String} newValue
-         */
-        handleMaterialChanges: function (newValue) {
-            this.values.material = newValue;
-            this.updateValue();
-        },
+            _.each(placeholders, function (placeholder) {
+                placeholder = placeholder.replace(/[{{}}]/g, ''); // Remove curly braces
 
-        /**
-         * Handle short description value changes, if it's allowed
-         *
-         * @param {String} newValue
-         */
-        handleShortDescriptionChanges: function (newValue) {
-            this.values['short_description'] = newValue;
-            this.updateValue();
+                registry.get(this.queryTemplate + placeholder, function (component) {
+                    this.values[placeholder] = component.getPreview();
+                    component.on('value', this.updateValue.bind(this, placeholder, component));
+                    component.valueUpdate = 'keyup';
+                }.bind(this));
+            }, this);
         },
 
         /**
-         * Handle size value changes, if it's allowed
+         * Update field with mask value, if it's allowed.
          *
-         * @param {String} newValue
+         * @param {Object} placeholder
+         * @param {Object} component
          */
-        handleSizeChanges: function (newValue) {
-            this.values.size = newValue;
-            this.updateValue();
-        },
+        updateValue: function (placeholder, component) {
+            var string = this.mask || '',
+                nonEmptyValueFlag = false;
 
-        /**
-         * Update field value, if it's allowed
-         */
-        updateValue: function () {
-            var str = this.mask || '',
-                nonEmptyValueFlag = false,
-                tmpElement;
+            if (placeholder) {
+                this.values[placeholder] = component.getPreview() || '';
+            }
 
             if (!this.allowImport) {
                 return;
             }
 
-            if (str) {
-                _.each(this.values, function (propertyValue, propertyName) {
-                    str = str.replace('{{' + propertyName + '}}', propertyValue);
-                    nonEmptyValueFlag = nonEmptyValueFlag || !!propertyValue;
-                });
-            }
-
-            // strip tags
-            tmpElement = document.createElement('div');
-            tmpElement.innerHTML = str;
-            str =  tmpElement.textContent || tmpElement.innerText || '';
+            _.each(this.values, function (propertyValue, propertyName) {
+                string = string.replace('{{' + propertyName + '}}', propertyValue);
+                nonEmptyValueFlag = nonEmptyValueFlag || !!propertyValue;
+            });
 
             if (nonEmptyValueFlag) {
-                this.value(str);
+                string = string.replace(/(<([^>]+)>)/ig, ''); // Remove html tags
+                this.value(string);
+            } else {
+                this.value('');
             }
         },
 
@@ -169,13 +99,20 @@ define([
          *  and disallow/allow import value
          */
         userChanges: function () {
+
+            /**
+             *  As userChanges is called before updateValue,
+             *  we forced to get value from component by reference
+             */
+            var actualValue = arguments[1].currentTarget.value;
+
             this._super();
 
-            if (this.value() === '') {
+            if (actualValue === '') {
                 this.allowImport = true;
 
                 if (this.autoImportIfEmpty) {
-                    this.updateValue();
+                    this.updateValue(null, null);
                 }
             } else {
                 this.allowImport = false;
diff --git a/app/code/Magento/Catalog/view/frontend/layout/catalog_category_view.xml b/app/code/Magento/Catalog/view/frontend/layout/catalog_category_view.xml
index 4c8ae8eaae9524fe75f74ba5f0dd45ef045c2954..298cdcc29e953a74625a3834edab6b9a5eb47631 100644
--- a/app/code/Magento/Catalog/view/frontend/layout/catalog_category_view.xml
+++ b/app/code/Magento/Catalog/view/frontend/layout/catalog_category_view.xml
@@ -28,53 +28,6 @@
                     </block>
                     <block class="Magento\Catalog\Block\Product\ProductList\Toolbar" name="product_list_toolbar" template="Magento_Catalog::product/list/toolbar.phtml">
                         <block class="Magento\Theme\Block\Html\Pager" name="product_list_toolbar_pager"/>
-                        <!-- The following code shows how to set your own pager increments -->
-                        <!--
-                            <action method="setDefaultListPerPage">
-                            <argument name="limit" xsi:type="string">4</argument>
-                        </action>
-                        <action method="setDefaultGridPerPage">
-                            <argument name="limit" xsi:type="string">3</argument>
-                        </action>
-                        <action method="addPagerLimit">
-                            <argument name="mode" xsi:type="string">list</argument>
-                            <argument name="limit" xsi:type="string">2</argument>
-                        </action>
-                        <action method="addPagerLimit">
-                            <argument name="mode" xsi:type="string">list</argument>
-                            <argument name="limit" xsi:type="string">4</argument>
-                        </action>
-                        <action method="addPagerLimit">
-                            <argument name="mode" xsi:type="string">list</argument>
-                            <argument name="limit" xsi:type="string">6</argument>
-                        </action>
-                        <action method="addPagerLimit">
-                            <argument name="mode" xsi:type="string">list</argument>
-                            <argument name="limit" xsi:type="string">8</argument>
-                        </action>
-                        <action method="addPagerLimit" translate="label">
-                            <argument name="mode" xsi:type="string">list</argument>
-                            <argument name="limit" xsi:type="string">all</argument>
-                            <argument name="label" xsi:type="string">All</argument>
-                        </action>
-                        <action method="addPagerLimit">
-                            <argument name="mode" xsi:type="string">grid</argument>
-                            <argument name="limit" xsi:type="string">3</argument>
-                        </action>
-                        <action method="addPagerLimit">
-                            <argument name="mode" xsi:type="string">grid</argument>
-                            <argument name="limit" xsi:type="string">6</argument>
-                        </action>
-                        <action method="addPagerLimit">
-                            <argument name="mode" xsi:type="string">grid</argument>
-                            <argument name="limit" xsi:type="string">9</argument>
-                        </action>
-                        <action method="addPagerLimit" translate="label">
-                            <argument name="mode" xsi:type="string">grid</argument>
-                            <argument name="limit" xsi:type="string">all</argument>
-                            <argument name="label" xsi:type="string">All</argument>
-                        </action>
-                        -->
                     </block>
                     <action method="setToolbarBlockName">
                         <argument name="name" xsi:type="string">product_list_toolbar</argument>
diff --git a/app/code/Magento/CatalogImportExport/Model/Export/Product.php b/app/code/Magento/CatalogImportExport/Model/Export/Product.php
index c9d155177e48a588a655d603234482ac53cbe545..fa704272962162d43edd1d129c1229275614015a 100644
--- a/app/code/Magento/CatalogImportExport/Model/Export/Product.php
+++ b/app/code/Magento/CatalogImportExport/Model/Export/Product.php
@@ -5,7 +5,6 @@
  */
 namespace Magento\CatalogImportExport\Model\Export;
 
-use Magento\Framework\DB\Ddl\Table;
 use Magento\ImportExport\Model\Import;
 use \Magento\Store\Model\Store;
 use \Magento\CatalogImportExport\Model\Import\Product as ImportProduct;
@@ -850,6 +849,24 @@ class Product extends \Magento\ImportExport\Model\Export\Entity\AbstractEntity
         return $writer->getContents();
     }
 
+    /**
+     * {@inheritdoc}
+     */
+    protected function _prepareEntityCollection(\Magento\Eav\Model\Entity\Collection\AbstractCollection $collection)
+    {
+        $exportFilter = !empty($this->_parameters[\Magento\ImportExport\Model\Export::FILTER_ELEMENT_GROUP]) ?
+            $this->_parameters[\Magento\ImportExport\Model\Export::FILTER_ELEMENT_GROUP] : [];
+
+        if (isset($exportFilter['category_ids'])
+            && trim($exportFilter['category_ids'])
+            && $collection instanceof \Magento\Catalog\Model\ResourceModel\Product\Collection
+        ) {
+            $collection->addCategoriesFilter(['in' => explode(',', $exportFilter['category_ids'])]);
+        }
+
+        return parent::_prepareEntityCollection($collection);
+    }
+
     /**
      * Get export data for collection
      *
diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product.php b/app/code/Magento/CatalogImportExport/Model/Import/Product.php
index afb2e86b6248a79523405c78acd1cf27953b90c2..54208dcdba534139c96e8fd975e0757f9ecb11e1 100644
--- a/app/code/Magento/CatalogImportExport/Model/Import/Product.php
+++ b/app/code/Magento/CatalogImportExport/Model/Import/Product.php
@@ -2304,7 +2304,7 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
 
         $sku = $rowData[self::COL_SKU];
 
-        if (isset($this->_oldSku[$sku])) {
+        if (isset($this->_oldSku[$sku]) && Import::BEHAVIOR_REPLACE !== $this->getBehavior()) {
             // can we get all necessary data from existent DB product?
             // check for supported type of existing product
             if (isset($this->_productTypeModels[$this->_oldSku[$sku]['type_id']])) {
@@ -2356,7 +2356,7 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
             $rowAttributesValid = $productTypeValidator->isRowValid(
                 $rowData,
                 $rowNum,
-                !isset($this->_oldSku[$sku])
+                !(isset($this->_oldSku[$sku]) && Import::BEHAVIOR_REPLACE !== $this->getBehavior())
             );
             if (!$rowAttributesValid && self::SCOPE_DEFAULT == $rowScope) {
                 // mark SCOPE_DEFAULT row as invalid for future child rows if product not in DB already
diff --git a/app/code/Magento/CatalogImportExport/composer.json b/app/code/Magento/CatalogImportExport/composer.json
index 7dbd7f4bc5e656ff09712549886e97a95fa3f4f1..8ed5f43692df51482038e1d1f7d4b91f05fd8c23 100644
--- a/app/code/Magento/CatalogImportExport/composer.json
+++ b/app/code/Magento/CatalogImportExport/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-catalog-import-export",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-catalog": "101.1.*",
         "magento/module-catalog-url-rewrite": "100.2.*",
         "magento/module-eav": "100.2.*",
diff --git a/app/code/Magento/CatalogInventory/Model/ResourceModel/Product/StockStatusBaseSelectProcessor.php b/app/code/Magento/CatalogInventory/Model/ResourceModel/Product/StockStatusBaseSelectProcessor.php
new file mode 100644
index 0000000000000000000000000000000000000000..829fa8decda7d74b554810ba17118faba2ca970c
--- /dev/null
+++ b/app/code/Magento/CatalogInventory/Model/ResourceModel/Product/StockStatusBaseSelectProcessor.php
@@ -0,0 +1,51 @@
+<?php
+/**
+ *
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\CatalogInventory\Model\ResourceModel\Product;
+
+use Magento\Catalog\Model\ResourceModel\Product\BaseSelectProcessorInterface;
+use Magento\CatalogInventory\Model\Stock;
+use Magento\Framework\App\ResourceConnection;
+use Magento\Framework\DB\Select;
+
+/**
+ * Class StockStatusBaseSelectProcessor
+ */
+class StockStatusBaseSelectProcessor implements BaseSelectProcessorInterface
+{
+    /**
+     * @var ResourceConnection
+     */
+    private $resource;
+
+    /**
+     * @param ResourceConnection $resource
+     */
+    public function __construct(ResourceConnection $resource)
+    {
+        $this->resource = $resource;
+    }
+
+    /**
+     * Add stock item filter to selects
+     *
+     * @param Select $select
+     * @return Select
+     */
+    public function process(Select $select)
+    {
+        $stockStatusTable = $this->resource->getTableName('cataloginventory_stock_status');
+
+        /** @var Select $select */
+        $select->join(
+            ['stock' => $stockStatusTable],
+            sprintf('stock.product_id = %s.entity_id', BaseSelectProcessorInterface::PRODUCT_TABLE_ALIAS),
+            []
+        )
+            ->where('stock.stock_status = ?', Stock::STOCK_IN_STOCK);
+        return $select;
+    }
+}
diff --git a/app/code/Magento/CatalogInventory/Test/Unit/Model/ResourceModel/Product/StockStatusBaseSelectProcessorTest.php b/app/code/Magento/CatalogInventory/Test/Unit/Model/ResourceModel/Product/StockStatusBaseSelectProcessorTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..4756e42ffe602bfc3b258656e0f2abe490a3acc1
--- /dev/null
+++ b/app/code/Magento/CatalogInventory/Test/Unit/Model/ResourceModel/Product/StockStatusBaseSelectProcessorTest.php
@@ -0,0 +1,69 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\CatalogInventory\Test\Unit\Model\ResourceModel\Product;
+
+use Magento\Catalog\Model\ResourceModel\Product\BaseSelectProcessorInterface;
+use Magento\CatalogInventory\Model\ResourceModel\Product\StockStatusBaseSelectProcessor;
+use Magento\CatalogInventory\Model\Stock;
+use Magento\Framework\App\ResourceConnection;
+use Magento\Framework\DB\Select;
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
+
+class StockStatusBaseSelectProcessorTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var ResourceConnection|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $resource;
+
+    /**
+     * @var Select|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $select;
+
+    /**
+     * @var StockStatusBaseSelectProcessor
+     */
+    private $stockStatusBaseSelectProcessor;
+
+    protected function setUp()
+    {
+        $this->resource = $this->getMockBuilder(ResourceConnection::class)->disableOriginalConstructor()->getMock();
+        $this->select = $this->getMockBuilder(Select::class)->disableOriginalConstructor()->getMock();
+
+        $this->stockStatusBaseSelectProcessor =  (new ObjectManager($this))->getObject(
+            StockStatusBaseSelectProcessor::class,
+            [
+                'resource' => $this->resource,
+            ]
+        );
+    }
+
+    public function testProcess()
+    {
+        $tableName = 'table_name';
+
+        $this->resource->expects($this->once())
+            ->method('getTableName')
+            ->with('cataloginventory_stock_status')
+            ->willReturn($tableName);
+
+        $this->select->expects($this->once())
+            ->method('join')
+            ->with(
+                ['stock' => $tableName],
+                sprintf('stock.product_id = %s.entity_id', BaseSelectProcessorInterface::PRODUCT_TABLE_ALIAS),
+                []
+            )
+            ->willReturnSelf();
+        $this->select->expects($this->once())
+            ->method('where')
+            ->with('stock.stock_status = ?', Stock::STOCK_IN_STOCK)
+            ->willReturnSelf();
+
+        $this->stockStatusBaseSelectProcessor->process($this->select);
+    }
+}
diff --git a/app/code/Magento/CatalogInventory/composer.json b/app/code/Magento/CatalogInventory/composer.json
index 254d8d2db4bf9db35b338507cdd744d1aaf0e152..684f616ecd6fcfca7088c257afec000fba6a4b1d 100644
--- a/app/code/Magento/CatalogInventory/composer.json
+++ b/app/code/Magento/CatalogInventory/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-catalog-inventory",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-config": "100.2.*",
         "magento/module-store": "100.2.*",
         "magento/module-catalog": "101.1.*",
diff --git a/app/code/Magento/CatalogInventory/etc/di.xml b/app/code/Magento/CatalogInventory/etc/di.xml
index 71b42ef89f73ce981f25393179fbbd05f59a4d08..e3ca5c01cedab6b5041a16248308208b3cccbcf5 100644
--- a/app/code/Magento/CatalogInventory/etc/di.xml
+++ b/app/code/Magento/CatalogInventory/etc/di.xml
@@ -79,4 +79,11 @@
             <argument name="indexerProcessor" xsi:type="object">Magento\CatalogInventory\Model\Indexer\Stock\Processor</argument>
         </arguments>
     </type>
+    <type name="Magento\Catalog\Model\ResourceModel\Product\CompositeBaseSelectProcessor">
+        <arguments>
+            <argument name="baseSelectProcessors" xsi:type="array">
+                <item name="stock_status" xsi:type="object">Magento\CatalogInventory\Model\ResourceModel\Product\StockStatusBaseSelectProcessor</item>
+            </argument>
+        </arguments>
+    </type>
 </config>
diff --git a/app/code/Magento/CatalogRule/Model/ResourceModel/Product/LinkedProductSelectBuilderByCatalogRulePrice.php b/app/code/Magento/CatalogRule/Model/ResourceModel/Product/LinkedProductSelectBuilderByCatalogRulePrice.php
index 7d8d44dcbb68ad2539f0556fb7aec8eebe0caa2e..55b76eb225028a1a3d96d115066a4abc4b78fd60 100644
--- a/app/code/Magento/CatalogRule/Model/ResourceModel/Product/LinkedProductSelectBuilderByCatalogRulePrice.php
+++ b/app/code/Magento/CatalogRule/Model/ResourceModel/Product/LinkedProductSelectBuilderByCatalogRulePrice.php
@@ -6,7 +6,8 @@
 namespace Magento\CatalogRule\Model\ResourceModel\Product;
 
 use Magento\Catalog\Api\Data\ProductInterface;
-use Magento\Catalog\Model\Product;
+use Magento\Catalog\Model\ResourceModel\Product\BaseSelectProcessorInterface;
+use Magento\Framework\App\ObjectManager;
 use Magento\Framework\DB\Select;
 use Magento\Catalog\Model\ResourceModel\Product\LinkedProductSelectBuilderInterface;
 
@@ -42,6 +43,11 @@ class LinkedProductSelectBuilderByCatalogRulePrice implements LinkedProductSelec
      */
     private $metadataPool;
 
+    /**
+     * @var BaseSelectProcessorInterface
+     */
+    private $baseSelectProcessor;
+
     /**
      * @param \Magento\Store\Model\StoreManagerInterface $storeManager
      * @param \Magento\Framework\App\ResourceConnection $resourceConnection
@@ -49,6 +55,7 @@ class LinkedProductSelectBuilderByCatalogRulePrice implements LinkedProductSelec
      * @param \Magento\Framework\Stdlib\DateTime $dateTime
      * @param \Magento\Framework\Stdlib\DateTime\TimezoneInterface $localeDate
      * @param \Magento\Framework\EntityManager\MetadataPool $metadataPool
+     * @param BaseSelectProcessorInterface $baseSelectProcessor
      */
     public function __construct(
         \Magento\Store\Model\StoreManagerInterface $storeManager,
@@ -56,7 +63,8 @@ class LinkedProductSelectBuilderByCatalogRulePrice implements LinkedProductSelec
         \Magento\Customer\Model\Session $customerSession,
         \Magento\Framework\Stdlib\DateTime $dateTime,
         \Magento\Framework\Stdlib\DateTime\TimezoneInterface $localeDate,
-        \Magento\Framework\EntityManager\MetadataPool $metadataPool
+        \Magento\Framework\EntityManager\MetadataPool $metadataPool,
+        BaseSelectProcessorInterface $baseSelectProcessor = null
     ) {
         $this->storeManager = $storeManager;
         $this->resource = $resourceConnection;
@@ -64,6 +72,8 @@ class LinkedProductSelectBuilderByCatalogRulePrice implements LinkedProductSelec
         $this->dateTime = $dateTime;
         $this->localeDate = $localeDate;
         $this->metadataPool = $metadataPool;
+        $this->baseSelectProcessor = (null !== $baseSelectProcessor)
+            ? $baseSelectProcessor : ObjectManager::getInstance()->get(BaseSelectProcessorInterface::class);
     }
 
     /**
@@ -76,25 +86,28 @@ class LinkedProductSelectBuilderByCatalogRulePrice implements LinkedProductSelec
         $linkField = $this->metadataPool->getMetadata(ProductInterface::class)->getLinkField();
         $productTable = $this->resource->getTableName('catalog_product_entity');
 
-        return [$this->resource->getConnection()->select()
-                ->from(['parent' => $productTable], '')
-                ->joinInner(
-                    ['link' => $this->resource->getTableName('catalog_product_relation')],
-                    "link.parent_id = parent.$linkField",
-                    []
-                )->joinInner(
-                    ['child' => $productTable],
-                    "child.entity_id = link.child_id",
-                    ['entity_id']
-                )->joinInner(
-                    ['t' => $this->resource->getTableName('catalogrule_product_price')],
-                    't.product_id = child.entity_id',
-                    []
-                )->where('parent.entity_id = ? ', $productId)
+        $priceSelect = $this->resource->getConnection()->select()
+            ->from(['parent' => $productTable], '')
+            ->joinInner(
+                ['link' => $this->resource->getTableName('catalog_product_relation')],
+                "link.parent_id = parent.$linkField",
+                []
+            )->joinInner(
+                [BaseSelectProcessorInterface::PRODUCT_TABLE_ALIAS => $productTable],
+                sprintf('%s.entity_id = link.child_id', BaseSelectProcessorInterface::PRODUCT_TABLE_ALIAS),
+                ['entity_id']
+            )->joinInner(
+                ['t' => $this->resource->getTableName('catalogrule_product_price')],
+                sprintf('t.product_id = %s.%s', BaseSelectProcessorInterface::PRODUCT_TABLE_ALIAS, $linkField),
+                []
+            )->where('parent.entity_id = ?', $productId)
             ->where('t.website_id = ?', $this->storeManager->getStore()->getWebsiteId())
             ->where('t.customer_group_id = ?', $this->customerSession->getCustomerGroupId())
             ->where('t.rule_date = ?', $currentDate)
             ->order('t.rule_price ' . Select::SQL_ASC)
-            ->limit(1)];
+            ->limit(1);
+        $priceSelect = $this->baseSelectProcessor->process($priceSelect);
+
+        return [$priceSelect];
     }
 }
diff --git a/app/code/Magento/CatalogRule/Setup/InstallSchema.php b/app/code/Magento/CatalogRule/Setup/InstallSchema.php
index 70c5724d446de5e3cd151e69b9ffc5534fec1cbe..cb36f6efbdcde67cff29f360d2aef0d65a954e6a 100644
--- a/app/code/Magento/CatalogRule/Setup/InstallSchema.php
+++ b/app/code/Magento/CatalogRule/Setup/InstallSchema.php
@@ -25,6 +25,9 @@ class InstallSchema implements InstallSchemaInterface
 
         $installer->startSetup();
 
+        $customerGroupTable = $setup->getConnection()->describeTable($setup->getTable('customer_group'));
+        $customerGroupIdType = $customerGroupTable['customer_group_id']['DATA_TYPE'] == 'int'
+            ? \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER : $customerGroupTable['customer_group_id']['DATA_TYPE'];
         /**
          * Create table 'catalogrule'
          */
@@ -372,7 +375,7 @@ class InstallSchema implements InstallSchemaInterface
             )
             ->addColumn(
                 'customer_group_id',
-                \Magento\Framework\DB\Ddl\Table::TYPE_SMALLINT,
+                $customerGroupIdType,
                 null,
                 ['unsigned' => true, 'nullable' => false, 'primary' => true, 'default' => '0'],
                 'Customer Group Id'
@@ -477,7 +480,7 @@ class InstallSchema implements InstallSchemaInterface
             )
             ->addColumn(
                 'customer_group_id',
-                \Magento\Framework\DB\Ddl\Table::TYPE_SMALLINT,
+                $customerGroupIdType,
                 null,
                 ['unsigned' => true, 'nullable' => false, 'primary' => true],
                 'Customer Group Id'
diff --git a/app/code/Magento/CatalogRule/Setup/UpgradeSchema.php b/app/code/Magento/CatalogRule/Setup/UpgradeSchema.php
index 1d576e74c4c80caabcac9a53f7d3701ba5d66ded..6bfb927c9c8f5ce33d53e68853554d131e5f188f 100644
--- a/app/code/Magento/CatalogRule/Setup/UpgradeSchema.php
+++ b/app/code/Magento/CatalogRule/Setup/UpgradeSchema.php
@@ -26,6 +26,20 @@ class UpgradeSchema implements UpgradeSchemaInterface
             $this->removeSubProductDiscounts($setup);
         }
 
+        if (version_compare($context->getVersion(), '2.0.2', '<')) {
+            $tables = [
+                'catalogrule_product',
+                'catalogrule_product_price',
+            ];
+            foreach ($tables as $table) {
+                $setup->getConnection()->modifyColumn(
+                    $setup->getTable($table),
+                    'customer_group_id',
+                    ['type' => 'integer']
+                );
+            }
+        }
+
         $setup->endSetup();
     }
 
diff --git a/app/code/Magento/CatalogRule/composer.json b/app/code/Magento/CatalogRule/composer.json
index 71eb5b49db1fc68eadb064968796cfdaf1081d60..004ab82a028d3aba288b71a234dead24d63a4755 100644
--- a/app/code/Magento/CatalogRule/composer.json
+++ b/app/code/Magento/CatalogRule/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-catalog-rule",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-store": "100.2.*",
         "magento/module-rule": "100.2.*",
         "magento/module-catalog": "101.1.*",
diff --git a/app/code/Magento/CatalogRule/etc/module.xml b/app/code/Magento/CatalogRule/etc/module.xml
index ea6a730279ed54ba2caf76f1cab17d8fc21f9585..d7db233e1eb06ee815e1c7e71a325b0c0d0f8f92 100644
--- a/app/code/Magento/CatalogRule/etc/module.xml
+++ b/app/code/Magento/CatalogRule/etc/module.xml
@@ -6,7 +6,7 @@
  */
 -->
 <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
-    <module name="Magento_CatalogRule" setup_version="2.0.1">
+    <module name="Magento_CatalogRule" setup_version="2.0.2">
         <sequence>
             <module name="Magento_Rule"/>
             <module name="Magento_Catalog"/>
diff --git a/app/code/Magento/CatalogRuleConfigurable/composer.json b/app/code/Magento/CatalogRuleConfigurable/composer.json
index cc51269e2d9720e380612cf56c712ff2459bbe35..b930380f7bb025ea409be398c013c12773cb2f20 100644
--- a/app/code/Magento/CatalogRuleConfigurable/composer.json
+++ b/app/code/Magento/CatalogRuleConfigurable/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-catalog-rule-configurable",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-configurable-product": "100.2.*",
         "magento/framework": "100.2.*",
         "magento/module-catalog": "101.1.*",
diff --git a/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Aggregation/DataProvider.php b/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Aggregation/DataProvider.php
index 9b75e6e6e0c325819d09f543cc445ae61eb7fb84..ddf86951068acc3c95017e54e489faf92e4b28cc 100644
--- a/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Aggregation/DataProvider.php
+++ b/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Aggregation/DataProvider.php
@@ -6,6 +6,7 @@
 namespace Magento\CatalogSearch\Model\Adapter\Mysql\Aggregation;
 
 use Magento\Catalog\Model\Product;
+use Magento\CatalogInventory\Model\Stock;
 use Magento\Customer\Model\Session;
 use Magento\Eav\Model\Config;
 use Magento\Framework\App\ResourceConnection;
@@ -79,7 +80,13 @@ class DataProvider implements DataProviderInterface
 
         $select = $this->getSelect();
 
-        if ($attribute->getAttributeCode() == 'price') {
+        $select->joinInner(
+            ['entities' => $entityIdsTable->getName()],
+            'main_table.entity_id  = entities.entity_id',
+            []
+        );
+
+        if ($attribute->getAttributeCode() === 'price') {
             /** @var \Magento\Store\Model\Store $store */
             $store = $this->scopeResolver->getScope($currentScope);
             if (!$store instanceof \Magento\Store\Model\Store) {
@@ -94,19 +101,24 @@ class DataProvider implements DataProviderInterface
             $currentScopeId = $this->scopeResolver->getScope($currentScope)
                 ->getId();
             $table = $this->resource->getTableName(
-                'catalog_product_index_eav' . ($attribute->getBackendType() == 'decimal' ? '_decimal' : '')
+                'catalog_product_index_eav' . ($attribute->getBackendType() === 'decimal' ? '_decimal' : '')
             );
-            $select->from(['main_table' => $table], ['value'])
+            $subSelect = $select;
+            $subSelect->from(['main_table' => $table], ['main_table.value'])
+                ->joinLeft(
+                    ['stock_index' => $this->resource->getTableName('cataloginventory_stock_status')],
+                    'main_table.source_id = stock_index.product_id',
+                    []
+                )
                 ->where('main_table.attribute_id = ?', $attribute->getAttributeId())
-                ->where('main_table.store_id = ? ', $currentScopeId);
+                ->where('main_table.store_id = ? ', $currentScopeId)
+                ->where('stock_index.stock_status = ?', Stock::STOCK_IN_STOCK)
+                ->group(['main_table.entity_id', 'main_table.value']);
+            $parentSelect = $this->getSelect();
+            $parentSelect->from(['main_table' => $subSelect], ['main_table.value']);
+            $select = $parentSelect;
         }
 
-        $select->joinInner(
-            ['entities' => $entityIdsTable->getName()],
-            'main_table.entity_id  = entities.entity_id',
-            []
-        );
-
         return $select;
     }
 
diff --git a/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Filter/AliasResolver.php b/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Filter/AliasResolver.php
new file mode 100644
index 0000000000000000000000000000000000000000..7099ce2502b19e21de48ae570e2dc063be6162d1
--- /dev/null
+++ b/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Filter/AliasResolver.php
@@ -0,0 +1,44 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\CatalogSearch\Model\Adapter\Mysql\Filter;
+
+
+use Magento\CatalogSearch\Model\Search\RequestGenerator;
+
+/**
+ * Purpose of class is to resolve table alias for Search Request filter
+ */
+class AliasResolver
+{
+    /**
+     * The suffix for stock status filter that may be added to the query beside the filter query
+     * Used when showing of Out of Stock products is disabled.
+     */
+    const STOCK_FILTER_SUFFIX = '_stock';
+
+    /**
+     * @param \Magento\Framework\Search\Request\FilterInterface $filter
+     * @return string alias of the filter in database
+     */
+    public function getAlias(\Magento\Framework\Search\Request\FilterInterface $filter)
+    {
+        $alias = null;
+        $field = $filter->getField();
+        switch ($field) {
+            case 'price':
+                $alias = 'price_index';
+                break;
+            case 'category_ids':
+                $alias = 'category_ids_index';
+                break;
+            default:
+                $alias = $field . RequestGenerator::FILTER_SUFFIX;
+                break;
+        }
+        return $alias;
+    }
+}
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 05205f04f8b99cd903f345f8c1f7dc04384e7aee..fb579c1dce29c7da26b35288ff61040363f4f510 100644
--- a/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Filter/Preprocessor.php
+++ b/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Filter/Preprocessor.php
@@ -8,8 +8,11 @@ namespace Magento\CatalogSearch\Model\Adapter\Mysql\Filter;
 use Magento\Catalog\Api\Data\ProductInterface;
 use Magento\Catalog\Model\Product;
 use Magento\Catalog\Model\ResourceModel\Eav\Attribute;
+use Magento\CatalogInventory\Model\Stock;
 use Magento\CatalogSearch\Model\Search\TableMapper;
 use Magento\Eav\Model\Config;
+use Magento\Framework\App\Config\ScopeConfigInterface;
+use Magento\Framework\App\ObjectManager;
 use Magento\Framework\App\ResourceConnection;
 use Magento\Framework\App\ScopeResolverInterface;
 use Magento\Framework\DB\Adapter\AdapterInterface;
@@ -17,6 +20,7 @@ use Magento\Framework\EntityManager\MetadataPool;
 use Magento\Framework\Search\Adapter\Mysql\ConditionManager;
 use Magento\Framework\Search\Adapter\Mysql\Filter\PreprocessorInterface;
 use Magento\Framework\Search\Request\FilterInterface;
+use Magento\Store\Model\ScopeInterface;
 use Magento\Store\Model\Store;
 
 /**
@@ -60,9 +64,14 @@ class Preprocessor implements PreprocessorInterface
     private $metadataPool;
 
     /**
-     * @var TableMapper
+     * @var ScopeConfigInterface
      */
-    private $tableMapper;
+    private $scopeConfig;
+
+    /**
+     * @var AliasResolver
+     */
+    private $aliasResolver;
 
     /**
      * @param ConditionManager $conditionManager
@@ -71,6 +80,9 @@ class Preprocessor implements PreprocessorInterface
      * @param ResourceConnection $resource
      * @param TableMapper $tableMapper
      * @param string $attributePrefix
+     * @param ScopeConfigInterface $scopeConfig
+     * @param AliasResolver $aliasResolver
+     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
      */
     public function __construct(
         ConditionManager $conditionManager,
@@ -78,7 +90,9 @@ class Preprocessor implements PreprocessorInterface
         Config $config,
         ResourceConnection $resource,
         TableMapper $tableMapper,
-        $attributePrefix
+        $attributePrefix,
+        ScopeConfigInterface $scopeConfig = null,
+        AliasResolver $aliasResolver = null
     ) {
         $this->conditionManager = $conditionManager;
         $this->scopeResolver = $scopeResolver;
@@ -86,7 +100,16 @@ class Preprocessor implements PreprocessorInterface
         $this->resource = $resource;
         $this->connection = $resource->getConnection();
         $this->attributePrefix = $attributePrefix;
-        $this->tableMapper = $tableMapper;
+
+        if (null === $scopeConfig) {
+            $scopeConfig = ObjectManager::getInstance()->get(ScopeConfigInterface::class);
+        }
+        if (null === $aliasResolver) {
+            $aliasResolver = ObjectManager::getInstance()->get(AliasResolver::class);
+        }
+
+        $this->scopeConfig = $scopeConfig;
+        $this->aliasResolver = $aliasResolver;
     }
 
     /**
@@ -117,7 +140,7 @@ class Preprocessor implements PreprocessorInterface
         } elseif ($filter->getField() === 'category_ids') {
             return 'category_ids_index.category_id = ' . (int) $filter->getValue();
         } elseif ($attribute->isStatic()) {
-            $alias = $this->tableMapper->getMappingAlias($filter);
+            $alias = $this->aliasResolver->getAlias($filter);
             $resultQuery = str_replace(
                 $this->connection->quoteIdentifier($attribute->getAttributeCode()),
                 $this->connection->quoteIdentifier($alias . '.' . $attribute->getAttributeCode()),
@@ -208,7 +231,7 @@ class Preprocessor implements PreprocessorInterface
      */
     private function processTermSelect(FilterInterface $filter, $isNegation)
     {
-        $alias = $this->tableMapper->getMappingAlias($filter);
+        $alias = $this->aliasResolver->getAlias($filter);
         if (is_array($filter->getValue())) {
             $value = sprintf(
                 '%s IN (%s)',
@@ -224,9 +247,31 @@ class Preprocessor implements PreprocessorInterface
             $value
         );
 
+        if ($this->isAddStockFilter()) {
+            $resultQuery = sprintf(
+                '%1$s AND %2$s%3$s.stock_status = %4$s',
+                $resultQuery,
+                $alias,
+                AliasResolver::STOCK_FILTER_SUFFIX,
+                Stock::STOCK_IN_STOCK
+            );
+        }
+
         return $resultQuery;
     }
 
+    /**
+     * @return bool
+     */
+    private function isAddStockFilter()
+    {
+        $isShowOutOfStock = $this->scopeConfig->isSetFlag(
+            'cataloginventory/options/show_out_of_stock',
+            ScopeInterface::SCOPE_STORE
+        );
+        return false === $isShowOutOfStock;
+    }
+
     /**
      * Get product metadata pool
      *
diff --git a/app/code/Magento/CatalogSearch/Model/Search/FilterMapper/ExclusionStrategy.php b/app/code/Magento/CatalogSearch/Model/Search/FilterMapper/ExclusionStrategy.php
new file mode 100644
index 0000000000000000000000000000000000000000..8626b2ea15b077fc42380afaba82b245e7387937
--- /dev/null
+++ b/app/code/Magento/CatalogSearch/Model/Search/FilterMapper/ExclusionStrategy.php
@@ -0,0 +1,83 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\CatalogSearch\Model\Search\FilterMapper;
+
+use Magento\CatalogSearch\Model\Adapter\Mysql\Filter\AliasResolver;
+
+/**
+ * Strategy which processes exclusions from general rules
+ */
+class ExclusionStrategy implements FilterStrategyInterface
+{
+    /**
+     * @var \Magento\Framework\App\ResourceConnection
+     */
+    private $resourceConnection;
+
+    /**
+     * @var AliasResolver
+     */
+    private $aliasResolver;
+
+    /**
+     * @var \Magento\Store\Model\StoreManagerInterface
+     */
+    private $storeManager;
+
+    /**
+     * @param \Magento\Framework\App\ResourceConnection $resourceConnection
+     * @param \Magento\Store\Model\StoreManagerInterface $storeManager
+     * @param AliasResolver $aliasResolver
+     */
+    public function __construct(
+        \Magento\Framework\App\ResourceConnection $resourceConnection,
+        \Magento\Store\Model\StoreManagerInterface $storeManager,
+        AliasResolver $aliasResolver
+    ) {
+        $this->resourceConnection = $resourceConnection;
+        $this->storeManager = $storeManager;
+        $this->aliasResolver = $aliasResolver;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function apply(
+        \Magento\Framework\Search\Request\FilterInterface $filter,
+        \Magento\Framework\DB\Select $select
+    ) {
+        $isApplied = false;
+        $field = $filter->getField();
+        if ('price' === $field) {
+            $alias = $this->aliasResolver->getAlias($filter);
+            $tableName = $this->resourceConnection->getTableName('catalog_product_index_price');
+            $select->joinInner(
+                [
+                    $alias => $tableName
+                ],
+                $this->resourceConnection->getConnection()->quoteInto(
+                    'search_index.entity_id = price_index.entity_id AND price_index.website_id = ?',
+                    $this->storeManager->getWebsite()->getId()
+                ),
+                []
+            );
+            $isApplied = true;
+        } elseif ('category_ids' === $field) {
+            $alias = $this->aliasResolver->getAlias($filter);
+            $tableName = $this->resourceConnection->getTableName('catalog_category_product_index');
+            $select->joinInner(
+                [
+                    $alias => $tableName
+                ],
+                'search_index.entity_id = category_ids_index.product_id',
+                []
+            );
+            $isApplied = true;
+        }
+        return $isApplied;
+    }
+}
diff --git a/app/code/Magento/CatalogSearch/Model/Search/FilterMapper/FilterContext.php b/app/code/Magento/CatalogSearch/Model/Search/FilterMapper/FilterContext.php
new file mode 100644
index 0000000000000000000000000000000000000000..d244e3d5f754893fb671a3b6c81565eb5c920ff7
--- /dev/null
+++ b/app/code/Magento/CatalogSearch/Model/Search/FilterMapper/FilterContext.php
@@ -0,0 +1,100 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\CatalogSearch\Model\Search\FilterMapper;
+
+
+use Magento\CatalogSearch\Model\Adapter\Mysql\Filter\AliasResolver;
+use Magento\Eav\Model\Config as EavConfig;
+use Magento\Eav\Model\Entity\Attribute\AbstractAttribute;
+
+/**
+ * FilterContext represents a Context of the Strategy pattern
+ * Its responsibility is to choose appropriate strategy to apply passed filter to the Select
+ */
+class FilterContext implements FilterStrategyInterface
+{
+    /**
+     * @var ExclusionStrategy
+     */
+    private $exclusionStrategy;
+
+    /**
+     * @var EavConfig
+     */
+    private $eavConfig;
+
+    /**
+     * @var TermDropdownStrategy
+     */
+    private $termDropdownStrategy;
+
+    /**
+     * @var StaticAttributeStrategy
+     */
+    private $staticAttributeStrategy;
+
+    /**
+     * @var AliasResolver
+     */
+    private $aliasResolver;
+
+    /**
+     * @param EavConfig $eavConfig
+     * @param AliasResolver $aliasResolver
+     * @param ExclusionStrategy $exclusionStrategy
+     * @param TermDropdownStrategy $termDropdownStrategy
+     * @param StaticAttributeStrategy $staticAttributeStrategy
+     */
+    public function __construct(
+        EavConfig $eavConfig,
+        AliasResolver $aliasResolver,
+        ExclusionStrategy $exclusionStrategy,
+        TermDropdownStrategy $termDropdownStrategy,
+        StaticAttributeStrategy $staticAttributeStrategy
+    ) {
+        $this->eavConfig = $eavConfig;
+        $this->aliasResolver = $aliasResolver;
+        $this->exclusionStrategy = $exclusionStrategy;
+        $this->termDropdownStrategy = $termDropdownStrategy;
+        $this->staticAttributeStrategy = $staticAttributeStrategy;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function apply(
+        \Magento\Framework\Search\Request\FilterInterface $filter,
+        \Magento\Framework\DB\Select $select
+    ) {
+        $isApplied = $this->exclusionStrategy->apply($filter, $select);
+
+        if (!$isApplied) {
+            $attribute = $this->getAttributeByCode($filter->getField());
+            if ($attribute) {
+                if ($filter->getType() === \Magento\Framework\Search\Request\FilterInterface::TYPE_TERM
+                    && in_array($attribute->getFrontendInput(), ['select', 'multiselect'], true)
+                ) {
+                    $isApplied = $this->termDropdownStrategy->apply($filter, $select);
+                } elseif ($attribute->getBackendType() === AbstractAttribute::TYPE_STATIC) {
+                    $isApplied = $this->staticAttributeStrategy->apply($filter, $select);
+                }
+            }
+        }
+
+        return $isApplied;
+    }
+
+    /**
+     * @param string $field
+     * @return \Magento\Catalog\Model\ResourceModel\Eav\Attribute
+     * @throws \Magento\Framework\Exception\LocalizedException
+     */
+    private function getAttributeByCode($field)
+    {
+        return $this->eavConfig->getAttribute(\Magento\Catalog\Model\Product::ENTITY, $field);
+    }
+}
diff --git a/app/code/Magento/CatalogSearch/Model/Search/FilterMapper/FilterStrategyInterface.php b/app/code/Magento/CatalogSearch/Model/Search/FilterMapper/FilterStrategyInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..cf17f7d5132efbf8246af0de674d7c789551aa3e
--- /dev/null
+++ b/app/code/Magento/CatalogSearch/Model/Search/FilterMapper/FilterStrategyInterface.php
@@ -0,0 +1,23 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\CatalogSearch\Model\Search\FilterMapper;
+
+/**
+ * FilterStrategyInterface provides the interface to work with strategies
+ */
+interface FilterStrategyInterface
+{
+    /**
+     * @param \Magento\Framework\Search\Request\FilterInterface $filter
+     * @param \Magento\Framework\DB\Select $select
+     * @return bool is filter was applied
+     */
+    public function apply(
+        \Magento\Framework\Search\Request\FilterInterface $filter,
+        \Magento\Framework\DB\Select $select
+    );
+}
diff --git a/app/code/Magento/CatalogSearch/Model/Search/FilterMapper/StaticAttributeStrategy.php b/app/code/Magento/CatalogSearch/Model/Search/FilterMapper/StaticAttributeStrategy.php
new file mode 100644
index 0000000000000000000000000000000000000000..eb9d61b5a7f4c352d23096050a5acd292dc80d54
--- /dev/null
+++ b/app/code/Magento/CatalogSearch/Model/Search/FilterMapper/StaticAttributeStrategy.php
@@ -0,0 +1,74 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\CatalogSearch\Model\Search\FilterMapper;
+
+use Magento\CatalogSearch\Model\Adapter\Mysql\Filter\AliasResolver;
+use Magento\Eav\Model\Config as EavConfig;
+
+/**
+ * This strategy handles static attributes
+ */
+class StaticAttributeStrategy implements FilterStrategyInterface
+{
+    /**
+     * @var \Magento\Framework\App\ResourceConnection
+     */
+    private $resourceConnection;
+
+    /**
+     * @var AliasResolver
+     */
+    private $aliasResolver;
+
+    /**
+     * @var EavConfig
+     */
+    private $eavConfig;
+
+    /**
+     * @param \Magento\Framework\App\ResourceConnection $resourceConnection
+     * @param EavConfig $eavConfig
+     * @param AliasResolver $aliasResolver
+     */
+    public function __construct(
+        \Magento\Framework\App\ResourceConnection $resourceConnection,
+        EavConfig $eavConfig,
+        AliasResolver $aliasResolver
+    ) {
+        $this->resourceConnection = $resourceConnection;
+        $this->eavConfig = $eavConfig;
+        $this->aliasResolver = $aliasResolver;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function apply(
+        \Magento\Framework\Search\Request\FilterInterface $filter,
+        \Magento\Framework\DB\Select $select
+    ) {
+        $attribute = $this->getAttributeByCode($filter->getField());
+        $alias = $this->aliasResolver->getAlias($filter);
+        $select->joinInner(
+            [$alias => $attribute->getBackendTable()],
+            'search_index.entity_id = '
+            . $this->resourceConnection->getConnection()->quoteIdentifier("$alias.entity_id"),
+            []
+        );
+        return true;
+    }
+
+    /**
+     * @param string $field
+     * @return \Magento\Catalog\Model\ResourceModel\Eav\Attribute
+     * @throws \Magento\Framework\Exception\LocalizedException
+     */
+    private function getAttributeByCode($field)
+    {
+        return $this->eavConfig->getAttribute(\Magento\Catalog\Model\Product::ENTITY, $field);
+    }
+}
diff --git a/app/code/Magento/CatalogSearch/Model/Search/FilterMapper/TermDropdownStrategy.php b/app/code/Magento/CatalogSearch/Model/Search/FilterMapper/TermDropdownStrategy.php
new file mode 100644
index 0000000000000000000000000000000000000000..76828fe28f4348c8b90c9f1bf695906242c77222
--- /dev/null
+++ b/app/code/Magento/CatalogSearch/Model/Search/FilterMapper/TermDropdownStrategy.php
@@ -0,0 +1,127 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\CatalogSearch\Model\Search\FilterMapper;
+
+use Magento\CatalogSearch\Model\Adapter\Mysql\Filter\AliasResolver;
+use Magento\Eav\Model\Config as EavConfig;
+use Magento\Framework\App\Config\ScopeConfigInterface;
+use Magento\Framework\App\ResourceConnection;
+use Magento\Store\Model\ScopeInterface;
+use Magento\Store\Model\StoreManagerInterface;
+
+/**
+ * This strategy handles attributes which comply with two criteria:
+ *   - The filter for dropdown or multi-select attribute
+ *   - The filter is Term filter
+ *
+ */
+class TermDropdownStrategy implements FilterStrategyInterface
+{
+    /**
+     * @var AliasResolver
+     */
+    private $aliasResolver;
+
+    /**
+     * @var StoreManagerInterface
+     */
+    private $storeManager;
+
+    /**
+     * @var EavConfig
+     */
+    private $eavConfig;
+
+    /**
+     * @var ResourceConnection
+     */
+    private $resourceConnection;
+
+    /**
+     * @var ScopeConfigInterface
+     */
+    private $scopeConfig;
+
+    /**
+     * @param StoreManagerInterface $storeManager
+     * @param ResourceConnection $resourceConnection
+     * @param EavConfig $eavConfig
+     * @param ScopeConfigInterface $scopeConfig
+     * @param AliasResolver $aliasResolver
+     */
+    public function __construct(
+        StoreManagerInterface $storeManager,
+        ResourceConnection $resourceConnection,
+        EavConfig $eavConfig,
+        ScopeConfigInterface $scopeConfig,
+        AliasResolver $aliasResolver
+    ) {
+        $this->storeManager = $storeManager;
+        $this->resourceConnection = $resourceConnection;
+        $this->eavConfig = $eavConfig;
+        $this->scopeConfig = $scopeConfig;
+        $this->aliasResolver = $aliasResolver;
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws \Magento\Framework\Exception\LocalizedException
+     */
+    public function apply(
+        \Magento\Framework\Search\Request\FilterInterface $filter,
+        \Magento\Framework\DB\Select $select
+    ) {
+        $alias = $this->aliasResolver->getAlias($filter);
+        $attribute = $this->getAttributeByCode($filter->getField());
+        $joinCondition = sprintf(
+            'search_index.entity_id = %1$s.entity_id AND %1$s.attribute_id = %2$d AND %1$s.store_id = %3$d',
+            $alias,
+            $attribute->getId(),
+            $this->storeManager->getWebsite()->getId()
+        );
+        $select->joinLeft(
+            [$alias => $this->resourceConnection->getTableName('catalog_product_index_eav')],
+            $joinCondition,
+            []
+        );
+        if ($this->isAddStockFilter()) {
+            $stockAlias = $alias . AliasResolver::STOCK_FILTER_SUFFIX;
+            $select->joinLeft(
+                [
+                    $stockAlias => $this->resourceConnection->getTableName('cataloginventory_stock_status'),
+                ],
+                sprintf('%2$s.product_id = %1$s.source_id', $alias, $stockAlias),
+                []
+            );
+        }
+
+        return true;
+    }
+
+    /**
+     * @param string $field
+     * @return \Magento\Catalog\Model\ResourceModel\Eav\Attribute
+     * @throws \Magento\Framework\Exception\LocalizedException
+     */
+    private function getAttributeByCode($field)
+    {
+        return $this->eavConfig->getAttribute(\Magento\Catalog\Model\Product::ENTITY, $field);
+    }
+
+    /**
+     * @return bool
+     */
+    private function isAddStockFilter()
+    {
+        $isShowOutOfStock = $this->scopeConfig->isSetFlag(
+            'cataloginventory/options/show_out_of_stock',
+            ScopeInterface::SCOPE_STORE
+        );
+
+        return false === $isShowOutOfStock;
+    }
+}
diff --git a/app/code/Magento/CatalogSearch/Model/Search/IndexBuilder.php b/app/code/Magento/CatalogSearch/Model/Search/IndexBuilder.php
index 1d30bb4a14d23a94d79a2faa5bc20823df220d8d..0e96e4de700259c9dc48c8f876983e2642316a86 100644
--- a/app/code/Magento/CatalogSearch/Model/Search/IndexBuilder.php
+++ b/app/code/Magento/CatalogSearch/Model/Search/IndexBuilder.php
@@ -99,6 +99,7 @@ class IndexBuilder implements IndexBuilderInterface
      *
      * @param RequestInterface $request
      * @return Select
+     * @throws \LogicException
      */
     public function build(RequestInterface $request)
     {
@@ -132,7 +133,7 @@ class IndexBuilder implements IndexBuilderInterface
                 ),
                 []
             );
-            $select->where('stock_index.stock_status = ?', Stock::DEFAULT_STOCK_ID);
+            $select->where('stock_index.stock_status = ?', Stock::STOCK_IN_STOCK);
         }
 
         return $select;
diff --git a/app/code/Magento/CatalogSearch/Model/Search/TableMapper.php b/app/code/Magento/CatalogSearch/Model/Search/TableMapper.php
index ca7298e1beaac560ee66427f2b9d57db7ce21508..ac726192856a5fa555eae6757cd83b16930565ee 100644
--- a/app/code/Magento/CatalogSearch/Model/Search/TableMapper.php
+++ b/app/code/Magento/CatalogSearch/Model/Search/TableMapper.php
@@ -6,10 +6,11 @@
 
 namespace Magento\CatalogSearch\Model\Search;
 
-use Magento\Catalog\Model\Product;
 use Magento\Catalog\Model\ResourceModel\Product\Attribute\CollectionFactory;
+use Magento\CatalogSearch\Model\Adapter\Mysql\Filter\AliasResolver;
+use Magento\CatalogSearch\Model\Search\FilterMapper\FilterStrategyInterface;
 use Magento\Eav\Model\Config as EavConfig;
-use Magento\Eav\Model\Entity\Attribute\AbstractAttribute;
+use Magento\Framework\App\Config\ScopeConfigInterface;
 use Magento\Framework\App\ObjectManager;
 use Magento\Framework\App\ResourceConnection as AppResource;
 use Magento\Framework\DB\Select;
@@ -21,12 +22,15 @@ use Magento\Framework\Search\Request\QueryInterface as RequestQueryInterface;
 use Magento\Store\Model\StoreManagerInterface;
 
 /**
+ * Responsibility of the TableMapper is to collect all filters from the search query
+ * and pass them one by one for processing in the FilterContext,
+ * which will apply them to the Select
  * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  */
 class TableMapper
 {
     /**
-     * @var Resource
+     * @var AppResource
      */
     private $resource;
 
@@ -40,22 +44,59 @@ class TableMapper
      */
     private $eavConfig;
 
+    /**
+     * @var ScopeConfigInterface
+     */
+    private $scopeConfig;
+
+    /**
+     * @var FilterStrategyInterface
+     */
+    private $filterStrategy;
+
+    /**
+     * @var AliasResolver
+     */
+    private $aliasResolver;
+
     /**
      * @SuppressWarnings(PHPMD.UnusedFormalParameter)
      * @param AppResource $resource
      * @param StoreManagerInterface $storeManager
      * @param CollectionFactory $attributeCollectionFactory
      * @param EavConfig $eavConfig
+     * @param ScopeConfigInterface $scopeConfig
+     * @param FilterStrategyInterface $filterStrategy
+     * @param AliasResolver $aliasResolver
      */
     public function __construct(
         AppResource $resource,
         StoreManagerInterface $storeManager,
         CollectionFactory $attributeCollectionFactory,
-        EavConfig $eavConfig = null
+        EavConfig $eavConfig = null,
+        ScopeConfigInterface $scopeConfig = null,
+        FilterStrategyInterface $filterStrategy = null,
+        AliasResolver $aliasResolver = null
     ) {
         $this->resource = $resource;
         $this->storeManager = $storeManager;
-        $this->eavConfig = $eavConfig !== null ? $eavConfig : ObjectManager::getInstance()->get(EavConfig::class);
+
+        if (null === $eavConfig) {
+            $eavConfig = ObjectManager::getInstance()->get(EavConfig::class);
+        }
+        if (null === $scopeConfig) {
+            $scopeConfig = ObjectManager::getInstance()->get(ScopeConfigInterface::class);
+        }
+        if (null === $filterStrategy) {
+            $filterStrategy = ObjectManager::getInstance()->get(FilterStrategyInterface::class);
+        }
+        if (null === $aliasResolver) {
+            $aliasResolver = ObjectManager::getInstance()->get(AliasResolver::class);
+        }
+        $this->eavConfig = $eavConfig;
+        $this->scopeConfig = $scopeConfig;
+        $this->filterStrategy = $filterStrategy;
+        $this->aliasResolver = $aliasResolver;
     }
 
     /**
@@ -66,111 +107,53 @@ class TableMapper
      */
     public function addTables(Select $select, RequestInterface $request)
     {
-        $mappedTables = [];
-        $filters = $this->getFilters($request->getQuery());
+        $appliedFilters = [];
+        $filters = $this->getFiltersFromQuery($request->getQuery());
         foreach ($filters as $filter) {
-            list($alias, $table, $mapOn, $mappedFields, $joinType) = $this->getMappingData($filter);
-            if (!array_key_exists($alias, $mappedTables)) {
-                switch ($joinType) {
-                    case \Magento\Framework\DB\Select::INNER_JOIN:
-                        $select->joinInner(
-                            [$alias => $table],
-                            $mapOn,
-                            $mappedFields
-                        );
-                        break;
-                    case \Magento\Framework\DB\Select::LEFT_JOIN:
-                        $select->joinLeft(
-                            [$alias => $table],
-                            $mapOn,
-                            $mappedFields
-                        );
-                        break;
-                    default:
-                        throw new \LogicException(__('Unsupported join type: %1', $joinType));
+            $alias = $this->aliasResolver->getAlias($filter);
+            if (!array_key_exists($alias, $appliedFilters)) {
+                $isApplied = $this->filterStrategy->apply($filter, $select);
+                if ($isApplied) {
+                    $appliedFilters[$alias] = true;
                 }
-                $mappedTables[$alias] = $table;
             }
         }
         return $select;
     }
 
     /**
+     * This method is deprecated.
+     * Please use \Magento\CatalogSearch\Model\Adapter\Mysql\Filter\AliasResolver::getAlias() instead.
+     *
+     * @deprecated
+     * @see AliasResolver::getAlias()
+     *
      * @param FilterInterface $filter
      * @return string
      */
     public function getMappingAlias(FilterInterface $filter)
     {
-        list($alias) = $this->getMappingData($filter);
-        return $alias;
-    }
-
-    /**
-     * Returns mapping data for field in format: [
-     *  'table_alias',
-     *  'table',
-     *  'join_condition',
-     *  ['fields'],
-     *  'joinType'
-     * ]
-     * @param FilterInterface $filter
-     * @return array
-     */
-    private function getMappingData(FilterInterface $filter)
-    {
-        $alias = null;
-        $table = null;
-        $mapOn = null;
-        $mappedFields = null;
-        $field = $filter->getField();
-        $joinType = \Magento\Framework\DB\Select::INNER_JOIN;
-        $fieldToTableMap = $this->getFieldToTableMap($field);
-        if ($fieldToTableMap) {
-            list($alias, $table, $mapOn, $mappedFields) = $fieldToTableMap;
-            $table = $this->resource->getTableName($table);
-        } elseif ($attribute = $this->getAttributeByCode($field)) {
-            if ($filter->getType() === FilterInterface::TYPE_TERM
-                && in_array($attribute->getFrontendInput(), ['select', 'multiselect'], true)
-            ) {
-                $joinType = \Magento\Framework\DB\Select::LEFT_JOIN;
-                $table = $this->resource->getTableName('catalog_product_index_eav');
-                $alias = $field . RequestGenerator::FILTER_SUFFIX;
-                $mapOn = sprintf(
-                    'search_index.entity_id = %1$s.entity_id AND %1$s.attribute_id = %2$d AND %1$s.store_id = %3$d',
-                    $alias,
-                    $attribute->getId(),
-                    $this->getStoreId()
-                );
-                $mappedFields = [];
-            } elseif ($attribute->getBackendType() === AbstractAttribute::TYPE_STATIC) {
-                $table = $attribute->getBackendTable();
-                $alias = $field . RequestGenerator::FILTER_SUFFIX;
-                $mapOn = 'search_index.entity_id = ' . $alias . '.entity_id';
-                $mappedFields = null;
-            }
-        }
-
-        return [$alias, $table, $mapOn, $mappedFields, $joinType];
+        return $this->aliasResolver->getAlias($filter);
     }
 
     /**
      * @param RequestQueryInterface $query
      * @return FilterInterface[]
      */
-    private function getFilters($query)
+    private function getFiltersFromQuery(RequestQueryInterface $query)
     {
         $filters = [];
         switch ($query->getType()) {
             case RequestQueryInterface::TYPE_BOOL:
                 /** @var \Magento\Framework\Search\Request\Query\BoolExpression $query */
                 foreach ($query->getMust() as $subQuery) {
-                    $filters = array_merge($filters, $this->getFilters($subQuery));
+                    $filters = array_merge($filters, $this->getFiltersFromQuery($subQuery));
                 }
                 foreach ($query->getShould() as $subQuery) {
-                    $filters = array_merge($filters, $this->getFilters($subQuery));
+                    $filters = array_merge($filters, $this->getFiltersFromQuery($subQuery));
                 }
                 foreach ($query->getMustNot() as $subQuery) {
-                    $filters = array_merge($filters, $this->getFilters($subQuery));
+                    $filters = array_merge($filters, $this->getFiltersFromQuery($subQuery));
                 }
                 break;
             case RequestQueryInterface::TYPE_FILTER:
@@ -219,57 +202,4 @@ class TableMapper
         }
         return $filters;
     }
-
-    /**
-     * @return int
-     */
-    private function getWebsiteId()
-    {
-        return $this->storeManager->getWebsite()->getId();
-    }
-
-    /**
-     * @return int
-     */
-    private function getStoreId()
-    {
-        return $this->storeManager->getStore()->getId();
-    }
-
-    /**
-     * @param string $field
-     * @return array|null
-     */
-    private function getFieldToTableMap($field)
-    {
-        $fieldToTableMap = [
-            'price' => [
-                'price_index',
-                'catalog_product_index_price',
-                $this->resource->getConnection()->quoteInto(
-                    'search_index.entity_id = price_index.entity_id AND price_index.website_id = ?',
-                    $this->getWebsiteId()
-                ),
-                []
-            ],
-            'category_ids' => [
-                'category_ids_index',
-                'catalog_category_product_index',
-                'search_index.entity_id = category_ids_index.product_id',
-                []
-            ]
-        ];
-        return array_key_exists($field, $fieldToTableMap) ? $fieldToTableMap[$field] : null;
-    }
-
-    /**
-     * @param string $field
-     * @return \Magento\Catalog\Model\ResourceModel\Eav\Attribute
-     * @throws \Magento\Framework\Exception\LocalizedException
-     */
-    private function getAttributeByCode($field)
-    {
-        $attribute = $this->eavConfig->getAttribute(Product::ENTITY, $field);
-        return $attribute;
-    }
 }
diff --git a/app/code/Magento/CatalogSearch/Test/Unit/Model/Adapter/Mysql/Filter/AliasResolverTest.php b/app/code/Magento/CatalogSearch/Test/Unit/Model/Adapter/Mysql/Filter/AliasResolverTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..ab01d2553a3edcebde8a564a8ca8b8bb8cf2c7dd
--- /dev/null
+++ b/app/code/Magento/CatalogSearch/Test/Unit/Model/Adapter/Mysql/Filter/AliasResolverTest.php
@@ -0,0 +1,68 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\CatalogSearch\Test\Unit\Model\Adapter\Mysql\Filter;
+
+use Magento\CatalogSearch\Model\Search\RequestGenerator;
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper;
+
+class AliasResolverTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\CatalogSearch\Model\Adapter\Mysql\Filter\AliasResolver
+     */
+    private $aliasResolver;
+
+    /**
+     * @inheritDoc
+     */
+    protected function setUp()
+    {
+        $objectManagerHelper = new ObjectManagerHelper($this);
+        $this->aliasResolver = $objectManagerHelper->getObject(
+            \Magento\CatalogSearch\Model\Adapter\Mysql\Filter\AliasResolver::class,
+            []
+        );
+    }
+
+    /**
+     * @param string $field
+     * @param string $expectedAlias
+     * @dataProvider aliasDataProvider
+     */
+    public function testGetFilterAlias($field, $expectedAlias)
+    {
+        $filter = $this->getMockBuilder(\Magento\Framework\Search\Request\Filter\Term::class)
+            ->setMethods(['getField'])
+            ->disableOriginalConstructor()
+            ->getMock();
+        $filter->expects($this->once())
+            ->method('getField')
+            ->willReturn($field);
+        $this->assertSame($expectedAlias, $this->aliasResolver->getAlias($filter));
+    }
+
+    /**
+     * @return array
+     */
+    public function aliasDataProvider()
+    {
+        return [
+            'general' => [
+                'field' => 'general',
+                'alias' => 'general' . RequestGenerator::FILTER_SUFFIX,
+            ],
+            'price' => [
+                'field' => 'price',
+                'alias' => 'price_index',
+            ],
+            'category_ids' => [
+                'field' => 'category_ids',
+                'alias' => 'category_ids_index',
+            ],
+        ];
+    }
+}
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 0949bf6469be92611fbefa4c45962d8255570892..2cd6935586bd816bcc8c1e444b242c3b3f7a1472 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
@@ -6,6 +6,7 @@
 
 namespace Magento\CatalogSearch\Test\Unit\Model\Adapter\Mysql\Filter;
 
+use Magento\CatalogSearch\Model\Adapter\Mysql\Filter\AliasResolver;
 use Magento\Framework\DB\Select;
 use Magento\Framework\EntityManager\EntityMetadata;
 use Magento\Framework\Search\Request\FilterInterface;
@@ -18,9 +19,9 @@ use PHPUnit_Framework_MockObject_MockObject as MockObject;
 class PreprocessorTest extends \PHPUnit_Framework_TestCase
 {
     /**
-     * @var \Magento\CatalogSearch\Model\Search\TableMapper|\PHPUnit_Framework_MockObject_MockObject
+     * @var AliasResolver|\PHPUnit_Framework_MockObject_MockObject
      */
-    private $tableMapper;
+    private $aliasResolver;
 
     /**
      * @var \Magento\Framework\DB\Adapter\AdapterInterface|MockObject
@@ -141,7 +142,7 @@ class PreprocessorTest extends \PHPUnit_Framework_TestCase
                 )
             );
 
-        $this->tableMapper = $this->getMockBuilder(\Magento\CatalogSearch\Model\Search\TableMapper::class)
+        $this->aliasResolver = $this->getMockBuilder(AliasResolver::class)
             ->disableOriginalConstructor()
             ->getMock();
         $this->metadataPoolMock = $this->getMockBuilder(\Magento\Framework\EntityManager\MetadataPool::class)
@@ -164,7 +165,7 @@ class PreprocessorTest extends \PHPUnit_Framework_TestCase
                 'resource' => $resource,
                 'attributePrefix' => 'attr_',
                 'metadataPool' => $this->metadataPoolMock,
-                'tableMapper' => $this->tableMapper,
+                'aliasResolver' => $this->aliasResolver,
             ]
         );
     }
@@ -234,7 +235,7 @@ class PreprocessorTest extends \PHPUnit_Framework_TestCase
 
         $this->attribute->method('getAttributeCode')
             ->willReturn('static_attribute');
-        $this->tableMapper->expects($this->once())->method('getMappingAlias')
+        $this->aliasResolver->expects($this->once())->method('getAlias')
             ->willReturn('attr_table_alias');
         $this->filter->expects($this->exactly(3))
             ->method('getField')
@@ -272,7 +273,7 @@ class PreprocessorTest extends \PHPUnit_Framework_TestCase
             ->method('getFrontendInput')
             ->willReturn($frontendInput);
 
-        $this->tableMapper->expects($this->once())->method('getMappingAlias')
+        $this->aliasResolver->expects($this->once())->method('getAlias')
             ->willReturn('termAttrAlias');
 
         $this->filter->expects($this->exactly(3))
diff --git a/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/FilterMapper/FilterContextTest.php b/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/FilterMapper/FilterContextTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..9f133b763889bafb4843f7f9f868a3995a842eed
--- /dev/null
+++ b/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/FilterMapper/FilterContextTest.php
@@ -0,0 +1,236 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\CatalogSearch\Test\Unit\Model\Search\FilterMapper;
+
+use Magento\Catalog\Model\ResourceModel\Eav\Attribute;
+use Magento\CatalogSearch\Model\Adapter\Mysql\Filter\AliasResolver;
+use Magento\CatalogSearch\Model\Search\FilterMapper\ExclusionStrategy;
+use Magento\CatalogSearch\Model\Search\FilterMapper\FilterContext;
+use Magento\CatalogSearch\Model\Search\FilterMapper\StaticAttributeStrategy;
+use Magento\CatalogSearch\Model\Search\FilterMapper\TermDropdownStrategy;
+use Magento\Eav\Model\Entity\Attribute\AbstractAttribute;
+use Magento\Framework\Search\Request\FilterInterface;
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
+
+class FilterContextTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var FilterContext|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $filterContext;
+
+    /**
+     * @var AliasResolver|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $aliasResolver;
+
+    /**
+     * @var \Magento\Eav\Model\Config|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $eavConfig;
+
+    /**
+     * @var ExclusionStrategy|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $exclusionStrategy;
+
+    /**
+     * @var TermDropdownStrategy|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $termDropdownStrategy;
+
+    /**
+     * @var StaticAttributeStrategy|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $staticAttributeStrategy;
+
+    /**
+     * @var \Magento\Framework\DB\Select
+     */
+    private $select;
+
+    /**
+     * @inheritDoc
+     */
+    protected function setUp()
+    {
+        $this->eavConfig = $this->getMockBuilder(\Magento\Eav\Model\Config::class)
+            ->disableOriginalConstructor()
+            ->setMethods(['getAttribute'])
+            ->getMock();
+        $this->aliasResolver = $this->getMockBuilder(
+            AliasResolver::class
+        )
+            ->disableOriginalConstructor()
+            ->setMethods(['getAlias'])
+            ->getMock();
+        $this->exclusionStrategy = $this->getMockBuilder(ExclusionStrategy::class)
+            ->disableOriginalConstructor()
+            ->setMethods(['apply'])
+            ->getMock();
+        $this->termDropdownStrategy = $this->getMockBuilder(TermDropdownStrategy::class)
+            ->disableOriginalConstructor()
+            ->setMethods(['apply'])
+            ->getMock();
+        $this->staticAttributeStrategy = $this->getMockBuilder(StaticAttributeStrategy::class)
+            ->disableOriginalConstructor()
+            ->setMethods(['apply'])
+            ->getMock();
+        $this->select = $this->getMockBuilder(\Magento\Framework\DB\Select::class)
+            ->disableOriginalConstructor()
+            ->setMethods([])
+            ->getMock();
+        $objectManager = new ObjectManager($this);
+        $this->filterContext = $objectManager->getObject(
+            FilterContext::class,
+            [
+                'eavConfig' => $this->eavConfig,
+                'aliasResolver' => $this->aliasResolver,
+                'exclusionStrategy' => $this->exclusionStrategy,
+                'termDropdownStrategy' => $this->termDropdownStrategy,
+                'staticAttributeStrategy' => $this->staticAttributeStrategy,
+            ]
+        );
+    }
+
+    public function testApplyOnExclusionFilter()
+    {
+        $filter = $this->createFilterMock();
+        $this->exclusionStrategy->expects($this->once())
+            ->method('apply')
+            ->with($filter, $this->select)
+            ->willReturn(true);
+        $this->eavConfig->expects($this->never())->method('getAttribute');
+        $this->assertTrue($this->filterContext->apply($filter, $this->select));
+    }
+
+    public function testApplyFilterWithoutAttribute()
+    {
+        $filter = $this->createFilterMock('some_field');
+        $this->exclusionStrategy->expects($this->once())
+            ->method('apply')
+            ->with($filter, $this->select)
+            ->willReturn(false);
+        $this->eavConfig->expects($this->once())
+            ->method('getAttribute')
+            ->with(\Magento\Catalog\Model\Product::ENTITY, 'some_field')
+            ->willReturn(null);
+        $this->assertFalse($this->filterContext->apply($filter, $this->select));
+    }
+
+    public function testApplyOnTermFilterBySelect()
+    {
+        $filter = $this->createFilterMock('select_field', FilterInterface::TYPE_TERM);
+        $attribute = $this->createAttributeMock('select');
+        $this->eavConfig->expects($this->once())
+            ->method('getAttribute')
+            ->with(\Magento\Catalog\Model\Product::ENTITY, 'select_field')
+            ->willReturn($attribute);
+        $this->exclusionStrategy->expects($this->once())
+            ->method('apply')
+            ->with($filter, $this->select)
+            ->willReturn(false);
+        $this->termDropdownStrategy->expects($this->once())
+            ->method('apply')
+            ->with($filter, $this->select)
+            ->willReturn(true);
+        $this->assertTrue($this->filterContext->apply($filter, $this->select));
+    }
+
+    public function testApplyOnTermFilterByMultiSelect()
+    {
+        $filter = $this->createFilterMock('multiselect_field', FilterInterface::TYPE_TERM);
+        $attribute = $this->createAttributeMock('multiselect');
+        $this->eavConfig->expects($this->once())
+            ->method('getAttribute')
+            ->with(\Magento\Catalog\Model\Product::ENTITY, 'multiselect_field')
+            ->willReturn($attribute);
+        $this->exclusionStrategy->expects($this->once())
+            ->method('apply')
+            ->with($filter, $this->select)
+            ->willReturn(false);
+        $this->termDropdownStrategy->expects($this->once())
+            ->method('apply')
+            ->with($filter, $this->select)
+            ->willReturn(true);
+        $this->assertTrue($this->filterContext->apply($filter, $this->select));
+    }
+
+    public function testApplyOnTermFilterByStaticAttribute()
+    {
+        $filter = $this->createFilterMock('multiselect_field', FilterInterface::TYPE_TERM);
+        $attribute = $this->createAttributeMock('text', AbstractAttribute::TYPE_STATIC);
+        $this->eavConfig->expects($this->once())
+            ->method('getAttribute')
+            ->with(\Magento\Catalog\Model\Product::ENTITY, 'multiselect_field')
+            ->willReturn($attribute);
+        $this->exclusionStrategy->expects($this->once())
+            ->method('apply')
+            ->with($filter, $this->select)
+            ->willReturn(false);
+        $this->staticAttributeStrategy->expects($this->once())
+            ->method('apply')
+            ->with($filter, $this->select)
+            ->willReturn(true);
+        $this->assertTrue($this->filterContext->apply($filter, $this->select));
+    }
+
+    public function testApplyOnTermFilterByUnknownAttributeType()
+    {
+        $filter = $this->createFilterMock('multiselect_field', FilterInterface::TYPE_TERM);
+        $attribute = $this->createAttributeMock('text', 'text');
+        $this->eavConfig->expects($this->once())
+            ->method('getAttribute')
+            ->with(\Magento\Catalog\Model\Product::ENTITY, 'multiselect_field')
+            ->willReturn($attribute);
+        $this->exclusionStrategy->expects($this->once())
+            ->method('apply')
+            ->with($filter, $this->select)
+            ->willReturn(false);
+        $this->assertFalse($this->filterContext->apply($filter, $this->select));
+    }
+
+    /**
+     * @param string $field
+     * @param string $type
+     * @return FilterInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private function createFilterMock($field = null, $type = null)
+    {
+        $filter = $this->getMockBuilder(FilterInterface::class)
+            ->setMethods(['getField', 'getType'])
+            ->getMockForAbstractClass();
+        $filter->expects($this->any())
+            ->method('getField')
+            ->willReturn($field);
+        $filter->expects($this->any())
+            ->method('getType')
+            ->willReturn($type);
+
+        return $filter;
+    }
+
+    /**
+     * @param string|null $frontendInput
+     * @param string|null $backendType
+     * @return Attribute|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private function createAttributeMock($frontendInput = null, $backendType = null)
+    {
+        $attribute = $this->getMockBuilder(Attribute::class)
+            ->disableOriginalConstructor()
+            ->setMethods(['getFrontendInput', 'getBackendType'])
+            ->getMock();
+        $attribute->expects($this->any())
+            ->method('getFrontendInput')
+            ->willReturn($frontendInput);
+        $attribute->expects($this->any())
+            ->method('getBackendType')
+            ->willReturn($backendType);
+        return $attribute;
+    }
+}
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 dd9a556146ab3e40e4e1182f44c959c8260d9c8d..dad4ad8095f5af27fa3ce7cd48b1803c706d80a6 100644
--- a/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/TableMapperTest.php
+++ b/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/TableMapperTest.php
@@ -6,6 +6,9 @@
 
 namespace Magento\CatalogSearch\Test\Unit\Model\Search;
 
+use Magento\Catalog\Model\ResourceModel\Product\Attribute\Collection;
+use Magento\Catalog\Model\ResourceModel\Product\Attribute\CollectionFactory;
+use Magento\CatalogSearch\Model\Adapter\Mysql\Filter\AliasResolver;
 use Magento\Framework\Search\Request\FilterInterface;
 use Magento\Framework\Search\Request\QueryInterface;
 use \Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
@@ -16,8 +19,10 @@ use \Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
  */
 class TableMapperTest extends \PHPUnit_Framework_TestCase
 {
-    const WEBSITE_ID = 4512;
-    const STORE_ID = 2514;
+    /**
+     * @var AliasResolver|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $aliasResolver;
 
     /**
      * @var \Magento\Eav\Model\Config|\PHPUnit_Framework_MockObject_MockObject
@@ -25,7 +30,7 @@ class TableMapperTest extends \PHPUnit_Framework_TestCase
     private $eavConfig;
 
     /**
-     * @var \Magento\Catalog\Model\ResourceModel\Product\Attribute\Collection|\PHPUnit_Framework_MockObject_MockObject
+     * @var Collection|\PHPUnit_Framework_MockObject_MockObject
      */
     private $attributeCollection;
 
@@ -59,11 +64,6 @@ class TableMapperTest extends \PHPUnit_Framework_TestCase
      */
     private $resource;
 
-    /**
-     * @var \Magento\Store\Api\Data\StoreInterface|\PHPUnit_Framework_MockObject_MockObject
-     */
-    private $store;
-
     /**
      * @var \Magento\CatalogSearch\Model\Search\TableMapper
      */
@@ -76,65 +76,49 @@ class TableMapperTest extends \PHPUnit_Framework_TestCase
         $this->connection = $this->getMockBuilder(\Magento\Framework\DB\Adapter\AdapterInterface::class)
             ->disableOriginalConstructor()
             ->getMock();
-        $this->connection->expects($this->any())
-            ->method('quoteInto')
-            ->willReturnCallback(
-                function ($query, $expression) {
-                    return str_replace('?', $expression, $query);
-                }
-            );
+        $this->connection->expects($this->never())->method('quoteInto');
 
         $this->resource = $this->getMockBuilder(\Magento\Framework\App\ResourceConnection::class)
             ->disableOriginalConstructor()
             ->getMock();
-        $this->resource->method('getTableName')
-            ->willReturnCallback(
-                function ($table) {
-                    return 'prefix_' . $table;
-                }
-            );
-        $this->resource->expects($this->any())
-            ->method('getConnection')
-            ->willReturn($this->connection);
+        $this->resource->expects($this->never())->method('getTableName');
+        $this->resource->expects($this->never())->method('getConnection');
 
         $this->website = $this->getMockBuilder(\Magento\Store\Api\Data\WebsiteInterface::class)
             ->disableOriginalConstructor()
             ->getMockForAbstractClass();
-        $this->website->expects($this->any())
-            ->method('getId')
-            ->willReturn(self::WEBSITE_ID);
-        $this->store = $this->getMockBuilder(\Magento\Store\Api\Data\StoreInterface::class)
-            ->disableOriginalConstructor()
-            ->getMockForAbstractClass();
-        $this->store->expects($this->any())
-            ->method('getId')
-            ->willReturn(self::STORE_ID);
+        $this->website->expects($this->never())->method('getId');
+
         $this->storeManager = $this->getMockBuilder(\Magento\Store\Model\StoreManagerInterface::class)
             ->disableOriginalConstructor()
             ->getMock();
-        $this->storeManager->expects($this->any())
-            ->method('getWebsite')
-            ->willReturn($this->website);
-        $this->storeManager->expects($this->any())
-            ->method('getStore')
-            ->willReturn($this->store);
-        $this->attributeCollection = $this->getMockBuilder(
-            \Magento\Catalog\Model\ResourceModel\Product\Attribute\Collection::class
-        )
+        $this->storeManager->expects($this->never())->method('getWebsite');
+        $this->storeManager->expects($this->never())->method('getStore');
+
+        $this->attributeCollection = $this->getMockBuilder(Collection::class)
             ->disableOriginalConstructor()
             ->getMock();
-        $attributeCollectionFactory = $this->getMockBuilder(
-            \Magento\Catalog\Model\ResourceModel\Product\Attribute\CollectionFactory::class
-        )
+        $attributeCollectionFactory = $this->getMockBuilder(CollectionFactory::class)
             ->setMethods(['create'])
             ->disableOriginalConstructor()
             ->getMock();
         $attributeCollectionFactory->expects($this->never())
             ->method('create');
+
         $this->eavConfig = $this->getMockBuilder(\Magento\Eav\Model\Config::class)
             ->setMethods(['getAttribute'])
             ->disableOriginalConstructor()
             ->getMock();
+
+        $this->aliasResolver = $this->getMockBuilder(AliasResolver::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->aliasResolver->expects($this->any())
+            ->method('getAlias')
+            ->willReturnCallback(function (FilterInterface $filter) {
+                return $filter->getField() . '_alias';
+            });
+
         $this->target = $objectManager->getObject(
             \Magento\CatalogSearch\Model\Search\TableMapper::class,
             [
@@ -142,6 +126,7 @@ class TableMapperTest extends \PHPUnit_Framework_TestCase
                 'storeManager' => $this->storeManager,
                 'attributeCollectionFactory' => $attributeCollectionFactory,
                 'eavConfig' => $this->eavConfig,
+                'aliasResolver' => $this->aliasResolver,
             ]
         );
 
@@ -160,14 +145,7 @@ class TableMapperTest extends \PHPUnit_Framework_TestCase
         $this->request->expects($this->once())
             ->method('getQuery')
             ->willReturn($query);
-        $this->select->expects($this->once())
-            ->method('joinInner')
-            ->with(
-                ['price_index' => 'prefix_catalog_product_index_price'],
-                'search_index.entity_id = price_index.entity_id AND price_index.website_id = ' . self::WEBSITE_ID,
-                []
-            )
-            ->willReturnSelf();
+
         $select = $this->target->addTables($this->select, $this->request);
         $this->assertEquals($this->select, $select, 'Returned results isn\'t equal to passed select');
     }
@@ -176,18 +154,10 @@ class TableMapperTest extends \PHPUnit_Framework_TestCase
     {
         $priceFilter = $this->createRangeFilter('static');
         $query = $this->createFilterQuery($priceFilter);
-        $this->createAttributeMock('static', 'static', 'backend_table', 0, 'select');
         $this->request->expects($this->once())
             ->method('getQuery')
             ->willReturn($query);
-        $this->select->expects($this->once())
-            ->method('joinInner')
-            ->with(
-                ['static_filter' => 'backend_table'],
-                'search_index.entity_id = static_filter.entity_id',
-                null
-            )
-            ->willReturnSelf();
+
         $select = $this->target->addTables($this->select, $this->request);
         $this->assertEquals($this->select, $select, 'Returned results isn\'t equal to passed select');
     }
@@ -199,46 +169,25 @@ class TableMapperTest extends \PHPUnit_Framework_TestCase
         $this->request->expects($this->once())
             ->method('getQuery')
             ->willReturn($query);
-        $this->select->expects($this->once())
-            ->method('joinInner')
-            ->with(
-                ['category_ids_index' => 'prefix_catalog_category_product_index'],
-                'search_index.entity_id = category_ids_index.product_id',
-                []
-            )
-            ->willReturnSelf();
+
         $select = $this->target->addTables($this->select, $this->request);
         $this->assertEquals($this->select, $select, 'Returned results isn\'t equal to passed select');
     }
 
     public function testAddTermFilter()
     {
-        $this->createAttributeMock('color', null, null, 132, 'select', 0);
         $categoryIdsFilter = $this->createTermFilter('color');
         $query = $this->createFilterQuery($categoryIdsFilter);
         $this->request->expects($this->once())
             ->method('getQuery')
             ->willReturn($query);
-        $this->select->expects($this->once())
-            ->method('joinLeft')
-            ->with(
-                ['color_filter' => 'prefix_catalog_product_index_eav'],
-                'search_index.entity_id = color_filter.entity_id'
-                . ' AND color_filter.attribute_id = 132'
-                . ' AND color_filter.store_id = 2514',
-                []
-            )
-            ->willReturnSelf();
+
         $select = $this->target->addTables($this->select, $this->request);
         $this->assertEquals($this->select, $select, 'Returned results isn\'t equal to passed select');
     }
 
     public function testAddBoolQueryWithTermFiltersInside()
     {
-        $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')),
@@ -253,45 +202,13 @@ class TableMapperTest extends \PHPUnit_Framework_TestCase
         $this->request->expects($this->once())
             ->method('getQuery')
             ->willReturn($query);
-        $this->select->expects($this->at(0))
-            ->method('joinLeft')
-            ->with(
-                ['must1_filter' => 'prefix_catalog_product_index_eav'],
-                'search_index.entity_id = must1_filter.entity_id'
-                . ' AND must1_filter.attribute_id = 101'
-                . ' AND must1_filter.store_id = 2514',
-                []
-            )
-            ->willReturnSelf();
-        $this->select->expects($this->at(1))
-            ->method('joinLeft')
-            ->with(
-                ['should1_filter' => 'prefix_catalog_product_index_eav'],
-                'search_index.entity_id = should1_filter.entity_id'
-                . ' AND should1_filter.attribute_id = 102'
-                . ' AND should1_filter.store_id = 2514',
-                []
-            )
-            ->willReturnSelf();
-        $this->select->expects($this->at(2))
-            ->method('joinLeft')
-            ->with(
-                ['mustNot1_filter' => 'prefix_catalog_product_index_eav'],
-                'search_index.entity_id = mustNot1_filter.entity_id'
-                . ' AND mustNot1_filter.attribute_id = 103'
-                . ' AND mustNot1_filter.store_id = 2514',
-                []
-            )
-            ->willReturnSelf();
+
         $select = $this->target->addTables($this->select, $this->request);
         $this->assertEquals($this->select, $select, 'Returned results isn\'t equal to passed select');
     }
 
     public function testAddBoolQueryWithTermAndPriceFiltersInside()
     {
-        $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')),
@@ -307,53 +224,13 @@ class TableMapperTest extends \PHPUnit_Framework_TestCase
         $this->request->expects($this->once())
             ->method('getQuery')
             ->willReturn($query);
-        $this->select->expects($this->at(0))
-            ->method('joinLeft')
-            ->with(
-                ['must1_filter' => 'prefix_catalog_product_index_eav'],
-                'search_index.entity_id = must1_filter.entity_id'
-                . ' AND must1_filter.attribute_id = 101'
-                . ' AND must1_filter.store_id = 2514',
-                []
-            )
-            ->willReturnSelf();
-        $this->select->expects($this->at(1))
-            ->method('joinInner')
-            ->with(
-                ['price_index' => 'prefix_catalog_product_index_price'],
-                'search_index.entity_id = price_index.entity_id AND price_index.website_id = ' . self::WEBSITE_ID,
-                []
-            )
-            ->willReturnSelf();
-        $this->select->expects($this->at(2))
-            ->method('joinLeft')
-            ->with(
-                ['should1_filter' => 'prefix_catalog_product_index_eav'],
-                'search_index.entity_id = should1_filter.entity_id'
-                . ' AND should1_filter.attribute_id = 102'
-                . ' AND should1_filter.store_id = 2514',
-                []
-            )
-            ->willReturnSelf();
-        $this->select->expects($this->at(3))
-            ->method('joinLeft')
-            ->with(
-                ['mustNot1_filter' => 'prefix_catalog_product_index_eav'],
-                'search_index.entity_id = mustNot1_filter.entity_id'
-                . ' AND mustNot1_filter.attribute_id = 103'
-                . ' AND mustNot1_filter.store_id = 2514',
-                []
-            )
-            ->willReturnSelf();
+
         $select = $this->target->addTables($this->select, $this->request);
         $this->assertEquals($this->select, $select, 'Returned results isn\'t equal to passed select');
     }
 
     public function testAddBoolFilterWithTermFiltersInside()
     {
-        $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(
                 [
@@ -370,45 +247,13 @@ class TableMapperTest extends \PHPUnit_Framework_TestCase
         $this->request->expects($this->once())
             ->method('getQuery')
             ->willReturn($query);
-        $this->select->expects($this->at(0))
-            ->method('joinLeft')
-            ->with(
-                ['must1_filter' => 'prefix_catalog_product_index_eav'],
-                'search_index.entity_id = must1_filter.entity_id'
-                . ' AND must1_filter.attribute_id = 101'
-                . ' AND must1_filter.store_id = 2514',
-                []
-            )
-            ->willReturnSelf();
-        $this->select->expects($this->at(1))
-            ->method('joinLeft')
-            ->with(
-                ['should1_filter' => 'prefix_catalog_product_index_eav'],
-                'search_index.entity_id = should1_filter.entity_id'
-                . ' AND should1_filter.attribute_id = 102'
-                . ' AND should1_filter.store_id = 2514',
-                []
-            )
-            ->willReturnSelf();
-        $this->select->expects($this->at(2))
-            ->method('joinLeft')
-            ->with(
-                ['mustNot1_filter' => 'prefix_catalog_product_index_eav'],
-                'search_index.entity_id = mustNot1_filter.entity_id'
-                . ' AND mustNot1_filter.attribute_id = 103'
-                . ' AND mustNot1_filter.store_id = 2514',
-                []
-            )
-            ->willReturnSelf();
+
         $select = $this->target->addTables($this->select, $this->request);
         $this->assertEquals($this->select, $select, 'Returned results isn\'t equal to passed select');
     }
 
     public function testAddBoolFilterWithBoolFiltersInside()
     {
-        $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(
                 [
@@ -425,36 +270,7 @@ class TableMapperTest extends \PHPUnit_Framework_TestCase
         $this->request->expects($this->once())
             ->method('getQuery')
             ->willReturn($query);
-        $this->select->expects($this->at(0))
-            ->method('joinLeft')
-            ->with(
-                ['must1_filter' => 'prefix_catalog_product_index_eav'],
-                'search_index.entity_id = must1_filter.entity_id'
-                . ' AND must1_filter.attribute_id = 101'
-                . ' AND must1_filter.store_id = 2514',
-                []
-            )
-            ->willReturnSelf();
-        $this->select->expects($this->at(1))
-            ->method('joinLeft')
-            ->with(
-                ['should1_filter' => 'prefix_catalog_product_index_eav'],
-                'search_index.entity_id = should1_filter.entity_id'
-                . ' AND should1_filter.attribute_id = 102'
-                . ' AND should1_filter.store_id = 2514',
-                []
-            )
-            ->willReturnSelf();
-        $this->select->expects($this->at(2))
-            ->method('joinLeft')
-            ->with(
-                ['mustNot1_filter' => 'prefix_catalog_product_index_eav'],
-                'search_index.entity_id = mustNot1_filter.entity_id'
-                . ' AND mustNot1_filter.attribute_id = 103'
-                . ' AND mustNot1_filter.store_id = 2514',
-                []
-            )
-            ->willReturnSelf();
+
         $select = $this->target->addTables($this->select, $this->request);
         $this->assertEquals($this->select, $select, 'Returned results isn\'t equal to passed select');
     }
@@ -472,6 +288,7 @@ class TableMapperTest extends \PHPUnit_Framework_TestCase
             ->willReturn(QueryInterface::TYPE_FILTER);
         $query->method('getReference')
             ->willReturn($filter);
+
         return $query;
     }
 
@@ -495,6 +312,7 @@ class TableMapperTest extends \PHPUnit_Framework_TestCase
             ->willReturn($should);
         $query->method('getMustNot')
             ->willReturn($mustNot);
+
         return $query;
     }
 
@@ -518,6 +336,7 @@ class TableMapperTest extends \PHPUnit_Framework_TestCase
             ->willReturn($should);
         $query->method('getMustNot')
             ->willReturn($mustNot);
+
         return $query;
     }
 
@@ -532,6 +351,7 @@ class TableMapperTest extends \PHPUnit_Framework_TestCase
             FilterInterface::TYPE_RANGE,
             $field
         );
+
         return $filter;
     }
 
@@ -546,6 +366,7 @@ class TableMapperTest extends \PHPUnit_Framework_TestCase
             FilterInterface::TYPE_TERM,
             $field
         );
+
         return $filter;
     }
 
@@ -564,40 +385,7 @@ class TableMapperTest extends \PHPUnit_Framework_TestCase
             ->willReturn($type);
         $filter->method('getField')
             ->willReturn($field);
-        return $filter;
-    }
 
-    /**
-     * @param string $code
-     * @param string $backendType
-     * @param string $backendTable
-     * @param int $attributeId
-     * @param string $frontendInput
-     * @param int $positionInCollection
-     */
-    private function createAttributeMock(
-        $code,
-        $backendType = null,
-        $backendTable = null,
-        $attributeId = 120,
-        $frontendInput = 'select',
-        $positionInCollection = 0
-    ) {
-        $attribute = $this->getMockBuilder(\Magento\Catalog\Model\ResourceModel\Eav\Attribute::class)
-            ->setMethods(['getBackendType', 'getBackendTable', 'getId', 'getFrontendInput'])
-            ->disableOriginalConstructor()
-            ->getMock();
-        $attribute->method('getId')
-            ->willReturn($attributeId);
-        $attribute->method('getBackendType')
-            ->willReturn($backendType);
-        $attribute->method('getBackendTable')
-            ->willReturn($backendTable);
-        $attribute->method('getFrontendInput')
-            ->willReturn($frontendInput);
-        $this->eavConfig->expects($this->at($positionInCollection))
-            ->method('getAttribute')
-            ->with(\Magento\Catalog\Model\Product::ENTITY, $code)
-            ->willReturn($attribute);
+        return $filter;
     }
 }
diff --git a/app/code/Magento/CatalogSearch/composer.json b/app/code/Magento/CatalogSearch/composer.json
index 49756420bd2308cd1f8326f474395b6209c7450c..313cc99881a318799c15488fa742151e26db18ec 100644
--- a/app/code/Magento/CatalogSearch/composer.json
+++ b/app/code/Magento/CatalogSearch/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-catalog-search",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-store": "100.2.*",
         "magento/module-catalog": "101.1.*",
         "magento/module-search": "100.2.*",
diff --git a/app/code/Magento/CatalogSearch/etc/di.xml b/app/code/Magento/CatalogSearch/etc/di.xml
index f62b4e47767a25230c5c2ad8372f99acc6bda2eb..7e9451f9b83e7ada30455509b8fd686a0c251705 100644
--- a/app/code/Magento/CatalogSearch/etc/di.xml
+++ b/app/code/Magento/CatalogSearch/etc/di.xml
@@ -11,6 +11,7 @@
     <preference for="Magento\Framework\Search\Adapter\Mysql\Filter\PreprocessorInterface" type="Magento\CatalogSearch\Model\Adapter\Mysql\Filter\Preprocessor" />
     <preference for="Magento\Framework\Search\Dynamic\DataProviderInterface" type="Magento\CatalogSearch\Model\Adapter\Mysql\Dynamic\DataProvider" />
     <preference for="Magento\Framework\Search\Adapter\OptionsInterface" type="Magento\CatalogSearch\Model\Adapter\Options" />
+    <preference for="Magento\CatalogSearch\Model\Search\FilterMapper\FilterStrategyInterface" type="Magento\CatalogSearch\Model\Search\FilterMapper\FilterContext"/>
     <type name="Magento\CatalogSearch\Model\Indexer\IndexerHandlerFactory">
         <arguments>
             <argument name="configPath" xsi:type="const">Magento\CatalogSearch\Model\ResourceModel\EngineInterface::CONFIG_ENGINE_PATH</argument>
diff --git a/app/code/Magento/CatalogUrlRewrite/composer.json b/app/code/Magento/CatalogUrlRewrite/composer.json
index 8fd54cbc8ee8319f625cd6320954a0c821bf9a52..a5f66cd09dda49086434a4dc73b073fe7f0ee9c3 100644
--- a/app/code/Magento/CatalogUrlRewrite/composer.json
+++ b/app/code/Magento/CatalogUrlRewrite/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-catalog-url-rewrite",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-backend": "100.2.*",
         "magento/module-catalog": "101.1.*",
         "magento/module-catalog-import-export": "100.2.*",
diff --git a/app/code/Magento/CatalogWidget/composer.json b/app/code/Magento/CatalogWidget/composer.json
index 330f46176286c70822a32762dccfed157a2ce358..198e54db32d888dfc32eafd33f5c6b3ca45da870 100644
--- a/app/code/Magento/CatalogWidget/composer.json
+++ b/app/code/Magento/CatalogWidget/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-catalog-widget",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-catalog": "101.1.*",
         "magento/module-widget": "100.2.*",
         "magento/module-backend": "100.2.*",
diff --git a/app/code/Magento/Checkout/Controller/Cart/Add.php b/app/code/Magento/Checkout/Controller/Cart/Add.php
index fddfa63b5983e5f508f5211c19f8980d56aafc34..bfbf0008bf5892067aaa7b0ba53ca1bbb7632339 100644
--- a/app/code/Magento/Checkout/Controller/Cart/Add.php
+++ b/app/code/Magento/Checkout/Controller/Cart/Add.php
@@ -84,6 +84,7 @@ class Add extends \Magento\Checkout\Controller\Cart
         }
 
         $params = $this->getRequest()->getParams();
+
         try {
             if (isset($params['qty'])) {
                 $filter = new \Zend_Filter_LocalizedToNormalized(
diff --git a/app/code/Magento/Checkout/Model/Cart.php b/app/code/Magento/Checkout/Model/Cart.php
index 4ce23c9c7f7090980d48f4c3bb231d4214a7e893..236c716f572d91e4bd4b88366414480567ccabc0 100644
--- a/app/code/Magento/Checkout/Model/Cart.php
+++ b/app/code/Magento/Checkout/Model/Cart.php
@@ -91,6 +91,11 @@ class Cart extends DataObject implements CartInterface
      */
     protected $productRepository;
 
+    /**
+     * @var \Magento\Checkout\Model\Cart\RequestInfoFilterInterface
+     */
+    private $requestInfoFilter;
+
     /**
      * @param \Magento\Framework\Event\ManagerInterface $eventManager
      * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
@@ -315,6 +320,7 @@ class Cart extends DataObject implements CartInterface
      *
      * @param   \Magento\Framework\DataObject|int|array $requestInfo
      * @return  \Magento\Framework\DataObject
+     * @throws \Magento\Framework\Exception\LocalizedException
      */
     protected function _getProductRequest($requestInfo)
     {
@@ -322,11 +328,14 @@ class Cart extends DataObject implements CartInterface
             $request = $requestInfo;
         } elseif (is_numeric($requestInfo)) {
             $request = new \Magento\Framework\DataObject(['qty' => $requestInfo]);
-        } else {
+        } elseif (is_array($requestInfo)) {
             $request = new \Magento\Framework\DataObject($requestInfo);
+        } else {
+            throw new \Magento\Framework\Exception\LocalizedException(
+                __('We found an invalid request for adding product to quote.')
+            );
         }
-
-        !$request->hasFormKey() ?: $request->unsFormKey();
+        $this->getRequestInfoFilter()->filter($request);
 
         return $request;
     }
@@ -722,4 +731,19 @@ class Cart extends DataObject implements CartInterface
         $this->_checkoutSession->setLastAddedProductId($productId);
         return $result;
     }
+
+    /**
+     * Getter for RequestInfoFilter
+     *
+     * @deprecated
+     * @return \Magento\Checkout\Model\Cart\RequestInfoFilterInterface
+     */
+    private function getRequestInfoFilter()
+    {
+        if ($this->requestInfoFilter === null) {
+            $this->requestInfoFilter = \Magento\Framework\App\ObjectManager::getInstance()
+                ->get(\Magento\Checkout\Model\Cart\RequestInfoFilterInterface::class);
+        }
+        return $this->requestInfoFilter;
+    }
 }
diff --git a/app/code/Magento/Checkout/Model/Cart/RequestInfoFilter.php b/app/code/Magento/Checkout/Model/Cart/RequestInfoFilter.php
new file mode 100644
index 0000000000000000000000000000000000000000..10f3b81386b8febcee8f2b49ee4acd6242d1e5e8
--- /dev/null
+++ b/app/code/Magento/Checkout/Model/Cart/RequestInfoFilter.php
@@ -0,0 +1,44 @@
+<?php
+/**
+ *
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Checkout\Model\Cart;
+
+/**
+ * Class RequestInfoFilter used for filtering data from a request
+ */
+class RequestInfoFilter implements RequestInfoFilterInterface
+{
+    /**
+     * @var array $params
+     */
+    private $filterList;
+
+    /**
+     * @param array $filterList
+     */
+    public function __construct(
+        array $filterList = []
+    ) {
+        $this->filterList = $filterList;
+    }
+
+    /**
+     * Filters the data with values from filterList
+     *
+     * @param \Magento\Framework\DataObject $params
+     * @return $this
+     */
+    public function filter(\Magento\Framework\DataObject $params)
+    {
+        foreach ($this->filterList as $filterKey) {
+            /** @var string $filterKey */
+            if ($params->hasData($filterKey)) {
+                $params->unsetData($filterKey);
+            }
+        }
+        return $this;
+    }
+}
diff --git a/app/code/Magento/Checkout/Model/Cart/RequestInfoFilterComposite.php b/app/code/Magento/Checkout/Model/Cart/RequestInfoFilterComposite.php
new file mode 100644
index 0000000000000000000000000000000000000000..2ef24c0a5f28a198be28cbb4fc0ba212ebbd9097
--- /dev/null
+++ b/app/code/Magento/Checkout/Model/Cart/RequestInfoFilterComposite.php
@@ -0,0 +1,41 @@
+<?php
+/**
+ *
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Checkout\Model\Cart;
+
+/**
+ * Class RequestInfoFilterComposite
+ */
+class RequestInfoFilterComposite implements RequestInfoFilterInterface
+{
+    /**
+     * @var RequestInfoFilter[] $params
+     */
+    private $filters = [];
+
+    /**
+     * @param RequestInfoFilter[] $filters
+     */
+    public function __construct(
+        $filters = []
+    ) {
+        $this->filters = $filters;
+    }
+
+    /**
+     * Loops through all leafs of the composite and calls filter method
+     *
+     * @param \Magento\Framework\DataObject $params
+     * @return $this
+     */
+    public function filter(\Magento\Framework\DataObject $params)
+    {
+        foreach ($this->filters as $filter) {
+            $filter->filter($params);
+        }
+        return $this;
+    }
+}
diff --git a/app/code/Magento/Checkout/Model/Cart/RequestInfoFilterInterface.php b/app/code/Magento/Checkout/Model/Cart/RequestInfoFilterInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..4bd268f6c896e149bf042ccdbaaa85e411ec6153
--- /dev/null
+++ b/app/code/Magento/Checkout/Model/Cart/RequestInfoFilterInterface.php
@@ -0,0 +1,21 @@
+<?php
+/**
+ *
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Checkout\Model\Cart;
+
+/**
+ * Interface RequestInfoFilterInterface used by composite and leafs to implement filtering
+ */
+interface RequestInfoFilterInterface
+{
+    /**
+     * Filters the data object by an array of parameters
+     *
+     * @param \Magento\Framework\DataObject $params
+     * @return RequestInfoFilterInterface
+     */
+    public function filter(\Magento\Framework\DataObject $params);
+}
diff --git a/app/code/Magento/Checkout/Model/GuestPaymentInformationManagement.php b/app/code/Magento/Checkout/Model/GuestPaymentInformationManagement.php
index b07e90384c1647b51d59405022bb63a0b8e108d3..f2ad294d06cbe45d0b5d77ebe8658d546d27efd3 100644
--- a/app/code/Magento/Checkout/Model/GuestPaymentInformationManagement.php
+++ b/app/code/Magento/Checkout/Model/GuestPaymentInformationManagement.php
@@ -9,6 +9,9 @@ namespace Magento\Checkout\Model;
 use Magento\Quote\Api\CartRepositoryInterface;
 use Magento\Framework\Exception\CouldNotSaveException;
 
+/**
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ */
 class GuestPaymentInformationManagement implements \Magento\Checkout\Api\GuestPaymentInformationManagementInterface
 {
 
@@ -42,6 +45,11 @@ class GuestPaymentInformationManagement implements \Magento\Checkout\Api\GuestPa
      */
     protected $cartRepository;
 
+    /**
+     * @var \Psr\Log\LoggerInterface
+     */
+    private $logger;
+
     /**
      * @param \Magento\Quote\Api\GuestBillingAddressManagementInterface $billingAddressManagement
      * @param \Magento\Quote\Api\GuestPaymentMethodManagementInterface $paymentMethodManagement
@@ -79,7 +87,13 @@ class GuestPaymentInformationManagement implements \Magento\Checkout\Api\GuestPa
         $this->savePaymentInformation($cartId, $email, $paymentMethod, $billingAddress);
         try {
             $orderId = $this->cartManagement->placeOrder($cartId);
+        } catch (\Magento\Framework\Exception\LocalizedException $e) {
+            throw new CouldNotSaveException(
+                __($e->getMessage()),
+                $e
+            );
         } catch (\Exception $e) {
+            $this->getLogger()->critical($e);
             throw new CouldNotSaveException(
                 __('An error occurred on the server. Please try to place the order again.'),
                 $e
@@ -117,4 +131,18 @@ class GuestPaymentInformationManagement implements \Magento\Checkout\Api\GuestPa
         $quoteIdMask = $this->quoteIdMaskFactory->create()->load($cartId, 'masked_id');
         return $this->paymentInformationManagement->getPaymentInformation($quoteIdMask->getQuoteId());
     }
+
+    /**
+     * Get logger instance
+     *
+     * @return \Psr\Log\LoggerInterface
+     * @deprecated
+     */
+    private function getLogger()
+    {
+        if (!$this->logger) {
+            $this->logger = \Magento\Framework\App\ObjectManager::getInstance()->get(\Psr\Log\LoggerInterface::class);
+        }
+        return $this->logger;
+    }
 }
diff --git a/app/code/Magento/Checkout/Model/PaymentInformationManagement.php b/app/code/Magento/Checkout/Model/PaymentInformationManagement.php
index 140917dcdfeff22eaa73b9a1dc928d5d83f6ccd5..79e76feb4366190cb1d81389e7c54ac4f97cca9e 100644
--- a/app/code/Magento/Checkout/Model/PaymentInformationManagement.php
+++ b/app/code/Magento/Checkout/Model/PaymentInformationManagement.php
@@ -7,6 +7,9 @@ namespace Magento\Checkout\Model;
 
 use Magento\Framework\Exception\CouldNotSaveException;
 
+/**
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ */
 class PaymentInformationManagement implements \Magento\Checkout\Api\PaymentInformationManagementInterface
 {
     /**
@@ -34,6 +37,11 @@ class PaymentInformationManagement implements \Magento\Checkout\Api\PaymentInfor
      */
     protected $cartTotalsRepository;
 
+    /**
+     * @var \Psr\Log\LoggerInterface
+     */
+    private $logger;
+
     /**
      * @param \Magento\Quote\Api\BillingAddressManagementInterface $billingAddressManagement
      * @param \Magento\Quote\Api\PaymentMethodManagementInterface $paymentMethodManagement
@@ -67,7 +75,13 @@ class PaymentInformationManagement implements \Magento\Checkout\Api\PaymentInfor
         $this->savePaymentInformation($cartId, $paymentMethod, $billingAddress);
         try {
             $orderId = $this->cartManagement->placeOrder($cartId);
+        } catch (\Magento\Framework\Exception\LocalizedException $e) {
+            throw new CouldNotSaveException(
+                __($e->getMessage()),
+                $e
+            );
         } catch (\Exception $e) {
+            $this->getLogger()->critical($e);
             throw new CouldNotSaveException(
                 __('An error occurred on the server. Please try to place the order again.'),
                 $e
@@ -102,4 +116,18 @@ class PaymentInformationManagement implements \Magento\Checkout\Api\PaymentInfor
         $paymentDetails->setTotals($this->cartTotalsRepository->get($cartId));
         return $paymentDetails;
     }
+
+    /**
+     * Get logger instance
+     *
+     * @return \Psr\Log\LoggerInterface
+     * @deprecated
+     */
+    private function getLogger()
+    {
+        if (!$this->logger) {
+            $this->logger = \Magento\Framework\App\ObjectManager::getInstance()->get(\Psr\Log\LoggerInterface::class);
+        }
+        return $this->logger;
+    }
 }
diff --git a/app/code/Magento/Checkout/Test/Unit/Model/Cart/RequestInfoFilterCompositeTest.php b/app/code/Magento/Checkout/Test/Unit/Model/Cart/RequestInfoFilterCompositeTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..6c758cf4661fdab253a58b04f70969dc845e89d1
--- /dev/null
+++ b/app/code/Magento/Checkout/Test/Unit/Model/Cart/RequestInfoFilterCompositeTest.php
@@ -0,0 +1,73 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Checkout\Test\Unit\Model\Cart;
+
+/**
+ * Class RequestInfoFilterTest
+ */
+class RequestInfoFilterCompositeTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\Checkout\Model\Cart\RequestInfoFilterComposite
+     */
+    protected $model;
+
+    /**
+     * @var \Magento\Framework\TestFramework\Unit\Helper\ObjectManager
+     */
+    protected $objectManager;
+
+    /**
+     * Setup the test
+     */
+    protected function setUp()
+    {
+        $this->objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
+
+        $requestInfoFilterMock1  = $this->getMock(
+            \Magento\Checkout\Model\Cart\RequestInfoFilter::class,
+            ['filter'],
+            [],
+            '',
+            false
+        );
+        $requestInfoFilterMock2  = $this->getMock(
+            \Magento\Checkout\Model\Cart\RequestInfoFilter::class,
+            ['filter'],
+            [],
+            '',
+            false
+        );
+
+        $requestInfoFilterMock1->expects($this->atLeastOnce())
+            ->method('filter');
+        $requestInfoFilterMock2->expects($this->atLeastOnce())
+            ->method('filter');
+
+        $filterList = [ $requestInfoFilterMock1, $requestInfoFilterMock2];
+
+        $this->model = $this->objectManager->getObject(
+            \Magento\Checkout\Model\Cart\RequestInfoFilterComposite::class,
+            [
+                'filters' => $filterList,
+            ]
+        );
+    }
+
+    /**
+     * Test Filter method
+     */
+    public function testFilter()
+    {
+        /** @var \Magento\Framework\DataObject $params */
+        $params = $this->objectManager->getObject(
+            \Magento\Framework\DataObject::class,
+            ['data' => ['abc' => 1, 'efg' => 1, 'xyz' => 1]]
+        );
+        $result = $this->model->filter($params);
+        $this->assertEquals($this->model, $result);
+    }
+}
diff --git a/app/code/Magento/Checkout/Test/Unit/Model/Cart/RequestInfoFilterTest.php b/app/code/Magento/Checkout/Test/Unit/Model/Cart/RequestInfoFilterTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..cd6ca330da1b2d7252b8911f1820d7bc217d3561
--- /dev/null
+++ b/app/code/Magento/Checkout/Test/Unit/Model/Cart/RequestInfoFilterTest.php
@@ -0,0 +1,52 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Checkout\Test\Unit\Model\Cart;
+
+/**
+ * Class RequestInfoFilterTest
+ */
+class RequestInfoFilterTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\Checkout\Model\Cart\RequestInfoFilter
+     */
+    protected $model;
+
+    /**
+     * @var \Magento\Framework\TestFramework\Unit\Helper\ObjectManager
+     */
+    protected $objectManager;
+
+    /**
+     * Setup the test
+     */
+    protected function setUp()
+    {
+        $this->objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
+
+        $this->model = $this->objectManager->getObject(
+            \Magento\Checkout\Model\Cart\RequestInfoFilter::class,
+            [
+                'filterList' => ['efg', 'xyz'],
+            ]
+        );
+    }
+
+    /**
+     * Test Filter method
+     */
+    public function testFilter()
+    {
+        /** @var \Magento\Framework\DataObject $params */
+        $params = $this->objectManager->getObject(
+            \Magento\Framework\DataObject::class,
+            ['data' => ['abc' => 1, 'efg' => 1, 'xyz' => 1]]
+        );
+        $result = $this->model->filter($params);
+        $this->assertEquals($this->model, $result);
+        $this->assertEquals(['abc' => 1], $params->convertToArray());
+    }
+}
diff --git a/app/code/Magento/Checkout/Test/Unit/Model/CartTest.php b/app/code/Magento/Checkout/Test/Unit/Model/CartTest.php
index 199e6692e68d1777c382c8125391cac88326a549..9984fe12d3792e95f0b29d0d2c71ff36b37a5897 100644
--- a/app/code/Magento/Checkout/Test/Unit/Model/CartTest.php
+++ b/app/code/Magento/Checkout/Test/Unit/Model/CartTest.php
@@ -29,7 +29,7 @@ class CartTest extends \PHPUnit_Framework_TestCase
      */
     protected $customerSessionMock;
 
-    /** @var \Magento\CatalogInventory\Api\StockItem|\PHPUnit_Framework_MockObject_MockObject */
+    /** @var \Magento\CatalogInventory\Api\Data\StockItemInterface|\PHPUnit_Framework_MockObject_MockObject */
     protected $stockItemMock;
 
     /**
@@ -57,16 +57,39 @@ class CartTest extends \PHPUnit_Framework_TestCase
      */
     protected $stockState;
 
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    private $storeManagerMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    private $storeMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    private $productRepository;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    private $requestInfoFilterMock;
+
     protected function setUp()
     {
         $this->checkoutSessionMock = $this->getMock(\Magento\Checkout\Model\Session::class, [], [], '', false);
         $this->customerSessionMock = $this->getMock(\Magento\Customer\Model\Session::class, [], [], '', false);
         $this->scopeConfigMock = $this->getMock(\Magento\Framework\App\Config\ScopeConfigInterface::class);
+        $this->quoteMock = $this->getMock(\Magento\Quote\Model\Quote::class, [], [], '', false);
+        $this->eventManagerMock = $this->getMock(\Magento\Framework\Event\ManagerInterface::class);
+        $this->storeManagerMock = $this->getMock(\Magento\Store\Model\StoreManagerInterface::class);
+        $this->productRepository = $this->getMock(\Magento\Catalog\Api\ProductRepositoryInterface::class);
         $this->stockRegistry = $this->getMockBuilder(\Magento\CatalogInventory\Model\StockRegistry::class)
             ->disableOriginalConstructor()
             ->setMethods(['getStockItem', '__wakeup'])
             ->getMock();
-
         $this->stockItemMock = $this->getMock(
             \Magento\CatalogInventory\Model\Stock\Item::class,
             ['getMinSaleQty', '__wakeup'],
@@ -74,7 +97,6 @@ class CartTest extends \PHPUnit_Framework_TestCase
             '',
             false
         );
-
         $this->stockState = $this->getMock(
             \Magento\CatalogInventory\Model\StockState::class,
             ['suggestQty', '__wakeup'],
@@ -82,12 +104,22 @@ class CartTest extends \PHPUnit_Framework_TestCase
             '',
             false
         );
+        $this->storeMock =
+            $this->getMock(\Magento\Store\Model\Store::class, ['getWebsiteId', 'getId', '__wakeup'], [], '', false);
+        $this->requestInfoFilterMock = $this->getMock(\Magento\Checkout\Model\Cart\RequestInfoFilterInterface::class);
 
         $this->stockRegistry->expects($this->any())
             ->method('getStockItem')
             ->will($this->returnValue($this->stockItemMock));
-        $this->quoteMock = $this->getMock(\Magento\Quote\Model\Quote::class, [], [], '', false);
-        $this->eventManagerMock = $this->getMock(\Magento\Framework\Event\ManagerInterface::class);
+        $this->storeMock->expects($this->any())
+            ->method('getWebsiteId')
+            ->will($this->returnValue(10));
+        $this->storeMock->expects($this->any())
+            ->method('getId')
+            ->will($this->returnValue(10));
+        $this->storeManagerMock->expects($this->any())
+            ->method('getStore')
+            ->will($this->returnValue($this->storeMock));
 
         $this->objectManagerHelper = new ObjectManagerHelper($this);
         $this->cart = $this->objectManagerHelper->getObject(
@@ -98,9 +130,14 @@ class CartTest extends \PHPUnit_Framework_TestCase
                 'stockRegistry' => $this->stockRegistry,
                 'stockState' => $this->stockState,
                 'customerSession' => $this->customerSessionMock,
-                'eventManager' => $this->eventManagerMock
+                'eventManager' => $this->eventManagerMock,
+                'storeManager' => $this->storeManagerMock,
+                'productRepository' => $this->productRepository
             ]
         );
+
+        $this->objectManagerHelper
+            ->setBackwardCompatibleProperty($this->cart, 'requestInfoFilter', $this->requestInfoFilterMock);
     }
 
     public function testSuggestItemsQty()
@@ -169,10 +206,17 @@ class CartTest extends \PHPUnit_Framework_TestCase
      */
     public function prepareQuoteItemMock($itemId)
     {
-        $store = $this->getMock(\Magento\Store\Model\Store::class, ['getWebsiteId', '__wakeup'], [], '', false);
+        $store = $this->getMock(\Magento\Store\Model\Store::class, ['getId', '__wakeup'], [], '', false);
         $store->expects($this->any())
             ->method('getWebsiteId')
             ->will($this->returnValue(10));
+        $store->expects($this->any())
+            ->method('getId')
+            ->will($this->returnValue(10));
+        $this->storeManagerMock->expects($this->any())
+            ->method('getStore')
+            ->will($this->returnValue($store));
+
         switch ($itemId) {
             case 2:
                 $product = $this->getMock(
@@ -255,4 +299,162 @@ class CartTest extends \PHPUnit_Framework_TestCase
             ['useQty' => false]
         ];
     }
+
+    /**
+     * Test successful scenarios for AddProduct
+     *
+     * @param int|\Magento\Catalog\Model\Product $productInfo
+     * @param \Magento\Framework\DataObject|int|array $requestInfo
+     * @dataProvider addProductDataProvider
+     */
+    public function testAddProduct($productInfo, $requestInfo)
+    {
+        $product = $this->getMock(
+            \Magento\Catalog\Model\Product::class,
+            ['getStore', 'getWebsiteIds', 'getProductUrl', 'getId', '__wakeup'],
+            [],
+            '',
+            false
+        );
+        $product->expects($this->any())
+            ->method('getId')
+            ->will($this->returnValue(4));
+        $product->expects($this->once())
+            ->method('getStore')
+            ->will($this->returnValue($this->storeMock));
+        $product->expects($this->any())
+            ->method('getWebsiteIds')
+            ->will($this->returnValue([10]));
+        $product->expects($this->any())
+            ->method('getProductUrl')
+            ->will($this->returnValue('url'));
+        $this->productRepository->expects($this->any())
+            ->method('getById')
+            ->will($this->returnValue($product));
+        $this->quoteMock->expects($this->once())
+        ->method('addProduct')
+        ->will($this->returnValue(1));
+        $this->checkoutSessionMock->expects($this->once())
+            ->method('getQuote')
+            ->will($this->returnValue($this->quoteMock));
+
+        $this->eventManagerMock->expects($this->at(0))->method('dispatch')->with(
+            'checkout_cart_product_add_after',
+            ['quote_item' => 1, 'product' => $product]
+        );
+
+        if (!$productInfo) {
+            $productInfo = $product;
+        }
+        $result = $this->cart->addProduct($productInfo, $requestInfo);
+        $this->assertSame($this->cart, $result);
+    }
+
+    /**
+     * Test exception on adding product for AddProduct
+     *
+     * @throws \Magento\Framework\Exception\LocalizedException
+     */
+    public function testAddProductException()
+    {
+        $product = $this->getMock(
+            \Magento\Catalog\Model\Product::class,
+            ['getStore', 'getWebsiteIds', 'getProductUrl', 'getId', '__wakeup'],
+            [],
+            '',
+            false
+        );
+        $product->expects($this->any())
+            ->method('getId')
+            ->will($this->returnValue(4));
+        $product->expects($this->once())
+            ->method('getStore')
+            ->will($this->returnValue($this->storeMock));
+        $product->expects($this->any())
+            ->method('getWebsiteIds')
+            ->will($this->returnValue([10]));
+        $product->expects($this->any())
+            ->method('getProductUrl')
+            ->will($this->returnValue('url'));
+        $this->productRepository->expects($this->any())
+            ->method('getById')
+            ->will($this->returnValue($product));
+        $this->quoteMock->expects($this->once())
+            ->method('addProduct')
+            ->will($this->returnValue('error'));
+        $this->checkoutSessionMock->expects($this->once())
+            ->method('getQuote')
+            ->will($this->returnValue($this->quoteMock));
+
+        $this->eventManagerMock->expects($this->never())->method('dispatch')->with(
+            'checkout_cart_product_add_after',
+            ['quote_item' => 1, 'product' => $product]
+        );
+        $this->setExpectedException(\Magento\Framework\Exception\LocalizedException::class);
+        $this->cart->addProduct(4, 4);
+    }
+
+    /**
+     * Test bad parameters on adding product for AddProduct
+     *
+     * @throws \Magento\Framework\Exception\LocalizedException
+     */
+    public function testAddProductExceptionBadParams()
+    {
+        $product = $this->getMock(
+            \Magento\Catalog\Model\Product::class,
+            ['getWebsiteIds', 'getId', '__wakeup'],
+            [],
+            '',
+            false
+        );
+        $product->expects($this->any())
+            ->method('getId')
+            ->will($this->returnValue(4));
+        $product->expects($this->any())
+            ->method('getWebsiteIds')
+            ->will($this->returnValue([10]));
+        $this->productRepository->expects($this->any())
+            ->method('getById')
+            ->will($this->returnValue($product));
+
+        $this->eventManagerMock->expects($this->never())->method('dispatch')->with(
+            'checkout_cart_product_add_after',
+            ['quote_item' => 1, 'product' => $product]
+        );
+        $this->setExpectedException(\Magento\Framework\Exception\LocalizedException::class);
+        $this->cart->addProduct(4, 'bad');
+    }
+
+    /**
+     * Data provider for testAddProduct
+     *
+     * @return array
+     */
+    public function addProductDataProvider()
+    {
+        $obj = new ObjectManagerHelper($this) ;
+        $data = ['qty' => 5.5, 'sku' => 'prod'];
+
+        return [
+            'prod_int_info_int' => [4, 4],
+            'prod_int_info_array' => [ 4, $data],
+            'prod_int_info_object' => [
+                4,
+                $obj->getObject(
+                    \Magento\Framework\DataObject::class,
+                    ['data' => $data]
+                )
+            ],
+            'prod_obj_info_int' => [null, 4],
+            'prod_obj_info_array' => [ null, $data],
+            'prod_obj_info_object' => [
+                null,
+                $obj->getObject(
+                    \Magento\Framework\DataObject::class,
+                    ['data' => $data]
+                )
+            ]
+        ];
+    }
 }
diff --git a/app/code/Magento/Checkout/Test/Unit/Model/GuestPaymentInformationManagementTest.php b/app/code/Magento/Checkout/Test/Unit/Model/GuestPaymentInformationManagementTest.php
index 093bbf4a5accc66bdd5c00fa4f30660409e09f79..76cbafb48ebd47e4fd83d01ef1361ef29df2f3be 100644
--- a/app/code/Magento/Checkout/Test/Unit/Model/GuestPaymentInformationManagementTest.php
+++ b/app/code/Magento/Checkout/Test/Unit/Model/GuestPaymentInformationManagementTest.php
@@ -42,6 +42,11 @@ class GuestPaymentInformationManagementTest extends \PHPUnit_Framework_TestCase
      */
     protected $model;
 
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    private $loggerMock;
+
     protected function setUp()
     {
         $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
@@ -61,6 +66,7 @@ class GuestPaymentInformationManagementTest extends \PHPUnit_Framework_TestCase
             '',
             false
         );
+        $this->loggerMock = $this->getMock(\Psr\Log\LoggerInterface::class);
         $this->model = $objectManager->getObject(
             \Magento\Checkout\Model\GuestPaymentInformationManagement::class,
             [
@@ -71,6 +77,7 @@ class GuestPaymentInformationManagementTest extends \PHPUnit_Framework_TestCase
                 'quoteIdMaskFactory' => $this->quoteIdMaskFactoryMock
             ]
         );
+        $objectManager->setBackwardCompatibleProperty($this->model, 'logger', $this->loggerMock);
     }
 
     public function testSavePaymentInformationAndPlaceOrder()
@@ -112,7 +119,7 @@ class GuestPaymentInformationManagementTest extends \PHPUnit_Framework_TestCase
             ->method('assign')
             ->with($cartId, $billingAddressMock);
         $this->paymentMethodManagementMock->expects($this->once())->method('set')->with($cartId, $paymentMock);
-        $exception = new CouldNotSaveException(__('DB exception'));
+        $exception = new \Exception(__('DB exception'));
         $this->cartManagementMock->expects($this->once())->method('placeOrder')->willThrowException($exception);
 
         $this->model->savePaymentInformationAndPlaceOrder($cartId, $email, $paymentMock, $billingAddressMock);
@@ -161,4 +168,29 @@ class GuestPaymentInformationManagementTest extends \PHPUnit_Framework_TestCase
         $billingAddressMock->expects($this->once())->method('setEmail')->with($email);
         $this->assertTrue($this->model->savePaymentInformation($cartId, $email, $paymentMock));
     }
+
+    /**
+     * @expectedExceptionMessage DB exception
+     * @expectedException \Magento\Framework\Exception\CouldNotSaveException
+     */
+    public function testSavePaymentInformationAndPlaceOrderWithLocolizedException()
+    {
+        $cartId = 100;
+        $email = 'email@magento.com';
+        $paymentMock = $this->getMock(\Magento\Quote\Api\Data\PaymentInterface::class);
+        $billingAddressMock = $this->getMock(\Magento\Quote\Api\Data\AddressInterface::class);
+
+        $billingAddressMock->expects($this->once())->method('setEmail')->with($email)->willReturnSelf();
+
+        $this->billingAddressManagementMock->expects($this->once())
+            ->method('assign')
+            ->with($cartId, $billingAddressMock);
+        $this->paymentMethodManagementMock->expects($this->once())->method('set')->with($cartId, $paymentMock);
+        $phrase = new \Magento\Framework\Phrase(__('DB exception'));
+        $exception = new \Magento\Framework\Exception\LocalizedException($phrase);
+        $this->loggerMock->expects($this->never())->method('critical');
+        $this->cartManagementMock->expects($this->once())->method('placeOrder')->willThrowException($exception);
+
+        $this->model->savePaymentInformationAndPlaceOrder($cartId, $email, $paymentMock, $billingAddressMock);
+    }
 }
diff --git a/app/code/Magento/Checkout/Test/Unit/Model/PaymentInformationManagementTest.php b/app/code/Magento/Checkout/Test/Unit/Model/PaymentInformationManagementTest.php
index 496054b2c7b1e0a0b9e60c119a8c25d322832a26..8da67a1fcb71512dd218a2c62d51b7922bb36c25 100644
--- a/app/code/Magento/Checkout/Test/Unit/Model/PaymentInformationManagementTest.php
+++ b/app/code/Magento/Checkout/Test/Unit/Model/PaymentInformationManagementTest.php
@@ -29,6 +29,11 @@ class PaymentInformationManagementTest extends \PHPUnit_Framework_TestCase
      */
     protected $model;
 
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    private $loggerMock;
+
     protected function setUp()
     {
         $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
@@ -40,6 +45,8 @@ class PaymentInformationManagementTest extends \PHPUnit_Framework_TestCase
         );
         $this->cartManagementMock = $this->getMock(\Magento\Quote\Api\CartManagementInterface::class);
 
+        $this->loggerMock = $this->getMock(\Psr\Log\LoggerInterface::class);
+
         $this->model = $objectManager->getObject(
             \Magento\Checkout\Model\PaymentInformationManagement::class,
             [
@@ -48,6 +55,7 @@ class PaymentInformationManagementTest extends \PHPUnit_Framework_TestCase
                 'cartManagement' => $this->cartManagementMock
             ]
         );
+        $objectManager->setBackwardCompatibleProperty($this->model, 'logger', $this->loggerMock);
     }
 
     public function testSavePaymentInformationAndPlaceOrder()
@@ -83,7 +91,8 @@ class PaymentInformationManagementTest extends \PHPUnit_Framework_TestCase
             ->method('assign')
             ->with($cartId, $billingAddressMock);
         $this->paymentMethodManagementMock->expects($this->once())->method('set')->with($cartId, $paymentMock);
-        $exception = new CouldNotSaveException(__('DB exception'));
+        $exception = new \Exception(__('DB exception'));
+        $this->loggerMock->expects($this->once())->method('critical');
         $this->cartManagementMock->expects($this->once())->method('placeOrder')->willThrowException($exception);
 
         $this->model->savePaymentInformationAndPlaceOrder($cartId, $paymentMock, $billingAddressMock);
@@ -129,4 +138,26 @@ class PaymentInformationManagementTest extends \PHPUnit_Framework_TestCase
 
         $this->assertTrue($this->model->savePaymentInformation($cartId, $paymentMock));
     }
+
+    /**
+     * @expectedExceptionMessage DB exception
+     * @expectedException \Magento\Framework\Exception\CouldNotSaveException
+     */
+    public function testSavePaymentInformationAndPlaceOrderWithLocolizedException()
+    {
+        $cartId = 100;
+        $paymentMock = $this->getMock(\Magento\Quote\Api\Data\PaymentInterface::class);
+        $billingAddressMock = $this->getMock(\Magento\Quote\Api\Data\AddressInterface::class);
+
+        $this->billingAddressManagementMock->expects($this->once())
+            ->method('assign')
+            ->with($cartId, $billingAddressMock);
+        $this->paymentMethodManagementMock->expects($this->once())->method('set')->with($cartId, $paymentMock);
+        $phrase = new \Magento\Framework\Phrase(__('DB exception'));
+        $exception = new \Magento\Framework\Exception\LocalizedException($phrase);
+        $this->loggerMock->expects($this->never())->method('critical');
+        $this->cartManagementMock->expects($this->once())->method('placeOrder')->willThrowException($exception);
+
+        $this->model->savePaymentInformationAndPlaceOrder($cartId, $paymentMock, $billingAddressMock);
+    }
 }
diff --git a/app/code/Magento/Checkout/composer.json b/app/code/Magento/Checkout/composer.json
index 5545e409b65abb3fb381e593c4ec34298dba6b80..60919d9fa2ca949817641c43328ad3be88edc8be 100644
--- a/app/code/Magento/Checkout/composer.json
+++ b/app/code/Magento/Checkout/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-checkout",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-store": "100.2.*",
         "magento/module-sales": "100.2.*",
         "magento/module-backend": "100.2.*",
diff --git a/app/code/Magento/Checkout/etc/di.xml b/app/code/Magento/Checkout/etc/di.xml
index c55598fdff5e792dd7404967d12f9fcc5e78e828..a2243b33a04edc0af4dc71ed79b802eac68f4cc2 100644
--- a/app/code/Magento/Checkout/etc/di.xml
+++ b/app/code/Magento/Checkout/etc/di.xml
@@ -26,4 +26,20 @@
     <preference for="Magento\Checkout\Api\GuestTotalsInformationManagementInterface" type="Magento\Checkout\Model\GuestTotalsInformationManagement" />
     <preference for="Magento\Checkout\Api\TotalsInformationManagementInterface" type="Magento\Checkout\Model\TotalsInformationManagement" />
     <preference for="Magento\Checkout\Api\AgreementsValidatorInterface" type="Magento\Checkout\Model\AgreementsValidator" />
+    <preference for="Magento\Checkout\Model\Cart\RequestInfoFilterInterface"
+                type="Magento\Checkout\Model\Cart\RequestInfoFilterComposite"/>
+    <type name="Magento\Checkout\Model\Cart\RequestInfoFilter">
+        <arguments>
+            <argument name="filterList" xsi:type="array">
+                <item name="form_key" xsi:type="string">form_key</item>
+            </argument>
+        </arguments>
+    </type>
+    <type name="Magento\Checkout\Model\Cart\RequestInfoFilterComposite">
+        <arguments>
+            <argument name="filters" xsi:type="array">
+                <item name="filter" xsi:type="object">Magento\Checkout\Model\Cart\RequestInfoFilter</item>
+            </argument>
+        </arguments>
+    </type>
 </config>
diff --git a/app/code/Magento/Checkout/etc/frontend/di.xml b/app/code/Magento/Checkout/etc/frontend/di.xml
index bccf81bcb6ee81c97bd6bef98d3c5f08ec33b9cc..6fb9058c3b7681c8905a40a5eace5d88d8566b6f 100644
--- a/app/code/Magento/Checkout/etc/frontend/di.xml
+++ b/app/code/Magento/Checkout/etc/frontend/di.xml
@@ -72,4 +72,12 @@
             </argument>
         </arguments>
     </type>
+    <type name="Magento\Checkout\Model\Cart\RequestInfoFilter">
+        <arguments>
+            <argument name="filterList" xsi:type="array">
+                <item name="form_key" xsi:type="string">form_key</item>
+                <item name="custom_price" xsi:type="string">custom_price</item>
+            </argument>
+        </arguments>
+    </type>
 </config>
diff --git a/app/code/Magento/Checkout/view/frontend/web/js/model/address-converter.js b/app/code/Magento/Checkout/view/frontend/web/js/model/address-converter.js
index 2d6fa460ef66d26d106ad9417ffdf8d3548a3d00..3ec34cd96574bc90e5b0f8bd3bf552a877444ab0 100644
--- a/app/code/Magento/Checkout/view/frontend/web/js/model/address-converter.js
+++ b/app/code/Magento/Checkout/view/frontend/web/js/model/address-converter.js
@@ -44,6 +44,13 @@ define(
                         addressData.region.region_code = region['code'];
                         addressData.region.region = region['name'];
                     }
+                } else if (
+                    !addressData.region_id
+                    && countryData()[addressData.country_id]
+                    && countryData()[addressData.country_id]['regions']
+                ) {
+                    addressData.region.region_code = '';
+                    addressData.region.region = '';
                 }
                 delete addressData.region_id;
 
diff --git a/app/code/Magento/Checkout/view/frontend/web/js/model/full-screen-loader.js b/app/code/Magento/Checkout/view/frontend/web/js/model/full-screen-loader.js
index ca9d6493a16740f1a43555d84459df4403bd3c88..9005015d2460e12c5462551aecce97f1bd31c003 100644
--- a/app/code/Magento/Checkout/view/frontend/web/js/model/full-screen-loader.js
+++ b/app/code/Magento/Checkout/view/frontend/web/js/model/full-screen-loader.js
@@ -24,7 +24,7 @@ define([
             /**
              * Stop full page loader action
              *
-             * @param {Boolean} forceStop
+             * @param {Boolean} [forceStop]
              */
             stopLoader: function (forceStop) {
                 var $elem = $(containerId),
diff --git a/app/code/Magento/Checkout/view/frontend/web/js/model/new-customer-address.js b/app/code/Magento/Checkout/view/frontend/web/js/model/new-customer-address.js
index bee4480b0dfb1c9db669d53f5091bb1d3564237a..9a3685b212b435e8c03adb7be2cd7a182e591b87 100644
--- a/app/code/Magento/Checkout/view/frontend/web/js/model/new-customer-address.js
+++ b/app/code/Magento/Checkout/view/frontend/web/js/model/new-customer-address.js
@@ -22,7 +22,7 @@ define([], function () {
         return {
             email: addressData.email,
             countryId: addressData['country_id'] || addressData.countryId || window.checkoutConfig.defaultCountryId,
-            regionId: regionId,
+            regionId: regionId || addressData.regionId,
             regionCode: (addressData.region) ? addressData.region.region_code : null,
             region: (addressData.region) ? addressData.region.region : null,
             customerId: addressData.customer_id,
@@ -30,7 +30,7 @@ define([], function () {
             company: addressData.company,
             telephone: addressData.telephone,
             fax: addressData.fax,
-            postcode: addressData.postcode ? addressData.postcode : window.checkoutConfig.defaultPostcode,
+            postcode: addressData.postcode ? addressData.postcode : window.checkoutConfig.defaultPostcode || undefined,
             city: addressData.city,
             firstname: addressData.firstname,
             lastname: addressData.lastname,
diff --git a/app/code/Magento/Checkout/view/frontend/web/js/model/payment/method-group.js b/app/code/Magento/Checkout/view/frontend/web/js/model/payment/method-group.js
new file mode 100644
index 0000000000000000000000000000000000000000..4236a215d73596b918d782a2773698e5fa25234f
--- /dev/null
+++ b/app/code/Magento/Checkout/view/frontend/web/js/model/payment/method-group.js
@@ -0,0 +1,31 @@
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+define([
+        'uiElement',
+        'mage/translate'
+], function (Element, $t) {
+    'use strict';
+
+    var DEFAULT_GROUP_ALIAS = 'default';
+
+    return Element.extend({
+        defaults: {
+            alias: DEFAULT_GROUP_ALIAS,
+            title: $t('Payment Method'),
+            sortOrder: 100,
+            displayArea: 'payment-methods-items-${ $.alias }'
+        },
+
+        /**
+         * Checks if group instance is default
+         *
+         * @returns {Boolean}
+         */
+        isDefault: function () {
+            return this.alias === DEFAULT_GROUP_ALIAS;
+        }
+    });
+});
diff --git a/app/code/Magento/Checkout/view/frontend/web/js/model/shipping-rates-validator.js b/app/code/Magento/Checkout/view/frontend/web/js/model/shipping-rates-validator.js
index 420d50b83478a91ab38b6a333a681f119b6db49e..c49960ecfb91dec735239c8bc1cc88f7ffebfab0 100644
--- a/app/code/Magento/Checkout/view/frontend/web/js/model/shipping-rates-validator.js
+++ b/app/code/Magento/Checkout/view/frontend/web/js/model/shipping-rates-validator.js
@@ -176,7 +176,7 @@ define(
                     address;
 
                 if (this.validateAddressData(addressFlat)) {
-                    addressFlat = $.extend(true, {}, quote.shippingAddress(), addressFlat);
+                    addressFlat = uiRegistry.get('checkoutProvider').shippingAddress;
                     address = addressConverter.formAddressDataToQuoteAddress(addressFlat);
                     selectShippingAddress(address);
                 }
diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/payment/list.js b/app/code/Magento/Checkout/view/frontend/web/js/view/payment/list.js
index 18f6b8479c229326e28e9c02157d6a39e34625ee..918d305ee031b1d2c96eb6b246a765a16f6c8446 100644
--- a/app/code/Magento/Checkout/view/frontend/web/js/view/payment/list.js
+++ b/app/code/Magento/Checkout/view/frontend/web/js/view/payment/list.js
@@ -10,14 +10,22 @@ define([
     'Magento_Checkout/js/model/payment/method-list',
     'Magento_Checkout/js/model/payment/renderer-list',
     'uiLayout',
-    'Magento_Checkout/js/model/checkout-data-resolver'
-], function (_, ko, utils, Component, paymentMethods, rendererList, layout, checkoutDataResolver) {
+    'Magento_Checkout/js/model/checkout-data-resolver',
+    'mage/translate',
+    'uiRegistry'
+], function (_, ko, utils, Component, paymentMethods, rendererList, layout, checkoutDataResolver, $t, registry) {
     'use strict';
 
     return Component.extend({
         defaults: {
             template: 'Magento_Checkout/payment-methods/list',
-            visible: paymentMethods().length > 0
+            visible: paymentMethods().length > 0,
+            configDefaultGroup: {
+                name: 'methodGroup',
+                component: 'Magento_Checkout/js/model/payment/method-group'
+            },
+            paymentGroupsList: [],
+            defaultGroupTitle: $t('Select a new payment method')
         },
 
         /**
@@ -26,7 +34,7 @@ define([
          * @returns {Component} Chainable.
          */
         initialize: function () {
-            this._super().initChildren();
+            this._super().initDefaulGroup().initChildren();
             paymentMethods.subscribe(
                 function (changes) {
                     checkoutDataResolver.resolvePaymentMethod();
@@ -47,6 +55,27 @@ define([
             return this;
         },
 
+        /** @inheritdoc */
+        initObservable: function () {
+            this._super().
+                observe(['paymentGroupsList']);
+
+            return this;
+        },
+
+        /**
+         * Creates default group
+         *
+         * @returns {Component} Chainable.
+         */
+        initDefaulGroup: function() {
+            layout([
+                this.configDefaultGroup
+            ]);
+
+            return this;
+        },
+
         /**
          * Create renders for child payment methods.
          *
@@ -77,7 +106,7 @@ define([
             rendererTemplate = {
                 parent: '${ $.$data.parentName }',
                 name: '${ $.$data.name }',
-                displayArea: 'payment-method-items',
+                displayArea: payment.displayArea,
                 component: payment.component
             };
             rendererComponent = utils.template(rendererTemplate, templateData);
@@ -95,49 +124,105 @@ define([
          * @param {Object} paymentMethodData
          */
         createRenderer: function (paymentMethodData) {
-            var isRendererForMethod = false;
+            var isRendererForMethod = false,
+                currentGroup;
+
+            registry.get(this.configDefaultGroup.name, function (defaultGroup) {
+                _.each(rendererList(), function (renderer) {
 
-            _.find(rendererList(), function (renderer) {
+                    if (renderer.hasOwnProperty('typeComparatorCallback') &&
+                        typeof renderer.typeComparatorCallback == 'function'
+                    ) {
+                        isRendererForMethod = renderer.typeComparatorCallback(renderer.type, paymentMethodData.method);
+                    } else {
+                        isRendererForMethod = renderer.type === paymentMethodData.method;
+                    }
 
-                if (renderer.hasOwnProperty('typeComparatorCallback') &&
-                    typeof renderer.typeComparatorCallback == 'function'
-                ) {
-                    isRendererForMethod = renderer.typeComparatorCallback(renderer.type, paymentMethodData.method);
-                } else {
-                    isRendererForMethod = renderer.type === paymentMethodData.method;
-                }
+                    if (isRendererForMethod) {
+                        currentGroup = renderer.group ? renderer.group : defaultGroup;
 
-                if (isRendererForMethod) {
-                    layout(
-                        [
+                        this.collectPaymentGroups(currentGroup);
+
+                        layout([
                             this.createComponent(
                                 {
                                     config: renderer.config,
                                     component: renderer.component,
                                     name: renderer.type,
                                     method: paymentMethodData.method,
-                                    item: paymentMethodData
+                                    item: paymentMethodData,
+                                    displayArea: currentGroup.displayArea
                                 }
-                            )
-                        ]
-                    );
-                }
+                            )]);
+                    }
+                }.bind(this));
             }.bind(this));
         },
 
+        /**
+         * Collects unique groups of available payment methods
+         *
+         * @param {Object} group
+         */
+        collectPaymentGroups: function (group) {
+            var groupsList = this.paymentGroupsList(),
+                isGroupExists = _.some(groupsList, function (existsGroup) {
+                    return existsGroup.alias === group.alias;
+                });
+
+            if (!isGroupExists) {
+                groupsList.push(group);
+                groupsList = _.sortBy(groupsList, function (existsGroup) {
+                    return existsGroup.sortOrder;
+                });
+                this.paymentGroupsList(groupsList);
+            }
+        },
+
+        /**
+         * Returns payment group title
+         *
+         * @param {Object} group
+         * @returns {String}
+         */
+        getGroupTitle: function (group) {
+            var title = group().title;
+
+            if (group().isDefault() && this.paymentGroupsList().length > 1) {
+                title = this.defaultGroupTitle;
+            }
+
+            return title + ':';
+        },
+
+        /**
+         * Checks if at least one payment method available
+         *
+         * @returns {String}
+         */
+        isPaymentMethodsAvailable: function () {
+            return _.some(this.paymentGroupsList(), function (group) {
+                return this.getRegion(group.displayArea)().length;
+            }, this);
+        },
+
         /**
          * Remove view renderer.
          *
          * @param {String} paymentMethodCode
          */
         removeRenderer: function (paymentMethodCode) {
-            var items = this.getRegion('payment-method-items');
+            var items;
+
+            _.each(this.paymentGroupsList(), function (group) {
+                items = this.getRegion(group.displayArea);
 
-            _.find(items(), function (value) {
-                if (value.item.method.indexOf(paymentMethodCode) === 0) {
-                    value.disposeSubscriptions();
-                    value.destroy();
-                }
+                _.find(items(), function (value) {
+                    if (value.item.method.indexOf(paymentMethodCode) === 0) {
+                        value.disposeSubscriptions();
+                        value.destroy();
+                    }
+                });
             }, this);
         }
     });
diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/shipping.js b/app/code/Magento/Checkout/view/frontend/web/js/view/shipping.js
index ddb62ceb37b37ef6bc7735c78f81367c5c6d4343..8910e41731d11a9be99bf1777dc13e3550781976 100644
--- a/app/code/Magento/Checkout/view/frontend/web/js/view/shipping.js
+++ b/app/code/Magento/Checkout/view/frontend/web/js/view/shipping.js
@@ -179,7 +179,7 @@ define(
                     newShippingAddress;
 
                 this.source.set('params.invalid', false);
-                this.source.trigger('shippingAddress.data.validate');
+                this.triggerShippingDataValidateEvent();
 
                 if (!this.source.get('params.invalid')) {
                     addressData = this.source.get('shippingAddress');
@@ -254,12 +254,7 @@ define(
 
                 if (this.isFormInline) {
                     this.source.set('params.invalid', false);
-                    this.source.trigger('shippingAddress.data.validate');
-
-                    if (this.source.get('shippingAddress.custom_attributes')) {
-                        this.source.trigger('shippingAddress.custom_attributes.data.validate');
-                    }
-
+                    this.triggerShippingDataValidateEvent();
                     if (emailValidationResult &&
                         this.source.get('params.invalid') ||
                         !quote.shippingMethod().method_code ||
@@ -304,6 +299,18 @@ define(
                 }
 
                 return true;
+            },
+
+            /**
+             * Trigger Shipping data Validate Event.
+             *
+             * @return {void}
+             */
+            triggerShippingDataValidateEvent: function () {
+                this.source.trigger('shippingAddress.data.validate');
+                if (this.source.get('shippingAddress.custom_attributes')) {
+                    this.source.trigger('shippingAddress.custom_attributes.data.validate');
+                }
             }
         });
     }
diff --git a/app/code/Magento/Checkout/view/frontend/web/template/billing-address/details.html b/app/code/Magento/Checkout/view/frontend/web/template/billing-address/details.html
index f45115181fe4c628c88d3b5a26129629c21415b5..da625c51d4b7734ccc4808fd9161502e15acf1a9 100644
--- a/app/code/Magento/Checkout/view/frontend/web/template/billing-address/details.html
+++ b/app/code/Magento/Checkout/view/frontend/web/template/billing-address/details.html
@@ -13,6 +13,11 @@
     <!-- ko if: (currentBillingAddress().telephone) -->
     <a data-bind="text: currentBillingAddress().telephone, attr: {'href': 'tel:' + currentBillingAddress().telephone}"></a>
     <!-- /ko --><br/>
+    <!-- ko foreach: { data: currentBillingAddress().customAttributes, as: 'element' } -->
+        <!-- ko foreach: { data: Object.keys(element), as: 'attribute' } -->
+            <!-- ko text: element[attribute].value --><!-- /ko -->
+        <!-- /ko -->
+    <!-- /ko -->
     <button type="button"
             class="action action-edit-address"
             data-bind="visible: !isAddressSameAsShipping(), click: editAddress">
diff --git a/app/code/Magento/Checkout/view/frontend/web/template/payment-methods/list.html b/app/code/Magento/Checkout/view/frontend/web/template/payment-methods/list.html
index 66769f37386d6402c3d71d19f7f08ef6d88ca8b7..f6c41c62eeca62fcd89e0d85715863806d95e9f8 100644
--- a/app/code/Magento/Checkout/view/frontend/web/template/payment-methods/list.html
+++ b/app/code/Magento/Checkout/view/frontend/web/template/payment-methods/list.html
@@ -4,9 +4,19 @@
  * See COPYING.txt for license details.
  */
  -->
-<div class="items payment-methods">
-    <!-- ko foreach: { data: getRegion('payment-method-items'), as: 'element'}  -->
-        <!-- ko template: element.getTemplate() --><!-- /ko -->
-    <!-- /ko -->
+<div if="isPaymentMethodsAvailable()"
+     class="items payment-methods">
+    <div repeat="foreach: paymentGroupsList, item: '$group'"
+         class="payment-group">
+        <div if="getRegion($group().displayArea)().length"
+             translate="getGroupTitle($group)"
+             class="step-title"
+             data-role="title">
+        </div>
+        <each args="data: getRegion($group().displayArea), as: 'method'" render=""/>
+    </div>
+</div>
+<div ifnot="isPaymentMethodsAvailable()"
+     class="no-payments-block"
+     translate="'No Payment Methods'">
 </div>
-<!-- ko ifnot: getRegion('payment-method-items')().length > 0 --><div class="no-payments-block"><!-- ko i18n: 'No Payment Methods'--><!-- /ko --></div><!-- /ko -->
diff --git a/app/code/Magento/Checkout/view/frontend/web/template/payment.html b/app/code/Magento/Checkout/view/frontend/web/template/payment.html
index 292ece611e6b664f04c4ee78a8ace01d03fb49f5..46467839da3fb08eb994d61b0d2aaa48912ada87 100644
--- a/app/code/Magento/Checkout/view/frontend/web/template/payment.html
+++ b/app/code/Magento/Checkout/view/frontend/web/template/payment.html
@@ -5,7 +5,6 @@
  */
 -->
 <li id="payment" role="presentation" class="checkout-payment-method" data-bind="fadeVisible: isVisible">
-    <div class="step-title" data-bind="i18n: title" data-role="title"></div>
     <div id="checkout-step-payment"
          class="step-content"
          data-role="content"
diff --git a/app/code/Magento/Checkout/view/frontend/web/template/shipping-address/address-renderer/default.html b/app/code/Magento/Checkout/view/frontend/web/template/shipping-address/address-renderer/default.html
index eeecbf346636613366db1f9d3fa33c4c7835b681..a2b83ead6b354451b99a4a1003a0f04df905dbbc 100644
--- a/app/code/Magento/Checkout/view/frontend/web/template/shipping-address/address-renderer/default.html
+++ b/app/code/Magento/Checkout/view/frontend/web/template/shipping-address/address-renderer/default.html
@@ -13,6 +13,11 @@
     <!-- ko if: (address().telephone) -->
     <a data-bind="text: address().telephone, attr: {'href': 'tel:' + address().telephone}"></a>
     <!-- /ko --><br/>
+    <!-- ko foreach: { data: address().customAttributes, as: 'element' } -->
+        <!-- ko foreach: { data: Object.keys(element), as: 'attribute' } -->
+            <!-- ko text: element[attribute].value --><!-- /ko -->
+        <!-- /ko -->
+    <!-- /ko -->
     <!-- ko if: (address().isEditable()) -->
     <button type="button"
             class="action edit-address-link"
diff --git a/app/code/Magento/Checkout/view/frontend/web/template/shipping-information/address-renderer/default.html b/app/code/Magento/Checkout/view/frontend/web/template/shipping-information/address-renderer/default.html
index f02eef5ded99ab86bb3a445f7de3355f810e94e8..440a2c7fc468fc493d10eb0cb57320c5593e1bf8 100644
--- a/app/code/Magento/Checkout/view/frontend/web/template/shipping-information/address-renderer/default.html
+++ b/app/code/Magento/Checkout/view/frontend/web/template/shipping-information/address-renderer/default.html
@@ -13,4 +13,9 @@
     <!-- ko if: (address().telephone) -->
     <a data-bind="text: address().telephone, attr: {'href': 'tel:' + address().telephone}"></a>
     <!-- /ko --><br/>
+    <!-- ko foreach: { data: address().customAttributes, as: 'element' } -->
+        <!-- ko foreach: { data: Object.keys(element), as: 'attribute' } -->
+            <!-- ko text: element[attribute].value --><!-- /ko -->
+        <!-- /ko -->
+    <!-- /ko -->
 <!-- /ko -->
diff --git a/app/code/Magento/CheckoutAgreements/composer.json b/app/code/Magento/CheckoutAgreements/composer.json
index afb706a39a25ec97915abfe0bc6bfcb99c95f6d4..56a2b567745c2dd81fa3ca691309c4a76fe05aed 100644
--- a/app/code/Magento/CheckoutAgreements/composer.json
+++ b/app/code/Magento/CheckoutAgreements/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-checkout-agreements",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-checkout": "100.2.*",
         "magento/module-quote": "100.2.*",
         "magento/module-store": "100.2.*",
diff --git a/app/code/Magento/CheckoutAgreements/view/frontend/web/js/model/agreement-validator.js b/app/code/Magento/CheckoutAgreements/view/frontend/web/js/model/agreement-validator.js
index 3d030a62eb425cdb0365331c8fac5325a5dbc91d..2fa3c2cddd3d5af870f02db0e189cae8456c51aa 100644
--- a/app/code/Magento/CheckoutAgreements/view/frontend/web/js/model/agreement-validator.js
+++ b/app/code/Magento/CheckoutAgreements/view/frontend/web/js/model/agreement-validator.js
@@ -12,9 +12,8 @@ define(
     function ($) {
         'use strict';
         var checkoutConfig = window.checkoutConfig,
-            agreementsConfig = checkoutConfig ? checkoutConfig.checkoutAgreements : {};
-
-        var agreementsInputPath = '.payment-method._active div.checkout-agreements input';
+            agreementsConfig = checkoutConfig ? checkoutConfig.checkoutAgreements : {},
+            agreementsInputPath = '.payment-method._active div.checkout-agreements input';
 
         return {
             /**
@@ -23,26 +22,11 @@ define(
              * @returns {boolean}
              */
             validate: function() {
-                if (!agreementsConfig.isEnabled) {
-                    return true;
-                }
-
-                if ($(agreementsInputPath).length == 0) {
+                if (!agreementsConfig.isEnabled || $(agreementsInputPath).length == 0) {
                     return true;
                 }
 
-                return $('#co-payment-form').validate({
-                    errorClass: 'mage-error',
-                    errorElement: 'div',
-                    meta: 'validate',
-                    errorPlacement: function (error, element) {
-                        var errorPlacement = element;
-                        if (element.is(':checkbox') || element.is(':radio')) {
-                            errorPlacement = element.siblings('label').last();
-                        }
-                        errorPlacement.after(error);
-                    }
-                }).element(agreementsInputPath);
+                return $.validator.validateSingleElement(agreementsInputPath, {errorElement: 'div'});
             }
         }
     }
diff --git a/app/code/Magento/CheckoutAgreements/view/frontend/web/template/checkout/checkout-agreements.html b/app/code/Magento/CheckoutAgreements/view/frontend/web/template/checkout/checkout-agreements.html
index bb7d5de636ce5fd98b5f98943500910603d56267..7d8ef43084f3264c09bb65d2939f6660fa343f7f 100644
--- a/app/code/Magento/CheckoutAgreements/view/frontend/web/template/checkout/checkout-agreements.html
+++ b/app/code/Magento/CheckoutAgreements/view/frontend/web/template/checkout/checkout-agreements.html
@@ -8,14 +8,13 @@
     <div class="checkout-agreements" data-bind="visible: isVisible">
         <!-- ko foreach: agreements -->
             <!-- ko if: ($parent.isAgreementRequired($data)) -->
-            <div class="checkout-agreement">
-                <input type="checkbox"
+            <div class="checkout-agreement required">
+                <input type="checkbox" class="required-entry"
                        data-bind="attr: {
                                     'id': 'agreement_' + agreementId,
                                     'name': 'agreement[' + agreementId + ']',
                                     'value': agreementId
-                                    }"
-                       data-validate="{required:true}" />
+                                    }"/>
                 <label data-bind="attr: {'for': 'agreement_' + agreementId}">
                     <button type="button"
                             class="action action-show"
diff --git a/app/code/Magento/Cms/Model/ResourceModel/Block/Collection.php b/app/code/Magento/Cms/Model/ResourceModel/Block/Collection.php
index ec5a438247e5cddc205d2f49c8d49ea746943e34..1bd96eff4dceef562040df73978679cc236a00bb 100644
--- a/app/code/Magento/Cms/Model/ResourceModel/Block/Collection.php
+++ b/app/code/Magento/Cms/Model/ResourceModel/Block/Collection.php
@@ -41,6 +41,7 @@ class Collection extends AbstractCollection
     {
         $this->_init(\Magento\Cms\Model\Block::class, \Magento\Cms\Model\ResourceModel\Block::class);
         $this->_map['fields']['store'] = 'store_table.store_id';
+        $this->_map['fields']['block_id'] = 'main_table.block_id';
     }
 
     /**
diff --git a/app/code/Magento/Cms/Test/Unit/Ui/Component/Listing/Column/BlockActionsTest.php b/app/code/Magento/Cms/Test/Unit/Ui/Component/Listing/Column/BlockActionsTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..4e1de289e5ef0e004a34d70dd793c1715a8bf292
--- /dev/null
+++ b/app/code/Magento/Cms/Test/Unit/Ui/Component/Listing/Column/BlockActionsTest.php
@@ -0,0 +1,134 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Cms\Test\Unit\Ui\Component\Listing\Column;
+
+use Magento\Cms\Ui\Component\Listing\Column\BlockActions;
+use Magento\Framework\Escaper;
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
+use Magento\Framework\UrlInterface;
+use Magento\Framework\View\Element\UiComponent\ContextInterface;
+use Magento\Framework\View\Element\UiComponent\Processor;
+use PHPUnit_Framework_MockObject_MockObject as MockObject;
+
+/**
+ * BlockActionsTest contains unit tests for \Magento\Cms\Ui\Component\Listing\Column\BlockActions class
+ */
+class BlockActionsTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var BlockActions
+     */
+    private $blockActions;
+
+    /**
+     * @var Escaper|MockObject
+     */
+    private $escaper;
+
+    /**
+     * @var UrlInterface|MockObject
+     */
+    private $urlBuilder;
+
+    protected function setUp()
+    {
+        $objectManager = new ObjectManager($this);
+
+        $context = $this->getMock(ContextInterface::class);
+
+        $processor = $this->getMockBuilder(Processor::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $context->expects(static::once())
+            ->method('getProcessor')
+            ->willReturn($processor);
+
+        $this->urlBuilder = $this->getMock(UrlInterface::class);
+
+        $this->escaper = $this->getMockBuilder(Escaper::class)
+            ->disableOriginalConstructor()
+            ->setMethods(['escapeHtml'])
+            ->getMock();
+
+        $this->blockActions = $objectManager->getObject(BlockActions::class, [
+            'context' => $context,
+            'urlBuilder' => $this->urlBuilder
+        ]);
+
+        $objectManager->setBackwardCompatibleProperty($this->blockActions, 'escaper', $this->escaper);
+    }
+
+    /**
+     * @covers \Magento\Cms\Ui\Component\Listing\Column\BlockActions::prepareDataSource
+     */
+    public function testPrepareDataSource()
+    {
+        $blockId = 1;
+        $title = 'block title';
+        $items = [
+            'data' => [
+                'items' => [
+                    [
+                        'block_id' => $blockId,
+                        'title' => $title
+                    ]
+                ]
+            ]
+        ];
+        $name = 'item_name';
+        $expectedItems = [
+            [
+                'block_id' => $blockId,
+                'title' => $title,
+                $name => [
+                    'edit' => [
+                        'href' => 'test/url/edit',
+                        'label' => __('Edit'),
+                    ],
+                    'delete' => [
+                        'href' => 'test/url/delete',
+                        'label' => __('Delete'),
+                        'confirm' => [
+                            'title' => __('Delete %1', $title),
+                            'message' => __('Are you sure you wan\'t to delete a %1 record?', $title)
+                        ],
+                    ]
+                ],
+            ]
+        ];
+
+        $this->escaper->expects(static::once())
+            ->method('escapeHtml')
+            ->with($title)
+            ->willReturn($title);
+
+        $this->urlBuilder->expects(static::exactly(2))
+            ->method('getUrl')
+            ->willReturnMap(
+                [
+                    [
+                        BlockActions::URL_PATH_EDIT,
+                        [
+                            'block_id' => $blockId
+                        ],
+                        'test/url/edit',
+                    ],
+                    [
+                        BlockActions::URL_PATH_DELETE,
+                        [
+                            'block_id' => $blockId
+                        ],
+                        'test/url/delete',
+                    ],
+                ]
+            );
+
+        $this->blockActions->setData('name', $name);
+
+        $actual = $this->blockActions->prepareDataSource($items);
+        static::assertEquals($expectedItems, $actual['data']['items']);
+    }
+}
diff --git a/app/code/Magento/Cms/Test/Unit/Ui/Component/Listing/Column/PageActionsTest.php b/app/code/Magento/Cms/Test/Unit/Ui/Component/Listing/Column/PageActionsTest.php
index 4b6ce1ae2ff42d39bf53a9e57bd3b9f6aa639f89..731c08fbc64dd59a967b4d74ea52ba188336d0a9 100644
--- a/app/code/Magento/Cms/Test/Unit/Ui/Component/Listing/Column/PageActionsTest.php
+++ b/app/code/Magento/Cms/Test/Unit/Ui/Component/Listing/Column/PageActionsTest.php
@@ -6,6 +6,7 @@
 namespace Magento\Cms\Test\Unit\Ui\Component\Listing\Column;
 
 use Magento\Cms\Ui\Component\Listing\Column\PageActions;
+use Magento\Framework\Escaper;
 
 class PageActionsTest extends \PHPUnit_Framework_TestCase
 {
@@ -34,12 +35,20 @@ class PageActionsTest extends \PHPUnit_Framework_TestCase
             ]
         );
 
+        $escaper = $this->getMockBuilder(Escaper::class)
+            ->disableOriginalConstructor()
+            ->setMethods(['escapeHtml'])
+            ->getMock();
+        $objectManager->setBackwardCompatibleProperty($model, 'escaper', $escaper);
+
         // Define test input and expectations
+        $title = 'page title';
         $items = [
             'data' => [
                 'items' => [
                     [
-                        'page_id' => $pageId
+                        'page_id' => $pageId,
+                        'title' => $title
                     ]
                 ]
             ]
@@ -48,6 +57,7 @@ class PageActionsTest extends \PHPUnit_Framework_TestCase
         $expectedItems = [
             [
                 'page_id' => $pageId,
+                'title' => $title,
                 $name => [
                     'edit' => [
                         'href' => 'test/url/edit',
@@ -57,14 +67,19 @@ class PageActionsTest extends \PHPUnit_Framework_TestCase
                         'href' => 'test/url/delete',
                         'label' => __('Delete'),
                         'confirm' => [
-                            'title' => __('Delete ${ $.$data.title }'),
-                            'message' => __('Are you sure you wan\'t to delete a ${ $.$data.title } record?')
+                            'title' => __('Delete %1', $title),
+                            'message' => __('Are you sure you wan\'t to delete a %1 record?', $title)
                         ],
                     ]
                 ],
             ]
         ];
 
+        $escaper->expects(static::once())
+            ->method('escapeHtml')
+            ->with($title)
+            ->willReturn($title);
+
         // Configure mocks and object data
         $urlBuilderMock->expects($this->any())
             ->method('getUrl')
diff --git a/app/code/Magento/Cms/Ui/Component/Listing/Column/BlockActions.php b/app/code/Magento/Cms/Ui/Component/Listing/Column/BlockActions.php
index e71352c465333396312cc0bd0242cbe45f62bd17..f0a1fe7981f8c3007055973eb4e296c23afe5ab8 100644
--- a/app/code/Magento/Cms/Ui/Component/Listing/Column/BlockActions.php
+++ b/app/code/Magento/Cms/Ui/Component/Listing/Column/BlockActions.php
@@ -9,6 +9,8 @@ use Magento\Framework\UrlInterface;
 use Magento\Framework\View\Element\UiComponent\ContextInterface;
 use Magento\Framework\View\Element\UiComponentFactory;
 use Magento\Ui\Component\Listing\Columns\Column;
+use Magento\Framework\App\ObjectManager;
+use Magento\Framework\Escaper;
 
 /**
  * Class BlockActions
@@ -27,6 +29,11 @@ class BlockActions extends Column
      */
     protected $urlBuilder;
 
+    /**
+     * @var Escaper
+     */
+    private $escaper;
+
     /**
      * Constructor
      *
@@ -47,10 +54,6 @@ class BlockActions extends Column
         parent::__construct($context, $uiComponentFactory, $components, $data);
     }
 
-    /**
-     * @param array $items
-     * @return array
-     */
     /**
      * Prepare Data Source
      *
@@ -62,6 +65,7 @@ class BlockActions extends Column
         if (isset($dataSource['data']['items'])) {
             foreach ($dataSource['data']['items'] as & $item) {
                 if (isset($item['block_id'])) {
+                    $title = $this->getEscaper()->escapeHtml($item['title']);
                     $item[$this->getData('name')] = [
                         'edit' => [
                             'href' => $this->urlBuilder->getUrl(
@@ -81,8 +85,8 @@ class BlockActions extends Column
                             ),
                             'label' => __('Delete'),
                             'confirm' => [
-                                'title' => __('Delete "${ $.$data.title }"'),
-                                'message' => __('Are you sure you wan\'t to delete a "${ $.$data.title }" record?')
+                                'title' => __('Delete %1', $title),
+                                'message' => __('Are you sure you wan\'t to delete a %1 record?', $title)
                             ]
                         ]
                     ];
@@ -92,4 +96,17 @@ class BlockActions extends Column
 
         return $dataSource;
     }
+
+    /**
+     * Get instance of escaper
+     * @return Escaper
+     * @deprecated
+     */
+    private function getEscaper()
+    {
+        if (!$this->escaper) {
+            $this->escaper = ObjectManager::getInstance()->get(Escaper::class);
+        }
+        return $this->escaper;
+    }
 }
diff --git a/app/code/Magento/Cms/Ui/Component/Listing/Column/PageActions.php b/app/code/Magento/Cms/Ui/Component/Listing/Column/PageActions.php
index fe85fd0ef314070c5c6cdb6f34435e72af3e152b..f23afbffa792e6b5b92166b5268e3942735bd21f 100644
--- a/app/code/Magento/Cms/Ui/Component/Listing/Column/PageActions.php
+++ b/app/code/Magento/Cms/Ui/Component/Listing/Column/PageActions.php
@@ -5,11 +5,13 @@
  */
 namespace Magento\Cms\Ui\Component\Listing\Column;
 
+use Magento\Cms\Block\Adminhtml\Page\Grid\Renderer\Action\UrlBuilder;
+use Magento\Framework\App\ObjectManager;
+use Magento\Framework\Escaper;
+use Magento\Framework\UrlInterface;
 use Magento\Framework\View\Element\UiComponent\ContextInterface;
 use Magento\Framework\View\Element\UiComponentFactory;
 use Magento\Ui\Component\Listing\Columns\Column;
-use Magento\Cms\Block\Adminhtml\Page\Grid\Renderer\Action\UrlBuilder;
-use Magento\Framework\UrlInterface;
 
 /**
  * Class PageActions
@@ -31,6 +33,11 @@ class PageActions extends Column
      */
     private $editUrl;
 
+    /**
+     * @var Escaper
+     */
+    private $escaper;
+
     /**
      * @param ContextInterface $context
      * @param UiComponentFactory $uiComponentFactory
@@ -71,12 +78,13 @@ class PageActions extends Column
                         'href' => $this->urlBuilder->getUrl($this->editUrl, ['page_id' => $item['page_id']]),
                         'label' => __('Edit')
                     ];
+                    $title = $this->getEscaper()->escapeHtml($item['title']);
                     $item[$name]['delete'] = [
                         'href' => $this->urlBuilder->getUrl(self::CMS_URL_PATH_DELETE, ['page_id' => $item['page_id']]),
                         'label' => __('Delete'),
                         'confirm' => [
-                            'title' => __('Delete ${ $.$data.title }'),
-                            'message' => __('Are you sure you wan\'t to delete a ${ $.$data.title } record?')
+                            'title' => __('Delete %1', $title),
+                            'message' => __('Are you sure you wan\'t to delete a %1 record?', $title)
                         ]
                     ];
                 }
@@ -95,4 +103,17 @@ class PageActions extends Column
 
         return $dataSource;
     }
+
+    /**
+     * Get instance of escaper
+     * @return Escaper
+     * @deprecated
+     */
+    private function getEscaper()
+    {
+        if (!$this->escaper) {
+            $this->escaper = ObjectManager::getInstance()->get(Escaper::class);
+        }
+        return $this->escaper;
+    }
 }
diff --git a/app/code/Magento/Cms/composer.json b/app/code/Magento/Cms/composer.json
index 66f6da042e6c9a77e25eb5c9e8f1595c16e3e5f6..7f2ed4d7a7dcdc59916c34c796f7f3fc05ec6cc9 100644
--- a/app/code/Magento/Cms/composer.json
+++ b/app/code/Magento/Cms/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-cms",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-store": "100.2.*",
         "magento/module-theme": "100.2.*",
         "magento/module-widget": "100.2.*",
diff --git a/app/code/Magento/Cms/i18n/en_US.csv b/app/code/Magento/Cms/i18n/en_US.csv
index 6f3a2955a5c65b5cf1760519741fd60d49133123..9a9f6ac4c6888e386d44c679c94a87533844342d 100644
--- a/app/code/Magento/Cms/i18n/en_US.csv
+++ b/app/code/Magento/Cms/i18n/en_US.csv
@@ -84,10 +84,8 @@ Exception,Exception
 "All Store Views","All Store Views"
 Edit,Edit
 Delete,Delete
-"Delete ${ $.$data.title }","Delete ${ $.$data.title }"
-"Are you sure you wan\'t to delete a ${ $.$data.title } record?","Are you sure you wan\'t to delete a ${ $.$data.title } record?"
-"Delete ""${ $.$data.title }""","Delete ""${ $.$data.title }"""
-"Are you sure you wan\'t to delete a ""${ $.$data.title }"" record?","Are you sure you wan\'t to delete a ""${ $.$data.title }"" record?"
+"Delete %1","Delete %1"
+"Are you sure you wan\'t to delete a %1 record?","Are you sure you wan\'t to delete a %1 record?"
 View,View
 px.,px.
 "No files found","No files found"
diff --git a/app/code/Magento/CmsUrlRewrite/composer.json b/app/code/Magento/CmsUrlRewrite/composer.json
index 1ae1efd9350a760846e76fcac8939ef574194361..1d2e70c74eb4f9fd0876f92c37b30b5e9387d2cd 100644
--- a/app/code/Magento/CmsUrlRewrite/composer.json
+++ b/app/code/Magento/CmsUrlRewrite/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-cms-url-rewrite",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-store": "100.2.*",
         "magento/module-cms": "101.1.*",
         "magento/module-url-rewrite": "100.2.*",
diff --git a/app/code/Magento/Config/Model/Config/Backend/Baseurl.php b/app/code/Magento/Config/Model/Config/Backend/Baseurl.php
index 09fd99773813117a71b43240eaafc5b96bf967ca..f08c2f8e04434c7a26645669ff3a4c1c8d1840c7 100644
--- a/app/code/Magento/Config/Model/Config/Backend/Baseurl.php
+++ b/app/code/Magento/Config/Model/Config/Backend/Baseurl.php
@@ -5,6 +5,9 @@
  */
 namespace Magento\Config\Model\Config\Backend;
 
+use Magento\Framework\Validator\Url as UrlValidator;
+use Magento\Framework\App\ObjectManager;
+
 class Baseurl extends \Magento\Framework\App\Config\Value
 {
     /**
@@ -12,6 +15,11 @@ class Baseurl extends \Magento\Framework\App\Config\Value
      */
     protected $_mergeService;
 
+    /**
+     * @var UrlValidator
+     */
+    private $urlValidator;
+
     /**
      * @param \Magento\Framework\Model\Context $context
      * @param \Magento\Framework\Registry $registry
@@ -193,8 +201,7 @@ class Baseurl extends \Magento\Framework\App\Config\Value
      */
     private function _isFullyQualifiedUrl($value)
     {
-        $url = parse_url($value);
-        return isset($url['scheme']) && isset($url['host']) && preg_match('/\/$/', $value);
+        return preg_match('/\/$/', $value) && $this->getUrlValidator()->isValid($value, ['http', 'https']);
     }
 
     /**
@@ -216,4 +223,18 @@ class Baseurl extends \Magento\Framework\App\Config\Value
         }
         return parent::afterSave();
     }
+
+    /**
+     * Get URL Validator
+     *
+     * @deprecated
+     * @return UrlValidator
+     */
+    private function getUrlValidator()
+    {
+        if (!$this->urlValidator) {
+            $this->urlValidator = ObjectManager::getInstance()->get(UrlValidator::class);
+        }
+        return $this->urlValidator;
+    }
 }
diff --git a/app/code/Magento/Config/composer.json b/app/code/Magento/Config/composer.json
index bdd1a9c14ae6894d052f6e7e2994f2c87c6554b0..b14dd825b0d12d819fd511222e80de12a7cf8c3a 100644
--- a/app/code/Magento/Config/composer.json
+++ b/app/code/Magento/Config/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-config",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/framework": "100.2.*",
         "magento/module-store": "100.2.*",
         "magento/module-cron": "100.2.*",
diff --git a/app/code/Magento/ConfigurableImportExport/composer.json b/app/code/Magento/ConfigurableImportExport/composer.json
index 6c249134d28626b4c8846fd7491cf25b2e278638..d292e73198435431015dff6bcfe1a69d516debc9 100644
--- a/app/code/Magento/ConfigurableImportExport/composer.json
+++ b/app/code/Magento/ConfigurableImportExport/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-configurable-import-export",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-catalog": "101.1.*",
         "magento/module-catalog-import-export": "100.2.*",
         "magento/module-eav": "100.2.*",
diff --git a/app/code/Magento/ConfigurableProduct/Block/Plugin/Product/Media/Gallery.php b/app/code/Magento/ConfigurableProduct/Block/Plugin/Product/Media/Gallery.php
deleted file mode 100644
index a4390bf94865084fd27d401e47982c3bdb3cabbf..0000000000000000000000000000000000000000
--- a/app/code/Magento/ConfigurableProduct/Block/Plugin/Product/Media/Gallery.php
+++ /dev/null
@@ -1,102 +0,0 @@
-<?php
-/**
- * Copyright © 2016 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-namespace Magento\ConfigurableProduct\Block\Plugin\Product\Media;
-
-use Magento\ConfigurableProduct\Model\Product\Type\Configurable;
-
-/**
- * Class Gallery
- */
-class Gallery extends \Magento\Catalog\Block\Product\View\AbstractView
-{
-    /**
-     * @var \Magento\Catalog\Model\Product\Gallery\ReadHandler
-     */
-    private $productGalleryReadHandler;
-
-    /**
-     * @var \Magento\Framework\Json\EncoderInterface
-     */
-    private $jsonEncoder;
-
-    /**
-     * @var \Magento\Framework\Json\DecoderInterface
-     */
-    private $jsonDecoder;
-
-    /**
-     * Gallery constructor.
-     * @param \Magento\Catalog\Block\Product\Context $context
-     * @param \Magento\Framework\Stdlib\ArrayUtils $arrayUtils
-     * @param \Magento\Catalog\Model\Product\Gallery\ReadHandler $productGalleryReadHandler
-     * @param \Magento\Framework\Json\EncoderInterface $jsonEncoder
-     * @param \Magento\Framework\Json\DecoderInterface $jsonDecoder
-     * @param array $data
-     */
-    public function __construct(
-        \Magento\Catalog\Block\Product\Context $context,
-        \Magento\Framework\Stdlib\ArrayUtils $arrayUtils,
-        \Magento\Catalog\Model\Product\Gallery\ReadHandler $productGalleryReadHandler,
-        \Magento\Framework\Json\EncoderInterface $jsonEncoder,
-        \Magento\Framework\Json\DecoderInterface $jsonDecoder,
-        array $data = []
-    ) {
-        $this->productGalleryReadHandler = $productGalleryReadHandler;
-        $this->jsonEncoder = $jsonEncoder;
-        $this->jsonDecoder = $jsonDecoder;
-        parent::__construct($context, $arrayUtils, $data);
-    }
-
-    /**
-     * @param \Magento\Catalog\Block\Product\View\Gallery $subject
-     * @param string $result
-     * @return string
-     *
-     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
-     */
-    public function afterGetOptionsMediaGalleryDataJson(
-        \Magento\Catalog\Block\Product\View\Gallery $subject,
-        $result
-    ) {
-        $result = $this->jsonDecoder->decode($result);
-        if ($this->getProduct()->getTypeId() == 'configurable') {
-            /** @var Configurable $productType */
-            $productType = $this->getProduct()->getTypeInstance();
-            $products = $productType->getUsedProducts($this->getProduct());
-            $attributes = $productType->getConfigurableAttributesAsArray($this->getProduct());
-            /** @var \Magento\Catalog\Model\Product $product */
-            foreach ($attributes as $attribute) {
-                foreach ($products as $product) {
-                    $attributeValue = $product->getData($attribute['attribute_code']);
-                    if ($attributeValue) {
-                        $key = $attribute['attribute_code'] . '_' . $attributeValue;
-                        $result[$key] = $this->getProductGallery($product);
-                    }
-                }
-            }
-        }
-        return $this->jsonEncoder->encode($result);
-    }
-
-    /**
-     * @param \Magento\Catalog\Model\Product $product
-     * @return array
-     */
-    private function getProductGallery($product)
-    {
-        $result = [];
-        $this->productGalleryReadHandler->execute($product);
-        $images = $product->getMediaGalleryImages();
-        foreach ($images as $image) {
-            $result[] = [
-                'mediaType' => $image->getMediaType(),
-                'videoUrl' => $image->getVideoUrl(),
-                'isBase' => $product->getImage() == $image->getFile(),
-            ];
-        }
-        return $result;
-    }
-}
diff --git a/app/code/Magento/ConfigurableProduct/Model/LinkManagement.php b/app/code/Magento/ConfigurableProduct/Model/LinkManagement.php
index 0fdfbd3bfa172ee597414ed3ab4c46bbac2a9549..5575d6f7ef56fa4f7f2fed433299c01eaa4ba98d 100644
--- a/app/code/Magento/ConfigurableProduct/Model/LinkManagement.php
+++ b/app/code/Magento/ConfigurableProduct/Model/LinkManagement.php
@@ -32,6 +32,16 @@ class LinkManagement implements \Magento\ConfigurableProduct\Api\LinkManagementI
      */
     private $dataObjectHelper;
 
+    /**
+     * @var \Magento\ConfigurableProduct\Helper\Product\Options\Factory;
+     */
+    private $optionsFactory;
+
+    /**
+     * @var \Magento\Catalog\Model\ResourceModel\Eav\AttributeFactory
+     */
+    private $attributeFactory;
+
     /**
      * @param \Magento\Catalog\Api\ProductRepositoryInterface $productRepository
      * @param \Magento\Catalog\Api\Data\ProductInterfaceFactory $productFactory
@@ -102,9 +112,28 @@ class LinkManagement implements \Magento\ConfigurableProduct\Api\LinkManagementI
             throw new StateException(__('Product has been already attached'));
         }
 
+        $configurableProductOptions = $product->getExtensionAttributes()->getConfigurableProductOptions();
+        if (empty($configurableProductOptions)) {
+            throw new StateException(__('Parent product does not have configurable product options'));
+        }
+
+        $attributeIds = [];
+        foreach ($configurableProductOptions as $configurableProductOption) {
+            $attributeCode = $configurableProductOption->getProductAttribute()->getAttributeCode();
+            if (!$child->getData($attributeCode)) {
+                throw new StateException(__('Child product does not have attribute value %1', $attributeCode));
+            }
+            $attributeIds[] = $configurableProductOption->getAttributeId();
+        }
+        $configurableOptionData = $this->getConfigurableAttributesData($attributeIds);
+
+        /** @var \Magento\ConfigurableProduct\Helper\Product\Options\Factory $optionFactory */
+        $optionFactory = $this->getOptionsFactory();
+        $options = $optionFactory->create($configurableOptionData);
         $childrenIds[] = $child->getId();
+        $product->getExtensionAttributes()->setConfigurableProductOptions($options);
         $product->getExtensionAttributes()->setConfigurableProductLinks($childrenIds);
-        $product->save();
+        $this->productRepository->save($product);
         return true;
     }
 
@@ -133,7 +162,75 @@ class LinkManagement implements \Magento\ConfigurableProduct\Api\LinkManagementI
             throw new NoSuchEntityException(__('Requested option doesn\'t exist'));
         }
         $product->getExtensionAttributes()->setConfigurableProductLinks($ids);
-        $product->save();
+        $this->productRepository->save($product);
         return true;
     }
+
+    /**
+     * Get Options Factory
+     *
+     * @return \Magento\ConfigurableProduct\Helper\Product\Options\Factory
+     *
+     * @deprecated
+     */
+    private function getOptionsFactory()
+    {
+        if (!$this->optionsFactory) {
+            $this->optionsFactory = \Magento\Framework\App\ObjectManager::getInstance()
+                ->get(\Magento\ConfigurableProduct\Helper\Product\Options\Factory::class);
+        }
+        return $this->optionsFactory;
+    }
+
+    /**
+     * Get Attribute Factory
+     *
+     * @return \Magento\Catalog\Model\ResourceModel\Eav\AttributeFactory
+     *
+     * @deprecated
+     */
+    private function getAttributeFactory()
+    {
+        if (!$this->attributeFactory) {
+            $this->attributeFactory = \Magento\Framework\App\ObjectManager::getInstance()
+                ->get(\Magento\Catalog\Model\ResourceModel\Eav\AttributeFactory::class);
+        }
+        return $this->attributeFactory;
+    }
+
+    /**
+     * Get Configurable Attribute Data
+     *
+     * @param int[] $attributeIds
+     * @return array
+     */
+    private function getConfigurableAttributesData($attributeIds)
+    {
+        $configurableAttributesData = [];
+        $attributeValues = [];
+        $attributes = $this->getAttributeFactory()->create()
+            ->getCollection()
+            ->addFieldToFilter('attribute_id', $attributeIds)
+            ->getItems();
+        foreach ($attributes as $attribute) {
+            foreach ($attribute->getOptions() as $option) {
+                if ($option->getValue()) {
+                    $attributeValues[] = [
+                        'label' => $option->getLabel(),
+                        'attribute_id' => $attribute->getId(),
+                        'value_index' => $option->getValue(),
+                    ];
+                }
+            }
+            $configurableAttributesData[] =
+                [
+                    'attribute_id' => $attribute->getId(),
+                    'code' => $attribute->getAttributeCode(),
+                    'label' => $attribute->getStoreLabel(),
+                    'values' => $attributeValues,
+                ];
+        }
+
+        return $configurableAttributesData;
+    }
 }
diff --git a/app/code/Magento/ConfigurableProduct/Model/ResourceModel/Product/Indexer/Price/Configurable.php b/app/code/Magento/ConfigurableProduct/Model/ResourceModel/Product/Indexer/Price/Configurable.php
index 4e6fa8ae5210d77726b393047a7433ca03d69c7d..fbb69798ff94fbdf8caafc7486e564da662cf655 100644
--- a/app/code/Magento/ConfigurableProduct/Model/ResourceModel/Product/Indexer/Price/Configurable.php
+++ b/app/code/Magento/ConfigurableProduct/Model/ResourceModel/Product/Indexer/Price/Configurable.php
@@ -8,6 +8,7 @@
 namespace Magento\ConfigurableProduct\Model\ResourceModel\Product\Indexer\Price;
 
 use Magento\Catalog\Api\Data\ProductInterface;
+use Magento\Catalog\Model\Product\Attribute\Source\Status as ProductStatus;
 
 class Configurable extends \Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\DefaultPrice
 {
@@ -166,6 +167,9 @@ class Configurable extends \Magento\Catalog\Model\ResourceModel\Product\Indexer\
         $this->_prepareConfigurableOptionAggregateTable();
         $this->_prepareConfigurableOptionPriceTable();
 
+        $statusAttribute = $this->_getAttribute(ProductInterface::STATUS);
+        $linkField = $metadata->getLinkField();
+
         $select = $connection->select()->from(
             ['i' => $this->_getDefaultFinalPriceTable()],
             []
@@ -175,7 +179,7 @@ class Configurable extends \Magento\Catalog\Model\ResourceModel\Product\Indexer\
             ['parent_id' => 'e.entity_id']
         )->join(
             ['l' => $this->getTable('catalog_product_super_link')],
-            'l.parent_id = e.' . $metadata->getLinkField(),
+            'l.parent_id = e.' . $linkField,
             ['product_id']
         )->columns(
             ['customer_group_id', 'website_id'],
@@ -186,11 +190,21 @@ class Configurable extends \Magento\Catalog\Model\ResourceModel\Product\Indexer\
             []
         )->where(
             'le.required_options=0'
+        )->join(
+            ['product_status' => $this->getTable($statusAttribute->getBackend()->getTable())],
+            sprintf(
+                'le.%1$s = product_status.%1$s AND product_status.attribute_id = %2$s',
+                $linkField,
+                $statusAttribute->getAttributeId()
+            ),
+            []
+        )->where(
+            'product_status.value=' . ProductStatus::STATUS_ENABLED
         )->group(
-            ['parent_id', 'i.customer_group_id', 'i.website_id', 'l.product_id']
+            ['e.entity_id', 'i.customer_group_id', 'i.website_id', 'l.product_id']
         );
-        $priceColumn = $this->_addAttributeToSelect($select, 'price', 'l.product_id', 0, null, true);
-        $tierPriceColumn = $connection->getCheckSql("MIN(i.tier_price) IS NOT NULL", "i.tier_price", 'NULL');
+        $priceColumn = $this->_addAttributeToSelect($select, 'price', 'le.' . $linkField, 0, null, true);
+        $tierPriceColumn = $connection->getIfNullSql('MIN(i.tier_price)', 'NULL');
 
         $select->columns(
             ['price' => $priceColumn, 'tier_price' => $tierPriceColumn]
diff --git a/app/code/Magento/ConfigurableProduct/Pricing/Price/ConfigurableOptionsProvider.php b/app/code/Magento/ConfigurableProduct/Pricing/Price/ConfigurableOptionsProvider.php
index dcb75fe725dc20d74aa245831e8046dbd9665949..872538d9babab02aec00763ee317298f9c93697e 100644
--- a/app/code/Magento/ConfigurableProduct/Pricing/Price/ConfigurableOptionsProvider.php
+++ b/app/code/Magento/ConfigurableProduct/Pricing/Price/ConfigurableOptionsProvider.php
@@ -18,26 +18,6 @@ class ConfigurableOptionsProvider implements ConfigurableOptionsProviderInterfac
     /** @var Configurable */
     private $configurable;
 
-    /**
-     * @var RequestSafetyInterface
-     */
-    private $requestSafety;
-
-    /**
-     * @var ResourceConnection
-     */
-    private $resource;
-
-    /**
-     * @var LinkedProductSelectBuilderInterface
-     */
-    private $linkedProductSelectBuilder;
-
-    /**
-     * @var CollectionFactory
-     */
-    private $collectionFactory;
-
     /**
      * @var ProductInterface[]
      */
@@ -49,6 +29,7 @@ class ConfigurableOptionsProvider implements ConfigurableOptionsProviderInterfac
      * @param LinkedProductSelectBuilderInterface $linkedProductSelectBuilder
      * @param CollectionFactory $collectionFactory
      * @param RequestSafetyInterface $requestSafety
+     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
      */
     public function __construct(
         Configurable $configurable,
@@ -58,10 +39,6 @@ class ConfigurableOptionsProvider implements ConfigurableOptionsProviderInterfac
         RequestSafetyInterface $requestSafety
     ) {
         $this->configurable = $configurable;
-        $this->resource = $resourceConnection;
-        $this->linkedProductSelectBuilder = $linkedProductSelectBuilder;
-        $this->collectionFactory = $collectionFactory;
-        $this->requestSafety = $requestSafety;
     }
 
     /**
@@ -70,17 +47,7 @@ class ConfigurableOptionsProvider implements ConfigurableOptionsProviderInterfac
     public function getProducts(ProductInterface $product)
     {
         if (!isset($this->products[$product->getId()])) {
-            if ($this->requestSafety->isSafeMethod()) {
-                $productIds = $this->resource->getConnection()->fetchCol(
-                    '(' . implode(') UNION (', $this->linkedProductSelectBuilder->build($product->getId())) . ')'
-                );
-
-                $this->products[$product->getId()] = $this->collectionFactory->create()
-                    ->addAttributeToSelect(['price', 'special_price'])
-                    ->addIdFilter($productIds);
-            } else {
-                $this->products[$product->getId()] = $this->configurable->getUsedProducts($product);
-            }
+            $this->products[$product->getId()] = $this->configurable->getUsedProducts($product);
         }
         return $this->products[$product->getId()];
     }
diff --git a/app/code/Magento/ConfigurableProduct/Pricing/Price/ConfigurableOptionsProviderInterface.php b/app/code/Magento/ConfigurableProduct/Pricing/Price/ConfigurableOptionsProviderInterface.php
index c7ac9446f42e306b78badec5f4b0825ce8c6f6c1..c0f2c218cc77c80a8e6785aba97431baea793975 100644
--- a/app/code/Magento/ConfigurableProduct/Pricing/Price/ConfigurableOptionsProviderInterface.php
+++ b/app/code/Magento/ConfigurableProduct/Pricing/Price/ConfigurableOptionsProviderInterface.php
@@ -10,6 +10,7 @@ use Magento\Catalog\Api\Data\ProductInterface;
 
 /**
  * Provide configurable sub-products for price calculation
+ * @api
  */
 interface ConfigurableOptionsProviderInterface
 {
diff --git a/app/code/Magento/ConfigurableProduct/Pricing/Price/ConfigurablePriceResolver.php b/app/code/Magento/ConfigurableProduct/Pricing/Price/ConfigurablePriceResolver.php
index 75d08b5aa419bdec6d9db0c3112f2aa1b7e836a6..68e82ed76a23fbdda404c32eb7406d3117b3cd0e 100644
--- a/app/code/Magento/ConfigurableProduct/Pricing/Price/ConfigurablePriceResolver.php
+++ b/app/code/Magento/ConfigurableProduct/Pricing/Price/ConfigurablePriceResolver.php
@@ -6,7 +6,6 @@
 
 namespace Magento\ConfigurableProduct\Pricing\Price;
 
-use Magento\Catalog\Model\Product;
 use Magento\ConfigurableProduct\Model\Product\Type\Configurable;
 use Magento\Framework\App\ObjectManager;
 use Magento\Framework\Pricing\PriceCurrencyInterface;
@@ -29,23 +28,27 @@ class ConfigurablePriceResolver implements PriceResolverInterface
     protected $configurable;
 
     /**
-     * @var ConfigurableOptionsProviderInterface
+     * @var LowestPriceOptionsProviderInterface
      */
-    private $configurableOptionsProvider;
+    private $lowestPriceOptionsProvider;
 
     /**
      * @param PriceResolverInterface $priceResolver
      * @param Configurable $configurable
      * @param PriceCurrencyInterface $priceCurrency
+     * @param LowestPriceOptionsProviderInterface $lowestPriceOptionsProvider
      */
     public function __construct(
         PriceResolverInterface $priceResolver,
         Configurable $configurable,
-        PriceCurrencyInterface $priceCurrency
+        PriceCurrencyInterface $priceCurrency,
+        LowestPriceOptionsProviderInterface $lowestPriceOptionsProvider = null
     ) {
         $this->priceResolver = $priceResolver;
         $this->configurable = $configurable;
         $this->priceCurrency = $priceCurrency;
+        $this->lowestPriceOptionsProvider = $lowestPriceOptionsProvider ?:
+            ObjectManager::getInstance()->get(LowestPriceOptionsProviderInterface::class);
     }
 
     /**
@@ -57,7 +60,7 @@ class ConfigurablePriceResolver implements PriceResolverInterface
     {
         $price = null;
 
-        foreach ($this->getConfigurableOptionsProvider()->getProducts($product) as $subProduct) {
+        foreach ($this->lowestPriceOptionsProvider->getProducts($product) as $subProduct) {
             $productPrice = $this->priceResolver->resolvePrice($subProduct);
             $price = $price ? min($price, $productPrice) : $productPrice;
         }
@@ -69,17 +72,4 @@ class ConfigurablePriceResolver implements PriceResolverInterface
 
         return (float)$price;
     }
-
-    /**
-     * @return \Magento\ConfigurableProduct\Pricing\Price\ConfigurableOptionsProviderInterface
-     * @deprecated
-     */
-    private function getConfigurableOptionsProvider()
-    {
-        if (null === $this->configurableOptionsProvider) {
-            $this->configurableOptionsProvider = ObjectManager::getInstance()
-                ->get(ConfigurableOptionsProviderInterface::class);
-        }
-        return $this->configurableOptionsProvider;
-    }
 }
diff --git a/app/code/Magento/ConfigurableProduct/Pricing/Price/ConfigurableRegularPrice.php b/app/code/Magento/ConfigurableProduct/Pricing/Price/ConfigurableRegularPrice.php
index 14b788258ab75502183aaf0b3f842b1943fcec2d..7a710e2caacc96f0a20eae124d973de9fa6a4c49 100644
--- a/app/code/Magento/ConfigurableProduct/Pricing/Price/ConfigurableRegularPrice.php
+++ b/app/code/Magento/ConfigurableProduct/Pricing/Price/ConfigurableRegularPrice.php
@@ -44,22 +44,31 @@ class ConfigurableRegularPrice extends AbstractPrice implements ConfigurableRegu
      */
     private $configurableOptionsProvider;
 
+    /**
+     * @var LowestPriceOptionsProviderInterface
+     */
+    private $lowestPriceOptionsProvider;
+
     /**
      * @param \Magento\Framework\Pricing\SaleableInterface $saleableItem
      * @param float $quantity
      * @param \Magento\Framework\Pricing\Adjustment\CalculatorInterface $calculator
      * @param \Magento\Framework\Pricing\PriceCurrencyInterface $priceCurrency
      * @param PriceResolverInterface $priceResolver
+     * @param LowestPriceOptionsProviderInterface $lowestPriceOptionsProvider
      */
     public function __construct(
         \Magento\Framework\Pricing\SaleableInterface $saleableItem,
         $quantity,
         \Magento\Framework\Pricing\Adjustment\CalculatorInterface $calculator,
         \Magento\Framework\Pricing\PriceCurrencyInterface $priceCurrency,
-        PriceResolverInterface $priceResolver
+        PriceResolverInterface $priceResolver,
+        LowestPriceOptionsProviderInterface $lowestPriceOptionsProvider = null
     ) {
         parent::__construct($saleableItem, $quantity, $calculator, $priceCurrency);
         $this->priceResolver = $priceResolver;
+        $this->lowestPriceOptionsProvider = $lowestPriceOptionsProvider ?:
+            ObjectManager::getInstance()->get(LowestPriceOptionsProviderInterface::class);
     }
 
     /**
@@ -88,7 +97,6 @@ class ConfigurableRegularPrice extends AbstractPrice implements ConfigurableRegu
     public function getMaxRegularAmount()
     {
         if (null === $this->maxRegularAmount) {
-            $this->maxRegularAmount = $this->doGetMaxRegularAmount();
             $this->maxRegularAmount = $this->doGetMaxRegularAmount() ?: false;
         }
         return $this->maxRegularAmount;
@@ -96,7 +104,7 @@ class ConfigurableRegularPrice extends AbstractPrice implements ConfigurableRegu
     }
 
     /**
-     * Get max regular amount. Template method
+     * Get max regular amount
      *
      * @return \Magento\Framework\Pricing\Amount\AmountInterface
      */
@@ -124,14 +132,14 @@ class ConfigurableRegularPrice extends AbstractPrice implements ConfigurableRegu
     }
 
     /**
-     * Get min regular amount. Template method
+     * Get min regular amount
      *
      * @return \Magento\Framework\Pricing\Amount\AmountInterface
      */
     protected function doGetMinRegularAmount()
     {
         $minAmount = null;
-        foreach ($this->getUsedProducts() as $product) {
+        foreach ($this->lowestPriceOptionsProvider->getProducts($this->product) as $product) {
             $childPriceAmount = $product->getPriceInfo()->getPrice(self::PRICE_CODE)->getAmount();
             if (!$minAmount || ($childPriceAmount->getValue() < $minAmount->getValue())) {
                 $minAmount = $childPriceAmount;
diff --git a/app/code/Magento/ConfigurableProduct/Pricing/Price/LowestPriceOptionsProvider.php b/app/code/Magento/ConfigurableProduct/Pricing/Price/LowestPriceOptionsProvider.php
new file mode 100644
index 0000000000000000000000000000000000000000..1b758866100eb8f52faa371e4bc1695ce385703f
--- /dev/null
+++ b/app/code/Magento/ConfigurableProduct/Pricing/Price/LowestPriceOptionsProvider.php
@@ -0,0 +1,63 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\ConfigurableProduct\Pricing\Price;
+
+use Magento\Catalog\Api\Data\ProductInterface;
+use Magento\Catalog\Model\ResourceModel\Product\LinkedProductSelectBuilderInterface;
+use Magento\Framework\App\ResourceConnection;
+use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory;
+
+/**
+ * Retrieve list of products where each product contains lower price than others at least for one possible price type
+ */
+class LowestPriceOptionsProvider implements LowestPriceOptionsProviderInterface
+{
+    /**
+     * @var ResourceConnection
+     */
+    private $resource;
+
+    /**
+     * @var LinkedProductSelectBuilderInterface
+     */
+    private $linkedProductSelectBuilder;
+
+    /**
+     * @var CollectionFactory
+     */
+    private $collectionFactory;
+
+    /**
+     * @param ResourceConnection $resourceConnection
+     * @param LinkedProductSelectBuilderInterface $linkedProductSelectBuilder
+     * @param CollectionFactory $collectionFactory
+     */
+    public function __construct(
+        ResourceConnection $resourceConnection,
+        LinkedProductSelectBuilderInterface $linkedProductSelectBuilder,
+        CollectionFactory $collectionFactory
+    ) {
+        $this->resource = $resourceConnection;
+        $this->linkedProductSelectBuilder = $linkedProductSelectBuilder;
+        $this->collectionFactory = $collectionFactory;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getProducts(ProductInterface $product)
+    {
+        $productIds = $this->resource->getConnection()->fetchCol(
+            '(' . implode(') UNION (', $this->linkedProductSelectBuilder->build($product->getId())) . ')'
+        );
+
+        $lowestPriceChildProducts = $this->collectionFactory->create()
+            ->addAttributeToSelect(['price', 'special_price'])
+            ->addIdFilter($productIds)
+            ->getItems();
+        return $lowestPriceChildProducts;
+    }
+}
diff --git a/app/code/Magento/ConfigurableProduct/Pricing/Price/LowestPriceOptionsProviderInterface.php b/app/code/Magento/ConfigurableProduct/Pricing/Price/LowestPriceOptionsProviderInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..c0989a929be55ce46bdaa3451ba88a8a3ae8272a
--- /dev/null
+++ b/app/code/Magento/ConfigurableProduct/Pricing/Price/LowestPriceOptionsProviderInterface.php
@@ -0,0 +1,21 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\ConfigurableProduct\Pricing\Price;
+
+use Magento\Catalog\Api\Data\ProductInterface;
+
+/**
+ * Retrieve list of products where each product contains lower price than others at least for one possible price type
+ * @api
+ */
+interface LowestPriceOptionsProviderInterface
+{
+    /**
+     * @param ProductInterface $product
+     * @return \Magento\Catalog\Api\Data\ProductInterface[]
+     */
+    public function getProducts(\Magento\Catalog\Api\Data\ProductInterface $product);
+}
diff --git a/app/code/Magento/ConfigurableProduct/Pricing/Render/FinalPriceBox.php b/app/code/Magento/ConfigurableProduct/Pricing/Render/FinalPriceBox.php
index 16a296a3554548d31f1692f397cd0124e272a1af..19bf0eee888f181902824505a2808f8ae5106c15 100644
--- a/app/code/Magento/ConfigurableProduct/Pricing/Render/FinalPriceBox.php
+++ b/app/code/Magento/ConfigurableProduct/Pricing/Render/FinalPriceBox.php
@@ -8,6 +8,8 @@ namespace Magento\ConfigurableProduct\Pricing\Render;
 use Magento\Catalog\Pricing\Price\FinalPrice;
 use Magento\Catalog\Pricing\Price\RegularPrice;
 use Magento\ConfigurableProduct\Pricing\Price\ConfigurableOptionsProviderInterface;
+use Magento\ConfigurableProduct\Pricing\Price\LowestPriceOptionsProviderInterface;
+use Magento\Framework\App\ObjectManager;
 use Magento\Framework\Pricing\Price\PriceInterface;
 use Magento\Framework\Pricing\Render\RendererPool;
 use Magento\Framework\Pricing\SaleableInterface;
@@ -16,9 +18,9 @@ use Magento\Framework\View\Element\Template\Context;
 class FinalPriceBox extends \Magento\Catalog\Pricing\Render\FinalPriceBox
 {
     /**
-     * @var ConfigurableOptionsProviderInterface
+     * @var LowestPriceOptionsProviderInterface
      */
-    private $configurableOptionsProvider;
+    private $lowestPriceOptionsProvider;
 
     /**
      * @param Context $context
@@ -27,6 +29,8 @@ class FinalPriceBox extends \Magento\Catalog\Pricing\Render\FinalPriceBox
      * @param RendererPool $rendererPool
      * @param ConfigurableOptionsProviderInterface $configurableOptionsProvider
      * @param array $data
+     * @param LowestPriceOptionsProviderInterface $lowestPriceOptionsProvider
+     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
      */
     public function __construct(
         Context $context,
@@ -34,10 +38,12 @@ class FinalPriceBox extends \Magento\Catalog\Pricing\Render\FinalPriceBox
         PriceInterface $price,
         RendererPool $rendererPool,
         ConfigurableOptionsProviderInterface $configurableOptionsProvider,
-        array $data = []
+        array $data = [],
+        LowestPriceOptionsProviderInterface $lowestPriceOptionsProvider = null
     ) {
-        $this->configurableOptionsProvider = $configurableOptionsProvider;
         parent::__construct($context, $saleableItem, $price, $rendererPool, $data);
+        $this->lowestPriceOptionsProvider = $lowestPriceOptionsProvider ?:
+            ObjectManager::getInstance()->get(LowestPriceOptionsProviderInterface::class);
     }
 
     /**
@@ -48,7 +54,7 @@ class FinalPriceBox extends \Magento\Catalog\Pricing\Render\FinalPriceBox
     public function hasSpecialPrice()
     {
         $product = $this->getSaleableItem();
-        foreach ($this->configurableOptionsProvider->getProducts($product) as $subProduct) {
+        foreach ($this->lowestPriceOptionsProvider->getProducts($product) as $subProduct) {
             $regularPrice = $subProduct->getPriceInfo()->getPrice(RegularPrice::PRICE_CODE)->getValue();
             $finalPrice = $subProduct->getPriceInfo()->getPrice(FinalPrice::PRICE_CODE)->getValue();
             if ($finalPrice < $regularPrice) {
diff --git a/app/code/Magento/ConfigurableProduct/Test/Unit/Block/Plugin/Product/Media/GalleryTest.php b/app/code/Magento/ConfigurableProduct/Test/Unit/Block/Plugin/Product/Media/GalleryTest.php
deleted file mode 100644
index 60aa30c8d40784796192d8c1b7a2ea871e505a25..0000000000000000000000000000000000000000
--- a/app/code/Magento/ConfigurableProduct/Test/Unit/Block/Plugin/Product/Media/GalleryTest.php
+++ /dev/null
@@ -1,111 +0,0 @@
-<?php
-/**
- * Copyright © 2016 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-
-namespace Magento\ConfigurableProduct\Test\Unit\Block\Plugin\Product\Media;
-
-/**
- * Class GalleryTest
- */
-class GalleryTest extends \PHPUnit_Framework_TestCase
-{
-    /**
-     * @var \Magento\ConfigurableProduct\Block\Plugin\Product\Media\Gallery
-     */
-    private $plugin;
-
-    /**
-     * @var \Magento\Framework\Json\EncoderInterface|\PHPUnit_Framework_MockObject_MockObject
-     */
-    private $jsonEncoder;
-
-    /**
-     * @var \Magento\Framework\Json\DecoderInterface|\PHPUnit_Framework_MockObject_MockObject
-     */
-    private $jsonDecoder;
-
-    /**
-     * @var \Magento\Catalog\Model\Product\Gallery\ReadHandler
-     */
-    private $galleryHandler;
-
-    protected function setUp()
-    {
-        $helper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
-        $this->galleryHandler = $this->getMockBuilder(\Magento\Catalog\Model\Product\Gallery\ReadHandler::class)
-            ->disableOriginalConstructor()
-            ->setMethods(['execute'])
-            ->getMock();
-
-        $this->jsonEncoder = $this->getMock(\Magento\Framework\Json\EncoderInterface::class);
-        $this->jsonDecoder = $this->getMock(\Magento\Framework\Json\DecoderInterface::class);
-
-        $productMock = $this->getMockBuilder(\Magento\Catalog\Model\Product::class)
-            ->setMethods(['getTypeId', 'getTypeInstance'])
-            ->disableOriginalConstructor()
-            ->getMock();
-
-        $variationProduct = $this->getMockBuilder(\Magento\Catalog\Model\Product::class)
-            ->setMethods(['setMediaGalleryEntries', 'getSku', 'getMediaGalleryImages', 'getImage', 'getData'])
-            ->disableOriginalConstructor()
-            ->getMock();
-        $image = new \Magento\Framework\DataObject(
-            ['media_type' => 'type', 'video_url' => 'url', 'file' => 'image.jpg']
-        );
-        $variationProduct->expects($this->any())->method('setMediaGalleryEntries')->willReturn([]);
-        $variationProduct->expects($this->any())->method('getSku')->willReturn('sku');
-        $variationProduct->expects($this->any())->method('getMediaGalleryImages')->willReturn([$image]);
-        $variationProduct->expects($this->any())->method('getImage')->willReturn('image.jpg');
-        $variationProduct->expects($this->any())->method('getData')->with('configurable_attribute')->willReturn(1);
-
-        $this->galleryHandler->expects($this->once())->method('execute')->with($variationProduct);
-
-        $configurableType = $this->getMockBuilder(\Magento\ConfigurableProduct\Model\Product\Type\Configurable::class)
-            ->disableOriginalConstructor()
-            ->setMethods(['getUsedProducts', 'getConfigurableAttributesAsArray'])
-            ->getMock();
-        $configurableType->expects($this->any())->method('getUsedProducts')->with($productMock)
-            ->willReturn([$variationProduct]);
-        $configurableType->expects($this->any())->method('getConfigurableAttributesAsArray')->with($productMock)
-            ->willReturn([['attribute_code' => 'configurable_attribute']]);
-
-        $productMock->expects($this->any())->method('getTypeId')->willReturn('configurable');
-        $productMock->expects($this->any())->method('getTypeInstance')->willReturn($configurableType);
-
-        $this->plugin = $helper->getObject(
-            \Magento\ConfigurableProduct\Block\Plugin\Product\Media\Gallery::class,
-            [
-                'productGalleryReadHandler' => $this->galleryHandler,
-                'jsonEncoder' => $this->jsonEncoder,
-                'jsonDecoder' => $this->jsonDecoder
-            ]
-        );
-        $this->plugin->setData('product', $productMock);
-    }
-
-    public function testAfterGetOptions()
-    {
-        $resultJson = '[]';
-        $this->jsonDecoder->expects($this->once())->method('decode')->with('[]')->willReturn([]);
-        $expected = [
-            'configurable_attribute_1' => [
-                [
-                    'mediaType' => 'type',
-                    'videoUrl' => 'url',
-                    'isBase' => true
-                ]
-            ]
-        ];
-        $this->jsonEncoder->expects($this->any())->method('encode')->with($expected)
-            ->willReturn(json_encode($expected));
-
-        $blockMock = $this->getMockBuilder(\Magento\ProductVideo\Block\Product\View\Gallery::class)
-            ->disableOriginalConstructor()
-            ->getMock();
-
-        $result = $this->plugin->afterGetOptionsMediaGalleryDataJson($blockMock, $resultJson);
-        $this->assertEquals(json_encode($expected), $result);
-    }
-}
diff --git a/app/code/Magento/ConfigurableProduct/Test/Unit/Model/LinkManagementTest.php b/app/code/Magento/ConfigurableProduct/Test/Unit/Model/LinkManagementTest.php
index 6b69888e6dd0924cf6e090bdb1eb0af2daddaab1..5a7886ea3ea640c2f276ffb7eedeaa243ff9e790 100644
--- a/app/code/Magento/ConfigurableProduct/Test/Unit/Model/LinkManagementTest.php
+++ b/app/code/Magento/ConfigurableProduct/Test/Unit/Model/LinkManagementTest.php
@@ -6,8 +6,8 @@
 
 namespace Magento\ConfigurableProduct\Test\Unit\Model;
 
+use Magento\ConfigurableProduct\Model\LinkManagement;
 use Magento\ConfigurableProduct\Model\Product\Type\Configurable;
-use Magento\ConfigurableProduct\Test\Unit\Model\Product\ProductExtensionAttributes;
 
 /**
  * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
@@ -146,15 +146,59 @@ class LinkManagementTest extends \PHPUnit_Framework_TestCase
 
         $configurable = $this->getMockBuilder(\Magento\Catalog\Model\Product::class)
             ->disableOriginalConstructor()
+            ->setMethods(['getId', 'getExtensionAttributes'])
+            ->getMock();
+        $simple = $this->getMockBuilder(\Magento\Catalog\Model\Product::class)
+            ->disableOriginalConstructor()
+            ->setMethods(['getId', 'getData'])
             ->getMock();
 
-        $configurable->expects($this->any())->method('getId')->will($this->returnValue(666));
+        $extensionAttributesMock = $this->getMockBuilder(\Magento\Catalog\Api\Data\ProductExtension::class)
+            ->disableOriginalConstructor()
+            ->setMethods([
+                'getConfigurableProductOptions', 'setConfigurableProductOptions', 'setConfigurableProductLinks'
+            ])
+            ->getMock();
+        $optionMock = $this->getMockBuilder(\Magento\ConfigurableProduct\Api\Data\Option::class)
+            ->disableOriginalConstructor()
+            ->setMethods(['getProductAttribute', 'getAttributeId'])
+            ->getMock();
+        $productAttributeMock = $this->getMockBuilder(\Magento\Eav\Model\Entity\Attribute\AbstractAttribute::class)
+            ->disableOriginalConstructor()
+            ->setMethods(['getAttributeCode'])
+            ->getMock();
+        $optionsFactoryMock = $this->getMockBuilder(\Magento\ConfigurableProduct\Helper\Product\Options\Factory::class)
+            ->disableOriginalConstructor()
+            ->setMethods(['create'])
+            ->getMock();
+        $reflectionClass = new \ReflectionClass(\Magento\ConfigurableProduct\Model\LinkManagement::class);
+        $optionsFactoryReflectionProperty = $reflectionClass->getProperty('optionsFactory');
+        $optionsFactoryReflectionProperty->setAccessible(true);
+        $optionsFactoryReflectionProperty->setValue($this->object, $optionsFactoryMock);
 
-        $simple = $this->getMockBuilder(\Magento\Catalog\Model\Product::class)
+        $attributeFactoryMock = $this->getMockBuilder(\Magento\Catalog\Model\ResourceModel\Eav\AttributeFactory::class)
             ->disableOriginalConstructor()
+            ->setMethods(['create'])
             ->getMock();
+        $attributeFactoryReflectionProperty = $reflectionClass->getProperty('attributeFactory');
+        $attributeFactoryReflectionProperty->setAccessible(true);
+        $attributeFactoryReflectionProperty->setValue($this->object, $attributeFactoryMock);
 
-        $simple->expects($this->any())->method('getId')->will($this->returnValue(999));
+        $attributeMock = $this->getMockBuilder(\Magento\Catalog\Model\ResourceModel\Eav\Attribute::class)
+            ->disableOriginalConstructor()
+            ->setMethods(['getCollection', 'getOptions', 'getId', 'getAttributeCode', 'getStoreLabel'])
+            ->getMock();
+        $attributeOptionMock = $this->getMockBuilder(\Magento\Eav\Model\Entity\Attribute\Option::class)
+            ->disableOriginalConstructor()
+            ->setMethods(['getValue', 'getLabel'])
+            ->getMock();
+
+        $attributeCollectionMock = $this->getMockBuilder(
+            \Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable\Attribute\Collection::class
+        )
+            ->disableOriginalConstructor()
+            ->setMethods(['addFieldToFilter', 'getItems'])
+            ->getMock();
 
         $this->productRepository->expects($this->at(0))->method('get')->with($productSku)->willReturn($configurable);
         $this->productRepository->expects($this->at(1))->method('get')->with($childSku)->willReturn($simple);
@@ -164,15 +208,30 @@ class LinkManagementTest extends \PHPUnit_Framework_TestCase
                 $this->returnValue([0 => [1, 2, 3]])
             );
 
-        $extensionAttributes = $this->getMockBuilder(ProductExtensionAttributes::class)
-            ->setMethods(['setConfigurableProductLinks'])
-            ->disableOriginalConstructor()
-            ->getMockForAbstractClass();
+        $configurable->expects($this->any())->method('getId')->will($this->returnValue(666));
+        $simple->expects($this->any())->method('getId')->will($this->returnValue(999));
+
+        $configurable->expects($this->any())->method('getExtensionAttributes')->willReturn($extensionAttributesMock);
+        $extensionAttributesMock->expects($this->any())
+            ->method('getConfigurableProductOptions')
+            ->willReturn([$optionMock]);
+        $optionMock->expects($this->any())->method('getProductAttribute')->willReturn($productAttributeMock);
+        $productAttributeMock->expects($this->any())->method('getAttributeCode')->willReturn('color');
+        $simple->expects($this->any())->method('getData')->willReturn('color');
+        $optionMock->expects($this->any())->method('getAttributeId')->willReturn('1');
 
-        $configurable->expects($this->once())->method('getExtensionAttributes')->willReturn($extensionAttributes);
-        $extensionAttributes->expects($this->once())->method('setConfigurableProductLinks')->willReturnSelf();
+        $optionsFactoryMock->expects($this->any())->method('create')->willReturn([$optionMock]);
+        $attributeFactoryMock->expects($this->any())->method('create')->willReturn($attributeMock);
+        $attributeMock->expects($this->any())->method('getCollection')->willReturn($attributeCollectionMock);
+        $attributeCollectionMock->expects($this->any())->method('addFieldToFilter')->willReturnSelf();
+        $attributeCollectionMock->expects($this->any())->method('getItems')->willReturn([$attributeMock]);
 
-        $configurable->expects($this->once())->method('save');
+        $attributeMock->expects($this->any())->method('getOptions')->willReturn([$attributeOptionMock]);
+
+        $extensionAttributesMock->expects($this->any())->method('setConfigurableProductOptions');
+        $extensionAttributesMock->expects($this->any())->method('setConfigurableProductLinks');
+
+        $this->productRepository->expects($this->once())->method('save');
 
         $this->assertTrue(true, $this->object->addChild($productSku, $childSku));
     }
@@ -243,15 +302,13 @@ class LinkManagementTest extends \PHPUnit_Framework_TestCase
         $productType->expects($this->once())->method('getUsedProducts')
             ->will($this->returnValue([$option]));
 
-        $extensionAttributes = $this->getMockBuilder(ProductExtensionAttributes::class)
+        $extensionAttributesMock = $this->getMockBuilder(\Magento\Framework\Api\ExtensionAttributesInterface::class)
             ->setMethods(['setConfigurableProductLinks'])
             ->disableOriginalConstructor()
             ->getMockForAbstractClass();
 
-        $product->expects($this->once())->method('getExtensionAttributes')->willReturn($extensionAttributes);
-        $extensionAttributes->expects($this->once())->method('setConfigurableProductLinks')->willReturnSelf();
-
-        $product->expects($this->once())->method('save');
+        $product->expects($this->once())->method('getExtensionAttributes')->willReturn($extensionAttributesMock);
+        $this->productRepository->expects($this->once())->method('save');
         $this->assertTrue($this->object->removeChild($productSku, $childSku));
     }
 
diff --git a/app/code/Magento/ConfigurableProduct/Test/Unit/Pricing/Price/ConfigurablePriceResolverTest.php b/app/code/Magento/ConfigurableProduct/Test/Unit/Pricing/Price/ConfigurablePriceResolverTest.php
index 0e2cfc0630226d500db55db0fd0fb0b60bb4d121..8db61bb5e0a4322ff3d614348616dfc0e2f34e27 100644
--- a/app/code/Magento/ConfigurableProduct/Test/Unit/Pricing/Price/ConfigurablePriceResolverTest.php
+++ b/app/code/Magento/ConfigurableProduct/Test/Unit/Pricing/Price/ConfigurablePriceResolverTest.php
@@ -5,13 +5,15 @@
  */
 namespace Magento\ConfigurableProduct\Test\Unit\Pricing\Price;
 
-use Magento\ConfigurableProduct\Pricing\Price\ConfigurableOptionsProviderInterface;
+use Magento\ConfigurableProduct\Pricing\Price\LowestPriceOptionsProviderInterface;
 use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
 
 class ConfigurablePriceResolverTest extends \PHPUnit_Framework_TestCase
 {
-    /** @var  ConfigurableOptionsProviderInterface */
-    private $cofigurableOptionProvider;
+    /**
+     * @var LowestPriceOptionsProviderInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $lowestPriceOptionsProvider;
 
     /**
      * @var \Magento\ConfigurableProduct\Pricing\Price\ConfigurablePriceResolver
@@ -19,12 +21,12 @@ class ConfigurablePriceResolverTest extends \PHPUnit_Framework_TestCase
     protected $resolver;
 
     /**
-     * @var PHPUnit_Framework_MockObject_MockObject | \Magento\ConfigurableProduct\Model\Product\Type\Configurable
+     * @var \PHPUnit_Framework_MockObject_MockObject | \Magento\ConfigurableProduct\Model\Product\Type\Configurable
      */
     protected $configurable;
 
     /**
-     * @var PHPUnit_Framework_MockObject_MockObject | \Magento\ConfigurableProduct\Pricing\Price\PriceResolverInterface
+     * @var \PHPUnit_Framework_MockObject_MockObject | \Magento\ConfigurableProduct\Pricing\Price\PriceResolverInterface
      */
     protected $priceResolver;
 
@@ -36,8 +38,7 @@ class ConfigurablePriceResolverTest extends \PHPUnit_Framework_TestCase
         $className = \Magento\ConfigurableProduct\Pricing\Price\PriceResolverInterface::class;
         $this->priceResolver = $this->getMockForAbstractClass($className, [], '', false, true, true, ['resolvePrice']);
 
-        $this->cofigurableOptionProvider = $this->getMockBuilder(ConfigurableOptionsProviderInterface::class)
-            ->disableOriginalConstructor()->getMock();
+        $this->lowestPriceOptionsProvider = $this->getMock(LowestPriceOptionsProviderInterface::class);
 
         $objectManager = new ObjectManager($this);
         $this->resolver = $objectManager->getObject(
@@ -45,7 +46,7 @@ class ConfigurablePriceResolverTest extends \PHPUnit_Framework_TestCase
             [
                 'priceResolver' => $this->priceResolver,
                 'configurable' => $this->configurable,
-                'configurableOptionsProvider' => $this->cofigurableOptionProvider,
+                'lowestPriceOptionsProvider' => $this->lowestPriceOptionsProvider,
             ]
         );
     }
@@ -63,7 +64,7 @@ class ConfigurablePriceResolverTest extends \PHPUnit_Framework_TestCase
 
         $product->expects($this->once())->method('getSku')->willReturn('Kiwi');
 
-        $this->cofigurableOptionProvider->expects($this->once())->method('getProducts')->willReturn([]);
+        $this->lowestPriceOptionsProvider->expects($this->once())->method('getProducts')->willReturn([]);
 
         $this->resolver->resolvePrice($product);
     }
@@ -83,8 +84,11 @@ class ConfigurablePriceResolverTest extends \PHPUnit_Framework_TestCase
 
         $product->expects($this->never())->method('getSku');
 
-        $this->cofigurableOptionProvider->expects($this->once())->method('getProducts')->willReturn([$product]);
-        $this->priceResolver->expects($this->atLeastOnce())->method('resolvePrice')->willReturn($price);
+        $this->lowestPriceOptionsProvider->expects($this->once())->method('getProducts')->willReturn([$product]);
+        $this->priceResolver->expects($this->once())
+            ->method('resolvePrice')
+            ->with($product)
+            ->willReturn($price);
 
         $this->assertEquals($expectedValue, $this->resolver->resolvePrice($product));
     }
diff --git a/app/code/Magento/ConfigurableProduct/Test/Unit/Pricing/Render/FinalPriceBoxTest.php b/app/code/Magento/ConfigurableProduct/Test/Unit/Pricing/Render/FinalPriceBoxTest.php
index 4dbcfed5315252c62494b6ede30d4d14f9a598b2..b102e1d81f48ea421ce29a7cd914a758e94ccb68 100644
--- a/app/code/Magento/ConfigurableProduct/Test/Unit/Pricing/Render/FinalPriceBoxTest.php
+++ b/app/code/Magento/ConfigurableProduct/Test/Unit/Pricing/Render/FinalPriceBoxTest.php
@@ -7,8 +7,9 @@ namespace Magento\ConfigurableProduct\Test\Unit\Pricing\Render;
 
 use Magento\Catalog\Pricing\Price\FinalPrice;
 use Magento\Catalog\Pricing\Price\RegularPrice;
-use Magento\ConfigurableProduct\Pricing\Price\ConfigurableOptionsProviderInterface;
+use Magento\ConfigurableProduct\Pricing\Price\LowestPriceOptionsProviderInterface;
 use Magento\ConfigurableProduct\Pricing\Render\FinalPriceBox;
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
 
 class FinalPriceBoxTest extends \PHPUnit_Framework_TestCase
 {
@@ -33,9 +34,9 @@ class FinalPriceBoxTest extends \PHPUnit_Framework_TestCase
     private $rendererPool;
 
     /**
-     * @var ConfigurableOptionsProviderInterface|\PHPUnit_Framework_MockObject_MockObject
+     * @var LowestPriceOptionsProviderInterface|\PHPUnit_Framework_MockObject_MockObject
      */
-    private $configurableOptionsProvider;
+    private $lowestPriceOptionsProvider;
 
     /**
      * @var FinalPriceBox
@@ -59,15 +60,18 @@ class FinalPriceBoxTest extends \PHPUnit_Framework_TestCase
             ->disableOriginalConstructor()
             ->getMock();
 
-        $this->configurableOptionsProvider = $this->getMockBuilder(ConfigurableOptionsProviderInterface::class)
+        $this->lowestPriceOptionsProvider = $this->getMockBuilder(LowestPriceOptionsProviderInterface::class)
             ->getMockForAbstractClass();
 
-        $this->model = new FinalPriceBox(
-            $this->context,
-            $this->saleableItem,
-            $this->price,
-            $this->rendererPool,
-            $this->configurableOptionsProvider
+        $this->model = (new ObjectManager($this))->getObject(
+            FinalPriceBox::class,
+            [
+                'context' => $this->context,
+                'saleableItem' => $this->saleableItem,
+                'price' => $this->price,
+                'rendererPool' => $this->rendererPool,
+                'lowestPriceOptionsProvider' => $this->lowestPriceOptionsProvider,
+            ]
         );
     }
 
@@ -115,7 +119,7 @@ class FinalPriceBoxTest extends \PHPUnit_Framework_TestCase
             ->method('getPriceInfo')
             ->willReturn($priceInfoMock);
 
-        $this->configurableOptionsProvider->expects($this->once())
+        $this->lowestPriceOptionsProvider->expects($this->once())
             ->method('getProducts')
             ->with($this->saleableItem)
             ->willReturn([$productMock]);
diff --git a/app/code/Magento/ConfigurableProduct/composer.json b/app/code/Magento/ConfigurableProduct/composer.json
index 8dda841250ff126d0fed90a03dd4272169266392..755b94a600a099a0ada188d435f3682cf6736e69 100644
--- a/app/code/Magento/ConfigurableProduct/composer.json
+++ b/app/code/Magento/ConfigurableProduct/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-configurable-product",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-store": "100.2.*",
         "magento/module-catalog": "101.1.*",
         "magento/module-catalog-inventory": "100.2.*",
diff --git a/app/code/Magento/ConfigurableProduct/etc/di.xml b/app/code/Magento/ConfigurableProduct/etc/di.xml
index 89b271de838f992e9acd93ecdd27bc321f59d54e..ca06ce5cc974bbab05232bdee33920ba87918ade 100644
--- a/app/code/Magento/ConfigurableProduct/etc/di.xml
+++ b/app/code/Magento/ConfigurableProduct/etc/di.xml
@@ -13,6 +13,7 @@
     <preference for="Magento\ConfigurableProduct\Api\Data\OptionValueInterface" type="Magento\ConfigurableProduct\Model\Product\Type\Configurable\OptionValue" />
     <preference for="Magento\ConfigurableProduct\Api\Data\ConfigurableItemOptionValueInterface" type="Magento\ConfigurableProduct\Model\Quote\Item\ConfigurableItemOptionValue" />
     <preference for="Magento\ConfigurableProduct\Pricing\Price\ConfigurableOptionsProviderInterface" type="Magento\ConfigurableProduct\Pricing\Price\ConfigurableOptionsProvider" />
+    <preference for="Magento\ConfigurableProduct\Pricing\Price\LowestPriceOptionsProviderInterface" type="Magento\ConfigurableProduct\Pricing\Price\LowestPriceOptionsProvider" />
 
     <type name="Magento\CatalogInventory\Model\Quote\Item\QuantityValidator\Initializer\Option">
         <plugin name="configurable_product" type="Magento\ConfigurableProduct\Model\Quote\Item\QuantityValidator\Initializer\Option\Plugin\ConfigurableProduct" sortOrder="50" />
@@ -142,9 +143,6 @@
     <type name="Magento\Catalog\Model\Product\Attribute\Backend\Price">
         <plugin name="configurable" type="Magento\ConfigurableProduct\Model\Plugin\PriceBackend" sortOrder="100" />
     </type>
-    <type name="\Magento\ProductVideo\Block\Product\View\Gallery">
-        <plugin name="product_video_gallery" type="\Magento\ConfigurableProduct\Block\Plugin\Product\Media\Gallery" />
-    </type>
     <type name="Magento\ConfigurableProduct\Model\Product\Type\Configurable">
         <arguments>
             <argument name="cache" xsi:type="object">Magento\Framework\App\Cache\Type\Collection</argument>
diff --git a/app/code/Magento/Contact/composer.json b/app/code/Magento/Contact/composer.json
index b541f1e7a0ed3afe8f8bfb8c25b7f27282bc9372..377e46256c0886c5479cbe256451310bac14b896 100644
--- a/app/code/Magento/Contact/composer.json
+++ b/app/code/Magento/Contact/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-contact",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-config": "100.2.*",
         "magento/module-store": "100.2.*",
         "magento/module-customer": "100.2.*",
diff --git a/app/code/Magento/Cookie/composer.json b/app/code/Magento/Cookie/composer.json
index 5222975723385a48adf043f695c08e319f11d57b..96a050f2ad20dfa94958fd11f7a24cfb73010642 100644
--- a/app/code/Magento/Cookie/composer.json
+++ b/app/code/Magento/Cookie/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-cookie",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-store": "100.2.*",
         "magento/framework": "100.2.*"
     },
diff --git a/app/code/Magento/Cron/composer.json b/app/code/Magento/Cron/composer.json
index b1155c028f91971b5508269a06ebef675032e5b5..75a7ce27a2aa110d55398a0588ae4f4907c724c2 100644
--- a/app/code/Magento/Cron/composer.json
+++ b/app/code/Magento/Cron/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-cron",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-store": "100.2.*",
         "magento/framework": "100.2.*"
     },
diff --git a/app/code/Magento/CurrencySymbol/composer.json b/app/code/Magento/CurrencySymbol/composer.json
index 2cdfedadf7a38c7c792a27de4498772cc59c692b..29f0bd7435eef99279f54273163f17041d64a351 100644
--- a/app/code/Magento/CurrencySymbol/composer.json
+++ b/app/code/Magento/CurrencySymbol/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-currency-symbol",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-config": "100.2.*",
         "magento/module-store": "100.2.*",
         "magento/module-page-cache": "100.2.*",
diff --git a/app/code/Magento/Customer/Block/Account/AuthorizationLink.php b/app/code/Magento/Customer/Block/Account/AuthorizationLink.php
index f2e2f1d0bd77f24408dc3f9f7492efce5775fe18..9cb3f8fdd94d613747595b3f03e3a492e6c0d342 100644
--- a/app/code/Magento/Customer/Block/Account/AuthorizationLink.php
+++ b/app/code/Magento/Customer/Block/Account/AuthorizationLink.php
@@ -6,13 +6,14 @@
 namespace Magento\Customer\Block\Account;
 
 use Magento\Customer\Model\Context;
+use Magento\Customer\Block\Account\SortLinkInterface;
 
 /**
  * Customer authorization link
  *
  * @SuppressWarnings(PHPMD.DepthOfInheritance)
  */
-class AuthorizationLink extends \Magento\Framework\View\Element\Html\Link
+class AuthorizationLink extends \Magento\Framework\View\Element\Html\Link implements SortLinkInterface
 {
     /**
      * Customer session
@@ -88,4 +89,12 @@ class AuthorizationLink extends \Magento\Framework\View\Element\Html\Link
     {
         return $this->httpContext->getValue(Context::CONTEXT_AUTH);
     }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getSortOrder()
+    {
+        return $this->getData(self::SORT_ORDER);
+    }
 }
diff --git a/app/code/Magento/Customer/Block/Account/Delimiter.php b/app/code/Magento/Customer/Block/Account/Delimiter.php
new file mode 100644
index 0000000000000000000000000000000000000000..31ded827184eb810cbffba562d2e1b388e573c5f
--- /dev/null
+++ b/app/code/Magento/Customer/Block/Account/Delimiter.php
@@ -0,0 +1,21 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Customer\Block\Account;
+
+/**
+ * Class for delimiter.
+ */
+class Delimiter extends \Magento\Framework\View\Element\Template implements SortLinkInterface
+{
+    /**
+     * {@inheritdoc}
+     */
+    public function getSortOrder()
+    {
+        return $this->getData(self::SORT_ORDER);
+    }
+}
diff --git a/app/code/Magento/Customer/Block/Account/Link.php b/app/code/Magento/Customer/Block/Account/Link.php
index 59961971a0ca8c697980f621e7b3777bd7569823..d37a9a548d44ffd5ef97ea0da05ee17a7149b38b 100644
--- a/app/code/Magento/Customer/Block/Account/Link.php
+++ b/app/code/Magento/Customer/Block/Account/Link.php
@@ -5,12 +5,14 @@
  */
 namespace Magento\Customer\Block\Account;
 
+use Magento\Customer\Block\Account\SortLinkInterface;
+
 /**
  * Class Link
  *
  * @SuppressWarnings(PHPMD.DepthOfInheritance)
  */
-class Link extends \Magento\Framework\View\Element\Html\Link
+class Link extends \Magento\Framework\View\Element\Html\Link implements SortLinkInterface
 {
     /**
      * @var \Magento\Customer\Model\Url
@@ -38,4 +40,12 @@ class Link extends \Magento\Framework\View\Element\Html\Link
     {
         return $this->_customerUrl->getAccountUrl();
     }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getSortOrder()
+    {
+        return $this->getData(self::SORT_ORDER);
+    }
 }
diff --git a/app/code/Magento/Customer/Block/Account/Navigation.php b/app/code/Magento/Customer/Block/Account/Navigation.php
new file mode 100644
index 0000000000000000000000000000000000000000..d8644f5565f3b6a8a4318c914719bc6c9fec3867
--- /dev/null
+++ b/app/code/Magento/Customer/Block/Account/Navigation.php
@@ -0,0 +1,47 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Customer\Block\Account;
+
+use \Magento\Framework\View\Element\Html\Links;
+use \Magento\Customer\Block\Account\SortLinkInterface;
+
+/**
+ * Class for sorting links in navigation panels.
+ */
+class Navigation extends Links
+{
+    /**
+     * {@inheritdoc}
+     */
+    public function getLinks()
+    {
+        $links = $this->_layout->getChildBlocks($this->getNameInLayout());
+        $sortableLink = [];
+        foreach ($links as $key => $link) {
+            if ($link instanceof SortLinkInterface) {
+                $sortableLink[] = $link;
+                unset($links[$key]);
+            }
+        }
+
+        usort($sortableLink, [$this, "compare"]);
+        return array_merge($sortableLink, $links);
+    }
+
+    /**
+     * Compare sortOrder in links.
+     *
+     * @param SortLinkInterface $firstLink
+     * @param SortLinkInterface $secondLink
+     * @return int
+     * @SuppressWarnings(PHPMD.UnusedPrivateMethod)
+     */
+    private function compare(SortLinkInterface $firstLink, SortLinkInterface $secondLink)
+    {
+        return ($firstLink->getSortOrder() < $secondLink->getSortOrder());
+    }
+}
diff --git a/app/code/Magento/Customer/Block/Account/SortLink.php b/app/code/Magento/Customer/Block/Account/SortLink.php
new file mode 100644
index 0000000000000000000000000000000000000000..2c60e804b7b216ebd26f8baefb8a3addd3fd9176
--- /dev/null
+++ b/app/code/Magento/Customer/Block/Account/SortLink.php
@@ -0,0 +1,21 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Customer\Block\Account;
+
+/**
+ * Class for sortable links.
+ */
+class SortLink extends \Magento\Framework\View\Element\Html\Link\Current implements SortLinkInterface
+{
+    /**
+     * {@inheritdoc}
+     */
+    public function getSortOrder()
+    {
+        return $this->getData(self::SORT_ORDER);
+    }
+}
diff --git a/app/code/Magento/Customer/Block/Account/SortLinkInterface.php b/app/code/Magento/Customer/Block/Account/SortLinkInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..815f4e5adf2fdc29993ea0bf9743c5049eb84967
--- /dev/null
+++ b/app/code/Magento/Customer/Block/Account/SortLinkInterface.php
@@ -0,0 +1,27 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Customer\Block\Account;
+
+/**
+ * Interface for sortable links.
+ * @api
+ */
+interface SortLinkInterface
+{
+    /**#@+
+     * Constant for confirmation status
+     */
+    const SORT_ORDER = 'sortOrder';
+    /**#@-*/
+
+    /**
+     * Get sort order for block.
+     *
+     * @return int
+     */
+    public function getSortOrder();
+}
diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Index/Save.php b/app/code/Magento/Customer/Controller/Adminhtml/Index/Save.php
index 77bf7af2a4031ac71488b7644225a6c13dc520f2..fd2ceaf09695bfb4a413bc6f680f254ca4edca4c 100644
--- a/app/code/Magento/Customer/Controller/Adminhtml/Index/Save.php
+++ b/app/code/Magento/Customer/Controller/Adminhtml/Index/Save.php
@@ -72,6 +72,7 @@ class Save extends \Magento\Customer\Controller\Adminhtml\Index
     ) {
         $metadataForm = $this->getMetadataForm($entityType, $formCode, $scope);
         $formData = $metadataForm->extractData($this->getRequest(), $scope);
+        $formData = $metadataForm->compactData($formData);
 
         // Initialize additional attributes
         /** @var \Magento\Framework\DataObject $object */
@@ -81,11 +82,6 @@ class Save extends \Magento\Customer\Controller\Adminhtml\Index
             $formData[$attributeCode] = isset($requestData[$attributeCode]) ? $requestData[$attributeCode] : false;
         }
 
-        $result = $metadataForm->compactData($formData);
-
-        // Re-initialize additional attributes
-        $formData = array_replace($formData, $result);
-
         // Unset unused attributes
         $formAttributes = $metadataForm->getAttributes();
         foreach ($formAttributes as $attribute) {
diff --git a/app/code/Magento/Customer/Controller/Section/Load.php b/app/code/Magento/Customer/Controller/Section/Load.php
index 19b361b2c830d763681184b5055f0d477c4641ae..c1ec593e4a7aeec51a53323052aeae62cb7036ff 100644
--- a/app/code/Magento/Customer/Controller/Section/Load.php
+++ b/app/code/Magento/Customer/Controller/Section/Load.php
@@ -5,10 +5,10 @@
  */
 namespace Magento\Customer\Controller\Section;
 
+use Magento\Customer\CustomerData\Section\Identifier;
 use Magento\Customer\CustomerData\SectionPoolInterface;
 use Magento\Framework\App\Action\Context;
 use Magento\Framework\Controller\Result\JsonFactory;
-use Magento\Framework\Exception\LocalizedException;
 
 /**
  * Customer section controller
@@ -22,6 +22,7 @@ class Load extends \Magento\Framework\App\Action\Action
 
     /**
      * @var Identifier
+     * @deprecated
      */
     protected $sectionIdentifier;
 
@@ -30,26 +31,34 @@ class Load extends \Magento\Framework\App\Action\Action
      */
     protected $sectionPool;
 
+    /**
+     * @var \Magento\Framework\Escaper
+     */
+    private $escaper;
+
     /**
      * @param Context $context
      * @param JsonFactory $resultJsonFactory
-     * @param \Magento\Customer\CustomerData\Section\Identifier $sectionIdentifier
+     * @param Identifier $sectionIdentifier
      * @param SectionPoolInterface $sectionPool
+     * @param Escaper $escaper
      */
     public function __construct(
         Context $context,
         JsonFactory $resultJsonFactory,
-        \Magento\Customer\CustomerData\Section\Identifier $sectionIdentifier,
-        SectionPoolInterface $sectionPool
+        Identifier $sectionIdentifier,
+        SectionPoolInterface $sectionPool,
+        \Magento\Framework\Escaper $escaper = null
     ) {
         parent::__construct($context);
         $this->resultJsonFactory = $resultJsonFactory;
         $this->sectionIdentifier = $sectionIdentifier;
         $this->sectionPool = $sectionPool;
+        $this->escaper = $escaper ?: $this->_objectManager->get(\Magento\Framework\Escaper::class);
     }
 
     /**
-     * @return \Magento\Framework\Controller\Result\Json|\Magento\Framework\Controller\Result\Redirect
+     * @return \Magento\Framework\Controller\Result\Json
      */
     public function execute()
     {
@@ -60,7 +69,7 @@ class Load extends \Magento\Framework\App\Action\Action
             $sectionNames = $sectionNames ? array_unique(\explode(',', $sectionNames)) : null;
 
             $updateSectionId = $this->getRequest()->getParam('update_section_id');
-            if ('false' == $updateSectionId) {
+            if ('false' === $updateSectionId) {
                 $updateSectionId = false;
             }
             $response = $this->sectionPool->getSectionsData($sectionNames, (bool)$updateSectionId);
@@ -70,7 +79,7 @@ class Load extends \Magento\Framework\App\Action\Action
                 \Zend\Http\AbstractMessage::VERSION_11,
                 'Bad Request'
             );
-            $response = ['message' => $e->getMessage()];
+            $response = ['message' => $this->escaper->escapeHtml($e->getMessage())];
         }
 
         return $resultJson->setData($response);
diff --git a/app/code/Magento/Customer/Model/ResourceModel/Group.php b/app/code/Magento/Customer/Model/ResourceModel/Group.php
index 7496940fe335067df022976b201e0d4ab85d9211..5fb02997cd73117eda354f2e1bf2617d41b10d77 100644
--- a/app/code/Magento/Customer/Model/ResourceModel/Group.php
+++ b/app/code/Magento/Customer/Model/ResourceModel/Group.php
@@ -129,4 +129,65 @@ class Group extends \Magento\Framework\Model\ResourceModel\Db\VersionControl\Abs
         $group->setCode(substr($group->getCode(), 0, $group::GROUP_CODE_MAX_LENGTH));
         return parent::_beforeSave($group);
     }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function _afterSave(\Magento\Framework\Model\AbstractModel $object)
+    {
+        if ($object->getId() == \Magento\Customer\Model\Group::CUST_GROUP_ALL) {
+            $this->skipReservedId($object);
+        }
+
+        return $this;
+    }
+
+    /**
+     * Here we do not allow to save systems reserved ID.
+     *
+     * @param \Magento\Framework\Model\AbstractModel $object
+     * @throws \Magento\Framework\Exception\LocalizedException
+     * @return void
+     */
+    private function skipReservedId(\Magento\Framework\Model\AbstractModel $object)
+    {
+        $tableFieldsWithoutIdField = $this->getTableFieldsWithoutIdField();
+        $select = $this->getConnection()->select();
+        $select->from(
+            [$this->getMainTable()],
+            $tableFieldsWithoutIdField
+        )
+            ->where('customer_group_id = ?', \Magento\Customer\Model\Group::CUST_GROUP_ALL);
+
+        $query = $this->getConnection()->insertFromSelect(
+            $select,
+            $this->getMainTable(),
+            $tableFieldsWithoutIdField
+        );
+        $this->getConnection()->query($query);
+        $lastInsertId = $this->getConnection()->lastInsertId();
+
+        $query = $this->getConnection()->deleteFromSelect(
+            $select,
+            $this->getMainTable()
+        );
+        $this->getConnection()->query($query);
+
+        $object->setId($lastInsertId);
+    }
+
+    /**
+     * Get main table fields except of ID field.
+     *
+     * @return array
+     */
+    private function getTableFieldsWithoutIdField()
+    {
+        $fields = $this->getConnection()->describeTable($this->getMainTable());
+        if (isset($fields['customer_group_id'])) {
+            unset($fields['customer_group_id']);
+        }
+
+        return array_keys($fields);
+    }
 }
diff --git a/app/code/Magento/Customer/Setup/UpgradeSchema.php b/app/code/Magento/Customer/Setup/UpgradeSchema.php
old mode 100644
new mode 100755
index 18fc9b9f8d597bc3789d0053192497292be807b9..33ec2352e865d0b6fd5cbbde5d9646b5dd92975d
--- a/app/code/Magento/Customer/Setup/UpgradeSchema.php
+++ b/app/code/Magento/Customer/Setup/UpgradeSchema.php
@@ -108,6 +108,96 @@ class UpgradeSchema implements UpgradeSchemaInterface
             );
         }
 
+        if (version_compare($context->getVersion(), '2.0.10', '<')) {
+            $foreignKeys = $this->getForeignKeys($setup);
+            $this->dropForeignKeys($setup, $foreignKeys);
+            $this->alterTables($setup, $foreignKeys);
+            $this->createForeignKeys($setup, $foreignKeys);
+        }
+
         $setup->endSetup();
     }
+
+    /**
+     * @param SchemaSetupInterface $setup
+     * @param array $keys
+     * @return void
+     */
+    private function alterTables(SchemaSetupInterface $setup, array $keys)
+    {
+        $setup->getConnection()->modifyColumn(
+            $setup->getTable('customer_group'),
+            'customer_group_id',
+            [
+                'type' => 'integer',
+                'unsigned' => true,
+                'identity' => true,
+                'nullable' => false
+            ]
+        );
+        foreach ($keys as $key) {
+            $setup->getConnection()->modifyColumn(
+                $key['TABLE_NAME'],
+                $key['COLUMN_NAME'],
+                [
+                    'type' => 'integer',
+                    'unsigned' => true,
+                    'nullable' => false
+                ]
+            );
+        }
+    }
+
+    /**
+     * @param SchemaSetupInterface $setup
+     * @param array $keys
+     * @return void
+     */
+    private function dropForeignKeys(SchemaSetupInterface $setup, array $keys)
+    {
+        foreach ($keys as $key) {
+            $setup->getConnection()->dropForeignKey($key['TABLE_NAME'], $key['FK_NAME']);
+        }
+    }
+
+    /**
+     * @param SchemaSetupInterface $setup
+     * @param array $keys
+     * @return void
+     */
+    private function createForeignKeys(SchemaSetupInterface $setup, array $keys)
+    {
+        foreach ($keys as $key) {
+            $setup->getConnection()->addForeignKey(
+                $key['FK_NAME'],
+                $key['TABLE_NAME'],
+                $key['COLUMN_NAME'],
+                $key['REF_TABLE_NAME'],
+                $key['REF_COLUMN_NAME'],
+                $key['ON_DELETE']
+            );
+        }
+    }
+
+    /**
+     * @param SchemaSetupInterface $setup
+     * @return array
+     */
+    private function getForeignKeys(SchemaSetupInterface $setup)
+    {
+        $foreignKeys = [];
+        $keysTree = $setup->getConnection()->getForeignKeysTree();
+        foreach ($keysTree as $indexes) {
+            foreach ($indexes as $index) {
+                if (
+                    $index['REF_TABLE_NAME'] == $setup->getTable('customer_group')
+                    && $index['REF_COLUMN_NAME'] == 'customer_group_id'
+                ) {
+                    $foreignKeys[] = $index;
+                }
+
+            }
+        }
+        return $foreignKeys;
+    }
 }
diff --git a/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/Index/SaveTest.php b/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/Index/SaveTest.php
index 8fb48fe9f87e76dcf4f5d489a830bb15bf910c79..11fd1b5a7fc3356f54cc1e72b76e111b22446383 100644
--- a/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/Index/SaveTest.php
+++ b/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/Index/SaveTest.php
@@ -304,33 +304,28 @@ class SaveTest extends \PHPUnit_Framework_TestCase
             ],
             'subscription' => $subscription,
         ];
-        $filteredData = [
+        $extractedData = [
             'entity_id' => $customerId,
             'code' => 'value',
             'coolness' => false,
             'disable_auto_group_change' => 'false',
         ];
-        $dataToCompact = [
+        $compactedData = [
             'entity_id' => $customerId,
             'code' => 'value',
             'coolness' => false,
             'disable_auto_group_change' => 'false',
-            CustomerInterface::DEFAULT_BILLING => false,
-            CustomerInterface::DEFAULT_SHIPPING => false,
-            'confirmation' => false,
-            'sendemail_store_id' => false,
-            'extension_attributes' => false,
+            CustomerInterface::DEFAULT_BILLING => 2,
+            CustomerInterface::DEFAULT_SHIPPING => 2
         ];
-        $addressFilteredData = [
+        $addressExtractedData = [
             'entity_id' => $addressId,
-            'default_billing' => 'true',
-            'default_shipping' => 'true',
             'code' => 'value',
             'coolness' => false,
             'region' => 'region',
             'region_id' => 'region_id',
         ];
-        $addressDataToCompact = [
+        $addressCompactedData = [
             'entity_id' => $addressId,
             'default_billing' => 'true',
             'default_shipping' => 'true',
@@ -430,11 +425,11 @@ class SaveTest extends \PHPUnit_Framework_TestCase
         $customerFormMock->expects($this->once())
             ->method('extractData')
             ->with($this->requestMock, 'customer')
-            ->willReturn($filteredData);
+            ->willReturn($extractedData);
         $customerFormMock->expects($this->once())
             ->method('compactData')
-            ->with($dataToCompact)
-            ->willReturn($filteredData);
+            ->with($extractedData)
+            ->willReturn($compactedData);
         $customerFormMock->expects($this->once())
             ->method('getAttributes')
             ->willReturn($attributes);
@@ -445,11 +440,11 @@ class SaveTest extends \PHPUnit_Framework_TestCase
         $customerAddressFormMock->expects($this->once())
             ->method('extractData')
             ->with($this->requestMock, 'address/' . $addressId)
-            ->willReturn($addressFilteredData);
+            ->willReturn($addressExtractedData);
         $customerAddressFormMock->expects($this->once())
             ->method('compactData')
-            ->with($addressDataToCompact)
-            ->willReturn($addressFilteredData);
+            ->with($addressExtractedData)
+            ->willReturn($addressCompactedData);
         $customerAddressFormMock->expects($this->once())
             ->method('getAttributes')
             ->willReturn($attributes);
@@ -625,8 +620,6 @@ class SaveTest extends \PHPUnit_Framework_TestCase
                 '_template_' => '_template_',
                 $addressId => [
                     'entity_id' => $addressId,
-                    'default_billing' => 'false',
-                    'default_shipping' => 'false',
                     'code' => 'value',
                     'coolness' => false,
                     'region' => 'region',
@@ -635,32 +628,12 @@ class SaveTest extends \PHPUnit_Framework_TestCase
             ],
             'subscription' => $subscription,
         ];
-        $filteredData = [
+        $extractedData = [
             'coolness' => false,
             'disable_auto_group_change' => 'false',
         ];
-        $dataToCompact = [
-            'coolness' => false,
-            'disable_auto_group_change' => 'false',
-            CustomerInterface::DEFAULT_BILLING => false,
-            CustomerInterface::DEFAULT_SHIPPING => false,
-            'confirmation' => false,
-            'sendemail_store_id' => false,
-            'extension_attributes' => false,
-        ];
-        $addressFilteredData = [
+        $addressExtractedData = [
             'entity_id' => $addressId,
-            'default_billing' => 'false',
-            'default_shipping' => 'false',
-            'code' => 'value',
-            'coolness' => false,
-            'region' => 'region',
-            'region_id' => 'region_id',
-        ];
-        $addressDataToCompact = [
-            'entity_id' => $addressId,
-            'default_billing' => 'false',
-            'default_shipping' => 'false',
             'code' => 'value',
             'coolness' => false,
             'region' => 'region',
@@ -739,11 +712,11 @@ class SaveTest extends \PHPUnit_Framework_TestCase
         $customerFormMock->expects($this->once())
             ->method('extractData')
             ->with($this->requestMock, 'customer')
-            ->willReturn($filteredData);
+            ->willReturn($extractedData);
         $customerFormMock->expects($this->once())
             ->method('compactData')
-            ->with($dataToCompact)
-            ->willReturn($filteredData);
+            ->with($extractedData)
+            ->willReturn($extractedData);
         $customerFormMock->expects($this->once())
             ->method('getAttributes')
             ->willReturn($attributes);
@@ -754,11 +727,11 @@ class SaveTest extends \PHPUnit_Framework_TestCase
         $customerAddressFormMock->expects($this->once())
             ->method('extractData')
             ->with($this->requestMock, 'address/' . $addressId)
-            ->willReturn($addressFilteredData);
+            ->willReturn($addressExtractedData);
         $customerAddressFormMock->expects($this->once())
             ->method('compactData')
-            ->with($addressDataToCompact)
-            ->willReturn($addressFilteredData);
+            ->with($addressExtractedData)
+            ->willReturn($addressExtractedData);
         $customerAddressFormMock->expects($this->once())
             ->method('getAttributes')
             ->willReturn($attributes);
@@ -910,19 +883,10 @@ class SaveTest extends \PHPUnit_Framework_TestCase
             ],
             'subscription' => $subscription,
         ];
-        $filteredData = [
+        $extractedData = [
             'coolness' => false,
             'disable_auto_group_change' => 'false',
         ];
-        $dataToCompact = [
-            'coolness' => false,
-            'disable_auto_group_change' => 'false',
-            CustomerInterface::DEFAULT_BILLING => false,
-            CustomerInterface::DEFAULT_SHIPPING => false,
-            'confirmation' => false,
-            'sendemail_store_id' => false,
-            'extension_attributes' => false,
-        ];
 
         /** @var AttributeMetadataInterface|\PHPUnit_Framework_MockObject_MockObject $customerFormMock */
         $attributeMock = $this->getMockBuilder(
@@ -971,11 +935,11 @@ class SaveTest extends \PHPUnit_Framework_TestCase
         $customerFormMock->expects($this->once())
             ->method('extractData')
             ->with($this->requestMock, 'customer')
-            ->willReturn($filteredData);
+            ->willReturn($extractedData);
         $customerFormMock->expects($this->once())
             ->method('compactData')
-            ->with($dataToCompact)
-            ->willReturn($filteredData);
+            ->with($extractedData)
+            ->willReturn($extractedData);
         $customerFormMock->expects($this->once())
             ->method('getAttributes')
             ->willReturn($attributes);
@@ -1062,19 +1026,10 @@ class SaveTest extends \PHPUnit_Framework_TestCase
             ],
             'subscription' => $subscription,
         ];
-        $filteredData = [
+        $extractedData = [
             'coolness' => false,
             'disable_auto_group_change' => 'false',
         ];
-        $dataToCompact = [
-            'coolness' => false,
-            'disable_auto_group_change' => 'false',
-            CustomerInterface::DEFAULT_BILLING => false,
-            CustomerInterface::DEFAULT_SHIPPING => false,
-            'confirmation' => false,
-            'sendemail_store_id' => false,
-            'extension_attributes' => false,
-        ];
 
         /** @var AttributeMetadataInterface|\PHPUnit_Framework_MockObject_MockObject $customerFormMock */
         $attributeMock = $this->getMockBuilder(
@@ -1124,11 +1079,11 @@ class SaveTest extends \PHPUnit_Framework_TestCase
         $customerFormMock->expects($this->once())
             ->method('extractData')
             ->with($this->requestMock, 'customer')
-            ->willReturn($filteredData);
+            ->willReturn($extractedData);
         $customerFormMock->expects($this->once())
             ->method('compactData')
-            ->with($dataToCompact)
-            ->willReturn($filteredData);
+            ->with($extractedData)
+            ->willReturn($extractedData);
         $customerFormMock->expects($this->once())
             ->method('getAttributes')
             ->willReturn($attributes);
@@ -1214,18 +1169,9 @@ class SaveTest extends \PHPUnit_Framework_TestCase
             ],
             'subscription' => $subscription,
         ];
-        $filteredData = [
-            'coolness' => false,
-            'disable_auto_group_change' => 'false',
-        ];
-        $dataToCompact = [
+        $extractedData = [
             'coolness' => false,
             'disable_auto_group_change' => 'false',
-            CustomerInterface::DEFAULT_BILLING => false,
-            CustomerInterface::DEFAULT_SHIPPING => false,
-            'confirmation' => false,
-            'sendemail_store_id' => false,
-            'extension_attributes' => false,
         ];
 
         /** @var AttributeMetadataInterface|\PHPUnit_Framework_MockObject_MockObject $customerFormMock */
@@ -1275,11 +1221,11 @@ class SaveTest extends \PHPUnit_Framework_TestCase
         $customerFormMock->expects($this->once())
             ->method('extractData')
             ->with($this->requestMock, 'customer')
-            ->willReturn($filteredData);
+            ->willReturn($extractedData);
         $customerFormMock->expects($this->once())
             ->method('compactData')
-            ->with($dataToCompact)
-            ->willReturn($filteredData);
+            ->with($extractedData)
+            ->willReturn($extractedData);
         $customerFormMock->expects($this->once())
             ->method('getAttributes')
             ->willReturn($attributes);
diff --git a/app/code/Magento/Customer/Test/Unit/Model/AccountManagementTest.php b/app/code/Magento/Customer/Test/Unit/Model/AccountManagementTest.php
index 9eed3d2b044ca166d35703d35e1fd1995e181108..28697fa5cf85faf8bb33dd61c9f5816fc0b60eed 100644
--- a/app/code/Magento/Customer/Test/Unit/Model/AccountManagementTest.php
+++ b/app/code/Magento/Customer/Test/Unit/Model/AccountManagementTest.php
@@ -1146,7 +1146,7 @@ class AccountManagementTest extends \PHPUnit_Framework_TestCase
 
         $storeId = 1;
 
-        mt_srand(mt_rand() + (100000000 * microtime()) % PHP_INT_MAX);
+        mt_srand(mt_rand() + (100000000 * (float)microtime()) % PHP_INT_MAX);
         $hash = md5(uniqid(microtime() . mt_rand(0, mt_getrandmax()), true));
 
         $this->emailNotificationMock->expects($this->once())
@@ -1168,7 +1168,7 @@ class AccountManagementTest extends \PHPUnit_Framework_TestCase
         $templateIdentifier = 'Template Identifier';
         $sender = 'Sender';
 
-        mt_srand(mt_rand() + (100000000 * microtime()) % PHP_INT_MAX);
+        mt_srand(mt_rand() + (100000000 * (float)microtime()) % PHP_INT_MAX);
         $hash = md5(uniqid(microtime() . mt_rand(0, mt_getrandmax()), true));
 
         $this->emailNotificationMock->expects($this->once())
@@ -1194,7 +1194,7 @@ class AccountManagementTest extends \PHPUnit_Framework_TestCase
         $templateIdentifier = 'Template Identifier';
         $sender = 'Sender';
 
-        mt_srand(mt_rand() + (100000000 * microtime()) % PHP_INT_MAX);
+        mt_srand(mt_rand() + (100000000 * (float)microtime()) % PHP_INT_MAX);
         $hash = md5(uniqid(microtime() . mt_rand(0, mt_getrandmax()), true));
 
         $this->prepareInitiatePasswordReset($email, $templateIdentifier, $sender, $storeId, $customerId, $hash);
diff --git a/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/GroupTest.php b/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/GroupTest.php
index 6520556842a79d5ad4fb44f05c7706e6dfacba69..8305114ad70cd1edfb15f6615b39f12ee41d8ec3 100644
--- a/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/GroupTest.php
+++ b/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/GroupTest.php
@@ -9,6 +9,7 @@
 namespace Magento\Customer\Test\Unit\Model\ResourceModel;
 
 use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper;
+use Magento\Framework\Model\ResourceModel\Db\VersionControl\Snapshot;
 
 /**
  * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
@@ -36,6 +37,16 @@ class GroupTest extends \PHPUnit_Framework_TestCase
     /** @var \PHPUnit_Framework_MockObject_MockObject */
     protected $relationProcessorMock;
 
+    /**
+     * @var Snapshot|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $snapshotMock;
+
+    /**
+     * Setting up dependencies.
+     *
+     * @return void
+     */
     protected function setUp()
     {
         $this->resource = $this->getMock(\Magento\Framework\App\ResourceConnection::class, [], [], '', false);
@@ -67,10 +78,18 @@ class GroupTest extends \PHPUnit_Framework_TestCase
             false
         );
 
+        $this->snapshotMock = $this->getMock(
+            \Magento\Framework\Model\ResourceModel\Db\VersionControl\Snapshot::class,
+            [],
+            [],
+            '',
+            false
+        );
+
         $transactionManagerMock = $this->getMock(
             \Magento\Framework\Model\ResourceModel\Db\TransactionManagerInterface::class
         );
-        $transactionManagerMock->expects($this->once())
+        $transactionManagerMock->expects($this->any())
             ->method('start')
             ->willReturn($this->getMock(\Magento\Framework\DB\Adapter\AdapterInterface::class));
         $contextMock->expects($this->once())
@@ -86,10 +105,62 @@ class GroupTest extends \PHPUnit_Framework_TestCase
                 'context' => $contextMock,
                 'groupManagement' => $this->groupManagement,
                 'customersFactory' => $this->customersFactory,
+                'entitySnapshot' => $this->snapshotMock
             ]
         );
     }
 
+    /**
+     * Test for save() method when we try to save entity with system's reserved ID.
+     * 
+     * @return void
+     */
+    public function testSaveWithReservedId()
+    {
+        $expectedId = 55;
+        $this->snapshotMock->expects($this->once())->method('isModified')->willReturn(true);
+        $this->snapshotMock->expects($this->once())->method('registerSnapshot')->willReturnSelf();
+
+        $this->groupModel->expects($this->any())->method('getId')
+            ->willReturn(\Magento\Customer\Model\Group::CUST_GROUP_ALL);
+        $this->groupModel->expects($this->any())->method('getData')
+            ->willReturn([]);
+        $this->groupModel->expects($this->any())->method('isSaveAllowed')
+            ->willReturn(true);
+        $this->groupModel->expects($this->any())->method('getStoredData')
+            ->willReturn([]);
+        $this->groupModel->expects($this->once())->method('setId')
+            ->with($expectedId);
+
+        $dbAdapter = $this->getMockBuilder(\Magento\Framework\DB\Adapter\AdapterInterface::class)
+            ->disableOriginalConstructor()
+            ->setMethods(
+                [
+                    'lastInsertId',
+                    'describeTable',
+                    'update',
+                    'select'
+                ]
+            )
+            ->getMockForAbstractClass();
+        $dbAdapter->expects($this->any())->method('describeTable')->willReturn([]);
+        $dbAdapter->expects($this->any())->method('update')->willReturnSelf();
+        $dbAdapter->expects($this->once())->method('lastInsertId')->willReturn($expectedId);
+        $selectMock = $this->getMockBuilder(\Magento\Framework\DB\Select::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $dbAdapter->expects($this->any())->method('select')->willReturn($selectMock);
+        $selectMock->expects($this->any())->method('from')->willReturnSelf();
+        $this->resource->expects($this->any())->method('getConnection')->willReturn($dbAdapter);
+
+        $this->groupResourceModel->save($this->groupModel);
+    }
+
+    /**
+     * Test for delete() method when we try to save entity with system's reserved ID.
+     *
+     * @return void
+     */
     public function testDelete()
     {
         $dbAdapter = $this->getMock(\Magento\Framework\DB\Adapter\AdapterInterface::class);
diff --git a/app/code/Magento/Customer/composer.json b/app/code/Magento/Customer/composer.json
index 74f0ebc2b5e0026acbdc5061949c10ad04aa8d9c..53e1a270fb3b04a791a368a375ce7e8b1ef62d8d 100644
--- a/app/code/Magento/Customer/composer.json
+++ b/app/code/Magento/Customer/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-customer",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-store": "100.2.*",
         "magento/module-eav": "100.2.*",
         "magento/module-directory": "100.2.*",
diff --git a/app/code/Magento/Customer/etc/di.xml b/app/code/Magento/Customer/etc/di.xml
index b45d00ad0cdddcc1c46645569b92c7848feb8cff..9113895f2e58a2ead7088b54e32e693bf0c1e975 100644
--- a/app/code/Magento/Customer/etc/di.xml
+++ b/app/code/Magento/Customer/etc/di.xml
@@ -55,6 +55,8 @@
                 type="Magento\Customer\Model\Customer\Source\Group" />
     <preference for="Magento\Customer\Model\Customer\Attribute\Source\GroupSourceLoggedInOnlyInterface"
                 type="Magento\Customer\Model\Customer\Attribute\Source\Group"/>
+    <preference for="Magento\Customer\Block\Account\SortLinkInterface"
+                type="Magento\Customer\Block\Account\SortLink"/>
     <type name="Magento\Customer\Model\Session">
         <arguments>
             <argument name="configShare" xsi:type="object">Magento\Customer\Model\Config\Share\Proxy</argument>
diff --git a/app/code/Magento/Customer/etc/module.xml b/app/code/Magento/Customer/etc/module.xml
index fd8307fc36657d8aacc419b2ad48006969cf68f0..f505adb98a0fab653636175a8e10c755521bd706 100644
--- a/app/code/Magento/Customer/etc/module.xml
+++ b/app/code/Magento/Customer/etc/module.xml
@@ -6,7 +6,7 @@
  */
 -->
 <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
-    <module name="Magento_Customer" setup_version="2.0.9">
+    <module name="Magento_Customer" setup_version="2.0.10">
         <sequence>
             <module name="Magento_Eav"/>
             <module name="Magento_Directory"/>
diff --git a/app/code/Magento/Customer/view/frontend/layout/customer_account.xml b/app/code/Magento/Customer/view/frontend/layout/customer_account.xml
index a96dfcd86e542d3ce3bce5fd9fcc39d434c28bcd..0f95cde6798fef89eb7e12673778b84c505029d3 100644
--- a/app/code/Magento/Customer/view/frontend/layout/customer_account.xml
+++ b/app/code/Magento/Customer/view/frontend/layout/customer_account.xml
@@ -9,24 +9,45 @@
     <body>
         <attribute name="class" value="account"/>
         <referenceContainer name="sidebar.main">
-            <block class="Magento\Framework\View\Element\Html\Links" name="customer_account_navigation" before="-" template="Magento_Customer::account/navigation.phtml">
-                <block class="Magento\Framework\View\Element\Html\Link\Current" name="customer-account-navigation-account-link">
+            <block class="Magento\Framework\View\Element\Template" template="Magento_Theme::html/collapsible.phtml" before="-">
+                <arguments>
+                    <argument name="block_css" xsi:type="string">account-nav</argument>
+                </arguments>
+                <block class="Magento\Customer\Block\Account\Navigation" name="customer_account_navigation" before="-">
                     <arguments>
-                        <argument name="label" xsi:type="string" translate="true">Account Dashboard</argument>
-                        <argument name="path" xsi:type="string">customer/account</argument>
-                    </arguments>
-                </block>
-                <block class="Magento\Framework\View\Element\Html\Link\Current" name="customer-account-navigation-account-edit-link">
-                    <arguments>
-                        <argument name="label" xsi:type="string" translate="true">Account Information</argument>
-                        <argument name="path" xsi:type="string">customer/account/edit</argument>
-                    </arguments>
-                </block>
-                <block class="Magento\Framework\View\Element\Html\Link\Current" name="customer-account-navigation-address-link">
-                    <arguments>
-                        <argument name="label" xsi:type="string" translate="true">Address Book</argument>
-                        <argument name="path" xsi:type="string">customer/address</argument>
+                        <argument name="css_class" xsi:type="string">nav items</argument>
                     </arguments>
+                    <block class="Magento\Customer\Block\Account\SortLinkInterface" name="customer-account-navigation-account-link">
+                        <arguments>
+                            <argument name="label" xsi:type="string" translate="true">Account Dashboard</argument>
+                            <argument name="path" xsi:type="string">customer/account</argument>
+                            <argument name="sortOrder" xsi:type="number">250</argument>
+                        </arguments>
+                    </block>
+                    <block class="Magento\Customer\Block\Account\Delimiter" name="customer-account-navigation-delimiter-1" template="Magento_Customer::account/navigation-delimiter.phtml">
+                        <arguments>
+                            <argument name="sortOrder" xsi:type="number">200</argument>
+                        </arguments>
+                    </block>
+                    <block class="Magento\Customer\Block\Account\SortLinkInterface" name="customer-account-navigation-address-link">
+                        <arguments>
+                            <argument name="label" xsi:type="string" translate="true">Address Book</argument>
+                            <argument name="path" xsi:type="string">customer/address</argument>
+                            <argument name="sortOrder" xsi:type="number">190</argument>
+                        </arguments>
+                    </block>
+                    <block class="Magento\Customer\Block\Account\SortLinkInterface" name="customer-account-navigation-account-edit-link">
+                        <arguments>
+                            <argument name="label" xsi:type="string" translate="true">Account Information</argument>
+                            <argument name="path" xsi:type="string">customer/account/edit</argument>
+                            <argument name="sortOrder" xsi:type="number">180</argument>
+                        </arguments>
+                    </block>
+                    <block class="Magento\Customer\Block\Account\Delimiter" name="customer-account-navigation-delimiter-2" template="Magento_Customer::account/navigation-delimiter.phtml">
+                        <arguments>
+                            <argument name="sortOrder" xsi:type="number">130</argument>
+                        </arguments>
+                    </block>
                 </block>
             </block>
         </referenceContainer>
diff --git a/app/code/Magento/Customer/view/frontend/layout/default.xml b/app/code/Magento/Customer/view/frontend/layout/default.xml
index 50580f73a9d3100dc4e17191f9d30804091e12b2..278c16b324da42c07b47c91d73d215e301af842f 100644
--- a/app/code/Magento/Customer/view/frontend/layout/default.xml
+++ b/app/code/Magento/Customer/view/frontend/layout/default.xml
@@ -11,6 +11,7 @@
             <block class="Magento\Customer\Block\Account\Link" name="my-account-link">
                 <arguments>
                     <argument name="label" xsi:type="string" translate="true">My Account</argument>
+                    <argument name="sortOrder" xsi:type="number">110</argument>
                 </arguments>
             </block>
             <block class="Magento\Customer\Block\Account\RegisterLink" name="register-link">
diff --git a/app/code/Magento/Customer/view/frontend/templates/account/navigation-delimiter.phtml b/app/code/Magento/Customer/view/frontend/templates/account/navigation-delimiter.phtml
new file mode 100644
index 0000000000000000000000000000000000000000..bbc80e6686c4f4345286a185c6156a744b6a52f5
--- /dev/null
+++ b/app/code/Magento/Customer/view/frontend/templates/account/navigation-delimiter.phtml
@@ -0,0 +1,9 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+?>
+<li class="nav item">
+    <span class="delimiter"></span>
+</li>
diff --git a/app/code/Magento/CustomerImportExport/composer.json b/app/code/Magento/CustomerImportExport/composer.json
index 533f40c7688e4aa8269bedfe84f5331a772b0b2a..cd02f6dbfb38b46bda32ebdcb87720124eab37e4 100644
--- a/app/code/Magento/CustomerImportExport/composer.json
+++ b/app/code/Magento/CustomerImportExport/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-customer-import-export",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-store": "100.2.*",
         "magento/module-backend": "100.2.*",
         "magento/module-customer": "100.2.*",
diff --git a/app/code/Magento/Deploy/composer.json b/app/code/Magento/Deploy/composer.json
index 856e0d8b3e542a37cdd7fcf7554b9e4e158de245..ed0b8520ca645afa8af2506616f9dccde6965f08 100644
--- a/app/code/Magento/Deploy/composer.json
+++ b/app/code/Magento/Deploy/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-deploy",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/framework": "100.2.*",
         "magento/module-store": "100.2.*",
         "magento/module-require-js": "100.2.*",
diff --git a/app/code/Magento/Developer/Model/View/Asset/PreProcessor/FrontendCompilation.php b/app/code/Magento/Developer/Model/View/Asset/PreProcessor/FrontendCompilation.php
index 4573f15b016fa47bab5cc0fa7c7010644c4ada6e..8cd04f7d1e4c54804ba32c3c8b5235f9da3dd1db 100644
--- a/app/code/Magento/Developer/Model/View/Asset/PreProcessor/FrontendCompilation.php
+++ b/app/code/Magento/Developer/Model/View/Asset/PreProcessor/FrontendCompilation.php
@@ -74,10 +74,6 @@ class FrontendCompilation implements PreProcessorInterface
      */
     public function process(PreProcessor\Chain $chain)
     {
-        $content = $chain->getContent();
-        if (trim($content) !== '') {
-            return;
-        }
 
         try {
             $this->lockerProcess->lockProcess($this->lockName);
@@ -88,7 +84,7 @@ class FrontendCompilation implements PreProcessorInterface
             /** @var FallbackContext $context */
             $context = $chain->getAsset()->getContext();
 
-            $result = $this->processContent($path, $content, $module, $context);
+            $result = $this->processContent($path, $chain->getContent(), $module, $context);
             $chain->setContent($result['content']);
             $chain->setContentType($result['sourceType']);
         } finally {
@@ -107,14 +103,14 @@ class FrontendCompilation implements PreProcessorInterface
      */
     private function processContent($path, $content, $module, FallbackContext $context)
     {
-        $sourceType = '#\.' . preg_quote(pathinfo($path, PATHINFO_EXTENSION), '#') . '$#';
+        $sourceTypePattern = '#\.' . preg_quote(pathinfo($path, PATHINFO_EXTENSION), '#') . '$#';
 
         foreach ($this->alternativeSource->getAlternativesExtensionsNames() as $name) {
             $asset = $this->assetBuilder->setArea($context->getAreaCode())
                 ->setTheme($context->getThemePath())
                 ->setLocale($context->getLocale())
                 ->setModule($module)
-                ->setPath(preg_replace($sourceType, '.' . $name, $path))
+                ->setPath(preg_replace($sourceTypePattern, '.' . $name, $path))
                 ->build();
 
             $processedContent = $this->assetSource->getContent($asset);
@@ -129,7 +125,7 @@ class FrontendCompilation implements PreProcessorInterface
 
         return [
             'content' => $content,
-            'sourceType' => $sourceType
+            'sourceType' => pathinfo($path, PATHINFO_EXTENSION)
         ];
     }
 }
diff --git a/app/code/Magento/Developer/Test/Unit/Model/View/Asset/PreProcessor/FrontendCompilationTest.php b/app/code/Magento/Developer/Test/Unit/Model/View/Asset/PreProcessor/FrontendCompilationTest.php
index 97f0b1d5a6bdb081a47f22884f6dac93b3a743f1..b43d91c5e4dc6bc7768c47b1f8599c73b5855932 100644
--- a/app/code/Magento/Developer/Test/Unit/Model/View/Asset/PreProcessor/FrontendCompilationTest.php
+++ b/app/code/Magento/Developer/Test/Unit/Model/View/Asset/PreProcessor/FrontendCompilationTest.php
@@ -189,38 +189,6 @@ class FrontendCompilationTest extends \PHPUnit_Framework_TestCase
         $frontendCompilation->process($this->getChainMockExpects('', 1, 1, $newContentType));
     }
 
-    /**
-     * Run test for process method (content not empty)
-     */
-    public function testProcessContentNotEmpty()
-    {
-        $chainMock = $this->getChainMock();
-        $assetMock = $this->getAssetMock();
-
-        $chainMock->expects(self::once())
-            ->method('getContent')
-            ->willReturn('test-content');
-
-        $chainMock->expects(self::never())
-            ->method('getAsset')
-            ->willReturn($assetMock);
-
-        $this->lockerProcessMock->expects(self::never())
-            ->method('lockProcess');
-        $this->lockerProcessMock->expects(self::never())
-            ->method('unlockProcess');
-
-        $frontendCompilation = new FrontendCompilation(
-            $this->assetSourceMock,
-            $this->assetBuilderMock,
-            $this->alternativeSourceMock,
-            $this->lockerProcessMock,
-            'lock'
-        );
-
-        $frontendCompilation->process($chainMock);
-    }
-
     /**
      * @return Chain|\PHPUnit_Framework_MockObject_MockObject
      */
diff --git a/app/code/Magento/Developer/composer.json b/app/code/Magento/Developer/composer.json
index 23f6d20c2aab74dc0f23c03f5727aa99379fbf54..73fd1c17750c6749bd0f89cd9fe55939fbe2d419 100644
--- a/app/code/Magento/Developer/composer.json
+++ b/app/code/Magento/Developer/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-developer",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-store": "100.2.*",
         "magento/framework": "100.2.*",
         "magento/module-config": "100.2.*"
diff --git a/app/code/Magento/Dhl/composer.json b/app/code/Magento/Dhl/composer.json
index e88cd535952d628628bbc984137430d5370a6ecd..15ca7882331a145ba1993ded371bd084bc8c83b3 100644
--- a/app/code/Magento/Dhl/composer.json
+++ b/app/code/Magento/Dhl/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-dhl",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-config": "100.2.*",
         "magento/module-store": "100.2.*",
         "magento/module-shipping": "100.2.*",
diff --git a/app/code/Magento/Directory/Model/Country/Postcode/Config/Reader.php b/app/code/Magento/Directory/Model/Country/Postcode/Config/Reader.php
index 9ea0babbfd9982c3e9c5657e218668c384b47501..ed36ad3ace22b232c8071bbb195184066a2ebd50 100644
--- a/app/code/Magento/Directory/Model/Country/Postcode/Config/Reader.php
+++ b/app/code/Magento/Directory/Model/Country/Postcode/Config/Reader.php
@@ -12,7 +12,10 @@ class Reader extends \Magento\Framework\Config\Reader\Filesystem
      *
      * @var array
      */
-    protected $_idAttributes = ['/config/zip' => 'countryCode'];
+    protected $_idAttributes = [
+        '/config/zip' => 'countryCode',
+        '/config/zip/codes/code' => 'id',
+    ];
 
     /**
      * Construct the FileSystem Reader Class
diff --git a/app/code/Magento/Directory/composer.json b/app/code/Magento/Directory/composer.json
index 9b3b253c26a35ed14c4de51c77624a10750ce5f2..82d8bca34da840e57511bb3912c9b531297d9e86 100644
--- a/app/code/Magento/Directory/composer.json
+++ b/app/code/Magento/Directory/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-directory",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-config": "100.2.*",
         "magento/module-store": "100.2.*",
         "magento/module-backend": "100.2.*",
diff --git a/app/code/Magento/Downloadable/Setup/UpgradeSchema.php b/app/code/Magento/Downloadable/Setup/UpgradeSchema.php
new file mode 100755
index 0000000000000000000000000000000000000000..76ed3f2aae275196993757de9a5a91240773a902
--- /dev/null
+++ b/app/code/Magento/Downloadable/Setup/UpgradeSchema.php
@@ -0,0 +1,41 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Downloadable\Setup;
+
+use Magento\Framework\Setup\UpgradeSchemaInterface;
+use Magento\Framework\Setup\ModuleContextInterface;
+use Magento\Framework\Setup\SchemaSetupInterface;
+
+/**
+ * @codeCoverageIgnore
+ */
+class UpgradeSchema implements UpgradeSchemaInterface
+{
+    /**
+     * {@inheritdoc}
+     */
+    public function upgrade(SchemaSetupInterface $setup, ModuleContextInterface $context)
+    {
+        $setup->startSetup();
+
+        if (version_compare($context->getVersion(), '2.0.2', '<')) {
+            $tables = [
+                'catalog_product_index_price_downlod_idx',
+                'catalog_product_index_price_downlod_tmp',
+            ];
+            foreach ($tables as $table) {
+                $setup->getConnection()->modifyColumn(
+                    $setup->getTable($table),
+                    'customer_group_id',
+                    ['type' => 'integer', 'nullable' => false]
+                );
+            }
+        }
+
+        $setup->endSetup();
+    }
+}
diff --git a/app/code/Magento/Downloadable/composer.json b/app/code/Magento/Downloadable/composer.json
index 8d8814740ccd13248b1e7ab903052ca429567ead..ea8eef6436ef9174e9643c742684f29d1129799f 100644
--- a/app/code/Magento/Downloadable/composer.json
+++ b/app/code/Magento/Downloadable/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-downloadable",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-store": "100.2.*",
         "magento/module-catalog": "101.1.*",
         "magento/module-customer": "100.2.*",
diff --git a/app/code/Magento/Downloadable/etc/module.xml b/app/code/Magento/Downloadable/etc/module.xml
index a2fa1d9d569ddd6d4f7a42c9bf47bb449c3ac637..c6fd9c6a982e433d555b18ff5c35965550943e7e 100644
--- a/app/code/Magento/Downloadable/etc/module.xml
+++ b/app/code/Magento/Downloadable/etc/module.xml
@@ -6,7 +6,7 @@
  */
 -->
 <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
-    <module name="Magento_Downloadable" setup_version="2.0.1">
+    <module name="Magento_Downloadable" setup_version="2.0.2">
         <sequence>
             <module name="Magento_Catalog"/>
         </sequence>
diff --git a/app/code/Magento/Downloadable/view/frontend/layout/customer_account.xml b/app/code/Magento/Downloadable/view/frontend/layout/customer_account.xml
index 8d4f13f2bfb160c490ab88f100586d745877d17b..96bcb556edf0dd652b149244ee288f50abff618e 100644
--- a/app/code/Magento/Downloadable/view/frontend/layout/customer_account.xml
+++ b/app/code/Magento/Downloadable/view/frontend/layout/customer_account.xml
@@ -8,10 +8,11 @@
 <page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
     <body>
         <referenceBlock name="customer_account_navigation">
-            <block class="Magento\Framework\View\Element\Html\Link\Current" name="customer-account-navigation-downloadable-products-link">
+            <block class="Magento\Customer\Block\Account\SortLinkInterface" name="customer-account-navigation-downloadable-products-link">
                 <arguments>
                     <argument name="path" xsi:type="string">downloadable/customer/products</argument>
                     <argument name="label" xsi:type="string">My Downloadable Products</argument>
+                    <argument name="sortOrder" xsi:type="number">220</argument>
                 </arguments>
             </block>
         </referenceBlock>
diff --git a/app/code/Magento/DownloadableImportExport/composer.json b/app/code/Magento/DownloadableImportExport/composer.json
index c99a0d6d05b822e792e24a27a69f68f240f8b002..4f95711b279d0f907934fc4cf2bc4b8056ff4817 100644
--- a/app/code/Magento/DownloadableImportExport/composer.json
+++ b/app/code/Magento/DownloadableImportExport/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-downloadable-import-export",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-catalog": "101.1.*",
         "magento/module-import-export": "100.2.*",
         "magento/module-catalog-import-export": "100.2.*",
diff --git a/app/code/Magento/Eav/Model/Entity/Attribute/Source/Table.php b/app/code/Magento/Eav/Model/Entity/Attribute/Source/Table.php
index 9c2aeeec4abf5d2817df474c4a7c1cfbb818df6f..2b5bbc406d4690602acff51e79904a82aaad9151 100644
--- a/app/code/Magento/Eav/Model/Entity/Attribute/Source/Table.php
+++ b/app/code/Magento/Eav/Model/Entity/Attribute/Source/Table.php
@@ -5,6 +5,9 @@
  */
 namespace Magento\Eav\Model\Entity\Attribute\Source;
 
+use Magento\Framework\App\ObjectManager;
+use Magento\Store\Model\StoreManagerInterface;
+
 class Table extends \Magento\Eav\Model\Entity\Attribute\Source\AbstractSource
 {
     /**
@@ -24,6 +27,11 @@ class Table extends \Magento\Eav\Model\Entity\Attribute\Source\AbstractSource
      */
     protected $_attrOptionFactory;
 
+    /**
+     * @var StoreManagerInterface
+     */
+    private $storeManager;
+
     /**
      * @param \Magento\Eav\Model\ResourceModel\Entity\Attribute\Option\CollectionFactory $attrOptionCollectionFactory
      * @param \Magento\Eav\Model\ResourceModel\Entity\Attribute\OptionFactory $attrOptionFactory
@@ -47,24 +55,30 @@ class Table extends \Magento\Eav\Model\Entity\Attribute\Source\AbstractSource
     public function getAllOptions($withEmpty = true, $defaultValues = false)
     {
         $storeId = $this->getAttribute()->getStoreId();
+        if ($storeId === null) {
+            $storeId = $this->getStoreManager()->getStore()->getId();
+        }
         if (!is_array($this->_options)) {
             $this->_options = [];
         }
         if (!is_array($this->_optionsDefault)) {
             $this->_optionsDefault = [];
         }
-        if (!isset($this->_options[$storeId])) {
+        $attributeId = $this->getAttribute()->getId();
+        if (!isset($this->_options[$storeId][$attributeId])) {
             $collection = $this->_attrOptionCollectionFactory->create()->setPositionOrder(
                 'asc'
             )->setAttributeFilter(
-                $this->getAttribute()->getId()
+                $attributeId
             )->setStoreFilter(
-                $this->getAttribute()->getStoreId()
+                $storeId
             )->load();
-            $this->_options[$storeId] = $collection->toOptionArray();
-            $this->_optionsDefault[$storeId] = $collection->toOptionArray('default_value');
+            $this->_options[$storeId][$attributeId] = $collection->toOptionArray();
+            $this->_optionsDefault[$storeId][$attributeId] = $collection->toOptionArray('default_value');
         }
-        $options = $defaultValues ? $this->_optionsDefault[$storeId] : $this->_options[$storeId];
+        $options = $defaultValues
+            ? $this->_optionsDefault[$storeId][$attributeId]
+            : $this->_options[$storeId][$attributeId];
         if ($withEmpty) {
             $options = $this->addEmptyOption($options);
         }
@@ -72,6 +86,20 @@ class Table extends \Magento\Eav\Model\Entity\Attribute\Source\AbstractSource
         return $options;
     }
 
+    /**
+     * Get StoreManager dependency
+     *
+     * @return StoreManagerInterface
+     * @deprecated
+     */
+    private function getStoreManager()
+    {
+        if ($this->storeManager === null) {
+            $this->storeManager = ObjectManager::getInstance()->get(StoreManagerInterface::class);
+        }
+        return $this->storeManager;
+    }
+
     /**
      * Retrieve Option values array by ids
      *
diff --git a/app/code/Magento/Eav/Test/Unit/Model/Entity/Attribute/Source/TableTest.php b/app/code/Magento/Eav/Test/Unit/Model/Entity/Attribute/Source/TableTest.php
index fcae389b8e2e3d6d7e312055a305b4b615734c59..9b893bf9017681b584a611939f1332ee50fbc869 100644
--- a/app/code/Magento/Eav/Test/Unit/Model/Entity/Attribute/Source/TableTest.php
+++ b/app/code/Magento/Eav/Test/Unit/Model/Entity/Attribute/Source/TableTest.php
@@ -6,6 +6,11 @@
 namespace Magento\Eav\Test\Unit\Model\Entity\Attribute\Source;
 
 use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
+use Magento\Eav\Model\Entity\Attribute\Source\AbstractSource;
+use Magento\Eav\Model\Entity\Attribute\AbstractAttribute;
+use Magento\Store\Model\StoreManagerInterface;
+use Magento\Store\Api\Data\StoreInterface;
+use Magento\Eav\Model\ResourceModel\Entity\Attribute\Option\Collection as AttributeOptionCollection;
 
 /**
  * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
@@ -28,6 +33,31 @@ class TableTest extends \PHPUnit_Framework_TestCase
      */
     private $attrOptionFactory;
 
+    /**
+     * @var AbstractSource | \PHPUnit_Framework_MockObject_MockObject
+     */
+    private $sourceMock;
+
+    /**
+     * @var AbstractAttribute | \PHPUnit_Framework_MockObject_MockObject
+     */
+    private $abstractAttributeMock;
+
+    /**
+     * @var StoreManagerInterface | \PHPUnit_Framework_MockObject_MockObject
+     */
+    private $storeManagerMock;
+
+    /**
+     * @var StoreInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $storeMock;
+
+    /**
+     * @var AttributeOptionCollection|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $attributeOptionCollectionMock;
+
     protected function setUp()
     {
         $objectManager = new ObjectManager($this);
@@ -48,6 +78,11 @@ class TableTest extends \PHPUnit_Framework_TestCase
             false
         );
 
+        $this->attributeOptionCollectionMock = $this->getMockBuilder(AttributeOptionCollection::class)
+            ->setMethods(['toOptionArray'])
+            ->disableOriginalConstructor()
+            ->getMock();
+
         $this->attrOptionFactory = $this->getMockBuilder(
             \Magento\Eav\Model\ResourceModel\Entity\Attribute\OptionFactory::class
         )
@@ -55,6 +90,20 @@ class TableTest extends \PHPUnit_Framework_TestCase
             ->disableOriginalConstructor()
             ->getMockForAbstractClass();
 
+        $this->sourceMock = $this->getMockBuilder(AbstractSource::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+
+        $this->abstractAttributeMock = $this->getMockBuilder(AbstractAttribute::class)
+            ->setMethods(
+                [
+                    'getFrontend', 'getAttributeCode', '__wakeup', 'getStoreId',
+                    'getId', 'getIsRequired', 'getEntity', 'getBackend'
+                ]
+            )
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+
         $this->model = $objectManager->getObject(
             \Magento\Eav\Model\Entity\Attribute\Source\Table::class,
             [
@@ -62,6 +111,16 @@ class TableTest extends \PHPUnit_Framework_TestCase
                 'attrOptionFactory' => $this->attrOptionFactory
             ]
         );
+        $this->model->setAttribute($this->abstractAttributeMock);
+
+        $this->storeManagerMock = $this->getMockForAbstractClass(StoreManagerInterface::class);
+        $this->storeMock = $this->getMockForAbstractClass(StoreInterface::class);
+
+        $objectManager->setBackwardCompatibleProperty(
+            $this->model,
+            'storeManager',
+            $this->storeManagerMock
+        );
     }
 
     public function testGetFlatColumns()
@@ -74,25 +133,8 @@ class TableTest extends \PHPUnit_Framework_TestCase
             false
         );
 
-        $abstractAttributeMock = $this->getMock(
-            \Magento\Eav\Model\Entity\Attribute\AbstractAttribute::class,
-            ['getFrontend', 'getAttributeCode', '__wakeup'],
-            [],
-            '',
-            false
-        );
-
-        $abstractAttributeMock->expects(
-            $this->any()
-        )->method(
-            'getFrontend'
-        )->will(
-            $this->returnValue($abstractFrontendMock)
-        );
-
-        $abstractAttributeMock->expects($this->any())->method('getAttributeCode')->will($this->returnValue('code'));
-
-        $this->model->setAttribute($abstractAttributeMock);
+        $this->abstractAttributeMock->expects($this->any())->method('getFrontend')->willReturn(($abstractFrontendMock));
+        $this->abstractAttributeMock->expects($this->any())->method('getAttributeCode')->willReturn('code');
 
         $flatColumns = $this->model->getFlatColumns();
 
@@ -121,25 +163,16 @@ class TableTest extends \PHPUnit_Framework_TestCase
         $storeId = 5;
         $options = [['label' => 'The label', 'value' => 'A value']];
 
-        $attribute = $this->getMock(
-            \Magento\Eav\Model\Entity\Attribute\AbstractAttribute::class,
-            ['getId', 'getStoreId', 'getIsRequired', '__wakeup'],
-            [],
-            '',
-            false
-        );
-        $attribute->expects($this->once())
+        $this->abstractAttributeMock->expects($this->once())
             ->method('getId')
             ->willReturn($attributeId);
-        $attribute->expects($this->once())
+        $this->abstractAttributeMock->expects($this->once())
             ->method('getStoreId')
             ->willReturn($storeId);
-        $attribute->expects($this->any())
+        $this->abstractAttributeMock->expects($this->any())
             ->method('getIsRequired')
             ->willReturn(false);
 
-        $this->model->setAttribute($attribute);
-
         $this->collectionFactory->expects($this->once())
             ->method('create')
             ->willReturnSelf();
@@ -191,22 +224,14 @@ class TableTest extends \PHPUnit_Framework_TestCase
     {
         $attributeId = 1;
         $storeId = 5;
-        $attribute = $this->getMock(
-            \Magento\Eav\Model\Entity\Attribute\AbstractAttribute::class,
-            ['getId', 'getStoreId', '__wakeup'],
-            [],
-            '',
-            false
-        );
-        $attribute->expects($this->once())
+
+        $this->abstractAttributeMock->expects($this->once())
             ->method('getId')
             ->willReturn($attributeId);
-        $attribute->expects($this->once())
+        $this->abstractAttributeMock->expects($this->once())
             ->method('getStoreId')
             ->willReturn($storeId);
 
-        $this->model->setAttribute($attribute);
-
         $this->collectionFactory->expects($this->once())
             ->method('create')
             ->willReturnSelf();
@@ -257,16 +282,13 @@ class TableTest extends \PHPUnit_Framework_TestCase
             ->setMethods([ 'getSelect', 'getStoreId'])
             ->disableOriginalConstructor()
             ->getMockForAbstractClass();
-        $attribute = $this->getMockBuilder(\Magento\Eav\Model\Entity\Attribute\AbstractAttribute::class)
-            ->setMethods(['getAttributeCode', 'getEntity', 'getBackend', 'getId'])
-            ->disableOriginalConstructor()
-            ->getMockForAbstractClass();
-        $attribute->expects($this->any())->method('getAttributeCode')->willReturn($attributeCode);
+
+        $this->abstractAttributeMock->expects($this->any())->method('getAttributeCode')->willReturn($attributeCode);
         $entity = $this->getMockBuilder(\Magento\Eav\Model\Entity\AbstractEntity::class)
             ->setMethods(['getLinkField'])
             ->disableOriginalConstructor()
             ->getMockForAbstractClass();
-        $attribute->expects($this->once())->method('getEntity')->willReturn($entity);
+        $this->abstractAttributeMock->expects($this->once())->method('getEntity')->willReturn($entity);
         $entity->expects($this->once())->method('getLinkField')->willReturn('entity_id');
         $select = $this->getMockBuilder(\Magento\Framework\DB\Select::class)
             ->setMethods(['joinLeft', 'getConnection', 'order'])
@@ -278,9 +300,9 @@ class TableTest extends \PHPUnit_Framework_TestCase
             ->setMethods(['getTable'])
             ->disableOriginalConstructor()
             ->getMockForAbstractClass();
-        $attribute->expects($this->any())->method('getBackend')->willReturn($backend);
+        $this->abstractAttributeMock->expects($this->any())->method('getBackend')->willReturn($backend);
         $backend->expects($this->any())->method('getTable')->willReturn('table_name');
-        $attribute->expects($this->any())->method('getId')->willReturn(1);
+        $this->abstractAttributeMock->expects($this->any())->method('getId')->willReturn(1);
         $collection->expects($this->once())->method('getStoreId')->willReturn(1);
         $connection = $this->getMockBuilder(\Magento\Framework\DB\Adapter\AdapterInterface::class)
             ->disableOriginalConstructor()
@@ -294,11 +316,99 @@ class TableTest extends \PHPUnit_Framework_TestCase
             ->disableOriginalConstructor()
             ->getMock();
         $this->attrOptionFactory->expects($this->once())->method('create')->willReturn($attrOption);
-        $attrOption->expects($this->once())->method('addOptionValueToCollection')->with($collection, $attribute, $expr)
+        $attrOption->expects($this->once())->method('addOptionValueToCollection')
+            ->with($collection, $this->abstractAttributeMock, $expr)
             ->willReturnSelf();
         $select->expects($this->once())->method('order')->with("{$attributeCode} {$dir}");
 
-        $this->model->setAttribute($attribute);
         $this->assertEquals($this->model, $this->model->addValueSortToCollection($collection, $dir));
     }
+
+    /**
+     * @param bool $withEmpty
+     * @param bool $defaultValues
+     * @param array $options
+     * @param array $optionsDefault
+     * @param array $expectedResult
+     * @dataProvider getAllOptionsDataProvider
+     */
+    public function testGetAllOptions(
+        $withEmpty,
+        $defaultValues,
+        array $options,
+        array $optionsDefault,
+        array $expectedResult
+    ) {
+        $storeId = '1';
+        $attributeId = '42';
+
+        $this->abstractAttributeMock->expects($this->once())->method('getStoreId')->willReturn(null);
+
+        $this->storeManagerMock->expects($this->once())->method('getStore')->willReturn($this->storeMock);
+        $this->storeMock->expects($this->once())->method('getId')->willReturn($storeId);
+
+        $this->abstractAttributeMock->expects($this->once())->method('getId')->willReturn($attributeId);
+
+        $this->collectionFactory->expects($this->once())
+            ->method('create')
+            ->willReturnSelf();
+        $this->collectionFactory->expects($this->once())
+            ->method('setPositionOrder')
+            ->willReturnSelf();
+        $this->collectionFactory->expects($this->once())
+            ->method('setAttributeFilter')
+            ->with($attributeId)
+            ->willReturnSelf();
+        $this->collectionFactory->expects($this->once())
+            ->method('setStoreFilter')
+            ->with($storeId)
+            ->willReturnSelf();
+        $this->collectionFactory->expects($this->once())
+            ->method('load')
+            ->willReturn($this->attributeOptionCollectionMock);
+        $this->attributeOptionCollectionMock->expects($this->any())
+            ->method('toOptionArray')
+            ->willReturnMap(
+                [
+                    ['value', $options],
+                    ['default_value', $optionsDefault]
+                ]
+            );
+
+        $this->assertEquals($expectedResult, $this->model->getAllOptions($withEmpty, $defaultValues));
+    }
+
+    /**
+     * @return array
+     */
+    public function getAllOptionsDataProvider()
+    {
+        return [
+            [
+                false,
+                false,
+                [['value' => '16', 'label' => 'black'], ['value' => '17', 'label' => 'white']],
+                [['value' => '16', 'label' => 'blck'], ['value' => '17', 'label' => 'wht']],
+                [['value' => '16', 'label' => 'black'], ['value' => '17', 'label' => 'white']]
+            ],
+            [
+                false,
+                true,
+                [['value' => '16', 'label' => 'black'], ['value' => '17', 'label' => 'white']],
+                [['value' => '16', 'label' => 'blck'], ['value' => '17', 'label' => 'wht']],
+                [['value' => '16', 'label' => 'blck'], ['value' => '17', 'label' => 'wht']]
+            ],
+            [
+                true,
+                false,
+                [['value' => '16', 'label' => 'black'], ['value' => '17', 'label' => 'white']],
+                [['value' => '16', 'label' => 'blck'], ['value' => '17', 'label' => 'wht']],
+                [
+                    ['label' => ' ', 'value' => ''],
+                    ['value' => '16', 'label' => 'black'],
+                    ['value' => '17', 'label' => 'white']
+                ]
+            ]
+        ];
+    }
 }
diff --git a/app/code/Magento/Eav/Test/Unit/Model/ResourceModel/Entity/AttributeTest.php b/app/code/Magento/Eav/Test/Unit/Model/ResourceModel/Entity/AttributeTest.php
index bcad34654b98aa2d6d3844d1a780d585713c8d86..c18af6380a3b71ca7adfd6af5146f853926b419d 100644
--- a/app/code/Magento/Eav/Test/Unit/Model/ResourceModel/Entity/AttributeTest.php
+++ b/app/code/Magento/Eav/Test/Unit/Model/ResourceModel/Entity/AttributeTest.php
@@ -29,7 +29,7 @@ class AttributeTest extends \PHPUnit_Framework_TestCase
     {
         $this->contextMock = $this->getMock(
             \Magento\Framework\Model\Context::class,
-            ['getCacheManager', 'getEventDispatcher', 'getLogger', 'getAppState', 'getActionValidator'],
+            [],
             [],
             '',
             false
diff --git a/app/code/Magento/Eav/composer.json b/app/code/Magento/Eav/composer.json
index 16e62a6434a26aa358a3491d697ce7cd3bb54ad7..9863a89fff5d3d64ccbf8eaa4b3f5691168e0155 100644
--- a/app/code/Magento/Eav/composer.json
+++ b/app/code/Magento/Eav/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-eav",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-store": "100.2.*",
         "magento/module-backend": "100.2.*",
         "magento/module-catalog": "101.1.*",
diff --git a/app/code/Magento/Eav/etc/di.xml b/app/code/Magento/Eav/etc/di.xml
index 0fcba9907cc4d46b76cf0b7e86c2e0e1bf61da5a..2de184b01d7c4673d49cf73f5fe0a35afa7149e2 100644
--- a/app/code/Magento/Eav/etc/di.xml
+++ b/app/code/Magento/Eav/etc/di.xml
@@ -93,9 +93,32 @@
     </virtualType>
     <type name="Magento\Eav\Model\AttributeRepository">
         <arguments>
-            <argument name="collectionProcessor" xsi:type="object">Magento\Framework\Api\SearchCriteria\CollectionProcessor</argument>
+            <argument name="collectionProcessor" xsi:type="object">Magento\Eav\Model\Api\SearchCriteria\AttributeCollectionProcessor</argument>
         </arguments>
     </type>
+    <virtualType name="Magento\Eav\Model\Api\SearchCriteria\AttributeCollectionProcessor" type="Magento\Framework\Api\SearchCriteria\CollectionProcessor">
+        <arguments>
+            <argument name="processors" xsi:type="array">
+                <item name="filters" xsi:type="object">Magento\Eav\Model\Api\SearchCriteria\CollectionProcessor\AttributeFilterProcessor</item>
+                <item name="sorting" xsi:type="object">Magento\Eav\Model\Api\SearchCriteria\CollectionProcessor\AttributeSortingProcessor</item>
+                <item name="pagination" xsi:type="object">Magento\Framework\Api\SearchCriteria\CollectionProcessor\PaginationProcessor</item>
+            </argument>
+        </arguments>
+    </virtualType>
+    <virtualType name="Magento\Eav\Model\Api\SearchCriteria\CollectionProcessor\AttributeFilterProcessor" type="Magento\Framework\Api\SearchCriteria\CollectionProcessor\FilterProcessor">
+        <arguments>
+            <argument name="fieldMapping" xsi:type="array">
+                <item name="attribute_id" xsi:type="string">main_table.attribute_id</item>
+            </argument>
+        </arguments>
+    </virtualType>
+    <virtualType name="Magento\Eav\Model\Api\SearchCriteria\CollectionProcessor\AttributeSortingProcessor" type="Magento\Framework\Api\SearchCriteria\CollectionProcessor\SortingProcessor">
+        <arguments>
+            <argument name="fieldMapping" xsi:type="array">
+                <item name="attribute_id" xsi:type="string">main_table.attribute_id</item>
+            </argument>
+        </arguments>
+    </virtualType>
     <virtualType name="Magento\Eav\Model\Api\SearchCriteria\CollectionProcessor\AttributeSetFilterProcessor" type="Magento\Framework\Api\SearchCriteria\CollectionProcessor\FilterProcessor">
         <arguments>
             <argument name="customFilters" xsi:type="array">
diff --git a/app/code/Magento/Email/composer.json b/app/code/Magento/Email/composer.json
index 33d04b921278d3c57ce0107792c6deef458c73ab..648c984de0bbb6e93d16f84110075dc36909cfda 100644
--- a/app/code/Magento/Email/composer.json
+++ b/app/code/Magento/Email/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-email",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-theme": "100.2.*",
         "magento/module-config": "100.2.*",
         "magento/module-store": "100.2.*",
diff --git a/app/code/Magento/EncryptionKey/composer.json b/app/code/Magento/EncryptionKey/composer.json
index 6d7ff5558734ab1952b59b2e02db4cc5093f9984..11b1c034a76a792cd782be06db484e494764553f 100644
--- a/app/code/Magento/EncryptionKey/composer.json
+++ b/app/code/Magento/EncryptionKey/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-encryption-key",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-config": "100.2.*",
         "magento/module-backend": "100.2.*",
         "magento/framework": "100.2.*"
diff --git a/app/code/Magento/Fedex/composer.json b/app/code/Magento/Fedex/composer.json
index d27d5c1c60d407ce4d1d5b3781b0209c5955a0d4..8d487485c0d210824949657ab7444ba937ef9996 100644
--- a/app/code/Magento/Fedex/composer.json
+++ b/app/code/Magento/Fedex/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-fedex",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-store": "100.2.*",
         "magento/module-shipping": "100.2.*",
         "magento/module-directory": "100.2.*",
diff --git a/app/code/Magento/GiftMessage/composer.json b/app/code/Magento/GiftMessage/composer.json
index 04c620dc36db5829f9c8c6aa8a6aec620d211e95..067bf16017b231977183491ff6a4e8cdf91dfe68 100644
--- a/app/code/Magento/GiftMessage/composer.json
+++ b/app/code/Magento/GiftMessage/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-gift-message",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-store": "100.2.*",
         "magento/module-catalog": "101.1.*",
         "magento/module-checkout": "100.2.*",
diff --git a/app/code/Magento/GoogleAdwords/composer.json b/app/code/Magento/GoogleAdwords/composer.json
index ad3df5c0b8b2621f395acbfe81bfde3c6b7bae27..cacbbe2088c778ff4a3777f129aea263cf9dee79 100644
--- a/app/code/Magento/GoogleAdwords/composer.json
+++ b/app/code/Magento/GoogleAdwords/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-google-adwords",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-store": "100.2.*",
         "magento/module-sales": "100.2.*",
         "magento/framework": "100.2.*"
diff --git a/app/code/Magento/GoogleAnalytics/composer.json b/app/code/Magento/GoogleAnalytics/composer.json
index 4cccc7bd0cbff69369ae852138045ed06a0dbf4a..8653e93d7a98338160895c65011cdc2f7471270f 100644
--- a/app/code/Magento/GoogleAnalytics/composer.json
+++ b/app/code/Magento/GoogleAnalytics/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-google-analytics",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-store": "100.2.*",
         "magento/module-sales": "100.2.*",
         "magento/framework": "100.2.*",
diff --git a/app/code/Magento/GoogleOptimizer/composer.json b/app/code/Magento/GoogleOptimizer/composer.json
index 20a48fc78060b53fb144aa5da405b343ce696063..8c61e9f068ea122b74a7dea02ed5c110d26629b6 100644
--- a/app/code/Magento/GoogleOptimizer/composer.json
+++ b/app/code/Magento/GoogleOptimizer/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-google-optimizer",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-store": "100.2.*",
         "magento/module-google-analytics": "100.2.*",
         "magento/module-catalog": "101.1.*",
diff --git a/app/code/Magento/GroupedImportExport/composer.json b/app/code/Magento/GroupedImportExport/composer.json
index b036a8d5d528bd3959ea66b294d7b51736f7ba2c..50c061e5b56da30c1faf2bfab9439460be6908a3 100644
--- a/app/code/Magento/GroupedImportExport/composer.json
+++ b/app/code/Magento/GroupedImportExport/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-grouped-import-export",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-catalog": "101.1.*",
         "magento/module-import-export": "100.2.*",
         "magento/module-catalog-import-export": "100.2.*",
diff --git a/app/code/Magento/GroupedProduct/composer.json b/app/code/Magento/GroupedProduct/composer.json
index 69aed214284454722708703068de37e3134393f0..0f207eb414789becda0c4e57846f0a48ced13d7a 100644
--- a/app/code/Magento/GroupedProduct/composer.json
+++ b/app/code/Magento/GroupedProduct/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-grouped-product",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-store": "100.2.*",
         "magento/module-catalog": "101.1.*",
         "magento/module-catalog-inventory": "100.2.*",
diff --git a/app/code/Magento/ImportExport/composer.json b/app/code/Magento/ImportExport/composer.json
index 35a088cbd9c91907c3f9f2c434f16cfb86ed57a8..5e403d2180652a6f3565bf03b573abf75310f19f 100644
--- a/app/code/Magento/ImportExport/composer.json
+++ b/app/code/Magento/ImportExport/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-import-export",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-store": "100.2.*",
         "magento/module-backend": "100.2.*",
         "magento/module-eav": "100.2.*",
diff --git a/app/code/Magento/Indexer/composer.json b/app/code/Magento/Indexer/composer.json
index cbaab12f6ee285ac1207f8c01d5ed5ff5af42c07..e80d8a9f7bc90d63dfbbced39431571d73fdc937 100644
--- a/app/code/Magento/Indexer/composer.json
+++ b/app/code/Magento/Indexer/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-indexer",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-backend": "100.2.*",
         "magento/framework": "100.2.*"
     },
diff --git a/app/code/Magento/Integration/composer.json b/app/code/Magento/Integration/composer.json
index 028e56472268abc0e0fcc612107a5bd8072da806..f76d60c957c87d828cc773e96a5edf10266293c9 100644
--- a/app/code/Magento/Integration/composer.json
+++ b/app/code/Magento/Integration/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-integration",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-store": "100.2.*",
         "magento/module-backend": "100.2.*",
         "magento/module-customer": "100.2.*",
diff --git a/app/code/Magento/LayeredNavigation/composer.json b/app/code/Magento/LayeredNavigation/composer.json
index 99299c3e4a32cccd465af4131bc549b033142545..d1d82781bb5c881cceaaf0b8ccdf85fa02c54e86 100644
--- a/app/code/Magento/LayeredNavigation/composer.json
+++ b/app/code/Magento/LayeredNavigation/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-layered-navigation",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-config": "100.2.*",
         "magento/module-catalog": "101.1.*",
         "magento/framework": "100.2.*"
diff --git a/app/code/Magento/Marketplace/composer.json b/app/code/Magento/Marketplace/composer.json
index 2916ff94544bcc46cd59a9e48e9385e89ea6283b..ed79a80bc0c35d81efa3f27867b33846e3a19007 100644
--- a/app/code/Magento/Marketplace/composer.json
+++ b/app/code/Magento/Marketplace/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-marketplace",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/framework": "100.2.*",
         "magento/module-backend": "100.2.*"
     },
diff --git a/app/code/Magento/MediaStorage/composer.json b/app/code/Magento/MediaStorage/composer.json
index fa7858d5b0aff32de7d37f2756aca1891cb15cf7..141e1c19c532cc67f8152459de7e12d50fb0b9d8 100644
--- a/app/code/Magento/MediaStorage/composer.json
+++ b/app/code/Magento/MediaStorage/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-media-storage",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-store": "100.2.*",
         "magento/module-backend": "100.2.*",
         "magento/module-config": "100.2.*",
diff --git a/app/code/Magento/Msrp/composer.json b/app/code/Magento/Msrp/composer.json
index b86374e6be2779d14fd3d2b3e8a4d5b46b1b881f..422aac99869919aa08c31e7ac4edd39d9e0a6f2e 100644
--- a/app/code/Magento/Msrp/composer.json
+++ b/app/code/Magento/Msrp/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-msrp",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-store": "100.2.*",
         "magento/module-catalog": "101.1.*",
         "magento/module-downloadable": "100.2.*",
diff --git a/app/code/Magento/Multishipping/composer.json b/app/code/Magento/Multishipping/composer.json
index 8d9ac91cd05a07b78c19588cbcd34ce3a110cc9f..970c7ea0569a28d226f8f50c419b3d5ee998a17f 100644
--- a/app/code/Magento/Multishipping/composer.json
+++ b/app/code/Magento/Multishipping/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-multishipping",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-store": "100.2.*",
         "magento/module-checkout": "100.2.*",
         "magento/module-sales": "100.2.*",
diff --git a/app/code/Magento/NewRelicReporting/composer.json b/app/code/Magento/NewRelicReporting/composer.json
index 9faa17d454e5072f7dc9ec5473057bfad1533dce..097de6bea926c60644bedefec56adde409f5aa04 100644
--- a/app/code/Magento/NewRelicReporting/composer.json
+++ b/app/code/Magento/NewRelicReporting/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-new-relic-reporting",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-store": "100.2.*",
         "magento/module-backend": "100.2.*",
         "magento/module-customer": "100.2.*",
diff --git a/app/code/Magento/Newsletter/composer.json b/app/code/Magento/Newsletter/composer.json
index 06a278aef6d48692c856f56daf213e4bab162db8..ab5cdd1510a35285d42698ee999737a74b699d54 100644
--- a/app/code/Magento/Newsletter/composer.json
+++ b/app/code/Magento/Newsletter/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-newsletter",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-store": "100.2.*",
         "magento/module-customer": "100.2.*",
         "magento/module-widget": "100.2.*",
diff --git a/app/code/Magento/Newsletter/view/frontend/layout/customer_account.xml b/app/code/Magento/Newsletter/view/frontend/layout/customer_account.xml
index 2daee81846c0bfb211aeb453e5727d4a130cb77c..f1b8340b1b88d1d5b519da4305f44992015948b8 100644
--- a/app/code/Magento/Newsletter/view/frontend/layout/customer_account.xml
+++ b/app/code/Magento/Newsletter/view/frontend/layout/customer_account.xml
@@ -8,10 +8,11 @@
 <page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
     <body>
         <referenceBlock name="customer_account_navigation">
-            <block class="Magento\Framework\View\Element\Html\Link\Current" name="customer-account-navigation-newsletter-subscriptions-link">
+            <block class="Magento\Customer\Block\Account\SortLinkInterface" name="customer-account-navigation-newsletter-subscriptions-link">
                 <arguments>
                     <argument name="path" xsi:type="string">newsletter/manage</argument>
                     <argument name="label" xsi:type="string" translate="true">Newsletter Subscriptions</argument>
+                    <argument name="sortOrder" xsi:type="number">40</argument>
                 </arguments>
             </block>
         </referenceBlock>
diff --git a/app/code/Magento/Newsletter/view/frontend/templates/subscribe.phtml b/app/code/Magento/Newsletter/view/frontend/templates/subscribe.phtml
index fb6989716cd2dfc64d1e97c487e77f3b47afeb35..0ee371c32817649669fe2bc20d88b08e132a9a11 100644
--- a/app/code/Magento/Newsletter/view/frontend/templates/subscribe.phtml
+++ b/app/code/Magento/Newsletter/view/frontend/templates/subscribe.phtml
@@ -10,7 +10,7 @@
 
 ?>
 <div class="block newsletter">
-    <div class="title"><strong>Newsletter</strong></div>
+    <div class="title"><strong><?php /* @escapeNotVerified */ echo __('Newsletter') ?></strong></div>
     <div class="content">
         <form class="form subscribe"
             novalidate
diff --git a/app/code/Magento/OfflinePayments/Block/Info/Checkmo.php b/app/code/Magento/OfflinePayments/Block/Info/Checkmo.php
index 84b6e554d4cfb193e1418f3d9460f9fcc44f6a7d..8616c186555e3e71db0a13a13c648b5c20ff3e0c 100644
--- a/app/code/Magento/OfflinePayments/Block/Info/Checkmo.php
+++ b/app/code/Magento/OfflinePayments/Block/Info/Checkmo.php
@@ -49,20 +49,13 @@ class Checkmo extends \Magento\Payment\Block\Info
     }
 
     /**
-     * Enter description here...
-     *
+     * @deprecated
      * @return $this
      */
     protected function _convertAdditionalData()
     {
-        $details = @unserialize($this->getInfo()->getAdditionalData());
-        if (is_array($details)) {
-            $this->_payableTo = isset($details['payable_to']) ? (string)$details['payable_to'] : '';
-            $this->_mailingAddress = isset($details['mailing_address']) ? (string)$details['mailing_address'] : '';
-        } else {
-            $this->_payableTo = '';
-            $this->_mailingAddress = '';
-        }
+        $this->_payableTo = $this->getInfo()->getAdditionalInformation('payable_to');
+        $this->_mailingAddress = $this->getInfo()->getAdditionalInformation('mailing_address');
         return $this;
     }
 
diff --git a/app/code/Magento/OfflinePayments/Test/Unit/Block/Info/CheckmoTest.php b/app/code/Magento/OfflinePayments/Test/Unit/Block/Info/CheckmoTest.php
index 848cfbae52b25a0b4b202b296f43ae4b79c5c19a..27209fc8d3538a1465e985929ef6adb52408de93 100644
--- a/app/code/Magento/OfflinePayments/Test/Unit/Block/Info/CheckmoTest.php
+++ b/app/code/Magento/OfflinePayments/Test/Unit/Block/Info/CheckmoTest.php
@@ -5,81 +5,118 @@
  */
 namespace Magento\OfflinePayments\Test\Unit\Block\Info;
 
+use Magento\Framework\View\Element\Template\Context;
+use Magento\OfflinePayments\Block\Info\Checkmo;
+use Magento\Payment\Model\Info;
+use PHPUnit_Framework_MockObject_MockObject as MockObject;
+
+/**
+ * CheckmoTest contains list of test for block methods testing
+ */
 class CheckmoTest extends \PHPUnit_Framework_TestCase
 {
     /**
-     * @var \Magento\OfflinePayments\Block\Info\Checkmo
+     * @var Info|MockObject
+     */
+    private $info;
+
+    /**
+     * @var Checkmo
      */
-    protected $_model;
+    private $block;
 
+    /**
+     * @inheritdoc
+     */
     protected function setUp()
     {
-        $context = $this->getMock(\Magento\Framework\View\Element\Template\Context::class, [], [], '', false);
-        $this->_model = new \Magento\OfflinePayments\Block\Info\Checkmo($context);
+        $context = $this->getMockBuilder(Context::class)
+            ->disableOriginalConstructor()
+            ->setMethods([])
+            ->getMock();
+
+        $this->info = $this->getMockBuilder(Info::class)
+            ->disableOriginalConstructor()
+            ->setMethods(['getAdditionalInformation'])
+            ->getMock();
+
+        $this->block = new Checkmo($context);
     }
 
     /**
+     * @covers \Magento\OfflinePayments\Block\Info\Checkmo::getPayableTo
+     * @param array $details
+     * @param string|null $expected
      * @dataProvider getPayableToDataProvider
      */
     public function testGetPayableTo($details, $expected)
     {
-        $info = $this->getMock(\Magento\Payment\Model\Info::class, ['getAdditionalData'], [], '', false);
-        $info->expects($this->once())
-            ->method('getAdditionalData')
-            ->willReturn(serialize($details));
-        $this->_model->setData('info', $info);
+        $this->info->expects(static::at(0))
+            ->method('getAdditionalInformation')
+            ->with('payable_to')
+            ->willReturn($details);
+        $this->block->setData('info', $this->info);
 
-        $this->assertEquals($expected, $this->_model->getPayableTo());
+        static::assertEquals($expected, $this->block->getPayableTo());
     }
 
     /**
+     * Get list of variations for payable configuration option testing
      * @return array
      */
     public function getPayableToDataProvider()
     {
         return [
-            [['payable_to' => 'payable'], 'payable'],
-            ['', '']
+            ['payable_to' => 'payable', 'payable'],
+            ['', null]
         ];
     }
 
     /**
+     * @covers \Magento\OfflinePayments\Block\Info\Checkmo::getMailingAddress
+     * @param array $details
+     * @param string|null $expected
      * @dataProvider getMailingAddressDataProvider
      */
     public function testGetMailingAddress($details, $expected)
     {
-        $info = $this->getMock(\Magento\Payment\Model\Info::class, ['getAdditionalData'], [], '', false);
-        $info->expects($this->once())
-            ->method('getAdditionalData')
-            ->willReturn(serialize($details));
-        $this->_model->setData('info', $info);
+        $this->info->expects(static::at(1))
+            ->method('getAdditionalInformation')
+            ->with('mailing_address')
+            ->willReturn($details);
+        $this->block->setData('info', $this->info);
 
-        $this->assertEquals($expected, $this->_model->getMailingAddress());
+        static::assertEquals($expected, $this->block->getMailingAddress());
     }
 
     /**
+     * Get list of variations for mailing address testing
      * @return array
      */
     public function getMailingAddressDataProvider()
     {
         return [
-            [['mailing_address' => 'blah@blah.com'], 'blah@blah.com'],
-            ['', '']
+            ['mailing_address' => 'blah@blah.com', 'blah@blah.com'],
+            ['mailing_address' => '', null]
         ];
     }
 
+    /**
+     * @covers \Magento\OfflinePayments\Block\Info\Checkmo::getMailingAddress
+     */
     public function testConvertAdditionalDataIsNeverCalled()
     {
-        $info = $this->getMock(\Magento\Payment\Model\Info::class, ['getAdditionalData'], [], '', false);
-        $info->expects($this->once())
-            ->method('getAdditionalData')
-            ->willReturn(serialize(['mailing_address' => 'blah@blah.com']));
-        $this->_model->setData('info', $info);
+        $mailingAddress = 'blah@blah.com';
+        $this->info->expects(static::at(1))
+            ->method('getAdditionalInformation')
+            ->with('mailing_address')
+            ->willReturn($mailingAddress);
+        $this->block->setData('info', $this->info);
 
         // First we set the property $this->_mailingAddress
-        $this->_model->getMailingAddress();
+        $this->block->getMailingAddress();
 
         // And now we get already setted property $this->_mailingAddress
-        $this->assertEquals('blah@blah.com', $this->_model->getMailingAddress());
+        static::assertEquals($mailingAddress, $this->block->getMailingAddress());
     }
 }
diff --git a/app/code/Magento/OfflinePayments/composer.json b/app/code/Magento/OfflinePayments/composer.json
index 52deb08ba3d904a824faa762391ddf67ae29b026..cf728aaa1c5f6a7ea7c36163b021cb378d7df7f0 100644
--- a/app/code/Magento/OfflinePayments/composer.json
+++ b/app/code/Magento/OfflinePayments/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-offline-payments",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-checkout": "100.2.*",
         "magento/module-payment": "100.2.*",
         "magento/framework": "100.2.*"
diff --git a/app/code/Magento/OfflinePayments/view/adminhtml/templates/info/checkmo.phtml b/app/code/Magento/OfflinePayments/view/adminhtml/templates/info/checkmo.phtml
index d5bff77e002d17d5ad8a80349ea646aee0135fa4..8c5cfd50cc110f2f8c61414c14ed2d48965929d6 100644
--- a/app/code/Magento/OfflinePayments/view/adminhtml/templates/info/checkmo.phtml
+++ b/app/code/Magento/OfflinePayments/view/adminhtml/templates/info/checkmo.phtml
@@ -10,7 +10,7 @@
  */
 ?>
 <?php echo $block->escapeHtml($block->getMethod()->getTitle()) ?>
-<?php if ($block->getInfo()->getAdditionalData()): ?>
+<?php if ($block->getInfo()->getAdditionalInformation()): ?>
     <?php if ($block->getPayableTo()): ?>
         <br /><?php echo $block->escapeHtml(__('Make Check payable to: %1', $block->getPayableTo())) ?>
     <?php endif; ?>
diff --git a/app/code/Magento/OfflinePayments/view/adminhtml/templates/info/pdf/checkmo.phtml b/app/code/Magento/OfflinePayments/view/adminhtml/templates/info/pdf/checkmo.phtml
index 6195cdbd776548c229a6d1dfca03c8f4c1b2a61f..5587ac239d37e84a21348cfd994d9d0b73f0ba97 100644
--- a/app/code/Magento/OfflinePayments/view/adminhtml/templates/info/pdf/checkmo.phtml
+++ b/app/code/Magento/OfflinePayments/view/adminhtml/templates/info/pdf/checkmo.phtml
@@ -11,7 +11,7 @@
 ?>
 <?php echo $block->escapeHtml($block->getMethod()->getTitle()) ?>
     {{pdf_row_separator}}
-<?php if ($block->getInfo()->getAdditionalData()): ?>
+<?php if ($block->getInfo()->getAdditionalInformation()): ?>
     {{pdf_row_separator}}
     <?php if ($block->getPayableTo()): ?>
         <?php echo $block->escapeHtml(__('Make Check payable to: %1', $block->getPayableTo())) ?>
diff --git a/app/code/Magento/OfflinePayments/view/frontend/templates/info/checkmo.phtml b/app/code/Magento/OfflinePayments/view/frontend/templates/info/checkmo.phtml
index f0dbff1add32b2fd7d49e3b6ca5f14c4038fc2ca..3c0b6bb23086a67b48de1134cdb245daffeab045 100644
--- a/app/code/Magento/OfflinePayments/view/frontend/templates/info/checkmo.phtml
+++ b/app/code/Magento/OfflinePayments/view/frontend/templates/info/checkmo.phtml
@@ -11,7 +11,7 @@
 ?>
 <dl class="payment-method checkmemo">
     <dt class="title"><?php echo $block->escapeHtml($block->getMethod()->getTitle()) ?></dt>
-    <?php if ($block->getInfo()->getAdditionalData()): ?>
+    <?php if ($block->getInfo()->getAdditionalInformation()): ?>
         <?php if ($block->getPayableTo()): ?>
             <dd class="content">
                 <strong><?php echo $block->escapeHtml(__('Make Check payable to')) ?></strong>
diff --git a/app/code/Magento/OfflineShipping/composer.json b/app/code/Magento/OfflineShipping/composer.json
index 3c959b4dec766fe09cf81df46571051b714ee4e1..b429376c6cd7adc0a70b133a633b4edf068d684e 100644
--- a/app/code/Magento/OfflineShipping/composer.json
+++ b/app/code/Magento/OfflineShipping/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-offline-shipping",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-config": "100.2.*",
         "magento/module-store": "100.2.*",
         "magento/module-backend": "100.2.*",
diff --git a/app/code/Magento/OfflineShipping/etc/adminhtml/system.xml b/app/code/Magento/OfflineShipping/etc/adminhtml/system.xml
index 50ed4cdc9417833683a04e3a715ff828f04b9674..4a4f550588f5366668f4ceee0ff895964246172b 100644
--- a/app/code/Magento/OfflineShipping/etc/adminhtml/system.xml
+++ b/app/code/Magento/OfflineShipping/etc/adminhtml/system.xml
@@ -52,6 +52,7 @@
                 <field id="showmethod" translate="label" type="select" sortOrder="92" showInDefault="1" showInWebsite="1" showInStore="0">
                     <label>Show Method if Not Applicable</label>
                     <source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
+                    <frontend_class>shipping-skip-hide</frontend_class>
                 </field>
                 <field id="specificerrmsg" translate="label" type="textarea" sortOrder="80" showInDefault="1" showInWebsite="1" showInStore="1" canRestore="1">
                     <label>Displayed Error Message</label>
@@ -146,6 +147,7 @@
                 <field id="showmethod" translate="label" type="select" sortOrder="92" showInDefault="1" showInWebsite="1" showInStore="0">
                     <label>Show Method if Not Applicable</label>
                     <source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
+                    <frontend_class>shipping-skip-hide</frontend_class>
                 </field>
                 <field id="specificerrmsg" translate="label" type="textarea" sortOrder="80" showInDefault="1" showInWebsite="1" showInStore="1" canRestore="1">
                     <label>Displayed Error Message</label>
diff --git a/app/code/Magento/PageCache/Model/Config.php b/app/code/Magento/PageCache/Model/Config.php
index 222d9d57e467a31988fd6b6ac221f7ce640c06c5..786165728406f0162be0da04f869a10020d9d3bb 100644
--- a/app/code/Magento/PageCache/Model/Config.php
+++ b/app/code/Magento/PageCache/Model/Config.php
@@ -148,12 +148,17 @@ class Config
             ),
             '/* {{ ips }} */' => $this->_getAccessList(),
             '/* {{ design_exceptions_code }} */' => $this->_getDesignExceptions(),
-            // http headers get transformed by php `X-Forwarded-Proto: https` becomes $SERVER['HTTP_X_FORWARDED_PROTO'] = 'https'
+            // http headers get transformed by php `X-Forwarded-Proto: https`
+            // becomes $SERVER['HTTP_X_FORWARDED_PROTO'] = 'https'
             // Apache and Nginx drop all headers with underlines by default.
-            '/* {{ ssl_offloaded_header }} */' => str_replace('_', '-', $this->_scopeConfig->getValue(
-                \Magento\Framework\HTTP\PhpEnvironment\Request::XML_PATH_OFFLOADER_HEADER,
-                \Magento\Store\Model\ScopeInterface::SCOPE_STORE))
-
+            '/* {{ ssl_offloaded_header }} */' => str_replace(
+                '_',
+                '-',
+                $this->_scopeConfig->getValue(
+                    \Magento\Framework\HTTP\PhpEnvironment\Request::XML_PATH_OFFLOADER_HEADER,
+                    \Magento\Store\Model\ScopeInterface::SCOPE_STORE
+                )
+            )
         ];
     }
 
@@ -176,6 +181,7 @@ class Config
             \Magento\Store\Model\ScopeInterface::SCOPE_STORE
         );
         if (!empty($accessList)) {
+            $result = [];
             $ips = explode(',', $accessList);
             foreach ($ips as $ip) {
                 $result[] = sprintf($tpl, trim($ip));
diff --git a/app/code/Magento/PageCache/composer.json b/app/code/Magento/PageCache/composer.json
index 5c29e4fc3c97081626ae4a77243ccd6ac9843d38..f18eb7bbe94edd31a48c4796dc41b21cdef38a8b 100644
--- a/app/code/Magento/PageCache/composer.json
+++ b/app/code/Magento/PageCache/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-page-cache",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-config": "100.2.*",
         "magento/module-store": "100.2.*",
         "magento/module-backend": "100.2.*",
diff --git a/app/code/Magento/PageCache/etc/events.xml b/app/code/Magento/PageCache/etc/events.xml
index 7ac67a931c7ac8bbbe3b5e397a7ade7b3a039633..8d88feeab18bca0ef4101933f54335d51eed2129 100644
--- a/app/code/Magento/PageCache/etc/events.xml
+++ b/app/code/Magento/PageCache/etc/events.xml
@@ -48,11 +48,6 @@
     <event name="model_save_commit_after">
         <observer name="flush_cache_after_model_save" instance="Magento\PageCache\Observer\FlushCacheByTags" />
     </event>
-    <event name="controller_action_predispatch">
-        <observer name="register_form_key"
-                  instance="Magento\PageCache\Observer\RegisterFormKeyFromCookie"
-                  />
-    </event>
     <event name="customer_logout">
         <observer name="FlushFormKeyOnLogout" instance="Magento\PageCache\Observer\FlushFormKeyOnLogout"/>
     </event>
diff --git a/app/code/Magento/PageCache/etc/frontend/events.xml b/app/code/Magento/PageCache/etc/frontend/events.xml
new file mode 100644
index 0000000000000000000000000000000000000000..10ef2eee02804fea57163ea4103cede60a01d220
--- /dev/null
+++ b/app/code/Magento/PageCache/etc/frontend/events.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0"?>
+<!--
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+-->
+<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
+    <event name="controller_action_predispatch">
+        <observer name="register_form_key" instance="Magento\PageCache\Observer\RegisterFormKeyFromCookie" />
+    </event>
+</config>
diff --git a/app/code/Magento/Payment/composer.json b/app/code/Magento/Payment/composer.json
index 35ff326d916bd43f8ae2366d9b50f5b77fe46dc8..c8d7254ce9e002ced1ecfb1067d821c63dbeb5be 100644
--- a/app/code/Magento/Payment/composer.json
+++ b/app/code/Magento/Payment/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-payment",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-config": "100.2.*",
         "magento/module-store": "100.2.*",
         "magento/module-sales": "100.2.*",
diff --git a/app/code/Magento/Paypal/Model/Payflow/Transparent.php b/app/code/Magento/Paypal/Model/Payflow/Transparent.php
index b5803c5ace3925b75e81df43992f714a74ed9905..f65edd71daa5b82b5191cd20a7f01a4b90b79b8c 100644
--- a/app/code/Magento/Paypal/Model/Payflow/Transparent.php
+++ b/app/code/Magento/Paypal/Model/Payflow/Transparent.php
@@ -186,6 +186,7 @@ class Transparent extends Payflowpro implements TransparentInterface
         $this->createPaymentToken($payment, $token);
 
         $payment->unsAdditionalInformation(self::CC_DETAILS);
+        $payment->unsAdditionalInformation(self::PNREF);
 
         return $this;
     }
diff --git a/app/code/Magento/Paypal/Test/Unit/Model/Payflow/TransparentTest.php b/app/code/Magento/Paypal/Test/Unit/Model/Payflow/TransparentTest.php
index 2d757147cec6a89dc1b6b6b28f283fd29b98f640..e2d5d348dda2cf96da1789806a43814c8960c49a 100644
--- a/app/code/Magento/Paypal/Test/Unit/Model/Payflow/TransparentTest.php
+++ b/app/code/Magento/Paypal/Test/Unit/Model/Payflow/TransparentTest.php
@@ -428,6 +428,13 @@ class TransparentTest extends \PHPUnit_Framework_TestCase
             ->method('setVaultPaymentToken')
             ->with($paymentTokenMock);
 
+        $this->paymentMock->expects($this->at(8))
+            ->method('unsAdditionalInformation')
+            ->with(Transparent::CC_DETAILS);
+        $this->paymentMock->expects($this->at(9))
+            ->method('unsAdditionalInformation')
+            ->with(Transparent::PNREF);
+
         $this->assertSame($this->object, $this->object->authorize($this->paymentMock, 33));
     }
 }
diff --git a/app/code/Magento/Paypal/composer.json b/app/code/Magento/Paypal/composer.json
index bddc5d91a94587f4d26532246d8c83f8de6ba7f7..7503db18f008ca76252f8687df6d52f88dc0e02d 100644
--- a/app/code/Magento/Paypal/composer.json
+++ b/app/code/Magento/Paypal/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-paypal",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-config": "100.2.*",
         "magento/module-store": "100.2.*",
         "magento/module-checkout": "100.2.*",
diff --git a/app/code/Magento/Paypal/etc/adminhtml/system/express_checkout.xml b/app/code/Magento/Paypal/etc/adminhtml/system/express_checkout.xml
index 1876f07830ba7b55df25230bc256b829f65b2fc3..90cb60186e34e3730ae6d068b34e4002add00a6c 100644
--- a/app/code/Magento/Paypal/etc/adminhtml/system/express_checkout.xml
+++ b/app/code/Magento/Paypal/etc/adminhtml/system/express_checkout.xml
@@ -23,7 +23,8 @@
                 <label>Express Checkout</label>
                 <frontend_model>Magento\Paypal\Block\Adminhtml\System\Config\Fieldset\Expanded</frontend_model>
                 <field id="business_account" translate="label comment tooltip" showInDefault="1" showInWebsite="1" sortOrder="5">
-                    <label>Email Associated with PayPal Merchant Account</label>
+                    <label>Email Associated with PayPal Merchant Account (Optional)</label>
+                    <frontend_class>not-required</frontend_class>
                     <comment>
                         <![CDATA[<a href="http://www.magentocommerce.com/paypal">Start accepting payments via PayPal!</a>]]>
                     </comment>
diff --git a/app/code/Magento/Paypal/view/frontend/layout/customer_account.xml b/app/code/Magento/Paypal/view/frontend/layout/customer_account.xml
index 5a355a2c399673ec54e1da9fed67f281c32fa1ab..27fa1511d09be68d350ad74a92146c928cff631c 100644
--- a/app/code/Magento/Paypal/view/frontend/layout/customer_account.xml
+++ b/app/code/Magento/Paypal/view/frontend/layout/customer_account.xml
@@ -11,10 +11,11 @@
     </head>
     <body>
         <referenceBlock name="customer_account_navigation">
-            <block class="Magento\Framework\View\Element\Html\Link\Current" name="customer-account-navigation-billing-agreements-link">
+            <block class="Magento\Customer\Block\Account\SortLinkInterface" name="customer-account-navigation-billing-agreements-link">
                 <arguments>
                     <argument name="path" xsi:type="string">paypal/billing_agreement</argument>
                     <argument name="label" xsi:type="string" translate="true">Billing Agreements</argument>
+                    <argument name="sortOrder" xsi:type="number">140</argument>
                 </arguments>
             </block>
         </referenceBlock>
diff --git a/app/code/Magento/Persistent/composer.json b/app/code/Magento/Persistent/composer.json
index 25cc9d76acd768fe970363628abad60945e418d9..61f77a104c016d23f3734433efd8646bd21b42f4 100644
--- a/app/code/Magento/Persistent/composer.json
+++ b/app/code/Magento/Persistent/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-persistent",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-store": "100.2.*",
         "magento/module-checkout": "100.2.*",
         "magento/module-customer": "100.2.*",
diff --git a/app/code/Magento/Persistent/etc/persistent.xml b/app/code/Magento/Persistent/etc/persistent.xml
index fb67e9d976af40adb4b95a5ba145a7d175995e5d..b4b87cb8e765df3e0dab3dad4a1f5b08fd414209 100644
--- a/app/code/Magento/Persistent/etc/persistent.xml
+++ b/app/code/Magento/Persistent/etc/persistent.xml
@@ -18,7 +18,7 @@
                 <name_in_layout>top.links</name_in_layout>
                 <class>Magento\Persistent\Model\Observer</class>
                 <method>emulateTopLinks</method>
-                <block_type>Magento\Theme\Block\Template\Links</block_type>
+                <block_type>Magento\Customer\Block\Account\Navigation</block_type>
             </reference>
         </blocks>
     </instances>
diff --git a/app/code/Magento/ProductAlert/composer.json b/app/code/Magento/ProductAlert/composer.json
index a43a52209740318e0f5adcc8bea03a8860c04037..9c63c6958a465852ea3148cab659102880b07630 100644
--- a/app/code/Magento/ProductAlert/composer.json
+++ b/app/code/Magento/ProductAlert/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-product-alert",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-backend": "100.2.*",
         "magento/module-store": "100.2.*",
         "magento/module-catalog": "101.1.*",
diff --git a/app/code/Magento/ProductVideo/Controller/Adminhtml/Product/Gallery/RetrieveImage.php b/app/code/Magento/ProductVideo/Controller/Adminhtml/Product/Gallery/RetrieveImage.php
index f0edccbaf812acbf8495d97817515395635af409..7a087f769877160a316635baf9017b8b37ebbd38 100644
--- a/app/code/Magento/ProductVideo/Controller/Adminhtml/Product/Gallery/RetrieveImage.php
+++ b/app/code/Magento/ProductVideo/Controller/Adminhtml/Product/Gallery/RetrieveImage.php
@@ -6,6 +6,7 @@
 namespace Magento\ProductVideo\Controller\Adminhtml\Product\Gallery;
 
 use Magento\Framework\App\Filesystem\DirectoryList;
+use Magento\Framework\Exception\LocalizedException;
 use Magento\Framework\File\Uploader;
 
 /**
@@ -43,6 +44,13 @@ class RetrieveImage extends \Magento\Backend\App\Action
      */
     protected $fileUtility;
 
+    /**
+     * URI validator
+     *
+     * @var \Magento\Framework\Validator\ValidatorInterface
+     */
+    private $protocolValidator;
+
     /**
      * @param \Magento\Backend\App\Action\Context $context
      * @param \Magento\Framework\Controller\Result\RawFactory $resultRawFactory
@@ -51,6 +59,7 @@ class RetrieveImage extends \Magento\Backend\App\Action
      * @param \Magento\Framework\Image\AdapterFactory $imageAdapterFactory
      * @param \Magento\Framework\HTTP\Adapter\Curl $curl
      * @param \Magento\MediaStorage\Model\ResourceModel\File\Storage\File $fileUtility
+     * @param \Magento\Framework\Validator\ValidatorInterface $protocolValidator
      */
     public function __construct(
         \Magento\Backend\App\Action\Context $context,
@@ -59,7 +68,8 @@ class RetrieveImage extends \Magento\Backend\App\Action
         \Magento\Framework\Filesystem $fileSystem,
         \Magento\Framework\Image\AdapterFactory $imageAdapterFactory,
         \Magento\Framework\HTTP\Adapter\Curl $curl,
-        \Magento\MediaStorage\Model\ResourceModel\File\Storage\File $fileUtility
+        \Magento\MediaStorage\Model\ResourceModel\File\Storage\File $fileUtility,
+        \Magento\Framework\Validator\ValidatorInterface $protocolValidator = null
     ) {
         parent::__construct($context);
         $this->resultRawFactory = $resultRawFactory;
@@ -68,6 +78,10 @@ class RetrieveImage extends \Magento\Backend\App\Action
         $this->imageAdapter = $imageAdapterFactory->create();
         $this->curl = $curl;
         $this->fileUtility = $fileUtility;
+
+        $this->protocolValidator = $protocolValidator ?:
+            \Magento\Framework\App\ObjectManager::getInstance()
+                ->get(\Magento\Framework\Validator\ValidatorInterface::class);
     }
 
     /**
@@ -78,15 +92,15 @@ class RetrieveImage extends \Magento\Backend\App\Action
         $baseTmpMediaPath = $this->mediaConfig->getBaseTmpMediaPath();
         try {
             $remoteFileUrl = $this->getRequest()->getParam('remote_image');
-            $originalFileName = basename($remoteFileUrl);
-            $localFileName = Uploader::getCorrectFileName($originalFileName);
+            $this->validateRemoteFile($remoteFileUrl);
+            $localFileName = Uploader::getCorrectFileName(basename($remoteFileUrl));
             $localTmpFileName = Uploader::getDispretionPath($localFileName) . DIRECTORY_SEPARATOR . $localFileName;
-            $localFileMediaPath = $baseTmpMediaPath . ($localTmpFileName);
-            $localUniqueFileMediaPath = $this->appendNewFileName($localFileMediaPath);
-            $this->retrieveRemoteImage($remoteFileUrl, $localUniqueFileMediaPath);
-            $localFileFullPath = $this->appendAbsoluteFileSystemPath($localUniqueFileMediaPath);
+            $localFilePath = $baseTmpMediaPath . ($localTmpFileName);
+            $localUniqFilePath = $this->appendNewFileName($localFilePath);
+            $this->retrieveRemoteImage($remoteFileUrl, $localUniqFilePath);
+            $localFileFullPath = $this->appendAbsoluteFileSystemPath($localUniqFilePath);
             $this->imageAdapter->validateUploadFile($localFileFullPath);
-            $result = $this->appendResultSaveRemoteImage($localUniqueFileMediaPath);
+            $result = $this->appendResultSaveRemoteImage($localUniqFilePath);
         } catch (\Exception $e) {
             $result = ['error' => $e->getMessage(), 'errorcode' => $e->getCode()];
         }
@@ -98,6 +112,25 @@ class RetrieveImage extends \Magento\Backend\App\Action
         return $response;
     }
 
+    /**
+     * Validate remote file
+     *
+     * @param string $remoteFileUrl
+     * @throws LocalizedException
+     *
+     * @return $this
+     */
+    private function validateRemoteFile($remoteFileUrl)
+    {
+        if (!$this->protocolValidator->isValid($remoteFileUrl)) {
+            throw new LocalizedException(
+                __("Protocol isn't allowed")
+            );
+        }
+
+        return $this;
+    }
+
     /**
      * @param string $fileName
      * @return mixed
@@ -116,6 +149,8 @@ class RetrieveImage extends \Magento\Backend\App\Action
     }
 
     /**
+     * Trying to get remote image to save it locally
+     *
      * @param string $fileUrl
      * @param string $localFilePath
      * @return void
@@ -127,7 +162,7 @@ class RetrieveImage extends \Magento\Backend\App\Action
         $this->curl->write('GET', $fileUrl);
         $image = $this->curl->read();
         if (empty($image)) {
-            throw new \Magento\Framework\Exception\LocalizedException(
+            throw new LocalizedException(
                 __('Could not get preview image information. Please check your connection and try again.')
             );
         }
diff --git a/app/code/Magento/ProductVideo/Test/Unit/Controller/Adminhtml/Product/Gallery/RetrieveImageTest.php b/app/code/Magento/ProductVideo/Test/Unit/Controller/Adminhtml/Product/Gallery/RetrieveImageTest.php
index 79d83f38421bba1a2e582efc3bc90f261c8b79dc..64149d529e5ca8f993e300594279a7e0842f9b8b 100644
--- a/app/code/Magento/ProductVideo/Test/Unit/Controller/Adminhtml/Product/Gallery/RetrieveImageTest.php
+++ b/app/code/Magento/ProductVideo/Test/Unit/Controller/Adminhtml/Product/Gallery/RetrieveImageTest.php
@@ -73,17 +73,11 @@ class RetrieveImageTest extends \PHPUnit_Framework_TestCase
      */
     protected function setUp()
     {
+        $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
         $this->contextMock = $this->getMock(\Magento\Backend\App\Action\Context::class, [], [], '', false);
         $this->rawFactoryMock =
             $this->getMock(\Magento\Framework\Controller\Result\RawFactory::class, ['create'], [], '', false);
-        $response =
-            $this->getMock(
-                \Magento\Framework\Controller\Result\Raw::class,
-                [],
-                [],
-                '',
-                false
-            );
+        $response = new \Magento\Framework\DataObject();
         $this->rawFactoryMock->expects($this->once())->method('create')->willReturn($response);
         $this->configMock = $this->getMock(\Magento\Catalog\Model\Product\Media\Config::class, [], [], '', false);
         $this->filesystemMock = $this->getMock(\Magento\Framework\Filesystem::class, [], [], '', false);
@@ -101,11 +95,15 @@ class RetrieveImageTest extends \PHPUnit_Framework_TestCase
         $this->adapterFactoryMock->expects($this->once())->method('create')->willReturn($this->abstractAdapter);
         $this->curlMock = $this->getMock(\Magento\Framework\HTTP\Adapter\Curl::class, [], [], '', false);
         $this->storageFileMock =
-            $this->getMock(\Magento\MediaStorage\Model\ResourceModel\File\Storage\File::class, [], [], '', false);
+        $this->getMock(\Magento\MediaStorage\Model\ResourceModel\File\Storage\File::class, [], [], '', false);
         $this->request = $this->getMock(\Magento\Framework\App\RequestInterface::class);
         $this->contextMock->expects($this->any())->method('getRequest')->will($this->returnValue($this->request));
-
-        $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
+        $managerMock = $this->getMockBuilder(\Magento\Framework\ObjectManagerInterface::class)
+            ->disableOriginalConstructor()
+            ->setMethods(['get'])
+            ->getMockForAbstractClass();
+        $this->contextMock->expects($this->any())->method('getRequest')->will($this->returnValue($this->request));
+        $this->contextMock->expects($this->any())->method('getObjectManager')->willReturn($managerMock);
 
         $this->image = $objectManager->getObject(
             \Magento\ProductVideo\Controller\Adminhtml\Product\Gallery\RetrieveImage::class,
@@ -117,6 +115,7 @@ class RetrieveImageTest extends \PHPUnit_Framework_TestCase
                 'imageAdapterFactory' => $this->adapterFactoryMock,
                 'curl' => $this->curlMock,
                 'fileUtility' => $this->storageFileMock,
+                'protocolValidator' => new \Magento\Framework\Validator\AllowedProtocols(),
             ]
         );
     }
diff --git a/app/code/Magento/ProductVideo/composer.json b/app/code/Magento/ProductVideo/composer.json
index 362fd006d2690c9f9b60b7be3abb71d5ce0b4da7..08d21e4c2abbfb167aed2ca24c0ba012d6b2e8c8 100644
--- a/app/code/Magento/ProductVideo/composer.json
+++ b/app/code/Magento/ProductVideo/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-product-video",
     "description": "Add Video to Products",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-catalog": "101.1.*",
         "magento/module-backend": "100.2.*",
         "magento/module-eav": "100.2.*",
diff --git a/app/code/Magento/ProductVideo/etc/di.xml b/app/code/Magento/ProductVideo/etc/di.xml
index 09c15d8fccecc64d3dd183e7940aa26b6819d6df..7242a9d48ce1e3c0da66a3f4d5953cda705132cd 100644
--- a/app/code/Magento/ProductVideo/etc/di.xml
+++ b/app/code/Magento/ProductVideo/etc/di.xml
@@ -7,6 +7,7 @@
 -->
 <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
     <preference for="Magento\Framework\Api\Data\VideoContentInterface" type="Magento\ProductVideo\Model\Product\Attribute\Media\VideoEntry" />
+    <preference for="Magento\Framework\Validator\ValidatorInterface" type="Magento\Framework\Validator\AllowedProtocols" />
     <type name="Magento\Catalog\Model\Product\Attribute\Backend\Media\EntryConverterPool">
         <arguments>
             <argument name="mediaGalleryEntryConvertersCollection" xsi:type="array">
diff --git a/app/code/Magento/ProductVideo/i18n/en_US.csv b/app/code/Magento/ProductVideo/i18n/en_US.csv
index 4cfabe1592dd2d0ce5c8072f0bdaafbc847689e6..64a08075c19548bc092f3918e7dabf606dd2052e 100644
--- a/app/code/Magento/ProductVideo/i18n/en_US.csv
+++ b/app/code/Magento/ProductVideo/i18n/en_US.csv
@@ -40,3 +40,4 @@ Delete,Delete
 "Show related video","Show related video"
 "Auto restart video","Auto restart video"
 "Images And Videos","Images And Videos"
+"Protocol isn't allowed", "Protocol isn't allowed"
diff --git a/app/code/Magento/Quote/Model/Quote.php b/app/code/Magento/Quote/Model/Quote.php
index 3cdcf70cf24266ae7613e7e6f790c4b6777ff23b..f84ca33b436f91e4afca6cae6f52c8b975cf4289 100644
--- a/app/code/Magento/Quote/Model/Quote.php
+++ b/app/code/Magento/Quote/Model/Quote.php
@@ -2157,6 +2157,12 @@ class Quote extends AbstractExtensibleModel implements \Magento\Quote\Api\Data\C
     {
         if (!$this->getReservedOrderId()) {
             $this->setReservedOrderId($this->_getResource()->getReservedOrderId($this));
+        } else {
+            //checking if reserved order id was already used for some order
+            //if yes reserving new one if not using old one
+            if ($this->_getResource()->isOrderIncrementIdUsed($this->getReservedOrderId())) {
+                $this->setReservedOrderId($this->_getResource()->getReservedOrderId($this));
+            }
         }
         return $this;
     }
diff --git a/app/code/Magento/Quote/Model/Quote/Address/Total/Shipping.php b/app/code/Magento/Quote/Model/Quote/Address/Total/Shipping.php
index f1660c9f9d6427fb617c2de9d87ae2a8026be3aa..7d8946661476cb851f2488405708847530e99673 100644
--- a/app/code/Magento/Quote/Model/Quote/Address/Total/Shipping.php
+++ b/app/code/Magento/Quote/Model/Quote/Address/Total/Shipping.php
@@ -59,10 +59,8 @@ class Shipping extends \Magento\Quote\Model\Quote\Address\Total\AbstractTotal
 
         $addressWeight = $address->getWeight();
         $freeMethodWeight = $address->getFreeMethodWeight();
+        $addressFreeShipping = $address->getFreeShipping();
 
-        $address->setFreeShipping(
-            $this->freeShipping->isFreeShipping($quote, $shippingAssignment->getItems())
-        );
         $total->setTotalAmount($this->getCode(), 0);
         $total->setBaseTotalAmount($this->getCode(), 0);
 
@@ -98,7 +96,7 @@ class Shipping extends \Magento\Quote\Model\Quote\Address\Total\AbstractTotal
                         $itemQty = $child->getTotalQty();
                         $rowWeight = $itemWeight * $itemQty;
                         $addressWeight += $rowWeight;
-                        if ($address->getFreeShipping() || $child->getFreeShipping() === true) {
+                        if ($addressFreeShipping || $child->getFreeShipping() === true) {
                             $rowWeight = 0;
                         } elseif (is_numeric($child->getFreeShipping())) {
                             $freeQty = $child->getFreeShipping();
@@ -116,7 +114,7 @@ class Shipping extends \Magento\Quote\Model\Quote\Address\Total\AbstractTotal
                     $itemWeight = $item->getWeight();
                     $rowWeight = $itemWeight * $item->getQty();
                     $addressWeight += $rowWeight;
-                    if ($address->getFreeShipping() || $item->getFreeShipping() === true) {
+                    if ($addressFreeShipping || $item->getFreeShipping() === true) {
                         $rowWeight = 0;
                     } elseif (is_numeric($item->getFreeShipping())) {
                         $freeQty = $item->getFreeShipping();
@@ -136,7 +134,7 @@ class Shipping extends \Magento\Quote\Model\Quote\Address\Total\AbstractTotal
                 $itemWeight = $item->getWeight();
                 $rowWeight = $itemWeight * $item->getQty();
                 $addressWeight += $rowWeight;
-                if ($address->getFreeShipping() || $item->getFreeShipping() === true) {
+                if ($addressFreeShipping || $item->getFreeShipping() === true) {
                     $rowWeight = 0;
                 } elseif (is_numeric($item->getFreeShipping())) {
                     $freeQty = $item->getFreeShipping();
@@ -157,6 +155,10 @@ class Shipping extends \Magento\Quote\Model\Quote\Address\Total\AbstractTotal
 
         $address->setWeight($addressWeight);
         $address->setFreeMethodWeight($freeMethodWeight);
+        $address->setFreeShipping(
+            $this->freeShipping->isFreeShipping($quote, $shippingAssignment->getItems())
+        );
+
         $address->collectShippingRates();
 
         if ($method) {
diff --git a/app/code/Magento/Quote/Model/ResourceModel/Quote.php b/app/code/Magento/Quote/Model/ResourceModel/Quote.php
index 241f0d6b272fc33f6b29ff4e2c069ca088c5073b..6113a1ba56ac184d59a6d0e37bd696455dce31cd 100644
--- a/app/code/Magento/Quote/Model/ResourceModel/Quote.php
+++ b/app/code/Magento/Quote/Model/ResourceModel/Quote.php
@@ -172,6 +172,29 @@ class Quote extends AbstractDb
         ->getNextValue();
     }
 
+    /**
+     * Check if order increment ID is already used.
+     * Method can be used to avoid collisions of order IDs.
+     *
+     * @param int $orderIncrementId
+     * @return bool
+     */
+    public function isOrderIncrementIdUsed($orderIncrementId)
+    {
+        /** @var  \Magento\Framework\DB\Adapter\AdapterInterface $adapter */
+        $adapter = $this->getConnection();
+        $bind = [':increment_id' => $orderIncrementId];
+        /** @var \Magento\Framework\DB\Select $select */
+        $select = $adapter->select();
+        $select->from($this->getTable('sales_order'), 'entity_id')->where('increment_id = :increment_id');
+        $entity_id = $adapter->fetchOne($select, $bind);
+        if ($entity_id > 0) {
+            return true;
+        }
+
+        return false;
+    }
+
     /**
      * Mark quotes - that depend on catalog price rules - to be recollected on demand
      *
diff --git a/app/code/Magento/Quote/Test/Unit/Model/QuoteTest.php b/app/code/Magento/Quote/Test/Unit/Model/QuoteTest.php
index 5165f299d45a96b7aa9b130a03747fad38955084..b54ce84fe1ac45fbee2d1b2c89a99c8546a11cab 100644
--- a/app/code/Magento/Quote/Test/Unit/Model/QuoteTest.php
+++ b/app/code/Magento/Quote/Test/Unit/Model/QuoteTest.php
@@ -314,7 +314,10 @@ class QuoteTest extends \PHPUnit_Framework_TestCase
                     'customerRepository' => $this->customerRepositoryMock,
                     'objectCopyService' => $this->objectCopyServiceMock,
                     'extensionAttributesJoinProcessor' => $this->extensionAttributesJoinProcessorMock,
-                    'customerDataFactory' => $this->customerDataFactoryMock
+                    'customerDataFactory' => $this->customerDataFactoryMock,
+                    'data' => [
+                        'reserved_order_id' => 1000001
+                    ]
                 ]
             );
     }
@@ -1237,4 +1240,30 @@ class QuoteTest extends \PHPUnit_Framework_TestCase
 
         $this->assertEquals($itemResult, $this->quote->getAllItems());
     }
+
+    /**
+     * Test to verify if existing reserved_order_id in use
+     *
+     * @param bool $isReservedOrderIdExist
+     * @param int $reservedOrderId
+     * @dataProvider reservedOrderIdDataProvider
+     */
+    public function testReserveOrderId($isReservedOrderIdExist, $reservedOrderId)
+    {
+        $this->resourceMock
+            ->expects($this->once())
+            ->method('isOrderIncrementIdUsed')
+            ->with(1000001)->willReturn($isReservedOrderIdExist);
+        $this->resourceMock->expects($this->any())->method('getReservedOrderId')->willReturn($reservedOrderId);
+        $this->quote->reserveOrderId();
+        $this->assertEquals($reservedOrderId, $this->quote->getReservedOrderId());
+    }
+
+    public function reservedOrderIdDataProvider()
+    {
+        return [
+            'id_already_in_use' => [true, 100002],
+            'id_not_in_use' => [false, 1000001]
+        ];
+    }
 }
diff --git a/app/code/Magento/Quote/Test/Unit/Model/ResourceModel/QuoteTest.php b/app/code/Magento/Quote/Test/Unit/Model/ResourceModel/QuoteTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..15c58073c2e26a4921f771e6c4097fafc9275c91
--- /dev/null
+++ b/app/code/Magento/Quote/Test/Unit/Model/ResourceModel/QuoteTest.php
@@ -0,0 +1,84 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Quote\Test\Unit\Model\ResourceModel;
+
+class QuoteTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\Quote\Model\ResourceModel\Quote
+     */
+    private $model;
+
+    /**
+     * @var \Magento\Framework\App\ResourceConnection
+     */
+    private $resourceMock;
+
+    /**
+     * @var \Magento\Framework\DB\Adapter\Pdo\Mysql
+     */
+    private $adapterMock;
+
+    /**
+     * @var \Magento\Framework\DB\Select
+     */
+    private $selectMock;
+
+    protected function setUp()
+    {
+        $objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
+        $this->selectMock = $this->getMockBuilder(\Magento\Framework\DB\Select::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->selectMock->expects($this->any())->method('from')->will($this->returnSelf());
+        $this->selectMock->expects($this->any())->method('where');
+
+        $this->adapterMock = $this->getMockBuilder(\Magento\Framework\DB\Adapter\Pdo\Mysql::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->adapterMock->expects($this->any())->method('select')->will($this->returnValue($this->selectMock));
+
+        $this->resourceMock = $this->getMockBuilder(\Magento\Framework\App\ResourceConnection::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->resourceMock->expects(
+            $this->any()
+        )->method(
+            'getConnection'
+        )->will(
+            $this->returnValue($this->adapterMock)
+        );
+
+        $this->model = $objectManagerHelper->getObject(
+            \Magento\Quote\Model\ResourceModel\Quote::class,
+            [
+                'resource' => $this->resourceMock
+            ]
+        );
+    }
+
+    /**
+     * Unit test to verify if isOrderIncrementIdUsed method works with different types increment ids
+     *
+     * @param array $value
+     * @dataProvider isOrderIncrementIdUsedDataProvider
+     */
+    public function testIsOrderIncrementIdUsed($value)
+    {
+        $expectedBind = [':increment_id' => $value];
+        $this->adapterMock->expects($this->once())->method('fetchOne')->with($this->selectMock, $expectedBind);
+        $this->model->isOrderIncrementIdUsed($value);
+    }
+
+    /**
+     * @return array
+     */
+    public function isOrderIncrementIdUsedDataProvider()
+    {
+        return [[100000001], ['10000000001'], ['M10000000001']];
+    }
+}
diff --git a/app/code/Magento/Quote/composer.json b/app/code/Magento/Quote/composer.json
index 79c3a1aaa9d907cea1c505ece12a22e4ee3986f2..76063b177d46c2eb93626dea77a346aaaeb5c21d 100644
--- a/app/code/Magento/Quote/composer.json
+++ b/app/code/Magento/Quote/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-quote",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-store": "100.2.*",
         "magento/module-catalog": "101.1.*",
         "magento/module-customer": "100.2.*",
diff --git a/app/code/Magento/Reports/composer.json b/app/code/Magento/Reports/composer.json
index 0bb989cb54ac8cb84e3da943a231634b6707f256..9c76abd07b9b35276f1f923138c9dd47031c289d 100644
--- a/app/code/Magento/Reports/composer.json
+++ b/app/code/Magento/Reports/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-reports",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-config": "100.2.*",
         "magento/module-store": "100.2.*",
         "magento/module-eav": "100.2.*",
diff --git a/app/code/Magento/RequireJs/composer.json b/app/code/Magento/RequireJs/composer.json
index 8c9fed33ab730dd2431b222b2edd04aa2252e12f..68428caa867bf7108fc466ebfd1fa2829a2b75fa 100644
--- a/app/code/Magento/RequireJs/composer.json
+++ b/app/code/Magento/RequireJs/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-require-js",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/framework": "100.2.*"
     },
     "type": "magento2-module",
diff --git a/app/code/Magento/Review/composer.json b/app/code/Magento/Review/composer.json
index 09f5529feabdd97512839be2dacd00f791083c3c..3ec82943476088c3aa307de1b5a934a3cac8ca0d 100644
--- a/app/code/Magento/Review/composer.json
+++ b/app/code/Magento/Review/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-review",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-store": "100.2.*",
         "magento/module-catalog": "101.1.*",
         "magento/module-customer": "100.2.*",
diff --git a/app/code/Magento/Review/view/frontend/layout/customer_account.xml b/app/code/Magento/Review/view/frontend/layout/customer_account.xml
index 9de10e43fa4d148dce5c4b316e93538a830e6d2b..5506a904ce0f76bce2a8552d517a0f31646644fb 100644
--- a/app/code/Magento/Review/view/frontend/layout/customer_account.xml
+++ b/app/code/Magento/Review/view/frontend/layout/customer_account.xml
@@ -8,10 +8,11 @@
 <page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
     <body>
         <referenceBlock name="customer_account_navigation">
-            <block class="Magento\Framework\View\Element\Html\Link\Current" name="customer-account-navigation-product-reviews-link">
+            <block class="Magento\Customer\Block\Account\SortLinkInterface" name="customer-account-navigation-product-reviews-link">
                 <arguments>
                     <argument name="path" xsi:type="string">review/customer</argument>
                     <argument name="label" xsi:type="string">My Product Reviews</argument>
+                    <argument name="sortOrder" xsi:type="number">50</argument>
                 </arguments>
             </block>
         </referenceBlock>
diff --git a/app/code/Magento/Review/view/frontend/templates/form.phtml b/app/code/Magento/Review/view/frontend/templates/form.phtml
index 7c89fd8740c5607ec83f0d0a4dda761de50d97ed..bcac1dbca059833749faf9db4d759f8a06a6f24a 100644
--- a/app/code/Magento/Review/view/frontend/templates/form.phtml
+++ b/app/code/Magento/Review/view/frontend/templates/form.phtml
@@ -20,7 +20,7 @@
         <?php if ($block->getRatings() && $block->getRatings()->getSize()): ?>
         <span id="input-message-box"></span>
         <fieldset class="field required review-field-ratings">
-            <legend class="label"><span><?php echo $block->escapeHtml(__('Your Rating')) ?><span></legend><br/>
+            <legend class="label"><span><?php echo $block->escapeHtml(__('Your Rating')) ?></span></legend><br/>
             <div class="control">
                 <div class="nested" id="product-review-table">
                     <?php foreach ($block->getRatings() as $_rating): ?>
diff --git a/app/code/Magento/Rss/composer.json b/app/code/Magento/Rss/composer.json
index d35f0ee6ebecbf75af87566d776f172ab3d22c0d..fedd0ffeaacfe9577ea6e5971411540d4925fe4c 100644
--- a/app/code/Magento/Rss/composer.json
+++ b/app/code/Magento/Rss/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-rss",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-store": "100.2.*",
         "magento/module-backend": "100.2.*",
         "magento/framework": "100.2.*",
diff --git a/app/code/Magento/Rule/composer.json b/app/code/Magento/Rule/composer.json
index 95b8e6ffec2a682895b3459ca7bdcc7b4f001669..31ee3254d99b98a10ce9973e3a8a4adb1c5818da 100644
--- a/app/code/Magento/Rule/composer.json
+++ b/app/code/Magento/Rule/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-rule",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-store": "100.2.*",
         "magento/module-eav": "100.2.*",
         "magento/module-catalog": "101.1.*",
diff --git a/app/code/Magento/Sales/Model/Order/Payment.php b/app/code/Magento/Sales/Model/Order/Payment.php
index 5deb24a068de1d0ff8a48bb4cc7f6f916c1c6dde..a0f56d6ea9a73ea02d4c852ef6ac4831be29b574 100644
--- a/app/code/Magento/Sales/Model/Order/Payment.php
+++ b/app/code/Magento/Sales/Model/Order/Payment.php
@@ -632,42 +632,48 @@ class Payment extends Info implements OrderPaymentInterface
             $this->transactionManager->generateTransactionId($this, Transaction::TYPE_REFUND)
         );
 
-        // call refund from gateway if required
         $isOnline = false;
         $gateway = $this->getMethodInstance();
         $invoice = null;
-        if ($gateway->canRefund() && $creditmemo->getDoTransaction()) {
+        if ($gateway->canRefund()) {
             $this->setCreditmemo($creditmemo);
-            $invoice = $creditmemo->getInvoice();
-            if ($invoice) {
-                $isOnline = true;
-                $captureTxn = $this->transactionRepository->getByTransactionId(
-                    $invoice->getTransactionId(),
-                    $this->getId(),
-                    $this->getOrder()->getId()
-                );
-                if ($captureTxn) {
-                    $this->setTransactionIdsForRefund($captureTxn);
-                }
-                $this->setShouldCloseParentTransaction(true);
-                // TODO: implement multiple refunds per capture
-                try {
-                    $gateway->setStore(
-                        $this->getOrder()->getStoreId()
+            if ($creditmemo->getDoTransaction()) {
+                $invoice = $creditmemo->getInvoice();
+                if ($invoice) {
+                    $isOnline = true;
+                    $captureTxn = $this->transactionRepository->getByTransactionId(
+                        $invoice->getTransactionId(),
+                        $this->getId(),
+                        $this->getOrder()->getId()
                     );
-                    $this->setRefundTransactionId($invoice->getTransactionId());
-                    $gateway->refund($this, $baseAmountToRefund);
-
-                    $creditmemo->setTransactionId($this->getLastTransId());
-                } catch (\Magento\Framework\Exception\LocalizedException $e) {
-                    if (!$captureTxn) {
-                        throw new \Magento\Framework\Exception\LocalizedException(
-                            __('If the invoice was created offline, try creating an offline credit memo.'),
-                            $e
+                    if ($captureTxn) {
+                        $this->setTransactionIdsForRefund($captureTxn);
+                    }
+                    $this->setShouldCloseParentTransaction(true);
+                    // TODO: implement multiple refunds per capture
+                    try {
+                        $gateway->setStore(
+                            $this->getOrder()->getStoreId()
                         );
+                        $this->setRefundTransactionId($invoice->getTransactionId());
+                        $gateway->refund($this, $baseAmountToRefund);
+
+                        $creditmemo->setTransactionId($this->getLastTransId());
+                    } catch (\Magento\Framework\Exception\LocalizedException $e) {
+                        if (!$captureTxn) {
+                            throw new \Magento\Framework\Exception\LocalizedException(
+                                __('If the invoice was created offline, try creating an offline credit memo.'),
+                                $e
+                            );
+                        }
+                        throw $e;
                     }
-                    throw $e;
                 }
+            } else if ($gateway->isOffline()) {
+                $gateway->setStore(
+                    $this->getOrder()->getStoreId()
+                );
+                $gateway->refund($this, $baseAmountToRefund);
             }
         }
 
diff --git a/app/code/Magento/Sales/Setup/UpgradeSchema.php b/app/code/Magento/Sales/Setup/UpgradeSchema.php
index b977cb28596eae3ff2e9c5ea0836ba716c54831e..d35825242fb291a41961eb882ad93f7d24c58ee9 100644
--- a/app/code/Magento/Sales/Setup/UpgradeSchema.php
+++ b/app/code/Magento/Sales/Setup/UpgradeSchema.php
@@ -69,6 +69,20 @@ class UpgradeSchema implements UpgradeSchemaInterface
             $this->addColumnBaseGrandTotal($installer);
             $this->addIndexBaseGrandTotal($installer);
         }
+        if (version_compare($context->getVersion(), '2.0.4', '<')) {
+            $tables = [
+                'sales_invoice_grid',
+                'sales_order',
+                'sales_shipment_grid',
+            ];
+            foreach ($tables as $table) {
+                $setup->getConnection()->modifyColumn(
+                    $setup->getTable($table),
+                    'customer_group_id',
+                    ['type' => 'integer']
+                );
+            }
+        }
     }
 
     /**
diff --git a/app/code/Magento/Sales/composer.json b/app/code/Magento/Sales/composer.json
index 09d1a9d6b7dd41ea95a09b26c0f72276327fe245..6b5638455a1c5986fb487f7f9c948d9ddf19aad3 100644
--- a/app/code/Magento/Sales/composer.json
+++ b/app/code/Magento/Sales/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-sales",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-store": "100.2.*",
         "magento/module-catalog": "101.1.*",
         "magento/module-customer": "100.2.*",
diff --git a/app/code/Magento/Sales/etc/module.xml b/app/code/Magento/Sales/etc/module.xml
index 88d6e25d31fb6c4ed9777595296e969028b154f2..980395e965e0899695206b7094b72f7f5b396ece 100644
--- a/app/code/Magento/Sales/etc/module.xml
+++ b/app/code/Magento/Sales/etc/module.xml
@@ -6,7 +6,7 @@
  */
 -->
 <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
-    <module name="Magento_Sales" setup_version="2.0.3">
+    <module name="Magento_Sales" setup_version="2.0.4">
         <sequence>
             <module name="Magento_Rule"/>
             <module name="Magento_Catalog"/>
diff --git a/app/code/Magento/Sales/view/adminhtml/templates/order/view/info.phtml b/app/code/Magento/Sales/view/adminhtml/templates/order/view/info.phtml
index 775c7214c2f104771c79d5fd299229187595b167..20cfcdeadf22a0f18d81b262134058640c04877f 100644
--- a/app/code/Magento/Sales/view/adminhtml/templates/order/view/info.phtml
+++ b/app/code/Magento/Sales/view/adminhtml/templates/order/view/info.phtml
@@ -38,10 +38,10 @@ $orderStoreDate = $block->formatDate(
             <div class="admin__page-section-item-title">
                 <span class="title">
                     <?php if ($block->getNoUseOrderLink()): ?>
-                        <?php /* @escapeNotVerified */ echo __('Order # %1', $_order->getRealOrderId()) ?> (<span><?php /* @escapeNotVerified */ echo $_email ?></span>)
+                        <?php /* @escapeNotVerified */ echo __('Order # %1', $_order->getRealOrderId()) ?> (<span><?php echo $block->escapeHtml($_email) ?></span>)
                     <?php else: ?>
                         <a href="<?php /* @escapeNotVerified */ echo $block->getViewUrl($_order->getId()) ?>"><?php /* @escapeNotVerified */ echo __('Order # %1', $_order->getRealOrderId()) ?></a>
-                        <span>(<?php /* @escapeNotVerified */ echo $_email ?>)</span>
+                        <span>(<?php echo $block->escapeHtml($_email) ?>)</span>
                     <?php endif; ?>
                 </span>
             </div>
@@ -49,7 +49,7 @@ $orderStoreDate = $block->formatDate(
                 <table class="admin__table-secondary order-information-table">
                 <tr>
                     <th><?php /* @escapeNotVerified */ echo __('Order Date') ?></th>
-                    <td><?php /* @escapeNotVerified */ echo $orderAdminDate ?></td>
+                    <td><?php echo $block->escapeHtml($orderAdminDate) ?></td>
                 </tr>
                 <?php if ($orderAdminDate != $orderStoreDate):?>
                     <tr>
@@ -57,12 +57,12 @@ $orderStoreDate = $block->formatDate(
                                 'Order Date (%1)',
                                 $block->getTimezoneForStore($_order->getStore())
                             ) ?></th>
-                        <td><?php /* @escapeNotVerified */ echo $orderStoreDate ?></td>
+                        <td><?php echo $block->escapeHtml($orderStoreDate) ?></td>
                     </tr>
                 <?php endif;?>
                 <tr>
                     <th><?php /* @escapeNotVerified */ echo __('Order Status') ?></th>
-                    <td><span id="order_status"><?php /* @escapeNotVerified */ echo $_order->getStatusLabel() ?></span></td>
+                    <td><span id="order_status"><?php echo $block->escapeHtml($_order->getStatusLabel()) ?></span></td>
                 </tr>
                 <?php echo $block->getChildHtml(); ?>
                 <?php if ($block->isSingleStoreMode() == false):?>
@@ -136,13 +136,13 @@ $orderStoreDate = $block->formatDate(
                     <?php if ($_groupName = $block->getCustomerGroupName()) : ?>
                         <tr>
                             <th><?php /* @escapeNotVerified */ echo __('Customer Group') ?></th>
-                            <td><?php /* @escapeNotVerified */ echo $_groupName ?></td>
+                            <td><?php echo $block->escapeHtml($_groupName) ?></td>
                         </tr>
                     <?php endif; ?>
                     <?php foreach ($block->getCustomerAccountData() as $data):?>
                         <tr>
-                            <th><?php /* @escapeNotVerified */ echo $data['label'] ?></th>
-                            <td><?php /* @escapeNotVerified */ echo $data['value'] ?></td>
+                            <th><?php echo $block->escapeHtml($data['label']) ?></th>
+                            <td><?php echo $block->escapeHtml($data['value']) ?></td>
                         </tr>
                     <?php endforeach;?>
                 </table>
diff --git a/app/code/Magento/Sales/view/frontend/layout/customer_account.xml b/app/code/Magento/Sales/view/frontend/layout/customer_account.xml
index a3933b8b221109b895f79646f6e0a9d36dc90905..239a38c09f5058c4f30fa86eb9bd0858517ad8b9 100644
--- a/app/code/Magento/Sales/view/frontend/layout/customer_account.xml
+++ b/app/code/Magento/Sales/view/frontend/layout/customer_account.xml
@@ -8,10 +8,11 @@
 <page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
     <body>
         <referenceBlock name="customer_account_navigation">
-            <block class="Magento\Framework\View\Element\Html\Link\Current" name="customer-account-navigation-orders-link">
+            <block class="Magento\Customer\Block\Account\SortLinkInterface" name="customer-account-navigation-orders-link">
                 <arguments>
                     <argument name="path" xsi:type="string">sales/order/history</argument>
                     <argument name="label" xsi:type="string" translate="true">My Orders</argument>
+                    <argument name="sortOrder" xsi:type="number">230</argument>
                 </arguments>
             </block>
         </referenceBlock>
diff --git a/app/code/Magento/SalesInventory/composer.json b/app/code/Magento/SalesInventory/composer.json
index ff72ce7f0022690682b356235c506512e65497b9..d7f9075cdd310141bab6b25869f33d6229f513dc 100644
--- a/app/code/Magento/SalesInventory/composer.json
+++ b/app/code/Magento/SalesInventory/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-sales-inventory",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-catalog-inventory": "100.2.*",
         "magento/module-sales": "100.2.*",
         "magento/module-store": "100.2.*",
diff --git a/app/code/Magento/SalesRule/Controller/Adminhtml/Promo/Quote/Save.php b/app/code/Magento/SalesRule/Controller/Adminhtml/Promo/Quote/Save.php
index 57477b5ce0623f57bfc048839cc8bdaee8d40593..efa45512acc8320cd878c97b92c5912c7713f882 100644
--- a/app/code/Magento/SalesRule/Controller/Adminhtml/Promo/Quote/Save.php
+++ b/app/code/Magento/SalesRule/Controller/Adminhtml/Promo/Quote/Save.php
@@ -26,8 +26,13 @@ class Save extends \Magento\SalesRule\Controller\Adminhtml\Promo\Quote
                     ['request' => $this->getRequest()]
                 );
                 $data = $this->getRequest()->getPostValue();
+
+                $filterValues = ['from_date' => $this->_dateFilter];
+                if ($this->getRequest()->getParam('to_date')) {
+                    $filterValues['to_date'] = $this->_dateFilter;
+                }
                 $inputFilter = new \Zend_Filter_Input(
-                    ['from_date' => $this->_dateFilter, 'to_date' => $this->_dateFilter],
+                    $filterValues,
                     [],
                     $data
                 );
diff --git a/app/code/Magento/SalesRule/Setup/InstallSchema.php b/app/code/Magento/SalesRule/Setup/InstallSchema.php
index 577d243cd6e1c0848f78328d26dfbf979216791c..9adf43fc19cce981bb9915bfe614a242cbce013d 100644
--- a/app/code/Magento/SalesRule/Setup/InstallSchema.php
+++ b/app/code/Magento/SalesRule/Setup/InstallSchema.php
@@ -23,7 +23,9 @@ class InstallSchema implements InstallSchemaInterface
     {
         $installer = $setup;
         $installer->startSetup();
-
+        $customerGroupTable = $setup->getConnection()->describeTable($setup->getTable('customer_group'));
+        $customerGroupIdType = $customerGroupTable['customer_group_id']['DATA_TYPE'] == 'int'
+            ? \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER : $customerGroupTable['customer_group_id']['DATA_TYPE'];
         /**
          * Create table 'salesrule'
          */
@@ -441,7 +443,7 @@ class InstallSchema implements InstallSchemaInterface
             'Website Id'
         )->addColumn(
             'customer_group_id',
-            \Magento\Framework\DB\Ddl\Table::TYPE_SMALLINT,
+            $customerGroupIdType,
             null,
             ['unsigned' => true, 'nullable' => false, 'primary' => true],
             'Customer Group Id'
@@ -757,7 +759,7 @@ class InstallSchema implements InstallSchemaInterface
             'Rule Id'
         )->addColumn(
             'customer_group_id',
-            \Magento\Framework\DB\Ddl\Table::TYPE_SMALLINT,
+            $customerGroupIdType,
             null,
             ['unsigned' => true, 'nullable' => false, 'primary' => true],
             'Customer Group Id'
diff --git a/app/code/Magento/SalesRule/composer.json b/app/code/Magento/SalesRule/composer.json
index fabef581762a84cac8844bf7e7099b0bb8b6b6c0..8479acad47246a1f91bc6b098d88cfa6f6027f76 100644
--- a/app/code/Magento/SalesRule/composer.json
+++ b/app/code/Magento/SalesRule/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-sales-rule",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-config": "100.2.*",
         "magento/module-store": "100.2.*",
         "magento/module-rule": "100.2.*",
diff --git a/app/code/Magento/SalesRule/view/frontend/web/js/action/cancel-coupon.js b/app/code/Magento/SalesRule/view/frontend/web/js/action/cancel-coupon.js
index ed5744feb6ce84df31a5a59b42f520bb97316792..d1e294c9a8f0c1dc4edf82e52cbe509b09da8fbe 100644
--- a/app/code/Magento/SalesRule/view/frontend/web/js/action/cancel-coupon.js
+++ b/app/code/Magento/SalesRule/view/frontend/web/js/action/cancel-coupon.js
@@ -17,16 +17,20 @@ define(
         'mage/storage',
         'Magento_Checkout/js/action/get-payment-information',
         'Magento_Checkout/js/model/totals',
-        'mage/translate'
+        'mage/translate',
+        'Magento_Checkout/js/model/full-screen-loader'
     ],
-    function ($, quote, urlManager, errorProcessor, messageContainer, storage, getPaymentInformationAction, totals, $t) {
+    function ($, quote, urlManager, errorProcessor, messageContainer, storage, getPaymentInformationAction, totals, $t,
+              fullScreenLoader) {
         'use strict';
 
-        return function (isApplied, isLoading) {
+        return function (isApplied) {
             var quoteId = quote.getQuoteId(),
                 url = urlManager.getCancelCouponUrl(quoteId),
                 message = $t('Your coupon was successfully removed.');
+
             messageContainer.clear();
+            fullScreenLoader.startLoader();
 
             return storage.delete(
                 url,
@@ -39,6 +43,7 @@ define(
                     $.when(deferred).done(function () {
                         isApplied(false);
                         totals.isLoading(false);
+                        fullScreenLoader.stopLoader();
                     });
                     messageContainer.addSuccessMessage({
                         'message': message
@@ -47,12 +52,9 @@ define(
             ).fail(
                 function (response) {
                     totals.isLoading(false);
+                    fullScreenLoader.stopLoader();
                     errorProcessor.process(response, messageContainer);
                 }
-            ).always(
-                function () {
-                    isLoading(false);
-                }
             );
         };
     }
diff --git a/app/code/Magento/SalesRule/view/frontend/web/js/action/set-coupon-code.js b/app/code/Magento/SalesRule/view/frontend/web/js/action/set-coupon-code.js
index 606fe4013ea762c5460c49202907463d7c7952f2..a2b7ff19f2139ffa7e23b37eda039d5b9ccc32a8 100644
--- a/app/code/Magento/SalesRule/view/frontend/web/js/action/set-coupon-code.js
+++ b/app/code/Magento/SalesRule/view/frontend/web/js/action/set-coupon-code.js
@@ -18,25 +18,22 @@ define(
         'mage/storage',
         'mage/translate',
         'Magento_Checkout/js/action/get-payment-information',
-        'Magento_Checkout/js/model/totals'
+        'Magento_Checkout/js/model/totals',
+        'Magento_Checkout/js/model/full-screen-loader'
     ],
     function (
-        ko,
-        $,
-        quote,
-        urlManager,
-        errorProcessor,
-        messageContainer,
-        storage,
-        $t,
-        getPaymentInformationAction,
-        totals
+        ko, $, quote, urlManager, errorProcessor, messageContainer, storage, $t, getPaymentInformationAction, totals,
+        fullScreenLoader
     ) {
         'use strict';
-        return function (couponCode, isApplied, isLoading) {
-            var quoteId = quote.getQuoteId();
-            var url = urlManager.getApplyCouponUrl(couponCode, quoteId);
-            var message = $t('Your coupon was successfully applied.');
+
+        return function (couponCode, isApplied) {
+            var quoteId = quote.getQuoteId(),
+                url = urlManager.getApplyCouponUrl(couponCode, quoteId),
+                message = $t('Your coupon was successfully applied.');
+
+            fullScreenLoader.startLoader();
+
             return storage.put(
                 url,
                 {},
@@ -45,19 +42,22 @@ define(
                 function (response) {
                     if (response) {
                         var deferred = $.Deferred();
-                        isLoading(false);
+
                         isApplied(true);
                         totals.isLoading(true);
                         getPaymentInformationAction(deferred);
                         $.when(deferred).done(function () {
+                            fullScreenLoader.stopLoader();
                             totals.isLoading(false);
                         });
-                        messageContainer.addSuccessMessage({'message': message});
+                        messageContainer.addSuccessMessage({
+                            'message': message
+                        });
                     }
                 }
             ).fail(
                 function (response) {
-                    isLoading(false);
+                    fullScreenLoader.stopLoader();
                     totals.isLoading(false);
                     errorProcessor.process(response, messageContainer);
                 }
diff --git a/app/code/Magento/SalesRule/view/frontend/web/js/view/payment/discount.js b/app/code/Magento/SalesRule/view/frontend/web/js/view/payment/discount.js
index 8e8c0798ff3b59ce0ffa0a803242abe1d02fcee7..6dc973a7a1e4298469251f71f6e26f09a95cc5d0 100644
--- a/app/code/Magento/SalesRule/view/frontend/web/js/view/payment/discount.js
+++ b/app/code/Magento/SalesRule/view/frontend/web/js/view/payment/discount.js
@@ -13,49 +13,53 @@ define(
     ],
     function ($, ko, Component, quote, setCouponCodeAction, cancelCouponAction) {
         'use strict';
-        var totals = quote.getTotals();
-        var couponCode = ko.observable(null);
+
+        var totals = quote.getTotals(),
+            couponCode = ko.observable(null),
+            isApplied = ko.observable(couponCode() != null);
+
         if (totals()) {
             couponCode(totals()['coupon_code']);
         }
-        var isApplied = ko.observable(couponCode() != null);
-        var isLoading = ko.observable(false);
+
         return Component.extend({
             defaults: {
                 template: 'Magento_SalesRule/payment/discount'
             },
             couponCode: couponCode,
+
             /**
              * Applied flag
              */
             isApplied: isApplied,
-            isLoading: isLoading,
+
             /**
              * Coupon code application procedure
              */
             apply: function() {
                 if (this.validate()) {
-                    isLoading(true);
-                    setCouponCodeAction(couponCode(), isApplied, isLoading);
+                    setCouponCodeAction(couponCode(), isApplied);
                 }
             },
+
             /**
              * Cancel using coupon
              */
             cancel: function() {
                 if (this.validate()) {
-                    isLoading(true);
                     couponCode('');
-                    cancelCouponAction(isApplied, isLoading);
+                    cancelCouponAction(isApplied);
                 }
             },
+
             /**
              * Coupon form validation
              *
-             * @returns {boolean}
+             * @returns {Boolean}
              */
-            validate: function() {
+            validate: function () {
                 var form = '#discount-form';
+
                 return $(form).validation() && $(form).validation('isValid');
             }
         });
diff --git a/app/code/Magento/SalesRule/view/frontend/web/template/payment/discount.html b/app/code/Magento/SalesRule/view/frontend/web/template/payment/discount.html
index d6bc4c764d5714382d017adce856deaf84c8b3ff..4ba38906fe9c1e98c8d248574585cc01ef815914 100644
--- a/app/code/Magento/SalesRule/view/frontend/web/template/payment/discount.html
+++ b/app/code/Magento/SalesRule/view/frontend/web/template/payment/discount.html
@@ -15,7 +15,7 @@
         <!-- ko foreach: getRegion('messages') -->
         <!-- ko template: getTemplate() --><!-- /ko -->
         <!--/ko-->
-        <form class="form form-discount" id="discount-form" data-bind="blockLoader: isLoading">
+        <form class="form form-discount" id="discount-form">
             <div class="payment-option-inner">
                 <div class="field">
                     <label class="label" for="discount-code">
diff --git a/app/code/Magento/SalesSequence/composer.json b/app/code/Magento/SalesSequence/composer.json
index eeda2be05e68f86cb5552e6f48ca502dd96cb9be..5b9efe61f72724e28d23c1af0dc197fede8e117f 100644
--- a/app/code/Magento/SalesSequence/composer.json
+++ b/app/code/Magento/SalesSequence/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-sales-sequence",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/framework": "100.2.*"
     },
     "type": "magento2-module",
diff --git a/app/code/Magento/SampleData/composer.json b/app/code/Magento/SampleData/composer.json
index 936bbf0d6be3a7399babc2e835282e7c71bea4c2..4c98a5abd3a16ab72b5ea04e0606955986924ebd 100644
--- a/app/code/Magento/SampleData/composer.json
+++ b/app/code/Magento/SampleData/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-sample-data",
     "description": "Sample Data fixtures",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/framework": "100.2.*"
     },
     "suggest": {
diff --git a/app/code/Magento/Search/composer.json b/app/code/Magento/Search/composer.json
index cc95e6784526f33bb65246b599a4147e8a1afa1d..8f809fb3b8af3533c4715aea1e13854650e0cbac 100644
--- a/app/code/Magento/Search/composer.json
+++ b/app/code/Magento/Search/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-search",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/framework": "100.2.*",
         "magento/module-backend": "100.2.*",
         "magento/module-catalog-search": "100.2.*",
diff --git a/app/code/Magento/Security/composer.json b/app/code/Magento/Security/composer.json
index f64c0f0b29d282b0feaefb24ebb3963086f0e083..4048b63bf607030d27ae7fa84dbec6a0da838957 100644
--- a/app/code/Magento/Security/composer.json
+++ b/app/code/Magento/Security/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-security",
     "description": "Security management module",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-backend": "100.2.*",
         "magento/module-store": "100.2.*",
         "magento/framework": "100.2.*"
diff --git a/app/code/Magento/SendFriend/composer.json b/app/code/Magento/SendFriend/composer.json
index de9dbf7a84576022d8f6b1a38324f902565870df..1095dedc0ba6606107660d65373096d8c82b204c 100644
--- a/app/code/Magento/SendFriend/composer.json
+++ b/app/code/Magento/SendFriend/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-send-friend",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-store": "100.2.*",
         "magento/module-catalog": "101.1.*",
         "magento/module-customer": "100.2.*",
diff --git a/app/code/Magento/Shipping/composer.json b/app/code/Magento/Shipping/composer.json
index dc9ea808c0f7b19e396a7c73f2b416221729a34b..03f51bbd95e0ff5f65b88e565cfbe77102a44760 100644
--- a/app/code/Magento/Shipping/composer.json
+++ b/app/code/Magento/Shipping/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-shipping",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-store": "100.2.*",
         "magento/module-catalog": "101.1.*",
         "magento/module-sales": "100.2.*",
diff --git a/app/code/Magento/Sitemap/composer.json b/app/code/Magento/Sitemap/composer.json
index be553a4da194f4dbf64fb4237fd92bb27e4e17ff..9f556178fc2cccfd070c272a89164e438f1d33e8 100644
--- a/app/code/Magento/Sitemap/composer.json
+++ b/app/code/Magento/Sitemap/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-sitemap",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-store": "100.2.*",
         "magento/module-catalog": "101.1.*",
         "magento/module-eav": "100.2.*",
diff --git a/app/code/Magento/Store/composer.json b/app/code/Magento/Store/composer.json
index b9f76f6c2c3137aa21d8f4a6cf97880fdc3e72f6..d5b8a2b4b980b58648c04cfed916b5bd390db048 100644
--- a/app/code/Magento/Store/composer.json
+++ b/app/code/Magento/Store/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-store",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-catalog": "101.1.*",
         "magento/module-directory": "100.2.*",
         "magento/module-ui": "100.2.*",
diff --git a/app/code/Magento/Swagger/composer.json b/app/code/Magento/Swagger/composer.json
index dc2d1cbee003de647cf72f7312ad7f7fcc222e3b..47e347426c83fdb1b969c5a03bd46d1776e89950 100644
--- a/app/code/Magento/Swagger/composer.json
+++ b/app/code/Magento/Swagger/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-swagger",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/framework": "100.2.*"
     },
     "type": "magento2-module",
diff --git a/app/code/Magento/Swatches/composer.json b/app/code/Magento/Swatches/composer.json
index f87fdb635cb73386b40fec6ac932eaee3f9cd398..b61ff41d8c955890aae0c22baedcdb8abd22e004 100644
--- a/app/code/Magento/Swatches/composer.json
+++ b/app/code/Magento/Swatches/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-swatches",
     "description": "Add Swatches to Products",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-catalog": "101.1.*",
         "magento/module-configurable-product": "100.2.*",
         "magento/module-eav": "100.2.*",
diff --git a/app/code/Magento/SwatchesLayeredNavigation/composer.json b/app/code/Magento/SwatchesLayeredNavigation/composer.json
index 9b658d0a42e61e0b556f1aa5aed6e12ed8cfdbe7..67c6d90c51e7f81de645451da6553bcdb750fddd 100644
--- a/app/code/Magento/SwatchesLayeredNavigation/composer.json
+++ b/app/code/Magento/SwatchesLayeredNavigation/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-swatches-layered-navigation",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/framework": "100.2.*",
         "magento/magento-composer-installer": "*"
     },
diff --git a/app/code/Magento/Tax/composer.json b/app/code/Magento/Tax/composer.json
index 4553fdbb383323732b667df9be3e140aca011744..3dfacaaecd9635dec8229175de2876da6c957a77 100644
--- a/app/code/Magento/Tax/composer.json
+++ b/app/code/Magento/Tax/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-tax",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-config": "100.2.*",
         "magento/module-store": "100.2.*",
         "magento/module-catalog": "101.1.*",
diff --git a/app/code/Magento/TaxImportExport/composer.json b/app/code/Magento/TaxImportExport/composer.json
index c3d09e4926e02d67a98c0e15c050d67997ae1ecd..9d9cac5dec59c94e8013bc5ab3275fee84c73b6b 100644
--- a/app/code/Magento/TaxImportExport/composer.json
+++ b/app/code/Magento/TaxImportExport/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-tax-import-export",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-tax": "100.2.*",
         "magento/module-backend": "100.2.*",
         "magento/module-directory": "100.2.*",
diff --git a/app/code/Magento/Theme/composer.json b/app/code/Magento/Theme/composer.json
index 49382f9642fa5d2b88d7d2f4cea79c07d5306cb1..7158ac314076d38aae4766bbea1a917dc869b5dd 100644
--- a/app/code/Magento/Theme/composer.json
+++ b/app/code/Magento/Theme/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-theme",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-store": "100.2.*",
         "magento/module-customer": "100.2.*",
         "magento/module-backend": "100.2.*",
diff --git a/app/code/Magento/Theme/view/frontend/layout/default.xml b/app/code/Magento/Theme/view/frontend/layout/default.xml
index a2e89afcce1ee0461921678bb1c5888c7dd3151f..0f020db7501ae725b25f0bd8bfda51ae5c74be1c 100644
--- a/app/code/Magento/Theme/view/frontend/layout/default.xml
+++ b/app/code/Magento/Theme/view/frontend/layout/default.xml
@@ -40,7 +40,7 @@
                         </arguments>
                     </block>
                     <block class="Magento\Store\Block\Switcher" name="store_language" as="store_language" template="switch/languages.phtml"/>
-                    <block class="Magento\Framework\View\Element\Html\Links" name="top.links">
+                    <block class="Magento\Customer\Block\Account\Navigation" name="top.links">
                         <arguments>
                             <argument name="css_class" xsi:type="string">header links</argument>
                         </arguments>
diff --git a/app/code/Magento/Translation/composer.json b/app/code/Magento/Translation/composer.json
index 9ea00544d805094927499672f98fb72ad12ae97a..b9ed830c9053ea492d76a2402ec8f523fb03a46a 100644
--- a/app/code/Magento/Translation/composer.json
+++ b/app/code/Magento/Translation/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-translation",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-backend": "100.2.*",
         "magento/module-developer": "100.2.*",
         "magento/module-store": "100.2.*",
diff --git a/app/code/Magento/Ui/README.md b/app/code/Magento/Ui/README.md
index 1337383ea3fb83bf3e2927589859587aad5a48f7..b7dd1a858e4a8161f836b3ea73d1483ae56ba2dd 100644
--- a/app/code/Magento/Ui/README.md
+++ b/app/code/Magento/Ui/README.md
@@ -1,7 +1,7 @@
 # Overview
 ## Purpose of module
 
-The Magento\Ui module introduces a set of common UI components, which could be easily used and configured via layout XML files.
+The Magento\Ui module introduces a set of common UI components, which could be used and configured via layout XML files.
 
 # Deployment
 ## System requirements
diff --git a/app/code/Magento/Ui/composer.json b/app/code/Magento/Ui/composer.json
index 43c7b7fa3011fd7c6386fcde17eb45b6c5e02695..a3de6c6dfbdde7860dbb07503e0e6fe25e8b3dcf 100644
--- a/app/code/Magento/Ui/composer.json
+++ b/app/code/Magento/Ui/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-ui",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-backend": "100.2.*",
         "magento/framework": "100.2.*",
         "magento/module-eav": "100.2.*",
diff --git a/app/code/Magento/Ui/view/base/web/js/dynamic-rows/dynamic-rows-grid.js b/app/code/Magento/Ui/view/base/web/js/dynamic-rows/dynamic-rows-grid.js
index de10c065d123bf773f9fba66135b2308a2abe3e9..518f09fa73ba6c6771654c7c9fc3f3ce07be79be 100644
--- a/app/code/Magento/Ui/view/base/web/js/dynamic-rows/dynamic-rows-grid.js
+++ b/app/code/Magento/Ui/view/base/web/js/dynamic-rows/dynamic-rows-grid.js
@@ -52,13 +52,15 @@ define([
                 obj;
 
             if (this.recordData().length && !this.update) {
-                this.recordData.each(function (recordData) {
+                _.each(this.recordData(), function (recordData) {
                     obj = {};
                     obj[this.map[this.identificationProperty]] = recordData[this.identificationProperty];
                     insertData.push(obj);
                 }, this);
 
-                this.source.set(this.dataProvider, insertData);
+                if (insertData.length) {
+                    this.source.set(this.dataProvider, insertData);
+                }
             }
         },
 
@@ -178,7 +180,7 @@ define([
                 tmpObj = {};
 
             if (data.length !== this.relatedData.length) {
-                data.forEach(function (obj) {
+                _.each(data, function (obj) {
                     tmpObj[this.identificationDRProperty] = obj[this.identificationDRProperty];
 
                     if (!_.findWhere(this.relatedData, tmpObj)) {
@@ -193,7 +195,7 @@ define([
         /**
          * Processing insert data
          *
-         * @param {Array} data
+         * @param {Object} data
          */
         processingInsertData: function (data) {
             var changes,
diff --git a/app/code/Magento/Ui/view/base/web/js/form/element/file-uploader.js b/app/code/Magento/Ui/view/base/web/js/form/element/file-uploader.js
index 1805dcd2f004ec91e5d3d1a96d2b0086e4b69e8c..917dc62f9f49b148d58ad62c671eb6fbeeff8beb 100644
--- a/app/code/Magento/Ui/view/base/web/js/form/element/file-uploader.js
+++ b/app/code/Magento/Ui/view/base/web/js/form/element/file-uploader.js
@@ -294,15 +294,20 @@ define([
         /**
          * Handler which is invoked prior to the start of a file upload.
          *
-         * @param {Event} e - Event obejct.
+         * @param {Event} e - Event object.
          * @param {Object} data - File data that will be uploaded.
          */
         onBeforeFileUpload: function (e, data) {
             var file     = data.files[0],
-                allowed  = this.isFileAllowed(file);
+                allowed  = this.isFileAllowed(file),
+                target   = $(e.target);
 
             if (allowed.passed) {
-                $(e.target).fileupload('process', data).done(function () {
+                target.on('fileuploadsend', function (event, postData) {
+                    postData.data.set('param_name', this.paramName);
+                }.bind(data));
+
+                target.fileupload('process', data).done(function () {
                     data.submit();
                 });
             } else {
diff --git a/app/code/Magento/Ui/view/base/web/js/form/element/ui-select.js b/app/code/Magento/Ui/view/base/web/js/form/element/ui-select.js
index be312c71f1fb20a1a2140765d598d8567bfaf648..b640b131aaf6fcb52ca883da80de65ab0cd75dd3 100644
--- a/app/code/Magento/Ui/view/base/web/js/form/element/ui-select.js
+++ b/app/code/Magento/Ui/view/base/web/js/form/element/ui-select.js
@@ -161,7 +161,6 @@ define([
                 defaultPlaceholder: $t('Select...'),
                 lotPlaceholders: $t('Selected')
             },
-            hoverElIndex: null,
             separator: 'optgroup',
             listens: {
                 listVisible: 'cleanHoveredElement',
@@ -295,7 +294,6 @@ define([
             this._super();
             this.observe([
                 'listVisible',
-                'hoverElIndex',
                 'placeholder',
                 'multiselectFocus',
                 'options',
@@ -539,7 +537,7 @@ define([
         },
 
         /**
-         * Clean hoverElIndex variable
+         * Clean hoveredElement variable
          *
          * @returns {Object} Chainable
          */
diff --git a/app/code/Magento/Ui/view/base/web/js/lib/core/collection.js b/app/code/Magento/Ui/view/base/web/js/lib/core/collection.js
index 49133721369c85dba954788626875d1a13c26a1e..493b8c78f0cdfbf56f43c8775ab2fcd0edf5ff64 100644
--- a/app/code/Magento/Ui/view/base/web/js/lib/core/collection.js
+++ b/app/code/Magento/Ui/view/base/web/js/lib/core/collection.js
@@ -268,6 +268,14 @@ define([
 
             _.each(grouped, this.updateRegion, this);
 
+            _.each(this.regions, function (items) {
+                var hasObsoleteComponents = items().length && !_.intersection(_elems, items()).length;
+
+                if (hasObsoleteComponents) {
+                    items.removeAll();
+                }
+            });
+
             this.elems(_elems);
 
             return this;
diff --git a/app/code/Magento/Ui/view/base/web/js/lib/knockout/bindings/datepicker.js b/app/code/Magento/Ui/view/base/web/js/lib/knockout/bindings/datepicker.js
index 16c102b8367f4b8762030057c4d249adb132693b..77d3a069ccef76bbcacad28459820b3359b025e7 100644
--- a/app/code/Magento/Ui/view/base/web/js/lib/knockout/bindings/datepicker.js
+++ b/app/code/Magento/Ui/view/base/web/js/lib/knockout/bindings/datepicker.js
@@ -51,7 +51,12 @@ define([
 
             observable() && $(el).datepicker(
                 'setDate',
-                moment(observable(), utils.normalizeDate(config.options.dateFormat)).toDate()
+                moment(
+                    observable(),
+                    utils.normalizeDate(
+                        options.dateFormat + (options.showsTime ? ' ' + options.timeFormat : '')
+                    )
+                ).toDate()
             );
 
             $(el).blur();
diff --git a/app/code/Magento/Ui/view/base/web/templates/dynamic-rows/templates/collapsible.html b/app/code/Magento/Ui/view/base/web/templates/dynamic-rows/templates/collapsible.html
index f3319a05525f2f55bc4ba43ec5ce9bc1e4e2c300..d1ec1d26df6c56dff099b09aa0eb83232687573e 100644
--- a/app/code/Magento/Ui/view/base/web/templates/dynamic-rows/templates/collapsible.html
+++ b/app/code/Magento/Ui/view/base/web/templates/dynamic-rows/templates/collapsible.html
@@ -43,6 +43,7 @@
                             </div>
 
                             <button class="action-delete"
+                                    data-index="delete_button"
                                     type="button"
                                     title="'Delete'"
                                     click="function(){
diff --git a/app/code/Magento/Ups/composer.json b/app/code/Magento/Ups/composer.json
index ade4e738a68efe0499041830892bb6b61f5a3156..c20dd28ba88876a70c04ea49038b94f82d3d9b06 100644
--- a/app/code/Magento/Ups/composer.json
+++ b/app/code/Magento/Ups/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-ups",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-store": "100.2.*",
         "magento/module-backend": "100.2.*",
         "magento/module-sales": "100.2.*",
diff --git a/app/code/Magento/UrlRewrite/composer.json b/app/code/Magento/UrlRewrite/composer.json
index ac75ecdf61b8fd0531f2b14f76d2aec7d72581be..290ffc6731d89ce142e94c58616ca1a74c82c54b 100644
--- a/app/code/Magento/UrlRewrite/composer.json
+++ b/app/code/Magento/UrlRewrite/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-url-rewrite",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-catalog": "101.1.*",
         "magento/module-store": "100.2.*",
         "magento/framework": "100.2.*",
diff --git a/app/code/Magento/User/Block/User/Edit.php b/app/code/Magento/User/Block/User/Edit.php
index f6c5b484861de36850d848e0eba2382d9688dade..116acd132a8487dbe56d933f307c40e62327bf6e 100644
--- a/app/code/Magento/User/Block/User/Edit.php
+++ b/app/code/Magento/User/Block/User/Edit.php
@@ -50,7 +50,7 @@ class Edit extends \Magento\Backend\Block\Widget\Form\Container
         $this->buttonList->update('save', 'label', __('Save User'));
         $this->buttonList->remove('delete');
 
-        $objId = $this->getRequest()->getParam($this->_objectId);
+        $objId = (int)$this->getRequest()->getParam($this->_objectId);
 
         if (!empty($objId)) {
             $this->addButton(
@@ -58,12 +58,9 @@ class Edit extends \Magento\Backend\Block\Widget\Form\Container
                 [
                     'label' => __('Delete User'),
                     'class' => 'delete',
-                    'onclick' => sprintf(
-                        'deleteConfirm("%s", "%s", %s)',
-                        __('Are you sure you want to do this?'),
-                        $this->getUrl('adminhtml/*/delete'),
-                        json_encode(['data' => ['user_id' => $objId]])
-                    ),
+                    'data_attribute' => [
+                        'role' => 'delete-user'
+                    ]
                 ]
             );
 
@@ -79,6 +76,44 @@ class Edit extends \Magento\Backend\Block\Widget\Form\Container
         }
     }
 
+    /**
+     * Returns message that is displayed for admin when he deletes user from the system.
+     * To see this message admin must do the following:
+     * - open user's account for editing;
+     * - type current user's password in the "Current User Identity Verification" field
+     * - click "Delete User" at top left part of the page;
+     *
+     * @return \Magento\Framework\Phrase
+     */
+    public function getDeleteMessage()
+    {
+        return __('Are you sure you want to do this?');
+    }
+
+    /**
+     * Returns the URL that is used for user deletion.
+     * The following Action is executed if admin navigates to returned url
+     * Magento\User\Controller\Adminhtml\User\Delete
+     *
+     * @return string
+     */
+    public function getDeleteUrl()
+    {
+        return $this->getUrl('adminhtml/*/delete');
+    }
+
+    /**
+     * This method is used to get the ID of the user who's account the Admin is editing.
+     * It can be used to determine the reason Admin opens the page:
+     * to create a new user account OR to edit the previously created user account
+     *
+     * @return int
+     */
+    public function getObjectId()
+    {
+        return (int)$this->getRequest()->getParam($this->_objectId);
+    }
+
     /**
      * @return \Magento\Framework\Phrase
      */
diff --git a/app/code/Magento/User/Controller/Adminhtml/User/Delete.php b/app/code/Magento/User/Controller/Adminhtml/User/Delete.php
index d892c8533a29716b1206ba8ee8dbeaccfc3defce..3ff336eeecff87361e79f260f30f0b77cd2c1a03 100644
--- a/app/code/Magento/User/Controller/Adminhtml/User/Delete.php
+++ b/app/code/Magento/User/Controller/Adminhtml/User/Delete.php
@@ -6,6 +6,9 @@
  */
 namespace Magento\User\Controller\Adminhtml\User;
 
+use Magento\User\Block\User\Edit\Tab\Main as UserEdit;
+use Magento\Framework\Exception\AuthenticationException;
+
 class Delete extends \Magento\User\Controller\Adminhtml\User
 {
     /**
@@ -13,8 +16,10 @@ class Delete extends \Magento\User\Controller\Adminhtml\User
      */
     public function execute()
     {
+        /** @var \Magento\User\Model\User */
         $currentUser = $this->_objectManager->get(\Magento\Backend\Model\Auth\Session::class)->getUser();
         $userId = (int)$this->getRequest()->getPost('user_id');
+
         if ($userId) {
             if ($currentUser->getId() == $userId) {
                 $this->messageManager->addError(__('You cannot delete your own account.'));
@@ -22,6 +27,11 @@ class Delete extends \Magento\User\Controller\Adminhtml\User
                 return;
             }
             try {
+                $currentUserPassword = (string)$this->getRequest()->getPost(UserEdit::CURRENT_USER_PASSWORD_FIELD);
+                if (empty($currentUserPassword)) {
+                    throw new AuthenticationException(__('You have entered an invalid password for current user.'));
+                }
+                $currentUser->performIdentityCheck($currentUserPassword);
                 /** @var \Magento\User\Model\User $model */
                 $model = $this->_userFactory->create();
                 $model->setId($userId);
diff --git a/app/code/Magento/User/Test/Unit/Controller/Adminhtml/User/DeleteTest.php b/app/code/Magento/User/Test/Unit/Controller/Adminhtml/User/DeleteTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..b88b28f0016964288bca46f793f0f5adb349dd39
--- /dev/null
+++ b/app/code/Magento/User/Test/Unit/Controller/Adminhtml/User/DeleteTest.php
@@ -0,0 +1,215 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\User\Test\Unit\Controller\Adminhtml\User;
+
+use Magento\Backend\Model\Auth\Session;
+use Magento\Framework\Exception\AuthenticationException;
+
+/**
+ * Test class for \Magento\User\Controller\Adminhtml\User\Delete testing
+ */
+class DeleteTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\User\Controller\Adminhtml\User\Delete
+     */
+    private $controller;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Framework\App\RequestInterface
+     */
+    private $requestMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Framework\App\ResponseInterface
+     */
+    private $responseMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject|Session
+     */
+    private $authSessionMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Framework\ObjectManagerInterface
+     */
+    private $objectManagerMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\User\Model\UserFactory
+     */
+    private $userFactoryMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\User\Model\User
+     */
+    private $userMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Framework\Message\ManagerInterface
+     */
+    private $messageManagerMock;
+
+    /**
+     * @return void
+     */
+    protected function setUp()
+    {
+        $this->objectManagerMock = $this->getMockBuilder(\Magento\Framework\ObjectManager\ObjectManager::class)
+            ->disableOriginalConstructor()
+            ->setMethods(['get', 'create'])
+            ->getMock();
+
+        $this->responseMock = $this->getMockBuilder(\Magento\Framework\App\ResponseInterface::class)
+            ->disableOriginalConstructor()
+            ->setMethods(['setRedirect'])
+            ->getMockForAbstractClass();
+
+        $this->requestMock = $this->getMockBuilder(\Magento\Framework\App\RequestInterface::class)
+            ->disableOriginalConstructor()
+            ->setMethods(['getPost'])
+            ->getMockForAbstractClass();
+
+        $this->authSessionMock = $this->getMockBuilder(Session::class)
+            ->disableOriginalConstructor()
+            ->setMethods(['getUser'])
+            ->getMock();
+
+        $this->userMock = $this->getMockBuilder(\Magento\User\Model\User::class)
+            ->disableOriginalConstructor()
+            ->setMethods(['getId', 'performIdentityCheck', 'delete'])
+            ->getMock();
+
+        $this->userFactoryMock = $this->getMockBuilder(\Magento\User\Model\UserFactory::class)
+            ->disableOriginalConstructor()
+            ->setMethods(['create'])
+            ->getMock();
+
+        $this->messageManagerMock = $this->getMockBuilder(\Magento\Framework\Message\ManagerInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
+
+        $this->controller = $objectManager->getObject(
+            \Magento\User\Controller\Adminhtml\User\Delete::class,
+            [
+                'request'        => $this->requestMock,
+                'response'       => $this->responseMock,
+                'objectManager'  => $this->objectManagerMock,
+                'messageManager' => $this->messageManagerMock,
+                'userFactory'  => $this->userFactoryMock,
+            ]
+        );
+    }
+
+    /**
+     * Test method \Magento\User\Controller\Adminhtml\User\Delete::execute
+     *
+     * @param string $currentUserPassword
+     * @param int    $userId
+     * @param int    $currentUserId
+     * @param string $resultMethod
+     *
+     * @dataProvider executeDataProvider
+     * @return void
+     *
+     */
+    public function testExecute($currentUserPassword, $userId, $currentUserId, $resultMethod)
+    {
+        $currentUserMock = $this->userMock;
+        $this->authSessionMock->expects($this->any())->method('getUser')->will($this->returnValue($currentUserMock));
+
+        $currentUserMock->expects($this->any())->method('getId')->willReturn($currentUserId);
+
+        $this->objectManagerMock
+            ->expects($this->any())
+            ->method('get')
+            ->with(Session::class)
+            ->willReturn($this->authSessionMock);
+
+        $this->requestMock->expects($this->any())
+            ->method('getPost')
+            ->willReturnMap([
+                ['user_id', $userId],
+                [\Magento\User\Block\User\Edit\Tab\Main::CURRENT_USER_PASSWORD_FIELD, $currentUserPassword],
+            ]);
+
+        $userMock = clone $currentUserMock;
+
+        $this->userFactoryMock->expects($this->any())->method('create')->will($this->returnValue($userMock));
+        $this->responseMock->expects($this->any())->method('setRedirect')->willReturnSelf();
+        $this->userMock->expects($this->any())->method('delete')->willReturnSelf();
+        $this->messageManagerMock->expects($this->once())->method($resultMethod);
+
+        $this->controller->execute();
+    }
+
+    /**
+     * @return void
+     */
+    public function testEmptyPasswordThrowsException()
+    {
+        try {
+            $currentUserId = 1;
+            $userId = 2;
+
+            $currentUserMock = $this->userMock;
+            $this->authSessionMock->expects($this->any())
+                ->method('getUser')
+                ->will($this->returnValue($currentUserMock));
+
+            $currentUserMock->expects($this->any())->method('getId')->willReturn($currentUserId);
+
+            $this->objectManagerMock
+                ->expects($this->any())
+                ->method('get')
+                ->with(Session::class)
+                ->willReturn($this->authSessionMock);
+
+            $this->requestMock->expects($this->any())
+                ->method('getPost')
+                ->willReturnMap([
+                    ['user_id', $userId],
+                    [\Magento\User\Block\User\Edit\Tab\Main::CURRENT_USER_PASSWORD_FIELD, ''],
+                ]);
+
+            $this->controller->execute();
+        } catch (AuthenticationException $e) {
+            $this->assertEquals($e->getMessage(), 'You have entered an invalid password for current user.');
+        }
+    }
+
+    /**
+     * Data Provider for execute method
+     *
+     * @return array
+     */
+    public function executeDataProvider()
+    {
+        return [
+            [
+                'currentUserPassword' => '123123q',
+                'userId'              => 1,
+                'currentUserId'       => 2,
+                'resultMethod'        => 'addSuccess',
+            ],
+            [
+                'currentUserPassword' => '123123q',
+                'userId'              => 0,
+                'currentUserId'       => 2,
+                'resultMethod'        => 'addError',
+            ],
+            [
+                'currentUserPassword' => '123123q',
+                'userId'              => 1,
+                'currentUserId'       => 1,
+                'resultMethod'        => 'addError',
+            ],
+        ];
+    }
+}
diff --git a/app/code/Magento/User/composer.json b/app/code/Magento/User/composer.json
index 755c47ac1147612e1e55b589e72afa705b39b0ce..4632e32bc17f90549f7271cadc5e1ef7ba08869e 100644
--- a/app/code/Magento/User/composer.json
+++ b/app/code/Magento/User/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-user",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-store": "100.2.*",
         "magento/module-authorization": "100.2.*",
         "magento/module-backend": "100.2.*",
diff --git a/app/code/Magento/User/view/adminhtml/requirejs-config.js b/app/code/Magento/User/view/adminhtml/requirejs-config.js
index 0424073c4d3db45d39394a95a99b9c697c88367d..44a5b331689bb6573c97da7f1d724e26bbea13ae 100644
--- a/app/code/Magento/User/view/adminhtml/requirejs-config.js
+++ b/app/code/Magento/User/view/adminhtml/requirejs-config.js
@@ -6,7 +6,8 @@
 var config = {
     map: {
         '*': {
-            rolesTree: 'Magento_User/js/roles-tree'
+            rolesTree: 'Magento_User/js/roles-tree',
+            deleteUserAccount: 'Magento_User/js/delete-user-account'
         }
     } 
-};
\ No newline at end of file
+};
diff --git a/app/code/Magento/User/view/adminhtml/templates/user/roles_grid_js.phtml b/app/code/Magento/User/view/adminhtml/templates/user/roles_grid_js.phtml
index bac0dd0b3f869bd33ad5d7e12886f47daded00c2..40287595b937b5426c439e0c688adbf286b36d4e 100644
--- a/app/code/Magento/User/view/adminhtml/templates/user/roles_grid_js.phtml
+++ b/app/code/Magento/User/view/adminhtml/templates/user/roles_grid_js.phtml
@@ -71,3 +71,18 @@ require([
 
 });
 </script>
+
+<?php $editBlock = $block->getLayout()->getBlock('adminhtml.user.edit'); ?>
+<?php if (is_object($editBlock)): ?>
+    <script type="text/x-magento-init">
+        {
+            "[data-role=delete-user]" : {
+                "deleteUserAccount" : {
+                    "message": "<?php echo $editBlock->escapeHtml($editBlock->getDeleteMessage()) ?>",
+                    "url": "<?php /* @noEscape */ echo $editBlock->getDeleteUrl(); ?>",
+                    "objId": "<?php echo $editBlock->escapeHtml($editBlock->getObjectId()) ?>"
+                }
+            }
+        }
+    </script>
+<?php endif; ?>
diff --git a/app/code/Magento/User/view/adminhtml/web/js/delete-user-account.js b/app/code/Magento/User/view/adminhtml/web/js/delete-user-account.js
new file mode 100644
index 0000000000000000000000000000000000000000..b326c7aeb20d06953baf406ecf339d40f5be8bc4
--- /dev/null
+++ b/app/code/Magento/User/view/adminhtml/web/js/delete-user-account.js
@@ -0,0 +1,28 @@
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+define([
+    'jquery'
+], function ($) {
+    'use strict';
+
+    var postData;
+
+    return function (params, elem) {
+
+        elem.on('click', function () {
+
+            postData = {
+                'data': {
+                    'user_id': params.objId,
+                    'current_password': $('[name="current_password"]').val()
+                }
+            };
+
+            if ($.validator.validateElement($('[name="current_password"]'))) {
+                window.deleteConfirm(params.message, params.url, postData);
+            }
+        });
+    };
+});
diff --git a/app/code/Magento/Usps/Model/Carrier.php b/app/code/Magento/Usps/Model/Carrier.php
index d12341659cb6d8ad1fc4acabe0b8052e346ca102..b2345a86bff4d6349035950373d1e7975076f513 100644
--- a/app/code/Magento/Usps/Model/Carrier.php
+++ b/app/code/Magento/Usps/Model/Carrier.php
@@ -426,9 +426,14 @@ class Carrier extends AbstractCarrierOnline implements \Magento\Shipping\Model\C
             if (!$service) {
                 $service = $r->getService();
             }
-            if ($r->getContainer() == 'FLAT RATE BOX' || $r->getContainer() == 'FLAT RATE ENVELOPE') {
+
+            if (
+                strpos($r->getContainer(), 'FLAT RATE ENVELOPE') !== false ||
+                strpos($r->getContainer(), 'FLAT RATE BOX') !== false
+            ) {
                 $service = 'Priority';
             }
+
             $package->addChild('Service', $service);
 
             // no matter Letter, Flat or Parcel, use Parcel
@@ -794,8 +799,15 @@ class Carrier extends AbstractCarrierOnline implements \Magento\Shipping\Model\C
             'first_class_mail_type' => ['LETTER' => __('Letter'), 'FLAT' => __('Flat'), 'PARCEL' => __('Parcel')],
             'container' => [
                 'VARIABLE' => __('Variable'),
-                'FLAT RATE BOX' => __('Flat-Rate Box'),
+                'SM FLAT RATE BOX' => __('Small Flat-Rate Box'),
+                'MD FLAT RATE BOX' => __('Medium Flat-Rate Box'),
+                'LG FLAT RATE BOX' => __('Large Flat-Rate Box'),
                 'FLAT RATE ENVELOPE' => __('Flat-Rate Envelope'),
+                'SM FLAT RATE ENVELOPE' => __('Small Flat-Rate Envelope'),
+                'WINDOW FLAT RATE ENVELOPE' => __('Window Flat-Rate Envelope'),
+                'GIFT CARD FLAT RATE ENVELOPE' => __('Gift Card Flat-Rate Envelope'),
+                'LEGAL FLAT RATE ENVELOPE' => __('Legal Flat-Rate Envelope'),
+                'PADDED FLAT RATE ENVELOPE' => __('Padded Flat-Rate Envelope'),
                 'RECTANGULAR' => __('Rectangular'),
                 'NONRECTANGULAR' => __('Non-rectangular'),
             ],
@@ -805,73 +817,103 @@ class Carrier extends AbstractCarrierOnline implements \Magento\Shipping\Model\C
                     'filters' => [
                         'within_us' => [
                             'method' => [
-                                'Priority Mail Express Flat Rate Envelope',
-                                'Priority Mail Express Flat Rate Envelope Hold For Pickup',
-                                'Priority Mail Flat Rate Envelope',
-                                'Priority Mail Large Flat Rate Box',
-                                'Priority Mail Medium Flat Rate Box',
-                                'Priority Mail Small Flat Rate Box',
-                                'Priority Mail Express Hold For Pickup',
-                                'Priority Mail Express',
-                                'Priority Mail',
-                                'Priority Mail Hold For Pickup',
-                                'Priority Mail Large Flat Rate Box Hold For Pickup',
-                                'Priority Mail Medium Flat Rate Box Hold For Pickup',
-                                'Priority Mail Small Flat Rate Box Hold For Pickup',
-                                'Priority Mail Flat Rate Envelope Hold For Pickup',
-                                'Priority Mail Small Flat Rate Envelope',
-                                'Priority Mail Small Flat Rate Envelope Hold For Pickup',
-                                'First-Class Package Service Hold For Pickup',
-                                'Retail Ground',
-                                'Media Mail',
-                                'First-Class Mail Large Envelope',
-                                'Priority Mail Express Sunday/Holiday Delivery',
-                                'Priority Mail Express Sunday/Holiday Delivery Flat Rate Envelope',
-                                'Priority Mail Express Sunday/Holiday Delivery Flat Rate Boxes',
+                                '13', '27', '16', '22', '17', '28', '2', '3', '1', '33', '34', '35',
+                                '36', '37', '42', '43', '53', '4', '6', '15', '23', '25', '57'
                             ],
                         ],
                         'from_us' => [
                             'method' => [
-                                'Priority Mail Express International Flat Rate Envelope',
-                                'Priority Mail International Flat Rate Envelope',
-                                'Priority Mail International Large Flat Rate Box',
-                                'Priority Mail International Medium Flat Rate Box',
-                                'Priority Mail International Small Flat Rate Box',
-                                'Priority Mail International Small Flat Rate Envelope',
-                                'Priority Mail Express International Flat Rate Boxes',
-                                'Global Express Guaranteed (GXG)',
-                                'USPS GXG Envelopes',
-                                'Priority Mail Express International',
-                                'Priority Mail International',
-                                'First-Class Mail International Letter',
-                                'First-Class Mail International Large Envelope',
-                                'First-Class Package International Service',
+                                'INT_10', 'INT_8', 'INT_11', 'INT_9', 'INT_16', 'INT_20', 'INT_4',
+                                'INT_12', 'INT_1', 'INT_2', 'INT_13', 'INT_14', 'INT_15'
                             ],
                         ],
                     ],
                 ],
                 [
-                    'containers' => ['FLAT RATE BOX'],
+                    'containers' => ['SM FLAT RATE BOX'],
                     'filters' => [
                         'within_us' => [
-                            'method' => [
-                                'Priority Mail Large Flat Rate Box',
-                                'Priority Mail Medium Flat Rate Box',
-                                'Priority Mail Small Flat Rate Box',
-                                'Priority Mail International Large Flat Rate Box',
-                                'Priority Mail International Medium Flat Rate Box',
-                                'Priority Mail International Small Flat Rate Box',
-                                'Priority Mail Express Sunday/Holiday Delivery Flat Rate Boxes',
-                            ],
+                            'method' => ['28', '57'],
                         ],
                         'from_us' => [
-                            'method' => [
-                                'Priority Mail International Large Flat Rate Box',
-                                'Priority Mail International Medium Flat Rate Box',
-                                'Priority Mail International Small Flat Rate Box',
-                                'Priority Mail International DVD Flat Rate priced box',
-                                'Priority Mail International Large Video Flat Rate priced box',
-                            ],
+                            'method' => ['INT_16', 'INT_24'],
+                        ],
+                    ]
+                ],
+                [
+                    'containers' => ['MD FLAT RATE BOX'],
+                    'filters' => [
+                        'within_us' => [
+                            'method' => ['17', '57'],
+                        ],
+                        'from_us' => [
+                            'method' => ['INT_9', 'INT_24'],
+                        ],
+                    ]
+                ],
+                [
+                    'containers' => ['LG FLAT RATE BOX'],
+                    'filters' => [
+                        'within_us' => [
+                            'method' => ['22', '57'],
+                        ],
+                        'from_us' => [
+                            'method' => ['INT_11', 'INT_24', 'INT_25'],
+                        ],
+                    ]
+                ],
+                [
+                    'containers' => ['SM FLAT RATE ENVELOPE'],
+                    'filters' => [
+                        'within_us' => [
+                            'method' => ['42', '43'],
+                        ],
+                        'from_us' => [
+                            'method' => ['INT_20'],
+                        ],
+                    ]
+                ],
+                [
+                    'containers' => ['WINDOW FLAT RATE ENVELOPE'],
+                    'filters' => [
+                        'within_us' => [
+                            'method' => ['40', '41'],
+                        ],
+                        'from_us' => [
+                            'method' => ['INT_19'],
+                        ],
+                    ]
+                ],
+                [
+                    'containers' => ['GIFT CARD FLAT RATE ENVELOPE'],
+                    'filters' => [
+                        'within_us' => [
+                            'method' => ['38', '39'],
+                        ],
+                        'from_us' => [
+                            'method' => ['INT_18'],
+                        ],
+                    ]
+                ],
+                [
+                    'containers' => ['PADDED FLAT RATE ENVELOPE'],
+                    'filters' => [
+                        'within_us' => [
+                            'method' => ['62', '63', '64', '46', '29'],
+                        ],
+                        'from_us' => [
+                            'method' => ['INT_27', 'INT_23'],
+                        ],
+                    ]
+                ],
+                [
+                    'containers' => ['LEGAL FLAT RATE ENVELOPE'],
+                    'filters' => [
+                        'within_us' => [
+                            'method' => ['44', '45', '30', '31', '32'],
+                        ],
+                        'from_us' => [
+                            'method' => ['INT_17', 'INT_22'],
                         ],
                     ]
                 ],
@@ -879,30 +921,11 @@ class Carrier extends AbstractCarrierOnline implements \Magento\Shipping\Model\C
                     'containers' => ['FLAT RATE ENVELOPE'],
                     'filters' => [
                         'within_us' => [
-                            'method' => [
-                                'Priority Mail Flat Rate Envelope',
-                                'Priority Mail Express Flat Rate Envelope',
-                                'Priority Mail Express Flat Rate Envelope Hold For Pickup',
-                                'Priority Mail Flat Rate Envelope',
-                                'First-Class Mail Large Envelope',
-                                'Priority Mail Flat Rate Envelope Hold For Pickup',
-                                'Priority Mail Small Flat Rate Envelope',
-                                'Priority Mail Small Flat Rate Envelope Hold For Pickup',
-                                'Priority Mail Express Sunday/Holiday Delivery Flat Rate Envelope',
-                                'Priority Mail Express Padded Flat Rate Envelope',
-                            ],
+                            'method' => ['16', '13', '27', '16', '15', '37', '42', '43', '25', '62'],
                         ],
                         'from_us' => [
                             'method' => [
-                                'Priority Mail Express International Flat Rate Envelope',
-                                'Priority Mail International Flat Rate Envelope',
-                                'First-Class Mail International Large Envelope',
-                                'Priority Mail International Small Flat Rate Envelope',
-                                'Priority Mail Express International Legal Flat Rate Envelope',
-                                'Priority Mail International Gift Card Flat Rate Envelope',
-                                'Priority Mail International Window Flat Rate Envelope',
-                                'Priority Mail International Legal Flat Rate Envelope',
-                                'Priority Mail Express International Padded Flat Rate Envelope',
+                                'INT_10', 'INT_8', 'INT_14', 'INT_20', 'INT_17', 'INT_18', 'INT_19', 'INT_22', 'INT_27'
                             ],
                         ],
                     ]
@@ -911,22 +934,10 @@ class Carrier extends AbstractCarrierOnline implements \Magento\Shipping\Model\C
                     'containers' => ['RECTANGULAR'],
                     'filters' => [
                         'within_us' => [
-                            'method' => [
-                                'Priority Mail Express',
-                                'Priority Mail',
-                                'Retail Ground',
-                                'Media Mail',
-                                'Library Mail',
-                                'First-Class Package Service',
-                            ],
+                            'method' => ['3', '1', '4', '6', '7', '61'],
                         ],
                         'from_us' => [
-                            'method' => [
-                                'USPS GXG Envelopes',
-                                'Priority Mail Express International',
-                                'Priority Mail International',
-                                'First-Class Package International Service',
-                            ],
+                            'method' => ['INT_12', 'INT_1', 'INT_2', 'INT_15'],
                         ],
                     ]
                 ],
@@ -934,21 +945,10 @@ class Carrier extends AbstractCarrierOnline implements \Magento\Shipping\Model\C
                     'containers' => ['NONRECTANGULAR'],
                     'filters' => [
                         'within_us' => [
-                            'method' => [
-                                'Priority Mail Express',
-                                'Priority Mail',
-                                'Retail Ground',
-                                'Media Mail',
-                                'Library Mail',
-                            ],
+                            'method' => ['3', '1', '4', '6', '7'],
                         ],
                         'from_us' => [
-                            'method' => [
-                                'Global Express Guaranteed (GXG)',
-                                'Priority Mail Express International',
-                                'Priority Mail International',
-                                'First-Class Package International Service',
-                            ],
+                            'method' => ['INT_4', 'INT_1', 'INT_2', 'INT_15'],
                         ],
                     ]
                 ],
diff --git a/app/code/Magento/Usps/composer.json b/app/code/Magento/Usps/composer.json
index 5baccddf4884307f4ebdeed9199fedb00debf4bc..15e93d0bea4fb6d0e89f21f180b2c91486c8f5aa 100644
--- a/app/code/Magento/Usps/composer.json
+++ b/app/code/Magento/Usps/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-usps",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-store": "100.2.*",
         "magento/module-shipping": "100.2.*",
         "magento/module-directory": "100.2.*",
diff --git a/app/code/Magento/Variable/composer.json b/app/code/Magento/Variable/composer.json
index 21f3ec1dd467f240c609d5931ffa5cbde8dc3e15..e4b06d0edb34ab25d4d1279fb463a4f630ee77e9 100644
--- a/app/code/Magento/Variable/composer.json
+++ b/app/code/Magento/Variable/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-variable",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-backend": "100.2.*",
         "magento/module-email": "100.2.*",
         "magento/module-store": "100.2.*",
diff --git a/app/code/Magento/Vault/Model/Method/Vault.php b/app/code/Magento/Vault/Model/Method/Vault.php
index 41a2d6b0e26efcd1c6745f5d5fbc2842ae6c8513..ca6fe06f91eef8ce52e5f0c5b0cdbd7f439f5710 100644
--- a/app/code/Magento/Vault/Model/Method/Vault.php
+++ b/app/code/Magento/Vault/Model/Method/Vault.php
@@ -5,17 +5,16 @@
  */
 namespace Magento\Vault\Model\Method;
 
-use Magento\Framework\DataObject;
 use Magento\Framework\Event\ManagerInterface;
 use Magento\Framework\ObjectManagerInterface;
 use Magento\Payment\Gateway\Command;
-use Magento\Sales\Api\Data\OrderPaymentExtensionInterfaceFactory;
 use Magento\Payment\Gateway\Config\ValueHandlerPoolInterface;
 use Magento\Payment\Gateway\ConfigFactoryInterface;
 use Magento\Payment\Gateway\ConfigInterface;
 use Magento\Payment\Model\InfoInterface;
 use Magento\Payment\Model\MethodInterface;
 use Magento\Payment\Observer\AbstractDataAssignObserver;
+use Magento\Sales\Api\Data\OrderPaymentExtensionInterfaceFactory;
 use Magento\Sales\Api\Data\OrderPaymentInterface;
 use Magento\Sales\Model\Order\Payment;
 use Magento\Vault\Api\Data\PaymentTokenInterface;
@@ -275,7 +274,12 @@ final class Vault implements VaultPaymentInterface
      */
     public function canUseInternal()
     {
-        return $this->getVaultProvider()->canUseInternal();
+        $isInternalAllowed = $this->getConfiguredValue('can_use_internal');
+        // if config has't been specified for Vault, need to check payment provider option
+        if ($isInternalAllowed === null) {
+            return $this->getVaultProvider()->canUseInternal();
+        }
+        return (bool) $isInternalAllowed;
     }
 
     /**
diff --git a/app/code/Magento/Vault/Model/Ui/Adminhtml/TokensConfigProvider.php b/app/code/Magento/Vault/Model/Ui/Adminhtml/TokensConfigProvider.php
index 98e7728f732fe51bcea79e555c5333a9cbd86684..f3a2cbfa78739d0ee748b5e38a01176ae6ed7e67 100644
--- a/app/code/Magento/Vault/Model/Ui/Adminhtml/TokensConfigProvider.php
+++ b/app/code/Magento/Vault/Model/Ui/Adminhtml/TokensConfigProvider.php
@@ -221,9 +221,11 @@ final class TokensConfigProvider
      */
     private function getPaymentTokenEntityId()
     {
-        return $this->getPaymentTokenManagement()
-            ->getByPaymentId($this->getOrderPaymentEntityId())
-            ->getEntityId();
+        $paymentToken = $this->getPaymentTokenManagement()->getByPaymentId($this->getOrderPaymentEntityId());
+        if ($paymentToken === null) {
+            throw new NoSuchEntityException(__('No available payment tokens for specified order payment.'));
+        }
+        return $paymentToken->getEntityId();
     }
 
     /**
diff --git a/app/code/Magento/Vault/Test/Unit/Model/Method/VaultTest.php b/app/code/Magento/Vault/Test/Unit/Model/Method/VaultTest.php
index 8bded498dab765a442ced658ba2562db81ca5b7e..ade93c9367858eafb1cfdf64035d2d4f9354e8a0 100644
--- a/app/code/Magento/Vault/Test/Unit/Model/Method/VaultTest.php
+++ b/app/code/Magento/Vault/Test/Unit/Model/Method/VaultTest.php
@@ -8,6 +8,8 @@ namespace Magento\Vault\Test\Unit\Model\Method;
 use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
 use Magento\Payment\Gateway\Command\CommandManagerInterface;
 use Magento\Payment\Gateway\Command\CommandManagerPoolInterface;
+use Magento\Payment\Gateway\Config\ValueHandlerInterface;
+use Magento\Payment\Gateway\Config\ValueHandlerPoolInterface;
 use Magento\Payment\Gateway\ConfigInterface;
 use Magento\Payment\Model\InfoInterface;
 use Magento\Payment\Model\MethodInterface;
@@ -19,6 +21,7 @@ use Magento\Vault\Api\Data\PaymentTokenInterface;
 use Magento\Vault\Api\PaymentTokenManagementInterface;
 use Magento\Vault\Model\Method\Vault;
 use Magento\Vault\Model\VaultPaymentInterface;
+use PHPUnit_Framework_MockObject_MockObject as MockObject;
 
 /**
  * Class VaultTest
@@ -31,9 +34,15 @@ class VaultTest extends \PHPUnit_Framework_TestCase
      */
     private $objectManager;
 
+    /**
+     * @var MethodInterface|MockObject
+     */
+    private $vaultProvider;
+
     public function setUp()
     {
         $this->objectManager = new ObjectManager($this);
+        $this->vaultProvider = $this->getMock(MethodInterface::class);
     }
 
     /**
@@ -137,8 +146,6 @@ class VaultTest extends \PHPUnit_Framework_TestCase
         $commandManagerPool = $this->getMock(CommandManagerPoolInterface::class);
         $commandManager = $this->getMock(CommandManagerInterface::class);
 
-        $vaultProvider = $this->getMock(MethodInterface::class);
-
         $tokenManagement = $this->getMock(PaymentTokenManagementInterface::class);
         $token = $this->getMock(PaymentTokenInterface::class);
 
@@ -161,7 +168,7 @@ class VaultTest extends \PHPUnit_Framework_TestCase
             ->method('setVaultPaymentToken')
             ->with($token);
 
-        $vaultProvider->expects(static::atLeastOnce())
+        $this->vaultProvider->expects(static::atLeastOnce())
             ->method('getCode')
             ->willReturn($vaultProviderCode);
         $commandManagerPool->expects(static::once())
@@ -188,7 +195,7 @@ class VaultTest extends \PHPUnit_Framework_TestCase
             [
                 'tokenManagement' => $tokenManagement,
                 'commandManagerPool' => $commandManagerPool,
-                'vaultProvider' => $vaultProvider
+                'vaultProvider' => $this->vaultProvider
             ]
         );
         $model->authorize($paymentModel, $amount);
@@ -235,10 +242,9 @@ class VaultTest extends \PHPUnit_Framework_TestCase
     {
         $storeId = 1;
         $quote = $this->getMockForAbstractClass(CartInterface::class);
-        $vaultProvider = $this->getMockForAbstractClass(MethodInterface::class);
         $config = $this->getMockForAbstractClass(ConfigInterface::class);
 
-        $vaultProvider->expects(static::once())
+        $this->vaultProvider->expects(static::once())
             ->method('isAvailable')
             ->with($quote)
             ->willReturn($isAvailableProvider);
@@ -255,7 +261,7 @@ class VaultTest extends \PHPUnit_Framework_TestCase
         /** @var Vault $model */
         $model = $this->objectManager->getObject(Vault::class, [
             'config' => $config,
-            'vaultProvider' => $vaultProvider
+            'vaultProvider' => $this->vaultProvider
         ]);
         $actual = $model->isAvailable($quote);
         static::assertEquals($expected, $actual);
@@ -281,11 +287,9 @@ class VaultTest extends \PHPUnit_Framework_TestCase
     public function testIsAvailableWithoutQuote()
     {
         $quote = null;
-
-        $vaultProvider = $this->getMockForAbstractClass(MethodInterface::class);
         $config = $this->getMockForAbstractClass(ConfigInterface::class);
 
-        $vaultProvider->expects(static::once())
+        $this->vaultProvider->expects(static::once())
             ->method('isAvailable')
             ->with($quote)
             ->willReturn(true);
@@ -298,8 +302,60 @@ class VaultTest extends \PHPUnit_Framework_TestCase
         /** @var Vault $model */
         $model = $this->objectManager->getObject(Vault::class, [
             'config' => $config,
-            'vaultProvider' => $vaultProvider
+            'vaultProvider' => $this->vaultProvider
         ]);
         static::assertFalse($model->isAvailable($quote));
     }
+
+    /**
+     * @covers \Magento\Vault\Model\Method\Vault::canUseInternal
+     * @param bool|null $configValue
+     * @param bool|null $paymentValue
+     * @param bool $expected
+     * @dataProvider internalUsageDataProvider
+     */
+    public function testCanUseInternal($configValue, $paymentValue, $expected)
+    {
+        $handlerPool = $this->getMock(ValueHandlerPoolInterface::class);
+        $handler = $this->getMock(ValueHandlerInterface::class);
+
+        $handlerPool->expects(static::once())
+            ->method('get')
+            ->with('can_use_internal')
+            ->willReturn($handler);
+
+        $handler->expects(static::once())
+            ->method('handle')
+            ->with(['field' => 'can_use_internal'], null)
+            ->willReturn($configValue);
+
+        $this->vaultProvider->expects(static::any())
+            ->method('canUseInternal')
+            ->willReturn($paymentValue);
+
+        /** @var Vault $model */
+        $model = $this->objectManager->getObject(Vault::class, [
+            'vaultProvider' => $this->vaultProvider,
+            'valueHandlerPool' => $handlerPool,
+        ]);
+        static::assertEquals($expected, $model->canUseInternal());
+    }
+
+    /**
+     * Get list of variations for testing canUseInternal method
+     * @return array
+     */
+    public function internalUsageDataProvider()
+    {
+        return [
+            ['configValue' => true, 'paymentValue' => true, 'expected' => true],
+            ['configValue' => true, 'paymentValue' => null, 'expected' => true],
+            ['configValue' => true, 'paymentValue' => false, 'expected' => true],
+            ['configValue' => false, 'paymentValue' => true, 'expected' => false],
+            ['configValue' => false, 'paymentValue' => false, 'expected' => false],
+            ['configValue' => null, 'paymentValue' => true, 'expected' => true],
+            ['configValue' => null, 'paymentValue' => false, 'expected' => false],
+            ['configValue' => null, 'paymentValue' => null, 'expected' => false],
+        ];
+    }
 }
diff --git a/app/code/Magento/Vault/Test/Unit/Model/Ui/Adminhtml/TokensConfigProviderTest.php b/app/code/Magento/Vault/Test/Unit/Model/Ui/Adminhtml/TokensConfigProviderTest.php
index 38948b004eebc358ce82eddf8bf2af88e1685c8c..bbac491386c44a231a1cc650a2ba3acfca791282 100644
--- a/app/code/Magento/Vault/Test/Unit/Model/Ui/Adminhtml/TokensConfigProviderTest.php
+++ b/app/code/Magento/Vault/Test/Unit/Model/Ui/Adminhtml/TokensConfigProviderTest.php
@@ -13,6 +13,7 @@ use Magento\Framework\Api\SearchCriteriaBuilder;
 use Magento\Framework\Exception\InputException;
 use Magento\Framework\Exception\NoSuchEntityException;
 use Magento\Framework\Intl\DateTimeFactory;
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
 use Magento\Framework\TestFramework\Unit\Matcher\MethodInvokedAtIndex;
 use Magento\Payment\Helper\Data;
 use Magento\Sales\Api\Data\OrderInterface;
@@ -29,7 +30,6 @@ use Magento\Vault\Model\Ui\TokenUiComponentInterface;
 use Magento\Vault\Model\Ui\TokenUiComponentProviderInterface;
 use Magento\Vault\Model\VaultPaymentInterface;
 use PHPUnit_Framework_MockObject_MockObject as MockObject;
-use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
 
 /**
  * Class TokensConfigProviderTest
@@ -104,11 +104,21 @@ class TokensConfigProviderTest extends \PHPUnit_Framework_TestCase
      */
     private $orderRepository;
 
+    /**
+     * @var TokenUiComponentProviderInterface|MockObject
+     */
+    private $tokenComponentProvider;
+
     /**
      * @var ObjectManager
      */
     private $objectManager;
 
+    /**
+     * @var TokensConfigProvider
+     */
+    private $configProvider;
+
     protected function setUp()
     {
         $this->paymentTokenRepository = $this->getMockBuilder(PaymentTokenRepositoryInterface::class)
@@ -138,6 +148,38 @@ class TokensConfigProviderTest extends \PHPUnit_Framework_TestCase
         $this->vaultPayment = $this->getMockForAbstractClass(VaultPaymentInterface::class);
         
         $this->objectManager = new ObjectManager($this);
+
+        $this->initStoreMock();
+
+        $this->tokenComponentProvider = $this->getMock(TokenUiComponentProviderInterface::class);
+
+        $this->configProvider = new TokensConfigProvider(
+            $this->session,
+            $this->paymentTokenRepository,
+            $this->filterBuilder,
+            $this->searchCriteriaBuilder,
+            $this->storeManager,
+            $this->dateTimeFactory,
+            [
+                self::VAULT_PROVIDER_CODE => $this->tokenComponentProvider
+            ]
+        );
+
+        $this->objectManager->setBackwardCompatibleProperty(
+            $this->configProvider,
+            'paymentDataHelper',
+            $this->paymentDataHelper
+        );
+        $this->objectManager->setBackwardCompatibleProperty(
+            $this->configProvider,
+            'paymentTokenManagement',
+            $this->paymentTokenManagement
+        );
+        $this->objectManager->setBackwardCompatibleProperty(
+            $this->configProvider,
+            'orderRepository',
+            $this->orderRepository
+        );
     }
 
     /**
@@ -147,8 +189,6 @@ class TokensConfigProviderTest extends \PHPUnit_Framework_TestCase
     {
         $customerId = 1;
 
-        $this->initStoreMock();
-
         $this->session->expects(static::once())
             ->method('getCustomerId')
             ->willReturn($customerId);
@@ -170,7 +210,7 @@ class TokensConfigProviderTest extends \PHPUnit_Framework_TestCase
         $token = $this->getMockBuilder(PaymentTokenInterface::class)
             ->getMockForAbstractClass();
 
-        list($tokenUiComponent, $tokenUiComponentProvider) = $this->getTokenUiComponentProvider($token);
+        $tokenUiComponent = $this->getTokenUiComponentProvider($token);
 
         $searchCriteria = $this->getSearchCriteria($customerId, self::ENTITY_ID, self::VAULT_PROVIDER_CODE);
 
@@ -197,25 +237,7 @@ class TokensConfigProviderTest extends \PHPUnit_Framework_TestCase
             ->method('getItems')
             ->willReturn([$token]);
 
-        $configProvider = new TokensConfigProvider(
-            $this->session,
-            $this->paymentTokenRepository,
-            $this->filterBuilder,
-            $this->searchCriteriaBuilder,
-            $this->storeManager,
-            $this->dateTimeFactory,
-            [
-                self::VAULT_PROVIDER_CODE => $tokenUiComponentProvider
-            ]
-        );
-
-        $this->objectManager->setBackwardCompatibleProperty(
-            $configProvider,
-            'paymentDataHelper',
-            $this->paymentDataHelper
-        );
-
-        static::assertEquals([$tokenUiComponent], $configProvider->getTokensComponents(self::VAULT_PAYMENT_CODE));
+        static::assertEquals([$tokenUiComponent], $this->configProvider->getTokensComponents(self::VAULT_PAYMENT_CODE));
     }
 
     /**
@@ -263,7 +285,7 @@ class TokensConfigProviderTest extends \PHPUnit_Framework_TestCase
             ->method('getEntityId')
             ->willReturn(self::ENTITY_ID);
 
-        list($tokenUiComponent, $tokenUiComponentProvider) = $this->getTokenUiComponentProvider($token);
+        $tokenUiComponent = $this->getTokenUiComponentProvider($token);
 
         $searchCriteria = $this->getSearchCriteria($customerId, self::ENTITY_ID, self::VAULT_PROVIDER_CODE);
 
@@ -290,35 +312,7 @@ class TokensConfigProviderTest extends \PHPUnit_Framework_TestCase
             ->method('getItems')
             ->willReturn([$token]);
 
-        $configProvider = new TokensConfigProvider(
-            $this->session,
-            $this->paymentTokenRepository,
-            $this->filterBuilder,
-            $this->searchCriteriaBuilder,
-            $this->storeManager,
-            $this->dateTimeFactory,
-            [
-                self::VAULT_PROVIDER_CODE => $tokenUiComponentProvider
-            ]
-        );
-
-        $this->objectManager->setBackwardCompatibleProperty(
-            $configProvider,
-            'paymentDataHelper',
-            $this->paymentDataHelper
-        );
-        $this->objectManager->setBackwardCompatibleProperty(
-            $configProvider,
-            'paymentTokenManagement',
-            $this->paymentTokenManagement
-        );
-        $this->objectManager->setBackwardCompatibleProperty(
-            $configProvider,
-            'orderRepository',
-            $this->orderRepository
-        );
-
-        static::assertEquals([$tokenUiComponent], $configProvider->getTokensComponents(self::VAULT_PAYMENT_CODE));
+        static::assertEquals([$tokenUiComponent], $this->configProvider->getTokensComponents(self::VAULT_PAYMENT_CODE));
     }
 
     /**
@@ -330,8 +324,6 @@ class TokensConfigProviderTest extends \PHPUnit_Framework_TestCase
     {
         $customerId = null;
 
-        $this->initStoreMock();
-
         $this->session->expects(static::once())
             ->method('getCustomerId')
             ->willReturn($customerId);
@@ -366,35 +358,7 @@ class TokensConfigProviderTest extends \PHPUnit_Framework_TestCase
         $this->searchCriteriaBuilder->expects(self::never())
             ->method('addFilters');
 
-        $configProvider = new TokensConfigProvider(
-            $this->session,
-            $this->paymentTokenRepository,
-            $this->filterBuilder,
-            $this->searchCriteriaBuilder,
-            $this->storeManager,
-            $this->dateTimeFactory,
-            [
-                self::VAULT_PROVIDER_CODE => $this->getMock(TokenUiComponentProviderInterface::class)
-            ]
-        );
-
-        $this->objectManager->setBackwardCompatibleProperty(
-            $configProvider,
-            'paymentDataHelper',
-            $this->paymentDataHelper
-        );
-        $this->objectManager->setBackwardCompatibleProperty(
-            $configProvider,
-            'paymentTokenManagement',
-            $this->paymentTokenManagement
-        );
-        $this->objectManager->setBackwardCompatibleProperty(
-            $configProvider,
-            'orderRepository',
-            $this->orderRepository
-        );
-
-        static::assertEmpty($configProvider->getTokensComponents(self::VAULT_PAYMENT_CODE));
+        static::assertEmpty($this->configProvider->getTokensComponents(self::VAULT_PAYMENT_CODE));
     }
 
     /**
@@ -453,18 +417,66 @@ class TokensConfigProviderTest extends \PHPUnit_Framework_TestCase
         static::assertEmpty($configProvider->getTokensComponents(self::VAULT_PAYMENT_CODE));
     }
 
+    /**
+     * @covers \Magento\Vault\Model\Ui\Adminhtml\TokensConfigProvider::getTokensComponents
+     */
+    public function testGetTokensComponentsForGuestCustomerWithoutStoredTokens()
+    {
+        $this->session->expects(static::once())
+            ->method('getCustomerId')
+            ->willReturn(null);
+
+        $this->paymentDataHelper->expects(static::once())
+            ->method('getMethodInstance')
+            ->with(self::VAULT_PAYMENT_CODE)
+            ->willReturn($this->vaultPayment);
+
+        $this->vaultPayment->expects(static::once())
+            ->method('isActive')
+            ->with(self::STORE_ID)
+            ->willReturn(true);
+        $this->vaultPayment->expects(static::once())
+            ->method('getProviderCode')
+            ->willReturn(self::VAULT_PROVIDER_CODE);
+
+        $this->session->expects(static::once())
+            ->method('getReordered')
+            ->willReturn(self::ORDER_ID);
+        $this->orderRepository->expects(static::once())
+            ->method('get')
+            ->with(self::ORDER_ID)
+            ->willReturn($this->getOrderMock());
+
+        $this->paymentTokenManagement->expects(static::once())
+            ->method('getByPaymentId')
+            ->with(self::ORDER_PAYMENT_ENTITY_ID)
+            ->willReturn(null);
+
+        $this->filterBuilder->expects(static::once())
+            ->method('setField')
+            ->with(PaymentTokenInterface::ENTITY_ID)
+            ->willReturnSelf();
+        $this->filterBuilder->expects(static::never())
+            ->method('setValue');
+
+        $this->searchCriteriaBuilder->expects(static::never())
+            ->method('addFilters');
+
+        static::assertEmpty($this->configProvider->getTokensComponents(self::VAULT_PAYMENT_CODE));
+    }
+
     /**
      * Create mock object for store
      */
     private function initStoreMock()
     {
         $this->store = $this->getMock(StoreInterface::class);
-        $this->store->expects(static::once())
+        $this->store->expects(static::any())
             ->method('getId')
             ->willReturn(self::STORE_ID);
 
         $this->storeManager = $this->getMock(StoreManagerInterface::class);
-        $this->storeManager->expects(static::once())
+        $this->storeManager->expects(static::any())
             ->method('getStore')
             ->with(null)
             ->willReturn($this->store);
@@ -476,39 +488,37 @@ class TokensConfigProviderTest extends \PHPUnit_Framework_TestCase
      */
     private function getOrderMock()
     {
-        /** @var OrderInterface|MockObject $orderMock */
-        $orderMock = $this->getMockBuilder(OrderInterface::class)
+        /** @var OrderInterface|MockObject $order */
+        $order = $this->getMockBuilder(OrderInterface::class)
             ->getMockForAbstractClass();
-        /** @var OrderPaymentInterface|MockObject $orderPaymentMock */
-        $orderPaymentMock = $this->getMockBuilder(OrderPaymentInterface::class)
+        /** @var OrderPaymentInterface|MockObject $orderPayment */
+        $orderPayment = $this->getMockBuilder(OrderPaymentInterface::class)
             ->getMockForAbstractClass();
 
-        $orderMock->expects(static::once())
+        $order->expects(static::once())
             ->method('getPayment')
-            ->willReturn($orderPaymentMock);
-        $orderPaymentMock->expects(static::once())
+            ->willReturn($orderPayment);
+        $orderPayment->expects(static::once())
             ->method('getEntityId')
             ->willReturn(self::ORDER_PAYMENT_ENTITY_ID);
 
-        return $orderMock;
+        return $order;
     }
 
     /**
      * Get mock for token ui component provider
      * @param PaymentTokenInterface $token
-     * @return array
+     * @return TokenUiComponentInterface|MockObject
      */
     private function getTokenUiComponentProvider($token)
     {
         $tokenUiComponent = $this->getMock(TokenUiComponentInterface::class);
-
-        $tokenUiComponentProvider = $this->getMock(TokenUiComponentProviderInterface::class);
-        $tokenUiComponentProvider->expects(static::once())
+        $this->tokenComponentProvider->expects(static::once())
             ->method('getComponentForToken')
             ->with($token)
             ->willReturn($tokenUiComponent);
 
-        return [$tokenUiComponent, $tokenUiComponentProvider];
+        return $tokenUiComponent;
     }
 
     /**
diff --git a/app/code/Magento/Vault/composer.json b/app/code/Magento/Vault/composer.json
index 74dd568e3b45ee4e3e7f9e235d3389191b7a93e4..b2edf040674d83f6335d407089201b46fe16ecce 100644
--- a/app/code/Magento/Vault/composer.json
+++ b/app/code/Magento/Vault/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-vault",
     "description": "",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/framework": "100.2.*",
         "magento/module-sales": "100.2.*",
         "magento/module-store": "100.2.*",
diff --git a/app/code/Magento/Vault/view/frontend/layout/customer_account.xml b/app/code/Magento/Vault/view/frontend/layout/customer_account.xml
index 2042721d9d387ed0354f8163738a83e1f94d1710..01edaa1f093478d0eb0eb03f42bf98815851e16b 100644
--- a/app/code/Magento/Vault/view/frontend/layout/customer_account.xml
+++ b/app/code/Magento/Vault/view/frontend/layout/customer_account.xml
@@ -8,10 +8,11 @@
 <page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
     <body>
         <referenceBlock name="customer_account_navigation">
-            <block class="Magento\Framework\View\Element\Html\Link\Current" name="customer-account-navigation-my-credit-cards-link">
+            <block class="Magento\Customer\Block\Account\SortLinkInterface" name="customer-account-navigation-my-credit-cards-link">
                 <arguments>
                     <argument name="path" xsi:type="string">vault/cards/listaction</argument>
                     <argument name="label" xsi:type="string" translate="true">Stored Payment Methods</argument>
+                    <argument name="sortOrder" xsi:type="number">160</argument>
                 </arguments>
             </block>
         </referenceBlock>
diff --git a/app/code/Magento/Vault/view/frontend/web/js/view/payment/vault.js b/app/code/Magento/Vault/view/frontend/web/js/view/payment/vault.js
index 05d56e305f23eea9473c5c3da2d0a130ca2c42a5..3015755191d37d3159158a9505a5b3c9bf5c7bf8 100644
--- a/app/code/Magento/Vault/view/frontend/web/js/view/payment/vault.js
+++ b/app/code/Magento/Vault/view/frontend/web/js/view/payment/vault.js
@@ -4,25 +4,32 @@
  */
 /*browser:true*/
 /*global define*/
-define(
-    [
-        'underscore',
-        'uiComponent',
-        'Magento_Checkout/js/model/payment/renderer-list'
-    ],
-    function (
-        _,
-        Component,
-        rendererList
-    ) {
-        'use strict';
+define([
+    'underscore',
+    'uiComponent',
+    'Magento_Checkout/js/model/payment/renderer-list',
+    'uiLayout',
+    'uiRegistry'
+], function (_, Component, rendererList, layout, registry) {
+    'use strict';
 
+    var vaultGroupName = 'vaultGroup';
+
+    layout([{
+        name: vaultGroupName,
+        component: 'Magento_Checkout/js/model/payment/method-group',
+        alias: 'vault',
+        sortOrder: 10
+    }]);
+
+    registry.get(vaultGroupName, function (vaultGroup) {
         _.each(window.checkoutConfig.payment.vault, function (config, index) {
             rendererList.push(
                 {
                     type: index,
                     config: config.config,
                     component: config.component,
+                    group: vaultGroup,
 
                     /**
                      * Custom payment method types comparator
@@ -37,10 +44,10 @@ define(
                 }
             );
         });
+    });
 
-        /**
-         * Add view logic here if needed
-         */
-        return Component.extend({});
-    }
-);
+    /**
+     * Add view logic here if needed
+     */
+    return Component.extend({});
+});
diff --git a/app/code/Magento/Version/composer.json b/app/code/Magento/Version/composer.json
index 3a972432101154fa2c4f167473fc6f4d6aa113a0..4396f1fb2b3bf4e114dd2ab4dfbd37eb7c2ffd7e 100644
--- a/app/code/Magento/Version/composer.json
+++ b/app/code/Magento/Version/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-version",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/framework": "100.2.*"
     },
     "type": "magento2-module",
diff --git a/app/code/Magento/Webapi/composer.json b/app/code/Magento/Webapi/composer.json
index f2796df70a8fae522a34d0c94e079afd9f525f9c..6fc712722adddf10c16e4add70913a62c2ef2bc7 100644
--- a/app/code/Magento/Webapi/composer.json
+++ b/app/code/Magento/Webapi/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-webapi",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-store": "100.2.*",
         "magento/module-authorization": "100.2.*",
         "magento/module-integration": "100.2.*",
diff --git a/app/code/Magento/WebapiSecurity/composer.json b/app/code/Magento/WebapiSecurity/composer.json
index 506975f1aa188d4f0d90f8d2f0484153998f2c39..0f4ef7b3dc8839518bcc2982e9975c53d99a6c1b 100644
--- a/app/code/Magento/WebapiSecurity/composer.json
+++ b/app/code/Magento/WebapiSecurity/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-webapi-security",
     "description": "WebapiSecurity module provides option to loosen security on some webapi resources.",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-webapi": "100.2.*",
         "magento/framework": "100.2.*"
     },
diff --git a/app/code/Magento/Weee/composer.json b/app/code/Magento/Weee/composer.json
index 035d66e5a96b416f1f5e3140ef9e45e299c1b52a..70fd4a25d0310d94d4254a8079755eab01ad610f 100644
--- a/app/code/Magento/Weee/composer.json
+++ b/app/code/Magento/Weee/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-weee",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-store": "100.2.*",
         "magento/module-catalog": "101.1.*",
         "magento/module-tax": "100.2.*",
diff --git a/app/code/Magento/Widget/composer.json b/app/code/Magento/Widget/composer.json
index f59c4180eb2bb56522ae20f3615da92dd0c60370..b5a5e9e5569e3c62641cfc2d3cbc34030229020b 100644
--- a/app/code/Magento/Widget/composer.json
+++ b/app/code/Magento/Widget/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-widget",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-store": "100.2.*",
         "magento/module-cms": "101.1.*",
         "magento/module-backend": "100.2.*",
diff --git a/app/code/Magento/Wishlist/Block/Link.php b/app/code/Magento/Wishlist/Block/Link.php
index fea2ad5941c5893ceaff7dac1e69bf9c9d133db2..51e59998339d8b809182851b940f4e156c61c0e9 100644
--- a/app/code/Magento/Wishlist/Block/Link.php
+++ b/app/code/Magento/Wishlist/Block/Link.php
@@ -9,12 +9,14 @@
  */
 namespace Magento\Wishlist\Block;
 
+use Magento\Customer\Block\Account\SortLinkInterface;
+
 /**
  * Class Link
  *
  * @SuppressWarnings(PHPMD.DepthOfInheritance)
  */
-class Link extends \Magento\Framework\View\Element\Html\Link
+class Link extends \Magento\Framework\View\Element\Html\Link implements SortLinkInterface
 {
     /**
      * Template name
@@ -68,4 +70,12 @@ class Link extends \Magento\Framework\View\Element\Html\Link
     {
         return __('My Wish List');
     }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getSortOrder()
+    {
+        return $this->getData(self::SORT_ORDER);
+    }
 }
diff --git a/app/code/Magento/Wishlist/Controller/Index/Cart.php b/app/code/Magento/Wishlist/Controller/Index/Cart.php
index f15e89d16c9b4f9bba2adbe2a23621417e255f1a..a907abcd1c56c829dedaddbd065fff3cc1fede08 100644
--- a/app/code/Magento/Wishlist/Controller/Index/Cart.php
+++ b/app/code/Magento/Wishlist/Controller/Index/Cart.php
@@ -113,6 +113,7 @@ class Cart extends \Magento\Wishlist\Controller\AbstractIndex
      * @return \Magento\Framework\Controller\ResultInterface
      * @SuppressWarnings(PHPMD.CyclomaticComplexity)
      * @SuppressWarnings(PHPMD.NPathComplexity)
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
      */
     public function execute()
     {
@@ -137,6 +138,10 @@ class Cart extends \Magento\Wishlist\Controller\AbstractIndex
 
         // Set qty
         $qty = $this->getRequest()->getParam('qty');
+        $postQty = $this->getRequest()->getPostValue('qty');
+        if ($postQty !== null && $qty !== $postQty) {
+            $qty = $postQty;
+        }
         if (is_array($qty)) {
             if (isset($qty[$itemId])) {
                 $qty = $qty[$itemId];
diff --git a/app/code/Magento/Wishlist/Pricing/ConfiguredPrice/ConfigurableProduct.php b/app/code/Magento/Wishlist/Pricing/ConfiguredPrice/ConfigurableProduct.php
index 6d8e4bcd2fd1c41844cd4398043b61dec4ff36ff..be995258794cc05f1fca4a2124cac04e8c0e1c87 100644
--- a/app/code/Magento/Wishlist/Pricing/ConfiguredPrice/ConfigurableProduct.php
+++ b/app/code/Magento/Wishlist/Pricing/ConfiguredPrice/ConfigurableProduct.php
@@ -21,15 +21,12 @@ class ConfigurableProduct extends FinalPrice implements ConfiguredPriceInterface
      */
     public function getValue()
     {
-        $result = 0.;
         /** @var \Magento\Wishlist\Model\Item\Option $customOption */
         $customOption = $this->getProduct()->getCustomOption('simple_product');
-        if ($customOption) {
-            /** @var \Magento\Framework\Pricing\PriceInfoInterface $priceInfo */
-            $priceInfo = $customOption->getProduct()->getPriceInfo();
-            $result = $priceInfo->getPrice(self::PRICE_CODE)->getValue();
-        }
-        return max(0, $result);
+        $product = $customOption ? $customOption->getProduct() : $this->getProduct();
+        $price = $product->getPriceInfo()->getPrice(self::PRICE_CODE)->getValue();
+
+        return max(0, $price);
     }
 
     /**
diff --git a/app/code/Magento/Wishlist/Test/Unit/Controller/Index/CartTest.php b/app/code/Magento/Wishlist/Test/Unit/Controller/Index/CartTest.php
index e1a7cd448569f05060d9995ee5d02de41630f680..743fc39e4b43d7819af97fc97c84efb9f3f38013 100644
--- a/app/code/Magento/Wishlist/Test/Unit/Controller/Index/CartTest.php
+++ b/app/code/Magento/Wishlist/Test/Unit/Controller/Index/CartTest.php
@@ -159,7 +159,7 @@ class CartTest extends \PHPUnit_Framework_TestCase
 
         $this->requestMock = $this->getMockBuilder(\Magento\Framework\App\RequestInterface::class)
             ->disableOriginalConstructor()
-            ->setMethods(['getParams', 'getParam', 'isAjax'])
+            ->setMethods(['getParams', 'getParam', 'isAjax', 'getPostValue'])
             ->getMockForAbstractClass();
 
         $this->redirectMock = $this->getMockBuilder(\Magento\Framework\App\Response\RedirectInterface::class)
@@ -916,4 +916,176 @@ class CartTest extends \PHPUnit_Framework_TestCase
 
         $this->assertSame($this->resultRedirectMock, $this->model->execute());
     }
+
+    /**
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+     */
+    public function testExecuteWithEditQuantity()
+    {
+        $itemId = 2;
+        $wishlistId = 1;
+        $qty = 1;
+        $postQty = 2;
+        $productId = 4;
+        $indexUrl = 'index_url';
+        $configureUrl = 'configure_url';
+        $options = [5 => 'option'];
+        $params = ['item' => $itemId, 'qty' => $qty];
+
+        $this->formKeyValidator->expects($this->once())
+            ->method('validate')
+            ->with($this->requestMock)
+            ->willReturn(true);
+
+        $itemMock = $this->getMockBuilder(\Magento\Wishlist\Model\Item::class)
+            ->disableOriginalConstructor()
+            ->setMethods(
+                [
+                    'load',
+                    'getId',
+                    'getWishlistId',
+                    'setQty',
+                    'setOptions',
+                    'getBuyRequest',
+                    'mergeBuyRequest',
+                    'addToCart',
+                    'getProduct',
+                    'getProductId',
+                ]
+            )
+            ->getMock();
+
+        $this->requestMock->expects($this->at(0))
+            ->method('getParam')
+            ->with('item', null)
+            ->willReturn($itemId);
+        $this->itemFactoryMock->expects($this->once())
+            ->method('create')
+            ->willReturn($itemMock);
+
+        $itemMock->expects($this->once())
+            ->method('load')
+            ->with($itemId, null)
+            ->willReturnSelf();
+        $itemMock->expects($this->exactly(2))
+            ->method('getId')
+            ->willReturn($itemId);
+        $itemMock->expects($this->once())
+            ->method('getWishlistId')
+            ->willReturn($wishlistId);
+
+        $wishlistMock = $this->getMockBuilder(\Magento\Wishlist\Model\Wishlist::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->wishlistProviderMock->expects($this->once())
+            ->method('getWishlist')
+            ->with($wishlistId)
+            ->willReturn($wishlistMock);
+
+        $this->requestMock->expects($this->at(1))
+            ->method('getParam')
+            ->with('qty', null)
+            ->willReturn($qty);
+
+        $this->requestMock->expects($this->once())
+            ->method('getPostValue')
+            ->with('qty')
+            ->willReturn($postQty);
+
+        $this->quantityProcessorMock->expects($this->once())
+            ->method('process')
+            ->with($postQty)
+            ->willReturnArgument(0);
+
+        $itemMock->expects($this->once())
+            ->method('setQty')
+            ->with($postQty)
+            ->willReturnSelf();
+
+        $this->urlMock->expects($this->at(0))
+            ->method('getUrl')
+            ->with('*/*', null)
+            ->willReturn($indexUrl);
+
+        $itemMock->expects($this->once())
+            ->method('getProductId')
+            ->willReturn($productId);
+
+        $this->urlMock->expects($this->at(1))
+            ->method('getUrl')
+            ->with('*/*/configure/', ['id' => $itemId, 'product_id' => $productId])
+            ->willReturn($configureUrl);
+
+        $optionMock = $this->getMockBuilder(\Magento\Wishlist\Model\Item\Option::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->optionFactoryMock->expects($this->once())
+            ->method('create')
+            ->willReturn($optionMock);
+
+        $optionsMock = $this->getMockBuilder(\Magento\Wishlist\Model\ResourceModel\Item\Option\Collection::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $optionMock->expects($this->once())
+            ->method('getCollection')
+            ->willReturn($optionsMock);
+
+        $optionsMock->expects($this->once())
+            ->method('addItemFilter')
+            ->with([$itemId])
+            ->willReturnSelf();
+        $optionsMock->expects($this->once())
+            ->method('getOptionsByItem')
+            ->with($itemId)
+            ->willReturn($options);
+
+        $itemMock->expects($this->once())
+            ->method('setOptions')
+            ->with($options)
+            ->willReturnSelf();
+
+        $this->requestMock->expects($this->once())
+            ->method('getParams')
+            ->willReturn($params);
+
+        $buyRequestMock = $this->getMockBuilder(\Magento\Framework\DataObject::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $itemMock->expects($this->once())
+            ->method('getBuyRequest')
+            ->willReturn($buyRequestMock);
+
+        $this->productHelperMock->expects($this->once())
+            ->method('addParamsToBuyRequest')
+            ->with($params, ['current_config' => $buyRequestMock])
+            ->willReturn($buyRequestMock);
+
+        $itemMock->expects($this->once())
+            ->method('mergeBuyRequest')
+            ->with($buyRequestMock)
+            ->willReturnSelf();
+        $itemMock->expects($this->once())
+            ->method('addToCart')
+            ->with($this->checkoutCartMock, true)
+            ->willThrowException(new \Magento\Framework\Exception\LocalizedException(__('message')));
+
+        $this->messageManagerMock->expects($this->once())
+            ->method('addNotice')
+            ->with('message', null)
+            ->willReturnSelf();
+
+        $this->helperMock->expects($this->once())
+            ->method('calculate')
+            ->willReturnSelf();
+
+        $this->resultRedirectMock->expects($this->once())
+            ->method('setUrl')
+            ->with($configureUrl)
+            ->willReturnSelf();
+
+        $this->assertSame($this->resultRedirectMock, $this->model->execute());
+    }
 }
diff --git a/app/code/Magento/Wishlist/Test/Unit/Pricing/ConfiguredPrice/ConfigurableProductTest.php b/app/code/Magento/Wishlist/Test/Unit/Pricing/ConfiguredPrice/ConfigurableProductTest.php
index 9e05a578080efbd7ec91f49babfbbafc447e330d..ee4841ef79f2e6e31545f12e44fe49073166a8e3 100644
--- a/app/code/Magento/Wishlist/Test/Unit/Pricing/ConfiguredPrice/ConfigurableProductTest.php
+++ b/app/code/Magento/Wishlist/Test/Unit/Pricing/ConfiguredPrice/ConfigurableProductTest.php
@@ -5,36 +5,30 @@
  */
 namespace Magento\Wishlist\Test\Unit\Pricing\ConfiguredPrice;
 
-use Magento\Framework\Pricing\Adjustment\CalculatorInterface;
-use Magento\Framework\Pricing\PriceCurrencyInterface;
-use Magento\Framework\Pricing\PriceInfoInterface;
-use Magento\Framework\Pricing\SaleableInterface;
-use Magento\Wishlist\Pricing\ConfiguredPrice\ConfigurableProduct;
-
 class ConfigurableProductTest extends \PHPUnit_Framework_TestCase
 {
     /**
-     * @var SaleableInterface|\PHPUnit_Framework_MockObject_MockObject
+     * @var \Magento\Framework\Pricing\SaleableInterface|\PHPUnit_Framework_MockObject_MockObject
      */
     private $saleableItem;
 
     /**
-     * @var CalculatorInterface|\PHPUnit_Framework_MockObject_MockObject
+     * @var \Magento\Framework\Pricing\Adjustment\CalculatorInterface|\PHPUnit_Framework_MockObject_MockObject
      */
     private $calculator;
 
     /**
-     * @var PriceCurrencyInterface|\PHPUnit_Framework_MockObject_MockObject
+     * @var \Magento\Framework\Pricing\PriceCurrencyInterface|\PHPUnit_Framework_MockObject_MockObject
      */
     private $priceCurrency;
 
     /**
-     * @var ConfigurableProduct
+     * @var \Magento\Wishlist\Pricing\ConfiguredPrice\ConfigurableProduct
      */
     private $model;
 
     /**
-     * @var PriceInfoInterface|\PHPUnit_Framework_MockObject_MockObject
+     * @var \Magento\Framework\Pricing\PriceInfoInterface|\PHPUnit_Framework_MockObject_MockObject
      */
     private $priceInfoMock;
 
@@ -49,9 +43,6 @@ class ConfigurableProductTest extends \PHPUnit_Framework_TestCase
                 'getCustomOption',
             ])
             ->getMockForAbstractClass();
-        $this->saleableItem->expects($this->once())
-            ->method('getPriceInfo')
-            ->willReturn($this->priceInfoMock);
 
         $this->calculator = $this->getMockBuilder(\Magento\Framework\Pricing\Adjustment\CalculatorInterface::class)
             ->getMockForAbstractClass();
@@ -59,7 +50,7 @@ class ConfigurableProductTest extends \PHPUnit_Framework_TestCase
         $this->priceCurrency = $this->getMockBuilder(\Magento\Framework\Pricing\PriceCurrencyInterface::class)
             ->getMockForAbstractClass();
 
-        $this->model = new ConfigurableProduct(
+        $this->model = new \Magento\Wishlist\Pricing\ConfiguredPrice\ConfigurableProduct(
             $this->saleableItem,
             null,
             $this->calculator,
@@ -82,7 +73,7 @@ class ConfigurableProductTest extends \PHPUnit_Framework_TestCase
             ->getMock();
         $this->priceInfoMock->expects($this->once())
             ->method('getPrice')
-            ->with(ConfigurableProduct::PRICE_CODE)
+            ->with(\Magento\Wishlist\Pricing\ConfiguredPrice\ConfigurableProduct::PRICE_CODE)
             ->willReturn($priceMock);
 
         $productMock = $this->getMockBuilder(\Magento\Catalog\Model\Product::class)
@@ -109,11 +100,28 @@ class ConfigurableProductTest extends \PHPUnit_Framework_TestCase
 
     public function testGetValueWithNoCustomOption()
     {
+        $priceValue = 100;
+
+        $priceMock = $this->getMockBuilder(\Magento\Framework\Pricing\Price\PriceInterface::class)
+            ->getMockForAbstractClass();
+        $priceMock->expects($this->once())
+            ->method('getValue')
+            ->willReturn($priceValue);
+
         $this->saleableItem->expects($this->once())
             ->method('getCustomOption')
             ->with('simple_product')
             ->willReturn(null);
 
-        $this->assertEquals(0, $this->model->getValue());
+        $this->saleableItem->expects($this->once())
+            ->method('getPriceInfo')
+            ->willReturn($this->priceInfoMock);
+
+        $this->priceInfoMock->expects($this->once())
+            ->method('getPrice')
+            ->with(\Magento\Wishlist\Pricing\ConfiguredPrice\ConfigurableProduct::PRICE_CODE)
+            ->willReturn($priceMock);
+
+        $this->assertEquals(100, $this->model->getValue());
     }
 }
diff --git a/app/code/Magento/Wishlist/composer.json b/app/code/Magento/Wishlist/composer.json
index 3faee8912493c96092f70d7fc3ca0e77164b39bc..b341edde760b0761872aecc488216faa37392c22 100644
--- a/app/code/Magento/Wishlist/composer.json
+++ b/app/code/Magento/Wishlist/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/module-wishlist",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/module-store": "100.2.*",
         "magento/module-customer": "100.2.*",
         "magento/module-catalog": "101.1.*",
diff --git a/app/code/Magento/Wishlist/view/frontend/layout/catalog_product_view.xml b/app/code/Magento/Wishlist/view/frontend/layout/catalog_product_view.xml
index 4c01d341bb68294cae5d48f5ab2dd99d8d5b08d8..a25546b1afc902a563c296a7adc24b1a9787729b 100644
--- a/app/code/Magento/Wishlist/view/frontend/layout/catalog_product_view.xml
+++ b/app/code/Magento/Wishlist/view/frontend/layout/catalog_product_view.xml
@@ -16,7 +16,7 @@
                 </arguments>
             </block>
             <referenceBlock name="product.info.addto">
-                <block class="Magento\Wishlist\Block\Catalog\Product\View\AddTo\Wishlist" name="view.addto.wishlist" after="view.addto.requisition"
+                <block class="Magento\Wishlist\Block\Catalog\Product\View\AddTo\Wishlist" name="view.addto.wishlist"
                        template="Magento_Wishlist::catalog/product/view/addto/wishlist.phtml" />
             </referenceBlock>
         </referenceContainer>
diff --git a/app/code/Magento/Wishlist/view/frontend/layout/customer_account.xml b/app/code/Magento/Wishlist/view/frontend/layout/customer_account.xml
index c1dc653efbe7e2f8877a926073f55744a744a624..9083fcdc8d13280dbb16fb917bc24a2bc577ad2d 100644
--- a/app/code/Magento/Wishlist/view/frontend/layout/customer_account.xml
+++ b/app/code/Magento/Wishlist/view/frontend/layout/customer_account.xml
@@ -8,10 +8,11 @@
 <page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
     <body>
         <referenceBlock name="customer_account_navigation">
-            <block class="Magento\Framework\View\Element\Html\Link\Current" ifconfig="wishlist/general/active" name="customer-account-navigation-wish-list-link">
+            <block class="Magento\Customer\Block\Account\SortLinkInterface" ifconfig="wishlist/general/active" name="customer-account-navigation-wish-list-link">
                 <arguments>
                     <argument name="path" xsi:type="string">wishlist</argument>
                     <argument name="label" xsi:type="string">My Wish List</argument>
+                    <argument name="sortOrder" xsi:type="number">210</argument>
                 </arguments>
             </block>
         </referenceBlock>
diff --git a/app/code/Magento/Wishlist/view/frontend/layout/default.xml b/app/code/Magento/Wishlist/view/frontend/layout/default.xml
index a0fc577547c5ac8ea91bc0b9699edcc6a2d499b3..dffa4ec79d64d3183e732aa043ccefc39fa1062f 100644
--- a/app/code/Magento/Wishlist/view/frontend/layout/default.xml
+++ b/app/code/Magento/Wishlist/view/frontend/layout/default.xml
@@ -11,7 +11,11 @@
             <block class="Magento\Framework\View\Element\Js\Components" name="wishlist_page_head_components" template="Magento_Wishlist::js/components.phtml"/>
         </referenceBlock>
         <referenceBlock name="top.links">
-            <block class="Magento\Wishlist\Block\Link" name="wish-list-link" after="my-account-link"/>
+            <block class="Magento\Wishlist\Block\Link" name="wish-list-link" after="my-account-link">
+                <arguments>
+                    <argument name="sortOrder" xsi:type="number">60</argument>
+                </arguments>
+            </block>
         </referenceBlock>
         <referenceContainer name="sidebar.additional">
             <block class="Magento\Wishlist\Block\Customer\Sidebar" name="wishlist_sidebar" as="wishlist" template="Magento_Wishlist::sidebar.phtml"/>
diff --git a/app/code/Magento/Wishlist/view/frontend/layout/wishlist_index_configure.xml b/app/code/Magento/Wishlist/view/frontend/layout/wishlist_index_configure.xml
index 50ba68940fc9d4027b359fe72ec86b305fb0f69a..02b737b7d5127320207669379ea7e3b09ddb5ac1 100644
--- a/app/code/Magento/Wishlist/view/frontend/layout/wishlist_index_configure.xml
+++ b/app/code/Magento/Wishlist/view/frontend/layout/wishlist_index_configure.xml
@@ -9,7 +9,7 @@
     <update handle="catalog_product_view"/>
     <body>
         <referenceBlock name="product.info.addto">
-            <block class="Magento\Wishlist\Block\Item\Configure" name="view.addto.wishlist" after="view.addto.requisition"
+            <block class="Magento\Wishlist\Block\Item\Configure" name="view.addto.wishlist"
                 template="item/configure/addto/wishlist.phtml" />
         </referenceBlock>
     </body>
diff --git a/app/code/Magento/Wishlist/view/frontend/layout/wishlist_index_configure_type_bundle.xml b/app/code/Magento/Wishlist/view/frontend/layout/wishlist_index_configure_type_bundle.xml
index dbb680f8f25806508e44ef31724899149ca2b6ce..84d0429a29c99ba204ec9d4401b69d2bf68e1abf 100644
--- a/app/code/Magento/Wishlist/view/frontend/layout/wishlist_index_configure_type_bundle.xml
+++ b/app/code/Magento/Wishlist/view/frontend/layout/wishlist_index_configure_type_bundle.xml
@@ -20,9 +20,9 @@
                 <block class="Magento\Catalog\Block\Product\View" name="product.info.addtocart.bundle" as="addtocart" template="product/view/addtocart.phtml" />
                 <block class="Magento\Catalog\Block\Product\View" name="product.info.addto.bundle" as="addto" after="product.info.addtocart.bundle"
                        template="Magento_Catalog::product/view/addto.phtml" cacheable="false">
-                    <block class="Magento\Wishlist\Block\Item\Configure" name="view.addto.wishlist.bundle" after="view.addto.requisition"
+                    <block class="Magento\Wishlist\Block\Item\Configure" name="view.addto.wishlist.bundle"
                            template="item/configure/addto/wishlist.phtml" />
-                    <block class="Magento\Catalog\Block\Product\View\Addto\Compare" name="view.addto.compare.bundle" after="view.addto.wishlist"
+                    <block class="Magento\Catalog\Block\Product\View\AddTo\Compare" name="view.addto.compare.bundle" after="view.addto.wishlist"
                            template="Magento_Catalog::product/view/addto/compare.phtml" />
                 </block>
             </block>
diff --git a/app/design/adminhtml/Magento/backend/composer.json b/app/design/adminhtml/Magento/backend/composer.json
index 29569db622d2ccc9fad9e9b87b3ad4f7ae4757d2..ff0eda055bba6a9e9899d66839216c14bbdbe02e 100644
--- a/app/design/adminhtml/Magento/backend/composer.json
+++ b/app/design/adminhtml/Magento/backend/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/theme-adminhtml-backend",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/framework": "100.2.*"
     },
     "type": "magento2-theme",
diff --git a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_payments.less b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_payments.less
index 7731595870f061c990acc5cc36d68980e8ba590f..453a9ce958f4d3f2716c015c99ff72a525b3838f 100644
--- a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_payments.less
+++ b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_payments.less
@@ -24,6 +24,7 @@
 & when (@media-common = true) {
     .checkout-payment-method {
         .step-title {
+            border-bottom: 0;
             margin-bottom: 0;
         }
 
@@ -39,6 +40,12 @@
                     display: block;
                 }
             }
+
+            & + .payment-method {
+                .payment-method-title {
+                    .lib-css(border-top, @checkout-payment-method-title__border);
+                }
+            }
         }
 
         .payment-method-content {
@@ -54,7 +61,6 @@
         }
 
         .payment-method-title {
-            .lib-css(border-top, @checkout-payment-method-title__border);
             .lib-css(padding, @checkout-payment-method-title__padding 0);
             margin: 0;
 
@@ -80,6 +86,14 @@
             }
         }
 
+        .payment-group {
+            & + .payment-group {
+                .step-title {
+                    margin: @indent__base 0 0;
+                }
+            }
+        }
+
         .field-select-billing,
         .billing-address-form {
             .lib-css(max-width, @checkout-billing-address-form__max-width);
diff --git a/app/design/frontend/Magento/blank/Magento_Customer/web/css/source/_module.less b/app/design/frontend/Magento/blank/Magento_Customer/web/css/source/_module.less
index 369e100506c4d76dd10347a6ee5ee772d605091f..2d54baf8f8e9f74bd3d764133bcc5a58e30ea2e0 100644
--- a/app/design/frontend/Magento/blank/Magento_Customer/web/css/source/_module.less
+++ b/app/design/frontend/Magento/blank/Magento_Customer/web/css/source/_module.less
@@ -15,6 +15,8 @@
 @account-nav-current-color: false;
 @account-nav-current-font-weight: @font-weight__semibold;
 
+@account-nav-delimiter__border-color: @color-gray82;
+
 @account-nav-item-hover: @color-gray91;
 
 @_password-default: @color-gray-light01;
@@ -219,6 +221,12 @@
                     .lib-css(border-color, @account-nav-current-border-color);
                 }
             }
+
+            .delimiter {
+                border-top: 1px solid @account-nav-delimiter__border-color;
+                display: block;
+                margin: @indent__s 1.8rem;
+            }
         }
     }
 
diff --git a/app/design/frontend/Magento/blank/composer.json b/app/design/frontend/Magento/blank/composer.json
index 27ed40860dd5b065dc51e82f487722eb519ba215..7c03167ebc23278eaab5a72cddd381de7cd5afcc 100644
--- a/app/design/frontend/Magento/blank/composer.json
+++ b/app/design/frontend/Magento/blank/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/theme-frontend-blank",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/framework": "100.2.*"
     },
     "type": "magento2-theme",
diff --git a/app/design/frontend/Magento/blank/etc/view.xml b/app/design/frontend/Magento/blank/etc/view.xml
index 3a92ad0a6741040e0adb3fc25e00948520cfa565..6c53a8613f09ca1f91c9e024b8e2cec723f0b309 100644
--- a/app/design/frontend/Magento/blank/etc/view.xml
+++ b/app/design/frontend/Magento/blank/etc/view.xml
@@ -227,7 +227,7 @@
                 </var>
                 <var name="options">
                     <var name="options">
-                        <var name="navigation">dots</var>
+                        <var name="nav">dots</var>
                     </var>
                 </var>
             </var>
diff --git a/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_payments.less b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_payments.less
index 85b2e96e6ea4add2316a572f0ce4ad16bfe073d2..a8c84ef51a92af04d403be3eb522610693a9a823 100644
--- a/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_payments.less
+++ b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_payments.less
@@ -24,6 +24,7 @@
 & when (@media-common = true) {
     .checkout-payment-method {
         .step-title {
+            border-bottom: 0;
             margin-bottom: 0;
         }
 
@@ -39,6 +40,12 @@
                     display: block;
                 }
             }
+
+            & + .payment-method {
+                .payment-method-title {
+                    .lib-css(border-top, @checkout-payment-method-title__border);
+                }
+            }
         }
 
         .payment-method-content {
@@ -54,7 +61,6 @@
         }
 
         .payment-method-title {
-            .lib-css(border-top, @checkout-payment-method-title__border);
             .lib-css(padding, @checkout-payment-method-title__padding 0);
             margin: 0;
 
@@ -80,6 +86,14 @@
             }
         }
 
+        .payment-group {
+            & + .payment-group {
+                .step-title {
+                    margin: @indent__base 0 0;
+                }
+            }
+        }
+
         .field-select-billing,
         .billing-address-form {
             .lib-css(max-width, @checkout-billing-address-form__max-width);
diff --git a/app/design/frontend/Magento/luma/Magento_Customer/layout/customer_account.xml b/app/design/frontend/Magento/luma/Magento_Customer/layout/customer_account.xml
index 5d02aec14bedc148d2cade4f47b87e496da23b9f..be8aa1200f21b0a861c088666f62828e052a1f7c 100644
--- a/app/design/frontend/Magento/luma/Magento_Customer/layout/customer_account.xml
+++ b/app/design/frontend/Magento/luma/Magento_Customer/layout/customer_account.xml
@@ -13,26 +13,41 @@
                     <argument name="block_title" translate="true" xsi:type="string">Account Dashboard</argument>
                     <argument name="block_css" xsi:type="string">block-collapsible-nav</argument>
                 </arguments>
-                <block class="Magento\Framework\View\Element\Html\Links" name="customer_account_navigation" before="-">
+                <block class="Magento\Customer\Block\Account\Navigation" name="customer_account_navigation" before="-">
                     <arguments>
                         <argument name="css_class" xsi:type="string">nav items</argument>
                     </arguments>
-                    <block class="Magento\Framework\View\Element\Html\Link\Current" name="customer-account-navigation-account-link">
+                    <block class="Magento\Customer\Block\Account\SortLinkInterface" name="customer-account-navigation-account-link">
                         <arguments>
                             <argument name="label" xsi:type="string" translate="true">Account Dashboard</argument>
                             <argument name="path" xsi:type="string">customer/account</argument>
+                            <argument name="sortOrder" xsi:type="number">250</argument>
                         </arguments>
                     </block>
-                    <block class="Magento\Framework\View\Element\Html\Link\Current" name="customer-account-navigation-account-edit-link">
+                    <block class="Magento\Customer\Block\Account\Delimiter" name="customer-account-navigation-delimiter-1"
+                           template="Magento_Customer::account/navigation-delimiter.phtml">
                         <arguments>
-                            <argument name="label" xsi:type="string" translate="true">Account Information</argument>
-                            <argument name="path" xsi:type="string">customer/account/edit</argument>
+                            <argument name="sortOrder" xsi:type="number">200</argument>
                         </arguments>
                     </block>
-                    <block class="Magento\Framework\View\Element\Html\Link\Current" name="customer-account-navigation-address-link">
+                    <block class="Magento\Customer\Block\Account\SortLinkInterface" name="customer-account-navigation-address-link">
                         <arguments>
                             <argument name="label" xsi:type="string" translate="true">Address Book</argument>
                             <argument name="path" xsi:type="string">customer/address</argument>
+                            <argument name="sortOrder" xsi:type="number">190</argument>
+                        </arguments>
+                    </block>
+                    <block class="Magento\Customer\Block\Account\SortLinkInterface" name="customer-account-navigation-account-edit-link">
+                        <arguments>
+                            <argument name="label" xsi:type="string" translate="true">Account Information</argument>
+                            <argument name="path" xsi:type="string">customer/account/edit</argument>
+                            <argument name="sortOrder" xsi:type="number">180</argument>
+                        </arguments>
+                    </block>
+                    <block class="Magento\Customer\Block\Account\Delimiter" name="customer-account-navigation-delimiter-2"
+                           template="Magento_Customer::account/navigation-delimiter.phtml">
+                        <arguments>
+                            <argument name="sortOrder" xsi:type="number">130</argument>
                         </arguments>
                     </block>
                 </block>
diff --git a/app/design/frontend/Magento/luma/Magento_Customer/layout/default.xml b/app/design/frontend/Magento/luma/Magento_Customer/layout/default.xml
index bd1fd91d6d338bd743ae49db05440c38f22e94a9..2592f9def7fa42f0d8e69cf0458d568651843f26 100644
--- a/app/design/frontend/Magento/luma/Magento_Customer/layout/default.xml
+++ b/app/design/frontend/Magento/luma/Magento_Customer/layout/default.xml
@@ -9,7 +9,11 @@
     <body>
         <referenceBlock name="header.links">
             <block class="Magento\Customer\Block\Account\Customer" name="customer" template="account/customer.phtml" before="-"/>
-            <block class="Magento\Customer\Block\Account\AuthorizationLink" name="authorization-link-login" template="account/link/authorization.phtml"/>
+            <block class="Magento\Customer\Block\Account\AuthorizationLink" name="authorization-link-login" template="account/link/authorization.phtml">
+                <arguments>
+                    <argument name="sortOrder" xsi:type="number">10</argument>
+                </arguments>
+            </block>
         </referenceBlock>
         <block class="Magento\Theme\Block\Html\Header" name="header" as="header">
             <arguments>
diff --git a/app/design/frontend/Magento/luma/Magento_Theme/web/css/source/module/_collapsible_navigation.less b/app/design/frontend/Magento/luma/Magento_Theme/web/css/source/module/_collapsible_navigation.less
index 95c7ec15ebb33a90e81b03ab553c636f39033fb1..33c0dacb8d99d8e3bb031114a43fd10dc3e767b1 100644
--- a/app/design/frontend/Magento/luma/Magento_Theme/web/css/source/module/_collapsible_navigation.less
+++ b/app/design/frontend/Magento/luma/Magento_Theme/web/css/source/module/_collapsible_navigation.less
@@ -13,6 +13,7 @@
 @collapsible-nav-current-border-color: @color-orange-red1;
 @collapsible-nav-current-color: @color-black;
 @collapsible-nav-current-font-weight: @font-weight__semibold;
+@collapsible-nav-delimiter__border-color: @color-gray82;
 @collapsible-nav-item-hover: @color-gray91;
 
 //
@@ -64,6 +65,12 @@
                     .lib-css(border-color, @collapsible-nav-current-border-color);
                 }
             }
+
+            .delimiter {
+                border-top: 1px solid @collapsible-nav-delimiter__border-color;
+                display: block;
+                margin: @indent__s 1.8rem;
+            }
         }
     }
 }
diff --git a/app/design/frontend/Magento/luma/composer.json b/app/design/frontend/Magento/luma/composer.json
index 98fe0ebf8061c23fa37d30a9551f05d5c41bce1b..97eb48f3c7e9efe028eae034757a6a17c4d98bd0 100644
--- a/app/design/frontend/Magento/luma/composer.json
+++ b/app/design/frontend/Magento/luma/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/theme-frontend-luma",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/theme-frontend-blank": "100.2.*",
         "magento/framework": "100.2.*"
     },
diff --git a/composer.json b/composer.json
index fed4465140724cef3c24cd7facdd2ec5ceeba5b6..f9e49415d6ad3aff6976144df442861909155d2d 100644
--- a/composer.json
+++ b/composer.json
@@ -8,7 +8,7 @@
         "AFL-3.0"
     ],
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "zendframework/zend-stdlib": "~2.4.6",
         "zendframework/zend-code": "~2.4.6",
         "zendframework/zend-server": "~2.4.6",
diff --git a/composer.lock b/composer.lock
index 7feb568d766d012e009c59a50226f3ea8bd7b74a..02f0e31a325638840641667cac1c6783cf381e87 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,8 +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": "c23e80be1cc71ab108ce5ac19b3fe509",
-    "content-hash": "5b9734c1bdbda68cf20507525cafa0f2",
+    "hash": "1f34dce6d48c9e4e694c27e001414000",
+    "content-hash": "600aca1692cf3fe5c2ea1cbf66de09ab",
     "packages": [
         {
             "name": "braintree/braintree_php",
@@ -56,7 +56,7 @@
         },
         {
             "name": "colinmollenhour/cache-backend-file",
-            "version": "1.4",
+            "version": "1.4.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/colinmollenhour/Cm_Cache_Backend_File.git",
@@ -818,16 +818,16 @@
         },
         {
             "name": "paragonie/random_compat",
-            "version": "v2.0.2",
+            "version": "v2.0.3",
             "source": {
                 "type": "git",
                 "url": "https://github.com/paragonie/random_compat.git",
-                "reference": "088c04e2f261c33bed6ca5245491cfca69195ccf"
+                "reference": "c0125896dbb151380ab47e96c621741e79623beb"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/paragonie/random_compat/zipball/088c04e2f261c33bed6ca5245491cfca69195ccf",
-                "reference": "088c04e2f261c33bed6ca5245491cfca69195ccf",
+                "url": "https://api.github.com/repos/paragonie/random_compat/zipball/c0125896dbb151380ab47e96c621741e79623beb",
+                "reference": "c0125896dbb151380ab47e96c621741e79623beb",
                 "shasum": ""
             },
             "require": {
@@ -862,7 +862,7 @@
                 "pseudorandom",
                 "random"
             ],
-            "time": "2016-04-03 06:00:07"
+            "time": "2016-10-17 15:23:22"
         },
         {
             "name": "pelago/emogrifier",
@@ -922,16 +922,16 @@
         },
         {
             "name": "phpseclib/phpseclib",
-            "version": "2.0.3",
+            "version": "2.0.4",
             "source": {
                 "type": "git",
                 "url": "https://github.com/phpseclib/phpseclib.git",
-                "reference": "41f85e9c2582b3f6d1b7d20395fb40c687ad5370"
+                "reference": "ab8028c93c03cc8d9c824efa75dc94f1db2369bf"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/41f85e9c2582b3f6d1b7d20395fb40c687ad5370",
-                "reference": "41f85e9c2582b3f6d1b7d20395fb40c687ad5370",
+                "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/ab8028c93c03cc8d9c824efa75dc94f1db2369bf",
+                "reference": "ab8028c93c03cc8d9c824efa75dc94f1db2369bf",
                 "shasum": ""
             },
             "require": {
@@ -1010,20 +1010,20 @@
                 "x.509",
                 "x509"
             ],
-            "time": "2016-08-18 18:49:14"
+            "time": "2016-10-04 00:57:04"
         },
         {
             "name": "psr/log",
-            "version": "1.0.1",
+            "version": "1.0.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/php-fig/log.git",
-                "reference": "5277094ed527a1c4477177d102fe4c53551953e0"
+                "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/php-fig/log/zipball/5277094ed527a1c4477177d102fe4c53551953e0",
-                "reference": "5277094ed527a1c4477177d102fe4c53551953e0",
+                "url": "https://api.github.com/repos/php-fig/log/zipball/4ebe3a8bf773a19edfe0a84b6585ba3d401b724d",
+                "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d",
                 "shasum": ""
             },
             "require": {
@@ -1057,7 +1057,7 @@
                 "psr",
                 "psr-3"
             ],
-            "time": "2016-09-19 16:02:08"
+            "time": "2016-10-10 12:19:37"
         },
         {
             "name": "ramsey/uuid",
@@ -1390,7 +1390,7 @@
         },
         {
             "name": "symfony/event-dispatcher",
-            "version": "v2.8.11",
+            "version": "v2.8.12",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/event-dispatcher.git",
@@ -1450,7 +1450,7 @@
         },
         {
             "name": "symfony/filesystem",
-            "version": "v2.8.11",
+            "version": "v2.8.12",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/filesystem.git",
@@ -1499,16 +1499,16 @@
         },
         {
             "name": "symfony/finder",
-            "version": "v3.1.4",
+            "version": "v3.1.5",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/finder.git",
-                "reference": "e568ef1784f447a0e54dcb6f6de30b9747b0f577"
+                "reference": "205b5ffbb518a98ba2ae60a52656c4a31ab00c6f"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/finder/zipball/e568ef1784f447a0e54dcb6f6de30b9747b0f577",
-                "reference": "e568ef1784f447a0e54dcb6f6de30b9747b0f577",
+                "url": "https://api.github.com/repos/symfony/finder/zipball/205b5ffbb518a98ba2ae60a52656c4a31ab00c6f",
+                "reference": "205b5ffbb518a98ba2ae60a52656c4a31ab00c6f",
                 "shasum": ""
             },
             "require": {
@@ -1544,20 +1544,20 @@
             ],
             "description": "Symfony Finder Component",
             "homepage": "https://symfony.com",
-            "time": "2016-08-26 12:04:02"
+            "time": "2016-09-28 00:11:12"
         },
         {
             "name": "symfony/process",
-            "version": "v2.8.11",
+            "version": "v2.8.12",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/process.git",
-                "reference": "05a03ed27073638658cab9405d99a67dd1014987"
+                "reference": "024de37f8a6b9e5e8244d9eb3fcf3e467dd2a93f"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/process/zipball/05a03ed27073638658cab9405d99a67dd1014987",
-                "reference": "05a03ed27073638658cab9405d99a67dd1014987",
+                "url": "https://api.github.com/repos/symfony/process/zipball/024de37f8a6b9e5e8244d9eb3fcf3e467dd2a93f",
+                "reference": "024de37f8a6b9e5e8244d9eb3fcf3e467dd2a93f",
                 "shasum": ""
             },
             "require": {
@@ -1593,7 +1593,7 @@
             ],
             "description": "Symfony Process Component",
             "homepage": "https://symfony.com",
-            "time": "2016-09-06 10:55:00"
+            "time": "2016-09-29 14:03:54"
         },
         {
             "name": "tedivm/jshrink",
@@ -4329,16 +4329,16 @@
         },
         {
             "name": "symfony/config",
-            "version": "v2.8.11",
+            "version": "v2.8.12",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/config.git",
-                "reference": "005bf10c156335ede2e89fb9a9ee10a0b742bc84"
+                "reference": "f8b1922bbda9d2ac86aecd649399040bce849fde"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/config/zipball/005bf10c156335ede2e89fb9a9ee10a0b742bc84",
-                "reference": "005bf10c156335ede2e89fb9a9ee10a0b742bc84",
+                "url": "https://api.github.com/repos/symfony/config/zipball/f8b1922bbda9d2ac86aecd649399040bce849fde",
+                "reference": "f8b1922bbda9d2ac86aecd649399040bce849fde",
                 "shasum": ""
             },
             "require": {
@@ -4378,20 +4378,20 @@
             ],
             "description": "Symfony Config Component",
             "homepage": "https://symfony.com",
-            "time": "2016-08-16 14:56:08"
+            "time": "2016-09-14 20:31:12"
         },
         {
             "name": "symfony/dependency-injection",
-            "version": "v2.8.11",
+            "version": "v2.8.12",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/dependency-injection.git",
-                "reference": "0a732a9cafc30e54077967da4d019e1d618a8cb9"
+                "reference": "ee9ec9ac2b046462d341e9de7c4346142d335e75"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/0a732a9cafc30e54077967da4d019e1d618a8cb9",
-                "reference": "0a732a9cafc30e54077967da4d019e1d618a8cb9",
+                "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/ee9ec9ac2b046462d341e9de7c4346142d335e75",
+                "reference": "ee9ec9ac2b046462d341e9de7c4346142d335e75",
                 "shasum": ""
             },
             "require": {
@@ -4441,11 +4441,11 @@
             ],
             "description": "Symfony DependencyInjection Component",
             "homepage": "https://symfony.com",
-            "time": "2016-09-06 23:19:39"
+            "time": "2016-09-24 09:47:20"
         },
         {
             "name": "symfony/stopwatch",
-            "version": "v3.1.4",
+            "version": "v3.1.5",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/stopwatch.git",
@@ -4494,7 +4494,7 @@
         },
         {
             "name": "symfony/yaml",
-            "version": "v2.8.11",
+            "version": "v2.8.12",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/yaml.git",
@@ -4590,7 +4590,7 @@
     "prefer-stable": true,
     "prefer-lowest": false,
     "platform": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "lib-libxml": "*",
         "ext-ctype": "*",
         "ext-gd": "*",
diff --git a/dev/tests/api-functional/_files/Magento/TestModuleIntegrationFromConfig/composer.json b/dev/tests/api-functional/_files/Magento/TestModuleIntegrationFromConfig/composer.json
index 629afd442a46e7549206c1520b1b6c75f024dcb1..00888c7baf74990c6ba4d98ba6569c210ba08c7e 100644
--- a/dev/tests/api-functional/_files/Magento/TestModuleIntegrationFromConfig/composer.json
+++ b/dev/tests/api-functional/_files/Magento/TestModuleIntegrationFromConfig/composer.json
@@ -2,7 +2,7 @@
   "name": "magento/module-test-module-integration-from-config",
   "description": "test integration create from config",
   "require": {
-    "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+    "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
     "magento/framework": "0.42.0-beta8",
     "magento/module-integration": "0.42.0-beta8"
   },
@@ -16,4 +16,4 @@
       ]
     ]
   }
-}
\ No newline at end of file
+}
diff --git a/dev/tests/api-functional/_files/Magento/TestModuleJoinDirectives/composer.json b/dev/tests/api-functional/_files/Magento/TestModuleJoinDirectives/composer.json
index 1e2d9c0fa13dd80fcfe69374a7e02700f6b570ea..a9aa5a2ede89ce314a1f2257bc70c6b20b3bb2a0 100644
--- a/dev/tests/api-functional/_files/Magento/TestModuleJoinDirectives/composer.json
+++ b/dev/tests/api-functional/_files/Magento/TestModuleJoinDirectives/composer.json
@@ -2,7 +2,7 @@
   "name": "magento/module-test-join-directives",
   "description": "test integration for join directives",
   "require": {
-    "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+    "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
     "magento/framework": "0.42.0-beta8",
     "magento/module-sales": "0.42.0-beta8"
   },
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 4191ec1faa959aa1203ee45850c298f1d43bb988..cd02c6d4d7500ef9adf7d17ac9f866bfc8ef0711 100644
--- a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductRepositoryInterfaceTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductRepositoryInterfaceTest.php
@@ -713,6 +713,18 @@ class ProductRepositoryInterfaceTest extends WebapiAbstract
 
         $this->assertNotNull($response['items'][0]['sku']);
         $this->assertEquals('simple', $response['items'][0]['sku']);
+
+        $index = null;
+        foreach ($response['items'][0]['custom_attributes'] as $key => $customAttribute) {
+            if ($customAttribute['attribute_code'] == 'category_ids') {
+                $index = $key;
+                break;
+            }
+        }
+        $this->assertNotNull($index, 'Category information wasn\'t set');
+
+        $expectedResult = (TESTS_WEB_API_ADAPTER == self::ADAPTER_SOAP) ? ['string' => '2'] : ['2'];
+        $this->assertEquals($expectedResult, $response['items'][0]['custom_attributes'][$index]['value']);
     }
 
     /**
diff --git a/dev/tests/api-functional/testsuite/Magento/ConfigurableProduct/Api/LinkManagementTest.php b/dev/tests/api-functional/testsuite/Magento/ConfigurableProduct/Api/LinkManagementTest.php
index e4129a0739912c05dbb8546beab7f028945ad5f6..1a06be978d34c897f10aadd32e7f3e1720b1983b 100644
--- a/dev/tests/api-functional/testsuite/Magento/ConfigurableProduct/Api/LinkManagementTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/ConfigurableProduct/Api/LinkManagementTest.php
@@ -6,12 +6,33 @@
  */
 namespace Magento\ConfigurableProduct\Api;
 
+use Magento\Eav\Model\AttributeRepository;
+
 class LinkManagementTest extends \Magento\TestFramework\TestCase\WebapiAbstract
 {
     const SERVICE_NAME = 'configurableProductLinkManagementV1';
     const SERVICE_VERSION = 'V1';
     const RESOURCE_PATH = '/V1/configurable-products';
 
+    /**
+     * @var \Magento\Framework\ObjectManagerInterface
+     */
+    protected $objectManager;
+
+    /**
+     * @var AttributeRepository
+     */
+    protected $attributeRepository;
+
+    /**
+     * Execute per test initialization
+     */
+    public function setUp()
+    {
+        $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
+        $this->attributeRepository = $this->objectManager->get(\Magento\Eav\Model\AttributeRepository::class);
+    }
+
     /**
      * @magentoApiDataFixture Magento/ConfigurableProduct/_files/product_configurable.php
      */
@@ -40,14 +61,76 @@ class LinkManagementTest extends \Magento\TestFramework\TestCase\WebapiAbstract
     }
 
     /**
-     * @magentoApiDataFixture Magento/ConfigurableProduct/_files/product_simple_77.php
      * @magentoApiDataFixture Magento/ConfigurableProduct/_files/product_configurable.php
+     * @magentoApiDataFixture Magento/ConfigurableProduct/_files/product_simple_77.php
      * @magentoApiDataFixture Magento/ConfigurableProduct/_files/delete_association.php
      */
     public function testAddChild()
     {
         $productSku = 'configurable';
         $childSku = 'simple_77';
+        $res = $this->addChild($productSku, $childSku);
+        $this->assertTrue($res);
+    }
+
+    /**
+     * Test the full flow of creating a configurable product and adding a child via REST
+     *
+     * @magentoApiDataFixture Magento/ConfigurableProduct/_files/configurable_attribute.php
+     */
+    public function testAddChildFullRestCreation()
+    {
+        $productSku = 'configurable-product-sku';
+        $childSku = 'simple-product-sku';
+
+        $this->createConfigurableProduct($productSku);
+        $attribute = $this->attributeRepository->get('catalog_product', 'test_configurable');
+        $attributeValue = $attribute->getOptions()[1]->getValue();
+        $this->addOptionToConfigurableProduct($productSku, $attribute->getAttributeId(), $attributeValue);
+        $this->createSimpleProduct($childSku, $attributeValue);
+        $res = $this->addChild($productSku, $childSku);
+        $this->assertTrue($res);
+
+        // confirm that the simple product was added
+        $children = $this->getChildren($productSku);
+        $added = false;
+        foreach ($children as $child) {
+            if ($child['sku'] == $childSku) {
+                $added = true;
+                break;
+            }
+        }
+        $this->assertTrue($added);
+
+        // clean up products
+        $serviceInfo = [
+            'rest' => [
+                'resourcePath' => '/V1/products/' . $productSku,
+                'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_DELETE
+            ],
+            'soap' => [
+                'service' => 'catalogProductRepositoryV1',
+                'serviceVersion' => self::SERVICE_VERSION,
+                'operation' => 'catalogProductRepositoryV1DeleteById',
+            ],
+        ];
+        $this->_webApiCall($serviceInfo, ['sku' => $productSku]);
+        $serviceInfo = [
+            'rest' => [
+                'resourcePath' => '/V1/products/' . $childSku,
+                'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_DELETE
+            ],
+            'soap' => [
+                'service' => 'catalogProductRepositoryV1',
+                'serviceVersion' => self::SERVICE_VERSION,
+                'operation' => 'catalogProductRepositoryV1DeleteById',
+            ],
+        ];
+        $this->_webApiCall($serviceInfo, ['sku' => $childSku]);
+    }
+
+    private function addChild($productSku, $childSku)
+    {
         $serviceInfo = [
             'rest' => [
                 'resourcePath' => self::RESOURCE_PATH . '/' . $productSku . '/child',
@@ -59,8 +142,90 @@ class LinkManagementTest extends \Magento\TestFramework\TestCase\WebapiAbstract
                 'operation' => self::SERVICE_NAME . 'AddChild'
             ]
         ];
-        $res = $this->_webApiCall($serviceInfo, ['sku' => $productSku, 'childSku' => $childSku]);
-        $this->assertTrue($res);
+        return $this->_webApiCall($serviceInfo, ['sku' => $productSku, 'childSku' => $childSku]);
+    }
+
+    protected function createConfigurableProduct($productSku)
+    {
+        $requestData = [
+            'product' => [
+                'sku' => $productSku,
+                'name' => 'configurable-product-' . $productSku,
+                'type_id' => 'configurable',
+                'price' => 50,
+                'attribute_set_id' => 4
+            ]
+        ];
+        $serviceInfo = [
+            'rest' => [
+                'resourcePath' => '/V1/products',
+                'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_POST
+            ],
+            'soap' => [
+                'service' => 'catalogProductRepositoryV1',
+                'serviceVersion' => self::SERVICE_VERSION,
+                'operation' => 'catalogProductRepositoryV1Save',
+            ],
+        ];
+        return $this->_webApiCall($serviceInfo, $requestData);
+    }
+
+    protected function addOptionToConfigurableProduct($productSku, $attributeId, $attributeValue)
+    {
+        $requestData = [
+            'sku' => $productSku,
+            'option' => [
+                'attribute_id' => $attributeId,
+                'label' => 'test_configurable',
+                'position' => 0,
+                'is_use_default' => true,
+                'values' => [
+                    ['value_index' => $attributeValue],
+                ]
+            ]
+        ];
+        $serviceInfo = [
+            'rest' => [
+                'resourcePath' => '/V1/configurable-products/'. $productSku .'/options',
+                'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_POST,
+            ],
+            'soap' => [
+                'service' => 'configurableProductOptionRepositoryV1',
+                'serviceVersion' => self::SERVICE_VERSION,
+                'operation' => 'configurableProductOptionRepositoryV1Save',
+            ],
+        ];
+        return $this->_webApiCall($serviceInfo, $requestData);
+    }
+
+    protected function createSimpleProduct($sku, $attributeValue)
+    {
+        $requestData = [
+            'product' => [
+                'sku' => $sku,
+                'name' => 'simple-product-' . $sku,
+                'type_id' => 'simple',
+                'attribute_set_id' => 4,
+                'price' => 3.62,
+                'status' => 1,
+                'visibility' => 4,
+                'custom_attributes' => [
+                    ['attribute_code' => 'test_configurable', 'value' => $attributeValue],
+                ]
+            ]
+        ];
+        $serviceInfo = [
+            'rest' => [
+                'resourcePath' => '/V1/products',
+                'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_POST,
+            ],
+            'soap' => [
+                'service' => 'catalogProductRepositoryV1',
+                'serviceVersion' => self::SERVICE_VERSION,
+                'operation' => 'catalogProductRepositoryV1Save',
+            ],
+        ];
+        return $this->_webApiCall($serviceInfo, $requestData);
     }
 
     /**
@@ -93,7 +258,7 @@ class LinkManagementTest extends \Magento\TestFramework\TestCase\WebapiAbstract
 
     /**
      * @param string $productSku
-     * @return string
+     * @return string[]
      */
     protected function getChildren($productSku)
     {
diff --git a/dev/tests/functional/composer.json b/dev/tests/functional/composer.json
index 512c5bc8d5df666ced655806af0da64952d0f4ef..cef145167860c8ebad9695d870b6cc73580e47f3 100644
--- a/dev/tests/functional/composer.json
+++ b/dev/tests/functional/composer.json
@@ -1,7 +1,7 @@
 {
     "require": {
         "magento/mtf": "1.0.0-rc48",
-        "php": "~5.6.0|7.0.2|~7.0.6",
+        "php": "~5.6.5|7.0.2|~7.0.6",
         "phpunit/phpunit": "~4.8.0|~5.5.0",
         "phpunit/phpunit-selenium": ">=1.2"
     },
diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Block/Template.php b/dev/tests/functional/tests/app/Magento/Backend/Test/Block/Template.php
index 29361ced38bcc6b4ba344e2191f3c963eb92576d..fb22754faf483aa32b97d3e1672aeb17d58bec26 100644
--- a/dev/tests/functional/tests/app/Magento/Backend/Test/Block/Template.php
+++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Block/Template.php
@@ -19,7 +19,7 @@ class Template extends Block
      *
      * @var string
      */
-    protected $spinner = '[data-role="spinner"]';
+    protected $spinner = '#container [data-role="spinner"]';
 
     /**
      * Magento loader.
diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/CreateOrderWithPayPalBraintreeVaultBackendTest.php b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/CreateOrderWithPayPalBraintreeVaultBackendTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..6fde39412d1fe66a987b12cf5cb29e09d81327fe
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/CreateOrderWithPayPalBraintreeVaultBackendTest.php
@@ -0,0 +1,56 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Braintree\Test\TestCase;
+
+use Magento\Mtf\TestCase\Scenario;
+
+/**
+ * Preconditions:
+ * 1. Configure shipping method.
+ * 2. Configure payment method.
+ * 3. Create products.
+ * 4. Create and setup customer.
+ *
+ * Steps:
+ * 1. Log in Storefront.
+ * 2. Add products to the Shopping Cart.
+ * 3. In 'Estimate Shipping and Tax' section specify destination using values from Test Data.
+ * 4. Click the 'Proceed to Checkout' button.
+ * 5. Fill shipping information.
+ * 6. Select shipping method.
+ * 8. Select payment method
+ * 9. Verify order total on review step.
+ * 10. Click 'Continue to PayPal' button.
+ * 11. Click 'Proceed purchase' in popup.
+ * 12. Log in Admin panel.
+ * 13. Open placed order.
+ * 14. Click 'Reorder' button.
+ * 15. Select stored Braintree PayPal token.
+ * 16. Click 'Submit Order'.
+ * 17. Perform assertions.
+ *
+ * @group Braintree
+ * @ZephyrId MAGETWO-59259
+ */
+class CreateOrderWithPayPalBraintreeVaultBackendTest extends Scenario
+{
+    /* tags */
+    const MVP = 'yes';
+
+    const TEST_TYPE = '3rd_party_test';
+
+    const SEVERITY = 'S0';
+    /* end tags */
+
+    /**
+     * Runs test scenario
+     * @return void
+     */
+    public function test()
+    {
+        $this->executeScenario();
+    }
+}
diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/CreateOrderWithPayPalBraintreeVaultBackendTest.xml b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/CreateOrderWithPayPalBraintreeVaultBackendTest.xml
new file mode 100644
index 0000000000000000000000000000000000000000..03e0ba330fa3b74e2a33c2983655ced95cf3dbfe
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/CreateOrderWithPayPalBraintreeVaultBackendTest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright © 2016 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\Braintree\Test\TestCase\CreateOrderWithPayPalBraintreeVaultBackendTest" summary="Checkout with PayPal Braintree Vault token from Admin">
+        <variation name="CreateOrderWithPayPalBraintreeVaultBackendTestVariation1" summary="Checkout with PayPal Braintree Vault token from Admin" ticketId="MAGETWO-59259">
+            <data name="tag" xsi:type="string">est_type:3rd_party_test, severity:S0</data>
+            <data name="products/0" xsi:type="string">catalogProductSimple::product_10_dollar</data>
+            <data name="customer/dataset" xsi:type="string">default</data>
+            <data name="shippingAddress/dataset" xsi:type="string">US_address_1_without_email</data>
+            <data name="checkoutMethod" xsi:type="string">login</data>
+            <data name="shipping/shipping_service" xsi:type="string">Flat Rate</data>
+            <data name="shipping/shipping_method" xsi:type="string">Fixed</data>
+            <data name="payment/method" xsi:type="string">braintree_paypal</data>
+            <data name="vault/method" xsi:type="string">braintree_paypal_vault</data>
+            <data name="status" xsi:type="string">Processing</data>
+            <data name="configData" xsi:type="string">braintree, braintree_paypal, braintree_paypal_use_vault, braintree_paypal_skip_order_review</data>
+            <data name="prices" xsi:type="array">
+                <item name="grandTotal" xsi:type="string">15.00</item>
+            </data>
+            <constraint name="Magento\Sales\Test\Constraint\AssertOrderSuccessCreateMessage" />
+            <constraint name="Magento\Sales\Test\Constraint\AssertOrderStatusIsCorrect" />
+            <constraint name="Magento\Sales\Test\Constraint\AssertAuthorizationInCommentsHistory" />
+            <constraint name="Magento\Sales\Test\Constraint\AssertOrderInOrdersGrid" />
+            <constraint name="Magento\Sales\Test\Constraint\AssertOrderInOrdersGridOnFrontend" />
+        </variation>
+    </testCase>
+</config>
diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/CreateVaultOrderBackendTest.xml b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/CreateVaultOrderBackendTest.xml
index db6cd3572eaa2acec5ded94997b1951c744e6652..c9b26df050cfc9cf9ef4913a4f538459cee1923f 100644
--- a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/CreateVaultOrderBackendTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/CreateVaultOrderBackendTest.xml
@@ -19,6 +19,7 @@
                 <item name="grandTotal" xsi:type="string">15.00</item>
             </data>
             <data name="payment/method" xsi:type="string">braintree</data>
+            <data name="vault/method" xsi:type="string">braintree_cc_vault</data>
             <data name="creditCardClass" xsi:type="string">credit_card_braintree</data>
             <data name="creditCard/dataset" xsi:type="string">visa_braintree</data>
             <data name="creditCardSave" xsi:type="string">Yes</data>
diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutWithDiscountTest.xml b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutWithDiscountTest.xml
index 23fc729edb99f9645f7587d8e350464c81083fcd..f8ffa51982f1fae4d34a6290e1bebce28ba85712 100644
--- a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutWithDiscountTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutWithDiscountTest.xml
@@ -30,5 +30,25 @@
             <constraint name="Magento\Sales\Test\Constraint\AssertOrderGrandTotal" />
             <constraint name="Magento\Sales\Test\Constraint\AssertOrderStatusIsCorrect" />
         </variation>
+        <variation name="OnePageCheckoutWithDiscountTestVariation2" summary="Checkout with 100% discount and free shipping if Braintree through PayPal is enabled" ticketId="MAGETWO-59940">
+            <data name="description" xsi:type="string">Use saved for Braintree credit card on checkout</data>
+            <data name="products/0" xsi:type="string">catalogProductSimple::product_10_dollar</data>
+            <data name="customer/dataset" xsi:type="string">default</data>
+            <data name="salesRule" xsi:type="string">active_sales_rule_with_fixed_price_discount_coupon</data>
+            <data name="shippingAddress/dataset" xsi:type="string">US_address_1_without_email</data>
+            <data name="checkoutMethod" xsi:type="string">login</data>
+            <data name="shipping/shipping_service" xsi:type="string">Free Shipping</data>
+            <data name="shipping/shipping_method" xsi:type="string">Free</data>
+            <data name="payment/method" xsi:type="string">free</data>
+            <data name="prices" xsi:type="array">
+                <item name="grandTotal" xsi:type="string">0.00</item>
+            </data>
+            <data name="configData" xsi:type="string">braintree, braintree_use_vault, freeshipping</data>
+            <data name="status" xsi:type="string">Pending</data>
+            <data name="tag" xsi:type="string">test_type:3rd_party_test, severity:S1</data>
+            <constraint name="Magento\Checkout\Test\Constraint\AssertOrderSuccessPlacedMessage" />
+            <constraint name="Magento\Sales\Test\Constraint\AssertOrderGrandTotal" />
+            <constraint name="Magento\Sales\Test\Constraint\AssertOrderStatusIsCorrect" />
+        </variation>
     </testCase>
 </config>
diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/ReorderUsingVaultTest.xml b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/ReorderUsingVaultTest.xml
index 5a99c4a89a313392cdd596891712b1d2d4bbaec3..ad4d5cc06e92e260aed4c90e6f534f2540d25034 100644
--- a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/ReorderUsingVaultTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/ReorderUsingVaultTest.xml
@@ -19,6 +19,7 @@
                 <item name="grandTotal" xsi:type="string">15.00</item>
             </data>
             <data name="payment/method" xsi:type="string">braintree</data>
+            <data name="vault/method" xsi:type="string">braintree_cc_vault</data>
             <data name="creditCardClass" xsi:type="string">credit_card_braintree</data>
             <data name="creditCard/dataset" xsi:type="string">visa_braintree</data>
             <data name="configData" xsi:type="string">braintree, braintree_use_vault</data>
diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/etc/testcase.xml b/dev/tests/functional/tests/app/Magento/Braintree/Test/etc/testcase.xml
index 34f4be6493838598b9872225997736da38b07ff7..495f455c43a72f4d61029a07a8633fc09744c2f0 100644
--- a/dev/tests/functional/tests/app/Magento/Braintree/Test/etc/testcase.xml
+++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/etc/testcase.xml
@@ -158,4 +158,21 @@
         <step name="changeOrderStatusToPaymentReview" module="Magento_Braintree" next="denyPayment" />
         <step name="denyPayment" module="Magento_Braintree" />
     </scenario>
+    <scenario name="CreateOrderWithPayPalBraintreeVaultBackendTest" firstStep="setupConfiguration">
+        <step name="setupConfiguration" module="Magento_Config" next="createProducts" />
+        <step name="createProducts" module="Magento_Catalog" next="addProductsToTheCart" />
+        <step name="addProductsToTheCart" module="Magento_Checkout" next="estimateShippingAndTax" />
+        <step name="estimateShippingAndTax" module="Magento_Checkout" next="clickProceedToCheckout" />
+        <step name="clickProceedToCheckout" module="Magento_Checkout" next="createCustomer" />
+        <step name="createCustomer" module="Magento_Customer" next="selectCheckoutMethod" />
+        <step name="selectCheckoutMethod" module="Magento_Checkout" next="fillShippingAddress" />
+        <step name="fillShippingAddress" module="Magento_Checkout" next="fillShippingMethod" />
+        <step name="fillShippingMethod" module="Magento_Checkout" next="selectPaymentMethod" />
+        <step name="selectPaymentMethod" module="Magento_Checkout" next="placeOrderWithPaypal" />
+        <step name="placeOrderWithPaypal" module="Magento_Braintree" next="openOrder"/>
+        <step name="openOrder" module="Magento_Sales" next="reorder" />
+        <step name="reorder" module="Magento_Sales" next="useVaultPaymentToken" />
+        <step name="useVaultPaymentToken" module="Magento_Vault" next="submitOrder" />
+        <step name="submitOrder" module="Magento_Sales" />
+    </scenario>
 </config>
diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Adminhtml/Catalog/Product/Edit/Section/Bundle.php b/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Adminhtml/Catalog/Product/Edit/Section/Bundle.php
index e94ec38d010f3d519e8ab2e06c5fdd21dccd544c..5cf84cf6764270708bd30327f2596253f510370d 100644
--- a/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Adminhtml/Catalog/Product/Edit/Section/Bundle.php
+++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Adminhtml/Catalog/Product/Edit/Section/Bundle.php
@@ -8,7 +8,6 @@ namespace Magento\Bundle\Test\Block\Adminhtml\Catalog\Product\Edit\Section;
 
 use Magento\Mtf\Client\Element\SimpleElement;
 use Magento\Bundle\Test\Block\Adminhtml\Catalog\Product\Edit\Section\Bundle\Option;
-use Magento\Mtf\Client\Element;
 use Magento\Mtf\Client\ElementInterface;
 use Magento\Mtf\Client\Locator;
 use Magento\Ui\Test\Block\Adminhtml\Section;
@@ -53,6 +52,13 @@ class Bundle extends Section
      */
     protected $bundleOptionRow = './tr[%d]';
 
+    /**
+     * Selector for trash can button in bundle option row.
+     *
+     * @var string
+     */
+    protected $deleteOption = './tr[%d]//*[@data-index="delete_button"]';
+
     /**
      * Get bundle options block.
      *
@@ -83,17 +89,49 @@ class Bundle extends Section
         if (!isset($fields['bundle_selections'])) {
             return $this;
         }
+
+        $context = $this->_rootElement->find($this->bundleOptions, Locator::SELECTOR_XPATH);
+
+        if (isset($fields['bundle_selections']['value']['bundle_options'])) {
+            foreach ($fields['bundle_selections']['value']['bundle_options'] as $key => $bundleOption) {
+                $count = $key + 1;
+                $itemOption = $context->find(sprintf($this->openOption, $count), Locator::SELECTOR_XPATH);
+                $isContent = $context->find(sprintf($this->optionContent, $count), Locator::SELECTOR_XPATH)
+                    ->isVisible();
+                if ($itemOption->isVisible() && !$isContent) {
+                    $itemOption->click();
+                } elseif (!$itemOption->isVisible()) {
+                    $this->_rootElement->find($this->addNewOption)->click();
+                }
+                $this->getBundleOptionBlock($count, $context)->fillOption($bundleOption);
+            }
+        }
+
+        if (isset($fields['bundle_selections']['value']['bundle_options_delete'])) {
+            $this->deleteFieldsData($fields['bundle_selections']['value']['bundle_options_delete']);
+        }
+
+        return $this;
+    }
+
+    /**
+     * Delete some bundle options.
+     *
+     * @param array $fields
+     * @return $this
+     */
+    public function deleteFieldsData(array $fields)
+    {
         $context = $this->_rootElement->find($this->bundleOptions, Locator::SELECTOR_XPATH);
-        foreach ($fields['bundle_selections']['value']['bundle_options'] as $key => $bundleOption) {
-            $count = $key + 1;
-            $itemOption = $context->find(sprintf($this->openOption, $count), Locator::SELECTOR_XPATH);
-            $isContent = $context->find(sprintf($this->optionContent, $count), Locator::SELECTOR_XPATH)->isVisible();
-            if ($itemOption->isVisible() && !$isContent) {
-                $itemOption->click();
-            } elseif (!$itemOption->isVisible()) {
-                $this->_rootElement->find($this->addNewOption)->click();
+        foreach (array_keys($fields) as $key) {
+            $bundleOptionIndex = $key + 1;
+            $deleteOption = $context->find(
+                sprintf($this->deleteOption, $bundleOptionIndex),
+                Locator::SELECTOR_XPATH
+            );
+            if ($deleteOption->isVisible()) {
+                $deleteOption->click();
             }
-            $this->getBundleOptionBlock($count, $context)->fillOption($bundleOption);
         }
         return $this;
     }
diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundleOptionsDeleted.php b/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundleOptionsDeleted.php
new file mode 100644
index 0000000000000000000000000000000000000000..69e694abd261ab4ca4e4102f542b72f612552d5b
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundleOptionsDeleted.php
@@ -0,0 +1,78 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Bundle\Test\Constraint;
+
+use Magento\Bundle\Test\Fixture\BundleProduct;
+use Magento\Mtf\Constraint\AbstractConstraint;
+use Magento\Catalog\Test\Page\Adminhtml\CatalogProductEdit;
+use Magento\Catalog\Test\Page\Adminhtml\CatalogProductIndex;
+use Magento\Mtf\Fixture\FixtureInterface;
+
+/**
+ * Assert bundle product form.
+ */
+class AssertBundleOptionsDeleted extends AbstractConstraint
+{
+    /**
+     * Assert that displayed price view for bundle product on product page equals passed from fixture.
+     * @param BundleProduct $product
+     * @param BundleProduct $originalProduct
+     * @param CatalogProductIndex $productGrid
+     * @param CatalogProductEdit $productPage
+     * @return void
+     */
+    public function processAssert(
+        BundleProduct $product,
+        BundleProduct $originalProduct,
+        CatalogProductIndex $productGrid,
+        CatalogProductEdit $productPage
+    ) {
+        $filter = ['sku' => $product->getSku()];
+        $productGrid->open();
+        $productGrid->getProductGrid()->searchAndOpen($filter);
+
+        $productData = $product->getData()['bundle_selections']['bundle_options'];
+        $originalProductData = $originalProduct->getData()['bundle_selections']['bundle_options'];
+        $formData = $productPage->getProductForm()->getData($product)['bundle_selections'];
+
+        $productDataLength = count($productData);
+        $formDataLength = count($productData);
+        \PHPUnit_Framework_Assert::assertEquals($productDataLength, $formDataLength);
+
+        foreach ($productData as $index => $option) {
+            $productAssociatedDataLength = count($option['assigned_products']);
+            $formAssociatedDataLength = count($formData[$index]['assigned_products']);
+            \PHPUnit_Framework_Assert::assertEquals($productAssociatedDataLength, $formAssociatedDataLength);
+
+            foreach ($option['assigned_products'] as $productIndex => $associatedProduct) {
+                $associatedProduct['data']['getProductName'] =
+                    $originalProductData[$index+1]['assigned_products'][$productIndex]['search_data']['name'];
+                $associatedProduct = $associatedProduct['data'];
+                $errorAssociatedProducts = array_diff(
+                    $associatedProduct,
+                    $formData[$index]['assigned_products'][$productIndex]
+                );
+                \PHPUnit_Framework_Assert::assertCount(0, $errorAssociatedProducts);
+            }
+
+            unset($option['assigned_products']);
+            unset($formData[$index]['assigned_products']);
+            $errorFields = array_diff($option, $formData[$index]);
+            \PHPUnit_Framework_Assert::assertCount(0, $errorFields);
+        }
+    }
+
+    /**
+     * Returns a string representation of the object
+     *
+     * @return string
+     */
+    public function toString()
+    {
+        return 'Bundle options were not deleted correctly. There is difference with expected options';
+    }
+}
diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Repository/BundleProduct.xml b/dev/tests/functional/tests/app/Magento/Bundle/Test/Repository/BundleProduct.xml
index 2b5e9a437b32bdec615fd9e2a928b3784ba68fb4..6a507a7a99b437a793b4096f8f10d9e33ccb825a 100644
--- a/dev/tests/functional/tests/app/Magento/Bundle/Test/Repository/BundleProduct.xml
+++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Repository/BundleProduct.xml
@@ -225,5 +225,27 @@
                 <item name="dataset" xsi:type="string">bundle_fixed_100_dollar</item>
             </field>
         </dataset>
+
+        <dataset name="with_3_bundle_options">
+            <field name="name" xsi:type="string">Bundle with 3 options %isolation%</field>
+            <field name="url_key" xsi:type="string">with_3_bundle_options-%isolation%</field>
+            <field name="sku" xsi:type="string">sku_with_3_bundle_options_%isolation%</field>
+            <field name="sku_type" xsi:type="string">No</field>
+            <field name="price_type" xsi:type="string">No</field>
+            <field name="price" xsi:type="array">
+                <item name="value" xsi:type="string">100</item>
+            </field>
+            <field name="tax_class_id" xsi:type="array">
+                <item name="dataset" xsi:type="string">taxable_goods</item>
+            </field>
+            <field name="website_ids" xsi:type="array">
+                <item name="0" xsi:type="array">
+                    <item name="dataset" xsi:type="string">default</item>
+                </item>
+            </field>
+            <field name="bundle_selections" xsi:type="array">
+                <item name="dataset" xsi:type="string">with_3_options</item>
+            </field>
+        </dataset>
     </repository>
 </config>
diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Repository/BundleProduct/BundleSelections.xml b/dev/tests/functional/tests/app/Magento/Bundle/Test/Repository/BundleProduct/BundleSelections.xml
index 3e9b055c48ca5a1bfa5df3410ec48ef708a71fa7..7131aab3cffcbb69ca84f1078540a2dbada2ae28 100644
--- a/dev/tests/functional/tests/app/Magento/Bundle/Test/Repository/BundleProduct/BundleSelections.xml
+++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Repository/BundleProduct/BundleSelections.xml
@@ -665,5 +665,170 @@
                 </item>
             </field>
         </dataset>
+
+        <dataset name="with_3_options">
+            <field name="bundle_options" xsi:type="array">
+                <item name="0" xsi:type="array">
+                    <item name="title" xsi:type="string">Option 1</item>
+                    <item name="type" xsi:type="string">Drop-down</item>
+                    <item name="required" xsi:type="string">No</item>
+                    <item name="assigned_products" xsi:type="array">
+                        <item name="0" xsi:type="array">
+                            <item name="search_data" xsi:type="array">
+                                <item name="name" xsi:type="string">%product_name%</item>
+                            </item>
+                            <item name="data" xsi:type="array">
+                                <item name="selection_qty" xsi:type="string">1</item>
+                                <item name="selection_price_value" xsi:type="string">1</item>
+                                <item name="selection_price_type" xsi:type="string">Fixed</item>
+                            </item>
+                        </item>
+                    </item>
+                </item>
+                <item name="1" xsi:type="array">
+                    <item name="title" xsi:type="string">Option 2</item>
+                    <item name="type" xsi:type="string">Radio Buttons</item>
+                    <item name="required" xsi:type="string">No</item>
+                    <item name="assigned_products" xsi:type="array">
+                        <item name="0" xsi:type="array">
+                            <item name="search_data" xsi:type="array">
+                                <item name="name" xsi:type="string">%product_name%</item>
+                            </item>
+                            <item name="data" xsi:type="array">
+                                <item name="selection_qty" xsi:type="string">20</item>
+                                <item name="selection_price_value" xsi:type="string">20</item>
+                                <item name="selection_price_type" xsi:type="string">Fixed</item>
+                            </item>
+                        </item>
+                        <item name="1" xsi:type="array">
+                            <item name="search_data" xsi:type="array">
+                                <item name="name" xsi:type="string">%product_name%</item>
+                            </item>
+                            <item name="data" xsi:type="array">
+                                <item name="selection_qty" xsi:type="string">21</item>
+                                <item name="selection_price_value" xsi:type="string">21</item>
+                                <item name="selection_price_type" xsi:type="string">Fixed</item>
+                            </item>
+                        </item>
+                        <item name="2" xsi:type="array">
+                            <item name="search_data" xsi:type="array">
+                                <item name="name" xsi:type="string">%product_name%</item>
+                            </item>
+                            <item name="data" xsi:type="array">
+                                <item name="selection_qty" xsi:type="string">22</item>
+                                <item name="selection_price_value" xsi:type="string">22</item>
+                                <item name="selection_price_type" xsi:type="string">Fixed</item>
+                            </item>
+                        </item>
+                    </item>
+                </item>
+                <item name="2" xsi:type="array">
+                    <item name="title" xsi:type="string">Option 3</item>
+                    <item name="type" xsi:type="string">Drop-down</item>
+                    <item name="required" xsi:type="string">No</item>
+                    <item name="assigned_products" xsi:type="array">
+                        <item name="0" xsi:type="array">
+                            <item name="search_data" xsi:type="array">
+                                <item name="name" xsi:type="string">%product_name%</item>
+                            </item>
+                            <item name="data" xsi:type="array">
+                                <item name="selection_qty" xsi:type="string">3</item>
+                                <item name="selection_price_value" xsi:type="string">3</item>
+                                <item name="selection_price_type" xsi:type="string">Fixed</item>
+                            </item>
+                        </item>
+                    </item>
+                </item>
+            </field>
+            <field name="products" xsi:type="array">
+                <item name="0" xsi:type="array">
+                    <item name="0" xsi:type="string">catalogProductSimple::default</item>
+                </item>
+                <item name="1" xsi:type="array">
+                    <item name="0" xsi:type="string">catalogProductSimple::default</item>
+                    <item name="1" xsi:type="string">catalogProductSimple::product_100_dollar</item>
+                    <item name="2" xsi:type="string">catalogProductSimple::product_without_category</item>
+                </item>
+                <item name="2" xsi:type="array">
+                    <item name="0" xsi:type="string">catalogProductSimple::default</item>
+                </item>
+            </field>
+        </dataset>
+
+        <dataset name="with_3_options_delete">
+            <field name="bundle_options_delete" xsi:type="array">
+                <item name="0" xsi:type="array">
+                    <item name="title" xsi:type="string">Option 1</item>
+                    <item name="type" xsi:type="string">Drop-down</item>
+                    <item name="required" xsi:type="string">No</item>
+                </item>
+            </field>
+            <field name="bundle_options" xsi:type="array">
+                <item name="0" xsi:type="array">
+                    <item name="title" xsi:type="string">Option 2</item>
+                    <item name="type" xsi:type="string">Radio Buttons</item>
+                    <item name="required" xsi:type="string">No</item>
+                    <item name="assigned_products" xsi:type="array">
+                        <item name="0" xsi:type="array">
+                            <item name="search_data" xsi:type="array">
+                                <item name="name" xsi:type="string">%product_name%</item>
+                            </item>
+                            <item name="data" xsi:type="array">
+                                <item name="selection_qty" xsi:type="string">20</item>
+                                <item name="selection_price_value" xsi:type="string">20</item>
+                                <item name="selection_price_type" xsi:type="string">Fixed</item>
+                            </item>
+                        </item>
+                        <item name="1" xsi:type="array">
+                            <item name="search_data" xsi:type="array">
+                                <item name="name" xsi:type="string">%product_name%</item>
+                            </item>
+                            <item name="data" xsi:type="array">
+                                <item name="selection_qty" xsi:type="string">21</item>
+                                <item name="selection_price_value" xsi:type="string">21</item>
+                                <item name="selection_price_type" xsi:type="string">Fixed</item>
+                            </item>
+                        </item>
+                        <item name="2" xsi:type="array">
+                            <item name="search_data" xsi:type="array">
+                                <item name="name" xsi:type="string">%product_name%</item>
+                            </item>
+                            <item name="data" xsi:type="array">
+                                <item name="selection_qty" xsi:type="string">22</item>
+                                <item name="selection_price_value" xsi:type="string">22</item>
+                                <item name="selection_price_type" xsi:type="string">Fixed</item>
+                            </item>
+                        </item>
+                    </item>
+                </item>
+                <item name="1" xsi:type="array">
+                    <item name="title" xsi:type="string">Option 3</item>
+                    <item name="type" xsi:type="string">Drop-down</item>
+                    <item name="required" xsi:type="string">No</item>
+                    <item name="assigned_products" xsi:type="array">
+                        <item name="0" xsi:type="array">
+                            <item name="search_data" xsi:type="array">
+                                <item name="name" xsi:type="string">%product_name%</item>
+                            </item>
+                            <item name="data" xsi:type="array">
+                                <item name="selection_qty" xsi:type="string">3</item>
+                                <item name="selection_price_value" xsi:type="string">3</item>
+                                <item name="selection_price_type" xsi:type="string">Fixed</item>
+                            </item>
+                        </item>
+                    </item>
+                </item>
+            </field>
+            <field name="products" xsi:type="array">
+                <item name="0" xsi:type="array">
+                    <item name="0" xsi:type="string">catalogProductSimple::default</item>
+                    <item name="1" xsi:type="string">catalogProductSimple::product_100_dollar</item>
+                    <item name="2" xsi:type="string">catalogProductSimple::product_without_category</item>
+                </item>
+                <item name="1" xsi:type="array">
+                    <item name="0" xsi:type="string">catalogProductSimple::default</item>
+                </item>
+            </field>
+        </dataset>
     </repository>
 </config>
diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/CreateBundleProductEntityTest.xml b/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/CreateBundleProductEntityTest.xml
index 678e9306cbadb3bc22dafd9bca089a8b7f304ba7..211e09861995f27e22a446b93e465a7197936965 100644
--- a/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/CreateBundleProductEntityTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/CreateBundleProductEntityTest.xml
@@ -195,8 +195,8 @@
             <data name="product/data/price_type" xsi:type="string">Yes</data>
             <data name="product/data/price/dataset" xsi:type="string">dynamic-8</data>
             <data name="product/data/special_price" xsi:type="string">20</data>
-            <data name="product/data/special_from_date/pattern" xsi:type="string">M j, Y -1 day</data>
-            <data name="product/data/special_to_date/pattern" xsi:type="string">M j, Y +3 days</data>
+            <data name="product/data/special_from_date/pattern" xsi:type="string">m/d/y -1 day</data>
+            <data name="product/data/special_to_date/pattern" xsi:type="string">m/d/y +3 days</data>
             <data name="product/data/bundle_selections/dataset" xsi:type="string">default_dynamic</data>
             <data name="product/data/bundle_selections/products" xsi:type="string">catalogProductSimple::product_100_dollar,catalogProductSimple::product_40_dollar</data>
             <data name="product/data/checkout_data/dataset" xsi:type="string">bundle_default</data>
diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/UpdateBundleOptionsTest.php b/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/UpdateBundleOptionsTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..3c17360200f44f2fe8875590578c6960ea7757d0
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/UpdateBundleOptionsTest.php
@@ -0,0 +1,94 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Bundle\Test\TestCase;
+
+use Magento\Bundle\Test\Fixture\BundleProduct;
+use Magento\Catalog\Test\Page\Adminhtml\CatalogProductEdit;
+use Magento\Catalog\Test\Page\Adminhtml\CatalogProductIndex;
+use Magento\Mtf\TestCase\Injectable;
+
+/**
+ * Test Flow:
+ * 1. Login as admin
+ * 2. Navigate to the Products>Inventory>Catalog
+ * 3. Click on Bundle product in the grid to edit it
+ * 4. Fill in some Bundle Options data according to data set
+ * 5. Delete some Bundle Options data according to data set
+ * 6. Save product
+ * 7. Verify Bundle Options in the updated product
+ *
+ * @group Bundle_Product
+ * @ZephyrId MAGETWO-26195
+ */
+class UpdateBundleOptionsTest extends Injectable
+{
+    /* tags */
+    const MVP = 'yes';
+    /* end tags */
+
+    /**
+     * Page product on backend
+     *
+     * @var CatalogProductIndex
+     */
+    protected $catalogProductIndex;
+
+    /**
+     * Edit page on backend
+     *
+     * @var CatalogProductEdit
+     */
+    protected $catalogProductEdit;
+
+    /**
+     * Injection data
+     *
+     * @param CatalogProductIndex $catalogProductIndexNewPage
+     * @param CatalogProductEdit $catalogProductEditPage
+     * @return void
+     */
+    public function __inject(
+        CatalogProductIndex $catalogProductIndexNewPage,
+        CatalogProductEdit $catalogProductEditPage
+    ) {
+        $this->catalogProductIndex = $catalogProductIndexNewPage;
+        $this->catalogProductEdit = $catalogProductEditPage;
+    }
+
+    /**
+     * Test update bundle product
+     *
+     * @param BundleProduct $product
+     * @param BundleProduct $originalProduct
+     * @return void
+     */
+    public function test(BundleProduct $product, BundleProduct $originalProduct)
+    {
+        // Preconditions
+        $originalProduct->persist();
+
+        // Steps
+        $filter = ['sku' => $originalProduct->getSku()];
+
+        $this->catalogProductIndex->open();
+        $this->catalogProductIndex->getProductGrid()->searchAndOpen($filter);
+
+        $form = $this->catalogProductEdit->getProductForm();
+        $form->openSection('bundle');
+        $container = $form->getSection('bundle');
+        $containerFields = $product->getData()['bundle_selections']['bundle_options_delete'];
+        $container->deleteFieldsData($containerFields);
+
+        $form->openSection('product-details');
+        $container = $form->getSection('product-details');
+        $containerFields = $product->getData();
+        unset($containerFields['bundle_selections']);
+        $container->setFieldsData($containerFields);
+
+        $this->catalogProductEdit->getFormPageActions()->save();
+    }
+}
diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/UpdateBundleOptionsTest.xml b/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/UpdateBundleOptionsTest.xml
new file mode 100644
index 0000000000000000000000000000000000000000..795665d66d2bf7d34438381d3390e94c8458d3b7
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/UpdateBundleOptionsTest.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright © 2016 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\Bundle\Test\TestCase\UpdateBundleOptionsTest" summary="Update Bundle Product Options" ticketId="MAGETWO-26195">
+        <variation name="UpdateBundleOptionsTestVariation1">
+            <data name="description" xsi:type="string">Update bundle product options</data>
+            <data name="originalProduct/dataset" xsi:type="string">with_3_bundle_options</data>
+            <data name="product/data/name" xsi:type="string">bundle_3_options_%isolation%</data>
+            <data name="product/data/sku" xsi:type="string">bundle_3_options_%isolation%</data>
+            <data name="product/data/bundle_selections/dataset" xsi:type="string">with_3_options_delete</data>
+            <constraint name="Magento\Bundle\Test\Constraint\AssertBundleOptionsDeleted" />
+        </variation>
+    </testCase>
+</config>
\ No newline at end of file
diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductSimple.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductSimple.xml
index ecd68593b08cc252e67a144ccd2a9610ac88f22d..e1cbc1a1d8ba2dba7f3be971b3f1b456f6e7d02a 100644
--- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductSimple.xml
+++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductSimple.xml
@@ -1233,5 +1233,35 @@
             <field name="url_key" xsi:type="string">overnight-duffle</field>
         </dataset>
 
+        <dataset name="simple_with_weight_10_for_salesrule">
+            <field name="attribute_set_id" xsi:type="array">
+                <item name="dataset" xsi:type="string">default</item>
+            </field>
+            <field name="name" xsi:type="string">Simple Product %isolation%</field>
+            <field name="sku" xsi:type="string">sku_simple_product_%isolation%</field>
+            <field name="product_has_weight" xsi:type="string">This item has weight</field>
+            <field name="weight" xsi:type="string">10</field>
+            <field name="quantity_and_stock_status" xsi:type="array">
+                <item name="qty" xsi:type="string">25</item>
+                <item name="is_in_stock" xsi:type="string">In Stock</item>
+            </field>
+            <field name="price" xsi:type="array">
+                <item name="value" xsi:type="string">560</item>
+            </field>
+            <field name="tax_class_id" xsi:type="array">
+                <item name="dataset" xsi:type="string">taxable_goods</item>
+            </field>
+            <field name="website_ids" xsi:type="array">
+                <item name="0" xsi:type="array">
+                    <item name="dataset" xsi:type="string">default</item>
+                </item>
+            </field>
+            <field name="visibility" xsi:type="string">Catalog, Search</field>
+            <field name="url_key" xsi:type="string">simple-product-%isolation%</field>
+            <field name="checkout_data" xsi:type="array">
+                <item name="dataset" xsi:type="string">simple_order_default</item>
+            </field>
+        </dataset>
+
     </repository>
 </config>
diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/ConfigData.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/ConfigData.xml
index 9ae1e2ebfacca405f8505496f546cf2182e2dd3f..c32999a6ebce7e0a4c44c1a10bc8fe4010a795f7 100644
--- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/ConfigData.xml
+++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/ConfigData.xml
@@ -34,5 +34,16 @@
                 <item name="inherit" xsi:type="number">1</item>
             </field>
         </dataset>
+        <dataset name="attribute_product_mask_sku">
+            <field name="catalog/fields_masks/sku" xsi:type="array">
+                <item name="value" xsi:type="string">{{name}} {{country_of_manufacture}}</item>
+            </field>
+        </dataset>
+        <dataset name="attribute_product_mask_sku_rollback">
+            <field name="catalog/fields_masks/sku" xsi:type="array">
+                <item name="value" xsi:type="string">{{name}}</item>
+                <item name="inherit" xsi:type="number">1</item>
+            </field>
+        </dataset>
     </repository>
 </config>
diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/CreateSimpleProductEntityByAttributeMaskSkuTest.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/CreateSimpleProductEntityByAttributeMaskSkuTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..0884e93387b2ac60c0be00e56791ae2b03443d38
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/CreateSimpleProductEntityByAttributeMaskSkuTest.php
@@ -0,0 +1,134 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Catalog\Test\TestCase\Product;
+
+use Magento\Catalog\Test\Fixture\CatalogProductSimple;
+use Magento\Catalog\Test\Page\Adminhtml\CatalogProductIndex;
+use Magento\Catalog\Test\Page\Adminhtml\CatalogProductNew;
+use Magento\Mtf\TestCase\Injectable;
+
+/**
+ * Steps:
+ * 1. Login to the backend.
+ * 2. Navigate to Products > Catalog.
+ * 3. Start to create simple product.
+ * 4. Fill in data according to data set.
+ * 5. Save Product.
+ * 6. Perform appropriate assertions.
+ *
+ * @group Products
+ * @ZephyrId MAGETWO-59861
+ */
+class CreateSimpleProductEntityByAttributeMaskSkuTest extends Injectable
+{
+    /**
+     * Configuration setting.
+     *
+     * @var string
+     */
+    protected $configData;
+
+    /**
+     * Should cache be flushed
+     *
+     * @var bool
+     */
+    private $flushCache;
+
+    /**
+     * @var \Magento\Mtf\Fixture\FixtureFactory
+     */
+    private $fixtureFactory;
+
+    /**
+     * Run create product simple entity by attribute mask SKU test.
+     *
+     * @param CatalogProductSimple $product
+     * @param CatalogProductIndex $productGrid
+     * @param CatalogProductNew $newProductPage
+     * @param string $configData
+     * @param bool $flushCache
+     * @return array
+     */
+    public function testCreate(
+        CatalogProductSimple $product,
+        CatalogProductIndex $productGrid,
+        CatalogProductNew $newProductPage,
+        \Magento\Mtf\Fixture\FixtureFactory $fixtureFactory,
+        $flushCache = false,
+        $configData = null
+    ) {
+        $this->configData = $configData;
+        $this->flushCache = $flushCache;
+        $this->fixtureFactory = $fixtureFactory;
+
+        // Preconditions
+        $this->objectManager->create(
+            \Magento\Config\Test\TestStep\SetupConfigurationStep::class,
+            ['configData' => $this->configData, 'flushCache' => $this->flushCache]
+        )->run();
+
+        // Steps
+        $productGrid->open();
+        $productGrid->getGridPageActionBlock()->addProduct('simple');
+        $newProductPage->getProductForm()->fill($product);
+        $newProductPage->getFormPageActions()->save();
+
+        $skuMask = $this->prepareSkuByMask($product);
+
+        $productSimple = $fixtureFactory->createByCode(
+            'catalogProductSimple',
+            ['data' => array_merge($product->getData(), ['sku' => $skuMask])]
+        );
+
+        return ['product' => $productSimple];
+    }
+
+    /**
+     * Obtains product sku based on attributes define in Stores > Configuration->Catalog > Catalog > Mask for SKU
+     *
+     * @param CatalogProductSimple $product
+     * @return string
+     */
+    private function prepareSkuByMask(CatalogProductSimple $product)
+    {
+        $productData = $product->getData();
+        $skuMask = '';
+        $config = $this->fixtureFactory->createByCode('configData', ['dataset' => $this->configData]);
+        $section = $config->getData('section');
+        if (is_array($section) && array_key_exists('catalog/fields_masks/sku', $section)) {
+            $skuMask = $section['catalog/fields_masks/sku']['value'];
+        }
+
+        $attributesInPattern = [];
+        $count = preg_match_all('/{{(\w+)}}/', $skuMask, $matches);
+        if ($count > 0 && is_array($matches[0])) {
+            foreach ($matches[1] as $attributeName) {
+                if (array_key_exists($attributeName, $productData)) {
+                    $attributesInPattern[$attributeName] = $productData[$attributeName];
+                }
+            }
+        }
+        foreach ($attributesInPattern as $attributeName => $attributeValue) {
+            $skuMask = str_replace('{{' . $attributeName . '}}', $attributeValue, $skuMask);
+        }
+        return $skuMask;
+    }
+
+    /**
+     * Clean data after running test.
+     *
+     * @return void
+     */
+    public function tearDown()
+    {
+        $this->objectManager->create(
+            \Magento\Config\Test\TestStep\SetupConfigurationStep::class,
+            ['configData' => $this->configData, 'rollback' => true, 'flushCache' => $this->flushCache]
+        )->run();
+    }
+}
diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/CreateSimpleProductEntityByAttributeMaskSkuTest.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/CreateSimpleProductEntityByAttributeMaskSkuTest.xml
new file mode 100644
index 0000000000000000000000000000000000000000..338f34a57ab5d8745a9cf53665d34e39a0369694
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/CreateSimpleProductEntityByAttributeMaskSkuTest.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright © 2016 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\CreateSimpleProductEntityByAttributeMaskSkuTest" summary="Create Simple Product with attribute sku mask" ticketId="MAGETWO-59861">
+        <variation name="CreateSimpleProductEntityByAttributeMaskSkuTest1">
+            <data name="configData" xsi:type="string">attribute_product_mask_sku</data>
+            <data name="description" xsi:type="string">Create product with country of manufacture attribute sku mask</data>
+            <data name="product/data/url_key" xsi:type="string">simple-product-%isolation%</data>
+            <data name="product/data/name" xsi:type="string">Simple Product %isolation%</data>
+            <data name="product/data/price/value" xsi:type="string">10000</data>
+            <data name="product/data/weight" xsi:type="string">50</data>
+            <data name="product/data/quantity_and_stock_status/qty" xsi:type="string">657</data>
+            <data name="product/data/country_of_manufacture" xsi:type="string">Ukraine</data>
+            <constraint name="Magento\Catalog\Test\Constraint\AssertProductSaveMessage" />
+            <constraint name="Magento\Catalog\Test\Constraint\AssertProductInGrid" />
+        </variation>
+    </testCase>
+</config>
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 697733fd3c33d8856f5d775452aca8ad977e77e9..fac0f811be2616675e85e3f34927731f13ea16b1 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
@@ -99,6 +99,13 @@ class Cart extends Block
      */
     protected $preloaderSpinner = '#preloaderSpinner';
 
+    /**
+     * Cart item class name.
+     *
+     * @var string
+     */
+    protected $cartItemClass = \Magento\Checkout\Test\Block\Cart\CartItem::class;
+
     /**
      * Wait for PayPal page is loaded.
      *
@@ -129,7 +136,7 @@ class Cart extends Block
                 Locator::SELECTOR_XPATH
             );
             $cartItem = $this->blockFactory->create(
-                '\\' . get_class($this) . '\CartItem',
+                $this->cartItemClass,
                 ['element' => $cartItemBlock]
             );
         }
diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Payment.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Payment.php
index f1776d2bf933e17d63006948795418309348ffe3..cad6dda90459845718bc3ab1e3ac2952cca16640 100644
--- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Payment.php
+++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Payment.php
@@ -85,6 +85,7 @@ class Payment extends Block
         $paymentLabelSelector = sprintf($this->paymentMethodLabel, $payment['method']);
 
         try {
+            $this->waitForElementNotVisible($this->waitElement);
             $this->waitForElementVisible($paymentLabelSelector);
         } catch (\Exception $exception) {
             throw new \Exception('Such payment method is absent.');
diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Shipping.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Shipping.php
index a3eda5ea1b3c5a3d6b5be217df906ca69b67f742..f2530c016b714bf5af16c2b6d0f0f6d690cc4af0 100644
--- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Shipping.php
+++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Shipping.php
@@ -6,12 +6,67 @@
 
 namespace Magento\Checkout\Test\Block\Onepage;
 
+use Magento\Checkout\Test\Block\Onepage\Shipping\AddressModal;
 use Magento\Mtf\Block\Form;
+use Magento\Mtf\Client\Locator;
 
 /**
  * Checkout shipping address block.
  */
 class Shipping extends Form
 {
-    //
+    /**
+     * CSS Selector for "New Address" button
+     *
+     * @var string
+     */
+    private $newAddressButton = '[data-bind*="isNewAddressAdded"]';
+
+    /**
+     * Wait element.
+     *
+     * @var string
+     */
+    private $waitElement = '.loading-mask';
+
+    /**
+     * SCC Selector for Address Modal block.
+     *
+     * @var string
+     */
+    private $addressModalBlock = '//*[@id="opc-new-shipping-address"]/../..';
+
+    /**
+     * Click on "New Address" button.
+     *
+     * @return void
+     */
+    public function clickOnNewAddressButton()
+    {
+        $this->waitForElementNotVisible($this->waitElement);
+        $this->_rootElement->find($this->newAddressButton)->click();
+    }
+
+    /**
+     * Get Address Modal Block.
+     *
+     * @return AddressModal
+     */
+    public function getAddressModalBlock()
+    {
+        return $this->blockFactory->create(
+            AddressModal::class,
+            ['element' => $this->browser->find($this->addressModalBlock, Locator::SELECTOR_XPATH)]
+        );
+    }
+
+    /**
+     * Returns form's required elements
+     *
+     * @return \Magento\Mtf\Client\ElementInterface[]
+     */
+    public function getRequiredFields()
+    {
+        return $this->_rootElement->getElements("div .field._required");
+    }
 }
diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Shipping/AddressModal.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Shipping/AddressModal.php
new file mode 100644
index 0000000000000000000000000000000000000000..8a949c474bc847942f1bd5922d00514cd6133d08
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Shipping/AddressModal.php
@@ -0,0 +1,68 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Checkout\Test\Block\Onepage\Shipping;
+
+use Magento\Mtf\Block\Form;
+
+/**
+ * Checkout shipping address modal block.
+ */
+class AddressModal extends Form
+{
+    /**
+     * CSS Selector for Save button.
+     *
+     * @var string
+     */
+    private $saveButton = '.action-save-address';
+
+    /**
+     * Selector for field's error message.
+     *
+     * @var string
+     */
+    private $errorMessage = '.field-error';
+
+    /**
+     * Selector for error fields.
+     *
+     * @var string
+     */
+    private $errorField = '._error';
+
+    /**
+     * Selector for field label that have error message.
+     *
+     * @var string
+     */
+    private $fieldLabel = '.label';
+
+    /**
+     * Click on 'Save Address' button.
+     *
+     * @return void
+     */
+    public function save()
+    {
+        $this->_rootElement->find($this->saveButton)->click();
+    }
+
+    /**
+     * Get Error messages for attributes.
+     *
+     * @return array
+     */
+    public function getErrorMessages()
+    {
+        $result = [];
+        foreach ($this->_rootElement->getElements($this->errorField) as $item) {
+            $result[$item->find($this->fieldLabel)->getText()] = $item->find($this->errorMessage)->getText();
+        }
+
+        return $result;
+    }
+}
diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Shipping/AddressModal.xml b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Shipping/AddressModal.xml
new file mode 100644
index 0000000000000000000000000000000000000000..13403b792684512c9741bca74a78f7c84036eb48
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Shipping/AddressModal.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" ?>
+<!--
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+-->
+<mapping strict="0">
+    <fields>
+        <firstname />
+        <lastname />
+        <company />
+        <street>
+            <selector>input[name="street[0]"]</selector>
+        </street>
+        <city />
+        <region_id>
+            <input>select</input>
+        </region_id>
+        <country_id>
+            <input>select</input>
+        </country_id>
+        <telephone />
+        <postcode />
+    </fields>
+</mapping>
diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertGrandTotalOrderReview.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertGrandTotalOrderReview.php
index 3bf6bda89ad939ad4ae100006996cf4077e1aeb9..dc1433506f2623d2122f293b063a0707017edc13 100644
--- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertGrandTotalOrderReview.php
+++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertGrandTotalOrderReview.php
@@ -14,6 +14,13 @@ use Magento\Mtf\Constraint\AbstractConstraint;
  */
 class AssertGrandTotalOrderReview extends AbstractConstraint
 {
+    /**
+     * Wait element.
+     *
+     * @var string
+     */
+    protected $waitElement = '.loading-mask';
+
     /**
      * Assert that Order Grand Total is correct on checkoutOnePage
      *
@@ -23,6 +30,7 @@ class AssertGrandTotalOrderReview extends AbstractConstraint
      */
     public function processAssert(CheckoutOnepage $checkoutOnepage, $grandTotal)
     {
+        $checkoutOnepage->getReviewBlock()->waitForElementNotVisible($this->waitElement);
         $checkoutReviewGrandTotal = $checkoutOnepage->getReviewBlock()->getGrandTotal();
 
         \PHPUnit_Framework_Assert::assertEquals(
diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertShippingAddressJsValidationMessagesIsAbsent.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertShippingAddressJsValidationMessagesIsAbsent.php
new file mode 100644
index 0000000000000000000000000000000000000000..f4f46a1c2b7c2577a0f61882f9d707397b1c1a20
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertShippingAddressJsValidationMessagesIsAbsent.php
@@ -0,0 +1,47 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Checkout\Test\Constraint;
+
+use Magento\Checkout\Test\Page\CheckoutOnepage;
+use Magento\Mtf\Constraint\AbstractConstraint;
+
+/**
+ * Class AssertShippingAddressJsValidationMessagesIsAbsent
+ * Assert js validation messages are absent for required fields.
+ */
+class AssertShippingAddressJsValidationMessagesIsAbsent extends AbstractConstraint
+{
+    /**
+     * Assert js validation messages are absent for required fields.
+     *
+     * @param CheckoutOnepage $checkoutOnepage
+     * @return void
+     */
+    public function processAssert(CheckoutOnepage $checkoutOnepage)
+    {
+        $requiredFields = $checkoutOnepage->getShippingBlock()->getRequiredFields();
+
+        /** @var \Magento\Mtf\Client\ElementInterface $field */
+        foreach ($requiredFields as $field) {
+            $errorContainer = $field->find("div .field-error");
+            \PHPUnit_Framework_Assert::assertFalse(
+                $errorContainer->isVisible(),
+                'Js validation error messages must be absent for required fields after checkout start.'
+            );
+        }
+    }
+
+    /**
+     * Returns string representation of successful assertion
+     *
+     * @return string
+     */
+    public function toString()
+    {
+        return 'Js validation messages are absent for required fields.';
+    }
+}
diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/OnePageCheckoutJsValidationTest.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/OnePageCheckoutJsValidationTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..5361ee6e3c127bafc03e53cd717ac067688f826a
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/OnePageCheckoutJsValidationTest.php
@@ -0,0 +1,33 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Checkout\Test\TestCase;
+
+use Magento\Mtf\TestCase\Scenario;
+
+/**
+ * Steps:
+ * 1. Go to Frontend as guest.
+ * 2. Add simple product to shopping cart
+ * 3. Go to shopping cart page
+ * 4. Proceed to checkout
+ * 5. Perform assertions.
+ *
+ * @group One_Page_Checkout
+ * @ZephyrId MAGETWO-59697
+ */
+class OnePageCheckoutJsValidationTest extends Scenario
+{
+    /**
+     * Runs one page checkout js validation test.
+     *
+     * @return void
+     */
+    public function test()
+    {
+        $this->executeScenario();
+    }
+}
diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/OnePageCheckoutJsValidationTest.xml b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/OnePageCheckoutJsValidationTest.xml
new file mode 100644
index 0000000000000000000000000000000000000000..e930ff29882ceed4e8f99947a6a6ef4b4acc1c7a
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/OnePageCheckoutJsValidationTest.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright © 2016 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\Checkout\Test\TestCase\OnePageCheckoutJsValidationTest" summary="JS validation verification for Checkout flow" ticketId="MAGETWO-59697">
+        <variation name="OnePageCheckoutJsValidationTestVariation1" summary="JS validation is not applied for empty required checkout fields if customer did not fill them">
+            <data name="products/0" xsi:type="string">catalogProductSimple::default</data>
+            <data name="checkoutMethod" xsi:type="string">guest</data>
+            <constraint name="Magento\Checkout\Test\Constraint\AssertShippingAddressJsValidationMessagesIsAbsent" />
+        </variation>
+    </testCase>
+</config>
diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/AddNewShippingAddressStep.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/AddNewShippingAddressStep.php
new file mode 100644
index 0000000000000000000000000000000000000000..a4ae00510a9de0b2e9e7d82ff3285e0ae780a7cc
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/AddNewShippingAddressStep.php
@@ -0,0 +1,57 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Checkout\Test\TestStep;
+
+use Magento\Checkout\Test\Page\CheckoutOnepage;
+use Magento\Customer\Test\Fixture\Address;
+use Magento\Mtf\TestStep\TestStepInterface;
+
+/**
+ * Create customer custom attribute step.
+ */
+class AddNewShippingAddressStep implements TestStepInterface
+{
+    /**
+     * Checkout One page.
+     *
+     * @var CheckoutOnepage
+     */
+    private $checkoutOnepage;
+
+    /**
+     * Shipping Address fixture.
+     *
+     * @var Address
+     */
+    private $address;
+
+    /**
+     * @constructor
+     * @param CheckoutOnepage $checkoutOnepage
+     * @param Address|null $address [optional]
+     */
+    public function __construct(CheckoutOnepage $checkoutOnepage, Address $address = null)
+    {
+        $this->checkoutOnepage = $checkoutOnepage;
+        $this->address = $address;
+    }
+
+    /**
+     * Create customer account.
+     *
+     * @return void
+     */
+    public function run()
+    {
+        $shippingBlock = $this->checkoutOnepage->getShippingBlock();
+        $shippingBlock->clickOnNewAddressButton();
+        if ($this->address) {
+            $shippingBlock->getAddressModalBlock()->fill($this->address);
+        }
+        $shippingBlock->getAddressModalBlock()->save();
+    }
+}
diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/etc/testcase.xml b/dev/tests/functional/tests/app/Magento/Checkout/Test/etc/testcase.xml
index a26a2cead49b07a094e550db1207e36d53269b15..24eb96c0a9347741384ffd6718bf349eeb452c85 100644
--- a/dev/tests/functional/tests/app/Magento/Checkout/Test/etc/testcase.xml
+++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/etc/testcase.xml
@@ -22,4 +22,10 @@
         <step name="placeOrder" module="Magento_Checkout" next="createCustomerAccount" />
         <step name="createCustomerAccount" module="Magento_Checkout" />
     </scenario>
+    <scenario name="OnePageCheckoutJsValidationTest" firstStep="setupConfiguration">
+        <step name="setupConfiguration" module="Magento_Config" next="createProducts" />
+        <step name="createProducts" module="Magento_Catalog" next="addProductsToTheCart" />
+        <step name="addProductsToTheCart" module="Magento_Checkout" next="ProceedToCheckout" />
+        <step name="ProceedToCheckout" module="Magento_Checkout" />
+    </scenario>
 </config>
diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertConfigurableProductPage.php b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertConfigurableProductPage.php
index 62d6c72efe8c6aa8d0a8ed4aff4594316318c9e3..ad9807b76d6e532fd00e9f22fac7bf4007a80502 100644
--- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertConfigurableProductPage.php
+++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertConfigurableProductPage.php
@@ -125,15 +125,23 @@ class AssertConfigurableProductPage extends AssertProductPage
     protected function getLowestConfigurablePrice()
     {
         $price = null;
-        $configurableOptions = $this->product->getConfigurableAttributesData();
-
-        foreach ($configurableOptions['matrix'] as $option) {
-            $price = $price === null ? $option['price'] : $price;
-            if ($price > $option['price']) {
-                $price = $option['price'];
+        $priceDataConfig = $this->product->getDataFieldConfig('price');
+        if (isset($priceDataConfig['source'])) {
+            $priceData = $priceDataConfig['source']->getPriceData();
+            if (isset($priceData['price_from'])) {
+                $price = $priceData['price_from'];
             }
         }
 
+        if (null === $price) {
+            $configurableOptions = $this->product->getConfigurableAttributesData();
+            foreach ($configurableOptions['matrix'] as $option) {
+                $price = $price === null ? $option['price'] : $price;
+                if ($price > $option['price']) {
+                    $price = $option['price'];
+                }
+            }
+        }
         return $price;
     }
 }
diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigurableProduct/Price.xml b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigurableProduct/Price.xml
index 2e9d708dd42d82ca79d0507b6a698c0c5c897d3b..1b6282b9432c39fd444ca2089f1b8c8aa6bfb876 100644
--- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigurableProduct/Price.xml
+++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigurableProduct/Price.xml
@@ -17,5 +17,8 @@
         <dataset name="MAGETWO-12620">
             <field name="category_price" xsi:type="string">11</field>
         </dataset>
+        <dataset name="from-9">
+            <field name="price_from" xsi:type="string">9</field>
+        </dataset>
     </repository>
 </config>
diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/CreateConfigurableProductEntityTest.xml b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/CreateConfigurableProductEntityTest.xml
index 58435b066261ed28cc7f33ff01fc250940b6eb17..187283da4602fd56c6fb6f2441d11dc5c1ad05bd 100644
--- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/CreateConfigurableProductEntityTest.xml
+++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/CreateConfigurableProductEntityTest.xml
@@ -58,6 +58,7 @@
             <data name="product/data/checkout_data/dataset" xsi:type="string">configurable_two_new_options_with_special_price</data>
             <data name="product/data/name" xsi:type="string">Configurable Product %isolation%</data>
             <data name="product/data/sku" xsi:type="string">configurable_sku_%isolation%</data>
+            <data name="product/data/price/dataset" xsi:type="string">from-9</data>
             <data name="product/data/price/value" xsi:type="string">100</data>
             <data name="product/data/special_price" xsi:type="string">9</data>
             <data name="product/data/short_description" xsi:type="string">Configurable short description</data>
diff --git a/dev/tests/functional/tests/app/Magento/Install/Test/Block/WebConfiguration.php b/dev/tests/functional/tests/app/Magento/Install/Test/Block/WebConfiguration.php
index 03dbfee05ca6973d90da4a4205eb1b64f9f2edca..bf4886a9f208d4a9bf308ee8f5f8b26daf9c6d6e 100644
--- a/dev/tests/functional/tests/app/Magento/Install/Test/Block/WebConfiguration.php
+++ b/dev/tests/functional/tests/app/Magento/Install/Test/Block/WebConfiguration.php
@@ -21,7 +21,7 @@ class WebConfiguration extends Form
      *
      * @var string
      */
-    protected $next = "[ng-click*='next']";
+    protected $next = "[ng-click*='validateUrl']";
 
     /**
      * 'Advanced Options' locator.
diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/System/Config/ExpressCheckout.php b/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/System/Config/ExpressCheckout.php
index d83ae0c53ec0a575ba11280b9a8731bbe23a6f8a..6e4849669568851cbe4787766c6cf8b2f630e9e6 100644
--- a/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/System/Config/ExpressCheckout.php
+++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/System/Config/ExpressCheckout.php
@@ -20,8 +20,6 @@ class ExpressCheckout extends Block
      * @var array
      */
     private $fields = [
-        'Email Associated with PayPal Merchant Account' => '#payment_us_paypal_alternative_payment_methods_express_' .
-            'checkout_us_express_checkout_required_express_checkout_required_express_checkout_business_account',
         'API Username' => '#payment_us_paypal_alternative_payment_methods_express_checkout_us_express_checkout_' .
             'required_express_checkout_required_express_checkout_api_username',
         'API Password' => '#payment_us_paypal_alternative_payment_methods_express_checkout_us_express_checkout_' .
@@ -72,8 +70,6 @@ class ExpressCheckout extends Block
      */
     public function specifyCredentials()
     {
-        $this->_rootElement->find($this->fields['Email Associated with PayPal Merchant Account'])
-            ->setValue('test@test.com');
         $this->_rootElement->find($this->fields['API Username'])->setValue('1');
         $this->_rootElement->find($this->fields['API Password'])->setValue('1');
         $this->_rootElement->find($this->fields['API Signature'])->setValue('1');
@@ -86,7 +82,6 @@ class ExpressCheckout extends Block
      */
     public function clearCredentials()
     {
-        $this->_rootElement->find($this->fields['Email Associated with PayPal Merchant Account'])->setValue('');
         $this->_rootElement->find($this->fields['API Username'])->setValue('');
         $this->_rootElement->find($this->fields['API Password'])->setValue('');
         $this->_rootElement->find($this->fields['API Signature'])->setValue('');
diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/System/Config/PayflowLink.php b/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/System/Config/PayflowLink.php
index de6eb107c61ce5e6b63451abdea0473351ddde43..f1af6acb6174e1b462651b7887d80159d6910952 100644
--- a/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/System/Config/PayflowLink.php
+++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/System/Config/PayflowLink.php
@@ -20,8 +20,6 @@ class PayflowLink extends Block
      * @var array
      */
     private $fields = [
-        'Email Associated with PayPal Merchant Account' => '#payment_us_paypal_payment_gateways_payflow_link_us_' .
-            'payflow_link_required_payflow_link_payflow_link_business_account',
         'Partner' => '#payment_us_paypal_payment_gateways_payflow_link_us_payflow_link_required_payflow_link_payflow_' .
             'link_partner',
         'Vendor' => '#payment_us_paypal_payment_gateways_payflow_link_us_payflow_link_required_payflow_link_payflow_' .
@@ -60,8 +58,6 @@ class PayflowLink extends Block
      */
     public function specifyCredentials()
     {
-        $this->_rootElement->find($this->fields['Email Associated with PayPal Merchant Account'])
-            ->setValue('test@test.com');
         $this->_rootElement->find($this->fields['Partner'])->setValue('1');
         $this->_rootElement->find($this->fields['Vendor'])->setValue('1');
         $this->_rootElement->find($this->fields['User'])->setValue('1');
@@ -75,7 +71,6 @@ class PayflowLink extends Block
      */
     public function clearCredentials()
     {
-        $this->_rootElement->find($this->fields['Email Associated with PayPal Merchant Account'])->setValue('');
         $this->_rootElement->find($this->fields['Partner'])->setValue('');
         $this->_rootElement->find($this->fields['Vendor'])->setValue('');
         $this->_rootElement->find($this->fields['User'])->setValue('');
diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/System/Config/PayflowPro.php b/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/System/Config/PayflowPro.php
index e3b01aa3af9a0dfa4517ad3fe4b527eec9d30ad0..1db07ac435a37ed9c9d9d237f62b7debed956861 100644
--- a/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/System/Config/PayflowPro.php
+++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/System/Config/PayflowPro.php
@@ -20,8 +20,6 @@ class PayflowPro extends Block
      * @var array
      */
     private $fields = [
-        'Email Associated with PayPal Merchant Account' => '#payment_us_paypal_payment_gateways_paypal_payflowpro_' .
-            'with_express_checkout_paypal_payflow_required_paypal_payflow_api_settings_business_account',
         'Partner' => '#payment_us_paypal_payment_gateways_paypal_payflowpro_with_express_checkout_paypal_payflow_' .
             'required_paypal_payflow_api_settings_partner',
         'Vendor' => '#payment_us_paypal_payment_gateways_paypal_payflowpro_with_express_checkout_paypal_payflow_' .
@@ -60,8 +58,6 @@ class PayflowPro extends Block
      */
     public function specifyCredentials()
     {
-        $this->_rootElement->find($this->fields['Email Associated with PayPal Merchant Account'])
-            ->setValue('test@test.com');
         $this->_rootElement->find($this->fields['Partner'])->setValue('1');
         $this->_rootElement->find($this->fields['Vendor'])->setValue('1');
         $this->_rootElement->find($this->fields['User'])->setValue('1');
@@ -75,7 +71,6 @@ class PayflowPro extends Block
      */
     public function clearCredentials()
     {
-        $this->_rootElement->find($this->fields['Email Associated with PayPal Merchant Account'])->setValue('');
         $this->_rootElement->find($this->fields['Partner'])->setValue('');
         $this->_rootElement->find($this->fields['Vendor'])->setValue('');
         $this->_rootElement->find($this->fields['User'])->setValue('');
diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/System/Config/PaymentsAdvanced.php b/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/System/Config/PaymentsAdvanced.php
index cd6d1a5b1b38a016382ffa2e68ab73bd566c4116..87adb729a1646e6eb5b61e8e167d2eed20111e4e 100644
--- a/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/System/Config/PaymentsAdvanced.php
+++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/System/Config/PaymentsAdvanced.php
@@ -20,8 +20,6 @@ class PaymentsAdvanced extends Block
      * @var array
      */
     private $fields = [
-        'Email Associated with PayPal Merchant Account' => '#payment_us_paypal_group_all_in_one_payflow_advanced_' .
-            'required_settings_payments_advanced_business_account',
         'Partner' => '#payment_us_paypal_group_all_in_one_payflow_advanced_required_settings_payments_advanced_partner',
         'Vendor' => '#payment_us_paypal_group_all_in_one_payflow_advanced_required_settings_payments_advanced_vendor',
         'User' => '#payment_us_paypal_group_all_in_one_payflow_advanced_required_settings_payments_advanced_user',
@@ -54,8 +52,6 @@ class PaymentsAdvanced extends Block
      */
     public function specifyCredentials()
     {
-        $this->_rootElement->find($this->fields['Email Associated with PayPal Merchant Account'])
-            ->setValue('test@test.com');
         $this->_rootElement->find($this->fields['Partner'])->setValue('1');
         $this->_rootElement->find($this->fields['Vendor'])->setValue('1');
         $this->_rootElement->find($this->fields['User'])->setValue('1');
@@ -69,7 +65,6 @@ class PaymentsAdvanced extends Block
      */
     public function clearCredentials()
     {
-        $this->_rootElement->find($this->fields['Email Associated with PayPal Merchant Account'])->setValue('');
         $this->_rootElement->find($this->fields['Partner'])->setValue('');
         $this->_rootElement->find($this->fields['Vendor'])->setValue('');
         $this->_rootElement->find($this->fields['User'])->setValue('');
diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/System/Config/PaymentsPro.php b/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/System/Config/PaymentsPro.php
index cd146aa8f809cf5de0cbddcb02be83a19e59928f..55fd7444ba50ad8dbf9662b758b10d7a70ee6c6d 100644
--- a/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/System/Config/PaymentsPro.php
+++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/System/Config/PaymentsPro.php
@@ -20,8 +20,6 @@ class PaymentsPro extends Block
      * @var array
      */
     private $fields = [
-        'Email Associated with PayPal Merchant Account' => '#payment_us_paypal_group_all_in_one_wpp_usuk_paypal_' .
-            'payflow_required_paypal_payflow_api_settings_business_account',
         'Partner' => '#payment_us_paypal_group_all_in_one_wpp_usuk_paypal_payflow_required_paypal_payflow_api_' .
             'settings_partner',
         'Vendor' => '#payment_us_paypal_group_all_in_one_wpp_usuk_paypal_payflow_required_paypal_payflow_api_' .
@@ -60,8 +58,6 @@ class PaymentsPro extends Block
      */
     public function specifyCredentials()
     {
-        $this->_rootElement->find($this->fields['Email Associated with PayPal Merchant Account'])
-            ->setValue('test@test.com');
         $this->_rootElement->find($this->fields['Partner'])->setValue('1');
         $this->_rootElement->find($this->fields['Vendor'])->setValue('1');
         $this->_rootElement->find($this->fields['User'])->setValue('1');
@@ -75,7 +71,6 @@ class PaymentsPro extends Block
      */
     public function clearCredentials()
     {
-        $this->_rootElement->find($this->fields['Email Associated with PayPal Merchant Account'])->setValue('');
         $this->_rootElement->find($this->fields['Partner'])->setValue('');
         $this->_rootElement->find($this->fields['Vendor'])->setValue('');
         $this->_rootElement->find($this->fields['User'])->setValue('');
diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/CreateVaultOrderBackendTest.xml b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/CreateVaultOrderBackendTest.xml
index 38666c36a2ba4e53641f45616060353ca5e5e22c..ca26ad42a020c80ab0540c21a2928b8a1874cae7 100644
--- a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/CreateVaultOrderBackendTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/CreateVaultOrderBackendTest.xml
@@ -19,6 +19,7 @@
                 <item name="grandTotal" xsi:type="string">15.00</item>
             </data>
             <data name="payment/method" xsi:type="string">payflowpro</data>
+            <data name="vault/method" xsi:type="string">payflowpro_cc_vault</data>
             <data name="creditCardClass" xsi:type="string">credit_card_admin</data>
             <data name="creditCard/dataset" xsi:type="string">visa_default</data>
             <data name="creditCardSave" xsi:type="string">Yes</data>
diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/ReorderUsingVaultTest.xml b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/ReorderUsingVaultTest.xml
index c33abb1dbdd2263fded6dbbfb0f683848a3bdd3f..b1da43e473bc5d78d4bfaf0fbcbb718dac6acd3e 100644
--- a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/ReorderUsingVaultTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/ReorderUsingVaultTest.xml
@@ -19,6 +19,7 @@
                 <item name="grandTotal" xsi:type="string">15.00</item>
             </data>
             <data name="payment/method" xsi:type="string">payflowpro</data>
+            <data name="vault/method" xsi:type="string">payflowpro_cc_vault</data>
             <data name="creditCardClass" xsi:type="string">credit_card</data>
             <data name="creditCard/dataset" xsi:type="string">visa_default</data>
             <data name="configData" xsi:type="string">payflowpro, payflowpro_use_vault</data>
diff --git a/dev/tests/functional/tests/app/Magento/SalesRule/Test/Constraint/AssertCartPriceRuleForm.php b/dev/tests/functional/tests/app/Magento/SalesRule/Test/Constraint/AssertCartPriceRuleForm.php
index bfe0bc9eabddfb0cc0f746f79efdad5b6ad0a43b..1f3f0e5a300b46ac9a193666796e52c584b8c944 100644
--- a/dev/tests/functional/tests/app/Magento/SalesRule/Test/Constraint/AssertCartPriceRuleForm.php
+++ b/dev/tests/functional/tests/app/Magento/SalesRule/Test/Constraint/AssertCartPriceRuleForm.php
@@ -25,8 +25,6 @@ class AssertCartPriceRuleForm extends AbstractConstraint
     protected $skippedFields = [
         'conditions_serialized',
         'actions_serialized',
-        'from_date',
-        'to_date',
         'rule_id'
     ];
 
diff --git a/dev/tests/functional/tests/app/Magento/SalesRule/Test/Handler/SalesRule/Curl.php b/dev/tests/functional/tests/app/Magento/SalesRule/Test/Handler/SalesRule/Curl.php
index 5ab10a0e26f79fcded0b42c77562b077cf0b5412..310f52f75e2cf124e07ab1d7d4bf431e48759e8d 100644
--- a/dev/tests/functional/tests/app/Magento/SalesRule/Test/Handler/SalesRule/Curl.php
+++ b/dev/tests/functional/tests/app/Magento/SalesRule/Test/Handler/SalesRule/Curl.php
@@ -70,6 +70,10 @@ class Curl extends Conditions implements SalesRuleInterface
             'type' => \Magento\SalesRule\Model\Rule\Condition\Address::class,
             'attribute' => 'postcode',
         ],
+        'Total Weight' => [
+            'type' => \Magento\SalesRule\Model\Rule\Condition\Address::class,
+            'attribute' => 'weight',
+        ],
         'Category' => [
             'type' => \Magento\SalesRule\Model\Rule\Condition\Product::class,
             'attribute' => 'category_ids',
diff --git a/dev/tests/functional/tests/app/Magento/SalesRule/Test/Repository/SalesRule.xml b/dev/tests/functional/tests/app/Magento/SalesRule/Test/Repository/SalesRule.xml
index 010b9d3233d163f6ec35ed4291bebbe352bbe9c4..3a35215d841d50780d212084d76d014af8708aa4 100644
--- a/dev/tests/functional/tests/app/Magento/SalesRule/Test/Repository/SalesRule.xml
+++ b/dev/tests/functional/tests/app/Magento/SalesRule/Test/Repository/SalesRule.xml
@@ -114,10 +114,10 @@
             <field name="uses_per_coupon" xsi:type="string">13</field>
             <field name="uses_per_customer" xsi:type="string">63</field>
             <field name="from_date" xsi:type="array">
-                <item name="pattern" xsi:type="string">3/25/2014</item>
+                <item name="pattern" xsi:type="string">03/25/2014</item>
             </field>
             <field name="to_date" xsi:type="array">
-                <item name="pattern" xsi:type="string">6/29/2024</item>
+                <item name="pattern" xsi:type="string">-</item>
             </field>
             <field name="sort_order" xsi:type="string">1</field>
             <field name="is_rss" xsi:type="string">Yes</field>
@@ -279,5 +279,24 @@
             <field name="stop_rules_processing" xsi:type="string">No</field>
             <field name="simple_free_shipping" xsi:type="string">No</field>
         </dataset>
+        <dataset name="rule_with_freeshipping_by_weight">
+            <field name="name" xsi:type="string">Cart price rule with free shipping by weight</field>
+            <field name="is_active" xsi:type="string">Yes</field>
+            <field name="website_ids" xsi:type="array">
+                <item name="0" xsi:type="string">Main Website</item>
+            </field>
+            <field name="customer_group_ids" xsi:type="array">
+                <item name="0" xsi:type="string">NOT LOGGED IN</item>
+            </field>
+            <field name="coupon_type" xsi:type="string">No Coupon</field>
+            <field name="sort_order" xsi:type="string">1</field>
+            <field name="is_rss" xsi:type="string">Yes</field>
+            <field name="conditions_serialized" xsi:type="string">[Total Weight|is|1]</field>
+            <field name="simple_action" xsi:type="string">Percent of product price discount</field>
+            <field name="discount_amount" xsi:type="string">0</field>
+            <field name="apply_to_shipping" xsi:type="string">No</field>
+            <field name="stop_rules_processing" xsi:type="string">No</field>
+            <field name="simple_free_shipping" xsi:type="string">For matching items only</field>
+        </dataset>
     </repository>
 </config>
diff --git a/dev/tests/functional/tests/app/Magento/SalesRule/Test/TestCase/ShoppingCartWithFreeShippingTest.php b/dev/tests/functional/tests/app/Magento/SalesRule/Test/TestCase/ShoppingCartWithFreeShippingTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..11e510759fdcc5aa4c9368e61c3f5373d32dd9bb
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/SalesRule/Test/TestCase/ShoppingCartWithFreeShippingTest.php
@@ -0,0 +1,77 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\SalesRule\Test\TestCase;
+
+/**
+ * Precondition:
+ * 1. Cart Price Rule was created.
+ *
+ * Steps:
+ * 1. Go to storefront
+ * 2. Add product to shopping cart
+ * 3. Go to shopping cart page
+ * 4. Perform asserts.
+ *
+ * @group Shopping_Cart_Price_Rules
+ * @ZephyrId MAGETWO-59665
+ */
+class ShoppingCartWithFreeShippingTest extends \Magento\Mtf\TestCase\Injectable
+{
+    /**
+     * @var \Magento\Mtf\TestStep\TestStepFactory
+     */
+    private $testStepFactory;
+
+    /**
+     * Inject data
+     *
+     * @param \Magento\Mtf\TestStep\TestStepFactory $testStepFactory
+     * @return void
+     */
+    public function __inject(
+        \Magento\Mtf\TestStep\TestStepFactory $testStepFactory
+    ) {
+        $this->testStepFactory = $testStepFactory;
+    }
+
+    /**
+     * Test sales rule with free shipping applied by product weight
+     *
+     * @param \Magento\SalesRule\Test\Fixture\SalesRule $salesRule
+     * @param \Magento\Catalog\Test\Fixture\CatalogProductSimple $product
+     * @param \Magento\Checkout\Test\Fixture\Cart $cart
+     * @return void
+     */
+    public function testRuleWithFreeShippingByWeight(
+        \Magento\SalesRule\Test\Fixture\SalesRule $salesRule,
+        \Magento\Catalog\Test\Fixture\CatalogProductSimple $product,
+        \Magento\Checkout\Test\Fixture\Cart $cart
+    ) {
+        $salesRule->persist();
+        $product->persist();
+
+        $this->testStepFactory->create(
+            \Magento\Checkout\Test\TestStep\AddProductsToTheCartStep::class,
+            ['products' => [$product]]
+        )->run();
+
+        $this->testStepFactory->create(
+            \Magento\Checkout\Test\TestStep\EstimateShippingAndTaxStep::class,
+            ['products' => [$product], 'cart' => $cart]
+        )->run();
+    }
+
+    /**
+     * Clear data after test.
+     *
+     * @return void
+     */
+    public function tearDown()
+    {
+        $this->testStepFactory->create(\Magento\SalesRule\Test\TestStep\DeleteAllSalesRuleStep::class)->run();
+    }
+}
diff --git a/dev/tests/functional/tests/app/Magento/SalesRule/Test/TestCase/ShoppingCartWithFreeShippingTest.xml b/dev/tests/functional/tests/app/Magento/SalesRule/Test/TestCase/ShoppingCartWithFreeShippingTest.xml
new file mode 100644
index 0000000000000000000000000000000000000000..7391d2281f8094b059cfaf9d26115c371d9498b0
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/SalesRule/Test/TestCase/ShoppingCartWithFreeShippingTest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright © 2016 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\SalesRule\Test\TestCase\ShoppingCartWithFreeShippingTest" summary="Shopping Cart With Freeshipping" ticketId="MAGETWO-59665">
+        <variation name="ShoppingCartWithFreeShippingTestVariation1">
+            <data name="salesRule/dataset" xsi:type="string">rule_with_freeshipping_by_weight</data>
+            <data name="product/dataset" xsi:type="string">default</data>
+            <data name="cart/data/subtotal" xsi:type="string">560.00</data>
+            <data name="cart/data/shipping_amount" xsi:type="string">0.00</data>
+            <data name="cart/data/grand_total" xsi:type="string">560.00</data>
+        </variation>
+        <variation name="ShoppingCartWithFreeShippingTestVariation2">
+            <data name="salesRule/dataset" xsi:type="string">rule_with_freeshipping_by_weight</data>
+            <data name="product/dataset" xsi:type="string">simple_with_weight_10_for_salesrule</data>
+            <data name="cart/data/subtotal" xsi:type="string">560.00</data>
+            <data name="cart/data/shipping_amount" xsi:type="string">5.00</data>
+            <data name="cart/data/grand_total" xsi:type="string">565.00</data>
+        </variation>
+    </testCase>
+</config>
diff --git a/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockAdminUserWhenCreatingNewUserTest.php b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockAdminUserWhenCreatingNewUserTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..4b42430c0b8a81987b78d907f8b4a4c56d6db834
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockAdminUserWhenCreatingNewUserTest.php
@@ -0,0 +1,134 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Security\Test\TestCase;
+
+
+use Magento\User\Test\Page\Adminhtml\UserEdit;
+use Magento\User\Test\Page\Adminhtml\UserIndex;
+use Magento\Mtf\TestCase\Injectable;
+use Magento\User\Test\Fixture\User;
+use Magento\Backend\Test\Page\AdminAuthLogin;
+
+/**
+ * Preconditions:
+ * 1. Create admin user.
+ * 2. Configure 'Maximum Login Failures to Lockout Account'.
+ *
+ * Steps:
+ * 1. Log in to backend as admin user.
+ * 2. Navigate to System > All Users.
+ * 3. Click on Add New User.
+ * 4. Fill in all data according to data set (password is incorrect).
+ * 5. Perform action 4 specified number of times.
+ * 6. "You have entered an invalid password for current user." appears after each attempt.
+ * 7. Perform all assertions.
+ *
+ * @ZephyrId MAGETWO-49034
+ */
+class LockAdminUserWhenCreatingNewUserTest extends Injectable
+{
+    /* tags */
+    const MVP = 'yes';
+    const SEVERITY = 'S2';
+    /* end tags */
+
+    /**
+     * User grid page
+     *
+     * @var UserIndex
+     */
+    protected $userIndexPage;
+
+    /**
+     * User new/edit page
+     *
+     * @var UserEdit
+     */
+    protected $userEditPage;
+
+    /**
+     * Configuration setting.
+     *
+     * @var string
+     */
+    protected $configData;
+
+    /**
+     * @var AdminAuthLogin page
+     */
+    protected $adminAuthLogin;
+
+    /**
+     * Setup data for test.
+     * @param UserIndex $userIndex
+     * @param UserEdit $userEdit
+     * @param AdminAuthLogin $adminAuthLogin
+     */
+    public function __inject(
+        UserIndex $userIndex,
+        UserEdit $userEdit,
+        AdminAuthLogin $adminAuthLogin
+    ) {
+        $this->userIndexPage = $userIndex;
+        $this->userEditPage = $userEdit;
+        $this->adminAuthLogin = $adminAuthLogin;
+    }
+
+    /**
+     * Runs Lock admin user when creating new user test.
+     *
+     * @param int $attempts
+     * @param User $customAdmin,
+     * @param User $user,
+     * @param string $configData
+     * @return void
+     */
+    public function test(
+        $attempts,
+        User $customAdmin,
+        User $user,
+        $configData
+    ) {
+        $this->configData = $configData;
+
+        // Preconditions
+        $this->objectManager->create(
+            \Magento\Config\Test\TestStep\SetupConfigurationStep::class,
+            ['configData' => $this->configData]
+        )->run();
+        $customAdmin->persist();
+
+        // Steps
+        $this->adminAuthLogin->open();
+        $this->adminAuthLogin->getLoginBlock()->fill($customAdmin);
+        $this->adminAuthLogin->getLoginBlock()->submit();
+        $this->userIndexPage->open();
+        $this->userIndexPage->getPageActions()->addNew();
+        for ($i = 0; $i < $attempts; $i++) {
+            $this->userEditPage->getUserForm()->fill($user);
+            $this->userEditPage->getPageActions()->save();
+        }
+
+        // Reload
+        $this->adminAuthLogin->open();
+        $this->adminAuthLogin->getLoginBlock()->fill($customAdmin);
+        $this->adminAuthLogin->getLoginBlock()->submit();
+    }
+
+    /**
+     * Clean data after running test.
+     *
+     * @return void
+     */
+    public function tearDown()
+    {
+        $this->objectManager->create(
+            \Magento\Config\Test\TestStep\SetupConfigurationStep::class,
+            ['configData' => $this->configData, 'rollback' => true]
+        )->run();
+    }
+}
diff --git a/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockAdminUserWhenCreatingNewUserTest.xml b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockAdminUserWhenCreatingNewUserTest.xml
new file mode 100644
index 0000000000000000000000000000000000000000..e36f8b4625dd66eeb5a41f15c74c4bdf6e7eeeea
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockAdminUserWhenCreatingNewUserTest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright © 2016 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\Security\Test\TestCase\LockAdminUserWhenCreatingNewUserTest" summary="Lock admin user after entering incorrect password while creating new User">
+        <variation name="LockAdminUserWhenCreatingNewUserTestVariation1">
+            <data name="configData" xsi:type="string">user_lockout_failures</data>
+            <data name="tag" xsi:type="string">severity:S2</data>
+            <data name="customAdmin/dataset" xsi:type="string">custom_admin_with_default_role</data>
+            <data name="user/data/username" xsi:type="string">AdminUser%isolation%</data>
+            <data name="user/data/firstname" xsi:type="string">FirstName%isolation%</data>
+            <data name="user/data/lastname" xsi:type="string">LastName%isolation%</data>
+            <data name="user/data/email" xsi:type="string">email%isolation%@example.com</data>
+            <data name="user/data/password" xsi:type="string">123123q</data>
+            <data name="user/data/password_confirmation" xsi:type="string">123123q</data>
+            <data name="user/data/current_password" xsi:type="string">incorrect password</data>
+            <data name="attempts" xsi:type="string">4</data>
+            <constraint name="Magento\Security\Test\Constraint\AssertUserIsLocked" />
+        </variation>
+    </testCase>
+</config>
diff --git a/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockAdminUserWhenEditingIntegrationTest.php b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockAdminUserWhenEditingIntegrationTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..4a1c1d0507c91ea3b9a86d254f6f2c01d58a7d2d
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockAdminUserWhenEditingIntegrationTest.php
@@ -0,0 +1,143 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Security\Test\TestCase;
+
+use Magento\Integration\Test\Fixture\Integration;
+use Magento\User\Test\Fixture\User;
+use Magento\Integration\Test\Page\Adminhtml\IntegrationIndex;
+use Magento\Integration\Test\Page\Adminhtml\IntegrationNew;
+use Magento\Mtf\TestCase\Injectable;
+use Magento\Backend\Test\Page\AdminAuthLogin;
+
+/**
+ * Preconditions:
+ * 1. Create admin user.
+ * 2. Create integration.
+ * 3. Configure 'Maximum Login Failures to Lockout Account'.
+ *
+ * Steps:
+ * 1. Log in to backend as admin user.
+ * 2. Navigate to System > Extensions > Integrations.
+ * 3. Start to edit existing Integration.
+ * 4. Fill in all data according to data set (password is incorrect).
+ * 5. Perform action 4 specified number of times.
+ * 6. "You have entered an invalid password for current user." appears after each attempt.
+ * 7. Perform all assertions.
+ *
+ * @ZephyrId MAGETWO-49039
+ */
+class LockAdminUserWhenEditingIntegrationTest extends Injectable
+{
+    /* tags */
+    const MVP = 'yes';
+    const SEVERITY = 'S2';
+    /* end tags */
+
+    /**
+     * Integration grid page.
+     *
+     * @var IntegrationIndex
+     */
+    protected $integrationIndexPage;
+
+    /**
+     * Integration new page.
+     *
+     * @var IntegrationNew
+     */
+    protected $integrationNewPage;
+
+    /**
+     * Configuration setting.
+     *
+     * @var string
+     */
+    protected $configData;
+
+    /**
+     * @var AdminAuthLogin
+     */
+    protected $adminAuthLogin;
+
+    /**
+     * Preparing pages for test.
+     *
+     * @param IntegrationIndex $integrationIndex
+     * @param IntegrationNew $integrationNew
+     * @param AdminAuthLogin $adminAuthLogin
+     * @return void
+     */
+    public function __inject(
+        IntegrationIndex $integrationIndex,
+        IntegrationNew $integrationNew,
+        AdminAuthLogin $adminAuthLogin
+    ) {
+        $this->integrationIndexPage = $integrationIndex;
+        $this->integrationNewPage = $integrationNew;
+        $this->adminAuthLogin = $adminAuthLogin;
+    }
+
+    /**
+     * Run Lock user when creating new integration test.
+     *
+     * @param Integration $initintegration
+     * @param Integration $integration
+     * @param int $attempts
+     * @param User $customAdmin
+     * @param string $configData
+     * @return void
+     */
+    public function test(
+        Integration $initintegration,
+        Integration $integration,
+        $attempts,
+        User $customAdmin,
+        $configData
+    ) {
+        $this->configData = $configData;
+
+        // Preconditions
+        $this->objectManager->create(
+            \Magento\Config\Test\TestStep\SetupConfigurationStep::class,
+            ['configData' => $this->configData]
+        )->run();
+        $customAdmin->persist();
+        $initintegration->persist();
+
+        // login to backend with new user
+        $this->adminAuthLogin->open();
+        $this->adminAuthLogin->getLoginBlock()->fill($customAdmin);
+        $this->adminAuthLogin->getLoginBlock()->submit();
+
+        // Steps
+        $filter = ['name' => $initintegration->getName()];
+        $this->integrationIndexPage->open();
+        $this->integrationIndexPage->getIntegrationGrid()->searchAndOpen($filter);
+        for ($i = 0; $i < $attempts; $i++) {
+            $this->integrationNewPage->getIntegrationForm()->fill($integration);
+            $this->integrationNewPage->getFormPageActions()->save();
+        }
+
+        // Reload page
+        $this->adminAuthLogin->open();
+        $this->adminAuthLogin->getLoginBlock()->fill($customAdmin);
+        $this->adminAuthLogin->getLoginBlock()->submit();
+    }
+
+    /**
+     * Clean data after running test.
+     *
+     * @return void
+     */
+    public function tearDown()
+    {
+        $this->objectManager->create(
+            \Magento\Config\Test\TestStep\SetupConfigurationStep::class,
+            ['configData' => $this->configData, 'rollback' => true]
+        )->run();
+    }
+}
diff --git a/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockAdminUserWhenEditingIntegrationTest.xml b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockAdminUserWhenEditingIntegrationTest.xml
new file mode 100644
index 0000000000000000000000000000000000000000..6efc88d78cd3836f00db79d2c567d3e6e38d1bb1
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockAdminUserWhenEditingIntegrationTest.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright © 2016 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\Security\Test\TestCase\LockAdminUserWhenEditingIntegrationTest" summary="Lock admin user after entering incorrect password while editing integration">
+        <variation name="LockAdminUserWhenCreatingNewIntegrationTestVariation1">
+            <data name="configData" xsi:type="string">user_lockout_failures</data>
+            <data name="tag" xsi:type="string">severity:S2</data>
+            <data name="customAdmin/dataset" xsi:type="string">custom_admin_with_default_role</data>
+            <data name="initintegration/dataset" xsi:type="string">default_active</data>
+            <data name="integration/data/name" xsi:type="string">Integration%isolation%</data>
+            <data name="integration/data/current_password" xsi:type="string">incorrect password</data>
+            <data name="attempts" xsi:type="string">4</data>
+            <constraint name="Magento\Security\Test\Constraint\AssertUserIsLocked" />
+        </variation>
+    </testCase>
+</config>
\ No newline at end of file
diff --git a/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockAdminUserWhenEditingRoleTest.php b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockAdminUserWhenEditingRoleTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..bd7c8cef92d8a320b43615983a95ea724cce0d78
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockAdminUserWhenEditingRoleTest.php
@@ -0,0 +1,140 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Security\Test\TestCase;
+
+use Magento\User\Test\Page\Adminhtml\UserRoleEditRole;
+use Magento\User\Test\Page\Adminhtml\UserRoleIndex;
+use Magento\Mtf\TestCase\Injectable;
+use Magento\User\Test\Fixture\User;
+use Magento\User\Test\Fixture\Role;
+use Magento\Backend\Test\Page\AdminAuthLogin;
+
+/**
+ * Preconditions:
+ * 1. Create new admin user and assign it to new role.
+ * 2. Configure 'Maximum Login Failures to Lockout Account'.
+ *
+ * Steps:
+ * 1. Log in to backend as new created admin user.
+ * 2. Navigate to System > User Roles.
+ * 3. Start editing existing User Role.
+ * 4. Fill in all data according to data set (password is incorrect).
+ * 5. Perform action 4 specified number of times.
+ * 6. Admin account is locked.
+ * 7. Perform all assertions.
+ *
+ * @ZephyrId MAGETWO-49037
+ * @Group Security
+ *
+ */
+class LockAdminUserWhenEditingRoleTest extends Injectable
+{
+    /* tags */
+    const MVP = 'yes';
+    const SEVERITY = 'S2';
+    /* end tags */
+
+    /**
+     * UserRoleIndex page.
+     *
+     * @var UserRoleIndex
+     */
+    protected $userRoleIndex;
+
+    /**
+     * UserRoleEditRole page.
+     *
+     * @var UserRoleEditRole
+     */
+    protected $userRoleEditRole;
+
+    /**
+     * Configuration setting.
+     *
+     * @var string
+     */
+    protected $configData;
+
+    /**
+     * Admin login Page.
+     *
+     * @var AdminAuthLogin
+     */
+    protected $adminAuthLogin;
+
+    /**
+     * Setup data for test.
+     *
+     * @param UserRoleIndex $userRoleIndex
+     * @param UserRoleEditRole $userRoleEditRole
+     * @param AdminAuthLogin $adminAuthLogin
+     * @return void
+     */
+    public function __inject(
+        UserRoleIndex $userRoleIndex,
+        UserRoleEditRole $userRoleEditRole,
+        AdminAuthLogin $adminAuthLogin
+    ) {
+        $this->userRoleIndex = $userRoleIndex;
+        $this->userRoleEditRole = $userRoleEditRole;
+        $this->adminAuthLogin = $adminAuthLogin;
+    }
+
+    /**
+     * Runs Lock admin user when editing existing role test.
+     *
+     * @param Role $role
+     * @param Role $initrole
+     * @param int $attempts
+     * @param User $customAdmin
+     * @param string $configData
+     * @return void
+     */
+    public function test(
+        Role $role,
+        Role $initrole,
+        $attempts,
+        User $customAdmin,
+        $configData
+    ) {
+        $this->configData = $configData;
+        // Preconditions
+        $this->objectManager->create(
+            \Magento\Config\Test\TestStep\SetupConfigurationStep::class,
+            ['configData' => $this->configData]
+        )->run();
+        $customAdmin->persist();
+        $initrole->persist();
+        // Steps login to backend with new user
+        $this->adminAuthLogin->open();
+        $this->adminAuthLogin->getLoginBlock()->fill($customAdmin);
+        $this->adminAuthLogin->getLoginBlock()->submit();
+        $filter = ['rolename' => $initrole->getRolename()];
+        $this->userRoleIndex->open();
+        $this->userRoleIndex->getRoleGrid()->searchAndOpen($filter);
+        for ($i = 0; $i < $attempts; $i++) {
+            $this->userRoleEditRole->getRoleFormTabs()->fill($role);
+            $this->userRoleEditRole->getPageActions()->save();
+        }
+        // Reload
+        $this->adminAuthLogin->open();
+        $this->adminAuthLogin->getLoginBlock()->fill($customAdmin);
+        $this->adminAuthLogin->getLoginBlock()->submit();
+    }
+
+    /**
+     * Clean data after running test.
+     *
+     * @return void
+     */
+    public function tearDown()
+    {
+        $this->objectManager->create(
+            \Magento\Config\Test\TestStep\SetupConfigurationStep::class,
+            ['configData' => $this->configData, 'rollback' => true]
+        )->run();
+    }
+}
diff --git a/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockAdminUserWhenEditingRoleTest.xml b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockAdminUserWhenEditingRoleTest.xml
new file mode 100644
index 0000000000000000000000000000000000000000..1d081e5d2dd9af69f90aeed8b787c966238e62de
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockAdminUserWhenEditingRoleTest.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright © 2016 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\Security\Test\TestCase\LockAdminUserWhenEditingRoleTest" summary="Lock admin user after entering incorrect password while editing existing role">
+        <variation name="LockAdminUserWhenEditingUserRoleTestVariation1">
+            <data name="configData" xsi:type="string">user_lockout_failures</data>
+            <data name="tag" xsi:type="string">severity:S2</data>
+            <data name="initrole/dataset" xsi:type="string">default</data>
+            <data name="customAdmin/dataset" xsi:type="string">custom_admin_with_default_role</data>
+            <data name="role/data/rolename" xsi:type="string">NewAdminRole%isolation%</data>
+            <data name="role/data/current_password" xsi:type="string">incorrect password</data>
+            <data name="role/data/resource_access" xsi:type="string">All</data>
+            <data name="attempts" xsi:type="string">4</data>
+            <constraint name="Magento\Security\Test\Constraint\AssertUserIsLocked" />
+        </variation>
+    </testCase>
+</config>
diff --git a/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockAdminUserWhenEditingUserTest.php b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockAdminUserWhenEditingUserTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..912ebef9e91054236cc6b85b91c3cd8d973b54e9
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockAdminUserWhenEditingUserTest.php
@@ -0,0 +1,133 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Security\Test\TestCase;
+
+use Magento\User\Test\Page\Adminhtml\UserEdit;
+use Magento\User\Test\Page\Adminhtml\UserIndex;
+use Magento\Backend\Test\Page\AdminAuthLogin;
+use Magento\User\Test\Fixture\User;
+use Magento\Mtf\TestCase\Injectable;
+
+/**
+ * Preconditions:
+ * 1. Create new admin user.
+ * 2. Configure 'Maximum Login Failures to Lockout Account'.
+ *
+ * Steps:
+ * 1. Log in to backend as new created admin user.
+ * 2. Navigate to System > All Users.
+ * 3. Start editing existing User.
+ * 4. Fill in all data according to data set (password is incorrect).
+ * 5. Perform action 4 specified number of times.
+ * 6. Admin account is locked.
+ * 7. Perform all assertions.
+ *
+ * @ZephyrId MAGETWO-49035
+ */
+class LockAdminUserWhenEditingUserTest extends Injectable
+{
+    /* tags */
+    const MVP = 'yes';
+    const SEVERITY = 'S2';
+    /* end tags */
+
+    /**
+     * User grid page
+     *
+     * @var UserIndex
+     */
+    protected $userIndexPage;
+
+    /**
+     * User edit page
+     *
+     * @var UserEdit
+     */
+    protected $userEditPage;
+
+    /**
+     * @var $configData
+     */
+    protected $configData;
+
+    /**
+     * @var AdminAuthLogin page
+     */
+    protected $adminAuthLogin;
+
+    /**
+     * Setup data for test.
+     * @param UserIndex $userIndex
+     * @param UserEdit $userEdit
+     * @param AdminAuthLogin $adminAuthLogin
+     */
+    public function __inject(
+        UserIndex $userIndex,
+        UserEdit $userEdit,
+        AdminAuthLogin $adminAuthLogin
+    ) {
+        $this->userIndexPage = $userIndex;
+        $this->userEditPage = $userEdit;
+        $this->adminAuthLogin = $adminAuthLogin;
+    }
+
+    /**
+     * Runs Lock admin user when editing existing role test.
+     *
+     * @param User $user
+     * @param int $attempts
+     * @param User $customAdmin
+     * @param string $configData
+     * @return void
+     */
+    public function test(
+        $attempts,
+        User $customAdmin,
+        User $user,
+        $configData
+    ) {
+        $this->configData = $configData;
+
+        // Preconditions
+        $this->objectManager->create(
+            \Magento\Config\Test\TestStep\SetupConfigurationStep::class,
+            ['configData' => $this->configData]
+        )->run();
+        $customAdmin->persist();
+
+        // Steps login to backend with new user
+        $this->adminAuthLogin->open();
+        $this->adminAuthLogin->getLoginBlock()->fill($customAdmin);
+        $this->adminAuthLogin->getLoginBlock()->submit();
+        // Select user to edit.
+        $filter = ['username' => $customAdmin->getUsername()];
+        $this->userIndexPage->open();
+        $this->userIndexPage->getUserGrid()->searchAndOpen($filter);
+        // Edit user with wrong password
+        for ($i = 0; $i < $attempts; $i++) {
+            $this->userEditPage->getUserForm()->fill($user);
+            $this->userEditPage->getPageActions()->save();
+        }
+        // Reload
+        $this->adminAuthLogin->open();
+        $this->adminAuthLogin->getLoginBlock()->fill($customAdmin);
+        $this->adminAuthLogin->getLoginBlock()->submit();
+    }
+
+    /**
+     * Clean data after running test.
+     *
+     * @return void
+     */
+    public function tearDown()
+    {
+        $this->objectManager->create(
+            \Magento\Config\Test\TestStep\SetupConfigurationStep::class,
+            ['configData' => $this->configData, 'rollback' => true]
+        )->run();
+    }
+}
diff --git a/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockAdminUserWhenEditingUserTest.xml b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockAdminUserWhenEditingUserTest.xml
new file mode 100644
index 0000000000000000000000000000000000000000..e1ec2f79ce6b5d306e694c9d2ae8e8adea0d3387
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockAdminUserWhenEditingUserTest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright © 2016 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\Security\Test\TestCase\LockAdminUserWhenEditingUserTest" summary="Lock admin user after entering incorrect password while editing existing user">
+        <variation name="LockAdminUserWhenEditingUseruserTestVariation1">
+            <data name="configData" xsi:type="string">user_lockout_failures</data>
+            <data name="tag" xsi:type="string">severity:S2</data>
+            <data name="customAdmin/dataset" xsi:type="string">custom_admin_with_default_role</data>
+            <data name="user/data/username" xsi:type="string">AdminUser%isolation%</data>
+            <data name="user/data/firstname" xsi:type="string">FirstName%isolation%</data>
+            <data name="user/data/lastname" xsi:type="string">LastName%isolation%</data>
+            <data name="user/data/email" xsi:type="string">email%isolation%@example.com</data>
+            <data name="user/data/password" xsi:type="string">123123qq</data>
+            <data name="user/data/password_confirmation" xsi:type="string">123123qq</data>
+            <data name="user/data/current_password" xsi:type="string">incorrect password</data>
+            <data name="attempts" xsi:type="string">4</data>
+            <constraint name="Magento\Security\Test\Constraint\AssertUserIsLocked" />
+        </variation>
+    </testCase>
+</config>
\ No newline at end of file
diff --git a/dev/tests/functional/tests/app/Magento/Ui/Test/Block/Adminhtml/DataGrid.php b/dev/tests/functional/tests/app/Magento/Ui/Test/Block/Adminhtml/DataGrid.php
index 80df7e6f8c631722fb314525b2d6733e2ac605ad..95240b5dba0644d7f10d80447399d516a4742ac2 100644
--- a/dev/tests/functional/tests/app/Magento/Ui/Test/Block/Adminhtml/DataGrid.php
+++ b/dev/tests/functional/tests/app/Magento/Ui/Test/Block/Adminhtml/DataGrid.php
@@ -165,7 +165,7 @@ class DataGrid extends Grid
      */
     protected function waitFilterToLoad()
     {
-        $this->getTemplateBlock()->waitForElementNotVisible($this->loader);
+        $this->getTemplateBlock()->waitLoader();
         $browser = $this->_rootElement;
         $selector = $this->filterButton . ', ' . $this->resetButton;
         $browser->waitUntil(
diff --git a/dev/tests/functional/tests/app/Magento/User/Test/Repository/User.xml b/dev/tests/functional/tests/app/Magento/User/Test/Repository/User.xml
index 25b812bf77665d09877835e676fc5d11fdd1434a..dbb7a4aeb53bb667bf22e99e0198d1b0e3cab25c 100644
--- a/dev/tests/functional/tests/app/Magento/User/Test/Repository/User.xml
+++ b/dev/tests/functional/tests/app/Magento/User/Test/Repository/User.xml
@@ -41,5 +41,9 @@
             <field name="current_password" xsi:type="string">%current_password%</field>
             <field name="is_active" xsi:type="string">Active</field>
         </dataset>
+
+        <dataset name="system_admin">
+            <field name="current_password" xsi:type="string">123123q</field>
+        </dataset>
     </repository>
 </config>
diff --git a/dev/tests/functional/tests/app/Magento/User/Test/TestCase/DeleteAdminUserEntityTest.php b/dev/tests/functional/tests/app/Magento/User/Test/TestCase/DeleteAdminUserEntityTest.php
index 57de56c7f56f7397282e1863ec43a3f42c6a9ec2..67ede3855e7a77b7da397a42c4de161289387b8f 100644
--- a/dev/tests/functional/tests/app/Magento/User/Test/TestCase/DeleteAdminUserEntityTest.php
+++ b/dev/tests/functional/tests/app/Magento/User/Test/TestCase/DeleteAdminUserEntityTest.php
@@ -101,11 +101,13 @@ class DeleteAdminUserEntityTest extends Injectable
      *
      * @param User $user
      * @param string $isDefaultUser
+     * @param User $systemAdmin
      * @return void
      */
     public function testDeleteAdminUserEntity(
         User $user,
-        $isDefaultUser
+        $isDefaultUser,
+        User $systemAdmin = null
     ) {
         $filter = [
             'username' => $user->getUsername(),
@@ -118,6 +120,7 @@ class DeleteAdminUserEntityTest extends Injectable
         }
         $this->userIndex->open();
         $this->userIndex->getUserGrid()->searchAndOpen($filter);
+        $this->userEdit->getUserForm()->fill($systemAdmin);
         $this->userEdit->getPageActions()->delete();
         $this->userEdit->getModalBlock()->acceptAlert();
     }
diff --git a/dev/tests/functional/tests/app/Magento/User/Test/TestCase/DeleteAdminUserEntityTest.xml b/dev/tests/functional/tests/app/Magento/User/Test/TestCase/DeleteAdminUserEntityTest.xml
index 782c3243eaa6be76578a9fc9f8b670fb6920c4da..fd10c53dfd53393dfcf122888a4d7b9e1003228a 100644
--- a/dev/tests/functional/tests/app/Magento/User/Test/TestCase/DeleteAdminUserEntityTest.xml
+++ b/dev/tests/functional/tests/app/Magento/User/Test/TestCase/DeleteAdminUserEntityTest.xml
@@ -9,11 +9,13 @@
     <testCase name="Magento\User\Test\TestCase\DeleteAdminUserEntityTest" summary="Delete Admin User" ticketId="MAGETWO-23416">
         <variation name="DeleteAdminUserEntityTestVariation1">
             <data name="isDefaultUser" xsi:type="string">0</data>
+            <data name="systemAdmin/dataset" xsi:type="string">system_admin</data>
             <constraint name="Magento\User\Test\Constraint\AssertImpossibleDeleteYourOwnAccount" />
             <constraint name="Magento\User\Test\Constraint\AssertUserInGrid" />
         </variation>
         <variation name="DeleteAdminUserEntityTestVariation2">
             <data name="isDefaultUser" xsi:type="string">1</data>
+            <data name="systemAdmin/dataset" xsi:type="string">system_admin</data>
             <constraint name="Magento\User\Test\Constraint\AssertUserSuccessDeleteMessage" />
             <constraint name="Magento\User\Test\Constraint\AssertUserNotInGrid" />
         </variation>
diff --git a/dev/tests/functional/tests/app/Magento/Usps/Test/Repository/ConfigData.xml b/dev/tests/functional/tests/app/Magento/Usps/Test/Repository/ConfigData.xml
index 85c6a6fd80eecc69cc945d96a908f40dcfb1a356..83b50205387d5da98401799e7486aba04368c355 100644
--- a/dev/tests/functional/tests/app/Magento/Usps/Test/Repository/ConfigData.xml
+++ b/dev/tests/functional/tests/app/Magento/Usps/Test/Repository/ConfigData.xml
@@ -54,7 +54,6 @@
                 <item name="value" xsi:type="number">1</item>
             </field>
         </dataset>
-
         <dataset name="usps_rollback">
             <field name="carriers/usps/active" xsi:type="array">
                 <item name="scope" xsi:type="string">carriers</item>
@@ -63,5 +62,21 @@
                 <item name="value" xsi:type="number">0</item>
             </field>
         </dataset>
+        <dataset name="usps_container_sm_flat_rate_box">
+            <field name="carriers/usps/container" xsi:type="array">
+                <item name="scope" xsi:type="string">carriers</item>
+                <item name="scope_id" xsi:type="number">1</item>
+                <item name="label" xsi:type="string">Small Flat-Rate Box</item>
+                <item name="value" xsi:type="string">SM FLAT RATE BOX</item>
+            </field>
+        </dataset>
+        <dataset name="usps_container_sm_flat_rate_box_rollback">
+            <field name="carriers/usps/container" xsi:type="array">
+                <item name="scope" xsi:type="string">carriers</item>
+                <item name="scope_id" xsi:type="number">1</item>
+                <item name="label" xsi:type="string">Variable</item>
+                <item name="value" xsi:type="string">VARIABLE</item>
+            </field>
+        </dataset>
     </repository>
 </config>
diff --git a/dev/tests/functional/tests/app/Magento/Usps/Test/TestCase/OnePageCheckoutTest.xml b/dev/tests/functional/tests/app/Magento/Usps/Test/TestCase/OnePageCheckoutTest.xml
index 0bd219bab3bfff2103ea9f7a1ff2934ca8e1ad59..8081b485c27d5c0e803a051f9126bdf6599e6781 100644
--- a/dev/tests/functional/tests/app/Magento/Usps/Test/TestCase/OnePageCheckoutTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Usps/Test/TestCase/OnePageCheckoutTest.xml
@@ -16,10 +16,10 @@
             <data name="address/dataset" xsi:type="string">US_address_1</data>
             <data name="shippingAddress/dataset" xsi:type="string">US_address_1_without_email</data>
             <data name="shipping/shipping_service" xsi:type="string">United States Postal Service</data>
-            <data name="shipping/shipping_method" xsi:type="string">Priority Mail 1-Day</data>
-            <data name="cart/data/shipping_method" xsi:type="string">Priority Mail 1-Day</data>
+            <data name="shipping/shipping_method" xsi:type="string">Priority Mail 1-Day Small Flat Rate Box</data>
+            <data name="cart/data/shipping_method" xsi:type="string">Priority Mail 1-Day Small Flat Rate Box</data>
             <data name="payment/method" xsi:type="string">checkmo</data>
-            <data name="configData" xsi:type="string">checkmo, usps, shipping_origin_US_CA</data>
+            <data name="configData" xsi:type="string">checkmo, usps, shipping_origin_US_CA, usps_container_sm_flat_rate_box</data>
             <data name="tag" xsi:type="string">test_type:3rd_party_test, severity:S0</data>
             <constraint name="Magento\Checkout\Test\Constraint\AssertOrderSuccessPlacedMessage"/>
             <constraint name="Magento\Checkout\Test\Constraint\AssertMinicartEmpty" />
diff --git a/dev/tests/functional/tests/app/Magento/Vault/Test/TestStep/UseVaultPaymentTokenStep.php b/dev/tests/functional/tests/app/Magento/Vault/Test/TestStep/UseVaultPaymentTokenStep.php
index ad693923955d4f439340970eb07ebb7c14789574..066dc7786d892619e84272c69b655cfd8a74f140 100644
--- a/dev/tests/functional/tests/app/Magento/Vault/Test/TestStep/UseVaultPaymentTokenStep.php
+++ b/dev/tests/functional/tests/app/Magento/Vault/Test/TestStep/UseVaultPaymentTokenStep.php
@@ -17,20 +17,20 @@ class UseVaultPaymentTokenStep implements TestStepInterface
      * @var OrderCreateIndex
      */
     private $orderCreatePage;
-    
+
     /**
      * @var array
      */
-    private $payment;
+    private $vault;
 
     /**
      * @param OrderCreateIndex $orderCreateIndex
-     * @param array $payment
+     * @param array $vault
      */
-    public function __construct(OrderCreateIndex $orderCreateIndex, array $payment)
+    public function __construct(OrderCreateIndex $orderCreateIndex, array $vault)
     {
         $this->orderCreatePage = $orderCreateIndex;
-        $this->payment = $payment;
+        $this->vault = $vault;
     }
 
     /**
@@ -39,8 +39,7 @@ class UseVaultPaymentTokenStep implements TestStepInterface
     public function run()
     {
         $block = $this->orderCreatePage->getCreateBlock();
-        $this->payment['method'] .= '_cc_vault';
-        $block->selectPaymentMethod($this->payment);
-        $block->selectVaultToken('token_switcher_' . $this->payment['method']);
+        $block->selectPaymentMethod($this->vault);
+        $block->selectVaultToken('token_switcher_' . $this->vault['method']);
     }
 }
diff --git a/dev/tests/functional/tests/app/Magento/Wishlist/Test/Block/Customer/Wishlist.php b/dev/tests/functional/tests/app/Magento/Wishlist/Test/Block/Customer/Wishlist.php
index 47f787da38b04264372015a52449f984820490e5..bda0780f553006bddc3f0ce164cb4f6f824ee75d 100644
--- a/dev/tests/functional/tests/app/Magento/Wishlist/Test/Block/Customer/Wishlist.php
+++ b/dev/tests/functional/tests/app/Magento/Wishlist/Test/Block/Customer/Wishlist.php
@@ -99,6 +99,7 @@ class Wishlist extends Block
     public function clickUpdateWishlist()
     {
         $this->waitFormToLoad();
+        $this->_rootElement->hover();
         $this->_rootElement->find($this->updateButton)->click();
     }
 
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 076739590e1f19b86fee7bc105221f51efda34cb..683ff71e8ff7212e4e9604d581d04b4cf9b0f238 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
@@ -164,6 +164,18 @@ class Product extends Form
         $this->_rootElement->find($this->price)->hover();
     }
 
+    /**
+     * Returns product price
+     *
+     * @param string $currency
+     * @return string
+     */
+    public function getPrice($currency = '$')
+    {
+        $price = $this->_rootElement->find($this->price)->getText();
+        return str_replace($currency, '', $price);
+    }
+
     /**
      * Get Wish List data for the Product.
      *
diff --git a/dev/tests/functional/tests/app/Magento/Wishlist/Test/Constraint/AssertProductPriceIsNotZero.php b/dev/tests/functional/tests/app/Magento/Wishlist/Test/Constraint/AssertProductPriceIsNotZero.php
new file mode 100644
index 0000000000000000000000000000000000000000..24f6222dac09eb34cf3c3d6c5a063341b2acc2ef
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Wishlist/Test/Constraint/AssertProductPriceIsNotZero.php
@@ -0,0 +1,47 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Wishlist\Test\Constraint;
+
+class AssertProductPriceIsNotZero extends \Magento\Mtf\Constraint\AbstractConstraint
+{
+    /**
+     * Assert that product price is not zero in default wishlist.
+     *
+     * @param \Magento\Cms\Test\Page\CmsIndex $cmsIndex
+     * @param \Magento\Customer\Test\Page\CustomerAccountIndex $customerAccountIndex
+     * @param \Magento\Wishlist\Test\Page\WishlistIndex $wishlistIndex
+     * @param \Magento\Mtf\Fixture\InjectableFixture $product
+     *
+     * @return void
+     */
+    public function processAssert(
+        \Magento\Cms\Test\Page\CmsIndex $cmsIndex,
+        \Magento\Customer\Test\Page\CustomerAccountIndex $customerAccountIndex,
+        \Magento\Wishlist\Test\Page\WishlistIndex $wishlistIndex,
+        \Magento\Mtf\Fixture\InjectableFixture $product
+    ) {
+        $cmsIndex->getLinksBlock()->openLink('My Account');
+        $customerAccountIndex->getAccountMenuBlock()->openMenuItem('My Wish List');
+        $wishlistItem = $wishlistIndex->getWishlistBlock()->getProductItemsBlock()->getItemProduct($product);
+
+        \PHPUnit_Framework_Assert::assertNotEquals(
+            '0.00',
+            $wishlistItem->getPrice(),
+            $product->getName() . ' has zero price on Wish List page.'
+        );
+    }
+
+    /**
+     * Returns a string representation of the object.
+     *
+     * @return string
+     */
+    public function toString()
+    {
+        return 'Product price is not zero in default Wish List.';
+    }
+}
diff --git a/dev/tests/functional/tests/app/Magento/Wishlist/Test/TestCase/AddProductToWishlistEntityTest.php b/dev/tests/functional/tests/app/Magento/Wishlist/Test/TestCase/AddProductToWishlistEntityTest.php
index 9959796828df23943db8fc3f6dfdce4b6387e1ac..bd922feee99d0315b5f7f16ee13b60eb101b626e 100644
--- a/dev/tests/functional/tests/app/Magento/Wishlist/Test/TestCase/AddProductToWishlistEntityTest.php
+++ b/dev/tests/functional/tests/app/Magento/Wishlist/Test/TestCase/AddProductToWishlistEntityTest.php
@@ -48,15 +48,16 @@ class AddProductToWishlistEntityTest extends AbstractWishlistTest
      *
      * @param Customer $customer
      * @param string $product
+     * @param bool $configure
      * @return array
      */
-    public function test(Customer $customer, $product)
+    public function test(Customer $customer, $product, $configure = true)
     {
         $product = $this->createProducts($product)[0];
 
         // Steps:
         $this->loginCustomer($customer);
-        $this->addToWishlist([$product], true);
+        $this->addToWishlist([$product], $configure);
 
         return ['product' => $product];
     }
diff --git a/dev/tests/functional/tests/app/Magento/Wishlist/Test/TestCase/AddProductToWishlistEntityTest.xml b/dev/tests/functional/tests/app/Magento/Wishlist/Test/TestCase/AddProductToWishlistEntityTest.xml
index 0557fa298ce985313593216b561b181175719a70..550cffa488130e16f73a9d89b9bc4344a57a2291 100644
--- a/dev/tests/functional/tests/app/Magento/Wishlist/Test/TestCase/AddProductToWishlistEntityTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Wishlist/Test/TestCase/AddProductToWishlistEntityTest.xml
@@ -49,5 +49,12 @@
             <constraint name="Magento\Wishlist\Test\Constraint\AssertProductDetailsInWishlist" />
             <constraint name="Magento\Wishlist\Test\Constraint\AssertProductIsPresentInCustomerBackendWishlist" />
         </variation>
+        <variation name="AddProductToWishlistEntityTestVariation8">
+            <data name="product/0" xsi:type="string">configurableProduct::default</data>
+            <data name="configure" xsi:type="boolean">false</data>
+            <constraint name="Magento\Wishlist\Test\Constraint\AssertAddProductToWishlistSuccessMessage" />
+            <constraint name="Magento\Wishlist\Test\Constraint\AssertProductIsPresentInWishlist" />
+            <constraint name="Magento\Wishlist\Test\Constraint\AssertProductPriceIsNotZero" />
+        </variation>
     </testCase>
 </config>
diff --git a/dev/tests/integration/_files/Magento/TestModuleDirectoryZipCodes/etc/module.xml b/dev/tests/integration/_files/Magento/TestModuleDirectoryZipCodes/etc/module.xml
new file mode 100644
index 0000000000000000000000000000000000000000..ce5ed9cb663a759edf057291f11ccc6a75fe6266
--- /dev/null
+++ b/dev/tests/integration/_files/Magento/TestModuleDirectoryZipCodes/etc/module.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0"?>
+<!--
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+-->
+<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
+    <module name="Magento_TestModuleDirectoryZipCodes" setup_version="0.0.1" active="true">
+        <sequence>
+            <module name="Magento_Directory"/>
+        </sequence>
+    </module>
+</config>
diff --git a/dev/tests/integration/_files/Magento/TestModuleDirectoryZipCodes/etc/zip_codes.xml b/dev/tests/integration/_files/Magento/TestModuleDirectoryZipCodes/etc/zip_codes.xml
new file mode 100644
index 0000000000000000000000000000000000000000..d4f121c60daeb8c44f327f8149f0148051c252ff
--- /dev/null
+++ b/dev/tests/integration/_files/Magento/TestModuleDirectoryZipCodes/etc/zip_codes.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+-->
+<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Directory:etc/zip_codes.xsd">
+    <zip countryCode="NL">
+        <codes>
+            <code id="pattern_1" active="true" example="test1">^[0-9]{4}\s[a-zA-Z]{2}$</code>
+            <code id="pattern_2" active="true" example="test2">^[0-5]{4}[a-z]{2}$</code>
+        </codes>
+    </zip>
+    <zip countryCode="NL_NEW">
+        <codes>
+            <code id="pattern_1" active="true" example="test1">^[0-2]{4}[A-Z]{2}$</code>
+        </codes>
+    </zip>
+</config>
diff --git a/dev/tests/integration/_files/Magento/TestModuleDirectoryZipCodes/registration.php b/dev/tests/integration/_files/Magento/TestModuleDirectoryZipCodes/registration.php
new file mode 100644
index 0000000000000000000000000000000000000000..2ed368ecf3b23a4bd4db86357f6cbbca0bfc55de
--- /dev/null
+++ b/dev/tests/integration/_files/Magento/TestModuleDirectoryZipCodes/registration.php
@@ -0,0 +1,12 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+use Magento\Framework\Component\ComponentRegistrar;
+
+$registrar = new ComponentRegistrar();
+if ($registrar->getPath(ComponentRegistrar::MODULE, 'Magento_TestModuleDirectoryZipCodes') === null) {
+    ComponentRegistrar::register(ComponentRegistrar::MODULE, 'Magento_TestModuleDirectoryZipCodes', __DIR__);
+}
diff --git a/dev/tests/integration/_files/Magento/TestModuleSample/composer.json b/dev/tests/integration/_files/Magento/TestModuleSample/composer.json
index 4d6383045d27f2123e84146eae970ec74ae77797..3e8e5650b85a77f75c079ae0ad9211a8d4d0764a 100644
--- a/dev/tests/integration/_files/Magento/TestModuleSample/composer.json
+++ b/dev/tests/integration/_files/Magento/TestModuleSample/composer.json
@@ -2,7 +2,7 @@
   "name": "magento/module-sample-test",
   "description": "test sample module",
   "require": {
-    "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+    "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
     "magento/framework": "100.1.*",
     "magento/module-integration": "100.1.*"
   },
diff --git a/dev/tests/integration/testsuite/Magento/Braintree/Model/Ui/Adminhtml/PayPal/TokenUiComponentProviderTest.php b/dev/tests/integration/testsuite/Magento/Braintree/Model/Ui/Adminhtml/PayPal/TokenUiComponentProviderTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..e79f4ad361e36d315e7bc30846325bbe97445d1e
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Braintree/Model/Ui/Adminhtml/PayPal/TokenUiComponentProviderTest.php
@@ -0,0 +1,62 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Braintree\Model\Ui\Adminhtml\PayPal;
+
+use Magento\Braintree\Model\Ui\Adminhtml\PayPal\TokenUiComponentProvider;
+use Magento\Braintree\Model\Ui\PayPal\ConfigProvider;
+use Magento\Framework\ObjectManagerInterface;
+use Magento\TestFramework\Helper\Bootstrap;
+use Magento\Vault\Model\PaymentTokenManagement;
+use Magento\Vault\Model\Ui\TokenUiComponentProviderInterface;
+
+/**
+ * Contains tests for PayPal token Ui component provider
+ */
+class TokenUiComponentProviderTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var ObjectManagerInterface
+     */
+    private $objectManager;
+
+    /**
+     * @var TokenUiComponentProvider
+     */
+    private $tokenComponentProvider;
+
+    protected function setUp()
+    {
+        $this->objectManager = Bootstrap::getObjectManager();
+        $this->tokenComponentProvider = $this->objectManager->get(TokenUiComponentProvider::class);
+    }
+
+    /**
+     * @covers \Magento\Braintree\Model\Ui\Adminhtml\PayPal\TokenUiComponentProvider::getComponentForToken
+     * @magentoDataFixture Magento/Braintree/_files/paypal_vault_token.php
+     * @magentoAppArea adminhtml
+     */
+    public function testGetComponentForToken()
+    {
+        $customerId = 1;
+        $token = 'mx29vk';
+        $payerEmail = 'john.doe@example.com';
+
+        /** @var PaymentTokenManagement $tokenManagement */
+        $tokenManagement = $this->objectManager->get(PaymentTokenManagement::class);
+        $paymentToken = $tokenManagement->getByGatewayToken($token, ConfigProvider::PAYPAL_CODE, $customerId);
+
+        $component = $this->tokenComponentProvider->getComponentForToken($paymentToken);
+        $config = $component->getConfig();
+
+        static::assertNotEmpty($config[TokenUiComponentProviderInterface::COMPONENT_DETAILS]);
+        static::assertNotEmpty($config[TokenUiComponentProviderInterface::COMPONENT_PUBLIC_HASH]);
+        static::assertEquals(ConfigProvider::PAYPAL_VAULT_CODE, $config['code']);
+
+        $details = $config[TokenUiComponentProviderInterface::COMPONENT_DETAILS];
+        static::assertEquals($payerEmail, $details['payerEmail']);
+        static::assertNotEmpty($details['icon']);
+    }
+}
diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/CategoryTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/CategoryTest.php
index a3e90819912f03a9413311600c7cd5cbcfddff60..49787c94038a1d9b1c3991c7f6261c0b7ef1453e 100644
--- a/dev/tests/integration/testsuite/Magento/Catalog/Model/CategoryTest.php
+++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/CategoryTest.php
@@ -293,7 +293,7 @@ class CategoryTest extends \PHPUnit_Framework_TestCase
             ->isObjectNew(true);
 
         $repository->save($model);
-        $this->assertNull($model->getImage());
+        $this->assertEmpty($model->getImage());
     }
 
     /**
diff --git a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Export/ProductTest.php b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Export/ProductTest.php
index 0afede93546f2c8ba69f8af9b64b70013b5d2c22..dc9e440b045f86ad2e85de45124ac01881d3892c 100644
--- a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Export/ProductTest.php
+++ b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Export/ProductTest.php
@@ -227,7 +227,34 @@ class ProductTest extends \PHPUnit_Framework_TestCase
 
         $this->assertContains('""Option 2""', $exportData);
         $this->assertContains('""Option 3""', $exportData);
-        $this->assertContains('""Option 4 """"!@#$%^&*"""', $exportData);
-        $this->assertContains('text_attribute=""!@#$%^&*()_+1234567890-=|\:;"""', $exportData);
+        $this->assertContains('""Option 4 """"!@#$%^&*""', $exportData);
+        $this->assertContains('text_attribute=""!@#$%^&*()_+1234567890-=|\:;""""\'<,>.?/', $exportData);
+    }
+
+    /**
+     * Verify that "category ids" filter correctly applies to export result
+     *
+     * @magentoDataFixture Magento/CatalogImportExport/_files/product_export_with_categories.php
+     */
+    public function testCategoryIdsFilter()
+    {
+        $this->model->setWriter(
+            $this->objectManager->create(
+                \Magento\ImportExport\Model\Export\Adapter\Csv::class
+            )
+        );
+
+        $this->model->setParameters([
+            \Magento\ImportExport\Model\Export::FILTER_ELEMENT_GROUP => [
+                'category_ids' => '2,13'
+            ]
+        ]);
+
+        $exportData = $this->model->export();
+
+        $this->assertContains('Simple Product', $exportData);
+        $this->assertContains('Simple Product Three', $exportData);
+        $this->assertNotContains('Simple Product Two', $exportData);
+        $this->assertNotContains('Simple Product Not Visible On Storefront', $exportData);
     }
 }
diff --git a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php
index 9ab7db147d811d370a4c2609d5baf5ea35225680..d8b2189e9f0d267d24d86ea77c67e84b2e2f73c9 100644
--- a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php
+++ b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php
@@ -1431,4 +1431,113 @@ class ProductTest extends \Magento\TestFramework\Indexer\TestCase
         $this->assertEquals(implode(',', [$multiselectOptions[1]->getValue(), $multiselectOptions[2]->getValue()]),
             $product2->getData('multiselect_attribute'));
     }
+
+    /**
+     * @param array $row
+     * @param string|null $behavior
+     * @param bool $expectedResult
+     * @magentoAppArea adminhtml
+     * @magentoAppIsolation enabled
+     * @magentoDbIsolation enabled
+     * @magentoDataFixture Magento/Catalog/Model/ResourceModel/_files/product_simple.php
+     * @dataProvider validateRowDataProvider
+     */
+    public function testValidateRow(array $row, $behavior, $expectedResult)
+    {
+        $this->_model->setParameters(['behavior' => $behavior, 'entity' => 'catalog_product']);
+        $this->assertSame($expectedResult, $this->_model->validateRow($row, 1));
+    }
+
+    /**
+     * @return array
+     */
+    public function validateRowDataProvider()
+    {
+        return [
+            [
+                'row' => ['sku' => 'simple products'],
+                'behavior' => null,
+                'expectedResult' => true,
+            ],
+            [
+                'row' => ['sku' => 'simple products absent'],
+                'behavior' => null,
+                'expectedResult' => false,
+            ],
+            [
+                'row' => [
+                    'sku' => 'simple products absent',
+                    'name' => 'Test',
+                    'product_type' => 'simple',
+                    '_attribute_set' => 'Default',
+                    'price' => 10.20,
+                ],
+                'behavior' => null,
+                'expectedResult' => true,
+            ],
+            [
+                'row' => ['sku' => 'simple products'],
+                'behavior' => Import::BEHAVIOR_ADD_UPDATE,
+                'expectedResult' => true,
+            ],
+            [
+                'row' => ['sku' => 'simple products absent'],
+                'behavior' => Import::BEHAVIOR_ADD_UPDATE,
+                'expectedResult' => false,
+            ],
+            [
+                'row' => [
+                    'sku' => 'simple products absent',
+                    'name' => 'Test',
+                    'product_type' => 'simple',
+                    '_attribute_set' => 'Default',
+                    'price' => 10.20,
+                ],
+                'behavior' => Import::BEHAVIOR_ADD_UPDATE,
+                'expectedResult' => true,
+            ],
+            [
+                'row' => ['sku' => 'simple products'],
+                'behavior' => Import::BEHAVIOR_DELETE,
+                'expectedResult' => true,
+            ],
+            [
+                'row' => ['sku' => 'simple products absent'],
+                'behavior' => Import::BEHAVIOR_DELETE,
+                'expectedResult' => false,
+            ],
+            [
+                'row' => ['sku' => 'simple products'],
+                'behavior' => Import::BEHAVIOR_REPLACE,
+                'expectedResult' => false,
+            ],
+            [
+                'row' => ['sku' => 'simple products absent'],
+                'behavior' => Import::BEHAVIOR_REPLACE,
+                'expectedResult' => false,
+            ],
+            [
+                'row' => [
+                    'sku' => 'simple products absent',
+                    'name' => 'Test',
+                    'product_type' => 'simple',
+                    '_attribute_set' => 'Default',
+                    'price' => 10.20,
+                ],
+                'behavior' => Import::BEHAVIOR_REPLACE,
+                'expectedResult' => false,
+            ],
+            [
+                'row' => [
+                    'sku' => 'simple products',
+                    'name' => 'Test',
+                    'product_type' => 'simple',
+                    '_attribute_set' => 'Default',
+                    'price' => 10.20,
+                ],
+                'behavior' => Import::BEHAVIOR_REPLACE,
+                'expectedResult' => true,
+            ],
+        ];
+    }
 }
diff --git a/dev/tests/integration/testsuite/Magento/CatalogImportExport/_files/product_export_with_categories.php b/dev/tests/integration/testsuite/Magento/CatalogImportExport/_files/product_export_with_categories.php
new file mode 100644
index 0000000000000000000000000000000000000000..e65ff00bcffcabd1e2fdeae3810876178e0d06aa
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/CatalogImportExport/_files/product_export_with_categories.php
@@ -0,0 +1,9 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+\Magento\TestFramework\Helper\Bootstrap::getInstance()->reinitialize();
+
+require dirname(dirname(__DIR__)) . '/Catalog/_files/categories.php';
diff --git a/dev/tests/integration/testsuite/Magento/CatalogInventory/Api/StockItemSaveTest.php b/dev/tests/integration/testsuite/Magento/CatalogInventory/Api/StockItemSaveTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..0dc5c3ef620c3c307d4b35b6b7b0e61091128775
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/CatalogInventory/Api/StockItemSaveTest.php
@@ -0,0 +1,43 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\CatalogInventory\Api;
+
+use Magento\Catalog\Api\Data\ProductExtensionInterface;
+use Magento\Catalog\Api\Data\ProductInterface;
+use Magento\Catalog\Api\ProductRepositoryInterface;
+
+class StockItemSaveTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @magentoDataFixture Magento/Catalog/_files/product_simple.php
+     */
+    public function testSave()
+    {
+        $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
+        /** @var ProductRepositoryInterface $productRepository */
+        $productRepository = $objectManager->get(ProductRepositoryInterface::class);
+        /** @var ProductInterface $product */
+        $product = $productRepository->get('simple', false, null, true);
+
+        /** @var ProductExtensionInterface $ea */
+        $ea = $product->getExtensionAttributes();
+        $ea->getStockItem()->setQty(555);
+        $productRepository->save($product);
+
+        $product = $productRepository->get('simple', false, null, true);
+        $this->assertEquals(555, $product->getExtensionAttributes()->getStockItem()->getQty());
+
+        $stockItem = $product->getExtensionAttributes()->getStockItem();
+        $stockItem->setQty(200);
+        /** @var StockItemRepositoryInterface $stockItemRepository */
+        $stockItemRepository = $objectManager->get(StockItemRepositoryInterface::class);
+        $stockItemRepository->save($stockItem);
+        $this->assertEquals(200, $product->getExtensionAttributes()->getStockItem()->getQty());
+
+        $product = $productRepository->get('simple', false, null, true);
+        $this->assertEquals(200, $product->getExtensionAttributes()->getStockItem()->getQty());
+    }
+}
diff --git a/dev/tests/integration/testsuite/Magento/Checkout/Controller/CartTest.php b/dev/tests/integration/testsuite/Magento/Checkout/Controller/CartTest.php
index 34a484f749b7807a7096e22fc24c21b8b6e6c5dd..54a068dad5d0a26f1564d662eb962eca64527110 100644
--- a/dev/tests/integration/testsuite/Magento/Checkout/Controller/CartTest.php
+++ b/dev/tests/integration/testsuite/Magento/Checkout/Controller/CartTest.php
@@ -229,4 +229,51 @@ class CartTest extends \Magento\TestFramework\TestCase\AbstractController
         }
         return null;
     }
+
+    /**
+     * Test for \Magento\Checkout\Controller\Cart::execute() with simple product
+     *
+     * @param string $area
+     * @param string $expectedPrice
+     * @magentoDataFixture Magento/Catalog/_files/products.php
+     * @magentoAppIsolation enabled
+     * @dataProvider addAddProductDataProvider
+     */
+    public function testAddToCartSimpleProduct($area, $expectedPrice)
+    {
+        $formKey = $this->_objectManager->get(\Magento\Framework\Data\Form\FormKey::class);
+        $postData = [
+            'qty' => '1',
+            'product' => '1',
+            'custom_price' => 1,
+            'form_key' => $formKey->getFormKey(),
+            'isAjax' => 1
+        ];
+        \Magento\TestFramework\Helper\Bootstrap::getInstance()->loadArea($area);
+        $this->getRequest()->setPostValue($postData);
+
+        $quote =  $this->_objectManager->create(\Magento\Checkout\Model\Cart::class);
+        /** @var \Magento\Checkout\Controller\Cart\Add $controller */
+        $controller = $this->_objectManager->create(\Magento\Checkout\Controller\Cart\Add::class, [$quote]);
+        $controller->execute();
+
+        $this->assertContains(json_encode([]), $this->getResponse()->getBody());
+        $items = $quote->getItems()->getItems();
+        $this->assertTrue(is_array($items), 'Quote doesn\'t have any items');
+        $this->assertCount(1, $items, 'Expected quote items not equal to 1');
+        $item = reset($items);
+        $this->assertEquals(1, $item->getProductId(), 'Quote has more than one product');
+        $this->assertEquals($expectedPrice, $item->getPrice(), 'Expected product price failed');
+    }
+
+    /**
+     * Data provider for testAddToCartSimpleProduct
+     */
+    public function addAddProductDataProvider()
+    {
+        return [
+            'frontend' => ['frontend', 'expected_price' => 10],
+            'adminhtml' => ['adminhtml', 'expected_price' => 1]
+        ];
+    }
 }
diff --git a/dev/tests/integration/testsuite/Magento/Config/Model/Config/Backend/BaseurlTest.php b/dev/tests/integration/testsuite/Magento/Config/Model/Config/Backend/BaseurlTest.php
index 0ce30e5b2984120c7e325a151d96c0ef044affa6..5a2db8ccb22fa0484ab71c04f8a6bbc4cbc7b0e6 100644
--- a/dev/tests/integration/testsuite/Magento/Config/Model/Config/Backend/BaseurlTest.php
+++ b/dev/tests/integration/testsuite/Magento/Config/Model/Config/Backend/BaseurlTest.php
@@ -95,33 +95,44 @@ class BaseurlTest extends \PHPUnit_Framework_TestCase
         $unsecurePlaceholder = '{{unsecure_base_url}}';
         $unsecureSuffix = '{{unsecure_base_url}}test/';
         $unsecureWrongSuffix = '{{unsecure_base_url}}test';
+        $unsecureWrongDomainName = 'http://example.com_test/';
         $securePlaceholder = '{{secure_base_url}}';
         $secureSuffix = '{{secure_base_url}}test/';
         $secureWrongSuffix = '{{secure_base_url}}test';
+        $secureWrongDomainName = 'https://example.com_test/';
 
         return [
             ['', 'not a valid URL'],
             ['', 'example.com'],
             ['', 'http://example.com'],
             ['', 'http://example.com/uri'],
+            ['', $unsecureWrongDomainName],
             [\Magento\Store\Model\Store::XML_PATH_UNSECURE_BASE_URL, ''],
             [\Magento\Store\Model\Store::XML_PATH_UNSECURE_BASE_URL, $baseSuffix],
             [\Magento\Store\Model\Store::XML_PATH_UNSECURE_BASE_URL, $unsecureSuffix],
             [\Magento\Store\Model\Store::XML_PATH_UNSECURE_BASE_URL, $unsecurePlaceholder],
+            [\Magento\Store\Model\Store::XML_PATH_UNSECURE_BASE_URL, $unsecureWrongDomainName],
             [\Magento\Store\Model\Store::XML_PATH_UNSECURE_BASE_LINK_URL, ''],
             [\Magento\Store\Model\Store::XML_PATH_UNSECURE_BASE_LINK_URL, $baseSuffix],
             [\Magento\Store\Model\Store::XML_PATH_UNSECURE_BASE_LINK_URL, $unsecureWrongSuffix],
+            [\Magento\Store\Model\Store::XML_PATH_UNSECURE_BASE_LINK_URL, $unsecureWrongDomainName],
             [\Magento\Store\Model\Store::XML_PATH_UNSECURE_BASE_MEDIA_URL, $unsecureWrongSuffix],
+            [\Magento\Store\Model\Store::XML_PATH_UNSECURE_BASE_MEDIA_URL, $unsecureWrongDomainName],
             [\Magento\Store\Model\Store::XML_PATH_UNSECURE_BASE_STATIC_URL, $unsecureWrongSuffix],
+            [\Magento\Store\Model\Store::XML_PATH_UNSECURE_BASE_STATIC_URL, $unsecureWrongDomainName],
             [\Magento\Store\Model\Store::XML_PATH_SECURE_BASE_URL, ''],
             [\Magento\Store\Model\Store::XML_PATH_SECURE_BASE_URL, $baseSuffix],
             [\Magento\Store\Model\Store::XML_PATH_SECURE_BASE_URL, $secureSuffix],
             [\Magento\Store\Model\Store::XML_PATH_SECURE_BASE_URL, $securePlaceholder],
+            [\Magento\Store\Model\Store::XML_PATH_SECURE_BASE_URL, $secureWrongDomainName],
             [\Magento\Store\Model\Store::XML_PATH_SECURE_BASE_LINK_URL, ''],
             [\Magento\Store\Model\Store::XML_PATH_SECURE_BASE_LINK_URL, $baseSuffix],
             [\Magento\Store\Model\Store::XML_PATH_SECURE_BASE_LINK_URL, $secureWrongSuffix],
+            [\Magento\Store\Model\Store::XML_PATH_SECURE_BASE_LINK_URL, $secureWrongDomainName],
             [\Magento\Store\Model\Store::XML_PATH_SECURE_BASE_MEDIA_URL, $secureWrongSuffix],
+            [\Magento\Store\Model\Store::XML_PATH_SECURE_BASE_MEDIA_URL, $secureWrongDomainName],
             [\Magento\Store\Model\Store::XML_PATH_SECURE_BASE_STATIC_URL, $secureWrongSuffix],
+            [\Magento\Store\Model\Store::XML_PATH_SECURE_BASE_STATIC_URL, $secureWrongDomainName],
         ];
     }
 }
diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/ResourceModel/Product/Indexer/Price/ConfigurableTest.php b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/ResourceModel/Product/Indexer/Price/ConfigurableTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..5db97cc36614924ae915b7b924b2c7a1f575e344
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/ResourceModel/Product/Indexer/Price/ConfigurableTest.php
@@ -0,0 +1,70 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\ConfigurableProduct\Model\ResourceModel\Product\Indexer\Price;
+
+use Magento\Catalog\Api\ProductRepositoryInterface;
+use Magento\Catalog\Model\Product\Attribute\Source\Status;
+use Magento\Catalog\Model\ResourceModel\Product\Collection;
+use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory;
+use Magento\Store\Model\Store;
+use Magento\Store\Model\StoreManagerInterface;
+use Magento\TestFramework\Helper\Bootstrap;
+
+/**
+ * @magentoAppArea adminhtml
+ */
+class ConfigurableTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var StoreManagerInterface
+     */
+    private $storeManager;
+
+    /**
+     * @var ProductRepositoryInterface
+     */
+    private $productRepository;
+
+    protected function setUp()
+    {
+        $this->storeManager = Bootstrap::getObjectManager()->get(StoreManagerInterface::class);
+        $this->productRepository = Bootstrap::getObjectManager()->get(ProductRepositoryInterface::class);
+    }
+
+    /**
+     * @magentoDataFixture Magento/ConfigurableProduct/_files/product_configurable.php
+     */
+    public function testGetProductFinalPriceIfOneOfChildIsDisabled()
+    {
+        /** @var Collection $collection */
+        $collection = Bootstrap::getObjectManager()->get(CollectionFactory::class)
+            ->create();
+        $configurableProduct = $collection
+            ->addIdFilter([1])
+            ->addMinimalPrice()
+            ->load()
+            ->getFirstItem();
+        $this->assertEquals(10, $configurableProduct->getMinimalPrice());
+
+        $childProduct = $this->productRepository->getById(10, false, null, true);
+        $childProduct->setStatus(Status::STATUS_DISABLED);
+        // update in global scope
+        $currentStoreId = $this->storeManager->getStore()->getId();
+        $this->storeManager->setCurrentStore(Store::ADMIN_CODE);
+        $this->productRepository->save($childProduct);
+        $this->storeManager->setCurrentStore($currentStoreId);
+
+        /** @var Collection $collection */
+        $collection = Bootstrap::getObjectManager()->get(CollectionFactory::class)
+            ->create();
+        $configurableProduct = $collection
+            ->addIdFilter([1])
+            ->addMinimalPrice()
+            ->load()
+            ->getFirstItem();
+        $this->assertEquals(20, $configurableProduct->getMinimalPrice());
+    }
+}
diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Pricing/Price/LowestPriceOptionProviderTest.php b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Pricing/Price/LowestPriceOptionProviderTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..50787c7962412b0611edf093825563061da67119
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Pricing/Price/LowestPriceOptionProviderTest.php
@@ -0,0 +1,98 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\ConfigurableProduct\Pricing\Price;
+
+use Magento\Catalog\Api\ProductRepositoryInterface;
+use Magento\Catalog\Model\Product\Attribute\Source\Status;
+use Magento\Store\Model\Store;
+use Magento\Store\Model\StoreManagerInterface;
+use Magento\TestFramework\Helper\Bootstrap;
+
+class LowestPriceOptionProviderTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var StoreManagerInterface
+     */
+    private $storeManager;
+
+    /**
+     * @var LowestPriceOptionsProviderInterface
+     */
+    private $lowestPriceOptionsProvider;
+
+    /**
+     * @var ProductRepositoryInterface
+     */
+    private $productRepository;
+
+    protected function setUp()
+    {
+        $this->storeManager = Bootstrap::getObjectManager()->get(StoreManagerInterface::class);
+        $this->productRepository = Bootstrap::getObjectManager()->get(ProductRepositoryInterface::class);
+        $this->lowestPriceOptionsProvider = Bootstrap::getObjectManager()->get(
+            LowestPriceOptionsProviderInterface::class
+        );
+    }
+
+    /**
+     * @magentoDataFixture Magento/ConfigurableProduct/_files/product_configurable.php
+     */
+    public function testGetProductsIfOneOfChildIsDisabled()
+    {
+        $configurableProduct = $this->productRepository->getById(1, false, null, true);
+        $lowestPriceChildrenProducts = $this->lowestPriceOptionsProvider->getProducts($configurableProduct);
+        $this->assertCount(1, $lowestPriceChildrenProducts);
+        $lowestPriceChildrenProduct = reset($lowestPriceChildrenProducts);
+        $this->assertEquals(10, $lowestPriceChildrenProduct->getPrice());
+
+        // load full aggregation root
+        $lowestPriceChildProduct = $this->productRepository->get(
+            $lowestPriceChildrenProduct->getSku(),
+            false,
+            null,
+            true
+        );
+        $lowestPriceChildProduct->setStatus(Status::STATUS_DISABLED);
+        // update in global scope
+        $currentStoreId = $this->storeManager->getStore()->getId();
+        $this->storeManager->setCurrentStore(Store::ADMIN_CODE);
+        $this->productRepository->save($lowestPriceChildProduct);
+        $this->storeManager->setCurrentStore($currentStoreId);
+
+        $lowestPriceChildrenProducts = $this->lowestPriceOptionsProvider->getProducts($configurableProduct);
+        $this->assertCount(1, $lowestPriceChildrenProducts);
+        $lowestPriceChildrenProduct = reset($lowestPriceChildrenProducts);
+        $this->assertEquals(20, $lowestPriceChildrenProduct->getPrice());
+    }
+
+    /**
+     * @magentoDataFixture Magento/ConfigurableProduct/_files/product_configurable.php
+     */
+    public function testGetProductsIfOneOfChildIsOutOfStock()
+    {
+        $configurableProduct = $this->productRepository->getById(1, false, null, true);
+        $lowestPriceChildrenProducts = $this->lowestPriceOptionsProvider->getProducts($configurableProduct);
+        $this->assertCount(1, $lowestPriceChildrenProducts);
+        $lowestPriceChildrenProduct = reset($lowestPriceChildrenProducts);
+        $this->assertEquals(10, $lowestPriceChildrenProduct->getPrice());
+
+        // load full aggregation root
+        $lowestPriceChildProduct = $this->productRepository->get(
+            $lowestPriceChildrenProduct->getSku(),
+            false,
+            null,
+            true
+        );
+        $stockItem = $lowestPriceChildProduct->getExtensionAttributes()->getStockItem();
+        $stockItem->setIsInStock(0);
+        $this->productRepository->save($lowestPriceChildProduct);
+
+        $lowestPriceChildrenProducts = $this->lowestPriceOptionsProvider->getProducts($configurableProduct);
+        $this->assertCount(1, $lowestPriceChildrenProducts);
+        $lowestPriceChildrenProduct = reset($lowestPriceChildrenProducts);
+        $this->assertEquals(20, $lowestPriceChildrenProduct->getPrice());
+    }
+}
diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/product_simple_77.php b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/product_simple_77.php
index ff08056e4b18def3f520d2a5d9f2090b168d5ec8..0d8361b4751e38a96ae4dbb7aadb86510dad92dc 100644
--- a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/product_simple_77.php
+++ b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/product_simple_77.php
@@ -1,5 +1,7 @@
 <?php
 /**
+ * Creates a simple product to be used for test cases.
+ *
  * Copyright © 2016 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
@@ -72,7 +74,8 @@ $product->setTypeId(Type::TYPE_SIMPLE)
             'is_in_stock'               => 1,
         ]
     )->setCanSaveCustomOptions(true)
-    ->setHasOptions(true);
+    ->setHasOptions(true)
+    ->setCustomAttribute('test_configurable', 42);
 
 $oldOptions = [
     [
diff --git a/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/IndexTest.php b/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/IndexTest.php
index 1576ff90cb38ee4cd89b68766395fa0746d071d6..5f9b9e928b3178f3ae06a8d5a885022cc8e954cc 100644
--- a/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/IndexTest.php
+++ b/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/IndexTest.php
@@ -313,6 +313,8 @@ class IndexTest extends \Magento\TestFramework\TestCase\AbstractBackendControlle
         $this->assertEquals(2, count($addresses));
         $updatedAddress = $this->addressRepository->getById(1);
         $this->assertEquals('update firstname', $updatedAddress->getFirstname());
+        $this->assertTrue($updatedAddress->isDefaultBilling());
+        $this->assertEquals($updatedAddress->getId(), $customer->getDefaultBilling());
         $newAddress = $this->accountManagement->getDefaultShippingAddress($customerId);
         $this->assertEquals('new firstname', $newAddress->getFirstname());
 
diff --git a/dev/tests/integration/testsuite/Magento/Customer/Controller/Section/LoadTest.php b/dev/tests/integration/testsuite/Magento/Customer/Controller/Section/LoadTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..c44e320e64f4d0cfe1646f97642a2080e604ed74
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Customer/Controller/Section/LoadTest.php
@@ -0,0 +1,19 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Customer\Controller\Section;
+
+class LoadTest extends \Magento\TestFramework\TestCase\AbstractController
+{
+    public function testLoadInvalidSection()
+    {
+        $expected = [
+            'message' => '&quot;section&lt;invalid&quot; section source is not supported',
+        ];
+        $this->dispatch('/customer/section/load/?sections=section<invalid&update_section_id=false&_=147066166394');
+        self::assertEquals(json_encode($expected), $this->getResponse()->getBody());
+    }
+}
diff --git a/dev/tests/integration/testsuite/Magento/Directory/Model/Country/Postcode/Config/ReaderTest.php b/dev/tests/integration/testsuite/Magento/Directory/Model/Country/Postcode/Config/ReaderTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..2b57fcb43a1a4326fc80dadcbc8211f6ed35b623
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Directory/Model/Country/Postcode/Config/ReaderTest.php
@@ -0,0 +1,43 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Directory\Model\Country\Postcode\Config;
+
+class ReaderTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\Directory\Model\Country\Postcode\Config\Reader
+     */
+    private $reader;
+
+    protected function setUp()
+    {
+        $this->reader = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
+            \Magento\Directory\Model\Country\Postcode\Config\Reader::class
+        );
+    }
+
+    public function testRead()
+    {
+        $result = $this->reader->read();
+
+        $this->assertArrayHasKey('NL', $result);
+        $this->assertArrayHasKey('pattern_1', $result['NL']);
+        $this->assertArrayHasKey('pattern_2', $result['NL']);
+
+        $this->assertEquals('test1', $result['NL']['pattern_1']['example']);
+        $this->assertEquals('^[0-9]{4}\s[a-zA-Z]{2}$', $result['NL']['pattern_1']['pattern']);
+
+        $this->assertEquals('test2', $result['NL']['pattern_2']['example']);
+        $this->assertEquals('^[0-5]{4}[a-z]{2}$', $result['NL']['pattern_2']['pattern']);
+
+        $this->assertArrayHasKey('NL_NEW', $result);
+        $this->assertArrayHasKey('pattern_1', $result['NL_NEW']);
+
+        $this->assertEquals('test1', $result['NL_NEW']['pattern_1']['example']);
+        $this->assertEquals('^[0-2]{4}[A-Z]{2}$', $result['NL_NEW']['pattern_1']['pattern']);
+    }
+}
diff --git a/dev/tests/integration/testsuite/Magento/Framework/DB/Adapter/Pdo/MysqlTest.php b/dev/tests/integration/testsuite/Magento/Framework/DB/Adapter/Pdo/MysqlTest.php
index 8a566a0d4efe55e856716c095f5a3a7e14896af1..14118414859f0d9bced34e393bfb699f22251edf 100644
--- a/dev/tests/integration/testsuite/Magento/Framework/DB/Adapter/Pdo/MysqlTest.php
+++ b/dev/tests/integration/testsuite/Magento/Framework/DB/Adapter/Pdo/MysqlTest.php
@@ -12,6 +12,7 @@
 namespace Magento\Framework\DB\Adapter\Pdo;
 
 use Magento\Framework\App\ResourceConnection;
+use Zend_Db_Statement_Exception;
 
 class MysqlTest extends \PHPUnit_Framework_TestCase
 {
@@ -32,6 +33,7 @@ class MysqlTest extends \PHPUnit_Framework_TestCase
         restore_error_handler();
     }
 
+
     /**
      * Test lost connection re-initializing
      *
@@ -125,9 +127,9 @@ class MysqlTest extends \PHPUnit_Framework_TestCase
     protected function _getConnection()
     {
         if (is_null($this->_connection)) {
-            /** @var $coreResource \Magento\Framework\App\ResourceConnection */
+            /** @var $coreResource ResourceConnection */
             $coreResource = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()
-                ->get(\Magento\Framework\App\ResourceConnection::class);
+                ->get(ResourceConnection::class);
             $this->_connection = $coreResource->getConnection();
         }
         return $this->_connection;
diff --git a/dev/tests/integration/testsuite/Magento/Framework/Search/Adapter/Mysql/AdapterTest.php b/dev/tests/integration/testsuite/Magento/Framework/Search/Adapter/Mysql/AdapterTest.php
index 9acfa6f1caab150b0a0db2d54e87358adf88cf5b..67a6e416973493887912e2e62674108b1694c315 100644
--- a/dev/tests/integration/testsuite/Magento/Framework/Search/Adapter/Mysql/AdapterTest.php
+++ b/dev/tests/integration/testsuite/Magento/Framework/Search/Adapter/Mysql/AdapterTest.php
@@ -414,6 +414,37 @@ class AdapterTest extends \PHPUnit_Framework_TestCase
         $this->assertEquals($expectedRecordsCount, $queryResponse->count());
     }
 
+    /**
+     * @magentoDataFixture Magento/Framework/Search/_files/product_configurable.php
+     * @magentoConfigFixture current_store catalog/search/engine mysql
+     */
+    public function testAdvancedSearchCompositeProductWithOutOfStockOption()
+    {
+        /** @var \Magento\Catalog\Model\ResourceModel\Eav\Attribute $attribute */
+        $attribute = $this->objectManager->get(\Magento\Catalog\Model\ResourceModel\Eav\Attribute::class)
+            ->loadByCode(\Magento\Catalog\Model\Product::ENTITY, 'test_configurable');
+        /** @var \Magento\Eav\Model\ResourceModel\Entity\Attribute\Option\Collection $selectOptions */
+        $selectOptions = $this->objectManager
+            ->create(\Magento\Eav\Model\ResourceModel\Entity\Attribute\Option\Collection::class)
+            ->setAttributeFilter($attribute->getId());
+
+        $firstOption = $selectOptions->getFirstItem();
+        $firstOptionId = $firstOption->getId();
+        $this->requestBuilder->bind('test_configurable', $firstOptionId);
+        $this->requestBuilder->setRequestName('filter_out_of_stock_child');
+
+        $queryResponse = $this->executeQuery();
+        $this->assertEquals(0, $queryResponse->count());
+
+        $secondOption = $selectOptions->getLastItem();
+        $secondOptionId = $secondOption->getId();
+        $this->requestBuilder->bind('test_configurable', $secondOptionId);
+        $this->requestBuilder->setRequestName('filter_out_of_stock_child');
+
+        $queryResponse = $this->executeQuery();
+        $this->assertEquals(1, $queryResponse->count());
+    }
+
     public function dateDataProvider()
     {
         return [
diff --git a/dev/tests/integration/testsuite/Magento/Framework/Search/_files/configurable_attribute.php b/dev/tests/integration/testsuite/Magento/Framework/Search/_files/configurable_attribute.php
new file mode 100644
index 0000000000000000000000000000000000000000..030e0250c3ec7fed4747aed4e168413207c7daf7
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Framework/Search/_files/configurable_attribute.php
@@ -0,0 +1,61 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+use Magento\TestFramework\Helper\Bootstrap;
+use Magento\Eav\Api\AttributeRepositoryInterface;
+
+$eavConfig = Bootstrap::getObjectManager()->get(\Magento\Eav\Model\Config::class);
+$attribute = $eavConfig->getAttribute('catalog_product', 'test_configurable');
+
+$eavConfig->clear();
+
+/** @var $installer \Magento\Catalog\Setup\CategorySetup */
+$installer = Bootstrap::getObjectManager()->create(\Magento\Catalog\Setup\CategorySetup::class);
+
+if (!$attribute->getId()) {
+
+    /** @var $attribute \Magento\Catalog\Model\ResourceModel\Eav\Attribute */
+    $attribute = Bootstrap::getObjectManager()->create(
+        \Magento\Catalog\Model\ResourceModel\Eav\Attribute::class
+    );
+
+    /** @var AttributeRepositoryInterface $attributeRepository */
+    $attributeRepository = Bootstrap::getObjectManager()->create(AttributeRepositoryInterface::class);
+
+    $attribute->setData(
+        [
+            'attribute_code' => 'test_configurable',
+            'entity_type_id' => $installer->getEntityTypeId('catalog_product'),
+            'is_global' => 1,
+            'is_user_defined' => 1,
+            'frontend_input' => 'select',
+            'is_unique' => 0,
+            'is_required' => 0,
+            'is_searchable' => 1,
+            'is_visible_in_advanced_search' => 1,
+            'is_comparable' => 0,
+            'is_filterable' => 1,
+            'is_filterable_in_search' => 1,
+            'is_used_for_promo_rules' => 0,
+            'is_html_allowed_on_front' => 1,
+            'is_visible_on_front' => 0,
+            'used_in_product_listing' => 0,
+            'used_for_sort_by' => 0,
+            'frontend_label' => ['Test Configurable'],
+            'backend_type' => 'int',
+            'option' => [
+                'value' => ['option_0' => ['Option 1'], 'option_1' => ['Option 2']],
+                'order' => ['option_0' => 1, 'option_1' => 2],
+            ],
+        ]
+    );
+
+    $attributeRepository->save($attribute);
+}
+
+/* Assign attribute to attribute set */
+$installer->addAttributeToGroup('catalog_product', 'Default', 'General', $attribute->getId());
+$eavConfig->clear();
diff --git a/dev/tests/integration/testsuite/Magento/Framework/Search/_files/configurable_attribute_rollback.php b/dev/tests/integration/testsuite/Magento/Framework/Search/_files/configurable_attribute_rollback.php
new file mode 100644
index 0000000000000000000000000000000000000000..bd18100f6d97b4b9b56c9743e8064e0723fdc6c8
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Framework/Search/_files/configurable_attribute_rollback.php
@@ -0,0 +1,28 @@
+<?php
+/**
+ * Copyright © 2016 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::class);
+
+$registry->unregister('isSecureArea');
+$registry->register('isSecureArea', true);
+$productCollection = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()
+    ->get(\Magento\Catalog\Model\ResourceModel\Product\Collection::class);
+foreach ($productCollection as $product) {
+    $product->delete();
+}
+
+$eavConfig = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get(\Magento\Eav\Model\Config::class);
+$attribute = $eavConfig->getAttribute('catalog_product', 'test_configurable');
+if ($attribute instanceof \Magento\Eav\Model\Entity\Attribute\AbstractAttribute
+    && $attribute->getId()
+) {
+    $attribute->delete();
+}
+$eavConfig->clear();
+
+$registry->unregister('isSecureArea');
+$registry->register('isSecureArea', false);
diff --git a/dev/tests/integration/testsuite/Magento/Framework/Search/_files/product_configurable.php b/dev/tests/integration/testsuite/Magento/Framework/Search/_files/product_configurable.php
new file mode 100644
index 0000000000000000000000000000000000000000..590f3c8041c6d819fafa14ef7ddc4d1f2ebccbeb
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Framework/Search/_files/product_configurable.php
@@ -0,0 +1,147 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+use Magento\Catalog\Api\ProductRepositoryInterface;
+use Magento\Catalog\Model\Product;
+use Magento\Catalog\Model\Product\Attribute\Source\Status;
+use Magento\Catalog\Model\Product\Type;
+use Magento\Catalog\Model\Product\Visibility;
+use Magento\Catalog\Setup\CategorySetup;
+use Magento\ConfigurableProduct\Helper\Product\Options\Factory;
+use Magento\ConfigurableProduct\Model\Product\Type\Configurable;
+use Magento\Eav\Api\Data\AttributeOptionInterface;
+use Magento\TestFramework\Helper\Bootstrap;
+
+\Magento\TestFramework\Helper\Bootstrap::getInstance()->reinitialize();
+
+require __DIR__ . '/configurable_attribute.php';
+
+/** @var ProductRepositoryInterface $productRepository */
+$productRepository = Bootstrap::getObjectManager()
+    ->create(ProductRepositoryInterface::class);
+
+/** @var $installer CategorySetup */
+$installer = Bootstrap::getObjectManager()->create(CategorySetup::class);
+
+/* Create simple products per each option value*/
+/** @var AttributeOptionInterface[] $options */
+$options = $attribute->getOptions();
+
+$attributeValues = [];
+$attributeSetId = $installer->getAttributeSetId('catalog_product', 'Default');
+$associatedProductIds = [];
+$productIds = [10, 20];
+array_shift($options); //remove the first option which is empty
+
+$isFirstOption = true;
+foreach ($options as $option) {
+    /** @var $product Product */
+    $product = Bootstrap::getObjectManager()->create(Product::class);
+    $productId = array_shift($productIds);
+    $product->setTypeId(Type::TYPE_SIMPLE)
+        ->setId($productId)
+        ->setAttributeSetId($attributeSetId)
+        ->setWebsiteIds([1])
+        ->setName('Configurable Option' . $option->getLabel())
+        ->setSku('simple_' . $productId)
+        ->setPrice($productId)
+        ->setTestConfigurable($option->getValue())
+        ->setVisibility(Visibility::VISIBILITY_NOT_VISIBLE)
+        ->setStatus(Status::STATUS_ENABLED)
+        ->setStockData(
+            [
+                'use_config_manage_stock' => 1,
+                'qty' => 100,
+                'is_qty_decimal' => 0,
+                'is_in_stock' => (int)!$isFirstOption,
+            ]
+        );
+
+    $product = $productRepository->save($product);
+
+    /** @var \Magento\CatalogInventory\Model\Stock\Item $stockItem */
+    $stockItem = Bootstrap::getObjectManager()->create(\Magento\CatalogInventory\Model\Stock\Item::class);
+    $stockItem->load($productId, 'product_id');
+
+    if (!$stockItem->getProductId()) {
+        $stockItem->setProductId($productId);
+    }
+    $stockItem->setUseConfigManageStock(1);
+    $stockItem->setQty(1000);
+    $stockItem->setIsQtyDecimal(0);
+    $stockItem->setIsInStock((int)!$isFirstOption);
+    $stockItem->save();
+
+    $attributeValues[] = [
+        'label' => 'test',
+        'attribute_id' => $attribute->getId(),
+        'value_index' => $option->getValue(),
+    ];
+    $associatedProductIds[] = $product->getId();
+    $isFirstOption = false;
+}
+
+/** @var $product Product */
+$product = Bootstrap::getObjectManager()->create(Product::class);
+
+/** @var Factory $optionsFactory */
+$optionsFactory = Bootstrap::getObjectManager()->create(Factory::class);
+
+$configurableAttributesData = [
+    [
+        'attribute_id' => $attribute->getId(),
+        'code' => $attribute->getAttributeCode(),
+        'label' => $attribute->getStoreLabel(),
+        'position' => '0',
+        'values' => $attributeValues,
+    ],
+];
+
+$configurableOptions = $optionsFactory->create($configurableAttributesData);
+
+$extensionConfigurableAttributes = $product->getExtensionAttributes();
+$extensionConfigurableAttributes->setConfigurableProductOptions($configurableOptions);
+$extensionConfigurableAttributes->setConfigurableProductLinks($associatedProductIds);
+
+$product->setExtensionAttributes($extensionConfigurableAttributes);
+
+// Remove any previously created product with the same id.
+/** @var \Magento\Framework\Registry $registry */
+$registry = Bootstrap::getObjectManager()->get(\Magento\Framework\Registry::class);
+$registry->unregister('isSecureArea');
+$registry->register('isSecureArea', true);
+try {
+    $productToDelete = $productRepository->getById(1);
+    $productRepository->delete($productToDelete);
+
+    /** @var \Magento\Quote\Model\ResourceModel\Quote\Item $itemResource */
+    $itemResource = Bootstrap::getObjectManager()->get(\Magento\Quote\Model\ResourceModel\Quote\Item::class);
+    $itemResource->getConnection()->delete(
+        $itemResource->getMainTable(),
+        'product_id = ' . $productToDelete->getId()
+    );
+} catch (\Exception $e) {
+    // Nothing to remove
+}
+$registry->unregister('isSecureArea');
+$registry->register('isSecureArea', false);
+
+$product->setTypeId(Configurable::TYPE_CODE)
+    ->setId(1)
+    ->setAttributeSetId($attributeSetId)
+    ->setWebsiteIds([1])
+    ->setName('Configurable Product')
+    ->setSku('configurable')
+    ->setVisibility(Visibility::VISIBILITY_BOTH)
+    ->setStatus(Status::STATUS_ENABLED)
+    ->setStockData(['use_config_manage_stock' => 1, 'is_in_stock' => 1]);
+
+$productRepository->save($product);
+//
+///** @var \Magento\Catalog\Model\Indexer\Product\Eav\Processor $eavIndexer */
+//$eavIndexer = Bootstrap::getObjectManager()
+//    ->get(\Magento\Catalog\Model\Indexer\Product\Eav\Processor::class);
+//$eavIndexer->reindexAll();
diff --git a/dev/tests/integration/testsuite/Magento/Framework/Search/_files/product_configurable_rollback.php b/dev/tests/integration/testsuite/Magento/Framework/Search/_files/product_configurable_rollback.php
new file mode 100644
index 0000000000000000000000000000000000000000..8ba4e3abe21cc14a75a66270d22ea262dffeb788
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Framework/Search/_files/product_configurable_rollback.php
@@ -0,0 +1,36 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
+
+/** @var \Magento\Framework\Registry $registry */
+$registry = $objectManager->get(\Magento\Framework\Registry::class);
+
+$registry->unregister('isSecureArea');
+$registry->register('isSecureArea', true);
+
+/** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository */
+$productRepository = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()
+    ->get(\Magento\Catalog\Api\ProductRepositoryInterface::class);
+
+foreach (['simple_10', 'simple_20', 'configurable'] as $sku) {
+    try {
+        $product = $productRepository->get($sku, false, null, true);
+
+        $stockStatus = $objectManager->create(\Magento\CatalogInventory\Model\Stock\Status::class);
+        $stockStatus->load($product->getEntityId(), 'product_id');
+        $stockStatus->delete();
+
+        $productRepository->delete($product);
+    } catch (\Magento\Framework\Exception\NoSuchEntityException $e) {
+        //Product already removed
+    }
+}
+
+require __DIR__ . '/configurable_attribute_rollback.php';
+
+$registry->unregister('isSecureArea');
+$registry->register('isSecureArea', false);
diff --git a/dev/tests/integration/testsuite/Magento/Framework/Search/_files/requests.xml b/dev/tests/integration/testsuite/Magento/Framework/Search/_files/requests.xml
index 0cdfa11c3b6b5744abbd911e063553cd23039cc5..4cdc9a93e1f1f0ee093b8e0fd8e555a157fce851 100644
--- a/dev/tests/integration/testsuite/Magento/Framework/Search/_files/requests.xml
+++ b/dev/tests/integration/testsuite/Magento/Framework/Search/_files/requests.xml
@@ -387,4 +387,24 @@
         <from>0</from>
         <size>10</size>
     </request>
+    <request query="filter_out_of_stock_child" index="catalogsearch_fulltext">
+        <dimensions>
+            <dimension name="scope" value="default"/>
+        </dimensions>
+        <queries>
+            <query xsi:type="boolQuery" name="filter_out_of_stock_child" boost="1">
+                <queryReference clause="must" ref="test_configurable"/>
+            </query>
+            <query xsi:type="filteredQuery" name="test_configurable">
+                <filterReference clause="must" ref="test_configurable_filter"/>
+            </query>
+        </queries>
+        <filters>
+            <filter xsi:type="termFilter" name="test_configurable_filter" field="test_configurable" value="$test_configurable$"/>
+        </filters>
+        <aggregations/>
+        <from>0</from>
+        <size>10</size>
+    </request>
+
 </requests>
diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/LayoutDirectivesTest.php b/dev/tests/integration/testsuite/Magento/Framework/View/LayoutDirectivesTest.php
index 7a20762bbe9d4493131bb0f2acb8e432a0a9ddbf..607ee4c919a62437cdfaf0d2219248dfc77f7a27 100755
--- a/dev/tests/integration/testsuite/Magento/Framework/View/LayoutDirectivesTest.php
+++ b/dev/tests/integration/testsuite/Magento/Framework/View/LayoutDirectivesTest.php
@@ -198,6 +198,18 @@ class LayoutDirectivesTest extends \PHPUnit_Framework_TestCase
         $this->assertTrue($layout->isBlock('child_block2'));
     }
 
+    /**
+     * @magentoAppIsolation enabled
+     */
+    public function testRemoveCancellation()
+    {
+        $layout = $this->_getLayoutModel('remove_cancellation.xml');
+        $this->assertTrue($layout->isContainer('container1'));
+        $this->assertTrue($layout->isBlock('child_block1'));
+        $this->assertTrue($layout->isBlock('no_name2'));
+        $this->assertFalse($layout->getBlock('not_exist'));
+    }
+
     /**
      * @magentoAppIsolation enabled
      */
diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/remove_cancellation.xml b/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/remove_cancellation.xml
new file mode 100644
index 0000000000000000000000000000000000000000..ff086b19fd1b02d80ffc849d9563bdb9419ae75e
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/remove_cancellation.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0"?>
+<!--
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+-->
+<layout>
+    <container name="container1" label="Container 1">
+        <block class="Magento\Framework\View\Element\Text" name="no_name2"/>
+    </container>
+    <referenceContainer name="container1" remove="true"/>
+    <referenceBlock name="child_block1" remove="true"/>
+    <block class="Magento\Framework\View\Element\Text" name="block_container" as="block.container">
+        <block class="Magento\Framework\View\Element\Text" name="child_block1"/>
+        <block class="Magento\Framework\View\Element\Text" name="child_block2"/>
+    </block>
+    <referenceContainer name="not_exist" remove="false"/>
+    <referenceContainer name="container1" remove="false"/>
+    <referenceBlock name="child_block1" remove="false"/>
+</layout>
diff --git a/dev/tests/integration/testsuite/Magento/Paypal/Model/Config/Structure/Reader/_files/expected/config.xml b/dev/tests/integration/testsuite/Magento/Paypal/Model/Config/Structure/Reader/_files/expected/config.xml
index f9f8f1ffba91a55536c9d2221b68dc85b702e7f0..19feb33748c840b6c87f506ffd450897e2ace286 100644
--- a/dev/tests/integration/testsuite/Magento/Paypal/Model/Config/Structure/Reader/_files/expected/config.xml
+++ b/dev/tests/integration/testsuite/Magento/Paypal/Model/Config/Structure/Reader/_files/expected/config.xml
@@ -593,7 +593,8 @@
                         <label>Express Checkout</label>
                         <frontend_model>Magento\Paypal\Block\Adminhtml\System\Config\Fieldset\Expanded</frontend_model>
                         <field id="business_account" translate="label comment tooltip" showInDefault="1" showInWebsite="1" sortOrder="5">
-                            <label>Email Associated with PayPal Merchant Account</label>
+                            <label>Email Associated with PayPal Merchant Account (Optional)</label>
+                            <frontend_class>not-required</frontend_class>
                             <comment>
                                 <![CDATA[<a href="http://www.magentocommerce.com/paypal">Start accepting payments via PayPal!</a>]]>
                             </comment>
diff --git a/dev/tests/integration/testsuite/Magento/Quote/Model/QuoteTest.php b/dev/tests/integration/testsuite/Magento/Quote/Model/QuoteTest.php
index da035c8eec78f8a547defd548f5cc93b10d474a6..8f295077afe330076e265c555cae280294cdd9f6 100644
--- a/dev/tests/integration/testsuite/Magento/Quote/Model/QuoteTest.php
+++ b/dev/tests/integration/testsuite/Magento/Quote/Model/QuoteTest.php
@@ -404,4 +404,23 @@ class QuoteTest extends \PHPUnit_Framework_TestCase
             \Magento\Customer\Model\Data\Customer::WEBSITE_ID => 1
         ];
     }
+
+    /**
+     * Test to verify that reserved_order_id will be changed if it already in used
+     *
+     * @magentoDataFixture Magento/Sales/_files/order.php
+     * @magentoDataFixture Magento/Quote/_files/empty_quote.php
+     */
+    public function testReserveOrderId()
+    {
+        $objectManager = Bootstrap::getObjectManager();
+        /** @var \Magento\Quote\Model\Quote  $quote */
+        $quote = $objectManager->create(\Magento\Quote\Model\Quote::class);
+        $quote->load('reserved_order_id', 'reserved_order_id');
+        $quote->reserveOrderId();
+        $this->assertEquals('reserved_order_id', $quote->getReservedOrderId());
+        $quote->setReservedOrderId('100000001');
+        $quote->reserveOrderId();
+        $this->assertNotEquals('100000001', $quote->getReservedOrderId());
+    }
 }
diff --git a/dev/tests/integration/testsuite/Magento/Quote/Model/ResourceModel/QuoteTest.php b/dev/tests/integration/testsuite/Magento/Quote/Model/ResourceModel/QuoteTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..43ee0893b75f9cc93bdca626d87d5592eefd62aa
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Quote/Model/ResourceModel/QuoteTest.php
@@ -0,0 +1,45 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Quote\Model\ResourceModel;
+
+/**
+ * Class QuoteTest to verify isOrderIncrementIdUsed method behaviour
+ */
+class QuoteTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\Quote\Model\ResourceModel\Quote
+     */
+    private $_resourceModel;
+
+    protected function setUp()
+    {
+        $this->_resourceModel = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
+            \Magento\Quote\Model\ResourceModel\Quote::class
+        );
+    }
+
+    /**
+     * Test to verify if isOrderIncrementIdUsed method works with numeric increment ids
+     *
+     * @magentoDataFixture Magento/Sales/_files/order.php
+     */
+    public function testIsOrderIncrementIdUsedNumericIncrementId()
+    {
+        $this->assertTrue($this->_resourceModel->isOrderIncrementIdUsed('100000001'));
+    }
+
+    /**
+     * Test to verify if isOrderIncrementIdUsed method works with alphanumeric increment ids
+     *
+     * @magentoDataFixture Magento/Sales/_files/order_alphanumeric_id.php
+     */
+    public function testIsOrderIncrementIdUsedAlphanumericIncrementId()
+    {
+        $this->assertTrue($this->_resourceModel->isOrderIncrementIdUsed('M00000001'));
+    }
+}
diff --git a/dev/tests/integration/testsuite/Magento/SalesRule/Model/Quote/Address/Total/ShippingTest.php b/dev/tests/integration/testsuite/Magento/SalesRule/Model/Quote/Address/Total/ShippingTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..543d02e42067483a56ee1b31d084a7e02c18952f
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/SalesRule/Model/Quote/Address/Total/ShippingTest.php
@@ -0,0 +1,106 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\SalesRule\Model\Quote\Address\Total;
+
+class ShippingTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\Quote\Api\GuestCartManagementInterface
+     */
+    private $cartManagement;
+
+    /**
+     * @var \Magento\Quote\Api\GuestCartItemRepositoryInterface
+     */
+    private $itemRepository;
+
+    /**
+     * @var \Magento\Framework\ObjectManagerInterface
+     */
+    private $objectManager;
+
+    protected function setUp()
+    {
+        $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
+        $this->cartManagement = $this->objectManager->get(\Magento\Quote\Api\GuestCartManagementInterface::class);
+        $this->itemRepository = $this->objectManager->get(\Magento\Quote\Api\GuestCartItemRepositoryInterface::class);
+    }
+
+    /**
+     * @magentoDataFixture Magento/SalesRule/_files/rule_free_shipping_by_product_weight.php
+     * @magentoDataFixture Magento/Catalog/_files/product_simple.php
+     */
+    public function testRuleByProductWeightWithFreeShipping()
+    {
+        $cartId = $this->prepareQuote(1);
+        $methods = $this->estimateShipping($cartId);
+
+        $this->assertTrue(count($methods) > 0);
+        $this->assertEquals('flatrate', $methods[0]->getMethodCode());
+        $this->assertEquals(0, $methods[0]->getAmount());
+
+    }
+
+    /**
+     * @magentoDataFixture Magento/SalesRule/_files/rule_free_shipping_by_product_weight.php
+     * @magentoDataFixture Magento/Catalog/_files/product_simple.php
+     */
+    public function testRuleByProductWeightWithoutFreeShipping()
+    {
+        $cartId = $this->prepareQuote(5);
+        $methods = $this->estimateShipping($cartId);
+
+        $this->assertTrue(count($methods) > 0);
+        $this->assertEquals('flatrate', $methods[0]->getMethodCode());
+        $this->assertEquals(25, $methods[0]->getAmount());
+
+    }
+
+    /**
+     * Estimate shipment for guest cart
+     *
+     * @param int $cartId
+     * @return \Magento\Quote\Api\Data\ShippingMethodInterface[]
+     */
+    private function estimateShipping($cartId)
+    {
+        $addressFactory = $this->objectManager->get(\Magento\Quote\Api\Data\AddressInterfaceFactory::class);
+        /** @var \Magento\Quote\Api\Data\AddressInterface $address */
+        $address = $addressFactory->create();
+        $address->setCountryId('US');
+        $address->setRegionId(2);
+
+        /** @var \Magento\Quote\Api\GuestShipmentEstimationInterface $estimation */
+        $estimation = $this->objectManager->get(\Magento\Quote\Api\GuestShipmentEstimationInterface::class);
+        return $estimation->estimateByExtendedAddress($cartId, $address);
+    }
+
+    /**
+     * Create guest quote with products
+     *
+     * @param int $itemQty
+     * @return int
+     */
+    private function prepareQuote($itemQty)
+    {
+        $cartId = $this->cartManagement->createEmptyCart();
+
+        /** @var \Magento\Quote\Api\Data\CartItemInterfaceFactory $cartItemFactory */
+        $cartItemFactory = $this->objectManager->get(\Magento\Quote\Api\Data\CartItemInterfaceFactory::class);
+
+        /** @var \Magento\Quote\Api\Data\CartItemInterface $cartItem */
+        $cartItem = $cartItemFactory->create();
+        $cartItem->setQuoteId($cartId);
+        $cartItem->setQty($itemQty);
+        $cartItem->setSku('simple');
+        $cartItem->setProductType(\Magento\Catalog\Model\Product\Type::TYPE_SIMPLE);
+
+        $this->itemRepository->save($cartItem);
+
+        return $cartId;
+    }
+}
diff --git a/dev/tests/integration/testsuite/Magento/SalesRule/_files/rule_free_shipping_by_product_weight.php b/dev/tests/integration/testsuite/Magento/SalesRule/_files/rule_free_shipping_by_product_weight.php
new file mode 100644
index 0000000000000000000000000000000000000000..d59f63d2f313601b06bafdac7287501980e20b37
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/SalesRule/_files/rule_free_shipping_by_product_weight.php
@@ -0,0 +1,35 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+require 'cart_rule_free_shipping.php';
+$row =
+    [
+        'name' => 'Free shipping if item weight <= 1',
+        'conditions' => [
+            1 =>
+                [
+                    'type' => \Magento\SalesRule\Model\Rule\Condition\Combine::class,
+                    'attribute' => null,
+                    'operator' => null,
+                    'value' => '1',
+                    'is_value_processed' => null,
+                    'aggregator' => 'all',
+                    'conditions' => [
+                        [
+                            'type' => Magento\SalesRule\Model\Rule\Condition\Address::class,
+                            'attribute' => 'weight',
+                            'operator' => '<=',
+                            'value' => '1',
+                            'is_value_processed' => false,
+                        ]
+                    ]
+                ]
+
+        ],
+        'actions' => [],
+    ];
+$salesRule->loadPost($row);
+$salesRule->save();
diff --git a/dev/tests/integration/testsuite/Magento/Setup/Console/Command/_files/root/app/code/Magento/A/composer.json b/dev/tests/integration/testsuite/Magento/Setup/Console/Command/_files/root/app/code/Magento/A/composer.json
index 222e5ff822b043185e44719804e0af75d8809c6e..a004d3a86b5b9d0c68ec096ab8beff48fa1e51c5 100644
--- a/dev/tests/integration/testsuite/Magento/Setup/Console/Command/_files/root/app/code/Magento/A/composer.json
+++ b/dev/tests/integration/testsuite/Magento/Setup/Console/Command/_files/root/app/code/Magento/A/composer.json
@@ -1,7 +1,7 @@
 {
     "name": "magento/module-a",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/framework": "0.1",
         "magento/module-b": "0.1"
     },
diff --git a/dev/tests/integration/testsuite/Magento/Setup/Console/Command/_files/root/app/code/Magento/B/composer.json b/dev/tests/integration/testsuite/Magento/Setup/Console/Command/_files/root/app/code/Magento/B/composer.json
index 57944758267fd668f541b34586a8eb9f7acd9c98..0626cc6a84d055757c32d9192cc7f2682696912f 100644
--- a/dev/tests/integration/testsuite/Magento/Setup/Console/Command/_files/root/app/code/Magento/B/composer.json
+++ b/dev/tests/integration/testsuite/Magento/Setup/Console/Command/_files/root/app/code/Magento/B/composer.json
@@ -1,7 +1,7 @@
 {
     "name": "magento/module-b",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/framework": "0.74.0-beta6",
         "magento/module-a": "0.1"
     },
diff --git a/dev/tests/integration/testsuite/Magento/Setup/Controller/UrlCheckTest.php b/dev/tests/integration/testsuite/Magento/Setup/Controller/UrlCheckTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..6fe9ec2ee3ea13ef4b2b5881e4970f7aa99e9447
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Setup/Controller/UrlCheckTest.php
@@ -0,0 +1,98 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Setup\Controller;
+
+use Magento\TestFramework\Helper\Bootstrap;
+use Zend\Stdlib\RequestInterface as Request;
+use Zend\View\Model\JsonModel;
+
+class UrlCheckTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var UrlCheck
+     */
+    private $controller;
+
+    protected function setUp()
+    {
+        $this->controller = Bootstrap::getObjectManager()->create(UrlCheck::class);
+    }
+
+    /**
+     * @param array $requestContent
+     * @param bool $successUrl
+     * @param bool $successSecureUrl
+     * @return void
+     * @dataProvider indexActionDataProvider
+     */
+    public function testIndexAction($requestContent, $successUrl, $successSecureUrl)
+    {
+        $requestMock = $this->getMockBuilder(Request::class)
+            ->getMockForAbstractClass();
+        $requestMock->expects($this->once())
+            ->method('getContent')
+            ->willReturn(json_encode($requestContent));
+
+        $requestProperty = new \ReflectionProperty(get_class($this->controller), 'request');
+        $requestProperty->setAccessible(true);
+        $requestProperty->setValue($this->controller, $requestMock);
+
+        $resultModel = new JsonModel(['successUrl' => $successUrl, 'successSecureUrl' => $successSecureUrl]);
+
+        $this->assertEquals($resultModel, $this->controller->indexAction());
+    }
+
+    /**
+     * @return array
+     */
+    public function indexActionDataProvider()
+    {
+        return [
+            [
+                'requestContent' => [
+                    'address' => [
+                        'actual_base_url' => 'http://example.com/'
+                    ],
+                    'https' => [
+                        'text' => 'https://example.com/',
+                        'admin' => true,
+                        'front' => false
+                    ],
+                ],
+                'successUrl' => true,
+                'successSecureUrl' => true
+            ],
+            [
+                'requestContent' => [
+                    'address' => [
+                        'actual_base_url' => 'http://example.com/folder/'
+                    ],
+                    'https' => [
+                        'text' => 'https://example.com/folder_name/',
+                        'admin' => false,
+                        'front' => true
+                    ],
+                ],
+                'successUrl' => true,
+                'successSecureUrl' => true
+            ],
+            [
+                'requestContent' => [
+                    'address' => [
+                        'actual_base_url' => 'ftp://example.com/'
+                    ],
+                    'https' => [
+                        'text' => 'https://example.com_test/',
+                        'admin' => true,
+                        'front' => true
+                    ],
+                ],
+                'successUrl' => false,
+                'successSecureUrl' => false
+            ],
+        ];
+    }
+}
diff --git a/dev/tests/integration/testsuite/Magento/Widget/_files/design/adminhtml/magento_basic/composer.json b/dev/tests/integration/testsuite/Magento/Widget/_files/design/adminhtml/magento_basic/composer.json
index 920dc1289b0cfa00cd696b35fb495434830850f6..47f9eb415d7badb00345e5436e2c10bd64532c2f 100644
--- a/dev/tests/integration/testsuite/Magento/Widget/_files/design/adminhtml/magento_basic/composer.json
+++ b/dev/tests/integration/testsuite/Magento/Widget/_files/design/adminhtml/magento_basic/composer.json
@@ -2,7 +2,7 @@
     "name": "magento/admin-Magento_Catalog",
     "description": "N/A",
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "magento/framework": "0.1.0-alpha103"
     },
     "type": "magento2-theme",
diff --git a/dev/tests/js/JsTestDriver/run_js_tests.php b/dev/tests/js/JsTestDriver/run_js_tests.php
index e6578c52b0699ee334c2f0ce9213ec5f78373330..448fd85869cd28dea34d7a00384838674f086c5a 100644
--- a/dev/tests/js/JsTestDriver/run_js_tests.php
+++ b/dev/tests/js/JsTestDriver/run_js_tests.php
@@ -30,6 +30,8 @@ if (isset($config['Browser'])) {
 } else {
     if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
         $browser = 'C:\Program Files (x86)\Mozilla Firefox\firefox.exe';
+    } elseif (PHP_OS === 'Darwin') {
+        $browser = '/Applications/Firefox.app/Contents/MacOS/firefox';
     } else {
         $browser = exec('which firefox');
     }
@@ -139,29 +141,35 @@ if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
             kill -9 $LSOF
         fi
 
-        DISPLAY_NUM=99
-        ps -ef | egrep "[X]vfb.*:$DISPLAY_NUM"
-        if [ $? -eq 0 ] ; then
-            pkill Xvfb
+        # Skip Xvfb setup for OS X since there browsers do not support headless display that way
+        if [ "$(uname)" != "Darwin" ]; then
+            DISPLAY_NUM=99
+            ps -ef | egrep "[X]vfb.*:$DISPLAY_NUM"
+            if [ $? -eq 0 ] ; then
+                pkill Xvfb
+            fi
+    
+            XVFB=`which Xvfb`
+            if [ "$?" -eq 1 ];
+            then
+                echo "Xvfb not found."
+                exit 1
+            fi
+    
+            $XVFB :$DISPLAY_NUM -nolisten inet6 -ac &
+            PID_XVFB="$!"        # take the process ID
+            export DISPLAY=:$DISPLAY_NUM   # set display to use that of the Xvfb
         fi
-
-        XVFB=`which Xvfb`
-        if [ "$?" -eq 1 ];
-        then
-            echo "Xvfb not found."
-            exit 1
-        fi
-
-        $XVFB :$DISPLAY_NUM -nolisten inet6 -ac &
-        PID_XVFB="$!"        # take the process ID
-        export DISPLAY=:$DISPLAY_NUM   # set display to use that of the Xvfb
+        
         USER=`whoami`
         SUDO=`which sudo`
 
         # run the tests
         $SUDO -u $USER ' . $command . '
 
-        kill -9 $PID_XVFB    # shut down Xvfb (firefox will shut down cleanly by JsTestDriver)
+        if [ "$(uname)" != "Darwin" ]; then
+            kill -9 $PID_XVFB    # shut down Xvfb (firefox will shut down cleanly by JsTestDriver)
+        fi
         echo "Done."';
 
     fwrite($fh, $shellCommand . PHP_EOL);
diff --git a/dev/tests/js/jasmine/spec_runner/index.js b/dev/tests/js/jasmine/spec_runner/index.js
index ce57b6c354cb98a4ab48e6043fc8648d8f9f040b..d8329bb35178fefc23ca9d68fc4047a432e98a31 100644
--- a/dev/tests/js/jasmine/spec_runner/index.js
+++ b/dev/tests/js/jasmine/spec_runner/index.js
@@ -13,38 +13,14 @@ function init(grunt, options) {
         stripJsonComments   = require('strip-json-comments'),
         path                = require('path'),
         config,
-        themes;
-        
+        themes,
+        file;
+
     config = grunt.file.read(__dirname + '/settings.json');
     config = stripJsonComments(config);
     config = JSON.parse(config);
 
-    //themes = require(path.resolve(process.cwd(), config.themes));
-    //TODO: MAGETWO-39843
-    themes = {
-        blank: {
-            area: 'frontend',
-            name: 'Magento/blank',
-            locale: 'en_US',
-            files: [
-                'css/styles-m',
-                'css/styles-l',
-                'css/email',
-                'css/email-inline'
-            ],
-            dsl: 'less'
-        },
-        backend: {
-            area: 'adminhtml',
-            name: 'Magento/backend',
-            locale: 'en_US',
-            files: [
-                'css/styles-old',
-                'css/styles'
-            ],
-            dsl: 'less'
-        }
-    }
+    themes = require(path.resolve(process.cwd(), config.themes));
 
     if (options.theme) {
         themes = _.pick(themes, options.theme);
@@ -54,6 +30,12 @@ function init(grunt, options) {
 
     config.themes = themes;
 
+    file = grunt.option('file');
+
+    if (file) {
+        config.singleTest = file;
+    }
+
     enableTasks(grunt, config);
 }
 
diff --git a/dev/tests/js/jasmine/spec_runner/tasks/jasmine.js b/dev/tests/js/jasmine/spec_runner/tasks/jasmine.js
index 5d520860f44105371984c918ddd643f1f05c1611..99f05198000ec2d3b400c4f8269435e40a7d3fe7 100644
--- a/dev/tests/js/jasmine/spec_runner/tasks/jasmine.js
+++ b/dev/tests/js/jasmine/spec_runner/tasks/jasmine.js
@@ -16,7 +16,6 @@ function init(config) {
     root         = config.root;
     port         = config.port;
     files        = config.files;
-    host         = _.template(config.host)({ port: port });
     themes       = config.themes;
 
     _.each(themes, function (themeData, themeName) {
@@ -26,7 +25,13 @@ function init(config) {
 
         _.extend(themeData, { root: root });
 
+        host    = _.template(config.host)({ port: port++ });
         render  = renderTemplate.bind(null, themeData);
+
+        if (config.singleTest) {
+            files.specs = [config.singleTest];
+        }
+
         specs   = files.specs.map(render);
         specs   = expand(specs).map(cutJsExtension);
         configs = files.requirejsConfigs.map(render);
@@ -37,6 +42,10 @@ function init(config) {
                 host: host,
                 template: render(files.template),
                 vendor: files.requireJs,
+                junit: {
+                    path: "var/log/js-unit/",
+                    consolidate: true
+                },
 
                 /**
                  * @todo rename "helpers" to "specs" (implies overriding grunt-contrib-jasmine code)
diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/components/collection/item.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/components/collection/item.test.js
index 806964352be5f23ea088d91b683400d00020c342..6fbbc63af473c36baa9f5c7fdf55d2e0fa6b907c 100644
--- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/components/collection/item.test.js
+++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/components/collection/item.test.js
@@ -21,38 +21,6 @@ define([
             index: ''
         });
 
-        registry.set('provName', {
-            on: function () {
-            },
-            get: function () {
-            },
-            set: function () {
-            }
-        });
-
-        describe('"initProperties" method', function () {
-            it('Check for defined ', function () {
-                expect(obj.hasOwnProperty('initProperties')).toBeDefined();
-            });
-            it('Check answer type', function () {
-                var type = typeof obj.initProperties;
-
-                expect(type).toEqual('function');
-            });
-            it('Check returned value if method called without arguments', function () {
-                expect(obj.initProperties()).toBeDefined();
-            });
-            it('Check returned value type if method called without arguments', function () {
-                var type = typeof obj.initProperties();
-
-                expect(type).toEqual('object');
-            });
-            it('Check "displayed" property', function () {
-                obj.displayed = null;
-                obj.initProperties();
-                expect(obj.displayed).toEqual([]);
-            });
-        });
         describe('"initObservable" method', function () {
             it('Check for defined ', function () {
                 expect(obj.hasOwnProperty('initObservable')).toBeDefined();
@@ -178,16 +146,23 @@ define([
                     prefix: 'magento'
                 };
 
+                obj.getPreview = jasmine.createSpy().and.callFake(function () {
+                    return [];
+                });
+
                 expect(obj.buildPreview(arg)).toBeDefined();
             });
             it('Check returned value type if method called with object argument', function () {
                 var arg = {
                         items: [],
                         prefix: 'magento'
-                    },
-                    type = typeof obj.buildPreview(arg);
+                    };
+
+                obj.getPreview = jasmine.createSpy().and.callFake(function () {
+                    return [];
+                });
 
-                expect(type).toEqual('string');
+                expect(typeof obj.buildPreview(arg)).toEqual('string');
             });
             it('Check called "this.getPreview" method with object argument', function () {
                 var arg = {
diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/components/tab.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/components/tab.test.js
index 56449c04406a08f0a8a5bc021726322ecd13bd59..10c9e5d35daeddeb16fa89b928f357b7770bdd66 100644
--- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/components/tab.test.js
+++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/components/tab.test.js
@@ -56,23 +56,6 @@ define([
                 expect(obj.observe).toHaveBeenCalled();
             });
         });
-        describe('"onUniqueUpdate" method', function () {
-            it('Check for defined ', function () {
-                expect(obj.hasOwnProperty('onUniqueUpdate')).toBeDefined();
-            });
-            it('Check method type', function () {
-                var type = typeof obj.onUniqueUpdate;
-
-                expect(type).toEqual('function');
-            });
-            it('Check called "this.trigger" inner onUniqueUpdate method', function () {
-                obj.trigger = jasmine.createSpy().and.callFake(function () {
-                    return obj;
-                });
-                obj.onUniqueUpdate();
-                expect(obj.trigger).toHaveBeenCalled();
-            });
-        });
         describe('"activate" method', function () {
             it('Check for defined ', function () {
                 expect(obj.hasOwnProperty('activate')).toBeDefined();
diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/components/tab_group.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/components/tab_group.test.js
index 173e803b14a2151df665ebd97bd145cf374f26ee..311b023a003a85fba8f8d4a7beb89f8cb65dce04 100644
--- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/components/tab_group.test.js
+++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/components/tab_group.test.js
@@ -23,14 +23,6 @@ define([
         });
 
         window.FORM_KEY = 'magentoFormKey';
-        registry.set('provName', {
-            on: function () {
-            },
-            get: function () {
-            },
-            set: function () {
-            }
-        });
 
         describe('"initElement" method', function () {
             it('Check for defined ', function () {
@@ -48,6 +40,8 @@ define([
                     on: function () {
                     },
                     active: function () {
+                    },
+                    activate: function () {
                     }
                 };
 
@@ -60,6 +54,8 @@ define([
                         on: function () {
                         },
                         active: function () {
+                        },
+                        activate: function () {
                         }
                     },
                     type = typeof obj.initElement(arg);
@@ -83,6 +79,8 @@ define([
                     on: function () {
                     },
                     active: function () {
+                    },
+                    activate: function () {
                     }
                 };
 
@@ -95,6 +93,8 @@ define([
                         on: function () {
                         },
                         active: function () {
+                        },
+                        activate: function () {
                         }
                     },
                     type = typeof obj.initActivation(arg);
@@ -119,6 +119,8 @@ define([
                     },
                     active: function () {
                     },
+                    activate: function () {
+                    },
                     delegate: jasmine.createSpy()
                 };
 
@@ -150,7 +152,7 @@ define([
                     return [];
                 });
                 obj.onValidate();
-                expect(obj.validate.calls.count()).toBe(3);
+                expect(obj.validate.calls.count()).toBe(1);
             });
         });
     });
diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/abstract.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/abstract.test.js
index 0923d84fce5ff0e39149219a2ba951dcc1b6ebf9..7730bc72f7af6e35ffea47a4e2c6831328672dcc 100644
--- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/abstract.test.js
+++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/abstract.test.js
@@ -43,17 +43,6 @@ define([
                 expect(model.validation).toEqual({});
             });
         });
-        describe('initProperties method', function () {
-            it('check for chainable', function () {
-                expect(model.initProperties()).toEqual(model);
-            });
-            it('check for extend', function () {
-                model.initProperties();
-                expect(model.uid).toBeDefined();
-                expect(model.noticeId).toBeDefined();
-                expect(model.inputName).toBeDefined();
-            });
-        });
         describe('setInitialValue method', function () {
             it('check for chainable', function () {
                 expect(model.setInitialValue()).toEqual(model);
@@ -78,15 +67,23 @@ define([
                 expect(model.additionalClasses).toEqual(1);
             });
             it('check for empty additional class', function () {
+                var expectedResult = {
+                    _required: model.required,
+                    _warn: model.warn,
+                    _error: model.error,
+                    _disabled: model.disabled
+                };
+
                 model.additionalClasses = '';
 
                 expect(model._setClasses()).toEqual(model);
-                expect(model.additionalClasses).toEqual('');
+                expect(model.additionalClasses).toEqual(expectedResult);
             });
             it('check for one class in additional', function () {
                 var extendObject = {
                     simple: true,
-                    required: model.required,
+                    _required: model.required,
+                    _warn: model.warn,
                     _error: model.error,
                     _disabled: model.disabled
                 };
@@ -98,7 +95,8 @@ define([
             it('check for one class with spaces in additional', function () {
                 var extendObject = {
                     simple: true,
-                    required: model.required,
+                    _required: model.required,
+                    _warn: model.warn,
                     _error: model.error,
                     _disabled: model.disabled
                 };
@@ -111,7 +109,8 @@ define([
                 var extendObject = {
                     simple: true,
                     example: true,
-                    required: model.required,
+                    _required: model.required,
+                    _warn: model.warn,
                     _error: model.error,
                     _disabled: model.disabled
                 };
@@ -124,7 +123,8 @@ define([
                 var extendObject = {
                     simple: true,
                     example: true,
-                    required: model.required,
+                    _required: model.required,
+                    _warn: model.warn,
                     _error: model.error,
                     _disabled: model.disabled
                 };
@@ -139,10 +139,8 @@ define([
                 expect(model.getInitialValue()).toEqual('');
             });
             it('check with default value', function () {
-                var expected = 1;
-
-                model.default = expected;
-                expect(model.getInitialValue()).toEqual(expected);
+                model.default = 1;
+                expect(model.getInitialValue()).toEqual('');
             });
             it('check with value', function () {
                 var expected = 1;
diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/date.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/date.test.js
index 632fef3d841d1becdc65ff4e8ddfdcc553a3557f..de6b83eaf2005d06c324c3b7da997b541d305522 100644
--- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/date.test.js
+++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/date.test.js
@@ -19,33 +19,5 @@ define([
             };
             model = new DateElement(params);
         });
-
-        describe('getInitialValue method', function () {
-            it('check for default', function () {
-                expect(model.getInitialValue()).toEqual('');
-            });
-            it('check with default value', function () {
-                model.default = 1;
-                expect(model.getInitialValue()).toEqual('01/01/1970');
-            });
-            it('check with value', function () {
-                model.value(1);
-                expect(model.getInitialValue()).toEqual('01/01/1970');
-            });
-            it('check with value and default', function () {
-                model.default = 1;
-                model.value(0);
-                expect(model.getInitialValue()).toEqual(0);
-            });
-        });
-        describe('initProperties method', function () {
-            it('check for chainable', function () {
-                expect(model.initProperties()).toEqual(model);
-            });
-            it('check for extend', function () {
-                model.initProperties();
-                expect(model.dateFormat).toBeDefined();
-            });
-        });
     });
 });
diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/multiselect.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/multiselect.test.js
deleted file mode 100644
index 09f21f6b175ee21661cc8138ae319fc9be98bd14..0000000000000000000000000000000000000000
--- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/multiselect.test.js
+++ /dev/null
@@ -1,47 +0,0 @@
-/**
- * Copyright © 2016 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-
-/*eslint max-nested-callbacks: 0*/
-
-define([
-    'Magento_Ui/js/form/element/multiselect'
-], function (MultiselectElement) {
-    'use strict';
-
-    describe('Magento_Ui/js/form/element/multiselect', function () {
-        var params, model;
-
-        beforeEach(function () {
-            params = {
-                dataScope: 'multiselect'
-            };
-            model = new MultiselectElement(params);
-        });
-
-        describe('getInitialValue method', function () {
-            it('check for default', function () {
-                expect(model.getInitialValue()).toEqual(undefined);
-            });
-            it('check with default value', function () {
-                model.indexedOptions = {
-                    Select: {
-                        value: 'value'
-                    }
-                };
-                model.default = 'Select';
-                expect(model.getInitialValue()).toEqual(['value']);
-            });
-            it('check with value', function () {
-                model.indexedOptions = {
-                    Select: {
-                        value: 'value'
-                    }
-                };
-                model.value('Select');
-                expect(model.getInitialValue()).toEqual(['value']);
-            });
-        });
-    });
-});
diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/select.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/select.test.js
index 6ce3428a6cb35f4a15063de0ba26e3612e1605d2..db5855b0a692bb7ac0c9b75de35d228abe309016 100644
--- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/select.test.js
+++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/select.test.js
@@ -52,64 +52,6 @@ define([
             it('check for chainable', function () {
                 expect(model.initConfig({})).toEqual(model);
             });
-            it('check with empty value and caption', function () {
-                var config = {
-                    options: [{
-                        label: 'Caption',
-                        value: null
-                    }, {
-                        label: 'Some label',
-                        value: 'Some value'
-                    }],
-                    caption: 'Main caption'
-                },
-                expected = {
-                    options: [config.options[1]],
-                    caption: config.caption
-                };
-
-                expect(model.initConfig(config)).toEqual(model);
-                expect(config).toEqual(expected);
-            });
-            it('check with empty value', function () {
-                var config = {
-                        options: [{
-                            label: 'Caption',
-                            value: null
-                        }, {
-                            label: 'Some label',
-                            value: 'Some value'
-                        }]
-                    },
-                    expected = {
-                        options: [config.options[1]],
-                        caption: config.options[0].label
-                    };
-
-                expect(model.initConfig(config)).toEqual(model);
-                expect(config).toEqual(expected);
-            });
-            it('check with multiple empty value', function () {
-                var config = {
-                        options: [{
-                            label: 'Caption',
-                            value: null
-                        }, {
-                            label: 'Some label',
-                            value: 'Some value'
-                        }, {
-                            label: 'Another caption',
-                            value: null
-                        }]
-                    },
-                    expected = {
-                        options: [config.options[1]],
-                        caption: config.options[0].label
-                    };
-
-                expect(model.initConfig(config)).toEqual(model);
-                expect(config).toEqual(expected);
-            });
         });
         describe('initObservable method', function () {
             it('check for chainable', function () {
diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/form.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/form.test.js
index 5a32d5c991e3e06b50647c03057a3cc19ac1239f..88203afba331333193482a79c3e061202e93a2b4 100644
--- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/form.test.js
+++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/form.test.js
@@ -67,26 +67,26 @@ define([
                 expect(type).toEqual('object');
             });
         });
-        describe('"initProperties" method', function () {
+        describe('"initConfig" method', function () {
             it('Check for defined ', function () {
-                expect(obj.hasOwnProperty('initProperties')).toBeDefined();
+                expect(obj.hasOwnProperty('initConfig')).toBeDefined();
             });
             it('Check method type', function () {
-                var type = typeof obj.initProperties;
+                var type = typeof obj.initConfig;
 
                 expect(type).toEqual('function');
             });
             it('Check returned value if method called without arguments', function () {
-                expect(obj.initProperties()).toBeDefined();
+                expect(obj.initConfig()).toBeDefined();
             });
             it('Check returned value type if method called without arguments', function () {
-                var type = typeof obj.initProperties();
+                var type = typeof obj.initConfig();
 
                 expect(type).toEqual('object');
             });
-            it('Check this.selector property (is modify in initProperties method)', function () {
+            it('Check this.selector property (is modify in initConfig method)', function () {
                 obj.selector = null;
-                obj.initProperties();
+                obj.initConfig();
                 expect(typeof obj.selector).toEqual('string');
             });
         });
@@ -117,33 +117,6 @@ define([
 
                 expect(type).toEqual('function');
             });
-            it('Check call method "this.validate" inner save method', function () {
-                obj.validate = jasmine.createSpy();
-                obj.source.get = jasmine.createSpy().and.callFake(function () {
-                    return true;
-                });
-                obj.save();
-                expect(obj.validate).toHaveBeenCalled();
-            });
-            it('Check call method "this.source.get" inner save method', function () {
-                obj.validate = jasmine.createSpy();
-                obj.source.get = jasmine.createSpy().and.callFake(function () {
-                    return true;
-                });
-                obj.save();
-                expect(obj.source.get).toHaveBeenCalled();
-            });
-            it('Check call method "this.submit" inner save method', function () {
-                obj.validate = jasmine.createSpy();
-                obj.source.get = jasmine.createSpy().and.callFake(function () {
-                    return false;
-                });
-                obj.submit = jasmine.createSpy().and.callFake(function () {
-                    return true;
-                });
-                obj.save();
-                expect(obj.source.get).toHaveBeenCalled();
-            });
         });
         describe('"submit" method', function () {
             it('Check for defined ', function () {
diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/ui-select.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/ui-select.test.js
index 6a646c7c709099b917a08df1f3f795cce262dca0..5ffa5792b0882385c26546d6fbd834f3dde68a03 100644
--- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/ui-select.test.js
+++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/ui-select.test.js
@@ -18,11 +18,13 @@ define([
     describe('Magento_Ui/js/form/element/ui-select', function () {
 
         var obj = new Constr({
+            name: 'uiSelect',
             dataScope: '',
             provider: 'provider'
         });
 
         obj.value = ko.observableArray([]);
+        obj.cacheOptions.plain = [];
 
         describe('"initialize" method', function () {
             it('Check for defined ', function () {
@@ -129,30 +131,6 @@ define([
             });
         });
 
-        describe('"initOptions" method', function () {
-            it('Check for defined ', function () {
-                expect(obj.hasOwnProperty('initOptions')).toBeDefined();
-            });
-            it('Check answer type', function () {
-                var type = typeof obj.initOptions;
-
-                expect(type).toEqual('function');
-            });
-            it('Check returned value if method called without arguments', function () {
-                expect(obj.initOptions()).toBeDefined();
-            });
-            it('Check returned value type if method called without arguments', function () {
-                var type = typeof obj.initOptions();
-
-                expect(type).toEqual('object');
-            });
-            it('Check "this.optionsConfig.options" property', function () {
-                obj.optionsConfig.options = null;
-                obj.initOptions();
-                expect(obj.optionsConfig.options).toEqual([]);
-            });
-        });
-
         describe('"cleanHoveredElement" method', function () {
             it('Check for defined ', function () {
                 expect(obj.hasOwnProperty('cleanHoveredElement')).toBeDefined();
@@ -170,11 +148,6 @@ define([
 
                 expect(type).toEqual('object');
             });
-            it('Check changes "this.hoverElIndex" observe variable', function () {
-                obj.hoverElIndex(5);
-                obj.cleanHoveredElement();
-                expect(obj.hoverElIndex()).toEqual(null);
-            });
         });
         describe('"isSelected" method', function () {
             it('Check for defined ', function () {
@@ -213,10 +186,6 @@ define([
 
                 expect(type).toEqual('boolean');
             });
-            it('Must return false if "hoverElIndex" does not equal value', function () {
-                obj.hoverElIndex(1);
-                expect(obj.isHovered(2)).toEqual(false);
-            });
         });
         describe('"toggleListVisible" method', function () {
             it('Check for defined ', function () {
@@ -281,34 +250,6 @@ define([
                 expect(obj.value()).toEqual([]);
             });
         });
-        describe('"onHoveredIn" method', function () {
-            it('Check for defined ', function () {
-                expect(obj.hasOwnProperty('onHoveredIn')).toBeDefined();
-            });
-            it('Check answer type', function () {
-                var type = typeof obj.onHoveredIn;
-
-                expect(type).toEqual('function');
-            });
-            it('Observe variable "hoverElIndex" must have transmitted value', function () {
-                obj.onHoveredIn({}, 5);
-                expect(obj.hoverElIndex()).toEqual(5);
-            });
-        });
-        describe('"onHoveredOut" method', function () {
-            it('Check for defined ', function () {
-                expect(obj.hasOwnProperty('onHoveredOut')).toBeDefined();
-            });
-            it('Check answer type', function () {
-                var type = typeof obj.onHoveredOut;
-
-                expect(type).toEqual('function');
-            });
-            it('Observe variable "hoverElIndex" must be null', function () {
-                obj.onHoveredOut();
-                expect(obj.hoverElIndex()).toEqual(null);
-            });
-        });
         describe('"onFocusIn" method', function () {
             it('Check for defined ', function () {
                 expect(obj.hasOwnProperty('onFocusIn')).toBeDefined();
@@ -319,7 +260,7 @@ define([
                 expect(type).toEqual('function');
             });
             it('Observe variable "multiselectFocus" must be true', function () {
-                obj.onFocusIn();
+                obj.onFocusIn({}, {});
                 expect(obj.multiselectFocus()).toEqual(true);
             });
         });
@@ -351,14 +292,6 @@ define([
                 obj.enterKeyHandler();
                 expect(obj.listVisible()).toEqual(true);
             });
-            it('if list visible is true, method "toggleOptionSelected" must be called with argument', function () {
-                obj.listVisible(true);
-                obj.hoverElIndex(0);
-                obj.options(['magento']);
-                obj.toggleOptionSelected = jasmine.createSpy();
-                obj.enterKeyHandler();
-                expect(obj.toggleOptionSelected).toHaveBeenCalledWith('magento');
-            });
         });
         describe('"escapeKeyHandler" method', function () {
             it('Check for defined ', function () {
@@ -388,23 +321,6 @@ define([
 
                 expect(type).toEqual('function');
             });
-            it('If "hoverElIndex" is null - "hoverElIndex" must be 0', function () {
-                obj.hoverElIndex(null);
-                obj.pageDownKeyHandler();
-                expect(obj.hoverElIndex()).toEqual(0);
-            });
-            it('If "hoverElIndex" is number - "hoverElIndex" must be number + 1', function () {
-                obj.hoverElIndex(1);
-                obj.options(['one', 'two', 'three']);
-                obj.pageDownKeyHandler();
-                expect(obj.hoverElIndex()).toEqual(2);
-            });
-            it('If "hoverElIndex" is number and number === options length -1, "hoverElIndex" must be 0', function () {
-                obj.hoverElIndex(1);
-                obj.options(['one', 'two']);
-                obj.pageDownKeyHandler();
-                expect(obj.hoverElIndex()).toEqual(0);
-            });
         });
         describe('"pageUpKeyHandler" method', function () {
             it('Check for defined ', function () {
@@ -415,24 +331,6 @@ define([
 
                 expect(type).toEqual('function');
             });
-            it('If "hoverElIndex" is null - "hoverElIndex" must be option length -1', function () {
-                obj.hoverElIndex(null);
-                obj.options(['one', 'two']);
-                obj.pageUpKeyHandler();
-                expect(obj.hoverElIndex()).toEqual(1);
-            });
-            it('If "hoverElIndex" is 0 - "hoverElIndex" must be option length -1', function () {
-                obj.hoverElIndex(0);
-                obj.options(['one', 'two']);
-                obj.pageUpKeyHandler();
-                expect(obj.hoverElIndex()).toEqual(1);
-            });
-            it('If "hoverElIndex" is number - "hoverElIndex" must be number - 1', function () {
-                obj.hoverElIndex(2);
-                obj.options(['one', 'two']);
-                obj.pageUpKeyHandler();
-                expect(obj.hoverElIndex()).toEqual(1);
-            });
         });
         describe('"keydownSwitcher" method', function () {
             it('Check for defined ', function () {
@@ -537,7 +435,7 @@ define([
                 expect(type).toEqual('function');
             });
             it('Check returned value if selected', function () {
-                obj.cacheOptions = [{value: 'magento'}, {value: 'magento2'}];
+                obj.cacheOptions.plain = [{value: 'magento'}, {value: 'magento2'}];
                 obj.value(['magento', 'magento2']);
 
                 expect(obj.getSelected()).toEqual([{value: 'magento'}, {value: 'magento2'}]);
diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/columns/actions.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/columns/actions.test.js
index c282660342ad1c25a7b0f35dd9d095fcaeb7604b..318e09453dc5af8f3f4d3f43e10c208c615a8b6c 100644
--- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/columns/actions.test.js
+++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/columns/actions.test.js
@@ -82,19 +82,5 @@ define([
             action.hidden = false;
             expect(model.isActionVisible(action)).toBeTruthy();
         });
-
-        it('Check toggleList function', function () {
-            model.toggleList(0);
-            expect(model.opened()).toEqual(0);
-            model.toggleList(0);
-            expect(model.opened()).toBeFalsy();
-        });
-
-        it('Check closeList function', function () {
-            model.toggleList(0);
-            expect(model.opened()).toEqual(0);
-            model.closeList(0);
-            expect(model.opened()).toBeFalsy();
-        });
     });
 });
\ No newline at end of file
diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/columns/column.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/columns/column.test.js
index b4db54bdb7b65fec6a557dd12f0d10e878277ece..ccfccdd195f0292163eab823ae5b15a61713594c 100644
--- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/columns/column.test.js
+++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/columns/column.test.js
@@ -17,7 +17,8 @@ define([
                 sortable: true,
                 sorting: false,
                 headerTmpl: 'header',
-                bodyTmpl: 'body'
+                bodyTmpl: 'body',
+                source: function () {}
             });
         });
 
@@ -27,11 +28,6 @@ define([
                 expect(column.sorting).toBe('asc');
             });
 
-            it('apply sorting in other direction', function () {
-                column.sort(true).sort(true);
-                expect(column.sorting).toBe('desc');
-            });
-
             it('remove sorting', function () {
                 column.sort(false);
                 expect(column.sorting).toBeFalsy();
diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/columns/date.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/columns/date.test.js
index e93209a5dfd04fbb6d897b650bc94cc7157b4f73..bee9a76a8ed390ab1aa8d6aaa8c5f5a13b2e6314 100644
--- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/columns/date.test.js
+++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/columns/date.test.js
@@ -22,21 +22,14 @@ define([
                 });
         });
 
-        describe('initProperties method', function () {
+        describe('initConfig method', function () {
             it('check for chainable', function () {
-                expect(date.initProperties()).toEqual(date);
+                expect(date.initConfig()).toEqual(date);
             });
             it('check for extend', function () {
-                date.initProperties();
+                date.initConfig();
                 expect(date.dateFormat).toBeDefined();
             });
         });
-
-        describe('getLabel method', function () {
-            it('check format', function () {
-                date.dateFormat = dateFormat;
-                expect(date.getLabel(dateRaw)).toBe(dateFormatted);
-            });
-        });
     });
 });
diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/columns/select.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/columns/select.test.js
index 9b9e0b35cf3ebc05a49ec2dbc26ebd15ae338d41..3179490ab1ed62391841b17df6f459e52b106db6 100644
--- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/columns/select.test.js
+++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/columns/select.test.js
@@ -25,11 +25,6 @@ define([
             it('get label while options empty', function () {
                 expect(select.getLabel(2)).toBe('');
             });
-
-            it('get label for existed value', function () {
-                select.options = opts;
-                expect(select.getLabel(2)).toBe('b');
-            });
         });
     });
 });
diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/controls/bookmarks/bookmarks.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/controls/bookmarks/bookmarks.test.js
deleted file mode 100644
index d85890b2c98f4372f5194684d011a4d1836a72a1..0000000000000000000000000000000000000000
--- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/controls/bookmarks/bookmarks.test.js
+++ /dev/null
@@ -1,104 +0,0 @@
-/**
- * Copyright © 2016 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-
-define([
-    'Magento_Ui/js/grid/controls/bookmarks/bookmarks'
-], function (Bookmarks) {
-    'use strict';
-    describe('ui/js/grid/controls/bookmarks/bookmarks', function () {
-        var bookmarksElement, returnContext;
-
-        beforeEach(function () {
-            bookmarksElement = new Bookmarks({
-                index: 'index',
-                name: 'name',
-                indexField: 'id',
-                dataScope: 'scope',
-                provider: 'provider'
-            });
-
-        });
-        it('has initialize method', function () {
-            spyOn(bookmarksElement, "initialize");
-            bookmarksElement.initialize();
-            expect(bookmarksElement.initialize).toHaveBeenCalled();
-        });
-        it('has initStorage method', function () {
-            spyOn(bookmarksElement, "initStorage");
-            bookmarksElement.initStorage();
-            expect(bookmarksElement.initStorage).toHaveBeenCalled();
-        });
-        it('has initElement method', function () {
-            spyOn(bookmarksElement, "initElement");
-            bookmarksElement.initElement();
-            expect(bookmarksElement.initElement).toHaveBeenCalled();
-        });
-        it('has initViews method', function () {
-            spyOn(bookmarksElement, "initViews");
-            bookmarksElement.initViews();
-            expect(bookmarksElement.initViews).toHaveBeenCalled();
-        });
-        it('has createView method', function () {
-            spyOn(bookmarksElement, "createView");
-            bookmarksElement.createView();
-            expect(bookmarksElement.createView).toHaveBeenCalled();
-        });
-        it('has createNewView method', function () {
-            spyOn(bookmarksElement, "createNewView");
-            bookmarksElement.createNewView();
-            expect(bookmarksElement.createNewView).toHaveBeenCalled();
-        });
-        it('has removeView method', function () {
-            spyOn(bookmarksElement, "removeView");
-            bookmarksElement.removeView();
-            expect(bookmarksElement.removeView).toHaveBeenCalled();
-        });
-        it('has saveView method', function () {
-            spyOn(bookmarksElement, "saveView");
-            bookmarksElement.saveView();
-            expect(bookmarksElement.saveView).toHaveBeenCalled();
-        });
-        it('has applyView method', function () {
-            spyOn(bookmarksElement, "applyView");
-            bookmarksElement.applyView();
-            expect(bookmarksElement.applyView).toHaveBeenCalled();
-        });
-        it('has applyState method', function () {
-            spyOn(bookmarksElement, "applyState");
-            bookmarksElement.applyState();
-            expect(bookmarksElement.applyState).toHaveBeenCalled();
-        });
-        it('has saveSate method', function () {
-            spyOn(bookmarksElement, "saveSate");
-            bookmarksElement.saveSate();
-            expect(bookmarksElement.saveSate).toHaveBeenCalled();
-        });
-        it('has checkChanges method', function () {
-            spyOn(bookmarksElement, "checkChanges");
-            bookmarksElement.checkChanges();
-            expect(bookmarksElement.checkChanges).toHaveBeenCalled();
-        });
-        it('has _defaultPolyfill method', function () {
-            spyOn(bookmarksElement, "_defaultPolyfill");
-            bookmarksElement._defaultPolyfill();
-            expect(bookmarksElement._defaultPolyfill).toHaveBeenCalled();
-        });
-        it('has onActiveIndexChange method', function () {
-            spyOn(bookmarksElement, "onActiveIndexChange");
-            bookmarksElement.onActiveIndexChange();
-            expect(bookmarksElement.onActiveIndexChange).toHaveBeenCalled();
-        });
-        it('has onStateChange method', function () {
-            spyOn(bookmarksElement, "onStateChange");
-            bookmarksElement.onStateChange();
-            expect(bookmarksElement.onStateChange).toHaveBeenCalled();
-        });
-        it('has onEditingChange method', function () {
-            spyOn(bookmarksElement, "onEditingChange");
-            bookmarksElement.onEditingChange();
-            expect(bookmarksElement.onEditingChange).toHaveBeenCalled();
-        });
-    });
-});
diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/controls/bookmarks/view.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/controls/bookmarks/view.test.js
deleted file mode 100644
index 791dccb14003ceee6047477a2c1bb1da0031f688..0000000000000000000000000000000000000000
--- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/controls/bookmarks/view.test.js
+++ /dev/null
@@ -1,67 +0,0 @@
-/**
- * Copyright © 2016 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-
-define([
-    'Magento_Ui/js/grid/controls/bookmarks/view'
-], function (BookmarkView) {
-        'use strict';
-    describe('ui/js/grid/controls/bookmarks/view', function () {
-        var view, returnContextOfItself;
-        beforeEach(function(){
-            view = new BookmarkView({
-                index: 'index',
-                name: 'name',
-                indexField: 'id',
-                dataScope: 'scope',
-                provider: 'provider'
-            });
-        });
-        it('has initialize method', function () {
-            spyOn(view, "initialize");
-            view.initialize();
-            expect(view.initialize).toHaveBeenCalled();
-        });
-        it('has initObservable method', function () {
-            spyOn(view, "initObservable");
-            view.initObservable();
-            expect(view.initObservable).toHaveBeenCalled();
-        });
-        it('has getData method', function () {
-            spyOn(view, "getData");
-            view.getData();
-            expect(view.getData).toHaveBeenCalled();
-        });
-        it('has setData method', function () {
-            spyOn(view, "setData");
-            view.setData();
-            expect(view.setData).toHaveBeenCalled();
-        });
-        it('has syncLabel method', function () {
-            spyOn(view, "syncLabel");
-            view.syncLabel();
-            expect(view.syncLabel).toHaveBeenCalled();
-        });
-        it('has startEdit method', function () {
-            spyOn(view, "startEdit");
-            view.startEdit();
-            expect(view.startEdit).toHaveBeenCalled();
-        });
-        it('has exportView method', function () {
-            spyOn(view, "exportView");
-            view.exportView();
-            expect(view.exportView).toHaveBeenCalled();
-        });
-        it('has onActivate method', function () {
-            spyOn(view, "onActivate");
-            view.onActivate();
-            expect(view.onActivate).toHaveBeenCalled();
-        });
-        it('has onActiveChange method', function () {
-            spyOn(view, "onActiveChange");
-            view.onActiveChange();
-            expect(view.onActiveChange).toHaveBeenCalled();
-        });
-    })
-});
diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/editing/bulk.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/editing/bulk.test.js
index 094ad409e5eb4415672702fb38eb219070b2fe54..bdbffbff347fe27c18b13b1c17b79f175f724ec2 100644
--- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/editing/bulk.test.js
+++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/editing/bulk.test.js
@@ -13,6 +13,7 @@ define([
 
         beforeEach(function () {
             bulkObj = new Bulk();
+            bulkObj.editor = jasmine.createSpy('editor');
         });
         it('has initObservable', function () {
             expect(bulkObj).toBeDefined();
@@ -33,5 +34,5 @@ define([
             bulkObj.updateState();
             expect(bulkObj.updateState).toHaveBeenCalled();
         });
-    })
-});
\ No newline at end of file
+    });
+});
diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/filters/filters.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/filters/filters.test.js
index 0555f056f5e90822b1aca09f39c1c27b08f7cf8a..05a65b038f3e3783d2af10d1ab75f1a2c0ee135f 100644
--- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/filters/filters.test.js
+++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/filters/filters.test.js
@@ -13,7 +13,9 @@ define([
             temp;
 
         beforeEach(function () {
-            filterObj = new Filter();
+            filterObj = new Filter({
+                name: 'filter'
+            });
         });
         it('has been initialized', function () {
             expect(filterObj).toBeDefined();
@@ -39,16 +41,6 @@ define([
             temp = filterObj.cancel();
             expect(temp).toBeDefined();
         });
-        it('has isOpened method', function () {
-            filterObj.opened = function () {
-                return true;
-            };
-            filterObj.hasVisible = function () {
-                return true;
-            };
-            temp = filterObj.isOpened();
-            expect(temp).toBeTruthy();
-        });
         it('has isFilterVisible method', function () {
             temp = {
                 visible: function () {
@@ -69,15 +61,5 @@ define([
             filterObj.hasVisible();
             expect(filterObj.hasVisible).toHaveBeenCalled();
         });
-        it('has extractActive method', function () {
-            spyOn(filterObj, 'extractActive');
-            filterObj.extractActive();
-            expect(filterObj.extractActive).toHaveBeenCalled();
-        });
-        it('has extractPreviews method', function () {
-            spyOn(filterObj, 'extractPreviews');
-            filterObj.extractPreviews();
-            expect(filterObj.extractPreviews).toHaveBeenCalled();
-        });
     });
-});
\ No newline at end of file
+});
diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/filters/range.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/filters/range.test.js
index 44640d6ef206367191e630c36dcdd5271982e268..c2f798927fa8e34fa453d505f532371ee0e801e0 100644
--- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/filters/range.test.js
+++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/filters/range.test.js
@@ -28,18 +28,6 @@ define([
             group.elems.push({id:1}, {id:1});
             expect(group.elems()).not.toEqual([]);
         });
-        it('Check for reset elements.', function () {
-            var elem = {
-                value: false,
-                reset: function() {
-                    this.value = true;
-                }
-            };
-
-            group.elems.push(elem);
-            expect(group.reset()).toBe(group);
-            expect(group.elems.first().value).toBe(true);
-        });
         it('Check for clear elements.', function () {
             var elem = {
                 value: 'text',
diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/paging/paging.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/paging/paging.test.js
index 36c2823eaf9e62706bc4d0d12174fedad4d25049..a240e5cfd432597d4bb38e10957b4495d4ed48b2 100644
--- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/paging/paging.test.js
+++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/paging/paging.test.js
@@ -39,103 +39,17 @@ define([
             });
         });
 
-        describe('countPages method', function () {
-            it('correct number of pages', function () {
-                paging.countPages();
-                expect(paging.pages).toBe(4);
-            });
-
-            it('if no records', function () {
-                paging.totalRecords = 0;
-                paging.countPages();
-                expect(paging.pages).toBe(1);
-            });
-        });
-
-        describe('page manipualations', function () {
-            it('setPage method', function () {
-                paging.setPage(2);
-                expect(paging.current).toBe(2);
-            });
-
-            it('next', function () {
-                paging.current = 1;
-                paging.next();
-                expect(paging.current).toBe(2);
-            });
-
-            it('next out of boundary', function () {
-                paging.current = 4;
-                paging.next();
-                expect(paging.current).toBe(4);
-            });
-
-            it('prev', function () {
-                paging.current = 4;
-                paging.prev();
-                expect(paging.current).toBe(3);
-            });
-
-            it('prev out of boundary', function () {
-                paging.current = 1;
-                paging.prev();
-                expect(paging.current).toBe(1);
-            });
-
-            it('goFirst', function () {
-                paging.goFirst();
-                expect(paging.current).toBe(1);
-            });
-
-            it('goLast', function () {
-                paging.goLast();
-                expect(paging.current).toBe(4);
-            });
-
-            it('isFirst for 1st page', function () {
-                paging.current = 1;
-                expect(paging.isFirst()).toBeTruthy();
-            });
-
-            it('isFirst for 2nd page', function () {
-                paging.current = 2;
-                expect(paging.isFirst()).toBeFalsy();
-            });
-
-            it('isLast for last page', function () {
-                paging.current = 4;
-                expect(paging.isLast()).toBeTruthy();
-            });
-
-            it('isLast for first page', function () {
-                paging.current = 1;
-                expect(paging.isLast()).toBeFalsy();
-            });
-        });
-
-        describe('countPages method', function () {
-            it('correct number of pages', function () {
-                paging.countPages();
-                expect(paging.pages).toBe(4);
-            });
-
-            it('if no records', function () {
-                paging.totalRecords = 0;
-                paging.countPages();
-                expect(paging.pages).toBe(1);
-            });
-        });
-
         describe('onPagesChange method', function () {
             it('pages amount became less than current', function () {
                 paging.current = 4;
                 expect(paging.current).toBe(4);
-                paging.onPagesChange(2);
-                expect(paging.current).toBe(2);
+                paging.pageSize = 3;
+                paging.onPagesChange();
+                expect(paging.current).toBe(3);
             });
         });
 
-        describe('ititObservable method', function () {
+        describe('initObservable method', function () {
             it('_current will be defined', function () {
                 expect(paging._current).toBeDefined();
             });
@@ -144,14 +58,6 @@ define([
                 paging.current = 2;
                 expect(paging._current()).toBe(2);
             });
-
-            it('write into current', function () {
-                spyOn(paging, 'normalize').and.callThrough();
-                spyOn(paging._current, 'notifySubscribers');
-                paging._current(4);
-                expect(paging.current).toBe(4);
-                expect(paging._current.notifySubscribers).toHaveBeenCalledWith(4);
-            });
         });
     });
 });
diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/resize.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/resize.test.js
index 948bfb84a85da7621273661ccf8da12483e196ab..4cbb9e73d5ae770bb1121b635dbf7ab4da260ecc 100644
--- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/resize.test.js
+++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/resize.test.js
@@ -63,10 +63,10 @@ define([
                         index: 1,
                         column: data,
                         on: function (arg1, arg2) {}
-                    }
+                    };
                 });
                 spyOn(ko, 'contextFor').and.callFake(function () {
-                    return {$index: 1, $parent: obj}
+                    return {$index: 1, $parent: obj};
                 });
                 $._data = jasmine.createSpy().and.callFake(function () {
                     return {
@@ -82,45 +82,6 @@ define([
                 type = typeof obj.initColumn;
                 expect(type).toEqual('function');
             });
-            it('Check call "this.getDefaultWidth" method', function () {
-                spyOn(obj, 'getDefaultWidth');
-                obj.initColumn('magento');
-                expect(obj.getDefaultWidth).toHaveBeenCalledWith('magento');
-            });
-            it('Check call "this.hasColumn" method', function () {
-                spyOn(obj, 'hasColumn').and.callFake(function () {
-                    return false;
-                });
-                obj.initColumn('magento');
-                expect(obj.hasColumn).toHaveBeenCalled();
-            });
-            it('Check call "this.initResizableElement" method', function () {
-                spyOn(obj, 'hasColumn').and.callFake(function () {
-                    return false;
-                });
-                spyOn(obj, 'initResizableElement').and.callFake(function (arg) {
-                    return true;
-                });
-                obj.initColumn('magento');
-                expect(obj.initResizableElement).toHaveBeenCalled();
-            });
-            it('Check call "this.setStopPropagationHandler" method', function () {
-                spyOn(obj, 'hasColumn').and.callFake(function () {
-                    return false;
-                });
-                spyOn(obj, 'setStopPropagationHandler').and.callFake(function (arg) {
-                    return true;
-                });
-                obj.initColumn('magento');
-                expect(obj.setStopPropagationHandler).toHaveBeenCalledWith('magento');
-            });
-            it('Check call "this.refreshLastColumn" method', function () {
-                spyOn(obj, 'refreshLastColumn').and.callFake(function (arg) {
-                    return true;
-                });
-                obj.initColumn('magento');
-                expect(obj.refreshLastColumn).toHaveBeenCalledWith('magento');
-            });
         });
         describe('"initResizableElement" method', function () {
             beforeEach(function(){
@@ -194,9 +155,9 @@ define([
                     }
                 });
                 spyOn(ko, 'contextFor').and.callFake(function () {
-                    return {$index: ko.observable(1), $parent: obj}
+                    return {$index: ko.observable(1), $parent: obj};
                 });
-                spyOn(obj, 'getNextElement').and.callFake(function () {
+                spyOn(obj, 'getNextElements').and.callFake(function () {
                     return true;
                 });
                 event = {stopImmediatePropagation: function(){}}
@@ -215,9 +176,9 @@ define([
                 obj.mousedownHandler(event);
                 expect(obj.hasColumn).toHaveBeenCalled();
             });
-            it('Check call "this.getNextElement" method', function () {
+            it('Check call "this.getNextElements" method', function () {
                 obj.mousedownHandler(event);
-                expect(obj.getNextElement).toHaveBeenCalled();
+                expect(obj.getNextElements).toHaveBeenCalled();
             });
         });
         describe('"mousemoveHandler" method', function () {
@@ -261,7 +222,7 @@ define([
                 expect(obj.storageColumnsData[2]).toEqual(200);
             });
         });
-        describe('"getNextElement" method', function () {
+        describe('"getNextElements" method', function () {
             beforeEach(function(){
                 spyOn(ko, 'dataFor').and.callFake(function (data) {
                     return {
@@ -275,24 +236,24 @@ define([
                 });
             });
             it('Check for defined ', function () {
-                expect(obj.hasOwnProperty('getNextElement')).toBeDefined();
+                expect(obj.hasOwnProperty('getNextElements')).toBeDefined();
             });
             it('Check method type', function () {
-                type = typeof obj.getNextElement;
+                type = typeof obj.getNextElements;
                 expect(type).toEqual('function');
             });
             it('Check call "this.hasColumn" method', function () {
                 spyOn(obj, 'hasColumn').and.callFake(function () {
                     return 'magento';
                 });
-                obj.getNextElement('magento');
+                obj.getNextElements('magento');
                 expect(obj.hasColumn).toHaveBeenCalled();
             });
             it('Check returned value', function () {
                 spyOn(obj, 'hasColumn').and.callFake(function () {
                     return 'magento';
                 });
-                expect(obj.getNextElement('magento')).toEqual('magento');
+                expect(obj.getNextElements('magento')).toEqual('magento');
             });
         });
         describe('"getDefaultWidth" method', function () {
@@ -337,21 +298,11 @@ define([
                 arg = { index: 'magento' };
                 expect(typeof obj.hasColumn(arg, false)).toEqual('boolean');
             });
-            it('Must return false if object columnsElements has not model.index property', function () {
-                arg = { index: 'magento' };
-                obj.columnsElements = {};
-                expect(obj.hasColumn(arg, false)).toEqual(false);
-            });
             it('Must return true if object columnsElements has  model.index property', function () {
                 arg = { index: 'magento' };
                 obj.columnsElements = {magento: 'magentoProp'};
                 expect(obj.hasColumn(arg, false)).toEqual(true);
             });
-            it('Must return property if object columnsElements has property and second argument is true', function () {
-                arg = { index: 'magento' };
-                obj.columnsElements = {magento: 'magentoProp'};
-                expect(obj.hasColumn(arg, true)).toEqual('magentoProp');
-            });
         });
         describe('"hasRow" method', function () {
             it('Check for defined ', function () {
diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/search/search.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/search/search.test.js
index b407fe3bebeae0153d60fe37a76953a50a1d72f6..e10061263d13a14214e50ab1266f809c96ec0883 100644
--- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/search/search.test.js
+++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/search/search.test.js
@@ -7,7 +7,7 @@ define([
 ], function (Search) {
     'use strict';
 
-    describe('Magento_Ui/js/search/search', function () {
+    describe('Magento_Ui/js/grid/search/search', function () {
         var searchObj,
             temp;
 
@@ -31,23 +31,6 @@ define([
             searchObj.initChips();
             expect(searchObj.chips).toHaveBeenCalled();
         });
-        it('has clear', function () {
-            spyOn(searchObj, 'value');
-            searchObj.clear();
-            expect(searchObj.value).toHaveBeenCalled();
-        });
-        it('has clear', function () {
-            spyOn(searchObj, 'inputValue');
-            searchObj.cancel();
-            expect(searchObj.inputValue).toHaveBeenCalled();
-        });
-        it('has apply', function () {
-            spyOn(searchObj, 'value');
-            spyOn(searchObj, 'inputValue');
-            searchObj.apply();
-            expect(searchObj.value).toHaveBeenCalled();
-            expect(searchObj.inputValue).toHaveBeenCalled();
-        });
         it('has updatePreview', function () {
             spyOn(searchObj, 'updatePreview');
             searchObj.updatePreview();
diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/sticky/sticky.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/sticky/sticky.test.js
index 4c2b68d8fcd01046895f88589d339948b032b269..426b453ab42852caf01763e5d6f73ff11933fffb 100644
--- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/sticky/sticky.test.js
+++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/sticky/sticky.test.js
@@ -135,10 +135,13 @@ define([
                 stickyObj.resetToTop();
                 expect(stickyObj.resetToTop).toHaveBeenCalled();
             });
-            it('has toggleContainerVisibility event', function () {
-                spyOn(stickyObj, 'visible');
+            it('has "toggleContainerVisibility" method', function () {
+                stickyObj.visible = false;
                 stickyObj.toggleContainerVisibility();
-                expect(stickyObj.visible).toHaveBeenCalled();
+                expect(stickyObj.visible).toEqual(true);
+                stickyObj.visible = true;
+                stickyObj.toggleContainerVisibility();
+                expect(stickyObj.visible).toEqual(false);
             });
             it('has adjustContainerElemsWidth event', function () {
                 stickyObj.resizeContainer = function(){
@@ -156,17 +159,6 @@ define([
                 stickyObj.adjustOffset();
                 expect(stickyObj.adjustOffset).toHaveBeenCalled();
             });
-            it('has checkPos event', function () {
-                stickyObj.visible = function(){
-                    return false;
-                };
-                stickyObj.getMustBeSticky = function(){
-                    return false;
-                };
-
-                data = stickyObj.checkPos();
-                expect(data).toBeDefined();
-            })
         });
     })
 });
\ No newline at end of file
diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/component/core.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/component/core.test.js
deleted file mode 100644
index 9a0e8c2c4de0874406e61619b43ba471f166beff..0000000000000000000000000000000000000000
--- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/component/core.test.js
+++ /dev/null
@@ -1,71 +0,0 @@
-/**
- * Copyright © 2016 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-
-define([
-    'Magento_Ui/js/lib/component/core'
-], function (core) {
-    'use strict';
-
-    describe('Magento_Ui/js/lib/component/core', function () {
-        var coreObj,
-            returnedValue;
-
-        beforeEach(function () {
-            coreObj = core;
-        });
-        it('has initialize', function () {
-            spyOn(coreObj, 'initialize');
-            coreObj.initialize();
-            expect(coreObj.initialize).toHaveBeenCalled();
-        });
-        it('has initProperties', function () {
-            returnedValue = coreObj.initProperties();
-            expect(typeof returnedValue).toEqual('object');
-        });
-        it('has initObservable', function () {
-            spyOn(coreObj, 'initObservable');
-            coreObj.initObservable();
-            expect(coreObj.initObservable).toHaveBeenCalled();
-        });
-        it('has initLinks', function () {
-            spyOn(coreObj, 'initLinks');
-            coreObj.initLinks();
-            expect(coreObj.initLinks).toHaveBeenCalled();
-        });
-        it('has initModules', function () {
-            returnedValue = coreObj.initModules();
-            expect(typeof returnedValue).toEqual('object');
-        });
-        it('has initUnique', function () {
-            returnedValue = coreObj.initUnique();
-            expect(typeof returnedValue).toEqual('object');
-        });
-        it('has initContainer', function () {
-            spyOn(coreObj, 'initContainer');
-            coreObj.initContainer();
-            expect(coreObj.initContainer).toHaveBeenCalled();
-        });
-        it('has initElement', function () {
-            spyOn(coreObj, 'initElement');
-            coreObj.initElement();
-            expect(coreObj.initElement).toHaveBeenCalled();
-        });
-        it('has getTemplate', function () {
-            spyOn(coreObj, 'getTemplate');
-            coreObj.getTemplate();
-            expect(coreObj.getTemplate).toHaveBeenCalled();
-        });
-        it('has setUnique', function () {
-            spyOn(coreObj, 'setUnique');
-            coreObj.setUnique();
-            expect(coreObj.setUnique).toHaveBeenCalled();
-        });
-        it('has onUniqueUpdate', function () {
-            spyOn(coreObj, 'onUniqueUpdate');
-            coreObj.onUniqueUpdate();
-            expect(coreObj.onUniqueUpdate).toHaveBeenCalled();
-        });
-    });
-});
diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/component/links.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/component/links.test.js
index cf122dbc31fdfe14c0e7654abd232f2558562447..ff17bd826b5c212cf7e2fe624d7da70a3fca2177 100644
--- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/component/links.test.js
+++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/component/links.test.js
@@ -19,9 +19,6 @@ define([
             };
 
         });
-        it('has defaults', function () {
-            expect(typeof linksObj.defaults).toEqual('object');
-        });
         it('has setLinks method', function () {
             returnedValue = linksObj.setLinks(undefined, 'imports');
             expect(typeof returnedValue).toEqual('object');
diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/component/manip.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/component/manip.test.js
deleted file mode 100644
index 51c460ab648ad948a756a12b131873740959ffe8..0000000000000000000000000000000000000000
--- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/component/manip.test.js
+++ /dev/null
@@ -1,67 +0,0 @@
-/**
- * Copyright © 2016 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-define([
-        'Magento_Ui/js/lib/component/manip'
-    ], function (manip) {
-        'use strict';
-
-        describe( 'Magento_Ui/js/lib/component/manip', function(){
-            var manipObj,
-                returnedValue;
-
-            beforeEach(function(){
-                manipObj = manip;
-            });
-            it('has getRegion method', function(){
-                returnedValue = manipObj.getRegion("region");
-                expect(returnedValue).toBeDefined();
-            });
-            it('has updateRegion method', function(){
-                returnedValue = manipObj.updateRegion([],"region");
-                expect(typeof returnedValue).toEqual('object');
-            });
-            it('has insertChild method', function(){
-                spyOn(manipObj, "insertChild");
-                manipObj.insertChild();
-                expect(manipObj.insertChild).toHaveBeenCalled();
-            });
-            it('has removeChild method', function(){
-                spyOn(manipObj, "removeChild");
-                manipObj.removeChild();
-                expect(manipObj.removeChild).toHaveBeenCalled();
-            });
-            it('has destroy method', function(){
-                spyOn(manipObj, "destroy");
-                manipObj.destroy();
-                expect(manipObj.destroy).toHaveBeenCalled();
-            });
-            it('has _dropHandlers method', function(){
-                spyOn(manipObj, "_dropHandlers");
-                manipObj._dropHandlers();
-                expect(manipObj._dropHandlers).toHaveBeenCalled();
-            });
-            it('has _clearData method', function(){
-                spyOn(manipObj, "_clearData");
-                manipObj._clearData();
-                expect(manipObj._clearData).toHaveBeenCalled();
-            });
-            it('has _clearRefs method', function(){
-                spyOn(manipObj, "_clearRefs");
-                manipObj._clearRefs();
-                expect(manipObj._clearRefs).toHaveBeenCalled();
-            });
-            it('has _insert method', function(){
-                spyOn(manipObj, "_insert");
-                manipObj._insert();
-                expect(manipObj._insert).toHaveBeenCalled();
-            });
-            it('has _update method', function(){
-                spyOn(manipObj, "_update");
-                manipObj._update();
-                expect(manipObj._update).toHaveBeenCalled();
-            });
-
-        });
-    });
diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/component/provider.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/component/provider.test.js
deleted file mode 100644
index 47e531677abef865d39428b21722d12ab87f5b29..0000000000000000000000000000000000000000
--- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/component/provider.test.js
+++ /dev/null
@@ -1,42 +0,0 @@
-/**
- * Copyright © 2016 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-define([
-        'Magento_Ui/js/lib/component/provider'
-    ], function (provider) {
-        'use strict';
-
-        describe( 'Magento_Ui/js/lib/component/provider', function(){
-            var providerObj,
-                returnedValue;
-
-            beforeEach(function(){
-                providerObj = provider;
-            });
-            it('has observe method', function(){
-                returnedValue = providerObj.observe("elems");
-                expect(typeof  returnedValue).toEqual('object');
-            });
-            it('has set method', function(){
-                spyOn(providerObj, "set");
-                providerObj.set();
-                expect(providerObj.set).toHaveBeenCalled();
-            });
-            it('has remove method', function(){
-                spyOn(providerObj, "remove");
-                providerObj.remove();
-                expect(providerObj.remove).toHaveBeenCalled();
-            });
-            it('has restore method', function(){
-                spyOn(providerObj, "restore");
-                providerObj.restore();
-                expect(providerObj.restore).toHaveBeenCalled();
-            });
-            it('has removeStored method', function(){
-                spyOn(providerObj, "removeStored");
-                providerObj.removeStored();
-                expect(providerObj.removeStored).toHaveBeenCalled();
-            });
-        });
-    });
diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/component/traversal.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/component/traversal.test.js
deleted file mode 100644
index c6b6784475f3b81506b8c7ee58774a1a9bf318dd..0000000000000000000000000000000000000000
--- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/component/traversal.test.js
+++ /dev/null
@@ -1,22 +0,0 @@
-/**
- * Copyright © 2016 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-define([
-        'Magento_Ui/js/lib/component/traversal'
-    ], function (traversal) {
-        'use strict';
-
-        describe( 'Magento_Ui/js/lib/component/traversal', function(){
-            var traversalObj;
-
-            beforeEach(function(){
-                traversalObj = traversal;
-            });
-            it('has delegate method', function(){
-                spyOn(traversalObj, "delegate");
-                traversalObj.delegate();
-                expect(traversalObj.delegate).toHaveBeenCalled();
-            });
-        });
-    });
diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/ko/bind/i18n.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/ko/bind/i18n.test.js
index 8d0a99361ea547eb8b1894346861c20a6fceae42..8f7485a2f0bed94f9460be567d8e39c2f7ded2cb 100644
--- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/ko/bind/i18n.test.js
+++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/ko/bind/i18n.test.js
@@ -82,36 +82,5 @@ define([
             expect(elWithVariable.attr(dataTranslateAttrName))
                 .toEqual(dataTranslateAttr.replace(/\$/g, variableText).replace(/\&/g, variableText));
         });
-
-        it('if inline translation is on, ' +
-        'and there is translation for this text,' +
-        ' set translated text for element', function () {
-            turnOnInlineTranslation();
-            $.mage.translate.add(staticText, staticTextTranslatedRaw);
-            $.mage.translate.add(variableText, variableTranslatedRaw);
-            spyOn($.mage.translate, 'parsedTranslate').and.callThrough();
-
-            context.config.config = {
-                'Magento_Ui/js/lib/knockout/bindings/i18n': {
-                    inlineTranslation: true
-                }
-            };
-
-            ko.applyBindingsToNode(elWithStaticText[0], {
-                i18n: staticText
-            });
-            ko.applyBindingsToNode(elWithVariable[0], {
-                i18n: variable
-            });
-
-            expect($.mage.translate.parsedTranslate).toHaveBeenCalledWith(staticText);
-            expect($.mage.translate.parsedTranslate).toHaveBeenCalledWith(variableText);
-            expect(elWithStaticText.text()).toEqual(staticTextTranslated);
-            expect(elWithVariable.text()).toEqual(variableTranslated);
-            expect(elWithStaticText.attr(dataTranslateAttrName))
-                .toEqual(dataTranslateAttr.replace(/\$/g, staticText).replace(/\&/g, staticTextTranslated));
-            expect(elWithVariable.attr(dataTranslateAttrName))
-                .toEqual(dataTranslateAttr.replace(/\$/g, variableText).replace(/\&/g, variableTranslated));
-        });
     });
 });
diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/registry/events.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/registry/events.test.js
deleted file mode 100644
index b6f9c42086040cad3daafdce3d27f3681f317f11..0000000000000000000000000000000000000000
--- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/registry/events.test.js
+++ /dev/null
@@ -1,58 +0,0 @@
-/**
- * Copyright © 2016 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-
-
-define([
-    'Magento_Ui/js/lib/registry/events'
-], function (EventBus) {
-    'use strict';
-
-    describe('Magento_Ui/js/lib/registry/events', function () {
-        var storage = {
-                has : function(){
-                    return false;
-                },
-                get : function(){
-                    return [];
-                }
-            },
-            eventsClass = new EventBus(storage);
-
-        describe('"resolve" method', function () {
-            it('Check for defined ', function () {
-                expect(eventsClass.resolve()).toBeDefined();
-            });
-            it('Check answer type', function () {
-                var type = typeof(eventsClass.resolve());
-
-                expect(type).toEqual('object');
-            });
-        });
-        describe('"wait" method', function () {
-            it('Check for defined ', function () {
-                expect(eventsClass.wait([],{})).toBeDefined();
-            });
-            it('Check return object property "requests" defined', function () {
-                var thisObject = eventsClass.wait([],{}).requests;
-
-                expect(thisObject).toBeDefined();
-            });
-            it('Check return object property "requests" type', function () {
-                var thisObject = typeof(eventsClass.wait([],{}).requests);
-
-                expect(thisObject).toEqual('object');
-            });
-        });
-        describe('"_resolve" method', function () {
-            it('Check completion method', function () {
-                eventsClass.request = [{
-                    callback: function(){return true;},
-                    deps: {}
-                }];
-                expect(eventsClass._resolve(0)).toEqual(false);
-            });
-        });
-    });
-});
diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/registry/registry.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/registry/registry.test.js
index fd814d0a68fd41a79daf74825595cbb402a6f752..a45deb1df23afc9263ad1476732ce58c912e6752 100644
--- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/registry/registry.test.js
+++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/registry/registry.test.js
@@ -38,13 +38,6 @@ define([
 
                 expect(type).toEqual('object');
             });
-            it('Check assigned value after used method', function () {
-                var elem = 'test',
-                    prop = 'magento';
-                
-                registry.set(elem, prop);
-                expect(registry.storage.data.get(elem)).toEqual(prop);
-            });
         });
         describe('"registry.get" method', function () {
             it('Check for defined', function () {
@@ -63,14 +56,6 @@ define([
 
                 expect(type).toBeFalsy();
             });
-            it('Check called callback with arguments', function () {
-                var elems = ['magento'],
-                    callback = function () {};
-
-                registry.events.wait = jasmine.createSpy();
-                registry.get(elems, callback);
-                expect(registry.events.wait).toHaveBeenCalledWith(elems, callback);
-            });
         });
         describe('"registry.remove" method', function () {
             it('Check for defined', function () {
@@ -89,13 +74,6 @@ define([
 
                 expect(type).toEqual('object');
             });
-            it('Check called registry.storage.remove with arguments', function () {
-                var elems = ['magento'];
-
-                registry.storage.remove = jasmine.createSpy();
-                registry.remove(elems);
-                expect(registry.storage.remove).toHaveBeenCalledWith(elems);
-            });
         });
         describe('"registry.has" method', function () {
             it('Check for defined', function () {
@@ -106,24 +84,11 @@ define([
 
                 expect(type).toEqual('function');
             });
-            it('Check returned value if registry.storage has property', function () {
-                var name = 'magento';
-
-                registry.storage.data.set(name, 'magentoValue');
-                expect(registry.has(name)).toEqual(true);
-            });
             it('Check returned value if registry.storage has not property', function () {
                 var name = 'magentoNonProperty';
 
                 expect(registry.has(name)).toEqual(false);
             });
-            it('Check called registry.storage.has with arguments', function () {
-                var elems = ['magento'];
-
-                registry.storage.has = jasmine.createSpy();
-                registry.has(elems);
-                expect(registry.storage.has).toHaveBeenCalledWith(elems);
-            });
         });
         describe('"registry.async" method', function () {
             it('Check for defined', function () {
@@ -149,22 +114,6 @@ define([
 
                 expect(type).toEqual('object');
             });
-            it('Check registry.storage for defined', function () {
-                registry.create();
-                expect(registry.storage).toBeDefined();
-            });
-            it('Check registry.storage type', function () {
-                registry.create();
-                expect(typeof registry.storage).toEqual('object');
-            });
-            it('Check registry.events for defined', function () {
-                registry.create();
-                expect(registry.events).toBeDefined();
-            });
-            it('Check registry.events type', function () {
-                registry.create();
-                expect(typeof registry.events).toEqual('object');
-            });
         });
     });
 });
diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/registry/storage.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/registry/storage.test.js
deleted file mode 100644
index a2e2fd3c1206b79b1da01ebba2f4cdb248a25ed7..0000000000000000000000000000000000000000
--- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/registry/storage.test.js
+++ /dev/null
@@ -1,122 +0,0 @@
-/**
- * Copyright © 2016 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-
-/*eslint max-nested-callbacks: 0*/
-
-define([
-    'Magento_Ui/js/lib/registry/storage'
-], function (Storage) {
-    'use strict';
-
-    describe('Magento_Ui/js/lib/registry/storage', function () {
-        var storage = new Storage();
-        describe('"Storage constructor"', function () {
-            it('Check for defined', function () {
-                expect(storage).toBeDefined();
-            });
-            it('Check type', function () {
-                var type = typeof storage;
-
-                expect(type).toEqual('object');
-            });
-            it('Check storage.data for defined', function () {
-                var data = storage.data;
-
-                expect(typeof data).toEqual('object');
-            });
-        });
-        describe('"storage.get" method', function () {
-            it('Check for defined', function () {
-                expect(storage.hasOwnProperty('get')).toBeDefined();
-            });
-            it('Check type', function () {
-                var type = typeof storage.get;
-
-                expect(type).toEqual('function');
-            });
-            it('Check returned value if argument is array values', function () {
-                var elem = 'magento',
-                    value = 'magentoValue';
-
-                storage.data.set(elem, value);
-                expect(storage.get([elem])).toEqual([value]);
-            });
-            it('Check returned value if called withot arguments', function () {
-                expect(storage.get()).toEqual([]);
-            });
-        });
-        describe('"storage.set" method', function () {
-            it('Check for defined', function () {
-                expect(storage.hasOwnProperty('set')).toBeDefined();
-            });
-            it('Check type', function () {
-                var type = typeof storage.set;
-
-                expect(type).toEqual('function');
-            });
-            it('Check returned value for defined', function () {
-                expect(storage.set()).toBeDefined();
-            });
-            it('Check returned value type', function () {
-                var type = typeof storage.set();
-
-                expect(type).toEqual('object');
-            });
-            it('Check returned value if argument is "elem, value" ', function () {
-                var elem = 'magento',
-                    value = 'magentoValue';
-
-                storage.set(elem, value);
-                expect(storage.data.get(elem)).toEqual(value);
-            });
-        });
-        describe('"storage.remove" method', function () {
-            it('Check for defined', function () {
-                expect(storage.hasOwnProperty('remove')).toBeDefined();
-            });
-            it('Check type', function () {
-                var type = typeof storage.remove;
-
-                expect(type).toEqual('function');
-            });
-            it('Check returned value for defined', function () {
-                expect(storage.remove([])).toBeDefined();
-            });
-            it('Check returned value type', function () {
-                var type = typeof storage.remove([]);
-
-                expect(type).toEqual('object');
-            });
-            it('Check if called with argument "elem" ', function () {
-                var elem = 'magento',
-                    value = 'magentoValue';
-
-                storage.data.set(elem, value);
-                storage.remove([elem]);
-                expect(storage.data.get(elem)).not.toBeDefined();
-            });
-        });
-        describe('"storage.has" method', function () {
-            it('Check for defined', function () {
-                expect(storage.hasOwnProperty('has')).toBeDefined();
-            });
-            it('Check type', function () {
-                var type = typeof storage.has;
-
-                expect(type).toEqual('function');
-            });
-            it('Check returned value if data has element property', function () {
-                var elem = 'magento',
-                    value = 'magentoValue';
-
-                storage.data.set(elem, value);
-                expect(storage.has([elem])).toEqual(true);
-            });
-            it('Check returned value if data has not element property', function () {
-                expect(storage.has(['value'])).toEqual(false);
-            });
-        });
-    });
-});
diff --git a/dev/tests/js/jasmine/tests/lib/mage/gallery.test.js b/dev/tests/js/jasmine/tests/lib/mage/gallery.test.js
deleted file mode 100644
index 984bdf0cc3919ca35d55f82bd730aa129ea935e6..0000000000000000000000000000000000000000
--- a/dev/tests/js/jasmine/tests/lib/mage/gallery.test.js
+++ /dev/null
@@ -1,154 +0,0 @@
-/**
- * Copyright © 2016 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-define([
-    'jquery',
-    'text!tests/assets/gallery/config.json',
-    'mage/gallery/gallery',
-    'magnifier/magnify'
-], function ($, config, gallery, magnifier) {
-
-    'use strict';
-
-    var body = $('body'),
-        galleryAPI,
-        conf = JSON.parse(config),
-        gallerySelector = '[data-gallery-role="gallery"]',
-        magnifierSelector = '[data-gallery-role="magnifier"]',
-        stageSelector = '[data-gallery-role="stage-shaft"]',
-        navSelector = '[data-gallery-role="nav-frame"]',
-        dotSelector = '[data-nav-type="dot"]',
-        navWrap = '[data-gallery-role="nav-wrap"]',
-        dataToUpdate = [
-            {
-                img: 'data:image/png;base64,' +
-                'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP4Xw8AAoABf5/NhYYAAAAASUVORK5CYII='
-            }, {
-                img: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAw' +
-                'CAAAAC0lEQVR42mP4Xw8AAoABf5/NhYYAAAAASUVORK5CYII='
-            }, {
-                img: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAw' +
-                'CAAAAC0lEQVR42mP4Xw8AAoABf5/NhYYAAAAASUVORK5CYII='
-            }, {
-                img: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAw' +
-                'CAAAAC0lEQVR42mP4Xw8AAoABf5/NhYYAAAAASUVORK5CYII='
-            }
-        ],
-        waitsFor = function (test, fn) {
-            if (test()) {
-                fn();
-            } else {
-                setTimeout(function () {
-                    waitsFor(test, fn);
-                }, 10);
-            }
-        };
-
-    gallery(magnifier(conf, body), body);
-
-    beforeEach(function () {
-        galleryAPI = $(gallerySelector).data('gallery');
-    });
-
-    describe('magnifier/magnify', function () {
-
-        if ('ontouchstart' in document.documentElement) {
-            it('magnifier is not initialized on mobile platforms', function () {
-                expect($(magnifierSelector).length).toBe(0);
-            });
-        } else {
-            it('magnifier is defined', function () {
-                expect($(gallerySelector).magnify).toBeDefined();
-                expect(typeof $(gallerySelector).magnify).toBe('function');
-                expect($(magnifierSelector).hasClass('hidden')).toBeTruthy();
-            });
-
-            it('magnifier is initialized on desktop platforms', function () {
-                expect($(magnifierSelector + ' img').attr('src')).toBe($(stageSelector + ' img').attr('src'));
-            });
-            it('magnifier appearing on event on desktop platforms', function () {
-                var ev = conf.magnifierOpts.eventType === 'click' ? 'click' : 'mouseover';
-                expect($($(magnifierSelector).children()[0]).hasClass('magnifier-large hidden')).toBeTruthy();
-                $(stageSelector + ' img').trigger(ev);
-                expect($($(magnifierSelector).children()[0]).hasClass('magnifier-large hidden')).toBeFalsy();
-                $(stageSelector + ' img').trigger('mouseleave');
-            });
-        }
-    });
-
-    describe('mage/gallery/gallery', function () {
-
-        it('gallery loaded', function () {
-            expect($(navSelector).length).toBe(conf.data.length);
-        });
-
-        it('show last', function () {
-            galleryAPI.last();
-            expect($(navSelector + ':eq(' + (conf.data.length - 1) + ')')
-                .attr('data-active') === 'true').toBeTruthy();
-        });
-
-        it('show first', function () {
-            galleryAPI.first();
-            expect($(navSelector + ':eq(0)').attr('data-active') === 'true').toBeTruthy();
-        });
-
-        it('show next', function () {
-            galleryAPI.next();
-            expect($(navSelector + ':eq(1)').attr('data-active') === 'true').toBeTruthy();
-        });
-
-        it('show previous', function () {
-            galleryAPI.prev();
-            expect($(navSelector + ':eq(0)').attr('data-active') === 'true').toBeTruthy();
-        });
-
-        it('show by number', function () {
-            galleryAPI.seek(3);
-            expect($(navSelector + ':eq(2)').attr('data-active') === 'true').toBeTruthy();
-        });
-
-        it('update options', function () {
-            expect($(navSelector).attr('data-nav-type') === 'thumb').toBeTruthy();
-            galleryAPI.updateOptions({
-                nav: 'dots'
-            });
-            expect($(dotSelector).length).toBe(conf.data.length);
-        });
-
-        it('update data', function () {
-            galleryAPI.updateData(dataToUpdate);
-            expect($(dotSelector).length).toBe(dataToUpdate.length);
-        });
-
-        it('breakpoints override configs', function () {
-            expect($('.fotorama__arr').css('display')).toBe('block');
-        });
-
-        it('fullscreen enter', function (done) {
-            expect($(navWrap).css('display') === 'block').toBeTruthy();
-            galleryAPI.fotorama.requestFullScreen();
-
-            waitsFor(function () {
-                return $(navWrap).css('display') !== 'block';
-            }, function () {
-                expect($(navWrap).css('display') === 'none').toBeTruthy();
-                done();
-            });
-        });
-
-        it('fullscreen exit', function (done) {
-            expect($(navWrap).css('display') === 'none').toBeTruthy();
-            galleryAPI.fotorama.cancelFullScreen();
-
-            waitsFor(function () {
-                return $(navWrap).css('display') !== 'none';
-            }, function () {
-                expect($(navWrap).css('display') === 'block').toBeTruthy();
-                done();
-            });
-        });
-
-    });
-});
diff --git a/dev/tests/static/get_github_changes.php b/dev/tests/static/get_github_changes.php
index c142aae18d8ecd5a4ab3fa895e32e5510b71683b..f332208cd17d0861dd1b28bd7096a0b3fe0066a5 100644
--- a/dev/tests/static/get_github_changes.php
+++ b/dev/tests/static/get_github_changes.php
@@ -12,9 +12,9 @@
 // @codingStandardsIgnoreFile
 
 define(
-'USAGE',
-<<<USAGE
-    php -f get_github_changes.php --
+    'USAGE',
+    <<<USAGE
+        php -f get_github_changes.php --
     --output-file="<output_file>"
     --base-path="<base_path>"
     --repo="<main_repo>"
@@ -36,6 +36,8 @@ $fileExtensions = explode(',', isset($options['file-extensions']) ? $options['fi
 
 $mainline = 'mainline_' . (string)rand(0, 9999);
 $repo = getRepo($options, $mainline);
+$branches = $repo->getBranches('--remotes');
+generateBranchesList($options['output-file'], $branches, $options['branch']);
 $changes = retrieveChangesAcrossForks($mainline, $repo, $options['branch']);
 $changedFiles = getChangedFiles($changes, $fileExtensions);
 generateChangedFilesList($options['output-file'], $changedFiles);
@@ -57,6 +59,25 @@ function generateChangedFilesList($outputFile, $changedFiles)
     fclose($changedFilesList);
 }
 
+/**
+ * Generates a file containing origin branches
+ *
+ * @param string $outputFile
+ * @param array $branches
+ * @param string $branchName
+ * @return void
+ */
+function generateBranchesList($outputFile, $branches, $branchName)
+{
+    $branchOutputFile = str_replace('changed_files', 'branches', $outputFile);
+    $branchesList = fopen($branchOutputFile, 'w');
+    fwrite($branchesList, $branchName . PHP_EOL);
+    foreach ($branches as $branch) {
+        fwrite($branchesList, substr(strrchr($branch, '/'), 1) . PHP_EOL);
+    }
+    fclose($branchesList);
+}
+
 /**
  * Gets list of changed files
  *
@@ -84,7 +105,7 @@ function getChangedFiles(array $changes, array $fileExtensions)
  *
  * @param array $options
  * @param string $mainline
- * @return array
+ * @return GitRepo
  * @throws Exception
  */
 function getRepo($options, $mainline)
@@ -203,6 +224,19 @@ class GitRepo
         $this->call(sprintf('fetch %s', $remoteAlias));
     }
 
+    /**
+     * Returns branches
+     *
+     * @param string $source
+     * @return array|mixed
+     */
+    public function getBranches($source = '--all')
+    {
+        $result = $this->call(sprintf('branch ' . $source));
+
+        return is_array($result) ? $result : [];
+    }
+
     /**
      * Returns files changes between branch and HEAD
      *
diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Framework/Search/RequestConfigTest.php b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Framework/Search/RequestConfigTest.php
index 52244463a535693746eddf8f4e0d07b05cf9de08..ff12618b399639fb8c4f56a422828cbb7c0c1e67 100644
--- a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Framework/Search/RequestConfigTest.php
+++ b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Framework/Search/RequestConfigTest.php
@@ -100,7 +100,7 @@ Element 'filterReference': The attribute 'clause' is required but missing.
 Element 'filterReference': The attribute 'ref' is required but missing.
 Element 'filter': The attribute 'field' is required but missing.
 Element 'metric', attribute 'type': [facet 'enumeration'] " .
-                "The value 'sumasdasd' is not an element of the set {'sum', 'count', 'min', 'max'}.
+                "The value 'sumasdasd' is not an element of the set {'sum', 'count', 'min', 'max', 'avg'}.
 Element 'metric', attribute 'type': 'sumasdasd' is not a valid value of the local atomic type.
 Element 'bucket': Missing child element(s). Expected is one of ( metrics, ranges ).
 Element 'request': Missing child element(s). Expected is ( from )."
diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/_files/blacklist/reference.txt b/dev/tests/static/testsuite/Magento/Test/Integrity/_files/blacklist/reference.txt
index 836a928dc5a72cf6a517dc1ae7f1bbc61e62a763..e4078a959c7a89284e508a884229f69d80e2e25a 100644
--- a/dev/tests/static/testsuite/Magento/Test/Integrity/_files/blacklist/reference.txt
+++ b/dev/tests/static/testsuite/Magento/Test/Integrity/_files/blacklist/reference.txt
@@ -115,3 +115,4 @@ DoubleColon
 \Magento\TestModuleMessageQueueConfiguration\AsyncHandler
 \Magento\TestModuleMessageQueueConfiguration\SyncHandler
 \Magento\TestModuleAsyncAmqp\Model\AsyncTestData
+\Magento\Mtf\Client\ElementInterface
diff --git a/dev/tests/static/testsuite/Magento/Test/Legacy/ModuleDBChangeTest.php b/dev/tests/static/testsuite/Magento/Test/Legacy/ModuleDBChangeTest.php
index 87bd329ef3b5611475c6ee9486cdc9f27c4ea5fe..2f3d312fb41ffba1287bafd324a64ac751316d5c 100644
--- a/dev/tests/static/testsuite/Magento/Test/Legacy/ModuleDBChangeTest.php
+++ b/dev/tests/static/testsuite/Magento/Test/Legacy/ModuleDBChangeTest.php
@@ -15,38 +15,49 @@ class ModuleDBChangeTest extends \PHPUnit_Framework_TestCase
     /**
      * @var string
      */
-    protected static $changedFilesPattern = __DIR__ . '/../_files/changed_files*';
+    private static $branchesFilesPattern = __DIR__ . '/../_files/branches*';
 
     /**
      * @var string
      */
-    protected static $changedFileList = '';
+    private static $changedFilesPattern = __DIR__ . '/../_files/changed_files*';
 
     /**
-     * @var string Path for Magento's composer.json
+     * @var string
      */
-    protected static $composerFilePath = BP . '/composer.json';
+    private static $changedFileList = '';
 
     /**
-     * @var bool Is tests executes on develop branch
+     * @var bool
      */
-    protected static $isOnDevVersion = false;
+    private static $actualBranch = false;
 
     /**
      *  Set changed files paths and list for all projects
      */
     public static function setUpBeforeClass()
     {
-        foreach (glob(self::$changedFilesPattern) as $changedFile) {
-            self::$changedFileList .= file_get_contents($changedFile) . PHP_EOL;
-        }
+        foreach (glob(self::$branchesFilesPattern) as $branchesFile) {
+            //get the current branchname from the first line
+            $branchName = trim(file($branchesFile)[0]);
+            if ($branchName === 'develop') {
+                self::$actualBranch = true;
+            } else {
+                //get current minor branch name
+                preg_match('|^(\d+\.\d+)|', $branchName, $minorBranch);
+                $branchName = $minorBranch[0];
+
+                //get all version branches
+                preg_match_all('|^(\d+\.\d+)|m', file_get_contents($branchesFile), $matches);
 
-        if (file_exists(self::$composerFilePath)) {
-            $jsonData = json_decode(file_get_contents(self::$composerFilePath));
-            if (substr((string) $jsonData->version, -4) == '-dev') {
-                self::$isOnDevVersion = true;
+                //check is this a latest release branch
+                self::$actualBranch = ($branchName == max($matches[0]));
             }
         }
+
+        foreach (glob(self::$changedFilesPattern) as $changedFile) {
+            self::$changedFileList .= file_get_contents($changedFile) . PHP_EOL;
+        }
     }
 
     /**
@@ -54,15 +65,14 @@ class ModuleDBChangeTest extends \PHPUnit_Framework_TestCase
      */
     public function testModuleXmlFiles()
     {
-        if (self::$isOnDevVersion) {
-            $this->markTestSkipped('This test isn\'t applicable to the developer version of Magento');
+        if (!self::$actualBranch) {
+            preg_match_all('|etc/module\.xml$|mi', self::$changedFileList, $matches);
+            $this->assertEmpty(
+                reset($matches),
+                'module.xml changes for patch releases in non-actual branches are not allowed:' . PHP_EOL .
+                implode(PHP_EOL, array_values(reset($matches)))
+            );
         }
-        preg_match_all('|etc/module\.xml$|mi', self::$changedFileList, $matches);
-        $this->assertEmpty(
-            reset($matches),
-            'module.xml changes for patch releases in non-actual branches are not allowed:' . PHP_EOL .
-            implode(PHP_EOL, array_values(reset($matches)))
-        );
     }
 
     /**
@@ -70,14 +80,13 @@ class ModuleDBChangeTest extends \PHPUnit_Framework_TestCase
      */
     public function testModuleSetupFiles()
     {
-        if (self::$isOnDevVersion) {
-            $this->markTestSkipped('This test isn\'t applicable to the developer version of Magento');
+        if (!self::$actualBranch) {
+            preg_match_all('|app/code/Magento/[^/]+/Setup/[^/]+$|mi', self::$changedFileList, $matches);
+            $this->assertEmpty(
+                reset($matches),
+                'Code with changes for DB schema or data in non-actual branches are not allowed:' . PHP_EOL .
+                implode(PHP_EOL, array_values(reset($matches)))
+            );
         }
-        preg_match_all('|app/code/Magento/[^/]+/Setup/[^/]+$|mi', self::$changedFileList, $matches);
-        $this->assertEmpty(
-            reset($matches),
-            'Code with changes for DB schema or data in non-actual branches are not allowed:' . PHP_EOL .
-            implode(PHP_EOL, array_values(reset($matches)))
-        );
     }
 }
diff --git a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_methods.php b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_methods.php
index bc49ab15a7d54151759f7e183fb36a8a7b6571c6..2ce1bf02bf3896da26a633c158b77697876c4d02 100644
--- a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_methods.php
+++ b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_methods.php
@@ -2155,7 +2155,6 @@ return [
     ['addOrderedQty', 'Magento\Reports\Model\ResourceModel\Product\Collection'],
     ['prepareForProductsInCarts', 'Magento\Reports\Model\ResourceModel\Quote\Collection'],
     ['getOrdersSubSelect', 'Magento\Reports\Model\ResourceModel\Quote\Collection'],
-    ['isOrderIncrementIdUsed', 'Magento\Quote\Model\ResourceModel\Quote'],
     ['isStateProtected', 'Magento\Sales\Model\Order'],
     ['_getBundleOptions', 'Magento\Bundle\Block\Checkout\Cart\Item\Renderer'],
     ['_getSelectionFinalPrice', 'Magento\Bundle\Block\Checkout\Cart\Item\Renderer'],
diff --git a/lib/internal/Magento/Framework/DB/Adapter/Pdo/Mysql.php b/lib/internal/Magento/Framework/DB/Adapter/Pdo/Mysql.php
index cfbeb4f54c9e29d2f7b320b57c51ae7a7b31a676..9af29ab2c458d8a8b09a73e570695d133bd7a123 100644
--- a/lib/internal/Magento/Framework/DB/Adapter/Pdo/Mysql.php
+++ b/lib/internal/Magento/Framework/DB/Adapter/Pdo/Mysql.php
@@ -341,6 +341,9 @@ class Mysql extends \Zend_Db_Adapter_Pdo_Mysql implements AdapterInterface
     /**
      * Creates a PDO object and connects to the database.
      *
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
+     * @SuppressWarnings(PHPMD.NPathComplexity)
+     *
      * @return void
      * @throws \Zend_Db_Adapter_Exception
      */
@@ -371,6 +374,10 @@ class Mysql extends \Zend_Db_Adapter_Pdo_Mysql implements AdapterInterface
             list($this->_config['host'], $this->_config['port']) = explode(':', $this->_config['host']);
         }
 
+        if (!isset($this->_config['driver_options'][\PDO::MYSQL_ATTR_MULTI_STATEMENTS])) {
+            $this->_config['driver_options'][\PDO::MYSQL_ATTR_MULTI_STATEMENTS] = false;
+        }
+
         $this->logger->startTimer();
         parent::_connect();
         $this->logger->logStats(LoggerInterface::TYPE_CONNECT, '');
@@ -562,6 +569,7 @@ class Mysql extends \Zend_Db_Adapter_Pdo_Mysql implements AdapterInterface
      * @throws \Zend_Db_Adapter_Exception To re-throw \PDOException.
      * @throws LocalizedException In case multiple queries are attempted at once, to protect from SQL injection
      * @SuppressWarnings(PHPMD.CyclomaticComplexity)
+     * @deprecated
      */
     public function multiQuery($sql, $bind = [])
     {
@@ -728,6 +736,8 @@ class Mysql extends \Zend_Db_Adapter_Pdo_Mysql implements AdapterInterface
      * @return array
      * @SuppressWarnings(PHPMD.CyclomaticComplexity)
      * @SuppressWarnings(PHPMD.NPathComplexity)
+
+     * @deprecated
      */
     protected function _splitMultiQuery($sql)
     {
diff --git a/lib/internal/Magento/Framework/Filter/Input/MaliciousCode.php b/lib/internal/Magento/Framework/Filter/Input/MaliciousCode.php
index 10f1289b90c1841c7e5c9c014b3943132ab8e5f3..ad4746a36513c4dd028b1c81d27dbbcec70148eb 100644
--- a/lib/internal/Magento/Framework/Filter/Input/MaliciousCode.php
+++ b/lib/internal/Magento/Framework/Filter/Input/MaliciousCode.php
@@ -31,7 +31,7 @@ class MaliciousCode implements \Zend_Filter_Interface
         //js attributes
         '/(ondblclick|onclick|onkeydown|onkeypress|onkeyup|onmousedown|onmousemove|onmouseout|onmouseover|onmouseup|onload|onunload|onerror)=[^<]*(?=\/*\>)/Uis',
         //tags
-        '/<\/?(script|meta|link|frame|iframe).*>/Uis',
+        '/<\/?(script|meta|link|frame|iframe|object).*>/Uis',
         //base64 usage
         '/src=[^<]*base64[^<]*(?=\/*\>)/Uis',
     ];
diff --git a/lib/internal/Magento/Framework/Filter/Test/Unit/Input/MaliciousCodeTest.php b/lib/internal/Magento/Framework/Filter/Test/Unit/Input/MaliciousCodeTest.php
index 512d8e89750bc24c666e58237668ad63f7e440b8..93de72e3c57c5610882aece936c9346be40dea64 100644
--- a/lib/internal/Magento/Framework/Filter/Test/Unit/Input/MaliciousCodeTest.php
+++ b/lib/internal/Magento/Framework/Filter/Test/Unit/Input/MaliciousCodeTest.php
@@ -89,6 +89,7 @@ class MaliciousCodeTest extends \PHPUnit_Framework_TestCase
                     'Tag is removed <link>SomeLink</link>',
                     'Tag is removed <frame>SomeFrame</frame>',
                     'Tag is removed <iframe>SomeIFrame</iframe>',
+                    'Tag is removed <object>SomeObject</object>',
                 ],
                 [
                     'Tag is removed SomeScript',
@@ -96,6 +97,7 @@ class MaliciousCodeTest extends \PHPUnit_Framework_TestCase
                     'Tag is removed SomeLink',
                     'Tag is removed SomeFrame',
                     'Tag is removed SomeIFrame',
+                    'Tag is removed SomeObject',
                 ],
             ],
             'Base64' => [
diff --git a/lib/internal/Magento/Framework/HTTP/Adapter/Curl.php b/lib/internal/Magento/Framework/HTTP/Adapter/Curl.php
index fb00e9f59c83097b13274e47e7b0a7a52634ecc2..181783c7b2115d8a216c681077e116e98344d15c 100644
--- a/lib/internal/Magento/Framework/HTTP/Adapter/Curl.php
+++ b/lib/internal/Magento/Framework/HTTP/Adapter/Curl.php
@@ -20,7 +20,15 @@ class Curl implements \Zend_Http_Client_Adapter_Interface
      *
      * @var array
      */
-    protected $_config = [];
+    protected $_config = [
+        'protocols' => (CURLPROTO_HTTP
+            | CURLPROTO_HTTPS
+            | CURLPROTO_FTP
+            | CURLPROTO_FTPS
+        ),
+        'verifypeer' => true,
+        'verifyhost' => 2,
+    ];
 
     /**
      * Curl handle
@@ -41,7 +49,10 @@ class Curl implements \Zend_Http_Client_Adapter_Interface
         'ssl_cert'     => CURLOPT_SSLCERT,
         'userpwd'      => CURLOPT_USERPWD,
         'useragent'    => CURLOPT_USERAGENT,
-        'referer'      => CURLOPT_REFERER
+        'referer'      => CURLOPT_REFERER,
+        'protocols'    => CURLOPT_PROTOCOLS,
+        'verifypeer'   => CURLOPT_SSL_VERIFYPEER,
+        'verifyhost'   => CURLOPT_SSL_VERIFYHOST,
     ];
 
     /**
@@ -55,8 +66,6 @@ class Curl implements \Zend_Http_Client_Adapter_Interface
      * Apply current configuration array to transport resource
      *
      * @return \Magento\Framework\HTTP\Adapter\Curl
-     * @SuppressWarnings(PHPMD.NPathComplexity)
-     * @SuppressWarnings(PHPMD.UnusedLocalVariable)
      */
     protected function _applyConfig()
     {
@@ -65,22 +74,28 @@ class Curl implements \Zend_Http_Client_Adapter_Interface
             curl_setopt($this->_getResource(), $option, $value);
         }
 
-        if (empty($this->_config)) {
-            return $this;
+        // apply config options
+        foreach ($this->getDefaultConfig() as $option => $value) {
+            curl_setopt($this->_getResource(), $option, $value);
         }
 
-        $verifyPeer = isset($this->_config['verifypeer']) ? $this->_config['verifypeer'] : true;
-        curl_setopt($this->_getResource(), CURLOPT_SSL_VERIFYPEER, $verifyPeer);
-
-        $verifyHost = isset($this->_config['verifyhost']) ? $this->_config['verifyhost'] : 2;
-        curl_setopt($this->_getResource(), CURLOPT_SSL_VERIFYHOST, $verifyHost);
+        return $this;
+    }
 
-        foreach ($this->_config as $param => $curlOption) {
+    /**
+     * Get default options
+     *
+     * @return array
+     */
+    private function getDefaultConfig()
+    {
+        $config = [];
+        foreach (array_keys($this->_config) as $param) {
             if (array_key_exists($param, $this->_allowedParams)) {
-                curl_setopt($this->_getResource(), $this->_allowedParams[$param], $this->_config[$param]);
+                $config[$this->_allowedParams[$param]] = $this->_config[$param];
             }
         }
-        return $this;
+        return $config;
     }
 
     /**
@@ -116,7 +131,9 @@ class Curl implements \Zend_Http_Client_Adapter_Interface
      */
     public function setConfig($config = [])
     {
-        $this->_config = $config;
+        foreach ($config as $key => $value) {
+            $this->_config[$key] = $value;
+        }
         return $this;
     }
 
@@ -268,6 +285,13 @@ class Curl implements \Zend_Http_Client_Adapter_Interface
 
         $multihandle = curl_multi_init();
 
+        // add default parameters
+        foreach ($this->getDefaultConfig() as $defaultOption => $defaultValue) {
+            if (!isset($options[$defaultOption])) {
+                $options[$defaultOption] = $defaultValue;
+            }
+        }
+
         foreach ($urls as $key => $url) {
             $handles[$key] = curl_init();
             curl_setopt($handles[$key], CURLOPT_URL, $url);
diff --git a/lib/internal/Magento/Framework/HTTP/Test/Unit/Adapter/CurlTest.php b/lib/internal/Magento/Framework/HTTP/Test/Unit/Adapter/CurlTest.php
index 255be0a5596a622151e9e1091841d4f5ff8bf58b..37cd33d18683062ab48d16ae8aae2733def7a75e 100644
--- a/lib/internal/Magento/Framework/HTTP/Test/Unit/Adapter/CurlTest.php
+++ b/lib/internal/Magento/Framework/HTTP/Test/Unit/Adapter/CurlTest.php
@@ -10,10 +10,14 @@ use \Magento\Framework\HTTP\Adapter\Curl;
 
 class CurlTest extends \PHPUnit_Framework_TestCase
 {
-    /** @var Curl */
+    /**
+     * @var Curl
+     */
     protected $model;
 
-    /** @var \Closure */
+    /**
+     * @var \Closure
+     */
     public static $curlExectClosure;
 
     protected function setUp()
@@ -42,4 +46,3 @@ class CurlTest extends \PHPUnit_Framework_TestCase
         ];
     }
 }
-
diff --git a/lib/internal/Magento/Framework/ObjectManager/Config/Compiled.php b/lib/internal/Magento/Framework/ObjectManager/Config/Compiled.php
index a3ed3b941844eec7497eb233d1c43e74045c45e1..779e8cf0a0e5ecf15b0fcb6da1e48b80a5bb3072 100644
--- a/lib/internal/Magento/Framework/ObjectManager/Config/Compiled.php
+++ b/lib/internal/Magento/Framework/ObjectManager/Config/Compiled.php
@@ -1,15 +1,15 @@
 <?php
 /**
- *
  * Copyright © 2016 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
 namespace Magento\Framework\ObjectManager\Config;
 
+use Magento\Framework\ObjectManager\ConfigInterface;
 use Magento\Framework\ObjectManager\ConfigCacheInterface;
 use Magento\Framework\ObjectManager\RelationsInterface;
 
-class Compiled implements \Magento\Framework\ObjectManager\ConfigInterface
+class Compiled implements ConfigInterface
 {
     /**
      * @var array
@@ -129,9 +129,15 @@ class Compiled implements \Magento\Framework\ObjectManager\ConfigInterface
      */
     public function extend(array $configuration)
     {
-        $this->arguments = $configuration['arguments'];
-        $this->virtualTypes = $configuration['instanceTypes'];
-        $this->preferences = $configuration['preferences'];
+        $this->arguments = isset($configuration['arguments'])
+            ? array_replace($this->arguments, $configuration['arguments'])
+            : $this->arguments;
+        $this->virtualTypes = isset($configuration['instanceTypes'])
+            ? array_replace($this->virtualTypes, $configuration['instanceTypes'])
+            : $this->virtualTypes;
+        $this->preferences = isset($configuration['preferences'])
+            ? array_replace($this->preferences, $configuration['preferences'])
+            : $this->preferences;
     }
 
     /**
diff --git a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Adapter.php b/lib/internal/Magento/Framework/Search/Adapter/Mysql/Adapter.php
index 8ddb6255b9b862a37dea1aaefd742a4c03923d24..3d280f1224b8f3bb2e9082436fa7524308730387 100644
--- a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Adapter.php
+++ b/lib/internal/Magento/Framework/Search/Adapter/Mysql/Adapter.php
@@ -71,6 +71,7 @@ class Adapter implements AdapterInterface
 
     /**
      * {@inheritdoc}
+     * @throws \LogicException
      */
     public function query(RequestInterface $request)
     {
diff --git a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Aggregation/Builder/Metrics.php b/lib/internal/Magento/Framework/Search/Adapter/Mysql/Aggregation/Builder/Metrics.php
index 5860591eaf702494614ec89a90e816e159ffeb12..cf544eb126e1195096603979bd7378e08f44730d 100644
--- a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Aggregation/Builder/Metrics.php
+++ b/lib/internal/Magento/Framework/Search/Adapter/Mysql/Aggregation/Builder/Metrics.php
@@ -14,7 +14,7 @@ class Metrics
      *
      * @var string[]
      */
-    private $mapMetrics = ['count', 'sum', 'min', 'max', 'avg'];
+    private $allowedMetrics = ['count', 'sum', 'min', 'max', 'avg'];
 
     /**
      * Build metrics for Select->columns
@@ -30,7 +30,7 @@ class Metrics
 
         foreach ($metrics as $metric) {
             $metricType = $metric->getType();
-            if (in_array($metricType, $this->mapMetrics)) {
+            if (in_array($metricType, $this->allowedMetrics, true)) {
                 $selectAggregations[$metricType] = "$metricType(main_table.value)";
             }
         }
diff --git a/lib/internal/Magento/Framework/Search/etc/requests.xsd b/lib/internal/Magento/Framework/Search/etc/requests.xsd
index f185699c5a5e890757850fa8985b2e0400c56c35..294232513b7d2ec1938e243423a3113e151fd0c0 100644
--- a/lib/internal/Magento/Framework/Search/etc/requests.xsd
+++ b/lib/internal/Magento/Framework/Search/etc/requests.xsd
@@ -263,6 +263,7 @@
               <xs:enumeration value="count" />
               <xs:enumeration value="min" />
               <xs:enumeration value="max" />
+              <xs:enumeration value="avg" />
             </xs:restriction>
           </xs:simpleType>
         </xs:attribute>
diff --git a/lib/internal/Magento/Framework/Session/SessionManager.php b/lib/internal/Magento/Framework/Session/SessionManager.php
index e8013b024f4384e2c9b2261daed97a2ccbfb7f03..a517f1fd0b0b744cd44bad6b78ddd9c687a1fab5 100644
--- a/lib/internal/Magento/Framework/Session/SessionManager.php
+++ b/lib/internal/Magento/Framework/Session/SessionManager.php
@@ -298,6 +298,7 @@ class SessionManager implements SessionManagerInterface
             return;
         }
 
+        session_regenerate_id(true);
         session_destroy();
         if ($options['send_expire_cookie']) {
             $this->expireSessionCookie();
diff --git a/lib/internal/Magento/Framework/Test/Unit/ObjectManager/Config/CompiledTest.php b/lib/internal/Magento/Framework/Test/Unit/ObjectManager/Config/CompiledTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..3dd9f5065a1421ec822d4a81377ea81a5c3f8f52
--- /dev/null
+++ b/lib/internal/Magento/Framework/Test/Unit/ObjectManager/Config/CompiledTest.php
@@ -0,0 +1,91 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Framework\Test\Unit\ObjectManager\Config;
+
+use Magento\Framework\ObjectManager\Config\Compiled as CompiledConfig;
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper;
+
+class CompiledTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var ObjectManagerHelper
+     */
+    private $objectManagerHelper;
+
+    protected function setUp()
+    {
+        $this->objectManagerHelper = new ObjectManagerHelper($this);
+    }
+
+    /**
+     * @param array $initialData
+     * @param array $configuration
+     * @param array $expectedArguments
+     * @param array $expectedVirtualTypes
+     * @param array $expectedPreferences
+     *
+     * @dataProvider extendDataProvider
+     */
+    public function testExtend(
+        array $initialData,
+        array $configuration,
+        array $expectedArguments,
+        array $expectedVirtualTypes,
+        array $expectedPreferences
+    ) {
+        /** @var CompiledConfig $compiledConfig */
+        $compiledConfig = $this->objectManagerHelper->getObject(CompiledConfig::class, ['data' => $initialData]);
+        $compiledConfig->extend($configuration);
+
+        foreach ($expectedArguments as $type => $arguments) {
+            $this->assertEquals($arguments, $compiledConfig->getArguments($type));
+        }
+
+        $this->assertEquals($expectedVirtualTypes, $compiledConfig->getVirtualTypes());
+        $this->assertEquals($expectedPreferences, $compiledConfig->getPreferences());
+    }
+
+    /**
+     * @return array
+     */
+    public function extendDataProvider()
+    {
+        return [
+            [
+                'initialData' => [
+                    'arguments' => [
+                        'type1' => serialize(['argument1_1' => 'argumentValue1_1', 'argument1_2' => 'argumentValue1_2'])
+                    ],
+                    'instanceTypes' => [
+                        'instanceType1' => 'instanceTypeValue1', 'instanceType2' => 'instanceTypeValue2'
+                    ],
+                    'preferences' => ['preference1' => 'preferenceValue1', 'preference2' => 'preferenceValue2']
+                ],
+                'configuration' => [
+                    'arguments' => [
+                        'type1' => serialize(['argument1_1' => 'newArgumentValue1_1']),
+                        'type2' => serialize(['argument2_1' => 'newArgumentValue2_1'])
+                    ],
+                    'instanceTypes' => [
+                        'instanceType2' => 'newInstanceTypeValue2', 'instanceType3' => 'newInstanceTypeValue3'
+                    ],
+                    'preferences' => ['preference1' => 'newPreferenceValue1']
+                ],
+                'expectedArguments' => [
+                    'type1' => ['argument1_1' => 'newArgumentValue1_1'],
+                    'type2' => ['argument2_1' => 'newArgumentValue2_1']
+                ],
+                'expectedVirtualTypes' => [
+                    'instanceType1' => 'instanceTypeValue1', 'instanceType2' => 'newInstanceTypeValue2',
+                    'instanceType3' => 'newInstanceTypeValue3'
+                ],
+                'expectedPreferences' => [
+                    'preference1' => 'newPreferenceValue1', 'preference2' => 'preferenceValue2'
+                ]
+            ]
+        ];
+    }
+}
diff --git a/lib/internal/Magento/Framework/Validator/AllowedProtocols.php b/lib/internal/Magento/Framework/Validator/AllowedProtocols.php
new file mode 100644
index 0000000000000000000000000000000000000000..3c7bbb3d997236aae0e7cc91994505af78620957
--- /dev/null
+++ b/lib/internal/Magento/Framework/Validator/AllowedProtocols.php
@@ -0,0 +1,59 @@
+<?php
+/**
+ * Protocol validator
+ *
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Framework\Validator;
+
+use \Zend\Uri\Uri;
+
+/**
+ * Check is URI starts from allowed protocol
+ *
+ * Class AllowedProtocols
+ * @package Magento\Framework\Validator
+ */
+class AllowedProtocols extends AbstractValidator
+{
+    /**
+     * List of supported protocols
+     *
+     * @var array
+     */
+    private $listOfProtocols = [
+        'http',
+        'https',
+    ];
+
+    /**
+     * Constructor.
+     * @param array $listOfProtocols
+     */
+    public function __construct($listOfProtocols = [])
+    {
+        if (count($listOfProtocols)) {
+            $this->listOfProtocols = $listOfProtocols;
+        }
+    }
+
+    /**
+     * Validate URI
+     *
+     * @param string $value
+     * @return bool
+     */
+    public function isValid($value)
+    {
+        $uri = new Uri($value);
+        $isValid = in_array(
+            strtolower($uri->getScheme()),
+            $this->listOfProtocols
+        );
+        if (!$isValid) {
+            $this->_addMessages(["Protocol isn't allowed"]);
+        }
+        return $isValid;
+    }
+}
diff --git a/lib/internal/Magento/Framework/Validator/Test/Unit/UrlTest.php b/lib/internal/Magento/Framework/Validator/Test/Unit/UrlTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..d66f84289424920d3d8aca1e5b39e76fa1ad1503
--- /dev/null
+++ b/lib/internal/Magento/Framework/Validator/Test/Unit/UrlTest.php
@@ -0,0 +1,76 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Framework\Validator\Test\Unit;
+
+use Magento\Framework\Validator\Url as UrlValidator;
+
+class UrlTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var UrlValidator
+     */
+    private $validator;
+
+    protected function setUp()
+    {
+        $this->validator = new UrlValidator();
+    }
+
+    /**
+     * @param array $allowedSchemes
+     * @param string $url
+     * @param bool $expectedResult
+     * @dataProvider isValidDataProvider
+     */
+    public function testIsValid(array $allowedSchemes, $url, $expectedResult)
+    {
+        $this->assertSame($expectedResult, $this->validator->isValid($url, $allowedSchemes));
+    }
+
+    /**
+     * @return array
+     */
+    public function isValidDataProvider()
+    {
+        return [
+            [
+                'allowedSchemes' => [],
+                'url' => 'http://example.com',
+                'expectedResult' => true,
+            ],
+            [
+                'allowedSchemes' => ['http'],
+                'url' => 'http://example.com',
+                'expectedResult' => true,
+            ],
+            [
+                'allowedSchemes' => [],
+                'url' => 'https://example.com',
+                'expectedResult' => true,
+            ],
+            [
+                'allowedSchemes' => ['https'],
+                'url' => 'https://example.com',
+                'expectedResult' => true,
+            ],
+            [
+                'allowedSchemes' => [],
+                'url' => 'http://example.com_test',
+                'expectedResult' => false,
+            ],
+            [
+                'allowedSchemes' => [],
+                'url' => 'ftp://example.com',
+                'expectedResult' => true,
+            ],
+            [
+                'allowedSchemes' => ['ftp'],
+                'url' => 'ftp://example.com',
+                'expectedResult' => true,
+            ],
+        ];
+    }
+}
diff --git a/lib/internal/Magento/Framework/Validator/Url.php b/lib/internal/Magento/Framework/Validator/Url.php
new file mode 100644
index 0000000000000000000000000000000000000000..27262009b2d200bc354947208bfd075898a3ac0e
--- /dev/null
+++ b/lib/internal/Magento/Framework/Validator/Url.php
@@ -0,0 +1,37 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Framework\Validator;
+
+/**
+ * Class Url validates URL and checks that it has allowed scheme
+ */
+class Url
+{
+    /**
+     * Validate URL and check that it has allowed scheme
+     *
+     * @param string $value
+     * @param array $allowedSchemes
+     * @return bool
+     */
+    public function isValid($value, array $allowedSchemes = [])
+    {
+        $isValid = true;
+
+        if (!filter_var($value, FILTER_VALIDATE_URL)) {
+            $isValid = false;
+        }
+
+        if ($isValid && !empty($allowedSchemes)) {
+            $url = parse_url($value);
+            if (empty($url['scheme']) || !in_array($url['scheme'], $allowedSchemes)) {
+                $isValid = false;
+            }
+        }
+
+        return $isValid;
+    }
+}
diff --git a/lib/internal/Magento/Framework/View/Layout/Reader/Block.php b/lib/internal/Magento/Framework/View/Layout/Reader/Block.php
index 9831c52a4656310e99c424ce7cc7dd8cd17f68fe..ff5ade125521acff54a182cea51e7f34985292d0 100755
--- a/lib/internal/Magento/Framework/View/Layout/Reader/Block.php
+++ b/lib/internal/Magento/Framework/View/Layout/Reader/Block.php
@@ -207,13 +207,15 @@ class Block implements Layout\ReaderInterface
         $elementRemove = filter_var($currentElement->getAttribute('remove'), FILTER_VALIDATE_BOOLEAN);
         if ($elementRemove) {
             $scheduledStructure->setElementToRemoveList($elementName);
-        } else {
-            $data = $scheduledStructure->getStructureElementData($elementName, []);
-            $data['attributes'] = $this->mergeBlockAttributes($data, $currentElement);
-            $this->updateScheduledData($currentElement, $data);
-            $this->evaluateArguments($currentElement, $data);
-            $scheduledStructure->setStructureElementData($elementName, $data);
+            return;
+        } elseif ($currentElement->getAttribute('remove')) {
+            $scheduledStructure->unsetElementFromListToRemove($elementName);
         }
+        $data = $scheduledStructure->getStructureElementData($elementName, []);
+        $data['attributes'] = $this->mergeBlockAttributes($data, $currentElement);
+        $this->updateScheduledData($currentElement, $data);
+        $this->evaluateArguments($currentElement, $data);
+        $scheduledStructure->setStructureElementData($elementName, $data);
     }
 
     /**
diff --git a/lib/internal/Magento/Framework/View/Layout/Reader/Container.php b/lib/internal/Magento/Framework/View/Layout/Reader/Container.php
index c4111a13c33b37fe7e5fcc202ec0773928a1844d..cd4956447a3b14a305e0ca90614633def896a6c7 100755
--- a/lib/internal/Magento/Framework/View/Layout/Reader/Container.php
+++ b/lib/internal/Magento/Framework/View/Layout/Reader/Container.php
@@ -141,11 +141,12 @@ class Container implements Layout\ReaderInterface
     ) {
         $containerName = $currentElement->getAttribute('name');
         $containerRemove = filter_var($currentElement->getAttribute('remove'), FILTER_VALIDATE_BOOLEAN);
-
         if ($containerRemove) {
             $scheduledStructure->setElementToRemoveList($containerName);
-        } else {
-            $this->mergeContainerAttributes($scheduledStructure, $currentElement);
+            return;
+        } elseif ($currentElement->getAttribute('remove')) {
+            $scheduledStructure->unsetElementFromListToRemove($containerName);
         }
+        $this->mergeContainerAttributes($scheduledStructure, $currentElement);
     }
 }
diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Layout/Reader/BlockTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Layout/Reader/BlockTest.php
index 24bbd9391807463226bbe5c276df9aca4c31fd59..8cf049f56f1743484f0d559e4f8abf0caaa6b5f3 100755
--- a/lib/internal/Magento/Framework/View/Test/Unit/Layout/Reader/BlockTest.php
+++ b/lib/internal/Magento/Framework/View/Test/Unit/Layout/Reader/BlockTest.php
@@ -188,6 +188,12 @@ class BlockTest extends \PHPUnit_Framework_TestCase
         $setCondition,
         $setRemoveCondition
     ) {
+        if ($literal == 'referenceBlock' && $remove == 'false') {
+            $this->scheduledStructure->expects($this->once())
+                ->method('unsetElementFromListToRemove')
+                ->with($literal);
+        }
+
         $this->context->expects($this->once())->method('getScheduledStructure')
             ->will($this->returnValue($this->scheduledStructure));
 
diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Layout/Reader/ContainerTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Layout/Reader/ContainerTest.php
index 4e10a5a6a08415ca9d06cb95f5e10fa3a9361c2e..198a70d2121f16962471d3e5f5587a1e89130c3f 100755
--- a/lib/internal/Magento/Framework/View/Test/Unit/Layout/Reader/ContainerTest.php
+++ b/lib/internal/Magento/Framework/View/Test/Unit/Layout/Reader/ContainerTest.php
@@ -102,6 +102,12 @@ class ContainerTest extends \PHPUnit_Framework_TestCase
             ->with($contextMock, $elementCurrent)
             ->willReturnSelf();
 
+        if ($elementCurrent->getAttribute('remove') == 'false') {
+            $scheduledStructureMock->expects($this->once())
+                ->method('unsetElementFromListToRemove')
+                ->with($elementCurrent->getAttribute('name'));
+        }
+        
         $this->container->interpret($contextMock, $elementCurrent);
     }
 
diff --git a/lib/internal/Magento/Framework/composer.json b/lib/internal/Magento/Framework/composer.json
index 98338ed4b099d202ce7d8e482b2bda9e3a675068..926d4cc54c140efb315921432b8afc5ebd237cf7 100644
--- a/lib/internal/Magento/Framework/composer.json
+++ b/lib/internal/Magento/Framework/composer.json
@@ -8,7 +8,7 @@
         "AFL-3.0"
     ],
     "require": {
-        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "php": "~5.6.5|7.0.2|7.0.4|~7.0.6",
         "ext-spl": "*",
         "ext-dom": "*",
         "ext-simplexml": "*",
diff --git a/lib/web/mage/adminhtml/wysiwyg/tiny_mce/setup.js b/lib/web/mage/adminhtml/wysiwyg/tiny_mce/setup.js
index 66b72857d003397b8a756dc6aae9c0de70c58eeb..2c4ab52b896cb8fd8bf01974d7f39cfc8f11e4f4 100755
--- a/lib/web/mage/adminhtml/wysiwyg/tiny_mce/setup.js
+++ b/lib/web/mage/adminhtml/wysiwyg/tiny_mce/setup.js
@@ -53,6 +53,10 @@ define([
                 });
             }
 
+            if (jQuery.isReady) {
+                tinyMCE.dom.Event.domLoaded = true;
+            }
+
             tinyMCE.init(this.getSettings(mode));
         },
 
@@ -78,6 +82,7 @@ define([
             }
 
             var settings = {
+                entity_encoding: 'raw',
                 mode: (mode != undefined ? mode : 'none'),
                 elements: this.id,
                 theme: 'advanced',
@@ -357,6 +362,8 @@ define([
             // escape special chars in directives url to use it in regular expression
             var url = this.makeDirectiveUrl('%directive%').replace(/([$^.?*!+:=()\[\]{}|\\])/g, '\\$1');
             var reg = new RegExp(url.replace('%directive%', '([a-zA-Z0-9,_-]+)'));
+            content = decodeURIComponent(content);
+
             return content.gsub(reg, function(match) {
                 return Base64.mageDecode(match[1]);
             }.bind(this));
diff --git a/lib/web/mage/validation.js b/lib/web/mage/validation.js
index 3041a177185cf1dfa5bda6e233a2c58a0282d0de..eed9c676b4c90ce1a944d9e7c5ce88a815af08cf 100644
--- a/lib/web/mage/validation.js
+++ b/lib/web/mage/validation.js
@@ -1441,17 +1441,19 @@
      * Validate single element.
      *
      * @param {Element} element
+     * @param {Object} config
      * @returns {*}
      */
-    $.validator.validateSingleElement = function (element) {
+    $.validator.validateSingleElement = function (element, config) {
         var errors = {},
             valid = true,
             validateConfig = {
                 errorElement: 'label',
                 ignore: '.ignore-validate'
             },
-            form, validator, classes;
+            form, validator, classes, elementValue;
 
+        $.extend(validateConfig, config);
         element = $(element).not(validateConfig.ignore);
 
         if (!element.length) {
@@ -1475,7 +1477,11 @@
         validator.toShow = validator.toHide = $([]);
 
         $.each(classes, $.proxy(function (i, className) {
-            if (this.methods[className] && !this.methods[className](element.val(), element.get(0))) {
+            elementValue = element.val();
+            if (element.is(':checkbox') || element.is(':radio')) {
+                elementValue = element.is(':checked') || null;
+            }
+            if (this.methods[className] && !this.methods[className](elementValue, element.get(0))) {
                 valid = false;
                 errors[element.get(0).name] = this.messages[className];
                 validator.invalid[element.get(0).name] = true;
diff --git a/package.json.sample b/package.json.sample
index 384aa88c65611a9e20892aade71488b31847ac5c..40169b3179052d98ad2c1a79baf48e376689f3c1 100644
--- a/package.json.sample
+++ b/package.json.sample
@@ -18,7 +18,7 @@
         "grunt-contrib-connect": "^0.9.0",
         "grunt-contrib-cssmin": "^0.10.0",
         "grunt-contrib-imagemin": "^0.9.2",
-        "grunt-contrib-jasmine": "^0.8.1",
+        "grunt-contrib-jasmine": "^1.0.0",
         "grunt-contrib-less": "^0.12.0",
         "grunt-contrib-watch": "^0.6.1",
         "grunt-eslint": "17.3.1",
diff --git a/setup/config/di.config.php b/setup/config/di.config.php
index 804f18462065aa3af62cbba93d1fa5339b548f7e..b0dcb452ccd4030cf9736e6ab4a521199d1a899f 100644
--- a/setup/config/di.config.php
+++ b/setup/config/di.config.php
@@ -21,6 +21,7 @@ return [
             \Magento\Setup\Controller\Environment::class,
             \Magento\Setup\Controller\DependencyCheck::class,
             \Magento\Setup\Controller\DatabaseCheck::class,
+            \Magento\Setup\Controller\UrlCheck::class,
             \Magento\Setup\Controller\ValidateAdminCredentials::class,
             \Magento\Setup\Controller\AddDatabase::class,
             \Magento\Setup\Controller\WebConfiguration::class,
diff --git a/setup/performance-toolkit/profiles/ce/attributeSets.xml b/setup/performance-toolkit/config/attributeSets.xml
similarity index 100%
rename from setup/performance-toolkit/profiles/ce/attributeSets.xml
rename to setup/performance-toolkit/config/attributeSets.xml
diff --git a/setup/performance-toolkit/profiles/ce/searchConfig.xml b/setup/performance-toolkit/config/searchConfig.xml
similarity index 100%
rename from setup/performance-toolkit/profiles/ce/searchConfig.xml
rename to setup/performance-toolkit/config/searchConfig.xml
diff --git a/setup/performance-toolkit/profiles/ce/searchTerms.xml b/setup/performance-toolkit/config/searchTerms.xml
similarity index 100%
rename from setup/performance-toolkit/profiles/ce/searchTerms.xml
rename to setup/performance-toolkit/config/searchTerms.xml
diff --git a/setup/performance-toolkit/profiles/ce/extra_large.xml b/setup/performance-toolkit/profiles/ce/extra_large.xml
index c9bf96ad4f4cab4cb8a6c1aacbe6e89a673e842c..fd1da116bc92b39fa23a3a4821daec93889fbad4 100644
--- a/setup/performance-toolkit/profiles/ce/extra_large.xml
+++ b/setup/performance-toolkit/profiles/ce/extra_large.xml
@@ -68,8 +68,8 @@
                 <set_scheduled>true</set_scheduled>
             </indexer>
         </indexers>
-        <xi:include href="searchTerms.xml" />
-        <xi:include href="searchConfig.xml" />
-        <xi:include href="attributeSets.xml" />
+        <xi:include href="../../config/searchTerms.xml" />
+        <xi:include href="../../config/searchConfig.xml" />
+        <xi:include href="../../config/attributeSets.xml" />
     </profile>
 </config>
diff --git a/setup/performance-toolkit/profiles/ce/large.xml b/setup/performance-toolkit/profiles/ce/large.xml
index 07e7ac33023b17d5d626986b76d84e88b3f7314b..d5d381fe059c95316d43ef88f56280c27494b197 100644
--- a/setup/performance-toolkit/profiles/ce/large.xml
+++ b/setup/performance-toolkit/profiles/ce/large.xml
@@ -68,8 +68,8 @@
                 <set_scheduled>true</set_scheduled>
             </indexer>
         </indexers>
-        <xi:include href="searchTerms.xml" />
-        <xi:include href="searchConfig.xml" />
-        <xi:include href="attributeSets.xml" />
+        <xi:include href="../../config/searchTerms.xml" />
+        <xi:include href="../../config/searchConfig.xml" />
+        <xi:include href="../../config/attributeSets.xml" />
     </profile>
 </config>
diff --git a/setup/performance-toolkit/profiles/ce/medium.xml b/setup/performance-toolkit/profiles/ce/medium.xml
index 6b1b289e823bab41a6d637350037b64c39e96935..95cd062fa74b6b94233066a6f0d0d3b296480b6b 100644
--- a/setup/performance-toolkit/profiles/ce/medium.xml
+++ b/setup/performance-toolkit/profiles/ce/medium.xml
@@ -68,8 +68,8 @@
                 <set_scheduled>false</set_scheduled>
             </indexer>
         </indexers>
-        <xi:include href="searchTerms.xml" />
-        <xi:include href="searchConfig.xml" />
-        <xi:include href="attributeSets.xml" />
+        <xi:include href="../../config/searchTerms.xml" />
+        <xi:include href="../../config/searchConfig.xml" />
+        <xi:include href="../../config/attributeSets.xml" />
     </profile>
 </config>
diff --git a/setup/performance-toolkit/profiles/ce/small.xml b/setup/performance-toolkit/profiles/ce/small.xml
index 4f9b436666f8c743c0fd0058c6fc747944506c9d..1949bb2a53f9aa69237b544ade511f4dd39815e0 100644
--- a/setup/performance-toolkit/profiles/ce/small.xml
+++ b/setup/performance-toolkit/profiles/ce/small.xml
@@ -68,8 +68,8 @@
                 <set_scheduled>false</set_scheduled>
             </indexer>
         </indexers>
-        <xi:include href="searchTerms.xml" />
-        <xi:include href="searchConfig.xml" />
-        <xi:include href="attributeSets.xml" />
+        <xi:include href="../../config/searchTerms.xml" />
+        <xi:include href="../../config/searchConfig.xml" />
+        <xi:include href="../../config/attributeSets.xml" />
     </profile>
 </config>
diff --git a/setup/pub/magento/setup/web-configuration.js b/setup/pub/magento/setup/web-configuration.js
index 03a0fc7845dda90225d3be867f4bf9ddd1621f63..47458056b33b52f8913017a5f6f7c6317fd98347 100644
--- a/setup/pub/magento/setup/web-configuration.js
+++ b/setup/pub/magento/setup/web-configuration.js
@@ -5,7 +5,7 @@
 
 'use strict';
 angular.module('web-configuration', ['ngStorage'])
-    .controller('webConfigurationController', ['$scope', '$state', '$localStorage', function ($scope, $state, $localStorage) {
+    .controller('webConfigurationController', ['$scope', '$state', '$localStorage', '$http', function ($scope, $state, $localStorage, $http) {
         $scope.config = {
             address: {
                 base_url: '',
@@ -119,4 +119,28 @@ angular.module('web-configuration', ['ngStorage'])
                 $scope.webconfig.submitted = false;
             }
         });
+
+        // Validate URL
+        $scope.validateUrl = function () {
+            if (!$scope.webconfig.submitted) {
+                $http.post('index.php/url-check', $scope.config)
+                    .success(function (data) {
+                        $scope.validateUrl.result = data;
+                        if ($scope.validateUrl.result.successUrl && $scope.validateUrl.result.successSecureUrl) {
+                            $scope.nextState();
+                        }
+                        if (!$scope.validateUrl.result.successUrl) {
+                            $scope.webconfig.submitted = true;
+                            $scope.webconfig.base_url.$setValidity('url', false);
+                        }
+                        if (!$scope.validateUrl.result.successSecureUrl) {
+                            $scope.webconfig.submitted = true;
+                            $scope.webconfig.https.$setValidity('url', false);
+                        }
+                    })
+                    .error(function (data) {
+                        $scope.validateUrl.failed = data;
+                    });
+            }
+        };
     }]);
diff --git a/setup/src/Magento/Setup/Console/Command/InstallStoreConfigurationCommand.php b/setup/src/Magento/Setup/Console/Command/InstallStoreConfigurationCommand.php
index 928fe1e3d4b8d32f7bc4656bf6c00ac500972234..f1098af2db00916e328f515a2a88696553603f78 100644
--- a/setup/src/Magento/Setup/Console/Command/InstallStoreConfigurationCommand.php
+++ b/setup/src/Magento/Setup/Console/Command/InstallStoreConfigurationCommand.php
@@ -16,11 +16,10 @@ use Magento\Setup\Model\StoreConfigurationDataMapper;
 use Magento\Setup\Model\ObjectManagerProvider;
 use Magento\Framework\ObjectManagerInterface;
 use Magento\Framework\Exception\LocalizedException;
-use Magento\Store\Model\Store;
-use Magento\Framework\Validator\Locale;
-use Magento\Framework\Validator\Timezone;
-use Magento\Framework\Validator\Currency;
-use Magento\Framework\Url\Validator;
+use Magento\Framework\Validator\Locale as LocaleValidator;
+use Magento\Framework\Validator\Timezone as TimezoneValidator;
+use Magento\Framework\Validator\Currency as CurrencyValidator;
+use Magento\Framework\Validator\Url as UrlValidator;
 
 /**
  * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
@@ -43,24 +42,57 @@ class InstallStoreConfigurationCommand extends AbstractSetupCommand
      * Object Manager
      *
      * @var ObjectManagerInterface
+     * @deprecated
      */
     private $objectManager;
 
+    /**
+     * @var LocaleValidator
+     */
+    private $localeValidator;
+
+    /**
+     * @var TimezoneValidator
+     */
+    private $timezoneValidator;
+
+    /**
+     * @var CurrencyValidator
+     */
+    private $currencyValidator;
+
+    /**
+     * @var UrlValidator
+     */
+    private $urlValidator;
+
     /**
      * Inject dependencies
      *
      * @param InstallerFactory $installerFactory
      * @param DeploymentConfig $deploymentConfig
      * @param ObjectManagerProvider $objectManagerProvider
+     * @param LocaleValidator $localeValidator,
+     * @param TimezoneValidator $timezoneValidator,
+     * @param CurrencyValidator $currencyValidator,
+     * @param UrlValidator $urlValidator
      */
     public function __construct(
         InstallerFactory $installerFactory,
         DeploymentConfig $deploymentConfig,
-        ObjectManagerProvider $objectManagerProvider
+        ObjectManagerProvider $objectManagerProvider,
+        LocaleValidator $localeValidator,
+        TimezoneValidator $timezoneValidator,
+        CurrencyValidator $currencyValidator,
+        UrlValidator $urlValidator
     ) {
         $this->installerFactory = $installerFactory;
         $this->deploymentConfig = $deploymentConfig;
         $this->objectManager = $objectManagerProvider->get();
+        $this->localeValidator = $localeValidator;
+        $this->timezoneValidator = $timezoneValidator;
+        $this->currencyValidator = $currencyValidator;
+        $this->urlValidator = $urlValidator;
         parent::__construct();
     }
 
@@ -173,6 +205,7 @@ class InstallStoreConfigurationCommand extends AbstractSetupCommand
     public function validate(InputInterface $input)
     {
         $errors = [];
+        $errorMsg = '';
         $options = $input->getOptions();
         foreach ($options as $key => $value) {
             if (!$value) {
@@ -180,99 +213,69 @@ class InstallStoreConfigurationCommand extends AbstractSetupCommand
             }
             switch ($key) {
                 case StoreConfigurationDataMapper::KEY_BASE_URL:
-                    /** @var Validator $url */
                     if (strcmp($value, '{{base_url}}') == 0) {
                         break;
                     }
-                    $url = $this->objectManager->get(\Magento\Framework\Url\Validator::class);
-                    if (!$url->isValid($value)) {
-                        $errorMsgs = $url->getMessages();
-                        $errors[] = '<error>' . 'Command option \'' . StoreConfigurationDataMapper::KEY_BASE_URL
-                            . '\': ' . $errorMsgs[Validator::INVALID_URL] .'</error>';
-                    }
+                    $errorMsg = $this->validateUrl(
+                        $value,
+                        StoreConfigurationDataMapper::KEY_BASE_URL,
+                        ['http', 'https']
+                    );
+
                     break;
                 case StoreConfigurationDataMapper::KEY_LANGUAGE:
-                    /** @var Locale $lists */
-                    $lists = $this->objectManager->get(\Magento\Framework\Validator\Locale::class);
-                    $errorMsg = $this->validateCodes($lists, $value, StoreConfigurationDataMapper::KEY_LANGUAGE);
-                    if ($errorMsg !== '') {
-                        $errors[] = $errorMsg;
-                    }
+                    $errorMsg = $this->validateCodes(
+                        $this->localeValidator,
+                        $value,
+                        StoreConfigurationDataMapper::KEY_LANGUAGE
+                    );
                     break;
                 case StoreConfigurationDataMapper::KEY_TIMEZONE:
-                    /** @var Timezone $lists */
-                    $lists = $this->objectManager->get(\Magento\Framework\Validator\Timezone::class);
-                    $errorMsg = $this->validateCodes($lists, $value, StoreConfigurationDataMapper::KEY_TIMEZONE);
-                    if ($errorMsg !== '') {
-                        $errors[] = $errorMsg;
-                    }
+                    $errorMsg = $this->validateCodes(
+                        $this->timezoneValidator,
+                        $value,
+                        StoreConfigurationDataMapper::KEY_TIMEZONE
+                    );
                     break;
                 case StoreConfigurationDataMapper::KEY_CURRENCY:
-                    /** @var Currency $lists */
-                    $lists = $this->objectManager->get(\Magento\Framework\Validator\Currency::class);
-                    $errorMsg = $this->validateCodes($lists, $value, StoreConfigurationDataMapper::KEY_CURRENCY);
-                    if ($errorMsg !== '') {
-                        $errors[] = $errorMsg;
-                    }
+                    $errorMsg = $this->validateCodes(
+                        $this->currencyValidator,
+                        $value,
+                        StoreConfigurationDataMapper::KEY_CURRENCY
+                    );
                     break;
                 case StoreConfigurationDataMapper::KEY_USE_SEF_URL:
                     $errorMsg = $this->validateBinaryValue($value, StoreConfigurationDataMapper::KEY_USE_SEF_URL);
-                    if ($errorMsg !== '') {
-                        $errors[] = $errorMsg;
-                    }
                     break;
                 case StoreConfigurationDataMapper::KEY_IS_SECURE:
                     $errorMsg = $this->validateBinaryValue($value, StoreConfigurationDataMapper::KEY_IS_SECURE);
-                    if ($errorMsg !== '') {
-                        $errors[] = $errorMsg;
-                    }
                     break;
                 case StoreConfigurationDataMapper::KEY_BASE_URL_SECURE:
-                    try {
-                        /** @var Validator $url */
-                        $url = $this->objectManager->get(\Magento\Framework\Url\Validator::class);
-                        $errorMsgs = '';
-                        if (!$url->isValid($value)) {
-                            $errorMsgs = $url->getMessages();
-                            if (!empty($errorMsgs)) {
-                                $errors[] = '<error>' . 'Command option \''
-                                    . StoreConfigurationDataMapper::KEY_BASE_URL_SECURE
-                                    . '\': ' . $errorMsgs[Validator::INVALID_URL] .'</error>';
-                            }
-                        }
-                        if (empty($errorMsgs) && strpos($value, 'https:') === false) {
-                            throw new LocalizedException(new \Magento\Framework\Phrase("Invalid secure URL."));
-                        }
-                    } catch (LocalizedException $e) {
-                        $errors[] = '<error>' . 'Command option \'' . StoreConfigurationDataMapper::KEY_BASE_URL_SECURE
-                            . '\': ' . $e->getLogMessage() .'</error>';
-                    }
+                    $errorMsg = $this->validateUrl(
+                        $value,
+                        StoreConfigurationDataMapper::KEY_BASE_URL_SECURE,
+                        ['https']
+                    );
                     break;
                 case StoreConfigurationDataMapper::KEY_IS_SECURE_ADMIN:
                     $errorMsg = $this->validateBinaryValue($value, StoreConfigurationDataMapper::KEY_IS_SECURE_ADMIN);
-                    if ($errorMsg !== '') {
-                        $errors[] = $errorMsg;
-                    }
                     break;
                 case StoreConfigurationDataMapper::KEY_ADMIN_USE_SECURITY_KEY:
                     $errorMsg = $this->validateBinaryValue(
                         $value,
                         StoreConfigurationDataMapper::KEY_ADMIN_USE_SECURITY_KEY
                     );
-                    if ($errorMsg !== '') {
-                        $errors[] = $errorMsg;
-                    }
                     break;
                 case StoreConfigurationDataMapper::KEY_JS_LOGGING:
                     $errorMsg = $this->validateBinaryValue(
                         $value,
                         StoreConfigurationDataMapper::KEY_JS_LOGGING
                     );
-                    if ($errorMsg !== '') {
-                        $errors[] = $errorMsg;
-                    }
                     break;
             }
+            if ($errorMsg !== '') {
+                $errors[] = $errorMsg;
+            }
         }
         return $errors;
     }
@@ -296,7 +299,7 @@ class InstallStoreConfigurationCommand extends AbstractSetupCommand
     /**
      * Validate codes for languages, currencies or timezones
      *
-     * @param Locale|Timezone|Currency  $lists
+     * @param LocaleValidator|TimezoneValidator|CurrencyValidator  $lists
      * @param string  $code
      * @param string  $type
      * @return string
@@ -310,4 +313,31 @@ class InstallStoreConfigurationCommand extends AbstractSetupCommand
         }
         return $errorMsg;
     }
+
+    /**
+     * Validate URL
+     *
+     * @param string $url
+     * @param string $option
+     * @param array $allowedSchemes
+     * @return string
+     */
+    private function validateUrl($url, $option, array $allowedSchemes)
+    {
+        $errorMsg = '';
+
+        if (!$this->urlValidator->isValid($url, $allowedSchemes)) {
+            $errorTemplate = '<error>Command option \'%s\': Invalid URL \'%s\'.'
+                . ' Domain Name should contain only letters, digits and hyphen.'
+                . ' And you should use only following schemes: \'%s\'.</error>';
+            $errorMsg = sprintf(
+                $errorTemplate,
+                $option,
+                $url,
+                implode(', ', $allowedSchemes)
+            );
+        }
+
+        return $errorMsg;
+    }
 }
diff --git a/setup/src/Magento/Setup/Controller/UrlCheck.php b/setup/src/Magento/Setup/Controller/UrlCheck.php
new file mode 100644
index 0000000000000000000000000000000000000000..08a0d50404c0a2e457a2646a30860d1f958f14d3
--- /dev/null
+++ b/setup/src/Magento/Setup/Controller/UrlCheck.php
@@ -0,0 +1,58 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Setup\Controller;
+
+use Zend\Mvc\Controller\AbstractActionController;
+use Zend\View\Model\JsonModel;
+use Zend\Json\Json;
+use Magento\Framework\Validator\Url as UrlValidator;
+
+class UrlCheck extends AbstractActionController
+{
+    /**
+     * @var UrlValidator
+     */
+    private $urlValidator;
+
+    /**
+     * @param UrlValidator $urlValidator
+     */
+    public function __construct(UrlValidator $urlValidator)
+    {
+        $this->urlValidator = $urlValidator;
+    }
+
+    /**
+     * Validate URL
+     *
+     * @return JsonModel
+     */
+    public function indexAction()
+    {
+        $params = Json::decode($this->getRequest()->getContent(), Json::TYPE_ARRAY);
+        $result = ['successUrl' => false, 'successSecureUrl' => true];
+
+        $hasBaseUrl = isset($params['address']['actual_base_url']);
+        $hasSecureBaseUrl = isset($params['https']['text']);
+        $hasSecureAdminUrl = !empty($params['https']['admin']);
+        $hasSecureFrontUrl = !empty($params['https']['front']);
+        $schemes = ['http', 'https'];
+
+        // Validating of Base URL
+        if ($hasBaseUrl && $this->urlValidator->isValid($params['address']['actual_base_url'], $schemes)) {
+            $result['successUrl'] = true;
+        }
+
+        // Validating of Secure Base URL
+        if ($hasSecureAdminUrl || $hasSecureFrontUrl) {
+            if (!($hasSecureBaseUrl && $this->urlValidator->isValid($params['https']['text'], $schemes))) {
+                $result['successSecureUrl'] = false;
+            }
+        }
+
+        return new JsonModel($result);
+    }
+}
diff --git a/setup/src/Magento/Setup/Fixtures/FixtureModel.php b/setup/src/Magento/Setup/Fixtures/FixtureModel.php
index 44173a32c3e771ec2c43480a73c380ad2a2691ab..997244f5508933d05ae731255b81779f2528a101 100644
--- a/setup/src/Magento/Setup/Fixtures/FixtureModel.php
+++ b/setup/src/Magento/Setup/Fixtures/FixtureModel.php
@@ -221,6 +221,12 @@ class FixtureModel
      */
     public function getValue($key, $default = null)
     {
-        return isset($this->config['config']['profile'][$key]) ? $this->config['config']['profile'][$key] : $default;
+        return isset($this->config['config']['profile'][$key]) ?
+            (
+                // Work around for how attributes are handled in the XML parser when injected via xinclude due to the
+                // files existing outside of the current working directory.
+                isset($this->config['config']['profile'][$key]['_value']) ?
+                    $this->config['config']['profile'][$key]['_value'] : $this->config['config']['profile'][$key]
+            ) : $default;
     }
 }
diff --git a/setup/src/Magento/Setup/Mvc/Bootstrap/InitParamListener.php b/setup/src/Magento/Setup/Mvc/Bootstrap/InitParamListener.php
index 6a4b3a72b372c8ff611bcc7e535c99cbef4bb404..935f395a5e219f0546daf7967dbcc0726c695055 100644
--- a/setup/src/Magento/Setup/Mvc/Bootstrap/InitParamListener.php
+++ b/setup/src/Magento/Setup/Mvc/Bootstrap/InitParamListener.php
@@ -99,10 +99,10 @@ class InitParamListener implements ListenerAggregateInterface, FactoryInterface
     }
 
     /**
-     * Check if user login
+     * Check if user logged-in and has permissions
      *
      * @param \Zend\Mvc\MvcEvent $event
-     * @return bool
+     * @return false|\Zend\Http\Response
      * @throws \Magento\Framework\Exception\LocalizedException
      */
     public function authPreDispatch($event)
@@ -115,6 +115,7 @@ class InitParamListener implements ListenerAggregateInterface, FactoryInterface
             /** @var Application $application */
             $application = $event->getApplication();
             $serviceManager = $application->getServiceManager();
+
             if ($serviceManager->get(\Magento\Framework\App\DeploymentConfig::class)->isAvailable()) {
                 /** @var \Magento\Setup\Model\ObjectManagerProvider $objectManagerProvider */
                 $objectManagerProvider = $serviceManager->get(\Magento\Setup\Model\ObjectManagerProvider::class);
@@ -135,17 +136,26 @@ class InitParamListener implements ListenerAggregateInterface, FactoryInterface
                         'appState' => $adminAppState
                     ]
                 );
-                if (!$objectManager->get(\Magento\Backend\Model\Auth::class)->isLoggedIn()) {
+                /** @var \Magento\Backend\Model\Auth $auth */
+                $authentication = $objectManager->get(\Magento\Backend\Model\Auth::class);
+
+                if (
+                    !$authentication->isLoggedIn() ||
+                    !$adminSession->isAllowed('Magento_Backend::setup_wizard')
+                ) {
                     $adminSession->destroy();
+                    /** @var \Zend\Http\Response $response */
                     $response = $event->getResponse();
                     $baseUrl = Http::getDistroBaseUrlPath($_SERVER);
                     $response->getHeaders()->addHeaderLine('Location', $baseUrl . 'index.php/session/unlogin');
                     $response->setStatusCode(302);
                     $event->stopPropagation();
+
                     return $response;
                 }
             }
         }
+
         return false;
     }
 
diff --git a/setup/src/Magento/Setup/Test/Unit/Console/Command/InstallStoreConfigurationCommandTest.php b/setup/src/Magento/Setup/Test/Unit/Console/Command/InstallStoreConfigurationCommandTest.php
index 6f5ab3a5a64c537751cc8964229e35869b06c8e5..c3494b389aa5ecb2a2ab2465b5d848627a5d8e7a 100644
--- a/setup/src/Magento/Setup/Test/Unit/Console/Command/InstallStoreConfigurationCommandTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Console/Command/InstallStoreConfigurationCommandTest.php
@@ -11,8 +11,14 @@ use Symfony\Component\Console\Tester\CommandTester;
 use Magento\Setup\Model\Installer;
 use Magento\Framework\ObjectManagerInterface;
 use Magento\Setup\Model\StoreConfigurationDataMapper;
-use Magento\Framework\Url\Validator;
+use Magento\Framework\Validator\Url as UrlValidator;
+use Magento\Framework\Validator\Locale as LocaleValidator;
+use Magento\Framework\Validator\Timezone as TimezoneValidator;
+use Magento\Framework\Validator\Currency as CurrencyValidator;
 
+/**
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ */
 class InstallStoreConfigurationCommandTest extends \PHPUnit_Framework_TestCase
 {
     /**
@@ -35,6 +41,26 @@ class InstallStoreConfigurationCommandTest extends \PHPUnit_Framework_TestCase
      */
     private $objectManager;
 
+    /**
+     * @var LocaleValidator|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $localeValidatorMock;
+
+    /**
+     * @var TimezoneValidator|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $timezoneValidatorMock;
+
+    /**
+     * @var CurrencyValidator|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $currencyValidatorMock;
+
+    /**
+     * @var UrlValidator|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $urlValidatorMock;
+
     /**
      * @var InstallStoreConfigurationCommand
      */
@@ -42,6 +68,11 @@ class InstallStoreConfigurationCommandTest extends \PHPUnit_Framework_TestCase
 
     protected function setUp()
     {
+        $this->urlValidatorMock = $this->getMock(UrlValidator::class, [], [], '', false);
+        $this->localeValidatorMock = $this->getMock(LocaleValidator::class, [], [], '', false);
+        $this->timezoneValidatorMock = $this->getMock(TimezoneValidator::class, [], [], '', false);
+        $this->currencyValidatorMock = $this->getMock(CurrencyValidator::class, [], [], '', false);
+
         $this->installerFactory = $this->getMock(\Magento\Setup\Model\InstallerFactory::class, [], [], '', false);
         $this->deploymentConfig = $this->getMock(\Magento\Framework\App\DeploymentConfig::class, [], [], '', false);
         $this->installer = $this->getMock(\Magento\Setup\Model\Installer::class, [], [], '', false);
@@ -62,7 +93,11 @@ class InstallStoreConfigurationCommandTest extends \PHPUnit_Framework_TestCase
         $this->command = new InstallStoreConfigurationCommand(
             $this->installerFactory,
             $this->deploymentConfig,
-            $objectManagerProvider
+            $objectManagerProvider,
+            $this->localeValidatorMock,
+            $this->timezoneValidatorMock,
+            $this->currencyValidatorMock,
+            $this->urlValidatorMock
         );
     }
 
@@ -102,41 +137,11 @@ class InstallStoreConfigurationCommandTest extends \PHPUnit_Framework_TestCase
      */
     public function testExecuteInvalidData(array $option, $error)
     {
-        $url= $this->getMock(\Magento\Framework\Url\Validator::class, [], [], '', false);
-        $url->expects($this->any())->method('isValid')->will($this->returnValue(false));
-        if (!isset($option['--' . StoreConfigurationDataMapper::KEY_BASE_URL_SECURE])) {
-            $url->expects($this->any())->method('getMessages')->will($this->returnValue([
-                Validator::INVALID_URL => 'Invalid URL.'
-            ]));
-        }
-        $localeLists= $this->getMock(\Magento\Framework\Validator\Locale::class, [], [], '', false);
-        $localeLists->expects($this->any())->method('isValid')->will($this->returnValue(false));
-        $timezoneLists= $this->getMock(\Magento\Framework\Validator\Timezone::class, [], [], '', false);
-        $timezoneLists->expects($this->any())->method('isValid')->will($this->returnValue(false));
-        $currencyLists= $this->getMock(\Magento\Framework\Validator\Currency::class, [], [], '', false);
-        $currencyLists->expects($this->any())->method('isValid')->will($this->returnValue(false));
-
-        $returnValueMapOM = [
-            [
-                \Magento\Framework\Url\Validator::class,
-                $url
-            ],
-            [
-                \Magento\Framework\Validator\Locale::class,
-                $localeLists
-            ],
-            [
-                \Magento\Framework\Validator\Timezone::class,
-                $timezoneLists
-            ],
-            [
-                \Magento\Framework\Validator\Currency::class,
-                $currencyLists
-            ],
-        ];
-        $this->objectManager->expects($this->any())
-            ->method('get')
-            ->will($this->returnValueMap($returnValueMapOM));
+        $this->localeValidatorMock->expects($this->any())->method('isValid')->willReturn(false);
+        $this->timezoneValidatorMock->expects($this->any())->method('isValid')->willReturn(false);
+        $this->currencyValidatorMock->expects($this->any())->method('isValid')->willReturn(false);
+        $this->urlValidatorMock->expects($this->any())->method('isValid')->willReturn(false);
+
         $this->deploymentConfig->expects($this->once())
             ->method('isAvailable')
             ->will($this->returnValue(true));
@@ -144,7 +149,7 @@ class InstallStoreConfigurationCommandTest extends \PHPUnit_Framework_TestCase
             ->method('create');
         $commandTester = new CommandTester($this->command);
         $commandTester->execute($option);
-        $this->assertEquals($error . PHP_EOL, $commandTester->getDisplay());
+        $this->assertContains($error, $commandTester->getDisplay());
     }
 
     /**
@@ -155,48 +160,54 @@ class InstallStoreConfigurationCommandTest extends \PHPUnit_Framework_TestCase
         return [
             [
                 ['--' . StoreConfigurationDataMapper::KEY_BASE_URL => 'sampleUrl'],
-                'Command option \'' . StoreConfigurationDataMapper::KEY_BASE_URL . '\': Invalid URL.'
+                'Command option \'' . StoreConfigurationDataMapper::KEY_BASE_URL . '\': Invalid URL \'sampleUrl\'.'
+            ],
+            [
+                ['--' . StoreConfigurationDataMapper::KEY_BASE_URL => 'http://example.com_test'],
+                'Command option \'' . StoreConfigurationDataMapper::KEY_BASE_URL
+                    . '\': Invalid URL \'http://example.com_test\'.'
             ],
             [
                 ['--' . StoreConfigurationDataMapper::KEY_LANGUAGE => 'sampleLanguage'],
                 'Command option \'' . StoreConfigurationDataMapper::KEY_LANGUAGE
-                . '\': Invalid value. To see possible values, run command \'bin/magento info:language:list\'.'
+                    . '\': Invalid value. To see possible values, run command \'bin/magento info:language:list\'.'
             ],
             [
                 ['--' . StoreConfigurationDataMapper::KEY_TIMEZONE => 'sampleTimezone'],
                 'Command option \'' . StoreConfigurationDataMapper::KEY_TIMEZONE
-                . '\': Invalid value. To see possible values, run command \'bin/magento info:timezone:list\'.'
+                    . '\': Invalid value. To see possible values, run command \'bin/magento info:timezone:list\'.'
             ],
             [
                 ['--' . StoreConfigurationDataMapper::KEY_CURRENCY => 'sampleLanguage'],
                 'Command option \'' . StoreConfigurationDataMapper::KEY_CURRENCY
-                . '\': Invalid value. To see possible values, run command \'bin/magento info:currency:list\'.'
+                    . '\': Invalid value. To see possible values, run command \'bin/magento info:currency:list\'.'
             ],
             [
                 ['--' . StoreConfigurationDataMapper::KEY_USE_SEF_URL => 'invalidValue'],
                 'Command option \'' . StoreConfigurationDataMapper::KEY_USE_SEF_URL
-                . '\': Invalid value. Possible values (0|1).'
+                    . '\': Invalid value. Possible values (0|1).'
             ],
             [
                 ['--' . StoreConfigurationDataMapper::KEY_IS_SECURE => 'invalidValue'],
                 'Command option \'' . StoreConfigurationDataMapper::KEY_IS_SECURE
-                . '\': Invalid value. Possible values (0|1).'
+                    . '\': Invalid value. Possible values (0|1).'
             ],
             [
                 ['--' . StoreConfigurationDataMapper::KEY_BASE_URL_SECURE => 'http://www.sample.com'],
                 'Command option \'' . StoreConfigurationDataMapper::KEY_BASE_URL_SECURE
-                . '\': Invalid secure URL.'
+                    . '\': Invalid URL \'http://www.sample.com\'.'
             ],
             [
                 ['--' . StoreConfigurationDataMapper::KEY_IS_SECURE_ADMIN => 'invalidValue'],
                 'Command option \'' . StoreConfigurationDataMapper::KEY_IS_SECURE_ADMIN
-                . '\': Invalid value. Possible values (0|1).'
+                    . '\': Invalid value. Possible values (0|1).'
             ],
             [
                 ['--' . StoreConfigurationDataMapper::KEY_ADMIN_USE_SECURITY_KEY => 'invalidValue'],
                 'Command option \'' . StoreConfigurationDataMapper::KEY_ADMIN_USE_SECURITY_KEY
-                . '\': Invalid value. Possible values (0|1).'
+                    . '\': Invalid value. Possible values (0|1).'
             ],
+
         ];
     }
 }
diff --git a/setup/src/Magento/Setup/Test/Unit/Controller/UrlCheckTest.php b/setup/src/Magento/Setup/Test/Unit/Controller/UrlCheckTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..0b44887b586d5c69b6c56a1e19a4b9d68ae96bfe
--- /dev/null
+++ b/setup/src/Magento/Setup/Test/Unit/Controller/UrlCheckTest.php
@@ -0,0 +1,143 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Setup\Test\Unit\Controller;
+
+use Magento\Setup\Controller\UrlCheck;
+use Zend\Stdlib\RequestInterface;
+use Zend\View\Model\JsonModel;
+use Magento\Framework\Validator\Url as UrlValidator;
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper;
+
+class UrlCheckTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @param array $requestJson
+     * @param array $expectedResult
+     * @dataProvider indexActionDataProvider
+     */
+    public function testIndexAction($requestJson, $expectedResult)
+    {
+        /** @var ObjectManagerHelper $objectManagerHelper */
+        $objectManagerHelper = new ObjectManagerHelper($this);
+
+        $allowedSchemes = ['http', 'https'];
+        $returnMap = [];
+        if (isset($requestJson['address']['actual_base_url'])) {
+            $returnMap[] = [
+                $requestJson['address']['actual_base_url'],
+                $allowedSchemes,
+                $expectedResult['successUrl'],
+            ];
+        }
+        if (isset($requestJson['https']['text'])) {
+            $returnMap[] = [
+                $requestJson['https']['text'],
+                $allowedSchemes,
+                $expectedResult['successSecureUrl'],
+            ];
+        }
+
+        /** @var UrlValidator|\PHPUnit_Framework_MockObject_MockObject $validator */
+        $validator = $this->getMockBuilder(UrlValidator::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $validator->expects($this->any())
+            ->method('isValid')
+            ->willReturnMap($returnMap);
+
+        /** @var RequestInterface|\PHPUnit_Framework_MockObject_MockObject $requestMock */
+        $requestMock = $this->getMockBuilder(RequestInterface::class)
+            ->getMockForAbstractClass();
+        $requestMock->expects($this->once())
+            ->method('getContent')
+            ->willReturn(json_encode($requestJson));
+
+        $controller = $objectManagerHelper->getObject(
+            UrlCheck::class,
+            ['urlValidator' => $validator]
+        );
+        $objectManagerHelper->setBackwardCompatibleProperty($controller, 'request', $requestMock);
+
+        $this->assertEquals(new JsonModel($expectedResult), $controller->indexAction());
+    }
+
+    /**
+     * @return array
+     */
+    public function indexActionDataProvider()
+    {
+        return [
+            [
+                'requestJson' => [
+                    'address' => [
+                        'actual_base_url' => 'http://localhost'
+                    ]
+                ],
+                'expectedResult' => ['successUrl' => true, 'successSecureUrl' => true]
+            ],
+            [
+                'requestJson' => [
+                    'address' => [
+                        'actual_base_url' => 'http://localhost.com_test'
+                    ]
+                ],
+                'expectedResult' => ['successUrl' => false, 'successSecureUrl' => true]
+            ],
+            [
+                'requestJson' => [
+                    'address' => [
+                        'actual_base_url' => 'http://localhost.com_test'
+                    ],
+                    'https' => [
+                        'admin' => false,
+                        'front' => false,
+                        'text' => ''
+                    ]
+                ],
+                'expectedResult' => ['successUrl' => false, 'successSecureUrl' => true]
+            ],
+            [
+                'requestJson' => [
+                    'address' => [
+                        'actual_base_url' => 'http://localhost.com:8080'
+                    ],
+                    'https' => [
+                        'admin' => true,
+                        'front' => false,
+                        'text' => 'https://example.com.ua/'
+                    ]
+                ],
+                'expectedResult' => ['successUrl' => true, 'successSecureUrl' => true]
+            ],
+            [
+                'requestJson' => [
+                    'address' => [
+                        'actual_base_url' => 'http://localhost.com:8080/folder_name/'
+                    ],
+                    'https' => [
+                        'admin' => false,
+                        'front' => true,
+                        'text' => 'https://example.com.ua/'
+                    ]
+                ],
+                'expectedResult' => ['successUrl' => true, 'successSecureUrl' => true]
+            ],
+            [
+                'requestJson' => [
+                    'address' => [
+                        'actual_base_url' => 'http://localhost.com:8080/folder_name/'
+                    ],
+                    'https' => [
+                        'admin' => true,
+                        'front' => true,
+                        'text' => 'https://example.com.ua:8090/folder_name/'
+                    ]
+                ],
+                'expectedResult' => ['successUrl' => true, 'successSecureUrl' => true]
+            ],
+        ];
+    }
+}
diff --git a/setup/src/Magento/Setup/Test/Unit/Mvc/Bootstrap/InitParamListenerTest.php b/setup/src/Magento/Setup/Test/Unit/Mvc/Bootstrap/InitParamListenerTest.php
index 558533afe92429582cbfa79e5fcd691b200ecef8..1ace3f452c4f917181c43a86744f2b4db39b9439 100644
--- a/setup/src/Magento/Setup/Test/Unit/Mvc/Bootstrap/InitParamListenerTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Mvc/Bootstrap/InitParamListenerTest.php
@@ -3,7 +3,6 @@
  * Copyright © 2016 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-
 namespace Magento\Setup\Test\Unit\Mvc\Bootstrap;
 
 use \Magento\Setup\Mvc\Bootstrap\InitParamListener;
@@ -59,11 +58,11 @@ class InitParamListenerTest extends \PHPUnit_Framework_TestCase
             ->withConsecutive(
                 [
                     \Magento\Framework\App\Filesystem\DirectoryList::class,
-                    $this->isInstanceOf(\Magento\Framework\App\Filesystem\DirectoryList::class)
+                    $this->isInstanceOf(\Magento\Framework\App\Filesystem\DirectoryList::class),
                 ],
                 [
                     \Magento\Framework\Filesystem::class,
-                    $this->isInstanceOf(\Magento\Framework\Filesystem::class)
+                    $this->isInstanceOf(\Magento\Framework\Filesystem::class),
                 ]
             );
         $mvcApplication->expects($this->any())->method('getServiceManager')->willReturn($serviceManager);
@@ -130,10 +129,10 @@ class InitParamListenerTest extends \PHPUnit_Framework_TestCase
         $request->expects($this->any())
             ->method('getContent')
             ->willReturn(
-                $cliParam ? ['install', '--magento-init-params=' . $cliParam ] : ['install']
+                $cliParam ? ['install', '--magento-init-params=' . $cliParam] : ['install']
             );
         $mvcApplication->expects($this->any())->method('getConfig')->willReturn(
-            $zfAppConfig ? [InitParamListener::BOOTSTRAP_PARAM => $zfAppConfig]:[]
+            $zfAppConfig ? [InitParamListener::BOOTSTRAP_PARAM => $zfAppConfig] : []
         );
 
         $mvcApplication->expects($this->any())->method('getRequest')->willReturn($request);
@@ -150,41 +149,55 @@ class InitParamListenerTest extends \PHPUnit_Framework_TestCase
             'mage_mode App' => [['MAGE_MODE' => 'developer'], [], '', ['MAGE_MODE' => 'developer']],
             'mage_mode Env' => [[], ['MAGE_MODE' => 'developer'], '', ['MAGE_MODE' => 'developer']],
             'mage_mode CLI' => [[], [], 'MAGE_MODE=developer', ['MAGE_MODE' => 'developer']],
-            'one MAGE_DIRS CLI' => [[], [], 'MAGE_MODE=developer&MAGE_DIRS[base][path]=/var/www/magento2',
-                       ['MAGE_DIRS' => ['base' => ['path' => '/var/www/magento2']], 'MAGE_MODE' => 'developer']],
+            'one MAGE_DIRS CLI' => [
+                [],
+                [],
+                'MAGE_MODE=developer&MAGE_DIRS[base][path]=/var/www/magento2',
+                ['MAGE_DIRS' => ['base' => ['path' => '/var/www/magento2']], 'MAGE_MODE' => 'developer'],
+            ],
             'two MAGE_DIRS CLI' => [
                 [],
                 [],
                 'MAGE_MODE=developer&MAGE_DIRS[base][path]=/var/www/magento2&MAGE_DIRS[cache][path]=/tmp/cache',
-                ['MAGE_DIRS' => ['base' => ['path' => '/var/www/magento2'], 'cache' => ['path' => '/tmp/cache']],
-                 'MAGE_MODE' => 'developer']],
+                [
+                    'MAGE_DIRS' => ['base' => ['path' => '/var/www/magento2'], 'cache' => ['path' => '/tmp/cache']],
+                    'MAGE_MODE' => 'developer',
+                ],
+            ],
             'mage_mode only' => [[], [], 'MAGE_MODE=developer', ['MAGE_MODE' => 'developer']],
             'MAGE_DIRS Env' => [
                 [],
                 ['MAGE_DIRS' => ['base' => ['path' => '/var/www/magento2']], 'MAGE_MODE' => 'developer'],
                 '',
-                ['MAGE_DIRS' => ['base' => ['path' => '/var/www/magento2']], 'MAGE_MODE' => 'developer']],
+                ['MAGE_DIRS' => ['base' => ['path' => '/var/www/magento2']], 'MAGE_MODE' => 'developer'],
+            ],
             'two MAGE_DIRS' => [
                 [],
                 [],
                 'MAGE_MODE=developer&MAGE_DIRS[base][path]=/var/www/magento2&MAGE_DIRS[cache][path]=/tmp/cache',
-                ['MAGE_DIRS' => ['base' => ['path' => '/var/www/magento2'], 'cache' => ['path' => '/tmp/cache']],
-                 'MAGE_MODE' => 'developer']],
+                [
+                    'MAGE_DIRS' => ['base' => ['path' => '/var/www/magento2'], 'cache' => ['path' => '/tmp/cache']],
+                    'MAGE_MODE' => 'developer',
+                ],
+            ],
             'Env overwrites App' => [
                 ['MAGE_DIRS' => ['base' => ['path' => '/var/www/magento2/App']], 'MAGE_MODE' => 'developer'],
                 ['MAGE_DIRS' => ['base' => ['path' => '/var/www/magento2/Env']], 'MAGE_MODE' => 'developer'],
                 '',
-                ['MAGE_DIRS' => ['base' => ['path' => '/var/www/magento2/Env']], 'MAGE_MODE' => 'developer']],
+                ['MAGE_DIRS' => ['base' => ['path' => '/var/www/magento2/Env']], 'MAGE_MODE' => 'developer'],
+            ],
             'CLI overwrites Env' => [
                 ['MAGE_MODE' => 'developerApp'],
                 ['MAGE_DIRS' => ['base' => ['path' => '/var/www/magento2/Env']]],
                 'MAGE_DIRS[base][path]=/var/www/magento2/CLI',
-                ['MAGE_DIRS' => ['base' => ['path' => '/var/www/magento2/CLI']], 'MAGE_MODE' => 'developerApp']],
+                ['MAGE_DIRS' => ['base' => ['path' => '/var/www/magento2/CLI']], 'MAGE_MODE' => 'developerApp'],
+            ],
             'CLI overwrites All' => [
                 ['MAGE_DIRS' => ['base' => ['path' => '/var/www/magento2/App']], 'MAGE_MODE' => 'production'],
                 ['MAGE_DIRS' => ['base' => ['path' => '/var/www/magento2/Env']]],
                 'MAGE_DIRS[base][path]=/var/www/magento2/CLI',
-                ['MAGE_DIRS' => ['base' => ['path' => '/var/www/magento2/CLI']], 'MAGE_MODE' => 'production']],
+                ['MAGE_DIRS' => ['base' => ['path' => '/var/www/magento2/CLI']], 'MAGE_MODE' => 'production'],
+            ],
         ];
     }
 
@@ -226,6 +239,168 @@ class InitParamListenerTest extends \PHPUnit_Framework_TestCase
             [$this->listener, 'onBootstrap']
         )->willReturn($this->callbackHandler);
         $eventManager->expects($this->once())->method('getSharedManager')->willReturn($sharedManager);
+
         return $eventManager;
     }
+
+    /**
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+     */
+    public function testAuthPreDispatch()
+    {
+        $eventMock = $this->getMockBuilder(\Zend\Mvc\MvcEvent::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $routeMatchMock = $this->getMockBuilder(\Zend\Mvc\Router\Http\RouteMatch::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $applicationMock = $this->getMockBuilder(\Zend\Mvc\Application::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $serviceManagerMock = $this->getMockBuilder(\Zend\ServiceManager\ServiceManager::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $deploymentConfigMock = $this->getMockBuilder(\Magento\Framework\App\DeploymentConfig::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $deploymentConfigMock->expects($this->once())
+            ->method('isAvailable')
+            ->willReturn(true);
+        $omProvider = $this->getMockBuilder(\Magento\Setup\Model\ObjectManagerProvider::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $objectManagerMock = $this->getMockForAbstractClass(\Magento\Framework\ObjectManagerInterface::class);
+        $adminAppStateMock = $this->getMockBuilder(\Magento\Framework\App\State::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $sessionConfigMock = $this->getMockBuilder(\Magento\Backend\Model\Session\AdminConfig::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $backendAppListMock = $this->getMockBuilder(\Magento\Backend\App\BackendAppList::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $backendAppMock = $this->getMockBuilder(\Magento\Backend\App\BackendApp::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $backendUrlFactoryMock = $this->getMockBuilder(\Magento\Backend\Model\UrlFactory::class)
+            ->setMethods(['create'])
+            ->disableOriginalConstructor()
+            ->getMock();
+        $backendUrlMock = $this->getMockBuilder(\Magento\Backend\Model\Url::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $authenticationMock = $this->getMockBuilder(\Magento\Backend\Model\Auth::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $adminSessionMock = $this->getMockBuilder(\Magento\Backend\Model\Auth\Session::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $responseMock = $this->getMockBuilder(\Zend\Http\Response::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $headersMock = $this->getMockBuilder(\Zend\Http\Headers::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $routeMatchMock->expects($this->once())
+            ->method('getParam')
+            ->with('controller')
+            ->willReturn('testController');
+        $eventMock->expects($this->once())
+            ->method('getRouteMatch')
+            ->willReturn($routeMatchMock);
+        $eventMock->expects($this->once())
+            ->method('getApplication')
+            ->willReturn($applicationMock);
+        $serviceManagerMock->expects($this->any())
+            ->method('get')
+            ->willReturnMap(
+                [
+                    [
+                        \Magento\Framework\App\DeploymentConfig::class,
+                        true,
+                        $deploymentConfigMock,
+                    ],
+                    [
+                        \Magento\Setup\Model\ObjectManagerProvider::class,
+                        true,
+                        $omProvider,
+                    ],
+                ]
+            );
+        $objectManagerMock->expects($this->any())
+            ->method('get')
+            ->willReturnMap(
+                [
+                    [
+                        \Magento\Framework\App\State::class,
+                        $adminAppStateMock,
+                    ],
+                    [
+                        \Magento\Backend\Model\Session\AdminConfig::class,
+                        $sessionConfigMock,
+                    ],
+                    [
+                        \Magento\Backend\App\BackendAppList::class,
+                        $backendAppListMock,
+                    ],
+                    [
+                        \Magento\Backend\Model\UrlFactory::class,
+                        $backendUrlFactoryMock,
+                    ],
+                    [
+                        \Magento\Backend\Model\Auth::class,
+                        $authenticationMock,
+                    ],
+                ]
+            );
+        $objectManagerMock->expects($this->any())
+            ->method('create')
+            ->willReturn($adminSessionMock);
+        $omProvider->expects($this->once())
+            ->method('get')
+            ->willReturn($objectManagerMock);
+        $adminAppStateMock->expects($this->once())
+            ->method('setAreaCode')
+            ->with(\Magento\Framework\App\Area::AREA_ADMINHTML);
+        $applicationMock->expects($this->once())
+            ->method('getServiceManager')
+            ->willReturn($serviceManagerMock);
+        $backendAppMock->expects($this->once())
+            ->method('getCookiePath')
+            ->willReturn('');
+        $backendUrlFactoryMock->expects($this->once())
+            ->method('create')
+            ->willReturn($backendUrlMock);
+        $backendAppListMock->expects($this->once())
+            ->method('getBackendApp')
+            ->willReturn($backendAppMock);
+        $authenticationMock->expects($this->once())
+            ->method('isLoggedIn')
+            ->willReturn(true);
+        $adminSessionMock->expects($this->once())
+            ->method('isAllowed')
+            ->with('Magento_Backend::setup_wizard', null)
+            ->willReturn(false);
+        $adminSessionMock->expects($this->once())
+            ->method('destroy');
+        $eventMock->expects($this->once())
+            ->method('getResponse')
+            ->willReturn($responseMock);
+        $responseMock->expects($this->once())
+            ->method('getHeaders')
+            ->willReturn($headersMock);
+        $headersMock->expects($this->once())
+            ->method('addHeaderLine');
+        $responseMock->expects($this->once())
+            ->method('setStatusCode')
+            ->with(302);
+        $eventMock->expects($this->once())
+            ->method('stopPropagation');
+
+        $this->assertSame(
+            $this->listener->authPreDispatch($eventMock),
+            $responseMock
+        );
+    }
 }
diff --git a/setup/view/magento/setup/web-configuration.phtml b/setup/view/magento/setup/web-configuration.phtml
index 35aa19484ed53f39bf37ae0e90e7b76c7f5efe87..ab2a00342b715b05f215d1d3e12010b0fc4993cc 100644
--- a/setup/view/magento/setup/web-configuration.phtml
+++ b/setup/view/magento/setup/web-configuration.phtml
@@ -30,7 +30,7 @@ $hints = [
 <div class="nav-bar-outer-actions">
     <div class="outer-actions-inner-wrap">
         <div class="btn-wrap btn-wrap-triangle-right btn-wrap-next">
-            <button type="button" class="btn btn-prime" ng-click="nextState()" dis>Next</button>
+            <button type="button" class="btn btn-prime" ng-click="validateUrl()" dis>Next</button>
         </div>
         <div class="btn-wrap btn-wrap-triangle-left btn-wrap-prev">
             <button type="button" class="btn" ng-click="previousState()">Back</button>
@@ -40,6 +40,13 @@ $hints = [
 
 <h2 class="page-sub-title">{{$state.current.header}}</h2>
 
+<div
+    class="message message-error"
+    ng-show="validateUrl.failed !== undefined"
+>
+    <span class="message-text">{{validateUrl.failed}}</span>
+</div>
+
 <form
     name="webconfig"
     role="form"