diff --git a/Gruntfile.js b/Gruntfile.js.sample
similarity index 100%
rename from Gruntfile.js
rename to Gruntfile.js.sample
diff --git a/app/code/Magento/AdvancedPricingImportExport/Model/Export/AdvancedPricing.php b/app/code/Magento/AdvancedPricingImportExport/Model/Export/AdvancedPricing.php
index 1f3ed3b32a851cced10d083bc2a537278e2cfa12..9183e182c29850cd7c99e27217667174611e77fd 100644
--- a/app/code/Magento/AdvancedPricingImportExport/Model/Export/AdvancedPricing.php
+++ b/app/code/Magento/AdvancedPricingImportExport/Model/Export/AdvancedPricing.php
@@ -142,8 +142,7 @@ class AdvancedPricing extends \Magento\CatalogImportExport\Model\Export\Product
             $attributeColFactory,
             $_typeFactory,
             $linkTypeProvider,
-            $rowCustomizer,
-            $metadataPool
+            $rowCustomizer
         );
     }
 
@@ -356,6 +355,7 @@ class AdvancedPricing extends \Magento\CatalogImportExport\Model\Export\Product
                 }
             }
             try {
+                $productEntityLinkField = $this->getProductEntityLinkField();
                 $select = $this->_connection->select()
                     ->from(
                         ['cpe' => $this->_resource->getTableName('catalog_product_entity')],
@@ -363,7 +363,7 @@ class AdvancedPricing extends \Magento\CatalogImportExport\Model\Export\Product
                     )
                     ->joinInner(
                         ['ap' => $this->_resource->getTableName($table)],
-                        'ap.entity_id = cpe.entity_id',
+                        'ap.' . $productEntityLinkField . ' = cpe.' . $productEntityLinkField,
                         []
                     )
                     ->where('cpe.entity_id IN (?)', $listSku);
diff --git a/app/code/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricing.php b/app/code/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricing.php
index 8290ddbd6714a67d3d1254bc8916676089ceb2eb..5fe6de9beaaf8dee4639101f3207a7d5d30d49ad 100644
--- a/app/code/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricing.php
+++ b/app/code/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricing.php
@@ -15,6 +15,7 @@ use Magento\Framework\App\ResourceConnection;
  *
  * @SuppressWarnings(PHPMD.ExcessiveParameterList)
  * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ * @SuppressWarnings(PHPMD.TooManyFields)
  */
 class AdvancedPricing extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
 {
@@ -126,7 +127,7 @@ class AdvancedPricing extends \Magento\ImportExport\Model\Import\Entity\Abstract
     /**
      * @var array
      */
-    protected $_oldSkus;
+    protected $_oldSkus = null;
 
     /**
      * Permanent entity columns.
@@ -147,6 +148,13 @@ class AdvancedPricing extends \Magento\ImportExport\Model\Import\Entity\Abstract
      */
     protected $dateTime;
 
+    /**
+     * Product entity link field
+     *
+     * @var string
+     */
+    private $productEntityLinkField;
+
     /**
      * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
      * @param \Magento\Framework\Json\Helper\Data $jsonHelper
@@ -199,11 +207,11 @@ class AdvancedPricing extends \Magento\ImportExport\Model\Import\Entity\Abstract
         $this->_storeResolver = $storeResolver;
         $this->_importProduct = $importProduct;
         $this->_validators[self::VALIDATOR_MAIN] = $validator->init($this);
+        $this->_catalogProductEntity = $this->_resourceFactory->create()->getTable('catalog_product_entity');
         $this->_oldSkus = $this->retrieveOldSkus();
         $this->_validators[self::VALIDATOR_WEBSITE] = $websiteValidator;
         $this->_validators[self::VALIDATOR_TEAR_PRICE] = $tierPriceValidator;
         $this->errorAggregator = $errorAggregator;
-        $this->_catalogProductEntity = $this->_resourceFactory->create()->getTable('catalog_product_entity');
 
         foreach (array_merge($this->errorMessageTemplates, $this->_messageTemplates) as $errorCode => $message) {
             $this->getErrorAggregator()->addErrorMessageTemplate($errorCode, $message);
@@ -409,11 +417,12 @@ class AdvancedPricing extends \Magento\ImportExport\Model\Import\Entity\Abstract
             $tableName = $this->_resourceFactory->create()->getTable($table);
             $priceIn = [];
             $entityIds = [];
+            $oldSkus = $this->retrieveOldSkus();
             foreach ($priceData as $sku => $priceRows) {
-                if (isset($this->_oldSkus[$sku])) {
-                    $productId = $this->_oldSkus[$sku];
+                if (isset($oldSkus[$sku])) {
+                    $productId = $oldSkus[$sku];
                     foreach ($priceRows as $row) {
-                        $row['entity_id'] = $productId;
+                        $row[$this->getProductEntityLinkField()] = $productId;
                         $priceIn[] = $row;
                         $entityIds[] = $productId;
                     }
@@ -430,16 +439,18 @@ class AdvancedPricing extends \Magento\ImportExport\Model\Import\Entity\Abstract
      * Deletes tier prices prices.
      *
      * @param array $listSku
-     * @param string $tableName
-     * @return bool
+     * @param string $table
+     * @return boolean
      */
-    protected function deleteProductTierPrices(array $listSku, $tableName)
+    protected function deleteProductTierPrices(array $listSku, $table)
     {
+        $tableName = $this->_resourceFactory->create()->getTable($table);
+        $productEntityLinkField = $this->getProductEntityLinkField();
         if ($tableName && $listSku) {
             if (!$this->_cachedSkuToDelete) {
                 $this->_cachedSkuToDelete = $this->_connection->fetchCol(
                     $this->_connection->select()
-                        ->from($this->_catalogProductEntity, 'entity_id')
+                        ->from($this->_catalogProductEntity, $productEntityLinkField)
                         ->where('sku IN (?)', $listSku)
                 );
             }
@@ -447,7 +458,7 @@ class AdvancedPricing extends \Magento\ImportExport\Model\Import\Entity\Abstract
                 try {
                     $this->countItemsDeleted += $this->_connection->delete(
                         $tableName,
-                        $this->_connection->quoteInto('entity_id IN (?)', $this->_cachedSkuToDelete)
+                        $this->_connection->quoteInto($productEntityLinkField . ' IN (?)', $this->_cachedSkuToDelete)
                     );
                     return true;
                 } catch (\Exception $e) {
@@ -511,13 +522,15 @@ class AdvancedPricing extends \Magento\ImportExport\Model\Import\Entity\Abstract
      */
     protected function retrieveOldSkus()
     {
-        $oldSkus = $this->_connection->fetchPairs(
-            $this->_connection->select()->from(
-                $this->_connection->getTableName('catalog_product_entity'),
-                ['sku', 'entity_id']
-            )
-        );
-        return $oldSkus;
+        if ($this->_oldSkus === null) {
+            $this->_oldSkus = $this->_connection->fetchPairs(
+                $this->_connection->select()->from(
+                    $this->_catalogProductEntity,
+                    ['sku', $this->getProductEntityLinkField()]
+                )
+            );
+        }
+        return $this->_oldSkus;
     }
 
     /**
@@ -529,15 +542,18 @@ class AdvancedPricing extends \Magento\ImportExport\Model\Import\Entity\Abstract
      */
     protected function processCountExistingPrices($prices, $table)
     {
+        $tableName = $this->_resourceFactory->create()->getTable($table);
+        $productEntityLinkField = $this->getProductEntityLinkField();
         $existingPrices = $this->_connection->fetchAssoc(
             $this->_connection->select()->from(
-                $this->_connection->getTableName($table),
-                ['value_id', 'entity_id', 'all_groups', 'customer_group_id']
+                $tableName,
+                ['value_id', $productEntityLinkField, 'all_groups', 'customer_group_id']
             )
         );
+        $oldSkus = $this->retrieveOldSkus();
         foreach ($existingPrices as $existingPrice) {
-            foreach ($this->_oldSkus as $sku => $productId) {
-                if ($existingPrice['entity_id'] == $productId && isset($prices[$sku])) {
+            foreach ($oldSkus as $sku => $productId) {
+                if ($existingPrice[$productEntityLinkField] == $productId && isset($prices[$sku])) {
                     $this->incrementCounterUpdated($prices[$sku], $existingPrice);
                 }
             }
@@ -579,4 +595,19 @@ class AdvancedPricing extends \Magento\ImportExport\Model\Import\Entity\Abstract
 
         return $this;
     }
+
+    /**
+     * Get product entity link field
+     *
+     * @return string
+     */
+    private function getProductEntityLinkField()
+    {
+        if (!$this->productEntityLinkField) {
+            $this->productEntityLinkField = $this->getMetadataPool()
+                ->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class)
+                ->getLinkField();
+        }
+        return $this->productEntityLinkField;
+    }
 }
diff --git a/app/code/Magento/AdvancedPricingImportExport/Test/Unit/Model/Import/AdvancedPricingTest.php b/app/code/Magento/AdvancedPricingImportExport/Test/Unit/Model/Import/AdvancedPricingTest.php
index 50b78742976cb51b2c60db8c6b79b151097db120..9b7bd169dea5e3ee68fce1874f95b75dbc8ba6eb 100644
--- a/app/code/Magento/AdvancedPricingImportExport/Test/Unit/Model/Import/AdvancedPricingTest.php
+++ b/app/code/Magento/AdvancedPricingImportExport/Test/Unit/Model/Import/AdvancedPricingTest.php
@@ -15,6 +15,8 @@ use \Magento\CatalogImportExport\Model\Import\Product\RowValidatorInterface as R
  */
 class AdvancedPricingTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractImportTestCase
 {
+    const TABLE_NAME = 'tableName';
+    const LINK_FIELD = 'linkField';
 
     /**
      * @var ResourceFactory |\PHPUnit_Framework_MockObject_MockObject
@@ -126,56 +128,56 @@ class AdvancedPricingTest extends \Magento\ImportExport\Test\Unit\Model\Import\A
         parent::setUp();
 
         $this->jsonHelper = $this->getMock(
-            '\Magento\Framework\Json\Helper\Data',
+            \Magento\Framework\Json\Helper\Data::class,
             [],
             [],
             '',
             false
         );
         $this->importExportData = $this->getMock(
-            '\Magento\ImportExport\Helper\Data',
+            \Magento\ImportExport\Helper\Data::class,
             [],
             [],
             '',
             false
         );
         $this->resourceHelper = $this->getMock(
-            '\Magento\ImportExport\Model\ResourceModel\Helper',
+            \Magento\ImportExport\Model\ResourceModel\Helper::class,
             [],
             [],
             '',
             false
         );
         $this->resource = $this->getMock(
-            '\Magento\Framework\App\ResourceConnection',
+            \Magento\Framework\App\ResourceConnection::class,
             ['getConnection'],
             [],
             '',
             false
         );
         $this->connection = $this->getMockForAbstractClass(
-            '\Magento\Framework\DB\Adapter\AdapterInterface',
+            \Magento\Framework\DB\Adapter\AdapterInterface::class,
             [],
             '',
             false
         );
         $this->resource->expects($this->any())->method('getConnection')->willReturn($this->connection);
         $this->dataSourceModel = $this->getMock(
-            '\Magento\ImportExport\Model\ResourceModel\Import\Data',
+            \Magento\ImportExport\Model\ResourceModel\Import\Data::class,
             [],
             [],
             '',
             false
         );
         $this->eavConfig = $this->getMock(
-            '\Magento\Eav\Model\Config',
+            \Magento\Eav\Model\Config::class,
             [],
             [],
             '',
             false
         );
         $entityType = $this->getMock(
-            '\Magento\Eav\Model\Entity\Type',
+            \Magento\Eav\Model\Entity\Type::class,
             [],
             [],
             '',
@@ -184,65 +186,65 @@ class AdvancedPricingTest extends \Magento\ImportExport\Test\Unit\Model\Import\A
         $entityType->method('getEntityTypeId')->willReturn('');
         $this->eavConfig->method('getEntityType')->willReturn($entityType);
         $this->resourceFactory = $this->getMock(
-            '\Magento\CatalogImportExport\Model\Import\Proxy\Product\ResourceModelFactory',
+            \Magento\CatalogImportExport\Model\Import\Proxy\Product\ResourceModelFactory::class,
             ['create', 'getTable'],
             [],
             '',
             false
         );
         $this->resourceFactory->expects($this->any())->method('create')->willReturnSelf();
-        $this->resourceFactory->expects($this->any())->method('getTable')->willReturnSelf();
+        $this->resourceFactory->expects($this->any())->method('getTable')->willReturn(self::TABLE_NAME);
         $this->catalogData = $this->getMock(
-            '\Magento\Catalog\Helper\Data',
+            \Magento\Catalog\Helper\Data::class,
             [],
             [],
             '',
             false
         );
         $this->storeResolver = $this->getMock(
-            '\Magento\CatalogImportExport\Model\Import\Product\StoreResolver',
+            \Magento\CatalogImportExport\Model\Import\Product\StoreResolver::class,
             [],
             [],
             '',
             false
         );
         $this->importProduct = $this->getMock(
-            '\Magento\CatalogImportExport\Model\Import\Product',
+            \Magento\CatalogImportExport\Model\Import\Product::class,
             [],
             [],
             '',
             false
         );
         $this->productModel = $this->getMock(
-            '\Magento\Catalog\Model\Product',
+            \Magento\Catalog\Model\Product::class,
             [],
             [],
             '',
             false
         );
         $this->validator = $this->getMock(
-            '\Magento\AdvancedPricingImportExport\Model\Import\AdvancedPricing\Validator',
+            \Magento\AdvancedPricingImportExport\Model\Import\AdvancedPricing\Validator::class,
             ['isValid', 'getMessages'],
             [],
             '',
             false
         );
         $this->websiteValidator = $this->getMock(
-            '\Magento\AdvancedPricingImportExport\Model\Import\AdvancedPricing\Validator\Website',
+            \Magento\AdvancedPricingImportExport\Model\Import\AdvancedPricing\Validator\Website::class,
             [],
             [],
             '',
             false
         );
         $this->tierPriceValidator = $this->getMock(
-            '\Magento\AdvancedPricingImportExport\Model\Import\AdvancedPricing\Validator\TierPrice',
+            \Magento\AdvancedPricingImportExport\Model\Import\AdvancedPricing\Validator\TierPrice::class,
             [],
             [],
             '',
             false
         );
         $this->stringObject = $this->getMock(
-            '\Magento\Framework\Stdlib\StringUtils',
+            \Magento\Framework\Stdlib\StringUtils::class,
             [],
             [],
             '',
@@ -250,7 +252,7 @@ class AdvancedPricingTest extends \Magento\ImportExport\Test\Unit\Model\Import\A
         );
         $this->errorAggregator = $this->getErrorAggregatorObject();
         $this->dateTime = $this->getMock(
-            '\Magento\Framework\Stdlib\DateTime\DateTime',
+            \Magento\Framework\Stdlib\DateTime\DateTime::class,
             ['date', 'format'],
             [],
             '',
@@ -258,19 +260,21 @@ class AdvancedPricingTest extends \Magento\ImportExport\Test\Unit\Model\Import\A
         );
         $this->dateTime->expects($this->any())->method('date')->willReturnSelf();
 
-        $this->advancedPricing = $this->getAdvancedPricingMock([
-            'retrieveOldSkus',
-            'validateRow',
-            'addRowError',
-            'saveProductPrices',
-            'getCustomerGroupId',
-            'getWebSiteId',
-            'deleteProductTierPrices',
-            'getBehavior',
-            'saveAndReplaceAdvancedPrices',
-            'processCountExistingPrices',
-            'processCountNewPrices'
-        ]);
+        $this->advancedPricing = $this->getAdvancedPricingMock(
+            [
+                'retrieveOldSkus',
+                'validateRow',
+                'addRowError',
+                'saveProductPrices',
+                'getCustomerGroupId',
+                'getWebSiteId',
+                'deleteProductTierPrices',
+                'getBehavior',
+                'saveAndReplaceAdvancedPrices',
+                'processCountExistingPrices',
+                'processCountNewPrices'
+            ]
+        );
 
         $this->advancedPricing->expects($this->any())->method('retrieveOldSkus')->willReturn([]);
     }
@@ -294,14 +298,16 @@ class AdvancedPricingTest extends \Magento\ImportExport\Test\Unit\Model\Import\A
     public function testValidateRowResult($rowData, $behavior, $expectedResult)
     {
         $rowNum = 0;
-        $advancedPricingMock = $this->getAdvancedPricingMock([
-            'retrieveOldSkus',
-            'addRowError',
-            'saveProductPrices',
-            'getCustomerGroupId',
-            'getWebSiteId',
-            'getBehavior',
-        ]);
+        $advancedPricingMock = $this->getAdvancedPricingMock(
+            [
+                'retrieveOldSkus',
+                'addRowError',
+                'saveProductPrices',
+                'getCustomerGroupId',
+                'getWebSiteId',
+                'getBehavior',
+            ]
+        );
         $this->validator->expects($this->any())->method('isValid')->willReturn(true);
         $advancedPricingMock->expects($this->any())->method('getBehavior')->willReturn($behavior);
 
@@ -317,14 +323,16 @@ class AdvancedPricingTest extends \Magento\ImportExport\Test\Unit\Model\Import\A
     public function testValidateRowAddRowErrorCall($rowData, $behavior, $error)
     {
         $rowNum = 0;
-        $advancedPricingMock = $this->getAdvancedPricingMock([
-            'retrieveOldSkus',
-            'addRowError',
-            'saveProductPrices',
-            'getCustomerGroupId',
-            'getWebSiteId',
-            'getBehavior',
-        ]);
+        $advancedPricingMock = $this->getAdvancedPricingMock(
+            [
+                'retrieveOldSkus',
+                'addRowError',
+                'saveProductPrices',
+                'getCustomerGroupId',
+                'getWebSiteId',
+                'getBehavior',
+            ]
+        );
         $this->validator->expects($this->any())->method('isValid')->willReturn(true);
         $advancedPricingMock->expects($this->any())->method('getBehavior')->willReturn($behavior);
         $advancedPricingMock->expects($this->once())->method('addRowError')->with($error, $rowNum);
@@ -341,13 +349,15 @@ class AdvancedPricingTest extends \Magento\ImportExport\Test\Unit\Model\Import\A
         $rowData = [
             \Magento\AdvancedPricingImportExport\Model\Import\AdvancedPricing::COL_SKU => 'sku value',
         ];
-        $advancedPricingMock = $this->getAdvancedPricingMock([
-            'retrieveOldSkus',
-            'addRowError',
-            'saveProductPrices',
-            'getCustomerGroupId',
-            'getWebSiteId',
-        ]);
+        $advancedPricingMock = $this->getAdvancedPricingMock(
+            [
+                'retrieveOldSkus',
+                'addRowError',
+                'saveProductPrices',
+                'getCustomerGroupId',
+                'getWebSiteId',
+            ]
+        );
         $this->setPropertyValue($advancedPricingMock, '_validatedRows', []);
         $this->validator->expects($this->once())->method('isValid')->willReturn(false);
         $messages = ['value'];
@@ -415,13 +425,17 @@ class AdvancedPricingTest extends \Magento\ImportExport\Test\Unit\Model\Import\A
         $this->dataSourceModel->expects($this->at(0))->method('getNextBunch')->willReturn($data);
         $this->advancedPricing->expects($this->any())->method('validateRow')->willReturn(true);
 
-        $this->advancedPricing->expects($this->any())->method('getCustomerGroupId')->willReturnMap([
-            [$data[0][AdvancedPricing::COL_TIER_PRICE_CUSTOMER_GROUP], $tierCustomerGroupId],
-        ]);
+        $this->advancedPricing->expects($this->any())->method('getCustomerGroupId')->willReturnMap(
+            [
+                [$data[0][AdvancedPricing::COL_TIER_PRICE_CUSTOMER_GROUP], $tierCustomerGroupId],
+            ]
+        );
 
-        $this->advancedPricing->expects($this->any())->method('getWebSiteId')->willReturnMap([
-            [$data[0][AdvancedPricing::COL_TIER_PRICE_WEBSITE], $tierWebsiteId],
-        ]);
+        $this->advancedPricing->expects($this->any())->method('getWebSiteId')->willReturnMap(
+            [
+                [$data[0][AdvancedPricing::COL_TIER_PRICE_WEBSITE], $tierWebsiteId],
+            ]
+        );
 
         $this->advancedPricing->expects($this->any())->method('saveProductPrices')->will($this->returnSelf());
 
@@ -570,8 +584,10 @@ class AdvancedPricingTest extends \Magento\ImportExport\Test\Unit\Model\Import\A
                 '$expectedTierPrices' => [
                     'sku value' => [
                         [
-                            'all_groups' => false,//$rowData[self::COL_TIER_PRICE_CUSTOMER_GROUP] == self::VALUE_ALL_GROUPS
-                            'customer_group_id' => 'tier customer group id value',//$tierCustomerGroupId
+                            'all_groups' => false,
+                            //$rowData[self::COL_TIER_PRICE_CUSTOMER_GROUP] == self::VALUE_ALL_GROUPS
+                            'customer_group_id' => 'tier customer group id value',
+                            //$tierCustomerGroupId
                             'qty' => 'tier price qty value',
                             'value' => 'tier price value',
                             'website_id' => 'tier website id value',
@@ -580,31 +596,33 @@ class AdvancedPricingTest extends \Magento\ImportExport\Test\Unit\Model\Import\A
                 ],
             ],
             [// tier customer group is equal to all group
-                 '$data' => [
-                     0 => [
-                         AdvancedPricing::COL_SKU => 'sku value',
-                         //tier
-                         AdvancedPricing::COL_TIER_PRICE_WEBSITE => 'tier price website value',
-                         AdvancedPricing::COL_TIER_PRICE_CUSTOMER_GROUP => AdvancedPricing::VALUE_ALL_GROUPS,
-                         AdvancedPricing::COL_TIER_PRICE_QTY => 'tier price qty value',
-                         AdvancedPricing::COL_TIER_PRICE => 'tier price value',
-                     ],
-                 ],
-                 '$tierCustomerGroupId' => 'tier customer group id value',
-                 '$groupCustomerGroupId' => 'group customer group id value',
-                 '$tierWebsiteId' => 'tier website id value',
-                 '$groupWebsiteId' => 'group website id value',
-                 '$expectedTierPrices' => [
-                     'sku value' => [
-                         [
-                             'all_groups' => true,//$rowData[self::COL_TIER_PRICE_CUSTOMER_GROUP] == self::VALUE_ALL_GROUPS
-                             'customer_group_id' => 'tier customer group id value',//$tierCustomerGroupId
-                             'qty' => 'tier price qty value',
-                             'value' => 'tier price value',
-                             'website_id' => 'tier website id value',
-                         ],
-                     ],
-                 ],
+                '$data' => [
+                    0 => [
+                        AdvancedPricing::COL_SKU => 'sku value',
+                        //tier
+                        AdvancedPricing::COL_TIER_PRICE_WEBSITE => 'tier price website value',
+                        AdvancedPricing::COL_TIER_PRICE_CUSTOMER_GROUP => AdvancedPricing::VALUE_ALL_GROUPS,
+                        AdvancedPricing::COL_TIER_PRICE_QTY => 'tier price qty value',
+                        AdvancedPricing::COL_TIER_PRICE => 'tier price value',
+                    ],
+                ],
+                '$tierCustomerGroupId' => 'tier customer group id value',
+                '$groupCustomerGroupId' => 'group customer group id value',
+                '$tierWebsiteId' => 'tier website id value',
+                '$groupWebsiteId' => 'group website id value',
+                '$expectedTierPrices' => [
+                    'sku value' => [
+                        [
+                            'all_groups' => true,
+                            //$rowData[self::COL_TIER_PRICE_CUSTOMER_GROUP] == self::VALUE_ALL_GROUPS
+                            'customer_group_id' => 'tier customer group id value',
+                            //$tierCustomerGroupId
+                            'qty' => 'tier price qty value',
+                            'value' => 'tier price value',
+                            'website_id' => 'tier website id value',
+                        ],
+                    ],
+                ],
             ],
             [
                 '$data' => [
@@ -641,8 +659,10 @@ class AdvancedPricingTest extends \Magento\ImportExport\Test\Unit\Model\Import\A
                 '$expectedTierPrices' => [
                     'sku value' => [
                         [
-                            'all_groups' => false,//$rowData[self::COL_TIER_PRICE_CUSTOMER_GROUP] == self::VALUE_ALL_GROUPS
-                            'customer_group_id' => 'tier customer group id value',//$tierCustomerGroupId
+                            'all_groups' => false,
+                            //$rowData[self::COL_TIER_PRICE_CUSTOMER_GROUP] == self::VALUE_ALL_GROUPS
+                            'customer_group_id' => 'tier customer group id value',
+                            //$tierCustomerGroupId
                             'qty' => 'tier price qty value',
                             'value' => 'tier price value',
                             'website_id' => 'tier website id value',
@@ -711,6 +731,199 @@ class AdvancedPricingTest extends \Magento\ImportExport\Test\Unit\Model\Import\A
         ];
     }
 
+    /**
+     * @param array $priceData
+     * @param array $oldSkus
+     * @param array $priceIn
+     * @param int $callNum
+     * @dataProvider saveProductPricesDataProvider
+     */
+    public function testSaveProductPrices($priceData, $oldSkus, $priceIn, $callNum)
+    {
+        $this->advancedPricing = $this->getAdvancedPricingMock(['retrieveOldSkus']);
+
+        $this->advancedPricing->expects($this->any())->method('retrieveOldSkus')->willReturn($oldSkus);
+
+        $this->connection->expects($this->exactly($callNum))
+            ->method('insertOnDuplicate')
+            ->with(self::TABLE_NAME, $priceIn, ['value']);
+
+        $this->invokeMethod($this->advancedPricing, 'saveProductPrices', [$priceData, 'table']);
+    }
+
+    public function saveProductPricesDataProvider()
+    {
+        return [
+            [[], ['oSku1' => 'product1', 'oSku2' => 'product2'], [], 0],
+            [
+                [
+                    'oSku1' => ['row1' => ['row1-1', 'row1-2'], 'row2' => ['row2-1', 'row2-2']],
+                    'nSku' => ['row3', 'row4'],
+                ],
+                ['oSku1' => 'product1', 'oSku2' => 'product2'],
+                [
+                    ['row1-1', 'row1-2', self::LINK_FIELD => 'product1'],
+                    ['row2-1', 'row2-2', self::LINK_FIELD => 'product1']
+                ],
+                1
+            ],
+        ];
+    }
+
+    /**
+     * @param array $listSku
+     * @param array $cachedSkuToDelete
+     * @param int $numCallAddError
+     * @param int $numCallDelete
+     * @param boolean $exceptionInDelete
+     * @param boolean $result
+     * @dataProvider deleteProductTierPricesDataProvider
+     */
+    public function testDeleteProductTierPrices(
+        $listSku,
+        $cachedSkuToDelete,
+        $numCallAddError,
+        $numCallDelete,
+        $exceptionInDelete,
+        $result
+    ) {
+        $this->advancedPricing = $this->getAdvancedPricingMock(['addRowError', 'retrieveOldSkus']);
+        $dbSelectMock = $this->getMock(\Magento\Framework\DB\Select::class, [], [], '', false);
+        if ($listSku) {
+            $this->connection->expects($this->once())
+                ->method('fetchCol')
+                ->willReturn($cachedSkuToDelete);
+            $this->connection->expects($this->once())
+                ->method('select')
+                ->willReturn($dbSelectMock);
+            $dbSelectMock->expects($this->once())
+                ->method('from')
+                ->with(self::TABLE_NAME, self::LINK_FIELD)
+                ->willReturnSelf();
+            $dbSelectMock->expects($this->once())
+                ->method('where')
+                ->willReturnSelf();
+        }
+
+        $this->advancedPricing->expects($this->exactly($numCallAddError))
+            ->method('addRowError');
+        if ($exceptionInDelete) {
+            $this->connection->expects($this->exactly($numCallDelete))
+                ->method('delete')
+                ->willThrowException(new \Exception());
+        } else {
+            $this->connection->expects($this->exactly($numCallDelete))
+                ->method('delete')
+                ->willReturn(1);
+        }
+        $this->assertEquals(
+            $result,
+            $this->invokeMethod($this->advancedPricing, 'deleteProductTierPrices', [$listSku, 'table'])
+        );
+    }
+
+    public function deleteProductTierPricesDataProvider()
+    {
+        return [
+            [
+                [],
+                ['toDelete1', 'toDelete2'],
+                0,
+                0,
+                0,
+                false
+            ],
+            [
+                ['sku1', 'sku2'],
+                ['toDelete1', 'toDelete2'],
+                0,
+                1,
+                0,
+                true
+            ],
+            [
+                ['sku1', 'sku2'],
+                ['toDelete1', 'toDelete2'],
+                0,
+                1,
+                1,
+                false
+            ],
+            [
+                ['sku1', 'sku2'],
+                [],
+                1,
+                0,
+                0,
+                false
+            ],
+        ];
+    }
+
+    /**
+     * @param array $prices
+     * @param array $existingPrices
+     * @param array $oldSkus
+     * @param int $numCall
+     * @param array $args
+     * @dataProvider processCountExistingPricesDataProvider
+     */
+    public function testProcessCountExistingPrices(
+        $prices,
+        $existingPrices,
+        $oldSkus,
+        $numCall,
+        $args
+    ) {
+        $this->advancedPricing = $this->getAdvancedPricingMock(
+            [
+                'incrementCounterUpdated',
+                'retrieveOldSkus'
+            ]
+        );
+        $dbSelectMock = $this->getMock(\Magento\Framework\DB\Select::class, [], [], '', false);
+        $this->connection->expects($this->once())
+            ->method('fetchAssoc')
+            ->willReturn($existingPrices);
+        $this->connection->expects($this->once())
+            ->method('select')
+            ->willReturn($dbSelectMock);
+        $dbSelectMock->expects($this->once())
+            ->method('from')
+            ->with(
+                self::TABLE_NAME,
+                ['value_id', self::LINK_FIELD, 'all_groups', 'customer_group_id']
+            )->willReturnSelf();
+        $this->advancedPricing->expects($this->once())
+            ->method('retrieveOldSkus')
+            ->willReturn($oldSkus);
+        $this->advancedPricing->expects($this->exactly($numCall))
+            ->method('incrementCounterUpdated')
+            ->withConsecutive($args);
+
+        $this->invokeMethod($this->advancedPricing, 'processCountExistingPrices', [$prices, 'table']);
+    }
+
+    public function processCountExistingPricesDataProvider()
+    {
+        return [
+            [
+                ['oSku1' => ['price1'], 'nSku' => 'price'],
+                [[self::LINK_FIELD => 'product1']],
+                ['oSku1' => 'product1', 'oSku2' => 'product2'],
+                1,
+                [['price1'], [self::LINK_FIELD => 'product1']]
+            ],
+            [
+                ['oSku1' => ['price1'], 'nSku' => 'price'],
+                [[self::LINK_FIELD => 'product']],
+                ['oSku1' => 'product1', 'oSku2' => 'product2'],
+                0,
+                [['price1'], [self::LINK_FIELD => 'product1']]
+            ],
+        ];
+    }
+
     /**
      * Get any object property value.
      *
@@ -755,11 +968,11 @@ class AdvancedPricingTest extends \Magento\ImportExport\Test\Unit\Model\Import\A
      */
     private function invokeMethod($object, $method, $args = [])
     {
-        $class = new \ReflectionClass('\Magento\AdvancedPricingImportExport\Model\Import\AdvancedPricing');
+        $class = new \ReflectionClass(\Magento\AdvancedPricingImportExport\Model\Import\AdvancedPricing::class);
         $method = $class->getMethod($method);
         $method->setAccessible(true);
 
-        return $method->invokeArgs($this->advancedPricing, []);
+        return $method->invokeArgs($object, $args);
     }
 
     /**
@@ -771,8 +984,29 @@ class AdvancedPricingTest extends \Magento\ImportExport\Test\Unit\Model\Import\A
      */
     private function getAdvancedPricingMock($methods = [])
     {
-        return $this->getMock(
-            '\Magento\AdvancedPricingImportExport\Model\Import\AdvancedPricing',
+        $metadataPoolMock = $this->getMock(
+            \Magento\Framework\Model\Entity\MetadataPool::class,
+            [],
+            [],
+            '',
+            false
+        );
+        $metadataMock = $this->getMock(
+            \Magento\Framework\Model\Entity\EntityMetadata::class,
+            [],
+            [],
+            '',
+            false
+        );
+        $metadataMock->expects($this->any())
+            ->method('getLinkField')
+            ->willReturn(self::LINK_FIELD);
+        $metadataPoolMock->expects($this->any())
+            ->method('getMetaData')
+            ->with(\Magento\Catalog\Api\Data\ProductInterface::class)
+            ->willReturn($metadataMock);
+        $advancedPricingMock = $this->getMock(
+            \Magento\AdvancedPricingImportExport\Model\Import\AdvancedPricing::class,
             $methods,
             [
                 $this->jsonHelper,
@@ -795,5 +1029,11 @@ class AdvancedPricingTest extends \Magento\ImportExport\Test\Unit\Model\Import\A
             ],
             ''
         );
+        $reflection = new \ReflectionClass(\Magento\AdvancedPricingImportExport\Model\Import\AdvancedPricing::class);
+        $reflectionProperty = $reflection->getProperty('metadataPool');
+        $reflectionProperty->setAccessible(true);
+        $reflectionProperty->setValue($advancedPricingMock, $metadataPoolMock);
+
+        return $advancedPricingMock;
     }
 }
diff --git a/app/code/Magento/Backend/Model/Auth/Session.php b/app/code/Magento/Backend/Model/Auth/Session.php
index d5cf7e86c4b8ae8c301a2993893a9d31d615e7e5..0e9383d4e63c6e11997e65389bc435cceb5b7af8 100644
--- a/app/code/Magento/Backend/Model/Auth/Session.php
+++ b/app/code/Magento/Backend/Model/Auth/Session.php
@@ -171,26 +171,13 @@ class Session extends \Magento\Framework\Session\SessionManager implements \Mage
     }
 
     /**
-     * Set session UpdatedAt to current time and update cookie expiration time
+     * Set session UpdatedAt to current time
      *
      * @return void
      */
     public function prolong()
     {
-        $lifetime = $this->_config->getValue(self::XML_PATH_SESSION_LIFETIME);
-        $currentTime = time();
-
-        $this->setUpdatedAt($currentTime);
-        $cookieValue = $this->cookieManager->getCookie($this->getName());
-        if ($cookieValue) {
-            $cookieMetadata = $this->cookieMetadataFactory->createPublicCookieMetadata()
-                ->setDuration($lifetime)
-                ->setPath($this->sessionConfig->getCookiePath())
-                ->setDomain($this->sessionConfig->getCookieDomain())
-                ->setSecure($this->sessionConfig->getCookieSecure())
-                ->setHttpOnly($this->sessionConfig->getCookieHttpOnly());
-            $this->cookieManager->setPublicCookie($this->getName(), $cookieValue, $cookieMetadata);
-        }
+        $this->setUpdatedAt(time());
     }
 
     /**
diff --git a/app/code/Magento/Backend/Model/Config/SessionLifetime/BackendModel.php b/app/code/Magento/Backend/Model/Config/SessionLifetime/BackendModel.php
new file mode 100644
index 0000000000000000000000000000000000000000..ccb5c65a8c5080984ff72627760a795e2507cbde
--- /dev/null
+++ b/app/code/Magento/Backend/Model/Config/SessionLifetime/BackendModel.php
@@ -0,0 +1,36 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Backend\Model\Config\SessionLifetime;
+
+use Magento\Framework\App\Config\Value;
+use Magento\Framework\Exception\LocalizedException;
+
+/**
+ * Backend model for the admin/security/session_lifetime configuration field. Validates session lifetime.
+ */
+class BackendModel extends Value
+{
+    /** Maximum dmin session lifetime; 1 year*/
+    const MAX_LIFETIME = 31536000;
+
+    /** Minimum admin session lifetime */
+    const MIN_LIFETIME = 60;
+
+    public function beforeSave()
+    {
+        $value = (int) $this->getValue();
+        if ($value > self::MAX_LIFETIME) {
+            throw new LocalizedException(
+                __('Admin session lifetime must be less than or equal to 31536000 seconds (one year)')
+            );
+        } else if ($value < self::MIN_LIFETIME) {
+            throw new LocalizedException(
+                __('Admin session lifetime must be greater than or equal to 60 seconds')
+            );
+        }
+        return parent::beforeSave();
+    }
+}
diff --git a/app/code/Magento/Backend/Model/Session/AdminConfig.php b/app/code/Magento/Backend/Model/Session/AdminConfig.php
index 9dced89caf30d572aeb36fd149850ef36acac015..8edec773402648d9be0653aab9e2496f67286d81 100644
--- a/app/code/Magento/Backend/Model/Session/AdminConfig.php
+++ b/app/code/Magento/Backend/Model/Session/AdminConfig.php
@@ -14,8 +14,6 @@ use Magento\Framework\Session\Config;
 
 /**
  * Magento Backend session configuration
- *
- * @method Config setSaveHandler()
  */
 class AdminConfig extends Config
 {
@@ -107,4 +105,14 @@ class AdminConfig extends Config
         $cookiePath = $baseUrl . $backendApp->getCookiePath();
         return $cookiePath;
     }
+
+    /**
+     * Set session cookie lifetime to session duration
+     *
+     * @return $this
+     */
+    protected function configureCookieLifetime()
+    {
+        return $this->setCookieLifetime(0);
+    }
 }
diff --git a/app/code/Magento/Backend/Test/Unit/Model/Auth/SessionTest.php b/app/code/Magento/Backend/Test/Unit/Model/Auth/SessionTest.php
index 3e41177e72c0cae37f1f4324caa310d63e471e2c..b5b3fed369f326ef9724fee32f003b6ea42f359d 100644
--- a/app/code/Magento/Backend/Test/Unit/Model/Auth/SessionTest.php
+++ b/app/code/Magento/Backend/Test/Unit/Model/Auth/SessionTest.php
@@ -162,67 +162,7 @@ class SessionTest extends \PHPUnit_Framework_TestCase
 
     public function testProlong()
     {
-        $name = session_name();
-        $cookie = 'cookie';
-        $lifetime = 900;
-        $path = '/';
-        $domain = 'magento2';
-        $secure = true;
-        $httpOnly = true;
-
-        $cookieMetadata = $this->getMock('Magento\Framework\Stdlib\Cookie\PublicCookieMetadata');
-        $cookieMetadata->expects($this->once())
-            ->method('setDuration')
-            ->with($lifetime)
-            ->will($this->returnSelf());
-        $cookieMetadata->expects($this->once())
-            ->method('setPath')
-            ->with($path)
-            ->will($this->returnSelf());
-        $cookieMetadata->expects($this->once())
-            ->method('setDomain')
-            ->with($domain)
-            ->will($this->returnSelf());
-        $cookieMetadata->expects($this->once())
-            ->method('setSecure')
-            ->with($secure)
-            ->will($this->returnSelf());
-        $cookieMetadata->expects($this->once())
-            ->method('setHttpOnly')
-            ->with($httpOnly)
-            ->will($this->returnSelf());
-
-        $this->cookieMetadataFactory->expects($this->once())
-            ->method('createPublicCookieMetadata')
-            ->will($this->returnValue($cookieMetadata));
-
-        $this->cookieManager->expects($this->once())
-            ->method('getCookie')
-            ->with($name)
-            ->will($this->returnValue($cookie));
-        $this->cookieManager->expects($this->once())
-            ->method('setPublicCookie')
-            ->with($name, $cookie, $cookieMetadata);
-
-        $this->config->expects($this->once())
-            ->method('getValue')
-            ->with(\Magento\Backend\Model\Auth\Session::XML_PATH_SESSION_LIFETIME)
-            ->will($this->returnValue($lifetime));
-        $this->sessionConfig->expects($this->once())
-            ->method('getCookiePath')
-            ->will($this->returnValue($path));
-        $this->sessionConfig->expects($this->once())
-            ->method('getCookieDomain')
-            ->will($this->returnValue($domain));
-        $this->sessionConfig->expects($this->once())
-            ->method('getCookieSecure')
-            ->will($this->returnValue($secure));
-        $this->sessionConfig->expects($this->once())
-            ->method('getCookieHttpOnly')
-            ->will($this->returnValue($httpOnly));
-
         $this->session->prolong();
-
         $this->assertLessThanOrEqual(time(), $this->session->getUpdatedAt());
     }
 
diff --git a/app/code/Magento/Backend/Test/Unit/Model/Config/SessionLifetime/BackendModelTest.php b/app/code/Magento/Backend/Test/Unit/Model/Config/SessionLifetime/BackendModelTest.php
new file mode 100755
index 0000000000000000000000000000000000000000..a26910a45baade098d5322eb655469f8fd106e8e
--- /dev/null
+++ b/app/code/Magento/Backend/Test/Unit/Model/Config/SessionLifetime/BackendModelTest.php
@@ -0,0 +1,43 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Backend\Test\Unit\Model\Config\SessionLifetime;
+
+use Magento\Backend\Model\Config\SessionLifetime\BackendModel;
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
+
+class BackendModelTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @dataProvider adminSessionLifetimeDataProvider
+     */
+    public function testBeforeSave($value, $errorMessage = null)
+    {
+        /** @var BackendModel $model */
+        $model = (new ObjectManager($this))->getObject('Magento\Backend\Model\Config\SessionLifetime\BackendModel');
+        if ($errorMessage !== null) {
+            $this->setExpectedException('\Magento\Framework\Exception\LocalizedException', $errorMessage);
+        }
+        $model->setValue($value);
+        $model->beforeSave();
+    }
+
+    public function adminSessionLifetimeDataProvider()
+    {
+        return [
+            [
+                BackendModel::MIN_LIFETIME - 1,
+                'Admin session lifetime must be greater than or equal to 60 seconds'
+            ],
+            [
+                BackendModel::MAX_LIFETIME + 1,
+                'Admin session lifetime must be less than or equal to 31536000 seconds (one year)'
+            ],
+            [
+                900
+            ]
+        ];
+    }
+}
diff --git a/app/code/Magento/Backend/etc/adminhtml/system.xml b/app/code/Magento/Backend/etc/adminhtml/system.xml
index f7b9bd917b030a232cc3584adcda2aa9653e785c..65a1872ed4999a765d002a98dd9b31ea73dbf168 100644
--- a/app/code/Magento/Backend/etc/adminhtml/system.xml
+++ b/app/code/Magento/Backend/etc/adminhtml/system.xml
@@ -388,7 +388,8 @@
                 </field>
                 <field id="session_lifetime" translate="label comment" sortOrder="30" showInDefault="1" showInWebsite="0" showInStore="0">
                     <label>Admin Session Lifetime (seconds)</label>
-                    <comment>Values less than 60 are ignored.</comment>
+                    <comment>Please enter at least 60 and at most 31536000 (one year).</comment>
+                    <backend_model>Magento\Backend\Model\Config\SessionLifetime\BackendModel</backend_model>
                     <validate>validate-digits</validate>
                 </field>
             </group>
diff --git a/app/code/Magento/Backend/i18n/en_US.csv b/app/code/Magento/Backend/i18n/en_US.csv
index 0c5586948801fcf220e16302f0d15949d6b68f6e..a704cab6687c3ff62f0f4e239c0edc0669688b74 100644
--- a/app/code/Magento/Backend/i18n/en_US.csv
+++ b/app/code/Magento/Backend/i18n/en_US.csv
@@ -556,7 +556,9 @@ Security,Security
 "Add Secret Key to URLs","Add Secret Key to URLs"
 "Login is Case Sensitive","Login is Case Sensitive"
 "Admin Session Lifetime (seconds)","Admin Session Lifetime (seconds)"
-"Values less than 60 are ignored.","Values less than 60 are ignored."
+"Please enter at least 60 and at most 31536000 (one year).","Please enter at least 60 and at most 31536000 (one year)."
+"Admin session lifetime must be less than or equal to 31536000 seconds (one year)","Admin session lifetime must be less than or equal to 31536000 seconds (one year)"
+"Admin session lifetime must be greater than or equal to 60 seconds","Admin session lifetime must be greater than or equal to 60 seconds"
 Web,Web
 "Url Options","Url Options"
 "Add Store Code to Urls","Add Store Code to Urls"
diff --git a/app/code/Magento/Backend/view/adminhtml/layout/default.xml b/app/code/Magento/Backend/view/adminhtml/layout/default.xml
index 84034331705379819372d2a719652d4279ab92c1..02fe5336a35a9b874c3f4b21d823387c78e3c9a9 100644
--- a/app/code/Magento/Backend/view/adminhtml/layout/default.xml
+++ b/app/code/Magento/Backend/view/adminhtml/layout/default.xml
@@ -8,7 +8,7 @@
 <page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="admin-1column" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
     <head>
         <title>Magento Admin</title>
-        <meta name="viewport" content="width=1024, initial-scale=1"/>
+        <meta name="viewport" content="width=1024"/>
         <link src="requirejs/require.js"/>
         <css src="extjs/resources/css/ext-all.css"/>
         <css src="extjs/resources/css/ytheme-magento.css"/>
diff --git a/app/code/Magento/Bundle/Controller/Adminhtml/Product/Initialization/Helper/Plugin/Bundle.php b/app/code/Magento/Bundle/Controller/Adminhtml/Product/Initialization/Helper/Plugin/Bundle.php
index 796af9fe13f418e5aa9df3979a583ab9f947bc4b..b6641286fd4507b2dd0990cba7ba239f4664c1fa 100644
--- a/app/code/Magento/Bundle/Controller/Adminhtml/Product/Initialization/Helper/Plugin/Bundle.php
+++ b/app/code/Magento/Bundle/Controller/Adminhtml/Product/Initialization/Helper/Plugin/Bundle.php
@@ -130,6 +130,7 @@ class Bundle
             if ((bool)$optionData['delete']) {
                 continue;
             }
+
             $option = $this->optionFactory->create(['data' => $optionData]);
             $option->setSku($product->getSku());
             $option->setOptionId(null);
diff --git a/app/code/Magento/Bundle/Model/ResourceModel/Indexer/Stock.php b/app/code/Magento/Bundle/Model/ResourceModel/Indexer/Stock.php
index dd246101c0f3517c38d042cbc02c05c0ef6e0116..0e26022d1e8a6590377c09e11601183c09ef9d0c 100644
--- a/app/code/Magento/Bundle/Model/ResourceModel/Indexer/Stock.php
+++ b/app/code/Magento/Bundle/Model/ResourceModel/Indexer/Stock.php
@@ -158,20 +158,7 @@ class Stock extends \Magento\CatalogInventory\Model\ResourceModel\Indexer\Stock\
         );
         $this->_addAttributeToSelect($select, 'status', "e.$linkField", 'cs.store_id', $condition);
 
-        if ($this->_isManageStock()) {
-            $statusExpr = $connection->getCheckSql(
-                'cisi.use_config_manage_stock = 0 AND cisi.manage_stock = 0',
-                '1',
-                'cisi.is_in_stock'
-            );
-        } else {
-            $statusExpr = $connection->getCheckSql(
-                'cisi.use_config_manage_stock = 0 AND cisi.manage_stock = 1',
-                'cisi.is_in_stock',
-                '1'
-            );
-        }
-
+        $statusExpr = $this->getStatusExpression($connection);
         $select->columns(
             [
                 'status' => $connection->getLeastSql(
diff --git a/app/code/Magento/BundleImportExport/Model/Import/Product/Type/Bundle.php b/app/code/Magento/BundleImportExport/Model/Import/Product/Type/Bundle.php
index 49e8fa02bad0874e4d6173803f0904bf4162126e..7a6ce6a074a455e409eec6256a5a52cfc7fee8aa 100644
--- a/app/code/Magento/BundleImportExport/Model/Import/Product/Type/Bundle.php
+++ b/app/code/Magento/BundleImportExport/Model/Import/Product/Type/Bundle.php
@@ -344,7 +344,7 @@ class Bundle extends \Magento\CatalogImportExport\Model\Import\Product\Type\Abst
             while ($bunch = $this->_entityModel->getNextBunch()) {
                 foreach ($bunch as $rowNum => $rowData) {
                     $productData = $newSku[$rowData[\Magento\CatalogImportExport\Model\Import\Product::COL_SKU]];
-                    $productIds[] = $productData['entity_id'];
+                    $productIds[] = $productData[$this->getProductEntityLinkField()];
                 }
                 $this->deleteOptionsAndSelections($productIds);
             }
@@ -359,7 +359,7 @@ class Bundle extends \Magento\CatalogImportExport\Model\Import\Product\Type\Abst
                     if ($this->_type != $productData['type_id']) {
                         continue;
                     }
-                    $this->parseSelections($rowData, $productData['entity_id']);
+                    $this->parseSelections($rowData, $productData[$this->getProductEntityLinkField()]);
                 }
                 if (!empty($this->_cachedOptions)) {
                     $this->retrieveProducsByCachedSkus();
diff --git a/app/code/Magento/BundleImportExport/Test/Unit/Model/Import/Product/Type/BundleTest.php b/app/code/Magento/BundleImportExport/Test/Unit/Model/Import/Product/Type/BundleTest.php
index d9c0cf547368a441f7621d6a6168425b15fb87db..8d88f4bcd54b9c5f4625c63723e9e36e9656895f 100644
--- a/app/code/Magento/BundleImportExport/Test/Unit/Model/Import/Product/Type/BundleTest.php
+++ b/app/code/Magento/BundleImportExport/Test/Unit/Model/Import/Product/Type/BundleTest.php
@@ -6,6 +6,12 @@
 
 namespace Magento\BundleImportExport\Test\Unit\Model\Import\Product\Type;
 
+/**
+ * Class BundleTest
+ *
+ * @SuppressWarnings(PHPMD.ExcessiveParameterList)
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ */
 class BundleTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractImportTestCase
 {
     /**
@@ -98,12 +104,18 @@ class BundleTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractIm
             ));
     }
 
+    /**
+     * Set up
+     *
+     * @return void
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+     */
     protected function setUp()
     {
         parent::setUp();
 
         $this->entityModel = $this->getMock(
-            'Magento\CatalogImportExport\Model\Import\Product',
+            \Magento\CatalogImportExport\Model\Import\Product::class,
             [
                 'getErrorAggregator',
                 'getBehavior',
@@ -119,13 +131,13 @@ class BundleTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractIm
         );
         $this->entityModel->method('getErrorAggregator')->willReturn($this->getErrorAggregatorObject());
         $this->connection = $this->getMock(
-            'Magento\Framework\DB\Adapter\Pdo\Mysql',
+            \Magento\Framework\DB\Adapter\Pdo\Mysql::class,
             ['select', 'fetchAll', 'fetchPairs', 'joinLeft', 'insertOnDuplicate', 'delete', 'quoteInto', 'fetchAssoc'],
             [],
             '',
             false
         );
-        $this->select = $this->getMock('Magento\Framework\DB\Select', [], [], '', false);
+        $this->select = $this->getMock(\Magento\Framework\DB\Select::class, [], [], '', false);
         $this->select->expects($this->any())->method('from')->will($this->returnSelf());
         $this->select->expects($this->any())->method('where')->will($this->returnSelf());
         $this->select->expects($this->any())->method('joinLeft')->will($this->returnSelf());
@@ -136,7 +148,7 @@ class BundleTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractIm
         $this->connection->expects($this->any())->method('delete')->willReturnSelf();
         $this->connection->expects($this->any())->method('quoteInto')->willReturn('');
         $this->resource = $this->getMock(
-            'Magento\Framework\App\ResourceConnection',
+            \Magento\Framework\App\ResourceConnection::class,
             ['getConnection', 'getTableName'],
             [],
             '',
@@ -145,14 +157,14 @@ class BundleTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractIm
         $this->resource->expects($this->any())->method('getConnection')->will($this->returnValue($this->connection));
         $this->resource->expects($this->any())->method('getTableName')->will($this->returnValue('tableName'));
         $this->attrSetColFac = $this->getMock(
-            'Magento\Eav\Model\ResourceModel\Entity\Attribute\Set\CollectionFactory',
+            \Magento\Eav\Model\ResourceModel\Entity\Attribute\Set\CollectionFactory::class,
             ['create'],
             [],
             '',
             false
         );
         $this->setCollection = $this->getMock(
-            'Magento\Eav\Model\ResourceModel\Entity\Attribute\Set\Collection',
+            \Magento\Eav\Model\ResourceModel\Entity\Attribute\Set\Collection::class,
             ['setEntityTypeFilter'],
             [],
             '',
@@ -165,14 +177,14 @@ class BundleTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractIm
             ->method('setEntityTypeFilter')
             ->will($this->returnValue([]));
         $this->prodAttrColFac = $this->getMock(
-            'Magento\Catalog\Model\ResourceModel\Product\Attribute\CollectionFactory',
+            \Magento\Catalog\Model\ResourceModel\Product\Attribute\CollectionFactory::class,
             ['create'],
             [],
             '',
             false
         );
         $attrCollection =
-            $this->getMock('\Magento\Catalog\Model\ResourceModel\Product\Attribute\Collection', [], [], '', false);
+            $this->getMock(\Magento\Catalog\Model\ResourceModel\Product\Attribute\Collection::class, [], [], '', false);
         $attrCollection->expects($this->any())->method('addFieldToFilter')->willReturn([]);
         $this->prodAttrColFac->expects($this->any())->method('create')->will($this->returnValue($attrCollection));
         $this->params = [
@@ -181,7 +193,7 @@ class BundleTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractIm
         ];
 
         $this->bundle = $this->objectManagerHelper->getObject(
-            'Magento\BundleImportExport\Model\Import\Product\Type\Bundle',
+            \Magento\BundleImportExport\Model\Import\Product\Type\Bundle::class,
             [
                 'attrSetColFac' => $this->attrSetColFac,
                 'prodAttrColFac' => $this->prodAttrColFac,
@@ -189,6 +201,20 @@ class BundleTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractIm
                 'params' => $this->params
             ]
         );
+
+        $metadataMock = $this->getMock(\Magento\Framework\Model\Entity\EntityMetadata::class, [], [], '', false);
+        $metadataMock->expects($this->any())
+            ->method('getLinkField')
+            ->willReturn('entity_id');
+        $metadataPoolMock = $this->getMock(\Magento\Framework\Model\Entity\MetadataPool::class, [], [], '', false);
+        $metadataPoolMock->expects($this->any())
+            ->method('getMetadata')
+            ->with(\Magento\Catalog\Api\Data\ProductInterface::class)
+            ->willReturn($metadataMock);
+        $reflection = new \ReflectionClass(\Magento\BundleImportExport\Model\Import\Product\Type\Bundle::class);
+        $reflectionProperty = $reflection->getProperty('metadataPool');
+        $reflectionProperty->setAccessible(true);
+        $reflectionProperty->setValue($this->bundle, $metadataPoolMock);
     }
 
     /**
@@ -258,7 +284,6 @@ class BundleTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractIm
         $this->bundle->saveData();
     }
 
-
     /**
      * Data provider for saveData()
      *
@@ -332,7 +357,7 @@ class BundleTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractIm
             ['bundle_values' => 'value1', 'sku' => 'sku', 'name' => 'name']
         ]));
         $this->entityModel->expects($this->any())->method('isRowAllowedToImport')->will($this->returnValue(true));
-        $select = $this->getMock('Magento\Framework\DB\Select', [], [], '', false);
+        $select = $this->getMock(\Magento\Framework\DB\Select::class, [], [], '', false);
         $this->connection->expects($this->any())->method('select')->will($this->returnValue($select));
         $select->expects($this->any())->method('from')->will($this->returnSelf());
         $select->expects($this->any())->method('where')->will($this->returnSelf());
@@ -346,7 +371,7 @@ class BundleTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractIm
     public function testPrepareAttributesWithDefaultValueForSaveInsideCall()
     {
         $bundleMock = $this->getMock(
-            'Magento\BundleImportExport\Model\Import\Product\Type\Bundle',
+            \Magento\BundleImportExport\Model\Import\Product\Type\Bundle::class,
             ['transformBundleCustomAttributes'],
             [],
             '',
diff --git a/app/code/Magento/Catalog/Block/Adminhtml/Category/Tree.php b/app/code/Magento/Catalog/Block/Adminhtml/Category/Tree.php
index 81c63b8fd5fb86cac947c0cd8f5cb100d321b3ae..4361d346a02e3489166af675d717300c696584f1 100644
--- a/app/code/Magento/Catalog/Block/Adminhtml/Category/Tree.php
+++ b/app/code/Magento/Catalog/Block/Adminhtml/Category/Tree.php
@@ -13,7 +13,15 @@ namespace Magento\Catalog\Block\Adminhtml\Category;
 
 use Magento\Catalog\Model\ResourceModel\Category\Collection;
 use Magento\Framework\Data\Tree\Node;
+use Magento\Store\Model\Store;
 
+/**
+ * Class Tree
+ *
+ * @package Magento\Catalog\Block\Adminhtml\Category
+ *
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ */
 class Tree extends \Magento\Catalog\Block\Adminhtml\Category\AbstractCategory
 {
     /**
@@ -76,31 +84,32 @@ class Tree extends \Magento\Catalog\Block\Adminhtml\Category\AbstractCategory
      */
     protected function _prepareLayout()
     {
-        $addUrl = $this->getUrl("*/*/add", ['_current' => true, 'id' => null, '_query' => false]);
-
-        $this->addChild(
-            'add_sub_button',
-            'Magento\Backend\Block\Widget\Button',
-            [
-                'label' => __('Add Subcategory'),
-                'onclick' => "addNew('" . $addUrl . "', false)",
-                'class' => 'add',
-                'id' => 'add_subcategory_button',
-                'style' => $this->canAddSubCategory() ? '' : 'display: none;'
-            ]
-        );
-
-        if ($this->canAddRootCategory()) {
+        $addUrl = $this->getUrl("*/*/add", ['_current' => false, 'id' => null, '_query' => false]);
+        if ($this->getStore()->getId() == Store::DEFAULT_STORE_ID) {
             $this->addChild(
-                'add_root_button',
+                'add_sub_button',
                 'Magento\Backend\Block\Widget\Button',
                 [
-                    'label' => __('Add Root Category'),
-                    'onclick' => "addNew('" . $addUrl . "', true)",
+                    'label' => __('Add Subcategory'),
+                    'onclick' => "addNew('" . $addUrl . "', false)",
                     'class' => 'add',
-                    'id' => 'add_root_category_button'
+                    'id' => 'add_subcategory_button',
+                    'style' => $this->canAddSubCategory() ? '' : 'display: none;'
                 ]
             );
+
+            if ($this->canAddRootCategory()) {
+                $this->addChild(
+                    'add_root_button',
+                    'Magento\Backend\Block\Widget\Button',
+                    [
+                        'label' => __('Add Root Category'),
+                        'onclick' => "addNew('" . $addUrl . "', true)",
+                        'class' => 'add',
+                        'id' => 'add_root_category_button'
+                    ]
+                );
+            }
         }
 
         return parent::_prepareLayout();
diff --git a/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Action/Attribute/Tab/Inventory.php b/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Action/Attribute/Tab/Inventory.php
index 07a86a028ed44584e8370199b770246806e6feea..d3c27a6b3ed1a1c9bbc2b2b1279bc9dac8ebf2c5 100644
--- a/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Action/Attribute/Tab/Inventory.php
+++ b/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Action/Attribute/Tab/Inventory.php
@@ -20,6 +20,11 @@ class Inventory extends \Magento\Backend\Block\Widget implements \Magento\Backen
      */
     protected $stockConfiguration;
 
+    /**
+     * @var array
+     */
+    protected $disabledFields = [];
+
     /**
      * @param \Magento\Backend\Block\Template\Context $context
      * @param \Magento\CatalogInventory\Model\Source\Backorders $backorders
@@ -112,4 +117,14 @@ class Inventory extends \Magento\Backend\Block\Widget implements \Magento\Backen
     {
         return false;
     }
+
+    /**
+     * @param string $fieldName
+     * @return bool
+     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+     */
+    public function isAvailable($fieldName)
+    {
+        return true;
+    }
 }
diff --git a/app/code/Magento/Catalog/Block/Category/Plugin/PriceBoxTags.php b/app/code/Magento/Catalog/Block/Category/Plugin/PriceBoxTags.php
new file mode 100644
index 0000000000000000000000000000000000000000..65c9b3ad624ee6c4ac4119c1c38064ea4943915a
--- /dev/null
+++ b/app/code/Magento/Catalog/Block/Category/Plugin/PriceBoxTags.php
@@ -0,0 +1,77 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Catalog\Block\Category\Plugin;
+
+use Magento\Catalog\Model\Product;
+use Magento\Customer\Model\Session;
+use Magento\Framework\App\ScopeResolverInterface;
+use Magento\Framework\Pricing\PriceCurrencyInterface;
+use Magento\Framework\Pricing\Render\PriceBox;
+use Magento\Framework\Stdlib\DateTime\TimezoneInterface;
+
+class PriceBoxTags
+{
+    /**
+     * @var TimezoneInterface
+     */
+    protected $dateTime;
+
+    /**
+     * @var \Magento\Customer\Model\Session
+     */
+    protected $customerSession;
+
+    /**
+     * @var PriceCurrencyInterface
+     */
+    private $priceCurrency;
+    
+    /**
+     * @var ScopeResolverInterface
+     */
+    private $scopeResolver;
+
+    /**
+     * PriceBoxTags constructor.
+     * @param PriceCurrencyInterface $priceCurrency
+     * @param TimezoneInterface $dateTime
+     * @param ScopeResolverInterface $scopeResolver
+     * @param Session $customerSession
+     */
+    public function __construct(
+        PriceCurrencyInterface $priceCurrency,
+        TimezoneInterface $dateTime,
+        ScopeResolverInterface $scopeResolver,
+        Session $customerSession
+    ) {
+        $this->dateTime = $dateTime;
+        $this->customerSession = $customerSession;
+        $this->priceCurrency = $priceCurrency;
+        $this->scopeResolver = $scopeResolver;
+    }
+
+    /**
+     * @param PriceBox $subject
+     * @param string $result
+     * @return string
+     *
+     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+     */
+    public function afterGetCacheKey(PriceBox $subject, $result)
+    {
+        return implode(
+            '-',
+            [
+                $result,
+                $this->priceCurrency->getCurrencySymbol(),
+                $this->dateTime->scopeDate($this->scopeResolver->getScope()->getId())->format('Ymd'),
+                $this->scopeResolver->getScope()->getId(),
+                $this->customerSession->getCustomerGroupId(),
+            ]
+        );
+    }
+}
diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Category.php b/app/code/Magento/Catalog/Controller/Adminhtml/Category.php
index c710e5f6e716a98ed9fc1d5006ce73324f3e7dd1..e2bb8a5d7bd1515afb2c9dc6ae540e4e938ec242 100644
--- a/app/code/Magento/Catalog/Controller/Adminhtml/Category.php
+++ b/app/code/Magento/Catalog/Controller/Adminhtml/Category.php
@@ -56,4 +56,55 @@ abstract class Category extends \Magento\Backend\App\Action
             ->setStoreId($this->getRequest()->getParam('store'));
         return $category;
     }
+
+    /**
+     * Build response for ajax request
+     *
+     * @param \Magento\Catalog\Model\Category $category
+     * @param \Magento\Backend\Model\View\Result\Page $resultPage
+     *
+     * @return \Magento\Framework\Controller\Result\Json
+     *
+     * @deprecated
+     */
+    protected function ajaxRequestResponse($category, $resultPage)
+    {
+        // prepare breadcrumbs of selected category, if any
+        $breadcrumbsPath = $category->getPath();
+        if (empty($breadcrumbsPath)) {
+            // but if no category, and it is deleted - prepare breadcrumbs from path, saved in session
+            $breadcrumbsPath = $this->_objectManager->get(
+                'Magento\Backend\Model\Auth\Session'
+            )->getDeletedPath(
+                true
+            );
+            if (!empty($breadcrumbsPath)) {
+                $breadcrumbsPath = explode('/', $breadcrumbsPath);
+                // no need to get parent breadcrumbs if deleting category level 1
+                if (count($breadcrumbsPath) <= 1) {
+                    $breadcrumbsPath = '';
+                } else {
+                    array_pop($breadcrumbsPath);
+                    $breadcrumbsPath = implode('/', $breadcrumbsPath);
+                }
+            }
+        }
+
+        $eventResponse = new \Magento\Framework\DataObject([
+            'content' => $resultPage->getLayout()->getUiComponent('category_form')->getFormHtml()
+                . $resultPage->getLayout()->getBlock('category.tree')
+                    ->getBreadcrumbsJavascript($breadcrumbsPath, 'editingCategoryBreadcrumbs'),
+            'messages' => $resultPage->getLayout()->getMessagesBlock()->getGroupedHtml(),
+            'toolbar' => $resultPage->getLayout()->getBlock('page.actions.toolbar')->toHtml()
+        ]);
+        $this->_eventManager->dispatch(
+            'category_prepare_ajax_response',
+            ['response' => $eventResponse, 'controller' => $this]
+        );
+        /** @var \Magento\Framework\Controller\Result\Json $resultJson */
+        $resultJson = $this->_objectManager->get('Magento\Framework\Controller\Result\Json');
+        $resultJson->setHeader('Content-type', 'application/json', true);
+        $resultJson->setData($eventResponse->getData());
+        return $resultJson;
+    }
 }
diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Category/Add.php b/app/code/Magento/Catalog/Controller/Adminhtml/Category/Add.php
index 0ed6aae446f5b3b78d1d19492c79a21b724f93ad..947b2dc2828af734c6573274bc10eef17245ab6f 100644
--- a/app/code/Magento/Catalog/Controller/Adminhtml/Category/Add.php
+++ b/app/code/Magento/Catalog/Controller/Adminhtml/Category/Add.php
@@ -6,14 +6,23 @@
  */
 namespace Magento\Catalog\Controller\Adminhtml\Category;
 
+/**
+ * Class Add Category
+ *
+ * @package Magento\Catalog\Controller\Adminhtml\Category
+ */
 class Add extends \Magento\Catalog\Controller\Adminhtml\Category
 {
     /**
+     * Forward factory for result
+     *
      * @var \Magento\Backend\Model\View\Result\ForwardFactory
      */
     protected $resultForwardFactory;
 
     /**
+     * Add category constructor
+     *
      * @param \Magento\Backend\App\Action\Context $context
      * @param \Magento\Backend\Model\View\Result\ForwardFactory $resultForwardFactory
      */
@@ -32,8 +41,32 @@ class Add extends \Magento\Catalog\Controller\Adminhtml\Category
      */
     public function execute()
     {
-        /** @var \Magento\Backend\Model\View\Result\Forward $resultForward */
-        $resultForward = $this->resultForwardFactory->create();
-        return $resultForward->forward('edit');
+        $parentId = (int)$this->getRequest()->getParam('parent');
+
+        $category = $this->_initCategory(true);
+        if (!$category || !$parentId || $category->getId()) {
+            /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */
+            $resultRedirect = $this->resultRedirectFactory->create();
+            return $resultRedirect->setPath('catalog/*/', ['_current' => true, 'id' => null]);
+        }
+
+        $resultPageFactory = $this->_objectManager->get('Magento\Framework\View\Result\PageFactory');
+        /** @var \Magento\Backend\Model\View\Result\Page $resultPage */
+        $resultPage = $resultPageFactory->create();
+
+        if ($this->getRequest()->getQuery('isAjax')) {
+            return $this->ajaxRequestResponse($category, $resultPage);
+        }
+
+        $resultPage->setActiveMenu('Magento_Catalog::catalog_categories');
+        $resultPage->getConfig()->getTitle()->prepend(__('New Category'));
+        $resultPage->addBreadcrumb(__('Manage Catalog Categories'), __('Manage Categories'));
+
+        $block = $resultPage->getLayout()->getBlock('catalog.wysiwyg.js');
+        if ($block) {
+            $block->setStoreId(0);
+        }
+
+        return $resultPage;
     }
 }
diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Category/Edit.php b/app/code/Magento/Catalog/Controller/Adminhtml/Category/Edit.php
index c3e5f200713940464ca2040e0dabb00e73aa504b..0dcd7b3b257c1f73051c1a33a12971d31c5c5c38 100644
--- a/app/code/Magento/Catalog/Controller/Adminhtml/Category/Edit.php
+++ b/app/code/Magento/Catalog/Controller/Adminhtml/Category/Edit.php
@@ -52,10 +52,9 @@ class Edit extends \Magento\Catalog\Controller\Adminhtml\Category
     public function execute()
     {
         $storeId = (int)$this->getRequest()->getParam('store');
-        $parentId = (int)$this->getRequest()->getParam('parent');
         $categoryId = (int)$this->getRequest()->getParam('id');
 
-        if (!$categoryId && !$parentId) {
+        if (!$categoryId) {
             if ($storeId) {
                 $categoryId = (int)$this->storeManager->getStore($storeId)->getRootCategoryId();
             } else {
@@ -74,7 +73,7 @@ class Edit extends \Magento\Catalog\Controller\Adminhtml\Category
         }
 
         $category = $this->_initCategory(true);
-        if (!$category) {
+        if (!$category || $categoryId != $category->getId() || !$category->getId()) {
             /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */
             $resultRedirect = $this->resultRedirectFactory->create();
             return $resultRedirect->setPath('catalog/*/', ['_current' => true, 'id' => null]);
@@ -90,47 +89,9 @@ class Edit extends \Magento\Catalog\Controller\Adminhtml\Category
 
         /** @var \Magento\Backend\Model\View\Result\Page $resultPage */
         $resultPage = $this->resultPageFactory->create();
-        /**
-         * Build response for ajax request
-         */
-        if ($this->getRequest()->getQuery('isAjax')) {
-            // prepare breadcrumbs of selected category, if any
-            $breadcrumbsPath = $category->getPath();
-            if (empty($breadcrumbsPath)) {
-                // but if no category, and it is deleted - prepare breadcrumbs from path, saved in session
-                $breadcrumbsPath = $this->_objectManager->get(
-                    'Magento\Backend\Model\Auth\Session'
-                )->getDeletedPath(
-                    true
-                );
-                if (!empty($breadcrumbsPath)) {
-                    $breadcrumbsPath = explode('/', $breadcrumbsPath);
-                    // no need to get parent breadcrumbs if deleting category level 1
-                    if (count($breadcrumbsPath) <= 1) {
-                        $breadcrumbsPath = '';
-                    } else {
-                        array_pop($breadcrumbsPath);
-                        $breadcrumbsPath = implode('/', $breadcrumbsPath);
-                    }
-                }
-            }
 
-            $eventResponse = new \Magento\Framework\DataObject([
-                'content' => $resultPage->getLayout()->getUiComponent('category_form')->getFormHtml()
-                    . $resultPage->getLayout()->getBlock('category.tree')
-                        ->getBreadcrumbsJavascript($breadcrumbsPath, 'editingCategoryBreadcrumbs'),
-                'messages' => $resultPage->getLayout()->getMessagesBlock()->getGroupedHtml(),
-                'toolbar' => $resultPage->getLayout()->getBlock('page.actions.toolbar')->toHtml()
-            ]);
-            $this->_eventManager->dispatch(
-                'category_prepare_ajax_response',
-                ['response' => $eventResponse, 'controller' => $this]
-            );
-            /** @var \Magento\Framework\Controller\Result\Json $resultJson */
-            $resultJson = $this->resultJsonFactory->create();
-            $resultJson->setHeader('Content-type', 'application/json', true);
-            $resultJson->setData($eventResponse->getData());
-            return $resultJson;
+        if ($this->getRequest()->getQuery('isAjax')) {
+            return $this->ajaxRequestResponse($category, $resultPage);
         }
 
         $resultPage->setActiveMenu('Magento_Catalog::catalog_categories');
diff --git a/app/code/Magento/Catalog/Controller/Category/View.php b/app/code/Magento/Catalog/Controller/Category/View.php
index b0684d90546f184c3e185c44d8d5e8e711be7f2f..e9266ee0216a5396ca9ef9eff3710fbd406d8c05 100644
--- a/app/code/Magento/Catalog/Controller/Category/View.php
+++ b/app/code/Magento/Catalog/Controller/Category/View.php
@@ -172,13 +172,15 @@ class View extends \Magento\Framework\App\Action\Action
             if ($settings->getPageLayout()) {
                 $page->getConfig()->setPageLayout($settings->getPageLayout());
             }
+
+            $hasChildren = $category->hasChildren();
             if ($category->getIsAnchor()) {
-                $type = $category->hasChildren() ? 'layered' : 'layered_without_children';
+                $type = $hasChildren ? 'layered' : 'layered_without_children';
             } else {
-                $type = $category->hasChildren() ? 'default' : 'default_without_children';
+                $type = $hasChildren ? 'default' : 'default_without_children';
             }
 
-            if (!$category->hasChildren()) {
+            if (!$hasChildren) {
                 // Two levels removed from parent.  Need to add default page type.
                 $parentType = strtok($type, '_');
                 $page->addPageLayoutHandles(['type' => $parentType]);
diff --git a/app/code/Magento/Catalog/Model/Category.php b/app/code/Magento/Catalog/Model/Category.php
index dd89956d3a66d8c531dc82bdb659c3db55305697..4efa1b08969929f59ea63d1dd4595a046af0c216 100644
--- a/app/code/Magento/Catalog/Model/Category.php
+++ b/app/code/Magento/Catalog/Model/Category.php
@@ -1115,7 +1115,10 @@ class Category extends \Magento\Catalog\Model\AbstractModel implements
         $identities = [
             self::CACHE_TAG . '_' . $this->getId(),
         ];
-        if ($this->hasDataChanges() || $this->isDeleted()) {
+        if (!$this->getId() || $this->hasDataChanges()
+            || $this->isDeleted() || $this->dataHasChangedFor(self::KEY_INCLUDE_IN_MENU)
+        ) {
+            $identities[] = self::CACHE_TAG;
             $identities[] = Product::CACHE_PRODUCT_CATEGORY_TAG . '_' . $this->getId();
         }
         return $identities;
diff --git a/app/code/Magento/Catalog/Model/Category/DataProvider.php b/app/code/Magento/Catalog/Model/Category/DataProvider.php
index 479f02796b57cbcfd15070ee3585fd0b3adf3b2c..8fa599af1ce77ed01a652551a81d89aae857245d 100644
--- a/app/code/Magento/Catalog/Model/Category/DataProvider.php
+++ b/app/code/Magento/Catalog/Model/Category/DataProvider.php
@@ -253,7 +253,7 @@ class DataProvider extends \Magento\Ui\DataProvider\AbstractDataProvider
                 $meta[$code]['validation'] = $rules;
             }
 
-            $meta[$code]['scope_label'] = $this->getScopeLabel($attribute);
+            $meta[$code]['scopeLabel'] = $this->getScopeLabel($attribute);
             $meta[$code]['componentType'] = Field::NAME;
         }
 
diff --git a/app/code/Magento/Catalog/Model/Indexer/Category/Product/Plugin/IndexerState.php b/app/code/Magento/Catalog/Model/Indexer/Category/Product/Plugin/IndexerState.php
deleted file mode 100644
index 15a51557e6cb56a3a0a99cb4fe5136ec7c5f8616..0000000000000000000000000000000000000000
--- a/app/code/Magento/Catalog/Model/Indexer/Category/Product/Plugin/IndexerState.php
+++ /dev/null
@@ -1,63 +0,0 @@
-<?php
-/**
- * Plugin for \Magento\Indexer\Model\Indexer\State model
- *
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-
-namespace Magento\Catalog\Model\Indexer\Category\Product\Plugin;
-
-use Magento\Catalog\Model\Indexer\Category\Product;
-use Magento\Catalog\Model\Indexer\Product\Category;
-use Magento\Indexer\Model\Indexer\State;
-
-class IndexerState
-{
-    /**
-     * @var State
-     */
-    protected $state;
-
-    /**
-     * Related indexers IDs
-     *
-     * @var int[]
-     */
-    protected $indexerIds = [
-        Category::INDEXER_ID,
-        Product::INDEXER_ID,
-    ];
-
-    /**
-     * @param State $state
-     */
-    public function __construct(State $state)
-    {
-        $this->state = $state;
-    }
-
-    /**
-     * Synchronize status for indexers
-     *
-     * @param State $state
-     * @return State
-     */
-    public function afterSave(State $state)
-    {
-        if (in_array($state->getIndexerId(), $this->indexerIds)) {
-            $indexerId = $state->getIndexerId() === Product::INDEXER_ID
-                ? Category::INDEXER_ID
-                : Product::INDEXER_ID;
-
-            $relatedIndexerState = $this->state->loadByIndexer($indexerId);
-
-            if ($relatedIndexerState->getStatus() !== $state->getStatus()) {
-                $relatedIndexerState->setData('status', $state->getStatus());
-                $relatedIndexerState->save();
-            }
-        }
-
-        return $state;
-    }
-}
diff --git a/app/code/Magento/Catalog/Model/Layer/Filter/AbstractFilter.php b/app/code/Magento/Catalog/Model/Layer/Filter/AbstractFilter.php
index fdf80681159cce87ab47cb677b5cb34508a556ce..1c4c8533ef2465d4d1520dac8c47aa921c39347f 100644
--- a/app/code/Magento/Catalog/Model/Layer/Filter/AbstractFilter.php
+++ b/app/code/Magento/Catalog/Model/Layer/Filter/AbstractFilter.php
@@ -376,7 +376,7 @@ abstract class AbstractFilter extends \Magento\Framework\DataObject implements F
      */
     protected function getAttributeIsFilterable($attribute)
     {
-        return $attribute->getIsFilterable();
+        return (int)$attribute->getIsFilterable();
     }
 
     /**
diff --git a/app/code/Magento/Catalog/Model/Product/Attribute/Backend/GroupPrice/AbstractGroupPrice.php b/app/code/Magento/Catalog/Model/Product/Attribute/Backend/GroupPrice/AbstractGroupPrice.php
index 13b119e93f5e8f46f60c18c2e0e85cc60182c801..b33f10728a29f9f0527103b908b9abff5fca7e04 100644
--- a/app/code/Magento/Catalog/Model/Product/Attribute/Backend/GroupPrice/AbstractGroupPrice.php
+++ b/app/code/Magento/Catalog/Model/Product/Attribute/Backend/GroupPrice/AbstractGroupPrice.php
@@ -166,7 +166,7 @@ abstract class AbstractGroupPrice extends Price
             if (!empty($priceRow['delete'])) {
                 continue;
             }
-            $compare = join(
+            $compare = implode(
                 '-',
                 array_merge(
                     [$priceRow['website_id'], $priceRow['cust_group']],
@@ -191,7 +191,7 @@ abstract class AbstractGroupPrice extends Price
             if ($origPrices) {
                 foreach ($origPrices as $price) {
                     if ($price['website_id'] == 0) {
-                        $compare = join(
+                        $compare = implode(
                             '-',
                             array_merge(
                                 [$price['website_id'], $price['cust_group']],
@@ -215,7 +215,7 @@ abstract class AbstractGroupPrice extends Price
                 continue;
             }
 
-            $globalCompare = join(
+            $globalCompare = implode(
                 '-',
                 array_merge([0, $priceRow['cust_group']], $this->_getAdditionalUniqueFields($priceRow))
             );
@@ -243,7 +243,7 @@ abstract class AbstractGroupPrice extends Price
         $data = [];
         $price = $this->_catalogProductType->priceFactory($productTypeId);
         foreach ($priceData as $v) {
-            $key = join('-', array_merge([$v['cust_group']], $this->_getAdditionalUniqueFields($v)));
+            $key = implode('-', array_merge([$v['cust_group']], $this->_getAdditionalUniqueFields($v)));
             if ($v['website_id'] == $websiteId) {
                 $data[$key] = $v;
                 $data[$key]['website_price'] = $v['price'];
@@ -316,7 +316,7 @@ abstract class AbstractGroupPrice extends Price
         $isGlobal = $this->getAttribute()->isScopeGlobal() || $websiteId == 0;
 
         $priceRows = $object->getData($this->getAttribute()->getName());
-        if ($priceRows === null) {
+        if (null === $priceRows) {
             return $this;
         }
 
@@ -330,7 +330,7 @@ abstract class AbstractGroupPrice extends Price
         }
         foreach ($origPrices as $data) {
             if ($data['website_id'] > 0 || $data['website_id'] == '0' && $isGlobal) {
-                $key = join(
+                $key = implode(
                     '-',
                     array_merge(
                         [$data['website_id'], $data['cust_group']],
@@ -361,7 +361,7 @@ abstract class AbstractGroupPrice extends Price
                 continue;
             }
 
-            $key = join(
+            $key = implode(
                 '-',
                 array_merge([$data['website_id'], $data['cust_group']], $this->_getAdditionalUniqueFields($data))
             );
diff --git a/app/code/Magento/Catalog/Model/Product/Attribute/Repository.php b/app/code/Magento/Catalog/Model/Product/Attribute/Repository.php
index 2cafca07cbfe0aeb4572dab9013268820a5eef74..5aec262a6911d28fef55ce3eeae92a1472289aa9 100644
--- a/app/code/Magento/Catalog/Model/Product/Attribute/Repository.php
+++ b/app/code/Magento/Catalog/Model/Product/Attribute/Repository.php
@@ -49,6 +49,11 @@ class Repository implements \Magento\Catalog\Api\ProductAttributeRepositoryInter
      */
     protected $searchCriteriaBuilder;
 
+    /**
+     * @var \Magento\Catalog\Api\ProductAttributeOptionManagementInterface
+     */
+    private $optionManagement;
+
     /**
      * @param \Magento\Catalog\Model\ResourceModel\Attribute $attributeResource
      * @param \Magento\Catalog\Helper\Product $productHelper
@@ -57,6 +62,7 @@ class Repository implements \Magento\Catalog\Api\ProductAttributeRepositoryInter
      * @param \Magento\Eav\Model\Config $eavConfig
      * @param \Magento\Eav\Model\Adminhtml\System\Config\Source\Inputtype\ValidatorFactory $validatorFactory
      * @param \Magento\Framework\Api\SearchCriteriaBuilder $searchCriteriaBuilder
+     * @param \Magento\Catalog\Api\ProductAttributeOptionManagementInterface $optionManagement
      */
     public function __construct(
         \Magento\Catalog\Model\ResourceModel\Attribute $attributeResource,
@@ -65,7 +71,8 @@ class Repository implements \Magento\Catalog\Api\ProductAttributeRepositoryInter
         \Magento\Eav\Api\AttributeRepositoryInterface $eavAttributeRepository,
         \Magento\Eav\Model\Config $eavConfig,
         \Magento\Eav\Model\Adminhtml\System\Config\Source\Inputtype\ValidatorFactory $validatorFactory,
-        \Magento\Framework\Api\SearchCriteriaBuilder $searchCriteriaBuilder
+        \Magento\Framework\Api\SearchCriteriaBuilder $searchCriteriaBuilder,
+        \Magento\Catalog\Api\ProductAttributeOptionManagementInterface $optionManagement
     ) {
         $this->attributeResource = $attributeResource;
         $this->productHelper = $productHelper;
@@ -74,6 +81,7 @@ class Repository implements \Magento\Catalog\Api\ProductAttributeRepositoryInter
         $this->eavConfig = $eavConfig;
         $this->inputtypeValidatorFactory = $validatorFactory;
         $this->searchCriteriaBuilder = $searchCriteriaBuilder;
+        $this->optionManagement = $optionManagement;
     }
 
     /**
@@ -171,7 +179,10 @@ class Repository implements \Magento\Catalog\Api\ProductAttributeRepositoryInter
             $attribute->setIsUserDefined(1);
         }
         $this->attributeResource->save($attribute);
-        return $attribute;
+        foreach ($attribute->getOptions() as $option) {
+            $this->optionManagement->add($attribute->getAttributeCode(), $option);
+        }
+        return $this->get($attribute->getAttributeCode());
     }
 
     /**
diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Eav/Attribute.php b/app/code/Magento/Catalog/Model/ResourceModel/Eav/Attribute.php
index cde304b004ac497e35502954291fda86a499533e..76729cdb7458c4869664feaf0b9e7897a932486a 100644
--- a/app/code/Magento/Catalog/Model/ResourceModel/Eav/Attribute.php
+++ b/app/code/Magento/Catalog/Model/ResourceModel/Eav/Attribute.php
@@ -818,4 +818,30 @@ class Attribute extends \Magento\Eav\Model\Entity\Attribute implements
         $this->_eavConfig->clear();
         return parent::afterDelete();
     }
+
+    /**
+     * @inheritdoc
+     */
+    public function __sleep()
+    {
+        return array_diff(
+            parent::__sleep(),
+            ['_indexerEavProcessor', '_productFlatIndexerProcessor', '_productFlatIndexerHelper', 'attrLockValidator']
+        );
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function __wakeup()
+    {
+        parent::__wakeup();
+        $objectManager = \Magento\Framework\App\ObjectManager::getInstance();
+        $this->_indexerEavProcessor = $objectManager->get(\Magento\Catalog\Model\Indexer\Product\Flat\Processor::class);
+        $this->_productFlatIndexerProcessor = $objectManager->get(
+            \Magento\Catalog\Model\Indexer\Product\Eav\Processor::class
+        );
+        $this->_productFlatIndexerHelper = $objectManager->get(\Magento\Catalog\Helper\Product\Flat\Indexer::class);
+        $this->attrLockValidator = $objectManager->get(LockValidatorInterface::class);
+    }
 }
diff --git a/app/code/Magento/Catalog/Test/Unit/Block/Adminhtml/Product/Edit/Action/Attribute/Tab/InventoryTest.php b/app/code/Magento/Catalog/Test/Unit/Block/Adminhtml/Product/Edit/Action/Attribute/Tab/InventoryTest.php
index 9c8ea48b531eb2cd9a5b26c250ef5d9106b32ff1..48ebd822875a4d025d3b6b73c4b8a04381360f37 100644
--- a/app/code/Magento/Catalog/Test/Unit/Block/Adminhtml/Product/Edit/Action/Attribute/Tab/InventoryTest.php
+++ b/app/code/Magento/Catalog/Test/Unit/Block/Adminhtml/Product/Edit/Action/Attribute/Tab/InventoryTest.php
@@ -177,4 +177,14 @@ class InventoryTest extends \PHPUnit_Framework_TestCase
     {
         $this->assertFalse($this->inventory->isHidden());
     }
+
+    /**
+     * Run test isEnabled method
+     *
+     * @return void
+     */
+    public function testIsEnabled()
+    {
+        $this->assertEquals(true, $this->inventory->isAvailable('field'));
+    }
 }
diff --git a/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Category/EditTest.php b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Category/EditTest.php
index 4036ec0d76ede96380822fd1725bbfa6ea29ca6a..bf999146702cf444e2c0abe78337ce4992a2df1d 100644
--- a/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Category/EditTest.php
+++ b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Category/EditTest.php
@@ -284,6 +284,10 @@ class EditTest extends \PHPUnit_Framework_TestCase
             ->with('id', $categoryId)
             ->will($this->returnValue(true));
 
+        $this->categoryMock->expects($this->atLeastOnce())
+            ->method('getId')
+            ->will($this->returnValue($categoryId));
+
         /**
          * @var \Magento\Framework\View\Element\Template
          * |\PHPUnit_Framework_MockObject_MockObject $blockMock
diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Category/Product/Plugin/IndexerStateTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Category/Product/Plugin/IndexerStateTest.php
deleted file mode 100644
index 62b961cd09775542c54a81a1e0f7145f3c056787..0000000000000000000000000000000000000000
--- a/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Category/Product/Plugin/IndexerStateTest.php
+++ /dev/null
@@ -1,49 +0,0 @@
-<?php
-/**
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-namespace Magento\Catalog\Test\Unit\Model\Indexer\Category\Product\Plugin;
-
-class IndexerStateTest extends \PHPUnit_Framework_TestCase
-{
-    public function testAfterSave()
-    {
-        $testableIndex = \Magento\Catalog\Model\Indexer\Product\Category::INDEXER_ID;
-        $changedIndex = \Magento\Catalog\Model\Indexer\Category\Product::INDEXER_ID;
-        $testableStatus = 'testable_status';
-
-        $testableState = $this->getMockBuilder(
-            'Magento\Indexer\Model\Indexer\State'
-        )->setMethods(
-            ['getIndexerId', 'getStatus', '__wakeup']
-        )->disableOriginalConstructor()->getMock();
-
-        $testableState->expects($this->exactly(2))->method('getIndexerId')->will($this->returnValue($testableIndex));
-
-        $testableState->expects($this->exactly(2))->method('getStatus')->will($this->returnValue($testableStatus));
-
-        $state = $this->getMockBuilder(
-            'Magento\Indexer\Model\Indexer\State'
-        )->setMethods(
-            ['setData', 'loadByIndexer', 'save', '__wakeup']
-        )->disableOriginalConstructor()->getMock();
-
-        $state->expects($this->once())->method('loadByIndexer')->with($changedIndex)->will($this->returnSelf());
-
-        $state->expects($this->once())->method('save')->will($this->returnSelf());
-
-        $state->expects(
-            $this->at(1)
-        )->method(
-            'setData'
-        )->with(
-            $this->logicalOr($this->equalTo('status'), $this->equalTo($testableStatus))
-        )->will(
-            $this->returnSelf()
-        );
-
-        $model = new \Magento\Catalog\Model\Indexer\Category\Product\Plugin\IndexerState($state);
-        $this->assertInstanceOf('\Magento\Indexer\Model\Indexer\State', $model->afterSave($testableState));
-    }
-}
diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Product/Attribute/RepositoryTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Product/Attribute/RepositoryTest.php
index 1cf511043804620a61c4c80fb338e0126b160230..c4cc6f48c5607baeed7b157d0f2777c47be4194d 100644
--- a/app/code/Magento/Catalog/Test/Unit/Model/Product/Attribute/RepositoryTest.php
+++ b/app/code/Magento/Catalog/Test/Unit/Model/Product/Attribute/RepositoryTest.php
@@ -63,6 +63,11 @@ class RepositoryTest extends \PHPUnit_Framework_TestCase
      */
     protected $searchResultMock;
 
+    /**
+     * @var \Magento\Eav\Api\AttributeOptionManagementInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $optionManagementMock;
+
     protected function setUp()
     {
         $this->attributeResourceMock =
@@ -99,6 +104,8 @@ class RepositoryTest extends \PHPUnit_Framework_TestCase
                 [],
                 '',
                 false);
+        $this->optionManagementMock =
+            $this->getMock('\Magento\Catalog\Api\ProductAttributeOptionManagementInterface', [], [], '', false);
 
         $this->model = new Repository(
             $this->attributeResourceMock,
@@ -107,7 +114,8 @@ class RepositoryTest extends \PHPUnit_Framework_TestCase
             $this->eavAttributeRepositoryMock,
             $this->eavConfigMock,
             $this->validatorFactoryMock,
-            $this->searchCriteriaBuilderMock
+            $this->searchCriteriaBuilderMock,
+            $this->optionManagementMock
         );
     }
 
diff --git a/app/code/Magento/Catalog/Test/Unit/Pricing/Render/FinalPriceBoxTest.php b/app/code/Magento/Catalog/Test/Unit/Pricing/Render/FinalPriceBoxTest.php
index 8719e6f3d60994d9780a67a70b8e53c60a445c38..43dc002857c6c20f0ea6d362622681ff9e648760 100644
--- a/app/code/Magento/Catalog/Test/Unit/Pricing/Render/FinalPriceBoxTest.php
+++ b/app/code/Magento/Catalog/Test/Unit/Pricing/Render/FinalPriceBoxTest.php
@@ -81,6 +81,9 @@ class FinalPriceBoxTest extends \PHPUnit_Framework_TestCase
             ->method('getBlock')
             ->will($this->returnValue($this->priceBox));
 
+        $cacheState = $this->getMockBuilder(\Magento\Framework\App\Cache\StateInterface::class)
+            ->getMockForAbstractClass();
+
         $scopeConfigMock = $this->getMockForAbstractClass('Magento\Framework\App\Config\ScopeConfigInterface');
         $context = $this->getMock('Magento\Framework\View\Element\Template\Context', [], [], '', false);
         $context->expects($this->any())
@@ -98,6 +101,9 @@ class FinalPriceBoxTest extends \PHPUnit_Framework_TestCase
         $context->expects($this->any())
             ->method('getScopeConfig')
             ->will($this->returnValue($scopeConfigMock));
+        $context->expects($this->any())
+            ->method('getCacheState')
+            ->will($this->returnValue($cacheState));
 
         $this->rendererPool = $this->getMockBuilder('Magento\Framework\Pricing\Render\RendererPool')
             ->disableOriginalConstructor()
diff --git a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/AdvancedPricing.php b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/AdvancedPricing.php
index 6a9379645d3786ee0d1a3ee62da87c5f33a4790c..1418967884a5006ff9e340ec12950bb532d4b867 100644
--- a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/AdvancedPricing.php
+++ b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/AdvancedPricing.php
@@ -74,7 +74,7 @@ class AdvancedPricing extends AbstractModifier
     /**
      * @var string
      */
-    protected $targetName = 'product_form.product_form';
+    protected $scopeName;
 
     /**
      * @var array
@@ -90,6 +90,7 @@ class AdvancedPricing extends AbstractModifier
      * @param ModuleManager $moduleManager
      * @param Data $directoryHelper
      * @param ArrayManager $arrayManager
+     * @param string $scopeName
      * @SuppressWarnings(PHPMD.ExcessiveParameterList)
      */
     public function __construct(
@@ -100,7 +101,8 @@ class AdvancedPricing extends AbstractModifier
         SearchCriteriaBuilder $searchCriteriaBuilder,
         ModuleManager $moduleManager,
         Data $directoryHelper,
-        ArrayManager $arrayManager
+        ArrayManager $arrayManager,
+        $scopeName = ''
     ) {
         $this->locator = $locator;
         $this->storeManager = $storeManager;
@@ -110,6 +112,7 @@ class AdvancedPricing extends AbstractModifier
         $this->moduleManager = $moduleManager;
         $this->directoryHelper = $directoryHelper;
         $this->arrayManager = $arrayManager;
+        $this->scopeName = $scopeName;
     }
 
     /**
@@ -366,7 +369,7 @@ class AdvancedPricing extends AbstractModifier
                 'template' => 'ui/form/components/button/container',
                 'actions' => [
                     [
-                        'targetName' => $this->targetName . '.advanced_pricing_modal',
+                        'targetName' => $this->scopeName . '.advanced_pricing_modal',
                         'actionName' => 'toggleModal',
                     ]
                 ],
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 f50df9c6f365c4bb4d92be1d2558c5e9d7909ffb..7ae19a786104878d3c47704a9684ce86c9ba434a 100644
--- a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Eav.php
+++ b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Eav.php
@@ -292,7 +292,8 @@ class Eav extends AbstractModifier
                 $child['arguments']['data']['config']['disabled'] = true;
             }
             // TODO: getAttributeModel() should not be used when MAGETWO-48284 is complete
-            if (($rules = $this->eavValidationRules->build($this->getAttributeModel($attribute), $child))) {
+            $childData = $child['arguments']['data']['config'];
+            if (($rules = $this->eavValidationRules->build($this->getAttributeModel($attribute), $childData))) {
                 $child['arguments']['data']['config']['validation'] = $rules;
             }
 
diff --git a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Related.php b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Related.php
index 54a899bcad5f0cd1d43ebdd540621f0fedd31c84..f39c5c69a2be72c7467b62b2ef08218b64d9ca3c 100644
--- a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Related.php
+++ b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Related.php
@@ -83,6 +83,11 @@ class Related extends AbstractModifier
      */
     protected $scopeName;
 
+    /**
+     * @var string
+     */
+    protected $scopePrefix;
+
     /**
      * @param LocatorInterface $locator
      * @param UrlInterface $urlBuilder
@@ -92,6 +97,7 @@ class Related extends AbstractModifier
      * @param Status $status
      * @param AttributeSetRepositoryInterface $attributeSetRepository
      * @param string $scopeName
+     * @param string $scopePrefix
      */
     public function __construct(
         LocatorInterface $locator,
@@ -101,7 +107,8 @@ class Related extends AbstractModifier
         ImageHelper $imageHelper,
         Status $status,
         AttributeSetRepositoryInterface $attributeSetRepository,
-        $scopeName = ''
+        $scopeName = '',
+        $scopePrefix = ''
     ) {
         $this->locator = $locator;
         $this->urlBuilder = $urlBuilder;
@@ -111,6 +118,7 @@ class Related extends AbstractModifier
         $this->status = $status;
         $this->attributeSetRepository = $attributeSetRepository;
         $this->scopeName = $scopeName;
+        $this->scopePrefix = $scopePrefix;
     }
 
     /**
@@ -123,9 +131,9 @@ class Related extends AbstractModifier
             [
                 static::GROUP_RELATED => [
                     'children' => [
-                        static::DATA_SCOPE_RELATED => $this->getRelatedFieldset(),
-                        static::DATA_SCOPE_UPSELL => $this->getUpSellFieldset(),
-                        static::DATA_SCOPE_CROSSSELL => $this->getCrossSellFieldset(),
+                        $this->scopePrefix . static::DATA_SCOPE_RELATED => $this->getRelatedFieldset(),
+                        $this->scopePrefix . static::DATA_SCOPE_UPSELL => $this->getUpSellFieldset(),
+                        $this->scopePrefix . static::DATA_SCOPE_CROSSSELL => $this->getCrossSellFieldset(),
                     ],
                     'arguments' => [
                         'data' => [
@@ -228,13 +236,13 @@ class Related extends AbstractModifier
                 'button_set' => $this->getButtonSet(
                     $content,
                     __('Add Related Products'),
-                    static::DATA_SCOPE_RELATED
+                    $this->scopePrefix . static::DATA_SCOPE_RELATED
                 ),
                 'modal' => $this->getGenericModal(
                     __('Add Related Products'),
-                    static::DATA_SCOPE_RELATED
+                    $this->scopePrefix . static::DATA_SCOPE_RELATED
                 ),
-                static::DATA_SCOPE_RELATED => $this->getGrid(static::DATA_SCOPE_RELATED),
+                static::DATA_SCOPE_RELATED => $this->getGrid($this->scopePrefix . static::DATA_SCOPE_RELATED),
             ],
             'arguments' => [
                 'data' => [
@@ -268,13 +276,13 @@ class Related extends AbstractModifier
                 'button_set' => $this->getButtonSet(
                     $content,
                     __('Add Up-Sell Products'),
-                    static::DATA_SCOPE_UPSELL
+                    $this->scopePrefix . static::DATA_SCOPE_UPSELL
                 ),
                 'modal' => $this->getGenericModal(
                     __('Add Up-Sell Products'),
-                    static::DATA_SCOPE_UPSELL
+                    $this->scopePrefix . static::DATA_SCOPE_UPSELL
                 ),
-                static::DATA_SCOPE_UPSELL => $this->getGrid(static::DATA_SCOPE_UPSELL),
+                static::DATA_SCOPE_UPSELL => $this->getGrid($this->scopePrefix . static::DATA_SCOPE_UPSELL),
             ],
             'arguments' => [
                 'data' => [
@@ -308,13 +316,13 @@ class Related extends AbstractModifier
                 'button_set' => $this->getButtonSet(
                     $content,
                     __('Add Cross-Sell Products'),
-                    static::DATA_SCOPE_CROSSSELL
+                    $this->scopePrefix . static::DATA_SCOPE_CROSSSELL
                 ),
                 'modal' => $this->getGenericModal(
                     __('Add Cross-Sell Products'),
-                    static::DATA_SCOPE_CROSSSELL
+                    $this->scopePrefix . static::DATA_SCOPE_CROSSSELL
                 ),
-                static::DATA_SCOPE_CROSSSELL => $this->getGrid(static::DATA_SCOPE_CROSSSELL),
+                static::DATA_SCOPE_CROSSSELL => $this->getGrid($this->scopePrefix . static::DATA_SCOPE_CROSSSELL),
             ],
             'arguments' => [
                 'data' => [
diff --git a/app/code/Magento/Catalog/etc/adminhtml/di.xml b/app/code/Magento/Catalog/etc/adminhtml/di.xml
index 14fba919ecda7b025a0c33add77da31650136934..4d69ba4c3eb1d03c43de4a999be139e2571c49db 100644
--- a/app/code/Magento/Catalog/etc/adminhtml/di.xml
+++ b/app/code/Magento/Catalog/etc/adminhtml/di.xml
@@ -154,4 +154,9 @@
             <argument name="scopeName" xsi:type="string">product_form.product_form</argument>
         </arguments>
     </type>
+    <type name="Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\AdvancedPricing">
+        <arguments>
+            <argument name="scopeName" xsi:type="string">product_form.product_form</argument>
+        </arguments>
+    </type>
 </config>
diff --git a/app/code/Magento/Catalog/etc/di.xml b/app/code/Magento/Catalog/etc/di.xml
index 83821bcb37b6ecd07626ff3d103170a267419749..e67b6d67bf3e8365c5051230b7176106620a9cde 100644
--- a/app/code/Magento/Catalog/etc/di.xml
+++ b/app/code/Magento/Catalog/etc/di.xml
@@ -46,17 +46,9 @@
     <type name="Magento\Customer\Model\ResourceModel\Visitor">
         <plugin name="catalogLog" type="Magento\Catalog\Model\Plugin\Log" />
     </type>
-    <type name="Magento\Indexer\Model\Indexer\State">
-        <plugin name="setStatusForIndexer" type="Magento\Catalog\Model\Indexer\Category\Product\Plugin\IndexerState" />
-    </type>
     <type name="Magento\Framework\Mview\View\StateInterface">
         <plugin name="setStatusForMview" type="Magento\Catalog\Model\Indexer\Category\Product\Plugin\MviewState" />
     </type>
-    <type name="Magento\Catalog\Model\Indexer\Category\Product\Plugin\IndexerState">
-        <arguments>
-            <argument name="state" xsi:type="object" shared="false">Magento\Indexer\Model\Indexer\State</argument>
-        </arguments>
-    </type>
     <type name="Magento\Catalog\Model\Indexer\Category\Product\Plugin\MviewState">
         <arguments>
             <argument name="state" xsi:type="object" shared="false">Magento\Framework\Mview\View\StateInterface</argument>
diff --git a/app/code/Magento/Catalog/etc/frontend/di.xml b/app/code/Magento/Catalog/etc/frontend/di.xml
index 07a5986dd17080ec208389ecb552ecc3b0b57b94..d9e46fb2517aede84bd5cf6eb9063619f7977cf0 100644
--- a/app/code/Magento/Catalog/etc/frontend/di.xml
+++ b/app/code/Magento/Catalog/etc/frontend/di.xml
@@ -60,4 +60,7 @@
             </argument>
         </arguments>
     </type>
+    <type name="\Magento\Framework\Pricing\Render\PriceBox">
+        <plugin name="catalog_price_box_key" type="Magento\Catalog\Block\Category\Plugin\PriceBoxTags" />
+    </type>
 </config>
diff --git a/app/code/Magento/Catalog/etc/indexer.xml b/app/code/Magento/Catalog/etc/indexer.xml
index 62b4930a6b92900b7368326e74357d4d68328e9c..d9f6e3fc7bd2190d373f8db592241f21cfff890c 100644
--- a/app/code/Magento/Catalog/etc/indexer.xml
+++ b/app/code/Magento/Catalog/etc/indexer.xml
@@ -14,11 +14,11 @@
         <title translate="true">Category Flat Data</title>
         <description translate="true">Reorganize EAV category structure to flat structure</description>
     </indexer>
-    <indexer id="catalog_category_product" view_id="catalog_category_product" class="Magento\Catalog\Model\Indexer\Category\Product">
+    <indexer id="catalog_category_product" view_id="catalog_category_product" class="Magento\Catalog\Model\Indexer\Category\Product" shared_index="category_product">
         <title translate="true">Category Products</title>
         <description translate="true">Indexed category/products association</description>
     </indexer>
-    <indexer id="catalog_product_category" view_id="catalog_product_category" class="Magento\Catalog\Model\Indexer\Product\Category">
+    <indexer id="catalog_product_category" view_id="catalog_product_category" class="Magento\Catalog\Model\Indexer\Product\Category" shared_index="category_product">
         <title translate="true">Product Categories</title>
         <description translate="true">Indexed product/categories association</description>
     </indexer>
diff --git a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_category_add.xml b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_category_add.xml
new file mode 100644
index 0000000000000000000000000000000000000000..734cd7ce50580e978384053dc382ece965e1cca5
--- /dev/null
+++ b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_category_add.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0"?>
+<!--
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+-->
+<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="admin-2columns-left" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
+    <update handle="styles"/>
+    <head>
+        <css src="jquery/fileUploader/css/jquery.fileupload-ui.css"/>
+        <link src="Magento_Catalog::js/edit-tree.js"/>
+    </head>
+    <update handle="editor"/>
+    <body>
+        <referenceContainer name="left" htmlTag="div" />
+        <referenceContainer name="left">
+            <block class="Magento\Catalog\Block\Adminhtml\Category\Tree" name="category.tree" template="catalog/category/tree.phtml"/>
+        </referenceContainer>
+        <referenceContainer name="content">
+            <uiComponent name="category_form"/>
+            <block class="Magento\Catalog\Block\Adminhtml\Category\Edit" name="category.edit" template="Magento_Catalog::catalog/category/edit.phtml" />
+        </referenceContainer>
+        <referenceContainer name="js">
+            <block class="Magento\Framework\View\Element\Template" template="Magento_Catalog::catalog/wysiwyg/js.phtml" name="catalog.wysiwyg.js"/>
+        </referenceContainer>
+        <referenceBlock name="head.components">
+            <block class="Magento\Framework\View\Element\Js\Components" name="catalog_category_page_head_components" template="Magento_Catalog::js/components.phtml"/>
+        </referenceBlock>
+    </body>
+</page>
diff --git a/app/code/Magento/CatalogImportExport/Model/Export/Product.php b/app/code/Magento/CatalogImportExport/Model/Export/Product.php
index 90f8640d493a8211ce4ad303024db85f93e0b171..0fbda9d526f0b8d35155a0070a31bd38950c28bb 100644
--- a/app/code/Magento/CatalogImportExport/Model/Export/Product.php
+++ b/app/code/Magento/CatalogImportExport/Model/Export/Product.php
@@ -315,6 +315,13 @@ class Product extends \Magento\ImportExport\Model\Export\Entity\AbstractEntity
      */
     protected $metadataPool;
 
+    /**
+     * Product entity link field
+     *
+     * @var string
+     */
+    private $productEntityLinkField;
+
     /**
      * @param \Magento\Framework\Stdlib\DateTime\TimezoneInterface $localeDate
      * @param \Magento\Eav\Model\Config $config
@@ -332,7 +339,6 @@ class Product extends \Magento\ImportExport\Model\Export\Entity\AbstractEntity
      * @param Product\Type\Factory $_typeFactory
      * @param \Magento\Catalog\Model\Product\LinkTypeProvider $linkTypeProvider
      * @param \Magento\CatalogImportExport\Model\Export\RowCustomizerInterface $rowCustomizer
-     * @param \Magento\Framework\Model\Entity\MetadataPool $metadataPool
      * @SuppressWarnings(PHPMD.ExcessiveParameterList)
      */
     public function __construct(
@@ -351,8 +357,7 @@ class Product extends \Magento\ImportExport\Model\Export\Entity\AbstractEntity
         \Magento\Catalog\Model\ResourceModel\Product\Attribute\CollectionFactory $attributeColFactory,
         \Magento\CatalogImportExport\Model\Export\Product\Type\Factory $_typeFactory,
         \Magento\Catalog\Model\Product\LinkTypeProvider $linkTypeProvider,
-        \Magento\CatalogImportExport\Model\Export\RowCustomizerInterface $rowCustomizer,
-        \Magento\Framework\Model\Entity\MetadataPool $metadataPool
+        \Magento\CatalogImportExport\Model\Export\RowCustomizerInterface $rowCustomizer
     ) {
         $this->_entityCollectionFactory = $collectionFactory;
         $this->_exportConfig = $exportConfig;
@@ -367,7 +372,6 @@ class Product extends \Magento\ImportExport\Model\Export\Entity\AbstractEntity
         $this->_typeFactory = $_typeFactory;
         $this->_linkTypeProvider = $linkTypeProvider;
         $this->rowCustomizer = $rowCustomizer;
-        $this->metadataPool = $metadataPool;
 
         parent::__construct($localeDate, $config, $resource, $storeManager);
 
@@ -486,13 +490,10 @@ class Product extends \Magento\ImportExport\Model\Export\Entity\AbstractEntity
         if (empty($productIds)) {
             return [];
         }
-        $linkField = $this->metadataPool
-            ->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class)
-            ->getLinkField();
         $select = $this->_connection->select()->from(
             ['mgvte' => $this->_resourceModel->getTableName('catalog_product_entity_media_gallery_value_to_entity')],
             [
-                'mgvte.' . $linkField,
+                "mgvte.{$this->getProductEntityLinkField()}",
                 'mgvte.value_id'
             ]
         )->joinLeft(
@@ -511,14 +512,14 @@ class Product extends \Magento\ImportExport\Model\Export\Entity\AbstractEntity
                 'mgv.disabled'
             ]
         )->where(
-            'mgvte.' . $linkField . ' IN(?)',
+            "mgvte.{$this->getProductEntityLinkField()} IN (?)",
             $productIds
         );
 
         $rowMediaGallery = [];
         $stmt = $this->_connection->query($select);
         while ($mediaRow = $stmt->fetch()) {
-            $rowMediaGallery[$mediaRow[$linkField]][] = [
+            $rowMediaGallery[$mediaRow[$this->getProductEntityLinkField()]][] = [
                 '_media_attribute_id' => $mediaRow['attribute_id'],
                 '_media_image' => $mediaRow['filename'],
                 '_media_label' => $mediaRow['label'],
@@ -875,6 +876,7 @@ class Product extends \Magento\ImportExport\Model\Export\Entity\AbstractEntity
              */
             foreach ($collection as $itemId => $item) {
                 $additionalAttributes = [];
+                $productLinkId = $item->getData($this->getProductEntityLinkField());
                 foreach ($this->_getExportAttrCodes() as $code) {
                     $attrValue = $item->getData($code);
                     if (!$this->isValidAttributeValue($code, $attrValue)) {
@@ -911,11 +913,11 @@ class Product extends \Magento\ImportExport\Model\Export\Entity\AbstractEntity
                         }
                     } else {
                         $this->collectMultiselectValues($item, $code, $storeId);
-                        if (!empty($this->collectedMultiselectsData[$storeId][$itemId][$code])) {
+                        if (!empty($this->collectedMultiselectsData[$storeId][$productLinkId][$code])) {
                             $additionalAttributes[$code] = $fieldName .
                                 ImportProduct::PAIR_NAME_VALUE_SEPARATOR . implode(
                                     ImportProduct::PSEUDO_MULTI_LINE_SEPARATOR,
-                                    $this->collectedMultiselectsData[$storeId][$itemId][$code]
+                                    $this->collectedMultiselectsData[$storeId][$productLinkId][$code]
                                 );
                         }
                     }
@@ -937,6 +939,7 @@ class Product extends \Magento\ImportExport\Model\Export\Entity\AbstractEntity
                 $data[$itemId][$storeId][self::COL_SKU] = $item->getSku();
                 $data[$itemId][$storeId]['store_id'] = $storeId;
                 $data[$itemId][$storeId]['product_id'] = $itemId;
+                $data[$itemId][$storeId]['product_link_id'] = $productLinkId;
             }
             $collection->clear();
         }
@@ -959,6 +962,7 @@ class Product extends \Magento\ImportExport\Model\Export\Entity\AbstractEntity
         $collection->addCategoryIds()->addWebsiteNamesToResult();
         /** @var \Magento\Catalog\Model\Product $item */
         foreach ($collection as $item) {
+            $productLinkIds[] = $item->getData($this->getProductEntityLinkField());
             $productIds[] = $item->getId();
             $rowWebsites[$item->getId()] = array_intersect(
                 array_keys($this->_websiteIdToCode),
@@ -976,10 +980,10 @@ class Product extends \Magento\ImportExport\Model\Export\Entity\AbstractEntity
 
         $data['rowWebsites'] = $rowWebsites;
         $data['rowCategories'] = $rowCategories;
-        $data['mediaGalery'] = $this->getMediaGallery($productIds);
-        $data['linksRows'] = $this->prepareLinks($productIds);
+        $data['mediaGalery'] = $this->getMediaGallery($productLinkIds);
+        $data['linksRows'] = $this->prepareLinks($productLinkIds);
 
-        $data['customOptionsData'] = $this->getCustomOptionsData($productIds);
+        $data['customOptionsData'] = $this->getCustomOptionsData($productLinkIds);
 
         return $data;
     }
@@ -991,7 +995,8 @@ class Product extends \Magento\ImportExport\Model\Export\Entity\AbstractEntity
      */
     protected function hasMultiselectData($item, $storeId)
     {
-        return !empty($this->collectedMultiselectsData[$storeId][$item->getId()]);
+        $linkId = $item->getData($this->getProductEntityLinkField());
+        return !empty($this->collectedMultiselectsData[$storeId][$linkId]);
     }
 
     /**
@@ -1008,10 +1013,11 @@ class Product extends \Magento\ImportExport\Model\Export\Entity\AbstractEntity
             $this->_attributeValues[$attrCode],
             array_flip($optionIds)
         );
-        if (!(isset($this->collectedMultiselectsData[Store::DEFAULT_STORE_ID][$item->getId()][$attrCode])
-            && $this->collectedMultiselectsData[Store::DEFAULT_STORE_ID][$item->getId()][$attrCode] == $options)
+        $linkId = $item->getData($this->getProductEntityLinkField());
+        if (!(isset($this->collectedMultiselectsData[Store::DEFAULT_STORE_ID][$linkId][$attrCode])
+            && $this->collectedMultiselectsData[Store::DEFAULT_STORE_ID][$linkId][$attrCode] == $options)
         ) {
-            $this->collectedMultiselectsData[$storeId][$item->getId()][$attrCode] = $options;
+            $this->collectedMultiselectsData[$storeId][$linkId][$attrCode] = $options;
         }
 
         return $this;
@@ -1042,15 +1048,18 @@ class Product extends \Magento\ImportExport\Model\Export\Entity\AbstractEntity
      * @return array
      * @SuppressWarnings(PHPMD.CyclomaticComplexity)
      * @SuppressWarnings(PHPMD.NPathComplexity)
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
      */
     protected function addMultirowData($dataRow, $multiRawData)
     {
         $result = [];
         $productId = $dataRow['product_id'];
+        $productLinkId = $dataRow['product_link_id'];
         $storeId = $dataRow['store_id'];
         $sku = $dataRow[self::COL_SKU];
 
         unset($dataRow['product_id']);
+        unset($dataRow['product_link_id']);
         unset($dataRow['store_id']);
         unset($dataRow[self::COL_SKU]);
 
@@ -1066,11 +1075,11 @@ class Product extends \Magento\ImportExport\Model\Export\Entity\AbstractEntity
                     implode(Import::DEFAULT_GLOBAL_MULTI_VALUE_SEPARATOR, $websiteCodes);
                 $multiRawData['rowWebsites'][$productId] = [];
             }
-            if (!empty($multiRawData['mediaGalery'][$productId])) {
+            if (!empty($multiRawData['mediaGalery'][$productLinkId])) {
                 $additionalImages = [];
                 $additionalImageLabels = [];
                 $additionalImageIsDisabled = [];
-                foreach ($multiRawData['mediaGalery'][$productId] as $mediaItem) {
+                foreach ($multiRawData['mediaGalery'][$productLinkId] as $mediaItem) {
                     $additionalImages[] = $mediaItem['_media_image'];
                     $additionalImageLabels[] = $mediaItem['_media_label'];
 
@@ -1084,14 +1093,14 @@ class Product extends \Magento\ImportExport\Model\Export\Entity\AbstractEntity
                     implode(Import::DEFAULT_GLOBAL_MULTI_VALUE_SEPARATOR, $additionalImageLabels);
                 $dataRow['hide_from_product_page'] =
                     implode(Import::DEFAULT_GLOBAL_MULTI_VALUE_SEPARATOR, $additionalImageIsDisabled);
-                $multiRawData['mediaGalery'][$productId] = [];
+                $multiRawData['mediaGalery'][$productLinkId] = [];
             }
             foreach ($this->_linkTypeProvider->getLinkTypes() as $linkTypeName => $linkId) {
-                if (!empty($multiRawData['linksRows'][$productId][$linkId])) {
+                if (!empty($multiRawData['linksRows'][$productLinkId][$linkId])) {
                     $colPrefix = $linkTypeName . '_';
 
                     $associations = [];
-                    foreach ($multiRawData['linksRows'][$productId][$linkId] as $linkData) {
+                    foreach ($multiRawData['linksRows'][$productLinkId][$linkId] as $linkData) {
                         if ($linkData['default_qty'] !== null) {
                             $skuItem = $linkData['sku'] . ImportProduct::PAIR_NAME_VALUE_SEPARATOR .
                                 $linkData['default_qty'];
@@ -1100,7 +1109,7 @@ class Product extends \Magento\ImportExport\Model\Export\Entity\AbstractEntity
                         }
                         $associations[$skuItem] = $linkData['position'];
                     }
-                    $multiRawData['linksRows'][$productId][$linkId] = [];
+                    $multiRawData['linksRows'][$productLinkId][$linkId] = [];
                     asort($associations);
                     $dataRow[$colPrefix . 'skus'] =
                         implode(Import::DEFAULT_GLOBAL_MULTI_VALUE_SEPARATOR, array_keys($associations));
@@ -1121,9 +1130,9 @@ class Product extends \Magento\ImportExport\Model\Export\Entity\AbstractEntity
             }
         }
 
-        if (!empty($multiRawData['customOptionsData'][$productId][$storeId])) {
-            $customOptionsRows = $multiRawData['customOptionsData'][$productId][$storeId];
-            $multiRawData['customOptionsData'][$productId][$storeId] = [];
+        if (!empty($multiRawData['customOptionsData'][$productLinkId][$storeId])) {
+            $customOptionsRows = $multiRawData['customOptionsData'][$productLinkId][$storeId];
+            $multiRawData['customOptionsData'][$productLinkId][$storeId] = [];
             $customOptions = implode(ImportProduct::PSEUDO_MULTI_LINE_SEPARATOR, $customOptionsRows);
 
             $dataRow = array_merge($dataRow, ['custom_options' => $customOptions]);
@@ -1325,4 +1334,33 @@ class Product extends \Magento\ImportExport\Model\Export\Entity\AbstractEntity
         }
         return $this;
     }
+
+    /**
+     * Get product metadata pool
+     *
+     * @return \Magento\Framework\Model\Entity\MetadataPool
+     */
+    private function getMetadataPool()
+    {
+        if (!$this->metadataPool) {
+            $this->metadataPool = \Magento\Framework\App\ObjectManager::getInstance()
+                ->get(\Magento\Framework\Model\Entity\MetadataPool::class);
+        }
+        return $this->metadataPool;
+    }
+
+    /**
+     * Get product entity link field
+     *
+     * @return string
+     */
+    protected function getProductEntityLinkField()
+    {
+        if (!$this->productEntityLinkField) {
+            $this->productEntityLinkField = $this->getMetadataPool()
+                ->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class)
+                ->getLinkField();
+        }
+        return $this->productEntityLinkField;
+    }
 }
diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product.php b/app/code/Magento/CatalogImportExport/Model/Import/Product.php
index 6ce20ca28a736080c6442f5eb938a6ad080108fc..140c4f3596ae58cddece531f1bbc5ee7d7410153 100644
--- a/app/code/Magento/CatalogImportExport/Model/Import/Product.php
+++ b/app/code/Magento/CatalogImportExport/Model/Import/Product.php
@@ -184,11 +184,6 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
      */
     protected $productEntityTableName;
 
-    /**
-     * @var string
-     */
-    protected $productEntityLinkField;
-
     /**
      * Attributes with index (not label) value.
      *
@@ -612,9 +607,18 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
     protected $rowNumbers = [];
 
     /**
-     * @var \Magento\Framework\Model\Entity\MetadataPool
+     * Product entity link field
+     *
+     * @var string
      */
-    protected $metadataPool;
+    private $productEntityLinkField;
+
+    /**
+     * Product entity identifier field
+     *
+     * @var string
+     */
+    private $productEntityIdentifierField;
 
     /**
      * @param \Magento\Framework\Json\Helper\Data $jsonHelper
@@ -651,7 +655,6 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
      * @param ObjectRelationProcessor $objectRelationProcessor
      * @param TransactionManagerInterface $transactionManager
      * @param Product\TaxClassProcessor $taxClassProcessor
-     * @param \Magento\Framework\Model\Entity\MetadataPool $metadataPool
      * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
      * @param array $data
      * @throws \Magento\Framework\Exception\LocalizedException
@@ -693,7 +696,6 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
         ObjectRelationProcessor $objectRelationProcessor,
         TransactionManagerInterface $transactionManager,
         Product\TaxClassProcessor $taxClassProcessor,
-        \Magento\Framework\Model\Entity\MetadataPool $metadataPool,
         \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
         \Magento\Catalog\Model\Product\Url $productUrl,
         array $data = []
@@ -723,7 +725,6 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
         $this->objectRelationProcessor = $objectRelationProcessor;
         $this->transactionManager = $transactionManager;
         $this->taxClassProcessor = $taxClassProcessor;
-        $this->metadataPool = $metadataPool;
         $this->scopeConfig = $scopeConfig;
         $this->productUrl = $productUrl;
         parent::__construct(
@@ -859,23 +860,31 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
         $productEntityTable = $this->_resourceFactory->create()->getEntityTable();
 
         while ($bunch = $this->_dataSourceModel->getNextBunch()) {
-            $idToDelete = [];
+            $idsToDelete = [];
 
             foreach ($bunch as $rowNum => $rowData) {
                 if ($this->validateRow($rowData, $rowNum) && self::SCOPE_DEFAULT == $this->getRowScope($rowData)) {
-                    $idToDelete[] = $this->_oldSku[$rowData[self::COL_SKU]]['entity_id'];
+                    $idsToDelete[] = $this->_oldSku[$rowData[self::COL_SKU]]['entity_id'];
                 }
             }
-            if ($idToDelete) {
-                $this->countItemsDeleted += count($idToDelete);
+            if ($idsToDelete) {
+                $this->countItemsDeleted += count($idsToDelete);
                 $this->transactionManager->start($this->_connection);
                 try {
                     $this->objectRelationProcessor->delete(
                         $this->transactionManager,
                         $this->_connection,
                         $productEntityTable,
-                        $this->_connection->quoteInto('entity_id IN (?)', $idToDelete),
-                        ['entity_id' => $idToDelete]
+                        $this->_connection->quoteInto('entity_id IN (?)', $idsToDelete),
+                        ['entity_id' => $idsToDelete]
+                    );
+                    $this->_eventManager->dispatch(
+                        'catalog_product_import_bunch_delete_commit_before',
+                        [
+                            'adapter' => $this,
+                            'bunch' => $bunch,
+                            'ids_to_delete' => $idsToDelete
+                        ]
                     );
                     $this->transactionManager->commit();
                 } catch (\Exception $e) {
@@ -1094,7 +1103,7 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
                 $sku = $rowData[self::COL_SKU];
 
                 foreach ($this->_linkNameToId as $linkName => $linkId) {
-                    $productId = $this->skuProcessor->getNewSku($sku)['entity_id'];
+                    $productId = $this->skuProcessor->getNewSku($sku)[$this->getProductEntityLinkField()];
                     $productIds[] = $productId;
                     if (isset($rowData[$linkName . 'sku'])) {
                         $linkSkus = explode($this->getMultipleValueSeparator(), $rowData[$linkName . 'sku']);
@@ -1181,7 +1190,6 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
      */
     protected function _saveProductAttributes(array $attributesData)
     {
-        $metadata = $this->metadataPool->getMetadata(ProductInterface::class);
         foreach ($attributesData as $tableName => $skuData) {
             $tableData = [];
             foreach ($skuData as $sku => $attributes) {
@@ -1189,14 +1197,13 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
                     $this->_connection->select()
                         ->from($this->getResource()->getTable('catalog_product_entity'))
                         ->where('sku = ?', $sku)
-                        ->columns($metadata->getLinkField())
+                        ->columns($this->getProductEntityLinkField())
                 );
-                    //$this->skuProcessor->getNewSku($sku)[$metadata->getLinkField()];
 
                 foreach ($attributes as $attributeId => $storeValues) {
                     foreach ($storeValues as $storeId => $storeValue) {
                         $tableData[] = [
-                            $metadata->getLinkField() => $linkId,
+                            $this->getProductEntityLinkField() => $linkId,
                             'attribute_id' => $attributeId,
                             'store_id' => $storeId,
                             'value' => $storeValue,
@@ -1269,23 +1276,39 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
         if ($entityRowsIn) {
             $this->_connection->insertMultiple($entityTable, $entityRowsIn);
 
-            $newProducts = $this->_connection->fetchPairs(
-                $this->_connection->select()->from(
-                    $entityTable,
-                    ['sku', 'entity_id']
-                )->where(
-                    'sku IN (?)',
-                    array_keys($entityRowsIn)
-                )
+            $select = $this->_connection->select()->from(
+                $entityTable,
+                $this->getNewSkuFieldsForSelect()
+            )->where(
+                'sku IN (?)',
+                array_keys($entityRowsIn)
             );
-            foreach ($newProducts as $sku => $newId) {
-                // fill up entity_id for new products
-                $this->skuProcessor->setNewSkuData($sku, 'entity_id', $newId);
+            $newProducts = $this->_connection->fetchAll($select);
+            foreach ($newProducts as $data) {
+                $sku = $data['sku'];
+                unset($data['sku']);
+                foreach ($data as $key => $value) {
+                    $this->skuProcessor->setNewSkuData($sku, $key, $value);
+                }
             }
         }
         return $this;
     }
 
+    /**
+     * Get new SKU fields for select
+     *
+     * @return array
+     */
+    private function getNewSkuFieldsForSelect()
+    {
+        $fields = ['sku', $this->getProductEntityLinkField()];
+        if ($this->getProductEntityLinkField() != $this->getProductIdentifierField()) {
+            $fields[] = $this->getProductIdentifierField();
+        }
+        return $fields;
+    }
+
     /**
      * Init media gallery resources
      * @return void
@@ -1301,9 +1324,6 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
             $this->mediaGalleryEntityToValueTableName = $this->getResource()->getTable(
                 'catalog_product_entity_media_gallery_value_to_entity'
             );
-            $this->productEntityLinkField = $this->metadataPool
-                ->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class)
-                ->getLinkField();
         }
     }
 
@@ -1328,10 +1348,10 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
         )->joinInner(
             ['mgvte' => $this->mediaGalleryEntityToValueTableName],
             '(mg.value_id = mgvte.value_id)',
-            [$this->productEntityLinkField => 'mgvte.' . $this->productEntityLinkField]
+            [$this->getProductEntityLinkField() => 'mgvte.' . $this->getProductEntityLinkField()]
         )->joinInner(
             ['pe' => $this->productEntityTableName],
-            "(mgvte.{$this->productEntityLinkField} = pe.{$this->productEntityLinkField})",
+            "(mgvte.{$this->getProductEntityLinkField()} = pe.{$this->getProductEntityLinkField()})",
             ['sku' => 'pe.sku']
         )->where(
             'pe.sku IN (?)',
@@ -1431,7 +1451,8 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
                     // existing row
                     $entityRowsUp[] = [
                         'updated_at' => (new \DateTime())->format(DateTime::DATETIME_PHP_FORMAT),
-                        'entity_id' => $this->_oldSku[$rowSku]['entity_id'],
+                        $this->getProductEntityLinkField()
+                            => $this->_oldSku[$rowSku][$this->getProductEntityLinkField()],
                     ];
                 } else {
                     if (!$productLimit || $productsQty < $productLimit) {
@@ -1732,18 +1753,18 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
             $delProductId = [];
 
             foreach ($tierPriceData as $delSku => $tierPriceRows) {
-                $productId = $this->skuProcessor->getNewSku($delSku)['entity_id'];
+                $productId = $this->skuProcessor->getNewSku($delSku)[$this->getProductEntityLinkField()];
                 $delProductId[] = $productId;
 
                 foreach ($tierPriceRows as $row) {
-                    $row['entity_id'] = $productId;
+                    $row[$this->getProductEntityLinkField()] = $productId;
                     $tierPriceIn[] = $row;
                 }
             }
             if (Import::BEHAVIOR_APPEND != $this->getBehavior()) {
                 $this->_connection->delete(
                     $tableName,
-                    $this->_connection->quoteInto('entity_id IN (?)', $delProductId)
+                    $this->_connection->quoteInto("{$this->getProductEntityLinkField()} IN (?)", $delProductId)
                 );
             }
             if ($tierPriceIn) {
@@ -1840,7 +1861,7 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
         $multiInsertData = [];
         $valueToProductId = [];
         foreach ($mediaGalleryData as $productSku => $mediaGalleryRows) {
-            $productId = $this->skuProcessor->getNewSku($productSku)['entity_id'];
+            $productId = $this->skuProcessor->getNewSku($productSku)[$this->getProductEntityLinkField()];
             $productIds[] = $productId;
             $insertedGalleryImgs = [];
             foreach ($mediaGalleryRows as $insertValue) {
@@ -1875,7 +1896,8 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
                 foreach ($newMediaValues as $value_id => $values) {
                     if ($values['value'] == $insertValue['value']) {
                         $insertValue['value_id'] = $value_id;
-                        $insertValue['entity_id'] = array_shift($valueToProductId[$values['value']]);
+                        $insertValue[$this->getProductEntityLinkField()]
+                            = array_shift($valueToProductId[$values['value']]);
                         unset($newMediaValues[$value_id]);
                         break;
                     }
@@ -1884,7 +1906,7 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
                     $valueArr = [
                         'value_id' => $insertValue['value_id'],
                         'store_id' => \Magento\Store\Model\Store::DEFAULT_STORE_ID,
-                        'entity_id' => $insertValue['entity_id'],
+                        $this->getProductEntityLinkField() => $insertValue[$this->getProductEntityLinkField()],
                         'label' => $insertValue['label'],
                         'position' => $insertValue['position'],
                         'disabled' => $insertValue['disabled'],
@@ -1892,7 +1914,7 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
                     $multiInsertData[] = $valueArr;
                     $dataForSkinnyTable[] = [
                         'value_id' => $insertValue['value_id'],
-                        'entity_id' => $insertValue['entity_id'],
+                        $this->getProductEntityLinkField() => $insertValue[$this->getProductEntityLinkField()],
                     ];
                 }
             }
@@ -1901,7 +1923,7 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
             $this->_connection->insertOnDuplicate(
                 $this->mediaGalleryValueTableName,
                 $multiInsertData,
-                ['value_id', 'store_id', 'entity_id', 'label', 'position', 'disabled']
+                ['value_id', 'store_id', $this->getProductEntityLinkField(), 'label', 'position', 'disabled']
             );
             $this->_connection->insertOnDuplicate(
                 $this->mediaGalleryEntityToValueTableName,
@@ -2189,12 +2211,7 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
             if (isset($this->_productTypeModels[$this->_oldSku[$sku]['type_id']])) {
                 $this->skuProcessor->addNewSku(
                     $sku,
-                    [
-                        'entity_id' => $this->_oldSku[$sku]['entity_id'],
-                        'type_id' => $this->_oldSku[$sku]['type_id'],
-                        'attr_set_id' => $this->_oldSku[$sku]['attr_set_id'],
-                        'attr_set_code' => $this->_attrSetIdToName[$this->_oldSku[$sku]['attr_set_id']],
-                    ]
+                    $this->prepareNewSkuData($sku)
                 );
             } else {
                 $this->addRowError(ValidatorInterface::ERROR_TYPE_UNSUPPORTED, $rowNum);
@@ -2216,6 +2233,7 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
                 $this->skuProcessor->addNewSku(
                     $sku,
                     [
+                        'row_id' => null,
                         'entity_id' => null,
                         'type_id' => $rowData[self::COL_TYPE],
                         'attr_set_id' => $this->_attrSetNameToId[$rowData[self::COL_ATTR_SET]],
@@ -2268,6 +2286,24 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
         return !$this->getErrorAggregator()->isRowInvalid($rowNum);
     }
 
+    /**
+     * Prepare new SKU data
+     *
+     * @param string $sku
+     * @return array
+     */
+    private function prepareNewSkuData($sku)
+    {
+        $data = [];
+        foreach ($this->_oldSku[$sku] as $key => $value) {
+            $data[$key] = $value;
+        }
+
+        $data['attr_set_code'] = $this->_attrSetIdToName[$this->_oldSku[$sku]['attr_set_id']];
+
+        return $data;
+    }
+
     /**
      * Parse attributes names and values string to array.
      *
@@ -2444,4 +2480,34 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
         }
         return $this->_resource;
     }
+
+    /**
+     * Get product entity link field
+     *
+     * @return string
+     */
+    private function getProductEntityLinkField()
+    {
+        if (!$this->productEntityLinkField) {
+            $this->productEntityLinkField = $this->getMetadataPool()
+                ->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class)
+                ->getLinkField();
+        }
+        return $this->productEntityLinkField;
+    }
+
+    /**
+     * Get product entity identifier field
+     *
+     * @return string
+     */
+    private function getProductIdentifierField()
+    {
+        if (!$this->productEntityIdentifierField) {
+            $this->productEntityIdentifierField = $this->getMetadataPool()
+                ->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class)
+                ->getIdentifierField();
+        }
+        return $this->productEntityIdentifierField;
+    }
 }
diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product/Option.php b/app/code/Magento/CatalogImportExport/Model/Import/Product/Option.php
index 8d6310d3a182527add7d0c3e5ba80db4f337afef..48dca0d9a6270d8eb3b0f684d3df658e30a0171d 100644
--- a/app/code/Magento/CatalogImportExport/Model/Import/Product/Option.php
+++ b/app/code/Magento/CatalogImportExport/Model/Import/Product/Option.php
@@ -11,6 +11,7 @@ namespace Magento\CatalogImportExport\Model\Import\Product;
 use Magento\CatalogImportExport\Model\Import\Product;
 use Magento\Framework\App\ResourceConnection;
 use Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingErrorAggregatorInterface;
+use Magento\Catalog\Api\Data\ProductInterface;
 
 /**
  * Entity class which provide possibility to import product custom options
@@ -309,6 +310,20 @@ class Option extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
      */
     protected $dateTime;
 
+    /**
+     * Product entity link field
+     *
+     * @var string
+     */
+    private $productEntityLinkField;
+
+    /**
+     * Product entity identifier field
+     *
+     * @var string
+     */
+    private $productEntityIdentifierField;
+
     /**
      * @param \Magento\ImportExport\Model\ResourceModel\Import\Data $importData
      * @param ResourceConnection $resource
@@ -368,6 +383,13 @@ class Option extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
             $this->_isPriceGlobal = $this->_catalogData->isPriceGlobal();
         }
 
+        /**
+         * TODO: Make metadataPool a direct constructor dependency, and eliminate its setter & getter
+         */
+        if (isset($data['metadata_pool'])) {
+            $this->metadataPool = $data['metadata_pool'];
+        }
+
         $this->errorAggregator = $errorAggregator;
 
         $this->_initSourceEntities($data)->_initTables($data)->_initStores($data);
@@ -1222,8 +1244,11 @@ class Option extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
     {
         if (!$this->_productsSkuToId || !empty($this->_newOptionsNewData)) {
             $columns = ['entity_id', 'sku'];
+            if ($this->getProductEntityLinkField() != $this->getProductIdentifierField()) {
+                $columns[] = $this->getProductEntityLinkField();
+            }
             foreach ($this->_productModel->getProductEntitiesInfo($columns) as $product) {
-                $this->_productsSkuToId[$product['sku']] = $product['entity_id'];
+                $this->_productsSkuToId[$product['sku']] = $product[$this->getProductEntityLinkField()];
             }
         }
 
@@ -1459,7 +1484,7 @@ class Option extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
     protected function _getProductData(array $rowData, $productId)
     {
         $productData = [
-            'entity_id' => $productId,
+            $this->getProductEntityLinkField() => $productId,
             'has_options' => 1,
             'required_options' => 0,
             'updated_at' => $this->dateTime->date(null, null, false)->format('Y-m-d H:i:s'),
@@ -1825,4 +1850,34 @@ class Option extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
         $this->_productsSkuToId = null;
         return $this;
     }
+
+    /**
+     * Get product entity link field
+     *
+     * @return string
+     */
+    private function getProductEntityLinkField()
+    {
+        if (!$this->productEntityLinkField) {
+            $this->productEntityLinkField = $this->getMetadataPool()
+                ->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class)
+                ->getLinkField();
+        }
+        return $this->productEntityLinkField;
+    }
+
+    /**
+     * Get product entity identifier field
+     *
+     * @return string
+     */
+    private function getProductIdentifierField()
+    {
+        if (!$this->productEntityIdentifierField) {
+            $this->productEntityIdentifierField = $this->getMetadataPool()
+                ->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class)
+                ->getIdentifierField();
+        }
+        return $this->productEntityIdentifierField;
+    }
 }
diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product/SkuProcessor.php b/app/code/Magento/CatalogImportExport/Model/Import/Product/SkuProcessor.php
index c83089fc43e3973e407a53a45e1f7fbcdcdbb81f..6d5fa576871d2403c4ab55f095b6cdad96fe584c 100644
--- a/app/code/Magento/CatalogImportExport/Model/Import/Product/SkuProcessor.php
+++ b/app/code/Magento/CatalogImportExport/Model/Import/Product/SkuProcessor.php
@@ -36,11 +36,33 @@ class SkuProcessor
      */
     protected $productTypeModels;
 
+    /**
+     * Product metadata pool
+     *
+     * @var \Magento\Framework\Model\Entity\MetadataPool
+     */
+    private $metadataPool;
+
+    /**
+     * Product entity link field
+     *
+     * @var string
+     */
+    private $productEntityLinkField;
+
+    /**
+     * Product entity identifier field
+     *
+     * @var string
+     */
+    private $productEntityIdentifierField;
+
     /**
      * @param \Magento\Catalog\Model\ProductFactory $productFactory
      */
-    public function __construct(\Magento\Catalog\Model\ProductFactory $productFactory)
-    {
+    public function __construct(
+        \Magento\Catalog\Model\ProductFactory $productFactory
+    ) {
         $this->productFactory = $productFactory;
     }
 
@@ -125,6 +147,9 @@ class SkuProcessor
     {
         $oldSkus = [];
         $columns = ['entity_id', 'type_id', 'attribute_set_id', 'sku'];
+        if ($this->getProductEntityLinkField() != $this->getProductIdentifierField()) {
+            $columns[] = $this->getProductEntityLinkField();
+        }
         foreach ($this->productFactory->create()->getProductEntitiesInfo($columns) as $info) {
             $typeId = $info['type_id'];
             $sku = $info['sku'];
@@ -133,8 +158,53 @@ class SkuProcessor
                 'attr_set_id' => $info['attribute_set_id'],
                 'entity_id' => $info['entity_id'],
                 'supported_type' => isset($this->productTypeModels[$typeId]),
+                $this->getProductEntityLinkField() => $info[$this->getProductEntityLinkField()],
             ];
         }
         return $oldSkus;
     }
+
+    /**
+     * Get product metadata pool
+     *
+     * @return \Magento\Framework\Model\Entity\MetadataPool
+     */
+    private function getMetadataPool()
+    {
+        if (!$this->metadataPool) {
+            $this->metadataPool = \Magento\Framework\App\ObjectManager::getInstance()
+                ->get(\Magento\Framework\Model\Entity\MetadataPool::class);
+        }
+        return $this->metadataPool;
+    }
+
+    /**
+     * Get product entity link field
+     *
+     * @return string
+     */
+    private function getProductEntityLinkField()
+    {
+        if (!$this->productEntityLinkField) {
+            $this->productEntityLinkField = $this->getMetadataPool()
+                ->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class)
+                ->getLinkField();
+        }
+        return $this->productEntityLinkField;
+    }
+
+    /**
+     * Get product entity identifier field
+     *
+     * @return string
+     */
+    private function getProductIdentifierField()
+    {
+        if (!$this->productEntityIdentifierField) {
+            $this->productEntityIdentifierField = $this->getMetadataPool()
+                ->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class)
+                ->getIdentifierField();
+        }
+        return $this->productEntityIdentifierField;
+    }
 }
diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product/Type/AbstractType.php b/app/code/Magento/CatalogImportExport/Model/Import/Product/Type/AbstractType.php
index 3107396c561adcd618b52ce8ac4af37e0ab388bd..4e04bf6a257276ece0614f2305c103ebe205607c 100644
--- a/app/code/Magento/CatalogImportExport/Model/Import/Product/Type/AbstractType.php
+++ b/app/code/Magento/CatalogImportExport/Model/Import/Product/Type/AbstractType.php
@@ -13,6 +13,7 @@ use Magento\CatalogImportExport\Model\Import\Product;
  * Import entity abstract product type model
  *
  * @SuppressWarnings(PHPMD.TooManyFields)
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  */
 abstract class AbstractType
 {
@@ -126,6 +127,20 @@ abstract class AbstractType
      */
     protected $connection;
 
+    /**
+     * Product metadata pool
+     *
+     * @var \Magento\Framework\Model\Entity\MetadataPool
+     */
+    protected $metadataPool;
+
+    /**
+     * Product entity link field
+     *
+     * @var string
+     */
+    private $productEntityLinkField;
+
     /**
      * @param \Magento\Eav\Model\ResourceModel\Entity\Attribute\Set\CollectionFactory $attrSetColFac
      * @param \Magento\Catalog\Model\ResourceModel\Product\Attribute\CollectionFactory $prodAttrColFac
@@ -523,4 +538,33 @@ abstract class AbstractType
     {
         return $this;
     }
+
+    /**
+     * Get product metadata pool
+     *
+     * @return \Magento\Framework\Model\Entity\MetadataPool
+     */
+    protected function getMetadataPool()
+    {
+        if (!$this->metadataPool) {
+            $this->metadataPool = \Magento\Framework\App\ObjectManager::getInstance()
+                ->get('Magento\Framework\Model\Entity\MetadataPool');
+        }
+        return $this->metadataPool;
+    }
+
+    /**
+     * Get product entity link field
+     *
+     * @return string
+     */
+    protected function getProductEntityLinkField()
+    {
+        if (!$this->productEntityLinkField) {
+            $this->productEntityLinkField = $this->getMetadataPool()
+                ->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class)
+                ->getLinkField();
+        }
+        return $this->productEntityLinkField;
+    }
 }
diff --git a/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/Product/SkuProcessorTest.php b/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/Product/SkuProcessorTest.php
index 12061e38ebed7e2d55bbbc716438bf3058d84c2c..7e0bcd9a305d85b4122f3848a38aaf93d78d4800 100644
--- a/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/Product/SkuProcessorTest.php
+++ b/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/Product/SkuProcessorTest.php
@@ -21,18 +21,12 @@ class SkuProcessorTest extends \PHPUnit_Framework_TestCase
 
     public function setUp()
     {
-        $this->productFactory = $this->getMock(
-            '\Magento\Catalog\Model\ProductFactory',
-            [],
-            [],
-            '',
-            false
-        );
+        $this->productFactory = $this->getMock(\Magento\Catalog\Model\ProductFactory::class, [], [], '', false);
         $this->skuProcessor = $this->getMock(
-            'Magento\CatalogImportExport\Model\Import\Product\SkuProcessor',
+            \Magento\CatalogImportExport\Model\Import\Product\SkuProcessor::class,
             ['_getSkus'],
             [
-                $this->productFactory
+                $this->productFactory,
             ],
             ''
         );
diff --git a/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/Product/Type/OptionTest.php b/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/Product/Type/OptionTest.php
index 2ad915d577af21f2177bc4aef1db62fe54e80e48..eb822e38b014d5f0ca342c2d72826911dc40faaa 100644
--- a/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/Product/Type/OptionTest.php
+++ b/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/Product/Type/OptionTest.php
@@ -45,21 +45,21 @@ class OptionTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractIm
      *
      * @var \Magento\CatalogImportExport\Model\Import\Product\Option
      */
-    protected $_model;
+    protected $model;
 
     /**
      * Test model mock
      *
      * @var \Magento\CatalogImportExport\Model\Import\Product\Option
      */
-    protected $_modelMock;
+    protected $modelMock;
 
     /**
      * Parent product entity
      *
      * @var \Magento\CatalogImportExport\Model\Import\Product
      */
-    protected $_productEntity;
+    protected $productEntity;
 
     /**
      * Array of expected (after import) option titles
@@ -208,6 +208,11 @@ class OptionTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractIm
      */
     protected $errorAggregator;
 
+    /**
+     * @var \Magento\Framework\Model\Entity\MetadataPool
+     */
+    protected $metadataPoolMock;
+
     /**
      * Init entity adapter model
      */
@@ -228,28 +233,43 @@ class OptionTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractIm
             $doubleOptions = true;
         }
 
-        $catalogDataMock = $this->getMock('Magento\Catalog\Helper\Data', ['__construct'], [], '', false);
+        $catalogDataMock = $this->getMock(\Magento\Catalog\Helper\Data::class, ['__construct'], [], '', false);
 
-        $scopeConfig = $this->getMock('Magento\Framework\App\Config\ScopeConfigInterface');
+        $scopeConfig = $this->getMock(\Magento\Framework\App\Config\ScopeConfigInterface::class);
 
-        $timezoneInterface = $this->getMock('Magento\Framework\Stdlib\DateTime\TimezoneInterface');
+        $timezoneInterface = $this->getMock(\Magento\Framework\Stdlib\DateTime\TimezoneInterface::class);
         $date = new \DateTime();
         $timezoneInterface->expects($this->any())->method('date')->willReturn($date);
+        $this->metadataPoolMock = $this->getMock(
+            \Magento\Framework\Model\Entity\MetadataPool::class,
+            [],
+            [],
+            '',
+            false
+        );
+        $entityMetadataMock = $this->getMock(\Magento\Framework\Model\Entity\EntityMetadata::class, [], [], '', false);
+        $this->metadataPoolMock->expects($this->any())
+            ->method('getMetadata')
+            ->with(\Magento\Catalog\Api\Data\ProductInterface::class)
+            ->willReturn($entityMetadataMock);
+        $entityMetadataMock->expects($this->any())
+            ->method('getLinkField')
+            ->willReturn('entity_id');
         $modelClassArgs = [
-            $this->getMock('Magento\ImportExport\Model\ResourceModel\Import\Data', [], [], '', false),
-            $this->getMock('Magento\Framework\App\ResourceConnection', [], [], '', false),
-            $this->getMock('Magento\ImportExport\Model\ResourceModel\Helper', [], [], '', false),
-            $this->getMock('Magento\Store\Model\StoreManagerInterface', [], [], '', false),
-            $this->getMock('Magento\Catalog\Model\ProductFactory', [], [], '', false),
+            $this->getMock(\Magento\ImportExport\Model\ResourceModel\Import\Data::class, [], [], '', false),
+            $this->getMock(\Magento\Framework\App\ResourceConnection::class, [], [], '', false),
+            $this->getMock(\Magento\ImportExport\Model\ResourceModel\Helper::class, [], [], '', false),
+            $this->getMock(\Magento\Store\Model\StoreManagerInterface::class, [], [], '', false),
+            $this->getMock(\Magento\Catalog\Model\ProductFactory::class, [], [], '', false),
             $this->getMock(
-                'Magento\Catalog\Model\ResourceModel\Product\Option\CollectionFactory',
+                \Magento\Catalog\Model\ResourceModel\Product\Option\CollectionFactory::class,
                 [],
                 [],
                 '',
                 false
             ),
             $this->getMock(
-                'Magento\ImportExport\Model\ResourceModel\CollectionByPagesIteratorFactory',
+                \Magento\ImportExport\Model\ResourceModel\CollectionByPagesIteratorFactory::class,
                 [],
                 [],
                 '',
@@ -259,7 +279,7 @@ class OptionTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractIm
             $scopeConfig,
             $timezoneInterface,
             $this->getMock(
-                'Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingErrorAggregatorInterface',
+                \Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingErrorAggregatorInterface::class,
                 [],
                 [],
                 '',
@@ -268,15 +288,18 @@ class OptionTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractIm
             $this->_getModelDependencies($addExpectations, $deleteBehavior, $doubleOptions)
         ];
 
-        $modelClassName = '\Magento\CatalogImportExport\Model\Import\Product\Option';
+        $modelClassName = \Magento\CatalogImportExport\Model\Import\Product\Option::class;
         $class = new \ReflectionClass($modelClassName);
-        $this->_model = $class->newInstanceArgs($modelClassArgs);
+        $this->model = $class->newInstanceArgs($modelClassArgs);
         // Create model mock with rewritten _getMultiRowFormat method to support test data with the old format.
-        $this->_modelMock = $this->
-            getMockBuilder($modelClassName)->
-            setConstructorArgs($modelClassArgs)->
-            setMethods(['_getMultiRowFormat'])->
-            getMock();
+        $this->modelMock = $this->getMockBuilder($modelClassName)
+            ->setConstructorArgs($modelClassArgs)
+            ->setMethods(['_getMultiRowFormat'])
+            ->getMock();
+        $reflection = new \ReflectionClass(\Magento\CatalogImportExport\Model\Import\Product\Option::class);
+        $reflectionProperty = $reflection->getProperty('metadataPool');
+        $reflectionProperty->setAccessible(true);
+        $reflectionProperty->setValue($this->modelMock, $this->metadataPoolMock);
     }
 
     /**
@@ -284,12 +307,12 @@ class OptionTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractIm
      */
     protected function tearDown()
     {
-        unset($this->_model);
-        unset($this->_productEntity);
+        unset($this->model);
+        unset($this->productEntity);
     }
 
     /**
-     * Create mocks for all $this->_model dependencies
+     * Create mocks for all $this->model dependencies
      *
      * @param bool $addExpectations
      * @param bool $deleteBehavior
@@ -343,7 +366,8 @@ class OptionTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractIm
             'tables' => $this->_tables,
             'resource_helper' => $resourceHelper,
             'is_price_global' => true,
-            'stores' => $this->_testStores
+            'stores' => $this->_testStores,
+            'metadata_pool' => $this->metadataPoolMock
         ];
         $sourceData = $this->_getSourceDataMocks($addExpectations, $doubleOptions);
 
@@ -390,14 +414,18 @@ class OptionTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractIm
             }
         }
 
-        $this->_productEntity = $this->getMock(
-            'Magento\CatalogImportExport\Model\Import\Product',
+        $this->productEntity = $this->getMock(
+            \Magento\CatalogImportExport\Model\Import\Product::class,
             ['getErrorAggregator'],
             [],
             '',
             false
         );
-        $this->_productEntity->method('getErrorAggregator')->willReturn($this->getErrorAggregatorObject());
+        $this->productEntity->method('getErrorAggregator')->willReturn($this->getErrorAggregatorObject());
+        $reflection = new \ReflectionClass(\Magento\CatalogImportExport\Model\Import\Product::class);
+        $reflectionProperty = $reflection->getProperty('metadataPool');
+        $reflectionProperty->setAccessible(true);
+        $reflectionProperty->setValue($this->productEntity, $this->metadataPoolMock);
 
         $productModelMock = $this->getMock('stdClass', ['getProductEntitiesInfo']);
         $productModelMock->expects(
@@ -409,18 +437,18 @@ class OptionTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractIm
         );
 
         $fetchStrategy = $this->getMockForAbstractClass(
-            'Magento\Framework\Data\Collection\Db\FetchStrategyInterface',
+            \Magento\Framework\Data\Collection\Db\FetchStrategyInterface::class,
             ['fetchAll']
         );
-        $logger = $this->getMock('Psr\Log\LoggerInterface');
-        $entityFactory = $this->getMock('Magento\Framework\Data\Collection\EntityFactory', [], [], '', false);
+        $logger = $this->getMock(\Psr\Log\LoggerInterface::class);
+        $entityFactory = $this->getMock(\Magento\Framework\Data\Collection\EntityFactory::class, [], [], '', false);
 
-        $optionCollection = $this->getMockBuilder('Magento\Framework\Data\Collection\AbstractDb')
+        $optionCollection = $this->getMockBuilder(\Magento\Framework\Data\Collection\AbstractDb::class)
             ->setConstructorArgs([$entityFactory, $logger, $fetchStrategy])
             ->setMethods(['reset', 'addProductToFilter', 'getSelect', 'getNewEmptyItem'])
             ->getMockForAbstractClass();
 
-        $select = $this->getMock('Magento\Framework\DB\Select', ['join', 'where'], [], '', false);
+        $select = $this->getMock(\Magento\Framework\DB\Select::class, ['join', 'where'], [], '', false);
         $select->expects($this->any())->method('join')->will($this->returnSelf());
         $select->expects($this->any())->method('where')->will($this->returnSelf());
 
@@ -458,7 +486,7 @@ class OptionTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractIm
         $data = [
             'data_source_model' => $dataSourceModel,
             'product_model' => $productModelMock,
-            'product_entity' => $this->_productEntity,
+            'product_entity' => $this->productEntity,
             'option_collection' => $optionCollection,
             'collection_by_pages_iterator' => $collectionIterator,
             'page_size' => $this->_iteratorPageSize
@@ -491,7 +519,7 @@ class OptionTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractIm
      */
     public function getNewOptionMock()
     {
-        return $this->getMock('Magento\Catalog\Model\Product\Option', ['__wakeup'], [], '', false);
+        return $this->getMock(\Magento\Catalog\Model\Product\Option::class, ['__wakeup'], [], '', false);
     }
 
     /**
@@ -591,7 +619,7 @@ class OptionTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractIm
      */
     public function testGetEntityTypeCode()
     {
-        $this->assertEquals('product_options', $this->_model->getEntityTypeCode());
+        $this->assertEquals('product_options', $this->model->getEntityTypeCode());
     }
 
     /**
@@ -607,7 +635,7 @@ class OptionTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractIm
      */
     public function testImportDataAppendBehavior()
     {
-        $this->_model->importData();
+        $this->model->importData();
     }
 
     /**
@@ -616,8 +644,8 @@ class OptionTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractIm
      */
     public function testImportDataDeleteBehavior()
     {
-        $this->_model->setParameters(['behavior' => \Magento\ImportExport\Model\Import::BEHAVIOR_DELETE]);
-        $this->_model->importData();
+        $this->model->setParameters(['behavior' => \Magento\ImportExport\Model\Import::BEHAVIOR_DELETE]);
+        $this->model->importData();
     }
 
     /**
@@ -669,7 +697,7 @@ class OptionTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractIm
      */
     private function _bypassModelMethodGetMultiRowFormat($rowData)
     {
-        $this->_modelMock->expects($this->any())
+        $this->modelMock->expects($this->any())
                         ->method('_getMultiRowFormat')
                         ->will($this->returnValue([$rowData]));
     }
@@ -683,7 +711,7 @@ class OptionTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractIm
     {
         $rowData = include __DIR__ . '/_files/row_data_no_custom_option.php';
         $this->_bypassModelMethodGetMultiRowFormat($rowData);
-        $this->assertFalse($this->_modelMock->validateRow($rowData, 0));
+        $this->assertFalse($this->modelMock->validateRow($rowData, 0));
     }
 
     /**
@@ -707,11 +735,11 @@ class OptionTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractIm
     {
         $this->_bypassModelMethodGetMultiRowFormat($rowData);
         if (empty($errors)) {
-            $this->assertTrue($this->_modelMock->validateRow($rowData, 0));
+            $this->assertTrue($this->modelMock->validateRow($rowData, 0));
         } else {
-            $this->assertFalse($this->_modelMock->validateRow($rowData, 0));
+            $this->assertFalse($this->modelMock->validateRow($rowData, 0));
         }
-        $resultErrors = $this->_productEntity->getErrorAggregator()->getRowsGroupedByErrorCode([], [], false);
+        $resultErrors = $this->productEntity->getErrorAggregator()->getRowsGroupedByErrorCode([], [], false);
         $this->assertEquals($errors, $resultErrors);
     }
 
@@ -739,21 +767,21 @@ class OptionTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractIm
         $this->_testStores = ['admin' => 0];
         $this->setUp();
         if ($behavior) {
-            $this->_modelMock->setParameters(['behavior' => \Magento\ImportExport\Model\Import::BEHAVIOR_APPEND]);
+            $this->modelMock->setParameters(['behavior' => \Magento\ImportExport\Model\Import::BEHAVIOR_APPEND]);
         }
 
         $this->_bypassModelMethodGetMultiRowFormat($rowData);
 
         for ($i = 0; $i < $numberOfValidations; $i++) {
-            $this->_modelMock->validateRow($rowData, $i);
+            $this->modelMock->validateRow($rowData, $i);
         }
 
         if (empty($errors)) {
-            $this->assertTrue($this->_modelMock->validateAmbiguousData());
+            $this->assertTrue($this->modelMock->validateAmbiguousData());
         } else {
-            $this->assertFalse($this->_modelMock->validateAmbiguousData());
+            $this->assertFalse($this->modelMock->validateAmbiguousData());
         }
-        $resultErrors = $this->_productEntity->getErrorAggregator()->getRowsGroupedByErrorCode([], [], false);
+        $resultErrors = $this->productEntity->getErrorAggregator()->getRowsGroupedByErrorCode([], [], false);
         $this->assertEquals($errors, $resultErrors);
     }
 
@@ -905,38 +933,50 @@ class OptionTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractIm
         $productModel = $this->getMock('stdClass', ['getProductEntitiesInfo']);
         $productModel->expects($this->any())->method('getProductEntitiesInfo')->will($this->returnValue([]));
 
-        $productEntity = $this->getMock(
-            '\Magento\CatalogImportExport\Model\Import\Product',
+        /** @var \Magento\CatalogImportExport\Model\Import\Product $productEntityMock */
+        $productEntityMock = $this->getMock(
+            \Magento\CatalogImportExport\Model\Import\Product::class,
             [],
             [],
             '',
             false
         );
+        $reflection = new \ReflectionClass(\Magento\CatalogImportExport\Model\Import\Product::class);
+        $reflectionProperty = $reflection->getProperty('metadataPool');
+        $reflectionProperty->setAccessible(true);
+        $reflectionProperty->setValue($productEntityMock, $this->metadataPoolMock);
 
+        /** @var \Magento\CatalogImportExport\Model\Import\Product\Option $model */
         $model = $this->objectManagerHelper->getObject(
-            'Magento\CatalogImportExport\Model\Import\Product\Option',
+            \Magento\CatalogImportExport\Model\Import\Product\Option::class,
             [
                 'data' => [
                     'data_source_model' => $modelData,
                     'product_model' => $productModel,
                     'option_collection' => $this->objectManagerHelper->getObject('stdClass'),
-                    'product_entity' => $productEntity,
+                    'product_entity' => $productEntityMock,
                     'collection_by_pages_iterator' => $this->objectManagerHelper->getObject('stdClass'),
                     'page_size' => 5000,
-                    'stores' => []
+                    'stores' => [],
+                    'metadata_pool' => $this->metadataPoolMock
                 ]
             ]
         );
+        $reflection = new \ReflectionClass(\Magento\CatalogImportExport\Model\Import\Product\Option::class);
+        $reflectionProperty = $reflection->getProperty('metadataPool');
+        $reflectionProperty->setAccessible(true);
+        $reflectionProperty->setValue($model, $this->metadataPoolMock);
+
         $this->assertTrue($model->importData());
     }
 
     public function testClearProductsSkuToId()
     {
-        $this->setPropertyValue($this->_modelMock, '_productsSkuToId', 'value');
+        $this->setPropertyValue($this->modelMock, '_productsSkuToId', 'value');
 
-        $this->_modelMock->clearProductsSkuToId();
+        $this->modelMock->clearProductsSkuToId();
 
-        $productsSkuToId = $this->getPropertyValue($this->_modelMock, '_productsSkuToId');
+        $productsSkuToId = $this->getPropertyValue($this->modelMock, '_productsSkuToId');
 
         $this->assertNull($productsSkuToId);
     }
@@ -947,6 +987,7 @@ class OptionTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractIm
      * @param object $object
      * @param string $property
      * @param mixed $value
+     * @return object
      */
     protected function setPropertyValue(&$object, $property, $value)
     {
@@ -963,6 +1004,7 @@ class OptionTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractIm
      *
      * @param object $object
      * @param string $property
+     * @return mixed
      */
     protected function getPropertyValue(&$object, $property)
     {
diff --git a/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/ProductTest.php b/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/ProductTest.php
index ae443adc9b5872ed9d41704cdc08c807ab5f3e8f..c19551bfa094bf2627ffa0494565c71c7119ab9f 100644
--- a/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/ProductTest.php
+++ b/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/ProductTest.php
@@ -146,11 +146,6 @@ class ProductTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractI
     // @codingStandardsIgnoreEnd
     protected $taxClassProcessor;
 
-    /**
-     * @var \Magento\Framework\Model\Entity\MetadataPool|\PHPUnit_Framework_MockObject_MockObject
-     */
-    protected $metadataPool;
-
     /** @var  \Magento\CatalogImportExport\Model\Import\Product */
     protected $importProduct;
 
@@ -172,173 +167,180 @@ class ProductTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractI
     {
         parent::setUp();
 
+        $metadataPoolMock = $this->getMock(\Magento\Framework\Model\Entity\MetadataPool::class, [], [], '', false);
+        $entityMetadataMock = $this->getMock(\Magento\Framework\Model\Entity\EntityMetadata::class, [], [], '', false);
+        $metadataPoolMock->expects($this->any())
+            ->method('getMetadata')
+            ->with(\Magento\Catalog\Api\Data\ProductInterface::class)
+            ->willReturn($entityMetadataMock);
+        $entityMetadataMock->expects($this->any())
+            ->method('getLinkField')
+            ->willReturn('entity_id');
+
         /* For parent object construct */
         $this->jsonHelper =
-            $this->getMockBuilder('\Magento\Framework\Json\Helper\Data')
+            $this->getMockBuilder(\Magento\Framework\Json\Helper\Data::class)
                 ->disableOriginalConstructor()
                 ->getMock();
         $this->importExportData =
-            $this->getMockBuilder('\Magento\ImportExport\Helper\Data')
+            $this->getMockBuilder(\Magento\ImportExport\Helper\Data::class)
                 ->disableOriginalConstructor()
                 ->getMock();
         $this->_dataSourceModel =
-            $this->getMockBuilder('\Magento\ImportExport\Model\ResourceModel\Import\Data')
+            $this->getMockBuilder(\Magento\ImportExport\Model\ResourceModel\Import\Data::class)
                 ->disableOriginalConstructor()
                 ->getMock();
         $this->config =
-            $this->getMockBuilder('\Magento\Eav\Model\Config')
+            $this->getMockBuilder(\Magento\Eav\Model\Config::class)
                 ->disableOriginalConstructor()
                 ->getMock();
         $this->resource =
-            $this->getMockBuilder('\Magento\Framework\App\ResourceConnection')
+            $this->getMockBuilder(\Magento\Framework\App\ResourceConnection::class)
                 ->disableOriginalConstructor()
                 ->getMock();
         $this->resourceHelper =
-            $this->getMockBuilder('\Magento\ImportExport\Model\ResourceModel\Helper')
+            $this->getMockBuilder(\Magento\ImportExport\Model\ResourceModel\Helper::class)
                 ->disableOriginalConstructor()
                 ->getMock();
         $this->string =
-            $this->getMockBuilder('\Magento\Framework\Stdlib\StringUtils')
+            $this->getMockBuilder(\Magento\Framework\Stdlib\StringUtils::class)
                 ->disableOriginalConstructor()
                 ->getMock();
 
         /* For object construct */
         $this->_eventManager =
-            $this->getMockBuilder('\Magento\Framework\Event\ManagerInterface')
+            $this->getMockBuilder(\Magento\Framework\Event\ManagerInterface::class)
                 ->getMock();
         $this->stockRegistry =
-            $this->getMockBuilder('\Magento\CatalogInventory\Api\StockRegistryInterface')
+            $this->getMockBuilder(\Magento\CatalogInventory\Api\StockRegistryInterface::class)
                 ->getMock();
         $this->stockConfiguration =
-            $this->getMockBuilder('\Magento\CatalogInventory\Api\StockConfigurationInterface')
+            $this->getMockBuilder(\Magento\CatalogInventory\Api\StockConfigurationInterface::class)
                 ->getMock();
         $this->stockStateProvider =
-            $this->getMockBuilder('\Magento\CatalogInventory\Model\Spi\StockStateProviderInterface')
+            $this->getMockBuilder(\Magento\CatalogInventory\Model\Spi\StockStateProviderInterface::class)
                 ->getMock();
         $this->_catalogData =
-            $this->getMockBuilder('\Magento\Catalog\Helper\Data')
+            $this->getMockBuilder(\Magento\Catalog\Helper\Data::class)
                 ->disableOriginalConstructor()
                 ->getMock();
         $this->_importConfig =
-            $this->getMockBuilder('\Magento\ImportExport\Model\Import\Config')
+            $this->getMockBuilder(\Magento\ImportExport\Model\Import\Config::class)
                 ->disableOriginalConstructor()
                 ->getMock();
         $this->_resourceFactory = $this->getMock(
-            '\Magento\CatalogImportExport\Model\Import\Proxy\Product\ResourceModelFactory',
+            \Magento\CatalogImportExport\Model\Import\Proxy\Product\ResourceModelFactory::class,
             ['create'],
             [],
             '',
             false
         );
         $this->_setColFactory = $this->getMock(
-            '\Magento\Eav\Model\ResourceModel\Entity\Attribute\Set\CollectionFactory',
+            \Magento\Eav\Model\ResourceModel\Entity\Attribute\Set\CollectionFactory::class,
             ['create'],
             [],
             '',
             false
         );
         $this->_productTypeFactory = $this->getMock(
-            '\Magento\CatalogImportExport\Model\Import\Product\Type\Factory',
+            \Magento\CatalogImportExport\Model\Import\Product\Type\Factory::class,
             ['create'],
             [],
             '',
             false
         );
         $this->_linkFactory = $this->getMock(
-            '\Magento\Catalog\Model\ResourceModel\Product\LinkFactory',
+            \Magento\Catalog\Model\ResourceModel\Product\LinkFactory::class,
             ['create'],
             [],
             '',
             false
         );
         $this->_proxyProdFactory = $this->getMock(
-            '\Magento\CatalogImportExport\Model\Import\Proxy\ProductFactory',
+            \Magento\CatalogImportExport\Model\Import\Proxy\ProductFactory::class,
             ['create'],
             [],
             '',
             false
         );
         $this->_uploaderFactory = $this->getMock(
-            '\Magento\CatalogImportExport\Model\Import\UploaderFactory',
+            \Magento\CatalogImportExport\Model\Import\UploaderFactory::class,
             ['create'],
             [],
             '',
             false
         );
         $this->_filesystem =
-            $this->getMockBuilder('\Magento\Framework\Filesystem')
+            $this->getMockBuilder(\Magento\Framework\Filesystem::class)
                 ->disableOriginalConstructor()
                 ->getMock();
         $this->_mediaDirectory =
-            $this->getMockBuilder('\Magento\Framework\Filesystem\Directory\WriteInterface')
+            $this->getMockBuilder(\Magento\Framework\Filesystem\Directory\WriteInterface::class)
                 ->getMock();
         $this->_stockResItemFac = $this->getMock(
-            '\Magento\CatalogInventory\Model\ResourceModel\Stock\ItemFactory',
+            \Magento\CatalogInventory\Model\ResourceModel\Stock\ItemFactory::class,
             ['create'],
             [],
             '',
             false
         );
         $this->_localeDate =
-            $this->getMockBuilder('\Magento\Framework\Stdlib\DateTime\TimezoneInterface')
+            $this->getMockBuilder(\Magento\Framework\Stdlib\DateTime\TimezoneInterface::class)
                 ->getMock();
         $this->dateTime =
-            $this->getMockBuilder('\Magento\Framework\Stdlib\DateTime')
+            $this->getMockBuilder(\Magento\Framework\Stdlib\DateTime::class)
                 ->disableOriginalConstructor()
                 ->getMock();
         $this->indexerRegistry =
-            $this->getMockBuilder('\Magento\Framework\Indexer\IndexerRegistry')
+            $this->getMockBuilder(\Magento\Framework\Indexer\IndexerRegistry::class)
                 ->disableOriginalConstructor()
                 ->getMock();
         $this->_logger =
-            $this->getMockBuilder('\Psr\Log\LoggerInterface')
+            $this->getMockBuilder(\Psr\Log\LoggerInterface::class)
                 ->getMock();
         $this->storeResolver =
-            $this->getMockBuilder('\Magento\CatalogImportExport\Model\Import\Product\StoreResolver')
+            $this->getMockBuilder(\Magento\CatalogImportExport\Model\Import\Product\StoreResolver::class)
                 ->setMethods([
                     'getStoreCodeToId',
                 ])
                 ->disableOriginalConstructor()
                 ->getMock();
         $this->skuProcessor =
-            $this->getMockBuilder('\Magento\CatalogImportExport\Model\Import\Product\SkuProcessor')
+            $this->getMockBuilder(\Magento\CatalogImportExport\Model\Import\Product\SkuProcessor::class)
                 ->disableOriginalConstructor()
                 ->getMock();
+        $reflection = new \ReflectionClass(\Magento\CatalogImportExport\Model\Import\Product\SkuProcessor::class);
+        $reflectionProperty = $reflection->getProperty('metadataPool');
+        $reflectionProperty->setAccessible(true);
+        $reflectionProperty->setValue($this->skuProcessor, $metadataPoolMock);
+
         $this->categoryProcessor =
-            $this->getMockBuilder('\Magento\CatalogImportExport\Model\Import\Product\CategoryProcessor')
+            $this->getMockBuilder(\Magento\CatalogImportExport\Model\Import\Product\CategoryProcessor::class)
                 ->disableOriginalConstructor()
                 ->getMock();
         $this->validator =
-            $this->getMockBuilder('\Magento\CatalogImportExport\Model\Import\Product\Validator')
+            $this->getMockBuilder(\Magento\CatalogImportExport\Model\Import\Product\Validator::class)
                 ->setMethods(['isAttributeValid', 'getMessages', 'isValid'])
                 ->disableOriginalConstructor()
                 ->getMock();
         $this->objectRelationProcessor =
-            $this->getMockBuilder('\Magento\Framework\Model\ResourceModel\Db\ObjectRelationProcessor')
+            $this->getMockBuilder(\Magento\Framework\Model\ResourceModel\Db\ObjectRelationProcessor::class)
                 ->disableOriginalConstructor()
                 ->getMock();
         $this->transactionManager =
-            $this->getMockBuilder('\Magento\Framework\Model\ResourceModel\Db\TransactionManagerInterface')
+            $this->getMockBuilder(\Magento\Framework\Model\ResourceModel\Db\TransactionManagerInterface::class)
                 ->getMock();
 
         $this->taxClassProcessor =
-            $this->getMockBuilder('\Magento\CatalogImportExport\Model\Import\Product\TaxClassProcessor')
+            $this->getMockBuilder(\Magento\CatalogImportExport\Model\Import\Product\TaxClassProcessor::class)
                 ->disableOriginalConstructor()
                 ->getMock();
 
-        $this->metadataPool = $this->getMock(
-            'Magento\Framework\Model\Entity\MetadataPool',
-            [],
-            [],
-            '',
-            false
-        );
-
-        $this->scopeConfig = $this->getMockBuilder('\Magento\Framework\App\Config\ScopeConfigInterface')
+        $this->scopeConfig = $this->getMockBuilder(\Magento\Framework\App\Config\ScopeConfigInterface::class)
             ->disableOriginalConstructor()
             ->getMockForAbstractClass();
 
-        $this->productUrl = $this->getMockBuilder('\Magento\Catalog\Model\Product\Url')
+        $this->productUrl = $this->getMockBuilder(\Magento\Catalog\Model\Product\Url::class)
             ->disableOriginalConstructor()
             ->getMock();
 
@@ -352,46 +354,54 @@ class ProductTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractI
             ->_initTypeModels()
             ->_initSkus();
 
-        $this->importProduct = new Product(
-            $this->jsonHelper,
-            $this->importExportData,
-            $this->_dataSourceModel,
-            $this->config,
-            $this->resource,
-            $this->resourceHelper,
-            $this->string,
-            $this->errorAggregator,
-            $this->_eventManager,
-            $this->stockRegistry,
-            $this->stockConfiguration,
-            $this->stockStateProvider,
-            $this->_catalogData,
-            $this->_importConfig,
-            $this->_resourceFactory,
-            $this->optionFactory,
-            $this->_setColFactory,
-            $this->_productTypeFactory,
-            $this->_linkFactory,
-            $this->_proxyProdFactory,
-            $this->_uploaderFactory,
-            $this->_filesystem,
-            $this->_stockResItemFac,
-            $this->_localeDate,
-            $this->dateTime,
-            $this->_logger,
-            $this->indexerRegistry,
-            $this->storeResolver,
-            $this->skuProcessor,
-            $this->categoryProcessor,
-            $this->validator,
-            $this->objectRelationProcessor,
-            $this->transactionManager,
-            $this->taxClassProcessor,
-            $this->metadataPool,
-            $this->scopeConfig,
-            $this->productUrl,
-            $this->data
+        $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
+
+        $this->importProduct = $objectManager->getObject(
+            \Magento\CatalogImportExport\Model\Import\Product::class,
+            [
+                'jsonHelper' => $this->jsonHelper,
+                'importExportData' => $this->importExportData,
+                'importData' => $this->_dataSourceModel,
+                'config' => $this->config,
+                'resource' => $this->resource,
+                'resourceHelper' => $this->resourceHelper,
+                'string' => $this->string,
+                'errorAggregator' => $this->errorAggregator,
+                'eventManager' => $this->_eventManager,
+                'stockRegistry' => $this->stockRegistry,
+                'stockConfiguration' => $this->stockConfiguration,
+                'stockStateProvider' => $this->stockStateProvider,
+                'catalogData' => $this->_catalogData,
+                'importConfig' => $this->_importConfig,
+                'resourceFactory' => $this->_resourceFactory,
+                'optionFactory' => $this->optionFactory,
+                'setColFactory' => $this->_setColFactory,
+                'productTypeFactory' => $this->_productTypeFactory,
+                'linkFactory' => $this->_linkFactory,
+                'proxyProdFactory' => $this->_proxyProdFactory,
+                'uploaderFactory' => $this->_uploaderFactory,
+                'filesystem' => $this->_filesystem,
+                'stockResItemFac' => $this->_stockResItemFac,
+                'localeDate' => $this->_localeDate,
+                'dateTime' => $this->dateTime,
+                'logger' => $this->_logger,
+                'indexerRegistry' => $this->indexerRegistry,
+                'storeResolver' => $this->storeResolver,
+                'skuProcessor' => $this->skuProcessor,
+                'categoryProcessor' => $this->categoryProcessor,
+                'validator' => $this->validator,
+                'objectRelationProcessor' => $this->objectRelationProcessor,
+                'transactionManager' => $this->transactionManager,
+                'taxClassProcessor' => $this->taxClassProcessor,
+                'scopeConfig' => $this->scopeConfig,
+                'productUrl' => $this->productUrl,
+                'data' => $this->data
+            ]
         );
+        $reflection = new \ReflectionClass('\Magento\CatalogImportExport\Model\Import\Product');
+        $reflectionProperty = $reflection->getProperty('metadataPool');
+        $reflectionProperty->setAccessible(true);
+        $reflectionProperty->setValue($this->importProduct, $metadataPoolMock);
     }
 
     /**
@@ -406,7 +416,7 @@ class ProductTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractI
             '',
             false
         );
-        $this->optionEntity = $this->getMockBuilder('\Magento\CatalogImportExport\Model\Import\Product\Option')
+        $this->optionEntity = $this->getMockBuilder(\Magento\CatalogImportExport\Model\Import\Product\Option::class)
             ->disableOriginalConstructor()->getMock();
         $this->optionFactory->expects($this->once())->method('create')->willReturn($this->optionEntity);
 
@@ -424,11 +434,11 @@ class ProductTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractI
      */
     protected function _parentObjectConstructor()
     {
-        $type = $this->getMockBuilder('Magento\Eav\Model\Entity\Type')->disableOriginalConstructor()->getMock();
+        $type = $this->getMockBuilder(\Magento\Eav\Model\Entity\Type::class)->disableOriginalConstructor()->getMock();
         $type->expects($this->any())->method('getEntityTypeId')->will($this->returnValue(self::ENTITY_TYPE_ID));
         $this->config->expects($this->any())->method('getEntityType')->with(self::ENTITY_TYPE_CODE)->willReturn($type);
 
-        $this->_connection = $this->getMock('\Magento\Framework\DB\Adapter\AdapterInterface');
+        $this->_connection = $this->getMock(\Magento\Framework\DB\Adapter\AdapterInterface::class);
         $this->resource->expects($this->any())->method('getConnection')->willReturn($this->_connection);
         return $this;
     }
@@ -438,7 +448,7 @@ class ProductTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractI
      */
     protected function _initAttributeSets()
     {
-        $attributeSetOne = $this->getMockBuilder('\Magento\Eav\Model\Entity\Attribute\Set')
+        $attributeSetOne = $this->getMockBuilder(\Magento\Eav\Model\Entity\Attribute\Set::class)
             ->disableOriginalConstructor()
             ->getMock();
         $attributeSetOne->expects($this->any())
@@ -447,7 +457,7 @@ class ProductTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractI
         $attributeSetOne->expects($this->any())
             ->method('getId')
             ->willReturn('1');
-        $attributeSetTwo = $this->getMockBuilder('\Magento\Eav\Model\Entity\Attribute\Set')
+        $attributeSetTwo = $this->getMockBuilder(\Magento\Eav\Model\Entity\Attribute\Set::class)
             ->disableOriginalConstructor()
             ->getMock();
         $attributeSetTwo->expects($this->any())
@@ -457,7 +467,7 @@ class ProductTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractI
             ->method('getId')
             ->willReturn('2');
         $attributeSetCol = [$attributeSetOne, $attributeSetTwo];
-        $collection = $this->getMockBuilder('\Magento\Eav\Model\ResourceModel\Entity\Attribute\Set\Collection')
+        $collection = $this->getMockBuilder(\Magento\Eav\Model\ResourceModel\Entity\Attribute\Set\Collection::class)
             ->disableOriginalConstructor()
             ->getMock();
         $collection->expects($this->once())
@@ -481,7 +491,7 @@ class ProductTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractI
                 'params' => [],
             ]];
         $productTypeInstance =
-            $this->getMockBuilder('\Magento\CatalogImportExport\Model\Import\Product\Type\AbstractType')
+            $this->getMockBuilder(\Magento\CatalogImportExport\Model\Import\Product\Type\AbstractType::class)
                 ->disableOriginalConstructor()->getMock();
         $productTypeInstance->expects($this->once())
             ->method('isSuitable')
@@ -527,21 +537,14 @@ class ProductTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractI
                 ]
             ]
         ];
-        $metadataMock = $this->getMockBuilder('\Magento\Framework\Model\Entity\EntityMetadata')
-            ->disableOriginalConstructor()
-            ->getMock();
-        $this->metadataPool->expects($this->any())->method('getMetadata')
-            ->with(\Magento\Catalog\Api\Data\ProductInterface::class)
-            ->willReturn($metadataMock);
-        $metadataMock->expects($this->any())->method('getLinkField')->willReturn('entity_id');
         $entityTable = 'catalog_product_entity';
-        $resource = $this->getMockBuilder('\Magento\CatalogImportExport\Model\Import\Proxy\Product\ResourceModel')
+        $resource = $this->getMockBuilder(\Magento\CatalogImportExport\Model\Import\Proxy\Product\ResourceModel::class)
             ->disableOriginalConstructor()
             ->setMethods(['getTable'])
             ->getMock();
         $resource->expects($this->once())->method('getTable')->with($entityTable)->willReturnArgument(0);
         $this->_resourceFactory->expects($this->once())->method('create')->willReturn($resource);
-        $selectMock = $this->getMockBuilder('Magento\Framework\DB\Select')
+        $selectMock = $this->getMockBuilder(\Magento\Framework\DB\Select::class)
             ->disableOriginalConstructor()
             ->getMock();
         $selectMock->expects($this->once())->method('from')->with($entityTable, '*', null)->willReturnSelf();
@@ -573,7 +576,7 @@ class ProductTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractI
     {
         $attrCode = 'code';
         $rowNum = 0;
-        $string = $this->getMockBuilder('\Magento\Framework\Stdlib\StringUtils')->setMethods(null)->getMock();
+        $string = $this->getMockBuilder(\Magento\Framework\Stdlib\StringUtils::class)->setMethods(null)->getMock();
         $this->setPropertyValue($this->importProduct, 'string', $string);
 
         $this->validator->expects($this->once())->method('isAttributeValid')->willReturn(true);
@@ -589,7 +592,7 @@ class ProductTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractI
     {
         $attrCode = 'code';
         $rowNum = 0;
-        $string = $this->getMockBuilder('\Magento\Framework\Stdlib\StringUtils')->setMethods(null)->getMock();
+        $string = $this->getMockBuilder(\Magento\Framework\Stdlib\StringUtils::class)->setMethods(null)->getMock();
         $this->setPropertyValue($this->importProduct, 'string', $string);
 
         $this->validator->expects($this->once())->method('isAttributeValid')->willReturn(false);
@@ -624,7 +627,7 @@ class ProductTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractI
 
     public function testDeleteProductsForReplacement()
     {
-        $importProduct = $this->getMockBuilder('\Magento\CatalogImportExport\Model\Import\Product')
+        $importProduct = $this->getMockBuilder(\Magento\CatalogImportExport\Model\Import\Product::class)
             ->disableOriginalConstructor()
             ->setMethods([
                 'setParameters', '_deleteProducts'
@@ -649,12 +652,12 @@ class ProductTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractI
         $this->setPropertyValue($this->importProduct, '_mediaGalleryAttributeId', null);
 
         $expectedId = '100';
-        $attribute = $this->getMockBuilder('\Magento\Eav\Model\Entity\Attribute\AbstractAttribute')
+        $attribute = $this->getMockBuilder(\Magento\Eav\Model\Entity\Attribute\AbstractAttribute::class)
             ->disableOriginalConstructor()
             ->setMethods(['getId'])
             ->getMockForAbstractClass();
         $attribute->expects($this->once())->method('getId')->willReturn($expectedId);
-        $resource = $this->getMockBuilder('\Magento\CatalogImportExport\Model\Import\Proxy\Product\ResourceModel')
+        $resource = $this->getMockBuilder(\Magento\CatalogImportExport\Model\Import\Proxy\Product\ResourceModel::class)
             ->disableOriginalConstructor()
             ->setMethods(['getAttribute'])
             ->getMock();
@@ -665,7 +668,6 @@ class ProductTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractI
         $this->assertEquals($expectedId, $result);
     }
 
-
     /**
      * @dataProvider getRowScopeDataProvider
      */
@@ -691,7 +693,7 @@ class ProductTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractI
      */
     public function testValidateRow($rowScope, $oldSku, $expectedResult, $behaviour = Import::BEHAVIOR_DELETE)
     {
-        $importProduct = $this->getMockBuilder('\Magento\CatalogImportExport\Model\Import\Product')
+        $importProduct = $this->getMockBuilder(\Magento\CatalogImportExport\Model\Import\Product::class)
             ->disableOriginalConstructor()
             ->setMethods(['getBehavior', 'getRowScope', 'getErrorAggregator'])
             ->getMock();
@@ -715,7 +717,7 @@ class ProductTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractI
 
     public function testValidateRowDeleteBehaviourAddRowErrorCall()
     {
-        $importProduct = $this->getMockBuilder('\Magento\CatalogImportExport\Model\Import\Product')
+        $importProduct = $this->getMockBuilder(\Magento\CatalogImportExport\Model\Import\Product::class)
             ->disableOriginalConstructor()
             ->setMethods(['getBehavior', 'getRowScope', 'addRowError'])
             ->getMock();
@@ -993,7 +995,7 @@ class ProductTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractI
         ];
         $this->skuProcessor->expects($this->once())->method('getNewSku')->with($expectedSku)->willReturn($newSku);
         $this->setPropertyValue($importProduct, 'skuProcessor', $this->skuProcessor);
-        $productType = $this->getMockBuilder('\Magento\CatalogImportExport\Model\Import\Product\Type\AbstractType')
+        $productType = $this->getMockBuilder(\Magento\CatalogImportExport\Model\Import\Product\Type\AbstractType::class)
             ->disableOriginalConstructor()
             ->getMock();
         $this->setPropertyValue($importProduct, '_productTypeModels', [
@@ -1072,6 +1074,7 @@ class ProductTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractI
             'attr_set_id' =>
                 $_attrSetNameToId[$rowData[\Magento\CatalogImportExport\Model\Import\Product::COL_ATTR_SET]],
             'attr_set_code' => $rowData[\Magento\CatalogImportExport\Model\Import\Product::COL_ATTR_SET],//value
+            'row_id' => null
         ];
         $importProduct = $this->createModelMockWithErrorAggregator(
             ['addRowError', 'getOptionEntity'],
@@ -1132,7 +1135,7 @@ class ProductTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractI
         ];
         $this->skuProcessor->expects($this->once())->method('getNewSku')->with($expectedSku)->willReturn($newSku);
         $this->setPropertyValue($importProduct, 'skuProcessor', $this->skuProcessor);
-        $productType = $this->getMockBuilder('\Magento\CatalogImportExport\Model\Import\Product\Type\AbstractType')
+        $productType = $this->getMockBuilder(\Magento\CatalogImportExport\Model\Import\Product\Type\AbstractType::class)
             ->disableOriginalConstructor()
             ->getMock();
         $this->setPropertyValue($importProduct, '_productTypeModels', [
@@ -1147,11 +1150,13 @@ class ProductTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractI
         $sku = 'sku';
         $rowNum = 0;
         $attrCode = 'code';
-        $stringUtilsMock = $this->getMockBuilder('\Magento\Framework\Stdlib\StringUtils')->setMethods(null)->getMock();
+        $stringUtilsMock = $this->getMockBuilder(\Magento\Framework\Stdlib\StringUtils::class)
+            ->setMethods(null)
+            ->getMock();
         $this->setPropertyValue($this->importProduct, 'string', $stringUtilsMock);
 
         $scopeMock = $this->getMock(
-            '\Magento\CatalogImportExport\Model\Import\Product',
+            \Magento\CatalogImportExport\Model\Import\Product::class,
             ['getRowScope'],
             [],
             '',
@@ -1227,7 +1232,7 @@ class ProductTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractI
         $this->skuProcessor->expects($this->any())->method('getNewSku')->willReturn($newSku);
         $this->setPropertyValue($importProduct, 'skuProcessor', $this->skuProcessor);
 
-        $productType = $this->getMockBuilder('\Magento\CatalogImportExport\Model\Import\Product\Type\AbstractType')
+        $productType = $this->getMockBuilder(\Magento\CatalogImportExport\Model\Import\Product\Type\AbstractType::class)
             ->disableOriginalConstructor()
             ->getMock();
         $productType->expects($this->once())->method('isRowValid')->with($expectedRowData);
@@ -1266,7 +1271,7 @@ class ProductTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractI
         //suppress validator
         $this->_setValidatorMockInImportProduct($importProduct);
 
-        $option = $this->getMockBuilder('\Magento\CatalogImportExport\Model\Import\Product\Option')
+        $option = $this->getMockBuilder(\Magento\CatalogImportExport\Model\Import\Product\Option::class)
             ->disableOriginalConstructor()
             ->getMock();
         $option->expects($this->once())->method('validateRow')->with($rowData, $rowNum);
@@ -1649,7 +1654,7 @@ class ProductTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractI
      */
     private function _rewriteGetOptionEntityInImportProduct($importProduct)
     {
-        $option = $this->getMockBuilder('\Magento\CatalogImportExport\Model\Import\Product\Option')
+        $option = $this->getMockBuilder(\Magento\CatalogImportExport\Model\Import\Product\Option::class)
             ->disableOriginalConstructor()
             ->getMock();
         $importProduct->expects($this->once())->method('getOptionEntity')->willReturn($option);
@@ -1665,7 +1670,7 @@ class ProductTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractI
     protected function createModelMockWithErrorAggregator(array $methods = [], array $errorAggregatorMethods = [])
     {
         $methods[] = 'getErrorAggregator';
-        $importProduct = $this->getMockBuilder('\Magento\CatalogImportExport\Model\Import\Product')
+        $importProduct = $this->getMockBuilder(\Magento\CatalogImportExport\Model\Import\Product::class)
             ->disableOriginalConstructor()
             ->setMethods($methods)
             ->getMock();
diff --git a/app/code/Magento/CatalogImportExportStaging/Observer/DeleteSequenceObserver.php b/app/code/Magento/CatalogImportExportStaging/Observer/DeleteSequenceObserver.php
new file mode 100644
index 0000000000000000000000000000000000000000..9b62f41a3e49080ab2521bddc8094306df8c14af
--- /dev/null
+++ b/app/code/Magento/CatalogImportExportStaging/Observer/DeleteSequenceObserver.php
@@ -0,0 +1,41 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\CatalogImportExportStaging\Observer;
+
+use Magento\Framework\Event\ObserverInterface;
+use Magento\CatalogStaging\Model\ResourceModel\ProductSequence\Collection;
+
+class DeleteSequenceObserver implements ObserverInterface
+{
+    /**
+     * @var Collection
+     */
+    private $productSequenceCollection;
+
+    /**
+     * Constructor
+     *
+     * @param Collection $productSequenceCollection
+     */
+    public function __construct(
+        Collection $productSequenceCollection
+    ) {
+        $this->productSequenceCollection = $productSequenceCollection;
+    }
+
+    /**
+     * Delete sequence
+     *
+     * @param \Magento\Framework\Event\Observer $observer
+     * @return void
+     * @throws \LogicException
+     */
+    public function execute(\Magento\Framework\Event\Observer $observer)
+    {
+        $ids = $observer->getIdsToDelete();
+        $this->productSequenceCollection->deleteSequence($ids);
+    }
+}
diff --git a/app/code/Magento/CatalogInventory/Block/Stockqty/AbstractStockqty.php b/app/code/Magento/CatalogInventory/Block/Stockqty/AbstractStockqty.php
index 93224e80fe3efdf07c602ec02d57bd36274b3db6..ffe5f6559c35dedcdda881b31d649a88d821c52c 100644
--- a/app/code/Magento/CatalogInventory/Block/Stockqty/AbstractStockqty.php
+++ b/app/code/Magento/CatalogInventory/Block/Stockqty/AbstractStockqty.php
@@ -25,11 +25,6 @@ abstract class AbstractStockqty extends \Magento\Framework\View\Element\Template
      */
     protected $_coreRegistry;
 
-    /**
-     * @var \Magento\CatalogInventory\Api\StockStateInterface
-     */
-    protected $stockState;
-
     /**
      * @var \Magento\CatalogInventory\Api\StockRegistryInterface
      */
@@ -38,19 +33,16 @@ abstract class AbstractStockqty extends \Magento\Framework\View\Element\Template
     /**
      * @param \Magento\Framework\View\Element\Template\Context $context
      * @param \Magento\Framework\Registry $registry
-     * @param \Magento\CatalogInventory\Api\StockStateInterface $stockState
      * @param \Magento\CatalogInventory\Api\StockRegistryInterface $stockRegistry
      * @param array $data
      */
     public function __construct(
         \Magento\Framework\View\Element\Template\Context $context,
         \Magento\Framework\Registry $registry,
-        \Magento\CatalogInventory\Api\StockStateInterface $stockState,
         \Magento\CatalogInventory\Api\StockRegistryInterface $stockRegistry,
         array $data = []
     ) {
         $this->_coreRegistry = $registry;
-        $this->stockState = $stockState;
         $this->stockRegistry = $stockRegistry;
 
         parent::__construct($context, $data);
@@ -92,7 +84,7 @@ abstract class AbstractStockqty extends \Magento\Framework\View\Element\Template
      */
     public function getProductStockQty($product)
     {
-        return $this->stockState->getStockQty($product->getId(), $product->getStore()->getWebsiteId());
+        return $this->stockRegistry->getStockStatus($product->getId(), $product->getStore()->getWebsiteId())->getQty();
     }
 
     /**
diff --git a/app/code/Magento/CatalogInventory/Helper/Stock.php b/app/code/Magento/CatalogInventory/Helper/Stock.php
index 8a227f53ebc1fce93a93a809ab5a0c1e887c06c4..8f7bb78776cba151fd7e3393d4144adb6c53e4cd 100644
--- a/app/code/Magento/CatalogInventory/Helper/Stock.php
+++ b/app/code/Magento/CatalogInventory/Helper/Stock.php
@@ -139,8 +139,16 @@ class Stock
      */
     public function addIsInStockFilterToCollection($collection)
     {
-        $resource = $this->getStockStatusResource();
-        $resource->addIsInStockFilterToCollection($collection);
+        $stockFlag = 'has_stock_status_filter';
+        if (!$collection->hasFlag($stockFlag)) {
+            $isShowOutOfStock = $this->scopeConfig->getValue(
+                \Magento\CatalogInventory\Model\Configuration::XML_PATH_SHOW_OUT_OF_STOCK,
+                \Magento\Store\Model\ScopeInterface::SCOPE_STORE
+            );
+            $resource = $this->getStockStatusResource();
+            $resource->addStockDataToCollection($collection, !$isShowOutOfStock);
+            $collection->setFlag($stockFlag, true);
+        }
     }
 
     /**
diff --git a/app/code/Magento/CatalogInventory/Model/AddStockStatusToCollection.php b/app/code/Magento/CatalogInventory/Model/AddStockStatusToCollection.php
new file mode 100644
index 0000000000000000000000000000000000000000..fdf613f5506a9aa6796881371194833c7a01318c
--- /dev/null
+++ b/app/code/Magento/CatalogInventory/Model/AddStockStatusToCollection.php
@@ -0,0 +1,42 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\CatalogInventory\Model;
+
+use Magento\Catalog\Model\ResourceModel\Product\Collection;
+
+/**
+ * Catalog inventory module plugin
+ */
+class AddStockStatusToCollection
+{
+    /**
+     * @var \Magento\CatalogInventory\Helper\Stock
+     */
+    protected $stockHelper;
+    
+    /**
+     * @param \Magento\CatalogInventory\Model\Configuration $configuration
+     * @param \Magento\CatalogInventory\Helper\Stock $stockHelper
+     */
+    public function __construct(
+        \Magento\CatalogInventory\Helper\Stock $stockHelper
+    ) {
+        $this->stockHelper = $stockHelper;
+    }
+
+    /**
+     * @param Collection $productCollection
+     * @param bool $printQuery
+     * @param bool $logQuery
+     * @return array
+     */
+    public function beforeLoad(Collection $productCollection, $printQuery = false, $logQuery = false)
+    {
+        $this->stockHelper->addIsInStockFilterToCollection($productCollection);
+        return [$printQuery, $logQuery];
+    }
+}
diff --git a/app/code/Magento/CatalogInventory/Model/ResourceModel/Indexer/Stock/DefaultStock.php b/app/code/Magento/CatalogInventory/Model/ResourceModel/Indexer/Stock/DefaultStock.php
index c31e0f02c955c465e975112c36e38387904ad85a..8de183aeb391e42b893e72bd77293a0ff080d1cb 100644
--- a/app/code/Magento/CatalogInventory/Model/ResourceModel/Indexer/Stock/DefaultStock.php
+++ b/app/code/Magento/CatalogInventory/Model/ResourceModel/Indexer/Stock/DefaultStock.php
@@ -7,6 +7,8 @@
 namespace Magento\CatalogInventory\Model\ResourceModel\Indexer\Stock;
 
 use Magento\Catalog\Model\ResourceModel\Product\Indexer\AbstractIndexer;
+use Magento\CatalogInventory\Model\Stock;
+use Magento\Framework\DB\Adapter\AdapterInterface;
 
 /**
  * CatalogInventory Default Stock Status Indexer Resource Model
@@ -35,14 +37,20 @@ class DefaultStock extends AbstractIndexer implements StockInterface
      */
     protected $_scopeConfig;
 
+    /**
+     * @var QueryProcessorComposite
+     */
+    private $queryProcessorComposite;
+
     /**
      * Class constructor
      *
      * @param \Magento\Framework\Model\ResourceModel\Db\Context $context
      * @param \Magento\Framework\Indexer\Table\StrategyInterface $tableStrategy
      * @param \Magento\Eav\Model\Config $eavConfig
-     * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
      * @param \Magento\Framework\Model\Entity\MetadataPool $metadataPool
+     * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
+     * @param QueryProcessorComposite $queryProcessorComposite
      * @param string $connectionName
      */
     public function __construct(
@@ -51,9 +59,11 @@ class DefaultStock extends AbstractIndexer implements StockInterface
         \Magento\Eav\Model\Config $eavConfig,
         \Magento\Framework\Model\Entity\MetadataPool $metadataPool,
         \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
+        QueryProcessorComposite $queryProcessorComposite,
         $connectionName = null
     ) {
         $this->_scopeConfig = $scopeConfig;
+        $this->queryProcessorComposite = $queryProcessorComposite;
         parent::__construct($context, $tableStrategy, $eavConfig, $metadataPool, $connectionName);
     }
 
@@ -188,9 +198,10 @@ class DefaultStock extends AbstractIndexer implements StockInterface
             ['cisi' => $this->getTable('cataloginventory_stock_item')],
             'cisi.stock_id = cis.stock_id AND cisi.product_id = e.entity_id',
             []
-        )->columns(['qty' => $qtyExpr])
+        )->columns(['qty' => new \Zend_Db_Expr('SUM(' . $qtyExpr . ')')])
             ->where('cw.website_id != 0')
-            ->where('e.type_id = ?', $this->getTypeId());
+            ->where('e.type_id = ?', $this->getTypeId())
+            ->group('e.entity_id');
 
         // add limitation of status
         $condition = $connection->quoteInto(
@@ -205,21 +216,7 @@ class DefaultStock extends AbstractIndexer implements StockInterface
             $condition
         );
 
-        if ($this->_isManageStock()) {
-            $statusExpr = $connection->getCheckSql(
-                'cisi.use_config_manage_stock = 0 AND cisi.manage_stock = 0',
-                1,
-                'cisi.is_in_stock'
-            );
-        } else {
-            $statusExpr = $connection->getCheckSql(
-                'cisi.use_config_manage_stock = 0 AND cisi.manage_stock = 1',
-                'cisi.is_in_stock',
-                1
-            );
-        }
-
-        $select->columns(['status' => $statusExpr]);
+        $select->columns(['status' => $this->getStatusExpression($connection, true)]);
 
         if ($entityIds !== null) {
             $select->where('e.entity_id IN(?)', $entityIds);
@@ -238,6 +235,7 @@ class DefaultStock extends AbstractIndexer implements StockInterface
     {
         $connection = $this->getConnection();
         $select = $this->_getStockStatusSelect($entityIds);
+        $select = $this->queryProcessorComposite->processQuery($select, $entityIds);
         $query = $select->insertFromSelect($this->getIdxTable());
         $connection->query($query);
 
@@ -254,6 +252,7 @@ class DefaultStock extends AbstractIndexer implements StockInterface
     {
         $connection = $this->getConnection();
         $select = $this->_getStockStatusSelect($entityIds, true);
+        $select = $this->queryProcessorComposite->processQuery($select, $entityIds, true);
         $query = $connection->query($select);
 
         $i = 0;
@@ -263,7 +262,7 @@ class DefaultStock extends AbstractIndexer implements StockInterface
             $data[] = [
                 'product_id' => (int)$row['entity_id'],
                 'website_id' => (int)$row['website_id'],
-                'stock_id' => (int)$row['stock_id'],
+                'stock_id' => Stock::DEFAULT_STOCK_ID,
                 'qty' => (double)$row['qty'],
                 'stock_status' => (int)$row['status'],
             ];
@@ -306,4 +305,28 @@ class DefaultStock extends AbstractIndexer implements StockInterface
     {
         return $this->tableStrategy->getTableName('cataloginventory_stock_status');
     }
+
+    /**
+     * @param AdapterInterface $connection
+     * @param bool $isAggregate
+     * @return mixed
+     */
+    protected function getStatusExpression(AdapterInterface $connection, $isAggregate = false)
+    {
+        $isInStockExpression = $isAggregate ? 'MAX(cisi.is_in_stock)' : 'cisi.is_in_stock';
+        if ($this->_isManageStock()) {
+            $statusExpr = $connection->getCheckSql(
+                'cisi.use_config_manage_stock = 0 AND cisi.manage_stock = 0',
+                1,
+                $isInStockExpression
+            );
+        } else {
+            $statusExpr = $connection->getCheckSql(
+                'cisi.use_config_manage_stock = 0 AND cisi.manage_stock = 1',
+                $isInStockExpression,
+                1
+            );
+        }
+        return $statusExpr;
+    }
 }
diff --git a/app/code/Magento/CatalogInventory/Model/ResourceModel/Indexer/Stock/QueryProcessorComposite.php b/app/code/Magento/CatalogInventory/Model/ResourceModel/Indexer/Stock/QueryProcessorComposite.php
new file mode 100644
index 0000000000000000000000000000000000000000..8b89df82573ae4881ae88d89eb7b84311ee5eb42
--- /dev/null
+++ b/app/code/Magento/CatalogInventory/Model/ResourceModel/Indexer/Stock/QueryProcessorComposite.php
@@ -0,0 +1,38 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\CatalogInventory\Model\ResourceModel\Indexer\Stock;
+
+class QueryProcessorComposite implements QueryProcessorInterface
+{
+    /**
+     * @var array
+     */
+    private $queryProcessors;
+
+    /**
+     * QueryProcessorPool constructor.
+     * @param QueryProcessorInterface[] $queryProcessors
+     */
+    public function __construct(array $queryProcessors = [])
+    {
+        $this->queryProcessors = $queryProcessors;
+    }
+
+    /**
+     * @param \Magento\Framework\DB\Select $select
+     * @param null|array $entityIds
+     * @param bool $usePrimaryTable
+     * @return \Magento\Framework\DB\Select
+     */
+    public function processQuery(\Magento\Framework\DB\Select $select, $entityIds = null, $usePrimaryTable = false)
+    {
+        foreach ($this->queryProcessors as $queryProcessor) {
+            $select = $queryProcessor->processQuery($select, $entityIds, $usePrimaryTable);
+        }
+        return $select;
+    }
+}
diff --git a/app/code/Magento/CatalogInventory/Model/ResourceModel/Indexer/Stock/QueryProcessorInterface.php b/app/code/Magento/CatalogInventory/Model/ResourceModel/Indexer/Stock/QueryProcessorInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..4815e173eba03671a59c9724164c9a59a5d2187c
--- /dev/null
+++ b/app/code/Magento/CatalogInventory/Model/ResourceModel/Indexer/Stock/QueryProcessorInterface.php
@@ -0,0 +1,20 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\CatalogInventory\Model\ResourceModel\Indexer\Stock;
+
+use Magento\Framework\DB\Select;
+
+interface QueryProcessorInterface
+{
+    /**
+     * @param Select $select
+     * @param null|array $entityIds
+     * @param bool $usePrimaryTable
+     * @return Select
+     */
+    public function processQuery(Select $select, $entityIds = null, $usePrimaryTable = false);
+}
diff --git a/app/code/Magento/CatalogInventory/Model/ResourceModel/Stock/Status.php b/app/code/Magento/CatalogInventory/Model/ResourceModel/Stock/Status.php
index be7e1ff2d1b64487e09ac206d40f6deecfb15f90..5fe199905837b553d16f02fb01bf4be5a07c01be 100644
--- a/app/code/Magento/CatalogInventory/Model/ResourceModel/Stock/Status.php
+++ b/app/code/Magento/CatalogInventory/Model/ResourceModel/Stock/Status.php
@@ -198,12 +198,45 @@ class Status extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb
         $select->joinLeft(
             ['stock_status' => $this->getMainTable()],
             'e.entity_id = stock_status.product_id AND stock_status.website_id=' . $websiteId,
-            ['salable' => 'stock_status.stock_status']
+            ['is_salable' => 'stock_status.stock_status']
         );
 
         return $this;
     }
 
+    /**
+     * @param \Magento\Catalog\Model\ResourceModel\Product\Collection $collection
+     * @param bool $isFilterInStock
+     * @return \Magento\Catalog\Model\ResourceModel\Product\Collection $collection
+     */
+    public function addStockDataToCollection($collection, $isFilterInStock)
+    {
+        $websiteId = $this->_storeManager->getStore($collection->getStoreId())->getWebsiteId();
+        $joinCondition = $this->getConnection()->quoteInto(
+            'e.entity_id = stock_status_index.product_id' . ' AND stock_status_index.website_id = ?',
+            $websiteId
+        );
+
+        $joinCondition .= $this->getConnection()->quoteInto(
+            ' AND stock_status_index.stock_id = ?',
+            Stock::DEFAULT_STOCK_ID
+        );
+
+        $collection->getSelect()->join(
+            ['stock_status_index' => $this->getMainTable()],
+            $joinCondition,
+            ['is_salable' => 'stock_status']
+        );
+
+        if ($isFilterInStock) {
+            $collection->getSelect()->where(
+                'stock_status_index.stock_status = ?',
+                Stock\Status::STATUS_IN_STOCK
+            );
+        }
+        return $collection;
+    }
+
     /**
      * Add only is in stock products filter to product collection
      *
diff --git a/app/code/Magento/CatalogInventory/Model/Stock/StockItemRepository.php b/app/code/Magento/CatalogInventory/Model/Stock/StockItemRepository.php
index b6eeea162c63d9efa13d09ce264fc5be75e234a8..8af927b7b893cd2d783ba0f4bc93b517cf460645 100644
--- a/app/code/Magento/CatalogInventory/Model/Stock/StockItemRepository.php
+++ b/app/code/Magento/CatalogInventory/Model/Stock/StockItemRepository.php
@@ -14,6 +14,7 @@ use Magento\CatalogInventory\Api\StockItemRepositoryInterface as StockItemReposi
 use Magento\CatalogInventory\Model\Indexer\Stock\Processor;
 use Magento\CatalogInventory\Model\ResourceModel\Stock\Item as StockItemResource;
 use Magento\CatalogInventory\Model\Spi\StockStateProviderInterface;
+use Magento\CatalogInventory\Model\StockRegistryStorage;
 use Magento\Framework\DB\MapperFactory;
 use Magento\Framework\DB\QueryBuilderFactory;
 use Magento\Framework\Exception\CouldNotDeleteException;
@@ -83,6 +84,11 @@ class StockItemRepository implements StockItemRepositoryInterface
      */
     protected $dateTime;
 
+    /**
+     * @var StockRegistryStorage
+     */
+    protected $stockRegistryStorage;
+
     /**
      * @param StockConfigurationInterface $stockConfiguration
      * @param StockStateProviderInterface $stockStateProvider
@@ -95,6 +101,7 @@ class StockItemRepository implements StockItemRepositoryInterface
      * @param TimezoneInterface $localeDate
      * @param Processor $indexProcessor
      * @param DateTime $dateTime
+     * @param StockRegistryStorage $stockRegistryStorage
      * @SuppressWarnings(PHPMD.ExcessiveParameterList)
      */
     public function __construct(
@@ -108,7 +115,8 @@ class StockItemRepository implements StockItemRepositoryInterface
         MapperFactory $mapperFactory,
         TimezoneInterface $localeDate,
         Processor $indexProcessor,
-        DateTime $dateTime
+        DateTime $dateTime,
+        StockRegistryStorage $stockRegistryStorage
     ) {
         $this->stockConfiguration = $stockConfiguration;
         $this->stockStateProvider = $stockStateProvider;
@@ -118,10 +126,10 @@ class StockItemRepository implements StockItemRepositoryInterface
         $this->productFactory = $productFactory;
         $this->queryBuilderFactory = $queryBuilderFactory;
         $this->mapperFactory = $mapperFactory;
-        $this->mapperFactory = $mapperFactory;
         $this->localeDate = $localeDate;
         $this->indexProcessor = $indexProcessor;
         $this->dateTime = $dateTime;
+        $this->stockRegistryStorage = $stockRegistryStorage;
     }
 
     /**
@@ -163,7 +171,7 @@ class StockItemRepository implements StockItemRepositoryInterface
 
             $this->indexProcessor->reindexRow($stockItem->getProductId());
         } catch (\Exception $exception) {
-            throw new CouldNotSaveException(__($exception->getMessage()));
+            throw new CouldNotSaveException(__('Unable to save Stock Item'), $exception);
         }
         return $stockItem;
     }
@@ -201,8 +209,13 @@ class StockItemRepository implements StockItemRepositoryInterface
     {
         try {
             $this->resource->delete($stockItem);
+            $this->stockRegistryStorage->removeStockItem($stockItem->getProductId());
+            $this->stockRegistryStorage->removeStockStatus($stockItem->getProductId());
         } catch (\Exception $exception) {
-            throw new CouldNotDeleteException(__($exception->getMessage()));
+            throw new CouldNotDeleteException(
+                __('Unable to remove Stock Item with id "%1"', $stockItem->getItemId()),
+                $exception
+            );
         }
         return true;
     }
@@ -216,7 +229,10 @@ class StockItemRepository implements StockItemRepositoryInterface
             $stockItem = $this->get($id);
             $this->delete($stockItem);
         } catch (\Exception $exception) {
-            throw new CouldNotDeleteException(__($exception->getMessage()));
+            throw new CouldNotDeleteException(
+                __('Unable to remove Stock Item with id "%1"', $id),
+                $exception
+            );
         }
         return true;
     }
diff --git a/app/code/Magento/CatalogInventory/Model/Stock/StockRepository.php b/app/code/Magento/CatalogInventory/Model/Stock/StockRepository.php
index ceff54964d77e7211b4c9a89487e5bc61f354d6b..e76b239876ae6ba61ece6ff0d973af1b01687600 100644
--- a/app/code/Magento/CatalogInventory/Model/Stock/StockRepository.php
+++ b/app/code/Magento/CatalogInventory/Model/Stock/StockRepository.php
@@ -10,6 +10,7 @@ use Magento\CatalogInventory\Api\Data\StockInterface;
 use Magento\CatalogInventory\Api\StockRepositoryInterface;
 use Magento\CatalogInventory\Model\ResourceModel\Stock as StockResource;
 use Magento\CatalogInventory\Model\StockFactory;
+use Magento\CatalogInventory\Model\StockRegistryStorage;
 use Magento\Framework\DB\MapperFactory;
 use Magento\Framework\DB\QueryBuilderFactory;
 use Magento\Framework\Exception\CouldNotDeleteException;
@@ -47,25 +48,33 @@ class StockRepository implements StockRepositoryInterface
      */
     protected $mapperFactory;
 
+    /**
+     * @var StockRegistryStorage
+     */
+    protected $stockRegistryStorage;
+
     /**
      * @param StockResource $resource
      * @param StockFactory $stockFactory
      * @param StockCollectionInterfaceFactory $collectionFactory
      * @param QueryBuilderFactory $queryBuilderFactory
      * @param MapperFactory $mapperFactory
+     * @param StockRegistryStorage $stockRegistryStorage
      */
     public function __construct(
         StockResource $resource,
         StockFactory $stockFactory,
         StockCollectionInterfaceFactory $collectionFactory,
         QueryBuilderFactory $queryBuilderFactory,
-        MapperFactory $mapperFactory
+        MapperFactory $mapperFactory,
+        StockRegistryStorage $stockRegistryStorage
     ) {
         $this->resource = $resource;
         $this->stockFactory = $stockFactory;
         $this->stockCollectionFactory = $collectionFactory;
         $this->queryBuilderFactory = $queryBuilderFactory;
         $this->mapperFactory = $mapperFactory;
+        $this->stockRegistryStorage = $stockRegistryStorage;
     }
 
     /**
@@ -78,7 +87,7 @@ class StockRepository implements StockRepositoryInterface
         try {
             $this->resource->save($stock);
         } catch (\Exception $exception) {
-            throw new CouldNotSaveException(__($exception->getMessage()));
+            throw new CouldNotSaveException(__('Unable to save Stock'), $exception);
         }
         return $stock;
     }
@@ -121,8 +130,12 @@ class StockRepository implements StockRepositoryInterface
     {
         try {
             $this->resource->delete($stock);
+            $this->stockRegistryStorage->removeStock();
         } catch (\Exception $exception) {
-            throw new CouldNotDeleteException(__($exception->getMessage()));
+            throw new CouldNotDeleteException(
+                __('Unable to remove Stock with id "%1"', $stock->getStockId()),
+                $exception
+            );
         }
         return true;
     }
@@ -138,7 +151,10 @@ class StockRepository implements StockRepositoryInterface
             $stock = $this->get($id);
             $this->delete($stock);
         } catch (\Exception $exception) {
-            throw new CouldNotDeleteException(__($exception->getMessage()));
+            throw new CouldNotDeleteException(
+                __('Unable to remove Stock with id "%1"', $id),
+                $exception
+            );
         }
         return true;
     }
diff --git a/app/code/Magento/CatalogInventory/Model/Stock/StockStatusRepository.php b/app/code/Magento/CatalogInventory/Model/Stock/StockStatusRepository.php
index 04f845ed0cd2a2bcacbf1ea38309c4170639564a..3e20bbf5927eda85524dc7e3a33830d5de073da5 100644
--- a/app/code/Magento/CatalogInventory/Model/Stock/StockStatusRepository.php
+++ b/app/code/Magento/CatalogInventory/Model/Stock/StockStatusRepository.php
@@ -9,6 +9,7 @@ use Magento\CatalogInventory\Api\Data\StockStatusCollectionInterfaceFactory;
 use Magento\CatalogInventory\Api\Data\StockStatusInterface;
 use Magento\CatalogInventory\Api\StockStatusRepositoryInterface;
 use Magento\CatalogInventory\Model\ResourceModel\Stock\Status as StockStatusResource;
+use Magento\CatalogInventory\Model\StockRegistryStorage;
 use Magento\Framework\DB\MapperFactory;
 use Magento\Framework\DB\QueryBuilderFactory;
 use Magento\Framework\Exception\CouldNotDeleteException;
@@ -45,25 +46,33 @@ class StockStatusRepository implements StockStatusRepositoryInterface
      */
     protected $mapperFactory;
 
+    /**
+     * @var StockRegistryStorage
+     */
+    protected $stockRegistryStorage;
+
     /**
      * @param StockStatusResource $resource
      * @param StatusFactory $stockStatusFactory
      * @param StockStatusCollectionInterfaceFactory $collectionFactory
      * @param QueryBuilderFactory $queryBuilderFactory
      * @param MapperFactory $mapperFactory
+     * @param StockRegistryStorage $stockRegistryStorage
      */
     public function __construct(
         StockStatusResource $resource,
         StatusFactory $stockStatusFactory,
         StockStatusCollectionInterfaceFactory $collectionFactory,
         QueryBuilderFactory $queryBuilderFactory,
-        MapperFactory $mapperFactory
+        MapperFactory $mapperFactory,
+        StockRegistryStorage $stockRegistryStorage
     ) {
         $this->resource = $resource;
         $this->stockStatusFactory = $stockStatusFactory;
         $this->stockStatusCollectionFactory = $collectionFactory;
         $this->queryBuilderFactory = $queryBuilderFactory;
         $this->mapperFactory = $mapperFactory;
+        $this->stockRegistryStorage = $stockRegistryStorage;
     }
 
     /**
@@ -76,7 +85,7 @@ class StockStatusRepository implements StockStatusRepositoryInterface
         try {
             $this->resource->save($stockStatus);
         } catch (\Exception $exception) {
-            throw new CouldNotSaveException(__($exception->getMessage()));
+            throw new CouldNotSaveException(__('Unable to save Stock Status'), $exception);
         }
         return $stockStatus;
     }
@@ -115,8 +124,12 @@ class StockStatusRepository implements StockStatusRepositoryInterface
     {
         try {
             $this->resource->delete($stockStatus);
+            $this->stockRegistryStorage->removeStockStatus($stockStatus->getProductId());
         } catch (\Exception $exception) {
-            throw new CouldNotDeleteException(__($exception->getMessage()));
+            throw new CouldNotDeleteException(
+                __('Unable to remove Stock Status for product %1', $stockStatus->getProductId()),
+                $exception
+            );
         }
         return true;
     }
@@ -132,7 +145,10 @@ class StockStatusRepository implements StockStatusRepositoryInterface
             $stockStatus = $this->get($id);
             $this->delete($stockStatus);
         } catch (\Exception $exception) {
-            throw new CouldNotDeleteException(__($exception->getMessage()));
+            throw new CouldNotDeleteException(
+                __('Unable to remove Stock Status for product %1', $id),
+                $exception
+            );
         }
         return true;
     }
diff --git a/app/code/Magento/CatalogInventory/Model/StockRegistryProvider.php b/app/code/Magento/CatalogInventory/Model/StockRegistryProvider.php
index e8f7ae5cc723fb8219aaf9990c1d23017cb35b4e..87e91c863220b4cd4be87f16406d54cd01691497 100644
--- a/app/code/Magento/CatalogInventory/Model/StockRegistryProvider.php
+++ b/app/code/Magento/CatalogInventory/Model/StockRegistryProvider.php
@@ -69,19 +69,9 @@ class StockRegistryProvider implements StockRegistryProviderInterface
     protected $stockStatusCriteriaFactory;
 
     /**
-     * @var array
+     * @var StockRegistryStorage
      */
-    protected $stocks = [];
-
-    /**
-     * @var array
-     */
-    protected $stockItems = [];
-
-    /**
-     * @var array
-     */
-    protected $stockStatuses = [];
+    protected $stockRegistryStorage;
 
     /**
      * @param StockRepositoryInterface $stockRepository
@@ -93,6 +83,8 @@ class StockRegistryProvider implements StockRegistryProviderInterface
      * @param StockCriteriaInterfaceFactory $stockCriteriaFactory
      * @param StockItemCriteriaInterfaceFactory $stockItemCriteriaFactory
      * @param StockStatusCriteriaInterfaceFactory $stockStatusCriteriaFactory
+     * @param StockRegistryStorage $stockRegistryStorage
+     * @SuppressWarnings(PHPMD.ExcessiveParameterList)
      */
     public function __construct(
         StockRepositoryInterface $stockRepository,
@@ -103,7 +95,8 @@ class StockRegistryProvider implements StockRegistryProviderInterface
         StockStatusInterfaceFactory $stockStatusFactory,
         StockCriteriaInterfaceFactory $stockCriteriaFactory,
         StockItemCriteriaInterfaceFactory $stockItemCriteriaFactory,
-        StockStatusCriteriaInterfaceFactory $stockStatusCriteriaFactory
+        StockStatusCriteriaInterfaceFactory $stockStatusCriteriaFactory,
+        StockRegistryStorage $stockRegistryStorage
     ) {
         $this->stockRepository = $stockRepository;
         $this->stockFactory = $stockFactory;
@@ -111,10 +104,10 @@ class StockRegistryProvider implements StockRegistryProviderInterface
         $this->stockItemFactory = $stockItemFactory;
         $this->stockStatusRepository = $stockStatusRepository;
         $this->stockStatusFactory = $stockStatusFactory;
-
         $this->stockCriteriaFactory = $stockCriteriaFactory;
         $this->stockItemCriteriaFactory = $stockItemCriteriaFactory;
         $this->stockStatusCriteriaFactory = $stockStatusCriteriaFactory;
+        $this->stockRegistryStorage = $stockRegistryStorage;
     }
 
     /**
@@ -123,18 +116,19 @@ class StockRegistryProvider implements StockRegistryProviderInterface
      */
     public function getStock($scopeId)
     {
-        if (!isset($this->stocks[$scopeId])) {
+        $stock = $this->stockRegistryStorage->getStock($scopeId);
+        if (null === $stock) {
             $criteria = $this->stockCriteriaFactory->create();
             $criteria->setScopeFilter($scopeId);
             $collection = $this->stockRepository->getList($criteria);
             $stock = current($collection->getItems());
             if ($stock && $stock->getStockId()) {
-                $this->stocks[$scopeId] = $stock;
+                $this->stockRegistryStorage->setStock($scopeId, $stock);
             } else {
-                return $this->stockFactory->create();
+                $stock = $this->stockFactory->create();
             }
         }
-        return $this->stocks[$scopeId];
+        return $stock;
     }
 
     /**
@@ -144,19 +138,19 @@ class StockRegistryProvider implements StockRegistryProviderInterface
      */
     public function getStockItem($productId, $scopeId)
     {
-        $key = $scopeId . '/' . $productId;
-        if (!isset($this->stockItems[$key])) {
+        $stockItem = $this->stockRegistryStorage->getStockItem($productId, $scopeId);
+        if (null === $stockItem) {
             $criteria = $this->stockItemCriteriaFactory->create();
             $criteria->setProductsFilter($productId);
             $collection = $this->stockItemRepository->getList($criteria);
             $stockItem = current($collection->getItems());
             if ($stockItem && $stockItem->getItemId()) {
-                $this->stockItems[$key] = $stockItem;
+                $this->stockRegistryStorage->setStockItem($productId, $scopeId, $stockItem);
             } else {
-                return $this->stockItemFactory->create();
+                $stockItem = $this->stockItemFactory->create();
             }
         }
-        return $this->stockItems[$key];
+        return $stockItem;
     }
 
     /**
@@ -166,19 +160,19 @@ class StockRegistryProvider implements StockRegistryProviderInterface
      */
     public function getStockStatus($productId, $scopeId)
     {
-        $key = $scopeId . '/' . $productId;
-        if (!isset($this->stockStatuses[$key])) {
+        $stockStatus = $this->stockRegistryStorage->getStockStatus($productId, $scopeId);
+        if (null === $stockStatus) {
             $criteria = $this->stockStatusCriteriaFactory->create();
             $criteria->setProductsFilter($productId);
             $criteria->setScopeFilter($scopeId);
             $collection = $this->stockStatusRepository->getList($criteria);
             $stockStatus = current($collection->getItems());
             if ($stockStatus && $stockStatus->getProductId()) {
-                $this->stockStatuses[$key] = $stockStatus;
+                $this->stockRegistryStorage->setStockStatus($productId, $scopeId, $stockStatus);
             } else {
-                return $this->stockStatusFactory->create();
+                $stockStatus = $this->stockStatusFactory->create();
             }
         }
-        return $this->stockStatuses[$key];
+        return $stockStatus;
     }
 }
diff --git a/app/code/Magento/CatalogInventory/Model/StockRegistryStorage.php b/app/code/Magento/CatalogInventory/Model/StockRegistryStorage.php
new file mode 100644
index 0000000000000000000000000000000000000000..b7c29e7fc9aa163d0ea8142348d7a28d0a37b310
--- /dev/null
+++ b/app/code/Magento/CatalogInventory/Model/StockRegistryStorage.php
@@ -0,0 +1,133 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\CatalogInventory\Model;
+
+use Magento\CatalogInventory\Api\Data\StockInterface;
+use Magento\CatalogInventory\Api\Data\StockItemInterface;
+use Magento\CatalogInventory\Api\Data\StockStatusInterface;
+
+/**
+ * Class StockRegistryStorage
+ */
+class StockRegistryStorage
+{
+    /**
+     * @var array
+     */
+    protected $stocks = [];
+
+    /**
+     * @var array
+     */
+    private $stockItems = [];
+
+    /**
+     * @var array
+     */
+    private $stockStatuses = [];
+
+    /**
+     * @param int $scopeId
+     * @return StockInterface
+     */
+    public function getStock($scopeId)
+    {
+        return isset($this->stocks[$scopeId]) ? $this->stocks[$scopeId] : null;
+    }
+
+    /**
+     * @param int $scopeId
+     * @param StockInterface $value
+     * @return void
+     */
+    public function setStock($scopeId, StockInterface $value)
+    {
+        $this->stocks[$scopeId] = $value;
+    }
+
+    /**
+     * @param int|null $scopeId
+     * @return void
+     */
+    public function removeStock($scopeId = null)
+    {
+        if (null === $scopeId) {
+            $this->stocks = [];
+        } else {
+            unset($this->stocks[$scopeId]);
+        }
+    }
+
+    /**
+     * @param int $productId
+     * @param int $scopeId
+     * @return StockItemInterface
+     */
+    public function getStockItem($productId, $scopeId)
+    {
+        return isset($this->stockItems[$productId][$scopeId]) ? $this->stockItems[$productId][$scopeId] : null;
+    }
+
+    /**
+     * @param int $productId
+     * @param int $scopeId
+     * @param StockItemInterface $value
+     * @return void
+     */
+    public function setStockItem($productId, $scopeId, StockItemInterface $value)
+    {
+        $this->stockItems[$productId][$scopeId] = $value;
+    }
+
+    /**
+     * @param int $productId
+     * @param int|null $scopeId
+     * @return void
+     */
+    public function removeStockItem($productId, $scopeId = null)
+    {
+        if (null === $scopeId) {
+            unset($this->stockItems[$productId]);
+        } else {
+            unset($this->stockItems[$productId][$scopeId]);
+        }
+    }
+
+    /**
+     * @param int $productId
+     * @param int $scopeId
+     * @return StockStatusInterface
+     */
+    public function getStockStatus($productId, $scopeId)
+    {
+        return isset($this->stockStatuses[$productId][$scopeId]) ? $this->stockStatuses[$productId][$scopeId] : null;
+    }
+
+    /**
+     * @param int $productId
+     * @param int $scopeId
+     * @param StockStatusInterface $value
+     * @return void
+     */
+    public function setStockStatus($productId, $scopeId, StockStatusInterface $value)
+    {
+        $this->stockStatuses[$productId][$scopeId] = $value;
+    }
+
+    /**
+     * @param int $productId
+     * @param int|null $scopeId
+     * @return void
+     */
+    public function removeStockStatus($productId, $scopeId = null)
+    {
+        if (null === $scopeId) {
+            unset($this->stockStatuses[$productId]);
+        } else {
+            unset($this->stockStatuses[$productId][$scopeId]);
+        }
+    }
+}
diff --git a/app/code/Magento/CatalogInventory/Model/StockState.php b/app/code/Magento/CatalogInventory/Model/StockState.php
index c3d0dc9aef0fd317d0d69e8b1b06b01b5af4f7e7..96b3162966211b4c21d0e206a12246b91b092777 100644
--- a/app/code/Magento/CatalogInventory/Model/StockState.php
+++ b/app/code/Magento/CatalogInventory/Model/StockState.php
@@ -146,7 +146,7 @@ class StockState implements StockStateInterface
      * @param float $qtyToCheck
      * @param float $origQty
      * @param int $scopeId
-     * @return \Magento\Framework\DataObject
+     * @return int
      */
     public function checkQuoteItemQty($productId, $itemQty, $qtyToCheck, $origQty, $scopeId = null)
     {
diff --git a/app/code/Magento/CatalogInventory/Observer/AddStockStatusToCollectionObserver.php b/app/code/Magento/CatalogInventory/Observer/AddStockStatusToCollectionObserver.php
deleted file mode 100644
index e777f81ba68425cce30934f2852771aac7acfec5..0000000000000000000000000000000000000000
--- a/app/code/Magento/CatalogInventory/Observer/AddStockStatusToCollectionObserver.php
+++ /dev/null
@@ -1,42 +0,0 @@
-<?php
-/**
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-
-namespace Magento\CatalogInventory\Observer;
-
-use Magento\Framework\Event\ObserverInterface;
-use Magento\Framework\Event\Observer as EventObserver;
-
-/**
- * Catalog inventory module observer
- */
-class AddStockStatusToCollectionObserver implements ObserverInterface
-{
-    /**
-     * @var \Magento\CatalogInventory\Helper\Stock
-     */
-    protected $stockHelper;
-
-    /**
-     * @param \Magento\CatalogInventory\Helper\Stock $stockHelper
-     */
-    public function __construct(\Magento\CatalogInventory\Helper\Stock $stockHelper)
-    {
-        $this->stockHelper = $stockHelper;
-    }
-
-    /**
-     * Add information about product stock status to collection
-     * Used in for product collection after load
-     *
-     * @param EventObserver $observer
-     * @return void
-     */
-    public function execute(EventObserver $observer)
-    {
-        $productCollection = $observer->getEvent()->getCollection();
-        $this->stockHelper->addStockStatusToProducts($productCollection);
-    }
-}
diff --git a/app/code/Magento/CatalogInventory/Test/Unit/Block/Stockqty/DefaultStockqtyTest.php b/app/code/Magento/CatalogInventory/Test/Unit/Block/Stockqty/DefaultStockqtyTest.php
index fd247ef871523bf14f3ee2480af22f3c648d6627..5c9396d32bfb526d7bd3da92856c00513f3c01ba 100644
--- a/app/code/Magento/CatalogInventory/Test/Unit/Block/Stockqty/DefaultStockqtyTest.php
+++ b/app/code/Magento/CatalogInventory/Test/Unit/Block/Stockqty/DefaultStockqtyTest.php
@@ -20,11 +20,6 @@ class DefaultStockqtyTest extends \PHPUnit_Framework_TestCase
      */
     protected $registryMock;
 
-    /**
-     * @var \Magento\CatalogInventory\Api\StockStateInterface|\PHPUnit_Framework_MockObject_MockObject
-     */
-    protected $stockState;
-
     /**
      * @var \PHPUnit_Framework_MockObject_MockObject
      */
@@ -39,13 +34,6 @@ class DefaultStockqtyTest extends \PHPUnit_Framework_TestCase
     {
         $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
         $this->registryMock = $this->getMock('Magento\Framework\Registry', [], [], '', false);
-        $this->stockState = $this->getMock(
-            'Magento\CatalogInventory\Api\StockStateInterface',
-            [],
-            [],
-            '',
-            false
-        );
         $this->stockRegistryMock = $this->getMockBuilder('Magento\CatalogInventory\Api\StockRegistryInterface')
             ->disableOriginalConstructor()
             ->getMock();
@@ -56,7 +44,6 @@ class DefaultStockqtyTest extends \PHPUnit_Framework_TestCase
             'Magento\CatalogInventory\Block\Stockqty\DefaultStockqty',
             [
                 'registry' => $this->registryMock,
-                'stockState' => $this->stockState,
                 'stockRegistry' => $this->stockRegistryMock,
                 'scopeConfig' => $this->scopeConfigMock
             ]
@@ -112,10 +99,13 @@ class DefaultStockqtyTest extends \PHPUnit_Framework_TestCase
                 ->will($this->returnValue($product));
 
             if ($productId) {
-                $this->stockState->expects($this->once())
-                    ->method('getStockQty')
+                $stockStatus = $this->getMockBuilder(\Magento\CatalogInventory\Api\Data\StockStatusInterface::class)
+                    ->getMockForAbstractClass();
+                $stockStatus->expects($this->any())->method('getQty')->willReturn($productStockQty);
+                $this->stockRegistryMock->expects($this->once())
+                    ->method('getStockStatus')
                     ->with($this->equalTo($productId), $this->equalTo($websiteId))
-                    ->will($this->returnValue($productStockQty));
+                    ->will($this->returnValue($stockStatus));
             }
         }
         $this->assertSame($expectedQty, $this->block->getStockQty());
@@ -157,10 +147,6 @@ class DefaultStockqtyTest extends \PHPUnit_Framework_TestCase
             ->method('getStockItem')
             ->with($productId)
             ->willReturn($stockItemMock);
-        $this->stockState->expects($this->once())
-            ->method('getStockQty')
-            ->with($productId, $storeMock)
-            ->willReturn($stockQty);
 
         $this->assertEquals($stockQty, $this->block->getStockQtyLeft());
     }
diff --git a/app/code/Magento/CatalogInventory/Test/Unit/Helper/StockTest.php b/app/code/Magento/CatalogInventory/Test/Unit/Helper/StockTest.php
index cb4209de616e798498590461c9db2e3e1891657d..01356277c5acf1f1a99f8ddfd374d85daabe6332 100644
--- a/app/code/Magento/CatalogInventory/Test/Unit/Helper/StockTest.php
+++ b/app/code/Magento/CatalogInventory/Test/Unit/Helper/StockTest.php
@@ -182,10 +182,10 @@ class StockTest extends \PHPUnit_Framework_TestCase
             ->getMock();
         $stockStatusMock = $this->getMockBuilder('Magento\CatalogInventory\Model\ResourceModel\Stock\Status')
             ->disableOriginalConstructor()
-            ->setMethods(['addIsInStockFilterToCollection'])
+            ->setMethods(['addStockDataToCollection'])
             ->getMock();
         $stockStatusMock->expects($this->once())
-            ->method('addIsInStockFilterToCollection')
+            ->method('addStockDataToCollection')
             ->with($collectionMock);
         $this->statusFactoryMock->expects($this->once())
             ->method('create')
diff --git a/app/code/Magento/CatalogInventory/Test/Unit/Model/AddStockStatusToCollectionTest.php b/app/code/Magento/CatalogInventory/Test/Unit/Model/AddStockStatusToCollectionTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..9d1796cbe117e781d7a88ca76cc4dd058fcece8b
--- /dev/null
+++ b/app/code/Magento/CatalogInventory/Test/Unit/Model/AddStockStatusToCollectionTest.php
@@ -0,0 +1,46 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\CatalogInventory\Test\Unit\Model;
+
+use Magento\CatalogInventory\Model\AddStockStatusToCollection;
+
+class AddStockStatusToCollectionTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var AddStockStatusToCollection
+     */
+    protected $plugin;
+
+    /**
+     * @var \Magento\CatalogInventory\Helper\Stock|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $stockHelper;
+
+    protected function setUp()
+    {
+        $this->stockHelper = $this->getMock('Magento\CatalogInventory\Helper\Stock', [], [], '', false);
+        $this->plugin = (new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this))->getObject(
+            'Magento\CatalogInventory\Model\AddStockStatusToCollection',
+            [
+                'stockHelper' => $this->stockHelper,
+            ]
+        );
+    }
+
+    public function testAddStockStatusToCollection()
+    {
+        $productCollection = $this->getMockBuilder('Magento\Catalog\Model\ResourceModel\Product\Collection')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->stockHelper->expects($this->once())
+            ->method('addIsInStockFilterToCollection')
+            ->with($productCollection)
+            ->will($this->returnSelf());
+
+        $this->plugin->beforeLoad($productCollection);
+    }
+}
diff --git a/app/code/Magento/CatalogInventory/Test/Unit/Model/Stock/StockItemRepositoryTest.php b/app/code/Magento/CatalogInventory/Test/Unit/Model/Stock/StockItemRepositoryTest.php
index a2db32bdb642a6c50223fe5812047431f2861fb3..76c6e6cf923c563d158d3b72503333f9b35af07b 100644
--- a/app/code/Magento/CatalogInventory/Test/Unit/Model/Stock/StockItemRepositoryTest.php
+++ b/app/code/Magento/CatalogInventory/Test/Unit/Model/Stock/StockItemRepositoryTest.php
@@ -5,8 +5,10 @@
  */
 namespace Magento\CatalogInventory\Test\Unit\Model\Stock;
 
-use \Magento\CatalogInventory\Model\Stock\StockItemRepository;
-use \Magento\CatalogInventory\Api\Data as InventoryApiData;
+use Magento\CatalogInventory\Model\Stock\StockItemRepository;
+use Magento\CatalogInventory\Api\Data as InventoryApiData;
+use Magento\CatalogInventory\Model\StockRegistryStorage;
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
 
 /**
  * Class StockItemRepositoryTest
@@ -24,6 +26,7 @@ class StockItemRepositoryTest extends \PHPUnit_Framework_TestCase
      * @var \Magento\CatalogInventory\Model\Stock\Item |\PHPUnit_Framework_MockObject_MockObject
      */
     protected $stockItemMock;
+
     /**
      * @var \Magento\CatalogInventory\Api\StockConfigurationInterface|\PHPUnit_Framework_MockObject_MockObject
      */
@@ -84,6 +87,14 @@ class StockItemRepositoryTest extends \PHPUnit_Framework_TestCase
      */
     protected $dateTime;
 
+    /**
+     * @var StockRegistryStorage|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $stockRegistryStorage;
+
+    /**
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+     */
     protected function setUp()
     {
         $this->stockItemMock = $this->getMockBuilder('\Magento\CatalogInventory\Model\Stock\Item')
@@ -168,24 +179,36 @@ class StockItemRepositoryTest extends \PHPUnit_Framework_TestCase
             '',
             false
         );
+        $this->stockRegistryStorage = $this->getMockBuilder(StockRegistryStorage::class)
+            ->disableOriginalConstructor()
+            ->getMock();
 
-        $this->model = new StockItemRepository(
-            $this->stockConfigurationMock,
-            $this->stockStateProviderMock,
-            $this->stockItemResourceMock,
-            $this->stockItemFactoryMock,
-            $this->stockItemCollectionMock,
-            $this->productFactoryMock,
-            $this->queryBuilderFactoryMock,
-            $this->mapperMock,
-            $this->localeDateMock,
-            $this->indexProcessorMock,
-            $this->dateTime
+        $this->model = (new ObjectManager($this))->getObject(
+            StockItemRepository::class,
+            [
+                'stockConfiguration' => $this->stockConfigurationMock,
+                'stockStateProvider' => $this->stockStateProviderMock,
+                'resource' => $this->stockItemResourceMock,
+                'stockItemFactory' => $this->stockItemFactoryMock,
+                'stockItemCollectionFactory' => $this->stockItemCollectionMock,
+                'productFactory' => $this->productFactoryMock,
+                'queryBuilderFactory' => $this->queryBuilderFactoryMock,
+                'mapperFactory' => $this->mapperMock,
+                'localeDate' => $this->localeDateMock,
+                'indexProcessor' => $this->indexProcessorMock,
+                'dateTime' => $this->dateTime,
+                'stockRegistryStorage' => $this->stockRegistryStorage,
+            ]
         );
     }
 
     public function testDelete()
     {
+        $productId = 1;
+        $this->stockItemMock->expects($this->atLeastOnce())->method('getProductId')->willReturn($productId);
+        $this->stockRegistryStorage->expects($this->once())->method('removeStockItem')->with($productId);
+        $this->stockRegistryStorage->expects($this->once())->method('removeStockStatus')->with($productId);
+
         $this->stockItemResourceMock->expects($this->once())
             ->method('delete')
             ->with($this->stockItemMock)
@@ -220,7 +243,7 @@ class StockItemRepositoryTest extends \PHPUnit_Framework_TestCase
 
     /**
      * @expectedException \Magento\Framework\Exception\CouldNotDeleteException
-     * @expectedExceptionMessage Stock Item with id "1" does not exist.
+     * @expectedExceptionMessage Unable to remove Stock Item with id "1"
      */
     public function testDeleteByIdException()
     {
@@ -286,6 +309,8 @@ class StockItemRepositoryTest extends \PHPUnit_Framework_TestCase
         $this->stockItemMock->expects($this->any())->method('getProductId')->willReturn($productId);
         $this->productMock->expects($this->once())->method('load')->with($productId)->willReturnSelf();
         $this->productMock->expects($this->once())->method('getId')->willReturn(null);
+        $this->stockRegistryStorage->expects($this->never())->method('removeStockItem');
+        $this->stockRegistryStorage->expects($this->never())->method('removeStockStatus');
 
         $this->assertEquals($this->stockItemMock, $this->model->save($this->stockItemMock));
     }
diff --git a/app/code/Magento/CatalogInventory/Test/Unit/Model/Stock/StockRepositoryTest.php b/app/code/Magento/CatalogInventory/Test/Unit/Model/Stock/StockRepositoryTest.php
index 3e9394a3995e53102bae88c0496080f15af113c3..779958ccf4c20fc650489926e4a907ac4d630bca 100644
--- a/app/code/Magento/CatalogInventory/Test/Unit/Model/Stock/StockRepositoryTest.php
+++ b/app/code/Magento/CatalogInventory/Test/Unit/Model/Stock/StockRepositoryTest.php
@@ -5,7 +5,9 @@
  */
 namespace Magento\CatalogInventory\Test\Unit\Model\Stock;
 
-use \Magento\CatalogInventory\Model\Stock\StockRepository;
+use Magento\CatalogInventory\Model\Stock\StockRepository;
+use Magento\CatalogInventory\Model\StockRegistryStorage;
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
 
 /**
  * Class StockRepositoryTest
@@ -47,9 +49,13 @@ class StockRepositoryTest extends \PHPUnit_Framework_TestCase
      */
     protected $mapperMock;
 
+    /**
+     * @var StockRegistryStorage|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $stockRegistryStorage;
+
     protected function setUp()
     {
-
         $this->stockMock = $this->getMockBuilder('\Magento\CatalogInventory\Model\Stock')
             ->disableOriginalConstructor()
             ->getMock();
@@ -77,13 +83,20 @@ class StockRepositoryTest extends \PHPUnit_Framework_TestCase
         $this->mapperMock = $this->getMockBuilder('Magento\Framework\DB\MapperFactory')
             ->disableOriginalConstructor()
             ->getMock();
+        $this->stockRegistryStorage = $this->getMockBuilder(StockRegistryStorage::class)
+            ->disableOriginalConstructor()
+            ->getMock();
 
-        $this->model = new StockRepository(
-            $this->stockResourceMock,
-            $this->stockFactoryMock,
-            $this->stockCollectionMock,
-            $this->queryBuilderFactoryMock,
-            $this->mapperMock
+        $this->model = (new ObjectManager($this))->getObject(
+            StockRepository::class,
+            [
+                'resource' => $this->stockResourceMock,
+                'stockFactory' => $this->stockFactoryMock,
+                'collectionFactory' => $this->stockCollectionMock,
+                'queryBuilderFactory' => $this->queryBuilderFactoryMock,
+                'mapperFactory' => $this->mapperMock,
+                'stockRegistryStorage' => $this->stockRegistryStorage,
+            ]
         );
     }
 
@@ -137,6 +150,8 @@ class StockRepositoryTest extends \PHPUnit_Framework_TestCase
 
     public function testDelete()
     {
+        $this->stockRegistryStorage->expects($this->once())->method('removeStock');
+
         $this->stockResourceMock->expects($this->once())
             ->method('delete')
             ->with($this->stockMock)
@@ -171,7 +186,7 @@ class StockRepositoryTest extends \PHPUnit_Framework_TestCase
 
     /**
      * @expectedException \Magento\Framework\Exception\CouldNotDeleteException
-     * @expectedExceptionMessage Stock with id "1" does not exist.
+     * @expectedExceptionMessage Unable to remove Stock with id "1"
      */
     public function testDeleteByIdException()
     {
diff --git a/app/code/Magento/CatalogInventory/Test/Unit/Model/Stock/StockStatusRepositoryTest.php b/app/code/Magento/CatalogInventory/Test/Unit/Model/Stock/StockStatusRepositoryTest.php
index 5c8d3efe356db03d40ec8ba1d4b43c0b32e336b2..5feb8e85af5421ab320fb77f9938c2458bffca80 100644
--- a/app/code/Magento/CatalogInventory/Test/Unit/Model/Stock/StockStatusRepositoryTest.php
+++ b/app/code/Magento/CatalogInventory/Test/Unit/Model/Stock/StockStatusRepositoryTest.php
@@ -5,8 +5,10 @@
  */
 namespace Magento\CatalogInventory\Test\Unit\Model\Stock;
 
-use \Magento\CatalogInventory\Model\Stock\StockStatusRepository;
-use \Magento\CatalogInventory\Api\Data as InventoryApiData;
+use Magento\CatalogInventory\Model\Stock\StockStatusRepository;
+use Magento\CatalogInventory\Api\Data as InventoryApiData;
+use Magento\CatalogInventory\Model\StockRegistryStorage;
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
 
 /**
  * Class StockStatusRepositoryTest
@@ -48,6 +50,11 @@ class StockStatusRepositoryTest extends \PHPUnit_Framework_TestCase
      */
     protected $mapperMock;
 
+    /**
+     * @var StockRegistryStorage|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $stockRegistryStorage;
+
     protected function setUp()
     {
         $this->stockStatusMock = $this->getMockBuilder('\Magento\CatalogInventory\Model\Stock\Status')
@@ -76,13 +83,20 @@ class StockStatusRepositoryTest extends \PHPUnit_Framework_TestCase
         $this->mapperMock = $this->getMockBuilder('Magento\Framework\DB\MapperFactory')
             ->disableOriginalConstructor()
             ->getMock();
+        $this->stockRegistryStorage = $this->getMockBuilder(StockRegistryStorage::class)
+            ->disableOriginalConstructor()
+            ->getMock();
 
-        $this->model = new StockStatusRepository(
-            $this->stockStatusResourceMock,
-            $this->stockStatusFactoryMock,
-            $this->stockStatusCollectionMock,
-            $this->queryBuilderFactoryMock,
-            $this->mapperMock
+        $this->model = (new ObjectManager($this))->getObject(
+            StockStatusRepository::class,
+            [
+                'resource' => $this->stockStatusResourceMock,
+                'stockStatusFactory' => $this->stockStatusFactoryMock,
+                'collectionFactory' => $this->stockStatusCollectionMock,
+                'queryBuilderFactory' => $this->queryBuilderFactoryMock,
+                'mapperFactory' => $this->mapperMock,
+                'stockRegistryStorage' => $this->stockRegistryStorage,
+            ]
         );
     }
 
@@ -136,6 +150,10 @@ class StockStatusRepositoryTest extends \PHPUnit_Framework_TestCase
 
     public function testDelete()
     {
+        $productId = 1;
+        $this->stockStatusMock->expects($this->atLeastOnce())->method('getProductId')->willReturn($productId);
+        $this->stockRegistryStorage->expects($this->once())->method('removeStockStatus')->with($productId);
+
         $this->stockStatusResourceMock->expects($this->once())
             ->method('delete')
             ->with($this->stockStatusMock)
diff --git a/app/code/Magento/CatalogInventory/Test/Unit/Observer/AddStockStatusToCollectionObserverTest.php b/app/code/Magento/CatalogInventory/Test/Unit/Observer/AddStockStatusToCollectionObserverTest.php
deleted file mode 100644
index ebba8ffe469324f70f4871d73cc438690b13a911..0000000000000000000000000000000000000000
--- a/app/code/Magento/CatalogInventory/Test/Unit/Observer/AddStockStatusToCollectionObserverTest.php
+++ /dev/null
@@ -1,75 +0,0 @@
-<?php
-/**
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-namespace Magento\CatalogInventory\Test\Unit\Observer;
-
-use Magento\CatalogInventory\Observer\AddStockStatusToCollectionObserver;
-
-class AddStockStatusToCollectionObserverTest extends \PHPUnit_Framework_TestCase
-{
-    /**
-     * @var AddStockStatusToCollectionObserver
-     */
-    protected $observer;
-
-    /**
-     * @var \Magento\CatalogInventory\Helper\Stock|\PHPUnit_Framework_MockObject_MockObject
-     */
-    protected $stockHelper;
-
-    /**
-     * @var \Magento\Framework\Event|\PHPUnit_Framework_MockObject_MockObject
-     */
-    protected $event;
-
-    /**
-     * @var \Magento\Framework\Event\Observer|\PHPUnit_Framework_MockObject_MockObject
-     */
-    protected $eventObserver;
-
-    protected function setUp()
-    {
-        $this->stockHelper = $this->getMock('Magento\CatalogInventory\Helper\Stock', [], [], '', false);
-
-        $this->event = $this->getMockBuilder('Magento\Framework\Event')
-            ->disableOriginalConstructor()
-            ->setMethods(['getCollection'])
-            ->getMock();
-
-        $this->eventObserver = $this->getMockBuilder('Magento\Framework\Event\Observer')
-            ->disableOriginalConstructor()
-            ->setMethods(['getEvent'])
-            ->getMock();
-
-        $this->eventObserver->expects($this->atLeastOnce())
-            ->method('getEvent')
-            ->will($this->returnValue($this->event));
-
-        $this->observer = (new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this))->getObject(
-            'Magento\CatalogInventory\Observer\AddStockStatusToCollectionObserver',
-            [
-                'stockHelper' => $this->stockHelper,
-            ]
-        );
-    }
-
-    public function testAddStockStatusToCollection()
-    {
-        $productCollection = $this->getMockBuilder('Magento\Catalog\Model\ResourceModel\Product\Collection')
-            ->disableOriginalConstructor()
-            ->getMock();
-
-        $this->event->expects($this->once())
-            ->method('getCollection')
-            ->will($this->returnValue($productCollection));
-
-        $this->stockHelper->expects($this->once())
-            ->method('addStockStatusToProducts')
-            ->with($productCollection)
-            ->will($this->returnSelf());
-
-        $this->observer->execute($this->eventObserver);
-    }
-}
diff --git a/app/code/Magento/CatalogInventory/etc/events.xml b/app/code/Magento/CatalogInventory/etc/events.xml
index 4252a093c4fe710f7a8a0cb64abb5777f0b5ef1a..96b08cf5123fbc58c53dfd42de556fd5eb1a2f21 100644
--- a/app/code/Magento/CatalogInventory/etc/events.xml
+++ b/app/code/Magento/CatalogInventory/etc/events.xml
@@ -12,12 +12,6 @@
     <event name="catalog_product_load_after">
         <observer name="inventory" instance="Magento\CatalogInventory\Observer\AddInventoryDataObserver"/>
     </event>
-    <event name="catalog_product_collection_load_after">
-        <observer name="inventory" instance="Magento\CatalogInventory\Observer\AddStockStatusToCollectionObserver"/>
-    </event>
-    <event name="sales_quote_item_collection_products_after_load">
-        <observer name="inventory" instance="Magento\CatalogInventory\Observer\AddStockStatusToCollectionObserver"/>
-    </event>
     <event name="sales_quote_item_qty_set_after">
         <observer name="inventory" instance="Magento\CatalogInventory\Observer\QuantityValidatorObserver"/>
     </event>
diff --git a/app/code/Magento/CatalogInventory/etc/frontend/di.xml b/app/code/Magento/CatalogInventory/etc/frontend/di.xml
index baa96cc29bb52cc66798ea39b2fe4a75397eef87..5d5fa9aab000f32f7eca3253bfc176f4e9f6e64a 100644
--- a/app/code/Magento/CatalogInventory/etc/frontend/di.xml
+++ b/app/code/Magento/CatalogInventory/etc/frontend/di.xml
@@ -9,4 +9,7 @@
     <type name="Magento\Catalog\Model\Product\Link">
         <plugin name="isInStockFilter" type="Magento\CatalogInventory\Model\Plugin\ProductLinks" />
     </type>
+    <type name="Magento\Catalog\Model\ResourceModel\Product\Collection">
+        <plugin name="add_stock_information" type="Magento\CatalogInventory\Model\AddStockStatusToCollection" />
+    </type>
 </config>
diff --git a/app/code/Magento/CatalogRule/Model/Rule/Action/SimpleActionOptionsProvider.php b/app/code/Magento/CatalogRule/Model/Rule/Action/SimpleActionOptionsProvider.php
index 2d73a5d2cc8d8b08df262c0b7161f3bf07231006..abe9448309a32a9b34f0dfb57b810a68f564904e 100644
--- a/app/code/Magento/CatalogRule/Model/Rule/Action/SimpleActionOptionsProvider.php
+++ b/app/code/Magento/CatalogRule/Model/Rule/Action/SimpleActionOptionsProvider.php
@@ -5,7 +5,7 @@
  */
 namespace Magento\CatalogRule\Model\Rule\Action;
 
-class SimpleActionOptionsProvider
+class SimpleActionOptionsProvider implements \Magento\Framework\Data\OptionSourceInterface
 {
     /**
      * @return array
diff --git a/app/code/Magento/CatalogRule/Model/Rule/CustomerGroupsOptionsProvider.php b/app/code/Magento/CatalogRule/Model/Rule/CustomerGroupsOptionsProvider.php
new file mode 100644
index 0000000000000000000000000000000000000000..2e24d8f31001391916b66d500db1486f564f45db
--- /dev/null
+++ b/app/code/Magento/CatalogRule/Model/Rule/CustomerGroupsOptionsProvider.php
@@ -0,0 +1,48 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\CatalogRule\Model\Rule;
+
+class CustomerGroupsOptionsProvider implements \Magento\Framework\Data\OptionSourceInterface
+{
+    /**
+     * @var \Magento\Customer\Api\GroupRepositoryInterface
+     */
+    private $groupRepository;
+
+    /**
+     * @var \Magento\Framework\Api\SearchCriteriaBuilder
+     */
+    private $searchCriteriaBuilder;
+
+    /**
+     * @var \Magento\Framework\Convert\DataObject
+     */
+    private $objectConverter;
+
+    /**
+     * @param \Magento\Customer\Api\GroupRepositoryInterface $groupRepository
+     * @param \Magento\Framework\Api\SearchCriteriaBuilder $searchCriteriaBuilder
+     * @param \Magento\Framework\Convert\DataObject $objectConverter
+     */
+    public function __construct(
+        \Magento\Customer\Api\GroupRepositoryInterface $groupRepository,
+        \Magento\Framework\Api\SearchCriteriaBuilder $searchCriteriaBuilder,
+        \Magento\Framework\Convert\DataObject $objectConverter
+    ) {
+        $this->groupRepository = $groupRepository;
+        $this->searchCriteriaBuilder = $searchCriteriaBuilder;
+        $this->objectConverter = $objectConverter;
+    }
+
+    /**
+     * @return array
+     */
+    public function toOptionArray()
+    {
+        $customerGroups = $this->groupRepository->getList($this->searchCriteriaBuilder->create())->getItems();
+        return $this->objectConverter->toOptionArray($customerGroups, 'id', 'code');
+    }
+}
diff --git a/app/code/Magento/CatalogRule/Model/Rule/DataProvider.php b/app/code/Magento/CatalogRule/Model/Rule/DataProvider.php
index 16d2147c6e1c9313769ad7cee3afab80ae54c460..4b114c542623706c1ce46c2d6093cf0d13436a47 100644
--- a/app/code/Magento/CatalogRule/Model/Rule/DataProvider.php
+++ b/app/code/Magento/CatalogRule/Model/Rule/DataProvider.php
@@ -8,11 +8,6 @@ namespace Magento\CatalogRule\Model\Rule;
 use Magento\CatalogRule\Model\ResourceModel\Rule\Collection;
 use Magento\CatalogRule\Model\ResourceModel\Rule\CollectionFactory;
 use Magento\CatalogRule\Model\Rule;
-use Magento\Store\Model\System\Store;
-use Magento\Customer\Api\GroupRepositoryInterface;
-use Magento\Framework\Api\SearchCriteriaBuilder;
-use Magento\Framework\Convert\DataObject;
-use Magento\CatalogRule\Model\Rule\Action\SimpleActionOptionsProvider;
 use Magento\Framework\App\Request\DataPersistorInterface;
 
 /**
@@ -31,31 +26,6 @@ class DataProvider extends \Magento\Ui\DataProvider\AbstractDataProvider
      */
     protected $loadedData;
 
-    /**
-     * @var Store
-     */
-    protected $store;
-
-    /**
-     * @var GroupRepositoryInterface
-     */
-    protected $groupRepository;
-
-    /**
-     * @var SearchCriteriaBuilder
-     */
-    protected $searchCriteriaBuilder;
-
-    /**
-     * @var DataObject
-     */
-    protected $objectConverter;
-
-    /**
-     * @var SimpleActionOptionsProvider
-     */
-    protected $actionOptions;
-
     /**
      * @var DataPersistorInterface
      */
@@ -66,112 +36,24 @@ class DataProvider extends \Magento\Ui\DataProvider\AbstractDataProvider
      * @param string $primaryFieldName
      * @param string $requestFieldName
      * @param CollectionFactory $collectionFactory
-     * @param Store $store
-     * @param GroupRepositoryInterface $groupRepository
-     * @param SearchCriteriaBuilder $searchCriteriaBuilder
-     * @param DataObject $objectConverter
-     * @param SimpleActionOptionsProvider $actionOptions
      * @param DataPersistorInterface $dataPersistor
      * @param array $meta
      * @param array $data
-     * @SuppressWarnings(PHPMD.ExcessiveParameterList)
      */
     public function __construct(
         $name,
         $primaryFieldName,
         $requestFieldName,
         CollectionFactory $collectionFactory,
-        Store $store,
-        GroupRepositoryInterface $groupRepository,
-        SearchCriteriaBuilder $searchCriteriaBuilder,
-        DataObject $objectConverter,
-        SimpleActionOptionsProvider $actionOptions,
         DataPersistorInterface $dataPersistor,
         array $meta = [],
         array $data = []
     ) {
-        $this->groupRepository = $groupRepository;
         $this->collection = $collectionFactory->create();
-        $this->store = $store;
-        $this->searchCriteriaBuilder = $searchCriteriaBuilder;
-        $this->objectConverter = $objectConverter;
-        $this->actionOptions = $actionOptions;
         $this->dataPersistor = $dataPersistor;
-
-        $meta = array_replace_recursive($meta, $this->getMetadata());
         parent::__construct($name, $primaryFieldName, $requestFieldName, $meta, $data);
     }
 
-    /**
-     * @return array
-     */
-    protected function getMetadata()
-    {
-        $customerGroups = $this->groupRepository->getList($this->searchCriteriaBuilder->create())->getItems();
-
-        return [
-            'rule_information' => [
-                'children' => [
-                    'website_ids' => [
-                        'arguments' => [
-                            'data' => [
-                                'config' => [
-                                    'options' => $this->store->getWebsiteValuesForForm(),
-                                ],
-                            ],
-                        ],
-                    ],
-                    'is_active' => [
-                        'arguments' => [
-                            'data' => [
-                                'config' => [
-                                    'options' => [
-                                        ['label' => __('Active'), 'value' => '1'],
-                                        ['label' => __('Inactive'), 'value' => '0']
-                                    ],
-                                ],
-                            ],
-                        ],
-                    ],
-                    'customer_group_ids' => [
-                        'arguments' => [
-                            'data' => [
-                                'config' => [
-                                    'options' => $this->objectConverter->toOptionArray($customerGroups, 'id', 'code'),
-                                ],
-                            ],
-                        ],
-                    ]
-                ]
-            ],
-            'actions' => [
-                'children' => [
-                    'simple_action' => [
-                        'arguments' => [
-                            'data' => [
-                                'config' => [
-                                    'options' => $this->actionOptions->toOptionArray()
-                                ],
-                            ],
-                        ],
-                    ],
-                    'stop_rules_processing' => [
-                        'arguments' => [
-                            'data' => [
-                                'config' => [
-                                    'options' => [
-                                        ['label' => __('Yes'), 'value' => '1'],
-                                        ['label' => __('No'), 'value' => '0']
-                                    ]
-                                ],
-                            ],
-                        ],
-                    ],
-                ]
-            ]
-        ];
-    }
-
     /**
      * @return array
      */
diff --git a/app/code/Magento/CatalogRule/Model/Rule/WebsitesOptionsProvider.php b/app/code/Magento/CatalogRule/Model/Rule/WebsitesOptionsProvider.php
new file mode 100644
index 0000000000000000000000000000000000000000..e41f6aa9fd5d19057c237b797a478bffc6a6060a
--- /dev/null
+++ b/app/code/Magento/CatalogRule/Model/Rule/WebsitesOptionsProvider.php
@@ -0,0 +1,30 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\CatalogRule\Model\Rule;
+
+class WebsitesOptionsProvider implements \Magento\Framework\Data\OptionSourceInterface
+{
+    /**
+     * @var \Magento\Store\Model\System\Store
+     */
+    private $store;
+
+    /**
+     * @param \Magento\Store\Model\System\Store $store
+     */
+    public function __construct(\Magento\Store\Model\System\Store $store)
+    {
+        $this->store = $store;
+    }
+
+    /**
+     * @return array
+     */
+    public function toOptionArray()
+    {
+        return $this->store->getWebsiteValuesForForm();
+    }
+}
diff --git a/app/code/Magento/CatalogRule/Test/Unit/Model/Rule/CustomerGroupsOptionsProviderTest.php b/app/code/Magento/CatalogRule/Test/Unit/Model/Rule/CustomerGroupsOptionsProviderTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..bd5ae8b8dc48af648acdc11dc2cb49721e62a624
--- /dev/null
+++ b/app/code/Magento/CatalogRule/Test/Unit/Model/Rule/CustomerGroupsOptionsProviderTest.php
@@ -0,0 +1,73 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\CatalogRule\Test\Unit\Model\Rule;
+
+class CustomerGroupsOptionsProviderTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\CatalogRule\Model\Rule\CustomerGroupsOptionsProvider
+     */
+    private $model;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    private $groupRepositoryMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    private $searchCriteriaBuilderMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    private $objectConverterMock;
+
+    protected function setup()
+    {
+        $this->groupRepositoryMock = $this->getMock('\Magento\Customer\Api\GroupRepositoryInterface');
+        $this->searchCriteriaBuilderMock = $this->getMock(
+            '\Magento\Framework\Api\SearchCriteriaBuilder',
+            [],
+            [],
+            '',
+            false
+        );
+        $this->objectConverterMock = $this->getMock('\Magento\Framework\Convert\DataObject', [], [], '', false);
+        $this->model = new \Magento\CatalogRule\Model\Rule\CustomerGroupsOptionsProvider(
+            $this->groupRepositoryMock,
+            $this->searchCriteriaBuilderMock,
+            $this->objectConverterMock
+        );
+    }
+
+    public function testToOptionArray()
+    {
+        $customerGroups = ['group1', 'group2'];
+
+        $options = [
+            ['label' => 'label', 'value' => 'value']
+        ];
+
+        $searchCriteriaMock = $this->getMock('\Magento\Framework\Api\SearchCriteria', [], [], '', false);
+        $searchResultMock = $this->getMock('\Magento\Customer\Api\Data\GroupSearchResultsInterface');
+        $this->searchCriteriaBuilderMock->expects($this->once())->method('create')->willReturn($searchCriteriaMock);
+
+        $this->groupRepositoryMock->expects($this->once())
+            ->method('getList')
+            ->with($searchCriteriaMock)
+            ->willReturn($searchResultMock);
+
+        $searchResultMock->expects($this->once())->method('getItems')->willReturn($customerGroups);
+        $this->objectConverterMock->expects($this->once())
+            ->method('toOptionArray')
+            ->with($customerGroups, 'id', 'code')
+            ->willReturn($options);
+
+        $this->assertEquals($options, $this->model->toOptionArray());
+    }
+}
diff --git a/app/code/Magento/CatalogRule/Test/Unit/Model/Rule/DataProviderTest.php b/app/code/Magento/CatalogRule/Test/Unit/Model/Rule/DataProviderTest.php
index b4746d728d918d154be544fce7de14ec66003691..18b60cbe092146f78dbdc6491eb50f5461e2b7eb 100644
--- a/app/code/Magento/CatalogRule/Test/Unit/Model/Rule/DataProviderTest.php
+++ b/app/code/Magento/CatalogRule/Test/Unit/Model/Rule/DataProviderTest.php
@@ -17,26 +17,6 @@ class DataProviderTest extends \PHPUnit_Framework_TestCase
      */
     protected $collectionFactoryMock;
 
-    /**
-     * @var \PHPUnit_Framework_MockObject_MockObject
-     */
-    protected $storeMock;
-
-    /**
-     * @var \PHPUnit_Framework_MockObject_MockObject
-     */
-    protected $groupRepositoryMock;
-
-    /**
-     * @var \PHPUnit_Framework_MockObject_MockObject
-     */
-    protected $searchCriteriaBuilderMock;
-
-    /**
-     * @var \PHPUnit_Framework_MockObject_MockObject
-     */
-    protected $dataObjectMock;
-
     /**
      * @var \PHPUnit_Framework_MockObject_MockObject
      */
@@ -56,17 +36,6 @@ class DataProviderTest extends \PHPUnit_Framework_TestCase
             '',
             false
         );
-        $this->searchCriteriaBuilderMock = $this->getMock(
-            'Magento\Framework\Api\SearchCriteriaBuilder',
-            [],
-            [],
-            '',
-            false
-        );
-        $this->storeMock = $this->getMock('Magento\Store\Model\System\Store', [], [], '', false);
-        $this->groupRepositoryMock = $this->getMock('Magento\Customer\Api\GroupRepositoryInterface', [], [], '', false);
-        $this->dataObjectMock = $this->getMock('Magento\Framework\Convert\DataObject', [], [], '', false);
-
         $this->collectionMock = $this->getMock(
             'Magento\CatalogRule\Model\ResourceModel\Rule\Collection',
             [],
@@ -75,31 +44,6 @@ class DataProviderTest extends \PHPUnit_Framework_TestCase
             false
         );
         $this->collectionFactoryMock->expects($this->once())->method('create')->willReturn($this->collectionMock);
-        $searchCriteriaMock = $this->getMock('Magento\Framework\Api\SearchCriteriaInterface', [], [], '', false);
-        $groupSearchResultsMock = $this->getMock(
-            'Magento\Customer\Api\Data\GroupSearchResultsInterface',
-            [],
-            [],
-            '',
-            false
-        );
-        $groupsMock = $this->getMock('Magento\Customer\Api\Data\GroupInterface', [], [], '', false);
-
-        $this->searchCriteriaBuilderMock->expects($this->once())->method('create')->willReturn($searchCriteriaMock);
-        $this->groupRepositoryMock->expects($this->once())->method('getList')->with($searchCriteriaMock)
-            ->willReturn($groupSearchResultsMock);
-        $groupSearchResultsMock->expects($this->once())->method('getItems')->willReturn([$groupsMock]);
-        $this->storeMock->expects($this->once())->method('getWebsiteValuesForForm')->willReturn([]);
-        $this->dataObjectMock->expects($this->once())->method('toOptionArray')->with([$groupsMock], 'id', 'code')
-            ->willReturn([]);
-
-        $actionOptionProviderMock = $this->getMock(
-            'Magento\CatalogRule\Model\Rule\Action\SimpleActionOptionsProvider',
-            [],
-            [],
-            '',
-            false
-        );
         $this->dataPersistorMock = $this->getMock('Magento\Framework\App\Request\DataPersistorInterface');
 
         $this->model = new \Magento\CatalogRule\Model\Rule\DataProvider(
@@ -107,11 +51,6 @@ class DataProviderTest extends \PHPUnit_Framework_TestCase
             'Primary',
             'Request',
             $this->collectionFactoryMock,
-            $this->storeMock,
-            $this->groupRepositoryMock,
-            $this->searchCriteriaBuilderMock,
-            $this->dataObjectMock,
-            $actionOptionProviderMock,
             $this->dataPersistorMock
         );
     }
diff --git a/app/code/Magento/CatalogRule/Test/Unit/Model/Rule/WebsitesOptionsProviderTest.php b/app/code/Magento/CatalogRule/Test/Unit/Model/Rule/WebsitesOptionsProviderTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..af61daf6aeb0fce990b139cc2d3a5efe1f35354d
--- /dev/null
+++ b/app/code/Magento/CatalogRule/Test/Unit/Model/Rule/WebsitesOptionsProviderTest.php
@@ -0,0 +1,34 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\CatalogRule\Test\Unit\Model\Rule;
+
+class WebsitesOptionsProviderTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\CatalogRule\Model\Rule\WebsitesOptionsProvider
+     */
+    private $model;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    private $storeMock;
+
+    protected function setup()
+    {
+        $this->storeMock = $this->getMock('\Magento\Store\Model\System\Store', [], [], '', false);
+        $this->model = new \Magento\CatalogRule\Model\Rule\WebsitesOptionsProvider($this->storeMock);
+    }
+
+    public function testToOptionArray()
+    {
+        $options = [
+            ['label' => 'label', 'value' => 'value']
+        ];
+        $this->storeMock->expects($this->once())->method('getWebsiteValuesForForm')->willReturn($options);
+        $this->assertEquals($options, $this->model->toOptionArray());
+    }
+}
diff --git a/app/code/Magento/CatalogRule/etc/indexer.xml b/app/code/Magento/CatalogRule/etc/indexer.xml
index de847b1ffca5538b38b7eed01ec3d7b5383ddf33..b4b065cd985317fc3a38f19d4e8d80aee1b85c51 100644
--- a/app/code/Magento/CatalogRule/etc/indexer.xml
+++ b/app/code/Magento/CatalogRule/etc/indexer.xml
@@ -6,11 +6,11 @@
  */
 -->
 <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Indexer/etc/indexer.xsd">
-    <indexer id="catalogrule_rule" view_id="catalogrule_rule" class="Magento\CatalogRule\Model\Indexer\Rule\RuleProductIndexer">
+    <indexer id="catalogrule_rule" view_id="catalogrule_rule" class="Magento\CatalogRule\Model\Indexer\Rule\RuleProductIndexer" shared_index="catalogrule">
         <title translate="true">Catalog Rule Product</title>
         <description translate="true">Indexed rule/product association</description>
     </indexer>
-    <indexer id="catalogrule_product" view_id="catalogrule_product" class="Magento\CatalogRule\Model\Indexer\Product\ProductRuleIndexer">
+    <indexer id="catalogrule_product" view_id="catalogrule_product" class="Magento\CatalogRule\Model\Indexer\Product\ProductRuleIndexer" shared_index="catalogrule">
         <title translate="true">Catalog Product Rule</title>
         <description translate="true">Indexed product/rule association</description>
     </indexer>
diff --git a/app/code/Magento/CatalogRule/view/adminhtml/ui_component/catalog_rule_form.xml b/app/code/Magento/CatalogRule/view/adminhtml/ui_component/catalog_rule_form.xml
index bca9264e3bcd5a9b81ed78aa68451919ba76a953..71ac90e5e8aff54cbc8aec46dc5fe805f4c1bb20 100644
--- a/app/code/Magento/CatalogRule/view/adminhtml/ui_component/catalog_rule_form.xml
+++ b/app/code/Magento/CatalogRule/view/adminhtml/ui_component/catalog_rule_form.xml
@@ -106,6 +106,16 @@
                     <item name="source" xsi:type="string">catalog_rule</item>
                     <item name="dataScope" xsi:type="string">is_active</item>
                 </item>
+                <item name="options" xsi:type="array">
+                    <item name="0" xsi:type="array">
+                        <item name="value" xsi:type="number">1</item>
+                        <item name="label" xsi:type="string" translate="true">Active</item>
+                    </item>
+                    <item name="1" xsi:type="array">
+                        <item name="value" xsi:type="number">0</item>
+                        <item name="label" xsi:type="string" translate="true">Inactive</item>
+                    </item>
+                </item>
             </argument>
         </field>
         <field name="website_ids">
@@ -124,6 +134,7 @@
                         <item name="description" xsi:type="string">What is this?</item>
                     </item>
                 </item>
+                <item name="options" xsi:type="object">Magento\CatalogRule\Model\Rule\WebsitesOptionsProvider</item>
             </argument>
         </field>
         <field name="customer_group_ids">
@@ -138,6 +149,7 @@
                     <item name="source" xsi:type="string">catalog_rule</item>
                     <item name="dataScope" xsi:type="string">customer_group_ids</item>
                 </item>
+                <item name="options" xsi:type="object">Magento\CatalogRule\Model\Rule\CustomerGroupsOptionsProvider</item>
             </argument>
         </field>
         <field name="from_date">
@@ -256,6 +268,7 @@
                         </item>
                     </item>
                 </item>
+                <item name="options" xsi:type="object">Magento\CatalogRule\Model\Rule\Action\SimpleActionOptionsProvider</item>
             </argument>
         </field>
         <field name="discount_amount">
@@ -283,6 +296,16 @@
                     <item name="source" xsi:type="string">catalog_rule</item>
                     <item name="dataScope" xsi:type="string">stop_rules_processing</item>
                 </item>
+                <item name="options" xsi:type="array">
+                    <item name="0" xsi:type="array">
+                        <item name="value" xsi:type="number">1</item>
+                        <item name="label" xsi:type="string" translate="true">Yes</item>
+                    </item>
+                    <item name="1" xsi:type="array">
+                        <item name="value" xsi:type="number">0</item>
+                        <item name="label" xsi:type="string" translate="true">No</item>
+                    </item>
+                </item>
             </argument>
         </field>
     </fieldset>
diff --git a/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Plugin/Aggregation/Category/DataProvider.php b/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Plugin/Aggregation/Category/DataProvider.php
index 38c87413b2b410f375a4c58156e4fbe143f27b35..da07e516427d1c96b4e1aa29cda43e28f7e47b52 100644
--- a/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Plugin/Aggregation/Category/DataProvider.php
+++ b/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Plugin/Aggregation/Category/DataProvider.php
@@ -75,8 +75,7 @@ class DataProvider
             $derivedTable->from(
                 ['main_table' => $this->resource->getTableName('catalog_category_product_index')],
                 [
-                    'entity_id' => 'product_id',
-                    'value' => 'category_id',
+                    'value' => 'category_id'
                 ]
             )->where('main_table.store_id = ?', $currentScopeId);
             $derivedTable->joinInner(
diff --git a/app/code/Magento/CatalogSearch/Model/Layer/Filter/Attribute.php b/app/code/Magento/CatalogSearch/Model/Layer/Filter/Attribute.php
index b326b2a59d72db1797d4e5ca36a39012bf85b616..01c123190d2e224f819fb8423084646b53e3d638 100644
--- a/app/code/Magento/CatalogSearch/Model/Layer/Filter/Attribute.php
+++ b/app/code/Magento/CatalogSearch/Model/Layer/Filter/Attribute.php
@@ -92,17 +92,24 @@ class Attribute extends AbstractFilter
             if (empty($option['value'])) {
                 continue;
             }
+
+            $value = $option['value'];
+
+            $count = isset($optionsFacetedData[$value]['count'])
+                ? (int)$optionsFacetedData[$value]['count']
+                : 0;
             // Check filter type
-            if (empty($optionsFacetedData[$option['value']]['count'])
-                || ($this->getAttributeIsFilterable($attribute) == static::ATTRIBUTE_OPTIONS_ONLY_WITH_RESULTS
-                    && !$this->isOptionReducesResults($optionsFacetedData[$option['value']]['count'], $productSize))
+            if (
+                $count === 0
+                && $this->getAttributeIsFilterable($attribute) === static::ATTRIBUTE_OPTIONS_ONLY_WITH_RESULTS
+                && !$this->isOptionReducesResults($count, $productSize)
             ) {
                 continue;
             }
             $this->itemDataBuilder->addItemData(
                 $this->tagFilter->filter($option['label']),
-                $option['value'],
-                $optionsFacetedData[$option['value']]['count']
+                $value,
+                $count
             );
         }
 
diff --git a/app/code/Magento/CatalogSearch/Test/Unit/Model/Layer/Filter/AttributeTest.php b/app/code/Magento/CatalogSearch/Test/Unit/Model/Layer/Filter/AttributeTest.php
index 77d097019a37a585a248c65c5cee8910c9571e30..35b502da8be49b450b0587b73492084f0d7d164b 100644
--- a/app/code/Magento/CatalogSearch/Test/Unit/Model/Layer/Filter/AttributeTest.php
+++ b/app/code/Magento/CatalogSearch/Test/Unit/Model/Layer/Filter/AttributeTest.php
@@ -283,15 +283,6 @@ class AttributeTest extends \PHPUnit_Framework_TestCase
         $this->attribute->expects($this->exactly(2))
             ->method('getAttributeCode')
             ->will($this->returnValue($attributeCode));
-        $this->attribute->expects($this->at(3))
-            ->method('getIsFilterable')
-            ->will($this->returnValue(1));
-        $this->attribute->expects($this->at(4))
-            ->method('getIsFilterable')
-            ->will($this->returnValue(2));
-        $this->attribute->expects($this->at(5))
-            ->method('getIsFilterable')
-            ->will($this->returnValue(1));
 
         $this->target->setAttributeModel($this->attribute);
 
diff --git a/app/code/Magento/Checkout/Model/PaymentInformationManagement.php b/app/code/Magento/Checkout/Model/PaymentInformationManagement.php
index 018fed2f513acd285b86c0bc6a13973144bd6cf5..30506d354281c5de5bdc80422f4e1d1be51dbb06 100644
--- a/app/code/Magento/Checkout/Model/PaymentInformationManagement.php
+++ b/app/code/Magento/Checkout/Model/PaymentInformationManagement.php
@@ -24,13 +24,11 @@ class PaymentInformationManagement implements \Magento\Checkout\Api\PaymentInfor
      */
     protected $cartManagement;
 
-
     /**
      * @var PaymentDetailsFactory
      */
     protected $paymentDetailsFactory;
 
-
     /**
      * @var \Magento\Quote\Api\CartTotalRepositoryInterface
      */
diff --git a/app/code/Magento/Checkout/view/frontend/web/js/sidebar.js b/app/code/Magento/Checkout/view/frontend/web/js/sidebar.js
index 9322100b6417b54d2b9aa7a176204962515556d6..afb34aa7826ab0bbeb09cbd08fdfcc889a160432 100644
--- a/app/code/Magento/Checkout/view/frontend/web/js/sidebar.js
+++ b/app/code/Magento/Checkout/view/frontend/web/js/sidebar.js
@@ -39,7 +39,7 @@ define([
             this._isOverflowed();
         },
 
-        _initContent: function() {
+        _initContent: function () {
             var self = this,
                 events = {};
 
@@ -47,13 +47,15 @@ define([
 
             events['click ' + this.options.button.close] = function (event) {
                 event.stopPropagation();
-                $(self.options.targetElement).dropdownDialog("close");
+                $(self.options.targetElement).dropdownDialog('close');
             };
             events['click ' + this.options.button.checkout] = $.proxy(function () {
                 var cart = customerData.get('cart'),
                     customer = customerData.get('customer');
 
                 if (!customer().firstname && !cart().isGuestCheckoutAllowed) {
+                    // set URL for redirect on successful login/registration. It's postprocessed on backend.
+                    $.cookie('login_redirect', this.options.url.checkout);
                     if (this.options.url.isRedirectRequired) {
                         location.href = this.options.url.loginUrl;
                     } else {
@@ -64,7 +66,7 @@ define([
                 }
                 location.href = this.options.url.checkout;
             }, this);
-            events['click ' + this.options.button.remove] =  function(event) {
+            events['click ' + this.options.button.remove] =  function (event) {
                 event.stopPropagation();
                 confirm({
                     content: self.options.confirmMessage,
@@ -78,14 +80,14 @@ define([
                     }
                 });
             };
-            events['keyup ' + this.options.item.qty] = function(event) {
+            events['keyup ' + this.options.item.qty] = function (event) {
                 self._showItemButton($(event.target));
             };
-            events['click ' + this.options.item.button] = function(event) {
+            events['click ' + this.options.item.button] = function (event) {
                 event.stopPropagation();
                 self._updateItemQty($(event.currentTarget));
             };
-            events['focusout ' + this.options.item.qty] = function(event) {
+            events['focusout ' + this.options.item.qty] = function (event) {
                 self._validateQty($(event.currentTarget));
             };
 
@@ -99,7 +101,7 @@ define([
          *
          * @private
          */
-        _isOverflowed: function() {
+        _isOverflowed: function () {
             var list = $(this.options.minicart.list),
                 cssOverflowClass = 'overflowed';
 
@@ -113,6 +115,7 @@ define([
         _showItemButton: function (elem) {
             var itemId = elem.data('cart-item'),
                 itemQty = elem.data('item-qty');
+
             if (this._isValidQty(itemQty, elem.val())) {
                 $('#update-cart-item-' + itemId).show('fade', 300);
             } else if (elem.val() == 0) {
@@ -128,18 +131,18 @@ define([
          * @returns {boolean}
          * @private
          */
-        _isValidQty: function(origin, changed) {
-            return (origin != changed)
-                && (changed.length > 0)
-                && (changed - 0 == changed)
-                && (changed - 0 > 0);
+        _isValidQty: function (origin, changed) {
+            return (origin != changed) &&
+                (changed.length > 0) &&
+                (changed - 0 == changed) &&
+                (changed - 0 > 0);
         },
 
         /**
          * @param {Object} elem
          * @private
          */
-        _validateQty: function(elem) {
+        _validateQty: function (elem) {
             var itemQty = elem.data('item-qty');
 
             if (!this._isValidQty(itemQty, elem.val())) {
@@ -147,12 +150,12 @@ define([
             }
         },
 
-        _hideItemButton: function(elem) {
+        _hideItemButton: function (elem) {
             var itemId = elem.data('cart-item');
             $('#update-cart-item-' + itemId).hide('fade', 300);
         },
 
-        _updateItemQty: function(elem) {
+        _updateItemQty: function (elem) {
             var itemId = elem.data('cart-item');
             this._ajax(this.options.url.update, {
                 item_id: itemId,
@@ -165,11 +168,11 @@ define([
          *
          * @param elem
          */
-        _updateItemQtyAfter: function(elem) {
+        _updateItemQtyAfter: function (elem) {
             this._hideItemButton(elem);
         },
 
-        _removeItem: function(elem) {
+        _removeItem: function (elem) {
             var itemId = elem.data('cart-item');
             this._ajax(this.options.url.remove, {
                 item_id: itemId
@@ -183,15 +186,16 @@ define([
          * @param response
          * @private
          */
-        _removeItemAfter: function(elem, response) {
+        _removeItemAfter: function (elem, response) {
         },
+
         /**
          * @param url - ajax url
          * @param data - post data for ajax call
          * @param elem - element that initiated the event
          * @param callback - callback method to execute after AJAX success
          */
-        _ajax: function(url, data, elem, callback) {
+        _ajax: function (url, data, elem, callback) {
             $.ajax({
                 url: url,
                 data: data,
@@ -205,11 +209,12 @@ define([
                     elem.attr('disabled', null);
                 }
             })
-                .done(function(response) {
+                .done(function (response) {
                     if (response.success) {
                         callback.call(this, elem, response);
                     } else {
                         var msg = response.error_message;
+
                         if (msg) {
                             alert({
                                 content: $.mage.__(msg)
@@ -217,7 +222,7 @@ define([
                         }
                     }
                 })
-                .fail(function(error) {
+                .fail(function (error) {
                     console.log(JSON.stringify(error));
                 });
         },
@@ -231,11 +236,15 @@ define([
             var self = this,
                 height = 0,
                 counter = this.options.maxItemsVisible,
-                target = $(this.options.minicart.list);
+                target = $(this.options.minicart.list),
+                outerHeight;
 
             target.children().each(function () {
-                $(this).collapsible();
-                var outerHeight = $(this).outerHeight();
+
+                if ($(this).find('.options').length > 0) {
+                    $(this).collapsible();
+                }
+                outerHeight = $(this).outerHeight();
 
                 if (counter-- > 0) {
                     height += outerHeight;
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 4de495ab96baae1bf7e9d9188d775acc2679f16b..ba91030f806f7f7ab5d1d98b492de2d899d44584 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
@@ -95,11 +95,13 @@ define([
          * @param {Object} paymentMethodData
          */
         createRenderer: function (paymentMethodData) {
+            var isRendererForMethod = false;
+
             _.find(rendererList(), function (renderer) {
-                var isRendererForMethod = false;
 
-                if (renderer.hasOwnProperty('typeComparatorCallback')
-                    && typeof renderer.typeComparatorCallback == 'function') {
+                if (renderer.hasOwnProperty('typeComparatorCallback') &&
+                    typeof renderer.typeComparatorCallback == 'function'
+                ) {
                     isRendererForMethod = renderer.typeComparatorCallback(renderer.type, paymentMethodData.method);
                 } else {
                     isRendererForMethod = renderer.type === paymentMethodData.method;
@@ -134,7 +136,7 @@ define([
             _.find(items(), function (value) {
                 if (value.item.method.indexOf(paymentMethodCode) === 0) {
                     value.disposeSubscriptions();
-                    this.removeChild(value);
+                    value.destroy();
                 }
             }, this);
         }
diff --git a/app/code/Magento/Config/Block/System/Config/Form/Field.php b/app/code/Magento/Config/Block/System/Config/Form/Field.php
index a138be8accda554d263fb1e1f6f01d9bf6159e7f..b2bb1f1103af70af73311f0a369377d25be5c504 100644
--- a/app/code/Magento/Config/Block/System/Config/Form/Field.php
+++ b/app/code/Magento/Config/Block/System/Config/Form/Field.php
@@ -180,7 +180,7 @@ class Field extends \Magento\Backend\Block\Template implements \Magento\Framewor
      * @param string $html
      * @return string
      */
-    protected function _decorateRowHtml($element, $html)
+    protected function _decorateRowHtml(\Magento\Framework\Data\Form\Element\AbstractElement $element, $html)
     {
         return '<tr id="row_' . $element->getHtmlId() . '">' . $html . '</tr>';
     }
diff --git a/app/code/Magento/Config/Test/Unit/Block/System/Config/Form/Field/NotificationTest.php b/app/code/Magento/Config/Test/Unit/Block/System/Config/Form/Field/NotificationTest.php
index a86323a4d9880b9071edc24f456b4ffd3268228a..ffb8c3bb285788cd8cbf419c31ee545598bbe245 100644
--- a/app/code/Magento/Config/Test/Unit/Block/System/Config/Form/Field/NotificationTest.php
+++ b/app/code/Magento/Config/Test/Unit/Block/System/Config/Form/Field/NotificationTest.php
@@ -20,6 +20,13 @@ class NotificationTest extends \PHPUnit_Framework_TestCase
 
         /** @var \Magento\Framework\Stdlib\DateTime\DateTimeFormatterInterface $dateTimeFormatter */
         $dateTimeFormatter = $objectManager->getObject('Magento\Framework\Stdlib\DateTime\DateTimeFormatter');
+        $localeResolver = $objectManager->getObject('Magento\Framework\Locale\Resolver');
+
+        $reflection = new \ReflectionClass('Magento\Framework\Stdlib\DateTime\DateTimeFormatter');
+        $reflectionProperty = $reflection->getProperty('localeResolver');
+        $reflectionProperty->setAccessible(true);
+        $reflectionProperty->setValue($dateTimeFormatter, $localeResolver);
+
         $formattedDate = $dateTimeFormatter->formatObject($testDatetime);
 
         $htmlId = 'test_HTML_id';
diff --git a/app/code/Magento/Config/etc/system.xsd b/app/code/Magento/Config/etc/system.xsd
index 62ab3f085391d0f7c64c922655bd2aa15634775c..ecede8b085fa9973cb48a4a39ad9e0560de41074 100644
--- a/app/code/Magento/Config/etc/system.xsd
+++ b/app/code/Magento/Config/etc/system.xsd
@@ -95,6 +95,7 @@
                     <xs:element name="header_css" type="xs:string" />
                     <xs:element name="resource" type="typeAclResourceId" />
                     <xs:element ref="group" />
+                    <xs:element name="frontend_model" type="typeModel" />
                 </xs:choice>
             </xs:sequence>
             <xs:attributeGroup ref="elementsAttributeGroup"/>
diff --git a/app/code/Magento/Config/etc/system_file.xsd b/app/code/Magento/Config/etc/system_file.xsd
index 7d134b518b12018112cc76775e973c1da1a32ffb..514e287e6b0014853590e4ca97398aa2dfb99dd3 100644
--- a/app/code/Magento/Config/etc/system_file.xsd
+++ b/app/code/Magento/Config/etc/system_file.xsd
@@ -106,6 +106,7 @@
                     <xs:element name="resource" type="typeAclResourceId" />
                     <xs:element ref="group" />
                     <xs:element name="include" type="includeType"/>
+                    <xs:element name="frontend_model" type="typeModel" />
                 </xs:choice>
             </xs:sequence>
 
diff --git a/app/code/Magento/ConfigurableImportExport/Model/Import/Product/Type/Configurable.php b/app/code/Magento/ConfigurableImportExport/Model/Import/Product/Type/Configurable.php
index 097557ec1170527d35b2d696dd5f4fc4fd29b032..4f0cfb3f107b1207a5acf7c52f29399a99209b87 100644
--- a/app/code/Magento/ConfigurableImportExport/Model/Import/Product/Type/Configurable.php
+++ b/app/code/Magento/ConfigurableImportExport/Model/Import/Product/Type/Configurable.php
@@ -10,6 +10,7 @@
 
 namespace Magento\ConfigurableImportExport\Model\Import\Product\Type;
 
+use Magento\Catalog\Api\Data\ProductInterface;
 use Magento\CatalogImportExport\Model\Import\Product as ImportProduct;
 
 /**
@@ -17,6 +18,7 @@ use Magento\CatalogImportExport\Model\Import\Product as ImportProduct;
  * @package Magento\ConfigurableImportExport\Model\Import\Product\Type
  * @SuppressWarnings(PHPMD.TooManyFields)
  * @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  */
 class Configurable extends \Magento\CatalogImportExport\Model\Import\Product\Type\AbstractType
 {
@@ -183,6 +185,13 @@ class Configurable extends \Magento\CatalogImportExport\Model\Import\Product\Typ
      */
     protected $_nextAttrId;
 
+    /**
+     * Product entity identifier field
+     *
+     * @var string
+     */
+    private $productEntityIdentifierField;
+
     /**
      * @param \Magento\Eav\Model\ResourceModel\Entity\Attribute\Set\CollectionFactory $attrSetColFac
      * @param \Magento\Catalog\Model\ResourceModel\Product\Attribute\CollectionFactory $prodAttrColFac
@@ -201,11 +210,11 @@ class Configurable extends \Magento\CatalogImportExport\Model\Import\Product\Typ
         \Magento\ImportExport\Model\ResourceModel\Helper $resourceHelper,
         \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory $_productColFac
     ) {
+        parent::__construct($attrSetColFac, $prodAttrColFac, $resource, $params);
         $this->_productTypesConfig = $productTypesConfig;
         $this->_resourceHelper = $resourceHelper;
         $this->_resource = $resource;
         $this->_productColFac = $_productColFac;
-        parent::__construct($attrSetColFac, $prodAttrColFac, $resource, $params);
         $this->_connection = $this->_entityModel->getConnection();
     }
 
@@ -318,9 +327,9 @@ class Configurable extends \Magento\CatalogImportExport\Model\Import\Product\Typ
                 foreach ($dataWithExtraVirtualRows as $data) {
                     if (!empty($data['_super_products_sku'])) {
                         if (isset($newSku[$data['_super_products_sku']])) {
-                            $productIds[] = $newSku[$data['_super_products_sku']]['entity_id'];
+                            $productIds[] = $newSku[$data['_super_products_sku']][$this->getProductEntityLinkField()];
                         } elseif (isset($oldSku[$data['_super_products_sku']])) {
-                            $productIds[] = $oldSku[$data['_super_products_sku']]['entity_id'];
+                            $productIds[] = $oldSku[$data['_super_products_sku']][$this->getProductEntityLinkField()];
                         }
                     }
                 }
@@ -330,7 +339,7 @@ class Configurable extends \Magento\CatalogImportExport\Model\Import\Product\Typ
                 'type_id',
                 $this->_productTypesConfig->getComposableTypes()
             )->addFieldToFilter(
-                'entity_id',
+                $this->getProductEntityLinkField(),
                 ['in' => $productIds]
             )->addAttributeToSelect(
                 array_keys($this->_superAttributes)
@@ -340,7 +349,8 @@ class Configurable extends \Magento\CatalogImportExport\Model\Import\Product\Typ
                 $data = array_intersect_key($product->getData(), $this->_superAttributes);
                 foreach ($data as $attrCode => $value) {
                     $attrId = $this->_superAttributes[$attrCode]['id'];
-                    $this->_skuSuperAttributeValues[$attrSetName][$product->getId()][$attrId] = $value;
+                    $productId = $product->getData($this->getProductEntityLinkField());
+                    $this->_skuSuperAttributeValues[$attrSetName][$productId][$attrId] = $value;
                 }
             }
         }
@@ -361,7 +371,7 @@ class Configurable extends \Magento\CatalogImportExport\Model\Import\Product\Typ
         foreach ($bunch as $rowData) {
             $sku = $rowData[ImportProduct::COL_SKU];
             $productData = isset($newSku[$sku]) ? $newSku[$sku] : $oldSku[$sku];
-            $productIds[] = $productData['entity_id'];
+            $productIds[] = $productData[$this->getProductEntityLinkField()];
         }
 
         $this->_productSuperAttrs = [];
@@ -434,7 +444,7 @@ class Configurable extends \Magento\CatalogImportExport\Model\Import\Product\Typ
                     $usedCombs[$comb] = true;
                 }
                 $this->_superAttributesData['super_link'][] = [
-                    'product_id' => $assocId,
+                    'product_id' => $this->_productSuperData['assoc_entity_ids'][$assocId],
                     'parent_id' => $this->_productSuperData['product_id'],
                 ];
                 $this->_superAttributesData['relation'][] = [
@@ -608,15 +618,16 @@ class Configurable extends \Magento\CatalogImportExport\Model\Import\Product\Typ
      */
     protected function _collectSuperData($rowData)
     {
-        $productId = $this->_productData['entity_id'];
+        $entityId = $this->_productData[$this->getProductEntityIdentifierField()];
+        $linkId = $this->_productData[$this->getProductEntityLinkField()];
 
         $this->_processSuperData();
 
         $this->_productSuperData = [
-            'product_id' => $productId,
+            'product_id' => $linkId,
+            'entity_id' => $entityId,
             'attr_set_code' => $this->_productData['attr_set_code'],
-            'used_attributes' => empty($this->_skuSuperData[$productId]) ? [] : $this
-                ->_skuSuperData[$productId],
+            'used_attributes' => empty($this->_skuSuperData[$linkId]) ? [] : $this->_skuSuperData[$linkId],
             'assoc_ids' => [],
         ];
 
@@ -631,15 +642,16 @@ class Configurable extends \Magento\CatalogImportExport\Model\Import\Product\Typ
             }
             $attrParams = $this->_superAttributes[$data['_super_attribute_code']];
 
-            if ($this->_getSuperAttributeId($productId, $attrParams['id'])) {
-                $productSuperAttrId = $this->_getSuperAttributeId($productId, $attrParams['id']);
-            } elseif (isset($this->_superAttributesData['attributes'][$productId][$attrParams['id']])) {
+            // @todo understand why do we need this condition
+            if ($this->_getSuperAttributeId($linkId, $attrParams['id'])) {
+                $productSuperAttrId = $this->_getSuperAttributeId($linkId, $attrParams['id']);
+            } elseif (isset($this->_superAttributesData['attributes'][$linkId][$attrParams['id']])) {
                 $attributes = $this->_superAttributesData['attributes'];
-                $productSuperAttrId = $attributes[$productId][$attrParams['id']]['product_super_attribute_id'];
-                $this->_collectSuperDataLabels($data, $productSuperAttrId, $productId, $variationLabels);
+                $productSuperAttrId = $attributes[$linkId][$attrParams['id']]['product_super_attribute_id'];
+                $this->_collectSuperDataLabels($data, $productSuperAttrId, $linkId, $variationLabels);
             } else {
                 $productSuperAttrId = $this->_getNextAttrId();
-                $this->_collectSuperDataLabels($data, $productSuperAttrId, $productId, $variationLabels);
+                $this->_collectSuperDataLabels($data, $productSuperAttrId, $linkId, $variationLabels);
             }
         }
         //@codingStandardsIgnoreEnd
@@ -658,18 +670,19 @@ class Configurable extends \Magento\CatalogImportExport\Model\Import\Product\Typ
         $newSku = $this->_entityModel->getNewSku();
         $oldSku = $this->_entityModel->getOldSku();
         if (!empty($data['_super_products_sku'])) {
-            $superProductId = '';
             if (isset($newSku[$data['_super_products_sku']])) {
-                $superProductId = $newSku[$data['_super_products_sku']]['entity_id'];
+                $superProductRowId = $newSku[$data['_super_products_sku']][$this->getProductEntityLinkField()];
+                $superProductEntityId = $newSku[$data['_super_products_sku']][$this->getProductEntityIdentifierField()];
             } elseif (isset($oldSku[$data['_super_products_sku']])) {
-                $superProductId = $oldSku[$data['_super_products_sku']]['entity_id'];
+                $superProductRowId = $oldSku[$data['_super_products_sku']][$this->getProductEntityLinkField()];
+                $superProductEntityId = $oldSku[$data['_super_products_sku']][$this->getProductEntityIdentifierField()];
             }
-
-            if ($superProductId) {
+            if (isset($superProductRowId)) {
                 if (isset($data['display']) && $data['display'] == 0) {
-                    $this->_simpleIdsToDelete[] = $superProductId;
+                    $this->_simpleIdsToDelete[] = $superProductRowId;
                 } else {
-                    $this->_productSuperData['assoc_ids'][$superProductId] = true;
+                    $this->_productSuperData['assoc_ids'][$superProductRowId] = true;
+                    $this->_productSuperData['assoc_entity_ids'][$superProductRowId] = $superProductEntityId;
                 }
             }
         }
@@ -820,4 +833,19 @@ class Configurable extends \Magento\CatalogImportExport\Model\Import\Product\Typ
         }
         return !$error;
     }
+
+    /**
+     * Get product entity identifier field
+     *
+     * @return string
+     */
+    private function getProductEntityIdentifierField()
+    {
+        if (!$this->productEntityIdentifierField) {
+            $this->productEntityIdentifierField = $this->getMetadataPool()
+                ->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class)
+                ->getIdentifierField();
+        }
+        return $this->productEntityIdentifierField;
+    }
 }
diff --git a/app/code/Magento/ConfigurableImportExport/Test/Unit/Model/Import/Product/Type/ConfigurableTest.php b/app/code/Magento/ConfigurableImportExport/Test/Unit/Model/Import/Product/Type/ConfigurableTest.php
index 1c91ac937b53b4e36be96cef85786eaaa38e3c4b..ec788551207522ccfc180f1f6fe94804b00954e1 100644
--- a/app/code/Magento/ConfigurableImportExport/Test/Unit/Model/Import/Product/Type/ConfigurableTest.php
+++ b/app/code/Magento/ConfigurableImportExport/Test/Unit/Model/Import/Product/Type/ConfigurableTest.php
@@ -72,6 +72,11 @@ class ConfigurableTest extends \Magento\ImportExport\Test\Unit\Model\Import\Abst
     /** @var \Magento\Framework\DB\Select|\PHPUnit_Framework_MockObject_MockObject */
     protected $select;
 
+    /**
+     * @var string
+     */
+    protected $productEntityLinkField = 'entity_id';
+
     /**
      * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
      */
@@ -80,14 +85,14 @@ class ConfigurableTest extends \Magento\ImportExport\Test\Unit\Model\Import\Abst
         parent::setUp();
 
         $this->setCollectionFactory = $this->getMock(
-            'Magento\Eav\Model\ResourceModel\Entity\Attribute\Set\CollectionFactory',
+            \Magento\Eav\Model\ResourceModel\Entity\Attribute\Set\CollectionFactory::class,
             ['create'],
             [],
             '',
             false
         );
         $this->setCollection = $this->getMock(
-            'Magento\Eav\Model\ResourceModel\Entity\Attribute\Set\Collection',
+            \Magento\Eav\Model\ResourceModel\Entity\Attribute\Set\Collection::class,
             ['setEntityTypeFilter'],
             [],
             '',
@@ -109,7 +114,7 @@ class ConfigurableTest extends \Magento\ImportExport\Test\Unit\Model\Import\Abst
             ->will($this->returnValue([$item]));
 
         $this->attrCollectionFactory = $this->getMock(
-            'Magento\Catalog\Model\ResourceModel\Product\Attribute\CollectionFactory',
+            \Magento\Catalog\Model\ResourceModel\Product\Attribute\CollectionFactory::class,
             ['create'],
             [],
             '',
@@ -117,7 +122,7 @@ class ConfigurableTest extends \Magento\ImportExport\Test\Unit\Model\Import\Abst
         );
 
         $this->attrCollection = $this->getMock(
-            '\Magento\Catalog\Model\ResourceModel\Product\Attribute\Collection',
+            \Magento\Catalog\Model\ResourceModel\Product\Attribute\Collection::class,
             ['setAttributeSetFilter'],
             [],
             '',
@@ -127,7 +132,7 @@ class ConfigurableTest extends \Magento\ImportExport\Test\Unit\Model\Import\Abst
         $superAttributes = [];
         foreach ($this->_getSuperAttributes() as $superAttribute) {
             $item = $this->getMock(
-                '\Magento\Eav\Model\Entity\Attribute\AbstractAttribute',
+                \Magento\Eav\Model\Entity\Attribute\AbstractAttribute::class,
                 ['isStatic'],
                 $superAttribute,
                 '',
@@ -148,7 +153,7 @@ class ConfigurableTest extends \Magento\ImportExport\Test\Unit\Model\Import\Abst
             ->will($this->returnValue($superAttributes));
 
         $this->_entityModel = $this->getMock(
-            'Magento\CatalogImportExport\Model\Import\Product',
+            \Magento\CatalogImportExport\Model\Import\Product::class,
             [
                 'getNewSku',
                 'getOldSku',
@@ -170,9 +175,8 @@ class ConfigurableTest extends \Magento\ImportExport\Test\Unit\Model\Import\Abst
             1 => 'configurable'
         ];
 
-
         $this->_connection = $this->getMock(
-            'Magento\Framework\DB\Adapter\Pdo\Mysql',
+            \Magento\Framework\DB\Adapter\Pdo\Mysql::class,
             [
                 'select',
                 'fetchAll',
@@ -187,7 +191,7 @@ class ConfigurableTest extends \Magento\ImportExport\Test\Unit\Model\Import\Abst
             false
         );
         $this->select = $this->getMock(
-            'Magento\Framework\DB\Select',
+            \Magento\Framework\DB\Select::class,
             [
                 'from',
                 'where',
@@ -202,7 +206,7 @@ class ConfigurableTest extends \Magento\ImportExport\Test\Unit\Model\Import\Abst
         $this->select->expects($this->any())->method('where')->will($this->returnSelf());
         $this->select->expects($this->any())->method('joinLeft')->will($this->returnSelf());
         $this->_connection->expects($this->any())->method('select')->will($this->returnValue($this->select));
-        $connectionMock = $this->getMock('Magento\Framework\DB\Adapter\Pdo\Mysql', [], [], '', false);
+        $connectionMock = $this->getMock(\Magento\Framework\DB\Adapter\Pdo\Mysql::class, [], [], '', false);
         $connectionMock->expects($this->any())->method('quoteInto')->will($this->returnValue('query'));
         $this->select->expects($this->any())->method('getConnection')->willReturn($connectionMock);
         $this->_connection->expects($this->any())->method('insertOnDuplicate')->willReturnSelf();
@@ -211,7 +215,7 @@ class ConfigurableTest extends \Magento\ImportExport\Test\Unit\Model\Import\Abst
         $this->_connection->expects($this->any())->method('fetchAll')->will($this->returnValue([]));
 
         $this->resource = $this->getMock(
-            '\Magento\Framework\App\ResourceConnection',
+            \Magento\Framework\App\ResourceConnection::class,
             [
                 'getConnection',
                 'getTableName',
@@ -231,7 +235,7 @@ class ConfigurableTest extends \Magento\ImportExport\Test\Unit\Model\Import\Abst
         );
 
         $this->productCollectionFactory = $this->getMock(
-            '\Magento\Catalog\Model\ResourceModel\Product\CollectionFactory',
+            \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory::class,
             ['create'],
             [],
             '',
@@ -239,7 +243,7 @@ class ConfigurableTest extends \Magento\ImportExport\Test\Unit\Model\Import\Abst
         );
 
         $this->productCollection = $this->getMock(
-            '\Magento\Catalog\Model\ResourceModel\Product\Collection',
+            \Magento\Catalog\Model\ResourceModel\Product\Collection::class,
             ['addFieldToFilter', 'addAttributeToSelect'],
             [],
             '',
@@ -254,7 +258,7 @@ class ConfigurableTest extends \Magento\ImportExport\Test\Unit\Model\Import\Abst
         ];
         foreach ($testProducts as $product) {
             $item = $this->getMock(
-                '\Magento\Framework\DataObject',
+                \Magento\Framework\DataObject::class,
                 ['getAttributeSetId'],
                 [],
                 '',
@@ -288,8 +292,21 @@ class ConfigurableTest extends \Magento\ImportExport\Test\Unit\Model\Import\Abst
             'testattr3v3' => '6',
         ]));
 
+        $metadataPoolMock = $this->getMock(\Magento\Framework\Model\Entity\MetadataPool::class, [], [], '', false);
+        $entityMetadataMock = $this->getMock(\Magento\Framework\Model\Entity\EntityMetadata::class, [], [], '', false);
+        $metadataPoolMock->expects($this->any())
+            ->method('getMetadata')
+            ->with(\Magento\Catalog\Api\Data\ProductInterface::class)
+            ->willReturn($entityMetadataMock);
+        $entityMetadataMock->expects($this->any())
+            ->method('getLinkField')
+            ->willReturn($this->productEntityLinkField);
+        $entityMetadataMock->expects($this->any())
+            ->method('getIdentifierField')
+            ->willReturn($this->productEntityLinkField);
+
         $this->configurable = $this->objectManagerHelper->getObject(
-            'Magento\ConfigurableImportExport\Model\Import\Product\Type\Configurable',
+            \Magento\ConfigurableImportExport\Model\Import\Product\Type\Configurable::class,
             [
                 'attrSetColFac' => $this->setCollectionFactory,
                 'prodAttrColFac' => $this->attrCollectionFactory,
@@ -298,6 +315,12 @@ class ConfigurableTest extends \Magento\ImportExport\Test\Unit\Model\Import\Abst
                 'productColFac' => $this->productCollectionFactory
             ]
         );
+        $reflection = new \ReflectionClass(
+            \Magento\ConfigurableImportExport\Model\Import\Product\Type\Configurable::class
+        );
+        $reflectionProperty = $reflection->getProperty('metadataPool');
+        $reflectionProperty->setAccessible(true);
+        $reflectionProperty->setValue($this->configurable, $metadataPoolMock);
     }
 
     /**
@@ -480,25 +503,25 @@ class ConfigurableTest extends \Magento\ImportExport\Test\Unit\Model\Import\Abst
     {
         $this->_entityModel->expects($this->any())->method('getNewSku')->will($this->returnValue([
             'configurableskuI22' =>
-                ['entity_id' => 1, 'type_id' => 'configurable', 'attr_set_code' => 'Default'],
+                [$this->productEntityLinkField => 1, 'type_id' => 'configurable', 'attr_set_code' => 'Default'],
             'testconf2-attr2val1-testattr3v1' =>
-                ['entity_id' => 2, 'type_id' => 'simple', 'attr_set_code' => 'Default'],
+                [$this->productEntityLinkField => 2, 'type_id' => 'simple', 'attr_set_code' => 'Default'],
             'testconf2-attr2val1-testattr30v1' =>
-                ['entity_id' => 20, 'type_id' => 'simple', 'attr_set_code' => 'Default'],
+                [$this->productEntityLinkField => 20, 'type_id' => 'simple', 'attr_set_code' => 'Default'],
             'testconf2-attr2val1-testattr3v2' =>
-                ['entity_id' => 3, 'type_id' => 'simple', 'attr_set_code' => 'Default'],
+                [$this->productEntityLinkField => 3, 'type_id' => 'simple', 'attr_set_code' => 'Default'],
             'testSimple' =>
-                ['entity_id' => 4, 'type_id' => 'simple', 'attr_set_code' => 'Default'],
+                [$this->productEntityLinkField => 4, 'type_id' => 'simple', 'attr_set_code' => 'Default'],
             'testSimpleToSkip' =>
-                ['entity_id' => 5, 'type_id' => 'simple', 'attr_set_code' => 'Default'],
+                [$this->productEntityLinkField => 5, 'type_id' => 'simple', 'attr_set_code' => 'Default'],
             'configurableskuI22withoutLabels' =>
-                ['entity_id' => 6, 'type_id' => 'configurable', 'attr_set_code' => 'Default'],
+                [$this->productEntityLinkField => 6, 'type_id' => 'configurable', 'attr_set_code' => 'Default'],
             'configurableskuI22withoutVariations' =>
-                ['entity_id' => 7, 'type_id' => 'configurable', 'attr_set_code' => 'Default'],
+                [$this->productEntityLinkField => 7, 'type_id' => 'configurable', 'attr_set_code' => 'Default'],
             'configurableskuI22Duplicated' =>
-                ['entity_id' => 8, 'type_id' => 'configurable', 'attr_set_code' => 'Default'],
+                [$this->productEntityLinkField => 8, 'type_id' => 'configurable', 'attr_set_code' => 'Default'],
             'configurableskuI22BadPrice' =>
-                ['entity_id' => 9, 'type_id' => 'configurable', 'attr_set_code' => 'Default'],
+                [$this->productEntityLinkField => 9, 'type_id' => 'configurable', 'attr_set_code' => 'Default'],
         ]));
 
         $this->_connection->expects($this->any())->method('select')->will($this->returnValue($this->select));
@@ -536,7 +559,11 @@ class ConfigurableTest extends \Magento\ImportExport\Test\Unit\Model\Import\Abst
                         ->will($this->returnCallback([$this, 'isRowAllowedToImport']));
 
         $this->_entityModel->expects($this->any())->method('getOldSku')->will($this->returnValue([
-            'testSimpleOld' => ['entity_id' => 10, 'type_id' => 'simple', 'attr_set_code' => 'Default'],
+            'testSimpleOld' => [
+                $this->productEntityLinkField => 10,
+                'type_id' => 'simple',
+                'attr_set_code' => 'Default'
+            ],
         ]));
 
         $this->_entityModel->expects($this->any())->method('getAttrSetIdToName')->willReturn([4 => 'Default']);
diff --git a/app/code/Magento/ConfigurableProduct/Helper/Product/Options/Loader.php b/app/code/Magento/ConfigurableProduct/Helper/Product/Options/Loader.php
index e71e7ccf2f377261b46efc22b974db0d25d22d39..8fe421128e2e437664276eaad91d6b7dcf61dec0 100644
--- a/app/code/Magento/ConfigurableProduct/Helper/Product/Options/Loader.php
+++ b/app/code/Magento/ConfigurableProduct/Helper/Product/Options/Loader.php
@@ -9,6 +9,7 @@ use Magento\Catalog\Api\Data\ProductInterface;
 use Magento\ConfigurableProduct\Api\Data\OptionInterface;
 use Magento\ConfigurableProduct\Model\Product\Type\Configurable;
 use Magento\ConfigurableProduct\Api\Data\OptionValueInterfaceFactory;
+use Magento\Framework\Api\ExtensionAttribute\JoinProcessorInterface;
 
 /**
  * Class Loader
@@ -20,14 +21,23 @@ class Loader
      */
     private $optionValueFactory;
 
+    /**
+     * @var JoinProcessorInterface
+     */
+    private $extensionAttributesJoinProcessor;
+
     /**
      * ReadHandler constructor
      *
      * @param OptionValueInterfaceFactory $optionValueFactory
+     * @param JoinProcessorInterface $extensionAttributesJoinProcessor
      */
-    public function __construct(OptionValueInterfaceFactory $optionValueFactory)
-    {
+    public function __construct(
+        OptionValueInterfaceFactory $optionValueFactory,
+        JoinProcessorInterface $extensionAttributesJoinProcessor
+    ) {
         $this->optionValueFactory = $optionValueFactory;
+        $this->extensionAttributesJoinProcessor = $extensionAttributesJoinProcessor;
     }
 
     /**
@@ -39,8 +49,8 @@ class Loader
         $options = [];
         /** @var Configurable $typeInstance */
         $typeInstance = $product->getTypeInstance();
-        $attributeCollection = $typeInstance->getConfigurableAttributes($product);
-
+        $attributeCollection = $typeInstance->getConfigurableAttributeCollection($product);
+        $this->extensionAttributesJoinProcessor->process($attributeCollection);
         foreach ($attributeCollection as $attribute) {
             $values = [];
             $attributeOptions = $attribute->getOptions();
diff --git a/app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable.php b/app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable.php
index 727b090c73e5b1139436a539943954578ed22f35..b7c4a060bf7e4e685bec38bebe36d657662f130c 100644
--- a/app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable.php
+++ b/app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable.php
@@ -134,6 +134,11 @@ class Configurable extends \Magento\Catalog\Model\Product\Type\AbstractType
      */
     protected $extensionAttributesJoinProcessor;
 
+    /**
+     * @var \Magento\Framework\Cache\FrontendInterface
+     */
+    private $cache;
+
     /**
      * @var MetadataPool
      */
@@ -159,7 +164,7 @@ class Configurable extends \Magento\Catalog\Model\Product\Type\AbstractType
      * @param \Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable $catalogProductTypeConfigurable
      * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
      * @param \Magento\Framework\Api\ExtensionAttribute\JoinProcessorInterface $extensionAttributesJoinProcessor
-     * @param MetadataPool $metadataPool
+     *
      * @SuppressWarnings(PHPMD.ExcessiveParameterList)
      */
     public function __construct(
@@ -180,6 +185,7 @@ class Configurable extends \Magento\Catalog\Model\Product\Type\AbstractType
         \Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable $catalogProductTypeConfigurable,
         \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
         \Magento\Framework\Api\ExtensionAttribute\JoinProcessorInterface $extensionAttributesJoinProcessor,
+        \Magento\Framework\Cache\FrontendInterface $cache,
         MetadataPool $metadataPool
     ) {
         $this->typeConfigurableFactory = $typeConfigurableFactory;
@@ -191,7 +197,7 @@ class Configurable extends \Magento\Catalog\Model\Product\Type\AbstractType
         $this->_scopeConfig = $scopeConfig;
         $this->extensionAttributesJoinProcessor = $extensionAttributesJoinProcessor;
         $this->metadataPool = $metadataPool;
-
+        $this->cache = $cache;
         parent::__construct(
             $catalogProductOption,
             $eavConfig,
@@ -203,6 +209,7 @@ class Configurable extends \Magento\Catalog\Model\Product\Type\AbstractType
             $logger,
             $productRepository
         );
+
     }
 
     /**
@@ -364,9 +371,21 @@ class Configurable extends \Magento\Catalog\Model\Product\Type\AbstractType
             ['group' => 'CONFIGURABLE', 'method' => __METHOD__]
         );
         if (!$product->hasData($this->_configurableAttributes)) {
-            $configurableAttributes = $this->getConfigurableAttributeCollection($product);
-            $this->extensionAttributesJoinProcessor->process($configurableAttributes);
-            $configurableAttributes->orderByPosition()->load();
+            $cacheId =  __CLASS__ . $product->getId();
+            $configurableAttributes = $this->cache->load($cacheId);
+            if ($configurableAttributes) {
+                $configurableAttributes = unserialize($configurableAttributes);
+                $configurableAttributes->setProductFilter($product);
+            } else {
+                $configurableAttributes = $this->getConfigurableAttributeCollection($product);
+                $this->extensionAttributesJoinProcessor->process($configurableAttributes);
+                $configurableAttributes->orderByPosition()->load();
+                $this->cache->save(
+                    serialize($configurableAttributes),
+                    $cacheId,
+                    $product->getIdentities()
+                );
+            }
             $product->setData($this->_configurableAttributes, $configurableAttributes);
         }
         \Magento\Framework\Profiler::stop('CONFIGURABLE:' . __METHOD__);
@@ -461,14 +480,6 @@ class Configurable extends \Magento\Catalog\Model\Product\Type\AbstractType
             ['group' => 'CONFIGURABLE', 'method' => __METHOD__]
         );
         if (!$product->hasData($this->_usedProducts)) {
-            if (is_null($requiredAttributeIds) && is_null($product->getData($this->_configurableAttributes))) {
-                // If used products load before attributes, we will load attributes.
-                $this->getConfigurableAttributes($product);
-                // After attributes loading products loaded too.
-                \Magento\Framework\Profiler::stop('CONFIGURABLE:' . __METHOD__);
-                return $product->getData($this->_usedProducts);
-            }
-
             $usedProducts = [];
             $collection = $this->getUsedProductCollection($product)
                 ->addAttributeToSelect('*')
@@ -564,6 +575,8 @@ class Configurable extends \Magento\Catalog\Model\Product\Type\AbstractType
     public function save($product)
     {
         parent::save($product);
+        $cacheId =  __CLASS__ . $product->getId();
+        $this->cache->remove($cacheId);
 
         $extensionAttributes = $product->getExtensionAttributes();
 
diff --git a/app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable/Attribute.php b/app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable/Attribute.php
index 46579e63d12c104e662cf4da26afb3429906325b..2afb897268a1b4f9fb466df0f7a382050acd2669 100644
--- a/app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable/Attribute.php
+++ b/app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable/Attribute.php
@@ -267,4 +267,25 @@ class Attribute extends \Magento\Framework\Model\AbstractExtensibleModel impleme
         return $this->setData(self::KEY_PRODUCT_ID, $value);
     }
     //@codeCoverageIgnoreEnd
+
+    /**
+     * @inheritdoc
+     */
+    public function __sleep()
+    {
+        return array_diff(
+            parent::__sleep(),
+            ['metadataPool']
+        );
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function __wakeup()
+    {
+        parent::__wakeup();
+        $objectManager = \Magento\Framework\App\ObjectManager::getInstance();
+        $this->metadataPool = $objectManager->get(MetadataPool::class);
+    }
 }
diff --git a/app/code/Magento/ConfigurableProduct/Model/ResourceModel/Indexer/Stock/Configurable.php b/app/code/Magento/ConfigurableProduct/Model/ResourceModel/Indexer/Stock/Configurable.php
index 4a2233b76a891ab4b9593258c7ef60bce00da763..01a6ad969f320ca8da089139dca0754a74029543 100644
--- a/app/code/Magento/ConfigurableProduct/Model/ResourceModel/Indexer/Stock/Configurable.php
+++ b/app/code/Magento/ConfigurableProduct/Model/ResourceModel/Indexer/Stock/Configurable.php
@@ -66,19 +66,7 @@ class Configurable extends \Magento\CatalogInventory\Model\ResourceModel\Indexer
         $psExpr = $this->_addAttributeToSelect($select, 'status', 'e.' . $metadata->getLinkField(), 'cs.store_id');
         $psCond = $connection->quoteInto($psExpr . '=?', ProductStatus::STATUS_ENABLED);
 
-        if ($this->_isManageStock()) {
-            $statusExpr = $connection->getCheckSql(
-                'cisi.use_config_manage_stock = 0 AND cisi.manage_stock = 0',
-                1,
-                'cisi.is_in_stock'
-            );
-        } else {
-            $statusExpr = $connection->getCheckSql(
-                'cisi.use_config_manage_stock = 0 AND cisi.manage_stock = 1',
-                'cisi.is_in_stock',
-                1
-            );
-        }
+        $statusExpr = $this->getStatusExpression($connection);
 
         $optExpr = $connection->getCheckSql("{$psCond} AND le.required_options = 0", 'i.stock_status', 0);
         $stockStatusExpr = $connection->getLeastSql(["MAX({$optExpr})", "MIN({$statusExpr})"]);
diff --git a/app/code/Magento/ConfigurableProduct/Model/ResourceModel/Product/Type/Configurable.php b/app/code/Magento/ConfigurableProduct/Model/ResourceModel/Product/Type/Configurable.php
index 5d7d9acce0c9b37aac3a5895a3122ab8c1654ce8..1cdd974ef0b054d99929d0f3bb6c5189848ad91f 100644
--- a/app/code/Magento/ConfigurableProduct/Model/ResourceModel/Product/Type/Configurable.php
+++ b/app/code/Magento/ConfigurableProduct/Model/ResourceModel/Product/Type/Configurable.php
@@ -9,7 +9,6 @@ namespace Magento\ConfigurableProduct\Model\ResourceModel\Product\Type;
 
 use Magento\Catalog\Api\Data\ProductInterface;
 use Magento\ConfigurableProduct\Api\Data\OptionInterface;
-use Magento\Framework\Model\Entity\MetadataPool;
 
 class Configurable extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb
 {
@@ -21,24 +20,30 @@ class Configurable extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb
     protected $catalogProductRelation;
 
     /**
-     * @var MetadataPool
+     * Product metadata pool
+     *
+     * @var \Magento\Framework\Model\Entity\MetadataPool
      */
     private $metadataPool;
 
+    /**
+     * Product entity link field
+     *
+     * @var string
+     */
+    private $productEntityLinkField;
+
     /**
      * @param \Magento\Framework\Model\ResourceModel\Db\Context $context
      * @param \Magento\Catalog\Model\ResourceModel\Product\Relation $catalogProductRelation
-     * @param MetadataPool $metadataPool
      * @param string $connectionName
      */
     public function __construct(
         \Magento\Framework\Model\ResourceModel\Db\Context $context,
         \Magento\Catalog\Model\ResourceModel\Product\Relation $catalogProductRelation,
-        MetadataPool $metadataPool,
         $connectionName = null
     ) {
         $this->catalogProductRelation = $catalogProductRelation;
-        $this->metadataPool = $metadataPool;
         parent::__construct($context, $connectionName);
     }
 
@@ -60,13 +65,11 @@ class Configurable extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb
      */
     public function getEntityIdByAttribute(OptionInterface $option)
     {
-        $metadata = $this->metadataPool->getMetadata(ProductInterface::class);
-
         $select = $this->getConnection()->select()->from(
             ['e' => $this->getTable('catalog_product_entity')],
             ['e.entity_id']
         )->where(
-            'e.' . $metadata->getLinkField() . '=?',
+            'e.' . $this->getProductEntityLinkField() . '=?',
             $option->getProductId()
         )->limit(1);
 
@@ -86,8 +89,7 @@ class Configurable extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb
             return $this;
         }
 
-        $metadata = $this->metadataPool->getMetadata(ProductInterface::class);
-        $productId = $mainProduct->getData($metadata->getLinkField());
+        $productId = $mainProduct->getData($this->getProductEntityLinkField());
 
         $data = [];
         foreach ($productIds as $id) {
@@ -128,13 +130,12 @@ class Configurable extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb
      */
     public function getChildrenIds($parentId, $required = true)
     {
-        $metadata = $this->metadataPool->getMetadata(ProductInterface::class);
         $select = $this->getConnection()->select()->from(
             ['e' => $this->getTable('catalog_product_entity')],
             ['l.product_id']
         )->join(
             ['l' => $this->getMainTable()],
-            'l.parent_id = e.' . $metadata->getLinkField(),
+            'l.parent_id = e.' . $this->getProductEntityLinkField(),
             []
         )->where(
             'e.entity_id IN (?) AND e.required_options = 0',
@@ -158,15 +159,12 @@ class Configurable extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb
     public function getParentIdsByChild($childId)
     {
         $parentIds = [];
-
-        $metadata = $this->metadataPool->getMetadata(ProductInterface::class);
-
         $select = $this->getConnection()
             ->select()
             ->from(['l' => $this->getMainTable()], [])
             ->join(
                 ['e' => $this->getTable('catalog_product_entity')],
-                'e.' . $metadata->getLinkField() . ' = l.parent_id',
+                'e.' . $this->getProductEntityLinkField() . ' = l.parent_id',
                 ['e.entity_id']
             )->where('l.product_id IN(?)', $childId);
 
@@ -187,8 +185,7 @@ class Configurable extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb
     public function getConfigurableOptions($product, $attributes)
     {
         $attributesOptionsData = [];
-        $metadata = $this->metadataPool->getMetadata(ProductInterface::class);
-        $productLinkFieldId = $product->getData($metadata->getLinkField());
+        $productId = $product->getData($this->getProductEntityLinkField());
         foreach ($attributes as $superAttribute) {
             $select = $this->getConnection()->select()->from(
                 ['super_attribute' => $this->getTable('catalog_product_super_attribute')],
@@ -201,7 +198,7 @@ class Configurable extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb
                 ]
             )->joinInner(
                 ['product_entity' => $this->getTable('catalog_product_entity')],
-                'product_entity.' . $metadata->getLinkField() . ' = super_attribute.product_id',
+                "product_entity.{$this->getProductEntityLinkField()} = super_attribute.product_id",
                 []
             )->joinInner(
                 ['product_link' => $this->getTable('catalog_product_super_link')],
@@ -222,7 +219,8 @@ class Configurable extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb
                     [
                         'entity_value.attribute_id = super_attribute.attribute_id',
                         'entity_value.store_id = 0',
-                        'entity_value.entity_id = product_link.product_id'
+                        "entity_value.{$this->getProductEntityLinkField()} = "
+                        . "entity.{$this->getProductEntityLinkField()}"
                     ]
                 ),
                 []
@@ -248,11 +246,39 @@ class Configurable extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb
                 []
             )->where(
                 'super_attribute.product_id = ?',
-                $productLinkFieldId
+                $productId
             );
-
             $attributesOptionsData[$superAttribute->getAttributeId()] = $this->getConnection()->fetchAll($select);
         }
         return $attributesOptionsData;
     }
+
+    /**
+     * Get product metadata pool
+     *
+     * @return \Magento\Framework\Model\Entity\MetadataPool
+     */
+    private function getMetadataPool()
+    {
+        if (!$this->metadataPool) {
+            $this->metadataPool = \Magento\Framework\App\ObjectManager::getInstance()
+                ->get(\Magento\Framework\Model\Entity\MetadataPool::class);
+        }
+        return $this->metadataPool;
+    }
+
+    /**
+     * Get product entity link field
+     *
+     * @return string
+     */
+    private function getProductEntityLinkField()
+    {
+        if (!$this->productEntityLinkField) {
+            $this->productEntityLinkField = $this->getMetadataPool()
+                ->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class)
+                ->getLinkField();
+        }
+        return $this->productEntityLinkField;
+    }
 }
diff --git a/app/code/Magento/ConfigurableProduct/Model/ResourceModel/Product/Type/Configurable/Attribute/Collection.php b/app/code/Magento/ConfigurableProduct/Model/ResourceModel/Product/Type/Configurable/Attribute/Collection.php
index 0a11e18b822e0007eefed9205f6f04b27adb70dd..9027608058c368647b5858c5cc3c55e6d9de5e82 100644
--- a/app/code/Magento/ConfigurableProduct/Model/ResourceModel/Product/Type/Configurable/Attribute/Collection.php
+++ b/app/code/Magento/ConfigurableProduct/Model/ResourceModel/Product/Type/Configurable/Attribute/Collection.php
@@ -7,7 +7,10 @@
  */
 namespace Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable\Attribute;
 
+use Magento\ConfigurableProduct\Model\Product\Type\Configurable;
+use Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable\Attribute;
 use Magento\Eav\Model\Entity\Attribute\AbstractAttribute;
+use Magento\Framework\App\ObjectManager;
 use Magento\Framework\Model\Entity\MetadataPool;
 use Magento\Catalog\Api\Data\ProductInterface;
 
@@ -41,7 +44,7 @@ class Collection extends \Magento\Framework\Model\ResourceModel\Db\Collection\Ab
     /**
      * Catalog product type configurable
      *
-     * @var \Magento\ConfigurableProduct\Model\Product\Type\Configurable
+     * @var Configurable
      */
     protected $_productTypeConfigurable;
 
@@ -63,9 +66,9 @@ class Collection extends \Magento\Framework\Model\ResourceModel\Db\Collection\Ab
      * @param \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy
      * @param \Magento\Framework\Event\ManagerInterface $eventManager
      * @param \Magento\Store\Model\StoreManagerInterface $storeManager
-     * @param \Magento\ConfigurableProduct\Model\Product\Type\Configurable $catalogProductTypeConfigurable
+     * @param Configurable $catalogProductTypeConfigurable
      * @param \Magento\Catalog\Helper\Data $catalogData
-     * @param \Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable\Attribute $resource
+     * @param Attribute $resource
      * @param MetadataPool $metadataPool
      * @param \Magento\Framework\DB\Adapter\AdapterInterface $connection
      * @SuppressWarnings(PHPMD.ExcessiveParameterList)
@@ -76,9 +79,9 @@ class Collection extends \Magento\Framework\Model\ResourceModel\Db\Collection\Ab
         \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy,
         \Magento\Framework\Event\ManagerInterface $eventManager,
         \Magento\Store\Model\StoreManagerInterface $storeManager,
-        \Magento\ConfigurableProduct\Model\Product\Type\Configurable $catalogProductTypeConfigurable,
+        Configurable $catalogProductTypeConfigurable,
         \Magento\Catalog\Helper\Data $catalogData,
-        \Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable\Attribute $resource,
+        Attribute $resource,
         MetadataPool $metadataPool,
         \Magento\Framework\DB\Adapter\AdapterInterface $connection = null
     ) {
@@ -119,7 +122,7 @@ class Collection extends \Magento\Framework\Model\ResourceModel\Db\Collection\Ab
     /**
      * Get product type
      *
-     * @return \Magento\ConfigurableProduct\Model\Product\Type\Configurable
+     * @return Configurable
      */
     private function getProductType()
     {
@@ -303,8 +306,38 @@ class Collection extends \Magento\Framework\Model\ResourceModel\Db\Collection\Ab
      *
      * @return \Magento\Catalog\Model\Product
      */
-    public function getProduct()
+    private function getProduct()
     {
         return $this->_product;
     }
+
+    /**
+     * @inheritdoc
+     */
+    public function __sleep()
+    {
+        return array_diff(
+            parent::__sleep(),
+            [
+                '_product',
+                '_catalogData',
+                '_productTypeConfigurable',
+                '_storeManager',
+                'metadataPool',
+            ]
+        );
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function __wakeup()
+    {
+        parent::__wakeup();
+        $objectManager = \Magento\Framework\App\ObjectManager::getInstance();
+        $this->_storeManager = $objectManager->get(\Magento\Store\Model\StoreManagerInterface::class);
+        $this->_productTypeConfigurable = $objectManager->get(Configurable::class);
+        $this->_catalogData = $objectManager->get(\Magento\Catalog\Helper\Data::class);
+        $this->metadataPool = $objectManager->get(MetadataPool::class);
+    }
 }
diff --git a/app/code/Magento/ConfigurableProduct/Plugin/Model/Product.php b/app/code/Magento/ConfigurableProduct/Plugin/Model/Product.php
new file mode 100644
index 0000000000000000000000000000000000000000..92870ca91f42c6af17fbb94957f084ba709b8252
--- /dev/null
+++ b/app/code/Magento/ConfigurableProduct/Plugin/Model/Product.php
@@ -0,0 +1,35 @@
+<?php
+/**
+ *
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\ConfigurableProduct\Plugin\Model;
+
+use Magento\ConfigurableProduct\Model\Product\Type\Configurable;
+
+/**
+ * Plugin for Product Identity
+ */
+class Product
+{
+    /**
+     * Add identity of child product to identities
+     *
+     * @param \Magento\Catalog\Model\Product $product
+     * @param string[] $result
+     * @return string[]
+     */
+    public function afterGetIdentities(\Magento\Catalog\Model\Product $product, $result)
+    {
+        /** @var Configurable $productType */
+        $productType = $product->getTypeInstance();
+        if ($productType instanceof Configurable) {
+            foreach ($productType->getUsedProductIds($product) as $productId) {
+                $result[] = \Magento\Catalog\Model\Product::CACHE_TAG . '_' . $productId;
+            }
+        }
+        return $result;
+    }
+}
diff --git a/app/code/Magento/ConfigurableProduct/Test/Unit/Helper/Product/Options/LoaderTest.php b/app/code/Magento/ConfigurableProduct/Test/Unit/Helper/Product/Options/LoaderTest.php
index b0f840ac224c24d600e328aa459213e847ee5365..c6081376d59e586a8d737e7f3a61dc7e9e734e53 100644
--- a/app/code/Magento/ConfigurableProduct/Test/Unit/Helper/Product/Options/LoaderTest.php
+++ b/app/code/Magento/ConfigurableProduct/Test/Unit/Helper/Product/Options/LoaderTest.php
@@ -11,6 +11,8 @@ use Magento\ConfigurableProduct\Api\Data\OptionValueInterfaceFactory;
 use Magento\ConfigurableProduct\Helper\Product\Options\Loader;
 use Magento\ConfigurableProduct\Model\Product\Type\Configurable;
 use Magento\ConfigurableProduct\Model\Product\Type\Configurable\Attribute;
+use Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable\Attribute\Collection;
+use Magento\Framework\Api\ExtensionAttribute\JoinProcessorInterface;
 use PHPUnit_Framework_MockObject_MockObject as MockObject;
 
 /**
@@ -52,10 +54,13 @@ class LoaderTest extends \PHPUnit_Framework_TestCase
 
         $this->configurable = $this->getMockBuilder(Configurable::class)
             ->disableOriginalConstructor()
-            ->setMethods(['getConfigurableAttributes'])
+            ->setMethods(['getConfigurableAttributeCollection'])
             ->getMock();
 
-        $this->loader = new Loader($this->optionValueFactory);
+        $extensionAttributesJoinProcessor = $this->getMockBuilder(JoinProcessorInterface::class)
+            ->getMockForAbstractClass();
+
+        $this->loader = new Loader($this->optionValueFactory, $extensionAttributesJoinProcessor);
     }
 
     /**
@@ -75,12 +80,17 @@ class LoaderTest extends \PHPUnit_Framework_TestCase
             ->disableOriginalConstructor()
             ->setMethods(['getOptions', 'setValues'])
             ->getMock();
+
         $attributes = [$attribute];
+        
+        $iterator = $this->getMockBuilder(Collection::class)->disableOriginalConstructor()->getMock();
+        $iterator->expects($this->once())->method('getIterator')
+            ->willReturn(new \ArrayIterator($attributes));
 
         $this->configurable->expects(static::once())
-            ->method('getConfigurableAttributes')
+            ->method('getConfigurableAttributeCollection')
             ->with($this->product)
-            ->willReturn($attributes);
+            ->willReturn($iterator);
 
         $attribute->expects(static::once())
             ->method('getOptions')
diff --git a/app/code/Magento/ConfigurableProduct/Test/Unit/Model/Product/Type/ConfigurableTest.php b/app/code/Magento/ConfigurableProduct/Test/Unit/Model/Product/Type/ConfigurableTest.php
index ef858285e1b8035e30d9867a909ea61b5892fc18..9c2bf6575f683682be8e4d2ee5ac98c57eaf3945 100644
--- a/app/code/Magento/ConfigurableProduct/Test/Unit/Model/Product/Type/ConfigurableTest.php
+++ b/app/code/Magento/ConfigurableProduct/Test/Unit/Model/Product/Type/ConfigurableTest.php
@@ -82,6 +82,9 @@ class ConfigurableTest extends \PHPUnit_Framework_TestCase
      */
     protected $entityMetadata;
 
+    /** @var \PHPUnit_Framework_MockObject_MockObject */
+    private $cache;
+
     /**
      * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
      */
@@ -144,6 +147,8 @@ class ConfigurableTest extends \PHPUnit_Framework_TestCase
             ->method('getMetadata')
             ->with(ProductInterface::class)
             ->willReturn($this->entityMetadata);
+        $this->cache = $this->getMockBuilder(\Magento\Framework\Cache\FrontendInterface::class)
+            ->getMockForAbstractClass();
 
         $this->_model = $this->_objectHelper->getObject(
             'Magento\ConfigurableProduct\Model\Product\Type\Configurable',
@@ -159,6 +164,7 @@ class ConfigurableTest extends \PHPUnit_Framework_TestCase
                 'logger' => $logger,
                 'productRepository' => $this->productRepository,
                 'extensionAttributesJoinProcessor' => $this->extensionAttributesJoinProcessorMock,
+                'cache' => $this->cache,
                 'metadataPool' => $this->metadataPool,
             ]
         );
@@ -440,13 +446,15 @@ class ConfigurableTest extends \PHPUnit_Framework_TestCase
 
         /** @var \Magento\Catalog\Model\Product|\PHPUnit_Framework_MockObject_MockObject $product */
         $product = $this->getMockBuilder('Magento\Catalog\Model\Product')
-            ->setMethods(['getData', 'hasData', 'setData'])
+            ->setMethods(['getData', 'hasData', 'setData', 'getIdentities', 'getId'])
             ->disableOriginalConstructor()
             ->getMock();
         $product->expects($this->once())->method('hasData')->with($configurableAttributes)->willReturn(false);
         $product->expects($this->once())->method('setData')->willReturnSelf();
         $product->expects($this->once())->method('getData')->with($configurableAttributes)->willReturn($expectedData);
+        $product->expects($this->once())->method('getIdentities')->willReturn([1,2,3]);
 
+        
         $attributeCollection = $this->getMockBuilder(
             'Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable\Attribute\Collection'
         )
diff --git a/app/code/Magento/ConfigurableProduct/Test/Unit/Model/ResourceModel/Product/Type/ConfigurableTest.php b/app/code/Magento/ConfigurableProduct/Test/Unit/Model/ResourceModel/Product/Type/ConfigurableTest.php
index 92603ce718c92b8e266de24e7285744e5ef98f6d..d12980c40aed3b9152a3534e6e36cbd9d93812eb 100644
--- a/app/code/Magento/ConfigurableProduct/Test/Unit/Model/ResourceModel/Product/Type/ConfigurableTest.php
+++ b/app/code/Magento/ConfigurableProduct/Test/Unit/Model/ResourceModel/Product/Type/ConfigurableTest.php
@@ -3,7 +3,6 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-
 namespace Magento\ConfigurableProduct\Test\Unit\Model\ResourceModel\Product\Type;
 
 use Magento\Catalog\Api\Data\ProductInterface;
@@ -11,6 +10,9 @@ use Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable;
 use Magento\Framework\Model\ResourceModel\Db\Context;
 use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper;
 
+/**
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ */
 class ConfigurableTest extends \PHPUnit_Framework_TestCase
 {
     /**
@@ -36,57 +38,66 @@ class ConfigurableTest extends \PHPUnit_Framework_TestCase
     /**
      * @var \Magento\Framework\Model\Entity\MetadataPool|\PHPUnit_Framework_MockObject_MockObject
      */
-    protected $metadataPool;
+    protected $metadataPoolMock;
 
     /**
      * @var \Magento\Framework\Model\Entity\EntityMetadata|\PHPUnit_Framework_MockObject_MockObject
      */
-    protected $metadata;
+    protected $metadataMock;
 
     protected function setUp()
     {
-        $connectionMock = $this->getMockBuilder('\Magento\Framework\DB\Adapter\AdapterInterface')->getMock();
-
-        $this->resource = $this->getMock('Magento\Framework\App\ResourceConnection', [], [], '', false);
+        $connectionMock = $this->getMockBuilder(\Magento\Framework\DB\Adapter\AdapterInterface::class)->getMock();
+        $this->resource = $this->getMock(\Magento\Framework\App\ResourceConnection::class, [], [], '', false);
         $this->resource->expects($this->any())->method('getConnection')->will($this->returnValue($connectionMock));
-
-        $this->relation = $this->getMock('Magento\Catalog\Model\ResourceModel\Product\Relation', [], [], '', false);
-
-        $this->metadata = $this->getMock('Magento\Framework\Model\Entity\EntityMetadata', [], [], '', false);
-
-        $this->metadataPool = $this->getMock('Magento\Framework\Model\Entity\MetadataPool', [], [], '', false);
-        $this->metadataPool->expects($this->any())
+        $this->relation = $this->getMock(
+            \Magento\Catalog\Model\ResourceModel\Product\Relation::class,
+            [],
+            [],
+            '',
+            false
+        );
+        $this->metadataMock = $this->getMock(\Magento\Framework\Model\Entity\EntityMetadata::class, [], [], '', false);
+        $this->metadataPoolMock = $this->getMock(
+            \Magento\Framework\Model\Entity\MetadataPool::class,
+            [],
+            [],
+            '',
+            false
+        );
+        $this->metadataPoolMock->expects($this->any())
             ->method('getMetadata')
             ->with(ProductInterface::class)
-            ->willReturn($this->metadata);
-
+            ->willReturn($this->metadataMock);
         $this->objectManagerHelper = new ObjectManagerHelper($this);
         $this->configurable = $this->objectManagerHelper->getObject(
-            'Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable',
+            \Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable::class,
             [
                 'resource' => $this->resource,
                 'catalogProductRelation' => $this->relation,
-                'metadataPool' => $this->metadataPool
             ]
         );
+        $reflection = new \ReflectionClass(
+            \Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable::class
+        );
+        $reflectionProperty = $reflection->getProperty('metadataPool');
+        $reflectionProperty->setAccessible(true);
+        $reflectionProperty->setValue($this->configurable, $this->metadataPoolMock);
     }
-
     public function testSaveProducts()
     {
         /** @var \Magento\Catalog\Model\Product|\PHPUnit_Framework_MockObject_MockObject $mainProduct */
-        $mainProduct = $this->getMockBuilder('Magento\Catalog\Model\Product')
+        $mainProduct = $this->getMockBuilder(\Magento\Catalog\Model\Product::class)
             ->setMethods(['__sleep', '__wakeup', 'getData'])
             ->disableOriginalConstructor()
             ->getMock();
-
-        $this->metadata->expects($this->once())
+        $this->metadataMock->expects($this->once())
             ->method('getLinkField')
             ->willReturn('link');
         $mainProduct->expects($this->once())
             ->method('getData')
             ->with('link')
             ->willReturn(3);
-
         $this->configurable->saveProducts($mainProduct, [1, 2, 3]);
     }
 
@@ -101,11 +112,15 @@ class ConfigurableTest extends \PHPUnit_Framework_TestCase
         /** @var Configurable|\PHPUnit_Framework_MockObject_MockObject $configurable */
         $configurable = $this->getMockBuilder(Configurable::class)
             ->setMethods(['getTable', 'getConnection'])
-            ->setConstructorArgs([$context, $this->relation, $this->metadataPool])
+            ->setConstructorArgs([$context, $this->relation])
             ->getMock();
+        $reflection = new \ReflectionClass(Configurable::class);
+        $reflectionProperty = $reflection->getProperty('metadataPool');
+        $reflectionProperty->setAccessible(true);
+        $reflectionProperty->setValue($configurable, $this->metadataPoolMock);
 
         /** @var \Magento\Catalog\Model\Product|\PHPUnit_Framework_MockObject_MockObject $product */
-        $product = $this->getMockBuilder('Magento\Catalog\Model\Product')
+        $product = $this->getMockBuilder(\Magento\Catalog\Model\Product::class)
             ->setMethods(
                 [
                     '__sleep',
@@ -115,15 +130,13 @@ class ConfigurableTest extends \PHPUnit_Framework_TestCase
             )
             ->disableOriginalConstructor()
             ->getMock();
-
-        $this->metadata->expects(self::exactly(2))
+        $this->metadataMock->expects($this->once())
             ->method('getLinkField')
             ->willReturn('link');
         $product->expects($this->once())
             ->method('getData')
             ->with('link')
             ->willReturn('getId value');
-
         $configurable->expects($this->exactly(7))
             ->method('getTable')
             ->will(
@@ -140,7 +153,7 @@ class ConfigurableTest extends \PHPUnit_Framework_TestCase
                 )
             );
         $select = $this->getMock(
-            '\Magento\Framework\DB\Select',
+            \Magento\Framework\DB\Select::class,
             [
                 'from',
                 'joinInner',
@@ -164,9 +177,8 @@ class ConfigurableTest extends \PHPUnit_Framework_TestCase
                 ]
             )
             ->will($this->returnSelf());
-
         $superAttribute = $this->getMock(
-            '\Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable\Attribute',
+            \Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable\Attribute::class,
             [
                 'getBackendTable',
                 'getAttributeId',
@@ -184,7 +196,6 @@ class ConfigurableTest extends \PHPUnit_Framework_TestCase
         $attributes = [
             $superAttribute,
         ];
-
         $select->expects($this->exactly(5))
             ->method('joinInner')
             ->will($this->returnSelf())
@@ -216,13 +227,12 @@ class ConfigurableTest extends \PHPUnit_Framework_TestCase
                         [
                             'entity_value.attribute_id = super_attribute.attribute_id',
                             'entity_value.store_id = 0',
-                            'entity_value.entity_id = product_link.product_id'
+                            'entity_value.link = entity.link'
                         ]
                     ),
                     []
                 ]
             );
-
         $select->expects($this->exactly(2))
             ->method('joinLeft')
             ->will($this->returnSelf())
@@ -257,8 +267,7 @@ class ConfigurableTest extends \PHPUnit_Framework_TestCase
                 'super_attribute.product_id = ?',
                 'getId value'
             );
-
-        $readerAdapter = $this->getMockBuilder('\Magento\Framework\DB\Adapter\AdapterInterface')
+        $readerAdapter = $this->getMockBuilder(\Magento\Framework\DB\Adapter\AdapterInterface::class)
             ->setMethods([
                 'select',
                 'fetchAll',
@@ -272,16 +281,13 @@ class ConfigurableTest extends \PHPUnit_Framework_TestCase
             ->method('fetchAll')
             ->with($select)
             ->willReturn('fetchAll value');
-
         $configurable->expects($this->exactly(2))
             ->method('getConnection')
             ->willReturn($readerAdapter);
         $expectedAttributesOptionsData = [
             'getAttributeId value' => 'fetchAll value',
         ];
-
         $actualAttributesOptionsData = $configurable->getConfigurableOptions($product, $attributes);
-
         $this->assertEquals($expectedAttributesOptionsData, $actualAttributesOptionsData);
     }
 }
diff --git a/app/code/Magento/ConfigurableProduct/etc/di.xml b/app/code/Magento/ConfigurableProduct/etc/di.xml
index c0622f73afe82c653383d45e50a5542a6fa9cb76..b3bfa1fb3111afb44d1a332a9323ec563ae8ad82 100644
--- a/app/code/Magento/ConfigurableProduct/etc/di.xml
+++ b/app/code/Magento/ConfigurableProduct/etc/di.xml
@@ -59,6 +59,9 @@
     <type name="Magento\Catalog\Api\ProductRepositoryInterface">
         <plugin name="configurableProductSaveOptions" type="\Magento\ConfigurableProduct\Model\Plugin\AroundProductRepositorySave"/>
     </type>
+    <type name="Magento\Catalog\Model\Product">
+        <plugin name="configurable_identity" type="Magento\ConfigurableProduct\Plugin\Model\Product" />
+    </type>
     <type name="Magento\Catalog\Model\Product\Type">
         <plugin name="configurable_output" type="Magento\ConfigurableProduct\Model\Product\Type\Plugin" />
     </type>
@@ -143,4 +146,9 @@
     <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>
+        </arguments>
+    </type>
 </config>
diff --git a/app/code/Magento/Cron/Test/Unit/Observer/ProcessCronQueueObserverTest.php b/app/code/Magento/Cron/Test/Unit/Observer/ProcessCronQueueObserverTest.php
index e582e83f3dcd4b9c2ad19da5307fc9d312ad0cbf..d08150611966309ef10ce500d7adda03489da305 100644
--- a/app/code/Magento/Cron/Test/Unit/Observer/ProcessCronQueueObserverTest.php
+++ b/app/code/Magento/Cron/Test/Unit/Observer/ProcessCronQueueObserverTest.php
@@ -642,13 +642,14 @@ class ProcessCronQueueObserverTest extends \PHPUnit_Framework_TestCase
         ];
 
         // This item was scheduled 2 days ago
+        /** @var \Magento\Cron\Model\Schedule|\PHPUnit_Framework_MockObject_MockObject $schedule1 */
         $schedule1 = $this->getMockBuilder(
             'Magento\Cron\Model\Schedule'
         )->disableOriginalConstructor()->setMethods(
             ['getExecutedAt', 'getScheduledAt', 'getStatus', 'delete', '__wakeup']
         )->getMock();
         $schedule1->expects($this->any())->method('getExecutedAt')->will($this->returnValue(null));
-        $schedule1->expects($this->any())->method('getScheduledAt')->will($this->returnValue('-2 day -1 hour'));
+        $schedule1->expects($this->any())->method('getScheduledAt')->will($this->returnValue('-2 day -2 hour'));
         $schedule1->expects($this->any())->method('getStatus')->will($this->returnValue(Schedule::STATUS_MISSED));
         //we expect this job be deleted from the list
         $schedule1->expects($this->once())->method('delete')->will($this->returnValue(true));
diff --git a/app/code/Magento/Customer/Controller/Account/CreatePost.php b/app/code/Magento/Customer/Controller/Account/CreatePost.php
index b332b69425637df8a735e7a0e9b5579e29d62138..8cf6bb8b313ceb49866e2bffeaf5552b9f596040 100644
--- a/app/code/Magento/Customer/Controller/Account/CreatePost.php
+++ b/app/code/Magento/Customer/Controller/Account/CreatePost.php
@@ -199,6 +199,7 @@ class CreatePost extends \Magento\Customer\Controller\AbstractAccount
      *
      * @return void
      * @SuppressWarnings(PHPMD.CyclomaticComplexity)
+     * @SuppressWarnings(PHPMD.NPathComplexity)
      */
     public function execute()
     {
@@ -258,6 +259,12 @@ class CreatePost extends \Magento\Customer\Controller\AbstractAccount
             } else {
                 $this->session->setCustomerDataAsLoggedIn($customer);
                 $this->messageManager->addSuccess($this->getSuccessMessage());
+                $requestedRedirect = $this->accountRedirect->getRedirectCookie();
+                if (!$this->scopeConfig->getValue('customer/startup/redirect_dashboard') && $requestedRedirect) {
+                    $resultRedirect->setUrl($this->_redirect->success($requestedRedirect));
+                    $this->accountRedirect->clearRedirectCookie();
+                    return $resultRedirect;
+                }
                 $resultRedirect = $this->accountRedirect->getRedirect();
             }
             return $resultRedirect;
diff --git a/app/code/Magento/Customer/Controller/Account/LoginPost.php b/app/code/Magento/Customer/Controller/Account/LoginPost.php
index a65e81ab876b5e0a8990301fa02bac46653b9b32..a5ae36310fa22f456728f72e02d581c6cd165f9e 100644
--- a/app/code/Magento/Customer/Controller/Account/LoginPost.php
+++ b/app/code/Magento/Customer/Controller/Account/LoginPost.php
@@ -117,6 +117,14 @@ class LoginPost extends \Magento\Customer\Controller\AbstractAccount
                     $customer = $this->customerAccountManagement->authenticate($login['username'], $login['password']);
                     $this->session->setCustomerDataAsLoggedIn($customer);
                     $this->session->regenerateId();
+                    $redirectUrl = $this->accountRedirect->getRedirectCookie();
+                    if (!$this->getScopeConfig()->getValue('customer/startup/redirect_dashboard') && $redirectUrl) {
+                        $this->accountRedirect->clearRedirectCookie();
+                        $resultRedirect = $this->resultRedirectFactory->create();
+                        // URL is checked to be internal in $this->_redirect->success()
+                        $resultRedirect->setUrl($this->_redirect->success($redirectUrl));
+                        return $resultRedirect;
+                    }
                 } catch (EmailNotConfirmedException $e) {
                     $value = $this->customerUrl->getEmailConfirmationUrl($login['username']);
                     $message = __(
diff --git a/app/code/Magento/Customer/Controller/Ajax/Login.php b/app/code/Magento/Customer/Controller/Ajax/Login.php
index 4258ebf1ef0e18d1c4042425036a343860e8ab38..8ae80ce73fd3d3664eaa1520bacad8bfd2a54d14 100644
--- a/app/code/Magento/Customer/Controller/Ajax/Login.php
+++ b/app/code/Magento/Customer/Controller/Ajax/Login.php
@@ -9,12 +9,16 @@ namespace Magento\Customer\Controller\Ajax;
 use Magento\Customer\Api\AccountManagementInterface;
 use Magento\Framework\Exception\EmailNotConfirmedException;
 use Magento\Framework\Exception\InvalidEmailOrPasswordException;
+use Magento\Framework\App\ObjectManager;
+use Magento\Customer\Model\Account\Redirect as AccountRedirect;
+use Magento\Framework\App\Config\ScopeConfigInterface;
 
 /**
  * Login controller
  *
  * @method \Magento\Framework\App\RequestInterface getRequest()
  * @method \Magento\Framework\App\Response\Http getResponse()
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  */
 class Login extends \Magento\Framework\App\Action\Action
 {
@@ -43,6 +47,16 @@ class Login extends \Magento\Framework\App\Action\Action
      */
     protected $resultRawFactory;
 
+    /**
+     * @var AccountRedirect
+     */
+    protected $accountRedirect;
+
+    /**
+     * @var ScopeConfigInterface
+     */
+    protected $scopeConfig;
+
     /**
      * Initialize Login controller
      *
@@ -69,12 +83,62 @@ class Login extends \Magento\Framework\App\Action\Action
         $this->resultRawFactory = $resultRawFactory;
     }
 
+    /**
+     * Get account redirect.
+     * For release backward compatibility.
+     *
+     * @deprecated
+     * @return AccountRedirect
+     */
+    protected function getAccountRedirect()
+    {
+        if (!is_object($this->accountRedirect)) {
+            $this->accountRedirect = ObjectManager::getInstance()->get(AccountRedirect::class);
+        }
+        return $this->accountRedirect;
+    }
+
+    /**
+     * Account redirect setter for unit tests.
+     *
+     * @deprecated
+     * @param AccountRedirect $value
+     * @return void
+     */
+    public function setAccountRedirect($value)
+    {
+        $this->accountRedirect = $value;
+    }
+
+    /**
+     * @deprecated
+     * @return ScopeConfigInterface
+     */
+    protected function getScopeConfig()
+    {
+        if (!is_object($this->scopeConfig)) {
+            $this->scopeConfig = ObjectManager::getInstance()->get(ScopeConfigInterface::class);
+        }
+        return $this->scopeConfig;
+    }
+
+    /**
+     * @deprecated
+     * @param ScopeConfigInterface $value
+     * @return void
+     */
+    public function setScopeConfig($value)
+    {
+        $this->scopeConfig = $value;
+    }
+
     /**
      * Login registered users and initiate a session.
      *
      * Expects a POST. ex for JSON {"username":"user@magento.com", "password":"userpassword"}
      *
      * @return \Magento\Framework\Controller\ResultInterface
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
      */
     public function execute()
     {
@@ -103,6 +167,11 @@ class Login extends \Magento\Framework\App\Action\Action
             );
             $this->customerSession->setCustomerDataAsLoggedIn($customer);
             $this->customerSession->regenerateId();
+            $redirectRoute = $this->getAccountRedirect()->getRedirectCookie();
+            if (!$this->getScopeConfig()->getValue('customer/startup/redirect_dashboard') && $redirectRoute) {
+                $response['redirectUrl'] = $this->_redirect->success($redirectRoute);
+                $this->getAccountRedirect()->clearRedirectCookie();
+            }
         } catch (EmailNotConfirmedException $e) {
             $response = [
                 'errors' => true,
diff --git a/app/code/Magento/Customer/Model/Account/Redirect.php b/app/code/Magento/Customer/Model/Account/Redirect.php
index ac134182e2aecaf18fa6b713234eaf0113bc9124..c3c8cc6d63f51156b7b33f06e5704d2e49318c78 100644
--- a/app/code/Magento/Customer/Model/Account/Redirect.php
+++ b/app/code/Magento/Customer/Model/Account/Redirect.php
@@ -16,12 +16,17 @@ use Magento\Framework\App\Config\ScopeConfigInterface;
 use Magento\Framework\Controller\Result\Redirect as ResultRedirect;
 use Magento\Framework\Controller\Result\Forward as ResultForward;
 use Magento\Framework\Url\DecoderInterface;
+use Magento\Framework\App\ObjectManager;
+use Magento\Framework\Stdlib\CookieManagerInterface;
 
 /**
  * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  */
 class Redirect
 {
+    /** URL to redirect user on successful login or registration */
+    const LOGIN_REDIRECT_URL = 'login_redirect';
+
     /**
      * @var RequestInterface
      */
@@ -57,6 +62,11 @@ class Redirect
      */
     protected $resultFactory;
 
+    /**
+     * @var CookieManagerInterface
+     */
+    protected $cookieManager;
+
     /**
      * @param RequestInterface $request
      * @param Session $customerSession
@@ -205,4 +215,61 @@ class Redirect
     {
         $this->session->setBeforeAuthUrl($url);
     }
+
+    /**
+     * Get Cookie manager. For release backward compatibility.
+     *
+     * @deprecated
+     * @return CookieManagerInterface
+     */
+    protected function getCookieManager()
+    {
+        if (!is_object($this->cookieManager)) {
+            $this->cookieManager = ObjectManager::getInstance()->get(CookieManagerInterface::class);
+        }
+        return $this->cookieManager;
+    }
+
+    /**
+     * Set cookie manager. For unit tests.
+     *
+     * @deprecated
+     * @param object $value
+     * @return void
+     */
+    public function setCookieManager($value)
+    {
+        $this->cookieManager = $value;
+    }
+
+    /**
+     * Get redirect route from cookie for case of successful login/registration
+     *
+     * @return null|string
+     */
+    public function getRedirectCookie()
+    {
+        return $this->getCookieManager()->getCookie(self::LOGIN_REDIRECT_URL, null);
+    }
+
+    /**
+     * Save redirect route to cookie for case of successful login/registration
+     *
+     * @param string $route
+     * @return void
+     */
+    public function setRedirectCookie($route)
+    {
+        $this->getCookieManager()->setPublicCookie(self::LOGIN_REDIRECT_URL, $route);
+    }
+
+    /**
+     * Clear cookie with requested route
+     *
+     * @return void
+     */
+    public function clearRedirectCookie()
+    {
+        $this->getCookieManager()->deleteCookie(self::LOGIN_REDIRECT_URL);
+    }
 }
diff --git a/app/code/Magento/Customer/Test/Unit/Controller/Account/LoginPostTest.php b/app/code/Magento/Customer/Test/Unit/Controller/Account/LoginPostTest.php
index f89a11e0058ea1cb908cec6a2fb4602f3623ca70..51e3b427aca9d207dbbe6f2a88911314e4a8246e 100644
--- a/app/code/Magento/Customer/Test/Unit/Controller/Account/LoginPostTest.php
+++ b/app/code/Magento/Customer/Test/Unit/Controller/Account/LoginPostTest.php
@@ -64,6 +64,16 @@ class LoginPostTest extends \PHPUnit_Framework_TestCase
     /**
      * @var Redirect | \PHPUnit_Framework_MockObject_MockObject
      */
+    protected $resultRedirect;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $redirectFactory;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
     protected $redirect;
 
     /**
@@ -137,12 +147,12 @@ class LoginPostTest extends \PHPUnit_Framework_TestCase
             ->with($this->request)
             ->willReturn($isValidFormKey);
 
-        $this->redirect->expects($this->once())
+        $this->resultRedirect->expects($this->once())
             ->method('setPath')
             ->with('*/*/')
             ->willReturnSelf();
 
-        $this->assertSame($this->redirect, $this->controller->execute());
+        $this->assertSame($this->resultRedirect, $this->controller->execute());
     }
 
     /**
@@ -183,9 +193,9 @@ class LoginPostTest extends \PHPUnit_Framework_TestCase
 
         $this->accountRedirect->expects($this->once())
             ->method('getRedirect')
-            ->willReturn($this->redirect);
+            ->willReturn($this->resultRedirect);
 
-        $this->assertSame($this->redirect, $this->controller->execute());
+        $this->assertSame($this->resultRedirect, $this->controller->execute());
     }
 
     public function testExecuteEmptyLoginData()
@@ -214,9 +224,79 @@ class LoginPostTest extends \PHPUnit_Framework_TestCase
 
         $this->accountRedirect->expects($this->once())
             ->method('getRedirect')
-            ->willReturn($this->redirect);
+            ->willReturn($this->resultRedirect);
 
-        $this->assertSame($this->redirect, $this->controller->execute());
+        $this->assertSame($this->resultRedirect, $this->controller->execute());
+    }
+
+    public function testExecuteSuccessCustomRedirect()
+    {
+        $username = 'user1';
+        $password = 'pass1';
+
+        $this->session->expects($this->once())
+            ->method('isLoggedIn')
+            ->willReturn(false);
+
+        $this->formkeyValidator->expects($this->once())
+            ->method('validate')
+            ->with($this->request)
+            ->willReturn(true);
+
+        $this->request->expects($this->once())
+            ->method('isPost')
+            ->willReturn(true);
+        $this->request->expects($this->once())
+            ->method('getPost')
+            ->with('login')
+            ->willReturn([
+                'username' => $username,
+                'password' => $password,
+            ]);
+
+        $customerMock = $this->getMockBuilder(\Magento\Customer\Api\Data\CustomerInterface::class)
+            ->getMockForAbstractClass();
+
+        $this->scopeConfig->expects($this->once())
+            ->method('getValue')
+            ->with('customer/startup/redirect_dashboard')
+            ->willReturn(0);
+
+        $cookieUrl = 'someUrl1';
+        $returnUrl = 'someUrl2';
+        $this->accountRedirect->expects($this->once())
+            ->method('getRedirectCookie')
+            ->willReturn($cookieUrl);
+        $this->accountRedirect->expects($this->once())
+            ->method('clearRedirectCookie');
+
+        $this->redirect->expects($this->once())
+            ->method('success')
+            ->with($cookieUrl)
+            ->willReturn($returnUrl);
+
+        $this->resultRedirect->expects($this->once())
+            ->method('setUrl')
+            ->with($returnUrl);
+
+        $this->accountManagement->expects($this->once())
+            ->method('authenticate')
+            ->with($username, $password)
+            ->willReturn($customerMock);
+
+        $this->session->expects($this->once())
+            ->method('setCustomerDataAsLoggedIn')
+            ->with($customerMock)
+            ->willReturnSelf();
+        $this->session->expects($this->once())
+            ->method('regenerateId')
+            ->willReturnSelf();
+
+        $this->accountRedirect->expects($this->never())
+            ->method('getRedirect')
+            ->willReturn($this->resultRedirect);
+
+        $this->assertSame($this->resultRedirect, $this->controller->execute());
     }
 
     public function testExecuteSuccess()
@@ -247,6 +327,11 @@ class LoginPostTest extends \PHPUnit_Framework_TestCase
         $customerMock = $this->getMockBuilder('Magento\Customer\Api\Data\CustomerInterface')
             ->getMockForAbstractClass();
 
+        $this->scopeConfig->expects($this->once())
+            ->method('getValue')
+            ->with('customer/startup/redirect_dashboard')
+            ->willReturn(1);
+
         $this->accountManagement->expects($this->once())
             ->method('authenticate')
             ->with($username, $password)
@@ -262,9 +347,9 @@ class LoginPostTest extends \PHPUnit_Framework_TestCase
 
         $this->accountRedirect->expects($this->once())
             ->method('getRedirect')
-            ->willReturn($this->redirect);
+            ->willReturn($this->resultRedirect);
 
-        $this->assertSame($this->redirect, $this->controller->execute());
+        $this->assertSame($this->resultRedirect, $this->controller->execute());
     }
 
     /**
@@ -309,9 +394,9 @@ class LoginPostTest extends \PHPUnit_Framework_TestCase
 
         $this->accountRedirect->expects($this->once())
             ->method('getRedirect')
-            ->willReturn($this->redirect);
+            ->willReturn($this->resultRedirect);
 
-        $this->assertSame($this->redirect, $this->controller->execute());
+        $this->assertSame($this->resultRedirect, $this->controller->execute());
     }
 
     /**
@@ -361,7 +446,7 @@ class LoginPostTest extends \PHPUnit_Framework_TestCase
             ])
             ->getMock();
 
-        $this->redirect = $this->getMockBuilder('Magento\Framework\Controller\Result\Redirect')
+        $this->resultRedirect = $this->getMockBuilder(\Magento\Framework\Controller\Result\Redirect::class)
             ->disableOriginalConstructor()
             ->getMock();
 
@@ -369,21 +454,27 @@ class LoginPostTest extends \PHPUnit_Framework_TestCase
             ->disableOriginalConstructor()
             ->getMock();
 
-        $redirectFactory = $this->getMockBuilder('Magento\Framework\Controller\Result\RedirectFactory')
+        $this->redirectFactory = $this->getMockBuilder(\Magento\Framework\Controller\Result\RedirectFactory::class)
             ->disableOriginalConstructor()
             ->getMock();
 
-        $redirectFactory->expects($this->any())
-            ->method('create')
+        $this->redirect = $this->getMockBuilder(\Magento\Framework\App\Response\RedirectInterface::class)
+            ->getMock();
+        $this->context->expects($this->atLeastOnce())
+            ->method('getRedirect')
             ->willReturn($this->redirect);
 
+        $this->redirectFactory->expects($this->any())
+            ->method('create')
+            ->willReturn($this->resultRedirect);
+
         $this->context->expects($this->any())
             ->method('getRequest')
             ->willReturn($this->request);
 
         $this->context->expects($this->any())
             ->method('getResultRedirectFactory')
-            ->willReturn($redirectFactory);
+            ->willReturn($this->redirectFactory);
 
         $this->context->expects($this->any())
             ->method('getMessageManager')
diff --git a/app/code/Magento/Customer/Test/Unit/Controller/Ajax/LoginTest.php b/app/code/Magento/Customer/Test/Unit/Controller/Ajax/LoginTest.php
index 77260f56c584d03aa54b3589d2979932e8c1484c..7592557048f3174366529972352bcbe56d445392 100644
--- a/app/code/Magento/Customer/Test/Unit/Controller/Ajax/LoginTest.php
+++ b/app/code/Magento/Customer/Test/Unit/Controller/Ajax/LoginTest.php
@@ -13,6 +13,9 @@ namespace Magento\Customer\Test\Unit\Controller\Ajax;
 
 use Magento\Framework\Exception\InvalidEmailOrPasswordException;
 
+/**
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ */
 class LoginTest extends \PHPUnit_Framework_TestCase
 {
     /**
@@ -65,6 +68,11 @@ class LoginTest extends \PHPUnit_Framework_TestCase
      */
     protected $resultRaw;
 
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $redirectMock;
+
     protected function setUp()
     {
         $this->request = $this->getMockBuilder('Magento\Framework\App\Request\Http')
@@ -133,13 +141,18 @@ class LoginTest extends \PHPUnit_Framework_TestCase
             ->method('create')
             ->willReturn($this->resultRaw);
 
+        $contextMock = $this->getMock(\Magento\Framework\App\Action\Context::class, [], [], '', false);
+        $this->redirectMock = $this->getMock(\Magento\Framework\App\Response\RedirectInterface::class);
+        $contextMock->expects($this->atLeastOnce())->method('getRedirect')->willReturn($this->redirectMock);
+        $contextMock->expects($this->atLeastOnce())->method('getRequest')->willReturn($this->request);
+
         $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
         $this->object = $objectManager->getObject(
             'Magento\Customer\Controller\Ajax\Login',
             [
+                'context' => $contextMock,
                 'customerSession' => $this->customerSession,
                 'helper' => $this->jsonHelperMock,
-                'request' => $this->request,
                 'response' => $this->response,
                 'resultRawFactory' => $resultRawFactory,
                 'resultJsonFactory' => $this->resultJsonFactory,
@@ -192,11 +205,23 @@ class LoginTest extends \PHPUnit_Framework_TestCase
 
         $this->customerSession->expects($this->once())->method('regenerateId');
 
+        $redirectMock = $this->getMock(\Magento\Customer\Model\Account\Redirect::class, [], [], '', false);
+        $this->object->setAccountRedirect($redirectMock);
+        $redirectMock->expects($this->once())->method('getRedirectCookie')->willReturn('some_url1');
+
+        $scopeConfigMock = $this->getMock(\Magento\Framework\App\Config\ScopeConfigInterface::class);
+        $this->object->setScopeConfig($scopeConfigMock);
+        $scopeConfigMock->expects($this->once())->method('getValue')
+            ->with('customer/startup/redirect_dashboard')
+            ->willReturn(0);
+
+        $this->redirectMock->expects($this->once())->method('success')->willReturn('some_url2');
         $this->resultRaw->expects($this->never())->method('setHttpResponseCode');
 
         $result = [
             'errors' => false,
-            'message' => __('Login successful.')
+            'message' => __('Login successful.'),
+            'redirectUrl' => 'some_url2',
         ];
 
         $this->resultJson
diff --git a/app/code/Magento/Customer/view/frontend/web/js/action/login.js b/app/code/Magento/Customer/view/frontend/web/js/action/login.js
index 2cbc02ba07456e7526a83240cd8fd58d85700dd6..67bc734bcb7d6b050ba42f974579aab6e73b43c7 100644
--- a/app/code/Magento/Customer/view/frontend/web/js/action/login.js
+++ b/app/code/Magento/Customer/view/frontend/web/js/action/login.js
@@ -32,6 +32,8 @@ define(
                         customerData.invalidate(['customer']);
                         if (redirectUrl) {
                             window.location.href = redirectUrl;
+                        } else if (response.redirectUrl) {
+                            window.location.href = response.redirectUrl;
                         } else {
                             location.reload();
                         }
diff --git a/app/code/Magento/Developer/Console/Command/XmlCatalogGenerateCommand.php b/app/code/Magento/Developer/Console/Command/XmlCatalogGenerateCommand.php
index ec5419771a6fda20396abf1a5d71a92c4cdbdd81..1b51d24993d9deb5fc1f10d6a9b5eb4c9589d087 100644
--- a/app/code/Magento/Developer/Console/Command/XmlCatalogGenerateCommand.php
+++ b/app/code/Magento/Developer/Console/Command/XmlCatalogGenerateCommand.php
@@ -160,6 +160,7 @@ class XmlCatalogGenerateCommand extends Command
      */
     private function getFormatters($format)
     {
+        $format = strtolower($format);
         if (!isset($this->formats[$format])) {
             return false;
         }
diff --git a/app/code/Magento/Downloadable/Block/Sales/Order/Email/Items/Downloadable.php b/app/code/Magento/Downloadable/Block/Sales/Order/Email/Items/Downloadable.php
index 5d2eaa4b8e82ee32e3ae961dbd46cf001e696d7d..32bbcc0f37519620ca52c3061754034596094d44 100644
--- a/app/code/Magento/Downloadable/Block/Sales/Order/Email/Items/Downloadable.php
+++ b/app/code/Magento/Downloadable/Block/Sales/Order/Email/Items/Downloadable.php
@@ -36,24 +36,27 @@ class Downloadable extends \Magento\Sales\Block\Order\Email\Items\DefaultItems
     protected $_itemsFactory;
 
     /**
-     * @var \Magento\Framework\UrlInterface
+     * @var \Magento\Framework\Url
      */
-    protected $urlGenerator;
+    protected $frontendUrlBuilder;
 
     /**
      * @param \Magento\Framework\View\Element\Template\Context $context
      * @param \Magento\Downloadable\Model\Link\PurchasedFactory $purchasedFactory
      * @param \Magento\Downloadable\Model\ResourceModel\Link\Purchased\Item\CollectionFactory $itemsFactory
+     * @param \Magento\Framework\Url $frontendUrlBuilder
      * @param array $data
      */
     public function __construct(
         \Magento\Framework\View\Element\Template\Context $context,
         \Magento\Downloadable\Model\Link\PurchasedFactory $purchasedFactory,
         \Magento\Downloadable\Model\ResourceModel\Link\Purchased\Item\CollectionFactory $itemsFactory,
+        \Magento\Framework\Url $frontendUrlBuilder,
         array $data = []
     ) {
         $this->_purchasedFactory = $purchasedFactory;
         $this->_itemsFactory = $itemsFactory;
+        $this->frontendUrlBuilder = $frontendUrlBuilder;
         parent::__construct($context, $data);
     }
 
@@ -94,7 +97,7 @@ class Downloadable extends \Magento\Sales\Block\Order\Email\Items\DefaultItems
      */
     public function getPurchasedLinkUrl($item)
     {
-        return $this->_urlBuilder->getUrl(
+        return $this->frontendUrlBuilder->getUrl(
             'downloadable/download/link',
             [
                 'id' => $item->getLinkHash(),
diff --git a/app/code/Magento/Downloadable/Controller/Adminhtml/Downloadable/File/Upload.php b/app/code/Magento/Downloadable/Controller/Adminhtml/Downloadable/File/Upload.php
index 6e056ee9e45a4c76c5701cca37e7d56563dc878c..aef2471617fa4710dd8d00b4bc69a06646d0aade 100644
--- a/app/code/Magento/Downloadable/Controller/Adminhtml/Downloadable/File/Upload.php
+++ b/app/code/Magento/Downloadable/Controller/Adminhtml/Downloadable/File/Upload.php
@@ -90,11 +90,7 @@ class Upload extends \Magento\Downloadable\Controller\Adminhtml\Downloadable\Fil
                 throw new \Exception('File can not be moved from temporary folder to the destination folder.');
             }
 
-            /**
-             * Workaround for prototype 1.7 methods "isJSON", "evalJSON" on Windows OS
-             */
-            $result['tmp_name'] = str_replace('\\', '/', $result['tmp_name']);
-            $result['path'] = str_replace('\\', '/', $result['path']);
+            unset($result['tmp_name'], $result['path']);
 
             if (isset($result['file'])) {
                 $relativePath = rtrim($tmpPath, '/') . '/' . ltrim($result['file'], '/');
diff --git a/app/code/Magento/Downloadable/view/frontend/templates/customer/products/list.phtml b/app/code/Magento/Downloadable/view/frontend/templates/customer/products/list.phtml
index 9146b0a26a291528840897f43f7969b170dbc577..7d9d0df2b78569ff8af333f237676b074aed10b6 100644
--- a/app/code/Magento/Downloadable/view/frontend/templates/customer/products/list.phtml
+++ b/app/code/Magento/Downloadable/view/frontend/templates/customer/products/list.phtml
@@ -38,7 +38,9 @@
                     <td data-th="<?php echo $block->escapeHtml(__('Date')) ?>" class="col date"><?php /* @escapeNotVerified */ echo $block->formatDate($_item->getPurchased()->getCreatedAt()) ?></td>
                     <td data-th="<?php echo $block->escapeHtml(__('Title')) ?>" class="col title">
                         <strong class="product-name"><?php echo $block->escapeHtml($_item->getPurchased()->getProductName()) ?></strong>
+                        <?php if ($_item->getStatus() == \Magento\Downloadable\Model\Link\Purchased\Item::LINK_STATUS_AVAILABLE): ?>
                         <a href="<?php /* @escapeNotVerified */ echo $block->getDownloadUrl($_item) ?>" title="<?php echo $block->escapeHtml(__('Start Download')) ?>" class="action download" <?php echo $block->getIsOpenInNewWindow() ? 'onclick="this.target=\'_blank\'"' : ''; ?>><?php echo $block->escapeHtml($_item->getLinkTitle()) ?></a>
+                        <?php endif; ?>
                     </td>
                     <td data-th="<?php echo $block->escapeHtml(__('Status')) ?>" class="col status"><?php /* @escapeNotVerified */ echo __(ucfirst($_item->getStatus())) ?></td>
                     <td data-th="<?php echo $block->escapeHtml(__('Remaining Downloads')) ?>" class="col remaining"><?php /* @escapeNotVerified */ echo $block->getRemainingDownloads($_item) ?></td>
diff --git a/app/code/Magento/DownloadableImportExport/Helper/Uploader.php b/app/code/Magento/DownloadableImportExport/Helper/Uploader.php
index cd1009aa3270b57899f3ec9f46ca3aa5218fe6a7..02f03407245485014165fdb1b88351620e024464 100644
--- a/app/code/Magento/DownloadableImportExport/Helper/Uploader.php
+++ b/app/code/Magento/DownloadableImportExport/Helper/Uploader.php
@@ -93,7 +93,7 @@ class Uploader extends \Magento\Framework\App\Helper\AbstractHelper
         $destinationDir = "downloadable/files/" . $type;
         $destinationPath = $dirAddon . $DS . $this->mediaDirectory->getRelativePath($destinationDir);
 
-        $this->mediaDirectory->create($destinationDir);
+        $this->mediaDirectory->create($destinationPath);
         if (!$this->fileUploader->setDestDir($destinationPath)) {
             throw new \Magento\Framework\Exception\LocalizedException(
                 __('File directory \'%1\' is not writable.', $destinationPath)
diff --git a/app/code/Magento/DownloadableImportExport/Model/Import/Product/Type/Downloadable.php b/app/code/Magento/DownloadableImportExport/Model/Import/Product/Type/Downloadable.php
index 9a9eaada5da3790ea550024e3c761dce82a6553e..879fa23c65af051f66dea49f911cef01960c26e4 100644
--- a/app/code/Magento/DownloadableImportExport/Model/Import/Product/Type/Downloadable.php
+++ b/app/code/Magento/DownloadableImportExport/Model/Import/Product/Type/Downloadable.php
@@ -12,6 +12,8 @@ use \Magento\Store\Model\Store;
 
 /**
  * Class Downloadable
+ *
+ * @SuppressWarnings(PHPMD.TooManyFields)
  */
 class Downloadable extends \Magento\CatalogImportExport\Model\Import\Product\Type\AbstractType
 {
@@ -285,7 +287,7 @@ class Downloadable extends \Magento\CatalogImportExport\Model\Import\Product\Typ
                 if ($this->_type != $productData['type_id']) {
                     continue;
                 }
-                $this->parseOptions($rowData, $productData['entity_id']);
+                $this->parseOptions($rowData, $productData[$this->getProductEntityLinkField()]);
             }
             if (!empty($this->cachedOptions['sample']) || !empty($this->cachedOptions['link'])) {
                 $this->saveOptions();
@@ -303,6 +305,8 @@ class Downloadable extends \Magento\CatalogImportExport\Model\Import\Product\Typ
      * @param bool $isNewProduct Optional
      *
      * @return bool
+     *
+     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
      */
     public function isRowValid(array $rowData, $rowNum, $isNewProduct = true)
     {
diff --git a/app/code/Magento/Eav/Model/Entity/Attribute.php b/app/code/Magento/Eav/Model/Entity/Attribute.php
index 2c8cc458caa908df9398b9af163efa77e71e36a0..0d1a65d258d6898e59d1092d3ff7d174d36da41f 100644
--- a/app/code/Magento/Eav/Model/Entity/Attribute.php
+++ b/app/code/Magento/Eav/Model/Entity/Attribute.php
@@ -463,4 +463,28 @@ class Attribute extends \Magento\Eav\Model\Entity\Attribute\AbstractAttribute im
     {
         return [self::CACHE_TAG . '_' . $this->getId()];
     }
+
+    /**
+     * @inheritdoc
+     */
+    public function __sleep()
+    {
+        return array_diff(
+            parent::__sleep(),
+            ['_localeDate', '_localeResolver', 'reservedAttributeList', 'dateTimeFormatter']
+        );
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function __wakeup()
+    {
+        parent::__wakeup();
+        $objectManager = \Magento\Framework\App\ObjectManager::getInstance();
+        $this->_localeDate = $objectManager->get(\Magento\Framework\Stdlib\DateTime\TimezoneInterface::class);
+        $this->_localeResolver = $objectManager->get(\Magento\Catalog\Model\Product\ReservedAttributeList::class);
+        $this->reservedAttributeList = $objectManager->get(\Magento\Framework\Locale\ResolverInterface::class);
+        $this->dateTimeFormatter = $objectManager->get(DateTimeFormatterInterface::class);
+    }
 }
diff --git a/app/code/Magento/Eav/Model/Entity/Attribute/AbstractAttribute.php b/app/code/Magento/Eav/Model/Entity/Attribute/AbstractAttribute.php
index d09156a107ebb934b9165caf6a34ada6b32b39a2..81535a0af1d9f0e31ceb7af5d9862bb3b1f2bd2c 100644
--- a/app/code/Magento/Eav/Model/Entity/Attribute/AbstractAttribute.php
+++ b/app/code/Magento/Eav/Model/Entity/Attribute/AbstractAttribute.php
@@ -1237,4 +1237,45 @@ abstract class AbstractAttribute extends \Magento\Framework\Model\AbstractExtens
     {
         return $this->_setExtensionAttributes($extensionAttributes);
     }
+
+    /**
+     * @inheritdoc
+     */
+    public function __sleep()
+    {
+        return array_diff(
+            parent::__sleep(),
+            [
+                '_eavConfig',
+                '_eavTypeFactory',
+                '_storeManager',
+                '_resourceHelper',
+                '_universalFactory',
+                'optionDataFactory',
+                'dataObjectProcessor',
+                'dataObjectHelper',
+                '_entity',
+                '_backend',
+                '_source',
+                '_frontend',
+            ]
+        );
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function __wakeup()
+    {
+        parent::__wakeup();
+        $objectManager = \Magento\Framework\App\ObjectManager::getInstance();
+        $this->_eavConfig = $objectManager->get(\Magento\Eav\Model\Config::class);
+        $this->_eavTypeFactory = $objectManager->get(\Magento\Eav\Model\Entity\TypeFactory::class);
+        $this->_storeManager = $objectManager->get(\Magento\Store\Model\StoreManagerInterface::class);
+        $this->_resourceHelper = $objectManager->get(\Magento\Eav\Model\ResourceModel\Helper::class);
+        $this->_universalFactory = $objectManager->get(\Magento\Framework\Validator\UniversalFactory ::class);
+        $this->optionDataFactory = $objectManager->get(\Magento\Eav\Api\Data\AttributeOptionInterfaceFactory::class);
+        $this->dataObjectProcessor = $objectManager->get(\Magento\Framework\Reflection\DataObjectProcessor::class);
+        $this->dataObjectHelper = $objectManager->get(\Magento\Framework\Api\DataObjectHelper::class);
+    }
 }
diff --git a/app/code/Magento/Eav/Model/Entity/Attribute/OptionManagement.php b/app/code/Magento/Eav/Model/Entity/Attribute/OptionManagement.php
index de6a6600fe3af43cf0f5223ba840b36b619eb344..9c98d5299735e1cf33a16190b40de35d33aa4465 100644
--- a/app/code/Magento/Eav/Model/Entity/Attribute/OptionManagement.php
+++ b/app/code/Magento/Eav/Model/Entity/Attribute/OptionManagement.php
@@ -48,20 +48,24 @@ class OptionManagement implements \Magento\Eav\Api\AttributeOptionManagementInte
         if (!$attribute->usesSource()) {
             throw new StateException(__('Attribute %1 doesn\'t work with options', $attributeCode));
         }
-        $key = 'new_option';
+        $optionId = 'new_option';
+        if ($option->getValue()) {
+            $this->validateOption($attribute, $option->getValue());
+            $optionId = $option->getValue();
+        }
 
         $options = [];
-        $options['value'][$key][0] = $option->getLabel();
-        $options['order'][$key] = $option->getSortOrder();
+        $options['value'][$optionId][0] = $option->getLabel();
+        $options['order'][$optionId] = $option->getSortOrder();
 
         if (is_array($option->getStoreLabels())) {
             foreach ($option->getStoreLabels() as $label) {
-                $options['value'][$key][$label->getStoreId()] = $label->getLabel();
+                $options['value'][$optionId][$label->getStoreId()] = $label->getLabel();
             }
         }
 
         if ($option->getIsDefault()) {
-            $attribute->setDefault([$key]);
+            $attribute->setDefault([$optionId]);
         }
 
         $attribute->setOption($options);
@@ -87,12 +91,7 @@ class OptionManagement implements \Magento\Eav\Api\AttributeOptionManagementInte
         if (!$attribute->usesSource()) {
             throw new StateException(__('Attribute %1 doesn\'t have any option', $attributeCode));
         }
-
-        if (!$attribute->getSource()->getOptionText($optionId)) {
-            throw new NoSuchEntityException(
-                __('Attribute %1 does not contain option with Id %2', $attribute->getId(), $optionId)
-            );
-        }
+        $this->validateOption($attribute, $optionId);
 
         $removalMarker = [
             'option' => [
@@ -128,4 +127,19 @@ class OptionManagement implements \Magento\Eav\Api\AttributeOptionManagementInte
 
         return $options;
     }
+
+    /**
+     * @param \Magento\Eav\Api\Data\AttributeInterface $attribute
+     * @param int $optionId
+     * @throws NoSuchEntityException
+     * @return void
+     */
+    protected function validateOption($attribute, $optionId)
+    {
+        if (!$attribute->getSource()->getOptionText($optionId)) {
+            throw new NoSuchEntityException(
+                __('Attribute %1 does not contain option with Id %2', $attribute->getAttributeCode(), $optionId)
+            );
+        }
+    }
 }
diff --git a/app/code/Magento/Eav/Test/Unit/Model/Entity/Attribute/OptionManagementTest.php b/app/code/Magento/Eav/Test/Unit/Model/Entity/Attribute/OptionManagementTest.php
index 622f920afccfa25dbd1871bab1a8b7babf82b5c1..9b9b1ad3b0d4737bebbdb4c0589bd3eaa08a1ef0 100644
--- a/app/code/Magento/Eav/Test/Unit/Model/Entity/Attribute/OptionManagementTest.php
+++ b/app/code/Magento/Eav/Test/Unit/Model/Entity/Attribute/OptionManagementTest.php
@@ -261,7 +261,7 @@ class OptionManagementTest extends \PHPUnit_Framework_TestCase
 
     /**
      * @expectedException \Magento\Framework\Exception\NoSuchEntityException
-     * @expectedExceptionMessage Attribute 42 does not contain option with Id option
+     * @expectedExceptionMessage Attribute atrCode does not contain option with Id option
      */
     public function testDeleteWithWrongOption()
     {
@@ -275,14 +275,15 @@ class OptionManagementTest extends \PHPUnit_Framework_TestCase
             false,
             false,
             true,
-            ['usesSource', 'getSource', 'getId', 'getOptionText', 'addData']
+            ['usesSource', 'getSource', 'getAttributeCode']
         );
         $this->attributeRepositoryMock->expects($this->once())->method('get')->with($entityType, $attributeCode)
             ->willReturn($attributeMock);
+        $sourceMock = $this->getMockForAbstractClass('\Magento\Eav\Model\Entity\Attribute\Source\SourceInterface');
+        $sourceMock->expects($this->once())->method('getOptionText')->willReturn(false);
         $attributeMock->expects($this->once())->method('usesSource')->willReturn(true);
-        $attributeMock->expects($this->once())->method('getSource')->willReturnSelf();
-        $attributeMock->expects($this->once())->method('getOptionText')->willReturn(false);
-        $attributeMock->expects($this->once())->method('getId')->willReturn(42);
+        $attributeMock->expects($this->once())->method('getSource')->willReturn($sourceMock);
+        $attributeMock->expects($this->any())->method('getAttributeCode')->willReturn($attributeCode);
         $this->resourceModelMock->expects($this->never())->method('save');
         $this->model->delete($entityType, $attributeCode, $optionId);
     }
diff --git a/app/code/Magento/GroupedImportExport/Model/Import/Product/Type/Grouped.php b/app/code/Magento/GroupedImportExport/Model/Import/Product/Type/Grouped.php
index 3185df16bdb3bc95e55f46361d911a07e4f7bde7..273f0ee493781938995951a07b099a84575bb50f 100644
--- a/app/code/Magento/GroupedImportExport/Model/Import/Product/Type/Grouped.php
+++ b/app/code/Magento/GroupedImportExport/Model/Import/Product/Type/Grouped.php
@@ -29,6 +29,13 @@ class Grouped extends \Magento\CatalogImportExport\Model\Import\Product\Type\Abs
      */
     protected $links;
 
+    /**
+     * Product entity identifier field
+     *
+     * @var string
+     */
+    private $productEntityIdentifierField;
+
     /**
      * @param \Magento\Eav\Model\ResourceModel\Entity\Attribute\Set\CollectionFactory $attrSetColFac
      * @param \Magento\Catalog\Model\ResourceModel\Product\Attribute\CollectionFactory $prodAttrColFac
@@ -84,9 +91,9 @@ class Grouped extends \Magento\CatalogImportExport\Model\Import\Product\Type\Abs
                     $associatedSkuAndQty = explode(self::SKU_QTY_DELIMITER, $associatedSkuAndQty);
                     $associatedSku = isset($associatedSkuAndQty[0]) ? trim($associatedSkuAndQty[0]) : null;
                     if (isset($newSku[$associatedSku])) {
-                        $linkedProductId = $newSku[$associatedSku]['entity_id'];
+                        $linkedProductId = $newSku[$associatedSku][$this->getProductEntityIdentifierField()];
                     } elseif (isset($oldSku[$associatedSku])) {
-                        $linkedProductId = $oldSku[$associatedSku]['entity_id'];
+                        $linkedProductId = $oldSku[$associatedSku][$this->getProductEntityIdentifierField()];
                     } else {
                         continue;
                     }
@@ -98,7 +105,7 @@ class Grouped extends \Magento\CatalogImportExport\Model\Import\Product\Type\Abs
                         $rowData[$colAttrSet] = $productData['attr_set_code'];
                         $rowData[Product::COL_TYPE] = $productData['type_id'];
                     }
-                    $productId = $productData['entity_id'];
+                    $productId = $productData[$this->getProductEntityLinkField()];
 
                     $linksData['product_ids'][$productId] = true;
                     $linksData['relation'][] = ['parent_id' => $productId, 'child_id' => $linkedProductId];
@@ -121,4 +128,19 @@ class Grouped extends \Magento\CatalogImportExport\Model\Import\Product\Type\Abs
         }
         return $this;
     }
+
+    /**
+     * Get product entity identifier field
+     *
+     * @return string
+     */
+    private function getProductEntityIdentifierField()
+    {
+        if (!$this->productEntityIdentifierField) {
+            $this->productEntityIdentifierField = $this->getMetadataPool()
+                ->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class)
+                ->getIdentifierField();
+        }
+        return $this->productEntityIdentifierField;
+    }
 }
diff --git a/app/code/Magento/GroupedImportExport/Test/Unit/Model/Import/Product/Type/GroupedTest.php b/app/code/Magento/GroupedImportExport/Test/Unit/Model/Import/Product/Type/GroupedTest.php
index c5eef2cac8757c36198871492dc0ed6a32d90a72..cca8ffca238bfe664dd69fda5d000ceed61a0497 100644
--- a/app/code/Magento/GroupedImportExport/Test/Unit/Model/Import/Product/Type/GroupedTest.php
+++ b/app/code/Magento/GroupedImportExport/Test/Unit/Model/Import/Product/Type/GroupedTest.php
@@ -8,6 +8,9 @@ namespace Magento\GroupedImportExport\Test\Unit\Model\Import\Product\Type;
 
 use \Magento\GroupedImportExport;
 
+/**
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ */
 class GroupedTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractImportTestCase
 {
     /** @var GroupedImportExport\Model\Import\Product\Type\Grouped */
@@ -58,19 +61,22 @@ class GroupedTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractI
      */
     protected $entityModel;
 
+    /**
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+     */
     protected function setUp()
     {
         parent::setUp();
 
         $this->setCollectionFactory = $this->getMock(
-            'Magento\Eav\Model\ResourceModel\Entity\Attribute\Set\CollectionFactory',
+            \Magento\Eav\Model\ResourceModel\Entity\Attribute\Set\CollectionFactory::class,
             ['create'],
             [],
             '',
             false
         );
         $this->setCollection = $this->getMock(
-            'Magento\Eav\Model\ResourceModel\Entity\Attribute\Set\Collection',
+            \Magento\Eav\Model\ResourceModel\Entity\Attribute\Set\Collection::class,
             ['setEntityTypeFilter'],
             [],
             '',
@@ -81,7 +87,7 @@ class GroupedTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractI
         );
         $this->setCollection->expects($this->any())->method('setEntityTypeFilter')->will($this->returnValue([]));
         $this->attrCollectionFactory = $this->getMock(
-            'Magento\Catalog\Model\ResourceModel\Product\Attribute\CollectionFactory',
+            \Magento\Catalog\Model\ResourceModel\Product\Attribute\CollectionFactory::class,
             ['create', 'addFieldToFilter'],
             [],
             '',
@@ -90,7 +96,7 @@ class GroupedTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractI
         $this->attrCollectionFactory->expects($this->any())->method('create')->will($this->returnSelf());
         $this->attrCollectionFactory->expects($this->any())->method('addFieldToFilter')->willReturn([]);
         $this->entityModel = $this->getMock(
-            'Magento\CatalogImportExport\Model\Import\Product',
+            \Magento\CatalogImportExport\Model\Import\Product::class,
             ['getErrorAggregator', 'getNewSku', 'getOldSku', 'getNextBunch', 'isRowAllowedToImport', 'getRowScope'],
             [],
             '',
@@ -102,7 +108,7 @@ class GroupedTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractI
             1 => 'grouped'
         ];
         $this->links = $this->getMock(
-            'Magento\GroupedImportExport\Model\Import\Product\Type\Grouped\Links',
+            \Magento\GroupedImportExport\Model\Import\Product\Type\Grouped\Links::class,
             [],
             [],
             '',
@@ -113,7 +119,7 @@ class GroupedTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractI
             'attribute_id' => 'attributeSetName',
         ]];
         $this->connection = $this->getMock(
-            'Magento\Framework\DB\Adapter\Pdo\Mysql',
+            \Magento\Framework\DB\Adapter\Pdo\Mysql::class,
             ['select', 'fetchAll', 'fetchPairs', 'joinLeft', 'insertOnDuplicate', 'delete', 'quoteInto'],
             [],
             '',
@@ -130,7 +136,7 @@ class GroupedTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractI
         $this->select->expects($this->any())->method('where')->will($this->returnSelf());
         $this->select->expects($this->any())->method('joinLeft')->will($this->returnSelf());
         $this->connection->expects($this->any())->method('select')->will($this->returnValue($this->select));
-        $connectionMock = $this->getMock('Magento\Framework\DB\Adapter\Pdo\Mysql', [], [], '', false);
+        $connectionMock = $this->getMock(\Magento\Framework\DB\Adapter\Pdo\Mysql::class, [], [], '', false);
         $connectionMock->expects($this->any())->method('quoteInto')->will($this->returnValue('query'));
         $this->select->expects($this->any())->method('getConnection')->willReturn($connectionMock);
         $this->connection->expects($this->any())->method('insertOnDuplicate')->willReturnSelf();
@@ -138,7 +144,7 @@ class GroupedTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractI
         $this->connection->expects($this->any())->method('quoteInto')->willReturn('');
         $this->connection->expects($this->any())->method('fetchAll')->will($this->returnValue($entityAttributes));
         $this->resource = $this->getMock(
-            '\Magento\Framework\App\ResourceConnection',
+            \Magento\Framework\App\ResourceConnection::class,
             ['getConnection', 'getTableName'],
             [],
             '',
@@ -147,7 +153,7 @@ class GroupedTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractI
         $this->resource->expects($this->any())->method('getConnection')->will($this->returnValue($this->connection));
         $this->resource->expects($this->any())->method('getTableName')->will($this->returnValue('tableName'));
         $this->grouped = $this->objectManagerHelper->getObject(
-            'Magento\GroupedImportExport\Model\Import\Product\Type\Grouped',
+            \Magento\GroupedImportExport\Model\Import\Product\Type\Grouped::class,
             [
                 'attrSetColFac' => $this->setCollectionFactory,
                 'prodAttrColFac' => $this->attrCollectionFactory,
@@ -156,6 +162,22 @@ class GroupedTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractI
                 'links' => $this->links
             ]
         );
+        $metadataPoolMock = $this->getMock(\Magento\Framework\Model\Entity\MetadataPool::class, [], [], '', false);
+        $entityMetadataMock = $this->getMock(\Magento\Framework\Model\Entity\EntityMetadata::class, [], [], '', false);
+        $metadataPoolMock->expects($this->any())
+            ->method('getMetadata')
+            ->with(\Magento\Catalog\Api\Data\ProductInterface::class)
+            ->willReturn($entityMetadataMock);
+        $entityMetadataMock->expects($this->any())
+            ->method('getLinkField')
+            ->willReturn('entity_id');
+        $entityMetadataMock->expects($this->any())
+            ->method('getIdentifierField')
+            ->willReturn('entity_id');
+        $reflection = new \ReflectionClass(\Magento\GroupedImportExport\Model\Import\Product\Type\Grouped::class);
+        $reflectionProperty = $reflection->getProperty('metadataPool');
+        $reflectionProperty->setAccessible(true);
+        $reflectionProperty->setValue($this->grouped, $metadataPoolMock);
     }
 
     /**
diff --git a/app/code/Magento/GroupedProduct/Model/ResourceModel/Indexer/Stock/Grouped.php b/app/code/Magento/GroupedProduct/Model/ResourceModel/Indexer/Stock/Grouped.php
index f8db07e887ca8698b47a8b33dd904cc417d7fa0d..2091c254b98c273b3add428d14514ff03c432c52 100644
--- a/app/code/Magento/GroupedProduct/Model/ResourceModel/Indexer/Stock/Grouped.php
+++ b/app/code/Magento/GroupedProduct/Model/ResourceModel/Indexer/Stock/Grouped.php
@@ -76,19 +76,7 @@ class Grouped extends \Magento\CatalogInventory\Model\ResourceModel\Indexer\Stoc
         );
         $productStatusCond = $connection->quoteInto($productStatusExpr . '=?', ProductStatus::STATUS_ENABLED);
 
-        if ($this->_isManageStock()) {
-            $statusExpression = $connection->getCheckSql(
-                'cisi.use_config_manage_stock = 0 AND cisi.manage_stock = 0',
-                1,
-                'cisi.is_in_stock'
-            );
-        } else {
-            $statusExpression = $connection->getCheckSql(
-                'cisi.use_config_manage_stock = 0 AND cisi.manage_stock = 1',
-                'cisi.is_in_stock',
-                1
-            );
-        }
+        $statusExpression = $this->getStatusExpression($connection);
 
         $optExpr = $connection->getCheckSql("{$productStatusCond} AND le.required_options = 0", 'i.stock_status', 0);
         $stockStatusExpr = $connection->getLeastSql(["MAX({$optExpr})", "MIN({$statusExpression})"]);
diff --git a/app/code/Magento/ImportExport/Model/Import/Entity/AbstractEntity.php b/app/code/Magento/ImportExport/Model/Import/Entity/AbstractEntity.php
index b44f390d6669fd67eebac065d4930bcd7a9fd1da..54f112b4e3d428c3ee7a64bd12f70c3e7143ee44 100644
--- a/app/code/Magento/ImportExport/Model/Import/Entity/AbstractEntity.php
+++ b/app/code/Magento/ImportExport/Model/Import/Entity/AbstractEntity.php
@@ -239,6 +239,13 @@ abstract class AbstractEntity
      */
     protected $errorAggregator;
 
+    /**
+     * Product metadata pool
+     *
+     * @var \Magento\Framework\Model\Entity\MetadataPool
+     */
+    protected $metadataPool;
+
     /**
      * @param \Magento\Framework\Json\Helper\Data $jsonHelper
      * @param \Magento\ImportExport\Helper\Data $importExportData
@@ -829,4 +836,18 @@ abstract class AbstractEntity
     {
         return $this->validColumnNames;
     }
+
+    /**
+     * Get product metadata pool
+     *
+     * @return \Magento\Framework\Model\Entity\MetadataPool
+     */
+    protected function getMetadataPool()
+    {
+        if (!$this->metadataPool) {
+            $this->metadataPool = \Magento\Framework\App\ObjectManager::getInstance()
+                ->get(\Magento\Framework\Model\Entity\MetadataPool::class);
+        }
+        return $this->metadataPool;
+    }
 }
diff --git a/app/code/Magento/Indexer/Console/Command/IndexerReindexCommand.php b/app/code/Magento/Indexer/Console/Command/IndexerReindexCommand.php
index c890c216fe84edb3f40e6c24e55877f1ebca9c54..a538c775f7423d66acd67f9f6abc42e7ee37f5e9 100644
--- a/app/code/Magento/Indexer/Console/Command/IndexerReindexCommand.php
+++ b/app/code/Magento/Indexer/Console/Command/IndexerReindexCommand.php
@@ -6,8 +6,10 @@
 namespace Magento\Indexer\Console\Command;
 
 use Magento\Framework\Exception\LocalizedException;
+use Magento\Framework\Indexer\StateInterface;
 use Symfony\Component\Console\Input\InputInterface;
 use Symfony\Component\Console\Output\OutputInterface;
+use Magento\Framework\Indexer\ConfigInterface;
 
 /**
  * Command for reindexing indexers.
@@ -32,10 +34,22 @@ class IndexerReindexCommand extends AbstractIndexerManageCommand
     protected function execute(InputInterface $input, OutputInterface $output)
     {
         $indexers = $this->getIndexers($input);
+        $config = $this->getConfig();
+        $sharedIndexesComplete = [];
         foreach ($indexers as $indexer) {
             try {
                 $startTime = microtime(true);
-                $indexer->reindexAll();
+                $indexerConfig = $config->getIndexer($indexer->getId());
+
+                // Skip indexers having shared index that was already complete
+                if (!in_array($indexerConfig['shared_index'], $sharedIndexesComplete)) {
+                    $indexer->reindexAll();
+                } else {
+                    $indexer->getState()->setStatus(StateInterface::STATUS_VALID)->save();
+                }
+                if ($indexerConfig['shared_index']) {
+                    $sharedIndexesComplete[] = $indexerConfig['shared_index'];
+                }
                 $resultTime = microtime(true) - $startTime;
                 $output->writeln(
                     $indexer->getTitle() . ' index has been rebuilt successfully in ' . gmdate('H:i:s', $resultTime)
@@ -48,4 +62,15 @@ class IndexerReindexCommand extends AbstractIndexerManageCommand
             }
         }
     }
+
+    /**
+     * Get config
+     *
+     * @return \Magento\Framework\Indexer\ConfigInterface
+     * @deprecated
+     */
+    private function getConfig()
+    {
+        return $this->getObjectManager()->get(ConfigInterface::class);
+    }
 }
diff --git a/app/code/Magento/Indexer/Model/Processor.php b/app/code/Magento/Indexer/Model/Processor.php
index dec0175102273febdb8bd985009e23198020643a..96201db1ac41561e16ca160fa4f17c68ffac83b1 100644
--- a/app/code/Magento/Indexer/Model/Processor.php
+++ b/app/code/Magento/Indexer/Model/Processor.php
@@ -7,6 +7,7 @@ namespace Magento\Indexer\Model;
 
 use Magento\Framework\Indexer\ConfigInterface;
 use Magento\Framework\Indexer\IndexerInterface;
+use Magento\Framework\Indexer\StateInterface;
 
 class Processor
 {
@@ -55,11 +56,25 @@ class Processor
      */
     public function reindexAllInvalid()
     {
+        $sharedIndexesComplete = [];
         foreach (array_keys($this->config->getIndexers()) as $indexerId) {
+            /** @var Indexer $indexer */
             $indexer = $this->indexerFactory->create();
             $indexer->load($indexerId);
+            $indexerConfig = $this->config->getIndexer($indexerId);
             if ($indexer->isInvalid()) {
-                $indexer->reindexAll();
+                // Skip indexers having shared index that was already complete
+                if (!in_array($indexerConfig['shared_index'], $sharedIndexesComplete)) {
+                    $indexer->reindexAll();
+                } else {
+                    /** @var \Magento\Indexer\Model\Indexer\State $state */
+                    $state = $indexer->getState();
+                    $state->setStatus(StateInterface::STATUS_VALID);
+                    $state->save();
+                }
+                if ($indexerConfig['shared_index']) {
+                    $sharedIndexesComplete[] = $indexerConfig['shared_index'];
+                }
             }
         }
     }
diff --git a/app/code/Magento/Indexer/Test/Unit/Console/Command/AbstractIndexerCommandCommonSetup.php b/app/code/Magento/Indexer/Test/Unit/Console/Command/AbstractIndexerCommandCommonSetup.php
index 0179895599cd579c574806a4eb319c222b27c0bf..826e956e9fa480185938be9c7a9782f8bd1e2994 100644
--- a/app/code/Magento/Indexer/Test/Unit/Console/Command/AbstractIndexerCommandCommonSetup.php
+++ b/app/code/Magento/Indexer/Test/Unit/Console/Command/AbstractIndexerCommandCommonSetup.php
@@ -13,7 +13,7 @@ class AbstractIndexerCommandCommonSetup extends \PHPUnit_Framework_TestCase
     /**
      * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Framework\App\ObjectManager\ConfigLoader
      */
-    private $configLoaderMock;
+    protected $configLoaderMock;
 
     /**
      * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Indexer\Model\IndexerFactory
@@ -51,10 +51,7 @@ class AbstractIndexerCommandCommonSetup extends \PHPUnit_Framework_TestCase
 
         $this->objectManager->expects($this->any())
             ->method('get')
-            ->will($this->returnValueMap([
-                ['Magento\Framework\App\State', $this->stateMock],
-                ['Magento\Framework\ObjectManager\ConfigLoaderInterface', $this->configLoaderMock]
-            ]));
+            ->will($this->returnValueMap($this->getObjectManagerReturnValueMap()));
 
         $this->collectionFactory = $this->getMockBuilder('Magento\Indexer\Model\Indexer\CollectionFactory')
             ->disableOriginalConstructor()
@@ -74,6 +71,19 @@ class AbstractIndexerCommandCommonSetup extends \PHPUnit_Framework_TestCase
             ]));
     }
 
+    /**
+     * Return value map for object manager
+     *
+     * @return array
+     */
+    protected function getObjectManagerReturnValueMap()
+    {
+        return [
+            ['Magento\Framework\App\State', $this->stateMock],
+            ['Magento\Framework\ObjectManager\ConfigLoaderInterface', $this->configLoaderMock]
+        ];
+    }
+
     protected function configureAdminArea()
     {
         $config = ['test config'];
diff --git a/app/code/Magento/Indexer/Test/Unit/Console/Command/IndexerReindexCommandTest.php b/app/code/Magento/Indexer/Test/Unit/Console/Command/IndexerReindexCommandTest.php
index 0e400fdba3f539ef1d18294cc2e1612334fb4295..07c17a13340a69c0b50acca75f3628203a52164d 100644
--- a/app/code/Magento/Indexer/Test/Unit/Console/Command/IndexerReindexCommandTest.php
+++ b/app/code/Magento/Indexer/Test/Unit/Console/Command/IndexerReindexCommandTest.php
@@ -5,6 +5,8 @@
  */
 namespace Magento\Indexer\Test\Unit\Console\Command;
 
+use Magento\Framework\Exception\LocalizedException;
+use Magento\Framework\Phrase;
 use Magento\Indexer\Console\Command\IndexerReindexCommand;
 use Symfony\Component\Console\Tester\CommandTester;
 
@@ -17,6 +19,32 @@ class IndexerReindexCommandTest extends AbstractIndexerCommandCommonSetup
      */
     private $command;
 
+    /**
+     * @var \Magento\Framework\Indexer\ConfigInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $configMock;
+
+    /**
+     * Set up
+     */
+    public function setUp()
+    {
+        $this->configMock = $this->getMock(\Magento\Indexer\Model\Config::class, [], [], '', false);
+        parent::setUp();
+    }
+
+    /**
+     * Get return value map for object manager
+     *
+     * @return array
+     */
+    protected function getObjectManagerReturnValueMap()
+    {
+        $result = parent::getObjectManagerReturnValueMap();
+        $result[] = [\Magento\Framework\Indexer\ConfigInterface::class, $this->configMock];
+        return $result;
+    }
+
     public function testGetOptions()
     {
         $this->stateMock->expects($this->never())->method('setAreaCode');
@@ -28,6 +56,10 @@ class IndexerReindexCommandTest extends AbstractIndexerCommandCommonSetup
 
     public function testExecuteAll()
     {
+        $this->configMock->expects($this->once())->method('getIndexer')->will($this->returnValue([
+            'title' => 'Title_indexerOne',
+            'shared_index' => null
+        ]));
         $this->configureAdminArea();
         $collection = $this->getMock('Magento\Indexer\Model\Indexer\Collection', [], [], '', false);
         $indexerOne = $this->getMock('Magento\Indexer\Model\Indexer', [], [], '', false);
@@ -45,23 +77,49 @@ class IndexerReindexCommandTest extends AbstractIndexerCommandCommonSetup
 
     public function testExecuteWithIndex()
     {
+        $this->configMock->expects($this->any())
+            ->method('getIndexer')
+            ->will($this->returnValueMap(
+                [
+                    ['id_indexerOne', ['title' => 'Title_indexerOne', 'shared_index' => null]],
+                    ['id_indexerTwo', ['title' => 'Title_indexerTwo', 'shared_index' => 'with_indexer_3']],
+                    ['id_indexer3', ['title' => 'Title_indexer3', 'shared_index' => 'with_indexer_3']]
+                ]
+            ));
+
         $this->configureAdminArea();
         $indexerOne = $this->getMock('Magento\Indexer\Model\Indexer', [], [], '', false);
         $indexerOne->expects($this->once())->method('reindexAll');
         $indexerOne->expects($this->once())->method('getTitle')->willReturn('Title_indexerOne');
+        $indexerOne->expects($this->any())->method('getId')->willReturn('id_indexerOne');
         $indexerOne->expects($this->once())->method('load')->with('id_indexerOne')->willReturn($indexerOne);
 
         $indexerTwo = $this->getMock('Magento\Indexer\Model\Indexer', [], [], '', false);
         $indexerTwo->expects($this->once())->method('reindexAll');
         $indexerTwo->expects($this->once())->method('getTitle')->willReturn('Title_indexerTwo');
+        $indexerTwo->expects($this->any())->method('getId')->willReturn('id_indexerTwo');
         $indexerTwo->expects($this->once())->method('load')->with('id_indexerTwo')->willReturn($indexerTwo);
 
+        $indexer3 = $this->getMock('Magento\Indexer\Model\Indexer', [], [], '', false);
+        $indexer3->expects($this->never())->method('reindexAll');
+        $indexer3->expects($this->once())->method('getTitle')->willReturn('Title_indexer3');
+        $indexer3->expects($this->any())->method('getId')->willReturn('id_indexer3');
+        $indexer3->expects($this->once())->method('load')->with('id_indexer3')->willReturn($indexer3);
+
+        $stateMock = $this->getMock(\Magento\Indexer\Model\Indexer\State::class, [], [], '', false);
+        $stateMock->expects($this->once())->method('setStatus')->will($this->returnSelf());
+        $stateMock->expects($this->once())->method('save');
+
+        $indexer3->expects($this->once())->method('getState')->willReturn($stateMock);
+
         $this->collectionFactory->expects($this->never())->method('create');
         $this->indexerFactory->expects($this->at(0))->method('create')->willReturn($indexerOne);
         $this->indexerFactory->expects($this->at(1))->method('create')->willReturn($indexerTwo);
+        $this->indexerFactory->expects($this->at(2))->method('create')->willReturn($indexer3);
+
         $this->command = new IndexerReindexCommand($this->objectManagerFactory);
         $commandTester = new CommandTester($this->command);
-        $commandTester->execute(['index' => ['id_indexerOne', 'id_indexerTwo']]);
+        $commandTester->execute(['index' => ['id_indexerOne', 'id_indexerTwo', 'id_indexer3']]);
         $actualValue = $commandTester->getDisplay();
         $this->assertStringStartsWith('Title_indexerOne index has been rebuilt successfully in', $actualValue);
     }
@@ -70,7 +128,7 @@ class IndexerReindexCommandTest extends AbstractIndexerCommandCommonSetup
     {
         $this->configureAdminArea();
         $indexerOne = $this->getMock('Magento\Indexer\Model\Indexer', [], [], '', false);
-        $localizedException = new \Magento\Framework\Exception\LocalizedException(__('Some Exception Message'));
+        $localizedException = new LocalizedException(new Phrase('Some Exception Message'));
         $indexerOne->expects($this->once())->method('reindexAll')->will($this->throwException($localizedException));
         $this->collectionFactory->expects($this->never())->method('create');
         $this->indexerFactory->expects($this->once())->method('create')->willReturn($indexerOne);
diff --git a/app/code/Magento/OfflineShipping/Model/Carrier/Flatrate.php b/app/code/Magento/OfflineShipping/Model/Carrier/Flatrate.php
index dcd22963ff7ecf411a02cfcc5d83795143dbaead..5a222a8a506c1f8052790fc4e6e3bca9915d1935 100644
--- a/app/code/Magento/OfflineShipping/Model/Carrier/Flatrate.php
+++ b/app/code/Magento/OfflineShipping/Model/Carrier/Flatrate.php
@@ -5,14 +5,16 @@
  */
 namespace Magento\OfflineShipping\Model\Carrier;
 
+use Magento\OfflineShipping\Model\Carrier\Flatrate\ItemPriceCalculator;
 use Magento\Quote\Model\Quote\Address\RateRequest;
+use Magento\Shipping\Model\Carrier\AbstractCarrier;
+use Magento\Shipping\Model\Carrier\CarrierInterface;
 use Magento\Shipping\Model\Rate\Result;
 
 /**
  * Flat rate shipping model
  */
-class Flatrate extends \Magento\Shipping\Model\Carrier\AbstractCarrier implements
-    \Magento\Shipping\Model\Carrier\CarrierInterface
+class Flatrate extends AbstractCarrier implements CarrierInterface
 {
     /**
      * @var string
@@ -34,12 +36,18 @@ class Flatrate extends \Magento\Shipping\Model\Carrier\AbstractCarrier implement
      */
     protected $_rateMethodFactory;
 
+    /**
+     * @var ItemPriceCalculator
+     */
+    private $itemPriceCalculator;
+
     /**
      * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
      * @param \Magento\Quote\Model\Quote\Address\RateResult\ErrorFactory $rateErrorFactory
      * @param \Psr\Log\LoggerInterface $logger
      * @param \Magento\Shipping\Model\Rate\ResultFactory $rateResultFactory
      * @param \Magento\Quote\Model\Quote\Address\RateResult\MethodFactory $rateMethodFactory
+     * @param ItemPriceCalculator $itemPriceCalculator
      * @param array $data
      */
     public function __construct(
@@ -48,10 +56,12 @@ class Flatrate extends \Magento\Shipping\Model\Carrier\AbstractCarrier implement
         \Psr\Log\LoggerInterface $logger,
         \Magento\Shipping\Model\Rate\ResultFactory $rateResultFactory,
         \Magento\Quote\Model\Quote\Address\RateResult\MethodFactory $rateMethodFactory,
+        \Magento\OfflineShipping\Model\Carrier\Flatrate\ItemPriceCalculator $itemPriceCalculator,
         array $data = []
     ) {
         $this->_rateResultFactory = $rateResultFactory;
         $this->_rateMethodFactory = $rateMethodFactory;
+        $this->itemPriceCalculator = $itemPriceCalculator;
         parent::__construct($scopeConfig, $rateErrorFactory, $logger, $data);
     }
 
@@ -67,6 +77,28 @@ class Flatrate extends \Magento\Shipping\Model\Carrier\AbstractCarrier implement
             return false;
         }
 
+        $freeBoxes = $this->getFreeBoxesCount($request);
+        $this->setFreeBoxes($freeBoxes);
+
+        /** @var Result $result */
+        $result = $this->_rateResultFactory->create();
+
+        $shippingPrice = $this->getShippingPrice($request, $freeBoxes);
+
+        if ($shippingPrice !== false) {
+            $method = $this->createResultMethod($shippingPrice);
+            $result->append($method);
+        }
+
+        return $result;
+    }
+
+    /**
+     * @param RateRequest $request
+     * @return int
+     */
+    private function getFreeBoxesCount(RateRequest $request)
+    {
         $freeBoxes = 0;
         if ($request->getAllItems()) {
             foreach ($request->getAllItems() as $item) {
@@ -75,64 +107,84 @@ class Flatrate extends \Magento\Shipping\Model\Carrier\AbstractCarrier implement
                 }
 
                 if ($item->getHasChildren() && $item->isShipSeparately()) {
-                    foreach ($item->getChildren() as $child) {
-                        if ($child->getFreeShipping() && !$child->getProduct()->isVirtual()) {
-                            $freeBoxes += $item->getQty() * $child->getQty();
-                        }
-                    }
+                    $freeBoxes += $this->getFreeBoxesCountFromChildren($item);
                 } elseif ($item->getFreeShipping()) {
                     $freeBoxes += $item->getQty();
                 }
             }
         }
-        $this->setFreeBoxes($freeBoxes);
+        return $freeBoxes;
+    }
 
-        /** @var Result $result */
-        $result = $this->_rateResultFactory->create();
-        if ($this->getConfigData('type') == 'O') {
+    /**
+     * @return array
+     */
+    public function getAllowedMethods()
+    {
+        return ['flatrate' => $this->getConfigData('name')];
+    }
+
+    /**
+     * @param RateRequest $request
+     * @param int $freeBoxes
+     * @return bool|float
+     */
+    private function getShippingPrice(RateRequest $request, $freeBoxes)
+    {
+        $shippingPrice = false;
+
+        $configPrice = $this->getConfigData('price');
+        if ($this->getConfigData('type') === 'O') {
             // per order
-            $shippingPrice = $this->getConfigData('price');
-        } elseif ($this->getConfigData('type') == 'I') {
+            $shippingPrice = $this->itemPriceCalculator->getShippingPricePerOrder($request, $configPrice, $freeBoxes);
+        } elseif ($this->getConfigData('type') === 'I') {
             // per item
-            $shippingPrice = $request->getPackageQty() * $this->getConfigData(
-                'price'
-            ) - $this->getFreeBoxes() * $this->getConfigData(
-                'price'
-            );
-        } else {
-            $shippingPrice = false;
+            $shippingPrice = $this->itemPriceCalculator->getShippingPricePerItem($request, $configPrice, $freeBoxes);
         }
 
         $shippingPrice = $this->getFinalPriceWithHandlingFee($shippingPrice);
 
-        if ($shippingPrice !== false) {
-            /** @var \Magento\Quote\Model\Quote\Address\RateResult\Method $method */
-            $method = $this->_rateMethodFactory->create();
-
-            $method->setCarrier('flatrate');
-            $method->setCarrierTitle($this->getConfigData('title'));
-
-            $method->setMethod('flatrate');
-            $method->setMethodTitle($this->getConfigData('name'));
+        if ($shippingPrice !== false && (
+                $request->getFreeShipping() === true || $request->getPackageQty() == $freeBoxes
+            )
+        ) {
+            $shippingPrice = '0.00';
+        }
+        return $shippingPrice;
+    }
 
-            if ($request->getFreeShipping() === true || $request->getPackageQty() == $this->getFreeBoxes()) {
-                $shippingPrice = '0.00';
-            }
+    /**
+     * @param int|float $shippingPrice
+     * @return \Magento\Quote\Model\Quote\Address\RateResult\Method
+     */
+    private function createResultMethod($shippingPrice)
+    {
+        /** @var \Magento\Quote\Model\Quote\Address\RateResult\Method $method */
+        $method = $this->_rateMethodFactory->create();
 
-            $method->setPrice($shippingPrice);
-            $method->setCost($shippingPrice);
+        $method->setCarrier('flatrate');
+        $method->setCarrierTitle($this->getConfigData('title'));
 
-            $result->append($method);
-        }
+        $method->setMethod('flatrate');
+        $method->setMethodTitle($this->getConfigData('name'));
 
-        return $result;
+        $method->setPrice($shippingPrice);
+        $method->setCost($shippingPrice);
+        return $method;
     }
 
     /**
-     * @return array
+     * @param mixed $item
+     * @return mixed
      */
-    public function getAllowedMethods()
+    private function getFreeBoxesCountFromChildren($item)
     {
-        return ['flatrate' => $this->getConfigData('name')];
+        $freeBoxes = 0;
+        foreach ($item->getChildren() as $child) {
+            if ($child->getFreeShipping() && !$child->getProduct()->isVirtual()) {
+                $freeBoxes += $item->getQty() * $child->getQty();
+            }
+        }
+        return $freeBoxes;
     }
 }
diff --git a/app/code/Magento/OfflineShipping/Model/Carrier/Flatrate/ItemPriceCalculator.php b/app/code/Magento/OfflineShipping/Model/Carrier/Flatrate/ItemPriceCalculator.php
new file mode 100644
index 0000000000000000000000000000000000000000..51b63969817e097ebea8b3f524f8d8e09a168905
--- /dev/null
+++ b/app/code/Magento/OfflineShipping/Model/Carrier/Flatrate/ItemPriceCalculator.php
@@ -0,0 +1,41 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\OfflineShipping\Model\Carrier\Flatrate;
+
+use Magento\Quote\Model\Quote\Address\RateRequest;
+
+class ItemPriceCalculator
+{
+    /**
+     * @param RateRequest $request
+     * @param int $basePrice
+     * @param int $freeBoxes
+     * @return float
+     */
+    public function getShippingPricePerItem(
+        \Magento\Quote\Model\Quote\Address\RateRequest $request,
+        $basePrice,
+        $freeBoxes
+    ) {
+        return $request->getPackageQty() * $basePrice - $freeBoxes * $basePrice;
+    }
+
+    /**
+     * @param RateRequest $request
+     * @param int $basePrice
+     * @param int $freeBoxes
+     * @return float
+     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+     */
+    public function getShippingPricePerOrder(
+        \Magento\Quote\Model\Quote\Address\RateRequest $request,
+        $basePrice,
+        $freeBoxes
+    ) {
+        return $basePrice;
+    }
+}
diff --git a/app/code/Magento/OfflineShipping/Model/Config/Backend/Tablerate.php b/app/code/Magento/OfflineShipping/Model/Config/Backend/Tablerate.php
index 08d23d9245564215089f6a4fb98f0703b901a681..c65993dfe592f842d1b6b82853888516f7792dbd 100644
--- a/app/code/Magento/OfflineShipping/Model/Config/Backend/Tablerate.php
+++ b/app/code/Magento/OfflineShipping/Model/Config/Backend/Tablerate.php
@@ -25,8 +25,8 @@ class Tablerate extends \Magento\Framework\App\Config\Value
      * @param \Magento\Framework\App\Config\ScopeConfigInterface $config
      * @param \Magento\Framework\App\Cache\TypeListInterface $cacheTypeList
      * @param \Magento\OfflineShipping\Model\ResourceModel\Carrier\TablerateFactory $tablerateFactory
-     * @param \Magento\Framework\Model\ResourceModel\AbstractResource $resource
-     * @param \Magento\Framework\Data\Collection\AbstractDb $resourceCollection
+     * @param \Magento\Framework\Model\ResourceModel\AbstractResource|null $resource
+     * @param \Magento\Framework\Data\Collection\AbstractDb|null $resourceCollection
      * @param array $data
      */
     public function __construct(
diff --git a/app/code/Magento/OfflineShipping/Model/ResourceModel/Carrier/Tablerate.php b/app/code/Magento/OfflineShipping/Model/ResourceModel/Carrier/Tablerate.php
index df0228a338358448f9af9d8106af49ed87a5a6ad..82f053fdbe0a77f18ee40330102fe6c44f694426 100644
--- a/app/code/Magento/OfflineShipping/Model/ResourceModel/Carrier/Tablerate.php
+++ b/app/code/Magento/OfflineShipping/Model/ResourceModel/Carrier/Tablerate.php
@@ -13,6 +13,9 @@ namespace Magento\OfflineShipping\Model\ResourceModel\Carrier;
 
 use Magento\Framework\Filesystem;
 use Magento\Framework\Filesystem\DirectoryList;
+use Magento\OfflineShipping\Model\ResourceModel\Carrier\Tablerate\Import;
+use Magento\OfflineShipping\Model\ResourceModel\Carrier\Tablerate\RateQuery;
+use Magento\OfflineShipping\Model\ResourceModel\Carrier\Tablerate\RateQueryFactory;
 
 /**
  * @SuppressWarnings(PHPMD.TooManyFields)
@@ -87,50 +90,51 @@ class Tablerate extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb
     /**
      * @var \Magento\Framework\App\Config\ScopeConfigInterface
      */
-    protected $_coreConfig;
+    protected $coreConfig;
 
     /**
      * @var \Psr\Log\LoggerInterface
      */
-    protected $_logger;
+    protected $logger;
 
     /**
      * @var \Magento\Store\Model\StoreManagerInterface
      */
-    protected $_storeManager;
+    protected $storeManager;
 
     /**
-     * @var \Magento\OfflineShipping\Model\Carrier\Tablerate
+     * @var \Magento\OfflineShipping\Model\ResourceModel\Carrier\Tablerate
      */
-    protected $_carrierTablerate;
+    protected $carrierTablerate;
 
     /**
-     * @var \Magento\Directory\Model\ResourceModel\Country\CollectionFactory
+     * Filesystem instance
+     *
+     * @var \Magento\Framework\Filesystem
      */
-    protected $_countryCollectionFactory;
+    protected $filesystem;
 
     /**
-     * @var \Magento\Directory\Model\ResourceModel\Region\CollectionFactory
+     * @var Import
      */
-    protected $_regionCollectionFactory;
+    private $import;
 
     /**
-     * Filesystem instance
-     *
-     * @var \Magento\Framework\Filesystem
+     * @var RateQueryFactory
      */
-    protected $_filesystem;
+    private $rateQueryFactory;
 
     /**
+     * Tablerate constructor.
      * @param \Magento\Framework\Model\ResourceModel\Db\Context $context
      * @param \Psr\Log\LoggerInterface $logger
      * @param \Magento\Framework\App\Config\ScopeConfigInterface $coreConfig
      * @param \Magento\Store\Model\StoreManagerInterface $storeManager
      * @param \Magento\OfflineShipping\Model\Carrier\Tablerate $carrierTablerate
-     * @param \Magento\Directory\Model\ResourceModel\Country\CollectionFactory $countryCollectionFactory
-     * @param \Magento\Directory\Model\ResourceModel\Region\CollectionFactory $regionCollectionFactory
-     * @param \Magento\Framework\Filesystem $filesystem
-     * @param string $connectionName
+     * @param Filesystem $filesystem
+     * @param RateQueryFactory $rateQueryFactory
+     * @param Import $import
+     * @param null $connectionName
      */
     public function __construct(
         \Magento\Framework\Model\ResourceModel\Db\Context $context,
@@ -138,19 +142,19 @@ class Tablerate extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb
         \Magento\Framework\App\Config\ScopeConfigInterface $coreConfig,
         \Magento\Store\Model\StoreManagerInterface $storeManager,
         \Magento\OfflineShipping\Model\Carrier\Tablerate $carrierTablerate,
-        \Magento\Directory\Model\ResourceModel\Country\CollectionFactory $countryCollectionFactory,
-        \Magento\Directory\Model\ResourceModel\Region\CollectionFactory $regionCollectionFactory,
         \Magento\Framework\Filesystem $filesystem,
+        Import $import,
+        RateQueryFactory $rateQueryFactory,
         $connectionName = null
     ) {
         parent::__construct($context, $connectionName);
-        $this->_coreConfig = $coreConfig;
-        $this->_logger = $logger;
-        $this->_storeManager = $storeManager;
-        $this->_carrierTablerate = $carrierTablerate;
-        $this->_countryCollectionFactory = $countryCollectionFactory;
-        $this->_regionCollectionFactory = $regionCollectionFactory;
-        $this->_filesystem = $filesystem;
+        $this->coreConfig = $coreConfig;
+        $this->logger = $logger;
+        $this->storeManager = $storeManager;
+        $this->carrierTablerate = $carrierTablerate;
+        $this->filesystem = $filesystem;
+        $this->import = $import;
+        $this->rateQueryFactory = $rateQueryFactory;
     }
 
     /**
@@ -172,73 +176,66 @@ class Tablerate extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb
     public function getRate(\Magento\Quote\Model\Quote\Address\RateRequest $request)
     {
         $connection = $this->getConnection();
-        $bind = [
-            ':website_id' => (int)$request->getWebsiteId(),
-            ':country_id' => $request->getDestCountryId(),
-            ':region_id' => (int)$request->getDestRegionId(),
-            ':postcode' => $request->getDestPostcode(),
-        ];
-        $select = $connection->select()->from(
-            $this->getMainTable()
-        )->where(
-            'website_id = :website_id'
-        )->order(
-            ['dest_country_id DESC', 'dest_region_id DESC', 'dest_zip DESC']
-        )->limit(
-            1
-        );
-
-        // Render destination condition
-        $orWhere = '(' . implode(
-            ') OR (',
-            [
-                "dest_country_id = :country_id AND dest_region_id = :region_id AND dest_zip = :postcode",
-                "dest_country_id = :country_id AND dest_region_id = :region_id AND dest_zip = ''",
-
-                // Handle asterix in dest_zip field
-                "dest_country_id = :country_id AND dest_region_id = :region_id AND dest_zip = '*'",
-                "dest_country_id = :country_id AND dest_region_id = 0 AND dest_zip = '*'",
-                "dest_country_id = '0' AND dest_region_id = :region_id AND dest_zip = '*'",
-                "dest_country_id = '0' AND dest_region_id = 0 AND dest_zip = '*'",
-                "dest_country_id = :country_id AND dest_region_id = 0 AND dest_zip = ''",
-                "dest_country_id = :country_id AND dest_region_id = 0 AND dest_zip = :postcode",
-                "dest_country_id = :country_id AND dest_region_id = 0 AND dest_zip = '*'"
-            ]
-        ) . ')';
-        $select->where($orWhere);
-
-        // Render condition by condition name
-        if (is_array($request->getConditionName())) {
-            $orWhere = [];
-            $i = 0;
-            foreach ($request->getConditionName() as $conditionName) {
-                $bindNameKey = sprintf(':condition_name_%d', $i);
-                $bindValueKey = sprintf(':condition_value_%d', $i);
-                $orWhere[] = "(condition_name = {$bindNameKey} AND condition_value <= {$bindValueKey})";
-                $bind[$bindNameKey] = $conditionName;
-                $bind[$bindValueKey] = $request->getData($conditionName);
-                $i++;
-            }
 
-            if ($orWhere) {
-                $select->where(implode(' OR ', $orWhere));
-            }
-        } else {
-            $bind[':condition_name'] = $request->getConditionName();
-            $bind[':condition_value'] = $request->getData($request->getConditionName());
+        $select = $connection->select()->from($this->getMainTable());
+        /** @var RateQuery $rateQuery */
+        $rateQuery = $this->rateQueryFactory->create(['request' => $request]);
 
-            $select->where('condition_name = :condition_name');
-            $select->where('condition_value <= :condition_value');
-        }
+        $rateQuery->prepareSelect($select);
+        $bindings = $rateQuery->getBindings();
 
-        $result = $connection->fetchRow($select, $bind);
+        $result = $connection->fetchRow($select, $bindings);
         // Normalize destination zip code
         if ($result && $result['dest_zip'] == '*') {
             $result['dest_zip'] = '';
         }
+
         return $result;
     }
 
+    /**
+     * @param array $condition
+     * @return $this
+     * @throws \Magento\Framework\Exception\LocalizedException
+     */
+    private function deleteByCondition(array $condition)
+    {
+        $connection = $this->getConnection();
+        $connection->beginTransaction();
+        $connection->delete($this->getMainTable(), $condition);
+        $connection->commit();
+        return $this;
+    }
+
+    /**
+     * @param array $fields
+     * @param array $values
+     * @throws \Magento\Framework\Exception\LocalizedException
+     * @return void
+     */
+    private function importData(array $fields, array $values)
+    {
+        $connection = $this->getConnection();
+        $connection->beginTransaction();
+
+        try {
+            if (count($fields) && count($values)) {
+                $this->getConnection()->insertArray($this->getMainTable(), $fields, $values);
+                $this->_importedRows += count($values);
+            }
+        } catch (\Magento\Framework\Exception\LocalizedException $e) {
+            $connection->rollback();
+            throw new \Magento\Framework\Exception\LocalizedException(__('Unable to import data'), $e);
+        } catch (\Exception $e) {
+            $connection->rollback();
+            $this->logger->critical($e);
+            throw new \Magento\Framework\Exception\LocalizedException(
+                __('Something went wrong while importing table rates.')
+            );
+        }
+        $connection->commit();
+    }
+
     /**
      * Upload table rate file and import data from it
      *
@@ -252,142 +249,72 @@ class Tablerate extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb
      */
     public function uploadAndImport(\Magento\Framework\DataObject $object)
     {
+        /**
+         * @var \Magento\Framework\App\Config\Value $object
+         */
         if (empty($_FILES['groups']['tmp_name']['tablerate']['fields']['import']['value'])) {
             return $this;
         }
+        $filePath = $_FILES['groups']['tmp_name']['tablerate']['fields']['import']['value'];
 
-        $csvFile = $_FILES['groups']['tmp_name']['tablerate']['fields']['import']['value'];
-        $website = $this->_storeManager->getWebsite($object->getScopeId());
-
-        $this->_importWebsiteId = (int)$website->getId();
-        $this->_importUniqueHash = [];
-        $this->_importErrors = [];
-        $this->_importedRows = 0;
-
-        $tmpDirectory = $this->_filesystem->getDirectoryRead(DirectoryList::SYS_TMP);
-        $path = $tmpDirectory->getRelativePath($csvFile);
-        $stream = $tmpDirectory->openFile($path);
-
-        // check and skip headers
-        $headers = $stream->readCsv();
-        if ($headers === false || count($headers) < 5) {
-            $stream->close();
-            throw new \Magento\Framework\Exception\LocalizedException(__('Please correct Table Rates File Format.'));
-        }
-
-        if ($object->getData('groups/tablerate/fields/condition_name/inherit') == '1') {
-            $conditionName = (string)$this->_coreConfig->getValue('carriers/tablerate/condition_name', 'default');
-        } else {
-            $conditionName = $object->getData('groups/tablerate/fields/condition_name/value');
-        }
-        $this->_importConditionName = $conditionName;
-
-        $connection = $this->getConnection();
-        $connection->beginTransaction();
+        $websiteId = $this->storeManager->getWebsite($object->getScopeId())->getId();
+        $conditionName = $this->getConditionName($object);
 
+        $file = $this->getCsvFile($filePath);
         try {
-            $rowNumber = 1;
-            $importData = [];
-
-            $this->_loadDirectoryCountries();
-            $this->_loadDirectoryRegions();
-
             // delete old data by website and condition name
             $condition = [
-                'website_id = ?' => $this->_importWebsiteId,
-                'condition_name = ?' => $this->_importConditionName,
+                'website_id = ?' => $websiteId,
+                'condition_name = ?' => $conditionName,
             ];
-            $connection->delete($this->getMainTable(), $condition);
-
-            while (false !== ($csvLine = $stream->readCsv())) {
-                $rowNumber++;
-
-                if (empty($csvLine)) {
-                    continue;
-                }
-
-                $row = $this->_getImportRow($csvLine, $rowNumber);
-                if ($row !== false) {
-                    $importData[] = $row;
-                }
+            $this->deleteByCondition($condition);
 
-                if (count($importData) == 5000) {
-                    $this->_saveImportData($importData);
-                    $importData = [];
-                }
+            $columns = $this->import->getColumns();
+            $conditionFullName = $this->_getConditionFullName($conditionName);
+            foreach ($this->import->getData($file, $websiteId, $conditionName, $conditionFullName) as $bunch) {
+                $this->importData($columns, $bunch);
             }
-            $this->_saveImportData($importData);
-            $stream->close();
-        } catch (\Magento\Framework\Exception\LocalizedException $e) {
-            $connection->rollback();
-            $stream->close();
-            throw new \Magento\Framework\Exception\LocalizedException(__($e->getMessage()));
         } catch (\Exception $e) {
-            $connection->rollback();
-            $stream->close();
-            $this->_logger->critical($e);
+            $this->logger->critical($e);
             throw new \Magento\Framework\Exception\LocalizedException(
                 __('Something went wrong while importing table rates.')
             );
+        } finally {
+            $file->close();
         }
 
-        $connection->commit();
-
-        if ($this->_importErrors) {
+        if ($this->import->hasErrors()) {
             $error = __(
                 'We couldn\'t import this file because of these errors: %1',
-                implode(" \n", $this->_importErrors)
+                implode(" \n", $this->import->getErrors())
             );
             throw new \Magento\Framework\Exception\LocalizedException($error);
         }
-
-        return $this;
     }
 
     /**
-     * Load directory countries
-     *
-     * @return \Magento\OfflineShipping\Model\ResourceModel\Carrier\Tablerate
+     * @param \Magento\Framework\DataObject $object
+     * @return mixed|string
      */
-    protected function _loadDirectoryCountries()
+    public function getConditionName(\Magento\Framework\DataObject $object)
     {
-        if ($this->_importIso2Countries !== null && $this->_importIso3Countries !== null) {
-            return $this;
-        }
-
-        $this->_importIso2Countries = [];
-        $this->_importIso3Countries = [];
-
-        /** @var $collection \Magento\Directory\Model\ResourceModel\Country\Collection */
-        $collection = $this->_countryCollectionFactory->create();
-        foreach ($collection->getData() as $row) {
-            $this->_importIso2Countries[$row['iso2_code']] = $row['country_id'];
-            $this->_importIso3Countries[$row['iso3_code']] = $row['country_id'];
+        if ($object->getData('groups/tablerate/fields/condition_name/inherit') == '1') {
+            $conditionName = (string)$this->coreConfig->getValue('carriers/tablerate/condition_name', 'default');
+        } else {
+            $conditionName = $object->getData('groups/tablerate/fields/condition_name/value');
         }
-
-        return $this;
+        return $conditionName;
     }
 
     /**
-     * Load directory regions
-     *
-     * @return \Magento\OfflineShipping\Model\ResourceModel\Carrier\Tablerate
+     * @param string $filePath
+     * @return \Magento\Framework\Filesystem\File\ReadInterface
      */
-    protected function _loadDirectoryRegions()
+    private function getCsvFile($filePath)
     {
-        if ($this->_importRegions !== null) {
-            return $this;
-        }
-
-        $this->_importRegions = [];
-
-        /** @var $collection \Magento\Directory\Model\ResourceModel\Region\Collection */
-        $collection = $this->_regionCollectionFactory->create();
-        foreach ($collection->getData() as $row) {
-            $this->_importRegions[$row['country_id']][$row['code']] = (int)$row['region_id'];
-        }
-
-        return $this;
+        $tmpDirectory = $this->filesystem->getDirectoryRead(DirectoryList::SYS_TMP);
+        $path = $tmpDirectory->getRelativePath($filePath);
+        return $tmpDirectory->openFile($path);
     }
 
     /**
@@ -399,110 +326,13 @@ class Tablerate extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb
     protected function _getConditionFullName($conditionName)
     {
         if (!isset($this->_conditionFullNames[$conditionName])) {
-            $name = $this->_carrierTablerate->getCode('condition_name_short', $conditionName);
+            $name = $this->carrierTablerate->getCode('condition_name_short', $conditionName);
             $this->_conditionFullNames[$conditionName] = $name;
         }
 
         return $this->_conditionFullNames[$conditionName];
     }
 
-    /**
-     * Validate row for import and return table rate array or false
-     * Error will be add to _importErrors array
-     *
-     * @param array $row
-     * @param int $rowNumber
-     * @return array|false
-     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
-     * @SuppressWarnings(PHPMD.NPathComplexity)
-     */
-    protected function _getImportRow($row, $rowNumber = 0)
-    {
-        // validate row
-        if (count($row) < 5) {
-            $this->_importErrors[] = __('Please correct Table Rates format in the Row #%1.', $rowNumber);
-            return false;
-        }
-
-        // strip whitespace from the beginning and end of each row
-        foreach ($row as $k => $v) {
-            $row[$k] = trim($v);
-        }
-
-        // validate country
-        if (isset($this->_importIso2Countries[$row[0]])) {
-            $countryId = $this->_importIso2Countries[$row[0]];
-        } elseif (isset($this->_importIso3Countries[$row[0]])) {
-            $countryId = $this->_importIso3Countries[$row[0]];
-        } elseif ($row[0] == '*' || $row[0] == '') {
-            $countryId = '0';
-        } else {
-            $this->_importErrors[] = __('Please correct Country "%1" in the Row #%2.', $row[0], $rowNumber);
-            return false;
-        }
-
-        // validate region
-        if ($countryId != '0' && isset($this->_importRegions[$countryId][$row[1]])) {
-            $regionId = $this->_importRegions[$countryId][$row[1]];
-        } elseif ($row[1] == '*' || $row[1] == '') {
-            $regionId = 0;
-        } else {
-            $this->_importErrors[] = __('Please correct Region/State "%1" in the Row #%2.', $row[1], $rowNumber);
-            return false;
-        }
-
-        // detect zip code
-        if ($row[2] == '*' || $row[2] == '') {
-            $zipCode = '*';
-        } else {
-            $zipCode = $row[2];
-        }
-
-        // validate condition value
-        $value = $this->_parseDecimalValue($row[3]);
-        if ($value === false) {
-            $this->_importErrors[] = __(
-                'Please correct %1 "%2" in the Row #%3.',
-                $this->_getConditionFullName($this->_importConditionName),
-                $row[3],
-                $rowNumber
-            );
-            return false;
-        }
-
-        // validate price
-        $price = $this->_parseDecimalValue($row[4]);
-        if ($price === false) {
-            $this->_importErrors[] = __('Please correct Shipping Price "%1" in the Row #%2.', $row[4], $rowNumber);
-            return false;
-        }
-
-        // protect from duplicate
-        $hash = sprintf("%s-%d-%s-%F", $countryId, $regionId, $zipCode, $value);
-        if (isset($this->_importUniqueHash[$hash])) {
-            $this->_importErrors[] = __(
-                'Duplicate Row #%1 (Country "%2", Region/State "%3", Zip "%4" and Value "%5")',
-                $rowNumber,
-                $row[0],
-                $row[1],
-                $zipCode,
-                $value
-            );
-            return false;
-        }
-        $this->_importUniqueHash[$hash] = true;
-
-        return [
-            $this->_importWebsiteId,    // website_id
-            $countryId,                 // dest_country_id
-            $regionId,                  // dest_region_id,
-            $zipCode,                   // dest_zip
-            $this->_importConditionName,// condition_name,
-            $value,                     // condition_value
-            $price                      // price
-        ];
-    }
-
     /**
      * Save import data batch
      *
@@ -527,23 +357,4 @@ class Tablerate extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb
 
         return $this;
     }
-
-    /**
-     * Parse and validate positive decimal value
-     * Return false if value is not decimal or is not positive
-     *
-     * @param string $value
-     * @return bool|float
-     */
-    protected function _parseDecimalValue($value)
-    {
-        if (!is_numeric($value)) {
-            return false;
-        }
-        $value = (double)sprintf('%.4F', $value);
-        if ($value < 0.0000) {
-            return false;
-        }
-        return $value;
-    }
 }
diff --git a/app/code/Magento/OfflineShipping/Model/ResourceModel/Carrier/Tablerate/CSV/ColumnNotFoundException.php b/app/code/Magento/OfflineShipping/Model/ResourceModel/Carrier/Tablerate/CSV/ColumnNotFoundException.php
new file mode 100644
index 0000000000000000000000000000000000000000..8cb6cda142c0f78c8a1b975d10923b6c03f399a0
--- /dev/null
+++ b/app/code/Magento/OfflineShipping/Model/ResourceModel/Carrier/Tablerate/CSV/ColumnNotFoundException.php
@@ -0,0 +1,14 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\OfflineShipping\Model\ResourceModel\Carrier\Tablerate\CSV;
+
+use Magento\Framework\Exception\LocalizedException;
+
+class ColumnNotFoundException extends LocalizedException
+{
+
+}
diff --git a/app/code/Magento/OfflineShipping/Model/ResourceModel/Carrier/Tablerate/CSV/ColumnResolver.php b/app/code/Magento/OfflineShipping/Model/ResourceModel/Carrier/Tablerate/CSV/ColumnResolver.php
new file mode 100644
index 0000000000000000000000000000000000000000..c1782b6b9a9e6b153c311341f4c123c571688f5c
--- /dev/null
+++ b/app/code/Magento/OfflineShipping/Model/ResourceModel/Carrier/Tablerate/CSV/ColumnResolver.php
@@ -0,0 +1,70 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\OfflineShipping\Model\ResourceModel\Carrier\Tablerate\CSV;
+
+class ColumnResolver
+{
+    const COLUMN_COUNTRY = 'Country';
+    const COLUMN_REGION = 'Region/State';
+    const COLUMN_ZIP = 'Zip/Postal Code';
+    const COLUMN_WEIGHT = 'Weight (and above)';
+    const COLUMN_WEIGHT_DESTINATION = 'Weight (and above)';
+    const COLUMN_PRICE = 'Shipping Price';
+
+    /**
+     * @var array
+     */
+    private $nameToPositionIdMap = [
+        self::COLUMN_COUNTRY => 0,
+        self::COLUMN_REGION => 1,
+        self::COLUMN_ZIP => 2,
+        self::COLUMN_WEIGHT => 3,
+        self::COLUMN_WEIGHT_DESTINATION => 3,
+        self::COLUMN_PRICE => 4,
+    ];
+
+    /**
+     * @var array
+     */
+    private $headers;
+
+    /**
+     * ColumnResolver constructor.
+     * @param array $headers
+     * @param array $columns
+     */
+    public function __construct(array $headers, array $columns = [])
+    {
+        $this->nameToPositionIdMap = array_merge($this->nameToPositionIdMap, $columns);
+        $this->headers = array_map('trim', $headers);
+    }
+
+    /**
+     * @param string $column
+     * @param array $values
+     * @return string|int|float|null
+     * @throws ColumnNotFoundException
+     */
+    public function getColumnValue($column, array $values)
+    {
+        $column = (string) $column;
+        $columnIndex = array_search($column, $this->headers, true);
+        if (false === $columnIndex) {
+            if (array_key_exists($column, $this->nameToPositionIdMap)) {
+                $columnIndex = $this->nameToPositionIdMap[$column];
+            } else {
+                throw new ColumnNotFoundException(__('Requested column "%1" cannot be resolved', $column));
+            }
+        }
+
+        if (!array_key_exists($columnIndex, $values)) {
+            throw new ColumnNotFoundException(__('Column "%1" not found', $column));
+        }
+
+        return  trim($values[$columnIndex]);
+    }
+}
diff --git a/app/code/Magento/OfflineShipping/Model/ResourceModel/Carrier/Tablerate/CSV/RowException.php b/app/code/Magento/OfflineShipping/Model/ResourceModel/Carrier/Tablerate/CSV/RowException.php
new file mode 100644
index 0000000000000000000000000000000000000000..a97bda4ec7d206e85003c9dc641a38d7bf1cb612
--- /dev/null
+++ b/app/code/Magento/OfflineShipping/Model/ResourceModel/Carrier/Tablerate/CSV/RowException.php
@@ -0,0 +1,13 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\OfflineShipping\Model\ResourceModel\Carrier\Tablerate\CSV;
+
+use Magento\Framework\Exception\LocalizedException;
+
+class RowException extends LocalizedException
+{
+}
diff --git a/app/code/Magento/OfflineShipping/Model/ResourceModel/Carrier/Tablerate/CSV/RowParser.php b/app/code/Magento/OfflineShipping/Model/ResourceModel/Carrier/Tablerate/CSV/RowParser.php
new file mode 100644
index 0000000000000000000000000000000000000000..6c1624f06005c85ad735ab533bfee20cec894c8a
--- /dev/null
+++ b/app/code/Magento/OfflineShipping/Model/ResourceModel/Carrier/Tablerate/CSV/RowParser.php
@@ -0,0 +1,207 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\OfflineShipping\Model\ResourceModel\Carrier\Tablerate\CSV;
+
+use Magento\Framework\Phrase;
+use Magento\OfflineShipping\Model\ResourceModel\Carrier\Tablerate\LocationDirectory;
+
+class RowParser
+{
+    /**
+     * @var LocationDirectory
+     */
+    private $locationDirectory;
+
+    /**
+     * RowParser constructor.
+     * @param LocationDirectory $locationDirectory
+     */
+    public function __construct(LocationDirectory $locationDirectory)
+    {
+        $this->locationDirectory = $locationDirectory;
+    }
+
+    /**
+     * @return array
+     */
+    public function getColumns()
+    {
+        return [
+            'website_id',
+            'dest_country_id',
+            'dest_region_id',
+            'dest_zip',
+            'condition_name',
+            'condition_value',
+            'price',
+        ];
+    }
+
+    /**
+     * @param array $rowData
+     * @param int $rowNumber
+     * @param int $websiteId
+     * @param string $conditionShortName
+     * @param string $conditionFullName
+     * @param ColumnResolver $columnResolver
+     * @return array
+     * @throws ColumnNotFoundException
+     * @throws RowException
+     */
+    public function parse(
+        array $rowData,
+        $rowNumber,
+        $websiteId,
+        $conditionShortName,
+        $conditionFullName,
+        ColumnResolver $columnResolver
+    ) {
+        // validate row
+        if (count($rowData) < 5) {
+            throw new RowException(__('Please correct Table Rates format in the Row #%1.', $rowNumber));
+        }
+
+        $countryId = $this->getCountryId($rowData, $rowNumber, $columnResolver);
+        $regionId = $this->getRegionId($rowData, $rowNumber, $columnResolver, $countryId);
+        $zipCode = $this->getZipCode($rowData, $columnResolver);
+        $conditionValue = $this->getConditionValue($rowData, $rowNumber, $conditionFullName, $columnResolver);
+        $price = $this->getPrice($rowData, $rowNumber, $columnResolver);
+
+        return [
+            'website_id' => $websiteId,
+            'dest_country_id' => $countryId,
+            'dest_region_id' => $regionId,
+            'dest_zip' => $zipCode,
+            'condition_name' => $conditionShortName,
+            'condition_value' => $conditionValue,
+            'price' => $price,
+        ];
+    }
+
+    /**
+     * @param array $rowData
+     * @param int $rowNumber
+     * @param ColumnResolver $columnResolver
+     * @return null|string
+     * @throws ColumnNotFoundException
+     * @throws RowException
+     */
+    private function getCountryId(array $rowData, $rowNumber, ColumnResolver $columnResolver)
+    {
+        $countryCode = $columnResolver->getColumnValue(ColumnResolver::COLUMN_COUNTRY, $rowData);
+        // validate country
+        if ($this->locationDirectory->hasCountryId($countryCode)) {
+            $countryId = $this->locationDirectory->getCountryId($countryCode);
+        } elseif ($countryCode === '*' || $countryCode === '') {
+            $countryId = '0';
+        } else {
+            throw new RowException(__('Please correct Country "%1" in the Row #%2.', $countryCode, $rowNumber));
+        }
+        return $countryId;
+    }
+
+    /**
+     * @param array $rowData
+     * @param int $rowNumber
+     * @param ColumnResolver $columnResolver
+     * @param int $countryId
+     * @return int|string
+     * @throws ColumnNotFoundException
+     * @throws RowException
+     */
+    private function getRegionId(array $rowData, $rowNumber, ColumnResolver $columnResolver, $countryId)
+    {
+        $regionCode = $columnResolver->getColumnValue(ColumnResolver::COLUMN_REGION, $rowData);
+        if ($countryId !== '0' && $this->locationDirectory->hasRegionId($countryId, $regionCode)) {
+            $regionId = $this->locationDirectory->getRegionId($countryId, $regionCode);
+        } elseif ($regionCode === '*' || $regionCode === '') {
+            $regionId = 0;
+        } else {
+            throw new RowException(__('Please correct Region/State "%1" in the Row #%2.', $regionCode, $rowNumber));
+        }
+        return $regionId;
+    }
+
+    /**
+     * @param array $rowData
+     * @param ColumnResolver $columnResolver
+     * @return float|int|null|string
+     * @throws ColumnNotFoundException
+     */
+    private function getZipCode(array $rowData, ColumnResolver $columnResolver)
+    {
+        $zipCode = $columnResolver->getColumnValue(ColumnResolver::COLUMN_ZIP, $rowData);
+        if ($zipCode === '') {
+            $zipCode = '*';
+        }
+        return $zipCode;
+    }
+
+    /**
+     * @param array $rowData
+     * @param int $rowNumber
+     * @param string $conditionFullName
+     * @param ColumnResolver $columnResolver
+     * @return bool|float
+     * @throws ColumnNotFoundException
+     * @throws RowException
+     */
+    private function getConditionValue(array $rowData, $rowNumber, $conditionFullName, ColumnResolver $columnResolver)
+    {
+        // validate condition value
+        $conditionValue = $columnResolver->getColumnValue($conditionFullName, $rowData);
+        $value = $this->_parseDecimalValue($conditionValue);
+        if ($value === false) {
+            throw new RowException(
+                __(
+                    'Please correct %1 "%2" in the Row #%3.',
+                    $conditionFullName,
+                    $conditionValue,
+                    $rowNumber
+                )
+            );
+        }
+        return $value;
+    }
+
+    /**
+     * @param array $rowData
+     * @param int $rowNumber
+     * @param ColumnResolver $columnResolver
+     * @return bool|float
+     * @throws ColumnNotFoundException
+     * @throws RowException
+     */
+    private function getPrice(array $rowData, $rowNumber, ColumnResolver $columnResolver)
+    {
+        $priceValue = $columnResolver->getColumnValue(ColumnResolver::COLUMN_PRICE, $rowData);
+        $price = $this->_parseDecimalValue($priceValue);
+        if ($price === false) {
+            throw new RowException(__('Please correct Shipping Price "%1" in the Row #%2.', $priceValue, $rowNumber));
+        }
+        return $price;
+    }
+
+    /**
+     * Parse and validate positive decimal value
+     * Return false if value is not decimal or is not positive
+     *
+     * @param string $value
+     * @return bool|float
+     */
+    private function _parseDecimalValue($value)
+    {
+        $result = false;
+        if (is_numeric($value)) {
+            $value = (double)sprintf('%.4F', $value);
+            if ($value >= 0.0000) {
+                $result = $value;
+            }
+        }
+        return $result;
+    }
+}
diff --git a/app/code/Magento/OfflineShipping/Model/ResourceModel/Carrier/Tablerate/DataHashGenerator.php b/app/code/Magento/OfflineShipping/Model/ResourceModel/Carrier/Tablerate/DataHashGenerator.php
new file mode 100644
index 0000000000000000000000000000000000000000..2ef8d09eab7371d55e956d913f7d47b68630c666
--- /dev/null
+++ b/app/code/Magento/OfflineShipping/Model/ResourceModel/Carrier/Tablerate/DataHashGenerator.php
@@ -0,0 +1,24 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\OfflineShipping\Model\ResourceModel\Carrier\Tablerate;
+
+class DataHashGenerator
+{
+    /**
+     * @param array $data
+     * @return string
+     */
+    public function getHash(array $data)
+    {
+        $countryId = $data['dest_country_id'];
+        $regionId = $data['dest_region_id'];
+        $zipCode = $data['dest_zip'];
+        $conditionValue = $data['condition_value'];
+
+        return sprintf("%s-%d-%s-%F", $countryId, $regionId, $zipCode, $conditionValue);
+    }
+}
diff --git a/app/code/Magento/OfflineShipping/Model/ResourceModel/Carrier/Tablerate/Import.php b/app/code/Magento/OfflineShipping/Model/ResourceModel/Carrier/Tablerate/Import.php
new file mode 100644
index 0000000000000000000000000000000000000000..00d13fdf7737f6b361614568867643abd0c6fefc
--- /dev/null
+++ b/app/code/Magento/OfflineShipping/Model/ResourceModel/Carrier/Tablerate/Import.php
@@ -0,0 +1,184 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\OfflineShipping\Model\ResourceModel\Carrier\Tablerate;
+
+use Magento\Framework\App\Config\ScopeConfigInterface;
+use Magento\Framework\Exception\LocalizedException;
+use Magento\Framework\Filesystem;
+use Magento\Framework\Filesystem\File\ReadInterface;
+use Magento\OfflineShipping\Model\ResourceModel\Carrier\Tablerate\CSV\ColumnResolver;
+use Magento\OfflineShipping\Model\ResourceModel\Carrier\Tablerate\CSV\ColumnResolverFactory;
+use Magento\OfflineShipping\Model\ResourceModel\Carrier\Tablerate\CSV\RowException;
+use Magento\OfflineShipping\Model\ResourceModel\Carrier\Tablerate\CSV\RowParser;
+use Magento\Store\Model\StoreManagerInterface;
+
+class Import
+{
+    /**
+     * @var StoreManagerInterface
+     */
+    private $storeManager;
+
+    /**
+     * @var Filesystem
+     */
+    private $filesystem;
+
+    /**
+     * @var ScopeConfigInterface
+     */
+    private $coreConfig;
+
+    /**
+     * @var array
+     */
+    private $errors = [];
+
+    /**
+     * @var CSV\RowParser
+     */
+    private $rowParser;
+
+    /**
+     * @var CSV\ColumnResolverFactory
+     */
+    private $columnResolverFactory;
+
+    /**
+     * @var DataHashGenerator
+     */
+    private $dataHashGenerator;
+
+    /**
+     * @var array
+     */
+    private $uniqueHash = [];
+
+    /**
+     * Import constructor.
+     * @param StoreManagerInterface $storeManager
+     * @param Filesystem $filesystem
+     * @param ScopeConfigInterface $coreConfig
+     * @param CSV\RowParser $rowParser
+     * @param CSV\ColumnResolverFactory $columnResolverFactory
+     * @param DataHashGenerator $dataHashGenerator
+     */
+    public function __construct(
+        StoreManagerInterface $storeManager,
+        Filesystem $filesystem,
+        ScopeConfigInterface $coreConfig,
+        RowParser $rowParser,
+        ColumnResolverFactory $columnResolverFactory,
+        DataHashGenerator $dataHashGenerator
+    ) {
+        $this->storeManager = $storeManager;
+        $this->filesystem = $filesystem;
+        $this->coreConfig = $coreConfig;
+        $this->rowParser = $rowParser;
+        $this->columnResolverFactory = $columnResolverFactory;
+        $this->dataHashGenerator = $dataHashGenerator;
+    }
+
+    /**
+     * @return bool
+     */
+    public function hasErrors()
+    {
+        return (bool)count($this->getErrors());
+    }
+
+    /**
+     * @return array
+     */
+    public function getErrors()
+    {
+        return $this->errors;
+    }
+
+    /**
+     * @return array
+     */
+    public function getColumns()
+    {
+        return $this->rowParser->getColumns();
+    }
+
+    /**
+     * @param ReadInterface $file
+     * @param int $websiteId
+     * @param string $conditionShortName
+     * @param string $conditionFullName
+     * @param int $bunchSize
+     * @return \Generator
+     * @throws LocalizedException
+     */
+    public function getData(ReadInterface $file, $websiteId, $conditionShortName, $conditionFullName, $bunchSize = 5000)
+    {
+        $this->errors = [];
+
+        $headers = $this->getHeaders($file);
+        /** @var ColumnResolver $columnResolver */
+        $columnResolver = $this->columnResolverFactory->create(['headers' => $headers]);
+
+        $rowNumber = 1;
+        $items = [];
+        while (false !== ($csvLine = $file->readCsv())) {
+            try {
+                if (empty($csvLine)) {
+                    continue;
+                }
+                $rowData = $this->rowParser->parse(
+                    $csvLine,
+                    ++$rowNumber,
+                    $websiteId,
+                    $conditionShortName,
+                    $conditionFullName,
+                    $columnResolver
+                );
+
+                // protect from duplicate
+                $hash = $this->dataHashGenerator->getHash($rowData);
+                if (array_key_exists($hash, $this->uniqueHash)) {
+                    throw new RowException(
+                        __(
+                            'Duplicate Row #%1 (duplicates row #%2)',
+                            $rowNumber,
+                            $this->uniqueHash[$hash]
+                        )
+                    );
+                }
+                $this->uniqueHash[$hash] = $csvLine;
+
+                $items[] = $rowData;
+                if (count($items) === $bunchSize) {
+                    yield $items;
+                    $items = [];
+                }
+            } catch (RowException $e) {
+                $this->errors[] = $e->getMessage();
+            }
+        }
+        if (count($items)) {
+            yield $items;
+        }
+    }
+
+    /**
+     * @param ReadInterface $file
+     * @return array|bool
+     * @throws LocalizedException
+     */
+    private function getHeaders(ReadInterface $file)
+    {
+        // check and skip headers
+        $headers = $file->readCsv();
+        if ($headers === false || count($headers) < 5) {
+            throw new LocalizedException(__('Please correct Table Rates File Format.'));
+        }
+        return $headers;
+    }
+}
diff --git a/app/code/Magento/OfflineShipping/Model/ResourceModel/Carrier/Tablerate/LocationDirectory.php b/app/code/Magento/OfflineShipping/Model/ResourceModel/Carrier/Tablerate/LocationDirectory.php
new file mode 100644
index 0000000000000000000000000000000000000000..a3a7d9e8c78942c6f0eac52228131e083e4b09c1
--- /dev/null
+++ b/app/code/Magento/OfflineShipping/Model/ResourceModel/Carrier/Tablerate/LocationDirectory.php
@@ -0,0 +1,143 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\OfflineShipping\Model\ResourceModel\Carrier\Tablerate;
+
+class LocationDirectory
+{
+    /**
+     * @var array
+     */
+    protected $regions;
+
+    /**
+     * @var array
+     */
+    protected $iso2Countries;
+
+    /**
+     * @var array
+     */
+    protected $iso3Countries;
+
+    /**
+     * @var \Magento\Directory\Model\ResourceModel\Country\CollectionFactory
+     */
+    protected $_countryCollectionFactory;
+
+    /**
+     * @var \Magento\Directory\Model\ResourceModel\Region\CollectionFactory
+     */
+    protected $_regionCollectionFactory;
+
+    /**
+     * LocationDirectory constructor.
+     * @param \Magento\Directory\Model\ResourceModel\Country\CollectionFactory $countryCollectionFactory
+     * @param \Magento\Directory\Model\ResourceModel\Region\CollectionFactory $regionCollectionFactory
+     */
+    public function __construct(
+        \Magento\Directory\Model\ResourceModel\Country\CollectionFactory $countryCollectionFactory,
+        \Magento\Directory\Model\ResourceModel\Region\CollectionFactory $regionCollectionFactory
+    ) {
+        $this->_countryCollectionFactory = $countryCollectionFactory;
+        $this->_regionCollectionFactory = $regionCollectionFactory;
+    }
+
+    /**
+     * @param string $countryCode
+     * @return null|string
+     */
+    public function getCountryId($countryCode)
+    {
+        $this->loadCountries();
+        $countryId = null;
+        if (isset($this->iso2Countries[$countryCode])) {
+            $countryId = $this->iso2Countries[$countryCode];
+        } elseif (isset($this->iso3Countries[$countryCode])) {
+            $countryId = $this->iso3Countries[$countryCode];
+        }
+
+        return $countryId;
+    }
+
+    /**
+     * Load directory countries
+     *
+     * @return \Magento\OfflineShipping\Model\ResourceModel\Carrier\Tablerate
+     */
+    protected function loadCountries()
+    {
+        if ($this->iso2Countries !== null && $this->iso3Countries !== null) {
+            return $this;
+        }
+
+        $this->iso2Countries = [];
+        $this->iso3Countries = [];
+
+        /** @var $collection \Magento\Directory\Model\ResourceModel\Country\Collection */
+        $collection = $this->_countryCollectionFactory->create();
+        foreach ($collection->getData() as $row) {
+            $this->iso2Countries[$row['iso2_code']] = $row['country_id'];
+            $this->iso3Countries[$row['iso3_code']] = $row['country_id'];
+        }
+
+        return $this;
+    }
+
+    /**
+     * @param string $countryCode
+     * @return bool
+     */
+    public function hasCountryId($countryCode)
+    {
+        $this->loadCountries();
+        return isset($this->iso2Countries[$countryCode]) || isset($this->iso3Countries[$countryCode]);
+    }
+
+    /**
+     * @param string $countryId
+     * @param string $regionCode
+     * @return bool
+     */
+    public function hasRegionId($countryId, $regionCode)
+    {
+        $this->loadRegions();
+        return isset($this->regions[$countryId][$regionCode]);
+    }
+
+    /**
+     * Load directory regions
+     *
+     * @return \Magento\OfflineShipping\Model\ResourceModel\Carrier\Tablerate
+     */
+    protected function loadRegions()
+    {
+        if ($this->regions !== null) {
+            return $this;
+        }
+
+        $this->regions = [];
+
+        /** @var $collection \Magento\Directory\Model\ResourceModel\Region\Collection */
+        $collection = $this->_regionCollectionFactory->create();
+        foreach ($collection->getData() as $row) {
+            $this->regions[$row['country_id']][$row['code']] = (int)$row['region_id'];
+        }
+
+        return $this;
+    }
+
+    /**
+     * @param int $countryId
+     * @param string $regionCode
+     * @return string
+     */
+    public function getRegionId($countryId, $regionCode)
+    {
+        $this->loadRegions();
+        return $this->regions[$countryId][$regionCode];
+    }
+}
diff --git a/app/code/Magento/OfflineShipping/Model/ResourceModel/Carrier/Tablerate/RateQuery.php b/app/code/Magento/OfflineShipping/Model/ResourceModel/Carrier/Tablerate/RateQuery.php
new file mode 100644
index 0000000000000000000000000000000000000000..1c4d87dd11c9f9ad6051d958f62b8422df255efb
--- /dev/null
+++ b/app/code/Magento/OfflineShipping/Model/ResourceModel/Carrier/Tablerate/RateQuery.php
@@ -0,0 +1,115 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\OfflineShipping\Model\ResourceModel\Carrier\Tablerate;
+
+class RateQuery
+{
+    /**
+     * @var \Magento\Quote\Model\Quote\Address\RateRequest
+     */
+    private $request;
+
+    /**
+     * RateQuery constructor.
+     * @param \Magento\Quote\Model\Quote\Address\RateRequest $request
+     */
+    public function __construct(
+        \Magento\Quote\Model\Quote\Address\RateRequest $request
+    ) {
+        $this->request = $request;
+    }
+
+    /**
+     * @param \Magento\Framework\DB\Select $select
+     * @return \Magento\Framework\DB\Select
+     */
+    public function prepareSelect(\Magento\Framework\DB\Select $select)
+    {
+        $select->where(
+            'website_id = :website_id'
+        )->order(
+            ['dest_country_id DESC', 'dest_region_id DESC', 'dest_zip DESC']
+        )->limit(
+            1
+        );
+
+        // Render destination condition
+        $orWhere = '(' . implode(
+            ') OR (',
+            [
+                "dest_country_id = :country_id AND dest_region_id = :region_id AND dest_zip = :postcode",
+                "dest_country_id = :country_id AND dest_region_id = :region_id AND dest_zip = ''",
+
+                // Handle asterisk in dest_zip field
+                "dest_country_id = :country_id AND dest_region_id = :region_id AND dest_zip = '*'",
+                "dest_country_id = :country_id AND dest_region_id = 0 AND dest_zip = '*'",
+                "dest_country_id = '0' AND dest_region_id = :region_id AND dest_zip = '*'",
+                "dest_country_id = '0' AND dest_region_id = 0 AND dest_zip = '*'",
+                "dest_country_id = :country_id AND dest_region_id = 0 AND dest_zip = ''",
+                "dest_country_id = :country_id AND dest_region_id = 0 AND dest_zip = :postcode",
+                "dest_country_id = :country_id AND dest_region_id = 0 AND dest_zip = '*'"
+            ]
+        ) . ')';
+        $select->where($orWhere);
+
+        // Render condition by condition name
+        if (is_array($this->request->getConditionName())) {
+            $orWhere = [];
+            foreach (range(0, count($this->request->getConditionName())) as $conditionNumber) {
+                $bindNameKey = sprintf(':condition_name_%d', $conditionNumber);
+                $bindValueKey = sprintf(':condition_value_%d', $conditionNumber);
+                $orWhere[] = "(condition_name = {$bindNameKey} AND condition_value <= {$bindValueKey})";
+            }
+
+            if ($orWhere) {
+                $select->where(implode(' OR ', $orWhere));
+            }
+        } else {
+            $select->where('condition_name = :condition_name');
+            $select->where('condition_value <= :condition_value');
+        }
+        return $select;
+    }
+
+    /**
+     * @return array
+     */
+    public function getBindings()
+    {
+        $bind = [
+            ':website_id' => (int)$this->request->getWebsiteId(),
+            ':country_id' => $this->request->getDestCountryId(),
+            ':region_id' => (int)$this->request->getDestRegionId(),
+            ':postcode' => $this->request->getDestPostcode(),
+        ];
+
+        // Render condition by condition name
+        if (is_array($this->request->getConditionName())) {
+            $i = 0;
+            foreach ($this->request->getConditionName() as $conditionName) {
+                $bindNameKey = sprintf(':condition_name_%d', $i);
+                $bindValueKey = sprintf(':condition_value_%d', $i);
+                $bind[$bindNameKey] = $conditionName;
+                $bind[$bindValueKey] = $this->request->getData($conditionName);
+                $i++;
+            }
+        } else {
+            $bind[':condition_name'] = $this->request->getConditionName();
+            $bind[':condition_value'] = $this->request->getData($this->request->getConditionName());
+        }
+
+        return $bind;
+    }
+
+    /**
+     * @return \Magento\Quote\Model\Quote\Address\RateRequest
+     */
+    public function getRequest()
+    {
+        return $this->request;
+    }
+}
diff --git a/app/code/Magento/OfflineShipping/Test/Unit/Model/ResourceModel/Carrier/Tablerate/CSV/ColumnResolverTest.php b/app/code/Magento/OfflineShipping/Test/Unit/Model/ResourceModel/Carrier/Tablerate/CSV/ColumnResolverTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..980204d7dab560c6414f5fb758242c221e36f973
--- /dev/null
+++ b/app/code/Magento/OfflineShipping/Test/Unit/Model/ResourceModel/Carrier/Tablerate/CSV/ColumnResolverTest.php
@@ -0,0 +1,142 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\OfflineShipping\Test\Unit\Model\ResourceModel\Carrier\Tablerate\CSV;
+
+use Magento\OfflineShipping\Model\ResourceModel\Carrier\Tablerate\CSV\ColumnResolver;
+
+/**
+ * Unit test for Magento\OfflineShipping\Model\ResourceModel\Carrier\Tablerate\CSV\ColumnResolver
+ */
+class ColumnResolverTest extends \PHPUnit_Framework_TestCase
+{
+    const CUSTOM_FIELD = 'custom_field';
+
+    private $values = [
+        ColumnResolver::COLUMN_COUNTRY => 'country value',
+        ColumnResolver::COLUMN_REGION => 'region value',
+        ColumnResolver::COLUMN_ZIP => 'zip_value',
+        ColumnResolver::COLUMN_WEIGHT => 'weight_value',
+        ColumnResolver::COLUMN_WEIGHT_DESTINATION => 'weight_destination_value',
+        ColumnResolver::COLUMN_PRICE => 'price_value',
+        self::CUSTOM_FIELD => 'custom_value',
+    ];
+
+    /**
+     * @param $column
+     * @param $expectedValue
+     * @throws \Magento\OfflineShipping\Model\ResourceModel\Carrier\Tablerate\CSV\ColumnNotFoundException
+     * @dataProvider getColumnValueDataProvider
+     */
+    public function testGetColumnValueByPosition($column, $expectedValue)
+    {
+        $headers = array_keys($this->values);
+        $headers = [];
+        $columnResolver = $this->createColumnResolver($headers);
+        $values = array_values($this->values);
+        $result = $columnResolver->getColumnValue($column, $values);
+        $this->assertEquals($expectedValue, $result);
+    }
+
+    /**
+     * @param array $headers
+     * @param array $columns
+     * @return ColumnResolver
+     */
+    private function createColumnResolver(array $headers = [], array $columns = [])
+    {
+        return new ColumnResolver($headers, $columns);
+    }
+
+    /**
+     * @return void
+     * @dataProvider getColumnValueWithCustomHeaderDataProvider
+     */
+    public function testGetColumnValueByHeader($column, $expectedValue)
+    {
+        $reversedValues = array_reverse($this->values);
+        $headers = array_keys($reversedValues);
+        $values = array_values($reversedValues);
+        $columnResolver = $this->createColumnResolver($headers);
+        $result = $columnResolver->getColumnValue($column, $values);
+        $this->assertEquals($expectedValue, $result);
+    }
+
+    /**
+     * @return array
+     */
+    public function getColumnValueDataProvider()
+    {
+        return [
+            ColumnResolver::COLUMN_COUNTRY => [
+                ColumnResolver::COLUMN_COUNTRY,
+                $this->values[ColumnResolver::COLUMN_COUNTRY],
+            ],
+            ColumnResolver::COLUMN_REGION => [
+                ColumnResolver::COLUMN_REGION,
+                $this->values[ColumnResolver::COLUMN_REGION],
+            ],
+            ColumnResolver::COLUMN_ZIP => [
+                ColumnResolver::COLUMN_ZIP,
+                $this->values[ColumnResolver::COLUMN_ZIP],
+            ],
+            ColumnResolver::COLUMN_WEIGHT => [
+                ColumnResolver::COLUMN_WEIGHT,
+                $this->values[ColumnResolver::COLUMN_WEIGHT],
+            ],
+            ColumnResolver::COLUMN_WEIGHT_DESTINATION => [
+                ColumnResolver::COLUMN_WEIGHT_DESTINATION,
+                $this->values[ColumnResolver::COLUMN_WEIGHT_DESTINATION],
+            ],
+            ColumnResolver::COLUMN_PRICE => [
+                ColumnResolver::COLUMN_PRICE,
+                $this->values[ColumnResolver::COLUMN_PRICE],
+            ]
+        ];
+    }
+
+    /**
+     * @return array
+     */
+    public function getColumnValueWithCustomHeaderDataProvider()
+    {
+        $customField = [
+            self::CUSTOM_FIELD => [
+                self::CUSTOM_FIELD,
+                $this->values[self::CUSTOM_FIELD],
+            ],
+        ];
+        return array_merge($this->getColumnValueDataProvider(), $customField);
+    }
+
+    /**
+     * @throws \Magento\OfflineShipping\Model\ResourceModel\Carrier\Tablerate\CSV\ColumnNotFoundException
+     * @expectedException \Magento\OfflineShipping\Model\ResourceModel\Carrier\Tablerate\CSV\ColumnNotFoundException
+     * @expectedExceptionMessage Requested column "custom_field" cannot be resolved
+     */
+    public function testGetColumnValueWithUnknownColumn()
+    {
+        $columnResolver = $this->createColumnResolver();
+        $values = array_values($this->values);
+        $columnResolver->getColumnValue(self::CUSTOM_FIELD, $values);
+    }
+
+    /**
+     * @throws \Magento\OfflineShipping\Model\ResourceModel\Carrier\Tablerate\CSV\ColumnNotFoundException
+     * @expectedException \Magento\OfflineShipping\Model\ResourceModel\Carrier\Tablerate\CSV\ColumnNotFoundException
+     * @expectedExceptionMessage Column "new_custom_column" not found
+     */
+    public function testGetColumnValueWithUndefinedValue()
+    {
+        $columnName = 'new_custom_column';
+
+        $headers = array_keys($this->values);
+        $headers[] = $columnName;
+        $columnResolver = $this->createColumnResolver($headers);
+        $values = array_values($this->values);
+        $columnResolver->getColumnValue($columnName, $values);
+    }
+}
diff --git a/app/code/Magento/OfflineShipping/Test/Unit/Model/ResourceModel/Carrier/Tablerate/CSV/RowParserTest.php b/app/code/Magento/OfflineShipping/Test/Unit/Model/ResourceModel/Carrier/Tablerate/CSV/RowParserTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..fc6ec40b46e084bcd7a22807dd223e7965e54433
--- /dev/null
+++ b/app/code/Magento/OfflineShipping/Test/Unit/Model/ResourceModel/Carrier/Tablerate/CSV/RowParserTest.php
@@ -0,0 +1,211 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\OfflineShipping\Test\Unit\Model\ResourceModel\Carrier\Tablerate\CSV;
+
+use Magento\OfflineShipping\Model\ResourceModel\Carrier\Tablerate\CSV\ColumnResolver;
+use Magento\OfflineShipping\Model\ResourceModel\Carrier\Tablerate\CSV\RowException;
+use Magento\OfflineShipping\Model\ResourceModel\Carrier\Tablerate\CSV\RowParser;
+use Magento\OfflineShipping\Model\ResourceModel\Carrier\Tablerate\LocationDirectory;
+
+/**
+ * Unit test for Magento\OfflineShipping\Model\ResourceModel\Carrier\Tablerate\CSV\RowParser
+ */
+class RowParserTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var  ColumnResolver|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $columnResolverMock;
+
+    /**
+     * @var RowParser
+     */
+    private $rowParser;
+
+    /**
+     * @var LocationDirectory|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $locationDirectoryMock;
+
+    /**
+     * {@inheritDoc}
+     */
+    protected function setUp()
+    {
+        $this->locationDirectoryMock = $this->getMockBuilder(LocationDirectory::class)
+            ->setMethods(['hasCountryId', 'getCountryId', 'hasRegionId', 'getRegionId'])
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->columnResolverMock = $this->getMockBuilder(ColumnResolver::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->rowParser = new RowParser(
+            $this->locationDirectoryMock
+        );
+    }
+
+    /**
+     * @return void
+     */
+    public function testGetColumns()
+    {
+        $columns = $this->rowParser->getColumns();
+        $this->assertTrue(is_array($columns), 'Columns should be array, ' . gettype($columns) . ' given');
+        $this->assertNotEmpty($columns);
+    }
+
+    /**
+     * @return void
+     */
+    public function testParse()
+    {
+        $expectedResult = [
+            'website_id' => 58,
+            'dest_country_id' => '0',
+            'dest_region_id' => 0,
+            'dest_zip' => '*',
+            'condition_name' => 'condition_short_name',
+            'condition_value' => 40.0,
+            'price' => 350.0,
+        ];
+        $rowData = ['a', 'b', 'c', 'd', 'e'];
+        $rowNumber = 120;
+        $websiteId = 58;
+        $conditionShortName = 'condition_short_name';
+        $conditionFullName = 'condition_full_name';
+        $columnValueMap = [
+            [ColumnResolver::COLUMN_COUNTRY, $rowData, '*'],
+            [ColumnResolver::COLUMN_REGION, $rowData, '*'],
+            [ColumnResolver::COLUMN_ZIP, $rowData, ''],
+            [$conditionFullName, $rowData, 40],
+            [ColumnResolver::COLUMN_PRICE, $rowData, 350],
+        ];
+        $result = $this->parse(
+            $rowData,
+            $conditionFullName,
+            $rowNumber,
+            $websiteId,
+            $conditionShortName,
+            $columnValueMap
+        );
+        $this->assertEquals($expectedResult, $result);
+    }
+
+    /**
+     * @param array $rowData
+     * @param $conditionFullName
+     * @param array $columnValueMap
+     * @param $expectedMessage
+     * @throws null|RowException
+     * @dataProvider parseWithExceptionDataProvider
+     * @expectedException \Magento\OfflineShipping\Model\ResourceModel\Carrier\Tablerate\CSV\RowException
+     */
+    public function testParseWithException(array $rowData, $conditionFullName, array $columnValueMap, $expectedMessage)
+    {
+        $rowNumber = 120;
+        $websiteId = 58;
+        $conditionShortName = 'condition_short_name';
+        $actualMessage = null;
+        $exception = null;
+        try {
+            $this->parse(
+                $rowData,
+                $conditionFullName,
+                $rowNumber,
+                $websiteId,
+                $conditionShortName,
+                $columnValueMap
+            );
+        } catch (\Exception $e) {
+            $actualMessage = $e->getMessage();
+            $exception = $e;
+        }
+        $this->assertEquals($expectedMessage, $actualMessage);
+        throw $exception;
+    }
+
+    public function parseWithExceptionDataProvider()
+    {
+        $rowData = ['a', 'b', 'c', 'd', 'e'];
+        $conditionFullName = 'condition_full_name';
+        return [
+            [
+                $rowData,
+                $conditionFullName,
+                [
+                    [ColumnResolver::COLUMN_COUNTRY, $rowData, 'XX'],
+                    [ColumnResolver::COLUMN_REGION, $rowData, '*'],
+                    [ColumnResolver::COLUMN_ZIP, $rowData, ''],
+                    [$conditionFullName, $rowData, 40],
+                    [ColumnResolver::COLUMN_PRICE, $rowData, 350],
+                ],
+                'Please correct Country "XX" in the Row #120.',
+            ],
+            [
+                $rowData,
+                $conditionFullName,
+                [
+                    [ColumnResolver::COLUMN_COUNTRY, $rowData, '*'],
+                    [ColumnResolver::COLUMN_REGION, $rowData, 'AA'],
+                    [ColumnResolver::COLUMN_ZIP, $rowData, ''],
+                    [$conditionFullName, $rowData, 40],
+                    [ColumnResolver::COLUMN_PRICE, $rowData, 350],
+                ],
+                'Please correct Region/State "AA" in the Row #120.',
+            ],
+            [
+                $rowData,
+                $conditionFullName,
+                [
+                    [ColumnResolver::COLUMN_COUNTRY, $rowData, '*'],
+                    [ColumnResolver::COLUMN_REGION, $rowData, '*'],
+                    [ColumnResolver::COLUMN_ZIP, $rowData, ''],
+                    [$conditionFullName, $rowData, 'QQQ'],
+                    [ColumnResolver::COLUMN_PRICE, $rowData, 350],
+                ],
+                'Please correct condition_full_name "QQQ" in the Row #120.',
+            ],
+            [
+                $rowData,
+                $conditionFullName,
+                [
+                    [ColumnResolver::COLUMN_COUNTRY, $rowData, '*'],
+                    [ColumnResolver::COLUMN_REGION, $rowData, '*'],
+                    [ColumnResolver::COLUMN_ZIP, $rowData, ''],
+                    [$conditionFullName, $rowData, 40],
+                    [ColumnResolver::COLUMN_PRICE, $rowData, 'BBB'],
+                ],
+                'Please correct Shipping Price "BBB" in the Row #120.',
+            ],
+        ];
+    }
+
+    /**
+     * @param $rowData
+     * @param $conditionFullName
+     * @param $rowNumber
+     * @param $websiteId
+     * @param $conditionShortName
+     * @return array
+     * @throws \Magento\OfflineShipping\Model\ResourceModel\Carrier\Tablerate\CSV\RowException
+     */
+    private function parse($rowData, $conditionFullName, $rowNumber, $websiteId, $conditionShortName, $columnValueMap)
+    {
+        $this->columnResolverMock->expects($this->any())
+            ->method('getColumnValue')
+            ->willReturnMap($columnValueMap);
+        $result = $this->rowParser->parse(
+            $rowData,
+            $rowNumber,
+            $websiteId,
+            $conditionShortName,
+            $conditionFullName,
+            $this->columnResolverMock
+        );
+        return $result;
+    }
+}
diff --git a/app/code/Magento/OfflineShipping/Test/Unit/Model/ResourceModel/Carrier/Tablerate/ImportTest.php b/app/code/Magento/OfflineShipping/Test/Unit/Model/ResourceModel/Carrier/Tablerate/ImportTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..0bb192e3deacbdbc0e118795fa1e911d75781ac9
--- /dev/null
+++ b/app/code/Magento/OfflineShipping/Test/Unit/Model/ResourceModel/Carrier/Tablerate/ImportTest.php
@@ -0,0 +1,229 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\OfflineShipping\Test\Unit\Model\ResourceModel\Carrier\Tablerate;
+
+use Magento\Framework\App\Config\ScopeConfigInterface;
+use Magento\Framework\Filesystem;
+use Magento\Framework\Filesystem\File\ReadInterface;
+use Magento\OfflineShipping\Model\ResourceModel\Carrier\Tablerate\CSV\ColumnResolverFactory;
+use Magento\OfflineShipping\Model\ResourceModel\Carrier\Tablerate\CSV\ColumnResolver;
+use Magento\OfflineShipping\Model\ResourceModel\Carrier\Tablerate\CSV\RowParser;
+use Magento\OfflineShipping\Model\ResourceModel\Carrier\Tablerate\DataHashGenerator;
+use Magento\OfflineShipping\Model\ResourceModel\Carrier\Tablerate\Import;
+use Magento\Store\Model\StoreManagerInterface;
+
+/**
+ * Unit test for Magento\OfflineShipping\Model\ResourceModel\Carrier\Tablerate\Import
+ */
+class ImportTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\OfflineShipping\Model\ResourceModel\Carrier\Tablerate\Import
+     */
+    private $import;
+
+    /**
+     * @var StoreManagerInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $storeManagerMock;
+
+    /**
+     * @var Filesystem|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $filesystemMock;
+
+    /**
+     * @var ScopeConfigInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $scopeConfigMock;
+
+    /**
+     * @var RowParser|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $rowParserMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    private $columnResolverFactoryMock;
+
+    /**
+     * @var DataHashGenerator|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $dataHashGeneratorMock;
+
+    /**
+     * {@inheritDoc}
+     */
+    protected function setUp()
+    {
+        $this->storeManagerMock = $this->getMockBuilder(StoreManagerInterface::class)
+            ->getMockForAbstractClass();
+        $this->filesystemMock = $this->getMockBuilder(Filesystem::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->scopeConfigMock = $this->getMockBuilder(ScopeConfigInterface::class)
+            ->getMockForAbstractClass();
+        $this->rowParserMock = $this->getMockBuilder(RowParser::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->columnResolverFactoryMock = $this->getMockBuilder(ColumnResolverFactory::class)
+            ->setMethods(['create'])
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->dataHashGeneratorMock = $this->getMockBuilder(DataHashGenerator::class)
+            ->getMock();
+        $this->rowParserMock->expects($this->any())
+            ->method('parse')
+            ->willReturnArgument(0);
+        $this->dataHashGeneratorMock->expects($this->any())
+            ->method('getHash')
+            ->willReturnCallback(
+                function (array $data) {
+                    return implode('_', $data);
+                }
+            );
+
+        $this->import = new Import(
+            $this->storeManagerMock,
+            $this->filesystemMock,
+            $this->scopeConfigMock,
+            $this->rowParserMock,
+            $this->columnResolverFactoryMock,
+            $this->dataHashGeneratorMock
+        );
+    }
+
+    /**
+     * @return void
+     */
+    public function testGetColumns()
+    {
+        $columns = ['column_1', 'column_2'];
+        $this->rowParserMock->expects($this->once())
+            ->method('getColumns')
+            ->willReturn($columns);
+        $result = $this->import->getColumns();
+        $this->assertEquals($columns, $result);
+    }
+
+    /**
+     * @return void
+     */
+    public function testGetData()
+    {
+        $lines = [
+            ['header_1', 'header_2', 'header_3', 'header_4', 'header_5'],
+            ['a1', 'b1', 'c1', 'd1', 'e1'],
+            ['a2', 'b2', 'c2', 'd2', 'e2'],
+            ['a3', 'b3', 'c3', 'd3', 'e3'],
+            ['a4', 'b4', 'c4', 'd4', 'e4'],
+            ['a5', 'b5', 'c5', 'd5', 'e5'],
+        ];
+        $file = $this->createFileMock($lines);
+        $expectedResult = [
+            [
+                $lines[1],
+                $lines[2],
+            ],
+            [
+                $lines[3],
+                $lines[4],
+            ],
+            [
+                $lines[5]
+            ]
+        ];
+
+        $columnResolver = $this->getMockBuilder(ColumnResolver::class)->disableOriginalConstructor()->getMock();
+        $this->columnResolverFactoryMock
+            ->expects($this->once())
+            ->method('create')
+            ->with(['headers' => $lines[0]])
+            ->willReturn($columnResolver);
+
+        $result = [];
+        foreach ($this->import->getData($file, 1, 'short_name', 'full_name', 2) as $bunch) {
+            $result[] = $bunch;
+        }
+        $this->assertEquals($expectedResult, $result);
+        $this->assertFalse($this->import->hasErrors());
+        $this->assertEquals([], $this->import->getErrors());
+    }
+
+    /**
+     * @return void
+     */
+    public function testGetDataWithDuplicatedLine()
+    {
+        $lines = [
+            ['header_1', 'header_2', 'header_3', 'header_4', 'header_5'],
+            ['a1', 'b1', 'c1', 'd1', 'e1'],
+            ['a1', 'b1', 'c1', 'd1', 'e1'],
+            [],
+            ['a2', 'b2', 'c2', 'd2', 'e2'],
+        ];
+        $file = $this->createFileMock($lines);
+        $expectedResult = [
+            [
+                $lines[1],
+                $lines[4],
+            ],
+        ];
+
+        $columnResolver = $this->getMockBuilder(ColumnResolver::class)->disableOriginalConstructor()->getMock();
+        $this->columnResolverFactoryMock
+            ->expects($this->once())
+            ->method('create')
+            ->with(['headers' => $lines[0]])
+            ->willReturn($columnResolver);
+
+        $result = [];
+        foreach ($this->import->getData($file, 1, 'short_name', 'full_name', 2) as $bunch) {
+            $result[] = $bunch;
+        }
+        $this->assertEquals($expectedResult, $result);
+        $this->assertTrue($this->import->hasErrors());
+        $this->assertEquals(['Duplicate Row #%1 (duplicates row #%2)'], $this->import->getErrors());
+    }
+
+    /**
+     * @expectedException \Magento\Framework\Exception\LocalizedException
+     * @expectedExceptionMessage Please correct Table Rates File Format.
+     * @SuppressWarnings(PHPMD.UnusedLocalVariable)
+     */
+    public function testGetDataFromEmptyFile()
+    {
+        $lines = [];
+        $file = $this->createFileMock($lines);
+        foreach ($this->import->getData($file, 1, 'short_name', 'full_name', 2) as $bunch) {
+            $this->assertTrue(false, 'Exception about empty header is not thrown');
+        }
+    }
+
+    /**
+     * @param array $lines
+     * @return ReadInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private function createFileMock(array $lines)
+    {
+        $file = $this->getMockBuilder(ReadInterface::class)
+            ->setMethods(['readCsv'])
+            ->getMockForAbstractClass();
+        $i = 0;
+        foreach ($lines as $line) {
+            $file->expects($this->at($i))
+                ->method('readCsv')
+                ->willReturn($line);
+            $i++;
+        }
+        $file->expects($this->at($i))
+            ->method('readCsv')
+            ->willReturn(false);
+        return $file;
+    }
+}
diff --git a/app/code/Magento/PageCache/Model/App/FrontController/BuiltinPlugin.php b/app/code/Magento/PageCache/Model/App/FrontController/BuiltinPlugin.php
index fd04f1fe4ca2fbe28854f837b0a3323d70164473..a8871f803a1be31fe12bd2fef45a1ad2a3d35f84 100644
--- a/app/code/Magento/PageCache/Model/App/FrontController/BuiltinPlugin.php
+++ b/app/code/Magento/PageCache/Model/App/FrontController/BuiltinPlugin.php
@@ -89,8 +89,10 @@ class BuiltinPlugin
      */
     protected function addDebugHeaders(ResponseHttp $result)
     {
-        $cacheControl = $result->getHeader('Cache-Control')->getFieldValue();
-        $this->addDebugHeader($result, 'X-Magento-Cache-Control', $cacheControl);
+        $cacheControlHeader = $result->getHeader('Cache-Control');
+        if ($cacheControlHeader instanceof \Zend\Http\Header\HeaderInterface) {
+            $this->addDebugHeader($result, 'X-Magento-Cache-Control', $cacheControlHeader->getFieldValue());
+        }
         $this->addDebugHeader($result, 'X-Magento-Cache-Debug', 'MISS', true);
         return $result;
     }
diff --git a/app/code/Magento/PageCache/Model/Cache/Server.php b/app/code/Magento/PageCache/Model/Cache/Server.php
index 2e2f3a87fb8c07a7eb33c9b61f4ef421992e6c49..797249c98cb09e61b2e14e955116d6c84f1cf83a 100644
--- a/app/code/Magento/PageCache/Model/Cache/Server.php
+++ b/app/code/Magento/PageCache/Model/Cache/Server.php
@@ -5,16 +5,17 @@
  */
 namespace Magento\PageCache\Model\Cache;
 
-use Zend\Uri\Uri;
+use Magento\Framework\UrlInterface;
 use Magento\Framework\App\DeploymentConfig;
 use Magento\Framework\Config\ConfigOptionsListConstants;
 use Magento\Framework\App\RequestInterface;
+use Zend\Uri\Uri;
 use Zend\Uri\UriFactory;
 
 class Server
 {
     /**
-     * @var \Magento\Framework\UrlInterface
+     * @var UrlInterface
      */
     protected $urlBuilder;
 
@@ -33,12 +34,12 @@ class Server
     /**
      * Constructor
      *
-     * @param \Magento\Framework\UrlInterface $urlBuilder
+     * @param UrlInterface $urlBuilder
      * @param DeploymentConfig $config
      * @param RequestInterface $request
      */
     public function __construct(
-        \Magento\Framework\UrlInterface $urlBuilder,
+        UrlInterface $urlBuilder,
         DeploymentConfig $config,
         RequestInterface $request
     ) {
@@ -56,21 +57,24 @@ class Server
     {
         $servers = [];
         $configuredHosts = $this->config->get(ConfigOptionsListConstants::CONFIG_PATH_CACHE_HOSTS);
-        if (null == $configuredHosts) {
-            $httpHost = $this->request->getHttpHost();
-            $servers[] = $httpHost ?
-                UriFactory::factory('')->setHost($httpHost)->setPort(self::DEFAULT_PORT)->setScheme('http') :
-                UriFactory::factory($this->urlBuilder->getUrl('*', ['_nosid' => true])) // Don't use SID in building URL
-                    ->setScheme('http')
-                    ->setPath(null)
-                    ->setQuery(null);
 
-        } else {
+        if (is_array($configuredHosts)) {
             foreach ($configuredHosts as $host) {
-                $servers[] = UriFactory::factory('')->setHost($host['host'])
+                $servers[] = UriFactory::factory('')
+                    ->setHost($host['host'])
                     ->setPort(isset($host['port']) ? $host['port'] : self::DEFAULT_PORT)
-                    ->setScheme('http');
+                ;
             }
+        } elseif ($this->request->getHttpHost()) {
+            $servers[] = UriFactory::factory('')->setHost($this->request->getHttpHost())->setPort(self::DEFAULT_PORT);
+        } else {
+            $servers[] = UriFactory::factory($this->urlBuilder->getUrl('*', ['_nosid' => true]));
+        }
+
+        foreach (array_keys($servers) as $key) {
+            $servers[$key]->setScheme('http')
+                ->setPath('/')
+                ->setQuery(null);
         }
         return $servers;
     }
diff --git a/app/code/Magento/PageCache/Model/Controller/Result/BuiltinPlugin.php b/app/code/Magento/PageCache/Model/Controller/Result/BuiltinPlugin.php
index 022824faafbd41faf61b1539f2939ee0ba0277bd..f72a0e3bc46b3a2b13ee869df164d29c439e47bd 100644
--- a/app/code/Magento/PageCache/Model/Controller/Result/BuiltinPlugin.php
+++ b/app/code/Magento/PageCache/Model/Controller/Result/BuiltinPlugin.php
@@ -73,8 +73,10 @@ class BuiltinPlugin
         }
 
         if ($this->state->getMode() == \Magento\Framework\App\State::MODE_DEVELOPER) {
-            $cacheControl = $response->getHeader('Cache-Control')->getFieldValue();
-            $response->setHeader('X-Magento-Cache-Control', $cacheControl);
+            $cacheControlHeader = $response->getHeader('Cache-Control');
+            if ($cacheControlHeader instanceof \Zend\Http\Header\HeaderInterface) {
+                $response->setHeader('X-Magento-Cache-Control', $cacheControlHeader->getFieldValue());
+            }
             $response->setHeader('X-Magento-Cache-Debug', 'MISS', true);
         }
 
diff --git a/app/code/Magento/PageCache/Observer/FlushAllCache.php b/app/code/Magento/PageCache/Observer/FlushAllCache.php
index a704c5e116bcb9df49849baf615f8671f61f0f3b..712cc51005569a953646ba69810f05e42a63e3d7 100644
--- a/app/code/Magento/PageCache/Observer/FlushAllCache.php
+++ b/app/code/Magento/PageCache/Observer/FlushAllCache.php
@@ -6,12 +6,15 @@
  */
 namespace Magento\PageCache\Observer;
 
+use Magento\Framework\App\ObjectManager;
 use Magento\Framework\Event\ObserverInterface;
 
 class FlushAllCache implements ObserverInterface
 {
     /**
      * @var \Magento\Framework\App\PageCache\Cache
+     *
+     * @deprecated
      */
     protected $_cache;
 
@@ -22,6 +25,11 @@ class FlushAllCache implements ObserverInterface
      */
     protected $_config;
 
+    /**
+     * @var \Magento\PageCache\Model\Cache\Type
+     */
+    private $fullPageCache;
+
     /**
      * @param \Magento\PageCache\Model\Config $config
      * @param \Magento\Framework\App\PageCache\Cache $cache
@@ -41,7 +49,20 @@ class FlushAllCache implements ObserverInterface
     public function execute(\Magento\Framework\Event\Observer $observer)
     {
         if ($this->_config->getType() == \Magento\PageCache\Model\Config::BUILT_IN) {
-            $this->_cache->clean();
+            $this->getCache()->clean();
+        }
+    }
+
+    /**
+     * TODO: Workaround to support backwards compatibility, will rework to use Dependency Injection in MAGETWO-49547
+     *
+     * @return \Magento\PageCache\Model\Cache\Type
+     */
+    private function getCache()
+    {
+        if (!$this->fullPageCache) {
+            $this->fullPageCache = ObjectManager::getInstance()->get('\Magento\PageCache\Model\Cache\Type');
         }
+        return $this->fullPageCache;
     }
 }
diff --git a/app/code/Magento/PageCache/Observer/FlushCacheByTags.php b/app/code/Magento/PageCache/Observer/FlushCacheByTags.php
index c77cacb77cce35648dab065025d9d147a93d9721..116162c5047b5491a424b55e9125b2ed99e21434 100644
--- a/app/code/Magento/PageCache/Observer/FlushCacheByTags.php
+++ b/app/code/Magento/PageCache/Observer/FlushCacheByTags.php
@@ -6,12 +6,15 @@
  */
 namespace Magento\PageCache\Observer;
 
+use Magento\Framework\App\ObjectManager;
 use Magento\Framework\Event\ObserverInterface;
 
 class FlushCacheByTags implements ObserverInterface
 {
     /**
      * @var \Magento\Framework\App\PageCache\Cache
+     *
+     * @deprecated
      */
     protected $_cache;
 
@@ -22,6 +25,11 @@ class FlushCacheByTags implements ObserverInterface
      */
     protected $_config;
 
+    /**
+     * @var \Magento\PageCache\Model\Cache\Type
+     */
+    private $fullPageCache;
+
     /**
      * @param \Magento\PageCache\Model\Config $config
      * @param \Magento\Framework\App\PageCache\Cache $cache
@@ -49,9 +57,22 @@ class FlushCacheByTags implements ObserverInterface
                     $tags[] = preg_replace("~_\\d+$~", '', $tag);
                 }
                 if (!empty($tags)) {
-                    $this->_cache->clean(array_unique($tags));
+                    $this->getCache()->clean(\Zend_Cache::CLEANING_MODE_ALL, array_unique($tags));
                 }
             }
         }
     }
+
+    /**
+     * TODO: Workaround to support backwards compatibility, will rework to use Dependency Injection in MAGETWO-49547
+     *
+     * @return \Magento\PageCache\Model\Cache\Type
+     */
+    private function getCache()
+    {
+        if (!$this->fullPageCache) {
+            $this->fullPageCache = ObjectManager::getInstance()->get('\Magento\PageCache\Model\Cache\Type');
+        }
+        return $this->fullPageCache;
+    }
 }
diff --git a/app/code/Magento/PageCache/Test/Unit/Model/Cache/ServerTest.php b/app/code/Magento/PageCache/Test/Unit/Model/Cache/ServerTest.php
index f18c5e04468da59169ae6b3b5642d428b7113667..82d6a10598fa7f193138fa0b352f100fbf6f75ac 100644
--- a/app/code/Magento/PageCache/Test/Unit/Model/Cache/ServerTest.php
+++ b/app/code/Magento/PageCache/Test/Unit/Model/Cache/ServerTest.php
@@ -5,11 +5,13 @@
  */
 namespace Magento\PageCache\Test\Unit\Model\Cache;
 
+use \Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
+use \Magento\PageCache\Model\Cache\Server;
 use \Zend\Uri\UriFactory;
 
 class ServerTest extends \PHPUnit_Framework_TestCase
 {
-    /** @var \Magento\PageCache\Model\Cache\Server */
+    /** @var Server */
     protected $model;
 
     /** @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Framework\App\DeploymentConfig */
@@ -30,7 +32,7 @@ class ServerTest extends \PHPUnit_Framework_TestCase
             ->disableOriginalConstructor()
             ->getMock();
 
-        $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
+        $objectManager = new ObjectManager($this);
         $this->model = $objectManager->getObject(
             'Magento\PageCache\Model\Cache\Server',
             [
@@ -56,12 +58,9 @@ class ServerTest extends \PHPUnit_Framework_TestCase
         $url,
         $hostConfig = null
     ) {
-        $this->configMock->expects($this->once())
-            ->method('get')
-            ->willReturn($hostConfig);
-        $this->requestMock->expects($this->exactly($getHttpHostCallCtr))
-            ->method('getHttpHost')
-            ->willReturn($httpHost);
+        $this->configMock->expects($this->once())->method('get')->willReturn($hostConfig);
+        $this->requestMock->expects($this->exactly($getHttpHostCallCtr))->method('getHttpHost')->willReturn($httpHost);
+
         $this->urlBuilderMock->expects($this->exactly($getUrlCallCtr))
             ->method('getUrl')
             ->with('*', ['_nosid' => true])
@@ -70,30 +69,32 @@ class ServerTest extends \PHPUnit_Framework_TestCase
         $uris = [];
         if (null === $hostConfig) {
             if (!empty($httpHost)) {
-                $uris[] = UriFactory::factory('')->setHost($httpHost)
-                    ->setPort(\Magento\PageCache\Model\Cache\Server::DEFAULT_PORT)
-                    ->setScheme('http');
+                $uris[] = UriFactory::factory('')->setHost($httpHost)->setPort(Server::DEFAULT_PORT);
             }
             if (!empty($url)) {
                 $uris[] = UriFactory::factory($url);
             }
         } else {
             foreach ($hostConfig as $host) {
-                $port = isset($host['port']) ? $host['port'] : \Magento\PageCache\Model\Cache\Server::DEFAULT_PORT;
-                $uris[] = UriFactory::factory('')->setHost($host['host'])
-                    ->setPort($port)
-                    ->setScheme('http');
+                $port = isset($host['port']) ? $host['port'] : Server::DEFAULT_PORT;
+                $uris[] = UriFactory::factory('')->setHost($host['host'])->setPort($port);
             }
         }
 
+        foreach (array_keys($uris) as $key) {
+            $uris[$key]->setScheme('http')
+                ->setPath('/')
+                ->setQuery(null);
+        }
+
         $this->assertEquals($uris, $this->model->getUris());
     }
 
     public function getUrisDataProvider()
     {
         return [
-            'http host' => [1, '127.0.0.1', 0, '',],
-            'url' => [1, '', 1, 'http://host',],
+            'http host' => [2, '127.0.0.1', 0, ''],
+            'url' => [1, '', 1, 'http://host'],
             'config' => [
                 0,
                 '',
diff --git a/app/code/Magento/PageCache/Test/Unit/Observer/FlushAllCacheTest.php b/app/code/Magento/PageCache/Test/Unit/Observer/FlushAllCacheTest.php
index 1ea42d6e592be247a64e22456962f030762a627f..20706ef5b790b42db45fcae76b5bcb5e728d01fe 100644
--- a/app/code/Magento/PageCache/Test/Unit/Observer/FlushAllCacheTest.php
+++ b/app/code/Magento/PageCache/Test/Unit/Observer/FlushAllCacheTest.php
@@ -12,18 +12,19 @@ namespace Magento\PageCache\Test\Unit\Observer;
 class FlushAllCacheTest extends \PHPUnit_Framework_TestCase
 {
     /** @var \Magento\PageCache\Observer\FlushAllCache */
-    protected $_model;
+    private $_model;
 
     /** @var \PHPUnit_Framework_MockObject_MockObject|\Magento\PageCache\Model\Config */
-    protected $_configMock;
+    private $_configMock;
 
     /** @var  \PHPUnit_Framework_MockObject_MockObject|\Magento\Framework\App\PageCache\Cache */
-    protected $_cacheMock;
+    private $_cacheMock;
 
-    /**
-     * @var \Magento\Framework\Event\Observer|\PHPUnit_Framework_MockObject_MockObject|
-     */
-    protected $observerMock;
+    /** @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Framework\Event\Observer */
+    private $observerMock;
+
+    /** @var  \PHPUnit_Framework_MockObject_MockObject|\Magento\PageCache\Model\Cache\Type */
+    private $fullPageCacheMock;
 
     /**
      * Set up all mocks and data for test
@@ -38,13 +39,18 @@ class FlushAllCacheTest extends \PHPUnit_Framework_TestCase
             false
         );
         $this->_cacheMock = $this->getMock('Magento\Framework\App\PageCache\Cache', ['clean'], [], '', false);
-
+        $this->fullPageCacheMock = $this->getMock('\Magento\PageCache\Model\Cache\Type', ['clean'], [], '', false);
         $this->observerMock = $this->getMock('Magento\Framework\Event\Observer');
 
         $this->_model = new \Magento\PageCache\Observer\FlushAllCache(
             $this->_configMock,
             $this->_cacheMock
         );
+
+        $reflection = new \ReflectionClass('\Magento\PageCache\Observer\FlushAllCache');
+        $reflectionProperty = $reflection->getProperty('fullPageCache');
+        $reflectionProperty->setAccessible(true);
+        $reflectionProperty->setValue($this->_model, $this->fullPageCacheMock);
     }
 
     /**
@@ -60,7 +66,7 @@ class FlushAllCacheTest extends \PHPUnit_Framework_TestCase
                 $this->returnValue(\Magento\PageCache\Model\Config::BUILT_IN)
             );
 
-        $this->_cacheMock->expects($this->once())->method('clean');
+        $this->fullPageCacheMock->expects($this->once())->method('clean');
         $this->_model->execute($this->observerMock);
     }
 }
diff --git a/app/code/Magento/PageCache/Test/Unit/Observer/FlushCacheByTagsTest.php b/app/code/Magento/PageCache/Test/Unit/Observer/FlushCacheByTagsTest.php
index 4020e4c9e3f9ff5e424acfad4d437ee8ec8d7176..a34dc5543c1593cacb08d2f1dc7dc738c8c938a3 100644
--- a/app/code/Magento/PageCache/Test/Unit/Observer/FlushCacheByTagsTest.php
+++ b/app/code/Magento/PageCache/Test/Unit/Observer/FlushCacheByTagsTest.php
@@ -20,6 +20,9 @@ class FlushCacheByTagsTest extends \PHPUnit_Framework_TestCase
     /** @var  \PHPUnit_Framework_MockObject_MockObject|\Magento\Framework\App\PageCache\Cache */
     protected $_cacheMock;
 
+    /** @var  \PHPUnit_Framework_MockObject_MockObject|\Magento\PageCache\Model\Cache\Type */
+    private $fullPageCacheMock;
+
     /**
      * Set up all mocks and data for test
      */
@@ -33,11 +36,16 @@ class FlushCacheByTagsTest extends \PHPUnit_Framework_TestCase
             false
         );
         $this->_cacheMock = $this->getMock('Magento\Framework\App\PageCache\Cache', ['clean'], [], '', false);
+        $this->fullPageCacheMock = $this->getMock('\Magento\PageCache\Model\Cache\Type', ['clean'], [], '', false);
 
         $this->_model = new \Magento\PageCache\Observer\FlushCacheByTags(
             $this->_configMock,
             $this->_cacheMock
         );
+        $reflection = new \ReflectionClass('\Magento\PageCache\Observer\FlushCacheByTags');
+        $reflectionProperty = $reflection->getProperty('fullPageCache');
+        $reflectionProperty->setAccessible(true);
+        $reflectionProperty->setValue($this->_model, $this->fullPageCacheMock);
     }
 
     /**
@@ -59,16 +67,14 @@ class FlushCacheByTagsTest extends \PHPUnit_Framework_TestCase
             $eventMock = $this->getMock('Magento\Framework\Event', ['getObject'], [], '', false);
             $eventMock->expects($this->once())->method('getObject')->will($this->returnValue($observedObject));
             $observerObject->expects($this->once())->method('getEvent')->will($this->returnValue($eventMock));
-            $this->_configMock->expects(
-                $this->once()
-            )->method(
-                    'getType'
-                )->will(
-                    $this->returnValue(\Magento\PageCache\Model\Config::BUILT_IN)
-                );
+            $this->_configMock->expects($this->once())
+                ->method('getType')
+                ->willReturn(\Magento\PageCache\Model\Config::BUILT_IN);
             $observedObject->expects($this->once())->method('getIdentities')->will($this->returnValue($tags));
 
-            $this->_cacheMock->expects($this->once())->method('clean')->with($this->equalTo($expectedTags));
+            $this->fullPageCacheMock->expects($this->once())
+                ->method('clean')
+                ->with(\Zend_Cache::CLEANING_MODE_ALL, $this->equalTo($expectedTags));
         }
 
         $this->_model->execute($observerObject);
@@ -102,7 +108,7 @@ class FlushCacheByTagsTest extends \PHPUnit_Framework_TestCase
         );
         $observedObject->expects($this->once())->method('getIdentities')->will($this->returnValue($tags));
 
-        $this->_cacheMock->expects($this->never())->method('clean');
+        $this->fullPageCacheMock->expects($this->never())->method('clean');
 
         $this->_model->execute($observerObject);
     }
diff --git a/app/code/Magento/Paypal/Block/Adminhtml/System/Config/Field/Hidden.php b/app/code/Magento/Paypal/Block/Adminhtml/System/Config/Field/Hidden.php
index 1a5e6618d3f36a3138208d1faca614d57e43ec92..d8a23f08db80e15b9cf7770e47d1391972aec1e4 100644
--- a/app/code/Magento/Paypal/Block/Adminhtml/System/Config/Field/Hidden.php
+++ b/app/code/Magento/Paypal/Block/Adminhtml/System/Config/Field/Hidden.php
@@ -18,7 +18,7 @@ class Hidden extends \Magento\Config\Block\System\Config\Form\Field
      * @param string $html
      * @return string
      */
-    protected function _decorateRowHtml($element, $html)
+    protected function _decorateRowHtml(\Magento\Framework\Data\Form\Element\AbstractElement $element, $html)
     {
         return '<tr id="row_' . $element->getHtmlId() . '" style="display: none;">' . $html . '</tr>';
     }
diff --git a/app/code/Magento/Paypal/view/frontend/web/js/in-context/express-checkout.js b/app/code/Magento/Paypal/view/frontend/web/js/in-context/express-checkout.js
index 704b9ad3ea55fbc5a3c870ad6cd7828fddf5ecb2..36a145b3c8d3cdf5879dfa3125cae43e672e95a3 100644
--- a/app/code/Magento/Paypal/view/frontend/web/js/in-context/express-checkout.js
+++ b/app/code/Magento/Paypal/view/frontend/web/js/in-context/express-checkout.js
@@ -8,13 +8,15 @@ define(
         'jquery',
         'uiComponent',
         'paypalInContextExpressCheckout',
+        'Magento_Customer/js/customer-data',
         'domReady!'
     ],
     function (
         _,
         $,
         Component,
-        paypalExpressCheckout
+        paypalExpressCheckout,
+        customerData
     ) {
         'use strict';
 
@@ -53,6 +55,7 @@ define(
                         ).always(
                             function () {
                                 $('body').trigger('processStop');
+                                customerData.invalidate(['cart']);
                             }
                         );
                     }
diff --git a/app/code/Magento/Paypal/view/frontend/web/js/view/payment/method-renderer/in-context/checkout-express.js b/app/code/Magento/Paypal/view/frontend/web/js/view/payment/method-renderer/in-context/checkout-express.js
index 0f8fa4f69f20f23893d4a18aeb0711a7f0698323..64b40c4563f69154a79c737f138db688500323f5 100644
--- a/app/code/Magento/Paypal/view/frontend/web/js/view/payment/method-renderer/in-context/checkout-express.js
+++ b/app/code/Magento/Paypal/view/frontend/web/js/view/payment/method-renderer/in-context/checkout-express.js
@@ -10,7 +10,8 @@ define(
         'Magento_Paypal/js/action/set-payment-method',
         'Magento_Checkout/js/model/payment/additional-validators',
         'Magento_Ui/js/lib/view/utils/dom-observer',
-        'paypalInContextExpressCheckout'
+        'paypalInContextExpressCheckout',
+        'Magento_Customer/js/customer-data'
     ],
     function (
         _,
@@ -19,7 +20,8 @@ define(
         setPaymentMethodAction,
         additionalValidators,
         domObserver,
-        paypalExpressCheckout
+        paypalExpressCheckout,
+        customerData
     ) {
         'use strict';
 
@@ -65,6 +67,7 @@ define(
                                     ).always(
                                         function () {
                                             $('body').trigger('processStop');
+                                            customerData.invalidate(['cart']);
                                         }
                                     );
 
diff --git a/app/code/Magento/Paypal/view/frontend/web/js/view/payment/method-renderer/paypal-express-abstract.js b/app/code/Magento/Paypal/view/frontend/web/js/view/payment/method-renderer/paypal-express-abstract.js
index 3abc932c15a86296486483dac932f3f039a00f94..f58b777b54a519da7e771f7e72c21c5a157e69be 100644
--- a/app/code/Magento/Paypal/view/frontend/web/js/view/payment/method-renderer/paypal-express-abstract.js
+++ b/app/code/Magento/Paypal/view/frontend/web/js/view/payment/method-renderer/paypal-express-abstract.js
@@ -10,14 +10,16 @@ define(
         'Magento_Checkout/js/view/payment/default',
         'Magento_Paypal/js/action/set-payment-method',
         'Magento_Checkout/js/model/payment/additional-validators',
-        'Magento_Checkout/js/model/quote'
+        'Magento_Checkout/js/model/quote',
+        'Magento_Customer/js/customer-data'
     ],
     function (
         $,
         Component,
         setPaymentMethodAction,
         additionalValidators,
-        quote
+        quote,
+        customerData
     ) {
         'use strict';
 
@@ -31,11 +33,12 @@ define(
             initObservable: function () {
                 this._super()
                     .observe('billingAgreement');
+
                 return this;
             },
 
             /** Open window with  */
-            showAcceptanceWindow: function(data, event) {
+            showAcceptanceWindow: function (data, event) {
                 window.open(
                     $(event.target).attr('href'),
                     'olcwhatispaypal',
@@ -45,26 +48,27 @@ define(
                     ' resizable=yes, ,left=0,' +
                     ' top=0, width=400, height=350'
                 );
+
                 return false;
             },
 
             /** Returns payment acceptance mark link path */
-            getPaymentAcceptanceMarkHref: function() {
+            getPaymentAcceptanceMarkHref: function () {
                 return window.checkoutConfig.payment.paypalExpress.paymentAcceptanceMarkHref;
             },
 
             /** Returns payment acceptance mark image path */
-            getPaymentAcceptanceMarkSrc: function() {
+            getPaymentAcceptanceMarkSrc: function () {
                 return window.checkoutConfig.payment.paypalExpress.paymentAcceptanceMarkSrc;
             },
 
             /** Returns billing agreement data */
-            getBillingAgreementCode: function() {
+            getBillingAgreementCode: function () {
                 return window.checkoutConfig.payment.paypalExpress.billingAgreementCode[this.item.method];
             },
 
             /** Returns payment information data */
-            getData: function() {
+            getData: function () {
                 var parent = this._super(),
                     additionalData = null;
 
@@ -72,7 +76,10 @@ define(
                     additionalData = {};
                     additionalData[this.getBillingAgreementCode()] = this.billingAgreement();
                 }
-                return $.extend(true, parent, {'additional_data': additionalData});
+
+                return $.extend(true, parent, {
+                    'additional_data': additionalData
+                });
             },
 
             /** Redirect to paypal */
@@ -82,11 +89,13 @@ define(
                     this.selectPaymentMethod();
                     setPaymentMethodAction(this.messageContainer).done(
                         function () {
+                            customerData.invalidate(['cart']);
                             $.mage.redirect(
                                 window.checkoutConfig.payment.paypalExpress.redirectUrl[quote.paymentMethod().method]
                             );
                         }
                     );
+
                     return false;
                 }
             }
diff --git a/app/code/Magento/Quote/Model/Quote/Address.php b/app/code/Magento/Quote/Model/Quote/Address.php
index 28909676328a0f41a45346b9d6b8819cda68912c..c748755052ca8f0d4a6ec1bd8e52ceceafaa3dda 100644
--- a/app/code/Magento/Quote/Model/Quote/Address.php
+++ b/app/code/Magento/Quote/Model/Quote/Address.php
@@ -1009,13 +1009,14 @@ class Address extends \Magento\Customer\Model\Address\AbstractAddress implements
                     if ($item) {
                         $item->setBaseShippingAmount($rate->getPrice());
                     } else {
-                        /**
-                         * possible bug: this should be setBaseShippingAmount(),
-                         * see \Magento\Quote\Model\Quote\Address\Total\Shipping::collect()
-                         * where this value is set again from the current specified rate price
-                         * (looks like a workaround for this bug)
-                         */
-                        $this->setShippingAmount($rate->getPrice());
+
+                        /** @var \Magento\Quote\Model\Quote $quote */
+                        $quote = $this->getQuote();
+                        $amountPrice = $quote->getStore()
+                            ->getBaseCurrency()
+                            ->convert($rate->getPrice(), $quote->getQuoteCurrencyCode());
+                        $this->setBaseShippingAmount($rate->getPrice());
+                        $this->setShippingAmount($amountPrice);
                     }
 
                     $found = true;
@@ -1027,6 +1028,7 @@ class Address extends \Magento\Customer\Model\Address\AbstractAddress implements
     }
 
     /******************************* Total Collector Interface *******************************************/
+
     /**
      * Get address totals as array
      *
@@ -1301,6 +1303,7 @@ class Address extends \Magento\Customer\Model\Address\AbstractAddress implements
     }
 
     //@codeCoverageIgnoreStart
+
     /**
      * Get all total amount values
      *
diff --git a/app/code/Magento/Reports/Block/Adminhtml/Sales/Grid/Column/Renderer/Date.php b/app/code/Magento/Reports/Block/Adminhtml/Sales/Grid/Column/Renderer/Date.php
index 7ffe3a73a943da66043c958b92be6f53c1cb1b3a..e763d77f3b4803d153911af7aacf372eed6d0965 100644
--- a/app/code/Magento/Reports/Block/Adminhtml/Sales/Grid/Column/Renderer/Date.php
+++ b/app/code/Magento/Reports/Block/Adminhtml/Sales/Grid/Column/Renderer/Date.php
@@ -13,6 +13,12 @@ use Magento\Framework\Stdlib\DateTime\DateTimeFormatterInterface;
  */
 class Date extends \Magento\Backend\Block\Widget\Grid\Column\Renderer\Date
 {
+
+    /**
+     * @var \Magento\Framework\Locale\ResolverInterface
+     */
+    private $localeResolver;
+
     /**
      * Constructor
      *
@@ -28,7 +34,7 @@ class Date extends \Magento\Backend\Block\Widget\Grid\Column\Renderer\Date
         array $data = []
     ) {
         parent::__construct($context, $dateTimeFormatter, $data);
-        $this->_localeResolver = $localeResolver;
+        $this->localeResolver = $localeResolver;
     }
 
     /**
@@ -41,7 +47,7 @@ class Date extends \Magento\Backend\Block\Widget\Grid\Column\Renderer\Date
         $format = $this->getColumn()->getFormat();
         if (!$format) {
             $dataBundle = new DataBundle();
-            $resourceBundle = $dataBundle->get($this->_localeResolver->getLocale());
+            $resourceBundle = $dataBundle->get($this->localeResolver->getLocale());
             $formats = $resourceBundle['calendar']['gregorian']['availableFormats'];
             switch ($this->getColumn()->getPeriodType()) {
                 case 'month':
@@ -81,7 +87,7 @@ class Date extends \Magento\Backend\Block\Widget\Grid\Column\Renderer\Date
             } else {
                 $date = $this->_localeDate->date(new \DateTime($data), null, false);
             }
-            return $this->dateTimeFormatter->formatObject($date, $format, $this->_localeResolver->getLocale());
+            return $this->dateTimeFormatter->formatObject($date, $format, $this->localeResolver->getLocale());
         }
         return $this->getColumn()->getDefault();
     }
diff --git a/app/code/Magento/Review/view/frontend/web/js/process-reviews.js b/app/code/Magento/Review/view/frontend/web/js/process-reviews.js
index 19e25f16a442f352dbb3df185ee39511d8f5d08e..b55d20968db6923bab8e796e60d3b17b486420b8 100644
--- a/app/code/Magento/Review/view/frontend/web/js/process-reviews.js
+++ b/app/code/Magento/Review/view/frontend/web/js/process-reviews.js
@@ -10,6 +10,7 @@ define([
     function processReviews(url, fromPages) {
         $.ajax({
             url: url,
+            cache: true,
             dataType: 'html'
         }).done(function (data) {
             $('#product-review-container').html(data);
diff --git a/app/code/Magento/Sales/Block/Adminhtml/Order/View/Items.php b/app/code/Magento/Sales/Block/Adminhtml/Order/View/Items.php
index 326fb104bbb2c242679fccb91bcbc16fe0ef515e..0f84c6a4f0205bd9c41b58e86f81561e41b2183e 100644
--- a/app/code/Magento/Sales/Block/Adminhtml/Order/View/Items.php
+++ b/app/code/Magento/Sales/Block/Adminhtml/Order/View/Items.php
@@ -12,6 +12,15 @@ use Magento\Sales\Model\ResourceModel\Order\Item\Collection;
  */
 class Items extends \Magento\Sales\Block\Adminhtml\Items\AbstractItems
 {
+    /**
+     * @return array
+     */
+    public function getColumns()
+    {
+        $columns = array_key_exists('columns', $this->_data) ? $this->_data['columns'] : [];
+        return $columns;
+    }
+
     /**
      * Retrieve required options from parent
      *
diff --git a/app/code/Magento/Sales/Block/Adminhtml/Order/View/Items/Renderer/DefaultRenderer.php b/app/code/Magento/Sales/Block/Adminhtml/Order/View/Items/Renderer/DefaultRenderer.php
index 30f059d0dbfe3c4e390469e9a7a4499e65feaa00..c22d0e7b55fbb691a5852203be5e78af703cb676 100644
--- a/app/code/Magento/Sales/Block/Adminhtml/Order/View/Items/Renderer/DefaultRenderer.php
+++ b/app/code/Magento/Sales/Block/Adminhtml/Order/View/Items/Renderer/DefaultRenderer.php
@@ -254,4 +254,57 @@ class DefaultRenderer extends \Magento\Sales\Block\Adminhtml\Items\Renderer\Defa
             $this->_checkoutHelper->getPriceInclTax($item)
         );
     }
+
+    /**
+     * @param \Magento\Framework\DataObject|Item $item
+     * @param string $column
+     * @param null $field
+     * @return string
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
+     */
+    public function getColumnHtml(\Magento\Framework\DataObject $item, $column, $field = null)
+    {
+        $html = '';
+        switch ($column) {
+            case 'product':
+                if ($this->canDisplayContainer()) {
+                    $html .= '<div id="' . $this->getHtmlId() . '">';
+                }
+                $html .= $this->getColumnHtml($item, 'name');
+                if ($this->canDisplayContainer()) {
+                    $html .= '</div>';
+                }
+                break;
+            case 'status':
+                $html = $item->getStatus();
+                break;
+            case 'price-original':
+                $html = $this->displayPriceAttribute('original_price');
+                break;
+            case 'price':
+                $html = $this->displayPriceAttribute('price');
+                break;
+            case 'tax-amount':
+                $html = $this->displayPriceAttribute('tax_amount');
+                break;
+            case 'tax-percent':
+                $html = $this->displayTaxPercent($item);
+                break;
+            case 'discont':
+                $html = $this->displayPriceAttribute('discount_amount');
+                break;
+            default:
+                $html = parent::getColumnHtml($item, $column, $field);
+        }
+        return $html;
+    }
+
+    /**
+     * @return array
+     */
+    public function getColumns()
+    {
+        $columns = array_key_exists('columns', $this->_data) ? $this->_data['columns'] : [];
+        return $columns;
+    }
 }
diff --git a/app/code/Magento/Sales/Model/Order/Email/Sender/OrderSender.php b/app/code/Magento/Sales/Model/Order/Email/Sender/OrderSender.php
index d32aed76cb78b0efb7f17bfd5898317dec6cddda..8c0a31d790c966af5a8af7db35d699b8eb3d054e 100644
--- a/app/code/Magento/Sales/Model/Order/Email/Sender/OrderSender.php
+++ b/app/code/Magento/Sales/Model/Order/Email/Sender/OrderSender.php
@@ -127,13 +127,14 @@ class OrderSender extends Sender
             'formattedShippingAddress' => $this->getFormattedShippingAddress($order),
             'formattedBillingAddress' => $this->getFormattedBillingAddress($order),
         ];
+        $transport = new \Magento\Framework\DataObject($transport);
 
         $this->eventManager->dispatch(
             'email_order_set_template_vars_before',
             ['sender' => $this, 'transport' => $transport]
         );
 
-        $this->templateContainer->setTemplateVars($transport);
+        $this->templateContainer->setTemplateVars($transport->getData());
 
         parent::prepareTemplate($order);
     }
diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_view.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_view.xml
index 10915f10d9355c4da3401dcab6fc330fe71b76dd..4e98f3b893d90505e4531409744c89e4d914e46b 100644
--- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_view.xml
+++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_view.xml
@@ -24,7 +24,36 @@
                     <block class="Magento\Sales\Block\Adminhtml\Order\View\Messages" name="order_messages"/>
                     <block class="Magento\Sales\Block\Adminhtml\Order\View\Info" name="order_info" template="order/view/info.phtml"/>
                     <block class="Magento\Sales\Block\Adminhtml\Order\View\Items" name="order_items" template="order/view/items.phtml">
-                        <block class="Magento\Sales\Block\Adminhtml\Order\View\Items\Renderer\DefaultRenderer" as="default" template="order/view/items/renderer/default.phtml"/>
+                        <arguments>
+                            <argument name="columns" xsi:type="array">
+                                <item name="product" xsi:type="string" translate="true">Product</item>
+                                <item name="status" xsi:type="string" translate="true">Item Status</item>
+                                <item name="price-original" xsi:type="string" translate="true">Original Price</item>
+                                <item name="price" xsi:type="string" translate="true">Price</item>
+                                <item name="ordered-qty" xsi:type="string" translate="true">Qty</item>
+                                <item name="subtotal" xsi:type="string" translate="true">Subtotal</item>
+                                <item name="tax-amount" xsi:type="string" translate="true">Tax Amount</item>
+                                <item name="tax-percent" xsi:type="string" translate="true">Tax Percent</item>
+                                <item name="discont" xsi:type="string" translate="true">Discount Amount</item>
+                                <item name="total" xsi:type="string" translate="true">Row Total</item>
+                            </argument>
+                        </arguments>
+                        <block class="Magento\Sales\Block\Adminhtml\Order\View\Items\Renderer\DefaultRenderer" as="default" template="order/view/items/renderer/default.phtml">
+                        <arguments>
+                            <argument name="columns" xsi:type="array">
+                                <item name="product" xsi:type="string" translate="false">col-product</item>
+                                <item name="status" xsi:type="string" translate="false">col-status</item>
+                                <item name="price-original" xsi:type="string" translate="false">col-price-original</item>
+                                <item name="price" xsi:type="string" translate="false">col-price</item>
+                                <item name="qty" xsi:type="string" translate="false">col-ordered-qty</item>
+                                <item name="subtotal" xsi:type="string" translate="false">col-subtotal</item>
+                                <item name="tax-amount" xsi:type="string" translate="false">col-tax-amount</item>
+                                <item name="tax-percent" xsi:type="string" translate="false">col-tax-percent</item>
+                                <item name="discont" xsi:type="string" translate="false">col-discont</item>
+                                <item name="total" xsi:type="string" translate="false">col-total</item>
+                            </argument>
+                        </arguments>
+                        </block>
                         <block class="Magento\Sales\Block\Adminhtml\Items\Column\Qty" name="column_qty" template="items/column/qty.phtml" group="column"/>
                         <block class="Magento\Sales\Block\Adminhtml\Items\Column\Name" name="column_name" template="items/column/name.phtml" group="column"/>
                         <block class="Magento\Framework\View\Element\Text\ListText" name="order_item_extra_info"/>
diff --git a/app/code/Magento/Sales/view/adminhtml/templates/order/view/items.phtml b/app/code/Magento/Sales/view/adminhtml/templates/order/view/items.phtml
index 879872ee9271a7bcb883f5ff2b84c5687fe8a5e5..41cb768997bfba9ff1532c50bdf32cefa7f5d864 100644
--- a/app/code/Magento/Sales/view/adminhtml/templates/order/view/items.phtml
+++ b/app/code/Magento/Sales/view/adminhtml/templates/order/view/items.phtml
@@ -5,23 +5,23 @@
  */
 
 // @codingStandardsIgnoreFile
-
 ?>
-<?php $_order = $block->getOrder() ?>
+<?php
+/**
+ * @var \Magento\Sales\Block\Adminhtml\Order\View\Items $block
+ */
+$_order = $block->getOrder() ?>
 <div class="admin__table-wrapper">
     <table class="data-table admin__table-primary edit-order-table">
         <thead>
             <tr class="headings">
-                <th class="col-product"><span><?php /* @escapeNotVerified */ echo __('Product') ?></span></th>
-                <th class="col-status"><span><?php /* @escapeNotVerified */ echo __('Item Status') ?></span></th>
-                <th class="col-price-original"><span><?php /* @escapeNotVerified */ echo __('Original Price') ?></span></th>
-                <th class="col-price"><span><?php /* @escapeNotVerified */ echo __('Price') ?></span></th>
-                <th class="col-ordered-qty"><span><?php /* @escapeNotVerified */ echo __('Qty') ?></span></th>
-                <th class="col-subtotal"><span><?php /* @escapeNotVerified */ echo __('Subtotal') ?></span></th>
-                <th class="col-tax-amount"><span><?php /* @escapeNotVerified */ echo __('Tax Amount') ?></span></th>
-                <th class="col-tax-percent"><span><?php /* @escapeNotVerified */ echo __('Tax Percent') ?></span></th>
-                <th class="col-discont"><span><?php /* @escapeNotVerified */ echo __('Discount Amount') ?></span></th>
-                <th class="col-total last"><span><?php /* @escapeNotVerified */ echo __('Row Total') ?></span></th>
+                <?php $i = 0;
+                $columns = $block->getColumns();
+                $lastItemNumber = count($columns) ?>
+                <?php foreach ($columns as $columnName => $columnTitle):?>
+                    <?php $i++; ?>
+                    <th class="col-<?php /* @noEscape */ echo $columnName ?><?php /* @noEscape */ echo ($i === $lastItemNumber ? ' last' : '')?>"><span><?php /* @noEscape */ echo $columnTitle ?></span></th>
+                <?php endforeach; ?>
             </tr>
         </thead>
         <?php $_items = $block->getItemsCollection();?>
@@ -31,7 +31,7 @@
             } else {
                 $i++;
             }?>
-            <tbody class="<?php /* @escapeNotVerified */ echo $i%2 ? 'even' : 'odd' ?>">
+            <tbody class="<?php /* @noEscape */ echo $i%2 ? 'even' : 'odd' ?>">
                 <?php echo $block->getItemHtml($_item) ?>
                 <?php echo $block->getItemExtraInfoHtml($_item) ?>
             </tbody>
diff --git a/app/code/Magento/Sales/view/adminhtml/templates/order/view/items/renderer/default.phtml b/app/code/Magento/Sales/view/adminhtml/templates/order/view/items/renderer/default.phtml
index da3367344c439d6deabd167a801bcc80e5937fa2..aec3fc17b54125b97f86e6ee7fc78498535b4db8 100644
--- a/app/code/Magento/Sales/view/adminhtml/templates/order/view/items/renderer/default.phtml
+++ b/app/code/Magento/Sales/view/adminhtml/templates/order/view/items/renderer/default.phtml
@@ -7,33 +7,15 @@
 // @codingStandardsIgnoreFile
 
 ?>
-<?php /** @var $block \Magento\Sales\Block\Adminhtml\Order\View\Items\Renderer\DefaultRenderer */ ?>
+<?php /** @var \Magento\Sales\Block\Adminhtml\Order\View\Items\Renderer\DefaultRenderer $block */ ?>
 <?php $_item = $block->getItem() ?>
 <?php $block->setPriceDataObject($_item) ?>
 <tr>
-    <td class="col-product">
-        <?php if ($block->canDisplayContainer()): ?>
-        <div id="<?php echo $block->getHtmlId() ?>">
-        <?php endif; ?>
-        <?php echo $block->getColumnHtml($_item, 'name') ?>
-        <?php if ($block->canDisplayContainer()): ?>
-        </div>
-        <?php endif ?>
-    </td>
-    <td class="col-status"><?php /* @escapeNotVerified */ echo $_item->getStatus() ?></td>
-    <td class="col-price-original"><?php /* @escapeNotVerified */ echo $block->displayPriceAttribute('original_price') ?></td>
-    <td class="col-price">
-        <?php echo $block->getColumnHtml($_item, 'price'); ?>
-    </td>
-    <td class="col-ordered-qty"><?php echo $block->getColumnHtml($_item, 'qty') ?></td>
-
-    <td class="col-subtotal">
-        <?php echo $block->getColumnHtml($_item, 'subtotal'); ?>
-    </td>
-    <td class="col-tax-amount"><?php /* @escapeNotVerified */ echo $block->displayPriceAttribute('tax_amount') ?></td>
-    <td class="col-tax-percent"><?php /* @escapeNotVerified */ echo $block->displayTaxPercent($_item) ?></td>
-    <td class="col-discont"><?php /* @escapeNotVerified */ echo $block->displayPriceAttribute('discount_amount') ?></td>
-    <td class="col-total last">
-        <?php echo $block->getColumnHtml($_item, 'total'); ?>
-    </td>
+    <?php $i = 0;
+    $columns = $block->getColumns();
+    $lastItemNumber = count($columns) ?>
+    <?php foreach ($columns as $columnName => $columnClass):?>
+        <?php $i++; ?>
+        <td class="<?php echo /* @noEscape */ $columnClass?><?php /* @noEscape */ echo ($i === $lastItemNumber ? ' last' : '')?>"><?php /* @escapeNotVerified */ echo $block->getColumnHtml($_item, $columnName) ?></td>
+    <?php endforeach; ?>
 </tr>
diff --git a/app/code/Magento/Sales/view/frontend/email/order_new.html b/app/code/Magento/Sales/view/frontend/email/order_new.html
index 8c7bbf3302938959d1c1cb62649914e9a77b1202..5963b574830c5718c0d1adbf7632aaac53a8ff1a 100644
--- a/app/code/Magento/Sales/view/frontend/email/order_new.html
+++ b/app/code/Magento/Sales/view/frontend/email/order_new.html
@@ -13,6 +13,7 @@
 "var payment_html|raw":"Payment Details",
 "var formattedShippingAddress|raw":"Shipping Address",
 "var order.getShippingDescription()":"Shipping Description"
+"var shipping_msg":"Shipping message"
 } @-->
 
 {{template config_path="design/email/header_template"}}
@@ -73,6 +74,9 @@
                     <td class="method-info">
                         <h3>{{trans "Shipping Method"}}</h3>
                         <p>{{var order.getShippingDescription()}}</p>
+                        {{if shipping_msg}}
+                        <p>{{var shipping_msg}}</p>
+                        {{/if}}
                     </td>
                     {{/depend}}
                 </tr>
diff --git a/app/code/Magento/Sales/view/frontend/email/order_new_guest.html b/app/code/Magento/Sales/view/frontend/email/order_new_guest.html
index 42bd401c7ae6651b9214959ee53c04011f422c13..4669fc43ff077cf241512343db8cdb2a4afc8f66 100644
--- a/app/code/Magento/Sales/view/frontend/email/order_new_guest.html
+++ b/app/code/Magento/Sales/view/frontend/email/order_new_guest.html
@@ -15,6 +15,7 @@
 "var payment_html|raw":"Payment Details",
 "var formattedShippingAddress|raw":"Shipping Address",
 "var order.getShippingDescription()":"Shipping Description"
+"var shipping_msg":"Shipping message"
 } @-->
 {{template config_path="design/email/header_template"}}
 
@@ -71,6 +72,9 @@
                     <td class="method-info">
                         <h3>{{trans "Shipping Method"}}</h3>
                         <p>{{var order.getShippingDescription()}}</p>
+                        {{if shipping_msg}}
+                        <p>{{var shipping_msg}}</p>
+                        {{/if}}
                     </td>
                     {{/depend}}
                 </tr>
diff --git a/app/code/Magento/Sales/view/frontend/templates/widget/guest/form.phtml b/app/code/Magento/Sales/view/frontend/templates/widget/guest/form.phtml
index b3f1e3431f43b2055a0791ec6f40ff142b8dfbf5..0c11445d8b8f74ef80625f9c9d4aab811fb6a04e 100644
--- a/app/code/Magento/Sales/view/frontend/templates/widget/guest/form.phtml
+++ b/app/code/Magento/Sales/view/frontend/templates/widget/guest/form.phtml
@@ -52,7 +52,7 @@
                                    data-validate="{required:true, 'validate-email':true}">
                         </div>
                     </div>
-                    <div id="oar-zip" style="display: none;" class="field required">
+                    <div id="oar-zip" style="display: none;" class="field zip required">
                         <label for="oar_zip" class="label"><span><?php /* @escapeNotVerified */ echo __('Billing ZIP Code') ?></span></label>
 
                         <div class="control">
diff --git a/app/code/Magento/Security/Controller/Adminhtml/Session/Check.php b/app/code/Magento/Security/Controller/Adminhtml/Session/Check.php
index e14a2b8f7ffb51684eb4f42b8e6beec81f0029d2..bdf990f05f619119ee7e474ea5d99c2003ea818e 100644
--- a/app/code/Magento/Security/Controller/Adminhtml/Session/Check.php
+++ b/app/code/Magento/Security/Controller/Adminhtml/Session/Check.php
@@ -7,6 +7,7 @@ namespace Magento\Security\Controller\Adminhtml\Session;
 
 use Magento\Backend\App\Action\Context;
 use Magento\Framework\Controller\Result\JsonFactory;
+use Magento\Security\Helper\SecurityCookie;
 use Magento\Security\Model\AdminSessionsManager;
 
 /**
@@ -17,15 +18,14 @@ class Check extends \Magento\Backend\App\Action
     /**
      * @var JsonFactory
      */
-    protected $jsonFactory;
+    private $jsonFactory;
 
     /**
      * @var AdminSessionsManager
      */
-    protected $sessionsManager;
+    private $sessionsManager;
 
     /**
-     * Check constructor.
      * @param Context $context
      * @param JsonFactory $jsonFactory
      * @param AdminSessionsManager $sessionsManager
@@ -48,7 +48,7 @@ class Check extends \Magento\Backend\App\Action
         /** @var \Magento\Framework\Controller\Result\Json $resultJson */
         return $this->jsonFactory->create()->setData(
             [
-                'isActive' => $this->sessionsManager->getCurrentSession()->isActive()
+                'isActive' => $this->sessionsManager->getCurrentSession()->isLoggedInStatus()
             ]
         );
     }
diff --git a/app/code/Magento/Security/Model/AdminSessionInfo.php b/app/code/Magento/Security/Model/AdminSessionInfo.php
index d47ae28dc4224b38d477f2fa80517699307b70b2..87b9e3ca0f17a855eb49ffcc94a75cd363404bab 100644
--- a/app/code/Magento/Security/Model/AdminSessionInfo.php
+++ b/app/code/Magento/Security/Model/AdminSessionInfo.php
@@ -89,17 +89,20 @@ class AdminSessionInfo extends \Magento\Framework\Model\AbstractModel
      */
     public function isLoggedInStatus()
     {
+        $this->checkActivity();
         return $this->getData('status') == self::LOGGED_IN;
     }
 
     /**
-     * Check if a user is active
+     * Check if session is timed out and set status accordingly
      *
-     * @return bool
+     * @return void
      */
-    public function isActive()
+    private function checkActivity()
     {
-        return $this->isLoggedInStatus() && !$this->isSessionExpired();
+        if ($this->isSessionExpired()) {
+            $this->setData('status', self::LOGGED_OUT);
+        }
     }
 
     /**
diff --git a/app/code/Magento/Security/Model/AdminSessionsManager.php b/app/code/Magento/Security/Model/AdminSessionsManager.php
index 77c057f7a63f8d23e7440d7126e318f8b598f690..29249ee9fb350aff6d8da260c191a732457b31e6 100644
--- a/app/code/Magento/Security/Model/AdminSessionsManager.php
+++ b/app/code/Magento/Security/Model/AdminSessionsManager.php
@@ -147,7 +147,7 @@ class AdminSessionsManager
     {
         switch ((int)$statusCode) {
             case AdminSessionInfo::LOGGED_IN:
-                $reasonMessage = '';
+                $reasonMessage = null;
                 break;
             case AdminSessionInfo::LOGGED_OUT_BY_LOGIN:
                 $reasonMessage = __(
diff --git a/app/code/Magento/Security/Model/Plugin/AuthSession.php b/app/code/Magento/Security/Model/Plugin/AuthSession.php
index 1ee9aa5cc9ba0d673009918308984454e71eb91b..ea15828afc733e135bfc16f7325dad2fdac21ff2 100644
--- a/app/code/Magento/Security/Model/Plugin/AuthSession.php
+++ b/app/code/Magento/Security/Model/Plugin/AuthSession.php
@@ -7,7 +7,6 @@ namespace Magento\Security\Model\Plugin;
 
 use Magento\Backend\Model\Auth\Session;
 use Magento\Security\Model\AdminSessionsManager;
-use Magento\Framework\Stdlib\Cookie\CookieReaderInterface;
 
 /**
  * Magento\Backend\Model\Auth\Session decorator
@@ -62,7 +61,7 @@ class AuthSession
     public function aroundProlong(Session $session, \Closure $proceed)
     {
         if (!$this->isSessionCheckRequest()) {
-            if (!$this->sessionsManager->getCurrentSession()->isActive()) {
+            if (!$this->sessionsManager->getCurrentSession()->isLoggedInStatus()) {
                 $session->destroy();
                 $this->addUserLogoutNotification();
                 return null;
@@ -84,10 +83,8 @@ class AuthSession
             $this->securityCookieHelper->setLogoutReasonCookie(
                 $this->sessionsManager->getCurrentSession()->getStatus()
             );
-        } else {
-            $this->messageManager->addError(
-                $this->sessionsManager->getLogoutReasonMessage()
-            );
+        } else if ($message = $this->sessionsManager->getLogoutReasonMessage()) {
+            $this->messageManager->addError($message);
         }
 
         return $this;
diff --git a/app/code/Magento/Security/Test/Unit/Controller/Adminhtml/Session/CheckTest.php b/app/code/Magento/Security/Test/Unit/Controller/Adminhtml/Session/CheckTest.php
index 959c7e62a63c1a99f3d60472278f432429c38dcc..03bc6029a9669a7d398db75207ffcb3473853cc9 100644
--- a/app/code/Magento/Security/Test/Unit/Controller/Adminhtml/Session/CheckTest.php
+++ b/app/code/Magento/Security/Test/Unit/Controller/Adminhtml/Session/CheckTest.php
@@ -64,7 +64,7 @@ class CheckTest extends \PHPUnit_Framework_TestCase
 
         $this->currentSession =  $this->getMock(
             '\Magento\Security\Model\AdminSessionInfo',
-            ['isActive'],
+            ['isLoggedInStatus'],
             [],
             '',
             false
@@ -92,7 +92,7 @@ class CheckTest extends \PHPUnit_Framework_TestCase
             ->disableOriginalConstructor()
             ->getMock();
         $this->sessionsManager->expects($this->any())->method('getCurrentSession')->willReturn($this->currentSession);
-        $this->currentSession->expects($this->any())->method('isActive')
+        $this->currentSession->expects($this->any())->method('isLoggedInStatus')
             ->will($this->returnValue($result));
         $this->jsonFactory->expects($this->any())->method('create')->willReturn($jsonMock);
         $jsonMock->expects($this->once())
diff --git a/app/code/Magento/Security/Test/Unit/Model/AdminSessionInfoTest.php b/app/code/Magento/Security/Test/Unit/Model/AdminSessionInfoTest.php
index 8d1e5569cb28b46ec16cb33095e5c748f3116516..efbae38d58d2a0edf6a9504b1fdbf7e3edc7a31c 100644
--- a/app/code/Magento/Security/Test/Unit/Model/AdminSessionInfoTest.php
+++ b/app/code/Magento/Security/Test/Unit/Model/AdminSessionInfoTest.php
@@ -19,7 +19,7 @@ class AdminSessionInfoTest extends \PHPUnit_Framework_TestCase
     protected $model;
 
     /**
-     * @var \Magento\Security\Helper\SecurityConfig
+     * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Security\Helper\SecurityConfig
      */
     protected $securityConfigMock;
 
@@ -57,9 +57,25 @@ class AdminSessionInfoTest extends \PHPUnit_Framework_TestCase
     public function testIsLoggedInStatus()
     {
         $this->model->setData('status', \Magento\Security\Model\AdminSessionInfo::LOGGED_IN);
+        $this->model->setUpdatedAt(901);
+        $this->securityConfigMock->expects($this->once())->method('getAdminSessionLifetime')->willReturn(100);
+        $this->securityConfigMock->expects($this->once())->method('getCurrentTimestamp')->willReturn(1000);
         $this->assertEquals(true, $this->model->isLoggedInStatus());
     }
 
+    /**
+     * @return void
+     */
+    public function testIsLoggedInStatusExpired()
+    {
+        $this->model->setData('status', \Magento\Security\Model\AdminSessionInfo::LOGGED_IN);
+        $this->model->setUpdatedAt(899);
+        $this->securityConfigMock->expects($this->once())->method('getAdminSessionLifetime')->willReturn(100);
+        $this->securityConfigMock->expects($this->once())->method('getCurrentTimestamp')->willReturn(1000);
+        $this->assertEquals(false, $this->model->isLoggedInStatus());
+        $this->assertEquals(\Magento\Security\Model\AdminSessionInfo::LOGGED_OUT, $this->model->getStatus());
+    }
+
     /**
      * @param bool $expectedResult
      * @param string $sessionLifetime
@@ -96,25 +112,6 @@ class AdminSessionInfoTest extends \PHPUnit_Framework_TestCase
         ];
     }
 
-    /**
-     * @param bool $expectedResult
-     * @param bool $sessionLifetime
-     * @dataProvider dataProviderIsActive
-     */
-    public function testIsActive($expectedResult, $sessionLifetime)
-    {
-        $this->model->setData('status', \Magento\Security\Model\AdminSessionInfo::LOGGED_IN);
-        $this->securityConfigMock->expects($this->any())
-            ->method('getAdminSessionLifetime')
-            ->will($this->returnValue($sessionLifetime));
-        $this->securityConfigMock->expects($this->any())
-            ->method('getCurrentTimestamp')
-            ->will($this->returnValue(10));
-        $this->model->setUpdatedAt(9);
-
-        $this->assertEquals($expectedResult, $this->model->isActive());
-    }
-
     /**
      * @return array
      */
diff --git a/app/code/Magento/Security/Test/Unit/Model/Plugin/AuthSessionTest.php b/app/code/Magento/Security/Test/Unit/Model/Plugin/AuthSessionTest.php
index 14ea2b4e2c2ca69d07b826b6b0142713cfddb4a3..23534ff62deddc7f918ac4418e9b747905f2d433 100644
--- a/app/code/Magento/Security/Test/Unit/Model/Plugin/AuthSessionTest.php
+++ b/app/code/Magento/Security/Test/Unit/Model/Plugin/AuthSessionTest.php
@@ -86,7 +86,7 @@ class AuthSessionTest extends \PHPUnit_Framework_TestCase
 
         $this->currentSessionMock = $this->getMock(
             '\Magento\Security\Model\AdminSessionInfo',
-            ['isActive', 'getStatus'],
+            ['isLoggedInStatus', 'getStatus'],
             [],
             '',
             false
@@ -128,7 +128,7 @@ class AuthSessionTest extends \PHPUnit_Framework_TestCase
         };
 
         $this->currentSessionMock->expects($this->once())
-            ->method('isActive')
+            ->method('isLoggedInStatus')
             ->willReturn(false);
 
         $this->authSessionMock->expects($this->once())
@@ -197,7 +197,7 @@ class AuthSessionTest extends \PHPUnit_Framework_TestCase
         };
 
         $this->currentSessionMock->expects($this->any())
-            ->method('isActive')
+            ->method('isLoggedInStatus')
             ->willReturn(true);
 
         $this->adminSessionsManagerMock->expects($this->any())
diff --git a/app/code/Magento/Shipping/Model/Rate/Result.php b/app/code/Magento/Shipping/Model/Rate/Result.php
index 697b91b4d5941629c46b1caf9d4bffdbbecf0fb9..a988e149e9e838aa45efb875594280e062b98836 100644
--- a/app/code/Magento/Shipping/Model/Rate/Result.php
+++ b/app/code/Magento/Shipping/Model/Rate/Result.php
@@ -91,7 +91,7 @@ class Result
     /**
      * Return all quotes in the result
      *
-     * @return array
+     * @return \Magento\Quote\Model\Quote\Address\RateResult\Method[]
      */
     public function getAllRates()
     {
diff --git a/app/code/Magento/Swatches/Block/Product/Renderer/Configurable.php b/app/code/Magento/Swatches/Block/Product/Renderer/Configurable.php
index 69caff420de64d68793217b6fbf210ed6e41ce56..f93d353445b4814c911f5891d70dee5fde410241 100644
--- a/app/code/Magento/Swatches/Block/Product/Renderer/Configurable.php
+++ b/app/code/Magento/Swatches/Block/Product/Renderer/Configurable.php
@@ -24,7 +24,8 @@ use Magento\Swatches\Model\Swatch;
  *
  * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  */
-class Configurable extends \Magento\ConfigurableProduct\Block\Product\View\Type\Configurable
+class Configurable extends \Magento\ConfigurableProduct\Block\Product\View\Type\Configurable implements
+    \Magento\Framework\DataObject\IdentityInterface
 {
     /**
      * Path to template file with Swatch renderer.
@@ -106,6 +107,26 @@ class Configurable extends \Magento\ConfigurableProduct\Block\Product\View\Type\
         );
     }
 
+    /**
+     * Get Key for caching block content
+     *
+     * @return string
+     */
+    public function getCacheKey()
+    {
+        return parent::getCacheKey() . '-' . $this->getProduct()->getId();
+    }
+
+    /**
+     * Get block cache life time
+     *
+     * @return int
+     */
+    protected function getCacheLifetime()
+    {
+        return parent::hasCacheLifetime() ? parent::getCacheLifetime() : 3600;
+    }
+
     /**
      * Get Swatch config data
      *
@@ -385,4 +406,18 @@ class Configurable extends \Magento\ConfigurableProduct\Block\Product\View\Type\
     {
         return $this->getBaseUrl() . self::MEDIA_CALLBACK_ACTION;
     }
+
+    /**
+     * Return unique ID(s) for each object in system
+     *
+     * @return string[]
+     */
+    public function getIdentities()
+    {
+        if ($this->product instanceof \Magento\Framework\DataObject\IdentityInterface) {
+            return $this->product->getIdentities();
+        } else {
+            return [];
+        }
+    }
 }
diff --git a/app/code/Magento/Ui/DataProvider/EavValidationRules.php b/app/code/Magento/Ui/DataProvider/EavValidationRules.php
index c8ae4b77340c4fefc7291c27bf5236ff92909796..18d249dc41da216d7605f306c4c4447b5e4b8242 100644
--- a/app/code/Magento/Ui/DataProvider/EavValidationRules.php
+++ b/app/code/Magento/Ui/DataProvider/EavValidationRules.php
@@ -15,11 +15,9 @@ class EavValidationRules
     /**
      * @var array
      */
-    protected $validationRul = [
-        'input_validation' => [
-            'email' => ['validate-email' => true],
-            'date' => ['validate-date' => true],
-        ],
+    protected $validationRules = [
+        'email' => ['validate-email' => true],
+        'date' => ['validate-date' => true],
     ];
 
     /**
@@ -31,30 +29,23 @@ class EavValidationRules
      */
     public function build(AbstractAttribute $attribute, array $data)
     {
-        $rules = [];
-        if (!empty($data['arguments']['data']['config']['required'])) {
-            $rules['required-entry'] = true;
+        $validation = [];
+        if (isset($data['required']) && $data['required'] == 1) {
+            $validation = array_merge($validation, ['required-entry' => true]);
         }
         if ($attribute->getFrontendInput() === 'price') {
-            $rules['validate-zero-or-greater'] = true;
+            $validation = array_merge($validation, ['validate-zero-or-greater' => true]);
         }
-
-        $validation = $attribute->getValidateRules();
-        if (!empty($validation)) {
-            foreach ($validation as $type => $ruleName) {
-                switch ($type) {
-                    case 'input_validation':
-                        if (isset($this->validationRul[$type][$ruleName])) {
-                            $rules = array_merge($rules, $this->validationRul[$type][$ruleName]);
-                        }
-                        break;
-                    case 'min_text_length':
-                    case 'max_text_length':
-                        $rules = array_merge($rules, [$type => $ruleName]);
-                        break;
-                }
-
+        if ($attribute->getValidateRules()) {
+            $validation = array_merge($validation, $attribute->getValidateRules());
+        }
+        $rules = [];
+        foreach ($validation as $type => $ruleName) {
+            $rule = [$type => $ruleName];
+            if ($type === 'input_validation') {
+                $rule = isset($this->validationRules[$ruleName]) ? $this->validationRules[$ruleName] : [];
             }
+            $rules = array_merge($rules, $rule);
         }
 
         return $rules;
diff --git a/app/code/Magento/Ui/Test/Unit/DataProvider/EavValidationRulesTest.php b/app/code/Magento/Ui/Test/Unit/DataProvider/EavValidationRulesTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..e3248fb9b661685917a1cc55c799b94582bab874
--- /dev/null
+++ b/app/code/Magento/Ui/Test/Unit/DataProvider/EavValidationRulesTest.php
@@ -0,0 +1,80 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Ui\Test\Unit\DataProvider;
+
+use Magento\Eav\Model\Entity\Attribute\AbstractAttribute;
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
+use Magento\Ui\DataProvider\EavValidationRules;
+
+/**
+ * Class EavValidationRulesTest
+ */
+class EavValidationRulesTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var ObjectManager
+     */
+    protected $objectManager;
+
+    /**
+     * @var \Magento\Ui\DataProvider\EavValidationRules
+     */
+    protected $subject;
+
+    /**
+     * @var \Magento\Eav\Model\Entity\Attribute\AbstractAttribute|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $attributeMock;
+
+    protected function setUp()
+    {
+        $this->objectManager = new ObjectManager($this);
+        $this->attributeMock =
+            $this->getMockBuilder(AbstractAttribute::class)
+                ->setMethods(['getFrontendInput', 'getValidateRules'])
+                ->disableOriginalConstructor()
+                ->getMockForAbstractClass();
+
+        $this->subject = new EavValidationRules();
+    }
+
+    /**
+     * @param array $data
+     * @param array $expected
+     * @dataProvider buildDataProvider
+     */
+    public function testBuild($attributeInputType, $validateRules, $data, $expected)
+    {
+        $this->attributeMock->expects($this->once())->method('getFrontendInput')->willReturn($attributeInputType);
+        $this->attributeMock->expects($this->any())->method('getValidateRules')->willReturn($validateRules);
+        $validationRules = $this->subject->build($this->attributeMock, $data);
+        $this->assertEquals($expected, $validationRules);
+    }
+
+    /**
+     * @return array
+     */
+    public function buildDataProvider()
+    {
+        return [
+            ['', '', [], []],
+            ['', null, [], []],
+            ['', false, [], []],
+            ['', [], [], []],
+            ['', '', ['required' => 1], ['required-entry' => true]],
+            ['price', '', [], ['validate-zero-or-greater' => true]],
+            ['price', '', ['required' => 1], ['validate-zero-or-greater' => true, 'required-entry' => true]],
+            ['', ['input_validation' => 'email'], [], ['validate-email' => true]],
+            ['', ['input_validation' => 'date'], [], ['validate-date' => true]],
+            ['', ['input_validation' => 'other'], [], []],
+            ['', ['max_text_length' => '254'], ['required' => 1], ['max_text_length' => 254, 'required-entry' => true]],
+            ['', ['max_text_length' => '254', 'min_text_length' => 1], [],
+                ['max_text_length' => 254, 'min_text_length' => 1]],
+            ['', ['max_text_length' => '254', 'input_validation' => 'date'], [],
+                ['max_text_length' => 254, 'validate-date' => true]],
+        ];
+    }
+}
diff --git a/app/code/Magento/Ui/view/base/web/js/form/components/button.js b/app/code/Magento/Ui/view/base/web/js/form/components/button.js
index 6acce9e43ad6cc5ef976ca6446aaf05717b55018..9fbd07790a30e813a2b30bead14377f619ced490 100644
--- a/app/code/Magento/Ui/view/base/web/js/form/components/button.js
+++ b/app/code/Magento/Ui/view/base/web/js/form/components/button.js
@@ -16,9 +16,9 @@ define([
             additionalClasses: {},
             displayArea: 'outsideGroup',
             displayAsLink: false,
+            visible: true,
             elementTmpl: 'ui/form/element/button',
             template: 'ui/form/components/button/simple',
-            visible: true,
             disabled: false
         },
 
diff --git a/app/code/Magento/Ui/view/base/web/js/grid/listing.js b/app/code/Magento/Ui/view/base/web/js/grid/listing.js
index 67e91821d663c18f685d3f6988f93e50599dc308..d0d932e0f22651b6acf82b6d1b8c40f49e6359e6 100644
--- a/app/code/Magento/Ui/view/base/web/js/grid/listing.js
+++ b/app/code/Magento/Ui/view/base/web/js/grid/listing.js
@@ -17,7 +17,16 @@ define([
         defaults: {
             template: 'ui/grid/listing',
             stickyTmpl: 'ui/grid/sticky/listing',
+            viewSwitcherTmpl: 'ui/grid/view-switcher',
             positions: false,
+            displayMode: 'grid',
+            displayModes: {
+                grid: {
+                    value: 'grid',
+                    label: 'Grid',
+                    template: '${ $.template }'
+                }
+            },
             dndConfig: {
                 name: '${ $.name }_dnd',
                 component: 'Magento_Ui/js/grid/dnd',
@@ -48,6 +57,12 @@ define([
             modules: {
                 dnd: '${ $.dndConfig.name }',
                 resize: '${ $.resizeConfig.name }'
+            },
+            tracks: {
+                displayMode: true
+            },
+            statefull: {
+                displayMode: true
             }
         },
 
@@ -96,7 +111,7 @@ define([
         },
 
         /**
-         * Inititalizes resize component.
+         * Initializes resize component.
          *
          * @returns {Listing} Chainable.
          */
@@ -170,7 +185,7 @@ define([
         },
 
         /**
-         * Reseorts child elements array according to provided positions.
+         * Resorts child elements array according to provided positions.
          *
          * @param {Object} positions - Object where key represents child
          *      index and value is its' position.
@@ -202,6 +217,41 @@ define([
             return observable || this.visibleColumns;
         },
 
+        /**
+         * Returns path to the template
+         * defined for a current display mode.
+         *
+         * @returns {String} Path to the template.
+         */
+        getTemplate: function () {
+            var mode = this.displayModes[this.displayMode];
+
+            return mode.template;
+        },
+
+        /**
+         * Returns an array of available display modes.
+         *
+         * @returns {Array<Object>}
+         */
+        getDisplayModes: function () {
+            var modes = this.displayModes;
+
+            return _.values(modes);
+        },
+
+        /**
+         * Sets display mode to provided value.
+         *
+         * @param {String} index
+         * @returns {Listing} Chainable
+         */
+        setDisplayMode: function (index) {
+            this.displayMode = index;
+
+            return this;
+        },
+
         /**
          * Returns total number of displayed columns in grid.
          *
diff --git a/app/code/Magento/Ui/view/base/web/js/lib/knockout/bindings/bootstrap.js b/app/code/Magento/Ui/view/base/web/js/lib/knockout/bindings/bootstrap.js
index de64a6d657a453a220ddc015d5d013afc375a94d..7d5a95346cf02f2d29555c4a4c2191c5c3cac0c3 100644
--- a/app/code/Magento/Ui/view/base/web/js/lib/knockout/bindings/bootstrap.js
+++ b/app/code/Magento/Ui/view/base/web/js/lib/knockout/bindings/bootstrap.js
@@ -21,6 +21,7 @@ define(function (require) {
     return {
         i18n:           require('./i18n'),
         scope:          require('./scope'),
+        range:          require('./range'),
         mageInit:       require('./mage-init'),
         keyboard:       require('./keyboard'),
         optgroup:       require('./optgroup'),
@@ -32,6 +33,7 @@ define(function (require) {
         collapsible:    require('./collapsible'),
         staticChecked:  require('./staticChecked'),
         simpleChecked:  require('./simple-checked'),
+        tooltip:        require('./tooltip'),
         repeat:         require('knockoutjs/knockout-repeat'),
         fastForEach:    require('knockoutjs/knockout-fast-foreach')
     };
diff --git a/app/code/Magento/Ui/view/base/web/js/lib/knockout/bindings/range.js b/app/code/Magento/Ui/view/base/web/js/lib/knockout/bindings/range.js
new file mode 100644
index 0000000000000000000000000000000000000000..208952e990af137a977d946a1903e94c45e341a5
--- /dev/null
+++ b/app/code/Magento/Ui/view/base/web/js/lib/knockout/bindings/range.js
@@ -0,0 +1,203 @@
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+define([
+    'ko',
+    'jquery',
+    'underscore',
+    '../template/renderer',
+    'jquery/ui'
+], function (ko, $, _, renderer) {
+    'use strict';
+
+    var isTouchDevice = !_.isUndefined(document.ontouchstart),
+        sliderFn = 'slider';
+
+    ko.bindingHandlers.range = {
+
+        /**
+         * Initializes binding and a slider update.
+         *
+         * @param {HTMLElement} element
+         * @param {Function} valueAccessor
+         */
+        init: function (element, valueAccessor) {
+            var config  = valueAccessor(),
+                value   = config.value;
+
+            _.extend(config, {
+                value: value(),
+
+                /**
+                 * Callback which is being called when sliders' value changes.
+                 *
+                 * @param {Event} event
+                 * @param {Object} ui
+                 */
+                slide: function (event, ui) {
+                    value(ui.value);
+                }
+            });
+
+            $(element)[sliderFn](config);
+        },
+
+        /**
+         * Updates sliders' plugin configuration.
+         *
+         * @param {HTMLElement} element
+         * @param {Function} valueAccessor
+         */
+        update: function (element, valueAccessor) {
+            var config = valueAccessor();
+
+            config.value = ko.unwrap(config.value);
+
+            $(element)[sliderFn]('option', config);
+        }
+    };
+
+    renderer.addAttribute('range');
+
+    if (!isTouchDevice) {
+        return;
+    }
+
+    $.widget('mage.touchSlider', $.ui.slider, {
+
+        /**
+         * Creates instance of widget.
+         *
+         * @override
+         */
+        _create: function () {
+            _.bindAll(
+                this,
+                '_mouseDown',
+                '_mouseMove',
+                '_onTouchEnd'
+            );
+
+            return this._superApply(arguments);
+        },
+
+        /**
+         * Initializes mouse events on element.
+         * @override
+         */
+        _mouseInit: function () {
+            var result = this._superApply(arguments);
+
+            this.element
+                .off('mousedown.' + this.widgetName)
+                .on('touchstart.' + this.widgetName, this._mouseDown);
+
+            return result;
+        },
+
+        /**
+         * Elements' 'mousedown' event handler polyfill.
+         * @override
+         */
+        _mouseDown: function (event) {
+            var prevDelegate = this._mouseMoveDelegate,
+                result;
+
+            event = this._touchToMouse(event);
+            result = this._super(event);
+
+            if (prevDelegate === this._mouseMoveDelegate) {
+                return result;
+            }
+
+            $(document)
+                .off('mousemove.' + this.widgetName)
+                .off('mouseup.' + this.widgetName);
+
+            $(document)
+                .on('touchmove.' + this.widgetName, this._mouseMove)
+                .on('touchend.' + this.widgetName, this._onTouchEnd)
+                .on('tochleave.' + this.widgetName, this._onTouchEnd);
+
+            return result;
+        },
+
+        /**
+         * Documents' 'mousemove' event handler polyfill.
+         *
+         * @override
+         * @param {Event} event - Touch event object.
+         */
+        _mouseMove: function (event) {
+            event = this._touchToMouse(event);
+
+            return this._super(event);
+        },
+
+        /**
+         * Documents' 'touchend' event handler.
+         */
+        _onTouchEnd: function (event) {
+            $(document).trigger('mouseup');
+
+            return this._mouseUp(event);
+        },
+
+        /**
+         * Removes previously assigned touch handlers.
+         *
+         * @override
+         */
+        _mouseUp: function () {
+            this._removeTouchHandlers();
+
+            return this._superApply(arguments);
+        },
+
+        /**
+         * Removes previously assigned touch handlers.
+         *
+         * @override
+         */
+        _mouseDestroy: function () {
+            this._removeTouchHandlers();
+
+            return this._superApply(arguments);
+        },
+
+        /**
+         * Removes touch events from document object.
+         */
+        _removeTouchHandlers: function () {
+            $(document)
+                .off('touchmove.' + this.widgetName)
+                .off('touchend.' + this.widgetName)
+                .off('touchleave.' + this.widgetName);
+        },
+
+        /**
+         * Adds properties to the touch event to mimic mouse event.
+         *
+         * @param {Event} event - Touch event object.
+         * @returns {Event}
+         */
+        _touchToMouse: function (event) {
+            var orig = event.originalEvent,
+                touch = orig.touches[0];
+
+            return _.extend(event, {
+                which:      1,
+                pageX:      touch.pageX,
+                pageY:      touch.pageY,
+                clientX:    touch.clientX,
+                clientY:    touch.clientY,
+                screenX:    touch.screenX,
+                screenY:    touch.screenY
+            });
+        }
+    });
+
+    sliderFn = 'touchSlider';
+});
diff --git a/app/code/Magento/Ui/view/base/web/js/lib/knockout/bindings/tooltip.js b/app/code/Magento/Ui/view/base/web/js/lib/knockout/bindings/tooltip.js
new file mode 100644
index 0000000000000000000000000000000000000000..99870e0d70aa9914a63af4ee7ea8fa8282caa4e6
--- /dev/null
+++ b/app/code/Magento/Ui/view/base/web/js/lib/knockout/bindings/tooltip.js
@@ -0,0 +1,743 @@
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+define([
+    'jquery',
+    'ko',
+    'underscore',
+    'mage/template',
+    'text!ui/template/tooltip/tooltip.html',
+    '../template/renderer'
+], function ($, ko, _, template, tooltipTmpl, renderer) {
+    'use strict';
+
+    var tooltip,
+        defaults,
+        positions,
+        transformProp,
+        checkedPositions = {},
+        iterator = 0,
+        previousTooltip,
+        tooltipData,
+        positionData = {},
+        tooltipsCollection = {},
+        isTouchDevice = (function () {
+            return 'ontouchstart' in document.documentElement;
+        })(),
+        CLICK_EVENT = (function () {
+            return isTouchDevice ? 'touchstart' : 'click';
+        })();
+
+    defaults = {
+        tooltipWrapper: '[data-tooltip=tooltip-wrapper]',
+        tooltipContentBlock: 'data-tooltip-content',
+        closeButtonClass: 'action-close',
+        tailClass: 'data-tooltip-tail',
+        action: 'hover',
+        delay: 300,
+        track: false,
+        step: 20,
+        position: 'top',
+        closeButton: false,
+        showed: false,
+        strict: true,
+        center: false
+    };
+
+    tooltipData = {
+        trigger: false,
+        timeout: 0,
+        element: false,
+        event: false,
+        targetElement: {},
+        showed: false,
+        currentID: 0
+    };
+
+    /**
+     * Polyfill for css transform
+     */
+    transformProp = (function () {
+        var style = document.createElement('div').style,
+            base = 'Transform',
+            vendors = ['webkit', 'moz', 'ms', 'o'],
+            vi = vendors.length,
+            property;
+
+        if (typeof style.transform !== 'undefined') {
+            return 'transform';
+        }
+
+        while (vi--) {
+            property = vendors[vi] + base;
+
+            if (typeof style[property] !== 'undefined') {
+                return property;
+            }
+        }
+    })();
+
+    positions = {
+
+        /*eslint max-depth: [0, 0]*/
+
+        map: {
+            horizontal: {
+                s: 'w',
+                p: 'left'
+            },
+            vertical: {
+                s: 'h',
+                p: 'top'
+            }
+        },
+
+        /**
+         * Wrapper function to get tooltip data (position, className, etc)
+         *
+         * @param {Object} s - object with sizes and positions elements
+         * @returns {Object} tooltip data (position, className, etc)
+         */
+        top: function (s) {
+            return positions._topLeftChecker(s, positions.map, 'vertical', '_bottom', 'top', 'right');
+        },
+
+        /**
+         * Wrapper function to get tooltip data (position, className, etc)
+         *
+         * @param {Object} s - object with sizes and positions elements
+         * @returns {Object} tooltip data (position, className, etc)
+         */
+        left: function (s) {
+            return positions._topLeftChecker(s, positions.map, 'horizontal', '_right', 'left', 'top');
+        },
+
+        /**
+         * Wrapper function to get tooltip data (position, className, etc)
+         *
+         * @param {Object} s - object with sizes and positions elements
+         * @returns {Object} tooltip data (position, className, etc)
+         */
+        bottom: function (s) {
+            return positions._bottomRightChecker(s, positions.map, 'vertical', '_top', 'bottom', 'left');
+        },
+
+        /**
+         * Wrapper function to get tooltip data (position, className, etc)
+         *
+         * @param {Object} s - object with sizes and positions elements
+         * @returns {Object} tooltip data (position, className, etc)
+         */
+        right: function (s) {
+            return positions._bottomRightChecker(s, positions.map, 'horizontal', '_left', 'right', 'bottom');
+        },
+
+        /**
+         * Check can tooltip setted on current position or not. If can't setted - delegate call.
+         *
+         * @param {Object} s - object with sizes and positions elements
+         * @param {Object} map - mapping for get direction positions
+         * @param {String} direction - vertical or horizontal
+         * @param {String} className - class whats should be setted to tooltip
+         * @param {String} side - parent method name
+         * @param {String} delegate - method name if tooltip can't be setted in current position
+         * @returns {Object} tooltip data (position, className, etc)
+         */
+        _topLeftChecker: function (s, map, direction, className, side, delegate) {
+            var result = {
+                    position: {}
+                },
+                config = tooltip.getTooltip(tooltipData.currentID),
+                startPosition = !config.strict ? s.eventPosition : s.elementPosition,
+                changedDirection;
+
+            checkedPositions[side] = true;
+
+            if (
+                startPosition[map[direction].p] - s.tooltipSize[map[direction].s] - config.step >
+                s.scrollPosition[map[direction].p]
+            ) {
+                result.position[map[direction].p] = startPosition[map[direction].p] - s.tooltipSize[map[direction].s] -
+                    config.step;
+                result.className = className;
+                result.side = side;
+                changedDirection = direction === 'vertical' ? 'horizontal' : 'vertical';
+                result = positions._normalize(s, result, config, delegate, map, changedDirection);
+            } else if (!checkedPositions[delegate]) {
+                result = positions[delegate].apply(null, arguments);
+            } else {
+                result = positions.positionCenter(s, result);
+            }
+
+            return result;
+        },
+
+        /**
+         * Check can tooltip setted on current position or not. If can't setted - delegate call.
+         *
+         * @param {Object} s - object with sizes and positions elements
+         * @param {Object} map - mapping for get direction positions
+         * @param {String} direction - vertical or horizontal
+         * @param {String} className - class whats should be setted to tooltip
+         * @param {String} side - parent method name
+         * @param {String} delegate - method name if tooltip can't be setted in current position
+         * @returns {Object} tooltip data (position, className, etc)
+         */
+        _bottomRightChecker: function (s, map, direction, className, side, delegate) {
+            var result = {
+                    position: {}
+                },
+                config = tooltip.getTooltip(tooltipData.currentID),
+                startPosition = !config.strict ? s.eventPosition : {
+                    top: s.elementPosition.top + s.elementSize.h,
+                    left: s.elementPosition.left + s.elementSize.w
+                },
+                changedDirection;
+
+            checkedPositions[side] = true;
+
+            if (
+                startPosition[map[direction].p] + s.tooltipSize[map[direction].s] + config.step <
+                s.scrollPosition[map[direction].p] + s.windowSize[map[direction].s]
+            ) {
+                result.position[map[direction].p] = startPosition[map[direction].p] + config.step;
+                result.className = className;
+                result.side = side;
+                changedDirection = direction === 'vertical' ? 'horizontal' : 'vertical';
+                result = positions._normalize(s, result, config, delegate, map, changedDirection);
+            } else if (!checkedPositions[delegate]) {
+                result = positions[delegate].apply(null, arguments);
+            } else {
+                result = positions.positionCenter(s, result);
+            }
+
+            return result;
+        },
+
+        /**
+         * Centered tooltip if tooltip does not fit in window
+         *
+         * @param {Object} s - object with sizes and positions elements
+         * @param {Object} data - current data (position, className, etc)
+         * @returns {Object} tooltip data (position, className, etc)
+         */
+        positionCenter: function (s, data) {
+            data = positions._positionCenter(s, data, 'horizontal', positions.map);
+            data = positions._positionCenter(s, data, 'vertical', positions.map);
+
+            return data;
+        },
+
+        /**
+         * Centered tooltip side
+         *
+         * @param {Object} s - object with sizes and positions elements
+         * @param {Object} data - current data (position, className, etc)
+         * @param {String} direction - vertical or horizontal
+         * @param {Object} map - mapping for get direction positions
+         * @returns {Object} tooltip data (position, className, etc)
+         */
+        _positionCenter: function (s, data, direction, map) {
+            if (s.tooltipSize[map[direction].s] < s.windowSize[map[direction].s]) {
+                data.position[map[direction].p] = (s.windowSize[map[direction].s] -
+                    s.tooltipSize[map[direction].s]) / 2 + s.scrollPosition[map[direction].p];
+            } else {
+                data.position[map[direction].p] = s.scrollPosition[map[direction].p];
+                data.tooltipSize = {};
+                data.tooltipSize[map[direction].s] = s.windowSize[map[direction].s];
+            }
+
+            return data;
+        },
+
+        /**
+         * Normalize horizontal or vertical position.
+         *
+         * @param {Object} s - object with sizes and positions elements
+         * @param {Object} data - current data (position, className, etc)
+         * @param {Object} config - tooltip config
+         * @param {String} delegate - method name if tooltip can't be setted in current position
+         * @param {Object} map - mapping for get direction positions
+         * @param {String} direction - vertical or horizontal
+         * @returns {Object} tooltip data (position, className, etc)
+         */
+        _normalize: function (s, data, config, delegate, map, direction) {
+            var startPosition = !config.center ? s.eventPosition : {
+                    left: s.elementPosition.left + s.elementSize.w / 2,
+                    top: s.elementPosition.top + s.elementSize.h / 2
+                },
+                depResult;
+
+            if (startPosition[map[direction].p] - s.tooltipSize[map[direction].s] / 2 >
+                s.scrollPosition[map[direction].p] && startPosition[map[direction].p] +
+                s.tooltipSize[map[direction].s] / 2 <
+                s.scrollPosition[map[direction].p] + s.windowSize[map[direction].s]
+            ) {
+                data.position[map[direction].p] = startPosition[map[direction].p] - s.tooltipSize[map[direction].s] / 2;
+            } else {
+
+                /*eslint-disable no-lonely-if*/
+                if (!checkedPositions[delegate]) {
+                    depResult = positions[delegate].apply(null, arguments);
+
+                    if (depResult.hasOwnProperty('className')) {
+                        data = depResult;
+                    } else {
+                        data = positions._normalizeTail(s, data, config, delegate, map, direction, startPosition);
+                    }
+                } else {
+                    data = positions._normalizeTail(s, data, config, delegate, map, direction, startPosition);
+                }
+            }
+
+            return data;
+        },
+
+        /**
+         * Calc tail position.
+         *
+         * @param {Object} s - object with sizes and positions elements
+         * @param {Object} data - current data (position, className, etc)
+         * @param {Object} config - tooltip config
+         * @param {String} delegate - method name if tooltip can't be setted in current position
+         * @param {Object} map - mapping for get direction positions
+         * @param {String} direction - vertical or horizontal
+         * @param {Object} startPosition - start position
+         * @returns {Object} tooltip data (position, className, etc)
+         */
+        _normalizeTail: function (s, data, config, delegate, map, direction, startPosition) {
+            data.tail = {};
+
+            if (s.tooltipSize[map[direction].s] < s.windowSize[map[direction].s]) {
+
+                if (
+                    startPosition[map[direction].p] >
+                    s.windowSize[map[direction].s] / 2 + s.scrollPosition[map[direction].p]
+                ) {
+                    data.position[map[direction].p] = s.windowSize[map[direction].s] +
+                        s.scrollPosition[map[direction].p] - s.tooltipSize[map[direction].s];
+                    data.tail[map[direction].p] = startPosition[map[direction].p] -
+                        s.tooltipSize[map[direction].s] / 2 - data.position[map[direction].p];
+                } else {
+                    data.position[map[direction].p] = s.scrollPosition[map[direction].p];
+                    data.tail[map[direction].p] = startPosition[map[direction].p] -
+                        s.tooltipSize[map[direction].s] / 2 - data.position[map[direction].p];
+                }
+            } else {
+                data.position[map[direction].p] = s.scrollPosition[map[direction].p];
+                data.tail[map[direction].p] = s.eventPosition[map[direction].p] - s.windowSize[map[direction].s] / 2;
+                data.tooltipSize = {};
+                data.tooltipSize[map[direction].s] = s.windowSize[map[direction].s];
+            }
+
+            return data;
+        }
+    };
+
+    tooltip = {
+
+        /**
+         * Set new tooltip to tooltipCollection, save config, and add unic id
+         *
+         * @param {Object} config - tooltip config
+         * @returns {String} tooltip id
+         */
+        setTooltip: function (config) {
+            var property = 'id-' + iterator;
+
+            tooltipsCollection[property] = config;
+            iterator++;
+
+            return property;
+        },
+
+        /**
+         * Get tooltip config by id
+         *
+         * @param {String} id - tooltip id
+         * @returns {Object} tooltip config
+         */
+        getTooltip: function (id) {
+            return tooltipsCollection[id];
+        },
+
+        /**
+         * Set content to current tooltip
+         *
+         * @param {Object} tooltipElement - tooltip element
+         * @param {Object} viewModel - tooltip view model
+         * @param {String} id - tooltip id
+         * @param {Object} bindingCtx - tooltip context
+         * @param {Object} event - action event
+         */
+        setContent: function (tooltipElement, viewModel, id, bindingCtx, event) {
+            var html = $(tooltipElement).html(),
+                config = tooltip.getTooltip(id),
+                body = $('body');
+
+            tooltipData.currentID = id;
+            tooltipData.trigger = $(event.currentTarget);
+            tooltip.setTargetData(event);
+            body.on('mousemove.setTargetData', tooltip.setTargetData);
+            tooltip.clearTimeout(id);
+
+            tooltipData.timeout = _.delay(function () {
+                body.off('mousemove.setTargetData', tooltip.setTargetData);
+
+                if (tooltipData.trigger[0] === tooltipData.targetElement) {
+                    tooltip.destroy(id);
+                    event.stopPropagation();
+                    tooltipElement = tooltip.createTooltip(id);
+                    tooltipElement.find('.' + defaults.tooltipContentBlock).append(html);
+                    tooltipElement.applyBindings(bindingCtx);
+                    tooltip.setHandlers(id);
+                    tooltip.setPosition(tooltipElement, id);
+                    previousTooltip = id;
+                }
+
+            }, config.delay);
+        },
+
+        /**
+         * Set position to current tooltip
+         *
+         * @param {Object} tooltipElement - tooltip element
+         * @param {String} id - tooltip id
+         */
+        setPosition: function (tooltipElement, id) {
+            var config = tooltip.getTooltip(id);
+
+            tooltip.sizeData = {
+                windowSize: {
+                    h: $(window).outerHeight(),
+                    w: $(window).outerWidth()
+                },
+                scrollPosition: {
+                    top: $(window).scrollTop(),
+                    left: $(window).scrollLeft()
+                },
+                tooltipSize: {
+                    h: tooltipElement.outerHeight(),
+                    w: tooltipElement.outerWidth()
+                },
+                elementSize: {
+                    h: tooltipData.trigger.outerHeight(),
+                    w: tooltipData.trigger.outerWidth()
+                },
+                elementPosition: tooltipData.trigger.offset(),
+                eventPosition: this.getEventPosition(tooltipData.event)
+            };
+
+            _.extend(positionData, positions[config.position](tooltip.sizeData));
+            tooltipElement.css(positionData.position);
+            tooltipElement.addClass(positionData.className);
+            tooltip._setTooltipSize(positionData, tooltipElement);
+            tooltip._setTailPosition(positionData, tooltipElement);
+            checkedPositions = {};
+        },
+
+        /**
+         * Check position data and change tooltip size if needs
+         *
+         * @param {Object} data - position data
+         * @param {Object} tooltipElement - tooltip element
+         */
+        _setTooltipSize: function (data, tooltipElement) {
+            if (data.tooltipSize) {
+                data.tooltipSize.w ?
+                    tooltipElement.css('width', data.tooltipSize.w) :
+                    tooltipElement.css('height', data.tooltipSize.h);
+            }
+        },
+
+        /**
+         * Check position data and set position to tail
+         *
+         * @param {Object} data - position data
+         * @param {Object} tooltipElement - tooltip element
+         */
+        _setTailPosition: function (data, tooltipElement) {
+            var tail,
+                tailMargin;
+
+            if (data.tail) {
+                tail = tooltipElement.find('.' + defaults.tailClass);
+
+                if (data.tail.left) {
+                    tailMargin = parseInt(tail.css('margin-left'), 10);
+                    tail.css('margin-left', tailMargin + data.tail.left);
+                } else {
+                    tailMargin = parseInt(tail.css('margin-top'), 10);
+                    tail.css('margin-top', tailMargin + data.tail.top);
+                }
+            }
+        },
+
+        /**
+         * Resolves position for tooltip
+         *
+         * @param {Object} event
+         * @returns {Object}
+         */
+        getEventPosition: function (event) {
+            var position = {
+                left: event.originalEvent && event.originalEvent.pageX || 0,
+                top: event.originalEvent && event.originalEvent.pageY || 0
+            };
+
+            if (position.left === 0 && position.top === 0) {
+                _.extend(position, event.target.getBoundingClientRect());
+            }
+
+            return position;
+        },
+
+        /**
+         * Close tooltip if action happened outside handler and tooltip element
+         *
+         * @param {String} id - tooltip id
+         * @param {Object} event - action event
+         */
+        outerClick: function (id, event) {
+            var tooltipElement = $(event.target).parents(defaults.tooltipWrapper)[0],
+                isTrigger = event.target === tooltipData.trigger[0] || $.contains(tooltipData.trigger[0], event.target);
+
+            if (tooltipData.showed && tooltipElement !== tooltipData.element[0] && !isTrigger) {
+                tooltip.destroy(id);
+            }
+        },
+
+        /**
+         * Parse keydown event and if event trigger is escape key - close tooltip
+         *
+         * @param {Object} event - action event
+         */
+        keydownHandler: function (event) {
+            if (tooltipData.showed && event.keyCode === 27) {
+                tooltip.destroy(tooltipData.currentID);
+            }
+        },
+
+        /**
+         * Change tooltip position when track is enabled
+         *
+         * @param {Object} event - current event
+         */
+        track: function (event) {
+            var inequality = {},
+                map = positions.map,
+                translate = {
+                    left: 'translateX',
+                    top: 'translateY'
+                },
+                eventPosition = {
+                    left: event.pageX,
+                    top: event.pageY
+                },
+                tooltipSize = {
+                    w: tooltipData.element.outerWidth(),
+                    h: tooltipData.element.outerHeight()
+                },
+                direction = positionData.side === 'bottom' || positionData.side === 'top' ? 'horizontal' : 'vertical';
+
+            inequality[map[direction].p] = eventPosition[map[direction].p] - (positionData.position[map[direction].p] +
+                tooltipSize[map[direction].s] / 2);
+
+            if (positionData.position[map[direction].p] + inequality[map[direction].p] +
+                tooltip.sizeData.tooltipSize[map[direction].s] >
+                tooltip.sizeData.windowSize[map[direction].s] + tooltip.sizeData.scrollPosition[map[direction].p] ||
+                inequality[map[direction].p] + positionData.position[map[direction].p] <
+                tooltip.sizeData.scrollPosition[map[direction].p]) {
+
+                return false;
+            }
+
+            tooltipData.element[0].style[transformProp] = translate[map[direction].p] +
+                '(' + inequality[map[direction].p] + 'px)';
+        },
+
+        /**
+         * Set handlers to tooltip
+         *
+         * @param {String} id - tooltip id
+         */
+        setHandlers: function (id) {
+            var config = tooltip.getTooltip(id);
+
+            if (config.track) {
+                tooltipData.trigger.on('mousemove.track', tooltip.track);
+            }
+
+            if (config.action === 'click') {
+                $(window).on(CLICK_EVENT + '.outerClick', tooltip.outerClick.bind(null, id));
+            }
+
+            if (config.closeButton) {
+                $('.' + config.closeButtonClass).on('click.closeButton', tooltip.destroy.bind(null, id));
+            }
+
+            document.addEventListener('scroll', tooltip.destroy, true);
+            $(window).on('keydown.tooltip', tooltip.keydownHandler);
+            $(window).on('scroll.tooltip', tooltip.outerClick.bind(null, id));
+            $(window).on('resize.outerClick', tooltip.outerClick.bind(null, id));
+        },
+
+        /**
+         * Toggle tooltip
+         *
+         * @param {Object} tooltipElement - tooltip element
+         * @param {Object} viewModel - tooltip view model
+         * @param {String} id - tooltip id
+         */
+        toggleTooltip: function (tooltipElement, viewModel, id) {
+            if (previousTooltip === id && tooltipData.showed) {
+                tooltip.destroy(id);
+
+                return false;
+            }
+
+            tooltip.setContent.apply(null, arguments);
+        },
+
+        /**
+         * Create tooltip and append to DOM
+         *
+         * @param {String} id - tooltip id
+         * @returns {Object} tooltip element
+         */
+        createTooltip: function (id) {
+            var body = $('body'),
+                config = tooltip.getTooltip(id);
+
+            $(template(tooltipTmpl, {
+                data: config
+            })).appendTo(body);
+
+            tooltipData.showed = true;
+            tooltipData.element = $(config.tooltipWrapper);
+
+            return tooltipData.element;
+        },
+
+        /**
+         * Check action and clean timeout
+         *
+         * @param {String} id - tooltip id
+         */
+        clearTimeout: function (id) {
+            var config = tooltip.getTooltip(id);
+
+            if (config.action === 'hover') {
+                clearTimeout(tooltipData.timeout);
+            }
+        },
+
+        /**
+         * Check previous tooltip
+         */
+        checkPreviousTooltip: function () {
+            if (!tooltipData.timeout) {
+                tooltip.destroy();
+            }
+        },
+
+        /**
+         * Destroy tooltip instance
+         */
+        destroy: function () {
+            if (tooltipData.element) {
+                tooltipData.element.remove();
+                tooltipData.showed = false;
+            }
+
+            positionData = {};
+            tooltipData.timeout = false;
+            tooltip.removeHandlers();
+        },
+
+        /**
+         * Remove tooltip handlers
+         */
+        removeHandlers: function () {
+            $('.' + defaults.closeButtonClass).off('click.closeButton');
+            tooltipData.trigger.off('mousemove.track');
+            document.removeEventListener('scroll', tooltip.destroy, true);
+            $(window).off(CLICK_EVENT + '.outerClick');
+            $(window).off('keydown.tooltip');
+            $(window).off('resize.outerClick');
+        },
+
+        /**
+         * Set target element
+         *
+         * @param {Object} event - current event
+         */
+        setTargetData: function (event) {
+            tooltipData.event = event;
+            tooltipData.targetElement = event.type === 'mousemove' ?
+                event.target : event.currentTarget;
+        },
+
+        /**
+         * Merged user config with defaults configuration
+         *
+         * @param {Object} config - user config
+         * @returns {Object} merged config
+         */
+        processingConfig: function (config) {
+            return _.extend({}, defaults, config);
+        }
+    };
+
+    ko.bindingHandlers.tooltip = {
+
+        /**
+         * Initialize tooltip
+         *
+         * @param {Object} elem - tooltip DOM element
+         * @param {Function} valueAccessor - ko observable property, tooltip data
+         * @param {Object} allBindings - all bindings on current element
+         * @param {Object} viewModel - current element viewModel
+         * @param {Object} bindingCtx - current element binding context
+         */
+        init: function (elem, valueAccessor, allBindings, viewModel, bindingCtx) {
+            var config = tooltip.processingConfig(valueAccessor()),
+                $parentScope = config.parentScope ? $(config.parentScope) : $(elem).parent(),
+                tooltipId;
+
+            $(elem).addClass('hidden');
+
+            if (isTouchDevice) {
+                config.action = 'click';
+            }
+            tooltipId = tooltip.setTooltip(config);
+
+            if (config.action === 'hover') {
+                $parentScope.on(
+                    'mouseenter',
+                    config.trigger,
+                    tooltip.setContent.bind(null, elem, viewModel, tooltipId, bindingCtx)
+                );
+                $parentScope.on(
+                    'mouseleave',
+                    config.trigger,
+                    tooltip.checkPreviousTooltip.bind(null, tooltipId)
+                );
+            } else if (config.action === 'click') {
+                $parentScope.on(
+                    'click',
+                    config.trigger,
+                    tooltip.toggleTooltip.bind(null, elem, viewModel, tooltipId, bindingCtx)
+                );
+            }
+
+            return {
+                controlsDescendantBindings: true
+            };
+        }
+    };
+
+    renderer.addAttribute('tooltip');
+});
diff --git a/app/code/Magento/Ui/view/base/web/js/lib/knockout/template/renderer.js b/app/code/Magento/Ui/view/base/web/js/lib/knockout/template/renderer.js
index 4bb148a0995c47210c6b593613617f2f7a8fe581..8f5fb6646efef5d3e9c7abbacbef113d2bcd0321 100644
--- a/app/code/Magento/Ui/view/base/web/js/lib/knockout/template/renderer.js
+++ b/app/code/Magento/Ui/view/base/web/js/lib/knockout/template/renderer.js
@@ -462,6 +462,8 @@ define([
             'textInput',
             'component',
             'uniqueName',
+            'optionsText',
+            'optionsValue',
             'checkedValue',
             'selectedOptions'
         ], Array.prototype)
diff --git a/app/code/Magento/Ui/view/base/web/js/timeline/timeline-view.js b/app/code/Magento/Ui/view/base/web/js/timeline/timeline-view.js
new file mode 100644
index 0000000000000000000000000000000000000000..a5bafc72b5e6db54cb01014352ba7f080938f1cb
--- /dev/null
+++ b/app/code/Magento/Ui/view/base/web/js/timeline/timeline-view.js
@@ -0,0 +1,415 @@
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+define([
+    'ko',
+    'Magento_Ui/js/lib/view/utils/async',
+    'underscore',
+    'Magento_Ui/js/lib/view/utils/raf',
+    'uiRegistry',
+    'uiClass'
+], function (ko, $, _, raf, registry, Class) {
+    'use strict';
+
+    var hasClassList = (function () {
+        var list = document.createElement('_').classList;
+
+        return !!list && !list.toggle('_test', false);
+    })();
+
+    /**
+     * Polyfill of the 'classList.toggle' method.
+     *
+     * @param {HTMLElement} elem
+     */
+    function toggleClass(elem) {
+        var classList   = elem.classList,
+            args        = Array.prototype.slice.call(arguments, 1),
+            $elem;
+
+        if (hasClassList) {
+            classList.toggle.apply(classList, args);
+        } else {
+            $elem = $(elem);
+            $elem.toggleClass.apply($elem, args);
+        }
+    }
+
+    return Class.extend({
+        defaults: {
+            selectors: {
+                content: '.timeline-content',
+                timeUnit: '.timeline-unit',
+                item: '.timeline-item:not([data-role=no-data-msg])',
+                event: '.timeline-event'
+            }
+        },
+
+        /**
+         * Initializes TimelineView component.
+         *
+         * @returns {TimelineView} Chainable.
+         */
+        initialize: function () {
+            _.bindAll(
+                this,
+                'refresh',
+                'initContent',
+                'initItem',
+                'initTimeUnit',
+                'getItemBindings',
+                'updateItemsPosition',
+                'onScaleChange',
+                'onEventElementRender',
+                'onWindowResize',
+                'onContentScroll',
+                'onDataReloaded',
+                'onToStartClick',
+                'onToEndClick'
+            );
+
+            this._super()
+                .initModel()
+                .waitContent();
+
+            return this;
+        },
+
+        /**
+         * Applies listeners for the model properties changes.
+         *
+         * @returns {TimelineView} Chainable.
+         */
+        initModel: function () {
+            var model = registry.get(this.model);
+
+            model.on('scale', this.onScaleChange);
+            model.source.on('reloaded', this.onDataReloaded);
+
+            this.model = model;
+
+            return this;
+        },
+
+        /**
+         * Applies DOM watcher for the
+         * content element rendering.
+         *
+         * @returns {TimelineView} Chainable.
+         */
+        waitContent: function () {
+            $.async({
+                selector: this.selectors.content,
+                component: this.model
+            }, this.initContent);
+
+            return this;
+        },
+
+        /**
+         * Initializes timelines' content element.
+         *
+         * @param {HTMLElement} content
+         * @returns {TimelineView} Chainable.
+         */
+        initContent: function (content) {
+            this.$content = content;
+
+            $(content).on('scroll', this.onContentScroll);
+            $(window).on('resize', this.onWindowResize);
+
+            $.async(this.selectors.item, content, this.initItem);
+            $.async(this.selectors.event, content, this.onEventElementRender);
+            $.async(this.selectors.timeUnit, content, this.initTimeUnit);
+
+            this.refresh();
+
+            return this;
+        },
+
+        /**
+         * Initializes timeline item element,
+         * e.g. establishes event listeners and applies data bindings.
+         *
+         * @param {HTMLElement} elem
+         * @returns {TimelineView} Chainable.
+         */
+        initItem: function (elem) {
+            $(elem)
+                .bindings(this.getItemBindings)
+                .on('click', '._toend', this.onToEndClick)
+                .on('click', '._tostart', this.onToStartClick);
+
+            return this;
+        },
+
+        /**
+         * Initializes timeline unit element.
+         *
+         * @param {HTMLElement} elem
+         * @returns {TimelineView} Chainable.
+         */
+        initTimeUnit: function (elem) {
+            $(elem).bindings(this.getTimeUnitBindings());
+
+            return this;
+        },
+
+        /**
+         * Updates items positions in a
+         * loop if state of a view has changed.
+         */
+        refresh: function () {
+            raf(this.refresh);
+
+            if (this._update) {
+                this._update = false;
+
+                this.updateItemsPosition();
+            }
+        },
+
+        /**
+         * Returns object width additional bindings
+         * for a timeline unit element.
+         *
+         * @returns {Object}
+         */
+        getTimeUnitBindings: function () {
+            return {
+                style: {
+                    width: ko.computed(function () {
+                        return this.getTimeUnitWidth() + '%';
+                    }.bind(this))
+                }
+            };
+        },
+
+        /**
+         * Returns object with additional
+         * bindings for a timeline item element.
+         *
+         * @param {Object} ctx
+         * @returns {Object}
+         */
+        getItemBindings: function (ctx) {
+            return {
+                style: {
+                    width: ko.computed(function () {
+                        return this.getItemWidth(ctx.$row()) + '%';
+                    }.bind(this)),
+
+                    'margin-left': ko.computed(function () {
+                        return this.getItemMargin(ctx.$row()) + '%';
+                    }.bind(this))
+                }
+            };
+        },
+
+        /**
+         * Calculates width in percents of a timeline unit element.
+         *
+         * @returns {Number}
+         */
+        getTimeUnitWidth: function () {
+            return 100 / this.model.scale;
+        },
+
+        /**
+         * Calculates width of a record in percents.
+         *
+         * @param {Object} record
+         * @returns {String}
+         */
+        getItemWidth: function (record) {
+            var days = 0;
+
+            if (record) {
+                days = this.model.getDaysLength(record);
+            }
+
+            return this.getTimeUnitWidth()  * days;
+        },
+
+        /**
+         * Calculates left margin value for provided record.
+         *
+         * @param {Object} record
+         * @returns {String}
+         */
+        getItemMargin: function (record) {
+            var offset = 0;
+
+            if (record) {
+                offset = this.model.getStartDelta(record);
+            }
+
+            return this.getTimeUnitWidth() * offset;
+        },
+
+        /**
+         * Returns collection of currently available
+         * timeline item elements.
+         *
+         * @returns {Array<HTMLElement>}
+         */
+        getItems: function () {
+            var items = this.$content.querySelectorAll(this.selectors.item);
+
+            return _.toArray(items);
+        },
+
+        /**
+         * Updates positions of timeline elements.
+         *
+         * @returns {TimelineView} Chainable.
+         */
+        updateItemsPosition: function () {
+            this.getItems()
+                .forEach(this.updatePositionFor, this);
+
+            return this;
+        },
+
+        /**
+         * Updates position of provided timeline element.
+         *
+         * @param {HTMLElement} $elem
+         * @returns {TimelineView} Chainable.
+         */
+        updatePositionFor: function ($elem) {
+            var $event      = $elem.querySelector(this.selectors.event),
+                leftEdge    = this.getLeftEdgeFor($elem),
+                rightEdge   = this.getRightEdgeFor($elem);
+
+            if ($event) {
+                $event.style.left = Math.max(-leftEdge, 0) + 'px';
+                $event.style.right = Math.max(rightEdge, 0) + 'px';
+            }
+
+            toggleClass($elem, '_scroll-start', leftEdge < 0);
+            toggleClass($elem, '_scroll-end', rightEdge > 0);
+
+            return this;
+        },
+
+        /**
+         * Scrolls content area to the start of provided element.
+         *
+         * @param {HTMLElement} elem
+         * @returns {TimelineView}
+         */
+        toStartOf: function (elem) {
+            var leftEdge = this.getLeftEdgeFor(elem);
+
+            this.$content.scrollLeft += leftEdge;
+
+            return this;
+        },
+
+        /**
+         * Scrolls content area to the end of provided element.
+         *
+         * @param {HTMLElement} elem
+         * @returns {TimelineView}
+         */
+        toEndOf: function (elem) {
+            var rightEdge = this.getRightEdgeFor(elem);
+
+            this.$content.scrollLeft += rightEdge + 1;
+
+            return this;
+        },
+
+        /**
+         * Calculates location of the left edge of an element
+         * relative to the contents' left edge.
+         *
+         * @param {HTMLElement} elem
+         * @returns {Number}
+         */
+        getLeftEdgeFor: function (elem) {
+            var leftOffset = elem.getBoundingClientRect().left;
+
+            return leftOffset - this.$content.getBoundingClientRect().left;
+        },
+
+        /**
+         * Calculates location of the right edge of an element
+         * relative to the contents' right edge.
+         *
+         * @param {HTMLElement} elem
+         * @returns {Number}
+         */
+        getRightEdgeFor: function (elem) {
+            var elemWidth   = elem.offsetWidth,
+                leftEdge    = this.getLeftEdgeFor(elem);
+
+            return leftEdge + elemWidth - this.$content.offsetWidth;
+        },
+
+        /**
+         * 'To Start' button 'click' event handler.
+         *
+         * @param {jQueryEvent} event
+         */
+        onToStartClick: function (event) {
+            var elem = event.originalEvent.currentTarget;
+
+            event.stopPropagation();
+
+            this.toStartOf(elem);
+        },
+
+        /**
+         * 'To End' button 'click' event handler.
+         *
+         * @param {jQueryEvent} event
+         */
+        onToEndClick: function (event) {
+            var elem = event.originalEvent.currentTarget;
+
+            event.stopPropagation();
+
+            this.toEndOf(elem);
+        },
+
+        /**
+         * Handler of the scale value 'change' event.
+         */
+        onScaleChange: function () {
+            this._update = true;
+        },
+
+        /**
+         * Callback function which is invoked
+         * when event element was rendered.
+         */
+        onEventElementRender: function () {
+            this._update = true;
+        },
+
+        /**
+         * Window 'resize' event handler.
+         */
+        onWindowResize: function () {
+            this._update = true;
+        },
+
+        /**
+         * Content container 'scroll' event handler.
+         */
+        onContentScroll: function () {
+            this._update = true;
+        },
+
+        /**
+         * Data 'reload' event handler.
+         */
+        onDataReloaded: function () {
+            this._update = true;
+        }
+    });
+});
diff --git a/app/code/Magento/Ui/view/base/web/js/timeline/timeline.js b/app/code/Magento/Ui/view/base/web/js/timeline/timeline.js
new file mode 100644
index 0000000000000000000000000000000000000000..50ab80d3f1548376691a9e862b2a54fc14d92600
--- /dev/null
+++ b/app/code/Magento/Ui/view/base/web/js/timeline/timeline.js
@@ -0,0 +1,329 @@
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+define([
+    'underscore',
+    'moment',
+    'uiLayout',
+    'Magento_Ui/js/grid/listing'
+], function (_, moment, layout, Listing) {
+    'use strict';
+
+    var ONE_DAY = 86400000;
+
+    return Listing.extend({
+        defaults: {
+            recordTmpl: 'ui/timeline/record',
+            dateFormat: 'YYYY-MM-DD HH:mm:ss',
+            headerFormat: 'ddd MM/DD',
+            detailsFormat: 'DD/MM/YYYY HH:mm:ss',
+            scale: 7,
+            scaleStep: 1,
+            minScale: 7,
+            maxScale: 28,
+            minDays: 28,
+            displayMode: 'timeline',
+            displayModes: {
+                timeline: {
+                    label: 'Timeline',
+                    value: 'timeline',
+                    template: 'ui/timeline/timeline'
+                }
+            },
+            viewConfig: {
+                component: 'Magento_Ui/js/timeline/timeline-view',
+                name: '${ $.name }_view',
+                model: '${ $.name }'
+            },
+            tracks: {
+                scale: true
+            },
+            statefull: {
+                scale: true
+            },
+            range: {}
+        },
+
+        /**
+         * Initializes Timeline component.
+         *
+         * @returns {Timeline} Chainable.
+         */
+        initialize: function () {
+            this._super()
+                .initView()
+                .updateRange();
+
+            return this;
+        },
+
+        /**
+         * Initializes components configuration.
+         *
+         * @returns {Timeline} Chainable.
+         */
+        initConfig: function () {
+            this._super();
+
+            this.maxScale = Math.min(this.minDays, this.maxScale);
+            this.minScale = Math.min(this.maxScale, this.minScale);
+
+            return this;
+        },
+
+        /**
+         * Initializes observable properties.
+         *
+         * @returns {Timeline} Chainable.
+         */
+        initObservable: function () {
+            this._super()
+                .observe.call(this.range, true, 'hasToday');
+
+            return this;
+        },
+
+        /**
+         * Initializes TimelineView component.
+         *
+         * @returns {Timeline} Chainable.
+         */
+        initView: function () {
+            layout([this.viewConfig]);
+
+            return this;
+        },
+
+        /**
+         * Checks if provided event record is active,
+         * i.e. it has already started.
+         *
+         * @param {Object} record
+         * @returns {Boolean}
+         */
+        isActive: function (record) {
+            return record.status === 1;
+        },
+
+        /**
+         * Checks if provided event record is upcoming,
+         * i.e. it will start later on.
+         *
+         * @param {Object} record
+         * @returns {Boolean}
+         */
+        isUpcoming: function (record) {
+            return record.status === 2;
+        },
+
+        /**
+         * Checks if provided event record is permanent,
+         * i.e. it has no ending time.
+         *
+         * @param {Object} record
+         * @returns {Boolean}
+         */
+        isPermanent: function (record) {
+            return !this.getEndDate(record);
+        },
+
+        /**
+         * Checks if provided date indicates current day.
+         *
+         * @param {(Number|Moment)} date
+         * @returns {Boolenan}
+         */
+        isToday: function (date) {
+            return moment().isSame(date, 'day');
+        },
+
+        /**
+         * Checks if range object contains todays date.
+         *
+         * @returns {Boolean}
+         */
+        hasToday: function () {
+            return this.range.hasToday;
+        },
+
+        /**
+         * Returns start date of provided record.
+         *
+         * @param {Object} record
+         * @returns {String}
+         */
+        getStartDate: function (record) {
+            return record['start_time'];
+        },
+
+        /**
+         * Returns end date of provided record.
+         *
+         * @param {Object} record
+         * @returns {String}
+         */
+        getEndDate: function (record) {
+            return record['end_time'];
+        },
+
+        /**
+         * Returns difference in days between records' start date
+         * and a first day of a range.
+         *
+         * @param {Object} record
+         * @returns {Number}
+         */
+        getStartDelta: function (record) {
+            var start    = this.createDate(this.getStartDate(record)),
+                firstDay = this.range.firstDay;
+
+            return start.diff(firstDay, 'days', true);
+        },
+
+        /**
+         * Calculates the amount of days that provided event lasts.
+         *
+         * @param {Object} record
+         * @returns {Number}
+         */
+        getDaysLength: function (record) {
+            var start   = this.createDate(this.getStartDate(record)),
+                end     = this.createDate(this.getEndDate(record));
+
+            if (!end.isValid()) {
+                end = this.range.lastDay.endOf('day');
+            }
+
+            return end.diff(start, 'days', true);
+        },
+
+        /**
+         * Creates new date object based on provided date string value.
+         *
+         * @param {String} dateStr
+         * @returns {Moment}
+         */
+        createDate: function (dateStr) {
+            return moment(dateStr, this.dateFormat);
+        },
+
+        /**
+         * Converts days to weeks.
+         *
+         * @param {Number} days
+         * @returns {Number}
+         */
+        daysToWeeks: function (days) {
+            var weeks = days / 7;
+
+            if (weeks % 1) {
+                weeks = weeks.toFixed(1);
+            }
+
+            return weeks;
+        },
+
+        /**
+         * Updates data of a range object,
+         * e.g. total days, first day and last day, etc.
+         *
+         * @returns {Object} Range instance.
+         */
+        updateRange: function () {
+            var firstDay    = this._getFirstDay(),
+                lastDay     = this._getLastDay(),
+                totalDays   = lastDay.diff(firstDay, 'days'),
+                days        = [],
+                i           = -1;
+
+            if (totalDays < this.minDays) {
+                totalDays += this.minDays - totalDays - 1;
+            }
+
+            while (++i <= totalDays) {
+                days.push(+firstDay + ONE_DAY * i);
+            }
+
+            return _.extend(this.range, {
+                days:       days,
+                totalDays:  totalDays,
+                firstDay:   firstDay,
+                lastDay:    moment(_.last(days)),
+                hasToday:   this.isToday(firstDay)
+            });
+        },
+
+        /**
+         *
+         * @private
+         * @param {String} key
+         * @returns {Array<Moment>}
+         */
+        _getDates: function (key) {
+            var dates = [];
+
+            this.rows.forEach(function (record) {
+                if (record[key]) {
+                    dates.push(this.createDate(record[key]));
+                }
+            }, this);
+
+            return dates;
+        },
+
+        /**
+         * Returns date which is closest to the current day.
+         *
+         * @private
+         * @returns {Moment}
+         */
+        _getFirstDay: function () {
+            var dates = this._getDates('start_time'),
+                first = moment.min(dates).subtract(1, 'day'),
+                today = moment();
+
+            if (!first.isValid() || first < today) {
+                first = today;
+            }
+
+            return first.startOf('day');
+        },
+
+        /**
+         * Returns the most distant date
+         * specified in available records.
+         *
+         * @private
+         * @returns {Moment}
+         */
+        _getLastDay: function () {
+            var startDates  = this._getDates('start_time'),
+                endDates    = this._getDates('end_time'),
+                last        = moment.max(startDates.concat(endDates));
+
+            return last.add(1, 'day').startOf('day');
+        },
+
+        /**
+         * TODO: remove after integration with date binding.
+         *
+         * @param {Number} timestamp
+         * @returns {String}
+         */
+        formatHeader: function (timestamp) {
+            return moment(timestamp).format(this.headerFormat);
+        },
+
+        /**
+         * TODO: remove after integration with date binding.
+         *
+         * @param {String} date
+         * @returns {String}
+         */
+        formatDetails: function (date) {
+            return moment(date).format(this.detailsFormat);
+        }
+    });
+});
diff --git a/app/code/Magento/Ui/view/base/web/templates/grid/listing.html b/app/code/Magento/Ui/view/base/web/templates/grid/listing.html
index 702c07351767c8a56e44a549a794e79859feac22..d02233cbe07c250858b0b7552384ec48f5f93dd3 100644
--- a/app/code/Magento/Ui/view/base/web/templates/grid/listing.html
+++ b/app/code/Magento/Ui/view/base/web/templates/grid/listing.html
@@ -12,7 +12,7 @@
         <tbody>
             <tr class="data-row" repeat="foreach: rows, item: '$row'" css="'_odd-row': $index % 2">
                 <td outerfasteach="data: getVisible(), as: '$col'"
-                    css="getFieldClass()" click="getFieldHandler($row())" template="getBody()"/>
+                    css="getFieldClass($row())" click="getFieldHandler($row())" template="getBody()"/>
             </tr>
             <tr ifnot="hasData()" class="data-grid-tr-no-data">
                 <td attr="colspan: countVisible()" translate="'We couldn\'t find any records.'"/>
diff --git a/app/code/Magento/Ui/view/base/web/templates/grid/view-switcher.html b/app/code/Magento/Ui/view/base/web/templates/grid/view-switcher.html
new file mode 100644
index 0000000000000000000000000000000000000000..d5335e2f4a38d06e458c4a66f3149001c8c49d79
--- /dev/null
+++ b/app/code/Magento/Ui/view/base/web/templates/grid/view-switcher.html
@@ -0,0 +1,16 @@
+<!--
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+-->
+
+<div class="admin__action-dropdown-wrap admin__action-grid-select">
+    <select
+        class="admin__control-select"
+        options="getDisplayModes()"
+        ko-value="displayMode"
+        optionsValue="'value'"
+        optionsText="'label'"
+    />
+</div>
diff --git a/app/code/Magento/Ui/view/base/web/templates/timeline/record.html b/app/code/Magento/Ui/view/base/web/templates/timeline/record.html
new file mode 100644
index 0000000000000000000000000000000000000000..8376d20371f96f3d46dcb1ed80cfbabe7aafb138
--- /dev/null
+++ b/app/code/Magento/Ui/view/base/web/templates/timeline/record.html
@@ -0,0 +1,32 @@
+<!--
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+-->
+<div class="timeline-event">
+    <strong class="timeline-event-title" ko-scope="requestChild('name')">
+        <text args="getLabel($row())"/>
+    </strong>
+    <div class="timeline-event-info">
+        <div class="timeline-event-details"></div>
+        <div class="timeline-event-summary"></div>
+    </div>
+    <div class="timeline-event-actions">
+        <button type="button"
+                attr="title: $t('To Start')"
+                class="timeline-action _tostart"
+                disabled>
+            <span translate="'To Start'"/>
+        </button>
+        <button type="button"
+                attr="title: $t('To End')"
+                class="timeline-action _toend"
+                disabled>
+            <span translate="'To End'"/>
+        </button>
+    </div>
+    <svg>
+        <use class="timeline-ending" xlink:href="#svg-ending"></use>
+    </svg>
+</div>
diff --git a/app/code/Magento/Ui/view/base/web/templates/timeline/timeline.html b/app/code/Magento/Ui/view/base/web/templates/timeline/timeline.html
new file mode 100644
index 0000000000000000000000000000000000000000..32119fb185135def78676c36ec9ec5e5cb8abf6f
--- /dev/null
+++ b/app/code/Magento/Ui/view/base/web/templates/timeline/timeline.html
@@ -0,0 +1,97 @@
+<!--
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+-->
+<div class="timeline">
+    <svg
+        version="1.1"
+        xmlns="http://www.w3.org/2000/svg"
+        xmlns:xlink="http://www.w3.org/1999/xlink"
+        style="position: absolute; width: 0; height: 0;"
+        width="0"
+        height="0">
+        <defs>
+            <symbol id="svg-ending" viewBox="0 0 28 36">
+                <path
+                    class="g__timeline-ending"
+                    d="
+                        M2.864,0.456
+                        h1.189 l14.625,17.55
+                        L4.054,35.557
+                        H2.681"/>
+                <path
+                    class="g__timeline-arrow"
+                    fill="currentColor"
+                    d="
+                        M9.175,0.04
+                        h4.002l15.006,18.007
+                        L13.177,36.055
+                        H9.175 l15.006-18.008
+                        L9.175,0.04z"/>
+            </symbol>
+        </defs>
+    </svg>
+
+    <div class="timeline-content"
+         css="'_from-now': hasToday(),
+              '_no-records': !hasData()">
+        <div class="timeline-past" if="hasToday()">
+            <time class="timeline-date" translate="'Past'"/>
+        </div>
+        <ul class="timeline-units">
+            <li class="timeline-unit" repeat="foreach: updateRange().days, item: '$date'">
+                <div tooltip="
+                    trigger: '[data-tooltip-trigger=' + $index + ']',
+                    action: 'hover',
+                    delay: 300,
+                    track: true,
+                    position: 'top',
+                    closeButton: false
+                ">
+                    <text args="isToday($date()) ? $t('Today') \: formatHeader($date())"/>
+                </div>
+                <time attr="'data-tooltip-trigger': $index" class="timeline-date">
+
+                    <!-- NOTE: needs to be replaced by the date binding -->
+                    <text args="isToday($date()) ? $t('Today') \: formatHeader($date())"/>
+                </time>
+            </li>
+        </ul>
+        <ul class="timeline-items">
+            <if args="hasData()">
+                <li class="timeline-item"
+                    repeat="foreach: rows, item: '$row'"
+                    attr="'data-tooltip-search-scope': 'search-scope-' + $index"
+                    css="
+                        _active: isActive($row()),
+                        _permanent: isPermanent($row())
+                    "
+                    render="recordTmpl"/>
+            </if>
+
+            <ifnot args="hasData()">
+                <li class="timeline-item" data-role="no-data-msg">
+                    <div class="timeline-event">
+                        <span class="timeline-event-title"
+                                translate="'We couldn\'t find any records.'"/>
+                        <div class="timeline-event-info"/>
+                    </div>
+                </li>
+            </ifnot>
+        </ul>
+    </div>
+    <div class="timeline-scale">
+        <div class="data-slider"
+            range="
+                value: ko.getObservable($data, 'scale'),
+                min: minScale,
+                max: maxScale,
+                step: scaleStep
+            ">
+            <span class="data-slider-from" text="daysToWeeks(minScale) + 'w'"/>
+            <span class="data-slider-to" text="daysToWeeks(maxScale) + 'w'"/>
+        </div>
+    </div>
+</div>
diff --git a/app/code/Magento/Ui/view/base/web/templates/tooltip/tooltip.html b/app/code/Magento/Ui/view/base/web/templates/tooltip/tooltip.html
new file mode 100644
index 0000000000000000000000000000000000000000..1ce32807315c68a9977e39aff9e0e70fee6491f7
--- /dev/null
+++ b/app/code/Magento/Ui/view/base/web/templates/tooltip/tooltip.html
@@ -0,0 +1,17 @@
+<!--
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+-->
+<div data-tooltip="tooltip-wrapper" class="data-tooltip-wrapper">
+    <div class="data-tooltip-tail"></div>
+    <div class="data-tooltip">
+        <% if(data.closeButton){ %>
+            <button type="button" class="action-close">
+                <span translate="'Close'"/>
+            </button>
+        <% } %>
+        <div class="data-tooltip-content"></div>
+    </div>
+</div>
\ No newline at end of file
diff --git a/app/code/Magento/Ui/view/frontend/web/templates/form/element/select.html b/app/code/Magento/Ui/view/frontend/web/templates/form/element/select.html
index ae8b5d277bc0b4e60d2dc95e82f73c729756f9ee..e8ec20c9454d6d0034122ef05ee6bce62b645cd1 100644
--- a/app/code/Magento/Ui/view/frontend/web/templates/form/element/select.html
+++ b/app/code/Magento/Ui/view/frontend/web/templates/form/element/select.html
@@ -15,6 +15,7 @@
     hasFocus: focused,
     options: options,
     value: value,
+    optionsCaption: caption,
     optionsValue: 'value',
     optionsText: 'label',
     optionsAfterRender: function(option, item) {
diff --git a/app/code/Magento/Widget/Model/ResourceModel/Layout/Update.php b/app/code/Magento/Widget/Model/ResourceModel/Layout/Update.php
index ec04453079d143e696535f418ddcff3dcdf1e06b..a6cbd245bbaf09bbe586974d8573112cccb421aa 100644
--- a/app/code/Magento/Widget/Model/ResourceModel/Layout/Update.php
+++ b/app/code/Magento/Widget/Model/ResourceModel/Layout/Update.php
@@ -63,6 +63,7 @@ class Update extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb
         $bind = ['theme_id' => $theme->getId(), 'store_id' => $store->getId()];
         $cacheKey = implode('-', $bind);
         if (!isset($this->layoutUpdateCache[$cacheKey])) {
+            $this->layoutUpdateCache[$cacheKey] = [];
             foreach ($this->getConnection()->fetchAll($this->_getFetchUpdatesByHandleSelect(), $bind) as $layout) {
                 if (!isset($this->layoutUpdateCache[$cacheKey][$layout['handle']])) {
                     $this->layoutUpdateCache[$cacheKey][$layout['handle']] = '';
diff --git a/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/main/_actions-bar.less b/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/main/_actions-bar.less
index 9f7f851af125ae3acf3d5453e5036d9cd768f68f..0319bf6d6de1dc82fc8561ce14671f32a88e703e 100644
--- a/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/main/_actions-bar.less
+++ b/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/main/_actions-bar.less
@@ -51,7 +51,7 @@
             position: fixed;
             right: 0;
             top: 0;
-            z-index: @page-actions__fixed__z-index + 1;
+            z-index: @page-actions__fixed__z-index + 101;
 
             .page-actions-inner {
                 &:before {
diff --git a/app/design/adminhtml/Magento/backend/Magento_Staging/web/css/source/_module.less b/app/design/adminhtml/Magento/backend/Magento_Staging/web/css/source/_module.less
index eb86620c8bc15bff8c9e0e68134db7239722c9c6..74c2b190d33cb26aedccdd7eb4acab8476be0309 100644
--- a/app/design/adminhtml/Magento/backend/Magento_Staging/web/css/source/_module.less
+++ b/app/design/adminhtml/Magento/backend/Magento_Staging/web/css/source/_module.less
@@ -4,3 +4,4 @@
 //  */
 
 @import 'module/_scheduled-changes.less';
+@import 'module/_staging-data-tooltip.less';
diff --git a/app/design/adminhtml/Magento/backend/Magento_Staging/web/css/source/module/_staging-data-tooltip.less b/app/design/adminhtml/Magento/backend/Magento_Staging/web/css/source/module/_staging-data-tooltip.less
new file mode 100644
index 0000000000000000000000000000000000000000..636e97a6e220dda5eb542455324dabbe2d196e89
--- /dev/null
+++ b/app/design/adminhtml/Magento/backend/Magento_Staging/web/css/source/module/_staging-data-tooltip.less
@@ -0,0 +1,110 @@
+// /**
+//  * Copyright © 2015 Magento. All rights reserved.
+//  * See COPYING.txt for license details.
+//  */
+
+//
+//  Variables
+//  _____________________________________________
+
+@staging-events__border-color: @color-gray80;
+@staging-events-duration__color: @color-gray60;
+@staging-events-objects__background-color: @color-gray-darken0;
+@staging-events-objects__timeline__background-color: #86de00;
+@staging-events-objects__timeline__active__background-color: #77dcff;
+@staging-events-objects-icon: @icon-clip__content;
+
+//
+//  Extends
+//  _____________________________________________
+
+.abs-staging-events-item {
+    border-bottom: 1px solid @staging-events__border-color;
+    padding: 0 0 @indent__base;
+}
+
+.abs-staging-events-count-icon {
+    border-radius: 10px;
+    display: inline-block;
+    line-height: 2.4rem;
+    padding: 0 @indent__s;
+
+    &:before {
+        &:extend(.abs-icon all);
+        content: @staging-events-objects-icon;
+        display: inline-block;
+        font-size: 1.4rem;
+        margin-right: @indent__xs;
+    }
+}
+
+//
+//  Staging events tooltip
+//  _____________________________________________
+
+.staging-events-actions {
+    &:extend(.abs-staging-events-item all);
+    margin: @indent__s 0 0;
+    text-align: right;
+
+    .action-secondary {
+        margin-left: @indent__s;
+    }
+}
+
+.staging-events-summary {
+    &:extend(.abs-clearfix all);
+    &:extend(.abs-staging-events-item all);
+    margin: 0 0 1.5rem;
+
+    dt {
+        clear: left;
+        float: left;
+        font-weight: @font-weight__bold;
+        margin: 1.5rem 0 0;
+    }
+
+    dd {
+        float: left;
+        margin: 1.5rem 0 0 @indent__s;
+
+        span {
+            color: @staging-events-duration__color;
+        }
+    }
+}
+
+.staging-events-campaign {
+    &:extend(.abs-staging-events-item all);
+
+    .items {
+        margin-left: @indent__base;
+    }
+}
+
+.staging-events-campaign-objects {
+    margin: 0 0 @indent__s;
+}
+
+.staging-events-campaign-objects-count {
+    &:extend(.abs-staging-events-count-icon all);
+    background-color: @staging-events-objects__background-color;
+    margin-left: @indent__s;
+
+    .timeline-item & {
+        background: @staging-events-objects__timeline__background-color;
+    }
+
+    .timeline-item._active & {
+        background: @staging-events-objects__timeline__active__background-color;
+    }
+}
+
+.staging-events-delete {
+    margin-top: @indent__s;
+    text-align: right;
+
+    .action-delete {
+        font-weight: @font-weight__regular;
+    }
+}
diff --git a/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/module/_data-grid.less b/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/module/_data-grid.less
index 13041211345720db9f1123d042c3c5186ca478dc..550b67b017e0775632619ee380e7a19e3272b398 100644
--- a/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/module/_data-grid.less
+++ b/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/module/_data-grid.less
@@ -92,7 +92,6 @@ body._in-resize {
     border: none;
     font-size: @data-grid__font-size;
     margin-bottom: 0;
-    max-width: 100%;
     width: 100%;
 
     &:not(._dragging-copy) {
@@ -136,10 +135,33 @@ body._in-resize {
         &._odd-row {
             td {
                 background-color: @data-grid-td__even__background-color;
+
+                &._update-status-active {
+                    background: @data-grid-td__odd__update__active__background-color;
+                }
+
+                &._update-status-upcoming {
+                    background: @data-grid-td__odd__update__upcoming__background-color;
+                }
+            }
+        }
+
+        &:hover {
+            td {
+                &._update-status-active,
+                &._update-status-upcoming {
+                    background-color: @data-grid-tr__hover__background-color;
+                }
             }
         }
 
         &.data-grid-tr-no-data {
+            td {
+                font-size: @data-grid__no-records__font-size;
+                padding: @data-grid__no-records__padding;
+                text-align: center;
+            }
+
             &:hover {
                 td {
                     background-color: @data-grid-td__odd__background-color;
@@ -273,6 +295,14 @@ body._in-resize {
             top: auto;
             z-index: 1;
         }
+
+        &._update-status-active {
+            background: @data-grid-td__update__active__background-color;
+        }
+
+        &._update-status-upcoming {
+            background: @data-grid-td__update__upcoming__background-color;
+        }
     }
 
     th {
@@ -958,6 +988,7 @@ body._in-resize {
                 transform: rotate(45deg);
                 width: 1.6rem;
                 z-index: 3;
+
                 .ie9 & {
                     display: none;
                 }
diff --git a/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/module/data-grid/data-grid-header/_data-grid-filters.less b/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/module/data-grid/data-grid-header/_data-grid-filters.less
index 87ebe43c580a762955343ad6e1b4a9b424a010ab..c4dbb1bc3cce64c897887ebafe443396741107c4 100644
--- a/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/module/data-grid/data-grid-header/_data-grid-filters.less
+++ b/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/module/data-grid/data-grid-header/_data-grid-filters.less
@@ -171,6 +171,14 @@
     }
 }
 
+.admin__action-grid-select {
+    .admin__control-select {
+        margin: .5rem .5rem 0 0;
+        padding-bottom: .6rem;
+        padding-top: .6rem;
+    }
+}
+
 //
 //  Filters content
 //  ---------------------------------------------
diff --git a/app/design/adminhtml/Magento/backend/web/css/source/_classes.less b/app/design/adminhtml/Magento/backend/web/css/source/_classes.less
index a3ba1fb0ccb81c3d6fbe1d0dd974f70cbe48eeb0..e57c2123be76f24206ec485bb50eecc47337b814 100644
--- a/app/design/adminhtml/Magento/backend/web/css/source/_classes.less
+++ b/app/design/adminhtml/Magento/backend/web/css/source/_classes.less
@@ -16,7 +16,7 @@
 }
 
 //  Text align classes
-.a-center { //  ToDo UI: should be renamed to ._text-center
+.a-center { // ToDo UI: should be renamed to ._text-center
     text-align: center;
 }
 
diff --git a/app/design/adminhtml/Magento/backend/web/css/source/_components.less b/app/design/adminhtml/Magento/backend/web/css/source/_components.less
index 32bb4dffbe8bb446a51e28685268ac06b73de81b..a3c0be3a5c52a91def110952529b264a1268ea3f 100644
--- a/app/design/adminhtml/Magento/backend/web/css/source/_components.less
+++ b/app/design/adminhtml/Magento/backend/web/css/source/_components.less
@@ -12,7 +12,10 @@
 @import 'components/_messages.less';
 @import 'components/_popups.less';
 @import 'components/_modals.less';
+@import 'components/_data-tooltip.less';
 @import 'components/_modals_extend.less';
+@import 'components/_timeline.less';
 @import 'components/_file-insertion.less';
 @import 'components/_media-gallery.less';
 @import 'components/_file-uploader.less';
+@import 'components/_slider.less';
diff --git a/app/design/adminhtml/Magento/backend/web/css/source/_extends.less b/app/design/adminhtml/Magento/backend/web/css/source/_extends.less
index b0919740ace5c14108c38a32f60153c3682f8ade..15b3e111ccbddcfb0e677d45d8a0890ac94d59b1 100644
--- a/app/design/adminhtml/Magento/backend/web/css/source/_extends.less
+++ b/app/design/adminhtml/Magento/backend/web/css/source/_extends.less
@@ -14,9 +14,9 @@
 .abs-icon {
     -webkit-font-smoothing: antialiased;
     font-family: @icons-admin__font-name;
-    line-height: 1;
     font-style: normal;
     font-weight: normal;
+    line-height: 1;
     speak: none;
 }
 
diff --git a/app/design/adminhtml/Magento/backend/web/css/source/_grid.less b/app/design/adminhtml/Magento/backend/web/css/source/_grid.less
index cc7e52c85b10d4fc88374cdb1992637dd1561cab..24dc0be17af5c485a1a901d2fc8663d7b3b9eea7 100644
--- a/app/design/adminhtml/Magento/backend/web/css/source/_grid.less
+++ b/app/design/adminhtml/Magento/backend/web/css/source/_grid.less
@@ -11,6 +11,7 @@
 
 @grid-columns: 12;
 @grid-gutter-width: 0;
+
 //
 //  Row
 //  ---------------------------------------------
diff --git a/app/design/adminhtml/Magento/backend/web/css/source/actions/_actions-select.less b/app/design/adminhtml/Magento/backend/web/css/source/actions/_actions-select.less
index abf88e5b06c4f7b2571edcb2284daa2854df96cb..7483caefc70c4856cfcd67d72ac5afd519d34312 100644
--- a/app/design/adminhtml/Magento/backend/web/css/source/actions/_actions-select.less
+++ b/app/design/adminhtml/Magento/backend/web/css/source/actions/_actions-select.less
@@ -18,11 +18,12 @@
 
     .action-select {
         .action-toggle-triangle(
-            @_dropdown__padding-right: @_action-select-toggle__size;
-            @_triangle__height: @button-marker-triangle__height;
-            @_triangle__width: @button-marker-triangle__width;
+        @_dropdown__padding-right: @_action-select-toggle__size;
+        @_triangle__height: @button-marker-triangle__height;
+        @_triangle__width: @button-marker-triangle__width;
         );
         .lib-text-overflow-ellipsis();
+
         background-color: @color-white;
         font-weight: @font-weight__regular;
         text-align: left;
diff --git a/app/design/adminhtml/Magento/backend/web/css/source/actions/_actions-split.less b/app/design/adminhtml/Magento/backend/web/css/source/actions/_actions-split.less
index d37c101112a9e8d7b6cff671de171cc8f16102f9..3525c536c891caf02ac34330ba7b58a9855e8ead 100644
--- a/app/design/adminhtml/Magento/backend/web/css/source/actions/_actions-split.less
+++ b/app/design/adminhtml/Magento/backend/web/css/source/actions/_actions-split.less
@@ -72,6 +72,7 @@
     .action-default {
         float: left;
         margin: 0;
+
         &.active,
         &._active,
         &:hover {
@@ -86,9 +87,9 @@
 
     .action-toggle {
         .action-toggle-triangle(
-            @_dropdown__padding-right: @_action-toggle__width;
-            @_triangle__height: @button-marker-triangle__height;
-            @_triangle__width: @button-marker-triangle__width;
+        @_dropdown__padding-right: @_action-toggle__width;
+        @_triangle__height: @button-marker-triangle__height;
+        @_triangle__width: @button-marker-triangle__width;
         );
         border-left-color: rgba(0, 0, 0, .2);
         bottom: 0;
diff --git a/app/design/adminhtml/Magento/backend/web/css/source/components/_data-tooltip.less b/app/design/adminhtml/Magento/backend/web/css/source/components/_data-tooltip.less
new file mode 100644
index 0000000000000000000000000000000000000000..2b5c581c95a6b2ceb15876eb974450dac0417eb5
--- /dev/null
+++ b/app/design/adminhtml/Magento/backend/web/css/source/components/_data-tooltip.less
@@ -0,0 +1,147 @@
+// /**
+//  * Copyright © 2015 Magento. All rights reserved.
+//  * See COPYING.txt for license details.
+//  */
+
+//
+//  Variables
+//  _____________________________________________
+
+@data-tooltip__background-color: @color-white;
+@data-tooltip__border-color: #007dbd;
+@data-tooltip__border-width: 1px;
+@data-tooltip__box-shadow: 2px 2px 8px 0 rgba(0,0,0,0.3);
+@data-tooltip__z-index: @overlay__z-index - 1;
+
+@data-tooltip-tail__height: 22px;
+@data-tooltip-tail__width: @data-tooltip-tail__height;
+@data-tooltip-tail__z-index: @z-index-1;
+
+//
+//  Tooltip
+//  _____________________________________________
+.data-tooltip-trigger {
+    cursor: pointer;
+}
+
+.data-tooltip-wrapper {
+    position: absolute;
+    top: 0;
+    z-index: @data-tooltip__z-index;
+
+    &._top {
+        .data-tooltip-tail {
+            display: block;
+            left: 50%;
+            margin-left: -@data-tooltip-tail__width / 2;
+            top: -(@data-tooltip-tail__height / 2 - @data-tooltip__border-width);
+        }
+    }
+
+    &._right {
+        .data-tooltip-tail {
+            display: block;
+            margin-top: -@data-tooltip-tail__width / 2;
+            right: @data-tooltip-tail__height / 2 + @data-tooltip__border-width;
+            top: 50%;
+        }
+    }
+
+    &._bottom {
+        .data-tooltip-tail {
+            bottom: @data-tooltip-tail__height / 2 + @data-tooltip__border-width;
+            display: block;
+            left: 50%;
+            margin-left: -@data-tooltip-tail__width / 2;
+        }
+    }
+
+    &._left {
+        .data-tooltip-tail {
+            display: block;
+            left: -(@data-tooltip-tail__height / 2 - @data-tooltip__border-width);
+            top: 50%;
+            margin-top: -@data-tooltip-tail__width / 2;
+        }
+    }
+
+    &._show {
+        height: auto;
+        opacity: 1;
+        transition: opacity .2s linear;
+    }
+
+    &._hide {
+        height: 0;
+        opacity: 0;
+        overflow: hidden;
+    }
+}
+
+.data-tooltip {
+    background-color: @data-tooltip__background-color;
+    border: @data-tooltip__border-width solid @data-tooltip__border-color;
+    box-shadow: @data-tooltip__box-shadow;
+    padding: @indent__base;
+    position: relative;
+    z-index: @data-tooltip-tail__z-index;
+
+    .action-close {
+        position: absolute;
+        right: @indent__base;
+        top: @indent__base;
+
+        &:focus {
+            background: none;
+        }
+    }
+}
+
+.data-tooltip-title {
+    font-size: 1.7rem;
+    font-weight: @font-weight__semibold;
+    margin: 0 @indent__base @indent__base 0;
+}
+
+.data-tooltip-content {
+    .items {
+        &:extend(.abs-list-reset-styles all);
+        .item {
+            margin: 0 0 1rem;
+            &:last-child {
+                margin-bottom: 0;
+            }
+        }
+    }
+}
+
+.data-tooltip-tail {
+    display: none;
+    position: absolute;
+
+    &:before {
+        background-color: @data-tooltip__background-color;
+        border: @data-tooltip__border-width solid @data-tooltip__border-color;
+        box-shadow: @data-tooltip__box-shadow;
+        content: '';
+        height: @data-tooltip-tail__height;
+        left: 0;
+        position: absolute;
+        top: 0;
+        transform: rotate(45deg);
+        width: @data-tooltip-tail__width;
+        z-index: @data-tooltip-tail__z-index - 1;
+    }
+
+    &:after {
+        background-color: @data-tooltip__background-color;
+        content: '';
+        height: @data-tooltip-tail__height - @data-tooltip__border-width * 2;
+        left: @data-tooltip__border-width;
+        position: absolute;
+        top: @data-tooltip__border-width;
+        transform: rotate(45deg);
+        width: @data-tooltip-tail__width - @data-tooltip__border-width * 2;
+        z-index: @data-tooltip-tail__z-index + 1;
+    }
+}
diff --git a/app/design/adminhtml/Magento/backend/web/css/source/components/_messages.less b/app/design/adminhtml/Magento/backend/web/css/source/components/_messages.less
index 40685017be652d670b4b69cf1aca083453161c6d..7583743ff9cbb6fd82823c648ad9ed6c1149a3ae 100644
--- a/app/design/adminhtml/Magento/backend/web/css/source/components/_messages.less
+++ b/app/design/adminhtml/Magento/backend/web/css/source/components/_messages.less
@@ -49,8 +49,8 @@
 
 .message {
     background: @alert__background-color;
-    border: none;
     border-radius: 0;
+    border: none;
     color: @alert__color;
     font-size: @alert__font-size;
     margin: 0 0 1px;
diff --git a/app/design/adminhtml/Magento/backend/web/css/source/components/_modals_extend.less b/app/design/adminhtml/Magento/backend/web/css/source/components/_modals_extend.less
index 0c20dc19e02e357415c048fa3e93dae60439cd36..cad3d7ab04e73181dc8b7c53c6e6b6e9e158c083 100644
--- a/app/design/adminhtml/Magento/backend/web/css/source/components/_modals_extend.less
+++ b/app/design/adminhtml/Magento/backend/web/css/source/components/_modals_extend.less
@@ -125,14 +125,14 @@
         padding: @modal-popup__padding @modal-popup__padding;
 
         &:active{
-            padding-top: @modal-popup__padding + (@modal-action-close__font-size - @modal-action-close__active__font-size) / 3;
             padding-right: @modal-popup__padding + (@modal-action-close__font-size - @modal-action-close__active__font-size) / 3;
+            padding-top: @modal-popup__padding + (@modal-action-close__font-size - @modal-action-close__active__font-size) / 3;
         }
     }
 
     .modal-footer {
-        text-align: right;
         padding-top: @modal-slide__padding;
+        text-align: right;
 
         .action-primary {
             &:extend(.abs-action-secondary all);
@@ -159,9 +159,9 @@
 
 .modal-slide {
     .modal-content-new-attribute {
+        -webkit-overflow-scrolling: touch;
         overflow: auto;
         padding-bottom: 0;
-        -webkit-overflow-scrolling: touch;
 
         iframe {
             margin-bottom: -@indent__m;
@@ -177,14 +177,14 @@
         padding: @modal-slide-header__padding-vertical @modal-slide__padding;
 
         &:active {
-            padding-top: @modal-slide-header__padding-vertical + (@modal-action-close__font-size - @modal-action-close__active__font-size) / 2;
             padding-right: @modal-slide__padding + (@modal-action-close__font-size - @modal-action-close__active__font-size) / 2;
+            padding-top: @modal-slide-header__padding-vertical + (@modal-action-close__font-size - @modal-action-close__active__font-size) / 2;
         }
     }
 
     .page-main-actions {
-        margin-top: @modal-slide-header__padding-vertical;
         margin-bottom: @modal-slide-header__padding-vertical - @page-main-actions__padding;
+        margin-top: @modal-slide-header__padding-vertical;
     }
 
     .magento_message {
diff --git a/app/design/adminhtml/Magento/backend/web/css/source/components/_popups.less b/app/design/adminhtml/Magento/backend/web/css/source/components/_popups.less
index 62cc8ab3776535241edd91b8cf329c5f3ccc9015..977789ba0ed8ec54e072ef79361c39e924c1a95f 100644
--- a/app/design/adminhtml/Magento/backend/web/css/source/components/_popups.less
+++ b/app/design/adminhtml/Magento/backend/web/css/source/components/_popups.less
@@ -160,65 +160,65 @@
     .ui-resizable-n {
         cursor: n-resize;
         height: 7px;
-        width: 100%;
-        top: -5px;
         left: 0;
+        top: -5px;
+        width: 100%;
     }
 
     .ui-resizable-s {
+        bottom: 0;
         cursor: s-resize;
         height: 7px;
-        width: 100%;
-        bottom: 0;
         left: 0;
+        width: 100%;
     }
 
     .ui-resizable-e {
         cursor: e-resize;
-        width: 7px;
+        height: 100%;
         right: 0;
         top: 0;
-        height: 100%;
+        width: 7px;
     }
 
     .ui-resizable-w {
         cursor: w-resize;
-        width: 7px;
+        height: 100%;
         left: -7px;
         top: 0;
-        height: 100%;
+        width: 7px;
     }
 
     .ui-resizable-se {
+        bottom: 1px;
         cursor: se-resize;
-        width: 12px;
         height: 12px;
         right: 1px;
-        bottom: 1px;
+        width: 12px;
     }
 
     .ui-resizable-sw {
+        bottom: 0;
         cursor: sw-resize;
-        width: 9px;
         height: 9px;
         left: -5px;
-        bottom: 0;
+        width: 9px;
     }
 
     .ui-resizable-nw {
         cursor: nw-resize;
-        width: 9px;
         height: 9px;
         left: -5px;
         top: -5px;
+        width: 9px;
     }
 
     .ui-resizable-ne {
         cursor: ne-resize;
-        width: 9px;
         height: 9px;
         right: 0;
         top: -5px;
+        width: 9px;
     }
 
     //
@@ -279,8 +279,8 @@
             }
 
             input {
-                border: none;
                 -moz-transform: none;
+                border: none;
                 opacity: 1;
                 position: static;
             }
@@ -562,13 +562,13 @@
 
     .popup {
         background: @popup__background-color;
-        border: 0;
         border-radius: 0;
+        border: 0;
         display: inline-block;
         left: 12.5%;
         position: absolute;
-        top: 5rem;
         text-align: left;
+        top: 5rem;
         width: 75%;
 
         .close {
diff --git a/app/design/adminhtml/Magento/backend/web/css/source/components/_slider.less b/app/design/adminhtml/Magento/backend/web/css/source/components/_slider.less
new file mode 100644
index 0000000000000000000000000000000000000000..1678cc6b5a8a266b13c4d20a7a8bc851be918e6d
--- /dev/null
+++ b/app/design/adminhtml/Magento/backend/web/css/source/components/_slider.less
@@ -0,0 +1,96 @@
+// /**
+//  * Copyright © 2015 Magento. All rights reserved.
+//  * See COPYING.txt for license details.
+//  */
+
+//
+//  Variables
+//  _____________________________________________
+
+@data-slider-track__background-color: @color-gray-light3;
+@data-slider-track__font-size: 1.1rem;
+@data-slider-track__height: .1rem;
+@data-slider-track__width: 100%;
+@data-slider-track__z-index: @z-index-1;
+
+@data-slider-handle__background-color: @color-white-smoke;
+@data-slider-handle__border-color: @color-gray76;
+@data-slider-handle__box-shadow: 0 1px 2px 2px rgba(0, 0, 0, .03);
+@data-slider-handle__height: 2.2rem;
+@data-slider-handle__width: @data-slider-handle__height;
+
+@data-slider-handle-accent__background-color__end: @color-white-fog;
+@data-slider-handle-accent__background-color__start: @color-gray-light2;
+@data-slider-handle-accent__height: .8rem;
+@data-slider-handle-accent__width: @data-slider-handle-accent__height;
+
+//
+//  Slider
+//  _____________________________________________
+
+.data-slider {
+    &:extend(.abs-clearfix all);
+    background: none;
+    font-size: @data-slider-track__font-size;
+    min-height: @data-slider-handle__height;
+    padding-top: 1.2rem;
+    position: relative;
+    width: @data-slider-track__width;
+
+    &:before {
+        background: @data-slider-track__background-color;
+        content: '';
+        display: block;
+        height: @data-slider-track__height;
+        position: absolute;
+        top: 0;
+        width: 100%;
+        z-index: @data-slider-track__z-index;
+    }
+
+    .ui-slider-handle {
+        .data-slider-handle;
+    }
+}
+
+.data-slider-from {
+    float: left;
+}
+
+.data-slider-to {
+    float: right;
+}
+
+.data-slider-handle {
+    background: @data-slider-handle__background-color;
+    border-radius: 50%;
+    border: 1px solid @data-slider-handle__border-color;
+    box-shadow: @data-slider-handle__box-shadow;
+    cursor: pointer;
+    display: block;
+    height: @data-slider-handle__height;
+    margin-left: -@data-slider-handle__width / 2 !important;
+    position: absolute;
+    top: -@data-slider-handle__height / 2;
+    width: @data-slider-handle__width;
+    z-index: @data-slider-track__z-index + 1 !important;
+
+    &:before {
+        .lib-background-gradient(
+        @_background-gradient: true,
+        @_background-gradient-direction: vertical,
+        @_background-gradient-color-start: @data-slider-handle-accent__background-color__start,
+        @_background-gradient-color-end: @data-slider-handle-accent__background-color__end,
+        @_background-gradient-color-position: false
+        );
+        border-radius: 50%;
+        content: '';
+        display: block;
+        height: @data-slider-handle-accent__height;
+        left: 50%;
+        margin: -@data-slider-handle-accent__height / 2 0 0 -@data-slider-handle-accent__width / 2;
+        position: absolute;
+        top: 50%;
+        width: @data-slider-handle-accent__width;
+    }
+}
diff --git a/app/design/adminhtml/Magento/backend/web/css/source/components/_timeline.less b/app/design/adminhtml/Magento/backend/web/css/source/components/_timeline.less
new file mode 100644
index 0000000000000000000000000000000000000000..c9652436008b9f9659bbe0d15d1ebba291514e54
--- /dev/null
+++ b/app/design/adminhtml/Magento/backend/web/css/source/components/_timeline.less
@@ -0,0 +1,423 @@
+// /**
+//  * Copyright © 2015 Magento. All rights reserved.
+//  * See COPYING.txt for license details.
+//  */
+
+//
+//  Variables
+//  _____________________________________________
+
+@timeline__background-color: @color-white-fog2;
+@timeline__border-color: @color-gray60;
+@timeline__margin-top: @indent__base;
+@timeline__scale: 1;
+@timeline__no-records__background-color: @color-white;
+
+@timeline-item__height: 3.6rem;
+@timeline-unit__width: 100%/7;
+
+@timeline-event__background-color: #ccf391;
+@timeline-event__border-color: #81c21d;
+@timeline-event__active__background-color: #bceeff;
+@timeline-event__active__border-color: #56c2e6;
+@timeline-event__active__permanent__color: @color-blue-pure;
+@timeline-event__no-records__background-color: transparent;
+@timeline-event__no-records__border-color: transparent;
+@timeline-event__no-records__color: @color-gray20;
+
+@timeline-action__color: #76c004;
+@timeline-action__active__color: #56c2e6;
+
+@timeline-summary__background-color: #86de00;
+@timeline-summary__active__background-color: #79dcff;
+
+@timeline-legend__color: @color-very-dark-gray;
+@timeline-past__boder-color: fade(@color-tomato-brick, 55);
+
+@timeline-date__background-color: @color-white;
+@timeline-date__color: @color-very-dark-gray-black;
+@timeline-date__padding: 1rem .3rem;
+
+@timeline-priority-scale__color: @color-gray80;
+
+//
+//  Timeline
+//  ---------------------------------------------
+
+.timeline {
+    &:extend(.abs-clearer);
+    margin-top: @timeline__margin-top;
+    position: relative;
+    z-index: 1;
+}
+
+.timeline-content {
+    background: @timeline__background-color;
+    border: 1px solid @timeline__border-color;
+    margin-bottom: @indent__base;
+    overflow-x: scroll;
+    overflow-y: hidden;
+    position: relative;
+
+    &._from-now {
+        padding-left: 50px;
+    }
+
+    &._no-records {
+        background: @timeline__no-records__background-color;
+    }
+}
+
+.timeline-past {
+    background: linear-gradient(to left, fade(@color-white, 0.1), fade(@color-white, 50) 25%, @color-white);
+    border-right: 2px solid @timeline-past__boder-color;
+    height: 100%;
+    left: 0;
+    position: absolute;
+    top: 0;
+    width: 50px;
+    z-index: 3;
+}
+
+.timeline-scale {
+    float: right;
+    width: 160px;
+}
+
+.timeline-legend {
+    float: left;
+}
+
+.timeline-legend-item {
+    color: @timeline-legend__color;
+    display: inline-block;
+    line-height: 2rem;
+    vertical-align: middle;
+
+    &:before {
+        border: 1px solid @timeline__border-color;
+        content: '';
+        display: inline-block;
+        height: 2rem;
+        margin-right: 5px;
+        vertical-align: middle;
+        width: 2rem;
+    }
+
+
+    &._update-status-active,
+    &._active {
+        &:before {
+            background: @timeline-event__active__background-color;
+        }
+    }
+
+
+    &._update-status-upcoming,
+    &._upcoming {
+        &:before {
+            background: @timeline-event__background-color;
+        }
+    }
+}
+
+//
+//  Timeline items
+//  ---------------------------------------------
+
+.timeline-items {
+    .extend__list-reset-styles();
+    min-height: @timeline-item__height * 7;
+    position: relative;
+}
+
+.timeline-item {
+    height: @timeline-item__height;
+    position: relative;
+    z-index: 2;
+
+    & + .timeline-item {
+        margin-top: -1px;
+    }
+
+    ._no-records & {
+        margin-top: -@timeline-item__height;
+        position: absolute;
+        top: 50%;
+        width: 100%;
+    }
+}
+
+.timeline-event {
+    .lib-vendor-prefix-display(flex);
+    background: @timeline-event__background-color;
+    border: 1px solid @timeline-event__border-color;
+    cursor: pointer;
+    height: @timeline-item__height;
+    left: -1px;
+    overflow: hidden;
+    padding: 0 @indent__s;
+    position: absolute;
+    right: 0;
+    white-space: nowrap;
+    width: auto;
+    min-width: 5.5rem;
+
+    ._permanent._active &,
+    ._no-records & {
+        justify-content: center;
+        text-align: center;
+    }
+
+    ._permanent._active & {
+        color: @timeline-event__active__permanent__color;
+    }
+
+    .timeline-item._active & {
+        background: @timeline-event__active__background-color;
+        border-color: @timeline-event__active__border-color;
+    }
+
+    ._scroll-start:not(._active) & {
+        padding-left: @indent__l;
+    }
+
+    ._scroll-end & {
+        padding-right: @indent__l;
+    }
+
+    ._permanent & {
+        margin-right: 23px;
+        overflow: visible;
+    }
+
+    ._no-records & {
+        background: @timeline-event__no-records__background-color;
+        border-color: @timeline-event__no-records__border-color;
+        color: @timeline-event__no-records__color;
+        cursor: default;
+    }
+}
+
+.timeline-event-title {
+    .lib-vendor-prefix-flex-shrink(1);
+    display: inline-block;
+    font-weight: @font-weight__semibold;
+    line-height: 3.4rem;
+    max-width: 100%;
+    min-width: 2.2rem;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+
+    ._no-records & {
+        font-weight: @font-weight__regular;
+    }
+}
+
+.timeline-event-info {
+    display: inline-block;
+    line-height: 3.4rem;
+    vertical-align: top;
+}
+
+.timeline-event-details {
+    display: none;
+}
+
+.timeline-action {
+    bottom: 0;
+    display: none;
+    margin: auto;
+    position: absolute;
+    right: 10px;
+    top: 0;
+
+    > span {
+        .hidden();
+    }
+
+    &:extend(.abs-action-reset all);
+    &:active {
+        .scale();
+    }
+
+    &:before {
+        &:extend(.abs-icon all);
+        .transition(color);
+        color: @timeline-action__color;
+        content: @icon-arrow-right__content;
+        font-size: 1.8rem;
+    }
+
+    &:hover {
+        cursor: pointer;
+        text-decoration: none;
+    }
+
+    .timeline-item._active & {
+        &:before {
+            color: @timeline-action__active__color;
+        }
+    }
+
+    &._tostart {
+        left: 10px;
+        right: auto;
+
+        &:before {
+            content: @icon-arrow-left__content;
+        }
+
+        .timeline-item._scroll-start:not(._active) & {
+            display: block;
+        }
+    }
+
+    &._toend {
+        .timeline-item._scroll-end & {
+            display: block;
+        }
+
+        .timeline-item._permanent & {
+            display: none;
+        }
+    }
+}
+
+//
+//  Timeline svg endings
+//  ---------------------------------------------
+
+svg {
+    .timeline-event & {
+        display: none;
+        height: 3.6rem;
+        margin-right: -2.4rem;
+        position: absolute;
+        right: 0;
+        top: -1px;
+        width: 2.8rem;
+    }
+    ._permanent .timeline-event & {
+        display: block;
+    }
+}
+
+//  Initial symbol styles
+.svg__timeline-ending {
+    fill: inherit;
+    stroke: inherit;
+}
+
+.svg__timeline-arrow {
+    stroke: transparent;
+}
+
+//  Context symbol use styles
+.timeline-ending {
+    color: @timeline-summary__background-color;
+    fill: @timeline-event__background-color;
+    stroke: @timeline-event__border-color;
+
+    .timeline-item._active & {
+        color: @timeline-summary__active__background-color;
+        fill: @timeline-event__active__background-color;
+        stroke: @timeline-event__active__border-color;
+    }
+}
+
+//
+//  Timeline units row
+//  ---------------------------------------------
+
+.timeline-units {
+    .extend__list-reset-styles();
+    font-size: 0;
+    white-space: nowrap;
+}
+
+.timeline-unit {
+    border-right: 1px solid @timeline__border-color;
+    display: inline-block;
+    list-style-type: none;
+    margin: 0;
+    padding: 0;
+    width: @timeline-unit__width/@timeline__scale;
+
+    &:last-child {
+        border-right: 0;
+    }
+
+    &:before {
+        background-image: repeating-linear-gradient(
+                180deg,
+                transparent,
+                transparent 5px,
+                #3e4040 5px,
+                #3e4040 6px,
+                #979999 6px,
+                #979999 7px
+        );
+        bottom: 0;
+        content: '';
+        margin-left: -1px;
+        position: absolute;
+        top: @font-size__tiny + 2rem + .2rem;
+        width: 1px;
+        z-index: 0;
+    }
+
+    &:first-child {
+        &:before {
+            content: none;
+        }
+    }
+
+    ._no-records & {
+        &:before {
+            display: none;
+        }
+    }
+}
+
+.timeline-date {
+    background: @timeline-date__background-color;
+    border-bottom: 1px solid @timeline__border-color;
+    color: @timeline-date__color;
+    display: block;
+    font-size: @font-size__tiny;
+    line-height: 1;
+    max-width: 100%;
+    overflow: hidden;
+    padding: @timeline-date__padding;
+    text-align: center;
+    text-overflow: ellipsis;
+}
+
+//
+//  Priority scale
+//  ---------------------------------------------
+
+.timeline-priority {
+    float: left;
+    font-size: 1.1rem;
+    font-weight: @font-weight__semibold;
+    margin-right: 1.8rem;
+    margin-top: @timeline__margin-top;
+    text-align: center;
+}
+
+.timeline-priority-title {
+    font-weight: @font-weight__bold;
+    padding: @timeline-date__padding;
+}
+
+.timeline-priority-scale {
+    border-left: 7px solid transparent;
+    border-right: 7px solid transparent;
+    border-top: 210px solid @timeline-priority-scale__color;
+    height: 0;
+    margin: @indent__xs auto;
+    width: 0;
+}
diff --git a/app/design/adminhtml/Magento/backend/web/css/source/forms/_controls.less b/app/design/adminhtml/Magento/backend/web/css/source/forms/_controls.less
index edc4b256ab710c621465a52f324641890285cdfb..0cc96e4570b2d851764b13f4cf8c658e0fa7959e 100644
--- a/app/design/adminhtml/Magento/backend/web/css/source/forms/_controls.less
+++ b/app/design/adminhtml/Magento/backend/web/css/source/forms/_controls.less
@@ -25,12 +25,13 @@
     color: @field-control__color;
     font-size: @field-control__font-size;
     font-weight: @font-weight__regular;
-    line-height: @field-control__line-height;
     height: auto;
-    width: auto;
+    line-height: @field-control__line-height;
     padding: @field-control__padding-top @field-control__padding-horizontal @field-control__padding-bottom;
     transition: @smooth__border-color;
     vertical-align: baseline;
+    width: auto;
+    -webkit-appearance: none;
 }
 
 .__form-control-pattern__hover() {
@@ -47,8 +48,8 @@
     background-color: @field-control__disabled__background-color;
     border-color: @field-control__border-color;
     color: @field-control__color;
-    opacity: @disabled__opacity;
     cursor: not-allowed;
+    opacity: @disabled__opacity;
 }
 
 //  Input text styles
@@ -181,8 +182,8 @@ option:empty {
     display: inline-block;
     font-size: @field-control__font-size;
     line-height: @field-control__line-height;
-    padding-top: @field-control__padding-top;
     padding-bottom: @field-control__padding-bottom;
+    padding-top: @field-control__padding-top;
 
     + [class*='admin__control-'] {
         margin-left: @action__outer-indent;
@@ -248,9 +249,9 @@ option:empty {
         .lib-vendor-prefix-flex-grow(1);
         .lib-vendor-prefix-order(1);
         .lib-vendor-prefix-flex-shrink(1);
-        box-shadow: none;
         background-color: transparent;
         border-color: transparent;
+        box-shadow: none;
         vertical-align: top;
 
         & + [class*='admin__control-'] {
diff --git a/app/design/adminhtml/Magento/backend/web/css/source/forms/_fields.less b/app/design/adminhtml/Magento/backend/web/css/source/forms/_fields.less
index 14a48da5ba8ce12399a62fe62022d14a469f381c..9ddbe53660df0ef0e540b32605f6a0333332ac7e 100644
--- a/app/design/adminhtml/Magento/backend/web/css/source/forms/_fields.less
+++ b/app/design/adminhtml/Magento/backend/web/css/source/forms/_fields.less
@@ -732,10 +732,10 @@
 
     &:extend(.abs-fieldset-legend);
     & + br {
+        clear: left;
         display: block;
         height: 0;
         overflow: hidden;
-        clear: left;
     }
 }
 
diff --git a/app/design/adminhtml/Magento/backend/web/css/source/forms/_temp.less b/app/design/adminhtml/Magento/backend/web/css/source/forms/_temp.less
index d8944b4a19f23d0c2cde6529a4537eb37f194101..e4b33238b2c60fc0025240b2eda6161ff150a7f2 100644
--- a/app/design/adminhtml/Magento/backend/web/css/source/forms/_temp.less
+++ b/app/design/adminhtml/Magento/backend/web/css/source/forms/_temp.less
@@ -61,7 +61,7 @@
 // @todo ui Move to other place - will be done in upcoming task "Address Tabs":
 
 .address-item-edit-content {
-    background: #fff;
+    background: @color-white;
     border: 1px solid #dad1c8;
     box-shadow: 0 2px 1px 0 rgba(217, 210, 202, .5);
     margin-left: 359px;
@@ -100,7 +100,7 @@
         z-index: 1;
 
         &.ui-state-active {
-            background: #fff;
+            background: @color-white;
             box-shadow: 0 1px 1px 0 rgba(217, 210, 202, 1);
             margin-left: -2px;
             padding-left: 12px;
@@ -109,8 +109,8 @@
 
             &:before,
             &:after {
-                color: #fff;
-                content: "\e02a";
+                color: @color-white;
+                content: '\e02a';
                 font-family: 'MUI-Icons';
                 font-size: 18px;
                 font-style: normal;
@@ -178,25 +178,25 @@
                 color: darken(@color-brown-darkie, 20%);
             }
 
-            // @todo ui - testing solution to show action hint without title attribute
+            //  @Todo ui - testing solution to show action hint without title attribute
             span {
                 background-color: @color-very-light-gray;
-                border: 1px solid @color-heathered-grey;
                 border-radius: .4rem;
+                border: 1px solid @color-heathered-grey;
                 bottom: 100%;
                 clip: auto;
                 font-size: @font-size__s;
                 height: auto;
                 left: auto;
                 margin: 0 auto .1rem;
+                max-height: 50px;
+                max-width: 200px;
                 padding: .5rem;
                 right: auto;
                 top: auto;
-                max-height: 50px;
-                max-width: 200px;
+                transition: all .01s linear .7s;
                 white-space: nowrap;
                 width: auto;
-                transition: all .01s linear .7s;
             }
         }
     }
@@ -215,14 +215,13 @@ label.mage-error {
     &:extend(.admin__field-error);
 }
 
-
 //
 //  Login page captcha reload @todo ui - remove after loader consistency
 //  _____________________________________________
 
 .page-layout-admin-login {
     .loading-mask {
-        background: rgba(255,255,255,0.2);
+        background: rgba(255,255,255,.2);
         height: 100%;
         left: 0;
         position: absolute;
@@ -236,9 +235,9 @@ label.mage-error {
         left: 50%;
         margin-left: -218px/2;
         margin-top: -149px/2;
+        overflow: hidden;
         position: absolute;
         top: 50%;
-        overflow: hidden;
         width: 218px;
     }
 }
@@ -279,16 +278,16 @@ label.mage-error {
     .data-grid-filters {
         td {
             padding: 1rem;
-            border-bottom: 1px solid #D6D6D6;
+            border-bottom: 1px solid @color-gray84;
         }
 
         select,
         input[type="text"]{
-            width: 100%;
-            padding: .2rem .4rem;
+            font-size: 1.3rem;
             height: 2.8rem;
             min-width: 5rem;
-            font-size: 1.3rem;
+            padding: .2rem .4rem;
+            width: 100%;
         }
 
         .admin__control-text {
@@ -348,11 +347,11 @@ label.mage-error {
 
 .mass-select-info {
     &:before {
-        content: "(";
+        content: '(';
     }
 
     &:after {
-        content:")";
+        content: ')';
     }
 
     &._empty {
@@ -361,33 +360,33 @@ label.mage-error {
 }
 
 .mass-select-wrap {
+    margin-left: 1.1rem;
+    margin-top: 3.3rem;
     position: absolute;
     top: 100%;
-    margin-top: 3.3rem;
-    margin-left: 1.1rem;
 
     select {
-        position:absolute;
-        top: 0;
+        cursor: pointer;
+        height: 22px;
         left: 0;
         opacity: 0.01;
+        position:absolute;
+        top: 0;
         width: 22px;
-        height: 22px;
-        cursor: pointer;
         z-index: 2;
 
         + label {
             &:extend(.abs-action-default);
-            z-index: 1;
-            width: 16px;
             height: 16px;
             line-height: 16px;
             padding: 0;
+            width: 16px;
+            z-index: 1;
 
             &:before {
                 &:extend(.admin__control-checkbox + label:before);
-                position:absolute;
                 left: 0;
+                position: absolute;
                 top: 0;
             }
 
@@ -427,8 +426,8 @@ label.mage-error {
             display: none;
 
             + label {
-                opacity: .6;
                 cursor: not-allowed;
+                opacity: .6;
             }
         }
     }
@@ -494,10 +493,10 @@ label.mage-error {
             display: inline;
 
             .admin__field-label {
-                width: auto;
                 float: none;
-                padding-right: 1rem;
                 padding-left: 2rem;
+                padding-right: 1rem;
+                width: auto;
             }
         }
 
@@ -517,7 +516,7 @@ label.mage-error {
         }
 
         .admin__control-select-placeholder {
-            color:  @color-darkie-gray;
+            color: @color-darkie-gray;
             font-weight: @font-weight__bold;
         }
     }
@@ -578,14 +577,13 @@ label.mage-error {
     td.col-action {
         a + a {
             &:before {
-                content: "";
+                content: '';
                 display: block;
             }
         }
     }
 }
 
-
 //
 //  Popups
 //  _____________________________________________
diff --git a/app/design/adminhtml/Magento/backend/web/css/source/forms/controls/_checkbox-radio.less b/app/design/adminhtml/Magento/backend/web/css/source/forms/controls/_checkbox-radio.less
index 0d24d5b3f4dfa829c1eadb10291b5a4af4aae051..7ada1bf14c45dcadfd8382383a837ab3adf7711e 100644
--- a/app/design/adminhtml/Magento/backend/web/css/source/forms/controls/_checkbox-radio.less
+++ b/app/design/adminhtml/Magento/backend/web/css/source/forms/controls/_checkbox-radio.less
@@ -58,8 +58,8 @@
     &.disabled,
     &[disabled] {
         + label {
-            cursor: default;
             color: @field-control__color;
+            cursor: default;
             opacity: .5;
 
             &:before {
diff --git a/app/design/adminhtml/Magento/backend/web/css/source/forms/fields/_control-table.less b/app/design/adminhtml/Magento/backend/web/css/source/forms/fields/_control-table.less
index 037358833e9a74155a3d74163a1d548c8001296d..c2c19596bad5fc200bb3e00de03333bb17b73d92 100644
--- a/app/design/adminhtml/Magento/backend/web/css/source/forms/fields/_control-table.less
+++ b/app/design/adminhtml/Magento/backend/web/css/source/forms/fields/_control-table.less
@@ -106,10 +106,10 @@
     }
 
     th {
-        vertical-align: bottom;
         color: @color-very-dark-gray-black;
         font-size: @font-size__base;
         font-weight: @font-weight__semibold;
+        vertical-align: bottom;
 
         &._required {
             span {
diff --git a/app/design/adminhtml/Magento/backend/web/css/source/utilities/_grid-framework.less b/app/design/adminhtml/Magento/backend/web/css/source/utilities/_grid-framework.less
index f8e535f0099cabcb62df168788591b200726449c..23cec5cd0a796b9d995d17ece6eb2476e65e1aaf 100644
--- a/app/design/adminhtml/Magento/backend/web/css/source/utilities/_grid-framework.less
+++ b/app/design/adminhtml/Magento/backend/web/css/source/utilities/_grid-framework.less
@@ -59,7 +59,7 @@
         }
     }
 
-    .col(1); //  Kickstart it
+    .col(1); // Kickstart it
 }
 
 .calc-grid-column(@index, @class, @type) when (@type = width) and (@index > 0) {
@@ -99,7 +99,6 @@
 }
 
 //  Basic looping in LESS
-
 .loop-grid-columns(@index, @class, @type) when (@index >= 0) {
     .calc-grid-column(@index, @class, @type);
     //  Next iteration
@@ -107,7 +106,6 @@
 }
 
 //  Create grid for specific class
-
 .make-grid(@class) {
     .float-grid-columns(@class);
     .loop-grid-columns(@grid-columns, @class, width);
diff --git a/app/design/adminhtml/Magento/backend/web/css/source/utilities/_grid.less b/app/design/adminhtml/Magento/backend/web/css/source/utilities/_grid.less
index 0a6a4d33c2acab776405375756c363a73fd5fbd0..bba3bcd2ce407323652188142900712da9e02c0a 100644
--- a/app/design/adminhtml/Magento/backend/web/css/source/utilities/_grid.less
+++ b/app/design/adminhtml/Magento/backend/web/css/source/utilities/_grid.less
@@ -12,7 +12,6 @@
 //  ---------------------------------------------
 
 //  Centered container element
-
 .container-fixed(@gutter: @grid-gutter-width) {
     margin-right: auto;
     margin-left: auto;
@@ -22,7 +21,6 @@
 }
 
 //  Creates a wrapper for a series of columns
-
 .make-row(@gutter: @grid-gutter-width) {
     margin-left: (@gutter / -2);
     margin-right: (@gutter / -2);
@@ -34,12 +32,12 @@
 //  ---------------------------------------------
 
 .make-xs-column(@columns; @gutter: @grid-gutter-width) {
-    position: relative;
     float: left;
-    width: percentage((@columns / @grid-columns));
     min-height: 1px;
     padding-left: (@gutter / 2);
     padding-right: (@gutter / 2);
+    position: relative;
+    width: percentage((@columns / @grid-columns));
 }
 
 .make-xs-column-offset(@columns) {
@@ -59,10 +57,10 @@
 //  ---------------------------------------------
 
 .make-m-column(@columns; @gutter: @grid-gutter-width) {
-    position: relative;
     min-height: 1px;
     padding-left: (@gutter / 2);
     padding-right: (@gutter / 2);
+    position: relative;
 
     .media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__m) {
         float: left;
@@ -93,10 +91,10 @@
 //  ---------------------------------------------
 
 .make-l-column(@columns; @gutter: @grid-gutter-width) {
-    position: relative;
     min-height: 1px;
     padding-left: (@gutter / 2);
     padding-right: (@gutter / 2);
+    position: relative;
 
     .media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__l) {
         float: left;
@@ -127,10 +125,10 @@
 //  ---------------------------------------------
 
 .make-xl-column(@columns; @gutter: @grid-gutter-width) {
-    position: relative;
     min-height: 1px;
     padding-left: (@gutter / 2);
     padding-right: (@gutter / 2);
+    position: relative;
 
     @media (min-width: @screen__xl) {
         float: left;
diff --git a/app/design/adminhtml/Magento/backend/web/css/source/variables/_data-grid.less b/app/design/adminhtml/Magento/backend/web/css/source/variables/_data-grid.less
index bea044357cfe43bc8f50b868f3f1901ded4ddbf8..c2d5bda0ad12af4817af444b006a7c13c8b0935b 100644
--- a/app/design/adminhtml/Magento/backend/web/css/source/variables/_data-grid.less
+++ b/app/design/adminhtml/Magento/backend/web/css/source/variables/_data-grid.less
@@ -25,6 +25,10 @@
 @data-grid-td__odd__background-color: @page__background-color;
 @data-grid-td__odd__dragging__background-color: @color-gray85;
 @data-grid-td__odd__edit__background-color: darken(@data-grid-td__odd__background-color, 10%);
+@data-grid-td__update__active__background-color: #bceeff;
+@data-grid-td__update__upcoming__background-color: #ccf391;
+@data-grid-td__odd__update__active__background-color: darken(@data-grid-td__update__active__background-color, 10%);
+@data-grid-td__odd__update__upcoming__background-color: darken(@data-grid-td__update__upcoming__background-color, 10%);
 
 @data-grid-th__border-color: @color-darkie-gray;
 @data-grid-th__border-style: solid;
@@ -58,6 +62,9 @@
 
 @data-grid-spinner__size: 4rem;
 
+@data-grid__no-records__font-size: @font-size__l;
+@data-grid__no-records__padding: @indent__l;
+
 //  Header
 
 @data-grid-header-add-indent__bottom: .9rem;
diff --git a/app/design/adminhtml/Magento/backend/web/css/source/variables/_icons.less b/app/design/adminhtml/Magento/backend/web/css/source/variables/_icons.less
index d74f83d42f69eead63a422b765b859e4880ab46a..adc7265a64930ed37a2d2e1df8d7d2d533c381bf 100644
--- a/app/design/adminhtml/Magento/backend/web/css/source/variables/_icons.less
+++ b/app/design/adminhtml/Magento/backend/web/css/source/variables/_icons.less
@@ -77,3 +77,4 @@
 @icon-screen__content: '\e640';
 @icon-video__content: '\e641';
 @icon-reset__content: '\e642';
+@icon-clip__content: '\e643';
diff --git a/app/design/adminhtml/Magento/backend/web/css/source/variables/_structure.less b/app/design/adminhtml/Magento/backend/web/css/source/variables/_structure.less
index 083ad9571fb767f061c4565ec4c534fb29a269fa..e488f091227a4ebc440e654304060891c30eaa5f 100644
--- a/app/design/adminhtml/Magento/backend/web/css/source/variables/_structure.less
+++ b/app/design/adminhtml/Magento/backend/web/css/source/variables/_structure.less
@@ -29,7 +29,6 @@
 @data-grid-header__z-index: @z-index-3;
 
 //  z-index 4
-@header__z-index: @z-index-4;
 @page-actions__fixed__z-index: @z-index-4;
 @data-grid-overlay__z-index: @z-index-4;
 @data-grid-sticky-header__z-index: @page-actions__fixed__z-index - 2;
@@ -37,6 +36,7 @@
 @actions-split__z-index: @data-grid-overlay__z-index + 1;
 
 //  z-index 5
+@header__z-index: @z-index-5;
 @field-tooltip__z-index: @z-index-5;
 @action-select__z-index: @z-index-5;
 @admin__page-nav-tooltip__z-index: @field-tooltip__z-index;
diff --git a/app/design/adminhtml/Magento/backend/web/css/styles-old.less b/app/design/adminhtml/Magento/backend/web/css/styles-old.less
index 5032d5ee130cf28901ebab25426b1f3c9ec83f61..af70d1088e1eb89bb48e0dac99e8d5c160873410 100644
--- a/app/design/adminhtml/Magento/backend/web/css/styles-old.less
+++ b/app/design/adminhtml/Magento/backend/web/css/styles-old.less
@@ -50,7 +50,7 @@
         &:not(.admin__field-label) {
             :after {
                 content: '*';
-                color: red;
+                color: #f00;
                 margin-left: 3px;
             }
         }
@@ -2580,7 +2580,7 @@
 
     //
     //  Customer
-    //  ---------------------------------------
+    //  ---------------------------------------------
 
     #customer_info_tabs_account_content #_accountsendemail {
         margin-top: 8px;
@@ -2607,37 +2607,55 @@
     }
 
     .customer-information address {
-        padding-top: 4px;
-        line-height: 2.2;
         float: right;
+        line-height: 2.2;
+        padding-top: 4px;
     }
 
     .address-list {
+        float: left;
         list-style: none;
-        width: 278px;
         margin: 0 0 10px;
         padding: 0;
-        float: left;
+        width: 278px;
     }
 
     //
-    //      Configuration -> Design
-    //  --------------------------------------
+    //  Configuration -> Design
+    //  ---------------------------------------------
 
-    #row_design_theme_ua_regexp .design_theme_ua_regexp {
-        float: left;
-        width: 100%;
-    }
-    #row_design_theme_ua_regexp .tooltip {
-        margin-top: 8px;
+    #row_design_theme_ua_regexp {
+        .design_theme_ua_regexp {
+            float: left;
+            width: 100%;
+        }
+
+        .tooltip {
+            margin-top: 8px;
+        }
+
+        .note {
+            clear: both;
+        }
     }
-    #row_design_theme_ua_regexp .note {
-        clear: both;
+
+    .form-list {
+        .small-image-preview {
+            display: inline-block;
+            margin: 0 @indent__xs 0 0;
+            vertical-align: middle;
+        }
+
+        .delete-image {
+            display: block;
+            margin: @indent__xs 0;
+            white-space: nowrap;
+        }
     }
 
     //
-    //      Configuration -> Advanced -> System -> Notifications section
-    //  --------------------------------------
+    //  Configuration -> Advanced -> System -> Notifications section
+    //  ---------------------------------------------
 
     #row_system_adminnotification_last_update {
         .value {
@@ -2647,7 +2665,7 @@
 
     //
     //  CMS -> Banners
-    //  --------------------------------------
+    //  ---------------------------------------------
 
     // Banner Properties
     #banner_properties_customer_segment_ids {
@@ -2656,7 +2674,7 @@
 
     //
     //  CMS -> Manage Hierarchy
-    //  --------------------------------------
+    //  ---------------------------------------------
 
     .cms-hierarchy .cms-scope {
         float: right;
@@ -2708,7 +2726,7 @@
 
     //
     //  CMS -> Widgets
-    //  --------------------------------------
+    //  ---------------------------------------------
 
     #widget_instace_tabs_properties_section_content .widget-option-label {
         margin-top: 6px;
@@ -5156,7 +5174,7 @@
 @media print {
     * {
         background: transparent !important;
-        color: black !important;
+        color: #000 !important;
         box-shadow: none !important;
         text-shadow: none !important;
         filter: none !important;
diff --git a/app/design/adminhtml/Magento/backend/web/fonts/admin-icons/admin-icons.eot b/app/design/adminhtml/Magento/backend/web/fonts/admin-icons/admin-icons.eot
old mode 100644
new mode 100755
index 75a4d833e5d1043a9ae56560bc87e058054537b0..cf4f06eac28466279457da61230f868b5e0ac141
Binary files a/app/design/adminhtml/Magento/backend/web/fonts/admin-icons/admin-icons.eot and b/app/design/adminhtml/Magento/backend/web/fonts/admin-icons/admin-icons.eot differ
diff --git a/app/design/adminhtml/Magento/backend/web/fonts/admin-icons/admin-icons.svg b/app/design/adminhtml/Magento/backend/web/fonts/admin-icons/admin-icons.svg
old mode 100644
new mode 100755
index 6829ccdc528ab71a8f7df53a496603502eb73b59..c03ead846ae961c52cdf44b4ada364236a7f74a6
--- a/app/design/adminhtml/Magento/backend/web/fonts/admin-icons/admin-icons.svg
+++ b/app/design/adminhtml/Magento/backend/web/fonts/admin-icons/admin-icons.svg
@@ -1 +1 @@
-<svg xmlns="http://www.w3.org/2000/svg"><metadata>Generated by IcoMoon</metadata><defs><font id="icomoon" horiz-adv-x="1024"><font-face units-per-em="1024" ascent="960" descent="-64"/><missing-glyph horiz-adv-x="1024"/><glyph unicode=" " horiz-adv-x="512" d=""/><glyph unicode="&#58880;" glyph-name="account" horiz-adv-x="1090" d="M709.921 801.306c8.139-32.295 8.927-34.974 8.192-68.162-0.263-12.813-7.772-71.943-5.724-90.112 1.628-14.966 5.461-16.174 11.448-28.514 10.398-21.425 6.984-51.095 2.941-72.678-2.206-11.868-6.827-28.725-13.916-38.387-7.667-10.66-23.211-10.713-30.142-23.158-9.872-17.854-4.306-43.008-10.503-62.385-7.142-21.898-25.101-23.421-26.466-52.145 8.822-1.155 17.592-2.468 26.466-3.623 8.822-18.59 25.049-55.874 41.59-67.059 13.863-3.728 27.727-7.457 41.59-11.185 48.627-19.64 102.558-43.061 151.237-63.33 44.373-18.432 97.411-24.996 113.48-70.84 0-31.035 2.941-104.501 2.153-145.25h-965.553c-0.893 40.697 2.153 114.215 2.153 145.25 15.964 45.844 69.002 52.408 113.375 70.84 48.679 20.27 102.61 43.691 151.237 63.33 13.811 3.728 27.674 7.457 41.59 11.185 16.489 11.185 32.715 48.522 41.538 67.059l19.692 4.621c-4.464 24.576-19.85 26.466-26.256 43.743-2.521 26.099-5.041 52.145-7.509 78.192 0.053-1.155-18.117 3.361-20.48 4.779-25.731 15.806-26.204 80.24-28.725 107.021-1.103 12.183 16.174 22.265 11.343 44.636-28.094 131.44 12.183 192.88 75.881 213.307 44.216 17.749 126.871 50.465 203.855 3.728l19.167-17.487 30.93-5.251c15.491-8.77 25.416-38.124 25.416-38.124z"/><glyph unicode="&#58881;" glyph-name="arrowdown" horiz-adv-x="1085" d="M529.203 73.86l-468.465 628.209h936.931l-468.465-628.209z"/><glyph unicode="&#58882;" glyph-name="cms" horiz-adv-x="1034" d="M976.793-22.006h-910.388v910.388h910.388v-910.388zM912.622 824.211h-782.046v-782.088h782.046v782.088zM221.432 137.2h152.876v372.033h-152.876v-372.033zM466.323 139.766h350.932v366.53h-350.932v-366.53zM221.432 599.511h595.865v147.125h-595.865v-147.125z"/><glyph unicode="&#58883;" glyph-name="customers" horiz-adv-x="489" d="M264.319 651.169c75.685 0 136.98 61.259 136.98 136.944 0 75.649-61.295 136.98-136.98 136.98s-137.017-61.331-137.017-136.98c0-75.649 61.331-136.944 137.017-136.944zM448.929 589.149c-28.962 28.926-63.325 46.252-187.655 46.252s-157.859-18.776-185.335-46.252c-27.44-27.44-18.196-320.43-18.196-320.43l60.824 144.411 38.241-430.334 110.23 220.278 102.907-220.278 36.393 430.334 60.824-144.411c-0.036 0 10.693 291.468-18.233 320.43z"/><glyph unicode="&#58884;" glyph-name="dashboard" horiz-adv-x="1376" d="M680.975 886.272c-337.523 0-610.976-273.515-611.038-610.976 0.122-37.72 1.039-251.812 1.039-251.812h1219.997c0 0 0.978 239.219 1.039 251.812-0.183 337.523-273.637 610.976-611.038 610.976zM737.708 762.169c31.117-3.607 61.379-10.271 90.418-19.624l-19.93-61.685c-25.004 8.070-51.169 13.939-78.191 16.995l7.703 64.313zM270.091 286.85h-64.864c0 31.423 3.118 62.235 8.803 92.007l63.702-12.349c-5.135-25.799-7.642-52.392-7.642-79.658zM305.855 455.581l-59.178 26.288c12.655 28.489 28 55.449 45.79 80.636l52.942-37.475c-15.284-21.825-28.611-45.056-39.554-69.449zM407.46 594.845l-43.405 48.113c22.925 20.541 47.807 39.187 74.462 54.96l33.318-55.571c-22.987-13.755-44.567-29.65-64.374-47.501zM536.943 742.545c29.039 9.292 59.178 16.017 90.418 19.624l7.581-64.313c-26.838-3.057-53.003-8.926-78.13-16.995l-19.869 61.685zM761.673 158.468l-152.897-27.205-38.881 150.452 395.172 404.22-203.394-527.467zM1019.476 525.029l52.942 37.414c17.79-25.187 33.257-52.148 45.851-80.636l-59.178-26.288c-10.943 24.454-24.209 47.685-39.615 69.51zM1094.916 286.85c0 27.266-2.69 53.859-7.703 79.658l63.702 12.349c5.808-29.834 8.803-60.645 8.803-92.007h-64.802zM646.006 189.341c26.777-17.056 62.174-9.415 79.291 17.24 17.118 26.593 9.292 62.051-17.301 79.108-26.655 17.24-62.051 9.354-79.23-17.362-17.118-26.349-9.476-61.99 17.24-78.986z"/><glyph unicode="&#58885;" glyph-name="filter" d="M24.097 846.535h972.827v-111.922l-410.504-412.792v-238.366l-171.447-87.505v325.871l-390.875 415.877v108.837z"/><glyph unicode="&#58886;" glyph-name="logo" horiz-adv-x="903" d="M454.495 911.101l-402.697-240.513v-457.026l104.632-60.727v457.049l298.157 178.728 299.698-179.142-0.138-455.922 103.528 60.013v457.026l-403.18 240.513zM507.766 629.72v-534.344l-53.271-32.124-53.34 32.262v533.792l-138.090-83.853v-456.934l191.453-115.516 193.087 116.322v456.451l-139.839 83.945z"/><glyph unicode="&#58887;" glyph-name="notification-02" horiz-adv-x="989" d="M870.821 228.163c-64.195 65.89-78.231 188.772-91.738 283.159-20.074 139.937-24.259 297.089-226.008 317.693v25.318c0 25.424-39.195 46.028-64.937 46.028s-62.024-20.551-62.024-46.028v-25.371c-200.054-20.816-206.993-177.914-226.855-317.693-13.453-94.439-27.331-217.268-91.049-283.264-12.818-13.348-16.473-32.998-9.11-49.947 7.362-16.843 24.153-27.913 42.797-27.913h695.343c18.75 0 35.593 11.070 42.903 28.019s3.655 36.653-9.322 50zM489.569-3.883c51.060 0 92.373 40.837 92.373 91.367h-184.694c-0.053-50.53 41.314-91.367 92.32-91.367z"/><glyph unicode="&#58888;" glyph-name="product" horiz-adv-x="954" d="M252.137 806.772l-160.070-92.393 378.042-218.205 160.023 92.393-377.996 218.205zM845.638 712.937l-377.996 218.252-145.222-83.828 377.996-218.205 145.222 83.782zM502.784 433.85v-433.664l376.832 217.507v433.711l-376.832-217.553zM55.668 217.74l376.785-217.507v436.503l-376.785 217.46v-436.457z"/><glyph unicode="&#58889;" glyph-name="promotions" horiz-adv-x="1170" d="M59.153 425.818l164.053-38.141v303.902l-164.053-38.141v-227.621zM1122.198 900.847l-837.712-194.959v-335.978l140.328-376.832 151.712 57.45-104.049 279.113 649.668-151.18v722.385z"/><glyph unicode="&#58890;" glyph-name="reports" horiz-adv-x="991" d="M736.707-21.234h207.134v322.703h-207.134v-322.703zM399.646-21.234h207.134v946.793h-207.134v-946.793zM62.673-21.19h207.134v634.704h-207.134v-634.704z"/><glyph unicode="&#58891;" glyph-name="sales" horiz-adv-x="659" d="M426.502 347.483c-15.866 13.512-42.796 25.753-80.79 36.723v-198.774c11.535 1.459 23.729 4.331 36.299 8.851 12.618 4.426 23.87 10.829 33.804 19.068 9.981 8.427 18.173 18.55 24.529 30.649 6.638 12.006 9.651 26.365 9.651 42.89 0.047 26.836-7.721 47.222-23.493 60.593zM576.736 223.144c-7.109-23.117-19.774-45.762-38.135-67.749-18.503-22.175-43.079-41.855-74.010-58.992-30.885-17.373-70.432-27.683-118.878-31.12v-88.088h-57.014v88.088c-72.080 5.603-128.483 29.237-169.113 71.374-40.536 42.090-63.935 104.095-70.432 185.544h136.251c-0.753-39.359 8.992-70.479 28.86-93.266 20.15-22.74 44.774-37.335 74.434-43.455v216.523c-3.060 1.318-7.486 2.919-12.994 4.567-5.508 1.789-11.393 3.343-17.938 4.708-23.776 6.827-47.175 15.019-70.291 24.294-23.493 9.369-44.114 21.704-62.523 37.335-18.456 15.584-33.098 34.84-43.879 57.956-11.111 23.211-16.478 51.977-16.478 86.487 0 35.31 6.168 66.336 18.785 93.313 12.665 26.836 29.143 49.529 49.858 67.702 20.621 18.314 44.303 32.58 71.468 42.419 27.071 10.122 55.037 16.149 83.992 18.314v79.66h57.014v-79.66c29.143-3.531 56.308-10.169 81.638-20.292 25.423-10.028 47.787-23.729 67.137-41.478 19.585-17.514 35.357-39.453 47.457-65.771 12.288-26.13 19.35-57.109 21.28-93.172h-137.287c-0.518 27.636-8.616 51.082-23.917 70.432-15.725 19.303-34.275 29.002-56.308 29.002v-183.331c7.862-2.072 15.631-4.143 23.729-6.12 8.098-2.072 16.525-4.567 25.565-7.297 47.645-13.983 84.415-31.12 110.168-51.318 25.8-20.292 44.726-41.666 56.92-63.653 12.335-22.175 19.633-44.256 21.704-66.336 2.448-22.081 3.531-41.713 3.531-59.039 0.047-15.207-3.531-34.416-10.593-57.579zM228.905 696.585c-8.38-7.156-15.113-16.196-19.962-26.883-4.802-10.781-7.062-23.352-7.062-37.759 0-22.834 6.733-40.536 20.103-52.824 13.653-12.618 35.734-22.552 66.713-30.131v168.831c-10.829 0-21.516-1.695-31.826-5.226-10.216-3.437-19.633-8.851-27.966-16.007z"/><glyph unicode="&#58892;" glyph-name="search" horiz-adv-x="1109" d="M555.139 938.358c-218.775 71.601-457.062-40.29-532.231-250.028-75.227-209.681 41.211-437.665 259.928-509.208 218.717-71.601 457.004 40.348 532.231 250.028s-41.211 437.665-259.928 509.208zM320.076 282.955c-158.915 52.089-243.467 217.681-188.903 369.978 54.679 152.296 227.754 233.625 386.669 181.593s243.409-217.624 188.788-369.92c-54.622-152.296-227.696-233.567-386.554-181.65zM638.482 274.206l358.927-349.602 24.807 69.241 24.865 69.241-310.348 302.29z"/><glyph unicode="&#58893;" glyph-name="stores" horiz-adv-x="1280" d="M1098.281 874.55c19.777 3.723 34.901 21.232 34.901 42.347-0.058 23.791-19.196 43.103-42.812 43.103h-900.508c-23.675 0-42.754-19.312-42.754-43.103 0-21.057 15.007-38.566 34.843-42.347l-181.951-354.421v-68.988c0-30.946 32.516-56.016 72.594-56.016 13.437 0 26.001 2.908 36.821 7.795v-466.919h1061.286v466.919c10.878-4.944 23.326-7.795 36.879-7.795 40.078 0 72.594 25.071 72.594 56.016v68.988l-181.893 354.421zM214.758 395.125c-38.217 0-69.221 25.071-69.221 56.016v6.457h-0.349v62.531l137.162 353.665h109.648l-107.961-353.665v-68.988c0 0 0 0 0 0 0-30.946-31.004-56.016-69.279-56.016zM498.447 395.125c-38.217 0-69.221 25.071-69.221 56.016v68.988l57.354 353.665h109.241l-28.095-353.665v-68.93c-0.058-31.004-31.004-56.075-69.279-56.075zM782.077 395.125c-38.217 0-69.162 25.071-69.162 56.016v68.988l-28.154 353.665h108.892l57.296-353.665v-68.988c0-0.931 0.175-1.92 0.233-2.792-1.803-29.666-32.051-53.224-69.104-53.224zM1134.637 451.141c0-30.946-31.004-56.016-69.221-56.016s-69.162 25.071-69.162 56.016v68.988l-108.019 353.665h109.59l137.22-353.665v-62.473h-0.349v-6.515h-0.058z"/><glyph unicode="&#58895;" glyph-name="views" horiz-adv-x="1890" d="M944.97 630.958c-97.861 0-177.522-79.581-177.522-177.443 0-97.94 79.66-177.679 177.522-177.679 98.019 0 177.679 79.739 177.679 177.679 0 97.861-79.66 177.443-177.679 177.443zM944.97 960c-470.712 0-944.97-512-944.97-512s474.258-512 944.97-512c470.949 0 945.128 512 945.128 512s-474.179 512-945.128 512zM944.97 91.144c-200.057 0-362.292 162.078-362.292 362.45 0 200.057 162.236 362.292 362.292 362.292 200.214 0 362.45-162.236 362.45-362.292 0-200.451-162.236-362.45-362.45-362.45z"/><glyph unicode="&#58896;" glyph-name="system-config" d="M1020.032 394.445v116.045l-16.41 5.376-124.237 40.525-33.152 80.102 63.718 134.784-82.048 82.125-15.411-7.808-116.531-59.213-80.077 33.178-50.278 140.442h-116.096l-45.875-140.698-80-33.126-134.963 63.744-82.022-82.074 7.834-15.334 59.162-116.608-33.126-80.026-140.518-50.253v-116.147l16.435-5.325 124.288-40.576 33.075-80-63.693-134.886 82.048-82.099 131.942 66.97 80.026-33.152 50.304-140.39h116.096l5.35 16.41 40.55 124.237 80.077 33.178 134.886-63.718 82.074 82.074-7.834 15.386-59.213 116.582 33.203 80.026 140.416 50.253zM510.003 287.411c-89.754 0-162.509 72.832-162.509 162.611 0 89.754 72.755 162.483 162.509 162.483 89.83 0 162.509-72.73 162.509-162.483 0.026-89.805-72.653-162.611-162.509-162.611z"/><glyph unicode="&#58897;" glyph-name="home" d="M509.978 905.574l-509.978-509.926 95.949-95.949 414.106 413.978 413.875-413.978 95.949 95.898-509.901 509.978zM146.253 271.437v-335.437h259.917v304.819h207.514v-304.819h259.917v335.488l-363.622 363.597-363.725-363.648z"/><glyph unicode="&#58898;" glyph-name="lego" d="M0 223.59l498.278-287.59v421.402l-498.278 287.667v-421.478zM894.464 735.514v-44.262c0-32.819-62.797-59.418-140.365-59.418-77.466 0-140.262 26.598-140.262 59.418v73.216h0.435c4.71-30.925 65.408-55.475 139.853-55.475 77.568 0 140.365 26.624 140.365 59.29 0 32.845-62.797 59.366-140.365 59.366-6.195 0-12.262-0.205-18.202-0.563l-90.317 52.147v-55.706c0-32.819-62.72-59.392-140.262-59.392-48.691 0-91.597 10.496-116.813 26.47-3.584 3.712-7.987 7.245-13.312 10.598-6.579 6.861-10.24 14.387-10.24 22.323v53.939l-87.322-50.381c-6.272 0.307-12.646 0.614-19.123 0.614-77.491 0-140.314-26.522-140.314-59.366 0-32.691 62.822-59.29 140.314-59.29 74.445 0 135.219 24.525 139.93 55.475h0.384v-73.216c0-32.819-62.746-59.418-140.314-59.418-77.491 0-140.314 26.598-140.314 59.418v43.622l-108.083-62.31 499.994-288.563 496.691 286.694-112.358 64.768zM646.784 551.987c0-32.794-62.874-59.315-140.365-59.315s-140.339 26.522-140.339 59.315v73.267h0.41c4.762-30.95 65.459-55.475 139.93-55.475s135.142 24.525 139.904 55.475h0.486v-73.267zM525.645 353.766v-417.766l498.355 287.718v417.766l-498.355-287.718zM505.318 841.344c77.542 0 140.262 26.547 140.262 59.315s-62.72 59.315-140.262 59.315c-77.491 0-140.339-26.573-140.339-59.315-0.026-32.768 62.822-59.315 140.339-59.315z"/><glyph unicode="&#58899;" glyph-name="tool" d="M287.002 478.336c0.205-0.23 0.461-0.486 0.691-0.717l103.347-103.373 36.045 36.045-56.55 56.499 90.266 90.189 11.904-1.28c3.046-0.307 6.093-0.538 9.19-0.538 6.246 0 12.314 0.768 18.253 2.125l-66.381 66.381c-1.357 1.382-2.765 2.611-4.173 3.814 20.454 73.6 1.766 155.725-56.038 213.555-57.421 57.421-138.803 76.237-211.968 56.525l123.955-123.981-32.563-121.446-121.395-32.589-124.032 124.006c-19.712-73.19-0.896-154.573 56.525-212.019 60.262-60.288 147.021-77.952 222.925-53.197zM653.235 404.198c-1.997-8.909-2.509-18.202-1.459-27.546l1.306-11.93-90.189-90.189-56.55 56.55-36.070-36.122 327.219-327.194c20.198-20.173 46.618-30.259 73.062-30.259s52.915 10.086 73.037 30.259c40.346 40.32 40.346 105.728 0 146.074l-290.355 290.355zM905.907 1.638l-51.866-13.875-42.112 42.112 13.901 51.891 51.866 13.926 42.112-42.138-13.901-51.917zM506.701 365.901l56.576-56.576 64.128 64.154c-3.482 31.334 6.707 63.821 30.669 87.808 24.013 23.962 56.474 34.176 87.808 30.72l280.397 280.346-157.056 157.056-280.448-280.397c3.482-31.258-6.682-63.821-30.669-87.782-24.013-23.987-56.525-34.176-87.808-30.643l-64.102-64.205 56.499-56.422-277.043-277.12-10.138 10.138-53.248-42.829-89.421-141.312 22.835-22.835 141.312 89.421 42.803 53.222-10.138 10.138 277.043 277.12z"/><glyph unicode="&#58900;" glyph-name="upgrade" d="M1023.932 454.895c-3.717 282.692-236.1 508.826-518.793 505.003-282.658-3.775-508.826-236.066-505.071-518.827 3.772-282.556 236.1-508.826 518.793-505.003 282.658 3.768 508.826 236.066 505.071 518.827zM623.991 478.696v-298.633h-223.983v298.633h-186.621l298.633 298.633 298.667-298.633h-186.679z"/><glyph unicode="&#58901;" glyph-name="expand-close" d="M512.794 960c-283.187 0-512.794-229.581-512.794-512.794 0-283.187 229.606-512.794 512.794-512.794s512.794 229.632 512.794 512.794c0 283.213-229.581 512.794-512.794 512.794zM512.794-11.213c-253.158 0-458.394 205.261-458.394 458.368 0 253.158 205.261 458.394 458.394 458.394 253.184 0 458.394-205.235 458.394-458.394 0.026-253.107-205.21-458.368-458.394-458.368zM760.013 334.387l30.387 38.4-265.6 206.413-20.787 1.613-259.226-208.026 28.826-39.987 236.8 177.613z"/><glyph unicode="&#58902;" glyph-name="expand-open" d="M512.794 960c-283.187 0-512.794-229.581-512.794-512.794 0-283.187 229.606-512.794 512.794-512.794s512.794 229.606 512.794 512.794c0 283.213-229.581 512.794-512.794 512.794zM512.794-11.213c-253.158 0-458.394 205.261-458.394 458.394 0 253.158 205.261 458.394 458.394 458.394 253.184 0 458.394-205.235 458.394-458.394 0.026-253.133-205.21-458.394-458.394-458.394zM265.6 505.6l-30.387-38.4 265.574-206.387 20.813-1.613 259.2 208-28.8 39.987-236.8-177.587z"/><glyph unicode="&#58903;" glyph-name="gripper" d="M259.2 960h214.323v-214.323h-214.323v214.323zM259.2 690.125h214.323v-214.349h-214.323v214.349zM259.2 420.224h214.323v-214.349h-214.323v214.349zM259.2 150.349h214.323v-214.349h-214.323v214.349zM549.325 960h214.323v-214.323h-214.323v214.323zM549.325 690.125h214.323v-214.349h-214.323v214.349zM549.325 420.224h214.323v-214.349h-214.323v214.349zM549.325 150.349h214.323v-214.349h-214.323v214.349z"/><glyph unicode="&#58904;" glyph-name="forward" d="M860.058 774.938v-272l-430.029 269.158-1.894-253.491-424.371 249.754-3.763-647.834 426.24 241.28-5.606-239.437 439.424 252.16v-259.635h163.942v660.045z"/><glyph unicode="&#58905;" glyph-name="backward" d="M163.942 114.893v271.974l430.029-269.133 1.894 253.491 424.397-249.754 3.738 647.834-426.24-241.28 5.606 239.437-439.424-252.16v259.635h-163.942v-660.045z"/><glyph unicode="&#58906;" glyph-name="info" d="M505.704 919.002c-260.096-3.489-468.158-217.202-464.706-477.336 3.489-259.982 217.202-468.12 477.298-464.631s468.158 217.202 464.706 477.336c-3.413 260.058-217.202 468.12-477.298 464.631zM557.928 762.027c47.863 0 62.009-27.762 62.009-59.544 0-39.671-31.782-76.383-86.016-76.383-45.359 0-66.901 22.831-65.65 60.53 0 31.782 26.624 75.435 89.657 75.435zM435.162 153.619c-32.73 0-56.661 19.873-33.792 107.217l37.547 154.814c6.485 24.841 7.585 34.778 0 34.778-9.785 0-52.262-17.143-77.407-34.057l-16.346 26.776c79.607 66.446 171.16 105.472 210.375 105.472 32.73 0 38.153-38.722 21.807-98.266l-43.008-162.816c-7.585-28.786-4.286-38.722 3.262-38.722 9.785 0 41.984 11.871 73.614 36.75l18.47-24.841c-77.369-77.369-161.792-107.179-194.56-107.179z"/><glyph unicode="&#58907;" glyph-name="lock" d="M591.986 511.981h-16.005v192.019c0 105.851-86.13 192.019-192.019 192.019h-128c-105.851 0-192.019-86.13-192.019-192.019v-192.019h-16.005c-26.396 0-48.014-21.618-48.014-48.014v-479.991c0-26.396 21.618-48.014 48.014-48.014h544.009c26.396 0 48.014 21.618 48.014 48.014v479.991c0 26.396-21.618 48.014-48.014 48.014zM384 64h-128l27.838 139.188c-16.801 11.529-27.838 30.872-27.838 52.793 0 35.347 28.672 64.019 64.019 64.019s64.019-28.672 64.019-64.019c0-21.921-11.036-41.263-27.838-52.793l27.838-139.188zM448.019 511.981h-256v192.019c0 35.271 28.71 64.019 64.019 64.019h128c35.271 0 64.019-28.71 64.019-64.019v-192.019z"/><glyph unicode="&#58908;" glyph-name="loop" d="M870.4 642.56h-194.56v-143.36h153.6v-215.040h-634.88v215.040h215.040v-112.64l204.8 184.32-204.8 184.32v-112.64h-256c-56.51 0-102.4-45.815-102.4-102.4v-296.96c0-56.51 45.89-102.4 102.4-102.4h716.8c56.585 0 102.4 45.89 102.4 102.4v296.96c0 56.585-45.815 102.4-102.4 102.4z"/><glyph unicode="&#58909;" glyph-name="plus" d="M991.991 576h-351.991v351.991c0 17.673-14.336 32.009-32.009 32.009h-192.019c-17.673 0-32.009-14.336-32.009-32.009v-351.991h-351.991c-17.673 0-32.009-14.336-32.009-32.009v-192.019c0-17.673 14.336-32.009 32.009-32.009h351.991v-351.991c0-17.673 14.336-32.009 32.009-32.009h192.019c17.673 0 32.009 14.336 32.009 32.009v351.991h351.991c17.673 0 32.009 14.336 32.009 32.009v192.019c0 17.673-14.336 32.009-32.009 32.009z"/><glyph unicode="&#58910;" glyph-name="recover" d="M505.704 919.002c-260.096-3.489-468.158-217.126-464.706-477.298 3.489-260.21 217.202-468.158 477.298-464.744 260.134 3.489 468.233 217.202 464.706 477.298-3.489 260.21-217.202 468.233-477.298 464.744zM506.577 857.6c70.163 0.986 136.382-15.853 194.56-46.118l-63.374-105.662c-38.002 18.47-80.631 28.937-125.762 28.937-45.056 0-87.723-10.43-125.687-28.975l-63.336 105.624c54.993 28.672 117.343 45.321 183.599 46.232zM254.255 322.313l-105.586-63.298c-28.672 54.955-45.321 117.305-46.194 183.486-0.986 70.201 15.853 136.457 46.118 194.56l105.624-63.45c-18.546-37.926-28.975-80.555-28.975-125.649 0-45.056 10.43-87.723 28.975-125.687zM517.461 38.438c-70.163-0.986-136.457 15.853-194.56 46.118l63.374 105.662c38.002-18.546 80.631-28.975 125.687-28.975 45.094 0 87.761 10.392 125.687 28.937l63.336-105.586c-54.993-28.634-117.305-45.246-183.561-46.194zM512 222.758c-124.397 0-225.242 100.883-225.242 225.242 0 124.397 100.883 225.28 225.242 225.28 124.473 0 225.28-100.883 225.28-225.28s-100.807-225.242-225.28-225.242zM769.745 322.313c18.546 38.002 28.975 80.631 28.975 125.687 0 45.094-10.43 87.723-28.975 125.687l105.586 63.374c28.672-54.993 45.359-117.305 46.232-183.561 0.91-70.201-15.929-136.457-46.194-194.56l-105.624 63.336z"/><glyph unicode="&#58911;" glyph-name="refresh" horiz-adv-x="1176" d="M906.126 824.187v0c-91.174 75.89-202.487 113.171-312.548 113.057-127.014 0.038-253.611-49.683-348.16-145.636l-95.004 79.265-1.593-305.342 300.184 56.282-99.442 82.944c67.546 64.247 155.269 97.204 244.015 97.28 79.948-0.038 159.782-26.7 226.114-81.806 84.347-70.125 127.659-170.629 127.772-272.46-0.038-14.715-0.948-29.431-2.769-44.070l137.519 26.283c0.19 5.954 0.303 11.871 0.303 17.787 0.152 140.098-60.151 279.78-176.431 376.415zM839.035 193.024c-67.736-65.498-156.255-99.025-245.912-99.1-79.986 0.038-159.82 26.738-226.114 81.806-84.347 70.125-127.697 170.629-127.772 272.498 0 16.839 1.252 33.716 3.679 50.366l-138.164-25.941c-0.379-8.116-0.683-16.346-0.683-24.462-0.114-140.174 60.226-279.817 176.545-376.491 91.136-75.852 202.411-113.057 312.51-112.981h0.341c127.924 0 255.241 50.441 349.943 147.759l90.795-75.207 0.569 305.38-299.956-57.344 104.183-86.281z"/><glyph unicode="&#58912;" glyph-name="remove-small" horiz-adv-x="1176" d="M593.351 938.268c-270.753 0-490.268-219.477-490.268-490.231s219.515-490.268 490.268-490.268 490.231 219.515 490.231 490.268c0 270.753-219.477 490.231-490.231 490.231zM828.947 276.347l-72.363-72.363-162.095 162.133-164.902-164.902-73.121 73.121 164.902 164.902-161.678 161.678 72.363 72.325 161.602-161.678 165.774 165.736 73.121-73.083-165.774-165.736 162.171-162.133z"/><glyph unicode="&#58913;" glyph-name="retweet" d="M254.976 284.16v267.264h103.424l-179.2 203.776-179.2-203.776h103.424v-308.224c0-56.51 45.815-102.4 102.4-102.4h459.776l-131.186 143.36h-279.438zM920.538 344.576v308.224c0 56.51-45.89 102.4-102.4 102.4h-459.738l131.11-143.36h279.514v-267.264h-103.424l179.2-203.776 179.2 203.776h-103.462z"/><glyph unicode="&#58914;" glyph-name="unlocked" d="M768 895.981h-128c-105.851 0-192.019-86.13-192.019-192.019v-192.019h-400.005c-26.396 0-48.014-21.618-48.014-48.014v-479.991c0-26.396 21.618-48.014 48.014-48.014h544.009c26.396 0 48.014 21.618 48.014 48.014v479.991c0 26.396-21.618 48.014-48.014 48.014h-16.005v192.019c0 35.271 28.71 64.019 64.019 64.019h128c35.271 0 64.019-28.71 64.019-64.019v-192.019h128v192.019c0 105.851-86.13 192.019-192.019 192.019zM384 64h-128l27.838 139.188c-16.801 11.529-27.838 30.872-27.838 52.793 0 35.347 28.672 64.019 64.019 64.019s64.019-28.672 64.019-64.019c0-21.921-11.036-41.263-27.838-52.793l27.838-139.188z"/><glyph unicode="&#58915;" glyph-name="warning" horiz-adv-x="1176" d="M593.351 960l-593.351-1023.962h1186.74l-593.351 1023.962zM653.236 60.549h-125.421v121.211h125.421v-121.211zM622.175 231.671h-62.502l-34.816 288.313v156.748h131.3v-156.748l-33.982-288.313z"/><glyph unicode="&#58916;" glyph-name="arrow-left" d="M0 448l512-512v320.019h512v384h-512v320.019z"/><glyph unicode="&#58917;" glyph-name="arrow-right" d="M1024 448l-512 512v-320.019h-512v-384h512v-320.019z"/><glyph unicode="&#58918;" glyph-name="back-arrow" d="M402.735 813.265l-320.019-320.019c-24.993-24.993-24.993-65.498 0-90.491l320.019-320.019c24.993-24.993 65.498-24.993 90.491 0s24.993 65.498 0 90.491l-210.754 210.754h613.49c35.347 0 64.019 28.634 64.019 64.019s-28.672 64.019-64.019 64.019h-613.49l210.754 210.754c12.478 12.478 18.735 28.862 18.735 45.246s-6.258 32.768-18.735 45.246c-24.993 24.993-65.498 24.993-90.491 0z"/><glyph unicode="&#58919;" glyph-name="calendar" horiz-adv-x="1176" d="M507.259 381.478h-102.059v-101.717h102.059v101.717zM650.885 245.286h-101.945v-101.717h101.945v101.717zM507.259 245.286h-102.059v-101.717h102.059v101.717zM507.259 517.67h-102.059v-101.679h102.059v101.679zM843.131 715.909c23.4 0 42.287 18.887 42.287 42.174v145.408c0 23.324-18.887 42.174-42.287 42.174s-42.325-18.849-42.325-42.174v-145.408c0.038-23.324 18.925-42.174 42.325-42.174zM343.419 715.909c23.362 0 42.249 18.887 42.249 42.174v145.408c0 23.324-18.887 42.174-42.249 42.174-23.4 0-42.325-18.849-42.325-42.174v-145.408c0-23.324 18.925-42.174 42.325-42.174zM363.444 381.478h-102.059v-101.717h102.059v101.717zM363.444 245.286h-102.059v-101.717h102.059v101.717zM650.885 381.478h-101.945v-101.717h101.945v101.717zM938.325 381.478h-102.059v-101.717h102.059v101.717zM938.325 517.67h-102.059v-101.679h102.059v101.679zM899.337 875.615v-46.914c17.598-15.474 28.71-38.153 28.71-63.412 0-46.801-37.964-84.764-84.916-84.764s-84.954 37.964-84.954 84.764c0 25.259 11.15 47.938 28.71 63.412v46.914h-387.262v-46.914c17.56-15.474 28.71-38.153 28.71-63.412 0-46.801-38.002-84.764-84.916-84.764s-84.954 37.964-84.954 84.764c0 25.259 11.15 47.938 28.71 63.412v46.914h-192.322v-925.279h997.035v925.279h-192.512zM999.234 44.696h-809.832v589.938h809.832v-589.938zM650.885 517.67h-101.945v-101.679h101.945v101.679zM794.624 517.67h-101.983v-101.679h101.983v101.679zM794.624 245.286h-101.983v-101.717h101.983v101.717zM794.624 381.478h-101.983v-101.717h101.983v101.717z"/><glyph unicode="&#58920;" glyph-name="caret-down" d="M132.21 673.242c-13.881 13.729-36.295 13.729-50.138 0-13.805-13.653-13.805-35.878 0-49.607l404.897-400.877c13.881-13.729 36.257-13.729 50.138 0l404.897 400.877c13.805 13.729 13.881 35.878 0 49.607s-36.371 13.729-50.138 0.038l-379.866-365.606-379.79 365.568z"/><glyph unicode="&#58921;" glyph-name="caret-left" d="M737.242 68.21c13.729-13.881 13.729-36.257 0-50.138s-35.878-13.881-49.607 0l-400.877 404.821c-13.729 13.881-13.729 36.295 0 50.138l400.877 404.897c13.729 13.881 35.878 13.881 49.607 0s13.729-36.257 0-50.138l-365.568-379.79 365.568-379.79z"/><glyph unicode="&#58922;" glyph-name="caret-right" d="M286.72 68.21c-13.729-13.881-13.729-36.257 0-50.138s35.878-13.881 49.607 0l400.877 404.821c13.729 13.881 13.729 36.295 0 50.138l-400.915 404.897c-13.729 13.881-35.878 13.881-49.607 0s-13.729-36.257 0-50.138l365.568-379.79-365.568-379.79z"/><glyph unicode="&#58923;" glyph-name="caret-up" d="M891.79 222.758c13.881-13.729 36.295-13.729 50.138 0 13.881 13.729 13.881 35.878 0 49.607l-404.897 400.877c-13.805 13.729-36.257 13.729-50.062 0l-404.897-400.877c-13.805-13.729-13.881-35.878 0-49.607s36.257-13.729 50.138 0l379.79 365.606 379.79-365.606z"/><glyph unicode="&#58924;" glyph-name="ccw" d="M574.767 867.84c-227.593 0-412.672-182.386-418.247-409.335h-125.8l188.378-209.92 188.302 209.92h-146.242c5.537 168.998 143.777 304.393 313.609 304.393 173.397 0 313.913-140.971 313.913-314.899s-140.478-314.861-313.913-314.861c-69.48 0-133.689 22.718-185.685 61.099l-71.983-76.99c70.997-55.751 160.465-89.050 257.707-89.050 231.159 0 418.551 187.961 418.551 419.84-0.038 231.879-187.43 419.84-418.551 419.84z"/><glyph unicode="&#58925;" glyph-name="check-mage" horiz-adv-x="1176" d="M996.617 833.214l-513.555-513.555-256.796 256.834-128.379-128.417 385.214-385.252 641.896 642.010z"/><glyph unicode="&#58926;" glyph-name="clock" d="M512 919.040c-260.134 0-471.040-210.944-471.040-471.040 0-260.134 210.906-471.040 471.040-471.040s471.040 210.906 471.040 471.040c0 260.134-210.906 471.040-471.040 471.040zM512 79.36c-203.624 0-368.64 165.054-368.64 368.64s165.016 368.64 368.64 368.64 368.64-165.054 368.64-368.64-165.016-368.64-368.64-368.64zM547.84 714.24h-71.68v-281.069l174.345-174.345 50.669 50.707-153.335 153.335z"/><glyph unicode="&#58927;" glyph-name="close-mage" horiz-adv-x="1176" d="M1094.391 882.29l-77.71 77.71-423.329-423.347-423.33 423.347-77.71-77.672 423.35-423.368-423.312-423.329 77.672-77.71 423.338 423.338 423.283-423.3 77.671 77.71-423.263 423.281z"/><glyph unicode="&#58928;" glyph-name="delete" horiz-adv-x="1176" d="M337.541-61.004h513.024l64.512 645.916h-639.128l61.592-645.916zM737.394 805.831v116.508c0 19.191-15.398 34.702-34.361 34.702h-217.847c-19.001 0-34.361-15.55-34.361-34.702v-114.574c-73.576-8.382-150.149-24.614-226.494-52.338v-106.989h738.001v109.833c0 0-90.074 31.403-224.977 47.559zM668.937 812.241c-47.749 3.224-99.252 4.096-153.297 0.986v61.44c0 9.519 7.623 17.332 17.143 17.332h118.936c9.519 0 17.218-7.813 17.218-17.332v-62.426z"/><glyph unicode="&#58929;" glyph-name="edit" horiz-adv-x="1176" d="M928.503 933.111l-111.502-112.109 156.065-156.9 111.502 112.071-156.065 156.937zM215.002 215.59l156.065-156.9 535.211 538.093-156.065 156.9-535.211-538.093zM103.917-47.161l188.985 49.873-139.302 140.098-49.683-190.009z"/><glyph unicode="&#58930;" glyph-name="error" d="M1014.67 137.349c0 0 0 0 0 0l-310.651 310.651 310.651 310.651c0 0 0 0 0 0 3.337 3.337 5.765 7.244 7.32 11.416 4.248 11.378 1.82 24.69-7.32 33.83l-146.735 146.735c-9.14 9.14-22.452 11.567-33.83 7.32-4.172-1.555-8.078-3.982-11.416-7.32 0 0 0 0 0 0l-310.651-310.651-310.651 310.651c0 0 0 0 0 0-3.337 3.337-7.244 5.765-11.416 7.32-11.378 4.248-24.69 1.82-33.83-7.32l-146.735-146.735c-9.14-9.14-11.567-22.452-7.32-33.83 1.555-4.172 3.982-8.078 7.32-11.416 0 0 0 0 0 0l310.651-310.651-310.651-310.651c0 0 0 0 0 0-3.337-3.337-5.765-7.244-7.32-11.416-4.248-11.378-1.82-24.69 7.32-33.83l146.735-146.735c9.14-9.14 22.452-11.567 33.83-7.32 4.172 1.555 8.078 3.982 11.416 7.32 0 0 0 0 0 0l310.651 310.651 310.651-310.651c0 0 0 0 0 0 3.337-3.337 7.244-5.765 11.416-7.32 11.378-4.248 24.69-1.82 33.83 7.32l146.735 146.735c9.14 9.14 11.567 22.452 7.32 33.83-1.555 4.172-3.982 8.078-7.32 11.416z"/><glyph unicode="&#58931;" glyph-name="help" horiz-adv-x="1176" d="M593.351 937.434c-270.336 0-489.434-219.098-489.434-489.358s219.098-489.434 489.434-489.434 489.434 219.136 489.434 489.434-219.136 489.358-489.434 489.358zM635.752 133.404c-11.985-11.719-26.396-17.636-43.16-17.636-8.154 0-15.967 1.517-23.4 4.589-7.358 3.034-13.843 7.168-19.456 12.174-5.613 5.158-10.126 11.226-13.388 18.356-3.337 7.13-4.968 14.753-4.968 22.945 0 16.308 5.992 30.303 17.977 42.060 11.947 11.681 26.396 17.598 43.198 17.598 16.308 0 30.606-5.689 42.78-16.801 12.25-11.188 18.318-24.993 18.318-41.339-0.038-16.384-5.992-30.303-17.939-41.984zM778.923 577.327c-3.982-13.767-9.747-26.396-17.18-37.774-7.471-11.454-16.498-22.49-27.079-33.071s-22.49-21.618-35.65-33.033c-11.454-9.785-20.783-18.318-27.913-25.79-7.168-7.396-12.895-14.867-17.218-22.338-4.286-7.433-7.282-15.398-9.026-24.007-1.707-8.609-2.617-49.721-2.617-62.35v-22.338h-101.376v32.616c0 13.729 0.986 56.661 3.034 67.584s5.158 21.125 9.481 30.872 10.012 19.228 17.18 28.369c7.168 9.14 16.232 18.887 27.079 29.203l38.647 36.902c10.847 9.747 20.177 20.632 27.951 32.616 7.737 12.060 11.529 26.7 11.529 43.88 0 22.3-6.978 41.036-21.011 56.206-14.071 15.17-33.944 22.793-59.695 22.793-13.16 0-25.069-2.389-35.65-7.282-10.619-4.817-19.797-11.454-27.496-19.759-7.737-8.344-13.577-17.901-17.598-28.786-3.982-10.847-6.334-21.997-6.865-33.527l-105.624 9.444c3.413 27.496 10.733 51.959 21.921 73.463 11.112 21.466 25.562 39.595 43.311 54.575 17.711 14.829 38.078 26.169 61.023 33.944 22.869 7.699 47.521 11.605 73.842 11.605 24.614 0 47.976-3.603 70.049-10.771 21.959-7.168 41.491-17.711 58.406-31.782 16.839-14.033 30.227-31.365 39.936-51.959 9.709-20.632 14.564-44.411 14.564-71.263 0-18.356-2.010-34.475-5.992-48.166z"/><glyph unicode="&#58932;" glyph-name="history" d="M574.805 867.84c-227.631 0-412.71-182.386-418.247-409.335h-125.838l188.378-209.958 188.302 209.958h-146.242c5.537 168.998 143.777 304.393 313.647 304.393 173.359 0 313.875-140.971 313.875-314.899s-140.478-314.861-313.875-314.861c-69.518 0-133.727 22.718-185.761 61.099l-71.983-76.99c71.073-55.751 160.503-89.050 257.745-89.050 231.121 0 418.513 187.961 418.513 419.84-0.038 231.879-187.43 419.84-418.513 419.84zM537.6 673.28v-240.109l153.865-153.865 50.669 50.669-132.855 132.855v210.413h-71.68z"/><glyph unicode="&#58933;" glyph-name="export" d="M383.462 382.49h255.693v213.043h127.795l-255.642 255.667-255.642-255.667h127.795zM852.173 382.49v-170.394h-681.754v170.394h-170.419v-340.89h1022.618v340.89z"/><glyph unicode="&#58934;" glyph-name="import" d="M639.155 851.2h-255.693v-213.043h-127.795l255.667-255.667 255.616 255.667h-127.795zM852.173 382.49v-170.394h-681.754v170.394h-170.419v-340.89h1022.618v340.89z"/><glyph unicode="&#58935;" glyph-name="dot" d="M505.139 959.915c-282.658-3.775-508.826-236.066-505.071-518.827 3.772-282.556 236.1-508.826 518.793-505.003 282.658 3.768 508.826 236.066 505.071 518.827-3.717 282.658-236.1 508.826-518.793 505.003z"/><glyph unicode="&#58936;" glyph-name="not-installed" d="M510.413 960c-281.907 0-510.413-228.582-510.413-510.413 0-281.933 228.506-510.464 510.413-510.464s510.387 228.557 510.387 510.464c0 281.83-228.48 510.413-510.387 510.413zM865.843 449.587c0-69.99-20.506-135.27-55.578-190.285l-490.163 490.163c55.091 35.021 120.32 55.475 190.31 55.475 195.942 0 355.43-159.411 355.43-355.354zM154.957 449.587c0 69.939 20.506 135.245 55.578 190.31l490.189-490.189c-55.066-35.072-120.371-55.501-190.31-55.501-195.942-0.026-355.456 159.437-355.456 355.379z"/><glyph unicode="&#58937;" glyph-name="disabled" d="M511.77 960c-282.778 0-512.102-229.222-512.102-512.179 0-282.829 229.325-512.102 512.102-512.102 282.931-0.026 512.23 229.248 512.23 512.102 0 282.957-229.299 512.179-512.23 512.179zM143.718 540.032h736.205v-184.269h-736.205v184.269z"/><glyph unicode="&#58938;" glyph-name="menu-item" horiz-adv-x="903" d="M857.675 670.587l-403.18 240.514-402.726-240.514v-457.026l403.18-240.515 402.726 240.514v457.027zM454.857 95.535l-298.427 178.383v335.966l298.157 178.729 298.428-178.383v-335.966l-298.158-178.729z"/><glyph unicode="&#58939;" glyph-name="tag" d="M904.192 959.973l-307.234-0.116-596.89-596.958 426.906-426.906 596.958 596.958-0.113 305.596-119.603 121.426zM858.679 646.663c-39.997-40.001-104.854-40.001-144.794 0-40.001 40.001-40.001 104.796 0 144.794 39.939 40.001 104.796 40.001 144.794 0 39.997-39.997 39.997-104.793 0-144.794z"/><glyph unicode="&#58940;" glyph-name="camera" d="M982.767 728.098h-250.095l-59.255 121.364c0 0-11.827 25.201-42.11 25.201-23.375 0-169.366 0-235.25 0-32.969 0-44.001-25.027-44.001-25.027l-57.484-121.539h-253.406c-22.74 0-41.131-18.459-41.131-41.267v-624.333c0-22.743 18.401-41.199 41.131-41.199h941.636c22.74 0 41.199 18.459 41.199 41.199v624.299c0 22.798-18.456 41.267-41.199 41.267zM512 136.090c-138.793 0-251.597 113.015-251.597 251.931 0 138.912 112.845 251.87 251.597 251.87 138.68 0 251.597-112.981 251.597-251.87 0-138.909-112.913-251.931-251.597-251.931zM512 539.068c-83.255 0-150.972-67.714-150.972-150.972 0-83.197 67.71-150.903 150.972-150.903 83.258 0 150.903 67.714 150.903 150.903 0 83.255-67.652 150.972-150.903 150.972z"/><glyph unicode="&#58941;" glyph-name="grid" d="M0.010 959.628h279.074v-279.074h-279.074zM372.77 959.628h279.074v-279.074h-279.074zM744.892 959.628h279.074v-279.074h-279.074zM0.010 587.503h279.074v-279.074h-279.074zM372.77 587.503h279.074v-279.074h-279.074zM744.892 587.503h279.074v-279.074h-279.074zM0.010 215.415h279.074v-279.074h-279.074zM372.77 215.415h279.074v-279.074h-279.074zM744.892 215.415h279.074v-279.074h-279.074z"/><glyph unicode="&#58942;" glyph-name="list-menu" d="M0.010 771.516h1023.966v-136.509h-1023.966zM0.010 517.53h1023.966v-136.506h-1023.966zM0.010 260.983h1023.966v-136.513h-1023.966z"/><glyph unicode="&#58943;" glyph-name="cart" d="M771.001 183.263c-55.445 0-100.448-44.754-100.448-100.2s44.879-100.324 100.448-100.324 100.448 44.879 100.448 100.324-45.003 100.2-100.448 100.2zM771.001 41.293c-23.123 0-41.77 18.648-41.77 41.771s18.647 41.77 41.77 41.77c23.247 0 41.895-18.648 41.895-41.77s-18.648-41.771-41.895-41.771zM469.532 183.263c-55.445 0-100.449-44.754-100.449-100.2s45.003-100.324 100.449-100.324c55.445 0 100.448 44.879 100.448 100.324s-45.003 100.2-100.448 100.2zM469.532 41.293c-23.123 0-41.771 18.648-41.771 41.771s18.648 41.77 41.771 41.77 41.77-18.648 41.77-41.77-18.648-41.771-41.77-41.771zM823.587 465.588c-130.036 0-238.441 91.622-264.547 213.825h-207.237l-136.749 198.162v1.865h-207.237v-83.541h169.942l78.693-117.729 83.417-412.857h581.183l49.23 243.786c-42.268-27.474-92.616-43.511-146.694-43.511zM1023.862 710.244v45.376l-55.073 18.026-12.929 31.204 24.863 52.71-31.95 32.074-5.967-2.984-45.5-23.123-31.328 12.929-19.642 54.948h-45.376l-2.114-6.464-15.912-48.608-31.203-12.929-52.835 24.863-32.074-31.95 3.108-5.967 23.247-45.624-13.053-31.328-54.948-19.766v-45.376l6.34-2.113 48.732-15.788 12.929-31.204-24.863-52.71 32.074-32.074 6.092 3.108 45.376 22.999 31.328-12.929 19.642-54.824h45.376l2.113 6.464 15.913 48.359 31.203 12.929 52.71-24.988 32.198 32.074-3.108 6.092-23.247 45.624 12.929 31.203 54.948 19.766zM824.582 668.473c-35.057 0-63.65 28.469-63.65 63.526 0 35.182 28.469 63.526 63.65 63.526s63.526-28.469 63.526-63.526c-0.124-35.182-28.469-63.526-63.526-63.526z"/><glyph unicode="&#58944;" glyph-name="screen" horiz-adv-x="1159" d="M723.661 70.399c-2.404 10.843-4.034 21.47-5.282 31.583h-277.528c-2.458-20.233-6.917-43.087-14.646-64.305-7.79-21.277-18.796-40.54-33.824-54.15-15.028-13.552-33.689-22.104-59.788-22.158v-25.369h494.020v25.369c-26.142 0.058-44.737 8.61-59.838 22.158-22.44 20.307-35.961 53.91-43.114 86.873zM1126.214 960h-1093.209c-18.22 0-33.005-15.024-33.005-33.596v-731.259c0-18.576 14.785-33.623 33.005-33.623h1093.209c18.224 0 33.067 15.051 33.067 33.623v731.259c0 18.572-14.843 33.596-33.067 33.596zM1079.193 243.078h-999.234v635.394h999.234v-635.394z"/><glyph unicode="&#58945;" glyph-name="video" horiz-adv-x="2041" d="M2041.366 958.898v-1021.449h-175.926l-411.263 409.297v204.59l411.263 407.568h175.926zM1305.997-29.076c0-19.377-15.608-34.924-34.856-34.924h-1236.279c-19.255 0-34.863 15.547-34.863 34.924v954.275c0 19.248 15.608 34.801 34.863 34.801h1236.279c19.248 0 34.856-15.553 34.856-34.801v-954.275z"/><glyph unicode="&#58946;" glyph-name="revert" horiz-adv-x="1404" d="M1042.226 660.151h-598.393v299.849l-443.833-384.316 443.833-384.403v299.859h598.393c106.478 0 192.801-86.318 192.801-192.801s-86.318-192.796-192.801-192.796v-0.483l-452.707-0.005c-46.695-0.005-84.53-37.845-84.53-84.535 0-46.68 37.84-84.525 84.535-84.525 0.377 0 0.744 0.053 1.121 0.058h451.581c199.964 0 362.044 162.085 362.044 362.039 0 199.964-162.080 362.059-362.044 362.059z"/></font></defs></svg>
\ No newline at end of file
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" ><svg xmlns="http://www.w3.org/2000/svg"><defs><font id="icomoon" horiz-adv-x="1024"><font-face units-per-em="1024" ascent="960" descent="-64" /><missing-glyph horiz-adv-x="1024" /><glyph unicode="&#x20;" horiz-adv-x="512" d="" /><glyph unicode="&#xe600;" glyph-name="account" horiz-adv-x="1090" d="M709.921 801.306c8.139-32.295 8.927-34.974 8.192-68.162-0.263-12.813-7.772-71.943-5.724-90.112 1.628-14.966 5.461-16.174 11.448-28.514 10.398-21.425 6.984-51.095 2.941-72.678-2.206-11.868-6.827-28.725-13.916-38.387-7.667-10.66-23.211-10.713-30.142-23.158-9.872-17.854-4.306-43.008-10.503-62.385-7.142-21.898-25.101-23.421-26.466-52.145 8.822-1.155 17.592-2.468 26.466-3.623 8.822-18.59 25.049-55.874 41.59-67.059 13.863-3.728 27.727-7.457 41.59-11.185 48.627-19.64 102.558-43.061 151.237-63.33 44.373-18.432 97.411-24.996 113.48-70.84 0-31.035 2.941-104.501 2.153-145.25h-965.553c-0.893 40.697 2.153 114.215 2.153 145.25 15.964 45.844 69.002 52.408 113.375 70.84 48.679 20.27 102.61 43.691 151.237 63.33 13.811 3.728 27.674 7.457 41.59 11.185 16.489 11.185 32.715 48.522 41.538 67.059l19.692 4.621c-4.464 24.576-19.85 26.466-26.256 43.743-2.521 26.099-5.041 52.145-7.509 78.192 0.053-1.155-18.117 3.361-20.48 4.779-25.731 15.806-26.204 80.24-28.725 107.021-1.103 12.183 16.174 22.265 11.343 44.636-28.094 131.44 12.183 192.88 75.881 213.307 44.216 17.749 126.871 50.465 203.855 3.728l19.167-17.487 30.93-5.251c15.491-8.77 25.416-38.124 25.416-38.124z" /><glyph unicode="&#xe601;" glyph-name="arrowdown" horiz-adv-x="1085" d="M529.203 73.86l-468.465 628.209h936.931l-468.465-628.209z" /><glyph unicode="&#xe602;" glyph-name="cms" horiz-adv-x="1034" d="M976.793-22.006h-910.388v910.388h910.388v-910.388zM912.622 824.211h-782.046v-782.088h782.046v782.088zM221.432 137.2h152.876v372.033h-152.876v-372.033zM466.323 139.766h350.932v366.53h-350.932v-366.53zM221.432 599.511h595.865v147.125h-595.865v-147.125z" /><glyph unicode="&#xe603;" glyph-name="customers" horiz-adv-x="489" d="M264.319 651.169c75.685 0 136.98 61.259 136.98 136.944 0 75.649-61.295 136.98-136.98 136.98s-137.017-61.331-137.017-136.98c0-75.649 61.331-136.944 137.017-136.944zM448.929 589.149c-28.962 28.926-63.325 46.252-187.655 46.252s-157.859-18.776-185.335-46.252c-27.44-27.44-18.196-320.43-18.196-320.43l60.824 144.411 38.241-430.334 110.23 220.278 102.907-220.278 36.393 430.334 60.824-144.411c-0.036 0 10.693 291.468-18.233 320.43z" /><glyph unicode="&#xe604;" glyph-name="dashboard" horiz-adv-x="1376" d="M680.975 886.272c-337.523 0-610.976-273.515-611.038-610.976 0.122-37.72 1.039-251.812 1.039-251.812h1219.997c0 0 0.978 239.219 1.039 251.812-0.183 337.523-273.637 610.976-611.038 610.976zM737.708 762.169c31.117-3.607 61.379-10.271 90.418-19.624l-19.93-61.685c-25.004 8.070-51.169 13.939-78.191 16.995l7.703 64.313zM270.091 286.85h-64.864c0 31.423 3.118 62.235 8.803 92.007l63.702-12.349c-5.135-25.799-7.642-52.392-7.642-79.658zM305.855 455.581l-59.178 26.288c12.655 28.489 28 55.449 45.79 80.636l52.942-37.475c-15.284-21.825-28.611-45.056-39.554-69.449zM407.46 594.845l-43.405 48.113c22.925 20.541 47.807 39.187 74.462 54.96l33.318-55.571c-22.987-13.755-44.567-29.65-64.374-47.501zM536.943 742.545c29.039 9.292 59.178 16.017 90.418 19.624l7.581-64.313c-26.838-3.057-53.003-8.926-78.13-16.995l-19.869 61.685zM761.673 158.468l-152.897-27.205-38.881 150.452 395.172 404.22-203.394-527.467zM1019.476 525.029l52.942 37.414c17.79-25.187 33.257-52.148 45.851-80.636l-59.178-26.288c-10.943 24.454-24.209 47.685-39.615 69.51zM1094.916 286.85c0 27.266-2.69 53.859-7.703 79.658l63.702 12.349c5.808-29.834 8.803-60.645 8.803-92.007h-64.802zM646.006 189.341c26.777-17.056 62.174-9.415 79.291 17.24 17.118 26.593 9.292 62.051-17.301 79.108-26.655 17.24-62.051 9.354-79.23-17.362-17.118-26.349-9.476-61.99 17.24-78.986z" /><glyph unicode="&#xe605;" glyph-name="filter" d="M24.097 846.535h972.827v-111.922l-410.504-412.792v-238.366l-171.447-87.505v325.871l-390.875 415.877v108.837z" /><glyph unicode="&#xe606;" glyph-name="logo" horiz-adv-x="903" d="M454.495 911.101l-402.697-240.513v-457.026l104.632-60.727v457.049l298.157 178.728 299.698-179.142-0.138-455.922 103.528 60.013v457.026l-403.18 240.513zM507.766 629.72v-534.344l-53.271-32.124-53.34 32.262v533.792l-138.090-83.853v-456.934l191.453-115.516 193.087 116.322v456.451l-139.839 83.945z" /><glyph unicode="&#xe607;" glyph-name="notification-02" horiz-adv-x="989" d="M870.821 228.163c-64.195 65.89-78.231 188.772-91.738 283.159-20.074 139.937-24.259 297.089-226.008 317.693v25.318c0 25.424-39.195 46.028-64.937 46.028s-62.024-20.551-62.024-46.028v-25.371c-200.054-20.816-206.993-177.914-226.855-317.693-13.453-94.439-27.331-217.268-91.049-283.264-12.818-13.348-16.473-32.998-9.11-49.947 7.362-16.843 24.153-27.913 42.797-27.913h695.343c18.75 0 35.593 11.070 42.903 28.019s3.655 36.653-9.322 50zM489.569-3.883c51.060 0 92.373 40.837 92.373 91.367h-184.694c-0.053-50.53 41.314-91.367 92.32-91.367z" /><glyph unicode="&#xe608;" glyph-name="product" horiz-adv-x="954" d="M252.137 806.772l-160.070-92.393 378.042-218.205 160.023 92.393-377.996 218.205zM845.638 712.937l-377.996 218.252-145.222-83.828 377.996-218.205 145.222 83.782zM502.784 433.85v-433.664l376.832 217.507v433.711l-376.832-217.553zM55.668 217.74l376.785-217.507v436.503l-376.785 217.46v-436.457z" /><glyph unicode="&#xe609;" glyph-name="promotions" horiz-adv-x="1170" d="M59.153 425.818l164.053-38.141v303.902l-164.053-38.141v-227.621zM1122.198 900.847l-837.712-194.959v-335.978l140.328-376.832 151.712 57.45-104.049 279.113 649.668-151.18v722.385z" /><glyph unicode="&#xe60a;" glyph-name="reports" horiz-adv-x="991" d="M736.707-21.234h207.134v322.703h-207.134v-322.703zM399.646-21.234h207.134v946.793h-207.134v-946.793zM62.673-21.19h207.134v634.704h-207.134v-634.704z" /><glyph unicode="&#xe60b;" glyph-name="sales" horiz-adv-x="659" d="M426.502 347.483c-15.866 13.512-42.796 25.753-80.79 36.723v-198.774c11.535 1.459 23.729 4.331 36.299 8.851 12.618 4.426 23.87 10.829 33.804 19.068 9.981 8.427 18.173 18.55 24.529 30.649 6.638 12.006 9.651 26.365 9.651 42.89 0.047 26.836-7.721 47.222-23.493 60.593zM576.736 223.144c-7.109-23.117-19.774-45.762-38.135-67.749-18.503-22.175-43.079-41.855-74.010-58.992-30.885-17.373-70.432-27.683-118.878-31.12v-88.088h-57.014v88.088c-72.080 5.603-128.483 29.237-169.113 71.374-40.536 42.090-63.935 104.095-70.432 185.544h136.251c-0.753-39.359 8.992-70.479 28.86-93.266 20.15-22.74 44.774-37.335 74.434-43.455v216.523c-3.060 1.318-7.486 2.919-12.994 4.567-5.508 1.789-11.393 3.343-17.938 4.708-23.776 6.827-47.175 15.019-70.291 24.294-23.493 9.369-44.114 21.704-62.523 37.335-18.456 15.584-33.098 34.84-43.879 57.956-11.111 23.211-16.478 51.977-16.478 86.487 0 35.31 6.168 66.336 18.785 93.313 12.665 26.836 29.143 49.529 49.858 67.702 20.621 18.314 44.303 32.58 71.468 42.419 27.071 10.122 55.037 16.149 83.992 18.314v79.66h57.014v-79.66c29.143-3.531 56.308-10.169 81.638-20.292 25.423-10.028 47.787-23.729 67.137-41.478 19.585-17.514 35.357-39.453 47.457-65.771 12.288-26.13 19.35-57.109 21.28-93.172h-137.287c-0.518 27.636-8.616 51.082-23.917 70.432-15.725 19.303-34.275 29.002-56.308 29.002v-183.331c7.862-2.072 15.631-4.143 23.729-6.12 8.098-2.072 16.525-4.567 25.565-7.297 47.645-13.983 84.415-31.12 110.168-51.318 25.8-20.292 44.726-41.666 56.92-63.653 12.335-22.175 19.633-44.256 21.704-66.336 2.448-22.081 3.531-41.713 3.531-59.039 0.047-15.207-3.531-34.416-10.593-57.579zM228.905 696.585c-8.38-7.156-15.113-16.196-19.962-26.883-4.802-10.781-7.062-23.352-7.062-37.759 0-22.834 6.733-40.536 20.103-52.824 13.653-12.618 35.734-22.552 66.713-30.131v168.831c-10.829 0-21.516-1.695-31.826-5.226-10.216-3.437-19.633-8.851-27.966-16.007z" /><glyph unicode="&#xe60c;" glyph-name="search" horiz-adv-x="1109" d="M555.139 938.358c-218.775 71.601-457.062-40.29-532.231-250.028-75.227-209.681 41.211-437.665 259.928-509.208 218.717-71.601 457.004 40.348 532.231 250.028s-41.211 437.665-259.928 509.208zM320.076 282.955c-158.915 52.089-243.467 217.681-188.903 369.978 54.679 152.296 227.754 233.625 386.669 181.593s243.409-217.624 188.788-369.92c-54.622-152.296-227.696-233.567-386.554-181.65zM638.482 274.206l358.927-349.602 24.807 69.241 24.865 69.241-310.348 302.29z" /><glyph unicode="&#xe60d;" glyph-name="stores" horiz-adv-x="1280" d="M1098.281 874.55c19.777 3.723 34.901 21.232 34.901 42.347-0.058 23.791-19.196 43.103-42.812 43.103h-900.508c-23.675 0-42.754-19.312-42.754-43.103 0-21.057 15.007-38.566 34.843-42.347l-181.951-354.421v-68.988c0-30.946 32.516-56.016 72.594-56.016 13.437 0 26.001 2.908 36.821 7.795v-466.919h1061.286v466.919c10.878-4.944 23.326-7.795 36.879-7.795 40.078 0 72.594 25.071 72.594 56.016v68.988l-181.893 354.421zM214.758 395.125c-38.217 0-69.221 25.071-69.221 56.016v6.457h-0.349v62.531l137.162 353.665h109.648l-107.961-353.665v-68.988c0 0 0 0 0 0 0-30.946-31.004-56.016-69.279-56.016zM498.447 395.125c-38.217 0-69.221 25.071-69.221 56.016v68.988l57.354 353.665h109.241l-28.095-353.665v-68.93c-0.058-31.004-31.004-56.075-69.279-56.075zM782.077 395.125c-38.217 0-69.162 25.071-69.162 56.016v68.988l-28.154 353.665h108.892l57.296-353.665v-68.988c0-0.931 0.175-1.92 0.233-2.792-1.803-29.666-32.051-53.224-69.104-53.224zM1134.637 451.141c0-30.946-31.004-56.016-69.221-56.016s-69.162 25.071-69.162 56.016v68.988l-108.019 353.665h109.59l137.22-353.665v-62.473h-0.349v-6.515h-0.058z" /><glyph unicode="&#xe60f;" glyph-name="views" horiz-adv-x="1890" d="M944.97 630.958c-97.861 0-177.522-79.581-177.522-177.443 0-97.94 79.66-177.679 177.522-177.679 98.019 0 177.679 79.739 177.679 177.679 0 97.861-79.66 177.443-177.679 177.443zM944.97 960c-470.712 0-944.97-512-944.97-512s474.258-512 944.97-512c470.949 0 945.128 512 945.128 512s-474.179 512-945.128 512zM944.97 91.144c-200.057 0-362.292 162.078-362.292 362.45 0 200.057 162.236 362.292 362.292 362.292 200.214 0 362.45-162.236 362.45-362.292 0-200.451-162.236-362.45-362.45-362.45z" /><glyph unicode="&#xe610;" glyph-name="system-config" d="M1020.032 394.445v116.045l-16.41 5.376-124.237 40.525-33.152 80.102 63.718 134.784-82.048 82.125-15.411-7.808-116.531-59.213-80.077 33.178-50.278 140.442h-116.096l-45.875-140.698-80-33.126-134.963 63.744-82.022-82.074 7.834-15.334 59.162-116.608-33.126-80.026-140.518-50.253v-116.147l16.435-5.325 124.288-40.576 33.075-80-63.693-134.886 82.048-82.099 131.942 66.97 80.026-33.152 50.304-140.39h116.096l5.35 16.41 40.55 124.237 80.077 33.178 134.886-63.718 82.074 82.074-7.834 15.386-59.213 116.582 33.203 80.026 140.416 50.253zM510.003 287.411c-89.754 0-162.509 72.832-162.509 162.611 0 89.754 72.755 162.483 162.509 162.483 89.83 0 162.509-72.73 162.509-162.483 0.026-89.805-72.653-162.611-162.509-162.611z" /><glyph unicode="&#xe611;" glyph-name="home" d="M509.978 905.574l-509.978-509.926 95.949-95.949 414.106 413.978 413.875-413.978 95.949 95.898-509.901 509.978zM146.253 271.437v-335.437h259.917v304.819h207.514v-304.819h259.917v335.488l-363.622 363.597-363.725-363.648z" /><glyph unicode="&#xe612;" glyph-name="lego" d="M0 223.59l498.278-287.59v421.402l-498.278 287.667v-421.478zM894.464 735.514v-44.262c0-32.819-62.797-59.418-140.365-59.418-77.466 0-140.262 26.598-140.262 59.418v73.216h0.435c4.71-30.925 65.408-55.475 139.853-55.475 77.568 0 140.365 26.624 140.365 59.29 0 32.845-62.797 59.366-140.365 59.366-6.195 0-12.262-0.205-18.202-0.563l-90.317 52.147v-55.706c0-32.819-62.72-59.392-140.262-59.392-48.691 0-91.597 10.496-116.813 26.47-3.584 3.712-7.987 7.245-13.312 10.598-6.579 6.861-10.24 14.387-10.24 22.323v53.939l-87.322-50.381c-6.272 0.307-12.646 0.614-19.123 0.614-77.491 0-140.314-26.522-140.314-59.366 0-32.691 62.822-59.29 140.314-59.29 74.445 0 135.219 24.525 139.93 55.475h0.384v-73.216c0-32.819-62.746-59.418-140.314-59.418-77.491 0-140.314 26.598-140.314 59.418v43.622l-108.083-62.31 499.994-288.563 496.691 286.694-112.358 64.768zM646.784 551.987c0-32.794-62.874-59.315-140.365-59.315s-140.339 26.522-140.339 59.315v73.267h0.41c4.762-30.95 65.459-55.475 139.93-55.475s135.142 24.525 139.904 55.475h0.486v-73.267zM525.645 353.766v-417.766l498.355 287.718v417.766l-498.355-287.718zM505.318 841.344c77.542 0 140.262 26.547 140.262 59.315s-62.72 59.315-140.262 59.315c-77.491 0-140.339-26.573-140.339-59.315-0.026-32.768 62.822-59.315 140.339-59.315z" /><glyph unicode="&#xe613;" glyph-name="tool" d="M287.002 478.336c0.205-0.23 0.461-0.486 0.691-0.717l103.347-103.373 36.045 36.045-56.55 56.499 90.266 90.189 11.904-1.28c3.046-0.307 6.093-0.538 9.19-0.538 6.246 0 12.314 0.768 18.253 2.125l-66.381 66.381c-1.357 1.382-2.765 2.611-4.173 3.814 20.454 73.6 1.766 155.725-56.038 213.555-57.421 57.421-138.803 76.237-211.968 56.525l123.955-123.981-32.563-121.446-121.395-32.589-124.032 124.006c-19.712-73.19-0.896-154.573 56.525-212.019 60.262-60.288 147.021-77.952 222.925-53.197zM653.235 404.198c-1.997-8.909-2.509-18.202-1.459-27.546l1.306-11.93-90.189-90.189-56.55 56.55-36.070-36.122 327.219-327.194c20.198-20.173 46.618-30.259 73.062-30.259s52.915 10.086 73.037 30.259c40.346 40.32 40.346 105.728 0 146.074l-290.355 290.355zM905.907 1.638l-51.866-13.875-42.112 42.112 13.901 51.891 51.866 13.926 42.112-42.138-13.901-51.917zM506.701 365.901l56.576-56.576 64.128 64.154c-3.482 31.334 6.707 63.821 30.669 87.808 24.013 23.962 56.474 34.176 87.808 30.72l280.397 280.346-157.056 157.056-280.448-280.397c3.482-31.258-6.682-63.821-30.669-87.782-24.013-23.987-56.525-34.176-87.808-30.643l-64.102-64.205 56.499-56.422-277.043-277.12-10.138 10.138-53.248-42.829-89.421-141.312 22.835-22.835 141.312 89.421 42.803 53.222-10.138 10.138 277.043 277.12z" /><glyph unicode="&#xe614;" glyph-name="upgrade" d="M1023.932 454.895c-3.717 282.692-236.1 508.826-518.793 505.003-282.658-3.775-508.826-236.066-505.071-518.827 3.772-282.556 236.1-508.826 518.793-505.003 282.658 3.768 508.826 236.066 505.071 518.827zM623.991 478.696v-298.633h-223.983v298.633h-186.621l298.633 298.633 298.667-298.633h-186.679z" /><glyph unicode="&#xe615;" glyph-name="expand-close" d="M512.794 960c-283.187 0-512.794-229.581-512.794-512.794 0-283.187 229.606-512.794 512.794-512.794s512.794 229.632 512.794 512.794c0 283.213-229.581 512.794-512.794 512.794zM512.794-11.213c-253.158 0-458.394 205.261-458.394 458.368 0 253.158 205.261 458.394 458.394 458.394 253.184 0 458.394-205.235 458.394-458.394 0.026-253.107-205.21-458.368-458.394-458.368zM760.013 334.387l30.387 38.4-265.6 206.413-20.787 1.613-259.226-208.026 28.826-39.987 236.8 177.613z" /><glyph unicode="&#xe616;" glyph-name="expand-open" d="M512.794 960c-283.187 0-512.794-229.581-512.794-512.794 0-283.187 229.606-512.794 512.794-512.794s512.794 229.606 512.794 512.794c0 283.213-229.581 512.794-512.794 512.794zM512.794-11.213c-253.158 0-458.394 205.261-458.394 458.394 0 253.158 205.261 458.394 458.394 458.394 253.184 0 458.394-205.235 458.394-458.394 0.026-253.133-205.21-458.394-458.394-458.394zM265.6 505.6l-30.387-38.4 265.574-206.387 20.813-1.613 259.2 208-28.8 39.987-236.8-177.587z" /><glyph unicode="&#xe617;" glyph-name="gripper" d="M259.2 960h214.323v-214.323h-214.323v214.323zM259.2 690.125h214.323v-214.349h-214.323v214.349zM259.2 420.224h214.323v-214.349h-214.323v214.349zM259.2 150.349h214.323v-214.349h-214.323v214.349zM549.325 960h214.323v-214.323h-214.323v214.323zM549.325 690.125h214.323v-214.349h-214.323v214.349zM549.325 420.224h214.323v-214.349h-214.323v214.349zM549.325 150.349h214.323v-214.349h-214.323v214.349z" /><glyph unicode="&#xe618;" glyph-name="forward" d="M860.058 774.938v-272l-430.029 269.158-1.894-253.491-424.371 249.754-3.763-647.834 426.24 241.28-5.606-239.437 439.424 252.16v-259.635h163.942v660.045z" /><glyph unicode="&#xe619;" glyph-name="backward" d="M163.942 114.893v271.974l430.029-269.133 1.894 253.491 424.397-249.754 3.738 647.834-426.24-241.28 5.606 239.437-439.424-252.16v259.635h-163.942v-660.045z" /><glyph unicode="&#xe61a;" glyph-name="info" d="M505.704 919.002c-260.096-3.489-468.158-217.202-464.706-477.336 3.489-259.982 217.202-468.12 477.298-464.631s468.158 217.202 464.706 477.336c-3.413 260.058-217.202 468.12-477.298 464.631zM557.928 762.027c47.863 0 62.009-27.762 62.009-59.544 0-39.671-31.782-76.383-86.016-76.383-45.359 0-66.901 22.831-65.65 60.53 0 31.782 26.624 75.435 89.657 75.435zM435.162 153.619c-32.73 0-56.661 19.873-33.792 107.217l37.547 154.814c6.485 24.841 7.585 34.778 0 34.778-9.785 0-52.262-17.143-77.407-34.057l-16.346 26.776c79.607 66.446 171.16 105.472 210.375 105.472 32.73 0 38.153-38.722 21.807-98.266l-43.008-162.816c-7.585-28.786-4.286-38.722 3.262-38.722 9.785 0 41.984 11.871 73.614 36.75l18.47-24.841c-77.369-77.369-161.792-107.179-194.56-107.179z" /><glyph unicode="&#xe61b;" glyph-name="lock" d="M591.986 511.981h-16.005v192.019c0 105.851-86.13 192.019-192.019 192.019h-128c-105.851 0-192.019-86.13-192.019-192.019v-192.019h-16.005c-26.396 0-48.014-21.618-48.014-48.014v-479.991c0-26.396 21.618-48.014 48.014-48.014h544.009c26.396 0 48.014 21.618 48.014 48.014v479.991c0 26.396-21.618 48.014-48.014 48.014zM384 64h-128l27.838 139.188c-16.801 11.529-27.838 30.872-27.838 52.793 0 35.347 28.672 64.019 64.019 64.019s64.019-28.672 64.019-64.019c0-21.921-11.036-41.263-27.838-52.793l27.838-139.188zM448.019 511.981h-256v192.019c0 35.271 28.71 64.019 64.019 64.019h128c35.271 0 64.019-28.71 64.019-64.019v-192.019z" /><glyph unicode="&#xe61c;" glyph-name="loop" d="M870.4 642.56h-194.56v-143.36h153.6v-215.040h-634.88v215.040h215.040v-112.64l204.8 184.32-204.8 184.32v-112.64h-256c-56.51 0-102.4-45.815-102.4-102.4v-296.96c0-56.51 45.89-102.4 102.4-102.4h716.8c56.585 0 102.4 45.89 102.4 102.4v296.96c0 56.585-45.815 102.4-102.4 102.4z" /><glyph unicode="&#xe61d;" glyph-name="plus" d="M991.991 576h-351.991v351.991c0 17.673-14.336 32.009-32.009 32.009h-192.019c-17.673 0-32.009-14.336-32.009-32.009v-351.991h-351.991c-17.673 0-32.009-14.336-32.009-32.009v-192.019c0-17.673 14.336-32.009 32.009-32.009h351.991v-351.991c0-17.673 14.336-32.009 32.009-32.009h192.019c17.673 0 32.009 14.336 32.009 32.009v351.991h351.991c17.673 0 32.009 14.336 32.009 32.009v192.019c0 17.673-14.336 32.009-32.009 32.009z" /><glyph unicode="&#xe61e;" glyph-name="recover" d="M505.704 919.002c-260.096-3.489-468.158-217.126-464.706-477.298 3.489-260.21 217.202-468.158 477.298-464.744 260.134 3.489 468.233 217.202 464.706 477.298-3.489 260.21-217.202 468.233-477.298 464.744zM506.577 857.6c70.163 0.986 136.382-15.853 194.56-46.118l-63.374-105.662c-38.002 18.47-80.631 28.937-125.762 28.937-45.056 0-87.723-10.43-125.687-28.975l-63.336 105.624c54.993 28.672 117.343 45.321 183.599 46.232zM254.255 322.313l-105.586-63.298c-28.672 54.955-45.321 117.305-46.194 183.486-0.986 70.201 15.853 136.457 46.118 194.56l105.624-63.45c-18.546-37.926-28.975-80.555-28.975-125.649 0-45.056 10.43-87.723 28.975-125.687zM517.461 38.438c-70.163-0.986-136.457 15.853-194.56 46.118l63.374 105.662c38.002-18.546 80.631-28.975 125.687-28.975 45.094 0 87.761 10.392 125.687 28.937l63.336-105.586c-54.993-28.634-117.305-45.246-183.561-46.194zM512 222.758c-124.397 0-225.242 100.883-225.242 225.242 0 124.397 100.883 225.28 225.242 225.28 124.473 0 225.28-100.883 225.28-225.28s-100.807-225.242-225.28-225.242zM769.745 322.313c18.546 38.002 28.975 80.631 28.975 125.687 0 45.094-10.43 87.723-28.975 125.687l105.586 63.374c28.672-54.993 45.359-117.305 46.232-183.561 0.91-70.201-15.929-136.457-46.194-194.56l-105.624 63.336z" /><glyph unicode="&#xe61f;" glyph-name="refresh" horiz-adv-x="1176" d="M906.126 824.187v0c-91.174 75.89-202.487 113.171-312.548 113.057-127.014 0.038-253.611-49.683-348.16-145.636l-95.004 79.265-1.593-305.342 300.184 56.282-99.442 82.944c67.546 64.247 155.269 97.204 244.015 97.28 79.948-0.038 159.782-26.7 226.114-81.806 84.347-70.125 127.659-170.629 127.772-272.46-0.038-14.715-0.948-29.431-2.769-44.070l137.519 26.283c0.19 5.954 0.303 11.871 0.303 17.787 0.152 140.098-60.151 279.78-176.431 376.415zM839.035 193.024c-67.736-65.498-156.255-99.025-245.912-99.1-79.986 0.038-159.82 26.738-226.114 81.806-84.347 70.125-127.697 170.629-127.772 272.498 0 16.839 1.252 33.716 3.679 50.366l-138.164-25.941c-0.379-8.116-0.683-16.346-0.683-24.462-0.114-140.174 60.226-279.817 176.545-376.491 91.136-75.852 202.411-113.057 312.51-112.981h0.341c127.924 0 255.241 50.441 349.943 147.759l90.795-75.207 0.569 305.38-299.956-57.344 104.183-86.281z" /><glyph unicode="&#xe620;" glyph-name="remove-small" horiz-adv-x="1176" d="M593.351 938.268c-270.753 0-490.268-219.477-490.268-490.231s219.515-490.268 490.268-490.268 490.231 219.515 490.231 490.268c0 270.753-219.477 490.231-490.231 490.231zM828.947 276.347l-72.363-72.363-162.095 162.133-164.902-164.902-73.121 73.121 164.902 164.902-161.678 161.678 72.363 72.325 161.602-161.678 165.774 165.736 73.121-73.083-165.774-165.736 162.171-162.133z" /><glyph unicode="&#xe621;" glyph-name="retweet" d="M254.976 284.16v267.264h103.424l-179.2 203.776-179.2-203.776h103.424v-308.224c0-56.51 45.815-102.4 102.4-102.4h459.776l-131.186 143.36h-279.438zM920.538 344.576v308.224c0 56.51-45.89 102.4-102.4 102.4h-459.738l131.11-143.36h279.514v-267.264h-103.424l179.2-203.776 179.2 203.776h-103.462z" /><glyph unicode="&#xe622;" glyph-name="unlocked" d="M768 895.981h-128c-105.851 0-192.019-86.13-192.019-192.019v-192.019h-400.005c-26.396 0-48.014-21.618-48.014-48.014v-479.991c0-26.396 21.618-48.014 48.014-48.014h544.009c26.396 0 48.014 21.618 48.014 48.014v479.991c0 26.396-21.618 48.014-48.014 48.014h-16.005v192.019c0 35.271 28.71 64.019 64.019 64.019h128c35.271 0 64.019-28.71 64.019-64.019v-192.019h128v192.019c0 105.851-86.13 192.019-192.019 192.019zM384 64h-128l27.838 139.188c-16.801 11.529-27.838 30.872-27.838 52.793 0 35.347 28.672 64.019 64.019 64.019s64.019-28.672 64.019-64.019c0-21.921-11.036-41.263-27.838-52.793l27.838-139.188z" /><glyph unicode="&#xe623;" glyph-name="warning" horiz-adv-x="1176" d="M593.351 960l-593.351-1023.962h1186.74l-593.351 1023.962zM653.236 60.549h-125.421v121.211h125.421v-121.211zM622.175 231.671h-62.502l-34.816 288.313v156.748h131.3v-156.748l-33.982-288.313z" /><glyph unicode="&#xe624;" glyph-name="arrow-left" d="M0 448l512-512v320.019h512v384h-512v320.019z" /><glyph unicode="&#xe625;" glyph-name="arrow-right" d="M1024 448l-512 512v-320.019h-512v-384h512v-320.019z" /><glyph unicode="&#xe626;" glyph-name="back-arrow" d="M402.735 813.265l-320.019-320.019c-24.993-24.993-24.993-65.498 0-90.491l320.019-320.019c24.993-24.993 65.498-24.993 90.491 0s24.993 65.498 0 90.491l-210.754 210.754h613.49c35.347 0 64.019 28.634 64.019 64.019s-28.672 64.019-64.019 64.019h-613.49l210.754 210.754c12.478 12.478 18.735 28.862 18.735 45.246s-6.258 32.768-18.735 45.246c-24.993 24.993-65.498 24.993-90.491 0z" /><glyph unicode="&#xe627;" glyph-name="calendar" horiz-adv-x="1176" d="M507.259 381.478h-102.059v-101.717h102.059v101.717zM650.885 245.286h-101.945v-101.717h101.945v101.717zM507.259 245.286h-102.059v-101.717h102.059v101.717zM507.259 517.67h-102.059v-101.679h102.059v101.679zM843.131 715.909c23.4 0 42.287 18.887 42.287 42.174v145.408c0 23.324-18.887 42.174-42.287 42.174s-42.325-18.849-42.325-42.174v-145.408c0.038-23.324 18.925-42.174 42.325-42.174zM343.419 715.909c23.362 0 42.249 18.887 42.249 42.174v145.408c0 23.324-18.887 42.174-42.249 42.174-23.4 0-42.325-18.849-42.325-42.174v-145.408c0-23.324 18.925-42.174 42.325-42.174zM363.444 381.478h-102.059v-101.717h102.059v101.717zM363.444 245.286h-102.059v-101.717h102.059v101.717zM650.885 381.478h-101.945v-101.717h101.945v101.717zM938.325 381.478h-102.059v-101.717h102.059v101.717zM938.325 517.67h-102.059v-101.679h102.059v101.679zM899.337 875.615v-46.914c17.598-15.474 28.71-38.153 28.71-63.412 0-46.801-37.964-84.764-84.916-84.764s-84.954 37.964-84.954 84.764c0 25.259 11.15 47.938 28.71 63.412v46.914h-387.262v-46.914c17.56-15.474 28.71-38.153 28.71-63.412 0-46.801-38.002-84.764-84.916-84.764s-84.954 37.964-84.954 84.764c0 25.259 11.15 47.938 28.71 63.412v46.914h-192.322v-925.279h997.035v925.279h-192.512zM999.234 44.696h-809.832v589.938h809.832v-589.938zM650.885 517.67h-101.945v-101.679h101.945v101.679zM794.624 517.67h-101.983v-101.679h101.983v101.679zM794.624 245.286h-101.983v-101.717h101.983v101.717zM794.624 381.478h-101.983v-101.717h101.983v101.717z" /><glyph unicode="&#xe628;" glyph-name="caret-down" d="M132.21 673.242c-13.881 13.729-36.295 13.729-50.138 0-13.805-13.653-13.805-35.878 0-49.607l404.897-400.877c13.881-13.729 36.257-13.729 50.138 0l404.897 400.877c13.805 13.729 13.881 35.878 0 49.607s-36.371 13.729-50.138 0.038l-379.866-365.606-379.79 365.568z" /><glyph unicode="&#xe629;" glyph-name="caret-left" d="M737.242 68.21c13.729-13.881 13.729-36.257 0-50.138s-35.878-13.881-49.607 0l-400.877 404.821c-13.729 13.881-13.729 36.295 0 50.138l400.877 404.897c13.729 13.881 35.878 13.881 49.607 0s13.729-36.257 0-50.138l-365.568-379.79 365.568-379.79z" /><glyph unicode="&#xe62a;" glyph-name="caret-right" d="M286.72 68.21c-13.729-13.881-13.729-36.257 0-50.138s35.878-13.881 49.607 0l400.877 404.821c13.729 13.881 13.729 36.295 0 50.138l-400.915 404.897c-13.729 13.881-35.878 13.881-49.607 0s-13.729-36.257 0-50.138l365.568-379.79-365.568-379.79z" /><glyph unicode="&#xe62b;" glyph-name="caret-up" d="M891.79 222.758c13.881-13.729 36.295-13.729 50.138 0 13.881 13.729 13.881 35.878 0 49.607l-404.897 400.877c-13.805 13.729-36.257 13.729-50.062 0l-404.897-400.877c-13.805-13.729-13.881-35.878 0-49.607s36.257-13.729 50.138 0l379.79 365.606 379.79-365.606z" /><glyph unicode="&#xe62c;" glyph-name="ccw" d="M574.767 867.84c-227.593 0-412.672-182.386-418.247-409.335h-125.8l188.378-209.92 188.302 209.92h-146.242c5.537 168.998 143.777 304.393 313.609 304.393 173.397 0 313.913-140.971 313.913-314.899s-140.478-314.861-313.913-314.861c-69.48 0-133.689 22.718-185.685 61.099l-71.983-76.99c70.997-55.751 160.465-89.050 257.707-89.050 231.159 0 418.551 187.961 418.551 419.84-0.038 231.879-187.43 419.84-418.551 419.84z" /><glyph unicode="&#xe62d;" glyph-name="check-mage" horiz-adv-x="1176" d="M996.617 833.214l-513.555-513.555-256.796 256.834-128.379-128.417 385.214-385.252 641.896 642.010z" /><glyph unicode="&#xe62e;" glyph-name="clock" d="M512 919.040c-260.134 0-471.040-210.944-471.040-471.040 0-260.134 210.906-471.040 471.040-471.040s471.040 210.906 471.040 471.040c0 260.134-210.906 471.040-471.040 471.040zM512 79.36c-203.624 0-368.64 165.054-368.64 368.64s165.016 368.64 368.64 368.64 368.64-165.054 368.64-368.64-165.016-368.64-368.64-368.64zM547.84 714.24h-71.68v-281.069l174.345-174.345 50.669 50.707-153.335 153.335z" /><glyph unicode="&#xe62f;" glyph-name="close-mage" horiz-adv-x="1176" d="M1094.391 882.29l-77.71 77.71-423.329-423.347-423.33 423.347-77.71-77.672 423.35-423.368-423.312-423.329 77.672-77.71 423.338 423.338 423.283-423.3 77.671 77.71-423.263 423.281z" /><glyph unicode="&#xe630;" glyph-name="delete" horiz-adv-x="1176" d="M337.541-61.004h513.024l64.512 645.916h-639.128l61.592-645.916zM737.394 805.831v116.508c0 19.191-15.398 34.702-34.361 34.702h-217.847c-19.001 0-34.361-15.55-34.361-34.702v-114.574c-73.576-8.382-150.149-24.614-226.494-52.338v-106.989h738.001v109.833c0 0-90.074 31.403-224.977 47.559zM668.937 812.241c-47.749 3.224-99.252 4.096-153.297 0.986v61.44c0 9.519 7.623 17.332 17.143 17.332h118.936c9.519 0 17.218-7.813 17.218-17.332v-62.426z" /><glyph unicode="&#xe631;" glyph-name="edit" horiz-adv-x="1176" d="M928.503 933.111l-111.502-112.109 156.065-156.9 111.502 112.071-156.065 156.937zM215.002 215.59l156.065-156.9 535.211 538.093-156.065 156.9-535.211-538.093zM103.917-47.161l188.985 49.873-139.302 140.098-49.683-190.009z" /><glyph unicode="&#xe632;" glyph-name="error" d="M1014.67 137.349c0 0 0 0 0 0l-310.651 310.651 310.651 310.651c0 0 0 0 0 0 3.337 3.337 5.765 7.244 7.32 11.416 4.248 11.378 1.82 24.69-7.32 33.83l-146.735 146.735c-9.14 9.14-22.452 11.567-33.83 7.32-4.172-1.555-8.078-3.982-11.416-7.32 0 0 0 0 0 0l-310.651-310.651-310.651 310.651c0 0 0 0 0 0-3.337 3.337-7.244 5.765-11.416 7.32-11.378 4.248-24.69 1.82-33.83-7.32l-146.735-146.735c-9.14-9.14-11.567-22.452-7.32-33.83 1.555-4.172 3.982-8.078 7.32-11.416 0 0 0 0 0 0l310.651-310.651-310.651-310.651c0 0 0 0 0 0-3.337-3.337-5.765-7.244-7.32-11.416-4.248-11.378-1.82-24.69 7.32-33.83l146.735-146.735c9.14-9.14 22.452-11.567 33.83-7.32 4.172 1.555 8.078 3.982 11.416 7.32 0 0 0 0 0 0l310.651 310.651 310.651-310.651c0 0 0 0 0 0 3.337-3.337 7.244-5.765 11.416-7.32 11.378-4.248 24.69-1.82 33.83 7.32l146.735 146.735c9.14 9.14 11.567 22.452 7.32 33.83-1.555 4.172-3.982 8.078-7.32 11.416z" /><glyph unicode="&#xe633;" glyph-name="help" horiz-adv-x="1176" d="M593.351 937.434c-270.336 0-489.434-219.098-489.434-489.358s219.098-489.434 489.434-489.434 489.434 219.136 489.434 489.434-219.136 489.358-489.434 489.358zM635.752 133.404c-11.985-11.719-26.396-17.636-43.16-17.636-8.154 0-15.967 1.517-23.4 4.589-7.358 3.034-13.843 7.168-19.456 12.174-5.613 5.158-10.126 11.226-13.388 18.356-3.337 7.13-4.968 14.753-4.968 22.945 0 16.308 5.992 30.303 17.977 42.060 11.947 11.681 26.396 17.598 43.198 17.598 16.308 0 30.606-5.689 42.78-16.801 12.25-11.188 18.318-24.993 18.318-41.339-0.038-16.384-5.992-30.303-17.939-41.984zM778.923 577.327c-3.982-13.767-9.747-26.396-17.18-37.774-7.471-11.454-16.498-22.49-27.079-33.071s-22.49-21.618-35.65-33.033c-11.454-9.785-20.783-18.318-27.913-25.79-7.168-7.396-12.895-14.867-17.218-22.338-4.286-7.433-7.282-15.398-9.026-24.007-1.707-8.609-2.617-49.721-2.617-62.35v-22.338h-101.376v32.616c0 13.729 0.986 56.661 3.034 67.584s5.158 21.125 9.481 30.872 10.012 19.228 17.18 28.369c7.168 9.14 16.232 18.887 27.079 29.203l38.647 36.902c10.847 9.747 20.177 20.632 27.951 32.616 7.737 12.060 11.529 26.7 11.529 43.88 0 22.3-6.978 41.036-21.011 56.206-14.071 15.17-33.944 22.793-59.695 22.793-13.16 0-25.069-2.389-35.65-7.282-10.619-4.817-19.797-11.454-27.496-19.759-7.737-8.344-13.577-17.901-17.598-28.786-3.982-10.847-6.334-21.997-6.865-33.527l-105.624 9.444c3.413 27.496 10.733 51.959 21.921 73.463 11.112 21.466 25.562 39.595 43.311 54.575 17.711 14.829 38.078 26.169 61.023 33.944 22.869 7.699 47.521 11.605 73.842 11.605 24.614 0 47.976-3.603 70.049-10.771 21.959-7.168 41.491-17.711 58.406-31.782 16.839-14.033 30.227-31.365 39.936-51.959 9.709-20.632 14.564-44.411 14.564-71.263 0-18.356-2.010-34.475-5.992-48.166z" /><glyph unicode="&#xe634;" glyph-name="history" d="M574.805 867.84c-227.631 0-412.71-182.386-418.247-409.335h-125.838l188.378-209.958 188.302 209.958h-146.242c5.537 168.998 143.777 304.393 313.647 304.393 173.359 0 313.875-140.971 313.875-314.899s-140.478-314.861-313.875-314.861c-69.518 0-133.727 22.718-185.761 61.099l-71.983-76.99c71.073-55.751 160.503-89.050 257.745-89.050 231.121 0 418.513 187.961 418.513 419.84-0.038 231.879-187.43 419.84-418.513 419.84zM537.6 673.28v-240.109l153.865-153.865 50.669 50.669-132.855 132.855v210.413h-71.68z" /><glyph unicode="&#xe635;" glyph-name="export" d="M383.462 382.49h255.693v213.043h127.795l-255.642 255.667-255.642-255.667h127.795zM852.173 382.49v-170.394h-681.754v170.394h-170.419v-340.89h1022.618v340.89z" /><glyph unicode="&#xe636;" glyph-name="import" d="M639.155 851.2h-255.693v-213.043h-127.795l255.667-255.667 255.616 255.667h-127.795zM852.173 382.49v-170.394h-681.754v170.394h-170.419v-340.89h1022.618v340.89z" /><glyph unicode="&#xe637;" glyph-name="dot" d="M505.139 959.915c-282.658-3.775-508.826-236.066-505.071-518.827 3.772-282.556 236.1-508.826 518.793-505.003 282.658 3.768 508.826 236.066 505.071 518.827-3.717 282.658-236.1 508.826-518.793 505.003z" /><glyph unicode="&#xe638;" glyph-name="not-installed" d="M510.413 960c-281.907 0-510.413-228.582-510.413-510.413 0-281.933 228.506-510.464 510.413-510.464s510.387 228.557 510.387 510.464c0 281.83-228.48 510.413-510.387 510.413zM865.843 449.587c0-69.99-20.506-135.27-55.578-190.285l-490.163 490.163c55.091 35.021 120.32 55.475 190.31 55.475 195.942 0 355.43-159.411 355.43-355.354zM154.957 449.587c0 69.939 20.506 135.245 55.578 190.31l490.189-490.189c-55.066-35.072-120.371-55.501-190.31-55.501-195.942-0.026-355.456 159.437-355.456 355.379z" /><glyph unicode="&#xe639;" glyph-name="disabled" d="M511.77 960c-282.778 0-512.102-229.222-512.102-512.179 0-282.829 229.325-512.102 512.102-512.102 282.931-0.026 512.23 229.248 512.23 512.102 0 282.957-229.299 512.179-512.23 512.179zM143.718 540.032h736.205v-184.269h-736.205v184.269z" /><glyph unicode="&#xe63a;" glyph-name="menu-item" horiz-adv-x="903" d="M857.675 670.587l-403.18 240.514-402.726-240.514v-457.026l403.18-240.515 402.726 240.514v457.027zM454.857 95.535l-298.427 178.383v335.966l298.157 178.729 298.428-178.383v-335.966l-298.158-178.729z" /><glyph unicode="&#xe63b;" glyph-name="tag" d="M904.192 959.973l-307.234-0.116-596.89-596.958 426.906-426.906 596.958 596.958-0.113 305.596-119.603 121.426zM858.679 646.663c-39.997-40.001-104.854-40.001-144.794 0-40.001 40.001-40.001 104.796 0 144.794 39.939 40.001 104.796 40.001 144.794 0 39.997-39.997 39.997-104.793 0-144.794z" /><glyph unicode="&#xe63c;" glyph-name="camera" d="M982.767 728.098h-250.095l-59.255 121.364c0 0-11.827 25.201-42.11 25.201-23.375 0-169.366 0-235.25 0-32.969 0-44.001-25.027-44.001-25.027l-57.484-121.539h-253.406c-22.74 0-41.131-18.459-41.131-41.267v-624.333c0-22.743 18.401-41.199 41.131-41.199h941.636c22.74 0 41.199 18.459 41.199 41.199v624.299c0 22.798-18.456 41.267-41.199 41.267zM512 136.090c-138.793 0-251.597 113.015-251.597 251.931 0 138.912 112.845 251.87 251.597 251.87 138.68 0 251.597-112.981 251.597-251.87 0-138.909-112.913-251.931-251.597-251.931zM512 539.068c-83.255 0-150.972-67.714-150.972-150.972 0-83.197 67.71-150.903 150.972-150.903 83.258 0 150.903 67.714 150.903 150.903 0 83.255-67.652 150.972-150.903 150.972z" /><glyph unicode="&#xe63d;" glyph-name="grid" d="M0.010 959.628h279.074v-279.074h-279.074zM372.77 959.628h279.074v-279.074h-279.074zM744.892 959.628h279.074v-279.074h-279.074zM0.010 587.503h279.074v-279.074h-279.074zM372.77 587.503h279.074v-279.074h-279.074zM744.892 587.503h279.074v-279.074h-279.074zM0.010 215.415h279.074v-279.074h-279.074zM372.77 215.415h279.074v-279.074h-279.074zM744.892 215.415h279.074v-279.074h-279.074z" /><glyph unicode="&#xe63e;" glyph-name="list-menu" d="M0.010 771.516h1023.966v-136.509h-1023.966zM0.010 517.53h1023.966v-136.506h-1023.966zM0.010 260.983h1023.966v-136.513h-1023.966z" /><glyph unicode="&#xe63f;" glyph-name="cart" d="M771.001 183.263c-55.445 0-100.448-44.754-100.448-100.2s44.879-100.324 100.448-100.324 100.448 44.879 100.448 100.324-45.003 100.2-100.448 100.2zM771.001 41.293c-23.123 0-41.77 18.648-41.77 41.771s18.647 41.77 41.77 41.77c23.247 0 41.895-18.648 41.895-41.77s-18.648-41.771-41.895-41.771zM469.532 183.263c-55.445 0-100.449-44.754-100.449-100.2s45.003-100.324 100.449-100.324c55.445 0 100.448 44.879 100.448 100.324s-45.003 100.2-100.448 100.2zM469.532 41.293c-23.123 0-41.771 18.648-41.771 41.771s18.648 41.77 41.771 41.77 41.77-18.648 41.77-41.77-18.648-41.771-41.77-41.771zM823.587 465.588c-130.036 0-238.441 91.622-264.547 213.825h-207.237l-136.749 198.162v1.865h-207.237v-83.541h169.942l78.693-117.729 83.417-412.857h581.183l49.23 243.786c-42.268-27.474-92.616-43.511-146.694-43.511zM1023.862 710.244v45.376l-55.073 18.026-12.929 31.204 24.863 52.71-31.95 32.074-5.967-2.984-45.5-23.123-31.328 12.929-19.642 54.948h-45.376l-2.114-6.464-15.912-48.608-31.203-12.929-52.835 24.863-32.074-31.95 3.108-5.967 23.247-45.624-13.053-31.328-54.948-19.766v-45.376l6.34-2.113 48.732-15.788 12.929-31.204-24.863-52.71 32.074-32.074 6.092 3.108 45.376 22.999 31.328-12.929 19.642-54.824h45.376l2.113 6.464 15.913 48.359 31.203 12.929 52.71-24.988 32.198 32.074-3.108 6.092-23.247 45.624 12.929 31.203 54.948 19.766zM824.582 668.473c-35.057 0-63.65 28.469-63.65 63.526 0 35.182 28.469 63.526 63.65 63.526s63.526-28.469 63.526-63.526c-0.124-35.182-28.469-63.526-63.526-63.526z" /><glyph unicode="&#xe640;" glyph-name="screen" horiz-adv-x="1159" d="M723.661 70.399c-2.404 10.843-4.034 21.47-5.282 31.583h-277.528c-2.458-20.233-6.917-43.087-14.646-64.305-7.79-21.277-18.796-40.54-33.824-54.15-15.028-13.552-33.689-22.104-59.788-22.158v-25.369h494.020v25.369c-26.142 0.058-44.737 8.61-59.838 22.158-22.44 20.307-35.961 53.91-43.114 86.873zM1126.214 960h-1093.209c-18.22 0-33.005-15.024-33.005-33.596v-731.259c0-18.576 14.785-33.623 33.005-33.623h1093.209c18.224 0 33.067 15.051 33.067 33.623v731.259c0 18.572-14.843 33.596-33.067 33.596zM1079.193 243.078h-999.234v635.394h999.234v-635.394z" /><glyph unicode="&#xe641;" glyph-name="video" horiz-adv-x="2041" d="M2041.366 958.898v-1021.449h-175.926l-411.263 409.297v204.59l411.263 407.568h175.926zM1305.997-29.076c0-19.377-15.608-34.924-34.856-34.924h-1236.279c-19.255 0-34.863 15.547-34.863 34.924v954.275c0 19.248 15.608 34.801 34.863 34.801h1236.279c19.248 0 34.856-15.553 34.856-34.801v-954.275z" /><glyph unicode="&#xe642;" glyph-name="revert" horiz-adv-x="1404" d="M1042.226 660.151h-598.393v299.849l-443.833-384.316 443.833-384.403v299.859h598.393c106.478 0 192.801-86.318 192.801-192.801s-86.318-192.796-192.801-192.796v-0.483l-452.707-0.005c-46.695-0.005-84.53-37.845-84.53-84.535 0-46.68 37.84-84.525 84.535-84.525 0.377 0 0.744 0.053 1.121 0.058h451.581c199.964 0 362.044 162.085 362.044 362.039 0 199.964-162.080 362.059-362.044 362.059z" /><glyph unicode="&#xe643;" glyph-name="clip" d="M939.616 811.616c112.512-112.448 112.512-294.816 0-407.264l-350.944-350.976c-12.512-12.544-32.736-12.544-45.248 0-12.576 12.512-12.576 32.704 0 45.248l346.432 346.464c87.488 87.488 87.488 229.248-0.064 316.768-87.36 87.488-229.248 87.488-316.736 0l-462.304-456.864c-62.496-62.464-62.496-163.776 0-226.24 62.496-62.496 163.744-62.496 226.24 0l466.88 461.344c37.44 37.44 37.44 98.336 0 135.776-37.44 37.408-98.304 37.408-135.744 0l-351.008-351.008c-12.512-12.512-32.736-12.512-45.248 0-12.512 12.544-12.512 32.736 0 45.28l350.976 350.976c62.432 62.464 163.744 62.464 226.24 0 62.496-62.496 62.496-163.776 0-226.272l-466.88-461.376c-87.296-87.328-229.408-87.328-316.736 0s-87.328 229.472 0 316.8l466.88 461.344c112.448 112.512 294.816 112.512 407.264 0z" /></font></defs></svg>
\ No newline at end of file
diff --git a/app/design/adminhtml/Magento/backend/web/fonts/admin-icons/admin-icons.ttf b/app/design/adminhtml/Magento/backend/web/fonts/admin-icons/admin-icons.ttf
old mode 100644
new mode 100755
index aaff9a417b4982c0e7f8f7b7a93ff543de8ffad6..79a0cb0cdf0bba450ad26a1354c0e803a99b0baf
Binary files a/app/design/adminhtml/Magento/backend/web/fonts/admin-icons/admin-icons.ttf and b/app/design/adminhtml/Magento/backend/web/fonts/admin-icons/admin-icons.ttf differ
diff --git a/app/design/adminhtml/Magento/backend/web/fonts/admin-icons/admin-icons.woff b/app/design/adminhtml/Magento/backend/web/fonts/admin-icons/admin-icons.woff
old mode 100644
new mode 100755
index 0cca0682a56913e6bf874c4295dfd9a45ffd5e8a..13c2be8474a731a8f64b56943c39ed4446e6ca27
Binary files a/app/design/adminhtml/Magento/backend/web/fonts/admin-icons/admin-icons.woff and b/app/design/adminhtml/Magento/backend/web/fonts/admin-icons/admin-icons.woff differ
diff --git a/app/design/adminhtml/Magento/backend/web/fonts/admin-icons/admin-icons.woff2 b/app/design/adminhtml/Magento/backend/web/fonts/admin-icons/admin-icons.woff2
old mode 100644
new mode 100755
index 16fa0ed29431b24807691325406d2042f0695a60..46b41963b5a724c0f5c8b8cada7db07454f8be0e
Binary files a/app/design/adminhtml/Magento/backend/web/fonts/admin-icons/admin-icons.woff2 and b/app/design/adminhtml/Magento/backend/web/fonts/admin-icons/admin-icons.woff2 differ
diff --git a/app/design/adminhtml/Magento/backend/web/fonts/admin-icons/selection.json b/app/design/adminhtml/Magento/backend/web/fonts/admin-icons/selection.json
old mode 100644
new mode 100755
index 72faf3e576aaf913a37c1053fa3ccc315d69e997..6efc4b0fef1989e2f9b7b715e0a76e625229ea4a
--- a/app/design/adminhtml/Magento/backend/web/fonts/admin-icons/selection.json
+++ b/app/design/adminhtml/Magento/backend/web/fonts/admin-icons/selection.json
@@ -1,31 +1,6 @@
 {
 	"IcoMoonType": "selection",
 	"icons": [
-		{
-			"icon": {
-				"paths": [
-					"M1042.226 299.849h-598.393v-299.849l-443.833 384.316 443.833 384.403v-299.859h598.393c106.478 0 192.801 86.318 192.801 192.801s-86.318 192.796-192.801 192.796v0.483l-452.707 0.005c-46.695 0.005-84.53 37.845-84.53 84.535 0 46.68 37.84 84.525 84.535 84.525 0.377 0 0.744-0.053 1.121-0.058h451.581c199.964 0 362.044-162.085 362.044-362.039 0-199.964-162.080-362.059-362.044-362.059z"
-				],
-				"attrs": [],
-				"isMulticolor": false,
-				"width": 1404,
-				"grid": 0,
-				"tags": [
-					"revert"
-				]
-			},
-			"attrs": [],
-			"properties": {
-				"order": 126,
-				"id": 65,
-				"prevSize": 32,
-				"code": 58946,
-				"name": "revert"
-			},
-			"setIdx": 0,
-			"setId": 5,
-			"iconIdx": 0
-		},
 		{
 			"icon": {
 				"paths": [
@@ -50,7 +25,7 @@
 			},
 			"setIdx": 0,
 			"setId": 5,
-			"iconIdx": 1
+			"iconIdx": 0
 		},
 		{
 			"icon": {
@@ -75,7 +50,7 @@
 			},
 			"setIdx": 0,
 			"setId": 5,
-			"iconIdx": 2
+			"iconIdx": 1
 		},
 		{
 			"icon": {
@@ -102,7 +77,7 @@
 			},
 			"setIdx": 0,
 			"setId": 5,
-			"iconIdx": 3
+			"iconIdx": 2
 		},
 		{
 			"icon": {
@@ -136,7 +111,7 @@
 			},
 			"setIdx": 0,
 			"setId": 5,
-			"iconIdx": 4
+			"iconIdx": 3
 		},
 		{
 			"icon": {
@@ -188,7 +163,7 @@
 			},
 			"setIdx": 0,
 			"setId": 5,
-			"iconIdx": 5
+			"iconIdx": 4
 		},
 		{
 			"icon": {
@@ -219,7 +194,7 @@
 			},
 			"setIdx": 0,
 			"setId": 5,
-			"iconIdx": 6
+			"iconIdx": 5
 		},
 		{
 			"icon": {
@@ -247,7 +222,7 @@
 			},
 			"setIdx": 0,
 			"setId": 5,
-			"iconIdx": 7
+			"iconIdx": 6
 		},
 		{
 			"icon": {
@@ -281,7 +256,7 @@
 			},
 			"setIdx": 0,
 			"setId": 5,
-			"iconIdx": 8
+			"iconIdx": 7
 		},
 		{
 			"icon": {
@@ -315,7 +290,7 @@
 			},
 			"setIdx": 0,
 			"setId": 5,
-			"iconIdx": 9
+			"iconIdx": 8
 		},
 		{
 			"icon": {
@@ -343,7 +318,7 @@
 			},
 			"setIdx": 0,
 			"setId": 5,
-			"iconIdx": 10
+			"iconIdx": 9
 		},
 		{
 			"icon": {
@@ -371,7 +346,7 @@
 			},
 			"setIdx": 0,
 			"setId": 5,
-			"iconIdx": 11
+			"iconIdx": 10
 		},
 		{
 			"icon": {
@@ -399,7 +374,7 @@
 			},
 			"setIdx": 0,
 			"setId": 5,
-			"iconIdx": 12
+			"iconIdx": 11
 		},
 		{
 			"icon": {
@@ -427,7 +402,7 @@
 			},
 			"setIdx": 0,
 			"setId": 5,
-			"iconIdx": 13
+			"iconIdx": 12
 		},
 		{
 			"icon": {
@@ -455,7 +430,7 @@
 			},
 			"setIdx": 0,
 			"setId": 5,
-			"iconIdx": 14
+			"iconIdx": 13
 		},
 		{
 			"icon": {
@@ -484,7 +459,7 @@
 			},
 			"setIdx": 0,
 			"setId": 5,
-			"iconIdx": 15
+			"iconIdx": 14
 		},
 		{
 			"icon": {
@@ -513,7 +488,7 @@
 			},
 			"setIdx": 0,
 			"setId": 5,
-			"iconIdx": 16
+			"iconIdx": 15
 		},
 		{
 			"icon": {
@@ -541,7 +516,7 @@
 			},
 			"setIdx": 0,
 			"setId": 5,
-			"iconIdx": 17
+			"iconIdx": 16
 		},
 		{
 			"icon": {
@@ -569,7 +544,7 @@
 			},
 			"setIdx": 0,
 			"setId": 5,
-			"iconIdx": 18
+			"iconIdx": 17
 		},
 		{
 			"icon": {
@@ -598,7 +573,7 @@
 			},
 			"setIdx": 0,
 			"setId": 5,
-			"iconIdx": 19
+			"iconIdx": 18
 		},
 		{
 			"icon": {
@@ -626,7 +601,7 @@
 			},
 			"setIdx": 0,
 			"setId": 5,
-			"iconIdx": 20
+			"iconIdx": 19
 		},
 		{
 			"icon": {
@@ -654,7 +629,7 @@
 			},
 			"setIdx": 0,
 			"setId": 5,
-			"iconIdx": 21
+			"iconIdx": 20
 		},
 		{
 			"icon": {
@@ -682,7 +657,7 @@
 			},
 			"setIdx": 0,
 			"setId": 5,
-			"iconIdx": 22
+			"iconIdx": 21
 		},
 		{
 			"icon": {
@@ -711,7 +686,7 @@
 			},
 			"setIdx": 0,
 			"setId": 5,
-			"iconIdx": 23
+			"iconIdx": 22
 		},
 		{
 			"icon": {
@@ -739,7 +714,7 @@
 			},
 			"setIdx": 0,
 			"setId": 5,
-			"iconIdx": 24
+			"iconIdx": 23
 		},
 		{
 			"icon": {
@@ -767,7 +742,7 @@
 			},
 			"setIdx": 0,
 			"setId": 5,
-			"iconIdx": 25
+			"iconIdx": 24
 		},
 		{
 			"icon": {
@@ -795,7 +770,7 @@
 			},
 			"setIdx": 0,
 			"setId": 5,
-			"iconIdx": 26
+			"iconIdx": 25
 		},
 		{
 			"icon": {
@@ -823,7 +798,7 @@
 			},
 			"setIdx": 0,
 			"setId": 5,
-			"iconIdx": 27
+			"iconIdx": 26
 		},
 		{
 			"icon": {
@@ -851,7 +826,7 @@
 			},
 			"setIdx": 0,
 			"setId": 5,
-			"iconIdx": 28
+			"iconIdx": 27
 		},
 		{
 			"icon": {
@@ -880,7 +855,7 @@
 			},
 			"setIdx": 0,
 			"setId": 5,
-			"iconIdx": 29
+			"iconIdx": 28
 		},
 		{
 			"icon": {
@@ -908,7 +883,7 @@
 			},
 			"setIdx": 0,
 			"setId": 5,
-			"iconIdx": 30
+			"iconIdx": 29
 		},
 		{
 			"icon": {
@@ -937,7 +912,7 @@
 			},
 			"setIdx": 0,
 			"setId": 5,
-			"iconIdx": 31
+			"iconIdx": 30
 		},
 		{
 			"icon": {
@@ -966,7 +941,7 @@
 			},
 			"setIdx": 0,
 			"setId": 5,
-			"iconIdx": 32
+			"iconIdx": 31
 		},
 		{
 			"icon": {
@@ -994,7 +969,7 @@
 			},
 			"setIdx": 0,
 			"setId": 5,
-			"iconIdx": 33
+			"iconIdx": 32
 		},
 		{
 			"icon": {
@@ -1023,7 +998,7 @@
 			},
 			"setIdx": 0,
 			"setId": 5,
-			"iconIdx": 34
+			"iconIdx": 33
 		},
 		{
 			"icon": {
@@ -1051,7 +1026,7 @@
 			},
 			"setIdx": 0,
 			"setId": 5,
-			"iconIdx": 35
+			"iconIdx": 34
 		},
 		{
 			"icon": {
@@ -1079,7 +1054,7 @@
 			},
 			"setIdx": 0,
 			"setId": 5,
-			"iconIdx": 36
+			"iconIdx": 35
 		},
 		{
 			"icon": {
@@ -1107,7 +1082,7 @@
 			},
 			"setIdx": 0,
 			"setId": 5,
-			"iconIdx": 37
+			"iconIdx": 36
 		},
 		{
 			"icon": {
@@ -1135,7 +1110,7 @@
 			},
 			"setIdx": 0,
 			"setId": 5,
-			"iconIdx": 38
+			"iconIdx": 37
 		},
 		{
 			"icon": {
@@ -1166,7 +1141,7 @@
 			},
 			"setIdx": 0,
 			"setId": 5,
-			"iconIdx": 39
+			"iconIdx": 38
 		},
 		{
 			"icon": {
@@ -1197,7 +1172,7 @@
 			},
 			"setIdx": 0,
 			"setId": 5,
-			"iconIdx": 40
+			"iconIdx": 39
 		},
 		{
 			"icon": {
@@ -1246,7 +1221,7 @@
 			},
 			"setIdx": 0,
 			"setId": 5,
-			"iconIdx": 41
+			"iconIdx": 40
 		},
 		{
 			"icon": {
@@ -1274,7 +1249,7 @@
 			},
 			"setIdx": 0,
 			"setId": 5,
-			"iconIdx": 42
+			"iconIdx": 41
 		},
 		{
 			"icon": {
@@ -1303,7 +1278,7 @@
 			},
 			"setIdx": 0,
 			"setId": 5,
-			"iconIdx": 43
+			"iconIdx": 42
 		},
 		{
 			"icon": {
@@ -1334,7 +1309,7 @@
 			},
 			"setIdx": 0,
 			"setId": 5,
-			"iconIdx": 44
+			"iconIdx": 43
 		},
 		{
 			"icon": {
@@ -1365,7 +1340,7 @@
 			},
 			"setIdx": 0,
 			"setId": 5,
-			"iconIdx": 45
+			"iconIdx": 44
 		},
 		{
 			"icon": {
@@ -1397,7 +1372,7 @@
 			},
 			"setIdx": 0,
 			"setId": 5,
-			"iconIdx": 46
+			"iconIdx": 45
 		},
 		{
 			"icon": {
@@ -1429,7 +1404,7 @@
 			},
 			"setIdx": 0,
 			"setId": 5,
-			"iconIdx": 47
+			"iconIdx": 46
 		},
 		{
 			"icon": {
@@ -1461,7 +1436,7 @@
 			},
 			"setIdx": 0,
 			"setId": 5,
-			"iconIdx": 48
+			"iconIdx": 47
 		},
 		{
 			"icon": {
@@ -1493,7 +1468,7 @@
 			},
 			"setIdx": 0,
 			"setId": 5,
-			"iconIdx": 49
+			"iconIdx": 48
 		},
 		{
 			"icon": {
@@ -1521,7 +1496,7 @@
 			},
 			"setIdx": 0,
 			"setId": 5,
-			"iconIdx": 50
+			"iconIdx": 49
 		},
 		{
 			"icon": {
@@ -1565,7 +1540,7 @@
 			},
 			"setIdx": 0,
 			"setId": 5,
-			"iconIdx": 51
+			"iconIdx": 50
 		},
 		{
 			"icon": {
@@ -1601,7 +1576,7 @@
 			},
 			"setIdx": 0,
 			"setId": 5,
-			"iconIdx": 52
+			"iconIdx": 51
 		},
 		{
 			"icon": {
@@ -1653,7 +1628,7 @@
 			},
 			"setIdx": 0,
 			"setId": 5,
-			"iconIdx": 53
+			"iconIdx": 52
 		},
 		{
 			"icon": {
@@ -1689,7 +1664,7 @@
 			},
 			"setIdx": 0,
 			"setId": 5,
-			"iconIdx": 54
+			"iconIdx": 53
 		},
 		{
 			"icon": {
@@ -1725,7 +1700,7 @@
 			},
 			"setIdx": 0,
 			"setId": 5,
-			"iconIdx": 55
+			"iconIdx": 54
 		},
 		{
 			"icon": {
@@ -1788,7 +1763,7 @@
 			},
 			"setIdx": 0,
 			"setId": 5,
-			"iconIdx": 56
+			"iconIdx": 55
 		},
 		{
 			"icon": {
@@ -1824,7 +1799,7 @@
 			},
 			"setIdx": 0,
 			"setId": 5,
-			"iconIdx": 57
+			"iconIdx": 56
 		},
 		{
 			"icon": {
@@ -1860,7 +1835,7 @@
 			},
 			"setIdx": 0,
 			"setId": 5,
-			"iconIdx": 58
+			"iconIdx": 57
 		},
 		{
 			"icon": {
@@ -1895,7 +1870,7 @@
 			},
 			"setIdx": 0,
 			"setId": 5,
-			"iconIdx": 59
+			"iconIdx": 58
 		},
 		{
 			"icon": {
@@ -1931,7 +1906,7 @@
 			},
 			"setIdx": 0,
 			"setId": 5,
-			"iconIdx": 60
+			"iconIdx": 59
 		},
 		{
 			"icon": {
@@ -1967,7 +1942,7 @@
 			},
 			"setIdx": 0,
 			"setId": 5,
-			"iconIdx": 61
+			"iconIdx": 60
 		},
 		{
 			"icon": {
@@ -2003,7 +1978,7 @@
 			},
 			"setIdx": 0,
 			"setId": 5,
-			"iconIdx": 62
+			"iconIdx": 61
 		},
 		{
 			"icon": {
@@ -2048,7 +2023,7 @@
 			},
 			"setIdx": 0,
 			"setId": 5,
-			"iconIdx": 63
+			"iconIdx": 62
 		},
 		{
 			"icon": {
@@ -2084,7 +2059,7 @@
 			},
 			"setIdx": 0,
 			"setId": 5,
-			"iconIdx": 64
+			"iconIdx": 63
 		},
 		{
 			"icon": {
@@ -2120,7 +2095,58 @@
 			},
 			"setIdx": 0,
 			"setId": 5,
+			"iconIdx": 64
+		},
+		{
+			"icon": {
+				"paths": [
+					"M1042.226 299.849h-598.393v-299.849l-443.833 384.316 443.833 384.403v-299.859h598.393c106.478 0 192.801 86.318 192.801 192.801s-86.318 192.796-192.801 192.796v0.483l-452.707 0.005c-46.695 0.005-84.53 37.845-84.53 84.535 0 46.68 37.84 84.525 84.535 84.525 0.377 0 0.744-0.053 1.121-0.058h451.581c199.964 0 362.044-162.085 362.044-362.039 0-199.964-162.080-362.059-362.044-362.059z"
+				],
+				"width": 1404,
+				"attrs": [],
+				"isMulticolor": false,
+				"tags": [
+					"revert"
+				],
+				"grid": 0
+			},
+			"attrs": [],
+			"properties": {
+				"order": 129,
+				"id": 65,
+				"prevSize": 32,
+				"code": 58946,
+				"name": "revert"
+			},
+			"setIdx": 0,
+			"setId": 5,
 			"iconIdx": 65
+		},
+		{
+			"icon": {
+				"paths": [
+					"M939.616 148.384c112.512 112.448 112.512 294.816 0 407.264l-350.944 350.976c-12.512 12.544-32.736 12.544-45.248 0-12.576-12.512-12.576-32.704 0-45.248l346.432-346.464c87.488-87.488 87.488-229.248-0.064-316.768-87.36-87.488-229.248-87.488-316.736 0l-462.304 456.864c-62.496 62.464-62.496 163.776 0 226.24 62.496 62.496 163.744 62.496 226.24 0l466.88-461.344c37.44-37.44 37.44-98.336 0-135.776-37.44-37.408-98.304-37.408-135.744 0l-351.008 351.008c-12.512 12.512-32.736 12.512-45.248 0-12.512-12.544-12.512-32.736 0-45.28l350.976-350.976c62.432-62.464 163.744-62.464 226.24 0 62.496 62.496 62.496 163.776 0 226.272l-466.88 461.376c-87.296 87.328-229.408 87.328-316.736 0-87.328-87.328-87.328-229.472 0-316.8l466.88-461.344c112.448-112.512 294.816-112.512 407.264 0z"
+				],
+				"attrs": [],
+				"isMulticolor": false,
+				"tags": [
+					"clip",
+					"paperclip",
+					"attachment"
+				],
+				"grid": 32
+			},
+			"attrs": [],
+			"properties": {
+				"id": 0,
+				"order": 130,
+				"prevSize": 32,
+				"code": 58947,
+				"name": "clip"
+			},
+			"setIdx": 1,
+			"setId": 4,
+			"iconIdx": 0
 		}
 	],
 	"height": 1024,
diff --git a/app/design/frontend/Magento/blank/web/css/print.less b/app/design/frontend/Magento/blank/web/css/print.less
index 43b4eca41f7b4d4af7bd48ff31d1e6657067c85a..be692fb409411b0adb28daa6a392689c9374fe13 100644
--- a/app/design/frontend/Magento/blank/web/css/print.less
+++ b/app/design/frontend/Magento/blank/web/css/print.less
@@ -21,10 +21,10 @@
 @media print {
     * {
         background: transparent !important;
-        color: black !important;
-        text-shadow: none !important;
+        color: @color-black !important;
         -webkit-filter: none !important; // Use in 41 Chrome
         filter: none !important;
+        text-shadow: none !important;
     }
 
     // Black prints faster:h5bp.com/s
@@ -112,16 +112,16 @@
         .order-items {
             .order-gift-message {
                 &:not(.expanded-content) {
-                    visibility: visible;
                     height: auto;
+                    visibility: visible;
                 }
             }
         }
     }
 
     .column.main {
-        width: 100% !important;
         float: none !important;
+        width: 100% !important;
     }
 
     .breadcrumbs {
diff --git a/app/design/frontend/Magento/blank/web/css/source/_actions-toolbar.less b/app/design/frontend/Magento/blank/web/css/source/_actions-toolbar.less
index 71ec096953932fd3aaf6f579bea13efa6d750b51..0d0a318c350d1c095f6c60dabb6a0e0f6a7467ab 100644
--- a/app/design/frontend/Magento/blank/web/css/source/_actions-toolbar.less
+++ b/app/design/frontend/Magento/blank/web/css/source/_actions-toolbar.less
@@ -4,37 +4,36 @@
 //  */
 
 //
-//    Common
-//--------------------------------------
+//  Common
+//  _____________________________________________
 
 & when (@media-common = true) {
+    .actions-toolbar {
+        > .primary,
+        > .secondary {
+            text-align: center;
+
+            .action {
+                &:extend(.abs-button-responsive all);
+                margin-bottom: @indent__s;
 
-.actions-toolbar {
-    > .primary,
-    > .secondary {
-        text-align: center;
+                &:last-child {
+                    margin-bottom: 0;
+                }
+            }
 
-        .action {
-            &:extend(.abs-button-responsive all);
             margin-bottom: @indent__s;
-
             &:last-child {
                 margin-bottom: 0;
             }
         }
-
-        margin-bottom: @indent__s;
-        &:last-child {
-            margin-bottom: 0;
-        }
     }
 }
 
-}
-
 //
-//    Desktop
-//--------------------------------------
+//  Desktop
+//  _____________________________________________
+
 .media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__m) {
     .actions-toolbar {
         .lib-actions-toolbar();
@@ -43,8 +42,8 @@
             margin-bottom: 0;
 
             .action {
-                width: auto;
                 margin-bottom: 0;
+                width: auto;
             }
         }
     }
diff --git a/app/design/frontend/Magento/blank/web/css/source/_buttons.less b/app/design/frontend/Magento/blank/web/css/source/_buttons.less
index 63a1a0b71604dc38e10510635562c59babb46c43..c6506c93c2a6118f7c9d8b08a945cb2b3eb15908 100644
--- a/app/design/frontend/Magento/blank/web/css/source/_buttons.less
+++ b/app/design/frontend/Magento/blank/web/css/source/_buttons.less
@@ -4,31 +4,28 @@
 //  */
 
 //
-//    Common
-//--------------------------------------
+//  Common
+//  _____________________________________________
 
 & when (@media-common = true) {
 
-//
-//    Using buttons mixins
-//--------------------------------------
-button,
-a.action.primary {
-    .lib-css(border-radius, @button__border-radius);
-}
-
-button {
-    &:active {
-        .lib-css(box-shadow, @button__shadow);
+    //  Using buttons mixins
+    button,
+    a.action.primary {
+        .lib-css(border-radius, @button__border-radius);
     }
-}
 
-a.action.primary {
-    .lib-link-as-button();
-}
+    button {
+        &:active {
+            .lib-css(box-shadow, @button__shadow);
+        }
+    }
 
-.action.primary {
-    .lib-button-primary();
-}
+    a.action.primary {
+        .lib-link-as-button();
+    }
 
+    .action.primary {
+        .lib-button-primary();
+    }
 }
diff --git a/app/design/frontend/Magento/blank/web/css/source/_components.less b/app/design/frontend/Magento/blank/web/css/source/_components.less
index 9f6db89c38d126d254ae3e4423ed7fccf8d3e1ed..1143001fec091e0ad497365742176a531836b7d4 100644
--- a/app/design/frontend/Magento/blank/web/css/source/_components.less
+++ b/app/design/frontend/Magento/blank/web/css/source/_components.less
@@ -7,5 +7,5 @@
 //  Components
 //  _____________________________________________
 
-@import 'components/_modals.less'; // from lib
-@import 'components/_modals_extend.less'; // local
+@import 'components/_modals.less'; // From lib
+@import 'components/_modals_extend.less'; // Local
diff --git a/app/design/frontend/Magento/blank/web/css/source/_email-base.less b/app/design/frontend/Magento/blank/web/css/source/_email-base.less
index 173695c9d037d0d44fda050a61e091093c6295a7..c204620916cee7bb4763c2b7233715dadd86f7f2 100644
--- a/app/design/frontend/Magento/blank/web/css/source/_email-base.less
+++ b/app/design/frontend/Magento/blank/web/css/source/_email-base.less
@@ -176,7 +176,7 @@ body {
 .media-width(@extremum, @break) when (@extremum = 'max') and (@break = @screen__s) {
     html,
     body {
-        // Change background/foreground to same color
+        //  Change background/foreground to same color
         background-color: @email-content__background-color;
         width: 100% !important;
     }
@@ -203,13 +203,13 @@ body {
             background-color: @button-primary__background;
 
             a {
-                font-size: @button__font-size;
-                color: @button-primary__color;
                 .lib-css(border-radius, @button__border-radius, 1);
                 border: 1px solid @button-primary__background;
-                text-decoration: none;
-                padding: @button__padding;
+                color: @button-primary__color;
                 display: inline-block;
+                font-size: @button__font-size;
+                padding: @button__padding;
+                text-decoration: none;
             }
         }
     }
@@ -231,10 +231,10 @@ body {
         a:active,
         a:hover,
         a:visited {
-            // Undo general link hover state
+            //  Undo general link hover state
+            border: 1px solid @button-primary__hover__background;
             color: @button-primary__color !important;
             text-decoration: none !important;
-            border: 1px solid @button-primary__hover__background;
         }
     }
 
diff --git a/app/design/frontend/Magento/blank/web/css/source/_email-extend.less b/app/design/frontend/Magento/blank/web/css/source/_email-extend.less
index 2fb086128d1ea517b91e8b8618a801df5a541657..122e421bcff7f91ef72d52ed030be1e38f9e8183 100644
--- a/app/design/frontend/Magento/blank/web/css/source/_email-extend.less
+++ b/app/design/frontend/Magento/blank/web/css/source/_email-extend.less
@@ -15,4 +15,5 @@
 
 //  Importing fonts from an external CSS file, rather than embedding @font-face declarations inside the <style> tag,
 //  as the latter will cause font rendering issues if the web fonts are inaccessible.
+
 @import url("@{baseUrl}css/email-fonts.css");
diff --git a/app/design/frontend/Magento/blank/web/css/source/_extends.less b/app/design/frontend/Magento/blank/web/css/source/_extends.less
index 3c6ebff3b47dce60e02f3b5ae2ef7679ed8af114..0de11876781a0b1f706fedec5cc949aa0f73098d 100644
--- a/app/design/frontend/Magento/blank/web/css/source/_extends.less
+++ b/app/design/frontend/Magento/blank/web/css/source/_extends.less
@@ -34,8 +34,8 @@
 
 @abs-product-options-list: {
     dt {
-        float: left;
         clear: left;
+        float: left;
         margin: 0 @indent__s @indent__xs 0;
 
         &:after {
@@ -119,7 +119,7 @@
 
 .abs-reset-image-wrapper {
     height: auto;
-    padding: 0!important;
+    padding: 0 !important;
     .product-image-photo {
         position: static;
     }
@@ -138,8 +138,8 @@
 .abs-adaptive-images-centered {
     display: block;
     height: auto;
-    max-width: 100%;
     margin: 0 auto;
+    max-width: 100%;
 }
 
 //
@@ -151,10 +151,10 @@
         font-weight: 500;
     }
 
-    padding-bottom: 12px;
-    margin-bottom: 15px;
-    border-bottom: 1px solid @secondary__color;
     .lib-font-size(18);
+    border-bottom: 1px solid @secondary__color;
+    margin-bottom: 15px;
+    padding-bottom: 12px;
 }
 
 //
@@ -303,11 +303,11 @@
 
 .abs-action-remove {
     &:extend(.abs-action-button-as-link all);
-    width: auto;
-    position: absolute;
-    top: 31px;
     left: @indent__s;
     margin-left: 70%;
+    position: absolute;
+    top: 31px;
+    width: auto;
 }
 
 //
@@ -316,8 +316,8 @@
 
 .media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__m) {
     .abs-action-remove-desktop when not (@form-field-type-label-inline__width = false) and not (@form-field-type-label-inline__width = '') {
-        top: 6px;
         margin-left: @form-field-type-label-inline__width + 50%;
+        top: 6px;
     }
 }
 
@@ -328,6 +328,7 @@
 .abs-add-fields {
     .fieldset {
         margin-bottom: 50px;
+
         .field {
             &:not(.choice) {
                 .control {
@@ -339,6 +340,7 @@
         .actions-toolbar {
             &:not(:first-child) {
                 &:extend(.abs-add-clearfix all);
+
                 > .secondary {
                     .action {
                         &.add {
@@ -550,6 +552,7 @@
             > .field,
             .fields > .field {
                 .lib-form-field-type-revert(@_type: block);
+
                 &:not(:first-child):last-of-type {
                     margin-bottom: 0;
                 }
@@ -584,7 +587,7 @@
 
 .abs-split-button {
     .lib-dropdown-split(
-        @_options-selector : ~".items",
+        @_options-selector : ~'.items',
         @_dropdown-split-button-border-radius-fix: true
     );
     vertical-align: middle;
@@ -669,8 +672,8 @@
     .price-including-tax,
     .price-excluding-tax,
     .weee {
-        display: inline-block;
         .lib-font-size(14);
+        display: inline-block;
         white-space: nowrap;
     }
 
@@ -679,11 +682,11 @@
         .lib-font-size(11);
 
         &:before {
-            content: "("attr(data-label)": ";
+            content: '('attr(data-label)': ';
         }
 
         &:after {
-            content:")";
+            content:')';
         }
     }
 }
@@ -731,8 +734,8 @@
 
 .abs-methods-shipping-title {
     .lib-font-size(14);
-    margin: 0 0 15px;
     font-weight: @font-weight__bold;
+    margin: 0 0 15px;
 }
 
 //
@@ -779,7 +782,7 @@
                     width: 33%;
 
                     &:before {
-                        content: attr(data-th) ":";
+                        content: attr(data-th) ':';
                         display: block;
                         font-weight: @font-weight__bold;
                         padding-bottom: @indent__s;
@@ -820,12 +823,12 @@
 .media-width(@extremum, @break) when (@extremum = 'max') and (@break = @screen__m) {
     .abs-icon-add-mobile {
         .lib-icon-font(
-            @_icon-font-content: @icon-expand,
-            @_icon-font-size: 10px,
-            @_icon-font-line-height: 10px,
-            @_icon-font-vertical-align: middle,
-            @_icon-font-margin: 0 5px 0 0,
-            @_icon-font-display: block
+        @_icon-font-content: @icon-expand,
+        @_icon-font-size: 10px,
+        @_icon-font-line-height: 10px,
+        @_icon-font-vertical-align: middle,
+        @_icon-font-margin: 0 5px 0 0,
+        @_icon-font-display: block
         );
     }
 }
@@ -856,18 +859,19 @@
 
 .media-width(@extremum, @break) when (@extremum = 'max') and (@break = @screen__m) {
     .abs-toggling-title-mobile {
-        border-top: @border-width__base solid @border-color__base;
         border-bottom: @border-width__base solid @border-color__base;
+        border-top: @border-width__base solid @border-color__base;
         cursor: pointer;
         margin-bottom: 0;
         padding: @indent__s @indent__xl @indent__s @layout__width-xs-indent;
         position: relative;
+
         .lib-icon-font(
-            @_icon-font-content: @icon-down,
-            @_icon-font-size: 28px,
-            @_icon-font-text-hide: false,
-            @_icon-font-position: after,
-            @_icon-font-display: block
+        @_icon-font-content: @icon-down,
+        @_icon-font-size: 28px,
+        @_icon-font-text-hide: false,
+        @_icon-font-position: after,
+        @_icon-font-display: block
         );
 
         &:after {
@@ -927,8 +931,8 @@
         .toolbar-amount,
         .limiter,
         .pages {
-            margin-bottom: @indent__m;
             float: none;
+            margin-bottom: @indent__m;
         }
     }
 }
@@ -973,8 +977,8 @@
 
         .pages {
             position: absolute;
-            z-index: 0;
             width: 100%;
+            z-index: 0;
         }
     }
 }
@@ -998,12 +1002,12 @@
         &.continue {
             .lib-link-as-button();
             .lib-button(
-                @_button-padding: 7px 15px 7px 0,
-                @_button-icon-use: true,
-                @_button-font-content: @icon-prev,
-                @_button-icon-font-size: 32px,
-                @_button-icon-font-line-height: 16px,
-                @_button-icon-font-position: before
+            @_button-padding: 7px 15px 7px 0,
+            @_button-icon-use: true,
+            @_button-font-content: @icon-prev,
+            @_button-icon-font-size: 32px,
+            @_button-icon-font-line-height: 16px,
+            @_button-icon-font-position: before
             );
             border-radius: 3px;
             font-weight: bold;
@@ -1046,8 +1050,8 @@
 .media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__m) {
     .abs-shopping-cart-items-desktop {
         float: left;
-        width: 73%;
         position: relative;
+        width: 73%;
 
         .actions {
             text-align: right;
diff --git a/app/design/frontend/Magento/blank/web/css/source/_forms.less b/app/design/frontend/Magento/blank/web/css/source/_forms.less
index 0b354c80739db4d6eb0a323041dc22d7e573c6b0..17bca6e241a3ec418e2a27bf0bc437b9f4a9975a 100644
--- a/app/design/frontend/Magento/blank/web/css/source/_forms.less
+++ b/app/design/frontend/Magento/blank/web/css/source/_forms.less
@@ -7,158 +7,159 @@
 @form-calendar-icon__color: @primary__color;
 
 //
-//    Common
-//--------------------------------------
+//  Common
+//  _____________________________________________
 
 & when (@media-common = true) {
 
-.fieldset {
-    .lib-form-fieldset();
-    &:last-child {
-        margin-bottom: 0;
-    }
+    .fieldset {
+        .lib-form-fieldset();
+        &:last-child {
+            margin-bottom: 0;
+        }
 
-    > .field,
-    > .fields > .field {
-        .lib-form-field();
+        > .field,
+        > .fields > .field {
+            .lib-form-field();
 
-        &.no-label {
-            > .label {
-                &:extend(.abs-visually-hidden all);
+            &.no-label {
+                > .label {
+                    &:extend(.abs-visually-hidden all);
+                }
             }
-        }
 
-        &.choice {
-            .label {
-                display: inline;
-                font-weight: normal;
+            &.choice {
+                .label {
+                    display: inline;
+                    font-weight: normal;
+                }
             }
-        }
 
-        .label {
-            .column:not(.main) & {
-                font-weight: normal;
+            .label {
+                .column:not(.main) & {
+                    font-weight: normal;
+                }
             }
-        }
 
-        .field.choice {
-            margin-bottom: @indent__s;
+            .field.choice {
+                margin-bottom: @indent__s;
 
-            &:last-child {
-                margin-bottom: 0;
+                &:last-child {
+                    margin-bottom: 0;
+                }
             }
-        }
 
-        input[type=file] {
-            margin: @indent__xs 0;
+            input[type=file] {
+                margin: @indent__xs 0;
+            }
         }
     }
-}
 
-.legend + .fieldset,
-.legend + div {
-    clear: both;
-}
-
-.legend {
-    strong {
-        margin-left: @indent__xs;
+    .legend + .fieldset,
+    .legend + div {
+        clear: both;
     }
-}
 
-fieldset.field {
-    border: 0;
-    padding: 0;
-}
+    .legend {
+        strong {
+            margin-left: @indent__xs;
+        }
+    }
 
+    fieldset.field {
+        border: 0;
+        padding: 0;
+    }
 
-.field {
-    &.date {
-        &:extend(.abs-field-date all);
+    .field {
+        &.date {
+            &:extend(.abs-field-date all);
 
-        .time-picker {
-            display: inline-block;
-            margin-top: @indent__s;
-            white-space: nowrap;
+            .time-picker {
+                display: inline-block;
+                margin-top: @indent__s;
+                white-space: nowrap;
+            }
         }
-    }
 
-    .message {
-        &.warning {
-            margin-top: @indent__s;
+        .message {
+            &.warning {
+                margin-top: @indent__s;
+            }
         }
     }
-}
 
-div.mage-error[generated] {
-    margin-top: 7px;
-}
-
-.field .tooltip {
-    .lib-tooltip(right);
-    .tooltip-content {
-        min-width: 200px;
-        white-space: normal;
+    div.mage-error[generated] {
+        margin-top: 7px;
     }
-}
 
-input:focus ~ .tooltip .tooltip-content,
-select:focus ~ .tooltip .tooltip-content {
-    display: block;
-}
-
-.hasDatepicker {
-    + .ui-datepicker-trigger {
-        .lib-button-reset();
-        .lib-icon-font(
-        @_icon-font-content: @icon-calendar,
-        @_icon-font-color: @primary__color__lighter,
-        @_icon-font-size: @icon-calendar__font-size,
-        @_icon-font-line-height: @icon-calendar__font-size,
-        @_icon-font-display: block,
-        @_icon-font-text-hide: true
-        );
-        display: inline-block;
-        vertical-align: middle;
-
-        &:focus {
-            box-shadow: none;
-            outline: 0;
+    .field .tooltip {
+        .lib-tooltip(right);
+        .tooltip-content {
+            min-width: 200px;
+            white-space: normal;
         }
     }
-}
 
-//
-//    Sidebar forms
-//--------------------------------------
-.sidebar {
-    .fieldset {
-        margin: 0;
-        > .field:not(.choice) >,
-        .fields > .field {
-            &:not(:last-child) {
-                margin: 0 0 @form-field__vertical-indent;
-            }
+    input:focus ~ .tooltip .tooltip-content,
+    select:focus ~ .tooltip .tooltip-content {
+        display: block;
+    }
 
-            .label {
-                margin: 0 0 4px;
-                padding: 0 0 @indent__xs;
-                text-align: left;
-                width: 100%;
-            }
+    .hasDatepicker {
+        + .ui-datepicker-trigger {
+            .lib-button-reset();
+            .lib-icon-font(
+            @_icon-font-content: @icon-calendar,
+            @_icon-font-color: @primary__color__lighter,
+            @_icon-font-size: @icon-calendar__font-size,
+            @_icon-font-line-height: @icon-calendar__font-size,
+            @_icon-font-display: block,
+            @_icon-font-text-hide: true
+            );
+            display: inline-block;
+            vertical-align: middle;
 
-            .control {
-                width: 100%;
+            &:focus {
+                box-shadow: none;
+                outline: 0;
             }
         }
     }
-}
 
+    //
+    //  Sidebar forms
+    //  -----------------------------------------
+
+    .sidebar {
+        .fieldset {
+            margin: 0;
+
+            > .field:not(.choice) >,
+            .fields > .field {
+                &:not(:last-child) {
+                    margin: 0 0 @form-field__vertical-indent;
+                }
+
+                .label {
+                    margin: 0 0 4px;
+                    padding: 0 0 @indent__xs;
+                    text-align: left;
+                    width: 100%;
+                }
+
+                .control {
+                    width: 100%;
+                }
+            }
+        }
+    }
 }
 
 //
-//    Desktop
-//--------------------------------------
+//  Desktop
+//  _____________________________________________
+
 .media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__m) {
     .fieldset {
         .legend {
diff --git a/app/design/frontend/Magento/blank/web/css/source/_layout.less b/app/design/frontend/Magento/blank/web/css/source/_layout.less
index 5d35440171a3981f98b6591491057b0bbfd8a288..cf4e94a277f7cdb1650329c537b19695753fd1bd 100644
--- a/app/design/frontend/Magento/blank/web/css/source/_layout.less
+++ b/app/design/frontend/Magento/blank/web/css/source/_layout.less
@@ -7,42 +7,42 @@
 @layout-column__additional-sidebar-offset: @layout-column-main__sidebar-offset;
 
 //
-//    Common
-//--------------------------------------
+//  Common
+//  _____________________________________________
 
 & when (@media-common = true) {
 
-.columns {
-    #lib-layout-columns();
-
-    .column.main {
-        &:extend(.abs-add-box-sizing all);
-        .lib-vendor-prefix-flex-grow(1);
-        .lib-vendor-prefix-flex-basis(100%);
-        .lib-css(padding-bottom, @indent__xl);
-        .lib-vendor-prefix-order(1);
-    }
+    .columns {
+        #lib-layout-columns();
+
+        .column.main {
+            &:extend(.abs-add-box-sizing all);
+            .lib-css(padding-bottom, @indent__xl);
+            .lib-vendor-prefix-flex-basis(100%);
+            .lib-vendor-prefix-flex-grow(1);
+            .lib-vendor-prefix-order(1);
+        }
 
-    .sidebar-main {
-        &:extend(.abs-add-box-sizing all);
-        .lib-vendor-prefix-flex-grow(1);
-        .lib-vendor-prefix-flex-basis(100%);
-        .lib-vendor-prefix-order(1);
-    }
+        .sidebar-main {
+            &:extend(.abs-add-box-sizing all);
+            .lib-vendor-prefix-flex-grow(1);
+            .lib-vendor-prefix-flex-basis(100%);
+            .lib-vendor-prefix-order(1);
+        }
 
-    .sidebar-additional {
-        &:extend(.abs-add-box-sizing all);
-        .lib-vendor-prefix-flex-grow(1);
-        .lib-vendor-prefix-flex-basis(100%);
-        .lib-vendor-prefix-order(2);
+        .sidebar-additional {
+            &:extend(.abs-add-box-sizing all);
+            .lib-vendor-prefix-flex-grow(1);
+            .lib-vendor-prefix-flex-basis(100%);
+            .lib-vendor-prefix-order(2);
+        }
     }
 }
 
-}
-
 //
-//    Mobile
-//--------------------------------------
+//  Mobile
+//  _____________________________________________
+
 .media-width(@extremum, @break) when (@extremum = 'max') and (@break = @screen__m) {
     .navigation,
     .breadcrumbs,
@@ -61,15 +61,16 @@
     .page-main {
         .account &,
         .cms-privacy-policy & {
-            position: relative;
             padding-top: 41px;
+            position: relative;
         }
     }
 }
 
 //
-//    Desktop
-//--------------------------------------
+//  Desktop
+//  _____________________________________________
+
 .media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__m) {
     .navigation,
     .breadcrumbs,
@@ -81,13 +82,13 @@
     .block.category.event,
     .top-container,
     .page-main {
-        padding-left: @layout-indent__width;
-        padding-right: @layout-indent__width;
+        box-sizing: border-box;
         margin-left: auto;
         margin-right: auto;
-        width: auto;
         max-width: @layout__max-width;
-        box-sizing: border-box;
+        padding-left: @layout-indent__width;
+        padding-right: @layout-indent__width;
+        width: auto;
     }
 
     .page-main {
@@ -96,6 +97,7 @@
         .lib-vendor-prefix-flex-grow(1);
         .lib-vendor-prefix-flex-shrink(0);
         .lib-vendor-prefix-flex-basis(auto);
+
         .ie9 & {
             width: auto;
         }
@@ -118,23 +120,23 @@
     }
 
     .page-layout-2columns-right .sidebar-main {
-        padding-right: 0;
         padding-left: @layout-column-main__sidebar-offset;
+        padding-right: 0;
     }
 
     .sidebar-additional {
         #lib-layout-columns > .right();
-        padding-left: @layout-column__additional-sidebar-offset;
         clear: right;
+        padding-left: @layout-column__additional-sidebar-offset;
         &:extend(.abs-add-box-sizing-desktop all);
     }
 
     .page-layout-2columns-left {
         .sidebar-additional {
-            padding-right: @layout-column__additional-sidebar-offset;
-            padding-left: 0;
             clear: left;
             float: left;
+            padding-left: 0;
+            padding-right: @layout-column__additional-sidebar-offset;
         }
     }
 
diff --git a/app/design/frontend/Magento/blank/web/css/source/_loaders.less b/app/design/frontend/Magento/blank/web/css/source/_loaders.less
index d60dfbb627601946bcdff0410be7b830b789b083..edcddbe9d08ab13fb64ab93718647e61992e7dea 100644
--- a/app/design/frontend/Magento/blank/web/css/source/_loaders.less
+++ b/app/design/frontend/Magento/blank/web/css/source/_loaders.less
@@ -4,8 +4,8 @@
 //  */
 
 //
-//    Common
-//--------------------------------------
+//  Common
+//  _____________________________________________
 
 & when (@media-common = true) {
 
diff --git a/app/design/frontend/Magento/blank/web/css/source/_navigation.less b/app/design/frontend/Magento/blank/web/css/source/_navigation.less
index 915a181f0a5da79970e4fb2f7321ff66a0aaf93b..0213d4f24a60886d8ddf16ecd6598bb3e6475c2f 100644
--- a/app/design/frontend/Magento/blank/web/css/source/_navigation.less
+++ b/app/design/frontend/Magento/blank/web/css/source/_navigation.less
@@ -43,6 +43,7 @@
 //  _____________________________________________
 
 @active-nav-indent: 54px;
+
 .media-width(@extremum, @break) when (@extremum = 'max') and (@break = @screen__m) {
     .navigation {
         padding: 0;
@@ -83,6 +84,7 @@
         top: 0;
         width: 80%;
         width: calc(~"100% - @{active-nav-indent}");
+        -webkit-overflow-scrolling: touch;
 
         .switcher {
             border-top: 1px solid @color-gray82;
diff --git a/app/design/frontend/Magento/blank/web/css/source/_popups.less b/app/design/frontend/Magento/blank/web/css/source/_popups.less
index eaaf7eeb6541c893f2325eab0faa555839fbc856..0df91afee0680777936af6f2d2fca8d827ef384a 100644
--- a/app/design/frontend/Magento/blank/web/css/source/_popups.less
+++ b/app/design/frontend/Magento/blank/web/css/source/_popups.less
@@ -15,7 +15,7 @@
 
 & when (@media-common = true) {
 
-//  Popup working with dropdown dialog
+    //  Popup working with dropdown dialog
     .ui-dialog {
         &.popup {
             .action {
diff --git a/app/design/frontend/Magento/blank/web/css/source/_price.less b/app/design/frontend/Magento/blank/web/css/source/_price.less
index 18747ac7213360841924529a5f032dde441317ba..4d541746624cfdcce98ba934272e3f36583ab2bd 100644
--- a/app/design/frontend/Magento/blank/web/css/source/_price.less
+++ b/app/design/frontend/Magento/blank/web/css/source/_price.less
@@ -4,74 +4,73 @@
 //  */
 
 //
-//    Common
-//--------------------------------------
+//  Common
+//  _____________________________________________
 
 & when (@media-common = true) {
 
-// Prices
-.price-style-1() {
-    .price {
-        &-tier_price .price-excluding-tax,
-        &-tier_price .price-including-tax {
-            display: inline;
+    //  Prices
+    .price-style-1() {
+        .price {
+            &-tier_price .price-excluding-tax,
+            &-tier_price .price-including-tax {
+                display: inline;
+            }
         }
     }
-}
 
-.price-style-2() {
-    .price {
-        &-including-tax,
-        &-excluding-tax {
-            display: inline !important;
-        }
+    .price-style-2() {
+        .price {
+            &-including-tax,
+            &-excluding-tax {
+                display: inline !important;
+            }
 
-        &-including-tax:before {
-            content:" / "
-        }
+            &-including-tax:before {
+                content:' / ';
+            }
 
-        &-including-tax:after {
-            content: "("attr(data-label)")";
+            &-including-tax:after {
+                content: '('attr(data-label)')';
+            }
         }
     }
-}
 
-.price-style-3() {
-    .price-including-tax,
-    .price-excluding-tax {
-        display: block;
-        .lib-font-size(18);
-        line-height: 1;
+    .price-style-3() {
+        .price-including-tax,
+        .price-excluding-tax {
+            display: block;
+            .lib-font-size(18);
+            line-height: 1;
 
-        .price {
-            font-weight: @font-weight__bold;
-        }
+            .price {
+                font-weight: @font-weight__bold;
+            }
 
-        .cart-tax-total {
-            &:extend(.abs-tax-total all);
-            &-expanded {
-                &:extend(.abs-tax-total-expanded all);
+            .cart-tax-total {
+                &:extend(.abs-tax-total all);
+                &-expanded {
+                    &:extend(.abs-tax-total-expanded all);
+                }
             }
         }
-    }
 
-    .price-including-tax + .price-excluding-tax,
-    .weee[data-label] {
-        display: block;
-        .lib-font-size(18);
+        .price-including-tax + .price-excluding-tax,
+        .weee[data-label] {
+            display: block;
+            .lib-font-size(18);
 
-        &:before {
-            content: attr(data-label) ": ";
-            .lib-font-size(11);
-        }
+            &:before {
+                content: attr(data-label) ': ';
+                .lib-font-size(11);
+            }
 
-        .price {
-            .lib-font-size(11);
+            .price {
+                .lib-font-size(11);
+            }
         }
     }
-}
-
-.price-style-1();
-.price-style-3();
 
+    .price-style-1();
+    .price-style-3();
 }
diff --git a/app/design/frontend/Magento/blank/web/css/source/_tables.less b/app/design/frontend/Magento/blank/web/css/source/_tables.less
index 4291ba5a71987a9e7829fc9dc549111f50697f4e..8f8095b8e4137e08bd571a369c42c836670add40 100644
--- a/app/design/frontend/Magento/blank/web/css/source/_tables.less
+++ b/app/design/frontend/Magento/blank/web/css/source/_tables.less
@@ -52,7 +52,7 @@
 .media-width(@extremum, @break) when (@extremum = 'max') and (@break = @screen__s) {
     .table-wrapper {
         .lib-table-overflow();
-        position: relative; // to hide unnecessary horizontal scrollbar in Safari
+        position: relative; // To hide unnecessary horizontal scrollbar in Safari
 
         .table {
             &:not(.cart) {
diff --git a/app/design/frontend/Magento/blank/web/css/source/_tooltips.less b/app/design/frontend/Magento/blank/web/css/source/_tooltips.less
index e6626b6b0957a3182f896c5ab51a4815b372cb44..d04c8b9277e56b3360d8c56f5cf5861e08cc76ea 100644
--- a/app/design/frontend/Magento/blank/web/css/source/_tooltips.less
+++ b/app/design/frontend/Magento/blank/web/css/source/_tooltips.less
@@ -4,52 +4,52 @@
 //  */
 
 //
-//    Common
-//--------------------------------------
+//  Common
+//  _____________________________________________
 
 & when (@media-common = true) {
 
-.tooltip.wrapper {
-    .lib-tooltip(
+    .tooltip.wrapper {
+        .lib-tooltip(
         @_tooltip-position: bottom,
-        @_tooltip-selector-content: ~".tooltip.content",
-        @_tooltip-selector-toggle: ~".tooltip.toggle"
-    );
+        @_tooltip-selector-content: ~'.tooltip.content',
+        @_tooltip-selector-toggle: ~'tooltip.toggle'
+        );
 
-    .tooltip.content {
-        dl {
-            margin-bottom: 0;
-        }
+        .tooltip.content {
+            dl {
+                margin-bottom: 0;
+            }
 
-        dd {
-            white-space: normal;
-        }
+            dd {
+                white-space: normal;
+            }
 
-        .subtitle {
-            display: inline-block;
-            margin-bottom: 15px;
-            font-size: 16px;
-            font-weight: 500;
-        }
+            .subtitle {
+                display: inline-block;
+                font-size: 16px;
+                font-weight: 500;
+                margin-bottom: 15px;
+            }
+
+            .label {
+                margin-top: @indent__s;
 
-        .label {
-            margin-top: @indent__s;
-            &:first-child {
-                margin-top: 0;
+                &:first-child {
+                    margin-top: 0;
+                }
             }
-        }
 
-        .values {
-            margin: 0;
+            .values {
+                margin: 0;
+            }
         }
     }
-}
-
-.ui-tooltip {
-  position: absolute;
-  z-index: 9999;
-}
 
+    .ui-tooltip {
+      position: absolute;
+      z-index: 9999;
+    }
 }
 
 //
diff --git a/app/design/frontend/Magento/blank/web/css/source/_typography.less b/app/design/frontend/Magento/blank/web/css/source/_typography.less
index e4f15c2bc34b8e3cfe6ac618a4da2e1290eb8a02..325c73a46aa3cf99f6bcc603ba7a28c196640259 100644
--- a/app/design/frontend/Magento/blank/web/css/source/_typography.less
+++ b/app/design/frontend/Magento/blank/web/css/source/_typography.less
@@ -32,8 +32,9 @@
 );
 
 //
-//    Desktop
-//--------------------------------------
+//  Desktop
+//  _____________________________________________
+
 .media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__m) {
     h1 {
         .lib-css(font-size, @h1__font-size-desktop);
@@ -41,15 +42,12 @@
     }
 }
 
-
 //
 //    Common
-//--------------------------------------
+//  _____________________________________________
 
 & when (@media-common = true) {
-
-.items {
-    .lib-list-reset-styles();
-}
-
+    .items {
+        .lib-list-reset-styles();
+    }
 }
diff --git a/app/design/frontend/Magento/blank/web/css/source/components/_modals_extend.less b/app/design/frontend/Magento/blank/web/css/source/components/_modals_extend.less
index bf2785cbeff0c793999394d052477e1404d709a0..a4552f51a15ad2f10e460f509338575731d28bd4 100644
--- a/app/design/frontend/Magento/blank/web/css/source/components/_modals_extend.less
+++ b/app/design/frontend/Magento/blank/web/css/source/components/_modals_extend.less
@@ -85,8 +85,8 @@
         }
 
         .page-main-actions {
-            margin-top: @modal-slide-header__padding-vertical;
             margin-bottom: @modal-slide-header__padding-vertical - (@indent__l/2);
+            margin-top: @modal-slide-header__padding-vertical;
         }
     }
 
@@ -124,8 +124,8 @@
 
         &._show {
             -webkit-overflow-scrolling: touch;
-            overflow-y: auto;
             overflow-x: hidden;
+            overflow-y: auto;
         }
 
         .modal-inner-wrap {
diff --git a/app/design/frontend/Magento/luma/Magento_LayeredNavigation/web/css/source/_module.less b/app/design/frontend/Magento/luma/Magento_LayeredNavigation/web/css/source/_module.less
index c3bfb808d27f6517e48966942375012b92d15e3d..2484576bd1af4f6b455df488bed8f83aed6fd1e5 100644
--- a/app/design/frontend/Magento/luma/Magento_LayeredNavigation/web/css/source/_module.less
+++ b/app/design/frontend/Magento/luma/Magento_LayeredNavigation/web/css/source/_module.less
@@ -32,7 +32,7 @@
 
                 &[data-count]:after {
                     .lib-css(color, @color-white);
-                    background: @color-orange-red4;
+                    background: @color-orange-red1;
                     border-radius: 2px;
                     content: attr(data-count);
                     display: inline-block;
@@ -204,6 +204,10 @@
 .media-width(@extremum, @break) when (@extremum = 'max') and (@break = @screen__m) {
     body {
         &.filter-active {
+            .page-header {
+                display: none;
+            }
+
             .page-wrapper {
                 height: 0;
                 margin-top: -999999em;
diff --git a/app/design/frontend/Magento/luma/Magento_Sales/email/order_new.html b/app/design/frontend/Magento/luma/Magento_Sales/email/order_new.html
index 66cf888a6112d27fad29a9e2bb6d653a807e84ce..97c09dd74c91fa6839a78eeb4d0e524a08afdfa2 100644
--- a/app/design/frontend/Magento/luma/Magento_Sales/email/order_new.html
+++ b/app/design/frontend/Magento/luma/Magento_Sales/email/order_new.html
@@ -13,6 +13,7 @@
 "var payment_html|raw":"Payment Details",
 "var formattedShippingAddress|raw":"Shipping Address",
 "var order.getShippingDescription()":"Shipping Description"
+"var shipping_msg":"Shipping message"
 } @-->
 
 {{template config_path="design/email/header_template"}}
@@ -70,6 +71,9 @@
                     <td class="method-info">
                         <h3>{{trans "Shipping Method"}}</h3>
                         <p>{{var order.getShippingDescription()}}</p>
+                        {{if shipping_msg}}
+                        <p>{{var shipping_msg}}</p>
+                        {{/if}}
                     </td>
                     {{/depend}}
                 </tr>
diff --git a/app/design/frontend/Magento/luma/Magento_Sales/email/order_new_guest.html b/app/design/frontend/Magento/luma/Magento_Sales/email/order_new_guest.html
index d2e42978760d04aac34abf1ce0657ca043d41be6..28c89ba3e264572a156535dd631cb68b677ccbbe 100644
--- a/app/design/frontend/Magento/luma/Magento_Sales/email/order_new_guest.html
+++ b/app/design/frontend/Magento/luma/Magento_Sales/email/order_new_guest.html
@@ -15,6 +15,7 @@
 "var payment_html|raw":"Payment Details",
 "var formattedShippingAddress|raw":"Shipping Address",
 "var order.getShippingDescription()":"Shipping Description"
+"var shipping_msg":"Shipping message"
 } @-->
 {{template config_path="design/email/header_template"}}
 
@@ -70,6 +71,9 @@
                     <td class="method-info">
                         <h3>{{trans "Shipping Method"}}</h3>
                         <p>{{var order.getShippingDescription()}}</p>
+                        {{if shipping_msg}}
+                        <p>{{var shipping_msg}}</p>
+                        {{/if}}
                     </td>
                     {{/depend}}
                 </tr>
diff --git a/app/design/frontend/Magento/luma/Magento_Sales/web/css/source/_module.less b/app/design/frontend/Magento/luma/Magento_Sales/web/css/source/_module.less
index ac52733372746d827e0c27023c78c0cba2886517..e29df378ef11df9b45a78efc2b2bb34c740a134c 100644
--- a/app/design/frontend/Magento/luma/Magento_Sales/web/css/source/_module.less
+++ b/app/design/frontend/Magento/luma/Magento_Sales/web/css/source/_module.less
@@ -317,11 +317,9 @@
 }
 
 .form-orders-search {
-    &:extend(.abs-forms-general-desktop all);
     .field {
-        &.email,
-        &.zip {
-            margin-bottom: 0;
+        &:last-child {
+            margin-bottom: @indent__base;
         }
     }
 }
diff --git a/app/design/frontend/Magento/luma/web/css/source/_actions-toolbar.less b/app/design/frontend/Magento/luma/web/css/source/_actions-toolbar.less
index 5ca1c505661824b148ea845a8d689c0c62a59592..28412080438b51a7957f15ad0077503fcfe74601 100644
--- a/app/design/frontend/Magento/luma/web/css/source/_actions-toolbar.less
+++ b/app/design/frontend/Magento/luma/web/css/source/_actions-toolbar.less
@@ -4,57 +4,58 @@
 //  */
 
 //
-//    Common
-//--------------------------------------
+//  Common
+//  _____________________________________________
 
 & when (@media-common = true) {
 
-.actions-toolbar {
-    > .primary,
-    > .secondary {
-        text-align: center;
-        .action {
-            &:extend(.abs-button-responsive all);
+    .actions-toolbar {
+        > .primary,
+        > .secondary {
             margin-bottom: @indent__s;
+            text-align: center;
 
-            &:last-child {
-                margin-bottom: 0;
-            }
+            .action {
+                &:extend(.abs-button-responsive all);
+                margin-bottom: @indent__s;
 
-            &.primary {
-                //&:extend(.abs-button-l all);
-            }
-        }
+                &:last-child {
+                    margin-bottom: 0;
+                }
 
-        margin-bottom: @indent__s;
+                &.primary {
+                    //&:extend(.abs-button-l all);
+                }
+            }
 
-        &:last-child {
-            margin-bottom: 0;
+            &:last-child {
+                margin-bottom: 0;
+            }
         }
-    }
 
-    > .secondary {
-        .action.back {
-            display: none;
+        > .secondary {
+            .action.back {
+                display: none;
+            }
         }
     }
 }
 
-}
-
 //
-//    Desktop
-//--------------------------------------
+//  Desktop
+//  _____________________________________________
+
 .media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__m) {
     .actions-toolbar {
         .lib-actions-toolbar();
+
         > .primary,
         > .secondary {
             margin-bottom: 0;
 
             .action {
-                width: auto;
                 margin-bottom: 0;
+                width: auto;
             }
         }
     }
diff --git a/app/design/frontend/Magento/luma/web/css/source/_buttons.less b/app/design/frontend/Magento/luma/web/css/source/_buttons.less
index ba06be7b1a7bb5da9aeae558ebfbde1652c7ef8c..c3ffc8e068c8f320dd63fd1cb4906ec850685acc 100644
--- a/app/design/frontend/Magento/luma/web/css/source/_buttons.less
+++ b/app/design/frontend/Magento/luma/web/css/source/_buttons.less
@@ -4,45 +4,42 @@
 //  */
 
 //
-//    Common
-//--------------------------------------
+//  Common
+//  _____________________________________________
 
 & when (@media-common = true) {
 
-//
-//    Using buttons mixins
-//--------------------------------------
-button,
-a.action.primary {
-    .lib-css(border-radius, @button__border-radius);
-}
+    //  Using buttons mixins
+    button,
+    a.action.primary {
+        .lib-css(border-radius, @button__border-radius);
+    }
 
-button {
-    &:not(.primary) {
-        .lib-css(box-shadow, @button__shadow);
+    button {
+        &:not(.primary) {
+            .lib-css(box-shadow, @button__shadow);
 
-        &:active {
-            .lib-css(box-shadow, @button__shadow-active);
+            &:active {
+                .lib-css(box-shadow, @button__shadow-active);
+            }
         }
     }
-}
 
-body {
-    &:not(._keyfocus) {
-        button {
-            &:focus {
-                box-shadow: none;
+    body {
+        &:not(._keyfocus) {
+            button {
+                &:focus {
+                    box-shadow: none;
+                }
             }
         }
     }
-}
 
-a.action.primary {
-    .lib-link-as-button();
-}
-
-.action.primary {
-    .lib-button-primary();
-}
+    a.action.primary {
+        .lib-link-as-button();
+    }
 
+    .action.primary {
+        .lib-button-primary();
+    }
 }
diff --git a/app/design/frontend/Magento/luma/web/css/source/_extends.less b/app/design/frontend/Magento/luma/web/css/source/_extends.less
index 1cdaf21ec2cb1d64095d26c116b0f90127024526..65dd6f738a8efd1924df9902cddfbb82a248d799 100644
--- a/app/design/frontend/Magento/luma/web/css/source/_extends.less
+++ b/app/design/frontend/Magento/luma/web/css/source/_extends.less
@@ -9,6 +9,7 @@
 
 .abs-reset-list {
     .lib-list-reset-styles();
+
     > li {
         margin: 0;
     }
@@ -58,8 +59,8 @@
     .lib-button-as-link(
         @_margin: false
     );
-    border-radius: 0;
     .lib-css(font-weight, @font-weight__regular);
+    border-radius: 0;
 
     &:active,
     &:not(:focus) {
@@ -97,8 +98,8 @@
 
 @abs-product-options-list: {
     dt {
-        float: left;
         clear: left;
+        float: left;
         margin: 0 @indent__s @indent__xs 0;
 
         &:after {
@@ -107,8 +108,8 @@
     }
 
     dd {
-        float: left;
         display: inline-block;
+        float: left;
         margin: 0 0 @indent__xs;
     }
 };
@@ -149,8 +150,8 @@
     width: 48%;
 
     &:nth-child(1) {
-        float: left;
         clear: left;
+        float: left;
     }
 
     &:nth-child(2) {
@@ -180,7 +181,7 @@
 
 .abs-reset-image-wrapper {
     height: auto;
-    padding: 0!important;
+    padding: 0 !important;
 
     .product-image-photo {
         position: static;
@@ -200,8 +201,8 @@
 .abs-adaptive-images-centered {
     display: block;
     height: auto;
-    max-width: 100%;
     margin: 0 auto;
+    max-width: 100%;
 }
 
 //
@@ -209,13 +210,14 @@
 //  ---------------------------------------------
 
 .abs-login-block-title {
+    .lib-css(border-bottom, 1px solid @secondary__color);
+    .lib-font-size(18);
+    margin-bottom: 15px;
+    padding-bottom: 12px;
+
     strong {
         font-weight: 500;
     }
-    padding-bottom: 12px;
-    margin-bottom: 15px;
-    .lib-css(border-bottom, 1px solid @secondary__color);
-    .lib-font-size(18);
 }
 
 //
@@ -240,8 +242,8 @@
 //  ---------------------------------------------
 
 .abs-input-qty {
-    width: 54px;
     text-align: center;
+    width: 54px;
 }
 
 //
@@ -264,13 +266,13 @@
 
 .abs-remove-button-for-blocks {
     .lib-icon-font(
-        @icon-remove,
-        @_icon-font-size: 12px,
-        @_icon-font-line-height: 15px,
-        @_icon-font-text-hide: true,
-        @_icon-font-color: @color-gray60,
-        @_icon-font-color-hover: @color-gray-darken4,
-        @_icon-font-color-active: @color-gray60
+    @icon-remove,
+    @_icon-font-size: 12px,
+    @_icon-font-line-height: 15px,
+    @_icon-font-text-hide: true,
+    @_icon-font-color: @color-gray60,
+    @_icon-font-color-hover: @color-gray-darken4,
+    @_icon-font-color-active: @color-gray60
     );
 }
 
@@ -333,11 +335,11 @@
 
 .abs-action-remove {
     &:extend(.abs-action-button-as-link all);
-    width: auto;
     line-height: normal;
+    margin-left: 73%;
     position: absolute;
     top: 34px;
-    margin-left: 73%;
+    width: auto;
 }
 
 //
@@ -567,6 +569,7 @@
             > .field,
             .fields > .field {
                 .lib-form-field-type-revert(@_type: block);
+
                 &:not(:first-child):last-of-type {
                     margin-bottom: 0;
                 }
@@ -601,8 +604,8 @@
 
 .abs-split-button {
     .lib-dropdown-split(
-        @_options-selector : ~".items",
-        @_dropdown-split-button-border-radius-fix: true
+    @_options-selector : ~".items",
+    @_dropdown-split-button-border-radius-fix: true
     );
     vertical-align: middle;
 }
@@ -665,9 +668,9 @@
 //  ---------------------------------------------
 
 .abs-methods-shipping-title {
+    .lib-css(font-weight, @font-weight__semibold);
     .lib-font-size(16);
     margin-bottom: 15px;
-    .lib-css(font-weight, @font-weight__semibold);
 }
 
 //
@@ -699,7 +702,7 @@
                     width: 33%;
 
                     &:before {
-                        content: attr(data-th) ":";
+                        content: attr(data-th) ':';
                         display: block;
                         font-weight: @font-weight__bold;
                         padding-bottom: @indent__s;
@@ -725,15 +728,15 @@
 .abs-actions-addto {
     .lib-css(color, @addto-color);
     display: inline-block;
-    text-transform: uppercase;
     font-weight: @font-weight__semibold;
     letter-spacing: .05em;
+    text-transform: uppercase;
     .lib-icon-font(
-        @_icon-font-content: '',
-        @_icon-font-size: 16px,
-        @_icon-font-line-height: 16px,
-        @_icon-font-margin: -2px 5px 0 0,
-        @_icon-font-vertical-align: middle
+    @_icon-font-content: '',
+    @_icon-font-size: 16px,
+    @_icon-font-line-height: 16px,
+    @_icon-font-margin: -2px 5px 0 0,
+    @_icon-font-vertical-align: middle
     );
 
     &:hover {
@@ -804,13 +807,13 @@
     @abs-toggling-title();
     .lib-css(padding, @indent__s @indent__xl @indent__s @mobile-cart-padding);
     .lib-icon-font(
-        @icon-down,
-        @_icon-font-size: 12px,
-        @_icon-font-line-height: 12px,
-        @_icon-font-text-hide: true,
-        @_icon-font-margin: 3px 0 0,
-        @_icon-font-position: after,
-        @_icon-font-display: block
+    @icon-down,
+    @_icon-font-size: 12px,
+    @_icon-font-line-height: 12px,
+    @_icon-font-text-hide: true,
+    @_icon-font-margin: 3px 0 0,
+    @_icon-font-position: after,
+    @_icon-font-display: block
     );
 }
 
@@ -820,18 +823,18 @@
         .lib-css(border-bottom, @border-width__base solid @border-color__base);
         .lib-css(padding, @indent__s @indent__xl @indent__s @layout__width-xs-indent);
         .lib-icon-font(
-            @icon-down,
-            @_icon-font-size: 12px,
-            @_icon-font-text-hide: false,
-            @_icon-font-margin: 3px 0 0 0,
-            @_icon-font-position: after,
-            @_icon-font-display: block
+        @icon-down,
+        @_icon-font-size: 12px,
+        @_icon-font-text-hide: false,
+        @_icon-font-margin: 3px 0 0 0,
+        @_icon-font-position: after,
+        @_icon-font-display: block
         );
 
         &.active {
             .lib-icon-font-symbol(
-                @_icon-font-content: @icon-up,
-                @_icon-font-position: after
+            @_icon-font-content: @icon-up,
+            @_icon-font-position: after
             );
         }
     }
@@ -843,6 +846,7 @@
 
 .abs-cart-block {
     margin: 0;
+
     > .title {
         &:extend(.abs-toggling-title all);
         &:after {
@@ -859,8 +863,8 @@
     &.active {
         > .title {
             .lib-icon-font-symbol(
-                @_icon-font-content: @icon-up,
-                @_icon-font-position: after
+            @_icon-font-content: @icon-up,
+            @_icon-font-position: after
             );
         }
 
@@ -952,9 +956,9 @@
         .lib-css(font-weight, @font-weight__light);
     }
 
+    .lib-css(border-bottom, 1px solid @account-title-border-color);
     .lib-css(margin-bottom, @indent__m);
     .lib-css(padding-bottom, @indent__s);
-    .lib-css(border-bottom, 1px solid @account-title-border-color);
 }
 
 //
@@ -1018,11 +1022,11 @@
 
 @abs-action-print: {
     .lib-icon-font(
-        @icon-print,
-        @_icon-font-size: 16px,
-        @_icon-font-line-height: 16px,
-        @_icon-font-margin: 0 4px 0 0,
-        @_icon-font-position: before
+    @icon-print,
+    @_icon-font-size: 16px,
+    @_icon-font-line-height: 16px,
+    @_icon-font-margin: 0 4px 0 0,
+    @_icon-font-position: before
     );
 
     &:hover {
@@ -1050,8 +1054,8 @@
     .price-including-tax,
     .price-excluding-tax {
         .lib-css(color, @cart-price-color);
-        display: block;
         .lib-font-size(18);
+        display: block;
         line-height: 1;
         white-space: nowrap;
 
@@ -1064,20 +1068,20 @@
 .abs-adjustment-incl-excl-tax {
     .price-including-tax,
     .price-excluding-tax {
-        display: inline-block;
         .lib-font-size(14);
+        display: inline-block;
     }
 
     .price-including-tax + .price-excluding-tax {
-        display: inline-block;
         .lib-font-size(11);
+        display: inline-block;
 
         &:before {
-            content: "("attr(data-label)": ";
+            content: '('attr(data-label)': ';
         }
 
         &:after {
-            content:")";
+            content:')';
         }
     }
 }
@@ -1088,14 +1092,15 @@
 
 .abs-tax-total {
     cursor: pointer;
-    position: relative;
     padding-right: @indent__s;
+    position: relative;
+
     .lib-icon-font(
-        @icon-down,
-        @_icon-font-size: 8px,
-        @_icon-font-line-height: 8px,
-        @_icon-font-margin: 3px 0 0 0,
-        @_icon-font-position: after
+    @icon-down,
+    @_icon-font-size: 8px,
+    @_icon-font-line-height: 8px,
+    @_icon-font-margin: 3px 0 0 0,
+    @_icon-font-position: after
     );
 
     &:after {
@@ -1107,8 +1112,8 @@
 
 .abs-tax-total-expanded {
     .lib-icon-font-symbol(
-        @_icon-font-content: @icon-up,
-        @_icon-font-position: after
+    @_icon-font-content: @icon-up,
+    @_icon-font-position: after
     );
 }
 
@@ -1132,15 +1137,15 @@
 
         &-label {
             display: table-cell;
-            vertical-align: top;
-            padding-top: 1px;
-            padding-right: @indent__m;
             padding-bottom: @indent__xs;
+            padding-right: @indent__m;
+            padding-top: 1px;
+            vertical-align: top;
         }
 
         &-result {
-            vertical-align: top;
             display: table-cell;
+            vertical-align: top;
         }
     }
 }
@@ -1151,11 +1156,11 @@
 
 .abs-account-actions {
     &:after {
-        content: "";
+        .lib-css(border-left, 1px solid @primary__color__light);
+        content: '';
         display: inline-block;
         height: 12px;
         margin: 0 @indent__s;
-        .lib-css(border-left, 1px solid @primary__color__light);
         vertical-align: -1px;
     }
 
@@ -1173,6 +1178,7 @@
 .abs-account-blocks {
     .block-title {
         &:extend(.abs-account-title all);
+
         > .action {
             margin-left: 15px;
         }
@@ -1199,7 +1205,7 @@
 
 .abs-colon {
     &:after {
-        content: ": ";
+        content: ': ';
     }
 }
 
@@ -1209,22 +1215,22 @@
 
 .abs-icon-add {
     .lib-icon-font(
-        @_icon-font-content: @icon-expand,
-        @_icon-font-size: 10px,
-        @_icon-font-line-height: 10px,
-        @_icon-font-vertical-align: middle
+    @_icon-font-content: @icon-expand,
+    @_icon-font-size: 10px,
+    @_icon-font-line-height: 10px,
+    @_icon-font-vertical-align: middle
     );
 }
 
 .media-width(@extremum, @break) when (@extremum = 'max') and (@break = @screen__m) {
     .abs-icon-add-mobile {
         .lib-icon-font(
-            @_icon-font-content: @icon-expand,
-            @_icon-font-size: 10px,
-            @_icon-font-line-height: 10px,
-            @_icon-font-vertical-align: middle,
-            @_icon-font-margin: 0 5px 0 0,
-            @_icon-font-display: block
+        @_icon-font-content: @icon-expand,
+        @_icon-font-size: 10px,
+        @_icon-font-line-height: 10px,
+        @_icon-font-vertical-align: middle,
+        @_icon-font-margin: 0 5px 0 0,
+        @_icon-font-display: block
         );
     }
 }
@@ -1375,8 +1381,8 @@
 .media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__m) {
     .abs-table-bordered-desktop {
         .lib-table-bordered(
-            @_table_type: light,
-            @_table_border-width: 1px
+        @_table_type: light,
+        @_table_border-width: 1px
         );
     }
 }
@@ -1524,9 +1530,9 @@
     &:before,
     &:after {
         .lib-arrow(
-            @_position: top,
-            @_size: @checkout-tooltip-icon-arrow__font-size,
-            @_color: @checkout-tooltip-content__background-color
+        @_position: top,
+        @_size: @checkout-tooltip-icon-arrow__font-size,
+        @_color: @checkout-tooltip-content__background-color
         );
         .lib-css(margin-top, @checkout-tooltip-icon-arrow__left);
         .lib-css(right, @indent__s);
@@ -1611,14 +1617,14 @@
         }
 
         .mark {
-            border-top: 1px solid @border-color__base;
             .lib-font-size(18);
+            border-top: 1px solid @border-color__base;
             padding-right: @indent__s;
         }
 
         .amount {
-            border-top: 1px solid @border-color__base;
             .lib-font-size(18);
+            border-top: 1px solid @border-color__base;
         }
     }
 
@@ -1634,14 +1640,14 @@
         &-summary {
             .mark,
             .amount {
-                border-top: @border-width__base solid @border-color__base;
                 border-bottom: @border-width__base solid @border-color__base;
+                border-top: @border-width__base solid @border-color__base;
                 cursor: pointer;
             }
 
             .amount .price {
-                position: relative;
                 padding-right: @indent__base;
+                position: relative;
                 .lib-icon-font(
                 @icon-down,
                 @_icon-font-size: 12px,
@@ -1673,8 +1679,8 @@
         }
 
         &-details {
-            display: none;
             border-bottom: @border-width__base solid @border-color__base;
+            display: none;
 
             &.shown {
                 display: table-row;
@@ -1697,8 +1703,10 @@
             &:extend(.abs-col-no-prefix all);
         }
 
-        tbody tr:not(:last-child) td {
-            &:extend(.abs-no-border-bottom-top all);
+        tbody tr:not(:last-child) {
+            td {
+                &:extend(.abs-no-border-bottom-top all);
+            }
         }
 
         .amount {
@@ -1762,6 +1770,7 @@
             }
         }
     }
+
     .field {
         display: table-cell;
     }
diff --git a/app/design/frontend/Magento/luma/web/css/source/_forms.less b/app/design/frontend/Magento/luma/web/css/source/_forms.less
index 58f870ef61434c15680926fb30ded0e378787658..fcc31746dcd396e331e852dd8edf674b2e619525 100644
--- a/app/design/frontend/Magento/luma/web/css/source/_forms.less
+++ b/app/design/frontend/Magento/luma/web/css/source/_forms.less
@@ -8,178 +8,181 @@
 @form-calendar-icon__color: @primary__color;
 
 //
-//    Common
-//--------------------------------------
+//  Common
+//  _____________________________________________
 
 & when (@media-common = true) {
 
-.fieldset {
-    .lib-form-fieldset();
-    &:last-child {
-        margin-bottom: 0;
-    }
+    .fieldset {
+        .lib-form-fieldset();
 
-    > .field,
-    > .fields > .field {
-        .lib-form-field();
-        &.no-label {
-            > .label {
-                .lib-visually-hidden();
-            }
+        &:last-child {
+            margin-bottom: 0;
         }
 
-        &.choice {
-            .label {
-                font-weight: normal;
-                margin: 0;
-                display: inline;
+        > .field,
+        > .fields > .field {
+            .lib-form-field();
+            &.no-label {
+                > .label {
+                    .lib-visually-hidden();
+                }
             }
-        }
 
-        .label {
-            .column:not(.main) & {
-                font-weight: normal;
+            &.choice {
+                .label {
+                    display: inline;
+                    font-weight: normal;
+                    margin: 0;
+                }
             }
-        }
 
-        .field.choice {
-            margin-bottom: @indent__s;
-            &:last-child {
-                margin-bottom: 0;
+            .label {
+                .column:not(.main) & {
+                    font-weight: normal;
+                }
             }
-        }
-    }
-}
 
-.legend + .fieldset,
-.legend + div {
-    clear: both;
-}
+            .field.choice {
+                margin-bottom: @indent__s;
 
-.legend {
-    span {
-        margin-right: @indent__xs;
+                &:last-child {
+                    margin-bottom: 0;
+                }
+            }
+        }
     }
-}
-
-fieldset.field {
-    border: 0;
-    padding: 0;
-}
 
-.field {
-    &.date {
-        .time-picker {
-            white-space: nowrap;
-            margin-top: @indent__s;
-            display: inline-block;
-        }
+    .legend + .fieldset,
+    .legend + div {
+        clear: both;
     }
 
-    .message {
-        &.warning {
-            margin-top: @indent__s;
+    .legend {
+        span {
+            margin-right: @indent__xs;
         }
     }
-}
 
-.select-styling() {
-    .lib-css(appearance, none, 1);
-    appearance: none;
-    border: 1px solid @border-color__base;
-    height: 32px;
-    background: @select__background url('../images/select-bg.svg') no-repeat 100% 45%;
-    background-size: 30px 60px;
-    padding-right: 25px;
-    text-indent: .01em;
-    text-overflow: '';
-
-    &::-ms-expand{
-        display:none;
+    fieldset.field {
+        border: 0;
+        padding: 0;
     }
 
-    .lt-ie10 & {
-        background-image: none;
-        padding-right: 4px;
+    .field {
+        &.date {
+            .time-picker {
+                display: inline-block;
+                margin-top: @indent__s;
+                white-space: nowrap;
+            }
+        }
+
+        .message {
+            &.warning {
+                margin-top: @indent__s;
+            }
+        }
     }
-}
 
-select {
-    .select-styling();
-}
+    .select-styling() {
+        .lib-css(appearance, none, 1);
+        appearance: none;
+        background-size: 30px 60px;
+        background: @select__background url('../images/select-bg.svg') no-repeat 100% 45%;
+        border: 1px solid @border-color__base;
+        height: 32px;
+        padding-right: 25px;
+        text-indent: .01em;
+        text-overflow: '';
+
+        &::-ms-expand{
+            display:none;
+        }
 
-div.mage-error[generated] {
-    margin-top: 7px;
-}
+        .lt-ie10 & {
+            background-image: none;
+            padding-right: 4px;
+        }
+    }
 
-// TEMP
+    select {
+        .select-styling();
+    }
 
-.field .tooltip {
-    .lib-tooltip(right);
-    .tooltip-content {
-        min-width: 200px;
-        white-space: normal;
+    div.mage-error[generated] {
+        margin-top: 7px;
     }
-}
 
-input:focus ~ .tooltip .tooltip-content,
-select:focus ~ .tooltip .tooltip-content {
-    display: block;
-}
+    //  TEMP
 
-.hasDatepicker {
-    + .ui-datepicker-trigger {
-        .lib-button-reset();
-        .lib-icon-font(
-        @_icon-font-content: @icon-calendar,
-        @_icon-font-color: @primary__color__lighter,
-        @_icon-font-size: @icon-calendar__font-size,
-        @_icon-font-line-height: @icon-calendar__font-size,
-        @_icon-font-display: block,
-        @_icon-font-text-hide: true
-        );
-        display: inline-block;
-        vertical-align: middle;
-
-        &:focus {
-            box-shadow: none;
-            outline: 0;
+    .field .tooltip {
+        .lib-tooltip(right);
+        .tooltip-content {
+            min-width: 200px;
+            white-space: normal;
         }
     }
-}
 
-//
-//    Sidebar forms
-//--------------------------------------
-.sidebar {
-    .fieldset {
-        margin: 0;
+    input:focus ~ .tooltip .tooltip-content,
+    select:focus ~ .tooltip .tooltip-content {
+        display: block;
+    }
 
-        > .field:not(.choice) >,
-        .fields > .field {
-            &:not(:last-child) {
-                margin: 0 0 @form-field__vertical-indent;
-            }
+    .hasDatepicker {
+        + .ui-datepicker-trigger {
+            .lib-button-reset();
+            .lib-icon-font(
+            @_icon-font-content: @icon-calendar,
+            @_icon-font-color: @primary__color__lighter,
+            @_icon-font-size: @icon-calendar__font-size,
+            @_icon-font-line-height: @icon-calendar__font-size,
+            @_icon-font-display: block,
+            @_icon-font-text-hide: true
+            );
+            display: inline-block;
+            vertical-align: middle;
 
-            .label {
-                margin: 0 0 4px;
-                padding: 0 0 @indent__xs;
-                text-align: left;
-                width: 100%;
+            &:focus {
+                box-shadow: none;
+                outline: 0;
             }
+        }
+    }
 
-            .control {
-                width: 100%;
+    //
+    //  Sidebar forms
+    //  ---------------------------------------------
+
+    .sidebar {
+        .fieldset {
+            margin: 0;
+
+            > .field:not(.choice) >,
+            .fields > .field {
+                &:not(:last-child) {
+                    margin: 0 0 @form-field__vertical-indent;
+                }
+
+                .label {
+                    margin: 0 0 4px;
+                    padding: 0 0 @indent__xs;
+                    text-align: left;
+                    width: 100%;
+                }
+
+                .control {
+                    width: 100%;
+                }
             }
         }
     }
 }
 
-}
-
 //
 //    Desktop
-//--------------------------------------
+//  _____________________________________________
+
 .media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__m) {
     .legend {
         .lib-css(border-bottom, @legend-border-bottom);
diff --git a/app/design/frontend/Magento/luma/web/css/source/_pages.less b/app/design/frontend/Magento/luma/web/css/source/_pages.less
index bd8fc71e4ebe988e74a9b7d63635927a74531917..d374a649398b7f4376a5f16ea28d1d82f6e1fbb1 100644
--- a/app/design/frontend/Magento/luma/web/css/source/_pages.less
+++ b/app/design/frontend/Magento/luma/web/css/source/_pages.less
@@ -10,8 +10,10 @@
 & when (@media-common = true) {
     .pages {
         .lib-pager();
+
         .action {
             @_shadow: inset 0 1px 0 0 @color-white, inset 0 -1px 0 0 fade(@border-color__base, 30);
+
             .lib-css(box-shadow, @_shadow);
             border-radius: 3px;
             padding: 0 8px;
diff --git a/app/design/frontend/Magento/luma/web/css/source/_popups.less b/app/design/frontend/Magento/luma/web/css/source/_popups.less
index 249b99e91b786ddc762a91fcf2042b533df6e1bd..55158957a68c1e6d106dac3ba3c9d73a0725d4f8 100644
--- a/app/design/frontend/Magento/luma/web/css/source/_popups.less
+++ b/app/design/frontend/Magento/luma/web/css/source/_popups.less
@@ -28,6 +28,7 @@
                     top: 0;
                     width: 40px;
                     z-index: 1001;
+                    
                     .lib-popup-button-close-icon(
                     @popup-button-close__icon,
                     @popup-icon-font__content,
diff --git a/app/design/frontend/Magento/luma/web/css/source/_sections.less b/app/design/frontend/Magento/luma/web/css/source/_sections.less
index e4e020e53570bef38bab550b917cc669fdb4472d..6393d5d1afa7913ff187a745deae7e4aec1bc9ee 100644
--- a/app/design/frontend/Magento/luma/web/css/source/_sections.less
+++ b/app/design/frontend/Magento/luma/web/css/source/_sections.less
@@ -19,16 +19,16 @@
             a {
                 position: relative;
                 .lib-icon-font(
-                    @_icon-font-content: @icon-down,
-                    @_icon-font-size: @font-size__base,
-                    @_icon-font-line-height: @icon-font__line-height,
-                    @_icon-font-color: @icon-font__color,
-                    @_icon-font-color-hover: @icon-font__color-hover,
-                    @_icon-font-color-active: @icon-font__color-active,
-                    @_icon-font-margin: @icon-font__margin,
-                    @_icon-font-vertical-align: @icon-font__vertical-align,
-                    @_icon-font-position: after,
-                    @_icon-font-display: false
+                @_icon-font-content: @icon-down,
+                @_icon-font-size: @font-size__base,
+                @_icon-font-line-height: @icon-font__line-height,
+                @_icon-font-color: @icon-font__color,
+                @_icon-font-color-hover: @icon-font__color-hover,
+                @_icon-font-color-active: @icon-font__color-active,
+                @_icon-font-margin: @icon-font__margin,
+                @_icon-font-vertical-align: @icon-font__vertical-align,
+                @_icon-font-position: after,
+                @_icon-font-display: false
                 );
 
                 &:after {
@@ -38,13 +38,17 @@
                 }
             }
 
-            &.active a:after {
-                content: @icon-up;
+            &.active a {
+                &:after {
+                    content: @icon-up;
+                }
             }
         }
 
-        .value p:last-child {
-            margin-bottom: 0;
+        .value p {
+            &:last-child {
+                margin-bottom: 0;
+            }
         }
 
         .table-wrapper {
@@ -64,8 +68,10 @@
         margin-left: 0;
         margin-right: 0;
 
-        .item.title a:after {
-            display: none;
+        .item.title a {
+            &:after {
+                display: none;
+            }
         }
     }
 }
diff --git a/app/design/frontend/Magento/luma/web/css/source/_tables.less b/app/design/frontend/Magento/luma/web/css/source/_tables.less
index 9632a8a81f8d42129247b1215cb1672b3e56ac1e..b0838c624c7fa8c4fd6bf9080360d49271276450 100644
--- a/app/design/frontend/Magento/luma/web/css/source/_tables.less
+++ b/app/design/frontend/Magento/luma/web/css/source/_tables.less
@@ -137,11 +137,13 @@
             padding-bottom: 0;
         }
 
-        tbody th,
-        tbody td {
-            display: block;
-            padding-left: 0;
-            padding-right: 0;
+        tbody {
+            th,
+            td {
+                display: block;
+                padding-left: 0;
+                padding-right: 0;
+            }
         }
     }
 }
diff --git a/app/design/frontend/Magento/luma/web/css/source/components/_modals_extend.less b/app/design/frontend/Magento/luma/web/css/source/components/_modals_extend.less
index 98c4c45cd072f287d79dd82626e7635ec36ef2ba..af3df5bae660bdc1665d3aada166e1136be6c855 100644
--- a/app/design/frontend/Magento/luma/web/css/source/components/_modals_extend.less
+++ b/app/design/frontend/Magento/luma/web/css/source/components/_modals_extend.less
@@ -85,8 +85,8 @@
         }
 
         .page-main-actions {
-            margin-top: @modal-slide-header__padding-vertical;
             margin-bottom: @modal-slide-header__padding-vertical - (@indent__l/2);
+            margin-top: @modal-slide-header__padding-vertical;
         }
     }
 
@@ -123,8 +123,8 @@
         .lib-modal-slide();
         &._show {
             -webkit-overflow-scrolling: touch;
-            overflow-y: auto;
             overflow-x: hidden;
+            overflow-y: auto;
         }
 
         .modal-inner-wrap {
diff --git a/app/etc/di.xml b/app/etc/di.xml
index bc0812e5d423c84983516c9235d1a3c4f0c5885c..ee07e6b9fb21b4a4e17c0627ca4c1af8e35a3df9 100755
--- a/app/etc/di.xml
+++ b/app/etc/di.xml
@@ -1075,6 +1075,11 @@
             </argument>
         </arguments>
     </type>
+    <type name="Magento\Framework\Validator\Factory">
+        <arguments>
+            <argument name="cache" xsi:type="object">Magento\Framework\App\Cache\Type\Config</argument>
+        </arguments>
+    </type>
     <type name="Magento\Server\Reflection" shared="false" />
     <type name="Magento\Framework\Reflection\DataObjectProcessor">
         <arguments>
diff --git a/composer.json b/composer.json
index 0c03b3342aaa9f67b641bb1b3eef8016051c989c..aa6febfe181ec1f70a73e2e9536b0949c630e636 100644
--- a/composer.json
+++ b/composer.json
@@ -60,14 +60,14 @@
         "ext-xsl": "*",
         "ext-mbstring": "*",
         "ext-openssl": "*",
-        "ext-zip": "*"
+        "ext-zip": "*",
+        "sjparkinson/static-review": "~4.1"
     },
     "require-dev": {
         "phpunit/phpunit": "4.1.0",
         "squizlabs/php_codesniffer": "1.5.3",
         "phpmd/phpmd": "@stable",
         "pdepend/pdepend": "2.2.2",
-        "sjparkinson/static-review": "~4.1",
         "fabpot/php-cs-fixer": "~1.2",
         "lusitanian/oauth": "~0.3 <=0.7.0"
     },
diff --git a/composer.lock b/composer.lock
index 908e43d314aa544362c7137dfb30b03d5ac26ca7..d8ccd062dfe8a2ebae78a2a3edcc8ef29d08af7a 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": "f4872f50ab960c5e2ab741970ac6af3a",
-    "content-hash": "0bca6f472b940c974ab8a2530f8d6443",
+    "hash": "8390f8d836d4daa2b32effa5c2a63ad1",
+    "content-hash": "dbb9b3bdfc1c4dea80cd1544eaabafa1",
     "packages": [
         {
             "name": "braintree/braintree_php",
@@ -265,6 +265,55 @@
             ],
             "time": "2016-01-25 15:43:01"
         },
+        {
+            "name": "league/climate",
+            "version": "2.6.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/thephpleague/climate.git",
+                "reference": "28851c909017424f61cc6a62089316313c645d1c"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/thephpleague/climate/zipball/28851c909017424f61cc6a62089316313c645d1c",
+                "reference": "28851c909017424f61cc6a62089316313c645d1c",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.4.0"
+            },
+            "require-dev": {
+                "mockery/mockery": "dev-master",
+                "phpunit/phpunit": "4.1.*"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "League\\CLImate\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Joe Tannenbaum",
+                    "email": "hey@joe.codes",
+                    "homepage": "http://joe.codes/",
+                    "role": "Developer"
+                }
+            ],
+            "description": "PHP's best friend for the terminal. CLImate allows you to easily output colored text, special formats, and more.",
+            "keywords": [
+                "cli",
+                "colors",
+                "command",
+                "php",
+                "terminal"
+            ],
+            "time": "2015-01-18 14:31:58"
+        },
         {
             "name": "magento/composer",
             "version": "1.0.2",
@@ -795,6 +844,59 @@
             ],
             "time": "2015-11-21 02:21:41"
         },
+        {
+            "name": "sjparkinson/static-review",
+            "version": "4.1.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sjparkinson/static-review.git",
+                "reference": "493c3410cf146a12fca84209bad126c494e125f0"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sjparkinson/static-review/zipball/493c3410cf146a12fca84209bad126c494e125f0",
+                "reference": "493c3410cf146a12fca84209bad126c494e125f0",
+                "shasum": ""
+            },
+            "require": {
+                "league/climate": "~2.0",
+                "php": ">=5.4.0",
+                "symfony/console": "~2.0",
+                "symfony/process": "~2.0"
+            },
+            "require-dev": {
+                "mockery/mockery": "~0.9",
+                "phpunit/phpunit": "~4.0",
+                "sensiolabs/security-checker": "~2.0",
+                "squizlabs/php_codesniffer": "~1.0"
+            },
+            "suggest": {
+                "sensiolabs/security-checker": "Required for ComposerSecurityReview.",
+                "squizlabs/php_codesniffer": "Required for PhpCodeSnifferReview."
+            },
+            "bin": [
+                "bin/static-review.php"
+            ],
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "StaticReview\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Samuel Parkinson",
+                    "email": "sam.james.parkinson@gmail.com",
+                    "homepage": "http://samp.im"
+                }
+            ],
+            "description": "An extendable framework for version control hooks.",
+            "time": "2014-09-22 08:40:36"
+        },
         {
             "name": "symfony/console",
             "version": "v2.6.13",
@@ -2710,55 +2812,6 @@
             "description": "A tool to automatically fix PHP code style",
             "time": "2016-02-26 07:37:29"
         },
-        {
-            "name": "league/climate",
-            "version": "2.6.1",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/thephpleague/climate.git",
-                "reference": "28851c909017424f61cc6a62089316313c645d1c"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/thephpleague/climate/zipball/28851c909017424f61cc6a62089316313c645d1c",
-                "reference": "28851c909017424f61cc6a62089316313c645d1c",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.4.0"
-            },
-            "require-dev": {
-                "mockery/mockery": "dev-master",
-                "phpunit/phpunit": "4.1.*"
-            },
-            "type": "library",
-            "autoload": {
-                "psr-4": {
-                    "League\\CLImate\\": "src/"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Joe Tannenbaum",
-                    "email": "hey@joe.codes",
-                    "homepage": "http://joe.codes/",
-                    "role": "Developer"
-                }
-            ],
-            "description": "PHP's best friend for the terminal. CLImate allows you to easily output colored text, special formats, and more.",
-            "keywords": [
-                "cli",
-                "colors",
-                "command",
-                "php",
-                "terminal"
-            ],
-            "time": "2015-01-18 14:31:58"
-        },
         {
             "name": "lusitanian/oauth",
             "version": "v0.7.0",
@@ -2868,16 +2921,16 @@
         },
         {
             "name": "phpmd/phpmd",
-            "version": "2.3.2",
+            "version": "2.4.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/phpmd/phpmd.git",
-                "reference": "08b5bcd454a7148579b68931fc500d824afd3bb5"
+                "reference": "fccbdb6b222f6d7a6d35af1c396ba5435cec76a9"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/phpmd/phpmd/zipball/08b5bcd454a7148579b68931fc500d824afd3bb5",
-                "reference": "08b5bcd454a7148579b68931fc500d824afd3bb5",
+                "url": "https://api.github.com/repos/phpmd/phpmd/zipball/fccbdb6b222f6d7a6d35af1c396ba5435cec76a9",
+                "reference": "fccbdb6b222f6d7a6d35af1c396ba5435cec76a9",
                 "shasum": ""
             },
             "require": {
@@ -2929,7 +2982,7 @@
                 "phpmd",
                 "pmd"
             ],
-            "time": "2015-09-24 14:37:49"
+            "time": "2016-03-10 17:17:44"
         },
         {
             "name": "phpunit/php-code-coverage",
@@ -3619,59 +3672,6 @@
             "homepage": "https://github.com/sebastianbergmann/version",
             "time": "2015-06-21 13:59:46"
         },
-        {
-            "name": "sjparkinson/static-review",
-            "version": "4.1.1",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sjparkinson/static-review.git",
-                "reference": "493c3410cf146a12fca84209bad126c494e125f0"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/sjparkinson/static-review/zipball/493c3410cf146a12fca84209bad126c494e125f0",
-                "reference": "493c3410cf146a12fca84209bad126c494e125f0",
-                "shasum": ""
-            },
-            "require": {
-                "league/climate": "~2.0",
-                "php": ">=5.4.0",
-                "symfony/console": "~2.0",
-                "symfony/process": "~2.0"
-            },
-            "require-dev": {
-                "mockery/mockery": "~0.9",
-                "phpunit/phpunit": "~4.0",
-                "sensiolabs/security-checker": "~2.0",
-                "squizlabs/php_codesniffer": "~1.0"
-            },
-            "suggest": {
-                "sensiolabs/security-checker": "Required for ComposerSecurityReview.",
-                "squizlabs/php_codesniffer": "Required for PhpCodeSnifferReview."
-            },
-            "bin": [
-                "bin/static-review.php"
-            ],
-            "type": "library",
-            "autoload": {
-                "psr-4": {
-                    "StaticReview\\": "src/"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Samuel Parkinson",
-                    "email": "sam.james.parkinson@gmail.com",
-                    "homepage": "http://samp.im"
-                }
-            ],
-            "description": "An extendable framework for version control hooks.",
-            "time": "2014-09-22 08:40:36"
-        },
         {
             "name": "squizlabs/php_codesniffer",
             "version": "1.5.3",
diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductAttributeOptionManagementInterfaceTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductAttributeOptionManagementInterfaceTest.php
index 2e31bec6182ee8d142cab94e7bc18eb3e49d9354..6f55dff0ba9f7d4b83a6799e16b7f44d8775b7f8 100644
--- a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductAttributeOptionManagementInterfaceTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductAttributeOptionManagementInterfaceTest.php
@@ -69,7 +69,6 @@ class ProductAttributeOptionManagementInterfaceTest extends WebapiAbstract
 
         $optionData = [
             AttributeOptionInterface::LABEL => 'new color',
-            AttributeOptionInterface::VALUE => 'grey',
             AttributeOptionInterface::SORT_ORDER => 100,
             AttributeOptionInterface::IS_DEFAULT => true,
             AttributeOptionInterface::STORE_LABELS => [
diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductAttributeRepositoryTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductAttributeRepositoryTest.php
index 41032701784ce7c9788a9da60abb28a2516ce807..7b8e51fb2a7a4d93e46a16746b8b29f0bc4c2149 100644
--- a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductAttributeRepositoryTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductAttributeRepositoryTest.php
@@ -84,56 +84,26 @@ class ProductAttributeRepositoryTest extends \Magento\TestFramework\TestCase\Web
 
         $expectedData = [
             'attribute_code' => $attributeCode,
-            'frontend_labels' => [
-                [
-                    'store_id' => 0,
-                    'label' => 'front_lbl'
-                ],
-            ],
             'is_required' => true,
-            "default_value" => "",
             "frontend_input" => "select",
             "is_visible_on_front" => true,
             "is_searchable" => true,
             "is_visible_in_advanced_search" => true,
             "is_filterable" => true,
             "is_filterable_in_search" => true,
-            "options" => [
-                [
-                    "label" => "string",
-                    "value" => "string",
-                    "sort_order" => 0,
-                    "is_default" => true,
-                    "store_labels" => [
-                        [
-                            "store_id" => 0,
-                            "label" => "Red"
-                        ],
-                        [
-                            "store_id" => 1,
-                            "label" => "Blue"
-                        ],
-                        [
-                            "store_id" => 2,
-                            "label" => "Yellow"
-                        ]
-                    ]
-                ]
-            ]
         ];
 
-        $this->assertEquals($attribute['options'], $expectedData['options']);
-        $this->assertEquals($attribute['attribute_code'], $expectedData['attribute_code']);
-        $this->assertEquals($attribute['frontend_labels'], $expectedData['frontend_labels']);
-        $this->assertEquals($attribute['is_required'], $expectedData['is_required']);
-        $this->assertEquals($attribute['default_value'], $expectedData['default_value']);
-        $this->assertEquals($attribute['frontend_input'], $expectedData['frontend_input']);
-        $this->assertEquals($attribute['is_filterable'], $expectedData['is_filterable']);
-        $this->assertEquals($attribute['is_filterable_in_search'], $expectedData['is_filterable_in_search']);
-        $this->assertEquals(
-            $attribute['is_visible_in_advanced_search'],
-            $expectedData['is_visible_in_advanced_search']
-        );
+        $this->assertEquals('front_lbl', $attribute['default_frontend_label']);
+        foreach ($expectedData as $key => $value) {
+            $this->assertEquals($value, $attribute[$key]);
+        }
+        //Validate options
+        //'Blue' should be first as it has sort_order = 0
+        $this->assertEquals('Default Blue', $attribute['options'][1]['label']);
+        $this->assertArrayHasKey('default_value', $attribute);
+        //'Blue' should be set as default
+        $this->assertEquals($attribute['default_value'], $attribute['options'][1]['value']);
+        $this->assertEquals('Default Red', $attribute['options'][2]['label']);
     }
 
     /**
@@ -153,46 +123,111 @@ class ProductAttributeRepositoryTest extends \Magento\TestFramework\TestCase\Web
     }
 
     /**
-     * @magentoApiDataFixture Magento/Catalog/_files/product_attribute.php
+     * @magentoApiDataFixture Magento/Catalog/Model/Product/Attribute/_files/create_attribute_service.php
      */
     public function testUpdate()
     {
-        $attributeCode = 'test_attribute_code_333';
-        $attribute = $this->getAttribute($attributeCode);
+        $attributeCode = 'label_attr_code3df4tr3';
+        $attribute = $this->createAttribute($attributeCode);
 
+        //Make sure that 'Blue' is set as default
+        $this->assertEquals($attribute['default_value'], $attribute['options'][1]['value']);
         $attributeData = [
             'attribute' => [
                 'attribute_id' => $attribute['attribute_id'],
                 'frontend_labels' => [
                     ['store_id' => 0, 'label' => 'front_lbl_new'],
                 ],
-                'default_value' => 'default value new',
+                "options" => [
+                    //Update existing
+                    [
+                        "value" => $attribute['options'][1]['value'],
+                        "label" => "New Label",
+                        "store_labels" => [
+                            [
+                                "store_id" => 1,
+                                "label" => "Default Blue Updated"
+                            ]
+                        ]
+                    ],
+                    //Add new option
+                    [
+                        "label" => "Green",
+                        "value" => "",
+                        "sort_order" => 200,
+                        "is_default" => true,
+                        "store_labels" => [
+                            [
+                                "store_id" => 0,
+                                "label" => "Admin Green"
+                            ],
+                            [
+                                "store_id" => 1,
+                                "label" => "Default Green"
+                            ]
+                        ]
+                    ]
+                ],
                 'is_required' => false,
-                'frontend_input' => 'text',
-            ],
-        ];
-
-        $serviceInfo = [
-            'rest' => [
-                'resourcePath' => self::RESOURCE_PATH . '/' . $attributeCode,
-                'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_PUT,
-            ],
-            'soap' => [
-                'service' => self::SERVICE_NAME,
-                'serviceVersion' => self::SERVICE_VERSION,
-                'operation' => self::SERVICE_NAME . 'Save',
+                'frontend_input' => 'select',
             ],
         ];
-
-        if (TESTS_WEB_API_ADAPTER == self::ADAPTER_SOAP) {
-            $attributeData['attribute']['attributeCode'] = $attributeCode;
-        }
-        $result = $this->_webApiCall($serviceInfo, $attributeData);
+        $result = $this->updateAttribute($attributeCode, $attributeData);
 
         $this->assertEquals($attribute['attribute_id'], $result['attribute_id']);
         $this->assertEquals($attributeCode, $result['attribute_code']);
-        $this->assertEquals('default value new', $result['default_value']);
         $this->assertEquals('front_lbl_new', $result['default_frontend_label']);
+        //New option set as default
+        $this->assertEquals($result['options'][3]['value'], $result['default_value']);
+        $this->assertEquals("Default Blue Updated", $result['options'][1]['label']);
+    }
+
+    /**
+     * @magentoApiDataFixture Magento/Catalog/Model/Product/Attribute/_files/create_attribute_service.php
+     */
+    public function testUpdateNotExistingOption()
+    {
+        $attributeCode = 'label_attr_code3df4tr3';
+        $attribute = $this->createAttribute($attributeCode);
+        $expectedMessage = 'Attribute %1 does not contain option with Id %2';
+
+        $attributeData = [
+            'attribute' => [
+                'attribute_id' => $attribute['attribute_id'],
+                'is_required' => true,
+                'frontend_labels' => [
+                    ['store_id' => 0, 'label' => 'front_lbl_new'],
+                ],
+                "options" => [
+                    [
+                        "value" => 1,
+                        "label" => "New Label",
+                        "store_labels" => [
+                            [
+                                "store_id" => 1,
+                                "label" => "new label"
+                            ]
+                        ]
+                    ],
+                ],
+                'frontend_input' => 'select',
+            ]
+        ];
+
+        try {
+            $this->updateAttribute($attributeCode, $attributeData);
+            $this->fail("Expected exception");
+        } catch (\SoapFault $e) {
+            $this->assertContains(
+                $expectedMessage,
+                $e->getMessage(),
+                "SoapFault does not contain expected message."
+            );
+        } catch (\Exception $e) {
+            $errorObj = $this->processRestExceptionResult($e);
+            $this->assertEquals($expectedMessage, $errorObj['message']);
+            $this->assertEquals([$attributeCode, 1], $errorObj['parameters']);
+        }
     }
 
     /**
@@ -204,9 +239,6 @@ class ProductAttributeRepositoryTest extends \Magento\TestFramework\TestCase\Web
         $this->assertTrue($this->deleteAttribute($attributeCode));
     }
 
-    /**
-     * @magentoApiDataFixture Magento/Catalog/_files/product_attribute.php
-     */
     public function testDeleteNoSuchEntityException()
     {
         $attributeCode = 'some_test_code';
@@ -266,22 +298,34 @@ class ProductAttributeRepositoryTest extends \Magento\TestFramework\TestCase\Web
                 "is_filterable_in_search" => true,
                 "options" => [
                     [
-                        "label" => "string",
-                        "value" => "string",
-                        "sort_order" => 0,
-                        "is_default" => true,
+                        "label" => "Red",
+                        "value" => "",
+                        "sort_order" => 100,
+                        "is_default" => false,
                         "store_labels" => [
                             [
                                 "store_id" => 0,
-                                "label" => "Red"
+                                "label" => "Admin Red"
                             ],
                             [
                                 "store_id" => 1,
-                                "label" => "Blue"
+                                "label" => "Default Red"
+                            ]
+                        ]
+                    ],
+                    [
+                        "label" => "Blue",
+                        "value" => "",
+                        "sort_order" => 0,
+                        "is_default" => true,
+                        "store_labels" => [
+                            [
+                                "store_id" => 0,
+                                "label" => "Admin Blue"
                             ],
                             [
-                                "store_id" => 2,
-                                "label" => "Yellow"
+                                "store_id" => 1,
+                                "label" => "Default Blue"
                             ]
                         ]
                     ]
@@ -345,4 +389,29 @@ class ProductAttributeRepositoryTest extends \Magento\TestFramework\TestCase\Web
         ];
         return $this->_webApiCall($serviceInfo, ['attributeCode' => $attributeCode]);
     }
+
+    /**
+     * Update attribute by code
+     *
+     * @param $attributeCode
+     * @return array|bool|float|int|string
+     */
+    protected function updateAttribute($attributeCode, $attributeData)
+    {
+        if (TESTS_WEB_API_ADAPTER == self::ADAPTER_SOAP) {
+            $attributeData['attribute']['attributeCode'] = $attributeCode;
+        }
+        $serviceInfo = [
+            'rest' => [
+                'resourcePath' => self::RESOURCE_PATH . '/' . $attributeCode,
+                'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_PUT,
+            ],
+            'soap' => [
+                'service' => self::SERVICE_NAME,
+                'serviceVersion' => self::SERVICE_VERSION,
+                'operation' => self::SERVICE_NAME . 'Save',
+            ],
+        ];
+        return $this->_webApiCall($serviceInfo, $attributeData);
+    }
 }
diff --git a/dev/tests/functional/lib/Magento/Mtf/Client/Element/DropdownmultiselectElement.php b/dev/tests/functional/lib/Magento/Mtf/Client/Element/DropdownmultiselectElement.php
index f698d6014e87b70169158ada5398a9b772c07176..302dc54c8fa68bac68af84dd60af56e90a5a44c5 100644
--- a/dev/tests/functional/lib/Magento/Mtf/Client/Element/DropdownmultiselectElement.php
+++ b/dev/tests/functional/lib/Magento/Mtf/Client/Element/DropdownmultiselectElement.php
@@ -32,7 +32,7 @@ class DropdownmultiselectElement extends MultiselectElement
      *
      * @var string
      */
-    protected $optionByValue = './/li[label[contains(normalize-space(.), %s)]]';
+    protected $optionByValue = './/li//label[contains(normalize-space(.), %s)]';
 
     /**
      * Set values.
diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/ExpireAdminSessionTest.php b/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/ExpireAdminSessionTest.php
index 5e29ed43311ce3d3538c6e12c4532a126564d0bb..dcadc4165c7552d72277a9652350af9fd5e37941 100644
--- a/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/ExpireAdminSessionTest.php
+++ b/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/ExpireAdminSessionTest.php
@@ -7,6 +7,7 @@
 namespace Magento\Backend\Test\TestCase;
 
 use Magento\Backend\Test\Page\Adminhtml\SystemConfigEdit;
+use Magento\Backend\Test\Page\AdminAuthLogin;
 use Magento\Config\Test\Fixture\ConfigData;
 use Magento\Mtf\TestCase\Injectable;
 
@@ -46,10 +47,14 @@ class ExpireAdminSessionTest extends Injectable
      *
      * @param SystemConfigEdit $systemConfigEdit
      * @param ConfigData $sessionLifetimeConfig
+     * @param AdminAuthLogin $adminAuthLogin
      * @return void
      */
-    public function test(SystemConfigEdit $systemConfigEdit, ConfigData $sessionLifetimeConfig)
-    {
+    public function test(
+        SystemConfigEdit $systemConfigEdit,
+        ConfigData $sessionLifetimeConfig,
+        AdminAuthLogin $adminAuthLogin
+    ) {
         $this->systemConfigEdit = $systemConfigEdit;
         $this->sessionLifetimeConfig = $sessionLifetimeConfig;
         $this->systemConfigEdit->open();
@@ -71,7 +76,7 @@ class ExpireAdminSessionTest extends Injectable
          */
         sleep($section[$keys[0]]['label']);
 
-        $this->systemConfigEdit->open();
+        $adminAuthLogin->open();
     }
 
     /**
diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/NavigateMenuTest.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/NavigateMenuTest.xml
index 847a1f2c242e6cbc840de37609d98898dd308a48..02535cf1bf01d5fc35f8c3bedcaaf64e634d64e3 100644
--- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/NavigateMenuTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/NavigateMenuTest.xml
@@ -14,7 +14,7 @@
         </variation>
         <variation name="NavigateMenuTest10">
             <data name="menuItem" xsi:type="string">Products > Categories</data>
-            <data name="pageTitle" xsi:type="string">Categories</data>
+            <data name="pageTitle" xsi:type="string">Default Category</data>
             <constraint name="Magento\Backend\Test\Constraint\AssertBackendPageIsAvailable"/>
         </variation>
         <variation name="NavigateMenuTest11">
diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/Block/Adminhtml/Block/Edit/CmsForm.xml b/dev/tests/functional/tests/app/Magento/Cms/Test/Block/Adminhtml/Block/Edit/CmsForm.xml
index 51cd1e54461e37fe1a48002f66635beec9a0d103..ae909b6ef26245cfa8487459ec318fb12d223623 100644
--- a/dev/tests/functional/tests/app/Magento/Cms/Test/Block/Adminhtml/Block/Edit/CmsForm.xml
+++ b/dev/tests/functional/tests/app/Magento/Cms/Test/Block/Adminhtml/Block/Edit/CmsForm.xml
@@ -12,7 +12,8 @@
             <input>multiselectgrouplist</input>
         </stores>
         <is_active>
-            <input>checkbox</input>
+            <selector>.admin__actions-switch-label</selector>
+            <input>switcher</input>
         </is_active>
     </fields>
 </mapping>
diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/Block/Adminhtml/Page/Edit/PageForm.xml b/dev/tests/functional/tests/app/Magento/Cms/Test/Block/Adminhtml/Page/Edit/PageForm.xml
index 61805c1c1ed3bdfd9aee91114c3ef411be527f23..c6bea89c36dca31d7962ea4ae612d600c25d391d 100644
--- a/dev/tests/functional/tests/app/Magento/Cms/Test/Block/Adminhtml/Page/Edit/PageForm.xml
+++ b/dev/tests/functional/tests/app/Magento/Cms/Test/Block/Adminhtml/Page/Edit/PageForm.xml
@@ -13,7 +13,8 @@
         <fields>
             <title />
             <is_active>
-                <input>checkbox</input>
+                <selector>.admin__actions-switch-label</selector>
+                <input>switcher</input>
             </is_active>
         </fields>
     </page_information>
diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/Block/Adminhtml/Page/Edit/Tab/Content.php b/dev/tests/functional/tests/app/Magento/Cms/Test/Block/Adminhtml/Page/Edit/Tab/Content.php
index 9402c76580fb4ecf768668ca62e6ab3470aea0a8..4293a6a7faf0509964ef0720b3e023ae53290070 100644
--- a/dev/tests/functional/tests/app/Magento/Cms/Test/Block/Adminhtml/Page/Edit/Tab/Content.php
+++ b/dev/tests/functional/tests/app/Magento/Cms/Test/Block/Adminhtml/Page/Edit/Tab/Content.php
@@ -59,6 +59,13 @@ class Content extends Tab
      */
     protected $contentHeading = '[name="content_heading"]';
 
+    /**
+     * Header locator.
+     *
+     * @var string
+     */
+    protected $header = 'header.page-header';
+
     /**
      * Clicking in content tab 'Insert Variable' button.
      *
@@ -85,7 +92,12 @@ class Content extends Tab
         $context = $element === null ? $this->_rootElement : $element;
         $addWidgetButton = $context->find($this->addWidgetButton);
         if ($addWidgetButton->isVisible()) {
-            $addWidgetButton->click();
+            try {
+                $addWidgetButton->click();
+            } catch (\PHPUnit_Extensions_Selenium2TestCase_WebDriverException $e) {
+                $this->browser->find($this->header)->hover();
+                $addWidgetButton->click();
+            }
         }
     }
 
diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsBlockNotInGrid.php b/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsBlockNotInGrid.php
index ad3ce5daef521523e6e439da296394955d995c81..2742eaee67c0f101baba23c35ac5ce17e0217ad8 100644
--- a/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsBlockNotInGrid.php
+++ b/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsBlockNotInGrid.php
@@ -29,6 +29,7 @@ class AssertCmsBlockNotInGrid extends AbstractConstraint
     {
         $cmsBlockIndex->open();
         $data = $cmsBlock->getData();
+        $data['is_active'] = $data['is_active'] == 'Yes' ?  'Enabled' : 'Disabled';
         if (isset($data['stores'])) {
             $storeId = is_array($data['stores']) ? reset($data['stores']) : $data['stores'];
             $parts = explode("/", $storeId);
diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Form/Register.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Form/Register.php
index d5de5868dba76339fe1fc00741d348f9bf65c3d1..80c66c31d9db3b448abd34d82b5abcda39333343 100644
--- a/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Form/Register.php
+++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Form/Register.php
@@ -30,6 +30,20 @@ class Register extends Form
      */
     protected $customerAttribute = "[name='%s']";
 
+    /**
+     * Locator for password error
+     *
+     * @var string
+     */
+    protected $passwordError = "#password-error";
+
+    /**
+     * Locator for password confirmation error
+     *
+     * @var string
+     */
+    protected $passwordConfirmationError = "#password-confirmation-error";
+
     /**
      * Create new customer account and fill billing address if it exists
      *
@@ -44,4 +58,26 @@ class Register extends Form
         }
         $this->_rootElement->find($this->submit, Locator::SELECTOR_CSS)->click();
     }
+
+    /**
+     * Get password error on new customer registration form.
+     *
+     * @return string
+     *
+     */
+    public function getPasswordError()
+    {
+        return $this->_rootElement->find($this->passwordError, Locator::SELECTOR_CSS)->getText();
+    }
+
+    /**
+     * Get password confirmation error on new customer registration form.
+     *
+     * @return string
+     *
+     */
+    public function getPasswordConfirmationError()
+    {
+        return $this->_rootElement->find($this->passwordConfirmationError, Locator::SELECTOR_CSS)->getText();
+    }
 }
diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/CreateExistingCustomerFrontendEntity.xml b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/CreateExistingCustomerFrontendEntity.xml
index 08af0a568a63a7eefed7903ab59ead405e7d65dc..a57ce7ec5a2343a09efb44066ee6f9e0b8242bc7 100644
--- a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/CreateExistingCustomerFrontendEntity.xml
+++ b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/CreateExistingCustomerFrontendEntity.xml
@@ -11,8 +11,8 @@
             <data name="customer/data/firstname" xsi:type="string">john</data>
             <data name="customer/data/lastname" xsi:type="string">doe</data>
             <data name="customer/data/email" xsi:type="string">johndoe%isolation%@example.com</data>
-            <data name="customer/data/password" xsi:type="string">123123q</data>
-            <data name="customer/data/password_confirmation" xsi:type="string">123123q</data>
+            <data name="customer/data/password" xsi:type="string">123123q#</data>
+            <data name="customer/data/password_confirmation" xsi:type="string">123123q#</data>
             <constraint name="Magento\Customer\Test\Constraint\AssertCustomerFailRegisterMessage" />
         </variation>
     </testCase>
diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/RegisterCustomerFrontendEntityTest.xml b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/RegisterCustomerFrontendEntityTest.xml
index 061ebbfd7518ad9dbab4055045ee86d56f6aa17d..a61daa8fd10e628805828390b6eb6222071fdba4 100644
--- a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/RegisterCustomerFrontendEntityTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/RegisterCustomerFrontendEntityTest.xml
@@ -41,23 +41,5 @@
             <constraint name="Magento\Customer\Test\Constraint\AssertCustomerSuccessRegisterMessage" />
             <constraint name="Magento\Customer\Test\Constraint\AssertCustomerRedirectToDashboard" />
         </variation>
-        <variation name="RegisterCustomerFrontendEntityTestVariation4" summary="Customer password length is below 8 characters">
-            <data name="customer/data/firstname" xsi:type="string">john</data>
-            <data name="customer/data/lastname" xsi:type="string">doe</data>
-            <data name="customer/data/email" xsi:type="string">johndoe%isolation%@example.com</data>
-            <data name="customer/data/is_subscribed" xsi:type="string">No</data>
-            <data name="customer/data/password" xsi:type="string">123123q</data>
-            <data name="customer/data/password_confirmation" xsi:type="string">123123q</data>
-            <constraint name="Magento\Customer\Test\Constraint\AssertPasswordLengthErrorMessage" />
-        </variation>
-        <variation name="RegisterCustomerFrontendEntityTestVariation5" summary="Customer password is not secure enough">
-            <data name="customer/data/firstname" xsi:type="string">john</data>
-            <data name="customer/data/lastname" xsi:type="string">doe</data>
-            <data name="customer/data/email" xsi:type="string">johndoe%isolation%@example.com</data>
-            <data name="customer/data/is_subscribed" xsi:type="string">No</data>
-            <data name="customer/data/password" xsi:type="string">123123qw</data>
-            <data name="customer/data/password_confirmation" xsi:type="string">123123qw</data>
-            <constraint name="Magento\Customer\Test\Constraint\AssertPasswordIsNotSecureEnoughMessage" />
-        </variation>
     </testCase>
 </config>
diff --git a/dev/tests/functional/tests/app/Magento/Integration/Test/TestCase/LockAdminUserWhenCreatingNewIntegrationTest.php b/dev/tests/functional/tests/app/Magento/Integration/Test/TestCase/LockAdminUserWhenCreatingNewIntegrationTest.php
index 5d3336f9068174c01f2da08ab2210088ff77b27a..52b071596e145faf52497b8443e8a5942ed2042f 100644
--- a/dev/tests/functional/tests/app/Magento/Integration/Test/TestCase/LockAdminUserWhenCreatingNewIntegrationTest.php
+++ b/dev/tests/functional/tests/app/Magento/Integration/Test/TestCase/LockAdminUserWhenCreatingNewIntegrationTest.php
@@ -107,6 +107,7 @@ class LockAdminUserWhenCreatingNewIntegrationTest extends Injectable
         $this->adminAuthLogin->open();
         $this->adminAuthLogin->getLoginBlock()->fill($customAdmin);
         $this->adminAuthLogin->getLoginBlock()->submit();
+
         // Steps
         $this->integrationIndexPage->open();
         $this->integrationIndexPage->getGridPageActions()->addNew();
@@ -114,6 +115,11 @@ class LockAdminUserWhenCreatingNewIntegrationTest extends Injectable
             $this->integrationNewPage->getIntegrationForm()->fill($integration);
             $this->integrationNewPage->getFormPageActions()->saveNew();
         }
+
+        // Reload page
+        $this->adminAuthLogin->open();
+        $this->adminAuthLogin->getLoginBlock()->fill($customAdmin);
+        $this->adminAuthLogin->getLoginBlock()->submit();
     }
 
     /**
diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CreateOrderBackendTest.php b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CreateOrderBackendTest.php
index 13b674ade8077da81bc1dff92597c55abd9618ab..eefedf3069bdcc3d9bb0b81ddb00bceaa170140c 100644
--- a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CreateOrderBackendTest.php
+++ b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CreateOrderBackendTest.php
@@ -45,7 +45,6 @@ class CreateOrderBackendTest extends Scenario
      */
     public function test()
     {
-        $this->markTestIncomplete('MAGETWO-48742');
         $this->executeScenario();
     }
 }
diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertPasswordIsNotSecureEnoughMessage.php b/dev/tests/functional/tests/app/Magento/Security/Test/Constraint/AssertPasswordIsNotSecureEnoughMessage.php
similarity index 83%
rename from dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertPasswordIsNotSecureEnoughMessage.php
rename to dev/tests/functional/tests/app/Magento/Security/Test/Constraint/AssertPasswordIsNotSecureEnoughMessage.php
index 7eff752f870a5cc1e99e8bf2089e65c8915f57b5..ce0eaf98e091b84c586d44c3e6c298a9f8109ce3 100644
--- a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertPasswordIsNotSecureEnoughMessage.php
+++ b/dev/tests/functional/tests/app/Magento/Security/Test/Constraint/AssertPasswordIsNotSecureEnoughMessage.php
@@ -4,7 +4,7 @@
  * See COPYING.txt for license details.
  */
 
-namespace Magento\Customer\Test\Constraint;
+namespace Magento\Security\Test\Constraint;
 
 use Magento\Customer\Test\Page\CustomerAccountCreate;
 use Magento\Mtf\Constraint\AbstractConstraint;
@@ -23,9 +23,9 @@ class AssertPasswordIsNotSecureEnoughMessage extends AbstractConstraint
      */
     public function processAssert(CustomerAccountCreate $registerPage)
     {
-        $expectedErrorMessage = 'Minimum different classes of characters in password are 3.' .
+        $expectedErrorMessage = 'Minimum of different classes of characters in password is 3.' .
             ' Classes of characters: Lower Case, Upper Case, Digits, Special Characters.';
-        $errorMessage = $registerPage->getMessagesBlock()->getErrorMessage();
+        $errorMessage = $registerPage->getRegisterForm()->getPasswordError();
         \PHPUnit_Framework_Assert::assertEquals(
             $expectedErrorMessage,
             $errorMessage,
diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertPasswordLengthErrorMessage.php b/dev/tests/functional/tests/app/Magento/Security/Test/Constraint/AssertPasswordLengthErrorMessage.php
similarity index 74%
rename from dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertPasswordLengthErrorMessage.php
rename to dev/tests/functional/tests/app/Magento/Security/Test/Constraint/AssertPasswordLengthErrorMessage.php
index 3a985a74b0281abc0243978f105129fc55535f6a..12a3bf248913ae3f0f973e528b98ed3287ebe57f 100644
--- a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertPasswordLengthErrorMessage.php
+++ b/dev/tests/functional/tests/app/Magento/Security/Test/Constraint/AssertPasswordLengthErrorMessage.php
@@ -4,7 +4,7 @@
  * See COPYING.txt for license details.
  */
 
-namespace Magento\Customer\Test\Constraint;
+namespace Magento\Security\Test\Constraint;
 
 use Magento\Customer\Test\Page\CustomerAccountCreate;
 use Magento\Mtf\Constraint\AbstractConstraint;
@@ -14,7 +14,7 @@ use Magento\Mtf\Constraint\AbstractConstraint;
  */
 class AssertPasswordLengthErrorMessage extends AbstractConstraint
 {
-    const PASSWORD_LENGTH_ERROR_MESSAGE = 'Please enter a password with at least 8 characters.';
+    const PASSWORD_LENGTH_ERROR_MESSAGE = 'Minimum length of this field must be equal or greater than 8 symbols';
 
     /**
      * Assert that appropriate message is displayed on "Create New Customer Account" page(frontend) if password length
@@ -25,11 +25,11 @@ class AssertPasswordLengthErrorMessage extends AbstractConstraint
      */
     public function processAssert(CustomerAccountCreate $registerPage)
     {
-        $errorMessage = $registerPage->getMessagesBlock()->getErrorMessage();
-        \PHPUnit_Framework_Assert::assertEquals(
+        $errorMessage = $registerPage->getRegisterForm()->getPasswordError();
+        \PHPUnit_Framework_Assert::assertContains(
             self::PASSWORD_LENGTH_ERROR_MESSAGE,
             $errorMessage,
-            'The messages are not equal.'
+            'Incorrect password error message.'
         );
     }
 
diff --git a/dev/tests/functional/tests/app/Magento/Security/Test/Page/UserAccountForgotPassword.php b/dev/tests/functional/tests/app/Magento/Security/Test/Page/UserAccountForgotPassword.php
new file mode 100644
index 0000000000000000000000000000000000000000..20e35317df6d788788c950d67e4110d3e34e08f0
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Security/Test/Page/UserAccountForgotPassword.php
@@ -0,0 +1,59 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Security\Test\Page;
+
+use Magento\Mtf\Page\Page;
+
+/**
+ * Class UserAccountForgotPassword
+ */
+class UserAccountForgotPassword extends Page
+{
+    const MCA = 'admin/auth/forgotpassword';
+
+    /**
+     * Blocks' config
+     *
+     * @var array
+     */
+    protected $blocks = [
+        'messagesBlock' => [
+            'class' => 'Magento\Backend\Test\Block\Messages',
+            'locator' => '.messages',
+            'strategy' => 'css selector',
+        ],
+        'forgotPasswordForm' => [
+            'class' => 'Magento\Security\Test\Block\Form\ForgotPassword',
+            'locator' => '#login-form',
+            'strategy' => 'css selector',
+        ],
+    ];
+
+    /**
+     * Constructor.
+     */
+    protected function initUrl()
+    {
+        $this->url = $_ENV['app_backend_url'] . self::MCA;
+    }
+
+    /**
+     * @return \Magento\Backend\Test\Block\Messages
+     */
+    public function getMessagesBlock()
+    {
+        return $this->getBlockInstance('messagesBlock');
+    }
+
+    /**
+     * @return \Magento\Security\Test\Block\Form\ForgotPassword
+     */
+    public function getForgotPasswordForm()
+    {
+        return $this->getBlockInstance('forgotPasswordForm');
+    }
+}
diff --git a/dev/tests/functional/tests/app/Magento/Security/Test/Page/UserAccountForgotPassword.xml b/dev/tests/functional/tests/app/Magento/Security/Test/Page/UserAccountForgotPassword.xml
deleted file mode 100644
index 7d467309126831fafbe47ebdd186c5ea58879be9..0000000000000000000000000000000000000000
--- a/dev/tests/functional/tests/app/Magento/Security/Test/Page/UserAccountForgotPassword.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" ?>
-<!--
-/**
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
- -->
-<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../vendor/magento/mtf/etc/pages.xsd">
-    <page name="UserAccountForgotPassword" mca="admin/admin/auth/forgotpassword" module="Magento_Security">
-        <block name="messagesBlock" class="Magento\Backend\Test\Block\Messages" locator=".messages" strategy="css selector"/>
-        <block name="forgotPasswordForm" class="Magento\Security\Test\Block\Form\ForgotPassword" locator="#login-form" strategy="css selector"/>
-    </page>
-</config>
\ No newline at end of file
diff --git a/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/NewFrontendCustomerPasswordTest.php b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/NewFrontendCustomerPasswordTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..77a37dc4369e51a296a786f13ed3e32fb9763f65
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/NewFrontendCustomerPasswordTest.php
@@ -0,0 +1,73 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Security\Test\TestCase;
+
+use Magento\Customer\Test\Fixture\Customer;
+use Magento\Customer\Test\Page\CustomerAccountCreate;
+use Magento\Cms\Test\Page\CmsIndex;
+use Magento\Mtf\TestCase\Injectable;
+
+/**
+ * Test Flow:
+ * 1. Go to frontend.
+ * 2. Click Register link.
+ * 3. Fill registry form.
+ * 4. Click 'Create account' button.
+ * 5. Perform assertions.
+ *
+ * @ZephyrId MAGETWO-49044
+ */
+class NewFrontendCustomerPasswordTest extends Injectable
+{
+    /* tags */
+    const MVP = 'yes';
+    const DOMAIN = 'PS';
+    /* end tags */
+
+    /**
+     * Customer registry page.
+     *
+     * @var CustomerAccountCreate
+     */
+    protected $customerAccountCreate;
+
+    /**
+     * Cms page.
+     *
+     * @var CmsIndex $cmsIndex
+     */
+    protected $cmsIndex;
+
+    /**
+     * Inject data.
+     *
+     * @param CustomerAccountCreate $customerAccountCreate
+     * @param CmsIndex $cmsIndex
+     * @return void
+     */
+    public function __inject(
+        CustomerAccountCreate $customerAccountCreate,
+        CmsIndex $cmsIndex
+    ) {
+        $this->customerAccountCreate = $customerAccountCreate;
+        $this->cmsIndex = $cmsIndex;
+    }
+
+    /**
+     * Create Customer account on Storefront.
+     *
+     * @param Customer $customer
+     * @return void
+     */
+    public function test(Customer $customer)
+    {
+        // Steps
+        $this->cmsIndex->open();
+        $this->cmsIndex->getLinksBlock()->openLink('Create an Account');
+        $this->customerAccountCreate->getRegisterForm()->registerCustomer($customer);
+    }
+}
diff --git a/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/NewFrontendCustomerPasswordTest.xml b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/NewFrontendCustomerPasswordTest.xml
new file mode 100644
index 0000000000000000000000000000000000000000..5426cc7679bc8131f1dee2c6e2ab702d02b6deb6
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/NewFrontendCustomerPasswordTest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+ -->
+<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/etc/variations.xsd">
+    <testCase name="Magento\Security\Test\TestCase\NewFrontendCustomerPasswordTest" summary="New frontend customer password check" ticketId="MAGETWO-49044">
+        <variation name="PasswordLengthTest" summary="Customer password length is below 8 characters">
+            <data name="customer/data/firstname" xsi:type="string">john</data>
+            <data name="customer/data/lastname" xsi:type="string">doe</data>
+            <data name="customer/data/email" xsi:type="string">johndoe%isolation%@example.com</data>
+            <data name="customer/data/is_subscribed" xsi:type="string">No</data>
+            <data name="customer/data/password" xsi:type="string">123123</data>
+            <data name="customer/data/password_confirmation" xsi:type="string">123123</data>
+            <constraint name="Magento\Security\Test\Constraint\AssertPasswordLengthErrorMessage" />
+        </variation>
+        <variation name="PasswordComplexityTest" summary="Customer password is not secure enough">
+            <data name="customer/data/firstname" xsi:type="string">john</data>
+            <data name="customer/data/lastname" xsi:type="string">doe</data>
+            <data name="customer/data/email" xsi:type="string">johndoe%isolation%@example.com</data>
+            <data name="customer/data/is_subscribed" xsi:type="string">No</data>
+            <data name="customer/data/password" xsi:type="string">123123qa</data>
+            <data name="customer/data/password_confirmation" xsi:type="string">123123qa</data>
+            <constraint name="Magento\Security\Test\Constraint\AssertPasswordIsNotSecureEnoughMessage" />
+        </variation>
+    </testCase>
+</config>
diff --git a/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserIsLocked.php b/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserIsLocked.php
index c2aef263fce46fbba4b88437e29111bb1d47dbb5..1a3631c74e5379bfe6afe18aa46c161d4ae1e774 100644
--- a/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserIsLocked.php
+++ b/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserIsLocked.php
@@ -14,7 +14,7 @@ use Magento\Mtf\Constraint\AbstractConstraint;
  */
 class AssertUserIsLocked extends AbstractConstraint
 {
-    const USER_ACCOUNT_DISABLED_MESSAGE = 'Your account is temporarily disabled.';
+    const USER_ACCOUNT_DISABLED_MESSAGE = 'account is temporarily disabled';
 
     /**
      * Verify that user account has been locked.
@@ -25,10 +25,12 @@ class AssertUserIsLocked extends AbstractConstraint
     public function processAssert(
         AdminAuthLogin $adminAuth
     ) {
-        \PHPUnit_Framework_Assert::assertEquals(
+        $ignoreCase = true;
+        \PHPUnit_Framework_Assert::assertContains(
             self::USER_ACCOUNT_DISABLED_MESSAGE,
             $adminAuth->getMessagesBlock()->getErrorMessage(),
-            'Message "' . self::USER_ACCOUNT_DISABLED_MESSAGE . '" is not visible.'
+            'Message "' . self::USER_ACCOUNT_DISABLED_MESSAGE . '" is not visible.',
+            $ignoreCase
         );
     }
 
diff --git a/dev/tests/functional/tests/app/Magento/User/Test/TestCase/LockAdminUserWhenCreatingNewRoleTest.php b/dev/tests/functional/tests/app/Magento/User/Test/TestCase/LockAdminUserWhenCreatingNewRoleTest.php
index 41d0ec81d7a950d05c6055493ea35378b7e50c7a..87e8a9c971e87dac46f57df66003f4e7d1d99be4 100644
--- a/dev/tests/functional/tests/app/Magento/User/Test/TestCase/LockAdminUserWhenCreatingNewRoleTest.php
+++ b/dev/tests/functional/tests/app/Magento/User/Test/TestCase/LockAdminUserWhenCreatingNewRoleTest.php
@@ -103,7 +103,7 @@ class LockAdminUserWhenCreatingNewRoleTest extends Injectable
         )->run();
         $customAdmin->persist();
 
-        //Steps
+        // Steps
         $this->adminAuthLogin->open();
         $this->adminAuthLogin->getLoginBlock()->fill($customAdmin);
         $this->adminAuthLogin->getLoginBlock()->submit();
@@ -114,6 +114,11 @@ class LockAdminUserWhenCreatingNewRoleTest extends Injectable
             $this->userRoleEditRole->getRoleFormTabs()->fill($role);
             $this->userRoleEditRole->getPageActions()->save();
         }
+
+        // Reload
+        $this->adminAuthLogin->open();
+        $this->adminAuthLogin->getLoginBlock()->fill($customAdmin);
+        $this->adminAuthLogin->getLoginBlock()->submit();
     }
 
     /**
diff --git a/dev/tests/integration/testsuite/Magento/AdvancedPricingImportExport/Model/Export/AdvancedPricingTest.php b/dev/tests/integration/testsuite/Magento/AdvancedPricingImportExport/Model/Export/AdvancedPricingTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..4b58b9f3343ba38c2cfb924c4b5c8d058e39944d
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/AdvancedPricingImportExport/Model/Export/AdvancedPricingTest.php
@@ -0,0 +1,121 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\AdvancedPricingImportExport\Model\Export;
+
+use Magento\Framework\App\Filesystem\DirectoryList;
+
+class AdvancedPricingTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\AdvancedPricingImportExport\Model\Export\AdvancedPricing
+     */
+    protected $model;
+
+    /**
+     * @var \Magento\Framework\ObjectManagerInterface
+     */
+    protected $objectManager;
+
+    /**
+     * @var \Magento\Framework\Filesystem
+     */
+    protected $fileSystem;
+
+    protected function setUp()
+    {
+        parent::setUp();
+
+        $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
+        $this->fileSystem = $this->objectManager->get(\Magento\Framework\Filesystem::class);
+        $this->model = $this->objectManager->create(
+            \Magento\AdvancedPricingImportExport\Model\Export\AdvancedPricing::class
+        );
+    }
+
+    /**
+     * @magentoAppArea adminhtml
+     * @magentoDbIsolation enabled
+     * @magentoAppIsolation enabled
+     * @magentoDataFixture Magento/Catalog/_files/product_simple.php
+     */
+    public function testExport()
+    {
+        $productRepository = $this->objectManager->create(
+            \Magento\Catalog\Api\ProductRepositoryInterface::class
+        );
+        $index = 0;
+        $ids = [];
+        $origPricingData = [];
+        while (isset($skus[$index])) {
+            $ids[$index] = $productRepository->get($skus[$index])->getId();
+            $origPricingData[$index] = $this->objectManager->create(\Magento\Catalog\Model\Product::class)
+                ->load($ids[$index])
+                ->getTierPrices();
+            $index++;
+        }
+
+        $csvfile = uniqid('importexport_') . '.csv';
+
+        $this->model->setWriter(
+            \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
+                \Magento\ImportExport\Model\Export\Adapter\Csv::class,
+                ['fileSystem' => $this->fileSystem, 'destination' => $csvfile]
+            )
+        );
+        $this->assertNotEmpty($this->model->export());
+
+        /** @var \Magento\AdvancedPricingImportExport\Model\Import\AdvancedPricing $importModel */
+        $importModel = $this->objectManager->create(
+            \Magento\AdvancedPricingImportExport\Model\Import\AdvancedPricing::class
+        );
+        $directory = $this->fileSystem->getDirectoryWrite(DirectoryList::VAR_DIR);
+        $source = $this->objectManager->create(
+            \Magento\ImportExport\Model\Import\Source\Csv::class,
+            [
+                'file' => $csvfile,
+                'directory' => $directory
+            ]
+        );
+        $errors = $importModel->setParameters(
+            [
+                'behavior' => \Magento\ImportExport\Model\Import::BEHAVIOR_APPEND,
+                'entity' => 'advanced_pricing'
+            ]
+        )->setSource(
+            $source
+        )->validateData();
+
+        $this->assertTrue(
+            $errors->getErrorsCount() == 0,
+            'Advanced Pricing import error, imported from file:' . $csvfile
+        );
+        $importModel->importData();
+
+        while ($index > 0) {
+            $index--;
+            $newPricingData = $this->objectManager->create(\Magento\Catalog\Model\Product::class)
+                ->load($ids[$index])
+                ->getTierPrices();
+            $this->assertEquals(count($origPricingData[$index]), count($newPricingData));
+            $this->assertEqualsOtherThanSkippedAttributes($origPricingData[$index], $newPricingData, []);
+        }
+    }
+
+    private function assertEqualsOtherThanSkippedAttributes($expected, $actual, $skippedAttributes)
+    {
+        foreach ($expected as $key => $value) {
+            if (in_array($key, $skippedAttributes)) {
+                continue;
+            } else {
+                $this->assertEquals(
+                    $value,
+                    $actual[$key],
+                    'Assert value at key - ' . $key . ' failed'
+                );
+            }
+        }
+    }
+}
diff --git a/dev/tests/integration/testsuite/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricingTest.php b/dev/tests/integration/testsuite/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricingTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..d923ea266ed7bee997808a5bbb6d3a6a728230d8
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricingTest.php
@@ -0,0 +1,247 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\AdvancedPricingImportExport\Model\Import;
+
+use Magento\Framework\App\Filesystem\DirectoryList;
+use Magento\ImportExport\Model\Import;
+
+/**
+ * @magentoAppArea adminhtml
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ */
+class AdvancedPricingTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\CatalogImportExport\Model\Import\Product
+     */
+    protected $model;
+
+    /**
+     * @var \Magento\Framework\ObjectManagerInterface
+     */
+    protected $objectManager;
+
+    /**
+     * @var \Magento\Framework\Filesystem
+     */
+    protected $fileSystem;
+
+    /**
+     * Expected Product Tier Price mapping with data
+     *
+     * @var array
+     */
+    protected $expectedTierPrice;
+
+    protected function setUp()
+    {
+        $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
+        $this->fileSystem = $this->objectManager->get(\Magento\Framework\Filesystem::class);
+        $this->model = $this->objectManager->create(
+            \Magento\AdvancedPricingImportExport\Model\Import\AdvancedPricing::class
+        );
+        $this->expectedTierPrice = [
+            'AdvancedPricingSimple 1' => [
+                [
+                    'customer_group_id' => \Magento\Customer\Model\Group::CUST_GROUP_ALL,
+                    'value'             => '300.0000',
+                    'qty'               => '10.0000'
+                ],
+                [
+                    'customer_group_id' => '1',
+                    'value'             => '11.0000',
+                    'qty'               => '11.0000'
+                ],
+                [
+                    'customer_group_id' => '3',
+                    'value'             => '14.0000',
+                    'qty'               => '14.0000'
+                ]
+            ],
+            'AdvancedPricingSimple 2' => [
+                [
+                    'customer_group_id' => \Magento\Customer\Model\Group::CUST_GROUP_ALL,
+                    'value'             => '1000000.0000',
+                    'qty'               => '100.0000'
+                ],
+                [
+                    'customer_group_id' => '0',
+                    'value'             => '12.0000',
+                    'qty'               => '12.0000'
+                ],
+                [
+                    'customer_group_id' => '2',
+                    'value'             => '13.0000',
+                    'qty'               => '13.0000'
+                ]
+            ]
+        ];
+    }
+
+    /**
+     * @magentoDataFixture Magento/AdvancedPricingImportExport/_files/create_products.php
+     * @magentoAppArea adminhtml
+     */
+    public function testImportAddUpdate()
+    {
+        // import data from CSV file
+        $pathToFile = __DIR__ . '/_files/import_advanced_pricing.csv';
+        $filesystem = $this->objectManager->create(
+            \Magento\Framework\Filesystem::class
+        );
+
+        $directory = $filesystem->getDirectoryWrite(DirectoryList::ROOT);
+        $source = $this->objectManager->create(
+            \Magento\ImportExport\Model\Import\Source\Csv::class,
+            [
+                'file' => $pathToFile,
+                'directory' => $directory
+            ]
+        );
+        $errors = $this->model->setSource(
+            $source
+        )->setParameters(
+            [
+                'behavior' => \Magento\ImportExport\Model\Import::BEHAVIOR_APPEND,
+                'entity' => 'advanced_pricing'
+            ]
+        )->validateData();
+
+        $this->assertEquals(0, $errors->getErrorsCount(), 'Advanced pricing import validation error');
+        $this->model->importData();
+
+        /** @var \Magento\Catalog\Model\ResourceModel\Product $resource */
+        $resource = $this->objectManager->get(\Magento\Catalog\Model\ResourceModel\Product::class);
+        $productIdList = $resource->getProductsIdsBySkus(array_keys($this->expectedTierPrice));
+        /** @var \Magento\Catalog\Model\Product $product */
+        $product = $this->objectManager->create(\Magento\Catalog\Model\Product::class);
+        foreach ($productIdList as $sku => $productId) {
+            $product->load($productId);
+            $tierPriceCollection = $product->getTierPrices();
+            $this->assertEquals(3, count($tierPriceCollection));
+            /** @var \Magento\Catalog\Model\Product\TierPrice $tierPrice */
+            foreach ($tierPriceCollection as $tierPrice) {
+                $this->assertContains($tierPrice->getData(), $this->expectedTierPrice[$sku]);
+            }
+        }
+    }
+
+    /**
+     * @magentoAppArea adminhtml
+     * @magentoDbIsolation enabled
+     * @magentoAppIsolation enabled
+     * @magentoDataFixture Magento/Catalog/_files/product_simple.php
+     */
+    public function testImportDelete()
+    {
+        $productRepository = $this->objectManager->create(
+            \Magento\Catalog\Api\ProductRepositoryInterface::class
+        );
+        $index = 0;
+        $ids = [];
+        $origPricingData = [];
+        while (isset($skus[$index])) {
+            $ids[$index] = $productRepository->get($skus[$index])->getId();
+            $origPricingData[$index] = $this->objectManager->create(\Magento\Catalog\Model\Product::class)
+                ->load($ids[$index])
+                ->getTierPrices();
+            $index++;
+        }
+
+        $csvfile = uniqid('importexport_') . '.csv';
+
+        /** @var \Magento\AdvancedPricingImportExport\Model\Export\AdvancedPricing $exportModel */
+        $exportModel = $this->objectManager->create(
+            \Magento\AdvancedPricingImportExport\Model\Export\AdvancedPricing::class
+        );
+        $exportModel->setWriter(
+            \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
+                \Magento\ImportExport\Model\Export\Adapter\Csv::class,
+                ['fileSystem' => $this->fileSystem, 'destination' => $csvfile]
+            )
+        );
+        $this->assertNotEmpty($exportModel->export());
+
+        $directory = $this->fileSystem->getDirectoryWrite(DirectoryList::VAR_DIR);
+        $source = $this->objectManager->create(
+            \Magento\ImportExport\Model\Import\Source\Csv::class,
+            [
+                'file' => $csvfile,
+                'directory' => $directory
+            ]
+        );
+        $errors = $this->model->setParameters(
+            [
+                'behavior' => \Magento\ImportExport\Model\Import::BEHAVIOR_DELETE,
+                'entity' => 'advanced_pricing'
+            ]
+        )->setSource(
+            $source
+        )->validateData();
+
+        $this->assertTrue(
+            $errors->getErrorsCount() == 0,
+            'Advanced Pricing import error, imported from file:' . $csvfile
+        );
+        $this->model->importData();
+
+        while ($index > 0) {
+            $index--;
+            $newPricingData = $this->objectManager->create(\Magento\Catalog\Model\Product::class)
+                ->load($ids[$index])
+                ->getTierPrices();
+            $this->assertEquals(0, count($newPricingData));
+        }
+    }
+
+    /**
+     * @magentoDataFixture Magento/AdvancedPricingImportExport/_files/create_products.php
+     * @magentoAppArea adminhtml
+     */
+    public function testImportReplace()
+    {
+        // import data from CSV file
+        $pathToFile = __DIR__ . '/_files/import_advanced_pricing.csv';
+        $filesystem = $this->objectManager->create(
+            \Magento\Framework\Filesystem::class
+        );
+
+        $directory = $filesystem->getDirectoryWrite(DirectoryList::ROOT);
+        $source = $this->objectManager->create(
+            \Magento\ImportExport\Model\Import\Source\Csv::class,
+            [
+                'file' => $pathToFile,
+                'directory' => $directory
+            ]
+        );
+        $errors = $this->model->setSource(
+            $source
+        )->setParameters(
+            [
+                'behavior' => \Magento\ImportExport\Model\Import::BEHAVIOR_REPLACE,
+                'entity' => 'advanced_pricing'
+            ]
+        )->validateData();
+
+        $this->assertEquals(0, $errors->getErrorsCount(), 'Advanced pricing import validation error');
+        $this->model->importData();
+
+        /** @var \Magento\Catalog\Model\ResourceModel\Product $resource */
+        $resource = $this->objectManager->get(\Magento\Catalog\Model\ResourceModel\Product::class);
+        $productIdList = $resource->getProductsIdsBySkus(array_keys($this->expectedTierPrice));
+        /** @var \Magento\Catalog\Model\Product $product */
+        $product = $this->objectManager->create(\Magento\Catalog\Model\Product::class);
+        foreach ($productIdList as $sku => $productId) {
+            $product->load($productId);
+            $tierPriceCollection = $product->getTierPrices();
+            $this->assertEquals(3, count($tierPriceCollection));
+            /** @var \Magento\Catalog\Model\Product\TierPrice $tierPrice */
+            foreach ($tierPriceCollection as $tierPrice) {
+                $this->assertContains($tierPrice->getData(), $this->expectedTierPrice[$sku]);
+            }
+        }
+    }
+}
diff --git a/dev/tests/integration/testsuite/Magento/AdvancedPricingImportExport/Model/Import/_files/import_advanced_pricing.csv b/dev/tests/integration/testsuite/Magento/AdvancedPricingImportExport/Model/Import/_files/import_advanced_pricing.csv
new file mode 100644
index 0000000000000000000000000000000000000000..37c0dff622f56e9bcbba0bfab9136b5aab0de4cd
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/AdvancedPricingImportExport/Model/Import/_files/import_advanced_pricing.csv
@@ -0,0 +1,7 @@
+sku,tier_price_website,tier_price_customer_group,tier_price_qty,tier_price
+"AdvancedPricingSimple 1","All Websites [USD]","ALL GROUPS",10.0000,300.0000
+"AdvancedPricingSimple 2","All Websites [USD]","ALL GROUPS",100.0000,1000000.0000
+"AdvancedPricingSimple 1","All Websites [USD]",General,11.0000,11.0000
+"AdvancedPricingSimple 2","All Websites [USD]","NOT LOGGED IN",12.0000,12.0000
+"AdvancedPricingSimple 1","All Websites [USD]",Retailer,14.0000,14.0000
+"AdvancedPricingSimple 2","All Websites [USD]",Wholesale,13.0000,13.0000
diff --git a/dev/tests/integration/testsuite/Magento/AdvancedPricingImportExport/_files/create_products.php b/dev/tests/integration/testsuite/Magento/AdvancedPricingImportExport/_files/create_products.php
new file mode 100644
index 0000000000000000000000000000000000000000..ed75b88bf30eb1449ffb6c07edbeca0011092c1a
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/AdvancedPricingImportExport/_files/create_products.php
@@ -0,0 +1,29 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+$productModel = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()
+    ->create(\Magento\Catalog\Model\Product::class);
+
+$productModel->setTypeId(\Magento\Catalog\Model\Product\Type::TYPE_SIMPLE)
+    ->setAttributeSetId(4)
+    ->setName('AdvancedPricingSimple 1')
+    ->setSku('AdvancedPricingSimple 1')
+    ->setPrice(321)
+    ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH)
+    ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED)
+    ->setWebsiteIds([1])
+    ->setCateroryIds([])
+    ->setStockData(['qty' => 100, 'is_in_stock' => 1])
+    ->setIsObjectNew(true)
+    ->save();
+
+$productModel->setName('AdvancedPricingSimple 2')
+    ->setId(null)
+    ->setUrlKey(null)
+    ->setSku('AdvancedPricingSimple 2')
+    ->setPrice(654)
+    ->setIsObjectNew(true)
+    ->save();
diff --git a/dev/tests/integration/testsuite/Magento/BundleImportExport/Model/BundleTest.php b/dev/tests/integration/testsuite/Magento/BundleImportExport/Model/BundleTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..50c84a64c4e1a43f78b8e3e4ac17941b8b0b0d18
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/BundleImportExport/Model/BundleTest.php
@@ -0,0 +1,101 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\BundleImportExport\Model;
+
+use Magento\CatalogImportExport\Model\AbstractProductExportImportTestCase;
+
+class BundleTest extends AbstractProductExportImportTestCase
+{
+    public function exportImportDataProvider()
+    {
+        return [
+            // @todo uncomment after MAGETWO-49677 resolved
+            /*
+            'bundle-product' => [
+                [
+                    'Magento/Bundle/_files/product.php'
+                ],
+                [
+                    'bundle-product',
+                ]
+            ],
+            */
+            'bundle-product-multi-options' => [
+                [
+                    'Magento/Bundle/_files/product_with_multiple_options.php'
+                ],
+                [
+                    'bundle-product',
+                ]
+            ],
+            // @todo uncomment after MAGETWO-49677 resolved
+            /*
+            'bundle-product-tier-pricing' => [
+                [
+                    'Magento/Bundle/_files/product_with_tier_pricing.php'
+                ],
+                [
+                    'bundle-product',
+                ]
+            ]
+            */
+        ];
+    }
+
+    public function importReplaceDataProvider()
+    {
+        return $this->exportImportDataProvider();
+    }
+
+    /**
+     * @param \Magento\Catalog\Model\Product $expectedProduct
+     * @param \Magento\Catalog\Model\Product $actualProduct
+     */
+    protected function assertEqualsSpecificAttributes($expectedProduct, $actualProduct)
+    {
+        $expectedBundleProductOptions = $expectedProduct->getExtensionAttributes()->getBundleProductOptions();
+        $actualBundleProductOptions = $actualProduct->getExtensionAttributes()->getBundleProductOptions();
+
+        $this->assertEquals(count($expectedBundleProductOptions), count($actualBundleProductOptions));
+
+        $expectedBundleProductOptionsToCompare = [];
+        foreach ($expectedBundleProductOptions as $expectedBundleProductOption) {
+            $expectedBundleProductOptionsToCompare[$expectedBundleProductOption->getTitle()]['type']
+                = $expectedBundleProductOption->getType();
+            foreach ($expectedBundleProductOption->getProductLinks() as $productLink) {
+                $expectedBundleProductOptionsToCompare[$expectedBundleProductOption->getTitle()]['product_links'][]
+                    = $productLink->getSku();
+            }
+        }
+
+        $actualBundleProductOptionsToCompare = [];
+        foreach ($actualBundleProductOptions as $actualBundleProductOption) {
+            $actualBundleProductOptionsToCompare[$actualBundleProductOption->getTitle()]['type']
+                = $actualBundleProductOption->getType();
+            foreach ($actualBundleProductOption->getProductLinks() as $productLink) {
+                $actualBundleProductOptionsToCompare[$actualBundleProductOption->getTitle()]['product_links'][]
+                    = $productLink->getSku();
+            }
+        }
+
+        $this->assertEquals(count($expectedBundleProductOptions), count($actualBundleProductOptions));
+
+        foreach ($expectedBundleProductOptionsToCompare as $key => $expectedBundleProductOption) {
+            $this->assertEquals(
+                $expectedBundleProductOption['type'],
+                $actualBundleProductOptionsToCompare[$key]['type']
+            );
+
+            $expectedProductLinks = $expectedBundleProductOption['product_links'];
+            $actualProductLinks = $actualBundleProductOptionsToCompare[$key]['product_links'];
+
+            sort($expectedProductLinks);
+            sort($actualProductLinks);
+
+            $this->assertEquals($expectedProductLinks, $actualProductLinks);
+        }
+    }
+}
diff --git a/dev/tests/integration/testsuite/Magento/BundleImportExport/Model/Import/Product/Type/BundleTest.php b/dev/tests/integration/testsuite/Magento/BundleImportExport/Model/Import/Product/Type/BundleTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..4958314cc2b7dcd00d23b33fa1b16c494edb61a0
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/BundleImportExport/Model/Import/Product/Type/BundleTest.php
@@ -0,0 +1,111 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\BundleImportExport\Model\Import\Product\Type;
+
+use Magento\Framework\App\Bootstrap;
+use Magento\Framework\App\Filesystem\DirectoryList;
+use Magento\ImportExport\Model\Import;
+
+/**
+ * @magentoAppArea adminhtml
+ */
+class BundleTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * Bundle product test Name
+     */
+    const TEST_PRODUCT_NAME = 'Bundle 1';
+
+    /**
+     * Bundle product test Type
+     */
+    const TEST_PRODUCT_TYPE = 'bundle';
+
+    /**
+     * @var \Magento\CatalogImportExport\Model\Import\Product
+     */
+    protected $model;
+
+    /**
+     * @var \Magento\Framework\ObjectManagerInterface
+     */
+    protected $objectManager;
+
+    /**
+     * List of Bundle options SKU
+     *
+     * @var array
+     */
+    protected $optionSkuList = ['Simple 1', 'Simple 2', 'Simple 3'];
+
+    protected function setUp()
+    {
+        $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
+        $this->model = $this->objectManager->create(\Magento\CatalogImportExport\Model\Import\Product::class);
+    }
+
+    /**
+     * @magentoAppArea adminhtml
+     * @magentoDbIsolation enabled
+     * @magentoAppIsolation enabled
+     */
+    public function testBundleImport()
+    {
+        // import data from CSV file
+        $pathToFile = __DIR__ . '/../../_files/import_bundle.csv';
+        $filesystem = $this->objectManager->create(
+            \Magento\Framework\Filesystem::class
+        );
+
+        $directory = $filesystem->getDirectoryWrite(DirectoryList::ROOT);
+        $source = $this->objectManager->create(
+            \Magento\ImportExport\Model\Import\Source\Csv::class,
+            [
+                'file' => $pathToFile,
+                'directory' => $directory
+            ]
+        );
+        $errors = $this->model->setSource(
+            $source
+        )->setParameters(
+            [
+                'behavior' => \Magento\ImportExport\Model\Import::BEHAVIOR_APPEND,
+                'entity' => 'catalog_product'
+            ]
+        )->validateData();
+
+        $this->assertTrue($errors->getErrorsCount() == 0);
+        $this->model->importData();
+
+        $resource = $this->objectManager->get(\Magento\Catalog\Model\ResourceModel\Product::class);
+        $productId = $resource->getIdBySku(self::TEST_PRODUCT_NAME);
+        $this->assertTrue(is_numeric($productId));
+        /** @var \Magento\Catalog\Model\Product $product */
+        $product = $this->objectManager->create(\Magento\Catalog\Model\Product::class);
+        $product->load($productId);
+
+        $this->assertFalse($product->isObjectNew());
+        $this->assertEquals(self::TEST_PRODUCT_NAME, $product->getName());
+        $this->assertEquals(self::TEST_PRODUCT_TYPE, $product->getTypeId());
+        //TODO: Uncomment assertion after MAGETWO-49157 fix
+        //$this->assertEquals(1, $product->getShipmentType());
+
+        $optionIdList = $resource->getProductsIdsBySkus($this->optionSkuList);
+        $bundleOptionCollection = $product->getExtensionAttributes()->getBundleProductOptions();
+        $this->assertEquals(2, count($bundleOptionCollection));
+        foreach ($bundleOptionCollection as $optionKey => $option) {
+            $this->assertEquals('checkbox', $option->getData('type'));
+            $this->assertEquals('Option ' . ($optionKey + 1), $option->getData('title'));
+            $this->assertEquals(self::TEST_PRODUCT_NAME, $option->getData('sku'));
+            $this->assertEquals($optionKey + 1, count($option->getData('product_links')));
+            foreach ($option->getData('product_links') as $linkKey => $productLink) {
+                $optionSku = 'Simple ' . ($optionKey + 1 + $linkKey);
+                $this->assertEquals($optionIdList[$optionSku], $productLink->getData('entity_id'));
+                $this->assertEquals($optionSku, $productLink->getData('sku'));
+            }
+        }
+    }
+}
diff --git a/dev/tests/integration/testsuite/Magento/BundleImportExport/Model/Import/_files/import_bundle.csv b/dev/tests/integration/testsuite/Magento/BundleImportExport/Model/Import/_files/import_bundle.csv
new file mode 100644
index 0000000000000000000000000000000000000000..21c342224d29f7c5d1983960e87b7cbf31357d44
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/BundleImportExport/Model/Import/_files/import_bundle.csv
@@ -0,0 +1,5 @@
+sku,store_view_code,attribute_set_code,product_type,product_websites,name,product_online,price,additional_attributes,qty,out_of_stock_qty,website_id,bundle_price_type,bundle_sku_type,bundle_price_view,bundle_weight_type,bundle_values
+Simple 1,,Default,simple,base,Simple 1,1,100,,1000,0,1,,,,,
+Simple 2,,Default,simple,base,Simple 2,1,200,,1000,0,1,,,,,
+Simple 3,,Default,simple,base,Simple 3,1,300,,1000,0,1,,,,,
+Bundle 1,,Default,bundle,base,Bundle 1,1,,shipment_type=1,0,0,1,dynamic,dynamic,Price range,dynamic,"name=Option 1,type=checkbox,required=1,sku=Simple 1,price=0.0000,default=0,default_qty=1.0000,price_type=fixed|name=Option 2,type=checkbox,required=1,sku=Simple 2,price=0.0000,default=0,default_qty=1.0000,price_type=fixed|name=Option 2,type=checkbox,required=1,sku=Simple 3,price=0.0000,default=0,default_qty=1.0000,price_type=fixed"
diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Category/DataProviderTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Category/DataProviderTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..2d47c0b49915b93045298d03059a8f9ce22e7e3c
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Category/DataProviderTest.php
@@ -0,0 +1,62 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Catalog\Model\Category;
+
+use Magento\Catalog\Model\Category\DataProvider;
+use Magento\Eav\Model\Config as EavConfig;
+use Magento\TestFramework\Helper\Bootstrap;
+
+class DataProviderTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var DataProvider
+     */
+    private $dataProvider;
+
+    /**
+     * @var \Magento\Eav\Model\Entity\Type
+     */
+    private $entityType;
+
+    /**
+     * {@inheritDoc}
+     */
+    protected function setUp()
+    {
+        parent::setUp();
+        $objectManager = Bootstrap::getObjectManager();
+        $this->dataProvider = $objectManager->create(
+            DataProvider::class,
+            [
+                'name' => 'category_form_data_source',
+                'primaryFieldName' => 'entity_id',
+                'requestFieldName' => 'id'
+            ]
+        );
+
+        $this->entityType = $objectManager->create(EavConfig::class)->getEntityType('catalog_category');
+    }
+
+    /**
+     * @return void
+     */
+    public function testGetMetaRequiredAttributes()
+    {
+        $requiredAttributes = [
+            'general' => ['name'],
+            'display_settings' => ['available_sort_by', 'default_sort_by'],
+        ];
+        $meta = $this->dataProvider->getMeta();
+        $this->assertArrayHasKey('url_key', $meta['search_engine_optimization']['children']);
+        foreach ($requiredAttributes as $scope => $attributes) {
+            foreach ($attributes as $attribute) {
+                $this->assertArrayHasKey($attribute, $meta[$scope]['children']);
+                $data = $meta[$scope]['children'][$attribute];
+                $this->assertTrue($data['arguments']['data']['config']['validation']['required-entry']);
+            }
+        }
+    }
+}
diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/CategoryTreeTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/CategoryTreeTest.php
index 46a36dbf0a0230214c77a0daadb096387390a985..3540b9ad076ac280d830352f9a1077bf2088512d 100644
--- a/dev/tests/integration/testsuite/Magento/Catalog/Model/CategoryTreeTest.php
+++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/CategoryTreeTest.php
@@ -125,7 +125,7 @@ class CategoryTreeTest extends \PHPUnit_Framework_TestCase
     public function testGetChildren()
     {
         $this->_model->load(3);
-        $this->assertEquals('4', $this->_model->getChildren());
+        $this->assertEquals('4,13', $this->_model->getChildren());
     }
 
     public function testGetPathInStore()
@@ -186,7 +186,7 @@ class CategoryTreeTest extends \PHPUnit_Framework_TestCase
     {
         $this->_model->load(3);
         $children = $this->_model->getChildrenCategories();
-        $this->assertEquals(1, count($children));
+        $this->assertEquals(2, count($children));
     }
 
     public function testGetChildrenCategoriesEmpty()
diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Layer/Filter/CategoryTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Layer/Filter/CategoryTest.php
index 2a2f4c6c1da25765fc81ed1a93e511589b575da9..26729a485c31e0b4ca9c0330da00248595af6850 100644
--- a/dev/tests/integration/testsuite/Magento/Catalog/Model/Layer/Filter/CategoryTest.php
+++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Layer/Filter/CategoryTest.php
@@ -126,11 +126,10 @@ class CategoryTest extends \PHPUnit_Framework_TestCase
         $this->assertInstanceOf('Magento\Catalog\Model\Category', $category);
         $this->assertEquals(3, $category->getId());
 
-
         $items = $model->getItems();
 
         $this->assertInternalType('array', $items);
-        $this->assertEquals(1, count($items));
+        $this->assertEquals(2, count($items));
 
         /** @var $item \Magento\Catalog\Model\Layer\Filter\Item */
         $item = $items[0];
@@ -139,6 +138,12 @@ class CategoryTest extends \PHPUnit_Framework_TestCase
         $this->assertSame($model, $item->getFilter());
         $this->assertEquals('Category 1.1', $item->getLabel());
         $this->assertEquals(4, $item->getValue());
-        $this->assertEquals(1, $item->getCount());
+        $this->assertEquals(2, $item->getCount());
+
+        $item = $items[1];
+        $this->assertInstanceOf('Magento\Catalog\Model\Layer\Filter\Item', $item);
+        $this->assertEquals('Category 1.2', $item->getLabel());
+        $this->assertEquals(13, $item->getValue());
+        $this->assertEquals(2, $item->getCount());
     }
 }
diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/ProductExternalTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/ProductExternalTest.php
index c87b553e18f8b4772ef7a5d562161cafa2508d21..3b39cfe48a314e0797b6938742b7354d54329d57 100644
--- a/dev/tests/integration/testsuite/Magento/Catalog/Model/ProductExternalTest.php
+++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/ProductExternalTest.php
@@ -112,7 +112,7 @@ class ProductExternalTest extends \PHPUnit_Framework_TestCase
         $this->_model->setId(
             $this->productRepository->get('simple')->getId()
         );
-        $this->assertEquals([2, 3, 4], $this->_model->getCategoryIds());
+        $this->assertEquals([2, 3, 4, 13], $this->_model->getCategoryIds());
     }
 
     public function testGetCategoryCollection()
@@ -132,7 +132,7 @@ class ProductExternalTest extends \PHPUnit_Framework_TestCase
         foreach ($fixtureCollection as $category) {
             $ids[] = $category->getId();
         }
-        $this->assertEquals([2, 3, 4], $ids);
+        $this->assertEquals([2, 3, 4, 13], $ids);
     }
 
     public function testGetWebsiteIds()
@@ -342,7 +342,7 @@ class ProductExternalTest extends \PHPUnit_Framework_TestCase
         $actualCategoryIds = $this->_model->getAvailableInCategories();
         sort($actualCategoryIds);
         // not depend on the order of items
-        $this->assertEquals([10, 11, 12], $actualCategoryIds);
+        $this->assertEquals([10, 11, 12, 13], $actualCategoryIds);
         //Check not visible product
         $this->_model->load(
             $this->productRepository->get('simple-3')->getId()
diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/categories.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/categories.php
index df15c30672c5471668bd850d446f4d00e497a42c..066e64a2ac81052b2208dd8b79519d5c2f77f7f7 100644
--- a/dev/tests/integration/testsuite/Magento/Catalog/_files/categories.php
+++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/categories.php
@@ -165,6 +165,20 @@ $category->setId(12)
     ->setPosition(8)
     ->save();
 
+$category = $objectManager->create('Magento\Catalog\Model\Category');
+$category->isObjectNew(true);
+$category->setId(13)
+    ->setName('Category 1.2')
+    ->setParentId(3)
+    ->setPath('1/2/3/13')
+    ->setLevel(3)
+    ->setAvailableSortBy('name')
+    ->setDefaultSortBy('name')
+    ->setIsActive(true)
+    ->setIsAnchor(true)
+    ->setPosition(2)
+    ->save();
+
 /** @var $product \Magento\Catalog\Model\Product */
 $product = $objectManager->create('Magento\Catalog\Model\Product');
 $product->isObjectNew(true);
@@ -183,7 +197,7 @@ $product->setTypeId(\Magento\Catalog\Model\Product\Type::TYPE_SIMPLE)
 
 $categoryLinkManagement->assignProductToCategories(
     $product->getSku(),
-    [2, 3, 4]
+    [2, 3, 4, 13]
 );
 
 $product = $objectManager->create('Magento\Catalog\Model\Product');
@@ -203,7 +217,7 @@ $product->setTypeId(\Magento\Catalog\Model\Product\Type::TYPE_SIMPLE)
 
 $categoryLinkManagement->assignProductToCategories(
     $product->getSku(),
-    [5]
+    [5, 4]
 );
 
 $product = $objectManager->create('Magento\Catalog\Model\Product');
@@ -244,5 +258,5 @@ $product->setTypeId(\Magento\Catalog\Model\Product\Type::TYPE_SIMPLE)
 
 $categoryLinkManagement->assignProductToCategories(
     $product->getSku(),
-    [10, 11, 12]
+    [10, 11, 12, 13]
 );
diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_virtual_in_stock.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_virtual_in_stock.php
index 9f5be07e7658d2f67a265dca5408150db7773d4e..7e70db91535d3c216e09ffd4e191081bcd060072 100644
--- a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_virtual_in_stock.php
+++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_virtual_in_stock.php
@@ -16,5 +16,5 @@ $product->setTypeId(\Magento\Catalog\Model\Product\Type::TYPE_VIRTUAL)
     ->setTaxClassId(0)
     ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH)
     ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED)
-    ->setStockData(['is_in_stock' => 1])
+    ->setStockData(['is_in_stock' => 1, 'qty' => 10])
     ->save();
diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_with_dropdown_option.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_with_dropdown_option.php
index d2455ebb0394b40d91d24f1ec8900cfe24d12790..02558b112b9748fa49826891eb3877cc6a440d68 100644
--- a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_with_dropdown_option.php
+++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_with_dropdown_option.php
@@ -40,6 +40,11 @@ $product->setTypeId(
     \Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED
 )->setCanSaveCustomOptions(
     true
+)->setStockData(
+    [
+        'qty' => 0,
+        'is_in_stock' => 0
+    ]
 );
 
 $options = [
diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_with_options.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_with_options.php
index 38c8911fbdb16b332c8c7e4606d557b85aef1583..59b236885fc8ff1c538c56f14474d22876d921ca 100644
--- a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_with_options.php
+++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_with_options.php
@@ -33,6 +33,11 @@ $product->setTypeId(
     \Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED
 )->setCanSaveCustomOptions(
     true
+)->setStockData(
+    [
+        'qty' => 0,
+        'is_in_stock' => 0
+    ]
 );
 
 $options = [
diff --git a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/AbstractProductExportImportTestCase.php b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/AbstractProductExportImportTestCase.php
new file mode 100644
index 0000000000000000000000000000000000000000..4f30d7409cf0a403fb9fbac1194b7b88b44b7b01
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/AbstractProductExportImportTestCase.php
@@ -0,0 +1,415 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\CatalogImportExport\Model;
+
+use Magento\Framework\App\Bootstrap;
+use Magento\Framework\App\Filesystem\DirectoryList;
+
+/**
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ */
+abstract class AbstractProductExportImportTestCase extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\CatalogImportExport\Model\Export\Product
+     */
+    protected $model;
+
+    /**
+     * @var \Magento\Framework\ObjectManagerInterface
+     */
+    protected $objectManager;
+
+    /**
+     * @var \Magento\Framework\Filesystem
+     */
+    protected $fileSystem;
+
+    /**
+     * @var \Magento\Catalog\Model\ResourceModel\Product
+     */
+    protected $productResource;
+
+    /**
+     * @var string[]
+     */
+    protected $fixtures;
+
+    /**
+     * skipped attributes
+     *
+     * @var array
+     */
+    public static $skippedAttributes = [
+        'options',
+        'created_at',
+        'updated_at',
+        'category_ids',
+        'special_from_date',
+        'news_from_date',
+        'custom_design_from',
+        'updated_in',
+        'tax_class_id',
+    ];
+
+    protected function setUp()
+    {
+        parent::setUp();
+
+        $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
+        $this->fileSystem = $this->objectManager->get(\Magento\Framework\Filesystem::class);
+        $this->productResource = $this->objectManager->create(
+            \Magento\Catalog\Model\ResourceModel\Product::class
+        );
+    }
+
+    protected function tearDown()
+    {
+        $this->executeRollbackFixtures($this->fixtures);
+    }
+
+    /**
+     * @magentoAppArea adminhtml
+     * @magentoDbIsolation enabled
+     * @magentoAppIsolation enabled
+     *
+     * @param array $fixtures
+     * @param string[] $skus
+     * @param string[] $skippedAttributes
+     * @dataProvider exportImportDataProvider
+     */
+    public function testExport($fixtures, $skus, $skippedAttributes = [])
+    {
+        $this->fixtures = $fixtures;
+        $this->executeFixtures($fixtures, $skus);
+        $this->modifyData($skus);
+        $skippedAttributes = array_merge(self::$skippedAttributes, $skippedAttributes);
+        $this->executeExportTest($skus, $skippedAttributes);
+    }
+
+    abstract public function exportImportDataProvider();
+
+    /**
+     * @param array $skus
+     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+     */
+    protected function modifyData($skus)
+    {
+    }
+
+    /**
+     * @param \Magento\Catalog\Model\Product $product
+     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+     */
+    public function prepareProduct($product)
+    {
+    }
+
+    protected function executeExportTest($skus, $skippedAttributes)
+    {
+        $index = 0;
+        $ids = [];
+        $origProducts = [];
+        while (isset($skus[$index])) {
+            $ids[$index] = $this->productResource->getIdBySku($skus[$index]);
+            $origProducts[$index] = $this->objectManager->create(\Magento\Catalog\Model\Product::class)
+                ->load($ids[$index]);
+            $index++;
+        }
+
+        $csvfile = $this->exportProducts();
+        $this->importProducts($csvfile, \Magento\ImportExport\Model\Import::BEHAVIOR_APPEND);
+
+        while ($index > 0) {
+            $index--;
+            $newProduct = $this->objectManager->create(\Magento\Catalog\Model\Product::class)
+                ->load($ids[$index]);
+
+            // @todo uncomment or remove after MAGETWO-49806 resolved
+            //$this->assertEquals(count($origProductData[$index]), count($newProductData));
+
+            $this->assertEqualsOtherThanSkippedAttributes(
+                $origProducts[$index]->getData(),
+                $newProduct->getData(),
+                $skippedAttributes
+            );
+
+            $this->assertEqualsSpecificAttributes($origProducts[$index], $newProduct);
+        }
+    }
+
+    private function assertEqualsOtherThanSkippedAttributes($expected, $actual, $skippedAttributes)
+    {
+        foreach ($expected as $key => $value) {
+            if (is_object($value) || in_array($key, $skippedAttributes)) {
+                continue;
+            }
+
+            $this->assertEquals(
+                $value,
+                $actual[$key],
+                'Assert value at key - ' . $key . ' failed'
+            );
+        }
+    }
+
+    /**
+     * @magentoAppArea adminhtml
+     * @magentoDbIsolation enabled
+     * @magentoAppIsolation enabled
+     *
+     * @param array $fixtures
+     * @param string[] $skus
+     * @dataProvider exportImportDataProvider
+     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+     */
+    public function testImportDelete($fixtures, $skus, $skippedAttributes = [])
+    {
+        $this->fixtures = $fixtures;
+        $this->executeFixtures($fixtures, $skus);
+        $this->modifyData($skus);
+        $this->executeImportDeleteTest($skus);
+    }
+
+    protected function executeImportDeleteTest($skus)
+    {
+        $csvfile = $this->exportProducts();
+        $this->importProducts($csvfile, \Magento\ImportExport\Model\Import::BEHAVIOR_DELETE);
+        /** @var \Magento\Catalog\Model\Product $product */
+        $product = $this->objectManager->create(\Magento\Catalog\Model\Product::class);
+        foreach ($skus as $sku) {
+            $productId = $this->productResource->getIdBySku($sku);
+            $product->load($productId);
+            $this->assertNull($product->getId());
+        }
+    }
+
+    /**
+     * Execute fixtures
+     *
+     * @param array $skus
+     * @param array $fixtures
+     * @return void
+     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+     */
+    protected function executeFixtures($fixtures, $skus = [])
+    {
+        foreach ($fixtures as $fixture) {
+            $fixturePath = $this->fileSystem->getDirectoryRead(DirectoryList::ROOT)
+                ->getAbsolutePath('/dev/tests/integration/testsuite/' . $fixture);
+            include $fixturePath;
+        }
+    }
+
+    /**
+     * Execute rollback fixtures
+     *
+     * @param array $fixtures
+     * @return void
+     */
+    private function executeRollbackFixtures($fixtures)
+    {
+        foreach ($fixtures as $fixture) {
+            $fixturePath = $this->fileSystem->getDirectoryRead(DirectoryList::ROOT)
+                ->getAbsolutePath('/dev/tests/integration/testsuite/' . $fixture);
+            $fileInfo = pathinfo($fixturePath);
+            $extension = '';
+            if (isset($fileInfo['extension'])) {
+                $extension = '.' . $fileInfo['extension'];
+            }
+            $rollbackfixturePath = $fileInfo['dirname'] . '/' . $fileInfo['filename'] . '_rollback' . $extension;
+            if (file_exists($rollbackfixturePath)) {
+                include $rollbackfixturePath;
+            }
+        }
+    }
+
+    /**
+     * @param \Magento\Catalog\Model\Product $expectedProduct
+     * @param \Magento\Catalog\Model\Product $actualProduct
+     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+     */
+    protected function assertEqualsSpecificAttributes($expectedProduct, $actualProduct)
+    {
+        // check custom options
+    }
+
+    /**
+     * @magentoAppArea adminhtml
+     * @magentoDbIsolation enabled
+     * @magentoAppIsolation enabled
+     *
+     * @param array $fixtures
+     * @param string[] $skus
+     * @param string[] $skippedAttributes
+     * @dataProvider importReplaceDataProvider
+     */
+    public function testImportReplace($fixtures, $skus, $skippedAttributes = [])
+    {
+        $this->fixtures = $fixtures;
+        $this->executeFixtures($fixtures, $skus);
+        $this->modifyData($skus);
+        $skippedAttributes = array_merge(self::$skippedAttributes, $skippedAttributes);
+        $this->executeImportReplaceTest($skus, $skippedAttributes);
+    }
+
+    /**
+     * @SuppressWarnings(PHPMD.NPathComplexity)
+     */
+    protected function executeImportReplaceTest($skus, $skippedAttributes)
+    {
+        $replacedAttributes = [
+            'row_id',
+            'entity_id',
+            'tier_price',
+            'is_salable',
+            'media_gallery'
+        ];
+        $skippedAttributes = array_merge($replacedAttributes, $skippedAttributes);
+
+        $index = 0;
+        $ids = [];
+        $origProducts = [];
+        while (isset($skus[$index])) {
+            $ids[$index] = $this->productResource->getIdBySku($skus[$index]);
+            $origProducts[$index] = $this->objectManager->create(\Magento\Catalog\Model\Product::class)
+                ->load($ids[$index]);
+            $index++;
+        }
+
+        $csvfile = $this->exportProducts();
+        $this->importProducts($csvfile, \Magento\ImportExport\Model\Import::BEHAVIOR_REPLACE);
+
+        while ($index > 0) {
+            $index--;
+
+            $id = $this->productResource->getIdBySku($skus[$index]);
+            $newProduct = $this->objectManager->create(\Magento\Catalog\Model\Product::class)->load($id);
+
+            // check original product is deleted
+            $origProduct = $this->objectManager->create(\Magento\Catalog\Model\Product::class)->load($ids[$index]);
+            $this->assertNull($origProduct->getId());
+
+            // check new product data
+            // @todo uncomment or remove after MAGETWO-49806 resolved
+            //$this->assertEquals(count($origProductData[$index]), count($newProductData));
+
+            $origProductData = $origProducts[$index]->getData();
+            $newProductData = $newProduct->getData();
+            $this->assertEqualsOtherThanSkippedAttributes($origProductData, $newProductData, $skippedAttributes);
+
+            $this->assertEqualsSpecificAttributes($origProducts[$index], $newProduct);
+
+            foreach ($replacedAttributes as $attribute) {
+                if (isset($origProductData[$attribute])) {
+                    $expected = is_array($origProductData[$attribute]) ?
+                        array_filter($origProductData[$attribute]) :
+                        $origProductData[$attribute];
+                    if (!empty($expected)) {
+                        $actual = isset($newProductData[$attribute]) ? $newProductData[$attribute] : null;
+                        $actual = is_array($actual) ? array_filter($actual) : $actual;
+                        $this->assertNotEquals($expected, $actual, $attribute . ' is expected to be changed');
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Export products in the system
+     *
+     * @return string Return exported file name
+     */
+    private function exportProducts()
+    {
+        $csvfile = uniqid('importexport_') . '.csv';
+
+        $exportProduct = $this->objectManager->create(\Magento\CatalogImportExport\Model\Export\Product::class);
+        $exportProduct->setWriter(
+            \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
+                \Magento\ImportExport\Model\Export\Adapter\Csv::class,
+                ['fileSystem' => $this->fileSystem, 'destination' => $csvfile]
+            )
+        );
+        $this->assertNotEmpty($exportProduct->export());
+        return $csvfile;
+    }
+
+    /**
+     * Import products from the given file
+     *
+     * @param string $csvfile
+     * @param string $behavior
+     * @return void
+     */
+    private function importProducts($csvfile, $behavior)
+    {
+        /** @var \Magento\CatalogImportExport\Model\Import\Product $importModel */
+        $importModel = $this->objectManager->create(
+            \Magento\CatalogImportExport\Model\Import\Product::class
+        );
+        $directory = $this->fileSystem->getDirectoryWrite(DirectoryList::VAR_DIR);
+        $source = $this->objectManager->create(
+            \Magento\ImportExport\Model\Import\Source\Csv::class,
+            [
+                'file' => $csvfile,
+                'directory' => $directory
+            ]
+        );
+
+        $appParams = \Magento\TestFramework\Helper\Bootstrap::getInstance()->getBootstrap()
+            ->getApplication()
+            ->getInitParams()[Bootstrap::INIT_PARAM_FILESYSTEM_DIR_PATHS];
+        $uploader = $importModel->getUploader();
+        $rootDirectory = $this->fileSystem->getDirectoryWrite(DirectoryList::ROOT);
+        $destDir = $rootDirectory->getRelativePath(
+            $appParams[DirectoryList::MEDIA][DirectoryList::PATH] . '/catalog/product'
+        );
+        $tmpDir = $rootDirectory->getRelativePath(
+            $appParams[DirectoryList::MEDIA][DirectoryList::PATH] . '/import'
+        );
+
+        $rootDirectory->create($destDir);
+        $rootDirectory->create($tmpDir);
+        $this->assertTrue($uploader->setDestDir($destDir));
+        $this->assertTrue($uploader->setTmpDir($tmpDir));
+
+        $errors = $importModel->setParameters(
+            [
+                'behavior' => $behavior,
+                'entity' => 'catalog_product',
+            ]
+        )->setSource(
+            $source
+        )->validateData();
+        $errorMessage = $this->extractErrorMessage($errors->getAllErrors());
+
+        $this->assertEmpty(
+            $errorMessage,
+            'Product import from file ' . $csvfile . ' validation errors: ' . $errorMessage
+        );
+        $importModel->importData();
+        $importErrors = $importModel->getErrorAggregator()->getAllErrors();
+        $importErrorMessage = $this->extractErrorMessage($importErrors);
+        $this->assertEmpty(
+            $importErrorMessage,
+            'Product import from file ' . $csvfile . ' errors: ' . $importErrorMessage
+        );
+    }
+
+    /**
+     * @param \Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingError[] $errors
+     * @return string
+     */
+    private function extractErrorMessage($errors)
+    {
+        $errorMessage = '';
+        foreach ($errors as $error) {
+            $errorMessage = "\n" . $error->getErrorMessage();
+        }
+        return $errorMessage;
+    }
+}
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 5d104dfef4cf4d74efcf7d89e56474363a5469f9..68f9b09a1afb1965d96a11d312e17b61c98e1e5c 100644
--- a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Export/ProductTest.php
+++ b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Export/ProductTest.php
@@ -13,7 +13,17 @@ class ProductTest extends \PHPUnit_Framework_TestCase
     /**
      * @var \Magento\CatalogImportExport\Model\Export\Product
      */
-    protected $_model;
+    protected $model;
+
+    /**
+     * @var \Magento\Framework\ObjectManagerInterface
+     */
+    protected $objectManager;
+
+    /**
+     * @var \Magento\Framework\Filesystem
+     */
+    protected $fileSystem;
 
     /**
      * Stock item attributes which must be exported
@@ -40,15 +50,17 @@ class ProductTest extends \PHPUnit_Framework_TestCase
         'qty_increments',
         'use_config_enable_qty_inc',
         'enable_qty_increments',
-        'is_decimal_divided',
+        'is_decimal_divided'
     ];
 
     protected function setUp()
     {
         parent::setUp();
 
-        $this->_model = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
-            'Magento\CatalogImportExport\Model\Export\Product'
+        $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
+        $this->fileSystem = $this->objectManager->get(\Magento\Framework\Filesystem::class);
+        $this->model = $this->objectManager->create(
+            \Magento\CatalogImportExport\Model\Export\Product::class
         );
     }
 
@@ -57,15 +69,14 @@ class ProductTest extends \PHPUnit_Framework_TestCase
      */
     public function testExport()
     {
-        $this->_model->setWriter(
-            \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
-                'Magento\ImportExport\Model\Export\Adapter\Csv'
+        $this->model->setWriter(
+            $this->objectManager->create(
+                \Magento\ImportExport\Model\Export\Adapter\Csv::class
             )
         );
-        $exportData = $this->_model->export();
+        $exportData = $this->model->export();
         $this->assertContains('New Product', $exportData);
 
-        $this->markTestIncomplete('Test must be unskiped after implementation MAGETWO-49018');
         $this->assertContains('Option 1 Value 1', $exportData);
         $this->assertContains('test_option_code_2', $exportData);
         $this->assertContains('max_characters=10', $exportData);
@@ -79,8 +90,8 @@ class ProductTest extends \PHPUnit_Framework_TestCase
      */
     public function testExportStockItemAttributesAreFilled()
     {
-        $fileWrite = $this->getMock('Magento\Framework\Filesystem\File\Write', [], [], '', false);
-        $directoryMock = $this->getMock('Magento\Framework\Filesystem\Directory\Write', [], [], '', false);
+        $fileWrite = $this->getMock(\Magento\Framework\Filesystem\File\Write::class, [], [], '', false);
+        $directoryMock = $this->getMock(\Magento\Framework\Filesystem\Directory\Write::class, [], [], '', false);
         $directoryMock->expects($this->any())->method('getParentDirectory')->will($this->returnValue('some#path'));
         $directoryMock->expects($this->any())->method('isWritable')->will($this->returnValue(true));
         $directoryMock->expects($this->any())->method('isFile')->will($this->returnValue(true));
@@ -93,12 +104,12 @@ class ProductTest extends \PHPUnit_Framework_TestCase
         );
         $directoryMock->expects($this->once())->method('openFile')->will($this->returnValue($fileWrite));
 
-        $filesystemMock = $this->getMock('Magento\Framework\Filesystem', [], [], '', false);
+        $filesystemMock = $this->getMock(\Magento\Framework\Filesystem::class, [], [], '', false);
         $filesystemMock->expects($this->once())->method('getDirectoryWrite')->will($this->returnValue($directoryMock));
 
         $exportAdapter = new \Magento\ImportExport\Model\Export\Adapter\Csv($filesystemMock);
 
-        $this->_model->setWriter($exportAdapter)->export();
+        $this->model->setWriter($exportAdapter)->export();
     }
 
     /**
@@ -142,17 +153,18 @@ class ProductTest extends \PHPUnit_Framework_TestCase
     {
         $exception = new \Exception('Error');
 
-        $rowCustomizerMock = $this->getMockBuilder('Magento\CatalogImportExport\Model\Export\RowCustomizerInterface')
+        $rowCustomizerMock =
+            $this->getMockBuilder(\Magento\CatalogImportExport\Model\Export\RowCustomizerInterface::class)
             ->disableOriginalConstructor()
             ->getMock();
 
-        $loggerMock = $this->getMockBuilder('\Psr\Log\LoggerInterface')->getMock();
+        $loggerMock = $this->getMockBuilder(\Psr\Log\LoggerInterface::class)->getMock();
 
-        $directoryMock = $this->getMock('Magento\Framework\Filesystem\Directory\Write', [], [], '', false);
+        $directoryMock = $this->getMock(\Magento\Framework\Filesystem\Directory\Write::class, [], [], '', false);
         $directoryMock->expects($this->any())->method('getParentDirectory')->will($this->returnValue('some#path'));
         $directoryMock->expects($this->any())->method('isWritable')->will($this->returnValue(true));
 
-        $filesystemMock = $this->getMock('Magento\Framework\Filesystem', [], [], '', false);
+        $filesystemMock = $this->getMock(\Magento\Framework\Filesystem::class, [], [], '', false);
         $filesystemMock->expects($this->once())->method('getDirectoryWrite')->will($this->returnValue($directoryMock));
 
         $exportAdapter = new \Magento\ImportExport\Model\Export\Adapter\Csv($filesystemMock);
@@ -161,12 +173,12 @@ class ProductTest extends \PHPUnit_Framework_TestCase
         $loggerMock->expects($this->once())->method('critical')->with($exception);
 
         $collection = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
-            '\Magento\Catalog\Model\ResourceModel\Product\Collection'
+            \Magento\Catalog\Model\ResourceModel\Product\Collection::class
         );
 
         /** @var \Magento\CatalogImportExport\Model\Export\Product $model */
         $model = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
-            'Magento\CatalogImportExport\Model\Export\Product',
+            \Magento\CatalogImportExport\Model\Export\Product::class,
             [
                 'rowCustomizer' => $rowCustomizerMock,
                 'logger' => $loggerMock,
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 4f44de03137faed64f08cda5d84f6987aad07e1e..bbc844340bc3da5e5a2c963d806999a98ba6fa88 100644
--- a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php
+++ b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php
@@ -22,6 +22,7 @@ use Magento\ImportExport\Model\Import;
  * Class ProductTest
  *
  * @magentoDataFixtureBeforeTransaction Magento/Catalog/_files/enable_reindex_schedule.php
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  */
 class ProductTest extends \Magento\TestFramework\Indexer\TestCase
 {
@@ -54,7 +55,7 @@ class ProductTest extends \Magento\TestFramework\Indexer\TestCase
     {
         $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
         $this->_model = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
-            'Magento\CatalogImportExport\Model\Import\Product'
+            \Magento\CatalogImportExport\Model\Import\Product::class
         );
         parent::setUp();
     }
@@ -87,10 +88,9 @@ class ProductTest extends \Magento\TestFramework\Indexer\TestCase
      */
     public function testSaveProductsVisibility()
     {
-        $this->markTestSkipped('Test must be unskiped after implementation MAGETWO-47449');
         /** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository */
         $productRepository = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
-            'Magento\Catalog\Api\ProductRepositoryInterface'
+            \Magento\Catalog\Api\ProductRepositoryInterface::class
         );
         $id1 = $productRepository->get('simple1')->getId();
         $id2 = $productRepository->get('simple2')->getId();
@@ -99,18 +99,18 @@ class ProductTest extends \Magento\TestFramework\Indexer\TestCase
         $productsBeforeImport = [];
         foreach ($existingProductIds as $productId) {
             $product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
-                'Magento\Catalog\Model\Product'
+                \Magento\Catalog\Model\Product::class
             );
             $product->load($productId);
             $productsBeforeImport[] = $product;
         }
 
         $filesystem = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()
-            ->create('Magento\Framework\Filesystem');
+            ->create(\Magento\Framework\Filesystem::class);
         $directory = $filesystem->getDirectoryWrite(DirectoryList::ROOT);
 
         $source = $this->objectManager->create(
-            '\Magento\ImportExport\Model\Import\Source\Csv',
+            \Magento\ImportExport\Model\Import\Source\Csv::class,
             [
                 'file' => __DIR__ . '/_files/products_to_import.csv',
                 'directory' => $directory
@@ -130,7 +130,7 @@ class ProductTest extends \Magento\TestFramework\Indexer\TestCase
         foreach ($productsBeforeImport as $productBeforeImport) {
             /** @var $productAfterImport \Magento\Catalog\Model\Product */
             $productAfterImport = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
-                'Magento\Catalog\Model\Product'
+                \Magento\Catalog\Model\Product::class
             );
             $productAfterImport->load($productBeforeImport->getId());
 
@@ -149,10 +149,9 @@ class ProductTest extends \Magento\TestFramework\Indexer\TestCase
      */
     public function testSaveStockItemQty()
     {
-        $this->markTestSkipped('Test must be unskiped after implementation MAGETWO-47449');
         /** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository */
         $productRepository = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
-            'Magento\Catalog\Api\ProductRepositoryInterface'
+            \Magento\Catalog\Api\ProductRepositoryInterface::class
         );
         $id1 = $productRepository->get('simple1')->getId();
         $id2 = $productRepository->get('simple2')->getId();
@@ -162,7 +161,7 @@ class ProductTest extends \Magento\TestFramework\Indexer\TestCase
         foreach ($existingProductIds as $productId) {
             /** @var $stockRegistry \Magento\CatalogInventory\Model\StockRegistry */
             $stockRegistry = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
-                'Magento\CatalogInventory\Model\StockRegistry'
+                \Magento\CatalogInventory\Model\StockRegistry::class
             );
 
             $stockItem = $stockRegistry->getStockItem($productId, 1);
@@ -170,10 +169,10 @@ class ProductTest extends \Magento\TestFramework\Indexer\TestCase
         }
 
         $filesystem = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()
-            ->create('Magento\Framework\Filesystem');
+            ->create(\Magento\Framework\Filesystem::class);
         $directory = $filesystem->getDirectoryWrite(DirectoryList::ROOT);
         $source = $this->objectManager->create(
-            '\Magento\ImportExport\Model\Import\Source\Csv',
+            \Magento\ImportExport\Model\Import\Source\Csv::class,
             [
                 'file' => __DIR__ . '/_files/products_to_import.csv',
                 'directory' => $directory
@@ -193,7 +192,7 @@ class ProductTest extends \Magento\TestFramework\Indexer\TestCase
         foreach ($stockItems as $productId => $stockItmBeforeImport) {
             /** @var $stockRegistry \Magento\CatalogInventory\Model\StockRegistry */
             $stockRegistry = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
-                'Magento\CatalogInventory\Model\StockRegistry'
+                \Magento\CatalogInventory\Model\StockRegistry::class
             );
 
             $stockItemAfterImport = $stockRegistry->getStockItem($productId, 1);
@@ -214,12 +213,11 @@ class ProductTest extends \Magento\TestFramework\Indexer\TestCase
      */
     public function testStockState()
     {
-        $this->markTestSkipped('Test must be unskiped after implementation MAGETWO-47449');
         $filesystem = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()
-            ->create('Magento\Framework\Filesystem');
+            ->create(\Magento\Framework\Filesystem::class);
         $directory = $filesystem->getDirectoryWrite(DirectoryList::ROOT);
         $source = $this->objectManager->create(
-            '\Magento\ImportExport\Model\Import\Source\Csv',
+            \Magento\ImportExport\Model\Import\Source\Csv::class,
             [
                 'file' => __DIR__ . '/_files/products_to_import_with_qty.csv',
                 'directory' => $directory
@@ -247,14 +245,13 @@ class ProductTest extends \Magento\TestFramework\Indexer\TestCase
      */
     public function testSaveCustomOptions($importFile, $sku)
     {
-        $this->markTestSkipped('Test must be unskiped after implementation MAGETWO-47449');
         $pathToFile = __DIR__ . '/_files/' . $importFile;
         $filesystem = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()
-            ->create('Magento\Framework\Filesystem');
+            ->create(\Magento\Framework\Filesystem::class);
         $directory = $filesystem->getDirectoryWrite(DirectoryList::ROOT);
 
         $source = $this->objectManager->create(
-            '\Magento\ImportExport\Model\Import\Source\Csv',
+            \Magento\ImportExport\Model\Import\Source\Csv::class,
             [
                 'file' => $pathToFile,
                 'directory' => $directory
@@ -274,7 +271,7 @@ class ProductTest extends \Magento\TestFramework\Indexer\TestCase
         );
         $product = $productRepository->get($sku);
 
-        $this->assertInstanceOf('Magento\Catalog\Model\Product', $product);
+        $this->assertInstanceOf(\Magento\Catalog\Model\Product::class, $product);
         $options = $product->getOptionInstance()->getProductOptions($product);
 
         $expectedData = $this->getExpectedOptionsData($pathToFile);
@@ -338,10 +335,9 @@ class ProductTest extends \Magento\TestFramework\Indexer\TestCase
      */
     public function testSaveDatetimeAttribute()
     {
-        $this->markTestSkipped('Test must be unskiped after implementation MAGETWO-47449');
         /** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository */
         $productRepository = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
-            'Magento\Catalog\Api\ProductRepositoryInterface'
+            \Magento\Catalog\Api\ProductRepositoryInterface::class
         );
         $id1 = $productRepository->get('simple1')->getId();
         $id2 = $productRepository->get('simple2')->getId();
@@ -350,18 +346,18 @@ class ProductTest extends \Magento\TestFramework\Indexer\TestCase
         $productsBeforeImport = [];
         foreach ($existingProductIds as $productId) {
             $product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
-                'Magento\Catalog\Model\Product'
+                \Magento\Catalog\Model\Product::class
             );
             $product->load($productId);
             $productsBeforeImport[$product->getSku()] = $product;
         }
 
         $filesystem = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()
-            ->create('Magento\Framework\Filesystem');
+            ->create(\Magento\Framework\Filesystem::class);
         $directory = $filesystem->getDirectoryWrite(DirectoryList::ROOT);
 
         $source = $this->objectManager->create(
-            '\Magento\ImportExport\Model\Import\Source\Csv',
+            \Magento\ImportExport\Model\Import\Source\Csv::class,
             [
                 'file' => __DIR__ . '/_files/products_to_import_with_datetime.csv',
                 'directory' => $directory
@@ -384,7 +380,7 @@ class ProductTest extends \Magento\TestFramework\Indexer\TestCase
 
             /** @var $productAfterImport \Magento\Catalog\Model\Product */
             $productAfterImport = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
-                'Magento\Catalog\Model\Product'
+                \Magento\Catalog\Model\Product::class
             );
             $productAfterImport->load($productBeforeImport->getId());
             $this->assertEquals(
@@ -564,14 +560,13 @@ class ProductTest extends \Magento\TestFramework\Indexer\TestCase
      */
     public function testSaveMediaImage()
     {
-        $this->markTestSkipped('Test must be unskiped after implementation MAGETWO-47449');
         $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
         $filesystem = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()
-            ->create('Magento\Framework\Filesystem');
+            ->create(\Magento\Framework\Filesystem::class);
         $directory = $filesystem->getDirectoryWrite(DirectoryList::ROOT);
 
         $source = $this->objectManager->create(
-            '\Magento\ImportExport\Model\Import\Source\Csv',
+            \Magento\ImportExport\Model\Import\Source\Csv::class,
             [
                 'file' => __DIR__ . '/_files/import_media.csv',
                 'directory' => $directory
@@ -584,7 +579,10 @@ class ProductTest extends \Magento\TestFramework\Indexer\TestCase
                 'import_images_file_dir' => 'pub/media/import'
             ]
         );
-        $appParams = \Magento\TestFramework\Helper\Bootstrap::getInstance()->getBootstrap()->getApplication()->getInitParams()[Bootstrap::INIT_PARAM_FILESYSTEM_DIR_PATHS];
+        $appParams = \Magento\TestFramework\Helper\Bootstrap::getInstance()
+            ->getBootstrap()
+            ->getApplication()
+            ->getInitParams()[Bootstrap::INIT_PARAM_FILESYSTEM_DIR_PATHS];
         $uploader = $this->_model->getUploader();
 
         $destDir = $directory->getRelativePath($appParams[DirectoryList::MEDIA][DirectoryList::PATH] . '/catalog/product');
@@ -599,21 +597,22 @@ class ProductTest extends \Magento\TestFramework\Indexer\TestCase
 
         $this->assertTrue($errors->getErrorsCount() == 0);
         $this->_model->importData();
+        $this->assertTrue($this->_model->getErrorAggregator()->getErrorsCount() == 0);
 
-        $resource = $objectManager->get('Magento\Catalog\Model\ResourceModel\Product');
+        $resource = $objectManager->get(\Magento\Catalog\Model\ResourceModel\Product::class);
         $productId = $resource->getIdBySku('simple_new');
 
         $product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
-            'Magento\Catalog\Model\Product'
+            \Magento\Catalog\Model\Product::class
         );
         $product->load($productId);
         $this->assertEquals('/m/a/magento_image.jpg', $product->getData('swatch_image'));
         $gallery = $product->getMediaGalleryImages();
-        $this->assertInstanceOf('Magento\Framework\Data\Collection', $gallery);
+        $this->assertInstanceOf(\Magento\Framework\Data\Collection::class, $gallery);
         $items = $gallery->getItems();
         $this->assertCount(1, $items);
         $item = array_pop($items);
-        $this->assertInstanceOf('Magento\Framework\DataObject', $item);
+        $this->assertInstanceOf(\Magento\Framework\DataObject::class, $item);
         $this->assertEquals('/m/a/magento_image.jpg', $item->getFile());
         $this->assertEquals('Image Label', $item->getLabel());
     }
@@ -625,7 +624,7 @@ class ProductTest extends \Magento\TestFramework\Indexer\TestCase
     {
         /** @var \Magento\Framework\Filesystem\Directory\Write $mediaDirectory */
         $mediaDirectory = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get(
-            'Magento\Framework\Filesystem'
+            \Magento\Framework\Filesystem::class
         )->getDirectoryWrite(
             DirectoryList::MEDIA
         );
@@ -641,7 +640,7 @@ class ProductTest extends \Magento\TestFramework\Indexer\TestCase
     {
         /** @var \Magento\Framework\Filesystem\Directory\Write $mediaDirectory */
         $mediaDirectory = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get(
-            'Magento\Framework\Filesystem'
+            \Magento\Framework\Filesystem::class
         )->getDirectoryWrite(
             DirectoryList::MEDIA
         );
@@ -685,15 +684,14 @@ class ProductTest extends \Magento\TestFramework\Indexer\TestCase
      */
     public function testInvalidSkuLink()
     {
-        $this->markTestSkipped('Test must be unskiped after implementation MAGETWO-47449');
         // import data from CSV file
         $pathToFile = __DIR__ . '/_files/products_to_import_invalid_attribute_set.csv';
         $filesystem = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
-            'Magento\Framework\Filesystem'
+            \Magento\Framework\Filesystem::class
         );
         $directory = $filesystem->getDirectoryWrite(DirectoryList::ROOT);
         $source = $this->objectManager->create(
-            '\Magento\ImportExport\Model\Import\Source\Csv',
+            \Magento\ImportExport\Model\Import\Source\Csv::class,
             [
                 'file' => $pathToFile,
                 'directory' => $directory
@@ -716,7 +714,7 @@ class ProductTest extends \Magento\TestFramework\Indexer\TestCase
         $this->_model->importData();
 
         $productCollection = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
-            'Magento\Catalog\Model\ResourceModel\Product\Collection'
+            \Magento\Catalog\Model\ResourceModel\Product\Collection::class
         );
 
         $products = [];
@@ -736,11 +734,11 @@ class ProductTest extends \Magento\TestFramework\Indexer\TestCase
     public function testValidateInvalidMultiselectValues()
     {
         $filesystem = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
-            'Magento\Framework\Filesystem'
+            \Magento\Framework\Filesystem::class
         );
         $directory = $filesystem->getDirectoryWrite(DirectoryList::ROOT);
         $source = $this->objectManager->create(
-            '\Magento\ImportExport\Model\Import\Source\Csv',
+            \Magento\ImportExport\Model\Import\Source\Csv::class,
             [
                 'file' => __DIR__ . '/_files/products_with_invalid_multiselect_values.csv',
                 'directory' => $directory
@@ -771,13 +769,12 @@ class ProductTest extends \Magento\TestFramework\Indexer\TestCase
      */
     public function testProductsWithMultipleStores()
     {
-        $this->markTestSkipped('Test must be unskiped after implementation MAGETWO-47449');
         $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
 
-        $filesystem = $objectManager->create('Magento\Framework\Filesystem');
+        $filesystem = $objectManager->create(\Magento\Framework\Filesystem::class);
         $directory = $filesystem->getDirectoryWrite(DirectoryList::ROOT);
         $source = $this->objectManager->create(
-            '\Magento\ImportExport\Model\Import\Source\Csv',
+            \Magento\ImportExport\Model\Import\Source\Csv::class,
             [
                 'file' => __DIR__ . '/_files/products_multiple_stores.csv',
                 'directory' => $directory
@@ -799,10 +796,10 @@ class ProductTest extends \Magento\TestFramework\Indexer\TestCase
         $product->load($id);
         $this->assertEquals('1', $product->getHasOptions());
 
-        $objectManager->get('Magento\Store\Model\StoreManagerInterface')->setCurrentStore('fixturestore');
+        $objectManager->get(\Magento\Store\Model\StoreManagerInterface::class)->setCurrentStore('fixturestore');
 
         /** @var \Magento\Catalog\Model\Product $simpleProduct */
-        $simpleProduct = $objectManager->create('Magento\Catalog\Model\Product');
+        $simpleProduct = $objectManager->create(\Magento\Catalog\Model\Product::class);
         $id = $simpleProduct->getIdBySku('Configurable 03-Option 1');
         $simpleProduct->load($id);
         $this->assertTrue(count($simpleProduct->getWebsiteIds()) == 2);
@@ -817,12 +814,12 @@ class ProductTest extends \Magento\TestFramework\Indexer\TestCase
         // import data from CSV file
         $pathToFile = __DIR__ . '/_files/product_to_import_invalid_weight.csv';
         $filesystem = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
-            'Magento\Framework\Filesystem'
+            \Magento\Framework\Filesystem::class
         );
 
         $directory = $filesystem->getDirectoryWrite(DirectoryList::ROOT);
         $source = $this->objectManager->create(
-            '\Magento\ImportExport\Model\Import\Source\Csv',
+            \Magento\ImportExport\Model\Import\Source\Csv::class,
             [
                 'file' => $pathToFile,
                 'directory' => $directory
@@ -849,16 +846,15 @@ class ProductTest extends \Magento\TestFramework\Indexer\TestCase
      */
     public function testProductCategories($fixture, $separator)
     {
-        $this->markTestSkipped('Test must be unskiped after implementation MAGETWO-47449');
         // import data from CSV file
         $pathToFile = __DIR__ . '/_files/' . $fixture;
         $filesystem = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
-            'Magento\Framework\Filesystem'
+            \Magento\Framework\Filesystem::class
         );
 
         $directory = $filesystem->getDirectoryWrite(DirectoryList::ROOT);
         $source = $this->objectManager->create(
-            '\Magento\ImportExport\Model\Import\Source\Csv',
+            \Magento\ImportExport\Model\Import\Source\Csv::class,
             [
                 'file' => $pathToFile,
                 'directory' => $directory
@@ -878,12 +874,12 @@ class ProductTest extends \Magento\TestFramework\Indexer\TestCase
         $this->_model->importData();
 
         $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
-        $resource = $objectManager->get('Magento\Catalog\Model\ResourceModel\Product');
+        $resource = $objectManager->get(\Magento\Catalog\Model\ResourceModel\Product::class);
         $productId = $resource->getIdBySku('simple1');
         $this->assertTrue(is_numeric($productId));
         /** @var \Magento\Catalog\Model\Product $product */
         $product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
-            'Magento\Catalog\Model\Product'
+            \Magento\Catalog\Model\Product::class
         );
         $product->load($productId);
         $this->assertFalse($product->isObjectNew());
@@ -910,17 +906,16 @@ class ProductTest extends \Magento\TestFramework\Indexer\TestCase
      */
     public function testProductDuplicateCategories()
     {
-        $this->markTestSkipped('Test must be unskiped after implementation MAGETWO-48871');
         $csvFixture = 'products_duplicate_category.csv';
         // import data from CSV file
         $pathToFile = __DIR__ . '/_files/' . $csvFixture;
         $filesystem = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
-            'Magento\Framework\Filesystem'
+            \Magento\Framework\Filesystem::class
         );
 
         $directory = $filesystem->getDirectoryWrite(DirectoryList::ROOT);
         $source = $this->objectManager->create(
-            '\Magento\ImportExport\Model\Import\Source\Csv',
+            \Magento\ImportExport\Model\Import\Source\Csv::class,
             [
                 'file' => $pathToFile,
                 'directory' => $directory
@@ -937,7 +932,7 @@ class ProductTest extends \Magento\TestFramework\Indexer\TestCase
 
         /** @var \Magento\Catalog\Model\Category $category */
         $category = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
-            'Magento\Catalog\Model\Category'
+            \Magento\Catalog\Model\Category::class
         );
 
         $category->setStoreId(1);
@@ -952,7 +947,7 @@ class ProductTest extends \Magento\TestFramework\Indexer\TestCase
         $this->_model->importData();
 
         $errorProcessor = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get(
-            'Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingErrorAggregator'
+            \Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingErrorAggregator::class
         );
         $errorCount = count($errorProcessor->getAllErrors());
 
@@ -966,7 +961,7 @@ class ProductTest extends \Magento\TestFramework\Indexer\TestCase
 
         /** @var \Magento\Catalog\Model\Product $product */
         $product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
-            'Magento\Catalog\Model\Product'
+            \Magento\Catalog\Model\Product::class
         );
         $product->load(1);
         $categories = $product->getCategoryIds();
@@ -976,7 +971,7 @@ class ProductTest extends \Magento\TestFramework\Indexer\TestCase
     protected function loadCategoryByName($categoryName)
     {
         /* @var \Magento\Catalog\Model\ResourceModel\Category\Collection $collection */
-        $collection = $this->objectManager->create('Magento\Catalog\Model\ResourceModel\Category\Collection');
+        $collection = $this->objectManager->create(\Magento\Catalog\Model\ResourceModel\Category\Collection::class);
         $collection->addNameToResult()->load();
         return $collection->getItemByColumnValue('name', $categoryName);
     }
@@ -991,12 +986,12 @@ class ProductTest extends \Magento\TestFramework\Indexer\TestCase
     public function testValidateUrlKeys($importFile, $errorsCount)
     {
         $filesystem = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
-            'Magento\Framework\Filesystem'
+            \Magento\Framework\Filesystem::class
         );
         $directory = $filesystem->getDirectoryWrite(DirectoryList::ROOT);
 
         $source = $this->objectManager->create(
-            '\Magento\ImportExport\Model\Import\Source\Csv',
+            \Magento\ImportExport\Model\Import\Source\Csv::class,
             [
                 'file' => __DIR__ . '/_files/' . $importFile,
                 'directory' => $directory
@@ -1038,12 +1033,12 @@ class ProductTest extends \Magento\TestFramework\Indexer\TestCase
     public function testValidateUrlKeysMultipleStores()
     {
         $filesystem = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
-            'Magento\Framework\Filesystem'
+            \Magento\Framework\Filesystem::class
         );
         $directory = $filesystem->getDirectoryWrite(DirectoryList::ROOT);
 
         $source = $this->objectManager->create(
-            '\Magento\ImportExport\Model\Import\Source\Csv',
+            \Magento\ImportExport\Model\Import\Source\Csv::class,
             [
                 'file' => __DIR__ . '/_files/products_to_check_valid_url_keys_multiple_stores.csv',
                 'directory' => $directory
diff --git a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/media_import_image.php b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/media_import_image.php
new file mode 100644
index 0000000000000000000000000000000000000000..0794f1fd9cd7488a1d8a4be4913450424b03dcd0
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/media_import_image.php
@@ -0,0 +1,15 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+/** @var \Magento\Framework\Filesystem\Directory\Write $mediaDirectory */
+$mediaDirectory = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get(
+    'Magento\Framework\Filesystem'
+)->getDirectoryWrite(
+    \Magento\Framework\App\Filesystem\DirectoryList::MEDIA
+);
+$mediaDirectory->create('import/m/a');
+$dirPath = $mediaDirectory->getAbsolutePath('import');
+copy(__DIR__ . '/../../../../../Magento/Catalog/_files/magento_image.jpg', "{$dirPath}/m/a/magento_image.jpg");
diff --git a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/media_import_image_rollback.php b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/media_import_image_rollback.php
new file mode 100644
index 0000000000000000000000000000000000000000..83aa6097cfe784d7b5fa9ec50f97312cc9e549a7
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/media_import_image_rollback.php
@@ -0,0 +1,14 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+/** @var \Magento\Framework\Filesystem\Directory\Write $mediaDirectory */
+$mediaDirectory = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get(
+    \Magento\Framework\Filesystem::class
+)->getDirectoryWrite(
+    \Magento\Framework\App\Filesystem\DirectoryList::MEDIA
+);
+$mediaDirectory->delete('import');
+$mediaDirectory->delete('catalog');
diff --git a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/ProductTest.php b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/ProductTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..e5e543732942f3acbcb851df63f857a5379e553b
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/ProductTest.php
@@ -0,0 +1,140 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\CatalogImportExport\Model;
+
+/**
+ * @magentoDataFixtureBeforeTransaction Magento/Catalog/_files/enable_reindex_schedule.php
+ */
+class ProductTest extends AbstractProductExportImportTestCase
+{
+    /**
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+     */
+    public function exportImportDataProvider()
+    {
+        return [
+            'product_export_data' => [
+                [
+                    'Magento/CatalogImportExport/_files/product_export_data.php'
+                ],
+                [
+                    'simple_ms_1',
+                    'simple_ms_2',
+                    'simple',
+                ]
+            ],
+            // @todo uncomment after resolving MAGETWO-49677
+            /*
+            'custom-design-simple-product' => [
+                [
+                    'Magento/Catalog/_files/products.php'
+                ],
+                [
+                    'simple',
+                    'custom-design-simple-product',
+                ]
+            ],
+            */
+            'simple-product' => [
+                [
+                    'Magento/Catalog/_files/product_simple.php'
+                ],
+                [
+                    'simple',
+                ]
+            ],
+            'simple-product-multistore' => [
+                [
+                    'Magento/Catalog/_files/product_simple_multistore.php'
+                ],
+                [
+                    'simple',
+                ]
+            ],
+            'simple-product-xss' => [
+                [
+                    'Magento/Catalog/_files/product_simple_xss.php'
+                ],
+                [
+                    'product-with-xss',
+                ]
+            ],
+            'simple-product-special-price' => [
+                [
+                    'Magento/Catalog/_files/product_special_price.php'
+                ],
+                [
+                    'simple',
+                ]
+            ],
+            'virtual-product' => [
+                [
+                    'Magento/Catalog/_files/product_virtual_in_stock.php'
+                ],
+                [
+                    'virtual-product',
+                ]
+            ],
+            'simple-product-options' => [
+                [
+                    'Magento/Catalog/_files/product_with_options.php'
+                ],
+                [
+                    'simple',
+                ]
+            ],
+            'simple-product-dropdown' => [
+                [
+                    'Magento/Catalog/_files/product_with_dropdown_option.php'
+                ],
+                [
+                    'simple_dropdown_option',
+                ]
+            ],
+            'simple-product-image' => [
+                [
+                    'Magento/CatalogImportExport/Model/Import/_files/media_import_image.php',
+                    'Magento/Catalog/_files/product_with_image.php'
+                ],
+                [
+                    'simple',
+                ]
+            ],
+            // @todo uncomment after resolving MAGETWO-49676
+            /*
+            'simple-product-crosssell' => [
+                [
+                    'Magento/Catalog/_files/products_crosssell.php'
+                ],
+                [
+                    'simple',
+                ]
+            ],
+            'simple-product-related' => [
+                [
+                    'Magento/Catalog/_files/products_related_multiple.php'
+                ],
+                [
+                    'simple',
+                ]
+            ],
+            'simple-product-upsell' => [
+                [
+                    'Magento/Catalog/_files/products_upsell.php'
+                ],
+                [
+                    'simple',
+                ]
+            ],
+            */
+        ];
+    }
+
+    public function importReplaceDataProvider()
+    {
+        return $this->exportImportDataProvider();
+    }
+}
diff --git a/dev/tests/integration/testsuite/Magento/CatalogSearch/Model/Layer/Filter/CategoryTest.php b/dev/tests/integration/testsuite/Magento/CatalogSearch/Model/Layer/Filter/CategoryTest.php
index 52931492226fd0accba927552a97474c3d1adfe1..6f3ef297d0a57aa856327519d875addf5e339305 100644
--- a/dev/tests/integration/testsuite/Magento/CatalogSearch/Model/Layer/Filter/CategoryTest.php
+++ b/dev/tests/integration/testsuite/Magento/CatalogSearch/Model/Layer/Filter/CategoryTest.php
@@ -106,26 +106,31 @@ class CategoryTest extends \PHPUnit_Framework_TestCase
     {
         $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
         $request = $objectManager->get('Magento\TestFramework\Request');
-        $request->setParam('cat', 4);
+        $request->setParam('cat', 3);
         $this->_model->apply($request);
 
         /** @var $category \Magento\Catalog\Model\Category */
         $category = $objectManager->get('Magento\Framework\Registry')->registry(self::CURRENT_CATEGORY_FILTER);
         $this->assertInstanceOf('Magento\Catalog\Model\Category', $category);
-        $this->assertEquals(4, $category->getId());
+        $this->assertEquals(3, $category->getId());
 
         $items = $this->_model->getItems();
 
         $this->assertInternalType('array', $items);
-        $this->assertEquals(1, count($items));
+        $this->assertEquals(2, count($items));
 
         /** @var $item \Magento\Catalog\Model\Layer\Filter\Item */
         $item = $items[0];
-
         $this->assertInstanceOf('Magento\Catalog\Model\Layer\Filter\Item', $item);
         $this->assertSame($this->_model, $item->getFilter());
-        $this->assertEquals('Category 1.1.1', $item->getLabel());
-        $this->assertEquals(5, $item->getValue());
-        $this->assertEquals(1, $item->getCount());
+        $this->assertEquals('Category 1.1', $item->getLabel());
+        $this->assertEquals(4, $item->getValue());
+        $this->assertEquals(2, $item->getCount());
+
+        $item = $items[1];
+        $this->assertInstanceOf('Magento\Catalog\Model\Layer\Filter\Item', $item);
+        $this->assertEquals('Category 1.2', $item->getLabel());
+        $this->assertEquals(13, $item->getValue());
+        $this->assertEquals(2, $item->getCount());
     }
 }
diff --git a/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/Plugin/Catalog/Block/Adminhtml/Category/Tab/AttributesTest.php b/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/Plugin/Catalog/Block/Adminhtml/Category/Tab/AttributesTest.php
index 86754a471fd4b1504fbb7c1b43389a12a2da32c4..27d196bb59e7b40058ea30f28bc05aa4eff59fcb 100644
--- a/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/Plugin/Catalog/Block/Adminhtml/Category/Tab/AttributesTest.php
+++ b/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/Plugin/Catalog/Block/Adminhtml/Category/Tab/AttributesTest.php
@@ -46,12 +46,13 @@ class AttributesTest extends \PHPUnit_Framework_TestCase
      */
     public function testGetAttributesMeta()
     {
-        $meta = $this->dataProvider->getAttributesMeta($this->entityType);
-        $this->assertArrayHasKey('url_key', $meta);
-        $this->assertEquals('text', $meta['url_key']['dataType']);
-        $this->assertEquals('input', $meta['url_key']['formElement']);
-        $this->assertEquals('1', $meta['url_key']['visible']);
-        $this->assertEquals('0', $meta['url_key']['required']);
-        $this->assertEquals('[STORE VIEW]', $meta['url_key']['scope_label']);
+        $meta = $this->dataProvider->getMeta();
+        $this->assertArrayHasKey('url_key', $meta['search_engine_optimization']['children']);
+        $urlKeyData = $meta['search_engine_optimization']['children']['url_key']['arguments']['data']['config'];
+        $this->assertEquals('text', $urlKeyData['dataType']);
+        $this->assertEquals('input', $urlKeyData['formElement']);
+        $this->assertEquals('1', $urlKeyData['visible']);
+        $this->assertEquals('0', $urlKeyData['required']);
+        $this->assertEquals('[STORE VIEW]', $urlKeyData['scopeLabel']);
     }
 }
diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableImportExport/Model/ConfigurableTest.php b/dev/tests/integration/testsuite/Magento/ConfigurableImportExport/Model/ConfigurableTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..71e13517e128197645b305b5c6c9eefadba6b1af
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/ConfigurableImportExport/Model/ConfigurableTest.php
@@ -0,0 +1,100 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\ConfigurableImportExport\Model;
+
+use Magento\CatalogImportExport\Model\AbstractProductExportImportTestCase;
+
+class ConfigurableTest extends AbstractProductExportImportTestCase
+{
+    public function exportImportDataProvider()
+    {
+        return [
+            'configurable-product' => [
+                [
+                    'Magento/ConfigurableProduct/_files/product_configurable.php'
+                ],
+                [
+                    'configurable',
+                ],
+                ['_cache_instance_products', '_cache_instance_configurable_attributes'],
+            ],
+        ];
+    }
+
+    /**
+     * @param \Magento\Catalog\Model\Product $expectedProduct
+     * @param \Magento\Catalog\Model\Product $actualProduct
+     */
+    protected function assertEqualsSpecificAttributes($expectedProduct, $actualProduct)
+    {
+        $expectedAssociatedProducts = $expectedProduct->getTypeInstance()->getUsedProducts($expectedProduct);
+        $actualAssociatedProducts = $actualProduct->getTypeInstance()->getUsedProducts($actualProduct);
+
+        $expectedAssociatedProductSkus = [];
+        $actualAssociatedProductSkus = [];
+        $i = 0;
+        foreach ($expectedAssociatedProducts as $associatedProduct) {
+            $expectedAssociatedProductSkus[] = $associatedProduct->getSku();
+            $actualAssociatedProductSkus[] = $actualAssociatedProducts[$i]->getSku();
+            $i++;
+        }
+
+        sort($expectedAssociatedProductSkus);
+        sort($actualAssociatedProductSkus);
+
+        $this->assertEquals($expectedAssociatedProductSkus, $actualAssociatedProductSkus);
+
+        $expectedProductExtensionAttributes = $expectedProduct->getExtensionAttributes();
+        $actualProductExtensionAttributes = $actualProduct->getExtensionAttributes();
+
+        $this->assertEquals(
+            count($expectedProductExtensionAttributes->getConfigurableProductLinks()),
+            count($actualProductExtensionAttributes->getConfigurableProductLinks())
+        );
+
+        $expectedConfigurableProductOptions = $expectedProductExtensionAttributes->getConfigurableProductOptions();
+        $actualConfigurableProductOptions = $actualProductExtensionAttributes->getConfigurableProductOptions();
+
+        $this->assertEquals(count($expectedConfigurableProductOptions), count($actualConfigurableProductOptions));
+
+        $expectedConfigurableProductOptionsToCompare = [];
+        foreach ($expectedConfigurableProductOptions as $expectedConfigurableProductOption) {
+            foreach ($expectedConfigurableProductOption->getOptions() as $optionValue) {
+                $expectedConfigurableProductOptionsToCompare[$expectedConfigurableProductOption->getLabel()][]
+                    = $optionValue['label'];
+            }
+        }
+
+        $actualConfigurableProductOptionsToCompare = [];
+        foreach ($actualConfigurableProductOptions as $actualConfigurableProductOption) {
+            foreach ($actualConfigurableProductOption->getOptions() as $optionValue) {
+                $actualConfigurableProductOptionsToCompare[$actualConfigurableProductOption->getLabel()][]
+                    = $optionValue['label'];
+            }
+        }
+
+        $this->assertEquals(
+            count($expectedConfigurableProductOptionsToCompare),
+            count($actualConfigurableProductOptionsToCompare)
+        );
+
+        foreach ($expectedConfigurableProductOptionsToCompare as $key => $expectedOptionValues) {
+            $actualOptionValues = $actualConfigurableProductOptionsToCompare[$key];
+            sort($expectedOptionValues);
+            sort($actualOptionValues);
+            $this->assertEquals($expectedOptionValues, $actualOptionValues);
+        }
+    }
+
+    public function importReplaceDataProvider()
+    {
+        $data = $this->exportImportDataProvider();
+        foreach ($data as $key => $value) {
+            $data[$key][2] = array_merge($value[2], ['_cache_instance_product_set_attributes']);
+        }
+        return $data;
+    }
+}
diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableImportExport/Model/Export/RowCustomizerTest.php b/dev/tests/integration/testsuite/Magento/ConfigurableImportExport/Model/Export/RowCustomizerTest.php
index 2ee583cbfc1bd268fa56949601f54887c1a6b5b9..9dc933734fd5ca8447851bb1097246738318867b 100644
--- a/dev/tests/integration/testsuite/Magento/ConfigurableImportExport/Model/Export/RowCustomizerTest.php
+++ b/dev/tests/integration/testsuite/Magento/ConfigurableImportExport/Model/Export/RowCustomizerTest.php
@@ -33,7 +33,6 @@ class RowCustomizerTest extends \PHPUnit_Framework_TestCase
      */
     public function testPrepareData()
     {
-        $this->markTestSkipped('Skipped till implementation MAGETWO-47395');
         $collection = $this->objectManager->get('Magento\Catalog\Model\ResourceModel\Product\Collection');
         $select = (string)$collection->getSelect();
         $this->model->prepareData($collection, [1, 2, 3, 4]);
diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableImportExport/Model/Import/Product/Type/ConfigurableTest.php b/dev/tests/integration/testsuite/Magento/ConfigurableImportExport/Model/Import/Product/Type/ConfigurableTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..5f510ff8f58d67dcf7068845e0f21726e605f59b
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/ConfigurableImportExport/Model/Import/Product/Type/ConfigurableTest.php
@@ -0,0 +1,147 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\ConfigurableImportExport\Model\Import\Product\Type;
+
+use Magento\Catalog\Api\ProductRepositoryInterface;
+use Magento\Framework\App\Bootstrap;
+use Magento\Framework\App\Filesystem\DirectoryList;
+use Magento\ImportExport\Model\Import;
+
+/**
+ * @magentoAppArea adminhtml
+ */
+class ConfigurableTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * Configurable product test Name
+     */
+    const TEST_PRODUCT_NAME = 'Configurable 1';
+
+    /**
+     * Configurable product test Type
+     */
+    const TEST_PRODUCT_TYPE = 'configurable';
+
+    /**
+     * @var \Magento\CatalogImportExport\Model\Import\Product
+     */
+    protected $model;
+
+    /**
+     * Configurable product options SKU list
+     *
+     * @var array
+     */
+    protected $optionSkuList = ['Configurable 1-Option 1', 'Configurable 1-Option 2'];
+
+    /**
+     * @var \Magento\Framework\ObjectManagerInterface
+     */
+    protected $objectManager;
+
+    /**
+     * @var \Magento\Framework\Model\Entity\EntityMetadata
+     */
+    protected $productMetadata;
+
+    protected function setUp()
+    {
+        $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
+        $this->model = $this->objectManager->create(\Magento\CatalogImportExport\Model\Import\Product::class);
+        /** @var \Magento\Framework\Model\Entity\MetadataPool $metadataPool */
+        $metadataPool = $this->objectManager->get(\Magento\Framework\Model\Entity\MetadataPool::class);
+        $this->productMetadata = $metadataPool->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class);
+    }
+
+    /**
+     * @magentoDataFixture Magento/ConfigurableProduct/_files/configurable_attribute.php
+     * @magentoAppArea adminhtml
+     */
+    public function testConfigurableImport()
+    {
+        // import data from CSV file
+        $pathToFile = __DIR__ . '/../../_files/import_configurable.csv';
+        $filesystem = $this->objectManager->create(
+            \Magento\Framework\Filesystem::class
+        );
+
+        $directory = $filesystem->getDirectoryWrite(DirectoryList::ROOT);
+        $source = $this->objectManager->create(
+            \Magento\ImportExport\Model\Import\Source\Csv::class,
+            [
+                'file' => $pathToFile,
+                'directory' => $directory
+            ]
+        );
+        $errors = $this->model->setSource(
+            $source
+        )->setParameters(
+            [
+                'behavior' => \Magento\ImportExport\Model\Import::BEHAVIOR_APPEND,
+                'entity' => 'catalog_product'
+            ]
+        )->validateData();
+
+        $this->assertTrue($errors->getErrorsCount() == 0);
+        $this->model->importData();
+
+        /** @var \Magento\Catalog\Model\ResourceModel\Product $resource */
+        $resource = $this->objectManager->get(\Magento\Catalog\Model\ResourceModel\Product::class);
+        $productId = $resource->getIdBySku(self::TEST_PRODUCT_NAME);
+        $this->assertTrue(is_numeric($productId));
+        /** @var \Magento\Catalog\Model\Product $product */
+        $product = $this->objectManager->get(ProductRepositoryInterface::class)->getById($productId);
+
+        $this->assertFalse($product->isObjectNew());
+        $this->assertEquals(self::TEST_PRODUCT_NAME, $product->getName());
+        $this->assertEquals(self::TEST_PRODUCT_TYPE, $product->getTypeId());
+
+        $optionCollection = $product->getTypeInstance()->getConfigurableOptions($product);
+        foreach ($optionCollection as $option) {
+            foreach ($option as $optionData) {
+                $this->assertContains($optionData['sku'], $this->optionSkuList);
+            }
+        }
+
+        $optionIdList = $resource->getProductsIdsBySkus($this->optionSkuList);
+        foreach ($optionIdList as $optionId) {
+            $this->assertArrayHasKey($optionId, $product->getExtensionAttributes()->getConfigurableProductLinks());
+        }
+
+        $configurableOptionCollection = $product->getExtensionAttributes()->getConfigurableProductOptions();
+        $this->assertEquals(1, count($configurableOptionCollection));
+        foreach ($configurableOptionCollection as $option) {
+            $optionData = $option->getData();
+            $this->assertArrayHasKey('product_super_attribute_id', $optionData);
+            $this->assertArrayHasKey('product_id', $optionData);
+            $this->assertEquals($product->getData($this->productMetadata->getLinkField()), $optionData['product_id']);
+            $this->assertArrayHasKey('attribute_id', $optionData);
+            $this->assertArrayHasKey('position', $optionData);
+            $this->assertArrayHasKey('extension_attributes', $optionData);
+            $this->assertArrayHasKey('product_attribute', $optionData);
+            $productAttributeData = $optionData['product_attribute']->getData();
+            $this->assertArrayHasKey('attribute_id', $productAttributeData);
+            $this->assertArrayHasKey('entity_type_id', $productAttributeData);
+            $this->assertArrayHasKey('attribute_code', $productAttributeData);
+            $this->assertEquals('test_configurable', $productAttributeData['attribute_code']);
+            $this->assertArrayHasKey('frontend_label', $productAttributeData);
+            $this->assertEquals('Test Configurable', $productAttributeData['frontend_label']);
+            $this->assertArrayHasKey('label', $optionData);
+            $this->assertEquals('test_configurable', $optionData['label']);
+            $this->assertArrayHasKey('use_default', $optionData);
+            $this->assertArrayHasKey('options', $optionData);
+            $this->assertEquals('Option 1', $optionData['options'][0]['label']);
+            $this->assertEquals('Option 1', $optionData['options'][0]['default_label']);
+            $this->assertEquals('Option 1', $optionData['options'][0]['store_label']);
+            $this->assertEquals('Option 2', $optionData['options'][1]['label']);
+            $this->assertEquals('Option 2', $optionData['options'][1]['default_label']);
+            $this->assertEquals('Option 2', $optionData['options'][1]['store_label']);
+            $this->assertArrayHasKey('values', $optionData);
+            $valuesData = $optionData['values'];
+            $this->assertEquals(2, count($valuesData));
+        }
+    }
+}
diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableImportExport/Model/Import/_files/import_configurable.csv b/dev/tests/integration/testsuite/Magento/ConfigurableImportExport/Model/Import/_files/import_configurable.csv
new file mode 100644
index 0000000000000000000000000000000000000000..54bb07125c58c6ddceddf3a443e75cb1ef4d7c0b
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/ConfigurableImportExport/Model/Import/_files/import_configurable.csv
@@ -0,0 +1,4 @@
+sku,store_view_code,attribute_set_code,product_type,name,description,short_description,weight,product_online,tax_class_name,visibility,price,url_key,display_product_options_in,map_price,additional_attributes,qty,out_of_stock_qty,use_config_min_qty,is_qty_decimal,allow_backorders,use_config_backorders,min_cart_qty,use_config_min_sale_qty,max_cart_qty,use_config_max_sale_qty,is_in_stock,notify_on_stock_below,use_config_notify_stock_qty,manage_stock,use_config_manage_stock,use_config_qty_increments,qty_increments,use_config_enable_qty_inc,enable_qty_increments,is_decimal_divided,website_id,configurable_variations,configurable_variation_labels,associated_skus
+Configurable 1-Option 1,,Default,simple,Configurable 1-Option 1,,,,1,Taxable Goods,Not Visible Individually,10,configurable-1-option-1,Block after Info Column,,"attribute_with_option=Option Label,has_options=0,quantity_and_stock_status=In Stock,required_options=0,test_configurable=Option 1",99999,0,0,0,0,1,1,0,0,0,1,,1,1,0,0,1,0,0,0,1,,,
+Configurable 1-Option 2,,Default,simple,Configurable 1-Option 2,,,,1,Taxable Goods,Not Visible Individually,10,configurable-1-option-2,Block after Info Column,,"has_options=0,quantity_and_stock_status=In Stock,required_options=0,test_configurable=Option 2",99999,0,0,0,0,1,1,0,0,0,1,,1,1,0,0,1,0,0,0,1,,,
+Configurable 1,,Default,configurable,Configurable 1,,,,1,Taxable Goods,"Catalog, Search",10,configurable-1,Block after Info Column,,"has_options=1,quantity_and_stock_status=In Stock,required_options=0",0,0,0,0,0,1,1,0,0,0,1,,1,0,0,0,1,0,0,0,1,"sku=Configurable 1-Option 1,test_configurable=Option 1|sku=Configurable 1-Option 2,test_configurable=Option 2",test_configurable=test_configurable,
diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/Product/Type/ConfigurableTest.php b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/Product/Type/ConfigurableTest.php
index a20c3e7b9ab0e4d38fa9482a01b39f7ed23fe29c..6dfe109ee431fbba639abac20418575395e029ad 100644
--- a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/Product/Type/ConfigurableTest.php
+++ b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/Product/Type/ConfigurableTest.php
@@ -128,7 +128,7 @@ class ConfigurableTest extends \PHPUnit_Framework_TestCase
         $attributeId = (int)$testConfigurable->getId();
         $attributes = $this->model->getUsedProductAttributes($this->product);
         $this->assertArrayHasKey($attributeId, $attributes);
-        $this->assertSame($testConfigurable, $attributes[$attributeId]);
+        $this->assertEquals($testConfigurable->getData(), $attributes[$attributeId]->getData());
     }
 
     public function testGetConfigurableAttributes()
diff --git a/dev/tests/integration/testsuite/Magento/DownloadableImportExport/Model/DownloadableTest.php b/dev/tests/integration/testsuite/Magento/DownloadableImportExport/Model/DownloadableTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..ffdb5ebd59bd5d146f7abb0088af68cacaeed7f6
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/DownloadableImportExport/Model/DownloadableTest.php
@@ -0,0 +1,114 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\DownloadableImportExport\Model;
+
+use Magento\CatalogImportExport\Model\AbstractProductExportImportTestCase;
+
+class DownloadableTest extends AbstractProductExportImportTestCase
+{
+    public function exportImportDataProvider()
+    {
+        return [
+            'downloadable-product' => [
+                [
+                    'Magento/Downloadable/_files/product_downloadable.php'
+                ],
+                [
+                    'downloadable-product',
+                ],
+            ],
+            'downloadable-product-with-files' => [
+                [
+                    'Magento/Downloadable/_files/product_downloadable_with_files.php'
+                ],
+                [
+                    'downloadable-product',
+                ],
+            ],
+        ];
+    }
+
+    public function importReplaceDataProvider()
+    {
+        return $this->exportImportDataProvider();
+    }
+
+    /**
+     * @param array $fixtures
+     * @param string[] $skus
+     * @param string[] $skippedAttributes
+     * @dataProvider exportImportDataProvider
+     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+     *
+     * @todo remove after MAGETWO-49467 resolved
+     */
+    public function testExport($fixtures, $skus, $skippedAttributes = [], $rollbackFixtures = [])
+    {
+        $this->markTestSkipped('Uncomment after MAGETWO-49467 resolved');
+    }
+
+    /**
+     * @param array $fixtures
+     * @param string[] $skus
+     * @dataProvider exportImportDataProvider
+     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+     *
+     * @todo remove after MAGETWO-49467 resolved
+     */
+    public function testImportDelete($fixtures, $skus, $skippedAttributes = [], $rollbackFixtures = [])
+    {
+        $this->markTestSkipped('Uncomment after MAGETWO-49467 resolved');
+    }
+
+    /**
+     * @magentoAppArea adminhtml
+     * @magentoDbIsolation enabled
+     * @magentoAppIsolation enabled
+     *
+     * @param array $fixtures
+     * @param string[] $skus
+     * @param string[] $skippedAttributes
+     * @dataProvider importReplaceDataProvider
+     *
+     * @todo remove after MAGETWO-49467 resolved
+     */
+    public function testImportReplace($fixtures, $skus, $skippedAttributes = [], $rollbackFixtures = [])
+    {
+        $this->markTestSkipped('Uncomment after MAGETWO-49467 resolved');
+    }
+
+    /**
+     * @param \Magento\Catalog\Model\Product $expectedProduct
+     * @param \Magento\Catalog\Model\Product $actualProduct
+     */
+    protected function assertEqualsSpecificAttributes($expectedProduct, $actualProduct)
+    {
+        $expectedProductLinks   = $expectedProduct->getExtensionAttributes()->getDownloadableProductLinks();
+        $expectedProductSamples = $expectedProduct->getExtensionAttributes()->getDownloadableProductSamples();
+
+        $actualProductLinks   = $actualProduct->getExtensionAttributes()->getDownloadableProductLinks();
+        $actualProductSamples = $actualProduct->getExtensionAttributes()->getDownloadableProductSamples();
+
+        $this->assertEquals(count($expectedProductLinks), count($actualProductLinks));
+        $this->assertEquals(count($expectedProductSamples), count($actualProductSamples));
+
+        $expectedLinksArray = [];
+        foreach ($expectedProductLinks as $link) {
+            $expectedLinksArray[] = $link->getData();
+        }
+        foreach ($actualProductLinks as $actualLink) {
+            $this->assertContains($expectedLinksArray, $actualLink->getData());
+        }
+
+        $expectedSamplesArray = [];
+        foreach ($expectedProductSamples as $sample) {
+            $expectedSamplesArray[] = $sample->getData();
+        }
+        foreach ($actualProductSamples as $actualSample) {
+            $this->assertContains($expectedSamplesArray, $actualSample->getData());
+        }
+    }
+}
diff --git a/dev/tests/integration/testsuite/Magento/DownloadableImportExport/Model/Import/Product/Type/DownloadableTest.php b/dev/tests/integration/testsuite/Magento/DownloadableImportExport/Model/Import/Product/Type/DownloadableTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..3a6d8166c9bc25e6a48be346b0a36012a5405880
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/DownloadableImportExport/Model/Import/Product/Type/DownloadableTest.php
@@ -0,0 +1,191 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\DownloadableImportExport\Model\Import\Product\Type;
+
+use Magento\Framework\App\Bootstrap;
+use Magento\Framework\App\Filesystem\DirectoryList;
+use Magento\ImportExport\Model\Import;
+
+/**
+ * @magentoAppArea adminhtml
+ */
+class DownloadableTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * Downloadable product test Name
+     */
+    const TEST_PRODUCT_NAME = 'Downloadable 1';
+
+    /**
+     * Downloadable product test Type
+     */
+    const TEST_PRODUCT_TYPE = 'downloadable';
+
+    /**
+     * Downloadable product Links Group Name
+     */
+    const TEST_PRODUCT_LINKS_GROUP_NAME = 'TEST Import Links';
+
+    /**
+     * Downloadable product Samples Group Name
+     */
+    const TEST_PRODUCT_SAMPLES_GROUP_NAME = 'TEST Import Samples';
+
+    /**
+     * @var \Magento\CatalogImportExport\Model\Import\Product
+     */
+    protected $model;
+
+    /**
+     * @var \Magento\Framework\ObjectManagerInterface
+     */
+    protected $objectManager;
+
+    /**
+     * @var \Magento\Framework\Model\Entity\EntityMetadata
+     */
+    protected $productMetadata;
+
+    protected function setUp()
+    {
+        $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
+        $this->model = $this->objectManager->create(
+            \Magento\CatalogImportExport\Model\Import\Product::class
+        );
+        /** @var \Magento\Framework\Model\Entity\MetadataPool $metadataPool */
+        $metadataPool = $this->objectManager->get(\Magento\Framework\Model\Entity\MetadataPool::class);
+        $this->productMetadata = $metadataPool->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class);
+    }
+
+    /**
+     * @magentoAppArea adminhtml
+     * @magentoDbIsolation enabled
+     * @magentoAppIsolation enabled
+     *
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+     */
+    public function testDownloadableImport()
+    {
+        // import data from CSV file
+        $pathToFile = __DIR__ . '/../../_files/import_downloadable.csv';
+        $filesystem = $this->objectManager->create(
+            \Magento\Framework\Filesystem::class
+        );
+
+        $directory = $filesystem->getDirectoryWrite(DirectoryList::ROOT);
+        $source = $this->objectManager->create(
+            \Magento\ImportExport\Model\Import\Source\Csv::class,
+            [
+                'file' => $pathToFile,
+                'directory' => $directory
+            ]
+        );
+        $errors = $this->model->setSource(
+            $source
+        )->setParameters(
+            [
+                'behavior' => \Magento\ImportExport\Model\Import::BEHAVIOR_APPEND,
+                'entity' => 'catalog_product'
+            ]
+        )->validateData();
+
+        $this->assertTrue($errors->getErrorsCount() == 0);
+        $this->model->importData();
+
+        $resource = $this->objectManager->get(\Magento\Catalog\Model\ResourceModel\Product::class);
+        $productId = $resource->getIdBySku(self::TEST_PRODUCT_NAME);
+        $this->assertTrue(is_numeric($productId));
+        /** @var \Magento\Catalog\Model\Product $product */
+        $product = $this->objectManager->create(
+            \Magento\Catalog\Model\Product::class
+        );
+        $product->load($productId);
+
+        $this->assertFalse($product->isObjectNew());
+        $this->assertEquals(self::TEST_PRODUCT_NAME, $product->getName());
+        $this->assertEquals(self::TEST_PRODUCT_TYPE, $product->getTypeId());
+
+        $downloadableProductLinks   = $product->getExtensionAttributes()->getDownloadableProductLinks();
+        $downloadableLinks          = $product->getDownloadableLinks();
+        $downloadableProductSamples = $product->getExtensionAttributes()->getDownloadableProductSamples();
+        $downloadableSamples        = $product->getDownloadableSamples();
+
+        //TODO: Track Fields: id, link_id, link_file and sample_file)
+        $expectedLinks= [
+            'file' => [
+                'title' => 'TEST Import Link Title File',
+                'sort_order' => '78',
+                'sample_type' => 'file',
+                'price' => '123.0000',
+                'number_of_downloads' => '123',
+                'is_shareable' => '0',
+                'link_type' => 'file'
+            ],
+            'url'  => [
+                'title' => 'TEST Import Link Title URL',
+                'sort_order' => '42',
+                'sample_type' => 'url',
+                'sample_url' => 'http://www.bing.com',
+                'price' => '1.0000',
+                'number_of_downloads' => '0',
+                'is_shareable' => '1',
+                'link_type' => 'url',
+                'link_url' => 'http://www.google.com'
+            ]
+        ];
+        foreach ($downloadableProductLinks as $link) {
+            $actualLink = $link->getData();
+            $this->assertArrayHasKey('link_type', $actualLink);
+            foreach ($expectedLinks[$actualLink['link_type']] as $expectedKey => $expectedValue) {
+                $this->assertArrayHasKey($expectedKey, $actualLink);
+                $this->assertEquals($actualLink[$expectedKey], $expectedValue);
+            }
+        }
+        foreach ($downloadableLinks as $link) {
+            $actualLink = $link->getData();
+            $this->assertArrayHasKey('link_type', $actualLink);
+            $this->assertArrayHasKey('product_id', $actualLink);
+            $this->assertEquals($actualLink['product_id'], $product->getData($this->productMetadata->getLinkField()));
+            foreach ($expectedLinks[$actualLink['link_type']] as $expectedKey => $expectedValue) {
+                $this->assertArrayHasKey($expectedKey, $actualLink);
+                $this->assertEquals($actualLink[$expectedKey], $expectedValue);
+            }
+        }
+
+        //TODO: Track Fields: id, sample_id and sample_file)
+        $expectedSamples= [
+            'file' => [
+                'title' => 'TEST Import Sample File',
+                'sort_order' => '178',
+                'sample_type' => 'file'
+            ],
+            'url'  => [
+                'title' => 'TEST Import Sample URL',
+                 'sort_order' => '178',
+                 'sample_type' => 'url',
+                 'sample_url' => 'http://www.yahoo.com'
+            ]
+        ];
+        foreach ($downloadableProductSamples as $sample) {
+            $actualSample = $sample->getData();
+            $this->assertArrayHasKey('sample_type', $actualSample);
+            foreach ($expectedSamples[$actualSample['sample_type']] as $expectedKey => $expectedValue) {
+                $this->assertArrayHasKey($expectedKey, $actualSample);
+                $this->assertEquals($actualSample[$expectedKey], $expectedValue);
+            }
+        }
+        foreach ($downloadableSamples as $sample) {
+            $actualSample = $sample->getData();
+            $this->assertArrayHasKey('sample_type', $actualSample);
+            $this->assertArrayHasKey('product_id', $actualSample);
+            $this->assertEquals($actualSample['product_id'], $product->getData($this->productMetadata->getLinkField()));
+            foreach ($expectedSamples[$actualSample['sample_type']] as $expectedKey => $expectedValue) {
+                $this->assertArrayHasKey($expectedKey, $actualSample);
+                $this->assertEquals($actualSample[$expectedKey], $expectedValue);
+            }
+        }
+    }
+}
diff --git a/dev/tests/integration/testsuite/Magento/DownloadableImportExport/Model/Import/_files/import_downloadable.csv b/dev/tests/integration/testsuite/Magento/DownloadableImportExport/Model/Import/_files/import_downloadable.csv
new file mode 100644
index 0000000000000000000000000000000000000000..0f668fc0f6dd1bc8c827f0aca84b39eab19f539d
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/DownloadableImportExport/Model/Import/_files/import_downloadable.csv
@@ -0,0 +1,2 @@
+sku,attribute_set_code,product_type,product_websites,name,product_online,tax_class_name,visibility,price,url_key,out_of_stock_qty,use_config_min_qty,is_qty_decimal,allow_backorders,use_config_backorders,min_cart_qty,use_config_min_sale_qty,max_cart_qty,use_config_max_sale_qty,is_in_stock,notify_on_stock_below,use_config_notify_stock_qty,manage_stock,use_config_manage_stock,use_config_qty_increments,qty_increments,use_config_enable_qty_inc,enable_qty_increments,is_decimal_divided,website_id,downloadable_links,downloadable_samples
+Downloadable 1,Default,downloadable,base,Downloadable 1,1,Taxable Goods,"Catalog, Search",100,downloadable-1,0,1,0,0,1,1,1,10000,1,0,1,1,1,1,1,1,0,0,0,1,"group_title=TEST Import Links,sample=/i/m/p/o/r/t/sample1.jpg,downloads=123,sortorder=78,shareable=0,file=/i/m/p/o/r/t/file.jpg,price=123,title=TEST Import Link Title File|group_title=TEST Import Links,sample=http://www.bing.com,downloads=unlimited,sortorder=42,shareable=1,url=http://www.google.com,price=1,title=TEST Import Link Title URL","group_title=TEST Import Samples,sortorder=178,file=/i/m/p/o/r/t/sample2.jpg,title=TEST Import Sample File|group_title=TEST Import Samples,sortorder=178,url=http://www.yahoo.com,title=TEST Import Sample URL"
diff --git a/dev/tests/integration/testsuite/Magento/Framework/Code/_expected/SourceClassWithNamespaceProxy.php.sample b/dev/tests/integration/testsuite/Magento/Framework/Code/_expected/SourceClassWithNamespaceProxy.php.sample
index 9074f2a8e0926e210c42a3853daff74537e5d237..af5b2e39078ab5f2fb77f2269e3db905cd8ce3e3 100644
--- a/dev/tests/integration/testsuite/Magento/Framework/Code/_expected/SourceClassWithNamespaceProxy.php.sample
+++ b/dev/tests/integration/testsuite/Magento/Framework/Code/_expected/SourceClassWithNamespaceProxy.php.sample
@@ -56,7 +56,7 @@ class Proxy extends \Magento\Framework\Code\GeneratorTest\SourceClassWithNamespa
      */
     public function __sleep()
     {
-        return array('_subject', '_isShared');
+        return ['_subject', '_isShared', '_instanceName'];
     }
 
     /**
diff --git a/dev/tests/integration/testsuite/Magento/GroupedImportExport/Model/GroupedTest.php b/dev/tests/integration/testsuite/Magento/GroupedImportExport/Model/GroupedTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..f0eebf405c978f8f4df245419ef9ef1ea99a9867
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/GroupedImportExport/Model/GroupedTest.php
@@ -0,0 +1,51 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\GroupedImportExport\Model;
+
+use Magento\CatalogImportExport\Model\AbstractProductExportImportTestCase;
+
+class GroupedTest extends AbstractProductExportImportTestCase
+{
+    public function exportImportDataProvider()
+    {
+        return [
+            'grouped-product' => [
+                [
+                    'Magento/GroupedProduct/_files/product_grouped.php'
+                ],
+                [
+                    'grouped-product',
+                ],
+            ],
+        ];
+    }
+
+    public function importReplaceDataProvider()
+    {
+        return $this->exportImportDataProvider();
+    }
+
+    /**
+     * @param \Magento\Catalog\Model\Product $expectedProduct
+     * @param \Magento\Catalog\Model\Product $actualProduct
+     */
+    protected function assertEqualsSpecificAttributes($expectedProduct, $actualProduct)
+    {
+        $expectedAssociatedProducts = $expectedProduct->getTypeInstance()->getAssociatedProducts($expectedProduct);
+        $actualAssociatedProducts = $actualProduct->getTypeInstance()->getAssociatedProducts($actualProduct);
+
+        $expectedAssociatedProductSkus = [];
+        $actualAssociatedProductSkus = [];
+        $i = 0;
+        foreach ($expectedAssociatedProducts as $associatedProduct) {
+            $expectedAssociatedProductSkus[] = $associatedProduct->getSku();
+            $actualAssociatedProductSkus[] = $actualAssociatedProducts[$i]->getSku();
+            $i++;
+        }
+
+        $this->assertEquals($expectedAssociatedProductSkus, $actualAssociatedProductSkus);
+    }
+}
diff --git a/dev/tests/integration/testsuite/Magento/GroupedImportExport/Model/Import/Product/Type/GroupedTest.php b/dev/tests/integration/testsuite/Magento/GroupedImportExport/Model/Import/Product/Type/GroupedTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..ca11fd61e592418e5f98e63f5b426ac9e5cef7e6
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/GroupedImportExport/Model/Import/Product/Type/GroupedTest.php
@@ -0,0 +1,94 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\GroupedImportExport\Model\Import\Product\Type;
+
+use Magento\Framework\App\Filesystem\DirectoryList;
+use Magento\ImportExport\Model\Import;
+
+class GroupedTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * Configurable product test Name
+     */
+    const TEST_PRODUCT_NAME = 'Test Grouped';
+
+    /**
+     * Configurable product test Type
+     */
+    const TEST_PRODUCT_TYPE = 'grouped';
+
+    /**
+     * @var \Magento\CatalogImportExport\Model\Import\Product
+     */
+    protected $model;
+
+    /**
+     * @var \Magento\Framework\ObjectManagerInterface
+     */
+    protected $objectManager;
+
+    /**
+     * Grouped product options SKU list
+     *
+     * @var array
+     */
+    protected $optionSkuList = ['Simple for Grouped 1', 'Simple for Grouped 2'];
+
+    protected function setUp()
+    {
+        $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
+        $this->model = $this->objectManager->create(\Magento\CatalogImportExport\Model\Import\Product::class);
+    }
+
+    /**
+     * @magentoAppArea adminhtml
+     * @magentoDbIsolation enabled
+     * @magentoAppIsolation enabled
+     */
+    public function testImport()
+    {
+        // Import data from CSV file
+        $pathToFile = __DIR__ . '/../../_files/grouped_product.csv';
+        $filesystem = $this->objectManager->create(\Magento\Framework\Filesystem::class);
+
+        $directory = $filesystem->getDirectoryWrite(DirectoryList::ROOT);
+        $source = $this->objectManager->create(
+            \Magento\ImportExport\Model\Import\Source\Csv::class,
+            [
+                'file' => $pathToFile,
+                'directory' => $directory
+            ]
+        );
+        $errors = $this->model->setSource(
+            $source
+        )->setParameters(
+            [
+                'behavior' => \Magento\ImportExport\Model\Import::BEHAVIOR_APPEND,
+                'entity' => 'catalog_product'
+            ]
+        )->validateData();
+
+        $this->assertTrue($errors->getErrorsCount() == 0);
+        $this->model->importData();
+
+        $resource = $this->objectManager->get(\Magento\Catalog\Model\ResourceModel\Product::class);
+        $productId = $resource->getIdBySku('Test Grouped');
+        $this->assertTrue(is_numeric($productId));
+        /** @var \Magento\Catalog\Model\Product $product */
+        $product = $this->objectManager->create(\Magento\Catalog\Model\Product::class);
+        $product->load($productId);
+
+        $this->assertFalse($product->isObjectNew());
+        $this->assertEquals(self::TEST_PRODUCT_NAME, $product->getName());
+        $this->assertEquals(self::TEST_PRODUCT_TYPE, $product->getTypeId());
+
+        $childProductCollection = $product->getTypeInstance()->getAssociatedProducts($product);
+
+        foreach ($childProductCollection as $childProduct) {
+            $this->assertContains($childProduct->getSku(), $this->optionSkuList);
+        }
+    }
+}
diff --git a/dev/tests/integration/testsuite/Magento/GroupedImportExport/Model/Import/_files/grouped_product.csv b/dev/tests/integration/testsuite/Magento/GroupedImportExport/Model/Import/_files/grouped_product.csv
new file mode 100644
index 0000000000000000000000000000000000000000..e9bd2df040fe5bde7daf757a5bb6c425c8519205
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/GroupedImportExport/Model/Import/_files/grouped_product.csv
@@ -0,0 +1,4 @@
+sku,store_view_code,attribute_set_code,product_type,categories,product_websites,name,description,short_description,weight,product_online,tax_class_name,visibility,price,special_price,special_price_from_date,special_price_to_date,url_key,meta_title,meta_keywords,meta_description,base_image,base_image_label,small_image,small_image_label,thumbnail_image,thumbnail_image_label,swatch_image,swatch_image_label,created_at,updated_at,new_from_date,new_to_date,display_product_options_in,map_price,msrp_price,map_enabled,gift_message_available,custom_design,custom_design_from,custom_design_to,custom_layout_update,page_layout,product_options_container,msrp_display_actual_price_type,country_of_manufacture,additional_attributes,qty,out_of_stock_qty,use_config_min_qty,is_qty_decimal,allow_backorders,use_config_backorders,min_cart_qty,use_config_min_sale_qty,max_cart_qty,use_config_max_sale_qty,is_in_stock,notify_on_stock_below,use_config_notify_stock_qty,manage_stock,use_config_manage_stock,use_config_qty_increments,qty_increments,use_config_enable_qty_inc,enable_qty_increments,is_decimal_divided,website_id,related_skus,crosssell_skus,upsell_skus,additional_images,additional_image_labels,hide_from_product_page,bundle_price_type,bundle_sku_type,bundle_price_view,bundle_weight_type,bundle_values,associated_skus
+"Test Grouped",,Default,grouped,,base,"Test Grouped",,,,1,,"Catalog, Search",,,,,test-grouped,"Test Grouped","Test Grouped","Test Grouped ",,,,,,,,,"2/16/16, 2:57 PM","2/16/16, 3:03 PM",,,"Block after Info Column",,,,,,,,,,,,,,0.0000,0.0000,0,0,0,1,1.0000,0,0.0000,0,1,,1,1,0,0,0.0000,0,0,0,1,,,,,,,,,,,,"Simple for Grouped 1=0.0000,Simple for Grouped 2=0.0000"
+"Simple for Grouped 1",,Default,simple,,base,"Simple for Grouped 1",,,5.0000,1,"Taxable Goods","Catalog, Search",10.0000,,,,simple-for-grouped-1,"Simple for Grouped 1","Simple for Grouped 1","Simple for Grouped 1",,,,,,,,,"2/16/16, 2:57 PM","2/16/16, 2:57 PM",,,"Block after Info Column",,,,,,,,,,,"Use config",,,100.0000,0.0000,0,0,0,1,1.0000,0,0.0000,0,1,1.0000,0,1,0,0,0.0000,0,0,0,1,,,,,,,,,,,,
+"Simple for Grouped 2",,Default,simple,,base,"Simple for Grouped 2",,,5.0000,1,"Taxable Goods","Catalog, Search",10.0000,,,,simple-for-grouped-2,"Simple for Grouped 2","Simple for Grouped 2","Simple for Grouped 2 ",,,,,,,,,"2/16/16, 3:03 PM","2/16/16, 3:03 PM",,,"Block after Info Column",,,,,,,,,,,,,,100.0000,0.0000,1,0,0,1,1.0000,1,10000.0000,1,1,1.0000,1,1,1,1,1.0000,0,0,0,1,,,,,,,,,,,,
diff --git a/dev/tests/integration/testsuite/Magento/Indexer/Model/Config/_files/result.php b/dev/tests/integration/testsuite/Magento/Indexer/Model/Config/_files/result.php
index 1ea56303ff15adc9598ecf0ea79db47759362bc1..d5f78c11a2effd085aed52958696c3f63412ef54 100644
--- a/dev/tests/integration/testsuite/Magento/Indexer/Model/Config/_files/result.php
+++ b/dev/tests/integration/testsuite/Magento/Indexer/Model/Config/_files/result.php
@@ -8,6 +8,7 @@ return [
     'catalogsearch_fulltext' =>
         [
             'indexer_id' => 'catalogsearch_fulltext',
+            'shared_index' => null,
             'primary' => 'first',
             'view_id' => 'catalogsearch_fulltext',
             'action_class' => 'Magento\\CatalogSearch\\Model\\Indexer\\Fulltext',
diff --git a/dev/tests/integration/testsuite/Magento/Paypal/_files/quote_payment_express.php b/dev/tests/integration/testsuite/Magento/Paypal/_files/quote_payment_express.php
index be4608b73fd656b953ceb49221950e808ee336fa..19d117c855f42c849afb643d90fc5d96df236c00 100644
--- a/dev/tests/integration/testsuite/Magento/Paypal/_files/quote_payment_express.php
+++ b/dev/tests/integration/testsuite/Magento/Paypal/_files/quote_payment_express.php
@@ -26,12 +26,6 @@ $product->setTypeId('simple')
     ->setName('Simple Product')
     ->setSku('simple')
     ->setPrice(10)
-    ->setStockData([
-    'use_config_manage_stock' => 1,
-    'qty' => 100,
-    'is_qty_decimal' => 0,
-    'is_in_stock' => 100,
-])
     ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH)
     ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED)
     ->save();
diff --git a/dev/tests/integration/testsuite/Magento/Sales/_files/quote.php b/dev/tests/integration/testsuite/Magento/Sales/_files/quote.php
index c89043d6345db606a24d0f9f0878b495ba5b36dc..f265f82244f19787e9f483e4cef95822aec1aebf 100644
--- a/dev/tests/integration/testsuite/Magento/Sales/_files/quote.php
+++ b/dev/tests/integration/testsuite/Magento/Sales/_files/quote.php
@@ -12,7 +12,6 @@ $product->setTypeId('simple')
     ->setSku('simple')
     ->setPrice(10)
     ->setTaxClassId(0)
-    ->setStockData(['use_config_manage_stock' => 1, 'qty' => 100, 'is_qty_decimal' => 0, 'is_in_stock' => 1])
     ->setMetaTitle('meta title')
     ->setMetaKeyword('meta keyword')
     ->setMetaDescription('meta description')
diff --git a/dev/tests/integration/testsuite/Magento/Setup/Fixtures/FixtureModelTest.php b/dev/tests/integration/testsuite/Magento/Setup/Fixtures/FixtureModelTest.php
index dfadc074211f0ab170e506f240e72bbab377e180..57b314dd57ea19f50f14e4c294b5970c15fbdd78 100644
--- a/dev/tests/integration/testsuite/Magento/Setup/Fixtures/FixtureModelTest.php
+++ b/dev/tests/integration/testsuite/Magento/Setup/Fixtures/FixtureModelTest.php
@@ -49,10 +49,6 @@ class FixtureModelTest extends \Magento\TestFramework\Indexer\TestCase
         $model->initObjectManager();
 
         foreach ($model->loadFixtures()->getFixtures() as $fixture) {
-            //TODO: OrderFixture execution must be unskiped after implementation MAGETWO-47449
-            if ($fixture->getPriority() == '135') {
-                continue;
-            }
             $fixture->execute();
         }
     }
diff --git a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_classes.php b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_classes.php
index 4cc3eae2aaa25ced7cd7b327564af4b129385706..608e6cff33d0c112431cd0829bdcfc60cc34b6e4 100755
--- a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_classes.php
+++ b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_classes.php
@@ -4129,6 +4129,7 @@ return [
         'Magento\Catalog\Model\ResourceModel\Product\Attribute\Backend\Media',
         'Magento\Catalog\Model\ResourceModel\Product\Gallery'
     ],
+    ['Magento\CatalogInventory\Observer\AddStockStatusToCollectionObserver'],
     ['Magento\CatalogRule\Block\Adminhtml\Promo\Catalog\Edit\Tab\Actions'],
     ['Magento\CatalogRule\Block\Adminhtml\Promo\Catalog\Edit\Tab\Main'],
     ['Magento\CatalogRule\Block\Adminhtml\Promo\Catalog\Edit\Form'],
diff --git a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_namespaces.php b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_namespaces.php
index e3df67aef78f061032f8fd7a5885a885a728a502..49979f223099e0da80283e3c1695cbe6eef76906 100644
--- a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_namespaces.php
+++ b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_namespaces.php
@@ -75,7 +75,6 @@ return [
     ['Magento\Core\Model\Resource\Config', 'Magento\Config\Model\ResourceModel\Config'],
     ['Magento\Backend\Block\System\Config', 'Magento\Config\Block\System\Config'],
     ['Magento\Backend\Controller\Adminhtml\System\Config', 'Magento\Config\Controller\Adminhtml\System\Config'],
-    ['Magento\Backend\Model\Config', 'Magento\Config\Model\Config'],
     ['Magento\Core\Model\Variable', 'Magento\Variable\Model\Variable'],
     ['Magento\Catalog\Service'],
     ['Magento\CheckoutAgreements\Service'],
diff --git a/lib/internal/Magento/Framework/AclFactory.php b/lib/internal/Magento/Framework/AclFactory.php
index 3e9839830049d1ec5d384e673e67a64a1de0e866..a48000fbdd33c80c5de69a42c2329f7675c2f984 100644
--- a/lib/internal/Magento/Framework/AclFactory.php
+++ b/lib/internal/Magento/Framework/AclFactory.php
@@ -31,6 +31,6 @@ class AclFactory
      */
     public function create()
     {
-        return $this->_objectManager->create('Magento\Framework\Acl');
+        return $this->_objectManager->create(Acl::class);
     }
 }
diff --git a/lib/internal/Magento/Framework/App/Config/Value.php b/lib/internal/Magento/Framework/App/Config/Value.php
index 8489ffd5c5f28f50cf68aab8196445f9fc9971af..dc09a05efc9d776514ae82e143a60b6fb3b41851 100644
--- a/lib/internal/Magento/Framework/App/Config/Value.php
+++ b/lib/internal/Magento/Framework/App/Config/Value.php
@@ -122,4 +122,18 @@ class Value extends \Magento\Framework\Model\AbstractModel implements \Magento\F
 
         return parent::afterSave();
     }
+
+    /**
+     * {@inheritdoc}
+     *
+     * {@inheritdoc}. In addition, it sets status 'invalidate' for config caches
+     *
+     * @return $this
+     */
+    public function afterDelete()
+    {
+        $this->cacheTypeList->invalidate(\Magento\Framework\App\Cache\Type\Config::TYPE_IDENTIFIER);
+
+        return parent::afterDelete();
+    }
 }
diff --git a/lib/internal/Magento/Framework/App/PageCache/Cache.php b/lib/internal/Magento/Framework/App/PageCache/Cache.php
index 7cb801730b1fe34b1f2a1e395a6371151ef95b44..9e58ed64d2c0adc75e345d80fc0e77f5eb0ec5d5 100644
--- a/lib/internal/Magento/Framework/App/PageCache/Cache.php
+++ b/lib/internal/Magento/Framework/App/PageCache/Cache.php
@@ -7,11 +7,15 @@ namespace Magento\Framework\App\PageCache;
 
 /**
  * Cache model for builtin cache
+ *
+ * @deprecated
  */
 class Cache extends \Magento\Framework\App\Cache
 {
     /**
      * @var string
+     *
+     * @deprecated
      */
     protected $_frontendIdentifier = 'page_cache';
 }
diff --git a/lib/internal/Magento/Framework/App/PageCache/Kernel.php b/lib/internal/Magento/Framework/App/PageCache/Kernel.php
index b065336108b9a985dd090650500254d94f16a03c..587e8100b5f97f35a20d1c933f0b92da945fe5d2 100644
--- a/lib/internal/Magento/Framework/App/PageCache/Kernel.php
+++ b/lib/internal/Magento/Framework/App/PageCache/Kernel.php
@@ -5,13 +5,17 @@
  */
 namespace Magento\Framework\App\PageCache;
 
+use Magento\Framework\App\ObjectManager;
+
 /**
  * Builtin cache processor
  */
 class Kernel
 {
     /**
-     * @var Cache
+     * @var \Magento\PageCache\Model\Cache\Type
+     *
+     * @deprecated
      */
     protected $cache;
 
@@ -25,6 +29,11 @@ class Kernel
      */
     protected $request;
 
+    /**
+     * @var \Magento\PageCache\Model\Cache\Type
+     */
+    private $fullPageCache;
+
     /**
      * @param Cache $cache
      * @param Identifier $identifier
@@ -48,7 +57,7 @@ class Kernel
     public function load()
     {
         if ($this->request->isGet() || $this->request->isHead()) {
-            return unserialize($this->cache->load($this->identifier->getValue()));
+            return unserialize($this->getCache()->load($this->identifier->getValue()));
         }
         return false;
     }
@@ -75,8 +84,21 @@ class Kernel
                 if (!headers_sent()) {
                     header_remove('Set-Cookie');
                 }
-                $this->cache->save(serialize($response), $this->identifier->getValue(), $tags, $maxAge);
+                $this->getCache()->save(serialize($response), $this->identifier->getValue(), $tags, $maxAge);
             }
         }
     }
+
+    /**
+     * TODO: Workaround to support backwards compatibility, will rework to use Dependency Injection in MAGETWO-49547
+     *
+     * @return \Magento\PageCache\Model\Cache\Type
+     */
+    private function getCache()
+    {
+        if (!$this->fullPageCache) {
+            $this->fullPageCache = ObjectManager::getInstance()->get('\Magento\PageCache\Model\Cache\Type');
+        }
+        return $this->fullPageCache;
+    }
 }
diff --git a/lib/internal/Magento/Framework/App/Test/Unit/Config/ValueTest.php b/lib/internal/Magento/Framework/App/Test/Unit/Config/ValueTest.php
index 175509af622a025d5b05b879e227f763cd3a3f56..be5dccf9920f83bfed4403f482bcda53579b8006 100644
--- a/lib/internal/Magento/Framework/App/Test/Unit/Config/ValueTest.php
+++ b/lib/internal/Magento/Framework/App/Test/Unit/Config/ValueTest.php
@@ -191,4 +191,13 @@ class ValueTest extends \PHPUnit_Framework_TestCase
             [1, 'other_value'],
         ];
     }
+
+    /**
+     * @return void;
+     */
+    public function testAfterDelete()
+    {
+        $this->cacheTypeListMock->expects($this->once())->method('invalidate');
+        $this->assertInstanceOf(get_class($this->model), $this->model->afterDelete());
+    }
 }
diff --git a/lib/internal/Magento/Framework/App/Test/Unit/PageCache/KernelTest.php b/lib/internal/Magento/Framework/App/Test/Unit/PageCache/KernelTest.php
index 1028112e36aefb5e92a9d62af8bf126caa6d5121..070223bf8ff3b6d2578db75b9baad8871a138d4d 100644
--- a/lib/internal/Magento/Framework/App/Test/Unit/PageCache/KernelTest.php
+++ b/lib/internal/Magento/Framework/App/Test/Unit/PageCache/KernelTest.php
@@ -9,41 +9,41 @@ use \Magento\Framework\App\PageCache\Kernel;
 
 class KernelTest extends \PHPUnit_Framework_TestCase
 {
-    /**
-     * @var Kernel
-     */
+    /** @var Kernel */
     protected $kernel;
 
-    /**
-     * @var \Magento\Framework\App\PageCache\Cache|\PHPUnit_Framework_MockObject_MockObject
-     */
+    /** @var \Magento\Framework\App\PageCache\Cache|\PHPUnit_Framework_MockObject_MockObject */
     protected $cacheMock;
 
-    /**
-     * @var \Magento\Framework\App\PageCache\Identifier|\PHPUnit_Framework_MockObject_MockObject
-     */
+    /** @var \Magento\Framework\App\PageCache\Identifier|\PHPUnit_Framework_MockObject_MockObject */
     protected $identifierMock;
 
-    /**
-     * @var \Magento\Framework\App\Request\Http|\PHPUnit_Framework_MockObject_MockObject
-     */
+    /** @var \Magento\Framework\App\Request\Http|\PHPUnit_Framework_MockObject_MockObject */
     protected $requestMock;
 
-    /**
-     * @var \Magento\Framework\App\Response\Http|\PHPUnit_Framework_MockObject_MockObject
-     */
+    /** @var \Magento\Framework\App\Response\Http|\PHPUnit_Framework_MockObject_MockObject */
     protected $responseMock;
 
+    /** @var  \PHPUnit_Framework_MockObject_MockObject|\Magento\PageCache\Model\Cache\Type */
+    private $fullPageCacheMock;
+
     /**
      * Setup
      */
     public function setUp()
     {
         $this->cacheMock = $this->getMock('Magento\Framework\App\PageCache\Cache', [], [], '', false);
+        $this->fullPageCacheMock = $this->getMock('\Magento\PageCache\Model\Cache\Type', [], [], '', false);
         $this->identifierMock =
             $this->getMock('Magento\Framework\App\PageCache\Identifier', [], [], '', false);
         $this->requestMock = $this->getMock('Magento\Framework\App\Request\Http', [], [], '', false);
         $this->kernel = new Kernel($this->cacheMock, $this->identifierMock, $this->requestMock);
+
+        $reflection = new \ReflectionClass('\Magento\Framework\App\PageCache\Kernel');
+        $reflectionProperty = $reflection->getProperty('fullPageCache');
+        $reflectionProperty->setAccessible(true);
+        $reflectionProperty->setValue($this->kernel, $this->fullPageCacheMock);
+
         $this->responseMock = $this->getMockBuilder(
             'Magento\Framework\App\Response\Http'
         )->setMethods(
@@ -63,7 +63,7 @@ class KernelTest extends \PHPUnit_Framework_TestCase
     {
         $this->requestMock->expects($this->once())->method('isGet')->will($this->returnValue($isGet));
         $this->requestMock->expects($this->any())->method('isHead')->will($this->returnValue($isHead));
-        $this->cacheMock->expects(
+        $this->fullPageCacheMock->expects(
             $this->any()
         )->method(
             'load'
@@ -136,7 +136,7 @@ class KernelTest extends \PHPUnit_Framework_TestCase
         $this->responseMock->expects($this->at($at[2]))
             ->method('clearHeader')
             ->with($this->equalTo('X-Magento-Tags'));
-        $this->cacheMock->expects($this->once())
+        $this->fullPageCacheMock->expects($this->once())
             ->method('save');
         $this->kernel->process($this->responseMock);
     }
@@ -173,7 +173,7 @@ class KernelTest extends \PHPUnit_Framework_TestCase
         if ($overrideHeaders) {
             $this->responseMock->expects($this->once())->method('setNoCacheHeaders');
         }
-        $this->cacheMock->expects($this->never())->method('save');
+        $this->fullPageCacheMock->expects($this->never())->method('save');
         $this->kernel->process($this->responseMock);
     }
 
diff --git a/lib/internal/Magento/Framework/Cache/Backend/Database.php b/lib/internal/Magento/Framework/Cache/Backend/Database.php
index f02c9975ab4b87fc73b6fde8180a3a082a08e8c2..4ed3a7be309e6ec5fb1c67ea14aa0a3eb6d16ef8 100644
--- a/lib/internal/Magento/Framework/Cache/Backend/Database.php
+++ b/lib/internal/Magento/Framework/Cache/Backend/Database.php
@@ -48,6 +48,7 @@ class Database extends \Zend_Cache_Backend implements \Zend_Cache_Backend_Extend
         'tags_table' => '',
         'tags_table_callback' => '',
         'store_data' => true,
+        'infinite_loop_flag' => false,
     ];
 
     /**
@@ -145,13 +146,16 @@ class Database extends \Zend_Cache_Backend implements \Zend_Cache_Backend_Extend
      */
     public function load($id, $doNotTestCacheValidity = false)
     {
-        if ($this->_options['store_data']) {
+        if ($this->_options['store_data'] && !$this->_options['infinite_loop_flag']) {
+            $this->_options['infinite_loop_flag'] = true;
             $select = $this->_getConnection()->select()->from($this->_getDataTable(), 'data')->where('id=:cache_id');
 
             if (!$doNotTestCacheValidity) {
                 $select->where('expire_time=0 OR expire_time>?', time());
             }
-            return $this->_getConnection()->fetchOne($select, ['cache_id' => $id]);
+            $result = $this->_getConnection()->fetchOne($select, ['cache_id' => $id]);
+            $this->_options['infinite_loop_flag'] = false;
+            return $result;
         } else {
             return false;
         }
@@ -165,7 +169,8 @@ class Database extends \Zend_Cache_Backend implements \Zend_Cache_Backend_Extend
      */
     public function test($id)
     {
-        if ($this->_options['store_data']) {
+        if ($this->_options['store_data'] && !$this->_options['infinite_loop_flag']) {
+            $this->_options['infinite_loop_flag'] = true;
             $select = $this->_getConnection()->select()->from(
                 $this->_getDataTable(),
                 'update_time'
@@ -175,7 +180,9 @@ class Database extends \Zend_Cache_Backend implements \Zend_Cache_Backend_Extend
                 'expire_time=0 OR expire_time>?',
                 time()
             );
-            return $this->_getConnection()->fetchOne($select, ['cache_id' => $id]);
+            $result = $this->_getConnection()->fetchOne($select, ['cache_id' => $id]);
+            $this->_options['infinite_loop_flag'] = false;
+            return $result;
         } else {
             return false;
         }
@@ -195,17 +202,21 @@ class Database extends \Zend_Cache_Backend implements \Zend_Cache_Backend_Extend
      */
     public function save($data, $id, $tags = [], $specificLifetime = false)
     {
-        if ($this->_options['store_data']) {
-            $connection = $this->_getConnection();
-            $dataTable = $this->_getDataTable();
+        $result = false;
+        if (!$this->_options['infinite_loop_flag']) {
+            $this->_options['infinite_loop_flag'] = true;
+            $result = true;
+            if ($this->_options['store_data']) {
+                $connection = $this->_getConnection();
+                $dataTable = $this->_getDataTable();
 
-            $lifetime = $this->getLifetime($specificLifetime);
-            $time = time();
-            $expire = $lifetime === 0 || $lifetime === null ? 0 : $time + $lifetime;
+                $lifetime = $this->getLifetime($specificLifetime);
+                $time = time();
+                $expire = $lifetime === 0 || $lifetime === null ? 0 : $time + $lifetime;
 
-            $dataCol = $connection->quoteIdentifier('data');
-            $expireCol = $connection->quoteIdentifier('expire_time');
-            $query = "INSERT INTO {$dataTable} (\n                    {$connection->quoteIdentifier(
+                $dataCol = $connection->quoteIdentifier('data');
+                $expireCol = $connection->quoteIdentifier('expire_time');
+                $query = "INSERT INTO {$dataTable} (\n                    {$connection->quoteIdentifier(
                 'id'
             )},\n                    {$dataCol},\n                    {$connection->quoteIdentifier(
                 'create_time'
@@ -213,13 +224,14 @@ class Database extends \Zend_Cache_Backend implements \Zend_Cache_Backend_Extend
                 'update_time'
             )},\n                    {$expireCol})\n                VALUES (?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE\n                    {$dataCol}=VALUES({$dataCol}),\n                    {$expireCol}=VALUES({$expireCol})";
 
-            $result = $connection->query($query, [$id, $data, $time, $time, $expire])->rowCount();
-            if (!$result) {
-                return false;
+                $result = $connection->query($query, [$id, $data, $time, $time, $expire])->rowCount();
             }
+            if ($result) {
+                $result = $this->_saveTags($id, $tags);
+            }
+            $this->_options['infinite_loop_flag'] = false;
         }
-        $tagRes = $this->_saveTags($id, $tags);
-        return $tagRes;
+        return $result;
     }
 
     /**
@@ -230,8 +242,11 @@ class Database extends \Zend_Cache_Backend implements \Zend_Cache_Backend_Extend
      */
     public function remove($id)
     {
-        if ($this->_options['store_data']) {
-            return $this->_getConnection()->delete($this->_getDataTable(), ['id=?' => $id]);
+        if ($this->_options['store_data'] && !$this->_options['infinite_loop_flag']) {
+            $this->_options['infinite_loop_flag'] = true;
+            $result = $this->_getConnection()->delete($this->_getDataTable(), ['id=?' => $id]);
+            $this->_options['infinite_loop_flag'] = false;
+            return $result;
         }
         return false;
     }
@@ -255,34 +270,26 @@ class Database extends \Zend_Cache_Backend implements \Zend_Cache_Backend_Extend
      */
     public function clean($mode = \Zend_Cache::CLEANING_MODE_ALL, $tags = [])
     {
-        $connection = $this->_getConnection();
-        switch ($mode) {
-            case \Zend_Cache::CLEANING_MODE_ALL:
-                if ($this->_options['store_data']) {
-                    $result = $connection->query('TRUNCATE TABLE ' . $this->_getDataTable());
-                } else {
-                    $result = true;
-                }
-                $result = $result && $connection->query('TRUNCATE TABLE ' . $this->_getTagsTable());
-                break;
-            case \Zend_Cache::CLEANING_MODE_OLD:
-                if ($this->_options['store_data']) {
-                    $result = $connection->delete(
-                        $this->_getDataTable(),
-                        ['expire_time> ?' => 0, 'expire_time<= ?' => time()]
-                    );
-                } else {
-                    $result = true;
-                }
-                break;
-            case \Zend_Cache::CLEANING_MODE_MATCHING_TAG:
-            case \Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG:
-            case \Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG:
-                $result = $this->_cleanByTags($mode, $tags);
-                break;
-            default:
-                \Zend_Cache::throwException('Invalid mode for clean() method');
-                break;
+        if (!$this->_options['infinite_loop_flag']) {
+            $this->_options['infinite_loop_flag'] = true;
+            $connection = $this->_getConnection();
+            switch ($mode) {
+                case \Zend_Cache::CLEANING_MODE_ALL:
+                    $result = $this->cleanAll($connection);
+                    break;
+                case \Zend_Cache::CLEANING_MODE_OLD:
+                    $result = $this->cleanOld($connection);
+                    break;
+                case \Zend_Cache::CLEANING_MODE_MATCHING_TAG:
+                case \Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG:
+                case \Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG:
+                    $result = $this->_cleanByTags($mode, $tags);
+                    break;
+                default:
+                    \Zend_Cache::throwException('Invalid mode for clean() method');
+                    break;
+            }
+            $this->_options['infinite_loop_flag'] = false;
         }
 
         return $result;
@@ -543,4 +550,41 @@ class Database extends \Zend_Cache_Backend implements \Zend_Cache_Backend_Extend
             return true;
         }
     }
+
+    /**
+     * Clean all cache entries
+     *
+     * @param $connection
+     * @return bool
+     */
+    private function cleanAll($connection)
+    {
+        if ($this->_options['store_data']) {
+            $result = $connection->query('TRUNCATE TABLE ' . $this->_getDataTable());
+        } else {
+            $result = true;
+        }
+        $result = $result && $connection->query('TRUNCATE TABLE ' . $this->_getTagsTable());
+        return $result;
+    }
+
+    /**
+     * Clean old cache entries
+     *
+     * @param $connection
+     * @return bool
+     */
+    private function cleanOld($connection)
+    {
+        if ($this->_options['store_data']) {
+            $result = $connection->delete(
+                $this->_getDataTable(),
+                ['expire_time> ?' => 0, 'expire_time<= ?' => time()]
+            );
+            return $result;
+        } else {
+            $result = true;
+            return $result;
+        }
+    }
 }
diff --git a/lib/internal/Magento/Framework/Code/Generator.php b/lib/internal/Magento/Framework/Code/Generator.php
index 92057208769f736643f05e8913ea973e8ec66f1f..f88025212b797910095b4f6f1f3631633d2401f5 100644
--- a/lib/internal/Magento/Framework/Code/Generator.php
+++ b/lib/internal/Magento/Framework/Code/Generator.php
@@ -81,7 +81,7 @@ class Generator
      *
      * @param string $className
      * @return string | void
-     * @throws \Magento\Framework\Exception\LocalizedException
+     * @throws \RuntimeException
      * @throws \InvalidArgumentException
      */
     public function generateClass($className)
@@ -112,9 +112,7 @@ class Generator
             $this->tryToLoadSourceClass($className, $generator);
             if (!($file = $generator->generate())) {
                 $errors = $generator->getErrors();
-                throw new \Magento\Framework\Exception\LocalizedException(
-                    new \Magento\Framework\Phrase(implode(' ', $errors))
-                );
+                throw new \RuntimeException(implode(' ', $errors));
             }
             if (!$this->definedClasses->isClassLoadableFromMemory($className)) {
                 $this->_ioObject->includeFile($file);
@@ -173,19 +171,18 @@ class Generator
      * @param string $className
      * @param \Magento\Framework\Code\Generator\EntityAbstract $generator
      * @return void
-     * @throws \Magento\Framework\Exception\LocalizedException
+     * @throws \RuntimeException
      */
     protected function tryToLoadSourceClass($className, $generator)
     {
         $sourceClassName = $generator->getSourceClassName();
         if (!$this->definedClasses->isClassLoadable($sourceClassName)) {
             if ($this->generateClass($sourceClassName) !== self::GENERATION_SUCCESS) {
-                throw new \Magento\Framework\Exception\LocalizedException(
-                    new \Magento\Framework\Phrase(
-                        'Source class "%1" for "%2" generation does not exist.',
-                        [$sourceClassName, $className]
-                    )
+                $phrase = new \Magento\Framework\Phrase(
+                    'Source class "%1" for "%2" generation does not exist.',
+                    [$sourceClassName, $className]
                 );
+                throw new \RuntimeException($phrase->__toString());
             }
         }
     }
diff --git a/lib/internal/Magento/Framework/Code/Test/Unit/GeneratorTest.php b/lib/internal/Magento/Framework/Code/Test/Unit/GeneratorTest.php
index c289ba47967435ded674df11cc9af595e280909e..afcf1072e874ccae04ec001d6e5a0e0ea49d6e1c 100644
--- a/lib/internal/Magento/Framework/Code/Test/Unit/GeneratorTest.php
+++ b/lib/internal/Magento/Framework/Code/Test/Unit/GeneratorTest.php
@@ -71,7 +71,7 @@ class GeneratorTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * @expectedException \Magento\Framework\Exception\LocalizedException
+     * @expectedException \RuntimeException
      * @dataProvider generateValidClassDataProvider
      */
     public function testGenerateClass($className, $entityType)
@@ -95,7 +95,7 @@ class GeneratorTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * @expectedException \Magento\Framework\Exception\LocalizedException
+     * @expectedException \RuntimeException
      */
     public function testGenerateClassWithError()
     {
diff --git a/lib/internal/Magento/Framework/Component/ComponentRegistrar.php b/lib/internal/Magento/Framework/Component/ComponentRegistrar.php
index 44258c7f135ce0e122f3a63d6f0fe1fd26737fe4..fd122da9985ee9fee355113bf59c5a00ac373ae7 100644
--- a/lib/internal/Magento/Framework/Component/ComponentRegistrar.php
+++ b/lib/internal/Magento/Framework/Component/ComponentRegistrar.php
@@ -46,7 +46,10 @@ class ComponentRegistrar implements ComponentRegistrarInterface
     {
         self::validateType($type);
         if (isset(self::$paths[$type][$componentName])) {
-            throw new \LogicException('\'' . $componentName . '\' component already exists');
+            throw new \LogicException(
+                ucfirst($type) . ' \'' . $componentName . '\' from \'' . $path . '\' '
+                . 'has been already defined in \'' . self::$paths[$type][$componentName] . '\'.'
+            );
         } else {
             self::$paths[$type][$componentName] = str_replace('\\', '/', $path);
         }
diff --git a/lib/internal/Magento/Framework/Component/Test/Unit/ComponentRegistrarTest.php b/lib/internal/Magento/Framework/Component/Test/Unit/ComponentRegistrarTest.php
index db7fa8f35e8c5eafdf6f7a797654a8947483c832..93f6983ce237aaaae81d22ce5a044ca356c55057 100644
--- a/lib/internal/Magento/Framework/Component/Test/Unit/ComponentRegistrarTest.php
+++ b/lib/internal/Magento/Framework/Component/Test/Unit/ComponentRegistrarTest.php
@@ -45,11 +45,11 @@ class ComponentRegistrarTest extends \PHPUnit_Framework_TestCase
 
     /**
      * @expectedException \LogicException
-     * @expectedExceptionMessage 'test_module_one' component already exists
+     * @expectedExceptionMessageRegExp /Module 'test_module_one' from '\w+' has been already defined in '\w+'./
      */
     public function testRegistrarWithExceptionForModules()
     {
-        ComponentRegistrar::register(ComponentRegistrar::MODULE, "test_module_one", "some/path/name/one");
+        ComponentRegistrar::register(ComponentRegistrar::MODULE, "test_module_one", "some/path/name/onemore");
     }
 
     public function testGetPath()
diff --git a/lib/internal/Magento/Framework/Controller/ResultFactory.php b/lib/internal/Magento/Framework/Controller/ResultFactory.php
index db78cf29c63014d7102ef03cabd1378fd6ee828d..1543368a9dd82985428f002efac6a01ae5f255f6 100644
--- a/lib/internal/Magento/Framework/Controller/ResultFactory.php
+++ b/lib/internal/Magento/Framework/Controller/ResultFactory.php
@@ -30,12 +30,12 @@ class ResultFactory
      * @var array
      */
     protected $typeMap = [
-        self::TYPE_JSON     => 'Magento\Framework\Controller\Result\Json',
-        self::TYPE_RAW      => 'Magento\Framework\Controller\Result\Raw',
-        self::TYPE_REDIRECT => 'Magento\Framework\Controller\Result\Redirect',
-        self::TYPE_FORWARD  => 'Magento\Framework\Controller\Result\Forward',
-        self::TYPE_LAYOUT   => 'Magento\Framework\View\Result\Layout',
-        self::TYPE_PAGE     => 'Magento\Framework\View\Result\Page',
+        self::TYPE_JSON     => Result\Json::class,
+        self::TYPE_RAW      => Result\Raw::class,
+        self::TYPE_REDIRECT => Result\Redirect::class,
+        self::TYPE_FORWARD  => Result\Forward::class,
+        self::TYPE_LAYOUT   => \Magento\Framework\View\Result\Layout::class,
+        self::TYPE_PAGE     => \Magento\Framework\View\Result\Page::class,
     ];
 
     /**
diff --git a/lib/internal/Magento/Framework/CurrencyFactory.php b/lib/internal/Magento/Framework/CurrencyFactory.php
index a1a126aecd1f99f568e00437842cd9e652184fb6..1f87858182d0e3b2fb2e94cddb4c50f24c7d9691 100644
--- a/lib/internal/Magento/Framework/CurrencyFactory.php
+++ b/lib/internal/Magento/Framework/CurrencyFactory.php
@@ -11,7 +11,7 @@ namespace Magento\Framework;
 class CurrencyFactory
 {
     /**
-     * @var \Magento\Framework\ObjectManagerInterface
+     * @var ObjectManagerInterface
      */
     protected $_objectManager = null;
 
@@ -21,10 +21,10 @@ class CurrencyFactory
     protected $_instanceName = null;
 
     /**
-     * @param \Magento\Framework\ObjectManagerInterface $objectManager
+     * @param ObjectManagerInterface $objectManager
      * @param string $instanceName
      */
-    public function __construct(\Magento\Framework\ObjectManagerInterface $objectManager, $instanceName = 'Magento\Framework\CurrencyInterface')
+    public function __construct(ObjectManagerInterface $objectManager, $instanceName = CurrencyInterface::class)
     {
         $this->_objectManager = $objectManager;
         $this->_instanceName = $instanceName;
@@ -34,7 +34,7 @@ class CurrencyFactory
      * Create class instance with specified parameters
      *
      * @param array $data
-     * @return \Magento\Framework\CurrencyInterface
+     * @return CurrencyInterface
      */
     public function create(array $data = [])
     {
diff --git a/lib/internal/Magento/Framework/DB/Select.php b/lib/internal/Magento/Framework/DB/Select.php
index 75abe8a90ed85df29a5ff6edcff0246e08424921..913dc4a4a92e7d7dace42fed2ff89447ffeabfe9 100644
--- a/lib/internal/Magento/Framework/DB/Select.php
+++ b/lib/internal/Magento/Framework/DB/Select.php
@@ -5,6 +5,7 @@
  */
 namespace Magento\Framework\DB;
 
+use Magento\Framework\App\ResourceConnection;
 use Magento\Framework\DB\Adapter\AdapterInterface;
 
 /**
@@ -501,4 +502,32 @@ class Select extends \Zend_Db_Select
     {
         return $this->selectRenderer->render($this);
     }
+
+    /**
+     * @return string[]
+     */
+    public function __sleep()
+    {
+        $properties = array_keys(get_object_vars($this));
+        $properties = array_diff(
+            $properties,
+            [
+                '_adapter',
+                'selectRenderer'
+            ]
+        );
+        return $properties;
+    }
+
+    /**
+     * Init not serializable fields
+     *
+     * @return void
+     */
+    public function __wakeup()
+    {
+        $objectManager = \Magento\Framework\App\ObjectManager::getInstance();
+        $this->_adapter = $objectManager->get(ResourceConnection::class)->getConnection();
+        $this->selectRenderer = $objectManager->get(\Magento\Framework\DB\Select\SelectRenderer::class);
+    }
 }
diff --git a/lib/internal/Magento/Framework/Data/Collection.php b/lib/internal/Magento/Framework/Data/Collection.php
index a4cf35da2a1de5063bbe73dbb5aecbac4a491431..ef0416419d18ca8a93b01a2a20be6235b4a35c0e 100644
--- a/lib/internal/Magento/Framework/Data/Collection.php
+++ b/lib/internal/Magento/Framework/Data/Collection.php
@@ -866,4 +866,30 @@ class Collection implements \IteratorAggregate, \Countable, ArrayInterface, Coll
     {
         return array_key_exists($flag, $this->_flags);
     }
+
+    /**
+     * @return string[]
+     */
+    public function __sleep()
+    {
+        $properties = array_keys(get_object_vars($this));
+        $properties = array_diff(
+            $properties,
+            [
+                '_entityFactory',
+            ]
+        );
+        return $properties;
+    }
+
+    /**
+     * Init not serializable fields
+     *
+     * @return void
+     */
+    public function __wakeup()
+    {
+        $objectManager = \Magento\Framework\App\ObjectManager::getInstance();
+        $this->_entityFactory = $objectManager->get(EntityFactoryInterface::class);
+    }
 }
diff --git a/lib/internal/Magento/Framework/Data/Collection/AbstractDb.php b/lib/internal/Magento/Framework/Data/Collection/AbstractDb.php
index b35881d0132767be0e28c9d9fd62fc99c99637f8..dc2b8de38ab12642791ed106d81d91da9f63438a 100644
--- a/lib/internal/Magento/Framework/Data/Collection/AbstractDb.php
+++ b/lib/internal/Magento/Framework/Data/Collection/AbstractDb.php
@@ -5,6 +5,7 @@
  */
 namespace Magento\Framework\Data\Collection;
 
+use Magento\Framework\App\ResourceConnection;
 use Magento\Framework\Data\Collection\Db\FetchStrategyInterface;
 use Magento\Framework\DB\Adapter\AdapterInterface;
 use Magento\Framework\DB\Select;
@@ -880,4 +881,27 @@ abstract class AbstractDb extends \Magento\Framework\Data\Collection
         }
         throw new \LogicException("Main table cannot be identified.");
     }
+
+    /**
+     * @inheritdoc
+     */
+    public function __sleep()
+    {
+        return array_diff(
+            parent::__sleep(),
+            ['_fetchStrategy', '_logger', '_conn', 'extensionAttributesJoinProcessor']
+        );
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function __wakeup()
+    {
+        parent::__wakeup();
+        $objectManager = \Magento\Framework\App\ObjectManager::getInstance();
+        $this->_fetchStrategy = $objectManager->get(Logger::class);
+        $this->_logger = $objectManager->get(FetchStrategyInterface::class);
+        $this->_conn = $objectManager->get(ResourceConnection::class)->getConnection();
+    }
 }
diff --git a/lib/internal/Magento/Framework/DataObject/IdentityInterface.php b/lib/internal/Magento/Framework/DataObject/IdentityInterface.php
index 9d8ab0169388e5a4a8ba3ce2e7043c01cb2973a1..614ca594e3c9d331b04bf299d2130470c3e8ddfd 100644
--- a/lib/internal/Magento/Framework/DataObject/IdentityInterface.php
+++ b/lib/internal/Magento/Framework/DataObject/IdentityInterface.php
@@ -15,7 +15,7 @@ interface IdentityInterface
     /**
      * Return unique ID(s) for each object in system
      *
-     * @return array
+     * @return string[]
      */
     public function getIdentities();
 }
diff --git a/lib/internal/Magento/Framework/EventFactory.php b/lib/internal/Magento/Framework/EventFactory.php
index 47433049bac1b5f03c13407f7bbb468d9cec5dde..e73cb8b96a0941156975523d44924318cb124016 100644
--- a/lib/internal/Magento/Framework/EventFactory.php
+++ b/lib/internal/Magento/Framework/EventFactory.php
@@ -26,6 +26,6 @@ class EventFactory
      */
     public function create($arguments = [])
     {
-        return $this->_objectManager->create('Magento\Framework\Event', $arguments);
+        return $this->_objectManager->create(Event::class, $arguments);
     }
 }
diff --git a/lib/internal/Magento/Framework/FlagFactory.php b/lib/internal/Magento/Framework/FlagFactory.php
index 99aa8d0047d19c9e85030a15b173c724bb53d77b..fcd066591a061b50fb865ec97c6435395008da1f 100644
--- a/lib/internal/Magento/Framework/FlagFactory.php
+++ b/lib/internal/Magento/Framework/FlagFactory.php
@@ -32,7 +32,7 @@ class FlagFactory
      */
     public function __construct(
         \Magento\Framework\ObjectManagerInterface $objectManager,
-        $instanceName = 'Magento\Framework\Flag'
+        $instanceName = Flag::class
     ) {
         $this->_objectManager = $objectManager;
         $this->_instanceName = $instanceName;
diff --git a/lib/internal/Magento/Framework/Indexer/Config/Converter.php b/lib/internal/Magento/Framework/Indexer/Config/Converter.php
index 5b441b97b3ee469d03847fc099ed0cb5bde0dfca..ff97c660d1303881750a71ce6a56ff25b8b652a9 100644
--- a/lib/internal/Magento/Framework/Indexer/Config/Converter.php
+++ b/lib/internal/Magento/Framework/Indexer/Config/Converter.php
@@ -29,6 +29,7 @@ class Converter implements ConverterInterface
             $data['primary'] = $this->getAttributeValue($indexerNode, 'primary');
             $data['view_id'] = $this->getAttributeValue($indexerNode, 'view_id');
             $data['action_class'] = $this->getAttributeValue($indexerNode, 'class');
+            $data['shared_index'] = $this->getAttributeValue($indexerNode, 'shared_index');
             $data['title'] = '';
             $data['description'] = '';
 
diff --git a/lib/internal/Magento/Framework/Indexer/Test/Unit/_files/indexer_config.php b/lib/internal/Magento/Framework/Indexer/Test/Unit/_files/indexer_config.php
index de81e44e2b39b4619de5a1c998c52bca39411617..9e655afa8effb56d0dba4672dde3b1b838bb1eca 100644
--- a/lib/internal/Magento/Framework/Indexer/Test/Unit/_files/indexer_config.php
+++ b/lib/internal/Magento/Framework/Indexer/Test/Unit/_files/indexer_config.php
@@ -19,6 +19,7 @@ return [
             'title' => __('Indexer public name'),
             'description' => __('Indexer public description'),
             'primary' => null,
+            'shared_index' => null,
             'fieldsets' => []
         ],
         'test_indexer' => [
@@ -28,6 +29,7 @@ return [
             'title' => '',
             'description' => '',
             'primary' => null,
+            'shared_index' => null,
         ],
     ]
 ];
diff --git a/lib/internal/Magento/Framework/Indexer/etc/indexer.xsd b/lib/internal/Magento/Framework/Indexer/etc/indexer.xsd
index fa6e0f7afd4ebfe51fdea9c5d85e945be1bb5a95..9b440ce7178e14d7e6e31b955f6580108d8db325 100644
--- a/lib/internal/Magento/Framework/Indexer/etc/indexer.xsd
+++ b/lib/internal/Magento/Framework/Indexer/etc/indexer.xsd
@@ -23,6 +23,7 @@
         <xs:attribute name="primary" type="nameType" use="optional" />
         <xs:attribute name="view_id" type="viewIdType" use="optional" />
         <xs:attribute name="class" type="classType" use="optional" />
+        <xs:attribute name="shared_index" type="xs:string" use="optional" />
     </xs:complexType>
 
     <xs:group name="fieldset">
diff --git a/lib/internal/Magento/Framework/Indexer/etc/indexer_merged.xsd b/lib/internal/Magento/Framework/Indexer/etc/indexer_merged.xsd
index fb60fd6d096e21b417b7c4183e2d110d4499783c..2aad6e4b4f91b443114d299ffcf10da88d21db41 100644
--- a/lib/internal/Magento/Framework/Indexer/etc/indexer_merged.xsd
+++ b/lib/internal/Magento/Framework/Indexer/etc/indexer_merged.xsd
@@ -23,6 +23,7 @@
         <xs:attribute name="primary" type="nameType" use="optional" />
         <xs:attribute name="view_id" type="viewIdType" use="required" />
         <xs:attribute name="class" type="classType" use="required" />
+        <xs:attribute name="shared_index" type="xs:string" use="optional" />
     </xs:complexType>
 
     <xs:group name="fieldset">
diff --git a/lib/internal/Magento/Framework/Interception/Interceptor.php b/lib/internal/Magento/Framework/Interception/Interceptor.php
index 1fcf8e4134812d81e65fbc3844cb3b63b4331e31..1c13c0c3b0bc83104e5bc353b32f1679ccfc37ff 100644
--- a/lib/internal/Magento/Framework/Interception/Interceptor.php
+++ b/lib/internal/Magento/Framework/Interception/Interceptor.php
@@ -82,10 +82,12 @@ trait Interceptor
     public function __sleep()
     {
         if (method_exists(get_parent_class($this), '__sleep')) {
-            return array_diff(parent::__sleep(), ['pluginLocator', 'pluginList', 'chain', 'subjectType']);
+            $properties = parent::__sleep();
         } else {
-            return array_keys(get_class_vars(get_parent_class($this)));
+            $properties = array_keys(get_object_vars($this));
         }
+        $properties = array_diff($properties, ['pluginLocator', 'pluginList', 'chain', 'subjectType', 'pluginLocator']);
+        return $properties;
     }
 
     /**
diff --git a/lib/internal/Magento/Framework/Interception/PluginList/PluginList.php b/lib/internal/Magento/Framework/Interception/PluginList/PluginList.php
index a1a7a29ba3313b4cd45128281cc7bae8d5320590..3bbf7a2f9743aa0ebe250c4be8e2f64581f81bad 100644
--- a/lib/internal/Magento/Framework/Interception/PluginList/PluginList.php
+++ b/lib/internal/Magento/Framework/Interception/PluginList/PluginList.php
@@ -17,7 +17,6 @@ use Magento\Framework\Interception\ObjectManager\ConfigInterface;
 use Magento\Framework\ObjectManager\RelationsInterface;
 use Magento\Framework\ObjectManager\DefinitionInterface as ClassDefinitions;
 use Magento\Framework\ObjectManagerInterface;
-use Zend\Soap\Exception\InvalidArgumentException;
 
 /**
  * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
@@ -115,7 +114,7 @@ class PluginList extends Scoped implements InterceptionPluginList
      *
      * @param string $type
      * @return array
-     * @throws InvalidArgumentException
+     * @throws \InvalidArgumentException
      * @SuppressWarnings(PHPMD.CyclomaticComplexity)
      * @SuppressWarnings(PHPMD.NPathComplexity)
      */
@@ -162,7 +161,7 @@ class PluginList extends Scoped implements InterceptionPluginList
                     }
                     $pluginType = $this->_omConfig->getOriginalInstanceType($plugin['instance']);
                     if (!class_exists($pluginType)) {
-                        throw new InvalidArgumentException('Plugin class ' . $pluginType . ' doesn\'t exist');
+                        throw new \InvalidArgumentException('Plugin class ' . $pluginType . ' doesn\'t exist');
                     }
                     foreach ($this->_definitions->getMethodList($pluginType) as $pluginMethod => $methodTypes) {
                         $current = isset($lastPerMethod[$pluginMethod]) ? $lastPerMethod[$pluginMethod] : '__self';
diff --git a/lib/internal/Magento/Framework/Model/AbstractExtensibleModel.php b/lib/internal/Magento/Framework/Model/AbstractExtensibleModel.php
index 24802ef1ac110d72e91c1af0e40c527843dce481..7be929ccc5a7e6362a97fcf8daedef27d6b3a36e 100644
--- a/lib/internal/Magento/Framework/Model/AbstractExtensibleModel.php
+++ b/lib/internal/Magento/Framework/Model/AbstractExtensibleModel.php
@@ -7,6 +7,7 @@
 namespace Magento\Framework\Model;
 
 use Magento\Framework\Api\AttributeValueFactory;
+use Magento\Framework\Api\ExtensionAttributesFactory;
 
 /**
  * Abstract model with custom attributes support.
@@ -19,7 +20,7 @@ abstract class AbstractExtensibleModel extends AbstractModel implements
     \Magento\Framework\Api\CustomAttributesDataInterface
 {
     /**
-     * @var \Magento\Framework\Api\ExtensionAttributesFactory
+     * @var ExtensionAttributesFactory
      */
     protected $extensionAttributesFactory;
 
@@ -46,7 +47,7 @@ abstract class AbstractExtensibleModel extends AbstractModel implements
     /**
      * @param \Magento\Framework\Model\Context $context
      * @param \Magento\Framework\Registry $registry
-     * @param \Magento\Framework\Api\ExtensionAttributesFactory $extensionFactory
+     * @param ExtensionAttributesFactory $extensionFactory
      * @param AttributeValueFactory $customAttributeFactory
      * @param \Magento\Framework\Model\ResourceModel\AbstractResource $resource
      * @param \Magento\Framework\Data\Collection\AbstractDb $resourceCollection
@@ -55,7 +56,7 @@ abstract class AbstractExtensibleModel extends AbstractModel implements
     public function __construct(
         \Magento\Framework\Model\Context $context,
         \Magento\Framework\Registry $registry,
-        \Magento\Framework\Api\ExtensionAttributesFactory $extensionFactory,
+        ExtensionAttributesFactory $extensionFactory,
         AttributeValueFactory $customAttributeFactory,
         \Magento\Framework\Model\ResourceModel\AbstractResource $resource = null,
         \Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null,
@@ -328,4 +329,23 @@ abstract class AbstractExtensibleModel extends AbstractModel implements
     {
         return $this->getData(self::EXTENSION_ATTRIBUTES_KEY);
     }
+
+    /**
+     * @inheritdoc
+     */
+    public function __sleep()
+    {
+        return array_diff(parent::__sleep(), ['extensionAttributesFactory', 'customAttributeFactory']);
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function __wakeup()
+    {
+        parent::__wakeup();
+        $objectManager = \Magento\Framework\App\ObjectManager::getInstance();
+        $this->extensionAttributesFactory = $objectManager->get(ExtensionAttributesFactory::class);
+        $this->customAttributeFactory = $objectManager->get(AttributeValueFactory::class);
+    }
 }
diff --git a/lib/internal/Magento/Framework/Model/AbstractModel.php b/lib/internal/Magento/Framework/Model/AbstractModel.php
index f72c455daf860caec4e77dbf71c901832015dec7..d53820eff1855582e5ad01ddcf0e936f05cb8cf1 100644
--- a/lib/internal/Magento/Framework/Model/AbstractModel.php
+++ b/lib/internal/Magento/Framework/Model/AbstractModel.php
@@ -220,7 +220,19 @@ abstract class AbstractModel extends \Magento\Framework\DataObject
     public function __sleep()
     {
         $properties = array_keys(get_object_vars($this));
-        $properties = array_diff($properties, ['_eventManager', '_cacheManager', '_registry', '_appState']);
+        $properties = array_diff(
+            $properties,
+            [
+                '_eventManager',
+                '_cacheManager',
+                '_registry',
+                '_appState',
+                '_actionValidator',
+                '_logger',
+                '_resourceCollection',
+                '_resource',
+            ]
+        );
         return $properties;
     }
 
@@ -232,12 +244,15 @@ abstract class AbstractModel extends \Magento\Framework\DataObject
     public function __wakeup()
     {
         $objectManager = \Magento\Framework\App\ObjectManager::getInstance();
-        $this->_eventManager = $objectManager->get('Magento\Framework\Event\ManagerInterface');
-        $this->_cacheManager = $objectManager->get('Magento\Framework\App\CacheInterface');
         $this->_registry = $objectManager->get('Magento\Framework\Registry');
+
         $context = $objectManager->get('Magento\Framework\Model\Context');
         if ($context instanceof \Magento\Framework\Model\Context) {
             $this->_appState = $context->getAppState();
+            $this->_eventManager = $context->getEventDispatcher();
+            $this->_cacheManager = $context->getCacheManager();
+            $this->_logger = $context->getLogger();
+            $this->_actionValidator = $context->getActionValidator();
         }
     }
 
@@ -263,7 +278,6 @@ abstract class AbstractModel extends \Magento\Framework\DataObject
         return $this->_idFieldName;
     }
 
-
     /**
      * Identifier getter
      *
diff --git a/lib/internal/Magento/Framework/Model/ResourceModel/Db/Collection/AbstractCollection.php b/lib/internal/Magento/Framework/Model/ResourceModel/Db/Collection/AbstractCollection.php
index de66653672dd6be913988ea1acd68391c47ec531..578b2c151164182c1d8242c2862fed5003b89ef6 100644
--- a/lib/internal/Magento/Framework/Model/ResourceModel/Db/Collection/AbstractCollection.php
+++ b/lib/internal/Magento/Framework/Model/ResourceModel/Db/Collection/AbstractCollection.php
@@ -592,4 +592,25 @@ abstract class AbstractCollection extends \Magento\Framework\Data\Collection\Abs
         }
         return $this;
     }
+
+    /**
+     * @inheritdoc
+     */
+    public function __sleep()
+    {
+        return array_diff(
+            parent::__sleep(),
+            ['_resource', '_eventManager']
+        );
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function __wakeup()
+    {
+        parent::__wakeup();
+        $objectManager = \Magento\Framework\App\ObjectManager::getInstance();
+        $this->_eventManager = $objectManager->get(\Magento\Framework\Event\ManagerInterface::class);
+    }
 }
diff --git a/lib/internal/Magento/Framework/Mview/Config/Data/Proxy.php b/lib/internal/Magento/Framework/Mview/Config/Data/Proxy.php
index a026f2a60c82e51d076d99b2b7655000c84db58f..15ebfc6a8539aeac634ae57805f7bd356facc2c8 100644
--- a/lib/internal/Magento/Framework/Mview/Config/Data/Proxy.php
+++ b/lib/internal/Magento/Framework/Mview/Config/Data/Proxy.php
@@ -59,7 +59,7 @@ class Proxy extends \Magento\Framework\Mview\Config\Data implements
      */
     public function __sleep()
     {
-        return ['_subject', '_isShared'];
+        return ['subject', 'isShared'];
     }
 
     /**
diff --git a/lib/internal/Magento/Framework/ObjectManager/Code/Generator/Proxy.php b/lib/internal/Magento/Framework/ObjectManager/Code/Generator/Proxy.php
index c0f86fa70b2bef63efa7896f6b30dc2c228acaa7..442ad8261a403fbe34fb659e2a1f4df8b1a901ca 100644
--- a/lib/internal/Magento/Framework/ObjectManager/Code/Generator/Proxy.php
+++ b/lib/internal/Magento/Framework/ObjectManager/Code/Generator/Proxy.php
@@ -81,7 +81,7 @@ class Proxy extends \Magento\Framework\Code\Generator\EntityAbstract
         $methods = [$construct];
         $methods[] = [
             'name' => '__sleep',
-            'body' => 'return array(\'_subject\', \'_isShared\');',
+            'body' => 'return [\'_subject\', \'_isShared\', \'_instanceName\'];',
             'docblock' => ['tags' => [['name' => 'return', 'description' => 'array']]],
         ];
         $methods[] = [
diff --git a/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Code/Generator/_files/SampleProxy.txt b/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Code/Generator/_files/SampleProxy.txt
index f3fadd9d31b50927ab0d573ead7521c89f2adc1e..43c99aa5e6843e3676a6b47c618022c78e5a9bc4 100644
--- a/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Code/Generator/_files/SampleProxy.txt
+++ b/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Code/Generator/_files/SampleProxy.txt
@@ -52,7 +52,7 @@ class Sample_Proxy extends \Magento\Framework\ObjectManager\Code\Generator\Sampl
      */
     public function __sleep()
     {
-        return array('_subject', '_isShared');
+        return ['_subject', '_isShared', '_instanceName'];
     }
 
     /**
diff --git a/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Relations/RuntimeTest.php b/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Relations/RuntimeTest.php
index 2485e8e156228c7e2206971dd890e3e125e100e7..8195a4f5f193e57a41e39ede7a1b8eec96c3c185 100644
--- a/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Relations/RuntimeTest.php
+++ b/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Relations/RuntimeTest.php
@@ -42,7 +42,7 @@ class RuntimeTest extends \PHPUnit_Framework_TestCase
 
     /**
      * @param $entity
-     * @expectedException  \Magento\Framework\Exception\LocalizedException
+     * @expectedException \RuntimeException
      * @dataProvider nonExistentGeneratorsDataProvider
      */
     public function testHasIfNonExists($entity)
diff --git a/lib/internal/Magento/Framework/Pricing/Render/PriceBox.php b/lib/internal/Magento/Framework/Pricing/Render/PriceBox.php
index 45181680b33ec8ec1767df9c8b720713e5f576e1..a8664e3f10a341809c78fddde828e0b3178b2631 100644
--- a/lib/internal/Magento/Framework/Pricing/Render/PriceBox.php
+++ b/lib/internal/Magento/Framework/Pricing/Render/PriceBox.php
@@ -6,6 +6,7 @@
 
 namespace Magento\Framework\Pricing\Render;
 
+use Magento\Framework\DataObject\IdentityInterface;
 use Magento\Framework\Pricing\Amount\AmountInterface;
 use Magento\Framework\Pricing\SaleableInterface;
 use Magento\Framework\Pricing\Price\PriceInterface;
@@ -17,8 +18,11 @@ use Magento\Framework\View\Element\Template;
  * @method bool hasListClass()
  * @method string getListClass()
  */
-class PriceBox extends Template implements PriceBoxRenderInterface
+class PriceBox extends Template implements PriceBoxRenderInterface, IdentityInterface
 {
+    /** Default block lifetime */
+    const DEFAULT_LIFETIME = 3600;
+
     /**
      * @var SaleableInterface
      */
@@ -65,6 +69,26 @@ class PriceBox extends Template implements PriceBoxRenderInterface
         return parent::_toHtml();
     }
 
+    /**
+     * Get Key for caching block content
+     *
+     * @return string
+     */
+    public function getCacheKey()
+    {
+        return parent::getCacheKey() . '-' . $this->getPriceId() . '-' . $this->getPrice()->getPriceCode();
+    }
+
+    /**
+     * Get block cache life time
+     *
+     * @return int
+     */
+    protected function getCacheLifetime()
+    {
+        return parent::hasCacheLifetime() ? parent::getCacheLifetime() : self::DEFAULT_LIFETIME;
+    }
+    
     /**
      * @return SaleableInterface
      */
@@ -146,4 +170,19 @@ class PriceBox extends Template implements PriceBoxRenderInterface
     {
         return $this->rendererPool;
     }
+
+    /**
+     * Return unique ID(s) for each object in system
+     *
+     * @return array
+     */
+    public function getIdentities()
+    {
+        $item = $this->getSaleableItem();
+        if ($item instanceof IdentityInterface) {
+            return $item->getIdentities();
+        } else {
+            return [];
+        }
+    }
 }
diff --git a/lib/internal/Magento/Framework/Pricing/Test/Unit/Render/PriceBoxTest.php b/lib/internal/Magento/Framework/Pricing/Test/Unit/Render/PriceBoxTest.php
index 8ffa2d1749f62a234c97f6da15f573d4e3a00995..9363c9fc0196c2870e60803907d4374c57c08434 100644
--- a/lib/internal/Magento/Framework/Pricing/Test/Unit/Render/PriceBoxTest.php
+++ b/lib/internal/Magento/Framework/Pricing/Test/Unit/Render/PriceBoxTest.php
@@ -54,6 +54,8 @@ class PriceBoxTest extends \PHPUnit_Framework_TestCase
         $layout = $this->getMock('Magento\Framework\View\LayoutInterface');
         $eventManager = $this->getMock('Magento\Framework\Event\ManagerInterface');
         $scopeConfigMock = $this->getMockForAbstractClass('Magento\Framework\App\Config\ScopeConfigInterface');
+        $cacheState = $this->getMockBuilder(\Magento\Framework\App\Cache\StateInterface::class)
+            ->getMockForAbstractClass();
         $storeConfig = $this->getMockBuilder('Magento\Store\Model\Store\Config')
             ->disableOriginalConstructor()
             ->getMock();
@@ -72,6 +74,9 @@ class PriceBoxTest extends \PHPUnit_Framework_TestCase
         $this->context->expects($this->any())
             ->method('getScopeConfig')
             ->will($this->returnValue($scopeConfigMock));
+        $this->context->expects($this->any())
+            ->method('getCacheState')
+            ->will($this->returnValue($cacheState));
 
         $this->saleable = $this->getMock('Magento\Framework\Pricing\SaleableInterface');
 
diff --git a/lib/internal/Magento/Framework/Session/Config.php b/lib/internal/Magento/Framework/Session/Config.php
index 793794b61826e09f088fef985593e40aae9aada5..99f3eb96d773c8dfa34c6f0a6380027c6288e174 100644
--- a/lib/internal/Magento/Framework/Session/Config.php
+++ b/lib/internal/Magento/Framework/Session/Config.php
@@ -18,44 +18,28 @@ use Magento\Framework\Session\SaveHandlerInterface;
  */
 class Config implements ConfigInterface
 {
-    /**
-     * Configuration path for session save method
-     */
+    /** Configuration path for session save method */
     const PARAM_SESSION_SAVE_METHOD = 'session/save';
 
-    /**
-     * Configuration path for session save path
-     */
+    /** Configuration path for session save path */
     const PARAM_SESSION_SAVE_PATH = 'session/save_path';
 
-    /**
-     * Configuration path for session cache limiter
-     */
+    /** Configuration path for session cache limiter */
     const PARAM_SESSION_CACHE_LIMITER = 'session/cache_limiter';
 
-    /**
-     * Configuration path for cookie domain
-     */
+    /** Configuration path for cookie domain */
     const XML_PATH_COOKIE_DOMAIN = 'web/cookie/cookie_domain';
 
-    /**
-     * Configuration path for cookie lifetime
-     */
+    /** Configuration path for cookie lifetime */
     const XML_PATH_COOKIE_LIFETIME = 'web/cookie/cookie_lifetime';
 
-    /**
-     * Configuration path for cookie http only param
-     */
+    /** Configuration path for cookie http only param */
     const XML_PATH_COOKIE_HTTPONLY = 'web/cookie/cookie_httponly';
 
-    /**
-     * Configuration path for cookie path
-     */
+    /** Configuration path for cookie path */
     const XML_PATH_COOKIE_PATH = 'web/cookie/cookie_path';
 
-    /**
-     * Cookie default lifetime
-     */
+    /** Cookie default lifetime */
     const COOKIE_LIFETIME_DEFAULT = 3600;
 
     /**
@@ -65,19 +49,13 @@ class Config implements ConfigInterface
      */
     protected $options = [];
 
-    /**
-     * @var \Magento\Framework\App\Config\ScopeConfigInterface
-     */
+    /** @var \Magento\Framework\App\Config\ScopeConfigInterface */
     protected $_scopeConfig;
 
-    /**
-     * @var \Magento\Framework\Stdlib\StringUtils
-     */
+    /** @var \Magento\Framework\Stdlib\StringUtils */
     protected $_stringHelper;
 
-    /**
-     * @var \Magento\Framework\App\RequestInterface
-     */
+    /** @var \Magento\Framework\App\RequestInterface */
     protected $_httpRequest;
 
     /**
@@ -92,17 +70,16 @@ class Config implements ConfigInterface
         'session.cookie_httponly',
     ];
 
-    /**
-     * @var string
-     */
+    /** @var string */
     protected $_scopeType;
 
-    /**
-     * @var string
-     */
+    /** @var string */
+    protected $lifetimePath;
+
+    /** @var string */
     private $saveHandlerName;
 
-    /** @var  \Magento\Framework\ValidatorFactory */
+    /** @var \Magento\Framework\ValidatorFactory */
     protected $_validatorFactory;
 
     /**
@@ -131,6 +108,7 @@ class Config implements ConfigInterface
         $this->_stringHelper = $stringHelper;
         $this->_httpRequest = $request;
         $this->_scopeType = $scopeType;
+        $this->lifetimePath = $lifetimePath;
 
         /**
          * Session handler
@@ -170,8 +148,7 @@ class Config implements ConfigInterface
         /**
          * Cookie settings: lifetime, path, domain, httpOnly. These govern settings for the session cookie.
          */
-        $lifetime = $this->_scopeConfig->getValue($lifetimePath, $this->_scopeType);
-        $this->setCookieLifetime($lifetime, self::COOKIE_LIFETIME_DEFAULT);
+        $this->configureCookieLifetime();
 
         $path = $this->_scopeConfig->getValue(self::XML_PATH_COOKIE_PATH, $this->_scopeType);
         $path = empty($path) ? $this->_httpRequest->getBasePath() : $path;
@@ -580,4 +557,15 @@ class Config implements ConfigInterface
             throw new \BadMethodCallException(sprintf('Method "%s" does not exist in %s', $method, get_class($this)));
         }
     }
+
+    /**
+     * Set session cookie lifetime according to configuration
+     *
+     * @return $this
+     */
+    protected function configureCookieLifetime()
+    {
+        $lifetime = $this->_scopeConfig->getValue($this->lifetimePath, $this->_scopeType);
+        return $this->setCookieLifetime($lifetime, self::COOKIE_LIFETIME_DEFAULT);
+    }
 }
diff --git a/lib/internal/Magento/Framework/Session/Test/Unit/ConfigTest.php b/lib/internal/Magento/Framework/Session/Test/Unit/ConfigTest.php
index 3c50426ce22347baf077bcf3f50739b5fa73bb6d..60d980f77df1ee84ddb89cbb22f116baa25a9322 100644
--- a/lib/internal/Magento/Framework/Session/Test/Unit/ConfigTest.php
+++ b/lib/internal/Magento/Framework/Session/Test/Unit/ConfigTest.php
@@ -376,7 +376,7 @@ class ConfigTest extends \PHPUnit_Framework_TestCase
                 [
                     'session.save_handler' => 'files',
                     'session.cache_limiter' => 'files',
-                    'session.cookie_lifetime' => 7200,
+                    'session.cookie_lifetime' => 0,
                     'session.cookie_path' => '/',
                     'session.cookie_domain' => 'init.host',
                     'session.cookie_httponly' => false,
@@ -443,7 +443,6 @@ class ConfigTest extends \PHPUnit_Framework_TestCase
 
         $this->configMock = $this->getMock('Magento\Framework\App\Config\ScopeConfigInterface');
         $getValueReturnMap = [
-            ['test_web/test_cookie/test_cookie_lifetime', 'store', null, 7200],
             ['web/cookie/cookie_path', 'store', null, ''],
         ];
         $this->configMock->method('getValue')
diff --git a/lib/internal/Magento/Framework/Stdlib/DateTime/DateTimeFormatter.php b/lib/internal/Magento/Framework/Stdlib/DateTime/DateTimeFormatter.php
index d4d136e0c9c14912e843b783d626c24487419e51..e0958f5635ad0c3cbfb6a63a19c106d143366a7e 100644
--- a/lib/internal/Magento/Framework/Stdlib/DateTime/DateTimeFormatter.php
+++ b/lib/internal/Magento/Framework/Stdlib/DateTime/DateTimeFormatter.php
@@ -18,21 +18,43 @@ class DateTimeFormatter implements DateTimeFormatterInterface
      */
     protected $useIntlFormatObject;
 
+    /**
+     * @var \Magento\Framework\Locale\ResolverInterface
+     */
+    private $localeResolver;
+
     /**
      * @param bool|null $useIntlFormatObject
      */
-    public function __construct($useIntlFormatObject = null)
-    {
+    public function __construct(
+        $useIntlFormatObject = null
+    ) {
         $this->useIntlFormatObject = (null === $useIntlFormatObject)
             ? !defined('HHVM_VERSION')
             : $useIntlFormatObject;
     }
 
+    /**
+     * Get locale resolver
+     *
+     * @return \Magento\Framework\Locale\ResolverInterface|mixed
+     */
+    private function getLocaleResolver()
+    {
+        if ($this->localeResolver === null) {
+            $this->localeResolver = \Magento\Framework\App\ObjectManager::getInstance()->get(
+                'Magento\Framework\Locale\ResolverInterface'
+            );
+        }
+        return $this->localeResolver;
+    }
+
     /**
      * {@inheritdoc}
      */
     public function formatObject($object, $format = null, $locale = null)
     {
+        $locale = (null === $locale) ? $this->getLocaleResolver()->getLocale() : $locale;
         if ($this->useIntlFormatObject) {
             return \IntlDateFormatter::formatObject($object, $format, $locale);
         }
diff --git a/lib/internal/Magento/Framework/Stdlib/Test/Unit/DateTime/DateTimeFormatterTest.php b/lib/internal/Magento/Framework/Stdlib/Test/Unit/DateTime/DateTimeFormatterTest.php
index 2c6358bc6ddc042a70a321ac017e271220861dd0..7a08498555ecace563771b3c432118e008486779 100644
--- a/lib/internal/Magento/Framework/Stdlib/Test/Unit/DateTime/DateTimeFormatterTest.php
+++ b/lib/internal/Magento/Framework/Stdlib/Test/Unit/DateTime/DateTimeFormatterTest.php
@@ -10,33 +10,58 @@ use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
 class DateTimeFormatterTest extends \PHPUnit_Framework_TestCase
 {
     /**
-     * @var \Magento\Framework\Stdlib\DateTime\DateTimeFormatter
+     * @var ObjectManager
      */
-    protected $dateTimeFormatter;
+    protected $objectManager;
+
+    /**
+     * @var \Magento\Framework\Locale\ResolverInterface | \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $localeResolverMock;
 
     protected function setUp()
     {
         if (defined('HHVM_VERSION')) {
             $this->markTestSkipped('Skip this test for hhvm due to problem with \IntlDateFormatter::formatObject');
         }
+        $this->objectManager = new ObjectManager($this);
+        $this->localeResolverMock = $this->getMockBuilder('Magento\Framework\Locale\ResolverInterface')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->localeResolverMock->expects($this->any())
+            ->method('getLocale')
+            ->willReturn('fr-FR');
 
-        $this->dateTimeFormatter = (new ObjectManager($this))
-            ->getObject('Magento\Framework\Stdlib\DateTime\DateTimeFormatter', [
-                'useIntlFormatObject' => false,
-            ]);
     }
 
     /**
      * @param \IntlCalendar|\DateTime $object
      * @param string|int|array|null $format
      * @param string|null $locale
+     * @param boolean $useIntlFormatObject
      * @dataProvider dataProviderFormatObject
      */
-    public function testFormatObject($object, $format = null, $locale = null)
+    public function testFormatObject($object, $format = null, $locale = null, $useIntlFormatObject = false)
     {
+        $dateTimeFormatter = $this->objectManager->getObject(
+            'Magento\Framework\Stdlib\DateTime\DateTimeFormatter',
+            [
+                'useIntlFormatObject' => $useIntlFormatObject,
+            ]
+        );
+
+        $reflection = new \ReflectionClass(get_class($dateTimeFormatter));
+        $reflectionProperty = $reflection->getProperty('localeResolver');
+        $reflectionProperty->setAccessible(true);
+        $reflectionProperty->setValue($dateTimeFormatter, $this->localeResolverMock);
+
         $this->assertEquals(
-            \IntlDateFormatter::formatObject($object, $format, $locale),
-            $this->dateTimeFormatter->formatObject($object, $format, $locale)
+            \IntlDateFormatter::formatObject(
+                $object,
+                $format,
+                (null === $locale) ? 'fr-FR' : $locale
+            ),
+            $dateTimeFormatter->formatObject($object, $format, $locale)
         );
     }
 
@@ -59,7 +84,6 @@ class DateTimeFormatterTest extends \PHPUnit_Framework_TestCase
             [new \DateTime('2013-09-09 09:09:09 Europe/Madrid'), \IntlDateFormatter::FULL, 'es_ES'],
             [new \DateTime('2013-09-09 09:09:09 -01:00'), null, null],
             [new \DateTime('2013-09-09 09:09:09 +01:00'), null, null],
-
             [$calendar, null, null],
             [$calendar, \IntlDateFormatter::FULL, null],
             [$calendar, null, 'en-US'],
@@ -70,6 +94,26 @@ class DateTimeFormatterTest extends \PHPUnit_Framework_TestCase
             [\IntlCalendar::fromDateTime('2013-09-09 09:09:09 Europe/Madrid'), \IntlDateFormatter::FULL, 'es_ES'],
             [\IntlCalendar::fromDateTime('2013-09-09 09:09:09 -01:00'), null, null],
             [\IntlCalendar::fromDateTime('2013-09-09 09:09:09 +01:00'), null, null],
+            [$date, null, null, true],
+            [$date, \IntlDateFormatter::FULL, null, true],
+            [$date, null, 'en-US', true],
+            [$date, [\IntlDateFormatter::SHORT, \IntlDateFormatter::FULL], 'en-US', true],
+            [$date, 'E y-MM-d HH,mm,ss.SSS v', 'en-US', true],
+            [$date, [\IntlDateFormatter::NONE, \IntlDateFormatter::FULL], null, true],
+            [$date, "d 'of' MMMM y", 'en_US', true],
+            [new \DateTime('2013-09-09 09:09:09 Europe/Madrid'), \IntlDateFormatter::FULL, 'es_ES', true],
+            [new \DateTime('2013-09-09 09:09:09 -01:00'), null, null, true],
+            [new \DateTime('2013-09-09 09:09:09 +01:00'), null, null, true],
+            [$calendar, null, null, true],
+            [$calendar, \IntlDateFormatter::FULL, null, true],
+            [$calendar, null, 'en-US', true],
+            [$calendar, [\IntlDateFormatter::SHORT, \IntlDateFormatter::FULL], 'en-US', true],
+            [$calendar, 'E y-MM-d HH,mm,ss.SSS v', 'en-US', true],
+            [$calendar, [\IntlDateFormatter::NONE, \IntlDateFormatter::FULL], null, true],
+            [$calendar, "d 'of' MMMM y", 'en_US', true],
+            [\IntlCalendar::fromDateTime('2013-09-09 09:09:09 Europe/Madrid'), \IntlDateFormatter::FULL, 'es_ES', true],
+            [\IntlCalendar::fromDateTime('2013-09-09 09:09:09 -01:00'), null, null, true],
+            [\IntlCalendar::fromDateTime('2013-09-09 09:09:09 +01:00'), null, null, true],
         ];
     }
 
@@ -79,6 +123,17 @@ class DateTimeFormatterTest extends \PHPUnit_Framework_TestCase
      */
     public function testFormatObjectIfPassedWrongFormat()
     {
-        $this->dateTimeFormatter->formatObject(new \DateTime('2013-06-06 17:05:06 Europe/Dublin'), new \StdClass());
+        $dateTimeFormatter = $this->objectManager->getObject(
+            'Magento\Framework\Stdlib\DateTime\DateTimeFormatter',
+            [
+                'useIntlFormatObject' => false,
+            ]
+        );
+
+        $reflection = new \ReflectionClass(get_class($dateTimeFormatter));
+        $reflectionProperty = $reflection->getProperty('localeResolver');
+        $reflectionProperty->setAccessible(true);
+        $reflectionProperty->setValue($dateTimeFormatter, $this->localeResolverMock);
+        $dateTimeFormatter->formatObject(new \DateTime('2013-06-06 17:05:06 Europe/Dublin'), new \StdClass());
     }
 }
diff --git a/lib/internal/Magento/Framework/Translate/Inline/Proxy.php b/lib/internal/Magento/Framework/Translate/Inline/Proxy.php
index 99440a39863f34a7951de2a2f845f241bd6064ea..ffa9368c5454d3937c1c23ca85f987e63d2d78f8 100644
--- a/lib/internal/Magento/Framework/Translate/Inline/Proxy.php
+++ b/lib/internal/Magento/Framework/Translate/Inline/Proxy.php
@@ -59,7 +59,7 @@ class Proxy extends \Magento\Framework\Translate\Inline implements
      */
     public function __sleep()
     {
-        return ['_subject', '_isShared'];
+        return ['subject', 'isShared'];
     }
 
     /**
diff --git a/lib/internal/Magento/Framework/UrlFactory.php b/lib/internal/Magento/Framework/UrlFactory.php
index f3e65d808ca58ceb6aba8bbc05f24daa62b878b5..65c7d55f1aac584d59863eb19a7f55a992c532fc 100644
--- a/lib/internal/Magento/Framework/UrlFactory.php
+++ b/lib/internal/Magento/Framework/UrlFactory.php
@@ -11,7 +11,7 @@ namespace Magento\Framework;
 class UrlFactory
 {
     /**
-     * @var \Magento\Framework\ObjectManagerInterface
+     * @var ObjectManagerInterface
      */
     protected $_objectManager = null;
 
@@ -21,10 +21,10 @@ class UrlFactory
     protected $_instanceName = null;
 
     /**
-     * @param \Magento\Framework\ObjectManagerInterface $objectManager
+     * @param ObjectManagerInterface $objectManager
      * @param string $instanceName
      */
-    public function __construct(\Magento\Framework\ObjectManagerInterface $objectManager, $instanceName = 'Magento\Framework\UrlInterface')
+    public function __construct(ObjectManagerInterface $objectManager, $instanceName = UrlInterface::class)
     {
         $this->_objectManager = $objectManager;
         $this->_instanceName = $instanceName;
@@ -34,7 +34,7 @@ class UrlFactory
      * Create Url instance with specified parameters
      *
      * @param array $data
-     * @return \Magento\Framework\UrlInterface
+     * @return UrlInterface
      */
     public function create(array $data = [])
     {
diff --git a/lib/internal/Magento/Framework/Validator/Factory.php b/lib/internal/Magento/Framework/Validator/Factory.php
index ef5679b220c2460dbc1e94d7d09760af0436fa31..d35bae829050054446b009c249b65d72baa849d8 100644
--- a/lib/internal/Magento/Framework/Validator/Factory.php
+++ b/lib/internal/Magento/Framework/Validator/Factory.php
@@ -10,8 +10,13 @@
 
 namespace Magento\Framework\Validator;
 
+use Magento\Framework\Cache\FrontendInterface;
+
 class Factory
 {
+    /** cache key */
+    const CACHE_KEY = __CLASS__;
+
     /**
      * @var \Magento\Framework\ObjectManagerInterface
      */
@@ -29,18 +34,47 @@ class Factory
      */
     private $isDefaultTranslatorInitialized = false;
 
+    /**
+     * @var \Magento\Framework\Module\Dir\Reader
+     */
+    private $moduleReader;
+
+    /**
+     * @var FrontendInterface
+     */
+    private $cache;
+
     /**
      * Initialize dependencies
      *
      * @param \Magento\Framework\ObjectManagerInterface $objectManager
      * @param \Magento\Framework\Module\Dir\Reader $moduleReader
+     * @param FrontendInterface $cache
      */
     public function __construct(
         \Magento\Framework\ObjectManagerInterface $objectManager,
-        \Magento\Framework\Module\Dir\Reader $moduleReader
+        \Magento\Framework\Module\Dir\Reader $moduleReader,
+        FrontendInterface $cache
     ) {
         $this->_objectManager = $objectManager;
-        $this->_configFiles = $moduleReader->getConfigurationFiles('validation.xml');
+        $this->moduleReader = $moduleReader;
+        $this->cache = $cache;
+    }
+
+    /**
+     * Init cached list of validation files
+     */
+    protected function _initializeConfigList()
+    {
+        if (!$this->_configFiles) {
+            $this->_configFiles = $this->cache->load(self::CACHE_KEY);
+            if (!$this->_configFiles) {
+                $this->_configFiles = $this->moduleReader->getConfigurationFiles('validation.xml');
+                $this->cache->save(serialize($this->_configFiles), self::CACHE_KEY);
+            } else {
+                $this->_configFiles = unserialize($this->_configFiles);
+            }
+        }
     }
 
     /**
@@ -73,6 +107,7 @@ class Factory
      */
     public function getValidatorConfig()
     {
+        $this->_initializeConfigList();
         $this->_initializeDefaultTranslator();
         return $this->_objectManager->create('Magento\Framework\Validator\Config', ['configFiles' => $this->_configFiles]);
     }
diff --git a/lib/internal/Magento/Framework/Validator/Test/Unit/FactoryTest.php b/lib/internal/Magento/Framework/Validator/Test/Unit/FactoryTest.php
index 222510a23bfc3839b10bb225ea59aeb3a0ff950c..d685e332a56118490139cc668d0026583c572e5b 100644
--- a/lib/internal/Magento/Framework/Validator/Test/Unit/FactoryTest.php
+++ b/lib/internal/Magento/Framework/Validator/Test/Unit/FactoryTest.php
@@ -29,6 +29,8 @@ class FactoryTest extends \PHPUnit_Framework_TestCase
      */
     protected $_validatorConfig;
 
+    private $cache;
+
     /**
      * @var \Magento\Framework\Translate\AdapterInterface|null
      */
@@ -88,6 +90,9 @@ class FactoryTest extends \PHPUnit_Framework_TestCase
         $this->_translateAdapter = $this->getMockBuilder(
             'Magento\Framework\TranslateInterface'
         )->disableOriginalConstructor()->getMock();
+
+        $this->cache = $this->getMockBuilder(\Magento\Framework\Cache\FrontendInterface::class)
+            ->getMockForAbstractClass();
     }
 
     /**
@@ -107,7 +112,7 @@ class FactoryTest extends \PHPUnit_Framework_TestCase
         $factory = new \Magento\Framework\Validator\Factory(
             $this->_objectManager,
             $this->_config,
-            $this->_translateAdapter
+            $this->cache
         );
         $actualConfig = $factory->getValidatorConfig();
         $this->assertInstanceOf(
@@ -147,7 +152,7 @@ class FactoryTest extends \PHPUnit_Framework_TestCase
         $factory = new \Magento\Framework\Validator\Factory(
             $this->_objectManager,
             $this->_config,
-            $this->_translateAdapter
+            $this->cache
         );
         $this->assertInstanceOf(
             'Magento\Framework\Validator\Builder',
@@ -174,7 +179,7 @@ class FactoryTest extends \PHPUnit_Framework_TestCase
         $factory = new \Magento\Framework\Validator\Factory(
             $this->_objectManager,
             $this->_config,
-            $this->_translateAdapter
+            $this->cache
         );
         $this->assertInstanceOf('Magento\Framework\Validator', $factory->createValidator('test', 'class', []));
     }
diff --git a/lib/internal/Magento/Framework/ValidatorFactory.php b/lib/internal/Magento/Framework/ValidatorFactory.php
index 6ec20b848735893f948d14562b2a66591b8dda30..6202a8b52cf3cbc201da18befa7f1e3fd0eccac8 100644
--- a/lib/internal/Magento/Framework/ValidatorFactory.php
+++ b/lib/internal/Magento/Framework/ValidatorFactory.php
@@ -10,7 +10,7 @@ namespace Magento\Framework;
  */
 class ValidatorFactory
 {
-    const DEFAULT_INSTANCE_NAME = 'Magento\Framework\Validator';
+    const DEFAULT_INSTANCE_NAME = Validator::class;
 
     /**
      * Object Manager instance
diff --git a/lib/internal/Magento/Framework/View/Element/AbstractBlock.php b/lib/internal/Magento/Framework/View/Element/AbstractBlock.php
index bfed571826a805cbeb263704644171dae4297cb6..2a48f91117cc15858fd8743b706438ae3ab174b2 100644
--- a/lib/internal/Magento/Framework/View/Element/AbstractBlock.php
+++ b/lib/internal/Magento/Framework/View/Element/AbstractBlock.php
@@ -5,6 +5,8 @@
  */
 namespace Magento\Framework\View\Element;
 
+use Magento\Framework\DataObject\IdentityInterface;
+
 /**
  * Base Content Block class
  *
@@ -965,16 +967,17 @@ abstract class AbstractBlock extends \Magento\Framework\DataObject implements Bl
         if ($this->hasData('cache_key')) {
             return static::CACHE_KEY_PREFIX . $this->getData('cache_key');
         }
+
         /**
          * don't prevent recalculation by saving generated cache key
          * because of ability to render single block instance with different data
          */
         $key = $this->getCacheKeyInfo();
-        //ksort($key);  // ignore order
-        $key = array_values($key);
-        // ignore array keys
+
+        $key = array_values($key);  // ignore array keys
+
         $key = implode('|', $key);
-        $key = sha1($key);
+        $key = sha1($key); // use hashing to hide potentially private data
         return static::CACHE_KEY_PREFIX . $key;
     }
 
@@ -991,6 +994,10 @@ abstract class AbstractBlock extends \Magento\Framework\DataObject implements Bl
             $tags = $this->getData('cache_tags');
         }
         $tags[] = self::CACHE_GROUP;
+
+        if ($this instanceof IdentityInterface) {
+            $tags += $this->getIdentities();
+        }
         return $tags;
     }
 
@@ -1047,7 +1054,7 @@ abstract class AbstractBlock extends \Magento\Framework\DataObject implements Bl
             $data
         );
 
-        $this->_cache->save($data, $cacheKey, $this->getCacheTags(), $this->getCacheLifetime());
+        $this->_cache->save($data, $cacheKey, array_unique($this->getCacheTags()), $this->getCacheLifetime());
         return $this;
     }
 
diff --git a/lib/web/css/docs/source/_dropdowns.less b/lib/web/css/docs/source/_dropdowns.less
index 76924daf5ce24df68352d43997db119e92b896af..bbe3ec05591a7c5c446734bebd9157409f9c30b3 100644
--- a/lib/web/css/docs/source/_dropdowns.less
+++ b/lib/web/css/docs/source/_dropdowns.less
@@ -909,8 +909,8 @@
         @_dropdown-split-toggle-icon-content: @icon-expand,
         @_dropdown-split-toggle-active-icon-content: @icon-collapse,
         @_icon-font-position: before,
-        @_icon-font-color: red,
-        @_icon-font-color-hover: red
+        @_icon-font-color: #f00,
+        @_icon-font-color-hover: #f00
     );
 }
 
diff --git a/lib/web/css/source/lib/variables/_colors.less b/lib/web/css/source/lib/variables/_colors.less
index 95374e5802e6db799efd9467872db5928d19fbec..b886f6d9aa590a31d576d9959fd5a22a500160fb 100644
--- a/lib/web/css/source/lib/variables/_colors.less
+++ b/lib/web/css/source/lib/variables/_colors.less
@@ -61,9 +61,9 @@
 @color-red12: #d10029;
 
 @color-orange-red1: #ff5501;
-@color-orange-red2: #ff5601;
-@color-orange-red3: #ff5700;
-@color-orange-red4: #fc5e10;
+@color-orange-red2: #ff5601; // Legacy orange
+@color-orange-red3: #ff5700; // Legacy orange
+@color-orange-red4: #fc5e10; // Legacy orange
 
 @color-dark-green1: #006400;
 
diff --git a/lib/web/css/source/lib/variables/_rating.less b/lib/web/css/source/lib/variables/_rating.less
index 6a2205ba22e13ddef1af15243b4c7d3a301f8b5a..889d01d3b56847874562c881b6059cadcb4bebac 100644
--- a/lib/web/css/source/lib/variables/_rating.less
+++ b/lib/web/css/source/lib/variables/_rating.less
@@ -14,6 +14,6 @@
 @rating-icon__letter-spacing: -10px;
 @rating-icon__color: @color-gray78;
 
-@rating-icon__active__color: @color-orange-red2;
+@rating-icon__active__color: @color-orange-red1;
 
 @rating-label__hide: false;
diff --git a/nginx.conf.sample b/nginx.conf.sample
index 87b28aa9f691d71666b2a91b433b77b1b4d672c2..04e6dda144b3cc6ea00f36a4004d234d6df20f7f 100644
--- a/nginx.conf.sample
+++ b/nginx.conf.sample
@@ -80,6 +80,12 @@ location /static/ {
     if ($MAGE_MODE = "production") {
         expires max;
     }
+    
+    # Remove signature of the static files that is used to overcome the browser cache
+    location ~ ^/static/version {
+        rewrite ^/static/(version\d*/)?(.*)$ /static/$2 last;
+    }
+    
     location ~* \.(ico|jpg|jpeg|png|gif|svg|js|css|swf|eot|ttf|otf|woff|woff2)$ {
         add_header Cache-Control "public";
         add_header X-Frame-Options "SAMEORIGIN";
@@ -145,9 +151,10 @@ location ~ cron\.php {
 location ~ (index|get|static|report|404|503)\.php$ {
     try_files $uri =404;
     fastcgi_pass   fastcgi_backend;
+    fastcgi_buffers 1024 4k;
 
     fastcgi_param  PHP_FLAG  "session.auto_start=off \n suhosin.session.cryptua=off";
-    fastcgi_param  PHP_VALUE "memory_limit=256M \n max_execution_time=600";
+    fastcgi_param  PHP_VALUE "memory_limit=768M \n max_execution_time=600";
     fastcgi_read_timeout 600s;
     fastcgi_connect_timeout 600s;
     fastcgi_param  MAGE_MODE $MAGE_MODE;
diff --git a/package.json b/package.json.sample
similarity index 100%
rename from package.json
rename to package.json.sample
diff --git a/setup/src/Magento/Setup/Fixtures/StoresFixture.php b/setup/src/Magento/Setup/Fixtures/StoresFixture.php
index fd694bc35de2ce86667d2b487d631714ef170aa9..21b0da0d01a9acaa3e425ccb218d9b66fe54d5a2 100644
--- a/setup/src/Magento/Setup/Fixtures/StoresFixture.php
+++ b/setup/src/Magento/Setup/Fixtures/StoresFixture.php
@@ -33,7 +33,6 @@ class StoresFixture extends Fixture
         /** @var \Magento\Store\Model\StoreManager $storeManager */
         $storeManager = $this->fixtureModel->getObjectManager()->create('Magento\Store\Model\StoreManager');
         /** @var $category \Magento\Catalog\Model\Category */
-        $category = $this->fixtureModel->getObjectManager()->create('Magento\Catalog\Model\Category');
 
         /** @var $defaultWebsite \Magento\Store\Model\Website */
         $defaultWebsite = $storeManager->getWebsite();
@@ -76,19 +75,18 @@ class StoresFixture extends Fixture
         //Create $storeGroupsCount websites
         $websiteNumber = 0;
         for ($i = 0; $i < $storeGroupsCount; $i++) {
+            $category = $this->fixtureModel->getObjectManager()->create('Magento\Catalog\Model\Category');
             $websiteId = $websitesId[$websiteNumber];
             $groupId = null;
-            $parentCategoryId = null;
             $categoryPath = '1';
 
             $storeGroupName = sprintf('Store Group %d - website_id_%d', $i + 1, $websiteId);
 
             if ($i == 0 && $websiteId == $defaultWebsiteId) {
                 $groupId = $defaultStoreGroupId;
-                $parentCategoryId = $defaultParentCategoryId;
                 $categoryPath = '1/' . $defaultParentCategoryId;
+                $category->load($defaultParentCategoryId);
             }
-            $category->load($parentCategoryId);
 
             $category->setName("Category $storeGroupName")
                 ->setPath($categoryPath)
diff --git a/setup/src/Magento/Setup/Module/Di/Code/Scanner/PhpScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Scanner/PhpScanner.php
index d46cbe86b291ee26eb29cf314873cbe99a09edd2..bfce36a8caca204ecaa5dbc6862424181b163b49 100644
--- a/setup/src/Magento/Setup/Module/Di/Code/Scanner/PhpScanner.php
+++ b/setup/src/Magento/Setup/Module/Di/Code/Scanner/PhpScanner.php
@@ -49,7 +49,7 @@ class PhpScanner implements ScannerInterface
                         if (class_exists($missingClassName)) {
                             continue;
                         }
-                    } catch (\Magento\Framework\Exception\LocalizedException $e) {
+                    } catch (\RuntimeException $e) {
                     }
                     $sourceClassName = $this->getSourceClassName($missingClassName, $entityType);
                     if (!class_exists($sourceClassName) && !interface_exists($sourceClassName)) {
diff --git a/setup/src/Magento/Setup/Module/Di/Code/Scanner/XmlScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Scanner/XmlScanner.php
index adc5a452ca9bb4bb8a96b552d9976d6a92954a17..2c0c4ed5915c3ab2290931c48357bd1339ad53ee 100644
--- a/setup/src/Magento/Setup/Module/Di/Code/Scanner/XmlScanner.php
+++ b/setup/src/Magento/Setup/Module/Di/Code/Scanner/XmlScanner.php
@@ -68,7 +68,7 @@ class XmlScanner implements ScannerInterface
             $isClassExists = false;
             try {
                 $isClassExists = class_exists($className);
-            } catch (\Magento\Framework\Exception\LocalizedException $e) {
+            } catch (\RuntimeException $e) {
             }
             if (false === $isClassExists) {
                 if (class_exists($entityName) || interface_exists($entityName)) {