Chromium Code Reviews| 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 "content/browser/loader/resource_scheduler.h" | 5 #include "content/browser/loader/resource_scheduler.h" |
| 6 | 6 |
| 7 #include "base/memory/scoped_vector.h" | 7 #include "base/memory/scoped_vector.h" |
| 8 #include "base/message_loop/message_loop.h" | 8 #include "base/message_loop/message_loop.h" |
| 9 #include "base/metrics/field_trial.h" | 9 #include "base/metrics/field_trial.h" |
| 10 #include "base/run_loop.h" | 10 #include "base/run_loop.h" |
| (...skipping 2342 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2353 } | 2353 } |
| 2354 scoped_ptr<TestRequest> lowest(NewRequestWithChildAndRoute( | 2354 scoped_ptr<TestRequest> lowest(NewRequestWithChildAndRoute( |
| 2355 "http://host/lowest", net::LOWEST, kChildId2, kRouteId2)); | 2355 "http://host/lowest", net::LOWEST, kChildId2, kRouteId2)); |
| 2356 EXPECT_FALSE(lowest->started()); | 2356 EXPECT_FALSE(lowest->started()); |
| 2357 scheduler_->OnClientDeleted(kChildId2, kRouteId2); | 2357 scheduler_->OnClientDeleted(kChildId2, kRouteId2); |
| 2358 high.reset(); | 2358 high.reset(); |
| 2359 delayable_requests.clear(); | 2359 delayable_requests.clear(); |
| 2360 EXPECT_TRUE(lowest->started()); | 2360 EXPECT_TRUE(lowest->started()); |
| 2361 } | 2361 } |
| 2362 | 2362 |
| 2363 TEST_F(ResourceSchedulerTest, DefaultLayoutBlockingPriority) { | |
| 2364 const int kDeferLateScripts = 0; | |
| 2365 const int kIncreaseFontPriority = 0; | |
| 2366 const int kIncreaseAsyncScriptPriority = 0; | |
| 2367 const int kEnablePriorityIncrease = 0; | |
| 2368 const int kEnableLayoutBlockingThreshold = 0; | |
| 2369 const int kLayoutBlockingThreshold = 0; | |
| 2370 const int kMaxNumDelayableWhileLayoutBlocking = 1; | |
| 2371 const int kMaxNumDelayableRequestsPerClient = 10; | |
| 2372 ASSERT_TRUE(InitializeFieldTrials(base::StringPrintf( | |
| 2373 "ResourcePriorities/LayoutBlocking_%d%d%d%d%d_%d_%d_%d/", | |
| 2374 kDeferLateScripts, | |
| 2375 kIncreaseFontPriority, | |
| 2376 kIncreaseAsyncScriptPriority, | |
| 2377 kEnablePriorityIncrease, | |
| 2378 kEnableLayoutBlockingThreshold, | |
| 2379 kLayoutBlockingThreshold, | |
| 2380 kMaxNumDelayableWhileLayoutBlocking, | |
| 2381 kMaxNumDelayableRequestsPerClient))); | |
| 2382 InitializeScheduler(); | |
| 2383 scoped_ptr<TestRequest> high( | |
| 2384 NewRequest("http://hosthigh/high", net::HIGHEST)); | |
| 2385 scoped_ptr<TestRequest> high2( | |
| 2386 NewRequest("http://hosthigh/high", net::HIGHEST)); | |
| 2387 scoped_ptr<TestRequest> medium( | |
| 2388 NewRequest("http://hostmedium/medium", net::MEDIUM)); | |
| 2389 scoped_ptr<TestRequest> medium2( | |
| 2390 NewRequest("http://hostmedium/medium", net::MEDIUM)); | |
| 2391 scoped_ptr<TestRequest> low(NewRequest("http://hostlow/low", net::LOW)); | |
| 2392 scoped_ptr<TestRequest> low2(NewRequest("http://hostlow/low", net::LOW)); | |
| 2393 scoped_ptr<TestRequest> lowest(NewRequest("http://hostlowest/lowest", net::LOW EST)); | |
| 2394 scoped_ptr<TestRequest> lowest2( | |
| 2395 NewRequest("http://hostlowest/lowest", net::LOWEST)); | |
| 2396 EXPECT_TRUE(high->started()); | |
| 2397 EXPECT_TRUE(high2->started()); | |
| 2398 EXPECT_TRUE(medium->started()); | |
| 2399 EXPECT_TRUE(medium2->started()); | |
| 2400 EXPECT_TRUE(low->started()); | |
| 2401 EXPECT_TRUE(low2->started()); | |
| 2402 EXPECT_TRUE(lowest->started()); | |
| 2403 EXPECT_FALSE(lowest2->started()); | |
| 2404 lowest.reset(); | |
| 2405 EXPECT_TRUE(lowest2->started()); | |
| 2406 } | |
| 2407 | |
| 2408 TEST_F(ResourceSchedulerTest, IncreaseLayoutBlockingPriority) { | |
| 2409 // Changes the level of priorities that are allowed during layout-blocking | |
| 2410 // from net::LOWEST to net::LOW. | |
| 2411 const int kDeferLateScripts = 0; | |
| 2412 const int kIncreaseFontPriority = 0; | |
| 2413 const int kIncreaseAsyncScriptPriority = 0; | |
| 2414 const int kEnablePriorityIncrease = 1; | |
| 2415 const int kEnableLayoutBlockingThreshold = 0; | |
| 2416 const int kLayoutBlockingThreshold = 0; | |
| 2417 const int kMaxNumDelayableWhileLayoutBlocking = 1; | |
| 2418 const int kMaxNumDelayableRequestsPerClient = 10; | |
| 2419 ASSERT_TRUE(InitializeFieldTrials(base::StringPrintf( | |
| 2420 "ResourcePriorities/LayoutBlocking_%d%d%d%d%d_%d_%d_%d/", | |
| 2421 kDeferLateScripts, | |
| 2422 kIncreaseFontPriority, | |
| 2423 kIncreaseAsyncScriptPriority, | |
| 2424 kEnablePriorityIncrease, | |
| 2425 kEnableLayoutBlockingThreshold, | |
| 2426 kLayoutBlockingThreshold, | |
| 2427 kMaxNumDelayableWhileLayoutBlocking, | |
| 2428 kMaxNumDelayableRequestsPerClient))); | |
| 2429 InitializeScheduler(); | |
| 2430 scoped_ptr<TestRequest> high( | |
| 2431 NewRequest("http://hosthigh/high", net::HIGHEST)); | |
| 2432 scoped_ptr<TestRequest> high2( | |
| 2433 NewRequest("http://hosthigh/high", net::HIGHEST)); | |
| 2434 scoped_ptr<TestRequest> medium( | |
| 2435 NewRequest("http://hostmedium/medium", net::MEDIUM)); | |
| 2436 scoped_ptr<TestRequest> medium2( | |
| 2437 NewRequest("http://hostmedium/medium", net::MEDIUM)); | |
| 2438 scoped_ptr<TestRequest> low(NewRequest("http://hostlow/low", net::LOW)); | |
| 2439 scoped_ptr<TestRequest> low2(NewRequest("http://hostlow/low", net::LOW)); | |
| 2440 scoped_ptr<TestRequest> lowest(NewRequest("http://hostlowest/lowest", net::LOW EST)); | |
| 2441 scoped_ptr<TestRequest> lowest2( | |
| 2442 NewRequest("http://hostlowest/lowest", net::LOWEST)); | |
| 2443 EXPECT_TRUE(high->started()); | |
| 2444 EXPECT_TRUE(high2->started()); | |
| 2445 EXPECT_TRUE(medium->started()); | |
| 2446 EXPECT_TRUE(medium2->started()); | |
| 2447 EXPECT_TRUE(low->started()); | |
| 2448 EXPECT_FALSE(low2->started()); | |
| 2449 EXPECT_FALSE(lowest->started()); | |
| 2450 EXPECT_FALSE(lowest2->started()); | |
| 2451 low.reset(); | |
| 2452 EXPECT_TRUE(low2->started()); | |
| 2453 EXPECT_FALSE(lowest->started()); | |
| 2454 EXPECT_FALSE(lowest2->started()); | |
| 2455 low2.reset(); | |
| 2456 EXPECT_TRUE(lowest->started()); | |
| 2457 EXPECT_FALSE(lowest2->started()); | |
| 2458 lowest.reset(); | |
| 2459 EXPECT_TRUE(lowest2->started()); | |
| 2460 } | |
| 2461 | |
| 2462 TEST_F(ResourceSchedulerTest, UseLayoutBlockingThresholdOne) { | |
| 2463 // Prevents any low priority requests from starting while more than | |
| 2464 // N high priority requests are pending (before body). | |
| 2465 const int kDeferLateScripts = 0; | |
| 2466 const int kIncreaseFontPriority = 0; | |
| 2467 const int kIncreaseAsyncScriptPriority = 0; | |
| 2468 const int kEnablePriorityIncrease = 0; | |
| 2469 const int kEnableLayoutBlockingThreshold = 1; | |
| 2470 const int kLayoutBlockingThreshold = 1; | |
| 2471 const int kMaxNumDelayableWhileLayoutBlocking = 1; | |
| 2472 const int kMaxNumDelayableRequestsPerClient = 10; | |
| 2473 ASSERT_TRUE(InitializeFieldTrials(base::StringPrintf( | |
| 2474 "ResourcePriorities/LayoutBlocking_%d%d%d%d%d_%d_%d_%d/", | |
| 2475 kDeferLateScripts, | |
| 2476 kIncreaseFontPriority, | |
| 2477 kIncreaseAsyncScriptPriority, | |
| 2478 kEnablePriorityIncrease, | |
| 2479 kEnableLayoutBlockingThreshold, | |
| 2480 kLayoutBlockingThreshold, | |
| 2481 kMaxNumDelayableWhileLayoutBlocking, | |
| 2482 kMaxNumDelayableRequestsPerClient))); | |
| 2483 InitializeScheduler(); | |
| 2484 scoped_ptr<TestRequest> high(NewRequest("http://host/high", net::HIGHEST)); | |
| 2485 scoped_ptr<TestRequest> high2(NewRequest("http://host/high", net::HIGHEST)); | |
| 2486 scoped_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST)); | |
| 2487 scoped_ptr<TestRequest> low2(NewRequest("http://host/low", net::LOWEST)); | |
| 2488 EXPECT_TRUE(high->started()); | |
| 2489 EXPECT_TRUE(high2->started()); | |
| 2490 EXPECT_FALSE(low->started()); | |
| 2491 EXPECT_FALSE(low2->started()); | |
| 2492 high.reset(); | |
| 2493 EXPECT_TRUE(low->started()); | |
| 2494 EXPECT_FALSE(low2->started()); | |
| 2495 high2.reset(); | |
| 2496 EXPECT_FALSE(low2->started()); | |
| 2497 scheduler()->OnWillInsertBody(kChildId, kRouteId); | |
| 2498 EXPECT_TRUE(low2->started()); | |
| 2499 } | |
| 2500 | |
| 2501 TEST_F(ResourceSchedulerTest, UseLayoutBlockingThresholdTwo) { | |
| 2502 // Prevents any low priority requests from starting while more than | |
| 2503 // N high priority requests are pending (before body). | |
| 2504 const int kDeferLateScripts = 0; | |
| 2505 const int kIncreaseFontPriority = 0; | |
| 2506 const int kIncreaseAsyncScriptPriority = 0; | |
| 2507 const int kEnablePriorityIncrease = 0; | |
| 2508 const int kEnableLayoutBlockingThreshold = 1; | |
| 2509 const int kLayoutBlockingThreshold = 2; | |
| 2510 const int kMaxNumDelayableWhileLayoutBlocking = 1; | |
| 2511 const int kMaxNumDelayableRequestsPerClient = 10; | |
| 2512 ASSERT_TRUE(InitializeFieldTrials(base::StringPrintf( | |
| 2513 "ResourcePriorities/LayoutBlocking_%d%d%d%d%d_%d_%d_%d/", | |
| 2514 kDeferLateScripts, | |
| 2515 kIncreaseFontPriority, | |
| 2516 kIncreaseAsyncScriptPriority, | |
| 2517 kEnablePriorityIncrease, | |
| 2518 kEnableLayoutBlockingThreshold, | |
| 2519 kLayoutBlockingThreshold, | |
| 2520 kMaxNumDelayableWhileLayoutBlocking, | |
| 2521 kMaxNumDelayableRequestsPerClient))); | |
| 2522 InitializeScheduler(); | |
| 2523 scoped_ptr<TestRequest> high(NewRequest("http://host/high", net::HIGHEST)); | |
| 2524 scoped_ptr<TestRequest> high2(NewRequest("http://host/high", net::HIGHEST)); | |
| 2525 scoped_ptr<TestRequest> high3(NewRequest("http://host/high", net::HIGHEST)); | |
| 2526 scoped_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST)); | |
| 2527 scoped_ptr<TestRequest> low2(NewRequest("http://host/low", net::LOWEST)); | |
| 2528 EXPECT_TRUE(high->started()); | |
| 2529 EXPECT_TRUE(high2->started()); | |
| 2530 EXPECT_TRUE(high3->started()); | |
| 2531 EXPECT_FALSE(low->started()); | |
| 2532 EXPECT_FALSE(low2->started()); | |
| 2533 high.reset(); | |
| 2534 EXPECT_TRUE(low->started()); | |
| 2535 EXPECT_FALSE(low2->started()); | |
| 2536 high2.reset(); | |
| 2537 high3.reset(); | |
| 2538 EXPECT_FALSE(low2->started()); | |
| 2539 scheduler()->OnWillInsertBody(kChildId, kRouteId); | |
| 2540 EXPECT_TRUE(low2->started()); | |
| 2541 } | |
| 2542 | |
| 2543 TEST_F(ResourceSchedulerTest, TwoDelayableLoadsUntilBodyInserted) { | |
| 2544 // Allow for two low priority requests to be in flight at any point in time | |
| 2545 // during the layout-blocking phase of loading. | |
| 2546 const int kDeferLateScripts = 0; | |
| 2547 const int kIncreaseFontPriority = 0; | |
| 2548 const int kIncreaseAsyncScriptPriority = 0; | |
| 2549 const int kEnablePriorityIncrease = 0; | |
| 2550 const int kEnableLayoutBlockingThreshold = 0; | |
| 2551 const int kLayoutBlockingThreshold = 0; | |
| 2552 const int kMaxNumDelayableWhileLayoutBlocking = 2; | |
| 2553 const int kMaxNumDelayableRequestsPerClient = 10; | |
| 2554 ASSERT_TRUE(InitializeFieldTrials(base::StringPrintf( | |
| 2555 "ResourcePriorities/LayoutBlocking_%d%d%d%d%d_%d_%d_%d/", | |
| 2556 kDeferLateScripts, | |
| 2557 kIncreaseFontPriority, | |
| 2558 kIncreaseAsyncScriptPriority, | |
| 2559 kEnablePriorityIncrease, | |
| 2560 kEnableLayoutBlockingThreshold, | |
| 2561 kLayoutBlockingThreshold, | |
| 2562 kMaxNumDelayableWhileLayoutBlocking, | |
| 2563 kMaxNumDelayableRequestsPerClient))); | |
| 2564 InitializeScheduler(); | |
| 2565 scoped_ptr<TestRequest> high(NewRequest("http://host/high", net::HIGHEST)); | |
| 2566 scoped_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST)); | |
| 2567 scoped_ptr<TestRequest> low2(NewRequest("http://host/low", net::LOWEST)); | |
| 2568 scoped_ptr<TestRequest> low3(NewRequest("http://host/low", net::LOWEST)); | |
| 2569 EXPECT_TRUE(high->started()); | |
| 2570 EXPECT_TRUE(low->started()); | |
| 2571 EXPECT_TRUE(low2->started()); | |
| 2572 EXPECT_FALSE(low3->started()); | |
| 2573 high.reset(); | |
| 2574 scheduler()->OnWillInsertBody(kChildId, kRouteId); | |
| 2575 EXPECT_TRUE(low3->started()); | |
| 2576 } | |
| 2577 | |
| 2578 TEST_F(ResourceSchedulerTest, | |
| 2579 UseLayoutBlockingThresholdOneAndTwoDelayableLoadsUntilBodyInserted) { | |
| 2580 // Allow for two low priority requests to be in flight during the | |
| 2581 // layout-blocking phase of loading but only when there is not more than one | |
| 2582 // in-flight high priority request. | |
| 2583 const int kDeferLateScripts = 0; | |
| 2584 const int kIncreaseFontPriority = 0; | |
| 2585 const int kIncreaseAsyncScriptPriority = 0; | |
| 2586 const int kEnablePriorityIncrease = 0; | |
| 2587 const int kEnableLayoutBlockingThreshold = 1; | |
| 2588 const int kLayoutBlockingThreshold = 1; | |
| 2589 const int kMaxNumDelayableWhileLayoutBlocking = 2; | |
| 2590 const int kMaxNumDelayableRequestsPerClient = 10; | |
| 2591 ASSERT_TRUE(InitializeFieldTrials(base::StringPrintf( | |
| 2592 "ResourcePriorities/LayoutBlocking_%d%d%d%d%d_%d_%d_%d/", | |
| 2593 kDeferLateScripts, | |
| 2594 kIncreaseFontPriority, | |
| 2595 kIncreaseAsyncScriptPriority, | |
| 2596 kEnablePriorityIncrease, | |
| 2597 kEnableLayoutBlockingThreshold, | |
| 2598 kLayoutBlockingThreshold, | |
| 2599 kMaxNumDelayableWhileLayoutBlocking, | |
| 2600 kMaxNumDelayableRequestsPerClient))); | |
| 2601 InitializeScheduler(); | |
| 2602 scoped_ptr<TestRequest> high(NewRequest("http://host/high", net::HIGHEST)); | |
| 2603 scoped_ptr<TestRequest> high2(NewRequest("http://host/high", net::HIGHEST)); | |
| 2604 scoped_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST)); | |
| 2605 scoped_ptr<TestRequest> low2(NewRequest("http://host/low", net::LOWEST)); | |
| 2606 scoped_ptr<TestRequest> low3(NewRequest("http://host/low", net::LOWEST)); | |
| 2607 EXPECT_TRUE(high->started()); | |
| 2608 EXPECT_TRUE(high2->started()); | |
| 2609 EXPECT_FALSE(low->started()); | |
| 2610 EXPECT_FALSE(low2->started()); | |
| 2611 EXPECT_FALSE(low3->started()); | |
| 2612 high.reset(); | |
| 2613 EXPECT_TRUE(low->started()); | |
| 2614 EXPECT_TRUE(low2->started()); | |
| 2615 EXPECT_FALSE(low3->started()); | |
| 2616 high2.reset(); | |
| 2617 scheduler()->OnWillInsertBody(kChildId, kRouteId); | |
| 2618 EXPECT_TRUE(low3->started()); | |
| 2619 } | |
| 2620 | |
| 2621 TEST_F(ResourceSchedulerTest, TwentyMaxNumDelayableRequestsPerClient) { | |
| 2622 // Do not exceed 20 low-priority requests to be in flight across all hosts | |
| 2623 // at any point in time. | |
| 2624 const int kDeferLateScripts = 0; | |
| 2625 const int kIncreaseFontPriority = 0; | |
| 2626 const int kIncreaseAsyncScriptPriority = 0; | |
| 2627 const int kEnablePriorityIncrease = 0; | |
| 2628 const int kEnableLayoutBlockingThreshold = 0; | |
| 2629 const int kLayoutBlockingThreshold = 0; | |
| 2630 const int kMaxNumDelayableWhileLayoutBlocking = 1; | |
| 2631 const int kMaxNumDelayableRequestsPerClient = 20; | |
| 2632 ASSERT_TRUE(InitializeFieldTrials(base::StringPrintf( | |
| 2633 "ResourcePriorities/LayoutBlocking_%d%d%d%d%d_%d_%d_%d/", | |
| 2634 kDeferLateScripts, | |
| 2635 kIncreaseFontPriority, | |
| 2636 kIncreaseAsyncScriptPriority, | |
| 2637 kEnablePriorityIncrease, | |
| 2638 kEnableLayoutBlockingThreshold, | |
| 2639 kLayoutBlockingThreshold, | |
| 2640 kMaxNumDelayableWhileLayoutBlocking, | |
| 2641 kMaxNumDelayableRequestsPerClient))); | |
| 2642 InitializeScheduler(); | |
| 2643 | |
| 2644 // Only load low priority resources if there's a body. | |
| 2645 scheduler()->OnWillInsertBody(kChildId, kRouteId); | |
| 2646 | |
| 2647 // Queue requests from different hosts until the total limit is reached. | |
| 2648 ScopedVector<TestRequest> lows_differenthosts; | |
| 2649 for (int i = 0; i < kMaxNumDelayableRequestsPerClient; ++i) { | |
| 2650 string url = "http://host" + base::IntToString(i) + "/low"; | |
| 2651 lows_differenthosts.push_back(NewRequest(url.c_str(), net::LOWEST)); | |
| 2652 EXPECT_TRUE(lows_differenthosts[i]->started()); | |
| 2653 } | |
| 2654 | |
| 2655 scoped_ptr<TestRequest> last_differenthost(NewRequest("http://host_new/last", | |
| 2656 net::LOWEST)); | |
| 2657 EXPECT_FALSE(last_differenthost->started()); | |
| 2658 } | |
| 2659 | |
| 2660 TEST_F(ResourceSchedulerTest, | |
| 2661 TwentyMaxNumDelayableRequestsPerClientWithEverythingEnabled) { | |
| 2662 // Do not exceed 20 low-priority requests to be in flight across all hosts | |
| 2663 // at any point in time and make sure it still works correctly when the other | |
| 2664 // options are toggled. | |
| 2665 const int kDeferLateScripts = 1; | |
| 2666 const int kIncreaseFontPriority = 1; | |
| 2667 const int kIncreaseAsyncScriptPriority = 1; | |
| 2668 const int kEnablePriorityIncrease = 1; | |
| 2669 const int kEnableLayoutBlockingThreshold = 1; | |
| 2670 const int kLayoutBlockingThreshold = 1; | |
| 2671 const int kMaxNumDelayableWhileLayoutBlocking = 1; | |
| 2672 const int kMaxNumDelayableRequestsPerClient = 20; | |
| 2673 ASSERT_TRUE(InitializeFieldTrials(base::StringPrintf( | |
| 2674 "ResourcePriorities/LayoutBlocking_%d%d%d%d%d_%d_%d_%d/", | |
| 2675 kDeferLateScripts, | |
| 2676 kIncreaseFontPriority, | |
| 2677 kIncreaseAsyncScriptPriority, | |
| 2678 kEnablePriorityIncrease, | |
| 2679 kEnableLayoutBlockingThreshold, | |
| 2680 kLayoutBlockingThreshold, | |
| 2681 kMaxNumDelayableWhileLayoutBlocking, | |
| 2682 kMaxNumDelayableRequestsPerClient))); | |
| 2683 InitializeScheduler(); | |
| 2684 | |
| 2685 // Only load low priority resources if there's a body. | |
| 2686 scheduler()->OnWillInsertBody(kChildId, kRouteId); | |
| 2687 | |
| 2688 // Queue requests from different hosts until the total limit is reached. | |
| 2689 ScopedVector<TestRequest> lows_differenthosts; | |
|
mmenke
2015/08/12 17:30:09
nit: *_different_host. Goes for all of these.
Pat Meenan
2015/08/13 12:11:03
Done.
| |
| 2690 for (int i = 0; i < kMaxNumDelayableRequestsPerClient; ++i) { | |
| 2691 string url = "http://host" + base::IntToString(i) + "/low"; | |
| 2692 lows_differenthosts.push_back(NewRequest(url.c_str(), net::LOWEST)); | |
| 2693 EXPECT_TRUE(lows_differenthosts[i]->started()); | |
| 2694 } | |
| 2695 | |
| 2696 scoped_ptr<TestRequest> last_differenthost(NewRequest("http://host_new/last", | |
| 2697 net::LOWEST)); | |
| 2698 EXPECT_FALSE(last_differenthost->started()); | |
| 2699 } | |
| 2700 | |
| 2363 } // unnamed namespace | 2701 } // unnamed namespace |
| 2364 | 2702 |
| 2365 } // namespace content | 2703 } // namespace content |
| OLD | NEW |