Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1176)

Side by Side Diff: webkit/browser/fileapi/file_system_operation_impl.cc

Issue 145303002: Convert Media Galleries to use base::File (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 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 "webkit/browser/fileapi/file_system_operation_impl.h" 5 #include "webkit/browser/fileapi/file_system_operation_impl.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/single_thread_task_runner.h" 8 #include "base/single_thread_task_runner.h"
9 #include "base/strings/utf_string_conversions.h" 9 #include "base/strings/utf_string_conversions.h"
10 #include "base/time/time.h" 10 #include "base/time/time.h"
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
43 } 43 }
44 44
45 void FileSystemOperationImpl::CreateFile(const FileSystemURL& url, 45 void FileSystemOperationImpl::CreateFile(const FileSystemURL& url,
46 bool exclusive, 46 bool exclusive,
47 const StatusCallback& callback) { 47 const StatusCallback& callback) {
48 DCHECK(SetPendingOperationType(kOperationCreateFile)); 48 DCHECK(SetPendingOperationType(kOperationCreateFile));
49 GetUsageAndQuotaThenRunTask( 49 GetUsageAndQuotaThenRunTask(
50 url, 50 url,
51 base::Bind(&FileSystemOperationImpl::DoCreateFile, 51 base::Bind(&FileSystemOperationImpl::DoCreateFile,
52 weak_factory_.GetWeakPtr(), url, callback, exclusive), 52 weak_factory_.GetWeakPtr(), url, callback, exclusive),
53 base::Bind(callback, base::PLATFORM_FILE_ERROR_FAILED)); 53 base::Bind(callback, base::File::FILE_ERROR_FAILED));
54 } 54 }
55 55
56 void FileSystemOperationImpl::CreateDirectory(const FileSystemURL& url, 56 void FileSystemOperationImpl::CreateDirectory(const FileSystemURL& url,
57 bool exclusive, 57 bool exclusive,
58 bool recursive, 58 bool recursive,
59 const StatusCallback& callback) { 59 const StatusCallback& callback) {
60 DCHECK(SetPendingOperationType(kOperationCreateDirectory)); 60 DCHECK(SetPendingOperationType(kOperationCreateDirectory));
61 GetUsageAndQuotaThenRunTask( 61 GetUsageAndQuotaThenRunTask(
62 url, 62 url,
63 base::Bind(&FileSystemOperationImpl::DoCreateDirectory, 63 base::Bind(&FileSystemOperationImpl::DoCreateDirectory,
64 weak_factory_.GetWeakPtr(), url, callback, 64 weak_factory_.GetWeakPtr(), url, callback,
65 exclusive, recursive), 65 exclusive, recursive),
66 base::Bind(callback, base::PLATFORM_FILE_ERROR_FAILED)); 66 base::Bind(callback, base::File::FILE_ERROR_FAILED));
67 } 67 }
68 68
69 void FileSystemOperationImpl::Copy( 69 void FileSystemOperationImpl::Copy(
70 const FileSystemURL& src_url, 70 const FileSystemURL& src_url,
71 const FileSystemURL& dest_url, 71 const FileSystemURL& dest_url,
72 CopyOrMoveOption option, 72 CopyOrMoveOption option,
73 const CopyProgressCallback& progress_callback, 73 const CopyProgressCallback& progress_callback,
74 const StatusCallback& callback) { 74 const StatusCallback& callback) {
75 DCHECK(SetPendingOperationType(kOperationCopy)); 75 DCHECK(SetPendingOperationType(kOperationCopy));
76 DCHECK(!recursive_operation_delegate_); 76 DCHECK(!recursive_operation_delegate_);
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after
175 weak_factory_.GetWeakPtr(), url, callback)); 175 weak_factory_.GetWeakPtr(), url, callback));
176 } 176 }
177 177
178 void FileSystemOperationImpl::Truncate(const FileSystemURL& url, int64 length, 178 void FileSystemOperationImpl::Truncate(const FileSystemURL& url, int64 length,
179 const StatusCallback& callback) { 179 const StatusCallback& callback) {
180 DCHECK(SetPendingOperationType(kOperationTruncate)); 180 DCHECK(SetPendingOperationType(kOperationTruncate));
181 GetUsageAndQuotaThenRunTask( 181 GetUsageAndQuotaThenRunTask(
182 url, 182 url,
183 base::Bind(&FileSystemOperationImpl::DoTruncate, 183 base::Bind(&FileSystemOperationImpl::DoTruncate,
184 weak_factory_.GetWeakPtr(), url, callback, length), 184 weak_factory_.GetWeakPtr(), url, callback, length),
185 base::Bind(callback, base::PLATFORM_FILE_ERROR_FAILED)); 185 base::Bind(callback, base::File::FILE_ERROR_FAILED));
186 } 186 }
187 187
188 void FileSystemOperationImpl::TouchFile(const FileSystemURL& url, 188 void FileSystemOperationImpl::TouchFile(const FileSystemURL& url,
189 const base::Time& last_access_time, 189 const base::Time& last_access_time,
190 const base::Time& last_modified_time, 190 const base::Time& last_modified_time,
191 const StatusCallback& callback) { 191 const StatusCallback& callback) {
192 DCHECK(SetPendingOperationType(kOperationTouchFile)); 192 DCHECK(SetPendingOperationType(kOperationTouchFile));
193 async_file_util_->Touch( 193 async_file_util_->Touch(
194 operation_context_.Pass(), url, 194 operation_context_.Pass(), url,
195 last_access_time, last_modified_time, 195 last_access_time, last_modified_time,
196 base::Bind(&FileSystemOperationImpl::DidFinishOperation, 196 base::Bind(&FileSystemOperationImpl::DidFinishOperation,
197 weak_factory_.GetWeakPtr(), callback)); 197 weak_factory_.GetWeakPtr(), callback));
198 } 198 }
199 199
200 void FileSystemOperationImpl::OpenFile(const FileSystemURL& url, 200 void FileSystemOperationImpl::OpenFile(const FileSystemURL& url,
201 int file_flags, 201 int file_flags,
202 const OpenFileCallback& callback) { 202 const OpenFileCallback& callback) {
203 DCHECK(SetPendingOperationType(kOperationOpenFile)); 203 DCHECK(SetPendingOperationType(kOperationOpenFile));
204 204
205 if (file_flags & 205 if (file_flags &
206 (base::PLATFORM_FILE_TEMPORARY | base::PLATFORM_FILE_HIDDEN)) { 206 (base::PLATFORM_FILE_TEMPORARY | base::PLATFORM_FILE_HIDDEN)) {
207 callback.Run(base::PLATFORM_FILE_ERROR_FAILED, 207 callback.Run(base::File::FILE_ERROR_FAILED,
208 base::kInvalidPlatformFileValue, 208 base::kInvalidPlatformFileValue,
209 base::Closure()); 209 base::Closure());
210 return; 210 return;
211 } 211 }
212 GetUsageAndQuotaThenRunTask( 212 GetUsageAndQuotaThenRunTask(
213 url, 213 url,
214 base::Bind(&FileSystemOperationImpl::DoOpenFile, 214 base::Bind(&FileSystemOperationImpl::DoOpenFile,
215 weak_factory_.GetWeakPtr(), 215 weak_factory_.GetWeakPtr(),
216 url, callback, file_flags), 216 url, callback, file_flags),
217 base::Bind(callback, base::PLATFORM_FILE_ERROR_FAILED, 217 base::Bind(callback, base::File::FILE_ERROR_FAILED,
218 base::kInvalidPlatformFileValue, 218 base::kInvalidPlatformFileValue,
219 base::Closure())); 219 base::Closure()));
220 } 220 }
221 221
222 // We can only get here on a write or truncate that's not yet completed. 222 // We can only get here on a write or truncate that's not yet completed.
223 // We don't support cancelling any other operation at this time. 223 // We don't support cancelling any other operation at this time.
224 void FileSystemOperationImpl::Cancel(const StatusCallback& cancel_callback) { 224 void FileSystemOperationImpl::Cancel(const StatusCallback& cancel_callback) {
225 DCHECK(cancel_callback_.is_null()); 225 DCHECK(cancel_callback_.is_null());
226 cancel_callback_ = cancel_callback; 226 cancel_callback_ = cancel_callback;
227 227
(...skipping 22 matching lines...) Expand all
250 void FileSystemOperationImpl::CopyInForeignFile( 250 void FileSystemOperationImpl::CopyInForeignFile(
251 const base::FilePath& src_local_disk_file_path, 251 const base::FilePath& src_local_disk_file_path,
252 const FileSystemURL& dest_url, 252 const FileSystemURL& dest_url,
253 const StatusCallback& callback) { 253 const StatusCallback& callback) {
254 DCHECK(SetPendingOperationType(kOperationCopyInForeignFile)); 254 DCHECK(SetPendingOperationType(kOperationCopyInForeignFile));
255 GetUsageAndQuotaThenRunTask( 255 GetUsageAndQuotaThenRunTask(
256 dest_url, 256 dest_url,
257 base::Bind(&FileSystemOperationImpl::DoCopyInForeignFile, 257 base::Bind(&FileSystemOperationImpl::DoCopyInForeignFile,
258 weak_factory_.GetWeakPtr(), src_local_disk_file_path, dest_url, 258 weak_factory_.GetWeakPtr(), src_local_disk_file_path, dest_url,
259 callback), 259 callback),
260 base::Bind(callback, base::PLATFORM_FILE_ERROR_FAILED)); 260 base::Bind(callback, base::File::FILE_ERROR_FAILED));
261 } 261 }
262 262
263 void FileSystemOperationImpl::RemoveFile( 263 void FileSystemOperationImpl::RemoveFile(
264 const FileSystemURL& url, 264 const FileSystemURL& url,
265 const StatusCallback& callback) { 265 const StatusCallback& callback) {
266 DCHECK(SetPendingOperationType(kOperationRemove)); 266 DCHECK(SetPendingOperationType(kOperationRemove));
267 async_file_util_->DeleteFile( 267 async_file_util_->DeleteFile(
268 operation_context_.Pass(), url, 268 operation_context_.Pass(), url,
269 base::Bind(&FileSystemOperationImpl::DidFinishOperation, 269 base::Bind(&FileSystemOperationImpl::DidFinishOperation,
270 weak_factory_.GetWeakPtr(), callback)); 270 weak_factory_.GetWeakPtr(), callback));
(...skipping 16 matching lines...) Expand all
287 const CopyFileProgressCallback& progress_callback, 287 const CopyFileProgressCallback& progress_callback,
288 const StatusCallback& callback) { 288 const StatusCallback& callback) {
289 DCHECK(SetPendingOperationType(kOperationCopy)); 289 DCHECK(SetPendingOperationType(kOperationCopy));
290 DCHECK(src_url.IsInSameFileSystem(dest_url)); 290 DCHECK(src_url.IsInSameFileSystem(dest_url));
291 291
292 GetUsageAndQuotaThenRunTask( 292 GetUsageAndQuotaThenRunTask(
293 dest_url, 293 dest_url,
294 base::Bind(&FileSystemOperationImpl::DoCopyFileLocal, 294 base::Bind(&FileSystemOperationImpl::DoCopyFileLocal,
295 weak_factory_.GetWeakPtr(), src_url, dest_url, option, 295 weak_factory_.GetWeakPtr(), src_url, dest_url, option,
296 progress_callback, callback), 296 progress_callback, callback),
297 base::Bind(callback, base::PLATFORM_FILE_ERROR_FAILED)); 297 base::Bind(callback, base::File::FILE_ERROR_FAILED));
298 } 298 }
299 299
300 void FileSystemOperationImpl::MoveFileLocal( 300 void FileSystemOperationImpl::MoveFileLocal(
301 const FileSystemURL& src_url, 301 const FileSystemURL& src_url,
302 const FileSystemURL& dest_url, 302 const FileSystemURL& dest_url,
303 CopyOrMoveOption option, 303 CopyOrMoveOption option,
304 const StatusCallback& callback) { 304 const StatusCallback& callback) {
305 DCHECK(SetPendingOperationType(kOperationMove)); 305 DCHECK(SetPendingOperationType(kOperationMove));
306 DCHECK(src_url.IsInSameFileSystem(dest_url)); 306 DCHECK(src_url.IsInSameFileSystem(dest_url));
307 GetUsageAndQuotaThenRunTask( 307 GetUsageAndQuotaThenRunTask(
308 dest_url, 308 dest_url,
309 base::Bind(&FileSystemOperationImpl::DoMoveFileLocal, 309 base::Bind(&FileSystemOperationImpl::DoMoveFileLocal,
310 weak_factory_.GetWeakPtr(), 310 weak_factory_.GetWeakPtr(),
311 src_url, dest_url, option, callback), 311 src_url, dest_url, option, callback),
312 base::Bind(callback, base::PLATFORM_FILE_ERROR_FAILED)); 312 base::Bind(callback, base::File::FILE_ERROR_FAILED));
313 } 313 }
314 314
315 base::PlatformFileError FileSystemOperationImpl::SyncGetPlatformPath( 315 base::File::Error FileSystemOperationImpl::SyncGetPlatformPath(
316 const FileSystemURL& url, 316 const FileSystemURL& url,
317 base::FilePath* platform_path) { 317 base::FilePath* platform_path) {
318 DCHECK(SetPendingOperationType(kOperationGetLocalPath)); 318 DCHECK(SetPendingOperationType(kOperationGetLocalPath));
319 if (!file_system_context()->IsSandboxFileSystem(url.type())) 319 if (!file_system_context()->IsSandboxFileSystem(url.type()))
320 return base::PLATFORM_FILE_ERROR_INVALID_OPERATION; 320 return base::File::FILE_ERROR_INVALID_OPERATION;
321 FileSystemFileUtil* file_util = 321 FileSystemFileUtil* file_util =
322 file_system_context()->sandbox_delegate()->sync_file_util(); 322 file_system_context()->sandbox_delegate()->sync_file_util();
323 file_util->GetLocalFilePath(operation_context_.get(), url, platform_path); 323 file_util->GetLocalFilePath(operation_context_.get(), url, platform_path);
324 return base::PLATFORM_FILE_OK; 324 return base::File::FILE_OK;
325 } 325 }
326 326
327 FileSystemOperationImpl::FileSystemOperationImpl( 327 FileSystemOperationImpl::FileSystemOperationImpl(
328 const FileSystemURL& url, 328 const FileSystemURL& url,
329 FileSystemContext* file_system_context, 329 FileSystemContext* file_system_context,
330 scoped_ptr<FileSystemOperationContext> operation_context) 330 scoped_ptr<FileSystemOperationContext> operation_context)
331 : file_system_context_(file_system_context), 331 : file_system_context_(file_system_context),
332 operation_context_(operation_context.Pass()), 332 operation_context_(operation_context.Pass()),
333 async_file_util_(NULL), 333 async_file_util_(NULL),
334 pending_operation_(kOperationNone), 334 pending_operation_(kOperationNone),
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after
449 const OpenFileCallback& callback, 449 const OpenFileCallback& callback,
450 int file_flags) { 450 int file_flags) {
451 async_file_util_->CreateOrOpen( 451 async_file_util_->CreateOrOpen(
452 operation_context_.Pass(), url, file_flags, 452 operation_context_.Pass(), url, file_flags,
453 base::Bind(&FileSystemOperationImpl::DidOpenFile, 453 base::Bind(&FileSystemOperationImpl::DidOpenFile,
454 weak_factory_.GetWeakPtr(), callback)); 454 weak_factory_.GetWeakPtr(), callback));
455 } 455 }
456 456
457 void FileSystemOperationImpl::DidEnsureFileExistsExclusive( 457 void FileSystemOperationImpl::DidEnsureFileExistsExclusive(
458 const StatusCallback& callback, 458 const StatusCallback& callback,
459 base::PlatformFileError rv, bool created) { 459 base::File::Error rv, bool created) {
460 if (rv == base::PLATFORM_FILE_OK && !created) { 460 if (rv == base::File::FILE_OK && !created) {
461 callback.Run(base::PLATFORM_FILE_ERROR_EXISTS); 461 callback.Run(base::File::FILE_ERROR_EXISTS);
462 } else { 462 } else {
463 DidFinishOperation(callback, rv); 463 DidFinishOperation(callback, rv);
464 } 464 }
465 } 465 }
466 466
467 void FileSystemOperationImpl::DidEnsureFileExistsNonExclusive( 467 void FileSystemOperationImpl::DidEnsureFileExistsNonExclusive(
468 const StatusCallback& callback, 468 const StatusCallback& callback,
469 base::PlatformFileError rv, bool /* created */) { 469 base::File::Error rv, bool /* created */) {
470 DidFinishOperation(callback, rv); 470 DidFinishOperation(callback, rv);
471 } 471 }
472 472
473 void FileSystemOperationImpl::DidFinishOperation( 473 void FileSystemOperationImpl::DidFinishOperation(
474 const StatusCallback& callback, 474 const StatusCallback& callback,
475 base::PlatformFileError rv) { 475 base::File::Error rv) {
476 if (!cancel_callback_.is_null()) { 476 if (!cancel_callback_.is_null()) {
477 StatusCallback cancel_callback = cancel_callback_; 477 StatusCallback cancel_callback = cancel_callback_;
478 callback.Run(rv); 478 callback.Run(rv);
479 479
480 // Return OK only if we succeeded to stop the operation. 480 // Return OK only if we succeeded to stop the operation.
481 cancel_callback.Run(rv == base::PLATFORM_FILE_ERROR_ABORT ? 481 cancel_callback.Run(rv == base::File::FILE_ERROR_ABORT ?
482 base::PLATFORM_FILE_OK : 482 base::File::FILE_OK :
483 base::PLATFORM_FILE_ERROR_INVALID_OPERATION); 483 base::File::FILE_ERROR_INVALID_OPERATION);
484 } else { 484 } else {
485 callback.Run(rv); 485 callback.Run(rv);
486 } 486 }
487 } 487 }
488 488
489 void FileSystemOperationImpl::DidDirectoryExists( 489 void FileSystemOperationImpl::DidDirectoryExists(
490 const StatusCallback& callback, 490 const StatusCallback& callback,
491 base::PlatformFileError rv, 491 base::File::Error rv,
492 const base::PlatformFileInfo& file_info) { 492 const base::File::Info& file_info) {
493 if (rv == base::PLATFORM_FILE_OK && !file_info.is_directory) 493 if (rv == base::File::FILE_OK && !file_info.is_directory)
494 rv = base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY; 494 rv = base::File::FILE_ERROR_NOT_A_DIRECTORY;
495 callback.Run(rv); 495 callback.Run(rv);
496 } 496 }
497 497
498 void FileSystemOperationImpl::DidFileExists( 498 void FileSystemOperationImpl::DidFileExists(
499 const StatusCallback& callback, 499 const StatusCallback& callback,
500 base::PlatformFileError rv, 500 base::File::Error rv,
501 const base::PlatformFileInfo& file_info) { 501 const base::File::Info& file_info) {
502 if (rv == base::PLATFORM_FILE_OK && file_info.is_directory) 502 if (rv == base::File::FILE_OK && file_info.is_directory)
503 rv = base::PLATFORM_FILE_ERROR_NOT_A_FILE; 503 rv = base::File::FILE_ERROR_NOT_A_FILE;
504 callback.Run(rv); 504 callback.Run(rv);
505 } 505 }
506 506
507 void FileSystemOperationImpl::DidDeleteRecursively( 507 void FileSystemOperationImpl::DidDeleteRecursively(
508 const FileSystemURL& url, 508 const FileSystemURL& url,
509 const StatusCallback& callback, 509 const StatusCallback& callback,
510 base::PlatformFileError rv) { 510 base::File::Error rv) {
511 if (rv == base::PLATFORM_FILE_ERROR_INVALID_OPERATION) { 511 if (rv == base::File::FILE_ERROR_INVALID_OPERATION) {
512 // Recursive removal is not supported on this platform. 512 // Recursive removal is not supported on this platform.
513 DCHECK(!recursive_operation_delegate_); 513 DCHECK(!recursive_operation_delegate_);
514 recursive_operation_delegate_.reset( 514 recursive_operation_delegate_.reset(
515 new RemoveOperationDelegate( 515 new RemoveOperationDelegate(
516 file_system_context(), url, 516 file_system_context(), url,
517 base::Bind(&FileSystemOperationImpl::DidFinishOperation, 517 base::Bind(&FileSystemOperationImpl::DidFinishOperation,
518 weak_factory_.GetWeakPtr(), callback))); 518 weak_factory_.GetWeakPtr(), callback)));
519 recursive_operation_delegate_->RunRecursively(); 519 recursive_operation_delegate_->RunRecursively();
520 return; 520 return;
521 } 521 }
522 522
523 callback.Run(rv); 523 callback.Run(rv);
524 } 524 }
525 525
526 void FileSystemOperationImpl::DidWrite( 526 void FileSystemOperationImpl::DidWrite(
527 const FileSystemURL& url, 527 const FileSystemURL& url,
528 const WriteCallback& write_callback, 528 const WriteCallback& write_callback,
529 base::PlatformFileError rv, 529 base::File::Error rv,
530 int64 bytes, 530 int64 bytes,
531 FileWriterDelegate::WriteProgressStatus write_status) { 531 FileWriterDelegate::WriteProgressStatus write_status) {
532 const bool complete = ( 532 const bool complete = (
533 write_status != FileWriterDelegate::SUCCESS_IO_PENDING); 533 write_status != FileWriterDelegate::SUCCESS_IO_PENDING);
534 if (complete && write_status != FileWriterDelegate::ERROR_WRITE_NOT_STARTED) { 534 if (complete && write_status != FileWriterDelegate::ERROR_WRITE_NOT_STARTED) {
535 DCHECK(operation_context_); 535 DCHECK(operation_context_);
536 operation_context_->change_observers()->Notify( 536 operation_context_->change_observers()->Notify(
537 &FileChangeObserver::OnModifyFile, MakeTuple(url)); 537 &FileChangeObserver::OnModifyFile, MakeTuple(url));
538 } 538 }
539 539
540 StatusCallback cancel_callback = cancel_callback_; 540 StatusCallback cancel_callback = cancel_callback_;
541 write_callback.Run(rv, bytes, complete); 541 write_callback.Run(rv, bytes, complete);
542 if (!cancel_callback.is_null()) 542 if (!cancel_callback.is_null())
543 cancel_callback.Run(base::PLATFORM_FILE_OK); 543 cancel_callback.Run(base::File::FILE_OK);
544 } 544 }
545 545
546 void FileSystemOperationImpl::DidOpenFile( 546 void FileSystemOperationImpl::DidOpenFile(
547 const OpenFileCallback& callback, 547 const OpenFileCallback& callback,
548 base::PlatformFileError rv, 548 base::File::Error rv,
549 base::PassPlatformFile file, 549 base::PassPlatformFile file,
550 const base::Closure& on_close_callback) { 550 const base::Closure& on_close_callback) {
551 callback.Run(rv, file.ReleaseValue(), on_close_callback); 551 callback.Run(rv, file.ReleaseValue(), on_close_callback);
552 } 552 }
553 553
554 bool FileSystemOperationImpl::SetPendingOperationType(OperationType type) { 554 bool FileSystemOperationImpl::SetPendingOperationType(OperationType type) {
555 if (pending_operation_ != kOperationNone) 555 if (pending_operation_ != kOperationNone)
556 return false; 556 return false;
557 pending_operation_ = type; 557 pending_operation_ = type;
558 return true; 558 return true;
559 } 559 }
560 560
561 } // namespace fileapi 561 } // namespace fileapi
OLDNEW
« no previous file with comments | « webkit/browser/fileapi/file_system_operation_impl.h ('k') | webkit/browser/fileapi/file_system_operation_runner.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698