190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved. 290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// found in the LICENSE file. 490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "remoting/host/chromoting_param_traits.h" 690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 75e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "base/strings/stringprintf.h" 86e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" 990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 1090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)namespace IPC { 1190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 1290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// static 1390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void ParamTraits<webrtc::DesktopVector>::Write(Message* m, 1490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) const webrtc::DesktopVector& p) { 1590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) m->WriteInt(p.x()); 1690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) m->WriteInt(p.y()); 1790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 1890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 1990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// static 2090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)bool ParamTraits<webrtc::DesktopVector>::Read(const Message* m, 2190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) PickleIterator* iter, 2290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) webrtc::DesktopVector* r) { 2390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) int x, y; 2490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (!m->ReadInt(iter, &x) || !m->ReadInt(iter, &y)) 2590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return false; 2690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) *r = webrtc::DesktopVector(x, y); 2790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return true; 2890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 2990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 3090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// static 3190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void ParamTraits<webrtc::DesktopVector>::Log(const webrtc::DesktopVector& p, 3290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) std::string* l) { 3390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) l->append(base::StringPrintf("webrtc::DesktopVector(%d, %d)", 3490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) p.x(), p.y())); 3590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 3690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 3790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// static 3890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void ParamTraits<webrtc::DesktopSize>::Write(Message* m, 3990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) const webrtc::DesktopSize& p) { 4090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) m->WriteInt(p.width()); 4190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) m->WriteInt(p.height()); 4290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 4390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 4490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// static 4590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)bool ParamTraits<webrtc::DesktopSize>::Read(const Message* m, 4690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) PickleIterator* iter, 4790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) webrtc::DesktopSize* r) { 4890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) int width, height; 4990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (!m->ReadInt(iter, &width) || !m->ReadInt(iter, &height)) 5090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return false; 5190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) *r = webrtc::DesktopSize(width, height); 5290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return true; 5390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 5490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 5590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// static 5690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void ParamTraits<webrtc::DesktopSize>::Log(const webrtc::DesktopSize& p, 5790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) std::string* l) { 5890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) l->append(base::StringPrintf("webrtc::DesktopSize(%d, %d)", 5990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) p.width(), p.height())); 6090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 6190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 6290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// static 6390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void ParamTraits<webrtc::DesktopRect>::Write(Message* m, 6490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) const webrtc::DesktopRect& p) { 6590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) m->WriteInt(p.left()); 6690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) m->WriteInt(p.top()); 6790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) m->WriteInt(p.right()); 6890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) m->WriteInt(p.bottom()); 6990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 7090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 7190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// static 7290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)bool ParamTraits<webrtc::DesktopRect>::Read(const Message* m, 7390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) PickleIterator* iter, 7490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) webrtc::DesktopRect* r) { 7590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) int left, right, top, bottom; 7690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (!m->ReadInt(iter, &left) || !m->ReadInt(iter, &top) || 7790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) !m->ReadInt(iter, &right) || !m->ReadInt(iter, &bottom)) { 7890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return false; 7990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 8090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) *r = webrtc::DesktopRect::MakeLTRB(left, top, right, bottom); 8190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return true; 8290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 8390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 8490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// static 8590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void ParamTraits<webrtc::DesktopRect>::Log(const webrtc::DesktopRect& p, 8690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) std::string* l) { 8790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) l->append(base::StringPrintf("webrtc::DesktopRect(%d, %d, %d, %d)", 8890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) p.left(), p.top(), p.right(), p.bottom())); 8990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 9090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 9190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// static 926e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void ParamTraits<webrtc::MouseCursor>::Write( 936e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) Message* m, 946e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) const webrtc::MouseCursor& p) { 956e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) ParamTraits<webrtc::DesktopSize>::Write(m, p.image()->size()); 966e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 976e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // Data is serialized in such a way that size is exactly width * height * 986e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // |kBytesPerPixel|. 996e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) std::string data; 1006e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) uint8_t* current_row = p.image()->data(); 1016e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) for (int y = 0; y < p.image()->size().height(); ++y) { 1026e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) data.append(current_row, 1036e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) current_row + p.image()->size().width() * 1046e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) webrtc::DesktopFrame::kBytesPerPixel); 1056e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) current_row += p.image()->stride(); 1066e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } 1076e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) m->WriteData(reinterpret_cast<const char*>(p.image()->data()), data.size()); 1086e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1096e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) ParamTraits<webrtc::DesktopVector>::Write(m, p.hotspot()); 1106e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} 1116e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1126e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// static 1136e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)bool ParamTraits<webrtc::MouseCursor>::Read( 1146e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) const Message* m, 1156e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) PickleIterator* iter, 1166e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) webrtc::MouseCursor* r) { 1176e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) webrtc::DesktopSize size; 1186e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if (!ParamTraits<webrtc::DesktopSize>::Read(m, iter, &size) || 1196e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) size.width() <= 0 || size.width() > (SHRT_MAX / 2) || 1206e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) size.height() <= 0 || size.height() > (SHRT_MAX / 2)) { 1216e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return false; 1226e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } 1236e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1246e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) const int expected_length = 1256e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) size.width() * size.height() * webrtc::DesktopFrame::kBytesPerPixel; 1266e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1276e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) const char* data; 1286e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) int data_length; 1296e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if (!m->ReadData(iter, &data, &data_length) || 1306e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) data_length != expected_length) { 1316e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return false; 1326e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } 1336e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1346e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) webrtc::DesktopVector hotspot; 1356e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if (!ParamTraits<webrtc::DesktopVector>::Read(m, iter, &hotspot)) 1366e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return false; 1376e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1386e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) webrtc::BasicDesktopFrame* image = new webrtc::BasicDesktopFrame(size); 1396e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) memcpy(image->data(), data, data_length); 1406e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1416e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) r->set_image(image); 1426e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) r->set_hotspot(hotspot); 1436e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return true; 1446e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} 1456e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1466e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// static 1476e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void ParamTraits<webrtc::MouseCursor>::Log( 1486e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) const webrtc::MouseCursor& p, 1496e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) std::string* l) { 1506e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) l->append(base::StringPrintf( 1516e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) "webrtc::DesktopRect{image(%d, %d), hotspot(%d, %d)}", 1526e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) p.image()->size().width(), p.image()->size().height(), 1536e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) p.hotspot().x(), p.hotspot().y())); 1546e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} 1556e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1566e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1576e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// static 15890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void ParamTraits<remoting::ScreenResolution>::Write( 15990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) Message* m, 16090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) const remoting::ScreenResolution& p) { 16190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) ParamTraits<webrtc::DesktopSize>::Write(m, p.dimensions()); 16290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) ParamTraits<webrtc::DesktopVector>::Write(m, p.dpi()); 16390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 16490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 16590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// static 16690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)bool ParamTraits<remoting::ScreenResolution>::Read( 16790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) const Message* m, 16890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) PickleIterator* iter, 16990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) remoting::ScreenResolution* r) { 17090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) webrtc::DesktopSize size; 17190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) webrtc::DesktopVector dpi; 17290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (!ParamTraits<webrtc::DesktopSize>::Read(m, iter, &size) || 17390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) !ParamTraits<webrtc::DesktopVector>::Read(m, iter, &dpi)) { 17490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return false; 17590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 17690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (size.width() < 0 || size.height() < 0 || 17790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) dpi.x() < 0 || dpi.y() < 0) { 17890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return false; 17990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 18090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) *r = remoting::ScreenResolution(size, dpi); 18190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return true; 18290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 18390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 18490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// static 18590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void ParamTraits<remoting::ScreenResolution>::Log( 18690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) const remoting::ScreenResolution& p, 18790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) std::string* l) { 18890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) l->append(base::StringPrintf("webrtc::ScreenResolution(%d, %d, %d, %d)", 18990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) p.dimensions().width(), p.dimensions().height(), 19090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) p.dpi().x(), p.dpi().y())); 19190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 19290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 19390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} // namespace IPC 19490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 195