diff --git a/app/code/Magento/Authorizenet/composer.json b/app/code/Magento/Authorizenet/composer.json
index b93cb6688f56d826a8d981518612897aae6f1ac8..f4acc4504604d0625543812ecec21b1d90286e59 100644
--- a/app/code/Magento/Authorizenet/composer.json
+++ b/app/code/Magento/Authorizenet/composer.json
@@ -12,6 +12,9 @@
         "magento/module-catalog": "101.1.*",
         "magento/framework": "100.2.*"
     },
+    "suggest": {
+        "magento/module-config": "100.2.*"
+    },
     "type": "magento2-module",
     "version": "100.2.0-dev",
     "license": [
diff --git a/app/code/Magento/Authorizenet/etc/di.xml b/app/code/Magento/Authorizenet/etc/di.xml
index f5e595fb450e83a60a4ce9b45196018cad335f3d..287cdec6fa0f7f62d68e20bfb49254209ef16ca9 100644
--- a/app/code/Magento/Authorizenet/etc/di.xml
+++ b/app/code/Magento/Authorizenet/etc/di.xml
@@ -16,4 +16,14 @@
             <argument name="storage" xsi:type="object">Magento\Authorizenet\Model\Directpost\Session\Storage</argument>
         </arguments>
     </type>
+    <type name="Magento\Config\Model\Config\Export\ExcludeList">
+        <arguments>
+            <argument name="configs" xsi:type="array">
+                <item name="payment/authorizenet_directpost/login" xsi:type="string">1</item>
+                <item name="payment/authorizenet_directpost/trans_key" xsi:type="string">1</item>
+                <item name="payment/authorizenet_directpost/trans_md5" xsi:type="string">1</item>
+                <item name="payment/authorizenet_directpost/merchant_email" xsi:type="string">1</item>
+            </argument>
+        </arguments>
+    </type>
 </config>
diff --git a/app/code/Magento/Backend/Block/Cache/Grid/Massaction/ProductionModeVisibilityChecker.php b/app/code/Magento/Backend/Block/Cache/Grid/Massaction/ProductionModeVisibilityChecker.php
new file mode 100644
index 0000000000000000000000000000000000000000..70a125e399ab3034669c011ee24c3877154469e9
--- /dev/null
+++ b/app/code/Magento/Backend/Block/Cache/Grid/Massaction/ProductionModeVisibilityChecker.php
@@ -0,0 +1,36 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Backend\Block\Cache\Grid\Massaction;
+
+use Magento\Backend\Block\Widget\Grid\Massaction\VisibilityCheckerInterface;
+use Magento\Framework\App\State;
+
+/**
+ * Class checks that action can be displayed on massaction list
+ */
+class ProductionModeVisibilityChecker implements VisibilityCheckerInterface
+{
+    /**
+     * @var State
+     */
+    private $state;
+
+    /**
+     * @param State $state
+     */
+    public function __construct(State $state)
+    {
+        $this->state = $state;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function isVisible()
+    {
+        return $this->state->getMode() !== State::MODE_PRODUCTION;
+    }
+}
diff --git a/app/code/Magento/Backend/Block/Widget/Grid/Massaction.php b/app/code/Magento/Backend/Block/Widget/Grid/Massaction.php
index ffe12c6cff46ee17442f7a69293172c02e206d30..c86907cc98042b30f6bac68ea0b0d2977ae87591 100644
--- a/app/code/Magento/Backend/Block/Widget/Grid/Massaction.php
+++ b/app/code/Magento/Backend/Block/Widget/Grid/Massaction.php
@@ -3,14 +3,11 @@
  * Copyright © 2016 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
+namespace Magento\Backend\Block\Widget\Grid;
 
 /**
  * Grid widget massaction default block
- *
- * @author     Magento Core Team <core@magentocommerce.com>
  */
-namespace Magento\Backend\Block\Widget\Grid;
-
 class Massaction extends \Magento\Backend\Block\Widget\Grid\Massaction\AbstractMassaction
 {
 }
diff --git a/app/code/Magento/Backend/Block/Widget/Grid/Massaction/AbstractMassaction.php b/app/code/Magento/Backend/Block/Widget/Grid/Massaction/AbstractMassaction.php
index 2f3df1377b395de426cc573f4d48016de82d7229..7f697599c7003583d08bc6c2f40ff138971bd4c0 100644
--- a/app/code/Magento/Backend/Block/Widget/Grid/Massaction/AbstractMassaction.php
+++ b/app/code/Magento/Backend/Block/Widget/Grid/Massaction/AbstractMassaction.php
@@ -5,14 +5,14 @@
  */
 namespace Magento\Backend\Block\Widget\Grid\Massaction;
 
-use Magento\Framework\View\Element\Template;
+use Magento\Backend\Block\Widget\Grid\Massaction\VisibilityCheckerInterface as VisibilityChecker;
+use Magento\Framework\DataObject;
 
 /**
  * Grid widget massaction block
  *
  * @method \Magento\Quote\Model\Quote setHideFormElement(boolean $value) Hide Form element to prevent IE errors
  * @method boolean getHideFormElement()
- * @author      Magento Core Team <core@magentocommerce.com>
  */
 abstract class AbstractMassaction extends \Magento\Backend\Block\Widget
 {
@@ -73,20 +73,21 @@ abstract class AbstractMassaction extends \Magento\Backend\Block\Widget
      *      'complete' => string, // Only for ajax enabled grid (optional)
      *      'url'      => string,
      *      'confirm'  => string, // text of confirmation of this action (optional)
-     *      'additional' => string // (optional)
+     *      'additional' => string, // (optional)
+     *      'visible' => object // instance of VisibilityCheckerInterface (optional)
      * );
      *
      * @param string $itemId
-     * @param array|\Magento\Framework\DataObject $item
+     * @param array|DataObject $item
      * @return $this
      */
     public function addItem($itemId, $item)
     {
         if (is_array($item)) {
-            $item = new \Magento\Framework\DataObject($item);
+            $item = new DataObject($item);
         }
 
-        if ($item instanceof \Magento\Framework\DataObject) {
+        if ($item instanceof DataObject && $this->isVisible($item)) {
             $item->setId($itemId);
             $item->setUrl($this->getUrl($item->getUrl()));
             $this->_items[$itemId] = $item;
@@ -95,6 +96,19 @@ abstract class AbstractMassaction extends \Magento\Backend\Block\Widget
         return $this;
     }
 
+    /**
+     * Check that item can be added to list
+     *
+     * @param DataObject $item
+     * @return bool
+     */
+    private function isVisible(DataObject $item)
+    {
+        /** @var VisibilityChecker $checker */
+        $checker = $item->getData('visible');
+        return (!$checker instanceof VisibilityChecker) || $checker->isVisible();
+    }
+
     /**
      * Retrieve massaction item with id $itemId
      *
diff --git a/app/code/Magento/Backend/Block/Widget/Grid/Massaction/VisibilityCheckerInterface.php b/app/code/Magento/Backend/Block/Widget/Grid/Massaction/VisibilityCheckerInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..934c4a84d145f349e028fc5497b9db62b2cdac54
--- /dev/null
+++ b/app/code/Magento/Backend/Block/Widget/Grid/Massaction/VisibilityCheckerInterface.php
@@ -0,0 +1,18 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Backend\Block\Widget\Grid\Massaction;
+
+use Magento\Framework\View\Element\Block\ArgumentInterface;
+
+interface VisibilityCheckerInterface extends ArgumentInterface
+{
+    /**
+     * Check that action can be displayed on massaction list
+     *
+     * @return bool
+     */
+    public function isVisible();
+}
diff --git a/app/code/Magento/Backend/Controller/Adminhtml/Cache/MassDisable.php b/app/code/Magento/Backend/Controller/Adminhtml/Cache/MassDisable.php
index 7266775959fc348796fabbb150f9e49b2ae9f7ad..42cbe229815aef16e13005ebdc802ec9b9bbd5c5 100644
--- a/app/code/Magento/Backend/Controller/Adminhtml/Cache/MassDisable.php
+++ b/app/code/Magento/Backend/Controller/Adminhtml/Cache/MassDisable.php
@@ -8,15 +8,41 @@ namespace Magento\Backend\Controller\Adminhtml\Cache;
 
 use Magento\Framework\Exception\LocalizedException;
 use Magento\Framework\Controller\ResultFactory;
+use Magento\Framework\App\State;
+use Magento\Framework\App\ObjectManager;
 
+/**
+ * Controller disables some types of cache
+ */
 class MassDisable extends \Magento\Backend\Controller\Adminhtml\Cache
 {
+    /**
+     * @var State
+     */
+    private $state;
+
     /**
      * Mass action for cache disabling
      *
      * @return \Magento\Backend\Model\View\Result\Redirect
      */
     public function execute()
+    {
+        if ($this->getState()->getMode() === State::MODE_PRODUCTION) {
+            $this->messageManager->addErrorMessage(__('You can\'t change status of cache type(s) in production mode'));
+        } else {
+            $this->disableCache();
+        }
+
+        return $this->resultFactory->create(ResultFactory::TYPE_REDIRECT)->setPath('adminhtml/*');
+    }
+
+    /**
+     * Disable cache
+     *
+     * @return void
+     */
+    private function disableCache()
     {
         try {
             $types = $this->getRequest()->getParam('types');
@@ -41,9 +67,20 @@ class MassDisable extends \Magento\Backend\Controller\Adminhtml\Cache
         } catch (\Exception $e) {
             $this->messageManager->addException($e, __('An error occurred while disabling cache.'));
         }
+    }
+
+    /**
+     * Get State Instance
+     *
+     * @return State
+     * @deprecated
+     */
+    private function getState()
+    {
+        if ($this->state === null) {
+            $this->state = ObjectManager::getInstance()->get(State::class);
+        }
 
-        /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */
-        $resultRedirect = $this->resultFactory->create(ResultFactory::TYPE_REDIRECT);
-        return $resultRedirect->setPath('adminhtml/*');
+        return $this->state;
     }
 }
diff --git a/app/code/Magento/Backend/Controller/Adminhtml/Cache/MassEnable.php b/app/code/Magento/Backend/Controller/Adminhtml/Cache/MassEnable.php
index 6c8bccfee166a5f746fd138c1b4e043ac1834542..8c4117831e8c8d7463b3112ac495cdede04f13d5 100644
--- a/app/code/Magento/Backend/Controller/Adminhtml/Cache/MassEnable.php
+++ b/app/code/Magento/Backend/Controller/Adminhtml/Cache/MassEnable.php
@@ -8,15 +8,41 @@ namespace Magento\Backend\Controller\Adminhtml\Cache;
 
 use Magento\Framework\Exception\LocalizedException;
 use Magento\Framework\Controller\ResultFactory;
+use Magento\Framework\App\State;
+use Magento\Framework\App\ObjectManager;
 
+/**
+ * Controller enables some types of cache
+ */
 class MassEnable extends \Magento\Backend\Controller\Adminhtml\Cache
 {
+    /**
+     * @var State
+     */
+    private $state;
+
     /**
      * Mass action for cache enabling
      *
      * @return \Magento\Backend\Model\View\Result\Redirect
      */
     public function execute()
+    {
+        if ($this->getState()->getMode() === State::MODE_PRODUCTION) {
+            $this->messageManager->addErrorMessage(__('You can\'t change status of cache type(s) in production mode'));
+        } else {
+            $this->enableCache();
+        }
+
+        return $this->resultFactory->create(ResultFactory::TYPE_REDIRECT)->setPath('adminhtml/*');
+    }
+
+    /**
+     * Enable cache
+     *
+     * @return void
+     */
+    private function enableCache()
     {
         try {
             $types = $this->getRequest()->getParam('types');
@@ -40,9 +66,20 @@ class MassEnable extends \Magento\Backend\Controller\Adminhtml\Cache
         } catch (\Exception $e) {
             $this->messageManager->addException($e, __('An error occurred while enabling cache.'));
         }
+    }
+
+    /**
+     * Get State Instance
+     *
+     * @return State
+     * @deprecated
+     */
+    private function getState()
+    {
+        if ($this->state === null) {
+            $this->state = ObjectManager::getInstance()->get(State::class);
+        }
 
-        /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */
-        $resultRedirect = $this->resultFactory->create(ResultFactory::TYPE_REDIRECT);
-        return $resultRedirect->setPath('adminhtml/*');
+        return $this->state;
     }
 }
diff --git a/app/code/Magento/Backend/Test/Unit/Block/Widget/Grid/MassactionTest.php b/app/code/Magento/Backend/Test/Unit/Block/Widget/Grid/MassactionTest.php
index 234e9d857549e073cb2fdba1bc39b3e4c7248349..79ecb388873eba21ed9fbfd166a651987194aa52 100644
--- a/app/code/Magento/Backend/Test/Unit/Block/Widget/Grid/MassactionTest.php
+++ b/app/code/Magento/Backend/Test/Unit/Block/Widget/Grid/MassactionTest.php
@@ -9,6 +9,8 @@
  */
 namespace Magento\Backend\Test\Unit\Block\Widget\Grid;
 
+use Magento\Backend\Block\Widget\Grid\Massaction\VisibilityCheckerInterface as VisibilityChecker;
+
 class MassactionTest extends \PHPUnit_Framework_TestCase
 {
     /**
@@ -17,12 +19,12 @@ class MassactionTest extends \PHPUnit_Framework_TestCase
     protected $_block;
 
     /**
-     * @var \PHPUnit_Framework_MockObject_MockObject
+     * @var \Magento\Framework\View\Layout|\PHPUnit_Framework_MockObject_MockObject
      */
     protected $_layoutMock;
 
     /**
-     * @var \PHPUnit_Framework_MockObject_MockObject
+     * @var \Magento\Backend\Block\Widget\Grid|\PHPUnit_Framework_MockObject_MockObject
      */
     protected $_gridMock;
 
@@ -32,63 +34,63 @@ class MassactionTest extends \PHPUnit_Framework_TestCase
     protected $_eventManagerMock;
 
     /**
-     * @var \PHPUnit_Framework_MockObject_MockObject
+     * @var \Magento\Backend\Model\Url|\PHPUnit_Framework_MockObject_MockObject
      */
     protected $_urlModelMock;
 
     /**
-     * @var \PHPUnit_Framework_MockObject_MockObject
+     * @var \Magento\Framework\App\Request\Http|\PHPUnit_Framework_MockObject_MockObject
      */
     protected $_requestMock;
 
+    /**
+     * @var VisibilityChecker|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $visibilityCheckerMock;
+
     protected function setUp()
     {
-        $this->_gridMock = $this->getMock(
-            \Magento\Backend\Block\Widget\Grid::class,
-            ['getId', 'getCollection'],
-            [],
-            '',
-            false
-        );
-        $this->_gridMock->expects($this->any())->method('getId')->will($this->returnValue('test_grid'));
-
-        $this->_layoutMock = $this->getMock(
-            \Magento\Framework\View\Layout::class,
-            ['getParentName', 'getBlock', 'helper'],
-            [],
-            '',
-            false,
-            false
-        );
+        $this->_gridMock = $this->getMockBuilder(\Magento\Backend\Block\Widget\Grid::class)
+            ->disableOriginalConstructor()
+            ->disableOriginalClone()
+            ->setMethods(['getId', 'getCollection'])
+            ->getMock();
+        $this->_gridMock->expects($this->any())
+            ->method('getId')
+            ->willReturn('test_grid');
 
-        $this->_layoutMock->expects(
-            $this->any()
-        )->method(
-            'getParentName'
-        )->with(
-            'test_grid_massaction'
-        )->will(
-            $this->returnValue('test_grid')
-        );
-        $this->_layoutMock->expects(
-            $this->any()
-        )->method(
-            'getBlock'
-        )->with(
-            'test_grid'
-        )->will(
-            $this->returnValue($this->_gridMock)
-        );
+        $this->_layoutMock = $this->getMockBuilder(\Magento\Framework\View\Layout::class)
+            ->disableOriginalConstructor()
+            ->disableOriginalClone()
+            ->setMethods(['getParentName', 'getBlock', 'helper'])
+            ->getMock();
+        $this->_layoutMock->expects($this->any())
+            ->method('getParentName')
+            ->with('test_grid_massaction')
+            ->willReturn('test_grid');
+        $this->_layoutMock->expects($this->any())
+            ->method('getBlock')
+            ->with('test_grid')
+            ->willReturn($this->_gridMock);
+
+        $this->_requestMock = $this->getMockBuilder(\Magento\Framework\App\Request\Http::class)
+            ->disableOriginalConstructor()
+            ->disableOriginalClone()
+            ->getMock();
 
-        $this->_requestMock = $this->getMock(\Magento\Framework\App\Request\Http::class, [], [], '', false);
+        $this->_urlModelMock = $this->getMockBuilder(\Magento\Backend\Model\Url::class)
+            ->disableOriginalConstructor()
+            ->disableOriginalClone()
+            ->getMock();
 
-        $this->_urlModelMock = $this->getMock(\Magento\Backend\Model\Url::class, [], [], '', false);
+        $this->visibilityCheckerMock = $this->getMockBuilder(VisibilityChecker::class)
+            ->getMockForAbstractClass();
 
         $arguments = [
             'layout' => $this->_layoutMock,
             'request' => $this->_requestMock,
             'urlBuilder' => $this->_urlModelMock,
-            'data' => ['massaction_id_field' => 'test_id', 'massaction_id_filter' => 'test_id'],
+            'data' => ['massaction_id_field' => 'test_id', 'massaction_id_filter' => 'test_id']
         ];
 
         $objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
@@ -124,26 +126,24 @@ class MassactionTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * @param $itemId
-     * @param $item
+     * @param string $itemId
+     * @param \Magento\Framework\DataObject $item
      * @param $expectedItem \Magento\Framework\DataObject
-     * @dataProvider itemsDataProvider
+     * @dataProvider itemsProcessingDataProvider
      */
     public function testItemsProcessing($itemId, $item, $expectedItem)
     {
-        $this->_urlModelMock->expects(
-            $this->any()
-        )->method(
-            'getBaseUrl'
-        )->will(
-            $this->returnValue('http://localhost/index.php')
-        );
+        $this->_urlModelMock->expects($this->any())
+            ->method('getBaseUrl')
+            ->willReturn('http://localhost/index.php');
 
         $urlReturnValueMap = [
             ['*/*/test1', [], 'http://localhost/index.php/backend/admin/test/test1'],
             ['*/*/test2', [], 'http://localhost/index.php/backend/admin/test/test2'],
         ];
-        $this->_urlModelMock->expects($this->any())->method('getUrl')->will($this->returnValueMap($urlReturnValueMap));
+        $this->_urlModelMock->expects($this->any())
+            ->method('getUrl')
+            ->willReturnMap($urlReturnValueMap);
 
         $this->_block->addItem($itemId, $item);
         $this->assertEquals(1, $this->_block->getCount());
@@ -157,7 +157,10 @@ class MassactionTest extends \PHPUnit_Framework_TestCase
         $this->assertNull($this->_block->getItem($itemId));
     }
 
-    public function itemsDataProvider()
+    /**
+     * @return array
+     */
+    public function itemsProcessingDataProvider()
     {
         return [
             [
@@ -186,22 +189,17 @@ class MassactionTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * @param $param
-     * @param $expectedJson
-     * @param $expected
+     * @param string $param
+     * @param string $expectedJson
+     * @param array $expected
      * @dataProvider selectedDataProvider
      */
     public function testSelected($param, $expectedJson, $expected)
     {
-        $this->_requestMock->expects(
-            $this->any()
-        )->method(
-            'getParam'
-        )->with(
-            $this->_block->getFormFieldNameInternal()
-        )->will(
-            $this->returnValue($param)
-        );
+        $this->_requestMock->expects($this->any())
+            ->method('getParam')
+            ->with($this->_block->getFormFieldNameInternal())
+            ->willReturn($param);
 
         $this->assertEquals($expectedJson, $this->_block->getSelectedJson());
         $this->assertEquals($expected, $this->_block->getSelected());
@@ -262,6 +260,9 @@ class MassactionTest extends \PHPUnit_Framework_TestCase
         $this->assertEquals($result, $this->_block->getGridIdsJson());
     }
 
+    /**
+     * @return array
+     */
     public function dataProviderGetGridIdsJsonWithUseSelectAll()
     {
         return [
@@ -279,4 +280,71 @@ class MassactionTest extends \PHPUnit_Framework_TestCase
             ],
         ];
     }
+
+    /**
+     * @param string $itemId
+     * @param array|\Magento\Framework\DataObject $item
+     * @param int $count
+     * @param bool $withVisibilityChecker
+     * @param bool $isVisible
+     * @dataProvider addItemDataProvider
+     */
+    public function testAddItem($itemId, $item, $count, $withVisibilityChecker, $isVisible)
+    {
+        $this->visibilityCheckerMock->expects($this->any())
+            ->method('isVisible')
+            ->willReturn($isVisible);
+
+        if ($withVisibilityChecker) {
+            $item['visible'] = $this->visibilityCheckerMock;
+        }
+
+        $urlReturnValueMap = [
+            ['*/*/test1', [], 'http://localhost/index.php/backend/admin/test/test1'],
+            ['*/*/test2', [], 'http://localhost/index.php/backend/admin/test/test2'],
+        ];
+        $this->_urlModelMock->expects($this->any())
+            ->method('getUrl')
+            ->willReturnMap($urlReturnValueMap);
+
+        $this->_block->addItem($itemId, $item);
+        $this->assertEquals($count, $this->_block->getCount());
+    }
+
+    /**
+     * @return array
+     */
+    public function addItemDataProvider()
+    {
+        return [
+            [
+                'itemId' => 'test1',
+                'item' => ['label' => 'Test 1', 'url' => '*/*/test1'],
+                'count' => 1,
+                'withVisibilityChecker' => false,
+                '$isVisible' => false,
+            ],
+            [
+                'itemId' => 'test2',
+                'item' => ['label' => 'Test 2', 'url' => '*/*/test2'],
+                'count' => 1,
+                'withVisibilityChecker' => false,
+                'isVisible' => true,
+            ],
+            [
+                'itemId' => 'test1',
+                'item' => ['label' => 'Test 1. Hide', 'url' => '*/*/test1'],
+                'count' => 0,
+                'withVisibilityChecker' => true,
+                'isVisible' => false,
+            ],
+            [
+                'itemId' => 'test2',
+                'item' => ['label' => 'Test 2. Does not hide', 'url' => '*/*/test2'],
+                'count' => 1,
+                'withVisibilityChecker' => true,
+                'isVisible' => true,
+            ]
+        ];
+    }
 }
diff --git a/app/code/Magento/Backend/Test/Unit/Controller/Adminhtml/Cache/MassDisableTest.php b/app/code/Magento/Backend/Test/Unit/Controller/Adminhtml/Cache/MassDisableTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..b2fc808b0e237b8bbeb5b323fb173ecff67d8071
--- /dev/null
+++ b/app/code/Magento/Backend/Test/Unit/Controller/Adminhtml/Cache/MassDisableTest.php
@@ -0,0 +1,224 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Backend\Test\Unit\Controller\Adminhtml\Cache;
+
+use PHPUnit_Framework_MockObject_MockObject as MockObject;
+use Magento\Backend\Controller\Adminhtml\Cache\MassDisable;
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper;
+use Magento\Framework\App\State;
+use Magento\Backend\App\Action\Context;
+use Magento\Framework\Message\ManagerInterface as MessageManager;
+use Magento\Framework\Controller\ResultFactory;
+use Magento\Backend\Model\View\Result\Redirect;
+use Magento\Framework\App\RequestInterface as Request;
+use Magento\Framework\App\Cache\TypeListInterface as CacheTypeList;
+use Magento\Framework\App\Cache\StateInterface as CacheState;
+
+/**
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ */
+class MassDisableTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var MassDisable
+     */
+    private $controller;
+
+    /**
+     * @var State|MockObject
+     */
+    private $stateMock;
+
+    /**
+     * @var MessageManager|MockObject
+     */
+    private $messageManagerMock;
+
+    /**
+     * @var Redirect|MockObject
+     */
+    private $redirectMock;
+
+    /**
+     * @var Request|MockObject
+     */
+    private $requestMock;
+
+    /**
+     * @var CacheTypeList|MockObject
+     */
+    private $cacheTypeListMock;
+
+    /**
+     * @var CacheState|MockObject
+     */
+    private $cacheStateMock;
+
+    protected function setUp()
+    {
+        $objectManagerHelper = new ObjectManagerHelper($this);
+
+        $this->stateMock = $this->getMockBuilder(State::class)
+            ->disableOriginalConstructor()
+            ->disableOriginalClone()
+            ->getMock();
+
+        $this->messageManagerMock = $this->getMockBuilder(MessageManager::class)
+            ->getMockForAbstractClass();
+
+        $this->requestMock = $this->getMockBuilder(Request::class)
+            ->getMockForAbstractClass();
+
+        $this->cacheTypeListMock = $this->getMockBuilder(CacheTypeList::class)
+            ->getMockForAbstractClass();
+
+        $this->cacheStateMock = $this->getMockBuilder(CacheState::class)
+            ->getMockForAbstractClass();
+
+        $this->redirectMock = $this->getMockBuilder(Redirect::class)
+            ->disableOriginalConstructor()
+            ->disableOriginalClone()
+            ->getMock();
+        $this->redirectMock->expects($this->once())
+            ->method('setPath')
+            ->with('adminhtml/*')
+            ->willReturnSelf();
+        $resultFactoryMock = $this->getMockBuilder(ResultFactory::class)
+            ->disableOriginalConstructor()
+            ->disableOriginalClone()
+            ->getMock();
+        $resultFactoryMock->expects($this->once())
+            ->method('create')
+            ->with(ResultFactory::TYPE_REDIRECT)
+            ->willReturn($this->redirectMock);
+
+        $contextMock = $this->getMockBuilder(Context::class)
+            ->disableOriginalConstructor()
+            ->disableOriginalClone()
+            ->getMock();
+        $contextMock->expects($this->once())
+            ->method('getMessageManager')
+            ->willReturn($this->messageManagerMock);
+        $contextMock->expects($this->once())
+            ->method('getResultFactory')
+            ->willReturn($resultFactoryMock);
+        $contextMock->expects($this->once())
+            ->method('getRequest')
+            ->willReturn($this->requestMock);
+
+        $this->controller = $objectManagerHelper->getObject(
+            MassDisable::class,
+            [
+                'context' => $contextMock,
+                'cacheTypeList' => $this->cacheTypeListMock,
+                'cacheState' => $this->cacheStateMock
+            ]
+        );
+        $objectManagerHelper->setBackwardCompatibleProperty($this->controller, 'state', $this->stateMock);
+    }
+
+    public function testExecuteInProductionMode()
+    {
+        $this->stateMock->expects($this->once())
+            ->method('getMode')
+            ->willReturn(State::MODE_PRODUCTION);
+
+        $this->messageManagerMock->expects($this->once())
+            ->method('addErrorMessage')
+            ->with('You can\'t change status of cache type(s) in production mode', null)
+            ->willReturnSelf();
+
+        $this->assertSame($this->redirectMock, $this->controller->execute());
+    }
+
+    public function testExecuteInvalidTypeCache()
+    {
+        $this->stateMock->expects($this->once())
+            ->method('getMode')
+            ->willReturn(State::MODE_DEVELOPER);
+
+        $this->cacheTypeListMock->expects($this->once())
+            ->method('getTypes')
+            ->willReturn([
+                'pageCache' => [
+                    'id' => 'pageCache',
+                    'label' => 'Cache of Page'
+                ]
+            ]);
+
+        $this->requestMock->expects($this->once())
+            ->method('getParam')
+            ->with('types')
+            ->willReturn(['someCache']);
+
+        $this->messageManagerMock->expects($this->once())
+            ->method('addError')
+            ->with('Specified cache type(s) don\'t exist: someCache')
+            ->willReturnSelf();
+
+        $this->assertSame($this->redirectMock, $this->controller->execute());
+    }
+
+    public function testExecuteWithException()
+    {
+        $exception = new \Exception();
+
+        $this->stateMock->expects($this->once())
+            ->method('getMode')
+            ->willReturn(State::MODE_DEVELOPER);
+
+        $this->requestMock->expects($this->once())
+            ->method('getParam')
+            ->willThrowException($exception);
+
+        $this->messageManagerMock->expects($this->once())
+            ->method('addException')
+            ->with($exception, 'An error occurred while disabling cache.')
+            ->willReturnSelf();
+
+        $this->assertSame($this->redirectMock, $this->controller->execute());
+    }
+
+    public function testExecuteSuccess()
+    {
+        $cacheType = 'pageCache';
+
+        $this->stateMock->expects($this->once())
+            ->method('getMode')
+            ->willReturn(State::MODE_DEVELOPER);
+
+        $this->cacheTypeListMock->expects($this->once())
+            ->method('getTypes')
+            ->willReturn([
+                'pageCache' => [
+                    'id' => 'pageCache',
+                    'label' => 'Cache of Page'
+                ]
+            ]);
+
+        $this->requestMock->expects($this->once())
+            ->method('getParam')
+            ->with('types')
+            ->willReturn([$cacheType]);
+
+        $this->cacheStateMock->expects($this->once())
+            ->method('isEnabled')
+            ->with($cacheType)
+            ->willReturn(true);
+        $this->cacheStateMock->expects($this->once())
+            ->method('setEnabled')
+            ->with($cacheType, false);
+        $this->cacheStateMock->expects($this->once())
+            ->method('persist');
+
+        $this->messageManagerMock->expects($this->once())
+            ->method('addSuccess')
+            ->with('1 cache type(s) disabled.')
+            ->willReturnSelf();
+
+        $this->assertSame($this->redirectMock, $this->controller->execute());
+    }
+}
diff --git a/app/code/Magento/Backend/Test/Unit/Controller/Adminhtml/Cache/MassEnableTest.php b/app/code/Magento/Backend/Test/Unit/Controller/Adminhtml/Cache/MassEnableTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..8c1b9f1718ab924379cf3e5440a942c0be5502d7
--- /dev/null
+++ b/app/code/Magento/Backend/Test/Unit/Controller/Adminhtml/Cache/MassEnableTest.php
@@ -0,0 +1,224 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Backend\Test\Unit\Controller\Adminhtml\Cache;
+
+use PHPUnit_Framework_MockObject_MockObject as MockObject;
+use Magento\Backend\Controller\Adminhtml\Cache\MassEnable;
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper;
+use Magento\Framework\App\State;
+use Magento\Backend\App\Action\Context;
+use Magento\Framework\Message\ManagerInterface as MessageManager;
+use Magento\Framework\Controller\ResultFactory;
+use Magento\Backend\Model\View\Result\Redirect;
+use Magento\Framework\App\RequestInterface as Request;
+use Magento\Framework\App\Cache\TypeListInterface as CacheTypeList;
+use Magento\Framework\App\Cache\StateInterface as CacheState;
+
+/**
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ */
+class MassEnableTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var MassEnable
+     */
+    private $controller;
+
+    /**
+     * @var State|MockObject
+     */
+    private $stateMock;
+
+    /**
+     * @var MessageManager|MockObject
+     */
+    private $messageManagerMock;
+
+    /**
+     * @var Redirect|MockObject
+     */
+    private $redirectMock;
+
+    /**
+     * @var Request|MockObject
+     */
+    private $requestMock;
+
+    /**
+     * @var CacheTypeList|MockObject
+     */
+    private $cacheTypeListMock;
+
+    /**
+     * @var CacheState|MockObject
+     */
+    private $cacheStateMock;
+
+    protected function setUp()
+    {
+        $objectManagerHelper = new ObjectManagerHelper($this);
+
+        $this->stateMock = $this->getMockBuilder(State::class)
+            ->disableOriginalConstructor()
+            ->disableOriginalClone()
+            ->getMock();
+
+        $this->messageManagerMock = $this->getMockBuilder(MessageManager::class)
+            ->getMockForAbstractClass();
+
+        $this->requestMock = $this->getMockBuilder(Request::class)
+            ->getMockForAbstractClass();
+
+        $this->cacheTypeListMock = $this->getMockBuilder(CacheTypeList::class)
+            ->getMockForAbstractClass();
+
+        $this->cacheStateMock = $this->getMockBuilder(CacheState::class)
+            ->getMockForAbstractClass();
+
+        $this->redirectMock = $this->getMockBuilder(Redirect::class)
+            ->disableOriginalConstructor()
+            ->disableOriginalClone()
+            ->getMock();
+        $this->redirectMock->expects($this->once())
+            ->method('setPath')
+            ->with('adminhtml/*')
+            ->willReturnSelf();
+        $resultFactoryMock = $this->getMockBuilder(ResultFactory::class)
+            ->disableOriginalConstructor()
+            ->disableOriginalClone()
+            ->getMock();
+        $resultFactoryMock->expects($this->once())
+            ->method('create')
+            ->with(ResultFactory::TYPE_REDIRECT)
+            ->willReturn($this->redirectMock);
+
+        $contextMock = $this->getMockBuilder(Context::class)
+            ->disableOriginalConstructor()
+            ->disableOriginalClone()
+            ->getMock();
+        $contextMock->expects($this->once())
+            ->method('getMessageManager')
+            ->willReturn($this->messageManagerMock);
+        $contextMock->expects($this->once())
+            ->method('getResultFactory')
+            ->willReturn($resultFactoryMock);
+        $contextMock->expects($this->once())
+            ->method('getRequest')
+            ->willReturn($this->requestMock);
+
+        $this->controller = $objectManagerHelper->getObject(
+            MassEnable::class,
+            [
+                'context' => $contextMock,
+                'cacheTypeList' => $this->cacheTypeListMock,
+                'cacheState' => $this->cacheStateMock
+            ]
+        );
+        $objectManagerHelper->setBackwardCompatibleProperty($this->controller, 'state', $this->stateMock);
+    }
+
+    public function testExecuteInProductionMode()
+    {
+        $this->stateMock->expects($this->once())
+            ->method('getMode')
+            ->willReturn(State::MODE_PRODUCTION);
+
+        $this->messageManagerMock->expects($this->once())
+            ->method('addErrorMessage')
+            ->with('You can\'t change status of cache type(s) in production mode', null)
+            ->willReturnSelf();
+
+        $this->assertSame($this->redirectMock, $this->controller->execute());
+    }
+
+    public function testExecuteInvalidTypeCache()
+    {
+        $this->stateMock->expects($this->once())
+            ->method('getMode')
+            ->willReturn(State::MODE_DEVELOPER);
+
+        $this->cacheTypeListMock->expects($this->once())
+            ->method('getTypes')
+            ->willReturn([
+                'pageCache' => [
+                    'id' => 'pageCache',
+                    'label' => 'Cache of Page'
+                ]
+            ]);
+
+        $this->requestMock->expects($this->once())
+            ->method('getParam')
+            ->with('types')
+            ->willReturn(['someCache']);
+
+        $this->messageManagerMock->expects($this->once())
+            ->method('addError')
+            ->with('Specified cache type(s) don\'t exist: someCache')
+            ->willReturnSelf();
+
+        $this->assertSame($this->redirectMock, $this->controller->execute());
+    }
+
+    public function testExecuteWithException()
+    {
+        $exception = new \Exception();
+
+        $this->stateMock->expects($this->once())
+            ->method('getMode')
+            ->willReturn(State::MODE_DEVELOPER);
+
+        $this->requestMock->expects($this->once())
+            ->method('getParam')
+            ->willThrowException($exception);
+
+        $this->messageManagerMock->expects($this->once())
+            ->method('addException')
+            ->with($exception, 'An error occurred while enabling cache.')
+            ->willReturnSelf();
+
+        $this->assertSame($this->redirectMock, $this->controller->execute());
+    }
+
+    public function testExecuteSuccess()
+    {
+        $cacheType = 'pageCache';
+
+        $this->stateMock->expects($this->once())
+            ->method('getMode')
+            ->willReturn(State::MODE_DEVELOPER);
+
+        $this->cacheTypeListMock->expects($this->once())
+            ->method('getTypes')
+            ->willReturn([
+                'pageCache' => [
+                    'id' => 'pageCache',
+                    'label' => 'Cache of Page'
+                ]
+            ]);
+
+        $this->requestMock->expects($this->once())
+            ->method('getParam')
+            ->with('types')
+            ->willReturn([$cacheType]);
+
+        $this->cacheStateMock->expects($this->once())
+            ->method('isEnabled')
+            ->with($cacheType)
+            ->willReturn(false);
+        $this->cacheStateMock->expects($this->once())
+            ->method('setEnabled')
+            ->with($cacheType, true);
+        $this->cacheStateMock->expects($this->once())
+            ->method('persist');
+
+        $this->messageManagerMock->expects($this->once())
+            ->method('addSuccess')
+            ->with('1 cache type(s) enabled.')
+            ->willReturnSelf();
+
+        $this->assertSame($this->redirectMock, $this->controller->execute());
+    }
+}
diff --git a/app/code/Magento/Backend/etc/di.xml b/app/code/Magento/Backend/etc/di.xml
index 8b52d08da48fbbd8fd1cf450bb8a2db66ca75b62..c0c5a0ec5b8a7ff217fcf0bb1772cb932f14bc55 100644
--- a/app/code/Magento/Backend/etc/di.xml
+++ b/app/code/Magento/Backend/etc/di.xml
@@ -213,4 +213,22 @@
             </argument>
         </arguments>
     </type>
+    <type name="Magento\Config\Model\Config\Export\ExcludeList">
+        <arguments>
+            <argument name="configs" xsi:type="array">
+                <item name="trans_email/ident_general/name" xsi:type="string">1</item>
+                <item name="trans_email/ident_general/email" xsi:type="string">1</item>
+                <item name="trans_email/ident_sales/name" xsi:type="string">1</item>
+                <item name="trans_email/ident_sales/email" xsi:type="string">1</item>
+                <item name="trans_email/ident_support/name" xsi:type="string">1</item>
+                <item name="trans_email/ident_support/email" xsi:type="string">1</item>
+                <item name="trans_email/ident_custom1/name" xsi:type="string">1</item>
+                <item name="trans_email/ident_custom1/email" xsi:type="string">1</item>
+                <item name="trans_email/ident_custom2/name" xsi:type="string">1</item>
+                <item name="trans_email/ident_custom2/email" xsi:type="string">1</item>
+                <item name="admin/url/custom" xsi:type="string">1</item>
+                <item name="admin/url/custom_path" xsi:type="string">1</item>
+            </argument>
+        </arguments>
+    </type>
 </config>
diff --git a/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_cache_block.xml b/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_cache_block.xml
index decc26f331c8298d16b4a76d4a74d82c5808c651..98f9ca89ba18accc9013c7b0851e39abafa517b2 100644
--- a/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_cache_block.xml
+++ b/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_cache_block.xml
@@ -23,10 +23,12 @@
                             <item name="enable" xsi:type="array">
                                 <item name="label" xsi:type="string" translate="true">Enable</item>
                                 <item name="url" xsi:type="string">adminhtml/*/massEnable</item>
+                                <item name="visible" xsi:type="object">Magento\Backend\Block\Cache\Grid\Massaction\ProductionModeVisibilityChecker</item>
                             </item>
                             <item name="disable" xsi:type="array">
                                 <item name="label" xsi:type="string" translate="true">Disable</item>
                                 <item name="url" xsi:type="string">adminhtml/*/massDisable</item>
+                                <item name="visible" xsi:type="object">Magento\Backend\Block\Cache\Grid\Massaction\ProductionModeVisibilityChecker</item>
                             </item>
                             <item name="refresh" xsi:type="array">
                                 <item name="label" xsi:type="string" translate="true">Refresh</item>
diff --git a/app/code/Magento/Braintree/etc/di.xml b/app/code/Magento/Braintree/etc/di.xml
index d051ef78cfcd22424fa359e47be3efc0ee8dcc2b..5417c96ba677204a0c3c3ffc69cefdc27f148ee3 100644
--- a/app/code/Magento/Braintree/etc/di.xml
+++ b/app/code/Magento/Braintree/etc/di.xml
@@ -365,7 +365,7 @@
         </arguments>
     </virtualType>
     <!-- END PayPal commands -->
-    
+
     <!-- Value handlers infrastructure -->
     <type name="Magento\Braintree\Gateway\Response\VaultDetailsHandler">
         <arguments>
@@ -452,7 +452,7 @@
         </arguments>
     </virtualType>
     <!-- END PayPal value handlers infrastructure -->
-    
+
     <!-- Void Command -->
     <virtualType name="BraintreeVoidCommand" type="Magento\Payment\Gateway\Command\GatewayCommand">
         <arguments>
@@ -544,4 +544,16 @@
         </arguments>
     </type>
     <!-- END Settlement Report Section -->
+    <type name="Magento\Config\Model\Config\Export\ExcludeList">
+        <arguments>
+            <argument name="configs" xsi:type="array">
+                <item name="payment/braintree/merchant_id" xsi:type="string">1</item>
+                <item name="payment/braintree/public_key" xsi:type="string">1</item>
+                <item name="payment/braintree/private_key" xsi:type="string">1</item>
+                <item name="payment/braintree/merchant_account_id" xsi:type="string">1</item>
+                <item name="payment/braintree/kount_id" xsi:type="string">1</item>
+                <item name="payment/braintree_paypal/merchant_name_override" xsi:type="string">1</item>
+            </argument>
+        </arguments>
+    </type>
 </config>
diff --git a/app/code/Magento/Checkout/etc/di.xml b/app/code/Magento/Checkout/etc/di.xml
index a2243b33a04edc0af4dc71ed79b802eac68f4cc2..81a430d52c49933cf70013f8856a96f5b6c26377 100644
--- a/app/code/Magento/Checkout/etc/di.xml
+++ b/app/code/Magento/Checkout/etc/di.xml
@@ -42,4 +42,11 @@
             </argument>
         </arguments>
     </type>
+    <type name="Magento\Config\Model\Config\Export\ExcludeList">
+        <arguments>
+            <argument name="configs" xsi:type="array">
+                <item name="checkout/payment_failed/copy_to" xsi:type="string">1</item>
+            </argument>
+        </arguments>
+    </type>
 </config>
diff --git a/app/code/Magento/Config/App/Config/Source/DumpConfigSourceAggregated.php b/app/code/Magento/Config/App/Config/Source/DumpConfigSourceAggregated.php
new file mode 100644
index 0000000000000000000000000000000000000000..80567d0504ee9c31d8cadef957c1d12dad9f1508
--- /dev/null
+++ b/app/code/Magento/Config/App/Config/Source/DumpConfigSourceAggregated.php
@@ -0,0 +1,152 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Config\App\Config\Source;
+
+use Magento\Config\Model\Config\Export\ExcludeList;
+use Magento\Framework\App\Config\ConfigSourceInterface;
+use Magento\Framework\App\Config\ScopeConfigInterface;
+
+/**
+ * Class DumpConfigSourceAggregated aggregates configurations from all available sources
+ */
+class DumpConfigSourceAggregated implements DumpConfigSourceInterface
+{
+    /**
+     * @var ExcludeList
+     */
+    private $excludeList;
+
+    /**
+     * @var ConfigSourceInterface[]
+     */
+    private $sources;
+
+    /**
+     * @var array
+     */
+    private $excludedFields;
+
+    /**
+     * @var array
+     */
+    private $data;
+
+    /**
+     * @param ExcludeList $excludeList
+     * @param array $sources
+     */
+    public function __construct(ExcludeList $excludeList, array $sources = [])
+    {
+        $this->excludeList = $excludeList;
+        $this->sources = $sources;
+    }
+
+    /**
+     * Retrieve aggregated configuration from all available sources.
+     *
+     * @param string $path
+     * @return array
+     */
+    public function get($path = '')
+    {
+        $path = (string)$path;
+        $data = [];
+
+        if (isset($this->data[$path])) {
+            return $this->data[$path];
+        }
+
+        $this->sortSources();
+
+        foreach ($this->sources as $sourceConfig) {
+            /** @var ConfigSourceInterface $source */
+            $source = $sourceConfig['source'];
+            $data = array_replace_recursive($data, $source->get($path));
+        }
+
+        $this->excludedFields = [];
+        $this->filterChain($path, $data);
+
+        return $this->data[$path] = $data;
+    }
+
+    /**
+     * Recursive filtering of sensitive data
+     *
+     * @param string $path
+     * @param array $data
+     * @return void
+     */
+    private function filterChain($path, &$data)
+    {
+        foreach ($data as $subKey => &$subData) {
+            $newPath = $path ? $path . '/' . $subKey : $subKey;
+            $filteredPath = $this->filterPath($newPath);
+
+            if (
+                $filteredPath
+                && !is_array($data[$subKey])
+                && $this->excludeList->isPresent($filteredPath)
+            ) {
+                $this->excludedFields[$newPath] = $filteredPath;
+
+                unset($data[$subKey]);
+            } elseif (is_array($subData)) {
+                $this->filterChain($newPath, $subData);
+            }
+        }
+    }
+
+    /**
+     * Eliminating scope info from path
+     *
+     * @param string $path
+     * @return null|string
+     */
+    private function filterPath($path)
+    {
+        $parts = explode('/', $path);
+
+        // Check if there are enough parts to recognize scope
+        if (count($parts) < 3) {
+            return null;
+        }
+
+        if ($parts[0] === ScopeConfigInterface::SCOPE_TYPE_DEFAULT) {
+            unset($parts[0]);
+        } else {
+            unset($parts[0], $parts[1]);
+        }
+
+        return implode('/', $parts);
+    }
+
+    /**
+     * Sort sources ASC from higher priority to lower
+     *
+     * @return void
+     */
+    private function sortSources()
+    {
+        uasort($this->sources, function ($firstItem, $secondItem) {
+            return $firstItem['sortOrder'] > $secondItem['sortOrder'];
+        });
+    }
+
+    /**
+     * Retrieves list of field paths were excluded from config dump
+     * @return array
+     */
+    public function getExcludedFields()
+    {
+        $this->get();
+
+        $fields = array_values($this->excludedFields);
+        $fields = array_unique($fields);
+
+        return $fields;
+    }
+}
diff --git a/app/code/Magento/Config/App/Config/Source/DumpConfigSourceInterface.php b/app/code/Magento/Config/App/Config/Source/DumpConfigSourceInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..cf0ce492b7d5265a5445a3fbe3f4e6d68ec384a4
--- /dev/null
+++ b/app/code/Magento/Config/App/Config/Source/DumpConfigSourceInterface.php
@@ -0,0 +1,21 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Config\App\Config\Source;
+
+use Magento\Framework\App\Config\ConfigSourceInterface;
+
+/**
+ * Interface DumpConfigSourceInterface
+ */
+interface DumpConfigSourceInterface extends ConfigSourceInterface
+{
+    /**
+     * Retrieves list of field paths were excluded from config dump
+     *
+     * @return array
+     */
+    public function getExcludedFields();
+}
diff --git a/app/code/Magento/Config/App/Config/Type/System.php b/app/code/Magento/Config/App/Config/Type/System.php
index 4a3c6da8379153a240e4869592fcef31788df608..a0fc0f1f10ebdfbbcd78695ee223e48efdd21b7a 100644
--- a/app/code/Magento/Config/App/Config/Type/System.php
+++ b/app/code/Magento/Config/App/Config/Type/System.php
@@ -6,18 +6,10 @@
 namespace Magento\Config\App\Config\Type;
 
 use Magento\Framework\App\Config\ConfigTypeInterface;
-use Magento\Framework\App\Config\ConfigSourceInterface;
-use Magento\Framework\App\Config\Spi\PostProcessorInterface;
-use Magento\Framework\Cache\FrontendInterface;
 use Magento\Framework\DataObject;
-use Magento\Framework\Serialize\Serializer\Serialize;
-use Magento\Framework\Serialize\SerializerInterface;
-use Magento\Store\Model\Config\Processor\Fallback;
 
 /**
  * Class process source, cache them and retrieve value by path
- *
- * @package Magento\Config\App\Config\Type
  */
 class System implements ConfigTypeInterface
 {
@@ -26,7 +18,7 @@ class System implements ConfigTypeInterface
     const CONFIG_TYPE = 'system';
 
     /**
-     * @var ConfigSourceInterface
+     * @var \Magento\Framework\App\Config\ConfigSourceInterface
      */
     private $source;
 
@@ -36,12 +28,17 @@ class System implements ConfigTypeInterface
     private $data;
 
     /**
-     * @var PostProcessorInterface
+     * @var \Magento\Framework\App\Config\Spi\PostProcessorInterface
      */
     private $postProcessor;
 
     /**
-     * @var FrontendInterface
+     * @var \Magento\Framework\App\Config\Spi\PreProcessorInterface
+     */
+    private $preProcessor;
+
+    /**
+     * @var \Magento\Framework\Cache\FrontendInterface
      */
     private $cache;
 
@@ -51,34 +48,36 @@ class System implements ConfigTypeInterface
     private $cachingNestedLevel;
 
     /**
-     * @var Fallback
+     * @var \Magento\Store\Model\Config\Processor\Fallback
      */
     private $fallback;
 
     /**
-     * @var Serialize
+     * @var \Magento\Framework\Serialize\SerializerInterface
      */
     private $serializer;
 
     /**
-     * System constructor.
-     * @param ConfigSourceInterface $source
-     * @param PostProcessorInterface $postProcessor
-     * @param Fallback $fallback
-     * @param FrontendInterface $cache
+     * @param \Magento\Framework\App\Config\ConfigSourceInterface $source
+     * @param \Magento\Framework\App\Config\Spi\PostProcessorInterface $postProcessor
+     * @param \Magento\Store\Model\Config\Processor\Fallback $fallback
+     * @param \Magento\Framework\Cache\FrontendInterface $cache
+     * @param \Magento\Framework\Serialize\SerializerInterface $serializer
+     * @param \Magento\Framework\App\Config\Spi\PreProcessorInterface $preProcessor
      * @param int $cachingNestedLevel
-     * @param Serialize $serializer
      */
     public function __construct(
-        ConfigSourceInterface $source,
-        PostProcessorInterface $postProcessor,
-        Fallback $fallback,
-        FrontendInterface $cache,
-        Serialize $serializer,
+        \Magento\Framework\App\Config\ConfigSourceInterface $source,
+        \Magento\Framework\App\Config\Spi\PostProcessorInterface $postProcessor,
+        \Magento\Store\Model\Config\Processor\Fallback $fallback,
+        \Magento\Framework\Cache\FrontendInterface $cache,
+        \Magento\Framework\Serialize\SerializerInterface $serializer,
+        \Magento\Framework\App\Config\Spi\PreProcessorInterface $preProcessor,
         $cachingNestedLevel = 1
     ) {
         $this->source = $source;
         $this->postProcessor = $postProcessor;
+        $this->preProcessor = $preProcessor;
         $this->cache = $cache;
         $this->cachingNestedLevel = $cachingNestedLevel;
         $this->fallback = $fallback;
@@ -96,7 +95,9 @@ class System implements ConfigTypeInterface
         if (!$this->data) {
             $data = $this->cache->load(self::CONFIG_TYPE);
             if (!$data) {
-                $data = $this->fallback->process($this->source->get());
+                $data = $this->preProcessor->process($this->source->get());
+                $this->data = new DataObject($data);
+                $data = $this->fallback->process($data);
                 $this->data = new DataObject($data);
                 //Placeholder processing need system config - so we need to save intermediate result
                 $data = $this->postProcessor->process($data);
diff --git a/app/code/Magento/Config/Block/System/Config/Form.php b/app/code/Magento/Config/Block/System/Config/Form.php
index d1a0da2a700a3f628c83ac2d61029bc915cd3ba6..f0ad7e4a28b1a365b6596f7175ae34434e09e59c 100644
--- a/app/code/Magento/Config/Block/System/Config/Form.php
+++ b/app/code/Magento/Config/Block/System/Config/Form.php
@@ -7,8 +7,10 @@ namespace Magento\Config\Block\System\Config;
 
 use Magento\Config\App\Config\Type\System;
 use Magento\Config\Model\Config\Reader\Source\Deployed\SettingChecker;
+use Magento\Framework\App\Config\ScopeConfigInterface;
 use Magento\Framework\App\DeploymentConfig;
 use Magento\Framework\App\ObjectManager;
+use Magento\Framework\DataObject;
 
 /**
  * System config form block
@@ -331,29 +333,9 @@ class Form extends \Magento\Backend\Block\Widget\Form\Generic
         $fieldPrefix = '',
         $labelPrefix = ''
     ) {
-        $inherit = true;
-        $data = $this->getAppConfigDataValue($path);
-        if ($data === null) {
-            if (array_key_exists($path, $this->_configData)) {
-                $data = $this->_configData[$path];
-                $inherit = false;
+        $inherit = !array_key_exists($path, $this->_configData);
+        $data = $this->getFieldData($field, $path);
 
-                if ($field->hasBackendModel()) {
-                    $backendModel = $field->getBackendModel();
-                    $backendModel->setPath($path)
-                        ->setValue($data)
-                        ->setWebsite($this->getWebsiteCode())
-                        ->setStore($this->getStoreCode())
-                        ->afterLoad();
-                    $data = $backendModel->getValue();
-                }
-
-            } elseif ($field->getConfigPath() !== null) {
-                $data = $this->getConfigValue($field->getConfigPath());
-            } else {
-                $data = $this->getConfigValue($path);
-            }
-        }
         $fieldRendererClass = $field->getFrontendModel();
         if ($fieldRendererClass) {
             $fieldRenderer = $this->_layout->getBlockSingleton($fieldRendererClass);
@@ -373,9 +355,7 @@ class Form extends \Magento\Backend\Block\Widget\Form\Generic
         $sharedClass = $this->_getSharedCssClass($field);
         $requiresClass = $this->_getRequiresCssClass($field, $fieldPrefix);
 
-        $isReadOnly = $this->getSettingChecker()->isReadOnly($path, $this->getScope(), $this->getScopeCode());
-        $canUseDefault = $this->canUseDefaultValue($field->showInDefault());
-        $canUseWebsite = $this->canUseWebsiteValue($field->showInWebsite());
+        $isReadOnly = $this->getSettingChecker()->isReadOnly($path, $this->getScope(), $this->getStringScopeCode());
         $formField = $fieldset->addField(
             $elementId,
             $field->getType(),
@@ -392,8 +372,8 @@ class Form extends \Magento\Backend\Block\Widget\Form\Generic
                 'scope' => $this->getScope(),
                 'scope_id' => $this->getScopeId(),
                 'scope_label' => $this->getScopeLabel($field),
-                'can_use_default_value' => $canUseDefault,
-                'can_use_website_value' => $canUseWebsite,
+                'can_use_default_value' => $this->canUseDefaultValue($field->showInDefault()),
+                'can_use_website_value' => $this->canUseWebsiteValue($field->showInWebsite()),
                 'can_restore_to_default' => $this->isCanRestoreToDefault($field->canRestore()),
                 'disabled' => $isReadOnly,
                 'is_disable_inheritance' => $isReadOnly
@@ -413,6 +393,74 @@ class Form extends \Magento\Backend\Block\Widget\Form\Generic
         $formField->setRenderer($fieldRenderer);
     }
 
+    /**
+     * Get data of field by path
+     *
+     * @param \Magento\Config\Model\Config\Structure\Element\Field $field
+     * @param string $path
+     * @return mixed|null|string
+     */
+    private function getFieldData(\Magento\Config\Model\Config\Structure\Element\Field $field, $path)
+    {
+        $data = $this->getAppConfigDataValue($path);
+
+        $placeholderValue = $this->getSettingChecker()->getPlaceholderValue(
+            $path,
+            $this->getScope(),
+            $this->getStringScopeCode()
+        );
+
+        if ($placeholderValue) {
+            $data = $placeholderValue;
+        }
+        if ($data === null) {
+            if (array_key_exists($path, $this->_configData)) {
+                $data = $this->_configData[$path];
+
+                if ($field->hasBackendModel()) {
+                    $backendModel = $field->getBackendModel();
+                    $backendModel->setPath($path)
+                        ->setValue($data)
+                        ->setWebsite($this->getWebsiteCode())
+                        ->setStore($this->getStoreCode())
+                        ->afterLoad();
+                    $data = $backendModel->getValue();
+                }
+
+            } elseif ($field->getConfigPath() !== null) {
+                $data = $this->getConfigValue($field->getConfigPath());
+            } else {
+                $data = $this->getConfigValue($path);
+            }
+        }
+
+        return $data;
+    }
+
+    /**
+     * Retrieve Scope string code
+     *
+     * @return string
+     */
+    private function getStringScopeCode()
+    {
+        $scopeCode = $this->getData('scope_string_code');
+
+        if (null === $scopeCode) {
+            if ($this->getStoreCode()) {
+                $scopeCode = $this->_storeManager->getStore($this->getStoreCode())->getCode();
+            } elseif ($this->getWebsiteCode()) {
+                $scopeCode = $this->_storeManager->getWebsite($this->getWebsiteCode())->getCode();
+            } else {
+                $scopeCode = '';
+            }
+
+            $this->setData('scope_string_code', $scopeCode);
+        }
+
+        return $scopeCode;
+    }
+
     /**
      * Populate dependencies block
      *
@@ -748,14 +796,13 @@ class Form extends \Magento\Backend\Block\Widget\Form\Generic
     {
         $appConfig = $this->getAppConfig()->get(System::CONFIG_TYPE);
         $scope = $this->getScope();
-        $scopeId = $this->getScopeId();
-        if ($scope === 'default') {
-            $data = isset($appConfig[$scope][$path]) ? $appConfig[$scope][$path] : null;
+        $scopeCode = $this->getStringScopeCode();
+
+        if ($scope === ScopeConfigInterface::SCOPE_TYPE_DEFAULT) {
+            $data = new DataObject(isset($appConfig[$scope]) ? $appConfig[$scope] : []);
         } else {
-            $data = isset($appConfig[$scope][$scopeId][$path])
-                ? $appConfig[$scope][$scopeId][$path]
-                : null;
+            $data = new DataObject(isset($appConfig[$scope][$scopeCode]) ? $appConfig[$scope][$scopeCode] : []);
         }
-        return $data;
+        return $data->getData($path);
     }
 }
diff --git a/app/code/Magento/Config/Model/Config/Export/Comment.php b/app/code/Magento/Config/Model/Config/Export/Comment.php
new file mode 100644
index 0000000000000000000000000000000000000000..ae0431c82daa031523f464ea1539209ca324996c
--- /dev/null
+++ b/app/code/Magento/Config/Model/Config/Export/Comment.php
@@ -0,0 +1,59 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Config\Model\Config\Export;
+
+use Magento\Config\App\Config\Source\DumpConfigSourceInterface;
+use Magento\Config\Model\Placeholder\PlaceholderFactory;
+use Magento\Config\Model\Placeholder\PlaceholderInterface;
+use Magento\Framework\App\Config\CommentInterface;
+
+/**
+ * Class Comment. Is used to retrieve comment for config dump file
+ */
+class Comment implements CommentInterface
+{
+    /**
+     * @var PlaceholderInterface
+     */
+    private $placeholder;
+
+    /**
+     * @var DumpConfigSourceInterface
+     */
+    private $source;
+
+    /**
+     * @param PlaceholderFactory $placeholderFactory
+     * @param DumpConfigSourceInterface $source
+     */
+    public function __construct(
+        PlaceholderFactory $placeholderFactory,
+        DumpConfigSourceInterface $source
+    ) {
+        $this->placeholder = $placeholderFactory->create(PlaceholderFactory::TYPE_ENVIRONMENT);
+        $this->source = $source;
+    }
+
+    /**
+     * Retrieves comments for config export file.
+     *
+     * @return string
+     */
+    public function get()
+    {
+        $comment = '';
+        $fields = $this->source->getExcludedFields();
+        foreach ($fields as $path) {
+            $comment .= "\n" . $this->placeholder->generate($path) . ' for ' . $path ;
+        }
+        if ($comment) {
+            $comment = 'The configuration file doesn\'t contain sensitive data for security reasons. '
+                . 'Sensitive data can be stored in the following environment variables:'
+                . $comment;
+        }
+        return $comment;
+    }
+}
diff --git a/app/code/Magento/Config/Model/Config/Export/ExcludeList.php b/app/code/Magento/Config/Model/Config/Export/ExcludeList.php
new file mode 100644
index 0000000000000000000000000000000000000000..f3c10b4100ed3a068b56873553c96e2e5852073b
--- /dev/null
+++ b/app/code/Magento/Config/Model/Config/Export/ExcludeList.php
@@ -0,0 +1,55 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Config\Model\Config\Export;
+
+use Magento\Framework\App\Config\ScopeConfigInterface;
+
+/**
+ * Class ExcludeList contains list of config fields which should be excluded from config export file
+ */
+class ExcludeList
+{
+    /**
+     * @var array
+     */
+    private $configs;
+
+    /**
+     * @param array $configs
+     */
+    public function __construct(array $configs = [])
+    {
+        $this->configs = $configs;
+    }
+
+    /**
+     * Check whether config item is excluded from export
+     *
+     * @param string $path
+     * @return bool
+     */
+    public function isPresent($path)
+    {
+        return !empty($this->configs[$path]) ;
+    }
+
+    /**
+     * Retrieves all excluded field paths for export
+     *
+     * @return array
+     */
+    public function get()
+    {
+        return array_keys(
+            array_filter(
+                $this->configs,
+                function ($value) {
+                    return filter_var($value, FILTER_VALIDATE_BOOLEAN);
+                }
+            )
+        );
+    }
+}
diff --git a/app/code/Magento/Config/Model/Config/Processor/EnvironmentPlaceholder.php b/app/code/Magento/Config/Model/Config/Processor/EnvironmentPlaceholder.php
new file mode 100644
index 0000000000000000000000000000000000000000..efbe888f2ebd62e0376e567e4046080af6ba8658
--- /dev/null
+++ b/app/code/Magento/Config/Model/Config/Processor/EnvironmentPlaceholder.php
@@ -0,0 +1,70 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Config\Model\Config\Processor;
+
+use Magento\Config\Model\Placeholder\PlaceholderFactory;
+use Magento\Config\Model\Placeholder\PlaceholderInterface;
+use Magento\Framework\App\Config\Spi\PreProcessorInterface;
+use Magento\Framework\Stdlib\ArrayManager;
+
+/**
+ * Allows to extract configurations from environment variables.
+ */
+class EnvironmentPlaceholder implements PreProcessorInterface
+{
+    /**
+     * @var PlaceholderFactory
+     */
+    private $placeholderFactory;
+
+    /**
+     * @var ArrayManager
+     */
+    private $arrayManager;
+
+    /**
+     * @var PlaceholderInterface
+     */
+    private $placeholder;
+
+    /**
+     * @param PlaceholderFactory $placeholderFactory
+     * @param ArrayManager $arrayManager
+     */
+    public function __construct(
+        PlaceholderFactory $placeholderFactory,
+        ArrayManager $arrayManager
+    ) {
+        $this->placeholderFactory = $placeholderFactory;
+        $this->arrayManager = $arrayManager;
+        $this->placeholder = $placeholderFactory->create(PlaceholderFactory::TYPE_ENVIRONMENT);
+    }
+
+    /**
+     * Method extracts environment variables.
+     * If environment variable is matching the desired rule - it's being used as value.
+     *
+     * {@inheritdoc}
+     */
+    public function process(array $config)
+    {
+        $environmentVariables = $_ENV;
+
+        foreach ($environmentVariables as $template => $value) {
+            if (!$this->placeholder->isApplicable($template)) {
+                continue;
+            }
+
+            $config = $this->arrayManager->set(
+                $this->placeholder->restore($template),
+                $config,
+                $value
+            );
+        }
+
+        return $config;
+    }
+}
diff --git a/app/code/Magento/Config/Model/Config/Reader/Source/Deployed/SettingChecker.php b/app/code/Magento/Config/Model/Config/Reader/Source/Deployed/SettingChecker.php
index 48b82086ad8b10d3b0241d2502b6199ab2584ab1..7e673401c7348c0721d917b5417c9940ceae16e3 100644
--- a/app/code/Magento/Config/Model/Config/Reader/Source/Deployed/SettingChecker.php
+++ b/app/code/Magento/Config/Model/Config/Reader/Source/Deployed/SettingChecker.php
@@ -6,10 +6,11 @@
 namespace Magento\Config\Model\Config\Reader\Source\Deployed;
 
 use Magento\Config\Model\Config\Reader;
-use Magento\Framework\App\Config\ScopeCodeResolver;
 use Magento\Framework\App\Config\ScopeConfigInterface;
 use Magento\Framework\App\DeploymentConfig;
-use Magento\Framework\App\ObjectManager;
+use Magento\Config\Model\Placeholder\PlaceholderInterface;
+use Magento\Config\Model\Placeholder\PlaceholderFactory;
+use Magento\Framework\App\Config\ScopeCodeResolver;
 
 /**
  * Class for checking settings that defined in config file
@@ -21,6 +22,11 @@ class SettingChecker
      */
     private $config;
 
+    /**
+     * @var PlaceholderInterface
+     */
+    private $placeholder;
+
     /**
      * @var ScopeCodeResolver
      */
@@ -28,45 +34,86 @@ class SettingChecker
 
     /**
      * @param DeploymentConfig $config
+     * @param PlaceholderFactory $placeholderFactory
      * @param ScopeCodeResolver $scopeCodeResolver
      */
     public function __construct(
         DeploymentConfig $config,
+        PlaceholderFactory $placeholderFactory,
         ScopeCodeResolver $scopeCodeResolver
     ) {
         $this->config = $config;
         $this->scopeCodeResolver = $scopeCodeResolver;
+        $this->placeholder = $placeholderFactory->create(PlaceholderFactory::TYPE_ENVIRONMENT);
     }
 
     /**
-     * Resolve path by scope and scope code
+     * Check that setting defined in deployed configuration
      *
+     * @param string $path
      * @param string $scope
-     * @param string $scopeCode
-     * @return string
+     * @param string|null $scopeCode
+     * @return boolean
      */
-    private function resolvePath($scope, $scopeCode)
+    public function isReadOnly($path, $scope, $scopeCode = null)
     {
-        $scopePath = 'system/' . $scope;
+        $config = $this->getEnvValue(
+            $this->placeholder->generate($path, $scope, $scopeCode)
+        );
 
-        if ($scope != ScopeConfigInterface::SCOPE_TYPE_DEFAULT) {
-            $scopePath .= '/' . $this->scopeCodeResolver->resolve($scope, $scopeCode);
+        if (null === $config) {
+            $config = $this->config->get($this->resolvePath($scope, $scopeCode) . "/" . $path);
         }
 
-        return $scopePath;
+        return $config !== null;
     }
 
     /**
-     * Check that setting defined in deployed configuration
+     * Check that there is value for generated placeholder
+     *
+     * Placeholder is generated from values of $path, $scope and $scopeCode
      *
      * @param string $path
      * @param string $scope
      * @param string $scopeCode
-     * @return boolean
+     * @param string|null $scopeCode
+     * @return string|null
      */
-    public function isReadOnly($path, $scope, $scopeCode)
+    public function getPlaceholderValue($path, $scope, $scopeCode = null)
     {
-        $config = $this->config->get($this->resolvePath($scope, $scopeCode) . "/" . $path);
-        return $config !== null;
+        return $this->getEnvValue($this->placeholder->generate($path, $scope, $scopeCode));
+    }
+
+    /**
+     * Retrieve value of environment variable by placeholder
+     *
+     * @param string $placeholder
+     * @return string|null
+     */
+    public function getEnvValue($placeholder)
+    {
+        if ($this->placeholder->isApplicable($placeholder) && isset($_ENV[$placeholder])) {
+            return $_ENV[$placeholder];
+        }
+
+        return null;
+    }
+
+    /**
+     * Resolve path by scope and scope code
+     *
+     * @param string $scope
+     * @param string $scopeCode
+     * @return string
+     */
+    private function resolvePath($scope, $scopeCode)
+    {
+        $scopePath = 'system/' . $scope;
+
+        if ($scope != ScopeConfigInterface::SCOPE_TYPE_DEFAULT) {
+            $scopePath .= '/' . $this->scopeCodeResolver->resolve($scope, $scopeCode);
+        }
+
+        return $scopePath;
     }
 }
diff --git a/app/code/Magento/Config/Model/Placeholder/Environment.php b/app/code/Magento/Config/Model/Placeholder/Environment.php
new file mode 100644
index 0000000000000000000000000000000000000000..96ffadc96c6f9a958ebc61e6626bcc02ac178237
--- /dev/null
+++ b/app/code/Magento/Config/Model/Placeholder/Environment.php
@@ -0,0 +1,76 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Config\Model\Placeholder;
+
+use Magento\Framework\App\Config\ScopeConfigInterface;
+use Magento\Framework\App\DeploymentConfig;
+
+/**
+ * Class is used to work with placeholders for environment variables names based on config paths
+ */
+class Environment implements PlaceholderInterface
+{
+    /**
+     * @const string Prefix for placeholder
+     */
+    const PREFIX = 'CONFIG__';
+
+    /**
+     * @var DeploymentConfig
+     */
+    private $deploymentConfig;
+
+    /**
+     * @param DeploymentConfig $deploymentConfig
+     */
+    public function __construct(DeploymentConfig $deploymentConfig)
+    {
+        $this->deploymentConfig = $deploymentConfig;
+    }
+
+    /**
+     * Generates placeholder like CONFIG__DEFAULT__TEST__TEST_VALUE
+     *
+     * @inheritdoc
+     */
+    public function generate($path, $scopeType = ScopeConfigInterface::SCOPE_TYPE_DEFAULT, $scopeCode = null)
+    {
+        $parts = $scopeType ? [$scopeType] : [];
+
+        if ($scopeType !== ScopeConfigInterface::SCOPE_TYPE_DEFAULT && $scopeCode) {
+            $parts[] = $scopeCode;
+        }
+
+        $parts[] = $path;
+
+        $template = implode('__', $parts);
+        $template = str_replace('/', '__', $template);
+        $template = static::PREFIX . $template;
+        $template = strtoupper($template);
+
+        return $template;
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function restore($template)
+    {
+        $template = preg_replace('/^' . static::PREFIX . '/', '', $template);
+        $template = str_replace('__', '/', $template);
+        $template = strtolower($template);
+
+        return $template;
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function isApplicable($placeholder)
+    {
+        return 1 === preg_match('/^' . static::PREFIX . '([a-zA-Z]+)([a-zA-Z0-9_])*$/', $placeholder);
+    }
+}
diff --git a/app/code/Magento/Config/Model/Placeholder/PlaceholderFactory.php b/app/code/Magento/Config/Model/Placeholder/PlaceholderFactory.php
new file mode 100644
index 0000000000000000000000000000000000000000..3f88bc2a289c4b32e47f24ef43223a868ea99267
--- /dev/null
+++ b/app/code/Magento/Config/Model/Placeholder/PlaceholderFactory.php
@@ -0,0 +1,59 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Config\Model\Placeholder;
+
+use Magento\Framework\Exception\LocalizedException;
+use Magento\Framework\ObjectManagerInterface;
+
+class PlaceholderFactory
+{
+    /**
+     * @const string Environment type
+     */
+    const TYPE_ENVIRONMENT = 'environment';
+
+    /**
+     * @var ObjectManagerInterface
+     */
+    private $objectManager;
+
+    /**
+     * @var array
+     */
+    private $types;
+
+    /**
+     * @param ObjectManagerInterface $objectManager
+     * @param array $types
+     */
+    public function __construct(ObjectManagerInterface $objectManager, array $types = [])
+    {
+        $this->objectManager = $objectManager;
+        $this->types = $types;
+    }
+
+    /**
+     * Create placeholder
+     *
+     * @param string $type
+     * @return PlaceholderInterface
+     * @throws LocalizedException
+     */
+    public function create($type)
+    {
+        if (!isset($this->types[$type])) {
+            throw new LocalizedException(__('There is no defined type ' . $type));
+        }
+
+        $object = $this->objectManager->create($this->types[$type]);
+
+        if (!$object instanceof PlaceholderInterface) {
+            throw new LocalizedException(__('Object is not instance of ' . PlaceholderInterface::class));
+        }
+
+        return $object;
+    }
+}
diff --git a/app/code/Magento/Config/Model/Placeholder/PlaceholderInterface.php b/app/code/Magento/Config/Model/Placeholder/PlaceholderInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..286eb0034a55063b8dcbf35cc13474ef144fd656
--- /dev/null
+++ b/app/code/Magento/Config/Model/Placeholder/PlaceholderInterface.php
@@ -0,0 +1,40 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Config\Model\Placeholder;
+
+use Magento\Framework\App\Config\ScopeConfigInterface;
+
+/**
+ * Interface PlaceholderInterface
+ */
+interface PlaceholderInterface
+{
+    /**
+     * Generating placeholder from value
+     *
+     * @param string $path
+     * @param string $scopeType
+     * @param string $scopeCode
+     * @return string
+     */
+    public function generate($path, $scopeType = ScopeConfigInterface::SCOPE_TYPE_DEFAULT, $scopeCode = null);
+
+    /**
+     * Restoring path parts from template.
+     *
+     * @param string $template
+     * @return string
+     */
+    public function restore($template);
+
+    /**
+     * Check whether provided string is placeholder
+     *
+     * @param string $placeholder
+     * @return bool
+     */
+    public function isApplicable($placeholder);
+}
diff --git a/app/code/Magento/Config/Test/Unit/App/Config/Source/DumpConfigSourceAggregatedTest.php b/app/code/Magento/Config/Test/Unit/App/Config/Source/DumpConfigSourceAggregatedTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..9c6aef37540e5d69f071b8f4f9ccb465f69233ff
--- /dev/null
+++ b/app/code/Magento/Config/Test/Unit/App/Config/Source/DumpConfigSourceAggregatedTest.php
@@ -0,0 +1,171 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Config\Test\Unit\App\Config\Source;
+
+use Magento\Config\App\Config\Source\DumpConfigSourceAggregated;
+use Magento\Config\Model\Config\Export\ExcludeList;
+use Magento\Framework\App\Config\ConfigSourceInterface;
+
+class DumpConfigSourceAggregatedTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var ConfigSourceInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $sourceMock;
+
+    /**
+     * @var ConfigSourceInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $sourceMockTwo;
+
+    /**
+     * @var DumpConfigSourceAggregated
+     */
+    private $model;
+
+    /**
+     * @var ExcludeList|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $excludeListMock;
+
+    public function setUp()
+    {
+        $this->sourceMock = $this->getMockBuilder(ConfigSourceInterface::class)
+            ->getMockForAbstractClass();
+        $this->sourceMockTwo = $this->getMockBuilder(ConfigSourceInterface::class)
+            ->getMockForAbstractClass();
+        $this->excludeListMock = $this->getMockBuilder(ExcludeList::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $sources = [
+            [
+                'source' => $this->sourceMockTwo,
+                'sortOrder' => 100
+            ],
+            [
+                'source' => $this->sourceMock,
+                'sortOrder' => 10
+            ],
+
+        ];
+
+        $this->model = new DumpConfigSourceAggregated($this->excludeListMock, $sources);
+    }
+
+    public function testGet()
+    {
+        $path = '';
+        $data = [
+            'default' => [
+                'web' => [
+                    'unsecure' => [
+                        'base_url' => 'http://test.local',
+                    ],
+                    'secure' => [
+                        'base_url' => 'https://test.local',
+                    ]
+                ]
+            ],
+            'test' => [
+                'test' => [
+                    'test1' => [
+                        'test2' => [
+                            'test3' => 5,
+                        ]
+                    ]
+                ]
+            ]
+        ];
+
+        $this->sourceMock->expects($this->once())
+            ->method('get')
+            ->with($path)
+            ->willReturn($data);
+        $this->sourceMockTwo->expects($this->once())
+            ->method('get')
+            ->with($path)
+            ->willReturn(['key' => 'value2']);
+        $this->excludeListMock->expects($this->any())
+            ->method('isPresent')
+            ->willReturnMap([
+                ['web/unsecure/base_url', false],
+                ['web/secure/base_url', true],
+                ['test1/test2/test/3', false]
+            ]);
+
+        $this->assertEquals(
+            [
+                'test' => [
+                    'test' => [
+                        'test1' => [
+                            'test2' => [
+                                'test3' => 5,
+                            ]
+                        ]
+                    ],
+                ],
+                'key' => 'value2',
+                'default' => [
+                    'web' => [
+                        'unsecure' => [
+                            'base_url' => 'http://test.local',
+                        ],
+                        'secure' => []
+                    ]
+                ],
+            ],
+            $this->model->get($path)
+        );
+    }
+
+    public function testGetExcludedFields()
+    {
+        $path = '';
+        $data = [
+            'default' => [
+                'web' => [
+                    'unsecure' => [
+                        'base_url' => 'http://test.local',
+                    ],
+                    'secure' => [
+                        'base_url' => 'https://test.local',
+                    ]
+                ]
+            ],
+            'test' => [
+                'test' => [
+                    'test1' => [
+                        'test2' => [
+                            'test3' => 5,
+                        ]
+                    ]
+                ]
+            ]
+        ];
+
+        $this->sourceMock->expects($this->once())
+            ->method('get')
+            ->with($path)
+            ->willReturn($data);
+        $this->sourceMockTwo->expects($this->once())
+            ->method('get')
+            ->with($path)
+            ->willReturn(['key' => 'value2']);
+        $this->excludeListMock->expects($this->any())
+            ->method('isPresent')
+            ->willReturnMap([
+                ['web/unsecure/base_url', false],
+                ['web/secure/base_url', true],
+                ['test1/test2/test/3', false]
+            ]);
+
+        $this->assertEquals(
+            ['web/secure/base_url'],
+            $this->model->getExcludedFields()
+        );
+    }
+}
diff --git a/app/code/Magento/Config/Test/Unit/App/Config/Type/SystemTest.php b/app/code/Magento/Config/Test/Unit/App/Config/Type/SystemTest.php
index be541228bf6d88a5ad7e459ba77a34e896c863a1..8409e96db552e61a8ee3a8a4ec788d457d84ba5c 100644
--- a/app/code/Magento/Config/Test/Unit/App/Config/Type/SystemTest.php
+++ b/app/code/Magento/Config/Test/Unit/App/Config/Type/SystemTest.php
@@ -8,9 +8,9 @@ namespace Magento\Config\Test\Unit\App\Config\Type;
 use Magento\Config\App\Config\Type\System;
 use Magento\Framework\App\Config\ConfigSourceInterface;
 use Magento\Framework\App\Config\Spi\PostProcessorInterface;
-use Magento\Framework\App\ObjectManager;
+use Magento\Framework\App\Config\Spi\PreProcessorInterface;
 use Magento\Framework\Cache\FrontendInterface;
-use Magento\Framework\Serialize\Serializer\Serialize;
+use Magento\Framework\Serialize\SerializerInterface;
 use Magento\Store\Model\Config\Processor\Fallback;
 
 /**
@@ -29,6 +29,11 @@ class SystemTest extends \PHPUnit_Framework_TestCase
      */
     private $postProcessor;
 
+    /**
+     * @var PreProcessorInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $preProcessor;
+
     /**
      * @var Fallback|\PHPUnit_Framework_MockObject_MockObject
      */
@@ -45,7 +50,7 @@ class SystemTest extends \PHPUnit_Framework_TestCase
     private $configType;
 
     /**
-     * @var Serialize|\PHPUnit_Framework_MockObject_MockObject
+     * @var SerializerInterface|\PHPUnit_Framework_MockObject_MockObject
      */
     private $serializer;
 
@@ -60,7 +65,9 @@ class SystemTest extends \PHPUnit_Framework_TestCase
             ->getMock();
         $this->cache = $this->getMockBuilder(FrontendInterface::class)
             ->getMockForAbstractClass();
-        $this->serializer = $this->getMockBuilder(Serialize::class)
+        $this->preProcessor = $this->getMockBuilder(PreProcessorInterface::class)
+            ->getMockForAbstractClass();
+        $this->serializer = $this->getMockBuilder(SerializerInterface::class)
             ->disableOriginalConstructor()
             ->getMock();
         $this->configType = new System(
@@ -68,7 +75,8 @@ class SystemTest extends \PHPUnit_Framework_TestCase
             $this->postProcessor,
             $this->fallback,
             $this->cache,
-            $this->serializer
+            $this->serializer,
+            $this->preProcessor
         );
     }
 
@@ -112,6 +120,10 @@ class SystemTest extends \PHPUnit_Framework_TestCase
                 ->method('process')
                 ->with($data)
                 ->willReturnArgument(0);
+            $this->preProcessor->expects($this->once())
+                ->method('process')
+                ->with($data)
+                ->willReturnArgument(0);
             $this->postProcessor->expects($this->once())
                 ->method('process')
                 ->with($data)
diff --git a/app/code/Magento/Config/Test/Unit/Block/System/Config/FormTest.php b/app/code/Magento/Config/Test/Unit/Block/System/Config/FormTest.php
index 2c671914f264b04ec34508d919a23c67bf64abad..5c7bf92f954285571bc6620a1726d2ccfd9432f4 100644
--- a/app/code/Magento/Config/Test/Unit/Block/System/Config/FormTest.php
+++ b/app/code/Magento/Config/Test/Unit/Block/System/Config/FormTest.php
@@ -10,6 +10,7 @@ namespace Magento\Config\Test\Unit\Block\System\Config;
 
 use Magento\Config\Model\Config\Reader\Source\Deployed\SettingChecker;
 use Magento\Framework\App\DeploymentConfig;
+use Magento\Store\Model\StoreManagerInterface;
 
 /**
  * Test System config form block
@@ -72,6 +73,11 @@ class FormTest extends \PHPUnit_Framework_TestCase
      */
     protected $_fieldsetFactoryMock;
 
+    /**
+     * @var StoreManagerInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $storeManagerMock;
+
     /**
      * @return void
      * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
@@ -161,6 +167,9 @@ class FormTest extends \PHPUnit_Framework_TestCase
             false
         );
 
+        $this->storeManagerMock = $this->getMockBuilder(StoreManagerInterface::class)
+            ->getMockForAbstractClass();
+
         $helper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
 
         $context = $helper->getObject(
@@ -168,7 +177,8 @@ class FormTest extends \PHPUnit_Framework_TestCase
             [
                 'scopeConfig' => $this->_coreConfigMock,
                 'request' => $requestMock,
-                'urlBuilder' => $this->_urlModelMock
+                'urlBuilder' => $this->_urlModelMock,
+                'storeManager' => $this->storeManagerMock
             ]
         );
 
@@ -423,6 +433,7 @@ class FormTest extends \PHPUnit_Framework_TestCase
      * @param string|null $configPath
      * @param bool $inherit
      * @param string $expectedValue
+     * @param string|null $placeholderValue
      * @param int $hasBackendModel
      *
      * @dataProvider initFieldsDataProvider
@@ -434,6 +445,7 @@ class FormTest extends \PHPUnit_Framework_TestCase
         $configPath,
         $inherit,
         $expectedValue,
+        $placeholderValue,
         $hasBackendModel
     ) {
         // Parameters initialization
@@ -503,6 +515,18 @@ class FormTest extends \PHPUnit_Framework_TestCase
             $this->returnValue($configValue)
         );
 
+        /** @var \Magento\Store\Api\Data\StoreInterface|\PHPUnit_Framework_MockObject_MockObject $storeMock */
+        $storeMock = $this->getMockBuilder(\Magento\Store\Api\Data\StoreInterface::class)
+            ->getMockForAbstractClass();
+        $storeMock->expects($this->once())
+            ->method('getCode')
+            ->willReturn('store_code');
+
+        $this->storeManagerMock->expects($this->atLeastOnce())
+            ->method('getStore')
+            ->with('store_code')
+            ->willReturn($storeMock);
+
         // Field mock configuration
         $fieldMock = $this->getMock(
             \Magento\Config\Model\Config\Structure\Element\Field::class,
@@ -596,17 +620,20 @@ class FormTest extends \PHPUnit_Framework_TestCase
 
         $fieldMock->expects($this->once())->method('populateInput');
 
-
-        $settingChecker = $this->getMockBuilder(SettingChecker::class)
+        $settingCheckerMock = $this->getMockBuilder(SettingChecker::class)
             ->disableOriginalConstructor()
             ->getMock();
-        $settingChecker->expects($this->once())
+        $settingCheckerMock->expects($this->once())
             ->method('isReadOnly')
             ->willReturn(false);
-        $reflection = new \ReflectionClass(get_class($this->object));
-        $reflectionProperty = $reflection->getProperty('settingChecker');
-        $reflectionProperty->setAccessible(true);
-        $reflectionProperty->setValue($this->object, $settingChecker);
+
+        $settingCheckerMock->expects($this->once())
+            ->method('getPlaceholderValue')
+            ->willReturn($placeholderValue);
+
+        $helper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
+
+        $helper->setBackwardCompatibleProperty($this->object, 'settingChecker', $settingCheckerMock);
 
         $this->object->initFields($fieldsetMock, $groupMock, $sectionMock, $fieldPrefix, $labelPrefix);
     }
@@ -617,8 +644,9 @@ class FormTest extends \PHPUnit_Framework_TestCase
     public function initFieldsDataProvider()
     {
         return [
-            [['section1/group1/field1' => 'some_value'], false, null, false, 'some_value', 1],
-            [[], 'Config Value', 'some/config/path', true, 'Config Value', 0]
+            [['section1/group1/field1' => 'some_value'], false, null, false, 'some_value', null, 1],
+            [[], 'Config Value', 'some/config/path', true, 'Config Value', null, 0],
+            [[], 'Config Value', 'some/config/path', true, 'Placeholder Value', 'Placeholder Value', 0]
         ];
     }
 }
diff --git a/app/code/Magento/Config/Test/Unit/Model/Config/Export/CommentTest.php b/app/code/Magento/Config/Test/Unit/Model/Config/Export/CommentTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..c8b10bcf4ddcd5393a62307c873646f87d1419e8
--- /dev/null
+++ b/app/code/Magento/Config/Test/Unit/Model/Config/Export/CommentTest.php
@@ -0,0 +1,88 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Config\Test\Unit\Model\Config\Export;
+
+use Magento\Config\Model\Config\Export\Comment;
+use Magento\Config\App\Config\Source\DumpConfigSourceInterface;
+use Magento\Config\Model\Placeholder\PlaceholderFactory;
+use Magento\Config\Model\Placeholder\PlaceholderInterface;
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
+
+class CommentTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var DumpConfigSourceInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $configSourceMock;
+
+    /**
+     * @var PlaceholderInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $placeholderMock;
+
+    /**
+     * @var Comment
+     */
+    private $model;
+
+    protected function setUp()
+    {
+        $objectManager = new ObjectManager($this);
+
+        $this->placeholderMock = $this->getMockBuilder(PlaceholderInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+
+        $placeholderFactoryMock = $this->getMockBuilder(PlaceholderFactory::class)
+            ->setMethods(['create'])
+            ->disableOriginalConstructor()
+            ->getMock();
+        $placeholderFactoryMock->expects($this->once())
+            ->method('create')
+            ->with(PlaceholderFactory::TYPE_ENVIRONMENT)
+            ->willReturn($this->placeholderMock);
+
+        $this->configSourceMock = $this->getMockBuilder(DumpConfigSourceInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+
+        $this->model = $objectManager->getObject(
+            Comment::class,
+            [
+                'placeholderFactory' => $placeholderFactoryMock,
+                'source' => $this->configSourceMock
+            ]
+        );
+    }
+
+    public function testGetEmpty()
+    {
+        $this->configSourceMock->expects($this->once())
+            ->method('getExcludedFields')
+            ->willReturn([]);
+        $this->assertEmpty($this->model->get());
+    }
+
+    public function testGet()
+    {
+        $path = 'one/two';
+        $placeholder = 'one__two';
+        $expectedResult = 'The configuration file doesn\'t contain sensitive data for security reasons. '
+            . 'Sensitive data can be stored in the following environment variables:'
+            . "\n$placeholder for $path";
+
+        $this->configSourceMock->expects($this->once())
+            ->method('getExcludedFields')
+            ->willReturn([$path]);
+
+        $this->placeholderMock->expects($this->once())
+            ->method('generate')
+            ->with($path)
+            ->willReturn($placeholder);
+
+        $this->assertEquals($expectedResult, $this->model->get());
+    }
+}
diff --git a/app/code/Magento/Config/Test/Unit/Model/Config/Export/ExcludeListTest.php b/app/code/Magento/Config/Test/Unit/Model/Config/Export/ExcludeListTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..3156ad1ec549325839bbf9470c6396d101ee557f
--- /dev/null
+++ b/app/code/Magento/Config/Test/Unit/Model/Config/Export/ExcludeListTest.php
@@ -0,0 +1,40 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Config\Test\Unit\Model\Config\Export;
+
+use Magento\Config\Model\Config\Export\ExcludeList;
+
+class ExcludeListTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var ExcludeList
+     */
+    private $model;
+
+    protected function setUp()
+    {
+        $this->model = new ExcludeList(
+            [
+                'web/unsecure/base_url' => '',
+                'web/test/test_value' => '0',
+                'web/test/test_sensitive' => '1',
+            ]
+        );
+    }
+
+    public function testGet()
+    {
+        $this->assertEquals(['web/test/test_sensitive'], $this->model->get());
+    }
+
+    public function testIsPresent()
+    {
+        $this->assertFalse($this->model->isPresent('some/new/path'));
+        $this->assertFalse($this->model->isPresent('web/unsecure/base_url'));
+        $this->assertFalse($this->model->isPresent('web/test/test_value'));
+        $this->assertTrue($this->model->isPresent('web/test/test_sensitive'));
+    }
+}
diff --git a/app/code/Magento/Config/Test/Unit/Model/Config/Processor/EnvironmentPlaceholderTest.php b/app/code/Magento/Config/Test/Unit/Model/Config/Processor/EnvironmentPlaceholderTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..25f9f6b3cb83222dd9c196114729e8b10465072b
--- /dev/null
+++ b/app/code/Magento/Config/Test/Unit/Model/Config/Processor/EnvironmentPlaceholderTest.php
@@ -0,0 +1,131 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Config\Test\Unit\Model\Config\Processor;
+
+use Magento\Config\Model\Config\Processor\EnvironmentPlaceholder;
+use Magento\Config\Model\Placeholder\PlaceholderFactory;
+use Magento\Config\Model\Placeholder\PlaceholderInterface;
+use Magento\Framework\Stdlib\ArrayManager;
+use \PHPUnit_Framework_MockObject_MockObject as Mock;
+
+class EnvironmentPlaceholderTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var EnvironmentPlaceholder
+     */
+    private $model;
+
+    /**
+     * @var PlaceholderFactory|Mock
+     */
+    private $placeholderFactoryMock;
+
+    /**
+     * @var ArrayManager|Mock
+     */
+    private $arrayManagerMock;
+
+    /**
+     * @var PlaceholderInterface|Mock
+     */
+    private $placeholderMock;
+
+    /**
+     * @var array
+     */
+    private $env;
+
+    protected function setUp()
+    {
+        $this->placeholderFactoryMock = $this->getMockBuilder(PlaceholderFactory::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->arrayManagerMock = $this->getMockBuilder(ArrayManager::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->placeholderMock = $this->getMockBuilder(PlaceholderInterface::class)
+            ->getMockForAbstractClass();
+        $this->env = $_ENV;
+
+        $this->placeholderFactoryMock->expects($this->any())
+            ->method('create')
+            ->with(PlaceholderFactory::TYPE_ENVIRONMENT)
+            ->willReturn($this->placeholderMock);
+
+        $this->model = new EnvironmentPlaceholder(
+            $this->placeholderFactoryMock,
+            $this->arrayManagerMock
+        );
+    }
+
+    public function testProcess()
+    {
+        $_ENV = array_merge(
+            $this->env,
+            [
+                'CONFIG_DEFAULT_TEST' => 1,
+                'CONFIG_DEFAULT_TEST2' => 2,
+                'BAD_CONFIG' => 3,
+            ]
+        );
+
+        $this->placeholderMock->expects($this->any())
+            ->method('isApplicable')
+            ->willReturnMap(
+                [
+                    ['CONFIG_DEFAULT_TEST', true],
+                    ['CONFIG_DEFAULT_TEST2', true],
+                    ['BAD_CONFIG', false],
+                ]
+            );
+        $this->placeholderMock->expects($this->any())
+            ->method('restore')
+            ->willReturnMap(
+                [
+                    ['CONFIG_DEFAULT_TEST', 'default/test'],
+                    ['CONFIG_DEFAULT_TEST2', 'default/test2'],
+                ]
+            );
+        $this->arrayManagerMock->expects($this->any())
+            ->method('set')
+            ->willReturnMap(
+                [
+                    ['default/test', [], 1, '/', ['default' => ['test' => 1]]],
+                    [
+                        'default/test2',
+                        [
+                            'default' => [
+                                'test' => 1
+                            ]
+                        ],
+                        2,
+                        '/',
+                        [
+                            'default' => [
+                                'test' => 1,
+                                'test2' => 2
+                            ]
+                        ],
+                    ]
+                ]
+            );
+
+        $this->assertSame(
+            [
+                'default' => [
+                    'test' => 1,
+                    'test2' => 2
+                ]
+            ],
+            $this->model->process([])
+        );
+    }
+
+    protected function tearDown()
+    {
+        $_ENV = $this->env;
+    }
+}
diff --git a/app/code/Magento/Config/Test/Unit/Model/Config/Reader/Source/Deployed/SettingCheckerTest.php b/app/code/Magento/Config/Test/Unit/Model/Config/Reader/Source/Deployed/SettingCheckerTest.php
index 2e746eae410f414788a7b5277e331be7075e6655..75bfab85616b588975175abe8976a8e57ec65e04 100644
--- a/app/code/Magento/Config/Test/Unit/Model/Config/Reader/Source/Deployed/SettingCheckerTest.php
+++ b/app/code/Magento/Config/Test/Unit/Model/Config/Reader/Source/Deployed/SettingCheckerTest.php
@@ -7,21 +7,30 @@ namespace Magento\Config\Test\Unit\Model\Config\Reader\Source\Deployed;
 
 use Magento\Config\Model\Config\Reader;
 use Magento\Config\Model\Config\Reader\Source\Deployed\SettingChecker;
-use Magento\Framework\App\Config\ScopeCodeResolver;
 use Magento\Framework\App\Config;
 use Magento\Framework\App\DeploymentConfig;
+use Magento\Config\Model\Placeholder\PlaceholderInterface;
+use Magento\Config\Model\Placeholder\PlaceholderFactory;
 
 /**
  * Test class for checking settings that defined in config file
- *
- * @package Magento\Config\Test\Unit\Model\Config\Reader\Source\Deployed
  */
 class SettingCheckerTest extends \PHPUnit_Framework_TestCase
 {
     /**
      * @var Config|\PHPUnit_Framework_MockObject_MockObject
      */
-    private $config;
+    private $configMock;
+
+    /**
+     * @var PlaceholderInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $placeholderMock;
+
+    /**
+     * @var Config\ScopeCodeResolver|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $scopeCodeResolverMock;
 
     /**
      * @var SettingChecker
@@ -29,43 +38,109 @@ class SettingCheckerTest extends \PHPUnit_Framework_TestCase
     private $checker;
 
     /**
-     * @var ScopeCodeResolver | \PHPUnit_Framework_MockObject_MockObject
+     * @var array
      */
-    private $scopeCodeResolver;
+    private $env;
 
     public function setUp()
     {
-        $this->config = $this->getMockBuilder(DeploymentConfig::class)
+        $this->configMock = $this->getMockBuilder(DeploymentConfig::class)
             ->disableOriginalConstructor()
             ->getMock();
-        $this->scopeCodeResolver = $this->getMockBuilder(ScopeCodeResolver::class)
+        $this->placeholderMock = $this->getMockBuilder(PlaceholderInterface::class)
+            ->getMockForAbstractClass();
+        $this->scopeCodeResolverMock = $this->getMockBuilder(Config\ScopeCodeResolver::class)
             ->disableOriginalConstructor()
             ->getMock();
-        $this->checker = new SettingChecker($this->config, $this->scopeCodeResolver);
+        $placeholderFactoryMock = $this->getMockBuilder(PlaceholderFactory::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->env = $_ENV;
+
+        $placeholderFactoryMock->expects($this->once())
+            ->method('create')
+            ->with(PlaceholderFactory::TYPE_ENVIRONMENT)
+            ->willReturn($this->placeholderMock);
+
+        $this->checker = new SettingChecker($this->configMock, $placeholderFactoryMock, $this->scopeCodeResolverMock);
     }
 
-    public function testIsDefined()
+    /**
+     * @param string $path
+     * @param string $scope
+     * @param string $scopeCode
+     * @param string|null $confValue
+     * @param array $variables
+     * @param bool $expectedResult
+     * @dataProvider isReadonlyDataProvider
+     */
+    public function testIsReadonly($path, $scope, $scopeCode, $confValue, array $variables, $expectedResult)
     {
-        $path = 'general/web/locale';
-        $scope = 'website';
-        $scopeCode = 'myWebsite';
-        $scopeCodeId = '4';
+        $this->placeholderMock->expects($this->once())
+            ->method('isApplicable')
+            ->willReturn(true);
+        $this->placeholderMock->expects($this->once())
+            ->method('generate')
+            ->with($path, $scope, $scopeCode)
+            ->willReturn('SOME_PLACEHOLDER');
+        $this->scopeCodeResolverMock->expects($this->any())
+            ->method('resolve')
+            ->willReturnMap(
+                [
+                    ['website', 'myWebsite', ($scopeCode ? $scopeCode : '')]
+                ]
+            );
+
+        $_ENV = array_merge($this->env, $variables);
 
-        $this->config->expects($this->once())
+        $this->configMock->expects($this->any())
             ->method('get')
-            ->willReturn([
-                $scope => [
-                    $scopeCode => [
-                        $path => 'value'
-                    ],
+            ->willReturnMap([
+                [
+                    'system/' . $scope . "/" . ($scopeCode ? $scopeCode . '/' : '') . $path,
+                    null,
+                    $confValue
                 ],
             ]);
 
-        $this->scopeCodeResolver->expects($this->once())
-            ->method('resolve')
-            ->with($scope, $scopeCodeId)
-            ->willReturn($scopeCode);
+        $this->assertSame($expectedResult, $this->checker->isReadOnly($path, $scope, $scopeCode));
+    }
 
-        $this->assertTrue($this->checker->isReadOnly($path, $scope, $scopeCodeId));
+    /**
+     * @return array
+     */
+    public function isReadonlyDataProvider()
+    {
+        return [
+            [
+                'path' => 'general/web/locale',
+                'scope' => 'website',
+                'scopeCode' => 'myWebsite',
+                'confValue' => 'value',
+                'variables' => [],
+                'expectedResult' => true,
+            ],
+            [
+                'path' => 'general/web/locale',
+                'scope' => 'website',
+                'scopeCode' => 'myWebsite',
+                'confValue' => null,
+                'variables' => ['SOME_PLACEHOLDER' => 'value'],
+                'expectedResult' => true,
+            ],
+            [
+                'path' => 'general/web/locale',
+                'scope' => 'website',
+                'scopeCode' => 'myWebsite',
+                'confValue' => null,
+                'variables' => [],
+                'expectedResult' => false,
+            ]
+        ];
+    }
+
+    protected function tearDown()
+    {
+        $_ENV = $this->env;
     }
 }
diff --git a/app/code/Magento/Config/Test/Unit/Model/Placeholder/EnvironmentTest.php b/app/code/Magento/Config/Test/Unit/Model/Placeholder/EnvironmentTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..64b4e6e37fb94867854da15f8e0f72d9b0ccbf3c
--- /dev/null
+++ b/app/code/Magento/Config/Test/Unit/Model/Placeholder/EnvironmentTest.php
@@ -0,0 +1,131 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Config\Test\Unit\Model\Placeholder;
+
+use Magento\Config\Model\Placeholder\Environment;
+use Magento\Framework\App\Config\ScopeConfigInterface;
+use Magento\Framework\App\DeploymentConfig;
+use Magento\Framework\Config\ConfigOptionsListConstants;
+use \PHPUnit_Framework_MockObject_MockObject as Mock;
+
+/**
+ * Class EnvironmentTest
+ */
+class EnvironmentTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var Environment
+     */
+    private $model;
+
+    /**
+     * @var DeploymentConfig|Mock
+     */
+    private $deploymentConfigMock;
+
+    protected function setUp()
+    {
+        $this->deploymentConfigMock = $this->getMockBuilder(DeploymentConfig::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->model = new Environment(
+            $this->deploymentConfigMock
+        );
+    }
+
+    /**
+     * @param string $path
+     * @param string $scope
+     * @param string $scopeId
+     * @param string $expected
+     * @dataProvider getGenerateDataProvider
+     */
+    public function testGenerate($path, $scope, $scopeId, $expected)
+    {
+        $this->assertSame(
+            $expected,
+            $this->model->generate($path, $scope, $scopeId)
+        );
+    }
+
+    public function getGenerateDataProvider()
+    {
+        return [
+            [
+                'web/unsecure/base_url',
+                ScopeConfigInterface::SCOPE_TYPE_DEFAULT,
+                null,
+                Environment::PREFIX . 'DEFAULT__WEB__UNSECURE__BASE_URL'
+            ],
+            [
+                'web/unsecure/base_url',
+                'web',
+                'test',
+                Environment::PREFIX . 'WEB__TEST__WEB__UNSECURE__BASE_URL'
+            ],
+            [
+                'web/unsecure/base_url',
+                'web',
+                null,
+                Environment::PREFIX . 'WEB__WEB__UNSECURE__BASE_URL'
+            ],
+        ];
+    }
+
+    /**
+     * @param string $placeholder
+     * @param bool $expected
+     * @dataProvider getIsPlaceholderDataProvider
+     */
+    public function testIsApplicable($placeholder, $expected)
+    {
+        $this->assertSame(
+            $expected,
+            $this->model->isApplicable($placeholder)
+        );
+    }
+
+    /**
+     * @return array
+     */
+    public function getIsPlaceholderDataProvider()
+    {
+        return [
+            [Environment::PREFIX . 'TEST', true],
+            ['TEST', false],
+            [Environment::PREFIX . 'TEST_test', true],
+            [Environment::PREFIX . '-:A', false],
+            [Environment::PREFIX . '_A', false],
+            [Environment::PREFIX . 'A@#$', false]
+        ];
+    }
+
+    /**
+     * @param string $template
+     * @param string $expected
+     * @dataProvider restoreDataProvider
+     */
+    public function testRestore($template, $expected)
+    {
+        $this->assertSame(
+            $expected,
+            $this->model->restore($template)
+        );
+    }
+
+    /**
+     * @return array
+     */
+    public function restoreDataProvider()
+    {
+        return [
+            [Environment::PREFIX . 'TEST__CONFIG', 'test/config'],
+            [Environment::PREFIX . 'TEST__CONFIG__VALUE', 'test/config/value'],
+            [Environment::PREFIX . 'TEST__CONFIG_VALUE', 'test/config_value'],
+        ];
+    }
+}
diff --git a/app/code/Magento/Config/Test/Unit/Model/Placeholder/PlaceholderFactoryTest.php b/app/code/Magento/Config/Test/Unit/Model/Placeholder/PlaceholderFactoryTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..e8f646e984187ed49ffc7df0798c8efa689ba767
--- /dev/null
+++ b/app/code/Magento/Config/Test/Unit/Model/Placeholder/PlaceholderFactoryTest.php
@@ -0,0 +1,76 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Config\Test\Unit\Model\Placeholder;
+
+use Magento\Config\Model\Placeholder\Environment;
+use Magento\Config\Model\Placeholder\PlaceholderFactory;
+use Magento\Framework\ObjectManagerInterface;
+
+class PlaceholderFactoryTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var PlaceholderFactory
+     */
+    private $model;
+
+    /**
+     * @var ObjectManagerInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $objectManagerMock;
+
+    /**
+     * @var Environment|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $environmentMock;
+
+    protected function setUp()
+    {
+        $this->objectManagerMock = $this->getMockBuilder(ObjectManagerInterface::class)
+            ->getMockForAbstractClass();
+        $this->environmentMock = $this->getMockBuilder(Environment::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->model = new PlaceholderFactory(
+            $this->objectManagerMock,
+            [
+                PlaceholderFactory::TYPE_ENVIRONMENT => Environment::class,
+                'wrongClass' => \stdClass::class,
+            ]
+        );
+    }
+
+    public function testCreate()
+    {
+        $this->objectManagerMock->expects($this->once())
+            ->method('create')
+            ->with(Environment::class)
+            ->willReturn($this->environmentMock);
+
+        $this->assertInstanceOf(
+            Environment::class,
+            $this->model->create(PlaceholderFactory::TYPE_ENVIRONMENT)
+        );
+    }
+
+    /**
+     * @expectedException \Magento\Framework\Exception\LocalizedException
+     * @expectedExceptionMessage There is no defined type dummyClass
+     */
+    public function testCreateNonExisted()
+    {
+        $this->model->create('dummyClass');
+    }
+
+    /**
+     * @expectedException \Magento\Framework\Exception\LocalizedException
+     * @expectedExceptionMessage Object is not instance of Magento\Config\Model\Placeholder\PlaceholderInterface
+     */
+    public function testCreateWrongImplementation()
+    {
+        $this->model->create('wrongClass');
+    }
+}
diff --git a/app/code/Magento/Config/etc/di.xml b/app/code/Magento/Config/etc/di.xml
index 4f9eae24b55f611db54f3f5423c3944f7d93a7f6..3e2fa4fbecf6da0a712a1df313eb5b63812a5a20 100644
--- a/app/code/Magento/Config/etc/di.xml
+++ b/app/code/Magento/Config/etc/di.xml
@@ -81,6 +81,8 @@
             <argument name="source" xsi:type="object">systemConfigSourceAggregatedProxy</argument>
             <argument name="postProcessor" xsi:type="object">systemConfigPostProcessorCompositeProxy</argument>
             <argument name="cache" xsi:type="object">Magento\Framework\App\Cache\Type\Config</argument>
+            <argument name="preProcessor" xsi:type="object">systemConfigPreProcessorComposite</argument>
+            <argument name="serializer" xsi:type="object">Magento\Framework\Serialize\Serializer\Serialize</argument>
         </arguments>
     </type>
     <virtualType name="modulesDataProviderProxy" type="Magento\Framework\App\Config\InitialConfigSource\Proxy">
@@ -113,6 +115,13 @@
             </argument>
         </arguments>
     </virtualType>
+    <virtualType name="systemConfigPreProcessorComposite" type="Magento\Framework\App\Config\PreProcessorComposite">
+        <arguments>
+            <argument name="processors" xsi:type="array">
+                <item name="environmentPlaceholder" xsi:type="object">Magento\Config\Model\Config\Processor\EnvironmentPlaceholder</item>
+            </argument>
+        </arguments>
+    </virtualType>
     <virtualType name="systemConfigSourceAggregated" type="Magento\Framework\App\Config\ConfigSourceAggregated">
         <arguments>
             <argument name="sources" xsi:type="array">
@@ -138,15 +147,15 @@
             <argument name="fileKey" xsi:type="const">Magento\Framework\Config\File\ConfigFilePool::APP_CONFIG</argument>
         </arguments>
     </virtualType>
-    <virtualType name="appDumpSystemSource" type="Magento\Framework\App\Config\ConfigSourceAggregated">
+    <virtualType name="appDumpSystemSource" type="Magento\Config\App\Config\Source\DumpConfigSourceAggregated">
         <arguments>
             <argument name="sources" xsi:type="array">
-                <item name="initial" xsi:type="array">
-                    <item name="source" xsi:type="object">systemConfigInitialDataProvider</item>
-                    <item name="sortOrder" xsi:type="string">10</item>
-                </item>
                 <item name="dynamic" xsi:type="array">
                     <item name="source" xsi:type="object">Magento\Config\App\Config\Source\RuntimeConfigSource</item>
+                    <item name="sortOrder" xsi:type="string">100</item>
+                </item>
+                <item name="initial" xsi:type="array">
+                    <item name="source" xsi:type="object">systemConfigInitialDataProvider</item>
                     <item name="sortOrder" xsi:type="string">1000</item>
                 </item>
             </argument>
@@ -158,8 +167,21 @@
                 <item name="system" xsi:type="array">
                     <item name="source" xsi:type="object">appDumpSystemSource</item>
                     <item name="namespace" xsi:type="const">Magento\Config\App\Config\Type\System::CONFIG_TYPE</item>
+                    <item name="comment" xsi:type="object">Magento\Config\Model\Config\Export\Comment</item>
                 </item>
             </argument>
         </arguments>
     </type>
+    <type name="Magento\Config\Model\Config\Export\Comment">
+        <arguments>
+            <argument name="source" xsi:type="object">appDumpSystemSource</argument>
+        </arguments>
+    </type>
+    <type name="Magento\Config\Model\Placeholder\PlaceholderFactory">
+        <arguments>
+            <argument name="types" xsi:type="array">
+                <item name="environment" xsi:type="string">Magento\Config\Model\Placeholder\Environment</item>
+            </argument>
+        </arguments>
+    </type>
 </config>
diff --git a/app/code/Magento/Contact/etc/di.xml b/app/code/Magento/Contact/etc/di.xml
new file mode 100644
index 0000000000000000000000000000000000000000..95cd40cb55e3171e025e3482a290168799395212
--- /dev/null
+++ b/app/code/Magento/Contact/etc/di.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>
+<!--
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+-->
+<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
+    <type name="Magento\Config\Model\Config\Export\ExcludeList">
+        <arguments>
+            <argument name="configs" xsi:type="array">
+                <item name="contact/email/recipient_email" xsi:type="string">1</item>
+            </argument>
+        </arguments>
+    </type>
+</config>
diff --git a/app/code/Magento/Cron/Console/Command/CronInstallCommand.php b/app/code/Magento/Cron/Console/Command/CronInstallCommand.php
new file mode 100644
index 0000000000000000000000000000000000000000..2835244599d38943fea5b2162814bbd6b9edb32e
--- /dev/null
+++ b/app/code/Magento/Cron/Console/Command/CronInstallCommand.php
@@ -0,0 +1,79 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Cron\Console\Command;
+
+use Magento\Framework\Crontab\CrontabManagerInterface;
+use Magento\Framework\Crontab\TasksProviderInterface;
+use Magento\Framework\Exception\LocalizedException;
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+use Magento\Framework\Console\Cli;
+use Symfony\Component\Console\Input\InputOption;
+
+/**
+ * CronInstallCommand installs Magento cron tasks
+ */
+class CronInstallCommand extends Command
+{
+    /**
+     * @var CrontabManagerInterface
+     */
+    private $crontabManager;
+
+    /**
+     * @var TasksProviderInterface
+     */
+    private $tasksProvider;
+
+    /**
+     * @param CrontabManagerInterface $crontabManager
+     * @param TasksProviderInterface $tasksProvider
+     */
+    public function __construct(
+        CrontabManagerInterface $crontabManager,
+        TasksProviderInterface $tasksProvider
+    ) {
+        $this->crontabManager = $crontabManager;
+        $this->tasksProvider = $tasksProvider;
+
+        parent::__construct();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function configure()
+    {
+        $this->setName('cron:install')
+            ->setDescription('Generates and installs crontab for current user')
+            ->addOption('force', 'f', InputOption::VALUE_NONE, 'Force install tasks');
+
+        parent::configure();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function execute(InputInterface $input, OutputInterface $output)
+    {
+        if ($this->crontabManager->getTasks() && !$input->getOption('force')) {
+            $output->writeln('<error>Crontab has already been generated and saved</error>');
+            return Cli::RETURN_FAILURE;
+        }
+
+        try {
+            $this->crontabManager->saveTasks($this->tasksProvider->getTasks());
+        } catch (LocalizedException $e) {
+            $output->writeln('<error>' . $e->getMessage() . '</error>');
+            return Cli::RETURN_FAILURE;
+        }
+
+        $output->writeln('<info>Crontab has been generated and saved</info>');
+
+        return Cli::RETURN_SUCCESS;
+    }
+}
diff --git a/app/code/Magento/Cron/Console/Command/CronRemoveCommand.php b/app/code/Magento/Cron/Console/Command/CronRemoveCommand.php
new file mode 100644
index 0000000000000000000000000000000000000000..11c666a556f899e9d7c6358c09291ee9df904998
--- /dev/null
+++ b/app/code/Magento/Cron/Console/Command/CronRemoveCommand.php
@@ -0,0 +1,62 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Cron\Console\Command;
+
+use Magento\Framework\Crontab\CrontabManagerInterface;
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+use Magento\Framework\Console\Cli;
+use Magento\Framework\Exception\LocalizedException;
+
+/**
+ * CronRemoveCommand removes Magento cron tasks
+ */
+class CronRemoveCommand extends Command
+{
+    /**
+     * @var CrontabManagerInterface
+     */
+    private $crontabManager;
+
+    /**
+     * @param CrontabManagerInterface $crontabManager
+     */
+    public function __construct(CrontabManagerInterface $crontabManager)
+    {
+        $this->crontabManager = $crontabManager;
+
+        parent::__construct();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function configure()
+    {
+        $this->setName('cron:remove')
+            ->setDescription('Removes tasks from crontab');
+
+        parent::configure();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function execute(InputInterface $input, OutputInterface $output)
+    {
+        try {
+            $this->crontabManager->removeTasks();
+        } catch (LocalizedException $e) {
+            $output->writeln('<error>' . $e->getMessage() . '</error>');
+            return Cli::RETURN_FAILURE;
+        }
+
+        $output->writeln('<info>Magento cron tasks have been removed</info>');
+
+        return Cli::RETURN_SUCCESS;
+    }
+}
diff --git a/app/code/Magento/Cron/Test/Unit/Console/Command/CronInstallCommandTest.php b/app/code/Magento/Cron/Test/Unit/Console/Command/CronInstallCommandTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..09949cf78dc8f267fe2bb668d91f2b28032ed8c1
--- /dev/null
+++ b/app/code/Magento/Cron/Test/Unit/Console/Command/CronInstallCommandTest.php
@@ -0,0 +1,126 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Cron\Test\Unit\Console\Command;
+
+use Symfony\Component\Console\Tester\CommandTester;
+use Magento\Cron\Console\Command\CronInstallCommand;
+use Magento\Framework\Crontab\CrontabManagerInterface;
+use Magento\Framework\Crontab\TasksProviderInterface;
+use Magento\Framework\Console\Cli;
+use Magento\Framework\Exception\LocalizedException;
+use Magento\Framework\Phrase;
+
+class CronInstallCommandTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var CrontabManagerInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $crontabManagerMock;
+
+    /**
+     * @var TasksProviderInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $tasksProviderMock;
+
+    /**
+     * @var CommandTester
+     */
+    private $commandTester;
+
+    /**
+     * @return void
+     */
+    protected function setUp()
+    {
+        $this->crontabManagerMock = $this->getMockBuilder(CrontabManagerInterface::class)
+            ->getMockForAbstractClass();
+        $this->tasksProviderMock = $this->getMockBuilder(TasksProviderInterface::class)
+            ->getMockForAbstractClass();
+
+        $this->commandTester = new CommandTester(
+            new CronInstallCommand($this->crontabManagerMock, $this->tasksProviderMock)
+        );
+    }
+
+    /**
+     * @return void
+     */
+    public function testExecuteAlreadyInstalled()
+    {
+        $this->crontabManagerMock->expects($this->once())
+            ->method('getTasks')
+            ->willReturn([['* * * * * /bin/php /var/run.php']]);
+        $this->tasksProviderMock->expects($this->never())
+            ->method('getTasks');
+
+        $this->commandTester->execute([]);
+        $this->assertEquals(
+            'Crontab has already been generated and saved' . PHP_EOL,
+            $this->commandTester->getDisplay()
+        );
+        $this->assertEquals(Cli::RETURN_FAILURE, $this->commandTester->getStatusCode());
+    }
+
+    /**
+     * @return void
+     */
+    public function testExecuteWithException()
+    {
+        $this->crontabManagerMock->expects($this->once())
+            ->method('getTasks')
+            ->willReturn([]);
+        $this->tasksProviderMock->expects($this->once())
+            ->method('getTasks')
+            ->willReturn([]);
+        $this->crontabManagerMock->expects($this->once())
+            ->method('saveTasks')
+            ->willThrowException(new LocalizedException(new Phrase('Some error')));
+
+        $this->commandTester->execute([]);
+        $this->assertEquals(
+            'Some error' . PHP_EOL,
+            $this->commandTester->getDisplay()
+        );
+        $this->assertEquals(Cli::RETURN_FAILURE, $this->commandTester->getStatusCode());
+    }
+
+    /**
+     * @param array $existingTasks
+     * @param array $options
+     * @return void
+     * @dataProvider executeDataProvider
+     */
+    public function testExecute($existingTasks, $options)
+    {
+        $this->crontabManagerMock->expects($this->once())
+            ->method('getTasks')
+            ->willReturn($existingTasks);
+        $this->tasksProviderMock->expects($this->once())
+            ->method('getTasks')
+            ->willReturn([]);
+        $this->crontabManagerMock->expects($this->once())
+            ->method('saveTasks')
+            ->with([]);
+
+        $this->commandTester->execute($options);
+        $this->assertEquals(
+            'Crontab has been generated and saved' . PHP_EOL,
+            $this->commandTester->getDisplay()
+        );
+        $this->assertEquals(Cli::RETURN_SUCCESS, $this->commandTester->getStatusCode());
+    }
+
+    /**
+     * @return array
+     */
+    public function executeDataProvider()
+    {
+        return [
+            ['existingTasks' => [], 'options' => []],
+            ['existingTasks' => ['* * * * * /bin/php /var/www/run.php'], 'options' => ['-f'=> true]]
+        ];
+    }
+}
diff --git a/app/code/Magento/Cron/Test/Unit/Console/Command/CronRemoveCommandTest.php b/app/code/Magento/Cron/Test/Unit/Console/Command/CronRemoveCommandTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..cd017b26d758578482bffa137a3f221650619bae
--- /dev/null
+++ b/app/code/Magento/Cron/Test/Unit/Console/Command/CronRemoveCommandTest.php
@@ -0,0 +1,72 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Cron\Test\Unit\Console\Command;
+
+use Symfony\Component\Console\Tester\CommandTester;
+use Magento\Cron\Console\Command\CronRemoveCommand;
+use Magento\Framework\Crontab\CrontabManagerInterface;
+use Magento\Framework\Console\Cli;
+use Magento\Framework\Exception\LocalizedException;
+use Magento\Framework\Phrase;
+
+class CronRemoveCommandTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var CrontabManagerInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $crontabManagerMock;
+
+    /**
+     * @var CommandTester
+     */
+    private $commandTester;
+
+    /**
+     * @return void
+     */
+    protected function setUp()
+    {
+        $this->crontabManagerMock = $this->getMockBuilder(CrontabManagerInterface::class)
+            ->getMockForAbstractClass();
+
+        $this->commandTester = new CommandTester(
+            new CronRemoveCommand($this->crontabManagerMock)
+        );
+    }
+
+    /**
+     * @return void
+     */
+    public function testExecute()
+    {
+        $this->crontabManagerMock->expects($this->once())
+            ->method('RemoveTasks');
+
+        $this->commandTester->execute([]);
+        $this->assertEquals(
+            'Magento cron tasks have been removed' . PHP_EOL,
+            $this->commandTester->getDisplay()
+        );
+        $this->assertEquals(Cli::RETURN_SUCCESS, $this->commandTester->getStatusCode());
+    }
+
+    /**
+     * @return void
+     */
+    public function testExecuteFailed()
+    {
+        $this->crontabManagerMock->expects($this->once())
+            ->method('RemoveTasks')
+            ->willThrowException(new LocalizedException(new Phrase('Some error')));
+
+        $this->commandTester->execute([]);
+        $this->assertEquals(
+            'Some error' . PHP_EOL,
+            $this->commandTester->getDisplay()
+        );
+        $this->assertEquals(Cli::RETURN_FAILURE, $this->commandTester->getStatusCode());
+    }
+}
diff --git a/app/code/Magento/Cron/etc/di.xml b/app/code/Magento/Cron/etc/di.xml
index d5624e96765c58bd699eebc29c14c7fe76037b7a..6abc9096f24012309a3b56cb0b84912d3a8d1e26 100644
--- a/app/code/Magento/Cron/etc/di.xml
+++ b/app/code/Magento/Cron/etc/di.xml
@@ -8,6 +8,8 @@
 <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
     <preference for="Magento\Cron\Model\ConfigInterface" type="Magento\Cron\Model\Config" />
     <preference for="Magento\Framework\Shell\CommandRendererInterface" type="Magento\Framework\Shell\CommandRenderer" />
+    <preference for="Magento\Framework\Crontab\CrontabManagerInterface" type="Magento\Framework\Crontab\CrontabManager" />
+    <preference for="Magento\Framework\Crontab\TasksProviderInterface" type="Magento\Framework\Crontab\TasksProvider" />
     <type name="Magento\Config\Model\Config\Structure\Converter">
         <plugin name="cron_backend_config_structure_converter_plugin" type="Magento\Cron\Model\Backend\Config\Structure\Converter" />
     </type>
@@ -28,6 +30,8 @@
         <arguments>
             <argument name="commands" xsi:type="array">
                 <item name="cronCommand" xsi:type="object">Magento\Cron\Console\Command\CronCommand</item>
+                <item name="cronInstall" xsi:type="object">Magento\Cron\Console\Command\CronInstallCommand</item>
+                <item name="cronRemove" xsi:type="object">Magento\Cron\Console\Command\CronRemoveCommand</item>
             </argument>
         </arguments>
     </type>
@@ -38,4 +42,24 @@
             </argument>
         </arguments>
     </type>
+    <type name="Magento\Framework\Crontab\CrontabManager">
+        <arguments>
+            <argument name="shell" xsi:type="object">Magento\Framework\App\Shell</argument>
+        </arguments>
+    </type>
+    <type name="Magento\Framework\Crontab\TasksProviderInterface">
+        <arguments>
+            <argument name="tasks" xsi:type="array">
+                <item name="cronMagento" xsi:type="array">
+                    <item name="command" xsi:type="string">{magentoRoot}bin/magento cron:run | grep -v "Ran jobs by schedule" >> {magentoLog}magento.cron.log</item>
+                </item>
+                <item name="cronUpdate" xsi:type="array">
+                    <item name="command" xsi:type="string">{magentoRoot}update/cron.php >> {magentoLog}update.cron.log</item>
+                </item>
+                <item name="cronSetup" xsi:type="array">
+                    <item name="command" xsi:type="string">{magentoRoot}bin/magento setup:cron:run >> {magentoLog}setup.cron.log</item>
+                </item>
+            </argument>
+        </arguments>
+    </type>
 </config>
diff --git a/app/code/Magento/Deploy/Console/Command/App/ApplicationDumpCommand.php b/app/code/Magento/Deploy/Console/Command/App/ApplicationDumpCommand.php
index b4e4fef8fb2f941eaa56cc33b2df65f783fa0413..40b262e3e4f5176f87d306be8babb5cfb2ba1898 100644
--- a/app/code/Magento/Deploy/Console/Command/App/ApplicationDumpCommand.php
+++ b/app/code/Magento/Deploy/Console/Command/App/ApplicationDumpCommand.php
@@ -5,7 +5,7 @@
  */
 namespace Magento\Deploy\Console\Command\App;
 
-use Magento\Framework\App\Config\Reader\Source\SourceInterface;
+use Magento\Framework\App\Config\ConfigSourceInterface;
 use Magento\Framework\App\DeploymentConfig\Writer;
 use Magento\Framework\Config\File\ConfigFilePool;
 use Magento\Framework\Console\Cli;
@@ -24,7 +24,7 @@ class ApplicationDumpCommand extends Command
     private $writer;
 
     /**
-     * @var SourceInterface[]
+     * @var ConfigSourceInterface[]
      */
     private $sources;
 
@@ -64,20 +64,29 @@ class ApplicationDumpCommand extends Command
     protected function execute(InputInterface $input, OutputInterface $output)
     {
         $dump = [];
+        $comments = [];
         foreach ($this->sources as $sourceData) {
-            /** @var SourceInterface $source */
+            /** @var ConfigSourceInterface $source */
             $source = $sourceData['source'];
             $namespace = $sourceData['namespace'];
             $dump[$namespace] = $source->get();
+            if (!empty($sourceData['comment'])) {
+                $comments[$namespace] = is_string($sourceData['comment'])
+                    ? $sourceData['comment']
+                    : $sourceData['comment']->get();
+            }
         }
-
         $this->writer
             ->saveConfig(
                 [ConfigFilePool::APP_CONFIG => $dump],
                 true,
-                ConfigFilePool::LOCAL
+                ConfigFilePool::LOCAL,
+                $comments
             );
+        if (!empty($comments)) {
+            $output->writeln($comments);
+        }
         $output->writeln('<info>Done.</info>');
-        return  Cli::RETURN_SUCCESS;
+        return Cli::RETURN_SUCCESS;
     }
 }
diff --git a/app/code/Magento/Developer/etc/di.xml b/app/code/Magento/Developer/etc/di.xml
index 80433242853b85378a31b50133716e8399084c29..2362aaa0780debfcdc0e55b270ed733dc1237e5b 100644
--- a/app/code/Magento/Developer/etc/di.xml
+++ b/app/code/Magento/Developer/etc/di.xml
@@ -252,4 +252,11 @@
             </argument>
         </arguments>
     </type>
+    <type name="Magento\Config\Model\Config\Export\ExcludeList">
+        <arguments>
+            <argument name="configs" xsi:type="array">
+                <item name="dev/restrict/allow_ips" xsi:type="string">1</item>
+            </argument>
+        </arguments>
+    </type>
 </config>
diff --git a/app/code/Magento/Dhl/etc/di.xml b/app/code/Magento/Dhl/etc/di.xml
index a215c2e82182535e14e659d20cf1f7db2317e915..cbe795791147cc03de7eb060c84108c6cbeb53fa 100644
--- a/app/code/Magento/Dhl/etc/di.xml
+++ b/app/code/Magento/Dhl/etc/di.xml
@@ -9,4 +9,13 @@
     <type name="Magento\Checkout\Block\Cart\LayoutProcessor">
         <plugin name="checkout_cart_shipping_dhl" type="Magento\Dhl\Model\Plugin\Checkout\Block\Cart\Shipping"/>
     </type>
+    <type name="Magento\Config\Model\Config\Export\ExcludeList">
+        <arguments>
+            <argument name="configs" xsi:type="array">
+                <item name="carriers/dhl/id" xsi:type="string">1</item>
+                <item name="carriers/dhl/password" xsi:type="string">1</item>
+                <item name="carriers/dhl/account" xsi:type="string">1</item>
+            </argument>
+        </arguments>
+    </type>
 </config>
diff --git a/app/code/Magento/Directory/etc/di.xml b/app/code/Magento/Directory/etc/di.xml
index f868197e60593cb59292a060b473f1d87d55820e..b4da40d119fe3e2269d1d33f47c5e2009a3379b1 100644
--- a/app/code/Magento/Directory/etc/di.xml
+++ b/app/code/Magento/Directory/etc/di.xml
@@ -47,4 +47,12 @@
     <preference for="Magento\Directory\Api\CountryInformationAcquirerInterface" type="Magento\Directory\Model\CountryInformationAcquirer" />
     <preference for="Magento\Directory\Api\Data\CountryInformationInterface" type="Magento\Directory\Model\Data\CountryInformation" />
     <preference for="Magento\Directory\Api\Data\RegionInformationInterface" type="Magento\Directory\Model\Data\RegionInformation" />
+
+    <type name="Magento\Config\Model\Config\Export\ExcludeList">
+        <arguments>
+            <argument name="configs" xsi:type="array">
+                <item name="currency/import/error_email" xsi:type="string">1</item>
+            </argument>
+        </arguments>
+    </type>
 </config>
diff --git a/app/code/Magento/NewRelicReporting/etc/di.xml b/app/code/Magento/NewRelicReporting/etc/di.xml
index caabf89be1871b05d55040d34f3b4b0e5b7a9120..6e3a24be91982e9f14b54228144157165094b1a5 100644
--- a/app/code/Magento/NewRelicReporting/etc/di.xml
+++ b/app/code/Magento/NewRelicReporting/etc/di.xml
@@ -12,4 +12,14 @@
             <argument name="fullModuleList" xsi:type="object">Magento\Framework\Module\FullModuleList</argument>
         </arguments>
     </type>
+    <type name="Magento\Config\Model\Config\Export\ExcludeList">
+        <arguments>
+            <argument name="configs" xsi:type="array">
+                <item name="newrelicreporting/general/account_id" xsi:type="string">1</item>
+                <item name="newrelicreporting/general/app_id" xsi:type="string">1</item>
+                <item name="newrelicreporting/general/api" xsi:type="string">1</item>
+                <item name="newrelicreporting/general/insights_insert_key" xsi:type="string">1</item>
+            </argument>
+        </arguments>
+    </type>
 </config>
diff --git a/app/code/Magento/Paypal/etc/di.xml b/app/code/Magento/Paypal/etc/di.xml
index c5cbdbdc51331c95a269581a97a8ee3a94c25e0f..940876451fd591984937faeae1deef5ac1e4ea60 100644
--- a/app/code/Magento/Paypal/etc/di.xml
+++ b/app/code/Magento/Paypal/etc/di.xml
@@ -182,4 +182,32 @@
             <argument name="paymentTokenFactory" xsi:type="object">Magento\Vault\Model\CreditCardTokenFactory</argument>
         </arguments>
     </type>
+    <type name="Magento\Config\Model\Config\Export\ExcludeList">
+        <arguments>
+            <argument name="configs" xsi:type="array">
+                <item name="paypal/general/business_account" xsi:type="string">1</item>
+                <item name="paypal/wpp/api_password" xsi:type="string">1</item>
+                <item name="paypal/wpp/api_signature" xsi:type="string">1</item>
+                <item name="paypal/wpp/api_username" xsi:type="string">1</item>
+                <item name="paypal/wpp/api_cert" xsi:type="string">1</item>
+                <item name="paypal/wpp/proxy_host" xsi:type="string">1</item>
+                <item name="paypal/wpp/proxy_port" xsi:type="string">1</item>
+                <item name="payment/paypal_express/merchant_id" xsi:type="string">1</item>
+                <item name="payment/paypal_express_bml/publisher_id" xsi:type="string">1</item>
+                <item name="paypal/fetch_reports/ftp_password" xsi:type="string">1</item>
+                <item name="paypal/fetch_reports/ftp_login" xsi:type="string">1</item>
+                <item name="paypal/fetch_reports/ftp_path" xsi:type="string">1</item>
+                <item name="paypal/fetch_reports/ftp_ip" xsi:type="string">1</item>
+                <item name="payment/payflow_advanced/user" xsi:type="string">1</item>
+                <item name="payment/payflow_advanced/pwd" xsi:type="string">1</item>
+                <item name="payment/payflow_link/user" xsi:type="string">1</item>
+                <item name="payment/payflow_link/pwd" xsi:type="string">1</item>
+                <item name="payment/payflowpro/user" xsi:type="string">1</item>
+                <item name="payment/payflowpro/pwd" xsi:type="string">1</item>
+                <item name="payment/payflowpro/partner" xsi:type="string">1</item>
+                <item name="payment/payflowpro/proxy_host" xsi:type="string">1</item>
+                <item name="payment/payflowpro/proxy_port" xsi:type="string">1</item>
+            </argument>
+        </arguments>
+    </type>
 </config>
diff --git a/app/code/Magento/ProductAlert/composer.json b/app/code/Magento/ProductAlert/composer.json
index 9c63c6958a465852ea3148cab659102880b07630..4ed6a998b084eb25a93ec939ebe20c70c6a4e5c2 100644
--- a/app/code/Magento/ProductAlert/composer.json
+++ b/app/code/Magento/ProductAlert/composer.json
@@ -9,6 +9,9 @@
         "magento/module-customer": "100.2.*",
         "magento/framework": "100.2.*"
     },
+    "suggest": {
+        "magento/module-config": "100.2.*"
+    },
     "type": "magento2-module",
     "version": "100.2.0-dev",
     "license": [
diff --git a/app/code/Magento/ProductAlert/etc/di.xml b/app/code/Magento/ProductAlert/etc/di.xml
index 734b0f6695778bc38744f185da7b58eb0faf50a1..d5c81adce46f0c66f10d5b60226f0525e3fd4c54 100644
--- a/app/code/Magento/ProductAlert/etc/di.xml
+++ b/app/code/Magento/ProductAlert/etc/di.xml
@@ -13,4 +13,12 @@
             </argument>
         </arguments>
     </type>
+
+    <type name="Magento\Config\Model\Config\Export\ExcludeList">
+        <arguments>
+            <argument name="configs" xsi:type="array">
+                <item name="catalog/productalert_cron/error_email" xsi:type="string">1</item>
+            </argument>
+        </arguments>
+    </type>
 </config>
diff --git a/app/code/Magento/ProductVideo/composer.json b/app/code/Magento/ProductVideo/composer.json
index 08d21e4c2abbfb167aed2ca24c0ba012d6b2e8c8..726104c084677dfcb69e3721adfe63f4d71a7ecd 100644
--- a/app/code/Magento/ProductVideo/composer.json
+++ b/app/code/Magento/ProductVideo/composer.json
@@ -12,7 +12,8 @@
         "magento/magento-composer-installer": "*"
     },
     "suggest": {
-        "magento/module-customer": "100.2.*"
+        "magento/module-customer": "100.2.*",
+        "magento/module-config": "100.2.*"
     },
     "type": "magento2-module",
     "version": "100.2.0-dev",
diff --git a/app/code/Magento/ProductVideo/etc/di.xml b/app/code/Magento/ProductVideo/etc/di.xml
index 7242a9d48ce1e3c0da66a3f4d5953cda705132cd..9aad01caaf72b65bc1a49951cb84c2f28a2de5e0 100644
--- a/app/code/Magento/ProductVideo/etc/di.xml
+++ b/app/code/Magento/ProductVideo/etc/di.xml
@@ -46,4 +46,11 @@
     <type name="Magento\Catalog\Model\ResourceModel\Product\Gallery">
         <plugin name="external_video_media_resource_backend" type="Magento\ProductVideo\Model\Plugin\ExternalVideoResourceBackend" />
     </type>
+    <type name="Magento\Config\Model\Config\Export\ExcludeList">
+        <arguments>
+            <argument name="configs" xsi:type="array">
+                <item name="catalog/product_video/youtube_api_key" xsi:type="string">1</item>
+            </argument>
+        </arguments>
+    </type>
 </config>
diff --git a/app/code/Magento/Sales/etc/di.xml b/app/code/Magento/Sales/etc/di.xml
index 4e2487d9dcada2eaf224f8cc30f65fc8fa4a4fc8..eb392fc83d8580e0cea6803a43c5f1a44f27fd58 100644
--- a/app/code/Magento/Sales/etc/di.xml
+++ b/app/code/Magento/Sales/etc/di.xml
@@ -956,4 +956,18 @@
     <type name="Magento\Sales\Model\ResourceModel\Order\Handler\Address">
         <plugin name="addressUpdate" type="Magento\Sales\Model\Order\Invoice\Plugin\AddressUpdate"/>
     </type>
+    <type name="Magento\Config\Model\Config\Export\ExcludeList">
+        <arguments>
+            <argument name="configs" xsi:type="array">
+                <item name="sales_email/order/copy_to" xsi:type="string">1</item>
+                <item name="sales_email/order_comment/copy_to" xsi:type="string">1</item>
+                <item name="sales_email/invoice/copy_to" xsi:type="string">1</item>
+                <item name="sales_email/invoice_comment/copy_to" xsi:type="string">1</item>
+                <item name="sales_email/shipment/copy_to" xsi:type="string">1</item>
+                <item name="sales_email/shipment_comment/copy_to" xsi:type="string">1</item>
+                <item name="sales_email/creditmemo/copy_to" xsi:type="string">1</item>
+                <item name="sales_email/creditmemo_comment/copy_to" xsi:type="string">1</item>
+            </argument>
+        </arguments>
+    </type>
 </config>
diff --git a/app/code/Magento/Shipping/composer.json b/app/code/Magento/Shipping/composer.json
index 03f51bbd95e0ff5f65b88e565cfbe77102a44760..6f3f5c3925fa5431446d0c40ccf1e4bf902afede 100644
--- a/app/code/Magento/Shipping/composer.json
+++ b/app/code/Magento/Shipping/composer.json
@@ -21,7 +21,8 @@
     },
     "suggest": {
         "magento/module-fedex": "100.2.*",
-        "magento/module-ups": "100.2.*"
+        "magento/module-ups": "100.2.*",
+        "magento/module-config": "100.2.*"
     },
     "type": "magento2-module",
     "version": "100.2.0-dev",
diff --git a/app/code/Magento/Shipping/etc/di.xml b/app/code/Magento/Shipping/etc/di.xml
index 1fe0657bf1337a1712c2aef7b614db6a45ea853f..44e138d6c9ac6f5c102727458edfe4d34fe4a9c5 100644
--- a/app/code/Magento/Shipping/etc/di.xml
+++ b/app/code/Magento/Shipping/etc/di.xml
@@ -9,4 +9,16 @@
     <preference for="Magento\Quote\Model\Quote\Address\RateCollectorInterface" type="Magento\Shipping\Model\Shipping" />
     <preference for="Magento\Shipping\Model\CarrierFactoryInterface" type="Magento\Shipping\Model\CarrierFactory" />
     <preference for="Magento\Shipping\Model\Carrier\Source\GenericInterface" type="\Magento\Shipping\Model\Carrier\Source\GenericDefault" />
+    <type name="Magento\Config\Model\Config\Export\ExcludeList">
+        <arguments>
+            <argument name="configs" xsi:type="array">
+                <item name="shipping/origin/country_id" xsi:type="string">1</item>
+                <item name="shipping/origin/region_id" xsi:type="string">1</item>
+                <item name="shipping/origin/postcode" xsi:type="string">1</item>
+                <item name="shipping/origin/city" xsi:type="string">1</item>
+                <item name="shipping/origin/street_line1" xsi:type="string">1</item>
+                <item name="shipping/origin/street_line2" xsi:type="string">1</item>
+            </argument>
+        </arguments>
+    </type>
 </config>
diff --git a/app/code/Magento/Sitemap/composer.json b/app/code/Magento/Sitemap/composer.json
index 9f556178fc2cccfd070c272a89164e438f1d33e8..307691a67d2e24617f381803d8a3f96a2c010d1b 100644
--- a/app/code/Magento/Sitemap/composer.json
+++ b/app/code/Magento/Sitemap/composer.json
@@ -12,6 +12,9 @@
         "magento/module-media-storage": "100.2.*",
         "magento/framework": "100.2.*"
     },
+    "suggest": {
+        "magento/module-config": "100.2.*"
+    },
     "type": "magento2-module",
     "version": "100.2.0-dev",
     "license": [
diff --git a/app/code/Magento/Sitemap/etc/di.xml b/app/code/Magento/Sitemap/etc/di.xml
index 7ce1fdee7b5b6a1de7947da82c2a1b93bf470bfc..dfe34a25fb7ba37766ae0247194df1cc85bdee28 100644
--- a/app/code/Magento/Sitemap/etc/di.xml
+++ b/app/code/Magento/Sitemap/etc/di.xml
@@ -11,4 +11,11 @@
             <argument name="resource" xsi:type="object">Magento\Sitemap\Model\ResourceModel\Sitemap</argument>
         </arguments>
     </type>
+    <type name="Magento\Config\Model\Config\Export\ExcludeList">
+        <arguments>
+            <argument name="configs" xsi:type="array">
+                <item name="sitemap/generate/error_email" xsi:type="string">1</item>
+            </argument>
+        </arguments>
+    </type>
 </config>
diff --git a/app/code/Magento/Theme/Model/Design/Config/DataProvider.php b/app/code/Magento/Theme/Model/Design/Config/DataProvider.php
index c433b02fab240d736637bf41b571c2eb75d193bc..977295c1f80c466899284f0e8e18c373a6007445 100644
--- a/app/code/Magento/Theme/Model/Design/Config/DataProvider.php
+++ b/app/code/Magento/Theme/Model/Design/Config/DataProvider.php
@@ -5,9 +5,13 @@
  */
 namespace Magento\Theme\Model\Design\Config;
 
+use Magento\Framework\App\Config\ScopeCodeResolver;
+use Magento\Framework\App\ObjectManager;
 use Magento\Theme\Model\ResourceModel\Design\Config\Collection;
 use Magento\Theme\Model\ResourceModel\Design\Config\CollectionFactory;
 use Magento\Ui\DataProvider\AbstractDataProvider;
+use Magento\Config\Model\Config\Reader\Source\Deployed\SettingChecker;
+use Magento\Framework\App\RequestInterface;
 
 class DataProvider extends AbstractDataProvider
 {
@@ -31,6 +35,21 @@ class DataProvider extends AbstractDataProvider
      */
     private $metadataLoader;
 
+    /**
+     * @var SettingChecker
+     */
+    private $settingChecker;
+
+    /**
+     * @var RequestInterface
+     */
+    private $request;
+
+    /**
+     * @var ScopeCodeResolver
+     */
+    private $scopeCodeResolver;
+
     /**
      * @param string $name
      * @param string $primaryFieldName
@@ -78,4 +97,84 @@ class DataProvider extends AbstractDataProvider
         $this->loadedData = $this->dataLoader->getData();
         return $this->loadedData;
     }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getMeta()
+    {
+        $meta = parent::getMeta();
+        if (!isset($meta['other_settings']['children'])) {
+            return $meta;
+        }
+
+        $request = $this->getRequest()->getParams();
+        if (!isset($request['scope'])) {
+            return $meta;
+        }
+
+        $scope = $request['scope'];
+        $scopeCode = $this->getScopeCodeResolver()->resolve(
+            $scope,
+            isset($request['scope_id']) ? $request['scope_id'] : null
+        );
+
+        foreach ($meta['other_settings']['children'] as $settingGroupName => &$settingGroup) {
+            foreach ($settingGroup['children'] as $fieldName => &$field) {
+                $path = sprintf(
+                    'design/%s/%s',
+                    $settingGroupName,
+                    preg_replace('/^' . $settingGroupName . '_/', '', $fieldName)
+                );
+                $isReadOnly = $this->getSettingChecker()->isReadOnly(
+                    $path,
+                    $scope,
+                    $scopeCode
+                );
+
+                if ($isReadOnly) {
+                    $field['arguments']['data']['config']['disabled'] = true;
+                    $field['arguments']['data']['config']['is_disable_inheritance'] = true;
+                }
+            }
+        }
+
+        return $meta;
+    }
+
+    /**
+     * @deprecated
+     * @return ScopeCodeResolver
+     */
+    private function getScopeCodeResolver()
+    {
+        if ($this->scopeCodeResolver === null) {
+            $this->scopeCodeResolver = ObjectManager::getInstance()->get(ScopeCodeResolver::class);
+        }
+        return $this->scopeCodeResolver;
+    }
+
+    /**
+     * @deprecated
+     * @return SettingChecker
+     */
+    private function getSettingChecker()
+    {
+        if ($this->settingChecker === null) {
+            $this->settingChecker = ObjectManager::getInstance()->get(SettingChecker::class);
+        }
+        return $this->settingChecker;
+    }
+
+    /**
+     * @deprecated
+     * @return RequestInterface
+     */
+    private function getRequest()
+    {
+        if ($this->request === null) {
+            $this->request = ObjectManager::getInstance()->get(RequestInterface::class);
+        }
+        return $this->request;
+    }
 }
diff --git a/app/code/Magento/Theme/Test/Unit/Model/Design/Config/DataProviderTest.php b/app/code/Magento/Theme/Test/Unit/Model/Design/Config/DataProviderTest.php
index 3ba61da79b5ca00073a14e11e7ab14c46b7af031..a5db6156efea32c56009620d9a8f2110f070bfe1 100644
--- a/app/code/Magento/Theme/Test/Unit/Model/Design/Config/DataProviderTest.php
+++ b/app/code/Magento/Theme/Test/Unit/Model/Design/Config/DataProviderTest.php
@@ -5,11 +5,18 @@
  */
 namespace Magento\Theme\Test\Unit\Model\Design\Config;
 
+use Magento\Config\Model\Config\Reader\Source\Deployed\SettingChecker;
+use Magento\Framework\App\Config\ScopeCodeResolver;
+use Magento\Framework\App\RequestInterface;
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
 use Magento\Theme\Model\Design\Config\DataLoader;
 use Magento\Theme\Model\Design\Config\DataProvider;
 use Magento\Theme\Model\Design\Config\MetadataLoader;
 use Magento\Theme\Model\ResourceModel\Design\Config\Collection;
 
+/**
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ */
 class DataProviderTest extends \PHPUnit_Framework_TestCase
 {
     /**
@@ -32,8 +39,29 @@ class DataProviderTest extends \PHPUnit_Framework_TestCase
      */
     protected $collection;
 
+    /**
+     * @var ObjectManager
+     */
+    private $objectManager;
+
+    /**
+     * @var RequestInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $requestMock;
+
+    /**
+     * @var ScopeCodeResolver|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $scopeCodeResolverMock;
+
+    /**
+     * @var SettingChecker|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $settingCheckerMock;
+
     protected function setUp()
     {
+        $this->objectManager = new ObjectManager($this);
         $this->dataLoader = $this->getMockBuilder(\Magento\Theme\Model\Design\Config\DataProvider\DataLoader::class)
             ->disableOriginalConstructor()
             ->getMock();
@@ -56,6 +84,16 @@ class DataProviderTest extends \PHPUnit_Framework_TestCase
             ->method('create')
             ->willReturn($this->collection);
 
+        $this->requestMock = $this->getMockBuilder(RequestInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->scopeCodeResolverMock = $this->getMockBuilder(ScopeCodeResolver::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->settingCheckerMock = $this->getMockBuilder(SettingChecker::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
         $this->model = new DataProvider(
             'scope',
             'scope',
@@ -64,6 +102,21 @@ class DataProviderTest extends \PHPUnit_Framework_TestCase
             $this->metadataLoader,
             $collectionFactory
         );
+        $this->objectManager->setBackwardCompatibleProperty(
+            $this->model,
+            'request',
+            $this->requestMock
+        );
+        $this->objectManager->setBackwardCompatibleProperty(
+            $this->model,
+            'scopeCodeResolver',
+            $this->scopeCodeResolverMock
+        );
+        $this->objectManager->setBackwardCompatibleProperty(
+            $this->model,
+            'settingChecker',
+            $this->settingCheckerMock
+        );
     }
 
     public function testGetData()
@@ -78,4 +131,119 @@ class DataProviderTest extends \PHPUnit_Framework_TestCase
 
         $this->assertEquals($data, $this->model->getData());
     }
+
+    /**
+     * @param array $inputMeta
+     * @param array $expectedMeta
+     * @param array $request
+     * @dataProvider getMetaDataProvider
+     */
+    public function testGetMeta(array $inputMeta, array $expectedMeta, array $request)
+    {
+        $this->requestMock->expects($this->any())
+            ->method('getParams')
+            ->willReturn($request);
+        $this->scopeCodeResolverMock->expects($this->any())
+            ->method('resolve')
+            ->with('stores', 1)
+            ->willReturn('default');
+        $this->settingCheckerMock->expects($this->any())
+            ->method('isReadOnly')
+            ->withConsecutive(
+                ['design/head/welcome', 'stores', 'default'],
+                ['design/head/logo', 'stores', 'default'],
+                ['design/head/head', 'stores', 'default']
+            )
+            ->willReturnOnConsecutiveCalls(
+                true,
+                false,
+                true
+            );
+
+        $this->objectManager->setBackwardCompatibleProperty(
+            $this->model,
+            'meta',
+            $inputMeta
+        );
+
+        $this->assertSame($expectedMeta, $this->model->getMeta());
+    }
+
+    /**
+     * @return array
+     */
+    public function getMetaDataProvider()
+    {
+        return [
+            [
+                [
+                    'option1'
+                ],
+                [
+                    'option1'
+                ],
+                [
+                    'scope' => 'default'
+                ]
+            ],
+            [
+                [
+                    'other_settings' => [
+                        'children' => [
+                            'head' => [
+                                'children' => [
+                                    'head_welcome' => [
+
+                                    ],
+                                    'head_logo' => [
+
+                                    ],
+                                    'head_head' => [
+
+                                    ]
+                                ]
+                            ]
+                        ]
+                    ]
+                ],
+                [
+                    'other_settings' => [
+                        'children' => [
+                            'head' => [
+                                'children' => [
+                                    'head_welcome' => [
+                                        'arguments' => [
+                                            'data' => [
+                                                'config' => [
+                                                    'disabled' => true,
+                                                    'is_disable_inheritance' => true,
+                                                ]
+                                            ]
+                                        ]
+                                    ],
+                                    'head_logo' => [
+
+                                    ],
+                                    'head_head' => [
+                                        'arguments' => [
+                                            'data' => [
+                                                'config' => [
+                                                    'disabled' => true,
+                                                    'is_disable_inheritance' => true,
+                                                ]
+                                            ]
+                                        ]
+                                    ]
+                                ]
+                            ]
+                        ]
+                    ]
+                ],
+                [
+                    'scope' => 'stores',
+                    'scope_id' => 1
+                ]
+            ]
+        ];
+    }
 }
diff --git a/app/code/Magento/Ups/composer.json b/app/code/Magento/Ups/composer.json
index c20dd28ba88876a70c04ea49038b94f82d3d9b06..e3cf2bce1813a0d6625f0b5dce2ac4cf0d8b5640 100644
--- a/app/code/Magento/Ups/composer.json
+++ b/app/code/Magento/Ups/composer.json
@@ -12,6 +12,9 @@
         "magento/module-quote": "100.2.*",
         "magento/framework": "100.2.*"
     },
+    "suggest": {
+        "magento/module-config": "100.2.*"
+    },
     "type": "magento2-module",
     "version": "100.2.0-dev",
     "license": [
diff --git a/app/code/Magento/Ups/etc/di.xml b/app/code/Magento/Ups/etc/di.xml
new file mode 100644
index 0000000000000000000000000000000000000000..324349a82994fdadec4d4db33cdb66f28029b137
--- /dev/null
+++ b/app/code/Magento/Ups/etc/di.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0"?>
+<!--
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+-->
+<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
+    <type name="Magento\Config\Model\Config\Export\ExcludeList">
+        <arguments>
+            <argument name="configs" xsi:type="array">
+                <item name="carriers/ups/username" xsi:type="string">1</item>
+                <item name="carriers/ups/password" xsi:type="string">1</item>
+                <item name="carriers/ups/access_license_number" xsi:type="string">1</item>
+                <item name="carriers/ups/tracking_xml_url" xsi:type="string">1</item>
+                <item name="carriers/ups/gateway_xml_url" xsi:type="string">1</item>
+                <item name="carriers/ups/shipper_number" xsi:type="string">1</item>
+            </argument>
+        </arguments>
+    </type>
+</config>
diff --git a/app/code/Magento/Usps/etc/di.xml b/app/code/Magento/Usps/etc/di.xml
new file mode 100644
index 0000000000000000000000000000000000000000..450a24ad8b9f734ec85d1640ea1df8bf75e12225
--- /dev/null
+++ b/app/code/Magento/Usps/etc/di.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0"?>
+<!--
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+-->
+<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
+    <type name="Magento\Config\Model\Config\Export\ExcludeList">
+        <arguments>
+            <argument name="configs" xsi:type="array">
+                <item name="carriers/usps/userid" xsi:type="string">1</item>
+                <item name="carriers/usps/password" xsi:type="string">1</item>
+                <item name="carriers/usps/gateway_url" xsi:type="string">1</item>
+                <item name="carriers/usps/gateway_secure_url" xsi:type="string">1</item>
+            </argument>
+        </arguments>
+    </type>
+</config>
diff --git a/app/etc/di.xml b/app/etc/di.xml
index e9767eccb28114ffa66bc8bc84829d92b1620e99..1b347574f4b2a2d3f010cb9a712da6cd6c7dbec2 100755
--- a/app/etc/di.xml
+++ b/app/etc/di.xml
@@ -433,7 +433,7 @@
     </virtualType>
     <virtualType name="layoutObjectArgumentInterpreter" type="Magento\Framework\View\Layout\Argument\Interpreter\DataObject">
         <arguments>
-            <argument name="expectedClass" xsi:type="string">Magento\Framework\Data\CollectionDataSourceInterface</argument>
+            <argument name="expectedClass" xsi:type="string">Magento\Framework\View\Element\Block\ArgumentInterface</argument>
         </arguments>
     </virtualType>
     <type name="Magento\Framework\View\Layout\Argument\Interpreter\NamedParams">
diff --git a/dev/tests/integration/testsuite/Magento/Backend/Block/Widget/Grid/MassactionTest.php b/dev/tests/integration/testsuite/Magento/Backend/Block/Widget/Grid/MassactionTest.php
index 1bbf40ca6dc72999e4d2bd0c65987d25ee2e6f2a..8c0a7dd201d62abd7e823de4c31c2e9aec57f954 100644
--- a/dev/tests/integration/testsuite/Magento/Backend/Block/Widget/Grid/MassactionTest.php
+++ b/dev/tests/integration/testsuite/Magento/Backend/Block/Widget/Grid/MassactionTest.php
@@ -3,11 +3,10 @@
  * Copyright © 2016 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-
-// @codingStandardsIgnoreFile
-
 namespace Magento\Backend\Block\Widget\Grid;
 
+use Magento\TestFramework\App\State;
+
 /**
  * @magentoAppArea adminhtml
  * @magentoComponentsDir Magento/Backend/Block/_files/design
@@ -25,18 +24,43 @@ class MassactionTest extends \PHPUnit_Framework_TestCase
      */
     protected $_layout;
 
+    /**
+     * @var \Magento\Framework\ObjectManagerInterface
+     */
+    private $objectManager;
+
+    /**
+     * @var string
+     */
+    private $mageMode;
+
     protected function setUp()
     {
-        $this->markTestIncomplete('MAGETWO-6406');
-
         parent::setUp();
 
-        $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
+        $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
+
+        $this->mageMode = $this->objectManager->get(State::class)->getMode();
+
         /** @var \Magento\Theme\Model\Theme\Registration $registration */
-        $registration = $objectManager->get(\Magento\Theme\Model\Theme\Registration::class);
+        $registration = $this->objectManager->get(\Magento\Theme\Model\Theme\Registration::class);
         $registration->register();
-        $objectManager->get(\Magento\Framework\View\DesignInterface::class)->setDesignTheme('BackendTest/test_default');
-        $this->_layout = $objectManager->create(
+        $this->objectManager->get(\Magento\Framework\View\DesignInterface::class)
+            ->setDesignTheme('BackendTest/test_default');
+    }
+
+    protected function tearDown()
+    {
+        $this->objectManager->get(State::class)->setMode($this->mageMode);
+    }
+
+    /**
+     * @param string $mageMode
+     */
+    private function loadLayout($mageMode = State::MODE_DEVELOPER)
+    {
+        $this->objectManager->get(State::class)->setMode($mageMode);
+        $this->_layout = $this->objectManager->create(
             \Magento\Framework\View\LayoutInterface::class,
             ['area' => 'adminhtml']
         );
@@ -48,20 +72,14 @@ class MassactionTest extends \PHPUnit_Framework_TestCase
         $this->assertNotFalse($this->_block, 'Could not load the block for testing');
     }
 
-    /**
-     * @covers \Magento\Backend\Block\Widget\Grid\Massaction::getItems
-     * @covers \Magento\Backend\Block\Widget\Grid\Massaction::getCount
-     * @covers \Magento\Backend\Block\Widget\Grid\Massaction::getItemsJson
-     * @covers \Magento\Backend\Block\Widget\Grid\Massaction::isAvailable
-     */
     public function testMassactionDefaultValues()
     {
+        $this->loadLayout();
+
         /** @var $blockEmpty \Magento\Backend\Block\Widget\Grid\Massaction */
-        $blockEmpty = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get(
-            \Magento\Framework\View\LayoutInterface::class
-        )->createBlock(
-            \Magento\Backend\Block\Widget\Grid\Massaction::class
-        );
+        $blockEmpty = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()
+            ->get(\Magento\Framework\View\LayoutInterface::class)
+            ->createBlock(\Magento\Backend\Block\Widget\Grid\Massaction::class);
         $this->assertEmpty($blockEmpty->getItems());
         $this->assertEquals(0, $blockEmpty->getCount());
         $this->assertSame('[]', $blockEmpty->getItemsJson());
@@ -71,6 +89,8 @@ class MassactionTest extends \PHPUnit_Framework_TestCase
 
     public function testGetJavaScript()
     {
+        $this->loadLayout();
+
         $javascript = $this->_block->getJavaScript();
 
         $expectedItemFirst = '#"option_id1":{"label":"Option One",' .
@@ -86,6 +106,8 @@ class MassactionTest extends \PHPUnit_Framework_TestCase
 
     public function testGetJavaScriptWithAddedItem()
     {
+        $this->loadLayout();
+
         $input = [
             'id' => 'option_id3',
             'label' => 'Option Three',
@@ -100,20 +122,49 @@ class MassactionTest extends \PHPUnit_Framework_TestCase
         $this->assertRegExp($expected, $this->_block->getJavaScript());
     }
 
-    public function testGetCount()
+    /**
+     * @param string $mageMode
+     * @param int $expectedCount
+     * @dataProvider getCountDataProvider
+     */
+    public function testGetCount($mageMode, $expectedCount)
     {
-        $this->assertEquals(2, $this->_block->getCount());
+        $this->loadLayout($mageMode);
+        $this->assertEquals($expectedCount, $this->_block->getCount());
+    }
+
+    /**
+     * @return array
+     */
+    public function getCountDataProvider()
+    {
+        return [
+            [
+                'mageMode' => State::MODE_DEVELOPER,
+                'expectedCount' => 3,
+            ],
+            [
+                'mageMode' => State::MODE_DEFAULT,
+                'expectedCount' => 3,
+            ],
+            [
+                'mageMode' => State::MODE_PRODUCTION,
+                'expectedCount' => 2,
+            ],
+        ];
     }
 
     /**
-     * @param $itemId
-     * @param $expectedItem
+     * @param string $itemId
+     * @param array $expectedItem
      * @dataProvider getItemsDataProvider
      */
     public function testGetItems($itemId, $expectedItem)
     {
+        $this->loadLayout();
+
         $items = $this->_block->getItems();
-        $this->assertCount(2, $items);
+        $this->assertCount(3, $items);
         $this->assertArrayHasKey($itemId, $items);
 
         $actualItem = $items[$itemId];
@@ -149,19 +200,29 @@ class MassactionTest extends \PHPUnit_Framework_TestCase
                     'selected' => false,
                     'blockname' => ''
                 ]
+            ],
+            [
+                'option_id3',
+                [
+                    'id' => 'option_id3',
+                    'label' => 'Option Three',
+                    'url' => '#http:\/\/localhost\/index\.php\/(?:key\/([\w\d]+)\/)?#',
+                    'selected' => false,
+                    'blockname' => ''
+                ]
             ]
         ];
     }
 
     public function testGridContainsMassactionColumn()
     {
+        $this->loadLayout();
         $this->_layout->getBlock('admin.test.grid')->toHtml();
 
-        $gridMassactionColumn = $this->_layout->getBlock(
-            'admin.test.grid'
-        )->getColumnSet()->getChildBlock(
-            'massaction'
-        );
+        $gridMassactionColumn = $this->_layout->getBlock('admin.test.grid')
+            ->getColumnSet()
+            ->getChildBlock('massaction');
+
         $this->assertNotNull($gridMassactionColumn, 'Massaction column does not exist in the grid column set');
         $this->assertInstanceOf(
             \Magento\Backend\Block\Widget\Grid\Column::class,
diff --git a/dev/tests/integration/testsuite/Magento/Backend/Block/_files/design/adminhtml/Magento/test_default/Magento_Backend/layout/layout_test_grid_handle.xml b/dev/tests/integration/testsuite/Magento/Backend/Block/_files/design/adminhtml/Magento/test_default/Magento_Backend/layout/layout_test_grid_handle.xml
index 5f9a80a5a3dbda9a86915c99aefce1066074ffb6..c072532a1c27c3471602abbb2442611fa49c6a59 100644
--- a/dev/tests/integration/testsuite/Magento/Backend/Block/_files/design/adminhtml/Magento/test_default/Magento_Backend/layout/layout_test_grid_handle.xml
+++ b/dev/tests/integration/testsuite/Magento/Backend/Block/_files/design/adminhtml/Magento/test_default/Magento_Backend/layout/layout_test_grid_handle.xml
@@ -6,60 +6,68 @@
  */
 -->
 <layout xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
-    <block class="Magento\Backend\Block\Widget\Grid" name="admin.test.grid" Output="1">
+    <block class="Magento\Backend\Block\Widget\Grid" name="admin.test.grid">
         <arguments>
-            <dataSource type="object">Magento\Framework\Data\Collection</dataSource>
+            <argument name="dataSource" xsi:type="object">Magento\Framework\Data\Collection</argument>
         </arguments>
-        <block class="Magento\Backend\Block\Widget\Grid\ColumnSet" as="grid.columnSet" name="admin.test.grid.columnSet" Output="1">
-            <block class="Magento\Backend\Block\Widget\Grid\Column" as="product_name" Output="1">
+        <block class="Magento\Backend\Block\Widget\Grid\ColumnSet" as="grid.columnSet" name="admin.test.grid.columnSet">
+            <block class="Magento\Backend\Block\Widget\Grid\Column" as="product_name">
                 <arguments>
-                    <header>Product name 1</header>
-                    <index>product_name</index>
-                    <type>text</type>
+                    <argument name="header" xsi:type="string" translate="true">Product name 1</argument>
+                    <argument name="id" xsi:type="string">product_name</argument>
+                    <argument name="index" xsi:type="string">product_name</argument>
+                    <argument name="type" xsi:type="string">text</argument>
                 </arguments>
             </block>
-            <block class="Magento\Backend\Block\Widget\Grid\Column" as="description" output="1">
+            <block class="Magento\Backend\Block\Widget\Grid\Column" as="description">
                 <arguments>
-                    <header>User Description</header>
-                    <index>description</index>
-                    <type>text</type>
+                    <argument name="header" xsi:type="string" translate="true">User Description</argument>
+                    <argument name="id" xsi:type="string">description</argument>
+                    <argument name="index" xsi:type="string">description</argument>
+                    <argument name="type" xsi:type="string">text</argument>
                 </arguments>
             </block>
-            <block class="Magento\Backend\Block\Widget\Grid\Column" as="qty" output="1">
+            <block class="Magento\Backend\Block\Widget\Grid\Column" as="qty">
                 <arguments>
-                    <header>Qty</header>
-                    <index>qty</index>
-                    <type>number</type>
-                    <width>60px</width>
+                    <argument name="header" xsi:type="string" translate="true">Qty</argument>
+                    <argument name="id" xsi:type="string">qty</argument>
+                    <argument name="index" xsi:type="string">qty</argument>
+                    <argument name="type" xsi:type="string">number</argument>
+                    <argument name="width" xsi:type="string">60</argument>
                 </arguments>
             </block>
-            <block class="Magento\Backend\Block\Widget\Grid\Column" as="added_at" output="1">
+            <block class="Magento\Backend\Block\Widget\Grid\Column" as="added_at">
                 <arguments>
-                    <header>Date Added</header>
-                    <index>added_at</index>
-                    <gmtoffset>1</gmtoffset>
-                    <type>date</type>
+                    <argument name="header" xsi:type="string" translate="true">Date Added</argument>
+                    <argument name="id" xsi:type="string">added_at</argument>
+                    <argument name="index" xsi:type="string">added_at</argument>
+                    <argument name="type" xsi:type="string">date</argument>
+                    <argument name="gmtoffset" xsi:type="string">1</argument>
                 </arguments>
             </block>
         </block>
-        <block class="Magento\Backend\Block\Widget\Grid\Massaction" as="grid.massaction" name='admin.test.grid.massaction' output="1">
+        <block class="Magento\Backend\Block\Widget\Grid\Massaction" as="grid.massaction" name='admin.test.grid.massaction'>
             <arguments>
-                <massaction_id_field>test_id</massaction_id_field>
-                <massaction_id_filter>test_id</massaction_id_filter>
-                <form_field_name>test</form_field_name>
-                <use_select_all>1</use_select_all>
-                <options>
-                    <option_id1>
-                        <label>Option One</label>
-                        <url>*/*/option1</url>
-                        <complete>Test</complete>
-                    </option_id1>
-                    <option_id2>
-                        <label>Option Two</label>
-                        <url>*/*/option2</url>
-                        <confirm>Are you sure?</confirm>
-                    </option_id2>
-                </options>
+                <argument name="massaction_id_field" xsi:type="string">test_id</argument>
+                <argument name="form_field_name" xsi:type="string">test_id</argument>
+                <argument name="use_select_all" xsi:type="string">1</argument>
+                <argument name="options" xsi:type="array">
+                    <item name="option_id1" xsi:type="array">
+                        <item name="label" xsi:type="string" translate="true">Option One</item>
+                        <item name="url" xsi:type="string">*/*/option1</item>
+                        <item name="complete" xsi:type="string">Test</item>
+                    </item>
+                    <item name="option_id2" xsi:type="array">
+                        <item name="label" xsi:type="string" translate="true">Option Two</item>
+                        <item name="url" xsi:type="string">*/*/option2</item>
+                        <item name="confirm" xsi:type="string">Are you sure?</item>
+                    </item>
+                    <item name="option_id3" xsi:type="array">
+                        <item name="label" xsi:type="string" translate="true">Option Three</item>
+                        <item name="url" xsi:type="string">*/*/option3</item>
+                        <item name="visible" xsi:type="object">Magento\Backend\Block\Cache\Grid\Massaction\ProductionModeVisibilityChecker</item>
+                    </item>
+                </argument>
             </arguments>
         </block>
     </block>
diff --git a/dev/tests/integration/testsuite/Magento/Backend/Controller/Adminhtml/Cache/MassActionTest.php b/dev/tests/integration/testsuite/Magento/Backend/Controller/Adminhtml/Cache/MassActionTest.php
index e9fbb76f513d545eb4d710423bfd58a0cbb3d03e..a1034643ae3dcd6064caea87cf13f052db967f0f 100644
--- a/dev/tests/integration/testsuite/Magento/Backend/Controller/Adminhtml/Cache/MassActionTest.php
+++ b/dev/tests/integration/testsuite/Magento/Backend/Controller/Adminhtml/Cache/MassActionTest.php
@@ -3,13 +3,13 @@
  * Copyright © 2016 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-
 namespace Magento\Backend\Controller\Adminhtml\Cache;
 
 use Magento\Framework\App\Cache\State;
 use Magento\TestFramework\Helper\Bootstrap;
 use Magento\Framework\Config\File\ConfigFilePool;
 use Magento\Framework\App\Filesystem\DirectoryList;
+use Magento\TestFramework\App\State as AppState;
 
 class MassActionTest extends \Magento\TestFramework\TestCase\AbstractBackendController
 {
@@ -20,6 +20,11 @@ class MassActionTest extends \Magento\TestFramework\TestCase\AbstractBackendCont
      */
     private static $typesConfig;
 
+    /**
+     * @var string
+     */
+    private $mageState;
+
     public static function setUpBeforeClass()
     {
         /** @var \Magento\Framework\App\DeploymentConfig $config */
@@ -27,8 +32,15 @@ class MassActionTest extends \Magento\TestFramework\TestCase\AbstractBackendCont
         self::$typesConfig = $config->get(State::CACHE_KEY);
     }
 
+    protected function setUp()
+    {
+        parent::setUp();
+        $this->mageState = Bootstrap::getObjectManager()->get(AppState::class)->getMode();
+    }
+
     protected function tearDown()
     {
+        Bootstrap::getObjectManager()->get(AppState::class)->setMode($this->mageState);
         /** @var $cacheState \Magento\Framework\App\Cache\StateInterface */
         $cacheState = Bootstrap::getObjectManager()->get(\Magento\Framework\App\Cache\StateInterface::class);
         foreach (self::$typesConfig as $type => $value) {
@@ -42,7 +54,7 @@ class MassActionTest extends \Magento\TestFramework\TestCase\AbstractBackendCont
      * @dataProvider massActionsDataProvider
      * @param array $typesToEnable
      */
-    public function testMassEnableAction($typesToEnable = [])
+    public function testMassEnableActionDeveloperMode($typesToEnable = [])
     {
         $this->setAll(false);
 
@@ -53,16 +65,33 @@ class MassActionTest extends \Magento\TestFramework\TestCase\AbstractBackendCont
             if (in_array($cacheType, $typesToEnable)) {
                 $this->assertEquals(1, $cacheState, "Type '{$cacheType}' has not been enabled");
             } else {
-                $this->assertEquals(0, $cacheState, "Type '{$cacheType}' has not been enabled");
+                $this->assertEquals(0, $cacheState, "Type '{$cacheType}' must remain disabled");
             }
         }
     }
 
+    /**
+     * @dataProvider massActionsDataProvider
+     * @param array $typesToEnable
+     */
+    public function testMassEnableActionProductionMode($typesToEnable = [])
+    {
+        Bootstrap::getObjectManager()->get(AppState::class)->setMode(AppState::MODE_PRODUCTION);
+        $this->setAll(false);
+
+        $this->getRequest()->setParams(['types' => $typesToEnable]);
+        $this->dispatch('backend/admin/cache/massEnable');
+
+        foreach ($this->getCacheStates() as $cacheType => $cacheState) {
+            $this->assertEquals(0, $cacheState, "Type '{$cacheType}' must remain disabled");
+        }
+    }
+
     /**
      * @dataProvider massActionsDataProvider
      * @param array $typesToDisable
      */
-    public function testMassDisableAction($typesToDisable = [])
+    public function testMassDisableActionDeveloperMode($typesToDisable = [])
     {
         $this->setAll(true);
 
@@ -78,6 +107,23 @@ class MassActionTest extends \Magento\TestFramework\TestCase\AbstractBackendCont
         }
     }
 
+    /**
+     * @dataProvider massActionsDataProvider
+     * @param array $typesToDisable
+     */
+    public function testMassDisableActionProductionMode($typesToDisable = [])
+    {
+        Bootstrap::getObjectManager()->get(AppState::class)->setMode(AppState::MODE_PRODUCTION);
+        $this->setAll(true);
+
+        $this->getRequest()->setParams(['types' => $typesToDisable]);
+        $this->dispatch('backend/admin/cache/massDisable');
+
+        foreach ($this->getCacheStates() as $cacheType => $cacheState) {
+            $this->assertEquals(1, $cacheState, "Type '{$cacheType}' must remain enabled");
+        }
+    }
+
     /**
      * Retrieve cache states (enabled/disabled) information
      *
diff --git a/dev/tests/integration/testsuite/Magento/Config/Model/Config/Processor/EnvironmentPlaceholderTest.php b/dev/tests/integration/testsuite/Magento/Config/Model/Config/Processor/EnvironmentPlaceholderTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..1e2b6aacc931446cee8f42accb17d684c4bb413c
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Config/Model/Config/Processor/EnvironmentPlaceholderTest.php
@@ -0,0 +1,103 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Config\Model\Config\Processor;
+
+use Magento\Framework\ObjectManagerInterface;
+
+class EnvironmentPlaceholderTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var ObjectManagerInterface
+     */
+    private $objectManager;
+
+    /**
+     * @var EnvironmentPlaceholder
+     */
+    private $model;
+
+    /**
+     * @var array
+     */
+    private $env = [];
+
+    protected function setUp()
+    {
+        $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
+        $this->model = $this->objectManager->get(EnvironmentPlaceholder::class);
+        $this->env = $_ENV;
+    }
+
+    public function testProcess()
+    {
+        $_ENV = array_merge(
+            $_ENV,
+            [
+                'CONFIG__DEFAULT__WEB__UNSECURE__BASE_URL' => 'http://expected.local',
+                'CONFIG__TEST__TEST__DESIGN__HEADER__WELCOME' => 'Expected header',
+                'TEST__TEST__WEB__SECURE__BASE_URL' => 'http://wrong_pattern.local',
+                'CONFIG__DEFAULT__GENERAL__REGION__DISPLAY_ALL' => 1
+            ]
+        );
+        $expected = [
+            'default' => [
+                'web' => [
+                    'unsecure' => [
+                        'base_url' => 'http://expected.local'
+                    ],
+                    'secure' => [
+                        'base_url' => 'https://original.local'
+                    ]
+                ],
+                'general' => [
+                    'region' => [
+                        'display_all' => 1
+                    ],
+                ],
+            ],
+            'test' => [
+                'test' => [
+                    'design' => [
+                        'header' => [
+                            'welcome' => 'Expected header'
+                        ]
+                    ],
+                ],
+            ]
+        ];
+        $config = [
+            'default' => [
+                'web' => [
+                    'unsecure' => [
+                        'base_url' => 'http://original.local',
+                    ],
+                    'secure' => [
+                        'base_url' => 'https://original.local'
+                    ]
+                ]
+            ],
+            'test' => [
+                'test' => [
+                    'design' => [
+                        'header' => [
+                            'welcome' => 'Original header'
+                        ]
+                    ],
+                ],
+            ]
+        ];
+
+        $this->assertSame(
+            $expected,
+            $this->model->process($config)
+        );
+    }
+
+    protected function tearDown()
+    {
+        $_ENV = $this->env;
+    }
+}
diff --git a/dev/tests/integration/testsuite/Magento/Deploy/Console/Command/App/ApplicationDumpCommandTest.php b/dev/tests/integration/testsuite/Magento/Deploy/Console/Command/App/ApplicationDumpCommandTest.php
index a229b64bb7dd10ef29acd5e824dfb5a9b28bfcc8..170d186e20af812a1c40bc4937559c6d5342942a 100644
--- a/dev/tests/integration/testsuite/Magento/Deploy/Console/Command/App/ApplicationDumpCommandTest.php
+++ b/dev/tests/integration/testsuite/Magento/Deploy/Console/Command/App/ApplicationDumpCommandTest.php
@@ -7,7 +7,6 @@ namespace Magento\Deploy\Console\Command\App;
 
 use Magento\Framework\App\DeploymentConfig;
 use Magento\Framework\App\Filesystem\DirectoryList;
-use Magento\Framework\App\ObjectManager;
 use Magento\Framework\Config\File\ConfigFilePool;
 use Magento\Framework\Filesystem\DriverPool;
 use Magento\Framework\ObjectManagerInterface;
@@ -18,37 +17,73 @@ use Symfony\Component\Console\Output\OutputInterface;
 class ApplicationDumpCommandTest extends \PHPUnit_Framework_TestCase
 {
     /**
-     * @var ApplicationDumpCommand
+     * @var ObjectManagerInterface
      */
-    private $command;
+    private $objectManager;
 
     /**
-     * @var ObjectManagerInterface
+     * @var DeploymentConfig\Reader
      */
-    private $objectManager;
+    private $reader;
 
     public function setUp()
     {
-        $this->command = Bootstrap::getObjectManager()->get(ApplicationDumpCommand::class);
         $this->objectManager = Bootstrap::getObjectManager();
+        $this->reader = $this->objectManager->get(DeploymentConfig\Reader::class);
     }
 
+    /**
+     * @magentoDbIsolation enabled
+     * @magentoDataFixture Magento/Deploy/_files/config_data.php
+     */
     public function testExecute()
     {
-        $inputMock = $this->getMock(InputInterface::class);
+        $this->objectManager->configure([
+            \Magento\Config\Model\Config\Export\ExcludeList::class => [
+                'arguments' => [
+                    'configs' => [
+                        'web/test/test_value_1' => '',
+                        'web/test/test_value_2' => '',
+                        'web/test/test_sensitive' => '1',
+                    ],
+                ],
+            ],
+        ]);
+
+        $comment = 'The configuration file doesn\'t contain sensitive data for security reasons. '
+            . 'Sensitive data can be stored in the following environment variables:'
+            . "\nCONFIG__DEFAULT__WEB__TEST__TEST_SENSITIVE for web/test/test_sensitive";
         $outputMock = $this->getMock(OutputInterface::class);
-        $outputMock->expects($this->once())
+        $outputMock->expects($this->at(0))
+            ->method('writeln')
+            ->with(['system' => $comment]);
+        $outputMock->expects($this->at(1))
             ->method('writeln')
             ->with('<info>Done.</info>');
-        $this->assertEquals(0, $this->command->run($inputMock, $outputMock));
+
+        /** @var ApplicationDumpCommand command */
+        $command = $this->objectManager->create(ApplicationDumpCommand::class);
+        $command->run($this->getMock(InputInterface::class), $outputMock);
+
+        $config = $this->reader->loadConfigFile(ConfigFilePool::APP_CONFIG, $this->getFileName());
+
+        $this->assertArrayHasKey(
+            'test_value_1',
+            $config['system']['default']['web']['test']
+        );
+        $this->assertArrayHasKey(
+            'test_value_2',
+            $config['system']['default']['web']['test']
+        );
+        $this->assertArrayNotHasKey(
+            'test_sensitive',
+            $config['system']['default']['web']['test']
+        );
     }
 
     public function tearDown()
     {
-        /** @var ConfigFilePool $configFilePool */
-        $configFilePool = $this->objectManager->get(ConfigFilePool::class);
-        $filePool = $configFilePool->getInitialFilePools();
-        $file = $filePool[ConfigFilePool::LOCAL][ConfigFilePool::APP_CONFIG];
+        $file = $this->getFileName();
         /** @var DirectoryList $dirList */
         $dirList = $this->objectManager->get(DirectoryList::class);
         $path = $dirList->getPath(DirectoryList::CONFIG);
@@ -61,4 +96,16 @@ class ApplicationDumpCommandTest extends \PHPUnit_Framework_TestCase
         $deploymentConfig = $this->objectManager->get(DeploymentConfig::class);
         $deploymentConfig->resetData();
     }
+
+    /**
+     * @return string
+     */
+    private function getFileName()
+    {
+        /** @var ConfigFilePool $configFilePool */
+        $configFilePool = $this->objectManager->get(ConfigFilePool::class);
+        $filePool = $configFilePool->getInitialFilePools();
+
+        return $filePool[ConfigFilePool::LOCAL][ConfigFilePool::APP_CONFIG];
+    }
 }
diff --git a/dev/tests/integration/testsuite/Magento/Deploy/_files/config_data.php b/dev/tests/integration/testsuite/Magento/Deploy/_files/config_data.php
new file mode 100644
index 0000000000000000000000000000000000000000..bd8e69262e1e03f98b3ce41735bbf2264e234292
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Deploy/_files/config_data.php
@@ -0,0 +1,33 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+$configData = [
+    'default' => [
+        '' => [
+            'web/test/test_value_1' => 'http://local2.test/',
+            'web/test/test_value_2' => 5,
+            'web/test/test_sensitive' => 10,
+        ]
+    ],
+];
+
+$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
+$configFactory = $objectManager->create(\Magento\Config\Model\Config\Factory::class);
+
+foreach ($configData as $scope => $data) {
+    foreach ($data as $scopeCode => $scopeData) {
+        foreach ($scopeData as $path => $value) {
+            $config = $configFactory->create();
+            $config->setCope($scope);
+
+            if ($scopeCode) {
+                $config->setScopeCode($scopeCode);
+            }
+
+            $config->setDataByPath($path, $value);
+            $config->save();
+        }
+    }
+}
diff --git a/lib/internal/Magento/Framework/App/Config/CommentInterface.php b/lib/internal/Magento/Framework/App/Config/CommentInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..902d63668f368912208ed38c9d19ebb985af8b31
--- /dev/null
+++ b/lib/internal/Magento/Framework/App/Config/CommentInterface.php
@@ -0,0 +1,21 @@
+<?php
+/**
+ * Provide access to data. Each Source can be responsible for each storage, where config data can be placed
+ *
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Framework\App\Config;
+
+/**
+ * Interface CommentInterface
+ */
+interface CommentInterface
+{
+    /**
+     * Retrieve comment for configuration data.
+     *
+     * @return string
+     */
+    public function get();
+}
diff --git a/lib/internal/Magento/Framework/App/Config/PreProcessorComposite.php b/lib/internal/Magento/Framework/App/Config/PreProcessorComposite.php
new file mode 100644
index 0000000000000000000000000000000000000000..10c355d290dfc43f818fa3799ad8b46807d7e6cd
--- /dev/null
+++ b/lib/internal/Magento/Framework/App/Config/PreProcessorComposite.php
@@ -0,0 +1,40 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Framework\App\Config;
+
+use Magento\Framework\App\Config\Spi\PreProcessorInterface;
+
+/**
+ * Class PreProcessorComposite
+ */
+class PreProcessorComposite implements PreProcessorInterface
+{
+    /**
+     * @var PreProcessorInterface[]
+     */
+    private $processors = [];
+
+    /**
+     * @param PreProcessorInterface[] $processors
+     */
+    public function __construct(array $processors = [])
+    {
+        $this->processors = $processors;
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function process(array $config)
+    {
+        /** @var PreProcessorInterface $processor */
+        foreach ($this->processors as $processor) {
+            $config = $processor->process($config);
+        }
+
+        return $config;
+    }
+}
diff --git a/lib/internal/Magento/Framework/App/Config/Spi/PreProcessorInterface.php b/lib/internal/Magento/Framework/App/Config/Spi/PreProcessorInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..1be0783d7f7deb9ec393a40eff2e2d0df3197281
--- /dev/null
+++ b/lib/internal/Magento/Framework/App/Config/Spi/PreProcessorInterface.php
@@ -0,0 +1,20 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Framework\App\Config\Spi;
+
+/**
+ * Allows to use custom callbacks and functions before applying fallback
+ */
+interface PreProcessorInterface
+{
+    /**
+     * Pre-processing of config
+     *
+     * @param array $config
+     * @return array
+     */
+    public function process(array $config);
+}
diff --git a/lib/internal/Magento/Framework/App/DeploymentConfig/Reader.php b/lib/internal/Magento/Framework/App/DeploymentConfig/Reader.php
index a1635fc4b2670d3749adbc8ac7bb88bab31904cf..d5a224d1b50b221d0afcf7c6127325d702c5217d 100644
--- a/lib/internal/Magento/Framework/App/DeploymentConfig/Reader.php
+++ b/lib/internal/Magento/Framework/App/DeploymentConfig/Reader.php
@@ -149,7 +149,9 @@ class Reader
             foreach ($initialFilePools as $initialFiles) {
                 if (isset($initialFiles[$fileKey]) && $fileDriver->isExists($path . '/' . $initialFiles[$fileKey])) {
                     $fileBuffer = include $path . '/' . $initialFiles[$fileKey];
-                    $result = array_replace_recursive($result, $fileBuffer);
+                    if (is_array($fileBuffer)) {
+                        $result = array_replace_recursive($result, $fileBuffer);
+                    }
                 }
             }
         }
@@ -159,6 +161,13 @@ class Reader
             $result = array_replace_recursive($result, $fileBuffer);
         }
 
+        if ($fileDriver->isExists($path . '/' . $pathConfig)) {
+            $configResult = include $path . '/' . $pathConfig;
+            if (is_array($configResult)) {
+                $result = array_replace_recursive($result, $configResult);
+            }
+        }
+
         return $result;
     }
 
diff --git a/lib/internal/Magento/Framework/App/DeploymentConfig/Writer.php b/lib/internal/Magento/Framework/App/DeploymentConfig/Writer.php
index 6cead0305a6c6ada899060a2a7debdbfe71f6f1a..2d8e7a14aaf55519d33376f1ee09f80b9b46cec6 100644
--- a/lib/internal/Magento/Framework/App/DeploymentConfig/Writer.php
+++ b/lib/internal/Magento/Framework/App/DeploymentConfig/Writer.php
@@ -94,10 +94,11 @@ class Writer
      * @param array $data
      * @param bool $override
      * @param string $pool
+     * @param array $comments
      * @return void
      * @throws FileSystemException
      */
-    public function saveConfig(array $data, $override = false, $pool = null)
+    public function saveConfig(array $data, $override = false, $pool = null, array $comments = [])
     {
         foreach ($data as $fileKey => $config) {
             $paths = $pool ? $this->configFilePool->getPathsByPool($pool) : $this->configFilePool->getPaths();
@@ -112,7 +113,7 @@ class Writer
                     }
                 }
 
-                $contents = $this->formatter->format($config);
+                $contents = $this->formatter->format($config, $comments);
                 try {
                     $writeFilePath = $paths[$fileKey];
                     $this->filesystem->getDirectoryWrite(DirectoryList::CONFIG)->writeFile($writeFilePath, $contents);
diff --git a/lib/internal/Magento/Framework/App/DeploymentConfig/Writer/FormatterInterface.php b/lib/internal/Magento/Framework/App/DeploymentConfig/Writer/FormatterInterface.php
index 24e31074501f3aae16a12bed0473ccfd43d45ac0..640bcb61d2031abd4d671e6f02de0636b252b16d 100644
--- a/lib/internal/Magento/Framework/App/DeploymentConfig/Writer/FormatterInterface.php
+++ b/lib/internal/Magento/Framework/App/DeploymentConfig/Writer/FormatterInterface.php
@@ -12,7 +12,8 @@ interface FormatterInterface
      * Format deployment configuration
      *
      * @param array $data
+     * @param array $comments
      * @return string
      */
-    public function format($data);
+    public function format($data, array $comments = []);
 }
diff --git a/lib/internal/Magento/Framework/App/DeploymentConfig/Writer/PhpFormatter.php b/lib/internal/Magento/Framework/App/DeploymentConfig/Writer/PhpFormatter.php
index 1ab99358cef1adacff5dc2dabc1ea884885e5d95..91bd906e3ca4d83438188e3131ba5e9537af939c 100644
--- a/lib/internal/Magento/Framework/App/DeploymentConfig/Writer/PhpFormatter.php
+++ b/lib/internal/Magento/Framework/App/DeploymentConfig/Writer/PhpFormatter.php
@@ -12,10 +12,26 @@ namespace Magento\Framework\App\DeploymentConfig\Writer;
 class PhpFormatter implements FormatterInterface
 {
     /**
+     * Format deployment configuration.
+     * If $comments is present, each item will be added
+     * as comment to the corresponding section
+     *
      * {@inheritdoc}
      */
-    public function format($data)
+    public function format($data, array $comments = [])
     {
+        if (!empty($comments) && is_array($data)) {
+            $elements = [];
+            foreach ($data as $key => $value) {
+                $comment = '  ';
+                if (!empty($comments[$key])) {
+                    $comment = "  /**\n * " . str_replace("\n", "\n * ", var_export($comments[$key], true)) . "\n */\n";
+                }
+                $space = is_array($value) ? " \n" : ' ';
+                $elements[] = $comment . var_export($key, true) . ' =>' . $space . var_export($value, true);
+            }
+            return "<?php\nreturn array (\n" . implode(",\n", str_replace("\n", "\n  ", $elements)) . "\n);\n";
+        }
         return "<?php\nreturn " . var_export($data, true) . ";\n";
     }
 }
diff --git a/lib/internal/Magento/Framework/App/Test/Unit/Config/PreProcessorCompositeTest.php b/lib/internal/Magento/Framework/App/Test/Unit/Config/PreProcessorCompositeTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..291bef1266134f7956919a2c831af4a7fd4715e2
--- /dev/null
+++ b/lib/internal/Magento/Framework/App/Test/Unit/Config/PreProcessorCompositeTest.php
@@ -0,0 +1,40 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Framework\App\Test\Unit\Config;
+
+use Magento\Framework\App\Config\PreProcessorComposite;
+use Magento\Framework\App\Config\Spi\PreProcessorInterface;
+
+class PreProcessorCompositeTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var PreProcessorComposite
+     */
+    private $model;
+
+    /**
+     * @var PreProcessorInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $preProcessorMock;
+
+    protected function setUp()
+    {
+        $this->preProcessorMock = $this->getMockBuilder(PreProcessorInterface::class)
+            ->getMockForAbstractClass();
+
+        $this->model = new PreProcessorComposite([$this->preProcessorMock]);
+    }
+
+    public function testProcess()
+    {
+        $this->preProcessorMock->expects($this->once())
+            ->method('process')
+            ->with(['test' => 'data'])
+            ->willReturn(['test' => 'data2']);
+
+        $this->assertSame(['test' => 'data2'], $this->model->process(['test' => 'data']));
+    }
+}
diff --git a/lib/internal/Magento/Framework/App/Test/Unit/DeploymentConfig/Writer/PhpFormatterTest.php b/lib/internal/Magento/Framework/App/Test/Unit/DeploymentConfig/Writer/PhpFormatterTest.php
index a9b5bc04a12768f8de76e5cdc514e226fb4af05b..2ab8b209272f1cc882c14fb1a2dd9a15c22605f4 100644
--- a/lib/internal/Magento/Framework/App/Test/Unit/DeploymentConfig/Writer/PhpFormatterTest.php
+++ b/lib/internal/Magento/Framework/App/Test/Unit/DeploymentConfig/Writer/PhpFormatterTest.php
@@ -10,10 +10,128 @@ use \Magento\Framework\App\DeploymentConfig\Writer\PhpFormatter;
 
 class PhpFormatterTest extends \PHPUnit_Framework_TestCase
 {
-    public function testFormat()
+    /**
+     * @dataProvider formatWithCommentDataProvider
+     * @param string|array $data
+     * @param array $comments
+     * @param string $expectedResult
+     */
+    public function testFormat($data, $comments, $expectedResult)
     {
         $formatter = new PhpFormatter();
-        $data = 'test';
-        $this->assertEquals("<?php\nreturn 'test';\n", $formatter->format($data));
+        $this->assertEquals($expectedResult, $formatter->format($data, $comments));
+    }
+
+    /**
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+     */
+    public function formatWithCommentDataProvider()
+    {
+        $array = [
+            'ns1' => [
+                's1' => [
+                    's11',
+                    's12'
+                ],
+                's2' => [
+                    's21',
+                    's22'
+                ],
+            ],
+            'ns2' => [
+                's1' => [
+                    's11'
+                ],
+            ],
+            'ns3' => 'just text',
+            'ns4' => 'just text'
+        ];
+        $comments1 = ['ns2' => 'comment for namespace 2'];
+        $comments2 = [
+            'ns1' => 'comment for namespace 1',
+            'ns2' => "comment for namespace 2.\nNext comment for namespace 2",
+            'ns3' => 'comment for namespace 3',
+            'ns4' => 'comment for namespace 4',
+            'ns5' => 'comment for unexisted namespace 5',
+        ];
+        $expectedResult1 = <<<TEXT
+<?php
+return array (
+  'ns1' => 
+  array (
+    's1' => 
+    array (
+      0 => 's11',
+      1 => 's12',
+    ),
+    's2' => 
+    array (
+      0 => 's21',
+      1 => 's22',
+    ),
+  ),
+  /**
+   * 'comment for namespace 2'
+   */
+  'ns2' => 
+  array (
+    's1' => 
+    array (
+      0 => 's11',
+    ),
+  ),
+  'ns3' => 'just text',
+  'ns4' => 'just text'
+);
+
+TEXT;
+        $expectedResult2 = <<<TEXT
+<?php
+return array (
+  /**
+   * 'comment for namespace 1'
+   */
+  'ns1' => 
+  array (
+    's1' => 
+    array (
+      0 => 's11',
+      1 => 's12',
+    ),
+    's2' => 
+    array (
+      0 => 's21',
+      1 => 's22',
+    ),
+  ),
+  /**
+   * 'comment for namespace 2.
+   * Next comment for namespace 2'
+   */
+  'ns2' => 
+  array (
+    's1' => 
+    array (
+      0 => 's11',
+    ),
+  ),
+  /**
+   * 'comment for namespace 3'
+   */
+  'ns3' => 'just text',
+  /**
+   * 'comment for namespace 4'
+   */
+  'ns4' => 'just text'
+);
+
+TEXT;
+        return [
+            ['string', [], "<?php\nreturn 'string';\n"],
+            ['string', ['comment'], "<?php\nreturn 'string';\n"],
+            [$array, [], "<?php\nreturn " . var_export($array, true) . ";\n"],
+            [$array, $comments1, $expectedResult1],
+            [$array, $comments2, $expectedResult2],
+        ];
     }
 }
diff --git a/lib/internal/Magento/Framework/Crontab/CrontabManager.php b/lib/internal/Magento/Framework/Crontab/CrontabManager.php
new file mode 100644
index 0000000000000000000000000000000000000000..2b597b8eb638fb21af887ab7b47490f5533fafae
--- /dev/null
+++ b/lib/internal/Magento/Framework/Crontab/CrontabManager.php
@@ -0,0 +1,199 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Framework\Crontab;
+
+use Magento\Framework\ShellInterface;
+use Magento\Framework\Phrase;
+use Magento\Framework\Exception\LocalizedException;
+use Magento\Framework\Filesystem;
+use Magento\Framework\App\Filesystem\DirectoryList;
+
+/**
+ * Manager works with cron tasks
+ */
+class CrontabManager implements CrontabManagerInterface
+{
+    /**
+     * @var ShellInterface
+     */
+    private $shell;
+
+    /**
+     * @var Filesystem
+     */
+    private $filesystem;
+
+    /**
+     * @param ShellInterface $shell
+     * @param Filesystem $filesystem
+     */
+    public function __construct(
+        ShellInterface $shell,
+        Filesystem $filesystem
+    ) {
+        $this->shell = $shell;
+        $this->filesystem = $filesystem;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getTasks()
+    {
+        $this->checkSupportedOs();
+        $content = $this->getCrontabContent();
+        $pattern = '!(' . self::TASKS_BLOCK_START . ')(.*?)(' . self::TASKS_BLOCK_END . ')!s';
+
+        if (preg_match($pattern, $content, $matches)) {
+            $tasks = trim($matches[2], PHP_EOL);
+            $tasks = explode(PHP_EOL, $tasks);
+            return $tasks;
+        }
+
+        return [];
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function saveTasks(array $tasks)
+    {
+        $this->checkSupportedOs();
+        $baseDir = $this->filesystem->getDirectoryRead(DirectoryList::ROOT)->getAbsolutePath();
+        $logDir = $this->filesystem->getDirectoryRead(DirectoryList::LOG)->getAbsolutePath();
+
+        if (!$tasks) {
+            throw new LocalizedException(new Phrase('List of tasks is empty'));
+        }
+
+        foreach ($tasks as $key => $task) {
+            if (empty($task['expression'])) {
+                $tasks[$key]['expression'] = '* * * * *';
+            }
+
+            if (empty($task['command'])) {
+                throw new LocalizedException(new Phrase('Command should not be empty'));
+            }
+
+            $tasks[$key]['command'] = str_replace(
+                ['{magentoRoot}', '{magentoLog}'],
+                [$baseDir, $logDir],
+                $task['command']
+            );
+        }
+
+        $content = $this->getCrontabContent();
+        $content = $this->cleanMagentoSection($content);
+        $content = $this->generateSection($content, $tasks);
+
+        $this->save($content);
+    }
+
+    /**
+     * {@inheritdoc}
+     * @throws LocalizedException
+     */
+    public function removeTasks()
+    {
+        $this->checkSupportedOs();
+        $content = $this->getCrontabContent();
+        $content = $this->cleanMagentoSection($content);
+        $this->save($content);
+    }
+
+    /**
+     * Generate Magento Tasks Section
+     *
+     * @param string $content
+     * @param array $tasks
+     * @return string
+     */
+    private function generateSection($content, $tasks = [])
+    {
+        if ($tasks) {
+            $content .= self::TASKS_BLOCK_START . PHP_EOL;
+            foreach ($tasks as $task) {
+                $content .=  $task['expression'] . ' ' . PHP_BINARY . ' '. $task['command'] . PHP_EOL;
+            }
+            $content .= self::TASKS_BLOCK_END . PHP_EOL;
+        }
+
+        return $content;
+    }
+
+    /**
+     * Clean Magento Tasks Section in crontab content
+     *
+     * @param string $content
+     * @return string
+     */
+    private function cleanMagentoSection($content)
+    {
+        $content = preg_replace(
+            '!' . preg_quote(self::TASKS_BLOCK_START) . '.*?' . preg_quote(self::TASKS_BLOCK_END . PHP_EOL) . '!s',
+            '',
+            $content
+        );
+
+        return $content;
+    }
+
+    /**
+     * Get crontab content without Magento Tasks Section
+     *
+     * In case of some exceptions the empty content is returned
+     *
+     * @return string
+     */
+    private function getCrontabContent()
+    {
+        try {
+            $content = (string)$this->shell->execute('crontab -l');
+        } catch (LocalizedException $e) {
+            return '';
+        }
+
+        return $content;
+    }
+
+    /**
+     * Save crontab
+     *
+     * @param string $content
+     * @return void
+     * @throws LocalizedException
+     */
+    private function save($content)
+    {
+        $content = str_replace('%', '%%', $content);
+
+        try {
+            $this->shell->execute('echo "' . $content . '" | crontab -');
+        } catch (LocalizedException $e) {
+            throw new LocalizedException(
+                new Phrase('Error during saving of crontab: %1', [$e->getPrevious()->getMessage()]),
+                $e
+            );
+        }
+    }
+
+    /**
+     * Check that OS is supported
+     *
+     * If OS is not supported then no possibility to work with crontab
+     *
+     * @return void
+     * @throws LocalizedException
+     */
+    private function checkSupportedOs()
+    {
+        if (stripos(PHP_OS, 'WIN') === 0) {
+            throw new LocalizedException(
+                new Phrase('Your operation system is not supported to work with this command')
+            );
+        }
+    }
+}
diff --git a/lib/internal/Magento/Framework/Crontab/CrontabManagerInterface.php b/lib/internal/Magento/Framework/Crontab/CrontabManagerInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..c00ab41d8b873a46dc27abbb1af37a23b7e7fd86
--- /dev/null
+++ b/lib/internal/Magento/Framework/Crontab/CrontabManagerInterface.php
@@ -0,0 +1,43 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Framework\Crontab;
+
+use Magento\Framework\Exception\LocalizedException;
+
+interface CrontabManagerInterface
+{
+    /**#@+
+     * Constants for wrapping Magento section in crontab
+     */
+    const TASKS_BLOCK_START = '#~ MAGENTO START';
+    const TASKS_BLOCK_END = '#~ MAGENTO END';
+    /**#@-*/
+
+    /**
+     * Get list of Magento Tasks
+     *
+     * @return array
+     * @throws LocalizedException
+     */
+    public function getTasks();
+
+    /**
+     * Save Magento Tasks to crontab
+     *
+     * @param array $tasks
+     * @return void
+     * @throws LocalizedException
+     */
+    public function saveTasks(array $tasks);
+
+    /**
+     * Remove Magento Tasks form crontab
+     *
+     * @return void
+     * @throws LocalizedException
+     */
+    public function removeTasks();
+}
diff --git a/lib/internal/Magento/Framework/Crontab/README.md b/lib/internal/Magento/Framework/Crontab/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..bfbf194715dc8f9f359137ecb79be5a1adbd5c5e
--- /dev/null
+++ b/lib/internal/Magento/Framework/Crontab/README.md
@@ -0,0 +1,12 @@
+Library for working with crontab
+
+The library has the next interfaces:
+* CrontabManagerInterface
+* TasksProviderInterface
+
+*CrontabManagerInterface* provides working with crontab:
+* *getTasks* - get list of Magento cron tasks from crontab
+* *saveTasks* - save Magento cron tasks to crontab
+* *removeTasks* - remove Magento cron tasks from crontab
+
+*TasksProviderInterface* has only one method *getTasks*. This interface provides transportation the list of tasks from DI
\ No newline at end of file
diff --git a/lib/internal/Magento/Framework/Crontab/TasksProvider.php b/lib/internal/Magento/Framework/Crontab/TasksProvider.php
new file mode 100644
index 0000000000000000000000000000000000000000..94524fd2bbd19b4395a8ba36daaa0f43c2b6c648
--- /dev/null
+++ b/lib/internal/Magento/Framework/Crontab/TasksProvider.php
@@ -0,0 +1,33 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Framework\Crontab;
+
+/**
+ * TasksProvider collects list of tasks
+ */
+class TasksProvider implements TasksProviderInterface
+{
+    /**
+     * @var array
+     */
+    private $tasks = [];
+
+    /**
+     * @param array $tasks
+     */
+    public function __construct(array $tasks = [])
+    {
+        $this->tasks = $tasks;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getTasks()
+    {
+        return $this->tasks;
+    }
+}
diff --git a/lib/internal/Magento/Framework/Crontab/TasksProviderInterface.php b/lib/internal/Magento/Framework/Crontab/TasksProviderInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..bb02c30797be4cbf015c5858ac1c88825bde54a7
--- /dev/null
+++ b/lib/internal/Magento/Framework/Crontab/TasksProviderInterface.php
@@ -0,0 +1,16 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Framework\Crontab;
+
+interface TasksProviderInterface
+{
+    /**
+     * Get list of tasks
+     *
+     * @return array
+     */
+    public function getTasks();
+}
diff --git a/lib/internal/Magento/Framework/Crontab/Test/Unit/CrontabManagerTest.php b/lib/internal/Magento/Framework/Crontab/Test/Unit/CrontabManagerTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..7cafd386c629a4b48350d5ca4937b58fd49da4b6
--- /dev/null
+++ b/lib/internal/Magento/Framework/Crontab/Test/Unit/CrontabManagerTest.php
@@ -0,0 +1,333 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Framework\Crontab\Test\Unit;
+
+use Magento\Framework\Crontab\CrontabManager;
+use Magento\Framework\Crontab\CrontabManagerInterface;
+use Magento\Framework\ShellInterface;
+use Magento\Framework\Phrase;
+use Magento\Framework\Exception\LocalizedException;
+use Magento\Framework\Filesystem;
+use Magento\Framework\App\Filesystem\DirectoryList;
+use Magento\Framework\Filesystem\Directory\ReadInterface;
+use Magento\Framework\Filesystem\DriverPool;
+
+class CrontabManagerTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var ShellInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $shellMock;
+
+    /**
+     * @var Filesystem|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $filesystemMock;
+
+    /**
+     * @var CrontabManager
+     */
+    private $crontabManager;
+
+    /**
+     * @return void
+     */
+    protected function setUp()
+    {
+        $this->shellMock = $this->getMockBuilder(ShellInterface::class)
+            ->getMockForAbstractClass();
+        $this->filesystemMock = $this->getMockBuilder(Filesystem::class)
+            ->disableOriginalClone()
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->crontabManager = new CrontabManager($this->shellMock, $this->filesystemMock);
+    }
+
+    /**
+     * @return void
+     */
+    public function testGetTasksNoCrontab()
+    {
+        $exception = new \Exception('crontab: no crontab for user');
+        $localizedException = new LocalizedException(new Phrase('Some error'), $exception);
+
+        $this->shellMock->expects($this->once())
+            ->method('execute')
+            ->with('crontab -l', [])
+            ->willThrowException($localizedException);
+
+        $this->assertEquals([], $this->crontabManager->getTasks());
+    }
+
+    /**
+     * @param string $content
+     * @param array $tasks
+     * @return void
+     * @dataProvider getTasksDataProvider
+     */
+    public function testGetTasks($content, $tasks)
+    {
+        $this->shellMock->expects($this->once())
+            ->method('execute')
+            ->with('crontab -l', [])
+            ->willReturn($content);
+
+        $this->assertEquals($tasks, $this->crontabManager->getTasks());
+    }
+
+    /**
+     * @return array
+     */
+    public function getTasksDataProvider()
+    {
+        return [
+            [
+                'content' => '* * * * * /bin/php /var/www/cron.php' . PHP_EOL
+                    . CrontabManagerInterface::TASKS_BLOCK_START . PHP_EOL
+                    . '* * * * * /bin/php /var/www/magento/bin/magento cron:run' . PHP_EOL
+                    . CrontabManagerInterface::TASKS_BLOCK_END . PHP_EOL,
+                'tasks' => ['* * * * * /bin/php /var/www/magento/bin/magento cron:run'],
+            ],
+            [
+                'content' => '* * * * * /bin/php /var/www/cron.php' . PHP_EOL
+                    . CrontabManagerInterface::TASKS_BLOCK_START . PHP_EOL
+                    . '* * * * * /bin/php /var/www/magento/bin/magento cron:run' . PHP_EOL
+                    . '* * * * * /bin/php /var/www/magento/bin/magento setup:cron:run' . PHP_EOL
+                    . CrontabManagerInterface::TASKS_BLOCK_END . PHP_EOL,
+                'tasks' => [
+                    '* * * * * /bin/php /var/www/magento/bin/magento cron:run',
+                    '* * * * * /bin/php /var/www/magento/bin/magento setup:cron:run',
+                ],
+            ],
+            [
+                'content' => '* * * * * /bin/php /var/www/cron.php' . PHP_EOL,
+                'tasks' => [],
+            ],
+            [
+                'content' => '',
+                'tasks' => [],
+            ],
+        ];
+    }
+
+    /**
+     * @return void
+     * @expectedException \Magento\Framework\Exception\LocalizedException
+     * @expectedExceptionMessage Shell error
+     */
+    public function testRemoveTasksWithException()
+    {
+        $exception = new \Exception('Shell error');
+        $localizedException = new LocalizedException(new Phrase('Some error'), $exception);
+
+        $this->shellMock->expects($this->at(0))
+            ->method('execute')
+            ->with('crontab -l', [])
+            ->willReturn('');
+
+        $this->shellMock->expects($this->at(1))
+            ->method('execute')
+            ->with('echo "" | crontab -', [])
+            ->willThrowException($localizedException);
+
+        $this->crontabManager->removeTasks();
+    }
+
+    /**
+     * @param string $contentBefore
+     * @param string $contentAfter
+     * @return void
+     * @dataProvider removeTasksDataProvider
+     */
+    public function testRemoveTasks($contentBefore, $contentAfter)
+    {
+        $this->shellMock->expects($this->at(0))
+            ->method('execute')
+            ->with('crontab -l', [])
+            ->willReturn($contentBefore);
+
+        $this->shellMock->expects($this->at(1))
+            ->method('execute')
+            ->with('echo "' . $contentAfter . '" | crontab -', []);
+
+        $this->crontabManager->removeTasks();
+    }
+
+    /**
+     * @return array
+     */
+    public function removeTasksDataProvider()
+    {
+        return [
+            [
+                'contentBefore' => '* * * * * /bin/php /var/www/cron.php' . PHP_EOL
+                    . CrontabManagerInterface::TASKS_BLOCK_START . PHP_EOL
+                    . '* * * * * /bin/php /var/www/magento/bin/magento cron:run' . PHP_EOL
+                    . CrontabManagerInterface::TASKS_BLOCK_END . PHP_EOL,
+                'contentAfter' => '* * * * * /bin/php /var/www/cron.php' . PHP_EOL
+            ],
+            [
+                'contentBefore' => '* * * * * /bin/php /var/www/cron.php' . PHP_EOL
+                    . CrontabManagerInterface::TASKS_BLOCK_START . PHP_EOL
+                    . '* * * * * /bin/php /var/www/magento/bin/magento cron:run' . PHP_EOL
+                    . '* * * * * /bin/php /var/www/magento/bin/magento setup:cron:run' . PHP_EOL
+                    . CrontabManagerInterface::TASKS_BLOCK_END . PHP_EOL,
+                'contentAfter' => '* * * * * /bin/php /var/www/cron.php' . PHP_EOL
+            ],
+            [
+                'contentBefore' => '* * * * * /bin/php /var/www/cron.php' . PHP_EOL,
+                'contentAfter' => '* * * * * /bin/php /var/www/cron.php' . PHP_EOL
+            ],
+            [
+                'contentBefore' => '',
+                'contentAfter' => ''
+            ],
+        ];
+    }
+
+    /**
+     * @return void
+     * @expectedException \Magento\Framework\Exception\LocalizedException
+     * @expectedExceptionMessage List of tasks is empty
+     */
+    public function testSaveTasksWithEmptyTasksList()
+    {
+        $baseDirMock = $this->getMockBuilder(ReadInterface::class)
+            ->getMockForAbstractClass();
+        $baseDirMock->expects($this->once())
+            ->method('getAbsolutePath')
+            ->willReturn('/var/www/magento2/');
+        $logDirMock = $this->getMockBuilder(ReadInterface::class)
+            ->getMockForAbstractClass();
+        $logDirMock->expects($this->once())
+            ->method('getAbsolutePath')
+            ->willReturn('/var/www/magento2/var/log/');
+
+        $this->filesystemMock->expects($this->any())
+            ->method('getDirectoryRead')
+            ->willReturnMap([
+                [DirectoryList::ROOT, DriverPool::FILE, $baseDirMock],
+                [DirectoryList::LOG, DriverPool::FILE, $logDirMock],
+            ]);
+
+        $this->crontabManager->saveTasks([]);
+    }
+
+    /**
+     * @return void
+     * @expectedException \Magento\Framework\Exception\LocalizedException
+     * @expectedExceptionMessage Command should not be empty
+     */
+    public function testSaveTasksWithoutCommand()
+    {
+        $baseDirMock = $this->getMockBuilder(ReadInterface::class)
+            ->getMockForAbstractClass();
+        $baseDirMock->expects($this->once())
+            ->method('getAbsolutePath')
+            ->willReturn('/var/www/magento2/');
+        $logDirMock = $this->getMockBuilder(ReadInterface::class)
+            ->getMockForAbstractClass();
+        $logDirMock->expects($this->once())
+            ->method('getAbsolutePath')
+            ->willReturn('/var/www/magento2/var/log/');
+
+        $this->filesystemMock->expects($this->any())
+            ->method('getDirectoryRead')
+            ->willReturnMap([
+                [DirectoryList::ROOT, DriverPool::FILE, $baseDirMock],
+                [DirectoryList::LOG, DriverPool::FILE, $logDirMock],
+            ]);
+
+        $this->crontabManager->saveTasks([
+            'myCron' => ['expression' => '* * * * *']
+        ]);
+    }
+
+    /**
+     * @param array $tasks
+     * @param string $content
+     * @param string $contentToSave
+     * @return void
+     * @dataProvider saveTasksDataProvider
+     */
+    public function testSaveTasks($tasks, $content, $contentToSave)
+    {
+        $baseDirMock = $this->getMockBuilder(ReadInterface::class)
+            ->getMockForAbstractClass();
+        $baseDirMock->expects($this->once())
+            ->method('getAbsolutePath')
+            ->willReturn('/var/www/magento2/');
+        $logDirMock = $this->getMockBuilder(ReadInterface::class)
+            ->getMockForAbstractClass();
+        $logDirMock->expects($this->once())
+            ->method('getAbsolutePath')
+            ->willReturn('/var/www/magento2/var/log/');
+
+        $this->filesystemMock->expects($this->any())
+            ->method('getDirectoryRead')
+            ->willReturnMap([
+                [DirectoryList::ROOT, DriverPool::FILE, $baseDirMock],
+                [DirectoryList::LOG, DriverPool::FILE, $logDirMock],
+            ]);
+
+        $this->shellMock->expects($this->at(0))
+            ->method('execute')
+            ->with('crontab -l', [])
+            ->willReturn($content);
+
+        $this->shellMock->expects($this->at(1))
+            ->method('execute')
+            ->with('echo "' . $contentToSave . '" | crontab -', []);
+
+        $this->crontabManager->saveTasks($tasks);
+    }
+
+    /**
+     * @return array
+     */
+    public function saveTasksDataProvider()
+    {
+        $content = '* * * * * /bin/php /var/www/cron.php' . PHP_EOL
+            . CrontabManagerInterface::TASKS_BLOCK_START . PHP_EOL
+            . '* * * * * /bin/php /var/www/magento/bin/magento cron:run' . PHP_EOL
+            . CrontabManagerInterface::TASKS_BLOCK_END . PHP_EOL;
+
+        return [
+            [
+                'tasks' => [
+                    ['expression' => '* * * * *', 'command' => 'run.php']
+                ],
+                'content' => $content,
+                'contentToSave' => '* * * * * /bin/php /var/www/cron.php' . PHP_EOL
+                    . CrontabManagerInterface::TASKS_BLOCK_START . PHP_EOL
+                    . '* * * * * ' . PHP_BINARY . ' run.php' . PHP_EOL
+                    . CrontabManagerInterface::TASKS_BLOCK_END . PHP_EOL,
+            ],
+            [
+                'tasks' => [
+                    ['expression' => '1 2 3 4 5', 'command' => 'run.php']
+                ],
+                'content' => $content,
+                'contentToSave' => '* * * * * /bin/php /var/www/cron.php' . PHP_EOL
+                    . CrontabManagerInterface::TASKS_BLOCK_START . PHP_EOL
+                    . '1 2 3 4 5 ' . PHP_BINARY . ' run.php' . PHP_EOL
+                    . CrontabManagerInterface::TASKS_BLOCK_END . PHP_EOL,
+            ],
+            [
+                'tasks' => [
+                    ['command' => '{magentoRoot}run.php >> {magentoLog}cron.log']
+                ],
+                'content' => $content,
+                'contentToSave' => '* * * * * /bin/php /var/www/cron.php' . PHP_EOL
+                    . CrontabManagerInterface::TASKS_BLOCK_START . PHP_EOL
+                    . '* * * * * ' . PHP_BINARY . ' /var/www/magento2/run.php >>'
+                    . ' /var/www/magento2/var/log/cron.log' . PHP_EOL
+                    . CrontabManagerInterface::TASKS_BLOCK_END . PHP_EOL,
+            ],
+        ];
+    }
+}
diff --git a/lib/internal/Magento/Framework/Crontab/Test/Unit/TasksProviderTest.php b/lib/internal/Magento/Framework/Crontab/Test/Unit/TasksProviderTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..80be47cda5ef4973ad1999968dd636da0bd1757a
--- /dev/null
+++ b/lib/internal/Magento/Framework/Crontab/Test/Unit/TasksProviderTest.php
@@ -0,0 +1,34 @@
+<?php
+
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Framework\Crontab\Test\Unit;
+
+use Magento\Framework\Crontab\TasksProvider;
+
+class TasksProviderTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @return void
+     */
+    public function testTasksProviderEmpty()
+    {
+        /** @var $tasksProvider $tasksProvider */
+        $tasksProvider = new TasksProvider();
+        $this->assertSame([], $tasksProvider->getTasks());
+    }
+
+    public function testTasksProvider()
+    {
+        $tasks = [
+            'magentoCron' => ['expressin' => '* * * * *', 'command' => 'bin/magento cron:run'],
+            'magentoSetup' => ['command' => 'bin/magento setup:cron:run'],
+        ];
+
+        /** @var $tasksProvider $tasksProvider */
+        $tasksProvider = new TasksProvider($tasks);
+        $this->assertSame($tasks, $tasksProvider->getTasks());
+    }
+}
diff --git a/lib/internal/Magento/Framework/Data/CollectionDataSourceInterface.php b/lib/internal/Magento/Framework/Data/CollectionDataSourceInterface.php
index eeff60c1f61c887ef87439b680e8d73fbf6791f2..4bdf29fd1c8fc167af98cc79fd1d20c9696c7b50 100644
--- a/lib/internal/Magento/Framework/Data/CollectionDataSourceInterface.php
+++ b/lib/internal/Magento/Framework/Data/CollectionDataSourceInterface.php
@@ -5,9 +5,11 @@
  */
 namespace Magento\Framework\Data;
 
+use Magento\Framework\View\Element\Block\ArgumentInterface;
+
 /**
  * Interface CollectionDataSourceInterface
  */
-interface CollectionDataSourceInterface
+interface CollectionDataSourceInterface extends ArgumentInterface
 {
 }
diff --git a/lib/internal/Magento/Framework/View/Element/Block/ArgumentInterface.php b/lib/internal/Magento/Framework/View/Element/Block/ArgumentInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..123a75946ba775c0e1565e7689201fde8f8c9f0b
--- /dev/null
+++ b/lib/internal/Magento/Framework/View/Element/Block/ArgumentInterface.php
@@ -0,0 +1,14 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Framework\View\Element\Block;
+
+/**
+ * Block argument interface.
+ * All objects that are injected to block arguments should implement this interface.
+ */
+interface ArgumentInterface
+{
+}
diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Layout/Argument/Interpreter/ObjectTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Layout/Argument/Interpreter/ObjectTest.php
index a8f2374cc0ce11efd32b7c6e0419db5c3a799086..8de579730b154035d02b38fbdb8d07ef3315d194 100644
--- a/lib/internal/Magento/Framework/View/Test/Unit/Layout/Argument/Interpreter/ObjectTest.php
+++ b/lib/internal/Magento/Framework/View/Test/Unit/Layout/Argument/Interpreter/ObjectTest.php
@@ -34,16 +34,11 @@ class ObjectTest extends \PHPUnit_Framework_TestCase
 
     public function testEvaluate()
     {
-        $input = ['value' => self::EXPECTED_CLASS];
-        $this->_objectManager->expects(
-            $this->once()
-        )->method(
-            'create'
-        )->with(
-            self::EXPECTED_CLASS
-        )->will(
-            $this->returnValue($this)
-        );
+        $input = ['name' => 'dataSource', 'value' => self::EXPECTED_CLASS];
+        $this->_objectManager->expects($this->once())
+            ->method('create')
+            ->with(self::EXPECTED_CLASS)
+            ->willReturn($this);
 
         $actual = $this->_model->evaluate($input);
         $this->assertSame($this, $actual);
@@ -56,17 +51,18 @@ class ObjectTest extends \PHPUnit_Framework_TestCase
     {
         $this->setExpectedException($expectedException, $expectedExceptionMessage);
         $self = $this;
-        $this->_objectManager->expects($this->any())->method('create')->will(
-            $this->returnCallback(
-                function ($className) use ($self) {
-                    return $self->getMock($className);
-                }
-            )
+        $this->_objectManager->expects($this->any())->method('create')->willReturnCallback(
+            function ($className) use ($self) {
+                return $self->getMock($className);
+            }
         );
 
         $this->_model->evaluate($input);
     }
 
+    /**
+     * @return array
+     */
     public function evaluateWrongClassDataProvider()
     {
         return [