17d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
27d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
37d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)// found in the LICENSE file.
47d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
57d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "content/child/runtime_features.h"
67d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
77d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "base/command_line.h"
81320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/metrics/field_trial.h"
95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "content/common/content_switches_internal.h"
107d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "content/public/common/content_switches.h"
117d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "third_party/WebKit/public/web/WebRuntimeFeatures.h"
1223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#include "ui/native_theme/native_theme_switches.h"
137d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
147d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#if defined(OS_ANDROID)
157d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include <cpu-features.h>
1646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "base/android/build_info.h"
175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/metrics/field_trial.h"
188bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "media/base/android/media_codec_bridge.h"
196e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#elif defined(OS_WIN)
206e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "base/win/windows_version.h"
217d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#endif
227d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
23f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)using blink::WebRuntimeFeatures;
247d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
257d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)namespace content {
267d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
277d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)static void SetRuntimeFeatureDefaultsForPlatform() {
287d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#if defined(OS_ANDROID)
298bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // MSE/EME implementation needs Android MediaCodec API.
308bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (!media::MediaCodecBridge::IsAvailable()) {
314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    WebRuntimeFeatures::enableMediaSource(false);
324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    WebRuntimeFeatures::enablePrefixedEncryptedMedia(false);
330529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    WebRuntimeFeatures::enableEncryptedMedia(false);
34a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
35116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // WebAudio is enabled by default but only when the MediaCodec API
36116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // is available.
37116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  AndroidCpuFamily cpu_family = android_getCpuFamily();
38a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  WebRuntimeFeatures::enableWebAudio(
39a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      media::MediaCodecBridge::IsAvailable() &&
40116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      ((cpu_family == ANDROID_CPU_FAMILY_ARM) ||
41116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch       (cpu_family == ANDROID_CPU_FAMILY_ARM64) ||
42116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch       (cpu_family == ANDROID_CPU_FAMILY_X86) ||
43116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch       (cpu_family == ANDROID_CPU_FAMILY_MIPS)));
4446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
457d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // Android does not have support for PagePopup
467d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  WebRuntimeFeatures::enablePagePopup(false);
4758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Android does not yet support the Web Notification API. crbug.com/115320
4858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  WebRuntimeFeatures::enableNotifications(false);
491e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // Android does not yet support SharedWorker. crbug.com/154571
501e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  WebRuntimeFeatures::enableSharedWorker(false);
51a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // Android does not yet support NavigatorContentUtils.
52a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  WebRuntimeFeatures::enableNavigatorContentUtils(false);
535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  WebRuntimeFeatures::enableTouchIconLoading(true);
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  WebRuntimeFeatures::enableOrientationEvent(true);
55f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  WebRuntimeFeatures::enableFastMobileScrolling(true);
56116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  WebRuntimeFeatures::enableMediaCapture(true);
571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  WebRuntimeFeatures::enableCompositedSelectionUpdate(true);
585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // If navigation transitions gets activated via field trial, enable it in
595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // blink. We don't set this to false in case the user has manually enabled
605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // the feature via experimental web platform features.
615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (base::FieldTrialList::FindFullName("NavigationTransitions") == "Enabled")
625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    WebRuntimeFeatures::enableNavigationTransitions(true);
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#else
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  WebRuntimeFeatures::enableNavigatorContentUtils(true);
65a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#endif  // defined(OS_ANDROID)
665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#if !(defined OS_ANDROID || defined OS_CHROMEOS || defined OS_IOS)
685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // Only Android, ChromeOS, and IOS support NetInfo right now.
695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    WebRuntimeFeatures::enableNetworkInformation(false);
705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#endif
716e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
726e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#if defined(OS_WIN)
736e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // Screen Orientation API is currently broken on Windows 8 Metro mode and
746e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // until we can find how to disable it only for Blink instances running in a
756e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // renderer process in Metro, we need to disable the API altogether for Win8.
766e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // See http://crbug.com/400846
776e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (base::win::OSInfo::GetInstance()->version() >= base::win::VERSION_WIN8)
786e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    WebRuntimeFeatures::enableScreenOrientation(false);
796e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#endif // OS_WIN
807d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
817d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
827d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void SetRuntimeFeaturesDefaultsAndUpdateFromArgs(
836e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    const base::CommandLine& command_line) {
847dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (command_line.HasSwitch(switches::kEnableExperimentalWebPlatformFeatures))
857d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    WebRuntimeFeatures::enableExperimentalFeatures(true);
867d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
877d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  SetRuntimeFeatureDefaultsForPlatform();
887d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
897d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (command_line.HasSwitch(switches::kDisableDatabases))
907d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    WebRuntimeFeatures::enableDatabase(false);
917d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
927d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (command_line.HasSwitch(switches::kDisableApplicationCache))
937d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    WebRuntimeFeatures::enableApplicationCache(false);
947d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
957d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (command_line.HasSwitch(switches::kDisableDesktopNotifications))
967d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    WebRuntimeFeatures::enableNotifications(false);
977d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
987d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (command_line.HasSwitch(switches::kDisableLocalStorage))
997d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    WebRuntimeFeatures::enableLocalStorage(false);
1007d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1017d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (command_line.HasSwitch(switches::kDisableSessionStorage))
1027d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    WebRuntimeFeatures::enableSessionStorage(false);
1037d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
104a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  if (command_line.HasSwitch(switches::kDisableMediaSource))
1054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    WebRuntimeFeatures::enableMediaSource(false);
1064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1071e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (command_line.HasSwitch(switches::kDisableSharedWorkers))
1081e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    WebRuntimeFeatures::enableSharedWorker(false);
1091e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1107d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#if defined(OS_ANDROID)
1111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (command_line.HasSwitch(switches::kDisableWebRTC))
1127d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    WebRuntimeFeatures::enablePeerConnection(false);
1137d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
114d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (!command_line.HasSwitch(switches::kEnableSpeechRecognition))
1157d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    WebRuntimeFeatures::enableScriptedSpeech(false);
1164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
117effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // WebAudio is enabled by default on ARM and X86, if the MediaCodec
118effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // API is available.
119a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  WebRuntimeFeatures::enableWebAudio(
120a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      !command_line.HasSwitch(switches::kDisableWebAudio) &&
121a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      media::MediaCodecBridge::IsAvailable());
122a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#else
1237d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (command_line.HasSwitch(switches::kDisableWebAudio))
1247d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    WebRuntimeFeatures::enableWebAudio(false);
125a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#endif
1267d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1277d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (command_line.HasSwitch(switches::kEnableEncryptedMedia))
1287d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    WebRuntimeFeatures::enableEncryptedMedia(true);
1297d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (command_line.HasSwitch(switches::kDisablePrefixedEncryptedMedia))
1314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    WebRuntimeFeatures::enablePrefixedEncryptedMedia(false);
1327d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1337d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (command_line.HasSwitch(switches::kEnableWebMIDI))
1347d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    WebRuntimeFeatures::enableWebMIDI(true);
1357d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1367d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (command_line.HasSwitch(switches::kDisableFileSystem))
1377d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    WebRuntimeFeatures::enableFileSystem(false);
1387d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1397d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (command_line.HasSwitch(switches::kEnableExperimentalCanvasFeatures))
1407d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    WebRuntimeFeatures::enableExperimentalCanvasFeatures(true);
1417d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
14234680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)  if (command_line.HasSwitch(switches::kEnableAcceleratedJpegDecoding))
14334680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)    WebRuntimeFeatures::enableDecodeToYUV(true);
14434680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)
1451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (command_line.HasSwitch(switches::kDisableDisplayList2dCanvas)) {
1461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    WebRuntimeFeatures::enableDisplayList2dCanvas(false);
1471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  } else if (command_line.HasSwitch(switches::kEnableDisplayList2dCanvas)) {
1485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    WebRuntimeFeatures::enableDisplayList2dCanvas(true);
1491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  } else {
1501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    WebRuntimeFeatures::enableDisplayList2dCanvas(
1511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        base::FieldTrialList::FindFullName("DisplayList2dCanvas") == "Enabled"
1521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    );
1531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
1547d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1557d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (command_line.HasSwitch(switches::kEnableWebGLDraftExtensions))
1567d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    WebRuntimeFeatures::enableWebGLDraftExtensions(true);
157ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
158cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (command_line.HasSwitch(switches::kEnableWebGLImageChromium))
159cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    WebRuntimeFeatures::enableWebGLImageChromium(true);
160cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
1614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (command_line.HasSwitch(switches::kEnableOverlayFullscreenVideo))
1624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    WebRuntimeFeatures::enableOverlayFullscreenVideo(true);
1634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
16423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  if (ui::IsOverlayScrollbarEnabled())
165c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    WebRuntimeFeatures::enableOverlayScrollbars(true);
166424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
167a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (command_line.HasSwitch(switches::kEnableBleedingEdgeRenderingFastPaths))
168a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    WebRuntimeFeatures::enableBleedingEdgeFastPaths(true);
169010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
170010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (command_line.HasSwitch(switches::kEnablePreciseMemoryInfo))
171010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    WebRuntimeFeatures::enablePreciseMemoryInfo(true);
172cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
173cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (command_line.HasSwitch(switches::kEnableLayerSquashing))
174cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    WebRuntimeFeatures::enableLayerSquashing(true);
1755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (command_line.HasSwitch(switches::kEnableNetworkInformation) ||
1775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      command_line.HasSwitch(
1785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          switches::kEnableExperimentalWebPlatformFeatures)) {
1795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    WebRuntimeFeatures::enableNetworkInformation(true);
1805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
1817d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
1827d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1837d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}  // namespace content
184