diff --git a/app/code/Magento/Backend/Block/Widget/Button/Item.php b/app/code/Magento/Backend/Block/Widget/Button/Item.php
index a500f836312fb3edacd942cc80e24e0582d2094e..73ed2c5f50e6993e5ebbff026d0b89194abcc52b 100644
--- a/app/code/Magento/Backend/Block/Widget/Button/Item.php
+++ b/app/code/Magento/Backend/Block/Widget/Button/Item.php
@@ -7,12 +7,12 @@
 namespace Magento\Backend\Block\Widget\Button;
 
 /**
- * @method string getButtonKey
- * @method string getRegion
- * @method string getName
- * @method int getLevel
- * @method int getSortOrder
- * @method string getTitle
+ * @method string getButtonKey()
+ * @method string getRegion()
+ * @method string getName()
+ * @method int getLevel()
+ * @method int getSortOrder()
+ * @method string getTitle()
  */
 class Item extends \Magento\Framework\DataObject
 {
diff --git a/app/code/Magento/Backend/Block/Widget/Button/Toolbar/Container.php b/app/code/Magento/Backend/Block/Widget/Button/Toolbar/Container.php
index e7c199cf4787ff9aedca6aa13061fddfafe5d20c..959ef806acfa15571046dbaf9e8b6b3055ef6d0b 100644
--- a/app/code/Magento/Backend/Block/Widget/Button/Toolbar/Container.php
+++ b/app/code/Magento/Backend/Block/Widget/Button/Toolbar/Container.php
@@ -9,8 +9,8 @@ namespace Magento\Backend\Block\Widget\Button\Toolbar;
 use Magento\Backend\Block\Widget\Button\ContextInterface;
 
 /**
- * @method \Magento\Backend\Block\Widget\Button\Item getButtonItem
- * @method ContextInterface getContext
+ * @method \Magento\Backend\Block\Widget\Button\Item getButtonItem()
+ * @method ContextInterface getContext()
  * @method ContextInterface setContext(ContextInterface $context)
  */
 class Container extends \Magento\Framework\View\Element\AbstractBlock
diff --git a/app/code/Magento/Catalog/Block/Adminhtml/Product/Attribute/Edit/Tab/Advanced.php b/app/code/Magento/Catalog/Block/Adminhtml/Product/Attribute/Edit/Tab/Advanced.php
index dec89ab52ff89d9275791fde97f7f2d4024de97d..5ed9016a59f6a799258ad17cee50c43c614ead97 100644
--- a/app/code/Magento/Catalog/Block/Adminhtml/Product/Attribute/Edit/Tab/Advanced.php
+++ b/app/code/Magento/Catalog/Block/Adminhtml/Product/Attribute/Edit/Tab/Advanced.php
@@ -31,12 +31,18 @@ class Advanced extends Generic
      */
     protected $_yesNo;
 
+    /**
+     * @var array
+     */
+    protected $disableScopeChangeList;
+
     /**
      * @param \Magento\Backend\Block\Template\Context $context
      * @param \Magento\Framework\Registry $registry
      * @param \Magento\Framework\Data\FormFactory $formFactory
      * @param Yesno $yesNo
      * @param Data $eavData
+     * @param array $disableScopeChangeList
      * @param array $data
      */
     public function __construct(
@@ -45,10 +51,12 @@ class Advanced extends Generic
         \Magento\Framework\Data\FormFactory $formFactory,
         Yesno $yesNo,
         Data $eavData,
+        array $disableScopeChangeList = ['sku'],
         array $data = []
     ) {
         $this->_yesNo = $yesNo;
         $this->_eavData = $eavData;
+        $this->disableScopeChangeList = $disableScopeChangeList;
         parent::__construct($context, $registry, $formFactory, $data);
     }
 
@@ -229,7 +237,7 @@ class Advanced extends Generic
         );
 
         $this->_eventManager->dispatch('product_attribute_form_build', ['form' => $form]);
-        if ($attributeObject->getId() && !$attributeObject->getIsUserDefined()) {
+        if (in_array($attributeObject->getAttributeCode(), $this->disableScopeChangeList)) {
             $form->getElement('is_global')->setDisabled(1);
         }
         $this->setForm($form);
diff --git a/app/code/Magento/Catalog/Block/Adminhtml/Product/Attribute/Edit/Tab/Options.php b/app/code/Magento/Catalog/Block/Adminhtml/Product/Attribute/Edit/Tab/Options.php
index eabcac9f715747f01c211f9d5fc7d6fcee0bf718..b08fdb85de106f3cb0197da629036350c5f90571 100644
--- a/app/code/Magento/Catalog/Block/Adminhtml/Product/Attribute/Edit/Tab/Options.php
+++ b/app/code/Magento/Catalog/Block/Adminhtml/Product/Attribute/Edit/Tab/Options.php
@@ -8,7 +8,7 @@
  * Product attribute add/edit form options tab
  *
  * @method \Magento\Catalog\Block\Adminhtml\Product\Attribute\Edit\Tab\Options setReadOnly(bool $value)
- * @method null|bool getReadOnly
+ * @method null|bool getReadOnly()
  *
  * @author     Magento Core Team <core@magentocommerce.com>
  */
diff --git a/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Tab/Options/Option.php b/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Tab/Options/Option.php
index f507d9ee30ec0bf3a8094bdc5fd7796f047e3cd3..7dbacd96990b59888da7ecccb736760b1836c5a4 100644
--- a/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Tab/Options/Option.php
+++ b/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Tab/Options/Option.php
@@ -461,4 +461,14 @@ class Option extends Widget
     {
         return $this->getUrl('catalog/*/customOptions');
     }
+
+    /**
+     * Return current product id
+     *
+     * @return null|int
+     */
+    public function getCurrentProductId()
+    {
+        return $this->getProduct()->getId();
+    }
 }
diff --git a/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Tab/Options/Popup/Grid.php b/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Tab/Options/Popup/Grid.php
index 53bcc298732f9d804846b252f950e4e9c5d3b936..646db241f82248d612d0d34e8d1dd74745cd85ef 100644
--- a/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Tab/Options/Popup/Grid.php
+++ b/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Tab/Options/Popup/Grid.php
@@ -62,7 +62,19 @@ class Grid extends \Magento\Catalog\Block\Adminhtml\Product\Grid
     protected function _prepareCollection()
     {
         parent::_prepareCollection();
-        $this->getCollection()->addFieldToFilter('has_options', 1);
+
+        if (null !== $this->getRequest()->getParam('current_product_id')) {
+            $this->getCollection()->getSelect()->where(
+                'e.entity_id != ?',
+                $this->getRequest()->getParam('current_product_id')
+            );
+        }
+
+        $this->getCollection()->getSelect()->distinct()->join(
+            ['opt' => $this->getCollection()->getTable('catalog_product_option')],
+            'opt.product_id = e.entity_id',
+            null
+        );
 
         return $this;
     }
diff --git a/app/code/Magento/Catalog/Model/CategoryLinkManagement.php b/app/code/Magento/Catalog/Model/CategoryLinkManagement.php
index 0c2c324bd8e2c931b57babe59147837b4feb193b..4ff351dc3d735b79ad3ee2adf3d9275ceb54c0c3 100644
--- a/app/code/Magento/Catalog/Model/CategoryLinkManagement.php
+++ b/app/code/Magento/Catalog/Model/CategoryLinkManagement.php
@@ -36,20 +36,20 @@ class CategoryLinkManagement implements \Magento\Catalog\Api\CategoryLinkManagem
     public function getAssignedProducts($categoryId)
     {
         $category = $this->categoryRepository->get($categoryId);
-        $productsPosition = $category->getProductsPosition();
 
-        /** @var \Magento\Framework\Data\Collection\AbstractDb $products */
+        /** @var \Magento\Catalog\Model\ResourceModel\Product\Collection $products */
         $products = $category->getProductCollection();
+        $products->addFieldToSelect('position');
 
         /** @var \Magento\Catalog\Api\Data\CategoryProductLinkInterface[] $links */
         $links = [];
 
         /** @var \Magento\Catalog\Model\Product $product */
-        foreach ($products->getItems() as $productId => $product) {
+        foreach ($products->getItems() as $product) {
             /** @var \Magento\Catalog\Api\Data\CategoryProductLinkInterface $link */
             $link = $this->productLinkFactory->create();
             $link->setSku($product->getSku())
-                ->setPosition($productsPosition[$productId])
+                ->setPosition($product->getData('cat_index_position'))
                 ->setCategoryId($category->getId());
             $links[] = $link;
         }
diff --git a/app/code/Magento/Catalog/Model/Config/Source/Product/Options/Type.php b/app/code/Magento/Catalog/Model/Config/Source/Product/Options/Type.php
index 5d0c1f24872a76b3345d9a4995535c180f4931e8..ca62402f23a378129cac9cd10f43a42a5a463aa7 100644
--- a/app/code/Magento/Catalog/Model/Config/Source/Product/Options/Type.php
+++ b/app/code/Magento/Catalog/Model/Config/Source/Product/Options/Type.php
@@ -43,7 +43,7 @@ class Type implements \Magento\Framework\Option\ArrayInterface
                 $types[] = ['label' => __($type['label']), 'value' => $type['name']];
             }
             if (count($types)) {
-                $groups[] = ['label' => __($option['label']), 'value' => $types];
+                $groups[] = ['label' => __($option['label']), 'value' => $types, 'optgroup-name' => $option['label']];
             }
         }
 
diff --git a/app/code/Magento/Catalog/Model/Product.php b/app/code/Magento/Catalog/Model/Product.php
index 99709b513ca2cf08167a07f76ac22169ec2001b7..63045d6d5e26f0be48e8602ff7aa5b0430ed263e 100644
--- a/app/code/Magento/Catalog/Model/Product.php
+++ b/app/code/Magento/Catalog/Model/Product.php
@@ -25,7 +25,7 @@ use Magento\Catalog\Api\Data\ProductAttributeMediaGalleryEntryExtensionFactory;
  * @method array getAssociatedProductIds()
  * @method Product setNewVariationsAttributeSetId(int $value)
  * @method int getNewVariationsAttributeSetId()
- * @method int getPriceType
+ * @method int getPriceType()
  * @method \Magento\Catalog\Model\ResourceModel\Product\Collection getCollection()
  * @method string getUrlKey()
  * @method Product setUrlKey(string $urlKey)
diff --git a/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Media.php b/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Media.php
index 8ca5ffbc429e567ddc1b37f5c24b482e62ec5335..f7fd135a134061614cbbc4b7d6c8557289cd0ad8 100644
--- a/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Media.php
+++ b/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Media.php
@@ -85,7 +85,7 @@ class Media extends Product\Attribute\Backend\AbstractMedia
             // For duplicating we need copy original images.
             $duplicate = [];
             foreach ($value['images'] as &$image) {
-                if (empty($image['value_id'])) {
+                if (empty($image['value_id']) || !empty($image['removed'])) {
                     continue;
                 }
                 $duplicate[$image['value_id']] = $this->copyImage($image['file']);
diff --git a/app/code/Magento/Catalog/Model/Product/Option/Type/File/ValidatorFile.php b/app/code/Magento/Catalog/Model/Product/Option/Type/File/ValidatorFile.php
index a9f7a1188c554ddfbd13abfd7aa2d57bdbc37ba1..1b3b2c5f0d8f3f2f824b16e2dde53d08e91a5505 100644
--- a/app/code/Magento/Catalog/Model/Product/Option/Type/File/ValidatorFile.php
+++ b/app/code/Magento/Catalog/Model/Product/Option/Type/File/ValidatorFile.php
@@ -21,21 +21,21 @@ class ValidatorFile extends Validator
      *
      * @var string
      */
-    protected $path = '/custom_options';
+    protected $path = 'custom_options';
 
     /**
      * Relative path for quote folder
      *
      * @var string
      */
-    protected $quotePath = '/custom_options/quote';
+    protected $quotePath = 'custom_options/quote';
 
     /**
      * Relative path for order folder
      *
      * @var string
      */
-    protected $orderPath = '/custom_options/order';
+    protected $orderPath = 'custom_options/order';
 
     /**
      * @var \Magento\Framework\Filesystem\Directory\WriteInterface
@@ -175,12 +175,12 @@ class ValidatorFile extends Validator
                     $_height = $imageSize[1];
                 }
             }
-            $uri = $this->filesystem->getUri(DirectoryList::MEDIA);
+
             $userValue = [
                 'type' => $fileInfo['type'],
                 'title' => $fileInfo['name'],
-                'quote_path' => $uri . $this->quotePath . $filePath,
-                'order_path' => $uri . $this->orderPath . $filePath,
+                'quote_path' => $this->quotePath . $filePath,
+                'order_path' => $this->orderPath . $filePath,
                 'fullpath' => $fileFullPath,
                 'size' => $fileInfo['size'],
                 'width' => $_width,
diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Category/Flat.php b/app/code/Magento/Catalog/Model/ResourceModel/Category/Flat.php
index 82000fb03d1703e6e34dfeb854e6d1ad6aca80ee..30c9476931f10aa0daf23dbbf1ff389bb02d2abd 100644
--- a/app/code/Magento/Catalog/Model/ResourceModel/Category/Flat.php
+++ b/app/code/Magento/Catalog/Model/ResourceModel/Category/Flat.php
@@ -671,4 +671,23 @@ class Flat extends \Magento\Indexer\Model\ResourceModel\AbstractResource
 
         return $this->getConnection()->fetchCol($select);
     }
+
+    /**
+     * Get positions of associated to category products
+     *
+     * @param \Magento\Catalog\Model\Category $category
+     * @return array
+     */
+    public function getProductsPosition($category)
+    {
+        $select = $this->getConnection()->select()->from(
+            $this->getTable('catalog_category_product'),
+            ['product_id', 'position']
+        )->where(
+            'category_id = :category_id'
+        );
+        $bind = ['category_id' => (int)$category->getId()];
+
+        return $this->getConnection()->fetchPairs($select, $bind);
+    }
 }
diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/Attribute/Backend/Media.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/Attribute/Backend/Media.php
index a77ea68ae16d5e42855e7e422ff3662eeba5bcf6..0ac7a8c1a7bf612d352c6ea352a879c40f303abe 100644
--- a/app/code/Magento/Catalog/Model/ResourceModel/Product/Attribute/Backend/Media.php
+++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/Attribute/Backend/Media.php
@@ -324,11 +324,12 @@ class Media extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb
         foreach ($this->getConnection()->fetchAll($select) as $row) {
             $data = [
                 'attribute_id' => $attributeId,
-                'entity_id' => $newProductId,
                 'value' => isset($newFiles[$row['value_id']]) ? $newFiles[$row['value_id']] : $row['value'],
             ];
 
             $valueIdMap[$row['value_id']] = $this->insertGallery($data);
+            $this->bindValueToEntity($valueIdMap[$row['value_id']], $newProductId);
+
         }
 
         if (count($valueIdMap) == 0) {
@@ -344,6 +345,8 @@ class Media extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb
         );
 
         foreach ($this->getConnection()->fetchAll($select) as $row) {
+            unset($row['record_id']);
+            $row['entity_id'] = $newProductId;
             $row['value_id'] = $valueIdMap[$row['value_id']];
             $this->insertGalleryValueInStore($row);
         }
diff --git a/app/code/Magento/Catalog/Test/Unit/Block/Adminhtml/Product/Attribute/Edit/Tab/AdvancedTest.php b/app/code/Magento/Catalog/Test/Unit/Block/Adminhtml/Product/Attribute/Edit/Tab/AdvancedTest.php
index a54834d4f56966f448480c1000f1f98ba45c4356..7408df0ede1d678644939f92c9055007e97e3759 100644
--- a/app/code/Magento/Catalog/Test/Unit/Block/Adminhtml/Product/Attribute/Edit/Tab/AdvancedTest.php
+++ b/app/code/Magento/Catalog/Test/Unit/Block/Adminhtml/Product/Attribute/Edit/Tab/AdvancedTest.php
@@ -89,7 +89,7 @@ class AdvancedTest extends \PHPUnit_Framework_TestCase
         $this->localeDate->expects($this->any())->method('getDateFormat')->willReturn('mm/dd/yy');
         $entityType->expects($this->any())->method('getEntityTypeCode')->willReturn('entity_type_code');
         $this->eavData->expects($this->any())->method('getFrontendClasses')->willReturn([]);
-        $formElement->expects($this->exactly(3))->method('setDisabled')->willReturnSelf();
+        $formElement->expects($this->exactly(2))->method('setDisabled')->willReturnSelf();
         $this->yesNo->expects($this->any())->method('toOptionArray')->willReturn(['yes', 'no']);
         $this->filesystem->expects($this->any())->method('getDirectoryRead')->willReturn($directoryReadInterface);
         $directoryReadInterface->expects($this->any())->method('getRelativePath')->willReturn('relative_path');
diff --git a/app/code/Magento/Catalog/Test/Unit/Model/CategoryLinkManagementTest.php b/app/code/Magento/Catalog/Test/Unit/Model/CategoryLinkManagementTest.php
index 9e75726f9dfa284355307d81760d848aa2d7de6e..4be4d33c4fcf2852cb23586fbdf505e387b0682b 100644
--- a/app/code/Magento/Catalog/Test/Unit/Model/CategoryLinkManagementTest.php
+++ b/app/code/Magento/Catalog/Test/Unit/Model/CategoryLinkManagementTest.php
@@ -44,7 +44,7 @@ class CategoryLinkManagementTest extends \PHPUnit_Framework_TestCase
     {
         $categoryId = 42;
         $productId = 55;
-        $productsPosition = [$productId => 25];
+        $position = 25;
         $productSku = 'testSku';
         $categoryProductLinkMock = $this->getMock('\Magento\Catalog\Api\Data\CategoryProductLinkInterface');
         $categoryMock = $this->getMock(
@@ -56,13 +56,14 @@ class CategoryLinkManagementTest extends \PHPUnit_Framework_TestCase
         );
         $productMock = $this->getMock('\Magento\Catalog\Model\Product', [], [], '', false);
         $productMock->expects($this->once())->method('getSku')->willReturn($productSku);
+        $productMock->expects($this->once())->method('getData')->with('cat_index_position')->willReturn($position);
         $items = [$productId => $productMock];
-        $productsMock = $this->getMock('\Magento\Framework\Data\Collection\AbstractDb', [], [], '', false);
+        $productsMock = $this->getMock('Magento\Catalog\Model\ResourceModel\Product\Collection', [], [], '', false);
         $this->categoryRepositoryMock->expects($this->once())->method('get')->with($categoryId)
             ->willReturn($categoryMock);
-        $categoryMock->expects($this->once())->method('getProductsPosition')->willReturn($productsPosition);
         $categoryMock->expects($this->once())->method('getProductCollection')->willReturn($productsMock);
         $categoryMock->expects($this->once())->method('getId')->willReturn($categoryId);
+        $productsMock->expects($this->once())->method('addFieldToSelect')->with('position')->willReturnSelf();
         $productsMock->expects($this->once())->method('getItems')->willReturn($items);
         $this->productLinkFactoryMock->expects($this->once())->method('create')->willReturn($categoryProductLinkMock);
         $categoryProductLinkMock->expects($this->once())
@@ -71,7 +72,7 @@ class CategoryLinkManagementTest extends \PHPUnit_Framework_TestCase
             ->willReturnSelf();
         $categoryProductLinkMock->expects($this->once())
             ->method('setPosition')
-            ->with(25)
+            ->with($position)
             ->willReturnSelf();
         $categoryProductLinkMock->expects($this->once())
             ->method('setCategoryId')
diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Config/Source/Product/Options/TypeTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Config/Source/Product/Options/TypeTest.php
index aa686d39ce8d9e1bcc08a00a1bcc6ab1bbb997c7..0696faaa9343593ec21d5108a3ccd5c8e98f1850 100644
--- a/app/code/Magento/Catalog/Test/Unit/Model/Config/Source/Product/Options/TypeTest.php
+++ b/app/code/Magento/Catalog/Test/Unit/Model/Config/Source/Product/Options/TypeTest.php
@@ -51,7 +51,11 @@ class TypeTest extends \PHPUnit_Framework_TestCase
         ];
         $expect = [
             ['value' => '', 'label' => __('-- Please select --')],
-            ['label' => 'optionLabel', 'value' => [['label' => 'typeLabel', 'value' => 'typeName']]],
+            [
+                'label' => 'optionLabel',
+                'optgroup-name' => 'optionLabel',
+                'value' => [['label' => 'typeLabel', 'value' => 'typeName']]
+            ],
         ];
 
         $this->productOptionConfig->expects($this->any())->method('getAll')->will($this->returnValue($allOptions));
diff --git a/app/code/Magento/Catalog/Ui/Component/Listing/Columns/Price.php b/app/code/Magento/Catalog/Ui/Component/Listing/Columns/Price.php
index 2c4af877568c3d9d33dfb033d034c254e03b376f..bcfef825f53453c3df348a1ea0313aebca153cac 100644
--- a/app/code/Magento/Catalog/Ui/Component/Listing/Columns/Price.php
+++ b/app/code/Magento/Catalog/Ui/Component/Listing/Columns/Price.php
@@ -53,14 +53,12 @@ class Price extends \Magento\Ui\Component\Listing\Columns\Column
             $store = $this->storeManager->getStore(
                 $this->context->getFilterParam('store_id', \Magento\Store\Model\Store::DEFAULT_STORE_ID)
             );
-            $currencyCode = $store->getCurrentCurrencyCode();
-            $currencyRate = $store->getCurrentCurrencyRate();
-            $currency = $this->localeCurrency->getCurrency($currencyCode);
+            $currency = $this->localeCurrency->getCurrency($store->getBaseCurrencyCode());
 
             $fieldName = $this->getData('name');
             foreach ($dataSource['data']['items'] as & $item) {
                 if (isset($item[$fieldName])) {
-                    $item[$fieldName] = $currency->toCurrency(sprintf("%f", $item[$fieldName] * $currencyRate));
+                    $item[$fieldName] = $currency->toCurrency(sprintf("%f", $item[$fieldName]));
                 }
             }
         }
diff --git a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/edit.phtml b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/edit.phtml
index 3bce181616dab3a8a99102a7105ba6dea9bd880e..30048cce246460ab521b5d608865acea320ea488 100644
--- a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/edit.phtml
+++ b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/edit.phtml
@@ -21,7 +21,7 @@
                 </button>
                 <ul class="dropdown-menu">
                     <li><input type="text" id="product-template-suggest" class="search"
-                           placeholder="start typing to search template"/></li>
+                           placeholder="<?php /* @noEscape */ echo __('start typing to search template'); ?>"/></li>
                 </ul>
             </div>
         </div>
diff --git a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/edit/options.phtml b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/edit/options.phtml
index 67b1e95e3084663f375efad98714f295ac897c41..6ed486f4c0b4ae21234947626e3f2749aa226d57 100644
--- a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/edit/options.phtml
+++ b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/edit/options.phtml
@@ -9,7 +9,7 @@
 ?>
 <?php /** @var $block \Magento\Catalog\Block\Adminhtml\Product\Edit\Tab\Options */ ?>
 
-<div class="fieldset-wrapper" id="product-custom-options-wrapper">
+<div class="fieldset-wrapper" id="product-custom-options-wrapper" data-block="product-custom-options">
     <div class="fieldset-wrapper-title">
         <strong class="title">
             <span><?php /* @escapeNotVerified */ echo __('Custom Options') ?></span>
diff --git a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/edit/options/option.phtml b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/edit/options/option.phtml
index 3403d4447f82f705375a32e5467793aabd2dff4d..778c8657a83c25d67548a80f156d9f3e674cd39c 100644
--- a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/edit/options/option.phtml
+++ b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/edit/options/option.phtml
@@ -88,7 +88,7 @@ require([
 ], function(jQuery){
 
 jQuery(function ($) {
-    var fieldSet = $('#Custom_Options');
+    var fieldSet = $('[data-block=product-custom-options]');
     fieldSet.customOptions(<?php /* @escapeNotVerified */ echo $this->helper('Magento\Framework\Json\Helper\Data')->jsonEncode(
         [
             'fieldId' => $block->getFieldId(),
@@ -97,6 +97,7 @@ jQuery(function ($) {
             'customOptionsUrl' => $block->getCustomOptionsUrl(),
             'isReadonly' => $block->isReadonly(),
             'itemCount' => $block->getItemCount(),
+            'currentProductId' => $block->getCurrentProductId(),
         ]
     )?>);
     //adding data to templates
diff --git a/app/code/Magento/Catalog/view/adminhtml/templates/product/edit/attribute/search.phtml b/app/code/Magento/Catalog/view/adminhtml/templates/product/edit/attribute/search.phtml
index d3c382f9276b8a2d9df9ec1473fbe1707779fc42..8d2cca19f20cae71303e2da1d50f12569dfd41fe 100644
--- a/app/code/Magento/Catalog/view/adminhtml/templates/product/edit/attribute/search.phtml
+++ b/app/code/Magento/Catalog/view/adminhtml/templates/product/edit/attribute/search.phtml
@@ -17,7 +17,7 @@
             <input data-role="product-attribute-search"
                    data-group="<?php echo $block->escapeHtml($block->getGroupCode()); ?>"
                    class="search" type="text"
-                   placeholder="start typing to search attribute"/>
+                   placeholder="<?php /* @noEscape */ echo __('start typing to search attribute'); ?>" />
         </div>
     </div>
 
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 d68497046a5bf00619fc2db9109ffb8869b7eed2..ae23c3476b8b71df0fd2ff600672c80279247b3b 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
@@ -179,7 +179,7 @@ define([
                     });
                     importContainer.load(
                         this.options.productGridUrl,
-                        {form_key: this.options.formKey},
+                        {form_key: this.options.formKey, current_product_id : this.options.currentProductId},
                         function () {
                             importContainer.modal('openModal');
                         }
@@ -194,7 +194,8 @@ define([
                     var widget = this,
                         currentElement = $(event.target),
                         parentId = '#' + currentElement.closest('.fieldset-alt').attr('id'),
-                        group = currentElement.find('[value="' + currentElement.val() + '"]').closest('optgroup').attr('label'),
+                        group = currentElement.find('[value="' + currentElement.val() + '"]')
+                            .closest('optgroup').attr('data-optgroup-name'),
                         previousGroup = $(parentId + '_previous_group').val(),
                         previousBlock = $(parentId + '_type_' + previousGroup),
                         tmpl;
diff --git a/app/code/Magento/CatalogUrlRewrite/Observer/ProductToWebsiteChangeObserver.php b/app/code/Magento/CatalogUrlRewrite/Observer/ProductToWebsiteChangeObserver.php
new file mode 100644
index 0000000000000000000000000000000000000000..cd094719838136b954de00b78e411e0ee7148461
--- /dev/null
+++ b/app/code/Magento/CatalogUrlRewrite/Observer/ProductToWebsiteChangeObserver.php
@@ -0,0 +1,78 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\CatalogUrlRewrite\Observer;
+
+use Magento\Catalog\Api\ProductRepositoryInterface;
+use Magento\CatalogUrlRewrite\Model\ProductUrlRewriteGenerator;
+use Magento\Framework\App\RequestInterface;
+use Magento\Framework\Event\ObserverInterface;
+use Magento\Store\Model\Store;
+use Magento\UrlRewrite\Model\UrlPersistInterface;
+use Magento\UrlRewrite\Service\V1\Data\UrlRewrite;
+
+class ProductToWebsiteChangeObserver implements ObserverInterface
+{
+    /**
+     * @var ProductUrlRewriteGenerator
+     */
+    protected $productUrlRewriteGenerator;
+
+    /**
+     * @var UrlPersistInterface
+     */
+    protected $urlPersist;
+
+    /**
+     * @var ProductRepositoryInterface
+     */
+    protected $productRepository;
+
+    /**
+     * @var RequestInterface
+     */
+    protected $request;
+
+    /**
+     * @param ProductUrlRewriteGenerator $productUrlRewriteGenerator
+     * @param UrlPersistInterface $urlPersist
+     * @param ProductRepositoryInterface $productRepository
+     * @param RequestInterface $request
+     */
+    public function __construct(
+        ProductUrlRewriteGenerator $productUrlRewriteGenerator,
+        UrlPersistInterface $urlPersist,
+        ProductRepositoryInterface $productRepository,
+        RequestInterface $request
+    ) {
+        $this->productUrlRewriteGenerator = $productUrlRewriteGenerator;
+        $this->urlPersist = $urlPersist;
+        $this->productRepository = $productRepository;
+        $this->request = $request;
+    }
+
+    /**
+     * Generate urls for UrlRewrite and save it in storage
+     *
+     * @param \Magento\Framework\Event\Observer $observer
+     * @return void
+     */
+    public function execute(\Magento\Framework\Event\Observer $observer)
+    {
+        foreach ($observer->getEvent()->getProducts() as $productId) {
+            $product = $this->productRepository->getById(
+                $productId,
+                false,
+                $this->request->getParam('store_id', Store::DEFAULT_STORE_ID)
+            );
+
+            $this->urlPersist->deleteByData([
+                UrlRewrite::ENTITY_ID => $product->getId(),
+                UrlRewrite::ENTITY_TYPE => ProductUrlRewriteGenerator::ENTITY_TYPE,
+            ]);
+            $this->urlPersist->replace($this->productUrlRewriteGenerator->generate($product));
+        }
+    }
+}
diff --git a/app/code/Magento/CatalogUrlRewrite/etc/adminhtml/events.xml b/app/code/Magento/CatalogUrlRewrite/etc/adminhtml/events.xml
index 194b45d59a41ab1754da85805935bb7d82e968ea..477a6cf338b1ba397c3559533c8957c617519017 100644
--- a/app/code/Magento/CatalogUrlRewrite/etc/adminhtml/events.xml
+++ b/app/code/Magento/CatalogUrlRewrite/etc/adminhtml/events.xml
@@ -27,4 +27,7 @@
     <event name="catalog_category_move_after">
         <observer name="process_url_rewrite_moving" instance="Magento\CatalogUrlRewrite\Observer\CategoryProcessUrlRewriteMovingObserver"/>
     </event>
+    <event name="catalog_product_to_website_change">
+        <observer name="catalog_product_to_website_change" instance="Magento\CatalogUrlRewrite\Observer\ProductToWebsiteChangeObserver"/>
+    </event>
 </config>
diff --git a/app/code/Magento/ConfigurableProduct/Block/Adminhtml/Product/Edit/Tab/Super/Config/Matrix.php b/app/code/Magento/ConfigurableProduct/Block/Adminhtml/Product/Edit/Tab/Super/Config/Matrix.php
index e48634a2c7d54cc513997d3b742ed612f9594c8b..bf336cbf87059b52ac2a024c8368d99e30aafe28 100644
--- a/app/code/Magento/ConfigurableProduct/Block/Adminhtml/Product/Edit/Tab/Super/Config/Matrix.php
+++ b/app/code/Magento/ConfigurableProduct/Block/Adminhtml/Product/Edit/Tab/Super/Config/Matrix.php
@@ -54,6 +54,11 @@ class Matrix extends \Magento\Backend\Block\Template
     /** @var null|array */
     private $productAttributes;
 
+    /**
+     * @var \Magento\Framework\Locale\CurrencyInterface
+     */
+    protected $localeCurrency;
+
     /**
      * @param \Magento\Backend\Block\Template\Context $context
      * @param \Magento\ConfigurableProduct\Model\Product\Type\Configurable $configurableType
@@ -62,6 +67,7 @@ class Matrix extends \Magento\Backend\Block\Template
      * @param \Magento\ConfigurableProduct\Model\Product\Type\VariationMatrix $variationMatrix
      * @param ProductRepositoryInterface $productRepository
      * @param \Magento\Catalog\Helper\Image $image
+     * @param \Magento\Framework\Locale\CurrencyInterface $localeCurrency
      * @param array $data
      */
     public function __construct(
@@ -72,6 +78,7 @@ class Matrix extends \Magento\Backend\Block\Template
         \Magento\ConfigurableProduct\Model\Product\Type\VariationMatrix $variationMatrix,
         ProductRepositoryInterface $productRepository,
         \Magento\Catalog\Helper\Image $image,
+        \Magento\Framework\Locale\CurrencyInterface $localeCurrency,
         array $data = []
     ) {
         parent::__construct($context, $data);
@@ -80,6 +87,7 @@ class Matrix extends \Magento\Backend\Block\Template
         $this->stockRegistry = $stockRegistry;
         $this->variationMatrix = $variationMatrix;
         $this->productRepository = $productRepository;
+        $this->localeCurrency = $localeCurrency;
         $this->image = $image;
     }
 
@@ -88,7 +96,7 @@ class Matrix extends \Magento\Backend\Block\Template
      */
     public function getCurrencySymbol()
     {
-        return $this->_storeManager->getStore()->getCurrentCurrency()->getCurrencySymbol();
+        return $this->localeCurrency->getCurrency($this->_storeManager->getStore()->getBaseCurrencyCode())->getSymbol();
     }
 
     /**
diff --git a/app/code/Magento/ConfigurableProduct/Block/Adminhtml/Product/Steps/Bulk.php b/app/code/Magento/ConfigurableProduct/Block/Adminhtml/Product/Steps/Bulk.php
index 69960ac40a6f37ab455591503f20b524c8244d99..d440b7347b6e65ad1b825b9e66fb43ad31ad2f80 100644
--- a/app/code/Magento/ConfigurableProduct/Block/Adminhtml/Product/Steps/Bulk.php
+++ b/app/code/Magento/ConfigurableProduct/Block/Adminhtml/Product/Steps/Bulk.php
@@ -39,12 +39,4 @@ class Bulk extends \Magento\Ui\Block\Component\StepsWizard\StepAbstract
     {
         return $this->image->getDefaultPlaceholderUrl('thumbnail');
     }
-
-    /**
-     * @return string
-     */
-    public function getCurrencySymbol()
-    {
-        return $this->_storeManager->getStore()->getCurrentCurrency()->getCurrencySymbol();
-    }
 }
diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/templates/catalog/product/edit/attribute/steps/bulk.phtml b/app/code/Magento/ConfigurableProduct/view/adminhtml/templates/catalog/product/edit/attribute/steps/bulk.phtml
index 8a1b3edc8053e65e07b1f9c59dd2887d0f5c1bb0..df8785085dea3ec27b267ac6835a42e6f75bebf8 100644
--- a/app/code/Magento/ConfigurableProduct/view/adminhtml/templates/catalog/product/edit/attribute/steps/bulk.phtml
+++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/templates/catalog/product/edit/attribute/steps/bulk.phtml
@@ -655,7 +655,6 @@
                     "component": "Magento_ConfigurableProduct/js/variations/steps/bulk",
                     "appendTo": "<?= /* @escapeNotVerified */  $block->getParentComponentName()?>",
                     "noImage": "<?= /* @escapeNotVerified */  $block->getNoImageUrl() ?>",
-                    "currencySymbol": "<?= /* @escapeNotVerified */  $block->getCurrencySymbol() ?>",
                     "variationsComponent": "configurableVariations"
                 }
             }
diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/templates/catalog/product/edit/super/config.phtml b/app/code/Magento/ConfigurableProduct/view/adminhtml/templates/catalog/product/edit/super/config.phtml
index b71eadea028641416be173ce6700cb0b860e8561..b1d12ed35ed1e3912a12ab4f13e910489f938595 100644
--- a/app/code/Magento/ConfigurableProduct/view/adminhtml/templates/catalog/product/edit/super/config.phtml
+++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/templates/catalog/product/edit/super/config.phtml
@@ -16,7 +16,7 @@
             You need to create a simple product for each configuration (Ex: a product for each color).');?>
             </div>
         </div>
-        <div class="product-create-configuration-actions">
+        <div class="product-create-configuration-actions" data-action="product-create-configuration-buttons">
             <div class="product-create-configuration-action">
                 <button type="button" data-action="open-steps-wizard" title="Create Product Configurations"
                         class="action-secondary" data-bind="click: open">
diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/templates/catalog/product/edit/super/matrix.phtml b/app/code/Magento/ConfigurableProduct/view/adminhtml/templates/catalog/product/edit/super/matrix.phtml
index e962963ccac6ca28245e4e25edc5b0917c01bfd9..a56ee49266f28a19835338c4da287ea02b745f3d 100644
--- a/app/code/Magento/ConfigurableProduct/view/adminhtml/templates/catalog/product/edit/super/matrix.phtml
+++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/templates/catalog/product/edit/super/matrix.phtml
@@ -144,7 +144,7 @@ $currencySymbol = $block->getCurrencySymbol();
                                 </td>
                                 <td class="col-price" data-column="price">
                                     <!-- ko ifnot: variation.editable -->
-                                        <!-- ko text: '<?= /* @noEscape */ $currencySymbol?>' + variation.price --><!--/ko-->
+                                        <!-- ko text: $parent.getCurrencySymbol() + variation.price --><!--/ko-->
                                     <!-- /ko -->
                                     <!-- ko if: variation.editable -->
                                         <div class="addon">
@@ -156,7 +156,7 @@ $currencySymbol = $block->getCurrencySymbol();
                                                      value: variation.price}"/>
                                             <label class="addafter"
                                                    data-bind="attr: {for: $parent.getRowId(variation, 'price')">
-                                                <strong>$</strong>
+                                                <strong data-bind="text: $parent.getCurrencySymbol()"></strong>
                                             </label>
                                         </div>
                                     <!-- /ko -->
@@ -255,6 +255,7 @@ $currencySymbol = $block->getCurrencySymbol();
                         "variations": <?= /* @noEscape */ $this->helper('Magento\Framework\Json\Helper\Data')->jsonEncode($productMatrix) ?>,
                         "productAttributes": <?= /* @noEscape */ $this->helper('Magento\Framework\Json\Helper\Data')->jsonEncode($attributes) ?>,
                         "productUrl": "<?= /* @noEscape */ $block->getUrl('catalog/product/edit', ['id' => '%id%']) ?>",
+                        "currencySymbol": "<?= /* @noEscape */ $currencySymbol ?>",
                         "configurableProductGrid": "configurableProductGrid"
                     }
                 }
diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/steps/bulk.js b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/steps/bulk.js
index 5f4af9cd5e3e2e777c05fe58bd5760e938654661..499962f8e59f8f68e598ce4800ac90ff824f7578 100644
--- a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/steps/bulk.js
+++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/steps/bulk.js
@@ -55,7 +55,7 @@ define([
                     type: ko.observable('none'),
                     value: ko.observable(),
                     attribute: ko.observable(),
-                    currencySymbol: this.currencySymbol
+                    currencySymbol: this.variationsComponent().getCurrencySymbol()
                 },
                 quantity: {
                     label: 'quantity',
diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/steps/summary.js b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/steps/summary.js
index 0da35357808085b8fe91792cd7bdac8e523a3e37..0a1088393c04f8b50c48c2405c6668477b2eb95f 100644
--- a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/steps/summary.js
+++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/steps/summary.js
@@ -40,7 +40,7 @@ define([
         nextLabelText: $.mage.__('Generate Products'),
         variations: [],
         generateGrid: function (variations, getSectionValue) {
-            var productName = this.variationsComponent().getProductValue('name'),
+            var productSku = this.variationsComponent().getProductValue('sku'),
                 productPrice = this.variationsComponent().getProductValue('price'),
                 productWeight = this.variationsComponent().getProductValue('weight'),
                 variationsKeys = [],
@@ -59,7 +59,7 @@ define([
                     });
                 }
                 images = getSectionValue('images', options);
-                sku = productName + _.reduce(options, function (memo, option) {
+                sku = productSku + _.reduce(options, function (memo, option) {
                     return memo + '-' + option.label;
                 }, '');
                 quantity = getSectionValue('quantity', options);
@@ -129,7 +129,7 @@ define([
             _.each(variation.options, function (option) {
                 row.push(option.label);
             });
-            row.push('$ ' + variation.price);
+            row.push(this.variationsComponent().getCurrencySymbol() +  ' ' + variation.price);
 
             return row;
         },
diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/variations.js b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/variations.js
index 862ffe05a6cfc78bfa750cce52b2c2fef1258273..150326b3fabaf055dbf1184c363635c7b4b16db8 100644
--- a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/variations.js
+++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/variations.js
@@ -368,6 +368,14 @@ define([
                     .addClass('disabled-configurable-elements')
                     .prop('disabled', true);
             });
+        },
+
+        /**
+         * Get currency symbol
+         * @returns {*}
+         */
+        getCurrencySymbol: function () {
+            return this.currencySymbol;
         }
     });
 });
diff --git a/app/code/Magento/Customer/Model/Config/Backend/Address/Street.php b/app/code/Magento/Customer/Model/Config/Backend/Address/Street.php
index d456491e5c33462e25d49386eb0c77fbf7674684..7ac2be353e6a403afbb46ee599a880e0704a4bc5 100644
--- a/app/code/Magento/Customer/Model/Config/Backend/Address/Street.php
+++ b/app/code/Magento/Customer/Model/Config/Backend/Address/Street.php
@@ -10,7 +10,7 @@ use Magento\Framework\App\Config\ScopeConfigInterface;
 /**
  * Line count config model for customer address street attribute
  *
- * @method string getWebsiteCode
+ * @method string getWebsiteCode()
  */
 class Street extends \Magento\Framework\App\Config\Value
 {
diff --git a/app/code/Magento/Downloadable/view/adminhtml/templates/product/edit/downloadable.phtml b/app/code/Magento/Downloadable/view/adminhtml/templates/product/edit/downloadable.phtml
index 0c4077543059fd746f88a67b946889ca286ce287..dac2edad7be49ec47e029d391901da6842ed6154 100644
--- a/app/code/Magento/Downloadable/view/adminhtml/templates/product/edit/downloadable.phtml
+++ b/app/code/Magento/Downloadable/view/adminhtml/templates/product/edit/downloadable.phtml
@@ -67,9 +67,9 @@ var uploaderTemplate = '<div class="no-display" id="[[idName]]-template">' +
         }
     };
 
-    var configurationSectionMessageHandler = (new function(attributeTitle, attributeTab) {
+    var configurationSectionMessageHandler = (new function(attributeTitle, buttons) {
         this.title = jQuery(attributeTitle);
-        this.buttons = jQuery('button', attributeTab);
+        this.buttons = jQuery(buttons);
         this.newText = '<?= /* @noEscape */ __('Configurations cannot be created for a standard product with downloadable files.'
              . ' To create configurations, first remove all downloadable files.');?>';
         this.oldText = this.title.text();
@@ -86,7 +86,7 @@ var uploaderTemplate = '<div class="no-display" id="[[idName]]-template">' +
             this.title.text(this.newText);
             this.buttons.hide();
         }
-    }('[data-role="product-create-configuration-info"]', '[data-tab="super_config"]'));
+    }('[data-role="product-create-configuration-info"]', '[data-action="product-create-configuration-buttons"]'));
 
     downloadableCheckbox.on('change', function () {
         switchConfigurationSectionMessage(!jQuery(this).is(':checked'));
diff --git a/app/code/Magento/Reports/Block/Adminhtml/Shopcart/Abandoned/Grid.php b/app/code/Magento/Reports/Block/Adminhtml/Shopcart/Abandoned/Grid.php
index 648db357ee120790bda999e2c009e6c21bfdd8ba..99d5ea9e11b1c04d7c0554aa6011dc32347b2fa7 100644
--- a/app/code/Magento/Reports/Block/Adminhtml/Shopcart/Abandoned/Grid.php
+++ b/app/code/Magento/Reports/Block/Adminhtml/Shopcart/Abandoned/Grid.php
@@ -8,7 +8,7 @@ namespace Magento\Reports\Block\Adminhtml\Shopcart\Abandoned;
 /**
  * Adminhtml abandoned shopping carts report grid block
  *
- * @method \Magento\Reports\Model\ResourceModel\Quote\Collection getCollection
+ * @method \Magento\Reports\Model\ResourceModel\Quote\Collection getCollection()
  *
  * @author      Magento Core Team <core@magentocommerce.com>
  * @SuppressWarnings(PHPMD.DepthOfInheritance)
diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/CreditmemoLoader.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/CreditmemoLoader.php
index cf69855c1489cf99d438b9892f7b0b38da97870c..5918bdb0326b94b22357a02afa89e3551b245ae4 100644
--- a/app/code/Magento/Sales/Controller/Adminhtml/Order/CreditmemoLoader.php
+++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/CreditmemoLoader.php
@@ -14,14 +14,14 @@ use \Magento\Sales\Model\Order\CreditmemoFactory;
  * Class CreditmemoLoader
  *
  * @package Magento\Sales\Controller\Adminhtml\Order
- * @method CreditmemoLoader setCreditmemoId
- * @method CreditmemoLoader setCreditmemo
- * @method CreditmemoLoader setInvoiceId
- * @method CreditmemoLoader setOrderId
- * @method int getCreditmemoId
- * @method string getCreditmemo
- * @method int getInvoiceId
- * @method int getOrderId
+ * @method CreditmemoLoader setCreditmemoId($id)
+ * @method CreditmemoLoader setCreditmemo($creditMemo)
+ * @method CreditmemoLoader setInvoiceId($id)
+ * @method CreditmemoLoader setOrderId($id)
+ * @method int getCreditmemoId()
+ * @method string getCreditmemo()
+ * @method int getInvoiceId()
+ * @method int getOrderId()
  */
 class CreditmemoLoader extends DataObject
 {
diff --git a/app/code/Magento/Sales/Model/Download.php b/app/code/Magento/Sales/Model/Download.php
index be8054315ea9ccf7ffaa42e4ffeaf86864f571bf..0f2649d7de582651d8ab65af4866b2cca21139d4 100644
--- a/app/code/Magento/Sales/Model/Download.php
+++ b/app/code/Magento/Sales/Model/Download.php
@@ -6,6 +6,7 @@
 namespace Magento\Sales\Model;
 
 use Magento\Framework\App\Filesystem\DirectoryList;
+use Magento\Framework\Exception\LocalizedException;
 
 class Download
 {
@@ -29,19 +30,27 @@ class Download
      */
     protected $_fileFactory;
 
+    /**
+     * @var string
+     */
+    protected $rootDirBasePath;
+
     /**
      * @param \Magento\Framework\Filesystem $filesystem
      * @param \Magento\MediaStorage\Helper\File\Storage\Database $fileStorageDatabase
      * @param \Magento\MediaStorage\Model\File\Storage\DatabaseFactory $storageDatabaseFactory
      * @param \Magento\Framework\App\Response\Http\FileFactory $fileFactory
+     * @param string $rootDirBasePath
      */
     public function __construct(
         \Magento\Framework\Filesystem $filesystem,
         \Magento\MediaStorage\Helper\File\Storage\Database $fileStorageDatabase,
         \Magento\MediaStorage\Model\File\Storage\DatabaseFactory $storageDatabaseFactory,
-        \Magento\Framework\App\Response\Http\FileFactory $fileFactory
+        \Magento\Framework\App\Response\Http\FileFactory $fileFactory,
+        $rootDirBasePath = DirectoryList::MEDIA
     ) {
-        $this->_rootDir = $filesystem->getDirectoryWrite(DirectoryList::ROOT);
+        $this->rootDirBasePath = $rootDirBasePath;
+        $this->_rootDir = $filesystem->getDirectoryWrite($this->rootDirBasePath);
         $this->_fileStorageDatabase = $fileStorageDatabase;
         $this->_storageDatabaseFactory = $storageDatabaseFactory;
         $this->_fileFactory = $fileFactory;
@@ -57,18 +66,19 @@ class Download
     public function downloadFile($info)
     {
         $relativePath = $info['order_path'];
-        if ($this->_isCanProcessed($relativePath)) {
+        if (!$this->_isCanProcessed($relativePath)) {
             //try get file from quote
             $relativePath = $info['quote_path'];
-            if ($this->_isCanProcessed($relativePath)) {
-                throw new \Exception();
+            if (!$this->_isCanProcessed($relativePath)) {
+                throw new LocalizedException(
+                    __('Path "%1" is not part of allowed directory "%2"', $relativePath, $this->rootDirBasePath)
+                );
             }
         }
-
         $this->_fileFactory->create(
             $info['title'],
             ['value' => $this->_rootDir->getRelativePath($relativePath), 'type' => 'filename'],
-            DirectoryList::ROOT
+            $this->rootDirBasePath
         );
     }
 
@@ -79,32 +89,28 @@ class Download
     protected function _isCanProcessed($relativePath)
     {
         $filePath = $this->_rootDir->getAbsolutePath($relativePath);
-        return (!$this->_rootDir->isFile(
-            $relativePath
-        ) || !$this->_rootDir->isReadable(
-            $relativePath
-        )) && !$this->_processDatabaseFile(
-            $filePath
-        );
+        return (strpos($this->_rootDir->getDriver()->getRealPath($filePath), $relativePath) !== false
+            && $this->_rootDir->isFile($relativePath) && $this->_rootDir->isReadable($relativePath))
+            || $this->_processDatabaseFile($filePath, $relativePath);
     }
 
     /**
      * Check file in database storage if needed and place it on file system
      *
      * @param string $filePath
+     * @param string $relativePath
      * @return bool
      */
-    protected function _processDatabaseFile($filePath)
+    protected function _processDatabaseFile($filePath, $relativePath)
     {
         if (!$this->_fileStorageDatabase->checkDbUsage()) {
             return false;
         }
-        $relativePath = $this->_fileStorageDatabase->getMediaRelativePath($filePath);
         $file = $this->_storageDatabaseFactory->create()->loadByFilename($relativePath);
         if (!$file->getId()) {
             return false;
         }
-        $stream = $this->_rootDir->openFile($filePath, 'w+');
+        $stream = $this->_rootDir->openFile($relativePath, 'w+');
         $stream->lock();
         $stream->write($filePath, $file->getContent());
         $stream->unlock();
diff --git a/app/code/Magento/Sales/Test/Unit/Model/DownloadTest.php b/app/code/Magento/Sales/Test/Unit/Model/DownloadTest.php
index e7410b411bfa6de5ca497929115cf224d31f45f6..295981ef91ed16cb6102014764155615ae87b492 100644
--- a/app/code/Magento/Sales/Test/Unit/Model/DownloadTest.php
+++ b/app/code/Magento/Sales/Test/Unit/Model/DownloadTest.php
@@ -39,6 +39,11 @@ class DownloadTest extends \PHPUnit_Framework_TestCase
      */
     protected $writeDirectoryMock;
 
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $driverMock;
+
     protected function setUp()
     {
         $this->writeDirectoryMock = $this->getMockBuilder('Magento\Framework\Filesystem\Directory\Write')
@@ -49,9 +54,10 @@ class DownloadTest extends \PHPUnit_Framework_TestCase
             ->getMock();
         $this->filesystemMock->expects($this->any())
             ->method('getDirectoryWrite')
-            ->with(DirectoryList::ROOT)
+            ->with(DirectoryList::MEDIA)
             ->will($this->returnValue($this->writeDirectoryMock));
 
+        $this->driverMock = $this->getMockForAbstractClass('Magento\Framework\Filesystem\DriverInterface');
         $this->storageMock = $this->getMockBuilder('Magento\MediaStorage\Helper\File\Storage\Database')
             ->disableOriginalConstructor()
             ->getMock();
@@ -83,17 +89,23 @@ class DownloadTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * @expectedException \Exception
+     * @param $realPatchCheck
+     * @param $isFile
+     * @param $isReadable
+     * @expectedException \Magento\Framework\Exception\LocalizedException
+     * @dataProvider dataProviderForTestDownloadFileException
      */
-    public function testDownloadFileException()
+    public function testDownloadFileException($realPatchCheck, $isFile, $isReadable)
     {
         $info = ['order_path' => 'test/path', 'quote_path' => 'test/path2', 'title' => 'test title'];
-        $isFile = true;
-        $isReadable = false;
 
         $this->writeDirectoryMock->expects($this->any())
             ->method('getAbsolutePath')
             ->will($this->returnArgument(0));
+        $this->writeDirectoryMock->expects($this->any())
+            ->method('getDriver')
+            ->willReturn($this->driverMock);
+        $this->driverMock->expects($this->any())->method('getRealPath')->willReturn($realPatchCheck);
         $this->writeDirectoryMock->expects($this->any())
             ->method('isFile')
             ->will($this->returnValue($isFile));
@@ -104,12 +116,25 @@ class DownloadTest extends \PHPUnit_Framework_TestCase
         $this->storageFactoryMock->expects($this->any())
             ->method('checkDbUsage')
             ->will($this->returnValue(false));
+        $this->httpFileFactoryMock->expects($this->never())->method('create');
 
         $this->model->downloadFile($info);
     }
 
     /**
-     * @expectedException \Exception
+     * @return array
+     */
+    public function dataProviderForTestDownloadFileException()
+    {
+        return [
+            [1, true, false],
+            [1, false, true],
+            [false, true, true],
+        ];
+    }
+
+    /**
+     * @expectedException \Magento\Framework\Exception\LocalizedException
      */
     public function testDownloadFileNoStorage()
     {
@@ -120,6 +145,11 @@ class DownloadTest extends \PHPUnit_Framework_TestCase
         $this->writeDirectoryMock->expects($this->any())
             ->method('getAbsolutePath')
             ->will($this->returnArgument(0));
+        $this->writeDirectoryMock->expects($this->any())
+            ->method('getDriver')
+            ->willReturn($this->driverMock);
+        $this->driverMock->expects($this->any())->method('getRealPath')->willReturn(true);
+
         $this->writeDirectoryMock->expects($this->any())
             ->method('isFile')
             ->will($this->returnValue($isFile));
@@ -130,9 +160,6 @@ class DownloadTest extends \PHPUnit_Framework_TestCase
         $this->storageMock->expects($this->any())
             ->method('checkDbUsage')
             ->will($this->returnValue(true));
-        $this->storageMock->expects($this->any())
-            ->method('getMediaRelativePath')
-            ->will($this->returnArgument(0));
 
         $storageDatabaseMock = $this->getMockBuilder('Magento\MediaStorage\Model\File\Storage\Database')
             ->disableOriginalConstructor()
@@ -153,6 +180,7 @@ class DownloadTest extends \PHPUnit_Framework_TestCase
         $this->storageFactoryMock->expects($this->any())
             ->method('create')
             ->will($this->returnValue($storageDatabaseMock));
+        $this->httpFileFactoryMock->expects($this->never())->method('create');
 
         $this->model->downloadFile($info);
     }
@@ -178,6 +206,11 @@ class DownloadTest extends \PHPUnit_Framework_TestCase
         $this->writeDirectoryMock->expects($this->any())
             ->method('getAbsolutePath')
             ->will($this->returnArgument(0));
+        $this->writeDirectoryMock->expects($this->any())
+            ->method('getDriver')
+            ->willReturn($this->driverMock);
+        $this->driverMock->expects($this->any())->method('getRealPath')->willReturn(true);
+
         $this->writeDirectoryMock->expects($this->any())
             ->method('isFile')
             ->will($this->returnValue($isFile));
@@ -195,9 +228,6 @@ class DownloadTest extends \PHPUnit_Framework_TestCase
         $this->storageMock->expects($this->any())
             ->method('checkDbUsage')
             ->will($this->returnValue(true));
-        $this->storageMock->expects($this->any())
-            ->method('getMediaRelativePath')
-            ->will($this->returnArgument(0));
 
         $storageDatabaseMock = $this->getMockBuilder('Magento\MediaStorage\Model\File\Storage\Database')
             ->disableOriginalConstructor()
@@ -220,7 +250,7 @@ class DownloadTest extends \PHPUnit_Framework_TestCase
             ->with(
                 $info['title'],
                 ['value' => $info['order_path'], 'type' => 'filename'],
-                DirectoryList::ROOT,
+                DirectoryList::MEDIA,
                 'application/octet-stream',
                 null
             );
diff --git a/app/code/Magento/Shipping/Controller/Adminhtml/Order/ShipmentLoader.php b/app/code/Magento/Shipping/Controller/Adminhtml/Order/ShipmentLoader.php
index 6bbaac5a04d4a34331323019cc7cbd4f03fbf704..c837623ac8ffd99323b1b116bbb8648db83f7433 100644
--- a/app/code/Magento/Shipping/Controller/Adminhtml/Order/ShipmentLoader.php
+++ b/app/code/Magento/Shipping/Controller/Adminhtml/Order/ShipmentLoader.php
@@ -12,14 +12,14 @@ use Magento\Framework\DataObject;
  * Class ShipmentLoader
  *
  * @package Magento\Shipping\Controller\Adminhtml\Order
- * @method ShipmentLoader setOrderId
- * @method ShipmentLoader setShipmentId
- * @method ShipmentLoader setShipment
- * @method ShipmentLoader setTracking
- * @method int getOrderId
- * @method int getShipmentId
- * @method array getShipment
- * @method array getTracking
+ * @method ShipmentLoader setOrderId($id)
+ * @method ShipmentLoader setShipmentId($id)
+ * @method ShipmentLoader setShipment($shipment)
+ * @method ShipmentLoader setTracking($tracking)
+ * @method int getOrderId()
+ * @method int getShipmentId()
+ * @method array getShipment()
+ * @method array getTracking()
  */
 class ShipmentLoader extends DataObject
 {
diff --git a/app/code/Magento/Theme/Block/Adminhtml/Wysiwyg/Files/Content/Files.php b/app/code/Magento/Theme/Block/Adminhtml/Wysiwyg/Files/Content/Files.php
index 9b11f465787d75ba95c8349733e76ad6d7668790..1af3ea8e4bc986b49e0c718e0a3e9b4bb9006ead 100644
--- a/app/code/Magento/Theme/Block/Adminhtml/Wysiwyg/Files/Content/Files.php
+++ b/app/code/Magento/Theme/Block/Adminhtml/Wysiwyg/Files/Content/Files.php
@@ -9,7 +9,7 @@
  *
  * @method
  *  \Magento\Theme\Block\Adminhtml\Wysiwyg\Files\Content\Files setStorage(\Magento\Theme\Model\Wysiwyg\Storage $storage)
- * @method \Magento\Theme\Model\Wysiwyg\Storage getStorage
+ * @method \Magento\Theme\Model\Wysiwyg\Storage getStorage()
  */
 namespace Magento\Theme\Block\Adminhtml\Wysiwyg\Files\Content;
 
diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Option/Type/File/ValidatorFileTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Option/Type/File/ValidatorFileTest.php
index 611e8c839d477cf9ad31672dbf27f387b61d4d14..b005c52813a7b987df53f64d5083c8a43f1434d9 100644
--- a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Option/Type/File/ValidatorFileTest.php
+++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Option/Type/File/ValidatorFileTest.php
@@ -16,7 +16,7 @@ class ValidatorFileTest extends \PHPUnit_Framework_TestCase
     protected $model;
 
     /**
-     * @var \Magento\Framework\ObjectManager
+     * @var \Magento\Framework\ObjectManagerInterface
      */
     protected $objectManager;
 
@@ -241,8 +241,8 @@ class ValidatorFileTest extends \PHPUnit_Framework_TestCase
         return [
             'type' => 'image/jpeg',
             'title' => 'test.jpg',
-            'quote_path' => 'pub/media/custom_options/quote/t/e/e1d601731b4b1a84163cd0e9370a4fcb.jpg',
-            'order_path' => 'pub/media/custom_options/order/t/e/e1d601731b4b1a84163cd0e9370a4fcb.jpg',
+            'quote_path' => 'custom_options/quote/t/e/e1d601731b4b1a84163cd0e9370a4fcb.jpg',
+            'order_path' => 'custom_options/order/t/e/e1d601731b4b1a84163cd0e9370a4fcb.jpg',
             'size' => '3300',
             'width' => 136,
             'height' => 131,
diff --git a/dev/tests/integration/testsuite/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Chooser/_files/design-abstraction_select.html b/dev/tests/integration/testsuite/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Chooser/_files/design-abstraction_select.html
index 15e322c12df580c58724b6193208e99bd8481cb8..ec08d09ec6bc5642bc18966ceda3196abb900ff4 100644
--- a/dev/tests/integration/testsuite/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Chooser/_files/design-abstraction_select.html
+++ b/dev/tests/integration/testsuite/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Chooser/_files/design-abstraction_select.html
@@ -6,9 +6,9 @@
 -->
 <select name="design_abstractions" id="design_abstraction_select" class="design-abstraction-select" title="Design Abstraction Select">
     <option value="">-- Please Select --</option>
-    <optgroup label="Custom Layouts">
+    <optgroup data-optgroup-name="Custom Layouts" label="Custom Layouts">
         <option value="customer_account" >Customer My Account (All Pages)</option>
     </optgroup>
-    <optgroup label="Page Layouts">
+    <optgroup data-optgroup-name="Page Layouts" label="Page Layouts">
         <option value="page_empty" >All Empty Layout Pages</option>
     </optgroup></select>
diff --git a/lib/internal/Magento/Framework/View/Element/Html/Select.php b/lib/internal/Magento/Framework/View/Element/Html/Select.php
index ab54697632aceffbda35a6fee7debca60dc6e3d8..884c11fe91950eca05b450eb1a8ea6b12114a23a 100644
--- a/lib/internal/Magento/Framework/View/Element/Html/Select.php
+++ b/lib/internal/Magento/Framework/View/Element/Html/Select.php
@@ -125,6 +125,7 @@ class Select extends \Magento\Framework\View\Element\AbstractBlock
      * @return string
      *
      * @SuppressWarnings(PHPMD.CyclomaticComplexity)
+     * @SuppressWarnings(PHPMD.NPathComplexity)
      */
     protected function _toHtml()
     {
@@ -151,9 +152,11 @@ class Select extends \Magento\Framework\View\Element\AbstractBlock
 
         $isArrayOption = true;
         foreach ($this->getOptions() as $key => $option) {
+            $optgroupName = '';
             if ($isArrayOption && is_array($option)) {
                 $value = $option['value'];
                 $label = (string)$option['label'];
+                $optgroupName = isset($option['optgroup-name']) ? $option['optgroup-name'] : $label;
                 $params = !empty($option['params']) ? $option['params'] : [];
             } else {
                 $value = (string)$key;
@@ -163,7 +166,7 @@ class Select extends \Magento\Framework\View\Element\AbstractBlock
             }
 
             if (is_array($value)) {
-                $html .= '<optgroup label="' . $label . '">';
+                $html .= '<optgroup label="' . $label . '" data-optgroup-name="' . $optgroupName . '">';
                 foreach ($value as $keyGroup => $optionGroup) {
                     if (!is_array($optionGroup)) {
                         $optionGroup = ['value' => $keyGroup, 'label' => $optionGroup];
diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Element/Html/SelectTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Element/Html/SelectTest.php
index d3660f32178ac024283b682bc5d93f93f00a5e39..3321d1eeaf8b6d1b1c1136faceaf08239c8413db 100644
--- a/lib/internal/Magento/Framework/View/Test/Unit/Element/Html/SelectTest.php
+++ b/lib/internal/Magento/Framework/View/Test/Unit/Element/Html/SelectTest.php
@@ -127,7 +127,7 @@ class SelectTest extends \PHPUnit_Framework_TestCase
             .   '<option value="testValue"  paramKey="paramValue" >testLabel</option>'
             .   '<option value="selectedValue" selected="selected"  paramKey="paramValue" '
             .       ' paramKey2="paramValue2" >selectedLabel</option>'
-            .   '<optgroup label="groupLabel">'
+            .   '<optgroup label="groupLabel" data-optgroup-name="groupLabel">'
             .       '<option value="groupElementValue" >GroupElementLabel</option>'
             .       '<option value="selectedGroupElementValue" selected="selected" >SelectedGroupElementLabel</option>'
             .   '</optgroup>'