| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/chromeos/input_method/input_method_manager_impl.h" | 5 #include "chrome/browser/chromeos/input_method/input_method_manager_impl.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/basictypes.h" | 9 #include "base/basictypes.h" |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| 11 #include "base/bind_helpers.h" | 11 #include "base/bind_helpers.h" |
| 12 #include "base/compiler_specific.h" | 12 #include "base/compiler_specific.h" |
| 13 #include "base/logging.h" | 13 #include "base/logging.h" |
| 14 #include "base/memory/scoped_ptr.h" | 14 #include "base/memory/scoped_ptr.h" |
| 15 #include "base/message_loop/message_loop.h" | 15 #include "base/message_loop/message_loop.h" |
| 16 #include "chrome/browser/chromeos/input_method/mock_candidate_window_controller.
h" | 16 #include "chrome/browser/chromeos/input_method/mock_candidate_window_controller.
h" |
| 17 #include "chrome/browser/chromeos/input_method/mock_ibus_controller.h" | 17 #include "chrome/browser/chromeos/input_method/mock_ibus_controller.h" |
| 18 #include "chromeos/dbus/fake_dbus_thread_manager.h" | 18 #include "chromeos/dbus/fake_dbus_thread_manager.h" |
| 19 #include "chromeos/dbus/ibus/mock_ibus_client.h" | |
| 20 #include "chromeos/ime/extension_ime_util.h" | 19 #include "chromeos/ime/extension_ime_util.h" |
| 21 #include "chromeos/ime/fake_input_method_delegate.h" | 20 #include "chromeos/ime/fake_input_method_delegate.h" |
| 22 #include "chromeos/ime/mock_component_extension_ime_manager_delegate.h" | 21 #include "chromeos/ime/mock_component_extension_ime_manager_delegate.h" |
| 23 #include "chromeos/ime/mock_ibus_daemon_controller.h" | 22 #include "chromeos/ime/mock_ibus_daemon_controller.h" |
| 24 #include "chromeos/ime/mock_ime_engine_handler.h" | 23 #include "chromeos/ime/mock_ime_engine_handler.h" |
| 25 #include "chromeos/ime/mock_xkeyboard.h" | 24 #include "chromeos/ime/mock_xkeyboard.h" |
| 26 #include "testing/gtest/include/gtest/gtest.h" | 25 #include "testing/gtest/include/gtest/gtest.h" |
| 27 #include "ui/base/accelerators/accelerator.h" | 26 #include "ui/base/accelerators/accelerator.h" |
| 28 #include "ui/events/keycodes/keyboard_codes.h" | 27 #include "ui/events/keycodes/keyboard_codes.h" |
| 29 | 28 |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 144 void InitComponentExtension() { | 143 void InitComponentExtension() { |
| 145 mock_delegate_ = new MockComponentExtIMEManagerDelegate(); | 144 mock_delegate_ = new MockComponentExtIMEManagerDelegate(); |
| 146 mock_delegate_->set_ime_list(ime_list_); | 145 mock_delegate_->set_ime_list(ime_list_); |
| 147 scoped_ptr<ComponentExtensionIMEManagerDelegate> delegate(mock_delegate_); | 146 scoped_ptr<ComponentExtensionIMEManagerDelegate> delegate(mock_delegate_); |
| 148 manager_->InitializeComponentExtensionForTesting(delegate.Pass()); | 147 manager_->InitializeComponentExtensionForTesting(delegate.Pass()); |
| 149 } | 148 } |
| 150 | 149 |
| 151 // Helper function to initialize IBus bus connection for testing. Do not use | 150 // Helper function to initialize IBus bus connection for testing. Do not use |
| 152 // ibus related mocks before calling this function. | 151 // ibus related mocks before calling this function. |
| 153 void InitIBusBus() { | 152 void InitIBusBus() { |
| 154 mock_ibus_client_ = new MockIBusClient; | |
| 155 fake_dbus_thread_manager_->SetIBusClient( | |
| 156 scoped_ptr<IBusClient>(mock_ibus_client_)); | |
| 157 mock_ibus_daemon_controller_->EmulateConnect(); | 153 mock_ibus_daemon_controller_->EmulateConnect(); |
| 158 } | 154 } |
| 159 | 155 |
| 160 scoped_ptr<InputMethodManagerImpl> manager_; | 156 scoped_ptr<InputMethodManagerImpl> manager_; |
| 161 FakeInputMethodDelegate* delegate_; | 157 FakeInputMethodDelegate* delegate_; |
| 162 MockIBusController* controller_; | 158 MockIBusController* controller_; |
| 163 MockCandidateWindowController* candidate_window_controller_; | 159 MockCandidateWindowController* candidate_window_controller_; |
| 164 MockIBusDaemonController* mock_ibus_daemon_controller_; | 160 MockIBusDaemonController* mock_ibus_daemon_controller_; |
| 165 scoped_ptr<MockIMEEngineHandler> mock_engine_handler_; | 161 scoped_ptr<MockIMEEngineHandler> mock_engine_handler_; |
| 166 MockIBusClient* mock_ibus_client_; | |
| 167 FakeDBusThreadManager* fake_dbus_thread_manager_; | 162 FakeDBusThreadManager* fake_dbus_thread_manager_; |
| 168 MockXKeyboard* xkeyboard_; | 163 MockXKeyboard* xkeyboard_; |
| 169 base::MessageLoop message_loop_; | 164 base::MessageLoop message_loop_; |
| 170 MockComponentExtIMEManagerDelegate* mock_delegate_; | 165 MockComponentExtIMEManagerDelegate* mock_delegate_; |
| 171 std::vector<ComponentExtensionIME> ime_list_; | 166 std::vector<ComponentExtensionIME> ime_list_; |
| 172 | 167 |
| 173 private: | 168 private: |
| 174 DISALLOW_COPY_AND_ASSIGN(InputMethodManagerImplTest); | 169 DISALLOW_COPY_AND_ASSIGN(InputMethodManagerImplTest); |
| 175 }; | 170 }; |
| 176 | 171 |
| (...skipping 921 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1098 scoped_ptr<InputMethodDescriptors> methods( | 1093 scoped_ptr<InputMethodDescriptors> methods( |
| 1099 manager_->GetActiveInputMethods()); | 1094 manager_->GetActiveInputMethods()); |
| 1100 ASSERT_EQ(2U, methods->size()); | 1095 ASSERT_EQ(2U, methods->size()); |
| 1101 EXPECT_EQ(extension_ime_util::GetInputMethodID("deadbeef", "engine_id"), | 1096 EXPECT_EQ(extension_ime_util::GetInputMethodID("deadbeef", "engine_id"), |
| 1102 // Ext. IMEs should be at the end of the list. | 1097 // Ext. IMEs should be at the end of the list. |
| 1103 methods->at(1).id()); | 1098 methods->at(1).id()); |
| 1104 } | 1099 } |
| 1105 manager_->RemoveObserver(&observer); | 1100 manager_->RemoveObserver(&observer); |
| 1106 } | 1101 } |
| 1107 | 1102 |
| 1108 TEST_F(InputMethodManagerImplTest, TestReset) { | |
| 1109 InitComponentExtension(); | |
| 1110 InitIBusBus(); | |
| 1111 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN); | |
| 1112 std::vector<std::string> ids; | |
| 1113 ids.push_back("xkb:us::eng"); | |
| 1114 ids.push_back(nacl_mozc_us_id); | |
| 1115 EXPECT_TRUE(manager_->EnableInputMethods(ids)); | |
| 1116 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods()); | |
| 1117 EXPECT_EQ(0, mock_engine_handler_->reset_call_count()); | |
| 1118 manager_->ChangeInputMethod(nacl_mozc_us_id); | |
| 1119 EXPECT_EQ(1, mock_ibus_client_->set_global_engine_call_count()); | |
| 1120 EXPECT_EQ(nacl_mozc_us_id, mock_ibus_client_->latest_global_engine_name()); | |
| 1121 EXPECT_EQ(0, mock_engine_handler_->reset_call_count()); | |
| 1122 manager_->ChangeInputMethod("xkb:us::eng"); | |
| 1123 EXPECT_EQ(1, mock_ibus_client_->set_global_engine_call_count()); | |
| 1124 EXPECT_EQ(nacl_mozc_us_id, mock_ibus_client_->latest_global_engine_name()); | |
| 1125 EXPECT_EQ(0, mock_engine_handler_->reset_call_count()); | |
| 1126 } | |
| 1127 | |
| 1128 TEST_F(InputMethodManagerImplTest, | 1103 TEST_F(InputMethodManagerImplTest, |
| 1129 ChangeInputMethodBeforeComponentExtensionInitialization_OneIME) { | 1104 ChangeInputMethodBeforeComponentExtensionInitialization_OneIME) { |
| 1130 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN); | 1105 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN); |
| 1131 std::vector<std::string> ids; | 1106 std::vector<std::string> ids; |
| 1132 ids.push_back(nacl_mozc_us_id); | 1107 ids.push_back(nacl_mozc_us_id); |
| 1133 EXPECT_TRUE(manager_->EnableInputMethods(ids)); | 1108 EXPECT_TRUE(manager_->EnableInputMethods(ids)); |
| 1134 EXPECT_EQ(1U, manager_->GetNumActiveInputMethods()); | 1109 EXPECT_EQ(1U, manager_->GetNumActiveInputMethods()); |
| 1135 manager_->ChangeInputMethod(nacl_mozc_us_id); | 1110 manager_->ChangeInputMethod(nacl_mozc_us_id); |
| 1136 | 1111 |
| 1137 InitIBusBus(); | 1112 InitIBusBus(); |
| 1138 InitComponentExtension(); | 1113 InitComponentExtension(); |
| 1139 EXPECT_EQ(1, mock_ibus_client_->set_global_engine_call_count()); | 1114 EXPECT_EQ(nacl_mozc_us_id, manager_->GetCurrentInputMethod().id()); |
| 1140 EXPECT_EQ(nacl_mozc_us_id, mock_ibus_client_->latest_global_engine_name()); | |
| 1141 } | 1115 } |
| 1142 | 1116 |
| 1143 TEST_F(InputMethodManagerImplTest, | 1117 TEST_F(InputMethodManagerImplTest, |
| 1144 ChangeInputMethodBeforeComponentExtensionInitialization_TwoIME) { | 1118 ChangeInputMethodBeforeComponentExtensionInitialization_TwoIME) { |
| 1145 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN); | 1119 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN); |
| 1146 std::vector<std::string> ids; | 1120 std::vector<std::string> ids; |
| 1147 ids.push_back(nacl_mozc_us_id); | 1121 ids.push_back(nacl_mozc_us_id); |
| 1148 ids.push_back(nacl_mozc_jp_id); | 1122 ids.push_back(nacl_mozc_jp_id); |
| 1149 EXPECT_TRUE(manager_->EnableInputMethods(ids)); | 1123 EXPECT_TRUE(manager_->EnableInputMethods(ids)); |
| 1150 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods()); | 1124 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods()); |
| 1151 manager_->ChangeInputMethod(nacl_mozc_us_id); | 1125 manager_->ChangeInputMethod(nacl_mozc_us_id); |
| 1152 manager_->ChangeInputMethod(nacl_mozc_jp_id); | 1126 manager_->ChangeInputMethod(nacl_mozc_jp_id); |
| 1153 | 1127 |
| 1154 InitComponentExtension(); | 1128 InitComponentExtension(); |
| 1155 InitIBusBus(); | 1129 InitIBusBus(); |
| 1156 EXPECT_EQ(1, mock_ibus_client_->set_global_engine_call_count()); | 1130 EXPECT_EQ(nacl_mozc_jp_id, manager_->GetCurrentInputMethod().id()); |
| 1157 EXPECT_EQ(nacl_mozc_jp_id, mock_ibus_client_->latest_global_engine_name()); | |
| 1158 } | 1131 } |
| 1159 | 1132 |
| 1160 TEST_F(InputMethodManagerImplTest, | 1133 TEST_F(InputMethodManagerImplTest, |
| 1161 ChangeInputMethodBeforeComponentExtensionInitialization_CompOneIME) { | 1134 ChangeInputMethodBeforeComponentExtensionInitialization_CompOneIME) { |
| 1162 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN); | 1135 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN); |
| 1163 const std::string ext_id = | 1136 const std::string ext_id = |
| 1164 TestableComponentExtensionIMEManager::GetComponentExtensionIMEId( | 1137 TestableComponentExtensionIMEManager::GetComponentExtensionIMEId( |
| 1165 ime_list_[0].id, | 1138 ime_list_[0].id, |
| 1166 ime_list_[0].engines[0].engine_id); | 1139 ime_list_[0].engines[0].engine_id); |
| 1167 std::vector<std::string> ids; | 1140 std::vector<std::string> ids; |
| 1168 ids.push_back(ext_id); | 1141 ids.push_back(ext_id); |
| 1169 EXPECT_TRUE(manager_->EnableInputMethods(ids)); | 1142 EXPECT_TRUE(manager_->EnableInputMethods(ids)); |
| 1170 EXPECT_EQ(1U, manager_->GetNumActiveInputMethods()); | 1143 EXPECT_EQ(1U, manager_->GetNumActiveInputMethods()); |
| 1171 manager_->ChangeInputMethod(ext_id); | 1144 manager_->ChangeInputMethod(ext_id); |
| 1172 | 1145 |
| 1173 InitComponentExtension(); | 1146 InitComponentExtension(); |
| 1174 InitIBusBus(); | 1147 InitIBusBus(); |
| 1175 EXPECT_EQ(1, mock_ibus_client_->set_global_engine_call_count()); | 1148 EXPECT_EQ(ext_id, manager_->GetCurrentInputMethod().id()); |
| 1176 EXPECT_EQ(ext_id, mock_ibus_client_->latest_global_engine_name()); | |
| 1177 } | 1149 } |
| 1178 | 1150 |
| 1179 TEST_F(InputMethodManagerImplTest, | 1151 TEST_F(InputMethodManagerImplTest, |
| 1180 ChangeInputMethodBeforeComponentExtensionInitialization_CompTwoIME) { | 1152 ChangeInputMethodBeforeComponentExtensionInitialization_CompTwoIME) { |
| 1181 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN); | 1153 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN); |
| 1182 const std::string ext_id1 = | 1154 const std::string ext_id1 = |
| 1183 TestableComponentExtensionIMEManager::GetComponentExtensionIMEId( | 1155 TestableComponentExtensionIMEManager::GetComponentExtensionIMEId( |
| 1184 ime_list_[0].id, | 1156 ime_list_[0].id, |
| 1185 ime_list_[0].engines[0].engine_id); | 1157 ime_list_[0].engines[0].engine_id); |
| 1186 const std::string ext_id2 = | 1158 const std::string ext_id2 = |
| 1187 TestableComponentExtensionIMEManager::GetComponentExtensionIMEId( | 1159 TestableComponentExtensionIMEManager::GetComponentExtensionIMEId( |
| 1188 ime_list_[1].id, | 1160 ime_list_[1].id, |
| 1189 ime_list_[1].engines[0].engine_id); | 1161 ime_list_[1].engines[0].engine_id); |
| 1190 std::vector<std::string> ids; | 1162 std::vector<std::string> ids; |
| 1191 ids.push_back(ext_id1); | 1163 ids.push_back(ext_id1); |
| 1192 ids.push_back(ext_id2); | 1164 ids.push_back(ext_id2); |
| 1193 EXPECT_TRUE(manager_->EnableInputMethods(ids)); | 1165 EXPECT_TRUE(manager_->EnableInputMethods(ids)); |
| 1194 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods()); | 1166 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods()); |
| 1195 manager_->ChangeInputMethod(ext_id1); | 1167 manager_->ChangeInputMethod(ext_id1); |
| 1196 manager_->ChangeInputMethod(ext_id2); | 1168 manager_->ChangeInputMethod(ext_id2); |
| 1197 | 1169 |
| 1198 InitComponentExtension(); | 1170 InitComponentExtension(); |
| 1199 InitIBusBus(); | 1171 InitIBusBus(); |
| 1200 EXPECT_EQ(1, mock_ibus_client_->set_global_engine_call_count()); | 1172 EXPECT_EQ(ext_id2, manager_->GetCurrentInputMethod().id()); |
| 1201 EXPECT_EQ(ext_id2, mock_ibus_client_->latest_global_engine_name()); | |
| 1202 } | 1173 } |
| 1203 | 1174 |
| 1204 TEST_F(InputMethodManagerImplTest, | 1175 TEST_F(InputMethodManagerImplTest, |
| 1205 ChangeInputMethod_ComponenteExtensionOneIME) { | 1176 ChangeInputMethod_ComponenteExtensionOneIME) { |
| 1206 InitComponentExtension(); | 1177 InitComponentExtension(); |
| 1207 InitIBusBus(); | 1178 InitIBusBus(); |
| 1208 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN); | 1179 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN); |
| 1209 const std::string ext_id = | 1180 const std::string ext_id = |
| 1210 TestableComponentExtensionIMEManager::GetComponentExtensionIMEId( | 1181 TestableComponentExtensionIMEManager::GetComponentExtensionIMEId( |
| 1211 ime_list_[0].id, | 1182 ime_list_[0].id, |
| 1212 ime_list_[0].engines[0].engine_id); | 1183 ime_list_[0].engines[0].engine_id); |
| 1213 std::vector<std::string> ids; | 1184 std::vector<std::string> ids; |
| 1214 ids.push_back(ext_id); | 1185 ids.push_back(ext_id); |
| 1215 EXPECT_TRUE(manager_->EnableInputMethods(ids)); | 1186 EXPECT_TRUE(manager_->EnableInputMethods(ids)); |
| 1216 EXPECT_EQ(1U, manager_->GetNumActiveInputMethods()); | 1187 EXPECT_EQ(1U, manager_->GetNumActiveInputMethods()); |
| 1217 EXPECT_EQ(1, mock_ibus_client_->set_global_engine_call_count()); | 1188 EXPECT_EQ(ext_id, manager_->GetCurrentInputMethod().id()); |
| 1218 EXPECT_EQ(ext_id, mock_ibus_client_->latest_global_engine_name()); | |
| 1219 } | 1189 } |
| 1220 | 1190 |
| 1221 TEST_F(InputMethodManagerImplTest, | 1191 TEST_F(InputMethodManagerImplTest, |
| 1222 ChangeInputMethod_ComponenteExtensionTwoIME) { | 1192 ChangeInputMethod_ComponenteExtensionTwoIME) { |
| 1223 InitComponentExtension(); | 1193 InitComponentExtension(); |
| 1224 InitIBusBus(); | 1194 InitIBusBus(); |
| 1225 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN); | 1195 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN); |
| 1226 const std::string ext_id1 = | 1196 const std::string ext_id1 = |
| 1227 TestableComponentExtensionIMEManager::GetComponentExtensionIMEId( | 1197 TestableComponentExtensionIMEManager::GetComponentExtensionIMEId( |
| 1228 ime_list_[0].id, | 1198 ime_list_[0].id, |
| 1229 ime_list_[0].engines[0].engine_id); | 1199 ime_list_[0].engines[0].engine_id); |
| 1230 const std::string ext_id2 = | 1200 const std::string ext_id2 = |
| 1231 TestableComponentExtensionIMEManager::GetComponentExtensionIMEId( | 1201 TestableComponentExtensionIMEManager::GetComponentExtensionIMEId( |
| 1232 ime_list_[1].id, | 1202 ime_list_[1].id, |
| 1233 ime_list_[1].engines[0].engine_id); | 1203 ime_list_[1].engines[0].engine_id); |
| 1234 std::vector<std::string> ids; | 1204 std::vector<std::string> ids; |
| 1235 ids.push_back(ext_id1); | 1205 ids.push_back(ext_id1); |
| 1236 ids.push_back(ext_id2); | 1206 ids.push_back(ext_id2); |
| 1237 EXPECT_TRUE(manager_->EnableInputMethods(ids)); | 1207 EXPECT_TRUE(manager_->EnableInputMethods(ids)); |
| 1238 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods()); | 1208 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods()); |
| 1239 EXPECT_EQ(1, mock_ibus_client_->set_global_engine_call_count()); | 1209 EXPECT_EQ(ext_id1, manager_->GetCurrentInputMethod().id()); |
| 1240 EXPECT_EQ(ext_id1, mock_ibus_client_->latest_global_engine_name()); | |
| 1241 manager_->ChangeInputMethod(ext_id2); | 1210 manager_->ChangeInputMethod(ext_id2); |
| 1242 EXPECT_EQ(2, mock_ibus_client_->set_global_engine_call_count()); | 1211 EXPECT_EQ(ext_id2, manager_->GetCurrentInputMethod().id()); |
| 1243 EXPECT_EQ(ext_id2, mock_ibus_client_->latest_global_engine_name()); | |
| 1244 } | 1212 } |
| 1245 | 1213 |
| 1246 TEST_F(InputMethodManagerImplTest, | 1214 TEST_F(InputMethodManagerImplTest, |
| 1247 AsyncComponentExtentionInitializeBeforeIBusDaemonConnection) { | 1215 AsyncComponentExtentionInitializeBeforeIBusDaemonConnection) { |
| 1248 const std::string xkb_id = "xkb:cz::cze"; | 1216 const std::string xkb_id = "xkb:cz::cze"; |
| 1249 const std::string ime_id = nacl_mozc_us_id; | 1217 const std::string ime_id = nacl_mozc_us_id; |
| 1250 const std::string fallback_id = "xkb:us::eng"; | 1218 const std::string fallback_id = "xkb:us::eng"; |
| 1251 std::vector<std::string> ids; | 1219 std::vector<std::string> ids; |
| 1252 ids.push_back(xkb_id); | 1220 ids.push_back(xkb_id); |
| 1253 ids.push_back(ime_id); | 1221 ids.push_back(ime_id); |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1296 EXPECT_EQ(fallback_id, manager_->GetCurrentInputMethod().id()); | 1264 EXPECT_EQ(fallback_id, manager_->GetCurrentInputMethod().id()); |
| 1297 | 1265 |
| 1298 // After component extension IME is initialized, previous specified input | 1266 // After component extension IME is initialized, previous specified input |
| 1299 // method should be automatically enabled. | 1267 // method should be automatically enabled. |
| 1300 InitComponentExtension(); | 1268 InitComponentExtension(); |
| 1301 EXPECT_EQ(xkb_id, manager_->GetCurrentInputMethod().id()); | 1269 EXPECT_EQ(xkb_id, manager_->GetCurrentInputMethod().id()); |
| 1302 } | 1270 } |
| 1303 | 1271 |
| 1304 } // namespace input_method | 1272 } // namespace input_method |
| 1305 } // namespace chromeos | 1273 } // namespace chromeos |
| OLD | NEW |