Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "components/autofill/core/browser/webdata/autofill_table.h" | 5 #include "components/autofill/core/browser/webdata/autofill_table.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <cmath> | 8 #include <cmath> |
| 9 #include <limits> | 9 #include <limits> |
| 10 #include <map> | 10 #include <map> |
| (...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 160 index++; | 160 index++; |
| 161 } | 161 } |
| 162 credit_card->SetRawInfo(CREDIT_CARD_NUMBER, credit_card_number); | 162 credit_card->SetRawInfo(CREDIT_CARD_NUMBER, credit_card_number); |
| 163 // Intentionally skip column 5, which stores the modification date. | 163 // Intentionally skip column 5, which stores the modification date. |
| 164 index++; | 164 index++; |
| 165 credit_card->set_origin(s.ColumnString(index++)); | 165 credit_card->set_origin(s.ColumnString(index++)); |
| 166 | 166 |
| 167 return credit_card.Pass(); | 167 return credit_card.Pass(); |
| 168 } | 168 } |
| 169 | 169 |
| 170 // Obsolete version of AddAutofillProfileNamesToProfile, but still needed | |
| 171 // for MigrateToVersion37MergeAndCullOlderProfiles(). | |
| 172 bool AddAutofillProfileNamesToProfileForVersion37(sql::Connection* db, | |
| 173 AutofillProfile* profile) { | |
| 174 sql::Statement s(db->GetUniqueStatement( | |
| 175 "SELECT guid, first_name, middle_name, last_name " | |
| 176 "FROM autofill_profile_names " | |
| 177 "WHERE guid=?")); | |
| 178 s.BindString(0, profile->guid()); | |
| 179 | |
| 180 if (!s.is_valid()) | |
| 181 return false; | |
| 182 | |
| 183 std::vector<base::string16> first_names; | |
| 184 std::vector<base::string16> middle_names; | |
| 185 std::vector<base::string16> last_names; | |
| 186 while (s.Step()) { | |
| 187 DCHECK_EQ(profile->guid(), s.ColumnString(0)); | |
| 188 first_names.push_back(s.ColumnString16(1)); | |
| 189 middle_names.push_back(s.ColumnString16(2)); | |
| 190 last_names.push_back(s.ColumnString16(3)); | |
| 191 } | |
| 192 if (!s.Succeeded()) | |
| 193 return false; | |
| 194 | |
| 195 profile->SetRawMultiInfo(NAME_FIRST, first_names); | |
| 196 profile->SetRawMultiInfo(NAME_MIDDLE, middle_names); | |
| 197 profile->SetRawMultiInfo(NAME_LAST, last_names); | |
| 198 return true; | |
| 199 } | |
| 200 | |
| 170 bool AddAutofillProfileNamesToProfile(sql::Connection* db, | 201 bool AddAutofillProfileNamesToProfile(sql::Connection* db, |
| 171 AutofillProfile* profile) { | 202 AutofillProfile* profile) { |
| 172 sql::Statement s(db->GetUniqueStatement( | 203 sql::Statement s(db->GetUniqueStatement( |
| 173 "SELECT guid, first_name, middle_name, last_name " | 204 "SELECT guid, first_name, middle_name, last_name, full_name " |
| 174 "FROM autofill_profile_names " | 205 "FROM autofill_profile_names " |
| 175 "WHERE guid=?")); | 206 "WHERE guid=?")); |
| 176 s.BindString(0, profile->guid()); | 207 s.BindString(0, profile->guid()); |
| 177 | 208 |
| 178 if (!s.is_valid()) | 209 if (!s.is_valid()) |
| 179 return false; | 210 return false; |
| 180 | 211 |
| 181 std::vector<base::string16> first_names; | 212 std::vector<base::string16> first_names; |
| 182 std::vector<base::string16> middle_names; | 213 std::vector<base::string16> middle_names; |
| 183 std::vector<base::string16> last_names; | 214 std::vector<base::string16> last_names; |
| 215 std::vector<base::string16> full_names; | |
| 184 while (s.Step()) { | 216 while (s.Step()) { |
| 185 DCHECK_EQ(profile->guid(), s.ColumnString(0)); | 217 DCHECK_EQ(profile->guid(), s.ColumnString(0)); |
| 186 first_names.push_back(s.ColumnString16(1)); | 218 first_names.push_back(s.ColumnString16(1)); |
| 187 middle_names.push_back(s.ColumnString16(2)); | 219 middle_names.push_back(s.ColumnString16(2)); |
| 188 last_names.push_back(s.ColumnString16(3)); | 220 last_names.push_back(s.ColumnString16(3)); |
| 221 full_names.push_back(s.ColumnString16(4)); | |
| 189 } | 222 } |
| 190 if (!s.Succeeded()) | 223 if (!s.Succeeded()) |
| 191 return false; | 224 return false; |
| 192 | 225 |
| 193 profile->SetRawMultiInfo(NAME_FIRST, first_names); | 226 profile->SetRawMultiInfo(NAME_FIRST, first_names); |
| 194 profile->SetRawMultiInfo(NAME_MIDDLE, middle_names); | 227 profile->SetRawMultiInfo(NAME_MIDDLE, middle_names); |
| 195 profile->SetRawMultiInfo(NAME_LAST, last_names); | 228 profile->SetRawMultiInfo(NAME_LAST, last_names); |
| 229 profile->SetRawMultiInfo(NAME_FULL, full_names); | |
| 196 return true; | 230 return true; |
| 197 } | 231 } |
| 198 | 232 |
| 199 bool AddAutofillProfileEmailsToProfile(sql::Connection* db, | 233 bool AddAutofillProfileEmailsToProfile(sql::Connection* db, |
| 200 AutofillProfile* profile) { | 234 AutofillProfile* profile) { |
| 201 sql::Statement s(db->GetUniqueStatement( | 235 sql::Statement s(db->GetUniqueStatement( |
| 202 "SELECT guid, email " | 236 "SELECT guid, email " |
| 203 "FROM autofill_profile_emails " | 237 "FROM autofill_profile_emails " |
| 204 "WHERE guid=?")); | 238 "WHERE guid=?")); |
| 205 s.BindString(0, profile->guid()); | 239 s.BindString(0, profile->guid()); |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 235 DCHECK_EQ(profile->guid(), s.ColumnString(0)); | 269 DCHECK_EQ(profile->guid(), s.ColumnString(0)); |
| 236 numbers.push_back(s.ColumnString16(1)); | 270 numbers.push_back(s.ColumnString16(1)); |
| 237 } | 271 } |
| 238 if (!s.Succeeded()) | 272 if (!s.Succeeded()) |
| 239 return false; | 273 return false; |
| 240 | 274 |
| 241 profile->SetRawMultiInfo(PHONE_HOME_WHOLE_NUMBER, numbers); | 275 profile->SetRawMultiInfo(PHONE_HOME_WHOLE_NUMBER, numbers); |
| 242 return true; | 276 return true; |
| 243 } | 277 } |
| 244 | 278 |
| 279 // Obsolete version of AddAutofillProfileNames needed for | |
| 280 // MigrateToVersion33ProfilesBasedOnFirstName() and | |
| 281 // MigrateToVersion37MergeAndCullOlderProfiles(). | |
| 282 bool AddAutofillProfileNamesForVersion3x( | |
| 283 const AutofillProfile& profile, | |
| 284 sql::Connection* db) { | |
| 285 std::vector<base::string16> first_names; | |
| 286 profile.GetRawMultiInfo(NAME_FIRST, &first_names); | |
| 287 std::vector<base::string16> middle_names; | |
| 288 profile.GetRawMultiInfo(NAME_MIDDLE, &middle_names); | |
| 289 std::vector<base::string16> last_names; | |
| 290 profile.GetRawMultiInfo(NAME_LAST, &last_names); | |
| 291 DCHECK_EQ(first_names.size(), middle_names.size()); | |
| 292 DCHECK_EQ(first_names.size(), last_names.size()); | |
| 293 | |
| 294 for (size_t i = 0; i < first_names.size(); ++i) { | |
| 295 // Add the new name. | |
| 296 sql::Statement s; | |
| 297 s.Assign(db->GetUniqueStatement( | |
| 298 "INSERT INTO autofill_profile_names" | |
| 299 " (guid, first_name, middle_name, last_name) " | |
| 300 "VALUES (?,?,?,?)")); | |
| 301 s.BindString(0, profile.guid()); | |
| 302 s.BindString16(1, first_names[i]); | |
| 303 s.BindString16(2, middle_names[i]); | |
| 304 s.BindString16(3, last_names[i]); | |
| 305 | |
| 306 if (!s.Run()) | |
| 307 return false; | |
| 308 } | |
| 309 return true; | |
| 310 } | |
| 311 | |
| 245 bool AddAutofillProfileNames(const AutofillProfile& profile, | 312 bool AddAutofillProfileNames(const AutofillProfile& profile, |
| 246 sql::Connection* db) { | 313 sql::Connection* db) { |
| 247 std::vector<base::string16> first_names; | 314 std::vector<base::string16> first_names; |
| 248 profile.GetRawMultiInfo(NAME_FIRST, &first_names); | 315 profile.GetRawMultiInfo(NAME_FIRST, &first_names); |
| 249 std::vector<base::string16> middle_names; | 316 std::vector<base::string16> middle_names; |
| 250 profile.GetRawMultiInfo(NAME_MIDDLE, &middle_names); | 317 profile.GetRawMultiInfo(NAME_MIDDLE, &middle_names); |
| 251 std::vector<base::string16> last_names; | 318 std::vector<base::string16> last_names; |
| 252 profile.GetRawMultiInfo(NAME_LAST, &last_names); | 319 profile.GetRawMultiInfo(NAME_LAST, &last_names); |
| 320 std::vector<base::string16> full_names; | |
| 321 profile.GetRawMultiInfo(NAME_FULL, &full_names); | |
| 253 DCHECK_EQ(first_names.size(), middle_names.size()); | 322 DCHECK_EQ(first_names.size(), middle_names.size()); |
| 254 DCHECK_EQ(middle_names.size(), last_names.size()); | 323 DCHECK_EQ(first_names.size(), last_names.size()); |
| 324 DCHECK_EQ(first_names.size(), full_names.size()); | |
| 255 | 325 |
| 256 for (size_t i = 0; i < first_names.size(); ++i) { | 326 for (size_t i = 0; i < first_names.size(); ++i) { |
| 257 // Add the new name. | 327 // Add the new name. |
| 258 sql::Statement s(db->GetUniqueStatement( | 328 sql::Statement s; |
| 259 "INSERT INTO autofill_profile_names" | 329 s.Assign(db->GetUniqueStatement( |
| 260 " (guid, first_name, middle_name, last_name) " | 330 "INSERT INTO autofill_profile_names" |
| 261 "VALUES (?,?,?,?)")); | 331 " (guid, first_name, middle_name, last_name, full_name) " |
| 332 "VALUES (?,?,?,?,?)")); | |
|
Scott Hess - ex-Googler
2014/06/16 21:55:54
Get this all the way back to the default construct
Evan Stade
2014/06/16 23:06:05
Done.
| |
| 262 s.BindString(0, profile.guid()); | 333 s.BindString(0, profile.guid()); |
| 263 s.BindString16(1, first_names[i]); | 334 s.BindString16(1, first_names[i]); |
| 264 s.BindString16(2, middle_names[i]); | 335 s.BindString16(2, middle_names[i]); |
| 265 s.BindString16(3, last_names[i]); | 336 s.BindString16(3, last_names[i]); |
| 337 s.BindString16(4, full_names[i]); | |
| 266 | 338 |
| 267 if (!s.Run()) | 339 if (!s.Run()) |
| 268 return false; | 340 return false; |
| 269 } | 341 } |
| 270 return true; | 342 return true; |
| 271 } | 343 } |
| 272 | 344 |
| 273 bool AddAutofillProfileEmails(const AutofillProfile& profile, | 345 bool AddAutofillProfileEmails(const AutofillProfile& profile, |
| 274 sql::Connection* db) { | 346 sql::Connection* db) { |
| 275 std::vector<base::string16> emails; | 347 std::vector<base::string16> emails; |
| (...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 440 return MigrateToVersion51AddOriginColumn(); | 512 return MigrateToVersion51AddOriginColumn(); |
| 441 case 54: | 513 case 54: |
| 442 *update_compatible_version = true; | 514 *update_compatible_version = true; |
| 443 return MigrateToVersion54AddI18nFieldsAndRemoveDeprecatedFields(); | 515 return MigrateToVersion54AddI18nFieldsAndRemoveDeprecatedFields(); |
| 444 case 55: | 516 case 55: |
| 445 *update_compatible_version = true; | 517 *update_compatible_version = true; |
| 446 return MigrateToVersion55MergeAutofillDatesTable(); | 518 return MigrateToVersion55MergeAutofillDatesTable(); |
| 447 case 56: | 519 case 56: |
| 448 *update_compatible_version = true; | 520 *update_compatible_version = true; |
| 449 return MigrateToVersion56AddProfileLanguageCodeForFormatting(); | 521 return MigrateToVersion56AddProfileLanguageCodeForFormatting(); |
| 522 case 57: | |
| 523 *update_compatible_version = true; | |
| 524 return MigrateToVersion57AddFullNameField(); | |
| 450 } | 525 } |
| 451 return true; | 526 return true; |
| 452 } | 527 } |
| 453 | 528 |
| 454 bool AutofillTable::AddFormFieldValues( | 529 bool AutofillTable::AddFormFieldValues( |
| 455 const std::vector<FormFieldData>& elements, | 530 const std::vector<FormFieldData>& elements, |
| 456 std::vector<AutofillChange>* changes) { | 531 std::vector<AutofillChange>* changes) { |
| 457 return AddFormFieldValuesTime(elements, changes, Time::Now()); | 532 return AddFormFieldValuesTime(elements, changes, Time::Now()); |
| 458 } | 533 } |
| 459 | 534 |
| (...skipping 825 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1285 } | 1360 } |
| 1286 return true; | 1361 return true; |
| 1287 } | 1362 } |
| 1288 | 1363 |
| 1289 bool AutofillTable::InitProfileNamesTable() { | 1364 bool AutofillTable::InitProfileNamesTable() { |
| 1290 if (!db_->DoesTableExist("autofill_profile_names")) { | 1365 if (!db_->DoesTableExist("autofill_profile_names")) { |
| 1291 if (!db_->Execute("CREATE TABLE autofill_profile_names ( " | 1366 if (!db_->Execute("CREATE TABLE autofill_profile_names ( " |
| 1292 "guid VARCHAR, " | 1367 "guid VARCHAR, " |
| 1293 "first_name VARCHAR, " | 1368 "first_name VARCHAR, " |
| 1294 "middle_name VARCHAR, " | 1369 "middle_name VARCHAR, " |
| 1295 "last_name VARCHAR)")) { | 1370 "last_name VARCHAR, " |
| 1371 "full_name VARCHAR)")) { | |
| 1296 NOTREACHED(); | 1372 NOTREACHED(); |
| 1297 return false; | 1373 return false; |
| 1298 } | 1374 } |
| 1299 } | 1375 } |
| 1300 return true; | 1376 return true; |
| 1301 } | 1377 } |
| 1302 | 1378 |
| 1303 bool AutofillTable::InitProfileEmailsTable() { | 1379 bool AutofillTable::InitProfileEmailsTable() { |
| 1304 if (!db_->DoesTableExist("autofill_profile_emails")) { | 1380 if (!db_->DoesTableExist("autofill_profile_emails")) { |
| 1305 if (!db_->Execute("CREATE TABLE autofill_profile_emails ( " | 1381 if (!db_->Execute("CREATE TABLE autofill_profile_emails ( " |
| (...skipping 552 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1858 s_insert.BindString16(index++, profile.GetRawInfo(ADDRESS_HOME_CITY)); | 1934 s_insert.BindString16(index++, profile.GetRawInfo(ADDRESS_HOME_CITY)); |
| 1859 s_insert.BindString16(index++, profile.GetRawInfo(ADDRESS_HOME_STATE)); | 1935 s_insert.BindString16(index++, profile.GetRawInfo(ADDRESS_HOME_STATE)); |
| 1860 s_insert.BindString16(index++, profile.GetRawInfo(ADDRESS_HOME_ZIP)); | 1936 s_insert.BindString16(index++, profile.GetRawInfo(ADDRESS_HOME_ZIP)); |
| 1861 s_insert.BindString16(index++, profile.GetRawInfo(ADDRESS_HOME_COUNTRY)); | 1937 s_insert.BindString16(index++, profile.GetRawInfo(ADDRESS_HOME_COUNTRY)); |
| 1862 s_insert.BindInt64(index++, date_modified); | 1938 s_insert.BindInt64(index++, date_modified); |
| 1863 | 1939 |
| 1864 if (!s_insert.Run()) | 1940 if (!s_insert.Run()) |
| 1865 return false; | 1941 return false; |
| 1866 | 1942 |
| 1867 // Add the other bits: names, emails, and phone numbers. | 1943 // Add the other bits: names, emails, and phone numbers. |
| 1868 if (!AddAutofillProfilePieces(profile, db_)) | 1944 if (!AddAutofillProfileNamesForVersion3x(profile, db_) || |
| 1945 !AddAutofillProfileEmails(profile, db_) || | |
| 1946 !AddAutofillProfilePhones(profile, db_)) { | |
| 1869 return false; | 1947 return false; |
| 1948 } | |
| 1870 } // endwhile | 1949 } // endwhile |
| 1871 if (!s.Succeeded()) | 1950 if (!s.Succeeded()) |
| 1872 return false; | 1951 return false; |
| 1873 | 1952 |
| 1874 if (!db_->Execute("DROP TABLE autofill_profiles")) | 1953 if (!db_->Execute("DROP TABLE autofill_profiles")) |
| 1875 return false; | 1954 return false; |
| 1876 | 1955 |
| 1877 if (!db_->Execute( | 1956 if (!db_->Execute( |
| 1878 "ALTER TABLE autofill_profiles_temp RENAME TO autofill_profiles")) { | 1957 "ALTER TABLE autofill_profiles_temp RENAME TO autofill_profiles")) { |
| 1879 return false; | 1958 return false; |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1998 profile->SetRawInfo(ADDRESS_HOME_ZIP, s.ColumnString16(index++)); | 2077 profile->SetRawInfo(ADDRESS_HOME_ZIP, s.ColumnString16(index++)); |
| 1999 // Intentionally skip column 7, which stores the localized country name. | 2078 // Intentionally skip column 7, which stores the localized country name. |
| 2000 index++; | 2079 index++; |
| 2001 profile->SetRawInfo(ADDRESS_HOME_COUNTRY, s.ColumnString16(index++)); | 2080 profile->SetRawInfo(ADDRESS_HOME_COUNTRY, s.ColumnString16(index++)); |
| 2002 // Intentionally skip column 9, which stores the profile's modification | 2081 // Intentionally skip column 9, which stores the profile's modification |
| 2003 // date. | 2082 // date. |
| 2004 index++; | 2083 index++; |
| 2005 profile->set_origin(s.ColumnString(index++)); | 2084 profile->set_origin(s.ColumnString(index++)); |
| 2006 | 2085 |
| 2007 // Get associated name info. | 2086 // Get associated name info. |
| 2008 AddAutofillProfileNamesToProfile(db_, profile.get()); | 2087 AddAutofillProfileNamesToProfileForVersion37(db_, profile.get()); |
| 2009 | 2088 |
| 2010 // Get associated email info. | 2089 // Get associated email info. |
| 2011 AddAutofillProfileEmailsToProfile(db_, profile.get()); | 2090 AddAutofillProfileEmailsToProfile(db_, profile.get()); |
| 2012 | 2091 |
| 2013 // Get associated phone info. | 2092 // Get associated phone info. |
| 2014 AddAutofillProfilePhonesToProfile(db_, profile.get()); | 2093 AddAutofillProfilePhonesToProfile(db_, profile.get()); |
| 2015 | 2094 |
| 2016 if (PersonalDataManager::IsValidLearnableProfile(*profile, app_locale_)) { | 2095 if (PersonalDataManager::IsValidLearnableProfile(*profile, app_locale_)) { |
| 2017 std::vector<AutofillProfile> merged_profiles; | 2096 std::vector<AutofillProfile> merged_profiles; |
| 2018 std::string merged_guid = PersonalDataManager::MergeProfile( | 2097 std::string merged_guid = PersonalDataManager::MergeProfile( |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2066 s.BindString16(index++, GetInfo(*iter, ADDRESS_HOME_CITY)); | 2145 s.BindString16(index++, GetInfo(*iter, ADDRESS_HOME_CITY)); |
| 2067 s.BindString16(index++, GetInfo(*iter, ADDRESS_HOME_STATE)); | 2146 s.BindString16(index++, GetInfo(*iter, ADDRESS_HOME_STATE)); |
| 2068 s.BindString16(index++, GetInfo(*iter, ADDRESS_HOME_ZIP)); | 2147 s.BindString16(index++, GetInfo(*iter, ADDRESS_HOME_ZIP)); |
| 2069 s.BindString16(index++, base::string16()); // This column is deprecated. | 2148 s.BindString16(index++, base::string16()); // This column is deprecated. |
| 2070 s.BindString16(index++, GetInfo(*iter, ADDRESS_HOME_COUNTRY)); | 2149 s.BindString16(index++, GetInfo(*iter, ADDRESS_HOME_COUNTRY)); |
| 2071 s.BindInt64(index++, date_item->second); | 2150 s.BindInt64(index++, date_item->second); |
| 2072 | 2151 |
| 2073 if (!s.Run()) | 2152 if (!s.Run()) |
| 2074 return false; | 2153 return false; |
| 2075 | 2154 |
| 2076 if (!AddAutofillProfilePieces(*iter, db_)) | 2155 if (!AddAutofillProfileNamesForVersion3x(*iter, db_) || |
| 2156 !AddAutofillProfileEmails(*iter, db_) || | |
| 2157 !AddAutofillProfilePhones(*iter, db_)) { | |
| 2077 return false; | 2158 return false; |
| 2159 } | |
| 2078 } | 2160 } |
| 2079 | 2161 |
| 2080 return true; | 2162 return true; |
| 2081 } | 2163 } |
| 2082 | 2164 |
| 2083 bool AutofillTable::MigrateToVersion51AddOriginColumn() { | 2165 bool AutofillTable::MigrateToVersion51AddOriginColumn() { |
| 2084 sql::Transaction transaction(db_); | 2166 sql::Transaction transaction(db_); |
| 2085 if (!transaction.Begin()) | 2167 if (!transaction.Begin()) |
| 2086 return false; | 2168 return false; |
| 2087 | 2169 |
| (...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2265 | 2347 |
| 2266 | 2348 |
| 2267 return transaction.Commit(); | 2349 return transaction.Commit(); |
| 2268 } | 2350 } |
| 2269 | 2351 |
| 2270 bool AutofillTable::MigrateToVersion56AddProfileLanguageCodeForFormatting() { | 2352 bool AutofillTable::MigrateToVersion56AddProfileLanguageCodeForFormatting() { |
| 2271 return db_->Execute("ALTER TABLE autofill_profiles " | 2353 return db_->Execute("ALTER TABLE autofill_profiles " |
| 2272 "ADD COLUMN language_code VARCHAR"); | 2354 "ADD COLUMN language_code VARCHAR"); |
| 2273 } | 2355 } |
| 2274 | 2356 |
| 2357 bool AutofillTable::MigrateToVersion57AddFullNameField() { | |
| 2358 return db_->Execute("ALTER TABLE autofill_profile_names " | |
| 2359 "ADD COLUMN full_name VARCHAR"); | |
| 2360 } | |
| 2361 | |
| 2275 } // namespace autofill | 2362 } // namespace autofill |
| OLD | NEW |