From f1494386a6e21928ecc688b9bfe91112ff8f6fab Mon Sep 17 00:00:00 2001
From: mage2-team <mage2-team@magento.com>
Date: Sun, 26 Aug 2012 22:56:20 -0700
Subject: [PATCH] Update as of 8/26/2012 * Decoupled Tag module functionality
 from other modules * Visual Design Editor:   * Implemented tracking of user
 changes history and rendering the actions at VDE toolbar   * Implemented
 compacting of user changes history. Compacting is done in order to save all
 the changes as a minimal layout update. * Improvements:   * Added Atlassian
 IDE Plugin configuration files to `.gitignore`   * Relocated `add_to_cart`,
 `checkout` and `product_edit` performance scenarios from `samples` to the
 normal `testsuite` directory. These scenarios can be used for Magento
 performance testing.   * Implemented verification of number of orders that
 were created during execution of `checkout` performance scenario   * Removed
 usage of deprecated `PHPUnit_Extensions_OutputTestCase` class from unit tests
 * Fixes:   * Fixed MySQL DB adapter to always throw exception, if it was not
 able to connect to DB because of wrong configuration. So now the adapter's
 behavior is not dependent on `error_reporting` settings.   * Added the
 missing closing tag to New Order email template   * Fixed
 `Mage_ImportExport_Model_Import_Entity_CustomerComposite` integration test
 issues   * Marked several integration tests in
 `Mage_Adminhtml_CustomerControllerTest` as incomplete, as the tested
 functionality was not MMDB-compliant   * Fixed issue with unit tests failure,
 when there was a Zend Framework installed as PEAR package   * Fixed
 `advanced_search` performance scenario to fail, if the searched product
 doesn't exist   * Fixed issue with non-escaped latest message link in admin
 backend * GitHub requests:   *
 [#48](https://github.com/magento/magento2/pull/48) -- fixed usage of a
 collection at the place, where just a single object was needed

---
 .gitignore                                    |   1 +
 CHANGELOG.markdown                            |  22 +
 .../Block/Catalog/Product/Edit/Tabs.php       |  16 -
 .../Block/Customer/Edit/Tab/Tags.php          | 122 ---
 .../Adminhtml/Block/Customer/Edit/Tabs.php    |   8 -
 .../controllers/Catalog/ProductController.php |  23 -
 .../controllers/CustomerController.php        | 569 +++++---------
 .../controllers/Sales/OrderController.php     |   7 +-
 app/code/core/Mage/Adminhtml/etc/config.xml   |   3 -
 .../Mage/Adminhtml/view/adminhtml/catalog.xml |  12 -
 .../Adminhtml/view/adminhtml/customer.xml     |  12 -
 .../view/adminhtml/notification/toolbar.phtml |   2 +-
 .../core/Mage/Catalog/Helper/Product/View.php |  56 +-
 app/code/core/Mage/Catalog/etc/config.xml     |  10 +
 .../CatalogSearch/view/frontend/result.phtml  |   4 +-
 app/code/core/Mage/Core/Helper/Js.php         |   3 +-
 .../core/Mage/DesignEditor/Block/Template.php |  23 +
 .../core/Mage/DesignEditor/Block/Toolbar.php  |  15 +-
 .../DesignEditor/Block/Toolbar/Buttons.php    |  61 ++
 .../Block/Toolbar/{Exit.php => History.php}   |  10 +-
 .../DesignEditor/Block/Wrapper/Remove.php     |  43 ++
 .../core/Mage/DesignEditor/Model/History.php  | 143 ++++
 .../DesignEditor/Model/History/Manager.php    |  83 ++
 .../Model/History/Manager/Adapter.php}        |  39 +-
 .../History/Manager/Adapter/Abstract.php      |  76 ++
 .../Model/History/Manager/Adapter/Layout.php  | 187 +++++
 .../Model/History/Manager/Collection.php      | 166 ++++
 .../core/Mage/DesignEditor/Model/Observer.php |  19 +-
 .../controllers/EditorController.php          |  58 +-
 .../Mage/DesignEditor/etc/jstranslator.xml    |  38 +
 .../DesignEditor/view/frontend/css/styles.css |  46 +-
 .../DesignEditor/view/frontend/js/base.js     | 272 +++----
 .../view/frontend/js/change/history.js        |  67 ++
 .../view/frontend/js/change/layout.js         | 333 ++++++++
 .../view/frontend/js/design_editor.js         | 717 +++++++++++++-----
 .../DesignEditor/view/frontend/layout.xml     |   4 +-
 .../DesignEditor/view/frontend/toolbar.phtml  |  50 +-
 .../view/frontend/toolbar/buttons.phtml       |  39 +
 .../toolbar/{exit.phtml => history.phtml}     |   8 +-
 .../view/frontend/wrapper/remove.phtml        |  32 +
 .../DesignEditor/view/frontend/wrapping.phtml |   9 +-
 .../Import/Entity/Product/Type/Abstract.php   |  15 -
 app/code/core/Mage/Page/etc/config.xml        |   1 -
 .../core/Mage/Reports/etc/adminhtml/acl.xml   |   5 -
 .../Rss/controllers/CatalogController.php     |  17 -
 app/code/core/Mage/Rss/etc/system.xml         |   9 -
 .../core/Mage/Rss/view/frontend/layout.xml    |   6 -
 .../core/Mage/Sales/view/email/order_new.html |   1 +
 .../Block/Adminhtml}/Assigned/Grid.php        |  28 +-
 .../Catalog/Product/Edit/Tab/Tag.php          | 164 ++++
 .../Catalog/Product/Edit/Tab/Tag/Customer.php | 164 ++++
 .../Product/Edit/Tab/Tag/Customer/Grid.php}   |  47 +-
 .../Catalog/Product/Edit/Tab/Tag/Grid.php}    |  22 +-
 .../Tag => Tag/Block/Adminhtml}/Customer.php  |   8 +-
 .../Block/Adminhtml/Customer/Edit/Tab/Tag.php | 163 ++++
 .../Adminhtml/Customer/Edit/Tab/Tag/Grid.php} |  97 ++-
 .../Block/Adminhtml}/Customer/Grid.php        |  10 +-
 .../Tag => Tag/Block/Adminhtml}/Edit.php      |  19 +-
 .../Block/Adminhtml}/Edit/Accordion.php       |   6 +-
 .../Block/Adminhtml}/Edit/Assigned.php        |   6 +-
 .../Tag => Tag/Block/Adminhtml}/Edit/Form.php |  12 +-
 .../Tag => Tag/Block/Adminhtml}/Grid/All.php  |   8 +-
 .../Block/Adminhtml}/Grid/Pending.php         |   6 +-
 .../Tag => Tag/Block/Adminhtml}/Pending.php   |   8 +-
 .../Tag => Tag/Block/Adminhtml}/Product.php   |   8 +-
 .../Block/Adminhtml}/Product/Grid.php         |  12 +-
 .../Block/Adminhtml/Report}/Customer.php      |  14 +-
 .../Adminhtml/Report}/Customer/Detail.php     |  15 +-
 .../Report}/Customer/Detail/Grid.php          |  23 +-
 .../Block/Adminhtml/Report}/Customer/Grid.php |  27 +-
 .../Block/Adminhtml/Report}/Popular.php       |  14 +-
 .../Adminhtml/Report}/Popular/Detail.php      |  16 +-
 .../Adminhtml/Report}/Popular/Detail/Grid.php |  29 +-
 .../Block/Adminhtml/Report}/Popular/Grid.php  |  24 +-
 .../Block/Adminhtml/Report}/Product.php       |  14 +-
 .../Adminhtml/Report}/Product/Detail.php      |  14 +-
 .../Adminhtml/Report}/Product/Detail/Grid.php |  23 +-
 .../Block/Adminhtml/Report}/Product/Grid.php  |  29 +-
 .../Block/Adminhtml}/Store/Switcher.php       |   6 +-
 .../Block/Tag => Tag/Block/Adminhtml}/Tag.php |  11 +-
 .../Tag => Tag/Block/Adminhtml}/Tag/Grid.php  |   6 +-
 .../Block/Catalog/Product/Rss.php}            |  17 +-
 .../Tag/Block/Catalog/Product/Rss/Link.php    | 114 +++
 .../Model/Resource/Reports}/Collection.php    |  11 +-
 .../Resource/Reports}/Customer/Collection.php |   9 +-
 .../Resource/Reports}/Product/Collection.php  |  25 +-
 .../Adminhtml/Catalog/ProductController.php   |  58 ++
 .../Adminhtml/CustomerController.php          |  91 +++
 .../Adminhtml}/Report/TagController.php       | 123 +--
 .../controllers/Adminhtml}/TagController.php  |  62 +-
 .../Mage/Tag/controllers/IndexController.php  |  36 +-
 .../Tag/controllers/Rss/CatalogController.php |  60 ++
 app/code/core/Mage/Tag/etc/adminhtml/acl.xml  |   7 +
 app/code/core/Mage/Tag/etc/config.xml         |  46 ++
 app/code/core/Mage/Tag/etc/system.xml         |  48 ++
 .../core/Mage/Tag/view/adminhtml/customer.xml |  49 ++
 .../core/Mage/Tag/view/adminhtml/product.xml  |  50 ++
 .../{Adminhtml => Tag}/view/adminhtml/tag.xml |  18 +-
 .../view/adminhtml/tag/edit/container.phtml   |   0
 .../view/adminhtml/tag/index.phtml            |   0
 .../core/Mage/Tag/view/frontend/layout.xml    |   1 +
 .../Tag/view/frontend/product/rss/link.phtml  |  30 +
 app/code/core/Mage/Tag/view/frontend/rss.xml  |  38 +
 .../iphone/Mage_Catalog/product/view.phtml    |   1 -
 .../iphone/Mage_CatalogSearch/result.phtml    |   4 +-
 .../default/iphone/Mage_Rss/layout.xml        |   6 -
 .../default/iphone/Mage_Tag/layout.xml        |   1 +
 .../default/modern/Mage_Rss/layout.xml        |   4 -
 .../default/modern/Mage_Tag/layout.xml        |   1 +
 .../controllers/CustomerControllerTest.php    |  10 +-
 .../controllers/Sales/OrderControllerTest.php |   7 +
 .../Catalog/Helper/Product/CompareTest.php    |   4 +-
 .../Mage/Catalog/Helper/Product/ViewTest.php  |  45 +-
 .../Model/Product/Type/AbstractTest.php       |   6 +-
 .../Mage/Catalog/Model/ProductTest.php        |   2 +-
 ...two_products.php => multiple_products.php} |  56 +-
 .../DesignEditor/Block/Toolbar/ExitTest.php   |   4 +-
 .../Mage/DesignEditor/Model/HistoryTest.php   | 178 +++++
 .../Mage/DesignEditor/Model/ObserverTest.php  |  44 +-
 .../_files/history/compact_log.xml            |  36 +
 .../Import/Entity/CustomerCompositeTest.php   | 196 -----
 .../Entity/Product/Type/AbstractTest.php      | 114 +++
 .../Model/Import/Entity/ProductTest.php       |  79 ++
 .../_files/customer_composite_delete.csv      |   2 -
 .../_files/customer_composite_update.csv      |   7 -
 .../Entity/_files/products_to_import.csv      |   4 +
 .../testsuite/Mage/Page/_files/robots.txt     |   1 -
 .../testsuite/Mage/Review/_files/reviews.php  |   2 +-
 .../Rss/controllers/CatalogControllerTest.php |   5 +-
 .../mage/design_editor/historyTest.js         |  30 +
 .../mage/design_editor/historyToolbarTest.js  |  31 +
 .../testsuite/mage/design_editor/pageTest.js  | 416 +++++-----
 .../framework/Magento/Scenario.php            |  42 +
 .../unit/testsuite/Magento/ConfigTest.php     |   4 +
 .../unit/testsuite/Magento/ScenarioTest.php   |  27 +
 .../Magento/_files/scenario_with_scripts.jmx  |  29 +
 .../Magento/_files/scenario_with_scripts.jtl  |  37 +
 .../_files/scenario_with_scripts_after.php    |  28 +
 .../_files/scenario_with_scripts_before.php   |  28 +
 .../testsuite/{_samples => }/add_to_cart.jmx  |   0
 .../performance/testsuite/advanced_search.jmx |  19 +-
 .../testsuite/{_samples => }/checkout.jmx     |   0
 .../performance/testsuite/checkout_after.php  |  49 ++
 .../performance/testsuite/checkout_before.php |  33 +
 .../testsuite/{_samples => }/product_edit.jmx |   0
 .../Legacy/_files/obsolete_methods.php        |   3 +-
 .../testsuite/Php/_files/whitelist/core.txt   |   2 +
 dev/tests/unit/framework/bootstrap.php        |   8 +-
 .../Mage/DesignEditor/Model/HistoryTest.php   | 226 ++++++
 .../Model/Manager/Adapter/LayoutTest.php      | 105 +++
 .../Model/_files/history/layout/move.xml      |  31 +
 .../Model/_files/history/layout/remove.xml    |  31 +
 .../Product/Edit/Tab/Tag/CustomerTest.php     |  55 ++
 .../Catalog/Product/Edit/Tab/TagTest.php      |  56 ++
 .../Product/Edit/Tab/TagTestCaseAbstract.php  | 135 ++++
 .../Adminhtml/Customer/Edit/Tab/TagTest.php   | 192 +++++
 .../Block/Catalog/Product/Rss/LinkTest.php    | 121 +++
 .../migration/Acl/Db/Logger/ConsoleTest.php   |   2 +-
 lib/Varien/Db/Adapter/Pdo/Mysql.php           |   4 +
 159 files changed, 6114 insertions(+), 1857 deletions(-)
 delete mode 100644 app/code/core/Mage/Adminhtml/Block/Customer/Edit/Tab/Tags.php
 create mode 100644 app/code/core/Mage/DesignEditor/Block/Toolbar/Buttons.php
 rename app/code/core/Mage/DesignEditor/Block/Toolbar/{Exit.php => History.php} (79%)
 create mode 100644 app/code/core/Mage/DesignEditor/Block/Wrapper/Remove.php
 create mode 100644 app/code/core/Mage/DesignEditor/Model/History.php
 create mode 100644 app/code/core/Mage/DesignEditor/Model/History/Manager.php
 rename app/code/core/Mage/{Rss/Helper/Catalog.php => DesignEditor/Model/History/Manager/Adapter.php} (51%)
 create mode 100644 app/code/core/Mage/DesignEditor/Model/History/Manager/Adapter/Abstract.php
 create mode 100644 app/code/core/Mage/DesignEditor/Model/History/Manager/Adapter/Layout.php
 create mode 100644 app/code/core/Mage/DesignEditor/Model/History/Manager/Collection.php
 create mode 100644 app/code/core/Mage/DesignEditor/etc/jstranslator.xml
 create mode 100644 app/code/core/Mage/DesignEditor/view/frontend/js/change/history.js
 create mode 100644 app/code/core/Mage/DesignEditor/view/frontend/js/change/layout.js
 create mode 100644 app/code/core/Mage/DesignEditor/view/frontend/toolbar/buttons.phtml
 rename app/code/core/Mage/DesignEditor/view/frontend/toolbar/{exit.phtml => history.phtml} (83%)
 create mode 100644 app/code/core/Mage/DesignEditor/view/frontend/wrapper/remove.phtml
 rename app/code/core/Mage/{Adminhtml/Block/Tag => Tag/Block/Adminhtml}/Assigned/Grid.php (88%)
 create mode 100644 app/code/core/Mage/Tag/Block/Adminhtml/Catalog/Product/Edit/Tab/Tag.php
 create mode 100644 app/code/core/Mage/Tag/Block/Adminhtml/Catalog/Product/Edit/Tab/Tag/Customer.php
 rename app/code/core/Mage/{Adminhtml/Block/Catalog/Product/Edit/Tab/Tag/Customer.php => Tag/Block/Adminhtml/Catalog/Product/Edit/Tab/Tag/Customer/Grid.php} (63%)
 rename app/code/core/Mage/{Adminhtml/Block/Catalog/Product/Edit/Tab/Tag.php => Tag/Block/Adminhtml/Catalog/Product/Edit/Tab/Tag/Grid.php} (81%)
 rename app/code/core/Mage/{Adminhtml/Block/Tag => Tag/Block/Adminhtml}/Customer.php (90%)
 create mode 100644 app/code/core/Mage/Tag/Block/Adminhtml/Customer/Edit/Tab/Tag.php
 rename app/code/core/Mage/{Adminhtml/Block/Customer/Edit/Tab/Tag.php => Tag/Block/Adminhtml/Customer/Edit/Tab/Tag/Grid.php} (50%)
 rename app/code/core/Mage/{Adminhtml/Block/Tag => Tag/Block/Adminhtml}/Customer/Grid.php (93%)
 rename app/code/core/Mage/{Adminhtml/Block/Tag => Tag/Block/Adminhtml}/Edit.php (88%)
 rename app/code/core/Mage/{Adminhtml/Block/Tag => Tag/Block/Adminhtml}/Edit/Accordion.php (94%)
 rename app/code/core/Mage/{Adminhtml/Block/Tag => Tag/Block/Adminhtml}/Edit/Assigned.php (93%)
 rename app/code/core/Mage/{Adminhtml/Block/Tag => Tag/Block/Adminhtml}/Edit/Form.php (91%)
 rename app/code/core/Mage/{Adminhtml/Block/Tag => Tag/Block/Adminhtml}/Grid/All.php (94%)
 rename app/code/core/Mage/{Adminhtml/Block/Tag => Tag/Block/Adminhtml}/Grid/Pending.php (97%)
 rename app/code/core/Mage/{Adminhtml/Block/Tag => Tag/Block/Adminhtml}/Pending.php (90%)
 rename app/code/core/Mage/{Adminhtml/Block/Tag => Tag/Block/Adminhtml}/Product.php (90%)
 rename app/code/core/Mage/{Adminhtml/Block/Tag => Tag/Block/Adminhtml}/Product/Grid.php (92%)
 rename app/code/core/Mage/{Adminhtml/Block/Report/Tag => Tag/Block/Adminhtml/Report}/Customer.php (76%)
 rename app/code/core/Mage/{Adminhtml/Block/Report/Tag => Tag/Block/Adminhtml/Report}/Customer/Detail.php (79%)
 rename app/code/core/Mage/{Adminhtml/Block/Report/Tag => Tag/Block/Adminhtml/Report}/Customer/Detail/Grid.php (79%)
 rename app/code/core/Mage/{Adminhtml/Block/Report/Tag => Tag/Block/Adminhtml/Report}/Customer/Grid.php (76%)
 rename app/code/core/Mage/{Adminhtml/Block/Report/Tag => Tag/Block/Adminhtml/Report}/Popular.php (84%)
 rename app/code/core/Mage/{Adminhtml/Block/Report/Tag => Tag/Block/Adminhtml/Report}/Popular/Detail.php (77%)
 rename app/code/core/Mage/{Adminhtml/Block/Report/Tag => Tag/Block/Adminhtml/Report}/Popular/Detail/Grid.php (72%)
 rename app/code/core/Mage/{Adminhtml/Block/Report/Tag => Tag/Block/Adminhtml/Report}/Popular/Grid.php (81%)
 rename app/code/core/Mage/{Adminhtml/Block/Report/Tag => Tag/Block/Adminhtml/Report}/Product.php (76%)
 rename app/code/core/Mage/{Adminhtml/Block/Report/Tag => Tag/Block/Adminhtml/Report}/Product/Detail.php (78%)
 rename app/code/core/Mage/{Adminhtml/Block/Report/Tag => Tag/Block/Adminhtml/Report}/Product/Detail/Grid.php (77%)
 rename app/code/core/Mage/{Adminhtml/Block/Report/Tag => Tag/Block/Adminhtml/Report}/Product/Grid.php (76%)
 rename app/code/core/Mage/{Adminhtml/Block/Tag => Tag/Block/Adminhtml}/Store/Switcher.php (91%)
 rename app/code/core/Mage/{Adminhtml/Block/Tag => Tag/Block/Adminhtml}/Tag.php (83%)
 rename app/code/core/Mage/{Adminhtml/Block/Tag => Tag/Block/Adminhtml}/Tag/Grid.php (97%)
 rename app/code/core/Mage/{Rss/Block/Catalog/Tag.php => Tag/Block/Catalog/Product/Rss.php} (90%)
 create mode 100644 app/code/core/Mage/Tag/Block/Catalog/Product/Rss/Link.php
 rename app/code/core/Mage/{Reports/Model/Resource/Tag => Tag/Model/Resource/Reports}/Collection.php (90%)
 mode change 100755 => 100644
 rename app/code/core/Mage/{Reports/Model/Resource/Tag => Tag/Model/Resource/Reports}/Customer/Collection.php (91%)
 mode change 100755 => 100644
 rename app/code/core/Mage/{Reports/Model/Resource/Tag => Tag/Model/Resource/Reports}/Product/Collection.php (86%)
 mode change 100755 => 100644
 create mode 100644 app/code/core/Mage/Tag/controllers/Adminhtml/Catalog/ProductController.php
 create mode 100644 app/code/core/Mage/Tag/controllers/Adminhtml/CustomerController.php
 rename app/code/core/Mage/{Adminhtml/controllers => Tag/controllers/Adminhtml}/Report/TagController.php (61%)
 rename app/code/core/Mage/{Adminhtml/controllers => Tag/controllers/Adminhtml}/TagController.php (82%)
 create mode 100644 app/code/core/Mage/Tag/controllers/Rss/CatalogController.php
 create mode 100644 app/code/core/Mage/Tag/etc/system.xml
 create mode 100644 app/code/core/Mage/Tag/view/adminhtml/customer.xml
 create mode 100644 app/code/core/Mage/Tag/view/adminhtml/product.xml
 rename app/code/core/Mage/{Adminhtml => Tag}/view/adminhtml/tag.xml (84%)
 rename app/code/core/Mage/{Adminhtml => Tag}/view/adminhtml/tag/edit/container.phtml (100%)
 rename app/code/core/Mage/{Adminhtml => Tag}/view/adminhtml/tag/index.phtml (100%)
 create mode 100644 app/code/core/Mage/Tag/view/frontend/product/rss/link.phtml
 create mode 100644 app/code/core/Mage/Tag/view/frontend/rss.xml
 rename dev/tests/integration/testsuite/Mage/Catalog/_files/{two_products.php => multiple_products.php} (59%)
 create mode 100644 dev/tests/integration/testsuite/Mage/DesignEditor/Model/HistoryTest.php
 create mode 100644 dev/tests/integration/testsuite/Mage/DesignEditor/_files/history/compact_log.xml
 delete mode 100644 dev/tests/integration/testsuite/Mage/ImportExport/Model/Import/Entity/CustomerCompositeTest.php
 create mode 100644 dev/tests/integration/testsuite/Mage/ImportExport/Model/Import/Entity/Product/Type/AbstractTest.php
 delete mode 100644 dev/tests/integration/testsuite/Mage/ImportExport/Model/Import/Entity/_files/customer_composite_delete.csv
 delete mode 100644 dev/tests/integration/testsuite/Mage/ImportExport/Model/Import/Entity/_files/customer_composite_update.csv
 create mode 100644 dev/tests/integration/testsuite/Mage/ImportExport/Model/Import/Entity/_files/products_to_import.csv
 create mode 100644 dev/tests/js/testsuite/mage/design_editor/historyTest.js
 create mode 100644 dev/tests/js/testsuite/mage/design_editor/historyToolbarTest.js
 create mode 100644 dev/tests/performance/framework/tests/unit/testsuite/Magento/_files/scenario_with_scripts.jmx
 create mode 100644 dev/tests/performance/framework/tests/unit/testsuite/Magento/_files/scenario_with_scripts.jtl
 create mode 100644 dev/tests/performance/framework/tests/unit/testsuite/Magento/_files/scenario_with_scripts_after.php
 create mode 100644 dev/tests/performance/framework/tests/unit/testsuite/Magento/_files/scenario_with_scripts_before.php
 rename dev/tests/performance/testsuite/{_samples => }/add_to_cart.jmx (100%)
 rename dev/tests/performance/testsuite/{_samples => }/checkout.jmx (100%)
 create mode 100644 dev/tests/performance/testsuite/checkout_after.php
 create mode 100644 dev/tests/performance/testsuite/checkout_before.php
 rename dev/tests/performance/testsuite/{_samples => }/product_edit.jmx (100%)
 create mode 100644 dev/tests/unit/testsuite/Mage/DesignEditor/Model/HistoryTest.php
 create mode 100644 dev/tests/unit/testsuite/Mage/DesignEditor/Model/Manager/Adapter/LayoutTest.php
 create mode 100644 dev/tests/unit/testsuite/Mage/DesignEditor/Model/_files/history/layout/move.xml
 create mode 100644 dev/tests/unit/testsuite/Mage/DesignEditor/Model/_files/history/layout/remove.xml
 create mode 100644 dev/tests/unit/testsuite/Mage/Tag/Block/Adminhtml/Catalog/Product/Edit/Tab/Tag/CustomerTest.php
 create mode 100644 dev/tests/unit/testsuite/Mage/Tag/Block/Adminhtml/Catalog/Product/Edit/Tab/TagTest.php
 create mode 100644 dev/tests/unit/testsuite/Mage/Tag/Block/Adminhtml/Catalog/Product/Edit/Tab/TagTestCaseAbstract.php
 create mode 100644 dev/tests/unit/testsuite/Mage/Tag/Block/Adminhtml/Customer/Edit/Tab/TagTest.php
 create mode 100644 dev/tests/unit/testsuite/Mage/Tag/Block/Catalog/Product/Rss/LinkTest.php

diff --git a/.gitignore b/.gitignore
index 7ac75f34ecb..82c0d67e570 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,6 +4,7 @@
 /.metadata
 /.project
 /.settings
+atlassian*
 /index.php
 /nbproject
 /sitemap
diff --git a/CHANGELOG.markdown b/CHANGELOG.markdown
index 3ef1a25616d..85f22179cd1 100644
--- a/CHANGELOG.markdown
+++ b/CHANGELOG.markdown
@@ -1,3 +1,25 @@
+Update as of 8/26/2012
+======================
+* Decoupled Tag module functionality from other modules
+* Visual Design Editor:
+  * Implemented tracking of user changes history and rendering the actions at VDE toolbar
+  * Implemented compacting of user changes history. Compacting is done in order to save all the changes as a minimal layout update.
+* Improvements:
+  * Added Atlassian IDE Plugin configuration files to `.gitignore`
+  * Relocated `add_to_cart`, `checkout` and `product_edit` performance scenarios from `samples` to the normal `testsuite` directory. These scenarios can be used for Magento performance testing.
+  * Implemented verification of number of orders that were created during execution of `checkout` performance scenario
+  * Removed usage of deprecated `PHPUnit_Extensions_OutputTestCase` class from unit tests
+* Fixes:
+  * Fixed MySQL DB adapter to always throw exception, if it was not able to connect to DB because of wrong configuration. So now the adapter's behavior is not dependent on `error_reporting` settings.
+  * Added the missing closing tag to New Order email template
+  * Fixed `Mage_ImportExport_Model_Import_Entity_CustomerComposite` integration test issues
+  * Marked several integration tests in `Mage_Adminhtml_CustomerControllerTest` as incomplete, as the tested functionality was not MMDB-compliant
+  * Fixed issue with unit tests failure, when there was a Zend Framework installed as PEAR package
+  * Fixed `advanced_search` performance scenario to fail, if the searched product doesn't exist
+  * Fixed issue with non-escaped latest message link in admin backend
+* GitHub requests:
+  * [#48](https://github.com/magento/magento2/pull/48) -- fixed usage of a collection at the place, where just a single object was needed
+
 Update as of 8/15/2012
 ======================
 * Refactored ACL functionality:
diff --git a/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Edit/Tabs.php b/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Edit/Tabs.php
index 22ea61a87c2..2c8568e270c 100644
--- a/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Edit/Tabs.php
+++ b/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Edit/Tabs.php
@@ -154,22 +154,6 @@ class Mage_Adminhtml_Block_Catalog_Product_Edit_Tabs extends Mage_Adminhtml_Bloc
                         ));
                     }
                 }
-                if (Mage::helper('Mage_Catalog_Helper_Data')->isModuleEnabled('Mage_Tag')) {
-                    if (Mage::getSingleton('Mage_Core_Model_Authorization')->isAllowed('Mage_Tag::tag')){
-                        $this->addTab('tags', array(
-                         'label'     => Mage::helper('Mage_Catalog_Helper_Data')->__('Product Tags'),
-                         'url'   => $this->getUrl('*/*/tagGrid', array('_current' => true)),
-                         'class' => 'ajax',
-                        ));
-
-                        $this->addTab('customers_tags', array(
-                            'label'     => Mage::helper('Mage_Catalog_Helper_Data')->__('Customers Tagged Product'),
-                            'url'   => $this->getUrl('*/*/tagCustomerGrid', array('_current' => true)),
-                            'class' => 'ajax',
-                        ));
-                    }
-                }
-
             }
 
             /**
diff --git a/app/code/core/Mage/Adminhtml/Block/Customer/Edit/Tab/Tags.php b/app/code/core/Mage/Adminhtml/Block/Customer/Edit/Tab/Tags.php
deleted file mode 100644
index 34a5c15acc7..00000000000
--- a/app/code/core/Mage/Adminhtml/Block/Customer/Edit/Tab/Tags.php
+++ /dev/null
@@ -1,122 +0,0 @@
-<?php
-/**
- * Magento
- *
- * NOTICE OF LICENSE
- *
- * This source file is subject to the Open Software License (OSL 3.0)
- * that is bundled with this package in the file LICENSE.txt.
- * It is also available through the world-wide-web at this URL:
- * http://opensource.org/licenses/osl-3.0.php
- * If you did not receive a copy of the license and are unable to
- * obtain it through the world-wide-web, please send an email
- * to license@magentocommerce.com so we can send you a copy immediately.
- *
- * DISCLAIMER
- *
- * Do not edit or add to this file if you wish to upgrade Magento to newer
- * versions in the future. If you wish to customize Magento for your
- * needs please refer to http://www.magentocommerce.com for more information.
- *
- * @category    Mage
- * @package     Mage_Adminhtml
- * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
- * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
- */
-
-/**
- * Adminhtml customer orders grid block
- *
- * @category   Mage
- * @package    Mage_Adminhtml
- * @author      Magento Core Team <core@magentocommerce.com>
- */
-class Mage_Adminhtml_Block_Customer_Edit_Tab_Tags extends Mage_Adminhtml_Block_Widget_Grid
-{
-
-    public function __construct()
-    {
-        parent::__construct();
-        $this->setId('ordersGrid');
-        $this->setUseAjax(true);
-    }
-
-    protected function _prepareCollection()
-    {
-        $collection = Mage::getResourceModel('Mage_Customer_Model_Resource_Customer_Collection')
-            ->addNameToSelect()
-            ->addAttributeToSelect('email')
-            ->addAttributeToSelect('created_at')
-            ->joinAttribute('billing_postcode', 'customer_address/postcode', 'default_billing')
-            ->joinAttribute('billing_city', 'customer_address/city', 'default_billing')
-            ->joinAttribute('billing_telephone', 'customer_address/telephone', 'default_billing')
-            ->joinAttribute('billing_country_id', 'customer_address/country_id', 'default_billing');
-
-        $this->setCollection($collection);
-
-        return parent::_prepareCollection();
-    }
-
-    protected function _prepareColumns()
-    {
-        $this->addColumn('entity_id', array(
-            'header'    => Mage::helper('Mage_Customer_Helper_Data')->__('ID'),
-            'width'     =>5,
-            'align'     =>'center',
-            'sortable'  =>true,
-            'index'     =>'entity_id'
-        ));
-        $this->addColumn('name', array(
-            'header'    => Mage::helper('Mage_Customer_Helper_Data')->__('Name'),
-            'index'     =>'name'
-        ));
-        $this->addColumn('email', array(
-            'header'    => Mage::helper('Mage_Customer_Helper_Data')->__('Email'),
-            'width'     =>40,
-            'align'     =>'center',
-            'index'     =>'email'
-        ));
-        $this->addColumn('telephone', array(
-            'header'    => Mage::helper('Mage_Customer_Helper_Data')->__('Telephone'),
-            'align'     =>'center',
-            'index'     =>'billing_telephone'
-        ));
-        $this->addColumn('billing_postcode', array(
-            'header'    => Mage::helper('Mage_Customer_Helper_Data')->__('ZIP/Post Code'),
-            'index'     =>'billing_postcode',
-        ));
-        $this->addColumn('billing_country_id', array(
-            'header'    => Mage::helper('Mage_Customer_Helper_Data')->__('Country'),
-            'type'      => 'country',
-            'index'     => 'billing_country_id',
-        ));
-        $this->addColumn('customer_since', array(
-            'header'    => Mage::helper('Mage_Customer_Helper_Data')->__('Customer Since'),
-            'type'      => 'date',
-            'format'    => 'Y.m.d',
-            'index'     =>'created_at',
-        ));
-        $this->addColumn('action', array(
-            'header'    => Mage::helper('Mage_Customer_Helper_Data')->__('Action'),
-            'align'     =>'center',
-            'format'    =>'<a href="'.$this->getUrl('*/sales/edit/id/$entity_id').'">'.Mage::helper('Mage_Customer_Helper_Data')->__('Edit').'</a>',
-            'filter'    =>false,
-            'sortable'  =>false,
-            'is_system' =>true
-        ));
-
-        $this->setColumnFilter('entity_id')
-            ->setColumnFilter('email')
-            ->setColumnFilter('name');
-
-        $this->addExportType('*/*/exportCsv', Mage::helper('Mage_Customer_Helper_Data')->__('CSV'));
-        $this->addExportType('*/*/exportXml', Mage::helper('Mage_Customer_Helper_Data')->__('Excel XML'));
-        return parent::_prepareColumns();
-    }
-
-    public function getGridUrl()
-    {
-        return $this->getUrl('*/*/index', array('_current'=>true));
-    }
-
-}
diff --git a/app/code/core/Mage/Adminhtml/Block/Customer/Edit/Tabs.php b/app/code/core/Mage/Adminhtml/Block/Customer/Edit/Tabs.php
index db6cef48a92..20516d0bee4 100644
--- a/app/code/core/Mage/Adminhtml/Block/Customer/Edit/Tabs.php
+++ b/app/code/core/Mage/Adminhtml/Block/Customer/Edit/Tabs.php
@@ -108,14 +108,6 @@ class Mage_Adminhtml_Block_Customer_Edit_Tabs extends Mage_Adminhtml_Block_Widge
                     'url'       => $this->getUrl('*/*/productReviews', array('_current' => true)),
                 ));
             }
-
-            if (Mage::getSingleton('Mage_Core_Model_Authorization')->isAllowed('Mage_Tag::tag')) {
-                $this->addTab('tags', array(
-                    'label'     => Mage::helper('Mage_Customer_Helper_Data')->__('Product Tags'),
-                    'class'     => 'ajax',
-                    'url'       => $this->getUrl('*/*/productTags', array('_current' => true)),
-                ));
-            }
         }
 
         $this->_updateActiveTab();
diff --git a/app/code/core/Mage/Adminhtml/controllers/Catalog/ProductController.php b/app/code/core/Mage/Adminhtml/controllers/Catalog/ProductController.php
index 38e1ec2370f..a918412713a 100644
--- a/app/code/core/Mage/Adminhtml/controllers/Catalog/ProductController.php
+++ b/app/code/core/Mage/Adminhtml/controllers/Catalog/ProductController.php
@@ -809,17 +809,6 @@ class Mage_Adminhtml_Catalog_ProductController extends Mage_Adminhtml_Controller
             ->setRedirect($this->getUrl('*/*/', array('store'=>$this->getRequest()->getParam('store'))));
     }
 
-    /**
-     * Get tag grid
-     */
-    public function tagGridAction()
-    {
-        $this->loadLayout();
-        $this->getLayout()->getBlock('admin.product.tags')
-            ->setProductId($this->getRequest()->getParam('id'));
-        $this->renderLayout();
-    }
-
     /**
      * Get alerts price grid
      */
@@ -936,18 +925,6 @@ class Mage_Adminhtml_Catalog_ProductController extends Mage_Adminhtml_Controller
         }
     }
 
-    /**
-     * Get tag customer grid
-     *
-     */
-    public function tagCustomerGridAction()
-    {
-        $this->loadLayout();
-        $this->getLayout()->getBlock('admin.product.tags.customers')
-                ->setProductId($this->getRequest()->getParam('id'));
-        $this->renderLayout();
-    }
-
     public function quickCreateAction()
     {
         $result = array();
diff --git a/app/code/core/Mage/Adminhtml/controllers/CustomerController.php b/app/code/core/Mage/Adminhtml/controllers/CustomerController.php
index b4055b65021..527346b2640 100644
--- a/app/code/core/Mage/Adminhtml/controllers/CustomerController.php
+++ b/app/code/core/Mage/Adminhtml/controllers/CustomerController.php
@@ -34,72 +34,18 @@
 class Mage_Adminhtml_CustomerController extends Mage_Adminhtml_Controller_Action
 {
 
-    /**
-     * @var Mage_Core_Model_Config
-     */
-    protected $_objectFactory;
-
-    /**
-     * Event manager
-     *
-     * @var Mage_Core_Model_Event_Manager
-     */
-    protected $_eventManager;
-
-    /**
-     * Registry model
-     *
-     * @var Mage_Core_Model_Registry
-     */
-    protected $_registryManager;
-
-    /**
-     * ACL
-     *
-     * @var Mage_Backend_Model_Auth_Session
-     */
-    protected $_acl;
-
-    /**
-     * Constructor
-     *
-     * @param Zend_Controller_Request_Abstract $request
-     * @param Zend_Controller_Response_Abstract $response
-     * @param array $invokeArgs
-     */
-    public function __construct(Zend_Controller_Request_Abstract $request,
-        Zend_Controller_Response_Abstract $response,
-        array $invokeArgs = array()
-    ) {
-        parent::__construct($request, $response, $invokeArgs);
-
-        $this->_objectFactory = isset($invokeArgs['objectFactory']) ? $invokeArgs['objectFactory'] : Mage::getConfig();
-
-        $this->_registryManager = isset($invokeArgs['registry']) ?
-            $invokeArgs['registry'] :
-            Mage::getSingleton('Mage_Core_Model_Registry');
-
-        $this->_acl = isset($invokeArgs['acl']) ?
-            $invokeArgs['acl'] :
-            Mage::getSingleton('Mage_Core_Model_Authorization');
-
-        $this->_eventManager = isset($invokeArgs['eventManager']) ?
-            $invokeArgs['eventManager'] :
-            Mage::getSingleton('Mage_Core_Model_Event_Manager');
-    }
-
     protected function _initCustomer($idFieldName = 'id')
     {
         $this->_title($this->__('Customers'))->_title($this->__('Manage Customers'));
 
         $customerId = (int) $this->getRequest()->getParam($idFieldName);
-        $customer = $this->_objectFactory->getModelInstance('Mage_Customer_Model_Customer');
+        $customer = Mage::getModel('Mage_Customer_Model_Customer');
 
         if ($customerId) {
             $customer->load($customerId);
         }
 
-        $this->_registryManager->register('current_customer', $customer);
+        Mage::register('current_customer', $customer);
         return $this;
     }
 
@@ -131,8 +77,8 @@ class Mage_Adminhtml_CustomerController extends Mage_Adminhtml_Controller_Action
         /**
          * Add breadcrumb item
          */
-        $this->_addBreadcrumb($this->_getHelper()->__('Customers'), $this->_getHelper()->__('Customers'));
-        $this->_addBreadcrumb($this->_getHelper()->__('Manage Customers'), $this->_getHelper()->__('Manage Customers'));
+        $this->_addBreadcrumb(Mage::helper('Mage_Adminhtml_Helper_Data')->__('Customers'), Mage::helper('Mage_Adminhtml_Helper_Data')->__('Customers'));
+        $this->_addBreadcrumb(Mage::helper('Mage_Adminhtml_Helper_Data')->__('Manage Customers'), Mage::helper('Mage_Adminhtml_Helper_Data')->__('Manage Customers'));
 
         $this->renderLayout();
     }
@@ -152,10 +98,10 @@ class Mage_Adminhtml_CustomerController extends Mage_Adminhtml_Controller_Action
         $this->loadLayout();
 
         /* @var $customer Mage_Customer_Model_Customer */
-        $customer = $this->_registryManager->registry('current_customer');
+        $customer = Mage::registry('current_customer');
 
         // set entered data if was error when we do save
-        $data = $this->_getSession()->getCustomerData(true);
+        $data = Mage::getSingleton('Mage_Adminhtml_Model_Session')->getCustomerData(true);
 
         // restore data from SESSION
         if ($data) {
@@ -164,7 +110,7 @@ class Mage_Adminhtml_CustomerController extends Mage_Adminhtml_Controller_Action
 
             if (isset($data['account'])) {
                 /* @var $customerForm Mage_Customer_Model_Form */
-                $customerForm = $this->_objectFactory->getModelInstance('Mage_Customer_Model_Form');
+                $customerForm = Mage::getModel('Mage_Customer_Model_Form');
                 $customerForm->setEntity($customer)
                     ->setFormCode('adminhtml_customer')
                     ->setIsAjaxRequest(true);
@@ -174,7 +120,7 @@ class Mage_Adminhtml_CustomerController extends Mage_Adminhtml_Controller_Action
 
             if (isset($data['address']) && is_array($data['address'])) {
                 /* @var $addressForm Mage_Customer_Model_Form */
-                $addressForm = $this->_objectFactory->getModelInstance('Mage_Customer_Model_Form');
+                $addressForm = Mage::getModel('Mage_Customer_Model_Form');
                 $addressForm->setFormCode('adminhtml_customer_address');
 
                 foreach (array_keys($data['address']) as $addressId) {
@@ -184,7 +130,7 @@ class Mage_Adminhtml_CustomerController extends Mage_Adminhtml_Controller_Action
 
                     $address = $customer->getAddressItemById($addressId);
                     if (!$address) {
-                        $address = $this->_objectFactory->getModelInstance('Mage_Customer_Model_Address');
+                        $address = Mage::getModel('Mage_Customer_Model_Address');
                         $customer->addAddress($address);
                     }
 
@@ -219,15 +165,15 @@ class Mage_Adminhtml_CustomerController extends Mage_Adminhtml_Controller_Action
     public function deleteAction()
     {
         $this->_initCustomer();
-        $customer = $this->_registryManager->registry('current_customer');
+        $customer = Mage::registry('current_customer');
         if ($customer->getId()) {
             try {
                 $customer->load($customer->getId());
                 $customer->delete();
-                $this->_getSession()->addSuccess($this->_getHelper()->__('The customer has been deleted.'));
+                Mage::getSingleton('Mage_Adminhtml_Model_Session')->addSuccess(Mage::helper('Mage_Adminhtml_Helper_Data')->__('The customer has been deleted.'));
             }
             catch (Exception $e){
-                $this->_getSession()->addError($e->getMessage());
+                Mage::getSingleton('Mage_Adminhtml_Model_Session')->addError($e->getMessage());
             }
         }
         $this->_redirect('*/customer');
@@ -240,64 +186,184 @@ class Mage_Adminhtml_CustomerController extends Mage_Adminhtml_Controller_Action
     {
         $data = $this->getRequest()->getPost();
         if ($data) {
+            $redirectBack = $this->getRequest()->getParam('back', false);
+            $this->_initCustomer('customer_id');
 
             /** @var $customer Mage_Customer_Model_Customer */
-            $this->_initCustomer('customer_id');
-            $customer = $this->_registryManager->registry('current_customer');
-            if (!$this->_processData($customer, $data)) {
+            $customer = Mage::registry('current_customer');
+
+            /** @var $customerForm Mage_Customer_Model_Form */
+            $customerForm = Mage::getModel('Mage_Customer_Model_Form');
+            $customerForm->setEntity($customer)
+                ->setFormCode('adminhtml_customer')
+                ->ignoreInvisible(false)
+            ;
+
+            $formData = $customerForm->extractData($this->getRequest(), 'account');
+
+            // Handle 'disable auto_group_change' attribute
+            if (isset($formData['disable_auto_group_change'])) {
+                $formData['disable_auto_group_change'] = empty($formData['disable_auto_group_change']) ? '0' : '1';
+            }
+
+            $errors = $customerForm->validateData($formData);
+            if ($errors !== true) {
+                foreach ($errors as $error) {
+                    $this->_getSession()->addError($error);
+                }
+                $this->_getSession()->setCustomerData($data);
+                $this->getResponse()->setRedirect($this->getUrl('*/customer/edit', array('id' => $customer->getId())));
                 return;
             }
 
+            $customerForm->compactData($formData);
+
             // Unset template data
             if (isset($data['address']['_template_'])) {
                 unset($data['address']['_template_']);
             }
 
-            if (!$this->_processAddress($customer, $data)) {
-                return;
+            $modifiedAddresses = array();
+            if (!empty($data['address'])) {
+                /** @var $addressForm Mage_Customer_Model_Form */
+                $addressForm = Mage::getModel('Mage_Customer_Model_Form');
+                $addressForm->setFormCode('adminhtml_customer_address')->ignoreInvisible(false);
+
+                foreach (array_keys($data['address']) as $index) {
+                    $address = $customer->getAddressItemById($index);
+                    if (!$address) {
+                        $address = Mage::getModel('Mage_Customer_Model_Address');
+                    }
+
+                    $requestScope = sprintf('address/%s', $index);
+                    $formData = $addressForm->setEntity($address)
+                        ->extractData($this->getRequest(), $requestScope);
+
+                    // Set default billing and shipping flags to address
+                    $isDefaultBilling = isset($data['account']['default_billing'])
+                        && $data['account']['default_billing'] == $index;
+                    $address->setIsDefaultBilling($isDefaultBilling);
+                    $isDefaultShipping = isset($data['account']['default_shipping'])
+                        && $data['account']['default_shipping'] == $index;
+                    $address->setIsDefaultShipping($isDefaultShipping);
+
+                    $errors = $addressForm->validateData($formData);
+                    if ($errors !== true) {
+                        foreach ($errors as $error) {
+                            $this->_getSession()->addError($error);
+                        }
+                        $this->_getSession()->setCustomerData($data);
+                        $this->getResponse()->setRedirect($this->getUrl('*/customer/edit', array(
+                            'id' => $customer->getId())
+                        ));
+                        return;
+                    }
+
+                    $addressForm->compactData($formData);
+
+                    // Set post_index for detect default billing and shipping addresses
+                    $address->setPostIndex($index);
+
+                    if ($address->getId()) {
+                        $modifiedAddresses[] = $address->getId();
+                    } else {
+                        $customer->addAddress($address);
+                    }
+                }
+            }
+
+            // Default billing and shipping
+            if (isset($data['account']['default_billing'])) {
+                $customer->setData('default_billing', $data['account']['default_billing']);
+            }
+            if (isset($data['account']['default_shipping'])) {
+                $customer->setData('default_shipping', $data['account']['default_shipping']);
+            }
+            if (isset($data['account']['confirmation'])) {
+                $customer->setData('confirmation', $data['account']['confirmation']);
+            }
+
+            // Mark not modified customer addresses for delete
+            foreach ($customer->getAddressesCollection() as $customerAddress) {
+                if ($customerAddress->getId() && !in_array($customerAddress->getId(), $modifiedAddresses)) {
+                    $customerAddress->setData('_deleted', true);
+                }
+            }
+
+            if (Mage::getSingleton('Mage_Core_Model_Authorization')
+                ->isAllowed(Mage_Backend_Model_Acl_Config::ACL_RESOURCE_ALL)
+                && !$customer->getConfirmation()
+            ) {
+                $customer->setIsSubscribed(isset($data['subscription']));
             }
 
-            $this->_processSubscriptionOptions($customer, $data);
+            if (isset($data['account']['sendemail_store_id'])) {
+                $customer->setSendemailStoreId($data['account']['sendemail_store_id']);
+            }
 
             $isNewCustomer = $customer->isObjectNew();
             try {
                 $sendPassToEmail = false;
                 // Force new customer confirmation
                 if ($isNewCustomer) {
-                    $sendPassToEmail = $this->_processPassword($customer, $data);
+                    $customer->setPassword($data['account']['password']);
+                    $customer->setForceConfirmed(true);
+                    if ($customer->getPassword() == 'auto') {
+                        $sendPassToEmail = true;
+                        $customer->setPassword($customer->generatePassword());
+                    }
                 }
 
-                $this->_eventManager->dispatch(
-                    'adminhtml_customer_prepare_save',
-                    array('customer' => $customer, 'request' => $this->getRequest())
-                );
+                Mage::dispatchEvent('adminhtml_customer_prepare_save', array(
+                    'customer'  => $customer,
+                    'request'   => $this->getRequest()
+                ));
 
                 $customer->save();
 
                 // Send welcome email
-                $data = $this->_sendWelcomeEmail($customer, $data, $sendPassToEmail, $isNewCustomer);
+                if ($customer->getWebsiteId() && (isset($data['account']['sendemail']) || $sendPassToEmail)) {
+                    $storeId = $customer->getSendemailStoreId();
+                    if ($isNewCustomer) {
+                        $customer->sendNewAccountEmail('registered', '', $storeId);
+                    } elseif ((!$customer->getConfirmation())) {
+                        // Confirm not confirmed customer
+                        $customer->sendNewAccountEmail('confirmed', '', $storeId);
+                    }
+                }
 
-                $data = $this->_changePassword($customer, $data);
+                if (!empty($data['account']['new_password'])) {
+                    $newPassword = $data['account']['new_password'];
+                    if ($newPassword == 'auto') {
+                        $newPassword = $customer->generatePassword();
+                    }
+                    $customer->changePassword($newPassword);
+                    $customer->sendPasswordReminderEmail();
+                }
 
-                $this->_session->addSuccess($this->_getHelper()->__('The customer has been saved.'));
-                $this->_eventManager->dispatch(
-                    'adminhtml_customer_save_after',
-                    array('customer'  => $customer, 'request'   => $this->getRequest())
+                Mage::getSingleton('Mage_Adminhtml_Model_Session')->addSuccess(
+                    Mage::helper('Mage_Adminhtml_Helper_Data')->__('The customer has been saved.')
                 );
+                Mage::dispatchEvent('adminhtml_customer_save_after', array(
+                    'customer'  => $customer,
+                    'request'   => $this->getRequest()
+                ));
 
-                if ($this->getRequest()->getParam('back', false)) {
-                    $this->_redirect('*/*/edit', array( 'id' => $customer->getId(), '_current' => true));
+                if ($redirectBack) {
+                    $this->_redirect('*/*/edit', array(
+                        'id' => $customer->getId(),
+                        '_current' => true
+                    ));
                     return;
                 }
             } catch (Mage_Core_Exception $e) {
-                $this->_session->addError($e->getMessage());
-                $this->_session->setCustomerData($data);
+                $this->_getSession()->addError($e->getMessage());
+                $this->_getSession()->setCustomerData($data);
                 $this->getResponse()->setRedirect($this->getUrl('*/customer/edit', array('id' => $customer->getId())));
-                return;
             } catch (Exception $e) {
-                $this->_session->addException($e,
-                    $this->_getHelper()->__('An error occurred while saving the customer.'));
-                $this->_session->setCustomerData($data);
+                $this->_getSession()->addException($e,
+                    Mage::helper('Mage_Adminhtml_Helper_Data')->__('An error occurred while saving the customer.'));
+                $this->_getSession()->setCustomerData($data);
                 $this->getResponse()->setRedirect($this->getUrl('*/customer/edit', array('id'=>$customer->getId())));
                 return;
             }
@@ -305,211 +371,6 @@ class Mage_Adminhtml_CustomerController extends Mage_Adminhtml_Controller_Action
         $this->getResponse()->setRedirect($this->getUrl('*/customer'));
     }
 
-    /**
-     * Set customer password
-     *
-     * @param Mage_Customer_Model_Customer $customer
-     * @param array $data
-     * @return bool
-     */
-    protected function _processPassword($customer, $data)
-    {
-        $customer->setPassword($data['account']['password']);
-        $customer->setForceConfirmed(true);
-        if ($customer->getPassword() == 'auto') {
-            $customer->setPassword($customer->generatePassword());
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * Process subscription options
-     *
-     * @param Mage_Customer_Model_Customer $customer
-     * @param array $data
-     */
-    protected function _processSubscriptionOptions($customer, $data)
-    {
-        if (isset($data['account']['confirmation'])) {
-            $customer->setData('confirmation', $data['account']['confirmation']);
-        }
-
-        if ($this->_acl->isAllowed(Mage_Backend_Model_Acl_Config::ACL_RESOURCE_ALL)
-            && !$customer->getConfirmation()
-        ) {
-            $customer->setIsSubscribed(isset($data['subscription']));
-        }
-
-        if (isset($data['account']['sendemail_store_id'])) {
-            $customer->setSendemailStoreId($data['account']['sendemail_store_id']);
-        }
-    }
-
-    /**
-     * Change Password
-     *
-     * @param Mage_Customer_Model_Customer $customer
-     * @param array $data
-     * @return mixed
-     */
-    protected function _changePassword($customer, $data)
-    {
-        if (!empty($data['account']['new_password'])) {
-            $newPassword = $data['account']['new_password'];
-            if ($newPassword == 'auto') {
-                $newPassword = $customer->generatePassword();
-            }
-            $customer->changePassword($newPassword);
-            $customer->sendPasswordReminderEmail();
-            return $data;
-        }
-        return $data;
-    }
-
-    /**
-     * @param Mage_Customer_Model_Customer $customer
-     * @param array $data
-     * @param bool $sendPassToEmail
-     * @param bool $isNewCustomer
-     * @return mixed
-     */
-    protected function _sendWelcomeEmail($customer, $data, $sendPassToEmail, $isNewCustomer)
-    {
-        if ($customer->getWebsiteId() && (isset($data['account']['sendemail']) || $sendPassToEmail)) {
-            $storeId = $customer->getSendemailStoreId();
-            if ($isNewCustomer) {
-                $customer->sendNewAccountEmail('registered', '', $storeId);
-                return $data;
-            } elseif ((!$customer->getConfirmation())) {
-                // Confirm not confirmed customer
-                $customer->sendNewAccountEmail('confirmed', '', $storeId);
-                return $data;
-            }
-            return $data;
-        }
-        return $data;
-    }
-
-    /**
-     * Process customer address
-     *
-     * @param Mage_Customer_Model_Customer $customer
-     * @param array $data
-     * @return bool
-     */
-    protected function _processAddress($customer, $data)
-    {
-        $modifiedAddresses = array();
-        if (!empty($data['address'])) {
-            $modifiedAddresses = $this->_processAddresses($customer, $data);
-            if ($modifiedAddresses === false) {
-                return false;
-            }
-        }
-
-        // Default billing and shipping
-        if (isset($data['account']['default_billing'])) {
-            $customer->setData('default_billing', $data['account']['default_billing']);
-        }
-        if (isset($data['account']['default_shipping'])) {
-            $customer->setData('default_shipping', $data['account']['default_shipping']);
-        }
-
-        // Mark not modified customer addresses for delete
-        /** @var $customerAddress Mage_Customer_Model_Address */
-        foreach ($customer->getAddressesCollection() as $customerAddress) {
-            if ($customerAddress->getId() && !in_array($customerAddress->getId(), $modifiedAddresses)) {
-                $customerAddress->setData('_deleted', true);
-            }
-        }
-        return true;
-    }
-
-    protected function _processData($customer, $data)
-    {
-        /** @var $customerForm Mage_Customer_Model_Form */
-        $customerForm = $this->_objectFactory->getModelInstance('Mage_Customer_Model_Form');
-        $customerForm->setEntity($customer)
-            ->setFormCode('adminhtml_customer')
-            ->ignoreInvisible(false);
-
-        $formData = $customerForm->extractData($this->getRequest(), 'account');
-
-        // Handle 'disable auto_group_change' attribute
-        if (isset($formData['disable_auto_group_change'])) {
-            $formData['disable_auto_group_change'] = empty($formData['disable_auto_group_change']) ? '0' : '1';
-        }
-
-        $errors = $customerForm->validateData($formData);
-        if ($errors !== true) {
-            foreach ($errors as $error) {
-                $this->_session->addError($error);
-            }
-            $this->_session->setCustomerData($data);
-            $this->getResponse()->setRedirect($this->getUrl('*/customer/edit', array('id' => $customer->getId())));
-            return false;
-        }
-
-        $customerForm->compactData($formData);
-        return true;
-    }
-
-    /**
-     * @param array $data
-     * @param Mage_Customer_Model_Customer $customer
-     * @return array
-     */
-    protected function _processAddresses($customer, $data)
-    {
-        /** @var $addressForm Mage_Customer_Model_Form */
-        $addressForm = $this->_objectFactory->getModelInstance('Mage_Customer_Model_Form');
-        $addressForm->setFormCode('adminhtml_customer_address')->ignoreInvisible(false);
-
-        $modifiedAddresses = array();
-        foreach (array_keys($data['address']) as $index) {
-            $address = $customer->getAddressItemById($index);
-            if (!$address) {
-                $address = $this->_objectFactory->getModelInstance('Mage_Customer_Model_Address');
-            }
-
-            $requestScope = sprintf('address/%s', $index);
-            $formData = $addressForm->setEntity($address)
-                ->extractData($this->getRequest(), $requestScope);
-
-            // Set default billing and shipping flags to address
-            $isDefaultBilling = isset($data['account']['default_billing'])
-                && $data['account']['default_billing'] == $index;
-            $address->setIsDefaultBilling($isDefaultBilling);
-            $isDefaultShipping = isset($data['account']['default_shipping'])
-                && $data['account']['default_shipping'] == $index;
-            $address->setIsDefaultShipping($isDefaultShipping);
-
-            $errors = $addressForm->validateData($formData);
-            if ($errors !== true) {
-                foreach ($errors as $error) {
-                    $this->_session->addError($error);
-                }
-                $this->_session->setCustomerData($data);
-                $this->getResponse()->setRedirect($this->getUrl('*/customer/edit', array(
-                        'id' => $customer->getId())
-                ));
-                return false;
-            }
-
-            $addressForm->compactData($formData);
-
-            // Set post_index for detect default billing and shipping addresses
-            $address->setPostIndex($index);
-            if ($address->getId()) {
-                $modifiedAddresses[] = $address->getId();
-            } else {
-                $customer->addAddress($address);
-            }
-        }
-        return $modifiedAddresses;
-    }
-
     /**
      * Export customer grid to CSV format
      */
@@ -538,8 +399,7 @@ class Mage_Adminhtml_CustomerController extends Mage_Adminhtml_Controller_Action
      * Customer orders grid
      *
      */
-    public function ordersAction()
-    {
+    public function ordersAction() {
         $this->_initCustomer();
         $this->loadLayout();
         $this->renderLayout();
@@ -549,8 +409,7 @@ class Mage_Adminhtml_CustomerController extends Mage_Adminhtml_Controller_Action
      * Customer last orders grid for ajax
      *
      */
-    public function lastOrdersAction()
-    {
+    public function lastOrdersAction() {
         $this->_initCustomer();
         $this->loadLayout();
         $this->renderLayout();
@@ -563,10 +422,10 @@ class Mage_Adminhtml_CustomerController extends Mage_Adminhtml_Controller_Action
     public function newsletterAction()
     {
         $this->_initCustomer();
-        $subscriber = $this->_objectFactory->getModelInstance('Mage_Newsletter_Model_Subscriber')
-            ->loadByCustomer($this->_registryManager->registry('current_customer'));
+        $subscriber = Mage::getModel('Mage_Newsletter_Model_Subscriber')
+            ->loadByCustomer(Mage::registry('current_customer'));
 
-        $this->_registryManager->register('subscriber', $subscriber);
+        Mage::register('subscriber', $subscriber);
         $this->loadLayout()
             ->renderLayout();
     }
@@ -574,11 +433,11 @@ class Mage_Adminhtml_CustomerController extends Mage_Adminhtml_Controller_Action
     public function wishlistAction()
     {
         $this->_initCustomer();
-        $customer = $this->_registryManager->registry('current_customer');
+        $customer = Mage::registry('current_customer');
         if ($customer->getId()) {
-            if ($itemId = (int) $this->getRequest()->getParam('delete')) {
+            if($itemId = (int) $this->getRequest()->getParam('delete')) {
                 try {
-                    $this->_objectFactory->getModelInstance('Mage_Wishlist_Model_Item')->load($itemId)
+                    Mage::getModel('Mage_Wishlist_Model_Item')->load($itemId)
                         ->delete();
                 }
                 catch (Exception $e) {
@@ -618,9 +477,9 @@ class Mage_Adminhtml_CustomerController extends Mage_Adminhtml_Controller_Action
         // delete an item from cart
         $deleteItemId = $this->getRequest()->getPost('delete');
         if ($deleteItemId) {
-            $quote = $this->_objectFactory->getModelInstance('Mage_Sales_Model_Quote')
+            $quote = Mage::getModel('Mage_Sales_Model_Quote')
                 ->setWebsite(Mage::app()->getWebsite($websiteId))
-                ->loadByCustomer($this->_registryManager->registry('current_customer'));
+                ->loadByCustomer(Mage::registry('current_customer'));
             $item = $quote->getItemById($deleteItemId);
             if ($item && $item->getId()) {
                 $quote->removeItem($deleteItemId);
@@ -640,7 +499,7 @@ class Mage_Adminhtml_CustomerController extends Mage_Adminhtml_Controller_Action
     public function viewCartAction()
     {
         $this->_initCustomer();
-        $this->loadLayout()
+        $layout = $this->loadLayout()
             ->getLayout()
             ->getBlock('admin.customer.view.cart')
             ->setWebsiteId();
@@ -668,36 +527,11 @@ class Mage_Adminhtml_CustomerController extends Mage_Adminhtml_Controller_Action
         $this->loadLayout()
             ->getLayout()
             ->getBlock('admin.customer.reviews')
-            ->setCustomerId($this->_registryManager->registry('current_customer')->getId())
+            ->setCustomerId(Mage::registry('current_customer')->getId())
             ->setUseAjax(true);
         $this->renderLayout();
     }
 
-    /**
-     * Get customer's tags list
-     *
-     */
-    public function productTagsAction()
-    {
-        $this->_initCustomer();
-        $this->loadLayout()
-            ->getLayout()
-            ->getBlock('admin.customer.tags')
-            ->setCustomerId($this->_registryManager->registry('current_customer')->getId())
-            ->setUseAjax(true);
-        $this->renderLayout();
-    }
-
-    public function tagGridAction()
-    {
-        $this->_initCustomer();
-        $this->loadLayout();
-        $this->getLayout()->getBlock('admin.customer.tags')->setCustomerId(
-            $this->_registryManager->registry('current_customer')
-        );
-        $this->renderLayout();
-    }
-
     public function validateAction()
     {
         $response       = new Varien_Object();
@@ -705,7 +539,7 @@ class Mage_Adminhtml_CustomerController extends Mage_Adminhtml_Controller_Action
         $websiteId      = Mage::app()->getStore()->getWebsiteId();
         $accountData    = $this->getRequest()->getPost('account');
 
-        $customer = $this->_objectFactory->getModelInstance('Mage_Customer_Model_Customer');
+        $customer = Mage::getModel('Mage_Customer_Model_Customer');
         $customerId = $this->getRequest()->getParam('id');
         if ($customerId) {
             $customer->load($customerId);
@@ -715,7 +549,7 @@ class Mage_Adminhtml_CustomerController extends Mage_Adminhtml_Controller_Action
         }
 
         /* @var $customerForm Mage_Customer_Model_Form */
-        $customerForm = $this->_objectFactory->getModelInstance('Mage_Customer_Model_Form');
+        $customerForm = Mage::getModel('Mage_Customer_Model_Form');
         $customerForm->setEntity($customer)
             ->setFormCode('adminhtml_customer')
             ->setIsAjaxRequest(true)
@@ -735,13 +569,13 @@ class Mage_Adminhtml_CustomerController extends Mage_Adminhtml_Controller_Action
         if (!$response->getError()) {
             # Trying to load customer with the same email and return error message
             # if customer with the same email address exisits
-            $checkCustomer = $this->_objectFactory->getModelInstance('Mage_Customer_Model_Customer')
+            $checkCustomer = Mage::getModel('Mage_Customer_Model_Customer')
                 ->setWebsiteId($websiteId);
             $checkCustomer->loadByEmail($accountData['email']);
             if ($checkCustomer->getId() && ($checkCustomer->getId() != $customer->getId())) {
                 $response->setError(1);
                 $this->_getSession()->addError(
-                    $this->_getHelper()->__('Customer with the same email already exists.')
+                    Mage::helper('Mage_Adminhtml_Helper_Data')->__('Customer with the same email already exists.')
                 );
             }
         }
@@ -749,7 +583,7 @@ class Mage_Adminhtml_CustomerController extends Mage_Adminhtml_Controller_Action
         $addressesData = $this->getRequest()->getParam('address');
         if (is_array($addressesData)) {
             /* @var $addressForm Mage_Customer_Model_Form */
-            $addressForm = $this->_objectFactory->getModelInstance('Mage_Customer_Model_Form');
+            $addressForm = Mage::getModel('Mage_Customer_Model_Form');
             $addressForm->setFormCode('adminhtml_customer_address')->ignoreInvisible(false);
             foreach (array_keys($addressesData) as $index) {
                 if ($index == '_template_') {
@@ -757,7 +591,7 @@ class Mage_Adminhtml_CustomerController extends Mage_Adminhtml_Controller_Action
                 }
                 $address = $customer->getAddressItemById($index);
                 if (!$address) {
-                    $address   = $this->_objectFactory->getModelInstance('Mage_Customer_Model_Address');
+                    $address   = Mage::getModel('Mage_Customer_Model_Address');
                 }
 
                 $requestScope = sprintf('address/%s', $index);
@@ -785,22 +619,21 @@ class Mage_Adminhtml_CustomerController extends Mage_Adminhtml_Controller_Action
     public function massSubscribeAction()
     {
         $customersIds = $this->getRequest()->getParam('customer');
-        if (!is_array($customersIds)) {
-             $this->_getSession()->addError($this->_getHelper()->__('Please select customer(s).'));
+        if(!is_array($customersIds)) {
+             Mage::getSingleton('Mage_Adminhtml_Model_Session')->addError(Mage::helper('Mage_Adminhtml_Helper_Data')->__('Please select customer(s).'));
 
         } else {
             try {
                 foreach ($customersIds as $customerId) {
-                    $customer = $this->_objectFactory->getModelInstance('Mage_Customer_Model_Customer')
-                        ->load($customerId);
+                    $customer = Mage::getModel('Mage_Customer_Model_Customer')->load($customerId);
                     $customer->setIsSubscribed(true);
                     $customer->save();
                 }
-                $this->_getSession()->addSuccess(
-                    $this->_getHelper()->__('Total of %d record(s) were updated.', count($customersIds))
+                Mage::getSingleton('Mage_Adminhtml_Model_Session')->addSuccess(
+                    Mage::helper('Mage_Adminhtml_Helper_Data')->__('Total of %d record(s) were updated.', count($customersIds))
                 );
             } catch (Exception $e) {
-                $this->_getSession()->addError($e->getMessage());
+                Mage::getSingleton('Mage_Adminhtml_Model_Session')->addError($e->getMessage());
             }
         }
         $this->_redirect('*/*/index');
@@ -809,21 +642,20 @@ class Mage_Adminhtml_CustomerController extends Mage_Adminhtml_Controller_Action
     public function massUnsubscribeAction()
     {
         $customersIds = $this->getRequest()->getParam('customer');
-        if (!is_array($customersIds)) {
-             $this->_getSession()->addError($this->_getHelper()->__('Please select customer(s).'));
+        if(!is_array($customersIds)) {
+             Mage::getSingleton('Mage_Adminhtml_Model_Session')->addError(Mage::helper('Mage_Adminhtml_Helper_Data')->__('Please select customer(s).'));
         } else {
             try {
                 foreach ($customersIds as $customerId) {
-                    $customer = $this->_objectFactory->getModelInstance('Mage_Customer_Model_Customer')
-                        ->load($customerId);
+                    $customer = Mage::getModel('Mage_Customer_Model_Customer')->load($customerId);
                     $customer->setIsSubscribed(false);
                     $customer->save();
                 }
-                $this->_getSession()->addSuccess(
-                    $this->_getHelper()->__('Total of %d record(s) were updated.', count($customersIds))
+                Mage::getSingleton('Mage_Adminhtml_Model_Session')->addSuccess(
+                    Mage::helper('Mage_Adminhtml_Helper_Data')->__('Total of %d record(s) were updated.', count($customersIds))
                 );
             } catch (Exception $e) {
-                $this->_getSession()->addError($e->getMessage());
+                Mage::getSingleton('Mage_Adminhtml_Model_Session')->addError($e->getMessage());
             }
         }
 
@@ -833,21 +665,21 @@ class Mage_Adminhtml_CustomerController extends Mage_Adminhtml_Controller_Action
     public function massDeleteAction()
     {
         $customersIds = $this->getRequest()->getParam('customer');
-        if (!is_array($customersIds)) {
-             $this->_getSession()->addError($this->_getHelper()->__('Please select customer(s).'));
+        if(!is_array($customersIds)) {
+             Mage::getSingleton('Mage_Adminhtml_Model_Session')->addError(Mage::helper('Mage_Adminhtml_Helper_Data')->__('Please select customer(s).'));
         } else {
             try {
-                $customer = $this->_objectFactory->getModelInstance('Mage_Customer_Model_Customer');
+                $customer = Mage::getModel('Mage_Customer_Model_Customer');
                 foreach ($customersIds as $customerId) {
                     $customer->reset()
                         ->load($customerId)
                         ->delete();
                 }
-                $this->_getSession()->addSuccess(
-                    $this->_getHelper()->__('Total of %d record(s) were deleted.', count($customersIds))
+                Mage::getSingleton('Mage_Adminhtml_Model_Session')->addSuccess(
+                    Mage::helper('Mage_Adminhtml_Helper_Data')->__('Total of %d record(s) were deleted.', count($customersIds))
                 );
             } catch (Exception $e) {
-                $this->_getSession()->addError($e->getMessage());
+                Mage::getSingleton('Mage_Adminhtml_Model_Session')->addError($e->getMessage());
             }
         }
 
@@ -857,21 +689,20 @@ class Mage_Adminhtml_CustomerController extends Mage_Adminhtml_Controller_Action
     public function massAssignGroupAction()
     {
         $customersIds = $this->getRequest()->getParam('customer');
-        if (!is_array($customersIds)) {
-             $this->_getSession()->addError($this->_getHelper()->__('Please select customer(s).'));
+        if(!is_array($customersIds)) {
+             Mage::getSingleton('Mage_Adminhtml_Model_Session')->addError(Mage::helper('Mage_Adminhtml_Helper_Data')->__('Please select customer(s).'));
         } else {
             try {
                 foreach ($customersIds as $customerId) {
-                    $customer = $this->_objectFactory->getModelInstance('Mage_Customer_Model_Customer')
-                        ->load($customerId);
+                    $customer = Mage::getModel('Mage_Customer_Model_Customer')->load($customerId);
                     $customer->setGroupId($this->getRequest()->getParam('group'));
                     $customer->save();
                 }
-                $this->_getSession()->addSuccess(
-                    $this->_getHelper()->__('Total of %d record(s) were updated.', count($customersIds))
+                Mage::getSingleton('Mage_Adminhtml_Model_Session')->addSuccess(
+                    Mage::helper('Mage_Adminhtml_Helper_Data')->__('Total of %d record(s) were updated.', count($customersIds))
                 );
             } catch (Exception $e) {
-                $this->_getSession()->addError($e->getMessage());
+                Mage::getSingleton('Mage_Adminhtml_Model_Session')->addError($e->getMessage());
             }
         }
 
@@ -952,7 +783,7 @@ class Mage_Adminhtml_CustomerController extends Mage_Adminhtml_Controller_Action
 
     protected function _isAllowed()
     {
-        return $this->_acl->isAllowed('Mage_Customer::manage');
+        return Mage::getSingleton('Mage_Core_Model_Authorization')->isAllowed('Mage_Customer::manage');
     }
 
     /**
diff --git a/app/code/core/Mage/Adminhtml/controllers/Sales/OrderController.php b/app/code/core/Mage/Adminhtml/controllers/Sales/OrderController.php
index 80e6052b11f..36337dfc1fd 100644
--- a/app/code/core/Mage/Adminhtml/controllers/Sales/OrderController.php
+++ b/app/code/core/Mage/Adminhtml/controllers/Sales/OrderController.php
@@ -721,11 +721,8 @@ class Mage_Adminhtml_Sales_OrderController extends Mage_Adminhtml_Controller_Act
     public function addressAction()
     {
         $addressId = $this->getRequest()->getParam('address_id');
-        $address = Mage::getModel('Mage_Sales_Model_Order_Address')
-            ->getCollection()
-            ->addFilter('entity_id', $addressId)
-            ->getItemById($addressId);
-        if ($address) {
+        $address = Mage::getModel('Mage_Sales_Model_Order_Address')->load($addressId);
+        if ($address->getId()) {
             Mage::register('order_address', $address);
             $this->loadLayout();
             // Do not display VAT validation button on edit order address form
diff --git a/app/code/core/Mage/Adminhtml/etc/config.xml b/app/code/core/Mage/Adminhtml/etc/config.xml
index 23c8d6ccab5..ace25b0cb1e 100644
--- a/app/code/core/Mage/Adminhtml/etc/config.xml
+++ b/app/code/core/Mage/Adminhtml/etc/config.xml
@@ -148,9 +148,6 @@
                 <sales module="Mage_Adminhtml">
                     <file>sales.xml</file>
                 </sales>
-                <tag module="Mage_Adminhtml">
-                    <file>tag.xml</file>
-                </tag>
             </updates>
         </layout>
         <sales>
diff --git a/app/code/core/Mage/Adminhtml/view/adminhtml/catalog.xml b/app/code/core/Mage/Adminhtml/view/adminhtml/catalog.xml
index 8d5eb757726..b2af721bd4f 100644
--- a/app/code/core/Mage/Adminhtml/view/adminhtml/catalog.xml
+++ b/app/code/core/Mage/Adminhtml/view/adminhtml/catalog.xml
@@ -100,18 +100,6 @@
         </container>
     </adminhtml_catalog_product_reviews>
 
-    <adminhtml_catalog_product_taggrid>
-        <container name="root" label="Root" output="1">
-            <block type="Mage_Adminhtml_Block_Catalog_Product_Edit_Tab_Tag" name="admin.product.tags"/>
-        </container>
-    </adminhtml_catalog_product_taggrid>
-
-    <adminhtml_catalog_product_tagcustomergrid>
-        <container name="root" label="Root" output="1">
-            <block type="Mage_Adminhtml_Block_Catalog_Product_Edit_Tab_Tag_Customer" name="admin.product.tags.customers"/>
-        </container>
-    </adminhtml_catalog_product_tagcustomergrid>
-
     <adminhtml_catalog_product_options>
         <container name="root" label="Root" output="1">
             <block type="Mage_Adminhtml_Block_Catalog_Product_Edit_Tab_Options" name="admin.product.options"/>
diff --git a/app/code/core/Mage/Adminhtml/view/adminhtml/customer.xml b/app/code/core/Mage/Adminhtml/view/adminhtml/customer.xml
index 8bb788e47c4..ba18c3bf176 100644
--- a/app/code/core/Mage/Adminhtml/view/adminhtml/customer.xml
+++ b/app/code/core/Mage/Adminhtml/view/adminhtml/customer.xml
@@ -94,18 +94,6 @@
         </container>
     </adminhtml_customer_productreviews>
 
-    <adminhtml_customer_producttags>
-        <container name="root" label="Root" output="1">
-            <block type="Mage_Adminhtml_Block_Customer_Edit_Tab_Tag" name="admin.customer.tags"/>
-        </container>
-    </adminhtml_customer_producttags>
-
-    <adminhtml_customer_taggrid>
-        <container name="root" label="Root" output="1">
-            <block type="Mage_Adminhtml_Block_Customer_Edit_Tab_Tag" name="admin.customer.tags"/>
-        </container>
-    </adminhtml_customer_taggrid>
-
     <adminhtml_customer_newsletter>
         <container name="root" label="Root" output="1">
             <block type="Mage_Adminhtml_Block_Customer_Edit_Tab_Newsletter_Grid" name="admin.customer.newsletter.grid"/>
diff --git a/app/code/core/Mage/Adminhtml/view/adminhtml/notification/toolbar.phtml b/app/code/core/Mage/Adminhtml/view/adminhtml/notification/toolbar.phtml
index 7c5b2e18365..322e421140e 100644
--- a/app/code/core/Mage/Adminhtml/view/adminhtml/notification/toolbar.phtml
+++ b/app/code/core/Mage/Adminhtml/view/adminhtml/notification/toolbar.phtml
@@ -77,7 +77,7 @@
 
     <?php echo $this->__('Latest Message:') ?></strong> <?php echo $this->getLatestNotice() ?>
     <?php if (!empty($latestNoticeUrl)): ?>
-        <a href="<?php echo $latestNoticeUrl ?>" onclick="this.target='_blank';"><?php echo $this->__('Read details') ?></a>
+        <a href="<?php echo $this->escapeHtml($latestNoticeUrl) ?>" onclick="this.target='_blank';"><?php echo $this->__('Read details') ?></a>
     <?php endif; ?>
 </div>
 <?php endif; ?>
diff --git a/app/code/core/Mage/Catalog/Helper/Product/View.php b/app/code/core/Mage/Catalog/Helper/Product/View.php
index f2944d70ac7..b22cf0c9bd0 100644
--- a/app/code/core/Mage/Catalog/Helper/Product/View.php
+++ b/app/code/core/Mage/Catalog/Helper/Product/View.php
@@ -27,6 +27,8 @@
 /**
  * Catalog category helper
  *
+ * @category    Mage
+ * @package     Mage_Catalog
  * @author      Magento Core Team <core@magentocommerce.com>
  */
 class Mage_Catalog_Helper_Product_View extends Mage_Core_Helper_Abstract
@@ -35,7 +37,33 @@ class Mage_Catalog_Helper_Product_View extends Mage_Core_Helper_Abstract
     public $ERR_NO_PRODUCT_LOADED = 1;
     public $ERR_BAD_CONTROLLER_INTERFACE = 2;
 
-     /**
+    /**
+     * Path to list of session models to get messages
+     */
+    const XML_PATH_SESSION_MESSAGE_MODELS = 'global/session/catalog/product/message_models';
+
+    /**
+     * General config object
+     *
+     * @var Mage_Core_Model_Config
+     */
+    protected $_config;
+
+    /**
+     * Constructor dependency injection
+     *
+     * @param array $data
+     */
+    public function __construct(array $data = array())
+    {
+        if (isset($data['config'])) {
+            $this->_config = $data['config'];
+        } else {
+            $this->_config = Mage::getConfig();
+        }
+    }
+
+    /**
      * Inits layout for viewing product page
      *
      * @param Mage_Catalog_Model_Product $product
@@ -61,7 +89,7 @@ class Mage_Catalog_Helper_Product_View extends Mage_Core_Helper_Abstract
         $layoutUpdates = $settings->getLayoutUpdates();
         if ($layoutUpdates) {
             if (is_array($layoutUpdates)) {
-                foreach($layoutUpdates as $layoutUpdate) {
+                foreach ($layoutUpdates as $layoutUpdate) {
                     $update->addUpdate($layoutUpdate);
                 }
             }
@@ -105,6 +133,7 @@ class Mage_Catalog_Helper_Product_View extends Mage_Core_Helper_Abstract
      * @param null|Varien_Object $params
      *
      * @return Mage_Catalog_Helper_Product_View
+     * @throws Mage_Core_Exception
      */
     public function prepareAndRender($productId, $controller, $params = null)
     {
@@ -141,14 +170,29 @@ class Mage_Catalog_Helper_Product_View extends Mage_Core_Helper_Abstract
         $this->initProductLayout($product, $controller);
 
         if ($controller instanceof Mage_Catalog_Controller_Product_View_Interface) {
-            $controller->initLayoutMessages('Mage_Catalog_Model_Session');
-            $controller->initLayoutMessages('Mage_Tag_Model_Session');
-            $controller->initLayoutMessages('Mage_Checkout_Model_Session');
+            foreach ($this->_getSessionMessageModels() as $sessionModel) {
+                $controller->initLayoutMessages($sessionModel);
+            }
         } else {
-            throw new Mage_Core_Exception($this->__('Bad controller interface for showing product'), $this->ERR_BAD_CONTROLLER_INTERFACE);
+            throw new Mage_Core_Exception(
+                $this->__('Bad controller interface for showing product'),
+                $this->ERR_BAD_CONTROLLER_INTERFACE
+            );
         }
         $controller->renderLayout();
 
         return $this;
     }
+
+    /**
+     * Get list of session models with messages
+     *
+     * @return array
+     */
+    protected function _getSessionMessageModels()
+    {
+        $messageModels = $this->_config->getNode(self::XML_PATH_SESSION_MESSAGE_MODELS)
+            ->asArray();
+        return array_values($messageModels);
+    }
 }
diff --git a/app/code/core/Mage/Catalog/etc/config.xml b/app/code/core/Mage/Catalog/etc/config.xml
index 8cb7d245367..f40dceda2a3 100644
--- a/app/code/core/Mage/Catalog/etc/config.xml
+++ b/app/code/core/Mage/Catalog/etc/config.xml
@@ -247,6 +247,16 @@
                 </visibility>
             </catalog_product>
         </eav_attributes>
+        <session>
+            <catalog>
+                <product>
+                    <message_models>
+                        <catalog>Mage_Catalog_Model_Session</catalog>
+                        <checkout>Mage_Checkout_Model_Session</checkout>
+                    </message_models>
+                </product>
+            </catalog>
+        </session>
     </global>
     <adminhtml>
         <translate>
diff --git a/app/code/core/Mage/CatalogSearch/view/frontend/result.phtml b/app/code/core/Mage/CatalogSearch/view/frontend/result.phtml
index 07edbd99bb8..5d6bd4ddc55 100644
--- a/app/code/core/Mage/CatalogSearch/view/frontend/result.phtml
+++ b/app/code/core/Mage/CatalogSearch/view/frontend/result.phtml
@@ -27,9 +27,7 @@
 <?php if($this->getResultCount()): ?>
 <?php echo $this->getMessagesBlock()->getGroupedHtml() ?>
 <div class="page-title">
-    <?php if ($this->helper('Mage_Rss_Helper_Catalog')->getTagFeedUrl()): ?>
-        <a href="<?php echo $this->helper('Mage_Rss_Helper_Catalog')->getTagFeedUrl() ?>" class="nobr link-rss"><?php echo $this->__('Subscribe to Feed') ?></a>
-    <?php endif; ?>
+    <?php echo $this->getChildHtml('tagged_product_list_rss_link'); ?>
     <h1><?php echo ($this->getHeaderText() || $this->getHeaderText() === false) ? $this->getHeaderText() : $this->__("Search results for '%s'", $this->helper('Mage_CatalogSearch_Helper_Data')->getEscapedQueryText()) ?></h1>
 </div>
     <?php if ($messages = $this->getNoteMessages()):?>
diff --git a/app/code/core/Mage/Core/Helper/Js.php b/app/code/core/Mage/Core/Helper/Js.php
index 957a3a164b9..a73a1ad9ce5 100644
--- a/app/code/core/Mage/Core/Helper/Js.php
+++ b/app/code/core/Mage/Core/Helper/Js.php
@@ -112,7 +112,8 @@ class Mage_Core_Helper_Js extends Mage_Core_Helper_Abstract
                 foreach ($messages as $message) {
                     $messageText = (string)$message;
                     $module = $message->getParent()->getAttribute("module");
-                    $this->_translateData[$messageText] = Mage::helper(empty($module) ? 'Mage_Core' : $module
+                    $this->_translateData[$messageText] = Mage::helper(
+                        empty($module) ? 'Mage_Core' : $module
                     )->__($messageText);
                 }
             }
diff --git a/app/code/core/Mage/DesignEditor/Block/Template.php b/app/code/core/Mage/DesignEditor/Block/Template.php
index 38094b052f8..77c3cde1d58 100644
--- a/app/code/core/Mage/DesignEditor/Block/Template.php
+++ b/app/code/core/Mage/DesignEditor/Block/Template.php
@@ -26,6 +26,13 @@
 
 /**
  * Extended template block for Visual Design Editor
+ *
+ * @method string getElementName()
+ * @method string getElementId()
+ * @method string getElementHtml()
+ * @method string getElementTitle()
+ * @method bool getIsManipulationAllowed()
+ * @method bool getIsContainer()
  */
 class Mage_DesignEditor_Block_Template extends Mage_Core_Block_Template
 {
@@ -38,4 +45,20 @@ class Mage_DesignEditor_Block_Template extends Mage_Core_Block_Template
     {
         return Mage::getSingleton('Mage_DesignEditor_Model_Session')->isHighlightingDisabled();
     }
+
+    /**
+     * Get remove button for block/container wrapper
+     *
+     * @param string $elementId
+     * @return string
+     */
+    public function getRemoveButton($elementId)
+    {
+        /** @var $block Mage_DesignEditor_Block_Wrapper_Remove */
+        $block = Mage::getModel('Mage_DesignEditor_Block_Wrapper_Remove', array(
+            'template'   => 'wrapper/remove.phtml',
+            'wrapped_element_id' => $elementId
+        ));
+        return $block->toHtml();
+    }
 }
diff --git a/app/code/core/Mage/DesignEditor/Block/Toolbar.php b/app/code/core/Mage/DesignEditor/Block/Toolbar.php
index 1001dc065d1..66f6cb36862 100644
--- a/app/code/core/Mage/DesignEditor/Block/Toolbar.php
+++ b/app/code/core/Mage/DesignEditor/Block/Toolbar.php
@@ -64,8 +64,21 @@ class Mage_DesignEditor_Block_Toolbar extends Mage_Core_Block_Template
     public function getOptionsJson()
     {
         $options = array(
-            'cookie_highlighting_name' => Mage_DesignEditor_Model_Session::COOKIE_HIGHLIGHTING,
+            'cookieHighlightingName' => Mage_DesignEditor_Model_Session::COOKIE_HIGHLIGHTING,
         );
+        /** @var $toolbarRowBlock Mage_DesignEditor_Block_Template */
+        $toolbarRowBlock = $this->getChildBlock('design_editor_toolbar_row');
+
+        if ($toolbarRowBlock) {
+            /** @var $buttonsBlock Mage_DesignEditor_Block_Toolbar_Buttons */
+            $buttonsBlock = $toolbarRowBlock->getChildBlock('design_editor_toolbar_buttons');
+            if ($buttonsBlock) {
+                $options['compactLogUrl'] = $buttonsBlock->getCompactLogUrl();
+                $options['viewLayoutUrl'] = $buttonsBlock->getViewLayoutUrl();
+                $options['baseUrl'] = Mage::getBaseUrl();
+            }
+        }
+
         return Mage::helper('Mage_Core_Helper_Data')->jsonEncode($options);
     }
 }
diff --git a/app/code/core/Mage/DesignEditor/Block/Toolbar/Buttons.php b/app/code/core/Mage/DesignEditor/Block/Toolbar/Buttons.php
new file mode 100644
index 00000000000..f3ce386f2e4
--- /dev/null
+++ b/app/code/core/Mage/DesignEditor/Block/Toolbar/Buttons.php
@@ -0,0 +1,61 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @category    Mage
+ * @package     Mage_DesignEditor
+ * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+/**
+ * Exit button control block
+ */
+class Mage_DesignEditor_Block_Toolbar_Buttons extends Mage_Core_Block_Template
+{
+    /**
+     * Get exit editor URL
+     *
+     * @return string
+     */
+    public function getExitUrl()
+    {
+        return Mage::getSingleton('Mage_Adminhtml_Model_Url')->getUrl('adminhtml/system_design_editor/exit');
+    }
+
+    /**
+     * Get "View Layout" button URL
+     *
+     * @return string
+     */
+    public function getViewLayoutUrl()
+    {
+        return $this->getUrl('design/editor/compactXml');
+    }
+
+    /**
+     * Get "Compact Log" button URL
+     *
+     * @return string
+     */
+    public function getCompactLogUrl()
+    {
+        return $this->getUrl('design/editor/compactHistory');
+    }
+}
diff --git a/app/code/core/Mage/DesignEditor/Block/Toolbar/Exit.php b/app/code/core/Mage/DesignEditor/Block/Toolbar/History.php
similarity index 79%
rename from app/code/core/Mage/DesignEditor/Block/Toolbar/Exit.php
rename to app/code/core/Mage/DesignEditor/Block/Toolbar/History.php
index 0fcb95c41d8..98e70c20015 100644
--- a/app/code/core/Mage/DesignEditor/Block/Toolbar/Exit.php
+++ b/app/code/core/Mage/DesignEditor/Block/Toolbar/History.php
@@ -25,17 +25,17 @@
  */
 
 /**
- * Exit button control block
+ * History toolbar block
  */
-class Mage_DesignEditor_Block_Toolbar_Exit extends Mage_Core_Block_Template
+class Mage_DesignEditor_Block_Toolbar_History extends Mage_Core_Block_Template
 {
     /**
-     * Get exit editor URL
+     * Get block title
      *
      * @return string
      */
-    public function getExitUrl()
+    public function getTitle()
     {
-        return Mage::getSingleton('Mage_Adminhtml_Model_Url')->getUrl('adminhtml/system_design_editor/exit');
+        return $this->__('Changes history');
     }
 }
diff --git a/app/code/core/Mage/DesignEditor/Block/Wrapper/Remove.php b/app/code/core/Mage/DesignEditor/Block/Wrapper/Remove.php
new file mode 100644
index 00000000000..881a16dcfd8
--- /dev/null
+++ b/app/code/core/Mage/DesignEditor/Block/Wrapper/Remove.php
@@ -0,0 +1,43 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @category    Mage
+ * @package     Mage_DesignEditor
+ * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+/**
+ * Remove button for template block for Visual Design Editor
+ *
+ * @method string getWrappedElementId()
+ */
+class Mage_DesignEditor_Block_Wrapper_Remove extends Mage_Core_Block_Template
+{
+    /**
+     * Build remove button HTML id
+     *
+     * @return string
+     */
+    public function getElementId()
+    {
+        return $this->getWrappedElementId() . '_remove';
+    }
+}
diff --git a/app/code/core/Mage/DesignEditor/Model/History.php b/app/code/core/Mage/DesignEditor/Model/History.php
new file mode 100644
index 00000000000..381429137c2
--- /dev/null
+++ b/app/code/core/Mage/DesignEditor/Model/History.php
@@ -0,0 +1,143 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @category    Mage
+ * @package     Mage_DesignEditor
+ * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+/**
+ * Visual Design Editor history model
+ */
+class Mage_DesignEditor_Model_History extends Mage_Backend_Model_Auth_Session
+{
+    /**
+     * Required change fields
+     *
+     * @var array
+     */
+    protected $_requiredFields = array('handle', 'change_type', 'element_name', 'action_name');
+
+
+    /**
+     * Change log
+     *
+     * @var array
+     */
+    protected $_changeLog = array();
+
+    /**
+     * Manager model
+     *
+     * @var null|Mage_DesignEditor_Model_History_Manager
+     */
+    protected $_managerModel;
+
+    /**
+     * Get compact log
+     *
+     * @return array
+     */
+    public function getCompactLog()
+    {
+        return $this->_compactLog()->_getManagerModel()->getHistoryLog();
+    }
+
+    /**
+     * Get compact xml
+     *
+     * @return string
+     */
+    public function getCompactXml()
+    {
+        return $this->_compactLog()->_getManagerModel()->getXml();
+    }
+
+    /**
+     * Set change log
+     *
+     * @param array $changeLog
+     * @return Mage_DesignEditor_Model_History
+     */
+    public function setChangeLog($changeLog)
+    {
+        $this->_changeLog = $changeLog;
+        return $this;
+    }
+
+    /**
+     * Compact log
+     *
+     * @return Mage_DesignEditor_Model_History
+     */
+    protected function _compactLog()
+    {
+        $managerModel = $this->_getManagerModel();
+        foreach ($this->_getChangeLog() as $change) {
+            $this->_validateChange($change);
+            $managerModel->addChange($change);
+        }
+
+        return $this;
+    }
+
+    /**
+     * Get change log
+     *
+     * @return array
+     */
+    protected function _getChangeLog()
+    {
+        return $this->_changeLog;
+    }
+
+    /**
+     * Get change model
+     *
+     * @return Mage_DesignEditor_Model_History_Manager
+     */
+    protected function _getManagerModel()
+    {
+        if ($this->_managerModel == null) {
+            $this->_managerModel = Mage::getModel('Mage_DesignEditor_Model_History_Manager');
+        }
+        return $this->_managerModel;
+    }
+
+    /**
+     * Validate change
+     *
+     * @throws Mage_DesignEditor_Exception
+     * @param array $change
+     * @return Mage_DesignEditor_Model_History
+     */
+    protected function _validateChange($change)
+    {
+        foreach ($this->_requiredFields as $field) {
+            if (!is_array($change) || !array_key_exists($field, $change) || empty($change[$field])) {
+                throw new Mage_DesignEditor_Exception(
+                    Mage::helper('Mage_DesignEditor_Helper_Data')->__('Invalid change data')
+                );
+            }
+        }
+        return $this;
+    }
+}
diff --git a/app/code/core/Mage/DesignEditor/Model/History/Manager.php b/app/code/core/Mage/DesignEditor/Model/History/Manager.php
new file mode 100644
index 00000000000..1e1384270e7
--- /dev/null
+++ b/app/code/core/Mage/DesignEditor/Model/History/Manager.php
@@ -0,0 +1,83 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @category    Mage
+ * @package     Mage_DesignEditor
+ * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+/**
+ * Visual design editor manager model
+ */
+class Mage_DesignEditor_Model_History_Manager extends Mage_Core_Model_Abstract
+{
+    /**
+     * Change collection
+     *
+     * @var null|Mage_DesignEditor_Model_History_Manager_Collection
+     */
+    protected $_changeCollection;
+
+    /**
+     * Add change
+     *
+     * @param array $change
+     * @return Mage_DesignEditor_Model_History_Manager
+     */
+    public function addChange($change)
+    {
+        $this->_getChangeCollection()->addElement($change);
+        return $this;
+    }
+
+    /**
+     * Get history log
+     *
+     * @return array
+     */
+    public function getHistoryLog()
+    {
+        return $this->_getChangeCollection()->toHistoryLog();
+    }
+
+    /**
+     * Get xml changes
+     *
+     * @return string
+     */
+    public function getXml()
+    {
+        return $this->_getChangeCollection()->toXml();
+    }
+
+    /**
+     * Get change collection
+     *
+     * @return Mage_DesignEditor_Model_History_Manager_Collection
+     */
+    protected function _getChangeCollection()
+    {
+        if ($this->_changeCollection == null) {
+            $this->_changeCollection = Mage::getModel('Mage_DesignEditor_Model_History_Manager_Collection');
+        }
+        return $this->_changeCollection;
+    }
+}
diff --git a/app/code/core/Mage/Rss/Helper/Catalog.php b/app/code/core/Mage/DesignEditor/Model/History/Manager/Adapter.php
similarity index 51%
rename from app/code/core/Mage/Rss/Helper/Catalog.php
rename to app/code/core/Mage/DesignEditor/Model/History/Manager/Adapter.php
index cd22bf7f00d..b421dfe24b5 100644
--- a/app/code/core/Mage/Rss/Helper/Catalog.php
+++ b/app/code/core/Mage/DesignEditor/Model/History/Manager/Adapter.php
@@ -19,29 +19,40 @@
  * needs please refer to http://www.magentocommerce.com for more information.
  *
  * @category    Mage
- * @package     Mage_Rss
+ * @package     Mage_DesignEditor
  * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
  * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
  */
 
 /**
- * Default rss helper
- *
- * @author      Magento Core Team <core@magentocommerce.com>
+ * Visual design editor manager adapter
  */
-class Mage_Rss_Helper_Catalog extends Mage_Core_Helper_Abstract
+class Mage_DesignEditor_Model_History_Manager_Adapter extends Mage_Core_Model_Abstract
 {
+    /**
+     * Layout change type
+     */
+    const CHANGE_TYPE_LAYOUT = 'layout';
 
-    public function getTagFeedUrl()
+    /**
+     * Get change by type
+     *
+     * @static
+     * @throws Mage_DesignEditor_Exception
+     * @param string $adapter
+     * @return Mage_DesignEditor_Model_History_Manager_Adapter_Abstract
+     */
+    public static function factory($adapter)
     {
-        $url = '';
-        if(Mage::getStoreConfig('rss/catalog/tag') && $this->_getRequest()->getParam('tagId')){
-            $tagModel = Mage::getModel('Mage_Tag_Model_Tag')->load($this->_getRequest()->getParam('tagId'));
-            if($tagModel && $tagModel->getId()){
-                return Mage::getUrl('rss/catalog/tag', array('tagName' => urlencode($tagModel->getName())));
-            }
+        switch ($adapter) {
+            case self::CHANGE_TYPE_LAYOUT:
+                return Mage::getModel('Mage_DesignEditor_Model_History_Manager_Adapter_Layout');
+                break;
+            default:
+                throw new Mage_DesignEditor_Exception(
+                    Mage::helper('Mage_DesignEditor_Helper_Data')->__('Change type %s is not exist.', $adapter)
+                );
+                break;
         }
-        return $url;
     }
-
 }
diff --git a/app/code/core/Mage/DesignEditor/Model/History/Manager/Adapter/Abstract.php b/app/code/core/Mage/DesignEditor/Model/History/Manager/Adapter/Abstract.php
new file mode 100644
index 00000000000..48a550aee06
--- /dev/null
+++ b/app/code/core/Mage/DesignEditor/Model/History/Manager/Adapter/Abstract.php
@@ -0,0 +1,76 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @category    Mage
+ * @package     Mage_DesignEditor
+ * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+/**
+ * Visual design editor adapter abstract
+ *
+ * @method string getName()
+ * @method string getHandle()
+ * @method string getType()
+ * @method array getActions()
+ */
+abstract class Mage_DesignEditor_Model_History_Manager_Adapter_Abstract extends Mage_Core_Model_Abstract
+{
+    /**
+     * Add action to element
+     *
+     * @abstract
+     * @param string $action
+     * @param array $data
+     * @return Mage_DesignEditor_Model_History_Manager_Adapter_Abstract
+     */
+    abstract public function addAction($action, $data);
+
+    /**
+     * Render element data
+     *
+     * @abstract
+     * @return mixed
+     */
+    abstract public function render();
+
+    /**
+     * Convert element to history log
+     *
+     * @return array
+     */
+    public function toHistoryLog()
+    {
+        $resultData = array();
+
+        foreach ($this->getActions() as $action => $data) {
+            $resultData[] = array(
+                'handle'       => $this->getHandle(),
+                'change_type'  => $this->getType(),
+                'element_name' => $this->getName(),
+                'action_name'  => $action,
+                'action_data'  => $data,
+            );
+        }
+
+        return $resultData;
+    }
+}
diff --git a/app/code/core/Mage/DesignEditor/Model/History/Manager/Adapter/Layout.php b/app/code/core/Mage/DesignEditor/Model/History/Manager/Adapter/Layout.php
new file mode 100644
index 00000000000..5371ecc62aa
--- /dev/null
+++ b/app/code/core/Mage/DesignEditor/Model/History/Manager/Adapter/Layout.php
@@ -0,0 +1,187 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @category    Mage
+ * @package     Mage_DesignEditor
+ * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+/**
+ * Visual design editor layout model
+ *
+ * @method bool getRemoveFlag()
+ * @method Varien_Simplexml_Element getHandleObject()
+ * @method Mage_DesignEditor_Model_History_Manager_Adapter_Layout setHandleObject()
+ * @method Mage_DesignEditor_Model_History_Manager_Adapter_Layout setRemoveFlag()
+ * @method Mage_DesignEditor_Model_History_Manager_Adapter_Layout setActions()
+ */
+class Mage_DesignEditor_Model_History_Manager_Adapter_Layout
+    extends Mage_DesignEditor_Model_History_Manager_Adapter_Abstract
+{
+    /**
+     * Type add
+     */
+    const TYPE_ADD = 'Add';
+
+    /**
+     * Type render
+     */
+    const TYPE_RENDER = 'Render';
+
+    /**
+     * Action move
+     */
+    const ACTION_MOVE = 'move';
+
+    /**
+     * Action remove
+     */
+    const ACTION_REMOVE = 'remove';
+
+    /**
+     * Add action to element
+     *
+     * @param string $action
+     * @param array $data
+     * @return Mage_DesignEditor_Model_History_Manager_Adapter_Layout
+     */
+    public function addAction($action, $data)
+    {
+        $this->_executeActionByType($action, self::TYPE_ADD, $data);
+        return $this;
+    }
+
+    /**
+     * Execute action by type
+     *
+     * @throws Mage_DesignEditor_Exception
+     * @param string $action
+     * @param string $type
+     * @param null|array $data
+     * @return mixed
+     */
+    protected function _executeActionByType($action, $type, $data = null)
+    {
+        switch ($action) {
+            case self::ACTION_MOVE:
+                return $this->{'_' . self::ACTION_MOVE . $type}($data);
+                break;
+            case self::ACTION_REMOVE:
+                return $this->{'_' . self::ACTION_REMOVE . $type}($data);
+                break;
+            default:
+                throw new Mage_DesignEditor_Exception(
+                    Mage::helper('Mage_DesignEditor_Helper_Data')->__('Action not exist: %s', $action)
+                );
+                break;
+        }
+    }
+
+    /**
+     * Remove action
+     *
+     * @return Mage_DesignEditor_Model_History_Manager_Adapter_Layout
+     */
+    protected function _removeAdd()
+    {
+        $this->_clearActions()->setRemoveFlag(true)->setActions(array(self::ACTION_REMOVE => array()));
+        return $this;
+    }
+
+    /**
+     * Clear actions data
+     *
+     * @return Mage_DesignEditor_Model_History_Manager_Adapter_Layout
+     */
+    protected function _clearActions()
+    {
+        $this->setActions(null);
+        return $this;
+    }
+
+    /**
+     * Action move
+     *
+     * @param array $data
+     * @return Mage_DesignEditor_Model_History_Manager_Adapter_Layout
+     */
+    protected function _moveAdd($data)
+    {
+        if ($this->getRemoveFlag()) {
+            return $this;
+        }
+        $this->setActions(array(self::ACTION_MOVE => $data));
+        return $this;
+    }
+
+    /**
+     * Element render action
+     *
+     * @return Mage_DesignEditor_Model_History_Manager_Adapter_Layout
+     */
+    public function render()
+    {
+        /** @var $handleObject Varien_Simplexml_Element */
+        $handleObject = $this->getHandleObject();
+        foreach ($this->getActions() as $action => $data) {
+            $handleObject->appendChild($this->_executeActionByType($action, self::TYPE_RENDER, $data));
+        }
+        return $this;
+    }
+
+    /**
+     *
+     * Render move action
+     *
+     * @param array $actionData
+     * @return Varien_Simplexml_Element
+     */
+    protected function _moveRender($actionData)
+    {
+        $move = new Varien_Simplexml_Element('<move></move>');
+        $move->addAttribute('element', $this->getName());
+
+        if (isset($actionData['after'])) {
+            $move->addAttribute('after', $actionData['after']);
+        } elseif ($actionData['before']) {
+            $move->addAttribute('before', $actionData['before']);
+        }
+
+        if (isset($actionData['as'])) {
+            $move->addAttribute('as', $actionData['as']);
+        }
+
+        $move->addAttribute('destination', $actionData['destination_container']);
+        return $move;
+    }
+
+    /**
+     * Render remove action
+     *
+     * @return Varien_Simplexml_Element
+     */
+    protected function _removeRender()
+    {
+        $remove = new Varien_Simplexml_Element('<remove></remove>');
+        $remove->addAttribute('name', $this->getName());
+        return $remove;
+    }
+}
diff --git a/app/code/core/Mage/DesignEditor/Model/History/Manager/Collection.php b/app/code/core/Mage/DesignEditor/Model/History/Manager/Collection.php
new file mode 100644
index 00000000000..cdba8065498
--- /dev/null
+++ b/app/code/core/Mage/DesignEditor/Model/History/Manager/Collection.php
@@ -0,0 +1,166 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @category    Mage
+ * @package     Mage_DesignEditor
+ * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+/**
+ * Visual design editor element collection
+ */
+class Mage_DesignEditor_Model_History_Manager_Collection
+{
+    /**
+     * Elements collection
+     *
+     * @var array
+     */
+    protected $_elements = array();
+
+    /**
+     * Xml types
+     *
+     * @var array
+     */
+    protected $_xmlTypes = array('layout');
+
+    /**
+     * Get types
+     *
+     * @return array
+     */
+    protected function _getElements()
+    {
+        return $this->_elements;
+    }
+
+    /**
+     * Get element
+     *
+     * @param string $type
+     * @param string $name
+     * @return Mage_DesignEditor_Model_History_Manager_Adapter_Abstract
+     */
+    protected function _getElement($type, $name)
+    {
+        if (!isset($this->_elements[$type][$name])) {
+            $this->_elements[$type][$name] = $this->_createElementByType($type);
+        }
+        return $this->_elements[$type][$name];
+    }
+
+    /**
+     * Create element by type
+     *
+     * @param string $type
+     * @return Mage_DesignEditor_Model_History_Manager_Adapter_Abstract
+     */
+    protected function _createElementByType($type)
+    {
+        return Mage_DesignEditor_Model_History_Manager_Adapter::factory($type);
+    }
+
+    /**
+     * Get elements by type
+     *
+     * @param string $type
+     * @return array|Mage_DesignEditor_Model_History_Manager_Adapter_Abstract
+     */
+    protected function _getElementsByType($type)
+    {
+        return isset($this->_elements[$type]) ? $this->_elements[$type] : array();
+    }
+
+    /**
+     * Add element
+     *
+     * @param string $change
+     * @return Mage_DesignEditor_Model_History_Manager_Adapter_Abstract
+     */
+    public function addElement($change)
+    {
+        $handle = $change['handle'];
+        $type   = $change['change_type'];
+        $name   = $change['element_name'];
+        $action = $change['action_name'];
+        $data   = isset($change['action_data']) ? $change['action_data'] : '';
+
+        $element = $this->_getElement($type, $name);
+        $element->setHandle($handle)->setType($type)->setName($name)->addAction($action, $data);
+        return $this;
+    }
+
+    /**
+     * Collection to xml
+     *
+     * @return string
+     */
+    public function toXml()
+    {
+        /** @var $xmlObject Varien_Simplexml_Element */
+        $xmlObject = new Varien_Simplexml_Element('<layout></layout>');
+
+        foreach ($this->_xmlTypes as $type) {
+            foreach ($this->_getElementsByType($type) as $element) {
+                $handleObject = $this->_getChildByHandle($xmlObject, $element->getHandle());
+                $element->setHandleObject($handleObject)->render();
+            }
+        }
+
+        return $xmlObject->asNiceXml();
+    }
+
+    /**
+     * Get child by handle
+     *
+     * @param Varien_Simplexml_Element $xmlObject
+     * @param string $handle
+     * @return Varien_Simplexml_Element
+     */
+    protected function _getChildByHandle($xmlObject, $handle)
+    {
+        foreach ($xmlObject->children() as $child) {
+            if ($child->getName() == $handle) {
+                return $child;
+            }
+        }
+        return $xmlObject->addChild($handle);
+    }
+
+    /**
+     * Collection to history log
+     *
+     * @return array
+     */
+    public function toHistoryLog()
+    {
+        $historyLog = array();
+
+        foreach ($this->_getElements() as $elementsByType) {
+            foreach ($elementsByType as $element) {
+                $historyLog = array_merge($historyLog, $element->toHistoryLog());
+            }
+        }
+
+        return $historyLog;
+    }
+}
diff --git a/app/code/core/Mage/DesignEditor/Model/Observer.php b/app/code/core/Mage/DesignEditor/Model/Observer.php
index 5a15788a488..602578bc1bd 100644
--- a/app/code/core/Mage/DesignEditor/Model/Observer.php
+++ b/app/code/core/Mage/DesignEditor/Model/Observer.php
@@ -29,8 +29,12 @@
  */
 class Mage_DesignEditor_Model_Observer
 {
-    const PAGE_HANDLE =             'design_editor_page';
-    const TOOLBAR_HANDLE =          'design_editor_toolbar';
+    /**#@+
+     * VDE specific layout update handles
+     */
+    const HANDLE_PAGE    = 'design_editor_page';
+    const HANDLE_TOOLBAR = 'design_editor_toolbar';
+    /**#@-*/
 
     /**
      * Renderer for wrapping html to be shown at frontend
@@ -70,9 +74,9 @@ class Mage_DesignEditor_Model_Observer
         $handles = $update->getHandles();
         $handle = reset($handles);
         if ($handle && $update->getPageHandleType($handle) == Mage_Core_Model_Layout_Update::TYPE_FRAGMENT) {
-            $update->addHandle(self::PAGE_HANDLE);
+            $update->addHandle(self::HANDLE_PAGE);
         }
-        $update->addHandle(self::TOOLBAR_HANDLE);
+        $update->addHandle(self::HANDLE_TOOLBAR);
     }
 
     /**
@@ -141,17 +145,18 @@ class Mage_DesignEditor_Model_Observer
 
         $block = $layout->getBlock($elementName);
         $isVde = ($block && 0 === strpos(get_class($block), 'Mage_DesignEditor_Block_'));
-        $isDraggable = $layout->isManipulationAllowed($elementName) && !$isVde;
+        $manipulationAllowed = $layout->isManipulationAllowed($elementName) && !$isVde;
         $isContainer = $layout->isContainer($elementName);
 
-        if ($isDraggable || $isContainer) {
+        if ($manipulationAllowed || $isContainer) {
             $elementId = 'vde_element_' . rtrim(strtr(base64_encode($elementName), '+/', '-_'), '=');
             $this->_wrappingRenderer->setData(array(
                 'element_id'    => $elementId,
                 'element_title' => $layout->getElementProperty($elementName, 'label') ?: $elementName,
                 'element_html'  => $transport->getData('output'),
-                'is_draggable'  => $isDraggable,
+                'is_manipulation_allowed'  => $manipulationAllowed,
                 'is_container'  => $isContainer,
+                'element_name'  => $elementName,
             ));
             $transport->setData('output', $this->_wrappingRenderer->toHtml());
         }
diff --git a/app/code/core/Mage/DesignEditor/controllers/EditorController.php b/app/code/core/Mage/DesignEditor/controllers/EditorController.php
index 3ab0500effa..65281c21e56 100644
--- a/app/code/core/Mage/DesignEditor/controllers/EditorController.php
+++ b/app/code/core/Mage/DesignEditor/controllers/EditorController.php
@@ -32,9 +32,11 @@ class Mage_DesignEditor_EditorController extends Mage_Core_Controller_Front_Acti
     /**
      * @var Mage_DesignEditor_Model_Session
      */
-    protected $_session = null;
+    protected $_session;
 
     /**
+     * Variable to store full action name
+     *
      * @var string
      */
     protected $_fullActionName = '';
@@ -132,4 +134,58 @@ class Mage_DesignEditor_EditorController extends Mage_Core_Controller_Front_Acti
         }
         $this->getResponse()->setRedirect($backUrl);
     }
+
+    /**
+     * Compact history
+     */
+    public function compactHistoryAction()
+    {
+        $historyData = Mage::app()->getRequest()->getPost();
+
+        if (!$historyData) {
+            $this->getResponse()->setBody(Mage::helper('Mage_Core_Helper_Data')->jsonEncode(
+                array(Mage_Core_Model_Message::ERROR => array($this->__('Invalid post data')))
+            ));
+            return;
+        }
+
+        /** @var $historyModel Mage_DesignEditor_Model_History */
+        $historyModel = Mage::getModel('Mage_DesignEditor_Model_History');
+        try {
+            $this->getResponse()->setBody(Mage::helper('Mage_Core_Helper_Data')->jsonEncode(array(
+                Mage_Core_Model_Message::SUCCESS => array($historyModel->setChangeLog($historyData)->getCompactLog())
+            )));
+        } catch (Mage_Core_Exception $e) {
+            $this->getResponse()->setBody(Mage::helper('Mage_Core_Helper_Data')->jsonEncode(
+                array(Mage_Core_Model_Message::ERROR => array($e->getMessage()))
+            ));
+        }
+    }
+
+    /**
+     * Get layout xml
+     */
+    public function compactXmlAction()
+    {
+        $historyData = Mage::app()->getRequest()->getPost();
+
+        if (!$historyData) {
+            $this->getResponse()->setBody(Mage::helper('Mage_Core_Helper_Data')->jsonEncode(
+                array(Mage_Core_Model_Message::ERROR => array($this->__('Invalid post data')))
+            ));
+            return;
+        }
+
+        /** @var $historyModel Mage_DesignEditor_Model_History */
+        $historyModel = Mage::getModel('Mage_DesignEditor_Model_History');
+        try {
+            $this->getResponse()->setBody(Mage::helper('Mage_Core_Helper_Data')->jsonEncode(array(
+                Mage_Core_Model_Message::SUCCESS => array($historyModel->setChangeLog($historyData)->getCompactXml())
+            )));
+        } catch (Mage_Core_Exception $e) {
+            $this->getResponse()->setBody(Mage::helper('Mage_Core_Helper_Data')->jsonEncode(
+                array(Mage_Core_Model_Message::ERROR => array($e->getMessage()))
+            ));
+        }
+    }
 }
diff --git a/app/code/core/Mage/DesignEditor/etc/jstranslator.xml b/app/code/core/Mage/DesignEditor/etc/jstranslator.xml
new file mode 100644
index 00000000000..e91b3038855
--- /dev/null
+++ b/app/code/core/Mage/DesignEditor/etc/jstranslator.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<!--
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Academic Free License (AFL 3.0)
+ * that is bundled with this package in the file LICENSE_AFL.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/afl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @category    Mage
+ * @package     Mage_DesignEditor
+ * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/afl-3.0.php  Academic Free License (AFL 3.0)
+ */
+-->
+<jstranslator>
+    <mage-designeditor-change-layout-moved-title translate="message" module="Mage_DesignEditor">
+        <message>Block #block# moved</message>
+    </mage-designeditor-change-layout-moved-title>
+    <mage-designeditor-change-layout-removed-title translate="message" module="Mage_DesignEditor">
+        <message>Block #block# removed</message>
+    </mage-designeditor-change-layout-removed-title>
+    <mage-designeditor-change-layout-invalid-type translate="message" module="Mage_DesignEditor">
+        <message>Invalid change type "#type#"</message>
+    </mage-designeditor-change-layout-invalid-type>
+</jstranslator>
diff --git a/app/code/core/Mage/DesignEditor/view/frontend/css/styles.css b/app/code/core/Mage/DesignEditor/view/frontend/css/styles.css
index f09b66684da..16d9a4a8cdf 100644
--- a/app/code/core/Mage/DesignEditor/view/frontend/css/styles.css
+++ b/app/code/core/Mage/DesignEditor/view/frontend/css/styles.css
@@ -85,6 +85,8 @@ body {
     text-decoration:none;
     background-image:url(../images/button.png);
     background-size:contain;
+    float: left;
+    margin-right:3px;
 }
 #vde_toolbar_buttons a.vde_button:hover {
     box-shadow:0 0 1pt 1pt #c9c6be;
@@ -108,15 +110,15 @@ body {
     border-radius: 4px;
 }
 .vde_element_title {
-    font: 10pt Arial, Helvetica, sans-serif;
-    margin: -2px 0px 0px -4px;
-    padding: 0px;
+    font-family:Arial, Helvetica, sans-serif;
+    margin: -2px 0 0 -4px;
+    padding: 0;
     border-width: 2px 5px 6px 7px;
     border-image: url(../images/block.png) 2 5 6 7 stretch stretch;
     border-image-outset: fill;
     -webkit-border-image: url(../images/block.png) 2 5 6 7 stretch stretch;
     -moz-border-image: url(../images/block.png) 2 5 6 7 stretch stretch;
-    color: white;
+    color: black;
     font-size: 8pt;
     font-weight: bold;
     max-width: 150px;
@@ -126,6 +128,22 @@ body {
     line-height: 17px;
     cursor: default;
 }
+.vde_element_remove {
+    margin: -26px -6px 0px -4px;
+    padding: 0px;
+    border-width: 2px 5px 6px 7px;
+    border-image: url(../images/stub.png) 2 5 6 7 stretch stretch;
+    border-image-outset: fill;
+    -webkit-border-image: url(../images/stub.png) 2 5 6 7 stretch stretch;
+    -moz-border-image: url(../images/stub.png) 2 5 6 7 stretch stretch;
+    max-width: 20px;
+    height: 18px;
+    overflow: hidden;
+    text-align: right;
+    line-height: 17px;
+    cursor: default;
+    float: right;
+}
 .vde_element_wrapper.vde_container {
     border: 2px solid #7bc361;
 }
@@ -262,3 +280,23 @@ body {
 #vde_handles_tree .vde_option_fragment a {
     color: #eea243;
 }
+
+.vde_history_toolbar {
+    position: fixed;
+    left:0; top:150px;
+    width:220px;
+    background: #f0efe9;
+    border-bottom: 1pt solid #dddcd8;
+    box-shadow: 0 0 4pt 1pt #cbcbcb;
+    padding: 0 3pt;
+    line-height: 13pt;
+}
+.vde_history_toolbar ul {}
+.vde_history_toolbar ul li {
+    white-space: nowrap;
+    overflow: hidden;
+}
+
+.vde_element_remove {
+    display: none;
+}
diff --git a/app/code/core/Mage/DesignEditor/view/frontend/js/base.js b/app/code/core/Mage/DesignEditor/view/frontend/js/base.js
index 1931a093862..080229e2686 100644
--- a/app/code/core/Mage/DesignEditor/view/frontend/js/base.js
+++ b/app/code/core/Mage/DesignEditor/view/frontend/js/base.js
@@ -1,4 +1,4 @@
-/**
+/**
  * Magento
  *
  * NOTICE OF LICENSE
@@ -15,138 +15,138 @@
  *
  * Do not edit or add to this file if you wish to upgrade Magento to newer
  * versions in the future. If you wish to customize Magento for your
- * needs please refer to http://www.magentocommerce.com for more information.
- *
- * @category    Mage
- * @package     Mage_DesignEditor
- * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
- * @license     http://opensource.org/licenses/afl-3.0.php  Academic Free License (AFL 3.0)
- */
-
-(function($) {
-
-    /**
-     * Widget tree
-     */
-    $.widget('vde.vde_tree', {
-        options: {
-            ui: {
-                select_limit: 1,
-                selected_parent_close: false
-            },
-            themes: {
-                dots: false,
-                icons: false
-            }
-        },
-        _create: function () {
-            this._bind();
-            this.element.jstree(this.options);
-        },
-        _bind: function() {
-            var self = this;
-            this.element
-                .on('loaded.jstree', function (e, data) {
-                    var selectNode = self.element.data('selected');
-                    if (selectNode) {
-                        self.element.jstree('select_node', self.element.find(selectNode));
-                    }
-                })
-                .on('select_node.jstree', function (e, data) {
-                    var link = $(data.rslt.obj).find('a:first');
-                    $(this).trigger('link_selected.' + self.widgetName, [link]);
-                    if (data.rslt.e) { // User clicked the link, not just tree initialization
-                        window.location = link.attr('href');
-                    }
-                });
-        }
-    });
-
-    /**
-     * Widget menu
-     */
-    $.widget('vde.vde_menu', {
-        options: {
-            type: 'popup',
-            titleSelector: '.vde_toolbar_cell_title',
-            titleTextSelector: '.vde_toolbar_cell_value',
-            activeClass: 'active'
-        },
-        _create: function () {
-            this._bind();
-            if (this.options.treeSelector) {
-                var tree = this.element.find(this.options.treeSelector);
-                if (tree.size()) {
-                    tree.vde_tree();
-                    if (this.options.slimScroll) {
-                        var self = this;
-                        this.element
-                            .one('activate_toolbar_cell.' + self.widgetName, function () {
-                                self.element.find(self.options.treeSelector).slimScroll({
-                                    color: '#cccccc',
-                                    alwaysVisible: true,
-                                    opacity: 1,
-                                    height: 'auto',
-                                    size: 9
-                                });
-                        })
-                    }
-                }
-            }
-        },
-        _bind: function () {
-            var self = this,
-                titleText = self.element.find(self.options.titleTextSelector);
-            this.element
-                .on('change_title.' + self.widgetName, function(e, title) {
-                    titleText.text(title);
-                })
-                .on('link_selected.vde_tree', function(e, link) {
-                    titleText.text(link.text());
-                })
-                .find(this.options.titleSelector)
-                .on('click.' + self.widgetName, function(e) {
-                    self.element.hasClass(self.options.activeClass) ?
-                        self.hide(e):
-                        self.show(e);
-                })
-            $('body').on('click', function(e) {
-                var widgetInstancesSelector = ':' + self.namespace + '-' + self.widgetName;
-                $(widgetInstancesSelector).not($(e.target).parents(widgetInstancesSelector)).vde_menu('hide');
-            })
-        },
-        show: function(e) {
-            this.element.addClass(this.options.activeClass).trigger('activate_toolbar_cell.' + this.widgetName);
-        },
-        hide: function(e) {
-            this.element.removeClass(this.options.activeClass);
-        }
-    });
-
-    /**
-     * Widget checkbox
-     */
-    $.widget('vde.vde_checkbox', {
-        options: {
-            checkedClass: 'checked'
-        },
-        _create: function () {
-            this._bind();
-        },
-        _bind: function () {
-            var self = this;
-            this.element.on('click', function () {
-                self._click();
-            })
-        },
-        _click: function () {
-            if (this.element.hasClass(this.options.checkedClass)) {
-                this.element.removeClass(this.options.checkedClass);
-                this.element.trigger('unchecked.' + this.widgetName);
-            } else {
-                this.element.addClass(this.options.checkedClass);
-                this.element.trigger('checked.' + this.widgetName);
-            }
-        }
-    });
-})(jQuery);
\ No newline at end of file
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @category    Mage
+ * @package     Mage_DesignEditor
+ * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/afl-3.0.php  Academic Free License (AFL 3.0)
+ */
+
+(function($) {
+
+    /**
+     * Widget tree
+     */
+    $.widget('vde.vde_tree', {
+        options: {
+            ui: {
+                select_limit: 1,
+                selected_parent_close: false
+            },
+            themes: {
+                dots: false,
+                icons: false
+            }
+        },
+        _create: function () {
+            this._bind();
+            this.element.jstree(this.options);
+        },
+        _bind: function() {
+            var self = this;
+            this.element
+                .on('loaded.jstree', function (e, data) {
+                    var selectNode = self.element.data('selected');
+                    if (selectNode) {
+                        self.element.jstree('select_node', self.element.find(selectNode));
+                    }
+                })
+                .on('select_node.jstree', function (e, data) {
+                    var link = $(data.rslt.obj).find('a:first');
+                    $(this).trigger('link_selected.' + self.widgetName, [link]);
+                    if (data.rslt.e) { // User clicked the link, not just tree initialization
+                        window.location = link.attr('href');
+                    }
+                });
+        }
+    });
+
+    /**
+     * Widget menu
+     */
+    $.widget('vde.vde_menu', {
+        options: {
+            type: 'popup',
+            titleSelector: '.vde_toolbar_cell_title',
+            titleTextSelector: '.vde_toolbar_cell_value',
+            activeClass: 'active'
+        },
+        _create: function () {
+            this._bind();
+            if (this.options.treeSelector) {
+                var tree = this.element.find(this.options.treeSelector);
+                if (tree.size()) {
+                    tree.vde_tree();
+                    if (this.options.slimScroll) {
+                        var self = this;
+                        this.element
+                            .one('activate_toolbar_cell.' + self.widgetName, function () {
+                                self.element.find(self.options.treeSelector).slimScroll({
+                                    color: '#cccccc',
+                                    alwaysVisible: true,
+                                    opacity: 1,
+                                    height: 'auto',
+                                    size: 9
+                                });
+                        })
+                    }
+                }
+            }
+        },
+        _bind: function () {
+            var self = this,
+                titleText = self.element.find(self.options.titleTextSelector);
+            this.element
+                .on('change_title.' + self.widgetName, function(e, title) {
+                    titleText.text(title);
+                })
+                .on('link_selected.vde_tree', function(e, link) {
+                    titleText.text(link.text());
+                })
+                .find(this.options.titleSelector)
+                .on('click.' + self.widgetName, function(e) {
+                    self.element.hasClass(self.options.activeClass) ?
+                        self.hide(e):
+                        self.show(e);
+                })
+            $('body').on('click', function(e) {
+                var widgetInstancesSelector = ':' + self.namespace + '-' + self.widgetName;
+                $(widgetInstancesSelector).not($(e.target).parents(widgetInstancesSelector)).vde_menu('hide');
+            })
+        },
+        show: function(e) {
+            this.element.addClass(this.options.activeClass).trigger('activate_toolbar_cell.' + this.widgetName);
+        },
+        hide: function(e) {
+            this.element.removeClass(this.options.activeClass);
+        }
+    });
+
+    /**
+     * Widget checkbox
+     */
+    $.widget('vde.vde_checkbox', {
+        options: {
+            checkedClass: 'checked'
+        },
+        _create: function () {
+            this._bind();
+        },
+        _bind: function () {
+            var self = this;
+            this.element.on('click', function () {
+                self._click();
+            })
+        },
+        _click: function () {
+            if (this.element.hasClass(this.options.checkedClass)) {
+                this.element.removeClass(this.options.checkedClass);
+                this.element.trigger('unchecked.' + this.widgetName);
+            } else {
+                this.element.addClass(this.options.checkedClass);
+                this.element.trigger('checked.' + this.widgetName);
+            }
+        }
+    });
+})(jQuery);
diff --git a/app/code/core/Mage/DesignEditor/view/frontend/js/change/history.js b/app/code/core/Mage/DesignEditor/view/frontend/js/change/history.js
new file mode 100644
index 00000000000..a84e9ecc498
--- /dev/null
+++ b/app/code/core/Mage/DesignEditor/view/frontend/js/change/history.js
@@ -0,0 +1,67 @@
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Academic Free License (AFL 3.0)
+ * that is bundled with this package in the file LICENSE_AFL.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/afl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @category    Mage
+ * @package     Mage_DesignEditor
+ * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/afl-3.0.php  Academic Free License (AFL 3.0)
+ */
+
+( function ( $ ) {
+    /**
+     * Change history
+     */
+    $.fn.history = (function() {
+        var _object;
+
+        var _init = function() {
+            if (!_object) {
+                _object = new HistoryObject();
+            }
+            return _object;
+        }
+
+        return _init();
+    })();
+
+    /**
+     * History object
+     */
+    function HistoryObject() {
+        var history = [];
+        return {
+            add: function(revision, title) {
+                history[revision] = title;
+                console.log(history[revision]);
+                /** @todo add your code */
+            },
+            undo: function() {
+                /** @todo add your code */
+            },
+            redo: function() {
+                /** @todo add your code */
+            },
+            revertToRevision: function(revision) {
+                /** @todo add your code */
+            }
+
+        };
+
+    };
+})( jQuery );
\ No newline at end of file
diff --git a/app/code/core/Mage/DesignEditor/view/frontend/js/change/layout.js b/app/code/core/Mage/DesignEditor/view/frontend/js/change/layout.js
new file mode 100644
index 00000000000..05e9a986c5a
--- /dev/null
+++ b/app/code/core/Mage/DesignEditor/view/frontend/js/change/layout.js
@@ -0,0 +1,333 @@
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Academic Free License (AFL 3.0)
+ * that is bundled with this package in the file LICENSE_AFL.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/afl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @category    Mage
+ * @package     Mage_DesignEditor
+ * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/afl-3.0.php  Academic Free License (AFL 3.0)
+ */
+
+( function ( $ ) {
+    /**
+     * Abstract change object
+     */
+    function abstractChange() {
+        /**
+         * Clean change data
+         */
+        var _cleanData = function() {
+            this.postData = {};
+        }
+
+        return {
+            type: null,
+            data: null,
+            status: 'active',
+            getType: function() {
+                if (!this.type) {
+                    throw Error(Translator.translate('Type of change is not defined'));
+                }
+                return this.type;
+            },
+            getStatus: function() {
+                return status;
+            },
+            undo: function() {
+                if (this.status == 'undone') {
+                    throw Error(Translator.translate("Can't undo change twice"));
+                }
+                alert('undo');
+                this.status = 'undone';
+            },
+            getTitle: function() {
+                throw Error(Translator.translate('Method "getTitle" is not implemented'));
+            },
+            setData: function(data) {
+                this.data = data;
+            },
+            getData: function() {
+                return this.data;
+            },
+            getPostData: function() {
+                throw Error(Translator.translate('Method "getTitle" is not implemented'));
+            },
+            setActionData: function() {
+                throw Error(Translator.translate('Method "getTitle" is not implemented'));
+            }
+        };
+    }
+
+    /**
+     * Layout change object
+     */
+    function layoutChange() {
+        /**
+         * Move action
+         */
+        var ACTION_MOVE = 'move';
+
+        /**
+         * Remove action
+         */
+        var ACTION_REMOVE = 'remove';
+
+        /**
+         * Type get post data
+         */
+        var TYPE_POST_DATA = 'getPostData';
+
+        /**
+         * Type set data
+         */
+        var TYPE_SET_ACTION = 'setAction';
+
+        return {
+            type: 'layout',
+            getTitle: function() {
+                var data = this.getData();
+                var title;
+                switch (data.action) {
+
+                    case ACTION_MOVE:
+                        if (data.origin.container == data.destination.container) {
+                            title = Translator.translate('Block #block# sorted').replace('#block#', data.block);
+                        } else {
+                            title = Translator.translate('Block #block# moved').replace('#block#', data.block);
+                        }
+                        break;
+                    case ACTION_REMOVE:
+                        title = Translator.translate('Block #block# removed').replace('#block#', data.block);
+                        break;
+                }
+                return title;
+            },
+            _executeActionByType: function(action, type, data) {
+                switch (action) {
+                    case ACTION_MOVE:
+                        return this[ '_' + type + this._stringToTitleCase(action) ](data);
+                        break;
+                    case ACTION_REMOVE:
+                        return this[ '_' + type + this._stringToTitleCase(action) ](data);
+                        break;
+                    default:
+                        throw Error(Translator.translate('Invalid action "#action#"').replace('#action#', action));
+                }
+            },
+            /** @todo maybe we need to create global object for strings? */
+            _stringToTitleCase: function(string) {
+                return string.charAt(0).toUpperCase() + string.slice(1).toLowerCase()
+            },
+            setActionData: function(data) {
+                this._executeActionByType(data.action_name, TYPE_SET_ACTION, data);
+            },
+            _setActionMove: function(data) {
+                this.setData({
+                    action: ACTION_MOVE,
+                    block: data.element_name,
+                    origin: {
+                        container: null,
+                        order: null
+                    },
+                    destination: {
+                        container: data.action_data.container,
+                        order: data.action_data.after
+                    }
+                });
+            },
+            _setActionRemove: function(data) {
+                this.setData({
+                    action: ACTION_REMOVE,
+                    block: data.element_name,
+                    origin: {
+                        container: null,
+                        order: null
+                    },
+                    destination: {
+                        container: null,
+                        order: null
+                    }
+                });
+            },
+            getPostData: function() {
+                var data = this.getData();
+                return this._executeActionByType(data.action, TYPE_POST_DATA, data);
+            },
+            _getPostDataMove: function(data) {
+                return {
+                    handle: 'current_handle',
+                    change_type: this.type,
+                    element_name: data.block,
+                    action_name: ACTION_MOVE,
+                    action_data: {
+                        container: data.destination.container,
+                        after: data.destination.order
+                    }
+                }
+            },
+            _getPostDataRemove: function(data) {
+                return {
+                    handle: 'current_handle',
+                    change_type: this.type,
+                    element_name: data.block,
+                    action_name: ACTION_REMOVE
+                }
+            }
+        };
+    }
+
+    /**
+     * File change object
+     */
+    function fileChange() {
+        this._getTitle = function() {
+            return 'File change';
+        };
+        return {
+            type: 'file'
+        };
+    }
+
+    /**
+     * Change factory
+     */
+    $.fn.changeFactory = (function() {
+        /**
+         * Data sender
+         */
+        var _dataSender;
+
+        return {
+            _init: function(baseUrl) {
+                _dataSender = $.fn.changeFactory.dataSender;
+                _dataSender._init(baseUrl);
+            },
+            post: function(data) {
+                _dataSender.post(data);
+            },
+            getInstance: function(type) {
+                switch(type) {
+                    case 'layout':
+                        var change = new layoutChange();
+                        break;
+                    case 'file':
+                        var change = new fileChange();
+                        break;
+                    default:
+                        throw Error(Translator.translate('Invalid change type "#type#"').replace('#type#', type));
+                }
+                return $.extend(new abstractChange(), change);
+            }
+        }
+    })();
+
+    /**
+     * Change factory data sender
+     */
+    $.fn.changeFactory.dataSender = (function() {
+        /**
+         * Save change url
+         *
+         */
+        var changeUrl = 'design/editor/savechange/';
+
+        /**
+         * Lock save when sending in progress
+         */
+        var _isSaveLocked = false;
+
+        /**
+         * Queue for layout changes
+         */
+        var _queue = {};
+
+        /**
+         * Queue length
+         */
+        var _queueLength = 0;
+
+        /**
+         * Save change url
+         */
+        var _saveChangeUrl = '';
+
+        /**
+         * Add data to queue
+         */
+        var _addDataToQueue = function(data) {
+            _queue[_queueLength] = data;
+            _queueLength++;
+        }
+
+        /**
+         * Clean queue
+         */
+        var _clearQueue = function() {
+            _queueLength = 0;
+            _queue = {};
+        }
+
+        /**
+         * Send queue
+         */
+        var _sendQueue = function() {
+            var data = _queue;
+            _clearQueue();
+
+            $.ajax({
+                url: _saveChangeUrl,
+                type: "post",
+                dataType: 'json',
+                data: data,
+                success: function(data) {
+                    if (data.success) {
+                        $.each(data.success[0], function(revision, actionTitle) {
+                            $.fn.history.add(revision, actionTitle);
+                        });
+                        if (_queueLength > 0) {
+                            _sendQueue();
+                            return;
+                        }
+                        _isSaveLocked = false;
+                    } else if(data.error) {
+                        _isSaveLocked = false;
+                        alert(data.error[0]);
+                    }
+                },
+                error: function(data) {
+                    _isSaveLocked = false;
+                    throw Error(Translator.translate('Some problem with save action'));
+                }
+            });
+        }
+
+        return {
+            _init: function(baseUrl) {
+                _saveChangeUrl = baseUrl + changeUrl;
+            },
+            post: function(data) {
+                _addDataToQueue(data);
+                if (_isSaveLocked) {
+                    return;
+                }
+                _isSaveLocked = true;
+                _sendQueue();
+            }
+        }
+    })();
+})( jQuery );
diff --git a/app/code/core/Mage/DesignEditor/view/frontend/js/design_editor.js b/app/code/core/Mage/DesignEditor/view/frontend/js/design_editor.js
index f77dc10f048..420a0627466 100644
--- a/app/code/core/Mage/DesignEditor/view/frontend/js/design_editor.js
+++ b/app/code/core/Mage/DesignEditor/view/frontend/js/design_editor.js
@@ -1,4 +1,4 @@
-/**
+/**
  * Magento
  *
  * NOTICE OF LICENSE
@@ -15,183 +15,538 @@
  *
  * Do not edit or add to this file if you wish to upgrade Magento to newer
  * versions in the future. If you wish to customize Magento for your
- * needs please refer to http://www.magentocommerce.com for more information.
- *
- * @category    Mage
- * @package     Mage_DesignEditor
- * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
- * @license     http://opensource.org/licenses/afl-3.0.php  Academic Free License (AFL 3.0)
- */
-
-(function($) {
-
-    /**
-     * Widget container
-     */
-    $.widget('vde.vde_container', $.ui.sortable, {
-        options: {
-            tolerance: 'pointer',
-            revert: true,
-            connectWithSelector: '.vde_element_wrapper.vde_container',
-            placeholder: 'vde_placeholder',
-            hoverClass: 'vde_container_hover',
-            items: '.vde_element_wrapper.vde_draggable',
-            helper: 'clone',
-            appendTo: 'body'
-        },
-        _create: function () {
-            this.element.data('sortable', this);
-            var self = this;
-            this.options = $.extend({}, this.options, {
-                start: function(event, ui) {
-                    ui.placeholder.css({height: $(ui.helper).outerHeight(true)});
-                    self.element.vde_container('option', 'connectWith', $(self.options.connectWithSelector).not(ui.item))
-                        .vde_container('refresh');
-                },
-                over: function(event, ui) {
-                    self.element.addClass(self.options.hoverClass);
-                },
-                out: function(event, ui) {
-                    self.element.removeClass(self.options.hoverClass);
-                }
-            });
-            $.ui.sortable.prototype._create.apply(this, arguments);
-        }
-    });
-
-    /**
-     * Widget panel
-     */
-    $.widget('vde.vde_panel', {
-        options: {
-            cellSelector: '.vde_toolbar_cell',
-            handlesHierarchySelector: '#vde_handles_hierarchy',
-            treeSelector: '#vde_handles_tree'
-        },
-        _create: function () {
-            var self = this;
-            this.element.find(this.options.cellSelector).each(function () {
-                var params = $(this).is(self.options.handlesHierarchySelector) ? {treeSelector: self.options.treeSelector, slimScroll: true } : {};
-                $(this).vde_menu(params);
-            });
-        }
-    });
-
-    /**
-     * Widget page
-     */
-    $.widget('vde.vde_page', {
-        options: {
-            containerSelector: '.vde_element_wrapper.vde_container',
-            panelSelector: '#vde_toolbar',
-            highlightElementSelector: '.vde_element_wrapper',
-            highlightElementTitleSelector: '.vde_element_title',
-            highlightCheckboxSelector: '#vde_highlighting',
-            cookieHighlightingName: 'vde_highlighting'
-        },
-        _create: function () {
-            this._initContainers();
-            this._initPanel();
-        },
-        _initContainers: function () {
-            $(this.options.containerSelector)
-                .vde_container().disableSelection();
-        },
-        _initPanel: function () {
-            $(this.options.panelSelector).vde_panel();
-        }
-    });
-
-    /**
-     * Widget page highlight functionality
-     */
-    var pageBasePrototype = $.vde.vde_page.prototype;
-    $.widget('vde.vde_page', $.extend({}, pageBasePrototype, {
-        _create: function () {
-            pageBasePrototype._create.apply(this, arguments);
-            if (this.options.highlightElementSelector) {
-                this._initHighlighting();
-                this._bind();
-            }
-        },
-        _bind: function () {
-            var self = this;
-            this.element
-                .on('checked.vde_checkbox', function () {
-                    self._highlight();
-                })
-                .on('unchecked.vde_checkbox', function () {
-                    self._unhighlight();
-                });
-        },
-        _initHighlighting: function () {
-            if (this.options.highlightCheckboxSelector) {
-                $(this.options.highlightCheckboxSelector)
-                    .vde_checkbox();
-            }
-            this.highlightBlocks = {};
-            if (Mage.Cookies.get(this.options.cookieHighlightingName) == 'off') {
-                this._processMarkers();
-            }
-
-        },
-        _highlight: function () {
-            Mage.Cookies.clear(this.options.cookieHighlightingName);
-            var self = this;
-            $(this.options.highlightElementSelector).each(function () {
-                $(this)
-                    .append(self._getChildren($(this).attr('id')))
-                    .show()
-                    .children(self.options.highlightElementTitleSelector).slideDown('fast');
-            });
-            this.highlightBlocks = {};
-        },
-        _unhighlight: function () {
-            Mage.Cookies.set(this.options.cookieHighlightingName, 'off');
-            var self = this;
-            $(this.options.highlightElementSelector).each(function () {
-                var elem = $(this);
-                elem.children(self.options.highlightElementTitleSelector).slideUp('fast', function () {
-                    var children = elem.contents(':not(' + self.options.highlightElementTitleSelector + ')');
-                    var parentId = elem.attr('id');
-                    children.each(function () {
-                        self._storeChild(parentId, this);
-                    });
-                    elem.after(children).hide();
-                });
-            });
-        },
-        _processMarkers: function () {
-            var self = this,
-                parentsIdsStack = [],
-                currentParentId;
-            $('*').contents().each(function () {
-                if (this.nodeType == Node.COMMENT_NODE) {
-                    if (this.data.substr(0, 9) == 'start_vde') {
-                        currentParentId = this.data.substr(6, this.data.length);
-                        parentsIdsStack.push(currentParentId);
-                        this.parentNode.removeChild(this);
-                    } else if (this.data.substr(0, 7) == 'end_vde') {
-                        if (this.data.substr(4, this.data.length) !== currentParentId) {
-                            throw "Could not find closing element for opened '" + currentParentId + "' element";
-                        }
-                        parentsIdsStack.pop();
-                        currentParentId = parentsIdsStack[parentsIdsStack.length - 1];
-                        this.parentNode.removeChild(this);
-                    }
-                } else if (currentParentId) {
-                    self._storeChild(currentParentId, this);
-                }
-            })
-        },
-        _storeChild: function(parentId, child) {
-            if (!this.highlightBlocks[parentId]) {
-                this.highlightBlocks[parentId] = [];
-            }
-            this.highlightBlocks[parentId].push(child);
-        },
-        _getChildren: function(parentId) {
-            return (!this.highlightBlocks[parentId]) ? [] : this.highlightBlocks[parentId];
-        }
-    }));
-})( jQuery );
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @category    Mage
+ * @package     Mage_DesignEditor
+ * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/afl-3.0.php  Academic Free License (AFL 3.0)
+ */
+
+(function($) {
+
+    /**
+     * Widget block
+     */
+    $.widget( "vde.block", { _create: function() {}} );
+
+    /**
+     * Widget container
+     */
+    $.widget('vde.vde_container', $.ui.sortable, {
+        options: {
+            tolerance: 'pointer',
+            revert: true,
+            connectWithSelector: '.vde_element_wrapper.vde_container',
+            placeholder: 'vde_placeholder',
+            hoverClass: 'vde_container_hover',
+            items: '.vde_element_wrapper.vde_draggable',
+            helper: 'clone',
+            appendTo: 'body',
+            containerSelector: '.vde_container'
+        },
+        _create: function() {
+            var self = this;
+            this.element.data('sortable', this);
+            self.options =  $.extend({}, self.options, {
+                start: function( event, ui ) {
+                    ui.placeholder.css( { height: $( ui.helper ).outerHeight( true ) } );
+                    self.element.vde_container('option', 'connectWith', $(self.options.connectWithSelector).not(ui.item))
+                        .vde_container('refresh');
+                },
+                over: function(event, ui) {
+                    self.element.addClass(self.options.hoverClass);
+                },
+                out: function(event, ui) {
+                    self.element.removeClass(self.options.hoverClass);
+                }
+            });
+            $.ui.sortable.prototype._create.apply(this, arguments);
+        }
+    });
+
+    /**
+     * Widget container with ability to log "move" operations
+     */
+    var containerBasePrototype = $.vde.vde_container.prototype;
+    $.widget( "vde.vde_container", $.extend({}, containerBasePrototype, {
+        history: null,
+        _onDragElementStart: function(event, ui) {
+            var block = ui.item;
+            if (this._isBlockDeeplyNested(block)) {
+                return;
+            }
+
+            if (this._getContainer(block).data('name') != this.element.data('name')) {
+                throw Error('Invalid container. Event "start" should be handled only for closest container');
+            }
+
+            this.element.bind( this.getEventName('stop', 'history'), {
+                position: block.index()
+            }, $.proxy(this._onDragElementStop, this));
+        },
+        _onDragElementStop: function(event, ui) {
+            var block = ui.item;
+            var originContainer = this.element.data('name');
+            var originPosition = event.data.position;
+            var destinationContainer = this._getContainer(block).data('name');
+            var destinationPosition = block.index();
+
+            var containerChanged = destinationContainer != originContainer;
+            var sortingOrderChanged = destinationPosition != originPosition;
+            if (containerChanged || sortingOrderChanged) {
+                var change = $.fn.changeFactory.getInstance('layout');
+                change.setData({
+                    action: 'move',
+                    block: block.data('name'),
+                    origin: {
+                        container: originContainer,
+                        order: originPosition
+                    },
+                    destination: {
+                        container: destinationContainer,
+                        order: destinationPosition
+                    }
+                });
+
+                // This is the dependency of Container on History
+                this.getHistory().addItem(change);
+            }
+
+            this.element.unbind( this.getEventName('stop', 'history'), $.proxy(this._onDragElementStop, this));
+        },
+        _getContainer: function(item) {
+            return item.parent().closest(this.options.containerSelector);
+        },
+        _isBlockDeeplyNested: function(block) {
+            return this._getContainer(block).attr('id') != this.element.attr('id');
+        },
+        getEventName: function(type, namespace) {
+            var name = this.widgetEventPrefix + type;
+            if (namespace) {
+                name =  name + '.' + namespace;
+            }
+            return name;
+        },
+        setHistory: function(history) {
+            this.history = history;
+            this.element.bind( this.getEventName('start', 'history'), $.proxy(this._onDragElementStart, this));
+        },
+        getHistory: function() {
+            if (!this.history) {
+                throw Error('History element should be set before usage');
+            }
+            return this.history;
+        }
+    }));
+
+    /**
+     * Widget panel
+     */
+    $.widget('vde.vde_panel', {
+        options: {
+            cellSelector: '.vde_toolbar_cell',
+            handlesHierarchySelector: '#vde_handles_hierarchy',
+            treeSelector: '#vde_handles_tree'
+        },
+        _create: function() {
+            this._initCells();
+        },
+        _initCells : function() {
+            var self = this;
+            this.element.find( this.options.cellSelector ).each( function(){
+                $( this ).is( self.options.handlesHierarchySelector ) ?
+                    $( this ).vde_menu( {treeSelector : self.options.treeSelector, slimScroll:true } ) :
+                    $( this ).vde_menu();
+            });
+            this.element.find( this.options.cellSelector ).vde_menu();
+        },
+        destroy: function() {
+            this.element.find( this.options.cellSelector ).each( function(i, element) {
+                $(element).data('vde_menu').destroy();
+            });
+            $.Widget.prototype.destroy.call( this );
+        }
+    });
+
+    /**
+     * Widget history
+     *
+     * @TODO can we make this not a widget but global object?
+     */
+    $.widget( "vde.vde_history" , {
+        widgetEventPrefix: 'history/',
+        options:{},
+        items: [],
+        _create: function() {},
+        getEventName: function(type, namespace) {
+            var name = this.widgetEventPrefix + type;
+            if (namespace) {
+                name =  name + '.' + namespace;
+            }
+            return name;
+        },
+        addItem: function(change) {
+            this.items.push(change);
+            this._trigger('add', null, change);
+        },
+        getItems: function() {
+            return this.items;
+        },
+        deleteItems: function() {
+            this.items = [];
+        }
+    });
+
+    /**
+     * Widget history toolbar
+     *
+     * @todo move out from history toolbar send POST data functionality
+     */
+    $.widget( "vde.vde_historyToolbar" , {
+        options:{
+            compactLogButtonSelector: '.compact-log',
+            viewLayoutButtonSelector: '.view-layout',
+            baseUrl: null,
+            compactLogUrl: null,
+            viewLayoutUrl: null
+        },
+        _history: null,
+        _create: function() {
+            this._initToolbar();
+            this._initButtons();
+        },
+        _initToolbar : function() {},
+        _initButtons : function() {
+            $(this.options.compactLogButtonSelector).bind(
+                'click', $.proxy(this._onCompactLogButtonClick, this)
+            );
+
+            $(this.options.viewLayoutButtonSelector).bind(
+                'click', $.proxy(this._onViewLayoutButtonClick, this)
+            );
+        },
+        _initEventObservers: function() {
+            this._history.element.bind(
+                this._history.getEventName('add'),
+                $.proxy(this._onHistoryAddItem, this)
+            );
+        },
+        _onHistoryAddItem: function(e, change) {
+            this.addItem(change);
+        },
+        _onCompactLogButtonClick: function(e) {
+            try {
+                if (this._history.getItems().length == 0) {
+                    /** @todo temporary report */
+                    alert(Translator.translate('No changes found.'));
+                    return false;
+                }
+                var data = this._preparePostItems(this._history.getItems());
+                var items = this._post(this.options.compactLogUrl, data);
+                this._compactLogToHistory(items);
+            } catch (e) {
+                alert(e.message);
+            } finally {
+                return false;
+            }
+        },
+        _onViewLayoutButtonClick: function(e) {
+            try {
+                if (this._history.getItems().length == 0) {
+                    /** @todo temporary report */
+                    alert(Translator.translate('No changes found.'));
+                    return false;
+                }
+                var data = this._preparePostItems(this._history.getItems());
+                var compactXml = this._post(this.options.viewLayoutUrl, data);
+                alert(compactXml);
+            } catch (e) {
+                alert(e.message);
+            } finally {
+                return false;
+            }
+
+        },
+        setHistory: function(history) {
+            this._history = history;
+            this._initEventObservers();
+        },
+        setBaseUrl: function(baseUrl) {
+            this.option('baseUrl', baseUrl);
+        },
+        setItems: function(items) {
+            //this.deleteItems();
+            $.each(items, function(index, item){this.addItem(item)});
+        },
+        deleteItems: function() {
+            this.element.find('ul').empty();
+        },
+        addItem: function(change) {
+            this.element.find('ul').append('<li>' + change.getTitle() + '</li>');
+        },
+        _compactLogToHistory: function(items) {
+            this._history.deleteItems();
+            this.deleteItems();
+            var self = this;
+            $.each(items[0], function(index, item) {
+                var change = $.fn.changeFactory.getInstance('layout');
+                change.setActionData(item);
+                self._history.addItem(change);
+            });
+        },
+        _preparePostItems: function(items) {
+            var postData = {};
+            $.each(items, function(index, item){
+                postData[index] = item.getPostData();
+            });
+            return postData;
+        },
+        _post: function(action, data) {
+            var url = action;
+            var postResult;
+            $.ajax({
+                url: url,
+                type: 'POST',
+                dataType: 'JSON',
+                data: data,
+                async: false,
+                success: function(data) {
+                    if (data.error) {
+                        /** @todo add error validator */
+                        throw Error(Translator.translate('Some problem with save action'));
+                        return;
+                    }
+                    postResult = data.success;
+                },
+                error: function(data) {
+                    throw Error(Translator.translate('Some problem with save action'));
+                }
+            });
+            return postResult;
+        }
+    });
+
+    /**
+     * Widget page
+     */
+    $.widget('vde.vde_page', {
+        options: {
+            containerSelector: '.vde_element_wrapper.vde_container',
+            panelSelector: '#vde_toolbar',
+            highlightElementSelector: '.vde_element_wrapper',
+            highlightElementTitleSelector: '.vde_element_title',
+            highlightCheckboxSelector: '#vde_highlighting',
+            cookieHighlightingName: 'vde_highlighting',
+            historyToolbarSelector: '.vde_history_toolbar',
+            baseUrl: null,
+            compactLogUrl: null,
+            viewLayoutUrl: null
+        },
+        _create: function () {
+            this._initContainers();
+            this._initPanel();
+        },
+        _initContainers: function () {
+            $(this.options.containerSelector)
+                .vde_container().disableSelection();
+        },
+        _initPanel: function () {
+            $(this.options.panelSelector).vde_panel();
+        }
+    });
+
+    /**
+     * Widget page highlight functionality
+     */
+    var pageBasePrototype = $.vde.vde_page.prototype;
+    $.widget('vde.vde_page', $.extend({}, pageBasePrototype, {
+        _create: function () {
+            pageBasePrototype._create.apply(this, arguments);
+            if (this.options.highlightElementSelector) {
+                this._initHighlighting();
+                this._bind();
+            }
+        },
+        _bind: function () {
+            var self = this;
+            this.element
+                .on('checked.vde_checkbox', function () {
+                    self._highlight();
+                })
+                .on('unchecked.vde_checkbox', function () {
+                    self._unhighlight();
+                });
+        },
+        _initHighlighting: function () {
+            if (this.options.highlightCheckboxSelector) {
+                $(this.options.highlightCheckboxSelector)
+                    .vde_checkbox();
+            }
+            this.highlightBlocks = {};
+            if (Mage.Cookies.get(this.options.cookieHighlightingName) == 'off') {
+                this._processMarkers();
+            }
+
+        },
+        _highlight: function () {
+            Mage.Cookies.clear(this.options.cookieHighlightingName);
+            var self = this;
+            $(this.options.highlightElementSelector).each(function () {
+                $(this)
+                    .append(self._getChildren($(this).attr('id')))
+                    .show()
+                    .children(self.options.highlightElementTitleSelector).slideDown('fast');
+            });
+            this.highlightBlocks = {};
+        },
+        _unhighlight: function () {
+            Mage.Cookies.set(this.options.cookieHighlightingName, 'off');
+            var self = this;
+            $(this.options.highlightElementSelector).each(function () {
+                var elem = $(this);
+                elem.children(self.options.highlightElementTitleSelector).slideUp('fast', function () {
+                    var children = elem.contents(':not(' + self.options.highlightElementTitleSelector + ')');
+                    var parentId = elem.attr('id');
+                    children.each(function () {
+                        self._storeChild(parentId, this);
+                    });
+                    elem.after(children).hide();
+                });
+            });
+        },
+        _processMarkers: function () {
+            var self = this,
+                parentsIdsStack = [],
+                currentParentId;
+            $('*').contents().each(function () {
+                if (this.nodeType == Node.COMMENT_NODE) {
+                    if (this.data.substr(0, 9) == 'start_vde') {
+                        currentParentId = this.data.substr(6, this.data.length);
+                        parentsIdsStack.push(currentParentId);
+                        this.parentNode.removeChild(this);
+                    } else if (this.data.substr(0, 7) == 'end_vde') {
+                        if (this.data.substr(4, this.data.length) !== currentParentId) {
+                            throw "Could not find closing element for opened '" + currentParentId + "' element";
+                        }
+                        parentsIdsStack.pop();
+                        currentParentId = parentsIdsStack[parentsIdsStack.length - 1];
+                        this.parentNode.removeChild(this);
+                    }
+                } else if (currentParentId) {
+                    self._storeChild(currentParentId, this);
+                }
+            })
+        },
+        _storeChild: function(parentId, child) {
+            if (!this.highlightBlocks[parentId]) {
+                this.highlightBlocks[parentId] = [];
+            }
+            this.highlightBlocks[parentId].push(child);
+        },
+        _getChildren: function(parentId) {
+            return (!this.highlightBlocks[parentId]) ? [] : this.highlightBlocks[parentId];
+        }
+    }));
+
+    /**
+     * Widget page history init
+     */
+    var pagePrototype = $.vde.vde_page.prototype;
+    $.widget( "vde.vde_page", $.extend({}, pagePrototype, {
+        _create: function() {
+            pagePrototype._create.apply( this, arguments );
+            var history = this._initHistory();
+            this._initHistoryToolbar(history);
+            this._initRemoveOperation(history);
+            this._setHistoryForContainers(history);
+        },
+        _initHistory: function() {
+            //@TODO can we make this not a widget but global object?
+            return $( window ).vde_history().data('vde_history');
+        },
+        _initHistoryToolbar: function(history) {
+            if (!history) {
+                throw new Error('History object is not set');
+            }
+            if ($( this.options.historyToolbarSelector )) {
+                var toolbar = $( this.options.historyToolbarSelector).vde_historyToolbar().data('vde_historyToolbar');
+                if (toolbar) {
+                    toolbar.setHistory(history);
+                    toolbar.option('baseUrl', this.options.baseUrl);
+                    toolbar.option('compactLogUrl', this.options.compactLogUrl);
+                    toolbar.option('viewLayoutUrl', this.options.viewLayoutUrl);
+                }
+            }
+        },
+        _initRemoveOperation : function(history) {
+            $( this.options.highlightElementSelector ).each(function(i, element) {
+                var widget = $(element).vde_removable().data('vde_removable');
+                widget.setHistory(history);
+            });
+        },
+        _setHistoryForContainers: function(history) {
+            $( this.options.containerSelector ).each(function(i, element) {
+                var widget = $(element).data('vde_container');
+                widget.setHistory(history);
+            });
+        },
+        destroy: function() {
+            //DOM structure can be missed when test executed
+            var panelContainer = $(this.options.panelSelector);
+            if (panelContainer.size()) {
+                panelContainer.vde_panel('destroy');
+            }
+            var toolbarContainer = $(this.options.historyToolbarSelector);
+            if (toolbarContainer.length) {
+                toolbarContainer.vde_historyToolbar('destroy');
+            }
+            $(window).vde_history('destroy');
+            $(this.options.highlightElementSelector).vde_removable('destroy');
+            $(this.options.containerSelector).vde_container('destroy');
+
+            pagePrototype.destroy.call(this);
+        }
+    }));
+
+    /**
+     * Widget removable
+     */
+    $.widget( "vde.vde_removable", {
+        options: {
+            relativeButtonSelector: '.vde_element_remove',
+            containerSelector: '.vde_container'
+        },
+        history: null,
+        _create: function() {
+            this._initButtons();
+        },
+        _initButtons: function() {
+            var self = this;
+            // Remember that container can have block inside with their own remove buttons
+            this.element.children(this.options.relativeButtonSelector)
+                .css('display', 'block')
+                .find('a').bind('click', $.proxy(self._onRemoveButtonClick, self));
+        },
+        _onRemoveButtonClick: function(e) {
+            var change = $.fn.changeFactory.getInstance('layout');
+            var block = this.element;
+            change.setData({
+                action: 'remove',
+                block: this.element.data('name'),
+                container: this.element.parent().closest(this.options.containerSelector)
+            });
+
+            // This is the dependency of Removable on History
+            this.history.addItem(change);
+            this.remove();
+        },
+        setHistory: function(history) {
+            this.history = history;
+        },
+        remove: function () {
+            this.element.remove();
+        }
+    });
+
+})( jQuery );
diff --git a/app/code/core/Mage/DesignEditor/view/frontend/layout.xml b/app/code/core/Mage/DesignEditor/view/frontend/layout.xml
index 38448fbd8b7..8e144419d70 100644
--- a/app/code/core/Mage/DesignEditor/view/frontend/layout.xml
+++ b/app/code/core/Mage/DesignEditor/view/frontend/layout.xml
@@ -34,6 +34,7 @@
             <action method="addJs"><file>jquery/jquery-ui-1.8.18.custom.min.js</file></action>
             <action method="addJs"><file>Mage_DesignEditor::js/base.js</file></action>
             <action method="addJs"><file>Mage_DesignEditor::js/design_editor.js</file></action>
+            <action method="addJs"><file>Mage_DesignEditor::js/change/layout.js</file></action>
             <action method="addJs"><file>jquery/jstree/jquery.jstree.js</file></action>
             <action method="addJs"><file>jquery/slimScroll/slimScroll.min.js</file></action>
             <action method="addJs"><file>prototype/prototype.js</file></action>
@@ -48,7 +49,8 @@
                 <block type="Mage_DesignEditor_Block_Toolbar_HandlesHierarchy" name="design_editor_toolbar_handles_hierarchy" template="toolbar/handles_hierarchy.phtml"/>
                 <block type="Mage_DesignEditor_Block_Toolbar_Skin" name="design_editor_toolbar_skin" template="toolbar/skin.phtml"/>
                 <block type="Mage_DesignEditor_Block_Template" name="design_editor_toolbar_highlighting" template="toolbar/highlighting.phtml"/>
-                <block type="Mage_DesignEditor_Block_Toolbar_Exit" name="design_editor_toolbar_exit" template="toolbar/exit.phtml"/>
+                <block type="Mage_DesignEditor_Block_Toolbar_Buttons" name="design_editor_toolbar_buttons" template="toolbar/buttons.phtml"/>
+                <block type="Mage_DesignEditor_Block_Toolbar_History" name="design_editor_toolbar_history" template="toolbar/history.phtml"/>
             </block>
         </block>
     </design_editor_toolbar>
diff --git a/app/code/core/Mage/DesignEditor/view/frontend/toolbar.phtml b/app/code/core/Mage/DesignEditor/view/frontend/toolbar.phtml
index ccdfd5089cf..d8db03e0ffd 100644
--- a/app/code/core/Mage/DesignEditor/view/frontend/toolbar.phtml
+++ b/app/code/core/Mage/DesignEditor/view/frontend/toolbar.phtml
@@ -1,5 +1,5 @@
-<?php
-/**
+<?php
+/**
  * Magento
  *
  * NOTICE OF LICENSE
@@ -16,25 +16,27 @@
  *
  * Do not edit or add to this file if you wish to upgrade Magento to newer
  * versions in the future. If you wish to customize Magento for your
- * needs please refer to http://www.magentocommerce.com for more information.
- *
- * @category    design
- * @package     Mage_DesignEditor
- * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
- * @license     http://opensource.org/licenses/afl-3.0.php  Academic Free License (AFL 3.0)
- */
-?>
-<?php /** @var $this Mage_DesignEditor_Block_Toolbar */ ?>
-<div id="vde_toolbar">
-    <?php $messages = $this->getMessages(); ?>
-    <?php foreach ($messages as $message): ?>
-        <p class="item-msg <?php echo $message->getType() ?>"><?php echo $this->escapeHtml($message->getCode()) ?></p>
-    <?php endforeach; ?>
-    <?php echo $this->getChildHtml(); ?>
-</div>
-
-<script type="text/javascript">
-(function ($) {
-    $( document ).ready( function( ){ $( window ).vde_page(<?php echo $this->getOptionsJson(); ?>); } );
-})(jQuery);
-</script>
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @category    design
+ * @package     Mage_DesignEditor
+ * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/afl-3.0.php  Academic Free License (AFL 3.0)
+ */
+?>
+<?php /** @var $this Mage_DesignEditor_Block_Toolbar */ ?>
+<div id="vde_toolbar">
+    <?php $messages = $this->getMessages(); ?>
+    <?php foreach ($messages as $message): ?>
+        <p class="item-msg <?php echo $message->getType() ?>"><?php echo $this->escapeHtml($message->getCode()) ?></p>
+    <?php endforeach; ?>
+    <?php echo $this->getChildHtml(); ?>
+</div>
+
+<script type="text/javascript">
+(function ($) {
+    $( document ).ready(function( ){
+        $( window ).vde_page(<?php echo $this->getOptionsJson(); ?>);
+    });
+})(jQuery);
+</script>
diff --git a/app/code/core/Mage/DesignEditor/view/frontend/toolbar/buttons.phtml b/app/code/core/Mage/DesignEditor/view/frontend/toolbar/buttons.phtml
new file mode 100644
index 00000000000..6a86e447a14
--- /dev/null
+++ b/app/code/core/Mage/DesignEditor/view/frontend/toolbar/buttons.phtml
@@ -0,0 +1,39 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Academic Free License (AFL 3.0)
+ * that is bundled with this package in the file LICENSE_AFL.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/afl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @category    design
+ * @package     Mage_DesignEditor
+ * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/afl-3.0.php  Academic Free License (AFL 3.0)
+ */
+?>
+<?php /** @var $this Mage_DesignEditor_Block_Toolbar_Buttons */ ?>
+<div id="vde_toolbar_buttons">
+    <a href="<?php echo $this->getViewLayoutUrl(); ?>" title="<?php echo $this->__('View Layout'); ?>" class="vde_button view-layout">
+        <?php echo $this->__('View Layout'); ?>
+    </a>
+    <a href="<?php echo $this->getCompactLogUrl(); ?>" title="<?php echo $this->__('Compact Log'); ?>" class="vde_button compact-log">
+        <?php echo $this->__('Compact Log'); ?>
+    </a>
+    <a href="<?php echo $this->getExitUrl(); ?>" title="<?php echo $this->__('Quit'); ?>" class="vde_button">
+        <?php echo $this->__('Quit'); ?>
+    </a>
+    <div style="clear:both;"></div>
+</div>
diff --git a/app/code/core/Mage/DesignEditor/view/frontend/toolbar/exit.phtml b/app/code/core/Mage/DesignEditor/view/frontend/toolbar/history.phtml
similarity index 83%
rename from app/code/core/Mage/DesignEditor/view/frontend/toolbar/exit.phtml
rename to app/code/core/Mage/DesignEditor/view/frontend/toolbar/history.phtml
index eb455a55fe9..b1af7b00b1f 100644
--- a/app/code/core/Mage/DesignEditor/view/frontend/toolbar/exit.phtml
+++ b/app/code/core/Mage/DesignEditor/view/frontend/toolbar/history.phtml
@@ -24,8 +24,8 @@
  * @license     http://opensource.org/licenses/afl-3.0.php  Academic Free License (AFL 3.0)
  */
 ?>
-<div id="vde_toolbar_buttons">
-    <a href="<?php echo $this->getExitUrl(); ?>" title="<?php echo $this->__('Quit'); ?>" class="vde_button">
-        <?php echo $this->__('Quit'); ?>
-    </a>
+<?php /** @var $this Mage_DesignEditor_Block_Toolbar_History */ ?>
+<div class="vde_history_toolbar">
+    <h4><?php echo $this->getTitle(); ?></h4>
+    <ul></ul>
 </div>
diff --git a/app/code/core/Mage/DesignEditor/view/frontend/wrapper/remove.phtml b/app/code/core/Mage/DesignEditor/view/frontend/wrapper/remove.phtml
new file mode 100644
index 00000000000..8518dd6b83f
--- /dev/null
+++ b/app/code/core/Mage/DesignEditor/view/frontend/wrapper/remove.phtml
@@ -0,0 +1,32 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Academic Free License (AFL 3.0)
+ * that is bundled with this package in the file LICENSE_AFL.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/afl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @category    design
+ * @package     Mage_DesignEditor
+ * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/afl-3.0.php  Academic Free License (AFL 3.0)
+ */
+?>
+<?php /** @var $this Mage_DesignEditor_Block_Wrapper_Remove */ ?>
+<div class="vde_element_title vde_element_remove" id="<?php echo $this->getElementId(); ?>">
+    <a href="#remove">
+        <img src="<?php echo $this->getSkinUrl('images/btn_remove.gif') ?>" alt="<?php echo $this->__('Remove')?>" />
+    </a>
+</div>
diff --git a/app/code/core/Mage/DesignEditor/view/frontend/wrapping.phtml b/app/code/core/Mage/DesignEditor/view/frontend/wrapping.phtml
index 6e78f9209f5..9101295b687 100644
--- a/app/code/core/Mage/DesignEditor/view/frontend/wrapping.phtml
+++ b/app/code/core/Mage/DesignEditor/view/frontend/wrapping.phtml
@@ -30,12 +30,15 @@ $elementId = $this->getElementId();
 $elementHtml = $this->getElementHtml();
 $hideWrapping = $this->isHighlightingDisabled();
 $cssClass = 'vde_element_wrapper'
-    . ($this->getIsDraggable() ? ' vde_draggable' : '')
+    . ($this->getIsManipulationAllowed() ? ' vde_draggable vde_removable' : '')
     . ($this->getIsContainer() ? ' vde_container' : '')
     . ($hideWrapping ? ' vde_wrapper_hidden' : '');
 ?>
-<div id="<?php echo $elementId; ?>" class="<?php echo $cssClass; ?>">
+<div id="<?php echo $elementId; ?>" class="<?php echo $cssClass; ?>" data-name="<?php echo $this->getElementName() ?>">
     <div class="vde_element_title"><?php echo $this->getElementTitle() ?></div>
+    <?php if ($this->getIsManipulationAllowed()): ?>
+        <?php echo $this->getRemoveButton($elementId) ?>
+    <?php endif; ?>
     <?php if (!$hideWrapping) : ?>
         <?php echo $elementHtml; ?>
     <?php endif; ?>
@@ -44,4 +47,4 @@ $cssClass = 'vde_element_wrapper'
     <!--start_<?php echo $elementId; ?>-->
     <?php echo $elementHtml; ?>
     <!--end_<?php echo $elementId; ?>-->
-<?php endif; ?>
+<?php endif;?>
diff --git a/app/code/core/Mage/ImportExport/Model/Import/Entity/Product/Type/Abstract.php b/app/code/core/Mage/ImportExport/Model/Import/Entity/Product/Type/Abstract.php
index 6325eff36ce..e0266611785 100644
--- a/app/code/core/Mage/ImportExport/Model/Import/Entity/Product/Type/Abstract.php
+++ b/app/code/core/Mage/ImportExport/Model/Import/Entity/Product/Type/Abstract.php
@@ -312,21 +312,6 @@ abstract class Mage_ImportExport_Model_Import_Entity_Product_Type_Abstract
         return $resultAttrs;
     }
 
-    /**
-     * Prepare attributes values for save: remove non-existent, remove empty values, remove static.
-     *
-     * @deprecated
-     * @see Mage_ImportExport_Model_Import_Entity_Product_Type_Abstract::prepareAttributesWithDefaultValueForSave()
-     *
-     * @param array $rowData
-     *
-     * @return array
-     */
-    public function prepareAttributesForSave(array $rowData)
-    {
-        return $this->prepareAttributesWithDefaultValueForSave($rowData);
-    }
-
     /**
      * Save product type specific data.
      *
diff --git a/app/code/core/Mage/Page/etc/config.xml b/app/code/core/Mage/Page/etc/config.xml
index 5f029138dcd..6c80568db16 100644
--- a/app/code/core/Mage/Page/etc/config.xml
+++ b/app/code/core/Mage/Page/etc/config.xml
@@ -127,7 +127,6 @@ Disallow: /*?
 Disallow: /*.js$
 Disallow: /*.css$
 Disallow: /checkout/
-Disallow: /tag/
 Disallow: /app/
 Disallow: /downloader/
 Disallow: /js/
diff --git a/app/code/core/Mage/Reports/etc/adminhtml/acl.xml b/app/code/core/Mage/Reports/etc/adminhtml/acl.xml
index 96def8beda5..a13f766ce32 100644
--- a/app/code/core/Mage/Reports/etc/adminhtml/acl.xml
+++ b/app/code/core/Mage/Reports/etc/adminhtml/acl.xml
@@ -58,11 +58,6 @@
                         <resource id="Mage_Reports::review_customer" title="Customers Reviews" />
                         <resource id="Mage_Reports::review_product" title="Products Reviews" />
                     </resource>
-                    <resource id="Mage_Reports::tags" module="Mage_Tag" title="Tags">
-                        <resource id="Mage_Reports::tags_customer" module="Mage_Tag" title="Customers" />
-                        <resource id="Mage_Reports::popular" module="Mage_Tag" title="Popular" />
-                        <resource id="Mage_Reports::tags_product" module="Mage_Tag" title="Products" />
-                    </resource>
                     <resource id="Mage_Reports::report_search" title="Search Terms" />
                     <resource id="Mage_Reports::statistics" title="Statistics" />
                 </resource>
diff --git a/app/code/core/Mage/Rss/controllers/CatalogController.php b/app/code/core/Mage/Rss/controllers/CatalogController.php
index 2990326bf5c..36963848d2c 100644
--- a/app/code/core/Mage/Rss/controllers/CatalogController.php
+++ b/app/code/core/Mage/Rss/controllers/CatalogController.php
@@ -69,23 +69,6 @@ class Mage_Rss_CatalogController extends Mage_Core_Controller_Front_Action
         $this->_genericAction('salesrule');
     }
 
-    public function tagAction()
-    {
-        if (!$this->_isEnabled('tag')) {
-            $this->_forward('nofeed', 'index', 'rss');
-            return;
-        }
-        $tagName = urldecode($this->getRequest()->getParam('tagName'));
-        $tagModel = Mage::getModel('Mage_Tag_Model_Tag');
-        $tagModel->loadByName($tagName);
-        if ($tagModel->getId() && $tagModel->getStatus() == $tagModel->getApprovedStatus()) {
-            Mage::register('tag_model', $tagModel);
-            $this->_render();
-            return;
-        }
-        $this->_forward('nofeed', 'index', 'rss');
-    }
-
     public function notifystockAction()
     {
         $this->_render();
diff --git a/app/code/core/Mage/Rss/etc/system.xml b/app/code/core/Mage/Rss/etc/system.xml
index 3ef8b8da3c8..1efe450b636 100644
--- a/app/code/core/Mage/Rss/etc/system.xml
+++ b/app/code/core/Mage/Rss/etc/system.xml
@@ -113,15 +113,6 @@
                             <show_in_website>1</show_in_website>
                             <show_in_store>1</show_in_store>
                         </salesrule>
-                        <tag translate="label">
-                            <label>Tags Products</label>
-                            <frontend_type>select</frontend_type>
-                            <source_model>Mage_Adminhtml_Model_System_Config_Source_Enabledisable</source_model>
-                            <sort_order>13</sort_order>
-                            <show_in_default>1</show_in_default>
-                            <show_in_website>1</show_in_website>
-                            <show_in_store>1</show_in_store>
-                        </tag>
                         <category translate="label">
                             <label>Top Level Category</label>
                             <frontend_type>select</frontend_type>
diff --git a/app/code/core/Mage/Rss/view/frontend/layout.xml b/app/code/core/Mage/Rss/view/frontend/layout.xml
index a319772b2c7..3922fda4cf7 100644
--- a/app/code/core/Mage/Rss/view/frontend/layout.xml
+++ b/app/code/core/Mage/Rss/view/frontend/layout.xml
@@ -68,12 +68,6 @@ Catalog layout
         <block type="Mage_Rss_Block_Catalog_Salesrule" output="1" name="rss.catalog.salesrule" />
     </rss_catalog_salesrule>
 
-    <rss_catalog_tag>
-        <block type="Mage_Rss_Block_Catalog_Tag" output="1" name="rss.catalog.tag">
-            <action method="addPriceBlockType"><type>msrp_rss</type><block>Mage_Catalog_Block_Product_Price</block><template>product/price_msrp_rss.phtml</template></action>
-        </block>
-    </rss_catalog_tag>
-
     <rss_catalog_category>
         <block type="Mage_Rss_Block_Catalog_Category" output="1" name="rss.catalog.category">
             <action method="addPriceBlockType"><type>msrp_rss</type><block>Mage_Catalog_Block_Product_Price</block><template>product/price_msrp_rss.phtml</template></action>
diff --git a/app/code/core/Mage/Sales/view/email/order_new.html b/app/code/core/Mage/Sales/view/email/order_new.html
index d936a507f34..bf432d6b6ec 100644
--- a/app/code/core/Mage/Sales/view/email/order_new.html
+++ b/app/code/core/Mage/Sales/view/email/order_new.html
@@ -40,6 +40,7 @@ body,td { color:#2f2f2f; font:11px/1.35em Verdana, Arial, Helvetica, sans-serif;
                         If you have any questions about your order please contact us at <a href="mailto:{{config path='trans_email/ident_support/email'}}" style="color:#1E7EC8;">{{config path='trans_email/ident_support/email'}}</a> or call us at <span class="nobr">{{config path='general/store_information/phone'}}</span> Monday - Friday, 8am - 5pm PST.
                     </p>
                     <p style="font-size:12px; line-height:16px; margin:0;">Your order confirmation is below. Thank you again for your business.</p>
+                </td>
             </tr>
             <tr>
                 <td>
diff --git a/app/code/core/Mage/Adminhtml/Block/Tag/Assigned/Grid.php b/app/code/core/Mage/Tag/Block/Adminhtml/Assigned/Grid.php
similarity index 88%
rename from app/code/core/Mage/Adminhtml/Block/Tag/Assigned/Grid.php
rename to app/code/core/Mage/Tag/Block/Adminhtml/Assigned/Grid.php
index 593a9ba853d..31147c9950c 100644
--- a/app/code/core/Mage/Adminhtml/Block/Tag/Assigned/Grid.php
+++ b/app/code/core/Mage/Tag/Block/Adminhtml/Assigned/Grid.php
@@ -19,7 +19,7 @@
  * needs please refer to http://www.magentocommerce.com for more information.
  *
  * @category    Mage
- * @package     Mage_Adminhtml
+ * @package     Mage_Tag
  * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
  * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
  */
@@ -28,10 +28,10 @@
  * Adminhtml assigned products grid block
  *
  * @category   Mage
- * @package    Mage_Adminhtml
+ * @package    Mage_Tag
  * @author     Magento Core Team <core@magentocommerce.com>
  */
-class Mage_Adminhtml_Block_Tag_Assigned_Grid extends Mage_Adminhtml_Block_Widget_Grid
+class Mage_Tag_Block_Adminhtml_Assigned_Grid extends Mage_Adminhtml_Block_Widget_Grid
 {
     protected $_currentTagModel;
 
@@ -77,7 +77,7 @@ class Mage_Adminhtml_Block_Tag_Assigned_Grid extends Mage_Adminhtml_Block_Widget
      * Add filter to grid columns
      *
      * @param mixed $column
-     * @return Mage_Adminhtml_Block_Tag_Assigned_Grid
+     * @return Mage_Tag_Block_Adminhtml_Assigned_Grid
      */
     protected function _addColumnFilterToCollection($column)
     {
@@ -103,7 +103,7 @@ class Mage_Adminhtml_Block_Tag_Assigned_Grid extends Mage_Adminhtml_Block_Widget
     /**
      * Retrieve Products Collection
      *
-     * @return Mage_Adminhtml_Block_Tag_Assigned_Grid
+     * @return Mage_Tag_Block_Adminhtml_Assigned_Grid
      */
     protected function _prepareCollection()
     {
@@ -158,7 +158,7 @@ class Mage_Adminhtml_Block_Tag_Assigned_Grid extends Mage_Adminhtml_Block_Widget
 
         $this->addColumn('entity_id',
             array(
-                'header'=> Mage::helper('Mage_Catalog_Helper_Data')->__('ID'),
+                'header'=> Mage::helper('Mage_Tag_Helper_Data')->__('ID'),
                 'width' => 50,
                 'sortable'  => true,
                 'type'  => 'number',
@@ -166,7 +166,7 @@ class Mage_Adminhtml_Block_Tag_Assigned_Grid extends Mage_Adminhtml_Block_Widget
         ));
         $this->addColumn('name',
             array(
-                'header'=> Mage::helper('Mage_Catalog_Helper_Data')->__('Name'),
+                'header'=> Mage::helper('Mage_Tag_Helper_Data')->__('Name'),
                 'index' => 'name',
         ));
 
@@ -174,14 +174,14 @@ class Mage_Adminhtml_Block_Tag_Assigned_Grid extends Mage_Adminhtml_Block_Widget
         if ($store->getId()) {
             $this->addColumn('custom_name',
                 array(
-                    'header'=> Mage::helper('Mage_Catalog_Helper_Data')->__('Name in %s', $store->getName()),
+                    'header'=> Mage::helper('Mage_Tag_Helper_Data')->__('Name in %s', $store->getName()),
                     'index' => 'custom_name',
             ));
         }
 
         $this->addColumn('type',
             array(
-                'header'    => Mage::helper('Mage_Catalog_Helper_Data')->__('Type'),
+                'header'    => Mage::helper('Mage_Tag_Helper_Data')->__('Type'),
                 'width'     => 100,
                 'index'     => 'type_id',
                 'type'      => 'options',
@@ -195,7 +195,7 @@ class Mage_Adminhtml_Block_Tag_Assigned_Grid extends Mage_Adminhtml_Block_Widget
 
         $this->addColumn('set_name',
             array(
-                'header'    => Mage::helper('Mage_Catalog_Helper_Data')->__('Attrib. Set Name'),
+                'header'    => Mage::helper('Mage_Tag_Helper_Data')->__('Attrib. Set Name'),
                 'width'     => 100,
                 'index'     => 'attribute_set_id',
                 'type'      => 'options',
@@ -204,7 +204,7 @@ class Mage_Adminhtml_Block_Tag_Assigned_Grid extends Mage_Adminhtml_Block_Widget
 
         $this->addColumn('sku',
             array(
-                'header'=> Mage::helper('Mage_Catalog_Helper_Data')->__('SKU'),
+                'header'=> Mage::helper('Mage_Tag_Helper_Data')->__('SKU'),
                 'width' => 80,
                 'index' => 'sku',
         ));
@@ -212,7 +212,7 @@ class Mage_Adminhtml_Block_Tag_Assigned_Grid extends Mage_Adminhtml_Block_Widget
         $store = $this->_getStore();
         $this->addColumn('price',
             array(
-                'header'        => Mage::helper('Mage_Catalog_Helper_Data')->__('Price'),
+                'header'        => Mage::helper('Mage_Tag_Helper_Data')->__('Price'),
                 'type'          => 'price',
                 'currency_code' => $store->getBaseCurrency()->getCode(),
                 'index'         => 'price',
@@ -220,7 +220,7 @@ class Mage_Adminhtml_Block_Tag_Assigned_Grid extends Mage_Adminhtml_Block_Widget
 
         $this->addColumn('visibility',
             array(
-                'header'    => Mage::helper('Mage_Catalog_Helper_Data')->__('Visibility'),
+                'header'    => Mage::helper('Mage_Tag_Helper_Data')->__('Visibility'),
                 'width'     => 100,
                 'index'     => 'visibility',
                 'type'      => 'options',
@@ -229,7 +229,7 @@ class Mage_Adminhtml_Block_Tag_Assigned_Grid extends Mage_Adminhtml_Block_Widget
 
         $this->addColumn('status',
             array(
-                'header'    => Mage::helper('Mage_Catalog_Helper_Data')->__('Status'),
+                'header'    => Mage::helper('Mage_Tag_Helper_Data')->__('Status'),
                 'width'     => 70,
                 'index'     => 'status',
                 'type'      => 'options',
diff --git a/app/code/core/Mage/Tag/Block/Adminhtml/Catalog/Product/Edit/Tab/Tag.php b/app/code/core/Mage/Tag/Block/Adminhtml/Catalog/Product/Edit/Tab/Tag.php
new file mode 100644
index 00000000000..d3d1465854e
--- /dev/null
+++ b/app/code/core/Mage/Tag/Block/Adminhtml/Catalog/Product/Edit/Tab/Tag.php
@@ -0,0 +1,164 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @category   Mage
+ * @package    Mage_Tag
+ * @copyright  Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
+ * @license    http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+/**
+ * Products tags tab
+ *
+ * @category   Mage
+ * @package    Mage_Tag
+ * @author     Magento Core Team <core@magentocommerce.com>
+ *
+ * @method     Mage_Tag_Block_Adminhtml_Catalog_Product_Edit_Tab_Tag setTitle() setTitle(string $title)
+ * @method     array getTitle() getTitle()
+ */
+
+class Mage_Tag_Block_Adminhtml_Catalog_Product_Edit_Tab_Tag
+    extends Mage_Backend_Block_Template
+    implements Mage_Backend_Block_Widget_Tab_Interface
+{
+    /**
+     * Id of current tab
+     */
+    const TAB_ID = 'tags';
+
+    /**
+     * Array of data helpers
+     *
+     * @var array
+     */
+    protected $_helpers;
+
+    /**
+     * Authentication session
+     *
+     * @var Mage_Core_Model_Authorization
+     */
+    protected $_authSession;
+
+    /**
+     * Set identifier and title
+     *
+     * @param array $data
+     */
+    public function __construct(array $data = array())
+    {
+        parent::__construct($data);
+
+        if (isset($data['helpers'])) {
+            $this->_helpers = $data['helpers'];
+        }
+
+        if (isset($data['auth_session'])) {
+            $this->_authSession = $data['auth_session'];
+        } else {
+            $this->_authSession = Mage::getSingleton('Mage_Core_Model_Authorization');
+        }
+
+        $this->setId(self::TAB_ID);
+        $this->setTitle($this->_helper('Mage_Tag_Helper_Data')->__('Product Tags'));
+    }
+
+    /**
+     * Helper getter
+     *
+     * @param string $helperName
+     * @return Mage_Core_Helper_Abstract
+     */
+    protected function _helper($helperName)
+    {
+        return isset($this->_helpers[$helperName]) ? $this->_helpers[$helperName] : Mage::helper($helperName);
+    }
+
+    /**
+     * Tab label getter
+     *
+     * @return string
+     */
+    public function getTabLabel()
+    {
+        return $this->getTitle();
+    }
+
+    /**
+     * Tab title getter
+     *
+     * @return string
+     */
+    public function getTabTitle()
+    {
+        return $this->getTitle();
+    }
+
+    /**
+     * Check whether tab can be showed
+     *
+     * @return bool
+     */
+    public function canShowTab()
+    {
+        return $this->_authSession->isAllowed('Mage_Tag::tag');
+    }
+
+    /**
+     * Check whether tab should be hidden
+     *
+     * @return bool
+     */
+    public function isHidden()
+    {
+        return false;
+    }
+
+    /**
+     * Tab class getter
+     *
+     * @return string
+     */
+    public function getTabClass()
+    {
+        return 'ajax';
+    }
+
+    /**
+     * Tab URL getter
+     *
+     * @return string
+     */
+    public function getTabUrl()
+    {
+        return $this->getUrl('*/*/tagGrid', array('_current' => true));
+    }
+
+    /**
+     * Retrieve id of tab after which current tab will be rendered
+     *
+     * @return string
+     */
+    public function getAfter()
+    {
+        return 'reviews';
+    }
+}
diff --git a/app/code/core/Mage/Tag/Block/Adminhtml/Catalog/Product/Edit/Tab/Tag/Customer.php b/app/code/core/Mage/Tag/Block/Adminhtml/Catalog/Product/Edit/Tab/Tag/Customer.php
new file mode 100644
index 00000000000..5eb74fe04ed
--- /dev/null
+++ b/app/code/core/Mage/Tag/Block/Adminhtml/Catalog/Product/Edit/Tab/Tag/Customer.php
@@ -0,0 +1,164 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @category   Mage
+ * @package    Mage_Tag
+ * @copyright  Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
+ * @license    http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+/**
+ * Customer tagged products tab
+ *
+ * @category   Mage
+ * @package    Mage_Tag
+ * @author     Magento Core Team <core@magentocommerce.com>
+ *
+ * @method     Mage_Tag_Block_Adminhtml_Catalog_Product_Edit_Tab_Tag_Customer setTitle() setTitle(string $title)
+ * @method     array getTitle() getTitle()
+ */
+
+class Mage_Tag_Block_Adminhtml_Catalog_Product_Edit_Tab_Tag_Customer
+    extends Mage_Backend_Block_Template
+    implements Mage_Backend_Block_Widget_Tab_Interface
+{
+    /**
+     * Id of current tab
+     */
+    const TAB_ID = 'customers_tags';
+
+    /**
+     * Array of data helpers
+     *
+     * @var array
+     */
+    protected $_helpers;
+
+    /**
+     * Authentication session
+     *
+     * @var Mage_Core_Model_Authorization
+     */
+    protected $_authSession;
+
+    /**
+     * Set identifier and title
+     *
+     * @param array $data
+     */
+    public function __construct(array $data = array())
+    {
+        parent::__construct($data);
+
+        if (isset($data['helpers'])) {
+            $this->_helpers = $data['helpers'];
+        }
+
+        if (isset($data['auth_session'])) {
+            $this->_authSession = $data['auth_session'];
+        } else {
+            $this->_authSession = Mage::getSingleton('Mage_Core_Model_Authorization');
+        }
+
+        $this->setId(self::TAB_ID);
+        $this->setTitle($this->_helper('Mage_Tag_Helper_Data')->__('Customers Tagged Product'));
+    }
+
+    /**
+     * Helper getter
+     *
+     * @param string $helperName
+     * @return Mage_Core_Helper_Abstract
+     */
+    protected function _helper($helperName)
+    {
+        return isset($this->_helpers[$helperName]) ? $this->_helpers[$helperName] : Mage::helper($helperName);
+    }
+
+    /**
+     * Tab label getter
+     *
+     * @return string
+     */
+    public function getTabLabel()
+    {
+        return $this->getTitle();
+    }
+
+    /**
+     * Tab title getter
+     *
+     * @return string
+     */
+    public function getTabTitle()
+    {
+        return $this->getTitle();
+    }
+
+    /**
+     * Check whether tab can be showed
+     *
+     * @return bool
+     */
+    public function canShowTab()
+    {
+        return $this->_authSession->isAllowed('Mage_Tag::tag');
+    }
+
+    /**
+     * Check whether tab should be hidden
+     *
+     * @return bool
+     */
+    public function isHidden()
+    {
+        return false;
+    }
+
+    /**
+     * Tab class getter
+     *
+     * @return string
+     */
+    public function getTabClass()
+    {
+        return 'ajax';
+    }
+
+    /**
+     * Tab URL getter
+     *
+     * @return string
+     */
+    public function getTabUrl()
+    {
+        return $this->getUrl('*/*/tagCustomerGrid', array('_current' => true));
+    }
+
+    /**
+     * Retrieve id of tab after which current tab will be rendered
+     *
+     * @return string
+     */
+    public function getAfter()
+    {
+        return 'reviews';
+    }
+}
diff --git a/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Edit/Tab/Tag/Customer.php b/app/code/core/Mage/Tag/Block/Adminhtml/Catalog/Product/Edit/Tab/Tag/Customer/Grid.php
similarity index 63%
rename from app/code/core/Mage/Adminhtml/Block/Catalog/Product/Edit/Tab/Tag/Customer.php
rename to app/code/core/Mage/Tag/Block/Adminhtml/Catalog/Product/Edit/Tab/Tag/Customer/Grid.php
index c4b190ffce5..14185b5c0d6 100644
--- a/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Edit/Tab/Tag/Customer.php
+++ b/app/code/core/Mage/Tag/Block/Adminhtml/Catalog/Product/Edit/Tab/Tag/Customer/Grid.php
@@ -19,7 +19,7 @@
  * needs please refer to http://www.magentocommerce.com for more information.
  *
  * @category    Mage
- * @package     Mage_Adminhtml
+ * @package     Mage_Tag
  * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
  * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
  */
@@ -28,11 +28,13 @@
  * List of customers tagged a product
  *
  * @category   Mage
- * @package    Mage_Adminhtml
- * @author      Magento Core Team <core@magentocommerce.com>
+ * @package    Mage_Tag
+ * @author     Magento Core Team <core@magentocommerce.com>
+ *
+ * @method     Mage_Tag_Block_Adminhtml_Catalog_Product_Edit_Tab_Tag_Customer_Grid setUseAjax() setUseAjax(bool $flag)
+ * @method     int getProductId() getProductId()
  */
-
-class Mage_Adminhtml_Block_Catalog_Product_Edit_Tab_Tag_Customer extends Mage_Adminhtml_Block_Widget_Grid
+class Mage_Tag_Block_Adminhtml_Catalog_Product_Edit_Tab_Tag_Customer_Grid extends Mage_Backend_Block_Widget_Grid
 {
     public function __construct()
     {
@@ -45,15 +47,14 @@ class Mage_Adminhtml_Block_Catalog_Product_Edit_Tab_Tag_Customer extends Mage_Ad
 
     protected function _prepareCollection()
     {
-        if (Mage::helper('Mage_Catalog_Helper_Data')->isModuleEnabled('Mage_Tag')) {
-            $collection = Mage::getModel('Mage_Tag_Model_Tag')
-                ->getCustomerCollection()
-                ->addProductFilter($this->getProductId())
-                ->addGroupByTag()
-                ->addDescOrder();
+        $collection = Mage::getModel('Mage_Tag_Model_Tag')
+            ->getCustomerCollection()
+            ->addProductFilter($this->getProductId())
+            ->addGroupByTag()
+            ->addDescOrder();
+
+        $this->setCollection($collection);
 
-            $this->setCollection($collection);
-        }
         return parent::_prepareCollection();
     }
 
@@ -65,23 +66,23 @@ class Mage_Adminhtml_Block_Catalog_Product_Edit_Tab_Tag_Customer extends Mage_Ad
     protected function _prepareColumns()
     {
         $this->addColumn('firstname', array(
-            'header'    => Mage::helper('Mage_Catalog_Helper_Data')->__('First Name'),
-            'index'     => 'firstname',
+            'header' => Mage::helper('Mage_Tag_Helper_Data')->__('First Name'),
+            'index'  => 'firstname',
         ));
 
         $this->addColumn('lastname', array(
-            'header'        => Mage::helper('Mage_Catalog_Helper_Data')->__('Last Name'),
-            'index'         => 'lastname',
+            'header' => Mage::helper('Mage_Tag_Helper_Data')->__('Last Name'),
+            'index'  => 'lastname',
         ));
 
         $this->addColumn('email', array(
-            'header'        => Mage::helper('Mage_Catalog_Helper_Data')->__('Email'),
-            'index'         => 'email',
+            'header' => Mage::helper('Mage_Tag_Helper_Data')->__('Email'),
+            'index'  => 'email',
         ));
 
         $this->addColumn('name', array(
-            'header'        => Mage::helper('Mage_Catalog_Helper_Data')->__('Tag Name'),
-            'index'         => 'name',
+            'header' => Mage::helper('Mage_Tag_Helper_Data')->__('Tag Name'),
+            'index'  => 'name',
         ));
 
         return parent::_prepareColumns();
@@ -95,8 +96,8 @@ class Mage_Adminhtml_Block_Catalog_Product_Edit_Tab_Tag_Customer extends Mage_Ad
     public function getGridUrl()
     {
         return $this->getUrl('*/catalog_product/tagCustomerGrid', array(
-            '_current' => true,
-            'id'       => $this->getProductId(),
+            '_current'   => true,
+            'id'         => $this->getProductId(),
             'product_id' => $this->getProductId(),
         ));
     }
diff --git a/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Edit/Tab/Tag.php b/app/code/core/Mage/Tag/Block/Adminhtml/Catalog/Product/Edit/Tab/Tag/Grid.php
similarity index 81%
rename from app/code/core/Mage/Adminhtml/Block/Catalog/Product/Edit/Tab/Tag.php
rename to app/code/core/Mage/Tag/Block/Adminhtml/Catalog/Product/Edit/Tab/Tag/Grid.php
index 49a246f592d..3fa093c39f3 100644
--- a/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Edit/Tab/Tag.php
+++ b/app/code/core/Mage/Tag/Block/Adminhtml/Catalog/Product/Edit/Tab/Tag/Grid.php
@@ -19,20 +19,20 @@
  * needs please refer to http://www.magentocommerce.com for more information.
  *
  * @category    Mage
- * @package     Mage_Adminhtml
+ * @package     Mage_Tag
  * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
  * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
  */
 
 /**
- * Products' tags grid
+ * Products tags grid
  *
  * @category   Mage
- * @package    Mage_Adminhtml
- * @author      Magento Core Team <core@magentocommerce.com>
+ * @package    Mage_Tag
+ * @author     Magento Core Team <core@magentocommerce.com>
  */
 
-class Mage_Adminhtml_Block_Catalog_Product_Edit_Tab_Tag extends Mage_Adminhtml_Block_Widget_Grid
+class Mage_Tag_Block_Adminhtml_Catalog_Product_Edit_Tab_Tag_Grid extends Mage_Backend_Block_Widget_Grid
 {
     public function __construct()
     {
@@ -62,12 +62,12 @@ class Mage_Adminhtml_Block_Catalog_Product_Edit_Tab_Tag extends Mage_Adminhtml_B
     protected function _prepareColumns()
     {
         $this->addColumn('name', array(
-            'header'    => Mage::helper('Mage_Catalog_Helper_Data')->__('Tag Name'),
+            'header'    => Mage::helper('Mage_Tag_Helper_Data')->__('Tag Name'),
             'index'     => 'name',
         ));
 
         $this->addColumn('popularity', array(
-            'header'        => Mage::helper('Mage_Catalog_Helper_Data')->__('# of Use'),
+            'header'        => Mage::helper('Mage_Tag_Helper_Data')->__('# of Use'),
             'width'         => '50px',
             'align'         => 'right',
             'index'         => 'popularity',
@@ -75,14 +75,14 @@ class Mage_Adminhtml_Block_Catalog_Product_Edit_Tab_Tag extends Mage_Adminhtml_B
         ));
 
         $this->addColumn('status', array(
-            'header'    => Mage::helper('Mage_Catalog_Helper_Data')->__('Status'),
+            'header'    => Mage::helper('Mage_Tag_Helper_Data')->__('Status'),
             'width'     => '90px',
             'index'     => 'status',
             'type'      => 'options',
             'options'   => array(
-                Mage_Tag_Model_Tag::STATUS_DISABLED => Mage::helper('Mage_Catalog_Helper_Data')->__('Disabled'),
-                Mage_Tag_Model_Tag::STATUS_PENDING  => Mage::helper('Mage_Catalog_Helper_Data')->__('Pending'),
-                Mage_Tag_Model_Tag::STATUS_APPROVED => Mage::helper('Mage_Catalog_Helper_Data')->__('Approved'),
+                Mage_Tag_Model_Tag::STATUS_DISABLED => Mage::helper('Mage_Tag_Helper_Data')->__('Disabled'),
+                Mage_Tag_Model_Tag::STATUS_PENDING  => Mage::helper('Mage_Tag_Helper_Data')->__('Pending'),
+                Mage_Tag_Model_Tag::STATUS_APPROVED => Mage::helper('Mage_Tag_Helper_Data')->__('Approved'),
             ),
         ));
 
diff --git a/app/code/core/Mage/Adminhtml/Block/Tag/Customer.php b/app/code/core/Mage/Tag/Block/Adminhtml/Customer.php
similarity index 90%
rename from app/code/core/Mage/Adminhtml/Block/Tag/Customer.php
rename to app/code/core/Mage/Tag/Block/Adminhtml/Customer.php
index a9704f35c0c..8879201a033 100644
--- a/app/code/core/Mage/Adminhtml/Block/Tag/Customer.php
+++ b/app/code/core/Mage/Tag/Block/Adminhtml/Customer.php
@@ -19,7 +19,7 @@
  * needs please refer to http://www.magentocommerce.com for more information.
  *
  * @category    Mage
- * @package     Mage_Adminhtml
+ * @package     Mage_Tag
  * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
  * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
  */
@@ -28,11 +28,11 @@
  * Adminhtml customers tagged with tag
  *
  * @category   Mage
- * @package    Mage_Adminhtml
- * @author      Magento Core Team <core@magentocommerce.com>
+ * @package    Mage_Tag
+ * @author     Magento Core Team <core@magentocommerce.com>
  */
 
-class Mage_Adminhtml_Block_Tag_Customer extends Mage_Adminhtml_Block_Widget_Grid_Container
+class Mage_Tag_Block_Adminhtml_Customer extends Mage_Adminhtml_Block_Widget_Grid_Container
 {
 
     public function __construct()
diff --git a/app/code/core/Mage/Tag/Block/Adminhtml/Customer/Edit/Tab/Tag.php b/app/code/core/Mage/Tag/Block/Adminhtml/Customer/Edit/Tab/Tag.php
new file mode 100644
index 00000000000..c4715361af4
--- /dev/null
+++ b/app/code/core/Mage/Tag/Block/Adminhtml/Customer/Edit/Tab/Tag.php
@@ -0,0 +1,163 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @category    Mage
+ * @package     Mage_Tag
+ * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ *
+ * @method Mage_Tag_Block_Adminhtml_Customer_Edit_Tab_Tag setTitle() setTitle(string $title)
+ * @method string getTitle() getTitle()
+ */
+class Mage_Tag_Block_Adminhtml_Customer_Edit_Tab_Tag extends Mage_Backend_Block_Template
+    implements Mage_Backend_Block_Widget_Tab_Interface
+{
+    /**
+     * Array of data helpers
+     *
+     * @var array
+     */
+    protected $_helpers;
+
+    /**
+     * Current customer
+     *
+     * @var Mage_Customer_Model_Customer
+     */
+    protected $_customer;
+
+    /**
+     * Backend auth session
+     *
+     * @var Mage_Core_Model_Authorization
+     */
+    protected $_authSession;
+
+    /**
+     * Dependency injections, set identifier and title
+     *
+     * @param array $data
+     */
+    public function __construct(array $data = array())
+    {
+        parent::__construct();
+
+        if (isset($data['helpers'])) {
+            $this->_helpers = $data['helpers'];
+        }
+        if (isset($data['current_customer'])) {
+            $this->_customer = $data['current_customer'];
+        } else {
+            $this->_customer = Mage::registry('current_customer');
+        }
+        if (isset($data['auth_session'])) {
+            $this->_authSession = $data['auth_session'];
+        } else {
+            $this->_authSession = Mage::getSingleton('Mage_Core_Model_Authorization');
+        }
+
+        $this->setId('tags');
+        $this->setTitle($this->_helper('Mage_Tag_Helper_Data')->__('Product Tags'));
+    }
+
+    /**
+     * Helper getter
+     *
+     * @param string $helperName
+     * @return Mage_Core_Helper_Abstract
+     */
+    protected function _helper($helperName)
+    {
+        return isset($this->_helpers[$helperName]) ? $this->_helpers[$helperName] : Mage::helper($helperName);
+    }
+
+    /**
+     * Tab label getter
+     *
+     * @return string
+     */
+    public function getTabLabel()
+    {
+        return $this->getTitle();
+    }
+
+    /**
+     * Tab title getter
+     *
+     * @return string
+     */
+    public function getTabTitle()
+    {
+        return $this->getTitle();
+    }
+
+    /**
+     * Check whether tab can be showed
+     *
+     * @return bool
+     */
+    public function canShowTab()
+    {
+        if (!$this->_customer) {
+            return false;
+        }
+        return $this->_customer->getId() && $this->_authSession->isAllowed('Mage_Tag::tag');
+    }
+
+    /**
+     * Check whether tab should be hidden
+     *
+     * @return bool
+     */
+    public function isHidden()
+    {
+        return false;
+    }
+
+    /**
+     * Place current tab after "Product Reviews"
+     *
+     * @return string
+     */
+    public function getAfter()
+    {
+        return 'reviews';
+    }
+
+    /**
+     * Tab class getter
+     *
+     * @return string
+     */
+    public function getTabClass()
+    {
+        return 'ajax';
+    }
+
+    /**
+     * Tab URL getter
+     *
+     * @return string
+     */
+    public function getTabUrl()
+    {
+        return $this->getUrl('*/customer/productTags', array('_current' => true));
+    }
+}
diff --git a/app/code/core/Mage/Adminhtml/Block/Customer/Edit/Tab/Tag.php b/app/code/core/Mage/Tag/Block/Adminhtml/Customer/Edit/Tab/Tag/Grid.php
similarity index 50%
rename from app/code/core/Mage/Adminhtml/Block/Customer/Edit/Tab/Tag.php
rename to app/code/core/Mage/Tag/Block/Adminhtml/Customer/Edit/Tab/Tag/Grid.php
index d4a540ea944..69db63e7c8c 100644
--- a/app/code/core/Mage/Adminhtml/Block/Customer/Edit/Tab/Tag.php
+++ b/app/code/core/Mage/Tag/Block/Adminhtml/Customer/Edit/Tab/Tag/Grid.php
@@ -19,7 +19,7 @@
  * needs please refer to http://www.magentocommerce.com for more information.
  *
  * @category    Mage
- * @package     Mage_Adminhtml
+ * @package     Mage_Tag
  * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
  * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
  */
@@ -28,12 +28,18 @@
  * Customer's tags grid
  *
  * @category   Mage
- * @package    Mage_Adminhtml
- * @author      Magento Core Team <core@magentocommerce.com>
+ * @package    Mage_Tag
+ * @author     Magento Core Team <core@magentocommerce.com>
+ *
+ * @method Mage_Customer_Model_Customer|int getCustomerId() getCustomerId()
+ * @method Mage_Tag_Block_Adminhtml_Customer_Edit_Tab_Tag_Grid setCustomerId() setCustomerId(int $customerId)
+ * @method Mage_Tag_Block_Adminhtml_Customer_Edit_Tab_Tag_Grid setUseAjax() setUseAjax(boolean $useAjax)
  */
-class Mage_Adminhtml_Block_Customer_Edit_Tab_Tag extends Mage_Adminhtml_Block_Widget_Grid
+class Mage_Tag_Block_Adminhtml_Customer_Edit_Tab_Tag_Grid extends Mage_Backend_Block_Widget_Grid
 {
-
+    /**
+     * Initialize grid parameters
+     */
     public function __construct()
     {
         parent::__construct();
@@ -44,73 +50,100 @@ class Mage_Adminhtml_Block_Customer_Edit_Tab_Tag extends Mage_Adminhtml_Block_Wi
         $this->setFilterVisibility(false);
     }
 
+    /**
+     * Prepare data collection for output
+     *
+     * @return Mage_Tag_Model_Resource_Customer_Collection
+     */
     protected function _prepareCollection()
     {
-        $tagId = Mage::registry('tagId');
-
-        if( $this->getCustomerId() instanceof Mage_Customer_Model_Customer ) {
-            $this->setCustomerId( $this->getCustomerId()->getId() );
+        if ($this->getCustomerId() instanceof Mage_Customer_Model_Customer) {
+            $this->setCustomerId($this->getCustomerId()->getId());
         }
 
-        $collection = Mage::getResourceModel('Mage_Tag_Model_Resource_Customer_Collection')
-            ->addCustomerFilter($this->getCustomerId())
+        /** @var $collection Mage_Tag_Model_Resource_Customer_Collection */
+        $collection = Mage::getResourceModel('Mage_Tag_Model_Resource_Customer_Collection');
+        $collection->addCustomerFilter($this->getCustomerId())
             ->addGroupByTag();
 
         $this->setCollection($collection);
         return parent::_prepareCollection();
     }
 
+    /**
+     * Manual adding of product name
+     *
+     * @return Mage_Tag_Block_Adminhtml_Customer_Edit_Tab_Tag_Grid
+     */
     protected function _afterLoadCollection()
     {
-            $this->getCollection()->addProductName();
+        /** @var $collection Mage_Tag_Model_Resource_Customer_Collection */
+        $collection = $this->getCollection();
+        $collection->addProductName();
         return parent::_afterLoadCollection();
     }
 
+    /**
+     * Add grid columns
+     *
+     * @return Mage_Tag_Block_Adminhtml_Customer_Edit_Tab_Tag_Grid
+     */
     protected function _prepareColumns()
     {
         $this->addColumn('name', array(
-            'header'    => Mage::helper('Mage_Customer_Helper_Data')->__('Tag Name'),
-            'index'     => 'name',
+            'header' => Mage::helper('Mage_Tag_Helper_Data')->__('Tag Name'),
+            'index'  => 'name',
         ));
 
         $this->addColumn('status', array(
-            'header'    => Mage::helper('Mage_Customer_Helper_Data')->__('Status'),
-            'width'     => '90px',
-            'index'     => 'status',
-            'type'      => 'options',
-            'options'    => array(
-                Mage_Tag_Model_Tag::STATUS_DISABLED => Mage::helper('Mage_Customer_Helper_Data')->__('Disabled'),
-                Mage_Tag_Model_Tag::STATUS_PENDING  => Mage::helper('Mage_Customer_Helper_Data')->__('Pending'),
-                Mage_Tag_Model_Tag::STATUS_APPROVED => Mage::helper('Mage_Customer_Helper_Data')->__('Approved'),
+            'header'  => Mage::helper('Mage_Tag_Helper_Data')->__('Status'),
+            'width'   => '90px',
+            'index'   => 'status',
+            'type'    => 'options',
+            'options' => array(
+                Mage_Tag_Model_Tag::STATUS_DISABLED => Mage::helper('Mage_Tag_Helper_Data')->__('Disabled'),
+                Mage_Tag_Model_Tag::STATUS_PENDING  => Mage::helper('Mage_Tag_Helper_Data')->__('Pending'),
+                Mage_Tag_Model_Tag::STATUS_APPROVED => Mage::helper('Mage_Tag_Helper_Data')->__('Approved'),
             ),
-            'filter'    => false,
+            'filter'  => false,
         ));
 
         $this->addColumn('product', array(
-            'header'    => Mage::helper('Mage_Customer_Helper_Data')->__('Product Name'),
-            'index'     => 'product',
-            'filter'    => false,
-            'sortable'  => false,
+            'header'   => Mage::helper('Mage_Tag_Helper_Data')->__('Product Name'),
+            'index'    => 'product',
+            'filter'   => false,
+            'sortable' => false,
         ));
 
         $this->addColumn('product_sku', array(
-            'header'    => Mage::helper('Mage_Customer_Helper_Data')->__('SKU'),
-            'index'     => 'product_sku',
-            'filter'    => false,
-            'sortable'  => false,
+            'header'   => Mage::helper('Mage_Tag_Helper_Data')->__('SKU'),
+            'index'    => 'product_sku',
+            'filter'   => false,
+            'sortable' => false,
         ));
 
         return parent::_prepareColumns();
     }
 
+    /**
+     * Returns URL for editing of row tag
+     *
+     * @param Varien_Object $row
+     * @return string
+     */
     public function getRowUrl($row)
     {
         return $this->getUrl('*/tag/edit', array(
-            'tag_id' => $row->getTagId(),
+            'tag_id'      => $row->getTagId(),
             'customer_id' => $this->getCustomerId(),
         ));
     }
 
+    /**
+     * Returns URL for grid updating
+     *
+     * @return string
+     */
     public function getGridUrl()
     {
         return $this->getUrl('*/customer/tagGrid', array(
diff --git a/app/code/core/Mage/Adminhtml/Block/Tag/Customer/Grid.php b/app/code/core/Mage/Tag/Block/Adminhtml/Customer/Grid.php
similarity index 93%
rename from app/code/core/Mage/Adminhtml/Block/Tag/Customer/Grid.php
rename to app/code/core/Mage/Tag/Block/Adminhtml/Customer/Grid.php
index ec2203dd2a2..b2f80066c6d 100644
--- a/app/code/core/Mage/Adminhtml/Block/Tag/Customer/Grid.php
+++ b/app/code/core/Mage/Tag/Block/Adminhtml/Customer/Grid.php
@@ -19,19 +19,19 @@
  * needs please refer to http://www.magentocommerce.com for more information.
  *
  * @category    Mage
- * @package     Mage_Adminhtml
+ * @package     Mage_Tag
  * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
  * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
  */
 
 /**
- * Child Of Mage_Adminhtml_Block_Tag_Customer
+ * Child Of Mage_Tag_Block_Adminhtml_Customer
  *
  * @category   Mage
- * @package    Mage_Adminhtml
- * @author      Magento Core Team <core@magentocommerce.com>
+ * @package    Mage_Tag
+ * @author     Magento Core Team <core@magentocommerce.com>
  */
-class Mage_Adminhtml_Block_Tag_Customer_Grid extends Mage_Adminhtml_Block_Widget_Grid
+class Mage_Tag_Block_Adminhtml_Customer_Grid extends Mage_Adminhtml_Block_Widget_Grid
 {
 
     public function __construct()
diff --git a/app/code/core/Mage/Adminhtml/Block/Tag/Edit.php b/app/code/core/Mage/Tag/Block/Adminhtml/Edit.php
similarity index 88%
rename from app/code/core/Mage/Adminhtml/Block/Tag/Edit.php
rename to app/code/core/Mage/Tag/Block/Adminhtml/Edit.php
index 2e840c7b3bf..df3e9d96e52 100644
--- a/app/code/core/Mage/Adminhtml/Block/Tag/Edit.php
+++ b/app/code/core/Mage/Tag/Block/Adminhtml/Edit.php
@@ -19,7 +19,7 @@
  * needs please refer to http://www.magentocommerce.com for more information.
  *
  * @category    Mage
- * @package     Mage_Adminhtml
+ * @package     Mage_Tag
  * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
  * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
  */
@@ -28,11 +28,11 @@
  * Admin tag edit block
  *
  * @category   Mage
- * @package    Mage_Adminhtml
- * @author      Magento Core Team <core@magentocommerce.com>
+ * @package    Mage_Tag
+ * @author     Magento Core Team <core@magentocommerce.com>
  */
 
-class Mage_Adminhtml_Block_Tag_Edit extends Mage_Adminhtml_Block_Widget_Form_Container
+class Mage_Tag_Block_Adminhtml_Edit extends Mage_Adminhtml_Block_Widget_Form_Container
 {
     /**
      * Add and update buttons
@@ -42,7 +42,8 @@ class Mage_Adminhtml_Block_Tag_Edit extends Mage_Adminhtml_Block_Widget_Form_Con
     public function __construct()
     {
         $this->_objectId   = 'tag_id';
-        $this->_controller = 'tag';
+        $this->_controller = 'adminhtml';
+        $this->_blockGroup = 'Mage_Tag';
 
         parent::__construct();
 
@@ -63,7 +64,7 @@ class Mage_Adminhtml_Block_Tag_Edit extends Mage_Adminhtml_Block_Widget_Form_Con
     /**
      * Add child HTML to layout
      *
-     * @return Mage_Adminhtml_Block_Tag_Edit
+     * @return Mage_Tag_Block_Adminhtml_Edit
      */
     protected function _prepareLayout()
     {
@@ -71,13 +72,13 @@ class Mage_Adminhtml_Block_Tag_Edit extends Mage_Adminhtml_Block_Widget_Form_Con
 
         $this->setChild(
                 'store_switcher',
-                $this->getLayout()->createBlock('Mage_Adminhtml_Block_Tag_Store_Switcher'))
+                $this->getLayout()->createBlock('Mage_Tag_Block_Adminhtml_Store_Switcher'))
              ->setChild(
                 'tag_assign_accordion',
-                $this->getLayout()->createBlock('Mage_Adminhtml_Block_Tag_Edit_Assigned'))
+                $this->getLayout()->createBlock('Mage_Tag_Block_Adminhtml_Edit_Assigned'))
              ->setChild(
                 'accordion',
-                $this->getLayout()->createBlock('Mage_Adminhtml_Block_Tag_Edit_Accordion'));
+                $this->getLayout()->createBlock('Mage_Tag_Block_Adminhtml_Edit_Accordion'));
 
         return $this;
     }
diff --git a/app/code/core/Mage/Adminhtml/Block/Tag/Edit/Accordion.php b/app/code/core/Mage/Tag/Block/Adminhtml/Edit/Accordion.php
similarity index 94%
rename from app/code/core/Mage/Adminhtml/Block/Tag/Edit/Accordion.php
rename to app/code/core/Mage/Tag/Block/Adminhtml/Edit/Accordion.php
index abf8a4ccffe..3859f1ee0dc 100644
--- a/app/code/core/Mage/Adminhtml/Block/Tag/Edit/Accordion.php
+++ b/app/code/core/Mage/Tag/Block/Adminhtml/Edit/Accordion.php
@@ -19,7 +19,7 @@
  * needs please refer to http://www.magentocommerce.com for more information.
  *
  * @category    Mage
- * @package     Mage_Adminhtml
+ * @package     Mage_Tag
  * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
  * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
  */
@@ -28,11 +28,11 @@
  * Adminhtml tag accordion
  *
  * @category   Mage
- * @package    Mage_Adminhtml
+ * @package    Mage_Tag
  * @author     Magento Core Team <core@magentocommerce.com>
  */
 
-class Mage_Adminhtml_Block_Tag_Edit_Accordion extends Mage_Adminhtml_Block_Widget_Accordion
+class Mage_Tag_Block_Adminhtml_Edit_Accordion extends Mage_Adminhtml_Block_Widget_Accordion
 {
     /**
      * Add products and customers accordion to layout
diff --git a/app/code/core/Mage/Adminhtml/Block/Tag/Edit/Assigned.php b/app/code/core/Mage/Tag/Block/Adminhtml/Edit/Assigned.php
similarity index 93%
rename from app/code/core/Mage/Adminhtml/Block/Tag/Edit/Assigned.php
rename to app/code/core/Mage/Tag/Block/Adminhtml/Edit/Assigned.php
index 3f17919d0d9..ff0fd90e46c 100644
--- a/app/code/core/Mage/Adminhtml/Block/Tag/Edit/Assigned.php
+++ b/app/code/core/Mage/Tag/Block/Adminhtml/Edit/Assigned.php
@@ -19,7 +19,7 @@
  * needs please refer to http://www.magentocommerce.com for more information.
  *
  * @category    Mage
- * @package     Mage_Adminhtml
+ * @package     Mage_Tag
  * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
  * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
  */
@@ -28,11 +28,11 @@
  * Adminhtml tag accordion
  *
  * @category   Mage
- * @package    Mage_Adminhtml
+ * @package    Mage_Tag
  * @author     Magento Core Team <core@magentocommerce.com>
  */
 
-class Mage_Adminhtml_Block_Tag_Edit_Assigned extends Mage_Adminhtml_Block_Widget_Accordion
+class Mage_Tag_Block_Adminhtml_Edit_Assigned extends Mage_Adminhtml_Block_Widget_Accordion
 {
     /**
      * Add Assigned products accordion to layout
diff --git a/app/code/core/Mage/Adminhtml/Block/Tag/Edit/Form.php b/app/code/core/Mage/Tag/Block/Adminhtml/Edit/Form.php
similarity index 91%
rename from app/code/core/Mage/Adminhtml/Block/Tag/Edit/Form.php
rename to app/code/core/Mage/Tag/Block/Adminhtml/Edit/Form.php
index b2b661fa0f9..df3655eff19 100644
--- a/app/code/core/Mage/Adminhtml/Block/Tag/Edit/Form.php
+++ b/app/code/core/Mage/Tag/Block/Adminhtml/Edit/Form.php
@@ -19,7 +19,7 @@
  * needs please refer to http://www.magentocommerce.com for more information.
  *
  * @category    Mage
- * @package     Mage_Adminhtml
+ * @package     Mage_Tag
  * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
  * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
  */
@@ -28,11 +28,11 @@
  * Adminhtml tag edit form
  *
  * @category   Mage
- * @package    Mage_Adminhtml
- * @author      Magento Core Team <core@magentocommerce.com>
+ * @package    Mage_Tag
+ * @author     Magento Core Team <core@magentocommerce.com>
  */
 
-class Mage_Adminhtml_Block_Tag_Edit_Form extends Mage_Adminhtml_Block_Widget_Form
+class Mage_Tag_Block_Adminhtml_Edit_Form extends Mage_Adminhtml_Block_Widget_Form
 {
 
     public function __construct()
@@ -79,7 +79,7 @@ class Mage_Adminhtml_Block_Tag_Edit_Form extends Mage_Adminhtml_Block_Widget_For
             'label' => Mage::helper('Mage_Tag_Helper_Data')->__('Tag Name'),
             'title' => Mage::helper('Mage_Tag_Helper_Data')->__('Tag Name'),
             'required' => true,
-            'after_element_html' => ' ' . Mage::helper('Mage_Adminhtml_Helper_Data')->__('[GLOBAL]'),
+            'after_element_html' => ' ' . Mage::helper('Mage_Tag_Helper_Data')->__('[GLOBAL]'),
         ));
 
         $fieldset->addField('status', 'select', array(
@@ -92,7 +92,7 @@ class Mage_Adminhtml_Block_Tag_Edit_Form extends Mage_Adminhtml_Block_Widget_For
                 Mage_Tag_Model_Tag::STATUS_PENDING  => Mage::helper('Mage_Tag_Helper_Data')->__('Pending'),
                 Mage_Tag_Model_Tag::STATUS_APPROVED => Mage::helper('Mage_Tag_Helper_Data')->__('Approved'),
             ),
-            'after_element_html' => ' ' . Mage::helper('Mage_Adminhtml_Helper_Data')->__('[GLOBAL]'),
+            'after_element_html' => ' ' . Mage::helper('Mage_Tag_Helper_Data')->__('[GLOBAL]'),
         ));
 
         $fieldset->addField('base_popularity', 'text', array(
diff --git a/app/code/core/Mage/Adminhtml/Block/Tag/Grid/All.php b/app/code/core/Mage/Tag/Block/Adminhtml/Grid/All.php
similarity index 94%
rename from app/code/core/Mage/Adminhtml/Block/Tag/Grid/All.php
rename to app/code/core/Mage/Tag/Block/Adminhtml/Grid/All.php
index a0a461fb4d5..fa4fc1395b5 100644
--- a/app/code/core/Mage/Adminhtml/Block/Tag/Grid/All.php
+++ b/app/code/core/Mage/Tag/Block/Adminhtml/Grid/All.php
@@ -19,7 +19,7 @@
  * needs please refer to http://www.magentocommerce.com for more information.
  *
  * @category    Mage
- * @package     Mage_Adminhtml
+ * @package     Mage_Tag
  * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
  * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
  */
@@ -28,10 +28,10 @@
  * Adminhtml all tags grid block
  *
  * @category   Mage
- * @package    Mage_Adminhtml
- * @author      Magento Core Team <core@magentocommerce.com>
+ * @package    Mage_Tag
+ * @author     Magento Core Team <core@magentocommerce.com>
  */
-class Mage_Adminhtml_Block_Tag_Grid_All extends Mage_Adminhtml_Block_Widget_Grid
+class Mage_Tag_Block_Adminhtml_Grid_All extends Mage_Adminhtml_Block_Widget_Grid
 {
     public function __construct()
     {
diff --git a/app/code/core/Mage/Adminhtml/Block/Tag/Grid/Pending.php b/app/code/core/Mage/Tag/Block/Adminhtml/Grid/Pending.php
similarity index 97%
rename from app/code/core/Mage/Adminhtml/Block/Tag/Grid/Pending.php
rename to app/code/core/Mage/Tag/Block/Adminhtml/Grid/Pending.php
index f2ca70e1530..2c95486c3c0 100644
--- a/app/code/core/Mage/Adminhtml/Block/Tag/Grid/Pending.php
+++ b/app/code/core/Mage/Tag/Block/Adminhtml/Grid/Pending.php
@@ -19,7 +19,7 @@
  * needs please refer to http://www.magentocommerce.com for more information.
  *
  * @category    Mage
- * @package     Mage_Adminhtml
+ * @package     Mage_Tag
  * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
  * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
  */
@@ -28,10 +28,10 @@
  * Adminhtml pending tags grid
  *
  * @category   Mage
- * @package    Mage_Adminhtml
+ * @package    Mage_Tag
  * @author     Magento Core Team <core@magentocommerce.com>
  */
-class Mage_Adminhtml_Block_Tag_Grid_Pending extends Mage_Adminhtml_Block_Widget_Grid
+class Mage_Tag_Block_Adminhtml_Grid_Pending extends Mage_Adminhtml_Block_Widget_Grid
 {
     /**
      * Constructor
diff --git a/app/code/core/Mage/Adminhtml/Block/Tag/Pending.php b/app/code/core/Mage/Tag/Block/Adminhtml/Pending.php
similarity index 90%
rename from app/code/core/Mage/Adminhtml/Block/Tag/Pending.php
rename to app/code/core/Mage/Tag/Block/Adminhtml/Pending.php
index 346f6218838..e61b9184920 100644
--- a/app/code/core/Mage/Adminhtml/Block/Tag/Pending.php
+++ b/app/code/core/Mage/Tag/Block/Adminhtml/Pending.php
@@ -19,7 +19,7 @@
  * needs please refer to http://www.magentocommerce.com for more information.
  *
  * @category    Mage
- * @package     Mage_Adminhtml
+ * @package     Mage_Tag
  * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
  * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
  */
@@ -28,10 +28,10 @@
  * Adminhtml pending tags grid block
  *
  * @category   Mage
- * @package    Mage_Adminhtml
+ * @package    Mage_Tag
  * @author     Magento Core Team <core@magentocommerce.com>
  */
-class Mage_Adminhtml_Block_Tag_Pending extends Mage_Adminhtml_Block_Template
+class Mage_Tag_Block_Adminhtml_Pending extends Mage_Adminhtml_Block_Template
 {
     /**
      * Constructor
@@ -46,7 +46,7 @@ class Mage_Adminhtml_Block_Tag_Pending extends Mage_Adminhtml_Block_Template
 
     protected function _prepareLayout()
     {
-        $this->setChild('tagsGrid', $this->getLayout()->createBlock('Mage_Adminhtml_Block_Tag_Grid_Pending'));
+        $this->setChild('tagsGrid', $this->getLayout()->createBlock('Mage_Tag_Block_Adminhtml_Grid_Pending'));
         return parent::_prepareLayout();
     }
 
diff --git a/app/code/core/Mage/Adminhtml/Block/Tag/Product.php b/app/code/core/Mage/Tag/Block/Adminhtml/Product.php
similarity index 90%
rename from app/code/core/Mage/Adminhtml/Block/Tag/Product.php
rename to app/code/core/Mage/Tag/Block/Adminhtml/Product.php
index 46b50f966cc..3ad74e03420 100644
--- a/app/code/core/Mage/Adminhtml/Block/Tag/Product.php
+++ b/app/code/core/Mage/Tag/Block/Adminhtml/Product.php
@@ -19,7 +19,7 @@
  * needs please refer to http://www.magentocommerce.com for more information.
  *
  * @category    Mage
- * @package     Mage_Adminhtml
+ * @package     Mage_Tag
  * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
  * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
  */
@@ -28,10 +28,10 @@
  * Adminhtml products tagged by tag
  *
  * @category   Mage
- * @package    Mage_Adminhtml
- * @author      Magento Core Team <core@magentocommerce.com>
+ * @package    Mage_Tag
+ * @author     Magento Core Team <core@magentocommerce.com>
  */
-class Mage_Adminhtml_Block_Tag_Product extends Mage_Adminhtml_Block_Widget_Grid_Container
+class Mage_Tag_Block_Adminhtml_Product extends Mage_Adminhtml_Block_Widget_Grid_Container
 {
 
     public function __construct()
diff --git a/app/code/core/Mage/Adminhtml/Block/Tag/Product/Grid.php b/app/code/core/Mage/Tag/Block/Adminhtml/Product/Grid.php
similarity index 92%
rename from app/code/core/Mage/Adminhtml/Block/Tag/Product/Grid.php
rename to app/code/core/Mage/Tag/Block/Adminhtml/Product/Grid.php
index b40c6ed554c..dd0f6e11646 100644
--- a/app/code/core/Mage/Adminhtml/Block/Tag/Product/Grid.php
+++ b/app/code/core/Mage/Tag/Block/Adminhtml/Product/Grid.php
@@ -19,19 +19,19 @@
  * needs please refer to http://www.magentocommerce.com for more information.
  *
  * @category    Mage
- * @package     Mage_Adminhtml
+ * @package     Mage_Tag
  * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
  * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
  */
 
 /**
- * Child Of Mage_Adminhtml_Block_Tag_Product
+ * Child Of Mage_Tag_Block_Adminhtml_Product
  *
  * @category   Mage
- * @package    Mage_Adminhtml
- * @author      Magento Core Team <core@magentocommerce.com>
+ * @package    Mage_Tag
+ * @author     Magento Core Team <core@magentocommerce.com>
  */
-class Mage_Adminhtml_Block_Tag_Product_Grid extends Mage_Adminhtml_Block_Widget_Grid
+class Mage_Tag_Block_Adminhtml_Product_Grid extends Mage_Adminhtml_Block_Widget_Grid
 {
 
     public function __construct()
@@ -111,7 +111,7 @@ class Mage_Adminhtml_Block_Tag_Product_Grid extends Mage_Adminhtml_Block_Widget_
 
     protected function _addColumnFilterToCollection($column)
     {
-        if($column->getIndex() == 'popularity') {
+        if ($column->getIndex() == 'popularity') {
             $this->getCollection()->addPopularityFilter($column->getFilter()->getCondition());
             return $this;
         } else {
diff --git a/app/code/core/Mage/Adminhtml/Block/Report/Tag/Customer.php b/app/code/core/Mage/Tag/Block/Adminhtml/Report/Customer.php
similarity index 76%
rename from app/code/core/Mage/Adminhtml/Block/Report/Tag/Customer.php
rename to app/code/core/Mage/Tag/Block/Adminhtml/Report/Customer.php
index 2d8984c8062..ddced90e49a 100644
--- a/app/code/core/Mage/Adminhtml/Block/Report/Tag/Customer.php
+++ b/app/code/core/Mage/Tag/Block/Adminhtml/Report/Customer.php
@@ -19,7 +19,7 @@
  * needs please refer to http://www.magentocommerce.com for more information.
  *
  * @category    Mage
- * @package     Mage_Adminhtml
+ * @package     Mage_Tag
  * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
  * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
  */
@@ -28,17 +28,17 @@
  * Adminhtml customers tag blocks content block
  *
  * @category   Mage
- * @package    Mage_Adminhtml
- * @author      Magento Core Team <core@magentocommerce.com>
+ * @package    Mage_Tag
+ * @author     Magento Core Team <core@magentocommerce.com>
  */
 
-class Mage_Adminhtml_Block_Report_Tag_Customer extends Mage_Adminhtml_Block_Widget_Grid_Container
+class Mage_Tag_Block_Adminhtml_Report_Customer extends Mage_Adminhtml_Block_Widget_Grid_Container
 {
-
     public function __construct()
     {
-        $this->_controller = 'report_tag_customer';
-        $this->_headerText = Mage::helper('Mage_Reports_Helper_Data')->__('Customers Tags');
+        $this->_blockGroup = 'Mage_Tag';
+        $this->_controller = 'adminhtml_report_customer';
+        $this->_headerText = Mage::helper('Mage_Tag_Helper_Data')->__('Customers Tags');
         parent::__construct();
         $this->_removeButton('add');
     }
diff --git a/app/code/core/Mage/Adminhtml/Block/Report/Tag/Customer/Detail.php b/app/code/core/Mage/Tag/Block/Adminhtml/Report/Customer/Detail.php
similarity index 79%
rename from app/code/core/Mage/Adminhtml/Block/Report/Tag/Customer/Detail.php
rename to app/code/core/Mage/Tag/Block/Adminhtml/Report/Customer/Detail.php
index 60562550a92..cd27e0bb79c 100644
--- a/app/code/core/Mage/Adminhtml/Block/Report/Tag/Customer/Detail.php
+++ b/app/code/core/Mage/Tag/Block/Adminhtml/Report/Customer/Detail.php
@@ -19,7 +19,7 @@
  * needs please refer to http://www.magentocommerce.com for more information.
  *
  * @category    Mage
- * @package     Mage_Adminhtml
+ * @package     Mage_Tag
  * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
  * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
  */
@@ -28,20 +28,19 @@
  * Adminhtml tags detail for customer report blocks content block
  *
  * @category   Mage
- * @package    Mage_Adminhtml
- * @author      Magento Core Team <core@magentocommerce.com>
+ * @package    Mage_Tag
+ * @author     Magento Core Team <core@magentocommerce.com>
  */
-
-class Mage_Adminhtml_Block_Report_Tag_Customer_Detail extends Mage_Adminhtml_Block_Widget_Grid_Container
+class Mage_Tag_Block_Adminhtml_Report_Customer_Detail extends Mage_Adminhtml_Block_Widget_Grid_Container
 {
-
     public function __construct()
     {
-        $this->_controller = 'report_tag_customer_detail';
+        $this->_blockGroup = 'Mage_Tag';
+        $this->_controller = 'adminhtml_report_customer_detail';
 
         $customer = Mage::getModel('Mage_Customer_Model_Customer')->load($this->getRequest()->getParam('id'));
         $customerName = $this->escapeHtml($customer->getName());
-        $this->_headerText = Mage::helper('Mage_Reports_Helper_Data')->__('Tags Submitted by %s', $customerName);
+        $this->_headerText = Mage::helper('Mage_Tag_Helper_Data')->__('Tags Submitted by %s', $customerName);
         parent::__construct();
         $this->_removeButton('add');
         $this->setBackUrl($this->getUrl('*/report_tag/customer/'));
diff --git a/app/code/core/Mage/Adminhtml/Block/Report/Tag/Customer/Detail/Grid.php b/app/code/core/Mage/Tag/Block/Adminhtml/Report/Customer/Detail/Grid.php
similarity index 79%
rename from app/code/core/Mage/Adminhtml/Block/Report/Tag/Customer/Detail/Grid.php
rename to app/code/core/Mage/Tag/Block/Adminhtml/Report/Customer/Detail/Grid.php
index f8cd8eb3a7f..e93e92200b2 100644
--- a/app/code/core/Mage/Adminhtml/Block/Report/Tag/Customer/Detail/Grid.php
+++ b/app/code/core/Mage/Tag/Block/Adminhtml/Report/Customer/Detail/Grid.php
@@ -19,7 +19,7 @@
  * needs please refer to http://www.magentocommerce.com for more information.
  *
  * @category    Mage
- * @package     Mage_Adminhtml
+ * @package     Mage_Tag
  * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
  * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
  */
@@ -28,12 +28,11 @@
  * Adminhtml tags detail for customer report grid block
  *
  * @category   Mage
- * @package    Mage_Adminhtml
- * @author      Magento Core Team <core@magentocommerce.com>
+ * @package    Mage_Tag
+ * @author     Magento Core Team <core@magentocommerce.com>
  */
-class Mage_Adminhtml_Block_Report_Tag_Customer_Detail_Grid extends Mage_Adminhtml_Block_Widget_Grid
+class Mage_Tag_Block_Adminhtml_Report_Customer_Detail_Grid extends Mage_Adminhtml_Block_Widget_Grid
 {
-
     public function __construct()
     {
         parent::__construct();
@@ -60,18 +59,18 @@ class Mage_Adminhtml_Block_Report_Tag_Customer_Detail_Grid extends Mage_Adminhtm
     protected function _prepareColumns()
     {
         $this->addColumn('name', array(
-            'header'    =>Mage::helper('Mage_Reports_Helper_Data')->__('Product Name'),
+            'header'    =>Mage::helper('Mage_Tag_Helper_Data')->__('Product Name'),
             'index'     =>'original_name'
         ));
 
         $this->addColumn('tag_name', array(
-            'header'    =>Mage::helper('Mage_Reports_Helper_Data')->__('Tag Name'),
+            'header'    =>Mage::helper('Mage_Tag_Helper_Data')->__('Tag Name'),
             'index'     =>'tag_name'
         ));
 
         if (!Mage::app()->isSingleStoreMode()) {
             $this->addColumn('visible', array(
-                'header'    => Mage::helper('Mage_Reports_Helper_Data')->__('Visible In'),
+                'header'    => Mage::helper('Mage_Tag_Helper_Data')->__('Visible In'),
                 'index'     => 'stores',
                 'type'      => 'store',
                 'sortable'  => false,
@@ -79,7 +78,7 @@ class Mage_Adminhtml_Block_Report_Tag_Customer_Detail_Grid extends Mage_Adminhtm
             ));
 
             $this->addColumn('added_in', array(
-                'header'    =>Mage::helper('Mage_Reports_Helper_Data')->__('Submitted In'),
+                'header'    =>Mage::helper('Mage_Tag_Helper_Data')->__('Submitted In'),
                 'index'     =>'store_id',
                 'type'      =>'store',
                 'store_view'=>true
@@ -87,7 +86,7 @@ class Mage_Adminhtml_Block_Report_Tag_Customer_Detail_Grid extends Mage_Adminhtm
         }
 
         $this->addColumn('created_at', array(
-            'header'    =>Mage::helper('Mage_Reports_Helper_Data')->__('Submitted On'),
+            'header'    =>Mage::helper('Mage_Tag_Helper_Data')->__('Submitted On'),
             'width'     => '140px',
             'type'      => 'datetime',
             'index'     => 'created_at'
@@ -95,8 +94,8 @@ class Mage_Adminhtml_Block_Report_Tag_Customer_Detail_Grid extends Mage_Adminhtm
 
         $this->setFilterVisibility(false);
 
-        $this->addExportType('*/*/exportCustomerDetailCsv', Mage::helper('Mage_Reports_Helper_Data')->__('CSV'));
-        $this->addExportType('*/*/exportCustomerDetailExcel', Mage::helper('Mage_Reports_Helper_Data')->__('Excel XML'));
+        $this->addExportType('*/*/exportCustomerDetailCsv', Mage::helper('Mage_Tag_Helper_Data')->__('CSV'));
+        $this->addExportType('*/*/exportCustomerDetailExcel', Mage::helper('Mage_Tag_Helper_Data')->__('Excel XML'));
 
         return parent::_prepareColumns();
     }
diff --git a/app/code/core/Mage/Adminhtml/Block/Report/Tag/Customer/Grid.php b/app/code/core/Mage/Tag/Block/Adminhtml/Report/Customer/Grid.php
similarity index 76%
rename from app/code/core/Mage/Adminhtml/Block/Report/Tag/Customer/Grid.php
rename to app/code/core/Mage/Tag/Block/Adminhtml/Report/Customer/Grid.php
index e667ae47121..e385d6ebb6d 100644
--- a/app/code/core/Mage/Adminhtml/Block/Report/Tag/Customer/Grid.php
+++ b/app/code/core/Mage/Tag/Block/Adminhtml/Report/Customer/Grid.php
@@ -19,7 +19,7 @@
  * needs please refer to http://www.magentocommerce.com for more information.
  *
  * @category    Mage
- * @package     Mage_Adminhtml
+ * @package     Mage_Tag
  * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
  * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
  */
@@ -28,12 +28,11 @@
  * Adminhtml tags by customers report grid block
  *
  * @category   Mage
- * @package    Mage_Adminhtml
- * @author      Magento Core Team <core@magentocommerce.com>
+ * @package    Mage_Tag
+ * @author     Magento Core Team <core@magentocommerce.com>
  */
-class Mage_Adminhtml_Block_Report_Tag_Customer_Grid extends Mage_Adminhtml_Block_Widget_Grid
+class Mage_Tag_Block_Adminhtml_Report_Customer_Grid extends Mage_Adminhtml_Block_Widget_Grid
 {
-
     public function __construct()
     {
         parent::__construct();
@@ -43,7 +42,7 @@ class Mage_Adminhtml_Block_Report_Tag_Customer_Grid extends Mage_Adminhtml_Block
     protected function _prepareCollection()
     {
 
-        $collection = Mage::getResourceModel('Mage_Reports_Model_Resource_Tag_Customer_Collection');
+        $collection = Mage::getResourceModel('Mage_Tag_Model_Resource_Reports_Customer_Collection');
 
         $collection->addStatusFilter(Mage_Tag_Model_Tag::STATUS_APPROVED)
             ->addGroupByCustomer()
@@ -57,24 +56,24 @@ class Mage_Adminhtml_Block_Report_Tag_Customer_Grid extends Mage_Adminhtml_Block
     {
 
         $this->addColumn('entity_id', array(
-            'header'    =>Mage::helper('Mage_Reports_Helper_Data')->__('ID'),
+            'header'    =>Mage::helper('Mage_Tag_Helper_Data')->__('ID'),
             'width'     => '50px',
             'align'     =>'right',
             'index'     =>'entity_id'
         ));
 
         $this->addColumn('firstname', array(
-            'header'    =>Mage::helper('Mage_Reports_Helper_Data')->__('First Name'),
+            'header'    =>Mage::helper('Mage_Tag_Helper_Data')->__('First Name'),
             'index'     =>'firstname'
         ));
 
         $this->addColumn('lastname', array(
-            'header'    =>Mage::helper('Mage_Reports_Helper_Data')->__('Last Name'),
+            'header'    =>Mage::helper('Mage_Tag_Helper_Data')->__('Last Name'),
             'index'     =>'lastname'
         ));
 
         $this->addColumn('taged', array(
-            'header'    =>Mage::helper('Mage_Reports_Helper_Data')->__('Total Tags'),
+            'header'    =>Mage::helper('Mage_Tag_Helper_Data')->__('Total Tags'),
             'width'     =>'50px',
             'align'     =>'right',
             'index'     =>'taged'
@@ -82,13 +81,13 @@ class Mage_Adminhtml_Block_Report_Tag_Customer_Grid extends Mage_Adminhtml_Block
 
         $this->addColumn('action',
             array(
-                'header'    => Mage::helper('Mage_Catalog_Helper_Data')->__('Action'),
+                'header'    => Mage::helper('Mage_Tag_Helper_Data')->__('Action'),
                 'width'     => '100%',
                 'type'      => 'action',
                 'getter'    => 'getId',
                 'actions'   => array(
                     array(
-                        'caption' => Mage::helper('Mage_Catalog_Helper_Data')->__('Show Tags'),
+                        'caption' => Mage::helper('Mage_Tag_Helper_Data')->__('Show Tags'),
                         'url'     => array(
                             'base'=>'*/*/customerDetail'
                         ),
@@ -103,8 +102,8 @@ class Mage_Adminhtml_Block_Report_Tag_Customer_Grid extends Mage_Adminhtml_Block
 
         $this->setFilterVisibility(false);
 
-        $this->addExportType('*/*/exportCustomerCsv', Mage::helper('Mage_Reports_Helper_Data')->__('CSV'));
-        $this->addExportType('*/*/exportCustomerExcel', Mage::helper('Mage_Reports_Helper_Data')->__('Excel XML'));
+        $this->addExportType('*/*/exportCustomerCsv', Mage::helper('Mage_Tag_Helper_Data')->__('CSV'));
+        $this->addExportType('*/*/exportCustomerExcel', Mage::helper('Mage_Tag_Helper_Data')->__('Excel XML'));
 
         return parent::_prepareColumns();
     }
diff --git a/app/code/core/Mage/Adminhtml/Block/Report/Tag/Popular.php b/app/code/core/Mage/Tag/Block/Adminhtml/Report/Popular.php
similarity index 84%
rename from app/code/core/Mage/Adminhtml/Block/Report/Tag/Popular.php
rename to app/code/core/Mage/Tag/Block/Adminhtml/Report/Popular.php
index f6427c30aa0..2537e206e88 100644
--- a/app/code/core/Mage/Adminhtml/Block/Report/Tag/Popular.php
+++ b/app/code/core/Mage/Tag/Block/Adminhtml/Report/Popular.php
@@ -19,7 +19,7 @@
  * needs please refer to http://www.magentocommerce.com for more information.
  *
  * @category    Mage
- * @package     Mage_Adminhtml
+ * @package     Mage_Tag
  * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
  * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
  */
@@ -28,16 +28,16 @@
  * Adminhtml popular tags report blocks content block
  *
  * @category   Mage
- * @package    Mage_Adminhtml
- * @author      Magento Core Team <core@magentocommerce.com>
+ * @package    Mage_Tag
+ * @author     Magento Core Team <core@magentocommerce.com>
  */
-class Mage_Adminhtml_Block_Report_Tag_Popular extends Mage_Adminhtml_Block_Widget_Grid_Container
+class Mage_Tag_Block_Adminhtml_Report_Popular extends Mage_Adminhtml_Block_Widget_Grid_Container
 {
-
     public function __construct()
     {
-        $this->_controller = 'report_tag_popular';
-        $this->_headerText = Mage::helper('Mage_Reports_Helper_Data')->__('Popular Tags');
+        $this->_blockGroup = 'Mage_Tag';
+        $this->_controller = 'adminhtml_report_popular';
+        $this->_headerText = Mage::helper('Mage_Tag_Helper_Data')->__('Popular Tags');
         parent::__construct();
         $this->_removeButton('add');
     }
diff --git a/app/code/core/Mage/Adminhtml/Block/Report/Tag/Popular/Detail.php b/app/code/core/Mage/Tag/Block/Adminhtml/Report/Popular/Detail.php
similarity index 77%
rename from app/code/core/Mage/Adminhtml/Block/Report/Tag/Popular/Detail.php
rename to app/code/core/Mage/Tag/Block/Adminhtml/Report/Popular/Detail.php
index 9932ee540e6..64ee46509d8 100644
--- a/app/code/core/Mage/Adminhtml/Block/Report/Tag/Popular/Detail.php
+++ b/app/code/core/Mage/Tag/Block/Adminhtml/Report/Popular/Detail.php
@@ -19,7 +19,7 @@
  * needs please refer to http://www.magentocommerce.com for more information.
  *
  * @category    Mage
- * @package     Mage_Adminhtml
+ * @package     Mage_Tag
  * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
  * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
  */
@@ -28,24 +28,22 @@
  * Adminhtml tag detail report blocks content block
  *
  * @category   Mage
- * @package    Mage_Adminhtml
- * @author      Magento Core Team <core@magentocommerce.com>
+ * @package    Mage_Tag
+ * @author     Magento Core Team <core@magentocommerce.com>
  */
-
-class Mage_Adminhtml_Block_Report_Tag_Popular_Detail extends Mage_Adminhtml_Block_Widget_Grid_Container
+class Mage_Tag_Block_Adminhtml_Report_Popular_Detail extends Mage_Adminhtml_Block_Widget_Grid_Container
 {
-
     public function __construct()
     {
-        $this->_controller = 'report_tag_popular_detail';
+        $this->_blockGroup = 'Mage_Tag';
+        $this->_controller = 'adminhtml_report_popular_detail';
 
         $tag = Mage::getModel('Mage_Tag_Model_Tag')->load($this->getRequest()->getParam('id'));
 
-        $this->_headerText = Mage::helper('Mage_Reports_Helper_Data')->__('Tag "%s" details', $this->escapeHtml($tag->getName()));
+        $this->_headerText = Mage::helper('Mage_Tag_Helper_Data')->__('Tag "%s" details', $this->escapeHtml($tag->getName()));
         parent::__construct();
         $this->_removeButton('add');
         $this->setBackUrl($this->getUrl('*/report_tag/popular/'));
         $this->_addBackButton();
     }
-
 }
diff --git a/app/code/core/Mage/Adminhtml/Block/Report/Tag/Popular/Detail/Grid.php b/app/code/core/Mage/Tag/Block/Adminhtml/Report/Popular/Detail/Grid.php
similarity index 72%
rename from app/code/core/Mage/Adminhtml/Block/Report/Tag/Popular/Detail/Grid.php
rename to app/code/core/Mage/Tag/Block/Adminhtml/Report/Popular/Detail/Grid.php
index 13aca61a7d0..7c04286cf8d 100644
--- a/app/code/core/Mage/Adminhtml/Block/Report/Tag/Popular/Detail/Grid.php
+++ b/app/code/core/Mage/Tag/Block/Adminhtml/Report/Popular/Detail/Grid.php
@@ -19,7 +19,7 @@
  * needs please refer to http://www.magentocommerce.com for more information.
  *
  * @category    Mage
- * @package     Mage_Adminhtml
+ * @package     Mage_Tag
  * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
  * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
  */
@@ -28,12 +28,11 @@
  * Adminhtml tags detail for product report grid block
  *
  * @category   Mage
- * @package    Mage_Adminhtml
- * @author      Magento Core Team <core@magentocommerce.com>
+ * @package    Mage_Tag
+ * @author     Magento Core Team <core@magentocommerce.com>
  */
-class Mage_Adminhtml_Block_Report_Tag_Popular_Detail_Grid extends Mage_Adminhtml_Block_Widget_Grid
+class Mage_Tag_Block_Adminhtml_Report_Popular_Detail_Grid extends Mage_Adminhtml_Block_Widget_Grid
 {
-
     public function __construct()
     {
         parent::__construct();
@@ -43,12 +42,12 @@ class Mage_Adminhtml_Block_Report_Tag_Popular_Detail_Grid extends Mage_Adminhtml
     /**
      * Prepare collection for grid
      *
-     * @return Mage_Adminhtml_Block_Report_Tag_Popular_Detail_Grid
+     * @return Mage_Tag_Block_Adminhtml_Report_Popular_Detail_Grid
      */
     protected function _prepareCollection()
     {
-        /* @var $collection Mage_Reports_Model_Resource_Tag_Customer_Collection */
-        $collection = Mage::getResourceModel('Mage_Reports_Model_Resource_Tag_Customer_Collection');
+        /* @var $collection Mage_Tag_Model_Resource_Reports_Customer_Collection */
+        $collection = Mage::getResourceModel('Mage_Tag_Model_Resource_Reports_Customer_Collection');
         $collection->addStatusFilter(Mage::getModel('Mage_Tag_Model_Tag')->getApprovedStatus())
             ->addTagFilter($this->getRequest()->getParam('id'))
             ->addProductToSelect();
@@ -61,29 +60,29 @@ class Mage_Adminhtml_Block_Report_Tag_Popular_Detail_Grid extends Mage_Adminhtml
     /**
      * Form columns for the grid
      *
-     * @return Mage_Adminhtml_Block_Report_Tag_Popular_Detail_Grid
+     * @return Mage_Tag_Block_Adminhtml_Report_Popular_Detail_Grid
      */
     protected function _prepareColumns()
     {
 
         $this->addColumn('firstname', array(
-            'header'    =>Mage::helper('Mage_Reports_Helper_Data')->__('First Name'),
+            'header'    =>Mage::helper('Mage_Tag_Helper_Data')->__('First Name'),
             'index'     =>'firstname'
         ));
 
         $this->addColumn('lastname', array(
-            'header'    =>Mage::helper('Mage_Reports_Helper_Data')->__('Last Name'),
+            'header'    =>Mage::helper('Mage_Tag_Helper_Data')->__('Last Name'),
             'index'     =>'lastname'
         ));
 
         $this->addColumn('product', array(
-            'header'    =>Mage::helper('Mage_Reports_Helper_Data')->__('Product Name'),
+            'header'    =>Mage::helper('Mage_Tag_Helper_Data')->__('Product Name'),
             'index'     =>'product_name'
         ));
 
         if (!Mage::app()->isSingleStoreMode()) {
             $this->addColumn('added_in', array(
-                'header'    => Mage::helper('Mage_Reports_Helper_Data')->__('Submitted In'),
+                'header'    => Mage::helper('Mage_Tag_Helper_Data')->__('Submitted In'),
                 'index'     => 'added_in',
                 'type'      => 'store',
                 'store_view'=> true
@@ -92,8 +91,8 @@ class Mage_Adminhtml_Block_Report_Tag_Popular_Detail_Grid extends Mage_Adminhtml
 
         $this->setFilterVisibility(false);
 
-        $this->addExportType('*/*/exportTagDetailCsv', Mage::helper('Mage_Reports_Helper_Data')->__('CSV'));
-        $this->addExportType('*/*/exportTagDetailExcel', Mage::helper('Mage_Reports_Helper_Data')->__('Excel XML'));
+        $this->addExportType('*/*/exportTagDetailCsv', Mage::helper('Mage_Tag_Helper_Data')->__('CSV'));
+        $this->addExportType('*/*/exportTagDetailExcel', Mage::helper('Mage_Tag_Helper_Data')->__('Excel XML'));
 
         return parent::_prepareColumns();
     }
diff --git a/app/code/core/Mage/Adminhtml/Block/Report/Tag/Popular/Grid.php b/app/code/core/Mage/Tag/Block/Adminhtml/Report/Popular/Grid.php
similarity index 81%
rename from app/code/core/Mage/Adminhtml/Block/Report/Tag/Popular/Grid.php
rename to app/code/core/Mage/Tag/Block/Adminhtml/Report/Popular/Grid.php
index 86e9fda9d1f..310592f6e96 100644
--- a/app/code/core/Mage/Adminhtml/Block/Report/Tag/Popular/Grid.php
+++ b/app/code/core/Mage/Tag/Block/Adminhtml/Report/Popular/Grid.php
@@ -19,7 +19,7 @@
  * needs please refer to http://www.magentocommerce.com for more information.
  *
  * @category    Mage
- * @package     Mage_Adminhtml
+ * @package     Mage_Tag
  * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
  * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
  */
@@ -28,12 +28,11 @@
  * Adminhtml popular tags report grid block
  *
  * @category   Mage
- * @package    Mage_Adminhtml
- * @author      Magento Core Team <core@magentocommerce.com>
+ * @package    Mage_Tag
+ * @author     Magento Core Team <core@magentocommerce.com>
  */
-class Mage_Adminhtml_Block_Report_Tag_Popular_Grid extends Mage_Adminhtml_Block_Widget_Grid
+class Mage_Tag_Block_Adminhtml_Report_Popular_Grid extends Mage_Adminhtml_Block_Widget_Grid
 {
-
     public function __construct()
     {
         parent::__construct();
@@ -53,7 +52,7 @@ class Mage_Adminhtml_Block_Report_Tag_Popular_Grid extends Mage_Adminhtml_Block_
             $storeId = '';
         }
 
-        $collection = Mage::getResourceModel('Mage_Reports_Model_Resource_Tag_Collection')
+        $collection = Mage::getResourceModel('Mage_Tag_Model_Resource_Reports_Collection')
             ->addPopularity($storeId)
             ->addStatusFilter(Mage_Tag_Model_Tag::STATUS_APPROVED);
 
@@ -64,12 +63,12 @@ class Mage_Adminhtml_Block_Report_Tag_Popular_Grid extends Mage_Adminhtml_Block_
     protected function _prepareColumns()
     {
         $this->addColumn('name', array(
-            'header'    =>Mage::helper('Mage_Reports_Helper_Data')->__('Tag Name'),
+            'header'    =>Mage::helper('Mage_Tag_Helper_Data')->__('Tag Name'),
             'index'     =>'name'
         ));
 
         $this->addColumn('taged', array(
-            'header'    =>Mage::helper('Mage_Reports_Helper_Data')->__('Popularity'),
+            'header'    =>Mage::helper('Mage_Tag_Helper_Data')->__('Popularity'),
             'width'     =>'50px',
             'align'     =>'right',
             'index'     =>'popularity'
@@ -77,13 +76,13 @@ class Mage_Adminhtml_Block_Report_Tag_Popular_Grid extends Mage_Adminhtml_Block_
 
         $this->addColumn('action',
             array(
-                'header'    => Mage::helper('Mage_Catalog_Helper_Data')->__('Action'),
+                'header'    => Mage::helper('Mage_Tag_Helper_Data')->__('Action'),
                 'width'     => '100%',
                 'type'      => 'action',
                 'getter'    => 'getId',
                 'actions'   => array(
                     array(
-                        'caption' => Mage::helper('Mage_Catalog_Helper_Data')->__('Show Details'),
+                        'caption' => Mage::helper('Mage_Tag_Helper_Data')->__('Show Details'),
                         'url'     => array(
                             'base'=>'*/*/tagDetail'
                         ),
@@ -97,8 +96,8 @@ class Mage_Adminhtml_Block_Report_Tag_Popular_Grid extends Mage_Adminhtml_Block_
         ));
         $this->setFilterVisibility(false);
 
-        $this->addExportType('*/*/exportPopularCsv', Mage::helper('Mage_Reports_Helper_Data')->__('CSV'));
-        $this->addExportType('*/*/exportPopularExcel', Mage::helper('Mage_Reports_Helper_Data')->__('Excel XML'));
+        $this->addExportType('*/*/exportPopularCsv', Mage::helper('Mage_Tag_Helper_Data')->__('CSV'));
+        $this->addExportType('*/*/exportPopularExcel', Mage::helper('Mage_Tag_Helper_Data')->__('Excel XML'));
 
         return parent::_prepareColumns();
     }
@@ -107,5 +106,4 @@ class Mage_Adminhtml_Block_Report_Tag_Popular_Grid extends Mage_Adminhtml_Block_
     {
         return $this->getUrl('*/*/tagDetail', array('id'=>$row->getTagId()));
     }
-
 }
diff --git a/app/code/core/Mage/Adminhtml/Block/Report/Tag/Product.php b/app/code/core/Mage/Tag/Block/Adminhtml/Report/Product.php
similarity index 76%
rename from app/code/core/Mage/Adminhtml/Block/Report/Tag/Product.php
rename to app/code/core/Mage/Tag/Block/Adminhtml/Report/Product.php
index 2bb3f0f50d1..79d4288f8f9 100644
--- a/app/code/core/Mage/Adminhtml/Block/Report/Tag/Product.php
+++ b/app/code/core/Mage/Tag/Block/Adminhtml/Report/Product.php
@@ -19,7 +19,7 @@
  * needs please refer to http://www.magentocommerce.com for more information.
  *
  * @category    Mage
- * @package     Mage_Adminhtml
+ * @package     Mage_Tag
  * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
  * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
  */
@@ -28,16 +28,16 @@
  * Adminhtml tag report product blocks content block
  *
  * @category   Mage
- * @package    Mage_Adminhtml
- * @author      Magento Core Team <core@magentocommerce.com>
+ * @package    Mage_Tag
+ * @author     Magento Core Team <core@magentocommerce.com>
  */
-class Mage_Adminhtml_Block_Report_Tag_Product extends Mage_Adminhtml_Block_Widget_Grid_Container
+class Mage_Tag_Block_Adminhtml_Report_Product extends Mage_Adminhtml_Block_Widget_Grid_Container
 {
-
     public function __construct()
     {
-        $this->_controller = 'report_tag_product';
-        $this->_headerText = Mage::helper('Mage_Reports_Helper_Data')->__('Products Tags');
+        $this->_blockGroup = 'Mage_Tag';
+        $this->_controller = 'adminhtml_report_product';
+        $this->_headerText = Mage::helper('Mage_Tag_Helper_Data')->__('Products Tags');
         parent::__construct();
         $this->_removeButton('add');
     }
diff --git a/app/code/core/Mage/Adminhtml/Block/Report/Tag/Product/Detail.php b/app/code/core/Mage/Tag/Block/Adminhtml/Report/Product/Detail.php
similarity index 78%
rename from app/code/core/Mage/Adminhtml/Block/Report/Tag/Product/Detail.php
rename to app/code/core/Mage/Tag/Block/Adminhtml/Report/Product/Detail.php
index cddb0869fa2..53f73701e16 100644
--- a/app/code/core/Mage/Adminhtml/Block/Report/Tag/Product/Detail.php
+++ b/app/code/core/Mage/Tag/Block/Adminhtml/Report/Product/Detail.php
@@ -19,7 +19,7 @@
  * needs please refer to http://www.magentocommerce.com for more information.
  *
  * @category    Mage
- * @package     Mage_Adminhtml
+ * @package     Mage_Tag
  * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
  * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
  */
@@ -28,20 +28,20 @@
  * Adminhtml tags detail for product report blocks content block
  *
  * @category   Mage
- * @package    Mage_Adminhtml
- * @author      Magento Core Team <core@magentocommerce.com>
+ * @package    Mage_Tag
+ * @author     Magento Core Team <core@magentocommerce.com>
  */
 
-class Mage_Adminhtml_Block_Report_Tag_Product_Detail extends Mage_Adminhtml_Block_Widget_Grid_Container
+class Mage_Tag_Block_Adminhtml_Report_Product_Detail extends Mage_Adminhtml_Block_Widget_Grid_Container
 {
-
     public function __construct()
     {
-        $this->_controller = 'report_tag_product_detail';
+        $this->_blockGroup = 'Mage_Tag';
+        $this->_controller = 'adminhtml_report_product_detail';
 
         $product = Mage::getModel('Mage_Catalog_Model_Product')->load($this->getRequest()->getParam('id'));
 
-        $this->_headerText = Mage::helper('Mage_Reports_Helper_Data')->__('Tags submitted to %s', $product->getName());
+        $this->_headerText = Mage::helper('Mage_Tag_Helper_Data')->__('Tags submitted to %s', $product->getName());
         parent::__construct();
         $this->_removeButton('add');
         $this->setBackUrl($this->getUrl('*/report_tag/product/'));
diff --git a/app/code/core/Mage/Adminhtml/Block/Report/Tag/Product/Detail/Grid.php b/app/code/core/Mage/Tag/Block/Adminhtml/Report/Product/Detail/Grid.php
similarity index 77%
rename from app/code/core/Mage/Adminhtml/Block/Report/Tag/Product/Detail/Grid.php
rename to app/code/core/Mage/Tag/Block/Adminhtml/Report/Product/Detail/Grid.php
index ada2d099824..82ab201fb8d 100644
--- a/app/code/core/Mage/Adminhtml/Block/Report/Tag/Product/Detail/Grid.php
+++ b/app/code/core/Mage/Tag/Block/Adminhtml/Report/Product/Detail/Grid.php
@@ -19,7 +19,7 @@
  * needs please refer to http://www.magentocommerce.com for more information.
  *
  * @category    Mage
- * @package     Mage_Adminhtml
+ * @package     Mage_Tag
  * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
  * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
  */
@@ -28,12 +28,11 @@
  * Adminhtml tags detail for product report grid block
  *
  * @category   Mage
- * @package    Mage_Adminhtml
- * @author      Magento Core Team <core@magentocommerce.com>
+ * @package    Mage_Tag
+ * @author     Magento Core Team <core@magentocommerce.com>
  */
-class Mage_Adminhtml_Block_Report_Tag_Product_Detail_Grid extends Mage_Adminhtml_Block_Widget_Grid
+class Mage_Tag_Block_Adminhtml_Report_Product_Detail_Grid extends Mage_Adminhtml_Block_Widget_Grid
 {
-
     public function __construct()
     {
         parent::__construct();
@@ -42,8 +41,8 @@ class Mage_Adminhtml_Block_Report_Tag_Product_Detail_Grid extends Mage_Adminhtml
 
     protected function _prepareCollection()
     {
-
-        $collection = Mage::getResourceModel('Mage_Reports_Model_Resource_Tag_Product_Collection');
+        /** @var $collection Mage_Tag_Model_Resource_Reports_Product_Collection */
+        $collection = Mage::getResourceModel('Mage_Tag_Model_Resource_Reports_Product_Collection');
 
         $collection->addTagedCount()
             ->addProductFilter($this->getRequest()->getParam('id'))
@@ -61,19 +60,19 @@ class Mage_Adminhtml_Block_Report_Tag_Product_Detail_Grid extends Mage_Adminhtml
     {
 
         $this->addColumn('tag_name', array(
-            'header'    =>Mage::helper('Mage_Reports_Helper_Data')->__('Tag Name'),
+            'header'    =>Mage::helper('Mage_Tag_Helper_Data')->__('Tag Name'),
             'index'     =>'tag_name'
         ));
 
         $this->addColumn('taged', array(
-            'header'    =>Mage::helper('Mage_Reports_Helper_Data')->__('Tag Use'),
+            'header'    =>Mage::helper('Mage_Tag_Helper_Data')->__('Tag Use'),
             'index'     =>'taged',
             'align'     => 'right'
         ));
 
         if (!Mage::app()->isSingleStoreMode()) {
             $this->addColumn('visible', array(
-                'header'    => Mage::helper('Mage_Reports_Helper_Data')->__('Visible In'),
+                'header'    => Mage::helper('Mage_Tag_Helper_Data')->__('Visible In'),
                 'sortable'  => false,
                 'index'     => 'stores',
                 'type'      => 'store',
@@ -81,8 +80,8 @@ class Mage_Adminhtml_Block_Report_Tag_Product_Detail_Grid extends Mage_Adminhtml
             ));
         }
 
-        $this->addExportType('*/*/exportProductDetailCsv', Mage::helper('Mage_Reports_Helper_Data')->__('CSV'));
-        $this->addExportType('*/*/exportProductDetailExcel', Mage::helper('Mage_Reports_Helper_Data')->__('Excel XML'));
+        $this->addExportType('*/*/exportProductDetailCsv', Mage::helper('Mage_Tag_Helper_Data')->__('CSV'));
+        $this->addExportType('*/*/exportProductDetailExcel', Mage::helper('Mage_Tag_Helper_Data')->__('Excel XML'));
 
         $this->setFilterVisibility(false);
 
diff --git a/app/code/core/Mage/Adminhtml/Block/Report/Tag/Product/Grid.php b/app/code/core/Mage/Tag/Block/Adminhtml/Report/Product/Grid.php
similarity index 76%
rename from app/code/core/Mage/Adminhtml/Block/Report/Tag/Product/Grid.php
rename to app/code/core/Mage/Tag/Block/Adminhtml/Report/Product/Grid.php
index 857ad36fb74..ed20fada9e0 100644
--- a/app/code/core/Mage/Adminhtml/Block/Report/Tag/Product/Grid.php
+++ b/app/code/core/Mage/Tag/Block/Adminhtml/Report/Product/Grid.php
@@ -19,7 +19,7 @@
  * needs please refer to http://www.magentocommerce.com for more information.
  *
  * @category    Mage
- * @package     Mage_Adminhtml
+ * @package     Mage_Tag
  * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
  * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
  */
@@ -28,12 +28,11 @@
  * Adminhtml tags by products report grid block
  *
  * @category   Mage
- * @package    Mage_Adminhtml
- * @author      Magento Core Team <core@magentocommerce.com>
+ * @package    Mage_Tag
+ * @author     Magento Core Team <core@magentocommerce.com>
  */
-class Mage_Adminhtml_Block_Report_Tag_Product_Grid extends Mage_Adminhtml_Block_Widget_Grid
+class Mage_Tag_Block_Adminhtml_Report_Product_Grid extends Mage_Adminhtml_Block_Widget_Grid
 {
-
     public function __construct()
     {
         parent::__construct();
@@ -42,8 +41,8 @@ class Mage_Adminhtml_Block_Report_Tag_Product_Grid extends Mage_Adminhtml_Block_
 
     protected function _prepareCollection()
     {
-
-        $collection = Mage::getResourceModel('Mage_Reports_Model_Resource_Tag_Product_Collection');
+        /** @var $collection Mage_Tag_Model_Resource_Reports_Product_Collection */
+        $collection = Mage::getResourceModel('Mage_Tag_Model_Resource_Reports_Product_Collection');
 
         $collection->addUniqueTagedCount()
             ->addAllTagedCount()
@@ -58,26 +57,26 @@ class Mage_Adminhtml_Block_Report_Tag_Product_Grid extends Mage_Adminhtml_Block_
     {
 
         $this->addColumn('entity_id', array(
-            'header'    =>Mage::helper('Mage_Reports_Helper_Data')->__('ID'),
+            'header'    =>Mage::helper('Mage_Tag_Helper_Data')->__('ID'),
             'width'     =>'50px',
             'align'     =>'right',
             'index'     =>'entity_id'
         ));
 
         $this->addColumn('name', array(
-            'header'    =>Mage::helper('Mage_Reports_Helper_Data')->__('Product Name'),
+            'header'    =>Mage::helper('Mage_Tag_Helper_Data')->__('Product Name'),
             'index'     =>'name'
         ));
 
         $this->addColumn('utaged', array(
-            'header'    =>Mage::helper('Mage_Reports_Helper_Data')->__('Number of Unique Tags'),
+            'header'    =>Mage::helper('Mage_Tag_Helper_Data')->__('Number of Unique Tags'),
             'width'     =>'50px',
             'align'     =>'right',
             'index'     =>'utaged'
         ));
 
         $this->addColumn('taged', array(
-            'header'    =>Mage::helper('Mage_Reports_Helper_Data')->__('Number of Total Tags'),
+            'header'    =>Mage::helper('Mage_Tag_Helper_Data')->__('Number of Total Tags'),
             'width'     =>'50px',
             'align'     =>'right',
             'index'     =>'taged'
@@ -85,13 +84,13 @@ class Mage_Adminhtml_Block_Report_Tag_Product_Grid extends Mage_Adminhtml_Block_
 
         $this->addColumn('action',
             array(
-                'header'    => Mage::helper('Mage_Catalog_Helper_Data')->__('Action'),
+                'header'    => Mage::helper('Mage_Tag_Helper_Data')->__('Action'),
                 'width'     => '100%',
                 'type'      => 'action',
                 'getter'    => 'getId',
                 'actions'   => array(
                     array(
-                        'caption' => Mage::helper('Mage_Catalog_Helper_Data')->__('Show Tags'),
+                        'caption' => Mage::helper('Mage_Tag_Helper_Data')->__('Show Tags'),
                         'url'     => array(
                             'base'=>'*/*/productDetail'
                         ),
@@ -106,8 +105,8 @@ class Mage_Adminhtml_Block_Report_Tag_Product_Grid extends Mage_Adminhtml_Block_
 
         $this->setFilterVisibility(false);
 
-        $this->addExportType('*/*/exportProductCsv', Mage::helper('Mage_Reports_Helper_Data')->__('CSV'));
-        $this->addExportType('*/*/exportProductExcel', Mage::helper('Mage_Reports_Helper_Data')->__('Excel XML'));
+        $this->addExportType('*/*/exportProductCsv', Mage::helper('Mage_Tag_Helper_Data')->__('CSV'));
+        $this->addExportType('*/*/exportProductExcel', Mage::helper('Mage_Tag_Helper_Data')->__('Excel XML'));
 
         return parent::_prepareColumns();
     }
diff --git a/app/code/core/Mage/Adminhtml/Block/Tag/Store/Switcher.php b/app/code/core/Mage/Tag/Block/Adminhtml/Store/Switcher.php
similarity index 91%
rename from app/code/core/Mage/Adminhtml/Block/Tag/Store/Switcher.php
rename to app/code/core/Mage/Tag/Block/Adminhtml/Store/Switcher.php
index 975c049c384..6efc1dfc79f 100644
--- a/app/code/core/Mage/Adminhtml/Block/Tag/Store/Switcher.php
+++ b/app/code/core/Mage/Tag/Block/Adminhtml/Store/Switcher.php
@@ -19,7 +19,7 @@
  * needs please refer to http://www.magentocommerce.com for more information.
  *
  * @category    Mage
- * @package     Mage_Adminhtml
+ * @package     Mage_Tag
  * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
  * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
  */
@@ -28,10 +28,10 @@
  * Adminhtml Tag Store Switcher
  *
  * @category   Mage
- * @package    Mage_Adminhtml
+ * @package    Mage_Tag
  * @author     Magento Core Team <core@magentocommerce.com>
  */
-class Mage_Adminhtml_Block_Tag_Store_Switcher extends Mage_Adminhtml_Block_Store_Switcher
+class Mage_Tag_Block_Adminhtml_Store_Switcher extends Mage_Adminhtml_Block_Store_Switcher
 {
     /**
      * @var bool
diff --git a/app/code/core/Mage/Adminhtml/Block/Tag/Tag.php b/app/code/core/Mage/Tag/Block/Adminhtml/Tag.php
similarity index 83%
rename from app/code/core/Mage/Adminhtml/Block/Tag/Tag.php
rename to app/code/core/Mage/Tag/Block/Adminhtml/Tag.php
index f174dce123b..a389ba7009e 100644
--- a/app/code/core/Mage/Adminhtml/Block/Tag/Tag.php
+++ b/app/code/core/Mage/Tag/Block/Adminhtml/Tag.php
@@ -19,7 +19,7 @@
  * needs please refer to http://www.magentocommerce.com for more information.
  *
  * @category    Mage
- * @package     Mage_Adminhtml
+ * @package     Mage_Tag
  * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
  * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
  */
@@ -28,16 +28,17 @@
  * Adminhtml all tags
  *
  * @category   Mage
- * @package    Mage_Adminhtml
- * @author      Magento Core Team <core@magentocommerce.com>
+ * @package    Mage_Tag
+ * @author     Magento Core Team <core@magentocommerce.com>
  */
 
-class Mage_Adminhtml_Block_Tag_Tag extends Mage_Adminhtml_Block_Widget_Grid_Container
+class Mage_Tag_Block_Adminhtml_Tag extends Mage_Adminhtml_Block_Widget_Grid_Container
 {
 
     public function __construct()
     {
-        $this->_controller = 'tag_tag';
+        $this->_blockGroup = 'Mage_Tag';
+        $this->_controller = 'adminhtml_tag';
         $this->_headerText = Mage::helper('Mage_Tag_Helper_Data')->__('Manage Tags');
         $this->_addButtonLabel = Mage::helper('Mage_Tag_Helper_Data')->__('Add New Tag');
         parent::__construct();
diff --git a/app/code/core/Mage/Adminhtml/Block/Tag/Tag/Grid.php b/app/code/core/Mage/Tag/Block/Adminhtml/Tag/Grid.php
similarity index 97%
rename from app/code/core/Mage/Adminhtml/Block/Tag/Tag/Grid.php
rename to app/code/core/Mage/Tag/Block/Adminhtml/Tag/Grid.php
index 16fed2f1482..ee9601717c9 100644
--- a/app/code/core/Mage/Adminhtml/Block/Tag/Tag/Grid.php
+++ b/app/code/core/Mage/Tag/Block/Adminhtml/Tag/Grid.php
@@ -19,7 +19,7 @@
  * needs please refer to http://www.magentocommerce.com for more information.
  *
  * @category    Mage
- * @package     Mage_Adminhtml
+ * @package     Mage_Tag
  * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
  * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
  */
@@ -28,10 +28,10 @@
  * Adminhtml all tags grid
  *
  * @category   Mage
- * @package    Mage_Adminhtml
+ * @package    Mage_Tag
  * @author     Magento Core Team <core@magentocommerce.com>
  */
-class Mage_Adminhtml_Block_Tag_Tag_Grid extends Mage_Adminhtml_Block_Widget_Grid
+class Mage_Tag_Block_Adminhtml_Tag_Grid extends Mage_Adminhtml_Block_Widget_Grid
 {
     /**
      * Constructor
diff --git a/app/code/core/Mage/Rss/Block/Catalog/Tag.php b/app/code/core/Mage/Tag/Block/Catalog/Product/Rss.php
similarity index 90%
rename from app/code/core/Mage/Rss/Block/Catalog/Tag.php
rename to app/code/core/Mage/Tag/Block/Catalog/Product/Rss.php
index eb03d3a00c4..ee4af5a5fa6 100644
--- a/app/code/core/Mage/Rss/Block/Catalog/Tag.php
+++ b/app/code/core/Mage/Tag/Block/Catalog/Product/Rss.php
@@ -19,19 +19,19 @@
  * needs please refer to http://www.magentocommerce.com for more information.
  *
  * @category    Mage
- * @package     Mage_Rss
+ * @package     Mage_Tag
  * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
  * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
  */
 
 /**
- * Review form block
+ * Catalog product rss feed builder
  *
  * @category   Mage
- * @package    Mage_Rss
- * @author      Magento Core Team <core@magentocommerce.com>
+ * @package    Mage_Tag
+ * @author     Magento Core Team <core@magentocommerce.com>
  */
-class Mage_Rss_Block_Catalog_Tag extends Mage_Rss_Block_Catalog_Abstract
+class Mage_Tag_Block_Catalog_Product_Rss extends Mage_Rss_Block_Catalog_Abstract
 {
     protected function _construct()
     {
@@ -51,7 +51,7 @@ class Mage_Rss_Block_Catalog_Tag extends Mage_Rss_Block_Catalog_Abstract
         $storeId = $this->_getStoreId();
         $tagModel = Mage::registry('tag_model');
         $newurl = Mage::getUrl('rss/catalog/tag/tagName/' . $tagModel->getName());
-        $title = Mage::helper('Mage_Rss_Helper_Data')->__('Products tagged with %s', $tagModel->getName());
+        $title = Mage::helper('Mage_Tag_Helper_Data')->__('Products tagged with %s', $tagModel->getName());
         $lang = Mage::getStoreConfig('general/locale/code');
 
         $rssObj = Mage::getModel('Mage_Rss_Model_Rss');
@@ -67,7 +67,8 @@ class Mage_Rss_Block_Catalog_Tag extends Mage_Rss_Block_Catalog_Abstract
             ->addTagFilter($tagModel->getId())
             ->addStoreFilter($storeId);
 
-        $_collection->setVisibility(Mage::getSingleton('Mage_Catalog_Model_Product_Visibility')->getVisibleInCatalogIds());
+        $_collection->setVisibility(Mage::getSingleton('Mage_Catalog_Model_Product_Visibility')
+            ->getVisibleInCatalogIds());
 
         $product = Mage::getModel('Mage_Catalog_Model_Product');
 
@@ -108,7 +109,7 @@ class Mage_Rss_Block_Catalog_Tag extends Mage_Rss_Block_Catalog_Abstract
             . '<td  style="text-decoration:none;">'.$product->getDescription();
 
         if ($allowedPriceInRss) {
-            $description .= $this->getPriceHtml($product,true);
+            $description .= $this->getPriceHtml($product, true);
         }
 
         $description .='</td></tr></table>';
diff --git a/app/code/core/Mage/Tag/Block/Catalog/Product/Rss/Link.php b/app/code/core/Mage/Tag/Block/Catalog/Product/Rss/Link.php
new file mode 100644
index 00000000000..064d8824a45
--- /dev/null
+++ b/app/code/core/Mage/Tag/Block/Catalog/Product/Rss/Link.php
@@ -0,0 +1,114 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @category    Mage
+ * @package     Mage_Tag
+ * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+/**
+ * Catalog product rss link builder class
+ *
+ * @category   Mage
+ * @package    Mage_Tag
+ * @author     Magento Core Team <core@magentocommerce.com>
+ */
+
+class Mage_Tag_Block_Catalog_Product_Rss_Link extends Mage_Core_Block_Template
+{
+    /**
+     * Keep true in cases when rss feed enabled for tagged products
+     *
+     * @var bool
+     */
+    protected $_isRssEnabled;
+
+    /**
+     * Id of tag
+     *
+     * @var int
+     */
+    protected $_tagId;
+
+    /**
+     * @var Mage_Tag_Model_Tag
+     */
+    protected $_tagModel;
+
+    /**
+     * @var Mage_Core_Model_Url
+     */
+    protected $_coreUrlModel;
+
+    /**
+     * Constructor
+     *
+     * @param array $data
+     */
+    public function __construct(array $data = array())
+    {
+        parent::__construct($data);
+
+        if (isset($data['rss_catalog_tag_enabled'])) {
+            $this->_isRssEnabled = $data['rss_catalog_tag_enabled'];
+        } else {
+            $this->_isRssEnabled = Mage::getStoreConfig('rss/catalog/tag');
+        }
+
+        if (isset($data['tag_id'])) {
+            $this->_tagId = $data['tag_id'];
+        } else {
+            $this->_tagId = $this->getRequest()->getParam('tagId');
+        }
+
+        if (isset($data['tag_model'])) {
+            $this->_tagModel = $data['tag_model'];
+        } else {
+            $this->_tagModel = Mage::getModel('Mage_Tag_Model_Tag');
+        }
+
+        if (isset($data['core_url_model'])) {
+            $this->_coreUrlModel = $data['core_url_model'];
+        } else {
+            $this->_coreUrlModel = Mage::getModel('Mage_Core_Model_Url');
+        }
+    }
+
+    /**
+     * Retrieve link on product rss feed tagged with loaded tag
+     *
+     * @return bool|string
+     */
+    public function getLinkUrl()
+    {
+        if ($this->_isRssEnabled && $this->_tagId) {
+            /** @var $tagModel Mage_Tag_Model_Tag */
+            $this->_tagModel->load($this->_tagId);
+            if ($this->_tagModel && $this->_tagModel->getId()) {
+                return $this->_coreUrlModel->getUrl('rss/catalog/tag',
+                    array('tagName' => urlencode($this->_tagModel->getName()))
+                );
+            }
+        }
+
+        return false;
+    }
+}
diff --git a/app/code/core/Mage/Reports/Model/Resource/Tag/Collection.php b/app/code/core/Mage/Tag/Model/Resource/Reports/Collection.php
old mode 100755
new mode 100644
similarity index 90%
rename from app/code/core/Mage/Reports/Model/Resource/Tag/Collection.php
rename to app/code/core/Mage/Tag/Model/Resource/Reports/Collection.php
index 8a4952f0358..62d80e44635
--- a/app/code/core/Mage/Reports/Model/Resource/Tag/Collection.php
+++ b/app/code/core/Mage/Tag/Model/Resource/Reports/Collection.php
@@ -19,26 +19,25 @@
  * needs please refer to http://www.magentocommerce.com for more information.
  *
  * @category    Mage
- * @package     Mage_Reports
+ * @package     Mage_Tag
  * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
  * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
  */
 
-
 /**
  * Report Products Tags collection
  *
  * @category    Mage
- * @package     Mage_Reports
+ * @package     Mage_Tag
  * @author      Magento Core Team <core@magentocommerce.com>
  */
-class Mage_Reports_Model_Resource_Tag_Collection extends Mage_Tag_Model_Resource_Popular_Collection
+class Mage_Tag_Model_Resource_Reports_Collection extends Mage_Tag_Model_Resource_Popular_Collection
 {
     /**
      * Add tag popularity to select by specified store ids
      *
      * @param int|array $storeIds
-     * @return Mage_Reports_Model_Resource_Tag_Collection
+     * @return Mage_Tag_Model_Resource_Reports_Collection
      */
     public function addPopularity($storeIds)
     {
@@ -61,4 +60,4 @@ class Mage_Reports_Model_Resource_Tag_Collection extends Mage_Tag_Model_Resource
 
         return $this;
     }
-}
\ No newline at end of file
+}
diff --git a/app/code/core/Mage/Reports/Model/Resource/Tag/Customer/Collection.php b/app/code/core/Mage/Tag/Model/Resource/Reports/Customer/Collection.php
old mode 100755
new mode 100644
similarity index 91%
rename from app/code/core/Mage/Reports/Model/Resource/Tag/Customer/Collection.php
rename to app/code/core/Mage/Tag/Model/Resource/Reports/Customer/Collection.php
index 9fbb7aed61c..9c5c39441ef
--- a/app/code/core/Mage/Reports/Model/Resource/Tag/Customer/Collection.php
+++ b/app/code/core/Mage/Tag/Model/Resource/Reports/Customer/Collection.php
@@ -19,20 +19,19 @@
  * needs please refer to http://www.magentocommerce.com for more information.
  *
  * @category    Mage
- * @package     Mage_Reports
+ * @package     Mage_Tag
  * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
  * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
  */
 
-
 /**
  * Report Customers Tags collection
  *
  * @category    Mage
- * @package     Mage_Reports
+ * @package     Mage_Tag
  * @author      Magento Core Team <core@magentocommerce.com>
  */
-class Mage_Reports_Model_Resource_Tag_Customer_Collection extends Mage_Tag_Model_Resource_Customer_Collection
+class Mage_Tag_Model_Resource_Reports_Customer_Collection extends Mage_Tag_Model_Resource_Customer_Collection
 {
     protected function _construct()
     {
@@ -42,7 +41,7 @@ class Mage_Reports_Model_Resource_Tag_Customer_Collection extends Mage_Tag_Model
     /**
      * Add target count
      *
-     * @return Mage_Reports_Model_Resource_Tag_Customer_Collection
+     * @return Mage_Tag_Model_Resource_Reports_Customer_Collection
      */
     public function addTagedCount()
     {
diff --git a/app/code/core/Mage/Reports/Model/Resource/Tag/Product/Collection.php b/app/code/core/Mage/Tag/Model/Resource/Reports/Product/Collection.php
old mode 100755
new mode 100644
similarity index 86%
rename from app/code/core/Mage/Reports/Model/Resource/Tag/Product/Collection.php
rename to app/code/core/Mage/Tag/Model/Resource/Reports/Product/Collection.php
index f9431bb6bc6..f504e1140cf
--- a/app/code/core/Mage/Reports/Model/Resource/Tag/Product/Collection.php
+++ b/app/code/core/Mage/Tag/Model/Resource/Reports/Product/Collection.php
@@ -19,20 +19,19 @@
  * needs please refer to http://www.magentocommerce.com for more information.
  *
  * @category    Mage
- * @package     Mage_Reports
+ * @package     Mage_Tag
  * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
  * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
  */
 
-
 /**
  * Report Products Tags collection
  *
  * @category    Mage
- * @package     Mage_Reports
+ * @package     Mage_Tag
  * @author      Magento Core Team <core@magentocommerce.com>
  */
-class Mage_Reports_Model_Resource_Tag_Product_Collection extends Mage_Tag_Model_Resource_Product_Collection
+class Mage_Tag_Model_Resource_Reports_Product_Collection extends Mage_Tag_Model_Resource_Product_Collection
 {
     protected function _construct()
     {
@@ -45,12 +44,12 @@ class Mage_Reports_Model_Resource_Tag_Product_Collection extends Mage_Tag_Model_
     /**
      * Add unique target count to result
      *
-     * @return Mage_Reports_Model_Resource_Tag_Product_Collection
+     * @return Mage_Tag_Model_Resource_Reports_Product_Collection
      */
     public function addUniqueTagedCount()
     {
         $select = clone $this->getSelect();
-        
+
         $select->reset()
             ->from(array('rel' => $this->getTable('tag_relation')), 'COUNT(DISTINCT rel.tag_id)')
             ->where('rel.product_id = e.entity_id');
@@ -63,7 +62,7 @@ class Mage_Reports_Model_Resource_Tag_Product_Collection extends Mage_Tag_Model_
     /**
      * Add all target count to result
      *
-     * @return Mage_Reports_Model_Resource_Tag_Product_Collection
+     * @return Mage_Tag_Model_Resource_Reports_Product_Collection
      */
     public function addAllTagedCount()
     {
@@ -75,7 +74,7 @@ class Mage_Reports_Model_Resource_Tag_Product_Collection extends Mage_Tag_Model_
     /**
      * Add target count to result
      *
-     * @return Mage_Reports_Model_Resource_Tag_Product_Collection
+     * @return Mage_Tag_Model_Resource_Reports_Product_Collection
      */
     public function addTagedCount()
     {
@@ -88,7 +87,7 @@ class Mage_Reports_Model_Resource_Tag_Product_Collection extends Mage_Tag_Model_
     /**
      * Add group by product to result
      *
-     * @return Mage_Reports_Model_Resource_Tag_Product_Collection
+     * @return Mage_Tag_Model_Resource_Reports_Product_Collection
      */
     public function addGroupByProduct()
     {
@@ -100,7 +99,7 @@ class Mage_Reports_Model_Resource_Tag_Product_Collection extends Mage_Tag_Model_
     /**
      * Add group by tag to result
      *
-     * @return Mage_Reports_Model_Resource_Tag_Product_Collection
+     * @return Mage_Tag_Model_Resource_Reports_Product_Collection
      */
     public function addGroupByTag()
     {
@@ -113,7 +112,7 @@ class Mage_Reports_Model_Resource_Tag_Product_Collection extends Mage_Tag_Model_
      * Add product filter
      *
      * @param int $customerId
-     * @return Mage_Reports_Model_Resource_Tag_Product_Collection
+     * @return Mage_Tag_Model_Resource_Reports_Product_Collection
      */
     public function addProductFilter($customerId)
     {
@@ -128,7 +127,7 @@ class Mage_Reports_Model_Resource_Tag_Product_Collection extends Mage_Tag_Model_
      *
      * @param string $attribute
      * @param string $dir
-     * @return Mage_Reports_Model_Resource_Tag_Product_Collection
+     * @return Mage_Tag_Model_Resource_Reports_Product_Collection
      */
     public function setOrder($attribute, $dir = self::SORT_ORDER_DESC)
     {
@@ -144,7 +143,7 @@ class Mage_Reports_Model_Resource_Tag_Product_Collection extends Mage_Tag_Model_
     /**
      * Join fields
      *
-     * @return Mage_Reports_Model_Resource_Tag_Product_Collection
+     * @return Mage_Tag_Model_Resource_Reports_Product_Collection
      */
     protected function _joinFields()
     {
diff --git a/app/code/core/Mage/Tag/controllers/Adminhtml/Catalog/ProductController.php b/app/code/core/Mage/Tag/controllers/Adminhtml/Catalog/ProductController.php
new file mode 100644
index 00000000000..e5cb2b78feb
--- /dev/null
+++ b/app/code/core/Mage/Tag/controllers/Adminhtml/Catalog/ProductController.php
@@ -0,0 +1,58 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @category    Mage
+ * @package     Mage_Tag
+ * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+/**
+ * Catalog product tag controller
+ *
+ * @category   Mage
+ * @package    Mage_Tag
+ * @author     Magento Core Team <core@magentocommerce.com>
+ */
+class Mage_Tag_Adminhtml_Catalog_ProductController extends Mage_Adminhtml_Controller_Action
+{
+    /**
+     * Get tag grid
+     */
+    public function tagGridAction()
+    {
+        $this->loadLayout();
+        $this->getLayout()->getBlock('admin.product.tags')
+            ->setProductId($this->getRequest()->getParam('id'));
+        $this->renderLayout();
+    }
+
+    /**
+     * Get tag customer grid
+     */
+    public function tagCustomerGridAction()
+    {
+        $this->loadLayout();
+        $this->getLayout()->getBlock('admin.product.tags.customers')
+            ->setProductId($this->getRequest()->getParam('id'));
+        $this->renderLayout();
+    }
+
+}
\ No newline at end of file
diff --git a/app/code/core/Mage/Tag/controllers/Adminhtml/CustomerController.php b/app/code/core/Mage/Tag/controllers/Adminhtml/CustomerController.php
new file mode 100644
index 00000000000..a3a45a4ac3b
--- /dev/null
+++ b/app/code/core/Mage/Tag/controllers/Adminhtml/CustomerController.php
@@ -0,0 +1,91 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @category    Mage
+ * @package     Mage_Tag
+ * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+/**
+ * Controller to process customer tag actions
+ *
+ * @category    Mage
+ * @package     Mage_Tag
+ * @author      Magento Core Team <core@magentocommerce.com>
+ */
+class Mage_Tag_Adminhtml_CustomerController extends Mage_Adminhtml_Controller_Action
+{
+    /**
+     * Adds to registry current customer instance
+     *
+     * @param string $idFieldName
+     * @return Mage_Tag_Adminhtml_CustomerController
+     */
+    protected function _initCustomer($idFieldName = 'id')
+    {
+        $this->_title($this->__('Customers'))->_title($this->__('Manage Customers'));
+
+        $customerId = (int) $this->getRequest()->getParam($idFieldName);
+        $customer   = Mage::getModel('Mage_Customer_Model_Customer');
+
+        if ($customerId) {
+            $customer->load($customerId);
+        }
+
+        Mage::register('current_customer', $customer);
+        return $this;
+    }
+
+    /**
+     * Processes ajax action to render tags tab content
+     */
+    public function productTagsAction()
+    {
+        $this->_initCustomer();
+
+        /** @var $customer Mage_Customer_Model_Customer */
+        $customer = Mage::registry('current_customer');
+        /** @var $block Mage_Tag_Block_Adminhtml_Customer_Edit_Tab_Tag_Grid */
+        $block = $this->loadLayout()
+            ->getLayout()
+            ->getBlock('admin.customer.tags');
+        $block->setCustomerId($customer->getId())
+            ->setUseAjax(true);
+
+        $this->renderLayout();
+    }
+
+    /**
+     * Processes tag grid actions
+     */
+    public function tagGridAction()
+    {
+        $this->_initCustomer();
+
+        /** @var $block Mage_Tag_Block_Adminhtml_Customer_Edit_Tab_Tag_Grid */
+        $block = $this->loadLayout()
+            ->getLayout()
+            ->getBlock('admin.customer.tags');
+        $block->setCustomerId(Mage::registry('current_customer'));
+
+        $this->renderLayout();
+    }
+}
diff --git a/app/code/core/Mage/Adminhtml/controllers/Report/TagController.php b/app/code/core/Mage/Tag/controllers/Adminhtml/Report/TagController.php
similarity index 61%
rename from app/code/core/Mage/Adminhtml/controllers/Report/TagController.php
rename to app/code/core/Mage/Tag/controllers/Adminhtml/Report/TagController.php
index 8df9311548a..b46e1bd9014 100644
--- a/app/code/core/Mage/Adminhtml/controllers/Report/TagController.php
+++ b/app/code/core/Mage/Tag/controllers/Adminhtml/Report/TagController.php
@@ -19,7 +19,7 @@
  * needs please refer to http://www.magentocommerce.com for more information.
  *
  * @category    Mage
- * @package     Mage_Adminhtml
+ * @package     Mage_Tag
  * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
  * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
  */
@@ -28,20 +28,23 @@
  * Tag report admin controller
  *
  * @category   Mage
- * @package    Mage_Adminhtml
- * @author      Magento Core Team <core@magentocommerce.com>
+ * @package    Mage_Tag
+ * @author     Magento Core Team <core@magentocommerce.com>
  */
-class Mage_Adminhtml_Report_TagController extends Mage_Adminhtml_Controller_Action
+class Mage_Tag_Adminhtml_Report_TagController extends Mage_Adminhtml_Controller_Action
 {
     public function _initAction()
     {
-        $act = $this->getRequest()->getActionName();
-        if(!$act)
-            $act = 'default';
-
         $this->loadLayout()
-            ->_addBreadcrumb(Mage::helper('Mage_Reports_Helper_Data')->__('Reports'), Mage::helper('Mage_Reports_Helper_Data')->__('Reports'))
-            ->_addBreadcrumb(Mage::helper('Mage_Reports_Helper_Data')->__('Tag'), Mage::helper('Mage_Reports_Helper_Data')->__('Tag'));
+            ->_addBreadcrumb(
+                Mage::helper('Mage_Tag_Helper_Data')->__('Reports'),
+                Mage::helper('Mage_Tag_Helper_Data')->__('Reports')
+            )
+            ->_addBreadcrumb(
+                Mage::helper('Mage_Tag_Helper_Data')->__('Tag'),
+                Mage::helper('Mage_Tag_Helper_Data')->__('Tag')
+            );
+
         return $this;
     }
 
@@ -53,8 +56,11 @@ class Mage_Adminhtml_Report_TagController extends Mage_Adminhtml_Controller_Acti
 
         $this->_initAction()
             ->_setActiveMenu('Mage_Tag::report_tags_customer')
-            ->_addBreadcrumb(Mage::helper('Mage_Reports_Helper_Data')->__('Customers Report'), Mage::helper('Mage_Reports_Helper_Data')->__('Customers Report'))
-            ->_addContent($this->getLayout()->createBlock('Mage_Adminhtml_Block_Report_Tag_Customer'))
+            ->_addBreadcrumb(
+                Mage::helper('Mage_Tag_Helper_Data')->__('Customers Report'),
+                Mage::helper('Mage_Tag_Helper_Data')->__('Customers Report')
+            )
+            ->_addContent($this->getLayout()->createBlock('Mage_Tag_Block_Adminhtml_Report_Customer'))
             ->renderLayout();
     }
 
@@ -64,7 +70,7 @@ class Mage_Adminhtml_Report_TagController extends Mage_Adminhtml_Controller_Acti
     public function exportCustomerCsvAction()
     {
         $fileName   = 'tag_customer.csv';
-        $content    = $this->getLayout()->createBlock('Mage_Adminhtml_Block_Report_Tag_Customer_Grid')
+        $content    = $this->getLayout()->createBlock('Mage_Tag_Block_Adminhtml_Report_Customer_Grid')
             ->getCsvFile();
 
         $this->_prepareDownloadResponse($fileName, $content);
@@ -76,7 +82,7 @@ class Mage_Adminhtml_Report_TagController extends Mage_Adminhtml_Controller_Acti
     public function exportCustomerExcelAction()
     {
         $fileName   = 'tag_customer.xml';
-        $content    = $this->getLayout()->createBlock('Mage_Adminhtml_Block_Report_Tag_Customer_Grid')
+        $content    = $this->getLayout()->createBlock('Mage_Tag_Block_Adminhtml_Report_Customer_Grid')
             ->getExcelFile($fileName);
 
         $this->_prepareDownloadResponse($fileName, $content);
@@ -90,8 +96,11 @@ class Mage_Adminhtml_Report_TagController extends Mage_Adminhtml_Controller_Acti
 
         $this->_initAction()
             ->_setActiveMenu('Mage_Tag::report_tags_product')
-            ->_addBreadcrumb(Mage::helper('Mage_Reports_Helper_Data')->__('Poducts Report'), Mage::helper('Mage_Reports_Helper_Data')->__('Products Report'))
-            ->_addContent($this->getLayout()->createBlock('Mage_Adminhtml_Block_Report_Tag_Product'))
+            ->_addBreadcrumb(
+                Mage::helper('Mage_Tag_Helper_Data')->__('Poducts Report'),
+                Mage::helper('Mage_Tag_Helper_Data')->__('Products Report')
+            )
+            ->_addContent($this->getLayout()->createBlock('Mage_Tag_Block_Adminhtml_Report_Product'))
             ->renderLayout();
     }
 
@@ -101,7 +110,7 @@ class Mage_Adminhtml_Report_TagController extends Mage_Adminhtml_Controller_Acti
     public function exportProductCsvAction()
     {
         $fileName   = 'tag_product.csv';
-        $content    = $this->getLayout()->createBlock('Mage_Adminhtml_Block_Report_Tag_Product_Grid')
+        $content    = $this->getLayout()->createBlock('Mage_Tag_Block_Adminhtml_Report_Product_Grid')
             ->getCsvFile();
 
         $this->_prepareDownloadResponse($fileName, $content);
@@ -113,13 +122,12 @@ class Mage_Adminhtml_Report_TagController extends Mage_Adminhtml_Controller_Acti
     public function exportProductExcelAction()
     {
         $fileName   = 'tag_product.xml';
-        $content    = $this->getLayout()->createBlock('Mage_Adminhtml_Block_Report_Tag_Product_Grid')
+        $content    = $this->getLayout()->createBlock('Mage_Tag_Block_Adminhtml_Report_Product_Grid')
             ->getExcelFile($fileName);
 
         $this->_prepareDownloadResponse($fileName, $content);
     }
 
-
     public function popularAction()
     {
         $this->_title($this->__('Reports'))
@@ -128,8 +136,11 @@ class Mage_Adminhtml_Report_TagController extends Mage_Adminhtml_Controller_Acti
 
         $this->_initAction()
             ->_setActiveMenu('Mage_Tag::report_tags_popular')
-            ->_addBreadcrumb(Mage::helper('Mage_Reports_Helper_Data')->__('Popular Tags'), Mage::helper('Mage_Reports_Helper_Data')->__('Popular Tags'))
-            ->_addContent($this->getLayout()->createBlock('Mage_Adminhtml_Block_Report_Tag_Popular'))
+            ->_addBreadcrumb(
+                Mage::helper('Mage_Tag_Helper_Data')->__('Popular Tags'),
+                Mage::helper('Mage_Tag_Helper_Data')->__('Popular Tags')
+            )
+            ->_addContent($this->getLayout()->createBlock('Mage_Tag_Block_Adminhtml_Report_Popular'))
             ->renderLayout();
     }
 
@@ -139,7 +150,7 @@ class Mage_Adminhtml_Report_TagController extends Mage_Adminhtml_Controller_Acti
     public function exportPopularCsvAction()
     {
         $fileName   = 'tag_popular.csv';
-        $content    = $this->getLayout()->createBlock('Mage_Adminhtml_Block_Report_Tag_Popular_Grid')
+        $content    = $this->getLayout()->createBlock('Mage_Tag_Block_Adminhtml_Report_Popular_Grid')
             ->getCsvFile();
 
         $this->_prepareDownloadResponse($fileName, $content);
@@ -151,7 +162,7 @@ class Mage_Adminhtml_Report_TagController extends Mage_Adminhtml_Controller_Acti
     public function exportPopularExcelAction()
     {
         $fileName   = 'tag_popular.xml';
-        $content    = $this->getLayout()->createBlock('Mage_Adminhtml_Block_Report_Tag_Popular_Grid')
+        $content    = $this->getLayout()->createBlock('Mage_Tag_Block_Adminhtml_Report_Popular_Grid')
             ->getExcelFile($fileName);
 
         $this->_prepareDownloadResponse($fileName, $content);
@@ -159,17 +170,25 @@ class Mage_Adminhtml_Report_TagController extends Mage_Adminhtml_Controller_Acti
 
     public function customerDetailAction()
     {
-        $detailBlock = $this->getLayout()->createBlock('Mage_Adminhtml_Block_Report_Tag_Customer_Detail');
+        $this->_initAction();
+
+        /** @var $detailBlock Mage_Tag_Block_Adminhtml_Report_Customer_Detail */
+        $detailBlock = $this->getLayout()->createBlock('Mage_Tag_Block_Adminhtml_Report_Customer_Detail');
 
         $this->_title($this->__('Reports'))
              ->_title($this->__('Tags'))
              ->_title($this->__('Customers'))
              ->_title($detailBlock->getHeaderText());
 
-        $this->_initAction()
-            ->_setActiveMenu('Mage_Tag::report_tags')
-            ->_addBreadcrumb(Mage::helper('Mage_Reports_Helper_Data')->__('Customers Report'), Mage::helper('Mage_Reports_Helper_Data')->__('Customers Report'))
-            ->_addBreadcrumb(Mage::helper('Mage_Reports_Helper_Data')->__('Customer Tags'), Mage::helper('Mage_Reports_Helper_Data')->__('Customer Tags'))
+        $this->_setActiveMenu('Mage_Tag::report_tags')
+            ->_addBreadcrumb(
+                Mage::helper('Mage_Tag_Helper_Data')->__('Customers Report'),
+                Mage::helper('Mage_Tag_Helper_Data')->__('Customers Report')
+            )
+            ->_addBreadcrumb(
+                Mage::helper('Mage_Tag_Helper_Data')->__('Customer Tags'),
+                Mage::helper('Mage_Tag_Helper_Data')->__('Customer Tags')
+            )
             ->_addContent($detailBlock)
             ->renderLayout();
     }
@@ -180,7 +199,7 @@ class Mage_Adminhtml_Report_TagController extends Mage_Adminhtml_Controller_Acti
     public function exportCustomerDetailCsvAction()
     {
         $fileName   = 'tag_customer_detail.csv';
-        $content    = $this->getLayout()->createBlock('Mage_Adminhtml_Block_Report_Tag_Customer_Detail_Grid')
+        $content    = $this->getLayout()->createBlock('Mage_Tag_Block_Adminhtml_Report_Customer_Detail_Grid')
             ->getCsvFile();
 
         $this->_prepareDownloadResponse($fileName, $content);
@@ -192,7 +211,7 @@ class Mage_Adminhtml_Report_TagController extends Mage_Adminhtml_Controller_Acti
     public function exportCustomerDetailExcelAction()
     {
         $fileName   = 'tag_customer_detail.xml';
-        $content    = $this->getLayout()->createBlock('Mage_Adminhtml_Block_Report_Tag_Customer_Detail_Grid')
+        $content    = $this->getLayout()->createBlock('Mage_Tag_Block_Adminhtml_Report_Customer_Detail_Grid')
             ->getExcelFile($fileName);
 
         $this->_prepareDownloadResponse($fileName, $content);
@@ -200,17 +219,25 @@ class Mage_Adminhtml_Report_TagController extends Mage_Adminhtml_Controller_Acti
 
     public function productDetailAction()
     {
-        $detailBlock = $this->getLayout()->createBlock('Mage_Adminhtml_Block_Report_Tag_Product_Detail');
+        $this->_initAction();
+
+        /** @var $detailBlock Mage_Tag_Block_Adminhtml_Report_Product_Detail */
+        $detailBlock = $this->getLayout()->createBlock('Mage_Tag_Block_Adminhtml_Report_Product_Detail');
 
         $this->_title($this->__('Reports'))
              ->_title($this->__('Tags'))
              ->_title($this->__('Products'))
              ->_title($detailBlock->getHeaderText());
 
-        $this->_initAction()
-            ->_setActiveMenu('Mage_Tag::report_tags')
-            ->_addBreadcrumb(Mage::helper('Mage_Reports_Helper_Data')->__('Products Report'), Mage::helper('Mage_Reports_Helper_Data')->__('Products Report'))
-            ->_addBreadcrumb(Mage::helper('Mage_Reports_Helper_Data')->__('Product Tags'), Mage::helper('Mage_Reports_Helper_Data')->__('Product Tags'))
+        $this->_setActiveMenu('Mage_Tag::report_tags')
+            ->_addBreadcrumb(
+                Mage::helper('Mage_Tag_Helper_Data')->__('Products Report'),
+                Mage::helper('Mage_Tag_Helper_Data')->__('Products Report')
+            )
+            ->_addBreadcrumb(
+                Mage::helper('Mage_Tag_Helper_Data')->__('Product Tags'),
+                Mage::helper('Mage_Tag_Helper_Data')->__('Product Tags')
+            )
             ->_addContent($detailBlock)
             ->renderLayout();
     }
@@ -221,7 +248,7 @@ class Mage_Adminhtml_Report_TagController extends Mage_Adminhtml_Controller_Acti
     public function exportProductDetailCsvAction()
     {
         $fileName   = 'tag_product_detail.csv';
-        $content    = $this->getLayout()->createBlock('Mage_Adminhtml_Block_Report_Tag_Product_Detail_Grid')
+        $content    = $this->getLayout()->createBlock('Mage_Tag_Block_Adminhtml_Report_Product_Detail_Grid')
             ->getCsvFile();
 
         $this->_prepareDownloadResponse($fileName, $content);
@@ -233,7 +260,7 @@ class Mage_Adminhtml_Report_TagController extends Mage_Adminhtml_Controller_Acti
     public function exportProductDetailExcelAction()
     {
         $fileName   = 'tag_product_detail.xml';
-        $content    = $this->getLayout()->createBlock('Mage_Adminhtml_Block_Report_Tag_Product_Detail_Grid')
+        $content    = $this->getLayout()->createBlock('Mage_Tag_Block_Adminhtml_Report_Product_Detail_Grid')
             ->getExcelFile($fileName);
 
         $this->_prepareDownloadResponse($fileName, $content);
@@ -241,17 +268,25 @@ class Mage_Adminhtml_Report_TagController extends Mage_Adminhtml_Controller_Acti
 
     public function tagDetailAction()
     {
-        $detailBlock = $this->getLayout()->createBlock('Mage_Adminhtml_Block_Report_Tag_Popular_Detail');
+        $this->_initAction();
+
+        /** @var $detailBlock Mage_Tag_Block_Adminhtml_Report_Popular_Detail */
+        $detailBlock = $this->getLayout()->createBlock('Mage_Tag_Block_Adminhtml_Report_Popular_Detail');
 
         $this->_title($this->__('Reports'))
              ->_title($this->__('Tags'))
              ->_title($this->__('Popular'))
              ->_title($detailBlock->getHeaderText());
 
-        $this->_initAction()
-            ->_setActiveMenu('Mage_Tag::report_tags')
-            ->_addBreadcrumb(Mage::helper('Mage_Reports_Helper_Data')->__('Popular Tags'), Mage::helper('Mage_Reports_Helper_Data')->__('Popular Tags'))
-            ->_addBreadcrumb(Mage::helper('Mage_Reports_Helper_Data')->__('Tag Detail'), Mage::helper('Mage_Reports_Helper_Data')->__('Tag Detail'))
+        $this->_setActiveMenu('Mage_Tag::report_tags')
+            ->_addBreadcrumb(
+                Mage::helper('Mage_Tag_Helper_Data')->__('Popular Tags'),
+                Mage::helper('Mage_Tag_Helper_Data')->__('Popular Tags')
+            )
+            ->_addBreadcrumb(
+                Mage::helper('Mage_Tag_Helper_Data')->__('Tag Detail'),
+                Mage::helper('Mage_Tag_Helper_Data')->__('Tag Detail')
+            )
             ->_addContent($detailBlock)
             ->renderLayout();
     }
@@ -262,7 +297,7 @@ class Mage_Adminhtml_Report_TagController extends Mage_Adminhtml_Controller_Acti
     public function exportTagDetailCsvAction()
     {
         $fileName   = 'tag_detail.csv';
-        $content    = $this->getLayout()->createBlock('Mage_Adminhtml_Block_Report_Tag_Popular_Detail_Grid')
+        $content    = $this->getLayout()->createBlock('Mage_Tag_Block_Adminhtml_Report_Popular_Detail_Grid')
             ->getCsvFile();
 
         $this->_prepareDownloadResponse($fileName, $content);
@@ -274,7 +309,7 @@ class Mage_Adminhtml_Report_TagController extends Mage_Adminhtml_Controller_Acti
     public function exportTagDetailExcelAction()
     {
         $fileName   = 'tag_detail.xml';
-        $content    = $this->getLayout()->createBlock('Mage_Adminhtml_Block_Report_Tag_Popular_Detail_Grid')
+        $content    = $this->getLayout()->createBlock('Mage_Tag_Block_Adminhtml_Report_Popular_Detail_Grid')
             ->getExcelFile($fileName);
 
         $this->_prepareDownloadResponse($fileName, $content);
diff --git a/app/code/core/Mage/Adminhtml/controllers/TagController.php b/app/code/core/Mage/Tag/controllers/Adminhtml/TagController.php
similarity index 82%
rename from app/code/core/Mage/Adminhtml/controllers/TagController.php
rename to app/code/core/Mage/Tag/controllers/Adminhtml/TagController.php
index 74a570d9ada..ca50f619d24 100644
--- a/app/code/core/Mage/Adminhtml/controllers/TagController.php
+++ b/app/code/core/Mage/Tag/controllers/Adminhtml/TagController.php
@@ -19,7 +19,7 @@
  * needs please refer to http://www.magentocommerce.com for more information.
  *
  * @category    Mage
- * @package     Mage_Adminhtml
+ * @package     Mage_Tag
  * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
  * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
  */
@@ -28,18 +28,22 @@
  * Product tags admin controller
  *
  * @category   Mage
- * @package    Mage_Adminhtml
- * @author      Magento Core Team <core@magentocommerce.com>
+ * @package    Mage_Tag
+ * @author     Magento Core Team <core@magentocommerce.com>
  */
-class Mage_Adminhtml_TagController extends Mage_Adminhtml_Controller_Action
+class Mage_Tag_Adminhtml_TagController extends Mage_Adminhtml_Controller_Action
 {
 
     protected function _initAction()
     {
         $this->loadLayout()
             ->_setActiveMenu('Mage_Tag::catalog_tag')
-            ->_addBreadcrumb(Mage::helper('Mage_Adminhtml_Helper_Data')->__('Catalog'), Mage::helper('Mage_Adminhtml_Helper_Data')->__('Catalog'))
-            ->_addBreadcrumb(Mage::helper('Mage_Adminhtml_Helper_Data')->__('Tags'), Mage::helper('Mage_Adminhtml_Helper_Data')->__('Tags'));
+            ->_addBreadcrumb(
+                Mage::helper('Mage_Tag_Helper_Data')->__('Catalog'), Mage::helper('Mage_Tag_Helper_Data')->__('Catalog')
+            )
+            ->_addBreadcrumb(
+                Mage::helper('Mage_Tag_Helper_Data')->__('Tags'), Mage::helper('Mage_Tag_Helper_Data')->__('Tags')
+            );
 
         return $this;
     }
@@ -80,7 +84,10 @@ class Mage_Adminhtml_TagController extends Mage_Adminhtml_Controller_Action
              ->_title($this->__('All Tags'));
 
         $this->_initAction()
-            ->_addBreadcrumb(Mage::helper('Mage_Adminhtml_Helper_Data')->__('All Tags'), Mage::helper('Mage_Adminhtml_Helper_Data')->__('All Tags'))
+            ->_addBreadcrumb(
+                Mage::helper('Mage_Tag_Helper_Data')->__('All Tags'),
+                Mage::helper('Mage_Tag_Helper_Data')->__('All Tags')
+            )
             ->_setActiveMenu('Mage_Tag::catalog_tag_all')
             ->renderLayout();
     }
@@ -124,11 +131,16 @@ class Mage_Adminhtml_TagController extends Mage_Adminhtml_Controller_Action
              ->_title($this->__('Tags'));
 
         if (! (int) $this->getRequest()->getParam('store')) {
-            return $this->_redirect('*/*/*/', array('store' => Mage::app()->getAnyStoreView()->getId(), '_current' => true));
+            return $this->_redirect(
+                '*/*/*/',
+                array('store' => Mage::app()->getAnyStoreView()->getId(), '_current' => true)
+            );
         }
 
         if (! ($model = $this->_initTag())) {
-            Mage::getSingleton('Mage_Adminhtml_Model_Session')->addError(Mage::helper('Mage_Adminhtml_Helper_Data')->__('Wrong tag was specified.'));
+            Mage::getSingleton('Mage_Adminhtml_Model_Session')->addError(
+                Mage::helper('Mage_Tag_Helper_Data')->__('Wrong tag was specified.')
+            );
             return $this->_redirect('*/*/index', array('store' => $this->getRequest()->getParam('store')));
         }
 
@@ -162,7 +174,9 @@ class Mage_Adminhtml_TagController extends Mage_Adminhtml_Controller_Action
             $data['store']              = $postData['store_id'];
 
             if (!$model = $this->_initTag()) {
-                Mage::getSingleton('Mage_Adminhtml_Model_Session')->addError(Mage::helper('Mage_Adminhtml_Helper_Data')->__('Wrong tag was specified.'));
+                Mage::getSingleton('Mage_Adminhtml_Model_Session')->addError(
+                    Mage::helper('Mage_Tag_Helper_Data')->__('Wrong tag was specified.')
+                );
                 return $this->_redirect('*/*/index', array('store' => $data['store']));
             }
 
@@ -179,11 +193,17 @@ class Mage_Adminhtml_TagController extends Mage_Adminhtml_Controller_Action
             try {
                 $model->save();
 
-                Mage::getSingleton('Mage_Adminhtml_Model_Session')->addSuccess(Mage::helper('Mage_Adminhtml_Helper_Data')->__('The tag has been saved.'));
+                Mage::getSingleton('Mage_Adminhtml_Model_Session')->addSuccess(
+                    Mage::helper('Mage_Tag_Helper_Data')->__('The tag has been saved.')
+                );
+
                 Mage::getSingleton('Mage_Adminhtml_Model_Session')->setTagData(false);
 
                 if (($continue = $this->getRequest()->getParam('continue'))) {
-                    return $this->_redirect('*/tag/edit', array('tag_id' => $model->getId(), 'store' => $model->getStoreId(), 'ret' => $continue));
+                    return $this->_redirect(
+                        '*/tag/edit',
+                        array('tag_id' => $model->getId(), 'store' => $model->getStoreId(), 'ret' => $continue)
+                    );
                 } else {
                     return $this->_redirect('*/tag/' . $this->getRequest()->getParam('ret', 'index'));
                 }
@@ -191,7 +211,10 @@ class Mage_Adminhtml_TagController extends Mage_Adminhtml_Controller_Action
                 Mage::getSingleton('Mage_Adminhtml_Model_Session')->addError($e->getMessage());
                 Mage::getSingleton('Mage_Adminhtml_Model_Session')->setTagData($data);
 
-                return $this->_redirect('*/*/edit', array('tag_id' => $model->getId(), 'store' => $model->getStoreId()));
+                return $this->_redirect(
+                    '*/*/edit',
+                    array('tag_id' => $model->getId(), 'store' => $model->getStoreId())
+                );
             }
         }
 
@@ -211,12 +234,12 @@ class Mage_Adminhtml_TagController extends Mage_Adminhtml_Controller_Action
         if ($model && $model->getId()) {
             try {
                 $model->delete();
-                $session->addSuccess(Mage::helper('Mage_Adminhtml_Helper_Data')->__('The tag has been deleted.'));
+                $session->addSuccess(Mage::helper('Mage_Tag_Helper_Data')->__('The tag has been deleted.'));
             } catch (Exception $e) {
                 $session->addError($e->getMessage());
             }
         } else {
-            $session->addError(Mage::helper('Mage_Adminhtml_Helper_Data')->__('Unable to find a tag to delete.'));
+            $session->addError(Mage::helper('Mage_Tag_Helper_Data')->__('Unable to find a tag to delete.'));
         }
 
         $this->getResponse()->setRedirect($this->getUrl('*/tag/' . $this->getRequest()->getParam('ret', 'index')));
@@ -233,7 +256,10 @@ class Mage_Adminhtml_TagController extends Mage_Adminhtml_Controller_Action
              ->_title($this->__('Pending Tags'));
 
         $this->_initAction()
-            ->_addBreadcrumb(Mage::helper('Mage_Adminhtml_Helper_Data')->__('Pending Tags'), Mage::helper('Mage_Adminhtml_Helper_Data')->__('Pending Tags'))
+            ->_addBreadcrumb(
+                Mage::helper('Mage_Tag_Helper_Data')->__('Pending Tags'),
+                Mage::helper('Mage_Tag_Helper_Data')->__('Pending Tags')
+            )
             ->_setActiveMenu('Mage_Tag::catalog_tag_pending')
             ->renderLayout();
     }
@@ -291,7 +317,7 @@ class Mage_Adminhtml_TagController extends Mage_Adminhtml_Controller_Action
     public function massDeleteAction()
     {
         $tagIds = $this->getRequest()->getParam('tag');
-        if(!is_array($tagIds)) {
+        if (!is_array($tagIds)) {
              Mage::getSingleton('Mage_Adminhtml_Model_Session')->addError($this->__('Please select tag(s).'));
         } else {
             try {
@@ -318,7 +344,7 @@ class Mage_Adminhtml_TagController extends Mage_Adminhtml_Controller_Action
     {
         $tagIds = $this->getRequest()->getParam('tag');
         $storeId = (int)$this->getRequest()->getParam('store', 0);
-        if(!is_array($tagIds)) {
+        if (!is_array($tagIds)) {
             // No products selected
             Mage::getSingleton('Mage_Adminhtml_Model_Session')->addError($this->__('Please select tag(s).'));
         } else {
diff --git a/app/code/core/Mage/Tag/controllers/IndexController.php b/app/code/core/Mage/Tag/controllers/IndexController.php
index 346480a9a40..5e7bef8835c 100644
--- a/app/code/core/Mage/Tag/controllers/IndexController.php
+++ b/app/code/core/Mage/Tag/controllers/IndexController.php
@@ -29,7 +29,7 @@
  *
  * @category   Mage
  * @package    Mage_Tag
- * @author      Magento Core Team <core@magentocommerce.com>
+ * @author     Magento Core Team <core@magentocommerce.com>
  */
 
 class Mage_Tag_IndexController extends Mage_Core_Controller_Front_Action
@@ -39,24 +39,27 @@ class Mage_Tag_IndexController extends Mage_Core_Controller_Front_Action
      */
     public function saveAction()
     {
+        /** @var $customerSession Mage_Customer_Model_Session */
         $customerSession = Mage::getSingleton('Mage_Customer_Model_Session');
-        if(!$customerSession->authenticate($this)) {
+        if (!$customerSession->authenticate($this)) {
             return;
         }
         $tagName    = (string) $this->getRequest()->getQuery('productTagName');
         $productId  = (int)$this->getRequest()->getParam('product');
 
-        if(strlen($tagName) && $productId) {
-            $session = Mage::getSingleton('Mage_Catalog_Model_Session');
+        if (strlen($tagName) && $productId) {
+            /** @var $session Mage_Tag_Model_Session */
+            $session = Mage::getSingleton('Mage_Tag_Model_Session');
             $product = Mage::getModel('Mage_Catalog_Model_Product')
                 ->load($productId);
-            if(!$product->getId()){
+            if (!$product->getId()) {
                 $session->addError($this->__('Unable to save tag(s).'));
             } else {
                 try {
                     $customerId = $customerSession->getCustomerId();
                     $storeId = Mage::app()->getStore()->getId();
 
+                    /** @var $tagModel Mage_Tag_Model_Tag */
                     $tagModel = Mage::getModel('Mage_Tag_Model_Tag');
 
                     // added tag relation statuses
@@ -70,8 +73,8 @@ class Mage_Tag_IndexController extends Mage_Core_Controller_Front_Action
                     $tagNamesArr = $this->_cleanTags($this->_extractTags($tagName));
                     foreach ($tagNamesArr as $tagName) {
                         // unset previously added tag data
-                        $tagModel->unsetData()
-                            ->loadByName($tagName);
+                        $tagModel->unsetData();
+                        $tagModel->loadByName($tagName);
 
                         if (!$tagModel->getId()) {
                             $tagModel->setName($tagName)
@@ -112,10 +115,10 @@ class Mage_Tag_IndexController extends Mage_Core_Controller_Front_Action
      */
     protected function _cleanTags(array $tagNamesArr)
     {
-        foreach( $tagNamesArr as $key => $tagName ) {
+        foreach ($tagNamesArr as $key => $tagName) {
             $tagNamesArr[$key] = trim($tagNamesArr[$key], '\'');
             $tagNamesArr[$key] = trim($tagNamesArr[$key]);
-            if( $tagNamesArr[$key] == '' ) {
+            if ($tagNamesArr[$key] == '') {
                 unset($tagNamesArr[$key]);
             }
         }
@@ -130,19 +133,19 @@ class Mage_Tag_IndexController extends Mage_Core_Controller_Front_Action
      */
     protected function _fillMessageBox($counter)
     {
-        $session = Mage::getSingleton('Mage_Catalog_Model_Session');
+        /** @var $session Mage_Tag_Model_Session */
+        $session = Mage::getSingleton('Mage_Tag_Model_Session');
         $helper = Mage::helper('Mage_Core_Helper_Data');
 
         if (count($counter[Mage_Tag_Model_Tag::ADD_STATUS_NEW])) {
-            $session->addSuccess(
-                $this->__('%s tag(s) have been accepted for moderation.', count($counter[Mage_Tag_Model_Tag::ADD_STATUS_NEW]))
-            );
+            $tagsCount = count($counter[Mage_Tag_Model_Tag::ADD_STATUS_NEW]);
+            $session->addSuccess($this->__('%s tag(s) have been accepted for moderation.', $tagsCount));
         }
 
         if (count($counter[Mage_Tag_Model_Tag::ADD_STATUS_EXIST])) {
             foreach ($counter[Mage_Tag_Model_Tag::ADD_STATUS_EXIST] as $tagName) {
                 $session->addNotice(
-                    $this->__('Tag "%s" has already been added to the product.' , $helper->escapeHtml($tagName))
+                    $this->__('Tag "%s" has already been added to the product.', $helper->escapeHtml($tagName))
                 );
             }
         }
@@ -150,7 +153,7 @@ class Mage_Tag_IndexController extends Mage_Core_Controller_Front_Action
         if (count($counter[Mage_Tag_Model_Tag::ADD_STATUS_SUCCESS])) {
             foreach ($counter[Mage_Tag_Model_Tag::ADD_STATUS_SUCCESS] as $tagName) {
                 $session->addSuccess(
-                    $this->__('Tag "%s" has been added to the product.' ,$helper->escapeHtml($tagName))
+                    $this->__('Tag "%s" has been added to the product.', $helper->escapeHtml($tagName))
                 );
             }
         }
@@ -158,10 +161,9 @@ class Mage_Tag_IndexController extends Mage_Core_Controller_Front_Action
         if (count($counter[Mage_Tag_Model_Tag::ADD_STATUS_REJECTED])) {
             foreach ($counter[Mage_Tag_Model_Tag::ADD_STATUS_REJECTED] as $tagName) {
                 $session->addNotice(
-                    $this->__('Tag "%s" has been rejected by administrator.' ,$helper->escapeHtml($tagName))
+                    $this->__('Tag "%s" has been rejected by administrator.', $helper->escapeHtml($tagName))
                 );
             }
         }
     }
-
 }
diff --git a/app/code/core/Mage/Tag/controllers/Rss/CatalogController.php b/app/code/core/Mage/Tag/controllers/Rss/CatalogController.php
new file mode 100644
index 00000000000..292ccac810b
--- /dev/null
+++ b/app/code/core/Mage/Tag/controllers/Rss/CatalogController.php
@@ -0,0 +1,60 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @category    Mage
+ * @package     Mage_Tag
+ * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+require_once 'Mage/Rss/controllers/CatalogController.php';
+
+/**
+ * Tag rss catalog controller
+ *
+ * @category   Mage
+ * @package    Mage_Tag
+ * @author     Magento Core Team <core@magentocommerce.com>
+ */
+class Mage_Tag_Rss_CatalogController extends Mage_Rss_CatalogController
+{
+    /**
+     * Tag rss action
+     *
+     * @return void
+     */
+    public function tagAction()
+    {
+        if (!$this->_isEnabled('tag')) {
+            $this->_forward('nofeed', 'index', 'rss');
+            return;
+        }
+        $tagName = urldecode($this->getRequest()->getParam('tagName'));
+        /** @var $tagModel Mage_Tag_Model_Tag */
+        $tagModel = Mage::getModel('Mage_Tag_Model_Tag');
+        $tagModel->loadByName($tagName);
+        if ($tagModel->getId() && $tagModel->getStatus() == $tagModel->getApprovedStatus()) {
+            Mage::register('tag_model', $tagModel);
+            $this->_render();
+            return;
+        }
+        $this->_forward('nofeed', 'index', 'rss');
+    }
+}
diff --git a/app/code/core/Mage/Tag/etc/adminhtml/acl.xml b/app/code/core/Mage/Tag/etc/adminhtml/acl.xml
index e8cd8105356..4d3d784a256 100644
--- a/app/code/core/Mage/Tag/etc/adminhtml/acl.xml
+++ b/app/code/core/Mage/Tag/etc/adminhtml/acl.xml
@@ -35,6 +35,13 @@
                         <resource id="Mage_Tag::tag_pending" title="Pending Tags" />
                     </resource>
                 </resource>
+                <resource id="Mage_Reports::report" module="Mage_Reports" title="Reports" sortOrder="80">
+                    <resource id="Mage_Reports::tags" module="Mage_Tag" title="Tags">
+                        <resource id="Mage_Reports::tags_customer" module="Mage_Tag" title="Customers" />
+                        <resource id="Mage_Reports::popular" module="Mage_Tag" title="Popular" />
+                        <resource id="Mage_Reports::tags_product" module="Mage_Tag" title="Products" />
+                    </resource>
+                </resource>
             </resource>
         </resources>
     </acl>
diff --git a/app/code/core/Mage/Tag/etc/config.xml b/app/code/core/Mage/Tag/etc/config.xml
index 84ce5619ec7..2fb8ed6badb 100644
--- a/app/code/core/Mage/Tag/etc/config.xml
+++ b/app/code/core/Mage/Tag/etc/config.xml
@@ -33,6 +33,9 @@
             <codePool>core</codePool>
             <depends>
                 <Mage_Catalog/>
+                <Mage_Customer/>
+                <Mage_Rss/>
+                <Mage_Reports/>
             </depends>
         </Mage_Tag>
     </modules>
@@ -51,9 +54,25 @@
                 </tag_summary>
             </indexer>
         </index>
+        <session>
+            <catalog>
+                <product>
+                    <message_models>
+                        <tag>Mage_Tag_Model_Session</tag>
+                    </message_models>
+                </product>
+            </catalog>
+        </session>
     </global>
     <frontend>
         <routers>
+            <rss>
+                <args>
+                    <modules>
+                        <tag before="Mage_Rss">Mage_Tag_Rss</tag>
+                    </modules>
+                </args>
+            </rss>
             <tag>
                 <use>standard</use>
                 <args>
@@ -76,12 +95,26 @@
                 <tag module="Mage_Tag">
                     <file>layout.xml</file>
                 </tag>
+                <tag_rss module="Mage_Tag">
+                    <file>rss.xml</file>
+                </tag_rss>
             </updates>
         </layout>
         <secure_url>
             <tag_customer>/tag/customer/</tag_customer>
         </secure_url>
     </frontend>
+    <admin>
+        <routers>
+            <adminhtml>
+                <args>
+                    <modules>
+                        <Mage_Tag before="Mage_Adminhtml">Mage_Tag_Adminhtml</Mage_Tag>
+                    </modules>
+                </args>
+            </adminhtml>
+        </routers>
+    </admin>
     <adminhtml>
         <events>
             <catalog_product_delete_before>
@@ -103,5 +136,18 @@
                 </Mage_Tag>
             </modules>
         </translate>
+        <layout>
+            <updates>
+                <tag_product module="Mage_Tag">
+                    <file>product.xml</file>
+                </tag_product>
+                <tag_customer module="Mage_Tag">
+                    <file>customer.xml</file>
+                </tag_customer>
+                <tag module="Mage_Tag">
+                    <file>tag.xml</file>
+                </tag>
+            </updates>
+        </layout>
     </adminhtml>
 </config>
diff --git a/app/code/core/Mage/Tag/etc/system.xml b/app/code/core/Mage/Tag/etc/system.xml
new file mode 100644
index 00000000000..ee017412fdc
--- /dev/null
+++ b/app/code/core/Mage/Tag/etc/system.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0"?>
+<!--
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Academic Free License (AFL 3.0)
+ * that is bundled with this package in the file LICENSE_AFL.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/afl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @category    Mage
+ * @package     Mage_Rss
+ * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/afl-3.0.php  Academic Free License (AFL 3.0)
+ */
+-->
+<config>
+    <sections>
+        <rss>
+            <groups>
+                <catalog translate="label">
+                    <fields>
+                        <tag translate="label">
+                            <label>Tags Products</label>
+                            <frontend_type>select</frontend_type>
+                            <source_model>Mage_Adminhtml_Model_System_Config_Source_Enabledisable</source_model>
+                            <sort_order>13</sort_order>
+                            <show_in_default>1</show_in_default>
+                            <show_in_website>1</show_in_website>
+                            <show_in_store>1</show_in_store>
+                        </tag>
+                    </fields>
+                </catalog>
+            </groups>
+        </rss>
+    </sections>
+</config>
diff --git a/app/code/core/Mage/Tag/view/adminhtml/customer.xml b/app/code/core/Mage/Tag/view/adminhtml/customer.xml
new file mode 100644
index 00000000000..d7ed5a2bc7b
--- /dev/null
+++ b/app/code/core/Mage/Tag/view/adminhtml/customer.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0"?>
+<!--
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Academic Free License (AFL 3.0)
+ * that is bundled with this package in the file LICENSE_AFL.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/afl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @category    Mage
+ * @package     Mage_Tag
+ * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/afl-3.0.php  Academic Free License (AFL 3.0)
+ */
+-->
+<layout>
+    <adminhtml_customer_edit>
+        <reference name="customer_edit_tabs">
+            <action method="addTab">
+                <tab>tags</tab>
+                <content>Mage_Tag_Block_Adminhtml_Customer_Edit_Tab_Tag</content>
+            </action>
+        </reference>
+    </adminhtml_customer_edit>
+
+    <adminhtml_customer_producttags>
+        <container name="root" label="Root" output="1">
+            <block type="Mage_Tag_Block_Adminhtml_Customer_Edit_Tab_Tag_Grid" name="admin.customer.tags"/>
+        </container>
+    </adminhtml_customer_producttags>
+
+    <adminhtml_customer_taggrid>
+        <container name="root" label="Root" output="1">
+            <block type="Mage_Tag_Block_Adminhtml_Customer_Edit_Tab_Tag_Grid" name="admin.customer.tags"/>
+        </container>
+    </adminhtml_customer_taggrid>
+</layout>
diff --git a/app/code/core/Mage/Tag/view/adminhtml/product.xml b/app/code/core/Mage/Tag/view/adminhtml/product.xml
new file mode 100644
index 00000000000..86d824c4b86
--- /dev/null
+++ b/app/code/core/Mage/Tag/view/adminhtml/product.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0"?>
+<!--
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Academic Free License (AFL 3.0)
+ * that is bundled with this package in the file LICENSE_AFL.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/afl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @category    design
+ * @package     base_default
+ * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/afl-3.0.php  Academic Free License (AFL 3.0)
+ */
+
+-->
+<layout version="0.1.0">
+
+    <adminhtml_catalog_product_edit>
+        <reference name="product_tabs">
+            <action method="addTab"><name>tags</name><block>Mage_Tag_Block_Adminhtml_Catalog_Product_Edit_Tab_Tag</block></action>
+            <action method="addTab"><name>customers_tags</name><block>Mage_Tag_Block_Adminhtml_Catalog_Product_Edit_Tab_Tag_Customer</block></action>
+        </reference>
+    </adminhtml_catalog_product_edit>
+
+    <adminhtml_catalog_product_taggrid>
+        <container name="root" label="Root" output="1">
+            <block type="Mage_Tag_Block_Adminhtml_Catalog_Product_Edit_Tab_Tag_Grid" name="admin.product.tags"/>
+        </container>
+    </adminhtml_catalog_product_taggrid>
+
+    <adminhtml_catalog_product_tagcustomergrid>
+        <container name="root" label="Root" output="1">
+            <block type="Mage_Tag_Block_Adminhtml_Catalog_Product_Edit_Tab_Tag_Customer_Grid" name="admin.product.tags.customers"/>
+        </container>
+    </adminhtml_catalog_product_tagcustomergrid>
+
+</layout>
diff --git a/app/code/core/Mage/Adminhtml/view/adminhtml/tag.xml b/app/code/core/Mage/Tag/view/adminhtml/tag.xml
similarity index 84%
rename from app/code/core/Mage/Adminhtml/view/adminhtml/tag.xml
rename to app/code/core/Mage/Tag/view/adminhtml/tag.xml
index 1ff60f7434e..9782dbb83cd 100644
--- a/app/code/core/Mage/Adminhtml/view/adminhtml/tag.xml
+++ b/app/code/core/Mage/Tag/view/adminhtml/tag.xml
@@ -28,12 +28,12 @@
 <layout>
     <adminhtml_tag_edit>
         <reference name="content">
-            <block type="Mage_Adminhtml_Block_Tag_Edit" name="tag_edit" template="tag/edit/container.phtml"></block>
+            <block type="Mage_Tag_Block_Adminhtml_Edit" name="tag_edit" template="tag/edit/container.phtml"></block>
         </reference>
     </adminhtml_tag_edit>
     <adminhtml_tag_assigned>
             <remove name="root" />
-            <block type="Mage_Adminhtml_Block_Tag_Assigned_Grid" name="tag_assigned_grid" output="1" />
+            <block type="Mage_Tag_Block_Adminhtml_Assigned_Grid" name="tag_assigned_grid" output="1" />
             <block type="Mage_Adminhtml_Block_Widget_Grid_Serializer" name="tag_grid_serializer" output="1">
                 <reference name="tag_grid_serializer">
                     <action method="initSerializerBlock">
@@ -47,44 +47,44 @@
     </adminhtml_tag_assigned>
     <adminhtml_tag_assignedgridonly>
         <remove name="root" />
-        <block type="Mage_Adminhtml_Block_Tag_Assigned_Grid" name="assigned_grid" output="1" />
+        <block type="Mage_Tag_Block_Adminhtml_Assigned_Grid" name="assigned_grid" output="1" />
     </adminhtml_tag_assignedgridonly>
 
     <adminhtml_tag_index>
         <reference name="content">
-            <block type="Mage_Adminhtml_Block_Tag_Tag" name="adminhtml.tag.tag"/>
+            <block type="Mage_Tag_Block_Adminhtml_Tag" name="adminhtml.tag.tag"/>
         </reference>
     </adminhtml_tag_index>
 
     <adminhtml_tag_pending>
         <reference name="content">
-            <block type="Mage_Adminhtml_Block_Tag_Pending" name="adminhtml.tag.pending"/>
+            <block type="Mage_Tag_Block_Adminhtml_Pending" name="adminhtml.tag.pending"/>
         </reference>
     </adminhtml_tag_pending>
 
     <adminhtml_tag_ajaxgrid>
         <update handle="formkey"/>
         <container name="root" label="Root" output="1">
-            <block type="Mage_Adminhtml_Block_Tag_Tag_Grid" name="adminhtml.tag.tag.grid"/>
+            <block type="Mage_Tag_Block_Adminhtml_Tag_Grid" name="adminhtml.tag.tag.grid"/>
         </container>
     </adminhtml_tag_ajaxgrid>
 
     <adminhtml_tag_ajaxpendinggrid>
         <update handle="formkey"/>
         <container name="root" label="Root" output="1">
-            <block type="Mage_Adminhtml_Block_Tag_Grid_Pending" name="adminhtml.tag.grid.pending"/>
+            <block type="Mage_Tag_Block_Adminhtml_Grid_Pending" name="adminhtml.tag.grid.pending"/>
         </container>
     </adminhtml_tag_ajaxpendinggrid>
 
     <adminhtml_tag_product>
         <container name="root" label="Root" output="1">
-            <block type="Mage_Adminhtml_Block_Tag_Product_Grid" name="adminhtml.tag.product.grid"/>
+            <block type="Mage_Tag_Block_Adminhtml_Product_Grid" name="adminhtml.tag.product.grid"/>
         </container>
     </adminhtml_tag_product>
 
     <adminhtml_tag_customer>
         <container name="root" label="Root" output="1">
-            <block type="Mage_Adminhtml_Block_Tag_Customer_Grid" name="adminhtml.tag.customer.grid"/>
+            <block type="Mage_Tag_Block_Adminhtml_Customer_Grid" name="adminhtml.tag.customer.grid"/>
         </container>
     </adminhtml_tag_customer>
 </layout>
diff --git a/app/code/core/Mage/Adminhtml/view/adminhtml/tag/edit/container.phtml b/app/code/core/Mage/Tag/view/adminhtml/tag/edit/container.phtml
similarity index 100%
rename from app/code/core/Mage/Adminhtml/view/adminhtml/tag/edit/container.phtml
rename to app/code/core/Mage/Tag/view/adminhtml/tag/edit/container.phtml
diff --git a/app/code/core/Mage/Adminhtml/view/adminhtml/tag/index.phtml b/app/code/core/Mage/Tag/view/adminhtml/tag/index.phtml
similarity index 100%
rename from app/code/core/Mage/Adminhtml/view/adminhtml/tag/index.phtml
rename to app/code/core/Mage/Tag/view/adminhtml/tag/index.phtml
diff --git a/app/code/core/Mage/Tag/view/frontend/layout.xml b/app/code/core/Mage/Tag/view/frontend/layout.xml
index 5552a09f725..b4559b1557c 100644
--- a/app/code/core/Mage/Tag/view/frontend/layout.xml
+++ b/app/code/core/Mage/Tag/view/frontend/layout.xml
@@ -98,6 +98,7 @@ All tags page
                     </block>
                     <action method="setToolbarBlockName"><name>product_list_toolbar</name></action>
                 </block>
+                <block type="Mage_Tag_Block_Catalog_Product_Rss_Link" name="tagged_product_list_rss_link" template="product/rss/link.phtml" />
                 <action method="setListOrders"/>
                 <action method="setListModes"/>
                 <action method="setListCollection"/>
diff --git a/app/code/core/Mage/Tag/view/frontend/product/rss/link.phtml b/app/code/core/Mage/Tag/view/frontend/product/rss/link.phtml
new file mode 100644
index 00000000000..530b8f5efd7
--- /dev/null
+++ b/app/code/core/Mage/Tag/view/frontend/product/rss/link.phtml
@@ -0,0 +1,30 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Academic Free License (AFL 3.0)
+ * that is bundled with this package in the file LICENSE_AFL.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/afl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @category    design
+ * @package     base_default
+ * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/afl-3.0.php  Academic Free License (AFL 3.0)
+ */
+/** @var $this Mage_Tag_Block_Catalog_Product_Rss_Link */
+?>
+<?php if ($this->getLinkUrl()): ?>
+    <a href="<?php echo $this->getLinkUrl(); ?>" class="nobr link-rss"><?php echo $this->__('Subscribe to Feed') ?></a>
+<?php endif; ?>
\ No newline at end of file
diff --git a/app/code/core/Mage/Tag/view/frontend/rss.xml b/app/code/core/Mage/Tag/view/frontend/rss.xml
new file mode 100644
index 00000000000..4bf825fc3af
--- /dev/null
+++ b/app/code/core/Mage/Tag/view/frontend/rss.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<!--
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Academic Free License (AFL 3.0)
+ * that is bundled with this package in the file LICENSE_AFL.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/afl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @category    design
+ * @package     base_default
+ * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/afl-3.0.php  Academic Free License (AFL 3.0)
+ */
+-->
+<layout version="0.1.0">
+<!--
+Rss feeds layouts
+-->
+    <rss_catalog_tag>
+        <block type="Mage_Tag_Block_Catalog_Product_Rss" output="1" name="rss.catalog.product.tag">
+            <action method="addPriceBlockType"><type>msrp_rss</type><block>Mage_Catalog_Block_Product_Price</block><template>product/price_msrp_rss.phtml</template></action>
+        </block>
+    </rss_catalog_tag>
+
+</layout>
diff --git a/app/design/frontend/default/iphone/Mage_Catalog/product/view.phtml b/app/design/frontend/default/iphone/Mage_Catalog/product/view.phtml
index d85781e294a..69173727901 100644
--- a/app/design/frontend/default/iphone/Mage_Catalog/product/view.phtml
+++ b/app/design/frontend/default/iphone/Mage_Catalog/product/view.phtml
@@ -108,7 +108,6 @@
         <?php endif;?>
     </form>
     <?php echo $this->getChildHtml('upsell_products') ?>
-    <?php echo $this->getChildHtml('productTagList') ?>
     <?php echo $this->getChildHtml('product_additional_data') ?>
 </div>
 
diff --git a/app/design/frontend/default/iphone/Mage_CatalogSearch/result.phtml b/app/design/frontend/default/iphone/Mage_CatalogSearch/result.phtml
index f34104959f7..895a077251c 100644
--- a/app/design/frontend/default/iphone/Mage_CatalogSearch/result.phtml
+++ b/app/design/frontend/default/iphone/Mage_CatalogSearch/result.phtml
@@ -27,9 +27,7 @@
 <?php if($this->getResultCount()): ?>
 <?php echo $this->getMessagesBlock()->getGroupedHtml() ?>
 <div class="page-title">
-    <?php if ($this->helper('Mage_Rss_Helper_Catalog')->getTagFeedUrl()): ?>
-        <a href="<?php echo $this->helper('Mage_Rss_Helper_Catalog')->getTagFeedUrl() ?>" class="nobr link-rss"><?php echo $this->__('Subscribe to Feed') ?></a>
-    <?php endif; ?>
+    <?php echo $this->getChildHtml('tagged_product_list_rss_link'); ?>
     <h1><?php echo ($this->getHeaderText() || $this->getHeaderText() === false) ? $this->getHeaderText() : $this->__("Search results for '%s'", $this->helper('Mage_CatalogSearch_Helper_Data')->getEscapedQueryText()) ?></h1>
 </div>
     <?php if ($messages = $this->getNoteMessages()):?>
diff --git a/app/design/frontend/default/iphone/Mage_Rss/layout.xml b/app/design/frontend/default/iphone/Mage_Rss/layout.xml
index a00b9276fa5..a7af42fbcf0 100644
--- a/app/design/frontend/default/iphone/Mage_Rss/layout.xml
+++ b/app/design/frontend/default/iphone/Mage_Rss/layout.xml
@@ -65,12 +65,6 @@ Catalog layout
         <block type="Mage_Rss_Block_Catalog_Salesrule" output="1" name="rss.catalog.salesrule"/>
     </rss_catalog_salesrule>
 
-    <rss_catalog_tag>
-        <block type="Mage_Rss_Block_Catalog_Tag" output="1" name="rss.catalog.tag">
-            <action method="addPriceBlockType"><type>msrp_rss</type><block>Mage_Catalog_Block_Product_Price</block><template>product/price_msrp_rss.phtml</template></action>
-        </block>
-    </rss_catalog_tag>
-
     <rss_catalog_category>
         <block type="Mage_Rss_Block_Catalog_Category" output="1" name="rss.catalog.category">
             <action method="addPriceBlockType"><type>msrp_rss</type><block>Mage_Catalog_Block_Product_Price</block><template>product/price_msrp_rss.phtml</template></action>
diff --git a/app/design/frontend/default/iphone/Mage_Tag/layout.xml b/app/design/frontend/default/iphone/Mage_Tag/layout.xml
index f43d972d41c..0ae78414038 100644
--- a/app/design/frontend/default/iphone/Mage_Tag/layout.xml
+++ b/app/design/frontend/default/iphone/Mage_Tag/layout.xml
@@ -80,6 +80,7 @@ All tags page
                     </block>
                     <action method="setToolbarBlockName"><name>product_list_toolbar</name></action>
                 </block>
+                <block type="Mage_Tag_Block_Catalog_Product_Rss_Link" name="tagged_product_list_rss_link" template="product/rss/link.phtml" />
                 <action method="setListOrders"/>
                 <action method="setListModes"/>
                 <action method="setListCollection"/>
diff --git a/app/design/frontend/default/modern/Mage_Rss/layout.xml b/app/design/frontend/default/modern/Mage_Rss/layout.xml
index 753b5fcfbcd..44eb7194f7d 100644
--- a/app/design/frontend/default/modern/Mage_Rss/layout.xml
+++ b/app/design/frontend/default/modern/Mage_Rss/layout.xml
@@ -63,10 +63,6 @@ Catalog layout
         <block type="Mage_Rss_Block_Catalog_Salesrule" output="1" name="rss.catalog.salesrule"/>
     </rss_catalog_salesrule>
 
-    <rss_catalog_tag>
-        <block type="Mage_Rss_Block_Catalog_Tag" output="1" name="rss.catalog.tag" />
-    </rss_catalog_tag>
-
     <rss_catalog_category>
         <block type="Mage_Rss_Block_Catalog_Category" output="1" name="rss.catalog.category" />
     </rss_catalog_category>
diff --git a/app/design/frontend/default/modern/Mage_Tag/layout.xml b/app/design/frontend/default/modern/Mage_Tag/layout.xml
index b16e22e3a76..97e81a1977e 100644
--- a/app/design/frontend/default/modern/Mage_Tag/layout.xml
+++ b/app/design/frontend/default/modern/Mage_Tag/layout.xml
@@ -98,6 +98,7 @@ All tags page
                     </block>
                     <action method="setToolbarBlockName"><name>product_list_toolbar</name></action>
                 </block>
+                <block type="Mage_Tag_Block_Catalog_Product_Rss_Link" name="tagged_product_list_rss_link" template="product/rss/link.phtml" />
                 <action method="setListOrders"/>
                 <action method="setListModes"/>
                 <action method="setListCollection"/>
diff --git a/dev/tests/integration/testsuite/Mage/Adminhtml/controllers/CustomerControllerTest.php b/dev/tests/integration/testsuite/Mage/Adminhtml/controllers/CustomerControllerTest.php
index 1584023f273..db304ae0e20 100644
--- a/dev/tests/integration/testsuite/Mage/Adminhtml/controllers/CustomerControllerTest.php
+++ b/dev/tests/integration/testsuite/Mage/Adminhtml/controllers/CustomerControllerTest.php
@@ -170,12 +170,9 @@ class Mage_Adminhtml_CustomerControllerTest extends Mage_Adminhtml_Utility_Contr
         );
     }
 
-    /**
-     *
-     * @magentoDataFixture Mage/Adminhtml/controllers/_files/customer_sample.php
-     */
     public function testSaveActionExistingCustomerAndExistingAddressData()
     {
+        $this->markTestIncomplete('Bug MAGETWO-2986');
         $post = array(
             'account' => array(
                 'middlename' => 'test middlename',
@@ -255,12 +252,9 @@ class Mage_Adminhtml_CustomerControllerTest extends Mage_Adminhtml_Utility_Contr
         $this->assertRedirect($this->stringStartsWith($this->_baseControllerUrl . 'index/key/'));
     }
 
-    /**
-     *
-     * @magentoDataFixture Mage/Adminhtml/controllers/_files/customer_sample.php
-     */
     public function testSaveActionCoreException()
     {
+        $this->markTestIncomplete('Bug MAGETWO-2986');
         $post = array(
             'account' => array(
                 'middlename' => 'test middlename',
diff --git a/dev/tests/integration/testsuite/Mage/Adminhtml/controllers/Sales/OrderControllerTest.php b/dev/tests/integration/testsuite/Mage/Adminhtml/controllers/Sales/OrderControllerTest.php
index 4d5d9df641e..3cc2b4a433d 100644
--- a/dev/tests/integration/testsuite/Mage/Adminhtml/controllers/Sales/OrderControllerTest.php
+++ b/dev/tests/integration/testsuite/Mage/Adminhtml/controllers/Sales/OrderControllerTest.php
@@ -53,6 +53,13 @@ class Mage_Adminhtml_Sales_OrderControllerTest extends Mage_Adminhtml_Utility_Co
         $this->assertContains('Los Angeles', $this->getResponse()->getBody());
     }
 
+    public function testAddressActionNonExistingAddress()
+    {
+        $this->getRequest()->setParam('address_id', -1);
+        $this->dispatch('backend/admin/sales_order/address');
+        $this->assertRedirect();
+    }
+
     /**
      * @magentoDataFixture Mage/Adminhtml/controllers/Sales/_files/address.php
      */
diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Helper/Product/CompareTest.php b/dev/tests/integration/testsuite/Mage/Catalog/Helper/Product/CompareTest.php
index 41b30bf0d2c..010da43bb85 100644
--- a/dev/tests/integration/testsuite/Mage/Catalog/Helper/Product/CompareTest.php
+++ b/dev/tests/integration/testsuite/Mage/Catalog/Helper/Product/CompareTest.php
@@ -43,7 +43,7 @@ class Mage_Catalog_Helper_Product_CompareTest extends PHPUnit_Framework_TestCase
     }
 
     /**
-     * @magentoDataFixture Mage/Catalog/_files/two_products.php
+     * @magentoDataFixture Mage/Catalog/_files/multiple_products.php
      */
     public function testGetListUrl()
     {
@@ -93,7 +93,7 @@ class Mage_Catalog_Helper_Product_CompareTest extends PHPUnit_Framework_TestCase
      * calculate()
      * getItemCount()
      * hasItems()
-     * @magentoDataFixture Mage/Catalog/_files/two_products.php
+     * @magentoDataFixture Mage/Catalog/_files/multiple_products.php
      */
     public function testCalculate()
     {
diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Helper/Product/ViewTest.php b/dev/tests/integration/testsuite/Mage/Catalog/Helper/Product/ViewTest.php
index 9225bf77731..caf027c8fda 100644
--- a/dev/tests/integration/testsuite/Mage/Catalog/Helper/Product/ViewTest.php
+++ b/dev/tests/integration/testsuite/Mage/Catalog/Helper/Product/ViewTest.php
@@ -78,7 +78,7 @@ class Mage_Catalog_Helper_Product_ViewTest extends PHPUnit_Framework_TestCase
     }
 
     /**
-     * @magentoDataFixture Mage/Catalog/_files/two_products.php
+     * @magentoDataFixture Mage/Catalog/_files/multiple_products.php
      * @magentoAppIsolation enabled
      */
     public function testPrepareAndRender()
@@ -89,7 +89,7 @@ class Mage_Catalog_Helper_Product_ViewTest extends PHPUnit_Framework_TestCase
     }
 
     /**
-     * @magentoDataFixture Mage/Catalog/_files/two_products.php
+     * @magentoDataFixture Mage/Catalog/_files/multiple_products.php
      * @expectedException Mage_Core_Exception
      * @magentoAppIsolation enabled
      */
@@ -106,4 +106,45 @@ class Mage_Catalog_Helper_Product_ViewTest extends PHPUnit_Framework_TestCase
     {
         $this->_helper->prepareAndRender(999, $this->_controller);
     }
+
+    /**
+     * Test for _getSessionMessageModels
+     *
+     * @magentoDataFixture Mage/Catalog/_files/multiple_products.php
+     * @magentoAppIsolation enabled
+     * @covers Mage_Catalog_Helper_Product_View::_getSessionMessageModels
+     */
+    public function testGetSessionMessageModels()
+    {
+        $expectedMessages = array(
+            'Mage_Catalog_Model_Session'  => 'catalog message',
+            'Mage_Checkout_Model_Session' => 'checkout message',
+        );
+
+        // add messages
+        foreach ($expectedMessages as $sessionModel => $messageText) {
+            /** @var $session Mage_Core_Model_Session_Abstract */
+            $session = Mage::getSingleton($sessionModel);
+            $session->addNotice($messageText);
+        }
+
+        // _getSessionMessageModels invokes inside prepareAndRender
+        $this->_helper->prepareAndRender(10, $this->_controller);
+
+        // assert messages
+        $actualMessages = $this->_controller->getLayout()
+            ->getMessagesBlock()
+            ->getMessages();
+        $this->assertSameSize($expectedMessages, $actualMessages);
+
+        sort($expectedMessages);
+
+        /** @var $message Mage_Core_Model_Message_Notice */
+        foreach ($actualMessages as $key => $message) {
+            $actualMessages[$key] = $message->getText();
+        }
+        sort($actualMessages);
+
+        $this->assertEquals($expectedMessages, $actualMessages);
+    }
 }
diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Type/AbstractTest.php b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Type/AbstractTest.php
index f595a3aa916..209ef227ff7 100644
--- a/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Type/AbstractTest.php
+++ b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Type/AbstractTest.php
@@ -144,9 +144,9 @@ class Mage_Catalog_Model_Product_Type_AbstractTest extends PHPUnit_Framework_Tes
     /**
      * @param array $requestData
      * @magentoAppIsolation enabled
-     * @magentoDataFixture Mage/Catalog/_files/two_products.php
-     * two_products.php because there are products without options, and they don't intersect with product_simple.php
-     * by ID
+     * @magentoDataFixture Mage/Catalog/_files/multiple_products.php
+     * multiple_products.php because there are products without options, and they don't intersect
+     * with product_simple.php by ID
      */
     public function testPrepareForCart()
     {
diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/ProductTest.php b/dev/tests/integration/testsuite/Mage/Catalog/Model/ProductTest.php
index 09af384decc..6201baed291 100644
--- a/dev/tests/integration/testsuite/Mage/Catalog/Model/ProductTest.php
+++ b/dev/tests/integration/testsuite/Mage/Catalog/Model/ProductTest.php
@@ -356,7 +356,7 @@ class Mage_Catalog_Model_ProductTest extends PHPUnit_Framework_TestCase
     }
 
     /**
-     * @magentoDataFixture Mage/Catalog/_files/two_products.php
+     * @magentoDataFixture Mage/Catalog/_files/multiple_products.php
      */
     public function testIsProductsHasSku()
     {
diff --git a/dev/tests/integration/testsuite/Mage/Catalog/_files/two_products.php b/dev/tests/integration/testsuite/Mage/Catalog/_files/multiple_products.php
similarity index 59%
rename from dev/tests/integration/testsuite/Mage/Catalog/_files/two_products.php
rename to dev/tests/integration/testsuite/Mage/Catalog/_files/multiple_products.php
index d58dd00ea51..119c976fa7a 100644
--- a/dev/tests/integration/testsuite/Mage/Catalog/_files/two_products.php
+++ b/dev/tests/integration/testsuite/Mage/Catalog/_files/multiple_products.php
@@ -31,8 +31,14 @@ $product->setTypeId(Mage_Catalog_Model_Product_Type::TYPE_SIMPLE)
     ->setAttributeSetId(4)
     ->setName('Simple Product')
     ->setSku('simple1')
+    ->setDescription('description')
+    ->setShortDescription('short description')
+    ->setOptionsContainer('container1')
+    ->setMsrpDisplayActualPriceType(
+        Mage_Catalog_Model_Product_Attribute_Source_Msrp_Type::TYPE_IN_CART
+    )
     ->setPrice(10)
-
+    ->setWeight(1)
     ->setMetaTitle('meta title')
     ->setMetaKeyword('meta keyword')
     ->setMetaDescription('meta description')
@@ -40,7 +46,7 @@ $product->setTypeId(Mage_Catalog_Model_Product_Type::TYPE_SIMPLE)
     ->setVisibility(Mage_Catalog_Model_Product_Visibility::VISIBILITY_BOTH)
     ->setStatus(Mage_Catalog_Model_Product_Status::STATUS_ENABLED)
     ->setWebsiteIds(array(1))
-
+    ->setCateroryIds(array())
     ->setStockData(
         array(
             'use_config_manage_stock'   => 1,
@@ -58,16 +64,25 @@ $product->setTypeId(Mage_Catalog_Model_Product_Type::TYPE_SIMPLE)
     ->setAttributeSetId(4)
     ->setName('Simple Product2')
     ->setSku('simple2')
-    ->setPrice(10)
-
+    ->setDescription('description')
+    ->setShortDescription('short description')
+    ->setEnableGooglecheckout(false)
+    ->setOptionsContainer('container1')
+    ->setMsrpEnabled(
+        Mage_Catalog_Model_Product_Attribute_Source_Msrp_Type_Enabled::MSRP_ENABLE_YES
+    )
+    ->setMsrpDisplayActualPriceType(
+        Mage_Catalog_Model_Product_Attribute_Source_Msrp_Type::TYPE_ON_GESTURE
+    )
+    ->setPrice(20)
+    ->setWeight(1)
     ->setMetaTitle('meta title')
     ->setMetaKeyword('meta keyword')
     ->setMetaDescription('meta description')
-
-    ->setVisibility(Mage_Catalog_Model_Product_Visibility::VISIBILITY_BOTH)
+    ->setVisibility(Mage_Catalog_Model_Product_Visibility::VISIBILITY_IN_CATALOG)
     ->setStatus(Mage_Catalog_Model_Product_Status::STATUS_ENABLED)
     ->setWebsiteIds(array(1))
-
+    ->setCateroryIds(array())
     ->setStockData(
         array(
             'use_config_manage_stock'   => 1,
@@ -78,3 +93,30 @@ $product->setTypeId(Mage_Catalog_Model_Product_Type::TYPE_SIMPLE)
     )
 
     ->save();
+
+$product = new Mage_Catalog_Model_Product();
+$product->setTypeId(Mage_Catalog_Model_Product_Type::TYPE_SIMPLE)
+    ->setId(12)
+    ->setAttributeSetId(4)
+    ->setName('Simple Product 3')
+    ->setSku('simple3')
+    ->setDescription('description')
+    ->setShortDescription('short description')
+    ->setMsrpEnabled(
+        Mage_Catalog_Model_Product_Attribute_Source_Msrp_Type_Enabled::MSRP_ENABLE_NO
+    )
+    ->setPrice(30)
+    ->setWeight(1)
+    ->setVisibility(Mage_Catalog_Model_Product_Visibility::VISIBILITY_IN_CATALOG)
+    ->setStatus(Mage_Catalog_Model_Product_Status::STATUS_DISABLED)
+    ->setWebsiteIds(array(1))
+    ->setCateroryIds(array())
+    ->setStockData(
+        array(
+            'use_config_manage_stock'   => 1,
+            'qty'                       => 140,
+            'is_qty_decimal'            => 0,
+            'is_in_stock'               => 1,
+        )
+    )
+    ->save();
\ No newline at end of file
diff --git a/dev/tests/integration/testsuite/Mage/DesignEditor/Block/Toolbar/ExitTest.php b/dev/tests/integration/testsuite/Mage/DesignEditor/Block/Toolbar/ExitTest.php
index 9d3270cf3b1..d1209987fcd 100644
--- a/dev/tests/integration/testsuite/Mage/DesignEditor/Block/Toolbar/ExitTest.php
+++ b/dev/tests/integration/testsuite/Mage/DesignEditor/Block/Toolbar/ExitTest.php
@@ -28,13 +28,13 @@
 class Mage_DesignEditor_Block_Toolbar_ExitTest extends PHPUnit_Framework_TestCase
 {
     /**
-     * @var Mage_DesignEditor_Block_Toolbar_Exit
+     * @var Mage_DesignEditor_Block_Toolbar_Buttons
      */
     protected $_block;
 
     protected function setUp()
     {
-        $this->_block = new Mage_DesignEditor_Block_Toolbar_Exit(array('template' => 'toolbar/exit.phtml'));
+        $this->_block = new Mage_DesignEditor_Block_Toolbar_Buttons(array('template' => 'toolbar/exit.phtml'));
     }
 
     protected function tearDown()
diff --git a/dev/tests/integration/testsuite/Mage/DesignEditor/Model/HistoryTest.php b/dev/tests/integration/testsuite/Mage/DesignEditor/Model/HistoryTest.php
new file mode 100644
index 00000000000..3de267e5c6e
--- /dev/null
+++ b/dev/tests/integration/testsuite/Mage/DesignEditor/Model/HistoryTest.php
@@ -0,0 +1,178 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @category    Magento
+ * @package     Mage_DesignEditor
+ * @subpackage  integration_tests
+ * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+class Mage_DesignEditor_Model_HistoryTest extends PHPUnit_Framework_TestCase
+{
+    /**
+     * @var Mage_DesignEditor_Model_History
+     */
+    protected $_historyObject;
+
+    public function setUp()
+    {
+        $this->_historyObject = Mage::getModel('Mage_DesignEditor_Model_History');
+    }
+
+    /**
+     * @dataProvider getChangeLogData
+     */
+    public function testGetCompactLog($changes)
+    {
+        $historyObject = $this->_historyObject;
+        $historyObject->setChangeLog($changes);
+        $this->assertEquals($this->getCompactedChangeLogData(), $historyObject->getCompactLog());
+    }
+
+    /**
+     * @dataProvider getInvalidChangeLogData
+     * @expectedException Mage_DesignEditor_Exception
+     */
+    public function testGetCompactLogInvalidData($changes)
+    {
+        $historyObject = $this->_historyObject;
+        $historyObject->setChangeLog($changes);
+        $historyObject->getCompactLog();
+    }
+
+    /**
+     * @dataProvider getChangeLogData
+     */
+    public function testGetCompactXml($changes)
+    {
+        $historyObject = $this->_historyObject;
+        $historyObject->setChangeLog($changes);
+        $this->assertXmlStringEqualsXmlFile(
+            realpath(__DIR__) . '/../_files/history/compact_log.xml', $historyObject->getCompactXml()
+        );
+    }
+
+    /**
+     * @dataProvider getInvalidChangeLogData
+     * @expectedException Mage_DesignEditor_Exception
+     */
+    public function testGetCompactXmlInvalidData($changes)
+    {
+        $historyObject = $this->_historyObject;
+        $historyObject->setChangeLog($changes);
+        $historyObject->getCompactXml();
+    }
+
+    public function getChangeLogData()
+    {
+        return array(array(
+            array(
+                array(
+                    'handle'       => 'catalog_category_view',
+                    'change_type'  => 'layout',
+                    'element_name' => 'category.products',
+                    'action_name'  => 'move',
+                    'action_data'  => array(
+                        'destination_container' => 'content',
+                        'after'          => '-',
+                    ),
+                ),
+                array(
+                    'handle'       => 'catalog_category_view',
+                    'change_type'  => 'layout',
+                    'element_name' => 'category.products',
+                    'action_name'  => 'remove',
+                    'action_data'  => array(),
+                ),
+                array(
+                    'handle'       => 'customer_account',
+                    'change_type'  => 'layout',
+                    'element_name' => 'customer_account_navigation',
+                    'action_name'  => 'move',
+                    'action_data'  => array(
+                        'destination_container' => 'content',
+                        'after'                 => '-',
+                        'as'                    => 'customer_account_navigation_alias',
+                    ),
+                ),
+                array(
+                    'handle'       => 'customer_account',
+                    'change_type'  => 'layout',
+                    'element_name' => 'customer_account_navigation',
+                    'action_name'  => 'move',
+                    'action_data'  => array(
+                        'destination_container' => 'top.menu',
+                        'after'                 => '-',
+                        'as'                    => 'customer_account_navigation_alias',
+                    ),
+                ),
+            ),
+        ));
+    }
+
+    public function getCompactedChangeLogData()
+    {
+        return array(
+            array(
+                'handle'       => 'catalog_category_view',
+                'change_type'  => 'layout',
+                'element_name' => 'category.products',
+                'action_name'  => 'remove',
+                'action_data'  => array(),
+            ),
+            array(
+                'handle'       => 'customer_account',
+                'change_type'  => 'layout',
+                'element_name' => 'customer_account_navigation',
+                'action_name'  => 'move',
+                'action_data'  => array(
+                    'destination_container' => 'top.menu',
+                    'after'                 => '-',
+                    'as'                    => 'customer_account_navigation_alias',
+                ),
+            ),
+        );
+    }
+
+    public function getInvalidChangeLogData()
+    {
+        return array(array(
+            array(
+                array(
+                    'handle'       => 'catalog_category_view',
+                    'change_type'  => 'layout',
+                    'element_name' => 'category.products',
+                    'action_name'  => 'move',
+                    'action_data'  => array(
+                        'destination_container' => 'content',
+                        'after'          => '-',
+                    ),
+                ),
+                array(
+                    'handle'       => '',
+                    'change_type'  => '',
+                    'element_name' => '',
+                    'action_name'  => '',
+                ),
+            ),
+        ));
+    }
+}
diff --git a/dev/tests/integration/testsuite/Mage/DesignEditor/Model/ObserverTest.php b/dev/tests/integration/testsuite/Mage/DesignEditor/Model/ObserverTest.php
index 3aefbd7d9ff..bd2de96f132 100644
--- a/dev/tests/integration/testsuite/Mage/DesignEditor/Model/ObserverTest.php
+++ b/dev/tests/integration/testsuite/Mage/DesignEditor/Model/ObserverTest.php
@@ -117,9 +117,9 @@ class Mage_DesignEditor_Model_ObserverTest extends PHPUnit_Framework_TestCase
     public function testAddToolbar()
     {
         $layoutUpdate = Mage::app()->getLayout()->getUpdate();
-        $this->assertNotContains(Mage_DesignEditor_Model_Observer::TOOLBAR_HANDLE, $layoutUpdate->getHandles());
+        $this->assertNotContains(Mage_DesignEditor_Model_Observer::HANDLE_TOOLBAR, $layoutUpdate->getHandles());
         $this->_observer->addToolbar($this->_eventObserver);
-        $this->assertContains(Mage_DesignEditor_Model_Observer::TOOLBAR_HANDLE, $layoutUpdate->getHandles());
+        $this->assertContains(Mage_DesignEditor_Model_Observer::HANDLE_TOOLBAR, $layoutUpdate->getHandles());
     }
 
     /**
@@ -167,8 +167,15 @@ class Mage_DesignEditor_Model_ObserverTest extends PHPUnit_Framework_TestCase
      */
     public function testWrapPageElement($elementName, $elementHtml, $expectedOutput)
     {
+        //@TODO Consider remaking the test cause now it's very fragile.
+        // Trivial change of wrapper template requires modifications in data provider
+
         $actualOutput = $this->_wrapElement($elementName, $elementHtml);
-        $this->assertXmlStringEqualsXmlString("<root>$expectedOutput</root>", "<root>$actualOutput</root>");
+        $this->assertXmlStringEqualsXmlString(
+            "<root>$expectedOutput</root>",
+            "<root>$actualOutput</root>",
+            "\n" . $expectedOutput . "\ndiffers from\n" . $actualOutput
+        );
     }
 
     /**
@@ -176,6 +183,9 @@ class Mage_DesignEditor_Model_ObserverTest extends PHPUnit_Framework_TestCase
      */
     public function wrapPageElementDataProvider()
     {
+        $removeLink = sprintf('<a href="#remove"><img src="%s" alt="Remove" /></a>',
+            Mage::getDesign()->getSkinUrl('images/btn_remove.gif')
+        );
         return array(
             'non-draggable block' => array(
                 'non_draggable_block',
@@ -190,15 +200,19 @@ class Mage_DesignEditor_Model_ObserverTest extends PHPUnit_Framework_TestCase
             'draggable block' => array(
                 'draggable_block',
                 '<b>Draggable Block</b>',
-                '<div id="vde_element_ZHJhZ2dhYmxlX2Jsb2Nr" class="vde_element_wrapper vde_draggable">
+                '<div id="vde_element_ZHJhZ2dhYmxlX2Jsb2Nr" class="vde_element_wrapper vde_draggable vde_removable"
+                    data-name="draggable_block">
                     <div class="vde_element_title">draggable_block</div>
+                    <div class="vde_element_title vde_element_remove"
+                        id="vde_element_ZHJhZ2dhYmxlX2Jsb2Nr_remove">' . $removeLink . '</div>
                     <b>Draggable Block</b>
                 </div>',
             ),
             'non-draggable container' => array(
                 'non_draggable_container',
                 '<b>Non-Draggable Container Text</b>',
-                '<div id="vde_element_bm9uX2RyYWdnYWJsZV9jb250YWluZXI" class="vde_element_wrapper vde_container">
+                '<div id="vde_element_bm9uX2RyYWdnYWJsZV9jb250YWluZXI" class="vde_element_wrapper vde_container"
+                    data-name="non_draggable_container">
                     <div class="vde_element_title">Non-Draggable Container</div>
                     <b>Non-Draggable Container Text</b>
                 </div>',
@@ -207,8 +221,11 @@ class Mage_DesignEditor_Model_ObserverTest extends PHPUnit_Framework_TestCase
                 'draggable_container',
                 '<b>Draggable Container Text</b>',
                 '<div id="vde_element_ZHJhZ2dhYmxlX2NvbnRhaW5lcg"
-                    class="vde_element_wrapper vde_draggable vde_container">
+                    class="vde_element_wrapper vde_draggable vde_removable vde_container"
+                    data-name="draggable_container">
                     <div class="vde_element_title">Draggable Container</div>
+                    <div class="vde_element_title vde_element_remove"
+                        id="vde_element_ZHJhZ2dhYmxlX2NvbnRhaW5lcg_remove">' . $removeLink . '</div>
                     <b>Draggable Container Text</b>
                 </div>',
             ),
@@ -216,7 +233,8 @@ class Mage_DesignEditor_Model_ObserverTest extends PHPUnit_Framework_TestCase
                 'after_body_start',
                 '<b>Page Top Container Text</b>',
                 '<div>VDE Toolbar</div>
-                <div id="vde_element_YWZ0ZXJfYm9keV9zdGFydA" class="vde_element_wrapper vde_container">
+                <div id="vde_element_YWZ0ZXJfYm9keV9zdGFydA" class="vde_element_wrapper vde_container"
+                    data-name="after_body_start">
                     <div class="vde_element_title">Page Top</div>
                     <b>Page Top Container Text</b>
                 </div>',
@@ -230,11 +248,21 @@ class Mage_DesignEditor_Model_ObserverTest extends PHPUnit_Framework_TestCase
      */
     public function testWrapPageElementHighlightingDisabled()
     {
+        //@TODO Consider remaking the test cause now it's very fragile.
+        // Trivial change of wrapper template requires modifications in data provider
+
         $elementName = 'draggable_block';
         $elementHtml = '<b>Draggable Block</b>';
         $expectedOutputFormat =
-            '<div id="vde_element_ZHJhZ2dhYmxlX2Jsb2Nr" class="vde_element_wrapper vde_draggable vde_wrapper_hidden">%w'
+            '<div id="vde_element_ZHJhZ2dhYmxlX2Jsb2Nr" '
+                . 'class="vde_element_wrapper vde_draggable vde_removable vde_wrapper_hidden" '
+                . 'data-name="draggable_block">%w'
                 . '<div class="vde_element_title">draggable_block</div>%w'
+                . '<div class="vde_element_title vde_element_remove" id="vde_element_ZHJhZ2dhYmxlX2Jsb2Nr_remove">%w'
+                    . '<a href="#remove">%w'
+                        . '<img src="' . Mage::getDesign()->getSkinUrl('images/btn_remove.gif') . '" alt="Remove" />%w'
+                    . '</a>%w'
+                . '</div>%w'
             . '</div>%w'
             . '<!--start_vde_element_ZHJhZ2dhYmxlX2Jsb2Nr-->%w'
             . '<b>Draggable Block</b>%w'
diff --git a/dev/tests/integration/testsuite/Mage/DesignEditor/_files/history/compact_log.xml b/dev/tests/integration/testsuite/Mage/DesignEditor/_files/history/compact_log.xml
new file mode 100644
index 00000000000..90e4508c245
--- /dev/null
+++ b/dev/tests/integration/testsuite/Mage/DesignEditor/_files/history/compact_log.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Academic Free License (AFL 3.0)
+ * that is bundled with this package in the file LICENSE_AFL.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/afl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @category    Mage
+ * @package     Mage_DesignEditor
+ * @subpackage  integration_tests
+ * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/afl-3.0.php  Academic Free License (AFL 3.0)
+ */
+-->
+<layout>
+    <catalog_category_view>
+        <remove name="category.products"/>
+    </catalog_category_view>
+    <customer_account>
+        <move element="customer_account_navigation" as="customer_account_navigation_alias" destination="top.menu" after="-"/>
+    </customer_account>
+</layout>
diff --git a/dev/tests/integration/testsuite/Mage/ImportExport/Model/Import/Entity/CustomerCompositeTest.php b/dev/tests/integration/testsuite/Mage/ImportExport/Model/Import/Entity/CustomerCompositeTest.php
deleted file mode 100644
index 256a12e1090..00000000000
--- a/dev/tests/integration/testsuite/Mage/ImportExport/Model/Import/Entity/CustomerCompositeTest.php
+++ /dev/null
@@ -1,196 +0,0 @@
-<?php
-/**
- * Magento
- *
- * NOTICE OF LICENSE
- *
- * This source file is subject to the Open Software License (OSL 3.0)
- * that is bundled with this package in the file LICENSE.txt.
- * It is also available through the world-wide-web at this URL:
- * http://opensource.org/licenses/osl-3.0.php
- * If you did not receive a copy of the license and are unable to
- * obtain it through the world-wide-web, please send an email
- * to license@magentocommerce.com so we can send you a copy immediately.
- *
- * DISCLAIMER
- *
- * Do not edit or add to this file if you wish to upgrade Magento to newer
- * versions in the future. If you wish to customize Magento for your
- * needs please refer to http://www.magentocommerce.com for more information.
- *
- * @category    Magento
- * @package     Mage_ImportExport
- * @subpackage  integration_tests
- * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
- * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
- */
-
-/**
- * Test class for Mage_ImportExport_Model_Import_Entity_CustomerComposite
- */
-class Mage_ImportExport_Model_Import_Entity_CustomerCompositeTest extends PHPUnit_Framework_TestCase
-{
-    /**
-     * Composite customer entity adapter instance
-     *
-     * @var Mage_ImportExport_Model_Import_Entity_CustomerComposite
-     */
-    protected $_entityAdapter;
-
-    /**
-     * Additional customer attributes for assertion
-     *
-     * @var array
-     */
-    protected $_customerAttributes = array('firstname', 'lastname');
-
-    /**
-     * Customers and addresses before import, address ID is postcode
-     *
-     * @var array
-     */
-    protected $_beforeImport = array(
-        'betsyparker@example.com' => array(
-            'addresses' => array('19107', '72701'),
-            'data' => array(
-                'firstname' => 'Betsy',
-                'lastname'  => 'Parker',
-            ),
-        ),
-    );
-
-    /**
-     * Customers and addresses after import, address ID is postcode
-     *
-     * @var array
-     */
-    protected $_afterImport = array(
-        'betsyparker@example.com'   => array(
-            'addresses' => array('19107', '72701', '19108'),
-            'data' => array(
-                'firstname' => 'NotBetsy',
-                'lastname'  => 'NotParker',
-            ),
-        ),
-        'anthonyanealy@magento.com' => array('addresses' => array('72701', '92664')),
-        'loribbanks@magento.com'    => array('addresses' => array('98801')),
-        'kellynilson@magento.com'   => array('addresses' => array()),
-    );
-
-    public function setUp()
-    {
-        $this->_entityAdapter = new Mage_ImportExport_Model_Import_Entity_CustomerComposite();
-    }
-
-    public function tearDown()
-    {
-        unset($this->_entityAdapter);
-    }
-
-    /**
-     * Test import data method with add/update behaviour
-     *
-     * @param string $behavior
-     * @param string $sourceFile
-     * @param array $dataBefore
-     * @param array $dataAfter
-     * @param array $errors
-     *
-     * @dataProvider importDataDataProvider
-     * @magentoDataFixture Mage/ImportExport/_files/customers_for_address_import.php
-     * @covers Mage_ImportExport_Model_Import_Entity_CustomerComposite::_importData
-     */
-    public function testImportData($behavior, $sourceFile, array $dataBefore, array $dataAfter, array $errors = array())
-    {
-        $this->markTestIncomplete('Need to be fixed.');
-
-        // set entity adapter parameters
-        $this->_entityAdapter->setParameters(array('behavior' => $behavior));
-
-        // set fixture CSV file
-        $result = $this->_entityAdapter
-            ->setSource(Mage_ImportExport_Model_Import_Adapter::findAdapterFor($sourceFile))
-            ->isDataValid();
-        if ($errors) {
-            $this->assertFalse($result);
-        } else {
-            $this->assertTrue($result);
-        }
-
-        // assert validation errors
-        // can't use error codes because entity adapter gathers only error messages from aggregated adapters
-        $actualErrors = array_values($this->_entityAdapter->getErrorMessages());
-        $this->assertEquals($errors, $actualErrors);
-
-        // assert data before import
-        $this->_assertCustomerData($dataBefore);
-
-        // import data
-        $this->_entityAdapter->importData();
-
-        // assert data after import
-        $this->_assertCustomerData($dataAfter);
-    }
-
-    /**
-     * Assertion of current customer and address data
-     *
-     * @param array $expectedData
-     */
-    protected function _assertCustomerData(array $expectedData)
-    {
-        /** @var $collection Mage_Customer_Model_Resource_Customer_Collection */
-        $collection = Mage::getResourceModel('Mage_Customer_Model_Resource_Customer_Collection');
-
-        $collection->addAttributeToSelect($this->_customerAttributes);
-        $customers = $collection->getItems();
-
-        $this->assertSameSize($expectedData, $customers);
-
-        /** @var $customer Mage_Customer_Model_Customer */
-        foreach ($customers as $customer) {
-            // assert customer existence
-            $email = strtolower($customer->getEmail());
-            $this->assertArrayHasKey($email, $expectedData);
-
-            // assert customer data (only for required customers)
-            if (isset($expectedData[$email]['data'])) {
-                foreach ($expectedData[$email]['data'] as $attribute => $expectedValue) {
-                    $this->assertEquals($expectedValue, $customer->getData($attribute));
-                }
-            }
-
-            // assert address data
-            $addresses = $customer->getAddresses();
-            $this->assertSameSize($expectedData[$email]['addresses'], $addresses);
-            /** @var $address Mage_Customer_Model_Address */
-            foreach ($addresses as $address) {
-                $this->assertContains($address->getData('postcode'), $expectedData[$email]['addresses']);
-            }
-        }
-    }
-
-    /**
-     * Data provider for testImportData
-     *
-     * @return array
-     */
-    public function importDataDataProvider()
-    {
-        return array(
-            'add_update_behavior' => array(
-                '$behavior'   => Mage_ImportExport_Model_Import::BEHAVIOR_ADD_UPDATE,
-                '$sourceFile' => __DIR__ . '/_files/customer_composite_update.csv',
-                '$dataBefore' => $this->_beforeImport,
-                '$dataAfter'  => $this->_afterImport,
-                '$errors'     => array(array(6)),     // row #6 has no website
-            ),
-            'delete_behavior' => array(
-                '$behavior'   => Mage_ImportExport_Model_Import::BEHAVIOR_DELETE,
-                '$sourceFile' => __DIR__ . '/_files/customer_composite_delete.csv',
-                '$dataBefore' => $this->_beforeImport,
-                '$dataAfter'  => array(),
-            ),
-        );
-    }
-}
diff --git a/dev/tests/integration/testsuite/Mage/ImportExport/Model/Import/Entity/Product/Type/AbstractTest.php b/dev/tests/integration/testsuite/Mage/ImportExport/Model/Import/Entity/Product/Type/AbstractTest.php
new file mode 100644
index 00000000000..367a05001d5
--- /dev/null
+++ b/dev/tests/integration/testsuite/Mage/ImportExport/Model/Import/Entity/Product/Type/AbstractTest.php
@@ -0,0 +1,114 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @category    Magento
+ * @package     Magento_ImportExport
+ * @subpackage  integration_tests
+ * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+class Mage_ImportExport_Model_Import_Entity_Product_Type_AbstractTest extends PHPUnit_Framework_TestCase
+{
+    /**
+     * @var Mage_ImportExport_Model_Import_Entity_Product_Type_Abstract
+     */
+    protected $_model;
+
+    /**
+     * On product import abstract class methods level it doesn't matter what product type is using.
+     * That is why current tests are using simple product entity type by default
+     */
+    public function setUp()
+    {
+        $arguments = array(array(new Mage_ImportExport_Model_Import_Entity_Product, 'simple'));
+        $this->_model = $this->getMockForAbstractClass(
+            'Mage_ImportExport_Model_Import_Entity_Product_Type_Abstract',
+            $arguments
+        );
+    }
+
+    protected function tearDown()
+    {
+        $this->_model = null;
+    }
+
+    /**
+     * @dataProvider prepareAttributesWithDefaultValueForSaveDataProvider
+     */
+    public function testPrepareAttributesWithDefaultValueForSave($rowData, $withDefaultValue, $expectedAttributes)
+    {
+        $actualAttributes = $this->_model->prepareAttributesWithDefaultValueForSave($rowData, $withDefaultValue);
+        foreach ($expectedAttributes as $key => $value) {
+            $this->assertArrayHasKey($key, $actualAttributes);
+            $this->assertEquals($value, $actualAttributes[$key]);
+        }
+    }
+
+    public function prepareAttributesWithDefaultValueForSaveDataProvider()
+    {
+        return array(
+            'Updating existing product with attributes that don\'t have default values' => array(
+                array('sku' => 'simple_product_1', 'price' => 55, '_attribute_set' => 'Default', '_type' => 'simple'),
+                false,
+                array('price' => 55)
+            ),
+            'Updating existing product with attributes that do have default values' => array(
+                array(
+                    'sku' => 'simple_product_2', 'price' => 65, '_attribute_set' => 'Default', '_type' => 'simple',
+                    'visibility' => 1, 'msrp_enabled' => 'Yes', 'tax_class_id' => ''
+                ),
+                false,
+                array('price' => 65, 'visibility' => 1, 'msrp_enabled' => 1, 'tax_class_id' => ''),
+            ),
+            'Adding new product with attributes that don\'t have default values' => array(
+                array(
+                    'sku' => 'simple_product_3', '_store' => '', '_attribute_set' => 'Default', '_type' => 'simple',
+                    '_category' => '_root_category', '_product_websites' => 'base', 'name' => 'Simple Product 3',
+                    'price' => 150, 'status' => 1, 'tax_class_id' => '0', 'weight' => 1, 'description' => 'a',
+                    'short_description' => 'a', 'visibility' => 1
+                ),
+                true,
+                array(
+                    'name' => 'Simple Product 3',
+                    'price' => 150, 'status' => 1, 'tax_class_id' => '0', 'weight' => 1, 'description' => 'a',
+                    'short_description' => 'a', 'visibility' => 1, 'options_container' => 'container2',
+                    'msrp_enabled' => 2, 'msrp_display_actual_price_type' => 4
+                )
+            ),
+            'Adding new product with attributes that do have default values' => array(
+                array(
+                    'sku' => 'simple_product_4', '_store' => '', '_attribute_set' => 'Default', '_type' => 'simple',
+                    '_category' => '_root_category', '_product_websites' => 'base', 'name' => 'Simple Product 4',
+                    'price' => 100, 'status' => 1, 'tax_class_id' => '0', 'weight' => 1, 'description' => 'a',
+                    'short_description' => 'a', 'visibility' => 2, 'msrp_enabled' => 'Yes',
+                    'msrp_display_actual_price_type' => 'In Cart'
+                ),
+                true,
+                array(
+                    'name' => 'Simple Product 4',
+                    'price' => 100, 'status' => 1, 'tax_class_id' => '0', 'weight' => 1, 'description' => 'a',
+                    'short_description' => 'a', 'visibility' => 2, 'options_container' => 'container2',
+                    'msrp_enabled' => 1, 'msrp_display_actual_price_type' => 2
+                )
+            ),
+        );
+    }
+}
diff --git a/dev/tests/integration/testsuite/Mage/ImportExport/Model/Import/Entity/ProductTest.php b/dev/tests/integration/testsuite/Mage/ImportExport/Model/Import/Entity/ProductTest.php
index 5324d7dc817..95763615208 100644
--- a/dev/tests/integration/testsuite/Mage/ImportExport/Model/Import/Entity/ProductTest.php
+++ b/dev/tests/integration/testsuite/Mage/ImportExport/Model/Import/Entity/ProductTest.php
@@ -64,6 +64,85 @@ class Mage_ImportExport_Model_Import_Entity_ProductTest extends PHPUnit_Framewor
      */
     protected $_assertOptionValues = array('title', 'price', 'sku');
 
+    /**
+     * Test if visibility properly saved after import
+     *
+     * @magentoDataFixture Mage/Catalog/_files/multiple_products.php
+     */
+    public function testSaveProductsVisibility()
+    {
+        $existingProductIds = array(10, 11, 12);
+        $productsBeforeImport = array();
+        foreach ($existingProductIds as $productId) {
+            $product = new Mage_Catalog_Model_Product();
+            $product->load($productId);
+            $productsBeforeImport[] = $product;
+        }
+
+        $source = new Mage_ImportExport_Model_Import_Adapter_Csv(__DIR__ . '/_files/products_to_import.csv');
+        $this->_model->setParameters(array(
+            'behavior' => Mage_ImportExport_Model_Import::BEHAVIOR_REPLACE,
+            'entity' => 'catalog_product'
+        ))->setSource($source)->isDataValid();
+
+        $this->_model->importData();
+
+        /** @var $productBeforeImport Mage_Catalog_Model_Product */
+        foreach ($productsBeforeImport as $productBeforeImport) {
+            /** @var $productAfterImport Mage_Catalog_Model_Product */
+            $productAfterImport = new Mage_Catalog_Model_Product();
+            $productAfterImport->load($productBeforeImport->getId());
+
+            $this->assertEquals(
+                $productBeforeImport->getVisibility(),
+                $productAfterImport->getVisibility()
+            );
+            unset($productAfterImport);
+        }
+
+        unset($productsBeforeImport, $product);
+    }
+
+    /**
+     * Test if stock item quantity properly saved after import
+     *
+     * @magentoDataFixture Mage/Catalog/_files/multiple_products.php
+     */
+    public function testSaveStockItemQty()
+    {
+        $existingProductIds = array(10, 11, 12);
+        $stockItems = array();
+        foreach ($existingProductIds as $productId) {
+            $stockItem = new Mage_CatalogInventory_Model_Stock_Item();
+            $stockItem->loadByProduct($productId);
+            $stockItems[$productId] = $stockItem;
+        }
+
+        $source = new Mage_ImportExport_Model_Import_Adapter_Csv(__DIR__ . '/_files/products_to_import.csv');
+        $this->_model->setParameters(array(
+            'behavior' => Mage_ImportExport_Model_Import::BEHAVIOR_REPLACE,
+            'entity' => 'catalog_product'
+        ))->setSource($source)->isDataValid();
+
+        $this->_model->importData();
+
+        /** @var $stockItmBeforeImport Mage_CatalogInventory_Model_Stock_Item */
+        foreach ($stockItems as $productId => $stockItmBeforeImport) {
+
+            /** @var $stockItemAfterImport Mage_CatalogInventory_Model_Stock_Item */
+            $stockItemAfterImport = new Mage_CatalogInventory_Model_Stock_Item();
+            $stockItemAfterImport->loadByProduct($productId);
+
+            $this->assertEquals(
+                $stockItmBeforeImport->getQty(),
+                $stockItemAfterImport->getQty()
+            );
+            unset($stockItemAfterImport);
+        }
+
+        unset($stockItems, $stockItem);
+    }
+
     /**
      * Tests adding of custom options with different behaviours
      *
diff --git a/dev/tests/integration/testsuite/Mage/ImportExport/Model/Import/Entity/_files/customer_composite_delete.csv b/dev/tests/integration/testsuite/Mage/ImportExport/Model/Import/Entity/_files/customer_composite_delete.csv
deleted file mode 100644
index 427df554c77..00000000000
--- a/dev/tests/integration/testsuite/Mage/ImportExport/Model/Import/Entity/_files/customer_composite_delete.csv
+++ /dev/null
@@ -1,2 +0,0 @@
-"email","_website","_store","confirmation","created_at","created_in","disable_auto_group_change","dob","firstname","gender","group_id","lastname","middlename","password_hash","prefix","reward_update_notification","reward_warning_notification","rp_token","rp_token_created_at","store_id","suffix","taxvat","website_id","password","_address_city","_address_company","_address_country_id","_address_fax","_address_firstname","_address_lastname","_address_middlename","_address_postcode","_address_prefix","_address_region","_address_street","_address_suffix","_address_telephone","_address_vat_id","_address_default_billing_","_address_default_shipping_"
-"BetsyParker@example.com","admin","admin",,"05/06/2012 16:13","Admin",0,,"NotBetsy","Female",1,"NotParker","H.","145d12bfff8a6a279eb61e277e3d727c0ba95acc1131237f1594ddbb7687a564:l1",,1,1,,,0,,,2,,"Philadelphia",,"US",,"Betsy","Parker",,19108,,"Pennsylvania","1079 Rocky Road 1079 Rocky Road 2",,"215-629-9720",,1,1
diff --git a/dev/tests/integration/testsuite/Mage/ImportExport/Model/Import/Entity/_files/customer_composite_update.csv b/dev/tests/integration/testsuite/Mage/ImportExport/Model/Import/Entity/_files/customer_composite_update.csv
deleted file mode 100644
index 5c21b7674c0..00000000000
--- a/dev/tests/integration/testsuite/Mage/ImportExport/Model/Import/Entity/_files/customer_composite_update.csv
+++ /dev/null
@@ -1,7 +0,0 @@
-"email","_website","_store","confirmation","created_at","created_in","disable_auto_group_change","dob","firstname","gender","group_id","lastname","middlename","password_hash","prefix","reward_update_notification","reward_warning_notification","rp_token","rp_token_created_at","store_id","suffix","taxvat","website_id","password","_address_city","_address_company","_address_country_id","_address_fax","_address_firstname","_address_lastname","_address_middlename","_address_postcode","_address_prefix","_address_region","_address_street","_address_suffix","_address_telephone","_address_vat_id","_address_default_billing_","_address_default_shipping_"
-"AnthonyANealy@magento.com","base","admin",,"05/06/2012 15:53","Admin",0,,"Anthony","Male",1,"Nealy","A.","6a9c9bfb2ba88a6ad2a64e7402df44a763e0c48cd21d7af9e7e796cd4677ee28:RF",,1,1,,,0,,,1,,"Fayetteville",,"US",,"Anthony","Nealy",,72701,,"Arkansas","3176 Cambridge Court",,"479-899-9849",,1,1
-,,,,,,,,,,,,,,,,,,,,,,,,"Irvine",,"US",,"Anthony","Nealy",,92664,,"California","4709 Pleasant Hill Road",,"562-208-2310",,,
-"LoriBBanks@magento.com","admin","admin",,"05/06/2012 15:59","Admin",0,,"Lori","Female",1,"Banks","B.","7ad6dbdc83d3e9f598825dc58b84678c7351e4281f6bc2b277a32dcd88b9756b:pz",,1,1,,,0,,,0,,"Wenatchee",,"US",,"Lori","Banks",,98801,,"Washington","2573 Goodwin Avenue",,"509-421-4364",,1,1
-"BetsyParker@example.com","admin","admin",,"05/06/2012 16:13","Admin",0,,"NotBetsy","Female",1,"NotParker","H.","145d12bfff8a6a279eb61e277e3d727c0ba95acc1131237f1594ddbb7687a564:l1",,1,1,,,0,,,2,,"Philadelphia",,"US",,"Betsy","Parker",,19108,,"Pennsylvania","1079 Rocky Road 1079 Rocky Road 2",,"215-629-9720",,1,1
-"KellyNIlson@magento.com","base","admin",,"05/06/2012 17:11","Admin",0,,"Kelly","Female",1,"Nilson","H.","145d12bfff8a6a279eb61e277e3d727c0ba95acc1131237f1594ddbb7687a564:l1",,1,1,,,0,,,2,,,,,,,,,,,,,,,,,
-"MichaelJackson@magento.com",,"admin",,"05/06/2012 17:11","Admin",0,,"Michael","Male",1,"Jackson","J.","145d12bfff8a6a279eb61e277e3d727c0ba95acc1131237f1594ddbb7687a564:l1",,1,1,,,0,,,2,,,,,,,,,,,,,,,,,
diff --git a/dev/tests/integration/testsuite/Mage/ImportExport/Model/Import/Entity/_files/products_to_import.csv b/dev/tests/integration/testsuite/Mage/ImportExport/Model/Import/Entity/_files/products_to_import.csv
new file mode 100644
index 00000000000..fd5768ec076
--- /dev/null
+++ b/dev/tests/integration/testsuite/Mage/ImportExport/Model/Import/Entity/_files/products_to_import.csv
@@ -0,0 +1,4 @@
+sku,price
+simple1,25
+simple2,34
+simple3,58
diff --git a/dev/tests/integration/testsuite/Mage/Page/_files/robots.txt b/dev/tests/integration/testsuite/Mage/Page/_files/robots.txt
index d260f6d139e..ea8baf9ec1a 100644
--- a/dev/tests/integration/testsuite/Mage/Page/_files/robots.txt
+++ b/dev/tests/integration/testsuite/Mage/Page/_files/robots.txt
@@ -4,7 +4,6 @@ Disallow: /*?
 Disallow: /*.js$
 Disallow: /*.css$
 Disallow: /checkout/
-Disallow: /tag/
 Disallow: /app/
 Disallow: /downloader/
 Disallow: /js/
diff --git a/dev/tests/integration/testsuite/Mage/Review/_files/reviews.php b/dev/tests/integration/testsuite/Mage/Review/_files/reviews.php
index 6b793dfcba3..8757c225a31 100644
--- a/dev/tests/integration/testsuite/Mage/Review/_files/reviews.php
+++ b/dev/tests/integration/testsuite/Mage/Review/_files/reviews.php
@@ -25,7 +25,7 @@
  * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
  */
 
-require __DIR__ . '/../../Catalog/_files/two_products.php';
+require __DIR__ . '/../../Catalog/_files/multiple_products.php';
 
 $review = new Mage_Review_Model_Review(array(
     'nickname' => 'Nickname', 'title' => 'Review Summary', 'detail' => 'Review text'
diff --git a/dev/tests/integration/testsuite/Mage/Rss/controllers/CatalogControllerTest.php b/dev/tests/integration/testsuite/Mage/Rss/controllers/CatalogControllerTest.php
index 17218c97834..7a1d2e7074d 100644
--- a/dev/tests/integration/testsuite/Mage/Rss/controllers/CatalogControllerTest.php
+++ b/dev/tests/integration/testsuite/Mage/Rss/controllers/CatalogControllerTest.php
@@ -113,7 +113,7 @@ class Mage_Rss_CatalogControllerTest extends Magento_Test_TestCase_ControllerAbs
     }
 
     /**
-     * @magentoDataFixture Mage/Catalog/_files/two_products.php
+     * @magentoDataFixture Mage/Catalog/_files/multiple_products.php
      * @magentoConfigFixture current_store cataloginventory/item_options/notify_stock_qty 75
      */
     public function testNotifyStockAction()
@@ -129,6 +129,7 @@ class Mage_Rss_CatalogControllerTest extends Magento_Test_TestCase_ControllerAbs
         $body = $this->getResponse()->getBody();
         $this->assertNotContains('<![CDATA[Simple Product]]>', $body); // this one was supposed to have qty 100 ( > 75)
         $this->assertContains('<![CDATA[Simple Product2]]>', $body); // 50 < 75
+        $this->assertNotContains('<![CDATA[Simple Product 3]]>', $body);// this one was supposed to have qty 140 ( > 75)
     }
 
     /**
@@ -140,7 +141,7 @@ class Mage_Rss_CatalogControllerTest extends Magento_Test_TestCase_ControllerAbs
         $this->dispatch('rss/catalog/review');
         $this->assertHeaderPcre('Content-Type', '/text\/xml/');
         $body = $this->getResponse()->getBody();
-        $this->assertContains('"Simple Product2"', $body);
+        $this->assertContains('"Simple Product 3"', $body);
         $this->assertContains('Review text', $body);
     }
 
diff --git a/dev/tests/js/testsuite/mage/design_editor/historyTest.js b/dev/tests/js/testsuite/mage/design_editor/historyTest.js
new file mode 100644
index 00000000000..b4d92d40da4
--- /dev/null
+++ b/dev/tests/js/testsuite/mage/design_editor/historyTest.js
@@ -0,0 +1,30 @@
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Academic Free License (AFL 3.0)
+ * that is bundled with this package in the file LICENSE_AFL.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/afl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @category    mage.design_editor
+ * @package     test
+ * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/afl-3.0.php  Academic Free License (AFL 3.0)
+ */
+HistoryTest = TestCase('HistoryTest');
+HistoryTest.prototype.testInit = function() {
+    jQuery(window).vde_history();
+    assertEquals(true, jQuery(window).is(':vde-vde_history'));
+    jQuery(window).vde_history('destroy');
+};
diff --git a/dev/tests/js/testsuite/mage/design_editor/historyToolbarTest.js b/dev/tests/js/testsuite/mage/design_editor/historyToolbarTest.js
new file mode 100644
index 00000000000..8026c0c4f3d
--- /dev/null
+++ b/dev/tests/js/testsuite/mage/design_editor/historyToolbarTest.js
@@ -0,0 +1,31 @@
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Academic Free License (AFL 3.0)
+ * that is bundled with this package in the file LICENSE_AFL.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/afl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @category    mage.design_editor
+ * @package     test
+ * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/afl-3.0.php  Academic Free License (AFL 3.0)
+ */
+HistoryToolbarTest = TestCase('HistoryToolbarTest');
+HistoryToolbarTest.prototype.testInit = function() {
+    /*:DOC += <div class="vde_history_toolbar"></div> */
+    var container = jQuery('.vde_history_toolbar').vde_historyToolbar();
+    assertEquals(true, container.is(':vde-vde_historyToolbar'));
+    container.vde_historyToolbar('destroy');
+};
diff --git a/dev/tests/js/testsuite/mage/design_editor/pageTest.js b/dev/tests/js/testsuite/mage/design_editor/pageTest.js
index 4d4069bb7b9..fe36f7729cb 100644
--- a/dev/tests/js/testsuite/mage/design_editor/pageTest.js
+++ b/dev/tests/js/testsuite/mage/design_editor/pageTest.js
@@ -1,4 +1,4 @@
-/**
+/**
  * Magento
  *
  * NOTICE OF LICENSE
@@ -15,188 +15,232 @@
  *
  * Do not edit or add to this file if you wish to upgrade Magento to newer
  * versions in the future. If you wish to customize Magento for your
- * needs please refer to http://www.magentocommerce.com for more information.
- *
- * @category    mage.design_editor
- * @package     test
- * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
- * @license     http://opensource.org/licenses/afl-3.0.php  Academic Free License (AFL 3.0)
- */
-PageTest = TestCase('PageTest');
-PageTest.prototype.testInit = function() {
-    var page = jQuery('body').vde_page();
-    assertEquals(true, page.is(':vde-vde_page'));
-    page.vde_page('destroy');
-};
-PageTest.prototype.testDefaultOptions = function() {
-    var page = jQuery('body').vde_page();
-    assertEquals('.vde_element_wrapper.vde_container', page.vde_page('option', 'containerSelector'));
-    assertEquals('#vde_toolbar', page.vde_page('option', 'panelSelector'));
-    assertEquals('.vde_element_wrapper', page.vde_page('option', 'highlightElementSelector'));
-    assertEquals('.vde_element_title', page.vde_page('option', 'highlightElementTitleSelector'));
-    assertEquals('#vde_highlighting', page.vde_page('option', 'highlightCheckboxSelector'));
-    assertEquals('vde_highlighting', page.vde_page('option', 'cookieHighlightingName'));
-    page.vde_page('destroy');
-};
-PageTest.prototype.testInitContainers = function() {
-    /*:DOC += <div class="vde_element_wrapper vde_container"></div> */
-    var page = jQuery('body').vde_page();
-    var containerSelector = page.vde_page('option', 'containerSelector');
-    assertEquals(true, jQuery(containerSelector).is(':vde-vde_container'));
-    page.vde_page('destroy');
-}
-PageTest.prototype.testInitPanel = function() {
-    /*:DOC += <div id="vde_toolbar"></div> */
-    var page = jQuery('body').vde_page();
-    var panelSelector = page.vde_page('option', 'panelSelector');
-    assertEquals(true, jQuery(panelSelector).is(':vde-vde_panel'));
-    page.vde_page('destroy');
-}
-PageTest.prototype.testInitHighlighting = function() {
-    /*:DOC += <div id="vde_toolbar"><div id="vde_highlighting"></div></div> */
-    var page = jQuery('body').vde_page();
-    var highlightCheckboxSelector = page.vde_page('option', 'highlightCheckboxSelector');
-    assertEquals(true, jQuery(highlightCheckboxSelector).is(':vde-vde_checkbox'));
-    page.vde_page('destroy');
-}
-PageTest.prototype.testProcessMarkers = function() {
-    /*:DOC +=
-    <div>
-        <div id="vde_element_1" class="vde_element_wrapper vde_container vde_wrapper_hidden">
-            <div class="vde_element_title">Title 1</div>
-        </div>
-        <!--start_vde_element_1-->
-        <div id="vde_element_2" class="vde_element_wrapper vde_draggable vde_wrapper_hidden">
-            <div class="vde_element_title">Title 2</div>
-        </div>
-        <!--start_vde_element_2-->
-        <div class="block block-list">
-            <div class="block-title">
-                <strong><span>Block Title</span></strong>
-            </div>
-            <div class="block-content">
-                <p class="empty">Block Content</p>
-            </div>
-        </div>
-        <!--end_vde_element_2-->
-        <!--end_vde_element_1-->
-    </div>
-    */
-    var page = jQuery('body').vde_page();
-    var cookieHighlightingName = page.vde_page('option', 'cookieHighlightingName');
-    page.vde_page('destroy');
-    Mage.Cookies.set(cookieHighlightingName, 'off');
-    page = jQuery('body').vde_page();
-    var commentsExist = false;
-    jQuery('*').contents().each(function () {
-        if (this.nodeType == Node.COMMENT_NODE) {
-            if (this.data.substr(0, 9) == 'start_vde') {
-                commentsExist = true;
-            } else if (this.data.substr(0, 7) == 'end_vde') {
-                commentsExist = true;
-            }
-        }
-    });
-    assertEquals(false, commentsExist);
-}
-PageTest.prototype.testHighlight = function() {
-    /*:DOC +=
-    <div>
-        <div id="vde_element_1" class="vde_element_wrapper vde_container vde_wrapper_hidden">
-            <div class="vde_element_title">Title 1</div>
-        </div>
-        <!--start_vde_element_1-->
-        <div id="vde_element_2" class="vde_element_wrapper vde_draggable vde_wrapper_hidden">
-            <div class="vde_element_title">Title 2</div>
-        </div>
-        <!--start_vde_element_2-->
-        <div class="block block-list" id="block">
-            <div class="block-title">
-                <strong><span>Block Title</span></strong>
-            </div>
-            <div class="block-content">
-                <p class="empty">Block Content</p>
-            </div>
-        </div>
-        <!--end_vde_element_2-->
-        <div id="vde_element_3" class="vde_element_wrapper vde_draggable vde_wrapper_hidden">
-            <div class="vde_element_title">Title 3</div>
-        </div>
-        <!--end_vde_element_1-->
-    </div>
-    */
-    jQuery.fx.off = true;
-    var page = jQuery('body').vde_page();
-    var cookieHighlightingName = page.vde_page('option', 'cookieHighlightingName');
-    page.vde_page('destroy');
-    Mage.Cookies.set(cookieHighlightingName, 'off');
-    page = jQuery('body').vde_page();
-    page.trigger('checked.vde_checkbox');
-    var resultHierarchy = {
-        vde_element_1: ['vde_element_2', 'vde_element_3'],
-        vde_element_2: ['block']
-    }
-    var hierarchyIsCorrect = true;
-    jQuery.each(resultHierarchy, function(parentKey, parentVal) {
-        jQuery.each(parentVal, function(childKey, childVal) {
-            if (!jQuery('#' + parentKey).has(jQuery('#' + childVal))) {
-                hierarchyIsCorrect = false;
-            }
-        })
-    });
-    assertEquals(true, hierarchyIsCorrect);
-    assertEquals(true, jQuery('.vde_wrapper_hidden').is(':visible'));
-    assertEquals(null, Mage.Cookies.get(cookieHighlightingName));
-    var highlightElementTitleSelector = page.vde_page('option', 'highlightElementTitleSelector');
-    assertEquals(true, jQuery(highlightElementTitleSelector).is(':visible'));
-    page.vde_page('destroy');
-    jQuery.fx.off = false;
-}
-PageTest.prototype.testUnhighlight = function() {
-    /*:DOC +=
-    <div>
-        <div id="vde_element_1" class="vde_element_wrapper vde_container">
-            <div class="vde_element_title">Title 1</div>
-            <div id="vde_element_2" class="vde_element_wrapper vde_draggable">
-                <div class="vde_element_title">Title 2</div>
-                <div class="block block-list block-compare" id="block">
-                    <div class="block-title">
-                        <strong><span>Block Title</span></strong>
-                    </div>
-                    <div class="block-content">
-                        <p class="empty">Block Content</p>
-                    </div>
-                </div>
-            </div>
-        </div>
-    </div>
-    */
-    jQuery.fx.off = true;
-    var page = jQuery('body').vde_page();
-    var highlightElementTitleSelector = page.vde_page('option', 'highlightElementTitleSelector');
-    var highlightElementSelector = page.vde_page('option', 'highlightElementSelector');
-    var hierarchy = {};
-    jQuery(highlightElementSelector).each(function() {
-        var elem = jQuery(this);
-        hierarchy[elem.attr('id')] = elem.contents(':not(' + highlightElementTitleSelector + ')');
-    })
-    var cookieHighlightingName = page.vde_page('option', 'cookieHighlightingName');
-    page.vde_page('destroy');
-    Mage.Cookies.clear(cookieHighlightingName);
-    page = jQuery('body').vde_page();
-    page.trigger('unchecked.vde_checkbox');
-    var hierarchyIsCorrect = true;
-    jQuery.each(hierarchy, function(parentKey, parentVal) {
-        jQuery.each(parentVal, function() {
-            if (jQuery(this).parents('#' + parentKey).size()) {
-                hierarchyIsCorrect = false;
-            }
-        })
-    });
-    assertEquals(true, hierarchyIsCorrect);
-    assertEquals(false, jQuery('.vde_wrapper_hidden').is(':visible'));
-    assertEquals('off', Mage.Cookies.get(cookieHighlightingName));
-    assertEquals(false, jQuery(highlightElementTitleSelector).is(':visible'));
-    page.vde_page('destroy');
-    jQuery.fx.off = false;
-}
\ No newline at end of file
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @category    mage.design_editor
+ * @package     test
+ * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/afl-3.0.php  Academic Free License (AFL 3.0)
+ */
+PageTest = TestCase('PageTest');
+PageTest.prototype.testInit = function() {
+    var page = jQuery('body').vde_page();
+    assertEquals(true, page.is(':vde-vde_page'));
+    page.vde_page('destroy');
+};
+PageTest.prototype.testDefaultOptions = function() {
+    var page = jQuery('body').vde_page();
+    assertEquals('.vde_element_wrapper.vde_container', page.vde_page('option', 'containerSelector'));
+    assertEquals('#vde_toolbar', page.vde_page('option', 'panelSelector'));
+    assertEquals('.vde_element_wrapper', page.vde_page('option', 'highlightElementSelector'));
+    assertEquals('.vde_element_title', page.vde_page('option', 'highlightElementTitleSelector'));
+    assertEquals('#vde_highlighting', page.vde_page('option', 'highlightCheckboxSelector'));
+    assertEquals('vde_highlighting', page.vde_page('option', 'cookieHighlightingName'));
+    page.vde_page('destroy');
+};
+PageTest.prototype.testInitContainers = function() {
+    /*:DOC += <div class="vde_element_wrapper vde_container"></div> */
+    var page = jQuery('body').vde_page();
+    var containerSelector = page.vde_page('option', 'containerSelector');
+    assertEquals(true, jQuery(containerSelector).is(':vde-vde_container'));
+    page.vde_page('destroy');
+}
+PageTest.prototype.testInitPanel = function() {
+    /*:DOC += <div id="vde_toolbar"></div> */
+    var page = jQuery('body').vde_page();
+    var panelSelector = page.vde_page('option', 'panelSelector');
+    assertEquals(true, jQuery(panelSelector).is(':vde-vde_panel'));
+    page.vde_page('destroy');
+}
+PageTest.prototype.testInitHighlighting = function() {
+    /*:DOC += <div id="vde_toolbar"><div id="vde_highlighting"></div></div> */
+    var page = jQuery('body').vde_page();
+    var highlightCheckboxSelector = page.vde_page('option', 'highlightCheckboxSelector');
+    assertEquals(true, jQuery(highlightCheckboxSelector).is(':vde-vde_checkbox'));
+    page.vde_page('destroy');
+}
+PageTest.prototype.testProcessMarkers = function() {
+    /*:DOC +=
+    <div>
+        <div id="vde_element_1" class="vde_element_wrapper vde_container vde_wrapper_hidden">
+            <div class="vde_element_title">Title 1</div>
+        </div>
+        <!--start_vde_element_1-->
+        <div id="vde_element_2" class="vde_element_wrapper vde_draggable vde_wrapper_hidden">
+            <div class="vde_element_title">Title 2</div>
+        </div>
+        <!--start_vde_element_2-->
+        <div class="block block-list">
+            <div class="block-title">
+                <strong><span>Block Title</span></strong>
+            </div>
+            <div class="block-content">
+                <p class="empty">Block Content</p>
+            </div>
+        </div>
+        <!--end_vde_element_2-->
+        <!--end_vde_element_1-->
+    </div>
+    */
+    var page = jQuery('body').vde_page();
+    var cookieHighlightingName = page.vde_page('option', 'cookieHighlightingName');
+    page.vde_page('destroy');
+    Mage.Cookies.set(cookieHighlightingName, 'off');
+    page = jQuery('body').vde_page();
+    var commentsExist = false;
+    jQuery('*').contents().each(function () {
+        if (this.nodeType == Node.COMMENT_NODE) {
+            if (this.data.substr(0, 9) == 'start_vde') {
+                commentsExist = true;
+            } else if (this.data.substr(0, 7) == 'end_vde') {
+                commentsExist = true;
+            }
+        }
+    });
+    assertEquals(false, commentsExist);
+}
+PageTest.prototype.testHighlight = function() {
+    /*:DOC +=
+    <div>
+        <div id="vde_element_1" class="vde_element_wrapper vde_container vde_wrapper_hidden">
+            <div class="vde_element_title">Title 1</div>
+        </div>
+        <!--start_vde_element_1-->
+        <div id="vde_element_2" class="vde_element_wrapper vde_draggable vde_wrapper_hidden">
+            <div class="vde_element_title">Title 2</div>
+        </div>
+        <!--start_vde_element_2-->
+        <div class="block block-list" id="block">
+            <div class="block-title">
+                <strong><span>Block Title</span></strong>
+            </div>
+            <div class="block-content">
+                <p class="empty">Block Content</p>
+            </div>
+        </div>
+        <!--end_vde_element_2-->
+        <div id="vde_element_3" class="vde_element_wrapper vde_draggable vde_wrapper_hidden">
+            <div class="vde_element_title">Title 3</div>
+        </div>
+        <!--end_vde_element_1-->
+    </div>
+    */
+    jQuery.fx.off = true;
+    var page = jQuery('body').vde_page();
+    var cookieHighlightingName = page.vde_page('option', 'cookieHighlightingName');
+    page.vde_page('destroy');
+    Mage.Cookies.set(cookieHighlightingName, 'off');
+    page = jQuery('body').vde_page();
+    page.trigger('checked.vde_checkbox');
+    var resultHierarchy = {
+        vde_element_1: ['vde_element_2', 'vde_element_3'],
+        vde_element_2: ['block']
+    }
+    var hierarchyIsCorrect = true;
+    jQuery.each(resultHierarchy, function(parentKey, parentVal) {
+        jQuery.each(parentVal, function(childKey, childVal) {
+            if (!jQuery('#' + parentKey).has(jQuery('#' + childVal))) {
+                hierarchyIsCorrect = false;
+            }
+        })
+    });
+    assertEquals(true, hierarchyIsCorrect);
+    assertEquals(true, jQuery('.vde_wrapper_hidden').is(':visible'));
+    assertEquals(null, Mage.Cookies.get(cookieHighlightingName));
+    var highlightElementTitleSelector = page.vde_page('option', 'highlightElementTitleSelector');
+    assertEquals(true, jQuery(highlightElementTitleSelector).is(':visible'));
+    page.vde_page('destroy');
+    jQuery.fx.off = false;
+}
+PageTest.prototype.testUnhighlight = function() {
+    /*:DOC +=
+    <div>
+        <div id="vde_element_1" class="vde_element_wrapper vde_container">
+            <div class="vde_element_title">Title 1</div>
+            <div id="vde_element_2" class="vde_element_wrapper vde_draggable">
+                <div class="vde_element_title">Title 2</div>
+                <div class="block block-list block-compare" id="block">
+                    <div class="block-title">
+                        <strong><span>Block Title</span></strong>
+                    </div>
+                    <div class="block-content">
+                        <p class="empty">Block Content</p>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+    */
+    jQuery.fx.off = true;
+    var page = jQuery('body').vde_page();
+    var highlightElementTitleSelector = page.vde_page('option', 'highlightElementTitleSelector');
+    var highlightElementSelector = page.vde_page('option', 'highlightElementSelector');
+    var hierarchy = {};
+    jQuery(highlightElementSelector).each(function() {
+        var elem = jQuery(this);
+        hierarchy[elem.attr('id')] = elem.contents(':not(' + highlightElementTitleSelector + ')');
+    })
+    var cookieHighlightingName = page.vde_page('option', 'cookieHighlightingName');
+    page.vde_page('destroy');
+    Mage.Cookies.clear(cookieHighlightingName);
+    page = jQuery('body').vde_page();
+    page.trigger('unchecked.vde_checkbox');
+    var hierarchyIsCorrect = true;
+    jQuery.each(hierarchy, function(parentKey, parentVal) {
+        jQuery.each(parentVal, function() {
+            if (jQuery(this).parents('#' + parentKey).size()) {
+                hierarchyIsCorrect = false;
+            }
+        })
+    });
+    assertEquals(true, hierarchyIsCorrect);
+    assertEquals(false, jQuery('.vde_wrapper_hidden').is(':visible'));
+    assertEquals('off', Mage.Cookies.get(cookieHighlightingName));
+    assertEquals(false, jQuery(highlightElementTitleSelector).is(':visible'));
+    page.vde_page('destroy');
+    jQuery.fx.off = false;
+}
+PageTest.prototype.testInitHistory = function() {
+    var page = jQuery('body').vde_page();
+    assertEquals(true, jQuery(window).is(':vde-vde_history'));
+    page.vde_page('destroy');
+}
+PageTest.prototype.testInitHistoryToolbar = function() {
+    /*:DOC += <div class="vde_history_toolbar"></div> */
+    jQuery(window).vde_page();
+    var container = jQuery('.vde_history_toolbar');
+    assertEquals(true, container.is(':vde-vde_historyToolbar'));
+    assertNotNull(container.data('vde_historyToolbar')._history);
+    jQuery(window).vde_page('destroy');
+};
+PageTest.prototype.testInitRemoveOperation = function() {
+    /*:DOC += <div class="vde_element_wrapper"></div> */
+    jQuery(window).vde_page();
+    var containers = jQuery('.vde_element_wrapper');
+    assertEquals(true, containers.is(':vde-vde_removable'));
+    jQuery(window).vde_page('destroy');
+};
+PageTest.prototype.testSetHistoryForContainers = function() {
+    jQuery(window).vde_page();
+    var containers = jQuery('.vde_element_wrapper.vde_container');
+    assertNotNull(containers.vde_container('getHistory'));
+    jQuery(window).vde_page('destroy');
+};
+PageTest.prototype.testDestroy = function() {
+    /*:DOC +=
+     <div id="vde_toolbar"></div>
+     <div class="vde_history_toolbar"></div>
+     <div class="vde_element_wrapper vde_container"></div>
+     */
+
+    jQuery(window).vde_page();
+    jQuery(window).vde_page('destroy');
+
+    //check no garbage is left
+    assertFalse($('#vde_toolbar').is(':vde-vde_panel'));
+    assertFalse($('.vde_history_toolbar').is(':vde-vde_historyToolbar'));
+    assertFalse($(window).is(':vde-vde_history'));
+    assertFalse($('.vde_element_wrapper').is(':vde-vde_removable'));
+    assertFalse($('.vde_element_wrapper.vde_container').is(':vde-vde_container'));
+};
+
diff --git a/dev/tests/performance/framework/Magento/Scenario.php b/dev/tests/performance/framework/Magento/Scenario.php
index 1358203b6f9..87211f62c72 100644
--- a/dev/tests/performance/framework/Magento/Scenario.php
+++ b/dev/tests/performance/framework/Magento/Scenario.php
@@ -108,6 +108,9 @@ class Magento_Scenario
             ));
         }
 
+        // Run before-the-scenario PHP script (if exists)
+        $beforeOutput = $this->_runScenarioAdditionalScript($scenarioFile, 'before');
+
         // Dry run - just to warm-up the system
         $dryScenarioParams = array_merge($scenarioParams, array(self::PARAM_USERS => 1, self::PARAM_LOOPS => 2));
         $this->_runScenario($scenarioFile, $dryScenarioParams);
@@ -116,6 +119,15 @@ class Magento_Scenario
         $fullScenarioParams = $scenarioParams + array(self::PARAM_USERS => 1, self::PARAM_LOOPS => 1);
         $reportFile = $this->_reportDir . DIRECTORY_SEPARATOR . basename($scenarioFile, '.jmx') . '.jtl';
         $this->_runScenario($scenarioFile, $fullScenarioParams, $reportFile);
+
+        // Run after-the-scenario PHP script (if exists)
+        $scenarioExecutions = $dryScenarioParams[self::PARAM_USERS] * $dryScenarioParams[self::PARAM_LOOPS]
+            + $fullScenarioParams[self::PARAM_USERS] * $fullScenarioParams[self::PARAM_LOOPS];
+        $params = array(
+            'beforeOutput' => $beforeOutput,
+            'scenarioExecutions' => $scenarioExecutions,
+        );
+        $this->_runScenarioAdditionalScript($scenarioFile, 'after', $params);
     }
 
     /**
@@ -184,4 +196,34 @@ class Magento_Scenario
             throw new Magento_Exception(implode(PHP_EOL, $failureMessages));
         }
     }
+
+    /**
+     * Execute additional before/after scenario PHP script, if it exists
+     *
+     * @param string $scenarioFile
+     * @param string $suffix
+     * @param array $params
+     * @return null|string
+     * @throws Magento_Exception
+     */
+    protected function _runScenarioAdditionalScript($scenarioFile, $suffix, $params = array())
+    {
+        // Check existence of additional script
+        $pathinfo = pathinfo($scenarioFile);
+        $scriptFile = $pathinfo['dirname'] . DIRECTORY_SEPARATOR . "{$pathinfo['filename']}_{$suffix}.php";
+        if (!file_exists($scriptFile)) {
+            return null;
+        }
+
+        // Run script
+        $cmd = 'php %s';
+        $execParams = array($scriptFile);
+        foreach ($params as $key => $value) {
+            $cmd .= " --{$key}=%s";
+            $execParams[] = $value;
+        }
+        $output = $this->_shell->execute($cmd, $execParams);
+
+        return $output;
+    }
 }
diff --git a/dev/tests/performance/framework/tests/unit/testsuite/Magento/ConfigTest.php b/dev/tests/performance/framework/tests/unit/testsuite/Magento/ConfigTest.php
index c4c160b1ace..2c81b341bc8 100644
--- a/dev/tests/performance/framework/tests/unit/testsuite/Magento/ConfigTest.php
+++ b/dev/tests/performance/framework/tests/unit/testsuite/Magento/ConfigTest.php
@@ -150,6 +150,10 @@ class Magento_ConfigTest extends PHPUnit_Framework_TestCase
                 'param1' => 'value 1',
                 'param2' => 'value 2',
             ),
+            $dir . '/scenario_with_scripts.jmx' => array(
+                'param1' => 'value 1',
+                'param2' => 'value 2',
+            ),
         );
 
         $actualScenarios = $this->_object->getScenarios();
diff --git a/dev/tests/performance/framework/tests/unit/testsuite/Magento/ScenarioTest.php b/dev/tests/performance/framework/tests/unit/testsuite/Magento/ScenarioTest.php
index 4c5f7f0d0c4..6c79d740625 100644
--- a/dev/tests/performance/framework/tests/unit/testsuite/Magento/ScenarioTest.php
+++ b/dev/tests/performance/framework/tests/unit/testsuite/Magento/ScenarioTest.php
@@ -135,4 +135,31 @@ class Magento_ScenarioTest extends PHPUnit_Framework_TestCase
             ),
         );
     }
+
+    public function testRunWithScripts()
+    {
+        $scenarioFile = realpath(__DIR__ . '/_files/scenario_with_scripts.jmx');
+        $scriptBefore = realpath(__DIR__ . '/_files/scenario_with_scripts_before.php');
+        $scriptAfter = realpath(__DIR__ . '/_files/scenario_with_scripts_after.php');
+
+        $this->_shell
+            ->expects($this->at(0))
+            ->method('execute')
+            ->with('php %s', array($scriptBefore))
+            ->will($this->returnValue('fixture output'));
+
+        $this->_shell
+            ->expects($this->at(3))
+            ->method('execute')
+            ->with(
+                'php %s --beforeOutput=%s --scenarioExecutions=%s',
+                array(
+                    $scriptAfter,
+                    'fixture output',
+                    4, // 2 warm-up executions + 2 users x 1 loop
+                )
+            );
+
+        $this->_object->run($scenarioFile, $this->_scenarioParams);
+    }
 }
diff --git a/dev/tests/performance/framework/tests/unit/testsuite/Magento/_files/scenario_with_scripts.jmx b/dev/tests/performance/framework/tests/unit/testsuite/Magento/_files/scenario_with_scripts.jmx
new file mode 100644
index 00000000000..a48e5b549e6
--- /dev/null
+++ b/dev/tests/performance/framework/tests/unit/testsuite/Magento/_files/scenario_with_scripts.jmx
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Academic Free License (AFL 3.0)
+ * that is bundled with this package in the file LICENSE_AFL.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/afl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @category    Magento
+ * @package     performance_tests
+ * @subpackage  unit_tests
+ * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/afl-3.0.php  Academic Free License (AFL 3.0)
+ */
+-->
+<jmeterTestPlan/>
diff --git a/dev/tests/performance/framework/tests/unit/testsuite/Magento/_files/scenario_with_scripts.jtl b/dev/tests/performance/framework/tests/unit/testsuite/Magento/_files/scenario_with_scripts.jtl
new file mode 100644
index 00000000000..f21637327db
--- /dev/null
+++ b/dev/tests/performance/framework/tests/unit/testsuite/Magento/_files/scenario_with_scripts.jtl
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Academic Free License (AFL 3.0)
+ * that is bundled with this package in the file LICENSE_AFL.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/afl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @category    Magento
+ * @package     performance_tests
+ * @subpackage  unit_tests
+ * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/afl-3.0.php  Academic Free License (AFL 3.0)
+ */
+-->
+<testResults version="1.2">
+    <httpSample>
+        <assertionResult>
+            <name>Response Assertion</name>
+            <failure>false</failure>
+            <error>false</error>
+        </assertionResult>
+    </httpSample>
+</testResults>
diff --git a/dev/tests/performance/framework/tests/unit/testsuite/Magento/_files/scenario_with_scripts_after.php b/dev/tests/performance/framework/tests/unit/testsuite/Magento/_files/scenario_with_scripts_after.php
new file mode 100644
index 00000000000..4b190a120f8
--- /dev/null
+++ b/dev/tests/performance/framework/tests/unit/testsuite/Magento/_files/scenario_with_scripts_after.php
@@ -0,0 +1,28 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @category    Magento
+ * @package     performance_tests
+ * @subpackage  unit_tests
+ * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+// Nothing here, just file existence is needed
diff --git a/dev/tests/performance/framework/tests/unit/testsuite/Magento/_files/scenario_with_scripts_before.php b/dev/tests/performance/framework/tests/unit/testsuite/Magento/_files/scenario_with_scripts_before.php
new file mode 100644
index 00000000000..4b190a120f8
--- /dev/null
+++ b/dev/tests/performance/framework/tests/unit/testsuite/Magento/_files/scenario_with_scripts_before.php
@@ -0,0 +1,28 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @category    Magento
+ * @package     performance_tests
+ * @subpackage  unit_tests
+ * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+// Nothing here, just file existence is needed
diff --git a/dev/tests/performance/testsuite/_samples/add_to_cart.jmx b/dev/tests/performance/testsuite/add_to_cart.jmx
similarity index 100%
rename from dev/tests/performance/testsuite/_samples/add_to_cart.jmx
rename to dev/tests/performance/testsuite/add_to_cart.jmx
diff --git a/dev/tests/performance/testsuite/advanced_search.jmx b/dev/tests/performance/testsuite/advanced_search.jmx
index 3de6928aa91..497cf17a8b6 100644
--- a/dev/tests/performance/testsuite/advanced_search.jmx
+++ b/dev/tests/performance/testsuite/advanced_search.jmx
@@ -104,7 +104,7 @@
           <stringProp name="HTTPSampler.embedded_url_re"></stringProp>
         </HTTPSamplerProxy>
         <hashTree>
-          <ResponseAssertion guiclass="AssertionGui" testclass="ResponseAssertion" testname="Response Assertion" enabled="true">
+          <ResponseAssertion guiclass="AssertionGui" testclass="ResponseAssertion" testname="Assertion: Header Presence" enabled="true">
             <collectionProp name="Asserion.test_strings">
               <stringProp name="-462078532">&lt;h1&gt;Catalog Advanced Search&lt;/h1&gt;</stringProp>
             </collectionProp>
@@ -178,17 +178,24 @@
           <stringProp name="HTTPSampler.embedded_url_re"></stringProp>
         </HTTPSamplerProxy>
         <hashTree>
-          <ResponseAssertion guiclass="AssertionGui" testclass="ResponseAssertion" testname="Response Assertion" enabled="true">
+          <ResponseAssertion guiclass="AssertionGui" testclass="ResponseAssertion" testname="Assertion: Non-Empty Search Results" enabled="true">
             <collectionProp name="Asserion.test_strings">
-              <stringProp name="1106631744">were found using the following search criteria</stringProp>
-              <stringProp name="1756567765">${search_parameter1}</stringProp>
-              <stringProp name="1756567796">${search_parameter2}</stringProp>
+              <stringProp name="110843263">No items were found using the following search criteria</stringProp>
             </collectionProp>
             <stringProp name="Assertion.test_field">Assertion.response_data</stringProp>
             <boolProp name="Assertion.assume_success">false</boolProp>
-            <intProp name="Assertion.test_type">2</intProp>
+            <intProp name="Assertion.test_type">6</intProp>
           </ResponseAssertion>
           <hashTree/>
+          <XPathAssertion guiclass="XPathAssertionGui" testclass="XPathAssertion" testname="Assertion: Product Found" enabled="true">
+            <boolProp name="XPath.negate">false</boolProp>
+            <stringProp name="XPath.xpath">//h2[@class=&quot;product-name&quot;]/a[@title=&quot;${search_parameter1}&quot; and text()=&quot;${search_parameter1}&quot;]</stringProp>
+            <boolProp name="XPath.validate">false</boolProp>
+            <boolProp name="XPath.whitespace">false</boolProp>
+            <boolProp name="XPath.tolerant">false</boolProp>
+            <boolProp name="XPath.namespace">false</boolProp>
+          </XPathAssertion>
+          <hashTree/>
         </hashTree>
       </hashTree>
       <CookieManager guiclass="CookiePanel" testclass="CookieManager" testname="HTTP Cookie Manager" enabled="true">
diff --git a/dev/tests/performance/testsuite/_samples/checkout.jmx b/dev/tests/performance/testsuite/checkout.jmx
similarity index 100%
rename from dev/tests/performance/testsuite/_samples/checkout.jmx
rename to dev/tests/performance/testsuite/checkout.jmx
diff --git a/dev/tests/performance/testsuite/checkout_after.php b/dev/tests/performance/testsuite/checkout_after.php
new file mode 100644
index 00000000000..a5fd2f95291
--- /dev/null
+++ b/dev/tests/performance/testsuite/checkout_after.php
@@ -0,0 +1,49 @@
+<?php
+/**
+ * Script to retrieve number of orders after checkout scenario execution, and to compare it to the expected value.
+ *
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @category    Magento
+ * @package     Mage_Sales
+ * @subpackage  performance_tests
+ * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+// Parse parameters
+$params = getopt('', array('beforeOutput:', 'scenarioExecutions:'));
+preg_match("/Num orders: (\\d+)/", $params['beforeOutput'], $matches);
+$numOrdersBefore = $matches[1];
+$expectedOrdersCreated = $params['scenarioExecutions'];
+
+// Retrieve current number of orders and calculate number of orders created
+require_once __DIR__ . '/../../../../app/bootstrap.php';
+Mage::app('', 'store');
+$collection = new Mage_Sales_Model_Resource_Order_Collection();
+$numOrdersNow = $collection->getSize();
+$actualOrdersCreated = $numOrdersNow - $numOrdersBefore;
+
+// Compare number of new orders to the expected value
+if ($expectedOrdersCreated != $actualOrdersCreated) {
+    echo "Failure: expected {$expectedOrdersCreated} new orders, while actually created {$actualOrdersCreated}";
+    exit(1);
+}
+
+echo "Verification successful, {$actualOrdersCreated} of {$expectedOrdersCreated} orders created";
diff --git a/dev/tests/performance/testsuite/checkout_before.php b/dev/tests/performance/testsuite/checkout_before.php
new file mode 100644
index 00000000000..5fa72008138
--- /dev/null
+++ b/dev/tests/performance/testsuite/checkout_before.php
@@ -0,0 +1,33 @@
+<?php
+/**
+ * Script to retrieve number of orders before checkout scenario execution
+ *
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @category    Magento
+ * @package     Mage_Sales
+ * @subpackage  performance_tests
+ * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+require_once __DIR__ . '/../../../../app/bootstrap.php';
+Mage::app('', 'store');
+$collection = new Mage_Sales_Model_Resource_Order_Collection();
+echo "Num orders: ", $collection->getSize(), PHP_EOL;
diff --git a/dev/tests/performance/testsuite/_samples/product_edit.jmx b/dev/tests/performance/testsuite/product_edit.jmx
similarity index 100%
rename from dev/tests/performance/testsuite/_samples/product_edit.jmx
rename to dev/tests/performance/testsuite/product_edit.jmx
diff --git a/dev/tests/static/testsuite/Legacy/_files/obsolete_methods.php b/dev/tests/static/testsuite/Legacy/_files/obsolete_methods.php
index b68f844959c..c8b5b38baac 100644
--- a/dev/tests/static/testsuite/Legacy/_files/obsolete_methods.php
+++ b/dev/tests/static/testsuite/Legacy/_files/obsolete_methods.php
@@ -116,7 +116,7 @@ return array(
     'addConstraint' => array('class_scope' => 'Varien_Db_Adapter_Pdo_Mysql'),
     'addCustomersToAlertQueueAction',
     'addCustomerToSegments',
-    'addGroupByTag' => array('class_scope' => 'Mage_Reports_Model_Resource_Tag_Collection'),
+    'addGroupByTag' => array('class_scope' => 'Mage_Tag_Model_Resource_Reports_Collection'),
     'addKey' => array('class_scope' => 'Varien_Db_Adapter_Pdo_Mysql'),
     'addSaleableFilterToCollection',
     'addSearchQfFilter',
@@ -376,4 +376,5 @@ return array(
     'validateDataArray' => array('class_scope' => 'Varien_Convert_Container_Abstract'),
     'validateFile' => array('class_scope' => 'Mage_Core_Model_Design_Package'),
     'validateOrder' => array('class_scope' => 'Mage_Checkout_Model_Type_Onepage'),
+    'prepareAttributesForSave' => array('class_scope' => 'Mage_ImportExport_Model_Import_Entity_Product')
 );
diff --git a/dev/tests/static/testsuite/Php/_files/whitelist/core.txt b/dev/tests/static/testsuite/Php/_files/whitelist/core.txt
index 852e4d30ddf..667e040416a 100644
--- a/dev/tests/static/testsuite/Php/_files/whitelist/core.txt
+++ b/dev/tests/static/testsuite/Php/_files/whitelist/core.txt
@@ -29,6 +29,8 @@ app/code/core/Mage/Log/Model/Resource/Helper
 app/code/core/Mage/Log/Model/Resource/Shell.php
 app/code/core/Mage/Log/Model/Shell.php
 app/code/core/Mage/Rss/Controller/AdminhtmlAbstract.php
+app/code/core/Mage/Tag/Block/Adminhtml/Customer/Edit/Tab/Tag.php
+app/code/core/Mage/Tag/Block/Catalog/Product/Rss/Link.php
 app/code/core/Mage/User
 app/code/core/Mage/Core/Controller/Varien/Action/Forward.php
 app/code/core/Mage/Core/Controller/Varien/DispatchableInterface.php
diff --git a/dev/tests/unit/framework/bootstrap.php b/dev/tests/unit/framework/bootstrap.php
index f5feb1f5a8d..43cdc0f962b 100755
--- a/dev/tests/unit/framework/bootstrap.php
+++ b/dev/tests/unit/framework/bootstrap.php
@@ -29,10 +29,10 @@ define('TESTS_TEMP_DIR', dirname(__DIR__) . DIRECTORY_SEPARATOR . 'tmp');
 $includePaths = array(
     "./framework",
     './testsuite',
-    '../../../lib',
-    '../../../app/code/core',
     '../../../app/',
-    get_include_path()
+    '../../../app/code/core',
+    '../../../lib',
+    get_include_path(),
 );
 set_include_path(implode(PATH_SEPARATOR, $includePaths));
 spl_autoload_register('magentoAutoloadForUnitTests');
@@ -44,7 +44,7 @@ function magentoAutoloadForUnitTests($class)
         $fileName = $path . DIRECTORY_SEPARATOR . $file;
         if (file_exists($fileName)) {
             include $file;
-            if (class_exists($class, false)) {
+            if (class_exists($class, false) || interface_exists($class, false)) {
                 return true;
             }
         }
diff --git a/dev/tests/unit/testsuite/Mage/DesignEditor/Model/HistoryTest.php b/dev/tests/unit/testsuite/Mage/DesignEditor/Model/HistoryTest.php
new file mode 100644
index 00000000000..c1fa74fc428
--- /dev/null
+++ b/dev/tests/unit/testsuite/Mage/DesignEditor/Model/HistoryTest.php
@@ -0,0 +1,226 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @category    Magento
+ * @package     Mage_DesignEditor
+ * @subpackage  unit_tests
+ * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+class Mage_DesignEditor_Model_HistoryTest extends PHPUnit_Framework_TestCase
+{
+    /**
+     * @covers Mage_DesignEditor_Model_History::getCompactLog
+     */
+    public function testGetCompactLog()
+    {
+        $methods = array('_getManagerModel');
+        /** @var $historyMock Mage_DesignEditor_Model_History */
+        $historyMock = $this->getMock('Mage_DesignEditor_Model_History', $methods, array(), '', false);
+
+        $methods = array('getHistoryLog', 'addChange');
+        /** @var $managerMock Mage_DesignEditor_Model_History_Manager */
+        $managerMock = $this->getMock('Mage_DesignEditor_Model_History_Manager', $methods, array(), '', false);
+
+        $historyMock->expects($this->exactly(2))
+            ->method('_getManagerModel')
+            ->will($this->returnValue($managerMock));
+
+        $managerMock->expects($this->exactly(4))
+            ->method('addChange')
+            ->will($this->returnValue($managerMock));
+
+        $managerMock->expects($this->once())
+            ->method('getHistoryLog')
+            ->will($this->returnValue(array()));
+
+        $historyMock->setChangeLog($this->_getChangeLogData())->getCompactLog();
+    }
+
+    /**
+     * @covers Mage_DesignEditor_Model_History::getCompactLog
+     * @expectedException Mage_DesignEditor_Exception
+     */
+    public function testGetCompactLogWithInvalidData()
+    {
+        $this->_mockTranslationHelper();
+
+        $methods = array('_getManagerModel');
+        /** @var $historyMock Mage_DesignEditor_Model_History */
+        $historyMock = $this->getMock('Mage_DesignEditor_Model_History', $methods, array(), '', false);
+
+        $methods = array('addChange');
+        /** @var $managerMock Mage_DesignEditor_Model_History_Manager */
+        $managerMock = $this->getMock('Mage_DesignEditor_Model_History_Manager', $methods, array(), '', false);
+
+        $historyMock->expects($this->exactly(1))
+            ->method('_getManagerModel')
+            ->will($this->returnValue($managerMock));
+
+        $managerMock->expects($this->exactly(1))
+            ->method('addChange')
+            ->will($this->returnValue($managerMock));
+
+        $historyMock->setChangeLog($this->_getInvalidChangeLogData())->getCompactLog();
+    }
+
+    /**
+     * @covers Mage_DesignEditor_Model_History::getCompactXml
+     */
+    public function testGetCompactXml()
+    {
+        $methods = array('_getManagerModel');
+        /** @var $historyMock Mage_DesignEditor_Model_History */
+        $historyMock = $this->getMock('Mage_DesignEditor_Model_History', $methods, array(), '', false);
+
+        $methods = array('getXml', 'addChange');
+        /** @var $managerMock Mage_DesignEditor_Model_History_Manager */
+        $managerMock = $this->getMock('Mage_DesignEditor_Model_History_Manager', $methods, array(), '', false);
+
+        $historyMock->expects($this->exactly(2))
+            ->method('_getManagerModel')
+            ->will($this->returnValue($managerMock));
+
+        $managerMock->expects($this->exactly(4))
+            ->method('addChange')
+            ->will($this->returnValue($managerMock));
+
+        $managerMock->expects($this->once())
+            ->method('getXml')
+            ->will($this->returnValue(array()));
+
+        $historyMock->setChangeLog($this->_getChangeLogData())->getCompactXml();
+    }
+
+    /**
+     * @covers Mage_DesignEditor_Model_History::getCompactXml
+     * @expectedException Mage_DesignEditor_Exception
+     */
+    public function testGetCompactXmlWithInvalidData()
+    {
+        $this->_mockTranslationHelper();
+
+        $methods = array('_getManagerModel');
+        /** @var $historyMock Mage_DesignEditor_Model_History */
+        $historyMock = $this->getMock('Mage_DesignEditor_Model_History', $methods, array(), '', false);
+
+        $methods = array('addChange');
+        /** @var $managerMock Mage_DesignEditor_Model_History_Manager */
+        $managerMock = $this->getMock('Mage_DesignEditor_Model_History_Manager', $methods, array(), '', false);
+
+        $historyMock->expects($this->exactly(1))
+            ->method('_getManagerModel')
+            ->will($this->returnValue($managerMock));
+
+        $managerMock->expects($this->exactly(1))
+            ->method('addChange')
+            ->will($this->returnValue($managerMock));
+
+        $historyMock->setChangeLog($this->_getInvalidChangeLogData())->getCompactXml();
+    }
+
+    protected function _getChangeLogData()
+    {
+        return array(
+            array(
+                'handle'       => 'checkout_cart_index',
+                'change_type'  => 'layout',
+                'element_name' => 'checkout.cart',
+                'action_name'  => 'move',
+                'action_data'  => array(
+                    'destination_container' => 'content',
+                    'after'                 => '-',
+                ),
+            ),
+            array(
+                'handle'       => 'checkout_cart_index',
+                'change_type'  => 'layout',
+                'element_name' => 'checkout.cart',
+                'action_name'  => 'remove',
+                'action_data'  => array(),
+            ),
+            array(
+                'handle'       => 'customer_account',
+                'change_type'  => 'layout',
+                'element_name' => 'customer_account_navigation',
+                'action_name'  => 'move',
+                'action_data'  => array(
+                    'destination_container' => 'content',
+                    'after'                 => '-',
+                    'as'                    => 'customer_account_navigation_alias',
+                ),
+            ),
+            array(
+                'handle'       => 'customer_account',
+                'change_type'  => 'layout',
+                'element_name' => 'customer_account_navigation',
+                'action_name'  => 'move',
+                'action_data'  => array(
+                    'destination_container' => 'top.menu',
+                    'after'                 => '-',
+                    'as'                    => 'customer_account_navigation_alias',
+                ),
+            ),
+        );
+    }
+
+    protected function _getInvalidChangeLogData()
+    {
+        return array(
+            array(
+                'handle'       => 'checkout_cart_index',
+                'change_type'  => 'layout',
+                'element_name' => 'checkout.cart',
+                'action_name'  => 'move',
+                'action_data'  => array(
+                    'destination_container' => 'content',
+                    'after'                 => '-',
+                ),
+            ),
+            array(
+                'handle'       => '',
+                'change_type'  => '',
+                'element_name' => '',
+                'action_name'  => '',
+            ),
+        );
+    }
+
+    /**
+     * Add/remove mock for translation helper
+     *
+     * @param bool $add
+     * @return void
+     */
+    protected function _mockTranslationHelper($add = true)
+    {
+        Mage::unregister('_helper/Mage_DesignEditor_Helper_Data');
+        if ($add) {
+            $helper = $this->getMock('stdClass', array('__'));
+            $helper->expects($this->any())->method('__')->will($this->returnArgument(0));
+            Mage::register('_helper/Mage_DesignEditor_Helper_Data', $helper);
+        }
+    }
+}
+
+class Mage_DesignEditor_Model_HistoryTest_Exception extends Exception
+{
+}
diff --git a/dev/tests/unit/testsuite/Mage/DesignEditor/Model/Manager/Adapter/LayoutTest.php b/dev/tests/unit/testsuite/Mage/DesignEditor/Model/Manager/Adapter/LayoutTest.php
new file mode 100644
index 00000000000..69575262cfe
--- /dev/null
+++ b/dev/tests/unit/testsuite/Mage/DesignEditor/Model/Manager/Adapter/LayoutTest.php
@@ -0,0 +1,105 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @category    Magento
+ * @package     Mage_DesignEditor
+ * @subpackage  unit_tests
+ * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+class Mage_DesignEditor_Model_Manager_LayoutTest extends PHPUnit_Framework_TestCase
+{
+    /**
+     * @cove Mage_DesignEditor_Model_History_Manager_Adapter_Layout::addAction
+     * @dataProvider moveChangeData
+     */
+    public function testAddAction($name, $handle, $type, $action, $data)
+    {
+        /** @var $layoutMock Mage_DesignEditor_Model_History_Manager_Adapter_Layout */
+        $layoutMock = $this->getMock(
+            'Mage_DesignEditor_Model_History_Manager_Adapter_Layout', null, array(), '', false
+        );
+        $layoutMock->setHandle($handle)->setType($type)->setName($name)->addAction($action, $data);
+
+        $this->assertEquals($this->expectedMoveActionData(), $layoutMock->getData());
+    }
+
+    /**
+     * @cove Mage_DesignEditor_Model_History_Manager_Adapter_Layout::render
+     * @dataProvider changeData
+     */
+    public function testRenderRemove($expectedXml, $name, $handle, $type, $action, $data)
+    {
+        /** @var $layoutMock Mage_DesignEditor_Model_History_Manager_Adapter_Layout */
+        $layoutMock = $this->getMock(
+            'Mage_DesignEditor_Model_History_Manager_Adapter_Layout', null, array(), '', false
+        );
+        $xmlObject = new Varien_Simplexml_Element('<layout></layout>');
+        $layoutMock->setHandle($handle)->setHandleObject($xmlObject)->setType($type)->setName($name)
+            ->addAction($action, $data)->render();
+
+        $this->assertXmlStringEqualsXmlFile(
+            realpath(__DIR__) . '/../../_files/history/layout/' . $expectedXml, $xmlObject->asNiceXml()
+        );
+    }
+
+    public function changeData()
+    {
+        return array(
+            array(
+                'move.xml', 'customer_account_navigation', 'customer_account', 'layout', 'move', array(
+                    'destination_container' => 'top.menu',
+                    'after'                 => '-',
+                    'as'                    => 'customer_account_navigation_alias',
+                )
+            ),
+            array(
+                'remove.xml', 'customer_account_navigation', 'customer_account', 'layout', 'remove', array()
+            ),
+        );
+    }
+
+    public function moveChangeData()
+    {
+        return array(
+            array('customer_account_navigation', 'customer_account', 'layout', 'move', array(
+                'destination_container' => 'top.menu',
+                'after'                 => '-',
+                'as'                    => 'customer_account_navigation_alias',
+            )));
+    }
+
+    public function expectedMoveActionData()
+    {
+        return array(
+            'actions' => array(
+                'move' => array(
+                    'destination_container' => 'top.menu',
+                    'after'                 => '-',
+                    'as'                    => 'customer_account_navigation_alias',
+                )
+            ),
+            'handle' => 'customer_account',
+            'name'   => 'customer_account_navigation',
+            'type'   => 'layout'
+        );
+    }
+}
diff --git a/dev/tests/unit/testsuite/Mage/DesignEditor/Model/_files/history/layout/move.xml b/dev/tests/unit/testsuite/Mage/DesignEditor/Model/_files/history/layout/move.xml
new file mode 100644
index 00000000000..90a778d14f1
--- /dev/null
+++ b/dev/tests/unit/testsuite/Mage/DesignEditor/Model/_files/history/layout/move.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Academic Free License (AFL 3.0)
+ * that is bundled with this package in the file LICENSE_AFL.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/afl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @category    Magento
+ * @package     Mage_DesignEditor
+ * @subpackage  unit_tests
+ * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/afl-3.0.php  Academic Free License (AFL 3.0)
+ */
+-->
+<layout>
+    <move element="customer_account_navigation" as="customer_account_navigation_alias" destination="top.menu" after="-"/>
+</layout>
diff --git a/dev/tests/unit/testsuite/Mage/DesignEditor/Model/_files/history/layout/remove.xml b/dev/tests/unit/testsuite/Mage/DesignEditor/Model/_files/history/layout/remove.xml
new file mode 100644
index 00000000000..46a9cf4cddd
--- /dev/null
+++ b/dev/tests/unit/testsuite/Mage/DesignEditor/Model/_files/history/layout/remove.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Academic Free License (AFL 3.0)
+ * that is bundled with this package in the file LICENSE_AFL.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/afl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @category    Magento
+ * @package     Mage_DesignEditor
+ * @subpackage  unit_tests
+ * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/afl-3.0.php  Academic Free License (AFL 3.0)
+ */
+-->
+<layout>
+    <remove name="customer_account_navigation"/>
+</layout>
diff --git a/dev/tests/unit/testsuite/Mage/Tag/Block/Adminhtml/Catalog/Product/Edit/Tab/Tag/CustomerTest.php b/dev/tests/unit/testsuite/Mage/Tag/Block/Adminhtml/Catalog/Product/Edit/Tab/Tag/CustomerTest.php
new file mode 100644
index 00000000000..9d85a2ce098
--- /dev/null
+++ b/dev/tests/unit/testsuite/Mage/Tag/Block/Adminhtml/Catalog/Product/Edit/Tab/Tag/CustomerTest.php
@@ -0,0 +1,55 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @category    Mage
+ * @package     Mage_Tag
+ * @subpackage  unit_tests
+ * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+class Mage_Tag_Block_Adminhtml_Catalog_Product_Edit_Tab_Tag_CustomerTest
+    extends Mage_Tag_Block_Adminhtml_Catalog_Product_Edit_Tab_TagTestCaseAbstract
+{
+    /**
+     * @var string
+     */
+    protected $_modelName = 'Mage_Tag_Block_Adminhtml_Catalog_Product_Edit_Tab_Tag_Customer';
+
+    /**
+     * @var string
+     */
+    protected $_title = 'Customers Tagged Product';
+
+    /**
+     * @covers Mage_Tag_Block_Adminhtml_Catalog_Product_Edit_Tab_Tag_Customer::getTabLabel
+     * @covers Mage_Tag_Block_Adminhtml_Catalog_Product_Edit_Tab_Tag_Customer::getTabTitle
+     * @covers Mage_Tag_Block_Adminhtml_Catalog_Product_Edit_Tab_Tag_Customer::canShowTab
+     * @covers Mage_Tag_Block_Adminhtml_Catalog_Product_Edit_Tab_Tag_Customer::isHidden
+     * @covers Mage_Tag_Block_Adminhtml_Catalog_Product_Edit_Tab_Tag_Customer::getTabClass
+     * @covers Mage_Tag_Block_Adminhtml_Catalog_Product_Edit_Tab_Tag_Customer::getAfter
+     * @dataProvider methodListDataProvider
+     * @param string $method
+     */
+    public function testDefinedPublicMethods($method)
+    {
+        $this->$method();
+    }
+}
diff --git a/dev/tests/unit/testsuite/Mage/Tag/Block/Adminhtml/Catalog/Product/Edit/Tab/TagTest.php b/dev/tests/unit/testsuite/Mage/Tag/Block/Adminhtml/Catalog/Product/Edit/Tab/TagTest.php
new file mode 100644
index 00000000000..1bfbcf0e614
--- /dev/null
+++ b/dev/tests/unit/testsuite/Mage/Tag/Block/Adminhtml/Catalog/Product/Edit/Tab/TagTest.php
@@ -0,0 +1,56 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @category    Mage
+ * @package     Mage_Tag
+ * @subpackage  unit_tests
+ * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+class Mage_Tag_Block_Adminhtml_Catalog_Product_Edit_Tab_TagTest
+    extends Mage_Tag_Block_Adminhtml_Catalog_Product_Edit_Tab_TagTestCaseAbstract
+{
+    /**
+     * @var string
+     */
+    protected $_modelName = 'Mage_Tag_Block_Adminhtml_Catalog_Product_Edit_Tab_Tag';
+
+    /**
+     * @var string
+     */
+    protected $_title = 'Product Tags';
+
+    /**
+     * @covers Mage_Tag_Block_Adminhtml_Catalog_Product_Edit_Tab_Tag::getTabLabel
+     * @covers Mage_Tag_Block_Adminhtml_Catalog_Product_Edit_Tab_Tag::getTabTitle
+     * @covers Mage_Tag_Block_Adminhtml_Catalog_Product_Edit_Tab_Tag::canShowTab
+     * @covers Mage_Tag_Block_Adminhtml_Catalog_Product_Edit_Tab_Tag::isHidden
+     * @covers Mage_Tag_Block_Adminhtml_Catalog_Product_Edit_Tab_Tag::getTabClass
+     * @covers Mage_Tag_Block_Adminhtml_Catalog_Product_Edit_Tab_Tag::getAfter
+     *
+     * @dataProvider methodListDataProvider
+     * @param string $method
+     */
+    public function testDefinedPublicMethods($method)
+    {
+        $this->$method();
+    }
+}
diff --git a/dev/tests/unit/testsuite/Mage/Tag/Block/Adminhtml/Catalog/Product/Edit/Tab/TagTestCaseAbstract.php b/dev/tests/unit/testsuite/Mage/Tag/Block/Adminhtml/Catalog/Product/Edit/Tab/TagTestCaseAbstract.php
new file mode 100644
index 00000000000..124325bb850
--- /dev/null
+++ b/dev/tests/unit/testsuite/Mage/Tag/Block/Adminhtml/Catalog/Product/Edit/Tab/TagTestCaseAbstract.php
@@ -0,0 +1,135 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @category    Mage
+ * @package     Mage_Tag
+ * @subpackage  unit_tests
+ * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+class Mage_Tag_Block_Adminhtml_Catalog_Product_Edit_Tab_TagTestCaseAbstract extends PHPUnit_Framework_TestCase
+{
+    /**
+     * @var Mage_Tag_Block_Adminhtml_Catalog_Product_Edit_Tab_Tag
+     */
+    protected $_model;
+
+    /**
+     * @var string
+     */
+    protected $_modelName;
+
+    /**
+     * @var string
+     */
+    protected $_title;
+
+    /**
+     * @var array
+     */
+    protected $_testedMethods = array(
+        'getTabLabel',
+        'getTabTitle',
+        'canShowTab',
+        'isHidden',
+        'getTabClass',
+        'getAfter'
+    );
+
+    protected function setUp()
+    {
+        $helperMock = $this->getMock('Mage_Tag_Helper_Data', array('__'), array(), '', false);
+        $helperMock->expects($this->any())
+            ->method('__')
+            ->will($this->returnArgument(0));
+
+        $authSession = $this->getMock('Mage_Backend_Model_Auth_Session', array('isAllowed'), array(), '', false);
+        $authSession->expects($this->any())
+            ->method('isAllowed')
+            ->will($this->returnCallback(array($this, 'isAllowedCallback')));
+
+        $data = array(
+            'helpers'      => array('Mage_Tag_Helper_Data' => $helperMock),
+            'auth_session' => $authSession
+        );
+
+        $this->_model = new $this->_modelName($data);
+    }
+
+    protected function tearDown()
+    {
+        unset($this->_model);
+    }
+
+    /**
+     * @return array
+     */
+    public function methodListDataProvider()
+    {
+        $methods = array();
+        foreach ($this->_testedMethods as $method) {
+            $methods['test for ' . $method] = array(
+                '$method' => '_test' . ucfirst($method)
+            );
+        }
+
+        return $methods;
+    }
+
+    protected function _testGetTabLabel()
+    {
+        $this->assertEquals($this->_title, $this->_model->getTabLabel());
+    }
+
+    protected function _testGetTabTitle()
+    {
+        $this->assertEquals($this->_title, $this->_model->getTabTitle());
+    }
+
+    protected function _testCanShowTab()
+    {
+        $this->assertTrue($this->_model->canShowTab());
+    }
+
+    /**
+     * @param string $data
+     * @return bool
+     */
+    public function isAllowedCallback($data)
+    {
+        return $data == 'Mage_Tag::tag';
+    }
+
+    protected function _testIsHidden()
+    {
+        $this->assertFalse($this->_model->isHidden());
+    }
+
+    protected function _testGetTabClass()
+    {
+        $this->assertEquals('ajax', $this->_model->getTabClass());
+    }
+
+    protected function _testGetAfter()
+    {
+        $this->assertEquals('reviews', $this->_model->getAfter());
+    }
+}
diff --git a/dev/tests/unit/testsuite/Mage/Tag/Block/Adminhtml/Customer/Edit/Tab/TagTest.php b/dev/tests/unit/testsuite/Mage/Tag/Block/Adminhtml/Customer/Edit/Tab/TagTest.php
new file mode 100644
index 00000000000..a9fb718a47a
--- /dev/null
+++ b/dev/tests/unit/testsuite/Mage/Tag/Block/Adminhtml/Customer/Edit/Tab/TagTest.php
@@ -0,0 +1,192 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @category    Magento
+ * @package     Mage_Tag
+ * @subpackage  unit_tests
+ * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+/**
+ * Test class for Mage_Tag_Block_Adminhtml_Customer_Edit_Tab_Tag
+ */
+class Mage_Tag_Block_Adminhtml_Customer_Edit_Tab_TagTest extends PHPUnit_Framework_TestCase
+{
+    /**
+     * Test model
+     *
+     * @var Mage_Tag_Block_Adminhtml_Customer_Edit_Tab_Tag
+     */
+    protected $_model;
+
+    /**
+     * Expected constant data
+     *
+     * @var array
+     */
+    protected $_constantData = array(
+        'id'        => 'tags',
+        'is_hidden' => false,
+        'after'     => 'reviews',
+        'tab_class' => 'ajax',
+    );
+
+    /**
+     * Array of data helpers
+     *
+     * @var array
+     */
+    protected $_helpers;
+
+    public function setUp()
+    {
+        $dataHelper = $this->getMock('stdClass', array('__'));
+        $dataHelper->expects($this->any())
+            ->method('__')
+            ->will($this->returnArgument(0));
+
+        $this->_helpers = array('Mage_Tag_Helper_Data' => $dataHelper);
+
+        $data = array(
+            'helpers'          => $this->_helpers,
+            'current_customer' => false,
+            'auth_session'     => false,
+        );
+        $this->_model = new Mage_Tag_Block_Adminhtml_Customer_Edit_Tab_Tag($data);
+    }
+
+    public function tearDown()
+    {
+        unset($this->_model);
+    }
+
+    /**
+     * Prepare mock for testCanShowTab
+     *
+     * @param boolean $isCustomer
+     * @param boolean $isCustomerExist
+     * @param boolean $isAllowed
+     */
+    protected function _getMockForCanShowTab($isCustomer, $isCustomerExist, $isAllowed)
+    {
+        $customer = false;
+        if ($isCustomer) {
+            $customer = $this->getMock('stdClass', array('getId'));
+            $customer->expects($this->any())
+                ->method('getId')
+                ->will($this->returnValue($isCustomerExist));
+        }
+
+        $authSession = $this->getMock('stdClass', array('isAllowed'));
+        $authSession->expects($this->any())
+            ->method('isAllowed')
+            ->will($this->returnValue($isAllowed));
+
+        $data = array(
+            'helpers'          => $this->_helpers,
+            'current_customer' => $customer,
+            'auth_session'     => $authSession,
+        );
+        $this->_model = new Mage_Tag_Block_Adminhtml_Customer_Edit_Tab_Tag($data);
+    }
+
+    /**
+     * Test for constant data
+     *
+     * @covers Mage_Tag_Block_Adminhtml_Customer_Edit_Tab_Tag::__construct
+     * @covers Mage_Tag_Block_Adminhtml_Customer_Edit_Tab_Tag::getTabLabel
+     * @covers Mage_Tag_Block_Adminhtml_Customer_Edit_Tab_Tag::getTabTitle
+     * @covers Mage_Tag_Block_Adminhtml_Customer_Edit_Tab_Tag::isHidden
+     * @covers Mage_Tag_Block_Adminhtml_Customer_Edit_Tab_Tag::getAfter
+     * @covers Mage_Tag_Block_Adminhtml_Customer_Edit_Tab_Tag::getTabClass
+     */
+    public function testConstantData()
+    {
+        $expectedTitle = $this->_model->getTitle();
+        $this->assertNotEmpty($expectedTitle);
+        $this->assertEquals($expectedTitle, $this->_model->getTabLabel());
+        $this->assertEquals($expectedTitle, $this->_model->getTabTitle());
+
+        $this->assertEquals($this->_constantData['id'], $this->_model->getId());
+        $this->assertEquals($this->_constantData['is_hidden'], $this->_model->isHidden());
+        $this->assertEquals($this->_constantData['after'], $this->_model->getAfter());
+        $this->assertEquals($this->_constantData['tab_class'], $this->_model->getTabClass());
+    }
+
+    /**
+     * Data provider for testCanShowTab
+     *
+     * @return array
+     */
+    public function canShowTabDataProvider()
+    {
+        return array(
+            'no_customer' => array(
+                '$isCustomer'      => false,
+                '$isCustomerExist' => true,
+                '$isAllowed'       => true,
+                '$result'          => false,
+            ),
+            'new_customer_allowed' => array(
+                '$isCustomer'      => true,
+                '$isCustomerExist' => false,
+                '$isAllowed'       => true,
+                '$result'          => false,
+            ),
+            'new_customer_not_allowed' => array(
+                '$isCustomer'      => true,
+                '$isCustomerExist' => false,
+                '$isAllowed'       => false,
+                '$result'          => false,
+            ),
+            'existing_customer_allowed' => array(
+                '$isCustomer'      => true,
+                '$isCustomerExist' => true,
+                '$isAllowed'       => true,
+                '$result'          => true,
+            ),
+            'existing_customer_not_allowed' => array(
+                '$isCustomer'      => true,
+                '$isCustomerExist' => true,
+                '$isAllowed'       => false,
+                '$result'          => false,
+            ),
+        );
+    }
+
+    /**
+     * Test for canShowTab method
+     *
+     * @param boolean $isCustomer
+     * @param boolean $isCustomerExist
+     * @param boolean $isAllowed
+     * @param boolean $result
+     *
+     * @dataProvider canShowTabDataProvider
+     * @covers Mage_Tag_Block_Adminhtml_Customer_Edit_Tab_Tag::canShowTab
+     */
+    public function testCanShowTab($isCustomer, $isCustomerExist, $isAllowed, $result)
+    {
+        $this->_getMockForCanShowTab($isCustomer, $isCustomerExist, $isAllowed);
+        $this->assertSame($result, $this->_model->canShowTab());
+    }
+}
+
diff --git a/dev/tests/unit/testsuite/Mage/Tag/Block/Catalog/Product/Rss/LinkTest.php b/dev/tests/unit/testsuite/Mage/Tag/Block/Catalog/Product/Rss/LinkTest.php
new file mode 100644
index 00000000000..ca216a16128
--- /dev/null
+++ b/dev/tests/unit/testsuite/Mage/Tag/Block/Catalog/Product/Rss/LinkTest.php
@@ -0,0 +1,121 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @category    Mage
+ * @package     Mage_Tag
+ * @subpackage  unit_tests
+ * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+class Mage_Tag_Block_Catalog_Product_Rss_LinkTest extends PHPUnit_Framework_TestCase
+{
+    /**
+     * @var Mage_Tag_Block_Catalog_Product_Rss_Link
+     */
+    protected $_model;
+
+    protected function tearDown()
+    {
+        unset($this->_model);
+    }
+
+    /**
+     * @covers Mage_Tag_Block_Catalog_Product_Rss_Link::getLinkUrl
+     * @dataProvider getUrlTestDataProvider
+     *
+     * @param bool $rssEnabled
+     * @param int $tagId
+     * @param int $existTagId
+     * @param string|bool $expected
+     */
+    public function testGetLinkUrl($rssEnabled, $tagId, $existTagId, $expected)
+    {
+        $tagModelMock = $this->getMock('Mage_Tag_Model_Tag', array('getId', 'getName', 'load'), array(), '', false);
+        $tagModelMock->expects($this->any())
+            ->method('getId')
+            ->will($this->returnValue($existTagId));
+        $tagModelMock->expects($this->any())
+            ->method('getName')
+            ->will($this->returnValue('test'));
+
+        $urlModelMock = $this->getMock('Mage_Core_Model_Url', array('getUrl'), array(), '', false);
+        $urlModelMock->expects($this->any())
+            ->method('getUrl')
+            ->will($this->returnCallback(array($this, 'validateGetUrlCallback')));
+
+        $data = array(
+            'rss_catalog_tag_enabled' => $rssEnabled,
+            'tag_id'                  => $tagId,
+            'tag_model'               => $tagModelMock,
+            'core_url_model'          => $urlModelMock
+        );
+        $this->_model = new Mage_Tag_Block_Catalog_Product_Rss_Link($data);
+
+        $this->assertSame($expected, $this->_model->getLinkUrl());
+    }
+
+    /**
+     * @return array
+     */
+    public function getUrlTestDataProvider()
+    {
+        return array(
+            'rss disabled' => array(
+                '$rssEnabled' => false,
+                '$tagId'      => false,
+                '$existTagId' => false,
+                '$expected'   => false
+            ),
+            'rss enabled tag_id missed' => array(
+                '$rssEnabled' => true,
+                '$tagId'      => false,
+                '$existTagId' => false,
+                '$expected'   => false
+            ),
+            'rss enabled tag not found' => array(
+                '$rssEnabled' => true,
+                '$tagId'      => 1,
+                '$existTagId' => false,
+                '$expected'   => false
+            ),
+            'rss enabled tag exists' => array(
+                '$rssEnabled' => true,
+                '$tagId'      => 1,
+                '$existTagId' => 1,
+                '$expected'   => 'rss/catalog/tag/tagName/test'
+            )
+        );
+    }
+
+    /**
+     * @param string $url
+     * @param array $params
+     * @return string
+     */
+    public function validateGetUrlCallback($url, $params)
+    {
+        $this->assertEquals('rss/catalog/tag', $url);
+        $this->assertArrayHasKey('tagName', $params);
+        $this->assertEquals('test', $params['tagName']);
+
+        return $url . '/tagName/' . $params['tagName'];
+    }
+}
diff --git a/dev/tests/unit/testsuite/tools/migration/Acl/Db/Logger/ConsoleTest.php b/dev/tests/unit/testsuite/tools/migration/Acl/Db/Logger/ConsoleTest.php
index 4d5b6d7afe1..82137597661 100644
--- a/dev/tests/unit/testsuite/tools/migration/Acl/Db/Logger/ConsoleTest.php
+++ b/dev/tests/unit/testsuite/tools/migration/Acl/Db/Logger/ConsoleTest.php
@@ -27,7 +27,7 @@
 require_once realpath(dirname(__FILE__) . '/../../../../../../../../') . '/tools/migration/Acl/Db/LoggerAbstract.php';
 require_once realpath(dirname(__FILE__) . '/../../../../../../../../') . '/tools/migration/Acl/Db/Logger/Console.php';
 
-class Tools_Migration_Acl_Db_Logger_ConsoleTest extends PHPUnit_Extensions_OutputTestCase
+class Tools_Migration_Acl_Db_Logger_ConsoleTest extends PHPUnit_Framework_TestCase
 {
     public function testReport()
     {
diff --git a/lib/Varien/Db/Adapter/Pdo/Mysql.php b/lib/Varien/Db/Adapter/Pdo/Mysql.php
index b92d9df7fe3..6dcab28bfbe 100644
--- a/lib/Varien/Db/Adapter/Pdo/Mysql.php
+++ b/lib/Varien/Db/Adapter/Pdo/Mysql.php
@@ -311,6 +311,10 @@ class Varien_Db_Adapter_Pdo_Mysql extends Zend_Db_Adapter_Pdo_Mysql implements V
             throw new Zend_Db_Adapter_Exception('pdo_mysql extension is not installed');
         }
 
+        if (!isset($this->_config['host'])) {
+            throw new Zend_Db_Adapter_Exception('No host configured to connect to');
+        }
+
         if (strpos($this->_config['host'], '/') !== false) {
             $this->_config['unix_socket'] = $this->_config['host'];
             unset($this->_config['host']);
-- 
GitLab