OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h" | 5 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h" |
6 | 6 |
7 #include "apps/shell_window.h" | 7 #include "apps/shell_window.h" |
8 #include "apps/shell_window_registry.h" | 8 #include "apps/shell_window_registry.h" |
9 #include "apps/ui/native_app_window.h" | 9 #include "apps/ui/native_app_window.h" |
10 #include "ash/ash_switches.h" | 10 #include "ash/ash_switches.h" |
11 #include "ash/display/display_controller.h" | 11 #include "ash/display/display_controller.h" |
12 #include "ash/launcher/launcher.h" | 12 #include "ash/launcher/launcher.h" |
13 #include "ash/launcher/launcher_button.h" | 13 #include "ash/launcher/launcher_button.h" |
14 #include "ash/launcher/launcher_model.h" | 14 #include "ash/launcher/launcher_model.h" |
15 #include "ash/launcher/launcher_model_util.h" | 15 #include "ash/shelf/shelf_model_util.h" |
16 #include "ash/shelf/shelf_view.h" | 16 #include "ash/shelf/shelf_view.h" |
17 #include "ash/shell.h" | 17 #include "ash/shell.h" |
18 #include "ash/test/app_list_controller_test_api.h" | 18 #include "ash/test/app_list_controller_test_api.h" |
19 #include "ash/test/launcher_test_api.h" | 19 #include "ash/test/launcher_test_api.h" |
20 #include "ash/test/shelf_view_test_api.h" | 20 #include "ash/test/shelf_view_test_api.h" |
21 #include "ash/test/shell_test_api.h" | 21 #include "ash/test/shell_test_api.h" |
22 #include "ash/wm/window_state.h" | 22 #include "ash/wm/window_state.h" |
23 #include "ash/wm/window_util.h" | 23 #include "ash/wm/window_util.h" |
24 #include "base/strings/stringprintf.h" | 24 #include "base/strings/stringprintf.h" |
25 #include "base/strings/utf_string_conversions.h" | 25 #include "base/strings/utf_string_conversions.h" |
(...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
261 void ActivateLauncherItem(int id) { | 261 void ActivateLauncherItem(int id) { |
262 launcher_->ActivateLauncherItem(id); | 262 launcher_->ActivateLauncherItem(id); |
263 } | 263 } |
264 | 264 |
265 ash::LauncherID PinFakeApp(const std::string& name) { | 265 ash::LauncherID PinFakeApp(const std::string& name) { |
266 return controller_->CreateAppShortcutLauncherItem( | 266 return controller_->CreateAppShortcutLauncherItem( |
267 name, model_->item_count()); | 267 name, model_->item_count()); |
268 } | 268 } |
269 | 269 |
270 // Get the index of an item which has the given type. | 270 // Get the index of an item which has the given type. |
271 int GetIndexOfLauncherItemType(ash::LauncherItemType type) { | 271 int GetIndexOfShelfItemType(ash::LauncherItemType type) { |
272 return ash::GetLauncherItemIndexForType(type, *model_); | 272 return ash::GetShelfItemIndexForType(type, *model_); |
273 } | 273 } |
274 | 274 |
275 // Try to rip off |item_index|. | 275 // Try to rip off |item_index|. |
276 void RipOffItemIndex(int index, | 276 void RipOffItemIndex(int index, |
277 aura::test::EventGenerator* generator, | 277 aura::test::EventGenerator* generator, |
278 ash::test::ShelfViewTestAPI* test, | 278 ash::test::ShelfViewTestAPI* test, |
279 RipOffCommand command) { | 279 RipOffCommand command) { |
280 ash::internal::LauncherButton* button = test->GetButton(index); | 280 ash::internal::LauncherButton* button = test->GetButton(index); |
281 gfx::Point start_point = button->GetBoundsInScreen().CenterPoint(); | 281 gfx::Point start_point = button->GetBoundsInScreen().CenterPoint(); |
282 gfx::Point rip_off_point(start_point.x(), 0); | 282 gfx::Point rip_off_point(start_point.x(), 0); |
(...skipping 737 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1020 ui_test_utils::NavigateToURL( | 1020 ui_test_utils::NavigateToURL( |
1021 browser(), GURL("http://www.example.com/path1/foo.html")); | 1021 browser(), GURL("http://www.example.com/path1/foo.html")); |
1022 EXPECT_EQ(ash::STATUS_ACTIVE, (*model_->ItemByID(shortcut_id)).status); | 1022 EXPECT_EQ(ash::STATUS_ACTIVE, (*model_->ItemByID(shortcut_id)).status); |
1023 } | 1023 } |
1024 | 1024 |
1025 // Confirm that a tab can be moved between browsers while maintaining the | 1025 // Confirm that a tab can be moved between browsers while maintaining the |
1026 // correct running state. | 1026 // correct running state. |
1027 IN_PROC_BROWSER_TEST_F(LauncherAppBrowserTest, TabDragAndDrop) { | 1027 IN_PROC_BROWSER_TEST_F(LauncherAppBrowserTest, TabDragAndDrop) { |
1028 TabStripModel* tab_strip_model1 = browser()->tab_strip_model(); | 1028 TabStripModel* tab_strip_model1 = browser()->tab_strip_model(); |
1029 EXPECT_EQ(1, tab_strip_model1->count()); | 1029 EXPECT_EQ(1, tab_strip_model1->count()); |
1030 int browser_index = GetIndexOfLauncherItemType(ash::TYPE_BROWSER_SHORTCUT); | 1030 int browser_index = GetIndexOfShelfItemType(ash::TYPE_BROWSER_SHORTCUT); |
1031 EXPECT_TRUE(browser_index >= 0); | 1031 EXPECT_TRUE(browser_index >= 0); |
1032 EXPECT_EQ(1u, chrome::GetTotalBrowserCount()); | 1032 EXPECT_EQ(1u, chrome::GetTotalBrowserCount()); |
1033 | 1033 |
1034 // Create a shortcut for app1. | 1034 // Create a shortcut for app1. |
1035 ash::LauncherID shortcut_id = CreateShortcut("app1"); | 1035 ash::LauncherID shortcut_id = CreateShortcut("app1"); |
1036 EXPECT_EQ(ash::STATUS_ACTIVE, model_->items()[browser_index].status); | 1036 EXPECT_EQ(ash::STATUS_ACTIVE, model_->items()[browser_index].status); |
1037 EXPECT_EQ(ash::STATUS_CLOSED, (*model_->ItemByID(shortcut_id)).status); | 1037 EXPECT_EQ(ash::STATUS_CLOSED, (*model_->ItemByID(shortcut_id)).status); |
1038 | 1038 |
1039 // Activate app1 and check its item status. | 1039 // Activate app1 and check its item status. |
1040 ActivateLauncherItem(model_->ItemIndexByID(shortcut_id)); | 1040 ActivateLauncherItem(model_->ItemIndexByID(shortcut_id)); |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1163 WebContents* second_tab = tab_strip->GetActiveWebContents(); | 1163 WebContents* second_tab = tab_strip->GetActiveWebContents(); |
1164 EXPECT_EQ(ash::STATUS_ACTIVE, model_->ItemByID(shortcut_id)->status); | 1164 EXPECT_EQ(ash::STATUS_ACTIVE, model_->ItemByID(shortcut_id)->status); |
1165 EXPECT_NE(first_tab, second_tab); | 1165 EXPECT_NE(first_tab, second_tab); |
1166 EXPECT_EQ(tab_strip->GetActiveWebContents(), second_tab); | 1166 EXPECT_EQ(tab_strip->GetActiveWebContents(), second_tab); |
1167 } | 1167 } |
1168 | 1168 |
1169 // Check the launcher activation state for applications and browser. | 1169 // Check the launcher activation state for applications and browser. |
1170 IN_PROC_BROWSER_TEST_F(LauncherAppBrowserTest, ActivationStateCheck) { | 1170 IN_PROC_BROWSER_TEST_F(LauncherAppBrowserTest, ActivationStateCheck) { |
1171 TabStripModel* tab_strip = browser()->tab_strip_model(); | 1171 TabStripModel* tab_strip = browser()->tab_strip_model(); |
1172 // Get the browser item index | 1172 // Get the browser item index |
1173 int browser_index = GetIndexOfLauncherItemType(ash::TYPE_BROWSER_SHORTCUT); | 1173 int browser_index = GetIndexOfShelfItemType(ash::TYPE_BROWSER_SHORTCUT); |
1174 EXPECT_TRUE(browser_index >= 0); | 1174 EXPECT_TRUE(browser_index >= 0); |
1175 | 1175 |
1176 // Even though we are just comming up, the browser should be active. | 1176 // Even though we are just comming up, the browser should be active. |
1177 EXPECT_EQ(ash::STATUS_ACTIVE, model_->items()[browser_index].status); | 1177 EXPECT_EQ(ash::STATUS_ACTIVE, model_->items()[browser_index].status); |
1178 | 1178 |
1179 ash::LauncherID shortcut_id = CreateShortcut("app1"); | 1179 ash::LauncherID shortcut_id = CreateShortcut("app1"); |
1180 controller_->SetRefocusURLPatternForTest( | 1180 controller_->SetRefocusURLPatternForTest( |
1181 shortcut_id, GURL("http://www.example.com/path1/*")); | 1181 shortcut_id, GURL("http://www.example.com/path1/*")); |
1182 | 1182 |
1183 EXPECT_EQ(ash::STATUS_CLOSED, model_->ItemByID(shortcut_id)->status); | 1183 EXPECT_EQ(ash::STATUS_CLOSED, model_->ItemByID(shortcut_id)->status); |
(...skipping 479 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1663 aura::test::EventGenerator generator( | 1663 aura::test::EventGenerator generator( |
1664 ash::Shell::GetPrimaryRootWindow(), gfx::Point()); | 1664 ash::Shell::GetPrimaryRootWindow(), gfx::Point()); |
1665 ash::test::ShelfViewTestAPI test( | 1665 ash::test::ShelfViewTestAPI test( |
1666 ash::test::LauncherTestAPI(launcher_).shelf_view()); | 1666 ash::test::LauncherTestAPI(launcher_).shelf_view()); |
1667 | 1667 |
1668 // Create a known application and check that we have 3 items in the launcher. | 1668 // Create a known application and check that we have 3 items in the launcher. |
1669 CreateShortcut("app1"); | 1669 CreateShortcut("app1"); |
1670 EXPECT_EQ(3, model_->item_count()); | 1670 EXPECT_EQ(3, model_->item_count()); |
1671 | 1671 |
1672 // Test #1: Ripping out the browser item should not change anything. | 1672 // Test #1: Ripping out the browser item should not change anything. |
1673 int browser_index = GetIndexOfLauncherItemType(ash::TYPE_BROWSER_SHORTCUT); | 1673 int browser_index = GetIndexOfShelfItemType(ash::TYPE_BROWSER_SHORTCUT); |
1674 EXPECT_LE(0, browser_index); | 1674 EXPECT_LE(0, browser_index); |
1675 RipOffItemIndex(browser_index, &generator, &test, RIP_OFF_ITEM); | 1675 RipOffItemIndex(browser_index, &generator, &test, RIP_OFF_ITEM); |
1676 // => It should not have been removed and the location should be unchanged. | 1676 // => It should not have been removed and the location should be unchanged. |
1677 EXPECT_EQ(3, model_->item_count()); | 1677 EXPECT_EQ(3, model_->item_count()); |
1678 EXPECT_EQ(browser_index, | 1678 EXPECT_EQ(browser_index, |
1679 GetIndexOfLauncherItemType(ash::TYPE_BROWSER_SHORTCUT)); | 1679 GetIndexOfShelfItemType(ash::TYPE_BROWSER_SHORTCUT)); |
1680 // Make sure that the hide state has been unset after the snap back animation | 1680 // Make sure that the hide state has been unset after the snap back animation |
1681 // finished. | 1681 // finished. |
1682 ash::internal::LauncherButton* button = test.GetButton(browser_index); | 1682 ash::internal::LauncherButton* button = test.GetButton(browser_index); |
1683 EXPECT_FALSE(button->state() & ash::internal::LauncherButton::STATE_HIDDEN); | 1683 EXPECT_FALSE(button->state() & ash::internal::LauncherButton::STATE_HIDDEN); |
1684 | 1684 |
1685 // Test #2: Ripping out the application and canceling the operation should | 1685 // Test #2: Ripping out the application and canceling the operation should |
1686 // not change anything. | 1686 // not change anything. |
1687 int app_index = GetIndexOfLauncherItemType(ash::TYPE_APP_SHORTCUT); | 1687 int app_index = GetIndexOfShelfItemType(ash::TYPE_APP_SHORTCUT); |
1688 EXPECT_LE(0, app_index); | 1688 EXPECT_LE(0, app_index); |
1689 RipOffItemIndex(app_index, &generator, &test, RIP_OFF_ITEM_AND_CANCEL); | 1689 RipOffItemIndex(app_index, &generator, &test, RIP_OFF_ITEM_AND_CANCEL); |
1690 // => It should not have been removed and the location should be unchanged. | 1690 // => It should not have been removed and the location should be unchanged. |
1691 ASSERT_EQ(3, model_->item_count()); | 1691 ASSERT_EQ(3, model_->item_count()); |
1692 EXPECT_EQ(app_index, GetIndexOfLauncherItemType(ash::TYPE_APP_SHORTCUT)); | 1692 EXPECT_EQ(app_index, GetIndexOfShelfItemType(ash::TYPE_APP_SHORTCUT)); |
1693 | 1693 |
1694 // Test #3: Ripping out the application and moving it back in should not | 1694 // Test #3: Ripping out the application and moving it back in should not |
1695 // change anything. | 1695 // change anything. |
1696 RipOffItemIndex(app_index, &generator, &test, RIP_OFF_ITEM_AND_RETURN); | 1696 RipOffItemIndex(app_index, &generator, &test, RIP_OFF_ITEM_AND_RETURN); |
1697 // => It should not have been removed and the location should be unchanged. | 1697 // => It should not have been removed and the location should be unchanged. |
1698 ASSERT_EQ(3, model_->item_count()); | 1698 ASSERT_EQ(3, model_->item_count()); |
1699 // Through the operation the index might have changed. | 1699 // Through the operation the index might have changed. |
1700 app_index = GetIndexOfLauncherItemType(ash::TYPE_APP_SHORTCUT); | 1700 app_index = GetIndexOfShelfItemType(ash::TYPE_APP_SHORTCUT); |
1701 | 1701 |
1702 // Test #4: Ripping out the application should remove the item. | 1702 // Test #4: Ripping out the application should remove the item. |
1703 RipOffItemIndex(app_index, &generator, &test, RIP_OFF_ITEM); | 1703 RipOffItemIndex(app_index, &generator, &test, RIP_OFF_ITEM); |
1704 // => It should not have been removed and the location should be unchanged. | 1704 // => It should not have been removed and the location should be unchanged. |
1705 EXPECT_EQ(2, model_->item_count()); | 1705 EXPECT_EQ(2, model_->item_count()); |
1706 EXPECT_EQ(-1, GetIndexOfLauncherItemType(ash::TYPE_APP_SHORTCUT)); | 1706 EXPECT_EQ(-1, GetIndexOfShelfItemType(ash::TYPE_APP_SHORTCUT)); |
1707 | 1707 |
1708 // Test #5: Uninstalling an application while it is being ripped off should | 1708 // Test #5: Uninstalling an application while it is being ripped off should |
1709 // not crash. | 1709 // not crash. |
1710 ash::LauncherID app_id = CreateShortcut("app2"); | 1710 ash::LauncherID app_id = CreateShortcut("app2"); |
1711 int app2_index = GetIndexOfLauncherItemType(ash::TYPE_APP_SHORTCUT); | 1711 int app2_index = GetIndexOfShelfItemType(ash::TYPE_APP_SHORTCUT); |
1712 EXPECT_EQ(3, model_->item_count()); // And it remains that way. | 1712 EXPECT_EQ(3, model_->item_count()); // And it remains that way. |
1713 RipOffItemIndex(app2_index, | 1713 RipOffItemIndex(app2_index, |
1714 &generator, | 1714 &generator, |
1715 &test, | 1715 &test, |
1716 RIP_OFF_ITEM_AND_DONT_RELEASE_MOUSE); | 1716 RIP_OFF_ITEM_AND_DONT_RELEASE_MOUSE); |
1717 RemoveShortcut(app_id); | 1717 RemoveShortcut(app_id); |
1718 EXPECT_EQ(2, model_->item_count()); // The item should now be gone. | 1718 EXPECT_EQ(2, model_->item_count()); // The item should now be gone. |
1719 generator.ReleaseLeftButton(); | 1719 generator.ReleaseLeftButton(); |
1720 base::MessageLoop::current()->RunUntilIdle(); | 1720 base::MessageLoop::current()->RunUntilIdle(); |
1721 EXPECT_EQ(2, model_->item_count()); // And it remains that way. | 1721 EXPECT_EQ(2, model_->item_count()); // And it remains that way. |
1722 EXPECT_EQ(-1, GetIndexOfLauncherItemType(ash::TYPE_APP_SHORTCUT)); | 1722 EXPECT_EQ(-1, GetIndexOfShelfItemType(ash::TYPE_APP_SHORTCUT)); |
1723 | 1723 |
1724 // Test #6: Ripping out the application when the overflow button exists. | 1724 // Test #6: Ripping out the application when the overflow button exists. |
1725 // After ripping out, overflow button should be removed. | 1725 // After ripping out, overflow button should be removed. |
1726 int items_added = 0; | 1726 int items_added = 0; |
1727 EXPECT_FALSE(test.IsOverflowButtonVisible()); | 1727 EXPECT_FALSE(test.IsOverflowButtonVisible()); |
1728 | 1728 |
1729 // Create fake app shortcuts until overflow button is created. | 1729 // Create fake app shortcuts until overflow button is created. |
1730 while (!test.IsOverflowButtonVisible()) { | 1730 while (!test.IsOverflowButtonVisible()) { |
1731 std::string fake_app_id = base::StringPrintf("fake_app_%d", items_added); | 1731 std::string fake_app_id = base::StringPrintf("fake_app_%d", items_added); |
1732 PinFakeApp(fake_app_id); | 1732 PinFakeApp(fake_app_id); |
1733 | 1733 |
1734 ++items_added; | 1734 ++items_added; |
1735 ASSERT_LT(items_added, 10000); | 1735 ASSERT_LT(items_added, 10000); |
1736 } | 1736 } |
1737 // Make one more item after creating a overflow button. | 1737 // Make one more item after creating a overflow button. |
1738 std::string fake_app_id = base::StringPrintf("fake_app_%d", items_added); | 1738 std::string fake_app_id = base::StringPrintf("fake_app_%d", items_added); |
1739 PinFakeApp(fake_app_id); | 1739 PinFakeApp(fake_app_id); |
1740 | 1740 |
1741 int total_count = model_->item_count(); | 1741 int total_count = model_->item_count(); |
1742 app_index = GetIndexOfLauncherItemType(ash::TYPE_APP_SHORTCUT); | 1742 app_index = GetIndexOfShelfItemType(ash::TYPE_APP_SHORTCUT); |
1743 RipOffItemIndex(app_index, &generator, &test, RIP_OFF_ITEM); | 1743 RipOffItemIndex(app_index, &generator, &test, RIP_OFF_ITEM); |
1744 // When an item is ripped off from the launcher that has overflow button | 1744 // When an item is ripped off from the launcher that has overflow button |
1745 // (see crbug.com/3050787), it was hidden accidentally and was then | 1745 // (see crbug.com/3050787), it was hidden accidentally and was then |
1746 // suppressing any further events. If handled correctly the operation will | 1746 // suppressing any further events. If handled correctly the operation will |
1747 // however correctly done and the item will get removed (as well as the | 1747 // however correctly done and the item will get removed (as well as the |
1748 // overflow button). | 1748 // overflow button). |
1749 EXPECT_EQ(total_count - 1, model_->item_count()); | 1749 EXPECT_EQ(total_count - 1, model_->item_count()); |
1750 EXPECT_TRUE(test.IsOverflowButtonVisible()); | 1750 EXPECT_TRUE(test.IsOverflowButtonVisible()); |
1751 | 1751 |
1752 // Rip off again and the overflow button should has disappeared. | 1752 // Rip off again and the overflow button should has disappeared. |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1827 | 1827 |
1828 // Check that GetIDByWindow() returns |LauncherID| of the active tab. | 1828 // Check that GetIDByWindow() returns |LauncherID| of the active tab. |
1829 IN_PROC_BROWSER_TEST_F(LauncherAppBrowserTest, MatchingLauncherIDandActiveTab) { | 1829 IN_PROC_BROWSER_TEST_F(LauncherAppBrowserTest, MatchingLauncherIDandActiveTab) { |
1830 EXPECT_EQ(1u, chrome::GetTotalBrowserCount()); | 1830 EXPECT_EQ(1u, chrome::GetTotalBrowserCount()); |
1831 EXPECT_EQ(1, browser()->tab_strip_model()->count()); | 1831 EXPECT_EQ(1, browser()->tab_strip_model()->count()); |
1832 EXPECT_EQ(0, browser()->tab_strip_model()->active_index()); | 1832 EXPECT_EQ(0, browser()->tab_strip_model()->active_index()); |
1833 EXPECT_EQ(2, model_->item_count()); | 1833 EXPECT_EQ(2, model_->item_count()); |
1834 | 1834 |
1835 aura::Window* window = browser()->window()->GetNativeWindow(); | 1835 aura::Window* window = browser()->window()->GetNativeWindow(); |
1836 | 1836 |
1837 int browser_index = GetIndexOfLauncherItemType(ash::TYPE_BROWSER_SHORTCUT); | 1837 int browser_index = GetIndexOfShelfItemType(ash::TYPE_BROWSER_SHORTCUT); |
1838 ash::LauncherID browser_id = model_->items()[browser_index].id; | 1838 ash::LauncherID browser_id = model_->items()[browser_index].id; |
1839 EXPECT_EQ(browser_id, controller_->GetIDByWindow(window)); | 1839 EXPECT_EQ(browser_id, controller_->GetIDByWindow(window)); |
1840 | 1840 |
1841 ash::LauncherID app_id = CreateShortcut("app1"); | 1841 ash::LauncherID app_id = CreateShortcut("app1"); |
1842 EXPECT_EQ(3, model_->item_count()); | 1842 EXPECT_EQ(3, model_->item_count()); |
1843 | 1843 |
1844 // Creates a new tab for "app1" and checks that GetIDByWindow() returns | 1844 // Creates a new tab for "app1" and checks that GetIDByWindow() returns |
1845 // |LauncherID| of "app1". | 1845 // |LauncherID| of "app1". |
1846 ActivateLauncherItem(model_->ItemIndexByID(app_id)); | 1846 ActivateLauncherItem(model_->ItemIndexByID(app_id)); |
1847 EXPECT_EQ(2, browser()->tab_strip_model()->count()); | 1847 EXPECT_EQ(2, browser()->tab_strip_model()->count()); |
(...skipping 29 matching lines...) Expand all Loading... |
1877 // Now show overflow bubble. | 1877 // Now show overflow bubble. |
1878 test.ShowOverflowBubble(); | 1878 test.ShowOverflowBubble(); |
1879 EXPECT_TRUE(launcher_->IsShowingOverflowBubble()); | 1879 EXPECT_TRUE(launcher_->IsShowingOverflowBubble()); |
1880 | 1880 |
1881 // Unpin first pinned app and there should be no crash. | 1881 // Unpin first pinned app and there should be no crash. |
1882 controller_->UnpinAppWithID(std::string("fake_app_0")); | 1882 controller_->UnpinAppWithID(std::string("fake_app_0")); |
1883 | 1883 |
1884 test.RunMessageLoopUntilAnimationsDone(); | 1884 test.RunMessageLoopUntilAnimationsDone(); |
1885 EXPECT_FALSE(launcher_->IsShowingOverflowBubble()); | 1885 EXPECT_FALSE(launcher_->IsShowingOverflowBubble()); |
1886 } | 1886 } |
OLD | NEW |