| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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 <limits.h> | 5 #include <limits.h> |
| 6 #include <stdio.h> | 6 #include <stdio.h> |
| 7 #include <stdlib.h> | 7 #include <stdlib.h> |
| 8 #include <string.h> | 8 #include <string.h> |
| 9 | 9 |
| 10 #include <list> | |
| 11 #include <sstream> | 10 #include <sstream> |
| 12 #include <string> | 11 #include <string> |
| 13 #include <utility> | 12 #include <utility> |
| 14 #include <vector> | 13 #include <vector> |
| 15 | 14 |
| 16 #if defined PDF_ENABLE_SKIA && !defined _SKIA_SUPPORT_ | 15 #if defined PDF_ENABLE_SKIA && !defined _SKIA_SUPPORT_ |
| 17 #define _SKIA_SUPPORT_ | 16 #define _SKIA_SUPPORT_ |
| 18 #endif | 17 #endif |
| 19 | 18 |
| 20 #include "public/fpdf_dataavail.h" | 19 #include "public/fpdf_dataavail.h" |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 88 out_len *= 3; | 87 out_len *= 3; |
| 89 | 88 |
| 90 char filename[256]; | 89 char filename[256]; |
| 91 snprintf(filename, sizeof(filename), "%s.%d.ppm", pdf_name, num); | 90 snprintf(filename, sizeof(filename), "%s.%d.ppm", pdf_name, num); |
| 92 FILE* fp = fopen(filename, "wb"); | 91 FILE* fp = fopen(filename, "wb"); |
| 93 if (!fp) | 92 if (!fp) |
| 94 return; | 93 return; |
| 95 fprintf(fp, "P6\n# PDF test render\n%d %d\n255\n", width, height); | 94 fprintf(fp, "P6\n# PDF test render\n%d %d\n255\n", width, height); |
| 96 // Source data is B, G, R, unused. | 95 // Source data is B, G, R, unused. |
| 97 // Dest data is R, G, B. | 96 // Dest data is R, G, B. |
| 98 char* result = new char[out_len]; | 97 std::vector<char> result(out_len); |
| 99 for (int h = 0; h < height; ++h) { | 98 for (int h = 0; h < height; ++h) { |
| 100 const char* src_line = buffer + (stride * h); | 99 const char* src_line = buffer + (stride * h); |
| 101 char* dest_line = result + (width * h * 3); | 100 char* dest_line = result.data() + (width * h * 3); |
| 102 for (int w = 0; w < width; ++w) { | 101 for (int w = 0; w < width; ++w) { |
| 103 // R | 102 // R |
| 104 dest_line[w * 3] = src_line[(w * 4) + 2]; | 103 dest_line[w * 3] = src_line[(w * 4) + 2]; |
| 105 // G | 104 // G |
| 106 dest_line[(w * 3) + 1] = src_line[(w * 4) + 1]; | 105 dest_line[(w * 3) + 1] = src_line[(w * 4) + 1]; |
| 107 // B | 106 // B |
| 108 dest_line[(w * 3) + 2] = src_line[w * 4]; | 107 dest_line[(w * 3) + 2] = src_line[w * 4]; |
| 109 } | 108 } |
| 110 } | 109 } |
| 111 fwrite(result, out_len, 1, fp); | 110 fwrite(result.data(), out_len, 1, fp); |
| 112 delete[] result; | |
| 113 fclose(fp); | 111 fclose(fp); |
| 114 } | 112 } |
| 115 | 113 |
| 116 void WriteText(FPDF_PAGE page, const char* pdf_name, int num) { | 114 void WriteText(FPDF_PAGE page, const char* pdf_name, int num) { |
| 117 char filename[256]; | 115 char filename[256]; |
| 118 int chars_formatted = | 116 int chars_formatted = |
| 119 snprintf(filename, sizeof(filename), "%s.%d.txt", pdf_name, num); | 117 snprintf(filename, sizeof(filename), "%s.%d.txt", pdf_name, num); |
| 120 if (chars_formatted < 0 || | 118 if (chars_formatted < 0 || |
| 121 static_cast<size_t>(chars_formatted) >= sizeof(filename)) { | 119 static_cast<size_t>(chars_formatted) >= sizeof(filename)) { |
| 122 fprintf(stderr, "Filename %s is too long\n", filename); | 120 fprintf(stderr, "Filename %s is too long\n", filename); |
| (...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 355 feature = "Screen"; | 353 feature = "Screen"; |
| 356 break; | 354 break; |
| 357 case FPDF_UNSP_ANNOT_SIG: | 355 case FPDF_UNSP_ANNOT_SIG: |
| 358 feature = "Digital_Signature"; | 356 feature = "Digital_Signature"; |
| 359 break; | 357 break; |
| 360 } | 358 } |
| 361 printf("Unsupported feature: %s.\n", feature.c_str()); | 359 printf("Unsupported feature: %s.\n", feature.c_str()); |
| 362 } | 360 } |
| 363 | 361 |
| 364 bool ParseCommandLine(const std::vector<std::string>& args, | 362 bool ParseCommandLine(const std::vector<std::string>& args, |
| 365 Options* options, std::list<std::string>* files) { | 363 Options* options, |
| 366 if (args.empty()) { | 364 std::vector<std::string>* files) { |
| 365 if (args.empty()) |
| 367 return false; | 366 return false; |
| 368 } | 367 |
| 369 options->exe_path = args[0]; | 368 options->exe_path = args[0]; |
| 370 size_t cur_idx = 1; | 369 size_t cur_idx = 1; |
| 371 for (; cur_idx < args.size(); ++cur_idx) { | 370 for (; cur_idx < args.size(); ++cur_idx) { |
| 372 const std::string& cur_arg = args[cur_idx]; | 371 const std::string& cur_arg = args[cur_idx]; |
| 373 if (cur_arg == "--show-config") { | 372 if (cur_arg == "--show-config") { |
| 374 options->show_config = true; | 373 options->show_config = true; |
| 375 } else if (cur_arg == "--send-events") { | 374 } else if (cur_arg == "--send-events") { |
| 376 options->send_events = true; | 375 options->send_events = true; |
| 377 } else if (cur_arg == "--ppm") { | 376 } else if (cur_arg == "--ppm") { |
| 378 if (options->output_format != OUTPUT_NONE) { | 377 if (options->output_format != OUTPUT_NONE) { |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 440 return false; | 439 return false; |
| 441 } | 440 } |
| 442 options->scale_factor_as_string = cur_arg.substr(8); | 441 options->scale_factor_as_string = cur_arg.substr(8); |
| 443 } else if (cur_arg.size() >= 2 && cur_arg[0] == '-' && cur_arg[1] == '-') { | 442 } else if (cur_arg.size() >= 2 && cur_arg[0] == '-' && cur_arg[1] == '-') { |
| 444 fprintf(stderr, "Unrecognized argument %s\n", cur_arg.c_str()); | 443 fprintf(stderr, "Unrecognized argument %s\n", cur_arg.c_str()); |
| 445 return false; | 444 return false; |
| 446 } else { | 445 } else { |
| 447 break; | 446 break; |
| 448 } | 447 } |
| 449 } | 448 } |
| 450 for (size_t i = cur_idx; i < args.size(); i++) { | 449 for (size_t i = cur_idx; i < args.size(); i++) |
| 451 files->push_back(args[i]); | 450 files->push_back(args[i]); |
| 452 } | 451 |
| 453 return true; | 452 return true; |
| 454 } | 453 } |
| 455 | 454 |
| 456 FPDF_BOOL Is_Data_Avail(FX_FILEAVAIL* pThis, size_t offset, size_t size) { | 455 FPDF_BOOL Is_Data_Avail(FX_FILEAVAIL* pThis, size_t offset, size_t size) { |
| 457 return true; | 456 return true; |
| 458 } | 457 } |
| 459 | 458 |
| 460 void Add_Segment(FX_DOWNLOADHINTS* pThis, size_t offset, size_t size) { | 459 void Add_Segment(FX_DOWNLOADHINTS* pThis, size_t offset, size_t size) { |
| 461 } | 460 } |
| 462 | 461 |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 521 } | 520 } |
| 522 } | 521 } |
| 523 | 522 |
| 524 bool RenderPage(const std::string& name, | 523 bool RenderPage(const std::string& name, |
| 525 const FPDF_DOCUMENT& doc, | 524 const FPDF_DOCUMENT& doc, |
| 526 const FPDF_FORMHANDLE& form, | 525 const FPDF_FORMHANDLE& form, |
| 527 const int page_index, | 526 const int page_index, |
| 528 const Options& options, | 527 const Options& options, |
| 529 const std::string& events) { | 528 const std::string& events) { |
| 530 FPDF_PAGE page = FPDF_LoadPage(doc, page_index); | 529 FPDF_PAGE page = FPDF_LoadPage(doc, page_index); |
| 531 if (!page) { | 530 if (!page) |
| 532 return false; | 531 return false; |
| 533 } | 532 |
| 534 FPDF_TEXTPAGE text_page = FPDFText_LoadPage(page); | 533 FPDF_TEXTPAGE text_page = FPDFText_LoadPage(page); |
| 535 FORM_OnAfterLoadPage(page, form); | 534 FORM_OnAfterLoadPage(page, form); |
| 536 FORM_DoPageAAction(page, form, FPDFPAGE_AACTION_OPEN); | 535 FORM_DoPageAAction(page, form, FPDFPAGE_AACTION_OPEN); |
| 537 | 536 |
| 538 if (options.send_events) | 537 if (options.send_events) |
| 539 SendPageEvents(form, page, events); | 538 SendPageEvents(form, page, events); |
| 540 | 539 |
| 541 double scale = 1.0; | 540 double scale = 1.0; |
| 542 if (!options.scale_factor_as_string.empty()) { | 541 if (!options.scale_factor_as_string.empty()) |
| 543 std::stringstream(options.scale_factor_as_string) >> scale; | 542 std::stringstream(options.scale_factor_as_string) >> scale; |
| 544 } | 543 |
| 545 int width = static_cast<int>(FPDF_GetPageWidth(page) * scale); | 544 int width = static_cast<int>(FPDF_GetPageWidth(page) * scale); |
| 546 int height = static_cast<int>(FPDF_GetPageHeight(page) * scale); | 545 int height = static_cast<int>(FPDF_GetPageHeight(page) * scale); |
| 547 int alpha = FPDFPage_HasTransparency(page) ? 1 : 0; | 546 int alpha = FPDFPage_HasTransparency(page) ? 1 : 0; |
| 548 FPDF_BITMAP bitmap = FPDFBitmap_Create(width, height, alpha); | 547 FPDF_BITMAP bitmap = FPDFBitmap_Create(width, height, alpha); |
| 549 if (bitmap) { | 548 if (bitmap) { |
| 550 FPDF_DWORD fill_color = alpha ? 0x00000000 : 0xFFFFFFFF; | 549 FPDF_DWORD fill_color = alpha ? 0x00000000 : 0xFFFFFFFF; |
| 551 FPDFBitmap_FillRect(bitmap, 0, 0, width, height, fill_color); | 550 FPDFBitmap_FillRect(bitmap, 0, 0, width, height, fill_color); |
| 552 FPDF_RenderPageBitmap(bitmap, page, 0, 0, width, height, 0, 0); | 551 FPDF_RenderPageBitmap(bitmap, page, 0, 0, width, height, 0, 0); |
| 553 | 552 |
| 554 FPDF_FFLDraw(form, bitmap, page, 0, 0, width, height, 0, 0); | 553 FPDF_FFLDraw(form, bitmap, page, 0, 0, width, height, 0, 0); |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 641 hints.AddSegment = Add_Segment; | 640 hints.AddSegment = Add_Segment; |
| 642 | 641 |
| 643 FPDF_DOCUMENT doc; | 642 FPDF_DOCUMENT doc; |
| 644 int nRet = PDF_DATA_NOTAVAIL; | 643 int nRet = PDF_DATA_NOTAVAIL; |
| 645 bool bIsLinearized = false; | 644 bool bIsLinearized = false; |
| 646 FPDF_AVAIL pdf_avail = FPDFAvail_Create(&file_avail, &file_access); | 645 FPDF_AVAIL pdf_avail = FPDFAvail_Create(&file_avail, &file_access); |
| 647 | 646 |
| 648 if (FPDFAvail_IsLinearized(pdf_avail) == PDF_LINEARIZED) { | 647 if (FPDFAvail_IsLinearized(pdf_avail) == PDF_LINEARIZED) { |
| 649 doc = FPDFAvail_GetDocument(pdf_avail, nullptr); | 648 doc = FPDFAvail_GetDocument(pdf_avail, nullptr); |
| 650 if (doc) { | 649 if (doc) { |
| 651 while (nRet == PDF_DATA_NOTAVAIL) { | 650 while (nRet == PDF_DATA_NOTAVAIL) |
| 652 nRet = FPDFAvail_IsDocAvail(pdf_avail, &hints); | 651 nRet = FPDFAvail_IsDocAvail(pdf_avail, &hints); |
| 653 } | 652 |
| 654 if (nRet == PDF_DATA_ERROR) { | 653 if (nRet == PDF_DATA_ERROR) { |
| 655 fprintf(stderr, "Unknown error in checking if doc was available.\n"); | 654 fprintf(stderr, "Unknown error in checking if doc was available.\n"); |
| 656 return; | 655 return; |
| 657 } | 656 } |
| 658 nRet = FPDFAvail_IsFormAvail(pdf_avail, &hints); | 657 nRet = FPDFAvail_IsFormAvail(pdf_avail, &hints); |
| 659 if (nRet == PDF_FORM_ERROR || nRet == PDF_FORM_NOTAVAIL) { | 658 if (nRet == PDF_FORM_ERROR || nRet == PDF_FORM_NOTAVAIL) { |
| 660 fprintf(stderr, | 659 fprintf(stderr, |
| 661 "Error %d was returned in checking if form was available.\n", | 660 "Error %d was returned in checking if form was available.\n", |
| 662 nRet); | 661 nRet); |
| 663 return; | 662 return; |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 717 | 716 |
| 718 FORM_DoDocumentJSAction(form); | 717 FORM_DoDocumentJSAction(form); |
| 719 FORM_DoDocumentOpenAction(form); | 718 FORM_DoDocumentOpenAction(form); |
| 720 | 719 |
| 721 int page_count = FPDF_GetPageCount(doc); | 720 int page_count = FPDF_GetPageCount(doc); |
| 722 int rendered_pages = 0; | 721 int rendered_pages = 0; |
| 723 int bad_pages = 0; | 722 int bad_pages = 0; |
| 724 for (int i = 0; i < page_count; ++i) { | 723 for (int i = 0; i < page_count; ++i) { |
| 725 if (bIsLinearized) { | 724 if (bIsLinearized) { |
| 726 nRet = PDF_DATA_NOTAVAIL; | 725 nRet = PDF_DATA_NOTAVAIL; |
| 727 while (nRet == PDF_DATA_NOTAVAIL) { | 726 while (nRet == PDF_DATA_NOTAVAIL) |
| 728 nRet = FPDFAvail_IsPageAvail(pdf_avail, i, &hints); | 727 nRet = FPDFAvail_IsPageAvail(pdf_avail, i, &hints); |
| 729 } | 728 |
| 730 if (nRet == PDF_DATA_ERROR) { | 729 if (nRet == PDF_DATA_ERROR) { |
| 731 fprintf(stderr, "Unknown error in checking if page %d is available.\n", | 730 fprintf(stderr, "Unknown error in checking if page %d is available.\n", |
| 732 i); | 731 i); |
| 733 return; | 732 return; |
| 734 } | 733 } |
| 735 } | 734 } |
| 736 if (RenderPage(name, doc, form, i, options, events)) { | 735 if (RenderPage(name, doc, form, i, options, events)) |
| 737 ++rendered_pages; | 736 ++rendered_pages; |
| 738 } else { | 737 else |
| 739 ++bad_pages; | 738 ++bad_pages; |
| 740 } | |
| 741 } | 739 } |
| 742 | 740 |
| 743 FORM_DoDocumentAAction(form, FPDFDOC_AACTION_WC); | 741 FORM_DoDocumentAAction(form, FPDFDOC_AACTION_WC); |
| 744 | 742 |
| 745 #ifdef PDF_ENABLE_XFA | 743 #ifdef PDF_ENABLE_XFA |
| 746 // Note: The shut down order here is the reverse of the non-XFA branch order. | 744 // Note: The shut down order here is the reverse of the non-XFA branch order. |
| 747 // Need to work out if this is required, and if it is, the lifetimes of | 745 // Need to work out if this is required, and if it is, the lifetimes of |
| 748 // objects owned by |doc| that |form| reference. | 746 // objects owned by |doc| that |form| reference. |
| 749 FPDF_CloseDocument(doc); | 747 FPDF_CloseDocument(doc); |
| 750 FPDFDOC_ExitFormFillEnvironment(form); | 748 FPDFDOC_ExitFormFillEnvironment(form); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 774 maybe_comma = ","; | 772 maybe_comma = ","; |
| 775 #endif // V8_USE_EXTERNAL_STARTUP_DATA | 773 #endif // V8_USE_EXTERNAL_STARTUP_DATA |
| 776 #ifdef PDF_ENABLE_XFA | 774 #ifdef PDF_ENABLE_XFA |
| 777 config.append(maybe_comma); | 775 config.append(maybe_comma); |
| 778 config.append("XFA"); | 776 config.append("XFA"); |
| 779 maybe_comma = ","; | 777 maybe_comma = ","; |
| 780 #endif // PDF_ENABLE_XFA | 778 #endif // PDF_ENABLE_XFA |
| 781 printf("%s\n", config.c_str()); | 779 printf("%s\n", config.c_str()); |
| 782 } | 780 } |
| 783 | 781 |
| 784 static const char usage_string[] = | 782 static const char kUsageString[] = |
| 785 "Usage: pdfium_test [OPTION] [FILE]...\n" | 783 "Usage: pdfium_test [OPTION] [FILE]...\n" |
| 786 " --show-config - print build options and exit\n" | 784 " --show-config - print build options and exit\n" |
| 787 " --send-events - send input described by .evt file\n" | 785 " --send-events - send input described by .evt file\n" |
| 788 " --bin-dir=<path> - override path to v8 external data\n" | 786 " --bin-dir=<path> - override path to v8 external data\n" |
| 789 " --font-dir=<path> - override path to external fonts\n" | 787 " --font-dir=<path> - override path to external fonts\n" |
| 790 " --scale=<number> - scale output size by number (e.g. 0.5)\n" | 788 " --scale=<number> - scale output size by number (e.g. 0.5)\n" |
| 791 " --txt - write page text in UTF32-LE <pdf-name>.<page-number>.txt\n" | |
| 792 #ifdef _WIN32 | 789 #ifdef _WIN32 |
| 793 " --bmp - write page images <pdf-name>.<page-number>.bmp\n" | 790 " --bmp - write page images <pdf-name>.<page-number>.bmp\n" |
| 794 " --emf - write page meta files <pdf-name>.<page-number>.emf\n" | 791 " --emf - write page meta files <pdf-name>.<page-number>.emf\n" |
| 795 #endif // _WIN32 | 792 #endif // _WIN32 |
| 793 " --txt - write page text in UTF32-LE <pdf-name>.<page-number>.txt\n" |
| 796 " --png - write page images <pdf-name>.<page-number>.png\n" | 794 " --png - write page images <pdf-name>.<page-number>.png\n" |
| 795 " --ppm - write page images <pdf-name>.<page-number>.ppm\n" |
| 797 #ifdef PDF_ENABLE_SKIA | 796 #ifdef PDF_ENABLE_SKIA |
| 798 " --skp - write page images <pdf-name>.<page-number>.skp\n" | 797 " --skp - write page images <pdf-name>.<page-number>.skp\n" |
| 799 #endif | 798 #endif |
| 800 ""; | 799 ""; |
| 801 | 800 |
| 802 int main(int argc, const char* argv[]) { | 801 int main(int argc, const char* argv[]) { |
| 803 std::vector<std::string> args(argv, argv + argc); | 802 std::vector<std::string> args(argv, argv + argc); |
| 804 Options options; | 803 Options options; |
| 805 std::list<std::string> files; | 804 std::vector<std::string> files; |
| 806 if (!ParseCommandLine(args, &options, &files)) { | 805 if (!ParseCommandLine(args, &options, &files)) { |
| 807 fprintf(stderr, "%s", usage_string); | 806 fprintf(stderr, "%s", kUsageString); |
| 808 return 1; | 807 return 1; |
| 809 } | 808 } |
| 810 | 809 |
| 811 if (options.show_config) { | 810 if (options.show_config) { |
| 812 ShowConfig(); | 811 ShowConfig(); |
| 813 return 0; | 812 return 0; |
| 814 } | 813 } |
| 815 | 814 |
| 816 if (files.empty()) { | 815 if (files.empty()) { |
| 817 fprintf(stderr, "No input files.\n"); | 816 fprintf(stderr, "No input files.\n"); |
| (...skipping 26 matching lines...) Expand all Loading... |
| 844 } | 843 } |
| 845 FPDF_InitLibraryWithConfig(&config); | 844 FPDF_InitLibraryWithConfig(&config); |
| 846 | 845 |
| 847 UNSUPPORT_INFO unsuppored_info; | 846 UNSUPPORT_INFO unsuppored_info; |
| 848 memset(&unsuppored_info, '\0', sizeof(unsuppored_info)); | 847 memset(&unsuppored_info, '\0', sizeof(unsuppored_info)); |
| 849 unsuppored_info.version = 1; | 848 unsuppored_info.version = 1; |
| 850 unsuppored_info.FSDK_UnSupport_Handler = ExampleUnsupportedHandler; | 849 unsuppored_info.FSDK_UnSupport_Handler = ExampleUnsupportedHandler; |
| 851 | 850 |
| 852 FSDK_SetUnSpObjProcessHandler(&unsuppored_info); | 851 FSDK_SetUnSpObjProcessHandler(&unsuppored_info); |
| 853 | 852 |
| 854 while (!files.empty()) { | 853 for (const std::string& filename : files) { |
| 855 std::string filename = files.front(); | |
| 856 files.pop_front(); | |
| 857 size_t file_length = 0; | 854 size_t file_length = 0; |
| 858 std::unique_ptr<char, pdfium::FreeDeleter> file_contents = | 855 std::unique_ptr<char, pdfium::FreeDeleter> file_contents = |
| 859 GetFileContents(filename.c_str(), &file_length); | 856 GetFileContents(filename.c_str(), &file_length); |
| 860 if (!file_contents) | 857 if (!file_contents) |
| 861 continue; | 858 continue; |
| 862 fprintf(stderr, "Rendering PDF file %s.\n", filename.c_str()); | 859 fprintf(stderr, "Rendering PDF file %s.\n", filename.c_str()); |
| 863 std::string events; | 860 std::string events; |
| 864 if (options.send_events) { | 861 if (options.send_events) { |
| 865 std::string event_filename = filename; | 862 std::string event_filename = filename; |
| 866 size_t event_length = 0; | 863 size_t event_length = 0; |
| (...skipping 17 matching lines...) Expand all Loading... |
| 884 delete platform; | 881 delete platform; |
| 885 | 882 |
| 886 #ifdef V8_USE_EXTERNAL_STARTUP_DATA | 883 #ifdef V8_USE_EXTERNAL_STARTUP_DATA |
| 887 free(const_cast<char*>(natives.data)); | 884 free(const_cast<char*>(natives.data)); |
| 888 free(const_cast<char*>(snapshot.data)); | 885 free(const_cast<char*>(snapshot.data)); |
| 889 #endif // V8_USE_EXTERNAL_STARTUP_DATA | 886 #endif // V8_USE_EXTERNAL_STARTUP_DATA |
| 890 #endif // PDF_ENABLE_V8 | 887 #endif // PDF_ENABLE_V8 |
| 891 | 888 |
| 892 return 0; | 889 return 0; |
| 893 } | 890 } |
| OLD | NEW |