1c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch// Copyright 2014 The Chromium Authors. All rights reserved.
258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// found in the LICENSE file.
458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
5c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "chrome/browser/ui/views/profiles/user_manager_view.h"
658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "chrome/browser/browser_process.h"
858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "chrome/browser/lifetime/application_lifetime.h"
958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "chrome/browser/profiles/profile_manager.h"
105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/browser/profiles/profile_metrics.h"
1123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#include "chrome/browser/profiles/profile_window.h"
121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "chrome/browser/profiles/profiles_state.h"
1358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "chrome/browser/ui/browser.h"
140f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "chrome/browser/ui/browser_dialogs.h"
1503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "chrome/browser/ui/browser_finder.h"
1658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "chrome/browser/ui/browser_window.h"
171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "chrome/browser/ui/user_manager.h"
18a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "chrome/browser/ui/views/auto_keep_alive.h"
196e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "chrome/grit/chromium_strings.h"
2058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "content/public/browser/web_contents.h"
2158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "ui/base/l10n/l10n_util.h"
2203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "ui/gfx/screen.h"
2358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "ui/views/controls/webview/webview.h"
2458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "ui/views/layout/fill_layout.h"
2558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "ui/views/view.h"
2658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "ui/views/widget/widget.h"
27116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "ui/views/window/dialog_client_view.h"
2858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
2958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#if defined(OS_WIN)
3058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "chrome/browser/shell_integration.h"
3158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "ui/base/win/shell.h"
3258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "ui/views/win/hwnd_util.h"
3358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#endif
3458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
3558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)namespace {
3658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// An open User Manager window. There can only be one open at a time. This
381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// is reset to NULL when the window is closed.
391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciUserManagerView* instance_ = NULL;
4058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} // namespace
420f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// UserManager -----------------------------------------------------------------
4458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid UserManager::Show(
461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const base::FilePath& profile_path_to_focus,
471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    profiles::UserManagerTutorialMode tutorial_mode,
481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    profiles::UserManagerProfileSelected profile_open_action) {
495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ProfileMetrics::LogProfileSwitchUser(ProfileMetrics::OPEN_USER_MANAGER);
5058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (instance_) {
511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // If we are showing the User Manager after locking a profile, change the
521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // active profile to Guest.
531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    profiles::SetActiveProfileToGuestIfLocked();
541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
5558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // If there's a user manager window open already, just activate it.
5658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    instance_->GetWidget()->Activate();
5758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return;
5858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
5958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
6058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Create the guest profile, if necessary, and open the user manager
6158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // from the guest profile.
6223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  profiles::CreateGuestProfileForUserManager(
6323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      profile_path_to_focus,
6423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      tutorial_mode,
651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      profile_open_action,
66010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      base::Bind(&UserManagerView::OnGuestProfileCreated,
6703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                 base::Passed(make_scoped_ptr(new UserManagerView)),
6803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                 profile_path_to_focus));
6958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
7058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid UserManager::Hide() {
720f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (instance_)
730f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    instance_->GetWidget()->Close();
740f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
750f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccibool UserManager::IsShowing() {
770f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  return instance_ ? instance_->GetWidget()->IsActive() : false;
780f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
790f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// UserManagerView -------------------------------------------------------------
811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciUserManagerView::UserManagerView()
831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    : web_view_(NULL),
841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      keep_alive_(new AutoKeepAlive(NULL)) {
851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciUserManagerView::~UserManagerView() {
881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
9023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)// static
91010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void UserManagerView::OnGuestProfileCreated(
92010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    scoped_ptr<UserManagerView> instance,
9303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    const base::FilePath& profile_path_to_focus,
94010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    Profile* guest_profile,
95010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    const std::string& url) {
961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // If we are showing the User Manager after locking a profile, change the
971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // active profile to Guest.
981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  profiles::SetActiveProfileToGuestIfLocked();
991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK(!instance_);
101010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  instance_ = instance.release();  // |instance_| takes over ownership.
10203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  instance_->Init(profile_path_to_focus, guest_profile, GURL(url));
103010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
104010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
10503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void UserManagerView::Init(
10603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    const base::FilePath& profile_path_to_focus,
10703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    Profile* guest_profile,
10803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    const GURL& url) {
109010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  web_view_ = new views::WebView(guest_profile);
110116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  web_view_->set_allow_accelerators(true);
111010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  AddChildView(web_view_);
112116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  SetLayoutManager(new views::FillLayout);
113116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  AddAccelerator(ui::Accelerator(ui::VKEY_W, ui::EF_CONTROL_DOWN));
11458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
11503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // If the user manager is being displayed from an existing profile, use
11603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // its last active browser to determine where the user manager should be
11703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // placed.  This is used so that we can center the dialog on the correct
11803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // monitor in a multiple-monitor setup.
11903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  //
12003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // If |profile_path_to_focus| is empty (for example, starting up chrome
12103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // when all existing profiles are locked) or we can't find an active
12203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // browser, bounds will remain empty and the user manager will be centered on
12303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // the default monitor by default.
12403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  gfx::Rect bounds;
12503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (!profile_path_to_focus.empty()) {
12603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    ProfileManager* manager = g_browser_process->profile_manager();
12703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if (manager) {
12803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      Profile* profile = manager->GetProfileByPath(profile_path_to_focus);
12903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      DCHECK(profile);
13003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      Browser* browser = chrome::FindLastActiveWithProfile(profile,
13103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)          chrome::GetActiveDesktop());
13203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      if (browser) {
13303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        gfx::NativeView native_view =
13403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)            views::Widget::GetWidgetForNativeWindow(
13503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                browser->window()->GetNativeWindow())->GetNativeView();
13603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        bounds = gfx::Screen::GetScreenFor(native_view)->
13703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)            GetDisplayNearestWindow(native_view).work_area();
1381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        bounds.ClampToCenteredSize(gfx::Size(UserManager::kWindowWidth,
1391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                             UserManager::kWindowHeight));
14003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      }
14103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    }
14203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
14303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
14403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  DialogDelegate::CreateDialogWidgetWithBounds(this, NULL, NULL, bounds);
14503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
146116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Since the User Manager can be the only top level window, we don't
147116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // want to accidentally quit all of Chrome if the user is just trying to
148116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // unfocus the selected pod in the WebView.
149116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  GetDialogClientView()->RemoveAccelerator(
150116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_NONE));
151a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
15258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#if defined(OS_WIN)
1530f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // Set the app id for the task manager to the app id of its parent
1540f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  ui::win::SetAppIdForWindow(
1550f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      ShellIntegration::GetChromiumModelIdForProfile(
1560f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)          guest_profile->GetPath()),
157010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      views::HWNDForWidget(GetWidget()));
15858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#endif
159010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  GetWidget()->Show();
1600f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
161010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  web_view_->LoadInitialURL(url);
162010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  web_view_->RequestFocus();
16358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
16458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
165116680a4aac90f2aa7413d9095a592090648e557Ben Murdochbool UserManagerView::AcceleratorPressed(const ui::Accelerator& accelerator) {
166116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK_EQ(ui::VKEY_W, accelerator.key_code());
167116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK_EQ(ui::EF_CONTROL_DOWN, accelerator.modifiers());
168116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  GetWidget()->Close();
169116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return true;
170116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
171116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
172cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)gfx::Size UserManagerView::GetPreferredSize() const {
1731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return gfx::Size(UserManager::kWindowWidth, UserManager::kWindowHeight);
17458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
17558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
17658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)bool UserManagerView::CanResize() const {
17758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return true;
17858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
17958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
18058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)bool UserManagerView::CanMaximize() const {
18158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return true;
18258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
18358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
1841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccibool UserManagerView::CanMinimize() const {
1851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return true;
1861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)base::string16 UserManagerView::GetWindowTitle() const {
1896e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  return l10n_util::GetStringUTF16(IDS_PRODUCT_NAME);
19058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
19158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
19258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)int UserManagerView::GetDialogButtons() const {
19358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return ui::DIALOG_BUTTON_NONE;
19458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
19558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
19658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void UserManagerView::WindowClosing() {
19758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Now that the window is closed, we can allow a new one to be opened.
19858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // (WindowClosing comes in asynchronously from the call to Close() and we
19958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // may have already opened a new instance).
20058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (instance_ == this)
20158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    instance_ = NULL;
20258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
20358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
20458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)bool UserManagerView::UseNewStyleForThisDialog() const {
20558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return false;
20658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
207