diff --git a/app/code/Magento/AdminNotification/view/adminhtml/layout/default.xml b/app/code/Magento/AdminNotification/view/adminhtml/layout/default.xml
index a7183277e514bfb390d08cf0241e9e3f3c581661..e3d32f17b6356bc974627b0daaba5dca5c467eea 100644
--- a/app/code/Magento/AdminNotification/view/adminhtml/layout/default.xml
+++ b/app/code/Magento/AdminNotification/view/adminhtml/layout/default.xml
@@ -8,9 +8,20 @@
 <page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
     <body>
         <referenceContainer name="notifications">
-            <block class="Magento\AdminNotification\Block\System\Messages" name="system_messages" as="system_messages" before="-" template="Magento_AdminNotification::system/messages.phtml"/>
-            <block class="Magento\AdminNotification\Block\System\Messages\UnreadMessagePopup" name="unread_system_messages" as="unread_system_messages" after="system_messages" template="Magento_AdminNotification::system/messages/popup.phtml"/>
-            <block class="Magento\AdminNotification\Block\Window" name="notification_window" as="notification_window" acl="Magento_AdminNotification::show_toolbar" template="notification/window.phtml"/>
+            <block class="Magento\AdminNotification\Block\System\Messages"
+                   name="system_messages"
+                   as="system_messages"
+                   before="-"
+                   template="Magento_AdminNotification::system/messages.phtml"/>
+            <block class="Magento\AdminNotification\Block\System\Messages\UnreadMessagePopup"
+                   name="unread_system_messages"
+                   as="unread_system_messages"
+                   template="Magento_AdminNotification::system/messages/popup.phtml"/>
+            <block class="Magento\AdminNotification\Block\Window"
+                   name="notification_window"
+                   as="notification_window"
+                   acl="Magento_AdminNotification::show_toolbar"
+                   template="notification/window.phtml"/>
         </referenceContainer>
         <referenceContainer name="header">
             <block class="Magento\AdminNotification\Block\ToolbarEntry" name="notification.messages" before="user" template="toolbar_entry.phtml"/>
diff --git a/app/code/Magento/Backend/Block/Page/System/Config/Robots/Reset.php b/app/code/Magento/Backend/Block/Page/System/Config/Robots/Reset.php
index e7d2742d34bab58f853a3b5ef6dfcc717c35ebfd..ae13ce4a7a4523d4b761778a67cd36cc3b4af00d 100644
--- a/app/code/Magento/Backend/Block/Page/System/Config/Robots/Reset.php
+++ b/app/code/Magento/Backend/Block/Page/System/Config/Robots/Reset.php
@@ -13,6 +13,7 @@ use Magento\Framework\App\Config\ScopeConfigInterface;
 /**
  * "Reset to Defaults" button renderer
  *
+ * @deprecated
  * @author     Magento Core Team <core@magentocommerce.com>
  */
 class Reset extends \Magento\Config\Block\System\Config\Form\Field
diff --git a/app/code/Magento/Backend/Test/Unit/Block/Page/System/Config/Robots/ResetTest.php b/app/code/Magento/Backend/Test/Unit/Block/Page/System/Config/Robots/ResetTest.php
index 6f64d49829fb52b736108fac183e769876d0812a..1bd0a81f78163025cec29a0e214f72e8d9c15c04 100644
--- a/app/code/Magento/Backend/Test/Unit/Block/Page/System/Config/Robots/ResetTest.php
+++ b/app/code/Magento/Backend/Test/Unit/Block/Page/System/Config/Robots/ResetTest.php
@@ -9,6 +9,11 @@
  */
 namespace Magento\Backend\Test\Unit\Block\Page\System\Config\Robots;
 
+/**
+ * Class ResetTest
+ * @deprecated 
+ * @package Magento\Backend\Test\Unit\Block\Page\System\Config\Robots
+ */
 class ResetTest extends \PHPUnit_Framework_TestCase
 {
     /**
diff --git a/app/code/Magento/Backend/view/adminhtml/templates/system/shipping/applicable_country.phtml b/app/code/Magento/Backend/view/adminhtml/templates/system/shipping/applicable_country.phtml
index 1ab29f9fc75994705eab61414a270eca9e953b51..6d003c6cb6810ee05982625e3b67bf6652b65ca2 100644
--- a/app/code/Magento/Backend/view/adminhtml/templates/system/shipping/applicable_country.phtml
+++ b/app/code/Magento/Backend/view/adminhtml/templates/system/shipping/applicable_country.phtml
@@ -37,7 +37,7 @@ CountryModel.prototype = {
             var showMethodElement  = $(applyCountryElement.id.replace(/sallowspecific/, 'showmethod'));
             //var specifErrMsgElement  = $(applyCountryElement.id.replace(/sallowspecific/, 'specificerrmsg'));
             if (specifCountryElement) {
-                if (applyCountryElement.value == 1) {
+                if (applyCountryElement.value == 1 && !specifCountryElement.hasAttribute('disabled')) {
                    //if specific country element selected
                    specifCountryElement.enable();
                    if (showMethodElement) {
diff --git a/app/code/Magento/Braintree/Model/Report/Row/TransactionMap.php b/app/code/Magento/Braintree/Model/Report/Row/TransactionMap.php
index 0abae8af89fbca4664c7b35568cf16e61533a3fe..c914b21893e253feb3a04fabe0f4a274d10deb1a 100644
--- a/app/code/Magento/Braintree/Model/Report/Row/TransactionMap.php
+++ b/app/code/Magento/Braintree/Model/Report/Row/TransactionMap.php
@@ -115,9 +115,13 @@ class TransactionMap implements DocumentInterface
      */
     public function getCustomAttributes()
     {
+        $shouldBeLocalized = ['paymentInstrumentType', 'type', 'status'];
         $output = [];
         foreach ($this->getMappedValues() as $key => $value) {
             $attribute = $this->attributeValueFactory->create();
+            if(in_array($key, $shouldBeLocalized)) {
+                $value = __($value);
+            }
             $output[] = $attribute->setAttributeCode($key)->setValue($value);
         }
         return $output;
diff --git a/app/code/Magento/Braintree/Model/Ui/ConfigProvider.php b/app/code/Magento/Braintree/Model/Ui/ConfigProvider.php
index d720b748ba819cce5515d052acde4bfda50c29db..cea02f249cbed4a6da6d7426c0ab20e27fe9cbc9 100644
--- a/app/code/Magento/Braintree/Model/Ui/ConfigProvider.php
+++ b/app/code/Magento/Braintree/Model/Ui/ConfigProvider.php
@@ -79,7 +79,6 @@ final class ConfigProvider implements ConfigProviderInterface
             'payment' => [
                 self::CODE => [
                     'isActive' => $this->config->isActive(),
-                    'isSingleUse' => !$isPayPalActive,
                     'clientToken' => $this->getClientToken(),
                     'ccTypesMapper' => $this->config->getCctypesMapper(),
                     'sdkUrl' => $this->config->getSdkUrl(),
diff --git a/app/code/Magento/Braintree/Test/Unit/Model/Report/TransactionMapTest.php b/app/code/Magento/Braintree/Test/Unit/Model/Report/TransactionMapTest.php
index c44a67b2c61d92cabe3087e9a47f20f1b94f9250..34c607c88784d7c270d75937cadfb550216744b1 100644
--- a/app/code/Magento/Braintree/Test/Unit/Model/Report/TransactionMapTest.php
+++ b/app/code/Magento/Braintree/Test/Unit/Model/Report/TransactionMapTest.php
@@ -11,6 +11,8 @@ use DateTime;
 use Magento\Braintree\Model\Report\Row\TransactionMap;
 use Magento\Framework\Api\AttributeValue;
 use Magento\Framework\Api\AttributeValueFactory;
+use Magento\Framework\Phrase;
+use Magento\Framework\Phrase\RendererInterface;
 use Magento\Store\Model\StoreManagerInterface;
 
 /**
@@ -30,6 +32,16 @@ class TransactionMapTest extends \PHPUnit_Framework_TestCase
      */
     private $attributeValueFactoryMock;
 
+    /**
+     * @var RendererInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $defaultRenderer;
+
+    /**
+     * @var RendererInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $rendererMock;
+
     /**
      * Setup
      */
@@ -39,6 +51,9 @@ class TransactionMapTest extends \PHPUnit_Framework_TestCase
             ->setMethods(['create'])
             ->disableOriginalConstructor()
             ->getMock();
+        $this->defaultRenderer = Phrase::getRenderer();
+        $this->rendererMock = $this->getMockBuilder(RendererInterface::class)
+            ->getMock();
     }
 
     /**
@@ -65,6 +80,8 @@ class TransactionMapTest extends \PHPUnit_Framework_TestCase
             $this->transactionStub
         );
 
+        Phrase::setRenderer($this->rendererMock);
+
         /** @var AttributeValue[] $result */
         $result = $map->getCustomAttributes();
 
@@ -77,6 +94,31 @@ class TransactionMapTest extends \PHPUnit_Framework_TestCase
             $result[6]->getValue()
         );
         $this->assertEquals(implode(', ', $transaction['refundIds']), $result[11]->getValue());
+        $this->assertEquals($transaction['merchantAccountId'], $result[1]->getValue());
+        $this->assertEquals($transaction['orderId'], $result[2]->getValue());
+        $this->assertEquals($transaction['amount'], $result[7]->getValue());
+        $this->assertEquals($transaction['processorSettlementResponseCode'], $result[8]->getValue());
+        $this->assertEquals($transaction['processorSettlementResponseText'], $result[10]->getValue());
+        $this->assertEquals($transaction['settlementBatchId'], $result[12]->getValue());
+        $this->assertEquals($transaction['currencyIsoCode'], $result[13]->getValue());
+
+        $this->rendererMock->expects($this->at(0))
+            ->method('render')
+            ->with([$transaction['paymentInstrumentType']])
+            ->willReturn('Credit card');
+        $this->assertEquals('Credit card', $result[3]->getValue()->render());
+
+        $this->rendererMock->expects($this->at(0))
+            ->method('render')
+            ->with([$transaction['type']])
+            ->willReturn('Sale');
+        $this->assertEquals('Sale', $result[5]->getValue()->render());
+
+        $this->rendererMock->expects($this->at(0))
+            ->method('render')
+            ->with([$transaction['status']])
+            ->willReturn('Pending for settlement');
+        $this->assertEquals('Pending for settlement', $result[9]->getValue()->render());
     }
 
     /**
@@ -90,9 +132,27 @@ class TransactionMapTest extends \PHPUnit_Framework_TestCase
                     'id' => 1,
                     'createdAt' => new \DateTime(),
                     'paypalDetails' => new PayPalDetails(['paymentId' => 10]),
-                    'refundIds' => [1, 2, 3, 4, 5]
+                    'refundIds' => [1, 2, 3, 4, 5],
+                    'merchantAccountId' => 'MerchantId',
+                    'orderId' => 1,
+                    'paymentInstrumentType' => 'credit_card',
+                    'type' => 'sale',
+                    'amount' => '$19.99',
+                    'processorSettlementResponseCode' => 1,
+                    'status' => 'pending_for_settlement',
+                    'processorSettlementResponseText' => 'sample text',
+                    'settlementBatchId' => 2,
+                    'currencyIsoCode' => 'USD'
                 ]
             ]
         ];
     }
+
+    /**
+     * @return void
+     */
+    protected function tearDown()
+    {
+        Phrase::setRenderer($this->defaultRenderer);
+    }
 }
diff --git a/app/code/Magento/Braintree/Test/Unit/Model/Report/TransactionsCollectionTest.php b/app/code/Magento/Braintree/Test/Unit/Model/Report/TransactionsCollectionTest.php
index 50488df2600c64f1267755b0da98cee69c993789..6024141280a021e443ad100eca65627a4728976c 100644
--- a/app/code/Magento/Braintree/Test/Unit/Model/Report/TransactionsCollectionTest.php
+++ b/app/code/Magento/Braintree/Test/Unit/Model/Report/TransactionsCollectionTest.php
@@ -184,4 +184,42 @@ class TransactionsCollectionTest extends \PHPUnit_Framework_TestCase
         $this->assertEquals(TransactionsCollection::TRANSACTION_MAXIMUM_COUNT, count($items));
         $this->assertInstanceOf(DocumentInterface::class, $items[1]);
     }
+
+    /**
+     * Add fields to filter
+     * 
+     * @dataProvider addToFilterDataProvider
+     */
+    public function testAddToFilter($field, $condition, $filterMapperCall, $expectedCondition)
+    {
+        $this->filterMapperMock->expects(static::exactly($filterMapperCall))
+            ->method('getFilter')
+            ->with($field, $expectedCondition)
+            ->willReturn(new BraintreeSearchNodeStub());
+
+        $collection = new TransactionsCollection(
+            $this->entityFactoryMock,
+            $this->braintreeAdapterMock,
+            $this->filterMapperMock
+        );
+
+        static::assertInstanceOf(
+            TransactionsCollection::class,
+            $collection->addFieldToFilter($field, $condition)
+        );
+    }
+
+    /**
+     * addToFilter DataProvider
+     * 
+     * @return array
+     */
+    public function addToFilterDataProvider()
+    {
+        return [
+            ['orderId', ['like' => 1], 1, ['like' => 1]],
+            ['type', 'sale', 1, ['eq' => 'sale']],
+            [['type', 'orderId'], [], 0, []],
+        ];
+    }
 }
diff --git a/app/code/Magento/Braintree/Test/Unit/Model/Ui/ConfigProviderTest.php b/app/code/Magento/Braintree/Test/Unit/Model/Ui/ConfigProviderTest.php
index a787111fa93aa383f6ec11b77f3cb2e623bc228e..ad9f99b39afb0820b3b0bcbdca10fbe4837e9a5e 100644
--- a/app/code/Magento/Braintree/Test/Unit/Model/Ui/ConfigProviderTest.php
+++ b/app/code/Magento/Braintree/Test/Unit/Model/Ui/ConfigProviderTest.php
@@ -154,7 +154,6 @@ class ConfigProviderTest extends \PHPUnit_Framework_TestCase
                     'payment' => [
                         ConfigProvider::CODE => [
                             'isActive' => true,
-                            'isSingleUse' => false,
                             'clientToken' => self::CLIENT_TOKEN,
                             'ccTypesMapper' => ['visa' => 'VI', 'american-express' => 'AE'],
                             'sdkUrl' => self::SDK_URL,
diff --git a/app/code/Magento/Braintree/Test/Unit/Ui/Component/Report/Filters/Type/DateRangeTest.php b/app/code/Magento/Braintree/Test/Unit/Ui/Component/Report/Filters/Type/DateRangeTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..b81dbe2fb036f66912c35f7cdf59a88deee6dd51
--- /dev/null
+++ b/app/code/Magento/Braintree/Test/Unit/Ui/Component/Report/Filters/Type/DateRangeTest.php
@@ -0,0 +1,251 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Braintree\Test\Unit\Ui\Component\Report\Filters\Type;
+
+use Magento\Framework\Api\Filter;
+use Magento\Framework\Api\FilterBuilder;
+use Magento\Framework\View\Element\UiComponent\DataProvider\DataProviderInterface;
+use Magento\Framework\View\Element\UiComponentFactory;
+use Magento\Ui\Component\Filters\FilterModifier;
+use Magento\Braintree\Ui\Component\Report\Filters\Type\DateRange;
+use Magento\Framework\View\Element\UiComponent\ContextInterface;
+use Magento\Ui\Component\Form\Element\DataType\Date as FormDate;
+
+/**
+ * Class DateRangeTest
+ */
+class DateRangeTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var ContextInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $contextMock;
+
+    /**
+     * @var UiComponentFactory|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $uiComponentFactory;
+
+    /**
+     * @var FilterBuilder|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $filterBuilderMock;
+
+    /**
+     * @var FilterModifier|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $filterModifierMock;
+
+
+    /**
+     * @var DataProviderInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $dataProviderMock;
+
+    /**
+     * Set up
+     */
+    protected function setUp()
+    {
+        $this->contextMock = $this->getMockForAbstractClass(ContextInterface::class);
+        $processor = $this->getMockBuilder(\Magento\Framework\View\Element\UiComponent\Processor::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->contextMock->expects(static::any())
+            ->method('getProcessor')
+            ->willReturn($processor);
+        $this->uiComponentFactory = $this->getMockBuilder(UiComponentFactory::class)
+            ->setMethods(['create'])
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->filterBuilderMock = $this->getMockBuilder(FilterBuilder::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->filterModifierMock = $this->getMockBuilder(FilterModifier::class)
+            ->setMethods(['applyFilterModifier'])
+            ->disableOriginalConstructor()
+            ->getMock();
+        
+        $this->dataProviderMock = $this->getMockForAbstractClass(DataProviderInterface::class);
+    }
+
+    /**
+     * Run test prepare method
+     *
+     * @param string $name
+     * @param array $filterData
+     * @param array|null $expectedCondition
+     * @dataProvider getPrepareDataProvider
+     * @return void
+     */
+    public function testPrepare($name, $filterData, $expectedCondition)
+    {
+        /** @var FormDate PHPUnit_Framework_MockObject_MockObject|$uiComponent */
+        $uiComponent = $this->getMockBuilder(FormDate::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $uiComponent->expects($this->any())
+            ->method('getContext')
+            ->willReturn($this->contextMock);
+
+        $this->contextMock->expects($this->any())
+            ->method('getNamespace')
+            ->willReturn(DateRange::NAME);
+        $this->contextMock->expects($this->any())
+            ->method('addComponentDefinition')
+            ->with(DateRange::NAME, ['extends' => DateRange::NAME]);
+
+        $this->contextMock->expects($this->any())
+            ->method('getFiltersParams')
+            ->willReturn($filterData);
+        
+        $this->contextMock->expects($this->any())
+            ->method('getDataProvider')
+            ->willReturn($this->dataProviderMock);
+
+        if ($expectedCondition !== null) {
+            if (is_string($filterData[$name])) {
+                $uiComponent->expects(static::once())
+                    ->method('convertDate')
+                    ->with($filterData[$name])
+                    ->willReturn(new \DateTime($filterData[$name], new \DateTimeZone('UTC')));
+            } else {
+                $uiComponent->method('convertDate')
+                    ->willReturnMap([
+                        [
+                            $filterData[$name]['from'], 0, 0, 0,
+                            new \DateTime($filterData[$name]['from'], new \DateTimeZone('UTC'))
+                        ],
+                        [
+                            $filterData[$name]['to'], 23, 59, 59,
+                            new \DateTime($filterData[$name]['to'] . ' 23:59:00', new \DateTimeZone('UTC'))
+                        ],
+                    ]);
+            }
+
+            $i=0;
+            switch (true) {
+                case is_string($filterData[$name]):
+                case isset($filterData[$name]['from']) && !isset($filterData[$name]['to']):
+                case !isset($filterData[$name]['from']) && isset($filterData[$name]['to']):
+                    $filterMock = $this->getFilterMock(
+                        $name,
+                        $expectedCondition['type'],
+                        $expectedCondition['date'],
+                        $i
+                    );
+                    $this->dataProviderMock->expects(static::once())
+                        ->method('addFilter')
+                        ->with($filterMock);
+                    break;
+                case isset($filterData[$name]['from']) && isset($filterData[$name]['to']):
+                    $this->getFilterMock(
+                        $name,
+                        $expectedCondition['type_from'],
+                        $expectedCondition['date_from'],
+                        $i
+                    );
+                    $filterMock = $this->getFilterMock(
+                        $name,
+                        $expectedCondition['type_to'],
+                        $expectedCondition['date_to'],
+                        $i
+                    );
+                    $this->dataProviderMock->expects(static::exactly(2))
+                        ->method('addFilter')
+                        ->with($filterMock);
+                    break;
+            }
+        }
+
+        $this->uiComponentFactory->expects($this->any())
+            ->method('create')
+            ->with($name, DateRange::COMPONENT, ['context' => $this->contextMock])
+            ->willReturn($uiComponent);
+
+        $date = new DateRange(
+            $this->contextMock,
+            $this->uiComponentFactory,
+            $this->filterBuilderMock,
+            $this->filterModifierMock,
+            [],
+            ['name' => $name]
+        );
+        $date->prepare();
+    }
+
+    /**
+     * Gets Filter mock
+     * 
+     * @param string $name
+     * @param string $expectedType
+     * @param string $expectedDate
+     * @param int $i
+     * 
+     * @return Filter|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private function getFilterMock($name, $expectedType, $expectedDate, &$i)
+    {
+        $this->filterBuilderMock->expects(static::at($i++))
+            ->method('setConditionType')
+            ->with($expectedType)
+            ->willReturnSelf();
+        $this->filterBuilderMock->expects(static::at($i++))
+            ->method('setField')
+            ->with($name)
+            ->willReturnSelf();
+        $this->filterBuilderMock->expects(static::at($i++))
+            ->method('setValue')
+            ->with($expectedDate)
+            ->willReturnSelf();
+        
+        $filterMock = $this->getMock(Filter::class);
+        $this->filterBuilderMock->expects(static::at($i++))
+            ->method('create')
+            ->willReturn($filterMock);
+
+        return $filterMock;
+    }
+
+    /**
+     * @return array
+     */
+    public function getPrepareDataProvider()
+    {
+        return [
+            [
+                'test_date',
+                ['test_date' => ['from' => '11-05-2015', 'to' => null]],
+                ['date' => '2015-05-11T00:00:00+0000', 'type' => 'gteq'],
+            ],
+            [
+                'test_date',
+                ['test_date' => ['from' => null, 'to' => '11-05-2015']],
+                ['date' => '2015-05-11T23:59:00+0000', 'type' => 'lteq'],
+            ],
+            [
+                'test_date',
+                ['test_date' => ['from' => '11-05-2015', 'to' => '11-05-2015']],
+                [
+                    'date_from' => '2015-05-11T00:00:00+0000', 'type_from' => 'gteq',
+                    'date_to' => '2015-05-11T23:59:00+0000', 'type_to' => 'lteq'
+                ],
+            ],
+            [
+                'test_date',
+                ['test_date' => '11-05-2015'],
+                ['date' => '2015-05-11T00:00:00+0000', 'type' => 'eq'],
+            ],
+            [
+                'test_date',
+                ['test_date' => ['from' => '', 'to' => '']],
+                null,
+            ]
+        ];
+    }
+}
diff --git a/app/code/Magento/Braintree/Ui/Component/Report/Filters/Type/DateRange.php b/app/code/Magento/Braintree/Ui/Component/Report/Filters/Type/DateRange.php
new file mode 100644
index 0000000000000000000000000000000000000000..adbb3b78cb663d92a46e7abdd9c41d70f63e3145
--- /dev/null
+++ b/app/code/Magento/Braintree/Ui/Component/Report/Filters/Type/DateRange.php
@@ -0,0 +1,19 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Braintree\Ui\Component\Report\Filters\Type;
+
+/**
+ * Class DateRange
+ */
+class DateRange extends \Magento\Ui\Component\Filters\Type\Date
+{
+    /**
+     * Braintree date format
+     *
+     * @var string
+     */
+    protected static $dateFormat = 'Y-m-d\TH:i:00O';
+}
diff --git a/app/code/Magento/Braintree/Ui/Component/Report/Listing/Column/PaymentType.php b/app/code/Magento/Braintree/Ui/Component/Report/Listing/Column/PaymentType.php
index df6c2ffcd229dd244c8f39a8191ac0955fd936c6..489c0d4cd1e49cd5b788b6927ee09515285b049c 100644
--- a/app/code/Magento/Braintree/Ui/Component/Report/Listing/Column/PaymentType.php
+++ b/app/code/Magento/Braintree/Ui/Component/Report/Listing/Column/PaymentType.php
@@ -44,12 +44,12 @@ class PaymentType implements OptionSourceInterface
     private function getAvailablePaymentTypes()
     {
         return [
-            PaymentInstrumentType::PAYPAL_ACCOUNT => __('Paypal account'),
-            PaymentInstrumentType::COINBASE_ACCOUNT => __('Coinbase account'),
-            PaymentInstrumentType::EUROPE_BANK_ACCOUNT => __('Europe bank account'),
-            PaymentInstrumentType::CREDIT_CARD => __('Credit card'),
-            PaymentInstrumentType::APPLE_PAY_CARD => __('Apple pay card'),
-            PaymentInstrumentType::ANDROID_PAY_CARD => __('Android pay card')
+            PaymentInstrumentType::PAYPAL_ACCOUNT => __(PaymentInstrumentType::PAYPAL_ACCOUNT),
+            PaymentInstrumentType::COINBASE_ACCOUNT => __(PaymentInstrumentType::COINBASE_ACCOUNT),
+            PaymentInstrumentType::EUROPE_BANK_ACCOUNT => __(PaymentInstrumentType::EUROPE_BANK_ACCOUNT),
+            PaymentInstrumentType::CREDIT_CARD => __(PaymentInstrumentType::CREDIT_CARD),
+            PaymentInstrumentType::APPLE_PAY_CARD => __(PaymentInstrumentType::APPLE_PAY_CARD),
+            PaymentInstrumentType::ANDROID_PAY_CARD => __(PaymentInstrumentType::ANDROID_PAY_CARD)
         ];
     }
 }
diff --git a/app/code/Magento/Braintree/Ui/Component/Report/Listing/Column/Status.php b/app/code/Magento/Braintree/Ui/Component/Report/Listing/Column/Status.php
index f5424c6dd9b7f1a1c30b761fe6b3041017191c7e..ca6d6522990b42e11fb4e8230d2c4fee2a64d68e 100644
--- a/app/code/Magento/Braintree/Ui/Component/Report/Listing/Column/Status.php
+++ b/app/code/Magento/Braintree/Ui/Component/Report/Listing/Column/Status.php
@@ -44,20 +44,20 @@ class Status implements OptionSourceInterface
     private function getAvailableStatuses()
     {
         return [
-            Transaction::AUTHORIZATION_EXPIRED => __('Authorization expired'),
-            Transaction::AUTHORIZING => __('Authorizing'),
-            Transaction::AUTHORIZED => __('Authorized'),
-            Transaction::GATEWAY_REJECTED => __('Gateway rejected'),
-            Transaction::FAILED => __('Failed'),
-            Transaction::PROCESSOR_DECLINED => __('Processor declined'),
-            Transaction::SETTLED => __('Settled'),
-            Transaction::SETTLING => __('Settling'),
-            Transaction::SUBMITTED_FOR_SETTLEMENT => __('Submitted for settlement'),
-            Transaction::VOIDED => __('Voided'),
-            Transaction::UNRECOGNIZED => __('Unrecognized'),
-            Transaction::SETTLEMENT_DECLINED => __('Settlement declined'),
-            Transaction::SETTLEMENT_PENDING => __('Settlement pending'),
-            Transaction::SETTLEMENT_CONFIRMED => __('Settlement confirmed')
+            Transaction::AUTHORIZATION_EXPIRED => __(Transaction::AUTHORIZATION_EXPIRED),
+            Transaction::AUTHORIZING => __(Transaction::AUTHORIZING),
+            Transaction::AUTHORIZED => __(Transaction::AUTHORIZED),
+            Transaction::GATEWAY_REJECTED => __(Transaction::GATEWAY_REJECTED),
+            Transaction::FAILED => __(Transaction::FAILED),
+            Transaction::PROCESSOR_DECLINED => __(Transaction::PROCESSOR_DECLINED),
+            Transaction::SETTLED => __(Transaction::SETTLED),
+            Transaction::SETTLING => __(Transaction::SETTLING),
+            Transaction::SUBMITTED_FOR_SETTLEMENT => __(Transaction::SUBMITTED_FOR_SETTLEMENT),
+            Transaction::VOIDED => __(Transaction::VOIDED),
+            Transaction::UNRECOGNIZED => __(Transaction::UNRECOGNIZED),
+            Transaction::SETTLEMENT_DECLINED => __(Transaction::SETTLEMENT_DECLINED),
+            Transaction::SETTLEMENT_PENDING => __(Transaction::SETTLEMENT_PENDING),
+            Transaction::SETTLEMENT_CONFIRMED => __(Transaction::SETTLEMENT_CONFIRMED)
         ];
     }
 }
diff --git a/app/code/Magento/Braintree/Ui/Component/Report/Listing/Column/TransactionType.php b/app/code/Magento/Braintree/Ui/Component/Report/Listing/Column/TransactionType.php
index 312b2f518b4644a3ba5165b877d0bba5b0ed9e4b..0fe752d423277f58c6ee79354541d910a00eb8a8 100644
--- a/app/code/Magento/Braintree/Ui/Component/Report/Listing/Column/TransactionType.php
+++ b/app/code/Magento/Braintree/Ui/Component/Report/Listing/Column/TransactionType.php
@@ -44,8 +44,8 @@ class TransactionType implements OptionSourceInterface
     private function getAvailableTransactionTypes()
     {
         return [
-            Transaction::SALE => __('Sale'),
-            Transaction::CREDIT => __('Credit')
+            Transaction::SALE => __(Transaction::SALE),
+            Transaction::CREDIT => __(Transaction::CREDIT)
         ];
     }
 }
diff --git a/app/code/Magento/Braintree/composer.json b/app/code/Magento/Braintree/composer.json
index fb833f763f370daf493eaf1a16e6791fca7e4f2a..9a86aec7a7d9dd391096b7ae8bd390ef39ec6dad 100644
--- a/app/code/Magento/Braintree/composer.json
+++ b/app/code/Magento/Braintree/composer.json
@@ -17,6 +17,7 @@
         "magento/module-quote": "100.2.*",
         "magento/module-paypal": "100.2.*",
         "magento/module-theme": "100.2.*",
+        "magento/module-ui": "100.2.*",
         "braintree/braintree_php": "3.7.0"
     },
     "suggest": {
diff --git a/app/code/Magento/Braintree/etc/adminhtml/system.xml b/app/code/Magento/Braintree/etc/adminhtml/system.xml
index 3668cd7779fdac701547ecb4d3b7471471943453..765260ce382917554a27b840c27e98ed2c1d8d6a 100644
--- a/app/code/Magento/Braintree/etc/adminhtml/system.xml
+++ b/app/code/Magento/Braintree/etc/adminhtml/system.xml
@@ -18,6 +18,7 @@
                     <label><![CDATA[&nbsp;]]></label>
                     <frontend_model>Magento\Paypal\Block\Adminhtml\System\Config\Fieldset\Payment</frontend_model>
                     <attribute type="activity_path">payment/braintree/active</attribute>
+                    <more_url>https://articles.braintreepayments.com/guides/magento/configuration</more_url>
                     <field id="active" translate="label" type="select" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="0">
                         <label>Enable this Solution</label>
                         <source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
@@ -43,7 +44,7 @@
                         </requires>
                     </field>
                     <group id="braintree_required" translate="label" showInDefault="1" showInWebsite="1" sortOrder="5">
-                        <comment><![CDATA[<a href="https://www.braintreegateway.com/login" target="_blank">Click here to login to your existing Braintree account</a>. Or to setup a new account and accept payments on your website, <a href="https://apply.braintreegateway.com/signup/us" target="_blank">click here to signup for a Braintree account</a>.]]></comment>
+                        <comment><![CDATA[<a href="https://www.braintreegateway.com/login" target="_blank">Click here to login to your existing Braintree account</a>. Or to setup a new account and accept payments on your website, <a href="https://apply.braintreegateway.com/signup/us" target="_blank">click here to signup for a Braintree account</a>.<br><br>Powered by <a href="https://www.braintreepayments.com/features/hosted-fields" target="_blank">Braintree v.zero with Hosted Fields</a> latest technology. Hosted Fields are small, transparent iframes that replace the sensitive credit card inputs in your checkout flow - helping you meet the latest data security requirements while ensuring your customization doesn't suffer. <a href="https://www.braintreepayments.com/features/hosted-fields" target="_blank">Find out more</a>.]]></comment>
                         <label>Basic Braintree Settings</label>
                         <attribute type="expanded">1</attribute>
                         <frontend_model>Magento\Config\Block\System\Config\Form\Fieldset</frontend_model>
diff --git a/app/code/Magento/Braintree/i18n/en_US.csv b/app/code/Magento/Braintree/i18n/en_US.csv
index f912e59c2edac48bc7da882f692c57802f07b54e..4cdb8538c3abf53b759b94d2adf78178654b9972 100644
--- a/app/code/Magento/Braintree/i18n/en_US.csv
+++ b/app/code/Magento/Braintree/i18n/en_US.csv
@@ -140,6 +140,28 @@ Debug,Debug
 "liabilityShifted", "Liability Shifted"
 "liabilityShiftPossible", "Liability Shift Possible"
 "riskDataId", "Risk ID"
-"riskDataDecision", "Risk Decision",
-"paymentId", "Payment Id",
-"payerEmail", "Payer Email",
+"riskDataDecision", "Risk Decision"
+"paymentId", "Payment Id"
+"payerEmail", "Payer Email"
+"sale","Sale"
+"credit","Credit"
+"authorization_expired","Authorization expired"
+"authorizing","Authorizing"
+"authorized","Authorized"
+"gateway_rejected","Gateway rejected"
+"failed","Failed"
+"processor_declined","Processor declined"
+"settled","Settled"
+"settling","Settling"
+"submitted_for_settlement","Submitted for settlement"
+"voided","Voided"
+"unrecognized","Unrecognized"
+"settlement_declined","Settlement declined"
+"settlement_pending","Settlement pending"
+"settlement_confirmed","Settlement confirmed"
+"paypal_account","Paypal account"
+"coinbase_account","Coinbase account"
+"europe_bank_accout","Europe bank account"
+"credit_card","Credit card"
+"apple_pay_card","Apple pay card"
+"android_pay_card","Android pay card"
\ No newline at end of file
diff --git a/app/code/Magento/Braintree/view/adminhtml/layout/sales_order_create_index.xml b/app/code/Magento/Braintree/view/adminhtml/layout/sales_order_create_index.xml
index 76f6b5a4d616cc4da49008649411fd8c2afe6689..5c519899208db8fd966552bab21ec893b7b6477f 100644
--- a/app/code/Magento/Braintree/view/adminhtml/layout/sales_order_create_index.xml
+++ b/app/code/Magento/Braintree/view/adminhtml/layout/sales_order_create_index.xml
@@ -19,12 +19,12 @@
                 <argument name="template" xsi:type="string">Magento_Vault::form/vault.phtml</argument>
             </action>
         </referenceBlock>
-        <referenceBlock name="content">
+        <referenceBlock name="data">
             <block name="braintree_payment_script"
                    as="braintree_payment_script"
-                   after="billing_method"
                    template="Magento_Braintree::payment/script.phtml"
-                   class="Magento\Braintree\Block\Payment"/>
+                   class="Magento\Braintree\Block\Payment"
+                   after="billing_method"/>
         </referenceBlock>
     </body>
 </page>
diff --git a/app/code/Magento/Braintree/view/adminhtml/ui_component/braintree_report.xml b/app/code/Magento/Braintree/view/adminhtml/ui_component/braintree_report.xml
index d1b661b2c3ecdf0d6bb92ffc03e3a235e090cb5f..031ddca7a87070ccad2a53a204aec84c67e62f1b 100644
--- a/app/code/Magento/Braintree/view/adminhtml/ui_component/braintree_report.xml
+++ b/app/code/Magento/Braintree/view/adminhtml/ui_component/braintree_report.xml
@@ -109,7 +109,6 @@
                     </item>
                 </argument>
             </filterSelect>
-            <!--
             <filterSelect name="paymentInstrumentType">
                 <argument name="optionsProvider" xsi:type="configurableObject">
                     <argument name="class" xsi:type="string">Magento\Braintree\Ui\Component\Report\Listing\Column\PaymentType</argument>
@@ -126,7 +125,6 @@
                     </item>
                 </argument>
             </filterSelect>
-            -->
             <filterInput name="paypalDetails_paymentId">
                 <argument name="data" xsi:type="array">
                     <item name="config" xsi:type="array">
@@ -135,6 +133,22 @@
                     </item>
                 </argument>
             </filterInput>
+            <filterRange name="createdAt" class="Magento\Braintree\Ui\Component\Report\Filters\Type\DateRange">
+                <argument name="data" xsi:type="array">
+                    <item name="config" xsi:type="array">
+                        <item name="provider" xsi:type="string">${ $.parentName }</item>
+                        <item name="imports" xsi:type="array">
+                            <item name="visible" xsi:type="string">componentType = column, index = ${ $.index }:visible</item>
+                        </item>
+                        <item name="parent" xsi:type="string">braintree_report.braintree_report.listing_top.listing_filters</item>
+                        <item name="template" xsi:type="string">ui/grid/filters/elements/group</item>
+                        <item name="component" xsi:type="string">Magento_Ui/js/grid/filters/range</item>
+                        <item name="rangeType" xsi:type="string">date</item>
+                        <item name="dataScope" xsi:type="string">createdAt</item>
+                        <item name="label" xsi:type="string" translate="true">Created At</item>
+                    </item>
+                </argument>
+            </filterRange>
         </filters>
     </container>
     <columns name="braintree_report_columns">
@@ -216,7 +230,6 @@
             <argument name="data" xsi:type="array">
                 <item name="config" xsi:type="array">
                     <item name="sorting" xsi:type="string">desc</item>
-                    <item name="filter" xsi:type="string">dateRange</item>
                     <item name="dataType" xsi:type="string">date</item>
                     <item name="component" xsi:type="string">Magento_Ui/js/grid/columns/date</item>
                     <item name="label" xsi:type="string" translate="true">Created At</item>
diff --git a/app/code/Magento/Braintree/view/frontend/web/js/view/payment/braintree.js b/app/code/Magento/Braintree/view/frontend/web/js/view/payment/braintree.js
index cb0b46a25327e10a54a771c887f60dd3b4817cc3..3cec7f1fb8ccc83ad21c7605918ffaca50d78387 100644
--- a/app/code/Magento/Braintree/view/frontend/web/js/view/payment/braintree.js
+++ b/app/code/Magento/Braintree/view/frontend/web/js/view/payment/braintree.js
@@ -7,26 +7,19 @@
 define(
     [
         'uiComponent',
-        'uiRegistry',
-        'Magento_Braintree/js/view/payment/adapter',
         'Magento_Checkout/js/model/payment/renderer-list'
     ],
     function (
         Component,
-        Registry,
-        Braintree,
         rendererList
     ) {
         'use strict';
 
         var config = window.checkoutConfig.payment,
             braintreeType = 'braintree',
-            payPalType = 'braintree_paypal',
-            path = 'checkout.steps.billing-step.payment.payments-list.',
-            components = [];
+            payPalType = 'braintree_paypal';
 
         if (config[braintreeType].isActive) {
-            components.push(path + braintreeType);
             rendererList.push(
                 {
                     type: braintreeType,
@@ -44,13 +37,6 @@ define(
             );
         }
 
-        // setup Braintree SDK with merged configuration from all related components
-        if (components.length) {
-            Registry.get(components, function () {
-                Braintree.setup();
-            });
-        }
-
         /** Add view logic here if needed */
         return Component.extend({});
     }
diff --git a/app/code/Magento/Braintree/view/frontend/web/js/view/payment/method-renderer/cc-form.js b/app/code/Magento/Braintree/view/frontend/web/js/view/payment/method-renderer/cc-form.js
index 6990c1e2e5a0bb78c52e0075f94995bb0da390ae..af71eb29a158d9c1573eb4dca60026f567afe796 100644
--- a/app/code/Magento/Braintree/view/frontend/web/js/view/payment/method-renderer/cc-form.js
+++ b/app/code/Magento/Braintree/view/frontend/web/js/view/payment/method-renderer/cc-form.js
@@ -61,11 +61,22 @@ define(
                         this.beforePlaceOrder(response);
                     },
 
+                    /**
+                     * Device data initialization
+                     *
+                     * @param {Object} checkout
+                     */
+                    onReady: function (checkout) {
+                        braintree.checkout = checkout;
+                    },
+
                     /**
                      * Triggers on any Braintree error
+                     * @param {Object} response
                      */
-                    onError: function () {
-                        this.paymentMethodNonce = null;
+                    onError: function (response) {
+                        braintree.showError($t('Payment ' + this.getTitle() + ' can\'t be initialized'));
+                        throw response.message;
                     },
 
                     /**
@@ -90,7 +101,7 @@ define(
                 this._super()
                     .observe(['active']);
                 this.validatorManager.initialize();
-                this.initBraintree();
+                this.initClientConfig();
 
                 return this;
             },
@@ -122,11 +133,11 @@ define(
              * @param {Boolean} isActive
              */
             onActiveChange: function (isActive) {
-                if (!isActive || this.isSingleUse()) {
+                if (!isActive) {
                     return;
                 }
 
-                this.reInitBraintree();
+                this.initBraintree();
             },
 
             /**
@@ -146,17 +157,9 @@ define(
             },
 
             /**
-             * Create Braintree configuration
+             * Init Braintree configuration
              */
             initBraintree: function () {
-                this.initClientConfig();
-                braintree.config = _.extend(braintree.config, this.clientConfig);
-            },
-
-            /**
-             * Re-init Braintree configuration
-             */
-            reInitBraintree: function () {
                 var intervalId = setInterval(function () {
                     // stop loader when frame will be loaded
                     if ($('#braintree-hosted-field-number').length) {
@@ -165,6 +168,12 @@ define(
                     }
                 }, 500);
 
+                if (braintree.checkout) {
+                    braintree.checkout.teardown(function () {
+                        braintree.checkout = null;
+                    });
+                }
+
                 fullScreenLoader.startLoader();
                 braintree.setConfig(this.clientConfig);
                 braintree.setup();
@@ -309,14 +318,6 @@ define(
                 });
 
                 return false;
-            },
-
-            /**
-             * Check if Braintree configured without PayPal
-             * @returns {Boolean}
-             */
-            isSingleUse: function () {
-                return window.checkoutConfig.payment[this.getCode()].isSingleUse;
             }
         });
     }
diff --git a/app/code/Magento/Bundle/Pricing/Price/BundleSelectionPrice.php b/app/code/Magento/Bundle/Pricing/Price/BundleSelectionPrice.php
index 3239931d5df7fb9a758425583617f9cb5c8cfeb0..5222e52c1145d6e7f7282d32899937f3fdd1eab4 100644
--- a/app/code/Magento/Bundle/Pricing/Price/BundleSelectionPrice.php
+++ b/app/code/Magento/Bundle/Pricing/Price/BundleSelectionPrice.php
@@ -124,7 +124,7 @@ class BundleSelectionPrice extends AbstractPrice
                 $value = $product->getData('final_price') * ($selectionPriceValue / 100);
             } else {
                 // calculate price for selection type fixed
-                $value = $this->priceCurrency->convert($selectionPriceValue) * $this->quantity;
+                $value = $this->priceCurrency->convert($selectionPriceValue);
             }
         }
         if (!$this->useRegularPrice) {
diff --git a/app/code/Magento/Bundle/Test/Unit/Pricing/Price/BundleSelectionPriceTest.php b/app/code/Magento/Bundle/Test/Unit/Pricing/Price/BundleSelectionPriceTest.php
index ddb5df9b6ced1c508a4123384c80c430249b57ca..d778f64f30bdf3c02144c28e1d7be9913b923fa4 100644
--- a/app/code/Magento/Bundle/Test/Unit/Pricing/Price/BundleSelectionPriceTest.php
+++ b/app/code/Magento/Bundle/Test/Unit/Pricing/Price/BundleSelectionPriceTest.php
@@ -313,6 +313,67 @@ class BundleSelectionPriceTest extends \PHPUnit_Framework_TestCase
         $this->assertEquals($expectedPrice, $this->selectionPrice->getValue());
     }
 
+    /**
+     * test for method getValue with type Fixed and selectionPriceType is empty or zero
+     *
+     * @param bool $useRegularPrice
+     * @dataProvider useRegularPriceDataProvider
+     */
+    public function testFixedPriceWithMultipleQty($useRegularPrice)
+    {
+        $qty = 2;
+
+        $selectionPrice = new \Magento\Bundle\Pricing\Price\BundleSelectionPrice(
+            $this->productMock,
+            $qty,
+            $this->calculatorMock,
+            $this->priceCurrencyMock,
+            $this->bundleMock,
+            $this->eventManagerMock,
+            $this->discountCalculatorMock,
+            $useRegularPrice
+        );
+
+        $this->setupSelectionPrice($useRegularPrice);
+        $regularPrice = 100.125;
+        $discountedPrice = 70.453;
+        $convertedValue = 100.247;
+        $actualPrice = $useRegularPrice ? $convertedValue : $discountedPrice;
+        $expectedPrice = $useRegularPrice ? round($convertedValue, 2) : round($discountedPrice, 2);
+
+        $this->bundleMock->expects($this->once())
+            ->method('getPriceType')
+            ->will($this->returnValue(\Magento\Bundle\Model\Product\Price::PRICE_TYPE_FIXED));
+        $this->productMock->expects($this->once())
+            ->method('getSelectionPriceType')
+            ->will($this->returnValue(false));
+        $this->productMock->expects($this->any())
+            ->method('getSelectionPriceValue')
+            ->will($this->returnValue($regularPrice));
+
+        $this->priceCurrencyMock->expects($this->once())
+            ->method('convert')
+            ->with($regularPrice)
+            ->will($this->returnValue($convertedValue));
+
+        if (!$useRegularPrice) {
+            $this->discountCalculatorMock->expects($this->once())
+                ->method('calculateDiscount')
+                ->with(
+                    $this->equalTo($this->bundleMock),
+                    $this->equalTo($convertedValue)
+                )
+                ->will($this->returnValue($discountedPrice));
+        }
+
+        $this->priceCurrencyMock->expects($this->once())
+            ->method('round')
+            ->with($actualPrice)
+            ->will($this->returnValue($expectedPrice));
+
+        $this->assertEquals($expectedPrice, $selectionPrice->getValue());
+    }
+
     public function useRegularPriceDataProvider()
     {
         return [
diff --git a/app/code/Magento/Bundle/view/base/web/js/price-bundle.js b/app/code/Magento/Bundle/view/base/web/js/price-bundle.js
index c4999b0d2a8b80cde1beec512c0399ed293c6f46..1a76acf17475670674c064c8384d628b87d924a7 100644
--- a/app/code/Magento/Bundle/view/base/web/js/price-bundle.js
+++ b/app/code/Magento/Bundle/view/base/web/js/price-bundle.js
@@ -55,7 +55,6 @@ define([
                 this._setOption('priceFormat', priceBox.priceBox('option').priceConfig.priceFormat);
                 priceBox.priceBox('setDefault', this.options.optionConfig.prices);
             }
-            this._applyQtyFix();
             this._applyOptionNodeFix(options);
 
             options.on('change', this._onBundleOptionChanged.bind(this));
@@ -113,6 +112,7 @@ define([
          * Helper to fix backend behavior:
          *  - if default qty large than 1 then backend multiply price in config
          *
+         * @deprecated
          * @private
          */
         _applyQtyFix: function applyQtyFix() {
diff --git a/app/code/Magento/Bundle/view/frontend/layout/catalog_product_view_type_bundle.xml b/app/code/Magento/Bundle/view/frontend/layout/catalog_product_view_type_bundle.xml
index ab0d6c303b2e7a4b273c28c1f01d822fa8416e98..5ab962f0b91b55dd6f617b97fa0f92e73cde766e 100644
--- a/app/code/Magento/Bundle/view/frontend/layout/catalog_product_view_type_bundle.xml
+++ b/app/code/Magento/Bundle/view/frontend/layout/catalog_product_view_type_bundle.xml
@@ -36,7 +36,7 @@
             </block>
         </referenceBlock>
         <referenceBlock name="product.info.form.options">
-            <container name="bundle.product.options.wrapper" htmlTag="div" htmlClass="bundle-options-wrapper" after="product.info.form.options" />
+            <container name="bundle.product.options.wrapper" htmlTag="div" htmlClass="bundle-options-wrapper"/>
         </referenceBlock> 
         <move element="product.info.options.wrapper" destination="bundle.product.options.wrapper" before="-" />
         <move element="product.info.options.wrapper.bottom" destination="bundle.product.options.wrapper" after="product.info.options.wrapper" />
diff --git a/app/code/Magento/Catalog/Pricing/Price/TierPrice.php b/app/code/Magento/Catalog/Pricing/Price/TierPrice.php
index 6835453173dbd02b25e53a63b34bc4905a888d5c..6c4820d5184ac8f458b7065f80819e82fa12119c 100644
--- a/app/code/Magento/Catalog/Pricing/Price/TierPrice.php
+++ b/app/code/Magento/Catalog/Pricing/Price/TierPrice.php
@@ -208,7 +208,7 @@ class TierPrice extends AbstractPrice implements TierPriceInterface, BasePricePr
      */
     public function getSavePercent(AmountInterface $amount)
     {
-        return ceil(
+        return round(
             100 - ((100 / $this->priceInfo->getPrice(FinalPrice::PRICE_CODE)->getValue())
                 * $amount->getBaseAmount())
         );
diff --git a/app/code/Magento/Catalog/Setup/CategorySetup.php b/app/code/Magento/Catalog/Setup/CategorySetup.php
index 14c23b0cb92bbf50dac38337f793c5e12dd22b46..a6eb9b7f19365988f220d82488d2eb2635350f34 100644
--- a/app/code/Magento/Catalog/Setup/CategorySetup.php
+++ b/app/code/Magento/Catalog/Setup/CategorySetup.php
@@ -24,6 +24,16 @@ class CategorySetup extends EavSetup
      */
     private $categoryFactory;
 
+    /**
+     * This should be set explicitly
+     */
+    const CATEGORY_ENTITY_TYPE_ID = 3;
+
+    /**
+     * This should be set explicitly
+     */
+    const CATALOG_PRODUCT_ENTITY_TYPE_ID = 4;
+
     /**
      * Init
      *
@@ -66,6 +76,7 @@ class CategorySetup extends EavSetup
     {
         return [
             'catalog_category' => [
+                'entity_type_id' => self::CATEGORY_ENTITY_TYPE_ID,
                 'entity_model' => 'Magento\Catalog\Model\ResourceModel\Category',
                 'attribute_model' => 'Magento\Catalog\Model\ResourceModel\Eav\Attribute',
                 'table' => 'catalog_category_entity',
@@ -334,6 +345,7 @@ class CategorySetup extends EavSetup
                 ],
             ],
             'catalog_product' => [
+                'entity_type_id' => self::CATALOG_PRODUCT_ENTITY_TYPE_ID,
                 'entity_model' => 'Magento\Catalog\Model\ResourceModel\Product',
                 'attribute_model' => 'Magento\Catalog\Model\ResourceModel\Eav\Attribute',
                 'table' => 'catalog_product_entity',
diff --git a/app/code/Magento/Catalog/Test/Unit/Pricing/Price/TierPriceTest.php b/app/code/Magento/Catalog/Test/Unit/Pricing/Price/TierPriceTest.php
index fce88c3a3fea780d8ab05cc1fce24aba8383a1a7..ab7c62d9b5669cc33ac91f7ed20bd6b8566eafdc 100644
--- a/app/code/Magento/Catalog/Test/Unit/Pricing/Price/TierPriceTest.php
+++ b/app/code/Magento/Catalog/Test/Unit/Pricing/Price/TierPriceTest.php
@@ -394,7 +394,8 @@ class TierPriceTest extends \PHPUnit_Framework_TestCase
         return [
             ['basePrice' => '100', 'tierPrice' => '90', 'savedPercent' => '10'],
             ['basePrice' => '70', 'tierPrice' => '35', 'savedPercent' => '50'],
-            ['basePrice' => '50', 'tierPrice' => '35', 'savedPercent' => '30']
+            ['basePrice' => '50', 'tierPrice' => '35', 'savedPercent' => '30'],
+            ['basePrice' => '20.80', 'tierPrice' => '18.72', 'savedPercent' => '10']
         ];
     }
 }
diff --git a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_set_edit.xml b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_set_edit.xml
index 1c7ae6de66ed062c751ddfa23e062c4b24d9a453..d61a2c344d666277fa2312ffea0c3f10c30d576c 100644
--- a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_set_edit.xml
+++ b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_set_edit.xml
@@ -9,7 +9,9 @@
     <body>
         <referenceContainer name="content">
             <container name="adminhtml.catalog.product.set.edit.wrapper" htmlTag="div" htmlClass="admin__scope-old"><!-- @todo ui: remove arguments within .admin__scope-old -->
-                <block class="Magento\Catalog\Block\Adminhtml\Product\Attribute\Set\Main" name="adminhtml.catalog.product.set.edit" template="catalog/product/attribute/set/main.phtml"/>
+                <block class="Magento\Catalog\Block\Adminhtml\Product\Attribute\Set\Main"
+                       name="adminhtml.catalog.product.set.edit"
+                       template="catalog/product/attribute/set/main.phtml"/>
             </container>
         </referenceContainer>
     </body>
diff --git a/app/code/Magento/Catalog/view/frontend/layout/catalog_product_view.xml b/app/code/Magento/Catalog/view/frontend/layout/catalog_product_view.xml
index f7f1ee4ae54b7d81c8b8c9b13203481203b732d2..991d9a36d18e04c7e8b17744dd3b2d32981fdc18 100644
--- a/app/code/Magento/Catalog/view/frontend/layout/catalog_product_view.xml
+++ b/app/code/Magento/Catalog/view/frontend/layout/catalog_product_view.xml
@@ -30,7 +30,7 @@
         </referenceBlock>
         <referenceContainer name="content">
             <container name="product.info.main" htmlTag="div" htmlClass="product-info-main" before="-">
-                <container name="product.info.price" label="Product info auxiliary container" htmlTag="div" htmlClass="product-info-price" after="product.info.review">
+                <container name="product.info.price" label="Product info auxiliary container" htmlTag="div" htmlClass="product-info-price">
                     <container name="product.info.stock.sku" label="Product auxiliary info" htmlTag="div" htmlClass="product-info-stock-sku">
                         <container name="product.info.type" before="-"/>
                         <block class="Magento\Catalog\Block\Product\View\Description" name="product.info.sku" template="product/view/attribute.phtml" after="product.info.type">
@@ -44,7 +44,7 @@
                         </block>
                     </container>
                     <block class="Magento\Catalog\Block\Product\View" name="product.info.review" template="product/view/review.phtml" after="product.info.stock.sku" />
-                    <block class="Magento\Catalog\Pricing\Render" name="product.price.final" after="product.info.sku">
+                    <block class="Magento\Catalog\Pricing\Render" name="product.price.final">
                         <arguments>
                             <argument name="price_render" xsi:type="string">product.price.render.default</argument>
                             <argument name="price_type_code" xsi:type="string">final_price</argument>
@@ -81,7 +81,7 @@
                     </block>
                 </block>
                 <container name="product.info.extrahint" as="extrahint" label="Product View Extra Hint">
-                    <container name="product.info.social" label="Product social links container" htmlTag="div" htmlClass="product-social-links" after="product.info.overview">
+                    <container name="product.info.social" label="Product social links container" htmlTag="div" htmlClass="product-social-links">
                         <block class="Magento\Catalog\Block\Product\View" name="product.info.addto" as="addto" template="product/view/addto.phtml">
                             <block class="Magento\Catalog\Block\Product\View\AddTo\Compare" name="view.addto.compare" after="view.addto.wishlist"
                                    template="Magento_Catalog::product/view/addto/compare.phtml" />
diff --git a/app/code/Magento/CatalogRule/view/adminhtml/layout/catalog_rule_promo_catalog_edit.xml b/app/code/Magento/CatalogRule/view/adminhtml/layout/catalog_rule_promo_catalog_edit.xml
index 37a39835fe9f6d1fefe54b2e629ebb8d1cc871da..ef8a6e758bac1c470dd9d80bca27e302db828ba7 100644
--- a/app/code/Magento/CatalogRule/view/adminhtml/layout/catalog_rule_promo_catalog_edit.xml
+++ b/app/code/Magento/CatalogRule/view/adminhtml/layout/catalog_rule_promo_catalog_edit.xml
@@ -5,21 +5,21 @@
  * 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">
+<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="admin-1column" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
     <body>
         <referenceContainer name="content">
             <referenceBlock name="catalog_rule_form">
                 <block class="Magento\CatalogRule\Block\Adminhtml\Promo\Catalog\Edit\Tab\Conditions" name="promo_catalog_edit_tab_conditions">
                     <arguments>
-                    <argument name="config" xsi:type="array">
-                        <item name="label" xsi:type="string" translate="true">Conditions</item>
-                        <item name="collapsible" xsi:type="boolean">true</item>
-                        <item name="opened" xsi:type="boolean">false</item>
-                        <item name="sortOrder" xsi:type="number">20</item>
-                        <item name="canShow" xsi:type="boolean">true</item>
-                        <item name="componentType" xsi:type="string">fieldset</item>
-                    </argument>
-                </arguments>
+                        <argument name="config" xsi:type="array">
+                            <item name="label" xsi:type="string" translate="true">Conditions</item>
+                            <item name="collapsible" xsi:type="boolean">true</item>
+                            <item name="opened" xsi:type="boolean">false</item>
+                            <item name="sortOrder" xsi:type="number">20</item>
+                            <item name="canShow" xsi:type="boolean">true</item>
+                            <item name="componentType" xsi:type="string">fieldset</item>
+                        </argument>
+                    </arguments>
                 </block>
             </referenceBlock>
             <uiComponent name="catalog_rule_form"/>
diff --git a/app/code/Magento/Config/view/adminhtml/templates/page/system/config/robots/reset.phtml b/app/code/Magento/Config/view/adminhtml/templates/page/system/config/robots/reset.phtml
index bacb94868cb603a15f7a453a8e953ce6531b27fe..3bfd63c8ee09d4e7f86f2bbe4d4b992cc904e668 100644
--- a/app/code/Magento/Config/view/adminhtml/templates/page/system/config/robots/reset.phtml
+++ b/app/code/Magento/Config/view/adminhtml/templates/page/system/config/robots/reset.phtml
@@ -7,6 +7,7 @@
 // @codingStandardsIgnoreFile
 
 /**
+ * @deprecated
  * @var $block \Magento\Backend\Block\Page\System\Config\Robots\Reset
  * @var $jsonHelper \Magento\Framework\Json\Helper\Data
  */
diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/layout/catalog_product_set_edit.xml b/app/code/Magento/ConfigurableProduct/view/adminhtml/layout/catalog_product_set_edit.xml
index 9a56d1f172cd4ee4c354bdbb91896f7d82f0f336..a72f712e77f3f6fa3f4aa4855c91ef33268e65fe 100644
--- a/app/code/Magento/ConfigurableProduct/view/adminhtml/layout/catalog_product_set_edit.xml
+++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/layout/catalog_product_set_edit.xml
@@ -8,7 +8,10 @@
 <page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
     <body>
         <referenceContainer name="content">
-            <block class="Magento\Backend\Block\Template" name="adminhtml.catalog.product.set.edit.configurable" template="Magento_ConfigurableProduct::catalog/product/attribute/set/js.phtml" after="adminhtml.catalog.product.set.edit"/>
+            <block class="Magento\Backend\Block\Template"
+                   name="adminhtml.catalog.product.set.edit.configurable"
+                   template="Magento_ConfigurableProduct::catalog/product/attribute/set/js.phtml"
+                   after="adminhtml.catalog.product.set.edit.wrapper"/>
         </referenceContainer>
     </body>
 </page>
diff --git a/app/code/Magento/Cookie/view/frontend/layout/default.xml b/app/code/Magento/Cookie/view/frontend/layout/default.xml
index d515c6a42a5e88fa1968658a407cbd0e7e0cb8fe..3e8bcafd3dba43b16d0721b8ba11c4d61b0656ea 100644
--- a/app/code/Magento/Cookie/view/frontend/layout/default.xml
+++ b/app/code/Magento/Cookie/view/frontend/layout/default.xml
@@ -8,7 +8,7 @@
 <page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
     <body>
         <referenceContainer name="after.body.start">
-            <block class="Magento\Cookie\Block\Html\Notices" name="cookie_notices" template="html/notices.phtml" after="global_notices" />
+            <block class="Magento\Cookie\Block\Html\Notices" name="cookie_notices" template="html/notices.phtml"/>
         </referenceContainer>
     </body>
 </page>
diff --git a/app/code/Magento/Customer/Controller/Account/EditPost.php b/app/code/Magento/Customer/Controller/Account/EditPost.php
index 8f078e77c3b129810b58145ca79e3868fd7159d8..b2f6384524147274ae808fc32f6478bf7b66f6a1 100644
--- a/app/code/Magento/Customer/Controller/Account/EditPost.php
+++ b/app/code/Magento/Customer/Controller/Account/EditPost.php
@@ -7,8 +7,10 @@
 namespace Magento\Customer\Controller\Account;
 
 use Magento\Customer\Model\AuthenticationInterface;
+use Magento\Customer\Model\Customer\Mapper;
 use Magento\Customer\Model\EmailNotificationInterface;
 use Magento\Framework\App\Config\ScopeConfigInterface;
+use Magento\Framework\App\ObjectManager;
 use Magento\Framework\Data\Form\FormKey\Validator;
 use Magento\Customer\Api\AccountManagementInterface;
 use Magento\Customer\Api\CustomerRepositoryInterface;
@@ -68,6 +70,11 @@ class EditPost extends \Magento\Customer\Controller\AbstractAccount
      */
     private $authentication;
 
+    /**
+     * @var Mapper
+     */
+    private $customerMapper;
+
     /**
      * @param Context $context
      * @param Session $customerSession
@@ -101,7 +108,7 @@ class EditPost extends \Magento\Customer\Controller\AbstractAccount
     {
 
         if (!($this->authentication instanceof AuthenticationInterface)) {
-            return \Magento\Framework\App\ObjectManager::getInstance()->get(
+            return ObjectManager::getInstance()->get(
                 \Magento\Customer\Model\AuthenticationInterface::class
             );
         } else {
@@ -118,7 +125,7 @@ class EditPost extends \Magento\Customer\Controller\AbstractAccount
     private function getEmailNotification()
     {
         if (!($this->emailNotification instanceof EmailNotificationInterface)) {
-            return \Magento\Framework\App\ObjectManager::getInstance()->get(
+            return ObjectManager::getInstance()->get(
                 EmailNotificationInterface::class
             );
         } else {
@@ -196,7 +203,7 @@ class EditPost extends \Magento\Customer\Controller\AbstractAccount
     private function getScopeConfig()
     {
         if (!($this->scopeConfig instanceof \Magento\Framework\App\Config\ScopeConfigInterface)) {
-            return \Magento\Framework\App\ObjectManager::getInstance()->get(
+            return ObjectManager::getInstance()->get(
                 \Magento\Framework\App\Config\ScopeConfigInterface::class
             );
         } else {
@@ -241,7 +248,12 @@ class EditPost extends \Magento\Customer\Controller\AbstractAccount
         \Magento\Framework\App\RequestInterface $inputData,
         \Magento\Customer\Api\Data\CustomerInterface $currentCustomerData
     ) {
-        $customerDto = $this->customerExtractor->extract(self::FORM_DATA_EXTRACTOR_CODE, $inputData);
+        $attributeValues = $this->getCustomerMapper()->toFlatArray($currentCustomerData);
+        $customerDto = $this->customerExtractor->extract(
+            self::FORM_DATA_EXTRACTOR_CODE,
+            $inputData,
+            $attributeValues
+        );
         $customerDto->setId($currentCustomerData->getId());
         if (!$customerDto->getAddresses()) {
             $customerDto->setAddresses($currentCustomerData->getAddresses());
@@ -299,4 +311,19 @@ class EditPost extends \Magento\Customer\Controller\AbstractAccount
             }
         }
     }
+
+    /**
+     * Get Customer Mapper instance
+     *
+     * @return Mapper
+     *
+     * @deprecated
+     */
+    private function getCustomerMapper()
+    {
+        if ($this->customerMapper === null) {
+            $this->customerMapper = ObjectManager::getInstance()->get('Magento\Customer\Model\Customer\Mapper');
+        }
+        return $this->customerMapper;
+    }
 }
diff --git a/app/code/Magento/Customer/Controller/Address/FormPost.php b/app/code/Magento/Customer/Controller/Address/FormPost.php
index 095fec3511c71a65f8f0df8b045053bd677585a0..2b302032f084b796bb6bee19b0c404ff441a56b2 100644
--- a/app/code/Magento/Customer/Controller/Address/FormPost.php
+++ b/app/code/Magento/Customer/Controller/Address/FormPost.php
@@ -9,12 +9,14 @@ use Magento\Customer\Api\AddressRepositoryInterface;
 use Magento\Customer\Api\Data\AddressInterfaceFactory;
 use Magento\Customer\Api\Data\RegionInterface;
 use Magento\Customer\Api\Data\RegionInterfaceFactory;
+use Magento\Customer\Model\Address\Mapper;
 use Magento\Customer\Model\Metadata\FormFactory;
 use Magento\Customer\Model\Session;
 use Magento\Directory\Helper\Data as HelperData;
 use Magento\Directory\Model\RegionFactory;
 use Magento\Framework\Api\DataObjectHelper;
 use Magento\Framework\App\Action\Context;
+use Magento\Framework\App\ObjectManager;
 use Magento\Framework\Controller\Result\ForwardFactory;
 use Magento\Framework\Data\Form\FormKey\Validator as FormKeyValidator;
 use Magento\Framework\Exception\InputException;
@@ -36,6 +38,11 @@ class FormPost extends \Magento\Customer\Controller\Address
      */
     protected $helperData;
 
+    /**
+     * @var Mapper
+     */
+    private $customerAddressMapper;
+
     /**
      * @param Context $context
      * @param Session $customerSession
@@ -127,12 +134,7 @@ class FormPost extends \Magento\Customer\Controller\Address
             if ($existingAddress->getCustomerId() !== $this->_getSession()->getCustomerId()) {
                 throw new \Exception();
             }
-            $existingAddressData = $this->_dataProcessor->buildOutputDataArray(
-                $existingAddress,
-                '\Magento\Customer\Api\Data\AddressInterface'
-            );
-            $existingAddressData['region_code'] = $existingAddress->getRegion()->getRegionCode();
-            $existingAddressData['region'] = $existingAddress->getRegion()->getRegion();
+            $existingAddressData = $this->getCustomerAddressMapper()->toFlatArray($existingAddress);
         }
         return $existingAddressData;
     }
@@ -212,4 +214,19 @@ class FormPost extends \Magento\Customer\Controller\Address
 
         return $this->resultRedirectFactory->create()->setUrl($this->_redirect->error($url));
     }
+
+    /**
+     * Get Customer Address Mapper instance
+     *
+     * @return Mapper
+     *
+     * @deprecated
+     */
+    private function getCustomerAddressMapper()
+    {
+        if ($this->customerAddressMapper === null) {
+            $this->customerAddressMapper = ObjectManager::getInstance()->get('Magento\Customer\Model\Address\Mapper');
+        }
+        return $this->customerAddressMapper;
+    }
 }
diff --git a/app/code/Magento/Customer/Controller/Adminhtml/File/Address/Upload.php b/app/code/Magento/Customer/Controller/Adminhtml/File/Address/Upload.php
new file mode 100644
index 0000000000000000000000000000000000000000..d7f83ba6a6380adadb3ebcd7dd3be1407741585a
--- /dev/null
+++ b/app/code/Magento/Customer/Controller/Adminhtml/File/Address/Upload.php
@@ -0,0 +1,127 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Customer\Controller\Adminhtml\File\Address;
+
+use Magento\Backend\App\Action;
+use Magento\Backend\App\Action\Context;
+use Magento\Customer\Api\AddressMetadataInterface;
+use Magento\Customer\Model\FileUploader;
+use Magento\Customer\Model\FileUploaderFactory;
+use Magento\Framework\Controller\ResultFactory;
+use Magento\Framework\Exception\LocalizedException;
+use Psr\Log\LoggerInterface;
+
+class Upload extends Action
+{
+    /**
+     * Authorization level of a basic admin session
+     *
+     * @see _isAllowed()
+     */
+    const ADMIN_RESOURCE = 'Magento_Customer::manage';
+
+    /**
+     * @var FileUploaderFactory
+     */
+    private $fileUploaderFactory;
+
+    /**
+     * @var AddressMetadataInterface
+     */
+    private $addressMetadataService;
+
+    /**
+     * @var LoggerInterface
+     */
+    private $logger;
+
+    /**
+     * @param Context $context
+     * @param FileUploaderFactory $fileUploaderFactory
+     * @param AddressMetadataInterface $addressMetadataService
+     * @param LoggerInterface $logger
+     */
+    public function __construct(
+        Context $context,
+        FileUploaderFactory $fileUploaderFactory,
+        AddressMetadataInterface $addressMetadataService,
+        LoggerInterface $logger
+    ) {
+        $this->fileUploaderFactory = $fileUploaderFactory;
+        $this->addressMetadataService = $addressMetadataService;
+        $this->logger = $logger;
+        parent::__construct($context);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function execute()
+    {
+        try {
+            if (empty($_FILES)) {
+                throw new \Exception('$_FILES array is empty.');
+            }
+
+            // Must be executed before any operations with $_FILES!
+            $this->convertFilesArray();
+
+            $attributeCode = key($_FILES['address']['name']);
+            $attributeMetadata = $this->addressMetadataService->getAttributeMetadata($attributeCode);
+
+            /** @var FileUploader $fileUploader */
+            $fileUploader = $this->fileUploaderFactory->create([
+                'attributeMetadata' => $attributeMetadata,
+                'entityTypeCode' => AddressMetadataInterface::ENTITY_TYPE_ADDRESS,
+                'scope' => 'address',
+            ]);
+
+            $errors = $fileUploader->validate();
+            if (true !== $errors) {
+                $errorMessage = implode('</br>', $errors);
+                throw new LocalizedException(__($errorMessage));
+            }
+
+            $result = $fileUploader->upload();
+        } catch (LocalizedException $e) {
+            $result = [
+                'error' => $e->getMessage(),
+                'errorcode' => $e->getCode(),
+            ];
+        } catch (\Exception $e) {
+            $this->logger->critical($e);
+            $result = [
+                'error' => __('Something went wrong while saving file.'),
+                'errorcode' => $e->getCode(),
+            ];
+        }
+
+        /** @var \Magento\Framework\Controller\Result\Json $resultJson */
+        $resultJson = $this->resultFactory->create(ResultFactory::TYPE_JSON);
+        $resultJson->setData($result);
+        return $resultJson;
+    }
+
+    /**
+     * Update global $_FILES array. Convert data to standard form
+     *
+     * NOTE: This conversion is required to use \Magento\Framework\File\Uploader::_setUploadFileId($fileId) method.
+     *
+     * @return void
+     */
+    private function convertFilesArray()
+    {
+        foreach($_FILES['address'] as $itemKey => $item) {
+            foreach ($item as $value) {
+                if (is_array($value)) {
+                    $_FILES['address'][$itemKey] = [
+                        key($value) => current($value),
+                    ];
+                }
+            }
+        }
+    }
+}
diff --git a/app/code/Magento/Customer/Controller/Adminhtml/File/Customer/Upload.php b/app/code/Magento/Customer/Controller/Adminhtml/File/Customer/Upload.php
new file mode 100644
index 0000000000000000000000000000000000000000..47bda9f30059c7713b5cd5ee8ccd0d1cfa50b375
--- /dev/null
+++ b/app/code/Magento/Customer/Controller/Adminhtml/File/Customer/Upload.php
@@ -0,0 +1,104 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Customer\Controller\Adminhtml\File\Customer;
+
+use Magento\Backend\App\Action;
+use Magento\Backend\App\Action\Context;
+use Magento\Customer\Api\CustomerMetadataInterface;
+use Magento\Customer\Model\FileUploader;
+use Magento\Customer\Model\FileUploaderFactory;
+use Magento\Framework\Controller\ResultFactory;
+use Magento\Framework\Exception\LocalizedException;
+use Psr\Log\LoggerInterface;
+
+class Upload extends Action
+{
+    /**
+     * Authorization level of a basic admin session
+     *
+     * @see _isAllowed()
+     */
+    const ADMIN_RESOURCE = 'Magento_Customer::manage';
+
+    /**
+     * @var FileUploaderFactory
+     */
+    private $fileUploaderFactory;
+
+    /**
+     * @var CustomerMetadataInterface
+     */
+    private $customerMetadataService;
+
+    /**
+     * @var LoggerInterface
+     */
+    private $logger;
+
+    /**
+     * @param Context $context
+     * @param FileUploaderFactory $fileUploaderFactory
+     * @param CustomerMetadataInterface $customerMetadataService
+     * @param LoggerInterface $logger
+     */
+    public function __construct(
+        Context $context,
+        FileUploaderFactory $fileUploaderFactory,
+        CustomerMetadataInterface $customerMetadataService,
+        LoggerInterface $logger
+    ) {
+        $this->fileUploaderFactory = $fileUploaderFactory;
+        $this->customerMetadataService = $customerMetadataService;
+        $this->logger = $logger;
+        parent::__construct($context);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function execute()
+    {
+        try {
+            if (empty($_FILES)) {
+                throw new \Exception('$_FILES array is empty.');
+            }
+
+            $attributeCode = key($_FILES['customer']['name']);
+            $attributeMetadata = $this->customerMetadataService->getAttributeMetadata($attributeCode);
+
+            /** @var FileUploader $fileUploader */
+            $fileUploader = $this->fileUploaderFactory->create([
+                'attributeMetadata' => $attributeMetadata,
+                'entityTypeCode' => CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER,
+                'scope' => 'customer',
+            ]);
+
+            $errors = $fileUploader->validate();
+            if (true !== $errors) {
+                $errorMessage = implode('</br>', $errors);
+                throw new LocalizedException(__($errorMessage));
+            }
+
+            $result = $fileUploader->upload();
+        } catch (LocalizedException $e) {
+            $result = [
+                'error' => $e->getMessage(),
+                'errorcode' => $e->getCode(),
+            ];
+        } catch (\Exception $e) {
+            $this->logger->critical($e);
+            $result = [
+                'error' => __('Something went wrong while saving file.'),
+                'errorcode' => $e->getCode(),
+            ];
+        }
+
+        /** @var \Magento\Framework\Controller\Result\Json $resultJson */
+        $resultJson = $this->resultFactory->create(ResultFactory::TYPE_JSON);
+        $resultJson->setData($result);
+        return $resultJson;
+    }
+}
diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Index/Save.php b/app/code/Magento/Customer/Controller/Adminhtml/Index/Save.php
index 601c4bad9c74c240b02cde04ccedc071b7b1dfe2..d1c41545955dbab54d8e6f4af578be1c7ac0a204 100644
--- a/app/code/Magento/Customer/Controller/Adminhtml/Index/Save.php
+++ b/app/code/Magento/Customer/Controller/Adminhtml/Index/Save.php
@@ -5,21 +5,14 @@
  */
 namespace Magento\Customer\Controller\Adminhtml\Index;
 
+use Magento\Customer\Api\AddressMetadataInterface;
+use Magento\Customer\Api\CustomerMetadataInterface;
 use Magento\Customer\Api\Data\CustomerInterface;
 use Magento\Customer\Controller\RegistryConstants;
 use Magento\Customer\Model\EmailNotificationInterface;
+use Magento\Customer\Model\Metadata\Form;
 use Magento\Framework\Exception\LocalizedException;
-use Magento\Customer\Api\CustomerRepositoryInterface;
-use Magento\Customer\Api\AccountManagementInterface;
-use Magento\Customer\Api\Data\CustomerInterfaceFactory;
-use Magento\Customer\Api\Data\AddressInterfaceFactory;
-use Magento\Framework\DataObjectFactory;
-use Magento\Customer\Model\Address\Mapper;
-use Magento\Customer\Api\AddressRepositoryInterface;
 
-/**
- * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
- */
 class Save extends \Magento\Customer\Controller\Adminhtml\Index
 {
     /**
@@ -36,7 +29,7 @@ class Save extends \Magento\Customer\Controller\Adminhtml\Index
     {
         $customerData = [];
         if ($this->getRequest()->getPost('customer')) {
-            $serviceAttributes = [
+            $additionalAttributes = [
                 CustomerInterface::DEFAULT_BILLING,
                 CustomerInterface::DEFAULT_SHIPPING,
                 'confirmation',
@@ -45,10 +38,9 @@ class Save extends \Magento\Customer\Controller\Adminhtml\Index
             ];
 
             $customerData = $this->_extractData(
-                $this->getRequest(),
                 'adminhtml_customer',
-                \Magento\Customer\Api\CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER,
-                $serviceAttributes,
+                CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER,
+                $additionalAttributes,
                 'customer'
             );
         }
@@ -66,54 +58,51 @@ class Save extends \Magento\Customer\Controller\Adminhtml\Index
     /**
      * Perform customer data filtration based on form code and form object
      *
-     * @param \Magento\Framework\App\RequestInterface $request
      * @param string $formCode The code of EAV form to take the list of attributes from
      * @param string $entityType entity type for the form
      * @param string[] $additionalAttributes The list of attribute codes to skip filtration for
      * @param string $scope scope of the request
-     * @param \Magento\Customer\Model\Metadata\Form $metadataForm to use for extraction
-     * @return array Filtered customer data
+     * @return array
      */
     protected function _extractData(
-        \Magento\Framework\App\RequestInterface $request,
         $formCode,
         $entityType,
         $additionalAttributes = [],
-        $scope = null,
-        \Magento\Customer\Model\Metadata\Form $metadataForm = null
+        $scope = null
     ) {
-        if ($metadataForm === null) {
-            $metadataForm = $this->_formFactory->create(
-                $entityType,
-                $formCode,
-                [],
-                false,
-                \Magento\Customer\Model\Metadata\Form::DONT_IGNORE_INVISIBLE
-            );
-        }
-        $filteredData = $metadataForm->extractData($request, $scope);
+        $metadataForm = $this->getMetadataForm($entityType, $formCode, $scope);
+        $formData = $metadataForm->extractData($this->getRequest(), $scope);
 
-        $object = $this->_objectFactory->create(['data' => $request->getPostValue()]);
+        // Initialize additional attributes
+        /** @var \Magento\Framework\DataObject $object */
+        $object = $this->_objectFactory->create(['data' => $this->getRequest()->getPostValue()]);
         $requestData = $object->getData($scope);
         foreach ($additionalAttributes as $attributeCode) {
-            $filteredData[$attributeCode] = isset($requestData[$attributeCode]) ? $requestData[$attributeCode] : false;
+            $formData[$attributeCode] = isset($requestData[$attributeCode]) ? $requestData[$attributeCode] : false;
         }
 
+        $result = $metadataForm->compactData($formData);
+
+        // Re-initialize additional attributes
+        $formData = array_replace($formData, $result);
+
+        // Unset unused attributes
         $formAttributes = $metadataForm->getAttributes();
-        /** @var \Magento\Customer\Api\Data\AttributeMetadataInterface $attribute */
         foreach ($formAttributes as $attribute) {
+            /** @var \Magento\Customer\Api\Data\AttributeMetadataInterface $attribute */
             $attributeCode = $attribute->getAttributeCode();
-            $frontendInput = $attribute->getFrontendInput();
-            if ($frontendInput != 'boolean' && $filteredData[$attributeCode] === false) {
-                unset($filteredData[$attributeCode]);
+            if ($attribute->getFrontendInput() != 'boolean'
+                && $formData[$attributeCode] === false
+            ) {
+                unset($formData[$attributeCode]);
             }
         }
 
-        if (empty($filteredData['extension_attributes'])) {
-            unset($filteredData['extension_attributes']);
+        if (empty($formData['extension_attributes'])) {
+            unset($formData['extension_attributes']);
         }
 
-        return $filteredData;
+        return $formData;
     }
 
     /**
@@ -131,9 +120,8 @@ class Save extends \Magento\Customer\Controller\Adminhtml\Index
         foreach ($addressIdList as $addressId) {
             $scope = sprintf('address/%s', $addressId);
             $addressData = $this->_extractData(
-                $this->getRequest(),
                 'adminhtml_customer_address',
-                \Magento\Customer\Api\AddressMetadataInterface::ENTITY_TYPE_ADDRESS,
+                AddressMetadataInterface::ENTITY_TYPE_ADDRESS,
                 ['default_billing', 'default_shipping'],
                 $scope
             );
@@ -193,18 +181,16 @@ class Save extends \Magento\Customer\Controller\Adminhtml\Index
     {
         $returnToEdit = false;
         $originalRequestData = $this->getRequest()->getPostValue();
-        $customerId = isset($originalRequestData['customer']['entity_id'])
-            ? $originalRequestData['customer']['entity_id']
-            : null;
+
+        $customerId = $this->getCurrentCustomerId();
+
         if ($originalRequestData) {
             try {
                 // optional fields might be set in request for future processing by observers in other modules
                 $customerData = $this->_extractCustomerData();
                 $addressesData = $this->_extractCustomerAddressData($customerData);
-                $request = $this->getRequest();
-                $isExistingCustomer = (bool)$customerId;
-                $customer = $this->customerDataFactory->create();
-                if ($isExistingCustomer) {
+
+                if ($customerId) {
                     $currentCustomer = $this->_customerRepository->getById($customerId);
                     $customerData = array_merge(
                         $this->customerMapper->toFlatArray($currentCustomer),
@@ -213,6 +199,8 @@ class Save extends \Magento\Customer\Controller\Adminhtml\Index
                     $customerData['id'] = $customerId;
                 }
 
+                /** @var CustomerInterface $customer */
+                $customer = $this->customerDataFactory->create();
                 $this->dataObjectHelper->populateWithArray(
                     $customer,
                     $customerData,
@@ -237,17 +225,18 @@ class Save extends \Magento\Customer\Controller\Adminhtml\Index
 
                 $this->_eventManager->dispatch(
                     'adminhtml_customer_prepare_save',
-                    ['customer' => $customer, 'request' => $request]
+                    ['customer' => $customer, 'request' => $this->getRequest()]
                 );
                 $customer->setAddresses($addresses);
-                $customer->setStoreId($customerData['sendemail_store_id']);
+                if (isset($customerData['sendemail_store_id'])) {
+                    $customer->setStoreId($customerData['sendemail_store_id']);
+                }
 
                 // Save customer
-                if ($isExistingCustomer) {
+                if ($customerId) {
                     $this->_customerRepository->save($customer);
 
                     $this->getEmailNotification()->credentialsChanged($customer, $currentCustomer->getEmail());
-
                 } else {
                     $customer = $this->customerAccountManagement->createAccount($customer);
                     $customerId = $customer->getId();
@@ -268,7 +257,7 @@ class Save extends \Magento\Customer\Controller\Adminhtml\Index
                 // After save
                 $this->_eventManager->dispatch(
                     'adminhtml_customer_save_after',
-                    ['customer' => $customer, 'request' => $request]
+                    ['customer' => $customer, 'request' => $this->getRequest()]
                 );
                 $this->_getSession()->unsCustomerFormData();
                 // Done Saving customer, finish save action
@@ -328,4 +317,59 @@ class Save extends \Magento\Customer\Controller\Adminhtml\Index
             return $this->emailNotification;
         }
     }
+
+    /**
+     * Get metadata form
+     *
+     * @param string $entityType
+     * @param string $formCode
+     * @param string $scope
+     * @return Form
+     */
+    private function getMetadataForm($entityType, $formCode, $scope)
+    {
+        $attributeValues = [];
+
+        if ($entityType == CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER) {
+            $customerId = $this->getCurrentCustomerId();
+            if ($customerId) {
+                $customer = $this->_customerRepository->getById($customerId);
+                $attributeValues = $this->customerMapper->toFlatArray($customer);
+            }
+        }
+
+        if ($entityType == AddressMetadataInterface::ENTITY_TYPE_ADDRESS) {
+            $scopeData = explode('/', $scope);
+            if (isset($scopeData[1]) && is_numeric($scopeData[1])) {
+                $customerAddress = $this->addressRepository->getById($scopeData[1]);
+                $attributeValues = $this->addressMapper->toFlatArray($customerAddress);
+            }
+        }
+
+        $metadataForm = $this->_formFactory->create(
+            $entityType,
+            $formCode,
+            $attributeValues,
+            false,
+            Form::DONT_IGNORE_INVISIBLE
+        );
+
+        return $metadataForm;
+    }
+
+    /**
+     * Retrieve current customer ID
+     *
+     * @return int
+     */
+    private function getCurrentCustomerId()
+    {
+        $originalRequestData = $this->getRequest()->getPostValue(CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER);
+
+        $customerId = isset($originalRequestData['entity_id'])
+            ? $originalRequestData['entity_id']
+            : null;
+
+        return $customerId;
+    }
 }
diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Index/Validate.php b/app/code/Magento/Customer/Controller/Adminhtml/Index/Validate.php
index 7c1f23881ec3d91d4dffddf111e824c4176dfc3a..2b3cbc2d2b6a0329b8aa66a0a6e6ab0ad6503f80 100644
--- a/app/code/Magento/Customer/Controller/Adminhtml/Index/Validate.php
+++ b/app/code/Magento/Customer/Controller/Adminhtml/Index/Validate.php
@@ -28,11 +28,7 @@ class Validate extends \Magento\Customer\Controller\Adminhtml\Index
             $customerForm = $this->_formFactory->create(
                 'customer',
                 'adminhtml_customer',
-                $this->_extensibleDataObjectConverter->toFlatArray(
-                    $customer,
-                    [],
-                    '\Magento\Customer\Api\Data\CustomerInterface'
-                ),
+                [],
                 true
             );
             $customerForm->setInvisibleIgnored(true);
diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Index/Viewfile.php b/app/code/Magento/Customer/Controller/Adminhtml/Index/Viewfile.php
index af512f7fa9f91830d99605aca65a8686eb84910b..57c008445daf4d1d59101da21d2e0390714158e6 100644
--- a/app/code/Magento/Customer/Controller/Adminhtml/Index/Viewfile.php
+++ b/app/code/Magento/Customer/Controller/Adminhtml/Index/Viewfile.php
@@ -7,6 +7,7 @@ namespace Magento\Customer\Controller\Adminhtml\Index;
 
 use Magento\Customer\Api\AccountManagementInterface;
 use Magento\Customer\Api\AddressRepositoryInterface;
+use Magento\Customer\Api\CustomerMetadataInterface;
 use Magento\Customer\Api\CustomerRepositoryInterface;
 use Magento\Customer\Api\Data\AddressInterfaceFactory;
 use Magento\Customer\Api\Data\CustomerInterfaceFactory;
@@ -124,7 +125,7 @@ class Viewfile extends \Magento\Customer\Controller\Adminhtml\Index
     /**
      * Customer view file action
      *
-     * @return void
+     * @return \Magento\Framework\Controller\ResultInterface|void
      * @throws NotFoundException
      *
      * @SuppressWarnings(PHPMD.ExitExpression)
@@ -151,7 +152,7 @@ class Viewfile extends \Magento\Customer\Controller\Adminhtml\Index
         /** @var \Magento\Framework\Filesystem $filesystem */
         $filesystem = $this->_objectManager->get('Magento\Framework\Filesystem');
         $directory = $filesystem->getDirectoryRead(DirectoryList::MEDIA);
-        $fileName = 'customer' . '/' . ltrim($file, '/');
+        $fileName = CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER . '/' . ltrim($file, '/');
         $path = $directory->getAbsolutePath($fileName);
         if (!$directory->isFile($fileName)
             && !$this->_objectManager->get('Magento\MediaStorage\Helper\File\Storage')->processStorageFile($path)
@@ -175,7 +176,7 @@ class Viewfile extends \Magento\Customer\Controller\Adminhtml\Index
                     $contentType = 'application/octet-stream';
                     break;
             }
-            $stat = $directory->stat($path);
+            $stat = $directory->stat($fileName);
             $contentLength = $stat['size'];
             $contentModify = $stat['mtime'];
 
diff --git a/app/code/Magento/Customer/Model/Customer/DataProvider.php b/app/code/Magento/Customer/Model/Customer/DataProvider.php
index 8c9811dfd0fedaa1cac07fb984dda328fdaf431a..8218d3be472a32ac6360766358c91890bfcea5e1 100644
--- a/app/code/Magento/Customer/Model/Customer/DataProvider.php
+++ b/app/code/Magento/Customer/Model/Customer/DataProvider.php
@@ -5,8 +5,14 @@
  */
 namespace Magento\Customer\Model\Customer;
 
+use Magento\Customer\Api\AddressMetadataInterface;
+use Magento\Customer\Api\CustomerMetadataInterface;
+use Magento\Customer\Model\Attribute;
+use Magento\Customer\Model\FileProcessor;
+use Magento\Customer\Model\FileProcessorFactory;
 use Magento\Eav\Api\Data\AttributeInterface;
 use Magento\Eav\Model\Config;
+use Magento\Eav\Model\Entity\Attribute\AbstractAttribute;
 use Magento\Eav\Model\Entity\Type;
 use Magento\Customer\Model\Address;
 use Magento\Customer\Model\Customer;
@@ -24,6 +30,11 @@ use Magento\Framework\View\Element\UiComponent\DataProvider\FilterPool;
  */
 class DataProvider extends \Magento\Ui\DataProvider\AbstractDataProvider
 {
+    /**
+     * Maximum file size allowed for file_uploader UI component
+     */
+    const MAX_FILE_SIZE = 2097152;
+
     /**
      * @var Collection
      */
@@ -81,8 +92,21 @@ class DataProvider extends \Magento\Ui\DataProvider\AbstractDataProvider
     protected $session;
 
     /**
-     * Constructor
+     * @var FileProcessorFactory
+     */
+    private $fileProcessorFactory;
+
+    /**
+     * File types allowed for file_uploader UI component
      *
+     * @var array
+     */
+    private $fileUploaderTypes = [
+        'image',
+        'file',
+    ];
+
+    /**
      * @param string $name
      * @param string $primaryFieldName
      * @param string $requestFieldName
@@ -90,6 +114,7 @@ class DataProvider extends \Magento\Ui\DataProvider\AbstractDataProvider
      * @param CustomerCollectionFactory $customerCollectionFactory
      * @param Config $eavConfig
      * @param FilterPool $filterPool
+     * @param FileProcessorFactory $fileProcessorFactory
      * @param array $meta
      * @param array $data
      */
@@ -101,6 +126,7 @@ class DataProvider extends \Magento\Ui\DataProvider\AbstractDataProvider
         CustomerCollectionFactory $customerCollectionFactory,
         Config $eavConfig,
         FilterPool $filterPool,
+        FileProcessorFactory $fileProcessorFactory = null,
         array $meta = [],
         array $data = []
     ) {
@@ -110,6 +136,7 @@ class DataProvider extends \Magento\Ui\DataProvider\AbstractDataProvider
         $this->collection->addAttributeToSelect('*');
         $this->eavConfig = $eavConfig;
         $this->filterPool = $filterPool;
+        $this->fileProcessorFactory = $fileProcessorFactory ?: $this->getFileProcessorFactory();
         $this->meta['customer']['children'] = $this->getAttributesMeta(
             $this->eavConfig->getEntityType('customer')
         );
@@ -122,6 +149,8 @@ class DataProvider extends \Magento\Ui\DataProvider\AbstractDataProvider
      * Get session object
      *
      * @return SessionManagerInterface
+     *
+     * @deprecated
      */
     protected function getSession()
     {
@@ -145,6 +174,9 @@ class DataProvider extends \Magento\Ui\DataProvider\AbstractDataProvider
         /** @var Customer $customer */
         foreach ($items as $customer) {
             $result['customer'] = $customer->getData();
+
+            $this->overrideFileUploaderData($customer, $result['customer']);
+
             unset($result['address']);
 
             /** @var Address $address */
@@ -153,6 +185,8 @@ class DataProvider extends \Magento\Ui\DataProvider\AbstractDataProvider
                 $address->load($addressId);
                 $result['address'][$addressId] = $address->getData();
                 $this->prepareAddressData($addressId, $result['address'], $result['customer']);
+
+                $this->overrideFileUploaderData($address, $result['address'][$addressId]);
             }
             $this->loadedData[$customer->getId()] = $result;
         }
@@ -167,6 +201,78 @@ class DataProvider extends \Magento\Ui\DataProvider\AbstractDataProvider
         return $this->loadedData;
     }
 
+    /**
+     * Override file uploader UI component data
+     *
+     * Overrides data for attributes with frontend_input equal to 'image' or 'file'.
+     *
+     * @param Customer|Address $entity
+     * @param array $entityData
+     */
+    private function overrideFileUploaderData($entity, array &$entityData)
+    {
+        $attributes = $entity->getAttributes();
+        foreach ($attributes as $attribute) {
+            /** @var Attribute $attribute */
+            if (in_array($attribute->getFrontendInput(), $this->fileUploaderTypes)) {
+                $entityData[$attribute->getAttributeCode()] = $this->getFileUploaderData(
+                    $entity->getEntityType(),
+                    $attribute,
+                    $entityData
+                );
+            }
+        }
+    }
+
+    /**
+     * Retrieve array of values required by file uploader UI component
+     *
+     * @param Type $entityType
+     * @param Attribute $attribute
+     * @param array $customerData
+     * @return array
+     */
+    private function getFileUploaderData(
+        Type $entityType,
+        Attribute $attribute,
+        array $customerData
+    ) {
+        $attributeCode = $attribute->getAttributeCode();
+
+        $file = isset($customerData[$attributeCode])
+            ? $customerData[$attributeCode]
+            : '';
+
+        /** @var FileProcessor $fileProcessor */
+        $fileProcessor = $this->getFileProcessorFactory()->create([
+            'entityTypeCode' => $entityType->getEntityTypeCode(),
+        ]);
+
+        if (!empty($file)
+            && $fileProcessor->isExist($file)
+        ) {
+            $stat = $fileProcessor->getStat($file);
+            $viewUrl = $fileProcessor->getViewUrl($file, $attribute->getFrontendInput());
+        }
+
+        $fileName = $file;
+        if (strrpos($fileName, '/') !== false) {
+            $fileName = substr($fileName, strrpos($fileName, '/') + 1);
+        }
+
+        if (!empty($file)) {
+            return [
+                [
+                    'file' => $file,
+                    'size' => isset($stat) ? $stat['size'] : 0,
+                    'url' => isset($viewUrl) ? $viewUrl : '',
+                    'name' => $fileName,
+                ],
+            ];
+        }
+        return [];
+    }
+
     /**
      * Get attributes meta
      *
@@ -178,7 +284,7 @@ class DataProvider extends \Magento\Ui\DataProvider\AbstractDataProvider
     {
         $meta = [];
         $attributes = $entityType->getAttributeCollection();
-        /* @var \Magento\Eav\Model\Entity\Attribute\AbstractAttribute $attribute */
+        /* @var AbstractAttribute $attribute */
         foreach ($attributes as $attribute) {
             $this->processFrontendInput($attribute, $meta);
 
@@ -203,10 +309,100 @@ class DataProvider extends \Magento\Ui\DataProvider\AbstractDataProvider
                 $meta[$code]['arguments']['data']['config']['validation'] = $rules;
             }
             $meta[$code]['arguments']['data']['config']['componentType'] = Field::NAME;
+
+            $this->overrideFileUploaderMetadata($entityType, $attribute, $meta[$code]['arguments']['data']['config']);
         }
         return $meta;
     }
 
+    /**
+     * Override file uploader UI component metadata
+     *
+     * Overrides metadata for attributes with frontend_input equal to 'image' or 'file'.
+     *
+     * @param Type $entityType
+     * @param AbstractAttribute $attribute
+     * @param array $config
+     */
+    private function overrideFileUploaderMetadata(
+        Type $entityType,
+        AbstractAttribute $attribute,
+        array &$config
+    ) {
+        if (in_array($attribute->getFrontendInput(), $this->fileUploaderTypes)) {
+            $maxFileSize = self::MAX_FILE_SIZE;
+
+            if (isset($config['validation']['max_file_size'])) {
+                $maxFileSize = (int)$config['validation']['max_file_size'];
+            }
+
+            $allowedExtensions = [];
+
+            if (isset($config['validation']['file_extensions'])) {
+                $allowedExtensions = explode(',', $config['validation']['file_extensions']);
+                array_walk($allowedExtensions, function(&$value) { $value = strtolower(trim($value)); });
+            }
+
+            $allowedExtensions = implode(' ', $allowedExtensions);
+
+            $entityTypeCode = $entityType->getEntityTypeCode();
+            $url = $this->getFileUploadUrl($entityTypeCode);
+
+            $config = [
+                'formElement' => 'fileUploader',
+                'componentType' => 'fileUploader',
+                'maxFileSize' => $maxFileSize,
+                'allowedExtensions' => $allowedExtensions,
+                'uploaderConfig' => [
+                    'url' => $url,
+                ],
+                'label' => $this->getMetadataValue($config, 'label'),
+                'sortOrder' => $this->getMetadataValue($config, 'sortOrder'),
+                'required' => $this->getMetadataValue($config, 'required'),
+                'visible' => $this->getMetadataValue($config, 'visible'),
+                'validation' => $this->getMetadataValue($config, 'validation'),
+            ];
+        }
+    }
+
+    /**
+     * Retrieve metadata value
+     *
+     * @param array $config
+     * @param string $name
+     * @param mixed $default
+     * @return mixed
+     */
+    private function getMetadataValue($config, $name, $default = null)
+    {
+        $value = isset($config[$name]) ? $config[$name] : $default;
+        return $value;
+    }
+
+    /**
+     * Retrieve URL to file upload
+     *
+     * @param string $entityTypeCode
+     * @return string
+     */
+    private function getFileUploadUrl($entityTypeCode)
+    {
+        switch ($entityTypeCode) {
+            case CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER:
+                $url = 'customer/file/customer_upload';
+                break;
+
+            case AddressMetadataInterface::ENTITY_TYPE_ADDRESS:
+                $url = 'customer/file/address_upload';
+                break;
+
+            default:
+                $url = '';
+                break;
+        }
+        return $url;
+    }
+
     /**
      * Process attributes by frontend input type
      *
@@ -250,4 +446,20 @@ class DataProvider extends \Magento\Ui\DataProvider\AbstractDataProvider
             $addresses[$addressId]['street'] = explode("\n", $addresses[$addressId]['street']);
         }
     }
+
+    /**
+     * Get FileProcessorFactory instance
+     *
+     * @return FileProcessorFactory
+     *
+     * @deprecated
+     */
+    private function getFileProcessorFactory()
+    {
+        if ($this->fileProcessorFactory === null) {
+            $this->fileProcessorFactory = ObjectManager::getInstance()
+                ->get('Magento\Customer\Model\FileProcessorFactory');
+        }
+        return $this->fileProcessorFactory;
+    }
 }
diff --git a/app/code/Magento/Customer/Model/CustomerExtractor.php b/app/code/Magento/Customer/Model/CustomerExtractor.php
index 56e127def199e470a5f939e59f6b8e6e442e544c..197d75943c8dd989e98336e021fc30b7e38b44f8 100644
--- a/app/code/Magento/Customer/Model/CustomerExtractor.php
+++ b/app/code/Magento/Customer/Model/CustomerExtractor.php
@@ -6,6 +6,8 @@
  */
 namespace Magento\Customer\Model;
 
+use Magento\Customer\Api\CustomerMetadataInterface;
+use Magento\Customer\Api\Data\CustomerInterface;
 use Magento\Customer\Api\GroupManagementInterface;
 use Magento\Framework\App\RequestInterface;
 
@@ -60,12 +62,23 @@ class CustomerExtractor
     /**
      * @param string $formCode
      * @param RequestInterface $request
-     * @return \Magento\Customer\Api\Data\CustomerInterface
+     * @param array $attributeValues
+     * @return CustomerInterface
      */
-    public function extract($formCode, RequestInterface $request)
-    {
-        $customerForm = $this->formFactory->create('customer', $formCode);
+    public function extract(
+        $formCode,
+        RequestInterface $request,
+        array $attributeValues = []
+    ) {
+        $customerForm = $this->formFactory->create(
+            CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER,
+            $formCode,
+            $attributeValues
+        );
+
         $customerData = $customerForm->extractData($request);
+        $customerData = $customerForm->compactData($customerData);
+
         $allowedAttributes = $customerForm->getAllowedAttributes();
         $isGroupIdEmpty = isset($allowedAttributes['group_id']);
 
diff --git a/app/code/Magento/Customer/Model/FileProcessor.php b/app/code/Magento/Customer/Model/FileProcessor.php
new file mode 100644
index 0000000000000000000000000000000000000000..c98a85cc18463306b3360982b336a945ed63de3c
--- /dev/null
+++ b/app/code/Magento/Customer/Model/FileProcessor.php
@@ -0,0 +1,237 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Customer\Model;
+
+use Magento\Customer\Api\AddressMetadataInterface;
+use Magento\Customer\Api\CustomerMetadataInterface;
+use Magento\Framework\App\Filesystem\DirectoryList;
+use Magento\Framework\Exception\LocalizedException;
+use Magento\Framework\Filesystem;
+use Magento\Framework\Filesystem\Directory\WriteInterface;
+use Magento\Framework\Url\EncoderInterface;
+use Magento\Framework\UrlInterface;
+use Magento\MediaStorage\Model\File\Uploader;
+use Magento\MediaStorage\Model\File\UploaderFactory;
+
+class FileProcessor
+{
+    /**
+     * Temporary directory name
+     */
+    const TMP_DIR = 'tmp';
+
+    /**
+     * @var WriteInterface
+     */
+    private $mediaDirectory;
+
+    /**
+     * @var UploaderFactory
+     */
+    private $uploaderFactory;
+
+    /**
+     * @var UrlInterface
+     */
+    private $urlBuilder;
+
+    /**
+     * @var EncoderInterface
+     */
+    private $urlEncoder;
+
+    /**
+     * @var string
+     */
+    private $entityTypeCode;
+
+    /**
+     * @var array
+     */
+    private $allowedExtensions = [];
+
+    /**
+     * @param Filesystem $filesystem
+     * @param UploaderFactory $uploaderFactory
+     * @param UrlInterface $urlBuilder
+     * @param EncoderInterface $urlEncoder
+     * @param string $entityTypeCode
+     * @param array $allowedExtensions
+     */
+    public function __construct(
+        Filesystem $filesystem,
+        UploaderFactory $uploaderFactory,
+        UrlInterface $urlBuilder,
+        EncoderInterface $urlEncoder,
+        $entityTypeCode,
+        array $allowedExtensions = []
+    ) {
+        $this->mediaDirectory = $filesystem->getDirectoryWrite(DirectoryList::MEDIA);
+        $this->uploaderFactory = $uploaderFactory;
+        $this->urlBuilder = $urlBuilder;
+        $this->urlEncoder = $urlEncoder;
+        $this->entityTypeCode = $entityTypeCode;
+        $this->allowedExtensions = $allowedExtensions;
+    }
+
+    /**
+     * Retrieve base64 encoded file content
+     *
+     * @param string $fileName
+     * @return string
+     */
+    public function getBase64EncodedData($fileName)
+    {
+        $filePath = $this->entityTypeCode . '/' . ltrim($fileName, '/');
+
+        $fileContent = $this->mediaDirectory->readFile($filePath);
+
+        $encodedContent = base64_encode($fileContent);
+        return $encodedContent;
+    }
+
+    /**
+     * Get file statistics data
+     *
+     * @param string $fileName
+     * @return array
+     */
+    public function getStat($fileName)
+    {
+        $filePath = $this->entityTypeCode . '/' . ltrim($fileName, '/');
+
+        $result = $this->mediaDirectory->stat($filePath);
+        return $result;
+    }
+
+    /**
+     * Check if the file exists
+     *
+     * @param string $fileName
+     * @return bool
+     */
+    public function isExist($fileName)
+    {
+        $filePath = $this->entityTypeCode . '/' . ltrim($fileName, '/');
+
+        $result = $this->mediaDirectory->isExist($filePath);
+        return $result;
+    }
+
+    /**
+     * Retrieve customer/index/viewfile action URL
+     *
+     * @param string $filePath
+     * @param string $type
+     * @return string
+     */
+    public function getViewUrl($filePath, $type)
+    {
+        $viewUrl = '';
+
+        if ($this->entityTypeCode == AddressMetadataInterface::ENTITY_TYPE_ADDRESS) {
+            $filePath = $this->entityTypeCode . '/' . ltrim($filePath, '/');
+            $viewUrl = $this->urlBuilder->getBaseUrl(['_type' => UrlInterface::URL_TYPE_MEDIA])
+                . $this->mediaDirectory->getRelativePath($filePath);
+        }
+
+        if ($this->entityTypeCode == CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER) {
+            $viewUrl = $this->urlBuilder->getUrl(
+                'customer/index/viewfile',
+                [$type => $this->urlEncoder->encode(ltrim($filePath, '/'))]
+            );
+        }
+
+        return $viewUrl;
+    }
+
+    /**
+     * Save uploaded file to temporary directory
+     *
+     * @param string $fileId
+     * @return \string[]
+     * @throws LocalizedException
+     */
+    public function saveTemporaryFile($fileId)
+    {
+        /** @var Uploader $uploader */
+        $uploader = $this->uploaderFactory->create(['fileId' => $fileId]);
+        $uploader->setFilesDispersion(false);
+        $uploader->setFilenamesCaseSensitivity(false);
+        $uploader->setAllowRenameFiles(true);
+        $uploader->setAllowedExtensions($this->allowedExtensions);
+
+        $path = $this->mediaDirectory->getAbsolutePath(
+            $this->entityTypeCode . '/' . self::TMP_DIR
+        );
+
+        $result = $uploader->save($path);
+        if (!$result) {
+            throw new LocalizedException(__('File can not be saved to the destination folder.'));
+        }
+
+        return $result;
+    }
+
+    /**
+     * Move file from temporary directory into base directory
+     *
+     * @param string $fileName
+     * @return string
+     * @throws LocalizedException
+     */
+    public function moveTemporaryFile($fileName)
+    {
+        $fileName = ltrim($fileName, '/');
+
+        $dispersionPath = Uploader::getDispretionPath($fileName);
+        $destinationPath = $this->entityTypeCode . $dispersionPath;
+
+        if (!$this->mediaDirectory->create($destinationPath)) {
+            throw new LocalizedException(
+                __('Unable to create directory %1.', $destinationPath)
+            );
+        }
+
+        if (!$this->mediaDirectory->isWritable($destinationPath)) {
+            throw new LocalizedException(
+                __('Destination folder is not writable or does not exists.')
+            );
+        }
+
+        $destinationFileName = Uploader::getNewFileName(
+            $this->mediaDirectory->getAbsolutePath($destinationPath) . '/' . $fileName
+        );
+
+        try {
+            $this->mediaDirectory->renameFile(
+                $this->entityTypeCode . '/' . self::TMP_DIR . '/' . $fileName,
+                $destinationPath . '/' . $destinationFileName
+            );
+        } catch (\Exception $e) {
+            throw new LocalizedException(
+                __('Something went wrong while saving the file.')
+            );
+        }
+
+        $fileName = $dispersionPath . '/' . $fileName;
+        return $fileName;
+    }
+
+    /**
+     * Remove uploaded file
+     *
+     * @param string $fileName
+     * @return bool
+     */
+    public function removeUploadedFile($fileName)
+    {
+        $filePath = $this->entityTypeCode . '/' . ltrim($fileName, '/');
+
+        $result = $this->mediaDirectory->delete($filePath);
+        return $result;
+    }
+}
diff --git a/app/code/Magento/Customer/Model/FileUploader.php b/app/code/Magento/Customer/Model/FileUploader.php
new file mode 100644
index 0000000000000000000000000000000000000000..97dfdafdf75754f47f52ee318e7bac64429193dd
--- /dev/null
+++ b/app/code/Magento/Customer/Model/FileUploader.php
@@ -0,0 +1,172 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Customer\Model;
+
+use Magento\Customer\Api\AddressMetadataInterface;
+use Magento\Customer\Api\CustomerMetadataInterface;
+use Magento\Customer\Api\Data\AttributeMetadataInterface;
+use Magento\Customer\Model\FileProcessorFactory;
+use Magento\Customer\Model\Metadata\ElementFactory;
+use Magento\Framework\Exception\LocalizedException;
+
+class FileUploader
+{
+    /**
+     * @var CustomerMetadataInterface
+     */
+    private $customerMetadataService;
+
+    /**
+     * @var AddressMetadataInterface
+     */
+    private $addressMetadataService;
+
+    /**
+     * @var ElementFactory
+     */
+    private $elementFactory;
+
+    /**
+     * @var FileProcessorFactory
+     */
+    private $fileProcessorFactory;
+
+    /**
+     * @var AttributeMetadataInterface
+     */
+    private $attributeMetadata;
+
+    /**
+     * @var string
+     */
+    private $entityTypeCode;
+
+    /**
+     * @var string
+     */
+    private $scope;
+
+    /**
+     * @param CustomerMetadataInterface $customerMetadataService
+     * @param AddressMetadataInterface $addressMetadataService
+     * @param ElementFactory $elementFactory
+     * @param FileProcessorFactory $fileProcessorFactory
+     * @param AttributeMetadataInterface $attributeMetadata
+     * @param string $entityTypeCode
+     * @param string $scope
+     */
+    public function __construct(
+        CustomerMetadataInterface $customerMetadataService,
+        AddressMetadataInterface $addressMetadataService,
+        ElementFactory $elementFactory,
+        FileProcessorFactory $fileProcessorFactory,
+        AttributeMetadataInterface $attributeMetadata,
+        $entityTypeCode,
+        $scope
+    ) {
+        $this->customerMetadataService = $customerMetadataService;
+        $this->addressMetadataService = $addressMetadataService;
+        $this->elementFactory = $elementFactory;
+        $this->fileProcessorFactory = $fileProcessorFactory;
+        $this->attributeMetadata = $attributeMetadata;
+        $this->entityTypeCode = $entityTypeCode;
+        $this->scope = $scope;
+    }
+
+    /**
+     * Validate uploaded file
+     *
+     * @return array|bool
+     */
+    public function validate()
+    {
+        $formElement = $this->elementFactory->create(
+            $this->attributeMetadata,
+            null,
+            $this->entityTypeCode
+        );
+
+        $errors = $formElement->validateValue($this->getData());
+        return $errors;
+    }
+
+    /**
+     * Execute file uploading
+     *
+     * @return \string[]
+     * @throws LocalizedException
+     */
+    public function upload()
+    {
+        /** @var FileProcessor $fileProcessor */
+        $fileProcessor = $this->fileProcessorFactory->create([
+            'entityTypeCode' => $this->entityTypeCode,
+            'allowedExtensions' => $this->getAllowedExtensions(),
+        ]);
+
+        $result = $fileProcessor->saveTemporaryFile($this->scope . '[' . $this->getAttributeCode() . ']');
+
+        // Update tmp_name param. Required for attribute validation!
+        $result['tmp_name'] = $result['path'] . '/' . ltrim($result['file'], '/');
+
+        $result['url'] = $fileProcessor->getViewUrl(
+            FileProcessor::TMP_DIR . '/' . ltrim($result['name'], '/'),
+            $this->attributeMetadata->getFrontendInput()
+        );
+
+        return $result;
+    }
+
+    /**
+     * Get attribute code
+     *
+     * @return string
+     */
+    private function getAttributeCode()
+    {
+        return key($_FILES[$this->scope]['name']);
+    }
+
+    /**
+     * Retrieve data from global $_FILES array
+     *
+     * @return array
+     */
+    private function getData()
+    {
+        $data = [];
+
+        $fileAttributes = $_FILES[$this->scope];
+        foreach ($fileAttributes as $attributeName => $attributeValue) {
+            $data[$attributeName] = $attributeValue[$this->getAttributeCode()];
+        }
+
+        return $data;
+    }
+
+    /**
+     * Get allowed extensions
+     *
+     * @return array
+     */
+    private function getAllowedExtensions()
+    {
+        $allowedExtensions = [];
+
+        $validationRules = $this->attributeMetadata->getValidationRules();
+        foreach ($validationRules as $validationRule) {
+            if ($validationRule->getName() == 'file_extensions') {
+                $allowedExtensions = explode(',', $validationRule->getValue());
+                array_walk($allowedExtensions, function (&$value) {
+                    $value = strtolower(trim($value));
+                });
+                break;
+            }
+        }
+
+        return $allowedExtensions;
+    }
+}
diff --git a/app/code/Magento/Customer/Model/Metadata/Form/File.php b/app/code/Magento/Customer/Model/Metadata/Form/File.php
index 09a369bd50bf8d2cfa21a2185da72ca4f4d24ad7..69b19bc37373d13f95d5080b3e69960c65593662 100644
--- a/app/code/Magento/Customer/Model/Metadata/Form/File.php
+++ b/app/code/Magento/Customer/Model/Metadata/Form/File.php
@@ -7,6 +7,10 @@
  */
 namespace Magento\Customer\Model\Metadata\Form;
 
+use Magento\Customer\Model\FileProcessor;
+use Magento\Customer\Model\FileProcessorFactory;
+use Magento\Framework\Api\Data\ImageContentInterface;
+use Magento\Framework\App\ObjectManager;
 use Magento\Framework\File\UploaderFactory;
 use Magento\Framework\Filesystem;
 use Magento\Framework\App\Filesystem\DirectoryList;
@@ -46,6 +50,16 @@ class File extends AbstractData
      */
     private $uploaderFactory;
 
+    /**
+     * @var FileProcessor
+     */
+    protected $fileProcessor;
+
+    /**
+     * @var FileProcessorFactory
+     */
+    protected $fileProcessorFactory;
+
     /**
      * @param \Magento\Framework\Stdlib\DateTime\TimezoneInterface $localeDate
      * @param \Psr\Log\LoggerInterface $logger
@@ -86,10 +100,6 @@ class File extends AbstractData
      */
     public function extractValue(\Magento\Framework\App\RequestInterface $request)
     {
-        if ($this->getIsAjaxRequest()) {
-            return false;
-        }
-
         $extend = $this->_getRequestValue($request);
 
         $attrCode = $this->getAttribute()->getAttributeCode();
@@ -117,6 +127,14 @@ class File extends AbstractData
                         $value[$fileKey] = $scopeData[$attrCode];
                     }
                 }
+            } else if (isset($extend[0]['file']) && !empty($extend[0]['file'])) {
+                /**
+                 * This case is required by file uploader UI component
+                 *
+                 * $extend[0]['file'] - uses for AJAX validation
+                 * $extend[0] - uses for POST request
+                 */
+                $value = $this->getIsAjaxRequest() ? $extend[0]['file'] : $extend[0];
             } else {
                 $value = [];
             }
@@ -194,7 +212,17 @@ class File extends AbstractData
      */
     protected function _isUploadedFile($filename)
     {
-        return is_uploaded_file($filename);
+        if (is_uploaded_file($filename)) {
+            return true;
+        }
+
+        // This case is required for file uploader UI component
+        $temporaryFile = FileProcessor::TMP_DIR . '/' . pathinfo($filename)['basename'];
+        if ($this->getFileProcessor()->isExist($temporaryFile)) {
+            return true;
+        }
+
+        return false;
     }
 
     /**
@@ -241,7 +269,7 @@ class File extends AbstractData
     /**
      * {@inheritdoc}
      *
-     * @return $this|string
+     * @return ImageContentInterface|array|string|null
      */
     public function compactValue($value)
     {
@@ -249,11 +277,49 @@ class File extends AbstractData
             return $this;
         }
 
-        $attribute = $this->getAttribute();
-        $original = $this->_value;
+        // Remove outdated file (in the case of file uploader UI component)
+        if (empty($value) && !empty($this->_value)) {
+            $this->getFileProcessor()->removeUploadedFile($this->_value);
+            return $value;
+        }
+
+        if (isset($value['file']) && !empty($value['file'])) {
+            if ($value['file'] == $this->_value) {
+                return $this->_value;
+            }
+            $result = $this->processUiComponentValue($value);
+        } else {
+            $result = $this->processInputFieldValue($value);
+        }
+
+        return $result;
+    }
+
+    /**
+     * Process file uploader UI component data
+     *
+     * @param array $value
+     * @return string|null
+     */
+    protected function processUiComponentValue(array $value)
+    {
+        $result = $this->getFileProcessor()->moveTemporaryFile($value['file']);
+        return $result;
+    }
+
+    /**
+     * Process input type=file component data
+     *
+     * @param string $value
+     * @return bool|int|string
+     */
+    protected function processInputFieldValue($value)
+    {
         $toDelete = false;
-        if ($original) {
-            if (!$attribute->isRequired() && !empty($value['delete'])) {
+        if ($this->_value) {
+            if (!$this->getAttribute()->isRequired()
+                && !empty($value['delete'])
+            ) {
                 $toDelete = true;
             }
             if (!empty($value['tmp_name'])) {
@@ -262,11 +328,11 @@ class File extends AbstractData
         }
 
         $mediaDir = $this->_fileSystem->getDirectoryWrite(DirectoryList::MEDIA);
-        $result = $original;
-        // unlink entity file
+        $result = $this->_value;
+
         if ($toDelete) {
+            $mediaDir->delete($this->_entityTypeCode . '/' . ltrim($this->_value, '/'));
             $result = '';
-            $mediaDir->delete($this->_entityTypeCode . $original);
         }
 
         if (!empty($value['tmp_name'])) {
@@ -309,4 +375,37 @@ class File extends AbstractData
 
         return $output;
     }
+
+    /**
+     * Get FileProcessor instance
+     *
+     * @return FileProcessor
+     *
+     * @deprecated
+     */
+    protected function getFileProcessor()
+    {
+        if ($this->fileProcessor === null) {
+            $this->fileProcessor = $this->getFileProcessorFactory()->create([
+                'entityTypeCode' => $this->_entityTypeCode,
+            ]);
+        }
+        return $this->fileProcessor;
+    }
+
+    /**
+     * Get FileProcessorFactory instance
+     *
+     * @return FileProcessorFactory
+     *
+     * @deprecated
+     */
+    protected function getFileProcessorFactory()
+    {
+        if ($this->fileProcessorFactory === null) {
+            $this->fileProcessorFactory = ObjectManager::getInstance()
+                ->get('Magento\Customer\Model\FileProcessorFactory');
+        }
+        return $this->fileProcessorFactory;
+    }
 }
diff --git a/app/code/Magento/Customer/Model/Metadata/Form/Image.php b/app/code/Magento/Customer/Model/Metadata/Form/Image.php
index b50a2d519f4e0e8a0c6d7ed1b89b9bcf345fe470..993cd83826627fbd55bb2284ab45be0c4936c4a4 100644
--- a/app/code/Magento/Customer/Model/Metadata/Form/Image.php
+++ b/app/code/Magento/Customer/Model/Metadata/Form/Image.php
@@ -7,10 +7,21 @@
  */
 namespace Magento\Customer\Model\Metadata\Form;
 
+use Magento\Customer\Api\AddressMetadataInterface;
+use Magento\Customer\Api\CustomerMetadataInterface;
+use Magento\Customer\Model\FileProcessor;
 use Magento\Framework\Api\ArrayObjectSearch;
+use Magento\Framework\Api\Data\ImageContentInterface;
+use Magento\Framework\Api\Data\ImageContentInterfaceFactory;
+use Magento\Framework\App\ObjectManager;
 
 class Image extends File
 {
+    /**
+     * @var ImageContentInterfaceFactory
+     */
+    private $imageContentFactory;
+
     /**
      * Validate file by attribute validate rules
      * Return array of errors
@@ -68,7 +79,7 @@ class Image extends File
 
         $maxImageHeight = ArrayObjectSearch::getArrayElementByName(
             $rules,
-            'max_image_height'
+            'max_image_heght'
         );
         if ($maxImageHeight !== null) {
             if ($maxImageHeight < $imageProp[1]) {
@@ -79,4 +90,81 @@ class Image extends File
 
         return $errors;
     }
+
+    /**
+     * Process file uploader UI component data
+     *
+     * @param array $value
+     * @return bool|int|ImageContentInterface|string
+     */
+    protected function processUiComponentValue(array $value)
+    {
+        if ($this->_entityTypeCode == AddressMetadataInterface::ENTITY_TYPE_ADDRESS) {
+            $result = $this->processCustomerAddressValue($value);
+            return $result;
+        }
+
+        if ($this->_entityTypeCode == CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER) {
+            $result = $this->processCustomerValue($value);
+            return $result;
+        }
+
+        return $this->_value;
+    }
+
+    /**
+     * Process file uploader UI component data for customer_address entity
+     *
+     * @param array $value
+     * @return string
+     */
+    protected function processCustomerAddressValue(array $value)
+    {
+        $result = $this->getFileProcessor()->moveTemporaryFile($value['file']);
+        return $result;
+    }
+
+    /**
+     * Process file uploader UI component data for customer entity
+     *
+     * @param array $value
+     * @return bool|int|ImageContentInterface|string
+     */
+    protected function processCustomerValue(array $value)
+    {
+        $temporaryFile = FileProcessor::TMP_DIR . '/' . ltrim($value['file'], '/');
+
+        if ($this->getFileProcessor()->isExist($temporaryFile)) {
+            $base64EncodedData = $this->getFileProcessor()->getBase64EncodedData($temporaryFile);
+
+            /** @var ImageContentInterface $imageContentDataObject */
+            $imageContentDataObject = $this->getImageContentFactory()->create()
+                ->setName($value['name'])
+                ->setBase64EncodedData($base64EncodedData)
+                ->setType($value['type']);
+
+            // Remove temporary file
+            $this->getFileProcessor()->removeUploadedFile($temporaryFile);
+
+            return $imageContentDataObject;
+        }
+
+        return $this->_value;
+    }
+
+    /**
+     * Get ImageContentInterfaceFactory instance
+     *
+     * @return ImageContentInterfaceFactory
+     *
+     * @deprecated
+     */
+    private function getImageContentFactory()
+    {
+        if ($this->imageContentFactory === null) {
+            $this->imageContentFactory = ObjectManager::getInstance()
+                ->get('Magento\Framework\Api\Data\ImageContentInterfaceFactory');
+        }
+        return $this->imageContentFactory;
+    }
 }
diff --git a/app/code/Magento/Customer/Model/ResourceModel/AddressRepository.php b/app/code/Magento/Customer/Model/ResourceModel/AddressRepository.php
index fb2b2d13c9c50e2ac24036a046ed65ae8dea3c64..891863d64051d64763a1b7a4620f028a357d48fc 100644
--- a/app/code/Magento/Customer/Model/ResourceModel/AddressRepository.php
+++ b/app/code/Magento/Customer/Model/ResourceModel/AddressRepository.php
@@ -107,6 +107,7 @@ class AddressRepository implements \Magento\Customer\Api\AddressRepositoryInterf
         }
 
         if ($addressModel === null) {
+            /** @var \Magento\Customer\Model\Address $addressModel */
             $addressModel = $this->addressFactory->create();
             $addressModel->updateData($address);
             $addressModel->setCustomer($customerModel);
diff --git a/app/code/Magento/Customer/Model/ResourceModel/CustomerRepository.php b/app/code/Magento/Customer/Model/ResourceModel/CustomerRepository.php
index 47ea0843ded2e5caf307c5fef1f98cdd46e307be..1dfdfb0c388cab31b46e38a640e60082693bb0be 100644
--- a/app/code/Magento/Customer/Model/ResourceModel/CustomerRepository.php
+++ b/app/code/Magento/Customer/Model/ResourceModel/CustomerRepository.php
@@ -168,20 +168,7 @@ class CustomerRepository implements \Magento\Customer\Api\CustomerRepositoryInte
                 \Magento\Customer\Api\CustomerMetadataInterface::ATTRIBUTE_SET_ID_CUSTOMER
             );
         }
-        // Populate model with secure data
-        if ($customer->getId()) {
-            $customerSecure = $this->customerRegistry->retrieveSecureData($customer->getId());
-            $customerModel->setRpToken($customerSecure->getRpToken());
-            $customerModel->setRpTokenCreatedAt($customerSecure->getRpTokenCreatedAt());
-            $customerModel->setPasswordHash($customerSecure->getPasswordHash());
-            $customerModel->setFailuresNum($customerSecure->getFailuresNum());
-            $customerModel->setFirstFailure($customerSecure->getFirstFailure());
-            $customerModel->setLockExpires($customerSecure->getLockExpires());
-        } else {
-            if ($passwordHash) {
-                $customerModel->setPasswordHash($passwordHash);
-            }
-        }
+        $this->populateCustomerWithSecureData($customerModel, $passwordHash);
 
         // If customer email was changed, reset RpToken info
         if ($prevCustomerData
@@ -229,6 +216,34 @@ class CustomerRepository implements \Magento\Customer\Api\CustomerRepositoryInte
         return $savedCustomer;
     }
 
+    /**
+     * Set secure data to customer model
+     *
+     * @param \Magento\Customer\Model\Customer $customerModel
+     * @param string|null $passwordHash
+     * @return void
+     */
+    private function populateCustomerWithSecureData($customerModel, $passwordHash = null)
+    {
+        if ($customerModel->getId()) {
+            $customerSecure = $this->customerRegistry->retrieveSecureData($customerModel->getId());
+
+            $customerModel->setRpToken($passwordHash ? null : $customerSecure->getRpToken());
+            $customerModel->setRpTokenCreatedAt($passwordHash ? null : $customerSecure->getRpTokenCreatedAt());
+            $customerModel->setPasswordHash($passwordHash ?: $customerSecure->getPasswordHash());
+
+            $customerModel->setFailuresNum($customerSecure->getFailuresNum());
+            $customerModel->setFirstFailure($customerSecure->getFirstFailure());
+            $customerModel->setLockExpires($customerSecure->getLockExpires());
+        } elseif ($passwordHash) {
+            $customerModel->setPasswordHash($passwordHash);
+        }
+
+        if ($passwordHash && $customerModel->getId()) {
+            $this->customerRegistry->remove($customerModel->getId());
+        }
+    }
+
     /**
      * {@inheritdoc}
      */
diff --git a/app/code/Magento/Customer/Setup/CustomerSetup.php b/app/code/Magento/Customer/Setup/CustomerSetup.php
index dc99278f670c41e529d48ab30e00c5d16c7e09fb..57d003407c21cf58bc15a5dcccf28932912b476d 100644
--- a/app/code/Magento/Customer/Setup/CustomerSetup.php
+++ b/app/code/Magento/Customer/Setup/CustomerSetup.php
@@ -126,6 +126,7 @@ class CustomerSetup extends EavSetup
     {
         $entities = [
             'customer' => [
+                'entity_type_id' => \Magento\Customer\Api\CustomerMetadataInterface::ATTRIBUTE_SET_ID_CUSTOMER,
                 'entity_model' => 'Magento\Customer\Model\ResourceModel\Customer',
                 'attribute_model' => 'Magento\Customer\Model\Attribute',
                 'table' => 'customer_entity',
@@ -338,6 +339,7 @@ class CustomerSetup extends EavSetup
                 ],
             ],
             'customer_address' => [
+                'entity_type_id' => \Magento\Customer\Api\AddressMetadataInterface::ATTRIBUTE_SET_ID_ADDRESS,
                 'entity_model' => 'Magento\Customer\Model\ResourceModel\Address',
                 'attribute_model' => 'Magento\Customer\Model\Attribute',
                 'table' => 'customer_address_entity',
diff --git a/app/code/Magento/Customer/Test/Unit/Controller/Account/EditPostTest.php b/app/code/Magento/Customer/Test/Unit/Controller/Account/EditPostTest.php
index cdad131d06453375f844cbc4ad7abf45ccde2a7a..84c0184c18cf3eca56a5a9f190009bfc83f86e5e 100644
--- a/app/code/Magento/Customer/Test/Unit/Controller/Account/EditPostTest.php
+++ b/app/code/Magento/Customer/Test/Unit/Controller/Account/EditPostTest.php
@@ -94,6 +94,11 @@ class EditPostTest extends \PHPUnit_Framework_TestCase
      */
     protected $authenticationMock;
 
+    /**
+     * @var \Magento\Customer\Model\Customer\Mapper|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $customerMapperMock;
+
     protected function setUp()
     {
         $this->prepareContext();
@@ -133,6 +138,10 @@ class EditPostTest extends \PHPUnit_Framework_TestCase
             ->disableOriginalConstructor()
             ->getMock();
 
+        $this->customerMapperMock = $this->getMockBuilder('Magento\Customer\Model\Customer\Mapper')
+            ->disableOriginalConstructor()
+            ->getMock();
+
         $this->model = new EditPost(
             $this->context,
             $this->customerSession,
@@ -141,16 +150,28 @@ class EditPostTest extends \PHPUnit_Framework_TestCase
             $this->validator,
             $this->customerExtractor
         );
-        $reflection = new \ReflectionClass(get_class($this->model));
-        $reflectionProperty = $reflection->getProperty('emailNotification');
-        $reflectionProperty->setAccessible(true);
-        $reflectionProperty->setValue($this->model, $this->emailNotification);
-        $reflectionProperty2 = $reflection->getProperty('scopeConfig');
-        $reflectionProperty2->setAccessible(true);
-        $reflectionProperty2->setValue($this->model, $scopeConfigMock);
-        $reflectionProperty3 = $reflection->getProperty('authentication');
-        $reflectionProperty3->setAccessible(true);
-        $reflectionProperty3->setValue($this->model, $this->authenticationMock);
+
+        $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
+        $objectManager->setBackwardCompatibleProperty(
+            $this->model,
+            'emailNotification',
+            $this->emailNotification
+        );
+        $objectManager->setBackwardCompatibleProperty(
+            $this->model,
+            'scopeConfig',
+            $scopeConfigMock
+        );
+        $objectManager->setBackwardCompatibleProperty(
+            $this->model,
+            'authentication',
+            $this->authenticationMock
+        );
+        $objectManager->setBackwardCompatibleProperty(
+            $this->model,
+            'customerMapper',
+            $this->customerMapperMock
+        );
     }
 
     public function testInvalidFormKey()
@@ -203,6 +224,11 @@ class EditPostTest extends \PHPUnit_Framework_TestCase
             ->method('getEmail')
             ->willReturn($customerEmail);
 
+        $this->customerMapperMock->expects($this->once())
+            ->method('toFlatArray')
+            ->with($currentCustomerMock)
+            ->willReturn([]);
+
         $this->customerSession->expects($this->once())
             ->method('getCustomerId')
             ->willReturn($customerId);
@@ -301,6 +327,11 @@ class EditPostTest extends \PHPUnit_Framework_TestCase
         $currentCustomerMock = $this->getCurrentCustomerMock($customerId, $address);
         $newCustomerMock = $this->getNewCustomerMock($customerId, $address);
 
+        $this->customerMapperMock->expects($this->once())
+            ->method('toFlatArray')
+            ->with($currentCustomerMock)
+            ->willReturn([]);
+
         $this->customerExtractor->expects($this->once())
             ->method('extract')
             ->with('customer_account_edit', $this->request)
@@ -409,6 +440,11 @@ class EditPostTest extends \PHPUnit_Framework_TestCase
         $currentCustomerMock = $this->getCurrentCustomerMock($customerId, $address);
         $newCustomerMock = $this->getNewCustomerMock($customerId, $address);
 
+        $this->customerMapperMock->expects($this->once())
+            ->method('toFlatArray')
+            ->with($currentCustomerMock)
+            ->willReturn([]);
+
         $this->customerSession->expects($this->once())
             ->method('getCustomerId')
             ->willReturn($customerId);
@@ -559,6 +595,11 @@ class EditPostTest extends \PHPUnit_Framework_TestCase
         $currentCustomerMock = $this->getCurrentCustomerMock($customerId, $address);
         $newCustomerMock = $this->getNewCustomerMock($customerId, $address);
 
+        $this->customerMapperMock->expects($this->once())
+            ->method('toFlatArray')
+            ->with($currentCustomerMock)
+            ->willReturn([]);
+
         $exception = new $exception(__($message));
 
         $this->validator->expects($this->once())
diff --git a/app/code/Magento/Customer/Test/Unit/Controller/Address/FormPostTest.php b/app/code/Magento/Customer/Test/Unit/Controller/Address/FormPostTest.php
index dea40e2769e0f23b472ccc72e85a51f77c138aae..86559c1c0e0e670a863ac2424ce374e1b6dacc6d 100644
--- a/app/code/Magento/Customer/Test/Unit/Controller/Address/FormPostTest.php
+++ b/app/code/Magento/Customer/Test/Unit/Controller/Address/FormPostTest.php
@@ -157,6 +157,11 @@ class FormPostTest extends \PHPUnit_Framework_TestCase
      */
     protected $messageManager;
 
+    /**
+     * @var \Magento\Customer\Model\Address\Mapper|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $customerAddressMapper;
+
     protected function setUp()
     {
         $this->prepareContext();
@@ -197,6 +202,10 @@ class FormPostTest extends \PHPUnit_Framework_TestCase
             ->disableOriginalConstructor()
             ->getMock();
 
+        $this->customerAddressMapper = $this->getMockBuilder('Magento\Customer\Model\Address\Mapper')
+            ->disableOriginalConstructor()
+            ->getMock();
+
         $this->model = new FormPost(
             $this->context,
             $this->session,
@@ -212,6 +221,13 @@ class FormPostTest extends \PHPUnit_Framework_TestCase
             $this->regionFactory,
             $this->helperData
         );
+
+        $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
+        $objectManager->setBackwardCompatibleProperty(
+            $this->model,
+            'customerAddressMapper',
+            $this->customerAddressMapper
+        );
     }
 
     protected function prepareContext()
@@ -458,22 +474,11 @@ class FormPostTest extends \PHPUnit_Framework_TestCase
             ->with($this->addressData)
             ->willReturnSelf();
 
-        $this->dataProcessor->expects($this->once())
-            ->method('buildOutputDataArray')
-            ->with($this->addressData, '\Magento\Customer\Api\Data\AddressInterface')
+        $this->customerAddressMapper->expects($this->once())
+            ->method('toFlatArray')
+            ->with($this->addressData)
             ->willReturn($existingAddressData);
 
-        $this->addressData->expects($this->any())
-            ->method('getRegion')
-            ->willReturn($this->regionData);
-
-        $this->regionData->expects($this->once())
-            ->method('getRegionCode')
-            ->willReturn($regionCode);
-        $this->regionData->expects($this->once())
-            ->method('getRegion')
-            ->willReturn($region);
-
         $this->formFactory->expects($this->once())
             ->method('create')
             ->with('customer_address', 'customer_address_edit', $existingAddressData)
diff --git a/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/File/Address/UploadTest.php b/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/File/Address/UploadTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..2853a39982367d0f992854e6f7ef707e822807ab
--- /dev/null
+++ b/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/File/Address/UploadTest.php
@@ -0,0 +1,234 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Customer\Test\Unit\Controller\Adminhtml\File\Address;
+
+use Magento\Customer\Api\AddressMetadataInterface;
+use Magento\Customer\Controller\Adminhtml\File\Address\Upload;
+use Magento\Framework\Controller\ResultFactory;
+
+class UploadTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var Upload
+     */
+    private $controller;
+
+    /**
+     * @var \Magento\Backend\App\Action\Context|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $context;
+
+    /**
+     * @var \Magento\Customer\Model\FileUploaderFactory|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $fileUploaderFactory;
+
+    /**
+     * @var ResultFactory|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $resultFactory;
+
+    /**
+     * @var AddressMetadataInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $addressMetadataService;
+
+    /**
+     * @var \Psr\Log\LoggerInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $logger;
+
+    protected function setUp()
+    {
+        $this->resultFactory = $this->getMockBuilder('Magento\Framework\Controller\ResultFactory')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->context = $this->getMockBuilder('Magento\Backend\App\Action\Context')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->context->expects($this->once())
+            ->method('getResultFactory')
+            ->willReturn($this->resultFactory);
+
+        $this->fileUploaderFactory = $this->getMockBuilder('Magento\Customer\Model\FileUploaderFactory')
+            ->disableOriginalConstructor()
+            ->setMethods(['create'])
+            ->getMock();
+
+        $this->addressMetadataService = $this->getMockBuilder('Magento\Customer\Api\AddressMetadataInterface')
+            ->getMockForAbstractClass();
+
+        $this->logger = $this->getMockBuilder('Psr\Log\LoggerInterface')
+            ->getMockForAbstractClass();
+
+        $this->controller = new Upload(
+            $this->context,
+            $this->fileUploaderFactory,
+            $this->addressMetadataService,
+            $this->logger
+        );
+    }
+
+    public function testExecuteEmptyFiles()
+    {
+        $exception = new \Exception('$_FILES array is empty.');
+        $this->logger->expects($this->once())
+            ->method('critical')
+            ->with($exception)
+            ->willReturnSelf();
+
+        $resultJson = $this->getMockBuilder('Magento\Framework\Controller\Result\Json')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $resultJson->expects($this->once())
+            ->method('setData')
+            ->with([
+                'error' => __('Something went wrong while saving file.'),
+                'errorcode' => 0,
+            ])
+            ->willReturnSelf();
+
+        $this->resultFactory->expects($this->once())
+            ->method('create')
+            ->with(ResultFactory::TYPE_JSON)
+            ->willReturn($resultJson);
+
+        $this->assertInstanceOf('Magento\Framework\Controller\Result\Json', $this->controller->execute());
+    }
+
+    public function testExecute()
+    {
+        $attributeCode = 'attribute_code';
+
+        $_FILES = [
+            'address' => [
+                'name' => [
+                    'new_0' => [
+                        $attributeCode => 'filename',
+                    ],
+                ],
+            ],
+        ];
+
+        $resultFileName = '/filename.ext1';
+        $resultFilePath = 'filepath';
+        $resultFileUrl = 'viewFileUrl';
+
+        $result = [
+            'name' => $resultFileName,
+            'file' => $resultFileName,
+            'path' => $resultFilePath,
+            'tmp_name' => $resultFilePath . $resultFileName,
+            'url' => $resultFileUrl,
+        ];
+
+        $attributeMetadataMock = $this->getMockBuilder('Magento\Customer\Api\Data\AttributeMetadataInterface')
+            ->getMockForAbstractClass();
+
+        $this->addressMetadataService->expects($this->once())
+            ->method('getAttributeMetadata')
+            ->with($attributeCode)
+            ->willReturn($attributeMetadataMock);
+
+        $fileUploader = $this->getMockBuilder('Magento\Customer\Model\FileUploader')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $fileUploader->expects($this->once())
+            ->method('validate')
+            ->willReturn(true);
+        $fileUploader->expects($this->once())
+            ->method('upload')
+            ->willReturn($result);
+
+        $this->fileUploaderFactory->expects($this->once())
+            ->method('create')
+            ->with([
+                'attributeMetadata' => $attributeMetadataMock,
+                'entityTypeCode' => AddressMetadataInterface::ENTITY_TYPE_ADDRESS,
+                'scope' => 'address',
+            ])
+            ->willReturn($fileUploader);
+
+        $resultJson = $this->getMockBuilder('Magento\Framework\Controller\Result\Json')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $resultJson->expects($this->once())
+            ->method('setData')
+            ->with($result)
+            ->willReturnSelf();
+
+        $this->resultFactory->expects($this->once())
+            ->method('create')
+            ->with(ResultFactory::TYPE_JSON)
+            ->willReturn($resultJson);
+
+        $this->assertInstanceOf('Magento\Framework\Controller\Result\Json', $this->controller->execute());
+    }
+
+    public function testExecuteWithErrors()
+    {
+        $attributeCode = 'attribute_code';
+
+        $_FILES = [
+            'address' => [
+                'name' => [
+                    'new_0' => [
+                        $attributeCode => 'filename',
+                    ],
+                ],
+            ],
+        ];
+
+        $errors = [
+            'error1',
+            'error2',
+        ];
+
+        $attributeMetadataMock = $this->getMockBuilder('Magento\Customer\Api\Data\AttributeMetadataInterface')
+            ->getMockForAbstractClass();
+
+        $this->addressMetadataService->expects($this->once())
+            ->method('getAttributeMetadata')
+            ->with($attributeCode)
+            ->willReturn($attributeMetadataMock);
+
+        $fileUploader = $this->getMockBuilder('Magento\Customer\Model\FileUploader')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $fileUploader->expects($this->once())
+            ->method('validate')
+            ->willReturn($errors);
+
+        $this->fileUploaderFactory->expects($this->once())
+            ->method('create')
+            ->with([
+                'attributeMetadata' => $attributeMetadataMock,
+                'entityTypeCode' => AddressMetadataInterface::ENTITY_TYPE_ADDRESS,
+                'scope' => 'address',
+            ])
+            ->willReturn($fileUploader);
+
+        $resultJson = $this->getMockBuilder('Magento\Framework\Controller\Result\Json')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $resultJson->expects($this->once())
+            ->method('setData')
+            ->with([
+                'error' => implode('</br>', $errors),
+                'errorcode' => 0,
+            ])
+            ->willReturnSelf();
+
+        $this->resultFactory->expects($this->once())
+            ->method('create')
+            ->with(ResultFactory::TYPE_JSON)
+            ->willReturn($resultJson);
+
+        $this->assertInstanceOf('Magento\Framework\Controller\Result\Json', $this->controller->execute());
+    }
+}
diff --git a/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/File/Customer/UploadTest.php b/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/File/Customer/UploadTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..29ac801bb58852cabc50b16dbd21f8be46515edf
--- /dev/null
+++ b/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/File/Customer/UploadTest.php
@@ -0,0 +1,230 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Customer\Test\Unit\Controller\Adminhtml\File\Customer;
+
+use Magento\Customer\Api\CustomerMetadataInterface;
+use Magento\Customer\Controller\Adminhtml\File\Customer\Upload;
+use Magento\Framework\Controller\ResultFactory;
+
+class UploadTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var Upload
+     */
+    private $controller;
+
+    /**
+     * @var \Magento\Backend\App\Action\Context|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $context;
+
+    /**
+     * @var \Magento\Customer\Model\FileUploaderFactory|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $fileUploaderFactory;
+
+    /**
+     * @var ResultFactory|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $resultFactory;
+
+    /**
+     * @var CustomerMetadataInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $customerMetadataService;
+
+    /**
+     * @var \Psr\Log\LoggerInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $logger;
+
+    protected function setUp()
+    {
+        $this->resultFactory = $this->getMockBuilder('Magento\Framework\Controller\ResultFactory')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->context = $this->getMockBuilder('Magento\Backend\App\Action\Context')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->context->expects($this->once())
+            ->method('getResultFactory')
+            ->willReturn($this->resultFactory);
+
+        $this->fileUploaderFactory = $this->getMockBuilder('Magento\Customer\Model\FileUploaderFactory')
+            ->disableOriginalConstructor()
+            ->setMethods(['create'])
+            ->getMock();
+
+        $this->customerMetadataService = $this->getMockBuilder('Magento\Customer\Api\CustomerMetadataInterface')
+            ->getMockForAbstractClass();
+
+        $this->logger = $this->getMockBuilder('Psr\Log\LoggerInterface')
+            ->getMockForAbstractClass();
+
+        $this->controller = new Upload(
+            $this->context,
+            $this->fileUploaderFactory,
+            $this->customerMetadataService,
+            $this->logger
+        );
+    }
+
+    public function testExecuteEmptyFiles()
+    {
+        $exception = new \Exception('$_FILES array is empty.');
+        $this->logger->expects($this->once())
+            ->method('critical')
+            ->with($exception)
+            ->willReturnSelf();
+
+        $resultJson = $this->getMockBuilder('Magento\Framework\Controller\Result\Json')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $resultJson->expects($this->once())
+            ->method('setData')
+            ->with([
+                'error' => __('Something went wrong while saving file.'),
+                'errorcode' => 0,
+            ])
+            ->willReturnSelf();
+
+        $this->resultFactory->expects($this->once())
+            ->method('create')
+            ->with(ResultFactory::TYPE_JSON)
+            ->willReturn($resultJson);
+
+        $this->assertInstanceOf('Magento\Framework\Controller\Result\Json', $this->controller->execute());
+    }
+
+    public function testExecute()
+    {
+        $attributeCode = 'attribute_code';
+
+        $_FILES = [
+            'customer' => [
+                'name' => [
+                    $attributeCode => 'filename',
+                ],
+            ],
+        ];
+
+        $resultFileName = '/filename.ext1';
+        $resultFilePath = 'filepath';
+        $resultFileUrl = 'viewFileUrl';
+
+        $result = [
+            'name' => $resultFileName,
+            'file' => $resultFileName,
+            'path' => $resultFilePath,
+            'tmp_name' => $resultFilePath . $resultFileName,
+            'url' => $resultFileUrl,
+        ];
+
+        $attributeMetadataMock = $this->getMockBuilder('Magento\Customer\Api\Data\AttributeMetadataInterface')
+            ->getMockForAbstractClass();
+
+        $this->customerMetadataService->expects($this->once())
+            ->method('getAttributeMetadata')
+            ->with($attributeCode)
+            ->willReturn($attributeMetadataMock);
+
+        $fileUploader = $this->getMockBuilder('Magento\Customer\Model\FileUploader')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $fileUploader->expects($this->once())
+            ->method('validate')
+            ->willReturn(true);
+        $fileUploader->expects($this->once())
+            ->method('upload')
+            ->willReturn($result);
+
+        $this->fileUploaderFactory->expects($this->once())
+            ->method('create')
+            ->with([
+                'attributeMetadata' => $attributeMetadataMock,
+                'entityTypeCode' => CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER,
+                'scope' => 'customer',
+            ])
+            ->willReturn($fileUploader);
+
+        $resultJson = $this->getMockBuilder('Magento\Framework\Controller\Result\Json')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $resultJson->expects($this->once())
+            ->method('setData')
+            ->with($result)
+            ->willReturnSelf();
+
+        $this->resultFactory->expects($this->once())
+            ->method('create')
+            ->with(ResultFactory::TYPE_JSON)
+            ->willReturn($resultJson);
+
+        $this->assertInstanceOf('Magento\Framework\Controller\Result\Json', $this->controller->execute());
+    }
+
+    public function testExecuteWithErrors()
+    {
+        $attributeCode = 'attribute_code';
+
+        $_FILES = [
+            'customer' => [
+                'name' => [
+                    $attributeCode => 'filename',
+                ],
+            ],
+        ];
+
+        $errors = [
+            'error1',
+            'error2',
+        ];
+
+        $attributeMetadataMock = $this->getMockBuilder('Magento\Customer\Api\Data\AttributeMetadataInterface')
+            ->getMockForAbstractClass();
+
+        $this->customerMetadataService->expects($this->once())
+            ->method('getAttributeMetadata')
+            ->with($attributeCode)
+            ->willReturn($attributeMetadataMock);
+
+        $fileUploader = $this->getMockBuilder('Magento\Customer\Model\FileUploader')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $fileUploader->expects($this->once())
+            ->method('validate')
+            ->willReturn($errors);
+
+        $this->fileUploaderFactory->expects($this->once())
+            ->method('create')
+            ->with([
+                'attributeMetadata' => $attributeMetadataMock,
+                'entityTypeCode' => CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER,
+                'scope' => 'customer',
+            ])
+            ->willReturn($fileUploader);
+
+        $resultJson = $this->getMockBuilder('Magento\Framework\Controller\Result\Json')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $resultJson->expects($this->once())
+            ->method('setData')
+            ->with([
+                'error' => implode('</br>', $errors),
+                'errorcode' => 0,
+            ])
+            ->willReturnSelf();
+
+        $this->resultFactory->expects($this->once())
+            ->method('create')
+            ->with(ResultFactory::TYPE_JSON)
+            ->willReturn($resultJson);
+
+        $this->assertInstanceOf('Magento\Framework\Controller\Result\Json', $this->controller->execute());
+    }
+}
diff --git a/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/Index/SaveTest.php b/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/Index/SaveTest.php
index 574f54cea931cfe7f5e3f98bd80106ba532ae613..7813690cea78044864f4b565488baec7a0da4786 100644
--- a/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/Index/SaveTest.php
+++ b/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/Index/SaveTest.php
@@ -5,9 +5,13 @@
  */
 namespace Magento\Customer\Test\Unit\Controller\Adminhtml\Index;
 
+use Magento\Customer\Api\AddressMetadataInterface;
+use Magento\Customer\Api\CustomerMetadataInterface;
 use Magento\Customer\Api\Data\AttributeMetadataInterface;
-use Magento\Customer\Controller\Adminhtml\Index\Save;
+use Magento\Customer\Api\Data\CustomerInterface;
+use Magento\Customer\Controller\RegistryConstants;
 use Magento\Customer\Model\EmailNotificationInterface;
+use Magento\Customer\Model\Metadata\Form;
 use Magento\Framework\Controller\Result\Redirect;
 
 /**
@@ -137,6 +141,16 @@ class SaveTest extends \PHPUnit_Framework_TestCase
      */
     protected $emailNotificationMock;
 
+    /**
+     * @var \Magento\Customer\Model\Address\Mapper|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $customerAddressMapperMock;
+
+    /**
+     * @var \Magento\Customer\Api\AddressRepositoryInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $customerAddressRepositoryMock;
+
     /**
      * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
      */
@@ -183,9 +197,15 @@ class SaveTest extends \PHPUnit_Framework_TestCase
         $this->customerRepositoryMock = $this->getMockBuilder('Magento\Customer\Api\CustomerRepositoryInterface')
             ->disableOriginalConstructor()
             ->getMock();
+        $this->customerAddressRepositoryMock = $this->getMockBuilder('Magento\Customer\Api\AddressRepositoryInterface')
+            ->disableOriginalConstructor()
+            ->getMock();
         $this->customerMapperMock = $this->getMockBuilder('Magento\Customer\Model\Customer\Mapper')
             ->disableOriginalConstructor()
             ->getMock();
+        $this->customerAddressMapperMock = $this->getMockBuilder('Magento\Customer\Model\Address\Mapper')
+            ->disableOriginalConstructor()
+            ->getMock();
         $this->dataHelperMock = $this->getMockBuilder('Magento\Framework\Api\DataObjectHelper')
             ->disableOriginalConstructor()
             ->getMock();
@@ -240,13 +260,16 @@ class SaveTest extends \PHPUnit_Framework_TestCase
                 'authorization' => $this->authorizationMock,
                 'messageManager' => $this->messageManagerMock,
                 'resultRedirectFactory' => $this->redirectFactoryMock,
+                'addressRepository' => $this->customerAddressRepositoryMock,
+                'addressMapper' => $this->customerAddressMapperMock,
             ]
         );
 
-        $refClass = new \ReflectionClass(Save::class);
-        $property = $refClass->getProperty('emailNotification');
-        $property->setAccessible(true);
-        $property->setValue($this->model, $this->emailNotificationMock);
+        $objectManager->setBackwardCompatibleProperty(
+            $this->model,
+            'emailNotification',
+            $this->emailNotificationMock
+        );
     }
 
     /**
@@ -285,6 +308,17 @@ class SaveTest extends \PHPUnit_Framework_TestCase
             'coolness' => false,
             'disable_auto_group_change' => 'false',
         ];
+        $dataToCompact = [
+            'entity_id' => $customerId,
+            'code' => 'value',
+            'coolness' => false,
+            'disable_auto_group_change' => 'false',
+            CustomerInterface::DEFAULT_BILLING => false,
+            CustomerInterface::DEFAULT_SHIPPING => false,
+            'confirmation' => false,
+            'sendemail_store_id' => false,
+            'extension_attributes' => false,
+        ];
         $addressFilteredData = [
             'entity_id' => $addressId,
             'default_billing' => 'true',
@@ -294,12 +328,26 @@ class SaveTest extends \PHPUnit_Framework_TestCase
             'region' => 'region',
             'region_id' => 'region_id',
         ];
+        $addressDataToCompact = [
+            'entity_id' => $addressId,
+            'default_billing' => 'true',
+            'default_shipping' => 'true',
+            'code' => 'value',
+            'coolness' => false,
+            'region' => 'region',
+            'region_id' => 'region_id',
+        ];
         $savedData = [
             'entity_id' => $customerId,
             'darkness' => true,
             'name' => 'Name',
-            \Magento\Customer\Api\Data\CustomerInterface::DEFAULT_BILLING => false,
-            \Magento\Customer\Api\Data\CustomerInterface::DEFAULT_SHIPPING => false,
+            CustomerInterface::DEFAULT_BILLING => false,
+            CustomerInterface::DEFAULT_SHIPPING => false,
+        ];
+        $savedAddressData = [
+            'entity_id' => $addressId,
+            'default_billing' => true,
+            'default_shipping' => true,
         ];
         $mergedData = [
             'entity_id' => $customerId,
@@ -307,8 +355,8 @@ class SaveTest extends \PHPUnit_Framework_TestCase
             'name' => 'Name',
             'code' => 'value',
             'disable_auto_group_change' => 0,
-            \Magento\Customer\Api\Data\CustomerInterface::DEFAULT_BILLING => $addressId,
-            \Magento\Customer\Api\Data\CustomerInterface::DEFAULT_SHIPPING => $addressId,
+            CustomerInterface::DEFAULT_BILLING => $addressId,
+            CustomerInterface::DEFAULT_SHIPPING => $addressId,
             'confirmation' => false,
             'sendemail_store_id' => '1',
             'id' => $customerId,
@@ -327,7 +375,7 @@ class SaveTest extends \PHPUnit_Framework_TestCase
             'id' => $addressId,
         ];
 
-        /** @var AttributeMetadataInterface|\PHPUnit_Framework_MockObject_MockObject $formMock */
+        /** @var AttributeMetadataInterface|\PHPUnit_Framework_MockObject_MockObject $customerFormMock */
         $attributeMock = $this->getMockBuilder('Magento\Customer\Api\Data\AttributeMetadataInterface')
             ->disableOriginalConstructor()
             ->getMock();
@@ -339,9 +387,13 @@ class SaveTest extends \PHPUnit_Framework_TestCase
             ->willReturn('int');
         $attributes = [$attributeMock];
 
-        $this->requestMock->expects($this->exactly(3))
+        $this->requestMock->expects($this->any())
             ->method('getPostValue')
-            ->willReturn($postValue);
+            ->willReturnMap([
+                [null, null, $postValue],
+                [CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER, null, $postValue['customer']],
+                ['address/' . $addressId, null, $postValue['address'][$addressId]],
+            ]);
         $this->requestMock->expects($this->exactly(3))
             ->method('getPost')
             ->willReturnMap(
@@ -352,69 +404,80 @@ class SaveTest extends \PHPUnit_Framework_TestCase
                 ]
             );
 
-        /** @var \Magento\Customer\Model\Metadata\Form|\PHPUnit_Framework_MockObject_MockObject $formMock */
-        $formMock = $this->getMockBuilder('Magento\Customer\Model\Metadata\Form')
+        /** @var \Magento\Framework\DataObject|\PHPUnit_Framework_MockObject_MockObject $objectMock */
+        $objectMock = $this->getMockBuilder('Magento\Framework\DataObject')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $objectMock->expects($this->exactly(2))
+            ->method('getData')
+            ->willReturnMap(
+                [
+                    ['customer', null, $postValue['customer']],
+                    ['address/' . $addressId, null, $postValue['address'][$addressId]],
+                ]
+            );
+
+        $this->objectFactoryMock->expects($this->exactly(2))
+            ->method('create')
+            ->with(['data' => $postValue])
+            ->willReturn($objectMock);
+
+        $customerFormMock = $this->getMockBuilder('Magento\Customer\Model\Metadata\Form')
             ->disableOriginalConstructor()
             ->getMock();
+        $customerFormMock->expects($this->once())
+            ->method('extractData')
+            ->with($this->requestMock, 'customer')
+            ->willReturn($filteredData);
+        $customerFormMock->expects($this->once())
+            ->method('compactData')
+            ->with($dataToCompact)
+            ->willReturn($filteredData);
+        $customerFormMock->expects($this->once())
+            ->method('getAttributes')
+            ->willReturn($attributes);
+
+        $customerAddressFormMock = $this->getMockBuilder('Magento\Customer\Model\Metadata\Form')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $customerAddressFormMock->expects($this->once())
+            ->method('extractData')
+            ->with($this->requestMock, 'address/' . $addressId)
+            ->willReturn($addressFilteredData);
+        $customerAddressFormMock->expects($this->once())
+            ->method('compactData')
+            ->with($addressDataToCompact)
+            ->willReturn($addressFilteredData);
+        $customerAddressFormMock->expects($this->once())
+            ->method('getAttributes')
+            ->willReturn($attributes);
 
         $this->formFactoryMock->expects($this->exactly(2))
             ->method('create')
             ->willReturnMap(
                 [
                     [
-                        \Magento\Customer\Api\CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER,
+                        CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER,
                         'adminhtml_customer',
-                        [],
+                        $savedData,
                         false,
-                        \Magento\Customer\Model\Metadata\Form::DONT_IGNORE_INVISIBLE,
+                        Form::DONT_IGNORE_INVISIBLE,
                         [],
-                        $formMock
+                        $customerFormMock
                     ],
                     [
-                        \Magento\Customer\Api\AddressMetadataInterface::ENTITY_TYPE_ADDRESS,
+                        AddressMetadataInterface::ENTITY_TYPE_ADDRESS,
                         'adminhtml_customer_address',
-                        [],
+                        $savedAddressData,
                         false,
-                        \Magento\Customer\Model\Metadata\Form::DONT_IGNORE_INVISIBLE,
+                        Form::DONT_IGNORE_INVISIBLE,
                         [],
-                        $formMock
+                        $customerAddressFormMock
                     ],
                 ]
             );
 
-        $formMock->expects($this->exactly(2))
-            ->method('extractData')
-            ->willReturnMap(
-                [
-                    [$this->requestMock, 'customer', true, $filteredData],
-                    [$this->requestMock, 'address/' . $addressId, true, $addressFilteredData],
-                ]
-            );
-
-        /** @var \Magento\Framework\DataObject|\PHPUnit_Framework_MockObject_MockObject $objectMock */
-        $objectMock = $this->getMockBuilder('Magento\Framework\DataObject')
-            ->disableOriginalConstructor()
-            ->getMock();
-
-        $this->objectFactoryMock->expects($this->exactly(2))
-            ->method('create')
-            ->with(['data' => $postValue])
-            ->willReturn($objectMock);
-
-        $objectMock->expects($this->exactly(2))
-            ->method('getData')
-            ->willReturnMap(
-                [
-                    ['customer', null, $postValue['customer']],
-                    ['address/' . $addressId, null, $postValue['address'][$addressId]],
-                ]
-            );
-
-        $formMock->expects($this->exactly(2))
-            ->method('getAttributes')
-            ->willReturn($attributes);
-
-        /** @var \Magento\Customer\Api\Data\CustomerInterface|\PHPUnit_Framework_MockObject_MockObject $customerMock */
+        /** @var CustomerInterface|\PHPUnit_Framework_MockObject_MockObject $customerMock */
         $customerMock = $this->getMockBuilder('Magento\Customer\Api\Data\CustomerInterface')
             ->disableOriginalConstructor()
             ->getMock();
@@ -423,12 +486,12 @@ class SaveTest extends \PHPUnit_Framework_TestCase
             ->method('create')
             ->willReturn($customerMock);
 
-        $this->customerRepositoryMock->expects($this->once())
+        $this->customerRepositoryMock->expects($this->exactly(2))
             ->method('getById')
             ->with($customerId)
             ->willReturn($customerMock);
 
-        $this->customerMapperMock->expects($this->once())
+        $this->customerMapperMock->expects($this->exactly(2))
             ->method('toFlatArray')
             ->with($customerMock)
             ->willReturn($savedData);
@@ -437,6 +500,16 @@ class SaveTest extends \PHPUnit_Framework_TestCase
             ->disableOriginalConstructor()
             ->getMock();
 
+        $this->customerAddressRepositoryMock->expects($this->once())
+            ->method('getById')
+            ->with($addressId)
+            ->willReturn($addressMock);
+
+        $this->customerAddressMapperMock->expects($this->once())
+            ->method('toFlatArray')
+            ->with($addressMock)
+            ->willReturn($savedAddressData);
+
         $this->addressDataFactoryMock->expects($this->once())
             ->method('create')
             ->willReturn($addressMock);
@@ -504,7 +577,7 @@ class SaveTest extends \PHPUnit_Framework_TestCase
 
         $this->registryMock->expects($this->once())
             ->method('register')
-            ->with(\Magento\Customer\Controller\RegistryConstants::CURRENT_CUSTOMER_ID, $customerId);
+            ->with(RegistryConstants::CURRENT_CUSTOMER_ID, $customerId);
 
         $this->messageManagerMock->expects($this->once())
             ->method('addSuccess')
@@ -566,6 +639,15 @@ class SaveTest extends \PHPUnit_Framework_TestCase
             'coolness' => false,
             'disable_auto_group_change' => 'false',
         ];
+        $dataToCompact = [
+            'coolness' => false,
+            'disable_auto_group_change' => 'false',
+            CustomerInterface::DEFAULT_BILLING => false,
+            CustomerInterface::DEFAULT_SHIPPING => false,
+            'confirmation' => false,
+            'sendemail_store_id' => false,
+            'extension_attributes' => false,
+        ];
         $addressFilteredData = [
             'entity_id' => $addressId,
             'default_billing' => 'false',
@@ -575,10 +657,19 @@ class SaveTest extends \PHPUnit_Framework_TestCase
             'region' => 'region',
             'region_id' => 'region_id',
         ];
+        $addressDataToCompact = [
+            'entity_id' => $addressId,
+            'default_billing' => 'false',
+            'default_shipping' => 'false',
+            'code' => 'value',
+            'coolness' => false,
+            'region' => 'region',
+            'region_id' => 'region_id',
+        ];
         $mergedData = [
             'disable_auto_group_change' => 0,
-            \Magento\Customer\Api\Data\CustomerInterface::DEFAULT_BILLING => null,
-            \Magento\Customer\Api\Data\CustomerInterface::DEFAULT_SHIPPING => null,
+            CustomerInterface::DEFAULT_BILLING => null,
+            CustomerInterface::DEFAULT_SHIPPING => null,
             'confirmation' => false,
         ];
         $mergedAddressData = [
@@ -595,7 +686,7 @@ class SaveTest extends \PHPUnit_Framework_TestCase
             'id' => $addressId,
         ];
 
-        /** @var AttributeMetadataInterface|\PHPUnit_Framework_MockObject_MockObject $formMock */
+        /** @var AttributeMetadataInterface|\PHPUnit_Framework_MockObject_MockObject $customerFormMock */
         $attributeMock = $this->getMockBuilder('Magento\Customer\Api\Data\AttributeMetadataInterface')
             ->disableOriginalConstructor()
             ->getMock();
@@ -607,9 +698,13 @@ class SaveTest extends \PHPUnit_Framework_TestCase
             ->willReturn('int');
         $attributes = [$attributeMock];
 
-        $this->requestMock->expects($this->exactly(3))
+        $this->requestMock->expects($this->any())
             ->method('getPostValue')
-            ->willReturn($postValue);
+            ->willReturnMap([
+                [null, null, $postValue],
+                [CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER, null, $postValue['customer']],
+                ['address/' . $addressId, null, $postValue['address'][$addressId]],
+            ]);
         $this->requestMock->expects($this->exactly(3))
             ->method('getPost')
             ->willReturnMap(
@@ -620,69 +715,80 @@ class SaveTest extends \PHPUnit_Framework_TestCase
                 ]
             );
 
-        /** @var \Magento\Customer\Model\Metadata\Form|\PHPUnit_Framework_MockObject_MockObject $formMock */
-        $formMock = $this->getMockBuilder('Magento\Customer\Model\Metadata\Form')
+        /** @var \Magento\Framework\DataObject|\PHPUnit_Framework_MockObject_MockObject $objectMock */
+        $objectMock = $this->getMockBuilder('Magento\Framework\DataObject')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $objectMock->expects($this->exactly(2))
+            ->method('getData')
+            ->willReturnMap(
+                [
+                    ['customer', null, $postValue['customer']],
+                    ['address/' . $addressId, null, $postValue['address'][$addressId]],
+                ]
+            );
+
+        $this->objectFactoryMock->expects($this->exactly(2))
+            ->method('create')
+            ->with(['data' => $postValue])
+            ->willReturn($objectMock);
+
+        $customerFormMock = $this->getMockBuilder('Magento\Customer\Model\Metadata\Form')
             ->disableOriginalConstructor()
             ->getMock();
+        $customerFormMock->expects($this->once())
+            ->method('extractData')
+            ->with($this->requestMock, 'customer')
+            ->willReturn($filteredData);
+        $customerFormMock->expects($this->once())
+            ->method('compactData')
+            ->with($dataToCompact)
+            ->willReturn($filteredData);
+        $customerFormMock->expects($this->once())
+            ->method('getAttributes')
+            ->willReturn($attributes);
+
+        $customerAddressFormMock = $this->getMockBuilder('Magento\Customer\Model\Metadata\Form')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $customerAddressFormMock->expects($this->once())
+            ->method('extractData')
+            ->with($this->requestMock, 'address/' . $addressId)
+            ->willReturn($addressFilteredData);
+        $customerAddressFormMock->expects($this->once())
+            ->method('compactData')
+            ->with($addressDataToCompact)
+            ->willReturn($addressFilteredData);
+        $customerAddressFormMock->expects($this->once())
+            ->method('getAttributes')
+            ->willReturn($attributes);
 
         $this->formFactoryMock->expects($this->exactly(2))
             ->method('create')
             ->willReturnMap(
                 [
                     [
-                        \Magento\Customer\Api\CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER,
+                        CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER,
                         'adminhtml_customer',
                         [],
                         false,
-                        \Magento\Customer\Model\Metadata\Form::DONT_IGNORE_INVISIBLE,
+                        Form::DONT_IGNORE_INVISIBLE,
                         [],
-                        $formMock
+                        $customerFormMock
                     ],
                     [
-                        \Magento\Customer\Api\AddressMetadataInterface::ENTITY_TYPE_ADDRESS,
+                        AddressMetadataInterface::ENTITY_TYPE_ADDRESS,
                         'adminhtml_customer_address',
                         [],
                         false,
-                        \Magento\Customer\Model\Metadata\Form::DONT_IGNORE_INVISIBLE,
+                        Form::DONT_IGNORE_INVISIBLE,
                         [],
-                        $formMock
+                        $customerAddressFormMock
                     ],
                 ]
             );
 
-        $formMock->expects($this->exactly(2))
-            ->method('extractData')
-            ->willReturnMap(
-                [
-                    [$this->requestMock, 'customer', true, $filteredData],
-                    [$this->requestMock, 'address/' . $addressId, true, $addressFilteredData],
-                ]
-            );
-
-        /** @var \Magento\Framework\DataObject|\PHPUnit_Framework_MockObject_MockObject $objectMock */
-        $objectMock = $this->getMockBuilder('Magento\Framework\DataObject')
-            ->disableOriginalConstructor()
-            ->getMock();
-
-        $this->objectFactoryMock->expects($this->exactly(2))
-            ->method('create')
-            ->with(['data' => $postValue])
-            ->willReturn($objectMock);
-
-        $objectMock->expects($this->exactly(2))
-            ->method('getData')
-            ->willReturnMap(
-                [
-                    ['customer', null, $postValue['customer']],
-                    ['address/' . $addressId, null, $postValue['address'][$addressId]],
-                ]
-            );
-
-        $formMock->expects($this->exactly(2))
-            ->method('getAttributes')
-            ->willReturn($attributes);
-
-        /** @var \Magento\Customer\Api\Data\CustomerInterface|\PHPUnit_Framework_MockObject_MockObject $customerMock */
+        /** @var CustomerInterface|\PHPUnit_Framework_MockObject_MockObject $customerMock */
         $customerMock = $this->getMockBuilder('Magento\Customer\Api\Data\CustomerInterface')
             ->disableOriginalConstructor()
             ->getMock();
@@ -699,6 +805,16 @@ class SaveTest extends \PHPUnit_Framework_TestCase
             ->method('create')
             ->willReturn($addressMock);
 
+        $this->customerAddressRepositoryMock->expects($this->once())
+            ->method('getById')
+            ->with($addressId)
+            ->willReturn($addressMock);
+
+        $this->customerAddressMapperMock->expects($this->once())
+            ->method('toFlatArray')
+            ->with($addressMock)
+            ->willReturn([]);
+
         $this->dataHelperMock->expects($this->exactly(2))
             ->method('populateWithArray')
             ->willReturnMap(
@@ -753,7 +869,7 @@ class SaveTest extends \PHPUnit_Framework_TestCase
 
         $this->registryMock->expects($this->once())
             ->method('register')
-            ->with(\Magento\Customer\Controller\RegistryConstants::CURRENT_CUSTOMER_ID, $customerId);
+            ->with(RegistryConstants::CURRENT_CUSTOMER_ID, $customerId);
 
         $this->messageManagerMock->expects($this->once())
             ->method('addSuccess')
@@ -800,8 +916,17 @@ class SaveTest extends \PHPUnit_Framework_TestCase
             'coolness' => false,
             'disable_auto_group_change' => 'false',
         ];
+        $dataToCompact = [
+            'coolness' => false,
+            'disable_auto_group_change' => 'false',
+            CustomerInterface::DEFAULT_BILLING => false,
+            CustomerInterface::DEFAULT_SHIPPING => false,
+            'confirmation' => false,
+            'sendemail_store_id' => false,
+            'extension_attributes' => false,
+        ];
 
-        /** @var AttributeMetadataInterface|\PHPUnit_Framework_MockObject_MockObject $formMock */
+        /** @var AttributeMetadataInterface|\PHPUnit_Framework_MockObject_MockObject $customerFormMock */
         $attributeMock = $this->getMockBuilder('Magento\Customer\Api\Data\AttributeMetadataInterface')
             ->disableOriginalConstructor()
             ->getMock();
@@ -813,9 +938,12 @@ class SaveTest extends \PHPUnit_Framework_TestCase
             ->willReturn('int');
         $attributes = [$attributeMock];
 
-        $this->requestMock->expects($this->exactly(2))
+        $this->requestMock->expects($this->any())
             ->method('getPostValue')
-            ->willReturn($postValue);
+            ->willReturnMap([
+                [null, null, $postValue],
+                [CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER, null, $postValue['customer']],
+            ]);
         $this->requestMock->expects($this->exactly(2))
             ->method('getPost')
             ->willReturnMap(
@@ -825,46 +953,46 @@ class SaveTest extends \PHPUnit_Framework_TestCase
                 ]
             );
 
-        /** @var \Magento\Customer\Model\Metadata\Form|\PHPUnit_Framework_MockObject_MockObject $formMock */
-        $formMock = $this->getMockBuilder('Magento\Customer\Model\Metadata\Form')
-            ->disableOriginalConstructor()
-            ->getMock();
-
-        $this->formFactoryMock->expects($this->once())
-            ->method('create')
-            ->with(
-                \Magento\Customer\Api\CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER,
-                'adminhtml_customer',
-                [],
-                false,
-                \Magento\Customer\Model\Metadata\Form::DONT_IGNORE_INVISIBLE
-            )->willReturn($formMock);
-
-        $formMock->expects($this->once())
-            ->method('extractData')
-            ->with($this->requestMock, 'customer')
-            ->willReturn($filteredData);
-
         /** @var \Magento\Framework\DataObject|\PHPUnit_Framework_MockObject_MockObject $objectMock */
         $objectMock = $this->getMockBuilder('Magento\Framework\DataObject')
             ->disableOriginalConstructor()
             ->getMock();
+        $objectMock->expects($this->once())
+            ->method('getData')
+            ->with('customer')
+            ->willReturn($postValue['customer']);
 
         $this->objectFactoryMock->expects($this->once())
             ->method('create')
             ->with(['data' => $postValue])
             ->willReturn($objectMock);
 
-        $objectMock->expects($this->once())
-            ->method('getData')
-            ->with('customer')
-            ->willReturn($postValue['customer']);
-
-        $formMock->expects($this->once())
+        $customerFormMock = $this->getMockBuilder('Magento\Customer\Model\Metadata\Form')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $customerFormMock->expects($this->once())
+            ->method('extractData')
+            ->with($this->requestMock, 'customer')
+            ->willReturn($filteredData);
+        $customerFormMock->expects($this->once())
+            ->method('compactData')
+            ->with($dataToCompact)
+            ->willReturn($filteredData);
+        $customerFormMock->expects($this->once())
             ->method('getAttributes')
             ->willReturn($attributes);
 
-        /** @var \Magento\Customer\Api\Data\CustomerInterface|\PHPUnit_Framework_MockObject_MockObject $customerMock */
+        $this->formFactoryMock->expects($this->once())
+            ->method('create')
+            ->with(
+                CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER,
+                'adminhtml_customer',
+                [],
+                false,
+                Form::DONT_IGNORE_INVISIBLE
+            )->willReturn($customerFormMock);
+
+        /** @var CustomerInterface|\PHPUnit_Framework_MockObject_MockObject $customerMock */
         $customerMock = $this->getMockBuilder('Magento\Customer\Api\Data\CustomerInterface')
             ->disableOriginalConstructor()
             ->getMock();
@@ -940,8 +1068,17 @@ class SaveTest extends \PHPUnit_Framework_TestCase
             'coolness' => false,
             'disable_auto_group_change' => 'false',
         ];
+        $dataToCompact = [
+            'coolness' => false,
+            'disable_auto_group_change' => 'false',
+            CustomerInterface::DEFAULT_BILLING => false,
+            CustomerInterface::DEFAULT_SHIPPING => false,
+            'confirmation' => false,
+            'sendemail_store_id' => false,
+            'extension_attributes' => false,
+        ];
 
-        /** @var AttributeMetadataInterface|\PHPUnit_Framework_MockObject_MockObject $formMock */
+        /** @var AttributeMetadataInterface|\PHPUnit_Framework_MockObject_MockObject $customerFormMock */
         $attributeMock = $this->getMockBuilder('Magento\Customer\Api\Data\AttributeMetadataInterface')
             ->disableOriginalConstructor()
             ->getMock();
@@ -953,9 +1090,12 @@ class SaveTest extends \PHPUnit_Framework_TestCase
             ->willReturn('int');
         $attributes = [$attributeMock];
 
-        $this->requestMock->expects($this->exactly(2))
+        $this->requestMock->expects($this->any())
             ->method('getPostValue')
-            ->willReturn($postValue);
+            ->willReturnMap([
+                [null, null, $postValue],
+                [CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER, null, $postValue['customer']],
+            ]);
         $this->requestMock->expects($this->exactly(2))
             ->method('getPost')
             ->willReturnMap(
@@ -965,46 +1105,46 @@ class SaveTest extends \PHPUnit_Framework_TestCase
                 ]
             );
 
-        /** @var \Magento\Customer\Model\Metadata\Form|\PHPUnit_Framework_MockObject_MockObject $formMock */
-        $formMock = $this->getMockBuilder('Magento\Customer\Model\Metadata\Form')
-            ->disableOriginalConstructor()
-            ->getMock();
-
-        $this->formFactoryMock->expects($this->once())
-            ->method('create')
-            ->with(
-                \Magento\Customer\Api\CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER,
-                'adminhtml_customer',
-                [],
-                false,
-                \Magento\Customer\Model\Metadata\Form::DONT_IGNORE_INVISIBLE
-            )->willReturn($formMock);
-
-        $formMock->expects($this->once())
-            ->method('extractData')
-            ->with($this->requestMock, 'customer')
-            ->willReturn($filteredData);
-
         /** @var \Magento\Framework\DataObject|\PHPUnit_Framework_MockObject_MockObject $objectMock */
         $objectMock = $this->getMockBuilder('Magento\Framework\DataObject')
             ->disableOriginalConstructor()
             ->getMock();
+        $objectMock->expects($this->once())
+            ->method('getData')
+            ->with('customer')
+            ->willReturn($postValue['customer']);
 
         $this->objectFactoryMock->expects($this->once())
             ->method('create')
             ->with(['data' => $postValue])
             ->willReturn($objectMock);
 
-        $objectMock->expects($this->once())
-            ->method('getData')
-            ->with('customer')
-            ->willReturn($postValue['customer']);
-
-        $formMock->expects($this->once())
+        /** @var Form|\PHPUnit_Framework_MockObject_MockObject $formMock */
+        $customerFormMock = $this->getMockBuilder('Magento\Customer\Model\Metadata\Form')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $customerFormMock->expects($this->once())
+            ->method('extractData')
+            ->with($this->requestMock, 'customer')
+            ->willReturn($filteredData);
+        $customerFormMock->expects($this->once())
+            ->method('compactData')
+            ->with($dataToCompact)
+            ->willReturn($filteredData);
+        $customerFormMock->expects($this->once())
             ->method('getAttributes')
             ->willReturn($attributes);
 
-        /** @var \Magento\Customer\Api\Data\CustomerInterface|\PHPUnit_Framework_MockObject_MockObject $customerMock */
+        $this->formFactoryMock->expects($this->once())
+            ->method('create')
+            ->with(
+                CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER,
+                'adminhtml_customer',
+                [],
+                false,
+                Form::DONT_IGNORE_INVISIBLE
+            )->willReturn($customerFormMock);
+
         $customerMock = $this->getMockBuilder('Magento\Customer\Api\Data\CustomerInterface')
             ->disableOriginalConstructor()
             ->getMock();
@@ -1080,8 +1220,17 @@ class SaveTest extends \PHPUnit_Framework_TestCase
             'coolness' => false,
             'disable_auto_group_change' => 'false',
         ];
+        $dataToCompact = [
+            'coolness' => false,
+            'disable_auto_group_change' => 'false',
+            CustomerInterface::DEFAULT_BILLING => false,
+            CustomerInterface::DEFAULT_SHIPPING => false,
+            'confirmation' => false,
+            'sendemail_store_id' => false,
+            'extension_attributes' => false,
+        ];
 
-        /** @var AttributeMetadataInterface|\PHPUnit_Framework_MockObject_MockObject $formMock */
+        /** @var AttributeMetadataInterface|\PHPUnit_Framework_MockObject_MockObject $customerFormMock */
         $attributeMock = $this->getMockBuilder('Magento\Customer\Api\Data\AttributeMetadataInterface')
             ->disableOriginalConstructor()
             ->getMock();
@@ -1093,9 +1242,12 @@ class SaveTest extends \PHPUnit_Framework_TestCase
             ->willReturn('int');
         $attributes = [$attributeMock];
 
-        $this->requestMock->expects($this->exactly(2))
+        $this->requestMock->expects($this->any())
             ->method('getPostValue')
-            ->willReturn($postValue);
+            ->willReturnMap([
+                [null, null, $postValue],
+                [CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER, null, $postValue['customer']],
+            ]);
         $this->requestMock->expects($this->exactly(2))
             ->method('getPost')
             ->willReturnMap(
@@ -1105,46 +1257,46 @@ class SaveTest extends \PHPUnit_Framework_TestCase
                 ]
             );
 
-        /** @var \Magento\Customer\Model\Metadata\Form|\PHPUnit_Framework_MockObject_MockObject $formMock */
-        $formMock = $this->getMockBuilder('Magento\Customer\Model\Metadata\Form')
-            ->disableOriginalConstructor()
-            ->getMock();
-
-        $this->formFactoryMock->expects($this->once())
-            ->method('create')
-            ->with(
-                \Magento\Customer\Api\CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER,
-                'adminhtml_customer',
-                [],
-                false,
-                \Magento\Customer\Model\Metadata\Form::DONT_IGNORE_INVISIBLE
-            )->willReturn($formMock);
-
-        $formMock->expects($this->once())
-            ->method('extractData')
-            ->with($this->requestMock, 'customer')
-            ->willReturn($filteredData);
-
         /** @var \Magento\Framework\DataObject|\PHPUnit_Framework_MockObject_MockObject $objectMock */
         $objectMock = $this->getMockBuilder('Magento\Framework\DataObject')
             ->disableOriginalConstructor()
             ->getMock();
+        $objectMock->expects($this->once())
+            ->method('getData')
+            ->with('customer')
+            ->willReturn($postValue['customer']);
 
         $this->objectFactoryMock->expects($this->once())
             ->method('create')
             ->with(['data' => $postValue])
             ->willReturn($objectMock);
 
-        $objectMock->expects($this->once())
-            ->method('getData')
-            ->with('customer')
-            ->willReturn($postValue['customer']);
-
-        $formMock->expects($this->once())
+        $customerFormMock = $this->getMockBuilder('Magento\Customer\Model\Metadata\Form')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $customerFormMock->expects($this->once())
+            ->method('extractData')
+            ->with($this->requestMock, 'customer')
+            ->willReturn($filteredData);
+        $customerFormMock->expects($this->once())
+            ->method('compactData')
+            ->with($dataToCompact)
+            ->willReturn($filteredData);
+        $customerFormMock->expects($this->once())
             ->method('getAttributes')
             ->willReturn($attributes);
 
-        /** @var \Magento\Customer\Api\Data\CustomerInterface|\PHPUnit_Framework_MockObject_MockObject $customerMock */
+        $this->formFactoryMock->expects($this->once())
+            ->method('create')
+            ->with(
+                CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER,
+                'adminhtml_customer',
+                [],
+                false,
+                Form::DONT_IGNORE_INVISIBLE
+            )->willReturn($customerFormMock);
+
+        /** @var CustomerInterface|\PHPUnit_Framework_MockObject_MockObject $customerMock */
         $customerMock = $this->getMockBuilder('Magento\Customer\Api\Data\CustomerInterface')
             ->disableOriginalConstructor()
             ->getMock();
diff --git a/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/Index/ValidateTest.php b/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/Index/ValidateTest.php
index 979d41c13bfc50663e051438b337c3adfdce03e9..8ac75a637b8f87dc859c49c2e88419495379b469 100644
--- a/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/Index/ValidateTest.php
+++ b/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/Index/ValidateTest.php
@@ -169,10 +169,6 @@ class ValidateTest extends \PHPUnit_Framework_TestCase
             ->method('validateData')
             ->willReturn([$error]);
 
-        $this->extensibleDataObjectConverter->expects($this->once())
-            ->method('toFlatArray')
-            ->willReturn([]);
-
         $validationResult = $this->getMockForAbstractClass(
             'Magento\Customer\Api\Data\ValidationResultsInterface',
             [],
@@ -208,10 +204,6 @@ class ValidateTest extends \PHPUnit_Framework_TestCase
             ->method('validateData')
             ->willReturn([$error]);
 
-        $this->extensibleDataObjectConverter->expects($this->once())
-            ->method('toFlatArray')
-            ->willReturn([]);
-
         $validationResult = $this->getMockForAbstractClass(
             'Magento\Customer\Api\Data\ValidationResultsInterface',
             [],
@@ -245,10 +237,6 @@ class ValidateTest extends \PHPUnit_Framework_TestCase
         $this->form->expects($this->never())
             ->method('validateData');
 
-        $this->extensibleDataObjectConverter->expects($this->once())
-            ->method('toFlatArray')
-            ->willReturn([]);
-
         $validationResult = $this->getMockForAbstractClass(
             'Magento\Customer\Api\Data\ValidationResultsInterface',
             [],
diff --git a/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/Index/ViewfileTest.php b/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/Index/ViewfileTest.php
index 3586651d269d0821264af27191e4e4a5517ea79d..0cc2ca730379753f6b96046656f422d258ed485f 100644
--- a/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/Index/ViewfileTest.php
+++ b/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/Index/ViewfileTest.php
@@ -169,7 +169,7 @@ class ViewfileTest extends \PHPUnit_Framework_TestCase
             ->willReturnMap([['file', null, null], ['image', null, $decodedFile]]);
 
         $this->directoryMock->expects($this->once())->method('getAbsolutePath')->with($fileName)->willReturn($path);
-        $this->directoryMock->expects($this->once())->method('stat')->with($path)->willReturn($stat);
+        $this->directoryMock->expects($this->once())->method('stat')->with($fileName)->willReturn($stat);
 
         $this->fileSystemMock->expects($this->once())->method('getDirectoryRead')
             ->with(\Magento\Framework\App\Filesystem\DirectoryList::MEDIA)
diff --git a/app/code/Magento/Customer/Test/Unit/Model/Customer/DataProviderTest.php b/app/code/Magento/Customer/Test/Unit/Model/Customer/DataProviderTest.php
index 8627a4737d614ae5e5472837a707da058a93b6fc..8a9e48bd889d0c04ec91e54c231dcfa8d83f3854 100644
--- a/app/code/Magento/Customer/Test/Unit/Model/Customer/DataProviderTest.php
+++ b/app/code/Magento/Customer/Test/Unit/Model/Customer/DataProviderTest.php
@@ -5,12 +5,12 @@
  */
 namespace Magento\Customer\Test\Unit\Model\Customer;
 
+use Magento\Customer\Api\CustomerMetadataInterface;
 use Magento\Eav\Model\Config;
 use Magento\Eav\Model\Entity\Type;
 use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
 use Magento\Ui\Component\Form\Field;
 use Magento\Ui\DataProvider\EavValidationRules;
-use Magento\Customer\Model\Customer\DataProvider;
 use Magento\Eav\Model\Entity\Attribute\AbstractAttribute;
 use Magento\Customer\Model\ResourceModel\Customer\CollectionFactory;
 
@@ -44,6 +44,16 @@ class DataProviderTest extends \PHPUnit_Framework_TestCase
      */
     protected $sessionMock;
 
+    /**
+     * @var \Magento\Customer\Model\FileProcessorFactory|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $fileProcessorFactory;
+
+    /**
+     * @var \Magento\Customer\Model\FileProcessor|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $fileProcessor;
+
     /**
      * Set up
      *
@@ -69,6 +79,15 @@ class DataProviderTest extends \PHPUnit_Framework_TestCase
             ->getMockBuilder('Magento\Framework\Session\SessionManagerInterface')
             ->setMethods(['getCustomerFormData', 'unsCustomerFormData'])
             ->getMockForAbstractClass();
+
+        $this->fileProcessor = $this->getMockBuilder('Magento\Customer\Model\FileProcessor')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->fileProcessorFactory = $this->getMockBuilder('Magento\Customer\Model\FileProcessorFactory')
+            ->disableOriginalConstructor()
+            ->setMethods(['create'])
+            ->getMock();
     }
 
     /**
@@ -94,6 +113,12 @@ class DataProviderTest extends \PHPUnit_Framework_TestCase
             ]
         );
 
+        $helper->setBackwardCompatibleProperty(
+            $dataProvider,
+            'fileProcessorFactory',
+            $this->fileProcessorFactory
+        );
+
         $meta = $dataProvider->getMeta();
         $this->assertNotEmpty($meta);
         $this->assertEquals($expected, $meta);
@@ -318,7 +343,7 @@ class DataProviderTest extends \PHPUnit_Framework_TestCase
         $attributeBooleanMock->expects($this->exactly(2))
             ->method('getAttributeCode')
             ->willReturn('test-code-boolean');
-        $attributeBooleanMock->expects($this->once())
+        $attributeBooleanMock->expects($this->any())
             ->method('getFrontendInput')
             ->willReturn('boolean');
         $attributeBooleanMock->expects($this->any())
@@ -375,6 +400,10 @@ class DataProviderTest extends \PHPUnit_Framework_TestCase
         $customer->expects($this->once())
             ->method('getAddresses')
             ->willReturn([$address]);
+        $customer->expects($this->once())
+            ->method('getAttributes')
+            ->willReturn([]);
+
         $address->expects($this->atLeastOnce())
             ->method('getId')
             ->willReturn(2);
@@ -389,6 +418,9 @@ class DataProviderTest extends \PHPUnit_Framework_TestCase
                 'lastname' => 'lastname',
                 'street' => "street\nstreet",
             ]);
+        $address->expects($this->once())
+            ->method('getAttributes')
+            ->willReturn([]);
 
         $helper = new ObjectManager($this);
         $dataProvider = $helper->getObject(
@@ -412,6 +444,12 @@ class DataProviderTest extends \PHPUnit_Framework_TestCase
             ->method('getCustomerFormData')
             ->willReturn(null);
 
+        $helper->setBackwardCompatibleProperty(
+            $dataProvider,
+            'fileProcessorFactory',
+            $this->fileProcessorFactory
+        );
+
         $this->assertEquals(
             [
                 '' => [
@@ -496,6 +534,10 @@ class DataProviderTest extends \PHPUnit_Framework_TestCase
         $customer->expects($this->once())
             ->method('getAddresses')
             ->willReturn([$address]);
+        $customer->expects($this->once())
+            ->method('getAttributes')
+            ->willReturn([]);
+
         $address->expects($this->atLeastOnce())
             ->method('getId')
             ->willReturn(2);
@@ -510,6 +552,9 @@ class DataProviderTest extends \PHPUnit_Framework_TestCase
                 'lastname' => 'lastname',
                 'street' => "street\nstreet",
             ]);
+        $address->expects($this->once())
+            ->method('getAttributes')
+            ->willReturn([]);
 
         $helper = new ObjectManager($this);
         $dataProvider = $helper->getObject(
@@ -535,6 +580,378 @@ class DataProviderTest extends \PHPUnit_Framework_TestCase
         $this->sessionMock->expects($this->once())
             ->method('unsCustomerFormData');
 
+        $helper->setBackwardCompatibleProperty(
+            $dataProvider,
+            'fileProcessorFactory',
+            $this->fileProcessorFactory
+        );
+
         $this->assertEquals([$customerId => $customerFormData], $dataProvider->getData());
     }
+
+    public function testGetDataWithCustomAttributeImage()
+    {
+        $customerId = 1;
+        $customerEmail = 'user1@example.com';
+
+        $filename = '/filename.ext1';
+        $viewUrl = 'viewUrl';
+
+        $expectedData = [
+            $customerId => [
+                'customer' => [
+                    'email' => $customerEmail,
+                    'img1' => [
+                        [
+                            'file' => $filename,
+                            'size' => 1,
+                            'url' => $viewUrl,
+                            'name' => 'filename.ext1',
+                        ],
+                    ],
+                ],
+            ],
+        ];
+
+        $attributeMock = $this->getMockBuilder('Magento\Customer\Model\Attribute')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $attributeMock->expects($this->exactly(2))
+            ->method('getFrontendInput')
+            ->willReturn('image');
+        $attributeMock->expects($this->exactly(2))
+            ->method('getAttributeCode')
+            ->willReturn('img1');
+
+        $entityTypeMock = $this->getMockBuilder('Magento\Eav\Model\Entity\Type')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $entityTypeMock->expects($this->once())
+            ->method('getEntityTypeCode')
+            ->willReturn(CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER);
+
+        $customerMock = $this->getMockBuilder('Magento\Customer\Model\Customer')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $customerMock->expects($this->once())
+            ->method('getData')
+            ->willReturn([
+                'email' => $customerEmail,
+                'img1' => $filename,
+            ]);
+        $customerMock->expects($this->once())
+            ->method('getAddresses')
+            ->willReturn([]);
+        $customerMock->expects($this->once())
+            ->method('getId')
+            ->willReturn($customerId);
+        $customerMock->expects($this->once())
+            ->method('getAttributes')
+            ->willReturn([$attributeMock]);
+        $customerMock->expects($this->once())
+            ->method('getEntityType')
+            ->willReturn($entityTypeMock);
+
+        $collectionMock = $this->getMockBuilder('Magento\Customer\Model\ResourceModel\Customer\Collection')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $collectionMock->expects($this->once())
+            ->method('getItems')
+            ->willReturn([$customerMock]);
+
+        $this->customerCollectionFactoryMock->expects($this->once())
+            ->method('create')
+            ->willReturn($collectionMock);
+
+        $this->sessionMock->expects($this->once())
+            ->method('getCustomerFormData')
+            ->willReturn([]);
+
+        $this->fileProcessorFactory->expects($this->any())
+            ->method('create')
+            ->with([
+                'entityTypeCode' => CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER,
+            ])
+            ->willReturn($this->fileProcessor);
+
+        $this->fileProcessor->expects($this->once())
+            ->method('isExist')
+            ->with($filename)
+            ->willReturn(true);
+        $this->fileProcessor->expects($this->once())
+            ->method('getStat')
+            ->with($filename)
+            ->willReturn(['size' => 1]);
+        $this->fileProcessor->expects($this->once())
+            ->method('getViewUrl')
+            ->with('/filename.ext1', 'image')
+            ->willReturn($viewUrl);
+
+        $objectManager = new ObjectManager($this);
+        $dataProvider = $objectManager->getObject(
+            '\Magento\Customer\Model\Customer\DataProvider',
+            [
+                'name' => 'test-name',
+                'primaryFieldName' => 'primary-field-name',
+                'requestFieldName' => 'request-field-name',
+                'eavValidationRules' => $this->eavValidationRulesMock,
+                'customerCollectionFactory' => $this->customerCollectionFactoryMock,
+                'eavConfig' => $this->getEavConfigMock()
+            ]
+        );
+
+        $objectManager->setBackwardCompatibleProperty(
+            $dataProvider,
+            'session',
+            $this->sessionMock
+        );
+
+        $objectManager->setBackwardCompatibleProperty(
+            $dataProvider,
+            'fileProcessorFactory',
+            $this->fileProcessorFactory
+        );
+
+        $this->assertEquals($expectedData, $dataProvider->getData());
+    }
+
+    public function testGetDataWithCustomAttributeImageNoData()
+    {
+        $customerId = 1;
+        $customerEmail = 'user1@example.com';
+
+        $expectedData = [
+            $customerId => [
+                'customer' => [
+                    'email' => $customerEmail,
+                    'img1' => [],
+                ],
+            ],
+        ];
+
+        $attributeMock = $this->getMockBuilder('Magento\Customer\Model\Attribute')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $attributeMock->expects($this->once())
+            ->method('getFrontendInput')
+            ->willReturn('image');
+        $attributeMock->expects($this->exactly(2))
+            ->method('getAttributeCode')
+            ->willReturn('img1');
+
+        $entityTypeMock = $this->getMockBuilder('Magento\Eav\Model\Entity\Type')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $entityTypeMock->expects($this->once())
+            ->method('getEntityTypeCode')
+            ->willReturn(CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER);
+
+        $customerMock = $this->getMockBuilder('Magento\Customer\Model\Customer')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $customerMock->expects($this->once())
+            ->method('getData')
+            ->willReturn([
+                'email' => $customerEmail,
+            ]);
+        $customerMock->expects($this->once())
+            ->method('getAddresses')
+            ->willReturn([]);
+        $customerMock->expects($this->once())
+            ->method('getId')
+            ->willReturn($customerId);
+        $customerMock->expects($this->once())
+            ->method('getAttributes')
+            ->willReturn([$attributeMock]);
+        $customerMock->expects($this->once())
+            ->method('getEntityType')
+            ->willReturn($entityTypeMock);
+
+        $collectionMock = $this->getMockBuilder('Magento\Customer\Model\ResourceModel\Customer\Collection')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $collectionMock->expects($this->once())
+            ->method('getItems')
+            ->willReturn([$customerMock]);
+
+        $this->customerCollectionFactoryMock->expects($this->once())
+            ->method('create')
+            ->willReturn($collectionMock);
+
+        $this->sessionMock->expects($this->once())
+            ->method('getCustomerFormData')
+            ->willReturn([]);
+
+        $objectManager = new ObjectManager($this);
+        $dataProvider = $objectManager->getObject(
+            '\Magento\Customer\Model\Customer\DataProvider',
+            [
+                'name' => 'test-name',
+                'primaryFieldName' => 'primary-field-name',
+                'requestFieldName' => 'request-field-name',
+                'eavValidationRules' => $this->eavValidationRulesMock,
+                'customerCollectionFactory' => $this->customerCollectionFactoryMock,
+                'eavConfig' => $this->getEavConfigMock()
+            ]
+        );
+
+        $objectManager->setBackwardCompatibleProperty(
+            $dataProvider,
+            'session',
+            $this->sessionMock
+        );
+
+        $objectManager->setBackwardCompatibleProperty(
+            $dataProvider,
+            'fileProcessorFactory',
+            $this->fileProcessorFactory
+        );
+
+        $this->assertEquals($expectedData, $dataProvider->getData());
+    }
+
+    public function testGetAttributesMetaWithCustomAttributeImage()
+    {
+        $maxFileSize = 1000;
+        $allowedExtension = 'ext1 ext2';
+
+        $attributeCode = 'img1';
+
+        $collectionMock = $this->getMockBuilder('Magento\Customer\Model\ResourceModel\Customer\Collection')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $collectionMock->expects($this->once())
+            ->method('addAttributeToSelect')
+            ->with('*');
+
+        $this->customerCollectionFactoryMock->expects($this->once())
+            ->method('create')
+            ->willReturn($collectionMock);
+
+        $attributeMock = $this->getMockBuilder('Magento\Eav\Model\Entity\Attribute\AbstractAttribute')
+            ->setMethods([
+                'getAttributeCode',
+                'getFrontendInput',
+                'getDataUsingMethod',
+            ])
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+        $attributeMock->expects($this->any())
+            ->method('getAttributeCode')
+            ->willReturn($attributeCode);
+        $attributeMock->expects($this->any())
+            ->method('getFrontendInput')
+            ->willReturn('image');
+        $attributeMock->expects($this->any())
+            ->method('getDataUsingMethod')
+            ->willReturnCallback(
+                function ($origName) {
+                    return $origName;
+                }
+            );
+
+        $typeCustomerMock = $this->getMockBuilder('Magento\Eav\Model\Entity\Type')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $typeCustomerMock->expects($this->once())
+            ->method('getAttributeCollection')
+            ->willReturn([$attributeMock]);
+        $typeCustomerMock->expects($this->once())
+            ->method('getEntityTypeCode')
+            ->willReturn(CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER);
+
+        $typeAddressMock = $this->getMockBuilder('Magento\Eav\Model\Entity\Type')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $typeAddressMock->expects($this->once())
+            ->method('getAttributeCollection')
+            ->willReturn([]);
+
+        $this->eavConfigMock->expects($this->at(0))
+            ->method('getEntityType')
+            ->with('customer')
+            ->willReturn($typeCustomerMock);
+        $this->eavConfigMock->expects($this->at(1))
+            ->method('getEntityType')
+            ->with('customer_address')
+            ->willReturn($typeAddressMock);
+
+        $this->eavValidationRulesMock->expects($this->once())
+            ->method('build')
+            ->with($attributeMock, [
+                'dataType' => 'frontend_input',
+                'formElement' => 'frontend_input',
+                'visible' => 'is_visible',
+                'required' => 'is_required',
+                'sortOrder' => 'sort_order',
+                'notice' => 'note',
+                'default' => 'default_value',
+                'size' => 'multiline_count',
+                'label' => __('frontend_label'),
+            ])
+            ->willReturn([
+                'max_file_size' => $maxFileSize,
+                'file_extensions' => 'ext1, eXt2 ', // Added spaces and upper-cases
+            ]);
+
+        $this->fileProcessorFactory->expects($this->any())
+            ->method('create')
+            ->with([
+                'entityTypeCode' => CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER,
+            ])
+            ->willReturn($this->fileProcessor);
+
+        $objectManager = new ObjectManager($this);
+        $dataProvider = $objectManager->getObject(
+            '\Magento\Customer\Model\Customer\DataProvider',
+            [
+                'name' => 'test-name',
+                'primaryFieldName' => 'primary-field-name',
+                'requestFieldName' => 'request-field-name',
+                'eavValidationRules' => $this->eavValidationRulesMock,
+                'customerCollectionFactory' => $this->customerCollectionFactoryMock,
+                'eavConfig' => $this->eavConfigMock,
+                'fileProcessorFactory' => $this->fileProcessorFactory,
+            ]
+        );
+
+        $result = $dataProvider->getMeta();
+
+        $this->assertNotEmpty($result);
+
+        $expected = [
+            'customer' => [
+                'children' => [
+                    $attributeCode => [
+                        'arguments' => [
+                            'data' => [
+                                'config' => [
+                                    'formElement' => 'fileUploader',
+                                    'componentType' => 'fileUploader',
+                                    'maxFileSize' => $maxFileSize,
+                                    'allowedExtensions' => $allowedExtension,
+                                    'uploaderConfig' => [
+                                        'url' => 'customer/file/customer_upload',
+                                    ],
+                                    'sortOrder' => 'sort_order',
+                                    'required' => 'is_required',
+                                    'visible' => 'is_visible',
+                                    'validation' => [
+                                        'max_file_size' => $maxFileSize,
+                                        'file_extensions' => 'ext1, eXt2 ',
+                                    ],
+                                    'label' => __('frontend_label'),
+                                ],
+                            ],
+                        ],
+                    ],
+                ],
+            ],
+            'address' => [
+                'children' => [],
+            ],
+        ];
+
+        $this->assertEquals($expected, $result);
+    }
 }
diff --git a/app/code/Magento/Customer/Test/Unit/Model/CustomerExtractorTest.php b/app/code/Magento/Customer/Test/Unit/Model/CustomerExtractorTest.php
index c414d648b21728edf5a49314edaa5f2397a12c61..5f112188d4387e43bf5e14f09f1c48a94c081964 100644
--- a/app/code/Magento/Customer/Test/Unit/Model/CustomerExtractorTest.php
+++ b/app/code/Magento/Customer/Test/Unit/Model/CustomerExtractorTest.php
@@ -120,6 +120,10 @@ class CustomerExtractorTest extends \PHPUnit_Framework_TestCase
             ->method('extractData')
             ->with($this->request)
             ->willReturn($customerData);
+        $this->customerForm->expects($this->once())
+            ->method('compactData')
+            ->with($customerData)
+            ->willReturn($customerData);
         $this->customerForm->expects($this->once())
             ->method('getAllowedAttributes')
             ->willReturn(['group_id' => 'attribute object']);
diff --git a/app/code/Magento/Customer/Test/Unit/Model/FileProcessorTest.php b/app/code/Magento/Customer/Test/Unit/Model/FileProcessorTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..b25aa7c4dc89fd319e809cabf1d82726230eec03
--- /dev/null
+++ b/app/code/Magento/Customer/Test/Unit/Model/FileProcessorTest.php
@@ -0,0 +1,380 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Customer\Test\Unit\Model;
+
+use Magento\Customer\Api\AddressMetadataInterface;
+use Magento\Customer\Api\CustomerMetadataInterface;
+use Magento\Customer\Model\FileProcessor;
+use Magento\Framework\App\Filesystem\DirectoryList;
+
+class FileProcessorTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\Framework\Filesystem|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $filesystem;
+
+    /**
+     * @var \Magento\MediaStorage\Model\File\UploaderFactory|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $uploaderFactory;
+
+    /**
+     * @var \Magento\Framework\UrlInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $urlBuilder;
+
+    /**
+     * @var \Magento\Framework\Url\EncoderInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $urlEncoder;
+
+    /**
+     * @var \Magento\Framework\Filesystem\Directory\WriteInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $mediaDirectory;
+
+    protected function setUp()
+    {
+        $this->mediaDirectory = $this->getMockBuilder('Magento\Framework\Filesystem\Directory\WriteInterface')
+            ->getMockForAbstractClass();
+
+        $this->filesystem = $this->getMockBuilder('Magento\Framework\Filesystem')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->filesystem->expects($this->any())
+            ->method('getDirectoryWrite')
+            ->with(DirectoryList::MEDIA)
+            ->willReturn($this->mediaDirectory);
+
+        $this->uploaderFactory = $this->getMockBuilder('Magento\MediaStorage\Model\File\UploaderFactory')
+            ->setMethods(['create'])
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->urlBuilder = $this->getMockBuilder('Magento\Framework\UrlInterface')
+            ->getMockForAbstractClass();
+
+        $this->urlEncoder = $this->getMockBuilder('Magento\Framework\Url\EncoderInterface')
+            ->getMockForAbstractClass();
+    }
+
+    private function getModel($entityTypeCode, array $allowedExtensions = [])
+    {
+        $model = new FileProcessor(
+            $this->filesystem,
+            $this->uploaderFactory,
+            $this->urlBuilder,
+            $this->urlEncoder,
+            $entityTypeCode,
+            $allowedExtensions
+        );
+        return $model;
+    }
+
+
+    public function testGetStat()
+    {
+        $fileName = '/filename.ext1';
+
+        $this->mediaDirectory->expects($this->once())
+            ->method('stat')
+            ->with(CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER . $fileName)
+            ->willReturn(['size' => 1]);
+
+        $model = $this->getModel(CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER);
+        $result = $model->getStat($fileName);
+
+        $this->assertTrue(is_array($result));
+        $this->assertArrayHasKey('size', $result);
+        $this->assertEquals(1, $result['size']);
+    }
+
+    public function testIsExist()
+    {
+        $fileName = '/filename.ext1';
+
+        $this->mediaDirectory->expects($this->once())
+            ->method('isExist')
+            ->with(CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER . $fileName)
+            ->willReturn(true);
+
+        $model = $this->getModel(CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER);
+        $this->assertTrue($model->isExist($fileName));
+    }
+
+    public function testGetViewUrlCustomer()
+    {
+        $filePath = 'filename.ext1';
+        $encodedFilePath = 'encodedfilenameext1';
+
+        $fileUrl = 'fileUrl';
+
+        $this->urlEncoder->expects($this->once())
+            ->method('encode')
+            ->with($filePath)
+            ->willReturn($encodedFilePath);
+
+        $this->urlBuilder->expects($this->once())
+            ->method('getUrl')
+            ->with('customer/index/viewfile', ['image' => $encodedFilePath])
+            ->willReturn($fileUrl);
+
+        $model = $this->getModel(CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER);
+        $this->assertEquals($fileUrl, $model->getViewUrl($filePath, 'image'));
+    }
+
+    public function testGetViewUrlCustomerAddress()
+    {
+        $filePath = 'filename.ext1';
+
+        $baseUrl = 'baseUrl';
+        $relativeUrl = 'relativeUrl';
+
+        $this->urlBuilder->expects($this->once())
+            ->method('getBaseUrl')
+            ->with(['_type' => \Magento\Framework\UrlInterface::URL_TYPE_MEDIA])
+            ->willReturn($baseUrl);
+
+        $this->mediaDirectory->expects($this->once())
+            ->method('getRelativePath')
+            ->with(AddressMetadataInterface::ENTITY_TYPE_ADDRESS . '/' . $filePath)
+            ->willReturn($relativeUrl);
+
+        $model = $this->getModel(AddressMetadataInterface::ENTITY_TYPE_ADDRESS);
+        $this->assertEquals($baseUrl . $relativeUrl, $model->getViewUrl($filePath, 'image'));
+    }
+
+    public function testRemoveUploadedFile()
+    {
+        $fileName = '/filename.ext1';
+
+        $this->mediaDirectory->expects($this->once())
+            ->method('delete')
+            ->with(CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER . $fileName)
+            ->willReturn(true);
+
+        $model = $this->getModel(CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER);
+        $this->assertTrue($model->removeUploadedFile($fileName));
+    }
+
+    public function testSaveTemporaryFile()
+    {
+        $attributeCode = 'img1';
+
+        $allowedExtensions = [
+            'ext1',
+            'ext2',
+        ];
+
+        $absolutePath = '/absolute/filepath';
+
+        $expectedResult = [
+            'file' => 'filename.ext1',
+            'path' => 'filepath',
+        ];
+
+        $uploaderMock = $this->getMockBuilder('Magento\MediaStorage\Model\File\Uploader')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $uploaderMock->expects($this->once())
+            ->method('setFilesDispersion')
+            ->with(false)
+            ->willReturnSelf();
+        $uploaderMock->expects($this->once())
+            ->method('setFilenamesCaseSensitivity')
+            ->with(false)
+            ->willReturnSelf();
+        $uploaderMock->expects($this->once())
+            ->method('setAllowRenameFiles')
+            ->with(true)
+            ->willReturnSelf();
+        $uploaderMock->expects($this->once())
+            ->method('setAllowedExtensions')
+            ->with($allowedExtensions)
+            ->willReturnSelf();
+        $uploaderMock->expects($this->once())
+            ->method('save')
+            ->with($absolutePath)
+            ->willReturn($expectedResult);
+
+        $this->uploaderFactory->expects($this->once())
+            ->method('create')
+            ->with(['fileId' => 'customer[' . $attributeCode . ']'])
+            ->willReturn($uploaderMock);
+
+        $this->mediaDirectory->expects($this->once())
+            ->method('getAbsolutePath')
+            ->with(CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER . '/' . FileProcessor::TMP_DIR)
+            ->willReturn($absolutePath);
+
+        $model = $this->getModel(CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER, $allowedExtensions);
+        $result = $model->saveTemporaryFile('customer[' . $attributeCode . ']');
+
+        $this->assertEquals($expectedResult, $result);
+    }
+
+    /**
+     * @expectedException \Magento\Framework\Exception\LocalizedException
+     * @expectedExceptionMessage File can not be saved to the destination folder.
+     */
+    public function testSaveTemporaryFileWithError()
+    {
+        $attributeCode = 'img1';
+
+        $allowedExtensions = [
+            'ext1',
+            'ext2',
+        ];
+
+        $absolutePath = '/absolute/filepath';
+
+        $uploaderMock = $this->getMockBuilder('Magento\MediaStorage\Model\File\Uploader')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $uploaderMock->expects($this->once())
+            ->method('setFilesDispersion')
+            ->with(false)
+            ->willReturnSelf();
+        $uploaderMock->expects($this->once())
+            ->method('setFilenamesCaseSensitivity')
+            ->with(false)
+            ->willReturnSelf();
+        $uploaderMock->expects($this->once())
+            ->method('setAllowRenameFiles')
+            ->with(true)
+            ->willReturnSelf();
+        $uploaderMock->expects($this->once())
+            ->method('setAllowedExtensions')
+            ->with($allowedExtensions)
+            ->willReturnSelf();
+        $uploaderMock->expects($this->once())
+            ->method('save')
+            ->with($absolutePath)
+            ->willReturn(false);
+
+        $this->uploaderFactory->expects($this->once())
+            ->method('create')
+            ->with(['fileId' => 'customer[' . $attributeCode . ']'])
+            ->willReturn($uploaderMock);
+
+        $this->mediaDirectory->expects($this->once())
+            ->method('getAbsolutePath')
+            ->with(CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER . '/' . FileProcessor::TMP_DIR)
+            ->willReturn($absolutePath);
+
+        $model = $this->getModel(CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER, $allowedExtensions);
+        $model->saveTemporaryFile('customer[' . $attributeCode . ']');
+    }
+
+    /**
+     * @expectedException \Magento\Framework\Exception\LocalizedException
+     * @expectedExceptionMessage Unable to create directory customer/f/i
+     */
+    public function testMoveTemporaryFileUnableToCreateDirectory()
+    {
+        $filePath = '/filename.ext1';
+
+        $destinationPath = 'customer/f/i';
+
+        $this->mediaDirectory->expects($this->once())
+            ->method('create')
+            ->with($destinationPath)
+            ->willReturn(false);
+
+        $model = $this->getModel(CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER);
+        $model->moveTemporaryFile($filePath);
+    }
+
+    /**
+     * @expectedException \Magento\Framework\Exception\LocalizedException
+     * @expectedExceptionMessage Destination folder is not writable or does not exists
+     */
+    public function testMoveTemporaryFileDestinationFolderDoesNotExists()
+    {
+        $filePath = '/filename.ext1';
+
+        $destinationPath = 'customer/f/i';
+
+        $this->mediaDirectory->expects($this->once())
+            ->method('create')
+            ->with($destinationPath)
+            ->willReturn(true);
+        $this->mediaDirectory->expects($this->once())
+            ->method('isWritable')
+            ->with($destinationPath)
+            ->willReturn(false);
+
+        $model = $this->getModel(CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER);
+        $model->moveTemporaryFile($filePath);
+    }
+
+    public function testMoveTemporaryFile()
+    {
+        $filePath = '/filename.ext1';
+
+        $destinationPath = 'customer/f/i';
+
+        $this->mediaDirectory->expects($this->once())
+            ->method('create')
+            ->with($destinationPath)
+            ->willReturn(true);
+        $this->mediaDirectory->expects($this->once())
+            ->method('isWritable')
+            ->with($destinationPath)
+            ->willReturn(true);
+        $this->mediaDirectory->expects($this->once())
+            ->method('getAbsolutePath')
+            ->with($destinationPath)
+            ->willReturn('/' . $destinationPath);
+
+        $path = CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER . '/' . FileProcessor::TMP_DIR . $filePath;
+        $newPath = $destinationPath . $filePath;
+
+        $this->mediaDirectory->expects($this->once())
+            ->method('renameFile')
+            ->with($path, $newPath)
+            ->willReturn(true);
+
+        $model = $this->getModel(CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER);
+        $this->assertEquals('/f/i' . $filePath, $model->moveTemporaryFile($filePath));
+    }
+
+    /**
+     * @expectedException \Magento\Framework\Exception\LocalizedException
+     * @expectedExceptionMessage Something went wrong while saving the file
+     */
+    public function testMoveTemporaryFileWithException()
+    {
+        $filePath = '/filename.ext1';
+
+        $destinationPath = 'customer/f/i';
+
+        $this->mediaDirectory->expects($this->once())
+            ->method('create')
+            ->with($destinationPath)
+            ->willReturn(true);
+        $this->mediaDirectory->expects($this->once())
+            ->method('isWritable')
+            ->with($destinationPath)
+            ->willReturn(true);
+        $this->mediaDirectory->expects($this->once())
+            ->method('getAbsolutePath')
+            ->with($destinationPath)
+            ->willReturn('/' . $destinationPath);
+
+        $path = CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER . '/' . FileProcessor::TMP_DIR . $filePath;
+        $newPath = $destinationPath . $filePath;
+
+        $this->mediaDirectory->expects($this->once())
+            ->method('renameFile')
+            ->with($path, $newPath)
+            ->willThrowException(new \Exception('Exception.'));
+
+        $model = $this->getModel(CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER);
+        $model->moveTemporaryFile($filePath);
+    }
+}
diff --git a/app/code/Magento/Customer/Test/Unit/Model/FileUploaderTest.php b/app/code/Magento/Customer/Test/Unit/Model/FileUploaderTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..a902151860f8f81c93f76b6dd617b1b6a7349f75
--- /dev/null
+++ b/app/code/Magento/Customer/Test/Unit/Model/FileUploaderTest.php
@@ -0,0 +1,186 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Customer\Test\Unit\Model;
+
+use Magento\Customer\Api\CustomerMetadataInterface;
+use Magento\Customer\Model\FileProcessor;
+use Magento\Customer\Model\FileUploader;
+
+class FileUploaderTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var CustomerMetadataInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $customerMetadataService;
+
+    /**
+     * @var \Magento\Customer\Api\AddressMetadataInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $addressMetadataService;
+
+    /**
+     * @var \Magento\Customer\Model\Metadata\ElementFactory|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $elementFactory;
+
+    /**
+     * @var \Magento\Customer\Model\FileProcessorFactory|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $fileProcessorFactory;
+
+    /**
+     * @var \Magento\Customer\Api\Data\AttributeMetadataInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $attributeMetadata;
+
+    protected function setUp()
+    {
+        $this->customerMetadataService = $this->getMockBuilder('Magento\Customer\Api\CustomerMetadataInterface')
+            ->getMockForAbstractClass();
+
+        $this->addressMetadataService = $this->getMockBuilder('Magento\Customer\Api\AddressMetadataInterface')
+            ->getMockForAbstractClass();
+
+        $this->elementFactory = $this->getMockBuilder('Magento\Customer\Model\Metadata\ElementFactory')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->fileProcessorFactory = $this->getMockBuilder('Magento\Customer\Model\FileProcessorFactory')
+            ->disableOriginalConstructor()
+            ->setMethods(['create'])
+            ->getMock();
+
+        $this->attributeMetadata = $this->getMockBuilder('Magento\Customer\Api\Data\AttributeMetadataInterface')
+            ->getMockForAbstractClass();
+    }
+
+    /**
+     * @param string $entityTypeCode
+     * @param string $scope
+     * @return FileUploader
+     */
+    private function getModel($entityTypeCode, $scope)
+    {
+        $model = new FileUploader(
+            $this->customerMetadataService,
+            $this->addressMetadataService,
+            $this->elementFactory,
+            $this->fileProcessorFactory,
+            $this->attributeMetadata,
+            $entityTypeCode,
+            $scope
+        );
+        return $model;
+    }
+
+    public function testValidate()
+    {
+        $attributeCode = 'attribute_code';
+
+        $filename = 'filename.ext1';
+
+        $_FILES = [
+            'customer' => [
+                'name' => [
+                    $attributeCode => $filename,
+                ],
+            ],
+        ];
+
+        $formElement = $this->getMockBuilder('Magento\Customer\Model\Metadata\Form\Image')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $formElement->expects($this->once())
+            ->method('validateValue')
+            ->with(['name' => $filename])
+            ->willReturn(true);
+
+        $this->elementFactory->expects($this->once())
+            ->method('create')
+            ->with($this->attributeMetadata, null, CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER)
+            ->willReturn($formElement);
+
+        $model = $this->getModel(CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER, 'customer');
+        $this->assertTrue($model->validate());
+    }
+
+    public function testUpload()
+    {
+        $attributeCode = 'attribute_code';
+        $attributeFrontendInput = 'image';
+
+        $resultFileName = '/filename.ext1';
+        $resultFilePath = 'filepath';
+        $resultFileUrl = 'viewFileUrl';
+
+        $allowedExtensions = 'ext1,EXT2 , eXt3';    // Added spaces, commas and upper-cases
+        $expectedAllowedExtensions = [
+            'ext1',
+            'ext2',
+            'ext3',
+        ];
+
+        $_FILES = [
+            'customer' => [
+                'name' => [
+                    $attributeCode => 'filename',
+                ],
+            ],
+        ];
+
+        $expectedResult = [
+            'name' => $resultFileName,
+            'file' => $resultFileName,
+            'path' => $resultFilePath,
+            'tmp_name' => $resultFilePath . $resultFileName,
+            'url' => $resultFileUrl,
+        ];
+
+        $fileProcessor = $this->getMockBuilder('Magento\Customer\Model\FileProcessor')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $fileProcessor->expects($this->once())
+            ->method('saveTemporaryFile')
+            ->with('customer[' . $attributeCode . ']')
+            ->willReturn([
+                'name' => $resultFileName,
+                'path' => $resultFilePath,
+                'file' => $resultFileName,
+            ]);
+        $fileProcessor->expects($this->once())
+            ->method('getViewUrl')
+            ->with(FileProcessor::TMP_DIR . '/filename.ext1', $attributeFrontendInput)
+            ->willReturn($resultFileUrl);
+
+        $this->fileProcessorFactory->expects($this->once())
+            ->method('create')
+            ->with([
+                'entityTypeCode' => CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER,
+                'allowedExtensions' => $expectedAllowedExtensions,
+            ])
+            ->willReturn($fileProcessor);
+
+        $validationRuleMock = $this->getMockBuilder('Magento\Customer\Api\Data\ValidationRuleInterface')
+            ->getMockForAbstractClass();
+        $validationRuleMock->expects($this->once())
+            ->method('getName')
+            ->willReturn('file_extensions');
+        $validationRuleMock->expects($this->once())
+            ->method('getValue')
+            ->willReturn($allowedExtensions);
+
+        $this->attributeMetadata->expects($this->once())
+            ->method('getFrontendInput')
+            ->willReturn($attributeFrontendInput);
+        $this->attributeMetadata->expects($this->once())
+            ->method('getValidationRules')
+            ->willReturn([$validationRuleMock]);
+
+
+        $model = $this->getModel(CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER, 'customer');
+        $this->assertEquals($expectedResult, $model->upload());
+    }
+}
diff --git a/app/code/Magento/Customer/Test/Unit/Model/Metadata/Form/FileTest.php b/app/code/Magento/Customer/Test/Unit/Model/Metadata/Form/FileTest.php
index 7a5b08fa531cb16f63197c6e90d012b14013370e..8bdd14daf53e63343d7ce2bf19a4356cf48a0912 100644
--- a/app/code/Magento/Customer/Test/Unit/Model/Metadata/Form/FileTest.php
+++ b/app/code/Magento/Customer/Test/Unit/Model/Metadata/Form/FileTest.php
@@ -8,6 +8,7 @@
 namespace Magento\Customer\Test\Unit\Model\Metadata\Form;
 
 use Magento\Customer\Model\Metadata\ElementFactory;
+use Magento\Framework\App\Filesystem\DirectoryList;
 use Magento\MediaStorage\Model\File\Validator\NotProtectedExtension;
 
 class FileTest extends AbstractFormTestCase
@@ -30,6 +31,11 @@ class FileTest extends AbstractFormTestCase
      */
     protected $uploaderFactoryMock;
 
+    /**
+     * @var \Magento\Customer\Model\FileProcessor|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $fileProcessorMock;
+
     protected function setUp()
     {
         parent::setUp();
@@ -43,6 +49,10 @@ class FileTest extends AbstractFormTestCase
         $this->requestMock = $this->getMockBuilder('Magento\Framework\App\Request\Http')
             ->disableOriginalConstructor()->getMock();
         $this->uploaderFactoryMock = $this->getMock('Magento\Framework\File\UploaderFactory', [], [], '', false);
+
+        $this->fileProcessorMock = $this->getMockBuilder('Magento\Customer\Model\FileProcessor')
+            ->disableOriginalConstructor()
+            ->getMock();
     }
 
     /**
@@ -52,10 +62,9 @@ class FileTest extends AbstractFormTestCase
      * @param string $delete
      * @dataProvider extractValueNoRequestScopeDataProvider
      */
-    public function testExtractValueNoRequestScope($expected, $attributeCode = '', $isAjax = false, $delete = '')
+    public function testExtractValueNoRequestScope($expected, $attributeCode = '', $delete = '')
     {
         $value = 'value';
-        $fileForm = $this->getClass($value, $isAjax);
 
         $this->requestMock->expects(
             $this->any()
@@ -75,7 +84,14 @@ class FileTest extends AbstractFormTestCase
         if (!empty($attributeCode)) {
             $_FILES[$attributeCode] = ['attributeCodeValue'];
         }
-        $this->assertEquals($expected, $fileForm->extractValue($this->requestMock));
+
+        $model = $this->initialize([
+            'value' => $value,
+            'isAjax' => false,
+            'entityTypeCode' => self::ENTITY_TYPE,
+        ]);
+
+        $this->assertEquals($expected, $model->extractValue($this->requestMock));
         if (!empty($attributeCode)) {
             unset($_FILES[$attributeCode]);
         }
@@ -84,11 +100,10 @@ class FileTest extends AbstractFormTestCase
     public function extractValueNoRequestScopeDataProvider()
     {
         return [
-            'ajax' => [false, '', true],
             'no_file' => [[]],
-            'delete' => [['delete' => true], '', false, true],
-            'file_delete' => [['attributeCodeValue', 'delete' => true], 'attributeCode', false, true],
-            'file_!delete' => [['attributeCodeValue'], 'attributeCode', false, false]
+            'delete' => [['delete' => true], '', true],
+            'file_delete' => [['attributeCodeValue', 'delete' => true], 'attributeCode', true],
+            'file_!delete' => [['attributeCodeValue'], 'attributeCode', false]
         ];
     }
 
@@ -101,7 +116,6 @@ class FileTest extends AbstractFormTestCase
     public function testExtractValueWithRequestScope($expected, $requestScope, $mainScope = false)
     {
         $value = 'value';
-        $fileForm = $this->getClass($value, false);
 
         $this->requestMock->expects(
             $this->any()
@@ -126,12 +140,18 @@ class FileTest extends AbstractFormTestCase
             $this->returnValue('attributeCode')
         );
 
-        $fileForm->setRequestScope($requestScope);
+        $model = $this->initialize([
+            'value' => $value,
+            'isAjax' => false,
+            'entityTypeCode' => self::ENTITY_TYPE,
+        ]);
+
+        $model->setRequestScope($requestScope);
 
         if ($mainScope) {
             $_FILES['mainScope'] = $mainScope;
         }
-        $this->assertEquals($expected, $fileForm->extractValue($this->requestMock));
+        $this->assertEquals($expected, $model->extractValue($this->requestMock));
         if ($mainScope) {
             unset($_FILES['mainScope']);
         }
@@ -163,7 +183,6 @@ class FileTest extends AbstractFormTestCase
      */
     public function testValidateValueNotToUpload($expected, $value, $isAjax = false, $isRequired = true)
     {
-        $fileForm = $this->getClass($value, $isAjax);
         $this->attributeMetadataMock->expects(
             $this->any()
         )->method(
@@ -179,7 +198,13 @@ class FileTest extends AbstractFormTestCase
             $this->returnValue('attributeLabel')
         );
 
-        $this->assertEquals($expected, $fileForm->validateValue($value));
+        $model = $this->initialize([
+            'value' => $value,
+            'isAjax' => $isAjax,
+            'entityTypeCode' => self::ENTITY_TYPE,
+        ]);
+
+        $this->assertEquals($expected, $model->validateValue($value));
     }
 
     public function validateValueNotToUploadDataProvider()
@@ -201,8 +226,7 @@ class FileTest extends AbstractFormTestCase
     public function testValidateValueToUpload($expected, $value, $parameters = [])
     {
         $parameters = array_merge(['uploaded' => true, 'valid' => true], $parameters);
-        $fileForm = $this->getClass($value, false);
-        $fileForm->expects($this->any())->method('_isUploadedFile')->will($this->returnValue($parameters['uploaded']));
+
         $this->attributeMetadataMock->expects($this->any())->method('isRequired')->will($this->returnValue(false));
         $this->attributeMetadataMock->expects(
             $this->any()
@@ -226,7 +250,18 @@ class FileTest extends AbstractFormTestCase
         )->will(
             $this->returnValue($parameters['valid'])
         );
-        $this->assertEquals($expected, $fileForm->validateValue($value));
+
+        $this->fileProcessorMock->expects($this->any())
+            ->method('isExist')
+            ->willReturn($parameters['uploaded']);
+
+        $model = $this->initialize([
+            'value' => $value,
+            'isAjax' => false,
+            'entityTypeCode' => self::ENTITY_TYPE,
+        ]);
+
+        $this->assertEquals($expected, $model->validateValue($value));
     }
 
     public function validateValueToUploadDataProvider()
@@ -248,30 +283,54 @@ class FileTest extends AbstractFormTestCase
 
     public function testCompactValueIsAjax()
     {
-        $fileForm = $this->getClass('value', true);
-        $this->assertSame($fileForm, $fileForm->compactValue('aValue'));
+        $model = $this->initialize([
+            'value' => 'value',
+            'isAjax' => true,
+            'entityTypeCode' => self::ENTITY_TYPE,
+        ]);
+
+        $this->assertSame($model, $model->compactValue('aValue'));
     }
 
     public function testCompactValueNoDelete()
     {
-        $fileForm = $this->getClass('value', false);
         $this->attributeMetadataMock->expects($this->any())->method('isRequired')->will($this->returnValue(false));
-        $this->assertSame('value', $fileForm->compactValue([]));
+
+        $model = $this->initialize([
+            'value' => 'value',
+            'isAjax' => false,
+            'entityTypeCode' => self::ENTITY_TYPE,
+        ]);
+
+        $this->fileProcessorMock->expects($this->once())
+            ->method('removeUploadedFile')
+            ->with('value')
+            ->willReturnSelf();
+
+        $this->assertSame([], $model->compactValue([]));
     }
 
     public function testCompactValueDelete()
     {
-        $fileForm = $this->getClass('value', false);
         $this->attributeMetadataMock->expects($this->any())->method('isRequired')->will($this->returnValue(false));
+
         $mediaDirMock = $this->getMockForAbstractClass('\Magento\Framework\Filesystem\Directory\WriteInterface');
         $mediaDirMock->expects($this->once())
             ->method('delete')
-            ->with(self::ENTITY_TYPE . 'value');
+            ->with(self::ENTITY_TYPE . '/' . 'value');
+
         $this->fileSystemMock->expects($this->once())
             ->method('getDirectoryWrite')
-            ->with(\Magento\Framework\App\Filesystem\DirectoryList::MEDIA)
+            ->with(DirectoryList::MEDIA)
             ->will($this->returnValue($mediaDirMock));
-        $this->assertSame('', $fileForm->compactValue(['delete' => true]));
+
+        $model = $this->initialize([
+            'value' => 'value',
+            'isAjax' => false,
+            'entityTypeCode' => self::ENTITY_TYPE,
+        ]);
+
+        $this->assertSame('', $model->compactValue(['delete' => true]));
     }
 
     public function testCompactValueTmpFile()
@@ -279,11 +338,10 @@ class FileTest extends AbstractFormTestCase
         $value = ['tmp_name' => 'tmp.file', 'name' => 'new.file'];
         $expected = 'saved.file';
 
-        $fileForm = $this->getClass(null, false);
         $mediaDirMock = $this->getMockForAbstractClass('\Magento\Framework\Filesystem\Directory\WriteInterface');
         $this->fileSystemMock->expects($this->once())
             ->method('getDirectoryWrite')
-            ->with(\Magento\Framework\App\Filesystem\DirectoryList::MEDIA)
+            ->with(DirectoryList::MEDIA)
             ->will($this->returnValue($mediaDirMock));
         $mediaDirMock->expects($this->any())
             ->method('getAbsolutePath')
@@ -309,14 +367,26 @@ class FileTest extends AbstractFormTestCase
             ->method('getUploadedFileName')
             ->will($this->returnValue($expected));
 
-        $this->assertSame($expected, $fileForm->compactValue($value));
+        $model = $this->initialize([
+            'value' => null,
+            'isAjax' => false,
+            'entityTypeCode' => self::ENTITY_TYPE,
+        ]);
+
+        $this->assertSame($expected, $model->compactValue($value));
     }
 
     public function testRestoreValue()
     {
         $value = 'value';
-        $fileForm = $this->getClass($value, false);
-        $this->assertEquals($value, $fileForm->restoreValue('aValue'));
+
+        $model = $this->initialize([
+            'value' => $value,
+            'isAjax' => false,
+            'entityTypeCode' => self::ENTITY_TYPE,
+        ]);
+
+        $this->assertEquals($value, $model->restoreValue('aValue'));
     }
 
     /**
@@ -325,8 +395,13 @@ class FileTest extends AbstractFormTestCase
      */
     public function testOutputValueNonJson($format)
     {
-        $fileForm = $this->getClass('value', false);
-        $this->assertSame('', $fileForm->outputValue($format));
+        $model = $this->initialize([
+            'value' => 'value',
+            'isAjax' => false,
+            'entityTypeCode' => self::ENTITY_TYPE,
+        ]);
+
+        $this->assertSame('', $model->outputValue($format));
     }
 
     public function outputValueDataProvider()
@@ -344,7 +419,7 @@ class FileTest extends AbstractFormTestCase
     {
         $value = 'value';
         $urlKey = 'url_key';
-        $fileForm = $this->getClass($value, false);
+
         $this->urlEncode->expects(
             $this->once()
         )->method(
@@ -354,36 +429,229 @@ class FileTest extends AbstractFormTestCase
         )->will(
             $this->returnValue($urlKey)
         );
+
         $expected = ['value' => $value, 'url_key' => $urlKey];
-        $this->assertSame($expected, $fileForm->outputValue(ElementFactory::OUTPUT_FORMAT_JSON));
+
+        $model = $this->initialize([
+            'value' => $value,
+            'isAjax' => false,
+            'entityTypeCode' => self::ENTITY_TYPE,
+        ]);
+
+        $this->assertSame($expected, $model->outputValue(ElementFactory::OUTPUT_FORMAT_JSON));
     }
 
     /**
-     * Helper for creating the unit under test.
-     *
-     * @param string|int|bool|null $value The value undergoing testing by a given test
-     * @param bool $isAjax
-     * @return \PHPUnit_Framework_MockObject_MockObject | File
+     * @param array $data
+     * @return \Magento\Customer\Model\Metadata\Form\File
      */
-    protected function getClass($value, $isAjax)
+    private function initialize(array $data)
     {
-        $fileForm = $this->getMock(
-            'Magento\Customer\Model\Metadata\Form\File',
-            ['_isUploadedFile'],
-            [
-                $this->localeMock,
-                $this->loggerMock,
-                $this->attributeMetadataMock,
-                $this->localeResolverMock,
-                $value,
-                self::ENTITY_TYPE,
-                $isAjax,
-                $this->urlEncode,
-                $this->fileValidatorMock,
-                $this->fileSystemMock,
-                $this->uploaderFactoryMock
-            ]
+        $model = new \Magento\Customer\Model\Metadata\Form\File(
+            $this->localeMock,
+            $this->loggerMock,
+            $this->attributeMetadataMock,
+            $this->localeResolverMock,
+            $data['value'],
+            $data['entityTypeCode'],
+            $data['isAjax'],
+            $this->urlEncode,
+            $this->fileValidatorMock,
+            $this->fileSystemMock,
+            $this->uploaderFactoryMock
         );
-        return $fileForm;
+
+        $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
+        $objectManager->setBackwardCompatibleProperty(
+            $model,
+            'fileProcessor',
+            $this->fileProcessorMock
+        );
+
+        return $model;
+    }
+
+    public function testExtractValueFileUploaderUIComponent()
+    {
+        $attributeCode = 'img1';
+        $requestScope = 'customer';
+        $fileName = 'filename.ext1';
+
+        $this->attributeMetadataMock->expects($this->exactly(2))
+            ->method('getAttributeCode')
+            ->willReturn($attributeCode);
+
+        $this->requestMock->expects($this->once())
+            ->method('getParam')
+            ->with($requestScope)
+            ->willReturn([
+                $attributeCode => [
+                    [
+                        'file' => $fileName,
+                    ],
+                ],
+            ]);
+
+        $model = $this->initialize([
+            'value' => 'value',
+            'isAjax' => false,
+            'entityTypeCode' => self::ENTITY_TYPE,
+        ]);
+
+        $model->setRequestScope($requestScope);
+        $result = $model->extractValue($this->requestMock);
+
+        $this->assertEquals(['file' => $fileName], $result);
+    }
+
+    public function testCompactValueRemoveUiComponentValue()
+    {
+        $value = 'value';
+
+        $model = $this->initialize([
+            'value' => $value,
+            'isAjax' => false,
+            'entityTypeCode' => self::ENTITY_TYPE,
+        ]);
+
+        $this->fileProcessorMock->expects($this->once())
+            ->method('removeUploadedFile')
+            ->with($value)
+            ->willReturnSelf();
+
+        $this->assertEquals([], $model->compactValue([]));
+    }
+
+    public function testCompactValueNoAction()
+    {
+        $value = 'value';
+
+        $model = $this->initialize([
+            'value' => $value,
+            'isAjax' => false,
+            'entityTypeCode' => self::ENTITY_TYPE,
+        ]);
+
+        $this->assertEquals($value, $model->compactValue($value));
+    }
+
+    public function testCompactValueUiComponent()
+    {
+        $value = [
+            'file' => 'filename',
+        ];
+
+        $model = $this->initialize([
+            'value' => null,
+            'isAjax' => false,
+            'entityTypeCode' => self::ENTITY_TYPE,
+        ]);
+
+        $this->fileProcessorMock->expects($this->once())
+            ->method('moveTemporaryFile')
+            ->with($value['file'])
+            ->willReturn(true);
+
+        $this->assertTrue($model->compactValue($value));
+    }
+
+    public function testCompactValueInputField()
+    {
+        $value = [
+            'name' => 'filename.ext1',
+            'tmp_name' => 'tmpfilename.ext1',
+        ];
+
+        $absolutePath = 'absolute_path';
+        $uploadedFilename = 'filename.ext1';
+
+        $mediaDirectoryMock = $this->getMockBuilder('Magento\Framework\Filesystem\Directory\WriteInterface')
+            ->getMockForAbstractClass();
+        $mediaDirectoryMock->expects($this->once())
+            ->method('getAbsolutePath')
+            ->with(self::ENTITY_TYPE)
+            ->willReturn($absolutePath);
+
+        $this->fileSystemMock->expects($this->once())
+            ->method('getDirectoryWrite')
+            ->with(DirectoryList::MEDIA)
+            ->willReturn($mediaDirectoryMock);
+
+        $uploaderMock = $this->getMockBuilder('Magento\Framework\File\Uploader')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $uploaderMock->expects($this->once())
+            ->method('setFilesDispersion')
+            ->with(true)
+            ->willReturnSelf();
+        $uploaderMock->expects($this->once())
+            ->method('setFilenamesCaseSensitivity')
+            ->with(false)
+            ->willReturnSelf();
+        $uploaderMock->expects($this->once())
+            ->method('setAllowRenameFiles')
+            ->with(true)
+            ->willReturnSelf();
+        $uploaderMock->expects($this->once())
+            ->method('save')
+            ->with($absolutePath, $value['name'])
+            ->willReturnSelf();
+        $uploaderMock->expects($this->once())
+            ->method('getUploadedFileName')
+            ->willReturn($uploadedFilename);
+
+        $this->uploaderFactoryMock->expects($this->once())
+            ->method('create')
+            ->with(['fileId' => $value])
+            ->willReturn($uploaderMock);
+
+        $model = $this->initialize([
+            'value' => null,
+            'isAjax' => false,
+            'entityTypeCode' => self::ENTITY_TYPE,
+        ]);
+
+        $this->assertEquals($uploadedFilename, $model->compactValue($value));
+    }
+
+    public function testCompactValueInputFieldWithException()
+    {
+        $value = [
+            'name' => 'filename.ext1',
+            'tmp_name' => 'tmpfilename.ext1',
+        ];
+
+        $originValue = 'origin';
+
+        $mediaDirectoryMock = $this->getMockBuilder('Magento\Framework\Filesystem\Directory\WriteInterface')
+            ->getMockForAbstractClass();
+        $mediaDirectoryMock->expects($this->once())
+            ->method('delete')
+            ->with(self::ENTITY_TYPE . '/' . $originValue);
+
+        $this->fileSystemMock->expects($this->once())
+            ->method('getDirectoryWrite')
+            ->with(DirectoryList::MEDIA)
+            ->willReturn($mediaDirectoryMock);
+
+        $exception = new \Exception('Error');
+
+        $this->uploaderFactoryMock->expects($this->once())
+            ->method('create')
+            ->with(['fileId' => $value])
+            ->willThrowException($exception);
+
+        $this->loggerMock->expects($this->once())
+            ->method('critical')
+            ->with($exception)
+            ->willReturnSelf();
+
+        $model = $this->initialize([
+            'value' => $originValue,
+            'isAjax' => false,
+            'entityTypeCode' => self::ENTITY_TYPE,
+        ]);
+
+        $this->assertEquals('', $model->compactValue($value));
     }
 }
diff --git a/app/code/Magento/Customer/Test/Unit/Model/Metadata/Form/ImageTest.php b/app/code/Magento/Customer/Test/Unit/Model/Metadata/Form/ImageTest.php
index f002a5cb1e4a5d8cd23ddf2a2ea16f0911be2a3a..e7b602ff241fbf7bd06ab036638e441059ed5edd 100644
--- a/app/code/Magento/Customer/Test/Unit/Model/Metadata/Form/ImageTest.php
+++ b/app/code/Magento/Customer/Test/Unit/Model/Metadata/Form/ImageTest.php
@@ -5,49 +5,399 @@
  */
 namespace Magento\Customer\Test\Unit\Model\Metadata\Form;
 
-use Magento\Customer\Model\Metadata\Form\Image;
+use Magento\Customer\Api\AddressMetadataInterface;
+use Magento\Customer\Api\CustomerMetadataInterface;
+use Magento\Customer\Model\FileProcessor;
 
-class ImageTest extends FileTest
+class ImageTest extends AbstractFormTestCase
 {
     /**
-     * Create an instance of the class that is being tested
-     *
-     * @param string|int|bool|null $value
-     * @param bool $isAjax
-     * @return Image
-     */
-    protected function getClass($value, $isAjax)
-    {
-        $imageForm = $this->getMock(
-            'Magento\Customer\Model\Metadata\Form\Image',
-            ['_isUploadedFile'],
-            [
-                $this->localeMock,
-                $this->loggerMock,
-                $this->attributeMetadataMock,
-                $this->localeResolverMock,
-                $value,
-                0,
-                $isAjax,
-                $this->urlEncode,
-                $this->fileValidatorMock,
-                $this->fileSystemMock,
-                $this->uploaderFactoryMock
-            ]
+     * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Framework\Url\EncoderInterface
+     */
+    protected $urlEncode;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\MediaStorage\Model\File\Validator\NotProtectedExtension
+     */
+    protected $fileValidatorMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Framework\Filesystem
+     */
+    protected $fileSystemMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Framework\App\Request\Http
+     */
+    protected $requestMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Framework\File\UploaderFactory
+     */
+    protected $uploaderFactoryMock;
+
+    /**
+     * @var FileProcessor|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $fileProcessorMock;
+
+    /**
+     * @var \Magento\Framework\Api\Data\ImageContentInterfaceFactory|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $imageContentFactory;
+
+    protected function setUp()
+    {
+        parent::setUp();
+
+        $this->urlEncode = $this->getMockBuilder('Magento\Framework\Url\EncoderInterface')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->fileValidatorMock = $this->getMockBuilder(
+            'Magento\MediaStorage\Model\File\Validator\NotProtectedExtension'
+        )
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->fileSystemMock = $this->getMockBuilder('Magento\Framework\Filesystem')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->requestMock = $this->getMockBuilder('Magento\Framework\App\Request\Http')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->uploaderFactoryMock = $this->getMockBuilder('Magento\Framework\File\UploaderFactory')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->fileProcessorMock = $this->getMockBuilder('Magento\Customer\Model\FileProcessor')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->imageContentFactory = $this->getMockBuilder('Magento\Framework\Api\Data\ImageContentInterfaceFactory')
+            ->disableOriginalConstructor()
+            ->setMethods(['create'])
+            ->getMock();
+    }
+
+    /**
+     * @param array $data
+     * @return \Magento\Customer\Model\Metadata\Form\File
+     */
+    private function initialize(array $data)
+    {
+        $model = new \Magento\Customer\Model\Metadata\Form\Image(
+            $this->localeMock,
+            $this->loggerMock,
+            $this->attributeMetadataMock,
+            $this->localeResolverMock,
+            $data['value'],
+            $data['entityTypeCode'],
+            $data['isAjax'],
+            $this->urlEncode,
+            $this->fileValidatorMock,
+            $this->fileSystemMock,
+            $this->uploaderFactoryMock
+        );
+
+        $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
+        $objectManager->setBackwardCompatibleProperty(
+            $model,
+            'fileProcessor',
+            $this->fileProcessorMock
+        );
+        $objectManager->setBackwardCompatibleProperty(
+            $model,
+            'imageContentFactory',
+            $this->imageContentFactory
         );
-        return $imageForm;
+
+        return $model;
+    }
+
+    public function testValidateIsNotValidFile()
+    {
+        $value = [
+            'tmp_name' => 'tmp_file',
+            'name' => 'realFileName',
+        ];
+
+        $this->attributeMetadataMock->expects($this->once())
+            ->method('getStoreLabel')
+            ->willReturn('File Input Field Label');
+
+        $this->fileProcessorMock->expects($this->once())
+            ->method('isExist')
+            ->with(FileProcessor::TMP_DIR . '/' . $value['tmp_name'])
+            ->willReturn(true);
+
+        $model = $this->initialize([
+            'value' => $value,
+            'isAjax' => false,
+            'entityTypeCode' => CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER,
+        ]);
+
+        $this->assertEquals(['"realFileName" is not a valid file.'], $model->validateValue($value));
+    }
+
+    public function testValidate()
+    {
+        $value = [
+            'tmp_name' => __DIR__ . '/_files/logo.gif',
+            'name' => 'logo.gif',
+        ];
+
+        $this->attributeMetadataMock->expects($this->once())
+            ->method('getStoreLabel')
+            ->willReturn('File Input Field Label');
+
+        $this->fileProcessorMock->expects($this->once())
+            ->method('isExist')
+            ->with(FileProcessor::TMP_DIR . '/' . $value['name'])
+            ->willReturn(true);
+
+        $model = $this->initialize([
+            'value' => $value,
+            'isAjax' => false,
+            'entityTypeCode' => CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER,
+        ]);
+
+        $this->assertTrue($model->validateValue($value));
     }
 
-    public function validateValueToUploadDataProvider()
+    public function testValidateMaxFileSize()
     {
-        $imagePath = __DIR__ . '/_files/logo.gif';
-        return [
-            [
-                ['"realFileName" is not a valid file.'],
-                ['tmp_name' => 'tmp_file', 'name' => 'realFileName'],
-                ['valid' => false],
-            ],
-            [true, ['tmp_name' => $imagePath, 'name' => 'logo.gif']]
+        $value = [
+            'tmp_name' => __DIR__ . '/_files/logo.gif',
+            'name' => 'logo.gif',
+            'size' => 2,
         ];
+
+        $maxFileSize = 1;
+
+        $validationRuleMock = $this->getMockBuilder('Magento\Customer\Api\Data\ValidationRuleInterface')
+            ->getMockForAbstractClass();
+        $validationRuleMock->expects($this->any())
+            ->method('getName')
+            ->willReturn('max_file_size');
+        $validationRuleMock->expects($this->any())
+            ->method('getValue')
+            ->willReturn($maxFileSize);
+
+        $this->attributeMetadataMock->expects($this->once())
+            ->method('getStoreLabel')
+            ->willReturn('File Input Field Label');
+        $this->attributeMetadataMock->expects($this->once())
+            ->method('getValidationRules')
+            ->willReturn([$validationRuleMock]);
+
+        $this->fileProcessorMock->expects($this->once())
+            ->method('isExist')
+            ->with(FileProcessor::TMP_DIR . '/' . $value['name'])
+            ->willReturn(true);
+
+        $model = $this->initialize([
+            'value' => $value,
+            'isAjax' => false,
+            'entityTypeCode' => CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER,
+        ]);
+
+        $this->assertEquals(['"logo.gif" exceeds the allowed file size.'], $model->validateValue($value));
+    }
+
+    public function testValidateMaxImageWidth()
+    {
+        $value = [
+            'tmp_name' => __DIR__ . '/_files/logo.gif',
+            'name' => 'logo.gif',
+        ];
+
+        $maxImageWidth = 1;
+
+        $validationRuleMock = $this->getMockBuilder('Magento\Customer\Api\Data\ValidationRuleInterface')
+            ->getMockForAbstractClass();
+        $validationRuleMock->expects($this->any())
+            ->method('getName')
+            ->willReturn('max_image_width');
+        $validationRuleMock->expects($this->any())
+            ->method('getValue')
+            ->willReturn($maxImageWidth);
+
+        $this->attributeMetadataMock->expects($this->once())
+            ->method('getStoreLabel')
+            ->willReturn('File Input Field Label');
+        $this->attributeMetadataMock->expects($this->once())
+            ->method('getValidationRules')
+            ->willReturn([$validationRuleMock]);
+
+        $this->fileProcessorMock->expects($this->once())
+            ->method('isExist')
+            ->with(FileProcessor::TMP_DIR . '/' . $value['name'])
+            ->willReturn(true);
+
+        $model = $this->initialize([
+            'value' => $value,
+            'isAjax' => false,
+            'entityTypeCode' => CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER,
+        ]);
+
+        $this->assertEquals(['"logo.gif" width exceeds allowed value of 1 px.'], $model->validateValue($value));
+    }
+
+    public function testValidateMaxImageHeight()
+    {
+        $value = [
+            'tmp_name' => __DIR__ . '/_files/logo.gif',
+            'name' => 'logo.gif',
+        ];
+
+        $maxImageHeight = 1;
+
+        $validationRuleMock = $this->getMockBuilder('Magento\Customer\Api\Data\ValidationRuleInterface')
+            ->getMockForAbstractClass();
+        $validationRuleMock->expects($this->any())
+            ->method('getName')
+            ->willReturn('max_image_heght');
+        $validationRuleMock->expects($this->any())
+            ->method('getValue')
+            ->willReturn($maxImageHeight);
+
+        $this->attributeMetadataMock->expects($this->once())
+            ->method('getStoreLabel')
+            ->willReturn('File Input Field Label');
+        $this->attributeMetadataMock->expects($this->once())
+            ->method('getValidationRules')
+            ->willReturn([$validationRuleMock]);
+
+        $this->fileProcessorMock->expects($this->once())
+            ->method('isExist')
+            ->with(FileProcessor::TMP_DIR . '/' . $value['name'])
+            ->willReturn(true);
+
+        $model = $this->initialize([
+            'value' => $value,
+            'isAjax' => false,
+            'entityTypeCode' => CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER,
+        ]);
+
+        $this->assertEquals(['"logo.gif" height exceeds allowed value of 1 px.'], $model->validateValue($value));
+    }
+
+    public function testCompactValueNoChanges()
+    {
+        $originValue = 'filename.ext1';
+
+        $value = [
+            'file' => $originValue,
+        ];
+
+        $model = $this->initialize([
+            'value' => $originValue,
+            'isAjax' => false,
+            'entityTypeCode' => CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER,
+        ]);
+
+        $this->assertEquals($originValue, $model->compactValue($value));
+    }
+
+    public function testCompactValueUiComponentAddress()
+    {
+        $originValue = 'filename.ext1';
+
+        $value = [
+            'file' => 'filename.ext2',
+        ];
+
+        $this->fileProcessorMock->expects($this->once())
+            ->method('moveTemporaryFile')
+            ->with($value['file'])
+            ->willReturn(true);
+
+        $model = $this->initialize([
+            'value' => $originValue,
+            'isAjax' => false,
+            'entityTypeCode' => AddressMetadataInterface::ENTITY_TYPE_ADDRESS,
+        ]);
+
+        $this->assertTrue($model->compactValue($value));
+    }
+
+    public function testCompactValueUiComponentCustomer()
+    {
+        $originValue = 'filename.ext1';
+
+        $value = [
+            'file' => 'filename.ext2',
+            'name' => 'filename.ext2',
+            'type' => 'image',
+        ];
+
+        $base64EncodedData = 'encoded_data';
+
+        $this->fileProcessorMock->expects($this->once())
+            ->method('isExist')
+            ->with(FileProcessor::TMP_DIR . '/' . $value['file'])
+            ->willReturn(true);
+        $this->fileProcessorMock->expects($this->once())
+            ->method('getBase64EncodedData')
+            ->with(FileProcessor::TMP_DIR . '/' . $value['file'])
+            ->willReturn($base64EncodedData);
+        $this->fileProcessorMock->expects($this->once())
+            ->method('removeUploadedFile')
+            ->with(FileProcessor::TMP_DIR . '/' . $value['file'])
+            ->willReturnSelf();
+
+        $imageContentMock = $this->getMockBuilder('Magento\Framework\Api\Data\ImageContentInterface')
+            ->getMockForAbstractClass();
+        $imageContentMock->expects($this->once())
+            ->method('setName')
+            ->with($value['name'])
+            ->willReturnSelf();
+        $imageContentMock->expects($this->once())
+            ->method('setBase64EncodedData')
+            ->with($base64EncodedData)
+            ->willReturnSelf();
+        $imageContentMock->expects($this->once())
+            ->method('setType')
+            ->with($value['type'])
+            ->willReturnSelf();
+
+        $this->imageContentFactory->expects($this->once())
+            ->method('create')
+            ->willReturn($imageContentMock);
+
+        $model = $this->initialize([
+            'value' => $originValue,
+            'isAjax' => false,
+            'entityTypeCode' => CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER,
+        ]);
+
+        $this->assertEquals($imageContentMock, $model->compactValue($value));
+    }
+
+    public function testCompactValueUiComponentCustomerNotExists()
+    {
+        $originValue = 'filename.ext1';
+
+        $value = [
+            'file' => 'filename.ext2',
+            'name' => 'filename.ext2',
+            'type' => 'image',
+        ];
+
+        $this->fileProcessorMock->expects($this->once())
+            ->method('isExist')
+            ->with(FileProcessor::TMP_DIR . '/' . $value['file'])
+            ->willReturn(false);
+
+        $model = $this->initialize([
+            'value' => $originValue,
+            'isAjax' => false,
+            'entityTypeCode' => CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER,
+        ]);
+
+        $this->assertEquals($originValue, $model->compactValue($value));
     }
 }
diff --git a/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/CustomerRepositoryTest.php b/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/CustomerRepositoryTest.php
index 2fe13090e544ed226b5aaca3f7e6ba7a3b38d985..d823fb9dfc00ba8f85398a219eb825496c7a7561 100644
--- a/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/CustomerRepositoryTest.php
+++ b/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/CustomerRepositoryTest.php
@@ -428,6 +428,20 @@ class CustomerRepositoryTest extends \PHPUnit_Framework_TestCase
         $storeId = 2;
         $passwordHash = 'ukfa4sdfa56s5df02asdf4rt';
 
+        $customerSecureData = $this->getMock(
+            'Magento\Customer\Model\Data\CustomerSecure',
+            [
+                'getRpToken',
+                'getRpTokenCreatedAt',
+                'getPasswordHash',
+                'getFailuresNum',
+                'getFirstFailure',
+                'getLockExpires',
+            ],
+            [],
+            '',
+            false
+        );
         $region = $this->getMockForAbstractClass('Magento\Customer\Api\Data\RegionInterface', [], '', false);
         $address = $this->getMockForAbstractClass(
             'Magento\Customer\Api\Data\AddressInterface',
@@ -491,6 +505,42 @@ class CustomerRepositoryTest extends \PHPUnit_Framework_TestCase
                 'setAddresses'
             ]
         );
+        $customerModel->expects($this->atLeastOnce())
+            ->method('setRpToken')
+            ->with(null);
+        $customerModel->expects($this->atLeastOnce())
+            ->method('setRpTokenCreatedAt')
+            ->with(null);
+        $customerModel->expects($this->atLeastOnce())
+            ->method('setPasswordHash')
+            ->with($passwordHash);
+        $this->customerRegistry->expects($this->once())
+            ->method('remove')
+            ->with($customerId);
+
+        $this->customerRegistry->expects($this->once())
+            ->method('retrieveSecureData')
+            ->with($customerId)
+            ->willReturn($customerSecureData);
+        $customerSecureData->expects($this->never())
+            ->method('getRpToken')
+            ->willReturn('rpToken');
+        $customerSecureData->expects($this->never())
+            ->method('getRpTokenCreatedAt')
+            ->willReturn('rpTokenCreatedAt');
+        $customerSecureData->expects($this->never())
+            ->method('getPasswordHash')
+            ->willReturn('passwordHash');
+        $customerSecureData->expects($this->once())
+            ->method('getFailuresNum')
+            ->willReturn('failuresNum');
+        $customerSecureData->expects($this->once())
+            ->method('getFirstFailure')
+            ->willReturn('firstFailure');
+        $customerSecureData->expects($this->once())
+            ->method('getLockExpires')
+            ->willReturn('lockExpires');
+
         $this->customer->expects($this->atLeastOnce())
             ->method('getId')
             ->willReturn($customerId);
@@ -527,6 +577,10 @@ class CustomerRepositoryTest extends \PHPUnit_Framework_TestCase
         $customerAttributesMetaData->expects($this->at(2))
             ->method('setAddresses')
             ->with([$address]);
+        $customerAttributesMetaData
+            ->expects($this->atLeastOnce())
+            ->method('getId')
+            ->willReturn($customerId);
         $this->extensibleDataObjectConverter->expects($this->once())
             ->method('toNestedArray')
             ->with($customerAttributesMetaData, [], '\Magento\Customer\Api\Data\CustomerInterface')
@@ -551,16 +605,13 @@ class CustomerRepositoryTest extends \PHPUnit_Framework_TestCase
             ->with($storeId);
         $customerModel->expects($this->once())
             ->method('setId')
-            ->with(null);
+            ->with($customerId);
         $customerModel->expects($this->once())
             ->method('getAttributeSetId')
             ->willReturn(null);
         $customerModel->expects($this->once())
             ->method('setAttributeSetId')
             ->with(\Magento\Customer\Api\CustomerMetadataInterface::ATTRIBUTE_SET_ID_CUSTOMER);
-        $customerModel->expects($this->once())
-            ->method('setPasswordHash')
-            ->with($passwordHash);
         $customerModel->expects($this->atLeastOnce())
             ->method('getId')
             ->willReturn($customerId);
diff --git a/app/code/Magento/Customer/view/frontend/layout/customer_account_index.xml b/app/code/Magento/Customer/view/frontend/layout/customer_account_index.xml
index 5d1da28d4c189ff7deb870521137af6782280b24..c3a255192eb9b353fac275da89cc7afbbf25ce6e 100644
--- a/app/code/Magento/Customer/view/frontend/layout/customer_account_index.xml
+++ b/app/code/Magento/Customer/view/frontend/layout/customer_account_index.xml
@@ -14,7 +14,6 @@
             </action>
         </referenceBlock>
         <referenceContainer name="content">
-            <block class="Magento\Framework\View\Element\Template" name="customer_account_dashboard_top" as="top"/>
             <block class="Magento\Customer\Block\Account\Dashboard\Info" name="customer_account_dashboard_info" as="info" template="account/dashboard/info.phtml" cacheable="false"/>
             <block class="Magento\Customer\Block\Account\Dashboard\Address" name="customer_account_dashboard_address" as="address" template="account/dashboard/address.phtml" cacheable="false"/>
         </referenceContainer>
diff --git a/app/code/Magento/Customer/view/frontend/templates/widget/name.phtml b/app/code/Magento/Customer/view/frontend/templates/widget/name.phtml
index f46d111b5b0587d36329fb4ff515da437e9e0ecd..f1f1416c2f4e4bedfd54db3fe4afdb5c56c5317d 100644
--- a/app/code/Magento/Customer/view/frontend/templates/widget/name.phtml
+++ b/app/code/Magento/Customer/view/frontend/templates/widget/name.phtml
@@ -30,7 +30,7 @@ $middle = $block->showMiddlename();
 $suffix = $block->showSuffix();
 ?>
 
-<?php if ($prefix || $middle || $suffix && !$block->getNoWrap()): ?>
+<?php if (($prefix || $middle || $suffix) && !$block->getNoWrap()): ?>
 <div class="field required fullname <?php /* @escapeNotVerified */ echo $block->getContainerClassName() ?>">
     <label for="<?php /* @escapeNotVerified */ echo $block->getFieldId('firstname') ?>" class="label">
         <span><?php /* @escapeNotVerified */ echo __('Name') ?></span>
@@ -139,7 +139,7 @@ $suffix = $block->showSuffix();
         </div>
     <?php endif; ?>
 
-    <?php if ($prefix || $middle || $suffix && !$block->getNoWrap()): ?>
+    <?php if (($prefix || $middle || $suffix) && !$block->getNoWrap()): ?>
             </div>
         </fieldset>
     </div>
diff --git a/app/code/Magento/Customer/view/frontend/web/js/password-strength-indicator.js b/app/code/Magento/Customer/view/frontend/web/js/password-strength-indicator.js
index 138ac06504155b3badcf6c8b032790e68fbb46f5..298af46103ec0eb80e18a01e7ec47cd418dd525c 100644
--- a/app/code/Magento/Customer/view/frontend/web/js/password-strength-indicator.js
+++ b/app/code/Magento/Customer/view/frontend/web/js/password-strength-indicator.js
@@ -17,7 +17,6 @@ define([
     $.widget('mage.passwordStrengthIndicator', {
         options: {
             cache: {},
-            defaultClassName: 'password-strength-meter-',
             passwordSelector: '[type=password]',
             passwordStrengthMeterSelector: '[data-role=password-strength-meter]',
             passwordStrengthMeterLabelSelector: '[data-role=password-strength-meter-label]'
@@ -54,14 +53,15 @@ define([
             var password = this._getPassword(),
                 isEmpty = password.length === 0,
                 zxcvbnScore = zxcvbn(password).score,
-                isValid = $.validator.validateSingleElement(this.options.cache.input),
-                displayScore = zxcvbnScore || 1;
+                displayScore,
+                isValid;
 
             // Display score is based on combination of whether password is empty, valid, and zxcvbn strength
             if (isEmpty) {
                 displayScore = 0;
-            } else if (!isValid) {
-                displayScore = 1;
+            } else {
+                isValid  = $.validator.validateSingleElement(this.options.cache.input);
+                displayScore = isValid ? zxcvbnScore : 1;
             }
 
             // Update label
@@ -75,27 +75,32 @@ define([
          */
         _displayStrength: function (displayScore) {
             var strengthLabel = '',
-                className = this._getClassName(displayScore);
+                className = 'password-';
 
             switch (displayScore) {
                 case 0:
                     strengthLabel = $t('No Password');
+                    className += 'none';
                     break;
 
                 case 1:
                     strengthLabel = $t('Weak');
+                    className += 'weak';
                     break;
 
                 case 2:
                     strengthLabel = $t('Medium');
+                    className += 'medium';
                     break;
 
                 case 3:
                     strengthLabel = $t('Strong');
+                    className += 'strong';
                     break;
 
                 case 4:
                     strengthLabel = $t('Very Strong');
+                    className += 'very-strong';
                     break;
             }
 
@@ -112,16 +117,6 @@ define([
          */
         _getPassword: function () {
             return this.options.cache.input.val();
-        },
-
-        /**
-         * Get class name for score
-         * @param {int} displayScore
-         * @returns {String}
-         * @private
-         */
-        _getClassName: function (displayScore) {
-            return this.options.defaultClassName + displayScore;
         }
     });
 
diff --git a/app/code/Magento/Eav/Setup/EavSetup.php b/app/code/Magento/Eav/Setup/EavSetup.php
index a53ed607747492e63b41532fabe907301ad36c4c..9ed8ffcdc93751c4f008276faa99322c29a20167 100644
--- a/app/code/Magento/Eav/Setup/EavSetup.php
+++ b/app/code/Magento/Eav/Setup/EavSetup.php
@@ -192,6 +192,9 @@ class EavSetup
             'additional_attribute_table' => $this->_getValue($params, 'additional_attribute_table'),
             'entity_attribute_collection' => $this->_getValue($params, 'entity_attribute_collection'),
         ];
+        if (isset($params['entity_type_id'])) {
+            $data['entity_type_id'] = $params['entity_type_id'];
+        }
 
         if ($this->getEntityType($code, 'entity_type_id')) {
             $this->updateEntityType($code, $data);
@@ -199,7 +202,11 @@ class EavSetup
             $this->setup->getConnection()->insert($this->setup->getTable('eav_entity_type'), $data);
         }
 
-        $this->addAttributeSet($code, $this->_defaultAttributeSetName);
+        if (isset($params['entity_type_id'])) {
+            $this->addAttributeSet($code, $this->_defaultAttributeSetName, null, $params['entity_type_id']);
+        } else {
+            $this->addAttributeSet($code, $this->_defaultAttributeSetName);
+        }
         $this->addAttributeGroup($code, $this->_defaultGroupName, $this->_generalGroupName);
 
         return $this;
@@ -310,9 +317,10 @@ class EavSetup
      * @param int|string $entityTypeId
      * @param string $name
      * @param int $sortOrder
+     * @param int $setId
      * @return $this
      */
-    public function addAttributeSet($entityTypeId, $name, $sortOrder = null)
+    public function addAttributeSet($entityTypeId, $name, $sortOrder = null, $setId = null)
     {
         $data = [
             'entity_type_id' => $this->getEntityTypeId($entityTypeId),
@@ -320,6 +328,10 @@ class EavSetup
             'sort_order' => $this->getAttributeSetSortOrder($entityTypeId, $sortOrder),
         ];
 
+        if ($setId !== null) {
+            $data['attribute_set_id'] = $setId;
+        }
+
         $setId = $this->getAttributeSet($entityTypeId, $name, 'attribute_set_id');
         if ($setId) {
             $this->updateAttributeSet($entityTypeId, $setId, $data);
diff --git a/app/code/Magento/GiftMessage/view/frontend/templates/inline.phtml b/app/code/Magento/GiftMessage/view/frontend/templates/inline.phtml
index c8be1ad14bfd1323d2a569ec30b0b07dc4704a06..250410fc3b5264d9dc077e92c7c5c1479c0d2693 100644
--- a/app/code/Magento/GiftMessage/view/frontend/templates/inline.phtml
+++ b/app/code/Magento/GiftMessage/view/frontend/templates/inline.phtml
@@ -28,7 +28,10 @@
 
             <dd id="allow-gift-options-for-order-container" class="order-options">
                 <div class="options-order-container" id="options-order-container-<?php /* @escapeNotVerified */ echo $block->getEntity()->getId() ?>"></div>
-                    <a href="#" class="action activate message" data-mage-init='{"toggleAdvanced": {"selectorsToggleClass":"hidden", "toggleContainers":"#allow-gift-messages-for-order-container"}}'><?php /* @escapeNotVerified */ echo __('Gift Message') ?></a>
+                    <button class="action action-gift"
+                            data-mage-init='{"toggleAdvanced": {"selectorsToggleClass":"hidden", "toggleContainers":"#allow-gift-messages-for-order-container"}}'>
+                        <span><?php /* @escapeNotVerified */ echo __('Gift Message') ?></span>
+                    </button>
                     <div id="allow-gift-messages-for-order-container" class="gift-messages-order hidden">
                         <fieldset class="fieldset">
                             <p><?php /* @escapeNotVerified */ echo __('Leave this box blank if you don\'t want to leave a gift message for the entire order.') ?></p>
@@ -52,13 +55,12 @@
                             </div>
                         </fieldset>
                         <script>
-require(['jquery'], function(jQuery){
-
-    jQuery('#add-gift-options-<?php /* @escapeNotVerified */ echo $block->getEntity()->getId() ?>')
-        .add('#add-gift-options-for-order-<?php /* @escapeNotVerified */ echo $block->getEntity()->getId() ?>').removeClass('hidden');
-
-});
-</script>
+                            require(['jquery'], function(jQuery){
+                                jQuery('#add-gift-options-<?php /* @escapeNotVerified */ echo $block->getEntity()->getId() ?>')
+                                    .add('#add-gift-options-for-order-<?php /* @escapeNotVerified */ echo $block->getEntity()->getId() ?>')
+                                    .removeClass('hidden');
+                            });
+                        </script>
                     </div>
             </dd>
             <?php endif ?>
@@ -87,7 +89,10 @@ require(['jquery'], function(jQuery){
                          <div class="options">
                              <div class="options-items-container" id="options-items-container-<?php /* @escapeNotVerified */ echo $block->getEntity()->getId() ?>-<?php /* @escapeNotVerified */ echo $_item->getId() ?>"></div>
                              <?php if ($block->isItemMessagesAvailable($_item)): ?>
-                             <a href="#" class="action activate message" data-mage-init='{"toggleAdvanced": {"selectorsToggleClass":"hidden", "toggleContainers":"#gift-messages-for-item-container-<?php /* @escapeNotVerified */ echo $_item->getId() ?>"}}'><?php /* @escapeNotVerified */ echo __('Gift Message') ?></a>
+                             <button class="action action-gift"
+                                     data-mage-init='{"toggleAdvanced": {"selectorsToggleClass":"hidden", "toggleContainers":"#gift-messages-for-item-container-<?php /* @escapeNotVerified */ echo $_item->getId() ?>"}}'>
+                                 <span><?php /* @escapeNotVerified */ echo __('Gift Message') ?></span>
+                             </button>
                              <div id="gift-messages-for-item-container-<?php /* @escapeNotVerified */ echo $_item->getId() ?>" class="block message hidden">
                                  <fieldset class="fieldset">
                                      <p><?php /* @escapeNotVerified */ echo __('Leave a box blank if you don\'t want to add a gift message for that item.') ?></p>
@@ -118,24 +123,23 @@ require(['jquery'], function(jQuery){
                 </ol>
             </dd>
             <script>
-require(['jquery'], function(jQuery){
-
-    jQuery('#add-gift-options-<?php /* @escapeNotVerified */ echo $block->getEntity()->getId() ?>')
-        .add('#add-gift-options-for-items-<?php /* @escapeNotVerified */ echo $block->getEntity()->getId() ?>').removeClass('hidden');
-
-});
-</script>
+                require(['jquery'], function(jQuery){
+                    jQuery('#add-gift-options-<?php /* @escapeNotVerified */ echo $block->getEntity()->getId() ?>')
+                        .add('#add-gift-options-for-items-<?php /* @escapeNotVerified */ echo $block->getEntity()->getId() ?>')
+                        .removeClass('hidden');
+                });
+            </script>
             <?php endif; ?>
             <dt class="extra-options-container" id="extra-options-container-<?php /* @escapeNotVerified */ echo $block->getEntity()->getId() ?>"></dt>
         </dl>
     </fieldset>
-<script type="text/x-magento-init">
-{
-    "#allow_gift_options, #allow_gift_options_for_order, #allow_gift_options_for_items": {
-        "giftOptions": {}
+    <script type="text/x-magento-init">
+    {
+        "#allow_gift_options, #allow_gift_options_for_order, #allow_gift_options_for_items": {
+            "giftOptions": {}
+        }
     }
-}
-</script>
+    </script>
 <?php break; ?>
 
 <?php case 'multishipping_address': ?>
@@ -159,7 +163,10 @@ require(['jquery'], function(jQuery){
                 <div class="options-order-container" id="options-order-container-<?php /* @escapeNotVerified */ echo $block->getEntity()->getId() ?>"></div>
                 <?php if ($block->isMessagesAvailable()): ?>
                     <?php $_giftMessage = true; ?>
-                    <a href="#" class="action activate message" data-mage-init='{"toggleAdvanced": {"selectorsToggleClass":"hidden", "toggleContainers":"#gift-messages-for-order-container-<?php /* @escapeNotVerified */ echo $block->getEntity()->getId() ?>"}}'><?php /* @escapeNotVerified */ echo __('Gift Message') ?></a>
+                    <button class="action action-gift"
+                            data-mage-init='{"toggleAdvanced": {"selectorsToggleClass":"hidden", "toggleContainers":"#gift-messages-for-order-container-<?php /* @escapeNotVerified */ echo $block->getEntity()->getId() ?>"}}'>
+                        <span><?php /* @escapeNotVerified */ echo __('Gift Message') ?></span>
+                    </button>
                     <div id="gift-messages-for-order-container-<?php /* @escapeNotVerified */ echo $block->getEntity()->getId() ?>" class="gift-messages-order hidden">
                         <fieldset class="fieldset">
                             <p><?php /* @escapeNotVerified */ echo __('You can leave this box blank if you don\'t want to add a gift message for this address.') ?></p>
@@ -212,7 +219,10 @@ require(['jquery'], function(jQuery){
 
                              <?php if ($block->isItemMessagesAvailable($_item)): ?>
                              <?php $_giftMessage = true; ?>
-                                 <a href="#" class="action activate message" data-mage-init='{"toggleAdvanced": {"selectorsToggleClass":"hidden", "toggleContainers":"#gift-messages-for-item-container-<?php /* @escapeNotVerified */ echo $_item->getId() ?>"}}'><?php /* @escapeNotVerified */ echo __('Gift Message') ?></a>
+                                 <button class="action action-gift"
+                                         data-mage-init='{"toggleAdvanced": {"selectorsToggleClass":"hidden", "toggleContainers":"#gift-messages-for-item-container-<?php /* @escapeNotVerified */ echo $_item->getId() ?>"}}'>
+                                     <span><?php /* @escapeNotVerified */ echo __('Gift Message') ?></span>
+                                 </button>
                                  <div id="gift-messages-for-item-container-<?php /* @escapeNotVerified */ echo $_item->getId() ?>" class="block message hidden">
                                      <fieldset class="fieldset">
                                         <p><?php /* @escapeNotVerified */ echo __('You can leave this box blank if you don\'t want to add a gift message for the item.') ?></p>
@@ -247,13 +257,13 @@ require(['jquery'], function(jQuery){
             <dt class="extra-options-container" id="extra-options-container-<?php /* @escapeNotVerified */ echo $block->getEntity()->getId() ?>"></dt>
         </dl>
     </fieldset>
-<script type="text/x-magento-init">
-    {
-        "#allow_gift_options_<?php /* @escapeNotVerified */ echo $block->getEntity()->getId() ?>, #allow_gift_options_for_order_<?php /* @escapeNotVerified */ echo $block->getEntity()->getId() ?>, #allow_gift_options_for_items_<?php /* @escapeNotVerified */ echo $block->getEntity()->getId() ?>": {
-            "giftOptions": {}
+    <script type="text/x-magento-init">
+        {
+            "#allow_gift_options_<?php /* @escapeNotVerified */ echo $block->getEntity()->getId() ?>, #allow_gift_options_for_order_<?php /* @escapeNotVerified */ echo $block->getEntity()->getId() ?>, #allow_gift_options_for_items_<?php /* @escapeNotVerified */ echo $block->getEntity()->getId() ?>": {
+                "giftOptions": {}
+            }
         }
-    }
-</script>
+    </script>
     <?php break; ?>
 <?php endswitch ?>
 <?php if ($_giftMessage): ?>
diff --git a/app/code/Magento/GiftMessage/view/frontend/web/template/gift-message-item-level.html b/app/code/Magento/GiftMessage/view/frontend/web/template/gift-message-item-level.html
index 559875c90f75a92132ed56a311116754e4e42014..a310dcddf6a19a3226bf4f66a2981d1146fd6736 100644
--- a/app/code/Magento/GiftMessage/view/frontend/web/template/gift-message-item-level.html
+++ b/app/code/Magento/GiftMessage/view/frontend/web/template/gift-message-item-level.html
@@ -5,14 +5,13 @@
  */
  -->
 <!-- ko if: isActive() || hasActiveOptions() -->
-<a href="#"
-   class="action action-gift"
-   data-bind="
-   click: $data.toggleFormBlockVisibility.bind($data),
-   css: {_active: formBlockVisibility() || resultBlockVisibility()}
-   ">
+<button class="action action-gift"
+        data-bind="
+            click: $data.toggleFormBlockVisibility.bind($data),
+            css: {_active: formBlockVisibility() || resultBlockVisibility()}
+        ">
     <span data-bind="i18n: 'Gift options'"></span>
-</a>
+</button>
 <div class="gift-content" data-bind="css: {_active: formBlockVisibility() || resultBlockVisibility()}"> <!-- add class "active" to display the content -->
     <!-- ko ifnot: resultBlockVisibility() -->
         <div class="gift-options">
diff --git a/app/code/Magento/Integration/Block/Adminhtml/Widget/Grid/Column/Renderer/Name.php b/app/code/Magento/Integration/Block/Adminhtml/Widget/Grid/Column/Renderer/Name.php
index b881ff04db1a217102dd3802f884f1dcbe60f6ae..c1d849f8b718785d00abc4daa7b09dac87da14df 100644
--- a/app/code/Magento/Integration/Block/Adminhtml/Widget/Grid/Column/Renderer/Name.php
+++ b/app/code/Magento/Integration/Block/Adminhtml/Widget/Grid/Column/Renderer/Name.php
@@ -23,7 +23,7 @@ class Name extends \Magento\Backend\Block\Widget\Grid\Column\Renderer\Text
         /** @var \Magento\Integration\Model\Integration $row */
         $text = parent::render($row);
         if (!$this->isUrlSecure($row->getEndpoint()) || !$this->isUrlSecure($row->getIdentityLinkUrl())) {
-            $text .= '<span class="icon-error"><span>Integration not secure</span></span>';
+            $text .= '<span class="security-notice"><span>' . __("Integration not secure") . '</span></span>';
         }
         return $text;
     }
diff --git a/app/code/Magento/Integration/Test/Unit/Block/Adminhtml/Widget/Grid/Column/Renderer/NameTest.php b/app/code/Magento/Integration/Test/Unit/Block/Adminhtml/Widget/Grid/Column/Renderer/NameTest.php
index 3fb03dd3f65dc05b5548120ab5cb15512bf34b5d..f1bca8620570a29cf31f55daeee68761b4f9bada 100644
--- a/app/code/Magento/Integration/Test/Unit/Block/Adminhtml/Widget/Grid/Column/Renderer/NameTest.php
+++ b/app/code/Magento/Integration/Test/Unit/Block/Adminhtml/Widget/Grid/Column/Renderer/NameTest.php
@@ -101,7 +101,7 @@ class NameTest extends \PHPUnit_Framework_TestCase
             [
                 'http://myurl',
                 'Custom Integration',
-                'Custom Integration<span class="icon-error"><span>Integration not secure</span></span>'
+                'Custom Integration<span class="security-notice"><span>Integration not secure</span></span>'
             ]
         ];
     }
diff --git a/app/code/Magento/Integration/view/adminhtml/layout/adminhtml_integration_index.xml b/app/code/Magento/Integration/view/adminhtml/layout/adminhtml_integration_index.xml
index 9825277958f6703c4d3e0d52610540047d00ec1b..8a4e55533d67820aa7b2bae9e6769b3d8df2304d 100644
--- a/app/code/Magento/Integration/view/adminhtml/layout/adminhtml_integration_index.xml
+++ b/app/code/Magento/Integration/view/adminhtml/layout/adminhtml_integration_index.xml
@@ -8,9 +8,6 @@
  */
 -->
 <page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
-    <head>
-        <css src="Magento_Integration::integration.css"/>
-    </head>
     <update handle="adminhtml_integration_grid_block"/>
     <body>
         <referenceBlock name="content">
diff --git a/app/code/Magento/Integration/view/adminhtml/layout/adminhtml_integration_new.xml b/app/code/Magento/Integration/view/adminhtml/layout/adminhtml_integration_new.xml
index 74deb27aaba968c40e345de5b71737c2593c2f32..492731b447ea2279d45f10ad2c1091aebccdbe3c 100644
--- a/app/code/Magento/Integration/view/adminhtml/layout/adminhtml_integration_new.xml
+++ b/app/code/Magento/Integration/view/adminhtml/layout/adminhtml_integration_new.xml
@@ -6,9 +6,6 @@
  */
 -->
 <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">
-    <head>
-        <css src="Magento_Integration::integration.css"/>
-    </head>
     <update handle="adminhtml_integration_edit"/>
     <body>
         <referenceBlock name="content">
diff --git a/app/code/Magento/Integration/view/adminhtml/templates/integration/activate/permissions.phtml b/app/code/Magento/Integration/view/adminhtml/templates/integration/activate/permissions.phtml
index 225eac3fc7d6338757f1bcdd024590f965bb945c..bcad96435a5cec25a8a02dfcdf00b227af92ff50 100644
--- a/app/code/Magento/Integration/view/adminhtml/templates/integration/activate/permissions.phtml
+++ b/app/code/Magento/Integration/view/adminhtml/templates/integration/activate/permissions.phtml
@@ -14,4 +14,4 @@
 <div id="integration-activate-permissions-tabs">
     <?php echo $block->getChildHtml('tabs'); ?>
 </div>
-<div id="integrations-activate-permissions-content"></div>
\ No newline at end of file
+<div id="integrations-activate-permissions-content"></div>
diff --git a/app/code/Magento/Integration/view/adminhtml/templates/integration/activate/permissions/tab/webapi.phtml b/app/code/Magento/Integration/view/adminhtml/templates/integration/activate/permissions/tab/webapi.phtml
index a5131655334a89b678f9a250b4e2aa885905dfd8..7b853b53a815d9b3e41f8f5152c748cc30df5966 100644
--- a/app/code/Magento/Integration/view/adminhtml/templates/integration/activate/permissions/tab/webapi.phtml
+++ b/app/code/Magento/Integration/view/adminhtml/templates/integration/activate/permissions/tab/webapi.phtml
@@ -24,22 +24,20 @@
 </fieldset>
 <?php if (!$block->isTreeEmpty()): ?>
     <script>
-require(["jquery", "Magento_User/js/roles-tree"], function($){
+        require(["jquery", "Magento_User/js/roles-tree"], function($){
+            $.widget('mage.rolesTree', $.mage.rolesTree, {
+                _checkNode: function(event) {},
+                _checkNodes: function() {
+                    this._super();
+                    this.element.jstree('disable_hotkeys').jstree('hide_checkboxes')
+                        .find('li.jstree-unchecked').hide().end().find('li.jstree-checked').attr('rel', 'disabled');
+                }
+            });
 
-    $.widget('mage.rolesTree', $.mage.rolesTree, {
-        _checkNode: function(event) {},
-        _checkNodes: function() {
-            this._super();
-            this.element.jstree('disable_hotkeys').jstree('hide_checkboxes')
-                .find('li.jstree-unchecked').hide().end().find('li.jstree-checked').attr('rel', 'disabled');
-        }
-    });
-
-    $('[data-role="resource-tree"]').rolesTree({
-        'treeInitData': <?php /* @escapeNotVerified */ echo $block->getResourcesTreeJson() ?>,
-        'treeInitSelectedData': <?php /* @escapeNotVerified */ echo $block->getSelectedResourcesJson() ?>
-    });
-
-});
-</script>
+            $('[data-role="resource-tree"]').rolesTree({
+                'treeInitData': <?php /* @escapeNotVerified */ echo $block->getResourcesTreeJson() ?>,
+                'treeInitSelectedData': <?php /* @escapeNotVerified */ echo $block->getSelectedResourcesJson() ?>
+            });
+        });
+    </script>
 <?php endif ?>
diff --git a/app/code/Magento/Integration/view/adminhtml/web/integration.css b/app/code/Magento/Integration/view/adminhtml/web/integration.css
deleted file mode 100644
index a9415ce2e5cdd3ac3d1c1926ca523977d935c40a..0000000000000000000000000000000000000000
--- a/app/code/Magento/Integration/view/adminhtml/web/integration.css
+++ /dev/null
@@ -1,86 +0,0 @@
-/**
- * Copyright © 2016 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-
-#integration-popup-container #resource-tree {
-    max-height: 170px;
-    overflow: auto;
-}
-
-#integrationGrid_table .action {
-    border: none;
-    border-radius: 0;
-    background: none;
-    margin: 0;
-    padding: 0;
-    box-shadow: none;
-    text-shadow: none;
-    filter: none;
-}
-#integrationGrid_table .action:before {
-    font-family: 'MUI-Icons';
-    font-style: normal;
-    speak: none;
-    font-weight: normal;
-    font-size: 18px;
-    -webkit-font-smoothing: antialiased;
-    color: #b7b3ad;
-}
-#integrationGrid_table .action:hover:before {
-    color: #7e7e7e;
-}
-
-#integrationGrid_table .action.edit:before {
-    content: '\e05b';
-}
-
-#integrationGrid_table .action.info:before {
-    content: '\e07e';    /* TOFIX: Need to get the proper character code */
-}
-
-#integrationGrid_table .action.delete:before {
-    content: '\e07f';
-}
-
-#integrationGrid_table .action[disabled] {
-    color: #bbb3b4;
-    cursor: not-allowed;
-    opacity: 0.6;
-}
-
-#integrationGrid_table .icon-error {
-    margin-left: 15px;
-    color: #c00815;
-    font-size: 11px;
-}
-#integrationGrid_table .icon-error:before {
-    font-family: 'MUI-Icons';
-    content: "\e086";
-    font-size: 13px;
-    line-height: 13px;
-    overflow: hidden;
-    speak: none;
-    font-weight: normal;
-    -webkit-font-smoothing: antialiased;
-    display: inline-block;
-    vertical-align: middle;
-    text-align: center;
-    margin: -1px 5px 0 0;
-}
-
-.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset {
-    float: none;
-}
-
-.ui-dialog .ui-dialog-buttonpane {
-    text-align: right;
-}
-
-.no-close .ui-dialog-titlebar-close {
-    display: none;
-}
-
-#integration_token_base_fieldset input[readonly] {
-    cursor: copy;
-}
diff --git a/app/code/Magento/PageCache/view/frontend/web/js/page-cache.js b/app/code/Magento/PageCache/view/frontend/web/js/page-cache.js
index 8076048a5020853b3ce13ed6b8fa62a2e9022d88..ce9335138618305b1e71a1560b45bb2d60b7b690 100644
--- a/app/code/Magento/PageCache/view/frontend/web/js/page-cache.js
+++ b/app/code/Magento/PageCache/view/frontend/web/js/page-cache.js
@@ -37,7 +37,7 @@ define([
                     case 9: // DOCUMENT_NODE
                         var hostName = window.location.hostname,
                             iFrameHostName = $('<a>')
-                                .prop('href', element.prop('src'))
+                                .prop('href', $(element).prop('src'))
                                 .prop('hostname');
 
                         if (hostName === iFrameHostName) {
diff --git a/app/code/Magento/Payment/Model/MethodList.php b/app/code/Magento/Payment/Model/MethodList.php
index df0ddb9ed4b0c5490db8813f028998f2d69e6a4f..d547fe42f332ca4c49f0ff51ac16c0b59e538556 100644
--- a/app/code/Magento/Payment/Model/MethodList.php
+++ b/app/code/Magento/Payment/Model/MethodList.php
@@ -61,6 +61,7 @@ class MethodList
     {
         return $this->methodSpecificationFactory->create(
             [
+                AbstractMethod::CHECK_USE_CHECKOUT,
                 AbstractMethod::CHECK_USE_FOR_COUNTRY,
                 AbstractMethod::CHECK_USE_FOR_CURRENCY,
                 AbstractMethod::CHECK_ORDER_TOTAL_MIN_MAX,
diff --git a/app/code/Magento/Payment/Test/Unit/Model/MethodListTest.php b/app/code/Magento/Payment/Test/Unit/Model/MethodListTest.php
index b1e5bedb5a250e4daf48d8107eb421c305397d69..241f3fc4fcf532ff283d0a2afcdee833beb6e211 100644
--- a/app/code/Magento/Payment/Test/Unit/Model/MethodListTest.php
+++ b/app/code/Magento/Payment/Test/Unit/Model/MethodListTest.php
@@ -8,8 +8,8 @@
 
 namespace Magento\Payment\Test\Unit\Model;
 
-use Magento\Payment\Model\Method\Free;
-use \Magento\Payment\Model\MethodList;
+use Magento\Payment\Model\MethodList;
+use Magento\Payment\Model\Method\AbstractMethod;
 
 class MethodListTest extends \PHPUnit_Framework_TestCase
 {
@@ -68,6 +68,12 @@ class MethodListTest extends \PHPUnit_Framework_TestCase
 
         $this->specificationFactoryMock->expects($this->atLeastOnce())
             ->method('create')
+            ->with([
+                AbstractMethod::CHECK_USE_CHECKOUT,
+                AbstractMethod::CHECK_USE_FOR_COUNTRY,
+                AbstractMethod::CHECK_USE_FOR_CURRENCY,
+                AbstractMethod::CHECK_ORDER_TOTAL_MIN_MAX
+            ])
             ->will($this->returnValue($compositeMock));
 
         $storeMethods = [$methodMock];
diff --git a/app/code/Magento/Paypal/Setup/InstallSchema.php b/app/code/Magento/Paypal/Setup/InstallSchema.php
index d55782be8627915e7458874c5e6cc9fddd60224c..d0a07242ad75e03b334d7d23f289e7e9847546bd 100644
--- a/app/code/Magento/Paypal/Setup/InstallSchema.php
+++ b/app/code/Magento/Paypal/Setup/InstallSchema.php
@@ -165,7 +165,7 @@ class InstallSchema implements InstallSchemaInterface
             'Report Id'
         )->addColumn(
             'report_date',
-            \Magento\Framework\DB\Ddl\Table::TYPE_TIMESTAMP,
+            \Magento\Framework\DB\Ddl\Table::TYPE_DATE,
             null,
             [],
             'Report Date'
diff --git a/app/code/Magento/Paypal/etc/adminhtml/rules/payment_ca.xml b/app/code/Magento/Paypal/etc/adminhtml/rules/payment_ca.xml
index fb2b7456fb7c591431fd89af3b8973110d4c8eca..fc0ca6ebb6e9da5170061678910a1ac620d7fc03 100644
--- a/app/code/Magento/Paypal/etc/adminhtml/rules/payment_ca.xml
+++ b/app/code/Magento/Paypal/etc/adminhtml/rules/payment_ca.xml
@@ -143,9 +143,13 @@
             <rule type="paypalExpressDisable" event="activate-rule"/>
             <rule type="paypalExpressLockConfiguration" event="activate-rule"/>
             <rule type="paypalExpressMarkDisable" event="deactivate-rule">
+                <argument name="wpp_ca">wpp_ca</argument>
+                <argument name="paypal_payflowpro_ca">paypal_payflowpro_ca</argument>
                 <argument name="payflow_link_ca">payflow_link_ca</argument>
             </rule>
             <rule type="paypalExpressUnlockConfiguration" event="deactivate-rule">
+                <argument name="wpp_ca">wpp_ca</argument>
+                <argument name="paypal_payflowpro_ca">paypal_payflowpro_ca</argument>
                 <argument name="payflow_link_ca">payflow_link_ca</argument>
             </rule>
         </relation>
diff --git a/app/code/Magento/Paypal/etc/adminhtml/rules/payment_us.xml b/app/code/Magento/Paypal/etc/adminhtml/rules/payment_us.xml
index dfbb68283daa971c0db56b80252816bdc3b919c3..554b459d3c45a0db6cfe4c11bba36528ae4361d5 100644
--- a/app/code/Magento/Paypal/etc/adminhtml/rules/payment_us.xml
+++ b/app/code/Magento/Paypal/etc/adminhtml/rules/payment_us.xml
@@ -351,6 +351,7 @@
             <rule type="payflowExpressEnable" event="activate-rule"/>
             <rule type="payflowBmlEnable" event="activate-rule"/>
             <rule type="payflowShowSortOrder" event="activate-rule"/>
+            <rule type="payflowShowSortOrder" event="activate-express"/>
             <rule type="simpleDisable" event="deactivate-rule"/>
             <rule type="payflowExpressEnableConditional" event="deactivate-rule">
                 <argument name="payflow_advanced">payflow_advanced</argument>
@@ -363,6 +364,7 @@
                 <argument name="paypal_payflowpro_with_express_checkout">paypal_payflowpro_with_express_checkout</argument>
             </rule>
             <rule type="payflowHideSortOrder" event="deactivate-rule"/>
+            <rule type="payflowHideSortOrder" event="deactivate-express"/>
             <rule type="payflowBmlDisableConditionalExpress" event="deactivate-express"/>
             <rule type="payflowBmlDisableConditionalExpress" event=":load"/>
             <rule type="payflowBmlEnable" event="activate-express"/>
diff --git a/app/code/Magento/Paypal/view/frontend/layout/catalog_product_view.xml b/app/code/Magento/Paypal/view/frontend/layout/catalog_product_view.xml
index 3b91748bf0ce7f221745f2d8247853af6173a846..de139d98d5118c549ac922199d3c10d454c193fd 100644
--- a/app/code/Magento/Paypal/view/frontend/layout/catalog_product_view.xml
+++ b/app/code/Magento/Paypal/view/frontend/layout/catalog_product_view.xml
@@ -16,7 +16,7 @@
             </block>
         </referenceContainer>
         <referenceContainer name="product.info.addtocart">
-            <block class="Magento\Paypal\Block\Bml\Banners" name="bml.right.logo" after="product.info.addtocart.paypal" template="bml.phtml">
+            <block class="Magento\Paypal\Block\Bml\Banners" name="bml.right.logo" template="bml.phtml">
                 <arguments>
                     <argument name="section" xsi:type="string">productpage</argument>
                     <argument name="position" xsi:type="number">1</argument>
diff --git a/app/code/Magento/Quote/Observer/Frontend/Quote/Address/CollectTotalsObserver.php b/app/code/Magento/Quote/Observer/Frontend/Quote/Address/CollectTotalsObserver.php
index 2ff39f99e412e4d9d84d921da0111e5a04b476bb..cd8c6dabb532f3a4631b8eff5700b8096725df0a 100644
--- a/app/code/Magento/Quote/Observer/Frontend/Quote/Address/CollectTotalsObserver.php
+++ b/app/code/Magento/Quote/Observer/Frontend/Quote/Address/CollectTotalsObserver.php
@@ -9,6 +9,16 @@ use Magento\Framework\Event\ObserverInterface;
 
 class CollectTotalsObserver implements ObserverInterface
 {
+    /**
+     * @var \Magento\Customer\Api\AddressRepositoryInterface
+     */
+    private $addressRepository;
+
+    /**
+     * @var \Magento\Customer\Model\Session
+     */
+    private $customerSession;
+
     /**
      * @var \Magento\Customer\Helper\Address
      */
@@ -50,13 +60,17 @@ class CollectTotalsObserver implements ObserverInterface
         \Magento\Customer\Model\Vat $customerVat,
         VatValidator $vatValidator,
         \Magento\Customer\Api\Data\CustomerInterfaceFactory $customerDataFactory,
-        \Magento\Customer\Api\GroupManagementInterface $groupManagement
+        \Magento\Customer\Api\GroupManagementInterface $groupManagement,
+        \Magento\Customer\Api\AddressRepositoryInterface $addressRepository,
+        \Magento\Customer\Model\Session $customerSession
     ) {
         $this->customerVat = $customerVat;
         $this->customerAddressHelper = $customerAddressHelper;
         $this->vatValidator = $vatValidator;
         $this->customerDataFactory = $customerDataFactory;
         $this->groupManagement = $groupManagement;
+        $this->addressRepository = $addressRepository;
+        $this->customerSession = $customerSession;
     }
 
     /**
@@ -84,6 +98,15 @@ class CollectTotalsObserver implements ObserverInterface
         }
         $customerCountryCode = $address->getCountryId();
         $customerVatNumber = $address->getVatId();
+
+        /** try to get data from customer if quote address needed data is empty */
+        if (empty($customerCountryCode) && empty($customerVatNumber) && $customer->getDefaultShipping()) {
+            $customerAddress = $this->addressRepository->getById($customer->getDefaultShipping());
+
+            $customerCountryCode = $customerAddress->getCountryId();
+            $customerVatNumber = $customerAddress->getVatId();
+        }
+
         $groupId = null;
         if (empty($customerVatNumber) || false == $this->customerVat->isCountryInEU($customerCountryCode)) {
             $groupId = $customer->getId() ? $this->groupManagement->getDefaultGroup(
@@ -101,6 +124,7 @@ class CollectTotalsObserver implements ObserverInterface
         if ($groupId) {
             $address->setPrevQuoteCustomerGroupId($quote->getCustomerGroupId());
             $quote->setCustomerGroupId($groupId);
+            $this->customerSession->setCustomerGroupId($groupId);
             $customer->setGroupId($groupId);
             $quote->setCustomer($customer);
         }
diff --git a/app/code/Magento/Quote/Test/Unit/Observer/Frontend/Quote/Address/CollectTotalsObserverTest.php b/app/code/Magento/Quote/Test/Unit/Observer/Frontend/Quote/Address/CollectTotalsObserverTest.php
index fedcd43bfdd50304651736f3e4e3de244c2d9cbd..1233535f20e107a1436d13a1094203229254e026 100644
--- a/app/code/Magento/Quote/Test/Unit/Observer/Frontend/Quote/Address/CollectTotalsObserverTest.php
+++ b/app/code/Magento/Quote/Test/Unit/Observer/Frontend/Quote/Address/CollectTotalsObserverTest.php
@@ -14,7 +14,7 @@ namespace Magento\Quote\Test\Unit\Observer\Frontend\Quote\Address;
 class CollectTotalsObserverTest extends \PHPUnit_Framework_TestCase
 {
     /**
-     * @var \Magento\Quote\Observer\Frontend\Quote\Address\CollectTotalsObserver;
+     * @var \Magento\Quote\Observer\Frontend\Quote\Address\CollectTotalsObserver
      */
     protected $model;
 
@@ -23,11 +23,21 @@ class CollectTotalsObserverTest extends \PHPUnit_Framework_TestCase
      */
     protected $customerAddressMock;
 
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $customerSession;
+
     /**
      * @var \PHPUnit_Framework_MockObject_MockObject
      */
     protected $customerVatMock;
 
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $addressRepository;
+
     /**
      * @var \PHPUnit_Framework_MockObject_MockObject
      */
@@ -172,6 +182,11 @@ class CollectTotalsObserverTest extends \PHPUnit_Framework_TestCase
             ->method('getCustomer')
             ->will($this->returnValue($this->customerMock));
 
+        $this->addressRepository = $this->getMock(\Magento\Customer\Api\AddressRepositoryInterface::class);
+        $this->customerSession = $this->getMockBuilder(\Magento\Customer\Model\Session::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
         $this->customerMock->expects($this->any())->method('getStoreId')->will($this->returnValue($this->storeId));
 
         $this->model = new \Magento\Quote\Observer\Frontend\Quote\Address\CollectTotalsObserver(
@@ -179,7 +194,9 @@ class CollectTotalsObserverTest extends \PHPUnit_Framework_TestCase
             $this->customerVatMock,
             $this->vatValidatorMock,
             $this->customerDataFactoryMock,
-            $this->groupManagementMock
+            $this->groupManagementMock,
+            $this->addressRepository,
+            $this->customerSession
         );
     }
 
@@ -319,4 +336,75 @@ class CollectTotalsObserverTest extends \PHPUnit_Framework_TestCase
             ->willReturn($this->customerMock);
         $this->model->execute($this->observerMock);
     }
+
+    public function testDispatchWithEmptyShippingAddress()
+    {
+        $customerCountryCode = "DE";
+        $customerVat = "123123123";
+        $defaultShipping = 1;
+
+        $customerAddress = $this->getMock(\Magento\Customer\Api\Data\AddressInterface::class);
+        $customerAddress->expects($this->once())
+            ->method("getCountryId")
+            ->willReturn($customerCountryCode);
+
+        $customerAddress->expects($this->once())
+            ->method("getVatId")
+            ->willReturn($customerVat);
+        $this->addressRepository->expects($this->once())
+            ->method("getById")
+            ->with($defaultShipping)
+            ->willReturn($customerAddress);
+
+        $this->customerMock->expects($this->atLeastOnce())
+            ->method("getDefaultShipping")
+            ->willReturn($defaultShipping);
+
+        $this->vatValidatorMock->expects($this->once())
+            ->method('isEnabled')
+            ->with($this->quoteAddressMock, $this->storeId)
+            ->will($this->returnValue(true));
+
+        $this->quoteAddressMock->expects($this->once())
+            ->method('getCountryId')
+            ->will($this->returnValue(null));
+        $this->quoteAddressMock->expects($this->once())
+            ->method('getVatId')
+            ->will($this->returnValue(null));
+
+        $this->customerVatMock->expects($this->once())
+            ->method('isCountryInEU')
+            ->with($customerCountryCode)
+            ->willReturn(true);
+
+        $this->quoteMock->expects($this->once())
+            ->method('getCustomerGroupId')
+            ->will($this->returnValue('customerGroupId'));
+        $validationResult = ['some' => 'result'];
+        $this->customerVatMock->expects($this->once())
+            ->method('getCustomerGroupIdBasedOnVatNumber')
+            ->with($customerCountryCode, $validationResult, $this->storeId)
+            ->will($this->returnValue('customerGroupId'));
+        $this->customerSession->expects($this->once())
+            ->method("setCustomerGroupId")
+            ->with('customerGroupId');
+
+        $this->vatValidatorMock->expects($this->once())
+            ->method('validate')
+            ->with($this->quoteAddressMock, $this->storeId)
+            ->will($this->returnValue($validationResult));
+
+        /** Assertions */
+        $this->quoteAddressMock->expects($this->once())
+            ->method('setPrevQuoteCustomerGroupId')
+            ->with('customerGroupId');
+
+        $this->quoteMock->expects($this->once())->method('setCustomerGroupId')->with('customerGroupId');
+        $this->quoteMock->expects($this->once())->method('setCustomer')->with($this->customerMock);
+        $this->customerDataFactoryMock->expects($this->any())
+            ->method('create')
+            ->willReturn($this->customerMock);
+        $this->model->execute($this->observerMock);
+
+    }
 }
diff --git a/app/code/Magento/Reports/Block/Adminhtml/Filter/Form.php b/app/code/Magento/Reports/Block/Adminhtml/Filter/Form.php
index e71cc97de683b1cd788e40beae556eaa403a5eef..437f7f6cd2f67a924075aff22ac68ef8c827b022 100644
--- a/app/code/Magento/Reports/Block/Adminhtml/Filter/Form.php
+++ b/app/code/Magento/Reports/Block/Adminhtml/Filter/Form.php
@@ -160,6 +160,7 @@ class Form extends \Magento\Backend\Block\Widget\Form\Generic
                 'label' => __('From'),
                 'title' => __('From'),
                 'required' => true,
+                'css_class' => 'admin__field-small',
                 'class' => 'admin__control-text'
             ]
         );
@@ -173,6 +174,7 @@ class Form extends \Magento\Backend\Block\Widget\Form\Generic
                 'label' => __('To'),
                 'title' => __('To'),
                 'required' => true,
+                'css_class' => 'admin__field-small',
                 'class' => 'admin__control-text'
             ]
         );
diff --git a/app/code/Magento/Reports/view/adminhtml/templates/report/grid/container.phtml b/app/code/Magento/Reports/view/adminhtml/templates/report/grid/container.phtml
index 9ae58816b17a36dd0179f8497bacb61860140016..f927a4cda56156a3e08a0a3a639f052d47d16487 100644
--- a/app/code/Magento/Reports/view/adminhtml/templates/report/grid/container.phtml
+++ b/app/code/Magento/Reports/view/adminhtml/templates/report/grid/container.phtml
@@ -4,7 +4,6 @@
  * See COPYING.txt for license details.
  */
 
-// @codingStandardsIgnoreFile
 
 ?>
 
@@ -24,11 +23,15 @@ require([
 //<![CDATA[
     jQuery('#filter_form').mage('validation', {errorClass: 'mage-error'});
     function filterFormSubmit() {
-        var filters = $$('#filter_form input', '#filter_form select');
-        var elements = [];
-        for(var i in filters){
-            if(filters[i].value && filters[i].value.length && !filters[i].disabled) elements.push(filters[i]);
+        var filters = $$('#filter_form input', '#filter_form select'),
+            elements = [];
+
+        for (var i in filters) {
+            if (filters[i].value && filters[i].value.length && !filters[i].disabled) {
+                elements.push(filters[i]);
+            }
         }
+
         if (jQuery('#filter_form').valid()) {
             setLocation('<?php /* @escapeNotVerified */ echo $block->getFilterUrl(); ?>filter/'+Base64.encode(Form.serializeElements(elements))+'/');
         }
diff --git a/app/code/Magento/Sales/Block/Order/History.php b/app/code/Magento/Sales/Block/Order/History.php
index 683234666262a7d2cc86b70a8d2c64d4b824b48a..9b212d40bfa6af7937f14aa31746b84a7ab507db 100644
--- a/app/code/Magento/Sales/Block/Order/History.php
+++ b/app/code/Magento/Sales/Block/Order/History.php
@@ -5,6 +5,9 @@
  */
 namespace Magento\Sales\Block\Order;
 
+use \Magento\Framework\App\ObjectManager;
+use \Magento\Sales\Model\ResourceModel\Order\CollectionFactoryInterface;
+
 /**
  * Sales order history block
  */
@@ -33,6 +36,11 @@ class History extends \Magento\Framework\View\Element\Template
     /** @var \Magento\Sales\Model\ResourceModel\Order\Collection */
     protected $orders;
 
+    /**
+     * @var CollectionFactoryInterface
+     */
+    private $orderCollectionFactory;
+
     /**
      * @param \Magento\Framework\View\Element\Template\Context $context
      * @param \Magento\Sales\Model\ResourceModel\Order\CollectionFactory $orderCollectionFactory
@@ -62,6 +70,19 @@ class History extends \Magento\Framework\View\Element\Template
         $this->pageConfig->getTitle()->set(__('My Orders'));
     }
 
+    /**
+     * @return CollectionFactoryInterface
+     *
+     * @deprecated
+     */
+    private function getOrderCollectionFactory()
+    {
+        if ($this->orderCollectionFactory === null) {
+            $this->orderCollectionFactory = ObjectManager::getInstance()->get(CollectionFactoryInterface::class);
+        }
+        return $this->orderCollectionFactory;
+    }
+
     /**
      * @return bool|\Magento\Sales\Model\ResourceModel\Order\Collection
      */
@@ -71,11 +92,8 @@ class History extends \Magento\Framework\View\Element\Template
             return false;
         }
         if (!$this->orders) {
-            $this->orders = $this->_orderCollectionFactory->create()->addFieldToSelect(
+            $this->orders = $this->getOrderCollectionFactory()->create($customerId)->addFieldToSelect(
                 '*'
-            )->addFieldToFilter(
-                'customer_id',
-                $customerId
             )->addFieldToFilter(
                 'status',
                 ['in' => $this->_orderConfig->getVisibleOnFrontStatuses()]
diff --git a/app/code/Magento/Sales/Block/Order/History/Container.php b/app/code/Magento/Sales/Block/Order/History/Container.php
new file mode 100644
index 0000000000000000000000000000000000000000..cc20f20ea84c085d62588bca6dfd265e8de224c8
--- /dev/null
+++ b/app/code/Magento/Sales/Block/Order/History/Container.php
@@ -0,0 +1,59 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Block\Order\History;
+
+/**
+ * Sales order history extra container block
+ */
+class Container extends \Magento\Framework\View\Element\Template
+{
+    /**
+     * @var \Magento\Sales\Api\Data\OrderInterface
+     */
+    private $order;
+
+    /**
+     * Set order
+     *
+     * @param \Magento\Sales\Api\Data\OrderInterface $order
+     * @return $this
+     */
+    public function setOrder(\Magento\Sales\Api\Data\OrderInterface $order)
+    {
+        $this->order = $order;
+        return $this;
+    }
+
+    /**
+     * Get order
+     *
+     * @return \Magento\Sales\Api\Data\OrderInterface
+     */
+    private function getOrder()
+    {
+        return $this->order;
+    }
+
+    /**
+     * Here we set an order for children during retrieving their HTML
+     *
+     * @param string $alias
+     * @param bool $useCache
+     * @return string
+     * @throws \Magento\Framework\Exception\LocalizedException
+     */
+    public function getChildHtml($alias = '', $useCache = false)
+    {
+        $layout = $this->getLayout();
+        if ($layout) {
+            $name = $this->getNameInLayout();
+            foreach ($layout->getChildBlocks($name) as $child) {
+                $child->setOrder($this->getOrder());
+            }
+        }
+        return parent::getChildHtml($alias, $useCache);
+    }
+}
diff --git a/app/code/Magento/Sales/Model/Order.php b/app/code/Magento/Sales/Model/Order.php
index 7ed85998bf520075a4a240795593cfcda37dd6b6..8984d2312db36840282fecc7f4abc811357837e2 100644
--- a/app/code/Magento/Sales/Model/Order.php
+++ b/app/code/Magento/Sales/Model/Order.php
@@ -1442,10 +1442,12 @@ class Order extends AbstractModel implements EntityInterface, OrderInterface
      */
     public function setPayment(\Magento\Sales\Api\Data\OrderPaymentInterface $payment = null)
     {
-        $payment->setOrder($this)->setParentId($this->getId());
-        if (!$payment->getId()) {
-            $this->setData(OrderInterface::PAYMENT, $payment);
-            $this->setDataChanges(true);
+        $this->setData(OrderInterface::PAYMENT, $payment);
+        if ($payment !== null) {
+            $payment->setOrder($this)->setParentId($this->getId());
+            if (!$payment->getId()) {
+                $this->setDataChanges(true);
+            }
         }
         return $payment;
     }
diff --git a/app/code/Magento/Sales/Model/ResourceModel/Order/CollectionFactory.php b/app/code/Magento/Sales/Model/ResourceModel/Order/CollectionFactory.php
new file mode 100644
index 0000000000000000000000000000000000000000..c2b9886e3fa52f54c0ba5f6b1456d5d493631313
--- /dev/null
+++ b/app/code/Magento/Sales/Model/ResourceModel/Order/CollectionFactory.php
@@ -0,0 +1,56 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Sales\Model\ResourceModel\Order;
+
+/**
+ * Class CollectionFactory
+ */
+class CollectionFactory implements CollectionFactoryInterface
+{
+    /**
+     * Object Manager instance
+     *
+     * @var \Magento\Framework\ObjectManagerInterface
+     */
+    private $objectManager = null;
+
+    /**
+     * Instance name to create
+     *
+     * @var string
+     */
+    private $instanceName = null;
+
+    /**
+     * Factory constructor
+     *
+     * @param \Magento\Framework\ObjectManagerInterface $objectManager
+     * @param string $instanceName
+     */
+    public function __construct(
+        \Magento\Framework\ObjectManagerInterface $objectManager,
+        $instanceName = '\\Magento\\Sales\\Model\\ResourceModel\\Order\\Collection'
+    ) {
+        $this->objectManager = $objectManager;
+        $this->instanceName = $instanceName;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function create($customerId = null)
+    {
+        /** @var \Magento\Sales\Model\ResourceModel\Order\Collection $collection */
+        $collection = $this->objectManager->create($this->instanceName);
+
+        if ($customerId) {
+            $collection->addFieldToFilter('customer_id', $customerId);
+        }
+
+        return $collection;
+    }
+}
diff --git a/app/code/Magento/Sales/Model/ResourceModel/Order/CollectionFactoryInterface.php b/app/code/Magento/Sales/Model/ResourceModel/Order/CollectionFactoryInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..27a9a640906b214705833c9f53ef25b157f89802
--- /dev/null
+++ b/app/code/Magento/Sales/Model/ResourceModel/Order/CollectionFactoryInterface.php
@@ -0,0 +1,21 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Sales\Model\ResourceModel\Order;
+
+/**
+ * Class CollectionFactoryInterface
+ */
+interface CollectionFactoryInterface
+{
+    /**
+     * Create class instance with specified parameters
+     *
+     * @param int $customerId
+     * @return \Magento\Sales\Model\ResourceModel\Order\Collection
+     */
+    public function create($customerId = null);
+}
diff --git a/app/code/Magento/Sales/Setup/InstallSchema.php b/app/code/Magento/Sales/Setup/InstallSchema.php
index 0801da31d117115b14b77de9a8f8313a98d612ca..6daa1b42b3a03734a1aeabcf46f3a91d0aa0198a 100644
--- a/app/code/Magento/Sales/Setup/InstallSchema.php
+++ b/app/code/Magento/Sales/Setup/InstallSchema.php
@@ -3216,12 +3216,6 @@ class InstallSchema implements InstallSchemaInterface
             '12,4',
             [],
             'Grand Total'
-        )->addColumn(
-            'base_grand_total',
-            \Magento\Framework\DB\Ddl\Table::TYPE_DECIMAL,
-            '12,4',
-            [],
-            'Base Grand Total'
         )->addColumn(
             'created_at',
             \Magento\Framework\DB\Ddl\Table::TYPE_TIMESTAMP,
@@ -3240,9 +3234,6 @@ class InstallSchema implements InstallSchemaInterface
         )->addIndex(
             $installer->getIdxName('sales_invoice_grid', ['grand_total']),
             ['grand_total']
-        )->addIndex(
-            $installer->getIdxName('sales_invoice_grid', ['base_grand_total']),
-            ['base_grand_total']
         )->addIndex(
             $installer->getIdxName('sales_invoice_grid', ['order_id']),
             ['order_id']
diff --git a/app/code/Magento/Sales/Setup/SalesSetup.php b/app/code/Magento/Sales/Setup/SalesSetup.php
index d69147ba925f02f169c74931194578c05f723faa..3c72ce093d87c5b75a5ce60f55fc83aa7b086dae 100644
--- a/app/code/Magento/Sales/Setup/SalesSetup.php
+++ b/app/code/Magento/Sales/Setup/SalesSetup.php
@@ -18,6 +18,26 @@ use Magento\Framework\Setup\ModuleDataSetupInterface;
  */
 class SalesSetup extends \Magento\Eav\Setup\EavSetup
 {
+    /**
+     * This should be set explicitly
+     */
+    const ORDER_ENTITY_TYPE_ID = 5;
+
+    /**
+     * This should be set explicitly
+     */
+    const INVOICE_PRODUCT_ENTITY_TYPE_ID = 6;
+
+    /**
+     * This should be set explicitly
+     */
+    const CREDITMEMO_PRODUCT_ENTITY_TYPE_ID = 7;
+
+    /**
+     * This should be set explicitly
+     */
+    const SHIPMENT_PRODUCT_ENTITY_TYPE_ID = 8;
+
     /**
      * @var ScopeConfigInterface
      */
@@ -214,6 +234,7 @@ class SalesSetup extends \Magento\Eav\Setup\EavSetup
     {
         $entities = [
             'order' => [
+                'entity_type_id' => self::ORDER_ENTITY_TYPE_ID,
                 'entity_model' => 'Magento\Sales\Model\ResourceModel\Order',
                 'table' => 'sales_order',
                 'increment_model' => 'Magento\Eav\Model\Entity\Increment\NumericValue',
@@ -221,6 +242,7 @@ class SalesSetup extends \Magento\Eav\Setup\EavSetup
                 'attributes' => [],
             ],
             'invoice' => [
+                'entity_type_id' => self::INVOICE_PRODUCT_ENTITY_TYPE_ID,
                 'entity_model' => 'Magento\Sales\Model\ResourceModel\Order\Invoice',
                 'table' => 'sales_invoice',
                 'increment_model' => 'Magento\Eav\Model\Entity\Increment\NumericValue',
@@ -228,6 +250,7 @@ class SalesSetup extends \Magento\Eav\Setup\EavSetup
                 'attributes' => [],
             ],
             'creditmemo' => [
+                'entity_type_id' => self::CREDITMEMO_PRODUCT_ENTITY_TYPE_ID,
                 'entity_model' => 'Magento\Sales\Model\ResourceModel\Order\Creditmemo',
                 'table' => 'sales_creditmemo',
                 'increment_model' => 'Magento\Eav\Model\Entity\Increment\NumericValue',
@@ -235,6 +258,7 @@ class SalesSetup extends \Magento\Eav\Setup\EavSetup
                 'attributes' => [],
             ],
             'shipment' => [
+                'entity_type_id' => self::SHIPMENT_PRODUCT_ENTITY_TYPE_ID,
                 'entity_model' => 'Magento\Sales\Model\ResourceModel\Order\Shipment',
                 'table' => 'sales_shipment',
                 'increment_model' => 'Magento\Eav\Model\Entity\Increment\NumericValue',
diff --git a/app/code/Magento/Sales/Setup/UpgradeSchema.php b/app/code/Magento/Sales/Setup/UpgradeSchema.php
index fbf2e929a2f0f39ff19716c11e3209e33d5be3e8..907d782e8deafd5649712ead99a6d94cbc93c1f1 100644
--- a/app/code/Magento/Sales/Setup/UpgradeSchema.php
+++ b/app/code/Magento/Sales/Setup/UpgradeSchema.php
@@ -7,6 +7,7 @@ namespace Magento\Sales\Setup;
 use Magento\Framework\Setup\UpgradeSchemaInterface;
 use Magento\Framework\Setup\ModuleContextInterface;
 use Magento\Framework\Setup\SchemaSetupInterface;
+use Magento\Framework\DB\Adapter\AdapterInterface;
 
 /**
  * @codeCoverageIgnore
@@ -53,5 +54,43 @@ class UpgradeSchema implements UpgradeSchemaInterface
 
             $installer->endSetup();
         }
+        if (version_compare($context->getVersion(), '2.0.3', '<')) {
+            $this->addColumnBaseGrandTotal($installer);
+            $this->addIndexBaseGrandTotal($installer);
+        }
+    }
+
+    /**
+     * @param SchemaSetupInterface $installer
+     * @return void
+     */
+    private function addColumnBaseGrandTotal(SchemaSetupInterface $installer)
+    {
+        $connection = $installer->getConnection();
+        $connection->addColumn(
+            $installer->getTable('sales_invoice_grid'),
+            'base_grand_total',
+            [
+                'type' => \Magento\Framework\DB\Ddl\Table::TYPE_DECIMAL,
+                'nullable' => true,
+                'length' => '12,4',
+                'comment' => 'Base Grand Total',
+                'after' => 'grand_total'
+            ]
+        );
+    }
+
+    /**
+     * @param SchemaSetupInterface $installer
+     * @return void
+     */
+    private function addIndexBaseGrandTotal(SchemaSetupInterface $installer)
+    {
+        $connection = $installer->getConnection();
+        $connection->addIndex(
+            $installer->getTable('sales_invoice_grid'),
+            $installer->getIdxName('sales_invoice_grid', ['base_grand_total']),
+            ['base_grand_total']
+        );
     }
-}
\ No newline at end of file
+}
diff --git a/app/code/Magento/Sales/Test/Unit/Block/Order/HistoryTest.php b/app/code/Magento/Sales/Test/Unit/Block/Order/HistoryTest.php
index 9e8f325857b6bb551f996de278169272c3c01e39..a4709ed7ccc98695e3a4701b7067646bb4b957e6 100644
--- a/app/code/Magento/Sales/Test/Unit/Block/Order/HistoryTest.php
+++ b/app/code/Magento/Sales/Test/Unit/Block/Order/HistoryTest.php
@@ -22,6 +22,16 @@ class HistoryTest extends \PHPUnit_Framework_TestCase
      */
     protected $orderCollectionFactory;
 
+    /**
+     * @var \Magento\Sales\Model\ResourceModel\Order\CollectionFactoryInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $orderCollectionFactoryInterface;
+
+    /**
+     * @var \Magento\Framework\App\ObjectManager|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $objectManager;
+
     /**
      * @var \Magento\Customer\Model\Session|\PHPUnit_Framework_MockObject_MockObject
      */
@@ -48,6 +58,14 @@ class HistoryTest extends \PHPUnit_Framework_TestCase
         $this->orderCollectionFactory =
             $this->getMockBuilder('Magento\Sales\Model\ResourceModel\Order\CollectionFactory')
             ->disableOriginalConstructor()->setMethods(['create'])->getMock();
+        $this->orderCollectionFactoryInterface =
+            $this->getMockBuilder(\Magento\Sales\Model\ResourceModel\Order\CollectionFactoryInterface::class)
+                ->disableOriginalConstructor()->setMethods(['create'])->getMock();
+        $this->objectManager = $this->getMock(\Magento\Framework\ObjectManagerInterface::class, [], [], '', false);
+        $this->objectManager->expects($this->any())
+            ->method('get')
+            ->will($this->returnValue($this->orderCollectionFactoryInterface));
+        \Magento\Framework\App\ObjectManager::setInstance($this->objectManager);
 
         $this->customerSession = $this->getMockBuilder('Magento\Customer\Model\Session')
             ->setMethods(['getCustomerId'])->disableOriginalConstructor()->getMock();
@@ -94,18 +112,14 @@ class HistoryTest extends \PHPUnit_Framework_TestCase
             ->with($this->equalTo('*'))
             ->will($this->returnSelf());
         $orderCollection->expects($this->at(1))
-            ->method('addFieldToFilter')
-            ->with('customer_id', $this->equalTo($customerId))
-            ->will($this->returnSelf());
-        $orderCollection->expects($this->at(2))
             ->method('addFieldToFilter')
             ->with('status', $this->equalTo(['in' => $statuses]))
             ->will($this->returnSelf());
-        $orderCollection->expects($this->at(3))
+        $orderCollection->expects($this->at(2))
             ->method('setOrder')
             ->with('created_at', 'desc')
             ->will($this->returnSelf());
-        $this->orderCollectionFactory->expects($this->atLeastOnce())
+        $this->orderCollectionFactoryInterface->expects($this->atLeastOnce())
             ->method('create')
             ->will($this->returnValue($orderCollection));
         $this->pageConfig->expects($this->atLeastOnce())
diff --git a/app/code/Magento/Sales/Test/Unit/Model/OrderTest.php b/app/code/Magento/Sales/Test/Unit/Model/OrderTest.php
index 399092745977a5b480d2218ab145e9ea81e767e2..e8bf1ef1bfe4fc50982e7243ef13d127291a9b2b 100644
--- a/app/code/Magento/Sales/Test/Unit/Model/OrderTest.php
+++ b/app/code/Magento/Sales/Test/Unit/Model/OrderTest.php
@@ -5,6 +5,7 @@
  */
 namespace Magento\Sales\Test\Unit\Model;
 
+use Magento\Sales\Api\Data\OrderInterface;
 use Magento\Sales\Model\Order;
 use Magento\Sales\Model\ResourceModel\Order\Status\History\CollectionFactory as HistoryCollectionFactory;
 
@@ -757,6 +758,115 @@ class OrderTest extends \PHPUnit_Framework_TestCase
         $this->assertSame($this->order, $this->order->loadByIncrementIdAndStoreId($incrementId, $storeId));
     }
 
+    public function testSetPaymentWithId()
+    {
+        $this->order->setId(123);
+        $payment = $this->getMockBuilder(\Magento\Sales\Model\Order\Payment::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->order->setData(OrderInterface::PAYMENT, $payment);
+        $this->order->setDataChanges(false);
+
+        $payment->expects($this->once())
+            ->method('setOrder')
+            ->with($this->order)
+            ->willReturnSelf();
+
+        $payment->expects($this->once())
+            ->method('setParentId')
+            ->with(123)
+            ->willReturnSelf();
+
+        $payment->expects($this->any())
+            ->method('getId')
+            ->willReturn(1);
+
+        $this->order->setPayment($payment);
+
+        $this->assertEquals(
+            $this->order->getData(
+                OrderInterface::PAYMENT
+            ),
+            $payment
+        );
+
+        $this->assertFalse(
+            $this->order->hasDataChanges()
+        );
+    }
+
+    public function testSetPaymentNoId()
+    {
+        $this->order->setId(123);
+        $this->order->setDataChanges(false);
+
+        $payment = $this->getMockBuilder(\Magento\Sales\Model\Order\Payment::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $payment->expects($this->once())
+            ->method('setOrder')
+            ->with($this->order)
+            ->willReturnSelf();
+
+        $payment->expects($this->once())
+            ->method('setParentId')
+            ->with(123)
+            ->willReturnSelf();
+
+        $payment->expects($this->any())
+            ->method('getId')
+            ->willReturn(null);
+
+        $this->order->setPayment($payment);
+
+        $this->assertEquals(
+            $this->order->getData(
+                OrderInterface::PAYMENT
+            ),
+            $payment
+        );
+
+        $this->assertTrue(
+            $this->order->hasDataChanges()
+        );
+    }
+
+    public function testSetPaymentNull()
+    {
+        $this->assertEquals(null, $this->order->setPayment(null));
+
+        $this->assertEquals(
+            $this->order->getData(
+                OrderInterface::PAYMENT
+            ),
+            null
+        );
+
+        $this->assertTrue(
+            $this->order->hasDataChanges()
+        );
+    }
+
+    public function testResetOrderWillResetPayment()
+    {
+        $payment = $this->getMockBuilder(\Magento\Sales\Model\Order\Payment::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->order->setData(OrderInterface::PAYMENT, $payment);
+        $this->order->reset();
+        $this->assertEquals(
+            $this->order->getData(
+                OrderInterface::PAYMENT
+            ),
+            null
+        );
+
+        $this->assertTrue(
+            $this->order->hasDataChanges()
+        );
+    }
+
     public function notInvoicingStatesProvider()
     {
         return [
diff --git a/app/code/Magento/Sales/etc/di.xml b/app/code/Magento/Sales/etc/di.xml
index 209e46c3240b675f32622f3547331856bf87a1eb..78dd17256703ad32b852262899a3b3a6b97545b6 100644
--- a/app/code/Magento/Sales/etc/di.xml
+++ b/app/code/Magento/Sales/etc/di.xml
@@ -80,6 +80,7 @@
     <preference for="Magento\Sales\Model\Spi\ShipmentResourceInterface" type="Magento\Sales\Model\ResourceModel\Order\Shipment"/>
     <preference for="Magento\Sales\Model\Spi\ShipmentTrackResourceInterface" type="Magento\Sales\Model\ResourceModel\Order\Shipment\Track"/>
     <preference for="Magento\Sales\Model\Spi\TransactionResourceInterface" type="Magento\Sales\Model\ResourceModel\Order\Payment\Transaction"/>
+    <preference for="Magento\Sales\Model\ResourceModel\Order\CollectionFactoryInterface" type="Magento\Sales\Model\ResourceModel\Order\CollectionFactory"/>
     <type name="Magento\Sales\Model\ResourceModel\Report" shared="false"/>
     <type name="Magento\Sales\Model\Order\Pdf\Config\Reader">
         <arguments>
diff --git a/app/code/Magento/Sales/etc/module.xml b/app/code/Magento/Sales/etc/module.xml
index 19956e89184471dfb60b25b58e5ccba168e4e33d..88d6e25d31fb6c4ed9777595296e969028b154f2 100644
--- a/app/code/Magento/Sales/etc/module.xml
+++ b/app/code/Magento/Sales/etc/module.xml
@@ -6,7 +6,7 @@
  */
 -->
 <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
-    <module name="Magento_Sales" setup_version="2.0.2">
+    <module name="Magento_Sales" setup_version="2.0.3">
         <sequence>
             <module name="Magento_Rule"/>
             <module name="Magento_Catalog"/>
diff --git a/app/code/Magento/Sales/view/adminhtml/templates/order/address/form.phtml b/app/code/Magento/Sales/view/adminhtml/templates/order/address/form.phtml
index 1a8985d2c3ccfb37782222bcd281f60509a54bcf..b2b7abf77acc9a938e7d0a6329ef05ca8aa6dd72 100644
--- a/app/code/Magento/Sales/view/adminhtml/templates/order/address/form.phtml
+++ b/app/code/Magento/Sales/view/adminhtml/templates/order/address/form.phtml
@@ -18,7 +18,7 @@
         <span><?php /* @escapeNotVerified */ echo $block->getHeaderText() ?></span>
     </legend>
     <br>
-    <div class="form-inline">
+    <div class="form-inline" data-mage-init='{"Magento_Sales/order/edit/address/form":{}}'>
         <?php echo $block->getForm()->toHtml() ?>
     </div>
 </fieldset>
diff --git a/app/code/Magento/Sales/view/adminhtml/web/order/edit/address/form.js b/app/code/Magento/Sales/view/adminhtml/web/order/edit/address/form.js
new file mode 100644
index 0000000000000000000000000000000000000000..bdcb2cc8a574601d78ba7ae7ed70d7b3030108ba
--- /dev/null
+++ b/app/code/Magento/Sales/view/adminhtml/web/order/edit/address/form.js
@@ -0,0 +1,34 @@
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+define([
+    'jquery'
+], function ($) {
+    'use strict';
+
+    /**
+     * Currently Magento App stores both  region_id and region (as text) values.
+     * To prevent missing region (as text) we need to copy it in hidden field.
+     * @param {Array} config
+     * @param {String} element
+     */
+    return function (config, element) {
+        var form = $(element),
+            regionId = form.find('#region_id'),
+
+            /**
+             * Set region callback
+             */
+            setRegion = function () {
+                form.find('#region').val(regionId.filter(':visible').find(':selected').text());
+            };
+
+        if (regionId.is('visible')) {
+            setRegion();
+        }
+
+        regionId.on('change', setRegion);
+        form.find('#country_id').on('change', setRegion);
+    };
+});
diff --git a/app/code/Magento/Sales/view/frontend/layout/customer_account_index.xml b/app/code/Magento/Sales/view/frontend/layout/customer_account_index.xml
index bf62f4c5c3a4ed07fd649573c5108fdfaf9e8387..cd3b81593734ffbfe49c4669ef9366785a09bdeb 100644
--- a/app/code/Magento/Sales/view/frontend/layout/customer_account_index.xml
+++ b/app/code/Magento/Sales/view/frontend/layout/customer_account_index.xml
@@ -8,7 +8,7 @@
 <page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
     <body>
         <referenceContainer name="content">
-            <block class="Magento\Sales\Block\Order\Recent" name="customer_account_dashboard_top" after="customer_account_dashboard_hello" template="order/recent.phtml"/>
+            <block class="Magento\Sales\Block\Order\Recent" name="customer_account_dashboard_top" template="order/recent.phtml"/>
         </referenceContainer>
     </body>
 </page>
diff --git a/app/code/Magento/Sales/view/frontend/layout/sales_order_history.xml b/app/code/Magento/Sales/view/frontend/layout/sales_order_history.xml
index 85b8a83a198f54facd9d931a684881056e12625c..c4c93b9655aa148ed31fdac6aa94c352faf13e9e 100644
--- a/app/code/Magento/Sales/view/frontend/layout/sales_order_history.xml
+++ b/app/code/Magento/Sales/view/frontend/layout/sales_order_history.xml
@@ -11,6 +11,12 @@
         <referenceContainer name="content">
             <block class="Magento\Sales\Block\Order\History" name="sales.order.history" cacheable="false">
                 <container name="sales.order.history.info" as="info" label="Order History Info"/>
+                <container name="sales.order.history.extra.column.header" as="extra.column.header" label="Order History Extra Column Header"/>
+                <block class="Magento\Sales\Block\Order\History\Container"
+                       name="sales.order.history.extra.container" as="extra.container">
+                    <block class="Magento\Framework\View\Element\Template"
+                        name="sales.order.history.extra.container.data" as="extra.container.data"/>
+                </block>
             </block>
             <block class="Magento\Customer\Block\Account\Dashboard" name="customer.account.link.back" template="account/link/back.phtml" cacheable="false"/>
         </referenceContainer>
diff --git a/app/code/Magento/Sales/view/frontend/templates/order/history.phtml b/app/code/Magento/Sales/view/frontend/templates/order/history.phtml
index b3723d56ac28dc7b85c9fa2fe1a8aa978b780b9a..a57c68d17258fddb1bd0a4d3f2b6da3758ae690b 100644
--- a/app/code/Magento/Sales/view/frontend/templates/order/history.phtml
+++ b/app/code/Magento/Sales/view/frontend/templates/order/history.phtml
@@ -17,6 +17,7 @@
                 <tr>
                     <th scope="col" class="col id"><?php /* @escapeNotVerified */ echo __('Order #') ?></th>
                     <th scope="col" class="col date"><?php /* @escapeNotVerified */ echo __('Date') ?></th>
+                    <?php /* @noEscape */ echo $block->getChildHtml('extra.column.header');?>
                     <th scope="col" class="col shipping"><?php /* @escapeNotVerified */ echo __('Ship To') ?></th>
                     <th scope="col" class="col total"><?php /* @escapeNotVerified */ echo __('Order Total') ?></th>
                     <th scope="col" class="col status"><?php /* @escapeNotVerified */ echo __('Status') ?></th>
@@ -28,6 +29,11 @@
                     <tr>
                         <td data-th="<?php echo $block->escapeHtml(__('Order #')) ?>" class="col id"><?php /* @escapeNotVerified */ echo $_order->getRealOrderId() ?></td>
                         <td data-th="<?php echo $block->escapeHtml(__('Date')) ?>" class="col date"><?php /* @escapeNotVerified */ echo $block->formatDate($_order->getCreatedAt()) ?></td>
+                        <?php $extra = $block->getChildBlock('extra.container'); ?>
+                        <?php if ($extra): ?>
+                            <?php $extra->setOrder($_order); ?>
+                            <?php /* @noEscape */ echo $extra->getChildHtml() ?>
+                        <?php endif; ?>
                         <td data-th="<?php echo $block->escapeHtml(__('Ship To')) ?>" class="col shipping"><?php echo $_order->getShippingAddress() ? $block->escapeHtml($_order->getShippingAddress()->getName()) : '&nbsp;' ?></td>
                         <td data-th="<?php echo $block->escapeHtml(__('Order Total')) ?>" class="col total"><?php /* @escapeNotVerified */ echo $_order->formatPrice($_order->getGrandTotal()) ?></td>
                         <td data-th="<?php echo $block->escapeHtml(__('Status')) ?>" class="col status"><?php /* @escapeNotVerified */ echo $_order->getStatusLabel() ?></td>
diff --git a/app/code/Magento/SalesRule/Model/Rule/Condition/Address.php b/app/code/Magento/SalesRule/Model/Rule/Condition/Address.php
index 62fcb8e4b3b6243d007e4d7c9dcbdb8b0985af63..3366ba4cd1f6e87903445e5f0c5e2a8954539a58 100644
--- a/app/code/Magento/SalesRule/Model/Rule/Condition/Address.php
+++ b/app/code/Magento/SalesRule/Model/Rule/Condition/Address.php
@@ -61,7 +61,6 @@ class Address extends \Magento\Rule\Model\Condition\AbstractCondition
             'base_subtotal' => __('Subtotal'),
             'total_qty' => __('Total Items Quantity'),
             'weight' => __('Total Weight'),
-            'payment_method' => __('Payment Method'),
             'shipping_method' => __('Shipping Method'),
             'postcode' => __('Shipping Postcode'),
             'region' => __('Shipping Region'),
diff --git a/app/code/Magento/SalesRule/view/adminhtml/ui_component/sales_rule_form.xml b/app/code/Magento/SalesRule/view/adminhtml/ui_component/sales_rule_form.xml
index a9a682be3194cbf91234dbcb837c394dc8b385fd..dea387e465685bb846e0368ba4f32f35e6531832 100644
--- a/app/code/Magento/SalesRule/view/adminhtml/ui_component/sales_rule_form.xml
+++ b/app/code/Magento/SalesRule/view/adminhtml/ui_component/sales_rule_form.xml
@@ -51,7 +51,7 @@
     <fieldset name="general">
         <argument name="data" xsi:type="array">
             <item name="config" xsi:type="array">
-                <item name="label" xsi:type="string">Currently Active</item>
+                <item name="label" xsi:type="string" translate="true">Currently Active</item>
                 <item name="additionalClasses" xsi:type="string">fieldset-schedule</item>
             </item>
         </argument>
diff --git a/app/code/Magento/Shipping/view/adminhtml/web/order/packaging.js b/app/code/Magento/Shipping/view/adminhtml/web/order/packaging.js
index 2ad2ff596a7077f92c91623fef98d374449480b1..b3a7ea2e2495657efcf2de1fcfc5a00eb8939f7b 100644
--- a/app/code/Magento/Shipping/view/adminhtml/web/order/packaging.js
+++ b/app/code/Magento/Shipping/view/adminhtml/web/order/packaging.js
@@ -353,7 +353,7 @@ Packaging.prototype = {
                     var response = transport.responseText;
                     if (response) {
                         packagePrapareGrid.update(response);
-                        this._processPackagePrapare(packagePrapareGrid);
+                        this.processPackagePrepare(packagePrapareGrid);
                         if (packagePrapareGrid.select('.grid tbody tr').length) {
                             packageBlock.select('[data-action=package-add-items]')[0].hide();
                             packageBlock.select('[data-action=package-save-items]')[0].show();
@@ -692,22 +692,27 @@ Packaging.prototype = {
         }
     },
 
-    _processPackagePrapare: function(packagePrapare) {
-        var itemsAll = [];
-        packagePrapare.select('.grid tbody tr').each(function(item) {
-            var qty  = item.select('[name="qty"]')[0];
-            var itemId = item.select('[type="checkbox"]')[0].value;
-            var qtyValue = 0;
+    processPackagePrepare: function(packagePrepare) {
+        var itemsAll = [],
+            qty,
+            itemId,
+            qtyValue = 0,
+            value = 1;
+
+        packagePrepare.select('.grid tbody tr').each(function(item) {
+            qty = item.select('[name="qty"]')[0],
+                itemId = item.select('[type="checkbox"]')[0].value,
+                qtyValue = parseFloat(qty.value);
+
             if (Object.isFunction(this.itemQtyCallback)) {
-                var value = this.itemQtyCallback(itemId);
-                qtyValue = ((typeof value == 'string') && (value.length == 0)) ? 0 : parseFloat(value);
-                if (isNaN(qtyValue) || qtyValue < 0) {
-                    qtyValue = 1;
+                value = this.itemQtyCallback(itemId);
+                if (typeof value !== 'undefined') {
+                    qtyValue = parseFloat(value);
+                    qtyValue = this.validateItemQty(itemId, qtyValue);
+                    qty.value = qtyValue;
                 }
-                qtyValue = this.validateItemQty(itemId, qtyValue);
-                qty.value = qtyValue;
             } else {
-                var value = item.select('[name="qty"]')[0].value;
+                value = item.select('[name="qty"]')[0].value;
                 qtyValue = ((typeof value == 'string') && (value.length == 0)) ? 0 : parseFloat(value);
                 if (isNaN(qtyValue) || qtyValue < 0) {
                     qtyValue = 1;
@@ -737,10 +742,10 @@ Packaging.prototype = {
             this.itemsAll = itemsAll;
         }
 
-        packagePrapare.select('tbody input[type="checkbox"]').each(function(item){
+        packagePrepare.select('tbody input[type="checkbox"]').each(function(item){
             $(item).observe('change', this._observeQty);
             this._observeQty.call(item);
-        }.bind(this))
+        }.bind(this));
     },
 
     _observeQty: function() {
diff --git a/app/code/Magento/Theme/Test/Unit/Ui/Component/Design/Config/SearchRobots/ResetButtonTest.php b/app/code/Magento/Theme/Test/Unit/Ui/Component/Design/Config/SearchRobots/ResetButtonTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..b1c7095c0f7c9215abc4c330e209a423221cfcb6
--- /dev/null
+++ b/app/code/Magento/Theme/Test/Unit/Ui/Component/Design/Config/SearchRobots/ResetButtonTest.php
@@ -0,0 +1,99 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Theme\Test\Unit\Ui\Component\Design\Config\SearchRobots;
+
+use Magento\Framework\View\Element\UiComponent\ContextInterface;
+use Magento\Framework\View\Element\UiComponentFactory;
+use Magento\Framework\App\Config\ScopeConfigInterface;
+use Magento\Theme\Ui\Component\Design\Config\SearchRobots\ResetButton;
+use Magento\Framework\View\Element\UiComponent\Processor;
+use Magento\Ui\Component\Form\Field;
+
+class ResetButtonTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject | ContextInterface
+     */
+    private $contextMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject | UiComponentFactory
+     */
+    private $componentFactoryMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject | ScopeConfigInterface
+     */
+    private $scopeConfigMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject |
+     */
+    private $processorMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject |
+     */
+    private $wrappingComponentMock;
+
+    /**
+     * @var ResetButton
+     */
+    private $resetButton;
+
+    public function setUp()
+    {
+        $this->contextMock = $this->getMockBuilder(ContextInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->componentFactoryMock = $this->getMockBuilder(UiComponentFactory::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->scopeConfigMock = $this->getMockBuilder(ScopeConfigInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->processorMock = $this->getMockBuilder(Processor::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->contextMock->expects($this->atLeastOnce())
+            ->method("getProcessor")
+            ->willReturn($this->processorMock);
+        $this->wrappingComponentMock = $this->getMockBuilder(Field::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->resetButton = new ResetButton(
+            $this->contextMock,
+            $this->componentFactoryMock,
+            [],
+            [
+                'config' => [
+                    'formElement' => 'button'
+                ]
+            ],
+            $this->scopeConfigMock
+        );
+    }
+    
+    public function testPrepare()
+    {
+        $robotsContent = "Content";
+
+        $this->componentFactoryMock->expects($this->once())
+            ->method("create")
+            ->willReturn($this->wrappingComponentMock);
+        $this->wrappingComponentMock->expects($this->once())
+            ->method("getContext")
+            ->willReturn($this->contextMock);
+        $this->scopeConfigMock->expects($this->once())
+            ->method("getValue")
+            ->willReturn($robotsContent);
+
+        $this->resetButton->prepare();
+        $actions = $this->resetButton->getData("config/actions");
+        $this->assertEquals(json_encode($robotsContent), $actions[0]["params"][0]);
+    }
+}
diff --git a/app/code/Magento/Theme/Ui/Component/Design/Config/SearchRobots/ResetButton.php b/app/code/Magento/Theme/Ui/Component/Design/Config/SearchRobots/ResetButton.php
new file mode 100644
index 0000000000000000000000000000000000000000..d57c10fd08f4a284ae01b9e42f3fbf22d1c41343
--- /dev/null
+++ b/app/code/Magento/Theme/Ui/Component/Design/Config/SearchRobots/ResetButton.php
@@ -0,0 +1,73 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Theme\Ui\Component\Design\Config\SearchRobots;
+
+use Magento\Framework\View\Element\UiComponent\ContextInterface;
+use Magento\Framework\View\Element\UiComponentFactory;
+use Magento\Ui\Component\Form\Field;
+use Magento\Framework\App\Config\ScopeConfigInterface;
+
+class ResetButton extends Field
+{
+    /**
+     * Page robots default instructions
+     */
+    const XML_PATH_ROBOTS_DEFAULT_CUSTOM_INSTRUCTIONS = 'design/search_engine_robots/default_custom_instructions';
+
+    /** @var ScopeConfigInterface  */
+    private $scopeConfig;
+
+    /**
+     * ResetButton constructor.
+     * @param ContextInterface $context
+     * @param UiComponentFactory $uiComponentFactory
+     * @param array|\Magento\Framework\View\Element\UiComponentInterface[] $components
+     * @param array $data
+     * @param ScopeConfigInterface $scopeConfig
+     */
+    public function __construct(
+        ContextInterface $context,
+        UiComponentFactory $uiComponentFactory,
+        $components,
+        array $data,
+        ScopeConfigInterface $scopeConfig
+    ) {
+        $this->scopeConfig = $scopeConfig;
+        parent::__construct($context, $uiComponentFactory, $components, $data);
+    }
+
+    /**
+     * Get robots.txt custom instruction default value
+     *
+     * @return string
+     */
+    private function getRobotsDefaultCustomInstructions()
+    {
+        return trim((string)$this->scopeConfig->getValue(
+            self::XML_PATH_ROBOTS_DEFAULT_CUSTOM_INSTRUCTIONS, ScopeConfigInterface::SCOPE_TYPE_DEFAULT
+        ));
+    }
+
+    /**
+     * Add js listener to reset button
+     *
+     * @throws \Magento\Framework\Exception\LocalizedException
+     */
+    public function prepare()
+    {
+        parent::prepare();
+
+        $this->_data['config']['actions'] = [
+            [
+                'actionName' => 'reset',
+                'targetName' => '${ $.name }',
+                'params'     => [
+                    json_encode($this->getRobotsDefaultCustomInstructions())
+                ]
+            ]
+        ];
+    }
+}
\ No newline at end of file
diff --git a/app/code/Magento/Theme/etc/adminhtml/system.xml b/app/code/Magento/Theme/etc/adminhtml/system.xml
deleted file mode 100644
index 84773112f504e400641d002e98fcc0d8a6d8d045..0000000000000000000000000000000000000000
--- a/app/code/Magento/Theme/etc/adminhtml/system.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0"?>
-<!--
-/**
- * Copyright © 2016 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
--->
-<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Config:etc/system_file.xsd">
-    <system>
-        <section id="design">
-            <group id="search_engine_robots" translate="label" type="text" sortOrder="25" showInDefault="1" showInWebsite="1" showInStore="1">
-                <label>Search Engine Robots</label>
-                <field id="default_robots" translate="label comment" type="select" sortOrder="40" showInDefault="1" showInWebsite="1" showInStore="1" canRestore="1">
-                    <label>Default Robots</label>
-                    <comment>This will be included before head closing tag in page HTML.</comment>
-                    <source_model>Magento\Config\Model\Config\Source\Design\Robots</source_model>
-                </field>
-                <field id="custom_instructions" translate="label comment" type="textarea" sortOrder="70" showInDefault="1" showInWebsite="1" showInStore="1">
-                    <label>Edit custom instruction of robots.txt File</label>
-                    <backend_model>Magento\Config\Model\Config\Backend\Admin\Robots</backend_model>
-                </field>
-                <field id="reset_to_defaults" translate="label comment" type="button" sortOrder="80" showInDefault="1" showInWebsite="1" showInStore="1">
-                    <label>Reset to Defaults</label>
-                    <frontend_model>Magento\Backend\Block\Page\System\Config\Robots\Reset</frontend_model>
-                    <comment>This action will delete your custom instructions and reset robots.txt file to system's default settings.</comment>
-                </field>
-            </group>
-        </section>
-    </system>
-</config>
diff --git a/app/code/Magento/Theme/etc/di.xml b/app/code/Magento/Theme/etc/di.xml
index 9cb17d93ab652e1ce5ef32aac0605e9a5046690b..cee9fc816914b55f31970995b64fa404ccbfcff8 100644
--- a/app/code/Magento/Theme/etc/di.xml
+++ b/app/code/Magento/Theme/etc/di.xml
@@ -211,6 +211,15 @@
                     <item name="path" xsi:type="string">design/footer/absolute_footer</item>
                     <item name="fieldset" xsi:type="string">other_settings/footer</item>
                 </item>
+                <item name="default_robots" xsi:type="array">
+                    <item name="path" xsi:type="string">design/search_engine_robots/default_robots</item>
+                    <item name="fieldset" xsi:type="string">other_settings/search_engine_robots</item>
+                </item>
+                <item name="custom_instructions" xsi:type="array">
+                    <item name="path" xsi:type="string">design/search_engine_robots/custom_instructions</item>
+                    <item name="backend_model" xsi:type="string">Magento\Config\Model\Config\Backend\Admin\Robots</item>
+                    <item name="fieldset" xsi:type="string">other_settings/search_engine_robots</item>
+                </item>
             </argument>
         </arguments>
     </type>
diff --git a/app/code/Magento/Theme/view/adminhtml/page_layout/admin-1column.xml b/app/code/Magento/Theme/view/adminhtml/page_layout/admin-1column.xml
index 51684b30fac9777de069a3e5207ff1ab060cf47d..570f5322e9eb95881ba29f6e6abac446e5a5d56c 100644
--- a/app/code/Magento/Theme/view/adminhtml/page_layout/admin-1column.xml
+++ b/app/code/Magento/Theme/view/adminhtml/page_layout/admin-1column.xml
@@ -17,9 +17,9 @@
                     <container name="global.notices" as="global_notices" after="notification.window"/>
                 </container>
 
-                <container name="header" after="global.notices" htmlTag="header" htmlClass="page-header"/>
+                <container name="header" htmlTag="header" htmlClass="page-header"/>
                 <container name="page.menu" as="page.menu" after="header"/>
-                <container name="page.breadcrumbs" after="notifications" as="page.breadcrumbs"/>
+                <container name="page.breadcrumbs" as="page.breadcrumbs"/>
 
                 <container name="page.formkey" as="page.formkey"/>
 
diff --git a/app/code/Magento/Theme/view/adminhtml/page_layout/admin-2columns-left.xml b/app/code/Magento/Theme/view/adminhtml/page_layout/admin-2columns-left.xml
index 62dc716817221eda59c8bc0bc1900639c5c91042..0c662a0d467da9cdd41b7e997dc3b9a7a8fde97f 100644
--- a/app/code/Magento/Theme/view/adminhtml/page_layout/admin-2columns-left.xml
+++ b/app/code/Magento/Theme/view/adminhtml/page_layout/admin-2columns-left.xml
@@ -17,9 +17,9 @@
                     <container name="global.notices" as="global_notices" after="notification.window"/>
                 </container>
 
-                <container name="header" after="global.notices" htmlTag="header" htmlClass="page-header"/>
+                <container name="header" htmlTag="header" htmlClass="page-header"/>
                 <container name="page.menu" as="page.menu" after="header"/>
-                <container name="page.breadcrumbs" after="notifications" as="page.breadcrumbs"/>
+                <container name="page.breadcrumbs" as="page.breadcrumbs"/>
 
                 <container name="page.formkey" as="page.formkey"/>
 
diff --git a/app/code/Magento/Theme/view/adminhtml/ui_component/design_config_form.xml b/app/code/Magento/Theme/view/adminhtml/ui_component/design_config_form.xml
index 696449889d6b28dd0096fbd1dfc237e63ab6fd19..8ff8430220abea0d25bc4f9dd3ea1cbd470aa3c4 100644
--- a/app/code/Magento/Theme/view/adminhtml/ui_component/design_config_form.xml
+++ b/app/code/Magento/Theme/view/adminhtml/ui_component/design_config_form.xml
@@ -188,7 +188,7 @@
             <field name="header_logo_width">
                 <argument name="data" xsi:type="array">
                     <item name="config" xsi:type="array">
-                        <item name="label" xsi:type="string" translate="true">Logo Image Width</item>
+                        <item name="label" xsi:type="string" translate="true">Logo Attribute Width</item>
                         <item name="dataType" xsi:type="string">number</item>
                         <item name="formElement" xsi:type="string">input</item>
                         <item name="dataScope" xsi:type="string">header_logo_width</item>
@@ -201,7 +201,7 @@
             <field name="header_logo_height">
                 <argument name="data" xsi:type="array">
                     <item name="config" xsi:type="array">
-                        <item name="label" xsi:type="string" translate="true">Logo Image Height</item>
+                        <item name="label" xsi:type="string" translate="true">Logo Attribute Height</item>
                         <item name="dataType" xsi:type="string">number</item>
                         <item name="formElement" xsi:type="string">input</item>
                         <item name="dataScope" xsi:type="string">header_logo_height</item>
@@ -271,5 +271,49 @@
                 </argument>
             </field>
         </fieldset>
+        <fieldset name="search_engine_robots">
+            <argument name="data" xsi:type="array">
+                <item name="config" xsi:type="array">
+                    <item name="label" xsi:type="string">Search Engine Robots</item>
+                    <item name="sortOrder" xsi:type="string">120</item>
+                    <item name="collapsible" xsi:type="boolean">true</item>
+                    <item name="level" xsi:type="number">1</item>
+                </item>
+            </argument>
+            <field name="default_robots">
+                <argument name="data" xsi:type="array">
+                    <item name="options" xsi:type="object">Magento\Config\Model\Config\Source\Design\Robots</item>
+                    <item name="config" xsi:type="array">
+                        <item name="label" xsi:type="string" translate="true">Default Robots</item>
+                        <item name="dataType" xsi:type="string">text</item>
+                        <item name="formElement" xsi:type="string">select</item>
+                        <item name="dataScope" xsi:type="string">default_robots</item>
+                        <item name="notice" xsi:type="string" translate="true">This will be included before head closing tag in page HTML.</item>
+                    </item>
+                </argument>
+            </field>
+            <field name="custom_instructions">
+                <argument name="data" xsi:type="array">
+                    <item name="config" xsi:type="array">
+                        <item name="label" xsi:type="string" translate="true">Edit custom instruction of robots.txt File</item>
+                        <item name="dataType" xsi:type="string">text</item>
+                        <item name="formElement" xsi:type="string">textarea</item>
+                        <item name="dataScope" xsi:type="string">custom_instructions</item>
+                    </item>
+                </argument>
+            </field>
+            <field name="reset_to_defaults" class="Magento\Theme\Ui\Component\Design\Config\SearchRobots\ResetButton">
+                <argument name="data" xsi:type="array">
+                    <item name="config" xsi:type="array">
+                        <item name="title" xsi:type="string">Reset To Defaults</item>
+                        <item name="formElement" xsi:type="string">button</item>
+                        <item name="dataScope" xsi:type="string">reset_to_defaults</item>
+                        <item name="component" xsi:type="string">Magento_Theme/js/form/component/robots-reset-button</item>
+                        <item name="template" xsi:type="string">Magento_Theme/form/button-field</item>
+                        <item name="notice" xsi:type="string" translate="true">This action will delete your custom instructions and reset robots.txt file to system's default settings.</item>
+                    </item>
+                </argument>
+            </field>
+        </fieldset>
     </fieldset>
 </form>
diff --git a/app/code/Magento/Theme/view/adminhtml/web/js/form/component/robots-reset-button.js b/app/code/Magento/Theme/view/adminhtml/web/js/form/component/robots-reset-button.js
new file mode 100644
index 0000000000000000000000000000000000000000..e483632734d4568ec14b702ba075a9484d255010
--- /dev/null
+++ b/app/code/Magento/Theme/view/adminhtml/web/js/form/component/robots-reset-button.js
@@ -0,0 +1,39 @@
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+define([
+    'Magento_Ui/js/form/components/button',
+    'uiRegistry'
+], function (Button, registry) {
+    'use strict';
+
+    return Button.extend({
+        defaults: {
+            customInstructionField: '${ $.parentName }.custom_instructions',
+            label: '',
+            buttonTpl: 'Magento_Theme/form/element/button'
+        },
+
+        /**
+         * @private
+         * @param {String} json
+         * @return {String}
+         */
+        _parseJson: function (json) {
+            return JSON.parse(json);
+        },
+
+        /**
+         * @param {String} defaultRobotsTxt
+         */
+        reset: function (defaultRobotsTxt) {
+            var customInstructions = registry.get(this.customInstructionField);
+
+            if (customInstructions) {
+                customInstructions.set('value', this._parseJson(defaultRobotsTxt));
+            }
+        }
+    });
+});
diff --git a/app/code/Magento/Theme/view/adminhtml/web/template/form/button-field.html b/app/code/Magento/Theme/view/adminhtml/web/template/form/button-field.html
new file mode 100644
index 0000000000000000000000000000000000000000..fa37c9bdf7e0fa44de49d136a0b326fa20d7b3e7
--- /dev/null
+++ b/app/code/Magento/Theme/view/adminhtml/web/template/form/button-field.html
@@ -0,0 +1,23 @@
+<!--
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+-->
+<div class="admin__field"
+     visible="visible"
+     css="$data.additionalClasses"
+     attr="'data-index': index">
+    <label class="admin__field-label">
+        <span text="label"/>
+    </label>
+
+    <div class="admin__field-control"
+         css="'_with-tooltip': $data.tooltip">
+        <render args="tooltipTpl" if="$data.tooltip"/>
+        <render args="buttonTpl" />
+        <div class="admin__field-note" if="$data.notice">
+            <span text="notice"/>
+        </div>
+    </div>
+</div>
\ No newline at end of file
diff --git a/app/code/Magento/Theme/view/adminhtml/web/template/form/element/button.html b/app/code/Magento/Theme/view/adminhtml/web/template/form/element/button.html
new file mode 100644
index 0000000000000000000000000000000000000000..4f9164baa07d02ec1f22ef9dfdbf15fb937292dc
--- /dev/null
+++ b/app/code/Magento/Theme/view/adminhtml/web/template/form/element/button.html
@@ -0,0 +1,13 @@
+<!--
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+-->
+<button type="button"
+        click="action"
+        disable="disabled"
+        attr="'data-index': index">
+    <span text="title">
+    </span>
+</button>
\ No newline at end of file
diff --git a/app/code/Magento/Ui/Component/Filters/Type/Date.php b/app/code/Magento/Ui/Component/Filters/Type/Date.php
index f670f826e4e20965c1312db80d14f4e9c52e7e09..f5d392ea5136565797ae7306b870c07399043d68 100644
--- a/app/code/Magento/Ui/Component/Filters/Type/Date.php
+++ b/app/code/Magento/Ui/Component/Filters/Type/Date.php
@@ -23,6 +23,13 @@ class Date extends AbstractFilter
      */
     protected $wrappedComponent;
 
+    /**
+     * Date format
+     *
+     * @var string
+     */
+    protected static $dateFormat = 'Y-m-d H:i:s';
+
     /**
      * Prepare component configuration
      *
@@ -96,7 +103,7 @@ class Date extends AbstractFilter
         if (!empty($value)) {
             $filter = $this->filterBuilder->setConditionType($type)
                 ->setField($this->getName())
-                ->setValue($value->format('Y-m-d H:i:s'))
+                ->setValue($value->format(static::$dateFormat))
                 ->create();
 
             $this->getContext()->getDataProvider()->addFilter($filter);
diff --git a/app/code/Magento/Ui/Test/Unit/Component/Filters/Type/DateTest.php b/app/code/Magento/Ui/Test/Unit/Component/Filters/Type/DateTest.php
index 7000d9e091139a08199a6d23059f4bcd3220ff21..af53b71f18414f8c0f16f27e32b13ba354d29567 100644
--- a/app/code/Magento/Ui/Test/Unit/Component/Filters/Type/DateTest.php
+++ b/app/code/Magento/Ui/Test/Unit/Component/Filters/Type/DateTest.php
@@ -5,9 +5,11 @@
  */
 namespace Magento\Ui\Test\Unit\Component\Filters\Type;
 
-use Magento\Framework\View\Element\UiComponent\ContextInterface as UiContext;
+use Magento\Framework\Api\Filter;
+use Magento\Framework\Api\FilterBuilder;
 use Magento\Framework\View\Element\UiComponent\DataProvider\DataProviderInterface;
 use Magento\Framework\View\Element\UiComponentFactory;
+use Magento\Ui\Component\Filters\FilterModifier;
 use Magento\Ui\Component\Filters\Type\Date;
 use Magento\Framework\View\Element\UiComponent\ContextInterface;
 use Magento\Ui\Component\Form\Element\DataType\Date as FormDate;
@@ -20,61 +22,55 @@ class DateTest extends \PHPUnit_Framework_TestCase
     /**
      * @var ContextInterface|\PHPUnit_Framework_MockObject_MockObject
      */
-    protected $contextMock;
+    private $contextMock;
 
     /**
      * @var UiComponentFactory|\PHPUnit_Framework_MockObject_MockObject
      */
-    protected $uiComponentFactory;
+    private $uiComponentFactory;
 
     /**
-     * @var \Magento\Framework\Api\FilterBuilder|\PHPUnit_Framework_MockObject_MockObject
+     * @var FilterBuilder|\PHPUnit_Framework_MockObject_MockObject
      */
-    protected $filterBuilderMock;
+    private $filterBuilderMock;
 
     /**
-     * @var \Magento\Ui\Component\Filters\FilterModifier|\PHPUnit_Framework_MockObject_MockObject
+     * @var FilterModifier|\PHPUnit_Framework_MockObject_MockObject
      */
-    protected $filterModifierMock;
+    private $filterModifierMock;
+
+
+    /**
+     * @var DataProviderInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $dataProviderMock;
 
     /**
      * Set up
      */
     protected function setUp()
     {
-        $this->contextMock = $this->getMockForAbstractClass(
-            'Magento\Framework\View\Element\UiComponent\ContextInterface',
-            [],
-            '',
-            false
-        );
-        $processor = $this->getMockBuilder('Magento\Framework\View\Element\UiComponent\Processor')
+        $this->contextMock = $this->getMockForAbstractClass(ContextInterface::class);
+        $processor = $this->getMockBuilder(\Magento\Framework\View\Element\UiComponent\Processor::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->contextMock->expects(static::any())
+            ->method('getProcessor')
+            ->willReturn($processor);
+        $this->uiComponentFactory = $this->getMockBuilder(UiComponentFactory::class)
+            ->setMethods(['create'])
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->filterBuilderMock = $this->getMockBuilder(FilterBuilder::class)
             ->disableOriginalConstructor()
             ->getMock();
-        $this->contextMock->expects($this->any())->method('getProcessor')->willReturn($processor);
-        $this->uiComponentFactory = $this->getMock(
-            'Magento\Framework\View\Element\UiComponentFactory',
-            ['create'],
-            [],
-            '',
-            false
-        );
-        $this->filterBuilderMock = $this->getMock(
-            'Magento\Framework\Api\FilterBuilder',
-            [],
-            [],
-            '',
-            false
-        );
-
-        $this->filterModifierMock = $this->getMock(
-            'Magento\Ui\Component\Filters\FilterModifier',
-            ['applyFilterModifier'],
-            [],
-            '',
-            false
-        );
 
+        $this->filterModifierMock = $this->getMockBuilder(FilterModifier::class)
+            ->setMethods(['applyFilterModifier'])
+            ->disableOriginalConstructor()
+            ->getMock();
+        
+        $this->dataProviderMock = $this->getMockForAbstractClass(DataProviderInterface::class);
     }
 
     /**
@@ -92,7 +88,7 @@ class DateTest extends \PHPUnit_Framework_TestCase
             []
         );
 
-        $this->assertTrue($date->getComponentName() === Date::NAME);
+        static::assertTrue($date->getComponentName() === Date::NAME);
     }
 
     /**
@@ -107,13 +103,9 @@ class DateTest extends \PHPUnit_Framework_TestCase
     public function testPrepare($name, $filterData, $expectedCondition)
     {
         /** @var FormDate $uiComponent */
-        $uiComponent = $this->getMock(
-            'Magento\Ui\Component\Form\Element\DataType\Date',
-            [],
-            [],
-            '',
-            false
-        );
+        $uiComponent = $this->getMockBuilder(FormDate::class)
+            ->disableOriginalConstructor()
+            ->getMock();
 
         $uiComponent->expects($this->any())
             ->method('getContext')
@@ -125,30 +117,62 @@ class DateTest extends \PHPUnit_Framework_TestCase
         $this->contextMock->expects($this->any())
             ->method('addComponentDefinition')
             ->with(Date::NAME, ['extends' => Date::NAME]);
+
         $this->contextMock->expects($this->any())
-            ->method('getRequestParam')
-            ->with(UiContext::FILTER_VAR)
+            ->method('getFiltersParams')
             ->willReturn($filterData);
-        $dataProvider = $this->getMockForAbstractClass(
-            'Magento\Framework\View\Element\UiComponent\DataProvider\DataProviderInterface',
-            [],
-            '',
-            false
-        );
+        
         $this->contextMock->expects($this->any())
             ->method('getDataProvider')
-            ->willReturn($dataProvider);
+            ->willReturn($this->dataProviderMock);
+
         if ($expectedCondition !== null) {
-            $dataProvider->expects($this->any())
-                ->method('addFilter')
-                ->with($expectedCondition, $name);
-
-            $uiComponent->expects($this->any())
-                ->method('getLocale')
-                ->willReturn($expectedCondition['locale']);
-            $uiComponent->expects($this->any())
-                ->method('convertDate')
-                ->willReturnArgument(0);
+            if (is_string($filterData[$name])) {
+                $uiComponent->expects(static::once())
+                    ->method('convertDate')
+                    ->with($filterData[$name])
+                    ->willReturn(new \DateTime($filterData[$name]));
+            } else {
+                $uiComponent->method('convertDate')
+                    ->willReturnMap([
+                        [$filterData[$name]['from'], 0, 0, 0, new \DateTime($filterData[$name]['from'])],
+                        [$filterData[$name]['to'], 23, 59, 59, new \DateTime($filterData[$name]['to'] . ' 23:59:59')],
+                    ]);
+            }
+
+            $i=0;
+            switch (true) {
+                case is_string($filterData[$name]):
+                case isset($filterData[$name]['from']) && !isset($filterData[$name]['to']):
+                case !isset($filterData[$name]['from']) && isset($filterData[$name]['to']):
+                    $filterMock = $this->getFilterMock(
+                        $name,
+                        $expectedCondition['type'],
+                        $expectedCondition['date'],
+                        $i
+                    );
+                    $this->dataProviderMock->expects(static::once())
+                        ->method('addFilter')
+                        ->with($filterMock);
+                    break;
+                case isset($filterData[$name]['from']) && isset($filterData[$name]['to']):
+                    $this->getFilterMock(
+                        $name,
+                        $expectedCondition['type_from'],
+                        $expectedCondition['date_from'],
+                        $i
+                    );
+                    $filterMock = $this->getFilterMock(
+                        $name,
+                        $expectedCondition['type_to'],
+                        $expectedCondition['date_to'],
+                        $i
+                    );
+                    $this->dataProviderMock->expects(static::exactly(2))
+                        ->method('addFilter')
+                        ->with($filterMock);
+                    break;
+            }
         }
 
         $this->uiComponentFactory->expects($this->any())
@@ -167,6 +191,39 @@ class DateTest extends \PHPUnit_Framework_TestCase
         $date->prepare();
     }
 
+    /**
+     * Gets Filter mock
+     * 
+     * @param string $name
+     * @param string $expectedType
+     * @param string $expectedDate
+     * @param int $i
+     * 
+     * @return Filter|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private function getFilterMock($name, $expectedType, $expectedDate, &$i)
+    {
+        $this->filterBuilderMock->expects(static::at($i++))
+            ->method('setConditionType')
+            ->with($expectedType)
+            ->willReturnSelf();
+        $this->filterBuilderMock->expects(static::at($i++))
+            ->method('setField')
+            ->with($name)
+            ->willReturnSelf();
+        $this->filterBuilderMock->expects(static::at($i++))
+            ->method('setValue')
+            ->with($expectedDate)
+            ->willReturnSelf();
+        
+        $filterMock = $this->getMock(Filter::class);
+        $this->filterBuilderMock->expects(static::at($i++))
+            ->method('create')
+            ->willReturn($filterMock);
+
+        return $filterMock;
+    }
+
     /**
      * @return array
      */
@@ -175,26 +232,27 @@ class DateTest extends \PHPUnit_Framework_TestCase
         return [
             [
                 'test_date',
-                ['test_date' => ['from' => '11-05-2015', 'to' => '']],
-                ['from' => '11-05-2015', 'orig_from' => '11-05-2015', 'datetime' => true, 'locale' => 'en_US'],
+                ['test_date' => ['from' => '11-05-2015', 'to' => null]],
+                ['date' => '2015-05-11 00:00:00', 'type' => 'gteq'],
             ],
             [
                 'test_date',
-                ['test_date' => ['from' => '', 'to' => '11-05-2015']],
-                ['to' => '11-05-2015', 'orig_to' => '11-05-2015', 'datetime' => true, 'locale' => 'en_US'],
+                ['test_date' => ['from' => null, 'to' => '11-05-2015']],
+                ['date' => '2015-05-11 23:59:59', 'type' => 'lteq'],
             ],
             [
                 'test_date',
-                ['test_date' => ['from' => '10-05-2015', 'to' => '11-05-2015']],
+                ['test_date' => ['from' => '11-05-2015', 'to' => '11-05-2015']],
                 [
-                    'from' => '10-05-2015',
-                    'orig_from' => '10-05-2015',
-                    'to' => '11-05-2015',
-                    'orig_to' => '11-05-2015',
-                    'datetime' => true,
-                    'locale' => 'en_US'
+                    'date_from' => '2015-05-11 00:00:00', 'type_from' => 'gteq',
+                    'date_to' => '2015-05-11 23:59:59', 'type_to' => 'lteq'
                 ],
             ],
+            [
+                'test_date',
+                ['test_date' => '11-05-2015'],
+                ['date' => '2015-05-11 00:00:00', 'type' => 'eq'],
+            ],
             [
                 'test_date',
                 ['test_date' => ['from' => '', 'to' => '']],
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 855b9ac5da177d5391ff28a8cfd57be4df54c823..cdcf2e9bb07895e7bdf3810fac7124368267de00 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
@@ -58,7 +58,7 @@ define([
          */
         applyAction: function (action) {
             var targetName = action.targetName,
-                params = action.params || [],
+                params = utils.copy(action.params) || [],
                 actionName = action.actionName,
                 target;
 
diff --git a/app/code/Magento/Ui/view/base/web/js/form/element/wysiwyg.js b/app/code/Magento/Ui/view/base/web/js/form/element/wysiwyg.js
index b3db5d11b98a51bc166082a10ae351949f317d9c..01c8ef29029a9ef34f82885e3efbada75774a88b 100644
--- a/app/code/Magento/Ui/view/base/web/js/form/element/wysiwyg.js
+++ b/app/code/Magento/Ui/view/base/web/js/form/element/wysiwyg.js
@@ -16,6 +16,7 @@ define([
         defaults: {
             elementSelector: 'textarea',
             value: '',
+            $wysiwygEditorButton: '',
             links: {
                 value: '${ $.provider }:${ $.dataScope }'
             },
@@ -23,7 +24,10 @@ define([
             elementTmpl: 'ui/form/element/wysiwyg',
             content:        '',
             showSpinner:    false,
-            loading:        false
+            loading:        false,
+            listens: {
+                disabled: 'setDisabled'
+            }
         },
 
         /**
@@ -34,6 +38,13 @@ define([
             this._super()
                 .initNodeListener();
 
+            $.async({
+                component: this,
+                selector: 'button'
+            }, function (element) {
+                this.$wysiwygEditorButton = $(element);
+            }.bind(this));
+
             return this;
         },
 
@@ -69,6 +80,26 @@ define([
             $(node).bindings({
                 value: this.value
             });
+        },
+
+        /**
+         * Set disabled property to wysiwyg component
+         *
+         * @param {Boolean} status
+         */
+        setDisabled: function (status) {
+            this.$wysiwygEditorButton.attr('disabled', status);
+
+            /* eslint-disable no-undef */
+            if (tinyMCE) {
+                _.each(tinyMCE.activeEditor.controlManager.controls, function (property, index, controls) {
+                    controls[property].setDisabled(status);
+                });
+
+                tinyMCE.activeEditor.getBody().setAttribute('contenteditable', !status);
+            }
+
+            /* eslint-enable  no-undef*/
         }
     });
 });
diff --git a/app/code/Magento/Ui/view/base/web/js/grid/resize.js b/app/code/Magento/Ui/view/base/web/js/grid/resize.js
index bad2061ec763562aa8bd927c9e6ba02911be4649..f7edde0ea47c422e48035f8254356edaa9091e46 100644
--- a/app/code/Magento/Ui/view/base/web/js/grid/resize.js
+++ b/app/code/Magento/Ui/view/base/web/js/grid/resize.js
@@ -261,11 +261,10 @@ define([
          */
         initResizableElement: function (column) {
             var model = ko.dataFor(column),
-                ctx = ko.contextFor(column),
-                tempalteDragElement = '<div class="' + ctx.$parent.resizeConfig.classResize + '"></div>';
+                templateDragElement = '<div class="' + this.resizableElementClass + '"></div>';
 
             if (_.isUndefined(model.resizeEnabled) || model.resizeEnabled) {
-                $(column).append(tempalteDragElement);
+                $(column).append(templateDragElement);
 
                 return true;
             }
diff --git a/app/code/Magento/Vault/Model/Method/Vault.php b/app/code/Magento/Vault/Model/Method/Vault.php
index 3457bc6a0a61f52adf2c86f68752e9df653ab2f0..aa0bead2327eabfb0414fcdcd21d46121553d9ff 100644
--- a/app/code/Magento/Vault/Model/Method/Vault.php
+++ b/app/code/Magento/Vault/Model/Method/Vault.php
@@ -576,7 +576,8 @@ final class Vault implements VaultPaymentInterface
      */
     public function isAvailable(\Magento\Quote\Api\Data\CartInterface $quote = null)
     {
-        return $this->getVaultProvider()->isAvailable($quote);
+        return $this->getVaultProvider()->isAvailable($quote)
+            && $this->config->getValue(self::$activeKey, $this->getStore() ?: $quote->getStoreId());
     }
 
     /**
diff --git a/app/code/Magento/Vault/Test/Unit/Model/Method/VaultTest.php b/app/code/Magento/Vault/Test/Unit/Model/Method/VaultTest.php
index 2dcece98e770a4958f15eac057acf24df3a96531..32e783278e1301f3bf45a085edb7b81d72801cd7 100644
--- a/app/code/Magento/Vault/Test/Unit/Model/Method/VaultTest.php
+++ b/app/code/Magento/Vault/Test/Unit/Model/Method/VaultTest.php
@@ -8,8 +8,10 @@ namespace Magento\Vault\Test\Unit\Model\Method;
 use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
 use Magento\Payment\Gateway\Command\CommandManagerInterface;
 use Magento\Payment\Gateway\Command\CommandManagerPoolInterface;
+use Magento\Payment\Gateway\ConfigInterface;
 use Magento\Payment\Model\InfoInterface;
 use Magento\Payment\Model\MethodInterface;
+use Magento\Quote\Api\Data\CartInterface;
 use Magento\Sales\Api\Data\OrderPaymentExtensionInterface;
 use Magento\Sales\Api\Data\TransactionInterface;
 use Magento\Sales\Model\Order\Payment;
@@ -18,6 +20,10 @@ use Magento\Vault\Api\PaymentTokenManagementInterface;
 use Magento\Vault\Model\Method\Vault;
 use Magento\Vault\Model\VaultPaymentInterface;
 
+/**
+ * Class VaultTest
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ */
 class VaultTest extends \PHPUnit_Framework_TestCase
 {
     /**
@@ -209,4 +215,52 @@ class VaultTest extends \PHPUnit_Framework_TestCase
         $model = $this->objectManager->getObject(Vault::class);
         $model->capture($paymentModel, 0);
     }
+
+    /**
+     * @covers \Magento\Vault\Model\Method\Vault::isAvailable
+     * @dataProvider isAvailableDataProvider
+     */
+    public function testIsAvailable($isAvailableProvider, $isActive, $expected)
+    {
+        $storeId = 1;
+        $quote = $this->getMockForAbstractClass(CartInterface::class);
+        $vaultProvider = $this->getMockForAbstractClass(MethodInterface::class);
+        $config = $this->getMockForAbstractClass(ConfigInterface::class);
+
+        $vaultProvider->expects(static::once())
+            ->method('isAvailable')
+            ->with($quote)
+            ->willReturn($isAvailableProvider);
+
+        $config->expects(static::any())
+            ->method('getValue')
+            ->with('active', $storeId)
+            ->willReturn($isActive);
+
+        $quote->expects(static::any())
+            ->method('getStoreId')
+            ->willReturn($storeId);
+
+        /** @var Vault $model */
+        $model = $this->objectManager->getObject(Vault::class, [
+            'config' => $config,
+            'vaultProvider' => $vaultProvider
+        ]);
+        $actual = $model->isAvailable($quote);
+        static::assertEquals($expected, $actual);
+    }
+
+    /**
+     * List of variations for testing isAvailable method
+     * @return array
+     */
+    public function isAvailableDataProvider()
+    {
+        return [
+            ['isAvailableProvider' => true, 'isActiveVault' => false, 'expected' => false],
+            ['isAvailableProvider' => false, 'isActiveVault' => false, 'expected' => false],
+            ['isAvailableProvider' => false, 'isActiveVault' => true, 'expected' => false],
+            ['isAvailableProvider' => true, 'isActiveVault' => true, 'expected' => true],
+        ];
+    }
 }
diff --git a/app/code/Magento/Wishlist/Model/ResourceModel/Item/Collection.php b/app/code/Magento/Wishlist/Model/ResourceModel/Item/Collection.php
index a80849133c53898d22b32738315d7cbb313626fa..ff74604d6fccd21880d7971533698c979ab89a26 100644
--- a/app/code/Magento/Wishlist/Model/ResourceModel/Item/Collection.php
+++ b/app/code/Magento/Wishlist/Model/ResourceModel/Item/Collection.php
@@ -291,6 +291,7 @@ class Collection extends \Magento\Framework\Model\ResourceModel\Db\Collection\Ab
             'thumbnail',
             'links_purchased_separately',
             'links_title',
+            'price_type'
         ];
 
         $productCollection->addPriceData()
diff --git a/app/design/adminhtml/Magento/backend/Magento_Backend/layout/default.xml b/app/design/adminhtml/Magento/backend/Magento_Backend/layout/default.xml
index 6c4156291d3219fdb96552feb9218181db4c32e7..d26590e617c163cd00d6bce47f56574172de8b67 100644
--- a/app/design/adminhtml/Magento/backend/Magento_Backend/layout/default.xml
+++ b/app/design/adminhtml/Magento/backend/Magento_Backend/layout/default.xml
@@ -29,7 +29,7 @@
         <move element="page.title" before="-" destination="header.inner.left" />
         <move element="user" before="-" destination="header.inner.right" />
         <move element="notification.messages" after="user" destination="header.inner.right" />
-        <move element="global.search" after="notification.messages" destination="header.inner.right" />
+        <move element="global.search" destination="header.inner.right" />
 
     </body>
 </page>
diff --git a/app/design/adminhtml/Magento/backend/Magento_Integration/web/css/source/_module.less b/app/design/adminhtml/Magento/backend/Magento_Integration/web/css/source/_module.less
new file mode 100644
index 0000000000000000000000000000000000000000..3527cb48759e89a388ac355480c132adb0e7dece
--- /dev/null
+++ b/app/design/adminhtml/Magento/backend/Magento_Integration/web/css/source/_module.less
@@ -0,0 +1,79 @@
+// /**
+//  * Copyright © 2016 Magento. All rights reserved.
+//  * See COPYING.txt for license details.
+//  */
+
+.adminhtml-integration-index {
+    .data-grid {
+        .action {
+            &:extend(.abs-action-reset all);
+
+            &[disabled] {
+                color: @color-gray-light2;
+                cursor: not-allowed;
+                opacity: 0.6;
+            }
+
+            &:hover {
+                &:before {
+                    color: @color-gray-middle3;
+                }
+            }
+
+            &:before {
+                &:extend(.abs-icon all);
+            }
+
+            &.edit {
+                &:before {
+                    content: @icon-edit__content;
+                }
+            }
+
+            &.info {
+                &:before {
+                    content: @icon-info__content;
+                }
+            }
+
+            &.delete {
+                &:before {
+                    content: @icon-delete__content;
+                }
+            }
+        }
+    }
+
+    .security-notice {
+        color: @color-red11;
+        font-size: @font-size__tiny;
+        margin-left: 1.5rem;
+        vertical-align: middle;
+
+        &:before {
+            &:extend(.abs-icon all);
+            content: @icon-warning__content;
+            margin-right: @indent__xs;
+        }
+    }
+
+    input[readonly] {
+        cursor: copy;
+    }
+
+    .ui-dialog {
+        .ui-dialog-buttonpane {
+            float: none;
+
+            .ui-dialog-buttonset {
+                text-align: right;
+            }
+        }
+    }
+
+    .no-close {
+        .ui-dialog-titlebar-close {
+            display: none;
+        }
+    }
+}
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 2bc734168353c70e68eeb235b77b3e57cf4d4aa2..90481b2f44545734536bdbb6dae324f2880644f0 100644
--- a/app/design/adminhtml/Magento/backend/web/css/styles-old.less
+++ b/app/design/adminhtml/Magento/backend/web/css/styles-old.less
@@ -756,10 +756,6 @@
         display: none;
     }
 
-    label {
-        display: inline-block;
-    }
-
     label > input[type="radio"],
     label > input[type="checkbox"] {
         margin: -3px 3px 0 0;
diff --git a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/_cart.less b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/_cart.less
index a7850c22dac19d2167fee48698f89c2532feb927..512ec326052272907de276af6299b53d26cc8265 100644
--- a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/_cart.less
+++ b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/_cart.less
@@ -276,6 +276,7 @@
                     text-align: center;
                     white-space: nowrap;
                     width: 33%;
+
                     &:before {
                         content: attr(data-th) ':';
                         display: block;
diff --git a/app/design/frontend/Magento/blank/Magento_Customer/web/css/source/_module.less b/app/design/frontend/Magento/blank/Magento_Customer/web/css/source/_module.less
index 9672c4ce214dc42fc1db55018b5ec81e6e617517..4453309461d020b96bccb033a18c92f26fa11e33 100644
--- a/app/design/frontend/Magento/blank/Magento_Customer/web/css/source/_module.less
+++ b/app/design/frontend/Magento/blank/Magento_Customer/web/css/source/_module.less
@@ -41,7 +41,7 @@
                 .lib-font-size(18);
             }
         }
-    
+
         .fieldset {
             .lib-form-hasrequired(bottom);
             &:after {
@@ -49,35 +49,35 @@
             }
         }
     }
-    
+
     .block-addresses-list {
         .items.addresses {
             > .item {
                 margin-bottom: @indent__base;
-    
+
                 &:last-child {
                     margin-bottom: 0;
                 }
             }
         }
     }
-    
+
     .form-address-edit {
         #region_id {
             display: none;
         }
-    
+
         .actions-toolbar .action.primary {
             &:extend(.abs-button-l all);
         }
     }
-    
+
     .form-edit-account {
         .fieldset.password {
             display: none;
         }
     }
-    
+
     .box-billing-address,
     .box-shipping-address,
     .box-information,
@@ -96,43 +96,43 @@
             h2 {
                 margin-top: 0;
             }
-    
+
             .toolbar {
                 text-align: center;
                 .limiter-options {
                     width: auto;
                 }
             }
-    
+
             .limiter {
                 >.label {
                     &:extend(.abs-visually-hidden all);
                 }
             }
-    
+
             .block:not(.widget) {
                 &:extend(.abs-account-blocks all);
             }
         }
-    
+
         .sidebar-additional {
             margin-top: 40px;
         }
-    
+
         .table-wrapper {
             &:last-child {
                 margin-bottom: 0;
             }
-    
+
             .action {
                 margin-right: 15px;
-    
+
                 &:last-child {
                     margin-right: 0;
                 }
             }
         }
-    
+
         .table-return-items {
             .qty {
                 .input-text {
@@ -141,7 +141,7 @@
             }
         }
     }
-    
+
     //  Checkout address (create shipping address)
     .field.street {
         .field.additional {
@@ -214,10 +214,10 @@
                 margin-bottom: 0;
             }
         }
-    
+
         .title {
             margin-bottom: @indent__s;
-    
+
             strong {
                 .lib-heading(h4);
                 .column.main & {
@@ -272,42 +272,42 @@
             z-index: -1;
         }
 
-        .password-strength-meter-0 & {
+        .password-none & {
             &:before {
                 background-color: @_password-default;
                 width: 100%;
             }
         }
 
-        .password-strength-meter-1 & {
+        .password-weak & {
             &:before {
                 background-color: @_password-weak;
                 width: 25%;
             }
         }
 
-        .password-strength-meter-2 & {
+        .password-medium & {
             &:before {
                 background-color: @_password-medium;
                 width: 50%;
             }
         }
 
-        .password-strength-meter-3 & {
+        .password-strong & {
             &:before {
                 background-color: @_password-strong;
                 width: 75%;
             }
         }
 
-        .password-strength-meter-4 & {
+        .password-very-strong & {
             &:before {
                 background-color: @_password-very-strong;
                 width: 100%;
             }
         }
     }
-    
+
     .control.captcha-image {
         .lib-css(margin-top, @indent__s);
 
diff --git a/app/design/frontend/Magento/blank/Magento_GiftMessage/web/css/source/_module.less b/app/design/frontend/Magento/blank/Magento_GiftMessage/web/css/source/_module.less
index 450de45c9152ec7a14e0bb0a9bf9f73aa458795a..59ee7d7dcc472ec6576e939cdcc53a86474d1164 100644
--- a/app/design/frontend/Magento/blank/Magento_GiftMessage/web/css/source/_module.less
+++ b/app/design/frontend/Magento/blank/Magento_GiftMessage/web/css/source/_module.less
@@ -18,6 +18,9 @@
 & when (@media-common = true) {
     .gift-message {
         .field {
+            &:extend(.abs-clearfix all);
+            margin-bottom: @indent__base;
+
             .label {
                 .lib-css(color, @gift-message-field-label__color);
                 .lib-css(font-weight, @font-weight__regular);
@@ -27,6 +30,7 @@
 
     .gift-options {
         &:extend(.abs-add-clearfix all);
+
         .actions-toolbar {
             .action-cancel {
                 &:extend(.abs-action-button-as-link all);
@@ -44,6 +48,7 @@
             margin: 0 0 @indent__base;
         }
     }
+
     .gift-summary {
         .actions-toolbar {
             > .secondary {
@@ -56,39 +61,43 @@
         }
     }
 
-    //
-    //  In-table block
-    //  ---------------------------------------------
-
-    .cart.table-wrapper {
-        .gift-content {
-            box-sizing: border-box;
-            clear: left;
-            display: none;
-            float: left;
-            margin: @indent__base 0;
-            text-align: left;
-            width: 100%;
-
-            &._active {
-                display: block;
-            }
-        }
+    .action-gift {
+        &:extend(.cart.table-wrapper .actions-toolbar > .action all);
 
-        .action-gift {
-            &:extend(.cart.table-wrapper .actions-toolbar > .action all);
-            .lib-button-icon(
+        .lib-button-icon(
             @icon-down,
             @_icon-font-size: 32px,
             @_icon-font-line-height: 16px,
             @_icon-font-position: after
-            );
+        );
 
-            &._active {
-                .lib-icon-font-symbol(
+        &.active,
+        &._active {
+            .lib-icon-font-symbol(
                 @icon-up,
                 @_icon-font-position: after
-                );
+            );
+        }
+    }
+
+    //
+    //  In-table block
+    //  ---------------------------------------------
+
+    .cart {
+        &.table-wrapper {
+            .gift-content {
+                box-sizing: border-box;
+                clear: left;
+                display: none;
+                float: left;
+                margin: @indent__s 0 @indent__base;
+                text-align: left;
+                width: 100%;
+
+                &._active {
+                    display: block;
+                }
             }
         }
     }
@@ -99,6 +108,7 @@
 
     .gift-item-block {
         margin: 0;
+
         &._active {
             .title {
                 .lib-icon-font-symbol(
@@ -109,7 +119,9 @@
         }
 
         .title {
+            .lib-css(font-weight, @font-weight__bold);
             border-radius: 3px;
+
             .lib-button(
             @_button-margin: 20px 0 0,
             @_button-padding: 7px 15px,
@@ -120,7 +132,6 @@
             @_button-icon-font-line-height: 16px,
             @_button-icon-font-position: after
             );
-            .lib-css(font-weight, @font-weight__bold);
 
             &:active {
                 .lib-css(box-shadow, @button__shadow);
@@ -165,41 +176,41 @@
                 clear: left;
             }
         }
-    }
 
-    .order-details-items .order-items {
-        .order-gift-message {
-            &:not(.expanded-content) {
-                &:extend(.abs-hidden);
-            }
+        .order-items {
+            .order-gift-message {
+                &:not(.expanded-content) {
+                    &:extend(.abs-hidden);
+                }
 
-            .action.close {
-                &:extend(.abs-no-display all);
+                .action.close {
+                    &:extend(.abs-no-display all);
+                }
             }
-        }
 
-        .action.show {
-            .lib-icon-font(
-            @_icon-font-content: @icon-down,
-            @_icon-font-size: 22px,
-            @_icon-font-text-hide: false,
-            @_icon-font-position: after,
-            @_icon-font-display: inline-block
-            );
-            padding-right: @indent__base;
-            position: relative;
+            .action.show {
+                .lib-icon-font(
+                @_icon-font-content: @icon-down,
+                @_icon-font-size: 22px,
+                @_icon-font-text-hide: false,
+                @_icon-font-position: after,
+                @_icon-font-display: inline-block
+                );
+                padding-right: @indent__base;
+                position: relative;
 
-            &:after {
-                position: absolute;
-                right: 0;
-                top: -4px;
-            }
+                &:after {
+                    position: absolute;
+                    right: 0;
+                    top: -4px;
+                }
 
-            &.expanded {
-                .lib-icon-font-symbol(
-                @_icon-font-content: @icon-up,
-                @_icon-font-position: after
-                );
+                &.expanded {
+                    .lib-icon-font-symbol(
+                    @_icon-font-content: @icon-up,
+                    @_icon-font-position: after
+                    );
+                }
             }
         }
     }
@@ -226,22 +237,26 @@
     }
 
     .gift-item-block {
-        border-bottom: 0;
         .lib-css(border-top, @gift-item-block__border-width solid @gift-item-block__border-color);
+        border-bottom: 0;
     }
 
-    .cart.table-wrapper {
-        .gift-content {
-            margin-right: -@indent__s;
+    .cart {
+        &.table-wrapper {
+            .gift-content {
+                margin-right: -@indent__s;
+            }
         }
     }
 }
 
 .media-width(@extremum, @break) when (@extremum = 'max') and (@break = @screen__s) {
-    .cart.table-wrapper {
-        .gift-content {
-            border-bottom: @border-width__base solid @border-color__base;
-            margin-bottom: @indent__base;
+    .cart {
+        &.table-wrapper {
+            .gift-content {
+                border-bottom: @border-width__base solid @border-color__base;
+                margin-bottom: @indent__base;
+            }
         }
     }
 }
@@ -253,11 +268,7 @@
 .media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__m) {
     .gift-message {
         .field {
-            &:extend(.abs-clearfix all);
-            .lib-form-field-type-revert(
-            @_type: inline,
-            @_type-inline-label-align: left
-            );
+            margin-bottom: @indent__base;
         }
     }
 
@@ -323,9 +334,22 @@
     //  In-table block
     //  ---------------------------------------------
 
-    .cart.table-wrapper {
-        .action-gift {
-            float: left;
+    .cart {
+        &.table-wrapper {
+            .action-gift {
+                float: left;
+            }
+        }
+    }
+
+    //
+    //  Multiple Shipping Checkout
+    //  ---------------------------------------------
+
+    .order-options,
+    .table-order-review {
+        .gift-wrapping {
+            max-width: 50%;
         }
     }
 }
diff --git a/app/design/frontend/Magento/blank/Magento_GiftWrapping/web/css/source/_module.less b/app/design/frontend/Magento/blank/Magento_GiftWrapping/web/css/source/_module.less
index e2b3771ac38863afddd2e4420d6b2337afb088c6..b4665dbd62e965e3bc5925ea2e47ece7bb063f28 100644
--- a/app/design/frontend/Magento/blank/Magento_GiftWrapping/web/css/source/_module.less
+++ b/app/design/frontend/Magento/blank/Magento_GiftWrapping/web/css/source/_module.less
@@ -25,6 +25,17 @@
 //  _____________________________________________
 
 & when (@media-common = true) {
+    .gift-wrapping {
+        .label {
+            .lib-css(margin, @form-field-type-label-block__margin);
+            display: inline-block;
+        }
+
+        .field {
+            margin-bottom: @indent__s;
+        }
+    }
+
     .gift-wrapping-info {
         .lib-css(font-weight, @font-weight__light);
         font-size: @font-size__l;
@@ -147,6 +158,8 @@
 
     .gift-summary,
     .gift-options {
+        &:extend(.abs-adjustment-incl-excl-tax all);
+
         .price-box {
             margin-left: 22px;
         }
@@ -160,8 +173,30 @@
                 font-weight: @font-weight__bold;
             }
         }
+    }
 
-        &:extend(.abs-adjustment-incl-excl-tax all);
+    //
+    //  Multiple Shipping Checkout
+    //  ---------------------------------------------
+
+    .order-options {
+        .item {
+            padding-bottom: @indent__base;
+        }
+
+        .product {
+            &:extend(.abs-add-clearfix all);
+            margin-bottom: @indent__s;
+        }
+
+        .product-image-container {
+            float: left;
+            padding-right: @indent__s;
+        }
+
+        .gift-wrapping {
+            margin-bottom: @indent__s;
+        }
     }
 }
 
@@ -217,18 +252,21 @@
         }
     }
 
-    .gift-wrapping {
-        box-sizing: border-box;
-        float: left;
-        padding-right: @indent__base;
-        width: 50%;
-
-        & + .gift-message {
-            .lib-css(border-left, @gift-wrapping__border-width solid @gift-wrapping__border-color);
+    .gift-options-cart-item,
+    .cart-gift-item {
+        .gift-wrapping {
             box-sizing: border-box;
             float: left;
-            padding-left: 4.5rem;
+            padding-right: @indent__base;
             width: 50%;
+
+            & + .gift-message {
+                .lib-css(border-left, @gift-wrapping__border-width solid @gift-wrapping__border-color);
+                box-sizing: border-box;
+                float: left;
+                padding-left: 4.5rem;
+                width: 50%;
+            }
         }
     }
 }
diff --git a/app/design/frontend/Magento/luma/Magento_Customer/web/css/source/_module.less b/app/design/frontend/Magento/luma/Magento_Customer/web/css/source/_module.less
index 5eaccc85a2c0d7a8d6f38e65cb478f313c64ebee..4ad7af8c4e8ba9eb362e03013376d51d89a68852 100644
--- a/app/design/frontend/Magento/luma/Magento_Customer/web/css/source/_module.less
+++ b/app/design/frontend/Magento/luma/Magento_Customer/web/css/source/_module.less
@@ -254,35 +254,35 @@
             z-index: -1;
         }
 
-        .password-strength-meter-0 & {
+        .password-none & {
             &:before {
                 background-color: @_password-default;
                 width: 100%;
             }
         }
 
-        .password-strength-meter-1 & {
+        .password-weak & {
             &:before {
                 background-color: @_password-weak;
                 width: 25%;
             }
         }
 
-        .password-strength-meter-2 & {
+        .password-medium & {
             &:before {
                 background-color: @_password-medium;
                 width: 50%;
             }
         }
 
-        .password-strength-meter-3 & {
+        .password-strong & {
             &:before {
                 background-color: @_password-strong;
                 width: 75%;
             }
         }
 
-        .password-strength-meter-4 & {
+        .password-very-strong & {
             &:before {
                 background-color: @_password-very-strong;
                 width: 100%;
diff --git a/app/design/frontend/Magento/luma/Magento_GiftMessage/web/css/source/_module.less b/app/design/frontend/Magento/luma/Magento_GiftMessage/web/css/source/_module.less
index 0b00a22ce92c2e8885977e350ff863295f3440c4..6a579f19583c1020664e88fa40be48494b2d82ab 100644
--- a/app/design/frontend/Magento/luma/Magento_GiftMessage/web/css/source/_module.less
+++ b/app/design/frontend/Magento/luma/Magento_GiftMessage/web/css/source/_module.less
@@ -27,6 +27,9 @@
 & when (@media-common = true) {
     .gift-message {
         .field {
+            &:extend(.abs-clearfix all);
+            margin-bottom: @indent__base;
+
             .label {
                 .lib-css(color, @gift-message-field-label__color);
                 .lib-css(font-weight, @font-weight__regular);
@@ -34,18 +37,6 @@
         }
     }
 
-    .cart.table-wrapper {
-        .item-gift {
-            &._active {
-                .lib-css(border-top, @gift-item-block__border-width solid @gift-item-block__border-color);
-            }
-
-            .action {
-                margin-right: 0;
-            }
-        }
-    }
-
     .gift-options {
         margin: @indent__base 0;
 
@@ -70,6 +61,8 @@
 
     .gift-summary {
         position: relative;
+        margin-top: @indent__s;
+
         .actions-toolbar {
             > .secondary {
                 .action {
@@ -92,6 +85,7 @@
             @_icon-font-color-active: @minicart-icons-color
             );
         }
+
         .action-delete {
             .lib-icon-font-symbol(
             @_icon-font-content: @icon-trash
@@ -99,6 +93,28 @@
         }
     }
 
+    .action-gift {
+        &:extend(.abs-action-button-as-link all);
+
+        .lib-icon-font(
+            @icon-down,
+            @_icon-font-size: 1.2rem,
+            @_icon-font-line-height: 20px,
+            @_icon-font-color: @minicart-icons-color,
+            @_icon-font-color-hover: @primary__color,
+            @_icon-font-color-active: @minicart-icons-color,
+            @_icon-font-margin: 0 0 0 @indent__s,
+            @_icon-font-position: after
+        );
+
+        &.active,
+        &._active {
+            &:after {
+                content: @icon-up;
+            }
+        }
+    }
+
     .gift-summary,
     .cart.table-wrapper .gift-summary {
         .actions-toolbar {
@@ -113,18 +129,30 @@
     //  In-table block
     //  ---------------------------------------------
 
-    .cart.table-wrapper {
-        .gift-content {
-            box-sizing: border-box;
-            clear: left;
-            display: none;
-            float: left;
-            margin-right: -100%;
-            padding: @indent__base 0;
-            width: 100%;
+    .cart {
+        &.table-wrapper {
+            .gift-content {
+                box-sizing: border-box;
+                clear: left;
+                display: none;
+                float: left;
+                margin-right: -100%;
+                padding: @indent__base 0;
+                width: 100%;
 
-            &._active {
-                display: block;
+                &._active {
+                    display: block;
+                }
+            }
+
+            .item-gift {
+                &._active {
+                    .lib-css(border-top, @gift-item-block__border-width solid @gift-item-block__border-color);
+                }
+
+                .action {
+                    margin-right: 0;
+                }
             }
         }
     }
@@ -148,6 +176,10 @@
         .title {
             .lib-css(color, @gift-item-block-title__color);
             cursor: pointer;
+            margin: 0;
+            padding: @indent__s @indent__xl @indent__s 15px;
+            position: relative;
+
             .lib-icon-font(
             @gift-item-block-title-icon__content,
             @_icon-font-size: @gift-item-block-title-icon__font-size,
@@ -158,9 +190,6 @@
             @_icon-font-position: after,
             @_icon-font-display: block
             );
-            margin: 0;
-            padding: @indent__s @indent__xl @indent__s 15px;
-            position: relative;
         }
 
         .content {
@@ -200,9 +229,7 @@
                 }
             }
         }
-    }
 
-    .order-details-items {
         .order-items {
             .order-gift-message {
                 &:not(.expanded-content) {
@@ -216,11 +243,6 @@
         }
     }
 
-    .options-order-container,
-    .options-items-container {
-        margin-bottom: @indent__s;
-    }
-
     .gift-messages-order {
         margin-bottom: @indent__m;
     }
@@ -242,8 +264,8 @@
     }
 
     .gift-item-block {
-        border-bottom: 0;
         .lib-css(border-top, @gift-item-block__border-width solid @gift-item-block__border-color);
+        border-bottom: 0;
 
         .title {
             &:after {
@@ -264,7 +286,21 @@
         padding-right: 7rem;
     }
 
-    .cart.table-wrapper {
+    //
+    //  In-table block
+    //  ---------------------------------------------
+
+    .cart {
+        &.table-wrapper {
+            .gift-content {
+                border-top: @border-width__base solid @color-gray-light5;
+                margin-right: -@mobile-cart-padding;
+                overflow: hidden;
+                padding-left: @mobile-cart-padding;
+                padding-right: @mobile-cart-padding;
+            }
+        }
+
         .action-gift {
             .lib-icon-font(
             @icon-present,
@@ -274,6 +310,7 @@
             @_icon-font-color: @minicart-icons-color,
             @_icon-font-color-hover: @primary__color,
             @_icon-font-color-active: @minicart-icons-color,
+            @_icon-font-margin: 0,
             @_icon-font-position: after
             );
 
@@ -288,14 +325,6 @@
                 }
             }
         }
-
-        .gift-content {
-            border-top: @border-width__base solid @color-gray-light5;
-            margin-right: -@mobile-cart-padding;
-            overflow: hidden;
-            padding-left: @mobile-cart-padding;
-            padding-right: @mobile-cart-padding;
-        }
     }
 
     .gift-options-cart-item {
@@ -311,16 +340,6 @@
 //  _____________________________________________
 
 .media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__m) {
-    .gift-message {
-        .field {
-            &:extend(.abs-clearfix all);
-            .lib-form-field-type-revert(
-            @_type: inline,
-            @_type-inline-label-align: left
-            );
-        }
-    }
-
     .gift-options {
         position: relative;
         z-index: 1;
@@ -369,6 +388,7 @@
 
     .gift-item-block {
         .title {
+            font-size: 1.6rem;
             padding: @indent__base 0;
         }
     }
@@ -384,33 +404,19 @@
     //  In-table block
     //  ---------------------------------------------
 
-    .cart.table-wrapper {
-        .action-gift {
-            float: left;
-            .lib-icon-font(
-            @icon-down,
-            @_icon-font-size: 1.2rem,
-            @_icon-font-line-height: 20px,
-            @_icon-font-color: @minicart-icons-color,
-            @_icon-font-color-hover: @primary__color,
-            @_icon-font-color-active: @minicart-icons-color,
-            @_icon-font-margin: 0 0 0 @indent__s,
-            @_icon-font-position: after
-            );
-
-            &._active {
-                &:after {
-                    content: @icon-up;
+    .cart {
+        &.table-wrapper {
+            .gift-options {
+                .actions-toolbar {
+                    clear: both;
+                    padding: 0;
+                    position: static;
                 }
             }
         }
 
-        .gift-options {
-            .actions-toolbar {
-                clear: both;
-                padding: 0;
-                position: static;
-            }
+        .action-gift {
+            float: left;
         }
     }
 
diff --git a/app/design/frontend/Magento/luma/Magento_GiftWrapping/web/css/source/_module.less b/app/design/frontend/Magento/luma/Magento_GiftWrapping/web/css/source/_module.less
index f751f491a6d4786912b6500598bbc355d36f92ef..858beaefc7d94fc94ae6b5e22a123292425bda54 100644
--- a/app/design/frontend/Magento/luma/Magento_GiftWrapping/web/css/source/_module.less
+++ b/app/design/frontend/Magento/luma/Magento_GiftWrapping/web/css/source/_module.less
@@ -25,6 +25,17 @@
 //  _____________________________________________
 
 & when (@media-common = true) {
+    .gift-wrapping {
+        .label {
+            .lib-css(margin, @form-field-type-label-block__margin);
+            display: inline-block;
+        }
+
+        .field {
+            margin-bottom: @indent__s;
+        }
+    }
+
     .gift-wrapping-info {
         .lib-css(font-weight, @font-weight__light);
         font-size: @font-size__l;
@@ -99,6 +110,7 @@
         .action-remove {
             &:extend(.abs-action-button-as-link all);
             margin: -@indent__xs 0 0 @indent__xs;
+
             .lib-icon-font(
             @icon-trash,
             @_icon-font-size: 18px,
@@ -130,9 +142,15 @@
     }
 
     .opc-wrapper {
-        .fieldset.gift-message .field.gift-wrapping {
-            padding: 0;
-            width: 100%;
+        .fieldset {
+            &.gift-message {
+                .field {
+                    &.gift-wrapping {
+                        padding: 0;
+                        width: 100%;
+                    }
+                }
+            }
         }
     }
 
@@ -140,6 +158,7 @@
     .table-order-items {
         .gift-wrapping {
             margin: @indent__base 0 0;
+
             .title {
                 float: none;
             }
@@ -160,6 +179,8 @@
 
     .gift-summary,
     .gift-options {
+        &:extend(.abs-adjustment-incl-excl-tax all);
+
         .price-box {
             margin-left: 22px;
         }
@@ -173,8 +194,30 @@
                 font-weight: @font-weight__bold;
             }
         }
+    }
 
-        &:extend(.abs-adjustment-incl-excl-tax all);
+    //
+    //  Multiple Shipping Checkout
+    //  ---------------------------------------------
+
+    .order-options {
+        .item {
+            padding-bottom: @indent__base;
+        }
+
+        .product {
+            &:extend(.abs-add-clearfix all);
+            margin-bottom: @indent__s;
+        }
+
+        .product-image-container {
+            float: left;
+            padding-right: @indent__s;
+        }
+
+        .gift-wrapping {
+            margin-bottom: @indent__s;
+        }
     }
 }
 
@@ -183,12 +226,16 @@
 //  _____________________________________________
 
 .media-width(@extremum, @break) when (@extremum = 'max') and (@break = @screen__m) {
-    .gift-wrapping {
-        .lib-css(border-bottom, @gift-wrapping__border-width solid @gift-wrapping__border-color);
-        margin-bottom: @indent__base;
-        padding-bottom: @indent__s;
+    .gift-options-cart-item,
+    .cart-gift-item {
+        .gift-wrapping {
+            .lib-css(border-bottom, @gift-wrapping__border-width solid @gift-wrapping__border-color);
+            margin-bottom: @indent__base;
+            padding-bottom: @indent__s;
+        }
     }
 
+
     .gift-wrapping-list {
         width: 100%;
     }
@@ -238,18 +285,42 @@
 //  _____________________________________________
 
 .media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__m) {
-    .gift-wrapping {
-        box-sizing: border-box;
-        float: left;
-        padding-right: @indent__base;
-        width: 50%;
-
-        & + .gift-message {
-            .lib-css(border-left, @gift-wrapping__border-width solid @gift-wrapping__border-color);
+    .gift-options-cart-item,
+    .cart-gift-item {
+        .gift-wrapping {
             box-sizing: border-box;
             float: left;
-            padding-left: 4.5rem;
+            padding-right: @indent__base;
             width: 50%;
+
+            & + .gift-message {
+                .lib-css(border-left, @gift-wrapping__border-width solid @gift-wrapping__border-color);
+                box-sizing: border-box;
+                float: left;
+                padding-left: 4.5rem;
+                width: 50%;
+            }
+        }
+
+        .gift-summary {
+            .regular-price {
+                white-space: nowrap;
+            }
+        }
+
+        .gift-wrapping-name {
+            padding-right: @indent__base;
+        }
+    }
+
+    //
+    //  Multiple Shipping Checkout
+    //  ---------------------------------------------
+
+    .order-options,
+    .table-order-review {
+        .gift-wrapping {
+            max-width: 50%;
         }
     }
 }
diff --git a/composer.json b/composer.json
index e95bd4e1a226d231f72ea191604cdfdf0e06f051..b90db7519b5aa6fabc7839e13918e7d88d8d7c0f 100644
--- a/composer.json
+++ b/composer.json
@@ -41,7 +41,7 @@
         "oyejorge/less.php": "~1.7.0",
         "pelago/emogrifier": "0.1.1",
         "tubalmartin/cssmin": "2.4.8-p4",
-        "magento/magento-composer-installer": "*",
+        "magento/magento-composer-installer": ">=0.1.11",
         "braintree/braintree_php": "3.7.0",
         "symfony/console": "~2.3 <2.7",
         "symfony/event-dispatcher": "~2.1",
diff --git a/composer.lock b/composer.lock
index fa33302ecd436068dc0e6f461ee1728a04e33a90..897f4db750e35c4ad1f6ffb4cb9687520c5b36b7 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": "aff7fa6dabe298220186da680893030c",
-    "content-hash": "38de5bfd21f69bb1a076b127b3a80d56",
+    "hash": "e447a3cde1c69182cd539976df5284d2",
+    "content-hash": "77f475ee4b3a11984e7cebfd321a1081",
     "packages": [
         {
             "name": "braintree/braintree_php",
@@ -1253,16 +1253,16 @@
         },
         {
             "name": "symfony/event-dispatcher",
-            "version": "v2.8.7",
+            "version": "v2.8.8",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/event-dispatcher.git",
-                "reference": "2a6b8713f8bdb582058cfda463527f195b066110"
+                "reference": "b180b70439dca70049b6b9b7e21d75e6e5d7aca9"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/2a6b8713f8bdb582058cfda463527f195b066110",
-                "reference": "2a6b8713f8bdb582058cfda463527f195b066110",
+                "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/b180b70439dca70049b6b9b7e21d75e6e5d7aca9",
+                "reference": "b180b70439dca70049b6b9b7e21d75e6e5d7aca9",
                 "shasum": ""
             },
             "require": {
@@ -1309,20 +1309,20 @@
             ],
             "description": "Symfony EventDispatcher Component",
             "homepage": "https://symfony.com",
-            "time": "2016-06-06 11:11:27"
+            "time": "2016-06-29 05:29:29"
         },
         {
             "name": "symfony/filesystem",
-            "version": "v2.8.7",
+            "version": "v2.8.8",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/filesystem.git",
-                "reference": "dee379131dceed90a429e951546b33edfe7dccbb"
+                "reference": "7258ddd6f987053f21fa43d03430580ba54e6096"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/filesystem/zipball/dee379131dceed90a429e951546b33edfe7dccbb",
-                "reference": "dee379131dceed90a429e951546b33edfe7dccbb",
+                "url": "https://api.github.com/repos/symfony/filesystem/zipball/7258ddd6f987053f21fa43d03430580ba54e6096",
+                "reference": "7258ddd6f987053f21fa43d03430580ba54e6096",
                 "shasum": ""
             },
             "require": {
@@ -1358,20 +1358,20 @@
             ],
             "description": "Symfony Filesystem Component",
             "homepage": "https://symfony.com",
-            "time": "2016-04-12 18:01:21"
+            "time": "2016-06-29 05:31:50"
         },
         {
             "name": "symfony/finder",
-            "version": "v3.1.1",
+            "version": "v3.1.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/finder.git",
-                "reference": "40d17ed287bf51a2f884c4619ce8ff2a1c5cd219"
+                "reference": "8201978de88a9fa0923e18601bb17f1df9c721e7"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/finder/zipball/40d17ed287bf51a2f884c4619ce8ff2a1c5cd219",
-                "reference": "40d17ed287bf51a2f884c4619ce8ff2a1c5cd219",
+                "url": "https://api.github.com/repos/symfony/finder/zipball/8201978de88a9fa0923e18601bb17f1df9c721e7",
+                "reference": "8201978de88a9fa0923e18601bb17f1df9c721e7",
                 "shasum": ""
             },
             "require": {
@@ -1407,20 +1407,20 @@
             ],
             "description": "Symfony Finder Component",
             "homepage": "https://symfony.com",
-            "time": "2016-05-13 18:06:41"
+            "time": "2016-06-29 05:41:56"
         },
         {
             "name": "symfony/process",
-            "version": "v2.8.7",
+            "version": "v2.8.8",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/process.git",
-                "reference": "115347d00c342198cdc52a7bd8bc15b5ab43500c"
+                "reference": "89f33c16796415ccfd8bb3cf8d520cbb79899bfe"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/process/zipball/115347d00c342198cdc52a7bd8bc15b5ab43500c",
-                "reference": "115347d00c342198cdc52a7bd8bc15b5ab43500c",
+                "url": "https://api.github.com/repos/symfony/process/zipball/89f33c16796415ccfd8bb3cf8d520cbb79899bfe",
+                "reference": "89f33c16796415ccfd8bb3cf8d520cbb79899bfe",
                 "shasum": ""
             },
             "require": {
@@ -1456,7 +1456,7 @@
             ],
             "description": "Symfony Process Component",
             "homepage": "https://symfony.com",
-            "time": "2016-06-06 11:11:27"
+            "time": "2016-06-29 05:29:29"
         },
         {
             "name": "tedivm/jshrink",
@@ -3105,16 +3105,16 @@
         },
         {
             "name": "fabpot/php-cs-fixer",
-            "version": "v1.11.4",
+            "version": "v1.11.5",
             "source": {
                 "type": "git",
                 "url": "https://github.com/FriendsOfPHP/PHP-CS-Fixer.git",
-                "reference": "eeb280e909834603ffe03524dbe0066e77c83084"
+                "reference": "d3d08b76753092a232a4d8c3b94095ac06898719"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/FriendsOfPHP/PHP-CS-Fixer/zipball/eeb280e909834603ffe03524dbe0066e77c83084",
-                "reference": "eeb280e909834603ffe03524dbe0066e77c83084",
+                "url": "https://api.github.com/repos/FriendsOfPHP/PHP-CS-Fixer/zipball/d3d08b76753092a232a4d8c3b94095ac06898719",
+                "reference": "d3d08b76753092a232a4d8c3b94095ac06898719",
                 "shasum": ""
             },
             "require": {
@@ -3128,8 +3128,12 @@
                 "symfony/process": "~2.3|~3.0",
                 "symfony/stopwatch": "~2.5|~3.0"
             },
+            "conflict": {
+                "hhvm": "<3.9"
+            },
             "require-dev": {
-                "satooshi/php-coveralls": "0.7.*@dev"
+                "phpunit/phpunit": "^4.5|^5",
+                "satooshi/php-coveralls": "^0.7.1"
             },
             "bin": [
                 "php-cs-fixer"
@@ -3156,7 +3160,7 @@
             ],
             "description": "A tool to automatically fix PHP code style",
             "abandoned": "friendsofphp/php-cs-fixer",
-            "time": "2016-06-07 07:51:27"
+            "time": "2016-07-06 22:49:35"
         },
         {
             "name": "lusitanian/oauth",
@@ -4189,16 +4193,16 @@
         },
         {
             "name": "symfony/config",
-            "version": "v2.8.7",
+            "version": "v2.8.8",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/config.git",
-                "reference": "a2edd59c2163c65747fc3f35d132b5a39266bd05"
+                "reference": "0926e69411eba491803dbafb9f1f233e2ced58d0"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/config/zipball/a2edd59c2163c65747fc3f35d132b5a39266bd05",
-                "reference": "a2edd59c2163c65747fc3f35d132b5a39266bd05",
+                "url": "https://api.github.com/repos/symfony/config/zipball/0926e69411eba491803dbafb9f1f233e2ced58d0",
+                "reference": "0926e69411eba491803dbafb9f1f233e2ced58d0",
                 "shasum": ""
             },
             "require": {
@@ -4238,20 +4242,20 @@
             ],
             "description": "Symfony Config Component",
             "homepage": "https://symfony.com",
-            "time": "2016-06-06 11:11:27"
+            "time": "2016-06-29 05:31:50"
         },
         {
             "name": "symfony/dependency-injection",
-            "version": "v2.8.7",
+            "version": "v2.8.8",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/dependency-injection.git",
-                "reference": "2d05009d890cf1139988ff059b5b2e0eb280ed13"
+                "reference": "2dd85de8216079d1360b2b14988cd5cdbbb49063"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/2d05009d890cf1139988ff059b5b2e0eb280ed13",
-                "reference": "2d05009d890cf1139988ff059b5b2e0eb280ed13",
+                "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/2dd85de8216079d1360b2b14988cd5cdbbb49063",
+                "reference": "2dd85de8216079d1360b2b14988cd5cdbbb49063",
                 "shasum": ""
             },
             "require": {
@@ -4301,20 +4305,20 @@
             ],
             "description": "Symfony DependencyInjection Component",
             "homepage": "https://symfony.com",
-            "time": "2016-06-06 11:11:27"
+            "time": "2016-06-29 05:31:50"
         },
         {
             "name": "symfony/stopwatch",
-            "version": "v3.1.1",
+            "version": "v3.1.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/stopwatch.git",
-                "reference": "e7238f98c90b99e9b53f3674a91757228663b04d"
+                "reference": "bb42806b12c5f89db4ebf64af6741afe6d8457e1"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/stopwatch/zipball/e7238f98c90b99e9b53f3674a91757228663b04d",
-                "reference": "e7238f98c90b99e9b53f3674a91757228663b04d",
+                "url": "https://api.github.com/repos/symfony/stopwatch/zipball/bb42806b12c5f89db4ebf64af6741afe6d8457e1",
+                "reference": "bb42806b12c5f89db4ebf64af6741afe6d8457e1",
                 "shasum": ""
             },
             "require": {
@@ -4350,20 +4354,20 @@
             ],
             "description": "Symfony Stopwatch Component",
             "homepage": "https://symfony.com",
-            "time": "2016-06-06 11:42:41"
+            "time": "2016-06-29 05:41:56"
         },
         {
             "name": "symfony/yaml",
-            "version": "v2.8.7",
+            "version": "v2.8.8",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/yaml.git",
-                "reference": "815fabf3f48c7d1df345a69d1ad1a88f59757b34"
+                "reference": "dba4bb5846798cd12f32e2d8f3f35d77045773c8"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/yaml/zipball/815fabf3f48c7d1df345a69d1ad1a88f59757b34",
-                "reference": "815fabf3f48c7d1df345a69d1ad1a88f59757b34",
+                "url": "https://api.github.com/repos/symfony/yaml/zipball/dba4bb5846798cd12f32e2d8f3f35d77045773c8",
+                "reference": "dba4bb5846798cd12f32e2d8f3f35d77045773c8",
                 "shasum": ""
             },
             "require": {
@@ -4399,7 +4403,7 @@
             ],
             "description": "Symfony Yaml Component",
             "homepage": "https://symfony.com",
-            "time": "2016-06-06 11:11:27"
+            "time": "2016-06-29 05:29:29"
         },
         {
             "name": "theseer/fdomdocument",
diff --git a/dev/tests/functional/tests/app/Magento/Authorizenet/Test/TestCase/OnePageCheckoutTest.xml b/dev/tests/functional/tests/app/Magento/Authorizenet/Test/TestCase/OnePageCheckoutTest.xml
index 2ea4873f454a3cbdada0b94c96b90f6c5271b91c..c8cbd35427d288174ce64f0ea5df6474219444c4 100644
--- a/dev/tests/functional/tests/app/Magento/Authorizenet/Test/TestCase/OnePageCheckoutTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Authorizenet/Test/TestCase/OnePageCheckoutTest.xml
@@ -26,8 +26,7 @@
                 <item name="isClosed" xsi:type="string">No</item>
                 <item name="transactionType" xsi:type="string">Authorization</item>
             </data>
-            <data name="tag" xsi:type="string">test_type:3rd_party_test_deprecated</data>
-            <constraint name="Magento\Sales\Test\Constraint\AssertTransactionDetails" />
+            <data name="tag" xsi:type="string">test_type:3rd_party_test</data>
             <constraint name="Magento\Checkout\Test\Constraint\AssertOrderSuccessPlacedMessage" />
             <constraint name="Magento\Checkout\Test\Constraint\AssertMinicartEmpty" />
             <constraint name="Magento\Sales\Test\Constraint\AssertOrderGrandTotal" />
diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Block/FormPageActions.php b/dev/tests/functional/tests/app/Magento/Backend/Test/Block/FormPageActions.php
old mode 100644
new mode 100755
index ecb59b6351a21eb68156216a9fecc0163e74c0e8..801000227c0d7fd7364be743ddad9ef36b240e49
--- a/dev/tests/functional/tests/app/Magento/Backend/Test/Block/FormPageActions.php
+++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Block/FormPageActions.php
@@ -85,7 +85,7 @@ class FormPageActions extends PageActions
      */
     public function reset()
     {
-        $this->waitBeforeClick();
+        $this->waitForElementVisible($this->resetButton);
         $this->_rootElement->find($this->resetButton)->click();
     }
 
@@ -94,7 +94,7 @@ class FormPageActions extends PageActions
      */
     public function saveAndContinue()
     {
-        $this->waitBeforeClick();
+        $this->waitForElementVisible($this->saveAndContinueButton);
         $this->_rootElement->find($this->saveAndContinueButton)->click();
         $this->waitForElementNotVisible('.popup popup-loading');
         $this->waitForElementNotVisible('.loader');
@@ -105,7 +105,7 @@ class FormPageActions extends PageActions
      */
     public function save()
     {
-        $this->waitBeforeClick();
+        $this->waitForElementVisible($this->saveButton);
         $this->_rootElement->find($this->saveButton)->click();
         $this->waitForElementNotVisible($this->spinner);
         $this->waitForElementNotVisible($this->loader, Locator::SELECTOR_XPATH);
@@ -117,7 +117,10 @@ class FormPageActions extends PageActions
      */
     public function delete()
     {
-        $this->waitBeforeClick();
+        $this->waitForElementNotVisible($this->spinner);
+        $this->waitForElementNotVisible($this->loader, Locator::SELECTOR_XPATH);
+        $this->waitForElementNotVisible($this->loaderOld, Locator::SELECTOR_XPATH);
+        $this->waitForElementVisible($this->deleteButton);
         $this->_rootElement->find($this->deleteButton)->click();
     }
 
@@ -130,16 +133,4 @@ class FormPageActions extends PageActions
     {
         return $this->_rootElement->find($this->deleteButton)->isVisible();
     }
-
-    /**
-     * Wait for User before clicking any Button which calls JS validation on correspondent form.
-     * See details in MAGETWO-31121.
-     *
-     * @return void
-     */
-    protected function waitBeforeClick()
-    {
-        time_nanosleep(0, 600000000);
-        usleep(1000000);
-    }
 }
diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Block/Widget/Grid.php b/dev/tests/functional/tests/app/Magento/Backend/Test/Block/Widget/Grid.php
old mode 100644
new mode 100755
index 45f4e3427554b4c2f8569ff08ae689a5915854bf..02f19ce4bce4c3c4e490704ae4a44d17f0117158
--- a/dev/tests/functional/tests/app/Magento/Backend/Test/Block/Widget/Grid.php
+++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Block/Widget/Grid.php
@@ -467,6 +467,7 @@ abstract class Grid extends Block
      */
     public function openFirstRow()
     {
+        $this->waitLoader();
         $this->_rootElement->find($this->firstRowSelector, Locator::SELECTOR_XPATH)->click();
     }
 
diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/History.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/History.php
index b3b0f4eafa74cc44467414cb127b08d099b7d7dd..2235122955a723ccc0cafcafc51d24934405e896 100644
--- a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/History.php
+++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/History.php
@@ -21,6 +21,13 @@ class History extends Block
      */
     protected $commentHistory = '.note-list-comment';
 
+    /**
+     * Authorized Amount.
+     *
+     * @var string
+     */
+    protected $authorizedAmount = '//div[@class="note-list-comment"][contains(text(), "Authorized amount of")]';
+
     /**
      * Captured Amount from IPN.
      *
@@ -53,6 +60,17 @@ class History extends Block
         return $this->_rootElement->find($this->commentHistory, Locator::SELECTOR_CSS)->getText();
     }
 
+    /**
+     * Get the authorized amount from the comments history.
+     *
+     * @return string
+     */
+    public function getAuthorizedAmount()
+    {
+        $this->waitCommentsHistory();
+        return $this->_rootElement->find($this->authorizedAmount, Locator::SELECTOR_XPATH)->getText();
+    }
+
     /**
      * Get the captured amount from the comments history.
      *
diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertAuthorizationInCommentsHistory.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertAuthorizationInCommentsHistory.php
index 7495855d5351fac31be919a13d3bb604c486d8bb..a6b8e8983d2b617953b93490dc4c3a3e1079cec2 100644
--- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertAuthorizationInCommentsHistory.php
+++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertAuthorizationInCommentsHistory.php
@@ -38,7 +38,7 @@ class AssertAuthorizationInCommentsHistory extends AbstractConstraint
         $salesOrder->open();
         $salesOrder->getSalesOrderGrid()->searchAndOpen(['id' => $orderId]);
 
-        $actualAuthorizedAmount = $salesOrderView->getOrderHistoryBlock()->getCommentsHistory();
+        $actualAuthorizedAmount = $salesOrderView->getOrderHistoryBlock()->getAuthorizedAmount();
 
         \PHPUnit_Framework_Assert::assertContains(
             self::AUTHORIZED_AMOUNT . $prices['grandTotal'],
diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertTransactionDetails.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertTransactionDetails.php
deleted file mode 100644
index f793d57df1108988f5a629fd90f5a20bea6935fa..0000000000000000000000000000000000000000
--- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertTransactionDetails.php
+++ /dev/null
@@ -1,69 +0,0 @@
-<?php
-/**
- * Copyright © 2016 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-
-namespace Magento\Sales\Test\Constraint;
-
-use Magento\Sales\Test\Block\Adminhtml\Order\View\Tab\Transactions\Grid;
-use Magento\Sales\Test\Fixture\OrderInjectable;
-use Magento\Sales\Test\Page\Adminhtml\OrderIndex;
-use Magento\Sales\Test\Page\Adminhtml\SalesOrderView;
-use Magento\Mtf\Constraint\AbstractConstraint;
-
-/**
- * Assert that transaction is present in the Transactions tab of the order with corresponding status
- */
-class AssertTransactionDetails extends AbstractConstraint
-{
-    /**
-     * Message about authorized amount in order.
-     */
-    const AUTHORIZED_AMOUNT = 'Authorized amount of $';
-
-    /**
-     * Assert that comment about authorized amount exist in Comments History section on order page in Admin.
-     *
-     * @param SalesOrderView $salesOrderView
-     * @param OrderIndex $salesOrder
-     * @param string $orderId
-     * @param array $transactionDetails
-     * @throws \Exception
-     */
-    public function processAssert(
-        SalesOrderView $salesOrderView,
-        OrderIndex $salesOrder,
-        $orderId,
-        array $transactionDetails
-    ) {
-        $transactionId = '';
-        $salesOrder->open();
-        $salesOrder->getSalesOrderGrid()->searchAndOpen(['id' => $orderId]);
-        $comment = $salesOrderView->getOrderHistoryBlock()->getCommentsHistory();
-        preg_match('/(ID: ")(\w+-*\w+)(")/', $comment, $matches);
-        if (!empty($matches[2])) {
-            $transactionId = $matches[2];
-        }
-        \PHPUnit_Framework_Assert::assertNotEmpty($transactionId);
-        $orderForm = $salesOrderView->getOrderForm()->openTab('transactions');
-        /** @var Grid $grid */
-        $grid = $orderForm->getTab('transactions')->getGridBlock();
-        $actualTxnIds = $grid->getIds();
-        \PHPUnit_Framework_Assert::assertEquals(
-            $transactionDetails,
-            $actualTxnIds[$transactionId],
-            'Incorrect transaction details for the order #' . $orderId
-        );
-    }
-
-    /**
-     * Returns string representation of successful assertion.
-     *
-     * @return string
-     */
-    public function toString()
-    {
-        return "Message about transaction details are present in Transactions tab.";
-    }
-}
diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/etc/di.xml b/dev/tests/functional/tests/app/Magento/Sales/Test/etc/di.xml
index 9a8f26a0505ba37a65bed0d0728b9594d6f29185..ea687be19d3c34b0eeb5093690e54243731543ff 100644
--- a/dev/tests/functional/tests/app/Magento/Sales/Test/etc/di.xml
+++ b/dev/tests/functional/tests/app/Magento/Sales/Test/etc/di.xml
@@ -36,9 +36,4 @@
             <argument name="severity" xsi:type="string">high</argument>
         </arguments>
     </type>
-    <type name="Magento\Sales\Test\Constraint\AssertTransactionDetails">
-        <arguments>
-            <argument name="severity" xsi:type="string">high</argument>
-        </arguments>
-    </type>
 </config>
diff --git a/dev/tests/functional/tests/app/Magento/SalesRule/Test/TestStep/CreateSalesRuleStep.php b/dev/tests/functional/tests/app/Magento/SalesRule/Test/TestStep/CreateSalesRuleStep.php
index d919ecc88eae2d141912a72daa6544291c7d20f3..cdceb7404e20bd22b3093655e7a8acd452dc870c 100644
--- a/dev/tests/functional/tests/app/Magento/SalesRule/Test/TestStep/CreateSalesRuleStep.php
+++ b/dev/tests/functional/tests/app/Magento/SalesRule/Test/TestStep/CreateSalesRuleStep.php
@@ -59,7 +59,6 @@ class CreateSalesRuleStep implements TestStepInterface
     {
         $result['salesRule'] = null;
         if ($this->salesRule !== null) {
-            $this->deleteAllSalesRule->run();
             $salesRule = $this->fixtureFactory->createByCode(
                 'salesRule',
                 ['dataset' => $this->salesRule]
diff --git a/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AbstractAssertOrderTaxOnBackend.php b/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AbstractAssertOrderTaxOnBackend.php
old mode 100644
new mode 100755
index c85ef8ea9a07920572d574828eb40e34bb8382b7..4c6c01b28d9d4ff12fcd0e5f1b2c45d2b4136c49
--- a/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AbstractAssertOrderTaxOnBackend.php
+++ b/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AbstractAssertOrderTaxOnBackend.php
@@ -93,7 +93,6 @@ abstract class AbstractAssertOrderTaxOnBackend extends AbstractConstraint
         $this->orderInvoiceNew = $orderInvoiceNew;
         $this->orderCreditMemoNew = $orderCreditMemoNew;
         $orderIndex->open();
-        $this->waitBeforeClick();
         $orderIndex->getSalesOrderGrid()->openFirstRow();
         //Check prices on order page
         $actualPrices = [];
@@ -223,15 +222,4 @@ abstract class AbstractAssertOrderTaxOnBackend extends AbstractConstraint
     {
         return 'Prices on backend after order creation is correct.';
     }
-
-    /**
-     * Wait for User before click
-     *
-     * @return void
-     */
-    protected function waitBeforeClick()
-    {
-        time_nanosleep(0, 600000000);
-        usleep(1000000);
-    }
 }
diff --git a/dev/tests/functional/tests/app/Magento/Tax/Test/TestStep/CreateTaxRuleStep.php b/dev/tests/functional/tests/app/Magento/Tax/Test/TestStep/CreateTaxRuleStep.php
index 4ddae5cc0da6742fcd42e073809152c975d6793d..37113ef0cc225e0d5f3fb51e626c6bcd499bbfb2 100644
--- a/dev/tests/functional/tests/app/Magento/Tax/Test/TestStep/CreateTaxRuleStep.php
+++ b/dev/tests/functional/tests/app/Magento/Tax/Test/TestStep/CreateTaxRuleStep.php
@@ -59,7 +59,6 @@ class CreateTaxRuleStep implements TestStepInterface
     {
         $result['taxRule'] = null;
         if ($this->taxRule !== null) {
-            $this->deleteAllTaxRule->run();
             $taxRuleDataSets = explode(',', $this->taxRule);
             foreach ($taxRuleDataSets as $taxRuleDataSet) {
                 $taxRule = $this->fixtureFactory->createByCode(
diff --git a/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/IndexTest.php b/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/IndexTest.php
index e3df4d34aabecbc083a17e93f2dfab2416561643..683c8669f73eff0f526cd5eb194f39b6d9118e0a 100644
--- a/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/IndexTest.php
+++ b/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/IndexTest.php
@@ -339,7 +339,12 @@ class IndexTest extends \Magento\TestFramework\TestCase\AbstractBackendControlle
         $this->assertEquals(1, $subscriber->getStatus());
 
         $post = [
-            'customer' => ['entity_id' => $customerId],
+            'customer' => [
+                'entity_id' => $customerId,
+                'email' => 'customer@example.com',
+                'firstname' => 'test firstname',
+                'lastname' => 'test lastname',
+            ],
             'subscription' => 'false'
         ];
         $this->getRequest()->setPostValue($post);
diff --git a/dev/tests/integration/testsuite/Magento/Customer/Model/ResourceModel/CustomerRepositoryTest.php b/dev/tests/integration/testsuite/Magento/Customer/Model/ResourceModel/CustomerRepositoryTest.php
index 250059158bea36881aa9e48fd753a1fe2d850291..1dc2da7750eb49cbe815cc2609e81aaf2c64c5f2 100644
--- a/dev/tests/integration/testsuite/Magento/Customer/Model/ResourceModel/CustomerRepositoryTest.php
+++ b/dev/tests/integration/testsuite/Magento/Customer/Model/ResourceModel/CustomerRepositoryTest.php
@@ -40,6 +40,12 @@ class CustomerRepositoryTest extends \PHPUnit_Framework_TestCase
     /** @var \Magento\Framework\Api\DataObjectHelper  */
     protected $dataObjectHelper;
 
+    /** @var \Magento\Framework\Encryption\EncryptorInterface */
+    protected $encryptor;
+
+    /** @var \Magento\Customer\Model\CustomerRegistry */
+    protected $customerRegistry;
+
     protected function setUp()
     {
         $this->objectManager = Bootstrap::getObjectManager();
@@ -50,6 +56,9 @@ class CustomerRepositoryTest extends \PHPUnit_Framework_TestCase
         $this->accountManagement = $this->objectManager->create('Magento\Customer\Api\AccountManagementInterface');
         $this->converter = $this->objectManager->create('Magento\Framework\Api\ExtensibleDataObjectConverter');
         $this->dataObjectHelper = $this->objectManager->create('Magento\Framework\Api\DataObjectHelper');
+        $this->encryptor = $this->objectManager->create(\Magento\Framework\Encryption\EncryptorInterface::class);
+        $this->customerRegistry = $this->objectManager->create(\Magento\Customer\Model\CustomerRegistry::class);
+
         /** @var \Magento\Framework\Config\CacheInterface $cache */
         $cache = $this->objectManager->create('Magento\Framework\Config\CacheInterface');
         $cache->remove('extension_attributes_config');
@@ -137,6 +146,8 @@ class CustomerRepositoryTest extends \PHPUnit_Framework_TestCase
         $email = 'savecustomer@example.com';
         $firstName = 'Firstsave';
         $lastName = 'Lastsave';
+        $newPassword = 'newPassword123';
+        $newPasswordHash = $this->encryptor->getHash($newPassword, true);
         $customerBefore = $this->customerRepository->getById($existingCustomerId);
         $customerData = array_merge($customerBefore->__toArray(), [
                 'id' => 1,
@@ -154,7 +165,7 @@ class CustomerRepositoryTest extends \PHPUnit_Framework_TestCase
             $customerData,
             '\Magento\Customer\Api\Data\CustomerInterface'
         );
-        $this->customerRepository->save($customerDetails);
+        $this->customerRepository->save($customerDetails, $newPasswordHash);
         $customerAfter = $this->customerRepository->getById($existingCustomerId);
         $this->assertEquals($email, $customerAfter->getEmail());
         $this->assertEquals($firstName, $customerAfter->getFirstname());
@@ -167,8 +178,7 @@ class CustomerRepositoryTest extends \PHPUnit_Framework_TestCase
             $defaultShipping
         );
         $this->assertEquals('Admin', $customerAfter->getCreatedIn());
-        $passwordFromFixture = 'password';
-        $this->accountManagement->authenticate($customerAfter->getEmail(), $passwordFromFixture);
+        $this->accountManagement->authenticate($customerAfter->getEmail(), $newPassword);
         $attributesBefore = $this->converter->toFlatArray(
             $customerBefore,
             [],
diff --git a/lib/internal/Magento/Framework/Api/ImageProcessor.php b/lib/internal/Magento/Framework/Api/ImageProcessor.php
index 768c8d8bdd4cd161c1f67326a9a62183174f6d26..d0cb13d995d7061ac117bbfafeeb6da743598bc6 100644
--- a/lib/internal/Magento/Framework/Api/ImageProcessor.php
+++ b/lib/internal/Magento/Framework/Api/ImageProcessor.php
@@ -123,7 +123,7 @@ class ImageProcessor implements ImageProcessorInterface
                 );
                 if ($previousImageAttribute) {
                     $previousImagePath = $previousImageAttribute->getValue();
-                    if (!empty($previousImagePath)) {
+                    if (!empty($previousImagePath) && ($previousImagePath != $filename)) {
                         @unlink($this->mediaDirectory->getAbsolutePath() . $entityType . $previousImagePath);
                     }
                 }
diff --git a/lib/internal/Magento/Framework/Composer/ComposerFactory.php b/lib/internal/Magento/Framework/Composer/ComposerFactory.php
index bf221531a176da006d5d44847a4b39ec768e6e2b..8169ea7bc666fa3549aeb7c662a4c55c93f62e11 100644
--- a/lib/internal/Magento/Framework/Composer/ComposerFactory.php
+++ b/lib/internal/Magento/Framework/Composer/ComposerFactory.php
@@ -40,9 +40,8 @@ class ComposerFactory
      */
     public function create()
     {
-        if (!getenv('COMPOSER_HOME')) {
-            putenv('COMPOSER_HOME=' . $this->directoryList->getPath(DirectoryList::COMPOSER_HOME));
-        }
+        putenv('COMPOSER_HOME=' . $this->directoryList->getPath(DirectoryList::COMPOSER_HOME));
+
         return \Composer\Factory::create(
             new BufferIO(),
             $this->composerJsonFinder->findComposerJson()
diff --git a/lib/internal/Magento/Framework/HTTP/Client/Curl.php b/lib/internal/Magento/Framework/HTTP/Client/Curl.php
index ee19ce7d961619348eff6e099f7e4f662ff004fb..67525f62f6336cf7de844e866a153be223dc0b5c 100644
--- a/lib/internal/Magento/Framework/HTTP/Client/Curl.php
+++ b/lib/internal/Magento/Framework/HTTP/Client/Curl.php
@@ -12,6 +12,12 @@ namespace Magento\Framework\HTTP\Client;
  */
 class Curl implements \Magento\Framework\HTTP\ClientInterface
 {
+    /**
+     * Max supported protocol by curl CURL_SSLVERSION_TLSv1_2
+     * @var int
+     */
+    private static $sslVersion = 6;
+
     /**
      * Hostname
      * @var string
@@ -374,6 +380,7 @@ class Curl implements \Magento\Framework\HTTP\ClientInterface
         //$this->curlOption(CURLOPT_HEADER, 1);
         $this->curlOption(CURLOPT_RETURNTRANSFER, 1);
         $this->curlOption(CURLOPT_HEADERFUNCTION, [$this, 'parseHeaders']);
+        $this->curlOption(CURLOPT_SSLVERSION, self::$sslVersion);
 
         if (count($this->_curlUserOptions)) {
             foreach ($this->_curlUserOptions as $k => $v) {
diff --git a/lib/internal/Magento/Framework/View/Layout/Data/Structure.php b/lib/internal/Magento/Framework/View/Layout/Data/Structure.php
index dcd01d423cdb48b64ef05198df8f6d27ad80f381..0612231ad5cc896b1daf24c3772ce6057c44b825 100644
--- a/lib/internal/Magento/Framework/View/Layout/Data/Structure.php
+++ b/lib/internal/Magento/Framework/View/Layout/Data/Structure.php
@@ -119,7 +119,7 @@ class Structure extends DataStructure
                 $siblingParentName = $this->getParentId($sibling);
                 if ($parentName !== $siblingParentName) {
                     if ($this->state->getMode() === State::MODE_DEVELOPER) {
-                        $this->logger->critical(
+                        $this->logger->info(
                             "Broken reference: the '{$childName}' tries to reorder itself towards '{$sibling}', but " .
                             "their parents are different: '{$parentName}' and '{$siblingParentName}' respectively."
                         );
diff --git a/lib/internal/Magento/Framework/View/Layout/ScheduledStructure/Helper.php b/lib/internal/Magento/Framework/View/Layout/ScheduledStructure/Helper.php
index 2e0ee3b63dcad103ddcdcc51a36f5930c3d10428..870f147a436342f13b196b430279e631ce60c981 100644
--- a/lib/internal/Magento/Framework/View/Layout/ScheduledStructure/Helper.php
+++ b/lib/internal/Magento/Framework/View/Layout/ScheduledStructure/Helper.php
@@ -201,7 +201,7 @@ class Helper
                 $scheduledStructure->setElementToBrokenParentList($key);
 
                 if ($this->state->getMode() === State::MODE_DEVELOPER) {
-                    $this->logger->critical(
+                    $this->logger->info(
                         "Broken reference: the '{$name}' element cannot be added as child to '{$parentName}', " .
                         'because the latter doesn\'t exist'
                     );
diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Layout/Data/StructureTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Layout/Data/StructureTest.php
index a5f00f082402689bd0943245519841c3e930d16b..d9c39373d76d4447f2a81c877e6e9838ab50ea89 100644
--- a/lib/internal/Magento/Framework/View/Test/Unit/Layout/Data/StructureTest.php
+++ b/lib/internal/Magento/Framework/View/Test/Unit/Layout/Data/StructureTest.php
@@ -64,7 +64,7 @@ class StructureTest extends \PHPUnit_Framework_TestCase
             ->method('getMode')
             ->willReturn($stateMode);
         $this->loggerMock->expects($loggerExpects)
-            ->method('critical')
+            ->method('info')
             ->with(
                 "Broken reference: the '{$childName}' tries to reorder itself towards '', but " .
                 "their parents are different: '{$parentName}' and '' respectively."
diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Layout/ScheduledStructure/HelperTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Layout/ScheduledStructure/HelperTest.php
index 6cb3a5cfdca8366d5cb439acb0f8ee8c00277b3f..8803392d184f0b329cfe22b5492da83b5136fdf7 100644
--- a/lib/internal/Magento/Framework/View/Test/Unit/Layout/ScheduledStructure/HelperTest.php
+++ b/lib/internal/Magento/Framework/View/Test/Unit/Layout/ScheduledStructure/HelperTest.php
@@ -181,7 +181,7 @@ class HelperTest extends \PHPUnit_Framework_TestCase
             ->method('getMode')
             ->willReturn($stateMode);
         $this->loggerMock->expects($loggerExpects)
-            ->method('critical')
+            ->method('info')
             ->with(
                 "Broken reference: the '{$key}' element cannot be added as child to '{$parentName}', " .
                 'because the latter doesn\'t exist'
diff --git a/lib/web/css/source/lib/_dropdowns.less b/lib/web/css/source/lib/_dropdowns.less
index f3559356c365a616bd2a91c94832de0d881af184..be9cef120a686e378d8ff2f681af666ff0d9d6a8 100644
--- a/lib/web/css/source/lib/_dropdowns.less
+++ b/lib/web/css/source/lib/_dropdowns.less
@@ -253,6 +253,7 @@
         .lib-css(z-index, @_dropdown-list-z-index);
         box-sizing: border-box;
         display: none;
+        position: absolute;
 
         ._lib-dropdown-list-position(
             @_dropdown-list-position-top,
@@ -291,7 +292,6 @@
 
         @{_options-selector} {
             display: block;
-            position: absolute;
         }
     }
 }
diff --git a/lib/web/mage/apply/scripts.js b/lib/web/mage/apply/scripts.js
index 7f059a45ae5cd9acbb7c2c1f330419d8abe9f5a8..3b87f4fd2f40e6330f1577ca8dc2251a9f6a04d3 100644
--- a/lib/web/mage/apply/scripts.js
+++ b/lib/web/mage/apply/scripts.js
@@ -88,7 +88,7 @@ define([
 
     /**
      * Parses 'script' tags with a custom type attribute and moves it's data
-     * to a 'data-mage-init' attribute of an elemennt found by provided selector.
+     * to a 'data-mage-init' attribute of an element found by provided selector.
      * Note: All found script nodes will be removed from DOM.
      *
      * @returns {Array} An array of components not assigned to the specific element.
diff --git a/lib/web/mage/menu.js b/lib/web/mage/menu.js
index a3f4ad36d0afa39f911f027754afab67e09925d7..4562285654c70f8b991e89866dfc82977842dd64 100644
--- a/lib/web/mage/menu.js
+++ b/lib/web/mage/menu.js
@@ -18,7 +18,9 @@ define([
         options: {
             responsive: false,
             expanded: false,
-            delay: 300
+            showDelay: 42,
+            hideDelay: 300,
+            mediaBreakpoint: '(max-width: 768px)'
         },
         _create: function () {
             var self = this;
@@ -31,7 +33,6 @@ define([
 
         _init: function () {
             this._super();
-            this.delay = this.options.delay;
 
             if (this.options.expanded === true) {
                 this.isExpanded();
@@ -39,7 +40,7 @@ define([
 
             if (this.options.responsive === true) {
                 mediaCheck({
-                    media: '(max-width: 640px)',
+                    media: this.options.mediaBreakpoint,
                     entry: $.proxy(function () {
                         this._toggleMobileMode();
                     }, this),
@@ -70,23 +71,25 @@ define([
         },
 
         toggle: function () {
-            if ($('html').hasClass('nav-open')) {
-                $('html').removeClass('nav-open');
+            var html = $('html');
+
+            if (html.hasClass('nav-open')) {
+                html.removeClass('nav-open');
                 setTimeout(function () {
-                    $('html').removeClass('nav-before-open');
-                }, 300);
+                    html.removeClass('nav-before-open');
+                }, this.options.hideDelay);
             } else {
-                $('html').addClass('nav-before-open');
+                html.addClass('nav-before-open');
                 setTimeout(function () {
-                    $('html').addClass('nav-open');
-                }, 42);
+                    html.addClass('nav-open');
+                }, this.options.showDelay);
             }
         },
 
         //Add class for expanded option
         isExpanded: function () {
             var subMenus = this.element.find(this.options.menus),
-                expandedMenus = subMenus.find('ul');
+                expandedMenus = subMenus.find(this.options.menus);
 
             expandedMenus.addClass('expanded');
         },
@@ -105,7 +108,7 @@ define([
                 return value.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&");
             }
 
-            if (this.active.closest('ul').attr('aria-expanded') != 'true') {
+            if (this.active.closest(this.options.menus).attr('aria-expanded') != 'true') {
 
                 switch (event.keyCode) {
                     case $.ui.keyCode.PAGE_UP:
@@ -334,15 +337,16 @@ define([
                 },
                 "mouseenter .ui-menu-item": function (event) {
                     var target = $(event.currentTarget),
+                        submenu = this.options.menus,
                         ulElement,
                         ulElementWidth,
                         width,
                         targetPageX,
                         rightBound;
 
-                    if (target.has('ul')) {
-                        ulElement = target.find('ul');
-                        ulElementWidth = target.find('ul').outerWidth(true);
+                    if (target.has(submenu)) {
+                        ulElement = target.find(submenu);
+                        ulElementWidth = ulElement.outerWidth(true);
                         width = target.outerWidth() * 2;
                         targetPageX = target.offset().left;
                         rightBound = $(window).width();
diff --git a/lib/web/mage/validation.js b/lib/web/mage/validation.js
index 209db5d024acc2d37f1c90db38117d37feca14fe..aff3141c2d4d1287ae2a801fd2d411bfa41b231a 100644
--- a/lib/web/mage/validation.js
+++ b/lib/web/mage/validation.js
@@ -1476,8 +1476,8 @@
             errorPlacement: function (error, element) {
                 var errorPlacement = element;
                 // logic for date-picker error placement
-                if (element.hasClass('hasDatepicker')) {
-                    errorPlacement = element.siblings('img');
+                if (element.hasClass('_has-datepicker')) {
+                    errorPlacement = element.siblings('button');
                 }
                 // logic for field wrapper
                 var fieldWrapper = element.closest('.addon');
@@ -1488,6 +1488,10 @@
                 if (element.is(':checkbox') || element.is(':radio')) {
                     errorPlacement = element.siblings('label').last();
                 }
+                //logic for control with tooltip
+                if (element.siblings('.tooltip').length) {
+                     errorPlacement = element.siblings('.tooltip');
+                }
                 errorPlacement.after(error);
             }
         },
diff --git a/setup/pub/magento/setup/install-extension-grid.js b/setup/pub/magento/setup/install-extension-grid.js
index 7e213fdbba9bb27beb60ced92c715f8d37686927..04a3bb1efb547fd73ad4f90046179cf8c171068b 100644
--- a/setup/pub/magento/setup/install-extension-grid.js
+++ b/setup/pub/magento/setup/install-extension-grid.js
@@ -143,6 +143,7 @@ angular.module('install-extension-grid', ['ngStorage', 'clickOut'])
                             version: extension.version
                         }
                     ];
+                    $localStorage.moduleName = extension.name;
                     $scope.error = false;
                     $scope.errorMessage = '';
                 }
diff --git a/setup/pub/magento/setup/select-version.js b/setup/pub/magento/setup/select-version.js
index 89bf9b63c1be47064bb5be77ab271f1888e3260e..83c201429f97bee59e8209e1142ced0923fa65d6 100644
--- a/setup/pub/magento/setup/select-version.js
+++ b/setup/pub/magento/setup/select-version.js
@@ -181,6 +181,7 @@ angular.module('select-version', ['ngStorage'])
                     $scope.packages.splice(1, $scope.totalForGrid);
                 }
             }
+            $localStorage.moduleName = '';
             $localStorage.packages = $scope.packages;
             $scope.nextState();
         };