text:
using autofill::PasswordForm;
using base::UTF8ToUTF16;
using base::UTF16ToUTF8;
using password_manager::PasswordStoreChange;
using password_manager::PasswordStoreChangeList;

namespace {

// What follows is a very simple implementation of the subset of the Libsecret
// API that we actually use. It gets substituted for the real one by
// MockLibsecretLoader, which hooks into the facility normally used to load
// the libsecret library at runtime to avoid a static dependency on it.

struct MockSecretValue {
  gchar* password;
  explicit MockSecretValue(gchar* password) : password(password) {}
  ~MockSecretValue() { g_free(password); }
};

struct MockSecretItem {
  MockSecretValue* value;
  GHashTable* attributes;

  MockSecretItem(MockSecretValue* value, GHashTable* attributes)
      : value(value), attributes(attributes) {}
  ~MockSecretItem() {
    delete value;
    g_hash_table_destroy(attributes);
  }

  void RemoveAttribute(const char* keyname) {
    g_hash_table_remove(attributes, keyname);
  }
};

bool Matches(MockSecretItem* item, GHashTable* query) {
  GHashTable* attributes = item->attributes;
  GHashTableIter iter;
  gchar* name;
  gchar* query_value;
  g_hash_table_iter_init(&iter, query);

  while (g_hash_table_iter_next(&iter, reinterpret_cast<gpointer*>(&name),
                                reinterpret_cast<gpointer*>(&query_value))) {
    gchar* value = static_cast<gchar*>(g_hash_table_lookup(attributes, name));
    if (value == nullptr || strcmp(value, query_value) != 0)
      return false;
  }
  return true;
}

bool IsStringAttribute(const SecretSchema* schema, const std::string& name) {
  for (size_t i = 0; schema->attributes[i].name; ++i)
    if (name == schema->attributes[i].name)
      return schema->attributes[i].type == SECRET_SCHEMA_ATTRIBUTE_STRING;
  NOTREACHED() << "Requested type of nonexistent attribute";
  return false;
}

// The list of all libsecret items we have stored.
ScopedVector<MockSecretItem>* global_mock_libsecret_items;
bool global_mock_libsecret_reject_local_ids = false;

gboolean mock_secret_password_store_sync(const SecretSchema* schema,
                                         const gchar* collection,
                                         const gchar* label,
                                         const gchar* password,
                                         GCancellable* cancellable,
                                         GError** error,
                                         ...) {
  GHashTable* attributes =
      g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
  va_list ap;
  va_start(ap, error);
  char* name;
  while ((name = va_arg(ap, gchar*))) {
    char* value;
    if (IsStringAttribute(schema, name)) {
      value = g_strdup(va_arg(ap, gchar*));
      VLOG(1) << "Adding item attribute " << name << ", value '" << value
              << "'";
    } else {
      uint32_t intvalue = va_arg(ap, uint32_t);
      VLOG(1) << "Adding item attribute " << name << ", value " << intvalue;
      value = g_strdup_printf("%u", intvalue);
    }
    g_hash_table_insert(attributes, g_strdup(name), value);
  }
  va_end(ap);
  MockSecretValue* secret_value = new MockSecretValue(g_strdup(password));
  MockSecretItem* item = new MockSecretItem(secret_value, attributes);
  global_mock_libsecret_items->push_back(item);
  return true;
}

GList* mock_secret_service_search_sync(SecretService* service,
                                       const SecretSchema* schema,
                                       GHashTable* attributes,
                                       SecretSearchFlags flags,
                                       GCancellable* cancellable,
                                       GError** error) {
  GList* result = nullptr;
  for (MockSecretItem* item : *global_mock_libsecret_items) {
    if (Matches(item, attributes))
      result = g_list_append(result, item);
  }
  return result;
}

gboolean mock_secret_password_clear_sync(const SecretSchema* schema,
                                         GCancellable* cancellable,
                                         GError** error,
                                         ...) {
  GHashTable* attributes =
      g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
  va_list ap;
  va_start(ap, error);
  char* name;
  while ((name = va_arg(ap, gchar*))) {
    char* value;
    if (IsStringAttribute(schema, name)) {
      value = g_strdup(va_arg(ap, gchar*));
      VLOG(1) << "Adding item attribute " << name << ", value '" << value
              << "'";
    } else {
      uint32_t intvalue = va_arg(ap, uint32_t);
      VLOG(1) << "Adding item attribute " << name << ", value " << intvalue;
      value = g_strdup_printf("%u", intvalue);
    }
    g_hash_table_insert(attributes, g_strdup(name), value);
  }
  va_end(ap);
  for (uint32_t i = 0; i < global_mock_libsecret_items->size();)
    if (Matches((*global_mock_libsecret_items)[i], attributes)) {
      global_mock_libsecret_items->erase(global_mock_libsecret_items->begin() +
                                         i);
    } else {
      ++i;
    }
  g_hash_table_unref(attributes);
  return true;
}

MockSecretValue* mock_secret_item_get_secret(MockSecretItem* self) {
  return self->value;
}

const gchar* mock_secret_value_get_text(MockSecretValue* value) {
  return value->password;
}

GHashTable* mock_secret_item_get_attributes(MockSecretItem* self) {
  // Libsecret backend will make unreference of received attributes, so in
  // order to save them we need to increase their reference number.
  g_hash_table_ref(self->attributes);
  return self->attributes;
}

gboolean mock_secret_item_load_secret_sync(MockSecretItem* self,
                                           GCancellable* cancellable,
                                           GError** error) {
  return true;
}

void mock_secret_value_unref(gpointer value) {
}

// Inherit to get access to protected fields.
class MockLibsecretLoader : public LibsecretLoader {
 public:
  static bool LoadMockLibsecret() {
    secret_password_store_sync = &mock_secret_password_store_sync;
    secret_service_search_sync = &mock_secret_service_search_sync;
    secret_password_clear_sync = &mock_secret_password_clear_sync;
    secret_item_get_secret =
        (decltype(&::secret_item_get_secret)) & mock_secret_item_get_secret;
    secret_value_get_text =
        (decltype(&::secret_value_get_text)) & mock_secret_value_get_text;
    secret_item_get_attributes = (decltype(&::secret_item_get_attributes)) &
                                 mock_secret_item_get_attributes;
    secret_item_load_secret_sync = (decltype(&::secret_item_load_secret_sync)) &
                                   mock_secret_item_load_secret_sync;
    secret_value_unref =
        (decltype(&::secret_value_unref)) & mock_secret_value_unref;
    libsecret_loaded = true;
    // Reset the state of the mock library.
    global_mock_libsecret_items->clear();
    global_mock_libsecret_reject_local_ids = false;
    return true;
  }
};

void CheckPasswordChanges(const PasswordStoreChangeList& expected_list,
                          const PasswordStoreChangeList& actual_list) {
  ASSERT_EQ(expected_list.size(), actual_list.size());
  for (size_t i = 0; i < expected_list.size(); ++i) {
    EXPECT_EQ(expected_list[i].type(), actual_list[i].type());
    const PasswordForm& expected = expected_list[i].form();
    const PasswordForm& actual = actual_list[i].form();

    EXPECT_EQ(expected.origin, actual.origin);
    EXPECT_EQ(expected.password_value, actual.password_value);
    EXPECT_EQ(expected.action, actual.action);
    EXPECT_EQ(expected.username_element, actual.username_element);
    EXPECT_EQ(expected.username_value, actual.username_value);
    EXPECT_EQ(expected.password_element, actual.password_element);
    EXPECT_EQ(expected.submit_element, actual.submit_element);
    EXPECT_EQ(expected.signon_realm, actual.signon_realm);
    EXPECT_EQ(expected.ssl_valid, actual.ssl_valid);
    EXPECT_EQ(expected.preferred, actual.preferred);
    EXPECT_EQ(expected.date_created, actual.date_created);
    EXPECT_EQ(expected.blacklisted_by_user, actual.blacklisted_by_user);
    EXPECT_EQ(expected.type, actual.type);
    EXPECT_EQ(expected.times_used, actual.times_used);
    EXPECT_EQ(expected.scheme, actual.scheme);
    EXPECT_EQ(expected.date_synced, actual.date_synced);
    EXPECT_EQ(expected.display_name, actual.display_name);
    EXPECT_EQ(expected.avatar_url, actual.avatar_url);
    EXPECT_EQ(expected.federation_url, actual.federation_url);
    EXPECT_EQ(expected.skip_zero_click, actual.skip_zero_click);
    EXPECT_EQ(expected.generation_upload_status,
              actual.generation_upload_status);
  }
}

}  // anonymous namespace

class NativeBackendLibsecretTest : public testing::Test {
 protected:
  enum UpdateType {  // Used in CheckPSLUpdate().
    UPDATE_BY_UPDATELOGIN,
    UPDATE_BY_ADDLOGIN,
  };
  enum RemoveBetweenMethod {  // Used in CheckRemoveLoginsBetween().
    CREATED,
    SYNCED,
  };

  NativeBackendLibsecretTest() {}

  void SetUp() override {
    ASSERT_FALSE(global_mock_libsecret_items);
    global_mock_libsecret_items = &mock_libsecret_items_;

    ASSERT_TRUE(MockLibsecretLoader::LoadMockLibsecret());

    form_google_.origin = GURL("http://www.google.com/");
    form_google_.action = GURL("http://www.google.com/login");
    form_google_.username_element = UTF8ToUTF16("user");
    form_google_.username_value = UTF8ToUTF16("joeschmoe");
    form_google_.password_element = UTF8ToUTF16("pass");
    form_google_.password_value = UTF8ToUTF16("seekrit");
    form_google_.submit_element = UTF8ToUTF16("submit");
    form_google_.signon_realm = "http://www.google.com/";
    form_google_.type = PasswordForm::TYPE_GENERATED;
    form_google_.date_created = base::Time::Now();
    form_google_.date_synced = base::Time::Now();
    form_google_.display_name = UTF8ToUTF16("Joe Schmoe");
    form_google_.avatar_url = GURL("http://www.google.com/avatar");
    form_google_.federation_url = GURL("http://www.google.com/federation_url");
    form_google_.skip_zero_click = true;
    form_google_.generation_upload_status = PasswordForm::POSITIVE_SIGNAL_SENT;
    form_google_.form_data.name = UTF8ToUTF16("form_name");
    form_google_.form_data.user_submitted = true;

    form_facebook_.origin = GURL("http://www.facebook.com/");
    form_facebook_.action = GURL("http://www.facebook.com/login");
    form_facebook_.username_element = UTF8ToUTF16("user");
    form_facebook_.username_value = UTF8ToUTF16("a");
    form_facebook_.password_element = UTF8ToUTF16("password");
    form_facebook_.password_value = UTF8ToUTF16("b");
    form_facebook_.submit_element = UTF8ToUTF16("submit");
    form_facebook_.signon_realm = "http://www.facebook.com/";
    form_facebook_.date_created = base::Time::Now();
    form_facebook_.date_synced = base::Time::Now();
    form_facebook_.display_name = UTF8ToUTF16("Joe Schmoe");
    form_facebook_.avatar_url = GURL("http://www.facebook.com/avatar");
    form_facebook_.federation_url = GURL("http://www.facebook.com/federation");
    form_facebook_.skip_zero_click = true;
    form_facebook_.generation_upload_status = PasswordForm::NO_SIGNAL_SENT;

    form_isc_.origin = GURL("http://www.isc.org/");
    form_isc_.action = GURL("http://www.isc.org/auth");
    form_isc_.username_element = UTF8ToUTF16("id");
    form_isc_.username_value = UTF8ToUTF16("janedoe");
    form_isc_.password_element = UTF8ToUTF16("passwd");
    form_isc_.password_value = UTF8ToUTF16("ihazabukkit");
    form_isc_.submit_element = UTF8ToUTF16("login");
    form_isc_.signon_realm = "http://www.isc.org/";
    form_isc_.date_created = base::Time::Now();
    form_isc_.date_synced = base::Time::Now();

    other_auth_.origin = GURL("http://www.example.com/");
    other_auth_.username_value = UTF8ToUTF16("username");
    other_auth_.password_value = UTF8ToUTF16("pass");
    other_auth_.signon_realm = "http://www.example.com/Realm";
    other_auth_.date_created = base::Time::Now();
    other_auth_.date_synced = base::Time::Now();
  }

  void TearDown() override {
    base::MessageLoop::current()->PostTask(FROM_HERE,
                                           base::MessageLoop::QuitClosure());
    base::MessageLoop::current()->Run();
    ASSERT_TRUE(global_mock_libsecret_items);
    global_mock_libsecret_items = nullptr;
  }

  void RunUIThread() { base::MessageLoop::current()->Run(); }

  void CheckUint32Attribute(const MockSecretItem* item,
                            const std::string& attribute,
                            uint32_t value) {
    gpointer item_value =
        g_hash_table_lookup(item->attributes, attribute.c_str());
    EXPECT_TRUE(item_value) << " in attribute " << attribute;
    if (item_value) {
      uint32_t int_value;
      bool conversion_ok = base::StringToUint((char*)item_value, &int_value);
      EXPECT_TRUE(conversion_ok);
      EXPECT_EQ(value, int_value);
    }
  }

  void CheckStringAttribute(const MockSecretItem* item,
                            const std::string& attribute,
                            const std::string& value) {
    gpointer item_value =
        g_hash_table_lookup(item->attributes, attribute.c_str());
    EXPECT_TRUE(item_value) << " in attribute " << attribute;
    if (item_value) {
      EXPECT_EQ(value, static_cast<char*>(item_value));
    }
  }

  void CheckMockSecretItem(const MockSecretItem* item,
                           const PasswordForm& form,
                           const std::string& app_string) {
    EXPECT_EQ(UTF16ToUTF8(form.password_value), item->value->password);
    EXPECT_EQ(22u, g_hash_table_size(item->attributes));
    CheckStringAttribute(item, "origin_url", form.origin.spec());
    CheckStringAttribute(item, "action_url", form.action.spec());
    CheckStringAttribute(item, "username_element",
                         UTF16ToUTF8(form.username_element));
    CheckStringAttribute(item, "username_value",
                         UTF16ToUTF8(form.username_value));
    CheckStringAttribute(item, "password_element",
                         UTF16ToUTF8(form.password_element));
    CheckStringAttribute(item, "submit_element",
                         UTF16ToUTF8(form.submit_element));
    CheckStringAttribute(item, "signon_realm", form.signon_realm);
    CheckUint32Attribute(item, "ssl_valid", form.ssl_valid);
    CheckUint32Attribute(item, "preferred", form.preferred);
    // We don't check the date created. It varies.
    CheckUint32Attribute(item, "blacklisted_by_user", form.blacklisted_by_user);
    CheckUint32Attribute(item, "type", form.type);
    CheckUint32Attribute(item, "times_used", form.times_used);
    CheckUint32Attribute(item, "scheme", form.scheme);
    CheckStringAttribute(
        item, "date_synced",
        base::Int64ToString(form.date_synced.ToInternalValue()));
    CheckStringAttribute(item, "display_name", UTF16ToUTF8(form.display_name));
    CheckStringAttribute(item, "avatar_url", form.avatar_url.spec());
    CheckStringAttribute(item, "federation_url", form.federation_url.spec());
    CheckUint32Attribute(item, "skip_zero_click", form.skip_zero_click);
    CheckUint32Attribute(item, "generation_upload_status",
                         form.generation_upload_status);
    CheckStringAttribute(item, "application", app_string);
    autofill::FormData actual;
    DeserializeFormDataFromBase64String(
        static_cast<char*>(g_hash_table_lookup(item->attributes, "form_data")),
        &actual);
    EXPECT_TRUE(form.form_data.SameFormAs(actual));
  }

  // Saves |credentials| and then gets logins matching |url| and |scheme|.
  // Returns true when something is found, and in such case copies the result to
  // |result| when |result| is not nullptr. (Note that there can be max. 1
  // result derived from |credentials|.)
  bool CheckCredentialAvailability(const PasswordForm& credentials,
                                   const GURL& url,
                                   const PasswordForm::Scheme& scheme,
                                   PasswordForm* result) {
    NativeBackendLibsecret backend(321);

    backend.AddLogin(credentials);

    PasswordForm target_form;
    target_form.origin = url;
    target_form.signon_realm = url.spec();
    if (scheme != PasswordForm::SCHEME_HTML) {
      // For non-HTML forms, the realm used for authentication
      // (http://tools.ietf.org/html/rfc1945#section-10.2) is appended to the
      // signon_realm. Just use a default value for now.
      target_form.signon_realm.append("Realm");
      target_form.scheme = scheme;
    }
    ScopedVector<autofill::PasswordForm> form_list;
    backend.GetLogins(target_form, &form_list);

    EXPECT_EQ(1u, global_mock_libsecret_items->size());
    if (!global_mock_libsecret_items->empty())
      CheckMockSecretItem((*global_mock_libsecret_items)[0], credentials,
                          "chrome-321");
    global_mock_libsecret_items->clear();

    if (form_list.empty())
      return false;
    EXPECT_EQ(1u, form_list.size());
    if (result)
      *result = *form_list[0];
    return true;
  }

  // Test that updating does not use PSL matching: Add a www.facebook.com
  // password, then use PSL matching to get a copy of it for m.facebook.com, and
  // add that copy as well. Now update the www.facebook.com password -- the
  // m.facebook.com password should not get updated. Depending on the argument,
  // the credential update is done via UpdateLogin or AddLogin.
  void CheckPSLUpdate(UpdateType update_type) {
    NativeBackendLibsecret backend(321);

    backend.AddLogin(form_facebook_);

    // Get the PSL-matched copy of the saved login for m.facebook.
    const GURL kMobileURL("http://m.facebook.com/");
    PasswordForm m_facebook_lookup;
    m_facebook_lookup.origin = kMobileURL;
    m_facebook_lookup.signon_realm = kMobileURL.spec();
    ScopedVector<autofill::PasswordForm> form_list;
    backend.GetLogins(m_facebook_lookup, &form_list);

    EXPECT_EQ(1u, global_mock_libsecret_items->size());
    EXPECT_EQ(1u, form_list.size());
    PasswordForm m_facebook = *form_list[0];
    form_list.clear();
    EXPECT_EQ(kMobileURL, m_facebook.origin);
    EXPECT_EQ(kMobileURL.spec(), m_facebook.signon_realm);

    // Add the PSL-matched copy to saved logins.
    backend.AddLogin(m_facebook);
    EXPECT_EQ(2u, global_mock_libsecret_items->size());

    // Update www.facebook.com login.
    PasswordForm new_facebook(form_facebook_);
    const base::string16 kOldPassword(form_facebook_.password_value);
    const base::string16 kNewPassword(UTF8ToUTF16("new_b"));
    EXPECT_NE(kOldPassword, kNewPassword);
    new_facebook.password_value = kNewPassword;
    scoped_ptr<PasswordStoreChangeList> not_used(new PasswordStoreChangeList());
    switch (update_type) {
      case UPDATE_BY_UPDATELOGIN:
        backend.UpdateLogin(new_facebook, not_used.get());
        break;
      case UPDATE_BY_ADDLOGIN:
        backend.AddLogin(new_facebook);
        break;
    }

    EXPECT_EQ(2u, global_mock_libsecret_items->size());

    // Check that m.facebook.com login was not modified by the update.
    backend.GetLogins(m_facebook_lookup, &form_list);

    // There should be two results -- the exact one, and the PSL-matched one.
    EXPECT_EQ(2u, form_list.size());
    size_t index_non_psl = 0;
    if (!form_list[index_non_psl]->original_signon_realm.empty())
      index_non_psl = 1;
    EXPECT_EQ(kMobileURL, form_list[index_non_psl]->origin);
    EXPECT_EQ(kMobileURL.spec(), form_list[index_non_psl]->signon_realm);
    EXPECT_EQ(kOldPassword, form_list[index_non_psl]->password_value);
    form_list.clear();

    // Check that www.facebook.com login was modified by the update.
    backend.GetLogins(form_facebook_, &form_list);
    // There should be two results -- the exact one, and the PSL-matched one.
    EXPECT_EQ(2u, form_list.size());
    index_non_psl = 0;
    if (!form_list[index_non_psl]->original_signon_realm.empty())
      index_non_psl = 1;
    EXPECT_EQ(form_facebook_.origin, form_list[index_non_psl]->origin);
    EXPECT_EQ(form_facebook_.signon_realm,
              form_list[index_non_psl]->signon_realm);
    EXPECT_EQ(kNewPassword, form_list[index_non_psl]->password_value);
    form_list.clear();
  }

  // Checks various types of matching for forms with a non-HTML |scheme|.
  void CheckMatchingWithScheme(const PasswordForm::Scheme& scheme) {
    ASSERT_NE(PasswordForm::SCHEME_HTML, scheme);
    other_auth_.scheme = scheme;

    // Don't match a non-HTML form with an HTML form.
    EXPECT_FALSE(
        CheckCredentialAvailability(other_auth_, GURL("http://www.example.com"),
                                    PasswordForm::SCHEME_HTML, nullptr));
    // Don't match an HTML form with non-HTML auth form.
    EXPECT_FALSE(CheckCredentialAvailability(
        form_google_, GURL("http://www.google.com/"), scheme, nullptr));
    // Don't match two different non-HTML auth forms with different origin.
    EXPECT_FALSE(CheckCredentialAvailability(
        other_auth_, GURL("http://first.example.com"), scheme, nullptr));
    // Do match non-HTML forms from the same origin.
    EXPECT_TRUE(CheckCredentialAvailability(
        other_auth_, GURL("http://www.example.com/"), scheme, nullptr));
  }

  void CheckRemoveLoginsBetween(RemoveBetweenMethod date_to_test) {
    NativeBackendLibsecret backend(42);

    base::Time now = base::Time::Now();
    base::Time next_day = now + base::TimeDelta::FromDays(1);
    form_google_.date_synced = base::Time();
    form_isc_.date_synced = base::Time();
    form_google_.date_created = now;
    form_isc_.date_created = now;
    if (date_to_test == CREATED) {
      form_google_.date_created = now;
      form_isc_.date_created = next_day;
    } else {
      form_google_.date_synced = now;
      form_isc_.date_synced = next_day;
    }

    backend.AddLogin(form_google_);
    backend.AddLogin(form_isc_);

    PasswordStoreChangeList expected_changes;
    expected_changes.push_back(
        PasswordStoreChange(PasswordStoreChange::REMOVE, form_google_));
    PasswordStoreChangeList changes;
    bool (NativeBackendLibsecret::*method)(
        base::Time, base::Time, password_manager::PasswordStoreChangeList*) =
        date_to_test == CREATED
            ? &NativeBackendLibsecret::RemoveLoginsCreatedBetween
            : &NativeBackendLibsecret::RemoveLoginsSyncedBetween;

    EXPECT_TRUE(base::Bind(method, base::Unretained(&backend), base::Time(),
                           next_day, &changes).Run());
    CheckPasswordChanges(expected_changes, changes);

    EXPECT_EQ(1u, global_mock_libsecret_items->size());
    if (!global_mock_libsecret_items->empty() > 0)
      CheckMockSecretItem((*global_mock_libsecret_items)[0], form_isc_,
                          "chrome-42");

    // Remove form_isc_.
    expected_changes.clear();
    expected_changes.push_back(
        PasswordStoreChange(PasswordStoreChange::REMOVE, form_isc_));

    EXPECT_TRUE(base::Bind(method, base::Unretained(&backend), next_day,
                           base::Time(), &changes).Run());
    CheckPasswordChanges(expected_changes, changes);

    EXPECT_TRUE(global_mock_libsecret_items->empty());
  }

  base::MessageLoopForUI message_loop_;

  // Provide some test forms to avoid having to set them up in each test.
  PasswordForm form_google_;
  PasswordForm form_facebook_;
  PasswordForm form_isc_;
  PasswordForm other_auth_;

  ScopedVector<MockSecretItem> mock_libsecret_items_;
};

TEST_F(NativeBackendLibsecretTest, BasicAddLogin) {
  NativeBackendLibsecret backend(42);

  backend.AddLogin(form_google_);

  EXPECT_EQ(1u, global_mock_libsecret_items->size());
  if (!global_mock_libsecret_items->empty())
    CheckMockSecretItem((*global_mock_libsecret_items)[0], form_google_,
                        "chrome-42");
}

TEST_F(NativeBackendLibsecretTest, BasicListLogins) {
  NativeBackendLibsecret backend(42);

  backend.AddLogin(form_google_);

  ScopedVector<autofill::PasswordForm> form_list;
  backend.GetAutofillableLogins(&form_list);

  // Quick check that we got something back.
  EXPECT_EQ(1u, form_list.size());
  form_list.clear();

  EXPECT_EQ(1u, global_mock_libsecret_items->size());
  if (!global_mock_libsecret_items->empty())
    CheckMockSecretItem((*global_mock_libsecret_items)[0], form_google_,
                        "chrome-42");
}

// Save a password for www.facebook.com and see it suggested for m.facebook.com.
TEST_F(NativeBackendLibsecretTest, PSLMatchingPositive) {
  PasswordForm result;
  const GURL kMobileURL("http://m.facebook.com/");
  EXPECT_TRUE(CheckCredentialAvailability(form_facebook_, kMobileURL,
                                          PasswordForm::SCHEME_HTML, &result));
  EXPECT_EQ(kMobileURL, result.origin);
  EXPECT_EQ(kMobileURL.spec(), result.signon_realm);
}

// Save a password for www.facebook.com and see it not suggested for
// m-facebook.com.
TEST_F(NativeBackendLibsecretTest, PSLMatchingNegativeDomainMismatch) {
  EXPECT_FALSE(CheckCredentialAvailability(form_facebook_,
                                           GURL("http://m-facebook.com/"),
                                           PasswordForm::SCHEME_HTML, nullptr));
}

// Test PSL matching is off for domains excluded from it.
TEST_F(NativeBackendLibsecretTest, PSLMatchingDisabledDomains) {
  EXPECT_FALSE(CheckCredentialAvailability(form_google_,
                                           GURL("http://one.google.com/"),
                                           PasswordForm::SCHEME_HTML, nullptr));
}

// Make sure PSL matches aren't available for non-HTML forms.
TEST_F(NativeBackendLibsecretTest, PSLMatchingDisabledForNonHTMLForms) {
  CheckMatchingWithScheme(PasswordForm::SCHEME_BASIC);
  CheckMatchingWithScheme(PasswordForm::SCHEME_DIGEST);
  CheckMatchingWithScheme(PasswordForm::SCHEME_OTHER);
}

TEST_F(NativeBackendLibsecretTest, PSLUpdatingStrictUpdateLogin) {
  CheckPSLUpdate(UPDATE_BY_UPDATELOGIN);
}

TEST_F(NativeBackendLibsecretTest, PSLUpdatingStrictAddLogin) {
  // TODO(vabr): if AddLogin becomes no longer valid for existing logins, then
  // just delete this test.
  CheckPSLUpdate(UPDATE_BY_ADDLOGIN);
}

TEST_F(NativeBackendLibsecretTest, BasicUpdateLogin) {
  NativeBackendLibsecret backend(42);

  backend.AddLogin(form_google_);

  PasswordForm new_form_google(form_google_);
  new_form_google.times_used = 1;
  new_form_google.action = GURL("http://www.google.com/different/login");

  EXPECT_EQ(1u, global_mock_libsecret_items->size());
  if (!global_mock_libsecret_items->empty())
    CheckMockSecretItem((*global_mock_libsecret_items)[0], form_google_,
                        "chrome-42");

  // Update login
  PasswordStoreChangeList changes;
  backend.UpdateLogin(new_form_google, &changes);

  ASSERT_EQ(1u, changes.size());
  EXPECT_EQ(PasswordStoreChange::UPDATE, changes.front().type());
  EXPECT_EQ(new_form_google, changes.front().form());
  EXPECT_EQ(1u, global_mock_libsecret_items->size());
  if (!global_mock_libsecret_items->empty())
    CheckMockSecretItem((*global_mock_libsecret_items)[0], new_form_google,
                        "chrome-42");
}

TEST_F(NativeBackendLibsecretTest, BasicRemoveLogin) {
  NativeBackendLibsecret backend(42);

  backend.AddLogin(form_google_);

  EXPECT_EQ(1u, global_mock_libsecret_items->size());
  if (!global_mock_libsecret_items->empty())
    CheckMockSecretItem((*global_mock_libsecret_items)[0], form_google_,
                        "chrome-42");

  backend.RemoveLogin(form_google_);

  EXPECT_TRUE(global_mock_libsecret_items->empty());
}

// Verify fix for http://crbug.com/408783.
TEST_F(NativeBackendLibsecretTest, RemoveLoginActionMismatch) {
  NativeBackendLibsecret backend(42);

  backend.AddLogin(form_google_);

  EXPECT_EQ(1u, global_mock_libsecret_items->size());
  if (!global_mock_libsecret_items->empty())
    CheckMockSecretItem((*global_mock_libsecret_items)[0], form_google_,
                        "chrome-42");

  // Action url match not required for removal.
  form_google_.action = GURL("https://some.other.url.com/path");

  backend.RemoveLogin(form_google_);

  EXPECT_TRUE(global_mock_libsecret_items->empty());
}

TEST_F(NativeBackendLibsecretTest, RemoveNonexistentLogin) {
  NativeBackendLibsecret backend(42);

  // First add an unrelated login.
  backend.AddLogin(form_google_);

  EXPECT_EQ(1u, global_mock_libsecret_items->size());
  if (!global_mock_libsecret_items->empty())
    CheckMockSecretItem((*global_mock_libsecret_items)[0], form_google_,
                        "chrome-42");

  // Attempt to remove a login that doesn't exist.
  backend.RemoveLogin(form_isc_);

  // Make sure we can still get the first form back.
  ScopedVector<autofill::PasswordForm> form_list;
  backend.GetAutofillableLogins(&form_list);

  // Quick check that we got something back.
  EXPECT_EQ(1u, form_list.size());
  form_list.clear();

  EXPECT_EQ(1u, global_mock_libsecret_items->size());
  if (!global_mock_libsecret_items->empty())
    CheckMockSecretItem((*global_mock_libsecret_items)[0], form_google_,
                        "chrome-42");
}

TEST_F(NativeBackendLibsecretTest, UpdateNonexistentLogin) {
  NativeBackendLibsecret backend(42);

  // First add an unrelated login.
  backend.AddLogin(form_google_);

  EXPECT_EQ(1u, global_mock_libsecret_items->size());
  if (!global_mock_libsecret_items->empty())
    CheckMockSecretItem((*global_mock_libsecret_items)[0], form_google_,
                        "chrome-42");

  // Attempt to update a login that doesn't exist.
  PasswordStoreChangeList changes;
  backend.UpdateLogin(form_isc_, &changes);

  EXPECT_EQ(PasswordStoreChangeList(), changes);
  EXPECT_EQ(1u, global_mock_libsecret_items->size());
  if (!global_mock_libsecret_items->empty())
    CheckMockSecretItem((*global_mock_libsecret_items)[0], form_google_,
                        "chrome-42");
}

TEST_F(NativeBackendLibsecretTest, AddDuplicateLogin) {
  NativeBackendLibsecret backend(42);

  PasswordStoreChangeList expected_changes, actual_changes;
  expected_changes.push_back(
      PasswordStoreChange(PasswordStoreChange::ADD, form_google_));
  actual_changes = backend.AddLogin(form_google_);
  CheckPasswordChanges(expected_changes, actual_changes);

  expected_changes.clear();
  expected_changes.push_back(
      PasswordStoreChange(PasswordStoreChange::REMOVE, form_google_));
  form_google_.times_used++;
  expected_changes.push_back(
      PasswordStoreChange(PasswordStoreChange::ADD, form_google_));

  actual_changes = backend.AddLogin(form_google_);
  CheckPasswordChanges(expected_changes, actual_changes);

  EXPECT_EQ(1u, global_mock_libsecret_items->size());
  if (!global_mock_libsecret_items->empty())
    CheckMockSecretItem((*global_mock_libsecret_items)[0], form_google_,
                        "chrome-42");
}

TEST_F(NativeBackendLibsecretTest, ListLoginsAppends) {
  NativeBackendLibsecret backend(42);

  backend.AddLogin(form_google_);

  // Send the same request twice with the same list both times.
  ScopedVector<autofill::PasswordForm> form_list;
  backend.GetAutofillableLogins(&form_list);
  backend.GetAutofillableLogins(&form_list);

  // Quick check that we got two results back.
  EXPECT_EQ(2u, form_list.size());
  form_list.clear();

  EXPECT_EQ(1u, global_mock_libsecret_items->size());
  if (!global_mock_libsecret_items->empty())
    CheckMockSecretItem((*global_mock_libsecret_items)[0], form_google_,
                        "chrome-42");
}

TEST_F(NativeBackendLibsecretTest, AndroidCredentials) {
  NativeBackendLibsecret backend(42);
  backend.Init();

  PasswordForm observed_android_form;
  observed_android_form.scheme = PasswordForm::SCHEME_HTML;
  observed_android_form.signon_realm =
      "android://7x7IDboo8u9YKraUsbmVkuf1-@net.rateflix.app/";
  PasswordForm saved_android_form = observed_android_form;
  saved_android_form.username_value = base::UTF8ToUTF16("randomusername");
  saved_android_form.password_value = base::UTF8ToUTF16("password");
  saved_android_form.date_created = base::Time::Now();

  backend.AddLogin(saved_android_form);

  ScopedVector<autofill::PasswordForm> form_list;
  backend.GetAutofillableLogins(&form_list);

  EXPECT_EQ(1u, form_list.size());
  EXPECT_EQ(saved_android_form, *form_list[0]);
}

TEST_F(NativeBackendLibsecretTest, RemoveLoginsCreatedBetween) {
  CheckRemoveLoginsBetween(CREATED);
}

TEST_F(NativeBackendLibsecretTest, RemoveLoginsSyncedBetween) {
  CheckRemoveLoginsBetween(SYNCED);
}

TEST_F(NativeBackendLibsecretTest, SomeKeyringAttributesAreMissing) {
  // Absent attributes should be filled with default values.
  NativeBackendLibsecret backend(42);

  backend.AddLogin(form_google_);

  EXPECT_EQ(1u, global_mock_libsecret_items->size());
  // Remove a string attribute.
  (*global_mock_libsecret_items)[0]->RemoveAttribute("avatar_url");
  // Remove an integer attribute.
  (*global_mock_libsecret_items)[0]->RemoveAttribute("ssl_valid");

  ScopedVector<autofill::PasswordForm> form_list;
  backend.GetAutofillableLogins(&form_list);

  EXPECT_EQ(1u, form_list.size());
  EXPECT_EQ(GURL(""), form_list[0]->avatar_url);
  EXPECT_FALSE(form_list[0]->ssl_valid);
}

// TODO(mdm): add more basic tests here at some point.


text:
package adb

import "github.com/thinkhy/go-adb/internal/errors"

// DeviceState represents one of the 3 possible states adb will report devices.
// A device can be communicated with when it's in StateOnline.
// A USB device will make the following state transitions:
// 	Plugged in: StateDisconnected->StateOffline->StateOnline
// 	Unplugged:  StateOnline->StateDisconnected
//go:generate stringer -type=DeviceState
type DeviceState int8

const (
	StateInvalid DeviceState = iota
	StateUnauthorized
	StateDisconnected
	StateOffline
	StateConnecting
	StateOnline
)

var deviceStateStrings = map[string]DeviceState{
	"":             StateDisconnected,
	"offline":      StateOffline,
	"connecting":   StateConnecting,
	"device":       StateOnline,
	"unauthorized": StateUnauthorized,
}

func parseDeviceState(str string) (DeviceState, error) {
	state, ok := deviceStateStrings[str]
	if !ok {
		return StateInvalid, errors.Errorf(errors.ParseError, "invalid device state: %q", state)
	}
	return state, nil
}

redpajama_set_name: RedPajamaGithub


text:
import json
import numpy as np
import Tkinter as tk
import tkFileDialog
import tkMessageBox
import sys
import traceback
from copy import deepcopy
from math import pi
from PIL import Image, ImageTk
from scipy.optimize import minimize
from threading import Thread

# Create rotation matrix from an arbitrary quaternion.  See also:
# https://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation#Conversion_to_and_from_the_matrix_representation
def get_rotation_matrix(qq):
    # Normalize matrix and extract individual items.
    qq_norm = np.sqrt(np.sum(np.square(qq)))
    w = qq[0] / qq_norm
    x = qq[1] / qq_norm
    y = qq[2] / qq_norm
    z = qq[3] / qq_norm
    # Convert to rotation matrix.
    return np.matrix([[w*w+x*x-y*y-z*z, 2*x*y-2*w*z, 2*x*z+2*w*y],
                      [2*x*y+2*w*z, w*w-x*x+y*y-z*z, 2*y*z-2*w*x],
                      [2*x*z-2*w*y, 2*y*z+2*w*x, w*w-x*x-y*y+z*z]], dtype='float32')

# Conjugate a quaternion to apply the opposite rotation.
def conj_qq(qq):
    return np.array([qq[0], -qq[1], -qq[2], -qq[3]])

# Multiply two quaternions:ab = (a0b0 - av dot bv; a0*bv + b0av + av cross bv)
# https://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation#Conversion_to_and_from_the_matrix_representation
def mul_qq(qa, qb):
    return np.array([qa[0]*qb[0] - qa[1]*qb[1] - qa[2]*qb[2] - qa[3]*qb[3],
                     qa[0]*qb[1] + qa[1]*qb[0] + qa[2]*qb[3] - qa[3]*qb[2],
                     qa[0]*qb[2] + qa[2]*qb[0] + qa[3]*qb[1] - qa[1]*qb[3],
                     qa[0]*qb[3] + qa[3]*qb[0] + qa[1]*qb[2] - qa[2]*qb[1]])

# Generate a normalized quaternion [W,X,Y,Z] from [X,Y,Z]
def norm_qq(x, y, z):
    rsq = x**2 + y**2 + z**2
    if rsq < 1:
        w = np.sqrt(1-rsq)
        return [w, x, y, z]
    else:
        r = np.sqrt(rsq)
        return [0, x/r, y/r, z/r]

# Return length of every column in an MxN matrix.
def matrix_len(x):
    #return np.sqrt(np.sum(np.square(x), axis=0))
    return np.linalg.norm(x, axis=0)

# Normalize an MxN matrix such that all N columns have unit length.
def matrix_norm(x):
    return x / (matrix_len(x) + 1e-9)

# Parameters for a fisheye lens, including its orientation.
class FisheyeLens:
    def __init__(self, rows=1024, cols=1024):
        # Fisheye lens parameters.
        self.fov_deg = 180
        self.radius_px = min(rows,cols) / 2
        # Pixel coordinates of the optical axis (X,Y).
        self.center_px = np.matrix([[cols/2], [rows/2]])
        # Quaternion mapping intended to actual optical axis.
        self.center_qq = [1, 0, 0, 0]

    def downsample(self, dsamp):
        self.radius_px /= dsamp
        self.center_px /= dsamp

    def get_x(self):
        return np.asscalar(self.center_px[0])

    def get_y(self):
        return np.asscalar(self.center_px[1])

    def to_dict(self):
        return {'cx':self.get_x(),
                'cy':self.get_y(),
                'cr':self.radius_px,
                'cf':self.fov_deg,
                'qw':self.center_qq[0],
                'qx':self.center_qq[1],
                'qy':self.center_qq[2],
                'qz':self.center_qq[3]}

    def from_dict(self, data):
        self.center_px[0] = data['cx']
        self.center_px[1] = data['cy']
        self.radius_px    = data['cr']
        self.fov_deg      = data['cf']
        self.center_qq[0] = data['qw']
        self.center_qq[1] = data['qx']
        self.center_qq[2] = data['qy']
        self.center_qq[3] = data['qz']

# Load or save lens configuration and alignment.
def load_config(file_obj, lens1, lens2):
    [data1, data2] = json.load(file_obj)
    lens1.from_dict(data1)
    lens2.from_dict(data2)

def save_config(file_obj, lens1, lens2):
    data = [lens1.to_dict(), lens2.to_dict()]
    json.dump(data, file_obj, indent=2, sort_keys=True)

# Fisheye source image, with lens and rotation parameters.
# Contains functions for extracting pixel data given direction vectors.
class FisheyeImage:
    # Load image file and set default parameters
    def __init__(self, src_file, lens=None):
        # Load the image file, and convert to a numpy matrix.
        self._update_img(Image.open(src_file))
        # Set lens parameters.
        if lens is None:
            self.lens = FisheyeLens(self.rows, self.cols)
        else:
            self.lens = lens

    # Update image matrix and corresponding size variables.
    def _update_img(self, img):
        self.img = np.array(img)
        self.rows = self.img.shape[0]
        self.cols = self.img.shape[1]
        self.clrs = self.img.shape[2]

    # Shrink source image and adjust lens accordingly.
    def downsample(self, dsamp):
        # Adjust lens parameters.
        self.lens.downsample(dsamp)
        # Determine the new image dimensions.
        # Note: PIL uses cols, rows whereas numpy uses rows, cols
        shape = (self.img.shape[1] / dsamp,     # Cols
                 self.img.shape[0] / dsamp)     # Rows
        # Convert matrix back to PIL Image and resample.
        img = Image.fromarray(self.img)
        img.thumbnail(shape, Image.BICUBIC)
        # Convert back and update size.
        self._update_img(img)

    # Given an 3xN array of "XYZ" vectors in panorama space (+X = Front),
    # convert each ray to 2xN coordinates in "UV" fisheye image space.
    def get_uv(self, xyz_vec):
        # Extract lens parameters of interest.
        fov_rad = self.lens.fov_deg * pi / 180
        fov_scale = np.float32(2 * self.lens.radius_px / fov_rad)
        # Normalize the input vector and rotate to match lens reference axes.
        xyz_rot = get_rotation_matrix(self.lens.center_qq) * matrix_norm(xyz_vec)
        # Convert to polar coordinates relative to lens boresight.
        # (In lens coordinates, unit vector's X axis gives boresight angle;
        #  normalize Y/Z to get a planar unit vector for the bearing.)
        # Note: Image +Y maps to 3D +Y, and image +X maps to 3D +Z.
        theta_rad = np.arccos(xyz_rot[0,:])
        proj_vec = matrix_norm(np.concatenate((xyz_rot[2,:], xyz_rot[1,:])))
        # Fisheye lens maps 3D angle to focal-plane radius.
        # TODO: Do we need a better model for lens distortion?
        rad_px = theta_rad * fov_scale
        # Convert back to focal-plane rectangular coordinates.
        uv = np.multiply(rad_px, proj_vec) + self.lens.center_px
        return np.asarray(uv + 0.5, dtype=int)

    # Given an 2xN array of UV pixel coordinates, check if each pixel is
    # within the fisheye field of view. Returns N-element boolean mask.
    def get_mask(self, uv_px):
        # Check whether each coordinate is within outer image bounds,
        # and within the illuminated area under the fisheye lens.
        x_mask = np.logical_and(0 <= uv_px[0], uv_px[0] < self.cols)
        y_mask = np.logical_and(0 <= uv_px[1], uv_px[1] < self.rows)
        # Check whether each coordinate is within the illuminated area.
        r_mask = matrix_len(uv_px - self.lens.center_px) < self.lens.radius_px
        # All three checks must pass to be considered visible.
        all_mask = np.logical_and(r_mask, np.logical_and(x_mask, y_mask))
        return np.squeeze(np.asarray(all_mask))

    # Given an 2xN array of UV pixel coordinates, return a weight score
    # that is proportional to the distance from the edge.
    def get_weight(self, uv_px):
        mm = self.get_mask(uv_px)
        rr = self.lens.radius_px - matrix_len(uv_px - self.lens.center_px)
        rr[~mm] = 0
        return rr

    # Given a 2xN array of UV pixel coordinates, return the value of each
    # corresponding pixel. Output format is Nx1 (grayscale) or Nx3 (color).
    # Pixels outside the fisheye's field of view are pure black (0) or (0,0,0).
    def get_pixels(self, uv_px):
        # Create output array with default pixel values.
        pcount = uv_px.shape[1]
        result = np.zeros((pcount, self.clrs), dtype=self.img.dtype)
        # Overwrite in-bounds pixels as specified above.
        self.add_pixels(uv_px, result)
        return result

    # Given a 2xN array of UV pixel coordinates, write the value of each
    # corresponding pixel to the linearized input/output image (Nx3).
    # Several weighting modes are available.
    def add_pixels(self, uv_px, img1d, weight=None):
        # Lookup row & column for each in-bounds coordinate.
        mask = self.get_mask(uv_px)
        xx = uv_px[0,mask]
        yy = uv_px[1,mask]
        # Update matrix according to assigned weight.
        if weight is None:
            img1d[mask] = self.img[yy,xx]
        elif np.isscalar(weight):
            img1d[mask] += self.img[yy,xx] * weight
        else:
            w1 = np.asmatrix(weight, dtype='float32')
            w3 = w1.transpose() * np.ones((1,3))
            img1d[mask] += np.multiply(self.img[yy,xx], w3[mask])

# A panorama image made from several FisheyeImage sources.
# TODO: Add support for supersampled anti-aliasing filters.
class PanoramaImage:
    def __init__(self, src_list):
        self.debug = True
        self.sources = src_list
        self.dtype = self.sources[0].img.dtype
        self.clrs = self.sources[0].clrs

    # Downsample each source image.
    def downsample(self, dsamp):
        for src in self.sources:
            src.downsample(dsamp)

    # Return a list of 'mode' strings suitable for render_xx() methods.
    def get_render_modes(self):
        return ['overwrite', 'align', 'blend']

    # Retrieve a scaled copy of lens parameters for the Nth source.
    def scale_lens(self, idx, scale=None):
        temp = deepcopy(self.sources[idx].lens)
        temp.downsample(1.0 / scale)
        return temp

    # Using current settings as an initial guess, use an iterative optimizer
    # to better align the source images.  Adjusts FOV of each lens, as well
    # as the rotation quaternions for all lenses except the first.
    # TODO: Implement a higher-order loop that iterates this step with
    #       progressively higher resolution.  (See also: create_panorama)
    # TODO: Find a better scoring heuristic.  Present solution always
    #       converges on either FOV=0 or FOV=9999, depending on wt_pixel.
    def optimize(self, psize=256, wt_pixel=1000, wt_blank=1000):
        # Precalculate raster-order XYZ coordinates at given resolution.
        [xyz, rows, cols] = self._get_equirectangular_raster(psize)
        # Scoring function gives bonus points per overlapping pixel.
        score = lambda svec: self._score(svec, xyz, wt_pixel, wt_blank)
        # Multivariable optimization using gradient-descent or similar.
        # https://docs.scipy.org/doc/scipy/reference/tutorial/optimize.html
        svec0 = self._get_state_vector()
        final = minimize(score, svec0, method='Nelder-Mead',
                         options={'xtol':1e-4, 'disp':True})
        # Store final lens parameters.
        self._set_state_vector(final.x)

    # Render combined panorama in equirectangular projection mode.
    # See also: https://en.wikipedia.org/wiki/Equirectangular_projection
    def render_equirectangular(self, out_size, mode='blend'):
        # Render the entire output in a single pass.
        [xyz, rows, cols] = self._get_equirectangular_raster(out_size)
        return Image.fromarray(self._render(xyz, rows, cols, mode))

    # Render combined panorama in cubemap projection mode.
    # See also: https://en.wikipedia.org/wiki/Cube_mapping
    def render_cubemap(self, out_size, mode='blend'):
        # Create coordinate arrays.
        cvec = np.arange(out_size, dtype='float32') - out_size/2        # Coordinate range [-S/2, S/2)
        vec0 = np.ones(out_size*out_size, dtype='float32') * out_size/2 # Constant vector +S/2
        vec1 = np.repeat(cvec, out_size)                                # Increment every N steps
        vec2 = np.tile(cvec, out_size)                                  # Sweep N times
        # Create XYZ coordinate vectors and render each cubemap face.
        render = lambda(xyz): self._render(xyz, out_size, out_size, mode)
        xm = render(np.matrix([-vec0, vec1, vec2]))     # -X face
        xp = render(np.matrix([vec0, vec1, -vec2]))     # +X face
        ym = render(np.matrix([-vec1, -vec0, vec2]))    # -Y face
        yp = render(np.matrix([vec1, vec0, vec2]))      # +Y face
        zm = render(np.matrix([-vec2, vec1, -vec0]))    # -Z face
        zp = render(np.matrix([vec2, vec1, vec0]))      # +Z face
        # Concatenate the individual faces in canonical order:
        # https://en.wikipedia.org/wiki/Cube_mapping#Memory_Addressing
        img_mat = np.concatenate([zp, zm, ym, yp, xm, xp], axis=0)
        return Image.fromarray(img_mat)

    # Get XYZ vectors for an equirectangular render, in raster order.
    # (Each row left to right, with rows concatenates from top to bottom.)
    def _get_equirectangular_raster(self, out_size):
        # Set image size (2x1 aspect ratio)
        rows = out_size
        cols = 2*out_size
        # Calculate longitude of each column.
        theta_x = np.linspace(-pi, pi, cols, endpoint=False, dtype='float32')
        cos_x = np.cos(theta_x).reshape(1,cols)
        sin_x = np.sin(theta_x).reshape(1,cols)
        # Calculate lattitude of each row.
        ystep = pi / rows
        theta_y = np.linspace(-pi/2 + ystep/2, pi/2 - ystep/2, rows, dtype='float32')
        cos_y = np.cos(theta_y).reshape(rows,1)
        sin_y = np.sin(theta_y).reshape(rows,1)
        # Calculate X, Y, and Z coordinates for each output pixel.
        x = cos_y * cos_x
        y = sin_y * np.ones((1,cols), dtype='float32')
        z = cos_y * sin_x
        # Vectorize the coordinates in raster order.
        xyz = np.matrix([x.ravel(), y.ravel(), z.ravel()])
        return [xyz, rows, cols]

    # Convert all lens parameters to a state vector. See also: optimize()
    def _get_state_vector(self):
        nsrc = len(self.sources)
        assert nsrc > 0
        svec = np.zeros(4*nsrc - 3)
        # First lens: Only the FOV is stored.
        svec[0] = self.sources[0].lens.fov_deg - 180
        # All other lenses: Store FOV and quaternion parameters.
        for n in range(1, nsrc):
            svec[4*n-3] = self.sources[n].lens.fov_deg - 180
            svec[4*n-2] = self.sources[n].lens.center_qq[1]
            svec[4*n-1] = self.sources[n].lens.center_qq[2]
            svec[4*n-0] = self.sources[n].lens.center_qq[3]
        return svec

    # Update lens parameters based on state vector.  See also: optimize()
    def _set_state_vector(self, svec):
        # Sanity check on input vector.
        nsrc = len(self.sources)
        assert len(svec) == (4*nsrc - 3)
        # First lens: Only the FOV is changed.
        self.sources[0].lens.fov_deg = svec[0] + 180
        # All other lenses: Update FOV and quaternion parameters.
        for n in range(1, nsrc):
            self.sources[n].lens.fov_deg = svec[4*n-3] + 180
            self.sources[n].lens.center_qq[1] = svec[4*n-2]
            self.sources[n].lens.center_qq[2] = svec[4*n-1]
            self.sources[n].lens.center_qq[3] = svec[4*n-0]

    # Add pixels from every source to form a complete output image.
    # Several blending modes are available. See also: get_render_modes()
    def _render(self, xyz, rows, cols, mode):
        # Allocate Nx3 or Nx1 "1D" pixel-list (raster-order).
        img1d = np.zeros((rows*cols, self.clrs), dtype='float32')
        # Determine rendering mode:
        if mode == 'overwrite':
            # Simplest mode: Draw first, then blindly overwrite second.
            for src in self.sources:
                uv = src.get_uv(xyz)
                src.add_pixels(uv, img1d)
        elif mode == 'align':
            # Alignment mode: Draw each one at 50% intensity.
            for src in self.sources:
                uv = src.get_uv(xyz)
                src.add_pixels(uv, img1d, 0.5)
        elif mode == 'blend':
            # Linear nearest-source blending.
            uv_list = []
            wt_list = []
            wt_total = np.zeros(rows*cols, dtype='float32')
            # Calculate per-image and total weight matrices.
            for src in self.sources:
                uv = src.get_uv(xyz)
                wt = src.get_weight(uv)
                uv_list.append(uv)
                wt_list.append(wt)
                wt_total += wt
            # Render overall image using calculated weights.
            for n in range(len(self.sources)):
                wt_norm = wt_list[n] / wt_total
                self.sources[n].add_pixels(uv_list[n], img1d, wt_norm)
        else:
            raise ValueError('Invalid render mode.')
        # Convert to fixed-point image matrix and return.
        img2d = np.reshape(img1d, (rows, cols, self.clrs))
        return np.asarray(img2d, dtype=self.dtype)

    # Compute a normalized alignment score, based on size of overlap and
    # the pixel-differences in that region.  Note: Lower = Better.
    def _score(self, svec, xyz, wt_pixel, wt_blank):
        # Update lens parameters from state vector.
        self._set_state_vector(svec)
        # Determine masks for each input image.
        uv0 = self.sources[0].get_uv(xyz)
        uv1 = self.sources[1].get_uv(xyz)
        wt0 = self.sources[0].get_weight(uv0) > 0
        wt1 = self.sources[1].get_weight(uv1) > 0
        # Count overlapping pixels.
        ovr_mask = np.logical_and(wt0, wt1)             # Overlapping pixel
        pix_count = np.sum(wt0) + np.sum(wt1)           # Total drawn pixels
        blk_count = np.sum(np.logical_and(~wt0, ~wt1))  # Number of blank pixels
        # Allocate Nx3 or Nx1 "1D" pixel-list (raster-order).
        pcount = max(xyz.shape)
        img1d = np.zeros((pcount, self.clrs), dtype='float32')
        # Render the difference image, overlapping region only.
        self.sources[0].add_pixels(uv0, img1d, 1.0*ovr_mask)
        self.sources[1].add_pixels(uv1, img1d, -1.0*ovr_mask)
        # Sum-of-differences.
        sum_sqd = np.sum(np.sum(np.sum(np.square(img1d))))
        # Compute overall score.  (Note: Higher = Better)
        score = sum_sqd + wt_blank * blk_count - wt_pixel * pix_count
        # (Debug) Print status information.
        if (self.debug):
            print str(svec) + ' --> ' + str(score)
        return score

# Tkinter GUI window for loading a fisheye image.
class FisheyeAlignmentGUI:
    def __init__(self, parent, src_file, lens):
        # Set flag once all window objects created.
        self.init_done = False
        # Final result is the lens object.
        self.lens = lens
        # Load the input file.
        self.img = Image.open(src_file)
        # Create frame for this window with two vertical panels...
        parent.wm_title('Fisheye Alignment')
        self.frame = tk.Frame(parent)
        self.controls = tk.Frame(self.frame)
        # Make sliders for adjusting the lens parameters quaternion.
        self.x = self._make_slider(self.controls, 0, 'Center-X (px)',
                                   lens.get_x(), self.img.size[0])
        self.y = self._make_slider(self.controls, 1, 'Center-Y (px)',
                                   lens.get_y(), self.img.size[1])
        self.r = self._make_slider(self.controls, 2, 'Radius (px)',
                                   lens.radius_px, self.img.size[0])
        self.f = self._make_slider(self.controls, 3, 'Field of view (deg)',
                                   lens.fov_deg, 240, res=0.1)
        # Create a frame for the preview image, which resizes based on the
        # outer frame but does not respond to the contained preview size.
        self.preview_frm = tk.Frame(self.frame)
        self.preview_frm.bind('<Configure>', self._update_callback)  # Update on resize
        # Create the canvas object for the preview image.
        self.preview = tk.Canvas(self.preview_frm)
        # Finish frame creation.
        self.controls.pack(side=tk.LEFT)
        self.preview.pack(fill=tk.BOTH, expand=1)
        self.preview_frm.pack(side=tk.LEFT, fill=tk.BOTH, expand=1)
        self.frame.pack(fill=tk.BOTH, expand=1)
        # Render the image once at default size
        self.init_done = True
        self.update_preview((800,800))
        # Disable further size propagation.
        self.preview_frm.update()
        self.preview_frm.pack_propagate(0)

    # Redraw the preview image using latest GUI parameters.
    def update_preview(self, psize):
        # Safety check: Ignore calls during construction/destruction.
        if not self.init_done: return
        # Copy latest user settings to the lens object.
        self.lens.fov_deg = self.f.get()
        self.lens.radius_px = self.r.get()
        self.lens.center_px[0] = self.x.get()
        self.lens.center_px[1] = self.y.get()
        # Re-scale the image to match the canvas size.
        # Note: Make a copy first, because thumbnail() operates in-place.
        self.img_sc = self.img.copy()
        self.img_sc.thumbnail(psize, Image.NEAREST)
        self.img_tk = ImageTk.PhotoImage(self.img_sc)
        # Re-scale the x/y/r parameters to match the preview scale.
        pre_scale = float(psize[0]) / float(self.img.size[0])
        x = self.x.get() * pre_scale
        y = self.y.get() * pre_scale
        r = self.r.get() * pre_scale
        # Clear and redraw the canvas.
        self.preview.delete('all')
        self.preview.create_image(0, 0, anchor=tk.NW, image=self.img_tk)
        self.preview.create_oval(x-r, y-r, x+r, y+r,
                                 outline='#C00000', width=3)

    # Make a combined label/textbox/slider for a given variable:
    def _make_slider(self, parent, rowidx, label, inival, maxval, res=0.5):
        # Create shared variable and set initial value.
        tkvar = tk.DoubleVar()
        tkvar.set(inival)
        # Set a callback for whenever tkvar is changed.
        # (The 'command' callback on the SpinBox only applies to the buttons.)
        tkvar.trace('w', self._update_callback)
        # Create the Label, SpinBox, and Scale objects.
        label = tk.Label(parent, text=label)
        spbox = tk.Spinbox(parent,
            textvariable=tkvar,
            from_=0, to=maxval, increment=res)
        slide = tk.Scale(parent,
            orient=tk.HORIZONTAL,
            showvalue=0,
            variable=tkvar,
            from_=0, to=maxval, resolution=res)
        label.grid(row=rowidx, column=0)
        spbox.grid(row=rowidx, column=1)
        slide.grid(row=rowidx, column=2)
        return tkvar

    # Find the largest output size that fits within the given bounds and
    # matches the aspect ratio of the original source image.
    def _get_aspect_size(self, max_size):
        img_ratio = float(self.img.size[1]) / float(self.img.size[0])
        return (min(max_size[0], max_size[1] / img_ratio),
                min(max_size[1], max_size[0] * img_ratio))

    # Thin wrapper for update_preview(), used to strip Tkinter arguments.
    def _update_callback(self, *args):
        # Sanity check that initialization is completed:
        if not self.init_done: return
        # Determine the render size.  (Always 2:1 aspect ratio.)
        psize = self._get_aspect_size((self.preview_frm.winfo_width(),
                                       self.preview_frm.winfo_height()))
        # Render the preview at the given size.
        if psize[0] >= 10 and psize[1] >= 10:
            self.update_preview(psize)

# Tkinter GUI window for calibrating fisheye alignment.
class PanoramaAlignmentGUI:
    def __init__(self, parent, panorama, psize=512):
        self.init_done = False
        # Store source and preview size
        self.panorama = panorama
        # Create frame for this window with two vertical panels...
        parent.wm_title('Panorama Alignment')
        self.frame = tk.Frame(parent)
        self.controls = tk.Frame(self.frame)
        # Make a drop-menu to select the rendering mode.
        tk.Label(self.controls, text='Preview mode').grid(row=0, column=0, sticky=tk.W)
        self.mode = tk.StringVar()
        self.mode.set('align')
        self.mode.trace('w', self._update_callback)
        mode_list = self.panorama.get_render_modes()
        mode_drop = tk.OptionMenu(self.controls, self.mode, *mode_list)
        mode_drop.grid(row=0, column=1, columnspan=2, sticky='NESW')
        # Determine which axis marks the main 180 degree rotation.
        front_qq = panorama.sources[0].lens.center_qq
        back_qq  = panorama.sources[1].lens.center_qq
        diff_qq  = mul_qq(front_qq, back_qq)
        # Create the axis selection toggle. (Flip on Y or Z)
        self.flip_axis = tk.BooleanVar()
        self.flip_axis.trace('w', self._update_callback)
        if abs(diff_qq[2]) > abs(diff_qq[3]):
            self.flip_axis.set(False)
            flip_qq = [0,0,1,0]
        else:
            self.flip_axis.set(True)
            flip_qq = [0,0,0,1]
        tk.Label(self.controls, text='Flip axis').grid(row=1, column=0, sticky=tk.W)
        axis_chk = tk.Checkbutton(self.controls, variable=self.flip_axis)
        axis_chk.grid(row=1, column=1, columnspan=2, sticky='NESW')
        # Extract the (hopefully small) alignment offset.
        flip_conj = conj_qq(mul_qq(flip_qq, front_qq))
        align_qq = mul_qq(back_qq, flip_conj)
        # Make three sliders for adjusting the relative alignment.
        self.slide_rx = self._make_slider(self.controls, 2, 'Rotate X', front_qq[1])
        self.slide_ry = self._make_slider(self.controls, 3, 'Rotate Y', front_qq[2])
        self.slide_rz = self._make_slider(self.controls, 4, 'Rotate Z', front_qq[3])
        self.slide_ax = self._make_slider(self.controls, 5, 'Align X', align_qq[1])
        self.slide_ay = self._make_slider(self.controls, 6, 'Align Y', align_qq[2])
        self.slide_az = self._make_slider(self.controls, 7, 'Align Z', align_qq[3])
        # Finish control-frame creation.
        self.controls.pack(side=tk.LEFT)
        # Create a frame for the preview image, which resizes based on the
        # outer frame but does not respond to the contained preview size.
        self.preview_frm = tk.Frame(self.frame)
        self.preview_frm.bind('<Configure>', self._update_callback)  # Update on resize
        # Add the preview.
        self.preview_lbl = tk.Label(self.preview_frm)   # Label displays image
        self.preview_lbl.pack()
        self.preview_frm.pack(fill=tk.BOTH, expand=1)
        # Finish frame creation.
        self.frame.pack(fill=tk.BOTH, expand=1)
        # Render the image once at default size
        self.init_done = True
        self.update_preview(psize)
        # Disable further size propagation.
        self.preview_frm.update()
        self.preview_frm.pack_propagate(0)

    # Update the GUI preview using latest alignment parameters.
    def update_preview(self, psize):
        # Sanity check that initialization is completed:
        if not self.init_done: return
        # Determine the primary axis of rotation.
        if self.flip_axis.get():
            flip_qq = [0,0,0,1]
        else:
            flip_qq = [0,0,1,0]
        # Calculate the orientation of both lenses.
        front_qq = norm_qq(self.slide_rx.get(),
                           self.slide_ry.get(),
                           self.slide_rz.get())
        align_qq = norm_qq(self.slide_ax.get(),
                           self.slide_ay.get(),
                           self.slide_az.get())
        back_qq = mul_qq(align_qq, mul_qq(flip_qq, front_qq))
        self.panorama.sources[0].lens.center_qq = front_qq
        self.panorama.sources[1].lens.center_qq = back_qq
        # Render the preview.
        # Note: The Tk-Label doesn't maintain a reference to the image object.
        #       To avoid garbage-collection, keep one in this class.
        self.preview_img = ImageTk.PhotoImage(
            self.panorama.render_equirectangular(psize, self.mode.get()))
        # Assign the new icon.
        self.preview_lbl.configure(image=self.preview_img)

    # Find the largest output size that fits within the given bounds and
    # matches the 2:1 aspect ratio of the equirectangular preview.
    def _get_aspect_size(self, max_size):
        return (min(max_size[0], max_size[1] / 2),
                min(max_size[1], max_size[0] * 2))

    # Make a combined label/textbox/slider for a given variable:
    def _make_slider(self, parent, rowidx, label, inival):
        # Set limits and resolution.
        lim = 1.0
        res = 0.001
        # Create shared variable.
        tkvar = tk.DoubleVar()
        tkvar.set(inival)
        # Set a callback for whenever tkvar is changed.
        # (The 'command' callback on the SpinBox only applies to the buttons.)
        tkvar.trace('w', self._update_callback)
        # Create the Label, SpinBox, and Scale objects.
        label = tk.Label(parent, text=label)
        spbox = tk.Spinbox(parent,
            textvariable=tkvar,
            from_=-lim, to=lim, increment=res)
        slide = tk.Scale(parent,
            orient=tk.HORIZONTAL,
            showvalue=0,
            variable=tkvar,
            from_=-lim, to=lim, resolution=res)
        label.grid(row=rowidx, column=0, sticky='W')
        spbox.grid(row=rowidx, column=1)
        slide.grid(row=rowidx, column=2)
        return tkvar

    # Thin wrapper for update_preview(), used to strip Tkinter arguments.
    def _update_callback(self, *args):
        # Sanity check that initialization is completed:
        if not self.init_done: return
        # Determine the render size.  (Always 2:1 aspect ratio.)
        psize = min(self.preview_frm.winfo_width()/2,
                    self.preview_frm.winfo_height())
        # Render the preview at the given size.
        # TODO: Fudge factor of -2 avoids infinite resize loop.
        #       Is there a better way?
        if psize >= 10:
            self.update_preview(psize-2)

# Tkinter GUI window for end-to-end alignment and rendering.
class PanoramaGUI:
    def __init__(self, parent):
        # Store reference object for creating child dialogs.
        self.parent = parent
        self.win_lens1 = None
        self.win_lens2 = None
        self.win_align = None
        self.work_done = False
        self.work_error = None
        self.work_status = None
        # Create dummy lens configuration.
        self.lens1 = FisheyeLens()
        self.lens2 = FisheyeLens()
        self.lens2.center_qq = [0,0,1,0]  # Default flip along Y axis.
        # Create frame for this GUI.
        parent.wm_title('Panorama Creation Tool')
        frame = tk.Frame(parent)
        # Make file-selection inputs for the two images.
        img_frame = tk.LabelFrame(frame, text='Input Images')
        self.img1 = self._make_file_select(img_frame, 0, 'Image #1')
        self.img2 = self._make_file_select(img_frame, 1, 'Image #2')
        img_frame.pack()
        # Make buttons to load, save, and adjust the lens configuration.
        lens_frame = tk.LabelFrame(frame, text='Lens Configuration and Alignment')
        btn_lens1 = tk.Button(lens_frame, text='Lens 1', command=self._adjust_lens1)
        btn_lens2 = tk.Button(lens_frame, text='Lens 2', command=self._adjust_lens2)
        btn_align = tk.Button(lens_frame, text='Align', command=self._adjust_align)
        btn_auto = tk.Button(lens_frame, text='Auto', command=self._auto_align_start)
        btn_load = tk.Button(lens_frame, text='Load', command=self.load_config)
        btn_save = tk.Button(lens_frame, text='Save', command=self.save_config)
        btn_lens1.grid(row=0, column=0, sticky='NESW')
        btn_lens2.grid(row=0, column=1, sticky='NESW')
        btn_align.grid(row=0, column=2, sticky='NESW')
        btn_auto.grid(row=0, column=3, sticky='NESW')
        btn_load.grid(row=1, column=0, columnspan=2, sticky='NESW')
        btn_save.grid(row=1, column=2, columnspan=2, sticky='NESW')
        lens_frame.pack(fill=tk.BOTH)
        # Buttons to render the final output in different modes.
        out_frame = tk.LabelFrame(frame, text='Final output rendering')
        btn_rect = tk.Button(out_frame, text='Equirectangular',
                             command=self._render_rect)
        btn_cube = tk.Button(out_frame, text='Cubemap',
                             command=self._render_cube)
        btn_rect.pack(fill=tk.BOTH)
        btn_cube.pack(fill=tk.BOTH)
        out_frame.pack(fill=tk.BOTH)
        # Status indicator box.
        self.status = tk.Label(frame, relief=tk.SUNKEN,
                               text='Select input images to begin.')
        self.status.pack(fill=tk.BOTH)
        # Finish frame creation.
        frame.pack()

    # Helper function to destroy an object.
    def _destroy(self, obj):
        if obj is not None:
            obj.destroy()

    # Popup dialogs for each alignment step.
    def _adjust_lens1(self):
        self._destroy(self.win_lens1)
        try:
            self.win_lens1 = tk.Toplevel(self.parent)
            FisheyeAlignmentGUI(self.win_lens1, self.img1.get(), self.lens1)
        except IOError:
            self._destroy(self.win_lens1)
            tkMessageBox.showerror('Error', 'Unable to read image file #1.')
        except:
            self._destroy(self.win_lens1)
            tkMessageBox.showerror('Dialog creation error', traceback.format_exc())

    def _adjust_lens2(self):
        self._destroy(self.win_lens2)
        try:
            self.win_lens2 = tk.Toplevel(self.parent)
            FisheyeAlignmentGUI(self.win_lens2, self.img2.get(), self.lens2)
        except IOError:
            self._destroy(self.win_lens2)
            tkMessageBox.showerror('Error', 'Unable to read image file #2.')
        except:
            self._destroy(self.win_lens2)
            tkMessageBox.showerror('Dialog creation error', traceback.format_exc())

    def _adjust_align(self):
        self._destroy(self.win_align)
        try:
            pan = self._create_panorama()
            self.win_align = tk.Toplevel(self.parent)
            PanoramaAlignmentGUI(self.win_align, pan)
        except:
            self._destroy(self.win_align)
            tkMessageBox.showerror('Dialog creation error', traceback.format_exc())

    # Automatic alignment.
    # Use worker thread, because this may take a while.
    def _auto_align_start(self):
        try:
            # Create panorama object from within GUI thread, since it depends
            # on Tk variables which are NOT thread-safe.
            pan = self._create_panorama()
            # Display status message and display hourglass...
            self._set_status('Starting auto-alignment...', 'wait')
            # Create a new worker thread.
            work = Thread(target=self._auto_align_work, args=[pan])
            work.start()
            # Set a timer to periodically check for completion.
            self.parent.after(200, self._auto_align_timer)
        except:
            tkMessageBox.showerror('Auto-alignment error', traceback.format_exc())

    def _auto_align_work(self, pan):
        try:
            # Repeat alignment at progressively higher resolution.
            self._auto_align_step(pan, 16, 128, 'Stage 1/4')
            self._auto_align_step(pan,  8, 128, 'Stage 2/4')
            self._auto_align_step(pan,  4, 192, 'Stage 3/4')
            self._auto_align_step(pan,  2, 256, 'Stage 4/4')
            # Signal success!
            self.work_status = 'Auto-alignment completed.'
            self.work_error = None
            self.work_done = True
        except:
            # Signal error.
            self.work_status = 'Auto-alignment failed.'
            self.work_error = traceback.format_exc()
            self.work_done = True

    def _auto_align_step(self, pan, scale, psize, label):
        # Update status message.
        self.work_status = 'Auto-alignment: ' + str(label)
        # Create a panorama object at 1/scale times original resolution.
        pan_sc = deepcopy(pan)
        pan_sc.downsample(scale)
        # Run optimization, rendering each hypothesis at the given resolution.
        pan_sc.optimize(psize)
        # Update local lens parameters.
        # Note: These are not Tk variables, so are safe to change.
        self.lens1 = pan_sc.scale_lens(0, scale)
        self.lens2 = pan_sc.scale_lens(1, scale)

    # Timer callback object checks outputs from worker thread.
    # (Tkinter objects are NOT thread safe.)
    def _auto_align_timer(self, *args):
        # Check thread status.
        if self.work_done:
            # Update status message, with popup on error.
            if self.work_status is not None:
                self._set_status(self.work_status)
            if self.work_error is not None:
                self._set_status('Auto-alignment failed.')
                tkMessageBox.showerror('Auto-alignment error', self.work_error)
            # Clear the 'done' flag for future runs.
            self.work_done = False
        else:
            # Update status message and keep hourglass.
            if self.work_status is not None:
                self._set_status(self.work_status, 'wait')
            # Reset timer to be called again.
            self.parent.after(200, self._auto_align_timer)

    # Create panorama object using current settings.
    def _create_panorama(self):
        img1 = FisheyeImage(self.img1.get(), self.lens1)
        img2 = FisheyeImage(self.img2.get(), self.lens2)
        return PanoramaImage((img1, img2))

    # Load or save lens configuration and alignment.
    def load_config(self, filename=None):
        if filename is None:
            file_obj = tkFileDialog.askopenfile()
            if file_obj is None: return
        else:
            file_obj = open(filename, 'r')
        try:
            load_config(file_obj, self.lens1, self.lens2)
        except:
            tkMessageBox.showerror('Config load error', traceback.format_exc())

    def save_config(self, filename=None):
        if filename is None:
            file_obj = tkFileDialog.asksaveasfile()
            if file_obj is None: return
        else:
            file_obj = open(filename, 'w')
        try:
            save_config(file_obj, self.lens1, self.lens2)
        except:
            tkMessageBox.showerror('Config save error', traceback.format_exc())

    # Render and save output in various modes.
    def _render_generic(self, render_type, render_size=1024):
        # Popup asks user for output file.
        file_obj = tkFileDialog.asksaveasfile(mode='wb')
        # Abort if user clicks 'cancel'.
        if file_obj is None: return
        # Proceed with rendering...
        self._set_status('Rendering image: ' + file_obj.name, 'wait')
        try:
            panorama = self._create_panorama()
            render_func = getattr(panorama, render_type)
            render_func(render_size).save(file_obj)
            self._set_status('Done!')
        except:
            tkMessageBox.showerror('Render error', traceback.format_exc())
            self._set_status('Render failed.')

    def _render_rect(self):
        self._render_generic('render_equirectangular')

    def _render_cube(self):
        self._render_generic('render_cubemap')

    # Callback to create a file-selection popup.
    def _file_select(self, tkstr):
        result = tkFileDialog.askopenfile()
        if result is not None:
            tkstr.set(result.name)
            result.close()

    # Make a combined label/textbox/slider for a given variable:
    def _make_file_select(self, parent, rowidx, label):
        # Create string variable.
        tkstr = tk.StringVar()
        # Create callback event handler.
        cmd = lambda: self._file_select(tkstr)
        # Create the Label, Entry, and Button objects.
        label = tk.Label(parent, text=label)
        entry = tk.Entry(parent, textvariable=tkstr)
        button = tk.Button(parent, text='...', command=cmd)
        label.grid(row=rowidx, column=0, sticky='W')
        entry.grid(row=rowidx, column=1)
        button.grid(row=rowidx, column=2)
        return tkstr

    # Set status text, and optionally update cursor.
    def _set_status(self, status, cursor='arrow'):
        self.parent.config(cursor=cursor)
        self.status.configure(text=status)

def launch_tk_gui(flens='', fimg1='', fimg2=''):
    # Create TK root object and GUI window.
    root = tk.Tk()
    gui = PanoramaGUI(root)
    # Load parameters if specified.
    if flens is not None and len(flens) > 0:
        gui.load_config(flens)
    if fimg1 is not None and len(fimg1) > 0:
        gui.img1.set(fimg1)
    if fimg2 is not None and len(fimg2) > 0:
        gui.img2.set(fimg2)
    # Start main loop.
    root.mainloop()

if __name__ == "__main__":
    # If we have exactly four arguments, run command-line version.
    if len(sys.argv) == 5 and sys.argv[4].startswith('gui'):
        # Special case for interactive mode.
        launch_tk_gui(sys.argv[1], sys.argv[2], sys.argv[3])
    elif len(sys.argv) == 5:
        # First argument is the lens alignment file.
        lens1 = FisheyeLens()
        lens2 = FisheyeLens()
        cfg = open(sys.argv[1], 'r')
        load_config(cfg, lens1, lens2)
        # Second and third arguments are the source files.
        img1 = FisheyeImage(sys.argv[2], lens1)
        img2 = FisheyeImage(sys.argv[3], lens2)
        # Fourth argument is the mode and output filename.
        if sys.argv[4].startswith('cube='):
            out = sys.argv[5:]
            pan = PanoramaImage((img1, img2))
            pan.render_cubemap(1024).save(out)
        elif sys.argv[4].startswith('rect='):
            out = sys.argv[5:]
            pan = PanoramaImage((img1, img2))
            pan.render_equirectangular(1024).save(out)
        else:
            print 'Unrecognized render mode (cube=, rect=, gui)'
    elif len(sys.argv) > 1:
        # If requested, print command-line usage information.
        print 'Usage instructions:'
        print '  python fisheye.py'
        print '    Start interactive alignment GUI.'
        print '  python fisheye.py -help'
        print '    Print this help message.'
        print '  python fisheye.py lens.cfg in1.jpg in2.jpg gui'
        print '    Launch interactive GUI with specified default options'
        print '  python fisheye.py lens.cfg in1.jpg in2.jpg rect=out.png'
        print '    Render and save equirectangular panorama using specified'
        print '    lens configuration and source images.'
        print '  python fisheye.py lens.cfg in1.jpg in2.jpg cube=out.png'
        print '    Render and save cubemap panorama using specified'
        print '    lens configuration and source images.'
    else:
        # Otherwise, start the interactive GUI with all fields blank.
        launch_tk_gui()


text:
#include <common.h>
#include <dm.h>
#include <errno.h>
#include <timer.h>
#include <asm/io.h>
#include <asm/arch/clock.h>

DECLARE_GLOBAL_DATA_PTR;

/* Timer register bits */
#define TCLR_START			BIT(0)	/* Start=1 */
#define TCLR_AUTO_RELOAD		BIT(1)	/* Auto reload */
#define TCLR_PRE_EN			BIT(5)	/* Pre-scaler enable */
#define TCLR_PTV_SHIFT			(2)	/* Pre-scaler shift value */

#define TIMER_CLOCK             (V_SCLK / (2 << CONFIG_SYS_PTV))

struct omap_gptimer_regs {
	unsigned int tidr;		/* offset 0x00 */
	unsigned char res1[12];
	unsigned int tiocp_cfg;		/* offset 0x10 */
	unsigned char res2[12];
	unsigned int tier;		/* offset 0x20 */
	unsigned int tistatr;		/* offset 0x24 */
	unsigned int tistat;		/* offset 0x28 */
	unsigned int tisr;		/* offset 0x2c */
	unsigned int tcicr;		/* offset 0x30 */
	unsigned int twer;		/* offset 0x34 */
	unsigned int tclr;		/* offset 0x38 */
	unsigned int tcrr;		/* offset 0x3c */
	unsigned int tldr;		/* offset 0x40 */
	unsigned int ttgr;		/* offset 0x44 */
	unsigned int twpc;		/* offset 0x48 */
	unsigned int tmar;		/* offset 0x4c */
	unsigned int tcar1;		/* offset 0x50 */
	unsigned int tscir;		/* offset 0x54 */
	unsigned int tcar2;		/* offset 0x58 */
};

/* Omap Timer Priv */
struct omap_timer_priv {
	struct omap_gptimer_regs *regs;
};

static int omap_timer_get_count(struct udevice *dev, u64 *count)
{
	struct omap_timer_priv *priv = dev_get_priv(dev);

	*count = readl(&priv->regs->tcrr);

	return 0;
}

static int omap_timer_probe(struct udevice *dev)
{
	struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
	struct omap_timer_priv *priv = dev_get_priv(dev);

	uc_priv->clock_rate = TIMER_CLOCK;

	/* start the counter ticking up, reload value on overflow */
	writel(0, &priv->regs->tldr);
	/* enable timer */
	writel((CONFIG_SYS_PTV << 2) | TCLR_PRE_EN | TCLR_AUTO_RELOAD |
	       TCLR_START, &priv->regs->tclr);

	return 0;
}

static int omap_timer_ofdata_to_platdata(struct udevice *dev)
{
	struct omap_timer_priv *priv = dev_get_priv(dev);

	priv->regs = (struct omap_gptimer_regs *)dev_get_addr(dev);

	return 0;
}

static const struct timer_ops omap_timer_ops = {
	.get_count = omap_timer_get_count,
};

static const struct udevice_id omap_timer_ids[] = {
	{ .compatible = "ti,am335x-timer" },
	{ .compatible = "ti,am4372-timer" },
	{ .compatible = "ti,omap5430-timer" },
	{}
};

U_BOOT_DRIVER(omap_timer) = {
	.name	= "omap_timer",
	.id	= UCLASS_TIMER,
	.of_match = omap_timer_ids,
	.ofdata_to_platdata = omap_timer_ofdata_to_platdata,
	.priv_auto_alloc_size = sizeof(struct omap_timer_priv),
	.probe = omap_timer_probe,
	.ops	= &omap_timer_ops,
	.flags = DM_FLAG_PRE_RELOC,
};


text:
package jhc.redsniff.internal.describe;

import jhc.redsniff.internal.core.Item;

import org.hamcrest.SelfDescribing;

public class ItemDescribaliser<T> implements Describaliser<Item<T>>{

	private Describaliser<T> innerDescribaliser;
	public ItemDescribaliser(Describaliser<T> innerDescribaliser){
		this.innerDescribaliser = innerDescribaliser;

	}
	@Override
	public SelfDescribing describable(Item<T> thing) {
		return innerDescribaliser.describable(thing.get());
	}

}


text:
package sh.isaac.api.util;

import java.io.Serializable;
import java.util.Comparator;
import java.util.Objects;
import java.util.function.Function;

/**
 * Looking for more efficient implementation than AplphanumComparator which allocates memory,
 * and breaks strings into parts.
 * Solution found at: https://stackoverflow.com/questions/104599/sort-on-a-string-that-may-contain-a-number
 *
 * @author kec
 */
public class NaturalOrder implements Comparator<String> {

   /**
    * From stack overflow...
    * The implementation I propose here is simple and efficient.
    * It does not allocate any extra memory, directly or indirectly
    * by using regular expressions or methods such as substring(),
    * split(), toCharArray(), etc.
    *
    * This implementation first goes across both strings to search for the
    * first characters that are different, at maximal speed, without doing
    * any special processing during this. Specific number comparison is
    * triggered only when these characters are both digits. A side-effect
    * of this implementation is that a digit is considered as greater than
    * other letters, contrarily to default lexicographic order.
    * @param s1 first string
    * @param s2 second string
    * @return result of comparison
    */
   public static final int compareStrings(String s1, String s2) {
      // Skip all identical characters
      int  len1 = s1.length();
      int  len2 = s2.length();
      int  i;
      char c1, c2;

      for (i = 0, c1 = 0, c2 = 0; (i < len1) && (i < len2) && ((c1 = s1.charAt(i)) == (c2 = s2.charAt(i)) || Character.toLowerCase(s1.charAt(i)) == Character.toLowerCase(s2.charAt(i))); i++) {}

      if (c1 == '.' && c2 == ' ') {
         return -1;
      }
      if (c1 == ' ' && c2 == '.') {
         return 1;
      }

      // Check end of string
      if (Character.toLowerCase(c1) == Character.toLowerCase(c2)) {
         return (len1 - len2);
      }

      // Check digit in first string
      if (Character.isDigit(c1)) {
         // Check digit only in first string
         if (!Character.isDigit(c2)) {
            return (1);
         }

         // Scan all integer digits
         int x1, x2;

         for (x1 = i + 1; (x1 < len1) && Character.isDigit(s1.charAt(x1)); x1++) {}

         for (x2 = i + 1; (x2 < len2) && Character.isDigit(s2.charAt(x2)); x2++) {}

         // Longer integer wins, first digit otherwise
         return ((x2 == x1) ? c1 - c2
                            : x1 - x2);
      }

      // Check digit only in second string
      if (Character.isDigit(c2)) {
         return (-1);
      }

      // No digits
      return (Character.toLowerCase(c1) - Character.toLowerCase(c2));
   }
   @Override
   public int compare(String o1, String o2) {
      return compareStrings(o1, o2);
   }
}


text:
package io.katharsis.repository.annotations;

import java.io.Serializable;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 *

 * Method annotated with this annotation will be used to perform delete operation on a particular resource. The method
 * must be defined in a class annotated with {@link JsonApiResourceRepository}.
 *

 *

 * The requirements for the method parameters are as follows:
 *

 *

 *
An identifier of a resource

 *

 *

 * The method's return value should be void.
 *

 *
 * @see io.katharsis.repository.ResourceRepository#delete(Serializable)
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface JsonApiDelete {
}


text:
describe('Reducer', () => {
  const ReducerInjector = require('inject!../src/Reducer');
  const sortedObject = require('../src/sortedObject');

  let sorted, Constants, Reducer;

  beforeEach(() => {
    Constants = {};
    Constants.NAVIGATE_TO = 0;
    Constants.ADD_DEFAULT_PARAM = 1;
    Constants.REMOVE_PARAM = 2;
    Constants.RESTORE_LOCATION = 3;

    sorted = jasmine.createSpy('sortedObject').and.callFake(sortedObject);
  });

  const createReducer = () => {
    Reducer = ReducerInjector({
      './sortedObject': sorted,
      './Constants': Constants
    });
  };

  describe('Init', () => {
    it('should initialize with default query', () => {
      createReducer();
      const initState = Reducer(undefined, {});

      expect(initState.query).toEqual({});
    });

    it('should have no default params', () => {
      createReducer();
      const initState = Reducer(undefined, {});

      expect(initState.defaultParams).toEqual({});
    });
  });

  describe('Restore location', () => {
    let action, newState;

    beforeEach(() => {
      createReducer();
      action = {
        type: Constants.RESTORE_LOCATION,
        payload: {location: '/hello?world=123&name=barry'}

      };
      newState = Reducer(undefined, action);
    });

    it('should restore location', () => {
      expect(newState.query).toEqual({world: '123', name: 'barry'});
    });

    it('should sort query params when restoring location', () => {
      expect(sorted.calls.mostRecent().args).toEqual([{world: '123', name: 'barry'}]);
      expect(Object.keys(newState.query)).toEqual(['name', 'world']);
    });
  });

  describe('Default params', () => {
    let newState;

    beforeEach(() => {
      createReducer();
      let state;

      state = Reducer(state, {
        type: Constants.RESTORE_LOCATION,
        payload: {location: '/?x=1'}
      });
      state = Reducer(state, {
        type: Constants.ADD_DEFAULT_PARAM,
        payload: {namespace: 'y', value: 10}
      });
      state = Reducer(state, {
        type: Constants.ADD_DEFAULT_PARAM,
        payload: {namespace: 'z', value: 100}
      });
      newState = state;
    });

    it('should add default params', () => {
      expect(newState.defaultParams).toEqual({y: '10', z: '100'});
    });

    it('should merge current query with default params', () => {
      expect(newState.query).toEqual({x: '1', y: '10', z: '100'});
    });

    it('should not override existing query param with default one', () => {
      newState = Reducer(newState, {
        type: Constants.ADD_DEFAULT_PARAM,
        payload: {namespace: 'x', value: 123}
      });
      expect(newState.query).toEqual({x: '1', y: '10', z: '100'});
    });

    it('should sort query params when adding default one', () => {
      expect(sorted.calls.mostRecent().args).toEqual([{x: '1', y: '10', z: '100'}]);
      expect(Object.keys(newState.query)).toEqual(['x', 'y', 'z']);
    });
  });

  describe('Remove param', () => {
    let newState;

    beforeEach(() => {
      createReducer();
      let state;

      state = Reducer(state, {
        type: Constants.RESTORE_LOCATION,
        payload: {location: '/?x=1&y=10'}
      });
      state = Reducer(state, {
        type: Constants.ADD_DEFAULT_PARAM,
        payload: {namespace: 'z', value: 100}
      });
      newState = state;
    });

    it('should remove param from query', () => {
      expect(newState.query).toEqual({x: '1', y: '10', z: '100'});
      newState = Reducer(newState, {
        type: Constants.REMOVE_PARAM,
        payload: {namespace: 'x'}
      });
      expect(newState.query).toEqual({y: '10', z: '100'});
    });

    it('should remove param from default params', () => {
      expect(newState.defaultParams).toEqual({z: '100'});
      newState = Reducer(newState, {
        type: Constants.REMOVE_PARAM,
        payload: {namespace: 'z'}
      });
      expect(newState.defaultParams).toEqual({});
    });

    it('should sort query params upon removal', () => {
      newState = Reducer(newState, {
        type: Constants.REMOVE_PARAM,
        payload: {namespace: 'x'}
      });
      expect(sorted.calls.mostRecent().args).toEqual([{y: '10', z: '100'}]);
      expect(Object.keys(newState.query)).toEqual(['y', 'z']);
    });
  });

  describe('Navigate to', () => {
    let newState;

    beforeEach(() => {
      createReducer();
      newState = Reducer(newState, {
        type: Constants.ADD_DEFAULT_PARAM,
        payload: {namespace: 'y', value: 2}
      });
    });

    it('should merge params', () => {
      newState = Reducer(newState, {
        type: Constants.NAVIGATE_TO,
        payload: {query: {y: 10}}
      });
      expect(newState.query).toEqual({y: '10'});
    });

    it('should sort query params', () => {
      newState = Reducer(newState, {
        type: Constants.NAVIGATE_TO,
        payload: {query: {y: 10}}
      });
      expect(sorted.calls.mostRecent().args).toEqual([{y: '10'}]);
      expect(Object.keys(newState.query)).toEqual(['y']);
    });
  });
});


text:
.. index:: migration, 1.0, upgrading

Upgrade Guides
##############

.. index::
   pair: source; compatibility
   pair: binary; compatibility

Compatibility Policy
====================

Slick requires Scala 2.10 or 2.11. (For Scala 2.9 please use ScalaQuery_, the predecessor of Slick).

Slick version numbers consist of an epoch, a major and minor version, and possibly a qualifier
(for milestone, RC and SNAPSHOT versions).

For release versions (i.e. versions without a qualifier), backward binary compatibility is
guaranteed between releases with the same epoch and major version (e.g. you could use 2.1.2 as a
drop-in replacement for 2.1.0 but not for 2.0.0). :doc:`Slick Extensions <extensions>` requires at
least the same minor version of Slick (e.g. Slick Extensions 2.1.2 can be used with Slick 2.1.2 but
not with Slick 2.1.1). Binary compatibility is not preserved for `slick-codegen`, which is generally
used at compile-time.

We do not guarantee source compatibility but we try to preserve it within the same major release.
Upgrading to a new major release may require some changes to your sources. We generally deprecate
old features and keep them around for a full major release cycle (i.e. features which become
deprecated in 2.1.0 will not be removed before 2.2.0) but this is not possible for all kinds of
changes.

Release candidates have the same compatibility guarantees as the final versions to which they
lead. There are *no compatibility guarantees* whatsoever for milestones and snapshots.

Upgrade from 3.1 to 3.2
=======================

This section describes the changes that are needed when upgrading from Slick 3.1 to 3.2. If you are
currently using an older version of Slick, please see the older `Slick Manuals`_ for details on other
changes that may be required.


text:
package org.bulldog.core.util.easing;

public enum EasingOptions {
	EaseIn,
	EaseOut,
	EaseInOut;

	public float calculate(Easing easing, float t, float d) {
		if(this == EasingOptions.EaseIn) {
			return easing.easeIn(t, d);
		} else if(this == EasingOptions.EaseOut) {
			return easing.easeOut(t, d);
		}

		return easing.easeInOut(t, d);
	}
}


text:
package client // import "github.com/docker/docker/client"

import (
	"bytes"
	"context"
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"
	"testing"

	"github.com/docker/docker/api/types/swarm"
)

func TestSwarmUpdateError(t *testing.T) {
	client := &Client{
		client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")),
	}

	err := client.SwarmUpdate(context.Background(), swarm.Version{}, swarm.Spec{}, swarm.UpdateFlags{})
	if err == nil || err.Error() != "Error response from daemon: Server error" {
		t.Fatalf("expected a Server Error, got %v", err)
	}
}

func TestSwarmUpdate(t *testing.T) {
	expectedURL := "/swarm/update"

	client := &Client{
		client: newMockClient(func(req *http.Request) (*http.Response, error) {
			if !strings.HasPrefix(req.URL.Path, expectedURL) {
				return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL)
			}
			if req.Method != "POST" {
				return nil, fmt.Errorf("expected POST method, got %s", req.Method)
			}
			return &http.Response{
				StatusCode: http.StatusOK,
				Body:       ioutil.NopCloser(bytes.NewReader([]byte(""))),
			}, nil
		}),
	}

	err := client.SwarmUpdate(context.Background(), swarm.Version{}, swarm.Spec{}, swarm.UpdateFlags{})
	if err != nil {
		t.Fatal(err)
	}
}


text:
/*
    Main board definitions include
*/
#ifndef BOARD_H_
#define BOARD_H_

#if defined(lpcxpresso)
    #include "lpcxpresso.h"
#elif defined(breadboard)
    #include "breadboard.h"
#else
    #error Unknown board!
#endif

#endif


text:
module.exports = function(bufferSize, m) {
  return µ(1, m.ampSpectrum);
};


text:
<!--
  Copyright 2013 C. A. Fitzgerald

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
-->

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/trainer_activity"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="20dp"
    android:paddingLeft="10dp"
    android:paddingRight="10dp"
    android:paddingTop="20dp"
    tools:context=".TrainerActivity" >

    <View
        android:id="@+id/landing_area"
        android:layout_width="@dimen/landing_circle_size"
        android:layout_height="@dimen/landing_circle_size"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:background="@drawable/circle" />

    <com.github.riotopsys.hexgrid.HexGrid
        android:id="@+id/answer_grid"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_above="@+id/landing_area"
        android:layout_alignParentLeft="true"
        android:layout_below="@+id/replay"
        app:max_columns="7"
        app:max_rows="5"
        app:radius="@dimen/grid_radius"
        app:start_indented="true" >

    </com.github.riotopsys.hexgrid.HexGrid>

    <RelativeLayout
        android:id="@+id/replay"
        android:layout_width="@dimen/landing_circle_size"
        android:layout_height="@dimen/landing_circle_size"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:background="@drawable/filled_circle"
        android:clickable="true" >

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true"
            android:layout_centerVertical="true"
            android:src="@drawable/ic_repeat" />
    </RelativeLayout>

</RelativeLayout>


text: struct element *rmEvens(struct element *head);