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

#include "components/password_manager/core/browser/login_database.h"

#include <stddef.h>
#include <stdint.h>
#include <algorithm>
#include <limits>
#include <map>
#include <utility>

#include "base/bind.h"
#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_macros.h"
#include "base/metrics/sparse_histogram.h"
#include "base/numerics/safe_conversions.h"
#include "base/pickle.h"
#include "base/stl_util.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "components/autofill/core/common/password_form.h"
#include "components/password_manager/core/browser/affiliation_utils.h"
#include "components/password_manager/core/browser/password_manager_client.h"
#include "components/password_manager/core/browser/password_manager_metrics_util.h"
#include "components/password_manager/core/browser/password_manager_util.h"
#include "components/password_manager/core/browser/sql_table_builder.h"
#include "google_apis/gaia/gaia_auth_util.h"
#include "google_apis/gaia/gaia_urls.h"
#include "sql/connection.h"
#include "sql/statement.h"
#include "sql/transaction.h"
#include "url/origin.h"
#include "url/url_constants.h"

using autofill::PasswordForm;

namespace password_manager {

// The current version number of the login database schema.
const int kCurrentVersionNumber = 18;
// The oldest version of the schema such that a legacy Chrome client using that
// version can still read/write the current database.
const int kCompatibleVersionNumber = 18;

base::Pickle SerializeVector(const std::vector<base::string16>& vec) {
  base::Pickle p;
  for (size_t i = 0; i < vec.size(); ++i) {
    p.WriteString16(vec[i]);
  }
  return p;
}

std::vector<base::string16> DeserializeVector(const base::Pickle& p) {
  std::vector<base::string16> ret;
  base::string16 str;

  base::PickleIterator iterator(p);
  while (iterator.ReadString16(&str)) {
    ret.push_back(str);
  }
  return ret;
}

namespace {

// Convenience enum for interacting with SQL queries that use all the columns.
enum LoginTableColumns {
  COLUMN_ORIGIN_URL = 0,
  COLUMN_ACTION_URL,
  COLUMN_USERNAME_ELEMENT,
  COLUMN_USERNAME_VALUE,
  COLUMN_PASSWORD_ELEMENT,
  COLUMN_PASSWORD_VALUE,
  COLUMN_SUBMIT_ELEMENT,
  COLUMN_SIGNON_REALM,
  COLUMN_PREFERRED,
  COLUMN_DATE_CREATED,
  COLUMN_BLACKLISTED_BY_USER,
  COLUMN_SCHEME,
  COLUMN_PASSWORD_TYPE,
  COLUMN_POSSIBLE_USERNAMES,
  COLUMN_TIMES_USED,
  COLUMN_FORM_DATA,
  COLUMN_DATE_SYNCED,
  COLUMN_DISPLAY_NAME,
  COLUMN_ICON_URL,
  COLUMN_FEDERATION_URL,
  COLUMN_SKIP_ZERO_CLICK,
  COLUMN_GENERATION_UPLOAD_STATUS,
  COLUMN_NUM  // Keep this last.
};

enum class HistogramSize { SMALL, LARGE };

// An enum for UMA reporting. Add values to the end only.
enum DatabaseInitError {
  INIT_OK,
  OPEN_FILE_ERROR,
  START_TRANSACTION_ERROR,
  META_TABLE_INIT_ERROR,
  INCOMPATIBLE_VERSION,
  INIT_LOGINS_ERROR,
  INIT_STATS_ERROR,
  MIGRATION_ERROR,
  COMMIT_TRANSACTION_ERROR,

  DATABASE_INIT_ERROR_COUNT,
};

void BindAddStatement(const PasswordForm& form,
                      const std::string& encrypted_password,
                      sql::Statement* s) {
  s->BindString(COLUMN_ORIGIN_URL, form.origin.spec());
  s->BindString(COLUMN_ACTION_URL, form.action.spec());
  s->BindString16(COLUMN_USERNAME_ELEMENT, form.username_element);
  s->BindString16(COLUMN_USERNAME_VALUE, form.username_value);
  s->BindString16(COLUMN_PASSWORD_ELEMENT, form.password_element);
  s->BindBlob(COLUMN_PASSWORD_VALUE, encrypted_password.data(),
              static_cast<int>(encrypted_password.length()));
  s->BindString16(COLUMN_SUBMIT_ELEMENT, form.submit_element);
  s->BindString(COLUMN_SIGNON_REALM, form.signon_realm);
  s->BindInt(COLUMN_PREFERRED, form.preferred);
  s->BindInt64(COLUMN_DATE_CREATED, form.date_created.ToInternalValue());
  s->BindInt(COLUMN_BLACKLISTED_BY_USER, form.blacklisted_by_user);
  s->BindInt(COLUMN_SCHEME, form.scheme);
  s->BindInt(COLUMN_PASSWORD_TYPE, form.type);
  base::Pickle usernames_pickle =
      SerializeVector(form.other_possible_usernames);
  s->BindBlob(COLUMN_POSSIBLE_USERNAMES,
              usernames_pickle.data(),
              usernames_pickle.size());
  s->BindInt(COLUMN_TIMES_USED, form.times_used);
  base::Pickle form_data_pickle;
  autofill::SerializeFormData(form.form_data, &form_data_pickle);
  s->BindBlob(COLUMN_FORM_DATA,
              form_data_pickle.data(),
              form_data_pickle.size());
  s->BindInt64(COLUMN_DATE_SYNCED, form.date_synced.ToInternalValue());
  s->BindString16(COLUMN_DISPLAY_NAME, form.display_name);
  s->BindString(COLUMN_ICON_URL, form.icon_url.spec());
  // An empty Origin serializes as "null" which would be strange to store here.
  s->BindString(COLUMN_FEDERATION_URL,
                form.federation_origin.unique()
                    ? std::string()
                    : form.federation_origin.Serialize());
  s->BindInt(COLUMN_SKIP_ZERO_CLICK, form.skip_zero_click);
  s->BindInt(COLUMN_GENERATION_UPLOAD_STATUS, form.generation_upload_status);
}

void AddCallback(int err, sql::Statement* /*stmt*/) {
  if (err == 19 /*SQLITE_CONSTRAINT*/)
    DLOG(WARNING) << "LoginDatabase::AddLogin updated an existing form";
}

bool DoesMatchConstraints(const PasswordForm& form) {
  if (!IsValidAndroidFacetURI(form.signon_realm) && form.origin.is_empty()) {
    DLOG(ERROR) << "Constraint violation: form.origin is empty";
    return false;
  }
  if (form.signon_realm.empty()) {
    DLOG(ERROR) << "Constraint violation: form.signon_realm is empty";
    return false;
  }
  return true;
}

void LogDatabaseInitError(DatabaseInitError error) {
  UMA_HISTOGRAM_ENUMERATION("PasswordManager.LoginDatabaseInit", error,
                            DATABASE_INIT_ERROR_COUNT);
}

// UMA_* macros assume that the name never changes. This is a helper function
// where this assumption doesn't hold.
void LogDynamicUMAStat(const std::string& name,
                       int sample,
                       int min,
                       int max,
                       int bucket_count) {
  base::HistogramBase* counter = base::Histogram::FactoryGet(
      name, min, max, bucket_count,
      base::HistogramBase::kUmaTargetedHistogramFlag);
  counter->Add(sample);
}

void LogAccountStat(const std::string& name, int sample) {
  LogDynamicUMAStat(name, sample, 0, 32, 6);
}

void LogTimesUsedStat(const std::string& name, int sample) {
  LogDynamicUMAStat(name, sample, 0, 100, 10);
}

void LogNumberOfAccountsForScheme(const std::string& scheme, int sample) {
  LogDynamicUMAStat("PasswordManager.TotalAccountsHiRes.WithScheme." + scheme,
                    sample, 1, 1000, 100);
}

void LogNumberOfAccountsReusingPassword(const std::string& suffix,
                                        int sample,
                                        HistogramSize histogram_size) {
  int max = histogram_size == HistogramSize::LARGE ? 500 : 100;
  int bucket_count = histogram_size == HistogramSize::LARGE ? 50 : 20;
  LogDynamicUMAStat("PasswordManager.AccountsReusingPassword." + suffix, sample,
                    1, max, bucket_count);
}

// Records password reuse metrics given the |signon_realms| corresponding to a
// set of accounts that reuse the same password. See histograms.xml for details.
void LogPasswordReuseMetrics(const std::vector<std::string>& signon_realms) {
  struct StatisticsPerScheme {
    StatisticsPerScheme() : num_total_accounts(0) {}

    // The number of accounts for each registry controlled domain.
    std::map<std::string, int> num_accounts_per_registry_controlled_domain;

    // The number of accounts for each domain.
    std::map<std::string, int> num_accounts_per_domain;

    // Total number of accounts with this scheme. This equals the sum of counts
    // in either of the above maps.
    int num_total_accounts;
  };

  // The scheme (i.e. protocol) of the origin, not PasswordForm::scheme.
  enum Scheme { SCHEME_HTTP, SCHEME_HTTPS };
  const Scheme kAllSchemes[] = {SCHEME_HTTP, SCHEME_HTTPS};

  StatisticsPerScheme statistics[arraysize(kAllSchemes)];
  std::map<std::string, std::string> domain_to_registry_controlled_domain;

  for (const std::string& signon_realm : signon_realms) {
    const GURL signon_realm_url(signon_realm);
    const std::string domain = signon_realm_url.host();
    if (domain.empty())
      continue;

    if (!domain_to_registry_controlled_domain.count(domain)) {
      domain_to_registry_controlled_domain[domain] =
          GetRegistryControlledDomain(signon_realm_url);
      if (domain_to_registry_controlled_domain[domain].empty())
        domain_to_registry_controlled_domain[domain] = domain;
    }
    const std::string& registry_controlled_domain =
        domain_to_registry_controlled_domain[domain];

    Scheme scheme = SCHEME_HTTP;
    static_assert(arraysize(kAllSchemes) == 2, "Update this logic");
    if (signon_realm_url.SchemeIs(url::kHttpsScheme))
      scheme = SCHEME_HTTPS;
    else if (!signon_realm_url.SchemeIs(url::kHttpScheme))
      continue;

    statistics[scheme].num_accounts_per_domain[domain]++;
    statistics[scheme].num_accounts_per_registry_controlled_domain
        [registry_controlled_domain]++;
    statistics[scheme].num_total_accounts++;
  }

  // For each "source" account of either scheme, count the number of "target"
  // accounts reusing the same password (of either scheme).
  for (const Scheme scheme : kAllSchemes) {
    for (const auto& kv : statistics[scheme].num_accounts_per_domain) {
      const std::string& domain(kv.first);
      const int num_accounts_per_domain(kv.second);
      const std::string& registry_controlled_domain =
          domain_to_registry_controlled_domain[domain];

      Scheme other_scheme = scheme == SCHEME_HTTP ? SCHEME_HTTPS : SCHEME_HTTP;
      static_assert(arraysize(kAllSchemes) == 2, "Update |other_scheme|");

      // Discount the account at hand from the number of accounts with the same
      // domain and scheme.
      int num_accounts_for_same_domain[arraysize(kAllSchemes)] = {};
      num_accounts_for_same_domain[scheme] =
          statistics[scheme].num_accounts_per_domain[domain] - 1;
      num_accounts_for_same_domain[other_scheme] =
          statistics[other_scheme].num_accounts_per_domain[domain];

      // By definition, a PSL match requires the scheme to be the same.
      int num_psl_matching_accounts =
          statistics[scheme].num_accounts_per_registry_controlled_domain
              [registry_controlled_domain] -
          statistics[scheme].num_accounts_per_domain[domain];

      // Discount PSL matches from the number of accounts with different domains
      // but the same scheme.
      int num_accounts_for_different_domain[arraysize(kAllSchemes)] = {};
      num_accounts_for_different_domain[scheme] =
          statistics[scheme].num_total_accounts -
          statistics[scheme].num_accounts_per_registry_controlled_domain
              [registry_controlled_domain];
      num_accounts_for_different_domain[other_scheme] =
          statistics[other_scheme].num_total_accounts -
          statistics[other_scheme].num_accounts_per_domain[domain];

      std::string source_realm_kind =
          scheme == SCHEME_HTTP ? "FromHttpRealm" : "FromHttpsRealm";
      static_assert(arraysize(kAllSchemes) == 2, "Update |source_realm_kind|");

      // So far, the calculation has been carried out once per "source" domain,
      // but the metrics need to be recorded on a per-account basis. The set of
      // metrics are the same for all accounts for the same domain, so simply
      // report them as many times as accounts.
      for (int i = 0; i < num_accounts_per_domain; ++i) {
        LogNumberOfAccountsReusingPassword(
            source_realm_kind + ".OnHttpRealmWithSameHost",
            num_accounts_for_same_domain[SCHEME_HTTP], HistogramSize::SMALL);
        LogNumberOfAccountsReusingPassword(
            source_realm_kind + ".OnHttpsRealmWithSameHost",
            num_accounts_for_same_domain[SCHEME_HTTPS], HistogramSize::SMALL);
        LogNumberOfAccountsReusingPassword(
            source_realm_kind + ".OnPSLMatchingRealm",
            num_psl_matching_accounts, HistogramSize::SMALL);

        LogNumberOfAccountsReusingPassword(
            source_realm_kind + ".OnHttpRealmWithDifferentHost",
            num_accounts_for_different_domain[SCHEME_HTTP],
            HistogramSize::LARGE);
        LogNumberOfAccountsReusingPassword(
            source_realm_kind + ".OnHttpsRealmWithDifferentHost",
            num_accounts_for_different_domain[SCHEME_HTTPS],
            HistogramSize::LARGE);

        LogNumberOfAccountsReusingPassword(
            source_realm_kind + ".OnAnyRealmWithDifferentHost",
            num_accounts_for_different_domain[SCHEME_HTTP] +
                num_accounts_for_different_domain[SCHEME_HTTPS],
            HistogramSize::LARGE);
      }
    }
  }
}

// Teaches |builder| about the different DB schemes in different versions.
void InitializeBuilder(SQLTableBuilder* builder) {
  // Versions 0 and 1, which are the same.
  builder->AddColumnToUniqueKey("origin_url", "VARCHAR NOT NULL");
  builder->AddColumn("action_url", "VARCHAR");
  builder->AddColumnToUniqueKey("username_element", "VARCHAR");
  builder->AddColumnToUniqueKey("username_value", "VARCHAR");
  builder->AddColumnToUniqueKey("password_element", "VARCHAR");
  builder->AddColumn("password_value", "BLOB");
  builder->AddColumn("submit_element", "VARCHAR");
  builder->AddColumnToUniqueKey("signon_realm", "VARCHAR NOT NULL");
  builder->AddColumn("ssl_valid", "INTEGER NOT NULL");
  builder->AddColumn("preferred", "INTEGER NOT NULL");
  builder->AddColumn("date_created", "INTEGER NOT NULL");
  builder->AddColumn("blacklisted_by_user", "INTEGER NOT NULL");
  builder->AddColumn("scheme", "INTEGER NOT NULL");
  builder->SealVersion();
  unsigned version = builder->SealVersion();
  DCHECK_EQ(1u, version);

  // Version 2.
  builder->AddColumn("password_type", "INTEGER");
  builder->AddColumn("possible_usernames", "BLOB");
  version = builder->SealVersion();
  DCHECK_EQ(2u, version);

  // Version 3.
  builder->AddColumn("times_used", "INTEGER");
  version = builder->SealVersion();
  DCHECK_EQ(3u, version);

  // Version 4.
  builder->AddColumn("form_data", "BLOB");
  version = builder->SealVersion();
  DCHECK_EQ(4u, version);

  // Version 5.
  builder->AddColumn("use_additional_auth", "INTEGER");
  version = builder->SealVersion();
  DCHECK_EQ(5u, version);

  // Version 6.
  builder->AddColumn("date_synced", "INTEGER");
  version = builder->SealVersion();
  DCHECK_EQ(6u, version);

  // Version 7.
  builder->AddColumn("display_name", "VARCHAR");
  builder->AddColumn("avatar_url", "VARCHAR");
  builder->AddColumn("federation_url", "VARCHAR");
  builder->AddColumn("is_zero_click", "INTEGER");
  version = builder->SealVersion();
  DCHECK_EQ(7u, version);

  // Version 8.
  builder->SealVersion();
  // Version 9.
  version = builder->SealVersion();
  // Version 10.
  builder->DropColumn("use_additional_auth");
  version = builder->SealVersion();
  DCHECK_EQ(10u, version);

  // Version 11.
  builder->RenameColumn("is_zero_click", "skip_zero_click");
  version = builder->SealVersion();
  DCHECK_EQ(11u, version);

  // Version 12.
  builder->AddColumn("generation_upload_status", "INTEGER");
  version = builder->SealVersion();
  DCHECK_EQ(12u, version);

  // Version 13.
  builder->SealVersion();
  // Version 14.
  builder->RenameColumn("avatar_url", "icon_url");
  version = builder->SealVersion();
  DCHECK_EQ(14u, version);

  // Version 15.
  builder->SealVersion();
  // Version 16.
  builder->SealVersion();
  // Version 17.
  version = builder->SealVersion();
  DCHECK_EQ(17u, version);

  // Version 18.
  builder->DropColumn("ssl_valid");
  version = builder->SealVersion();
  DCHECK_EQ(18u, version);

  DCHECK_EQ(static_cast<size_t>(COLUMN_NUM), builder->NumberOfColumns())
      << "Adjust LoginTableColumns if you change column definitions here.";
}

// Call this after having called InitializeBuilder, to migrate the database from
// the current version to kCurrentVersionNumber.
bool MigrateLogins(unsigned current_version,
                   SQLTableBuilder* builder,
                   sql::Connection* db) {
  if (!builder->MigrateFrom(current_version, db))
    return false;

  // Data changes, not covered by the schema migration above.
  if (current_version <= 8) {
    sql::Statement fix_time_format;
    fix_time_format.Assign(db->GetCachedStatement(
        SQL_FROM_HERE,
        "UPDATE logins SET date_created = (date_created * ?) + ?"));
    fix_time_format.BindInt64(0, base::Time::kMicrosecondsPerSecond);
    fix_time_format.BindInt64(1, base::Time::kTimeTToMicrosecondsOffset);
    if (!fix_time_format.Run())
      return false;
  }

  if (current_version <= 16) {
    sql::Statement reset_zero_click;
    reset_zero_click.Assign(db->GetCachedStatement(
        SQL_FROM_HERE, "UPDATE logins SET skip_zero_click = 1"));
    if (!reset_zero_click.Run())
      return false;
  }

  return true;
}

// Because of https://crbug.com/295851, some early version numbers might be
// wrong. This function detects that and fixes the version.
bool FixVersionIfNeeded(sql::Connection* db, int* current_version) {
  if (*current_version == 1) {
    int extra_columns = 0;
    if (db->DoesColumnExist("logins", "password_type"))
      ++extra_columns;
    if (db->DoesColumnExist("logins", "possible_usernames"))
      ++extra_columns;
    if (extra_columns == 2) {
      *current_version = 2;
    } else if (extra_columns == 1) {
      // If this is https://crbug.com/295851 then either both columns exist
      // or none.
      return false;
    }
  }
  if (*current_version == 2) {
    if (db->DoesColumnExist("logins", "times_used"))
      *current_version = 3;
  }
  if (*current_version == 3) {
    if (db->DoesColumnExist("logins", "form_data"))
      *current_version = 4;
  }
  return true;
}

// Generates the string "(?,?,...,?)" with |count| repetitions of "?".
std::string GeneratePlaceholders(size_t count) {
  std::string result(2 * count + 1, ',');
  result.front() = '(';
  result.back() = ')';
  for (size_t i = 1; i < 2 * count + 1; i += 2) {
    result[i] = '?';
  }
  return result;
}

}  // namespace

LoginDatabase::LoginDatabase(const base::FilePath& db_path)
    : db_path_(db_path), clear_password_values_(false) {
}

LoginDatabase::~LoginDatabase() {
}

bool LoginDatabase::Init() {
  // Set pragmas for a small, private database (based on WebDatabase).
  db_.set_page_size(2048);
  db_.set_cache_size(32);
  db_.set_exclusive_locking();
  db_.set_restrict_to_user();
  db_.set_histogram_tag("Passwords");

  if (!db_.Open(db_path_)) {
    LogDatabaseInitError(OPEN_FILE_ERROR);
    LOG(ERROR) << "Unable to open the password store database.";
    return false;
  }

  sql::Transaction transaction(&db_);
  if (!transaction.Begin()) {
    LogDatabaseInitError(START_TRANSACTION_ERROR);
    LOG(ERROR) << "Unable to start a transaction.";
    db_.Close();
    return false;
  }

  // Check the database version.
  if (!meta_table_.Init(&db_, kCurrentVersionNumber,
                        kCompatibleVersionNumber)) {
    LogDatabaseInitError(META_TABLE_INIT_ERROR);
    LOG(ERROR) << "Unable to create the meta table.";
    transaction.Rollback();
    db_.Close();
    return false;
  }
  if (meta_table_.GetCompatibleVersionNumber() > kCurrentVersionNumber) {
    LogDatabaseInitError(INCOMPATIBLE_VERSION);
    LOG(ERROR) << "Password store database is too new, kCurrentVersionNumber="
               << kCurrentVersionNumber << ", GetCompatibleVersionNumber="
               << meta_table_.GetCompatibleVersionNumber();
    transaction.Rollback();
    db_.Close();
    return false;
  }

  SQLTableBuilder builder;
  InitializeBuilder(&builder);
  InitializeStatementStrings(builder);

  if (!db_.DoesTableExist("logins")) {
    if (!builder.CreateTable(&db_)) {
      VLOG(0) << "Failed to create the 'logins' table";
      transaction.Rollback();
      db_.Close();
      return false;
    }
  }

  stats_table_.Init(&db_);

  int current_version = meta_table_.GetVersionNumber();
  bool migration_success = FixVersionIfNeeded(&db_, &current_version);
  DCHECK_LE(current_version, kCurrentVersionNumber);

  // If the file on disk is an older database version, bring it up to date.
  if (migration_success && current_version < kCurrentVersionNumber) {
    migration_success = MigrateLogins(
        base::checked_cast<unsigned>(current_version), &builder, &db_);
  }
  if (migration_success && current_version <= 15) {
    migration_success = stats_table_.MigrateToVersion(16);
  }
  if (migration_success) {
    meta_table_.SetCompatibleVersionNumber(kCompatibleVersionNumber);
    meta_table_.SetVersionNumber(kCurrentVersionNumber);
  } else {
    LogDatabaseInitError(MIGRATION_ERROR);
    UMA_HISTOGRAM_SPARSE_SLOWLY("PasswordManager.LoginDatabaseFailedVersion",
                                meta_table_.GetVersionNumber());
    LOG(ERROR) << "Unable to migrate database from "
               << meta_table_.GetVersionNumber() << " to "
               << kCurrentVersionNumber;
    transaction.Rollback();
    db_.Close();
    return false;
  }

  if (!stats_table_.CreateTableIfNecessary()) {
    LogDatabaseInitError(INIT_STATS_ERROR);
    LOG(ERROR) << "Unable to create the stats table.";
    transaction.Rollback();
    db_.Close();
    return false;
  }

  if (!transaction.Commit()) {
    LogDatabaseInitError(COMMIT_TRANSACTION_ERROR);
    LOG(ERROR) << "Unable to commit a transaction.";
    db_.Close();
    return false;
  }

  LogDatabaseInitError(INIT_OK);
  return true;
}

void LoginDatabase::ReportMetrics(const std::string& sync_username,
                                  bool custom_passphrase_sync_enabled) {
  sql::Statement s(db_.GetCachedStatement(
      SQL_FROM_HERE,
      "SELECT signon_realm, password_type, blacklisted_by_user,"
      "COUNT(username_value) FROM logins GROUP BY "
      "signon_realm, password_type, blacklisted_by_user"));

  if (!s.is_valid())
    return;

  std::string custom_passphrase = "WithoutCustomPassphrase";
  if (custom_passphrase_sync_enabled) {
    custom_passphrase = "WithCustomPassphrase";
  }

  int total_user_created_accounts = 0;
  int total_generated_accounts = 0;
  int blacklisted_sites = 0;
  while (s.Step()) {
    PasswordForm::Type password_type =
        static_cast<PasswordForm::Type>(s.ColumnInt(1));
    int blacklisted = s.ColumnInt(2);
    int accounts_per_site = s.ColumnInt(3);
    if (blacklisted) {
      ++blacklisted_sites;
    } else if (password_type == PasswordForm::TYPE_GENERATED) {
      total_generated_accounts += accounts_per_site;
      LogAccountStat(
          base::StringPrintf("PasswordManager.AccountsPerSite.AutoGenerated.%s",
                             custom_passphrase.c_str()),
          accounts_per_site);
    } else {
      total_user_created_accounts += accounts_per_site;
      LogAccountStat(
          base::StringPrintf("PasswordManager.AccountsPerSite.UserCreated.%s",
                             custom_passphrase.c_str()),
          accounts_per_site);
    }
  }
  LogAccountStat(
      base::StringPrintf("PasswordManager.TotalAccounts.UserCreated.%s",
                         custom_passphrase.c_str()),
      total_user_created_accounts);
  LogAccountStat(
      base::StringPrintf("PasswordManager.TotalAccounts.AutoGenerated.%s",
                         custom_passphrase.c_str()),
      total_generated_accounts);
  LogAccountStat(base::StringPrintf("PasswordManager.BlacklistedSites.%s",
                                    custom_passphrase.c_str()),
                 blacklisted_sites);

  sql::Statement usage_statement(db_.GetCachedStatement(
      SQL_FROM_HERE, "SELECT password_type, times_used FROM logins"));

  if (!usage_statement.is_valid())
    return;

  while (usage_statement.Step()) {
    PasswordForm::Type type =
        static_cast<PasswordForm::Type>(usage_statement.ColumnInt(0));

    if (type == PasswordForm::TYPE_GENERATED) {
      LogTimesUsedStat(base::StringPrintf(
                           "PasswordManager.TimesPasswordUsed.AutoGenerated.%s",
                           custom_passphrase.c_str()),
                       usage_statement.ColumnInt(1));
    } else {
      LogTimesUsedStat(
          base::StringPrintf("PasswordManager.TimesPasswordUsed.UserCreated.%s",
                             custom_passphrase.c_str()),
          usage_statement.ColumnInt(1));
    }
  }

  bool syncing_account_saved = false;
  if (!sync_username.empty()) {
    sql::Statement sync_statement(db_.GetCachedStatement(
        SQL_FROM_HERE,
        "SELECT username_value FROM logins "
        "WHERE signon_realm == ?"));
    sync_statement.BindString(
        0, GaiaUrls::GetInstance()->gaia_url().GetOrigin().spec());

    if (!sync_statement.is_valid())
      return;

    while (sync_statement.Step()) {
      std::string username = sync_statement.ColumnString(0);
      if (gaia::AreEmailsSame(sync_username, username)) {
        syncing_account_saved = true;
        break;
      }
    }
  }
  UMA_HISTOGRAM_ENUMERATION("PasswordManager.SyncingAccountState",
                            2 * sync_username.empty() + syncing_account_saved,
                            4);

  sql::Statement empty_usernames_statement(db_.GetCachedStatement(
      SQL_FROM_HERE, "SELECT COUNT(*) FROM logins "
                     "WHERE blacklisted_by_user=0 AND username_value=''"));
  if (empty_usernames_statement.Step()) {
    int empty_forms = empty_usernames_statement.ColumnInt(0);
    UMA_HISTOGRAM_COUNTS_100("PasswordManager.EmptyUsernames.CountInDatabase",
                             empty_forms);
  }

  sql::Statement standalone_empty_usernames_statement(db_.GetCachedStatement(
      SQL_FROM_HERE, "SELECT COUNT(*) FROM logins a "
                     "WHERE a.blacklisted_by_user=0 AND a.username_value='' "
                     "AND NOT EXISTS (SELECT * FROM logins b "
                     "WHERE b.blacklisted_by_user=0 AND b.username_value!='' "
                     "AND a.signon_realm = b.signon_realm)"));
  if (standalone_empty_usernames_statement.Step()) {
    int num_entries = standalone_empty_usernames_statement.ColumnInt(0);
    UMA_HISTOGRAM_COUNTS_100(
        "PasswordManager.EmptyUsernames.WithoutCorrespondingNonempty",
        num_entries);
  }

  sql::Statement logins_with_schemes_statement(db_.GetUniqueStatement(
      "SELECT signon_realm, origin_url, blacklisted_by_user FROM logins;"));

  if (!logins_with_schemes_statement.is_valid())
    return;

  int android_logins = 0;
  int ftp_logins = 0;
  int http_logins = 0;
  int https_logins = 0;
  int other_logins = 0;

  while (logins_with_schemes_statement.Step()) {
    std::string signon_realm = logins_with_schemes_statement.ColumnString(0);
    GURL origin_url = GURL(logins_with_schemes_statement.ColumnString(1));
    bool blacklisted_by_user = !!logins_with_schemes_statement.ColumnInt(2);
    if (blacklisted_by_user)
      continue;

    if (IsValidAndroidFacetURI(signon_realm)) {
      ++android_logins;
    } else if (origin_url.SchemeIs(url::kHttpsScheme)) {
      ++https_logins;
    } else if (origin_url.SchemeIs(url::kHttpScheme)) {
      ++http_logins;
    } else if (origin_url.SchemeIs(url::kFtpScheme)) {
      ++ftp_logins;
    } else {
      ++other_logins;
    }
  }

  LogNumberOfAccountsForScheme("Android", android_logins);
  LogNumberOfAccountsForScheme("Ftp", ftp_logins);
  LogNumberOfAccountsForScheme("Http", http_logins);
  LogNumberOfAccountsForScheme("Https", https_logins);
  LogNumberOfAccountsForScheme("Other", other_logins);

  sql::Statement form_based_passwords_statement(
      db_.GetUniqueStatement("SELECT signon_realm, password_value FROM logins "
                             "WHERE blacklisted_by_user = 0 AND scheme = 0"));

  std::map<base::string16, std::vector<std::string>> passwords_to_realms;
  while (form_based_passwords_statement.Step()) {
    std::string signon_realm = form_based_passwords_statement.ColumnString(0);
    base::string16 decrypted_password;
    // Note that CryptProtectData() is non-deterministic, so passwords must be
    // decrypted before checking equality.
    if (!IsValidAndroidFacetURI(signon_realm) &&
        DecryptedString(form_based_passwords_statement.ColumnString(1),
                        &decrypted_password) == ENCRYPTION_RESULT_SUCCESS) {
      passwords_to_realms[decrypted_password].push_back(signon_realm);
    }
  }

  for (const auto& password_to_realms : passwords_to_realms)
    LogPasswordReuseMetrics(password_to_realms.second);
}

PasswordStoreChangeList LoginDatabase::AddLogin(const PasswordForm& form) {
  PasswordStoreChangeList list;
  if (!DoesMatchConstraints(form))
    return list;
  std::string encrypted_password;
  if (EncryptedString(
          clear_password_values_ ? base::string16() : form.password_value,
          &encrypted_password) != ENCRYPTION_RESULT_SUCCESS)
    return list;

  DCHECK(!add_statement_.empty());
  sql::Statement s(
      db_.GetCachedStatement(SQL_FROM_HERE, add_statement_.c_str()));
  BindAddStatement(form, encrypted_password, &s);
  db_.set_error_callback(base::Bind(&AddCallback));
  const bool success = s.Run();
  db_.reset_error_callback();
  if (success) {
    list.push_back(PasswordStoreChange(PasswordStoreChange::ADD, form));
    return list;
  }
  // Repeat the same statement but with REPLACE semantic.
  DCHECK(!add_replace_statement_.empty());
  s.Assign(
      db_.GetCachedStatement(SQL_FROM_HERE, add_replace_statement_.c_str()));
  BindAddStatement(form, encrypted_password, &s);
  if (s.Run()) {
    list.push_back(PasswordStoreChange(PasswordStoreChange::REMOVE, form));
    list.push_back(PasswordStoreChange(PasswordStoreChange::ADD, form));
  }
  return list;
}

PasswordStoreChangeList LoginDatabase::UpdateLogin(const PasswordForm& form) {
  std::string encrypted_password;
  if (EncryptedString(
          clear_password_values_ ? base::string16() : form.password_value,
          &encrypted_password) != ENCRYPTION_RESULT_SUCCESS)
    return PasswordStoreChangeList();

#if defined(OS_IOS)
  DeleteEncryptedPassword(form);
#endif
  // Replacement is necessary to deal with updating imported credentials. See
  // crbug.com/349138 for details.
  DCHECK(!update_statement_.empty());
  sql::Statement s(
      db_.GetCachedStatement(SQL_FROM_HERE, update_statement_.c_str()));
  s.BindString(0, form.action.spec());
  s.BindBlob(1, encrypted_password.data(),
             static_cast<int>(encrypted_password.length()));
  s.BindString16(2, form.submit_element);
  s.BindInt(3, form.preferred);
  s.BindInt64(4, form.date_created.ToInternalValue());
  s.BindInt(5, form.blacklisted_by_user);
  s.BindInt(6, form.scheme);
  s.BindInt(7, form.type);
  base::Pickle pickle = SerializeVector(form.other_possible_usernames);
  s.BindBlob(8, pickle.data(), pickle.size());
  s.BindInt(9, form.times_used);
  base::Pickle form_data_pickle;
  autofill::SerializeFormData(form.form_data, &form_data_pickle);
  s.BindBlob(10, form_data_pickle.data(), form_data_pickle.size());
  s.BindInt64(11, form.date_synced.ToInternalValue());
  s.BindString16(12, form.display_name);
  s.BindString(13, form.icon_url.spec());
  // An empty Origin serializes as "null" which would be strange to store here.
  s.BindString(14, form.federation_origin.unique()
                       ? std::string()
                       : form.federation_origin.Serialize());
  s.BindInt(15, form.skip_zero_click);
  s.BindInt(16, form.generation_upload_status);

  // WHERE starts here.
  s.BindString(17, form.origin.spec());
  s.BindString16(18, form.username_element);
  s.BindString16(19, form.username_value);
  s.BindString16(20, form.password_element);
  s.BindString(21, form.signon_realm);

  if (!s.Run())
    return PasswordStoreChangeList();

  PasswordStoreChangeList list;
  if (db_.GetLastChangeCount())
    list.push_back(PasswordStoreChange(PasswordStoreChange::UPDATE, form));

  return list;
}

bool LoginDatabase::RemoveLogin(const PasswordForm& form) {
  if (form.is_public_suffix_match) {
    // TODO(dvadym): Discuss whether we should allow to remove PSL matched
    // credentials.
    return false;
  }
#if defined(OS_IOS)
  DeleteEncryptedPassword(form);
#endif
  // Remove a login by UNIQUE-constrained fields.
  DCHECK(!delete_statement_.empty());
  sql::Statement s(
      db_.GetCachedStatement(SQL_FROM_HERE, delete_statement_.c_str()));
  s.BindString(0, form.origin.spec());
  s.BindString16(1, form.username_element);
  s.BindString16(2, form.username_value);
  s.BindString16(3, form.password_element);
  s.BindString(4, form.signon_realm);

  return s.Run() && db_.GetLastChangeCount() > 0;
}

bool LoginDatabase::RemoveLoginsCreatedBetween(base::Time delete_begin,
                                               base::Time delete_end) {
#if defined(OS_IOS)
  std::vector<std::unique_ptr<PasswordForm>> forms;
  if (GetLoginsCreatedBetween(delete_begin, delete_end, &forms)) {
    for (size_t i = 0; i < forms.size(); i++) {
      DeleteEncryptedPassword(*forms[i]);
    }
  }
#endif

  sql::Statement s(db_.GetCachedStatement(SQL_FROM_HERE,
      "DELETE FROM logins WHERE "
      "date_created >= ? AND date_created < ?"));
  s.BindInt64(0, delete_begin.ToInternalValue());
  s.BindInt64(1, delete_end.is_null() ? std::numeric_limits<int64_t>::max()
                                      : delete_end.ToInternalValue());

  return s.Run();
}

bool LoginDatabase::RemoveLoginsSyncedBetween(base::Time delete_begin,
                                              base::Time delete_end) {
  sql::Statement s(db_.GetCachedStatement(
      SQL_FROM_HERE,
      "DELETE FROM logins WHERE date_synced >= ? AND date_synced < ?"));
  s.BindInt64(0, delete_begin.ToInternalValue());
  s.BindInt64(1,
              delete_end.is_null() ? base::Time::Max().ToInternalValue()
                                   : delete_end.ToInternalValue());

  return s.Run();
}

bool LoginDatabase::GetAutoSignInLogins(
    std::vector<std::unique_ptr<PasswordForm>>* forms) const {
  DCHECK(forms);
  DCHECK(!autosignin_statement_.empty());
  sql::Statement s(
      db_.GetCachedStatement(SQL_FROM_HERE, autosignin_statement_.c_str()));

  return StatementToForms(&s, nullptr, forms);
}

bool LoginDatabase::DisableAutoSignInForOrigin(const GURL& origin) {
  sql::Statement s(db_.GetCachedStatement(
      SQL_FROM_HERE,
      "UPDATE logins SET skip_zero_click = 1 WHERE origin_url = ?;"));
  s.BindString(0, origin.spec());

  return s.Run();
}

// static
LoginDatabase::EncryptionResult LoginDatabase::InitPasswordFormFromStatement(
    PasswordForm* form,
    const sql::Statement& s) {
  std::string encrypted_password;
  s.ColumnBlobAsString(COLUMN_PASSWORD_VALUE, &encrypted_password);
  base::string16 decrypted_password;
  EncryptionResult encryption_result =
      DecryptedString(encrypted_password, &decrypted_password);
  if (encryption_result != ENCRYPTION_RESULT_SUCCESS) {
    VLOG(0) << "Password decryption failed, encryption_result is "
            << encryption_result;
    return encryption_result;
  }

  std::string tmp = s.ColumnString(COLUMN_ORIGIN_URL);
  form->origin = GURL(tmp);
  tmp = s.ColumnString(COLUMN_ACTION_URL);
  form->action = GURL(tmp);
  form->username_element = s.ColumnString16(COLUMN_USERNAME_ELEMENT);
  form->username_value = s.ColumnString16(COLUMN_USERNAME_VALUE);
  form->password_element = s.ColumnString16(COLUMN_PASSWORD_ELEMENT);
  form->password_value = decrypted_password;
  form->submit_element = s.ColumnString16(COLUMN_SUBMIT_ELEMENT);
  tmp = s.ColumnString(COLUMN_SIGNON_REALM);
  form->signon_realm = tmp;
  form->preferred = (s.ColumnInt(COLUMN_PREFERRED) > 0);
  form->date_created =
      base::Time::FromInternalValue(s.ColumnInt64(COLUMN_DATE_CREATED));
  form->blacklisted_by_user = (s.ColumnInt(COLUMN_BLACKLISTED_BY_USER) > 0);
  int scheme_int = s.ColumnInt(COLUMN_SCHEME);
  DCHECK_LE(0, scheme_int);
  DCHECK_GE(PasswordForm::SCHEME_LAST, scheme_int);
  form->scheme = static_cast<PasswordForm::Scheme>(scheme_int);
  int type_int = s.ColumnInt(COLUMN_PASSWORD_TYPE);
  DCHECK(type_int >= 0 && type_int <= PasswordForm::TYPE_LAST) << type_int;
  form->type = static_cast<PasswordForm::Type>(type_int);
  if (s.ColumnByteLength(COLUMN_POSSIBLE_USERNAMES)) {
    base::Pickle pickle(
        static_cast<const char*>(s.ColumnBlob(COLUMN_POSSIBLE_USERNAMES)),
        s.ColumnByteLength(COLUMN_POSSIBLE_USERNAMES));
    form->other_possible_usernames = DeserializeVector(pickle);
  }
  form->times_used = s.ColumnInt(COLUMN_TIMES_USED);
  if (s.ColumnByteLength(COLUMN_FORM_DATA)) {
    base::Pickle form_data_pickle(
        static_cast<const char*>(s.ColumnBlob(COLUMN_FORM_DATA)),
        s.ColumnByteLength(COLUMN_FORM_DATA));
    base::PickleIterator form_data_iter(form_data_pickle);
    bool success =
        autofill::DeserializeFormData(&form_data_iter, &form->form_data);
    metrics_util::FormDeserializationStatus status =
        success ? metrics_util::LOGIN_DATABASE_SUCCESS
                : metrics_util::LOGIN_DATABASE_FAILURE;
    metrics_util::LogFormDataDeserializationStatus(status);
  }
  form->date_synced =
      base::Time::FromInternalValue(s.ColumnInt64(COLUMN_DATE_SYNCED));
  form->display_name = s.ColumnString16(COLUMN_DISPLAY_NAME);
  form->icon_url = GURL(s.ColumnString(COLUMN_ICON_URL));
  form->federation_origin =
      url::Origin(GURL(s.ColumnString(COLUMN_FEDERATION_URL)));
  form->skip_zero_click = (s.ColumnInt(COLUMN_SKIP_ZERO_CLICK) > 0);
  int generation_upload_status_int =
      s.ColumnInt(COLUMN_GENERATION_UPLOAD_STATUS);
  DCHECK(generation_upload_status_int >= 0 &&
         generation_upload_status_int <= PasswordForm::UNKNOWN_STATUS);
  form->generation_upload_status =
      static_cast<PasswordForm::GenerationUploadStatus>(
          generation_upload_status_int);
  return ENCRYPTION_RESULT_SUCCESS;
}

bool LoginDatabase::GetLogins(
    const PasswordStore::FormDigest& form,
    std::vector<std::unique_ptr<PasswordForm>>* forms) const {
  DCHECK(forms);
  const GURL signon_realm(form.signon_realm);
  std::string registered_domain = GetRegistryControlledDomain(signon_realm);
  const bool should_PSL_matching_apply =
      form.scheme == PasswordForm::SCHEME_HTML &&
      ShouldPSLDomainMatchingApply(registered_domain);
  const bool should_federated_apply = form.scheme == PasswordForm::SCHEME_HTML;
  DCHECK(!get_statement_.empty());
  DCHECK(!get_statement_psl_.empty());
  DCHECK(!get_statement_federated_.empty());
  DCHECK(!get_statement_psl_federated_.empty());
  const std::string* sql_query = &get_statement_;
  if (should_PSL_matching_apply && should_federated_apply)
    sql_query = &get_statement_psl_federated_;
  else if (should_PSL_matching_apply)
    sql_query = &get_statement_psl_;
  else if (should_federated_apply)
    sql_query = &get_statement_federated_;

  // TODO(nyquist) Consider usage of GetCachedStatement when
  // http://crbug.com/248608 is fixed.
  sql::Statement s(db_.GetUniqueStatement(sql_query->c_str()));
  s.BindString(0, form.signon_realm);
  int placeholder = 1;

  // PSL matching only applies to HTML forms.
  if (should_PSL_matching_apply) {
    // We are extending the original SQL query with one that includes more
    // possible matches based on public suffix domain matching. Using a regexp
    // here is just an optimization to not have to parse all the stored entries
    // in the |logins| table. The result (scheme, domain and port) is verified
    // further down using GURL. See the functions SchemeMatches,
    // RegistryControlledDomainMatches and PortMatches.
    // We need to escape . in the domain. Since the domain has already been
    // sanitized using GURL, we do not need to escape any other characters.
    base::ReplaceChars(registered_domain, ".", "\\.", &registered_domain);
    std::string scheme = signon_realm.scheme();
    // We need to escape . in the scheme. Since the scheme has already been
    // sanitized using GURL, we do not need to escape any other characters.
    // The scheme soap.beep is an example with '.'.
    base::ReplaceChars(scheme, ".", "\\.", &scheme);
    const std::string port = signon_realm.port();
    // For a signon realm such as http://foo.bar/, this regexp will match
    // domains on the form http://foo.bar/, http://www.foo.bar/,
    // http://www.mobile.foo.bar/. It will not match http://notfoo.bar/.
    // The scheme and port has to be the same as the observed form.
    std::string regexp = "^(" + scheme + ":\\/\\/)([\\w-]+\\.)*" +
                         registered_domain + "(:" + port + ")?\\/$";
    s.BindString(placeholder++, regexp);

    if (should_federated_apply) {
      // This regex matches any subdomain of |registered_domain|, in particular
      // it matches the empty subdomain. Hence exact domain matches are also
      // retrieved.
      s.BindString(placeholder++,
                   "^federation://([\\w-]+\\.)*" + registered_domain + "/.+$");
    }
  } else if (should_federated_apply) {
    std::string expression =
        base::StringPrintf("federation://%s/%%", form.origin.host().c_str());
    s.BindString(placeholder++, expression);
  }

  if (!should_PSL_matching_apply && !should_federated_apply) {
    // Otherwise the histogram is reported in StatementToForms.
    UMA_HISTOGRAM_ENUMERATION("PasswordManager.PslDomainMatchTriggering",
                              PSL_DOMAIN_MATCH_NOT_USED,
                              PSL_DOMAIN_MATCH_COUNT);
  }

  bool success = StatementToForms(
      &s, should_PSL_matching_apply || should_federated_apply ? &form : nullptr,
      forms);
  if (success)
    return true;
  forms->clear();
  return false;
}

bool LoginDatabase::GetLoginsCreatedBetween(
    const base::Time begin,
    const base::Time end,
    std::vector<std::unique_ptr<PasswordForm>>* forms) const {
  DCHECK(forms);
  DCHECK(!created_statement_.empty());
  sql::Statement s(
      db_.GetCachedStatement(SQL_FROM_HERE, created_statement_.c_str()));
  s.BindInt64(0, begin.ToInternalValue());
  s.BindInt64(1, end.is_null() ? std::numeric_limits<int64_t>::max()
                               : end.ToInternalValue());

  return StatementToForms(&s, nullptr, forms);
}

bool LoginDatabase::GetLoginsSyncedBetween(
    const base::Time begin,
    const base::Time end,
    std::vector<std::unique_ptr<PasswordForm>>* forms) const {
  DCHECK(forms);
  DCHECK(!synced_statement_.empty());
  sql::Statement s(
      db_.GetCachedStatement(SQL_FROM_HERE, synced_statement_.c_str()));
  s.BindInt64(0, begin.ToInternalValue());
  s.BindInt64(1,
              end.is_null() ? base::Time::Max().ToInternalValue()
                            : end.ToInternalValue());

  return StatementToForms(&s, nullptr, forms);
}

bool LoginDatabase::GetAutofillableLogins(
    std::vector<std::unique_ptr<PasswordForm>>* forms) const {
  return GetAllLoginsWithBlacklistSetting(false, forms);
}

bool LoginDatabase::GetBlacklistLogins(
    std::vector<std::unique_ptr<PasswordForm>>* forms) const {
  return GetAllLoginsWithBlacklistSetting(true, forms);
}

bool LoginDatabase::GetAllLoginsWithBlacklistSetting(
    bool blacklisted,
    std::vector<std::unique_ptr<PasswordForm>>* forms) const {
  DCHECK(forms);
  DCHECK(!blacklisted_statement_.empty());
  sql::Statement s(
      db_.GetCachedStatement(SQL_FROM_HERE, blacklisted_statement_.c_str()));
  s.BindInt(0, blacklisted ? 1 : 0);

  bool success = StatementToForms(&s, nullptr, forms);
  if (success)
    return true;
  forms->clear();
  return false;
}

bool LoginDatabase::DeleteAndRecreateDatabaseFile() {
  DCHECK(db_.is_open());
  meta_table_.Reset();
  db_.Close();
  sql::Connection::Delete(db_path_);
  return Init();
}

std::string LoginDatabase::GetEncryptedPassword(
    const PasswordForm& form) const {
  DCHECK(!encrypted_statement_.empty());
  sql::Statement s(
      db_.GetCachedStatement(SQL_FROM_HERE, encrypted_statement_.c_str()));

  s.BindString(0, form.origin.spec());
  s.BindString16(1, form.username_element);
  s.BindString16(2, form.username_value);
  s.BindString16(3, form.password_element);
  s.BindString(4, form.signon_realm);

  std::string encrypted_password;
  if (s.Step()) {
    s.ColumnBlobAsString(0, &encrypted_password);
  }
  return encrypted_password;
}

// static
bool LoginDatabase::StatementToForms(
    sql::Statement* statement,
    const PasswordStore::FormDigest* matched_form,
    std::vector<std::unique_ptr<PasswordForm>>* forms) {
  PSLDomainMatchMetric psl_domain_match_metric = PSL_DOMAIN_MATCH_NONE;

  forms->clear();
  while (statement->Step()) {
    auto new_form = base::MakeUnique<PasswordForm>();
    EncryptionResult result =
        InitPasswordFormFromStatement(new_form.get(), *statement);
    if (result == ENCRYPTION_RESULT_SERVICE_FAILURE)
      return false;
    if (result == ENCRYPTION_RESULT_ITEM_FAILURE)
      continue;
    DCHECK_EQ(ENCRYPTION_RESULT_SUCCESS, result);
    if (matched_form && matched_form->signon_realm != new_form->signon_realm) {
      if (new_form->scheme != PasswordForm::SCHEME_HTML)
        continue;  // Ignore non-HTML matches.

      if (IsPublicSuffixDomainMatch(new_form->signon_realm,
                                    matched_form->signon_realm)) {
        psl_domain_match_metric = PSL_DOMAIN_MATCH_FOUND;
        new_form->is_public_suffix_match = true;
      } else if (!new_form->federation_origin.unique() &&
                 IsFederatedMatch(new_form->signon_realm,
                                  matched_form->origin)) {
      } else if (!new_form->federation_origin.unique() &&
                 IsFederatedPSLMatch(new_form->signon_realm,
                                     matched_form->origin)) {
        psl_domain_match_metric = PSL_DOMAIN_MATCH_FOUND_FEDERATED;
        new_form->is_public_suffix_match = true;
      } else {
        continue;
      }
    }
    forms->push_back(std::move(new_form));
  }

  if (matched_form) {
    UMA_HISTOGRAM_ENUMERATION("PasswordManager.PslDomainMatchTriggering",
                              psl_domain_match_metric, PSL_DOMAIN_MATCH_COUNT);
  }

  if (!statement->Succeeded())
    return false;
  return true;
}

void LoginDatabase::InitializeStatementStrings(const SQLTableBuilder& builder) {
  // This method may be called multiple times, if Chrome switches backends and
  // LoginDatabase::DeleteAndRecreateDatabaseFile ends up being called. In those
  // case do not recompute the SQL statements, because they would end up the
  // same.
  if (!add_statement_.empty())
    return;

  // Initialize the cached strings.
  std::string all_column_names = builder.ListAllColumnNames();
  std::string right_amount_of_placeholders =
      GeneratePlaceholders(builder.NumberOfColumns());
  std::string all_unique_key_column_names = builder.ListAllUniqueKeyNames();
  std::string all_nonunique_key_column_names =
      builder.ListAllNonuniqueKeyNames();

  add_statement_ = "INSERT INTO logins (" + all_column_names + ") VALUES " +
                   right_amount_of_placeholders;
  DCHECK(add_replace_statement_.empty());
  add_replace_statement_ = "INSERT OR REPLACE INTO logins (" +
                           all_column_names + ") VALUES " +
                           right_amount_of_placeholders;
  DCHECK(update_statement_.empty());
  update_statement_ = "UPDATE OR REPLACE logins SET " +
                      all_nonunique_key_column_names + " WHERE " +
                      all_unique_key_column_names;
  DCHECK(delete_statement_.empty());
  delete_statement_ = "DELETE FROM logins WHERE " + all_unique_key_column_names;
  DCHECK(autosignin_statement_.empty());
  autosignin_statement_ = "SELECT " + all_column_names +
                          " FROM logins "
                          "WHERE skip_zero_click = 0 ORDER BY origin_url";
  DCHECK(get_statement_.empty());
  get_statement_ = "SELECT " + all_column_names +
                   " FROM logins "
                   "WHERE signon_realm == ?";
  std::string psl_statement = "OR signon_realm REGEXP ? ";
  std::string federated_statement =
      "OR (signon_realm LIKE ? AND password_type == 2) ";
  std::string psl_federated_statement =
      "OR (signon_realm REGEXP ? AND password_type == 2) ";
  DCHECK(get_statement_psl_.empty());
  get_statement_psl_ = get_statement_ + psl_statement;
  DCHECK(get_statement_federated_.empty());
  get_statement_federated_ = get_statement_ + federated_statement;
  DCHECK(get_statement_psl_federated_.empty());
  get_statement_psl_federated_ =
      get_statement_ + psl_statement + psl_federated_statement;
  DCHECK(created_statement_.empty());
  created_statement_ =
      "SELECT " + all_column_names +
      " FROM logins WHERE date_created >= ? AND date_created < "
      "? ORDER BY origin_url";
  DCHECK(synced_statement_.empty());
  synced_statement_ = "SELECT " + all_column_names +
                      " FROM logins WHERE date_synced >= ? AND date_synced < "
                      "? ORDER BY origin_url";
  DCHECK(blacklisted_statement_.empty());
  blacklisted_statement_ =
      "SELECT " + all_column_names +
      " FROM logins WHERE blacklisted_by_user == ? ORDER BY origin_url";
  DCHECK(encrypted_statement_.empty());
  encrypted_statement_ =
      "SELECT password_value FROM logins WHERE " + all_unique_key_column_names;
}

}  // namespace password_manager


text:
module Sprout

  module Executable

    ##
    # A collection of Paths.
    #
    # @see Sprout::Executable::Path
    # @see Sprout::Executable::Param
    # @see Sprout::Executable::CollectionParam
    #
    class Paths < Files

      def prepare_prerequisites
        value.each do |path|
          files = FileList[path + file_expression]
          files.each do |f|
            Rake::FileTask.define_task f
            belongs_to.prerequisites << f
          end
        end
      end
    end
  end
end

redpajama_set_name: RedPajamaGithub


text:
#include "avmplus.h"

namespace avmplus
{
	//
	// XMLParser
	//

	bool XMLParser::skipWhiteSpace()
	{
		bool eof = atEnd();
		while (!eof)
		{
			wchar ch = m_str[m_pos];
			if (!String::isSpace(ch))
				break;
			m_pos++;
			eof = atEnd();
		}
		return !eof;
	}

	// !!@ I'm not sure what this was supposed to do originally but I've rewritten it
	// to remove the leading and trailing white space for text elements.
	// "     5     4     3     " becomes "5     4     3"
	// This is to simulate the E4X XML parser
	static Stringp _condenseWhitespace(Stringp text)
	{
		StringIndexer str (text);
		// leading space
		int32_t start = 0;
		while (start < text->length() && String::isSpace(str[start]))
			start++;
		// trailing space
		int32_t end = text->length() - 1;
		while ((end > start) && String::isSpace(str[end]))
			end--;
		return text->substring(start, end + 1);
	}

	int XMLParser::getNext(XMLTag& tag)
	{
		wchar ch;
		int32_t start, end;
		tag.reset();

		// If there's nothing left, exit.
		if (atEnd()) {
			return XMLParser::kEndOfDocument;
		}

		// R41
		// If the ignore whitespace flag is on, don't produce
		// all-whitespace text nodes.
		if (m_ignoreWhite)
		{
			if (!skipWhiteSpace())
				return XMLParser::kEndOfDocument;
		}
		// end R41

		// If it starts with <, it's an XML element.
		// If it doesn't, it must be a text element.
		start = m_pos;
		ch = m_str[m_pos];
		if (ch != '<')
		{
			// Treat it as text.  Scan up to the next < or until EOF.
			m_pos = m_str->indexOfLatin1("<", 1, m_pos + 1);
			if (m_pos < 0)
				m_pos = m_str->length();

			tag.text = unescape(start, m_pos, false);

			// Condense whitespace if desired
			if (m_ignoreWhite && m_condenseWhite)
				tag.text = _condenseWhitespace(tag.text);

			tag.nodeType = XMLTag::kTextNodeType;
			return XMLParser::kNoError;
		}

		// Is this a <?xml> declaration?
		start = m_pos;
		if (m_str->matchesLatin1("<?xml ", 6, start))
		{
			end = m_str->indexOfLatin1("?>", 2, start + 6);
			if (end >= 0)
			{
				// We have the end of the XML declaration
				// !!@ changed to not return <?...?> parts
				tag.text = m_str->substring(start + 2, end);
				m_pos = end + 2;
				tag.nodeType = XMLTag::kXMLDeclaration;
				return XMLParser::kNoError;
			}
			return XMLParser::kUnterminatedXMLDeclaration;
		}

		// Is this a <!DOCTYPE> declaration?
		if (m_str->matchesLatin1("<!DOCTYPE", 8, start))
		{
			// Scan forward for '>', but check for embedded <>
			int32_t depth = 0;
			end = start + 1;
			while (!atEnd())
			{
				ch = m_str[end++];
				if (ch == '<')
					depth++;
				else if (ch == '>')
				{
					if (!depth)
					{
						// We've reached the end of the DOCTYPE.
						tag.text = m_str->substring(start, end - 1);
						tag.nodeType = XMLTag::kDocTypeDeclaration;
						m_pos = end;
						return XMLParser::kNoError;
					}
					depth--;
				}
				m_pos = end;
			}
			return XMLParser::kUnterminatedDocTypeDeclaration;
		}

		// Is this a CDATA section?
		if (m_str->matchesLatin1("<![CDATA[", 9, start))
		{
			start += 9;
			end = m_str->indexOfLatin1("]]>", 3, start);
			if (end >= 0)
			{
				// We have the end of the CDATA section.
				tag.text = m_str->substring(start, end);
				tag.nodeType = XMLTag::kCDataSection;
				m_pos = end + 3;
				return XMLParser::kNoError;
			}
			return XMLParser::kUnterminatedCDataSection;
		}

		// Is this a processing instruction?
		if (m_str->matchesLatin1("<?", 2, start))
		{
			// Scan forward for "?>"
			start += 2;
			end = m_str->indexOfLatin1("?>", 2, start);
			if (end >= 0)
			{
				// We have the end of the processing instruction.
				tag.text = m_str->substring(start, end);
				tag.nodeType = XMLTag::kProcessingInstruction;
				m_pos = end + 2;
				return XMLParser::kNoError;
			}
			return XMLParser::kUnterminatedProcessingInstruction;
		}

		// Advance past the "<"
		start = ++m_pos;

		// Is this a comment?  Return a comment tag->
		if (m_str->matchesLatin1("!--", 3, start))
		{
			// Skip up to '-->'.
			start += 3;
			end = m_str->indexOfLatin1("-->", 3, start);
			if (end >= 0)
			{
				tag.text = m_str->substring(start, end);
				tag.nodeType = XMLTag::kComment;
				m_pos = end  + 3;
				return XMLParser::kNoError;
			}
			// Got to the end of the buffer without finding a new tag->
			return XMLParser::kUnterminatedComment;
		}

		// Extract the tag name.  Scan up to ">" or whitespace.
		start = m_pos;
		while (!atEnd())
		{
			ch = m_str[m_pos];
			if (ch == '>' || String::isSpace(ch))
				break;
			if (ch == '/' && (m_pos < m_str->length() - 1) && m_str[m_pos+1] == '>')
			{
				// Found close of an empty element.
				// Exit!
				break;
			}
			m_pos++;
		}
		if (atEnd() || m_pos == start)
			// Premature end, or empty tag name
			return XMLParser::kMalformedElement;

		tag.text = unescape(start, m_pos, true);
		tag.nodeType = XMLTag::kElementType;

		// Extract attributes.
		for (;;)
		{
			if (!skipWhiteSpace())
				// Premature end!
				return XMLParser::kMalformedElement;

			ch = m_str[m_pos];
			if (ch == '>')
				break;

			if (ch == '/' && (m_pos < m_str->length() - 1) && m_str[m_pos+1] == '>')
			{
				// Found close of an empty element.
				// Exit!
				tag.empty = true;
				ch = m_str[++m_pos];
				break;
			}

			// Extract the attribute name.
			start = m_pos;
			while (!String::isSpace(ch) && ch != '=' && ch != '>')
			{
				if (atEnd())
					// Premature end!
					return XMLParser::kMalformedElement;
				ch = m_str[++m_pos];
			}
			if (start == m_pos)
				// Empty attribute name?
				return XMLParser::kMalformedElement;

			Stringp attributeName = unescape(start, m_pos, true);

			if (!skipWhiteSpace())
				// No attribute value, error!
				return XMLParser::kMalformedElement;

			ch = m_str[m_pos++];
			if (ch != '=')
				// No attribute value, error!
				return XMLParser::kMalformedElement;

			if (!skipWhiteSpace())
				// No attribute value, error!
				return XMLParser::kMalformedElement;

			wchar delimiter = m_str[m_pos++];
			// Extract the attribute value.
			if (delimiter != '"' && delimiter != '\'')
				// Error; no opening quote for attribute value.
				return XMLParser::kMalformedElement;

			// Extract up to the next quote.
			start = m_pos;
			ch = 0;
			while (ch != delimiter)
			{
				if (atEnd() || ch == '<')
					// '<' is not permitted in an attribute value
					// Changed this from kMalformedElement to kUnterminatedAttributeValue for bug 117058(105422)
					return XMLParser::kUnterminatedAttributeValue;
				ch = m_str[m_pos++];
			}

			Stringp attributeValue = unescape(start, m_pos - 1, false);

			AvmAssert(attributeName->isInterned());
			tag.attributes.add(attributeName);
			tag.attributes.add(attributeValue);
		}

		// Advance past the end > of this element.
		if (ch == '>')
			m_pos++;

		return XMLParser::kNoError;
	}

	Stringp XMLParser::unescape(int32_t start, int32_t last, bool bIntern)
	{
		if (start == last)
			return core->kEmptyString;

		int32_t bgn = m_str->indexOfLatin1("&", 1, start, last);
		int32_t end = start;
		Stringp dest = core->kEmptyString;
		while (bgn >= start && bgn < last)
		{
			int32_t ampEnd = m_str->indexOfLatin1(";", 1, ++bgn, last);
			if (ampEnd < 0)
				// &xxx without semicolon - we are done
				break;
			// add the text between the last sequence and this sequence
			dest = String::concatStrings(dest, m_str->substring(end, bgn-1));
			end = ampEnd;
			int32_t len = end - bgn;
			// an &xx; sequence is at least two characters
			bool ok = true;
			if (len >= 2)
			{
				int32_t ch = m_str[bgn];
				if (ch == '#')
				{
					// Parse a &#xx; decimal sequence.  Or a &#xDD hex sequence
					ch = m_str[++bgn];
					len--;
					int base = 10;
					if (len >= 2 && ch == 'x')
						base = 16, bgn++, len--;
					if (len > 0)
					{
						int32_t value = 0;
						while (len-- && ok)
						{
							ch = m_str[bgn++];
							if (ch >= 'A' && ch <= 'F')
								ch -= 7;
							ch -= '0';
							if (ch >= 0 && ch < base)
								value = (value * base) + ch;
							else
								ok = false;
							if (value > 0xFFFF)
								ok = false;
						}
						if (ok)
						{
							wchar c = (wchar) value;
							// note: this code is allowed to construct a string
							// containing illegal UTF16 sequences!
							dest = dest->append16(&c, 1);
							bgn = ++end;
						}
					}
				}
				else if (len <= 4) // Our xmlEntities are only 4 characters or less
				{
					Atom entityAtom = core->internString(m_str->substring(bgn, end))->atom();
					Atom result = core->xmlEntities->get(entityAtom);
					if (result != undefinedAtom)
					{
						AvmAssert(atomKind(result) == kIntegerType);
						wchar c = (wchar) (result>>3);
						// note: this code is allowed to construct a string
						// containing illegal UTF16 sequences!
						dest = dest->append16(&c, 1);
						bgn = ++end;
					}
					else
						ok = false;
				}
				else
					ok = false;
			}
			if (!ok)
				bgn = end + 1;
			bgn = m_str->indexOfLatin1("&", 1, bgn, last);
		}
		// add any remaining text
		if (end < last)
			dest = String::concatStrings(dest, m_str->substring(end, last));

		return (bIntern) ? core->internString(dest) : dest;
	}

	XMLParser::XMLParser(AvmCore *core, Stringp str) : m_str (str), m_pos (0)
	{
		this->core = core;

		if (!core->xmlEntities)
		{
			// Lazy creation of the XML entities table.
			core->xmlEntities = new (core->GetGC()) Hashtable(core->GetGC());

			const char *entities = "&amp\0\"quot\0'apos\0<lt\0>gt\0\xA0nbsp\0";

			while (*entities)
			{
				core->xmlEntities->add(core->internConstantStringLatin1(entities+1)->atom(),
							   (void*)core->intToAtom(*entities));
				while (*entities++) {
					// do nothing
				}
			}
		}
	}

	void XMLParser::parse(bool ignoreWhite /*=false*/ )
	{
		m_pos = 0;
		m_ignoreWhite = ignoreWhite;
	}

	bool XMLTag::nextAttribute(uint32& index,
							   Stringp& name,
							   Stringp& value)
	{
		if (index >= attributes.size()) {
			return false;
		}
		name  = attributes.get(index++);
		value = attributes.get(index++);
		return true;
	}

} // namespace


text:
title: Salimos en Hobby Consolas
header:
  overlay_image: /img/2014/02/HobbyConsolasMarzo2014Header.jpg
layout: single
categories:
- General
- Personal
tags:
- General
---
Ayer salió un nuevo número de la revista Hobby Consolas, un número un tanto especial:
Dedican un reportaje de seis páginas a la escena del romhacking en España y el resto
del mundo.

En dicho reportaje se hace mención a muchos de los proyectos que la comunidad hispana
lleva a cabo, entre ellos varios que tienen su hogar en esta web: Shenmue, Resident Evil,
The 3rd Birthday...

Incluso hay una mención destacada a The World Ends With You, por ser de las primeras
traducciones en incluir un doblaje completo del juego (Ver cuadro rojo).

Pero no habría sido posible sin todos vosotros. Sin todos aquellos que habéis puesto vuestro
granito (o granazo) de arena para conseguir que estos proyectos salgan a la luz. Puede que
Traducciones del Tío Víctor solo mencione al Tío Víctor, pero nadie debería olvidar que esta
web no es de una persona, sino de un colectivo de personas interesadas en traeros aquellos
juegos que no tuvieron una localización oficial.

Quiero dar las gracias a Alberto Lloret por su fantástico artículo, sin negatividades, lo más
neutro posible, mencionando los pros y los contras, las perspectivas de las empresas...

También quiero felicitar desde aquí a [SkyBladeCloud](http://www.skybladecloud.net/) y a
[Pablo Muñoz](http://algomasquetraducir.com/) por sus entrevistas. Os las habéis ganado.

Así que, este logro no es solo para mí, sino para todos vosotros: Para aquellos que habéis
colaborado en mis proyectos, para aquellos con los que me llevo bien, para aquellos con los
que me llevo mal, para los que habéis apoyado comentando, indicando fallos, subiendo gameplays
a YouTube; para los que habéis puesto voz, para los que habéis puesto palabra.... Gracias de
todo corazón. Esto no habría pasado si no hubiera sido por todos vosotros.

FE DE ERRATAS: En la mención al proyecto de Fatal Frame/Project Zero 4 se indica que el juego
va a ser doblado. Eso es una equivocación, PZ4 solo está subtitulado.


text:
package org.sisioh.aws4s.sns.model

import com.amazonaws.services.sns.model.SetSubscriptionAttributesRequest
import org.sisioh.aws4s.PimpedType

object SetSubscriptionAttributesRequestFactory {

  def create(): SetSubscriptionAttributesRequest =
    new SetSubscriptionAttributesRequest()

  def create(subscriptionArn: String, attributeName: String, attributeValue: String): SetSubscriptionAttributesRequest =
    new SetSubscriptionAttributesRequest(subscriptionArn, attributeName, attributeValue)
}

class RichSetSubscriptionAttributesRequest(val underlying: SetSubscriptionAttributesRequest)
    extends AnyVal
    with PimpedType[SetSubscriptionAttributesRequest] {

  def subscriptionArnOpt: Option[String] =
    Option(underlying.getSubscriptionArn)

  def subscriptionArnOpt_=(value: Option[String]): Unit =
    underlying.setSubscriptionArn(value.orNull)

  def withSubscriptionArnOpt(value: Option[String]): SetSubscriptionAttributesRequest =
    underlying.withSubscriptionArn(value.orNull)

  def attributeNameOpt: Option[String] =
    Option(underlying.getAttributeName)

  def attributeNameOpt_=(value: Option[String]): Unit =
    underlying.setAttributeName(value.orNull)

  def withAttributeNameOpt(value: Option[String]): SetSubscriptionAttributesRequest =
    underlying.withAttributeName(value.orNull)

  def attributeValueOpt: Option[String] =
    Option(underlying.getAttributeValue)

  def attributeValueOpt_=(value: Option[String]): Unit =
    underlying.setAttributeValue(value.orNull)

  def withAttributeValueOpt(value: Option[String]): SetSubscriptionAttributesRequest =
    underlying.withAttributeValue(value.orNull)

}


text:
<?php

namespace LiveTest\Packages\Runner\Listeners;

use LiveTest\Listener\Base;
use LiveTest\TestRun\Properties;
use phmLabs\Components\Annovent\Annotation\Event;

/**
 * This listener echoes the run information before the test start.
 *
 * @author Nils Langner
 */
class InfoHeader extends Base
{
    /**
     * This function echoes the default domian, start time, number of uri and number of tests.
     *
     * @Event("LiveTest.Run.PreRun")
     *
     * @param Properties $properties
     */
    public function preRun(Properties $properties)
    {
        $sessions = $properties->getTestSets();
        $uriCount = 0;
        foreach ($sessions as $testSets) {
            $uriCount += count($testSets);
        }

        $output = $this->getEventDispatcher()->getOutput();

        $output->writeln('  Default Domain  : <comment>' . $properties->getDefaultDomain()->toString().'</comment>');
        $output->writeln('  Start Time      : <comment>' . date('Y-m-d H:i:s').'</comment>');
        $output->writeln('  Number of URIs  : <comment>' . $uriCount .'</comment>');
        $output->writeln('  Number of Tests : <comment>' . $this->getTotalTestCount($properties) .'</comment>');
        $output->writeln('');
    }

    /**
     * This function returns the total number of tests defined in a given properties object.
     *
     * @param Properties $properties
     */
    private function getTotalTestCount(Properties $properties)
    {
        $count = 0;
        foreach ($properties->getTestSets() as $testSets) {
            foreach ($testSets as $testSet) {
                $count += $testSet->getTestCount();
            }
        }
        return $count;
    }
}


text:
package org.jd.jclap.options;

public class InvalidOptionLongNameException extends OptionCreationException {

    private static final long serialVersionUID = 1L;
    public static final String DEFAULT_MSG = "Option creation: invalid long name";

    public InvalidOptionLongNameException(String msg) {
        super(msg);
    }

    public InvalidOptionLongNameException() {
        super(DEFAULT_MSG);
    }
}


text:
namespace BoatRacingSimulator.Interfaces
{
    public interface IModel
    {
        string Model { get; }
    }
}


text:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FWViewModels.ViewModels
{
    public class FavoriteTruckVM
    {
        public string Id { get; set; }
        public string Title { get; set; }
        public string ImageUrl { get; set; }
    }
}


text:
package controls

import (
	"errors"
	"github.com/DirtyHairy/arduino-butler/go/util/runner"
)

type switchCommandToggle bool

type PlainSwitch struct {
	name string
	id   string

	backend    Backend
	backendIdx uint

	runner runner.T
}

func (s *PlainSwitch) Toggle(state bool) error {
	return s.runner.Dispatch(switchCommandToggle(state))
}

func (s *PlainSwitch) executeToggle(state bool) error {
	return s.backend.Toggle(s.backendIdx, state)
}

func (s *PlainSwitch) Name() string {
	return s.name
}

func (s *PlainSwitch) SetName(name string) {
	s.name = name
}

func (s *PlainSwitch) Id() string {
	return s.id
}

func (s *PlainSwitch) setId(id string) {
	s.id = id
}

func (s *PlainSwitch) setBackend(b Backend) error {
	s.backend = b

	return nil
}

func (s *PlainSwitch) setEventChannel(chan interface{}) {}

func (s *PlainSwitch) execute(c interface{}) error {
	cmd, ok := c.(switchCommandToggle)

	if !ok {
		return errors.New("invalid command")
	}

	return s.executeToggle(bool(cmd))
}

func (s *PlainSwitch) Start() error {
	return s.runner.Start()
}

func (s *PlainSwitch) Stop() error {
	return s.runner.Stop()
}

func (s *PlainSwitch) Marshal() MarshalledSwitch {
	return MarshalledSwitch{
		Id:           s.id,
		Type:         SwitchTypePlain,
		BackendId:    s.backend.Id(),
		BackendIndex: s.backendIdx,
		Name:         s.name,

		Generation: <-generationChannel,
	}
}

func CreatePlainSwitch(backendIdx uint) *PlainSwitch {
	swtch := PlainSwitch{
		backendIdx: backendIdx,
	}

	swtch.runner.Execute = swtch.execute

	return &swtch
}


text:
RSpec::Matchers.define :have_attributes do |expected|
  match do |actual|
    expected.each do |key, value|
      actual.attrs[key].should == value
    end
  end

  failure_message_for_should do |actual|
    "expected #{actual.attrs} to match #{expected}"
  end
end


text:
module WeatherObject
  module Data
    class NullRate < NullConvertableUnits
      def mm_per_hour
        nil
      end

      def in_per_hour
        nil
      end
    end
  end
end


text:
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package edu.virginia.cs.parsers;

import edu.virginia.cs.descriptors.Votes;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

/**
 *
 * @author Wasi
 */
public class ParseVotes {

    private SAXParserFactory factory;
    private SAXParser saxParser;

    public ParseVotes() {
        try {
            factory = SAXParserFactory.newInstance();
            saxParser = factory.newSAXParser();
        } catch (ParserConfigurationException | SAXException ex) {
            Logger.getLogger(ParseUsers.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void readFile(String filename) {
        try {
            File inputFile = new File(filename);
            VoteHandler voteHandler = new VoteHandler("./data/parsedData/votes.txt");
            saxParser.parse(inputFile, voteHandler);
        } catch (SAXException | IOException ex) {
            Logger.getLogger(ParseUsers.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

}

class VoteHandler extends DefaultHandler {

    private Votes vote;
    private FileWriter fwriter;

    public VoteHandler(String filename) {
        try {
            fwriter = new FileWriter(filename);
        } catch (IOException ex) {
            Logger.getLogger(UserHandler.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    @Override
    public void startElement(String uri,
            String localName, String qName, Attributes attributes)
            throws SAXException {
        if (qName.equalsIgnoreCase("votes")) {
            System.out.println("Parsing Started!!!");
        } else if (qName.equalsIgnoreCase("row")) {
            vote = new Votes();
            String id = attributes.getValue("Id");
            if (id != null) {
                vote.setId(Integer.parseInt(id));
            }
            String postId = attributes.getValue("PostId");
            if (postId != null) {
                vote.setPostId(Integer.parseInt(postId));
            }
            String creationDate = attributes.getValue("CreationDate");
            if (creationDate != null) {
                vote.setCreationDate(creationDate);
            }
            String voteTypeId = attributes.getValue("VoteTypeId");
            if (voteTypeId != null) {
                vote.setVoteTypeId(Integer.parseInt(voteTypeId));
            }
        } else {
            System.err.println("Unknown tag in the file!");
        }
    }

    @Override
    public void endElement(String uri,
            String localName, String qName) throws SAXException {
        if (qName.equalsIgnoreCase("votes")) {
            System.out.println("Parsing Completed!!!");
            try {
                fwriter.close();
            } catch (IOException ex) {
                Logger.getLogger(UserHandler.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        if (qName.equalsIgnoreCase("row")) {
            try {
                fwriter.write(vote.getId() + "\t" + vote.getPostId() + "\t" + vote.getVoteTypeId()+ "\t"
                        + vote.getCreationDate()+ "\n");
            } catch (IOException ex) {
                Logger.getLogger(UserHandler.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    @Override
    public void characters(char ch[],
            int start, int length) throws SAXException {
    }
}


text:
var cloudfront = require('..');

var cf = cloudfront.createClient(process.env.AWS_KEY, process.env.AWS_SECRET);

cf.getDistributionConfig(process.argv[2], function(err, config) {
  if (err) throw err;

  config.cname.push.apply(config.cname, process.argv.slice(3));

  console.log(config);
  console.log(cf.generateDistributionXml(config));

  cf.setDistributionConfig(process.argv[2], config, function(err, config2) {
    if (err) throw err;

    console.log(config2);
  });
});


text:
require 'test_helper'

class MenuItemsControllerTest < ActionController::TestCase
  setup do
    @menu_item = menu_items(:one)
  end

  test "should get index" do
    get :index
    assert_response :success
    assert_not_nil assigns(:menu_items)
  end

  test "should get new" do
    get :new
    assert_response :success
  end

  test "should create menu_item" do
    assert_difference('MenuItem.count') do
      post :create, menu_item: { menu_id: @menu_item.menu_id, name: @menu_item.name, price: @menu_item.price }
    end

    assert_redirected_to menu_item_path(assigns(:menu_item))
  end

  test "should show menu_item" do
    get :show, id: @menu_item
    assert_response :success
  end

  test "should get edit" do
    get :edit, id: @menu_item
    assert_response :success
  end

  test "should update menu_item" do
    patch :update, id: @menu_item, menu_item: { menu_id: @menu_item.menu_id, name: @menu_item.name, price: @menu_item.price }
    assert_redirected_to menu_item_path(assigns(:menu_item))
  end

  test "should destroy menu_item" do
    assert_difference('MenuItem.count', -1) do
      delete :destroy, id: @menu_item
    end

    assert_redirected_to menu_items_path
  end
end


text:
package jobs

import (
	"encoding/csv"
	"fmt"
	"io"
	"os"
	"path/filepath"

	"github.com/hyperledger/burrow/execution/exec"
	"github.com/hyperledger/burrow/logging"
	"github.com/hyperledger/burrow/txs/payload"
	"github.com/tmthrgd/go-hex"

	"github.com/hyperledger/burrow/deploy/def"
)

func FormulateSendJob(send *def.Send, account string, client *def.Client, logger *logging.Logger) (*payload.SendTx, error) {
	// Use Default
	send.Source = FirstOf(send.Source, account)

	// Formulate tx
	logger.InfoMsg("Sending Transaction",
		"source", send.Source,
		"destination", send.Destination,
		"amount", send.Amount)

	return client.Send(&def.SendArg{
		Input:    send.Source,
		Output:   send.Destination,
		Amount:   send.Amount,
		Sequence: send.Sequence,
	}, logger)
}

func SendJob(tx *payload.SendTx, client *def.Client, logger *logging.Logger) (string, error) {
	// Sign, broadcast, display
	txe, err := client.SignAndBroadcast(tx, logger)
	if err != nil {
		return "", fmt.Errorf("error in SendJob with payload %v: %w", tx, err)
	}

	LogTxExecution(txe, logger)
	if err != nil {
		return "", err
	}

	return txe.Receipt.TxHash.String(), nil
}

func FormulateRegisterNameJob(name *def.RegisterName, do *def.DeployArgs, playbook *def.Playbook, client *def.Client, logger *logging.Logger) ([]*payload.NameTx, error) {
	txs := make([]*payload.NameTx, 0)

	// If a data file is given it should be in csv format and
	// it will be read first. Once the file is parsed and sent
	// to the chain then a single nameRegTx will be sent if that
	// has been populated.
	if name.DataFile != "" {
		// open the file and use a reader
		var path string
		if filepath.IsAbs(name.DataFile) {
			path = name.Data
		} else {
			path = filepath.Join(playbook.Path, name.DataFile)
		}
		fileReader, err := os.Open(path)
		if err != nil {
			return nil, err
		}

		defer fileReader.Close()
		r := csv.NewReader(fileReader)

		// loop through the records
		for {
			// Read the record
			record, err := r.Read()

			// Catch the errors
			if err == io.EOF {
				break
			}
			if err != nil {
				return nil, err
			}

			// Sink the Amount into the third slot in the record if
			// it doesn't exist
			if len(record) <= 2 {
				record = append(record, name.Amount)
			}

			// Send an individual Tx for the record
			// [TODO]: move these to async using goroutines?
			r, err := registerNameTx(&def.RegisterName{
				Source:   name.Source,
				Name:     record[0],
				Data:     record[1],
				Amount:   record[2],
				Fee:      name.Fee,
				Sequence: name.Sequence,
			}, do, playbook.Account, client, logger)

			if err != nil {
				return nil, err
			}

			txs = append(txs, r)

			n := fmt.Sprintf("%s:%s", record[0], record[1])

			// TODO: write smarter
			if err = WriteJobResultCSV(n, r.String()); err != nil {
				return nil, err
			}
		}
	}

	// If the data field is populated then there is a single
	// nameRegTx to send. So do that *now*.
	if name.Data != "" {
		tx, err := registerNameTx(name, do, playbook.Account, client, logger)
		if err != nil {
			return nil, err
		}
		txs = append(txs, tx)
	}

	if len(txs) == 0 {
		return nil, fmt.Errorf("nothing to do")
	}

	return txs, nil
}

// Runs an individual nametx.
func registerNameTx(name *def.RegisterName, do *def.DeployArgs, account string, client *def.Client, logger *logging.Logger) (*payload.NameTx, error) {
	// Set Defaults
	name.Source = FirstOf(name.Source, account)
	name.Fee = FirstOf(name.Fee, do.DefaultFee)
	name.Amount = FirstOf(name.Amount, do.DefaultAmount)

	// Formulate tx
	logger.InfoMsg("NameReg Transaction",
		"name", name.Name,
		"data", name.Data,
		"amount", name.Amount)

	return client.Name(&def.NameArg{
		Input:    name.Source,
		Sequence: name.Sequence,
		Name:     name.Name,
		Amount:   name.Amount,
		Data:     name.Data,
		Fee:      name.Fee,
	}, logger)
}

func RegisterNameJob(txs []*payload.NameTx, client *def.Client, logger *logging.Logger) (string, error) {
	var result string

	for _, tx := range txs {
		// Sign, broadcast, display
		txe, err := client.SignAndBroadcast(tx, logger)
		if err != nil {
			return "", fmt.Errorf("error in RegisterNameJob with payload %v: %w", tx, err)
		}

		LogTxExecution(txe, logger)
		if err != nil {
			return "", err
		}

		result = txe.Receipt.TxHash.String()
	}
	return result, nil
}

func FormulatePermissionJob(perm *def.Permission, account string, client *def.Client, logger *logging.Logger) (*payload.PermsTx, error) {
	// Set defaults
	perm.Source = FirstOf(perm.Source, account)

	logger.TraceMsg("Permsision",
		"Target", perm.Target,
		"Marmots Deny", perm.Role,
		"Action", perm.Action)
	// Populate the transaction appropriately

	// Formulate tx
	return client.Permissions(&def.PermArg{
		Input:      perm.Source,
		Sequence:   perm.Sequence,
		Action:     perm.Action,
		Target:     perm.Target,
		Permission: perm.Permission,
		Role:       perm.Role,
		Value:      perm.Value,
	}, logger)
}

func PermissionJob(tx *payload.PermsTx, client *def.Client, logger *logging.Logger) (string, error) {
	logger.TraceMsg("Permissions returned in transaction: ", "args", tx.PermArgs)

	// Sign, broadcast, display
	txe, err := client.SignAndBroadcast(tx, logger)
	if err != nil {
		return "", fmt.Errorf("error in PermissionJob with payload %v: %w", tx, err)
	}

	LogTxExecution(txe, logger)
	if err != nil {
		return "", err
	}

	return txe.Receipt.TxHash.String(), nil
}

func FormulateIdentifyJob(id *def.Identify, account string, client *def.Client, logger *logging.Logger) (*payload.IdentifyTx, error) {
	// Use Default
	id.Source = FirstOf(id.Source, account)

	// Formulate tx
	logger.InfoMsg("Identify Transaction",
		"source", id.Source,
		"nodeKey", id.NodeKey,
		"netAddress", id.NetAddress)

	return client.Identify(&def.IdentifyArg{
		Input:      id.Source,
		Moniker:    id.Moniker,
		NodeKey:    id.NodeKey,
		NetAddress: id.NetAddress,
		Sequence:   id.Sequence,
	}, logger)
}

func IdentifyJob(tx *payload.IdentifyTx, client *def.Client, logger *logging.Logger) (string, error) {
	// Sign, broadcast, display
	txe, err := client.SignAndBroadcast(tx, logger)
	if err != nil {
		return "", fmt.Errorf("error in IdentifyJob with payload %v: %w", tx, err)
	}

	LogTxExecution(txe, logger)
	if err != nil {
		return "", err
	}

	return txe.Receipt.TxHash.String(), nil
}

func FirstOf(inputs ...string) string {
	for _, in := range inputs {
		if in != "" {
			return in
		}
	}
	return ""
}

func LogTxExecution(txe *exec.TxExecution, logger *logging.Logger) {
	// if there is nothing to unpack then just return.
	if txe == nil {
		return
	}

	// Unpack and display for the user.
	height := fmt.Sprintf("%d", txe.Height)

	if txe.Receipt.CreatesContract {
		logger.InfoMsg("Tx Return",
			"addr", txe.Receipt.ContractAddress.String(),
			"Transaction Hash", hex.EncodeToString(txe.TxHash))
	} else {
		logger.InfoMsg("Tx Return",
			"Transaction Hash", hex.EncodeToString(txe.TxHash),
			"Block Height", height)

		ret := txe.GetResult().GetReturn()
		if len(ret) != 0 {
			logger.InfoMsg("Return",
				"Return Value", hex.EncodeUpperToString(ret),
				"Exception", txe.Exception)
		}
	}
}


text:
from calvin.actor.actor import Actor, manage, condition, calvinsys, stateguard

from calvin.utilities.calvinlogger import get_logger

_log = get_logger(__name__)

class TriggeredWeather(Actor):
    """
    Get current weather at selected destination, given as "city,country code", "city", or ",country code"

    Input:
      trigger : start fetching weather on any token
    Output:
        forecast: weather at given city, or null on error
    """

    @manage(["city"])
    def init(self, city):
        self._city = city
        self.setup()

    def did_migrate(self):
        self.setup()

    def setup(self):
        self._service = calvinsys.open(self, "weather")
        calvinsys.write(self._service, self._city)

    def teardown(self):
        calvinsys.close(self._service)

    def will_migrate(self):
        self.teardown()

    def will_end(self):
        self.teardown()

    @stateguard(lambda self: self._service and calvinsys.can_write(self._service))
    @condition(action_input=['trigger'])
    def start_forecast(self, _):
        calvinsys.write(self._service, self._city)

    @stateguard(lambda self: self._service and calvinsys.can_read(self._service))
    @condition(action_output=['forecast'])
    def finish_forecast(self):
        forecast = calvinsys.read(self._service)
        return (forecast,)

    action_priority = (start_forecast, finish_forecast,)
    requires = ['weather']

    test_kwargs = {'city': 'Lund'}
    test_calvinsys = {'weather': {'read': ["sunny"],
                                  'write': ["Lund", "Lund"]}}
    test_set = [
        {
            'inports': {'trigger': [True]},
            'outports': {'forecast': ["sunny"]}
        }
    ]


text:
package edu.kit.iti.formal.pse.worthwhile.validation;

import org.antlr.runtime.EarlyExitException;
import org.antlr.runtime.NoViableAltException;
import org.eclipse.xtext.nodemodel.SyntaxErrorMessage;
import org.eclipse.xtext.parser.antlr.SyntaxErrorMessageProvider;

import edu.kit.iti.formal.pse.worthwhile.model.ast.Program;

/**
 * This class provides the correct syntax error messages.
 *
 * @author matthias
 *
 */
public class WorthwhileSyntaxErrorMessageProvider extends SyntaxErrorMessageProvider {

	/**
	 * Error code for "No newline at end of file".
	 */
	public static final String NO_NEWLINE_AT_EOF = "NoNewlineAtEOF";

	/**
	 * Error code for "No return type specified for function".
	 */
	public static final String NO_FUNCTION_RETURN_TYPE = "NoFunctionReturnType";

	/**
	 * Returns a syntax error messages for the context.
	 *
	 * @param context
	 *                the context from which you want the error message
	 *
	 * @return the syntax error message
	 */
	@Override
	public final SyntaxErrorMessage getSyntaxErrorMessage(final IParserErrorContext context) {
		if (context.getRecognitionException() instanceof EarlyExitException) {

			if (context.getCurrentNode().getRootNode().getTotalEndLine() == context.getCurrentNode()
			                .getEndLine()) {
				return new SyntaxErrorMessage("Newline is missing", NO_NEWLINE_AT_EOF);
			} else {
				return new SyntaxErrorMessage("Delete this token.", "deleteToken");
			}
		} else if (context.getRecognitionException() instanceof NoViableAltException
		                && context.getCurrentContext() instanceof Program) {
			return new SyntaxErrorMessage("Return type of function is missing", NO_FUNCTION_RETURN_TYPE);

		}

		return super.getSyntaxErrorMessage(context);

	}

}


text:
#if defined(GTK_DISABLE_SINGLE_INCLUDES) && !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gtk/gtk.h> can be included directly."
#endif

#ifndef __UBUNTU_OVERLAY_SCROLLBAR_H__
#define __UBUNTU_OVERLAY_SCROLLBAR_H__

#include <gtk/gtkwidget.h>

G_BEGIN_DECLS

gboolean   ubuntu_overlay_scrollbar_get_enabled (void);

void       ubuntu_overlay_scrollbar_set_enabled (gboolean enabled);

void       _ubuntu_overlay_scrollbar_init       (void);

GtkWidget* _ubuntu_overlay_scrollbar_new        (GtkOrientation orientation,
                                                                 GtkAdjustment* adjustment);

G_END_DECLS

#endif /* __UBUNTU_OVERLAY_SCROLLBAR_H__ */


text:
import sys, os, string, datetime, time, urllib, re
import cPickle, xml.sax.saxutils
import types # FIXME see too_old

#
# Settings
#

# ...General
settings = {
	'rss_webmaster': 'tgergo@sch.bme.hu',
	'program_name': 'Fafafa',
	'version': '0.8'
	}

# ...for Picture of the Day
settings_potd = {
	'language': 'hu',
	'entries': 20,
	'output_filename': '/home/t/tgergo/public_html/commons-potd.xml',
	'cache_filename': '/home/t/tgergo/temp/commons-potd_cache.pickle',
	'name_url' : 'http://commons.wikimedia.org/w/index.php?title=Template:Potd/%(year)d-%(month)02d-%(day)02d_(%(lang)s)&action=raw',
	'url': 'http://commons.wikimedia.org/w/index.php?title=Special:ExpandTemplates&input=%(template)s',
	'rss_title_url': 'http://commons.wikimedia.org/wiki/Template:Potd/name/%(lang)s'
	'rss_link': 'http://commons.wikimedia.org/wiki/Commons:Picture_of_the_day',
	'rss_description': 'RSS feed of the Commons Picture of the Day, generated from HTML by ' \
                           '(slightly modified) Fafafa: http://en.wikipedia/wiki/User:Skagedal/Fafafa'
}

# Insert time- and language-related variables into URL

template = """
{| style="width:%(width)dpx; text-align:center;"
|[[Image:{{Potd/%(year)d-%(month)02d-%(day)02d}}|%(width)dpx|]]
|-
| {{lang|%(lang)s|{{ {{#ifexist:Template:Potd/%(year)d-%(month)02d-%(day)02d (%(lang)s)|Potd/%(year)d-%(month)02d-%(day)02d (%(lang)s)|{{#ifexist:Template:Potd/%(year)d-%(month)02d-%(day)02d (%(fallback_lang)s)|Potd/%(year)d-%(month)02d-%(day)02d (%(fallback_lang)s)|empty}}}} }} }}
|}
"""

def calculate_url(url, date, lang=settings['language']):
	return url % { \
                'days_ago': (datetime.date.today() - date).days +1, 'monthname': months[date.month - 1], \
                'day': date.day, 'month': date.month, 'year': date.year, 'lang': lang }

# Subclassing of URLopener - sets "User-agent: ", which Wikipedia requires to be set
# to something else than the default "Python-urllib"

class MyURLopener(urllib.URLopener):
	version = settings['program_name'] + "/" + settings['version']

def too_old(date):
        # FIXME ugly hack to mix dates and date-language tuples in the cache
        if type(date) is types.TupleType:
            date = date[0]
	return (datetime.date.today() - date).days > settings['entries']

# Caching of HTML from Wikipedia

class CacheItem:
	def __init__(self, html, fetchtime):
		self.html = html
		self.fetchtime = fetchtime

class WPCache:

	def __init__(self, cachefilename):
		self.url_opener = MyURLopener()
		self.filename = cachefilename
		if (os.path.exists(cachefilename)):
			file = open(cachefilename)
			self.cache = cPickle.load(file)
			file.close()
		else:
			self.cache = {}

	def get_html(self, date):
		if date in self.cache:
			return self.cache[date].html
		else:
			html = self.url_opener.open(get_content_url(date)).read()
			cacheitem = CacheItem(html, time.gmtime())
			self.cache[date] = cacheitem
			return html

        def get_name(self, date, lang):
                if (date, lang) in self.cache:
			return self.cache[(date, lang)].html
                else:
                        html = self.url_opener.open(calculate_url(settings['name_url'], date, lang)).read()
                        cacheitem = CacheItem(html, time.gmtime())
                        self.cache[(date, lang)] = cacheitem
                        return html

	# Weed out old entries, so cache doesn't get big
	def weed_out_old(self):
		self.cache = dict([x for x in self.cache.items() if not too_old(x[0])])

	def save(self):
		self.weed_out_old()
		file = open(self.filename, "w")
		p = cPickle.Pickler(file)
		p.dump(self.cache)

# Get useful part of the article

def get_section(s, n):
        re_section = re.compile('
%02d
(.*?
)' % (n), re.DOTALL)
	m = re_section.search(s)
	s = m.group(1)

        return s.strip()

# Get title of article

def get_title(s):
        # get content
        re_content = re.compile('(.*)
', re.DOTALL)
        m = re_content.search(s)
        s = m.group(1)

        # strip HTML tags
        re_tag = re.compile('<[^>]*>', re.DOTALL)
        s = re.sub(re_tag, '', s)

        # strip superfluous whitespace
        s = re.sub(r'\s+', ' ', s)

        return s.strip()

# Create RSS item - expects html filtered by get_content

def rss_item(date, name, content):

	if 'no_title' in settings and settings['no_title']:
		title = "%s %d" % (months[date.month - 1], date.day)
	else:
		title = "%s %d: %s" % (months[date.month - 1], date.day, name)
	return """<item>

<title>%(title)s</title>

<link>%(url)s</link>

<description>%(escaped_content)s</description>

</item>
""" % {
	'title': title,
	'url': calculate_url(settings['url'], date),
	'escaped_content': xml.sax.saxutils.escape(content)}

# Puts the final RSS together

def rss(items):
	return """<?xml version="1.0" encoding="UTF-8"?>

<rss version="2.0" xmlns:blogChannel="http://backend.userland.com/blogChannelModule">

<channel>
<title>%(rss_title)s</title>
<link>%(rss_link)s</link>
<description>%(rss_description)s</description>
<language>en-us</language>
<copyright>Varoius free licenses</copyright>
<lastBuildDate>%(build_date)s</lastBuildDate>
<docs>http://blogs.law.harvard.edu/tech/rss</docs>
<webMaster>%(webmaster)s</webMaster>
<generator>%(generator)s</generator>

%(items)s

</channel>
</rss>
""" % {
	'rss_title': settings['rss_title'],
	'rss_link': settings['rss_link'],
	'rss_description': settings['rss_description'],
	'webmaster': settings['rss_webmaster'],
	'build_date': time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.gmtime()),
	'items': items,
	'generator': settings['program_name'] + " " + settings['version'] }

# Main

def main():
	settings.update(settings_potd)

	today = datetime.date.today()
	one_day = datetime.timedelta(days = 1)

	cache = WPCache(settings['cache_filename'])

	dates = [today - one_day*x for x in range(settings['entries'])]

	def item(date, lang):
                #TODO fall back to english if language not found
                name = get_title(cache.get_name(date, lang))
		content = get_section(cache.get_html(date), date.day)

		return rss_item(date, name, content)

	# Iterate over the items
	items = string.join([item(date, settings['language']) for date in dates], "")
	the_rss = rss(items)

	# Write to file
	file = open(settings['output_filename'], "w")
	file.write(the_rss)
	file.close()

	cache.save()

# Don't run if we're imported

if __name__ == '__main__':
	main()


text:
/* global angular, ace */
(function () {
    'use strict';

    angular
        .module('plugins.config')
        .component('configView', {
            templateUrl: 'plugins/config/config.tmpl.html',
            controllerAs: 'vm',
            controller: configController
        });

    function configController($http, base64, $mdDialog, CacheFactory, configService) {
        var vm = this;

        vm.$onInit = activate;
        vm.updateTheme = updateTheme;
        vm.saveConfig = saveConfig;

        var aceThemeCache;

        function activate() {
            loadConfig();
            initCache();

            setupAceOptions();
        }

        function initCache() {
            if (!CacheFactory.get('aceThemeCache')) {
                CacheFactory.createCache('aceThemeCache', {
                    storageMode: 'localStorage'
                });
            }

            aceThemeCache = CacheFactory.get('aceThemeCache');
        }

        function loadConfig() {
            configService.getRawConfig().then(function (data) {
                var encoded = data.raw_config;
                vm.config = base64.decode(encoded);
                saveOriginalConfig();
            });
        }

        function saveOriginalConfig() {
            vm.origConfig = angular.copy(vm.config);
        }

        function setupAceOptions() {
            vm.aceOptions = {
                mode: 'yaml',
                theme: getTheme(),
                onLoad: aceLoaded
            };

            var themelist = ace.require('ace/ext/themelist');
            vm.themes = themelist.themes;
        }

        function aceLoaded(_editor) {
            //Get all commands, but keep the find command
            var commandsToRemove = [
                'transposeletters',
                'gotoline'
            ];

            _editor.commands.removeCommands(commandsToRemove);

            _editor.commands.addCommand({
                name: 'saveConfig',
                bindKey: { win: 'Ctrl-S', mac: 'Command-S' },
                exec: function () {
                    if (vm.config !== vm.origConfig) {
                        saveConfig();
                    }
                }
            });

            _editor.setShowPrintMargin(false);
        }

        function getTheme() {
            var theme = aceThemeCache.get('theme');
            return theme ? theme : 'chrome';
        }

        function updateTheme() {
            aceThemeCache.put('theme', vm.aceOptions.theme);
        }

        function saveConfig() {
            var encoded = base64.encode(vm.config);
            configService.saveRawConfig(encoded)
                .then(function () {
                    var dialog = $mdDialog.alert()
                        .title('Update success')
                        .ok('Ok')
                        .textContent('Your config file has been successfully updated');

                    $mdDialog.show(dialog);

                    delete vm.errorMessage;
                    delete vm.errors;

                    saveOriginalConfig();
                }, function (error) {
                    vm.errors = error.errors;
                });
        }
    }
}());


text:
package org.eclipse.cft.server.ui.internal.editor;

import org.eclipse.cft.server.core.CFServiceInstance;
import org.eclipse.cft.server.ui.internal.CloudFoundryImages;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.TableColumn;

/**
 * @author Terry Denney
 * @author Christian Dupuis
 */
public class ServicesTreeLabelProvider extends LabelProvider implements ITableLabelProvider {

	private final TableViewer viewer;

	public ServicesTreeLabelProvider(TableViewer viewer) {
		this.viewer = viewer;
	}

	@Override
	public Image getImage(Object element) {
		if (element instanceof CFServiceInstance) {
			return CloudFoundryImages.getImage(CloudFoundryImages.OBJ_SERVICE);
		}
		return null;
	}

	@Override
	public String getText(Object element) {
		if (element instanceof CFServiceInstance) {
			CFServiceInstance service = (CFServiceInstance) element;
			return service.getName();
		}
		return super.getText(element);
	}

	public Image getColumnImage(Object element, int columnIndex) {

		TableColumn column = viewer.getTable().getColumn(columnIndex);
		if (column != null && column.getData() instanceof ServiceViewColumn) {

			switch ((ServiceViewColumn) column.getData()) {
			case Name:
				return getImage(element);
			default:
				return getColumnImage((CFServiceInstance) element, (ServiceViewColumn) column.getData());
			}
		}

		return null;
	}

	protected Image getColumnImage(CFServiceInstance service, ServiceViewColumn column) {
		return null;
	}

	public String getColumnText(Object element, int columnIndex) {
		String result = null;
		TableColumn column = viewer.getTable().getColumn(columnIndex);
		if (column != null && element instanceof CFServiceInstance) {
			CFServiceInstance cloudService = (CFServiceInstance) element;
			ServiceViewColumn serviceColumn = (ServiceViewColumn) column.getData();

			if (serviceColumn != null) {
				switch (serviceColumn) {
				case Name:
					result = getText(element);
					break;
				case Version:
					result = cloudService.getVersion();
					break;
				case Service:
					result = cloudService.getService();
					break;
				case Plan:
					result = cloudService.getPlan();
					break;
				}
			}
		}
		return result;
	}

}