text:
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/browser/preloading/prerender/prerender_host_registry.h"

#include "base/test/bind.h"
#include "base/test/scoped_feature_list.h"
#include "content/browser/preloading/prerender/prerender_host.h"
#include "content/browser/preloading/speculation_rules/speculation_host_impl.h"
#include "content/browser/renderer_host/render_frame_host_impl.h"
#include "content/browser/site_instance_impl.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/test/prerender_test_util.h"
#include "content/public/test/test_browser_context.h"
#include "content/test/mock_commit_deferring_condition.h"
#include "content/test/navigation_simulator_impl.h"
#include "content/test/test_render_view_host.h"
#include "content/test/test_web_contents.h"
#include "net/base/load_flags.h"
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/mojom/loader/mixed_content.mojom.h"
#include "third_party/blink/public/mojom/speculation_rules/speculation_rules.mojom.h"

namespace content {
namespace {

blink::mojom::SpeculationCandidatePtr CreatePrerenderCandidate(
    const GURL& url) {
  auto candidate = blink::mojom::SpeculationCandidate::New();
  candidate->action = blink::mojom::SpeculationAction::kPrerender;
  candidate->url = url;
  candidate->referrer = blink::mojom::Referrer::New();
  return candidate;
}

void SendCandidates(const std::vector<GURL>& urls,
                    mojo::Remote<blink::mojom::SpeculationHost>& remote) {
  std::vector<blink::mojom::SpeculationCandidatePtr> candidates;
  candidates.resize(urls.size());
  base::ranges::transform(urls, candidates.begin(), &CreatePrerenderCandidate);
  remote->UpdateSpeculationCandidates(std::move(candidates));
  remote.FlushForTesting();
}

void SendCandidate(const GURL& url,
                   mojo::Remote<blink::mojom::SpeculationHost>& remote) {
  SendCandidates({url}, remote);
}

PrerenderAttributes GeneratePrerenderAttributes(
    const GURL& url,
    PrerenderTriggerType trigger_type,
    const std::string& embedder_histogram_suffix,
    RenderFrameHostImpl* rfh) {
  if (trigger_type == PrerenderTriggerType::kSpeculationRule) {
    return PrerenderAttributes(
        url, trigger_type, embedder_histogram_suffix, Referrer(),
        rfh->GetLastCommittedOrigin(), rfh->GetLastCommittedURL(),
        rfh->GetProcess()->GetID(), rfh->GetFrameToken(),
        rfh->GetFrameTreeNodeId(), rfh->GetPageUkmSourceId(),
        ui::PAGE_TRANSITION_LINK,
        /*url_match_predicate=*/absl::nullopt);
  } else {
    // TODO(https://crbug.com/1325211): remove initiator_origin and
    // initiator_frame_token after fixing prerendering activation for
    // embedder-triggered prerendering in unittests.
    return PrerenderAttributes(
        url, trigger_type, embedder_histogram_suffix, Referrer(),
        /*initiator_origin=*/rfh->GetLastCommittedOrigin(),
        rfh->GetLastCommittedURL(),
        /*initiator_process_id=*/ChildProcessHost::kInvalidUniqueID,
        /*initiator_frame_token=*/rfh->GetFrameToken(),
        /*initiator_frame_tree_node_id=*/RenderFrameHost::kNoFrameTreeNodeId,
        /*initiator_ukm_id=*/ukm::kInvalidSourceId, ui::PAGE_TRANSITION_LINK,
        /*url_match_predicate=*/absl::nullopt);
  }
}

// This definition is needed because this constant is odr-used in gtest macros.
// https://en.cppreference.com/w/cpp/language/static#Constant_static_members
const int kNoFrameTreeNodeId = RenderFrameHost::kNoFrameTreeNodeId;

std::unique_ptr<NavigationSimulatorImpl> CreateActivation(
    const GURL& prerendering_url,
    WebContentsImpl& web_contents) {
  std::unique_ptr<NavigationSimulatorImpl> navigation =
      NavigationSimulatorImpl::CreateRendererInitiated(
          prerendering_url, web_contents.GetPrimaryMainFrame());
  navigation->SetReferrer(blink::mojom::Referrer::New(
      web_contents.GetPrimaryMainFrame()->GetLastCommittedURL(),
      network::mojom::ReferrerPolicy::kStrictOriginWhenCrossOrigin));
  return navigation;
}

// Finish a prerendering navigation that was already started with
// CreateAndStartHost().
void CommitPrerenderNavigation(PrerenderHost& host) {
  // Normally we could use EmbeddedTestServer to provide a response, but these
  // tests use RenderViewHostImplTestHarness so the load goes through a
  // TestNavigationURLLoader which we don't have access to in order to
  // complete. Use NavigationSimulator to finish the navigation.
  FrameTreeNode* ftn = FrameTreeNode::From(host.GetPrerenderedMainFrameHost());
  std::unique_ptr<NavigationSimulator> sim =
      NavigationSimulatorImpl::CreateFromPendingInFrame(ftn);
  sim->Commit();
  EXPECT_TRUE(host.is_ready_for_activation());
}

class PrerenderWebContentsDelegate : public WebContentsDelegate {
 public:
  PrerenderWebContentsDelegate() = default;

  bool IsPrerender2Supported(WebContents& web_contents) override {
    return true;
  }
};

class PrerenderHostRegistryTest : public RenderViewHostImplTestHarness {
 public:
  PrerenderHostRegistryTest() {
    scoped_feature_list_.InitWithFeatures(
        {blink::features::kPrerender2},
        // Disable the memory requirement of Prerender2 so the test can run on
        // any bot.
        {blink::features::kPrerender2MemoryControls});
  }
  ~PrerenderHostRegistryTest() override = default;

  std::unique_ptr<TestWebContents> CreateWebContents(const GURL& url) {
    std::unique_ptr<TestWebContents> web_contents(TestWebContents::Create(
        GetBrowserContext(), SiteInstanceImpl::Create(GetBrowserContext())));
    web_contents->SetDelegate(&web_contents_delegate_);
    web_contents->NavigateAndCommit(url);
    return web_contents;
  }

  RenderFrameHostImpl* NavigatePrimaryPage(TestWebContents* web_contents,
                                           const GURL& dest_url) {
    std::unique_ptr<NavigationSimulatorImpl> navigation =
        NavigationSimulatorImpl::CreateRendererInitiated(
            dest_url, web_contents->GetPrimaryMainFrame());
    navigation->SetTransition(ui::PAGE_TRANSITION_LINK);
    navigation->Start();
    navigation->Commit();
    RenderFrameHostImpl* render_frame_host =
        web_contents->GetPrimaryMainFrame();
    EXPECT_EQ(render_frame_host->GetLastCommittedURL(), dest_url);
    return render_frame_host;
  }

  // Helper method to test the navigation param matching logic which allows a
  // prerender host to be used in a potential activation navigation only if its
  // params match the potential activation navigation params. Use setup_callback
  // to set the parameters. Returns true if the host was selected as a
  // potential candidate for activation, and false otherwise.
  [[nodiscard]] bool CheckIsActivatedForParams(
      base::OnceCallback<void(NavigationSimulatorImpl*)> setup_callback) {
    const GURL kOriginalUrl("https://example.com/");

    std::unique_ptr<TestWebContents> web_contents =
        CreateWebContents(kOriginalUrl);
    RenderFrameHostImpl* render_frame_host =
        web_contents->GetPrimaryMainFrame();

    const GURL kPrerenderingUrl("https://example.com/next");

    PrerenderHostRegistry* registry = web_contents->GetPrerenderHostRegistry();
    registry->CreateAndStartHost(
        GeneratePrerenderAttributes(kPrerenderingUrl,
                                    PrerenderTriggerType::kSpeculationRule, "",
                                    render_frame_host),
        *web_contents);
    PrerenderHost* prerender_host =
        registry->FindHostByUrlForTesting(kPrerenderingUrl);
    CommitPrerenderNavigation(*prerender_host);

    std::unique_ptr<NavigationSimulatorImpl> navigation =
        NavigationSimulatorImpl::CreateRendererInitiated(kPrerenderingUrl,
                                                         render_frame_host);
    // Set a default referrer policy that matches the initial prerender
    // navigation.
    // TODO(falken): Fix NavigationSimulatorImpl to do this itself.
    navigation->SetReferrer(blink::mojom::Referrer::New(
        web_contents->GetPrimaryMainFrame()->GetLastCommittedURL(),
        network::mojom::ReferrerPolicy::kStrictOriginWhenCrossOrigin));

    // Change a parameter to differentiate the activation request from the
    // prerendering request.
    std::move(setup_callback).Run(navigation.get());
    navigation->Start();
    NavigationRequest* navigation_request = navigation->GetNavigationHandle();
    // Use is_potentially_prerendered_page_activation_for_testing() instead of
    // IsPrerenderedPageActivation() because the NavigationSimulator does not
    // proceed past CommitDeferringConditions on potential activations,
    // so IsPrerenderedPageActivation() will fail with a CHECK because
    // prerender_frame_tree_node_id_ is not populated.
    // TODO(https://crbug.com/1239220): Fix NavigationSimulator to wait for
    // commit deferring conditions as it does throttles.
    return navigation_request
        ->is_potentially_prerendered_page_activation_for_testing();
  }

  // Helper method to perform a prerender activation that includes specialized
  // handling or setup on the initial prerender navigation via the
  // setup_callback parameter.
  void SetupPrerenderAndCommit(
      base::OnceCallback<void(NavigationSimulatorImpl*)> setup_callback) {
    const GURL kOriginalUrl("https://example.com/");

    TestWebContents* wc = static_cast<TestWebContents*>(web_contents());
    web_contents()->SetDelegate(&web_contents_delegate_);
    wc->NavigateAndCommit(kOriginalUrl);
    RenderFrameHostImpl* render_frame_host = wc->GetPrimaryMainFrame();
    ASSERT_TRUE(render_frame_host);

    const GURL kPrerenderingUrl("https://example.com/next");

    PrerenderHostRegistry* registry = wc->GetPrerenderHostRegistry();
    const int prerender_frame_tree_node_id = registry->CreateAndStartHost(
        GeneratePrerenderAttributes(kPrerenderingUrl,
                                    PrerenderTriggerType::kSpeculationRule, "",
                                    render_frame_host),
        *wc);
    ASSERT_NE(prerender_frame_tree_node_id, kNoFrameTreeNodeId);
    PrerenderHost* prerender_host =
        registry->FindNonReservedHostById(prerender_frame_tree_node_id);

    // Complete the initial prerender navigation.
    FrameTreeNode* ftn =
        FrameTreeNode::From(prerender_host->GetPrerenderedMainFrameHost());
    std::unique_ptr<NavigationSimulatorImpl> sim =
        NavigationSimulatorImpl::CreateFromPendingInFrame(ftn);
    std::move(setup_callback).Run(sim.get());
    sim->Commit();
    EXPECT_TRUE(prerender_host->is_ready_for_activation());

    // Activate the prerendered page.
    wc->ActivatePrerenderedPage(kPrerenderingUrl);
  }

  void ExpectUniqueSampleOfFinalStatus(PrerenderHost::FinalStatus status) {
    histogram_tester_.ExpectUniqueSample(
        "Prerender.Experimental.PrerenderHostFinalStatus.SpeculationRule",
        status, 1);
  }

  void ExpectBucketCountOfFinalStatus(PrerenderHost::FinalStatus status) {
    histogram_tester_.ExpectBucketCount(
        "Prerender.Experimental.PrerenderHostFinalStatus.SpeculationRule",
        status, 1);
  }

  void ExpectUniqueSampleOfActivationNavigationParamsMatch(
      PrerenderHost::ActivationNavigationParamsMatch result) {
    histogram_tester_.ExpectUniqueSample(
        "Prerender.Experimental.ActivationNavigationParamsMatch."
        "SpeculationRule",
        result, 1);
  }

  void ExpectBucketCountOfActivationNavigationParamsMatch(
      PrerenderHost::ActivationNavigationParamsMatch result,
      base::HistogramBase::Count count) {
    histogram_tester_.ExpectBucketCount(
        "Prerender.Experimental.ActivationNavigationParamsMatch."
        "SpeculationRule",
        result, count);
  }

 private:
  base::test::ScopedFeatureList scoped_feature_list_;
  PrerenderWebContentsDelegate web_contents_delegate_;
  base::HistogramTester histogram_tester_;
};

TEST_F(PrerenderHostRegistryTest, CreateAndStartHost_SpeculationRule) {
  base::HistogramTester histogram_tester;

  const GURL kOriginalUrl("https://example.com/");
  std::unique_ptr<TestWebContents> web_contents =
      CreateWebContents(kOriginalUrl);
  RenderFrameHostImpl* render_frame_host = web_contents->GetPrimaryMainFrame();
  ASSERT_TRUE(render_frame_host);

  const GURL kPrerenderingUrl("https://example.com/next");

  PrerenderHostRegistry* registry = web_contents->GetPrerenderHostRegistry();
  const int prerender_frame_tree_node_id = registry->CreateAndStartHost(
      GeneratePrerenderAttributes(kPrerenderingUrl,
                                  PrerenderTriggerType::kSpeculationRule, "",
                                  render_frame_host),
      *web_contents);
  ASSERT_NE(prerender_frame_tree_node_id, kNoFrameTreeNodeId);
  PrerenderHost* prerender_host =
      registry->FindHostByUrlForTesting(kPrerenderingUrl);
  CommitPrerenderNavigation(*prerender_host);

  web_contents->ActivatePrerenderedPage(kPrerenderingUrl);

  // "Navigation.TimeToActivatePrerender.SpeculationRule" histogram should be
  // recorded on every prerender activation.
  histogram_tester.ExpectTotalCount(
      "Navigation.TimeToActivatePrerender.SpeculationRule", 1u);
}

TEST_F(PrerenderHostRegistryTest, CreateAndStartHost_Embedder_DirectURLInput) {
  base::HistogramTester histogram_tester;

  const GURL kOriginalUrl("https://example.com/");
  std::unique_ptr<TestWebContents> web_contents =
      CreateWebContents(kOriginalUrl);
  RenderFrameHostImpl* render_frame_host = web_contents->GetPrimaryMainFrame();
  ASSERT_TRUE(render_frame_host);

  const GURL kPrerenderingUrl("https://example.com/next");

  PrerenderHostRegistry* registry = web_contents->GetPrerenderHostRegistry();
  const int prerender_frame_tree_node_id = registry->CreateAndStartHost(
      GeneratePrerenderAttributes(kPrerenderingUrl,
                                  PrerenderTriggerType::kEmbedder,
                                  "DirectURLInput", render_frame_host),
      *web_contents);
  ASSERT_NE(prerender_frame_tree_node_id, kNoFrameTreeNodeId);
  PrerenderHost* prerender_host =
      registry->FindHostByUrlForTesting(kPrerenderingUrl);
  CommitPrerenderNavigation(*prerender_host);

  web_contents->ActivatePrerenderedPage(kPrerenderingUrl);

  // "Navigation.TimeToActivatePrerender.Embedder_DirectURLInput" histogram
  // should be recorded on every prerender activation.
  histogram_tester.ExpectTotalCount(
      "Navigation.TimeToActivatePrerender.Embedder_DirectURLInput", 1u);
}

TEST_F(PrerenderHostRegistryTest, CreateAndStartHostForSameURL) {
  const GURL kOriginalUrl("https://example.com/");
  std::unique_ptr<TestWebContents> web_contents =
      CreateWebContents(kOriginalUrl);
  RenderFrameHostImpl* render_frame_host = web_contents->GetPrimaryMainFrame();
  ASSERT_TRUE(render_frame_host);

  const GURL kPrerenderingUrl("https://example.com/next");

  PrerenderHostRegistry* registry = web_contents->GetPrerenderHostRegistry();
  const int frame_tree_node_id1 = registry->CreateAndStartHost(
      GeneratePrerenderAttributes(kPrerenderingUrl,
                                  PrerenderTriggerType::kSpeculationRule, "",
                                  render_frame_host),
      *web_contents);
  EXPECT_NE(frame_tree_node_id1, RenderFrameHost::kNoFrameTreeNodeId);
  PrerenderHost* prerender_host1 =
      registry->FindHostByUrlForTesting(kPrerenderingUrl);

  // Start the prerender host for the same URL. This second host should be
  // ignored, and the first host should still be findable.
  const int frame_tree_node_id2 = registry->CreateAndStartHost(
      GeneratePrerenderAttributes(kPrerenderingUrl,
                                  PrerenderTriggerType::kSpeculationRule, "",
                                  render_frame_host),
      *web_contents);
  EXPECT_EQ(frame_tree_node_id2, RenderFrameHost::kNoFrameTreeNodeId);
  EXPECT_EQ(registry->FindHostByUrlForTesting(kPrerenderingUrl),
            prerender_host1);
  CommitPrerenderNavigation(*prerender_host1);

  web_contents->ActivatePrerenderedPage(kPrerenderingUrl);
}

// Tests that PrerenderHostRegistry limits the number of started prerenders
// to 1.
TEST_F(PrerenderHostRegistryTest, NumberLimit_Activation) {
  const GURL kOriginalUrl("https://example.com/");
  std::unique_ptr<TestWebContents> web_contents =
      CreateWebContents(kOriginalUrl);
  RenderFrameHostImpl* render_frame_host = web_contents->GetPrimaryMainFrame();
  ASSERT_TRUE(render_frame_host);

  // After the first prerender page was activated, PrerenderHostRegistry can
  // start prerendering a new one.
  const GURL kPrerenderingUrl1("https://example.com/next1");
  const GURL kPrerenderingUrl2("https://example.com/next2");

  PrerenderHostRegistry* registry = web_contents->GetPrerenderHostRegistry();
  int frame_tree_node_id1 = registry->CreateAndStartHost(
      GeneratePrerenderAttributes(kPrerenderingUrl1,
                                  PrerenderTriggerType::kSpeculationRule, "",
                                  render_frame_host),
      *web_contents);
  int frame_tree_node_id2 = registry->CreateAndStartHost(
      GeneratePrerenderAttributes(kPrerenderingUrl2,
                                  PrerenderTriggerType::kSpeculationRule, "",
                                  render_frame_host),
      *web_contents);
  ExpectUniqueSampleOfFinalStatus(
      PrerenderHost::FinalStatus::kMaxNumOfRunningPrerendersExceeded);

  // PrerenderHostRegistry should only start prerendering for kPrerenderingUrl1.
  EXPECT_NE(frame_tree_node_id1, kNoFrameTreeNodeId);
  EXPECT_EQ(frame_tree_node_id2, kNoFrameTreeNodeId);

  // Activate the first prerender.
  PrerenderHost* prerender_host1 =
      registry->FindHostByUrlForTesting(kPrerenderingUrl1);
  CommitPrerenderNavigation(*prerender_host1);
  web_contents->ActivatePrerenderedPage(kPrerenderingUrl1);

  // After the first prerender page was activated, PrerenderHostRegistry can
  // start prerendering a new one.
  frame_tree_node_id2 = registry->CreateAndStartHost(
      GeneratePrerenderAttributes(kPrerenderingUrl2,
                                  PrerenderTriggerType::kSpeculationRule, "",
                                  render_frame_host),
      *web_contents);
  EXPECT_NE(frame_tree_node_id2, kNoFrameTreeNodeId);
  ExpectBucketCountOfFinalStatus(
      PrerenderHost::FinalStatus::kMaxNumOfRunningPrerendersExceeded);
}

// Tests that PrerenderHostRegistry limits the number of started prerenders
// to 1, and new candidates can be processed after the initiator page navigates
// to a new same-origin page.
TEST_F(PrerenderHostRegistryTest, NumberLimit_SameOriginNavigateAway) {
  const GURL kOriginalUrl("https://example.com/");
  std::unique_ptr<TestWebContents> web_contents =
      CreateWebContents(kOriginalUrl);
  RenderFrameHostImpl* render_frame_host = web_contents->GetPrimaryMainFrame();
  ASSERT_TRUE(render_frame_host);

  mojo::Remote<blink::mojom::SpeculationHost> remote1;
  SpeculationHostImpl::Bind(render_frame_host,
                            remote1.BindNewPipeAndPassReceiver());
  ASSERT_TRUE(remote1.is_connected());
  const GURL kPrerenderingUrl1("https://example.com/next1");
  const GURL kPrerenderingUrl2("https://example.com/next2");
  SendCandidates({kPrerenderingUrl1, kPrerenderingUrl2}, remote1);
  PrerenderHostRegistry* registry = web_contents->GetPrerenderHostRegistry();

  // PrerenderHostRegistry should only start prerendering for kPrerenderingUrl1.
  ASSERT_NE(registry->FindHostByUrlForTesting(kPrerenderingUrl1), nullptr);
  ASSERT_EQ(registry->FindHostByUrlForTesting(kPrerenderingUrl2), nullptr);
  ExpectUniqueSampleOfFinalStatus(
      PrerenderHost::FinalStatus::kMaxNumOfRunningPrerendersExceeded);

  // The initiator document navigates away.
  render_frame_host = NavigatePrimaryPage(
      web_contents.get(), GURL("https://example.com/elsewhere"));
  EXPECT_EQ(registry->FindHostByUrlForTesting(kPrerenderingUrl1), nullptr);

  // After the initiator page navigates away, the started prerendering should be
  // cancelled, and PrerenderHostRegistry can start prerendering a new one.
  mojo::Remote<blink::mojom::SpeculationHost> remote2;
  SpeculationHostImpl::Bind(render_frame_host,
                            remote2.BindNewPipeAndPassReceiver());
  SendCandidate(kPrerenderingUrl2, remote2);

  EXPECT_NE(registry->FindHostByUrlForTesting(kPrerenderingUrl2), nullptr);
  ExpectBucketCountOfFinalStatus(
      PrerenderHost::FinalStatus::kMaxNumOfRunningPrerendersExceeded);
}

// Tests that PrerenderHostRegistry limits the number of started prerenders
// to 1, and new candidates can be processed after the initiator page navigates
// to a new cross-origin page.
TEST_F(PrerenderHostRegistryTest, NumberLimit_CrossOriginNavigateAway) {
  const GURL kOriginalUrl("https://example.com/");

  std::unique_ptr<TestWebContents> web_contents =
      CreateWebContents(kOriginalUrl);
  RenderFrameHostImpl* render_frame_host = web_contents->GetPrimaryMainFrame();
  ASSERT_TRUE(render_frame_host);

  mojo::Remote<blink::mojom::SpeculationHost> remote1;
  SpeculationHostImpl::Bind(render_frame_host,
                            remote1.BindNewPipeAndPassReceiver());
  ASSERT_TRUE(remote1.is_connected());
  const GURL kPrerenderingUrl1("https://example.com/next1");
  const GURL kPrerenderingUrl2("https://example.com/next2");
  SendCandidates({kPrerenderingUrl1, kPrerenderingUrl2}, remote1);
  PrerenderHostRegistry* registry = web_contents->GetPrerenderHostRegistry();

  // PrerenderHostRegistry should only start prerendering for kPrerenderingUrl1.
  ASSERT_NE(registry->FindHostByUrlForTesting(kPrerenderingUrl1), nullptr);
  ASSERT_EQ(registry->FindHostByUrlForTesting(kPrerenderingUrl2), nullptr);
  ExpectUniqueSampleOfFinalStatus(
      PrerenderHost::FinalStatus::kMaxNumOfRunningPrerendersExceeded);

  // The initiator document navigates away to a cross-origin page.
  render_frame_host =
      NavigatePrimaryPage(web_contents.get(), GURL("https://example.org/"));
  EXPECT_EQ(registry->FindHostByUrlForTesting(kPrerenderingUrl1), nullptr);

  // After the initiator page navigates away, the started prerendering should be
  // cancelled, and PrerenderHostRegistry can start prerendering a new one.
  mojo::Remote<blink::mojom::SpeculationHost> remote2;
  SpeculationHostImpl::Bind(render_frame_host,
                            remote2.BindNewPipeAndPassReceiver());
  const GURL kPrerenderingUrl3("https://example.org/next1");
  SendCandidate(kPrerenderingUrl3, remote2);
  EXPECT_NE(registry->FindHostByUrlForTesting(kPrerenderingUrl3), nullptr);
  ExpectBucketCountOfFinalStatus(
      PrerenderHost::FinalStatus::kMaxNumOfRunningPrerendersExceeded);
}

TEST_F(PrerenderHostRegistryTest,
       ReserveHostToActivateBeforeReadyForActivation) {
  const GURL kOriginalUrl("https://example.com/");
  std::unique_ptr<TestWebContents> web_contents =
      CreateWebContents(kOriginalUrl);
  RenderFrameHostImpl* render_frame_host = web_contents->GetPrimaryMainFrame();
  ASSERT_TRUE(render_frame_host);

  const GURL kPrerenderingUrl("https://example.com/next");

  PrerenderHostRegistry* registry = web_contents->GetPrerenderHostRegistry();
  const int prerender_frame_tree_node_id = registry->CreateAndStartHost(
      GeneratePrerenderAttributes(kPrerenderingUrl,
                                  PrerenderTriggerType::kSpeculationRule, "",
                                  render_frame_host),
      *web_contents);
  ASSERT_NE(prerender_frame_tree_node_id, kNoFrameTreeNodeId);
  PrerenderHost* prerender_host =
      registry->FindHostByUrlForTesting(kPrerenderingUrl);
  FrameTreeNode* ftn =
      FrameTreeNode::From(prerender_host->GetPrerenderedMainFrameHost());
  std::unique_ptr<NavigationSimulatorImpl> sim =
      NavigationSimulatorImpl::CreateFromPendingInFrame(ftn);
  // Ensure that navigation in prerendering frame tree does not commit and
  // PrerenderHost doesn't become ready for activation.
  sim->SetAutoAdvance(false);

  EXPECT_FALSE(prerender_host->is_ready_for_activation());

  test::PrerenderHostObserver prerender_host_observer(*web_contents,
                                                      kPrerenderingUrl);

  // Start activation.
  std::unique_ptr<NavigationSimulatorImpl> navigation =
      CreateActivation(kPrerenderingUrl, *web_contents);
  navigation->Start();

  // Wait until PrerenderCommitDeferringCondition runs.
  // TODO(nhiroki): Avoid using base::RunUntilIdle() and instead use some
  // explicit signal of the running condition.
  base::RunLoop().RunUntilIdle();

  // The activation should be deferred by PrerenderCommitDeferringCondition
  // until the main frame navigation in the prerendering frame tree finishes.
  NavigationRequest* navigation_request = navigation->GetNavigationHandle();
  EXPECT_TRUE(
      navigation_request->IsCommitDeferringConditionDeferredForTesting());
  EXPECT_FALSE(prerender_host_observer.was_activated());
  EXPECT_EQ(web_contents->GetPrimaryMainFrame()->GetLastCommittedURL(),
            kOriginalUrl);

  // Finish the main frame navigation.
  sim->Commit();

  // Finish the activation.
  prerender_host_observer.WaitForDestroyed();
  EXPECT_TRUE(prerender_host_observer.was_activated());
  EXPECT_EQ(registry->FindHostByUrlForTesting(kPrerenderingUrl), nullptr);
  EXPECT_EQ(web_contents->GetPrimaryMainFrame()->GetLastCommittedURL(),
            kPrerenderingUrl);
}

TEST_F(PrerenderHostRegistryTest, CancelHost) {
  std::unique_ptr<TestWebContents> web_contents =
      CreateWebContents(GURL("https://example.com/"));
  RenderFrameHostImpl* render_frame_host = web_contents->GetPrimaryMainFrame();
  ASSERT_TRUE(render_frame_host);

  const GURL kPrerenderingUrl("https://example.com/next");

  PrerenderHostRegistry* registry = web_contents->GetPrerenderHostRegistry();

  const int prerender_frame_tree_node_id = registry->CreateAndStartHost(
      GeneratePrerenderAttributes(kPrerenderingUrl,
                                  PrerenderTriggerType::kSpeculationRule, "",
                                  render_frame_host),
      *web_contents);
  EXPECT_NE(registry->FindHostByUrlForTesting(kPrerenderingUrl), nullptr);

  registry->CancelHost(prerender_frame_tree_node_id,
                       PrerenderHost::FinalStatus::kDestroyed);
  EXPECT_EQ(registry->FindHostByUrlForTesting(kPrerenderingUrl), nullptr);
}

// Test cancelling a prerender while a CommitDeferringCondition is running.
// This activation should fall back to a regular navigation.
TEST_F(PrerenderHostRegistryTest,
       CancelHostWhileCommitDeferringConditionIsRunning) {
  const GURL kOriginalUrl("https://example.com/");
  std::unique_ptr<TestWebContents> web_contents =
      CreateWebContents(kOriginalUrl);
  RenderFrameHostImpl* render_frame_host = web_contents->GetPrimaryMainFrame();
  ASSERT_TRUE(render_frame_host);

  // Start prerendering.
  const GURL kPrerenderingUrl("https://example.com/next");

  PrerenderHostRegistry* registry = web_contents->GetPrerenderHostRegistry();

  const int prerender_frame_tree_node_id = registry->CreateAndStartHost(
      GeneratePrerenderAttributes(kPrerenderingUrl,
                                  PrerenderTriggerType::kSpeculationRule, "",
                                  render_frame_host),
      *web_contents);
  ASSERT_NE(prerender_frame_tree_node_id, kNoFrameTreeNodeId);
  PrerenderHost* prerender_host =
      registry->FindHostByUrlForTesting(kPrerenderingUrl);
  CommitPrerenderNavigation(*prerender_host);

  test::PrerenderHostObserver prerender_host_observer(*web_contents,
                                                      kPrerenderingUrl);

  // Now navigate the primary page to the prerendered URL so that we activate
  // the prerender. Use a CommitDeferringCondition to pause activation
  // before it completes.
  std::unique_ptr<NavigationSimulatorImpl> navigation;

  {
    MockCommitDeferringConditionInstaller installer(
        kPrerenderingUrl,
        /*is_ready_to_commit=*/false);
    // Start trying to activate the prerendered page.
    navigation = CreateActivation(kPrerenderingUrl, *web_contents);
    navigation->Start();

    // Wait for the condition to pause the activation.
    installer.WaitUntilInstalled();
    installer.condition().WaitUntilInvoked();

    // The request should be deferred by the condition.
    NavigationRequest* navigation_request =
        static_cast<NavigationRequest*>(navigation->GetNavigationHandle());
    EXPECT_TRUE(
        navigation_request->IsCommitDeferringConditionDeferredForTesting());

    // The primary page should still be the original page.
    EXPECT_EQ(web_contents->GetLastCommittedURL(), kOriginalUrl);

    // Cancel the prerender while the CommitDeferringCondition is running.
    registry->CancelHost(prerender_frame_tree_node_id,
                         PrerenderHost::FinalStatus::kDestroyed);
    prerender_host_observer.WaitForDestroyed();
    EXPECT_FALSE(prerender_host_observer.was_activated());
    EXPECT_EQ(registry->FindHostByUrlForTesting(kPrerenderingUrl), nullptr);

    // Resume the activation. This should fall back to a regular navigation.
    installer.condition().CallResumeClosure();
  }

  navigation->Commit();
  EXPECT_EQ(web_contents->GetPrimaryMainFrame()->GetLastCommittedURL(),
            kPrerenderingUrl);
}

// Test cancelling a prerender and then starting a new prerender for the same
// URL while a CommitDeferringCondition is running. This activation should not
// reserve the second prerender and should fall back to a regular navigation.
TEST_F(PrerenderHostRegistryTest,
       CancelAndStartHostWhileCommitDeferringConditionIsRunning) {
  const GURL kOriginalUrl("https://example.com/");
  std::unique_ptr<TestWebContents> web_contents =
      CreateWebContents(kOriginalUrl);
  RenderFrameHostImpl* render_frame_host = web_contents->GetPrimaryMainFrame();
  ASSERT_TRUE(render_frame_host);

  const GURL kPrerenderingUrl("https://example.com/next");

  PrerenderHostRegistry* registry = web_contents->GetPrerenderHostRegistry();

  const int prerender_frame_tree_node_id = registry->CreateAndStartHost(
      GeneratePrerenderAttributes(kPrerenderingUrl,
                                  PrerenderTriggerType::kSpeculationRule, "",
                                  render_frame_host),
      *web_contents);
  ASSERT_NE(prerender_frame_tree_node_id, kNoFrameTreeNodeId);
  PrerenderHost* prerender_host =
      registry->FindHostByUrlForTesting(kPrerenderingUrl);
  CommitPrerenderNavigation(*prerender_host);

  test::PrerenderHostObserver prerender_host_observer(*web_contents,
                                                      kPrerenderingUrl);

  // Now navigate the primary page to the prerendered URL so that we activate
  // the prerender. Use a CommitDeferringCondition to pause activation
  // before it completes.
  std::unique_ptr<NavigationSimulatorImpl> navigation;
  base::OnceClosure resume_navigation;

  {
    MockCommitDeferringConditionInstaller installer(
        kPrerenderingUrl,
        /*is_ready_to_commit=*/false);
    // Start trying to activate the prerendered page.
    navigation = CreateActivation(kPrerenderingUrl, *web_contents);
    navigation->Start();

    // Wait for the condition to pause the activation.
    installer.WaitUntilInstalled();
    installer.condition().WaitUntilInvoked();
    resume_navigation = installer.condition().TakeResumeClosure();

    // The request should be deferred by the condition.
    NavigationRequest* navigation_request =
        static_cast<NavigationRequest*>(navigation->GetNavigationHandle());
    EXPECT_TRUE(
        navigation_request->IsCommitDeferringConditionDeferredForTesting());

    // The primary page should still be the original page.
    EXPECT_EQ(web_contents->GetLastCommittedURL(), kOriginalUrl);

    // Cancel the prerender while the CommitDeferringCondition is running.
    registry->CancelHost(prerender_frame_tree_node_id,
                         PrerenderHost::FinalStatus::kDestroyed);
    prerender_host_observer.WaitForDestroyed();
    EXPECT_FALSE(prerender_host_observer.was_activated());
    EXPECT_EQ(registry->FindHostByUrlForTesting(kPrerenderingUrl), nullptr);
  }

  {
    // Start the second prerender for the same URL.
    const int prerender_frame_tree_node_id2 = registry->CreateAndStartHost(
        GeneratePrerenderAttributes(kPrerenderingUrl,
                                    PrerenderTriggerType::kSpeculationRule, "",
                                    render_frame_host),
        *web_contents);
    ASSERT_NE(prerender_frame_tree_node_id2, kNoFrameTreeNodeId);
    PrerenderHost* prerender_host2 =
        registry->FindHostByUrlForTesting(kPrerenderingUrl);
    CommitPrerenderNavigation(*prerender_host2);

    EXPECT_NE(prerender_frame_tree_node_id, prerender_frame_tree_node_id2);
  }

  // Resume the initial activation. This should not reserve the second
  // prerender and should fall back to a regular navigation.
  std::move(resume_navigation).Run();
  navigation->Commit();
  EXPECT_EQ(web_contents->GetPrimaryMainFrame()->GetLastCommittedURL(),
            kPrerenderingUrl);

  // The second prerender should still exist.
  EXPECT_NE(registry->FindHostByUrlForTesting(kPrerenderingUrl), nullptr);
}

TEST_F(PrerenderHostRegistryTest,
       DontStartPrerenderWhenTriggerIsAlreadyHidden) {
  std::unique_ptr<TestWebContents> web_contents =
      CreateWebContents(GURL("https://example.com/"));
  // The visibility state to be HIDDEN will cause prerendering not started.
  web_contents->WasHidden();

  const GURL kPrerenderingUrl = GURL("https://example.com/empty.html");
  RenderFrameHostImpl* initiator_rfh = web_contents->GetPrimaryMainFrame();
  PrerenderHostRegistry* registry = web_contents->GetPrerenderHostRegistry();
  const int prerender_frame_tree_node_id = registry->CreateAndStartHost(
      GeneratePrerenderAttributes(kPrerenderingUrl,
                                  PrerenderTriggerType::kSpeculationRule, "",
                                  initiator_rfh),
      *web_contents);
  EXPECT_EQ(prerender_frame_tree_node_id, RenderFrameHost::kNoFrameTreeNodeId);
  PrerenderHost* prerender_host =
      registry->FindNonReservedHostById(prerender_frame_tree_node_id);
  EXPECT_EQ(prerender_host, nullptr);
  ExpectUniqueSampleOfFinalStatus(
      PrerenderHost::FinalStatus::kTriggerBackgrounded);
}

// -------------------------------------------------
// Activation navigation parameter matching unit tests.
// These tests change a parameter to differentiate the activation request from
// the prerendering request.

// A positive test to show that if the navigation params are equal then the
// prerender host is selected for activation.
TEST_F(PrerenderHostRegistryTest, SameInitialAndActivationParams) {
  EXPECT_TRUE(CheckIsActivatedForParams(
      base::BindLambdaForTesting([](NavigationSimulatorImpl* navigation) {
        // Do not change any params, so activation happens.
      })));
  ExpectUniqueSampleOfActivationNavigationParamsMatch(
      PrerenderHost::ActivationNavigationParamsMatch::kOk);
}

TEST_F(PrerenderHostRegistryTest,
       CompareInitialAndActivationBeginParams_InitiatorFrameToken) {
  EXPECT_FALSE(CheckIsActivatedForParams(
      base::BindLambdaForTesting([](NavigationSimulatorImpl* navigation) {
        const GURL kOriginalUrl("https://example.com/");
        navigation->SetInitiatorFrame(nullptr);
        navigation->set_initiator_origin(url::Origin::Create(kOriginalUrl));
      })));
  ExpectUniqueSampleOfActivationNavigationParamsMatch(
      PrerenderHost::ActivationNavigationParamsMatch::kInitiatorFrameToken);
}

TEST_F(PrerenderHostRegistryTest,
       CompareInitialAndActivationBeginParams_Headers) {
  EXPECT_FALSE(CheckIsActivatedForParams(
      base::BindLambdaForTesting([](NavigationSimulatorImpl* navigation) {
        navigation->set_request_headers("User-Agent: Test");
      })));
  ExpectUniqueSampleOfActivationNavigationParamsMatch(
      PrerenderHost::ActivationNavigationParamsMatch::kHttpRequestHeader);
}

// Tests that the Purpose header is ignored when comparing request headers.
TEST_F(PrerenderHostRegistryTest, PurposeHeaderIsIgnoredForParamMatching) {
  EXPECT_TRUE(CheckIsActivatedForParams(
      base::BindLambdaForTesting([](NavigationSimulatorImpl* navigation) {
        navigation->set_request_headers("Purpose: Test");
      })));
  ExpectUniqueSampleOfActivationNavigationParamsMatch(
      PrerenderHost::ActivationNavigationParamsMatch::kOk);
}

TEST_F(PrerenderHostRegistryTest,
       CompareInitialAndActivationBeginParams_LoadFlags) {
  EXPECT_FALSE(CheckIsActivatedForParams(
      base::BindLambdaForTesting([](NavigationSimulatorImpl* navigation) {
        navigation->set_load_flags(net::LOAD_ONLY_FROM_CACHE);
      })));
  ExpectUniqueSampleOfActivationNavigationParamsMatch(
      PrerenderHost::ActivationNavigationParamsMatch::kLoadFlags);

  // If the potential activation request requires validation or bypass of the
  // browser cache, the prerendered page should not be activated.
  EXPECT_FALSE(CheckIsActivatedForParams(
      base::BindLambdaForTesting([](NavigationSimulatorImpl* navigation) {
        navigation->set_load_flags(net::LOAD_VALIDATE_CACHE);
      })));
  EXPECT_FALSE(CheckIsActivatedForParams(
      base::BindLambdaForTesting([](NavigationSimulatorImpl* navigation) {
        navigation->set_load_flags(net::LOAD_BYPASS_CACHE);
      })));
  EXPECT_FALSE(CheckIsActivatedForParams(
      base::BindLambdaForTesting([](NavigationSimulatorImpl* navigation) {
        navigation->set_load_flags(net::LOAD_DISABLE_CACHE);
      })));
  ExpectBucketCountOfActivationNavigationParamsMatch(
      PrerenderHost::ActivationNavigationParamsMatch::kCacheLoadFlags, 3);
}

TEST_F(PrerenderHostRegistryTest,
       CompareInitialAndActivationBeginParams_SkipServiceWorker) {
  EXPECT_FALSE(CheckIsActivatedForParams(
      base::BindLambdaForTesting([](NavigationSimulatorImpl* navigation) {
        navigation->set_skip_service_worker(true);
      })));
  ExpectUniqueSampleOfActivationNavigationParamsMatch(
      PrerenderHost::ActivationNavigationParamsMatch::kSkipServiceWorker);
}

TEST_F(PrerenderHostRegistryTest,
       CompareInitialAndActivationBeginParams_MixedContentContextType) {
  EXPECT_FALSE(CheckIsActivatedForParams(
      base::BindLambdaForTesting([](NavigationSimulatorImpl* navigation) {
        navigation->set_mixed_content_context_type(
            blink::mojom::MixedContentContextType::kNotMixedContent);
      })));
  ExpectUniqueSampleOfActivationNavigationParamsMatch(
      PrerenderHost::ActivationNavigationParamsMatch::kMixedContentContextType);
}

TEST_F(PrerenderHostRegistryTest,
       CompareInitialAndActivationBeginParams_IsFormSubmission) {
  EXPECT_FALSE(CheckIsActivatedForParams(
      base::BindLambdaForTesting([](NavigationSimulatorImpl* navigation) {
        navigation->SetIsFormSubmission(true);
      })));
  ExpectUniqueSampleOfActivationNavigationParamsMatch(
      PrerenderHost::ActivationNavigationParamsMatch::kIsFormSubmission);
}

TEST_F(PrerenderHostRegistryTest,
       CompareInitialAndActivationBeginParams_SearchableFormUrl) {
  EXPECT_FALSE(CheckIsActivatedForParams(
      base::BindLambdaForTesting([](NavigationSimulatorImpl* navigation) {
        const GURL kOriginalUrl("https://example.com/");
        navigation->set_searchable_form_url(kOriginalUrl);
      })));
  ExpectUniqueSampleOfActivationNavigationParamsMatch(
      PrerenderHost::ActivationNavigationParamsMatch::kSearchableFormUrl);
}

TEST_F(PrerenderHostRegistryTest,
       CompareInitialAndActivationBeginParams_SearchableFormEncoding) {
  EXPECT_FALSE(CheckIsActivatedForParams(
      base::BindLambdaForTesting([](NavigationSimulatorImpl* navigation) {
        navigation->set_searchable_form_encoding("Test encoding");
      })));
  ExpectUniqueSampleOfActivationNavigationParamsMatch(
      PrerenderHost::ActivationNavigationParamsMatch::kSearchableFormEncoding);
}

TEST_F(PrerenderHostRegistryTest,
       CompareInitialAndActivationCommonParams_InitiatorOrigin) {
  EXPECT_FALSE(CheckIsActivatedForParams(
      base::BindLambdaForTesting([](NavigationSimulatorImpl* navigation) {
        navigation->set_initiator_origin(url::Origin());
      })));
  ExpectUniqueSampleOfActivationNavigationParamsMatch(
      PrerenderHost::ActivationNavigationParamsMatch::kInitiatorOrigin);
}

TEST_F(PrerenderHostRegistryTest,
       CompareInitialAndActivationCommonParams_ShouldNotCheckMainWorldCSP) {
  // Initial navigation blocked by the main world CSP cancels prerendering.
  // So, it's safe to match the page for CSP bypassing requests from isolated
  // worlds (e.g., extensions).
  EXPECT_TRUE(CheckIsActivatedForParams(
      base::BindLambdaForTesting([](NavigationSimulatorImpl* navigation) {
        navigation->set_should_check_main_world_csp(
            network::mojom::CSPDisposition::DO_NOT_CHECK);
      })));
  ExpectUniqueSampleOfActivationNavigationParamsMatch(
      PrerenderHost::ActivationNavigationParamsMatch::kOk);
}

TEST_F(PrerenderHostRegistryTest,
       CompareInitialAndActivationCommonParams_Method) {
  EXPECT_FALSE(CheckIsActivatedForParams(
      base::BindLambdaForTesting([](NavigationSimulatorImpl* navigation) {
        navigation->SetMethod("POST");
      })));
  // The method parameter change is detected as a HTTP request header change.
  ExpectUniqueSampleOfActivationNavigationParamsMatch(
      PrerenderHost::ActivationNavigationParamsMatch::kHttpRequestHeader);
}

TEST_F(PrerenderHostRegistryTest,
       CompareInitialAndActivationCommonParams_HrefTranslate) {
  EXPECT_FALSE(CheckIsActivatedForParams(
      base::BindLambdaForTesting([](NavigationSimulatorImpl* navigation) {
        navigation->set_href_translate("test");
      })));
  ExpectUniqueSampleOfActivationNavigationParamsMatch(
      PrerenderHost::ActivationNavigationParamsMatch::kHrefTranslate);
}

TEST_F(PrerenderHostRegistryTest,
       CompareInitialAndActivationCommonParams_Transition) {
  EXPECT_FALSE(CheckIsActivatedForParams(
      base::BindLambdaForTesting([](NavigationSimulatorImpl* navigation) {
        navigation->SetTransition(ui::PAGE_TRANSITION_FORM_SUBMIT);
      })));
  ExpectUniqueSampleOfActivationNavigationParamsMatch(
      PrerenderHost::ActivationNavigationParamsMatch::kTransition);
}

TEST_F(PrerenderHostRegistryTest,
       CompareInitialAndActivationCommonParams_RequestContextType) {
  EXPECT_FALSE(CheckIsActivatedForParams(
      base::BindLambdaForTesting([](NavigationSimulatorImpl* navigation) {
        navigation->set_request_context_type(
            blink::mojom::RequestContextType::AUDIO);
      })));
  ExpectUniqueSampleOfActivationNavigationParamsMatch(
      PrerenderHost::ActivationNavigationParamsMatch::kRequestContextType);
}

TEST_F(PrerenderHostRegistryTest,
       CompareInitialAndActivationCommonParams_ReferrerPolicy) {
  EXPECT_TRUE(CheckIsActivatedForParams(
      base::BindLambdaForTesting([&](NavigationSimulatorImpl* navigation) {
        navigation->SetReferrer(blink::mojom::Referrer::New(
            web_contents()->GetPrimaryMainFrame()->GetLastCommittedURL(),
            network::mojom::ReferrerPolicy::kAlways));
      })));
  ExpectUniqueSampleOfActivationNavigationParamsMatch(
      PrerenderHost::ActivationNavigationParamsMatch::kOk);
}

// End navigation parameter matching tests ---------

// Begin replication state matching tests ----------

TEST_F(PrerenderHostRegistryTest, InsecureRequestPolicyIsSetWhilePrerendering) {
  SetupPrerenderAndCommit(
      base::BindLambdaForTesting([](NavigationSimulatorImpl* navigation) {
        navigation->set_insecure_request_policy(
            blink::mojom::InsecureRequestPolicy::kBlockAllMixedContent);
      }));
  EXPECT_EQ(static_cast<TestWebContents*>(web_contents())
                ->GetPrimaryMainFrame()
                ->frame_tree_node()
                ->current_replication_state()
                .insecure_request_policy,
            blink::mojom::InsecureRequestPolicy::kBlockAllMixedContent);
}

TEST_F(PrerenderHostRegistryTest,
       InsecureNavigationsSetIsSetWhilePrerendering) {
  SetupPrerenderAndCommit(
      base::BindLambdaForTesting([](NavigationSimulatorImpl* navigation) {
        const std::vector<uint32_t> insecure_navigations = {1, 2};
        navigation->set_insecure_navigations_set(insecure_navigations);
      }));
  const std::vector<uint32_t> insecure_navigations = {1, 2};
  EXPECT_EQ(static_cast<TestWebContents*>(web_contents())
                ->GetPrimaryMainFrame()
                ->frame_tree_node()
                ->current_replication_state()
                .insecure_navigations_set,
            insecure_navigations);
}

TEST_F(PrerenderHostRegistryTest,
       HasPotentiallyTrustworthyUniqueOriginIsSetWhilePrerendering) {
  SetupPrerenderAndCommit(
      base::BindLambdaForTesting([](NavigationSimulatorImpl* navigation) {
        navigation->set_has_potentially_trustworthy_unique_origin(true);
      }));
  EXPECT_TRUE(static_cast<TestWebContents*>(web_contents())
                  ->GetPrimaryMainFrame()
                  ->frame_tree_node()
                  ->current_replication_state()
                  .has_potentially_trustworthy_unique_origin);
}

TEST_F(PrerenderHostRegistryTest, DisallowPageHavingEffectiveUrl) {
  const GURL kOriginalUrl("https://example.com/");
  const GURL kModifiedSiteUrl("custom-scheme://custom");

  EffectiveURLContentBrowserClient modified_client(
      kOriginalUrl, kModifiedSiteUrl,
      /* requires_dedicated_process */ false);
  ContentBrowserClient* old_client =
      SetBrowserClientForTesting(&modified_client);

  std::unique_ptr<TestWebContents> web_contents =
      CreateWebContents(kOriginalUrl);
  RenderFrameHostImpl* render_frame_host = web_contents->GetPrimaryMainFrame();
  ASSERT_TRUE(render_frame_host);

  const GURL kPrerenderingUrl = GURL("https://example.com/empty.html");
  RenderFrameHostImpl* initiator_rfh = web_contents->GetPrimaryMainFrame();
  PrerenderHostRegistry* registry = web_contents->GetPrerenderHostRegistry();
  const int prerender_frame_tree_node_id = registry->CreateAndStartHost(
      GeneratePrerenderAttributes(kPrerenderingUrl,
                                  PrerenderTriggerType::kSpeculationRule, "",
                                  initiator_rfh),
      *web_contents);
  EXPECT_EQ(prerender_frame_tree_node_id, RenderFrameHost::kNoFrameTreeNodeId);
  PrerenderHost* prerender_host =
      registry->FindNonReservedHostById(prerender_frame_tree_node_id);
  EXPECT_EQ(prerender_host, nullptr);
  ExpectUniqueSampleOfFinalStatus(PrerenderHost::FinalStatus::kHasEffectiveUrl);

  SetBrowserClientForTesting(old_client);
}

// End replication state matching tests ------------

}  // namespace
}  // namespace content


text:
Do you ever wonder how list of all countries and cities looks like? Or maybe you wish wikipedia was only for such purpose?
I have something for you, weirdo

_created for educational purpose_

## how to start?
- `git clone https://github.com/goldenpears/wmappy.git`
- import `wmappy/wmappy` folder via Android Studio (yes, second one)
- run on the emulator or your device in the debug mode

**or** download `.apk` from latest [release](https://github.com/goldenpears/wmappy/releases)

**or** get it at [PlayStore](https://play.google.com/store/apps/details?id=com.locovna.wmappy) and become Alpha tester!

## this is how we do it

- [x] ~~Download a list of countries and cities from [there](https://raw.githubusercontent.com/David-Haim/CountriesToCitiesJSON/master/countriesToCities.json)~~
- [ ] Parse that list into a local database ~~(for now it parses and shows straight into recycle view, right after request via HTTP)~~
- [ ] ~~Create a country selector (dropdown or picker)~~ which is populated from the local database.
- [x] ~~Show a list of cities of the selected country.~~
- [x] ~~Upon selecting a city from the list, fetch info about it and display it on a separate screen. For fetching city info use [Wikipedia search service](http://www.geonames.org/export/wikipedia-webservice.html#wikipediaSearch)~~

## any third-party libraries and frameworks?
[Picasso](http://square.github.io/picasso/) - for load image of `City` at `WikiActivity`.

Why: unfortunately, at native methods, it would be much junky, so we just use  single line of code for single and simple purpose for keep things clean and readable.

## screenshots
![screenshots](img/wmappy.png)
`splash screen` ⭐
`list of countries` ⭐
`dialog with cities` ⭐
`info about city and photo if exist` ⭐

## formally it is
Example of implementing:
- parsing `JSON` via `HTTP`
- showing result as `recycle view`
- displaying `dialog` using `ArrayList`
- and `explicit intent` to `Activity` with, again, parsed `JSON`
- load image if exist, at `WikiActivity` via `Picasso`

redpajama_set_name: RedPajamaGithub


text:
namespace ppatierno.AzureSBLite.Messaging
{
    /// <summary>
    /// Options for the message pump
    /// </summary>
    public sealed class OnMessageOptions
    {
        /// <summary>
        /// Message pump call complete or not when callback completed processing
        /// </summary>
        public bool AutoComplete { get; set; }

        /// <summary>
        /// Constructor
        /// </summary>
        public OnMessageOptions()
        {
            this.AutoComplete = true;
        }
    }
}


text:
#include "config.h"
#include "core/html/HTMLOptGroupElement.h"

#include "core/HTMLNames.h"
#include "core/dom/NodeComputedStyle.h"
#include "core/dom/Text.h"
#include "core/editing/htmlediting.h"
#include "core/html/HTMLContentElement.h"
#include "core/html/HTMLDivElement.h"
#include "core/html/HTMLSelectElement.h"
#include "core/html/shadow/ShadowElementNames.h"
#include "wtf/StdLibExtras.h"
#include "wtf/text/CharacterNames.h"

namespace blink {

using namespace HTMLNames;

inline HTMLOptGroupElement::HTMLOptGroupElement(Document& document)
    : HTMLElement(optgroupTag, document)
{
    setHasCustomStyleCallbacks();
}

PassRefPtrWillBeRawPtr<HTMLOptGroupElement> HTMLOptGroupElement::create(Document& document)
{
    RefPtrWillBeRawPtr<HTMLOptGroupElement> optGroupElement = adoptRefWillBeNoop(new HTMLOptGroupElement(document));
    optGroupElement->ensureUserAgentShadowRoot();
    return optGroupElement.release();
}

bool HTMLOptGroupElement::isDisabledFormControl() const
{
    return fastHasAttribute(disabledAttr);
}

void HTMLOptGroupElement::childrenChanged(const ChildrenChange& change)
{
    recalcSelectOptions();
    HTMLElement::childrenChanged(change);
}

void HTMLOptGroupElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
{
    HTMLElement::parseAttribute(name, value);
    recalcSelectOptions();

    if (name == disabledAttr) {
        pseudoStateChanged(CSSSelector::PseudoDisabled);
        pseudoStateChanged(CSSSelector::PseudoEnabled);
    } else if (name == labelAttr) {
        updateGroupLabel();
    }
}

void HTMLOptGroupElement::recalcSelectOptions()
{
    if (HTMLSelectElement* select = Traversal<HTMLSelectElement>::firstAncestor(*this))
        select->setRecalcListItems();
}

void HTMLOptGroupElement::attach(const AttachContext& context)
{
    if (context.resolvedStyle) {
        ASSERT(!m_style || m_style == context.resolvedStyle);
        m_style = context.resolvedStyle;
    }
    HTMLElement::attach(context);
}

void HTMLOptGroupElement::detach(const AttachContext& context)
{
    m_style.clear();
    HTMLElement::detach(context);
}

bool HTMLOptGroupElement::supportsFocus() const
{
    RefPtrWillBeRawPtr<HTMLSelectElement> select = ownerSelectElement();
    if (select && select->usesMenuList())
        return false;
    return HTMLElement::supportsFocus();
}

void HTMLOptGroupElement::updateNonComputedStyle()
{
    m_style = originalStyleForLayoutObject();
    if (layoutObject()) {
        if (HTMLSelectElement* select = ownerSelectElement())
            select->updateListOnLayoutObject();
    }
}

ComputedStyle* HTMLOptGroupElement::nonLayoutObjectComputedStyle() const
{
    return m_style.get();
}

PassRefPtr<ComputedStyle> HTMLOptGroupElement::customStyleForLayoutObject()
{
    updateNonComputedStyle();
    return m_style;
}

String HTMLOptGroupElement::groupLabelText() const
{
    String itemText = getAttribute(labelAttr);

    // In WinIE, leading and trailing whitespace is ignored in options and optgroups. We match this behavior.
    itemText = itemText.stripWhiteSpace();
    // We want to collapse our whitespace too.  This will match other browsers.
    itemText = itemText.simplifyWhiteSpace();

    return itemText;
}

HTMLSelectElement* HTMLOptGroupElement::ownerSelectElement() const
{
    return Traversal<HTMLSelectElement>::firstAncestor(*this);
}

void HTMLOptGroupElement::accessKeyAction(bool)
{
    HTMLSelectElement* select = ownerSelectElement();
    // send to the parent to bring focus to the list box
    if (select && !select->focused())
        select->accessKeyAction(false);
}

void HTMLOptGroupElement::didAddUserAgentShadowRoot(ShadowRoot& root)
{
    DEFINE_STATIC_LOCAL(AtomicString, labelPadding, ("0 2px 1px 2px", AtomicString::ConstructFromLiteral));
    DEFINE_STATIC_LOCAL(AtomicString, labelMinHeight, ("1.2em", AtomicString::ConstructFromLiteral));
    RefPtrWillBeRawPtr<HTMLDivElement> label = HTMLDivElement::create(document());
    label->setAttribute(roleAttr, AtomicString("group", AtomicString::ConstructFromLiteral));
    label->setAttribute(aria_labelAttr, AtomicString());
    label->setInlineStyleProperty(CSSPropertyPadding, labelPadding);
    label->setInlineStyleProperty(CSSPropertyMinHeight, labelMinHeight);
    label->setIdAttribute(ShadowElementNames::optGroupLabel());
    root.appendChild(label);

    RefPtrWillBeRawPtr<HTMLContentElement> content = HTMLContentElement::create(document());
    content->setAttribute(selectAttr, "option,optgroup,hr");
    root.appendChild(content);
}

void HTMLOptGroupElement::updateGroupLabel()
{
    const String& labelText = groupLabelText();
    HTMLDivElement& label = optGroupLabelElement();
    label.setTextContent(labelText);
    label.setAttribute(aria_labelAttr, AtomicString(labelText));
}

HTMLDivElement& HTMLOptGroupElement::optGroupLabelElement() const
{
    return *toHTMLDivElement(userAgentShadowRoot()->getElementById(ShadowElementNames::optGroupLabel()));
}

} // namespace


text:
An interpretor for a language inspired by Joy.

The purpose of this language is to stick to the Joy philosophy, but not necessarily to be completely backwards compatible. This is a toy research project after all!

For more about Joy, check out the [Joy archive](http://joy-lang.org) for papers, tutorials, and code from Dr Manfred von Thun, the creator of Joy.

## Building the source

There currently are no released packages.

To build Rejoice, run the following at the project's root directory.

```
mvn package
````

## Evaluating code

The `eval` command executes the provided program and exits the process.

```
java -jar target/rejoice-{version}.jar eval '1 2 + !'
```

The command has a `--load` option that will load a module from a file. If any options are provided, the program must be provided after `--` to indicate that there are no more options to handle.

```
java -jar target/rejoice-{version}.jar eval --load foo.rejoice -- 'foo/bar'
```

## Running a REPL

The `repl` command will start a REPL. Type `Ctl-C` to quit the REPL.

```
java -jar target/rejoice-{version}.jar repl
```

As with the `eval` command, `repl` supports the `--load` option to load a module from a file.

```
java -jar target/rejoice-{version}.jar repl --load foo.rejoice
```

Another option is `--eval`, which will execute the provided program immediately after starting the REPL.

The following program will load the `foo` module execute the `bar` function from that module.

```
java -jar target/rejoice-{version}.jar repl --load foo.rejoice --eval 'foo/bar'
```

## Help

The `help` command will list all available commands.

## License

This is a pet project. Feel free to play with it, but don't steal it. Thanks :)

Copyright © 2021 Jeremy Heiler.


text:
<?php

namespace lithium\console\command;

use lithium\util\Text;
use lithium\core\Libraries;
use lithium\util\Inflector;
use lithium\core\ClassNotFoundException;

/**
 * The `create` command allows you to rapidly develop your models, views, controllers, and tests
 * by generating the minimum code necessary to test and run your application.
 *
 * These commands create the `Posts`-controller and model.
 * ```sh
 * li3 create controller Posts
 * li3 create model Posts
 * ```
 *
 * To create the tests for each run:
 * ```sh
 * li3 create test controller Posts
 * li3 create test model Posts
 * ```
 *
 * To create everything in one go run:
 * ```sh
 * li3 create Posts
 * ```
 *
 * Have your own model template? Use the `--template` option:
 * ```sh
 * li3 create --template=MyModel model Posts
 * ```
 */
class Create extends \lithium\console\Command {

	/**
	 * The name of the template to use to generate the file. This allows you to add a custom
	 * template to be used in place of the core template for each command. Place templates in
	 * `<library>\extensions\command\create\template`.
	 *
	 * ```sh
	 * li3 create --template=MyModel model Posts
	 * ```
	 *
	 * @var string
	 */
	public $template = null;

	/**
	 * Name of the library to use, defaults to the current application.
	 *
	 * The following command creates a `Posts` model inside the `blog` library.
	 * ```sh
	 * li3 create --library=blog model Posts
	 * ```
	 *
	 * @var string
	 */
	public $library = null;

	/**
	 * Holds library data from `lithium\core\Libraries::get()`.
	 *
	 * @var array
	 */
	protected $_library = [];

	/**
	 * Class initializer. Parses template and sets up params that need to be filled.
	 *
	 * @return void
	 */
	protected function _init() {
		parent::_init();
		$this->library = $this->library ?: true;
		$defaults = ['prefix' => null, 'path' => null];
		$this->_library = (array) Libraries::get($this->library) + $defaults;
	}

	/**
	 * Run the create command. Takes `$command` and delegates to `$command::$method`
	 *
	 * @param string $command
	 * @return boolean
	 */
	public function run($command = null) {
		if ($command && !$this->request->args()) {
			return $this->_default($command);
		}
		$this->request->shift();
		$this->template = $this->template ?: $command;

		if (!$command) {
			return false;
		}
		if ($this->_execute($command)) {
			return true;
		}
		$this->error("{$command} could not be created.");
		return false;
	}

	/**
	 * Execute the given sub-command for the current request.
	 *
	 * @param string $command The sub-command name. example: Model, Controller, Test
	 * @return boolean
	 */
	protected function _execute($command) {
		try {
			if (!$class = $this->_instance($command)) {
				return false;
			}
		} catch (ClassNotFoundException $e) {
			return false;
		}
		$data = [];
		$params = $class->invokeMethod('_params');

		foreach ($params as $param) {
			$data[$param] = $class->invokeMethod("_{$param}", [$this->request]);
		}

		if ($message = $class->invokeMethod('_save', [$data])) {
			$this->out($message);
			return true;
		}
		return false;
	}

	/**
	 * Run through the default set. model, controller, test model, test controller
	 *
	 * @param string $name class name to create
	 * @return boolean
	 */
	protected function _default($name) {
		$commands = [
			['model', $name],
			['controller', $name],
			['test', 'model', $name],
			['test', 'controller', $name]
		];
		foreach ($commands as $args) {
			$command = $this->template = $this->request->params['command'] = array_shift($args);
			$this->request->params['action'] = array_shift($args);
			$this->request->params['args'] = $args;

			if (!$this->_execute($command)) {
				return false;
			}
		}
		return true;
	}

	/**
	 * Get the namespace.
	 *
	 * @param string $request
	 * @param array $options
	 * @return string
	 */
	protected function _namespace($request, $options  = []) {
		$name = $request->command;
		$defaults = [
			'prefix' => $this->_library['prefix'],
			'prepend' => null,
			'spaces' => [
				'model' => 'models', 'view' => 'views', 'controller' => 'controllers',
				'command' => 'extensions.command', 'adapter' => 'extensions.adapter',
				'helper' => 'extensions.helper'
			]
		];
		$options += $defaults;

		if (isset($options['spaces'][$name])) {
			$name = $options['spaces'][$name];
		}
		return str_replace('.', '\\', $options['prefix'] . $options['prepend'] . $name);
	}

	/**
	 * Parse a template to find available variables specified in `{:name}` format. Each variable
	 * corresponds to a method in the sub command. For example, a `{:namespace}` variable will
	 * call the namespace method in the model command when `li3 create model Post` is called.
	 *
	 * @return array
	 */
	protected function _params() {
		$contents = $this->_template();

		if (empty($contents)) {
			return [];
		}
		preg_match_all('/(?:\{:(?P<params>[^}]+)\})/', $contents, $keys);

		if (!empty($keys['params'])) {
			return array_values(array_unique($keys['params']));
		}
		return [];
	}

	/**
	 * Returns the contents of the template.
	 *
	 * @return string
	 */
	protected function _template() {
		$file = Libraries::locate('command.create.template', $this->template, [
			'filter' => false, 'type' => 'file', 'suffix' => '.txt.php'
		]);
		if (!$file || is_array($file)) {
			return false;
		}
		return file_get_contents($file);
	}

	/**
	 * Get an instance of a sub-command
	 *
	 * @param string $name the name of the sub-command to instantiate
	 * @param array $config
	 * @return object
	 */
	protected function _instance($name, array $config = []) {
		if ($class = Libraries::locate('command.create', Inflector::camelize($name))) {
			$this->request->params['template'] = $this->template;

			return new $class([
				'request' => $this->request,
				'classes' => $this->_classes
			]);
		}
		return parent::_instance($name, $config);
	}

	/**
	 * Save a template with the current params. Writes file to `Create::$path`.
	 *
	 * @param array $params
	 * @return string|boolean A result string on success of writing the file. If any errors
	 *         occur along the way such as missing information boolean false is returned.
	 */
	protected function _save(array $params = []) {
		$defaults = ['namespace' => null, 'class' => null];
		$params += $defaults;

		if (empty($params['class']) || empty($this->_library['path'])) {
			return false;
		}
		$contents = $this->_template();
		$result = Text::insert($contents, $params);
		$namespace = str_replace($this->_library['prefix'], '\\', $params['namespace']);
		$path = str_replace('\\', '/', "{$namespace}\\{$params['class']}");
		$path = $this->_library['path'] . stristr($path, '/');
		$file = str_replace('//', '/', "{$path}.php");
		$directory = dirname($file);
		$relative = str_replace($this->_library['path'] . '/', "", $file);

		if ((!is_dir($directory)) && !mkdir($directory, 0755, true)) {
			return false;
		}
		if (file_exists($file)) {
			$prompt = "{$relative} already exists. Overwrite?";
			$choices = ['y', 'n'];
			if ($this->in($prompt, compact('choices')) !== 'y') {
				return "{$params['class']} skipped.";
			}
		}

		if (file_put_contents($file, "<?php\n\n{$result}\n\n?>")) {
			return "{$params['class']} created in {$relative}.";
		}
		return false;
	}
}

?>


text:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.0" language="it_IT">
<context>
    <name>AddFriendForm</name>
    <message>
        <location filename="../widget/form/addfriendform.cpp" line="32"/>
        <source>Add Friends</source>
        <translation>Aggiungi Contatto</translation>
    </message>
    <message>
        <location filename="../widget/form/addfriendform.cpp" line="35"/>
        <source>Tox ID</source>
        <comment>Tox ID of the person you're sending a friend request to</comment>
        <translation>Tox ID</translation>
    </message>
    <message>
        <location filename="../widget/form/addfriendform.cpp" line="36"/>
        <source>Message</source>
        <comment>The message you send in friend requests</comment>
        <translation>Messaggio</translation>
    </message>
    <message>
        <location filename="../widget/form/addfriendform.cpp" line="37"/>
        <source>Send friend request</source>
        <translation>Invia richiesta d'amicizia</translation>
    </message>
    <message>
        <location filename="../widget/form/addfriendform.cpp" line="38"/>
        <source>Tox me maybe?</source>
        <comment>Default message in friend requests if the field is left blank. Write something appropriate!</comment>
        <translation>Permettimi di aggiungerti alla mia lista contatti</translation>
    </message>
    <message>
        <location filename="../widget/form/addfriendform.cpp" line="93"/>
        <source>Please fill in a valid Tox ID</source>
        <comment>Tox ID of the friend you're sending a friend request to</comment>
        <translation>Inserisci un Tox ID valido</translation>
    </message>
    <message>
        <location filename="../widget/form/addfriendform.cpp" line="110"/>
        <source>This address does not exist</source>
        <comment>The DNS gives the Tox ID associated to toxme.se addresses</comment>
        <translation>Questo indirizzo non esiste</translation>
    </message>
    <message>
        <location filename="../widget/form/addfriendform.cpp" line="114"/>
        <source>Error while looking up DNS</source>
        <comment>The DNS gives the Tox ID associated to toxme.se addresses</comment>
        <translation>Errore nel consultare il server DNS</translation>
    </message>
    <message>
        <location filename="../widget/form/addfriendform.cpp" line="120"/>
        <source>Unexpected number of text records</source>
        <comment>Error with the DNS</comment>
        <translation>Numero inaspettato di text-records</translation>
    </message>
    <message>
        <location filename="../widget/form/addfriendform.cpp" line="126"/>
        <source>Unexpected number of values in text record</source>
        <comment>Error with the DNS</comment>
        <translation>Numero inaspettato di valori nel text-record</translation>
    </message>
    <message>
        <location filename="../widget/form/addfriendform.cpp" line="133"/>
        <source>The DNS lookup does not contain any Tox ID</source>
        <comment>Error with the DNS</comment>
        <translation>La risposta del server DNS non contiene nessun Tox ID</translation>
    </message>
    <message>
        <location filename="../widget/form/addfriendform.cpp" line="139"/>
        <location filename="../widget/form/addfriendform.cpp" line="145"/>
        <source>The DNS lookup does not contain a valid Tox ID</source>
        <comment>Error with the DNS</comment>
        <translation>La risposta del server DNS non contiene un Tox ID valido</translation>
    </message>
</context>
<context>
    <name>Camera</name>
    <message>
        <location filename="../widget/camera.cpp" line="161"/>
        <source>Camera eror</source>
        <translation>Errore webcam</translation>
    </message>
    <message>
        <location filename="../widget/camera.cpp" line="162"/>
        <source>Camera format %1 not supported, can't use the camera</source>
        <translation>Formato webcam %1 non supportato, impossibile usare la webcam</translation>
    </message>
</context>
<context>
    <name>ChatForm</name>
    <message>
        <location filename="../widget/form/chatform.cpp" line="295"/>
        <source>Send a file</source>
        <translation>Invia un file</translation>
    </message>
    <message>
        <location filename="../widget/form/chatform.cpp" line="620"/>
        <location filename="../widget/form/chatform.cpp" line="626"/>
        <source>Save chat log</source>
        <translation>Salva il log della chat</translation>
    </message>
</context>
<context>
    <name>CopyableElideLabel</name>
    <message>
        <location filename="../widget/tool/copyableelidelabel.cpp" line="29"/>
        <source>Copy</source>
        <translation>Copia</translation>
    </message>
</context>
<context>
    <name>FileTransfertWidget</name>
    <message>
        <location filename="../widget/filetransfertwidget.cpp" line="289"/>
        <source>Save a file</source>
        <comment>Title of the file saving dialog</comment>
        <translation>Salva file</translation>
    </message>
    <message>
        <location filename="../widget/filetransfertwidget.cpp" line="300"/>
        <source>Location not writable</source>
        <comment>Title of permissions popup</comment>
        <translation>Errore</translation>
    </message>
    <message>
        <location filename="../widget/filetransfertwidget.cpp" line="300"/>
        <source>You do not have permission to write that location. Choose another, or cancel the save dialog.</source>
        <comment>text of permissions popup</comment>
        <translation>Non hai sufficienti permessi per scrivere in questa locazione. Scegli un'altra posizione, o annulla il salvataggio.</translation>
    </message>
</context>
<context>
    <name>FilesForm</name>
    <message>
        <location filename="../widget/form/filesform.cpp" line="25"/>
        <source>Transfered Files</source>
        <comment>"Headline" of the window</comment>
        <translation>Files inviati</translation>
    </message>
    <message>
        <location filename="../widget/form/filesform.cpp" line="33"/>
        <source>Downloads</source>
        <translation>Ricevuti</translation>
    </message>
    <message>
        <location filename="../widget/form/filesform.cpp" line="34"/>
        <source>Uploads</source>
        <translation>Inviati</translation>
    </message>
</context>
<context>
    <name>FriendRequestDialog</name>
    <message>
        <location filename="../widget/tool/friendrequestdialog.cpp" line="30"/>
        <source>Friend request</source>
        <comment>Title of the window to aceept/deny a friend request</comment>
        <translation>Richiesta d'amicizia</translation>
    </message>
    <message>
        <location filename="../widget/tool/friendrequestdialog.cpp" line="32"/>
        <source>Someone wants to make friends with you</source>
        <translation>Qualcuno vuole chattare con te</translation>
    </message>
    <message>
        <location filename="../widget/tool/friendrequestdialog.cpp" line="33"/>
        <source>User ID:</source>
        <translation>ID Utente:</translation>
    </message>
    <message>
        <location filename="../widget/tool/friendrequestdialog.cpp" line="37"/>
        <source>Friend request message:</source>
        <translation>Messaggio della richiesta d'amicizia:</translation>
    </message>
    <message>
        <location filename="../widget/tool/friendrequestdialog.cpp" line="44"/>
        <source>Accept</source>
        <comment>Accept a friend request</comment>
        <translation>Accetta</translation>
    </message>
    <message>
        <location filename="../widget/tool/friendrequestdialog.cpp" line="45"/>
        <source>Reject</source>
        <comment>Reject a friend request</comment>
        <translation>Rifiuta</translation>
    </message>
</context>
<context>
    <name>FriendWidget</name>
    <message>
        <location filename="../widget/friendwidget.cpp" line="87"/>
        <source>Copy friend ID</source>
        <comment>Menu to copy the Tox ID of that friend</comment>
        <translation>Copia Tox ID del contatto</translation>
    </message>
    <message>
        <location filename="../widget/friendwidget.cpp" line="88"/>
        <source>Invite in group</source>
        <comment>Menu to invite a friend in a groupchat</comment>
        <translation>Invita nel gruppo</translation>
    </message>
    <message>
        <location filename="../widget/friendwidget.cpp" line="98"/>
        <source>Remove friend</source>
        <comment>Menu to remove the friend from our friendlist</comment>
        <translation>Rimuovi contatto</translation>
    </message>
</context>
<context>
    <name>GroupChatForm</name>
    <message>
        <location filename="../widget/form/groupchatform.cpp" line="48"/>
        <source>%1 users in chat</source>
        <comment>Number of users in chat</comment>
        <translation>%1 utenti in chat</translation>
    </message>
    <message>
        <location filename="../widget/form/groupchatform.cpp" line="173"/>
        <source><Unknown></source>
        <translation><Sconosciuto></translation>
    </message>
    <message>
        <location filename="../widget/form/groupchatform.cpp" line="242"/>
        <source>%1 users in chat</source>
        <translation>%1 utenti in chat</translation>
    </message>
    <message>
        <location filename="../widget/form/groupchatform.cpp" line="261"/>
        <source>Save chat log</source>
        <translation>Salva il log della chat</translation>
    </message>
</context>
<context>
    <name>GroupWidget</name>
    <message>
        <location filename="../widget/groupwidget.cpp" line="54"/>
        <location filename="../widget/groupwidget.cpp" line="146"/>
        <source>%1 users in chat</source>
        <translation>%1 utenti in chat</translation>
    </message>
    <message>
        <location filename="../widget/groupwidget.cpp" line="56"/>
        <location filename="../widget/groupwidget.cpp" line="148"/>
        <source>0 users in chat</source>
        <translation>0 utenti in chat</translation>
    </message>
    <message>
        <location filename="../widget/groupwidget.cpp" line="89"/>
        <source>Quit group</source>
        <comment>Menu to quit a groupchat</comment>
        <translation>Esci dal gruppo</translation>
    </message>
</context>
<context>
    <name>SelfCamView</name>
    <message>
        <location filename="../widget/selfcamview.cpp" line="32"/>
        <source>Tox video test</source>
        <comment>Title of the window to test the video/webcam</comment>
        <translation>qTox video test</translation>
    </message>
</context>
<context>
    <name>SettingsForm</name>
    <message>
        <location filename="../widget/form/settingsform.cpp" line="33"/>
        <source>User Settings</source>
        <comment>"Headline" of the window</comment>
        <translation>Impostazioni</translation>
    </message>
    <message>
        <location filename="../widget/form/settingsform.cpp" line="36"/>
        <source>Name</source>
        <comment>Username/nick</comment>
        <translation>Nome</translation>
    </message>
    <message>
        <location filename="../widget/form/settingsform.cpp" line="37"/>
        <source>Status</source>
        <comment>Status message</comment>
        <translation>Stato</translation>
    </message>
    <message>
        <location filename="../widget/form/settingsform.cpp" line="38"/>
        <source>(click here to copy)</source>
        <comment>Click on this text to copy TID to clipboard</comment>
        <translation>(clicca qui per copiare)</translation>
    </message>
    <message>
        <location filename="../widget/form/settingsform.cpp" line="46"/>
        <source>Test video</source>
        <comment>Text on a button to test the video/webcam</comment>
        <translation>Prova la webcam</translation>
    </message>
    <message>
        <location filename="../widget/form/settingsform.cpp" line="47"/>
        <source>Enable IPv6 (recommended)</source>
        <comment>Text on a checkbox to enable IPv6</comment>
        <translation>Abilita IPv6 (consigliato)</translation>
    </message>
    <message>
        <location filename="../widget/form/settingsform.cpp" line="49"/>
        <source>Use translations</source>
        <comment>Text on a checkbox to enable translations</comment>
        <translation>Abilita traduzioni</translation>
    </message>
    <message>
        <location filename="../widget/form/settingsform.cpp" line="51"/>
        <source>Make Tox portable</source>
        <comment>Text on a checkbox to make qTox a portable application</comment>
        <translation>Rendi qTox portabile</translation>
    </message>
    <message>
        <location filename="../widget/form/settingsform.cpp" line="53"/>
        <source>Save settings to the working directory instead of the usual conf dir</source>
        <comment>describes makeToxPortable checkbox</comment>
        <translation>Slava le impostazioni nella directory di lavoro corrente, invece della directory di default</translation>
    </message>
    <message>
        <location filename="../widget/form/settingsform.cpp" line="55"/>
        <source>Smiley Pack</source>
        <comment>Text on smiley pack label</comment>
        <translation>Emoticons</translation>
    </message>
    <message>
        <location filename="../widget/form/settingsform.cpp" line="133"/>
        <source>Select smiley pack</source>
        <translation>Scegli pacchetto emoticons</translation>
    </message>
</context>
<context>
    <name>Widget</name>
    <message>
        <location filename="../widget.ui" line="42"/>
        <source>Tox</source>
        <translation>Tox</translation>
    </message>
    <message>
        <location filename="../widget.ui" line="1951"/>
        <source>Your name</source>
        <translation>Tox User</translation>
    </message>
    <message>
        <location filename="../widget.ui" line="2033"/>
        <source>Your status</source>
        <translation>Toxin on qTox</translation>
    </message>
    <message>
        <location filename="../widget.ui" line="2610"/>
        <source>Add friends</source>
        <translation>Aggiungi contatto</translation>
    </message>
    <message>
        <location filename="../widget.ui" line="2652"/>
        <source>Create a group chat</source>
        <translation>Crea un gruppo</translation>
    </message>
    <message>
        <location filename="../widget.ui" line="2700"/>
        <source>View completed file transfers</source>
        <translation>Visualizza i trasferimenti completati</translation>
    </message>
    <message>
        <source>(button inactive currently)</source>
        <translation type="obsolete">(bottone attualmente inattivo)</translation>
    </message>
    <message>
        <location filename="../widget.ui" line="2748"/>
        <source>Change your settings</source>
        <translation>Cambia le impostazioni</translation>
    </message>
    <message>
        <location filename="../widget.ui" line="3321"/>
        <source>Close</source>
        <translation>Chiudi</translation>
    </message>
    <message>
        <location filename="../widget.ui" line="3324"/>
        <source>Ctrl+Q</source>
        <translation>Ctrl+Q</translation>
    </message>
    <message>
        <source>Online</source>
        <comment>Button to set your status to 'Online'</comment>
        <translation type="obsolete">Online</translation>
    </message>
    <message>
        <source>Away</source>
        <comment>Button to set your status to 'Away'</comment>
        <translation type="obsolete">Assente</translation>
    </message>
    <message>
        <source>Busy</source>
        <comment>Button to set your status to 'Busy'</comment>
        <translation type="obsolete">Occupato</translation>
    </message>
</context>
</TS>


text:
using System.Collections.Generic;

using ASC.Mail.Server.Core.DbSchema.Interfaces;

namespace ASC.Mail.Server.Core.DbSchema.Tables
{
    public class MailboxTable : ITable
    {
        public const string TABLE_NAME = "mailbox";

        public static class Columns
        {
            public const string USERNAME = "username";
            public const string PASSWORD = "password";
            public const string NAME = "name";
            public const string MAILDIR = "maildir";
            public const string MAXQUOTA = "maxquota";
            public const string QUOTA = "quota";
            public const string LOCAL_PART = "local_part";
            public const string DOMAIN = "domain";
            public const string CREATED = "created";
            public const string MODIFIED = "modified";
            public const string ACTIVE = "active";
            public const string ENABLE_IMAP = "enableimap";
            public const string ENABLE_IMAP_SECURED = "enableimapsecured";
            public const string ENABLE_POP = "enablepop3";
            public const string ENABLE_POP_SECURED = "enablepop3secured";
            public const string ENABLE_DELIVER = "enabledeliver";
            public const string ENABLE_LDA = "enablelda";
        }

        public string Name
        {
            get { return TABLE_NAME; }
        }

        public IEnumerable<string> OrderedColumnCollection { get; private set; }

        public MailboxTable()
        {
            OrderedColumnCollection = new List<string>
            {
                Columns.USERNAME,
                Columns.PASSWORD,
                Columns.NAME,
                Columns.MAILDIR,
                Columns.MAXQUOTA,
                Columns.QUOTA,
                Columns.LOCAL_PART,
                Columns.DOMAIN,
                Columns.CREATED,
                Columns.MODIFIED,
                Columns.ACTIVE,
                Columns.ENABLE_IMAP,
                Columns.ENABLE_IMAP_SECURED,
                Columns.ENABLE_POP,
                Columns.ENABLE_POP_SECURED,
                Columns.ENABLE_DELIVER,
                Columns.ENABLE_LDA
            };
        }
    }
}


text:
package vcr

import (
	"encoding/json"
	"io/ioutil"
	"log"
	"net/http"
	"os"
)

func exists(path string) bool {
	_, err := os.Stat(path)
	if err == nil {
		return true
	}
	if os.IsNotExist(err) {
		return false
	}
	return false
}

func createCassetteFile(filename string) string {
	if !exists("fixtures") {
		if os.MkdirAll("fixtures", 0755) != nil {
			panic("Unable to create directory for tagfile!")
		}
	}

	if !exists(filename) {
		file, err := os.Create(filename)
		if err != nil {
			panic("Unable to create tag file!")
		}
		defer file.Close()
	}

	return filename
}

func requestHandler(r *http.Request) (*http.Response, error) {
	client := &http.Client{}
	req, err := http.NewRequest(r.Method, r.URL.String(), r.Body)
	if err != nil {
		log.Fatal(err)
	}

	req.Header = r.Header
	return client.Do(req)
}

func useCassette(filename string) cassetteData {
	file, err := ioutil.ReadFile(filename)
	if err != nil {
		log.Fatal(err)
	}

	cassette := cassetteData{}
	json.Unmarshal(file, &cassette)

	return cassette
}

func newCassette(r *http.Request, resp *http.Response, filename string) cassetteData {
	cassette := cassetteData{}

	cassette.Request.Method = r.Method
	cassette.Request.URL = r.URL.String()
	cassette.Request.Header = r.Header
	cassette.Request.Values = r.PostForm

	cassette.Response.Header = resp.Header
	cassette.Response.Status = resp.Status
	cassette.Response.StatusCode = resp.StatusCode

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Fatal(err)
	}
	cassette.Response.Body = string(body)

	data, err := json.Marshal(cassette)
	if err != nil {
		log.Fatal(err)
	}
	ioutil.WriteFile(filename, data, 0644)

	return cassette
}

func recordCassette(r *http.Request, filename string) cassetteData {
	createCassetteFile(filename)

	resp, err := requestHandler(r)
	if err != nil {
		log.Fatal(err)
	}

	cassette := newCassette(r, resp, filename)
	return cassette
}


text:
package ipam_test

import (
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"

	"testing"
)

func TestIpam(t *testing.T) {
	RegisterFailHandler(Fail)
	RunSpecs(t, "Ipam Suite")
}


text:
package com.chhuang.novel.data.dao;

import android.provider.BaseColumns;
import com.chhuang.novel.data.sql.SQLiteTable;

import static com.chhuang.novel.data.sql.Column.DataType.*;

/**
 * Date: 2014/6/4
 * Time: 15:29
 *
 * @author chhuang
 */
public class ArticleInfo implements BaseColumns {
    public static final String      TABLE_NAME  = "articles";
    public static final String      NOVEL_NAME  = "novel_name";
    public static final String      TITLE       = "title";
    public static final String      CONTENT     = "content";
    public static final String      PERCENTAGE  = "percentage";
    public static final String      URL         = "url";
    public static final String      ID          = "id";
    public static final String      TIME        = "time";
    public static final SQLiteTable TABLE       = new SQLiteTable(TABLE_NAME)
            .addColumn(NOVEL_NAME, TEXT)
            .addColumn(ID, INTEGER)
            .addColumn(PERCENTAGE, REAL)
            .addColumn(TITLE, TEXT)
            .addColumn(CONTENT, BLOB)
            .addColumn(URL, TEXT)
            .addColumn(TIME, INTEGER)
            .addUniqueColumns(NOVEL_NAME, ID);
    public static final String[] PROJECTIONS = new String[]{
            _ID, NOVEL_NAME, ID, PERCENTAGE, TITLE, CONTENT, URL, TIME};

    ArticleInfo() {
    }
}


text:
<?php

namespace Database\Migrations;

use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;

class Version20170531071852_add_pin_table extends AbstractMigration
{
    /**
     * @param Schema $schema
     */
    public function up(Schema $schema): void
    {
        $this->abortIf($this->connection->getDatabasePlatform()->getName() != 'mysql', 'Migration can only be executed safely on \'mysql\'.');

        $this->addSql('CREATE TABLE pins (id INT UNSIGNED AUTO_INCREMENT NOT NULL, user_id INT UNSIGNED DEFAULT NULL, pin VARCHAR(12) NOT NULL, date_added DATETIME NOT NULL, expiry DATETIME DEFAULT NULL, state INT DEFAULT 10 NOT NULL, UNIQUE INDEX UNIQ_3F0FE980B5852DF3 (pin), INDEX IDX_3F0FE980A76ED395 (user_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB');
        $this->addSql('ALTER TABLE pins ADD CONSTRAINT FK_3F0FE980A76ED395 FOREIGN KEY (user_id) REFERENCES user (id)');
    }

    /**
     * @param Schema $schema
     */
    public function down(Schema $schema): void
    {
        $this->abortIf($this->connection->getDatabasePlatform()->getName() != 'mysql', 'Migration can only be executed safely on \'mysql\'.');

        $this->addSql('DROP TABLE pins');
    }
}


text:
import { RoutingManager } from '../../../../../../app/livechat/server/lib/RoutingManager';
import { Users } from '../../../../../../app/models/server/raw';
import { IRoutingManagerConfig } from '../../../../../../definition/IRoutingManagerConfig';
import { IOmnichannelCustomAgent } from '../../../../../../definition/IOmnichannelCustomAgent';

/* Load Rotation Queuing method:
	* Routing method where the agent with the oldest routing time is the next agent to serve incoming chats
*/
class LoadRotation {
	private _config: IRoutingManagerConfig;

	constructor() {
		this._config = {
			previewRoom: false,
			showConnecting: false,
			showQueue: false,
			showQueueLink: false,
			returnQueue: false,
			enableTriggerAction: true,
			autoAssignAgent: true,
		};
	}

	get config(): IRoutingManagerConfig {
		return this._config;
	}

	public async getNextAgent(department?: string, ignoreAgentId?: string): Promise<IOmnichannelCustomAgent | undefined> {
		const nextAgent = await Users.getLastAvailableAgentRouted(department, ignoreAgentId);
		if (!nextAgent) {
			return;
		}

		const { agentId, username } = nextAgent;
		return { agentId, username };
	}
}

RoutingManager.registerMethod('Load_Rotation', LoadRotation);


text:
require "fileutils"
require "pathname"
require "digest/md5"
require "active_support/core_ext/numeric/bytes"

module ActiveStorage
  # Wraps a local disk path as an Active Storage service. See ActiveStorage::Service for the generic API
  # documentation that applies to all services.
  class Service::DiskService < Service
    attr_reader :root

    def initialize(root:)
      @root = root
    end

    def upload(key, io, checksum: nil)
      instrument :upload, key, checksum: checksum do
        IO.copy_stream(io, make_path_for(key))
        ensure_integrity_of(key, checksum) if checksum
      end
    end

    def download(key)
      if block_given?
        instrument :streaming_download, key do
          File.open(path_for(key), "rb") do |file|
            while data = file.read(64.kilobytes)
              yield data
            end
          end
        end
      else
        instrument :download, key do
          File.binread path_for(key)
        end
      end
    end

    def delete(key)
      instrument :delete, key do
        begin
          File.delete path_for(key)
        rescue Errno::ENOENT
          # Ignore files already deleted
        end
      end
    end

    def exist?(key)
      instrument :exist, key do |payload|
        answer = File.exist? path_for(key)
        payload[:exist] = answer
        answer
      end
    end

    def url(key, expires_in:, filename:, disposition:, content_type:)
      instrument :url, key do |payload|
        verified_key_with_expiration = ActiveStorage.verifier.generate(key, expires_in: expires_in, purpose: :blob_key)

        generated_url =
          if defined?(Rails.application)
            Rails.application.routes.url_helpers.rails_disk_service_path \
              verified_key_with_expiration,
              filename: filename, disposition: disposition, content_type: content_type
          else
            "/rails/active_storage/disk/#{verified_key_with_expiration}/#{filename}?content_type=#{content_type}&disposition=#{disposition}"
          end

        payload[:url] = generated_url

        generated_url
      end
    end

    def url_for_direct_upload(key, expires_in:, content_type:, content_length:, checksum:)
      instrument :url, key do |payload|
        verified_token_with_expiration = ActiveStorage.verifier.generate(
          {
            key: key,
            content_type: content_type,
            content_length: content_length,
            checksum: checksum
          },
          { expires_in: expires_in,
          purpose: :blob_token }
        )

        generated_url =
          if defined?(Rails.application)
            Rails.application.routes.url_helpers.update_rails_disk_service_path verified_token_with_expiration
          else
            "/rails/active_storage/disk/#{verified_token_with_expiration}"
          end

        payload[:url] = generated_url

        generated_url
      end
    end

    def headers_for_direct_upload(key, content_type:, **)
      { "Content-Type" => content_type }
    end

    private
      def path_for(key)
        File.join root, folder_for(key), key
      end

      def folder_for(key)
        [ key[0..1], key[2..3] ].join("/")
      end

      def make_path_for(key)
        path_for(key).tap { |path| FileUtils.mkdir_p File.dirname(path) }
      end

      def ensure_integrity_of(key, checksum)
        unless Digest::MD5.file(path_for(key)).base64digest == checksum
          delete key
          raise ActiveStorage::IntegrityError
        end
      end
  end
end


text:
char *mne_tos(long l);

// The result type for mne_tol()
//
// error if err != 0,
// result if err == 0
//
typedef struct {
  int err;
  long result;
} mne_tol_result;

// Takes a string, returns the corresponding long.
//
// If there is no corresponding long, returns 0...
//
mne_tol_result mne_tol(char *s);

// Returns 1 if the string is a mnemo string, 0 else.
//
int mne_ismnemo(char *s);

#endif // MNEMO_H


text:
class Trigger(object):
    def __init__(self):
        self._callbacks = set()

    def add_callback(self, f):
        self._callbacks.add(f)
        # Always call it immediately -- this is always legal (b/c as soon as
        # you call add_callback you have to be prepared for changes to
        # happen), saves having to explicitly call refresh methods in every
        # __init__, and flushes out bugs.
        f()

    def remove_callback(self, f):
        self._callbacks.remove(f)

    def fire(self):
        for f in self._callbacks:
            f()


text:
var actionSteps = function() {

    this.World = require("../support/world.js");
    var PROPERTIES = require('../../config.json');

    this.When(/^I click on weather tab$/, function(callback) {
        this.click('#weather', function(err, callback) {});
        // callback();
        this.pause(1000, callback);
    });

    this.When(/^I click on tab "([^"]*)"$/, function(arg1, callback) {
        // Write code here that turns the phrase above into concrete actions
        // callback.pending();
        console.log("Click Tab == arg1 = " + arg1);
        if (arg1 === "weather") {
            this.isVisible('#weather', function(err) {
                if (err) callback.fail(new Error("Expected to be on page  "));
            });
            this.click('#weather', function(err, callback) {});
            // callback();
            this.pause(1000, callback);
        }
    });

    this.When(/^I click button "([^"]*)"$/, function(arg1, callback) {
        // Write code here that turns the phrase above into concrete actions
        // callback.pending();
        console.log("Click button arg1 = " + arg1);
        if (arg1 === "Submit") {
            this.isVisible('#submit', function(err) {
                if (err) callback.fail(new Error("Expected to be on page  "));
            });
            this.click('#submit', function(err, callback) {});
        }
        // callback();
        this.pause(1000, callback);
    });
}
module.exports = actionSteps;