media_galleries_test_util.cc revision f2477e01787aa58f445919b809d89e252beef54f
12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file. 42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/media_galleries/media_galleries_test_util.h" 62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 74e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#if defined(OS_WIN) 84e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include <windows.h> 94e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#endif 104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 11eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/base_paths.h" 122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/file_util.h" 132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/file_path.h" 142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/path_service.h" 15868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/stringprintf.h" 1690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "chrome/browser/extensions/extension_prefs.h" 172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/extension_service.h" 182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/extension_system.h" 194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chrome/browser/media_galleries/fileapi/picasa_finder.h" 202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/profiles/profile.h" 212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/common/chrome_paths.h" 22f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/common/extension.h" 233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "extensions/common/manifest_constants.h" 242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h" 252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 268bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#if defined(OS_MACOSX) 278bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "base/mac/foundation_util.h" 288bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "base/strings/sys_string_conversions.h" 298bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "chrome/browser/media_galleries/fileapi/iapps_finder_impl.h" 308bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "chrome/browser/policy/preferences_mock_mac.h" 318bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#endif // OS_MACOSX 328bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#if defined(OS_WIN) 344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/test/test_reg_util_win.h" 354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/win/registry.h" 368bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#endif // OS_WIN 374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)scoped_refptr<extensions::Extension> AddMediaGalleriesApp( 392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const std::string& name, 402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const std::vector<std::string>& media_galleries_permissions, 412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Profile* profile) { 422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_ptr<DictionaryValue> manifest(new DictionaryValue); 433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) manifest->SetString(extensions::manifest_keys::kName, name); 443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) manifest->SetString(extensions::manifest_keys::kVersion, "0.1"); 453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) manifest->SetInteger(extensions::manifest_keys::kManifestVersion, 2); 462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ListValue* background_script_list = new ListValue; 472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) background_script_list->Append(Value::CreateStringValue("background.js")); 483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) manifest->Set(extensions::manifest_keys::kPlatformAppBackgroundScripts, 492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) background_script_list); 502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ListValue* permission_detail_list = new ListValue; 522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (size_t i = 0; i < media_galleries_permissions.size(); i++) 532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) permission_detail_list->Append( 542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Value::CreateStringValue(media_galleries_permissions[i])); 552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DictionaryValue* media_galleries_permission = new DictionaryValue(); 562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) media_galleries_permission->Set("mediaGalleries", permission_detail_list); 572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ListValue* permission_list = new ListValue; 582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) permission_list->Append(media_galleries_permission); 593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) manifest->Set(extensions::manifest_keys::kPermissions, permission_list); 602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 6190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) extensions::ExtensionPrefs* extension_prefs = 6290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) extensions::ExtensionPrefs::Get(profile); 6390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) base::FilePath path = extension_prefs->install_directory().AppendASCII(name); 642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string errors; 652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_refptr<extensions::Extension> extension = 662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) extensions::Extension::Create(path, extensions::Manifest::INTERNAL, 672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *manifest.get(), 682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) extensions::Extension::NO_FLAGS, &errors); 692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) EXPECT_TRUE(extension.get() != NULL) << errors; 702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) EXPECT_TRUE(extensions::Extension::IdIsValid(extension->id())); 712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!extension.get() || !extensions::Extension::IdIsValid(extension->id())) 722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return NULL; 732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 7490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) extension_prefs->OnExtensionInstalled( 75a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) extension.get(), 76a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) extensions::Extension::ENABLED, 77f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) false, 782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) syncer::StringOrdinal::CreateInitialOrdinal()); 7990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) ExtensionService* extension_service = 8090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) extensions::ExtensionSystem::Get(profile)->extension_service(); 81868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) extension_service->AddExtension(extension.get()); 822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) extension_service->EnableExtension(extension->id()); 832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return extension; 852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)EnsureMediaDirectoriesExists::EnsureMediaDirectoriesExists() 882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) : num_galleries_(0) { 892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Init(); 902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 92eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochEnsureMediaDirectoriesExists::~EnsureMediaDirectoriesExists() { 931e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#if defined(OS_MACOSX) 941e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) iapps::SetMacPreferencesForTesting(NULL); 951e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) picasa::SetMacPreferencesForTesting(NULL); 961e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#endif // OS_MACOSX 97eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 98eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)base::FilePath EnsureMediaDirectoriesExists::GetFakeAppDataPath() const { 1004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) DCHECK(fake_dir_.IsValid()); 1014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return fake_dir_.path().AppendASCII("appdata"); 1024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 1034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 1044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#if defined(OS_WIN) 1054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)base::FilePath EnsureMediaDirectoriesExists::GetFakeLocalAppDataPath() const { 1064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) DCHECK(fake_dir_.IsValid()); 1074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return fake_dir_.path().AppendASCII("localappdata"); 1084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 1094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 1101e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void EnsureMediaDirectoriesExists::SetCustomPicasaAppDataPath( 1114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) const base::FilePath& path) { 1124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) base::win::RegKey key(HKEY_CURRENT_USER, picasa::kPicasaRegistryPath, 1134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) KEY_SET_VALUE); 1141e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) key.WriteValue(picasa::kPicasaRegistryAppDataPathKey, path.value().c_str()); 1154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 1168bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#endif // OS_WIN 1174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 1181e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#if defined(OS_MACOSX) 1191e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void EnsureMediaDirectoriesExists::SetCustomPicasaAppDataPath( 1201e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) const base::FilePath& path) { 1211e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) mac_preferences_->AddTestItem( 1221e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) base::mac::NSToCFCast(picasa::kPicasaAppDataPathMacPreferencesKey), 1231e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) base::SysUTF8ToNSString(path.value()), 1241e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) false); 1251e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)} 1261e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#endif // OS_MACOSX 1271e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 1284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#if defined(OS_WIN) || defined(OS_MACOSX) 1294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)base::FilePath 1304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)EnsureMediaDirectoriesExists::GetFakePicasaFoldersRootPath() const { 1314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) DCHECK(fake_dir_.IsValid()); 1324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return fake_dir_.path().AppendASCII("picasa_folders"); 1334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 1348bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#endif // OS_WIN || OS_MACOSX 1354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void EnsureMediaDirectoriesExists::Init() { 1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(OS_CHROMEOS) || defined(OS_ANDROID) 1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#else 1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 141eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ASSERT_TRUE(fake_dir_.CreateUniqueTempDir()); 1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 143eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#if defined(OS_WIN) || defined(OS_MACOSX) 1448bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // This is to control whether or not tests think iTunes (on Windows) and 1458bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // Picasa are installed. 1464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) app_data_override_.reset(new base::ScopedPathOverride( 1474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) base::DIR_APP_DATA, GetFakeAppDataPath())); 1488bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#endif // OS_WIN || OS_MACOSX 1498bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 1504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#if defined(OS_WIN) 1514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // Picasa on Windows is by default in the DIR_LOCAL_APP_DATA directory. 1524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) local_app_data_override_.reset(new base::ScopedPathOverride( 1534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) base::DIR_LOCAL_APP_DATA, GetFakeLocalAppDataPath())); 1544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // Picasa also looks in the registry for an alternate path. 1554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) registry_override_.OverrideRegistry(HKEY_CURRENT_USER, L"hkcu_picasa"); 1568bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#endif // OS_WIN 1578bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 1588bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#if defined(OS_MACOSX) 1598bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) mac_preferences_.reset(new MockPreferences); 1608bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) iapps::SetMacPreferencesForTesting(mac_preferences_.get()); 1611e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) picasa::SetMacPreferencesForTesting(mac_preferences_.get()); 1628bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 1638bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // iTunes override. 1648bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) mac_preferences_->AddTestItem( 1658bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) base::mac::NSToCFCast(iapps::kITunesRecentDatabasePathsKey), 1668bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) base::SysUTF8ToNSString(fake_dir_.path().AppendASCII("itunes").value()), 1678bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) false); 1688bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 1698bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // iPhoto override. 1708bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) mac_preferences_->AddTestItem( 1718bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) base::mac::NSToCFCast(iapps::kIPhotoRecentDatabasesKey), 1728bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) base::SysUTF8ToNSString(fake_dir_.path().AppendASCII("iphoto").value()), 1738bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) false); 1748bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#endif // OS_MACOSX 1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 176eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch music_override_.reset(new base::ScopedPathOverride( 1774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) chrome::DIR_USER_MUSIC, fake_dir_.path().AppendASCII("music"))); 178eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch pictures_override_.reset(new base::ScopedPathOverride( 1794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) chrome::DIR_USER_PICTURES, fake_dir_.path().AppendASCII("pictures"))); 180eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch video_override_.reset(new base::ScopedPathOverride( 1814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) chrome::DIR_USER_VIDEOS, fake_dir_.path().AppendASCII("videos"))); 182eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch num_galleries_ = 3; 1838bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#endif // OS_CHROMEOS || OS_ANDROID 1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 185