| 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/common/metrics/metrics_log_manager.h" | 5 #include "chrome/common/metrics/metrics_log_manager.h" |
| 6 | 6 |
| 7 #include <string> | 7 #include <string> |
| 8 #include <utility> | 8 #include <utility> |
| 9 #include <vector> | 9 #include <vector> |
| 10 | 10 |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 110 EXPECT_EQ(ongoing_log, log_manager.current_log()); | 110 EXPECT_EQ(ongoing_log, log_manager.current_log()); |
| 111 | 111 |
| 112 EXPECT_FALSE(log_manager.has_staged_log()); | 112 EXPECT_FALSE(log_manager.has_staged_log()); |
| 113 log_manager.StageNextLogForUpload(); | 113 log_manager.StageNextLogForUpload(); |
| 114 log_manager.DiscardStagedLog(); | 114 log_manager.DiscardStagedLog(); |
| 115 EXPECT_FALSE(log_manager.has_unsent_logs()); | 115 EXPECT_FALSE(log_manager.has_unsent_logs()); |
| 116 } | 116 } |
| 117 | 117 |
| 118 TEST(MetricsLogManagerTest, InterjectedLogPreservesType) { | 118 TEST(MetricsLogManagerTest, InterjectedLogPreservesType) { |
| 119 MetricsLogManager log_manager; | 119 MetricsLogManager log_manager; |
| 120 DummyLogSerializer* serializer = new DummyLogSerializer; |
| 121 log_manager.set_log_serializer(serializer); |
| 122 log_manager.LoadPersistedUnsentLogs(); |
| 120 | 123 |
| 121 MetricsLogBase* ongoing_log = new MetricsLogBase("id", 0, "version"); | 124 MetricsLogBase* ongoing_log = new MetricsLogBase("id", 0, "version"); |
| 122 MetricsLogBase* temp_log = new MetricsLogBase("id", 0, "version"); | 125 MetricsLogBase* temp_log = new MetricsLogBase("id", 0, "version"); |
| 123 | 126 |
| 124 log_manager.BeginLoggingWithLog(ongoing_log, MetricsLogBase::ONGOING_LOG); | 127 log_manager.BeginLoggingWithLog(ongoing_log, MetricsLogBase::ONGOING_LOG); |
| 125 log_manager.PauseCurrentLog(); | 128 log_manager.PauseCurrentLog(); |
| 126 log_manager.BeginLoggingWithLog(temp_log, MetricsLogBase::INITIAL_LOG); | 129 log_manager.BeginLoggingWithLog(temp_log, MetricsLogBase::INITIAL_LOG); |
| 127 log_manager.FinishCurrentLog(); | 130 log_manager.FinishCurrentLog(); |
| 128 log_manager.ResumePausedLog(); | 131 log_manager.ResumePausedLog(); |
| 129 log_manager.StageNextLogForUpload(); | 132 log_manager.StageNextLogForUpload(); |
| 130 log_manager.DiscardStagedLog(); | 133 log_manager.DiscardStagedLog(); |
| 131 | 134 |
| 132 // Verify that the remaining log (which is the original ongoing log) still | 135 // Verify that the remaining log (which is the original ongoing log) still |
| 133 // has the right type. | 136 // has the right type. |
| 134 DummyLogSerializer* serializer = new DummyLogSerializer; | |
| 135 log_manager.set_log_serializer(serializer); | |
| 136 log_manager.FinishCurrentLog(); | 137 log_manager.FinishCurrentLog(); |
| 137 log_manager.PersistUnsentLogs(); | 138 log_manager.PersistUnsentLogs(); |
| 138 EXPECT_EQ(0U, serializer->TypeCount(MetricsLogBase::INITIAL_LOG)); | 139 EXPECT_EQ(0U, serializer->TypeCount(MetricsLogBase::INITIAL_LOG)); |
| 139 EXPECT_EQ(1U, serializer->TypeCount(MetricsLogBase::ONGOING_LOG)); | 140 EXPECT_EQ(1U, serializer->TypeCount(MetricsLogBase::ONGOING_LOG)); |
| 140 } | 141 } |
| 141 | 142 |
| 142 TEST(MetricsLogManagerTest, StoreAndLoad) { | 143 TEST(MetricsLogManagerTest, StoreAndLoad) { |
| 143 std::vector<MetricsLogManager::SerializedLog> initial_logs; | 144 std::vector<MetricsLogManager::SerializedLog> initial_logs; |
| 144 std::vector<MetricsLogManager::SerializedLog> ongoing_logs; | 145 std::vector<MetricsLogManager::SerializedLog> ongoing_logs; |
| 145 | 146 |
| 146 // Set up some in-progress logging in a scoped log manager simulating the | 147 // Set up some in-progress logging in a scoped log manager simulating the |
| 147 // leadup to quitting, then persist as would be done on quit. | 148 // leadup to quitting, then persist as would be done on quit. |
| 148 { | 149 { |
| 149 MetricsLogManager log_manager; | 150 MetricsLogManager log_manager; |
| 150 DummyLogSerializer* serializer = new DummyLogSerializer; | 151 DummyLogSerializer* serializer = new DummyLogSerializer; |
| 151 log_manager.set_log_serializer(serializer); | 152 log_manager.set_log_serializer(serializer); |
| 153 log_manager.LoadPersistedUnsentLogs(); |
| 154 |
| 152 // Simulate a log having already been unsent from a previous session. | 155 // Simulate a log having already been unsent from a previous session. |
| 153 MetricsLogManager::SerializedLog log; | 156 MetricsLogManager::SerializedLog log; |
| 154 std::string text = "proto"; | 157 std::string text = "proto"; |
| 155 log.SwapLogText(&text); | 158 log.SwapLogText(&text); |
| 156 serializer->persisted_logs_[MetricsLogBase::ONGOING_LOG].push_back(log); | 159 serializer->persisted_logs_[MetricsLogBase::ONGOING_LOG].push_back(log); |
| 157 EXPECT_FALSE(log_manager.has_unsent_logs()); | 160 EXPECT_FALSE(log_manager.has_unsent_logs()); |
| 158 log_manager.LoadPersistedUnsentLogs(); | 161 log_manager.LoadPersistedUnsentLogs(); |
| 159 EXPECT_TRUE(log_manager.has_unsent_logs()); | 162 EXPECT_TRUE(log_manager.has_unsent_logs()); |
| 160 | 163 |
| 161 MetricsLogBase* log1 = new MetricsLogBase("id", 0, "version"); | 164 MetricsLogBase* log1 = new MetricsLogBase("id", 0, "version"); |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 221 EXPECT_EQ(0U, serializer->TypeCount(MetricsLogBase::ONGOING_LOG)); | 224 EXPECT_EQ(0U, serializer->TypeCount(MetricsLogBase::ONGOING_LOG)); |
| 222 } | 225 } |
| 223 } | 226 } |
| 224 | 227 |
| 225 TEST(MetricsLogManagerTest, StoreStagedLogTypes) { | 228 TEST(MetricsLogManagerTest, StoreStagedLogTypes) { |
| 226 // Ensure that types are preserved when storing staged logs. | 229 // Ensure that types are preserved when storing staged logs. |
| 227 { | 230 { |
| 228 MetricsLogManager log_manager; | 231 MetricsLogManager log_manager; |
| 229 DummyLogSerializer* serializer = new DummyLogSerializer; | 232 DummyLogSerializer* serializer = new DummyLogSerializer; |
| 230 log_manager.set_log_serializer(serializer); | 233 log_manager.set_log_serializer(serializer); |
| 234 log_manager.LoadPersistedUnsentLogs(); |
| 231 | 235 |
| 232 MetricsLogBase* log = new MetricsLogBase("id", 0, "version"); | 236 MetricsLogBase* log = new MetricsLogBase("id", 0, "version"); |
| 233 log_manager.BeginLoggingWithLog(log, MetricsLogBase::ONGOING_LOG); | 237 log_manager.BeginLoggingWithLog(log, MetricsLogBase::ONGOING_LOG); |
| 234 log_manager.FinishCurrentLog(); | 238 log_manager.FinishCurrentLog(); |
| 235 log_manager.StageNextLogForUpload(); | 239 log_manager.StageNextLogForUpload(); |
| 236 log_manager.StoreStagedLogAsUnsent(MetricsLogManager::NORMAL_STORE); | 240 log_manager.StoreStagedLogAsUnsent(MetricsLogManager::NORMAL_STORE); |
| 237 log_manager.PersistUnsentLogs(); | 241 log_manager.PersistUnsentLogs(); |
| 238 | 242 |
| 239 EXPECT_EQ(0U, serializer->TypeCount(MetricsLogBase::INITIAL_LOG)); | 243 EXPECT_EQ(0U, serializer->TypeCount(MetricsLogBase::INITIAL_LOG)); |
| 240 EXPECT_EQ(1U, serializer->TypeCount(MetricsLogBase::ONGOING_LOG)); | 244 EXPECT_EQ(1U, serializer->TypeCount(MetricsLogBase::ONGOING_LOG)); |
| 241 } | 245 } |
| 242 | 246 |
| 243 { | 247 { |
| 244 MetricsLogManager log_manager; | 248 MetricsLogManager log_manager; |
| 245 DummyLogSerializer* serializer = new DummyLogSerializer; | 249 DummyLogSerializer* serializer = new DummyLogSerializer; |
| 246 log_manager.set_log_serializer(serializer); | 250 log_manager.set_log_serializer(serializer); |
| 251 log_manager.LoadPersistedUnsentLogs(); |
| 247 | 252 |
| 248 MetricsLogBase* log = new MetricsLogBase("id", 0, "version"); | 253 MetricsLogBase* log = new MetricsLogBase("id", 0, "version"); |
| 249 log_manager.BeginLoggingWithLog(log, MetricsLogBase::INITIAL_LOG); | 254 log_manager.BeginLoggingWithLog(log, MetricsLogBase::INITIAL_LOG); |
| 250 log_manager.FinishCurrentLog(); | 255 log_manager.FinishCurrentLog(); |
| 251 log_manager.StageNextLogForUpload(); | 256 log_manager.StageNextLogForUpload(); |
| 252 log_manager.StoreStagedLogAsUnsent(MetricsLogManager::NORMAL_STORE); | 257 log_manager.StoreStagedLogAsUnsent(MetricsLogManager::NORMAL_STORE); |
| 253 log_manager.PersistUnsentLogs(); | 258 log_manager.PersistUnsentLogs(); |
| 254 | 259 |
| 255 EXPECT_EQ(1U, serializer->TypeCount(MetricsLogBase::INITIAL_LOG)); | 260 EXPECT_EQ(1U, serializer->TypeCount(MetricsLogBase::INITIAL_LOG)); |
| 256 EXPECT_EQ(0U, serializer->TypeCount(MetricsLogBase::ONGOING_LOG)); | 261 EXPECT_EQ(0U, serializer->TypeCount(MetricsLogBase::ONGOING_LOG)); |
| 257 } | 262 } |
| 258 } | 263 } |
| 259 | 264 |
| 260 TEST(MetricsLogManagerTest, LargeLogDiscarding) { | 265 TEST(MetricsLogManagerTest, LargeLogDiscarding) { |
| 261 MetricsLogManager log_manager; | 266 MetricsLogManager log_manager; |
| 262 DummyLogSerializer* serializer = new DummyLogSerializer; | 267 DummyLogSerializer* serializer = new DummyLogSerializer; |
| 263 log_manager.set_log_serializer(serializer); | 268 log_manager.set_log_serializer(serializer); |
| 269 log_manager.LoadPersistedUnsentLogs(); |
| 270 |
| 264 // Set the size threshold very low, to verify that it's honored. | 271 // Set the size threshold very low, to verify that it's honored. |
| 265 log_manager.set_max_ongoing_log_store_size(1); | 272 log_manager.set_max_ongoing_log_store_size(1); |
| 266 | 273 |
| 267 MetricsLogBase* log1 = new MetricsLogBase("id", 0, "version"); | 274 MetricsLogBase* log1 = new MetricsLogBase("id", 0, "version"); |
| 268 MetricsLogBase* log2 = new MetricsLogBase("id", 0, "version"); | 275 MetricsLogBase* log2 = new MetricsLogBase("id", 0, "version"); |
| 269 log_manager.BeginLoggingWithLog(log1, MetricsLogBase::INITIAL_LOG); | 276 log_manager.BeginLoggingWithLog(log1, MetricsLogBase::INITIAL_LOG); |
| 270 log_manager.FinishCurrentLog(); | 277 log_manager.FinishCurrentLog(); |
| 271 log_manager.BeginLoggingWithLog(log2, MetricsLogBase::ONGOING_LOG); | 278 log_manager.BeginLoggingWithLog(log2, MetricsLogBase::ONGOING_LOG); |
| 272 log_manager.FinishCurrentLog(); | 279 log_manager.FinishCurrentLog(); |
| 273 | 280 |
| 274 // Only the ongoing log should be written out, due to the threshold. | 281 // Only the ongoing log should be written out, due to the threshold. |
| 275 log_manager.PersistUnsentLogs(); | 282 log_manager.PersistUnsentLogs(); |
| 276 EXPECT_EQ(1U, serializer->TypeCount(MetricsLogBase::INITIAL_LOG)); | 283 EXPECT_EQ(1U, serializer->TypeCount(MetricsLogBase::INITIAL_LOG)); |
| 277 EXPECT_EQ(0U, serializer->TypeCount(MetricsLogBase::ONGOING_LOG)); | 284 EXPECT_EQ(0U, serializer->TypeCount(MetricsLogBase::ONGOING_LOG)); |
| 278 } | 285 } |
| 279 | 286 |
| 280 TEST(MetricsLogManagerTest, ProvisionalStoreStandardFlow) { | 287 TEST(MetricsLogManagerTest, ProvisionalStoreStandardFlow) { |
| 281 // Ensure that provisional store works, and discards the correct log. | 288 // Ensure that provisional store works, and discards the correct log. |
| 282 { | 289 { |
| 283 MetricsLogManager log_manager; | 290 MetricsLogManager log_manager; |
| 291 DummyLogSerializer* serializer = new DummyLogSerializer; |
| 292 log_manager.set_log_serializer(serializer); |
| 293 log_manager.LoadPersistedUnsentLogs(); |
| 294 |
| 284 MetricsLogBase* log1 = new MetricsLogBase("id", 0, "version"); | 295 MetricsLogBase* log1 = new MetricsLogBase("id", 0, "version"); |
| 285 MetricsLogBase* log2 = new MetricsLogBase("id", 0, "version"); | 296 MetricsLogBase* log2 = new MetricsLogBase("id", 0, "version"); |
| 286 log_manager.BeginLoggingWithLog(log1, MetricsLogBase::INITIAL_LOG); | 297 log_manager.BeginLoggingWithLog(log1, MetricsLogBase::INITIAL_LOG); |
| 287 log_manager.FinishCurrentLog(); | 298 log_manager.FinishCurrentLog(); |
| 288 log_manager.BeginLoggingWithLog(log2, MetricsLogBase::ONGOING_LOG); | 299 log_manager.BeginLoggingWithLog(log2, MetricsLogBase::ONGOING_LOG); |
| 289 log_manager.StageNextLogForUpload(); | 300 log_manager.StageNextLogForUpload(); |
| 290 log_manager.StoreStagedLogAsUnsent(MetricsLogManager::PROVISIONAL_STORE); | 301 log_manager.StoreStagedLogAsUnsent(MetricsLogManager::PROVISIONAL_STORE); |
| 291 log_manager.FinishCurrentLog(); | 302 log_manager.FinishCurrentLog(); |
| 292 log_manager.DiscardLastProvisionalStore(); | 303 log_manager.DiscardLastProvisionalStore(); |
| 293 | 304 |
| 294 DummyLogSerializer* serializer = new DummyLogSerializer; | |
| 295 log_manager.set_log_serializer(serializer); | |
| 296 log_manager.PersistUnsentLogs(); | 305 log_manager.PersistUnsentLogs(); |
| 297 EXPECT_EQ(0U, serializer->TypeCount(MetricsLogBase::INITIAL_LOG)); | 306 EXPECT_EQ(0U, serializer->TypeCount(MetricsLogBase::INITIAL_LOG)); |
| 298 EXPECT_EQ(1U, serializer->TypeCount(MetricsLogBase::ONGOING_LOG)); | 307 EXPECT_EQ(1U, serializer->TypeCount(MetricsLogBase::ONGOING_LOG)); |
| 299 } | 308 } |
| 300 } | 309 } |
| 301 | 310 |
| 302 TEST(MetricsLogManagerTest, ProvisionalStoreNoop) { | 311 TEST(MetricsLogManagerTest, ProvisionalStoreNoop) { |
| 303 // Ensure that trying to drop a sent log is a no-op, even if another log has | 312 // Ensure that trying to drop a sent log is a no-op, even if another log has |
| 304 // since been staged. | 313 // since been staged. |
| 305 { | 314 { |
| 306 MetricsLogManager log_manager; | 315 MetricsLogManager log_manager; |
| 316 DummyLogSerializer* serializer = new DummyLogSerializer; |
| 317 log_manager.set_log_serializer(serializer); |
| 318 log_manager.LoadPersistedUnsentLogs(); |
| 319 |
| 307 MetricsLogBase* log1 = new MetricsLogBase("id", 0, "version"); | 320 MetricsLogBase* log1 = new MetricsLogBase("id", 0, "version"); |
| 308 MetricsLogBase* log2 = new MetricsLogBase("id", 0, "version"); | 321 MetricsLogBase* log2 = new MetricsLogBase("id", 0, "version"); |
| 309 log_manager.BeginLoggingWithLog(log1, MetricsLogBase::ONGOING_LOG); | 322 log_manager.BeginLoggingWithLog(log1, MetricsLogBase::ONGOING_LOG); |
| 310 log_manager.FinishCurrentLog(); | 323 log_manager.FinishCurrentLog(); |
| 311 log_manager.StageNextLogForUpload(); | 324 log_manager.StageNextLogForUpload(); |
| 312 log_manager.StoreStagedLogAsUnsent(MetricsLogManager::PROVISIONAL_STORE); | 325 log_manager.StoreStagedLogAsUnsent(MetricsLogManager::PROVISIONAL_STORE); |
| 313 log_manager.StageNextLogForUpload(); | 326 log_manager.StageNextLogForUpload(); |
| 314 log_manager.DiscardStagedLog(); | 327 log_manager.DiscardStagedLog(); |
| 315 log_manager.BeginLoggingWithLog(log2, MetricsLogBase::ONGOING_LOG); | 328 log_manager.BeginLoggingWithLog(log2, MetricsLogBase::ONGOING_LOG); |
| 316 log_manager.FinishCurrentLog(); | 329 log_manager.FinishCurrentLog(); |
| 317 log_manager.StageNextLogForUpload(); | 330 log_manager.StageNextLogForUpload(); |
| 318 log_manager.StoreStagedLogAsUnsent(MetricsLogManager::NORMAL_STORE); | 331 log_manager.StoreStagedLogAsUnsent(MetricsLogManager::NORMAL_STORE); |
| 319 log_manager.DiscardLastProvisionalStore(); | 332 log_manager.DiscardLastProvisionalStore(); |
| 320 | 333 |
| 321 DummyLogSerializer* serializer = new DummyLogSerializer; | |
| 322 log_manager.set_log_serializer(serializer); | |
| 323 log_manager.PersistUnsentLogs(); | 334 log_manager.PersistUnsentLogs(); |
| 324 EXPECT_EQ(1U, serializer->TypeCount(MetricsLogBase::ONGOING_LOG)); | 335 EXPECT_EQ(1U, serializer->TypeCount(MetricsLogBase::ONGOING_LOG)); |
| 325 } | 336 } |
| 326 | 337 |
| 327 // Ensure that trying to drop more than once is a no-op | 338 // Ensure that trying to drop more than once is a no-op |
| 328 { | 339 { |
| 329 MetricsLogManager log_manager; | 340 MetricsLogManager log_manager; |
| 341 DummyLogSerializer* serializer = new DummyLogSerializer; |
| 342 log_manager.set_log_serializer(serializer); |
| 343 log_manager.LoadPersistedUnsentLogs(); |
| 344 |
| 330 MetricsLogBase* log1 = new MetricsLogBase("id", 0, "version"); | 345 MetricsLogBase* log1 = new MetricsLogBase("id", 0, "version"); |
| 331 MetricsLogBase* log2 = new MetricsLogBase("id", 0, "version"); | 346 MetricsLogBase* log2 = new MetricsLogBase("id", 0, "version"); |
| 332 log_manager.BeginLoggingWithLog(log1, MetricsLogBase::ONGOING_LOG); | 347 log_manager.BeginLoggingWithLog(log1, MetricsLogBase::ONGOING_LOG); |
| 333 log_manager.FinishCurrentLog(); | 348 log_manager.FinishCurrentLog(); |
| 334 log_manager.StageNextLogForUpload(); | 349 log_manager.StageNextLogForUpload(); |
| 335 log_manager.StoreStagedLogAsUnsent(MetricsLogManager::NORMAL_STORE); | 350 log_manager.StoreStagedLogAsUnsent(MetricsLogManager::NORMAL_STORE); |
| 336 log_manager.BeginLoggingWithLog(log2, MetricsLogBase::ONGOING_LOG); | 351 log_manager.BeginLoggingWithLog(log2, MetricsLogBase::ONGOING_LOG); |
| 337 log_manager.FinishCurrentLog(); | 352 log_manager.FinishCurrentLog(); |
| 338 log_manager.StageNextLogForUpload(); | 353 log_manager.StageNextLogForUpload(); |
| 339 log_manager.StoreStagedLogAsUnsent(MetricsLogManager::PROVISIONAL_STORE); | 354 log_manager.StoreStagedLogAsUnsent(MetricsLogManager::PROVISIONAL_STORE); |
| 340 log_manager.DiscardLastProvisionalStore(); | 355 log_manager.DiscardLastProvisionalStore(); |
| 341 log_manager.DiscardLastProvisionalStore(); | 356 log_manager.DiscardLastProvisionalStore(); |
| 342 | 357 |
| 343 DummyLogSerializer* serializer = new DummyLogSerializer; | |
| 344 log_manager.set_log_serializer(serializer); | |
| 345 log_manager.PersistUnsentLogs(); | 358 log_manager.PersistUnsentLogs(); |
| 346 EXPECT_EQ(1U, serializer->TypeCount(MetricsLogBase::ONGOING_LOG)); | 359 EXPECT_EQ(1U, serializer->TypeCount(MetricsLogBase::ONGOING_LOG)); |
| 347 } | 360 } |
| 348 } | 361 } |
| 349 | 362 |
| 350 TEST(MetricsLogManagerTest, SerializedLog) { | 363 TEST(MetricsLogManagerTest, SerializedLog) { |
| 351 const char kFooText[] = "foo"; | 364 const char kFooText[] = "foo"; |
| 352 const std::string foo_hash = base::SHA1HashString(kFooText); | 365 const std::string foo_hash = base::SHA1HashString(kFooText); |
| 353 const char kBarText[] = "bar"; | 366 const char kBarText[] = "bar"; |
| 354 const std::string bar_hash = base::SHA1HashString(kBarText); | 367 const std::string bar_hash = base::SHA1HashString(kBarText); |
| (...skipping 25 matching lines...) Expand all Loading... |
| 380 foo = kFooText; | 393 foo = kFooText; |
| 381 log2.SwapLogText(&foo); | 394 log2.SwapLogText(&foo); |
| 382 log.Swap(&log2); | 395 log.Swap(&log2); |
| 383 EXPECT_FALSE(log.IsEmpty()); | 396 EXPECT_FALSE(log.IsEmpty()); |
| 384 EXPECT_EQ(kFooText, log.log_text()); | 397 EXPECT_EQ(kFooText, log.log_text()); |
| 385 EXPECT_EQ(foo_hash, log.log_hash()); | 398 EXPECT_EQ(foo_hash, log.log_hash()); |
| 386 EXPECT_TRUE(log2.IsEmpty()); | 399 EXPECT_TRUE(log2.IsEmpty()); |
| 387 EXPECT_TRUE(log2.log_text().empty()); | 400 EXPECT_TRUE(log2.log_text().empty()); |
| 388 EXPECT_TRUE(log2.log_hash().empty()); | 401 EXPECT_TRUE(log2.log_hash().empty()); |
| 389 } | 402 } |
| OLD | NEW |