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

Side by Side Diff: minidump/minidump_misc_info_writer_test.cc

Issue 804593002: Move string16 and char16 in to base:: (Closed) Base URL: https://chromium.googlesource.com/crashpad/crashpad@master
Patch Set: include roll of mini_chromium to 37bac7... Created 6 years 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
« no previous file with comments | « compat/non_win/timezoneapi.h ('k') | minidump/minidump_module_writer.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 The Crashpad Authors. All rights reserved. 1 // Copyright 2014 The Crashpad Authors. All rights reserved.
2 // 2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); 3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License. 4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at 5 // You may obtain a copy of the License at
6 // 6 //
7 // http://www.apache.org/licenses/LICENSE-2.0 7 // http://www.apache.org/licenses/LICENSE-2.0
8 // 8 //
9 // Unless required by applicable law or agreed to in writing, software 9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, 10 // distributed under the License is distributed on an "AS IS" BASIS,
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
53 ASSERT_TRUE(directory); 53 ASSERT_TRUE(directory);
54 54
55 ASSERT_EQ(kMinidumpStreamTypeMiscInfo, directory[0].StreamType); 55 ASSERT_EQ(kMinidumpStreamTypeMiscInfo, directory[0].StreamType);
56 EXPECT_EQ(kMiscInfoStreamOffset, directory[0].Location.Rva); 56 EXPECT_EQ(kMiscInfoStreamOffset, directory[0].Location.Rva);
57 57
58 *misc_info = MinidumpWritableAtLocationDescriptor<T>(file_contents, 58 *misc_info = MinidumpWritableAtLocationDescriptor<T>(file_contents,
59 directory[0].Location); 59 directory[0].Location);
60 ASSERT_TRUE(misc_info); 60 ASSERT_TRUE(misc_info);
61 } 61 }
62 62
63 void ExpectNULPaddedString16Equal(const char16* expected, 63 void ExpectNULPaddedString16Equal(const base::char16* expected,
64 const char16* observed, 64 const base::char16* observed,
65 size_t size) { 65 size_t size) {
66 string16 expected_string(expected, size); 66 base::string16 expected_string(expected, size);
67 string16 observed_string(observed, size); 67 base::string16 observed_string(observed, size);
68 EXPECT_EQ(expected_string, observed_string); 68 EXPECT_EQ(expected_string, observed_string);
69 } 69 }
70 70
71 void ExpectSystemTimeEqual(const SYSTEMTIME* expected, 71 void ExpectSystemTimeEqual(const SYSTEMTIME* expected,
72 const SYSTEMTIME* observed) { 72 const SYSTEMTIME* observed) {
73 EXPECT_EQ(expected->wYear, observed->wYear); 73 EXPECT_EQ(expected->wYear, observed->wYear);
74 EXPECT_EQ(expected->wMonth, observed->wMonth); 74 EXPECT_EQ(expected->wMonth, observed->wMonth);
75 EXPECT_EQ(expected->wDayOfWeek, observed->wDayOfWeek); 75 EXPECT_EQ(expected->wDayOfWeek, observed->wDayOfWeek);
76 EXPECT_EQ(expected->wDay, observed->wDay); 76 EXPECT_EQ(expected->wDay, observed->wDay);
77 EXPECT_EQ(expected->wHour, observed->wHour); 77 EXPECT_EQ(expected->wHour, observed->wHour);
(...skipping 277 matching lines...) Expand 10 before | Expand all | Expand 10 after
355 StringFileWriter file_writer; 355 StringFileWriter file_writer;
356 ASSERT_TRUE(minidump_file_writer.WriteEverything(&file_writer)); 356 ASSERT_TRUE(minidump_file_writer.WriteEverything(&file_writer));
357 357
358 const MINIDUMP_MISC_INFO_3* observed; 358 const MINIDUMP_MISC_INFO_3* observed;
359 ASSERT_NO_FATAL_FAILURE(GetMiscInfoStream(file_writer.string(), &observed)); 359 ASSERT_NO_FATAL_FAILURE(GetMiscInfoStream(file_writer.string(), &observed));
360 360
361 MINIDUMP_MISC_INFO_3 expected = {}; 361 MINIDUMP_MISC_INFO_3 expected = {};
362 expected.Flags1 = MINIDUMP_MISC3_TIMEZONE; 362 expected.Flags1 = MINIDUMP_MISC3_TIMEZONE;
363 expected.TimeZoneId = kTimeZoneId; 363 expected.TimeZoneId = kTimeZoneId;
364 expected.TimeZone.Bias = kBias; 364 expected.TimeZone.Bias = kBias;
365 string16 standard_name_utf16 = base::UTF8ToUTF16(kStandardName); 365 base::string16 standard_name_utf16 = base::UTF8ToUTF16(kStandardName);
366 c16lcpy(expected.TimeZone.StandardName, 366 c16lcpy(expected.TimeZone.StandardName,
367 standard_name_utf16.c_str(), 367 standard_name_utf16.c_str(),
368 arraysize(expected.TimeZone.StandardName)); 368 arraysize(expected.TimeZone.StandardName));
369 memcpy(&expected.TimeZone.StandardDate, 369 memcpy(&expected.TimeZone.StandardDate,
370 &kStandardDate, 370 &kStandardDate,
371 sizeof(expected.TimeZone.StandardDate)); 371 sizeof(expected.TimeZone.StandardDate));
372 expected.TimeZone.StandardBias = kStandardBias; 372 expected.TimeZone.StandardBias = kStandardBias;
373 string16 daylight_name_utf16 = base::UTF8ToUTF16(kDaylightName); 373 base::string16 daylight_name_utf16 = base::UTF8ToUTF16(kDaylightName);
374 c16lcpy(expected.TimeZone.DaylightName, 374 c16lcpy(expected.TimeZone.DaylightName,
375 daylight_name_utf16.c_str(), 375 daylight_name_utf16.c_str(),
376 arraysize(expected.TimeZone.DaylightName)); 376 arraysize(expected.TimeZone.DaylightName));
377 memcpy(&expected.TimeZone.DaylightDate, 377 memcpy(&expected.TimeZone.DaylightDate,
378 &kDaylightDate, 378 &kDaylightDate,
379 sizeof(expected.TimeZone.DaylightDate)); 379 sizeof(expected.TimeZone.DaylightDate));
380 expected.TimeZone.DaylightBias = kDaylightBias; 380 expected.TimeZone.DaylightBias = kDaylightBias;
381 381
382 ExpectMiscInfoEqual(&expected, observed); 382 ExpectMiscInfoEqual(&expected, observed);
383 } 383 }
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
417 StringFileWriter file_writer; 417 StringFileWriter file_writer;
418 ASSERT_TRUE(minidump_file_writer.WriteEverything(&file_writer)); 418 ASSERT_TRUE(minidump_file_writer.WriteEverything(&file_writer));
419 419
420 const MINIDUMP_MISC_INFO_3* observed; 420 const MINIDUMP_MISC_INFO_3* observed;
421 ASSERT_NO_FATAL_FAILURE(GetMiscInfoStream(file_writer.string(), &observed)); 421 ASSERT_NO_FATAL_FAILURE(GetMiscInfoStream(file_writer.string(), &observed));
422 422
423 MINIDUMP_MISC_INFO_3 expected = {}; 423 MINIDUMP_MISC_INFO_3 expected = {};
424 expected.Flags1 = MINIDUMP_MISC3_TIMEZONE; 424 expected.Flags1 = MINIDUMP_MISC3_TIMEZONE;
425 expected.TimeZoneId = kTimeZoneId; 425 expected.TimeZoneId = kTimeZoneId;
426 expected.TimeZone.Bias = kBias; 426 expected.TimeZone.Bias = kBias;
427 string16 standard_name_utf16 = base::UTF8ToUTF16(standard_name); 427 base::string16 standard_name_utf16 = base::UTF8ToUTF16(standard_name);
428 c16lcpy(expected.TimeZone.StandardName, 428 c16lcpy(expected.TimeZone.StandardName,
429 standard_name_utf16.c_str(), 429 standard_name_utf16.c_str(),
430 arraysize(expected.TimeZone.StandardName)); 430 arraysize(expected.TimeZone.StandardName));
431 memcpy(&expected.TimeZone.StandardDate, 431 memcpy(&expected.TimeZone.StandardDate,
432 &kSystemTimeZero, 432 &kSystemTimeZero,
433 sizeof(expected.TimeZone.StandardDate)); 433 sizeof(expected.TimeZone.StandardDate));
434 expected.TimeZone.StandardBias = kStandardBias; 434 expected.TimeZone.StandardBias = kStandardBias;
435 string16 daylight_name_utf16 = base::UTF8ToUTF16(daylight_name); 435 base::string16 daylight_name_utf16 = base::UTF8ToUTF16(daylight_name);
436 c16lcpy(expected.TimeZone.DaylightName, 436 c16lcpy(expected.TimeZone.DaylightName,
437 daylight_name_utf16.c_str(), 437 daylight_name_utf16.c_str(),
438 arraysize(expected.TimeZone.DaylightName)); 438 arraysize(expected.TimeZone.DaylightName));
439 memcpy(&expected.TimeZone.DaylightDate, 439 memcpy(&expected.TimeZone.DaylightDate,
440 &kSystemTimeZero, 440 &kSystemTimeZero,
441 sizeof(expected.TimeZone.DaylightDate)); 441 sizeof(expected.TimeZone.DaylightDate));
442 expected.TimeZone.DaylightBias = kDaylightBias; 442 expected.TimeZone.DaylightBias = kDaylightBias;
443 443
444 ExpectMiscInfoEqual(&expected, observed); 444 ExpectMiscInfoEqual(&expected, observed);
445 } 445 }
(...skipping 10 matching lines...) Expand all
456 minidump_file_writer.AddStream(misc_info_writer.Pass()); 456 minidump_file_writer.AddStream(misc_info_writer.Pass());
457 457
458 StringFileWriter file_writer; 458 StringFileWriter file_writer;
459 ASSERT_TRUE(minidump_file_writer.WriteEverything(&file_writer)); 459 ASSERT_TRUE(minidump_file_writer.WriteEverything(&file_writer));
460 460
461 const MINIDUMP_MISC_INFO_4* observed; 461 const MINIDUMP_MISC_INFO_4* observed;
462 ASSERT_NO_FATAL_FAILURE(GetMiscInfoStream(file_writer.string(), &observed)); 462 ASSERT_NO_FATAL_FAILURE(GetMiscInfoStream(file_writer.string(), &observed));
463 463
464 MINIDUMP_MISC_INFO_4 expected = {}; 464 MINIDUMP_MISC_INFO_4 expected = {};
465 expected.Flags1 = MINIDUMP_MISC4_BUILDSTRING; 465 expected.Flags1 = MINIDUMP_MISC4_BUILDSTRING;
466 string16 build_string_utf16 = base::UTF8ToUTF16(kBuildString); 466 base::string16 build_string_utf16 = base::UTF8ToUTF16(kBuildString);
467 c16lcpy(expected.BuildString, 467 c16lcpy(expected.BuildString,
468 build_string_utf16.c_str(), 468 build_string_utf16.c_str(),
469 arraysize(expected.BuildString)); 469 arraysize(expected.BuildString));
470 string16 debug_build_string_utf16 = base::UTF8ToUTF16(kDebugBuildString); 470 base::string16 debug_build_string_utf16 =
471 base::UTF8ToUTF16(kDebugBuildString);
471 c16lcpy(expected.DbgBldStr, 472 c16lcpy(expected.DbgBldStr,
472 debug_build_string_utf16.c_str(), 473 debug_build_string_utf16.c_str(),
473 arraysize(expected.DbgBldStr)); 474 arraysize(expected.DbgBldStr));
474 475
475 ExpectMiscInfoEqual(&expected, observed); 476 ExpectMiscInfoEqual(&expected, observed);
476 } 477 }
477 478
478 TEST(MinidumpMiscInfoWriter, BuildStringsOverflow) { 479 TEST(MinidumpMiscInfoWriter, BuildStringsOverflow) {
479 // This test makes sure that the build strings are truncated properly to the 480 // This test makes sure that the build strings are truncated properly to the
480 // widths of their fields. 481 // widths of their fields.
(...skipping 11 matching lines...) Expand all
492 minidump_file_writer.AddStream(misc_info_writer.Pass()); 493 minidump_file_writer.AddStream(misc_info_writer.Pass());
493 494
494 StringFileWriter file_writer; 495 StringFileWriter file_writer;
495 ASSERT_TRUE(minidump_file_writer.WriteEverything(&file_writer)); 496 ASSERT_TRUE(minidump_file_writer.WriteEverything(&file_writer));
496 497
497 const MINIDUMP_MISC_INFO_4* observed; 498 const MINIDUMP_MISC_INFO_4* observed;
498 ASSERT_NO_FATAL_FAILURE(GetMiscInfoStream(file_writer.string(), &observed)); 499 ASSERT_NO_FATAL_FAILURE(GetMiscInfoStream(file_writer.string(), &observed));
499 500
500 MINIDUMP_MISC_INFO_4 expected = {}; 501 MINIDUMP_MISC_INFO_4 expected = {};
501 expected.Flags1 = MINIDUMP_MISC4_BUILDSTRING; 502 expected.Flags1 = MINIDUMP_MISC4_BUILDSTRING;
502 string16 build_string_utf16 = base::UTF8ToUTF16(build_string); 503 base::string16 build_string_utf16 = base::UTF8ToUTF16(build_string);
503 c16lcpy(expected.BuildString, 504 c16lcpy(expected.BuildString,
504 build_string_utf16.c_str(), 505 build_string_utf16.c_str(),
505 arraysize(expected.BuildString)); 506 arraysize(expected.BuildString));
506 string16 debug_build_string_utf16 = base::UTF8ToUTF16(debug_build_string); 507 base::string16 debug_build_string_utf16 =
508 base::UTF8ToUTF16(debug_build_string);
507 c16lcpy(expected.DbgBldStr, 509 c16lcpy(expected.DbgBldStr,
508 debug_build_string_utf16.c_str(), 510 debug_build_string_utf16.c_str(),
509 arraysize(expected.DbgBldStr)); 511 arraysize(expected.DbgBldStr));
510 512
511 ExpectMiscInfoEqual(&expected, observed); 513 ExpectMiscInfoEqual(&expected, observed);
512 } 514 }
513 515
514 TEST(MinidumpMiscInfoWriter, Everything) { 516 TEST(MinidumpMiscInfoWriter, Everything) {
515 MinidumpFileWriter minidump_file_writer; 517 MinidumpFileWriter minidump_file_writer;
516 auto misc_info_writer = make_scoped_ptr(new MinidumpMiscInfoWriter()); 518 auto misc_info_writer = make_scoped_ptr(new MinidumpMiscInfoWriter());
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
579 expected.ProcessorMaxMhz = kProcessorMaxMhz; 581 expected.ProcessorMaxMhz = kProcessorMaxMhz;
580 expected.ProcessorCurrentMhz = kProcessorCurrentMhz; 582 expected.ProcessorCurrentMhz = kProcessorCurrentMhz;
581 expected.ProcessorMhzLimit = kProcessorMhzLimit; 583 expected.ProcessorMhzLimit = kProcessorMhzLimit;
582 expected.ProcessorMaxIdleState = kProcessorMaxIdleState; 584 expected.ProcessorMaxIdleState = kProcessorMaxIdleState;
583 expected.ProcessorCurrentIdleState = kProcessorCurrentIdleState; 585 expected.ProcessorCurrentIdleState = kProcessorCurrentIdleState;
584 expected.ProcessIntegrityLevel = kProcessIntegrityLevel; 586 expected.ProcessIntegrityLevel = kProcessIntegrityLevel;
585 expected.ProcessExecuteFlags = kProcessExecuteFlags; 587 expected.ProcessExecuteFlags = kProcessExecuteFlags;
586 expected.ProtectedProcess = kProtectedProcess; 588 expected.ProtectedProcess = kProtectedProcess;
587 expected.TimeZoneId = kTimeZoneId; 589 expected.TimeZoneId = kTimeZoneId;
588 expected.TimeZone.Bias = kBias; 590 expected.TimeZone.Bias = kBias;
589 string16 standard_name_utf16 = base::UTF8ToUTF16(kStandardName); 591 base::string16 standard_name_utf16 = base::UTF8ToUTF16(kStandardName);
590 c16lcpy(expected.TimeZone.StandardName, 592 c16lcpy(expected.TimeZone.StandardName,
591 standard_name_utf16.c_str(), 593 standard_name_utf16.c_str(),
592 arraysize(expected.TimeZone.StandardName)); 594 arraysize(expected.TimeZone.StandardName));
593 memcpy(&expected.TimeZone.StandardDate, 595 memcpy(&expected.TimeZone.StandardDate,
594 &kSystemTimeZero, 596 &kSystemTimeZero,
595 sizeof(expected.TimeZone.StandardDate)); 597 sizeof(expected.TimeZone.StandardDate));
596 expected.TimeZone.StandardBias = kStandardBias; 598 expected.TimeZone.StandardBias = kStandardBias;
597 string16 daylight_name_utf16 = base::UTF8ToUTF16(kDaylightName); 599 base::string16 daylight_name_utf16 = base::UTF8ToUTF16(kDaylightName);
598 c16lcpy(expected.TimeZone.DaylightName, 600 c16lcpy(expected.TimeZone.DaylightName,
599 daylight_name_utf16.c_str(), 601 daylight_name_utf16.c_str(),
600 arraysize(expected.TimeZone.DaylightName)); 602 arraysize(expected.TimeZone.DaylightName));
601 memcpy(&expected.TimeZone.DaylightDate, 603 memcpy(&expected.TimeZone.DaylightDate,
602 &kSystemTimeZero, 604 &kSystemTimeZero,
603 sizeof(expected.TimeZone.DaylightDate)); 605 sizeof(expected.TimeZone.DaylightDate));
604 expected.TimeZone.DaylightBias = kDaylightBias; 606 expected.TimeZone.DaylightBias = kDaylightBias;
605 string16 build_string_utf16 = base::UTF8ToUTF16(kBuildString); 607 base::string16 build_string_utf16 = base::UTF8ToUTF16(kBuildString);
606 c16lcpy(expected.BuildString, 608 c16lcpy(expected.BuildString,
607 build_string_utf16.c_str(), 609 build_string_utf16.c_str(),
608 arraysize(expected.BuildString)); 610 arraysize(expected.BuildString));
609 string16 debug_build_string_utf16 = base::UTF8ToUTF16(kDebugBuildString); 611 base::string16 debug_build_string_utf16 =
612 base::UTF8ToUTF16(kDebugBuildString);
610 c16lcpy(expected.DbgBldStr, 613 c16lcpy(expected.DbgBldStr,
611 debug_build_string_utf16.c_str(), 614 debug_build_string_utf16.c_str(),
612 arraysize(expected.DbgBldStr)); 615 arraysize(expected.DbgBldStr));
613 616
614 ExpectMiscInfoEqual(&expected, observed); 617 ExpectMiscInfoEqual(&expected, observed);
615 } 618 }
616 619
617 TEST(MinidumpMiscInfoWriter, InitializeFromSnapshot) { 620 TEST(MinidumpMiscInfoWriter, InitializeFromSnapshot) {
618 MINIDUMP_MISC_INFO_4 expect_misc_info = {}; 621 MINIDUMP_MISC_INFO_4 expect_misc_info = {};
619 622
620 const char kStandardTimeName[] = "EST"; 623 const char kStandardTimeName[] = "EST";
621 const char kDaylightTimeName[] = "EDT"; 624 const char kDaylightTimeName[] = "EDT";
622 const char kOSVersionFull[] = 625 const char kOSVersionFull[] =
623 "Mac OS X 10.9.5 (13F34); " 626 "Mac OS X 10.9.5 (13F34); "
624 "Darwin 13.4.0 Darwin Kernel Version 13.4.0: " 627 "Darwin 13.4.0 Darwin Kernel Version 13.4.0: "
625 "Sun Aug 17 19:50:11 PDT 2014; " 628 "Sun Aug 17 19:50:11 PDT 2014; "
626 "root:xnu-2422.115.4~1/RELEASE_X86_64 x86_64"; 629 "root:xnu-2422.115.4~1/RELEASE_X86_64 x86_64";
627 const char kMachineDescription[] = "MacBookPro11,3 (Mac-2BD1B31983FE1663)"; 630 const char kMachineDescription[] = "MacBookPro11,3 (Mac-2BD1B31983FE1663)";
628 string16 standard_time_name_utf16 = base::UTF8ToUTF16(kStandardTimeName); 631 base::string16 standard_time_name_utf16 =
629 string16 daylight_time_name_utf16 = base::UTF8ToUTF16(kDaylightTimeName); 632 base::UTF8ToUTF16(kStandardTimeName);
630 string16 build_string_utf16 = base::UTF8ToUTF16( 633 base::string16 daylight_time_name_utf16 =
634 base::UTF8ToUTF16(kDaylightTimeName);
635 base::string16 build_string_utf16 = base::UTF8ToUTF16(
631 std::string(kOSVersionFull) + "; " + kMachineDescription); 636 std::string(kOSVersionFull) + "; " + kMachineDescription);
632 std::string debug_build_string = internal::MinidumpMiscInfoDebugBuildString(); 637 std::string debug_build_string = internal::MinidumpMiscInfoDebugBuildString();
633 EXPECT_FALSE(debug_build_string.empty()); 638 EXPECT_FALSE(debug_build_string.empty());
634 string16 debug_build_string_utf16 = base::UTF8ToUTF16(debug_build_string); 639 base::string16 debug_build_string_utf16 =
640 base::UTF8ToUTF16(debug_build_string);
635 641
636 expect_misc_info.SizeOfInfo = sizeof(expect_misc_info); 642 expect_misc_info.SizeOfInfo = sizeof(expect_misc_info);
637 expect_misc_info.Flags1 = MINIDUMP_MISC1_PROCESS_ID | 643 expect_misc_info.Flags1 = MINIDUMP_MISC1_PROCESS_ID |
638 MINIDUMP_MISC1_PROCESS_TIMES | 644 MINIDUMP_MISC1_PROCESS_TIMES |
639 MINIDUMP_MISC1_PROCESSOR_POWER_INFO | 645 MINIDUMP_MISC1_PROCESSOR_POWER_INFO |
640 MINIDUMP_MISC3_TIMEZONE | 646 MINIDUMP_MISC3_TIMEZONE |
641 MINIDUMP_MISC4_BUILDSTRING; 647 MINIDUMP_MISC4_BUILDSTRING;
642 expect_misc_info.ProcessId = 12345; 648 expect_misc_info.ProcessId = 12345;
643 expect_misc_info.ProcessCreateTime = 0x555c7740; 649 expect_misc_info.ProcessCreateTime = 0x555c7740;
644 expect_misc_info.ProcessUserTime = 60; 650 expect_misc_info.ProcessUserTime = 60;
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
701 707
702 const MINIDUMP_MISC_INFO_4* misc_info; 708 const MINIDUMP_MISC_INFO_4* misc_info;
703 ASSERT_NO_FATAL_FAILURE(GetMiscInfoStream(file_writer.string(), &misc_info)); 709 ASSERT_NO_FATAL_FAILURE(GetMiscInfoStream(file_writer.string(), &misc_info));
704 710
705 ExpectMiscInfoEqual(&expect_misc_info, misc_info); 711 ExpectMiscInfoEqual(&expect_misc_info, misc_info);
706 } 712 }
707 713
708 } // namespace 714 } // namespace
709 } // namespace test 715 } // namespace test
710 } // namespace crashpad 716 } // namespace crashpad
OLDNEW
« no previous file with comments | « compat/non_win/timezoneapi.h ('k') | minidump/minidump_module_writer.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698