OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 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/ui/webui/sync_setup_handler.h" | 5 #include "chrome/browser/ui/webui/sync_setup_handler.h" |
6 | 6 |
7 #include "base/basictypes.h" | 7 #include "base/basictypes.h" |
8 #include "base/bind.h" | 8 #include "base/bind.h" |
9 #include "base/bind_helpers.h" | 9 #include "base/bind_helpers.h" |
10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
(...skipping 10 matching lines...) Expand all Loading... | |
21 #include "chrome/browser/profiles/profile_info_cache.h" | 21 #include "chrome/browser/profiles/profile_info_cache.h" |
22 #include "chrome/browser/profiles/profile_manager.h" | 22 #include "chrome/browser/profiles/profile_manager.h" |
23 #include "chrome/browser/profiles/profile_metrics.h" | 23 #include "chrome/browser/profiles/profile_metrics.h" |
24 #include "chrome/browser/prefs/pref_service.h" | 24 #include "chrome/browser/prefs/pref_service.h" |
25 #include "chrome/browser/signin/signin_manager.h" | 25 #include "chrome/browser/signin/signin_manager.h" |
26 #include "chrome/browser/signin/signin_manager_factory.h" | 26 #include "chrome/browser/signin/signin_manager_factory.h" |
27 #include "chrome/browser/sync/profile_sync_service.h" | 27 #include "chrome/browser/sync/profile_sync_service.h" |
28 #include "chrome/browser/sync/profile_sync_service_factory.h" | 28 #include "chrome/browser/sync/profile_sync_service_factory.h" |
29 #include "chrome/browser/ui/browser_finder.h" | 29 #include "chrome/browser/ui/browser_finder.h" |
30 #include "chrome/browser/ui/browser_navigator.h" | 30 #include "chrome/browser/ui/browser_navigator.h" |
31 #include "chrome/browser/ui/tabs/tab_strip_model.h" | |
31 #include "chrome/browser/ui/webui/signin/login_ui_service.h" | 32 #include "chrome/browser/ui/webui/signin/login_ui_service.h" |
32 #include "chrome/browser/ui/webui/signin/login_ui_service_factory.h" | 33 #include "chrome/browser/ui/webui/signin/login_ui_service_factory.h" |
33 #include "chrome/browser/ui/webui/sync_promo/sync_promo_ui.h" | 34 #include "chrome/browser/ui/webui/sync_promo/sync_promo_ui.h" |
34 #include "chrome/common/chrome_switches.h" | 35 #include "chrome/common/chrome_switches.h" |
35 #include "chrome/common/pref_names.h" | 36 #include "chrome/common/pref_names.h" |
36 #include "chrome/common/url_constants.h" | 37 #include "chrome/common/url_constants.h" |
37 #include "content/public/browser/render_view_host.h" | 38 #include "content/public/browser/render_view_host.h" |
38 #include "content/public/browser/web_contents.h" | 39 #include "content/public/browser/web_contents.h" |
39 #include "content/public/browser/web_contents_delegate.h" | 40 #include "content/public/browser/web_contents_delegate.h" |
40 #include "google_apis/gaia/gaia_constants.h" | 41 #include "google_apis/gaia/gaia_constants.h" |
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
184 bool IsKeystoreEncryptionEnabled() { | 185 bool IsKeystoreEncryptionEnabled() { |
185 return CommandLine::ForCurrentProcess()->HasSwitch( | 186 return CommandLine::ForCurrentProcess()->HasSwitch( |
186 switches::kSyncKeystoreEncryption); | 187 switches::kSyncKeystoreEncryption); |
187 } | 188 } |
188 | 189 |
189 bool UseWebBasedSigninFlow() { | 190 bool UseWebBasedSigninFlow() { |
190 return CommandLine::ForCurrentProcess()->HasSwitch( | 191 return CommandLine::ForCurrentProcess()->HasSwitch( |
191 switches::kUseWebBasedSigninFlow); | 192 switches::kUseWebBasedSigninFlow); |
192 } | 193 } |
193 | 194 |
195 void BringTabToFront(WebContents* web_contents) { | |
196 Browser* browser = browser::FindBrowserWithWebContents(web_contents); | |
Andrew T Wilson (Slow)
2012/11/30 16:40:12
We have FocusUI() to do the same thing - make this
Roger Tawa OOO till Jul 10th
2012/12/01 16:09:55
Done.
| |
197 if (browser) { | |
198 TabStripModel* tab_strip_model = browser->tab_strip_model(); | |
199 if (tab_strip_model) { | |
200 int index = tab_strip_model->GetIndexOfWebContents(web_contents); | |
201 if (index != TabStripModel::kNoTab) | |
202 tab_strip_model->ActivateTabAt(index, false); | |
203 } | |
204 } | |
205 } | |
206 | |
194 } // namespace | 207 } // namespace |
195 | 208 |
209 SyncSetupHandler* SyncSetupHandler::active_sync_setup_handler_ = NULL; | |
210 | |
196 SyncSetupHandler::SyncSetupHandler(ProfileManager* profile_manager) | 211 SyncSetupHandler::SyncSetupHandler(ProfileManager* profile_manager) |
197 : configuring_sync_(false), | 212 : configuring_sync_(false), |
198 profile_manager_(profile_manager), | 213 profile_manager_(profile_manager), |
199 last_signin_error_(GoogleServiceAuthError::NONE), | 214 last_signin_error_(GoogleServiceAuthError::NONE), |
200 retry_on_signin_failure_(true) { | 215 retry_on_signin_failure_(true), |
216 active_gaia_signin_tab_(NULL) { | |
201 } | 217 } |
202 | 218 |
203 SyncSetupHandler::~SyncSetupHandler() { | 219 SyncSetupHandler::~SyncSetupHandler() { |
204 // Just exit if running unit tests (no actual WebUI is attached). | 220 // Just exit if running unit tests (no actual WebUI is attached). |
205 if (!web_ui()) | 221 if (!web_ui()) |
206 return; | 222 return; |
207 | 223 |
208 // This case is hit when the user performs a back navigation. | 224 // This case is hit when the user performs a back navigation. |
209 CloseSyncSetup(); | 225 CloseSyncSetup(); |
210 } | 226 } |
(...skipping 271 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
482 "fullEncryptionBody", | 498 "fullEncryptionBody", |
483 GetStringUTF16(IDS_SYNC_FULL_ENCRYPTION_DATA)); | 499 GetStringUTF16(IDS_SYNC_FULL_ENCRYPTION_DATA)); |
484 } | 500 } |
485 } else { | 501 } else { |
486 args.SetBoolean("usePassphrase", service->IsUsingSecondaryPassphrase()); | 502 args.SetBoolean("usePassphrase", service->IsUsingSecondaryPassphrase()); |
487 } | 503 } |
488 | 504 |
489 StringValue page("configure"); | 505 StringValue page("configure"); |
490 web_ui()->CallJavascriptFunction( | 506 web_ui()->CallJavascriptFunction( |
491 "SyncSetupOverlay.showSyncSetupPage", page, args); | 507 "SyncSetupOverlay.showSyncSetupPage", page, args); |
508 | |
509 if (UseWebBasedSigninFlow()) { | |
510 // Make sure the tab used for the Gaia sign in does not cover this tab. | |
511 BringTabToFront(web_ui()->GetWebContents()); | |
512 } | |
492 } | 513 } |
493 | 514 |
494 void SyncSetupHandler::ConfigureSyncDone() { | 515 void SyncSetupHandler::ConfigureSyncDone() { |
495 StringValue page("done"); | 516 StringValue page("done"); |
496 web_ui()->CallJavascriptFunction( | 517 web_ui()->CallJavascriptFunction( |
497 "SyncSetupOverlay.showSyncSetupPage", page); | 518 "SyncSetupOverlay.showSyncSetupPage", page); |
498 | 519 |
499 // Suppress the sync promo once the user signs into sync. This way the user | 520 // Suppress the sync promo once the user signs into sync. This way the user |
500 // doesn't see the sync promo even if they sign out of sync later on. | 521 // doesn't see the sync promo even if they sign out of sync later on. |
501 SyncPromoUI::SetUserSkippedSyncPromo(GetProfile()); | 522 SyncPromoUI::SetUserSkippedSyncPromo(GetProfile()); |
502 | 523 |
503 ProfileSyncService* service = GetSyncService(); | 524 ProfileSyncService* service = GetSyncService(); |
504 if (!service->HasSyncSetupCompleted()) { | 525 if (!service->HasSyncSetupCompleted()) { |
505 // This is the first time configuring sync, so log it. | 526 // This is the first time configuring sync, so log it. |
506 FilePath profile_file_path = GetProfile()->GetPath(); | 527 FilePath profile_file_path = GetProfile()->GetPath(); |
507 ProfileMetrics::LogProfileSyncSignIn(profile_file_path); | 528 ProfileMetrics::LogProfileSyncSignIn(profile_file_path); |
508 | 529 |
509 // We're done configuring, so notify ProfileSyncService that it is OK to | 530 // We're done configuring, so notify ProfileSyncService that it is OK to |
510 // start syncing. | 531 // start syncing. |
511 service->SetSyncSetupCompleted(); | 532 service->SetSyncSetupCompleted(); |
512 } | 533 } |
513 } | 534 } |
514 | 535 |
515 bool SyncSetupHandler::IsActiveLogin() const { | 536 bool SyncSetupHandler::IsActiveLogin() const { |
516 // LoginUIService can be NULL if page is brought up in incognito mode | 537 if (UseWebBasedSigninFlow()) { |
517 // (i.e. if the user is running in guest mode in cros and brings up settings). | 538 return active_sync_setup_handler_ == this; |
Andrew T Wilson (Slow)
2012/11/30 16:40:12
I'm not sure I understand why we need different lo
Roger Tawa OOO till Jul 10th
2012/12/01 16:09:55
Done.
| |
518 LoginUIService* service = GetLoginUIService(); | 539 } else { |
519 return service && (service->current_login_ui() == this); | 540 // LoginUIService can be NULL if page is brought up in incognito mode |
541 // (i.e. if the user is running in guest mode in cros and brings up | |
542 // settings). | |
543 LoginUIService* service = GetLoginUIService(); | |
544 return service && (service->current_login_ui() == this); | |
545 } | |
520 } | 546 } |
521 | 547 |
522 void SyncSetupHandler::RegisterMessages() { | 548 void SyncSetupHandler::RegisterMessages() { |
523 web_ui()->RegisterMessageCallback( | 549 web_ui()->RegisterMessageCallback( |
524 "SyncSetupDidClosePage", | 550 "SyncSetupDidClosePage", |
525 base::Bind(&SyncSetupHandler::OnDidClosePage, | 551 base::Bind(&SyncSetupHandler::OnDidClosePage, |
526 base::Unretained(this))); | 552 base::Unretained(this))); |
527 web_ui()->RegisterMessageCallback( | 553 web_ui()->RegisterMessageCallback( |
528 "SyncSetupSubmitAuth", | 554 "SyncSetupSubmitAuth", |
529 base::Bind(&SyncSetupHandler::HandleSubmitAuth, | 555 base::Bind(&SyncSetupHandler::HandleSubmitAuth, |
(...skipping 29 matching lines...) Expand all Loading... | |
559 base::Bind(&SyncSetupHandler::HandleStopSyncing, | 585 base::Bind(&SyncSetupHandler::HandleStopSyncing, |
560 base::Unretained(this))); | 586 base::Unretained(this))); |
561 } | 587 } |
562 | 588 |
563 SigninManager* SyncSetupHandler::GetSignin() const { | 589 SigninManager* SyncSetupHandler::GetSignin() const { |
564 return SigninManagerFactory::GetForProfile(GetProfile()); | 590 return SigninManagerFactory::GetForProfile(GetProfile()); |
565 } | 591 } |
566 | 592 |
567 void SyncSetupHandler::DisplayGaiaLogin(bool fatal_error) { | 593 void SyncSetupHandler::DisplayGaiaLogin(bool fatal_error) { |
568 if (UseWebBasedSigninFlow()) { | 594 if (UseWebBasedSigninFlow()) { |
595 DCHECK_EQ(active_sync_setup_handler_, this); | |
596 DCHECK(!active_gaia_signin_tab_); | |
597 | |
569 GURL url(SyncPromoUI::GetSyncPromoURL(GURL(), | 598 GURL url(SyncPromoUI::GetSyncPromoURL(GURL(), |
570 SyncPromoUI::SOURCE_SETTINGS, false)); | 599 SyncPromoUI::SOURCE_SETTINGS, false)); |
571 Browser* browser = browser::FindBrowserWithWebContents( | 600 Browser* browser = browser::FindBrowserWithWebContents( |
572 web_ui()->GetWebContents()); | 601 web_ui()->GetWebContents()); |
573 browser->OpenURL( | 602 active_gaia_signin_tab_ = browser->OpenURL( |
574 content::OpenURLParams(url, content::Referrer(), SINGLETON_TAB, | 603 content::OpenURLParams(url, content::Referrer(), SINGLETON_TAB, |
575 content::PAGE_TRANSITION_AUTO_BOOKMARK, false)); | 604 content::PAGE_TRANSITION_AUTO_BOOKMARK, |
605 false)); | |
606 content::WebContentsObserver::Observe(active_gaia_signin_tab_); | |
607 signin_tracker_.reset( | |
608 new SigninTracker(GetProfile(), this, | |
609 SigninTracker::WAITING_FOR_GAIA_VALIDATION)); | |
576 } else { | 610 } else { |
577 retry_on_signin_failure_ = true; | 611 retry_on_signin_failure_ = true; |
578 DisplayGaiaLoginWithErrorMessage(string16(), fatal_error); | 612 DisplayGaiaLoginWithErrorMessage(string16(), fatal_error); |
579 } | 613 } |
580 } | 614 } |
581 | 615 |
582 void SyncSetupHandler::DisplayGaiaLoginWithErrorMessage( | 616 void SyncSetupHandler::DisplayGaiaLoginWithErrorMessage( |
583 const string16& error_message, bool fatal_error) { | 617 const string16& error_message, bool fatal_error) { |
584 // We are no longer configuring sync if the login screen is visible. | 618 // We are no longer configuring sync if the login screen is visible. |
585 // If the user exits the signin wizard after this without configuring sync, | 619 // If the user exits the signin wizard after this without configuring sync, |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
655 return false; | 689 return false; |
656 } | 690 } |
657 | 691 |
658 // If the wizard is already visible, just focus that one. | 692 // If the wizard is already visible, just focus that one. |
659 if (FocusExistingWizardIfPresent()) { | 693 if (FocusExistingWizardIfPresent()) { |
660 if (!IsActiveLogin()) | 694 if (!IsActiveLogin()) |
661 CloseOverlay(); | 695 CloseOverlay(); |
662 return false; | 696 return false; |
663 } | 697 } |
664 | 698 |
665 if (!UseWebBasedSigninFlow()) { | 699 if (UseWebBasedSigninFlow()) { |
700 DCHECK(!active_sync_setup_handler_); | |
701 active_sync_setup_handler_ = this; | |
702 } else { | |
666 // Notify services that login UI is now active. | 703 // Notify services that login UI is now active. |
667 GetLoginUIService()->SetLoginUI(this); | 704 GetLoginUIService()->SetLoginUI(this); |
668 service->SetSetupInProgress(true); | 705 service->SetSetupInProgress(true); |
669 } | 706 } |
670 | 707 |
671 return true; | 708 return true; |
672 } | 709 } |
673 | 710 |
674 void SyncSetupHandler::DisplaySpinner() { | 711 void SyncSetupHandler::DisplaySpinner() { |
675 configuring_sync_ = true; | 712 configuring_sync_ = true; |
(...skipping 330 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1006 ProfileSyncService::SyncEvent( | 1043 ProfileSyncService::SyncEvent( |
1007 ProfileSyncService::CANCEL_DURING_SIGNON); | 1044 ProfileSyncService::CANCEL_DURING_SIGNON); |
1008 } else if (configuring_sync_) { | 1045 } else if (configuring_sync_) { |
1009 ProfileSyncService::SyncEvent( | 1046 ProfileSyncService::SyncEvent( |
1010 ProfileSyncService::CANCEL_DURING_CONFIGURE); | 1047 ProfileSyncService::CANCEL_DURING_CONFIGURE); |
1011 } else { | 1048 } else { |
1012 ProfileSyncService::SyncEvent( | 1049 ProfileSyncService::SyncEvent( |
1013 ProfileSyncService::CANCEL_FROM_SIGNON_WITHOUT_AUTH); | 1050 ProfileSyncService::CANCEL_FROM_SIGNON_WITHOUT_AUTH); |
1014 } | 1051 } |
1015 } | 1052 } |
1053 | |
1016 // Let the various services know that we're no longer active. | 1054 // Let the various services know that we're no longer active. |
1017 GetLoginUIService()->LoginUIClosed(this); | 1055 if (UseWebBasedSigninFlow()) { |
1056 CloseGaiaSigninPage(); | |
Andrew T Wilson (Slow)
2012/11/30 16:40:12
Should we not also call LoginUIClosed() here?
Roger Tawa OOO till Jul 10th
2012/12/01 16:09:55
Done.
| |
1057 } else { | |
1058 GetLoginUIService()->LoginUIClosed(this); | |
1059 } | |
1018 } | 1060 } |
1019 | 1061 |
1020 if (sync_service) { | 1062 if (sync_service) { |
1021 sync_service->SetSetupInProgress(false); | 1063 sync_service->SetSetupInProgress(false); |
1022 | 1064 |
1023 // Make sure user isn't left half-logged-in (signed in, but without sync | 1065 // Make sure user isn't left half-logged-in (signed in, but without sync |
1024 // started up). If the user hasn't finished setting up sync, then sign out | 1066 // started up). If the user hasn't finished setting up sync, then sign out |
1025 // and shut down sync. | 1067 // and shut down sync. |
1026 if (!sync_service->HasSyncSetupCompleted()) { | 1068 if (!sync_service->HasSyncSetupCompleted()) { |
1027 DVLOG(1) << "Signin aborted by user action"; | 1069 DVLOG(1) << "Signin aborted by user action"; |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1091 DCHECK(IsActiveLogin()); | 1133 DCHECK(IsActiveLogin()); |
1092 WebContents* web_contents = web_ui()->GetWebContents(); | 1134 WebContents* web_contents = web_ui()->GetWebContents(); |
1093 web_contents->GetDelegate()->ActivateContents(web_contents); | 1135 web_contents->GetDelegate()->ActivateContents(web_contents); |
1094 } | 1136 } |
1095 | 1137 |
1096 void SyncSetupHandler::CloseUI() { | 1138 void SyncSetupHandler::CloseUI() { |
1097 DCHECK(IsActiveLogin()); | 1139 DCHECK(IsActiveLogin()); |
1098 CloseOverlay(); | 1140 CloseOverlay(); |
1099 } | 1141 } |
1100 | 1142 |
1143 void SyncSetupHandler::WebContentsDestroyed( | |
1144 content::WebContents* web_contents) { | |
1145 DCHECK_EQ(active_sync_setup_handler_, this); | |
1146 DCHECK(active_gaia_signin_tab_); | |
1147 | |
1148 content::WebContentsObserver::Observe(NULL); | |
1149 active_sync_setup_handler_ = NULL; | |
1150 active_gaia_signin_tab_ = NULL; | |
Andrew T Wilson (Slow)
2012/11/30 16:40:12
Should we call CloseSyncSetup here? Seems like we
Roger Tawa OOO till Jul 10th
2012/12/01 16:09:55
Done.
| |
1151 } | |
1152 | |
1101 // Private member functions. | 1153 // Private member functions. |
1102 | 1154 |
1103 bool SyncSetupHandler::FocusExistingWizardIfPresent() { | 1155 bool SyncSetupHandler::FocusExistingWizardIfPresent() { |
1104 LoginUIService* service = GetLoginUIService(); | 1156 if (UseWebBasedSigninFlow()) { |
1105 if (!service->current_login_ui()) | 1157 if (active_sync_setup_handler_ == NULL) |
1106 return false; | 1158 return false; |
1107 service->current_login_ui()->FocusUI(); | 1159 |
1160 // |configuring_sync_| true means we are focusing to bring the configure | |
1161 // popup window to the top, not the Gaia sign in page. Therefore don't | |
1162 // bring Gaia to the front. | |
1163 if (!configuring_sync_) | |
1164 BringTabToFront(active_sync_setup_handler_->active_gaia_signin_tab_); | |
1165 } else { | |
1166 LoginUIService* service = GetLoginUIService(); | |
1167 if (!service->current_login_ui()) | |
1168 return false; | |
1169 service->current_login_ui()->FocusUI(); | |
1170 } | |
1108 return true; | 1171 return true; |
1109 } | 1172 } |
1110 | 1173 |
1111 LoginUIService* SyncSetupHandler::GetLoginUIService() const { | 1174 LoginUIService* SyncSetupHandler::GetLoginUIService() const { |
1112 return LoginUIServiceFactory::GetForProfile(GetProfile()); | 1175 return LoginUIServiceFactory::GetForProfile(GetProfile()); |
1113 } | 1176 } |
1114 | 1177 |
1115 void SyncSetupHandler::CloseOverlay() { | 1178 void SyncSetupHandler::CloseOverlay() { |
1116 // Stop a timer to handle timeout in waiting for sync setup. | 1179 // Stop a timer to handle timeout in waiting for sync setup. |
1117 backend_start_timer_.reset(); | 1180 backend_start_timer_.reset(); |
1118 | 1181 |
1119 CloseSyncSetup(); | 1182 CloseSyncSetup(); |
1120 web_ui()->CallJavascriptFunction("OptionsPage.closeOverlay"); | 1183 web_ui()->CallJavascriptFunction("OptionsPage.closeOverlay"); |
1121 } | 1184 } |
1122 | 1185 |
1186 void SyncSetupHandler::CloseGaiaSigninPage() { | |
1187 if (active_sync_setup_handler_ == this && active_gaia_signin_tab_) { | |
1188 content::WebContentsObserver::Observe(NULL); | |
1189 | |
1190 Browser* browser = browser::FindBrowserWithWebContents( | |
1191 active_sync_setup_handler_->active_gaia_signin_tab_); | |
1192 TabStripModel* tab_strip_model = browser->tab_strip_model(); | |
1193 int index = tab_strip_model->GetIndexOfWebContents( | |
1194 active_sync_setup_handler_->active_gaia_signin_tab_); | |
1195 tab_strip_model->ExecuteContextMenuCommand( | |
1196 index, TabStripModel::CommandCloseTab); | |
1197 } | |
1198 | |
1199 active_gaia_signin_tab_ = NULL; | |
1200 active_sync_setup_handler_ = NULL; | |
1201 } | |
1202 | |
1123 bool SyncSetupHandler::IsLoginAuthDataValid(const std::string& username, | 1203 bool SyncSetupHandler::IsLoginAuthDataValid(const std::string& username, |
1124 string16* error_message) { | 1204 string16* error_message) { |
1125 if (username.empty()) | 1205 if (username.empty()) |
1126 return true; | 1206 return true; |
1127 | 1207 |
1128 // Can be null during some unit tests. | 1208 // Can be null during some unit tests. |
1129 if (!web_ui()) | 1209 if (!web_ui()) |
1130 return true; | 1210 return true; |
1131 | 1211 |
1132 if (!GetSignin()->IsAllowedUsername(username)) { | 1212 if (!GetSignin()->IsAllowedUsername(username)) { |
(...skipping 15 matching lines...) Expand all Loading... | |
1148 if (i != current_profile_index && AreUserNamesEqual( | 1228 if (i != current_profile_index && AreUserNamesEqual( |
1149 cache.GetUserNameOfProfileAtIndex(i), username_utf16)) { | 1229 cache.GetUserNameOfProfileAtIndex(i), username_utf16)) { |
1150 *error_message = l10n_util::GetStringUTF16( | 1230 *error_message = l10n_util::GetStringUTF16( |
1151 IDS_SYNC_USER_NAME_IN_USE_ERROR); | 1231 IDS_SYNC_USER_NAME_IN_USE_ERROR); |
1152 return false; | 1232 return false; |
1153 } | 1233 } |
1154 } | 1234 } |
1155 | 1235 |
1156 return true; | 1236 return true; |
1157 } | 1237 } |
OLD | NEW |