text:
// Copyright 2017 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "auth/src/desktop/user_desktop.h"

#include "app/rest/transport_builder.h"
#include "app/rest/transport_curl.h"
#include "app/rest/transport_mock.h"
#include "app/src/include/firebase/app.h"
#include "app/src/include/firebase/internal/mutex.h"
#include "app/tests/include/firebase/app_for_testing.h"
#include "auth/src/desktop/auth_desktop.h"
#include "auth/src/include/firebase/auth.h"
#include "auth/src/include/firebase/auth/user.h"
#include "auth/tests/desktop/fakes.h"
#include "auth/tests/desktop/test_utils.h"
#include "flatbuffers/stl_emulation.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "testing/config.h"
#include "testing/ticker.h"

namespace firebase {
namespace auth {

using test::CreateErrorHttpResponse;
using test::FakeSetT;
using test::FakeSuccessfulResponse;
using test::GetFakeOAuthProviderData;
using test::GetUrlForApi;
using test::InitializeConfigWithAFake;
using test::InitializeConfigWithFakes;
using test::OAuthProviderTestHandler;
using test::SleepUponDestruction;
using test::VerifySignInResult;
using test::WaitForFuture;

using ::testing::AnyOf;
using ::testing::IsEmpty;

namespace {

const char* const API_KEY = "MY-FAKE-API-KEY";
// Constant, describing how many times we would like to sleep 1ms to wait
// for loading persistence cache.
const int kWaitForLoadMaxTryout = 500;

void InitializeSignUpFlowFakes() {
  FakeSetT fakes;

  fakes[GetUrlForApi(API_KEY, "signupNewUser")] =
      FakeSuccessfulResponse("SignupNewUserResponse",
                             " \"idToken\": \"idtoken123\","
                             " \"refreshToken\": \"refreshtoken123\","
                             " \"expiresIn\": \"3600\","
                             " \"localId\": \"localid123\"");
  fakes[GetUrlForApi(API_KEY, "getAccountInfo")] =
      FakeSuccessfulResponse("GetAccountInfoResponse",
                             " \"users\": ["
                             "  {"
                             "   \"localId\": \"localid123\","
                             "   \"lastLoginAt\": \"123\","
                             "   \"createdAt\": \"456\""
                             "  }"
                             " ]");

  InitializeConfigWithFakes(fakes);
}

std::string GetSingleFakeProvider(const std::string& provider_id) {
  // clang-format off
  return std::string(
      "  {"
      "    \"federatedId\": \"fake_uid\","
      "    \"email\": \"fake_email@example.com\","
      "    \"displayName\": \"fake_display_name\","
      "    \"photoUrl\": \"fake_photo_url\","
      "    \"providerId\": \"") + provider_id + "\","
      "    \"phoneNumber\": \"123123\""
      "  }";
  // clang-format on
}

std::string GetFakeProviderInfo(
    const std::string& provider_id = "fake_provider_id") {
  return std::string("\"providerUserInfo\": [") +
         GetSingleFakeProvider(provider_id) + "]";
}

std::string FakeSetAccountInfoResponse() {
  return FakeSuccessfulResponse(
      "SetAccountInfoResponse",
      std::string("\"localId\": \"fake_local_id\","
                  "\"email\": \"new_fake_email@example.com\","
                  "\"idToken\": \"new_fake_token\","
                  "\"expiresIn\": \"3600\","
                  "\"passwordHash\": \"new_fake_hash\","
                  "\"emailVerified\": false,") +
          GetFakeProviderInfo());
}

std::string FakeSetAccountInfoResponseWithDetails() {
  return FakeSuccessfulResponse(
      "SetAccountInfoResponse",
      std::string("\"localId\": \"fake_local_id\","
                  "\"email\": \"new_fake_email@example.com\","
                  "\"idToken\": \"new_fake_token2\","
                  "\"expiresIn\": \"3600\","
                  "\"passwordHash\": \"new_fake_hash\","
                  "\"displayName\": \"Fake Name\","
                  "\"photoUrl\": \"https://fake_url.com\","
                  "\"emailVerified\": false,") +
          GetFakeProviderInfo());
}

std::string FakeVerifyAssertionResponse() {
  return FakeSuccessfulResponse("VerifyAssertionResponse",
                                "\"isNewUser\": true,"
                                "\"localId\": \"localid123\","
                                "\"idToken\": \"verify_idtoken123\","
                                "\"providerId\": \"google.com\","
                                "\"refreshToken\": \"verify_refreshtoken123\","
                                "\"expiresIn\": \"3600\"");
}

std::string FakeGetAccountInfoResponse() {
  return FakeSuccessfulResponse(
      "GetAccountInfoResponse",
      std::string("\"users\":"
                  "  ["
                  "    {"
                  "       \"localId\": \"localid123\","
                  "       \"email\": \"testsignin@example.com\","
                  "       \"emailVerified\": false,"
                  "       \"passwordHash\": \"abcdefg\","
                  "       \"passwordUpdatedAt\": 31415926,"
                  "       \"validSince\": \"123\","
                  "       \"lastLoginAt\": \"123\","
                  "       \"createdAt\": \"123\",") +
          GetFakeProviderInfo() +
          "    }"
          " ]");
}

std::string CreateGetAccountInfoFake() {
  return FakeSuccessfulResponse(
      "GetAccountInfoResponse",
      std::string("\"users\":"
                  "  ["
                  "    {"
                  "       \"localId\": \"localid123\","
                  "       \"email\": \"testsignin@example.com\","
                  "       \"emailVerified\": false,"
                  "       \"passwordHash\": \"abcdefg\","
                  "       \"passwordUpdatedAt\": 31415926,"
                  "       \"validSince\": \"123\","
                  "       \"lastLoginAt\": \"123\","
                  "       \"createdAt\": \"123\",") +
          GetFakeProviderInfo() +
          "    }"
          " ]");
}

void InitializeAuthorizeWithProviderFakes(
    const std::string& get_account_info_response) {
  FakeSetT fakes;
  fakes[GetUrlForApi(API_KEY, "getAccountInfo")] = get_account_info_response;
  InitializeConfigWithFakes(fakes);
}

void InitializeSuccessfulAuthenticateWithProviderFlow(
    FederatedOAuthProvider* provider, OAuthProviderTestHandler* handler,
    const std::string& get_account_info_response) {
  InitializeAuthorizeWithProviderFakes(get_account_info_response);
  provider->SetProviderData(GetFakeOAuthProviderData());
  provider->SetAuthHandler(handler);
}

void InitializeSuccessfulAuthenticateWithProviderFlow(
    FederatedOAuthProvider* provider, OAuthProviderTestHandler* handler) {
  InitializeSuccessfulAuthenticateWithProviderFlow(provider, handler,
                                                   CreateGetAccountInfoFake());
}

void VerifyUser(const User& user) {
  EXPECT_EQ("localid123", user.uid());
  EXPECT_EQ("testsignin@example.com", user.email());
  EXPECT_EQ("", user.display_name());
  EXPECT_EQ("", user.photo_url());
  EXPECT_EQ("Firebase", user.provider_id());
  EXPECT_EQ("", user.phone_number());
  EXPECT_FALSE(user.is_email_verified());
}

void VerifyProviderData(const User& user) {
  const std::vector<UserInfoInterface*>& provider_data = user.provider_data();
  EXPECT_EQ(1, provider_data.size());
  if (provider_data.empty()) {
    return;  // Avoid crashing on vector out-of-bounds access below
  }
  EXPECT_EQ("fake_uid", provider_data[0]->uid());
  EXPECT_EQ("fake_email@example.com", provider_data[0]->email());
  EXPECT_EQ("fake_display_name", provider_data[0]->display_name());
  EXPECT_EQ("fake_photo_url", provider_data[0]->photo_url());
  EXPECT_EQ("fake_provider_id", provider_data[0]->provider_id());
  EXPECT_EQ("123123", provider_data[0]->phone_number());
}

void InitializeSuccessfulVerifyAssertionFlow(
    const std::string& verify_assertion_response) {
  FakeSetT fakes;
  fakes[GetUrlForApi(API_KEY, "verifyAssertion")] = verify_assertion_response;
  fakes[GetUrlForApi(API_KEY, "getAccountInfo")] = FakeGetAccountInfoResponse();
  InitializeConfigWithFakes(fakes);
}

void InitializeSuccessfulVerifyAssertionFlow() {
  InitializeSuccessfulVerifyAssertionFlow(FakeVerifyAssertionResponse());
}

bool WaitOnLoadPersistence(AuthData* auth_data) {
  bool load_finished = false;
  int load_wait_counter = 0;
  while (!load_finished) {
    if (load_wait_counter >= kWaitForLoadMaxTryout) {
      break;
    }
    load_wait_counter++;
    firebase::internal::Sleep(1);
    {
      MutexLock lock(auth_data->listeners_mutex);
      load_finished = !auth_data->persistent_cache_load_pending;
    }
  }
  return load_finished;
}

}  // namespace

class UserDesktopTest : public ::testing::Test {
 protected:
  UserDesktopTest() : sem_(0) {}

  void SetUp() override {
    rest::SetTransportBuilder([]() -> flatbuffers::unique_ptr<rest::Transport> {
      return flatbuffers::unique_ptr<rest::Transport>(
          new rest::TransportMock());
    });
    AppOptions options = testing::MockAppOptions();
    options.set_api_key(API_KEY);
    firebase_app_ = std::unique_ptr<App>(testing::CreateApp(options));
    firebase_auth_ = std::unique_ptr<Auth>(Auth::GetAuth(firebase_app_.get()));

    InitializeSignUpFlowFakes();

    firebase_auth_->AddIdTokenListener(&id_token_listener);
    firebase_auth_->AddAuthStateListener(&auth_state_listener);

    WaitOnLoadPersistence(firebase_auth_->auth_data_);

    // Current user should be updated upon successful anonymous sign-in.
    // Should expect one extra trigger during either listener add after load
    // credential is done, or load finish after listener added, so changed
    // twice.
    id_token_listener.ExpectChanges(2);
    auth_state_listener.ExpectChanges(2);

    Future<User*> future = firebase_auth_->SignInAnonymously();
    while (future.status() == kFutureStatusPending) {
    }
    firebase_user_ = firebase_auth_->current_user();
    EXPECT_NE(nullptr, firebase_user_);

    // Reset listeners before tests are run.
    id_token_listener.VerifyAndReset();
    auth_state_listener.VerifyAndReset();
  }

  void TearDown() override {
    // Reset listeners before signing out.
    id_token_listener.VerifyAndReset();
    auth_state_listener.VerifyAndReset();
    firebase_auth_->SignOut();

    // Wait for the app to finish any remaining tasks in queue,
    // specifically delete app data from persistent cache after SignOut.
    // This is to avoid race conditions where the next test's SignIn
    // doesn't cause a change in auth state or id tokens because persistent
    // cache has valid user logged in, preventing listeners from firing.
    { SleepUponDestruction sleep_for_listeners; }

    firebase_auth_.reset(nullptr);
    firebase_app_.reset(nullptr);
    // cppsdk needs to be the last thing torn down, because the mocks are still
    // needed for parts of the firebase destructors.
    firebase::testing::cppsdk::ConfigReset();
  }

  Future<SignInResult> ProcessLinkWithProviderFlow(
      FederatedOAuthProvider* provider, OAuthProviderTestHandler* handler,
      bool trigger_link) {
    InitializeSuccessfulAuthenticateWithProviderFlow(provider, handler);
    Future<SignInResult> future = firebase_user_->LinkWithProvider(provider);
    if (trigger_link) {
      handler->TriggerLinkComplete();
    }
    return future;
  }

  Future<SignInResult> ProcessReauthenticateWithProviderFlow(
      FederatedOAuthProvider* provider, OAuthProviderTestHandler* handler,
      bool trigger_reauthenticate) {
    InitializeSuccessfulAuthenticateWithProviderFlow(provider, handler);
    Future<SignInResult> future =
        firebase_user_->ReauthenticateWithProvider(provider);
    if (trigger_reauthenticate) {
      handler->TriggerReauthenticateComplete();
    }
    return future;
  }

  std::unique_ptr<App> firebase_app_;
  std::unique_ptr<Auth> firebase_auth_;
  User* firebase_user_ = nullptr;

  test::IdTokenChangesCounter id_token_listener;
  test::AuthStateChangesCounter auth_state_listener;

  Semaphore sem_;
};

// Test that metadata is correctly being populated and exposed
TEST_F(UserDesktopTest, TestAccountMetadata) {
  EXPECT_EQ(123,
            firebase_auth_->current_user()->metadata().last_sign_in_timestamp);
  EXPECT_EQ(456, firebase_auth_->current_user()->metadata().creation_timestamp);
}

TEST_F(UserDesktopTest, TestGetToken) {
  const auto api_url =
      std::string("https://securetoken.googleapis.com/v1/token?key=") + API_KEY;
  InitializeConfigWithAFake(
      api_url,
      FakeSuccessfulResponse("\"access_token\": \"new accesstoken123\","
                             "\"expires_in\": \"3600\","
                             "\"token_type\": \"Bearer\","
                             "\"refresh_token\": \"new refreshtoken123\","
                             "\"id_token\": \"new idtoken123\","
                             "\"user_id\": \"localid123\","
                             "\"project_id\": \"53101460582\""));

  // Token should change, but user stays the same.
  id_token_listener.ExpectChanges(1);
  auth_state_listener.ExpectChanges(0);

  // Call the function and verify results.
  std::string token = WaitForFuture(firebase_user_->GetToken(false));
  EXPECT_EQ("idtoken123", token);

  // Call again won't change token since it is still valid.
  token = WaitForFuture(firebase_user_->GetToken(false));
  EXPECT_NE("new idtoken123", token);

  // Call again to force refreshing token.
  const std::string new_token = WaitForFuture(firebase_user_->GetToken(true));
  EXPECT_NE(token, new_token);
  EXPECT_EQ("new idtoken123", new_token);
}

TEST_F(UserDesktopTest, TestDelete) {
  InitializeConfigWithAFake(
      GetUrlForApi(API_KEY, "deleteAccount"),
      FakeSuccessfulResponse("DeleteAccountResponse", ""));

  // Expect logout.
  id_token_listener.ExpectChanges(1);
  auth_state_listener.ExpectChanges(1);

  EXPECT_FALSE(firebase_user_->uid().empty());
  WaitForFuture(firebase_user_->Delete());
  EXPECT_TRUE(firebase_user_->uid().empty());
}

TEST_F(UserDesktopTest, TestSendEmailVerification) {
  InitializeConfigWithAFake(
      GetUrlForApi(API_KEY, "getOobConfirmationCode"),
      FakeSuccessfulResponse("GetOobConfirmationCodeResponse",
                             "\"email\": \"fake_email@example.com\""));

  // Sending email shouldn't affect the current user in any way.
  id_token_listener.ExpectChanges(0);
  auth_state_listener.ExpectChanges(0);

  WaitForFuture(firebase_user_->SendEmailVerification());
}

TEST_F(UserDesktopTest, TestReload) {
  InitializeConfigWithAFake(
      GetUrlForApi(API_KEY, "getAccountInfo"),
      FakeSuccessfulResponse(
          "GetAccountInfoResponse",
          std::string("\"users\": ["
                      "  {"
                      "    \"localId\": \"fake_local_id\","
                      "    \"email\": \"fake_email@example.com\","
                      "    \"emailVerified\": false,"
                      "    \"passwordHash\": \"fake_hash\","
                      "    \"passwordUpdatedAt\": 1.509402565E12,"
                      // Note: these values are copied from an actual
                      // backend response, so it seems that backend uses
                      // seconds for validSince but microseconds for the
                      // other time fields.
                      "    \"validSince\": \"1509402565\","
                      "    \"lastLoginAt\": \"1509402565000\","
                      "    \"createdAt\": \"1509402565000\",") +
              GetFakeProviderInfo() +
              "  }"
              "]"));

  // User stayed the same, and GetAccountInfoResponse doesn't contain tokens.
  id_token_listener.ExpectChanges(0);
  auth_state_listener.ExpectChanges(0);

  WaitForFuture(firebase_user_->Reload());
  VerifyProviderData(*firebase_user_);
}

// Tests the happy case of setting a new email on the currently logged in user.
TEST_F(UserDesktopTest, TestUpdateEmail) {
  InitializeConfigWithAFake(GetUrlForApi(API_KEY, "setAccountInfo"),
                            FakeSetAccountInfoResponse());

  // SetAccountInfoResponse contains a new token.
  id_token_listener.ExpectChanges(1);
  auth_state_listener.ExpectChanges(0);

  const std::string new_email = "new_fake_email@example.com";

  EXPECT_NE(new_email, firebase_user_->email());
  WaitForFuture(firebase_user_->UpdateEmail(new_email.c_str()));
  EXPECT_EQ(new_email, firebase_user_->email());
  VerifyProviderData(*firebase_user_);
}

// Tests the happy case of setting a new password on the currently logged in
// user.
TEST_F(UserDesktopTest, TestUpdatePassword) {
  InitializeConfigWithAFake(GetUrlForApi(API_KEY, "setAccountInfo"),
                            FakeSetAccountInfoResponse());

  // SetAccountInfoResponse contains a new token.
  id_token_listener.ExpectChanges(1);
  auth_state_listener.ExpectChanges(0);

  WaitForFuture(firebase_user_->UpdatePassword("new_password"));
  VerifyProviderData(*firebase_user_);
}

// Tests the happy case of setting new profile properties (display name and
// photo URL) on the currently logged in user.
TEST_F(UserDesktopTest, TestUpdateProfile_Update) {
  InitializeConfigWithAFake(GetUrlForApi(API_KEY, "setAccountInfo"),
                            FakeSetAccountInfoResponseWithDetails());

  // SetAccountInfoResponse contains a new token.
  id_token_listener.ExpectChanges(1);
  auth_state_listener.ExpectChanges(0);

  const std::string display_name = "Fake Name";
  const std::string photo_url = "https://fake_url.com";
  User::UserProfile profile;
  profile.display_name = display_name.c_str();
  profile.photo_url = photo_url.c_str();

  EXPECT_NE(display_name, firebase_user_->display_name());
  EXPECT_NE(photo_url, firebase_user_->photo_url());
  WaitForFuture(firebase_user_->UpdateUserProfile(profile));
  EXPECT_EQ(display_name, firebase_user_->display_name());
  EXPECT_EQ(photo_url, firebase_user_->photo_url());
  VerifyProviderData(*firebase_user_);
}

// Tests the happy case of deleting profile properties from the currently logged
// in user (setting display name and photo URL to be blank).
TEST_F(UserDesktopTest, TestUpdateProfile_Delete) {
  InitializeConfigWithAFake(GetUrlForApi(API_KEY, "setAccountInfo"),
                            FakeSetAccountInfoResponseWithDetails());

  const std::string display_name = "Fake Name";
  const std::string photo_url = "https://fake_url.com";
  User::UserProfile profile;
  profile.display_name = display_name.c_str();
  profile.photo_url = photo_url.c_str();

  WaitForFuture(firebase_user_->UpdateUserProfile(profile));
  EXPECT_EQ(display_name, firebase_user_->display_name());
  EXPECT_EQ(photo_url, firebase_user_->photo_url());

  InitializeConfigWithAFake(GetUrlForApi(API_KEY, "setAccountInfo"),
                            FakeSetAccountInfoResponse());

  User::UserProfile blank_profile;
  blank_profile.display_name = blank_profile.photo_url = "";
  WaitForFuture(firebase_user_->UpdateUserProfile(blank_profile));
  EXPECT_TRUE(firebase_user_->display_name().empty());
  EXPECT_TRUE(firebase_user_->photo_url().empty());
}

// Tests the happy case of unlinking a provider from the currently logged in
// user.
TEST_F(UserDesktopTest, TestUnlink) {
  FakeSetT fakes;
  // So that the user has an associated provider
  fakes[GetUrlForApi(API_KEY, "getAccountInfo")] = FakeGetAccountInfoResponse();
  fakes[GetUrlForApi(API_KEY, "setAccountInfo")] = FakeSetAccountInfoResponse();
  InitializeConfigWithFakes(fakes);

  // SetAccountInfoResponse contains a new token.
  id_token_listener.ExpectChanges(1);
  auth_state_listener.ExpectChanges(0);

  WaitForFuture(firebase_user_->Reload());
  WaitForFuture(firebase_user_->Unlink("fake_provider_id"));
  VerifyProviderData(*firebase_user_);
}

TEST_F(UserDesktopTest, TestUnlink_NonLinkedProvider) {
  InitializeConfigWithAFake(GetUrlForApi(API_KEY, "setAccountInfo"),
                            FakeSetAccountInfoResponse());

  id_token_listener.ExpectChanges(0);
  auth_state_listener.ExpectChanges(0);

  WaitForFuture(firebase_user_->Unlink("no_such_provider"),
                kAuthErrorNoSuchProvider);
}

TEST_F(UserDesktopTest, TestLinkWithCredential_OauthCredential) {
  InitializeSuccessfulVerifyAssertionFlow();

  // Response contains a new ID token, but user should have stayed the same.
  id_token_listener.ExpectChanges(1);
  auth_state_listener.ExpectChanges(0);

  EXPECT_TRUE(firebase_user_->is_anonymous());
  const Credential credential =
      GoogleAuthProvider::GetCredential("fake_id_token", "");
  const User* const user =
      WaitForFuture(firebase_user_->LinkWithCredential(credential));
  EXPECT_FALSE(user->is_anonymous());
  VerifyUser(*user);
}

TEST_F(UserDesktopTest, TestLinkWithCredential_EmailCredential) {
  InitializeConfigWithAFake(GetUrlForApi(API_KEY, "setAccountInfo"),
                            FakeSetAccountInfoResponse());

  // Response contains a new ID token, but user should have stayed the same.
  id_token_listener.ExpectChanges(1);
  auth_state_listener.ExpectChanges(0);

  const std::string new_email = "new_fake_email@example.com";

  EXPECT_NE(new_email, firebase_user_->email());

  EXPECT_TRUE(firebase_user_->is_anonymous());
  const Credential credential =
      EmailAuthProvider::GetCredential(new_email.c_str(), "fake_password");
  WaitForFuture(firebase_user_->LinkWithCredential(credential));
  EXPECT_EQ(new_email, firebase_user_->email());
  EXPECT_FALSE(firebase_user_->is_anonymous());
}

TEST_F(UserDesktopTest, TestLinkWithCredential_NeedsConfirmation) {
  InitializeConfigWithAFake(
      GetUrlForApi(API_KEY, "verifyAssertion"),
      FakeSuccessfulResponse("verifyAssertion", "\"needConfirmation\": true"));

  // If response contains needConfirmation, the whole operation should fail, and
  // current user should be unaffected.
  id_token_listener.ExpectChanges(0);
  auth_state_listener.ExpectChanges(0);

  const Credential credential =
      GoogleAuthProvider::GetCredential("fake_id_token", "");
  WaitForFuture(firebase_user_->LinkWithCredential(credential),
                kAuthErrorAccountExistsWithDifferentCredentials);
}

TEST_F(UserDesktopTest, TestLinkWithCredential_ChecksAlreadyLinkedProviders) {
  {
    FakeSetT fakes;
    fakes[GetUrlForApi(API_KEY, "verifyAssertion")] =
        FakeVerifyAssertionResponse();
    fakes[GetUrlForApi(API_KEY, "getAccountInfo")] = FakeSuccessfulResponse(
        // clang-format off
        "GetAccountInfoResponse",
        std::string(
            "\"users\":"
            "  ["
            "    {"
            "      \"localId\": \"localid123\",") +
            GetFakeProviderInfo("google.com") +
            "    }"
            " ]");
    // clang-format on
    InitializeConfigWithFakes(fakes);
  }

  // Upon linking, user should stay the same, but ID token should be updated.
  id_token_listener.ExpectChanges(1);
  auth_state_listener.ExpectChanges(0);

  const Credential google_credential =
      GoogleAuthProvider::GetCredential("fake_id_token", "");
  WaitForFuture(firebase_user_->LinkWithCredential(google_credential));

  // The same provider shouldn't be linked twice.
  WaitForFuture(firebase_user_->LinkWithCredential(google_credential),
                kAuthErrorProviderAlreadyLinked);

  id_token_listener.VerifyAndReset();
  auth_state_listener.VerifyAndReset();
  // Linking already linked provider, should fail, so current user shouldn't be
  // updated at all.
  id_token_listener.ExpectChanges(0);
  auth_state_listener.ExpectChanges(0);

  {
    FakeSetT fakes;
    fakes[GetUrlForApi(API_KEY, "verifyAssertion")] =
        FakeVerifyAssertionResponse();
    fakes[GetUrlForApi(API_KEY, "getAccountInfo")] =
        // clang-format off
        FakeSuccessfulResponse("GetAccountInfoResponse",
          std::string(
              "\"users\":"
              "  ["
              "    {"
              "       \"localId\": \"localid123\","
              "      \"providerUserInfo\": [") +
              GetSingleFakeProvider("google.com") + "," +
              GetSingleFakeProvider("facebook.com") +
              "      ]"
              "    }"
              " ]");
    // clang-format on
    InitializeConfigWithFakes(fakes);
  }

  // Should be able to link a different provider.
  const Credential facebook_credential =
      FacebookAuthProvider::GetCredential("fake_access_token");
  WaitForFuture(firebase_user_->LinkWithCredential(facebook_credential));

  // The same provider shouldn't be linked twice.
  WaitForFuture(firebase_user_->LinkWithCredential(facebook_credential),
                kAuthErrorProviderAlreadyLinked);
  // Check that the previously linked provider wasn't overridden.
  WaitForFuture(firebase_user_->LinkWithCredential(google_credential),
                kAuthErrorProviderAlreadyLinked);
}

TEST_F(UserDesktopTest, TestLinkWithCredentialAndRetrieveData) {
  InitializeSuccessfulVerifyAssertionFlow();

  // Upon linking, user should stay the same, but ID token should be updated.
  id_token_listener.ExpectChanges(1);
  auth_state_listener.ExpectChanges(0);

  const Credential credential =
      GoogleAuthProvider::GetCredential("fake_id_token", "");
  const SignInResult sign_in_result = WaitForFuture(
      firebase_user_->LinkAndRetrieveDataWithCredential(credential));
  EXPECT_FALSE(sign_in_result.user->is_anonymous());
  VerifyUser(*sign_in_result.user);
}

TEST_F(UserDesktopTest, TestReauthenticate) {
  InitializeSuccessfulVerifyAssertionFlow();

  // Upon reauthentication, user should have stayed the same, but ID token
  // should have changed.
  id_token_listener.ExpectChanges(1);
  auth_state_listener.ExpectChanges(0);

  const Credential credential =
      GoogleAuthProvider::GetCredential("fake_id_token", "");
  WaitForFuture(firebase_user_->Reauthenticate(credential));
}

TEST_F(UserDesktopTest, TestReauthenticate_NeedsConfirmation) {
  InitializeConfigWithAFake(
      GetUrlForApi(API_KEY, "verifyAssertion"),
      FakeSuccessfulResponse("verifyAssertion", "\"needConfirmation\": true"));

  // If response contains needConfirmation, the whole operation should fail, and
  // current user should be unaffected.
  id_token_listener.ExpectChanges(0);
  auth_state_listener.ExpectChanges(0);

  const Credential credential =
      GoogleAuthProvider::GetCredential("fake_id_token", "");
  WaitForFuture(firebase_user_->Reauthenticate(credential),
                kAuthErrorAccountExistsWithDifferentCredentials);
}

TEST_F(UserDesktopTest, TestReauthenticateAndRetrieveData) {
  InitializeSuccessfulVerifyAssertionFlow();

  // Upon reauthentication, user should have stayed the same, but ID token
  // should have changed.
  id_token_listener.ExpectChanges(1);
  auth_state_listener.ExpectChanges(0);

  const Credential credential =
      GoogleAuthProvider::GetCredential("fake_id_token", "");
  const SignInResult sign_in_result =
      WaitForFuture(firebase_user_->ReauthenticateAndRetrieveData(credential));
  EXPECT_FALSE(sign_in_result.user->is_anonymous());
  VerifyUser(*sign_in_result.user);
}

// Checks that current user is signed out upon receiving errors from the
// backend indicating the user is no longer valid.
class UserDesktopTestSignOutOnError : public UserDesktopTest {
 protected:
  // Reduces boilerplate in similar tests checking for sign out in several API
  // methods.
  template <typename OperationT>
  void CheckSignOutIfUserIsInvalid(const std::string& api_endpoint,
                                   const std::string& backend_error,
                                   const AuthError sdk_error,
                                   const OperationT operation) {
    // Receiving error from the backend should make the operation fail, and
    // current user shouldn't be affected.
    id_token_listener.ExpectChanges(0);
    auth_state_listener.ExpectChanges(0);

    // First check that sign out doesn't happen on just any error
    // (kAuthErrorOperationNotAllowed is chosen arbitrarily).
    InitializeConfigWithAFake(api_endpoint,
                              CreateErrorHttpResponse("OPERATION_NOT_ALLOWED"));
    EXPECT_FALSE(firebase_user_->uid().empty());
    WaitForFuture(operation(), kAuthErrorOperationNotAllowed);
    EXPECT_FALSE(firebase_user_->uid().empty());  // User is still signed in.

    id_token_listener.VerifyAndReset();
    auth_state_listener.VerifyAndReset();
    // Expect sign out.
    id_token_listener.ExpectChanges(1);
    auth_state_listener.ExpectChanges(1);

    // Now check that the user will be logged out upon receiving a certain
    // error from the backend.
    InitializeConfigWithAFake(api_endpoint,
                              CreateErrorHttpResponse(backend_error));
    WaitForFuture(operation(), sdk_error);
    EXPECT_THAT(firebase_user_->uid(), IsEmpty());
  }
};

TEST_F(UserDesktopTestSignOutOnError, Reauth) {
  CheckSignOutIfUserIsInvalid(
      GetUrlForApi(API_KEY, "verifyAssertion"), "USER_NOT_FOUND",
      kAuthErrorUserNotFound, [&] {
        sem_.Post();
        return firebase_user_->Reauthenticate(
            GoogleAuthProvider::GetCredential("fake_id_token", ""));
      });
  sem_.Wait();
}

TEST_F(UserDesktopTestSignOutOnError, Reload) {
  CheckSignOutIfUserIsInvalid(GetUrlForApi(API_KEY, "getAccountInfo"),
                              "USER_NOT_FOUND", kAuthErrorUserNotFound, [&] {
                                sem_.Post();
                                return firebase_user_->Reload();
                              });
  sem_.Wait();
}

TEST_F(UserDesktopTestSignOutOnError, UpdateEmail) {
  CheckSignOutIfUserIsInvalid(
      GetUrlForApi(API_KEY, "setAccountInfo"), "USER_NOT_FOUND",
      kAuthErrorUserNotFound, [&] {
        sem_.Post();
        return firebase_user_->UpdateEmail("fake_email@example.com");
      });
  sem_.Wait();
}

TEST_F(UserDesktopTestSignOutOnError, UpdatePassword) {
  CheckSignOutIfUserIsInvalid(
      GetUrlForApi(API_KEY, "setAccountInfo"), "USER_DISABLED",
      kAuthErrorUserDisabled, [&] {
        sem_.Post();
        return firebase_user_->UpdatePassword("fake_password");
      });
  sem_.Wait();
}

TEST_F(UserDesktopTestSignOutOnError, UpdateProfile) {
  CheckSignOutIfUserIsInvalid(
      GetUrlForApi(API_KEY, "setAccountInfo"), "TOKEN_EXPIRED",
      kAuthErrorUserTokenExpired, [&] {
        sem_.Post();
        return firebase_user_->UpdateUserProfile(User::UserProfile());
      });
  sem_.Wait();
}

TEST_F(UserDesktopTestSignOutOnError, Unlink) {
  InitializeConfigWithAFake(GetUrlForApi(API_KEY, "getAccountInfo"),
                            FakeGetAccountInfoResponse());
  WaitForFuture(firebase_user_->Reload());

  CheckSignOutIfUserIsInvalid(
      GetUrlForApi(API_KEY, "setAccountInfo"), "USER_NOT_FOUND",
      kAuthErrorUserNotFound, [&] {
        sem_.Post();
        return firebase_user_->Unlink("fake_provider_id");
      });
  sem_.Wait();
}

TEST_F(UserDesktopTestSignOutOnError, LinkWithEmail) {
  CheckSignOutIfUserIsInvalid(
      GetUrlForApi(API_KEY, "setAccountInfo"), "USER_NOT_FOUND",
      kAuthErrorUserNotFound, [&] {
        sem_.Post();
        return firebase_user_->LinkWithCredential(
            EmailAuthProvider::GetCredential("fake_email@example.com",
                                             "fake_password"));
      });
  sem_.Wait();
}

TEST_F(UserDesktopTestSignOutOnError, LinkWithOauthCredential) {
  CheckSignOutIfUserIsInvalid(
      GetUrlForApi(API_KEY, "verifyAssertion"), "USER_NOT_FOUND",
      kAuthErrorUserNotFound, [&] {
        sem_.Post();
        return firebase_user_->LinkWithCredential(
            GoogleAuthProvider::GetCredential("fake_id_token", ""));
      });
  sem_.Wait();
}

TEST_F(UserDesktopTestSignOutOnError, GetToken) {
  const auto api_url =
      std::string("https://securetoken.googleapis.com/v1/token?key=") + API_KEY;
  CheckSignOutIfUserIsInvalid(api_url, "USER_NOT_FOUND", kAuthErrorUserNotFound,
                              [&] {
                                sem_.Post();
                                return firebase_user_->GetToken(true);
                              });
  sem_.Wait();
}

// This test is to expose potential race condition and is primarily intended to
// be run with --config=tsan
TEST_F(UserDesktopTest, TestRaceCondition_SetAccountInfoAndSignOut) {
  InitializeConfigWithAFake(GetUrlForApi(API_KEY, "setAccountInfo"),
                            FakeSetAccountInfoResponse());

  // SignOut is engaged on the main thread, whereas UpdateEmail will be executed
  // on the background thread; consequently, the order in which they are
  // executed is not defined. Nevertheless, this should not lead to any data
  // corruption, when UpdateEmail writes to user profile while it's being
  // deleted by SignOut. Whichever method succeeds first, user must be signed
  // out once both are finished: if SignOut finishes last, it overrides the
  // updated user, and if UpdateEmail finishes last, it should note that there
  // is no currently signed in user and fail with kAuthErrorUserNotFound.

  auto future = firebase_user_->UpdateEmail("some_email");
  firebase_auth_->SignOut();
  while (future.status() == firebase::kFutureStatusPending) {
  }

  EXPECT_THAT(future.error(), AnyOf(kAuthErrorNone, kAuthErrorNoSignedInUser));
  EXPECT_EQ(nullptr, firebase_auth_->current_user());
}

// LinkWithProvider tests.
TEST_F(UserDesktopTest, TestLinkWithProviderReturnsUnsupportedError) {
  FederatedOAuthProvider provider;
  Future<SignInResult> future = firebase_user_->LinkWithProvider(&provider);
  EXPECT_EQ(future.result()->user, nullptr);
  EXPECT_EQ(future.error(), kAuthErrorUnimplemented);
  EXPECT_EQ(std::string(future.error_message()),
            "Operation is not supported on non-mobile systems.");
}

// TODO(drsanta) The following tests are disabled as the AuthHandler support has
// not yet been released.
TEST_F(UserDesktopTest,
       DISABLED_TestLinkWithProviderAndHandlerPassingIntegrityChecks) {
  FederatedOAuthProvider provider;
  test::OAuthProviderTestHandler handler(/*extra_integrity_checks_=*/true);
  InitializeSuccessfulAuthenticateWithProviderFlow(&provider, &handler);

  Future<SignInResult> future = firebase_user_->LinkWithProvider(&provider);
  handler.TriggerLinkComplete();
  SignInResult sign_in_result = WaitForFuture(future);
}

TEST_F(UserDesktopTest,
       DISABLED_TestPendingLinkWithProviderSecondConcurrentSignInFails) {
  FederatedOAuthProvider provider1;
  OAuthProviderTestHandler handler1;
  InitializeSuccessfulAuthenticateWithProviderFlow(&provider1, &handler1);

  FederatedOAuthProvider provider2;
  provider2.SetProviderData(GetFakeOAuthProviderData());

  OAuthProviderTestHandler handler2;
  provider2.SetAuthHandler(&handler2);
  Future<SignInResult> future1 = firebase_user_->LinkWithProvider(&provider1);
  EXPECT_EQ(future1.status(), kFutureStatusPending);
  Future<SignInResult> future2 = firebase_user_->LinkWithProvider(&provider2);
  VerifySignInResult(future2, kAuthErrorFederatedProviderAreadyInUse);
  handler1.TriggerLinkComplete();
  const SignInResult sign_in_result = WaitForFuture(future1);
}

TEST_F(UserDesktopTest, DISABLED_TestLinkWithProviderSignInResultUserPasses) {
  FederatedOAuthProvider provider;
  OAuthProviderTestHandler handler;
  FederatedAuthProvider::AuthenticatedUserData user_data =
      *(handler.GetAuthenticatedUserData());
  Future<SignInResult> future =
      ProcessLinkWithProviderFlow(&provider, &handler, /*trigger_link=*/true);
  SignInResult sign_in_result = WaitForFuture(future);
  EXPECT_NE(sign_in_result.user, nullptr);
  EXPECT_EQ(sign_in_result.user->is_email_verified(),
            user_data.is_email_verified);
  EXPECT_FALSE(sign_in_result.user->is_anonymous());
  EXPECT_EQ(sign_in_result.user->uid(), user_data.uid);
  EXPECT_EQ(sign_in_result.user->email(), user_data.email);
  EXPECT_EQ(sign_in_result.user->display_name(), user_data.display_name);
  EXPECT_EQ(sign_in_result.user->photo_url(), user_data.photo_url);
  EXPECT_EQ(sign_in_result.user->provider_id(), user_data.provider_id);
  VerifyProviderData(*sign_in_result.user);
}

TEST_F(UserDesktopTest, DISABLED_TestLinkCompleteNullUIDFails) {
  FederatedOAuthProvider provider;
  OAuthProviderTestHandler handler;
  handler.GetAuthenticatedUserData()->uid = nullptr;
  Future<SignInResult> future =
      ProcessLinkWithProviderFlow(&provider, &handler, /*trigger_link=*/true);
  VerifySignInResult(future, kAuthErrorInvalidAuthenticatedUserData);
}

TEST_F(UserDesktopTest, DISABLED_TestLinkCompleteNullDisplayNamePasses) {
  FederatedOAuthProvider provider;
  OAuthProviderTestHandler handler;
  handler.GetAuthenticatedUserData()->display_name = nullptr;
  Future<SignInResult> future =
      ProcessLinkWithProviderFlow(&provider, &handler, /*trigger_link=*/true);
  SignInResult sign_in_result = WaitForFuture(future);
  VerifyProviderData(*sign_in_result.user);
}

TEST_F(UserDesktopTest, DISABLED_TestLinkCompleteNullUsernamePasses) {
  FederatedOAuthProvider provider;
  OAuthProviderTestHandler handler;
  handler.GetAuthenticatedUserData()->user_name = nullptr;
  Future<SignInResult> future =
      ProcessLinkWithProviderFlow(&provider, &handler, /*trigger_link=*/true);
  SignInResult sign_in_result = WaitForFuture(future);
  VerifyProviderData(*sign_in_result.user);
}

TEST_F(UserDesktopTest, DISABLED_TestLinkCompleteNullPhotoUrlPasses) {
  FederatedOAuthProvider provider;
  OAuthProviderTestHandler handler;
  handler.GetAuthenticatedUserData()->photo_url = nullptr;
  Future<SignInResult> future =
      ProcessLinkWithProviderFlow(&provider, &handler, /*trigger_link=*/true);
  SignInResult sign_in_result = WaitForFuture(future);
  VerifyProviderData(*sign_in_result.user);
}

TEST_F(UserDesktopTest, DISABLED_TestLinkCompleteNullProvderIdFails) {
  FederatedOAuthProvider provider;
  OAuthProviderTestHandler handler;
  handler.GetAuthenticatedUserData()->provider_id = nullptr;
  Future<SignInResult> future =
      ProcessLinkWithProviderFlow(&provider, &handler, /*trigger_link=*/true);
  VerifySignInResult(future, kAuthErrorInvalidAuthenticatedUserData);
}

TEST_F(UserDesktopTest,
       DISABLED_TestLinkCompleteNuDISABLED_llAccessTokenFails) {
  FederatedOAuthProvider provider;
  OAuthProviderTestHandler handler;
  handler.GetAuthenticatedUserData()->access_token = nullptr;
  Future<SignInResult> future =
      ProcessLinkWithProviderFlow(&provider, &handler, /*trigger_link=*/true);
  VerifySignInResult(future, kAuthErrorInvalidAuthenticatedUserData);
}

TEST_F(UserDesktopTest, DISABLED_TestLinkCompleteNullRefreshTokenFails) {
  FederatedOAuthProvider provider;
  OAuthProviderTestHandler handler;
  handler.GetAuthenticatedUserData()->refresh_token = nullptr;
  Future<SignInResult> future =
      ProcessLinkWithProviderFlow(&provider, &handler, /*trigger_link=*/true);
  VerifySignInResult(future, kAuthErrorInvalidAuthenticatedUserData);
}

TEST_F(UserDesktopTest, DISABLED_TestLinkCompleteExpiresInMaxUInt64Passes) {
  FederatedOAuthProvider provider;
  OAuthProviderTestHandler handler;
  handler.GetAuthenticatedUserData()->token_expires_in_seconds = ULONG_MAX;
  Future<SignInResult> future =
      ProcessLinkWithProviderFlow(&provider, &handler, /*trigger_link=*/true);
  SignInResult sign_in_result = WaitForFuture(future);
  VerifyProviderData(*sign_in_result.user);
}

TEST_F(UserDesktopTest, DISABLED_TestLinkCompleteErrorMessagePasses) {
  FederatedOAuthProvider provider;
  OAuthProviderTestHandler handler;
  Future<SignInResult> future =
      ProcessLinkWithProviderFlow(&provider, &handler, /*trigger_link=*/false);
  const char* error_message = "oh nos!";
  handler.TriggerLinkCompleteWithError(kAuthErrorApiNotAvailable,
                                       error_message);
  VerifySignInResult(future, kAuthErrorApiNotAvailable, error_message);
}

TEST_F(UserDesktopTest, DISABLED_TestLinkCompleteNullErrorMessageFails) {
  FederatedOAuthProvider provider;
  OAuthProviderTestHandler handler;
  Future<SignInResult> future =
      ProcessLinkWithProviderFlow(&provider, &handler, /*trigger_link=*/false);
  handler.TriggerLinkCompleteWithError(kAuthErrorApiNotAvailable, nullptr);
  VerifySignInResult(future, kAuthErrorApiNotAvailable);
}

// ReauthenticateWithProvider tests.
TEST_F(UserDesktopTest, TestReauthentciateWithProviderReturnsUnsupportedError) {
  FederatedOAuthProvider provider;
  Future<SignInResult> future =
      firebase_user_->ReauthenticateWithProvider(&provider);
  EXPECT_EQ(future.result()->user, nullptr);
  EXPECT_EQ(future.error(), kAuthErrorUnimplemented);
  EXPECT_EQ(std::string(future.error_message()),
            "Operation is not supported on non-mobile systems.");
}

// TODO(drsanta) The following tests are disabled as the AuthHandler support has
// not yet been released.
TEST_F(
    UserDesktopTest,
    DISABLED_TestReauthenticateWithProviderAndHandlerPassingIntegrityChecks) {
  FederatedOAuthProvider provider;
  test::OAuthProviderTestHandler handler(/*extra_integrity_checks_=*/true);
  InitializeSuccessfulAuthenticateWithProviderFlow(&provider, &handler);

  Future<SignInResult> future =
      firebase_user_->ReauthenticateWithProvider(&provider);
  handler.TriggerReauthenticateComplete();
  SignInResult sign_in_result = WaitForFuture(future);
}

TEST_F(UserDesktopTest,
       DISABLED_TestReauthenticateWithProviderSecondConcurrentSignInFails) {
  FederatedOAuthProvider provider1;
  OAuthProviderTestHandler handler1;
  InitializeSuccessfulAuthenticateWithProviderFlow(&provider1, &handler1);

  FederatedOAuthProvider provider2;
  provider2.SetProviderData(GetFakeOAuthProviderData());

  OAuthProviderTestHandler handler2;
  provider2.SetAuthHandler(&handler2);
  Future<SignInResult> future1 =
      firebase_user_->ReauthenticateWithProvider(&provider1);
  EXPECT_EQ(future1.status(), kFutureStatusPending);
  Future<SignInResult> future2 =
      firebase_user_->ReauthenticateWithProvider(&provider2);
  VerifySignInResult(future2, kAuthErrorFederatedProviderAreadyInUse);
  handler1.TriggerReauthenticateComplete();
  const SignInResult sign_in_result = WaitForFuture(future1);
}

TEST_F(UserDesktopTest,
       DISABLED_TestReauthenticateWithProviderSignInResultUserPasses) {
  FederatedOAuthProvider provider;
  OAuthProviderTestHandler handler;
  FederatedAuthProvider::AuthenticatedUserData user_data =
      *(handler.GetAuthenticatedUserData());
  Future<SignInResult> future = ProcessReauthenticateWithProviderFlow(
      &provider, &handler, /*trigger_reauthenticate=*/true);
  SignInResult sign_in_result = WaitForFuture(future);
  EXPECT_NE(sign_in_result.user, nullptr);
  EXPECT_EQ(sign_in_result.user->is_email_verified(),
            user_data.is_email_verified);
  EXPECT_FALSE(sign_in_result.user->is_anonymous());
  EXPECT_EQ(sign_in_result.user->uid(), user_data.uid);
  EXPECT_EQ(sign_in_result.user->email(), user_data.email);
  EXPECT_EQ(sign_in_result.user->display_name(), user_data.display_name);
  EXPECT_EQ(sign_in_result.user->photo_url(), user_data.photo_url);
  EXPECT_EQ(sign_in_result.user->provider_id(), user_data.provider_id);
  VerifyProviderData(*sign_in_result.user);
}

TEST_F(UserDesktopTest, DISABLED_TestReauthenticateCompleteNullUIDFails) {
  FederatedOAuthProvider provider;
  OAuthProviderTestHandler handler;
  handler.GetAuthenticatedUserData()->uid = nullptr;
  Future<SignInResult> future = ProcessReauthenticateWithProviderFlow(
      &provider, &handler, /*trigger_reauthenticate=*/true);
  VerifySignInResult(future, kAuthErrorInvalidAuthenticatedUserData);
}

TEST_F(UserDesktopTest,
       DISABLED_TestReauthenticateCompleteNullDisplayNamePasses) {
  FederatedOAuthProvider provider;
  OAuthProviderTestHandler handler;
  handler.GetAuthenticatedUserData()->display_name = nullptr;
  Future<SignInResult> future = ProcessReauthenticateWithProviderFlow(
      &provider, &handler, /*trigger_reauthenticate=*/true);
  SignInResult sign_in_result = WaitForFuture(future);
  VerifyProviderData(*sign_in_result.user);
}

TEST_F(UserDesktopTest, DISABLED_TestReauthenticateCompleteNullUsernamePasses) {
  FederatedOAuthProvider provider;
  OAuthProviderTestHandler handler;
  handler.GetAuthenticatedUserData()->user_name = nullptr;
  Future<SignInResult> future = ProcessReauthenticateWithProviderFlow(
      &provider, &handler, /*trigger_reauthenticate=*/true);
  SignInResult sign_in_result = WaitForFuture(future);
  VerifyProviderData(*sign_in_result.user);
}

TEST_F(UserDesktopTest, DISABLED_TestReauthenticateCompleteNullPhotoUrlPasses) {
  FederatedOAuthProvider provider;
  OAuthProviderTestHandler handler;
  handler.GetAuthenticatedUserData()->photo_url = nullptr;
  Future<SignInResult> future = ProcessReauthenticateWithProviderFlow(
      &provider, &handler, /*trigger_reauthenticate=*/true);
  SignInResult sign_in_result = WaitForFuture(future);
  VerifyProviderData(*sign_in_result.user);
}

TEST_F(UserDesktopTest, DISABLED_TestReauthenticateCompleteNullProvderIdFails) {
  FederatedOAuthProvider provider;
  OAuthProviderTestHandler handler;
  handler.GetAuthenticatedUserData()->provider_id = nullptr;
  Future<SignInResult> future = ProcessReauthenticateWithProviderFlow(
      &provider, &handler, /*trigger_reauthenticate=*/true);
  VerifySignInResult(future, kAuthErrorInvalidAuthenticatedUserData);
}

TEST_F(UserDesktopTest,
       DISABLED_TestReauthenticateCompleteNullAccessTokenFails) {
  FederatedOAuthProvider provider;
  OAuthProviderTestHandler handler;
  handler.GetAuthenticatedUserData()->access_token = nullptr;
  Future<SignInResult> future = ProcessReauthenticateWithProviderFlow(
      &provider, &handler, /*trigger_reauthenticate=*/true);
  VerifySignInResult(future, kAuthErrorInvalidAuthenticatedUserData);
}

TEST_F(UserDesktopTest,
       DISABLED_TestReauthenticateCompleteNullRefreshTokenFails) {
  FederatedOAuthProvider provider;
  OAuthProviderTestHandler handler;
  handler.GetAuthenticatedUserData()->refresh_token = nullptr;
  Future<SignInResult> future = ProcessReauthenticateWithProviderFlow(
      &provider, &handler, /*trigger_reauthenticate=*/true);
  VerifySignInResult(future, kAuthErrorInvalidAuthenticatedUserData);
}

TEST_F(UserDesktopTest,
       DISABLED_TestReauthenticateCompleteExpiresInMaxUInt64Passes) {
  FederatedOAuthProvider provider;
  OAuthProviderTestHandler handler;
  handler.GetAuthenticatedUserData()->token_expires_in_seconds = ULONG_MAX;
  Future<SignInResult> future = ProcessReauthenticateWithProviderFlow(
      &provider, &handler, /*trigger_reauthenticate=*/true);
  SignInResult sign_in_result = WaitForFuture(future);
  VerifyProviderData(*sign_in_result.user);
}

TEST_F(UserDesktopTest, DISABLED_TestReauthenticateCompleteErrorMessagePasses) {
  FederatedOAuthProvider provider;
  OAuthProviderTestHandler handler;
  Future<SignInResult> future = ProcessReauthenticateWithProviderFlow(
      &provider, &handler, /*trigger_reauthenticate=*/false);
  const char* error_message = "oh nos!";
  handler.TriggerReauthenticateCompleteWithError(kAuthErrorApiNotAvailable,
                                                 error_message);
  VerifySignInResult(future, kAuthErrorApiNotAvailable, error_message);
}

TEST_F(UserDesktopTest,
       DISABLED_TestReauthenticateCompleteNullErrorMessageFails) {
  FederatedOAuthProvider provider;
  OAuthProviderTestHandler handler;
  Future<SignInResult> future = ProcessReauthenticateWithProviderFlow(
      &provider, &handler, /*trigger_reauthenticate=*/false);
  handler.TriggerReauthenticateCompleteWithError(kAuthErrorApiNotAvailable,
                                                 nullptr);
  VerifySignInResult(future, kAuthErrorApiNotAvailable);
}

}  // namespace auth
}  // namespace firebase


text:
import requests
import time
import random
from bs4 import BeautifulSoup
import sys, os

def fetch(url,delay=(1,3)):
    """
    Simulate human random clicking x..y seconds then fetch URL.
    Returns the actual page source fetched and the HTML object.
    """
    time.sleep(random.randint(delay[0],delay[1])) # wait random seconds
    try:
        response = requests.get(url, headers={'User-Agent': "Resistance is futile"})
    except ValueError as e:
        print(str(e))
        return '', BeautifulSoup('', "html.parser")
    html = response.text
    soup = BeautifulSoup(html, "html.parser")
    return (html,soup)

def crawl(links, outputdir):
    i = 0
    for link in links:
        page,html = fetch(link,delay=(0,0)) # no need to delay; pulling from random sites
        filename = f"page{i}.html"
        i += 1
        print("Writing {filename}")
        with open(os.path.join(outputdir,filename), "w") as f:
            f.write(page)

def parseHN():
    page,html = fetch("https://news.ycombinator.com/newest")
    links = []
    for link in html.find_all(class_="storylink"):
        links.append(link['href'])

    return links

outputdir = sys.argv[1]
if not os.path.exists(outputdir):
    os.makedirs(outputdir)

links = parseHN()
print(links)
crawl(links, outputdir)

redpajama_set_name: RedPajamaGithub


text:
MongoDB\BSON\Decimal128 requires valid decimal string
--SKIPIF--
<?php if (!class_exists('MongoDB\BSON\Decimal128')) { die('skip MongoDB\BSON\Decimal128 is not available'); } ?>
--FILE--
<?php

require_once __DIR__ . '/../utils/tools.php';

echo throws(function() {
    new MongoDB\BSON\Decimal128([]);
}, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n";

?>
===DONE===
<?php exit(0); ?>
--EXPECT--
OK: Got MongoDB\Driver\Exception\InvalidArgumentException
MongoDB\BSON\Decimal128::__construct() expects parameter 1 to be string, array given
===DONE===


text:
ACCEPTED

#### According to
Index Fungorum

#### Published in
Novitates Mycologicae Novissimae 32 (1947)

#### Original name
Pseudomycena rosella Velen.

### Remarks
null


text:
package com.exponent.androidopacitydemo;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;

import java.util.concurrent.Semaphore;

/**
 * Dialog fragment for obtaining numeric input from the user.
 * The dialog is implemented as a modal dialog.
 */
public class GetNumericInputDialogFragment extends DialogFragment
{
	private String input;
	private final Semaphore dialogSemaphore = new Semaphore(0, true);

	public static GetNumericInputDialogFragment create(String title)
	{
		GetNumericInputDialogFragment frag = new GetNumericInputDialogFragment();
		Bundle args = new Bundle();
		args.putCharSequence("title", title);
		frag.setArguments(args);
		return frag;
	}

	@Override
	public Dialog onCreateDialog(Bundle savedInstanceState)
	{
		AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());

		//noinspection ConstantConditions
		builder.setTitle(getArguments().get("title").toString());
		builder.setCancelable(false);
		LayoutInflater inflater = getActivity().getLayoutInflater();
		final View dialogLayout = inflater.inflate(R.layout.dialog_get_numeric_input, null);
		builder.setView(dialogLayout);
		builder.setPositiveButton("OK", new DialogInterface.OnClickListener()
		{
			@Override
			public void onClick(DialogInterface dialog, int id)
			{
				TextView tv = (TextView) dialogLayout.findViewById(R.id.numericPassword);
				input = tv.getText().toString();
				dialogSemaphore.release();
			}
		});

		Dialog dialog = builder.create();
		dialog.setCancelable(false);
		dialog.setCanceledOnTouchOutside(false);
		return dialog;
	}

	/**
	 * Displays the modal dialog and returns the characters entered by the user.
	 */
	public String showDialog(Activity activity)
	{
		show(activity.getFragmentManager(),"numericPassword");

		try
		{
			dialogSemaphore.acquire();
		}
		catch (InterruptedException ex)
		{
			//ignore
		}

		return input;
	}

}


text:
var template = require('./template.marko');

exports.renderer = function(input, out) {
  console.log('ui-button', input);
  if (!input.fieldWrap && input.field)
    input.fieldWrap = input.field !== '';
  input.type = input.type || 'button';
  input.btn = true;
  if (typeof input.icon === 'string') {
    input.icon = {
      name: input.icon
    };
  }
  console.log('ui-button ready', input);
  template.render(input, out);
};


text:
var PluginInstance = require(__core + "PluginInstance.js");

var admin = new PluginInstance();

admin.init = function() {
    this.plug = this.manager.getPlugin("plug").plug; //TODO: implement better method

    admin.loadDir(__dirname+"/cmds");
};

module.exports = admin;


text:
<?php //-->

/**
 * Definition for overriding classes.
 * This class also provides methods to list out various routes
 *
 * @package    Eden
 * @category   core
 * @author     Christian Blanquera cblanquera@openovate.com
 */
class eden_route_function extends Eden_Class
{
    /* Constants
    -------------------------------*/
    /* Public Properties
    -------------------------------*/
    /* Protected Properties
    -------------------------------*/
    protected static $_instance = NULL;
    protected $_route = array();	//class registry

    /* Private Properties
    -------------------------------*/
    /* Get
    -------------------------------*/
    public static function i()
    {
        $class = __CLASS__;
        if (is_null(self::$_instance)) {
            self::$_instance = new $class();
        }

        return self::$_instance;
    }

    /* Magic
    -------------------------------*/
    /* Public Methods
    -------------------------------*/
    /**
     * Calls a function considering all routes.
     *
     * @param *string class
     * @param [variable..] arguments
     * @return object
     */
    public function call($function)
    {
        //argument 1 must be a string
        Eden_Route_Error::i()->argument(1, 'string');

        $args = func_get_args();
        $function = array_shift($args);

        return $this->callArray($function, $args);
    }

    /**
     * Calls a function considering all routes.
     *
     * @param *string class
     * @param array arguments
     * @return object
     */
    public function callArray($function, array $args = array())
    {
        //argument 1 must be a string
        Eden_Route_Error::i()->argument(1, 'string');

        $function = $this->getRoute($function);

        //try to run the function using PHP call_user_func_array
        return call_user_func_array($function, $args);
    }

    /**
     * Returns the class that will be routed to given the route.
     *
     * @param *string the class route name
     * @param string|null returns this variable if no route is found
     * @return string|variable
     */
    public function getRoute($route)
    {
        //argument 1 must be a string
        Eden_Route_Error::i()->argument(1, 'string');

        if ($this->isRoute($route)) {
            return $this->_route[strtolower($route)];
        }

        return $route;
    }

    /**
     * Returns all class routes
     *
     * @return array
     */
    public function getRoutes()
    {
        return $this->_route;
    }

    /**
     * Checks to see if a name is a route
     *
     * @param string
     * @return bool
     */
    public function isRoute($route)
    {
        return isset($this->_route[strtolower($route)]);
    }

    /**
     * Unsets the route
     *
     * @param *string the class route name
     * @return string|variable
     */
    public function release($route)
    {
        if ($this->isRoute($route)) {
            unset($this->_route[strtolower($route)]);
        }

        return $this;
    }

    /**
     * Routes a class
     *
     * @param *string the class route name
     * @param *string the name of the class to route to
     * @return Eden_Route
     */
    public function route($route, $function)
    {
        Eden_Route_Error::i()
            ->argument(1, 'string')		//argument 1 must be a string
            ->argument(2, 'string');	//argument 2 must be a string

        $function = $this->getRoute($function);

        $this->_route[strtolower($route)] = $function;

        return $this;
    }

    /* Protected Methods
    -------------------------------*/
    /* Private Methods
    -------------------------------*/
}


text:
package com.francetelecom.clara.cloud.mvn.consumer;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.francetelecom.clara.cloud.commons.MavenReference;

@ContextConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
public class MvnRepoDaoImplIT
{

	private static Logger logger = LoggerFactory.getLogger(MvnRepoDaoImplIT.class.getName());

	@Autowired
	private MvnRepoDao mvnRepoDao;

	@Autowired
	@Qualifier("systemTestAppsVersion")
	private String systemTestAppsVersion;

	@BeforeClass
	public static void setup() throws MalformedURLException {
		logger.info("MvnRepoDaoImplIT setup...");

		File basedir = new File(System.getProperty("basedir", "")).getAbsoluteFile();
		System.setProperty("build.dir", new File(basedir, "target").toURI().toURL().toExternalForm());
	}

	public void should_create_a_maven_ref_representing_Springoo700SnapshotUrl() {
		/*
		 * <dependency>
		 * <groupId>com.francetelecom.clara.prototype.springoojpa</groupId>
		 * <artifactId>springoojpa-ear</artifactId>
		 * <version>7.0.0-SNAPSHOT</version> <classifier>mysql</classifier>
		 * <type>ear</type> </dependency>
		 */

		MavenReference ear = new MavenReference("com.francetelecom.clara.prototype.springoojpa", "springoojpa-ear", "7.0.0-SNAPSHOT", "ear", "mysql");
		assertNotNull(ear);
	}

	static void assertValidMavenRef(MvnRepoDao mvnRepoDao, String systemTestAppsVersion) {
		MavenReference mavenReference = new MavenReference("com.orange.clara.cloud.probes", "out-of-order-probe", systemTestAppsVersion, "jar");
        File f = mvnRepoDao.getFileFromLocalRepository(mavenReference);
        logger.info("testGeFile - mavenRef:" + mavenReference + " file:" + f);
        assertNotNull(f);
    }

	@Test
	public void should_get_out_of_order_probe_using_system_test_apps_version_from_local_repository() {
        assertValidMavenRef(mvnRepoDao, systemTestAppsVersion);
	}

	@Test(expected = MavenReferenceResolutionException.class)
	public void should_fail_to_get_an_invalid_maven_ref_from_local() {
		MavenReference mavenReference = new MavenReference("group", "artifact", "version", "ear");
		File f = mvnRepoDao.getFileFromLocalRepository(mavenReference);
		assertNotNull(f);
	}

	@Test
	@Ignore("no repository available to test deployment")
	public void should_deploy_dummy_TarGz_on_Maven2_and_check_availability_on_paas_proxy() {
		//if this test fail then synchronisation between maven2 and paas doesn't work properly
        MavenReference gav = new MavenReference("com.francetelecom.clara.cloud.dummy", "new-dummy-tar-gz", "1.0-SNAPSHOT", "tar.gz");

		ArrayList<FileRef> fileSet = new ArrayList<FileRef>();
		fileSet.add(new FileRef("install.sh", "<the content of my script file/>"));
		fileSet.add(new FileRef("package.bin", "<the content of my bin file/>"));

		assertNull(gav.getAccessUrl());
		mvnRepoDao.deployFileset(gav, fileSet);
		URL accessUrl = gav.getAccessUrl();
		logger.debug("Access url: " + accessUrl);
		assertNotNull(accessUrl);
		try {
			accessUrl.openStream();
		} catch (IOException e) {
			fail("Invalid URL" + e.getLocalizedMessage());
		}
	}

	@Test
	@Ignore("no repository available to test deployment")
	public void should_deploy_dummy_Rar_on_Maven2_and_check_availability_on_paas_proxy() {
        //if this test fail then synchronisation between maven2 and paas doesn't work properly

		MavenReference gav = new MavenReference("com.francetelecom.clara.cloud.dummy", "dummy-rar", "1.1-SNAPSHOT", "rar");

		ArrayList<FileRef> fileSet = new ArrayList<FileRef>();
		fileSet.add(new FileRef("META-INF/ra.xml", "<the content of my ra xml file/>"));
		fileSet.add(new FileRef("META-INF/jonas-ra.xml", "<the content of my jonas xml file/>"));

		assertNull(gav.getAccessUrl());
		mvnRepoDao.deployFileset(gav, fileSet);
		URL accessUrl = gav.getAccessUrl();
		logger.debug("Access url: " + accessUrl);
		assertNotNull(accessUrl);
		try {
			accessUrl.openStream();
		} catch (IOException e) {
			fail("Invalid URL" + e.getLocalizedMessage());
		}
	}

}


text:
``shell`` is the default processor on *nix systems (e.g. Linux). The code is interpreted as a shell script which stops at
the first error.

### bat
``bat`` is the default processor on windows. The code is interpreted as a batch script which stops at the first error.

### python
The ``python`` processor runs the code as a python 2.7 script

### SQLite
The ``sqlite`` processor is valid only if all input and output resources are ``sqlite://`` resources from the same
database file. The processor will run the sql code inside that database.

### PostgreSQL
The ``postgresql`` processor is valid only if all input and output resources are ``pg://`` resources from the same
database file. The processor will run the sql code inside that database.

### download
The ``download`` processor is valid only if it has one ``http://``, ``https://`` or ``ftp;//resource`` as input and one ``file://``
resource as output. The processor will download the resource and save it in the file.

### csv2sqlite
The ``csv2sqlite`` processor is valid only if it has one ``file://`` resource as input and ``sqlite://`` resource as
output. If the file is a valid CSV file, the processor will load it inside the ouput table, using the first line of
 the csv file as column names.

### Future plans
The official list of requested processors is available as [github issues](https://github.com/lexman/tuttle/issues?q=is%3Aopen+is%3Aissue+label%3Aprocessor)

NB : A lot of other magic transfer processor, like download and csv2sqlite are planned for the future

Writing your own processor is easy if you know the python language. So consider contributing... Pull requests are
welcome !


text:
@implementation DLChartValueFormatter

- (NSString * _Nonnull)stringForValue:(double)value axis:(ChartAxisBase * _Nullable)axis {
    NSUInteger num = (int )value / _spaceForX;
    return (_names[num]);
}

@end


text:
package com.diamondq.common.tracing.opentracing.testhelpers;

import org.junit.Assert;

import io.opentracing.mock.MockTracer;
import io.opentracing.util.GlobalTracer;

public class TracingAssertions {

  /**
   * Asserts that there is no active span
   *
   * @param pMessage the identifying message for the {@link AssertionError} (null okay)
   */
  public static void assertNoActiveSpan(String pMessage) {
    Assert.assertNull(pMessage, GlobalTracer.get().activeSpan());
  }

  /**
   * Asserts that there is an active span
   *
   * @param pMessage the identifying message for the {@link AssertionError} (null okay)
   */
  public static void assertActiveSpan(String pMessage) {
    Assert.assertNotNull(pMessage, GlobalTracer.get().activeSpan());
  }

  public static void assertCompletedSpans(String pMessage, int pExpected, MockTracer pTracker) {
    Assert.assertEquals(pMessage, pExpected, pTracker.finishedSpans().size());
  }
}


text:
package org.pdfserv;

import javax.ws.rs.ApplicationPath;

import org.glassfish.jersey.server.ResourceConfig;
import org.springframework.stereotype.Component;

@Component
@ApplicationPath("/services")
public class JerseyConfig extends ResourceConfig {

    public JerseyConfig() {
        register(DocumentResource.class);
    }

}


text:
package trans;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.TimeZone;
import org.apache.avro.specific.SpecificRecordBase;
import org.torproject.descriptor.Descriptor;
import org.torproject.descriptor.DescriptorFile;

/**
 * Provides fields and methods that all types of converters need
 * @param <C>   type of incoming descriptor
 */
abstract class Convert<C> {

  /**
   * Details about type: name, schema, avro schema class etc
   */
  Types type;

  /**
   * Month of creation of original descriptor, as YYYY_MM
   */
  String date;

  /**
   * Avro object, containing the converted descriptor
   */
  SpecificRecordBase load;

  /**
   * Abstract convert method
   * @param descriptor   incoming descriptor
   */
  abstract void convert(Descriptor descriptor, Long srcDate);

  /**
   * Check for unrecognized attributes
   */
  void checkUnrecognized(Descriptor descriptor, DescriptorFile descriptorFile) {
    if (!descriptor.getUnrecognizedLines().isEmpty()) {
      if (Args.INSTANCE.isLog()) {
        Base.logger.warning(
          "Unrecognized lines in " + descriptorFile.getFileName() + ":\n" +
          descriptor.getUnrecognizedLines()
        );
      }
      else {
        System.err.println("Unrecognized lines in "
            + descriptorFile.getFileName() + ":");
        System.err.println(descriptor.getUnrecognizedLines());
      }
    }
  }

  /**
   * Date-time formatter
   */
  static final String dateTimePattern = "yyyy-MM-dd HH:mm:ss";
  static final Locale dateTimeLocale = Locale.US;
  static final TimeZone dateTimezone = TimeZone.getTimeZone("UTC");
  static DateFormat dateTimeFormat;
  static {
    dateTimeFormat = new SimpleDateFormat(dateTimePattern, dateTimeLocale);
    dateTimeFormat.setLenient(false);
    dateTimeFormat.setTimeZone(dateTimezone);
  }

  /**
   * Derive accepted ports
   */
  String acceptedPortIntervals(String policy, String ports)
      throws NullPointerException {

    /**
     * incoming policy - accept or reject
     */
    Boolean policyIsAccept = "accept".equals(policy);

    /**
     * incoming port intervals as array
     */
    String[] incomingIntervals = ports.split(",");

    /**
     * outgoing string containing all accepted ports
     */
    String accepted = "";

    /* derive array of accepted port intervals */
    List<int[]> intervalsArrays = new ArrayList<>();
    int lastToPort = 0;
    for (String incomingInterval : incomingIntervals) {
      String[] incomingIntervalPorts = incomingInterval.split("-");
      int fromPort = Integer.parseInt(incomingIntervalPorts[0]);
      int toPort = ( incomingIntervalPorts.length == 1
              ? fromPort
              : Integer.parseInt(incomingIntervalPorts[1])
      );
      if (policyIsAccept) {
        intervalsArrays.add(new int[] { fromPort, toPort });
      } else if (fromPort > lastToPort + 1) {
        intervalsArrays.add(new int[] { lastToPort + 1, fromPort - 1 });
      }
      lastToPort = toPort;
    }
    if (!policyIsAccept && lastToPort < 65535) {
      intervalsArrays.add(new int[] { lastToPort + 1, 65535 });
    }

    /* write array of accepted port intervals to string */
    int writtenIntervals = 0;
    for (int[] interval : intervalsArrays) {
      accepted = accepted + (writtenIntervals++ > 0 ? "," : "") + interval[0];
      if (interval[1] > interval[0]) {
        accepted = accepted + "-" + interval[1];
      }
    }

    return accepted;
  }

}


text:
<?xml version="1.0" ?>
<tei>
	<teiHeader>
		<fileDesc xml:id="55005197"/>
	</teiHeader>
	<text xml:lang="en">
		<front>
			<lb/>
			<reference>JOURNAL OF PARALLEL AND DISTRIBUTED COMPUTING 48, 71–95
				(1998)<lb/></reference>
			<idno>ARTICLE NO. PC971403<lb/></idno>
			<docTitle>
				<titlePart>A Parallel Algorithm for Multilevel Graph<lb/> Partitioning and Sparse
					Matrix Ordering 1<lb/></titlePart>
			</docTitle>
			<byline>
				<docAuthor>George Karypis 2 and Vipin Kumar 3<lb/></docAuthor>
			</byline>
			<byline>
				<affiliation>Department of Computer Science/Army HPC Research Center,
					University<lb/> of Minnesota,</affiliation>
			</byline>
			<address>Minneapolis, Minnesota 55455<lb/></address>
			<div type="abstract">In this paper we present a parallel formulation of the multilevel
				graph<lb/> partitioning and sparse matrix ordering algorithm. A key feature of our
				parallel<lb/> formulation (that distinguishes it from other proposed parallel
				formulations of<lb/> multilevel algorithms) is that it partitions the vertices of
				the graph into<lb/> √ p parts<lb/> while distributing the overall adjacency matrix
				of the graph among all p processors.<lb/> This mapping results in substantially
				smaller communication than one-dimensional<lb/> distribution for graphs with
				relatively high degree, especially if the graph is<lb/> randomly distributed among
				the processors. We also present a parallel algorithm<lb/> for computing a minimal
				cover of a bipartite graph which is a key operation for<lb/> obtaining a small
				vertex separator that is useful for computing the fill reducing<lb/> ordering of
				sparse matrices. Our parallel algorithm achieves a speedup of up to<lb/> 56 on 128
				processors for moderate size problems, further reducing the already<lb/> moderate
				serial run time of multilevel schemes. Furthermore, the quality of the<lb/> produced
				partitions and orderings are comparable to those produced by the serial<lb/>
				multilevel algorithm that has been shown to outperform both spectral
				partitioning<lb/> and multiple minimum degree. </div>
			<space dim="horizontal"/>
			<note type="copyright">© 1998 Academic Press<lb/></note>
			<keywords>Key Words: parallel graph partitioning; multilevel partitioning methods;
				fill<lb/> reducing ordering; numerical linear algebra.<lb/>
			</keywords>
			<note type="grant">1<lb/> This work was supported by NSF CCR-9423082, by the Army
				Research Office Contract DA/DAAH04-95-<lb/> 1-0538, by the IBM Partnership Award,
				and by Army High Performance Computing Research Center under the<lb/> auspices of
				the Department of the Army, Army Research Laboratory Cooperative Agreement Number
				DAAH04-<lb/> 95-2-0003/Contract DAAH04-95-C-0008, the content of which does not
				necessarily reflect the position or the<lb/> policy of the government, and no
				official endorsement should be inferred. Access to computing facilities<lb/> was
				provided by AHPCRC. Minnesota Supercomputer Institute, Cray Research Inc., and by
				the Pittsburgh<lb/> Supercomputing Center.</note>
			<note type="other">Related papers are available via WWW at</note>

			<ptr type="web">URL: http://www.cs.umn.edu/ ∼ karypis.<lb/></ptr>>

			<email> 2<lb/> E-mail:
				karypis@cs.umn.edu.<lb/>
			</email>

			<email> 3<lb/> E-mail: kumar@cs.umn.edu.<lb/>
			</email>

			<note type="other">71<lb/></note>

			<note type="other">0743-7315/98$25.00<lb/></note>

			<note type="copyright">Copyright © 1998 by Academic Press<lb/> All rights of
				reproduction in any form reserved.<lb/></note>
		</front>
	</text>
</tei>


text:
using System;
using VSTOContrib.Core.RibbonFactory.Interfaces;

namespace VSTOContrib.Core
{
    /// <summary>
    /// Creates instances of view models using Activator.CreateInstance (viewmodels need a default constructor
    /// </summary>
    public class DefaultViewModelFactory : IViewModelFactory
    {
        /// <summary>
        /// Builds the requested viewmodel type
        /// </summary>
        /// <param name="viewModelType"></param>
        /// <returns></returns>
        public IRibbonViewModel Resolve(Type viewModelType)
        {
            return (IRibbonViewModel) Activator.CreateInstance(viewModelType);
        }

        /// <summary>
        /// Releases the viewmodel instance and gives the factory the chance to clean up any related services
        /// </summary>
        /// <param name="viewModelInstance"></param>
        public void Release(IRibbonViewModel viewModelInstance)
        {
            // ReSharper disable once SuspiciousTypeConversion.Global
            var disposable = viewModelInstance as IDisposable;
            if (disposable != null)
                disposable.Dispose();
        }
    }
}


text:
package com.athena.meerkat.agent.monitoring.websocket;

import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.messaging.Message;
import org.springframework.messaging.simp.stomp.StompCommand;
import org.springframework.messaging.simp.stomp.StompDecoder;
import org.springframework.messaging.simp.stomp.StompEncoder;
import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import com.athena.meerkat.agent.MeerkatAgentConstants;
import com.athena.meerkat.agent.monitoring.jobs.ServerInitialMonTask;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;

/**
 *

 *
 *

 * @author Bongjin Kwon
 * @version 1.0
 */
public class StompWebSocketHandler extends TextWebSocketHandler {

	private static final Logger LOGGER = LoggerFactory.getLogger(StompWebSocketHandler.class);

	public static final byte[] EMPTY_PAYLOAD = new byte[0];
	private static final Charset UTF_8 = Charset.forName("UTF-8");

	private final StompEncoder encoder = new StompEncoder();
	private final StompDecoder decoder = new StompDecoder();

	private ObjectMapper mapper = new ObjectMapper();

	private ArrayNode instanceConfigs;//DomainTomcatConfiguration array

	private TextMessage subscribeMsg;

	private StompWebSocketClient webSocketClient;

	/**
	 *

	 *
	 *

	 */
	public StompWebSocketHandler(String subscriptionId, StompWebSocketClient webSocketClient, String topic) {
		subscribeMsg = StompTextMessageBuilder.create(StompCommand.SUBSCRIBE).headers("id:" + subscriptionId, "destination:" + topic).build();
		this.webSocketClient = webSocketClient;
	}

	@Override
	public void afterConnectionEstablished(WebSocketSession session) throws Exception {

		LOGGER.debug("Connection estableshed!!.");

		sendSubscription(session);

	}

	private void sendSubscription(WebSocketSession session) throws Exception  {

		session.sendMessage(subscribeMsg);
		/*
		StompHeaderAccessor subheaders = StompHeaderAccessor.create(StompCommand.SUBSCRIBE);
		subheaders.setSubscriptionId("sub-0");
		subheaders.setDestination("/topic/greetings");

		StompEncoder encoder = new StompEncoder();
		byte[] bytes = encoder.encode(MessageBuilder.withPayload(EMPTY_PAYLOAD).setHeaders(subheaders).build());
		session.sendMessage(new TextMessage(new String(bytes, UTF_8)));
		*/
		LOGGER.debug(">>> SUBSCRIBE: {}", getHeader(subscribeMsg).getDestination());
	}

	protected StompHeaderAccessor getHeader(TextMessage message) {
		ByteBuffer payload = ByteBuffer.wrap(message.getPayload().getBytes(UTF_8));
		List<Message<byte[]>> messages = this.decoder.decode(payload);

		return StompHeaderAccessor.wrap(messages.get(0));
	}

	@Override
	protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
		LOGGER.debug("<<<<<: {}", message.getPayload());

		ByteBuffer payload = ByteBuffer.wrap(message.getPayload().getBytes(UTF_8));
		List<Message<byte[]>> messages = this.decoder.decode(payload);

		for (Message<byte[]> msg : messages) {
			StompHeaderAccessor headers = StompHeaderAccessor.wrap(msg);

			if (StompCommand.CONNECTED.equals(headers.getCommand())) {

				LOGGER.info("<< Connected!!");

			} else if (StompCommand.MESSAGE.equals(headers.getCommand())) {

				String content = new String(msg.getPayload());

				JsonNode node = mapper.readTree(content);
				JsonNode dataNode = node.get("data"); // data of SimpleJsonResponse

				if (dataNode instanceof ArrayNode) {
					instanceConfigs = (ArrayNode)dataNode;
					ServerInitialMonTask.ENABLE_MNITORING = true;
					LOGGER.debug("MESSAGE instance size : {}", instanceConfigs.size());

				} else if (dataNode instanceof ObjectNode) {
					ObjectNode cmdObj = (ObjectNode)dataNode;

					JsonNode cmd = cmdObj.get("cmd");

					if (cmd == null) {
						LOGGER.warn("###### cmd is null.");
					}

					if ("add_tomcat_instnace".equals(cmd.asText())) {

						//see MonJmxService.requestTomcatInstanceAdding(..)
						LOGGER.info("cmd is 'add_tomcat_instnace'");

						addInstanceConfig(cmdObj);
					} else if ("remove_tomcat_instnace".equals(cmd.asText())) {
						LOGGER.info("cmd is 'remove_tomcat_instnace'");

						removeInstanceConfig(cmdObj);
					}
				}

				//this.stompMessageHandler.handleMessage(message);
			} else if (StompCommand.RECEIPT.equals(headers.getCommand())) {

				LOGGER.debug("RECEIPT!!");

				//this.stompMessageHandler.handleReceipt(headers.getReceiptId());
			} else if (StompCommand.ERROR.equals(headers.getCommand())) {

				LOGGER.debug("ERROR!!");

				//this.stompMessageHandler.handleError(message);
			} else {
				LOGGER.debug("Unhandled message " + message);
			}
		}

	}

	@Override
	public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
		LOGGER.debug("Connection closed!!");
		this.webSocketClient.connect();
	}

	public synchronized ArrayNode getInstanceConfigs() {
		return instanceConfigs;
	}

	private synchronized void addInstanceConfig(ObjectNode cmdObj){

		ObjectNode instanceConfig = (ObjectNode)cmdObj.get("tomcatInstanceConfig");

		this.instanceConfigs.add(instanceConfig);

		LOGGER.info("## added tomcatInstanceId : {}", instanceConfig.get(MeerkatAgentConstants.JSON_KEY_TOMCAT_INSTANCE_ID).asText());
	}

	public synchronized void removeInstanceConfig(ObjectNode cmdObj){
		int removalInstanceId = cmdObj.get("tomcatInstanceId").asInt();
		removeInstanceConfig(removalInstanceId);
	}

	private void removeInstanceConfig(int removalInstanceId){
		boolean removed = false;
		for (Iterator<JsonNode> iterator = this.instanceConfigs.elements(); iterator.hasNext();) {
			JsonNode instanceConfig = iterator.next();

			int tomcatInstanceId = instanceConfig.get(MeerkatAgentConstants.JSON_KEY_TOMCAT_INSTANCE_ID).asInt();

			if (removalInstanceId == tomcatInstanceId) {
				iterator.remove();
				removed = true;
				LOGGER.info("## removed tomcatInstanceId : {}", removalInstanceId);
				break;
			}
		}

		if(removed == false) {
			LOGGER.warn("## remove fail. not found tomcatInstanceId : {}", removalInstanceId);
		}
	}

}
//end of AgentWebSocketHandler.java


text:
<?php

namespace GCNAF\NAFBundle\Controller;

use Symfony\Component\HttpFoundation\Request;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpFoundation\Session\Session;

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;

use GCNAF\NAFBundle\Entity\Taches;
use GCNAF\NAFBundle\Entity\ProjetChef;
use GCNAF\NAFBundle\Entity\Ressource;
use GCNAF\NAFBundle\Form\TachesType;

/**
 * Taches controller.
 *
 * @Route("/naf")
 */
class TachesController extends Controller
{

    /**
     * Lists all Taches entities.
     *
     * @Route("/", name="naf")
     * @Method("GET")
     * @Template()
     */
    public function indexAction()
    {
        $em = $this->getDoctrine()->getManager();
		$myq = $em->createQueryBuilder();
		$myq->select('t.id as IDtache,t.libelle,t.dated,t.datef,t.projet,p.id,p.projet')
			->from('GCNAFNAFBundle:Taches', 't')
			->from('GCNAFNAFBundle:ProjetChef', 'p')
			->where('t.projet = p.id')
			->orderBy('t.dated', 'DESC');
		$resu = $myq->getQuery();
		$entities = $resu->getResult();

		$request = $this->container->get('request');
		$session = $request->getSession();
		$name   = $session->get('nomAdmin');
		$prenom = $session->get('preAdmin');

		return array(
            'entities' => $entities,'name'=> $name ,'prenom'=> $prenom);
    }
    /**
     * Creates a new Taches entity.
     *
     * @Route("/", name="naf_create")
     * @Method("POST")
     * @Template("GCNAFNAFBundle:Taches:new.html.twig")
     */
    public function createAction(Request $request)
    {
        $entity = new Taches();
        $form = $this->createCreateForm($entity);
        $form->handleRequest($request);

        if ($form->isValid()) {
            $em = $this->getDoctrine()->getManager();
            $em->persist($entity);
            $em->flush();

            return $this->redirect($this->generateUrl('naf_show', array('id' => $entity->getId())));
        }

        return array(
            'entity' => $entity,
            'form'   => $form->createView(),
        );
    }

    /**
    * Creates a form to create a Taches entity.
    *
    * @param Taches $entity The entity
    *
    * @return \Symfony\Component\Form\Form The form
    */
    private function createCreateForm(Taches $entity)
    {
        $form = $this->createForm(new TachesType(), $entity, array(
            'action' => $this->generateUrl('naf_create'),
            'method' => 'POST',
        ));

        $form->add('submit', 'submit', array('label' => 'Create'));

        return $form;
    }

    /**
     * Displays a form to create a new Taches entity.
     *
     * @Route("/new", name="naf_new")
     * @Method("GET")
     * @Template()
     */
    public function newAction()
    {
        $entity = new Taches();
        $form   = $this->createCreateForm($entity);

        return array(
            'entity' => $entity,
            'form'   => $form->createView(),
        );
    }

    /**
     * Finds and displays a Taches entity.
     *
     * @Route("/{id}", name="naf_show")
     * @Method("GET")
     * @Template()
     */
    public function showAction($id)
    {
        $em = $this->getDoctrine()->getManager();

        $entity = $em->getRepository('GCNAFNAFBundle:Taches')->find($id);

        if (!$entity) {
            throw $this->createNotFoundException('Unable to find Taches entity.');
        }

        $deleteForm = $this->createDeleteForm($id);

        return array(
            'entity'      => $entity,
            'delete_form' => $deleteForm->createView(),
        );
    }

    /**
     * Displays a form to edit an existing Taches entity.
     *
     * @Route("/{id}/edit", name="naf_edit")
     * @Method("GET")
     * @Template()
     */
    public function editAction($id)
    {
        $em = $this->getDoctrine()->getManager();

        $entity = $em->getRepository('GCNAFNAFBundle:Taches')->find($id);

        if (!$entity) {
            throw $this->createNotFoundException('Unable to find Taches entity.');
        }

        $editForm = $this->createEditForm($entity);
        $deleteForm = $this->createDeleteForm($id);

        return array(
            'entity'      => $entity,
            'edit_form'   => $editForm->createView(),
            'delete_form' => $deleteForm->createView(),
        );
    }

    /**
    * Creates a form to edit a Taches entity.
    *
    * @param Taches $entity The entity
    *
    * @return \Symfony\Component\Form\Form The form
    */
    private function createEditForm(Taches $entity)
    {
        $form = $this->createForm(new TachesType(), $entity, array(
            'action' => $this->generateUrl('naf_update', array('id' => $entity->getId())),
            'method' => 'PUT',
        ));

        $form->add('submit', 'submit', array('label' => 'Update'));

        return $form;
    }
    /**
     * Edits an existing Taches entity.
     *
     * @Route("/{id}", name="naf_update")
     * @Method("PUT")
     * @Template("GCNAFNAFBundle:Taches:edit.html.twig")
     */
    public function updateAction(Request $request, $id)
    {
        $em = $this->getDoctrine()->getManager();

        $entity = $em->getRepository('GCNAFNAFBundle:Taches')->find($id);

        if (!$entity) {
            throw $this->createNotFoundException('Unable to find Taches entity.');
        }

        $deleteForm = $this->createDeleteForm($id);
        $editForm = $this->createEditForm($entity);
        $editForm->handleRequest($request);

        if ($editForm->isValid()) {
            $em->flush();

            return $this->redirect($this->generateUrl('naf_edit', array('id' => $id)));
        }

        return array(
            'entity'      => $entity,
            'edit_form'   => $editForm->createView(),
            'delete_form' => $deleteForm->createView(),
        );
    }
    /**
     * Deletes a Taches entity.
     *
     * @Route("/{id}", name="naf_delete")
     * @Method("DELETE")
     */
    public function deleteAction($id)
    {
		$em = $this->getDoctrine()->getManager();
		$entity = $em->getRepository('GCNAFNAFBundle:Taches')->find($id);
		if (!$entity) {
			throw $this->createNotFoundException('Tache introuvable');
		}
		$em->remove($entity);
		$em->flush();
		return new RedirectResponse($this->container->get('router')->generate('GCNAFNAFBundle_admin_listeTaches'));
    }

    /**
     * Creates a form to delete a Taches entity by id.
     *
     * @param mixed $id The entity id
     *
     * @return \Symfony\Component\Form\Form The form
     */
    private function createDeleteForm($id)
    {
        return $this->createFormBuilder()
            ->setAction($this->generateUrl('naf_delete', array('id' => $id)))
            ->setMethod('DELETE')
            ->add('submit', 'submit', array('label' => 'Delete'))
            ->getForm()
        ;
    }

	 public function ajouterAction()
	{
		$request = $this->container->get('request');
		$session = $request->getSession();
		$name   = $session->get('nomAdmin');
		$prenom = $session->get('preAdmin');
		$em = $this->container->get('doctrine')->getManager();
		$erreur='';

		$projets=array();
		$query1=$this->getDoctrine()->getRepository('GCNAFNAFBundle:ProjetChef')->findAll();
		foreach ($query1 as $ref1) {
		$projets[$ref1->getId()]=$ref1->getProjet();
		}

		$taches = new Taches();
		$formBuilder = $this->createFormBuilder($taches);
		$formBuilder
			->add('projet', 'choice', array('choices' => $projets,'empty_value' =>'Choisissez un projet'))
			->add('libelle','text')
            ->add('dated','date', array('format' => 'yyyy-MM-dd','years' => range(2010 ,2030) ))
            ->add('datef','date', array('format' => 'yyyy-MM-dd','years' => range(2010 ,2030) ));
		$form = $formBuilder->getForm();
		if ($request->getMethod() == 'POST')
		{
			$form->bind($request);
			if ($form->isValid())
			{
			$form_user = $form->getData();
			$dateD = $form_user->getDated();
			$dateF = $form_user->getDatef();
				if ($dateD < $dateF)
				{
				$em->persist($taches);
				$em->flush();
				return new RedirectResponse($this->container->get('router')->generate('GCNAFNAFBundle_admin_listeTaches'));
				}
				else {$erreur='La date debut de la tache doit etre inferieure a la date de fin de cette tache!';}
			}
		}
		return $this->container->get('templating')->renderResponse(
		'GCNAFNAFBundle:Taches:new.html.twig',
		array(
		'form' => $form->createView(),
		'erreur' => $erreur,
		'name'=> $name ,'prenom'=> $prenom,
		));
  }

 	 public function modifierAction($id)
	{
		$request = $this->container->get('request');
		$session = $request->getSession();
		$name   = $session->get('nomAdmin');
		$prenom = $session->get('preAdmin');
		$em = $this->container->get('doctrine')->getManager();
		$erreur='';

		$projets=array();
		$query1=$this->getDoctrine()->getRepository('GCNAFNAFBundle:ProjetChef')->findAll();
		foreach ($query1 as $ref1) {
		$projets[$ref1->getId()]=$ref1->getProjet();
		}
		$taches = $em->find('GCNAFNAFBundle:Taches', $id);
		$formBuilder = $this->createFormBuilder($taches);
		$formBuilder
			->add('projet', 'choice', array('choices' => $projets,'empty_value' =>'Choisissez un projet'))
			->add('libelle','text')
            ->add('dated','date', array('format' => 'yyyy-MM-dd','years' => range(2010 ,2030) ))
            ->add('datef','date', array('format' => 'yyyy-MM-dd','years' => range(2010 ,2030) ));
		$form = $formBuilder->getForm();
		if ($request->getMethod() == 'POST')
		{
			$form->bind($request);
			if ($form->isValid())
			{
			$form_user = $form->getData();
			$dateD = $form_user->getDated();
			$dateF = $form_user->getDatef();
				if ($dateD < $dateF)
				{
				$em->persist($taches);
				$em->flush();
				return new RedirectResponse($this->container->get('router')->generate('GCNAFNAFBundle_admin_listeTaches'));
				}
				else {$erreur='La date debut de la tache doit etre inferieure a la date de fin de cette tache!';}
			}
		}
		return $this->container->get('templating')->renderResponse(
		'GCNAFNAFBundle:Taches:edit.html.twig',
		array(
		'form' => $form->createView(),
		'erreur' => $erreur,
		'name'=> $name ,'prenom'=> $prenom,
		));
 }
}// fin classe


text:
export JAVA_8_HOME=`/usr/libexec/java_home -v 1.8`
# Mac at work
export SPARK_HOME=/Users/jiedong/software/spark-1.5.2-bin-hadoop2.6
# jar filepath
export TARGET_JAR=target/scala-2.11/scala-infrastructure-apache-spark_2.11-1.0.0.jar

### 1 package jar
cd ..
sbt -java-home $JAVA_8_HOME package

### 2 submit spark tasks
$SPARK_HOME/bin/spark-submit \
  --class "com.spike.giantdataanalysis.spark.example.ConsoleLogMining" \
  --master local[4] \
  $TARGET_JAR


text:
import time

from helper import PackageHelper

import cocos

class PackageInfo(object):
    @staticmethod
    def plugin_name():
        return "info"

    @staticmethod
    def brief_description():
        return cocos.MultiLanguage.get_string('PACKAGE_INFO_BRIEF')

    def parse_args(self, argv):
        from argparse import ArgumentParser

        parser = ArgumentParser(prog="cocos package %s" % self.__class__.plugin_name(),
                                description=self.__class__.brief_description())
        parser.add_argument("name", metavar="NAME", help=cocos.MultiLanguage.get_string('PACKAGE_INFO_ARG_NAME'))
        parser.add_argument('-v', '--version', default='all', help=cocos.MultiLanguage.get_string('PACKAGE_INFO_ARG_VERSION'))
        return parser.parse_args(argv)

    def run(self, argv):
        args = self.parse_args(argv)
        name = args.name
        version = args.version
        package_data = PackageHelper.query_package_data(name, version)
        if package_data is None:
            print cocos.MultiLanguage.get_string('PACKAGE_INFO_ERROR_NO_PKG_FMT') % (name, version)
            return

        if isinstance(package_data, list):
            for data in package_data:
                self.show_info(name, data)
                return

        if package_data.has_key('err'):
            print cocos.MultiLanguage.get_string('PACKAGE_INFO_ERROR_NO_PKG_FMT') % (name, version)
            return

        self.show_info(name, package_data)

    def show_info(self, name, package_data):
        print cocos.MultiLanguage.get_string('PACKAGE_INFO_PKG_FMT') % \
              (name, package_data["name"], package_data["version"],
               time.strftime("%Y-%m-%d %H:%I:%S", time.gmtime(int(package_data["filetime"]))),
               package_data["author"], (int(package_data["filesize"]) / 1024),
               package_data["description"])


text:
package main.java.fr.dauphine.lamsade.hib.ads.servlets;

import java.io.IOException;
import java.util.logging.Logger;

import javax.ejb.EJB;
import javax.naming.NamingException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import main.java.fr.dauphine.lamsade.hib.ads.dao.ClubDao;
import main.java.fr.dauphine.lamsade.hib.ads.entities.Club;

/**
 * @author mathias pereira
 */
@WebServlet("/clubs/delete")
public class ClubDeleteServlet extends HttpServlet {
  private static final long serialVersionUID = 1L;
  private static final Logger LOGGER = Logger.getLogger(ClubDeleteServlet.class.getCanonicalName());
  @EJB
  private ClubDao clubDao;

  public ClubDeleteServlet() throws NamingException {
    super();
  }

  protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    Club club = clubDao.find(Integer.parseInt(request.getParameter("id")));
    request.setAttribute("club", club);
    LOGGER.info("GET /clubs/delete with id: " + club.getId());
    this.getServletContext().getRequestDispatcher("/WEB-INF/clubs/delete.jsp").forward(request, response);
  }

  protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    clubDao.delete(Integer.parseInt(request.getParameter("id")));
    LOGGER.info("POST /clubs/delete with id: " + request.getParameter("id"));
    response.sendRedirect("../clubs");
  }

}


text:
<?xml version="1.0" encoding="utf-8"?>

<!-- Generated with http://android-holo-colors.com -->
<resources xmlns:android="http://schemas.android.com/apk/res/android">

  <style name="AutoCompleteTextViewAppTheme" parent="android:Widget.Holo.AutoCompleteTextView">
      <item name="android:dropDownSelector">@drawable/apptheme_list_selector_holo_dark</item>
	    <item name="android:background">@drawable/apptheme_edit_text_holo_dark</item>
  </style>

  <style name="ButtonAppTheme" parent="android:Widget.Holo.Button">
	  <item name="android:background">@drawable/apptheme_btn_default_holo_dark</item>
  </style>

  <style name="ImageButtonAppTheme" parent="android:Widget.Holo.ImageButton">
	  <item name="android:background">@drawable/apptheme_btn_default_holo_dark</item>
  </style>

  <style name="SpinnerAppTheme" parent="android:Widget.Holo.Spinner">
      <item name="android:background">@drawable/apptheme_spinner_background_holo_dark</item>
      <item name="android:dropDownSelector">@drawable/apptheme_list_selector_holo_dark</item>
  </style>

  <style name="TabAppTheme">
      <item name="android:gravity">center_horizontal</item>
      <item name="android:paddingLeft">16dip</item>
      <item name="android:paddingRight">16dip</item>
      <item name="android:background">@drawable/apptheme_tab_indicator_holo</item>
      <item name="android:layout_width">0dip</item>
      <item name="android:layout_weight">1</item>
      <item name="android:minWidth">80dip</item>
  </style>

  <style name="TabTextAppTheme">
	  <item name="android:textColor">#ffffff</item>
      <item name="android:textSize">12sp</item>
      <item name="android:textStyle">bold</item>
      <!-- v14 <item name="android:textAllCaps">true</item> -->
      <item name="android:ellipsize">marquee</item>
      <item name="android:maxLines">2</item>
      <item name="android:maxWidth">180dip</item>
  </style>

  <style name="ProgressBarAppTheme" parent="android:Widget.Holo.ProgressBar.Horizontal">
      <item name="android:progressDrawable">@drawable/apptheme_progress_horizontal_holo_dark</item>
      <item name="android:indeterminateDrawable">@drawable/apptheme_progress_indeterminate_horizontal_holo_dark</item>
  </style>

  <style name="SeekBarAppTheme" parent="android:Widget.Holo.SeekBar">
      <item name="android:progressDrawable">@drawable/apptheme_scrubber_progress_horizontal_holo_dark</item>
      <item name="android:indeterminateDrawable">@drawable/apptheme_scrubber_progress_horizontal_holo_dark</item>
      <item name="android:thumb">@drawable/apptheme_scrubber_control_selector_holo_dark</item>
  </style>

  <style name="RatingBarAppTheme" parent="android:Widget.Holo.RatingBar">
      <item name="android:progressDrawable">@drawable/apptheme_ratingbar_full_holo_dark</item>
      <item name="android:indeterminateDrawable">@drawable/apptheme_ratingbar_full_holo_dark</item>
  </style>

  <style name="RatingBarBigAppTheme" parent="android:Widget.Holo.RatingBar.Indicator">
      <item name="android:progressDrawable">@drawable/apptheme_ratingbar_holo_dark</item>
      <item name="android:indeterminateDrawable">@drawable/apptheme_ratingbar_holo_dark</item>
  </style>

  <style name="RatingBarSmallAppTheme" parent="android:Widget.Holo.RatingBar.Small">
      <item name="android:progressDrawable">@drawable/apptheme_ratingbar_small_holo_dark</item>
      <item name="android:indeterminateDrawable">@drawable/apptheme_ratingbar_small_holo_dark</item>
  </style>

  <style name="ToggleAppTheme" parent="android:Widget.Holo.Button.Toggle">
      <item name="android:background">@drawable/apptheme_btn_toggle_holo_dark</item>
  </style>

</resources>


text:
var sections = function(haystack, needle, remaining, acc, offset) {
  if (!acc) acc = [];
  if (!remaining) remaining = "";
  if (!offset) offset = 0;

  needle = needle.trim();
  var index = haystack.toLowerCase().indexOf(needle.toLowerCase());
  if (index > -1) {
    if (remaining.length) {
      var remainingHaystack = haystack.substr(needle.length + index);
      var newAcc = acc.concat([[offset + index, offset + needle.length + index]]);
      return sections(remainingHaystack, remaining, null, newAcc, offset + needle.length + index);
    } else {
      return acc.concat([[offset + index, offset + needle.length + index]]);
    }
  } else if (needle.length > 1) {
    var nextNeedle = needle.substr(0, needle.length - 1);
    return sections(haystack, nextNeedle, needle.substr(needle.length - 1) + remaining, acc, offset);
  } else {
    return [];
  }
};

module.exports = function(haystack, needle, pre, post) {
  if (!pre) pre = '';
  if (!post) post = '';

  var matches = sections(haystack, needle);
  if (!matches.length) return haystack;
  var lastPos = 0;
  var result = '';

  for (var idx in matches) {
    var match = matches[idx];
    var start = match[0];
    var end = match[1];
    result += haystack.substring(lastPos, start);
    result += pre + haystack.substring(start, end) + post;
    lastPos = end;
  }

  result += haystack.substr(lastPos);

  return result;
};