diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/MassDelete.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/MassDelete.php
index 783c78b0f8784cac5dd38dded247708bec394baa..4a312adfb6366089f024dd06a6e33c6ed65e2f14 100644
--- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/MassDelete.php
+++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/MassDelete.php
@@ -6,29 +6,69 @@
  */
 namespace Magento\Catalog\Controller\Adminhtml\Product;
 
+use Magento\Catalog\Model\Resource\Product\Collection;
+use Magento\Framework\Controller\ResultFactory;
+
 class MassDelete extends \Magento\Catalog\Controller\Adminhtml\Product
 {
+    /**
+     * Field id
+     */
+    const ID_FIELD = 'entity_id';
+
+    /**
+     * Redirect url
+     */
+    const REDIRECT_URL = 'catalog/*/index';
+
+    /**
+     * Resource collection
+     *
+     * @var string
+     */
+    protected $collection = 'Magento\Catalog\Model\Resource\Product\Collection';
+
     /**
      * @return \Magento\Backend\Model\View\Result\Redirect
      */
     public function execute()
     {
-        $productIds = $this->getRequest()->getParam('selected');
-        if (!is_array($productIds) || empty($productIds)) {
-            $this->messageManager->addError(__('Please select product(s).'));
-        } else {
-            try {
-                foreach ($productIds as $productId) {
-                    $product = $this->_objectManager->get('Magento\Catalog\Model\Product')->load($productId);
-                    $product->delete();
-                }
-                $this->messageManager->addSuccess(
-                    __('A total of %1 record(s) have been deleted.', count($productIds))
-                );
-            } catch (\Exception $e) {
-                $this->messageManager->addError($e->getMessage());
+        $selected = $this->getRequest()->getParam('selected');
+        $excluded = $this->getRequest()->getParam('excluded');
+
+        $collection = $this->_objectManager->create($this->collection);
+        try {
+            if (!empty($excluded)) {
+                $collection->addFieldToFilter(static::ID_FIELD, ['nin' => $excluded]);
+                $this->massAction($collection);
+            } elseif (!empty($selected)) {
+                $collection->addFieldToFilter(static::ID_FIELD, ['in' => $selected]);
+                $this->massAction($collection);
+            } else {
+                $this->messageManager->addError(__('Please select product(s).'));
             }
+        } catch (\Exception $e) {
+            $this->messageManager->addError($e->getMessage());
+        }
+
+        /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */
+        $resultRedirect = $this->resultFactory->create(ResultFactory::TYPE_REDIRECT);
+        return $resultRedirect->setPath(static::REDIRECT_URL);
+    }
+
+    /**
+     * Cancel selected orders
+     *
+     * @param Collection $collection
+     * @return void
+     */
+    protected function massAction($collection)
+    {
+        $count = 0;
+        foreach ($collection->getItems() as $product) {
+            $product->delete();
+            ++$count;
         }
-        return $this->resultRedirectFactory->create()->setPath('catalog/*/index');
+        $this->messageManager->addSuccess(__('A total of %1 record(s) have been deleted.', $count));
     }
 }
diff --git a/app/code/Magento/Catalog/Plugin/Model/Product/Action/UpdateAttributesFlushCache.php b/app/code/Magento/Catalog/Plugin/Model/Product/Action/UpdateAttributesFlushCache.php
new file mode 100644
index 0000000000000000000000000000000000000000..22133ccc921a18fe7e62c4ef658390f2c75a2a91
--- /dev/null
+++ b/app/code/Magento/Catalog/Plugin/Model/Product/Action/UpdateAttributesFlushCache.php
@@ -0,0 +1,61 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Catalog\Plugin\Model\Product\Action;
+
+use Magento\Catalog\Model\Product;
+use Magento\Catalog\Model\Product\Action;
+use Magento\Indexer\Model\CacheContext;
+use Magento\Framework\Event\ManagerInterface as EventManager;
+
+class UpdateAttributesFlushCache
+{
+    /**
+     * @var CacheContext
+     */
+    protected $cacheContext;
+
+    /**
+     * @var EventManager
+     */
+    protected $eventManager;
+
+    /**
+     * @param CacheContext $cacheContext
+     * @param EventManager $eventManager
+     */
+    public function __construct(
+        CacheContext $cacheContext,
+        EventManager $eventManager
+    ) {
+        $this->cacheContext = $cacheContext;
+        $this->eventManager = $eventManager;
+    }
+
+    /**
+     * @param Action $subject
+     * @param \Closure $proceed
+     * @param array $productIds
+     * @param array $attrData
+     * @param int $storeId
+     * @return Action
+     *
+     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+     */
+    public function aroundUpdateAttributes(
+        Action $subject,
+        \Closure $proceed,
+        $productIds,
+        $attrData,
+        $storeId
+    ) {
+        $returnValue = $proceed($productIds, $attrData, $storeId);
+
+        $this->cacheContext->registerEntities(Product::CACHE_TAG, $productIds);
+        $this->eventManager->dispatch('clean_cache_by_tags', ['object' => $this->cacheContext]);
+
+        return $returnValue;
+    }
+}
diff --git a/app/code/Magento/Catalog/Test/Unit/Plugin/Model/Product/Action/UpdateAttributesFlushCacheTest.php b/app/code/Magento/Catalog/Test/Unit/Plugin/Model/Product/Action/UpdateAttributesFlushCacheTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..3d70aac87798ac25f787812fa5ce1b0460ada648
--- /dev/null
+++ b/app/code/Magento/Catalog/Test/Unit/Plugin/Model/Product/Action/UpdateAttributesFlushCacheTest.php
@@ -0,0 +1,46 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Catalog\Test\Unit\Plugin\Model\Product\Action;
+
+use Magento\Catalog\Model\Product;
+
+class UpdateAttributesFlushCacheTest extends \PHPUnit_Framework_TestCase
+{
+    public function testAroundUpdateAttributes()
+    {
+        $productIds = [1, 2, 3];
+        $attrData = [];
+        $storeId = 1;
+
+        $productActionMock = $this->getMock('Magento\Catalog\Model\Product\Action', [], [], '', false);
+
+        $cacheContextMock = $this->getMock('Magento\Indexer\Model\CacheContext', [], [], '', false);
+        $cacheContextMock->expects($this->once())
+            ->method('registerEntities')
+            ->with(Product::CACHE_TAG, $productIds);
+
+
+        $eventManagerMock = $this->getMock('Magento\Framework\Event\ManagerInterface');
+        $eventManagerMock->expects($this->once())
+            ->method('dispatch')
+            ->with('clean_cache_by_tags', ['object' => $cacheContextMock]);
+
+        $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
+        $model = $objectManager->getObject(
+            'Magento\Catalog\Plugin\Model\Product\Action\UpdateAttributesFlushCache',
+            [
+                'cacheContext' => $cacheContextMock,
+                'eventManager' => $eventManagerMock,
+            ]
+        );
+
+        $closureMock = function () use ($productActionMock) {
+            return $productActionMock;
+        };
+
+        $model->aroundUpdateAttributes($productActionMock, $closureMock, $productIds, $attrData, $storeId);
+    }
+}
diff --git a/app/code/Magento/Catalog/etc/adminhtml/di.xml b/app/code/Magento/Catalog/etc/adminhtml/di.xml
index dd16554ac015f2044bb7984990b9e8ca4f0301f5..5cf13196cbd26779ea6c7619a34636e9aef6163b 100644
--- a/app/code/Magento/Catalog/etc/adminhtml/di.xml
+++ b/app/code/Magento/Catalog/etc/adminhtml/di.xml
@@ -76,4 +76,7 @@
             </argument>
         </arguments>
     </type>
+    <type name="Magento\Catalog\Model\Product\Action">
+        <plugin name="invalidate_pagecache_after_update_product_attributes" type="Magento\Catalog\Plugin\Model\Product\Action\UpdateAttributesFlushCache"/>
+    </type>
 </config>
diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/custom-options.js b/app/code/Magento/Catalog/view/adminhtml/web/js/custom-options.js
index cb65d9dcee1c12cdb1eb76ba6cc20c6da3b5695e..b7a16ce3db853a02f454b58af0d72e6e6d32dc31 100644
--- a/app/code/Magento/Catalog/view/adminhtml/web/js/custom-options.js
+++ b/app/code/Magento/Catalog/view/adminhtml/web/js/custom-options.js
@@ -132,6 +132,11 @@ define([
                             at: 'center top',
                             of: 'body'
                         },
+                        create: function (event, ui) {
+                            $(document).on('click', '#productGrid_massaction-form button', function () {
+                                $('#import-custom-options-apply-button').trigger('click', 'massActionTrigger');
+                            });
+                        },
                         open: function () {
                             $(this).closest('.ui-dialog').addClass('ui-dialog-active');
 
@@ -195,19 +200,14 @@ define([
                             }]
                     });
                     importContainer.load(
-                        this.options.productGridUrl, {
-                            form_key: this.options.formKey
-                        },
+                        this.options.productGridUrl,
+                        {form_key: this.options.formKey},
                         function () {
                             importContainer.dialog('open');
                         }
                     );
                 },
 
-                'click #productGrid_massaction-form button': function () {
-                    $('#import-custom-options-apply-button').trigger('click', 'massActionTrigger');
-                },
-
                 /**
                  * Change custom option type
                  */
@@ -470,4 +470,4 @@ define([
         }
     });
 
-});
\ No newline at end of file
+});
diff --git a/app/code/Magento/Catalog/view/adminhtml/web/product/product.css b/app/code/Magento/Catalog/view/adminhtml/web/product/product.css
index e383de8ce411d5c38a5f1e8b9e59c7cc11ee2599..fce4af6f57f8f08d8ed05262f303fb170c6e870a 100644
--- a/app/code/Magento/Catalog/view/adminhtml/web/product/product.css
+++ b/app/code/Magento/Catalog/view/adminhtml/web/product/product.css
@@ -280,13 +280,6 @@
     position: static;
 }
 
-/* Change Attribute Set */
-.admin__scope-old #product_info_tabs li.removed,
-.admin__scope-old div.removed,
-.admin__scope-old .field.removed {
-    display: none !important;
-}
-
 /*
     Custom Options
 -------------------------------------- */
diff --git a/app/code/Magento/Catalog/view/base/web/js/price-box.js b/app/code/Magento/Catalog/view/base/web/js/price-box.js
index c2f0e23951cfbb1be1884418627bc1afaf69bcd4..4a5e3a2f8f0ab7cfdad559f8d366f528a4e94c14 100644
--- a/app/code/Magento/Catalog/view/base/web/js/price-box.js
+++ b/app/code/Magento/Catalog/view/base/web/js/price-box.js
@@ -97,11 +97,11 @@ define([
                         'amount': 0,
                         'adjustments': {}
                     };
-                    additionalPrice[priceCode].amount = parseInt(additionalPrice[priceCode].amount || 0, 10)
+                    additionalPrice[priceCode].amount =  0 + (additionalPrice[priceCode].amount || 0)
                         + priceValue.amount;
                     _.each(priceValue.adjustments, function (adValue, adCode) {
-                        additionalPrice[priceCode].adjustments[adCode] =
-                            parseInt(additionalPrice[priceCode].adjustments[adCode] || 0, 10) + adValue;
+                        additionalPrice[priceCode].adjustments[adCode] = 0
+                            + (additionalPrice[priceCode].adjustments[adCode] || 0) + adValue;
                     });
                 });
             });
@@ -117,9 +117,9 @@ define([
                     origin.adjustments = origin.adjustments || {};
                     final.adjustments = final.adjustments || {};
 
-                    final.amount = parseInt(origin.amount, 10) + option.amount;
+                    final.amount = 0 + origin.amount + option.amount;
                     _.each(option.adjustments, function (pa, paCode) {
-                        final.adjustments[paCode] = parseInt(origin.adjustments[paCode] || 0, 10) + pa;
+                        final.adjustments[paCode] = 0 + (origin.adjustments[paCode] || 0) + pa;
                     });
                 }, this);
             }
diff --git a/app/code/Magento/Catalog/view/frontend/web/js/catalog-add-to-cart.js b/app/code/Magento/Catalog/view/frontend/web/js/catalog-add-to-cart.js
index b774dd8090d1474c4ebf777b83a1c9da7cca66f1..02898a8e87fff11dbfb6607fd39224bcdf9d3395 100644
--- a/app/code/Magento/Catalog/view/frontend/web/js/catalog-add-to-cart.js
+++ b/app/code/Magento/Catalog/view/frontend/web/js/catalog-add-to-cart.js
@@ -74,8 +74,8 @@ define([
                         $('body').trigger(self.options.processStop);
                     }
 
-                    if (res.redirect) {
-                        window.location = res.redirect;
+                    if (res.backUrl) {
+                        window.location = res.backUrl;
                         return;
                     }
                     if (res.messages) {
diff --git a/app/code/Magento/CatalogInventory/Model/Indexer/Stock/AbstractAction.php b/app/code/Magento/CatalogInventory/Model/Indexer/Stock/AbstractAction.php
index 573997db6c7a9467fb9b258776e3b23000b495f4..b75aabfcb45a857de4da641b4a8a9d9f944f700b 100644
--- a/app/code/Magento/CatalogInventory/Model/Indexer/Stock/AbstractAction.php
+++ b/app/code/Magento/CatalogInventory/Model/Indexer/Stock/AbstractAction.php
@@ -8,6 +8,8 @@
 
 namespace Magento\CatalogInventory\Model\Indexer\Stock;
 
+use Magento\Catalog\Model\Category;
+
 /**
  * Abstract action reindex class
  *
@@ -52,19 +54,36 @@ abstract class AbstractAction
      */
     protected $_isNeedUseIdxTable = false;
 
+    /**
+     * @var \Magento\Indexer\Model\CacheContext
+     */
+    private $cacheContext;
+
+    /**
+     * @var \Magento\Framework\Event\ManagerInterface
+     */
+    private $eventManager;
+
+
     /**
      * @param \Magento\Framework\App\Resource $resource
      * @param \Magento\CatalogInventory\Model\Resource\Indexer\StockFactory $indexerFactory
      * @param \Magento\Catalog\Model\Product\Type $catalogProductType
+     * @param \Magento\Indexer\Model\CacheContext $cacheContext
+     * @param \Magento\Framework\Event\ManagerInterface $eventManager
      */
     public function __construct(
         \Magento\Framework\App\Resource $resource,
         \Magento\CatalogInventory\Model\Resource\Indexer\StockFactory $indexerFactory,
-        \Magento\Catalog\Model\Product\Type $catalogProductType
+        \Magento\Catalog\Model\Product\Type $catalogProductType,
+        \Magento\Indexer\Model\CacheContext $cacheContext,
+        \Magento\Framework\Event\ManagerInterface $eventManager
     ) {
         $this->_resource = $resource;
         $this->_indexerFactory = $indexerFactory;
         $this->_catalogProductType = $catalogProductType;
+        $this->cacheContext = $cacheContext;
+        $this->eventManager = $eventManager;
     }
 
     /**
@@ -228,6 +247,16 @@ abstract class AbstractAction
             }
         }
 
+        $select = $adapter->select()
+            ->distinct(true)
+            ->from($this->_getTable('catalog_category_product'), ['category_id'])
+            ->where('product_id IN(?)', $processIds);
+
+        $affectedCategories = $adapter->fetchCol($select);
+        $this->cacheContext->registerEntities(Category::CACHE_TAG, $affectedCategories);
+
+        $this->eventManager->dispatch('clean_cache_by_tags', ['object' => $this->cacheContext]);
+
         return $this;
     }
 
diff --git a/app/code/Magento/CatalogInventory/Test/Unit/Model/Indexer/Stock/Action/FullTest.php b/app/code/Magento/CatalogInventory/Test/Unit/Model/Indexer/Stock/Action/FullTest.php
index a096f71925e83c08696139a9d64d5abed10ec239..af4fb3bba4dabb88fe5099709a28ce1cf38baa4e 100644
--- a/app/code/Magento/CatalogInventory/Test/Unit/Model/Indexer/Stock/Action/FullTest.php
+++ b/app/code/Magento/CatalogInventory/Test/Unit/Model/Indexer/Stock/Action/FullTest.php
@@ -25,20 +25,23 @@ class FullTest extends \PHPUnit_Framework_TestCase
         $adapterMock = $this->getMock('Magento\Framework\DB\Adapter\AdapterInterface');
 
         $exceptionMessage = 'exception message';
-        $exception = new \Exception($exceptionMessage);
 
         $adapterMock->expects($this->once())
             ->method('delete')
-            ->will($this->throwException($exception));
+            ->will($this->throwException(new \Exception($exceptionMessage)));
 
         $resourceMock->expects($this->any())
             ->method('getConnection')
             ->will($this->returnValue($adapterMock));
 
-        $model = new \Magento\CatalogInventory\Model\Indexer\Stock\Action\Full(
-            $resourceMock,
-            $indexerFactoryMock,
-            $productTypeMock
+        $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
+        $model = $objectManager->getObject(
+            'Magento\CatalogInventory\Model\Indexer\Stock\Action\Full',
+            [
+               'resource' => $resourceMock,
+               'indexerFactory' => $indexerFactoryMock,
+               'catalogProductType' => $productTypeMock,
+            ]
         );
 
         $this->setExpectedException('\Magento\Framework\Exception\LocalizedException', $exceptionMessage);
diff --git a/app/code/Magento/Checkout/Controller/Cart/Add.php b/app/code/Magento/Checkout/Controller/Cart/Add.php
index 97c2a346efc987f653bfec9d76659ebc9b080824..05bafe1daa1ae6d614fadff393de49607e1194ba 100644
--- a/app/code/Magento/Checkout/Controller/Cart/Add.php
+++ b/app/code/Magento/Checkout/Controller/Cart/Add.php
@@ -169,7 +169,7 @@ class Add extends \Magento\Checkout\Controller\Cart
         $result = [];
 
         if ($backUrl || $backUrl = $this->getBackUrl()) {
-            $result['redirect'] = $backUrl;
+            $result['backUrl'] = $backUrl;
         } else {
             if ($product && !$product->getIsSalable()) {
                 $result['product'] = [
diff --git a/app/code/Magento/Customer/view/frontend/web/js/customer-data.js b/app/code/Magento/Customer/view/frontend/web/js/customer-data.js
index 3fc839a52be45cbd2cf3aa9e67fa1be27c052875..2ab04102c3dc2e348619af7f728e6f1eff5c6181 100644
--- a/app/code/Magento/Customer/view/frontend/web/js/customer-data.js
+++ b/app/code/Magento/Customer/view/frontend/web/js/customer-data.js
@@ -134,7 +134,7 @@ define([
             var sections = sectionConfig.getAffectedSections(settings.url);
             if (sections) {
                 customerData.invalidate(sections);
-                var redirects = ['redirect'];
+                var redirects = ['redirect', 'backUrl'];
                 if (_.isObject(xhr.responseJSON) && !_.isEmpty(_.pick(xhr.responseJSON, redirects))) {
                     return ;
                 }
diff --git a/app/code/Magento/Ui/etc/di.xml b/app/code/Magento/Ui/etc/di.xml
index d81fb2c0bd00a7d2681ffdcb66148924494922bd..df69d1edebb07d1c3c082f2b6fd0f8920fea7c9d 100644
--- a/app/code/Magento/Ui/etc/di.xml
+++ b/app/code/Magento/Ui/etc/di.xml
@@ -180,7 +180,7 @@
     <type name="Magento\Framework\Data\Argument\Interpreter\Composite">
         <arguments>
             <argument name="interpreters" xsi:type="array">
-                <item name="object" xsi:type="object">Magento\Framework\Data\Argument\Interpreter\Object</item>
+                <item name="object" xsi:type="object">configurableObjectArgumentInterpreterProxy</item>
                 <item name="configurableObject" xsi:type="object">configurableObjectArgumentInterpreterProxy</item>
                 <item name="array" xsi:type="object">arrayArgumentInterpreterProxy</item>
                 <item name="boolean" xsi:type="object">Magento\Framework\Data\Argument\Interpreter\Boolean</item>
diff --git a/app/design/adminhtml/Magento/backend/Magento_Catalog/web/css/source/_module.less b/app/design/adminhtml/Magento/backend/Magento_Catalog/web/css/source/_module.less
index bfdae677b798e4b9b90e54c00a62ee0d84bc1e2b..8fdf8ecbf2e8750384aa9f3b0c322ef90e17ea7b 100644
--- a/app/design/adminhtml/Magento/backend/Magento_Catalog/web/css/source/_module.less
+++ b/app/design/adminhtml/Magento/backend/Magento_Catalog/web/css/source/_module.less
@@ -10,3 +10,10 @@
         }
     }
 }
+
+/* Change Attribute Set */
+#product_info_tabs li.removed,
+div.removed,
+.field.removed {
+  display: none !important;
+}
diff --git a/lib/internal/Magento/Framework/View/Element/UiComponent/Argument/Interpreter/ConfigurableObject.php b/lib/internal/Magento/Framework/View/Element/UiComponent/Argument/Interpreter/ConfigurableObject.php
index f2d2779be11166b93310f688199c584c3b63c44f..78e4e7a15ff84cd5a89547d2ffa6ede3d2a48cce 100644
--- a/lib/internal/Magento/Framework/View/Element/UiComponent/Argument/Interpreter/ConfigurableObject.php
+++ b/lib/internal/Magento/Framework/View/Element/UiComponent/Argument/Interpreter/ConfigurableObject.php
@@ -40,17 +40,22 @@ class ConfigurableObject implements InterpreterInterface
      */
     public function evaluate(array $data)
     {
-        if (!isset($data['argument'])) {
-            throw new \InvalidArgumentException('Node "argument" required for this type.');
+        if (isset($data['value'])) {
+            $className = $data['value'];
+            $arguments = [];
+        } else {
+            if (!isset($data['argument'])) {
+                throw new \InvalidArgumentException('Node "argument" required for this type.');
+            }
+            foreach ($data['argument'] as $name => $argument) {
+                $arguments[$name] = $this->argumentInterpreter->evaluate($argument);
+            }
+            if (!isset($arguments['class'])) {
+                throw new \InvalidArgumentException('Node "argument" with name "class" is required for this type.');
+            }
+            $className = $arguments['class'];
+            unset($arguments['class']);
         }
-        foreach ($data['argument'] as $name => $argument) {
-            $arguments[$name] = $this->argumentInterpreter->evaluate($argument);
-        }
-        if (!isset($arguments['class'])) {
-            throw new \InvalidArgumentException('Node "argument" with name "class" is required for this type.');
-        }
-        $className = $arguments['class'];
-        unset($arguments['class']);
 
         return $this->objectManager->create($className, $arguments);
     }