Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(232)

Side by Side Diff: chrome/browser/autocomplete/search_provider.cc

Issue 456843003: Remove protected virtual methods from BaseSearchProvider (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2012 The Chromium Authors. All rights reserved. 1 // Copyright 2012 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 "chrome/browser/autocomplete/search_provider.h" 5 #include "chrome/browser/autocomplete/search_provider.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <cmath> 8 #include <cmath>
9 9
10 #include "base/base64.h" 10 #include "base/base64.h"
11 #include "base/callback.h" 11 #include "base/callback.h"
12 #include "base/command_line.h" 12 #include "base/command_line.h"
13 #include "base/i18n/break_iterator.h" 13 #include "base/i18n/break_iterator.h"
14 #include "base/i18n/case_conversion.h" 14 #include "base/i18n/case_conversion.h"
15 #include "base/json/json_string_value_serializer.h" 15 #include "base/json/json_string_value_serializer.h"
16 #include "base/message_loop/message_loop.h" 16 #include "base/message_loop/message_loop.h"
17 #include "base/metrics/histogram.h" 17 #include "base/metrics/histogram.h"
18 #include "base/metrics/user_metrics.h"
19 #include "base/prefs/pref_service.h" 18 #include "base/prefs/pref_service.h"
20 #include "base/rand_util.h" 19 #include "base/rand_util.h"
21 #include "base/strings/string_util.h" 20 #include "base/strings/string_util.h"
22 #include "base/strings/utf_string_conversions.h" 21 #include "base/strings/utf_string_conversions.h"
23 #include "chrome/browser/autocomplete/autocomplete_classifier.h" 22 #include "chrome/browser/autocomplete/autocomplete_classifier.h"
24 #include "chrome/browser/autocomplete/autocomplete_classifier_factory.h" 23 #include "chrome/browser/autocomplete/autocomplete_classifier_factory.h"
25 #include "chrome/browser/autocomplete/autocomplete_result.h" 24 #include "chrome/browser/autocomplete/autocomplete_result.h"
26 #include "chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.h" 25 #include "chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.h"
27 #include "chrome/browser/autocomplete/keyword_provider.h" 26 #include "chrome/browser/autocomplete/keyword_provider.h"
28 #include "chrome/browser/history/history_service.h" 27 #include "chrome/browser/history/history_service.h"
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
65 enum SuggestRequestsHistogramValue { 64 enum SuggestRequestsHistogramValue {
66 REQUEST_SENT = 1, 65 REQUEST_SENT = 1,
67 REQUEST_INVALIDATED, 66 REQUEST_INVALIDATED,
68 REPLY_RECEIVED, 67 REPLY_RECEIVED,
69 MAX_SUGGEST_REQUEST_HISTOGRAM_VALUE 68 MAX_SUGGEST_REQUEST_HISTOGRAM_VALUE
70 }; 69 };
71 70
72 // The verbatim score for an input which is not an URL. 71 // The verbatim score for an input which is not an URL.
73 const int kNonURLVerbatimRelevance = 1300; 72 const int kNonURLVerbatimRelevance = 1300;
74 73
74 // User metrics action strings.
75 const char kUserMetricsActionDeletionSuccess[] =
76 "Omnibox.ServerSuggestDelete.Success";
77 const char kUserMetricsActionDeletionFailure[] =
78 "Omnibox.ServerSuggestDelete.Failure";
79
75 // Increments the appropriate value in the histogram by one. 80 // Increments the appropriate value in the histogram by one.
76 void LogOmniboxSuggestRequest( 81 void LogOmniboxSuggestRequest(
77 SuggestRequestsHistogramValue request_value) { 82 SuggestRequestsHistogramValue request_value) {
78 UMA_HISTOGRAM_ENUMERATION("Omnibox.SuggestRequests", request_value, 83 UMA_HISTOGRAM_ENUMERATION("Omnibox.SuggestRequests", request_value,
79 MAX_SUGGEST_REQUEST_HISTOGRAM_VALUE); 84 MAX_SUGGEST_REQUEST_HISTOGRAM_VALUE);
80 } 85 }
81 86
82 bool HasMultipleWords(const base::string16& text) { 87 bool HasMultipleWords(const base::string16& text) {
83 base::i18n::BreakIterator i(text, base::i18n::BreakIterator::BREAK_WORD); 88 base::i18n::BreakIterator i(text, base::i18n::BreakIterator::BREAK_WORD);
84 bool found_word = false; 89 bool found_word = false;
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
125 130
126 131
127 // SearchProvider ------------------------------------------------------------- 132 // SearchProvider -------------------------------------------------------------
128 133
129 // static 134 // static
130 int SearchProvider::kMinimumTimeBetweenSuggestQueriesMs = 100; 135 int SearchProvider::kMinimumTimeBetweenSuggestQueriesMs = 100;
131 136
132 SearchProvider::SearchProvider(AutocompleteProviderListener* listener, 137 SearchProvider::SearchProvider(AutocompleteProviderListener* listener,
133 TemplateURLService* template_url_service, 138 TemplateURLService* template_url_service,
134 Profile* profile) 139 Profile* profile)
135 : BaseSearchProvider(template_url_service, profile, 140 : BaseSearchProvider(
136 AutocompleteProvider::TYPE_SEARCH), 141 template_url_service, profile,
142 base::UserMetricsAction(kUserMetricsActionDeletionSuccess),
143 base::UserMetricsAction(kUserMetricsActionDeletionFailure),
144 AutocompleteProvider::TYPE_SEARCH),
137 listener_(listener), 145 listener_(listener),
138 suggest_results_pending_(0), 146 suggest_results_pending_(0),
139 providers_(template_url_service) { 147 providers_(template_url_service) {
140 } 148 }
141 149
142 // static 150 // static
143 std::string SearchProvider::GetSuggestMetadata(const AutocompleteMatch& match) { 151 std::string SearchProvider::GetSuggestMetadata(const AutocompleteMatch& match) {
144 return match.GetAdditionalInfo(kSuggestMetadataKey); 152 return match.GetAdditionalInfo(kSuggestMetadataKey);
145 } 153 }
146 154
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after
243 } 251 }
244 252
245 input_ = input; 253 input_ = input;
246 254
247 DoHistoryQuery(minimal_changes); 255 DoHistoryQuery(minimal_changes);
248 DoAnswersQuery(input); 256 DoAnswersQuery(input);
249 StartOrStopSuggestQuery(minimal_changes); 257 StartOrStopSuggestQuery(minimal_changes);
250 UpdateMatches(); 258 UpdateMatches();
251 } 259 }
252 260
253 const TemplateURL* SearchProvider::GetTemplateURL(bool is_keyword) const { 261 void SearchProvider::Stop(bool clear_cached_results) {
254 return is_keyword ? providers_.GetKeywordProviderURL() 262 StopSuggest();
255 : providers_.GetDefaultProviderURL(); 263 done_ = true;
256 }
257 264
258 const AutocompleteInput SearchProvider::GetInput(bool is_keyword) const { 265 if (clear_cached_results)
259 return is_keyword ? keyword_input_ : input_; 266 ClearAllResults();
260 }
261
262 bool SearchProvider::ShouldAppendExtraParams(
263 const SearchSuggestionParser::SuggestResult& result) const {
264 return !result.from_keyword_provider() ||
265 providers_.default_provider().empty();
266 }
267
268 void SearchProvider::StopSuggest() {
269 // Increment the appropriate field in the histogram by the number of
270 // pending requests that were invalidated.
271 for (int i = 0; i < suggest_results_pending_; ++i)
272 LogOmniboxSuggestRequest(REQUEST_INVALIDATED);
273 suggest_results_pending_ = 0;
274 timer_.Stop();
275 // Stop any in-progress URL fetches.
276 keyword_fetcher_.reset();
277 default_fetcher_.reset();
278 }
279
280 void SearchProvider::ClearAllResults() {
281 keyword_results_.Clear();
282 default_results_.Clear();
283 }
284
285 void SearchProvider::RecordDeletionResult(bool success) {
286 if (success) {
287 base::RecordAction(
288 base::UserMetricsAction("Omnibox.ServerSuggestDelete.Success"));
289 } else {
290 base::RecordAction(
291 base::UserMetricsAction("Omnibox.ServerSuggestDelete.Failure"));
292 }
293 } 267 }
294 268
295 void SearchProvider::OnURLFetchComplete(const net::URLFetcher* source) { 269 void SearchProvider::OnURLFetchComplete(const net::URLFetcher* source) {
296 DCHECK(!done_); 270 DCHECK(!done_);
297 --suggest_results_pending_; 271 --suggest_results_pending_;
298 DCHECK_GE(suggest_results_pending_, 0); // Should never go negative. 272 DCHECK_GE(suggest_results_pending_, 0); // Should never go negative.
299 273
300 const bool is_keyword = source == keyword_fetcher_.get(); 274 const bool is_keyword = source == keyword_fetcher_.get();
301 275
302 // Ensure the request succeeded and that the provider used is still available. 276 // Ensure the request succeeded and that the provider used is still available.
303 // A verbatim match cannot be generated without this provider, causing errors. 277 // A verbatim match cannot be generated without this provider, causing errors.
304 const bool request_succeeded = 278 const bool request_succeeded =
305 source->GetStatus().is_success() && (source->GetResponseCode() == 200) && 279 source->GetStatus().is_success() && (source->GetResponseCode() == 200) &&
306 GetTemplateURL(is_keyword); 280 GetTemplateURL(is_keyword);
307 281
308 LogFetchComplete(request_succeeded, is_keyword); 282 LogFetchComplete(request_succeeded, is_keyword);
309 283
310 bool results_updated = false; 284 bool results_updated = false;
311 if (request_succeeded) { 285 if (request_succeeded) {
312 scoped_ptr<base::Value> data(SearchSuggestionParser::DeserializeJsonData( 286 scoped_ptr<base::Value> data(SearchSuggestionParser::DeserializeJsonData(
313 SearchSuggestionParser::ExtractJsonData(source))); 287 SearchSuggestionParser::ExtractJsonData(source)));
314 if (data) { 288 if (data) {
315 SearchSuggestionParser::Results* results = 289 SearchSuggestionParser::Results* results =
316 is_keyword ? &keyword_results_ : &default_results_; 290 is_keyword ? &keyword_results_ : &default_results_;
317 results_updated = ParseSuggestResults(*data, -1, is_keyword, results); 291 results_updated = ParseSuggestResults(
292 *data, GetInput(is_keyword), -1, is_keyword, results);
318 if (results_updated) 293 if (results_updated)
319 SortResults(is_keyword, results); 294 SortResults(is_keyword, results);
320 } 295 }
321 } 296 }
322 UpdateMatches(); 297 UpdateMatches();
323 if (done_ || results_updated) 298 if (done_ || results_updated)
324 listener_->OnProviderUpdate(results_updated); 299 listener_->OnProviderUpdate(results_updated);
325 } 300 }
326 301
302 const TemplateURL* SearchProvider::GetTemplateURL(bool is_keyword) const {
303 return is_keyword ? providers_.GetKeywordProviderURL()
Peter Kasting 2014/08/12 18:31:18 Nit: clang-format error, please break after ? and
hashimoto 2014/08/13 05:21:22 Done.
304 : providers_.GetDefaultProviderURL();
305 }
306
307 const AutocompleteInput& SearchProvider::GetInput(bool is_keyword) const {
308 return is_keyword ? keyword_input_ : input_;
309 }
310
311 bool SearchProvider::ShouldAppendExtraParams(
312 const SearchSuggestionParser::SuggestResult& result) const {
313 return !result.from_keyword_provider() ||
314 providers_.default_provider().empty();
315 }
316
317 void SearchProvider::StopSuggest() {
318 // Increment the appropriate field in the histogram by the number of
319 // pending requests that were invalidated.
320 for (int i = 0; i < suggest_results_pending_; ++i)
321 LogOmniboxSuggestRequest(REQUEST_INVALIDATED);
322 suggest_results_pending_ = 0;
323 timer_.Stop();
324 // Stop any in-progress URL fetches.
325 keyword_fetcher_.reset();
326 default_fetcher_.reset();
327 }
328
329 void SearchProvider::ClearAllResults() {
330 keyword_results_.Clear();
331 default_results_.Clear();
332 }
333
327 void SearchProvider::UpdateMatchContentsClass( 334 void SearchProvider::UpdateMatchContentsClass(
328 const base::string16& input_text, 335 const base::string16& input_text,
329 SearchSuggestionParser::Results* results) { 336 SearchSuggestionParser::Results* results) {
330 for (SearchSuggestionParser::SuggestResults::iterator sug_it = 337 for (SearchSuggestionParser::SuggestResults::iterator sug_it =
331 results->suggest_results.begin(); 338 results->suggest_results.begin();
332 sug_it != results->suggest_results.end(); ++sug_it) { 339 sug_it != results->suggest_results.end(); ++sug_it) {
333 sug_it->ClassifyMatchContents(false, input_text); 340 sug_it->ClassifyMatchContents(false, input_text);
334 } 341 }
335 const std::string languages( 342 const std::string languages(
336 profile_->GetPrefs()->GetString(prefs::kAcceptLanguages)); 343 profile_->GetPrefs()->GetString(prefs::kAcceptLanguages));
(...skipping 395 matching lines...) Expand 10 before | Expand all | Expand 10 after
732 TemplateURLRef::NO_SUGGESTION_CHOSEN; 739 TemplateURLRef::NO_SUGGESTION_CHOSEN;
733 if (verbatim_relevance > 0) { 740 if (verbatim_relevance > 0) {
734 const base::string16& trimmed_verbatim = 741 const base::string16& trimmed_verbatim =
735 base::CollapseWhitespace(input_.text(), false); 742 base::CollapseWhitespace(input_.text(), false);
736 SearchSuggestionParser::SuggestResult verbatim( 743 SearchSuggestionParser::SuggestResult verbatim(
737 trimmed_verbatim, AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, 744 trimmed_verbatim, AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
738 trimmed_verbatim, base::string16(), base::string16(), base::string16(), 745 trimmed_verbatim, base::string16(), base::string16(), base::string16(),
739 base::string16(), std::string(), std::string(), false, 746 base::string16(), std::string(), std::string(), false,
740 verbatim_relevance, relevance_from_server, false, 747 verbatim_relevance, relevance_from_server, false,
741 trimmed_verbatim); 748 trimmed_verbatim);
742 AddMatchToMap(verbatim, std::string(), did_not_accept_default_suggestion, 749 AddMatchToMap(GetInput(false), verbatim, GetTemplateURL(false),
743 false, &map); 750 std::string(), did_not_accept_default_suggestion,
751 ShouldAppendExtraParams(verbatim), false, &map);
744 } 752 }
745 if (!keyword_input_.text().empty()) { 753 if (!keyword_input_.text().empty()) {
746 const TemplateURL* keyword_url = providers_.GetKeywordProviderURL(); 754 const TemplateURL* keyword_url = providers_.GetKeywordProviderURL();
747 // We only create the verbatim search query match for a keyword 755 // We only create the verbatim search query match for a keyword
748 // if it's not an extension keyword. Extension keywords are handled 756 // if it's not an extension keyword. Extension keywords are handled
749 // in KeywordProvider::Start(). (Extensions are complicated...) 757 // in KeywordProvider::Start(). (Extensions are complicated...)
750 // Note: in this provider, SEARCH_OTHER_ENGINE must correspond 758 // Note: in this provider, SEARCH_OTHER_ENGINE must correspond
751 // to the keyword verbatim search query. Do not create other matches 759 // to the keyword verbatim search query. Do not create other matches
752 // of type SEARCH_OTHER_ENGINE. 760 // of type SEARCH_OTHER_ENGINE.
753 if (keyword_url && 761 if (keyword_url &&
754 (keyword_url->GetType() != TemplateURL::OMNIBOX_API_EXTENSION)) { 762 (keyword_url->GetType() != TemplateURL::OMNIBOX_API_EXTENSION)) {
755 bool keyword_relevance_from_server; 763 bool keyword_relevance_from_server;
756 const int keyword_verbatim_relevance = 764 const int keyword_verbatim_relevance =
757 GetKeywordVerbatimRelevance(&keyword_relevance_from_server); 765 GetKeywordVerbatimRelevance(&keyword_relevance_from_server);
758 if (keyword_verbatim_relevance > 0) { 766 if (keyword_verbatim_relevance > 0) {
759 const base::string16& trimmed_verbatim = 767 const base::string16& trimmed_verbatim =
760 base::CollapseWhitespace(keyword_input_.text(), false); 768 base::CollapseWhitespace(keyword_input_.text(), false);
761 SearchSuggestionParser::SuggestResult verbatim( 769 SearchSuggestionParser::SuggestResult verbatim(
762 trimmed_verbatim, AutocompleteMatchType::SEARCH_OTHER_ENGINE, 770 trimmed_verbatim, AutocompleteMatchType::SEARCH_OTHER_ENGINE,
763 trimmed_verbatim, base::string16(), base::string16(), 771 trimmed_verbatim, base::string16(), base::string16(),
764 base::string16(), base::string16(), std::string(), std::string(), 772 base::string16(), base::string16(), std::string(), std::string(),
765 true, keyword_verbatim_relevance, keyword_relevance_from_server, 773 true, keyword_verbatim_relevance, keyword_relevance_from_server,
766 false, trimmed_verbatim); 774 false, trimmed_verbatim);
767 AddMatchToMap(verbatim, std::string(), 775 AddMatchToMap(GetInput(true), verbatim, keyword_url,
768 did_not_accept_keyword_suggestion, false, &map); 776 std::string(), did_not_accept_keyword_suggestion,
777 ShouldAppendExtraParams(verbatim), false, &map);
769 } 778 }
770 } 779 }
771 } 780 }
772 AddHistoryResultsToMap(keyword_history_results_, true, 781 AddHistoryResultsToMap(keyword_history_results_, true,
773 did_not_accept_keyword_suggestion, &map); 782 did_not_accept_keyword_suggestion, &map);
774 AddHistoryResultsToMap(default_history_results_, false, 783 AddHistoryResultsToMap(default_history_results_, false,
775 did_not_accept_default_suggestion, &map); 784 did_not_accept_default_suggestion, &map);
776 785
777 AddSuggestResultsToMap(keyword_results_.suggest_results, 786 AddSuggestResultsToMap(keyword_results_.suggest_results,
778 keyword_results_.metadata, &map); 787 keyword_results_.metadata, &map);
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after
900 if ((scored_results.front().relevance() < 1200) || 909 if ((scored_results.front().relevance() < 1200) ||
901 !HasMultipleWords(scored_results.front().suggestion())) 910 !HasMultipleWords(scored_results.front().suggestion()))
902 scored_results.clear(); // Didn't detect the case above, score normally. 911 scored_results.clear(); // Didn't detect the case above, score normally.
903 } 912 }
904 if (scored_results.empty()) 913 if (scored_results.empty())
905 scored_results = ScoreHistoryResults(results, prevent_inline_autocomplete, 914 scored_results = ScoreHistoryResults(results, prevent_inline_autocomplete,
906 input_multiple_words, input_text, 915 input_multiple_words, input_text,
907 is_keyword); 916 is_keyword);
908 for (SearchSuggestionParser::SuggestResults::const_iterator i( 917 for (SearchSuggestionParser::SuggestResults::const_iterator i(
909 scored_results.begin()); i != scored_results.end(); ++i) { 918 scored_results.begin()); i != scored_results.end(); ++i) {
910 AddMatchToMap(*i, std::string(), did_not_accept_suggestion, true, map); 919 AddMatchToMap(GetInput(is_keyword), *i, GetTemplateURL(is_keyword),
920 std::string(), did_not_accept_suggestion,
921 ShouldAppendExtraParams(*i), true, map);
911 } 922 }
912 UMA_HISTOGRAM_TIMES("Omnibox.SearchProvider.AddHistoryResultsTime", 923 UMA_HISTOGRAM_TIMES("Omnibox.SearchProvider.AddHistoryResultsTime",
913 base::TimeTicks::Now() - start_time); 924 base::TimeTicks::Now() - start_time);
914 } 925 }
915 926
916 SearchSuggestionParser::SuggestResults SearchProvider::ScoreHistoryResults( 927 SearchSuggestionParser::SuggestResults SearchProvider::ScoreHistoryResults(
917 const HistoryResults& results, 928 const HistoryResults& results,
918 bool base_prevent_inline_autocomplete, 929 bool base_prevent_inline_autocomplete,
919 bool input_multiple_words, 930 bool input_multiple_words,
920 const base::string16& input_text, 931 const base::string16& input_text,
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after
1022 last_relevance = i->relevance(); 1033 last_relevance = i->relevance();
1023 } 1034 }
1024 1035
1025 return scored_results; 1036 return scored_results;
1026 } 1037 }
1027 1038
1028 void SearchProvider::AddSuggestResultsToMap( 1039 void SearchProvider::AddSuggestResultsToMap(
1029 const SearchSuggestionParser::SuggestResults& results, 1040 const SearchSuggestionParser::SuggestResults& results,
1030 const std::string& metadata, 1041 const std::string& metadata,
1031 MatchMap* map) { 1042 MatchMap* map) {
1032 for (size_t i = 0; i < results.size(); ++i) 1043 for (size_t i = 0; i < results.size(); ++i) {
1033 AddMatchToMap(results[i], metadata, i, false, map); 1044 AddMatchToMap(GetInput(results[i].from_keyword_provider()), results[i],
1045 GetTemplateURL(results[i].from_keyword_provider()), metadata,
1046 i, ShouldAppendExtraParams(results[i]), false, map);
1047 }
1034 } 1048 }
1035 1049
1036 int SearchProvider::GetVerbatimRelevance(bool* relevance_from_server) const { 1050 int SearchProvider::GetVerbatimRelevance(bool* relevance_from_server) const {
1037 // Use the suggested verbatim relevance score if it is non-negative (valid), 1051 // Use the suggested verbatim relevance score if it is non-negative (valid),
1038 // if inline autocomplete isn't prevented (always show verbatim on backspace), 1052 // if inline autocomplete isn't prevented (always show verbatim on backspace),
1039 // and if it won't suppress verbatim, leaving no default provider matches. 1053 // and if it won't suppress verbatim, leaving no default provider matches.
1040 // Otherwise, if the default provider returned no matches and was still able 1054 // Otherwise, if the default provider returned no matches and was still able
1041 // to suppress verbatim, the user would have no search/nav matches and may be 1055 // to suppress verbatim, the user would have no search/nav matches and may be
1042 // left unable to search using their default provider from the omnibox. 1056 // left unable to search using their default provider from the omnibox.
1043 // Check for results on each verbatim calculation, as results from older 1057 // Check for results on each verbatim calculation, as results from older
(...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after
1262 last_answer_seen_.query_type = match->answer_type; 1276 last_answer_seen_.query_type = match->answer_type;
1263 } 1277 }
1264 1278
1265 void SearchProvider::DoAnswersQuery(const AutocompleteInput& input) { 1279 void SearchProvider::DoAnswersQuery(const AutocompleteInput& input) {
1266 // If the query text starts with trimmed input, this is valid prefetch data. 1280 // If the query text starts with trimmed input, this is valid prefetch data.
1267 prefetch_data_ = StartsWith(last_answer_seen_.full_query_text, 1281 prefetch_data_ = StartsWith(last_answer_seen_.full_query_text,
1268 base::CollapseWhitespace(input.text(), false), 1282 base::CollapseWhitespace(input.text(), false),
1269 false) ? 1283 false) ?
1270 last_answer_seen_ : AnswersQueryData(); 1284 last_answer_seen_ : AnswersQueryData();
1271 } 1285 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698