Spreadsheet-ParseExcel-0.66/000755 000765 000024 00000000000 14543415026 016012 5ustar00Johnstaff000000 000000 Spreadsheet-ParseExcel-0.66/Changes000644 000765 000024 00000051512 14543414510 017306 0ustar00Johnstaff000000 000000 Revision history for Perl module Spreadsheet::ParseExcel. 0.66 December 29 2023 ! Fix for CVE-2023-7101 https://github.com/runrig/spreadsheet-parseexcel/issues/33 0.65 March 15 2014 ! Merge support for accessing hyperlink data 0.64 March 11 2014 ! RT #47072 (ExcelLocaltime rounding) http://rt.cpan.org/Public/Bug/Display.html?id=47072 ! RT #93142 (date format w/commas) http://rt.cpan.org/Public/Bug/Display.html?id=93142 ! RT #93651 (Update metadata) http://rt.cpan.org/Public/Bug/Display.html?id=93651 0.63 March 7 2014 ! RT #12946 (IO::Wrap) http://rt.cpan.org/Public/Bug/Display.html?id=12946 ! RT #93065 (auto color) http://rt.cpan.org/Public/Bug/Display.html?id=93065 0.62 ! Fix test 46 skip_all plan logic. From CPAN testers. ! RT #52830 (0x00 general fmt) && fix test. http://rt.cpan.org/Public/Bug/Display.html?id=52830 ! RT #93138 (undefined value as ARRAY) http://rt.cpan.org/Public/Bug/Display.html?id=93138 0.61 ! RT #93500 (Red Cell formats) http://rt.cpan.org/Public/Bug/Display.html?id=93500 + RT #93379 (tab color) http://rt.cpan.org/Public/Bug/Display.html?id=93379 + RT #93393 (active worksheet) http://rt.cpan.org/Public/Bug/Display.html?id=93393 ! Fix RT #93425 (color from workbook leaks) http://rt.cpan.org/Public/Bug/Display.html?id=93425 + RT #93367 (hidden rows/columns) http://rt.cpan.org/Public/Bug/Display.html?id=93367 ! Fix RT #93065 (black is white) http://rt.cpan.org/Public/Bug/Display.html?id=93065 ! Fix RT #62593 (?)(merge from apla/master). http://rt.cpan.org/Public/Bug/Display.html?id=62593 0.60 February 26 2014 + Fix RT #43250 http://rt.cpan.org/Public/Bug/Display.html?id=43250 0.59 April 6 2011 + Patch for decryption of default encrypted workbooks from Alexey Mazurin. ! Fix for invalid formatting of text cell that are numeric. http://rt.cpan.org/Public/Bug/Display.html?id=62073 0.58 September 17 2010 ! Fix for text cells formatted with a leading apostrophe. http://rt.cpan.org/Public/Bug/Display.html?id=61299 ! Documentation fixes. Thanks to Dan Dascalescu Fix RT #61320 (typos) http://rt.cpan.org/Public/Bug/Display.html?id=61320 ! Fix for currency locales in format strings. Reported by wjaguar. http://rt.cpan.org/Public/Bug/Display.html?id=60547 ! Fix for incomplete SETUP records. Reported by M.C. Deurloo. 0.57 January 24 2010 ! Added fix for reading formatted data from Excel 4 files. ! Added example programs, a_simple_parser.pl and display_text_table.pl. ! Removed Build.PL from README. Thanks Ed Avis. https://rt.cpan.org/Ticket/Display.html?id=52670 0.56 November 9 2009 + Added error() and error_code() error handling routines. This allows encrypted files to be ignored. Added t/10_error_codes.t for the above methods. http://rt.cpan.org/Public/Bug/Display.html?id=51033 http://rt.cpan.org/Public/Bug/Display.html?id=47978 ! Made version 0.19 of OLE::Storage_Lite a prerequisite to avoid issues when writing OLE header in SaveParser. ! Changed Parse() method name to parse() for consistency with the rest of the API. The older method name is still supported but not documented. 0.55 August 25 2009 + Refactored Cell.pm documentation and method names and added regression suite, t/06_regression.t. ! Added float comparison test to avoid false failing tests on 64bit systems. 0.54 August 25 2009 ! Fix for height/width of hidden rows/columns with additional. tests in 05_regression.t. Thanks to Greger Leijonhufvud. http://rt.cpan.org/Public/Bug/Display.html?id=48450 ! Fix for mal-formed Print_Title Name block. Reported by Marc Elser. 0.53 August 24 2009 + Made perl 5.8.0 a requirement for proper Unicode handling. ! Fixed minor int2col() bug thanks to David Black. Added 28_int2col.t test for above. http://rt.cpan.org/Public/Bug/Display.html?id=48967 + Refactored Workbook API and docs. 0.52 August 21 2009 + Added new FmtJapan module and tests written by Goro Fuji. ! Fixed bug in ExcelFmt() date handling where conversion to weekday and month names wasn't handled correctly. Add extra tests to 21_number_format_user.t for above. ! Fixed bug when checking $Config{useperlio}. Reported by kbates and H.Merijn Brand. http://rt.cpan.org/Public/Bug/Display.html?id=28861 ! Fixed bug where CellHandler variables weren't scoped to package. Reported by pomoxp. http://rt.cpan.org/Public/Bug/Display.html?id=43250 + Added tests for ExcelLocaltime() and LocaltimeExcel(). 26_localtime2excel.t and 27_localtime2excel.t. + Refactored SaveParser docs. Work still ongoing. 0.51 August 19 2009 ! Added fix for incorrectly skipped charts. Thanks Guntram Blohm. https://rt.cpan.org/Ticket/Display.html?id=44009 ! Added fix for locale [$-ddd] strings in number formats. Reported by Jeff Mitchell. https://rt.cpan.org/Ticket/Display.html?id=43638 ! Added fix for multiple dots in number formats. Thanks to Father Chrysostomos. http://rt.cpan.org/Public/Bug/Display.html?id=45502 ! Added fix to make half way rounding behave like Excel. Thanks to Joshua Megerman. http://rt.cpan.org/Public/Bug/Display.html?id=45626 ! Added checks for valid dates in Utility::ExcelFmt. Reported by Alan James. http://rt.cpan.org/Public/Bug/Display.html?id=48831 0.50 August 18 2009 + Refactored Worksheet interface and documentation. Added 04_regression.t and 05_regression.t to test above changes. ! Fixed column units conversion. Added 24_row_col_sizes.t for above change. ! Fixed RK number conversion. The existing code was the source of several RT bugs and portability issues. Added 25_decode_rk_numbers.t testcase. 0.49 January 24 2009 ! Added Text::CSV_XS to xls2csv() function to handle embedded commas in csv data. Reported by Fredrik Linde. http://rt.cpan.org/Public/Bug/Display.html?id=41337 + Rewrote Utility.pm documentation. - Removed wantarray from ExcelFmt() and the unused and undocumented feature of returning the result and a format color in a list context. The older mechanism is still available but now requires an explicit flag. 0.48 January 23 2009 ! Fixed bug where numbers with uppercase formats such as MM/DD/YY were ignored. Applies to files created by OpenOffice.org and some international versions of Excel. Added tests for above. http://rt.cpan.org/Public/Bug/Display.html?id=20526 http://rt.cpan.org/Public/Bug/Display.html?id=31206 http://rt.cpan.org/Public/Bug/Display.html?id=40307 ! Removed undocumented and counter-intuitive use of overload on SheetNo in Worksheet.pm. http://rt.cpan.org/Public/Bug/Display.html?id=14278 0.47 January 22 2009 ! Fixed bug where multiple embedded charts on a worksheet caused the worksheet order to be lost and data to get overwritten. Reported by Steven Martin and others. http://rt.cpan.org/Public/Bug/Display.html?id=13365 0.46 January 18 2009 ! Heavily refactored the ExcelFmt() function for maintainability and fixed several bugs, in particular for 12 hour clock times. Added test cases for above. ! Removed use of $& match variables from ExcelFmt. Reported by Aaron Wigley. http://rt.cpan.org/Public/Bug/Display.html?id=42425 ! Replaced lvalue substr() in ExcelFmt () with 4-arg substr() for efficiency. Reported by Goro Fuji. http://rt.cpan.org/Public/Bug/Display.html?id=42518 ! Removed spurious t/examples dir from Makefile.PL and removed unused t/lib dir. Reported by Peter (Stig) Edwards. http://rt.cpan.org/Public/Bug/Display.html?id=42442 0.45 January 13 2009 ! Fixed failed parsing of large (8-16k) Unicode strings. Reported by Graham Stead and Moka. http://rt.cpan.org/Public/Bug/Display.html?id=41813 http://rt.cpan.org/Public/Bug/Display.html?id=35678 ! Fixed critical bug where data rows could be ignored. Reported and isolated by Peter (Stig) Edwards. http://rt.cpan.org/Public/Bug/Display.html?id=30677 0.44 January 8 2009 ! Fix for OpenOffice.org GENERAL format. http://rt.cpan.org/Public/Bug/Display.html?id=7206 Thanks to Niko Tyni and the Debian Perl team + Perltidyed source and added standard headers and Pod sections to all modules. 0.43 January 7 2009 + Restructured and rewrote the main documentation. This is the start of a general refactoring. + Added worksheets() Workbook method to iterate over the Worksheet objects. + Added unformatted() method to get a Cell's unformatted value. + Renamed public methods RowRange(), ColRange() and Cell() to row_range(), col_range() and get_cell(). Old methods are still available. ! Turned on compatibility_mode() by default in SaveParser to avoid SP3 problems. ! Fixed minor SaveParser bug with font rotation. http://rt.cpan.org/Public/Bug/Display.html?id=41626 0.42 January 1 2009 + Fix for world writeable files in distro to allow PAUSE indexing. 0.41 October 24 2008 + Changed maintainership to John McNamara. ! Fixed bug when parsing RK numbers (generally ints or small floats). http://rt.cpan.org/Public/Bug/Display.html?id=39892 ! Changed margin units to inches to (cleanly) avoid undef warning in SaveParser. 0.33 2008.09.07 - Default format for formatted dates changed from 'm-d-yy' to 'yyyy-mm-dd' - Numeric fields with date-formats now promote to Date - Added docs about date type 14 problem - skip another test when prereq is missing - split Spreadsheet::ParseExcel::SaveParser into packages - split Spreadsheet::ParseExcel into packages 0.32 2007.05.05 - Remove the memory_leak test as well as it still fails. 0.31 2007.05.03 - Require IO::Scalar always as OLE::Storage_Lite needs it but does not prereq it - disable some of the tests that don't yet work on 64 bit due to number precision in order to allow automatic installation 0.30 2007.03.31 - add some more tests - add test to see memory leak using Proc::ProcessTable - Start using Scalar::Util qw(weaken) to (hopefully) avoid memory leak - It seems we did not check correctly if PERLIO is available in Makefile.PL now it is the same test we do in the code itself. - Flag1904 renamed to Flg1904 in documentation (Chad) RT #24293 0.29 2007.03.30 - clean up basic.t to skip tests that need additional and missing module - No more need for IO::Scalar if PERLIO is available (H.Merijn Brand) 0.28 Wed Jan 7, 2007 - Documentation update - Add t/parse.t - Add sample/parse.pl - fix some syntax errors in the sub-modules 0.27 Wed Jan 3, 2007 - See changes in the 0.27_XX versions 0.27_03 Thu Nov 2, 2006 - Officially receive maintainership (Gabor Szabo) - slight code cleanup - more sample test 0.27_02 - Fixing another warning: Character in 'c' format wrapped in pack http://rt.cpan.org/Ticket/Display.html?id=18063 (Grant Stevens) - More test, enable use of Devel::Cover 0.27_01 Mon Sep 11, 2006 - Moving test.pl to t/ and using Test::More - Add tests running (some of the) sample files - Add 'use warnings', remove prototypes - Fix the warning in Spreadsheet::ParseExcel::FmtDefault Character in "C" format wrapped at .../Spreadsheet/ParseExcel/FmtDefault.pm line 68. http://rt.cpan.org/Public/Bug/Display.html?id=7376 (Slaven Rezić and others) 0.2603 Mon May 30, 2004 - Mod SaveParser : Apply a path from Eduardo J adding Protect feature (Thank you, Eduardo J for patch) - Mod ParseExcel : Apply a path from C. Jon Larsen adding GetContent (Thank you, C. Jon Larsen) 0.2602 Mon Jul 15, 2002 - Fix SaveParser : Mod hidden support(with 0 column width) (Thank you, HIROSHIGE,Shigeru for report) 0.2601 Sat Jul 13, 2002 Thank you for Peter Marschall for PATCH. - Mod ParseExcel : Add new methods - Mod SaveParser : Add new methods - Mod ParseExcel : Mod subHeader, subFooter (Thank you, RT? for report) - Mod SaveParser : Add hidden support (Thank you, HIROSHIGE,Shigeru for report) - Add new sample : Add dmpEx_2xml.pl (Thank you, Khalid EZZARAOUI for new code) 0.26 Sat Jun 1, 2002 Thank you for Peter Marschall. - Mod ParseExcel : Add new interface - Mod SaveParser : Add new interface 0.25 Fri May 10, 2002 - Mod ParseExcel : Fix For SaveParser - Mod SaveParser : Add Create Add page setting Add some documents 0.2407 Mon Apr 24, 2002 - Mod Utility : Fix Numeric format (Thank you, Jeff Shaffer for report) Fix MakeBun - Mod ParseExcel : Fix Continue (COTINUE with no header) (Thank you, Tuneyosi Fukusima for report) : Add {Val} in sample :-) (Thank you, Ernst Kloppenburg for suggestion) 0.2406 Mon Apr 8, 2002 - Mod Utility : Fix $sNUMEXP (Thank you for Xavier Catteau for patch) Add col2int int2col sheetRef xls2csv (Thank you for Xavier Catteau for patch) - Mod ParseExcel : Add file contents - Mod SaveParser : Mod AddCell 0.2405 Tue Jan 29, 2002 - Mod FmtDefault : Fix 0x01 (='0') format (Thank you Marc Pohl for report) - Mod ParseExcel : Mod Parse Fh of CGI.pm and GLOB ref. (Thank you Nicholas Hamlin and Abe Daisuke for reports) Fix PrintArea detection (Thank you Todd A. Green for patch) Add custom palette support (Thank you Florian Pflug for patch) Fix _SetDimension prototype (Thank you David Dyck for patch) - Mod SaveParser : Mod return value of SaveParser (Thank you Iceman for patch) - Mod Utility : Mod $iAftP manipulation (Thank you Stanislav Sukholet for patch) 0.2404 Tue Jul 24 7:30:00 2001 - Tue Dec 4 11:00:00 2001 - Mod ParseExcel : Mod _SwapForUnicode for a string with odd length (Thank you, Mikhail Turenko) : Add GLOB reference support (Thank you, coral.) : Fix/Add Font name Unicode judge (Thank you, Mikhail Turenko, Alex Edelman) - Mod Utility : Fix Backslash problem (Thank you, Bruno Wolff III. And sorry for TOO LATE) : Fix add number expressions (Thank you, Jing Zhao) 0.2403 Tue Jul 24 7:30:00 2001 - Mod FmtUnicode, FmtJapan, FmtJapan2 : Fix NL (Thank you, Jeremy Smartt) 0.2402 Thu Jul 12 20:30:00 2001 - Mod Utility, FmtDefault :Fix format error (Thank you, Kevin Ko) - Mod Utility :Mod for Japanese sign(triangle) 0.2401 Mon Jul 9 19:00:00 2001 - Mod FmtUnicode :Mod alphanumeric in BIG5 (Thank you, Kevin Ko) Sorry, it is not effective (ToT) 0.24 Wed Jul 5 06:30:00 2001 - Mod ParseExcel :Add OO style callback (Thank you, Ilya Sterin) - Add sample/Ilya.pl :-) - Mod ParseExcel : Mod use FmtDefault for PDK (Thank you, Maxime Alechine) 0.2301 Tue Jun 26 8:00:00 2001 - Mod FmtDefault :Fix not convert undefined or '' string 0.23 Thu Jun 21 21:00:00 2001 - Mod ParseExcel, FmtUnicode, FmtJapan, FmtJapan2 : :Fix Unicode Latin1 adapt (Thank you, Seiko Yamamura and Sadahiro) - Mod ParseExcel : my(undef) -> my($undef1) ... (Thank you, Alex) 0.22.3 Thu May 16 8:00:00 2001 - Mod FmtUnicode : Fix code undefined - Mod ParseExcel : Fix Marged area (row>255) (Thank you, Dmitriy Litovchin) 0.22.2 Thu May 16 8:00:00 2001 - Mod ParseExcel : Fix Hidden RowHeight, ColWidht (Thank you, Maxim Ovchinnikov) 0.22.1 Wed May 14 20:35:00 2001 - Mod ParseExcel : Fix Continue (COTINUE with no header) (Thank you, Steve Sapovits) : Fix ignore Graph sheet (Thank you, Joel Defarge ) - Mod Utility : Fix eval at Conditiona-Format (Thank you, Alok K. Dhir) 0.22 Sat May 5 19:00:00 2001 - Add SaveParser : For DBD::Excel 0.21.2 Tue May 1 7:00:00 2001 - Fix ParseExcel : MergedArea (Thank you, Bradley M. Handy ) 0.21.1 Sat Apr 29 14:00:00 2001 - Add ParseExcel : Rich text information support (Thank you, Vladimir Igrevsky) 0.21 Sat Apr 24 18:00:00 2001 - Mod ParseExcel : Add New Feature for CellHandler (Thank you, Jeff Clark) - Mod ParseExcel, FmtDefault, FmtJapan, Utility: : Expanding format information to support (Supported by Nippon-RAD OP Division) 0.20.2 Wed Apr 18 9:00:00 2001 - Fix Utility : ExcelFmt (For Number format) (Thank you, Jeff Clark) 0.20.1 Sun Apr 11 9:00:00 2001 - Fix FmtJapan, FmtJapan2 : TxtFmt - Fix FmtDefault : ValFmt (for 'String' format') (Thank you, Fukusima, Tuneyosi) 0.20 Mon Mar 30 20:00:00 2001 - Fix ParseExcel.pm : RK int minus (Thank you, Morten Sickel) - Mod ParseExcel.pm : Fix Font number but not complete (Thank you, Vladimir Igrevsky) - Fix ParseExcel.pm : _convBIFF8 non conversion (LABEL, String...) (Thank you, Fukusima, Tuneyosi) - Add pod : Limitaion with Spreadsheet::WriteExcel.pm (Thank you, Venkataramana Mokkapati) 0.19 Mon Mar 26 12:00:00 2001 - Fix Utility.pm :Month short name (Thank you, Morten Sickel) - Fix Utility.pm :Formatting Error (Thank you, yusuf_najuddin) - Fix FmtJapan2.pm: CP932Excel.map readable check (Thank you, Kawasaki) 0.18 Sat Mar 18 16:00:00 2001 - Fix Excel4 file support - Fix subLabel (Unicode) (Thank you, yusuf_najmuddin) 0.17 Wed Mar 12 9:00:00 2001 - Fix Utility.pm for Number format - Fix FmtJapan2.pm to use FmtJapan (Thank you, Kawasaki) - Fix Utility.pm for Number format (not Numeric) (Thank you, John Dawson) - Fix Format string with Chinese Character (in Excel95) 0.16 Wed Mar 7 22:00:00 2001 - Fix Format String - Avoding warnings (Thank you Jimmy Sieben and Daniel Berger) 0.15 Wed Mar 6 10:00:00 2001 - Fix RK number (Thank you Jimmy Sieben) - Modify many internal functions!! - Add Spreadsheet::ParseExcel::Utity for formatting! 0.13 Sat Feb 21 20:40:00 2001 - Support Pps 'BOOK' (not 'Book') with OLE::Storage_Lite 0.07 (Thank you, Punam Chordia ) - Modify Makefile.PL (define OLE::Storage_Lite Version) (Thank you, Aldo Calpini) - Fix Conetinue ASCII-Unicode pattern (Thank you, Tim Wills) - Add FmtUnicode sample :dmpExU.pl (Sorry and thank you, Mike Goblin) 0.12 Sat Feb 5 11:00:00 2001 - Support Excel4 file (Thank you, Jeff Haferman and herbert ) - Add reference of scalar and IO::File object support in Parse (Thank you, Jeff Haferman) - Fix Continue SST (Thank you, Gennadiy) - Delete VBAMacros from sample/Excel/Test97j.xls and Test97.xls avoiding virus check. (Thank you, Alfred Nathaniel) - Fix weekday of ExcelLocaltime 0.11 Sat Jan 26 14:00:00 2001 - Skip 0xEF to EOF(0x0A) (Thank you, Phil DiFalco) 0.10 Mon Jan 15 12:00:00 2001 - Fix _subString, _subFormula (Thank you, Ilter Cekic and Mike Edwards) 0.09 Sat Dec 15 12:00:00 2000 - Fix Month name of FmtDefault.pm (Thank you, Michael Edwards) - Add FmtJapan2.pm - Fix Slightly Bug 0.08 Sat Nov 25 12:00:00 2000 - Fix RString, PackedString BUGS (Thank you, Kim Namsuk) - Fix undefined function _subDefColW (Thank you, Hirofumi Morisada) 0.07 Sat Nov 18 12:00:00 2000 - Change to use OLE::Storage_Lite - Fix RString, PackedString BUGS (Thank you, Hirofumi Morisada) - Fix and Add Formula String (Thank you, Michael Edwards) 0.05 Mon Oct 2 03:14:04 2000 - original version Spreadsheet-ParseExcel-0.66/MANIFEST000644 000765 000024 00000005340 14543415026 017145 0ustar00Johnstaff000000 000000 CP932Excel.map Changes MANIFEST Makefile.PL README README_Japan.htm META.yml t/00_basic.t t/01_parse.t t/02_parse-dates.t t/03_regression.t t/04_regression.t t/05_regression.t t/06_regression.t t/07_cell_handler.t t/10_error_codes.t t/11_encryption.t t/20_number_format_default.t t/21_number_format_user.t t/22_number_format_datetime.t t/23_number_format_time.t t/24_row_col_sizes.t t/25_decode_rk_numbers.t t/26_localtime2excel.t t/27_localtime2excel.t t/28_int2col.t t/29_active_sheet.t t/30_sst_01.t t/32_charts.t t/41_test95-97j.t t/42_test95-97j-2.t t/43_test2000J.t t/44_oem.t t/45_oem-2.t t/46_save_parser.t t/47_hyperlinks.t t/90_pod.t t/91_minimumversion.t t/92_meta.t t/excel_files/Dates.xls t/excel_files/Dates1904.xls t/excel_files/Test2000J.xls t/excel_files/Test95.xls t/excel_files/Test95J.xls t/excel_files/Test97J.xls t/excel_files/TestEncoding.xls t/excel_files/chart1.xls t/excel_files/chart2.xls t/excel_files/chart3.xls t/excel_files/chart4.xls t/excel_files/encrypted.xls t/excel_files/long_string1.xls t/excel_files/long_string2.xls t/excel_files/long_string3.xls t/excel_files/long_string4.xls t/excel_files/long_string5.xls t/excel_files/long_string6.xls t/excel_files/long_string7.xls t/excel_files/long_string8.xls t/excel_files/pers-encrypted-RC4-pass-11.xls t/excel_files/pers-encrypted-def-pass-QwErTyUiOp.xls t/excel_files/pers-protected.xls t/excel_files/worksheet_01.xls t/excel_files/TestActiveSheet.xls lib/Spreadsheet/ParseExcel.pm lib/Spreadsheet/ParseExcel/Cell.pm lib/Spreadsheet/ParseExcel/Dump.pm lib/Spreadsheet/ParseExcel/FmtDefault.pm lib/Spreadsheet/ParseExcel/FmtJapan.pm lib/Spreadsheet/ParseExcel/FmtJapan2.pm lib/Spreadsheet/ParseExcel/FmtUnicode.pm lib/Spreadsheet/ParseExcel/Font.pm lib/Spreadsheet/ParseExcel/Format.pm lib/Spreadsheet/ParseExcel/SaveParser.pm lib/Spreadsheet/ParseExcel/SaveParser/Workbook.pm lib/Spreadsheet/ParseExcel/SaveParser/Worksheet.pm lib/Spreadsheet/ParseExcel/Utility.pm lib/Spreadsheet/ParseExcel/Workbook.pm lib/Spreadsheet/ParseExcel/Worksheet.pm examples/a_simple_parser.pl examples/display_text_table.pl sample/Excel/AuthorK.xls sample/Excel/AuthorK95.xls sample/Excel/FmtTest.xls sample/Excel/Rich.xls sample/Excel/Test1904.xls sample/Excel/Test1904_95.xls sample/Excel/Test95.xls sample/Excel/Test95J.xls sample/Excel/Test97.xls sample/Excel/Test97J.xls sample/Excel/oem.xls sample/README sample/chkFmt.pl sample/chkInfo.pl sample/dmpEx.pl sample/dmpExU.pl sample/dmpExH.pl sample/dmpExHJ.pl sample/dmpExJ.pl sample/dmpExR.pl sample/Ilya.pl sample/sample.pl sample/sampleOEM.pl sample/sample_j.pl sample/smpFile.pl sample/xls2csv.pl sample/iftest.pl sample/iftestj.pl sample/dmpEx_2xml.pl sample/parse.pl META.json Module JSON meta-data (added by MakeMaker) Spreadsheet-ParseExcel-0.66/t/000755 000765 000024 00000000000 14543415025 016254 5ustar00Johnstaff000000 000000 Spreadsheet-ParseExcel-0.66/README000644 000765 000024 00000003657 14543412610 016701 0ustar00Johnstaff000000 000000 NAME Spreadsheet::ParseExcel - Extract information from Excel file. DESCRIPTION This module allows you to extract information from Excel file. This module can handle files in Excel95, 97 and 2000 format. The module will work on the majority of Windows, UNIX and Macintosh platforms. REQUIREMENT This module requires these modules: OLE::Storage_Lite Jcode.pm (if you are using FmtJapan, or FmtJapan2) Unicode::Map (if you are using FmtJapan2 or FmtUnicode) IO::Scalar (if PERLIO is not available) Spreadsheet::WriteExcel (to use Spreadsheet::ParseExcel::SaveParser) INSTALLATION The module can be installed using the standard Perl procedure: perl Makefile.PL make make test make install # You may need to be root make clean # or make realclean or using CPAN.pm or CPANPLUS.pm cpan Spreadsheet::ParseExcel Windows users without a working "make" can get nmake from: ftp://ftp.microsoft.com/Softlib/MSLFILES/nmake15.exe For FmtJapan2 If you use FmtJapan2, you must do following actions: (1) Copy "CP932Excel.map" included with this distribution to an applicatable directry. (2) To add "CP932Excel" as map name, append following lines to REGISTRY in the Unicode::Map hierarchy (changing map directy to applicatable directry): name: CP932Excel srcURL: $SrcUnicode/VENDORS/MICSFT/WINDOWS/CP932.TXT src: $DestUnicode/VENDORS/MICSFT/WINDOWS/CP932.TXT map: (which you copied directry)/CP932Excel.map # Don't remove this line AUTHOR Maintainer 0.60+: Douglas Wilson dougw@cpan.org Maintainer 0.40-0.59: John McNamara jmcnamara@cpan.org Maintainer 0.27-0.33: Gabor Szabo szabgab@cpan.org Original author: Kawai Takanori (Hippo2000) kwitknr@cpan.org SUPPORT Please check the "KNOWN PROBLEMS" section in the manual page for Spreadsheet::ParseExcel. Spreadsheet-ParseExcel-0.66/README_Japan.htm000644 000765 000024 00000013406 11247565351 020603 0ustar00Johnstaff000000 000000
Speadsheet::ParseExcel.pm - 0.2405

                                                by 繧ŵ (Hippo2000)

Changes


  Υ⥸塼ϡޤСǤ

  MicrosoftҤExcelեWindowsʳΥץåȥեǤ
  Ф褦ˤ⥸塼Ǥ

ưǧ
  DOS/V     WindowsNT ver.4.0    Perl5.005
  DOS/V     TurboLinux ver.6.0   Perl5.005
  Sun Sparc Solaris 2.6          Perl5.005
  DOS/V     Vine Linux 2.0       Perl5.005
  Macintosh JPerlFreeBSDǤưƤȤݡȤ򤤤Ƥޤ

  ¾δĶǼ¹Ԥ줿ϡƤ
  ưƤưʤƤ⡢Ϥꤤޤ <(__)>

ñʳǧ(testǥ쥯ȥ
  sampleǥ쥯ȥ˰ʲΥե뤬äƤޤ

  sample.pl   ñʥƥȥץȡSpreadsheet::ParseExcel::FmtDefaultѡ
  sample_j.pl ñʥƥȥץȡSpreadsheet::ParseExcel::FmtJapanѡɤꤷƽϡ
  res_sample  sample.plμ¹Է
  res_sample_jsample_j.plμ¹Է(euc)

  dmpEx.pl  : ExcelեƤɽSpreadsheet::ParseExcel::FmtDefaultѡ
  dmpExj.pl : ExcelեƤɽSpreadsheet::ParseExcel::FmtJapanѡ

  ñˤΥ⥸塼ưǧǤСdmpExj.plˤä
  ꤷExcelեƤɽ뤳ȤǤޤ

  ex.
    # perl -I.. dmpExj.pl Excel/Test97.xls euc 

    -I..פϡƥǥ쥯ȥˤSpreadsheet::ParseExcel.pmѤ뤿˻ꤷޤ
    Excel/Test97.xlsפоݤȤʤե̾
    eucפϴϤȤʸɤǤeucsjisjisʤ
    Jcode.pmƱǤ

󥹥ȡ
  OLE::Storage_Lite󥹥ȡ뤵Ƥɬפޤ
Spreadsheet::ParseExcel::FmtJapanѤ硢Jcode.pmɬפȤޤ¾Υ⥸塼ɬפȤޤ󡣡
Spreadsheet::ParseExcel::FmtJapan2Ѥ硢Jcode.pmUnicode::MapɬפȤޤ
PerlɸŪʥ󥹥ȡˤʤޤΥ⥸塼뼫ΤPerlΤߤǺƤΤǡԡǤưޤ
  perl Makefile.PL
  make
  make test
  make install (rootˤʤäơ
FmtJapan2Τ
 ¸ʸб뤿FmtJapan20.09Ʊޤ
 Ѥ뤿ˤUnicode::Map򥤥󥹥ȡ뤹ۤʲμ礬ɬפˤʤޤ
  (1) Ʊ"CP932Excel.map"Ŭڤʥǥ쥯ȥ˥ԡޤ
  (2) "CP932Excel"ޥå̾Ȥɲä뤿ˡUnicode::MapؤˤREGISTRY˰ʲιԤɲäޤ
      mapΥǥ쥯ȥ̾Ŭڤʥǥ쥯ȥ̾ˤƤ
name:    CP932Excel
srcURL:  $SrcUnicode/VENDORS/MICSFT/WINDOWS/CP932.TXT
src:     $DestUnicode/VENDORS/MICSFT/WINDOWS/CP932.TXT
map:     (ԡΥǥ쥯ȥ)/CP932Excel.map
# Don't remove this line
Ȥ
  use strict;
  use Spreadsheet::ParseExcel;
  my $oExcel = new Spreadsheet::ParseExcel;
  my $oBook = $oExcel->Parse('Excel/Test97.xls');
  
  #ޤܸбǤ
  use strict;
  use Spreadsheet::ParseExcel;
  use Spreadsheet::ParseExcel::FmtJapan;
  my $oExcel = new Spreadsheet::ParseExcel;
  my $oFmtJ = Spreadsheet::ParseExcel::FmtJapan->new(Code => 'euc'); #sjisjisʤɤΥ
  my $oBook = $oExcel->Parse('Excel/Test97.xls', $oFmtJ);
  #μФ
  my($iR, $iC, $oWkS, $oWkC);
  
  print "FILE  :", $oBook->{File} , "\n";
  print "COUNT :", $oBook->{SheetCount} , "\n";
  print "AUTHOR:", $oBook->{Author} , "\n";
  for(my $iSheet=0; $iSheet < $oBook->{SheetCount} ; $iSheet++) {
    $oWkS = $oBook->{Worksheet}[$iSheet];
    print "--------- SHEET:", $oWkS->{Name}, "\n";
    for(my $iR = $oWkS->{MinRow} ; 
            defined $oWkS->{MaxRow} && $iR <= $oWkS->{MaxRow} ; $iR++) {
        for(my $iC = $oWkS->{MinCol} ;
               defined $oWkS->{MaxCol} && $iC <= $oWkS->{MaxCol} ; $iC++) {
            $oWkC = $oWkS->{Cells}[$iR][$iC];
            print "( $iR , $iC ) =>", $oWkC->Value, "\n" if($oWkC);
        }
    }
  }

Х
ǤäExce97 ǥ٥åѡ åȡפޤ
  Hirofumi Morisada˴ադǤ
  Excel97/2000¸硢FmtJapanǤϵ¸ʸ()޿IʤɡˤˤʤäƤޤޤ
  FmtJapan2ǤϰбƤĤǤ
  ޤƥȤȤǤƤޤ󡣤ȤꤢưǤ礦 <(__)>
  TurboLinux Version 6ǺƤΤǡ¾δĶǤɤʤΤȤƤⵤ
  ʤޤ
  SolarisǤưǧ򤷤Ƥ餤ޤʤޤԶ礬ꤽǤ

  ȡХݡȤԤƤޤ 繧ŵkwitknr@cpn.org

ʤ㤤ʤȡ
  ƥȡ
  ɥȤ
  Ϥؤб (^_^) Spreadsheet::WriteExcelȤäƤΤ

  줫ޤ뤴ȰĤƤͤϤޤ󤫡(^^)

ռ
  Ⱦüʾ֤Ǽռ⤢äΤǤϤޤ󤬡ʲΥץࡢ
  ⥸塼򻲹ͤˤƤޤ

    xlHtml
    OLE::Storage
        herbert (OLE::StorageƱġ
    Spreadsheet::WriteExcel

   SolarisΥǥХåȻϩव󤬤ʤСΩޤǤ(cloudy˴ա
 ǸˤExcel2000Υե򤤤ޤ
   Hirofumi Morisada󤫤ξʸΥХȯ뤳ȤǤޤ
   ơExcel97ǥ٥åѡåȡפɤ⤢꤬Ȥޤ

  ¾ưХݡȤ򤤤ադǤ
Spreadsheet-ParseExcel-0.66/examples/000755 000765 000024 00000000000 14543415025 017627 5ustar00Johnstaff000000 000000 Spreadsheet-ParseExcel-0.66/META.yml000644 000765 000024 00000001577 14543415025 017274 0ustar00Johnstaff000000 000000 --- abstract: 'Read information from an Excel file.' author: - 'John McNamara (jmcnamara@cpan.org)' build_requires: ExtUtils::MakeMaker: '0' configure_requires: ExtUtils::MakeMaker: '0' dynamic_config: 1 generated_by: 'ExtUtils::MakeMaker version 7.62, CPAN::Meta::Converter version 2.150010' license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: '1.4' name: Spreadsheet-ParseExcel no_index: directory: - t - inc requires: Crypt::RC4: '0' Digest::Perl::MD5: '0' IO::File: '0' IO::Scalar: '0' OLE::Storage_Lite: '0.19' Scalar::Util: '0' resources: bugtracker: http://github.com/jmcnamara/spreadsheet-parseexcel/issues homepage: http://github.com/jmcnamara/spreadsheet-parseexcel/ repository: http://github.com/jmcnamara/spreadsheet-parseexcel version: '0.66' x_serialization_backend: 'CPAN::Meta::YAML version 0.018' Spreadsheet-ParseExcel-0.66/sample/000755 000765 000024 00000000000 14543415025 017272 5ustar00Johnstaff000000 000000 Spreadsheet-ParseExcel-0.66/lib/000755 000765 000024 00000000000 14543415025 016557 5ustar00Johnstaff000000 000000 Spreadsheet-ParseExcel-0.66/Makefile.PL000644 000765 000024 00000002164 14543413376 017775 0ustar00Johnstaff000000 000000 #!/usr/bin/perl -w use strict; use warnings; use ExtUtils::MakeMaker; use 5.008; my %deps = ( 'OLE::Storage_Lite' => 0.19, 'IO::File' => 0, 'Scalar::Util' => 0, 'IO::Scalar' => 0, 'Crypt::RC4' => 0, 'Digest::Perl::MD5' => 0, ); my %resources = ( homepage => 'http://github.com/jmcnamara/spreadsheet-parseexcel/', repository => 'http://github.com/jmcnamara/spreadsheet-parseexcel', bugtracker => 'http://github.com/jmcnamara/spreadsheet-parseexcel/issues', ); my %params = ( 'AUTHOR' => 'John McNamara (jmcnamara@cpan.org)', 'NAME' => 'Spreadsheet::ParseExcel', 'ABSTRACT' => 'Read information from an Excel file.', 'VERSION_FROM' => 'lib/Spreadsheet/ParseExcel.pm', 'LICENSE' => 'perl', 'EXE_FILES' => [], 'INSTALLDIRS' => 'site', 'PL_FILES' => {}, 'PREREQ_PM' => \%deps, 'NEEDS_LINKING' => 0, 'test' => { TESTS => 't/*.t' } ); if ( $ExtUtils::MakeMaker::VERSION ge '6.46' ) { $params{META_MERGE} = { resources => \%resources }; } WriteMakefile(%params); Spreadsheet-ParseExcel-0.66/CP932Excel.map000644 000765 000024 00000050122 11247565351 020237 0ustar00Johnstaff000000 000000 '0??a?@0 00@>?000N00  <^"%\ & %  0;=[] 0  -"`"f""4&B&@ 2!  &&%%%%%%%%%%% ;0!!!0"" """*")"'!!""" "#"""a"R"j""=""5"+!+ 0&o&m&j % O `!ASS0A?@?00!@p0Q6> %%% %%%%%,%$%4%<%%%%%%%#%3%+%;%K% %/%(%7%?%%0%%%8%B@$` !`_3I33"3M33'3363Q3W3 3&3#3+3J3;3333~3{00!3!!221293~3}3|"."""^NUZ?Tac(Y"uzP`cn%efhW'ebq[Y{}b}b|[^c fhHgONO OMOPIVY7YZ\ `aapfipuOupy}}cUzS;NNWxNXn8z2(/QASpTTVY_m-?@bpT S[pSo\zNxn&VUk;YSmftVBNKO SU[0_qf fhl8lm)t[vzN4[`muv`iSQ}WX0YD[^`(cclopqqYqs?~v`[XielZu%QY.Ye__bej*k'ksV,\l{Q\KahvraNYOSx`in)zON SNOUO=OOsRSV YZ[[yfggkLlpksyyz<{wfV)NO\brYu;NOVXJX^_`*``babbe9?@AffhmwppuLv}uQRYT[]ahimxWrmlWgRVT^bdh<h8ksrxzkki[f\i}Mc{ j+}jh o_RrU`pbm;nn[DN9Sij:h*Q\zV[(h"1|RtN~OQ[R RR]UX*Y[[[^r^y`aacacebghShk>kSlWo"ooEtuvw z{|!}6fQe(N8T+\]svLw<\ TXOOSqUVhWYG[ [\^ ^~_cg:eeghh?@j_^0kll}uyH[cz}_w<NP}QY[b/bdk:ruyGpcT TUhTjXpx'guSt[PNNENOST8[_`%eQ}g=lBlrlpxtzvz{}|}fer[S\E]bbcn Z1oyZNNOOPQGzQqQSTS!SSUX\_7_J`/`P`mceYjKlrrwNWZNQ\-fim\@fiushP|PRWG]&ek#k=t4yy{K}_9TN]P6SS:rswQwa^UzzPv[GN2j\Q\H?@czltazq|h~phQlRTSfyAOPRQDUSW-sWYQ_b_`uavagacd:elfohBnufz=|}L}~KkJcf}RbdohAPk lzoTzt}P@#gNP9P&PeQ|R8RcUWXZ^aabcrij)r}rs.xxo}yw cuzUxQCSS^{_&nnss}C7PNNP ST|VY[d]^_'b8eEgnVr|N7gNNO SHTIT>Z/__`hjtZxwN^NO|OPPQIQlRRRSST?@TUWQWY}[T[][]]]^x^^^_`RaLbbce;ffCfgmh!hil_m*min/nu2vxlz?|}}}^}T*RLauqx?M};R[RSTXboj_QKR;TJVz@w`sDo pu_`rkdNVWdXZZ`haffh9hmu}:nBNOPSU]o]]gltsxPWP^c+PPQgTX^Y[_ibMch=ksnp}rxx&yme}0 RdW(gPjQWB*X:iT]WxO\RJTd>f(ggz{V}"/h\{9SQR7?@[bddg-kvcLvfRN PS\q`dech_qsu#{~xefkNNO:OR:SSUVXYYY[P\M^^+_`ce/[\eeegkb}k{lsEyIy|}}+^ifkoNO<OQP[W[aHcfBk!nlr>tuxy: 3lP_X+z[NSWY1Z[`nou[{Prg\aJ~Q\chfeqny>}nPR\:gSp|r5L+[_1`N;S[bKg1krsz.kRQSTj[cj9}VSTh?@[\1]Oabm2yy}B~MFrt/1KlNOOQESA_bglAn sc~&SY[my]~.|X~qQSO\f%wzQ_eiokm}nodv}]uQRb@ffn^}rfRSYs^_`UdPQRS SGSTUFU1VYhYZ<[\\\\^^^_pbbbccwff f-fvg~hjj5lmn nXq<q&qguwx]yyeyz{|}9I]<Tsaf~N NNNWQRpWX4X["^8`dgagVmDruszcr V1W?@bi kq~TwrU\;O8OOUZ [[_aNc/efKhimxmu3uwy^y}3:2NNRXuX\ u\=N cm{%bVS}T9W^%cl4pwa|pBTt^]]iepgcngIiodz[Np,u]f/QR6RY_`'be?etffthhkcnrruv|VXRYez^-`befgwzM|M~> d_xRbcdBb-z{}v INQHSCS`[\\]b&bGdhh4lmEmgo\qNq}ez{}?@~Jz9nxwRMUo8q6Qhy~U|VLXQ\cffiZruuyyVy|} }D4;a PRuSSP UXYOr=[\dS``c\cc?c}def]iioqNuvz|}}aIXlpmPXa5 OPtRGSs`ocIg_n,O\^e}SRQvc[X[k\ d gQ\NYY*lpQU>XY`bSg5iU@(OSX[\^/_` aKb4fln.NSY'{,Lnp'SSUD[bXbblot"8o8QS?@SOFTYj1]zh7rHj=N9SXVWfbcekNmn[pwz{}=[VX_>efjku7P$wW0_`efzl`uznE{u\z{Q}yz6Zw@N-N[_bf<glkw;Njp&s*WNQFQU[^^3^__5_k_acfgonrRu:w:t9xvwRcWvglssm%XiiuXZhciOCo,g&}Ti?opWjX[,},r*T NONP\PuRCTHX$[^^^^_`bc:chl@xyz }GD?@-ldXdeunv{inT_dMDQxXkY)\U^m~u[pOkou0QNTX5XWY\`_eg\n!v{Mx%x:R^WYt`PQZQ}QRUXTXXYW[\]`bd-gqhChhvmnompoq_Suyw{I{T{R|}qR0ciFv-0PRT X\admwzS\S?__mrywcy{krhjaQzi4\J[IpVx\o`eflZATQf YHQNMQpXczKib~uwSWi`l]N\<_Sy^eNsQe?@Y\?NY_oyyb[qs+q^t_c{dq|NC^NKWV`o} 3]bdgwlm>t6x4ZFuO^bceWgovrL)MP WZh}isqdrXjyw)O/ReSZbglv}{|6fo r~Q{xr{{Hj^auQu`QkbnvzOpb{OVzXYO4R$SJSS^d,egl>lNrHrsuT~A,{qic=fiujvxCS*SQT&Y^_|`bIbybekluvxy}w^j |8P\>_gkt5w ?@;gzS9u_f_<_ub{F<hgYZ}v~,O_jjl7otyhhUy^cuy(-T_lem\p;eOtN NWY+Zf[Q^^`bvew}efnmnr6{&P\tDOdkfaj\iSzWORo_^Eg yym_bUlNriRT;VtXabnqYn||}e^NOuQuX@^c^s_ gN&=[|sPXvVxR%w{POY rG{}MORZ)_OWcUkiu+zBRXaUb fk|?P#OSTFX1YI[\\])^bcge>eg ?@llpx2~+ *JlNONPRVWJY^=_b?fgghQ}!~2T ,SPS\Xdg4rgwfzFRlkX^LYTg,Qv}dixTWYf'gkTi^UggRh]NOSbg+lO~mNabno+Tsg*E]{\[nJzY|lw RY"q!r_w'ai ZZQT T}fvYr]nQMh}}bdxj!Y[_ksv}Q2g(vgbR\$b;|~UO`} SN_QYr:6_%wS_y}3VgSa alvR?@8U/OQQ*RS[^}`acg gngms6u1yPJYNOYN?P^|Y[^ccdfiJim nqu(zI! e} a~bk2}lmtmge<m}a=jNqSu]Pko-R)T\egNhttux_szNcueRmAnt uYxk|zOane\NNPN!Q[ehmsvBwz|o|uR}P+Sgmqt3*Wt`XAm}/^NO6OQR]`sy<4 bfktRRp^`Kao#qI|>}o3@#,TBojp2RZA^_gi|imjorbr{~KQmy2P-Tqkj`gNNkhin~xU^_ NNN*N1N6N<N?NBNVNXNNkN_ NNNNNNNNNNNNNNNNO OZO0O[O]OWOGOvOOOO{OiOpOOoOOQOOOOOOOOOPP(PP*P%POOP!P)P,OOPPPCPGgPUPPPHPZPVPlPxPPPPP?@PPPPPPPPPPPQ QQQQQQ!Q:Q7Q<Q;Q?QRQLQTQbzQiQnQQVQQQQQQQQQQQQQQQQQQQUQQ}QQQRR RRR'R*R.R3R9RORDRKR^RTRjRtRiRsRR}RRRRqRRRRRRRRRRRRRRRSSu8S SSSSS#S/S1S3S8S@SFSENSISMQS^SiSnYS{SwSSSSSSSSS|SfqSSSSTT=T@T,T<T.T6T)TTNTTuTT_TqTwTpTT{TTvTTTTTTTTTTT?@TTTTTTTUUTTTTTU9U@UcULU.U\UEUVU8U3U]UUTUUU{U~UUUU|UUUUUUUUUUUVUVUUVUVNVPqV4V6V2V8}VkVdV/VlVjVVVVVVVVVVVVVVVVVVVVVVWVWW WW W WWWUWW&W7WNW;W@WOWiWWWaWWWWWWWWWWWWX WWX XXXrX!XbXKXpkXRX=XyXXXXXXXXXXXXXXXXXXXXXXXYY YYhY%Y,Y2Y8Y>zYUYPYNYZYXYbY`YgYlYi?@YxYYO^OYYYYYYYZ%ZZZZ ZZ@ZlZIZ5ZbZjZZZZZZZZZZZZ[ [ [[2Z[*[6[>[C[E[@[Q[U[Z[e[i[p[s[u[xe[z[}[[[[[[[[[[[[[[[[[\\\ \\ \"\(\8\A\F\N\S\P\O[q\l\nNb\v\y\\\Y\\\\\\\\\\\\\]\] ]]]\]]]]]"]]]]L]R]N]K]l]s]v]]]]]]]]]]]]]]]]]]]]^ ^^^^^6^D^C^@^N^W^T^_^b^d^G^u^z^^^^^^?@^^^^^^^^^^^^^^__ _]_\_ ___)_-_8_A_H_L_N_/_Q_V_Y_a_m_s_w____________________`_`!``}```)``1```+`&``:`Z`A`j`w`_`J`F`M`c`C`d`B`l`k`Y````````````````_````aMaa`a``aa!``a aGa>a(a'aJa?a<a,a4a=aBaDasawaXakataoaeaqa_a]aSauaaaaaaaaaaaaaaaaaaayaaaaaaaaaabbb b bb?@bb!b*b.b0b2bAbNb^bcb[b`bhb|bbb~bbbbbbbbbbbdbbbbbbbbc bbc'ccbbcPc>cMdcOcccccvcccccck}cicccccccccdd4ddd&d6edd(ddgdodvdNe*ddddddddddddddd dbdde,ddddedeeee$e#e+e4e7e6e8uKeHeVeUeMeXe^e]erexeeeeeeeeeeeeeeegrf fegsf5f4ffOfDfIfAf^f]fdfgf_fbfpffffffffffff?@ffffff?fffffgggg&8g.g?g6gAg8g7gFg^g`gYgcggpgg|gjgggggggggggggggggggggjhhFh)h@hMh2hN}hh+hYhchwhhhhhhhhjhhthhhihh~ihihi"i&hi hhhhi6iihhi%hhhi(i*ii#i!hiyiwi\ixikiTi~ini9iti=iYi0iai^i]iijiiiiiiii[iiiiij.iiiiiiijjik iiijijijij jjj#jjDj jrj6jxjGjbjYjfjHj8j"jjjjj?@jjjjjjjjjjjjjjkjkk1kk8k7vk9kGkCkIkPkYkTk[k_kakxkkkkkkkkkkkkkkkkkkkkkkk}llll$l#l^lUlbljllllll~lhlslllllllllllllllllmMm6m+m=m8mm5m3mm mcmmdmZmymYmmommnn mmmmmmmmmmmmmmmmmn-nnn.nnrn_n>n#nkn+nvnMnnCn:nNn$nnn8nnnnnnnnnnnnnnnoAopLnnno?no1no2n?@o>onoozoxooooo[oomoo|oXoooofooooooooooooooop p opppoppotpppp0p>p2pQpcppppppppppp}pq pqqqeqUqqfqbqLqVqlqqqqqqqqqqqqqqqqqqqqr rrr(r-r,r0r2r;r?rFrKrXrtr~rrrrrrrrrrrrrrrrrrPss ssss4s/s)s%s>sNsWsjshspsxsus{szsssssssstttot%st2t:tUt?t_tYtAt\titptctjtvt~tttttts?@tttttttttuuuu uu uuuu&u,u<uDuMuJuIu[uFuZuiudugukumuxuvuutuuuuuuuuuuuuuuuuuuuuuuu}uvuuuv v v vv'v v$v4v0v;vGvFv\vXvavhvgvlvpvrvvvxv|vvvvvvvvvvvvvvvvvvvv/vwwww)w$ww%ww7wGwZwhwkw[weww~wywwwwwwwwwwwwwwwwwwwx xy&x y*xExxtxx|xxxxxxxxxxxxxxx?@xxxxyyyyy,y+y@y`yWy_yZyUySyzyyyyKyyyyyyyyyyzz zz zyz1z;z>z7zCzWzIzazizpzyz}zzzzzzzz}zzzzzzzzzzzzzzzz{{{ {{3{{{5{({6{P{z{{M{ {L{E{u{e{t{g{p{l{n{{{{{{{{{{]{{{{{{{{{||{{|`|||{{|| {|#|'|*||7|+|=|L|C|T|O|@|P|X|_|d|V|e|l|u|||||||||||||||||||||;|||||}?@}}}} }E}K}.}2}?}5}F}s}V}N}r}h}n}O}c}}}[}}}}}}}}}}}~=}}}}}}}}}}}}}~~ ~#~!~~1~~ ~ ~"~F~f~;~5~9~C~7}~2~:~g~]~V~^~Y~y~j~i~|~{~}~}~~~~~~~~~8:ELPUTX_hgxq !(?;JFRXZ_bhsrpvy}Q )#/K?@F>SQqnet_  )+83@YX]Z_d}bhj.qw~ 5421@9PE/+#|su  " 8m*<ZwkniF,oy5b!,@cXH?@AKUmw~  "0?MNUT_gq#}   4?7;%)`_xLNtWhnYScj "!169';DBRY^bk~u}r  C%*AD;68L`^?@fdmjotw~ %6A[RFH|mlb}  3&+>(ALONIV[Zk_lot}:A?HLNPUblxz|b  NgmqsB504J?@GILPHYd`*cUvr|  &3;9EB>LIFNW\}b!  '659OI>VX^hovr}bH20JVXceisr,^WEIdH?KPZD.?@"#:5;\`|nV6+5!:ARD[`b^j)puw}Z|~}o!(.BLOKw\^]_frlM $*09=DFHBI\`dfhRkqy|zOz 8$!7=FOKko?@qts !$ ,.=BIEPKQLU+7EB@C}>UM[W_bedikj"%'.2DCOMQXt:   .%$!0G2F>Z`gvx *&#DA?>FH?@]dQPYrozuy}a%v!,>JRTc_fljwrvX/iYtdQq?@~HOpf1hf_EN(NNOOO9OVOOOOOP@P"OPPFPpPBPPPQJQdQQQRRRRRSSS$SrSSSTTTTUWYWeWWW}XXY YSY[Y]YcYY[V[u/[[\\\\]']S]B]m]]_!_4_g__`]````a `aa7a0abbcd`ddeNfff;f f.ff$fefWfYfsfffffg)gfghRghhDhihiij0jkjFjsj~jjkl?l\llolmmmommmmmmn9n\n'n<noooppp(ppqqq\qFqqr?@rs$swssssstst&t*t)t.tbttuuovvvvvwFRx!xNxdxzy0yyzzz{}H}\}}}~RGbHSYmk 7y"Sv#$g&' :@<NYQ9gw'%!(pW1EH)3;CMOQUWe*',Nurpk- !pSpreadsheet-ParseExcel-0.66/META.json000644 000765 000024 00000002634 14543415026 017440 0ustar00Johnstaff000000 000000 { "abstract" : "Read information from an Excel file.", "author" : [ "John McNamara (jmcnamara@cpan.org)" ], "dynamic_config" : 1, "generated_by" : "ExtUtils::MakeMaker version 7.62, CPAN::Meta::Converter version 2.150010", "license" : [ "perl_5" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : 2 }, "name" : "Spreadsheet-ParseExcel", "no_index" : { "directory" : [ "t", "inc" ] }, "prereqs" : { "build" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "configure" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "runtime" : { "requires" : { "Crypt::RC4" : "0", "Digest::Perl::MD5" : "0", "IO::File" : "0", "IO::Scalar" : "0", "OLE::Storage_Lite" : "0.19", "Scalar::Util" : "0" } } }, "release_status" : "stable", "resources" : { "bugtracker" : { "web" : "http://github.com/jmcnamara/spreadsheet-parseexcel/issues" }, "homepage" : "http://github.com/jmcnamara/spreadsheet-parseexcel/", "repository" : { "url" : "http://github.com/jmcnamara/spreadsheet-parseexcel" } }, "version" : "0.66", "x_serialization_backend" : "JSON::PP version 4.06" } Spreadsheet-ParseExcel-0.66/lib/Spreadsheet/000755 000765 000024 00000000000 14543415025 021026 5ustar00Johnstaff000000 000000 Spreadsheet-ParseExcel-0.66/lib/Spreadsheet/ParseExcel/000755 000765 000024 00000000000 14543415025 023061 5ustar00Johnstaff000000 000000 Spreadsheet-ParseExcel-0.66/lib/Spreadsheet/ParseExcel.pm000644 000765 000024 00000337741 14543414145 023440 0ustar00Johnstaff000000 000000 package Spreadsheet::ParseExcel; ############################################################################## # # Spreadsheet::ParseExcel - Extract information from an Excel file. # # Copyright (c) 2014 Douglas Wilson # Copyright (c) 2009-2013 John McNamara # Copyright (c) 2006-2008 Gabor Szabo # Copyright (c) 2000-2008 Takanori Kawai # # perltidy with standard settings. # # Documentation after __END__ # use strict; use warnings; use 5.008; use OLE::Storage_Lite; use File::Basename qw(fileparse); use IO::File; use Config; use Crypt::RC4; use Digest::Perl::MD5; our $VERSION = '0.66'; use Spreadsheet::ParseExcel::Workbook; use Spreadsheet::ParseExcel::Worksheet; use Spreadsheet::ParseExcel::Font; use Spreadsheet::ParseExcel::Format; use Spreadsheet::ParseExcel::Cell; use Spreadsheet::ParseExcel::FmtDefault; my $currentbook; my @aColor = ( '000000', # 0x00 'FFFFFF', 'FFFFFF', 'FFFFFF', 'FFFFFF', 'FFFFFF', 'FFFFFF', 'FFFFFF', '000000', # 0x08 'FFFFFF', 'FF0000', '00FF00', '0000FF', 'FFFF00', 'FF00FF', '00FFFF', '800000', # 0x10 '008000', '000080', '808000', '800080', '008080', 'C0C0C0', '808080', '9999FF', # 0x18 '993366', 'FFFFCC', 'CCFFFF', '660066', 'FF8080', '0066CC', 'CCCCFF', '000080', # 0x20 'FF00FF', 'FFFF00', '00FFFF', '800080', '800000', '008080', '0000FF', '00CCFF', # 0x28 'CCFFFF', 'CCFFCC', 'FFFF99', '99CCFF', 'FF99CC', 'CC99FF', 'FFCC99', '3366FF', # 0x30 '33CCCC', '99CC00', 'FFCC00', 'FF9900', 'FF6600', '666699', '969696', '003366', # 0x38 '339966', '003300', '333300', '993300', '993366', '333399', '333333', '000000' # 0x40 ); use constant verExcel95 => 0x500; use constant verExcel97 => 0x600; use constant verBIFF2 => 0x00; use constant verBIFF3 => 0x02; use constant verBIFF4 => 0x04; use constant verBIFF5 => 0x08; use constant verBIFF8 => 0x18; use constant MS_BIFF_CRYPTO_NONE => 0; use constant MS_BIFF_CRYPTO_XOR => 1; use constant MS_BIFF_CRYPTO_RC4 => 2; use constant sizeof_BIFF_8_FILEPASS => ( 6 + 3 * 16 ); use constant REKEY_BLOCK => 0x400; # Error code for some of the common parsing errors. use constant ErrorNone => 0; use constant ErrorNoFile => 1; use constant ErrorNoExcelData => 2; use constant ErrorFileEncrypted => 3; # Color index for the 'auto' color use constant AutoColor => 64; our %error_strings = ( ErrorNone, '', # 0 ErrorNoFile, 'File not found', # 1 ErrorNoExcelData, 'No Excel data found in file', # 2 ErrorFileEncrypted, 'File is encrypted', # 3 ); our %ProcTbl = ( #Develpers' Kit P291 0x14 => \&_subHeader, # Header 0x15 => \&_subFooter, # Footer 0x18 => \&_subName, # NAME(?) 0x1A => \&_subVPageBreak, # Vertical Page Break 0x1B => \&_subHPageBreak, # Horizontal Page Break 0x22 => \&_subFlg1904, # 1904 Flag 0x26 => \&_subMargin, # Left Margin 0x27 => \&_subMargin, # Right Margin 0x28 => \&_subMargin, # Top Margin 0x29 => \&_subMargin, # Bottom Margin 0x2A => \&_subPrintHeaders, # Print Headers 0x2B => \&_subPrintGridlines, # Print Gridlines 0x3C => \&_subContinue, # Continue 0x3D => \&_subWindow1, # Window1 0x43 => \&_subXF, # XF for Excel < 4. 0x0443 => \&_subXF, # XF for Excel = 4. 0x862 => \&_subSheetLayout, # Sheet Layout 0x1B8 => \&_subHyperlink, # HYPERLINK #Develpers' Kit P292 0x55 => \&_subDefColWidth, # Consider 0x5C => \&_subWriteAccess, # WRITEACCESS 0x7D => \&_subColInfo, # Colinfo 0x7E => \&_subRK, # RK 0x81 => \&_subWSBOOL, # WSBOOL 0x83 => \&_subHcenter, # HCENTER 0x84 => \&_subVcenter, # VCENTER 0x85 => \&_subBoundSheet, # BoundSheet 0x92 => \&_subPalette, # Palette, fgp 0x99 => \&_subStandardWidth, # Standard Col #Develpers' Kit P293 0xA1 => \&_subSETUP, # SETUP 0xBD => \&_subMulRK, # MULRK 0xBE => \&_subMulBlank, # MULBLANK 0xD6 => \&_subRString, # RString #Develpers' Kit P294 0xE0 => \&_subXF, # ExTended Format 0xE5 => \&_subMergeArea, # MergeArea (Not Documented) 0xFC => \&_subSST, # Shared String Table 0xFD => \&_subLabelSST, # Label SST #Develpers' Kit P295 0x201 => \&_subBlank, # Blank 0x202 => \&_subInteger, # Integer(Not Documented) 0x203 => \&_subNumber, # Number 0x204 => \&_subLabel, # Label 0x205 => \&_subBoolErr, # BoolErr 0x207 => \&_subString, # STRING 0x208 => \&_subRow, # RowData 0x221 => \&_subArray, # Array (Consider) 0x225 => \&_subDefaultRowHeight, # Consider 0x31 => \&_subFont, # Font 0x231 => \&_subFont, # Font 0x27E => \&_subRK, # RK 0x41E => \&_subFormat, # Format 0x06 => \&_subFormula, # Formula 0x406 => \&_subFormula, # Formula 0x009 => \&_subBOF, # BOF(BIFF2) 0x209 => \&_subBOF, # BOF(BIFF3) 0x409 => \&_subBOF, # BOF(BIFF4) 0x809 => \&_subBOF, # BOF(BIFF5-8) ); our $BIGENDIAN; our $PREFUNC; our $_use_perlio; #------------------------------------------------------------------------------ # Spreadsheet::ParseExcel->new #------------------------------------------------------------------------------ sub new { my ( $class, %hParam ) = @_; if ( not defined $_use_perlio ) { if ( exists $Config{useperlio} && defined $Config{useperlio} && $Config{useperlio} eq "define" ) { $_use_perlio = 1; } else { $_use_perlio = 0; require IO::Scalar; import IO::Scalar; } } # Check ENDIAN(Little: Intel etc. BIG: Sparc etc) $BIGENDIAN = ( defined $hParam{Endian} ) ? $hParam{Endian} : ( unpack( "H08", pack( "L", 2 ) ) eq '02000000' ) ? 0 : 1; my $self = {}; bless $self, $class; $self->{GetContent} = \&_subGetContent; if ( $hParam{EventHandlers} ) { $self->SetEventHandlers( $hParam{EventHandlers} ); } else { $self->SetEventHandlers( \%ProcTbl ); } if ( $hParam{AddHandlers} ) { foreach my $sKey ( keys( %{ $hParam{AddHandlers} } ) ) { $self->SetEventHandler( $sKey, $hParam{AddHandlers}->{$sKey} ); } } $self->{CellHandler} = $hParam{CellHandler}; $self->{NotSetCell} = $hParam{NotSetCell}; $self->{Object} = $hParam{Object}; if ( defined $hParam{Password} ) { $self->{Password} = $hParam{Password}; } else { $self->{Password} = 'VelvetSweatshop'; } $self->{_error_status} = ErrorNone; return $self; } #------------------------------------------------------------------------------ # Spreadsheet::ParseExcel->SetEventHandler #------------------------------------------------------------------------------ sub SetEventHandler { my ( $self, $key, $sub_ref ) = @_; $self->{FuncTbl}->{$key} = $sub_ref; } #------------------------------------------------------------------------------ # Spreadsheet::ParseExcel->SetEventHandlers #------------------------------------------------------------------------------ sub SetEventHandlers { my ( $self, $rhTbl ) = @_; $self->{FuncTbl} = undef; foreach my $sKey ( keys %$rhTbl ) { $self->{FuncTbl}->{$sKey} = $rhTbl->{$sKey}; } } #------------------------------------------------------------------------------ # Decryption routines # based on sources of gnumeric (ms-biff.c ms-excel-read.c) #------------------------------------------------------------------------------ sub md5state { my ( $md5 ) = @_; my $s = ''; for ( my $i = 0 ; $i < 4 ; $i++ ) { my $v = $md5->{_state}[$i]; $s .= chr( $v & 0xff ); $s .= chr( ( $v >> 8 ) & 0xff ); $s .= chr( ( $v >> 16 ) & 0xff ); $s .= chr( ( $v >> 24 ) & 0xff ); } return $s; } sub MakeKey { my ( $block, $key, $valContext ) = @_; my $pwarray = "\0" x 64; substr( $pwarray, 0, 5 ) = substr( $valContext, 0, 5 ); substr( $pwarray, 5, 1 ) = chr( $block & 0xff ); substr( $pwarray, 6, 1 ) = chr( ( $block >> 8 ) & 0xff ); substr( $pwarray, 7, 1 ) = chr( ( $block >> 16 ) & 0xff ); substr( $pwarray, 8, 1 ) = chr( ( $block >> 24 ) & 0xff ); substr( $pwarray, 9, 1 ) = "\x80"; substr( $pwarray, 56, 1 ) = "\x48"; my $md5 = Digest::Perl::MD5->new(); $md5->add( $pwarray ); my $s = md5state( $md5 ); ${$key} = Crypt::RC4->new( $s ); } sub VerifyPassword { my ( $password, $docid, $salt_data, $hashedsalt_data, $valContext ) = @_; my $pwarray = "\0" x 64; my $i; my $md5 = Digest::Perl::MD5->new(); for ( $i = 0 ; $i < length( $password ) ; $i++ ) { my $o = ord( substr( $password, $i, 1 ) ); substr( $pwarray, 2 * $i, 1 ) = chr( $o & 0xff ); substr( $pwarray, 2 * $i + 1, 1 ) = chr( ( $o >> 8 ) & 0xff ); } substr( $pwarray, 2 * $i, 1 ) = chr( 0x80 ); substr( $pwarray, 56, 1 ) = chr( ( $i << 4 ) & 0xff ); $md5->add( $pwarray ); my $mdContext1 = md5state( $md5 ); my $offset = 0; my $keyoffset = 0; my $tocopy = 5; $md5->reset; while ( $offset != 16 ) { if ( ( 64 - $offset ) < 5 ) { $tocopy = 64 - $offset; } substr( $pwarray, $offset, $tocopy ) = substr( $mdContext1, $keyoffset, $tocopy ); $offset += $tocopy; if ( $offset == 64 ) { $md5->add( $pwarray ); $keyoffset = $tocopy; $tocopy = 5 - $tocopy; $offset = 0; next; } $keyoffset = 0; $tocopy = 5; substr( $pwarray, $offset, 16 ) = $docid; $offset += 16; } substr( $pwarray, 16, 1 ) = "\x80"; substr( $pwarray, 17, 47 ) = "\0" x 47; substr( $pwarray, 56, 1 ) = "\x80"; substr( $pwarray, 57, 1 ) = "\x0a"; $md5->add( $pwarray ); ${$valContext} = md5state( $md5 ); my $key; MakeKey( 0, \$key, ${$valContext} ); my $salt = $key->RC4( $salt_data ); my $hashedsalt = $key->RC4( $hashedsalt_data ); $salt .= "\x80" . "\0" x 47; substr( $salt, 56, 1 ) = "\x80"; $md5->reset; $md5->add( $salt ); my $mdContext2 = md5state( $md5 ); return ( $mdContext2 eq $hashedsalt ); } sub SkipBytes { my ( $q, $start, $count ) = @_; my $scratch = "\0" x REKEY_BLOCK; my $block; $block = int( ( $start + $count ) / REKEY_BLOCK ); if ( $block != $q->{block} ) { MakeKey( $q->{block} = $block, \$q->{rc4_key}, $q->{md5_ctxt} ); $count = ( $start + $count ) % REKEY_BLOCK; } $q->{rc4_key}->RC4( substr( $scratch, 0, $count ) ); return 1; } sub SetDecrypt { my ( $q, $version, $password ) = @_; if ( $q->{opcode} != 0x2f ) { return 0; } if ( $password eq '' ) { return 0; } # TODO old versions decryption #if (version < MS_BIFF_V8 || q->data[0] == 0) # return ms_biff_pre_biff8_query_set_decrypt (q, password); if ( $q->{length} != sizeof_BIFF_8_FILEPASS ) { return 0; } unless ( VerifyPassword( $password, substr( $q->{data}, 6, 16 ), substr( $q->{data}, 22, 16 ), substr( $q->{data}, 38, 16 ), \$q->{md5_ctxt} ) ) { return 0; } $q->{encryption} = MS_BIFF_CRYPTO_RC4; $q->{block} = -1; # The first record after FILEPASS seems to be unencrypted $q->{dont_decrypt_next_record} = 1; # Pretend to decrypt the entire stream up till this point, it was # encrypted, but do it anyway to keep the rc4 state in sync SkipBytes( $q, 0, $q->{streamPos} ); return 1; } sub InitStream { my ( $stream_data ) = @_; my %q; $q{opcode} = 0; $q{length} = 0; $q{data} = ''; $q{stream} = $stream_data; # data stream $q{streamLen} = length( $stream_data ); # stream length $q{streamPos} = 0; # stream position $q{encryption} = 0; $q{xor_key} = ''; $q{rc4_key} = ''; $q{md5_ctxt} = ''; $q{block} = 0; $q{dont_decrypt_next_record} = 0; return \%q; } sub QueryNext { my ( $q ) = @_; if ( $q->{streamPos} + 4 >= $q->{streamLen} ) { return 0; } my $data = substr( $q->{stream}, $q->{streamPos}, 4 ); ( $q->{opcode}, $q->{length} ) = unpack( 'v2', $data ); # No biff record should be larger than around 20,000. if ( $q->{length} >= 20000 ) { return 0; } if ( $q->{length} > 0 ) { $q->{data} = substr( $q->{stream}, $q->{streamPos} + 4, $q->{length} ); } else { $q->{data} = undef; $q->{dont_decrypt_next_record} = 1; } if ( $q->{encryption} == MS_BIFF_CRYPTO_RC4 ) { if ( $q->{dont_decrypt_next_record} ) { SkipBytes( $q, $q->{streamPos}, 4 + $q->{length} ); $q->{dont_decrypt_next_record} = 0; } else { my $pos = $q->{streamPos}; my $data = $q->{data}; my $len = $q->{length}; my $res = ''; # Pretend to decrypt header. SkipBytes( $q, $pos, 4 ); $pos += 4; while ( $q->{block} != int( ( $pos + $len ) / REKEY_BLOCK ) ) { my $step = REKEY_BLOCK - ( $pos % REKEY_BLOCK ); $res .= $q->{rc4_key}->RC4( substr( $data, 0, $step ) ); $data = substr( $data, $step ); $pos += $step; $len -= $step; MakeKey( ++$q->{block}, \$q->{rc4_key}, $q->{md5_ctxt} ); } $res .= $q->{rc4_key}->RC4( substr( $data, 0, $len ) ); $q->{data} = $res; } } elsif ( $q->{encryption} == MS_BIFF_CRYPTO_XOR ) { # not implemented return 0; } elsif ( $q->{encryption} == MS_BIFF_CRYPTO_NONE ) { } $q->{streamPos} += 4 + $q->{length}; return 1; } ############################################################################### # # Parse() # # Parse the Excel file and convert it into a tree of objects.. # sub parse { my ( $self, $source, $formatter ) = @_; my $workbook = Spreadsheet::ParseExcel::Workbook->new(); $currentbook = $workbook; $workbook->{SheetCount} = 0; $workbook->{CellHandler} = $self->{CellHandler}; $workbook->{NotSetCell} = $self->{NotSetCell}; $workbook->{Object} = $self->{Object}; $workbook->{aColor} = [ @aColor ]; my ( $biff_data, $data_length ) = $self->_get_content( $source, $workbook ); return undef if not $biff_data; if ( $formatter ) { $workbook->{FmtClass} = $formatter; } else { $workbook->{FmtClass} = Spreadsheet::ParseExcel::FmtDefault->new(); } # Parse the BIFF data. my $stream = InitStream( $biff_data ); while ( QueryNext( $stream ) ) { my $record = $stream->{opcode}; my $record_length = $stream->{length}; my $record_header = $stream->{data}; # If the file contains a FILEPASS record we assume that it is encrypted # and cannot be parsed. if ( $record == 0x002F ) { unless ( SetDecrypt( $stream, '', $self->{Password} ) ) { $self->{_error_status} = ErrorFileEncrypted; return undef; } } # Special case of a formula String with no string. if ( $workbook->{_PrevPos} && ( defined $self->{FuncTbl}->{$record} ) && ( $record != 0x207 ) ) { my $iPos = $workbook->{_PrevPos}; $workbook->{_PrevPos} = undef; my ( $row, $col, $format_index ) = @$iPos; _NewCell( $workbook, $row, $col, Kind => 'Formula String', Val => '', FormatNo => $format_index, Format => $workbook->{Format}[$format_index], Numeric => 0, Code => undef, Book => $workbook, ); } # If the BIFF record matches 0x0*09 then it is a BOF record. # We reset the _skip_chart flag to ensure we check the sheet type. if ( ( $record & 0xF0FF ) == 0x09 ) { $workbook->{_skip_chart} = 0; } if ( defined $self->{FuncTbl}->{$record} && !$workbook->{_skip_chart} ) { $self->{FuncTbl}->{$record} ->( $workbook, $record, $record_length, $record_header ); } $PREFUNC = $record if ( $record != 0x3C ); #Not Continue last if defined $workbook->{_ParseAbort}; } foreach my $worksheet (@{$workbook->{Worksheet}} ) { # Install hyperlinks into each cell # Range is undocumented for user; allows reuse of data if ($worksheet->{HyperLinks}) { foreach my $link (@{$worksheet->{HyperLinks}}) { for( my $row = $link->[3]; $row <= $link->[4]; $row++ ) { for( my $col = $link->[5]; $col <= $link->[6]; $col++ ) { $worksheet->{Cells}[$row][$col]{Hyperlink} = $link; } } } } } return $workbook; } ############################################################################### # # _get_content() # # Get the Excel BIFF content from the file or filehandle. # sub _get_content { my ( $self, $source, $workbook ) = @_; my ( $biff_data, $data_length ); # Reset the error status in case method is called more than once. $self->{_error_status} = ErrorNone; my $ref = ref($source); if ( $ref ) { if ( $ref eq 'SCALAR' ) { # Specified by a scalar buffer. ( $biff_data, $data_length ) = $self->{GetContent}->( $source ); } elsif ( $ref eq 'ARRAY' ) { # Specified by file content $workbook->{File} = undef; my $sData = join( '', @$source ); ( $biff_data, $data_length ) = $self->{GetContent}->( \$sData ); } else { # Assume filehandle # For CGI.pm (Light FileHandle) my $sBuff = ''; if ( eval { binmode( $source ) } ) { my $sWk; while ( read( $source, $sWk, 4096 ) ) { $sBuff .= $sWk; } } else { # Assume IO::Wrap or some other filehandle-like OO-only object my $sWk; # IO::Wrap does not implement binmode eval { $source->binmode() }; while ( $source->read( $sWk, 4096 ) ) { $sBuff .= $sWk; } } ( $biff_data, $data_length ) = $self->{GetContent}->( \$sBuff ); } } else { # Specified by filename . $workbook->{File} = $source; if ( !-e $source ) { $self->{_error_status} = ErrorNoFile; return undef; } ( $biff_data, $data_length ) = $self->{GetContent}->( $source ); } # If the read was successful return the data. if ( $data_length ) { return ( $biff_data, $data_length ); } else { $self->{_error_status} = ErrorNoExcelData; return undef; } } #------------------------------------------------------------------------------ # _subGetContent (for Spreadsheet::ParseExcel) #------------------------------------------------------------------------------ sub _subGetContent { my ( $sFile ) = @_; my $oOl = OLE::Storage_Lite->new( $sFile ); return ( undef, undef ) unless ( $oOl ); my @aRes = $oOl->getPpsSearch( [ OLE::Storage_Lite::Asc2Ucs( 'Book' ), OLE::Storage_Lite::Asc2Ucs( 'Workbook' ) ], 1, 1 ); return ( undef, undef ) if ( $#aRes < 0 ); #Hack from Herbert if ( $aRes[0]->{Data} ) { return ( $aRes[0]->{Data}, length( $aRes[0]->{Data} ) ); } #Same as OLE::Storage_Lite my $oIo; #1. $sFile is Ref of scalar if ( ref( $sFile ) eq 'SCALAR' ) { if ( $_use_perlio ) { open $oIo, "<", \$sFile; } else { $oIo = IO::Scalar->new; $oIo->open( $sFile ); } } #2. $sFile is a IO::Handle object elsif ( UNIVERSAL::isa( $sFile, 'IO::Handle' ) ) { $oIo = $sFile; binmode( $oIo ); } #3. $sFile is a simple filename string elsif ( !ref( $sFile ) ) { $oIo = IO::File->new; $oIo->open( "<$sFile" ) || return undef; binmode( $oIo ); } my $sWk; my $sBuff = ''; while ( $oIo->read( $sWk, 4096 ) ) { #4_096 has no special meanings $sBuff .= $sWk; } $oIo->close(); #Not Excel file (simple method) return ( undef, undef ) if ( substr( $sBuff, 0, 1 ) ne "\x09" ); return ( $sBuff, length( $sBuff ) ); } #------------------------------------------------------------------------------ # _subBOF (for Spreadsheet::ParseExcel) Developers' Kit : P303 #------------------------------------------------------------------------------ sub _subBOF { my ( $oBook, $bOp, $bLen, $sWk ) = @_; my ( $iVer, $iDt ) = unpack( "v2", $sWk ); #Workbook Global if ( $iDt == 0x0005 ) { $oBook->{Version} = unpack( "v", $sWk ); $oBook->{BIFFVersion} = ( $oBook->{Version} == verExcel95 ) ? verBIFF5 : verBIFF8; $oBook->{_CurSheet} = undef; $oBook->{_CurSheet_} = -1; } #Worksheet or Dialogsheet elsif ( $iDt != 0x0020 ) { #if($iDt == 0x0010) if ( defined $oBook->{_CurSheet_} ) { $oBook->{_CurSheet} = $oBook->{_CurSheet_} + 1; $oBook->{_CurSheet_}++; ( $oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{SheetVersion}, $oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{SheetType}, ) = unpack( "v2", $sWk ) if ( length( $sWk ) > 4 ); } else { $oBook->{BIFFVersion} = int( $bOp / 0x100 ); if ( ( $oBook->{BIFFVersion} == verBIFF2 ) || ( $oBook->{BIFFVersion} == verBIFF3 ) || ( $oBook->{BIFFVersion} == verBIFF4 ) ) { $oBook->{Version} = $oBook->{BIFFVersion}; $oBook->{_CurSheet} = 0; $oBook->{Worksheet}[ $oBook->{SheetCount} ] = Spreadsheet::ParseExcel::Worksheet->new( _Name => '', Name => '', _Book => $oBook, _SheetNo => $oBook->{SheetCount}, ); $oBook->{SheetCount}++; } } } else { # Set flag to ignore all chart records until we reach another BOF. $oBook->{_skip_chart} = 1; } } #------------------------------------------------------------------------------ # _subBlank (for Spreadsheet::ParseExcel) DK:P303 #------------------------------------------------------------------------------ sub _subBlank { my ( $oBook, $bOp, $bLen, $sWk ) = @_; my ( $iR, $iC, $iF ) = unpack( "v3", $sWk ); _NewCell( $oBook, $iR, $iC, Kind => 'BLANK', Val => '', FormatNo => $iF, Format => $oBook->{Format}[$iF], Numeric => 0, Code => undef, Book => $oBook, ); #2.MaxRow, MaxCol, MinRow, MinCol _SetDimension( $oBook, $iR, $iC, $iC ); } #------------------------------------------------------------------------------ # _subInteger (for Spreadsheet::ParseExcel) Not in DK #------------------------------------------------------------------------------ sub _subInteger { my ( $oBook, $bOp, $bLen, $sWk ) = @_; my ( $iR, $iC, $iF, $sTxt, $sDum ); ( $iR, $iC, $iF, $sDum, $sTxt ) = unpack( "v3cv", $sWk ); _NewCell( $oBook, $iR, $iC, Kind => 'INTEGER', Val => $sTxt, FormatNo => $iF, Format => $oBook->{Format}[$iF], Numeric => 0, Code => undef, Book => $oBook, ); #2.MaxRow, MaxCol, MinRow, MinCol _SetDimension( $oBook, $iR, $iC, $iC ); } #------------------------------------------------------------------------------ # _subNumber (for Spreadsheet::ParseExcel) : DK: P354 #------------------------------------------------------------------------------ sub _subNumber { my ( $oBook, $bOp, $bLen, $sWk ) = @_; my ( $iR, $iC, $iF ) = unpack( "v3", $sWk ); my $dVal = _convDval( substr( $sWk, 6, 8 ) ); _NewCell( $oBook, $iR, $iC, Kind => 'Number', Val => $dVal, FormatNo => $iF, Format => $oBook->{Format}[$iF], Numeric => 1, Code => undef, Book => $oBook, ); #2.MaxRow, MaxCol, MinRow, MinCol _SetDimension( $oBook, $iR, $iC, $iC ); } #------------------------------------------------------------------------------ # _convDval (for Spreadsheet::ParseExcel) #------------------------------------------------------------------------------ sub _convDval { my ( $sWk ) = @_; return unpack( "d", ( $BIGENDIAN ) ? pack( "c8", reverse( unpack( "c8", $sWk ) ) ) : $sWk ); } #------------------------------------------------------------------------------ # _subRString (for Spreadsheet::ParseExcel) DK:P405 #------------------------------------------------------------------------------ sub _subRString { my ( $oBook, $bOp, $bLen, $sWk ) = @_; my ( $iR, $iC, $iF, $iL, $sTxt ); ( $iR, $iC, $iF, $iL ) = unpack( "v4", $sWk ); $sTxt = substr( $sWk, 8, $iL ); #Has STRUN if ( length( $sWk ) > ( 8 + $iL ) ) { _NewCell( $oBook, $iR, $iC, Kind => 'RString', Val => $sTxt, FormatNo => $iF, Format => $oBook->{Format}[$iF], Numeric => 0, Code => '_native_', #undef, Book => $oBook, Rich => substr( $sWk, ( 8 + $iL ) + 1 ), ); } else { _NewCell( $oBook, $iR, $iC, Kind => 'RString', Val => $sTxt, FormatNo => $iF, Format => $oBook->{Format}[$iF], Numeric => 0, Code => '_native_', Book => $oBook, ); } #2.MaxRow, MaxCol, MinRow, MinCol _SetDimension( $oBook, $iR, $iC, $iC ); } #------------------------------------------------------------------------------ # _subBoolErr (for Spreadsheet::ParseExcel) DK:P306 #------------------------------------------------------------------------------ sub _subBoolErr { my ( $oBook, $bOp, $bLen, $sWk ) = @_; my ( $iR, $iC, $iF ) = unpack( "v3", $sWk ); my ( $iVal, $iFlg ) = unpack( "cc", substr( $sWk, 6, 2 ) ); my $sTxt = DecodeBoolErr( $iVal, $iFlg ); _NewCell( $oBook, $iR, $iC, Kind => 'BoolError', Val => $sTxt, FormatNo => $iF, Format => $oBook->{Format}[$iF], Numeric => 0, Code => undef, Book => $oBook, ); #2.MaxRow, MaxCol, MinRow, MinCol _SetDimension( $oBook, $iR, $iC, $iC ); } ############################################################################### # # _subRK() # # Decode the RK BIFF record. # sub _subRK { my ( $workbook, $biff_number, $length, $data ) = @_; my ( $row, $col, $format_index, $rk_number ) = unpack( 'vvvV', $data ); my $number = _decode_rk_number( $rk_number ); _NewCell( $workbook, $row, $col, Kind => 'RK', Val => $number, FormatNo => $format_index, Format => $workbook->{Format}->[$format_index], Numeric => 1, Code => undef, Book => $workbook, ); # Store the max and min row/col values. _SetDimension( $workbook, $row, $col, $col ); } #------------------------------------------------------------------------------ # _subArray (for Spreadsheet::ParseExcel) DK:P297 #------------------------------------------------------------------------------ sub _subArray { my ( $oBook, $bOp, $bLen, $sWk ) = @_; my ( $iBR, $iER, $iBC, $iEC ) = unpack( "v2c2", $sWk ); } #------------------------------------------------------------------------------ # _subFormula (for Spreadsheet::ParseExcel) DK:P336 #------------------------------------------------------------------------------ sub _subFormula { my ( $oBook, $bOp, $bLen, $sWk ) = @_; my ( $iR, $iC, $iF ) = unpack( "v3", $sWk ); my ( $iFlg ) = unpack( "v", substr( $sWk, 12, 2 ) ); if ( $iFlg == 0xFFFF ) { my ( $iKind ) = unpack( "c", substr( $sWk, 6, 1 ) ); my ( $iVal ) = unpack( "c", substr( $sWk, 8, 1 ) ); if ( ( $iKind == 1 ) or ( $iKind == 2 ) ) { my $sTxt = ( $iKind == 1 ) ? DecodeBoolErr( $iVal, 0 ) : DecodeBoolErr( $iVal, 1 ); _NewCell( $oBook, $iR, $iC, Kind => 'Formula Bool', Val => $sTxt, FormatNo => $iF, Format => $oBook->{Format}[$iF], Numeric => 0, Code => undef, Book => $oBook, ); } else { # Result (Reserve Only) $oBook->{_PrevPos} = [ $iR, $iC, $iF ]; } } else { my $dVal = _convDval( substr( $sWk, 6, 8 ) ); _NewCell( $oBook, $iR, $iC, Kind => 'Formula Number', Val => $dVal, FormatNo => $iF, Format => $oBook->{Format}[$iF], Numeric => 1, Code => undef, Book => $oBook, ); } #2.MaxRow, MaxCol, MinRow, MinCol _SetDimension( $oBook, $iR, $iC, $iC ); } #------------------------------------------------------------------------------ # _subString (for Spreadsheet::ParseExcel) DK:P414 #------------------------------------------------------------------------------ sub _subString { my ( $oBook, $bOp, $bLen, $sWk ) = @_; #Position (not enough for ARRAY) my $iPos = $oBook->{_PrevPos}; return undef unless ( $iPos ); $oBook->{_PrevPos} = undef; my ( $iR, $iC, $iF ) = @$iPos; my ( $iLen, $sTxt, $sCode ); if ( $oBook->{BIFFVersion} == verBIFF8 ) { my ( $raBuff, $iLen ) = _convBIFF8String( $oBook, $sWk, 1 ); $sTxt = $raBuff->[0]; $sCode = ( $raBuff->[1] ) ? 'ucs2' : undef; } elsif ( $oBook->{BIFFVersion} == verBIFF5 ) { $sCode = '_native_'; $iLen = unpack( "v", $sWk ); $sTxt = substr( $sWk, 2, $iLen ); } else { $sCode = '_native_'; $iLen = unpack( "c", $sWk ); $sTxt = substr( $sWk, 1, $iLen ); } _NewCell( $oBook, $iR, $iC, Kind => 'String', Val => $sTxt, FormatNo => $iF, Format => $oBook->{Format}[$iF], Numeric => 0, Code => $sCode, Book => $oBook, ); #2.MaxRow, MaxCol, MinRow, MinCol _SetDimension( $oBook, $iR, $iC, $iC ); } #------------------------------------------------------------------------------ # _subLabel (for Spreadsheet::ParseExcel) DK:P344 #------------------------------------------------------------------------------ sub _subLabel { my ( $oBook, $bOp, $bLen, $sWk ) = @_; my ( $iR, $iC, $iF ) = unpack( "v3", $sWk ); my ( $sLbl, $sCode ); #BIFF8 if ( $oBook->{BIFFVersion} >= verBIFF8 ) { my ( $raBuff, $iLen, $iStPos, $iLenS ) = _convBIFF8String( $oBook, substr( $sWk, 6 ), 1 ); $sLbl = $raBuff->[0]; $sCode = ( $raBuff->[1] ) ? 'ucs2' : undef; } #Before BIFF8 else { $sLbl = substr( $sWk, 8 ); $sCode = '_native_'; } _NewCell( $oBook, $iR, $iC, Kind => 'Label', Val => $sLbl, FormatNo => $iF, Format => $oBook->{Format}[$iF], Numeric => 0, Code => $sCode, Book => $oBook, ); #2.MaxRow, MaxCol, MinRow, MinCol _SetDimension( $oBook, $iR, $iC, $iC ); } ############################################################################### # # _subMulRK() # # Decode the Multiple RK BIFF record. # sub _subMulRK { my ( $workbook, $biff_number, $length, $data ) = @_; # JMN: I don't know why this is here. return if $workbook->{SheetCount} <= 0; my ( $row, $first_col ) = unpack( "v2", $data ); my $last_col = unpack( "v", substr( $data, length( $data ) - 2, 2 ) ); # Iterate over the RK array and decode the data. my $pos = 4; for my $col ( $first_col .. $last_col ) { my $data = substr( $data, $pos, 6 ); my ( $format_index, $rk_number ) = unpack 'vV', $data; my $number = _decode_rk_number( $rk_number ); _NewCell( $workbook, $row, $col, Kind => 'MulRK', Val => $number, FormatNo => $format_index, Format => $workbook->{Format}->[$format_index], Numeric => 1, Code => undef, Book => $workbook, ); $pos += 6; } # Store the max and min row/col values. _SetDimension( $workbook, $row, $first_col, $last_col ); } #------------------------------------------------------------------------------ # _subMulBlank (for Spreadsheet::ParseExcel) DK:P349 #------------------------------------------------------------------------------ sub _subMulBlank { my ( $oBook, $bOp, $bLen, $sWk ) = @_; my ( $iR, $iSc ) = unpack( "v2", $sWk ); my $iEc = unpack( "v", substr( $sWk, length( $sWk ) - 2, 2 ) ); my $iPos = 4; for ( my $iC = $iSc ; $iC <= $iEc ; $iC++ ) { my $iF = unpack( 'v', substr( $sWk, $iPos, 2 ) ); _NewCell( $oBook, $iR, $iC, Kind => 'MulBlank', Val => '', FormatNo => $iF, Format => $oBook->{Format}[$iF], Numeric => 0, Code => undef, Book => $oBook, ); $iPos += 2; } #2.MaxRow, MaxCol, MinRow, MinCol _SetDimension( $oBook, $iR, $iSc, $iEc ); } #------------------------------------------------------------------------------ # _subLabelSST (for Spreadsheet::ParseExcel) DK: P345 #------------------------------------------------------------------------------ sub _subLabelSST { my ( $oBook, $bOp, $bLen, $sWk ) = @_; my ( $iR, $iC, $iF, $iIdx ) = unpack( 'v3V', $sWk ); _NewCell( $oBook, $iR, $iC, Kind => 'PackedIdx', Val => $oBook->{PkgStr}[$iIdx]->{Text}, FormatNo => $iF, Format => $oBook->{Format}[$iF], Numeric => 0, Code => ( $oBook->{PkgStr}[$iIdx]->{Unicode} ) ? 'ucs2' : undef, Book => $oBook, Rich => $oBook->{PkgStr}[$iIdx]->{Rich}, ); #2.MaxRow, MaxCol, MinRow, MinCol _SetDimension( $oBook, $iR, $iC, $iC ); } #------------------------------------------------------------------------------ # _subFlg1904 (for Spreadsheet::ParseExcel) DK:P296 #------------------------------------------------------------------------------ sub _subFlg1904 { my ( $oBook, $bOp, $bLen, $sWk ) = @_; $oBook->{Flg1904} = unpack( "v", $sWk ); } #------------------------------------------------------------------------------ # _subRow (for Spreadsheet::ParseExcel) DK:P403 #------------------------------------------------------------------------------ sub _subRow { my ( $oBook, $bOp, $bLen, $sWk ) = @_; return undef unless ( defined $oBook->{_CurSheet} ); #0. Get Worksheet info (MaxRow, MaxCol, MinRow, MinCol) my ( $iR, $iSc, $iEc, $iHght, $undef1, $undef2, $iGr, $iXf ) = unpack( "v8", $sWk ); $iEc--; if ( $iGr & 0x20 ) { $oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{RowHidden}[$iR] = 1; } $oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{RowHeight}[$iR] = $iHght / 20; #2.MaxRow, MaxCol, MinRow, MinCol _SetDimension( $oBook, $iR, $iSc, $iEc ); } #------------------------------------------------------------------------------ # _SetDimension (for Spreadsheet::ParseExcel) #------------------------------------------------------------------------------ sub _SetDimension { my ( $oBook, $iR, $iSc, $iEc ) = @_; return undef unless ( defined $oBook->{_CurSheet} ); #2.MaxRow, MaxCol, MinRow, MinCol #2.1 MinRow $oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{MinRow} = $iR unless ( defined $oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{MinRow} ) and ( $oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{MinRow} <= $iR ); #2.2 MaxRow $oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{MaxRow} = $iR unless ( defined $oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{MaxRow} ) and ( $oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{MaxRow} > $iR ); #2.3 MinCol $oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{MinCol} = $iSc unless ( defined $oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{MinCol} ) and ( $oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{MinCol} <= $iSc ); #2.4 MaxCol $oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{MaxCol} = $iEc unless ( defined $oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{MaxCol} ) and ( $oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{MaxCol} > $iEc ); } #------------------------------------------------------------------------------ # _subDefaultRowHeight (for Spreadsheet::ParseExcel) DK: P318 #------------------------------------------------------------------------------ sub _subDefaultRowHeight { my ( $oBook, $bOp, $bLen, $sWk ) = @_; return undef unless ( defined $oBook->{_CurSheet} ); #1. RowHeight my ( $iDum, $iHght ) = unpack( "v2", $sWk ); $oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{DefRowHeight} = $iHght / 20; } #------------------------------------------------------------------------------ # _subStandardWidth(for Spreadsheet::ParseExcel) DK:P413 #------------------------------------------------------------------------------ sub _subStandardWidth { my ( $oBook, $bOp, $bLen, $sWk ) = @_; my $iW = unpack( "v", $sWk ); $oBook->{StandardWidth} = _convert_col_width( $oBook, $iW ); } ############################################################################### # # _subDefColWidth() # # Read the DEFCOLWIDTH Biff record. This gives the width in terms of chars # and is different from the width in the COLINFO record. # sub _subDefColWidth { my ( $self, $record, $length, $data ) = @_; my $width = unpack 'v', $data; # Adjustment for default Arial 10 width. $width = 8.43 if $width == 8; $self->{Worksheet}->[ $self->{_CurSheet} ]->{DefColWidth} = $width; } ############################################################################### # # _convert_col_width() # # Converts from the internal Excel column width units to user units seen in the # interface. It is first necessary to convert the internal width to pixels and # then to user units. The conversion is specific to a default font of Arial 10. # TODO, the conversion should be extended to other fonts and sizes. # sub _convert_col_width { my $self = shift; my $excel_width = shift; # Convert from Excel units to pixels (rounded up). my $pixels = int( 0.5 + $excel_width * 7 / 256 ); # Convert from pixels to user units. # The conversion is different for columns <= 1 user unit (12 pixels). my $user_width; if ( $pixels <= 12 ) { $user_width = $pixels / 12; } else { $user_width = ( $pixels - 5 ) / 7; } # Round up to 2 decimal places. $user_width = int( $user_width * 100 + 0.5 ) / 100; return $user_width; } #------------------------------------------------------------------------------ # _subColInfo (for Spreadsheet::ParseExcel) DK:P309 #------------------------------------------------------------------------------ sub _subColInfo { my ( $oBook, $bOp, $bLen, $sWk ) = @_; return undef unless defined $oBook->{_CurSheet}; my ( $iSc, $iEc, $iW, $iXF, $iGr ) = unpack( "v5", $sWk ); for ( my $i = $iSc ; $i <= $iEc ; $i++ ) { $oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{ColWidth}[$i] = _convert_col_width( $oBook, $iW ); $oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{ColFmtNo}[$i] = $iXF; if ( $iGr & 0x01 ) { $oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{ColHidden}[$i] = 1; } } } #------------------------------------------------------------------------------ # _subWindow1 Window information P 273 #------------------------------------------------------------------------------ sub _subWindow1 { my ( $workbook, $op, $len, $wk ) = @_; return if ( $workbook->{BIFFVersion} <= verBIFF4() ); my ( $hpos, $vpos, $width, $height, $options, $active, $firsttab, $numselected, $tabbarwidth ) = unpack( "v9", $wk ); $workbook->{ActiveSheet} = $active; } #------------------------------------------------------------------------------ # _subSheetLayout OpenOffice 5.96 (P207) #------------------------------------------------------------------------------ sub _subSheetLayout { my ( $workbook, $op, $len, $wk ) = @_; my @unused; ( my $rc, @unused[ 1 .. 10 ], @unused[ 11 .. 14 ], my $color, @unused[ 15, 16 ] ) = unpack( "vC10C4vC2", $wk ); return unless ( $rc == 0x0862 ); $workbook->{Worksheet}[ $workbook->{_CurSheet} ]->{TabColor} = $color; } #------------------------------------------------------------------------------ # _subHyperlink OpenOffice 5.96 (P182) # # Also see: http://msdn.microsoft.com/en-us/library/gg615407(v=office.14).aspx #------------------------------------------------------------------------------ # Helper: Extract a GID, returns as text string sub _getguid { my( $wk ) = @_; my( $text, $guidl, $guids1, $guids2, @guidb ); ( $guidl, $guids1, $guids2, @guidb[0..7] ) = unpack( 'Vv2C8', $wk ); $text = sprintf( '%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X', $guidl, $guids1, $guids2, @guidb); return $text; } # Helper: Extract a counted (16-bit) unicode string, returns string, # updates $offset # $zterm == 1 if string is null-terminated. # $bc if length is in bytes (not chars) sub _getustr { my( $wk, $offset, $zterm, $bc ) = @_; my $len = unpack( 'V', substr( $wk, $offset ) ); $offset += 4; if( $bc ) { $len /= 2; } $len -= $zterm; my $text = join( '', map { chr $_ } unpack( "v$len", substr( $wk, $offset ) ) ); $text =~ s/\0.*\z// if( $zterm ); $_[1] = ( $offset += ($len + $zterm) *2 ); return $text; } # HYPERLINK record sub _subHyperlink { my ( $workbook, $op, $len, $wk ) = @_; # REF my( $srow, $erow, $scol, $ecol ) = unpack( 'v4', $wk ); my $guid = _getguid( substr( $wk, 8 ) ); return unless( $guid eq '79EAC9D0-BAF9-11CE-8C82-00AA004BA90B' ); my( $stmvers, $flags ) = unpack( 'VV', substr( $wk, 24 ) ); return if( $flags & 0x60 || $stmvers != 2 ); my $offset = 32; my( $desc,$frame, $link, $mark ); if( ($flags & 0x14) == 0x14 ) { $desc = _getustr( $wk, $offset, 1, 0 ); } if( $flags & 0x80 ) { $frame = _getustr( $wk, $offset, 1, 0 ); } $link = ''; if( $flags & 0x100 ) { # UNC path $link = 'file:///' . _getustr( $wk, $offset, 1, 0 ); } elsif( $flags & 0x1 ) { # Has link (URI) $guid = _getguid( substr( $wk, $offset ) ); $offset += 16; if( $guid eq '79EAC9E0-BAF9-11CE-8C82-00AA004BA90B' ) { # URI $link = _getustr( $wk, $offset, 1, 1 ); } elsif( $guid eq '00000303-0000-0000-C000-000000000046' ) { # Local file $link = 'file:///'; # !($flags & 2) = 'relative path' if( !($flags & 0x2) ) { my $file = $workbook->{File}; if( defined $file && length $file ) { $link .= (fileparse($file))[1]; } else { $link .= '%REL%' } } my $dirn = unpack( 'v', substr( $wk, $offset ) ); $offset += 2; $link .= '..\\' x $dirn; my $namelen = unpack( 'V', substr( $wk, $offset ) ); $offset += 4; my $name = unpack( 'Z*', substr( $wk, $offset ) ); $offset += $namelen; $offset += 24; my $size = unpack( 'V', substr( $wk, $offset ) ); $offset += 4; if( $size ) { my $xlen = unpack( 'V', substr( $wk, $offset ) ) / 2; $name = join( '', map { chr $_} unpack( "v$xlen", substr( $wk, $offset+4+2) ) ); $offset += $size; } $link .= $name; } else { return; } } # Text mark (Fragment identifier) if( $flags & 0x8 ) { # Cellrefs contain reserved characters, so url-encode my $fragment = _getustr( $wk, $offset, 1 ); $fragment =~ s/([^\w.~-])/sprintf( '%%%02X', ord( $1 ) )/gems; $link .= '#' . $fragment; } # Update loop at end of parse() if this changes push @{ $workbook->{Worksheet}[ $workbook->{_CurSheet} ]->{HyperLinks} }, [ $desc, $link, $frame, $srow, $erow, $scol, $ecol ]; } #------------------------------------------------------------------------------ # _subSST (for Spreadsheet::ParseExcel) DK:P413 #------------------------------------------------------------------------------ sub _subSST { my ( $oBook, $bOp, $bLen, $sWk ) = @_; _subStrWk( $oBook, substr( $sWk, 8 ) ); } #------------------------------------------------------------------------------ # _subContinue (for Spreadsheet::ParseExcel) DK:P311 #------------------------------------------------------------------------------ sub _subContinue { my ( $oBook, $bOp, $bLen, $sWk ) = @_; #if(defined $self->{FuncTbl}->{$bOp}) { # $self->{FuncTbl}->{$PREFUNC}->($oBook, $bOp, $bLen, $sWk); #} _subStrWk( $oBook, $sWk, 1 ) if ( $PREFUNC == 0xFC ); } #------------------------------------------------------------------------------ # _subWriteAccess (for Spreadsheet::ParseExcel) DK:P451 #------------------------------------------------------------------------------ sub _subWriteAccess { my ( $oBook, $bOp, $bLen, $sWk ) = @_; return if ( defined $oBook->{_Author} ); #BIFF8 if ( $oBook->{BIFFVersion} >= verBIFF8 ) { $oBook->{Author} = _convBIFF8String( $oBook, $sWk ); } #Before BIFF8 else { my ( $iLen ) = unpack( "c", $sWk ); $oBook->{Author} = $oBook->{FmtClass}->TextFmt( substr( $sWk, 1, $iLen ), '_native_' ); } } #------------------------------------------------------------------------------ # _convBIFF8String (for Spreadsheet::ParseExcel) #------------------------------------------------------------------------------ sub _convBIFF8String { my ( $oBook, $sWk, $iCnvFlg ) = @_; my ( $iLen, $iFlg ) = unpack( "vc", $sWk ); my ( $iHigh, $iExt, $iRich ) = ( $iFlg & 0x01, $iFlg & 0x04, $iFlg & 0x08 ); my ( $iStPos, $iExtCnt, $iRichCnt, $sStr ); #2. Rich and Ext if ( $iRich && $iExt ) { $iStPos = 9; ( $iRichCnt, $iExtCnt ) = unpack( 'vV', substr( $sWk, 3, 6 ) ); } elsif ( $iRich ) { #Only Rich $iStPos = 5; $iRichCnt = unpack( 'v', substr( $sWk, 3, 2 ) ); $iExtCnt = 0; } elsif ( $iExt ) { #Only Ext $iStPos = 7; $iRichCnt = 0; $iExtCnt = unpack( 'V', substr( $sWk, 3, 4 ) ); } else { #Nothing Special $iStPos = 3; $iExtCnt = 0; $iRichCnt = 0; } #3.Get String if ( $iHigh ) { #Compressed $iLen *= 2; $sStr = substr( $sWk, $iStPos, $iLen ); _SwapForUnicode( \$sStr ); $sStr = $oBook->{FmtClass}->TextFmt( $sStr, 'ucs2' ) unless ( $iCnvFlg ); } else { #Not Compressed $sStr = substr( $sWk, $iStPos, $iLen ); $sStr = $oBook->{FmtClass}->TextFmt( $sStr, undef ) unless ( $iCnvFlg ); } #4. return if ( wantarray ) { #4.1 Get Rich and Ext if ( length( $sWk ) < $iStPos + $iLen + $iRichCnt * 4 + $iExtCnt ) { return ( [ undef, $iHigh, undef, undef ], $iStPos + $iLen + $iRichCnt * 4 + $iExtCnt, $iStPos, $iLen ); } else { return ( [ $sStr, $iHigh, substr( $sWk, $iStPos + $iLen, $iRichCnt * 4 ), substr( $sWk, $iStPos + $iLen + $iRichCnt * 4, $iExtCnt ) ], $iStPos + $iLen + $iRichCnt * 4 + $iExtCnt, $iStPos, $iLen ); } } else { return $sStr; } } #------------------------------------------------------------------------------ # _subXF (for Spreadsheet::ParseExcel) DK:P453 #------------------------------------------------------------------------------ sub _subXF { my ( $oBook, $bOp, $bLen, $sWk ) = @_; my ( $iFnt, $iIdx ); my ( $iLock, $iHidden, $iStyle, $i123, $iAlH, $iWrap, $iAlV, $iJustL, $iRotate, $iInd, $iShrink, $iMerge, $iReadDir, $iBdrD, $iBdrSL, $iBdrSR, $iBdrST, $iBdrSB, $iBdrSD, $iBdrCL, $iBdrCR, $iBdrCT, $iBdrCB, $iBdrCD, $iFillP, $iFillCF, $iFillCB ); if ( $oBook->{BIFFVersion} == verBIFF4 ) { # Minimal support for Excel 4. We just get the font and format indices # so that the cell data value can be formatted. ( $iFnt, $iIdx, ) = unpack( "CC", $sWk ); } elsif ( $oBook->{BIFFVersion} == verBIFF8 ) { my ( $iGen, $iAlign, $iGen2, $iBdr1, $iBdr2, $iBdr3, $iPtn ); ( $iFnt, $iIdx, $iGen, $iAlign, $iGen2, $iBdr1, $iBdr2, $iBdr3, $iPtn ) = unpack( "v7Vv", $sWk ); $iLock = ( $iGen & 0x01 ) ? 1 : 0; $iHidden = ( $iGen & 0x02 ) ? 1 : 0; $iStyle = ( $iGen & 0x04 ) ? 1 : 0; $i123 = ( $iGen & 0x08 ) ? 1 : 0; $iAlH = ( $iAlign & 0x07 ); $iWrap = ( $iAlign & 0x08 ) ? 1 : 0; $iAlV = ( $iAlign & 0x70 ) / 0x10; $iJustL = ( $iAlign & 0x80 ) ? 1 : 0; $iRotate = ( ( $iAlign & 0xFF00 ) / 0x100 ) & 0x00FF; $iRotate = 90 if ( $iRotate == 255 ); $iRotate = 90 - $iRotate if ( $iRotate > 90 ); $iInd = ( $iGen2 & 0x0F ); $iShrink = ( $iGen2 & 0x10 ) ? 1 : 0; $iMerge = ( $iGen2 & 0x20 ) ? 1 : 0; $iReadDir = ( ( $iGen2 & 0xC0 ) / 0x40 ) & 0x03; $iBdrSL = $iBdr1 & 0x0F; $iBdrSR = ( ( $iBdr1 & 0xF0 ) / 0x10 ) & 0x0F; $iBdrST = ( ( $iBdr1 & 0xF00 ) / 0x100 ) & 0x0F; $iBdrSB = ( ( $iBdr1 & 0xF000 ) / 0x1000 ) & 0x0F; $iBdrCL = ( ( $iBdr2 & 0x7F ) ) & 0x7F; $iBdrCR = ( ( $iBdr2 & 0x3F80 ) / 0x80 ) & 0x7F; $iBdrD = ( ( $iBdr2 & 0xC000 ) / 0x4000 ) & 0x3; $iBdrCT = ( ( $iBdr3 & 0x7F ) ) & 0x7F; $iBdrCB = ( ( $iBdr3 & 0x3F80 ) / 0x80 ) & 0x7F; $iBdrCD = ( ( $iBdr3 & 0x1FC000 ) / 0x4000 ) & 0x7F; $iBdrSD = ( ( $iBdr3 & 0x1E00000 ) / 0x200000 ) & 0xF; $iFillP = ( ( $iBdr3 & 0xFC000000 ) / 0x4000000 ) & 0x3F; $iFillCF = ( $iPtn & 0x7F ); $iFillCB = ( ( $iPtn & 0x3F80 ) / 0x80 ) & 0x7F; } else { my ( $iGen, $iAlign, $iPtn, $iPtn2, $iBdr1, $iBdr2 ); ( $iFnt, $iIdx, $iGen, $iAlign, $iPtn, $iPtn2, $iBdr1, $iBdr2 ) = unpack( "v8", $sWk ); $iLock = ( $iGen & 0x01 ) ? 1 : 0; $iHidden = ( $iGen & 0x02 ) ? 1 : 0; $iStyle = ( $iGen & 0x04 ) ? 1 : 0; $i123 = ( $iGen & 0x08 ) ? 1 : 0; $iAlH = ( $iAlign & 0x07 ); $iWrap = ( $iAlign & 0x08 ) ? 1 : 0; $iAlV = ( $iAlign & 0x70 ) / 0x10; $iJustL = ( $iAlign & 0x80 ) ? 1 : 0; $iRotate = ( ( $iAlign & 0x300 ) / 0x100 ) & 0x3; $iFillCF = ( $iPtn & 0x7F ); $iFillCB = ( ( $iPtn & 0x1F80 ) / 0x80 ) & 0x7F; $iFillP = ( $iPtn2 & 0x3F ); $iBdrSB = ( ( $iPtn2 & 0x1C0 ) / 0x40 ) & 0x7; $iBdrCB = ( ( $iPtn2 & 0xFE00 ) / 0x200 ) & 0x7F; $iBdrST = ( $iBdr1 & 0x07 ); $iBdrSL = ( ( $iBdr1 & 0x38 ) / 0x8 ) & 0x07; $iBdrSR = ( ( $iBdr1 & 0x1C0 ) / 0x40 ) & 0x07; $iBdrCT = ( ( $iBdr1 & 0xFE00 ) / 0x200 ) & 0x7F; $iBdrCL = ( $iBdr2 & 0x7F ) & 0x7F; $iBdrCR = ( ( $iBdr2 & 0x3F80 ) / 0x80 ) & 0x7F; } push @{ $oBook->{Format} }, Spreadsheet::ParseExcel::Format->new( FontNo => $iFnt, Font => $oBook->{Font}[$iFnt], FmtIdx => $iIdx, Lock => $iLock, Hidden => $iHidden, Style => $iStyle, Key123 => $i123, AlignH => $iAlH, Wrap => $iWrap, AlignV => $iAlV, JustLast => $iJustL, Rotate => $iRotate, Indent => $iInd, Shrink => $iShrink, Merge => $iMerge, ReadDir => $iReadDir, BdrStyle => [ $iBdrSL, $iBdrSR, $iBdrST, $iBdrSB ], BdrColor => [ $iBdrCL, $iBdrCR, $iBdrCT, $iBdrCB ], BdrDiag => [ $iBdrD, $iBdrSD, $iBdrCD ], Fill => [ $iFillP, $iFillCF, $iFillCB ], ); } #------------------------------------------------------------------------------ # _subFormat (for Spreadsheet::ParseExcel) DK: P336 #------------------------------------------------------------------------------ sub _subFormat { my ( $oBook, $bOp, $bLen, $sWk ) = @_; my $sFmt; if ( $oBook->{BIFFVersion} <= verBIFF5 ) { $sFmt = substr( $sWk, 3, unpack( 'c', substr( $sWk, 2, 1 ) ) ); $sFmt = $oBook->{FmtClass}->TextFmt( $sFmt, '_native_' ); } else { $sFmt = _convBIFF8String( $oBook, substr( $sWk, 2 ) ); } my $format_index = unpack( 'v', substr( $sWk, 0, 2 ) ); # Excel 4 and earlier used an index of 0 to indicate that a built-in format # that was stored implicitly. if ( $oBook->{BIFFVersion} <= verBIFF4 && $format_index == 0 ) { $format_index = keys %{ $oBook->{FormatStr} }; } $oBook->{FormatStr}->{$format_index} = $sFmt; } #------------------------------------------------------------------------------ # _subPalette (for Spreadsheet::ParseExcel) DK: P393 #------------------------------------------------------------------------------ sub _subPalette { my ( $oBook, $bOp, $bLen, $sWk ) = @_; for ( my $i = 0 ; $i < unpack( 'v', $sWk ) ; $i++ ) { # push @aColor, unpack('H6', substr($sWk, $i*4+2)); $oBook->{aColor}[ $i + 8 ] = unpack( 'H6', substr( $sWk, $i * 4 + 2 ) ); } } #------------------------------------------------------------------------------ # _subFont (for Spreadsheet::ParseExcel) DK:P333 #------------------------------------------------------------------------------ sub _subFont { my ( $oBook, $bOp, $bLen, $sWk ) = @_; my ( $iHeight, $iAttr, $iCIdx, $iBold, $iSuper, $iUnderline, $sFntName ); my ( $bBold, $bItalic, $bUnderline, $bStrikeout ); if ( $oBook->{BIFFVersion} == verBIFF8 ) { ( $iHeight, $iAttr, $iCIdx, $iBold, $iSuper, $iUnderline ) = unpack( "v5c", $sWk ); my ( $iSize, $iHigh ) = unpack( 'cc', substr( $sWk, 14, 2 ) ); if ( $iHigh ) { $sFntName = substr( $sWk, 16, $iSize * 2 ); _SwapForUnicode( \$sFntName ); $sFntName = $oBook->{FmtClass}->TextFmt( $sFntName, 'ucs2' ); } else { $sFntName = substr( $sWk, 16, $iSize ); $sFntName = $oBook->{FmtClass}->TextFmt( $sFntName, '_native_' ); } $bBold = ( $iBold >= 0x2BC ) ? 1 : 0; $bItalic = ( $iAttr & 0x02 ) ? 1 : 0; $bStrikeout = ( $iAttr & 0x08 ) ? 1 : 0; $bUnderline = ( $iUnderline ) ? 1 : 0; } elsif ( $oBook->{BIFFVersion} == verBIFF5 ) { ( $iHeight, $iAttr, $iCIdx, $iBold, $iSuper, $iUnderline ) = unpack( "v5c", $sWk ); $sFntName = $oBook->{FmtClass} ->TextFmt( substr( $sWk, 15, unpack( "c", substr( $sWk, 14, 1 ) ) ), '_native_' ); $bBold = ( $iBold >= 0x2BC ) ? 1 : 0; $bItalic = ( $iAttr & 0x02 ) ? 1 : 0; $bStrikeout = ( $iAttr & 0x08 ) ? 1 : 0; $bUnderline = ( $iUnderline ) ? 1 : 0; } else { ( $iHeight, $iAttr ) = unpack( "v2", $sWk ); $iCIdx = undef; $iSuper = 0; $bBold = ( $iAttr & 0x01 ) ? 1 : 0; $bItalic = ( $iAttr & 0x02 ) ? 1 : 0; $bUnderline = ( $iAttr & 0x04 ) ? 1 : 0; $bStrikeout = ( $iAttr & 0x08 ) ? 1 : 0; $sFntName = substr( $sWk, 5, unpack( "c", substr( $sWk, 4, 1 ) ) ); } push @{ $oBook->{Font} }, Spreadsheet::ParseExcel::Font->new( Height => $iHeight / 20.0, Attr => $iAttr, Color => $iCIdx, Super => $iSuper, UnderlineStyle => $iUnderline, Name => $sFntName, Bold => $bBold, Italic => $bItalic, Underline => $bUnderline, Strikeout => $bStrikeout, ); #Skip Font[4] push @{ $oBook->{Font} }, {} if ( scalar( @{ $oBook->{Font} } ) == 4 ); } #------------------------------------------------------------------------------ # _subBoundSheet (for Spreadsheet::ParseExcel): DK: P307 #------------------------------------------------------------------------------ sub _subBoundSheet { my ( $oBook, $bOp, $bLen, $sWk ) = @_; my ( $iPos, $iGr, $iKind ) = unpack( "Lc2", $sWk ); $iKind &= 0x0F; return if ( ( $iKind != 0x00 ) && ( $iKind != 0x01 ) ); if ( $oBook->{BIFFVersion} >= verBIFF8 ) { my ( $iSize, $iUni ) = unpack( "cc", substr( $sWk, 6, 2 ) ); my $sWsName = substr( $sWk, 8 ); if ( $iUni & 0x01 ) { _SwapForUnicode( \$sWsName ); $sWsName = $oBook->{FmtClass}->TextFmt( $sWsName, 'ucs2' ); } $oBook->{Worksheet}[ $oBook->{SheetCount} ] = Spreadsheet::ParseExcel::Worksheet->new( Name => $sWsName, Kind => $iKind, _Pos => $iPos, _Book => $oBook, _SheetNo => $oBook->{SheetCount}, SheetHidden => $iGr & 0x03 ); } else { $oBook->{Worksheet}[ $oBook->{SheetCount} ] = Spreadsheet::ParseExcel::Worksheet->new( Name => $oBook->{FmtClass}->TextFmt( substr( $sWk, 7 ), '_native_' ), Kind => $iKind, _Pos => $iPos, _Book => $oBook, _SheetNo => $oBook->{SheetCount}, SheetHidden => $iGr & 0x03 ); } $oBook->{SheetCount}++; } #------------------------------------------------------------------------------ # _subHeader (for Spreadsheet::ParseExcel) DK: P340 #------------------------------------------------------------------------------ sub _subHeader { my ( $oBook, $bOp, $bLen, $sWk ) = @_; return undef unless ( defined $oBook->{_CurSheet} ); my $sW; if ( !defined $sWk ) { $oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{Header} = undef; return; } #BIFF8 if ( $oBook->{BIFFVersion} >= verBIFF8 ) { $sW = _convBIFF8String( $oBook, $sWk ); $oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{Header} = ( $sW eq "\x00" ) ? undef : $sW; } #Before BIFF8 else { my ( $iLen ) = unpack( "c", $sWk ); $sW = $oBook->{FmtClass}->TextFmt( substr( $sWk, 1, $iLen ), '_native_' ); $oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{Header} = ( $sW eq "\x00\x00\x00" ) ? undef : $sW; } } #------------------------------------------------------------------------------ # _subFooter (for Spreadsheet::ParseExcel) DK: P335 #------------------------------------------------------------------------------ sub _subFooter { my ( $oBook, $bOp, $bLen, $sWk ) = @_; return undef unless ( defined $oBook->{_CurSheet} ); my $sW; if ( !defined $sWk ) { $oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{Footer} = undef; return; } #BIFF8 if ( $oBook->{BIFFVersion} >= verBIFF8 ) { $sW = _convBIFF8String( $oBook, $sWk ); $oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{Footer} = ( $sW eq "\x00" ) ? undef : $sW; } #Before BIFF8 else { my ( $iLen ) = unpack( "c", $sWk ); $sW = $oBook->{FmtClass}->TextFmt( substr( $sWk, 1, $iLen ), '_native_' ); $oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{Footer} = ( $sW eq "\x00\x00\x00" ) ? undef : $sW; } } #------------------------------------------------------------------------------ # _subHPageBreak (for Spreadsheet::ParseExcel) DK: P341 #------------------------------------------------------------------------------ sub _subHPageBreak { my ( $oBook, $bOp, $bLen, $sWk ) = @_; my @aBreak; my $iCnt = unpack( "v", $sWk ); return undef unless ( defined $oBook->{_CurSheet} ); #BIFF8 if ( $oBook->{BIFFVersion} >= verBIFF8 ) { for ( my $i = 0 ; $i < $iCnt ; $i++ ) { my ( $iRow, $iColB, $iColE ) = unpack( 'v3', substr( $sWk, 2 + $i * 6, 6 ) ); # push @aBreak, [$iRow, $iColB, $iColE]; push @aBreak, $iRow; } } #Before BIFF8 else { for ( my $i = 0 ; $i < $iCnt ; $i++ ) { my ( $iRow ) = unpack( 'v', substr( $sWk, 2 + $i * 2, 2 ) ); push @aBreak, $iRow; # push @aBreak, [$iRow, 0, 255]; } } @aBreak = sort { $a <=> $b } @aBreak; $oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{HPageBreak} = \@aBreak; } #------------------------------------------------------------------------------ # _subVPageBreak (for Spreadsheet::ParseExcel) DK: P447 #------------------------------------------------------------------------------ sub _subVPageBreak { my ( $oBook, $bOp, $bLen, $sWk ) = @_; return undef unless ( defined $oBook->{_CurSheet} ); my @aBreak; my $iCnt = unpack( "v", $sWk ); #BIFF8 if ( $oBook->{BIFFVersion} >= verBIFF8 ) { for ( my $i = 0 ; $i < $iCnt ; $i++ ) { my ( $iCol, $iRowB, $iRowE ) = unpack( 'v3', substr( $sWk, 2 + $i * 6, 6 ) ); push @aBreak, $iCol; # push @aBreak, [$iCol, $iRowB, $iRowE]; } } #Before BIFF8 else { for ( my $i = 0 ; $i < $iCnt ; $i++ ) { my ( $iCol ) = unpack( 'v', substr( $sWk, 2 + $i * 2, 2 ) ); push @aBreak, $iCol; # push @aBreak, [$iCol, 0, 65535]; } } @aBreak = sort { $a <=> $b } @aBreak; $oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{VPageBreak} = \@aBreak; } #------------------------------------------------------------------------------ # _subMargin (for Spreadsheet::ParseExcel) DK: P306, 345, 400, 440 #------------------------------------------------------------------------------ sub _subMargin { my ( $oBook, $bOp, $bLen, $sWk ) = @_; return undef unless ( defined $oBook->{_CurSheet} ); # The "Mergin" options are a workaround for a backward compatible typo. my $dWk = _convDval( substr( $sWk, 0, 8 ) ); if ( $bOp == 0x26 ) { $oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{LeftMergin} = $dWk; $oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{LeftMargin} = $dWk; } elsif ( $bOp == 0x27 ) { $oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{RightMergin} = $dWk; $oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{RightMargin} = $dWk; } elsif ( $bOp == 0x28 ) { $oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{TopMergin} = $dWk; $oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{TopMargin} = $dWk; } elsif ( $bOp == 0x29 ) { $oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{BottomMergin} = $dWk; $oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{BottomMargin} = $dWk; } } #------------------------------------------------------------------------------ # _subHcenter (for Spreadsheet::ParseExcel) DK: P340 #------------------------------------------------------------------------------ sub _subHcenter { my ( $oBook, $bOp, $bLen, $sWk ) = @_; return undef unless ( defined $oBook->{_CurSheet} ); my $iWk = unpack( "v", $sWk ); $oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{HCenter} = $iWk; } #------------------------------------------------------------------------------ # _subVcenter (for Spreadsheet::ParseExcel) DK: P447 #------------------------------------------------------------------------------ sub _subVcenter { my ( $oBook, $bOp, $bLen, $sWk ) = @_; return undef unless ( defined $oBook->{_CurSheet} ); my $iWk = unpack( "v", $sWk ); $oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{VCenter} = $iWk; } #------------------------------------------------------------------------------ # _subPrintGridlines (for Spreadsheet::ParseExcel) DK: P397 #------------------------------------------------------------------------------ sub _subPrintGridlines { my ( $oBook, $bOp, $bLen, $sWk ) = @_; return undef unless ( defined $oBook->{_CurSheet} ); my $iWk = unpack( "v", $sWk ); $oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{PrintGrid} = $iWk; } #------------------------------------------------------------------------------ # _subPrintHeaders (for Spreadsheet::ParseExcel) DK: P397 #------------------------------------------------------------------------------ sub _subPrintHeaders { my ( $oBook, $bOp, $bLen, $sWk ) = @_; return undef unless ( defined $oBook->{_CurSheet} ); my $iWk = unpack( "v", $sWk ); $oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{PrintHeaders} = $iWk; } #------------------------------------------------------------------------------ # _subSETUP (for Spreadsheet::ParseExcel) DK: P409 #------------------------------------------------------------------------------ sub _subSETUP { my ( $oBook, $bOp, $bLen, $sWk ) = @_; return undef unless ( defined $oBook->{_CurSheet} ); # Workaround for some apps and older Excels that don't write a # complete SETUP record. return undef if $bLen != 34; my $oWkS = $oBook->{Worksheet}[ $oBook->{_CurSheet} ]; my $iGrBit; ( $oWkS->{PaperSize}, $oWkS->{Scale}, $oWkS->{PageStart}, $oWkS->{FitWidth}, $oWkS->{FitHeight}, $iGrBit, $oWkS->{Res}, $oWkS->{VRes}, ) = unpack( 'v8', $sWk ); $oWkS->{HeaderMargin} = _convDval( substr( $sWk, 16, 8 ) ); $oWkS->{FooterMargin} = _convDval( substr( $sWk, 24, 8 ) ); $oWkS->{Copis} = unpack( 'v2', substr( $sWk, 32, 2 ) ); $oWkS->{LeftToRight} = ( ( $iGrBit & 0x01 ) ? 1 : 0 ); $oWkS->{Landscape} = ( ( $iGrBit & 0x02 ) ? 1 : 0 ); $oWkS->{NoPls} = ( ( $iGrBit & 0x04 ) ? 1 : 0 ); $oWkS->{NoColor} = ( ( $iGrBit & 0x08 ) ? 1 : 0 ); $oWkS->{Draft} = ( ( $iGrBit & 0x10 ) ? 1 : 0 ); $oWkS->{Notes} = ( ( $iGrBit & 0x20 ) ? 1 : 0 ); $oWkS->{NoOrient} = ( ( $iGrBit & 0x40 ) ? 1 : 0 ); $oWkS->{UsePage} = ( ( $iGrBit & 0x80 ) ? 1 : 0 ); # The NoPls flag indicates that the values have not been taken from an # actual printer and thus may not be accurate. # Set default scale if NoPls otherwise it may be an invalid value of 0XFF. $oWkS->{Scale} = 100 if $oWkS->{NoPls}; # Workaround for a backward compatible typo. $oWkS->{HeaderMergin} = $oWkS->{HeaderMargin}; $oWkS->{FooterMergin} = $oWkS->{FooterMargin}; } #------------------------------------------------------------------------------ # _subName (for Spreadsheet::ParseExcel) DK: P350 #------------------------------------------------------------------------------ sub _subName { my ( $oBook, $bOp, $bLen, $sWk ) = @_; my ( $iGrBit, $cKey, $cCh, $iCce, $ixAls, $iTab, $cchCust, $cchDsc, $cchHep, $cchStatus ) = unpack( 'vc2v3c4', $sWk ); #Builtin Name + Length == 1 if ( ( $iGrBit & 0x20 ) && ( $cCh == 1 ) ) { #BIFF8 if ( $oBook->{BIFFVersion} >= verBIFF8 ) { my $iName = unpack( 'n', substr( $sWk, 14 ) ); my $iSheet = unpack( 'v', substr( $sWk, 8 ) ) - 1; # Workaround for mal-formed Excel workbooks where Print_Title is # set as Global (i.e. itab = 0). Note, this will have to be # treated differently when we get around to handling global names. return undef if $iSheet == -1; if ( $iName == 6 ) { #PrintArea my ( $iSheetW, $raArea ) = _ParseNameArea( substr( $sWk, 16 ) ); $oBook->{PrintArea}[$iSheet] = $raArea; } elsif ( $iName == 7 ) { #Title my ( $iSheetW, $raArea ) = _ParseNameArea( substr( $sWk, 16 ) ); my @aTtlR = (); my @aTtlC = (); foreach my $raI ( @$raArea ) { if ( $raI->[3] == 0xFF ) { #Row Title push @aTtlR, [ $raI->[0], $raI->[2] ]; } else { #Col Title push @aTtlC, [ $raI->[1], $raI->[3] ]; } } $oBook->{PrintTitle}[$iSheet] = { Row => \@aTtlR, Column => \@aTtlC }; } } else { my $iName = unpack( 'c', substr( $sWk, 14 ) ); if ( $iName == 6 ) { #PrintArea my ( $iSheet, $raArea ) = _ParseNameArea95( substr( $sWk, 15 ) ); $oBook->{PrintArea}[$iSheet] = $raArea; } elsif ( $iName == 7 ) { #Title my ( $iSheet, $raArea ) = _ParseNameArea95( substr( $sWk, 15 ) ); my @aTtlR = (); my @aTtlC = (); foreach my $raI ( @$raArea ) { if ( $raI->[3] == 0xFF ) { #Row Title push @aTtlR, [ $raI->[0], $raI->[2] ]; } else { #Col Title push @aTtlC, [ $raI->[1], $raI->[3] ]; } } $oBook->{PrintTitle}[$iSheet] = { Row => \@aTtlR, Column => \@aTtlC }; } } } } #------------------------------------------------------------------------------ # ParseNameArea (for Spreadsheet::ParseExcel) DK: 494 (ptgAread3d) #------------------------------------------------------------------------------ sub _ParseNameArea { my ( $sObj ) = @_; my ( $iOp ); my @aRes = (); $iOp = unpack( 'C', $sObj ); my $iSheet; if ( $iOp == 0x3b ) { my ( $iWkS, $iRs, $iRe, $iCs, $iCe ) = unpack( 'v5', substr( $sObj, 1 ) ); $iSheet = $iWkS; push @aRes, [ $iRs, $iCs, $iRe, $iCe ]; } elsif ( $iOp == 0x29 ) { my $iLen = unpack( 'v', substr( $sObj, 1, 2 ) ); my $iSt = 0; while ( $iSt < $iLen ) { my ( $iOpW, $iWkS, $iRs, $iRe, $iCs, $iCe ) = unpack( 'cv5', substr( $sObj, $iSt + 3, 11 ) ); if ( $iOpW == 0x3b ) { $iSheet = $iWkS; push @aRes, [ $iRs, $iCs, $iRe, $iCe ]; } if ( $iSt == 0 ) { $iSt += 11; } else { $iSt += 12; #Skip 1 byte; } } } return ( $iSheet, \@aRes ); } #------------------------------------------------------------------------------ # ParseNameArea95 (for Spreadsheet::ParseExcel) DK: 494 (ptgAread3d) #------------------------------------------------------------------------------ sub _ParseNameArea95 { my ( $sObj ) = @_; my ( $iOp ); my @aRes = (); $iOp = unpack( 'C', $sObj ); my $iSheet; if ( $iOp == 0x3b ) { $iSheet = unpack( 'v', substr( $sObj, 11, 2 ) ); my ( $iRs, $iRe, $iCs, $iCe ) = unpack( 'v2C2', substr( $sObj, 15, 6 ) ); push @aRes, [ $iRs, $iCs, $iRe, $iCe ]; } elsif ( $iOp == 0x29 ) { my $iLen = unpack( 'v', substr( $sObj, 1, 2 ) ); my $iSt = 0; while ( $iSt < $iLen ) { my $iOpW = unpack( 'c', substr( $sObj, $iSt + 3, 6 ) ); $iSheet = unpack( 'v', substr( $sObj, $iSt + 14, 2 ) ); my ( $iRs, $iRe, $iCs, $iCe ) = unpack( 'v2C2', substr( $sObj, $iSt + 18, 6 ) ); push @aRes, [ $iRs, $iCs, $iRe, $iCe ] if ( $iOpW == 0x3b ); if ( $iSt == 0 ) { $iSt += 21; } else { $iSt += 22; #Skip 1 byte; } } } return ( $iSheet, \@aRes ); } #------------------------------------------------------------------------------ # _subBOOL (for Spreadsheet::ParseExcel) DK: P452 #------------------------------------------------------------------------------ sub _subWSBOOL { my ( $oBook, $bOp, $bLen, $sWk ) = @_; return undef unless ( defined $oBook->{_CurSheet} ); $oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{PageFit} = ( ( unpack( 'v', $sWk ) & 0x100 ) ? 1 : 0 ); } #------------------------------------------------------------------------------ # _subMergeArea (for Spreadsheet::ParseExcel) DK: (Not) #------------------------------------------------------------------------------ sub _subMergeArea { my ( $oBook, $bOp, $bLen, $sWk ) = @_; return undef unless ( defined $oBook->{_CurSheet} ); my $iCnt = unpack( "v", $sWk ); my $oWkS = $oBook->{Worksheet}[ $oBook->{_CurSheet} ]; $oWkS->{MergedArea} = [] unless ( defined $oWkS->{MergedArea} ); for ( my $i = 0 ; $i < $iCnt ; $i++ ) { my ( $iRs, $iRe, $iCs, $iCe ) = unpack( 'v4', substr( $sWk, $i * 8 + 2, 8 ) ); for ( my $iR = $iRs ; $iR <= $iRe ; $iR++ ) { for ( my $iC = $iCs ; $iC <= $iCe ; $iC++ ) { $oWkS->{Cells}[$iR][$iC]->{Merged} = 1 if ( defined $oWkS->{Cells}[$iR][$iC] ); } } push @{ $oWkS->{MergedArea} }, [ $iRs, $iCs, $iRe, $iCe ]; } } #------------------------------------------------------------------------------ # DecodeBoolErr (for Spreadsheet::ParseExcel) DK: P306 #------------------------------------------------------------------------------ sub DecodeBoolErr { my ( $iVal, $iFlg ) = @_; if ( $iFlg ) { # ERROR if ( $iVal == 0x00 ) { return "#NULL!"; } elsif ( $iVal == 0x07 ) { return "#DIV/0!"; } elsif ( $iVal == 0x0F ) { return "#VALUE!"; } elsif ( $iVal == 0x17 ) { return "#REF!"; } elsif ( $iVal == 0x1D ) { return "#NAME?"; } elsif ( $iVal == 0x24 ) { return "#NUM!"; } elsif ( $iVal == 0x2A ) { return "#N/A!"; } else { return "#ERR"; } } else { return ( $iVal ) ? "TRUE" : "FALSE"; } } ############################################################################### # # _decode_rk_number() # # Convert an encoded RK number into a real number. The RK encoding is # explained in some detail in the MS docs. It is a way of storing applicable # ints and doubles in 32bits (30 data + 2 info bits) in order to save space. # sub _decode_rk_number { my $rk_number = shift; my $number; # Check the main RK type. if ( $rk_number & 0x02 ) { # RK Type 2 and 4, a packed integer. # Shift off the info bits. $number = $rk_number >> 2; # Convert from unsigned to signed if required. $number -= 0x40000000 if $number & 0x20000000; } else { # RK Type 1 and 3, a truncated IEEE Double. # Pack the RK number into the high 30 bits of an IEEE double. $number = pack "VV", 0x0000, $rk_number & 0xFFFFFFFC; # Reverse the packed IEEE double on big-endian machines. $number = reverse $number if $BIGENDIAN; # Unpack the number. $number = unpack "d", $number; } # RK Types 3 and 4 were multiplied by 100 prior to encoding. $number /= 100 if $rk_number & 0x01; return $number; } ############################################################################### # # _subStrWk() # # Extract the workbook strings from the SST (Shared String Table) record and # any following CONTINUE records. # # The workbook strings are initially contained in the SST block but may also # occupy one or more CONTINUE blocks. Reading the CONTINUE blocks is made a # little tricky by the fact that they can contain an additional initial byte # if a string is continued from a previous block. # # Parsing is further complicated by the fact that the continued section of the # string may have a different encoding (ASCII or UTF-8) from the previous # section. Excel does this to save space. # sub _subStrWk { my ( $self, $biff_data, $is_continue ) = @_; if ( $is_continue ) { # We are reading a CONTINUE record. if ( $self->{_buffer} eq '' ) { # A CONTINUE block with no previous SST. $self->{_buffer} .= $biff_data; } elsif ( !defined $self->{_string_continued} ) { # The CONTINUE block starts with a new (non-continued) string. # Strip the Grbit byte and store the string data. $self->{_buffer} .= substr $biff_data, 1; } else { # A CONTINUE block that starts with a continued string. # The first byte (Grbit) of the CONTINUE record indicates if (0) # the continued string section is single bytes or (1) double bytes. my $grbit = ord $biff_data; my ( $str_position, $str_length ) = @{ $self->{_previous_info} }; my $buff_length = length $self->{_buffer}; if ( $buff_length >= ( $str_position + $str_length ) ) { # Not in a string. $self->{_buffer} .= $biff_data; } elsif ( ( $self->{_string_continued} & 0x01 ) == ( $grbit & 0x01 ) ) { # Same encoding as the previous block of the string. $self->{_buffer} .= substr( $biff_data, 1 ); } else { # Different encoding to the previous block of the string. if ( $grbit & 0x01 ) { # Current block is UTF-16, previous was ASCII. my ( undef, $cch ) = unpack 'vc', $self->{_buffer}; substr( $self->{_buffer}, 2, 1 ) = pack( 'C', $cch | 0x01 ); # Convert the previous ASCII, single character, portion of # the string into a double character UTF-16 string by # inserting zero bytes. for ( my $i = ( $buff_length - $str_position ) ; $i >= 1 ; $i-- ) { substr( $self->{_buffer}, $str_position + $i, 0 ) = "\x00"; } } else { # Current block is ASCII, previous was UTF-16. # Convert the current ASCII, single character, portion of # the string into a double character UTF-16 string by # inserting null bytes. my $change_length = ( $str_position + $str_length ) - $buff_length; # Length of the current CONTINUE record data. my $biff_length = length $biff_data; # Restrict the portion to be changed to the current block # if the string extends over more than one block. if ( $change_length > ( $biff_length - 1 ) * 2 ) { $change_length = ( $biff_length - 1 ) * 2; } # Insert the null bytes. for ( my $i = ( $change_length / 2 ) ; $i >= 1 ; $i-- ) { substr( $biff_data, $i + 1, 0 ) = "\x00"; } } # Strip the Grbit byte and store the string data. $self->{_buffer} .= substr $biff_data, 1; } } } else { # Not a CONTINUE block therefore an SST block. $self->{_buffer} .= $biff_data; } # Reset the state variables. $self->{_string_continued} = undef; $self->{_previous_info} = undef; # Extract out any full strings from the current buffer leaving behind a # partial string that is continued into the next block, or an empty # buffer is no string is continued. while ( length $self->{_buffer} >= 4 ) { my ( $str_info, $length, $str_position, $str_length ) = _convBIFF8String( $self, $self->{_buffer}, 1 ); if ( defined $str_info->[0] ) { push @{ $self->{PkgStr} }, { Text => $str_info->[0], Unicode => $str_info->[1], Rich => $str_info->[2], Ext => $str_info->[3], }; $self->{_buffer} = substr( $self->{_buffer}, $length ); } else { $self->{_string_continued} = $str_info->[1]; $self->{_previous_info} = [ $str_position, $str_length ]; last; } } } #------------------------------------------------------------------------------ # _SwapForUnicode (for Spreadsheet::ParseExcel) #------------------------------------------------------------------------------ sub _SwapForUnicode { my ( $sObj ) = @_; # for(my $i = 0; $i{_CurSheet} ); my $FmtClass = $oBook->{FmtClass}; $rhKey{Type} = $FmtClass->ChkType( $rhKey{Numeric}, $rhKey{Format}{FmtIdx} ); my $FmtStr = $oBook->{FormatStr}{ $rhKey{Format}{FmtIdx} }; # Set "Date" type if required for numbers in a MulRK BIFF block. if ( defined $FmtStr && $rhKey{Type} eq "Numeric" ) { # Match a range of possible date formats. Note: this isn't important # except for reporting. The number will still be converted to a date # by ExcelFmt() even if 'Type' isn't set to 'Date'. if ( $FmtStr =~ m{^[dmy][-\\/dmy]*$}i ) { $rhKey{Type} = "Date"; } } my $oCell = Spreadsheet::ParseExcel::Cell->new( Val => $rhKey{Val}, FormatNo => $rhKey{FormatNo}, Format => $rhKey{Format}, Code => $rhKey{Code}, Type => $rhKey{Type}, ); $oCell->{_Kind} = $rhKey{Kind}; $oCell->{_Value} = $FmtClass->ValFmt( $oCell, $oBook ); if ( $rhKey{Rich} ) { my @aRich = (); my $sRich = $rhKey{Rich}; for ( my $iWk = 0 ; $iWk < length( $sRich ) ; $iWk += 4 ) { my ( $iPos, $iFnt ) = unpack( 'v2', substr( $sRich, $iWk ) ); push @aRich, [ $iPos, $oBook->{Font}[$iFnt] ]; } $oCell->{Rich} = \@aRich; } if ( defined $oBook->{CellHandler} ) { if ( defined $oBook->{Object} ) { no strict; ref( $oBook->{CellHandler} ) eq "CODE" ? $oBook->{CellHandler}->( $_Object, $oBook, $oBook->{_CurSheet}, $iR, $iC, $oCell ) : $oBook->{CellHandler}->callback( $_Object, $oBook, $oBook->{_CurSheet}, $iR, $iC, $oCell ); } else { $oBook->{CellHandler}->( $oBook, $oBook->{_CurSheet}, $iR, $iC, $oCell ); } } unless ( $oBook->{NotSetCell} ) { $oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{Cells}[$iR][$iC] = $oCell; } return $oCell; } #------------------------------------------------------------------------------ # ColorIdxToRGB (for Spreadsheet::ParseExcel) # # Returns for most recently opened book for compatibility, use # Workbook::color_idx_to_rgb instead # #------------------------------------------------------------------------------ sub ColorIdxToRGB { my ( $sPkg, $iIdx ) = @_; unless( defined $currentbook ) { return ( ( defined $aColor[$iIdx] ) ? $aColor[$iIdx] : $aColor[0] ); } return $currentbook->color_idx_to_rgb( $iIdx ); } ############################################################################### # # error(). # # Return an error string for a failed parse(). # sub error { my $self = shift; my $parse_error = $self->{_error_status}; if ( exists $error_strings{$parse_error} ) { return $error_strings{$parse_error}; } else { return 'Unknown parse error'; } } ############################################################################### # # error_code(). # # Return an error code for a failed parse(). # sub error_code { my $self = shift; return $self->{_error_status}; } ############################################################################### # # Mapping between legacy method names and new names. # { no warnings; # Ignore warnings about variables used only once. *Parse = *parse; } 1; __END__ =head1 NAME Spreadsheet::ParseExcel - Read information from an Excel file. =head1 SYNOPSIS #!/usr/bin/perl -w use strict; use Spreadsheet::ParseExcel; my $parser = Spreadsheet::ParseExcel->new(); my $workbook = $parser->parse('Book1.xls'); if ( !defined $workbook ) { die $parser->error(), ".\n"; } for my $worksheet ( $workbook->worksheets() ) { my ( $row_min, $row_max ) = $worksheet->row_range(); my ( $col_min, $col_max ) = $worksheet->col_range(); for my $row ( $row_min .. $row_max ) { for my $col ( $col_min .. $col_max ) { my $cell = $worksheet->get_cell( $row, $col ); next unless $cell; print "Row, Col = ($row, $col)\n"; print "Value = ", $cell->value(), "\n"; print "Unformatted = ", $cell->unformatted(), "\n"; print "\n"; } } } =head1 DESCRIPTION The Spreadsheet::ParseExcel module can be used to read information from Excel 95-2003 binary files. The module cannot read files in the Excel 2007 Open XML XLSX format. See the L module instead. =head1 Parser =head2 new() The C method is used to create a new C parser object. my $parser = Spreadsheet::ParseExcel->new(); It is possible to pass a password to decrypt an encrypted file: $parser = Spreadsheet::ParseExcel->new( Password => 'secret' ); Only the default Excel encryption scheme is currently supported. See L. As an advanced feature it is also possible to pass a call-back handler to the parser to control the parsing of the spreadsheet. $parser = Spreadsheet::ParseExcel->new( CellHandler => \&cell_handler, NotSetCell => 1, ); The call-back can be used to ignore certain cells or to reduce memory usage. See the section L for more information. =head2 parse($filename, $formatter) The Parser C method returns a L object. my $parser = Spreadsheet::ParseExcel->new(); my $workbook = $parser->parse('Book1.xls'); If an error occurs C returns C. In general, programs should contain a test for failed parsing as follows: my $parser = Spreadsheet::ParseExcel->new(); my $workbook = $parser->parse('Book1.xls'); if ( !defined $workbook ) { die $parser->error(), ".\n"; } The C<$filename> parameter is generally the file to be parsed. However, it can also be a filehandle or a scalar reference. The optional C<$formatter> parameter can be an reference to a L to format the value of cells. This is useful for parsing workbooks with Unicode or Asian characters: my $parser = Spreadsheet::ParseExcel->new(); my $formatter = Spreadsheet::ParseExcel::FmtJapan->new(); my $workbook = $parser->parse( 'Book1.xls', $formatter ); The L formatter also supports Unicode. If you encounter any encoding problems with the default formatter try that instead. =head2 error() The Parser C method returns an error string if a C fails: my $parser = Spreadsheet::ParseExcel->new(); my $workbook = $parser->parse('Book1.xls'); if ( !defined $workbook ) { die $parser->error(), ".\n"; } If you wish to generate you own error string you can use the C method instead (see below). The C and C values are as follows: error() error_code() ======= ============ '' 0 'File not found' 1 'No Excel data found in file' 2 'File is encrypted' 3 The C method is explained below. Spreadsheet::ParseExcel will try to decrypt an encrypted Excel file using the default password or a user supplied password passed to C, see above. If these fail the module will return the C<'File is encrypted'> error. Only the default Excel encryption scheme is currently supported, see L. =head2 error_code() The Parser C method returns an error code if a C fails: my $parser = Spreadsheet::ParseExcel->new(); my $workbook = $parser->parse('Book1.xls'); if ( !defined $workbook ) { die "Got error code ", $parser->error_code, ".\n"; } This can be useful if you wish to employ you own error strings or error handling methods. =head1 Workbook A C is created via the C C method: my $parser = Spreadsheet::ParseExcel->new(); my $workbook = $parser->parse('Book1.xls'); The main methods of the Workbook class are: $workbook->worksheets() $workbook->worksheet() $workbook->worksheet_count() $workbook->get_filename() These more commonly used methods of the Workbook class are outlined below. The other, less commonly used, methods are documented in L. =head2 worksheets() Returns an array of L objects. This was most commonly used to iterate over the worksheets in a workbook: for my $worksheet ( $workbook->worksheets() ) { ... } =head2 worksheet() The C method returns a single C object using either its name or index: $worksheet = $workbook->worksheet('Sheet1'); $worksheet = $workbook->worksheet(0); Returns C if the sheet name or index doesn't exist. =head2 worksheet_count() The C method returns the number of Worksheet objects in the Workbook. my $worksheet_count = $workbook->worksheet_count(); =head2 get_filename() The C method returns the name of the Excel file of C if the data was read from a filehandle rather than a file. my $filename = $workbook->get_filename(); =head2 Other Workbook Methods For full documentation of the methods available via a Workbook object see L. =head1 Worksheet The C class encapsulates the properties of an Excel worksheet. A Worksheet object is obtained via the L or L methods. for my $worksheet ( $workbook->worksheets() ) { ... } # Or: $worksheet = $workbook->worksheet('Sheet1'); $worksheet = $workbook->worksheet(0); The most commonly used methods of the Worksheet class are: $worksheet->get_cell() $worksheet->row_range() $worksheet->col_range() $worksheet->get_name() The Spreadsheet::ParseExcel::Worksheet class exposes a lot of methods but in general very few are required unless you are writing an advanced filter. The most commonly used methods are detailed below. The others are documented in L. =head2 get_cell($row, $col) Return the L object at row C<$row> and column C<$col> if it is defined. Otherwise returns undef. my $cell = $worksheet->get_cell($row, $col); =head2 row_range() Returns a two-element list C<($min, $max)> containing the minimum and maximum defined rows in the worksheet. If there is no row defined C<$max> is smaller than C<$min>. my ( $row_min, $row_max ) = $worksheet->row_range(); =head2 col_range() Returns a two-element list C<($min, $max)> containing the minimum and maximum of defined columns in the worksheet. If there is no column defined C<$max> is smaller than C<$min>. my ( $col_min, $col_max ) = $worksheet->col_range(); =head2 get_name() The C method returns the name of the worksheet, such as 'Sheet1'. my $name = $worksheet->get_name(); =head2 Other Worksheet Methods For other, less commonly used, Worksheet methods see L. =head1 Cell The C class has the following main methods. $cell->value() $cell->unformatted() =head2 value() The C method returns the formatted value of the cell. my $value = $cell->value(); Formatted in this sense refers to the numeric format of the cell value. For example a number such as 40177 might be formatted as 40,117, 40117.000 or even as the date 2009/12/30. If the cell doesn't contain a numeric format then the formatted and unformatted cell values are the same, see the C method below. For a defined C<$cell> the C method will always return a value. In the case of a cell with formatting but no numeric or string contents the method will return the empty string C<''>. =head2 unformatted() The C method returns the unformatted value of the cell. my $unformatted = $cell->unformatted(); Returns the cell value without a numeric format. See the C method above. =head2 Other Cell Methods For other, less commonly used, Worksheet methods see L. =head1 Format The C class has the following properties: =head2 Format properties $format->{Font} $format->{AlignH} $format->{AlignV} $format->{Indent} $format->{Wrap} $format->{Shrink} $format->{Rotate} $format->{JustLast} $format->{ReadDir} $format->{BdrStyle} $format->{BdrColor} $format->{BdrDiag} $format->{Fill} $format->{Lock} $format->{Hidden} $format->{Style} These properties are generally only of interest to advanced users. Casual users can skip this section. =head2 $format->{Font} Returns the L object for the Format. =head2 $format->{AlignH} Returns the horizontal alignment of the format where the value has the following meaning: 0 => No alignment 1 => Left 2 => Center 3 => Right 4 => Fill 5 => Justify 6 => Center across 7 => Distributed/Equal spaced =head2 $format->{AlignV} Returns the vertical alignment of the format where the value has the following meaning: 0 => Top 1 => Center 2 => Bottom 3 => Justify 4 => Distributed/Equal spaced =head2 $format->{Indent} Returns the indent level of the C horizontal alignment. =head2 $format->{Wrap} Returns true if textwrap is on. =head2 $format->{Shrink} Returns true if "Shrink to fit" is set for the format. =head2 $format->{Rotate} Returns the text rotation. In Excel97+, it returns the angle in degrees of the text rotation. In Excel95 or earlier it returns a value as follows: 0 => No rotation 1 => Top down 2 => 90 degrees anti-clockwise, 3 => 90 clockwise =head2 $format->{JustLast} Return true if the "justify last" property is set for the format. =head2 $format->{ReadDir} Returns the direction that the text is read from. =head2 $format->{BdrStyle} Returns an array ref of border styles as follows: [ $left, $right, $top, $bottom ] =head2 $format->{BdrColor} Returns an array ref of border color indexes as follows: [ $left, $right, $top, $bottom ] =head2 $format->{BdrDiag} Returns an array ref of diagonal border kind, style and color index as follows: [$kind, $style, $color ] Where kind is: 0 => None 1 => Right-Down 2 => Right-Up 3 => Both =head2 $format->{Fill} Returns an array ref of fill pattern and color indexes as follows: [ $pattern, $front_color, $back_color ] =head2 $format->{Lock} Returns true if the cell is locked. =head2 $format->{Hidden} Returns true if the cell is Hidden. =head2 $format->{Style} Returns true if the format is a Style format. =head1 Font I Format class has these properties: =head1 Font Properties $font->{Name} $font->{Bold} $font->{Italic} $font->{Height} $font->{Underline} $font->{UnderlineStyle} $font->{Color} $font->{Strikeout} $font->{Super} =head2 $font->{Name} Returns the name of the font, for example 'Arial'. =head2 $font->{Bold} Returns true if the font is bold. =head2 $font->{Italic} Returns true if the font is italic. =head2 $font->{Height} Returns the size (height) of the font. =head2 $font->{Underline} Returns true if the font in underlined. =head2 $font->{UnderlineStyle} Returns the style of an underlined font where the value has the following meaning: 0 => None 1 => Single 2 => Double 33 => Single accounting 34 => Double accounting =head2 $font->{Color} Returns the color index for the font. The mapping to an RGB color is defined by each workbook. The index can be converted to a RGB string using the C<$workbook->ColorIdxToRGB()> Parser method. (Older versions of C provided the C class method, which is deprecated.) =head2 $font->{Strikeout} Returns true if the font has the strikeout property set. =head2 $font->{Super} Returns one of the following values if the superscript or subscript property of the font is set: 0 => None 1 => Superscript 2 => Subscript =head1 Formatter Class Formatters can be passed to the C method to deal with Unicode or Asian formatting. Spreadsheet::ParseExcel includes 2 formatter classes. C and C. It is also possible to create a user defined formatting class. The formatter class C should provide the following functions: =head2 ChkType($self, $is_numeric, $format_index) Method to check the type of data in the cell. Should return C, C or C. It is passed the following parameters: =over =item $self A scalar reference to the Formatter object. =item $is_numeric If true, the value seems to be number. =item $format_index The index number for the cell Format object. =back =head2 TextFmt($self, $string_data, $string_encoding) Converts the string data in the cell into the correct encoding. It is passed the following parameters: =over =item $self A scalar reference to the Formatter object. =item $string_data The original string/text data. =item $string_encoding The character encoding of original string/text. =back =head2 ValFmt($self, $cell, $workbook) Convert the original unformatted cell value into the appropriate formatted value. For instance turn a number into a formatted date. It is passed the following parameters: =over =item $self A scalar reference to the Formatter object. =item $cell A scalar reference to the Cell object. =item $workbook A scalar reference to the Workbook object. =back =head2 FmtString($self, $cell, $workbook) Get the format string for the Cell. It is passed the following parameters: =over =item $self A scalar reference to the Formatter object. =item $cell A scalar reference to the Cell object. =item $workbook A scalar reference to the Workbook object. =back =head1 Reducing the memory usage of Spreadsheet::ParseExcel In some cases a C application may consume a lot of memory when processing a large Excel file and, as a result, may fail to complete. The following explains why this can occur and how to resolve it. C processes an Excel file in two stages. In the first stage it extracts the Excel binary stream from the OLE container file using C. In the second stage it parses the binary stream to read workbook, worksheet and cell data which it then stores in memory. The majority of the memory usage is required for storing cell data. The reason for this is that as the Excel file is parsed and each cell is encountered a cell handling function creates a relatively large nested cell object that contains the cell value and all of the data that relates to the cell formatting. For large files (a 10MB Excel file on a 256MB system) this overhead can cause the system to grind to a halt. However, in a lot of cases when an Excel file is being processed the only information that is required are the cell values. In these cases it is possible to avoid most of the memory overhead by specifying your own cell handling function and by telling Spreadsheet::ParseExcel not to store the parsed cell data. This is achieved by passing a cell handler function to C when creating the parse object. Here is an example. #!/usr/bin/perl -w use strict; use Spreadsheet::ParseExcel; my $parser = Spreadsheet::ParseExcel->new( CellHandler => \&cell_handler, NotSetCell => 1 ); my $workbook = $parser->parse('file.xls'); sub cell_handler { my $workbook = $_[0]; my $sheet_index = $_[1]; my $row = $_[2]; my $col = $_[3]; my $cell = $_[4]; # Do something useful with the formatted cell value print $cell->value(), "\n"; } The user specified cell handler is passed as a code reference to C along with the parameter C which tells Spreadsheet::ParseExcel not to store the parsed cell. Note, you don't have to iterate over the rows and columns, this happens automatically as part of the parsing. The cell handler is passed 5 arguments. The first, C<$workbook>, is a reference to the C object that represent the parsed workbook. This can be used to access any of the C methods, see L. The second C<$sheet_index> is the zero-based index of the worksheet being parsed. The third and fourth, C<$row> and C<$col>, are the zero-based row and column number of the cell. The fifth, C<$cell>, is a reference to the C object. This is used to extract the data from the cell. See L for more information. This technique can be useful if you are writing an Excel to database filter since you can put your DB calls in the cell handler. If you don't want all of the data in the spreadsheet you can add some control logic to the cell handler. For example we can extend the previous example so that it only prints the first 10 rows of the first two worksheets in the parsed workbook by adding some C statements to the cell handler: #!/usr/bin/perl -w use strict; use Spreadsheet::ParseExcel; my $parser = Spreadsheet::ParseExcel->new( CellHandler => \&cell_handler, NotSetCell => 1 ); my $workbook = $parser->parse('file.xls'); sub cell_handler { my $workbook = $_[0]; my $sheet_index = $_[1]; my $row = $_[2]; my $col = $_[3]; my $cell = $_[4]; # Skip some worksheets and rows (inefficiently). return if $sheet_index >= 3; return if $row >= 10; # Do something with the formatted cell value print $cell->value(), "\n"; } However, this still processes the entire workbook. If you wish to save some additional processing time you can abort the parsing after you have read the data that you want, using the workbook C method: #!/usr/bin/perl -w use strict; use Spreadsheet::ParseExcel; my $parser = Spreadsheet::ParseExcel->new( CellHandler => \&cell_handler, NotSetCell => 1 ); my $workbook = $parser->parse('file.xls'); sub cell_handler { my $workbook = $_[0]; my $sheet_index = $_[1]; my $row = $_[2]; my $col = $_[3]; my $cell = $_[4]; # Skip some worksheets and rows (more efficiently). if ( $sheet_index >= 1 and $row >= 10 ) { $workbook->ParseAbort(1); return; } # Do something with the formatted cell value print $cell->value(), "\n"; } =head1 Decryption If a workbook is "protected" then Excel will encrypt the file whether a password is supplied or not. As of version 0.59 Spreadsheet::ParseExcel supports decrypting Excel workbooks using a default or user supplied password. However, only the following encryption scheme is supported: Office 97/2000 Compatible encryption The following encryption methods are not supported: Weak Encryption (XOR) RC4, Microsoft Base Cryptographic Provider v1.0 RC4, Microsoft Base DSS and Diffie-Hellman Cryptographic Provider RC4, Microsoft DH SChannel Cryptographic Provider RC4, Microsoft Enhanced Cryptographic Provider v1.0 RC4, Microsoft Enhanced DSS and Diffie-Hellman Cryptographic Provider RC4, Microsoft Enhanced RSA and AES Cryptographic Provider RC4, Microsoft RSA SChannel Cryptographic Provider RC4, Microsoft Strong Cryptographic Provider See the following for more information on Excel encryption: L. =head1 KNOWN PROBLEMS =over =item * This module cannot read the values of formulas from files created with Spreadsheet::WriteExcel unless the user specified the values when creating the file (which is generally not the case). The reason for this is that Spreadsheet::WriteExcel writes the formula but not the formula result since it isn't in a position to calculate arbitrary Excel formulas without access to Excel's formula engine. =item * If Excel has date fields where the specified format is equal to the system-default for the short-date locale, Excel does not store the format, but defaults to an internal format which is system dependent. In these cases ParseExcel uses the date format 'yyyy-mm-dd'. =back =head1 REPORTING A BUG Please report bugs on GitHub with a complete, working, sample application and a test xls file. L =head1 SEE ALSO =over =item * xls2csv by Ken Prows L. =item * xls2csv and xlscat by H.Merijn Brand (these utilities are part of Spreadsheet::Read, see below). =item * excel2txt by Ken Youens-Clark, L. This is an excellent example of an Excel filter using Spreadsheet::ParseExcel. It can produce CSV, Tab delimited, Html, XML and Yaml. =item * XLSperl by Jon Allen L. This application allows you to use Perl "one-liners" with Microsoft Excel files. =item * Spreadsheet::XLSX L by Dmitry Ovsyanko. A module with a similar interface to Spreadsheet::ParseExcel for parsing Excel 2007 XLSX OpenXML files. =item * Spreadsheet::Read L by H.Merijn Brand. A single interface for reading several different spreadsheet formats. =item * Spreadsheet::WriteExcel L. A perl module for creating new Excel files. =item * Spreadsheet::ParseExcel::SaveParser L. This is a combination of Spreadsheet::ParseExcel and Spreadsheet::WriteExcel and it allows you to "rewrite" an Excel file. See the following example L. It is part of the Spreadsheet::ParseExcel distro. =item * Text::CSV_XS L by H.Merijn Brand. A fast and rigorous module for reading and writing CSV data. Don't consider rolling your own CSV handling, use this module instead. =back =head1 DONATIONS If you'd care to donate to the Spreadsheet::ParseExcel project, you can do so via PayPal: L =head1 TODO =over =item * The current maintenance work is directed towards making the documentation more useful, improving and simplifying the API, and improving the maintainability of the code base. After that new features will be added. =item * Fix open bugs and documentation for SaveParser. =item * Add Formula support, Hyperlink support, Named Range support. =item * Improve Spreadsheet::ParseExcel::SaveParser compatibility with Spreadsheet::WriteExcel. =item * Improve Unicode and other encoding support. This will probably require dropping support for perls prior to 5.8+. =back =head1 ACKNOWLEDGEMENTS From Kawai Takanori: First of all, I would like to acknowledge the following valuable programs and modules: XHTML, OLE::Storage and Spreadsheet::WriteExcel. In no particular order: Yamaji Haruna, Simamoto Takesi, Noguchi Harumi, Ikezawa Kazuhiro, Suwazono Shugo, Hirofumi Morisada, Michael Edwards, Kim Namusk, Slaven Rezic, Grant Stevens, H.Merijn Brand and many many people + Kawai Mikako. Alexey Mazurin added the decryption facility. =head1 DISCLAIMER OF WARRANTY Because this software is licensed free of charge, there is no warranty for the software, to the extent permitted by applicable law. Except when otherwise stated in writing the copyright holders and/or other parties provide the software "as is" without warranty of any kind, either expressed or implied, including, but not limited to, the implied warranties of merchantability and fitness for a particular purpose. The entire risk as to the quality and performance of the software is with you. Should the software prove defective, you assume the cost of all necessary servicing, repair, or correction. In no event unless required by applicable law or agreed to in writing will any copyright holder, or any other party who may modify and/or redistribute the software as permitted by the above licence, be liable to you for damages, including any general, special, incidental, or consequential damages arising out of the use or inability to use the software (including but not limited to loss of data or data being rendered inaccurate or losses sustained by you or third parties or a failure of the software to operate with any other software), even if such holder or other party has been advised of the possibility of such damages. =head1 LICENSE Either the Perl Artistic Licence L or the GPL L =head1 AUTHOR Current maintainer 0.60+: Douglas Wilson dougw@cpan.org Maintainer 0.40-0.59: John McNamara jmcnamara@cpan.org Maintainer 0.27-0.33: Gabor Szabo szabgab@cpan.org Original author: Kawai Takanori (Hippo2000) kwitknr@cpan.org =head1 COPYRIGHT Copyright (c) 2014 Douglas Wilson Copyright (c) 2009-2013 John McNamara Copyright (c) 2006-2008 Gabor Szabo Copyright (c) 2000-2006 Kawai Takanori All rights reserved. This is free software. You may distribute under the terms of either the GNU General Public License or the Artistic License. =cut Spreadsheet-ParseExcel-0.66/lib/Spreadsheet/ParseExcel/SaveParser.pm000644 000765 000024 00000017275 14543413026 025505 0ustar00Johnstaff000000 000000 package Spreadsheet::ParseExcel::SaveParser; ############################################################################### # # Spreadsheet::ParseExcel::SaveParser - Rewrite an existing Excel file. # # Used in conjunction with Spreadsheet::ParseExcel. # # Copyright (c) 2014 Douglas Wilson # Copyright (c) 2009-2013 John McNamara # Copyright (c) 2006-2008 Gabor Szabo # Copyright (c) 2000-2006 Kawai Takanori # # perltidy with standard settings. # # Documentation after __END__ # use strict; use warnings; use Spreadsheet::ParseExcel; use Spreadsheet::ParseExcel::SaveParser::Workbook; use Spreadsheet::ParseExcel::SaveParser::Worksheet; use Spreadsheet::WriteExcel; use base 'Spreadsheet::ParseExcel'; our $VERSION = '0.66'; ############################################################################### # # new() # sub new { my ( $package, %params ) = @_; $package->SUPER::new(%params); } ############################################################################### # # Create() # sub Create { my ( $self, $formatter ) = @_; #0. New $workbook my $workbook = Spreadsheet::ParseExcel::Workbook->new(); $workbook->{SheetCount} = 0; # User specified formatter class. if ($formatter) { $workbook->{FmtClass} = $formatter; } else { $workbook->{FmtClass} = Spreadsheet::ParseExcel::FmtDefault->new(); } return Spreadsheet::ParseExcel::SaveParser::Workbook->new($workbook); } ############################################################################### # # Parse() # sub Parse { my ( $self, $sFile, $formatter ) = @_; my $workbook = $self->SUPER::Parse( $sFile, $formatter ); return undef unless defined $workbook; return Spreadsheet::ParseExcel::SaveParser::Workbook->new($workbook); } ############################################################################### # # SaveAs() # sub SaveAs { my ( $self, $workbook, $filename ) = @_; $workbook->SaveAs($filename); } 1; __END__ =head1 NAME Spreadsheet::ParseExcel::SaveParser - Rewrite an existing Excel file. =head1 SYNOPSIS Say we start with an Excel file that looks like this: ----------------------------------------------------- | | A | B | C | ----------------------------------------------------- | 1 | Hello | ... | ... | ... | 2 | World | ... | ... | ... | 3 | *Bold text* | ... | ... | ... | 4 | ... | ... | ... | ... | 5 | ... | ... | ... | ... Then we process it with the following program: #!/usr/bin/perl use strict; use warnings; use Spreadsheet::ParseExcel; use Spreadsheet::ParseExcel::SaveParser; # Open an existing file with SaveParser my $parser = Spreadsheet::ParseExcel::SaveParser->new(); my $template = $parser->Parse('template.xls'); # Get the first worksheet. my $worksheet = $template->worksheet(0); my $row = 0; my $col = 0; # Overwrite the string in cell A1 $worksheet->AddCell( $row, $col, 'New string' ); # Add a new string in cell B1 $worksheet->AddCell( $row, $col + 1, 'Newer' ); # Add a new string in cell C1 with the format from cell A3. my $cell = $worksheet->get_cell( $row + 2, $col ); my $format_number = $cell->{FormatNo}; $worksheet->AddCell( $row, $col + 2, 'Newest', $format_number ); # Write over the existing file or write a new file. $template->SaveAs('newfile.xls'); We should now have an Excel file that looks like this: ----------------------------------------------------- | | A | B | C | ----------------------------------------------------- | 1 | New string | Newer | *Newest* | ... | 2 | World | ... | ... | ... | 3 | *Bold text* | ... | ... | ... | 4 | ... | ... | ... | ... | 5 | ... | ... | ... | ... =head1 DESCRIPTION The C module rewrite an existing Excel file by reading it with C and rewriting it with C. =head1 METHODS =head1 Parser =head2 new() $parse = new Spreadsheet::ParseExcel::SaveParser(); Constructor. =head2 Parse() $workbook = $parse->Parse($sFileName); $workbook = $parse->Parse($sFileName , $formatter); Returns a L object. If an error occurs, returns undef. The optional C<$formatter> is a Formatter Class to format the value of cells. =head1 Workbook The C method returns a C object. This is a subclass of the L and has the following methods: =head2 worksheets() Returns an array of L objects. This was most commonly used to iterate over the worksheets in a workbook: for my $worksheet ( $workbook->worksheets() ) { ... } =head2 worksheet() The C method returns a single C object using either its name or index: $worksheet = $workbook->worksheet('Sheet1'); $worksheet = $workbook->worksheet(0); Returns C if the sheet name or index doesn't exist. =head2 AddWorksheet() $workbook = $workbook->AddWorksheet($name, %properties); Create a new Worksheet object of type C. The C<%properties> hash contains the properties of new Worksheet. =head2 AddFont $workbook = $workbook->AddFont(%properties); Create new Font object of type C. The C<%properties> hash contains the properties of new Font. =head2 AddFormat $workbook = $workbook->AddFormat(%properties); The C<%properties> hash contains the properties of new Font. =head1 Worksheet Spreadsheet::ParseExcel::SaveParser::Worksheet Worksheet is a subclass of Spreadsheet::ParseExcel::Worksheet. And has these methods : The C method returns a C object. This is a subclass of the L and has the following methods: =head1 AddCell $workbook = $worksheet->AddCell($row, $col, $value, $format [$encoding]); Create new Cell object of type C. The C<$format> parameter is the format number rather than a full format object. To specify just same as another cell, you can set it like below: $row = 0; $col = 0; $worksheet = $template->worksheet(0); $cell = $worksheet->get_cell( $row, $col ); $format_number = $cell->{FormatNo}; $worksheet->AddCell($row +1, $coll, 'New data', $format_number); =head1 TODO Please note that this module is currently (versions 0.50-0.60) undergoing a major restructuring and rewriting. =head1 Known Problems You can only rewrite the features that Spreadsheet::WriteExcel supports so macros, graphs and some other features in the original Excel file will be lost. Also, formulas aren't rewritten, only the result of a formula is written. Only last print area will remain. (Others will be removed) =head1 AUTHOR Current maintainer 0.60+: Douglas Wilson dougw@cpan.org Maintainer 0.40-0.59: John McNamara jmcnamara@cpan.org Maintainer 0.27-0.33: Gabor Szabo szabgab@cpan.org Original author: Kawai Takanori kwitknr@cpan.org =head1 COPYRIGHT Copyright (c) 2014 Douglas Wilson Copyright (c) 2009-2013 John McNamara Copyright (c) 2006-2008 Gabor Szabo Copyright (c) 2000-2002 Kawai Takanori and Nippon-RAD Co. OP Division All rights reserved. You may distribute under the terms of either the GNU General Public License or the Artistic License, as specified in the Perl README file. =cut Spreadsheet-ParseExcel-0.66/lib/Spreadsheet/ParseExcel/FmtDefault.pm000644 000765 000024 00000014315 14543413026 025455 0ustar00Johnstaff000000 000000 package Spreadsheet::ParseExcel::FmtDefault; ############################################################################### # # Spreadsheet::ParseExcel::FmtDefault - A class for Cell formats. # # Used in conjunction with Spreadsheet::ParseExcel. # # Copyright (c) 2014 Douglas Wilson # Copyright (c) 2009-2013 John McNamara # Copyright (c) 2006-2008 Gabor Szabo # Copyright (c) 2000-2006 Kawai Takanori # # perltidy with standard settings. # # Documentation after __END__ # use strict; use warnings; use Spreadsheet::ParseExcel::Utility qw(ExcelFmt); our $VERSION = '0.66'; my %hFmtDefault = ( 0x00 => 'General', 0x01 => '0', 0x02 => '0.00', 0x03 => '#,##0', 0x04 => '#,##0.00', 0x05 => '($#,##0_);($#,##0)', 0x06 => '($#,##0_);[Red]($#,##0)', 0x07 => '($#,##0.00_);($#,##0.00_)', 0x08 => '($#,##0.00_);[Red]($#,##0.00_)', 0x09 => '0%', 0x0A => '0.00%', 0x0B => '0.00E+00', 0x0C => '# ?/?', 0x0D => '# ??/??', 0x0E => 'yyyy-mm-dd', # Was 'm-d-yy', which is bad as system default 0x0F => 'd-mmm-yy', 0x10 => 'd-mmm', 0x11 => 'mmm-yy', 0x12 => 'h:mm AM/PM', 0x13 => 'h:mm:ss AM/PM', 0x14 => 'h:mm', 0x15 => 'h:mm:ss', 0x16 => 'm-d-yy h:mm', #0x17-0x24 -- Differs in Natinal 0x25 => '(#,##0_);(#,##0)', 0x26 => '(#,##0_);[Red](#,##0)', 0x27 => '(#,##0.00);(#,##0.00)', 0x28 => '(#,##0.00);[Red](#,##0.00)', 0x29 => '_(*#,##0_);_(*(#,##0);_(*"-"_);_(@_)', 0x2A => '_($*#,##0_);_($*(#,##0);_(*"-"_);_(@_)', 0x2B => '_(*#,##0.00_);_(*(#,##0.00);_(*"-"??_);_(@_)', 0x2C => '_($*#,##0.00_);_($*(#,##0.00);_(*"-"??_);_(@_)', 0x2D => 'mm:ss', 0x2E => '[h]:mm:ss', 0x2F => 'mm:ss.0', 0x30 => '##0.0E+0', 0x31 => '@', ); #------------------------------------------------------------------------------ # new (for Spreadsheet::ParseExcel::FmtDefault) #------------------------------------------------------------------------------ sub new { my ( $sPkg, %hKey ) = @_; my $oThis = {}; bless $oThis; return $oThis; } #------------------------------------------------------------------------------ # TextFmt (for Spreadsheet::ParseExcel::FmtDefault) #------------------------------------------------------------------------------ sub TextFmt { my ( $oThis, $sTxt, $sCode ) = @_; return $sTxt if ( ( !defined($sCode) ) || ( $sCode eq '_native_' ) ); return pack( 'U*', unpack( 'n*', $sTxt ) ); } #------------------------------------------------------------------------------ # FmtStringDef (for Spreadsheet::ParseExcel::FmtDefault) #------------------------------------------------------------------------------ sub FmtStringDef { my ( $oThis, $iFmtIdx, $oBook, $rhFmt ) = @_; my $sFmtStr = $oBook->{FormatStr}->{$iFmtIdx}; if ( !( defined($sFmtStr) ) && defined($rhFmt) ) { $sFmtStr = $rhFmt->{$iFmtIdx}; } $sFmtStr = $hFmtDefault{$iFmtIdx} unless ($sFmtStr); return $sFmtStr; } #------------------------------------------------------------------------------ # FmtString (for Spreadsheet::ParseExcel::FmtDefault) #------------------------------------------------------------------------------ sub FmtString { my ( $oThis, $oCell, $oBook ) = @_; my $sFmtStr = $oThis->FmtStringDef( $oBook->{Format}[ $oCell->{FormatNo} ]->{FmtIdx}, $oBook ); # Special case for cells that use Lotus123 style leading # apostrophe to designate text formatting. if ( $oBook->{Format}[ $oCell->{FormatNo} ]->{Key123} ) { $sFmtStr = '@'; } unless ( defined($sFmtStr) ) { if ( $oCell->{Type} eq 'Numeric' ) { if ( int( $oCell->{Val} ) != $oCell->{Val} ) { $sFmtStr = '0.00'; } else { $sFmtStr = '0'; } } elsif ( $oCell->{Type} eq 'Date' ) { if ( int( $oCell->{Val} ) <= 0 ) { $sFmtStr = 'h:mm:ss'; } else { $sFmtStr = 'yyyy-mm-dd'; } } else { $sFmtStr = '@'; } } return $sFmtStr; } #------------------------------------------------------------------------------ # ValFmt (for Spreadsheet::ParseExcel::FmtDefault) #------------------------------------------------------------------------------ sub ValFmt { my ( $oThis, $oCell, $oBook ) = @_; my ( $Dt, $iFmtIdx, $iNumeric, $Flg1904 ); if ( $oCell->{Type} eq 'Text' ) { $Dt = ( ( defined $oCell->{Val} ) && ( $oCell->{Val} ne '' ) ) ? $oThis->TextFmt( $oCell->{Val}, $oCell->{Code} ) : ''; return $Dt; } else { $Dt = $oCell->{Val}; $Flg1904 = $oBook->{Flg1904}; my $sFmtStr = $oThis->FmtString( $oCell, $oBook ); return ExcelFmt( $sFmtStr, $Dt, $Flg1904, $oCell->{Type} ); } } #------------------------------------------------------------------------------ # ChkType (for Spreadsheet::ParseExcel::FmtDefault) #------------------------------------------------------------------------------ sub ChkType { my ( $oPkg, $iNumeric, $iFmtIdx ) = @_; if ($iNumeric) { if ( ( ( $iFmtIdx >= 0x0E ) && ( $iFmtIdx <= 0x16 ) ) || ( ( $iFmtIdx >= 0x2D ) && ( $iFmtIdx <= 0x2F ) ) ) { return "Date"; } else { return "Numeric"; } } else { return "Text"; } } 1; __END__ =pod =head1 NAME Spreadsheet::ParseExcel::FmtDefault - A class for Cell formats. =head1 SYNOPSIS See the documentation for Spreadsheet::ParseExcel. =head1 DESCRIPTION This module is used in conjunction with Spreadsheet::ParseExcel. See the documentation for Spreadsheet::ParseExcel. =head1 AUTHOR Current maintainer 0.60+: Douglas Wilson dougw@cpan.org Maintainer 0.40-0.59: John McNamara jmcnamara@cpan.org Maintainer 0.27-0.33: Gabor Szabo szabgab@cpan.org Original author: Kawai Takanori kwitknr@cpan.org =head1 COPYRIGHT Copyright (c) 2014 Douglas Wilson Copyright (c) 2009-2013 John McNamara Copyright (c) 2006-2008 Gabor Szabo Copyright (c) 2000-2006 Kawai Takanori All rights reserved. You may distribute under the terms of either the GNU General Public License or the Artistic License, as specified in the Perl README file. =cut Spreadsheet-ParseExcel-0.66/lib/Spreadsheet/ParseExcel/Workbook.pm000644 000765 000024 00000016026 14543413026 025220 0ustar00Johnstaff000000 000000 package Spreadsheet::ParseExcel::Workbook; ############################################################################### # # Spreadsheet::ParseExcel::Workbook - A class for Workbooks. # # Used in conjunction with Spreadsheet::ParseExcel. # # Copyright (c) 2014 Douglas Wilson # Copyright (c) 2009-2013 John McNamara # Copyright (c) 2006-2008 Gabor Szabo # Copyright (c) 2000-2006 Kawai Takanori # # perltidy with standard settings. # # Documentation after __END__ # use strict; use warnings; our $VERSION = '0.66'; ############################################################################### # # new() # # Constructor. # sub new { my ($class) = @_; my $self = {}; bless $self, $class; } ############################################################################### sub color_idx_to_rgb { my( $workbook, $iidx ) = @_; my $palette = $workbook->{aColor}; return ( ( defined $palette->[$iidx] ) ? $palette->[$iidx] : $palette->[0] ); } ############################################################################### # # worksheet() # # This method returns a single Worksheet object using either its name or index. # sub worksheet { my ( $oBook, $sName ) = @_; my $oWkS; foreach $oWkS ( @{ $oBook->{Worksheet} } ) { return $oWkS if ( $oWkS->{Name} eq $sName ); } if ( $sName =~ /^\d+$/ ) { return $oBook->{Worksheet}->[$sName]; } return undef; } ############################################################################### # # worksheets() # # Returns an array of Worksheet objects. # sub worksheets { my $self = shift; return @{ $self->{Worksheet} }; } ############################################################################### # # worksheet_count() # # Returns the number Woksheet objects in the Workbook. # sub worksheet_count { my $self = shift; return $self->{SheetCount}; } ############################################################################### # # get_filename() # # Returns the name of the Excel file of C if the data was read from a filehandle rather than a file. # sub get_filename { my $self = shift; return $self->{File}; } ############################################################################### # # get_print_areas() # # Returns an array ref of print areas. # # TODO. This should really be a Worksheet method. # sub get_print_areas { my $self = shift; return $self->{PrintArea}; } ############################################################################### # # get_print_titles() # # Returns an array ref of print title hash refs. # # TODO. This should really be a Worksheet method. # sub get_print_titles { my $self = shift; return $self->{PrintTitle}; } ############################################################################### # # using_1904_date() # # Returns true if the Excel file is using the 1904 date epoch. # sub using_1904_date { my $self = shift; return $self->{Flg1904}; } ############################################################################### # # ParseAbort() # # Todo # sub ParseAbort { my ( $self, $val ) = @_; $self->{_ParseAbort} = $val; } =head2 get_active_sheet() Return the number of the active (open) worksheet (at the time the workbook was saved. May return undef. =cut sub get_active_sheet { my $workbook = shift; return $workbook->{ActiveSheet}; } ############################################################################### # # Parse(). Deprecated. # # Syntactic wrapper around Spreadsheet::ParseExcel::Parse(). # This method is *deprecated* since it doesn't conform to the current # error handling in the S::PE Parse() method. # sub Parse { my ( $class, $source, $formatter ) = @_; my $excel = Spreadsheet::ParseExcel->new(); my $workbook = $excel->Parse( $source, $formatter ); $workbook->{_Excel} = $excel; return $workbook; } ############################################################################### # # Mapping between legacy method names and new names. # { no warnings; # Ignore warnings about variables used only once. *Worksheet = *worksheet; } 1; __END__ =pod =head1 NAME Spreadsheet::ParseExcel::Workbook - A class for Workbooks. =head1 SYNOPSIS See the documentation for Spreadsheet::ParseExcel. =head1 DESCRIPTION This module is used in conjunction with Spreadsheet::ParseExcel. See the documentation for L. =head1 Methods The following Workbook methods are available: $workbook->worksheets() $workbook->worksheet() $workbook->worksheet_count() $workbook->get_filename() $workbook->get_print_areas() $workbook->get_print_titles() $workbook->using_1904_date() =head2 worksheets() The C method returns an array of Worksheet objects. This was most commonly used to iterate over the worksheets in a workbook: for my $worksheet ( $workbook->worksheets() ) { ... } =head2 worksheet() The C method returns a single C object using either its name or index: $worksheet = $workbook->worksheet('Sheet1'); $worksheet = $workbook->worksheet(0); Returns C if the sheet name or index doesn't exist. =head2 worksheet_count() The C method returns the number of Woksheet objects in the Workbook. my $worksheet_count = $workbook->worksheet_count(); =head2 get_filename() The C method returns the name of the Excel file of C if the data was read from a filehandle rather than a file. my $filename = $workbook->get_filename(); =head2 get_print_areas() The C method returns an array ref of print areas. my $print_areas = $workbook->get_print_areas(); Each print area is as follows: [ $start_row, $start_col, $end_row, $end_col ] Returns undef if there are no print areas. =head2 get_print_titles() The C method returns an array ref of print title hash refs. my $print_titles = $workbook->get_print_titles(); Each print title array ref is as follows: { Row => [ $start_row, $end_row ], Column => [ $start_col, $end_col ], } Returns undef if there are no print titles. =head2 using_1904_date() The C method returns true if the Excel file is using the 1904 date epoch instead of the 1900 epoch. my $using_1904_date = $workbook->using_1904_date(); The Windows version of Excel generally uses the 1900 epoch while the Mac version of Excel generally uses the 1904 epoch. Returns 0 if the 1900 epoch is in use. =head1 AUTHOR Current maintainer 0.60+: Douglas Wilson dougw@cpan.org Maintainer 0.40-0.59: John McNamara jmcnamara@cpan.org Maintainer 0.27-0.33: Gabor Szabo szabgab@cpan.org Original author: Kawai Takanori kwitknr@cpan.org =head1 COPYRIGHT Copyright (c) 2014 Douglas Wilson Copyright (c) 2009-2013 John McNamara Copyright (c) 2006-2008 Gabor Szabo Copyright (c) 2000-2006 Kawai Takanori All rights reserved. You may distribute under the terms of either the GNU General Public License or the Artistic License, as specified in the Perl README file. =cut Spreadsheet-ParseExcel-0.66/lib/Spreadsheet/ParseExcel/Utility.pm000644 000765 000024 00000156055 14543413026 025075 0ustar00Johnstaff000000 000000 package Spreadsheet::ParseExcel::Utility; ############################################################################### # # Spreadsheet::ParseExcel::Utility - Utility functions for ParseExcel. # # Used in conjunction with Spreadsheet::ParseExcel. # # Copyright (c) 2014 Douglas Wilson # Copyright (c) 2009-2013 John McNamara # Copyright (c) 2006-2008 Gabor Szabo # Copyright (c) 2000-2006 Kawai Takanori # # perltidy with standard settings. # # Documentation after __END__ # use strict; use warnings; require Exporter; use vars qw(@ISA @EXPORT_OK); @ISA = qw(Exporter); @EXPORT_OK = qw(ExcelFmt LocaltimeExcel ExcelLocaltime col2int int2col sheetRef xls2csv); our $VERSION = '0.66'; my $qrNUMBER = qr/(^[+-]?\d+(\.\d+)?$)|(^[+-]?\d+\.?(\d*)[eE][+-](\d+))$/; ############################################################################### # # ExcelFmt() # # This function takes an Excel style number format and converts a number into # that format. for example: 'hh:mm:ss AM/PM' + 0.01023148 = '12:14:44 AM'. # # It does this with a type of templating mechanism. The format string is parsed # to identify tokens that need to be replaced and their position within the # string is recorded. These can be thought of as placeholders. The number is # then converted to the required formats and substituted into the placeholders. # # Interested parties should refer to the Excel documentation on cell formats for # more information: http://office.microsoft.com/en-us/excel/HP051995001033.aspx # The Microsoft documentation for the Excel Binary File Format, [MS-XLS].pdf, # also contains a ABNF grammar for number format strings. # # Maintainers notes: # ================== # # Note on format subsections: # A format string can contain 4 possible sub-sections separated by semi-colons: # Positive numbers, negative numbers, zero values, and text. # For example: _(* #,##0_);_(* (#,##0);_(* "-"_);_(@_) # # Note on conditional formats. # A number format in Excel can have a conditional expression such as: # [>9999999](000)000-0000;000-0000 # This is equivalent to the following in Perl: # $format = $number > 9999999 ? '(000)000-0000' : '000-0000'; # Nested conditionals are also possible but we don't support them. # # Efficiency: The excessive use of substr() isn't very efficient. However, # it probably doesn't merit rewriting this function with a parser or regular # expressions and \G. # # TODO: I think the single quote handling may not be required. Check. # sub ExcelFmt { my ( $format_str, $number, $is_1904, $number_type, $want_subformats ) = @_; # Return text strings without further formatting. return $number unless $number =~ $qrNUMBER; # Handle OpenOffice.org GENERAL format. $format_str = '@' if uc($format_str) eq "GENERAL"; # Check for a conditional at the start of the format. See notes above. my $conditional_op; my $conditional_value; if ( $format_str =~ /^\[([<>=]+)([^\]]+)\](.*)$/ ) { $conditional_op = $1; $conditional_value = $2; $format_str = $3; } # Ignore the underscore token which is used to indicate a padding space. $format_str =~ s/_/ /g; # Split the format string into 4 possible sub-sections: positive numbers, # negative numbers, zero values, and text. See notes above. my @formats; my $section = 0; my $double_quote = 0; my $single_quote = 0; # Initial parsing of the format string to remove escape characters. This # also handles quoted strings. See note about single quotes above. CHARACTER: for my $char ( split //, $format_str ) { if ( $double_quote or $single_quote ) { $formats[$section] .= $char; $double_quote = 0 if $char eq '"'; $single_quote = 0; next CHARACTER; } if ( $char eq ';' ) { $section++; next CHARACTER; } elsif ( $char eq '"' ) { $double_quote = 1; } elsif ( $char eq '!' ) { $single_quote = 1; } elsif ( $char eq '\\' ) { $single_quote = 1; } elsif ( $char eq '(' ) { next CHARACTER; # Ignore. } elsif ( $char eq ')' ) { next CHARACTER; # Ignore. } # Convert upper case OpenOffice.org date/time formats to lowercase.. $char = lc($char) if $char =~ /[DMYHS]/; $formats[$section] .= $char; } # Select the appropriate format from the 4 possible sub-sections: # positive numbers, negative numbers, zero values, and text. # We ignore the Text section since non-numeric values are returned # unformatted at the start of the function. my $format; $section = 0; if ( @formats == 1 ) { $section = 0; } elsif ( @formats == 2 ) { if ( $number < 0 ) { $section = 1; } else { $section = 0; } } elsif ( @formats == 3 ) { if ( $number == 0 ) { $section = 2; } elsif ( $number < 0 ) { $section = 1; } else { $section = 0; } } else { $section = 0; } # Override the previous choice if the format is conditional. if ($conditional_op) { if ($conditional_op eq '>') { $section = $number > $conditional_value ? 0 : 1; } elsif ($conditional_op eq '>=') { $section = $number >= $conditional_value ? 0 : 1; } elsif ($conditional_op eq '<') { $section = $number < $conditional_value ? 0 : 1; } elsif ($conditional_op eq '<=') { $section = $number <= $conditional_value ? 0 : 1; } elsif ($conditional_op eq '=') { $section = $number == $conditional_value ? 0 : 1; } elsif ($conditional_op eq '==') { $section = $number == $conditional_value ? 0 : 1; } elsif ($conditional_op eq '<>') { $section = $number != $conditional_value ? 0 : 1; } } # We now have the required format. $format = $formats[$section]; # The format string can contain one of the following colours: # [Black] [Blue] [Cyan] [Green] [Magenta] [Red] [White] [Yellow] # or the string [ColorX] where x is a colour index from 1 to 56. # We don't use the colour but we return it to the caller. # my $color = ''; if ( $format =~ s/^(\[[A-Za-z]{3,}(\d{1,2})?\])// ) { $color = $1; } # Remove the locale, such as [$-409], from the format string. my $locale = ''; if ( $format =~ s/^(\[\$?-F?\d+\])// ) { $locale = $1; } # Replace currency locale, such as [$$-409], with $ in the format string. # See the RT#60547 test cases in 21_number_format_user.t. if ( $format =~ s/(\[\$([^-]+)(-\d+)?\])/$2/s ) { $locale = $1; } # Remove leading # from '# ?/?', '# ??/??' fraction formats. $format =~ s{# \?}{?}g; # Parse the format string and create an AoA of placeholders that contain # the parts of the string to be replaced. The format of the information # stored is: [ $token, $start_pos, $end_pos, $option_info ]. # my $format_mode = ''; # Either: '', 'number', 'date' my $pos = 0; # Character position within format string. my @placeholders = (); # Arefs with parts of the format to be replaced. my $token = ''; # The actual format extracted from the total str. my $start_pos; # A position variable. Initial parser position. my $token_start = -1; # A position variable. my $decimal_pos = -1; # Position of the punctuation char "." or ",". my $comma_count = 0; # Count of the commas in the format. my $is_fraction = 0; # Number format is a fraction. my $is_currency = 0; # Number format is a currency. my $is_percent = 0; # Number format is a percentage. my $is_12_hour = 0; # Time format is using 12 hour clock. my $seen_dot = 0; # Treat only the first "." as the decimal point. # Parse the format. PARSER: while ( $pos < length $format ) { $start_pos = $pos; my $char = substr( $format, $pos, 1 ); # Ignore control format characters such as '#0+-.?eE,%'. However, # only ignore '.' if it is the first one encountered. RT 45502. if ( ( !$seen_dot && $char !~ /[#0\+\-\.\?eE\,\%]/ ) || $char !~ /[#0\+\-\?eE\,\%]/ ) { if ( $token_start != -1 ) { push @placeholders, [ substr( $format, $token_start, $pos - $token_start ), $decimal_pos, $pos - $token_start ]; $token_start = -1; } } # Processing for quoted strings within the format. See notes above. if ( $char eq '"' ) { $double_quote = $double_quote ? 0 : 1; $pos++; next PARSER; } elsif ( $char eq '!' ) { $single_quote = 1; $pos++; next PARSER; } elsif ( $char eq '\\' ) { if ( $single_quote != 1 ) { $single_quote = 1; $pos++; next PARSER; } } if ( ( defined($double_quote) and ($double_quote) ) or ( defined($single_quote) and ($single_quote) ) or ( $seen_dot && $char eq '.' ) ) { $single_quote = 0; if ( ( $format_mode ne 'date' ) and ( ( substr( $format, $pos, 2 ) eq "\x81\xA2" ) || ( substr( $format, $pos, 2 ) eq "\x81\xA3" ) || ( substr( $format, $pos, 2 ) eq "\xA2\xA4" ) || ( substr( $format, $pos, 2 ) eq "\xA2\xA5" ) ) ) { # The above matches are currency symbols. push @placeholders, [ substr( $format, $pos, 2 ), length($token), 2 ]; $is_currency = 1; $pos += 2; } else { $pos++; } } elsif ( ( $char =~ /[#0\+\.\?eE\,\%]/ ) || ( ( $format_mode ne 'date' ) and ( ( $char eq '-' ) || ( $char eq '(' ) || ( $char eq ')' ) ) ) ) { $format_mode = 'number' unless $format_mode; if ( substr( $format, $pos, 1 ) =~ /[#0]/ ) { if ( substr( $format, $pos ) =~ /^([#0]+[\.]?[0#]*[eE][\+\-][0#]+)/ ) { push @placeholders, [ $1, $pos, length($1) ]; $pos += length($1); } else { if ( $token_start == -1 ) { $token_start = $pos; $decimal_pos = length($token); } } } elsif ( substr( $format, $pos, 1 ) eq '?' ) { # Look for a fraction format like ?/? or ??/?? if ( $token_start != -1 ) { push @placeholders, [ substr( $format, $token_start, $pos - $token_start + 1 ), $decimal_pos, $pos - $token_start + 1 ]; } $token_start = $pos; # Find the end of the fraction format. FRACTION: while ( $pos < length($format) ) { if ( substr( $format, $pos, 1 ) eq '/' ) { $is_fraction = 1; } elsif ( substr( $format, $pos, 1 ) eq '?' ) { $pos++; next FRACTION; } else { if ( $is_fraction && ( substr( $format, $pos, 1 ) =~ /[0-9]/ ) ) { # TODO: Could invert if() logic and remove this. $pos++; next FRACTION; } else { last FRACTION; } } $pos++; } $pos--; push @placeholders, [ substr( $format, $token_start, $pos - $token_start + 1 ), length($token), $pos - $token_start + 1 ]; $token_start = -1; } elsif ( substr( $format, $pos, 3 ) =~ /^[eE][\+\-][0#]$/ ) { if ( substr( $format, $pos ) =~ /([eE][\+\-][0#]+)/ ) { push @placeholders, [ $1, $pos, length($1) ]; $pos += length($1); } $token_start = -1; } else { if ( $token_start != -1 ) { push @placeholders, [ substr( $format, $token_start, $pos - $token_start ), $decimal_pos, $pos - $token_start ]; $token_start = -1; } if ( substr( $format, $pos, 1 ) =~ /[\+\-]/ ) { push @placeholders, [ substr( $format, $pos, 1 ), length($token), 1 ]; $is_currency = 1; } elsif ( substr( $format, $pos, 1 ) eq '.' ) { push @placeholders, [ substr( $format, $pos, 1 ), length($token), 1 ]; $seen_dot = 1; } elsif ( substr( $format, $pos, 1 ) eq ',' ) { $comma_count++; push @placeholders, [ substr( $format, $pos, 1 ), length($token), 1 ]; } elsif ( substr( $format, $pos, 1 ) eq '%' ) { $is_percent = 1; } elsif (( substr( $format, $pos, 1 ) eq '(' ) || ( substr( $format, $pos, 1 ) eq ')' ) ) { push @placeholders, [ substr( $format, $pos, 1 ), length($token), 1 ]; $is_currency = 1; } } $pos++; } elsif ( $char =~ /[ymdhsapg]/i ) { $format_mode = 'date' unless $format_mode; if ( substr( $format, $pos, 5 ) =~ /am\/pm/i ) { push @placeholders, [ 'am/pm', length($token), 5 ]; $is_12_hour = 1; $pos += 5; } elsif ( substr( $format, $pos, 3 ) =~ /a\/p/i ) { push @placeholders, [ 'a/p', length($token), 3 ]; $is_12_hour = 1; $pos += 3; } elsif ( substr( $format, $pos, 5 ) eq 'mmmmm' ) { push @placeholders, [ 'mmmmm', length($token), 5 ]; $pos += 5; } elsif (( substr( $format, $pos, 4 ) eq 'mmmm' ) || ( substr( $format, $pos, 4 ) eq 'dddd' ) || ( substr( $format, $pos, 4 ) eq 'yyyy' ) || ( substr( $format, $pos, 4 ) eq 'ggge' ) ) { push @placeholders, [ substr( $format, $pos, 4 ), length($token), 4 ]; $pos += 4; } elsif (( substr( $format, $pos, 3 ) eq 'ddd' ) || ( substr( $format, $pos, 3 ) eq 'mmm' ) || ( substr( $format, $pos, 3 ) eq 'yyy' ) ) { push @placeholders, [ substr( $format, $pos, 3 ), length($token), 3 ]; $pos += 3; } elsif (( substr( $format, $pos, 2 ) eq 'yy' ) || ( substr( $format, $pos, 2 ) eq 'mm' ) || ( substr( $format, $pos, 2 ) eq 'dd' ) || ( substr( $format, $pos, 2 ) eq 'hh' ) || ( substr( $format, $pos, 2 ) eq 'ss' ) || ( substr( $format, $pos, 2 ) eq 'ge' ) ) { if ( ( substr( $format, $pos, 2 ) eq 'mm' ) && (@placeholders) && ( ( $placeholders[-1]->[0] eq 'h' ) or ( $placeholders[-1]->[0] eq 'hh' ) ) ) { # For this case 'm' is minutes not months. push @placeholders, [ 'mm', length($token), 2, 'minutes' ]; } else { push @placeholders, [ substr( $format, $pos, 2 ), length($token), 2 ]; } if ( ( substr( $format, $pos, 2 ) eq 'ss' ) && ( @placeholders > 1 ) ) { if ( ( $placeholders[-2]->[0] eq 'm' ) || ( $placeholders[-2]->[0] eq 'mm' ) ) { # For this case 'm' is minutes not months. push( @{ $placeholders[-2] }, 'minutes' ); } } $pos += 2; } elsif (( substr( $format, $pos, 1 ) eq 'm' ) || ( substr( $format, $pos, 1 ) eq 'd' ) || ( substr( $format, $pos, 1 ) eq 'h' ) || ( substr( $format, $pos, 1 ) eq 's' ) ) { if ( ( substr( $format, $pos, 1 ) eq 'm' ) && (@placeholders) && ( ( $placeholders[-1]->[0] eq 'h' ) or ( $placeholders[-1]->[0] eq 'hh' ) ) ) { # For this case 'm' is minutes not months. push @placeholders, [ 'm', length($token), 1, 'minutes' ]; } else { push @placeholders, [ substr( $format, $pos, 1 ), length($token), 1 ]; } if ( ( substr( $format, $pos, 1 ) eq 's' ) && ( @placeholders > 1 ) ) { if ( ( $placeholders[-2]->[0] eq 'm' ) || ( $placeholders[-2]->[0] eq 'mm' ) ) { # For this case 'm' is minutes not months. push( @{ $placeholders[-2] }, 'minutes' ); } } $pos += 1; } } elsif ( ( substr( $format, $pos, 3 ) eq '[h]' ) ) { $format_mode = 'date' unless $format_mode; push @placeholders, [ '[h]', length($token), 3 ]; $pos += 3; } elsif ( ( substr( $format, $pos, 4 ) eq '[mm]' ) ) { $format_mode = 'date' unless $format_mode; push @placeholders, [ '[mm]', length($token), 4 ]; $pos += 4; } elsif ( $char eq '@' ) { push @placeholders, [ '@', length($token), 1 ]; $pos++; } elsif ( $char eq '*' ) { push @placeholders, [ substr( $format, $pos, 1 ), length($token), 1 ]; } else { $pos++; } $pos++ if ( $pos == $start_pos ); #No Format match $token .= substr( $format, $start_pos, $pos - $start_pos ); } # End of parsing. # Copy the located format string to a result string that we will perform # the substitutions on and return to the user. my $result = $token; # Add a placeholder between the decimal/comma and end of the token, if any. if ( $token_start != -1 ) { push @placeholders, [ substr( $format, $token_start, $pos - $token_start + 1 ), $decimal_pos, $pos - $token_start + 1 ]; } # # In the next sections we process date, number and text formats. We take a # format such as yyyy/mm/dd and replace it with something like 2008/12/25. # if ( ( $format_mode eq 'date' ) && ( $number =~ $qrNUMBER ) ) { # The maximum allowable date in Excel is 9999-12-31T23:59:59.000 which # equates to 2958465.999+ in the 1900 epoch and 2957003.999+ in the # 1904 epoch. We use 0 as the minimum in both epochs. The 1904 system # actually supports negative numbers but that isn't worth the effort. my $min_date = 0; my $max_date = 2958466; $max_date = 2957004 if $is_1904; if ( $number < $min_date || $number >= $max_date ) { return $number; # Return unformatted number. } # Process date formats. my @time = ExcelLocaltime( $number, $is_1904 ); # 0 1 2 3 4 5 6 7 my ( $sec, $min, $hour, $day, $month, $year, $wday, $msec ) = @time; $month++; # localtime() zero indexed month. $year += 1900; # localtime() year. my @full_month_name = qw( None January February March April May June July August September October November December ); my @short_month_name = qw( None Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec ); my @full_day_name = qw( Sunday Monday Tuesday Wednesday Thursday Friday Saturday ); my @short_day_name = qw( Sun Mon Tue Wed Thu Fri Sat ); # Replace the placeholders in the template such as yyyy mm dd with # actual numbers or strings. my $replacement; for my $placeholder ( reverse @placeholders ) { if ( $placeholder->[-1] eq 'minutes' ) { # For this case 'm/mm' is minutes not months. if ( $placeholder->[0] eq 'mm' ) { $replacement = sprintf( "%02d", $min ); } else { $replacement = sprintf( "%d", $min ); } } elsif ( $placeholder->[0] eq 'yyyy' ) { # 4 digit Year. 2000 -> 2000. $replacement = sprintf( '%04d', $year ); } elsif ( $placeholder->[0] eq 'yy' ) { # 2 digit Year. 2000 -> 00. $replacement = sprintf( '%02d', $year % 100 ); } elsif ( $placeholder->[0] eq 'mmmmm' ) { # First character of the month name. 1 -> J. $replacement = substr( $short_month_name[$month], 0, 1 ); } elsif ( $placeholder->[0] eq 'mmmm' ) { # Full month name. 1 -> January. $replacement = $full_month_name[$month]; } elsif ( $placeholder->[0] eq 'mmm' ) { # Short month name. 1 -> Jan. $replacement = $short_month_name[$month]; } elsif ( $placeholder->[0] eq 'mm' ) { # 2 digit month. 1 -> 01. $replacement = sprintf( '%02d', $month ); } elsif ( $placeholder->[0] eq 'm' ) { # 1 digit month. 1 -> 1. $replacement = sprintf( '%d', $month ); } elsif ( $placeholder->[0] eq 'dddd' ) { # Full day name. Wednesday (for example.) $replacement = $full_day_name[$wday]; } elsif ( $placeholder->[0] eq 'ddd' ) { # Short day name. Wed (for example.) $replacement = $short_day_name[$wday]; } elsif ( $placeholder->[0] eq 'dd' ) { # 2 digit day. 1 -> 01. $replacement = sprintf( '%02d', $day ); } elsif ( $placeholder->[0] eq 'd' ) { # 1 digit day. 1 -> 1. $replacement = sprintf( '%d', $day ); } elsif ( $placeholder->[0] eq 'hh' ) { # 2 digit hour. if ($is_12_hour) { my $hour_tmp = $hour % 12; $hour_tmp = 12 if $hour % 12 == 0; $replacement = sprintf( '%d', $hour_tmp ); } else { $replacement = sprintf( '%02d', $hour ); } } elsif ( $placeholder->[0] eq 'h' ) { # 1 digit hour. if ($is_12_hour) { my $hour_tmp = $hour % 12; $hour_tmp = 12 if $hour % 12 == 0; $replacement = sprintf( '%2d', $hour_tmp ); } else { $replacement = sprintf( '%d', $hour ); } } elsif ( $placeholder->[0] eq 'ss' ) { # 2 digit seconds. $replacement = sprintf( '%02d', $sec ); } elsif ( $placeholder->[0] eq 's' ) { # 1 digit seconds. $replacement = sprintf( '%d', $sec ); } elsif ( $placeholder->[0] eq 'am/pm' ) { # AM/PM. $replacement = ( $hour >= 12 ) ? 'PM' : 'AM'; } elsif ( $placeholder->[0] eq 'a/p' ) { # AM/PM. $replacement = ( $hour >= 12 ) ? 'P' : 'A'; } elsif ( $placeholder->[0] eq '.' ) { # Decimal point for seconds. $replacement = '.'; } elsif ( $placeholder->[0] =~ /(^0+$)/ ) { # Milliseconds. For example h:ss.000. my $length = length($1); $replacement = substr( sprintf( "%.${length}f", $msec / 1000 ), 2, $length ); } elsif ( $placeholder->[0] eq '[h]' ) { # Hours modulus 24. 25 displays as 25 not as 1. $replacement = sprintf( '%d', int($number) * 24 + $hour ); } elsif ( $placeholder->[0] eq '[mm]' ) { # Mins modulus 60. 72 displays as 72 not as 12. $replacement = sprintf( '%d', ( int($number) * 24 + $hour ) * 60 + $min ); } elsif ( $placeholder->[0] eq 'ge' ) { require Spreadsheet::ParseExcel::FmtJapan; # Japanese Nengo (aka Gengo) in initialism (abbr. name) $replacement = Spreadsheet::ParseExcel::FmtJapan::CnvNengo( abbr_name => @time ); } elsif ( $placeholder->[0] eq 'ggge' ) { require Spreadsheet::ParseExcel::FmtJapan; # Japanese Nengo (aka Gengo) in Kanji (full name) $replacement = Spreadsheet::ParseExcel::FmtJapan::CnvNengo( name => @time ); } elsif ( $placeholder->[0] eq '@' ) { # Text format. $replacement = $number; } elsif ( $placeholder->[0] eq ',' ) { next; } # Substitute the replacement string back into the template. substr( $result, $placeholder->[1], $placeholder->[2], $replacement ); } } elsif ( ( $format_mode eq 'number' ) && ( $number =~ $qrNUMBER ) ) { # Process non date formats. if (@placeholders) { while ( $placeholders[-1]->[0] eq ',' ) { $comma_count--; substr( $result, $placeholders[-1]->[1], $placeholders[-1]->[2], '' ); $number /= 1000; pop @placeholders; } my $number_format = join( '', map { $_->[0] } @placeholders ); my $number_result; my $str_length = 0; my $engineering = 0; my $is_decimal = 0; my $is_integer = 0; my $after_decimal = undef; for my $token ( split //, $number_format ) { if ( $token eq '.' ) { $str_length++; $is_decimal = 1; } elsif ( ( $token eq 'E' ) || ( $token eq 'e' ) ) { $engineering = 1; } elsif ( $token eq '0' ) { $str_length++; $after_decimal++ if $is_decimal; $is_integer = 1; } elsif ( $token eq '#' ) { $after_decimal++ if $is_decimal; $is_integer = 1; } elsif ( $token eq '?' ) { $after_decimal++ if $is_decimal; } } $number *= 100.0 if $is_percent; my $data = ($is_currency) ? abs($number) : $number + 0; if ($is_fraction) { $number_result = sprintf( "%0${str_length}d", int($data) ); } else { if ($is_decimal) { if ( defined $after_decimal ) { $number_result = sprintf "%0${str_length}.${after_decimal}f", $data; } else { $number_result = sprintf "%0${str_length}f", $data; } # Fix for Perl and sprintf not rounding up like Excel. # http://rt.cpan.org/Public/Bug/Display.html?id=45626 if ( $data =~ /^${number_result}5/ ) { $number_result = sprintf "%0${str_length}.${after_decimal}f", $data . '1'; } } else { $number_result = sprintf( "%0${str_length}.0f", $data ); } } $number_result = AddComma($number_result) if $comma_count > 0; my $number_length = length($number_result); my $decimal_pos = -1; my $replacement; for ( my $i = @placeholders - 1 ; $i >= 0 ; $i-- ) { my $placeholder = $placeholders[$i]; if ( $placeholder->[0] =~ /([#0]*)([\.]?)([0#]*)([eE])([\+\-])([0#]+)/ ) { substr( $result, $placeholder->[1], $placeholder->[2], MakeE( $placeholder->[0], $number ) ); } elsif ( $placeholder->[0] =~ /\// ) { substr( $result, $placeholder->[1], $placeholder->[2], MakeFraction( $placeholder->[0], $number, $is_integer ) ); } elsif ( $placeholder->[0] eq '.' ) { $number_length--; $decimal_pos = $number_length; } elsif ( $placeholder->[0] eq '+' ) { substr( $result, $placeholder->[1], $placeholder->[2], ( $number > 0 ) ? '+' : ( ( $number == 0 ) ? '+' : '-' ) ); } elsif ( $placeholder->[0] eq '-' ) { substr( $result, $placeholder->[1], $placeholder->[2], ( $number > 0 ) ? '' : ( ( $number == 0 ) ? '' : '-' ) ); } elsif ( $placeholder->[0] eq '@' ) { substr( $result, $placeholder->[1], $placeholder->[2], $number ); } elsif ( $placeholder->[0] eq '*' ) { substr( $result, $placeholder->[1], $placeholder->[2], '' ); } elsif (( $placeholder->[0] eq "\xA2\xA4" ) or ( $placeholder->[0] eq "\xA2\xA5" ) or ( $placeholder->[0] eq "\x81\xA2" ) or ( $placeholder->[0] eq "\x81\xA3" ) ) { substr( $result, $placeholder->[1], $placeholder->[2], $placeholder->[0] ); } elsif (( $placeholder->[0] eq '(' ) or ( $placeholder->[0] eq ')' ) ) { substr( $result, $placeholder->[1], $placeholder->[2], $placeholder->[0] ); } else { if ( $number_length > 0 ) { if ( $i <= 0 ) { $replacement = substr( $number_result, 0, $number_length ); $number_length = 0; } else { my $real_part_length = length( $placeholder->[0] ); if ( $decimal_pos >= 0 ) { my $format = $placeholder->[0]; $format =~ s/^#+//; $real_part_length = length $format; $real_part_length = ( $number_length <= $real_part_length ) ? $number_length : $real_part_length; } else { $real_part_length = ( $number_length <= $real_part_length ) ? $number_length : $real_part_length; } $replacement = substr( $number_result, $number_length - $real_part_length, $real_part_length ); $number_length -= $real_part_length; } } else { $replacement = ''; } substr( $result, $placeholder->[1], $placeholder->[2], "\x00" . $replacement ); } } $replacement = ( $number_length > 0 ) ? substr( $number_result, 0, $number_length ) : ''; $result =~ s/\x00/$replacement/; $result =~ s/\x00//g; } } else { # Process text formats my $is_text = 0; for ( my $i = @placeholders - 1 ; $i >= 0 ; $i-- ) { my $placeholder = $placeholders[$i]; if ( $placeholder->[0] eq '@' ) { substr( $result, $placeholder->[1], $placeholder->[2], $number ); $is_text++; } else { substr( $result, $placeholder->[1], $placeholder->[2], '' ); } } $result = $number unless $is_text; } # End of placeholder substitutions. # Trim the leading and trailing whitespace from the results. $result =~ s/^\s+//; $result =~ s/\s+$//; # Fix for negative currency. $result =~ s/^\$\-/\-\$/; $result =~ s/^\$ \-/\-\$ /; # Return color and locale strings if required. if ($want_subformats) { return ( $result, $color, $locale ); } else { return $result; } } #------------------------------------------------------------------------------ # AddComma (for Spreadsheet::ParseExcel::Utility) #------------------------------------------------------------------------------ sub AddComma { my ($sNum) = @_; if ( $sNum =~ /^([^\d]*)(\d\d\d\d+)(\.*.*)$/ ) { my ( $sPre, $sObj, $sAft ) = ( $1, $2, $3 ); for ( my $i = length($sObj) - 3 ; $i > 0 ; $i -= 3 ) { substr( $sObj, $i, 0, ',' ); } return $sPre . $sObj . $sAft; } else { return $sNum; } } #------------------------------------------------------------------------------ # MakeFraction (for Spreadsheet::ParseExcel::Utility) #------------------------------------------------------------------------------ sub MakeFraction { my ( $sFmt, $iData, $iFlg ) = @_; my $iBunbo; my $iShou; #1. Init # print "FLG: $iFlg\n"; if ($iFlg) { $iShou = $iData - int($iData); return '' if ( $iShou == 0 ); } else { $iShou = $iData; } $iShou = abs($iShou); my $sSWk; #2.Calc BUNBO #2.1 BUNBO defined if ( $sFmt =~ /\/(\d+)$/ ) { $iBunbo = $1; return sprintf( "%d/%d", $iShou * $iBunbo, $iBunbo ); } else { #2.2 Calc BUNBO $sFmt =~ /\/(\?+)$/; my $iKeta = length($1); my $iSWk = 1; my $sSWk = ''; my $iBunsi; for ( my $iBunbo = 2 ; $iBunbo < 10**$iKeta ; $iBunbo++ ) { $iBunsi = int( $iShou * $iBunbo + 0.5 ); my $iCmp = abs( $iShou - ( $iBunsi / $iBunbo ) ); if ( $iCmp < $iSWk ) { $iSWk = $iCmp; $sSWk = sprintf( "%d/%d", $iBunsi, $iBunbo ); last if ( $iSWk == 0 ); } } return $sSWk; } } #------------------------------------------------------------------------------ # MakeE (for Spreadsheet::ParseExcel::Utility) #------------------------------------------------------------------------------ sub MakeE { my ( $sFmt, $iData ) = @_; $sFmt =~ /(([#0]*)[\.]?[#0]*)([eE])([\+\-][0#]+)/; my ( $sKari, $iKeta, $sE, $sSisu ) = ( $1, length($2), $3, $4 ); $iKeta = 1 if ( $iKeta <= 0 ); my $iLog10 = 0; $iLog10 = ( $iData == 0 ) ? 0 : ( log( abs($iData) ) / log(10) ); $iLog10 = ( int( $iLog10 / $iKeta ) + ( ( ( $iLog10 - int( $iLog10 / $iKeta ) ) < 0 ) ? -1 : 0 ) ) * $iKeta; my $sUe = ExcelFmt( $sKari, $iData * ( 10**( $iLog10 * -1 ) ), 0 ); my $sShita = ExcelFmt( $sSisu, $iLog10, 0 ); return $sUe . $sE . $sShita; } #------------------------------------------------------------------------------ # LeapYear (for Spreadsheet::ParseExcel::Utility) #------------------------------------------------------------------------------ sub LeapYear { my ($iYear) = @_; return 1 if ( $iYear == 1900 ); #Special for Excel return ( ( ( $iYear % 4 ) == 0 ) && ( ( $iYear % 100 ) || ( $iYear % 400 ) == 0 ) ) ? 1 : 0; } #------------------------------------------------------------------------------ # LocaltimeExcel (for Spreadsheet::ParseExcel::Utility) #------------------------------------------------------------------------------ sub LocaltimeExcel { my ( $iSec, $iMin, $iHour, $iDay, $iMon, $iYear, $iwDay, $iMSec, $flg1904 ) = @_; #0. Init $iMon++; $iYear += 1900; #1. Calc Time my $iTime; $iTime = $iHour; $iTime *= 60; $iTime += $iMin; $iTime *= 60; $iTime += $iSec; $iTime += $iMSec / 1000.0 if ( defined($iMSec) ); $iTime /= 86400.0; #3600*24(1day in seconds) my $iY; my $iYDays; #2. Calc Days if ($flg1904) { $iY = 1904; $iTime--; #Start from Jan 1st $iYDays = 366; } else { $iY = 1900; $iYDays = 366; #In Excel 1900 is leap year (That's not TRUE!) } while ( $iY < $iYear ) { $iTime += $iYDays; $iY++; $iYDays = ( LeapYear($iY) ) ? 366 : 365; } for ( my $iM = 1 ; $iM < $iMon ; $iM++ ) { if ( $iM == 1 || $iM == 3 || $iM == 5 || $iM == 7 || $iM == 8 || $iM == 10 || $iM == 12 ) { $iTime += 31; } elsif ( $iM == 4 || $iM == 6 || $iM == 9 || $iM == 11 ) { $iTime += 30; } elsif ( $iM == 2 ) { $iTime += ( LeapYear($iYear) ) ? 29 : 28; } } $iTime += $iDay; return $iTime; } my @month_days = qw( 0 31 28 31 30 31 30 31 31 30 31 30 31 ); #------------------------------------------------------------------------------ # ExcelLocaltime (for Spreadsheet::ParseExcel::Utility) #------------------------------------------------------------------------------ sub ExcelLocaltime { my ( $dObj, $flg1904 ) = @_; my ( $iSec, $iMin, $iHour, $iDay, $iMon, $iYear, $iwDay, $iMSec ); my ( $iDt, $iTime, $iYDays, $iMD ); $iDt = int($dObj); $iTime = $dObj - $iDt; #1. Calc Days if ($flg1904) { $iYear = 1904; $iDt++; #Start from Jan 1st $iYDays = 366; $iwDay = ( ( $iDt + 4 ) % 7 ); } else { $iYear = 1900; $iYDays = 366; #In Excel 1900 is leap year (That's not TRUE!) $iwDay = ( ( $iDt + 6 ) % 7 ); } while ( $iDt > $iYDays ) { $iDt -= $iYDays; $iYear++; $iYDays = ( ( ( $iYear % 4 ) == 0 ) && ( ( $iYear % 100 ) || ( $iYear % 400 ) == 0 ) ) ? 366 : 365; } $iYear -= 1900; # Localtime year is relative to 1900. for ( $iMon = 1 ; $iMon <= 12 ; $iMon++ ) { $iMD = $month_days[$iMon]; $iMD++ if $iMon == 2 and $iYear % 4 == 0; last if ( $iDt <= $iMD ); $iDt -= $iMD; } #2. Calc Time $iDay = $iDt; $iTime += ( 0.0005 / 86400.0 ); if ($iTime >= 1.0) { $iTime -= int($iTime); $iwDay = ($iwDay == 6) ? 0 : $iwDay + 1; if ($iDay == $iMD) { if ($iMon == 12) { $iMon = 1; $iYear++; } else { $iMon++; } $iDay = 1; } else { $iDay++; } } # Localtime month is 0 based. $iMon -= 1; $iTime *= 24.0; $iHour = int($iTime); $iTime -= $iHour; $iTime *= 60.0; $iMin = int($iTime); $iTime -= $iMin; $iTime *= 60.0; $iSec = int($iTime); $iTime -= $iSec; $iTime *= 1000.0; $iMSec = int($iTime); return ( $iSec, $iMin, $iHour, $iDay, $iMon, $iYear, $iwDay, $iMSec ); } # ----------------------------------------------------------------------------- # col2int (for Spreadsheet::ParseExcel::Utility) #------------------------------------------------------------------------------ # converts a excel row letter into an int for use in an array sub col2int { my $result = 0; my $str = shift; my $incr = 0; for ( my $i = length($str) ; $i > 0 ; $i-- ) { my $char = substr( $str, $i - 1 ); my $curr += ord( lc($char) ) - ord('a') + 1; $curr *= $incr if ($incr); $result += $curr; $incr += 26; } # this is one out as we range 0..x-1 not 1..x $result--; return $result; } # ----------------------------------------------------------------------------- # int2col (for Spreadsheet::ParseExcel::Utility) #------------------------------------------------------------------------------ ### int2col # convert a column number into column letters # @note this is quite a brute force coarse method # does not manage values over 701 (ZZ) # @arg number, to convert # @returns string, column name # sub int2col { my $out = ""; my $val = shift; do { $out .= chr( ( $val % 26 ) + ord('A') ); $val = int( $val / 26 ) - 1; } while ( $val >= 0 ); return scalar reverse $out; } # ----------------------------------------------------------------------------- # sheetRef (for Spreadsheet::ParseExcel::Utility) #------------------------------------------------------------------------------ # ----------------------------------------------------------------------------- ### sheetRef # convert an excel letter-number address into a useful array address # @note that also Excel uses X-Y notation, we normally use Y-X in arrays # @args $str, excel coord eg. A2 # @returns an array - 2 elements - column, row, or undefined # sub sheetRef { my $str = shift; my @ret; $str =~ m/^(\D+)(\d+)$/; if ( $1 && $2 ) { push( @ret, $2 - 1, col2int($1) ); } if ( $ret[0] < 0 ) { undef @ret; } return @ret; } # ----------------------------------------------------------------------------- # xls2csv (for Spreadsheet::ParseExcel::Utility) #------------------------------------------------------------------------------ ### xls2csv # convert a chunk of an excel file into csv text chunk # @args $param, sheet-colrow:colrow (1-A1:B2 or A1:B2 for sheet 1 # @args $rotate, 0 or 1 decides if output should be rotated or not # @returns string containing a chunk of csv # sub xls2csv { my ( $filename, $regions, $rotate ) = @_; my $sheet = 0; # We need Text::CSV_XS for proper CSV handling. require Text::CSV_XS; # extract any sheet number from the region string $regions =~ m/^(\d+)-(.*)/; if ($2) { $sheet = $1 - 1; $regions = $2; } # now extract the start and end regions $regions =~ m/(.*):(.*)/; if ( !$1 || !$2 ) { print STDERR "Bad Params"; return ""; } my @start = sheetRef($1); my @end = sheetRef($2); if ( !@start ) { print STDERR "Bad coorinates - $1"; return ""; } if ( !@end ) { print STDERR "Bad coorinates - $2"; return ""; } if ( $start[1] > $end[1] ) { print STDERR "Bad COLUMN ordering\n"; print STDERR "Start column " . int2col( $start[1] ); print STDERR " after end column " . int2col( $end[1] ) . "\n"; return ""; } if ( $start[0] > $end[0] ) { print STDERR "Bad ROW ordering\n"; print STDERR "Start row " . ( $start[0] + 1 ); print STDERR " after end row " . ( $end[0] + 1 ) . "\n"; exit; } # start the excel object now my $oExcel = new Spreadsheet::ParseExcel; my $oBook = $oExcel->Parse($filename); # open the sheet my $oWkS = $oBook->{Worksheet}[$sheet]; # now check that the region exists in the file # if not truncate to the possible region # output a warning msg if ( $start[1] < $oWkS->{MinCol} ) { print STDERR int2col( $start[1] ) . " < min col " . int2col( $oWkS->{MinCol} ) . " Resetting\n"; $start[1] = $oWkS->{MinCol}; } if ( $end[1] > $oWkS->{MaxCol} ) { print STDERR int2col( $end[1] ) . " > max col " . int2col( $oWkS->{MaxCol} ) . " Resetting\n"; $end[1] = $oWkS->{MaxCol}; } if ( $start[0] < $oWkS->{MinRow} ) { print STDERR "" . ( $start[0] + 1 ) . " < min row " . ( $oWkS->{MinRow} + 1 ) . " Resetting\n"; $start[0] = $oWkS->{MinCol}; } if ( $end[0] > $oWkS->{MaxRow} ) { print STDERR "" . ( $end[0] + 1 ) . " > max row " . ( $oWkS->{MaxRow} + 1 ) . " Resetting\n"; $end[0] = $oWkS->{MaxRow}; } my $x1 = $start[1]; my $y1 = $start[0]; my $x2 = $end[1]; my $y2 = $end[0]; my @cell_data; my $row = 0; if ( !$rotate ) { for ( my $y = $y1 ; $y <= $y2 ; $y++ ) { for ( my $x = $x1 ; $x <= $x2 ; $x++ ) { my $cell = $oWkS->{Cells}[$y][$x]; my $value; if ( defined $cell ) { $value .= $cell->value(); } else { $value = ''; } push @{ $cell_data[$row] }, $value; } $row++; } } else { for ( my $x = $x1 ; $x <= $x2 ; $x++ ) { for ( my $y = $y1 ; $y <= $y2 ; $y++ ) { my $cell = $oWkS->{Cells}[$y][$x]; my $value; if ( defined $cell ) { $value .= $cell->value(); } else { $value = ''; } push @{ $cell_data[$row] }, $value; } $row++; } } # Create the CSV output string. my $csv = Text::CSV_XS->new( { binary => 1, eol => $/ } ); my $output = ""; for my $row (@cell_data) { $csv->combine(@$row); $output .= $csv->string(); } return $output; } 1; __END__ =pod =head1 NAME Spreadsheet::ParseExcel::Utility - Utility functions for Spreadsheet::ParseExcel. =head1 SYNOPSIS use Spreadsheet::ParseExcel::Utility qw(ExcelFmt ExcelLocaltime LocaltimeExcel); # Convert localtime to Excel time my $datetime = LocaltimeExcel(11, 10, 12, 23, 2, 64); # 1964-3-23 12:10:11 print $datetime, "\n"; # 23459.5070717593 (Excel date/time format) # Convert Excel Time to localtime my @time = ExcelLocaltime($datetime); print join(":", @time), "\n"; # 11:10:12:23:2:64:1:0 # Formatting print ExcelFmt('yyyy-mm-dd', $datetime), "\n"; # 1964-3-23 print ExcelFmt('m-d-yy', $datetime), "\n"; # 3-23-64 print ExcelFmt('#,##0', $datetime), "\n"; # 23,460 print ExcelFmt('#,##0.00', $datetime), "\n"; # 23,459.51 =head1 DESCRIPTION The C module provides utility functions for working with ParseExcel and Excel data. =head1 Functions C can export the following functions: ExcelFmt ExcelLocaltime LocaltimeExcel col2int int2col sheetRef xls2csv These functions must be imported implicitly: # Just one function. use Spreadsheet::ParseExcel::Utility 'col2int'; # More than one. use Spreadsheet::ParseExcel::Utility qw(ExcelFmt ExcelLocaltime LocaltimeExcel); =head2 ExcelFmt($format_string, $number, $is_1904) Excel stores data such as dates and currency values as numbers. The way these numbers are displayed is controlled by the number format string for the cell. For example a cell with a number format of C<'$#,##0.00'> for currency and a value of 1234.567 would be displayed as follows: '$#,##0.00' + 1234.567 = '$1,234.57'. The C function tries to emulate this formatting so that the user can convert raw numbers returned by C to a desired format. For example: print ExcelFmt('$#,##0.00', 1234.567); # $1,234.57. The syntax of the function is: my $text = ExcelFmt($format_string, $number, $is_1904); Where C<$format_string> is an Excel number format string, C<$number> is a real or integer number and C is an optional flag to indicate that dates should use Excel's 1904 epoch instead of the default 1900 epoch. C is also used internally to convert numbers returned by the C method to the formatted value returned by the C method: my $cell = $worksheet->get_cell( 0, 0 ); print $cell->unformatted(), "\n"; # 1234.567 print $cell->value(), "\n"; # $1,234.57 The most common usage for C is to convert numbers to dates. Dates and times in Excel are represented by real numbers, for example "1 Jan 2001 12:30 PM" is represented by the number 36892.521. The integer part of the number stores the number of days since the epoch and the fractional part stores the percentage of the day. By applying an Excel number format the number is converted to the desired string representation: print ExcelFmt('d mmm yyyy h:mm AM/PM', 36892.521); # 1 Jan 2001 12:30 PM C<$is_1904> is an optional flag to indicate that dates should use Excel's 1904 epoch instead of the default 1900 epoch. Excel for Windows generally uses 1900 and Excel for Mac OS uses 1904. The C<$is1904> flag isn't required very often by a casual user and can usually be ignored. =head2 ExcelLocaltime($excel_datetime, $is_1904) The C function converts from an Excel date/time number to a C-like array of values: my @time = ExcelLocaltime($excel_datetime); # 0 1 2 3 4 5 6 7 my ( $sec, $min, $hour, $day, $month, $year, $wday, $msec ) = @time; The array elements from C<(0 .. 6)> are the same as Perl's C. The last element C<$msec> is milliseconds. In particular it should be noted that, in common with C, the month is zero indexed and the year is the number of years since 1900. This means that you will usually need to do the following: $month++; $year += 1900; See also Perl's documentation for L: The C<$is_1904> flag is an optional. It is used to indicate that dates should use Excel's 1904 epoch instead of the default 1900 epoch. =head2 LocaltimeExcel($sec, $min, $hour, $day, $month, $year, $wday, $msec, $is_1904) The C function converts from a C-like array of values to an Excel date/time number: $excel_datetime = LocaltimeExcel($sec, $min, $hour, $day, $month, $year, $wday, $msec); The array elements from C<(0 .. 6)> are the same as Perl's C. The last element C<$msec> is milliseconds. In particular it should be noted that, in common with C, the month is zero indexed and the year is the number of years since 1900. See also Perl's documentation for L: The C<$wday> and C<$msec> elements are usually optional. This time elements can also be zeroed if they aren't of interest: # sec, min, hour, day, month, year $excel_datetime = LocaltimeExcel( 0, 0, 0, 1, 0, 101 ); print ExcelFmt('d mmm yyyy', $excel_datetime); # 1 Jan 2001 The C<$is_1904> flag is also optional. It is used to indicate that dates should use Excel's 1904 epoch instead of the default 1900 epoch. =head2 col2int($column) The C function converts an Excel column letter to an zero-indexed column number: print col2int('A'); # 0 print col2int('AA'); # 26 This function was contributed by Kevin Mulholland. =head2 int2col($column_number) The C function converts an zero-indexed Excel column number to a column letter: print int2col(0); # 'A' print int2col(26); # 'AA' This function was contributed by Kevin Mulholland. =head2 sheetRef($cell_string) The C function converts an Excel cell reference in 'A1' notation to a zero-indexed C<(row, col)> pair. my ($row, $col) = sheetRef('A1'); # ( 0, 0 ) my ($row, $col) = sheetRef('C2'); # ( 1, 2 ) This function was contributed by Kevin Mulholland. =head2 xls2csv($filename, $region, $rotate) The C function converts a section of an Excel file into a CSV text string. $csv_text = xls2csv($filename, $region, $rotate); Where: $region = "sheet-colrow:colrow" For example '1-A1:B2' means 'A1:B2' for sheet 1. and $rotate = 0 or 1 (output is rotated/transposed or not) This function requires C to be installed. It was contributed by Kevin Mulholland along with the C script in the C directory of the distro. See also the following xls2csv utilities: Ken Prows' C: http://search.cpan.org/~ken/xls2csv/script/xls2csv and H.Merijn Brand's C (which is part of Spreadsheet::Read): http://search.cpan.org/~hmbrand/Spreadsheet-Read/ =head1 AUTHOR Current maintainer 0.60+: Douglas Wilson dougw@cpan.org Maintainer 0.40-0.59: John McNamara jmcnamara@cpan.org Maintainer 0.27-0.33: Gabor Szabo szabgab@cpan.org Original author: Kawai Takanori kwitknr@cpan.org =head1 COPYRIGHT Copyright (c) 2014 Douglas Wilson Copyright (c) 2009-2013 John McNamara Copyright (c) 2006-2008 Gabor Szabo Copyright (c) 2000-2006 Kawai Takanori All rights reserved. You may distribute under the terms of either the GNU General Public License or the Artistic License, as specified in the Perl README file. =cut Spreadsheet-ParseExcel-0.66/lib/Spreadsheet/ParseExcel/Cell.pm000644 000765 000024 00000022400 14543413026 024273 0ustar00Johnstaff000000 000000 package Spreadsheet::ParseExcel::Cell; ############################################################################### # # Spreadsheet::ParseExcel::Cell - A class for Cell data and formatting. # # Used in conjunction with Spreadsheet::ParseExcel. # # Copyright (c) 2014 Douglas Wilson # Copyright (c) 2009-2013 John McNamara # Copyright (c) 2006-2008 Gabor Szabo # Copyright (c) 2000-2006 Kawai Takanori # # perltidy with standard settings. # # Documentation after __END__ # use strict; use warnings; our $VERSION = '0.66'; ############################################################################### # # new() # # Constructor. # sub new { my ( $package, %properties ) = @_; my $self = \%properties; bless $self, $package; } ############################################################################### # # value() # # Returns the formatted value of the cell. # sub value { my $self = shift; return $self->{_Value}; } ############################################################################### # # unformatted() # # Returns the unformatted value of the cell. # sub unformatted { my $self = shift; return $self->{Val}; } ############################################################################### # # get_format() # # Returns the Format object for the cell. # sub get_format { my $self = shift; return $self->{Format}; } ############################################################################### # # type() # # Returns the type of cell such as Text, Numeric or Date. # sub type { my $self = shift; return $self->{Type}; } ############################################################################### # # encoding() # # Returns the character encoding of the cell. # sub encoding { my $self = shift; if ( !defined $self->{Code} ) { return 1; } elsif ( $self->{Code} eq 'ucs2' ) { return 2; } elsif ( $self->{Code} eq '_native_' ) { return 3; } else { return 0; } return $self->{Code}; } ############################################################################### # # is_merged() # # Returns true if the cell is merged. # sub is_merged { my $self = shift; return $self->{Merged}; } ############################################################################### # # get_rich_text() # # Returns an array ref of font information about each string block in a "rich", # i.e. multi-format, string. # sub get_rich_text { my $self = shift; return $self->{Rich}; } ############################################################################### # # get_hyperlink { # # Returns an array ref of hyperlink information if the cell contains a hyperlink. # Returns undef otherwise # # [0] : Description of link (You may want $cell->value, as it will have rich text) # [1] : URL - the link expressed as a URL. N.B. relative URLs will be defaulted to # the directory of the input file, if the input file name is known. Otherwise # %REL% will be inserted as a place-holder. Depending on your application, # you should either remove %REL% or replace it with the appropriate path. # [2] : Target frame (or undef if none) sub get_hyperlink { my $self = shift; return $self->{Hyperlink} if exists $self->{Hyperlink}; return undef; } # ############################################################################### # # Mapping between legacy method names and new names. # { no warnings; # Ignore warnings about variables used only once. *Value = \&value; } 1; __END__ =pod =head1 NAME Spreadsheet::ParseExcel::Cell - A class for Cell data and formatting. =head1 SYNOPSIS See the documentation for Spreadsheet::ParseExcel. =head1 DESCRIPTION This module is used in conjunction with Spreadsheet::ParseExcel. See the documentation for Spreadsheet::ParseExcel. =head1 Methods The following Cell methods are available: $cell->value() $cell->unformatted() $cell->get_format() $cell->type() $cell->encoding() $cell->is_merged() $cell->get_rich_text() $cell->get_hyperlink() =head2 value() The C method returns the formatted value of the cell. my $value = $cell->value(); Formatted in this sense refers to the numeric format of the cell value. For example a number such as 40177 might be formatted as 40,117, 40117.000 or even as the date 2009/12/30. If the cell doesn't contain a numeric format then the formatted and unformatted cell values are the same, see the C method below. For a defined C<$cell> the C method will always return a value. In the case of a cell with formatting but no numeric or string contents the method will return the empty string C<''>. =head2 unformatted() The C method returns the unformatted value of the cell. my $unformatted = $cell->unformatted(); Returns the cell value without a numeric format. See the C method above. =head2 get_format() The C method returns the L object for the cell. my $format = $cell->get_format(); If a user defined format hasn't been applied to the cell then the default cell format is returned. =head2 type() The C method returns the type of cell such as Text, Numeric or Date. If the type was detected as Numeric, and the Cell Format matches C, it will be treated as a Date type. my $type = $cell->type(); See also L. =head2 encoding() The C method returns the character encoding of the cell. my $encoding = $cell->encoding(); This method is only of interest to developers. In general Spreadsheet::ParseExcel will return all character strings in UTF-8 regardless of the encoding used by Excel. The C method returns one of the following values: =over =item * 0: Unknown format. This shouldn't happen. In the default case the format should be 1. =item * 1: 8bit ASCII or single byte UTF-16. This indicates that the characters are encoded in a single byte. In Excel 95 and earlier This usually meant ASCII or an international variant. In Excel 97 it refers to a compressed UTF-16 character string where all of the high order bytes are 0 and are omitted to save space. =item * 2: UTF-16BE. =item * 3: Native encoding. In Excel 95 and earlier this encoding was used to represent multi-byte character encodings such as SJIS. =back =head2 is_merged() The C method returns true if the cell is merged. my $is_merged = $cell->is_merged(); Returns C if the property isn't set. =head2 get_rich_text() The C method returns an array ref of font information about each string block in a "rich", i.e. multi-format, string. my $rich_text = $cell->get_rich_text(); The return value is an arrayref of arrayrefs in the form: [ [ $start_position, $font_object ], ..., ] Returns undef if the property isn't set. =head2 get_hyperlink() If a cell contains a hyperlink, the C method returns an array ref of information about it. A cell can contain at most one hyperlink. If it does, it contains no other value. Otherwise, it returns undef; The array contains: =over =item * 0: Description (what's displayed); undef if not present =item * 1: Link, converted to an appropriate URL - Note: Relative links are based on the input file. %REL% is used if the input file is unknown (e.g. a file handle or scalar) =item * 2: Target - target frame (or undef if none) =back =head1 Dates and Time in Excel Dates and times in Excel are represented by real numbers, for example "Jan 1 2001 12:30 PM" is represented by the number 36892.521. The integer part of the number stores the number of days since the epoch and the fractional part stores the percentage of the day. A date or time in Excel is just like any other number. The way in which it is displayed is controlled by the number format: Number format $cell->value() $cell->unformatted() ============= ============== ============== 'dd/mm/yy' '28/02/08' 39506.5 'mm/dd/yy' '02/28/08' 39506.5 'd-m-yyyy' '28-2-2008' 39506.5 'dd/mm/yy hh:mm' '28/02/08 12:00' 39506.5 'd mmm yyyy' '28 Feb 2008' 39506.5 'mmm d yyyy hh:mm AM/PM' 'Feb 28 2008 12:00 PM' 39506.5 The L module contains a function called C which will convert between an unformatted Excel date/time number and a C like array. For date conversions using the CPAN C framework see L http://search.cpan.org/search?dist=DateTime-Format-Excel =head1 AUTHOR Current maintainer 0.60+: Douglas Wilson dougw@cpan.org Maintainer 0.40-0.59: John McNamara jmcnamara@cpan.org Maintainer 0.27-0.33: Gabor Szabo szabgab@cpan.org Original author: Kawai Takanori kwitknr@cpan.org =head1 COPYRIGHT Copyright (c) 2014 Douglas Wilson Copyright (c) 2009-2013 John McNamara Copyright (c) 2006-2008 Gabor Szabo Copyright (c) 2000-2006 Kawai Takanori All rights reserved. You may distribute under the terms of either the GNU General Public License or the Artistic License, as specified in the Perl README file. =cut Spreadsheet-ParseExcel-0.66/lib/Spreadsheet/ParseExcel/Font.pm000644 000765 000024 00000002704 14543413026 024327 0ustar00Johnstaff000000 000000 package Spreadsheet::ParseExcel::Font; ############################################################################### # # Spreadsheet::ParseExcel::Font - A class for Cell fonts. # # Used in conjunction with Spreadsheet::ParseExcel. # # Copyright (c) 2014 Douglas Wilson # Copyright (c) 2009-2013 John McNamara # Copyright (c) 2006-2008 Gabor Szabo # Copyright (c) 2000-2006 Kawai Takanori # # perltidy with standard settings. # # Documentation after __END__ # use strict; use warnings; our $VERSION = '0.66'; sub new { my ( $class, %rhIni ) = @_; my $self = \%rhIni; bless $self, $class; } 1; __END__ =pod =head1 NAME Spreadsheet::ParseExcel::Font - A class for Cell fonts. =head1 SYNOPSIS See the documentation for Spreadsheet::ParseExcel. =head1 DESCRIPTION This module is used in conjunction with Spreadsheet::ParseExcel. See the documentation for Spreadsheet::ParseExcel. =head1 AUTHOR Current maintainer 0.60+: Douglas Wilson dougw@cpan.org Maintainer 0.40-0.59: John McNamara jmcnamara@cpan.org Maintainer 0.27-0.33: Gabor Szabo szabgab@cpan.org Original author: Kawai Takanori kwitknr@cpan.org =head1 COPYRIGHT Copyright (c) 2014 Douglas Wilson Copyright (c) 2009-2013 John McNamara Copyright (c) 2006-2008 Gabor Szabo Copyright (c) 2000-2006 Kawai Takanori All rights reserved. You may distribute under the terms of either the GNU General Public License or the Artistic License, as specified in the Perl README file. =cut Spreadsheet-ParseExcel-0.66/lib/Spreadsheet/ParseExcel/Format.pm000644 000765 000024 00000002715 14543413026 024653 0ustar00Johnstaff000000 000000 package Spreadsheet::ParseExcel::Format; ############################################################################### # # Spreadsheet::ParseExcel::Format - A class for Cell formats. # # Used in conjunction with Spreadsheet::ParseExcel. # # Copyright (c) 2014 Douglas Wilson # Copyright (c) 2009-2013 John McNamara # Copyright (c) 2006-2008 Gabor Szabo # Copyright (c) 2000-2006 Kawai Takanori # # perltidy with standard settings. # # Documentation after __END__ # use strict; use warnings; our $VERSION = '0.66'; sub new { my ( $class, %rhIni ) = @_; my $self = \%rhIni; bless $self, $class; } 1; __END__ =pod =head1 NAME Spreadsheet::ParseExcel::Format - A class for Cell formats. =head1 SYNOPSIS See the documentation for Spreadsheet::ParseExcel. =head1 DESCRIPTION This module is used in conjunction with Spreadsheet::ParseExcel. See the documentation for Spreadsheet::ParseExcel. =head1 AUTHOR Current maintainer 0.60+: Douglas Wilson dougw@cpan.org Maintainer 0.40-0.59: John McNamara jmcnamara@cpan.org Maintainer 0.27-0.33: Gabor Szabo szabgab@cpan.org Original author: Kawai Takanori kwitknr@cpan.org =head1 COPYRIGHT Copyright (c) 2014 Douglas Wilson Copyright (c) 2009-2013 John McNamara Copyright (c) 2006-2008 Gabor Szabo Copyright (c) 2000-2006 Kawai Takanori All rights reserved. You may distribute under the terms of either the GNU General Public License or the Artistic License, as specified in the Perl README file. =cut Spreadsheet-ParseExcel-0.66/lib/Spreadsheet/ParseExcel/Worksheet.pm000644 000765 000024 00000057656 14543413026 025414 0ustar00Johnstaff000000 000000 package Spreadsheet::ParseExcel::Worksheet; ############################################################################### # # Spreadsheet::ParseExcel::Worksheet - A class for Worksheets. # # Used in conjunction with Spreadsheet::ParseExcel. # # Copyright (c) 2014 Douglas Wilson # Copyright (c) 2009-2013 John McNamara # Copyright (c) 2006-2008 Gabor Szabo # Copyright (c) 2000-2006 Kawai Takanori # # perltidy with standard settings. # # Documentation after __END__ # use strict; use warnings; use Scalar::Util qw(weaken); our $VERSION = '0.66'; ############################################################################### # # new() # sub new { my ( $class, %properties ) = @_; my $self = \%properties; weaken $self->{_Book}; $self->{Cells} = undef; $self->{DefColWidth} = 8.43; return bless $self, $class; } ############################################################################### # # get_cell( $row, $col ) # # Returns the Cell object at row $row and column $col, if defined. # sub get_cell { my ( $self, $row, $col ) = @_; if ( !defined $row || !defined $col || !defined $self->{MaxRow} || !defined $self->{MaxCol} ) { # Return undef if no arguments are given or if no cells are defined. return undef; } elsif ($row < $self->{MinRow} || $row > $self->{MaxRow} || $col < $self->{MinCol} || $col > $self->{MaxCol} ) { # Return undef if outside allowable row/col range. return undef; } else { # Return the Cell object. return $self->{Cells}->[$row]->[$col]; } } ############################################################################### # # row_range() # # Returns a two-element list ($min, $max) containing the minimum and maximum # defined rows in the worksheet. # # If there is no row defined $max is smaller than $min. # sub row_range { my $self = shift; my $min = $self->{MinRow} || 0; my $max = defined( $self->{MaxRow} ) ? $self->{MaxRow} : ( $min - 1 ); return ( $min, $max ); } ############################################################################### # # col_range() # # Returns a two-element list ($min, $max) containing the minimum and maximum # defined cols in the worksheet. # # If there is no column defined $max is smaller than $min. # sub col_range { my $self = shift; my $min = $self->{MinCol} || 0; my $max = defined( $self->{MaxCol} ) ? $self->{MaxCol} : ( $min - 1 ); return ( $min, $max ); } ############################################################################### # # get_name() # # Returns the name of the worksheet. # sub get_name { my $self = shift; return $self->{Name}; } ############################################################################### # # sheet_num() # sub sheet_num { my $self = shift; return $self->{_SheetNo}; } ############################################################################### # # get_h_pagebreaks() # # Returns an array ref of row numbers where a horizontal page break occurs. # sub get_h_pagebreaks { my $self = shift; return $self->{HPageBreak}; } ############################################################################### # # get_v_pagebreaks() # # Returns an array ref of column numbers where a vertical page break occurs. # sub get_v_pagebreaks { my $self = shift; return $self->{VPageBreak}; } ############################################################################### # # get_merged_areas() # # Returns an array ref of cells that are merged. # sub get_merged_areas { my $self = shift; return $self->{MergedArea}; } ############################################################################### # # get_row_heights() # # Returns an array of row heights. # sub get_row_heights { my $self = shift; if ( wantarray() ) { return unless $self->{RowHeight}; return @{ $self->{RowHeight} }; } return $self->{RowHeight}; } ############################################################################### # # get_col_widths() # # Returns an array of column widths. # sub get_col_widths { my $self = shift; if ( wantarray() ) { return unless $self->{ColWidth}; return @{ $self->{ColWidth} }; } return $self->{ColWidth}; } ############################################################################### # # get_default_row_height() # # Returns the default row height for the worksheet. Generally 12.75. # sub get_default_row_height { my $self = shift; return $self->{DefRowHeight}; } ############################################################################### # # get_default_col_width() # # Returns the default column width for the worksheet. Generally 8.43. # sub get_default_col_width { my $self = shift; return $self->{DefColWidth}; } ############################################################################### # # _get_row_properties() # # Returns an array_ref of row properties. # TODO. This is a placeholder for a future method. # sub _get_row_properties { my $self = shift; return $self->{RowProperties}; } ############################################################################### # # _get_col_properties() # # Returns an array_ref of column properties. # TODO. This is a placeholder for a future method. # sub _get_col_properties { my $self = shift; return $self->{ColProperties}; } ############################################################################### # # get_header() # # Returns the worksheet header string. # sub get_header { my $self = shift; return $self->{Header}; } ############################################################################### # # get_footer() # # Returns the worksheet footer string. # sub get_footer { my $self = shift; return $self->{Footer}; } ############################################################################### # # get_margin_left() # # Returns the left margin of the worksheet in inches. # sub get_margin_left { my $self = shift; return $self->{LeftMargin}; } ############################################################################### # # get_margin_right() # # Returns the right margin of the worksheet in inches. # sub get_margin_right { my $self = shift; return $self->{RightMargin}; } ############################################################################### # # get_margin_top() # # Returns the top margin of the worksheet in inches. # sub get_margin_top { my $self = shift; return $self->{TopMargin}; } ############################################################################### # # get_margin_bottom() # # Returns the bottom margin of the worksheet in inches. # sub get_margin_bottom { my $self = shift; return $self->{BottomMargin}; } ############################################################################### # # get_margin_header() # # Returns the header margin of the worksheet in inches. # sub get_margin_header { my $self = shift; return $self->{HeaderMargin}; } ############################################################################### # # get_margin_footer() # # Returns the footer margin of the worksheet in inches. # sub get_margin_footer { my $self = shift; return $self->{FooterMargin}; } ############################################################################### # # get_paper() # # Returns the printer paper size. # sub get_paper { my $self = shift; return $self->{PaperSize}; } ############################################################################### # # get_start_page() # # Returns the page number that printing will start from. # sub get_start_page { my $self = shift; # Only return the page number if the "First page number" option is set. if ( $self->{UsePage} ) { return $self->{PageStart}; } else { return 0; } } ############################################################################### # # get_print_order() # # Returns the Worksheet page printing order. # sub get_print_order { my $self = shift; return $self->{LeftToRight}; } ############################################################################### # # get_print_scale() # # Returns the workbook scale for printing. # sub get_print_scale { my $self = shift; return $self->{Scale}; } ############################################################################### # # get_fit_to_pages() # # Returns the number of pages wide and high that the printed worksheet page # will fit to. # sub get_fit_to_pages { my $self = shift; if ( !$self->{PageFit} ) { return ( 0, 0 ); } else { return ( $self->{FitWidth}, $self->{FitHeight} ); } } ############################################################################### # # is_portrait() # # Returns true if the worksheet has been set for printing in portrait mode. # sub is_portrait { my $self = shift; return $self->{Landscape}; } ############################################################################### # # is_centered_horizontally() # # Returns true if the worksheet has been centered horizontally for printing. # sub is_centered_horizontally { my $self = shift; return $self->{HCenter}; } ############################################################################### # # is_centered_vertically() # # Returns true if the worksheet has been centered vertically for printing. # sub is_centered_vertically { my $self = shift; return $self->{HCenter}; } ############################################################################### # # is_print_gridlines() # # Returns true if the worksheet print "gridlines" option is turned on. # sub is_print_gridlines { my $self = shift; return $self->{PrintGrid}; } ############################################################################### # # is_print_row_col_headers() # # Returns true if the worksheet print "row and column headings" option is on. # sub is_print_row_col_headers { my $self = shift; return $self->{PrintHeaders}; } ############################################################################### # # is_print_black_and_white() # # Returns true if the worksheet print "black and white" option is turned on. # sub is_print_black_and_white { my $self = shift; return $self->{NoColor}; } ############################################################################### # # is_print_draft() # # Returns true if the worksheet print "draft" option is turned on. # sub is_print_draft { my $self = shift; return $self->{Draft}; } ############################################################################### # # is_print_comments() # # Returns true if the worksheet print "comments" option is turned on. # sub is_print_comments { my $self = shift; return $self->{Notes}; } =head2 get_tab_color() Return color index of tab, or undef if not set. =cut sub get_tab_color { my $worksheet = shift; return $worksheet->{TabColor}; } =head2 is_sheet_hidden() Return true if sheet is hidden =cut sub is_sheet_hidden { my $worksheet = shift; return $worksheet->{SheetHidden}; } =head2 is_row_hidden($row) In scalar context, return true if $row is hidden In array context, return an array whose elements are true if the corresponding row is hidden. =cut sub is_row_hidden { my $worksheet = shift; my ($row) = @_; unless ( $worksheet->{RowHidden} ) { return () if (wantarray); return 0; } return @{ $worksheet->{RowHidden} } if (wantarray); return $worksheet->{RowHidden}[$row]; } =head2 is_col_hidden($col) In scalar context, return true if $col is hidden In array context, return an array whose elements are true if the corresponding column is hidden. =cut sub is_col_hidden { my $worksheet = shift; my ($col) = @_; unless ( $worksheet->{ColHidden} ) { return () if (wantarray); return 0; } return @{ $worksheet->{ColHidden} } if (wantarray); return $worksheet->{ColHidden}[$col]; } ############################################################################### # # Mapping between legacy method names and new names. # { no warnings; # Ignore warnings about variables used only once. *sheetNo = *sheet_num; *Cell = *get_cell; *RowRange = *row_range; *ColRange = *col_range; } 1; __END__ =pod =head1 NAME Spreadsheet::ParseExcel::Worksheet - A class for Worksheets. =head1 SYNOPSIS See the documentation for L. =head1 DESCRIPTION This module is used in conjunction with Spreadsheet::ParseExcel. See the documentation for Spreadsheet::ParseExcel. =head1 Methods The C class encapsulates the properties of an Excel worksheet. It has the following methods: $worksheet->get_cell() $worksheet->row_range() $worksheet->col_range() $worksheet->get_name() $worksheet->get_h_pagebreaks() $worksheet->get_v_pagebreaks() $worksheet->get_merged_areas() $worksheet->get_row_heights() $worksheet->get_col_widths() $worksheet->get_default_row_height() $worksheet->get_default_col_width() $worksheet->get_header() $worksheet->get_footer() $worksheet->get_margin_left() $worksheet->get_margin_right() $worksheet->get_margin_top() $worksheet->get_margin_bottom() $worksheet->get_margin_header() $worksheet->get_margin_footer() $worksheet->get_paper() $worksheet->get_start_page() $worksheet->get_print_order() $worksheet->get_print_scale() $worksheet->get_fit_to_pages() $worksheet->is_portrait() $worksheet->is_centered_horizontally() $worksheet->is_centered_vertically() $worksheet->is_print_gridlines() $worksheet->is_print_row_col_headers() $worksheet->is_print_black_and_white() $worksheet->is_print_draft() $worksheet->is_print_comments() =head2 get_cell($row, $col) Return the L object at row C<$row> and column C<$col> if it is defined. Otherwise returns undef. my $cell = $worksheet->get_cell($row, $col); =head2 row_range() Returns a two-element list C<($min, $max)> containing the minimum and maximum defined rows in the worksheet. If there is no row defined C<$max> is smaller than C<$min>. my ( $row_min, $row_max ) = $worksheet->row_range(); =head2 col_range() Returns a two-element list C<($min, $max)> containing the minimum and maximum of defined columns in the worksheet. If there is no column defined C<$max> is smaller than C<$min>. my ( $col_min, $col_max ) = $worksheet->col_range(); =head2 get_name() The C method returns the name of the worksheet. my $name = $worksheet->get_name(); =head2 get_h_pagebreaks() The C method returns an array ref of row numbers where a horizontal page break occurs. my $h_pagebreaks = $worksheet->get_h_pagebreaks(); Returns C if there are no pagebreaks. =head2 get_v_pagebreaks() The C method returns an array ref of column numbers where a vertical page break occurs. my $v_pagebreaks = $worksheet->get_v_pagebreaks(); Returns C if there are no pagebreaks. =head2 get_merged_areas() The C method returns an array ref of cells that are merged. my $merged_areas = $worksheet->get_merged_areas(); Each merged area is represented as follows: [ $start_row, $start_col, $end_row, $end_col] Returns C if there are no merged areas. =head2 get_row_heights() The C method returns an array_ref of row heights in scalar context, and an array in list context. my $row_heights = $worksheet->get_row_heights(); Returns C if the property isn't set. =head2 get_col_widths() The C method returns an array_ref of column widths in scalar context, and an array in list context. my $col_widths = $worksheet->get_col_widths(); Returns C if the property isn't set. =head2 get_default_row_height() The C method returns the default row height for the worksheet. Generally 12.75. my $default_row_height = $worksheet->get_default_row_height(); =head2 get_default_col_width() The C method returns the default column width for the worksheet. Generally 8.43. my $default_col_width = $worksheet->get_default_col_width(); =head2 get_header() The C method returns the worksheet header string. This string can contain control codes for alignment and font properties. Refer to the Excel on-line help on headers and footers or to the Spreadsheet::WriteExcel documentation for set_header(). my $header = $worksheet->get_header(); Returns C if the property isn't set. =head2 get_footer() The C method returns the worksheet footer string. This string can contain control codes for alignment and font properties. Refer to the Excel on-line help on headers and footers or to the Spreadsheet::WriteExcel documentation for set_header(). my $footer = $worksheet->get_footer(); Returns C if the property isn't set. =head2 get_margin_left() The C method returns the left margin of the worksheet in inches. my $margin_left = $worksheet->get_margin_left(); Returns C if the property isn't set. =head2 get_margin_right() The C method returns the right margin of the worksheet in inches. my $margin_right = $worksheet->get_margin_right(); Returns C if the property isn't set. =head2 get_margin_top() The C method returns the top margin of the worksheet in inches. my $margin_top = $worksheet->get_margin_top(); Returns C if the property isn't set. =head2 get_margin_bottom() The C method returns the bottom margin of the worksheet in inches. my $margin_bottom = $worksheet->get_margin_bottom(); Returns C if the property isn't set. =head2 get_margin_header() The C method returns the header margin of the worksheet in inches. my $margin_header = $worksheet->get_margin_header(); Returns a default value of 0.5 if not set. =head2 get_margin_footer() The C method returns the footer margin of the worksheet in inches. my $margin_footer = $worksheet->get_margin_footer(); Returns a default value of 0.5 if not set. =head2 get_paper() The C method returns the printer paper size. my $paper = $worksheet->get_paper(); The value corresponds to the formats shown below: Index Paper format Paper size ===== ============ ========== 0 Printer default - 1 Letter 8 1/2 x 11 in 2 Letter Small 8 1/2 x 11 in 3 Tabloid 11 x 17 in 4 Ledger 17 x 11 in 5 Legal 8 1/2 x 14 in 6 Statement 5 1/2 x 8 1/2 in 7 Executive 7 1/4 x 10 1/2 in 8 A3 297 x 420 mm 9 A4 210 x 297 mm 10 A4 Small 210 x 297 mm 11 A5 148 x 210 mm 12 B4 250 x 354 mm 13 B5 182 x 257 mm 14 Folio 8 1/2 x 13 in 15 Quarto 215 x 275 mm 16 - 10x14 in 17 - 11x17 in 18 Note 8 1/2 x 11 in 19 Envelope 9 3 7/8 x 8 7/8 20 Envelope 10 4 1/8 x 9 1/2 21 Envelope 11 4 1/2 x 10 3/8 22 Envelope 12 4 3/4 x 11 23 Envelope 14 5 x 11 1/2 24 C size sheet - 25 D size sheet - 26 E size sheet - 27 Envelope DL 110 x 220 mm 28 Envelope C3 324 x 458 mm 29 Envelope C4 229 x 324 mm 30 Envelope C5 162 x 229 mm 31 Envelope C6 114 x 162 mm 32 Envelope C65 114 x 229 mm 33 Envelope B4 250 x 353 mm 34 Envelope B5 176 x 250 mm 35 Envelope B6 176 x 125 mm 36 Envelope 110 x 230 mm 37 Monarch 3.875 x 7.5 in 38 Envelope 3 5/8 x 6 1/2 in 39 Fanfold 14 7/8 x 11 in 40 German Std Fanfold 8 1/2 x 12 in 41 German Legal Fanfold 8 1/2 x 13 in 256 User defined The two most common paper sizes are C<1 = "US Letter"> and C<9 = A4>. Returns 9 by default. =head2 get_start_page() The C method returns the page number that printing will start from. my $start_page = $worksheet->get_start_page(); Returns 0 if the property isn't set. =head2 get_print_order() The C method returns 0 if the worksheet print "page order" is "Down then over" (the default) or 1 if it is "Over then down". my $print_order = $worksheet->get_print_order(); =head2 get_print_scale() The C method returns the workbook scale for printing. The print scale factor can be in the range 10 .. 400. my $print_scale = $worksheet->get_print_scale(); Returns 100 by default. =head2 get_fit_to_pages() The C method returns the number of pages wide and high that the printed worksheet page will fit to. my ($pages_wide, $pages_high) = $worksheet->get_fit_to_pages(); Returns (0, 0) if the property isn't set. =head2 is_portrait() The C method returns true if the worksheet has been set for printing in portrait mode. my $is_portrait = $worksheet->is_portrait(); Returns 0 if the worksheet has been set for printing in horizontal mode. =head2 is_centered_horizontally() The C method returns true if the worksheet has been centered horizontally for printing. my $is_centered_horizontally = $worksheet->is_centered_horizontally(); Returns 0 if the property isn't set. =head2 is_centered_vertically() The C method returns true if the worksheet has been centered vertically for printing. my $is_centered_vertically = $worksheet->is_centered_vertically(); Returns 0 if the property isn't set. =head2 is_print_gridlines() The C method returns true if the worksheet print "gridlines" option is turned on. my $is_print_gridlines = $worksheet->is_print_gridlines(); Returns 0 if the property isn't set. =head2 is_print_row_col_headers() The C method returns true if the worksheet print "row and column headings" option is turned on. my $is_print_row_col_headers = $worksheet->is_print_row_col_headers(); Returns 0 if the property isn't set. =head2 is_print_black_and_white() The C method returns true if the worksheet print "black and white" option is turned on. my $is_print_black_and_white = $worksheet->is_print_black_and_white(); Returns 0 if the property isn't set. =head2 is_print_draft() The C method returns true if the worksheet print "draft" option is turned on. my $is_print_draft = $worksheet->is_print_draft(); Returns 0 if the property isn't set. =head2 is_print_comments() The C method returns true if the worksheet print "comments" option is turned on. my $is_print_comments = $worksheet->is_print_comments(); Returns 0 if the property isn't set. =head1 AUTHOR Current maintainer 0.60+: Douglas Wilson dougw@cpan.org Maintainer 0.40-0.59: John McNamara jmcnamara@cpan.org Maintainer 0.27-0.33: Gabor Szabo szabgab@cpan.org Original author: Kawai Takanori kwitknr@cpan.org =head1 COPYRIGHT Copyright (c) 2014 Douglas Wilson Copyright (c) 2009-2013 John McNamara Copyright (c) 2006-2008 Gabor Szabo Copyright (c) 2000-2006 Kawai Takanori All rights reserved. You may distribute under the terms of either the GNU General Public License or the Artistic License, as specified in the Perl README file. =cut Spreadsheet-ParseExcel-0.66/lib/Spreadsheet/ParseExcel/Dump.pm000644 000765 000024 00000017567 14543413026 024343 0ustar00Johnstaff000000 000000 package Spreadsheet::ParseExcel::Dump; ############################################################################### # # Spreadsheet::ParseExcel::Dump - A class for dumping Excel records. # # Used in conjunction with Spreadsheet::ParseExcel. # # Copyright (c) 2014 Douglas Wilson # Copyright (c) 2009-2013 John McNamara # Copyright (c) 2006-2008 Gabor Szabo # Copyright (c) 2000-2006 Kawai Takanori # # perltidy with standard settings. # # Documentation after __END__ # use strict; use warnings; our $VERSION = '0.66'; my %NameTbl = ( #P291 0x0A => 'EOF', 0x0C => 'CALCCOUNT', 0x0D => 'CALCMODE', 0x0E => 'PRECISION', 0x0F => 'REFMODE', 0x10 => 'DELTA', 0x11 => 'ITERATION', 0x12 => 'PROTECT', 0x13 => 'PASSWORD', 0x14 => 'HEADER', 0x15 => 'FOOTER', 0x16 => 'EXTERNCOUNT', 0x17 => 'EXTERNSHEET', 0x19 => 'WINDOWPROTECT', 0x1A => 'VERTICALPAGEBREAKS', 0x1B => 'HORIZONTALPAGEBREAKS', 0x1C => 'NOTE', 0x1D => 'SELECTION', 0x22 => '1904', 0x26 => 'LEFTMARGIN', 0x27 => 'RIGHTMARGIN', 0x28 => 'TOPMARGIN', 0x29 => 'BOTTOMMARGIN', 0x2A => 'PRINTHEADERS', 0x2B => 'PRINTGRIDLINES', 0x2F => 'FILEPASS', 0x3C => 'COUNTINUE', 0x3D => 'WINDOW1', 0x40 => 'BACKUP', 0x41 => 'PANE', 0x42 => 'CODEPAGE', 0x4D => 'PLS', 0x50 => 'DCON', 0x51 => 'DCONREF', #P292 0x52 => 'DCONNAME', 0x55 => 'DEFCOLWIDTH', 0x59 => 'XCT', 0x5A => 'CRN', 0x5B => 'FILESHARING', 0x5C => 'WRITEACCES', 0x5D => 'OBJ', 0x5E => 'UNCALCED', 0x5F => 'SAVERECALC', 0x60 => 'TEMPLATE', 0x63 => 'OBJPROTECT', 0x7D => 'COLINFO', 0x7E => 'RK', 0x7F => 'IMDATA', 0x80 => 'GUTS', 0x81 => 'WSBOOL', 0x82 => 'GRIDSET', 0x83 => 'HCENTER', 0x84 => 'VCENTER', 0x85 => 'BOUNDSHEET', 0x86 => 'WRITEPROT', 0x87 => 'ADDIN', 0x88 => 'EDG', 0x89 => 'PUB', 0x8C => 'COUNTRY', 0x8D => 'HIDEOBJ', 0x90 => 'SORT', 0x91 => 'SUB', 0x92 => 'PALETTE', 0x94 => 'LHRECORD', 0x95 => 'LHNGRAPH', 0x96 => 'SOUND', 0x98 => 'LPR', 0x99 => 'STANDARDWIDTH', 0x9A => 'FNGROUPNAME', 0x9B => 'FILTERMODE', 0x9C => 'FNGROUPCOUNT', #P293 0x9D => 'AUTOFILTERINFO', 0x9E => 'AUTOFILTER', 0xA0 => 'SCL', 0xA1 => 'SETUP', 0xA9 => 'COORDLIST', 0xAB => 'GCW', 0xAE => 'SCENMAN', 0xAF => 'SCENARIO', 0xB0 => 'SXVIEW', 0xB1 => 'SXVD', 0xB2 => 'SXV', 0xB4 => 'SXIVD', 0xB5 => 'SXLI', 0xB6 => 'SXPI', 0xB8 => 'DOCROUTE', 0xB9 => 'RECIPNAME', 0xBC => 'SHRFMLA', 0xBD => 'MULRK', 0xBE => 'MULBLANK', 0xBF => 'TOOLBARHDR', 0xC0 => 'TOOLBAREND', 0xC1 => 'MMS', 0xC2 => 'ADDMENU', 0xC3 => 'DELMENU', 0xC5 => 'SXDI', 0xC6 => 'SXDB', 0xCD => 'SXSTRING', 0xD0 => 'SXTBL', 0xD1 => 'SXTBRGIITM', 0xD2 => 'SXTBPG', 0xD3 => 'OBPROJ', 0xD5 => 'SXISDTM', 0xD6 => 'RSTRING', 0xD7 => 'DBCELL', 0xDA => 'BOOKBOOL', 0xDC => 'PARAMQRY', 0xDC => 'SXEXT', 0xDD => 'SCENPROTECT', 0xDE => 'OLESIZE', #P294 0xDF => 'UDDESC', 0xE0 => 'XF', 0xE1 => 'INTERFACEHDR', 0xE2 => 'INTERFACEEND', 0xE3 => 'SXVS', 0xEA => 'TABIDCONF', 0xEB => 'MSODRAWINGGROUP', 0xEC => 'MSODRAWING', 0xED => 'MSODRAWINGSELECTION', 0xEF => 'PHONETICINFO', 0xF0 => 'SXRULE', 0xF1 => 'SXEXT', 0xF2 => 'SXFILT', 0xF6 => 'SXNAME', 0xF7 => 'SXSELECT', 0xF8 => 'SXPAIR', 0xF9 => 'SXFMLA', 0xFB => 'SXFORMAT', 0xFC => 'SST', 0xFD => 'LABELSST', 0xFF => 'EXTSST', 0x100 => 'SXVDEX', 0x103 => 'SXFORMULA', 0x122 => 'SXDBEX', 0x13D => 'TABID', 0x160 => 'USESELFS', 0x161 => 'DSF', 0x162 => 'XL5MODIFY', 0x1A5 => 'FILESHARING2', 0x1A9 => 'USERBVIEW', 0x1AA => 'USERVIEWBEGIN', 0x1AB => 'USERSVIEWEND', 0x1AD => 'QSI', 0x1AE => 'SUPBOOK', 0x1AF => 'PROT4REV', 0x1B0 => 'CONDFMT', 0x1B1 => 'CF', 0x1B2 => 'DVAL', #P295 0x1B5 => 'DCONBIN', 0x1B6 => 'TXO', 0x1B7 => 'REFRESHALL', 0x1B8 => 'HLINK', 0x1BA => 'CODENAME', 0x1BB => 'SXFDBTYPE', 0x1BC => 'PROT4REVPASS', 0x1BE => 'DV', 0x200 => 'DIMENSIONS', 0x201 => 'BLANK', 0x202 => 'Integer', #Not Documented 0x203 => 'NUMBER', 0x204 => 'LABEL', 0x205 => 'BOOLERR', 0x207 => 'STRING', 0x208 => 'ROW', 0x20B => 'INDEX', 0x218 => 'NAME', 0x221 => 'ARRAY', 0x223 => 'EXTERNNAME', 0x225 => 'DEFAULTROWHEIGHT', 0x231 => 'FONT', 0x236 => 'TABLE', 0x23E => 'WINDOW2', 0x293 => 'STYLE', 0x406 => 'FORMULA', 0x41E => 'FORMAT', 0x18 => 'NAME', 0x06 => 'FORMULA', 0x09 => 'BOF(BIFF2)', 0x209 => 'BOF(BIFF3)', 0x409 => 'BOF(BIFF4)', 0x809 => 'BOF(BIFF5-7)', 0x31 => 'FONT', 0x27E => 'RK', #Chart/Graph 0x1001 => 'UNITS', 0x1002 => 'CHART', 0x1003 => 'SERISES', 0x1006 => 'DATAFORMAT', 0x1007 => 'LINEFORMAT', 0x1009 => 'MAKERFORMAT', 0x100A => 'AREAFORMAT', 0x100B => 'PIEFORMAT', 0x100C => 'ATTACHEDLABEL', 0x100D => 'SERIESTEXT', 0x1014 => 'CHARTFORMAT', 0x1015 => 'LEGEND', 0x1016 => 'SERIESLIST', 0x1017 => 'BAR', 0x1018 => 'LINE', 0x1019 => 'PIE', 0x101A => 'AREA', 0x101B => 'SCATTER', 0x101C => 'CHARTLINE', 0x101D => 'AXIS', 0x101E => 'TICK', 0x101F => 'VALUERANGE', 0x1020 => 'CATSERRANGE', 0x1021 => 'AXISLINEFORMAT', 0x1022 => 'CHARTFORMATLINK', 0x1024 => 'DEFAULTTEXT', 0x1025 => 'TEXT', 0x1026 => 'FONTX', 0x1027 => 'OBJECTLINK', 0x1032 => 'FRAME', 0x1033 => 'BEGIN', 0x1034 => 'END', 0x1035 => 'PLOTAREA', 0x103A => '3D', 0x103C => 'PICF', 0x103D => 'DROPBAR', 0x103E => 'RADAR', 0x103F => 'SURFACE', 0x1040 => 'RADARAREA', 0x1041 => 'AXISPARENT', 0x1043 => 'LEGENDXN', 0x1044 => 'SHTPROPS', 0x1045 => 'SERTOCRT', 0x1046 => 'AXESUSED', 0x1048 => 'SBASEREF', 0x104A => 'SERPARENT', 0x104B => 'SERAUXTREND', 0x104E => 'IFMT', 0x104F => 'POS', 0x1050 => 'ALRUNS', 0x1051 => 'AI', 0x105B => 'SERAUXERRBAR', 0x105D => 'SERFMT', 0x1060 => 'FBI', 0x1061 => 'BOPPOP', 0x1062 => 'AXCEXT', 0x1063 => 'DAT', 0x1064 => 'PLOTGROWTH', 0x1065 => 'SINDEX', 0x1066 => 'GELFRAME', 0x1067 => 'BPOPPOPCUSTOM', ); #------------------------------------------------------------------------------ # subDUMP (for Spreadsheet::ParseExcel) #------------------------------------------------------------------------------ sub subDUMP { my ( $oBook, $bOp, $bLen, $sWk ) = @_; printf "%04X:%-23s (Len:%3d) : %s\n", $bOp, OpName($bOp), $bLen, unpack( "H40", $sWk ); } #------------------------------------------------------------------------------ # Spreadsheet::ParseExcel->OpName #------------------------------------------------------------------------------ sub OpName { my ($bOp) = @_; return ( defined $NameTbl{$bOp} ) ? $NameTbl{$bOp} : 'undef'; } 1; __END__ =pod =head1 NAME Spreadsheet::ParseExcel::Dump - A class for dumping Excel records. =head1 SYNOPSIS See the documentation for Spreadsheet::ParseExcel. =head1 DESCRIPTION This module is used in conjunction with Spreadsheet::ParseExcel. See the documentation for Spreadsheet::ParseExcel. =head1 AUTHOR Current maintainer 0.60+: Douglas Wilson dougw@cpan.org Maintainer 0.40-0.59: John McNamara jmcnamara@cpan.org Maintainer 0.27-0.33: Gabor Szabo szabgab@cpan.org Original author: Kawai Takanori kwitknr@cpan.org =head1 COPYRIGHT Copyright (c) 2014 Douglas Wilson Copyright (c) 2009-2013 John McNamara Copyright (c) 2006-2008 Gabor Szabo Copyright (c) 2000-2006 Kawai Takanori All rights reserved. You may distribute under the terms of either the GNU General Public License or the Artistic License, as specified in the Perl README file. =cut Spreadsheet-ParseExcel-0.66/lib/Spreadsheet/ParseExcel/SaveParser/000755 000765 000024 00000000000 14543415025 025134 5ustar00Johnstaff000000 000000 Spreadsheet-ParseExcel-0.66/lib/Spreadsheet/ParseExcel/FmtUnicode.pm000644 000765 000024 00000005306 14543413026 025457 0ustar00Johnstaff000000 000000 package Spreadsheet::ParseExcel::FmtUnicode; ############################################################################### # # Spreadsheet::ParseExcel::FmtUnicode - A class for Cell formats. # # Used in conjunction with Spreadsheet::ParseExcel. # # Copyright (c) 2014 Douglas Wilson # Copyright (c) 2009-2013 John McNamara # Copyright (c) 2006-2008 Gabor Szabo # Copyright (c) 2000-2006 Kawai Takanori # # perltidy with standard settings. # # Documentation after __END__ # use strict; use warnings; use Unicode::Map; use base 'Spreadsheet::ParseExcel::FmtDefault'; our $VERSION = '0.66'; #------------------------------------------------------------------------------ # new (for Spreadsheet::ParseExcel::FmtUnicode) #------------------------------------------------------------------------------ sub new { my ( $sPkg, %hKey ) = @_; my $sMap = $hKey{Unicode_Map}; my $oMap; $oMap = Unicode::Map->new($sMap) if $sMap; my $oThis = { Unicode_Map => $sMap, _UniMap => $oMap, }; bless $oThis; return $oThis; } #------------------------------------------------------------------------------ # TextFmt (for Spreadsheet::ParseExcel::FmtUnicode) #------------------------------------------------------------------------------ sub TextFmt { my ( $oThis, $sTxt, $sCode ) = @_; if ( $oThis->{_UniMap} ) { if ( !defined($sCode) ) { my $sSv = $sTxt; $sTxt =~ s/(.)/\x00$1/sg; $sTxt = $oThis->{_UniMap}->from_unicode($sTxt); $sTxt = $sSv unless ($sTxt); } elsif ( $sCode eq 'ucs2' ) { $sTxt = $oThis->{_UniMap}->from_unicode($sTxt); } # $sTxt = $oThis->{_UniMap}->from_unicode($sTxt) # if(defined($sCode) && $sCode eq 'ucs2'); return $sTxt; } else { return $sTxt; } } 1; __END__ =pod =head1 NAME Spreadsheet::ParseExcel::FmtUnicode - A class for Cell formats. =head1 SYNOPSIS See the documentation for Spreadsheet::ParseExcel. =head1 DESCRIPTION This module is used in conjunction with Spreadsheet::ParseExcel. See the documentation for Spreadsheet::ParseExcel. =head1 AUTHOR Current maintainer 0.60+: Douglas Wilson dougw@cpan.org Maintainer 0.40-0.59: John McNamara jmcnamara@cpan.org Maintainer 0.27-0.33: Gabor Szabo szabgab@cpan.org Original author: Kawai Takanori kwitknr@cpan.org =head1 COPYRIGHT Copyright (c) 2014 Douglas Wilson Copyright (c) 2009-2013 John McNamara Copyright (c) 2006-2008 Gabor Szabo Copyright (c) 2000-2006 Kawai Takanori All rights reserved. You may distribute under the terms of either the GNU General Public License or the Artistic License, as specified in the Perl README file. =cut Spreadsheet-ParseExcel-0.66/lib/Spreadsheet/ParseExcel/FmtJapan.pm000644 000765 000024 00000013040 14543413026 025114 0ustar00Johnstaff000000 000000 package Spreadsheet::ParseExcel::FmtJapan; use utf8; ############################################################################### # # Spreadsheet::ParseExcel::FmtJapan - A class for Cell formats. # # Used in conjunction with Spreadsheet::ParseExcel. # # Copyright (c) 2014 Douglas Wilson # Copyright (c) 2009-2013 John McNamara # Copyright (c) 2006-2008 Gabor Szabo # Copyright (c) 2000-2006 Kawai Takanori # # perltidy with standard settings. # # Documentation after __END__ # use strict; use warnings; use Encode qw(find_encoding decode); use base 'Spreadsheet::ParseExcel::FmtDefault'; our $VERSION = '0.66'; my %FormatTable = ( 0x00 => 'General', 0x01 => '0', 0x02 => '0.00', 0x03 => '#,##0', 0x04 => '#,##0.00', 0x05 => '(\\#,##0_);(\\#,##0)', 0x06 => '(\\#,##0_);[Red](\\#,##0)', 0x07 => '(\\#,##0.00_);(\\#,##0.00_)', 0x08 => '(\\#,##0.00_);[Red](\\#,##0.00_)', 0x09 => '0%', 0x0A => '0.00%', 0x0B => '0.00E+00', 0x0C => '# ?/?', 0x0D => '# ??/??', # 0x0E => 'm/d/yy', 0x0E => 'yyyy/m/d', 0x0F => 'd-mmm-yy', 0x10 => 'd-mmm', 0x11 => 'mmm-yy', 0x12 => 'h:mm AM/PM', 0x13 => 'h:mm:ss AM/PM', 0x14 => 'h:mm', 0x15 => 'h:mm:ss', # 0x16 => 'm/d/yy h:mm', 0x16 => 'yyyy/m/d h:mm', #0x17-0x24 -- Differs in Natinal 0x1E => 'm/d/yy', 0x1F => 'yyyy"年"m"月"d"日"', 0x20 => 'h"時"mm"分"', 0x21 => 'h"時"mm"分"ss"秒"', #0x17-0x24 -- Differs in Natinal 0x25 => '(#,##0_);(#,##0)', 0x26 => '(#,##0_);[Red](#,##0)', 0x27 => '(#,##0.00);(#,##0.00)', 0x28 => '(#,##0.00);[Red](#,##0.00)', 0x29 => '_(*#,##0_);_(*(#,##0);_(*"-"_);_(@_)', 0x2A => '_(\\*#,##0_);_(\\*(#,##0);_(*"-"_);_(@_)', 0x2B => '_(*#,##0.00_);_(*(#,##0.00);_(*"-"??_);_(@_)', 0x2C => '_(\\*#,##0.00_);_(\\*(#,##0.00);_(*"-"??_);_(@_)', 0x2D => 'mm:ss', 0x2E => '[h]:mm:ss', 0x2F => 'mm:ss.0', 0x30 => '##0.0E+0', 0x31 => '@', 0x37 => 'yyyy"年"m"月"', 0x38 => 'm"月"d"日"', 0x39 => 'ge.m.d', 0x3A => 'ggge"年"m"月"d"日"', ); #------------------------------------------------------------------------------ # new (for Spreadsheet::ParseExcel::FmtJapan) #------------------------------------------------------------------------------ sub new { my ( $class, %args ) = @_; my $encoding = $args{Code} || $args{encoding}; my $self = { Code => $encoding }; if($encoding){ $self->{encoding} = find_encoding($encoding eq 'sjis' ? 'cp932' : $encoding) or do{ require Carp; Carp::croak(qq{Unknown encoding '$encoding'}); }; } return bless $self, $class; } #------------------------------------------------------------------------------ # TextFmt (for Spreadsheet::ParseExcel::FmtJapan) #------------------------------------------------------------------------------ sub TextFmt { my ( $self, $text, $input_encoding ) = @_; if(!defined $input_encoding){ $input_encoding = 'utf8'; } elsif($input_encoding eq '_native_'){ $input_encoding = 'cp932'; # Shift_JIS in Microsoft products } $text = decode($input_encoding, $text); return $self->{Code} ? $self->{encoding}->encode($text) : $text; } #------------------------------------------------------------------------------ # FmtStringDef (for Spreadsheet::ParseExcel::FmtJapan) #------------------------------------------------------------------------------ sub FmtStringDef { my ( $self, $format_index, $book ) = @_; return $self->SUPER::FmtStringDef( $format_index, $book, \%FormatTable ); } #------------------------------------------------------------------------------ # CnvNengo (for Spreadsheet::ParseExcel::FmtJapan) #------------------------------------------------------------------------------ # Convert A.D. into Japanese Nengo (aka Gengo) my @Nengo = ( { name => '平成', # Heisei abbr_name => 'H', base => 1988, start => 19890108, }, { name => '昭和', # Showa abbr_name => 'S', base => 1925, start => 19261225, }, { name => '大正', # Taisho abbr_name => 'T', base => 1911, start => 19120730, }, { name => '明治', # Meiji abbr_name => 'M', base => 1867, start => 18680908, }, ); # Usage: CnvNengo(name => @tm) or CnvNeng(abbr_name => @tm) sub CnvNengo { my ( $kind, @tm ) = @_; my $year = $tm[5] + 1900; my $wk = ($year * 10000) + ($tm[4] * 100) + ($tm[3] * 1); #my $wk = sprintf( '%04d%02d%02d', $year, $tm[4], $tm[3] ); foreach my $nengo(@Nengo){ if( $wk >= $nengo->{start} ){ return $nengo->{$kind} . ($year - $nengo->{base}); } } return $year; } 1; __END__ =pod =head1 NAME Spreadsheet::ParseExcel::FmtJapan - A class for Cell formats. =head1 SYNOPSIS See the documentation for Spreadsheet::ParseExcel. =head1 DESCRIPTION This module is used in conjunction with Spreadsheet::ParseExcel. See the documentation for Spreadsheet::ParseExcel. =head1 AUTHOR Current maintainer 0.60+: Douglas Wilson dougw@cpan.org Maintainer 0.40-0.59: John McNamara jmcnamara@cpan.org Maintainer 0.27-0.33: Gabor Szabo szabgab@cpan.org Original author: Kawai Takanori kwitknr@cpan.org =head1 COPYRIGHT Copyright (c) 2014 Douglas Wilson Copyright (c) 2009-2013 John McNamara Copyright (c) 2006-2008 Gabor Szabo Copyright (c) 2000-2006 Kawai Takanori All rights reserved. You may distribute under the terms of either the GNU General Public License or the Artistic License, as specified in the Perl README file. =cut Spreadsheet-ParseExcel-0.66/lib/Spreadsheet/ParseExcel/FmtJapan2.pm000644 000765 000024 00000005271 14543413026 025205 0ustar00Johnstaff000000 000000 package Spreadsheet::ParseExcel::FmtJapan2; ############################################################################### # # Spreadsheet::ParseExcel::FmtJapan2 - A class for Cell formats. # # Used in conjunction with Spreadsheet::ParseExcel. # # Copyright (c) 2014 Douglas Wilson # Copyright (c) 2009-2013 John McNamara # Copyright (c) 2006-2008 Gabor Szabo # Copyright (c) 2000-2006 Kawai Takanori # # perltidy with standard settings. # # Documentation after __END__ # use strict; use warnings; use Jcode; use Unicode::Map; use base 'Spreadsheet::ParseExcel::FmtJapan'; our $VERSION = '0.66'; #------------------------------------------------------------------------------ # new (for Spreadsheet::ParseExcel::FmtJapan2) #------------------------------------------------------------------------------ sub new { my ( $sPkg, %hKey ) = @_; my $oMap = Unicode::Map->new('CP932Excel'); die "NO MAP FILE CP932Excel!!" unless ( -r Unicode::Map->mapping("CP932Excel") ); my $oThis = { Code => $hKey{Code}, _UniMap => $oMap, }; bless $oThis; $oThis->SUPER::new(%hKey); return $oThis; } #------------------------------------------------------------------------------ # TextFmt (for Spreadsheet::ParseExcel::FmtJapan2) #------------------------------------------------------------------------------ sub TextFmt { my ( $oThis, $sTxt, $sCode ) = @_; # $sCode = 'sjis' if((! defined($sCode)) || ($sCode eq '_native_')); if ( $oThis->{Code} ) { if ( !defined($sCode) ) { $sTxt =~ s/(.)/\x00$1/sg; $sTxt = $oThis->{_UniMap}->from_unicode($sTxt); } elsif ( $sCode eq 'ucs2' ) { $sTxt = $oThis->{_UniMap}->from_unicode($sTxt); } return Jcode::convert( $sTxt, $oThis->{Code}, 'sjis' ); } else { return $sTxt; } } 1; __END__ =pod =head1 NAME Spreadsheet::ParseExcel::FmtJapan2 - A class for Cell formats. =head1 SYNOPSIS See the documentation for Spreadsheet::ParseExcel. =head1 DESCRIPTION This module is used in conjunction with Spreadsheet::ParseExcel. See the documentation for Spreadsheet::ParseExcel. =head1 AUTHOR Current maintainer 0.60+: Douglas Wilson dougw@cpan.org Maintainer 0.40-0.59: John McNamara jmcnamara@cpan.org Maintainer 0.27-0.33: Gabor Szabo szabgab@cpan.org Original author: Kawai Takanori kwitknr@cpan.org =head1 COPYRIGHT Copyright (c) 2014 Douglas Wilson Copyright (c) 2009-2013 John McNamara Copyright (c) 2006-2008 Gabor Szabo Copyright (c) 2000-2006 Kawai Takanori All rights reserved. You may distribute under the terms of either the GNU General Public License or the Artistic License, as specified in the Perl README file. =cut Spreadsheet-ParseExcel-0.66/lib/Spreadsheet/ParseExcel/SaveParser/Workbook.pm000644 000765 000024 00000035777 14543413026 027311 0ustar00Johnstaff000000 000000 package Spreadsheet::ParseExcel::SaveParser::Workbook; ############################################################################### # # Spreadsheet::ParseExcel::SaveParser::Workbook - A class for SaveParser Workbooks. # # Used in conjunction with Spreadsheet::ParseExcel. # # Copyright (c) 2014 Douglas Wilson # Copyright (c) 2009-2013 John McNamara # Copyright (c) 2006-2008 Gabor Szabo # Copyright (c) 2000-2006 Kawai Takanori # # perltidy with standard settings. # # Documentation after __END__ # use strict; use warnings; use base 'Spreadsheet::ParseExcel::Workbook'; our $VERSION = '0.66'; #============================================================================== # Spreadsheet::ParseExcel::SaveParser::Workbook #============================================================================== sub new { my ( $sPkg, $oBook ) = @_; return undef unless ( defined $oBook ); my %oThis = %$oBook; bless \%oThis, $sPkg; # re-bless worksheets (and set their _Book properties !!!) my $sWkP = ref($sPkg) || "$sPkg"; $sWkP =~ s/Workbook$/Worksheet/; map { bless( $_, $sWkP ); } @{ $oThis{Worksheet} }; map { $_->{_Book} = \%oThis; } @{ $oThis{Worksheet} }; return \%oThis; } #------------------------------------------------------------------------------ # Parse (for Spreadsheet::ParseExcel::SaveParser::Workbook) #------------------------------------------------------------------------------ sub Parse { my ( $sClass, $sFile, $oWkFmt ) = @_; my $oBook = Spreadsheet::ParseExcel::Workbook->Parse( $sFile, $oWkFmt ); bless $oBook, $sClass; # re-bless worksheets (and set their _Book properties !!!) my $sWkP = ref($sClass) || "$sClass"; $sWkP =~ s/Workbook$/Worksheet/; map { bless( $_, $sWkP ); } @{ $oBook->{Worksheet} }; map { $_->{_Book} = $oBook; } @{ $oBook->{Worksheet} }; return $oBook; } #------------------------------------------------------------------------------ # SaveAs (for Spreadsheet::ParseExcel::SaveParser::Workbook) #------------------------------------------------------------------------------ sub SaveAs { my ( $oBook, $sName ) = @_; # Create a new Excel workbook my $oWrEx = Spreadsheet::WriteExcel->new($sName); $oWrEx->compatibility_mode(); my %hFmt; my $iNo = 0; my @aAlH = ( 'left', 'left', 'center', 'right', 'fill', 'justify', 'merge', 'equal_space' ); my @aAlV = ( 'top', 'vcenter', 'bottom', 'vjustify', 'vequal_space' ); foreach my $pFmt ( @{ $oBook->{Format} } ) { my $oFmt = $oWrEx->addformat(); # Add Formats unless ( $pFmt->{Style} ) { $hFmt{$iNo} = $oFmt; my $rFont = $pFmt->{Font}; $oFmt->set_font( $rFont->{Name} ); $oFmt->set_size( $rFont->{Height} ); $oFmt->set_color( $rFont->{Color} ); $oFmt->set_bold( $rFont->{Bold} ); $oFmt->set_italic( $rFont->{Italic} ); $oFmt->set_underline( $rFont->{Underline} ); $oFmt->set_font_strikeout( $rFont->{Strikeout} ); $oFmt->set_font_script( $rFont->{Super} ); $oFmt->set_hidden( $rFont->{Hidden} ); #Add $oFmt->set_locked( $pFmt->{Lock} ); $oFmt->set_align( $aAlH[ $pFmt->{AlignH} ] ); $oFmt->set_align( $aAlV[ $pFmt->{AlignV} ] ); $oFmt->set_rotation( $pFmt->{Rotate} ); $oFmt->set_num_format( $oBook->{FmtClass}->FmtStringDef( $pFmt->{FmtIdx}, $oBook ) ); $oFmt->set_text_wrap( $pFmt->{Wrap} ); $oFmt->set_pattern( $pFmt->{Fill}->[0] ); $oFmt->set_fg_color( $pFmt->{Fill}->[1] ) if ( ( $pFmt->{Fill}->[1] >= 8 ) && ( $pFmt->{Fill}->[1] <= 63 ) ); $oFmt->set_bg_color( $pFmt->{Fill}->[2] ) if ( ( $pFmt->{Fill}->[2] >= 8 ) && ( $pFmt->{Fill}->[2] <= 63 ) ); $oFmt->set_left( ( $pFmt->{BdrStyle}->[0] > 7 ) ? 3 : $pFmt->{BdrStyle}->[0] ); $oFmt->set_right( ( $pFmt->{BdrStyle}->[1] > 7 ) ? 3 : $pFmt->{BdrStyle}->[1] ); $oFmt->set_top( ( $pFmt->{BdrStyle}->[2] > 7 ) ? 3 : $pFmt->{BdrStyle}->[2] ); $oFmt->set_bottom( ( $pFmt->{BdrStyle}->[3] > 7 ) ? 3 : $pFmt->{BdrStyle}->[3] ); $oFmt->set_left_color( $pFmt->{BdrColor}->[0] ) if ( ( $pFmt->{BdrColor}->[0] >= 8 ) && ( $pFmt->{BdrColor}->[0] <= 63 ) ); $oFmt->set_right_color( $pFmt->{BdrColor}->[1] ) if ( ( $pFmt->{BdrColor}->[1] >= 8 ) && ( $pFmt->{BdrColor}->[1] <= 63 ) ); $oFmt->set_top_color( $pFmt->{BdrColor}->[2] ) if ( ( $pFmt->{BdrColor}->[2] >= 8 ) && ( $pFmt->{BdrColor}->[2] <= 63 ) ); $oFmt->set_bottom_color( $pFmt->{BdrColor}->[3] ) if ( ( $pFmt->{BdrColor}->[3] >= 8 ) && ( $pFmt->{BdrColor}->[3] <= 63 ) ); } $iNo++; } for ( my $iSheet = 0 ; $iSheet < $oBook->{SheetCount} ; $iSheet++ ) { my $oWkS = $oBook->{Worksheet}[$iSheet]; my $oWrS = $oWrEx->addworksheet( $oWkS->{Name} ); #Landscape if ( !$oWkS->{Landscape} ) { # Landscape (0:Horizontal, 1:Vertical) $oWrS->set_landscape(); } else { $oWrS->set_portrait(); } #Protect if ( defined $oWkS->{Protect} ) { # Protect ('':NoPassword, Password:Password) if ( $oWkS->{Protect} ne '' ) { $oWrS->protect( $oWkS->{Protect} ); } else { $oWrS->protect(); } } if ( $oWkS->{Scale} != 100 ) { # Pages on fit with width and Heigt $oWrS->fit_to_pages( $oWkS->{FitWidth}, $oWkS->{FitHeight} ); #Print Scale and reset FitWidth/FitHeight $oWrS->set_print_scale( $oWkS->{Scale} ); } else { #Print Scale $oWrS->set_print_scale( $oWkS->{Scale} ); # Pages on fit with width and Heigt $oWrS->fit_to_pages( $oWkS->{FitWidth}, $oWkS->{FitHeight} ); } # Paper Size $oWrS->set_paper( $oWkS->{PaperSize} ); # Margin $oWrS->set_margin_left( $oWkS->{LeftMargin} ); $oWrS->set_margin_right( $oWkS->{RightMargin} ); $oWrS->set_margin_top( $oWkS->{TopMargin} ); $oWrS->set_margin_bottom( $oWkS->{BottomMargin} ); # HCenter $oWrS->center_horizontally() if ( $oWkS->{HCenter} ); # VCenter $oWrS->center_vertically() if ( $oWkS->{VCenter} ); # Header, Footer $oWrS->set_header( $oWkS->{Header}, $oWkS->{HeaderMargin} ); $oWrS->set_footer( $oWkS->{Footer}, $oWkS->{FooterMargin} ); # Print Area if ( ref( $oBook->{PrintArea}[$iSheet] ) eq 'ARRAY' ) { my $raP; for $raP ( @{ $oBook->{PrintArea}[$iSheet] } ) { $oWrS->print_area(@$raP); } } # Print Title my $raW; foreach $raW ( @{ $oBook->{PrintTitle}[$iSheet]->{Row} } ) { $oWrS->repeat_rows(@$raW); } foreach $raW ( @{ $oBook->{PrintTitle}[$iSheet]->{Column} } ) { $oWrS->repeat_columns(@$raW); } # Print Gridlines if ( $oWkS->{PrintGrid} == 1 ) { $oWrS->hide_gridlines(0); } else { $oWrS->hide_gridlines(1); } # Print Headings if ( $oWkS->{PrintHeaders} ) { $oWrS->print_row_col_headers(); } # Horizontal Page Breaks $oWrS->set_h_pagebreaks( @{ $oWkS->{HPageBreak} } ); # Veritical Page Breaks $oWrS->set_v_pagebreaks( @{ $oWkS->{VPageBreak} } ); # PageStart => $oWkS->{PageStart}, # Page number for start # UsePage => $oWkS->{UsePage}, # Use own start page number # NoColor => $oWkS->{NoColor}, # Print in black-white # Draft => $oWkS->{Draft}, # Print in draft mode # Notes => $oWkS->{Notes}, # Print notes # LeftToRight => $oWkS->{LeftToRight}, # Left to Right for ( my $iC = $oWkS->{MinCol} ; defined $oWkS->{MaxCol} && $iC <= $oWkS->{MaxCol} ; $iC++ ) { if ( defined $oWkS->{ColWidth}[$iC] ) { if ( $oWkS->{ColWidth}[$iC] > 0 ) { $oWrS->set_column( $iC, $iC, $oWkS->{ColWidth}[$iC] ) ; #, undef, 1) ; } else { $oWrS->set_column( $iC, $iC, 0, undef, 1 ); } } } my $merged_areas = $oWkS->get_merged_areas(); my $merged_areas_h = {}; if ($merged_areas) { foreach my $range (@$merged_areas) { $merged_areas_h->{$range->[0]}{$range->[1]} = $range; } } for ( my $iR = $oWkS->{MinRow} ; defined $oWkS->{MaxRow} && $iR <= $oWkS->{MaxRow} ; $iR++ ) { $oWrS->set_row( $iR, $oWkS->{RowHeight}[$iR] ); for ( my $iC = $oWkS->{MinCol} ; defined $oWkS->{MaxCol} && $iC <= $oWkS->{MaxCol} ; $iC++ ) { my $oWkC = $oWkS->{Cells}[$iR][$iC]; if ($oWkC) { if ( $oWkC->{Merged} and exists $merged_areas_h->{$iR}{$iC} ) { my $oFmtN = $oWrEx->addformat(); $oFmtN->copy( $hFmt{ $oWkC->{FormatNo} } ); $oWrS->merge_range ( @{$merged_areas_h->{$iR}{$iC}}, $oBook->{FmtClass} ->TextFmt( $oWkC->{Val}, $oWkC->{Code} ), $oFmtN ); } else { $oWrS->write( $iR, $iC, $oBook->{FmtClass} ->TextFmt( $oWkC->{Val}, $oWkC->{Code} ), $hFmt{ $oWkC->{FormatNo} } ); } } } } } return $oWrEx; } #------------------------------------------------------------------------------ # AddWorksheet (for Spreadsheet::ParseExcel::SaveParser::Workbook) #------------------------------------------------------------------------------ sub AddWorksheet { my ( $oBook, $sName, %hAttr ) = @_; $oBook->AddFormat if ( $#{ $oBook->{Format} } < 0 ); $hAttr{Name} ||= $sName; $hAttr{LeftMargin} ||= 0; $hAttr{RightMargin} ||= 0; $hAttr{TopMargin} ||= 0; $hAttr{BottomMargin} ||= 0; $hAttr{HeaderMargin} ||= 0; $hAttr{FooterMargin} ||= 0; $hAttr{FitWidth} ||= 0; $hAttr{FitHeight} ||= 0; $hAttr{PrintGrid} ||= 0; my $oWkS = Spreadsheet::ParseExcel::SaveParser::Worksheet->new(%hAttr); $oWkS->{_Book} = $oBook; $oWkS->{_SheetNo} = $oBook->{SheetCount}; $oBook->{Worksheet}[ $oBook->{SheetCount} ] = $oWkS; $oBook->{SheetCount}++; return $oWkS; #$oBook->{SheetCount} - 1; } #------------------------------------------------------------------------------ # AddFont (for Spreadsheet::ParseExcel::SaveParser::Workbook) #------------------------------------------------------------------------------ sub AddFont { my ( $oBook, %hAttr ) = @_; $hAttr{Name} ||= 'Arial'; $hAttr{Height} ||= 10; $hAttr{Bold} ||= 0; $hAttr{Italic} ||= 0; $hAttr{Underline} ||= 0; $hAttr{Strikeout} ||= 0; $hAttr{Super} ||= 0; push @{ $oBook->{Font} }, Spreadsheet::ParseExcel::Font->new(%hAttr); return $#{ $oBook->{Font} }; } #------------------------------------------------------------------------------ # AddFormat (for Spreadsheet::ParseExcel::SaveParser::Workbook) #------------------------------------------------------------------------------ sub AddFormat { my ( $oBook, %hAttr ) = @_; $hAttr{Fill} ||= [ 0, 0, 0 ]; $hAttr{BdrStyle} ||= [ 0, 0, 0, 0 ]; $hAttr{BdrColor} ||= [ 0, 0, 0, 0 ]; $hAttr{AlignH} ||= 0; $hAttr{AlignV} ||= 0; $hAttr{Rotate} ||= 0; $hAttr{Landscape} ||= 0; $hAttr{FmtIdx} ||= 0; if ( !defined( $hAttr{Font} ) ) { my $oFont; if ( defined $hAttr{FontNo} ) { $oFont = $oBook->{Font}[ $hAttr{FontNo} ]; } elsif ( !defined $oFont ) { if ( $#{ $oBook->{Font} } >= 0 ) { $oFont = $oBook->{Font}[0]; } else { my $iNo = $oBook->AddFont; $oFont = $oBook->{Font}[$iNo]; } } $hAttr{Font} = $oFont; } push @{ $oBook->{Format} }, Spreadsheet::ParseExcel::Format->new(%hAttr); return $#{ $oBook->{Format} }; } #------------------------------------------------------------------------------ # AddCell (for Spreadsheet::ParseExcel::SaveParser::Workbook) #------------------------------------------------------------------------------ sub AddCell { my ( $oBook, $iSheet, $iR, $iC, $sVal, $oCell, $sCode ) = @_; my %rhKey; $oCell ||= $oBook->{Worksheet}[$iSheet] ->{Cells}[$iR][$iC]->{FormatNo} || 0; my $iFmt = ( UNIVERSAL::isa( $oCell, 'Spreadsheet::ParseExcel::Cell' ) ) ? $oCell->{FormatNo} : ( ref($oCell) ) ? 0 : $oCell + 0; $rhKey{FormatNo} = $iFmt; $rhKey{Format} = $oBook->{Format}[$iFmt]; $rhKey{Val} = $sVal; $rhKey{Code} = $sCode || '_native_'; $oBook->{_CurSheet} = $iSheet; my $merged_areas = $oBook->{Worksheet}[$iSheet]->get_merged_areas(); my $merged_areas_h = {}; if ($merged_areas) { foreach my $range (@$merged_areas) { $merged_areas_h->{$range->[0]}{$range->[1]} = $range; } } my $oNewCell = Spreadsheet::ParseExcel::_NewCell( $oBook, $iR, $iC, %rhKey ); Spreadsheet::ParseExcel::_SetDimension( $oBook, $iR, $iC, $iC ); $oNewCell->{Merged} = 1 if exists $merged_areas_h->{$iR}{$iC}; return $oNewCell; } 1; __END__ =pod =head1 NAME Spreadsheet::ParseExcel::SaveParser::Workbook - A class for SaveParser Workbooks. =head1 SYNOPSIS See the documentation for Spreadsheet::ParseExcel. =head1 DESCRIPTION This module is used in conjunction with Spreadsheet::ParseExcel. See the documentation for Spreadsheet::ParseExcel. =head1 AUTHOR Current maintainer 0.60+: Douglas Wilson dougw@cpan.org Maintainer 0.40-0.59: John McNamara jmcnamara@cpan.org Maintainer 0.27-0.33: Gabor Szabo szabgab@cpan.org Original author: Kawai Takanori kwitknr@cpan.org =head1 COPYRIGHT Copyright (c) 2014 Douglas Wilson Copyright (c) 2009-2013 John McNamara Copyright (c) 2006-2008 Gabor Szabo Copyright (c) 2000-2006 Kawai Takanori All rights reserved. You may distribute under the terms of either the GNU General Public License or the Artistic License, as specified in the Perl README file. =cut Spreadsheet-ParseExcel-0.66/lib/Spreadsheet/ParseExcel/SaveParser/Worksheet.pm000644 000765 000024 00000005135 14543413026 027450 0ustar00Johnstaff000000 000000 package Spreadsheet::ParseExcel::SaveParser::Worksheet; ############################################################################### # # Spreadsheet::ParseExcel::SaveParser::Worksheet - A class for SaveParser Worksheets. # # Used in conjunction with Spreadsheet::ParseExcel. # # Copyright (c) 2014 Douglas Wilson # Copyright (c) 2009-2013 John McNamara # Copyright (c) 2006-2008 Gabor Szabo # Copyright (c) 2000-2006 Kawai Takanori # # perltidy with standard settings. # # Documentation after __END__ # use strict; use warnings; #============================================================================== # Spreadsheet::ParseExcel::SaveParser::Worksheet #============================================================================== use base 'Spreadsheet::ParseExcel::Worksheet'; our $VERSION = '0.66'; sub new { my ( $sClass, %rhIni ) = @_; $sClass->SUPER::new(%rhIni); # returns object } #------------------------------------------------------------------------------ # AddCell (for Spreadsheet::ParseExcel::SaveParser::Worksheet) #------------------------------------------------------------------------------ sub AddCell { my ( $oSelf, $iR, $iC, $sVal, $oCell, $sCode ) = @_; $oSelf->{_Book} ->AddCell( $oSelf->{_SheetNo}, $iR, $iC, $sVal, $oCell, $sCode ); } #------------------------------------------------------------------------------ # Protect (for Spreadsheet::ParseExcel::SaveParser::Worksheet) # - Password = undef -> No protect # - Password = '' -> Protected. No password # - Password = $pwd -> Protected. Password = $pwd #------------------------------------------------------------------------------ sub Protect { my ( $oSelf, $sPassword ) = @_; $oSelf->{Protect} = $sPassword; } 1; __END__ =pod =head1 NAME Spreadsheet::ParseExcel::SaveParser::Worksheet - A class for SaveParser Worksheets. =head1 SYNOPSIS See the documentation for Spreadsheet::ParseExcel. =head1 DESCRIPTION This module is used in conjunction with Spreadsheet::ParseExcel. See the documentation for Spreadsheet::ParseExcel. =head1 AUTHOR Current maintainer 0.60+: Douglas Wilson dougw@cpan.org Maintainer 0.40-0.59: John McNamara jmcnamara@cpan.org Maintainer 0.27-0.33: Gabor Szabo szabgab@cpan.org Original author: Kawai Takanori kwitknr@cpan.org =head1 COPYRIGHT Copyright (c) 2014 Douglas Wilson Copyright (c) 2009-2013 John McNamara Copyright (c) 2006-2008 Gabor Szabo Copyright (c) 2000-2006 Kawai Takanori All rights reserved. You may distribute under the terms of either the GNU General Public License or the Artistic License, as specified in the Perl README file. =cut Spreadsheet-ParseExcel-0.66/sample/dmpExH.pl000644 000765 000024 00000001711 11247565351 021022 0ustar00Johnstaff000000 000000 use strict; use Spreadsheet::ParseExcel; if(!(defined $ARGV[0])) { print<{File} , "\n"; print "COUNT :", $oBook->{SheetCount} , "\n"; print "AUTHOR:", $oBook->{Author} , "\n"; } if($iPreSheet != $iSheet) { print "--------- SHEET:", $oBook->{Worksheet}[$iSheet]->{Name}, "\n" ; $iPreSheet = $iSheet; } print "( $iRow , $iCol ) =>", $oCell->Value, "\n"; # $oBook->ParseAbort('Exceed Data') if($iRow >= 1); } my $oExcel = new Spreadsheet::ParseExcel ( CellHandler => \&subCellHandler, NotSetCell => 1); my $oBook = $oExcel->Parse($ARGV[0]); print "ABORTED:", $oBook->{_ParseAbort} if($oBook->{_ParseAbort}); Spreadsheet-ParseExcel-0.66/sample/Excel/000755 000765 000024 00000000000 14543415025 020332 5ustar00Johnstaff000000 000000 Spreadsheet-ParseExcel-0.66/sample/smpFile.pl000644 000765 000024 00000002204 11247565351 021232 0ustar00Johnstaff000000 000000 use lib qw(../); use strict; use Spreadsheet::ParseExcel; my $oExcel = new Spreadsheet::ParseExcel; sub PrnBook($); #1.2 Normal Excel97 open(IN, 'Excel/Test97.xls'); binmode IN; my $sWk; read(IN, $sWk, 2000000); close IN; my $oBook1 = $oExcel->Parse([$sWk]); PrnBook($oBook1); sub PrnBook($) { my($oBook) = @_; my($iR, $iC, $oWkS, $oWkC); print "=========================================\n"; print "FILE :", $oBook->{File} , "\n"; print "COUNT :", $oBook->{SheetCount} , "\n"; print "AUTHOR:", $oBook->{Author} , "\n"; for(my $iSheet=0; $iSheet < $oBook->{SheetCount} ; $iSheet++) { $oWkS = $oBook->{Worksheet}[$iSheet]; print "--------- SHEET:", $oWkS->{Name}, "\n"; for(my $iR = $oWkS->{MinRow} ; defined $oWkS->{MaxRow} && $iR <= $oWkS->{MaxRow} ; $iR++) { for(my $iC = $oWkS->{MinCol} ; defined $oWkS->{MaxCol} && $iC <= $oWkS->{MaxCol} ; $iC++) { $oWkC = $oWkS->{Cells}[$iR][$iC]; print "( $iR , $iC ) =>", $oWkC->Value, "\n" if($oWkC); } } } } Spreadsheet-ParseExcel-0.66/sample/dmpEx_2xml.pl000644 000765 000024 00000002646 11247565351 021664 0ustar00Johnstaff000000 000000 #Khalid EZZARAOUI khalid@yromem.com use strict; if(!(defined $ARGV[0])) { print<Parse($ARGV[0]); my($iR, $iC, $oWkS, $oWkC); print '', "\n"; print "", "\n"; print "\t", "", "\n"; print "\t\t", "", $oBook->{File} , "", "\n"; print "\t\t", "", $oBook->{SheetCount} , "", "\n"; print "\t\t", "", $oBook->{Author} , "", "\n"; print "\t", "", "\n"; print "\t", "", "\n"; #for(my $iSheet=0; $iSheet < $oBook->{SheetCount} ; $iSheet++) { # $oWkS = $oBook->{Worksheet}[$iSheet]; foreach my $oWkS (@{$oBook->{Worksheet}}) { print "\t\t", "{Name}, "\" >", "\n"; for(my $iR = $oWkS->{MinRow} ; defined $oWkS->{MaxRow} && $iR <= $oWkS->{MaxRow} ; $iR++) { print "\t\t\t", "", "\n" ; for(my $iC = $oWkS->{MinCol} ; defined $oWkS->{MaxCol} && $iC <= $oWkS->{MaxCol} ; $iC++) { $oWkC = $oWkS->{Cells}[$iR][$iC]; print "\t\t\t\t", "", $oWkC->Value, "", "\n" if($oWkC); # print $oWkC->{_Kind}, "\n"; } print "\t\t\t", "", "\n" ; } print "\t\t", "\n" ; } print "\t", "", "\n"; print "", "\n"; Spreadsheet-ParseExcel-0.66/sample/dmpExU.pl000644 000765 000024 00000002353 11247565351 021042 0ustar00Johnstaff000000 000000 # This script requieres Unicode::Map use strict; if($#ARGV < 1) { print<new(Unicode_Map => $ARGV[1]); my $oBook = $oExcel->Parse($ARGV[0], $oFmtJ); my($iR, $iC, $oWkS, $oWkC); print "=========================================\n"; print "FILE :", $oBook->{File} , "\n"; print "COUNT :", $oBook->{SheetCount} , "\n"; print "AUTHOR:", $oBook->{Author} , "\n"; my $table = []; for(my $iSheet=0; $iSheet < $oBook->{SheetCount} ; $iSheet++) { $oWkS = $oBook->{Worksheet}[$iSheet]; print "--------- SHEET:", $oWkS->{Name}, "\n"; for(my $iR = $oWkS->{MinRow} ; defined $oWkS->{MaxRow} && $iR <= $oWkS->{MaxRow} ; $iR++) { # print "ROW HEIGHT:", $oWkS->{RowHeight}[$iR], "\n"; for(my $iC = $oWkS->{MinCol} ; defined $oWkS->{MaxCol} && $iC <= $oWkS->{MaxCol} ; $iC++) { $oWkC = $oWkS->{Cells}[$iR][$iC]; print "( $iR , $iC ) =>", $oWkC->Value, "\n" if($oWkC); } } } Spreadsheet-ParseExcel-0.66/sample/sampleOEM.pl000644 000765 000024 00000002544 11247565351 021464 0ustar00Johnstaff000000 000000 use strict; use warnings; use Spreadsheet::ParseExcel; use Spreadsheet::ParseExcel::FmtJapan; use Spreadsheet::ParseExcel::FmtJapan2; my $oExcel = Spreadsheet::ParseExcel->new; my $oFmtJ = Spreadsheet::ParseExcel::FmtJapan->new(Code => 'euc'); my $oFmtJ2 = Spreadsheet::ParseExcel::FmtJapan2->new(Code => 'euc'); my $oBook = $oExcel->Parse('Excel/oem.xls', $oFmtJ); PrnAll($oBook); $oBook = $oExcel->Parse('Excel/oem.xls', $oFmtJ2); PrnAll($oBook); sub PrnAll { my ($oBook) = @_; my($iR, $iC, $oWkS, $oWkC); print "=========================================\n"; print "FILE :", $oBook->{File} , "\n"; print "COUNT :", $oBook->{SheetCount} , "\n"; print "AUTHOR:", $oBook->{Author} , "\n"; for(my $iSheet=0; $iSheet < $oBook->{SheetCount} ; $iSheet++) { $oWkS = $oBook->{Worksheet}[$iSheet]; print "--------- SHEET:", $oWkS->{Name}, "\n"; for(my $iR = $oWkS->{MinRow} ; defined $oWkS->{MaxRow} && $iR <= $oWkS->{MaxRow} ; $iR++) { print "ROW HEIGHT:", $oWkS->{RowHeight}[$iR], "\n"; for(my $iC = $oWkS->{MinCol} ; defined $oWkS->{MaxCol} && $iC <= $oWkS->{MaxCol} ; $iC++) { $oWkC = $oWkS->{Cells}[$iR][$iC]; print "( $iR , $iC ) =>", $oWkC->Value, "\n" if($oWkC); } } } } Spreadsheet-ParseExcel-0.66/sample/README000644 000765 000024 00000002546 11247565351 020167 0ustar00Johnstaff000000 000000 chkFmt.pl : Sample Script for formatting res_fmt : result of chkFmt.pl chkInfo.pl : Sample Script for get information about format res_info : result of chkInfo.pl with Excel/FmtTest.xls sample.pl :Simple Script (using SpreadSheet::ParseExcel::FmtDefault) sample_j.pl :Simple Script using Japanese character (using SpreadSheet::ParseExcel::FmtJapan) res_sample :result of sample.pl res_samplej :result of sample_j.pl (in euc) dmpEx.pl : print out content of Excel file (using SpreadSheet::ParseExcel::FmtDefault) dmpExJ.pl : print out content of Excel file (using SpreadSheet::ParseExcel::FmtJapan) dmpExU.pl : print out content of Excel file (using SpreadSheet::ParseExcel::FmtUnicode) dmpExH.pl : print out content of Excel file (using SpreadSheet::ParseExcel::FmtDefault + event handler) sampleOEM.pl: Displys difference between FmtJapan and FmtJapan2 res_oem : result of samplOEM.pl dmpExR.pl : Sample Script for get information about each characters. res_rich : result of dmpExR.pl with Excel/Rich.xls Ilya.pl : Sample script for Object Oriented callback smpFile.pl : Sample scripr for parsing perl variable xls2csv.pl : Sample script for xls2csv iftest.pl : Sample script for new interface iftestj.pl : Sample script for new interface with FmtJapan Spreadsheet-ParseExcel-0.66/sample/dmpExHJ.pl000644 000765 000024 00000002404 11247565351 021134 0ustar00Johnstaff000000 000000 use strict; use Spreadsheet::ParseExcel; use Spreadsheet::ParseExcel::FmtJapan2; if(!(defined $ARGV[0])) { print<{File} , "\n"; print "COUNT :", $oBook->{SheetCount} , "\n"; print "AUTHOR:", $oBook->{Author} , "\n"; } if($iPreSheet != $iSheet) { print "--------- SHEET:", $oBook->{Worksheet}[$iSheet]->{Name}, "\n" ; $iPreSheet = $iSheet; } print "( $iRow , $iCol ) =>", $oCell->Value, "\n"; # $oBook->ParseAbort('Exceed Data') if($iRow >= 1); } my $oExcel = new Spreadsheet::ParseExcel ( CellHandler => \&subCellHandler, NotSetCell => 1); my $oFmtJ = Spreadsheet::ParseExcel::FmtJapan2->new(Code => $ARGV[1]); my $oBook = $oExcel->Parse($ARGV[0], $oFmtJ); for(my $i=0;$i<$oBook->{SheetCount};$i++) { print "LAST:\n"; print "Row:", $oBook->{Worksheet}[$i]->{MaxRow}, "\n"; print "Col:", $oBook->{Worksheet}[$i]->{MaxCol}, "\n"; } print "ABORTED:", $oBook->{_ParseAbort} if($oBook->{_ParseAbort}); Spreadsheet-ParseExcel-0.66/sample/sample_j.pl000644 000765 000024 00000003513 11247565351 021431 0ustar00Johnstaff000000 000000 use strict; use warnings; use Spreadsheet::ParseExcel; use Spreadsheet::ParseExcel::FmtJapan; if(($#ARGV< 0) or (grep($ARGV[0] eq $_, ('euc', 'sjis', 'jis')) <= 0)) { print "USAGE: \n > perl ", $0, " euc|sjis|jis\n"; exit; } my $oExcel = Spreadsheet::ParseExcel->new; #1. Make Formatter my $oFmtJ = Spreadsheet::ParseExcel::FmtJapan->new(Code => $ARGV[0]); #2.1 Test97 my $oBook = $oExcel->Parse('sample/Excel/Test97J.xls', $oFmtJ); PrnBook($oBook); #2.2 Test95 $oBook = $oExcel->Parse('sample/Excel/Test95J.xls', $oFmtJ); PrnBook($oBook); #2.3 1904 (1904 - 97) $oBook = $oExcel->Parse('sample/Excel/Test1904.xls', $oFmtJ); PrnBook($oBook); #2.4 1904 (1904 - 95) $oBook = $oExcel->Parse('sample/Excel/Test1904_95.xls', $oFmtJ); PrnBook($oBook); #2.5 1904 (1904 - 95) $oBook = $oExcel->Parse('sample/Excel/AuthorK.xls', $oFmtJ); PrnBook($oBook); #2.6 1904 (1904 - 95) $oBook = $oExcel->Parse('sample/Excel/AuthorK95.xls', $oFmtJ); PrnBook($oBook); sub PrnBook { my($oBook) = @_; my($iR, $iC, $oWkS, $oWkC); print "=========================================\n"; print "FILE :", $oBook->{File} , "\n"; print "COUNT :", $oBook->{SheetCount} , "\n"; print "AUTHOR:", $oBook->{Author} , "\n"; for(my $iSheet=0; $iSheet < $oBook->{SheetCount} ; $iSheet++) { $oWkS = $oBook->{Worksheet}[$iSheet]; print "--------- SHEET:", $oWkS->{Name}, "\n"; for(my $iR = $oWkS->{MinRow} ; defined $oWkS->{MaxRow} && $iR <= $oWkS->{MaxRow} ; $iR++) { for(my $iC = $oWkS->{MinCol} ; defined $oWkS->{MaxCol} && $iC <= $oWkS->{MaxCol} ; $iC++) { $oWkC = $oWkS->{Cells}[$iR][$iC]; print "( $iR , $iC ) =>", $oWkC->Value, "\n" if($oWkC); } } } } Spreadsheet-ParseExcel-0.66/sample/dmpExJ.pl000644 000765 000024 00000002326 11247565351 021027 0ustar00Johnstaff000000 000000 use strict; if(!(defined $ARGV[0])) { print<new(Code => $ARGV[1]); my $oBook = $oExcel->Parse($ARGV[0], $oFmtJ); my($iR, $iC, $oWkS, $oWkC); print "=========================================\n"; print "FILE :", $oBook->{File} , "\n"; print "COUNT :", $oBook->{SheetCount} , "\n"; print "AUTHOR:", $oBook->{Author} , "\n"; #for(my $iSheet=0; $iSheet < $oBook->{SheetCount} ; $iSheet++) { # $oWkS = $oBook->{Worksheet}[$iSheet]; for my $oWkS (@{$oBook->{Worksheet}}) { print "--------- SHEET:", $oWkS->{Name}, "\n"; for(my $iR = $oWkS->{MinRow} ; defined $oWkS->{MaxRow} && $iR <= $oWkS->{MaxRow} ; $iR++) { print "ROW HEIGHT:", $oWkS->{RowHeight}[$iR], "\n"; for(my $iC = $oWkS->{MinCol} ; defined $oWkS->{MaxCol} && $iC <= $oWkS->{MaxCol} ; $iC++) { $oWkC = $oWkS->{Cells}[$iR][$iC]; print "( $iR , $iC ) =>", $oWkC->Value, "\n" if($oWkC); } } } Spreadsheet-ParseExcel-0.66/sample/Ilya.pl000644 000765 000024 00000001112 11247565351 020526 0ustar00Johnstaff000000 000000 use strict; use Spreadsheet::ParseExcel; package IlyaPackage; #:-) sub new($){ my $self = shift; my $obj = {}; bless $obj, $self; } sub cb_routine($@) { my($self, $oBook, $iSheet, $iRow, $iCol, $oCell) = @_; print "( $iRow , $iCol ) =>", $oCell->Value, "\n"; } sub parse($$){ my($self, $sFile) = @_; my $oEx = Spreadsheet::ParseExcel->new( CellHandler => \&cb_routine, Object => $self, NotSetCell => 1); $oEx->Parse($sFile); } 1; my $oIlya =IlyaPackage->new; $oIlya->parse($ARGV[0]); Spreadsheet-ParseExcel-0.66/sample/chkInfo.pl000644 000765 000024 00000014364 11247565351 021226 0ustar00Johnstaff000000 000000 use strict; use warnings; use Spreadsheet::ParseExcel; my $oExcel = Spreadsheet::ParseExcel->new; die "Usage: $0 file.xls\n" if not @ARGV; #=Default use Spreadsheet::ParseExcel::FmtDefault; my $oFmt = Spreadsheet::ParseExcel::FmtDefault->new; my $oBook = $oExcel->Parse($ARGV[0]); #=cut #Japan #use Spreadsheet::ParseExcel::FmtJapan2; #my $oFmt = Spreadsheet::ParseExcel::FmtJapan2->new(Code=>'sjis'); #my $oBook = $oExcel->Parse('Excel/FmtTest.xls', $oFmt); #=cut #Other Countries (ex. Russia (CP1251)) #use Spreadsheet::ParseExcel::FmtUnicode; #my $oFmt = Spreadsheet::ParseExcel::FmtUnicode->new(Unicode_Map => 'CP1251'); #my $oBook = $oExcel->Parse('Excel/FmtTest.xls', $oFmt); #=cut my($iR, $iC, $oWkS, $oWkC); print "=========================================\n"; print 'FILE :', $oBook->{File} , "\n", 'COUNT :', $oBook->{SheetCount} , "\n", 'AUTHOR :', $oBook->{Author} , "\n"; for(my $iSheet=0; $iSheet < $oBook->{SheetCount} ; $iSheet++) { $oWkS = $oBook->{Worksheet}[$iSheet]; print "--------- SHEET:", $oWkS->{Name}, "\n"; print ">> Print Setting\n", 'Landscape :', $oWkS->{Landscape} , "\n", 'Scale :', $oWkS->{Scale} , "\n", 'FitWidth :', $oWkS->{FitWidth} , "\n", 'FitHeight :', $oWkS->{FitHeight} , "\n", 'PageFit :', $oWkS->{PageFit} , "\n", 'PaperSize :', $oWkS->{PaperSize} , "\n", 'PageStart :', $oWkS->{PageStart} , "\n", 'UsePage :', $oWkS->{UsePage} , "\n"; print ">> Format\n", 'Mergin Left :', $oWkS->{LeftMergin} , "\n", ' Right :', $oWkS->{RightMergin} , "\n", ' Top :', $oWkS->{TopMergin} , "\n", ' Bottom :', $oWkS->{BottomMergin} , "\n", ' Header :', $oWkS->{HeaderMergin} , "\n", ' Footer :', $oWkS->{FooterMergin} , "\n", 'Horizontal Center:', $oWkS->{HCenter} , "\n", 'Vertical Center :', $oWkS->{VCenter} , "\n", 'Header :', $oWkS->{Header} , "\n", 'Footer :', $oWkS->{Footer} , "\n"; print "Print Area :\n"; foreach my $raA (@{$oBook->{PrintArea}[$iSheet]}) { print ' Area :', join(",", @$raA), "\n"; } my $rhA = $oBook->{PrintTitle}[$iSheet]; print "Print Title :\n"; print " Row :\n"; foreach my $raTr (@{$rhA->{Row}}) { print '>> :', join(",", @$raTr) , "\n"; } print " Column :\n"; foreach my $raTr (@{$rhA->{Column}}) { print '>> :', join(",", @$raTr) , "\n"; } print 'Print Gridlines :', $oWkS->{PrintGrid} , "\n", 'Print Headings :', $oWkS->{PrintHeaders} , "\n", 'NoColor :', $oWkS->{NoColor} , "\n", 'Draft :', $oWkS->{Draft} , "\n", 'Notes :', $oWkS->{Notes} , "\n", 'LeftToRight :', $oWkS->{LeftToRight} , "\n"; foreach my $raA (@{$oWkS->{MergedArea}}) { print "Merged Area:", join(",", @$raA), "\n"; } print 'Horizontal PageBreak :', join(',', @{$oWkS->{HPageBreak}}), "\n" if($oWkS->{HPageBreak}); print 'Vertical PageBreak :', join(',', @{$oWkS->{VPageBreak}}), "\n" if($oWkS->{VPageBreak}); for(my $iR = $oWkS->{MinRow} ; defined $oWkS->{MaxRow} && $iR <= $oWkS->{MaxRow} ; $iR++) { for(my $iC = $oWkS->{MinCol} ; defined $oWkS->{MaxCol} && $iC <= $oWkS->{MaxCol} ; $iC++) { $oWkC = $oWkS->{Cells}[$iR][$iC]; if($oWkC) { print "------------------------------------------------------\n", "( $iR , $iC ) =>", $oWkC->Value, "\n"; print 'Format :', $oFmt->FmtString($oWkC, $oBook), "\n", 'AlignH :', $oWkC->{Format}->{AlignH}, "\n", 'AlignV :', $oWkC->{Format}->{AlignV}, "\n", 'Indent :', $oWkC->{Format}->{Indent}, "\n", 'Wrap :', $oWkC->{Format}->{Wrap}, "\n", 'Shrink :', $oWkC->{Format}->{Shrink}, "\n", 'Merged :', (defined($oWkC->{Merged})? $oWkC->{Merged}: 'No'), "\n", 'Rotate :', $oWkC->{Format}->{Rotate}, "\n"; # 'JustLast :', $oWkC->{Format}->{JustLast}, "\n", # 'ReadDir :', $oWkC->{Format}->{ReadDir}, "\n", my $oFont = $oWkC->{Format}->{Font}; print 'Name :', $oFont->{Name}, "\n", 'Bold :', $oFont->{Bold}, "\n", 'Italic :', $oFont->{Italic}, "\n", 'Height :', $oFont->{Height}, "\n", 'Underline :', $oFont->{Underline}, "\n", 'UnderlineStyle :', sprintf("%02x", $oFont->{UnderlineStyle}), "\n", 'Color :', $oFont->{Color}, "\n", 'Color RGB :', Spreadsheet::ParseExcel->ColorIdxToRGB($oFont->{Color}), "\n", 'Strikeout :', $oFont->{Strikeout}, "\n", 'Super :', $oFont->{Super}, "\n", 'BdrStyle :', join(',', @{$oWkC->{Format}->{BdrStyle}}), "\n", 'BdrColor :', join(',', @{$oWkC->{Format}->{BdrColor}}), "\n", 'BdrDiag :', join(',', @{$oWkC->{Format}->{BdrDiag}}), "\n", 'Pattern :', join(',', @{$oWkC->{Format}->{Fill}}), "\n", 'Lock :', $oWkC->{Format}->{Lock}, "\n", 'Hidden :', $oWkC->{Format}->{Hidden}, "\n"; } } } } Spreadsheet-ParseExcel-0.66/sample/dmpExR.pl000644 000765 000024 00000004255 11247565351 021042 0ustar00Johnstaff000000 000000 use strict; use warnings; if(!(defined $ARGV[0])) { print<new; my $oBook = $oExcel->Parse($ARGV[0]); my($iR, $iC, $oWkS, $oWkC); print "=========================================\n"; print "FILE :", $oBook->{File} , "\n"; print "COUNT :", $oBook->{SheetCount} , "\n"; print "AUTHOR:", $oBook->{Author} , "\n"; for(my $iSheet=0; $iSheet < $oBook->{SheetCount} ; $iSheet++) { $oWkS = $oBook->{Worksheet}[$iSheet]; print "--------- SHEET:", $oWkS->{Name}, "\n"; for(my $iR = $oWkS->{MinRow} ; defined $oWkS->{MaxRow} && $iR <= $oWkS->{MaxRow} ; $iR++) { for(my $iC = $oWkS->{MinCol} ; defined $oWkS->{MaxCol} && $iC <= $oWkS->{MaxCol} ; $iC++) { $oWkC = $oWkS->{Cells}[$iR][$iC]; print "( $iR , $iC ) =>", $oWkC->Value, "\n" if($oWkC); if($oWkC) { if($oWkC->{Rich}) { foreach my $raR (@{$oWkC->{Rich}}) { my $oFont = $raR->[1]; print "--------------------------------------------\n", 'POS :', $raR->[0], "\n", 'Name :', $oFont->{Name}, "\n", 'Bold :', $oFont->{Bold}, "\n", 'Italic :', $oFont->{Italic}, "\n", 'Height :', $oFont->{Height}, "\n", 'Underline :', $oFont->{Underline}, "\n", 'UnderlineStyle :', sprintf("%02x", $oFont->{UnderlineStyle}), "\n", 'Color :', $oFont->{Color}, "\n", 'Color RGB :', Spreadsheet::ParseExcel->ColorIdxToRGB($oFont->{Color}), "\n", 'Strikeout :', $oFont->{Strikeout}, "\n", 'Super :', $oFont->{Super}, "\n", } } } } } } } Spreadsheet-ParseExcel-0.66/sample/xls2csv.pl000644 000765 000024 00000003024 11247565351 021240 0ustar00Johnstaff000000 000000 #!/usr/bin/perl -w # Script to extract a range of columns/rows from an Excel spreadsheet # and present it as a csv, there is also the option to rotate the # output, # # (c) kevin Mulholland 2002, kevin@moodfarm.demon.co.uk # This code is released under the Perl Artistic License # # See also the following utilities:. # Ken Prows' xls2csv: # http://search.cpan.org/~ken/xls2csv/script/xls2csv # H.Merijn Brand's xls2csv (which is part of Spreadsheet::Read): # http://search.cpan.org/~hmbrand/Spreadsheet-Read/ # use strict ; use Spreadsheet::ParseExcel; use Spreadsheet::ParseExcel::Utility qw(xls2csv); use Text::CSV_XS; if(!(defined $ARGV[0])) { usage( "Bad Args") ; exit; } my $rotate = 0 ; my $filename = $ARGV[0] ; my $coords = $ARGV[1] ; $rotate = 1 if( defined $ARGV[2] && $ARGV[2] eq "-rotate") ; if( !$coords) { usage( "No co-ordinates defined") ; exit ; } if( ! -f $filename) { usage( "File $filename does not exist") ; exit ; } printf xls2csv( $filename, $coords, $rotate) ; # ----------------------------------------------------------------------------- ### error # writes a message to STDERR # sub error { printf STDERR shift ; } # ----------------------------------------------------------------------------- ### usage # this decribes how the program as a whole is to be used # sub usage { my $errmsg = shift ; error( "\n" . $errmsg . "\n") if( $errmsg) ; error( " Usage: $0 filename sheet-colrow:colrow [-rotate] eg: $0 filename.xls 1-A1:B12 $0 filename.xls A1:M1 -rotate\n\n") ; } Spreadsheet-ParseExcel-0.66/sample/iftest.pl000644 000765 000024 00000002310 11247565351 021127 0ustar00Johnstaff000000 000000 use strict; use warnings; use Spreadsheet::ParseExcel; die "Usage: $0 Excel/Test97.xls\n" if not @ARGV; my $filename = $ARGV[0]; my $oBook = Spreadsheet::ParseExcel::Workbook->Parse($filename); my($iR, $iC, $oWkS, $oWkC); foreach my $oWkS (@{$oBook->{Worksheet}}) { print "--------- SHEET:", $oWkS->{Name}, "\n"; for(my $iR = $oWkS->{MinRow} ; defined $oWkS->{MaxRow} && $iR <= $oWkS->{MaxRow} ; $iR++) { for(my $iC = $oWkS->{MinCol} ; defined $oWkS->{MaxCol} && $iC <= $oWkS->{MaxCol} ; $iC++) { $oWkC = $oWkS->{Cells}[$iR][$iC]; print "( $iR , $iC ) =>", $oWkC->Value, "\n" if($oWkC); } } } #Sheet Name print $oBook->Worksheet('Sheet1-ASC')->{Cells}[0][1]->Value, "\n"; #Sheet No print $oBook->Worksheet(0)->{Cells}[0][1]->Value, "\n"; #Sheet Not found print (($oBook->Worksheet('SHEET1') ? 'Exists' : 'Not Exists'), "\n"); __END__ # removed so we can run test (by Gabor) use Spreadsheet::ParseExcel::SaveParser; $oBook = Spreadsheet::ParseExcel::SaveParser::Workbook->Parse($filename); my $oWs = $oBook->AddWorksheet('TEST1'); $oWs->AddCell(10, 1, 'New Cell'); $oBook->SaveAs('iftest.xls'); Spreadsheet-ParseExcel-0.66/sample/iftestj.pl000644 000765 000024 00000002034 11247565351 021304 0ustar00Johnstaff000000 000000 use strict; use Spreadsheet::ParseExcel; use Spreadsheet::ParseExcel::FmtJapan; my $oBook = Spreadsheet::ParseExcel::Workbook->Parse( 'Excel/Test97J.xls', Spreadsheet::ParseExcel::FmtJapan->new (Code => 'sjis')); my($iR, $iC, $oWkS, $oWkC); print "=========================================\n"; print "FILE :", $oBook->{File} , "\n"; print "COUNT :", $oBook->{SheetCount} , "\n"; print "AUTHOR:", $oBook->{Author} , "\n"; #for(my $iSheet=0; $iSheet < $oBook->{SheetCount} ; $iSheet++) { # $oWkS = $oBook->{Worksheet}[$iSheet]; foreach my $oWkS (@{$oBook->{Worksheet}}) { print "--------- SHEET:", $oWkS->{Name}, "\n"; for(my $iR = $oWkS->{MinRow} ; defined $oWkS->{MaxRow} && $iR <= $oWkS->{MaxRow} ; $iR++) { for(my $iC = $oWkS->{MinCol} ; defined $oWkS->{MaxCol} && $iC <= $oWkS->{MaxCol} ; $iC++) { $oWkC = $oWkS->{Cells}[$iR][$iC]; print "( $iR , $iC ) =>", $oWkC->Value, "\n" if($oWkC); print $oWkC->{_Kind}, "\n"; } } } Spreadsheet-ParseExcel-0.66/sample/sample.pl000644 000765 000024 00000002557 11247565351 021127 0ustar00Johnstaff000000 000000 use strict; use warnings; use Spreadsheet::ParseExcel; my $oExcel = Spreadsheet::ParseExcel->new; sub PrnBook($); #1.1 Normal Excel97 my $oBook = $oExcel->Parse('sample/Excel/Test97.xls'); PrnBook($oBook); #1.2 Normal Excel95 $oBook = $oExcel->Parse('sample/Excel/Test95.xls'); PrnBook($oBook); #1.3 Year 1904 Base (Excel97) $oBook = $oExcel->Parse('sample/Excel/Test1904.xls'); PrnBook($oBook); #1.4 Year 1904 Base (Excel95) $oBook = $oExcel->Parse('sample/Excel/Test1904_95.xls'); PrnBook($oBook); sub PrnBook($) { my($oBook) = @_; my($iR, $iC, $oWkS, $oWkC); print "=========================================\n"; print "FILE :", $oBook->{File} , "\n"; print "COUNT :", $oBook->{SheetCount} , "\n"; print "AUTHOR:", $oBook->{Author} , "\n"; for(my $iSheet=0; $iSheet < $oBook->{SheetCount} ; $iSheet++) { $oWkS = $oBook->{Worksheet}[$iSheet]; print "--------- SHEET:", $oWkS->{Name}, "\n"; for(my $iR = $oWkS->{MinRow} ; defined $oWkS->{MaxRow} && $iR <= $oWkS->{MaxRow} ; $iR++) { for(my $iC = $oWkS->{MinCol} ; defined $oWkS->{MaxCol} && $iC <= $oWkS->{MaxCol} ; $iC++) { $oWkC = $oWkS->{Cells}[$iR][$iC]; print "( $iR , $iC ) =>", $oWkC->Value, "\n" if($oWkC); } } } } Spreadsheet-ParseExcel-0.66/sample/parse.pl000644 000765 000024 00000002745 11247565351 020757 0ustar00Johnstaff000000 000000 #!/usr/bin/perl use strict; use warnings; use Spreadsheet::ParseExcel; use Getopt::Long qw(GetOptions); my $file; my $help; my $dump; my ($row, $col); GetOptions( "file=s" => \$file, "help" => \$help, "dump" => \$dump, "row=i" => \$row, "col=i" => \$col, ) or usage(); usage() if $help; usage() if not $file; my $excel = Spreadsheet::ParseExcel::Workbook->Parse($file); if ($dump) { foreach my $sheet (@{$excel->{Worksheet}}) { printf("Sheet: %s\n", $sheet->{Name}); $sheet->{MaxRow} ||= $sheet->{MinRow}; foreach my $row ($sheet->{MinRow} .. $sheet->{MaxRow}) { $sheet->{MaxCol} ||= $sheet->{MinCol}; foreach my $col ($sheet->{MinCol} .. $sheet->{MaxCol}) { my $cell = $sheet->{Cells}[$row][$col]; if ($cell) { printf("( %s , %s ) => %s\n", $row, $col, $cell->{Val}); } } } } } if (defined $row and defined $col) { foreach my $sheet (@{$excel->{Worksheet}}) { printf("Sheet: %s\n", $sheet->{Name}); my $cell = $sheet->{Cells}[$row][$col]; printf("( %s , %s ) => '%s'\n", $row, $col, $cell->{Val}); printf("( %s , %s ) => '%s'\n", $row, $col, $cell->Value); } } sub usage { print <<"END_USAGE"; Usage: $0 --file FILENAME --dump --row ROW --col COL --help END_USAGE exit; } Spreadsheet-ParseExcel-0.66/sample/chkFmt.pl000644 000765 000024 00000003322 11247565351 021051 0ustar00Johnstaff000000 000000 use strict; use warnings; use Spreadsheet::ParseExcel::Utility; my $sWk; my @aData = (-2, 0, 1234, -1234, 34323.23232, -233232.3233, Spreadsheet::ParseExcel::Utility::LocaltimeExcel(13, 11, 12, 23, 2, 64, undef, 238)); my %hFmtTest = ( 0x00 => '@', 0x01 => '0', 0x02 => '0.00', 0x03 => '#,##0', 0x04 => '#,##0.00', 0x05 => '(\\\\#,##0_);(\\\\#,##0)', 0x06 => '(\\\\#,##0_);[RED](\\\\#,##0)', 0x07 => '(\\\\#,##0.00_);(\\\\#,##0.00_)', 0x08 => '(\\\\#,##0.00_);[RED](\\\\#,##0.00_)', 0x09 => '0%', 0x0A => '0.00%', 0x0B => '0.00E+00', 0x0C => '# ?/?', 0x0D => '# ??/??', 0x0E => 'm/d/yy', 0x0F => 'd-mmm-yy', 0x10 => 'd-mmm', 0x11 => 'mmm-yy', 0x12 => 'h:mm AM/PM', 0x13 => 'h:mm:ss AM/PM', 0x14 => 'h:mm', 0x15 => 'h:mm:ss', 0x16 => 'm/d/yy h:mm', #0x17-0x24 -- Differs in Natinal 0x25 => '(#,##0_);(#,##0)', 0x26 => '(#,##0_);[RED](#,##0)', 0x27 => '(#,##0.00);(#,##0.00)', 0x28 => '(#,##0.00);[RED](#,##0.00)', 0x29 => '_(*#,##0_);_(*(#,##0);_(*"-"_);_(@_)', 0x2A => '_(\\\\*#,##0_);_(\\\\*(#,##0);_(*"-"_);_(@_)', 0x2B => '_(*#,##0.00_);_(*(#,##0.00);_(*"-"??_);_(@_)', 0x2C => '_(\\\\*#,##0.00_);_(\\\\*(#,##0.00);_(*"-"??_);_(@_)', 0x2D => 'mm:ss', 0x2E => '[h]:mm:ss', 0x2F => 'mm:ss.0', 0x30 => '##0.0E+0', 0x31 => '@', ); foreach my $sKey (sort {$a <=> $b} keys(%hFmtTest)) { my $sVal = $hFmtTest{$sKey}; printf "============ %02x \n", $sKey; foreach my $sDt (@aData) { $sWk = Spreadsheet::ParseExcel::Utility::ExcelFmt($sVal, $sDt); printf "Fmt: %-20s : %-10s: Data: %s\n", $sVal, "$sDt", $sWk; } } Spreadsheet-ParseExcel-0.66/sample/dmpEx.pl000644 000765 000024 00000002014 11247565351 020707 0ustar00Johnstaff000000 000000 use strict; if(!(defined $ARGV[0])) { print<Parse($ARGV[0]); my($iR, $iC, $oWkS, $oWkC); print "=========================================\n"; print "FILE :", $oBook->{File} , "\n"; print "COUNT :", $oBook->{SheetCount} , "\n"; print "AUTHOR:", $oBook->{Author} , "\n"; #for(my $iSheet=0; $iSheet < $oBook->{SheetCount} ; $iSheet++) { # $oWkS = $oBook->{Worksheet}[$iSheet]; foreach my $oWkS (@{$oBook->{Worksheet}}) { print "--------- SHEET:", $oWkS->{Name}, "\n"; for(my $iR = $oWkS->{MinRow} ; defined $oWkS->{MaxRow} && $iR <= $oWkS->{MaxRow} ; $iR++) { for(my $iC = $oWkS->{MinCol} ; defined $oWkS->{MaxCol} && $iC <= $oWkS->{MaxCol} ; $iC++) { $oWkC = $oWkS->{Cells}[$iR][$iC]; print "( $iR , $iC ) =>", $oWkC->Value, "\n" if($oWkC); print $oWkC->{_Kind}, "\n"; } } } Spreadsheet-ParseExcel-0.66/sample/Excel/AuthorK.xls000644 000765 000024 00000034000 11247565351 022442 0ustar00Johnstaff000000 000000 ࡱ>  \pkawait Ba==<G28X@"1 -3 000001 -3 000001 -3 000001 -3 000001 x-3 00000"\"#,##0;"\"\-#,##0"\"#,##0;[Red]"\"\-#,##0"\"#,##0.00;"\"\-#,##0.00#"\"#,##0.00;[Red]"\"\-#,##0.007*2_ "\"* #,##0_ ;_ "\"* \-#,##0_ ;_ "\"* "-"_ ;_ @_ .))_ * #,##0_ ;_ * \-#,##0_ ;_ * "-"_ ;_ @_ ?,:_ "\"* #,##0.00_ ;_ "\"* \-#,##0.00_ ;_ "\"* "-"??_ ;_ @_ 6+1_ * #,##0.00_ ;_ * \-#,##0.00_ ;_ * "-"??_ ;_ @_ \$#,##0_);\(\$#,##0\)\$#,##0_);[Red]\(\$#,##0\) \$#,##0.00_);\(\$#,##0.00\)% \$#,##0.00_);[Red]\(\$#,##0.00\)                 & (   ` Sheet1)Sheet20Sheet3QQ|&"oW[ Tn0000"500000 "oW[000o0i0F0j0050006 HWzp0C&zp0C#J0CT0(E0 Ahy-p0~F t1n: 0t1n޻V0 y-p0+p0zB!!0xV0n00+p0ֺ0n00@0zBxnzD0B@]0z@pjn[0.00]]λV0@0ֺZ0غW0pW0 0Ѿ0rW0#)% F '0)pW0% 0P0 pxT`!W0`%W0t`@`xphpywx`!W0`!W000``!W0̻`%W0Ի0`!W0`!W00`!W0`%W0$Lh0    dMbP?_*+%M,EPSON PM-800C`N 4dhh4 *** qhhDLLName32=e_du01jj.dll L dL 2EPSON PM-800C" dMb?Mb?U7E  0>@5    dMbP?_*+%"Mb?Mb?U>@5    dMbP?_*+%"Mb?Mb?U>@5 Oh+'08@P` x͔n͔nMicrosoft Excel@"՜.+,D՜.+,( PXt | {bh Sheet1Sheet2Sheet3 ܰ 6> _PID_GUIDAN{4CD40480-8ECE-11D4-95E0-0090CC001ADF} Root EntryMicrosoft Visual Stud Fr\opq9.Workbookl;C:\Program Files\Instd\InstallShield 5.7ofSummaryInformationgram;(h( DocumentSummaryInformation8Spreadsheet-ParseExcel-0.66/sample/Excel/Test95J.xls000644 000765 000024 00000033000 11247565351 022273 0ustar00Johnstaff000000 000000 ࡱ>  \pkawait B=x>G"8X@"1lr oSVbN1lr oSVbN1lr oSVbN1lr oSVbN1xlr oSVbN"\"#,##0;"\"\-#,##0"\"#,##0;[Red]"\"\-#,##0"\"#,##0.00;"\"\-#,##0.00!"\"#,##0.00;[Red]"\"\-#,##0.005*2_ "\"* #,##0_ ;_ "\"* \-#,##0_ ;_ "\"* "-"_ ;_ @_ ,))_ * #,##0_ ;_ * \-#,##0_ ;_ * "-"_ ;_ @_ =,:_ "\"* #,##0.00_ ;_ "\"* \-#,##0.00_ ;_ "\"* "-"??_ ;_ @_ 4+1_ * #,##0.00_ ;_ * \-#,##0.00_ ;_ * "-"??_ ;_ @_ \$#,##0_);\(\$#,##0\)\$#,##0_);[Red]\(\$#,##0\)\$#,##0.00_);\(\$#,##0.00\)# \$#,##0.00_);[Red]\(\$#,##0.00\) "Hippo2000:"@ "͔n:"\:@"Ɋ:"@                 & (       83ffff̙3f3fff3f3f33333f33333 Sheet1-ASC i   n  dMbP?_*+%QQM\\Lins\lp`!W0`%W0`N 4dhhpXXp ?4 *** qhhDLLName32=e_du01jj.dll L dL 2EPSON PM-800C" dMb?Mb?U} ` F8 ASCThis Data is 'ASC Only' Date~ @INTEGER~ @ Float~  `@Doublec!2AFormulac!3Aa i DDbd2!$=x>G"8X> "  !   dMbP?_*+%QQ"QMb?Mb?U} }  F8 ASCThis Data is 'ASC Only'  ̃f[^ Date~ @INTEGER~ @ Float~  `@Doublec!2AFormulac!3A[ DD Float2.!$6=x>G"8X> " Oh+'08@dt Kawai, Takanori (Hippo2000)kawaitTMicrosoft Excel@Ǻ"՜.+,08@ \d l {bhp  Sheet1-ASC ܰ Root Entryc:\Program files\MicrFo\VC98\B:\Bookopenssl-0.9.4\out32dll;C:\P iles\InstallShieldtaSummaryInformationional Editio(m;e:\UNIX6nhDocumentSummaryInformation8Spreadsheet-ParseExcel-0.66/sample/Excel/AuthorK95.xls000644 000765 000024 00000033000 11247565351 022617 0ustar00Johnstaff000000 000000 ࡱ>  \pkawait B=<G28X@"1lr oSVbN1lr oSVbN1lr oSVbN1lr oSVbN1xlr oSVbN"\"#,##0;"\"\-#,##0"\"#,##0;[Red]"\"\-#,##0"\"#,##0.00;"\"\-#,##0.00!"\"#,##0.00;[Red]"\"\-#,##0.005*2_ "\"* #,##0_ ;_ "\"* \-#,##0_ ;_ "\"* "-"_ ;_ @_ ,))_ * #,##0_ ;_ * \-#,##0_ ;_ * "-"_ ;_ @_ =,:_ "\"* #,##0.00_ ;_ "\"* \-#,##0.00_ ;_ "\"* "-"??_ ;_ @_ 4+1_ * #,##0.00_ ;_ * \-#,##0.00_ ;_ * "-"??_ ;_ @_ \$#,##0_);\(\$#,##0\)\$#,##0_);[Red]\(\$#,##0\)\$#,##0.00_);\(\$#,##0.00\)# \$#,##0.00_);[Red]\(\$#,##0.00\)                 & (   83ffff̙3f3fff3f3f33333f33333 oSheet1 Sheet2 Sheet3   {  dMbP?_*+%QQMEPSON PM-800C`%W0`N 4dhhpPywT`!W0t4 *** qhhDLLName32=e_du01jj.dll L dL 2EPSON PM-800C" dMb?Mb?U F̃eXgf[^͂ǂȂHP=<G28X>    t  dMbP?_*+%QQ"QMb?Mb?HU =<G28X>    w  dMbP?_*+%QQ"QMb?Mb?HU =<G28X>  Oh+'08@P` x͔n͔nMicrosoft Excel@"՜.+,08@ \d l {bh Sheet1Sheet2Sheet3 ܰ Root Entryq`2"1qGCPVFtor.7 oBook SummaryInformation(DocumentSummaryInformation8Spreadsheet-ParseExcel-0.66/sample/Excel/Rich.xls000644 000765 000024 00000033000 11247565351 021751 0ustar00Johnstaff000000 000000 ࡱ>  \pkawait Ba==iG.8X@"1 -3 000001 -3 000001 -3 000001 -3 000001 x-3 000001.Times New Roman1.h Times New Roman1. Times New Roman1.@ Times New Roman1.Times New Roman1.Times New Roman"\"#,##0;"\"\-#,##0"\"#,##0;[Red]"\"\-#,##0"\"#,##0.00;"\"\-#,##0.00#"\"#,##0.00;[Red]"\"\-#,##0.007*2_ "\"* #,##0_ ;_ "\"* \-#,##0_ ;_ "\"* "-"_ ;_ @_ .))_ * #,##0_ ;_ * \-#,##0_ ;_ * "-"_ ;_ @_ ?,:_ "\"* #,##0.00_ ;_ "\"* \-#,##0.00_ ;_ "\"* "-"??_ ;_ @_ 6+1_ * #,##0.00_ ;_ * \-#,##0.00_ ;_ * "-"??_ ;_ @_ \$#,##0_);\(\$#,##0\)\$#,##0_);[Red]\(\$#,##0\) \$#,##0.00_);\(\$#,##0.00\)% \$#,##0.00_);[Red]\(\$#,##0.00\)                 & (       ` Sheet1QQ\ example     5 example  5j Uww |XKwLwH8w | Ahy-p0~F ER: 0ERRi.xls y-p0+p0zB!!0xV0n000n00@0zBxnzD0B@]0z@pjn[0.00]]pt`!W00غW0pW0 0Ѿ0rW0#)% F '0)pW0% 0P0 Pf0 JW00W0t`0tW0`W0Zda0 00dn0 RomanLh0  N  dMbP?_*+%,M,EPSON PM-800C`N 4dhh4 *** qhhDLLName32=e_du01jj.dll L dL 2EPSON PM-800C" dMb?Mb?U} }  ,7Ew8   b(>@5 Oh+'08@P` xkawaitkawaitMicrosoft Excel@e[՜.+,D՜.+, PXt | {bh Sheet1 ܰ 6> _PID_GUIDAN{CCA73380-3C4E-11D5-97F7-0090CC001ADF} Root Entry\E:\PEm$preadshe F.1\s ceWorkbook[$8SummaryInformation(DocumentSummaryInformation8Spreadsheet-ParseExcel-0.66/sample/Excel/oem.xls000644 000765 000024 00000033000 11247565351 021644 0ustar00Johnstaff000000 000000 ࡱ>  \pkawait Ba==KGW08X@"1 -3 000001 -3 000001 -3 000001 -3 000001 x-3 00000"\"#,##0;"\"\-#,##0"\"#,##0;[Red]"\"\-#,##0"\"#,##0.00;"\"\-#,##0.00#"\"#,##0.00;[Red]"\"\-#,##0.007*2_ "\"* #,##0_ ;_ "\"* \-#,##0_ ;_ "\"* "-"_ ;_ @_ .))_ * #,##0_ ;_ * \-#,##0_ ;_ * "-"_ ;_ @_ ?,:_ "\"* #,##0.00_ ;_ "\"* \-#,##0.00_ ;_ "\"* "-"??_ ;_ @_ 6+1_ * #,##0.00_ ;_ * \-#,##0.00_ ;_ * "-"??_ ;_ @_ \$#,##0_);\(\$#,##0\)\$#,##0_);[Red]\(\$#,##0\) \$#,##0.00_);\(\$#,##0.00\)% \$#,##0.00_);[Red]\(\$#,##0.00\)                 & (   ` Sheet1QQ eW[SQ0Y0000005000`! 000W[n05000012 5 ^j00f0j00n00SQ0050 ̾Wzp0C&zp0C#J0Cؾ0(E0 Ahy-p0~ʷ : 0 y-p0+p0zƷ!!0xV0n000n00@0zƷxnzȹ0Ʒķ]0zķpjn[0.00]]0\W0pW0 0Ѿ0rW0#)% F'0)pW0% 0Ը0 ppظ`!W0`%W0t`ĸ`xphpywp`!W0@`!W0040`!W0@P`%W0X0`!W0`!W00`!W0`%W0$й404   ^  dMbP?_*+%M,EPSON PM-800C`N 4dhh4 *** qhhDLLName32=e_du01jj.dll L dL 2EPSON PM-800C" dMb?Mb?UG8     <>@5 Oh+'08@P` xkawaitkawaitMicrosoft Excel@\ŋe՜.+,D՜.+, PXt | {bh Sheet1 ܰ 6> _PID_GUIDAN{2829BC80-D17F-11D4-96BB-0090CC001ADF} Root Entry FqpWorkbookSummaryInformation(DocumentSummaryInformation8Spreadsheet-ParseExcel-0.66/sample/Excel/FmtTest.xls000644 000765 000024 00000061000 11247565351 022453 0ustar00Johnstaff000000 000000 ࡱ> /. \pkawait Ba==y /$8X@"1 -3 000001 -3 000001 -3 000001 -3 000001 x-3 000001& Arial Black1& Arial Black1&( Arial Black1&( Arial Black1&( Arial Black1& Courier New1& Courier New1&  Courier New1& Courier New1& Courier New1Century1Century1 Century1 Century1 Century"\"#,##0;"\"\-#,##0"\"#,##0;[Red]"\"\-#,##0"\"#,##0.00;"\"\-#,##0.00#"\"#,##0.00;[Red]"\"\-#,##0.007*2_ "\"* #,##0_ ;_ "\"* \-#,##0_ ;_ "\"* "-"_ ;_ @_ .))_ * #,##0_ ;_ * \-#,##0_ ;_ * "-"_ ;_ @_ ?,:_ "\"* #,##0.00_ ;_ "\"* \-#,##0.00_ ;_ "\"* "-"??_ ;_ @_ 6+1_ * #,##0.00_ ;_ * \-#,##0.00_ ;_ * "-"??_ ;_ @_ \$#,##0_);\(\$#,##0\)\$#,##0_);[Red]\(\$#,##0\) \$#,##0.00_);\(\$#,##0.00\)% \$#,##0.00_);[Red]\(\$#,##0.00\) #,##0_ %yyyy"t^"m"g"d"eD"yyyy/m/d\ h:mm\ AM/PMm/d mm/dd/yy0;"% "00;"% "0[<=999]000;000\-00.)[<=99999999]####\-####;\(00\)\ ####\-####/"%"\ #,##0;"%"\ #,##0 yyyy\.mm\.dd 0_);\(0\) 0;"@ "0 dd\-mmm\-yy0_ ;[Red]\-0\                  & (   6@ @ 6@ @ 6@ @  6@ @  6@ @  6@ @  6@ @  6@ @ 6@ @ 6@ @ 2@ @ 6@ @ 6@ @ 6@ @ 6@ @  " $  4   (  -       ) + * , % & ' (           0         9          - / 1 .      ! # & & ' K !  H@ H   Z    H  HA  H  H@ H  H  H-  H  H  H  H @ H  H4  H3  H/  H  H!  H  H H$  H2  H  H+  H  H"  H@ H( H9  H  H*  H  H#  HD  HD@ H,  H1  H  H)  H  H$  HH  HH@  H0@ H0  H(  H,  H  H%  H  H@ H4@ H  H=  H.  H  H&  H  H H8  H7  H  H  H  H'  H  H  H$  H(  H,  H0  H4  H8  H<  H@  (@ @  (@ @  (*@ @  (@@  (UU<  (UU  (UU  (UU   (UU   (UU1  (UU  (UU(   (UU/  (UU) ! ! ! -   " " `!Formatp7 Format(Print)QQ  ;' * );;+ * );;4 Arial Black 5Font 12 5 Arial Black 8 5RED 5YELLOW 5Sky Blue 5Sky Blue 5 PINK BOLD 5KABA 5FORMAT 5kaba 5 Courier New 5Courier New 20 5 PINK Super 5 Sky Super 5Font 5*KABA 5a cd  5KA BA 5ABCDEFGHIJKLMNOPQR 5ABC 5abc 5( D!L Print_Titlesrea,40 Ahy-p0F   A0 y-p0+p0B8!!00@V0n00 v00n00@0B@nB0]0B Djn[0.00]]W0 $0>C>CѾ0rW0# _ "'0 pW0H _ 00 p`!W0`%W0`xphp\yw`!W0`!W0`!W0t0i`!W0Ʉp0p00$:I$w 0$' R0D  E=%/67  dMbP?_*+%&LLeft Header&RHippo2000&LHippo2000&CCenter Footer&M&d2?'M&d2?(\.?)M&d2?M,EPSON PM-800C`N dhh4 *** ;hhDLLName32=e_du01jj.dll K d K 2EPSON PM-800C" d~?\.@U} `,} `} @}  }  }  }  E  w@s  w8@ w  , , , , , ŀ, :, v, , , , , , , , , , , , , , , p, , , 0, ,        !   "   #  $@YY@~ %@ZLUUU@ [~ &@@ \] ^~ '@@ [ _ (@@   ` ) ) * ab + c d e f , ~ -3./0g~ ,?hijklmn ~ .3o~ ,@pqrstuv ~ /3w~ ,@xyz{|}~ ~ 03f~ ,@ 131{1 1~ ,@ 232{2 2~ ,@ 333{3 3~ ,@ 434{4 4~ , @ 535{5 5~ ,"@636{6 6~ ,$@737{7 7~ ,&@838{8 8~ ,(@939{9 9~ ,*@:3:{: :~ ,,@;3;{; ;~ ,.@<3<{< <~ ,0@=3={= =~ ,1@>3>{> >~ ,2@D l*****.F<<BF>>>ZZZZBBBBBBBBL ,, ! ;,0" ,8,# ;,0$ ;ǀ,0% ;,0& ,,' ,, ( ;,0) ;,0* ;ŀ,0+ ,,, ,- ,. ,/ ,0,1,2,3,4,5,6,7,8,9,:,;p,<,=,>0,?, ?3?{? ?!@3@{@ !@!!!! "A3A{A "A#B3B{B #B#### $C3C{C $C%D3D{D %D%%%% &E3E{E &E'F3F{F 'F~ (G@(GGG((( ~ )K@~ *K@**~ +K@~ ,K@~ -H@~ .I@~ /J@~ 0K@1L@2M@3NB@4O@5O@6O@7P@8Q@9R@:S@;T@<$@=U@>V@?@Dl*R*R*R**>"@,A,B8,C,Dǀ,@@~ ATBW@CX@DX@P>'@BBB  5  :  dMbP?_*+%  &CHeader Center &RLeft Footer&\.@'~?(M&d2?)\.?M,EPSON PM-800C`N 4dhh4 *** qhhDLLName32=e_du01jj.dll L dL 2EPSON PM-800C" Z:M&d2?M&d2?U} ,:>@<d  5 Oh+'0@HXh kawaitkawaitMicrosoft Excel@M>m@:Ǹ՜.+,D՜.+,$ PXt | {bh FormatFormat(Print) ܰ 6> _PID_GUIDAN{12CDE0F0-37AC-11D5-97E9-0090CC001ADF}  !"#$%'()*+,-Root Entry :i+00/C:\ FProfilesWorkbookPersonal$9;SummaryInformation(DocumentSummaryInformation8&Spreadsheet-ParseExcel-0.66/sample/Excel/Test1904_95.xls000644 000765 000024 00000033000 11247565351 022636 0ustar00Johnstaff000000 000000 ࡱ>  \pkawait B=>G"8X@"1lr oSVbN1lr oSVbN1lr oSVbN1lr oSVbN1xlr oSVbN"\"#,##0;"\"\-#,##0"\"#,##0;[Red]"\"\-#,##0"\"#,##0.00;"\"\-#,##0.00!"\"#,##0.00;[Red]"\"\-#,##0.005*2_ "\"* #,##0_ ;_ "\"* \-#,##0_ ;_ "\"* "-"_ ;_ @_ ,))_ * #,##0_ ;_ * \-#,##0_ ;_ * "-"_ ;_ @_ =,:_ "\"* #,##0.00_ ;_ "\"* \-#,##0.00_ ;_ "\"* "-"??_ ;_ @_ 4+1_ * #,##0.00_ ;_ * \-#,##0.00_ ;_ * "-"??_ ;_ @_ \$#,##0_);\(\$#,##0\)\$#,##0_);[Red]\(\$#,##0\)\$#,##0.00_);\(\$#,##0.00\)# \$#,##0.00_);[Red]\(\$#,##0.00\)                 & (     83ffff̙3f3fff3f3f33333f33333e Sheet1-ASC    dMbP?_*+%QQM\\Lins\lp`!W0`%W0`N 4dhhp$yw`!W0H4 *** qhhDLLName32=e_du01jj.dll L dL 2EPSON PM-800C" dMb?Mb?U} ` D8T ASCThis Data is 'ASC Only' Date~ @{@INTEGER~ @ Float~  `@Doublec!2AFormulac!3Aa i DDbd2!$=>G"8X> " Oh+'08@dt Kawai, Takanori (Hippo2000)kawaitTMicrosoft Excel@Ǻ"՜.+,08@ \d l {bhp  Sheet1-ASC ܰ Root EntryOX[Y004XTo0 [D0D0H0] 0xoxW0FfL01Y0t+t~0Y0Book _SummaryInformation !"(+,-./0123456789:;<ABDocumentSummaryInformation_`ab8klmnopqrstuvwxyz{|Spreadsheet-ParseExcel-0.66/sample/Excel/Test97.xls000644 000765 000024 00000042000 11247565351 022163 0ustar00Johnstaff000000 000000 ࡱ>   Root Entry F`{ E'Workbook T_VBA_PROJECT_CUR" 'E'VBA0'008'  !"#$%&'()*+,-/0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]_`abcdefghjlmnopqstuwxyz{|~   ~ @ ~ @ ~  `@ c!2A !c!3A` DD ~ W4o @5 Sheet1    dMbP?_*+%M,\\Lins\lp`N 4dhh4 *** qhhDLLName32=e_du01jj.dll L dL 2EPSON PM-800C" dMb?Mb?U} }   ">@  5 Sheet11     & ( ThisWorkbookSheet1Sheet11_VBA_PROJECT. x# (SLSS<N0{00020819-0000-0000-C000-000000000046}8($HMExAttribute VB_Name = "ThisWorkbook" Bas0{00020P819-0C$0046} |CreatablFalse ^PredeclaIdTru "@ExposeTemplateD0eriv$eCustomiz2ƗɄp0p00|`|w \pkawait Ba= ThisWorkbook=x>G"8X@"1 -3 000001 -3 000001 -3 000001 -3 000001 x-3 00000"\"#,##0;"\"\-#,##0"\"#,##0;[Red]"\"\-#,##0"\"#,##0.00;"\"\-#,##0.00#"\"#,##0.00;[Red]"\"\-#,##0.007*2_ "\"* #,##0_ ;_ "\"* \-#,##0_ ;_ "\"* "-"_ ;_ @_ .))_ * #,##0_ ;_ * \-#,##0_ ;_ * "-"_ ;_ @_ ?,:_ "\"* #,##0.00_ ;_ "\"* \-#,##0.00_ ;_ "\"* "-"??_ ;_ @_ 6+1_ * #,##0.00_ ;_ * \-#,##0.00_ ;_ * "-"??_ ;_ @_ \$#,##0_);\(\$#,##0\)\$#,##0_);[Red]\(\$#,##0\) \$#,##0.00_);\(\$#,##0.00\)% \$#,##0.00_);[Red]\(\$#,##0.00\) "KABAYONN:"@ "KABA:"@"0""0"\: "0""0"\:@                 & (         `C Sheet1-ASCSheet2QQB ASC 5Date 5This Data is 'ASC Only' 5INTEGER 5Double 5Float 5Formula 5Data 5 BIG INTEGER 5This is Sheet2 5   xw`!W0 Ahy-p0~ 8 |p0e 8+p0z<? +w466w4V08n008460n00@0zn|0zx]0xjn[0.00]]8`!W07? 0`!W040wѾ0rW0#:D'0:pW0 0 0 K0  f0 W00W0t`0tW0`W0a0 40$ 4ƗɄp0p00|`|w 08t0  c  dMbP?_*+%# &L&P/&N&CCHECK FOR HEADER&R&F &A &R&D &T&M&d2?'M&d2?(~?)~?M,EPSON PM-800C`N 4dhh4 *** qhhDLLName32=e_du01jj.dll L dL 2EPSON PM-800C" d `? `?U} } 8x# (SLSS<N0{00020820-0000-0000-C000-000000000046}8($HMExAttribute VB_Name = "She@et1" Bast0{00020820- C$0046} |CreatablFalse PredeclaIdTru "ExposeTemplate`Deriv$eCustomizdx# (SLSS<N0{00020820-0000-0000-C000-000000000046}8($HMExAttribute VB_Name = "Sheet11" Basx0{00020820- C$0046} |CreatablFalse Predec$laIdTru "ExposeTemplateDeriv$eCustomizda^ *\G{000204EF-0000-0000-C000-000000000046}#3.0#9#C:\Program Files\Common Files\Microsoft Shared\VBA\VBA332.dll#Visual Basic For Applications *\G{00020813-0000-0000-C000-000000000046}#1.2#0#C:\Program Files\Microsoft Office\Office\EXCEL8.OLB#Microsoft Excel 8.0 Object Library*\G{00020430-0000-0000-C000-000000000046}#2.0#0#C:\WINNT\System32\stdole2.tlb#OLE Automation*\G{148D6DF0-924B-11D3-946A-0090CC001ADF}#2.0#0#C:\WINNT\System32\MSForms.TWD#Microsoft Forms 2.0 Object Library*\G{148D6DF4-924B-11D3-946A-0090CC001ADF}#2.0#0#C:\RECYCLER\S-70DB~1\DC0\VBE\MSForms.EXD#Microsoft Forms 2.0 Object Library.E .`M *\G{2DF8D04C-5BFA-101B-BDE5-00AA0044DE52}#2.0#0#C:\Program Files\Microsoft Office\Office\MSO97.DLL#Microsoft Office 8.0 Object Library9ThisWorkbook 339d3c9b8*D Sheet1 439d3c9b8*DSheet11 439d905d7*D'0Hh0w y hP)&SubExcel+@VBA@Win16~@Win32@Mac@Test97@stdole`@MSFormsC@ VBAProject@Officeu@ ThisWorkbook|@ _Evaluate@Sheet1@Sheet2@Module1b@test4@ _B_var_Sub@Workbookk@ Worksheet@Sheet11!P@l' 60* pHd VBAProject4@j = r 9 J< rstdole>stdole f%\*\Gdir^PROJECTwmiVPROJECT kSummaryInformation( r{00020430-C 0046}#2.0#0#C:\WINNT\System32\c2.tlb#OLE Automation#^MSForms>!SFErms/z pF148D6DF0-924B-11D3-94D6AF90CK1ADFF3.TWD#MicrosPoft = ` Ob Library90-{?4?RECYCLER\S-70DB~1\DC0\VBE\ EEX".E .`0M ACrOf(ficDrO@oficBr./2DF8D04C-5BFA-101B-BDE5OAA@q42Ogram FilXes\K\MSO97.DLLCHT 8.0TBBThisWor@kbookN2D@1Th@6sDWkbokHB1¼B,B"B +BSheet12S@e@Pt1dLC2? )ThisWorkbookThisWorkbookSheet1Sheet1Sheet11Sheet11ID="{BDFD977E-950A-11D4-95F2-0090CC001ADF}" Document=ThisWorkbook/&H00000000 Document=Sheet1/&H00000000 Document=Sheet11/&H00000000 Name="VBAProject" HelpContextID="0" CMG="A5A7573C59E55DE55DE55DE55D" DPB="4A48B89F5CA05CA05C" GC="EFED1D7A67BA0DBB0DBBF2" [Host Extender Info] &H00000001={3832D640-CF90-11CF-8E43-00A0C911005A};VBE;&H00000000 [Workspace] ThisWorkbook=0, 0, 0, 0, C Sheet1=0, 0, 0, 0, C Sheet11=0, 0, 0, 0, C Oh+'08@dt Kawai, Takanori (Hippo2000)kawaitTMicrosoft Excel@Ǻ"՜.+,D՜.+,$ PXt |DocumentSummaryInformation8vCompObj}c {bh1  Sheet1-ASCSheet2 ܰ 6> _PID_GUIDAN{87BA1E80-8E98-11D4-95E0-0090CC001ADF} FMicrosoft Excel ܰBiff8Excel.Sheet.89qSpreadsheet-ParseExcel-0.66/sample/Excel/Test97J.xls000644 000765 000024 00000041000 11247565351 022274 0ustar00Johnstaff000000 000000 ࡱ>  Root Entry FP nWorkbook _VBA_PROJECT_CUR"  7VBA{  !"#$%&'()*+,-/0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\^_`abcdefgiklmnoprstvwxyz{} @ ~ @ ~  `@ c!2A !c!3AMb DD  ~ W4o  @5 Sheet1    dMbP?_*+%"Mb?Mb?U} 7E8Ⱥ     ~ @ ~ @ ~  `@ c!2A !c!3AMb DD   3>@  5 Sheet2 ThisWorkbookSheet1Sheet2_VBA_PROJECT. x# (SLSS<N0{00020819-0000-0000-C000-000000000046}8($HMExAttribute VB_Name = "ThisWorkbook" Bas0{00020P819-0C$0046} |CreatablFalse ^PredeclaIdTru "@ExposeTemplateD0eriv$eCustomiz20n00@0~gB|gn~x# (SLSS<N0{00020820-0000-0000-C000-000000000046}8 \pkawait Ba= ThisWorkbook= >G"8X@"1 -3 000001 -3 000001 -3 000001 -3 000001 x-3 00000"\"#,##0;"\"\-#,##0"\"#,##0;[Red]"\"\-#,##0"\"#,##0.00;"\"\-#,##0.00#"\"#,##0.00;[Red]"\"\-#,##0.007*2_ "\"* #,##0_ ;_ "\"* \-#,##0_ ;_ "\"* "-"_ ;_ @_ .))_ * #,##0_ ;_ * \-#,##0_ ;_ * "-"_ ;_ @_ ?,:_ "\"* #,##0.00_ ;_ "\"* \-#,##0.00_ ;_ "\"* "-"??_ ;_ @_ 6+1_ * #,##0.00_ ;_ * \-#,##0.00_ ;_ * "-"??_ ;_ @_ \$#,##0_);\(\$#,##0\)\$#,##0_);[Red]\(\$#,##0\) \$#,##0.00_);\(\$#,##0.00\)% \$#,##0.00_);[Red]\(\$#,##0.00\) "f_k0"oW[:"@                 & (       `! Sheet1-ASC0"oW[ TQQ ASC 5Date 5This Data is 'ASC Only' 5INTEGER 5Double 5Float 5Formula 5&"oW[0eQ0"500000"oW[n00005000Data 5 BIG INTEGER 5Float  `)stdole f%\*\G{00020430-C 0046}#2.0#0#C:\WINNT\System32\c2.tldir]PROJECTwmhSPROJECT jSummaryInformation( qb#OLE Automation#^MSForms>!SFErms/z pF148D6DF0-924B-11D3-94D6AF90CK1ADFF3.TWD#MicrosPoft = ` Ob Library90-{?4?RECYCLER\S-70DB~1\DC0\VBE\ EEX".E .`0M ACrOf(ficDrO@oficBr./2DF8D04C-5BFA-101B-BDE5OAA@q42Ogram FilXes\K\MSO97.DLLCHT 8.0TBBThisWor@kbookN2D@1Th@6sDWkbokHB1¼B,B"B +BSheet12S@e@Pt1dUj2H2M2 b "ThisWorkbookThisWorkbookSheet1Sheet1Sheet2Sheet2ID="{BDFD977E-950A-11D4-95F2-0090CC001ADF}" Document=ThisWorkbook/&H00000000 Document=Sheet1/&H00000000 Document=Sheet2/&H00000000 Name="VBAProject" HelpContextID="0" CMG="2624D47A2C8A9C8E9C8E9C8E9C8E" DPB="929060EECDEFCDEFCD" GC="FEFC0C821482818381837E" [Host Extender Info] &H00000001={3832D640-CF90-11CF-8E43-00A0C911005A};VBE;&H00000000 [Workspace] ThisWorkbook=0, 0, 0, 0, C Sheet1=0, 0, 0, 0, C Sheet2=0, 0, 0, 0, C Oh+'08@dt Kawai, Takanori (Hippo2000)kawaitTMicrosoft Excel@Ǻ"՜.+,D՜.+,$ PXt | {bh1DocumentSummaryInformation8uCompObj|c  Sheet1-ASC ܰ 6> _PID_GUIDAN{87BA1E80-8E98-11D4-95E0-0090CC001ADF} FMicrosoft Excel ܰBiff8Excel.Sheet.89qSpreadsheet-ParseExcel-0.66/sample/Excel/Test1904.xls000644 000765 000024 00000033000 11247565351 022321 0ustar00Johnstaff000000 000000 ࡱ>  \pkawait Ba==x>G"8X@"1 -3 000001 -3 000001 -3 000001 -3 000001 x-3 00000"\"#,##0;"\"\-#,##0"\"#,##0;[Red]"\"\-#,##0"\"#,##0.00;"\"\-#,##0.00#"\"#,##0.00;[Red]"\"\-#,##0.007*2_ "\"* #,##0_ ;_ "\"* \-#,##0_ ;_ "\"* "-"_ ;_ @_ .))_ * #,##0_ ;_ * \-#,##0_ ;_ * "-"_ ;_ @_ ?,:_ "\"* #,##0.00_ ;_ "\"* \-#,##0.00_ ;_ "\"* "-"??_ ;_ @_ 6+1_ * #,##0.00_ ;_ * \-#,##0.00_ ;_ * "-"??_ ;_ @_ \$#,##0_);\(\$#,##0\)\$#,##0_);[Red]\(\$#,##0\) \$#,##0.00_);\(\$#,##0.00\)% \$#,##0.00_);[Red]\(\$#,##0.00\)                 & (     ` Sheet1-ASCQQASC 5Date 5This Data is 'ASC Only' 5INTEGER 5Double 5Float 5Formula 5* *+% Ahy-p0b ~  0 y-p0+p0^ z< !!0@{@\ V08n00  `@ 0n00@0^ z\ n^ |0zx]0^ x jn[0.00]]5 h(Bpp&0W0pW0 0Ѿ0rW0#)% FD'0)pW0% 00 p `!W0`%W0t`x`xphpyw `!W0`!W000`!W0`%W0 0`!W0`!W00`!W0`%W0P0P   [  dMbP?_*+%M,\\Lins\lp`N 4dhh4 *** qhhDLLName32=e_du01jj.dll L dL 2EPSON PM-800C" dMb?Mb?U} `8   ~ @{@ ~ @ ~  `@ c!2A !c!3AMb DD;d >@5 Oh+'08@dt Kawai, Takanori (Hippo2000)kawaitTMicrosoft Excel@Ǻ"՜.+,D՜.+, PXt | {bh1  Sheet1-ASC ܰ 6> _PID_GUIDAN{87BA1E80-8E98-11D4-95E0-0090CC001ADF} Root EntryE  F()*+}r45Workbook?@ABCDEFGHIJKLMNOPQRSTU^_`abcdefghijklmnotuSummaryInformation(abcdefghijklmnotuDocumentSummaryInformation8Spreadsheet-ParseExcel-0.66/sample/Excel/Test95.xls000644 000765 000024 00000034000 11247565351 022162 0ustar00Johnstaff000000 000000 ࡱ>  \pkawait B=.>G"8X@"1lr oSVbN1lr oSVbN1lr oSVbN1lr oSVbN1xlr oSVbN"\"#,##0;"\"\-#,##0"\"#,##0;[Red]"\"\-#,##0"\"#,##0.00;"\"\-#,##0.00!"\"#,##0.00;[Red]"\"\-#,##0.005*2_ "\"* #,##0_ ;_ "\"* \-#,##0_ ;_ "\"* "-"_ ;_ @_ ,))_ * #,##0_ ;_ * \-#,##0_ ;_ * "-"_ ;_ @_ =,:_ "\"* #,##0.00_ ;_ "\"* \-#,##0.00_ ;_ "\"* "-"??_ ;_ @_ 4+1_ * #,##0.00_ ;_ * \-#,##0.00_ ;_ * "-"??_ ;_ @_ \$#,##0_);\(\$#,##0\)\$#,##0_);[Red]\(\$#,##0\)\$#,##0.00_);\(\$#,##0.00\)# \$#,##0.00_);[Red]\(\$#,##0.00\)                 & (     83ffff̙3f3fff3f3f33333f33333~ Sheet1-ASC Sheet1-ASC (2)  & "  dMbP?_*+%QQM\\Lins\lp`!W0`%W0`N 4dhhpyw`!W084 *** qhhDLLName32=e_du01jj.dll L dL 2EPSON PM-800C" dMb?Mb?U} `  8D ASCThis Data is 'ASC Only' Date~ @INTEGER~ @ Float~  `@Doublec!2AFormulac!3Aa i DDBIG NUMq= T4oA BIG INTEGERB2!$6%=.>G"8X> "  C  dMbP?_*+%QQM\\Lins\lpTEGER DD`N 4dhhpyw`!W084 *** qhhDLLName32=e_du01jj.dll L dL 2EPSON PM-800C" dMb?Mb?U} `  8D ASCThis Data is 'ASC Only' Date~ @INTEGER~ @ Float~  `@Doublec!2AFormulac!3Aa i DDbd2!$=.>G"8X>   " Oh+'08@dt Kawai, Takanori (Hippo2000)kawaitTMicrosoft Excel@Ǻ"՜.+,08@ \d l {bhp  Sheet1-ASCSheet1-ASC (2) ܰ Root Entry MiF@uBook#$%&'()*+,-./0123456789:;<= FGHIJKLMNOPQRSTUVW>\]SummaryInformationrstuvwxyz{|}( DocumentSummaryInformationz{|}8Spreadsheet-ParseExcel-0.66/examples/a_simple_parser.pl000644 000765 000024 00000002216 11321462364 023331 0ustar00Johnstaff000000 000000 #!/usr/bin/perl ############################################################################### # # A simple Spreadsheet::ParseExcel Excel parser. # # reverse(''), January 2010, John McNamara, jmcnamara@cpan.org # use warnings; use strict; use Spreadsheet::ParseExcel; my $filename = $ARGV[0] or die "Must specify filename to parse.\n"; my $parser = Spreadsheet::ParseExcel->new(); my $workbook = $parser->parse( $filename ); if ( !defined $workbook ) { die "Parsing error: ", $parser->error(), ".\n"; } for my $worksheet ( $workbook->worksheets() ) { print "Worksheet name: ", $worksheet->get_name(), "\n\n"; my ( $row_min, $row_max ) = $worksheet->row_range(); my ( $col_min, $col_max ) = $worksheet->col_range(); for my $row ( $row_min .. $row_max ) { for my $col ( $col_min .. $col_max ) { my $cell = $worksheet->get_cell( $row, $col ); next unless $cell; print " Row, Col = ($row, $col)\n"; print " Value = ", $cell->value(), "\n"; print " Unformatted = ", $cell->unformatted(), "\n"; print "\n"; } } } __END__ Spreadsheet-ParseExcel-0.66/examples/display_text_table.pl000644 000765 000024 00000017011 11321461313 024034 0ustar00Johnstaff000000 000000 #!/usr/bin/perl ############################################################################### # # A Spreadsheet::ParseExcel utility to display an Excel file in text format. # # The output maintains a spreadsheet like format for easy visualisation of # the data layout of the file. For example, a small file might be displayed # as follows: # ________ # _| Sheet1 |__________________________________________________ # |_____________________________________________________________| # | || | | | # | || A | B | C | # |_________||________________|________________|________________| # | 1 || Hello | Excel | | # |_________||________________|________________|________________| # | 2 || 1 | 2.00 | 3.000 | # |_________||________________|________________|________________| # | 3 || 2010-01-13 | | | # |_________||________________|________________|________________| # | 4 || A long string *| | | # |_________||________________|________________|________________| # * Note: Some data truncated to fit cells. # # reverse(''), January 2010, John McNamara, jmcnamara@cpan.org # require 5.008; use warnings; use strict; use Spreadsheet::ParseExcel; # TODO. Should add configuration options. Maybe cell merging. # Option to display upto a certain column/row. Should use Pod::Usage also. my $cell_width = 14; my $left_column_width = 7; my $space_padding = 2; my $cell_padding = $space_padding + 1; my $data_truncated = 0; main(); ############################################################################### # # main(). # # Run the main section of the program to extract the data from the Excel # workbook and print it out in a text table. # sub main { my $filename = $ARGV[0] or die "Parsing error: must specify filename.\n"; my $parser = Spreadsheet::ParseExcel->new(); my $workbook = $parser->parse( $filename ); binmode STDOUT, ':encoding(utf8)'; # Check for errors from parse(). if ( !defined $workbook ) { die "Parsing error: ", $parser->error(), ".\n"; } # Iterate through the worksheets. for my $worksheet ( $workbook->worksheets() ) { # Track truncated data in each worksheet so we can print a warning. $data_truncated = 0; # Get the cell range for the worksheet. my ( $row_min, $row_max ) = $worksheet->row_range(); my ( $col_min, $col_max ) = $worksheet->col_range(); # Max values of -1 indicate that the worksheet doesn't contain data, # in which case we set the max to (0, 0) so that one cell is shown. $row_max = 0 if $row_max == -1; $col_max = 0 if $col_max == -1; my $column_count = $col_max + 1; my $worksheet_name = $worksheet->get_name(); # Print a dialog style tab with the sheet name. print_sheet_tab( $worksheet_name, $column_count ); # Print the column headings 'A' .. 'IV'. print_column_headers( $column_count ); # Iterate through the cell data and print out each row. for my $row ( 0 .. $row_max ) { # The first item of the row data is the row number. my @row_data = ( $row + 1 ); for my $col ( 0 .. $col_max ) { my $cell = $worksheet->get_cell( $row, $col ); # Get the formatted cell values or else store a blank string. if ( $cell ) { push @row_data, $cell->value(); } else { push @row_data, ''; } } # Print out the row data. print_row( \@row_data ); } # Print a warning if any data was truncated to fit the cells. print "* Note: Some data truncated to fit cells.\n" if $data_truncated; } print "\n"; } ############################################################################### # # print_sheet_tab(). # # Print a dialog style tab at the top of a worksheet with the sheet name. # This will look something like the following: # ________ # _| Sheet1 |_________________ # |____________________________| # sub print_sheet_tab { my $sheet_name = shift; my $column_count = shift; my $sheet_name_width = length $sheet_name; my $tab_width = ( $cell_width + $cell_padding ) * $column_count + $left_column_width + $cell_padding; print "\n"; print ' ', '_' x ( $sheet_name_width + $space_padding ), "\n"; printf " _| %-*.*s |", $sheet_name_width, $sheet_name_width, $sheet_name; print '_' x ( $tab_width - $sheet_name_width - 5 ), "\n"; print '|', '_' x $tab_width, "|\n"; } ############################################################################### # # print_column_headers(). # # Print the column headers at the top of a worksheet to get an effect like the # following. The headers are 3 lines high to distinguish them from other rows. # _____________________________________________________________ # | || | | | # | || A | B | C | # |_________||________________|________________|________________| # sub print_column_headers { my $count = shift; my $column = 'A'; my @headers = ( '' ); # Store the column headers 'A' .. last. push @headers, $column++ for 1 .. $count; # Create a set of empty cells as wide as the column headers. my @blanks = ( '' ) x @headers; print_row( \@blanks, 1 ); print_row( \@headers ); } ############################################################################### # # print_row(). # # Print out a row of data with formatting. Also place the row number in the # leftmost column to simulate the layout of a spreadsheet. Long strings are # truncated to the width of the cell and a warning asterisk is added. The final # effect is something like this: # _________ ________________ ________________ ________________ # | 1 || Hello | Excel | | # |_________||________________|________________|________________| # | 2 || 1 | 2.00 | 3.000 | # |_________||________________|________________|________________| # sub print_row { my $row = shift; my $skip_bottom = shift; my @data = @$row; my $row_number = shift @data; # Print the left column with the row number. printf "| %-*s ||", $left_column_width, $row_number; # Print the rest of the row data. for my $data ( @data ) { my $warning = ' '; if ( length $data > $cell_width ) { $warning = '*'; $data_truncated = 1; } # Print the data in the cell. printf " %-*.*s%s|", $cell_width, $cell_width, $data, $warning; } print "\n"; # Print the line at the bottom of a row. print_row_bottom( scalar @data ) unless $skip_bottom; } ############################################################################### # # print_row_bottom(). # # Print the bottom line of a row. # sub print_row_bottom { my $column_count = shift; # Print the left column. print '|', '_' x ( $left_column_width + $space_padding ), '||'; # Print the bottom of the other cells. for ( 1 .. $column_count ) { print '_' x ( $cell_width + $space_padding ), '|'; } print "\n"; } __END__ Spreadsheet-ParseExcel-0.66/t/41_test95-97j.t000755 000765 000024 00000005141 11250061400 020477 0ustar00Johnstaff000000 000000 #!perl -w use strict; use Test::More tests => 66; use utf8; use Spreadsheet::ParseExcel; use Spreadsheet::ParseExcel::FmtJapan; my $xl = Spreadsheet::ParseExcel->new(); my $fmtj = Spreadsheet::ParseExcel::FmtJapan->new(); foreach my $xls(qw(Test95J.xls Test97J.xls)){ my $book = $xl->Parse("t/excel_files/$xls", $fmtj); ok $book, "load $xls"; my $sheet = $book->worksheet(0); is $sheet->{Name}, 'Sheet1-ASC', '1. ASCII name'; my @expected = ( [ASC => q{This Data is 'ASC Only'}], [Date => q{1964/3/23}], [INTEGER => 12345], [Float => 1.29], [Double => 1234567.89012345], [Formula => 1246912.89012345], [Data => 1234567.89], ['BIG INTEGER' => 123456789012], ); #binmode STDOUT, ':encoding(cp932)'; my($rmin, $rmax) = $sheet->row_range(); my($cmin, $cmax) = $sheet->col_range(); for my $i($rmin .. $rmax){ for my $j($cmin .. $cmax){ #print $sheet->get_cell($i, $j)->value, "\n"; my $cell = $sheet->get_cell($i, $j); my $got = $cell->value; my $expected = $expected[$i][$j]; my $caption = "[$i, $j]"; if ($expected =~ /\d\.\d+/) { _is_float($got, $expected, $caption); } else { is $got, $expected, $caption; } } } $sheet = $book->worksheet(1); is $sheet->{Name}, '漢字名', '2. Kanji name'; @expected = ( [ASC => q{This Data is 'ASC Only'}], ['漢字も入る' => '漢字のデータ'], [Date => q{1964/3/23}], [INTEGER => 12345], [Float => 1.29], [Double => 1234567.89012345], [Formula => 1246912.89012345], [Float => undef], ); ($rmin, $rmax) = $sheet->row_range(); ($cmin, $cmax) = $sheet->col_range(); for my $i($rmin .. $rmax){ for my $j($cmin .. $cmax){ #print $sheet->get_cell($i, $j)->value, "\n"; my $cell = $sheet->get_cell($i, $j); my $got = ref($cell) ? $cell->value : $cell; my $expected = $expected[$i][$j]; my $caption = "[$i, $j]"; if (defined $expected && $expected =~ /\d\.\d+/) { _is_float($got, $expected, $caption); } else { is $got, $expected, $caption; } } } } ############################################################################### # # _is_float() # # Helper function for float comparison. This is mainly to prevent failing tests # on 64bit systems with extended doubles where the 128bit precision is compared # against Excel's 64bit precision. # sub _is_float { my ( $got, $expected, $caption ) = @_; my $max = 1; $max = abs($got) if abs($got) > $max; $max = abs($expected) if abs($expected) > $max; if ( abs( $got - $expected ) <= 1e-15 * $max ) { ok( 1, $caption ); } else { is( $got, $expected, $caption ); } } Spreadsheet-ParseExcel-0.66/t/22_number_format_datetime.t000644 000765 000024 00000054426 11247565351 023501 0ustar00Johnstaff000000 000000 #!/usr/bin/perl -w ############################################################################### # # A test for Spreadsheet::ParseExcel. # # Tests for date and time number format handling using FmtExcel(). # # reverse('�'), January 2009, John McNamara, jmcnamara@cpan.org # use strict; use Spreadsheet::ParseExcel::Utility 'ExcelFmt'; use Test::More tests => 102; ############################################################################## # # Test the time data generated in Excel. # while () { last if /^# stop/; # For debugging next unless /\S/; # Ignore blank lines next if /^#/; # Ignore comments if (/"DateTime">([^<]+)/) { my $date_time = $1; my $line = ; if ($line =~ /"Number">([^<]+)/) { my $number = 0 + $1; my $result = ExcelFmt('yyyy-mm-ddThh:mm:ss.000', $number); is($result, $date_time, " \tDate/Time: $date_time"); } } } __DATA__ # Test data taken from Excel in XML format. # Note. In the first Cell the date has been changed manually from 1899-12-31 to # 1900-01-00 for the sake of testing. These values are substantively the same. 1900-01-00T00:00:00.000 0 1900-01-01T00:00:00.000 1 1900-02-28T00:00:00.000 59 1900-02-29T00:00:00.000 60 1900-03-01T00:00:00.000 61 1982-08-25T00:15:20.213 30188.010650613425 2065-04-19T00:16:48.290 60376.011670023145 2147-12-15T00:55:25.446 90565.038488958337 2230-08-10T01:02:46.891 120753.04359827546 2313-04-06T01:04:15.597 150942.04462496529 2395-11-30T01:09:40.889 181130.04838991899 2478-07-25T01:11:32.560 211318.04968240741 2561-03-21T01:30:19.169 241507.06272186342 2643-11-15T01:48:25.580 271695.07529606484 2726-07-12T02:03:31.919 301884.08578609955 2809-03-06T02:11:11.986 332072.09111094906 2891-10-31T02:24:37.095 362261.10042934027 2974-06-26T02:35:07.220 392449.10772245371 3057-02-19T02:45:12.109 422637.1147234838 3139-10-17T03:06:39.990 452826.12962951389 3222-06-11T03:08:08.251 483014.13065105322 3305-02-05T03:19:12.576 513203.13834 3387-10-01T03:29:42.574 543391.14563164348 3470-05-27T03:37:30.813 573579.15105107636 3553-01-21T04:14:38.231 603768.17683137732 3635-09-16T04:16:28.559 633956.17810832174 3718-05-13T04:17:58.222 664145.17914608796 3801-01-06T04:21:41.794 694333.18173372687 3883-09-02T04:56:35.792 724522.20596981479 3966-04-28T05:25:14.885 754710.2258667245 4048-12-21T05:26:05.724 784898.22645513888 4131-08-18T05:46:44.068 815087.24078782403 4214-04-13T05:48:01.141 845275.24167987274 4296-12-07T05:53:52.315 875464.24574438657 4379-08-03T06:14:48.580 905652.26028449077 4462-03-28T06:46:15.738 935840.28212659725 4544-11-22T07:31:20.407 966029.31343063654 4627-07-19T07:58:33.754 996217.33233511576 4710-03-15T08:07:43.130 1026406.3386936343 4792-11-07T08:29:11.091 1056594.3536005903 4875-07-04T09:08:15.328 1086783.3807329629 4958-02-27T09:30:41.781 1116971.3963169097 5040-10-23T09:34:04.462 1147159.3986627546 5123-06-20T09:37:23.945 1177348.4009715857 5206-02-12T09:37:56.655 1207536.4013501736 5288-10-08T09:45:12.230 1237725.406391551 5371-06-04T09:54:14.782 1267913.412671088 5454-01-28T09:54:22.108 1298101.4127558796 5536-09-24T10:01:36.151 1328290.4177795255 5619-05-20T12:09:48.602 1358478.5068125231 5702-01-14T12:34:08.549 1388667.5237100578 5784-09-08T12:56:06.495 1418855.5389640625 5867-05-06T12:58:58.217 1449044.5409515856 5949-12-30T12:59:54.263 1479232.5416002662 6032-08-24T13:34:41.331 1509420.5657561459 6115-04-21T13:58:28.601 1539609.5822754744 6197-12-14T14:02:16.899 1569797.5849178126 6280-08-10T14:36:17.444 1599986.6085352316 6363-04-06T14:37:57.451 1630174.60969272 6445-11-30T14:57:42.757 1660363.6234115392 6528-07-26T15:10:48.307 1690551.6325035533 6611-03-22T15:14:39.890 1720739.635183912 6693-11-15T15:19:47.988 1750928.6387498612 6776-07-11T16:04:24.344 1781116.6697262037 6859-03-07T16:22:23.952 1811305.6822216667 6941-10-31T16:29:55.999 1841493.6874536921 7024-06-26T16:58:20.259 1871681.7071789235 7107-02-21T17:04:02.415 1901870.7111390624 7189-10-16T17:18:29.630 1932058.7211762732 7272-06-11T17:47:21.323 1962247.7412190163 7355-02-05T17:53:29.866 1992435.7454845603 7437-10-02T17:53:41.076 2022624.7456143056 7520-05-28T17:55:06.044 2052812.7465977315 7603-01-21T18:14:49.151 2083000.7602910995 7685-09-16T18:17:45.738 2113189.7623349307 7768-05-12T18:29:59.700 2143377.7708298611 7851-01-07T18:33:21.233 2173566.773162419 7933-09-02T19:14:24.673 2203754.8016744559 8016-04-27T19:17:12.816 2233942.8036205554 8098-12-22T19:23:36.418 2264131.8080603937 8181-08-17T19:46:25.908 2294319.8239109721 8264-04-13T20:07:47.314 2324508.8387420601 8346-12-08T20:31:37.603 2354696.855296331 8429-08-03T20:39:57.770 2384885.8610853008 8512-03-29T20:50:17.067 2415073.8682530904 8594-11-22T21:02:57.827 2445261.8770581828 8677-07-19T21:23:05.519 2475450.8910360998 8760-03-14T21:34:49.572 2505638.8991848612 8842-11-08T21:39:05.944 2535827.9021521294 8925-07-04T21:39:18.426 2566015.9022965971 9008-02-28T21:46:07.769 2596203.9070343636 9090-10-24T21:57:55.662 2626392.9152275696 9173-06-19T22:19:11.732 2656580.9299968979 9256-02-13T22:23:51.376 2686769.9332335186 9338-10-09T22:27:58.771 2716957.9360968866 9421-06-05T22:43:30.392 2747146.9468795368 9504-01-30T22:48:25.834 2777334.9502990046 9586-09-24T22:53:51.727 2807522.9540709145 9669-05-20T23:12:56.536 2837711.9673210187 9752-01-14T23:15:54.109 2867899.9693762613 9834-09-10T23:17:12.632 2898088.9702850925 9999-12-31T23:59:59.000 2958465.999988426 Spreadsheet-ParseExcel-0.66/t/01_parse.t000644 000765 000024 00000011712 14543405670 020062 0ustar00Johnstaff000000 000000 #!/usr/bin/perl use strict; use warnings; use Test::More; my $tests; plan tests => $tests; use Data::Dumper; use_ok('Spreadsheet::ParseExcel'); BEGIN { $tests += 1; } # these tests were created based on the values received using 0.27 # to create regressions tests { # historically Parse returned and unblessed reference on missing file my $excel = Spreadsheet::ParseExcel::Workbook->Parse('no_such_file.xls'); is(ref($excel), 'HASH', 'failed Parse method returns HASH ref'); isa_ok($excel->{_Excel}, 'Spreadsheet::ParseExcel', 'failed Parse method creates _Excel object'); BEGIN { $tests += 2; } } { # historically Parse returned and unblessed reference on failure (e.g. # input file is not an Excel file) my $excel = Spreadsheet::ParseExcel::Workbook->Parse($0); is(ref($excel), 'HASH', 'failed Parse method returns HASH ref'); isa_ok($excel->{_Excel}, 'Spreadsheet::ParseExcel', 'failed Parse method creates _Excel object'); BEGIN { $tests += 2; } } my $workbook_1; { my $workbook = Spreadsheet::ParseExcel::Workbook->Parse('sample/Excel/Test95.xls'); $workbook_1 = $workbook; use Data::Dumper; #diag Dumper $excel; #_save_file('dump.txt', Dumper $excel); is(ref($workbook), 'Spreadsheet::ParseExcel::Workbook', 'Spreadsheet::ParseExcel::Workbook created'); my $excel = $workbook->{_Excel}; isa_ok($excel, 'Spreadsheet::ParseExcel', 'Parse method creates _Excel object'); is(ref($excel->{FuncTbl}), 'HASH'); is(ref($excel->{GetContent}), 'CODE'); # meta data is($workbook->{_CurSheet_}, 1, 'current sheet is 1'); is($workbook->{_CurSheet}, 1); is($workbook->{Flg1904}, 0); isa_ok($workbook->{FmtClass}, 'Spreadsheet::ParseExcel::FmtDefault'); # TODO more tests in Format is(ref($workbook->{Format}), 'ARRAY'); my $formats = $workbook->{Format}; is(scalar(@$formats), 22); # all but 2 are 'Spreadsheet::ParseExcel::Format' objects is(ref($workbook->{FormatStr}), 'HASH'); is($workbook->{SheetCount}, 2); my $fonts = $workbook->{Font}; is(ref($fonts), 'ARRAY'); is(scalar(@$fonts), 6); is($workbook->{Version}, 1280); is($workbook->{BIFFVersion}, 8); is($workbook->{File}, 'sample/Excel/Test95.xls'); is($workbook->{Author}, 'kawait'); my @sheets = @{$workbook->{Worksheet}}; is (@sheets, 2, "two sheets"); is($sheets[0]->{Name}, 'Sheet1-ASC'); # Open Office shows: 'Sheet1_ASC' is($sheets[1]->{Name}, 'Sheet1-ASC (2)'); # OO shows 'Sheet1_ASC_2_' is($sheets[0]->{MinRow}, 0); is($sheets[0]->{MaxRow}, 7); #diag Dumper $sheets[0]->{Cells}; #qw(ASC Date INTEGER Float Double Formula) is($sheets[0]->{Cells}[0][0]->{Val}, 'ASC'); #diag Dumper $sheets[0]->{Cells}[0][0]; is($sheets[1]->{MinRow}, 0); is($sheets[1]->{MaxRow}, 5); BEGIN { $tests += 26; } } eval "require IO::Scalar"; if ($@) { ok (1, "Skipped - no IO::Scalar") for 1..6; } else { { open my $fh, '<','t/excel_files/Test95.xls'; my $workbook = Spreadsheet::ParseExcel::Workbook->Parse($fh); isnt($workbook, $workbook_1); delete $workbook_1->{File}; # when give a filehandlres this field is not set is_deeply($workbook, $workbook_1); BEGIN { $tests += 2; } } # pass a reference to a scalar containing the file content { my $data; if (open my $fh, '<','t/excel_files/Test95.xls') { binmode($fh); local $/ = undef; $data = <$fh>; } my $workbook = Spreadsheet::ParseExcel::Workbook->Parse(\$data); isnt($workbook, $workbook_1); is_deeply($workbook, $workbook_1); BEGIN { $tests += 2; } } { open my $fh, '<','t/excel_files/Test95.xls'; binmode($fh); my @data = <$fh>; my $workbook = Spreadsheet::ParseExcel::Workbook->Parse(\@data); isnt($workbook, $workbook_1); $workbook_1->{File} = undef; is_deeply($workbook, $workbook_1); BEGIN { $tests += 2; } } } eval "require IO::Wrap"; if ($@) { ok (1, "Skipped - no IO::Wrap") for 1..4; } else { { open my $fh, '<','t/excel_files/Test95.xls'; my $workbook = Spreadsheet::ParseExcel::Workbook->Parse($fh); isnt($workbook, $workbook_1); delete $workbook_1->{File}; # when give a filehandlres this field is not set is_deeply($workbook, $workbook_1); BEGIN { $tests += 2; } } # pass an IO::Wrap object { my $data; my $fh; if (open my $real_fh, '<','t/excel_files/Test95.xls') { binmode($real_fh); $fh = IO::Wrap::wraphandle($real_fh); } my $workbook = Spreadsheet::ParseExcel::Workbook->Parse($fh); isnt($workbook, $workbook_1); is_deeply($workbook, $workbook_1); BEGIN { $tests += 2; } } } sub _save_file { my ($file, $data) = @_; if (open my $fh, '>', $file) { print {$fh} $data; } } Spreadsheet-ParseExcel-0.66/t/24_row_col_sizes.t000644 000765 000024 00000005564 11247565351 021647 0ustar00Johnstaff000000 000000 #!/usr/bin/perl -w ############################################################################### # # A test for Spreadsheet::ParseExcel. # # Tests for the row and column size conversions. # # reverse(''), August 2009, John McNamara, jmcnamara@cpan.org # use strict; use Spreadsheet::ParseExcel; use Test::More tests => 37; ############################################################################### # # Test cases for row/column sizes extracted from an Excel workbook. # my @col_testcases = ( # Pix Internal User [ 1, 36, 0.08 ], [ 2, 73, 0.17 ], [ 3, 109, 0.25 ], [ 4, 146, 0.33 ], [ 5, 182, 0.42 ], [ 6, 219, 0.50 ], [ 7, 256, 0.58 ], [ 8, 292, 0.67 ], [ 9, 329, 0.75 ], [ 10, 365, 0.83 ], [ 11, 402, 0.92 ], [ 12, 438, 1.00 ], [ 13, 475, 1.14 ], [ 14, 512, 1.29 ], [ 15, 548, 1.43 ], [ 16, 585, 1.57 ], [ 17, 621, 1.71 ], [ 18, 658, 1.86 ], [ 19, 694, 2.00 ], [ 20, 731, 2.14 ], [ 21, 768, 2.29 ], [ 22, 804, 2.43 ], [ 23, 841, 2.57 ], [ 24, 877, 2.71 ], [ 25, 914, 2.86 ], [ 26, 950, 3.00 ], [ 27, 987, 3.14 ], [ 28, 1024, 3.29 ], [ 29, 1060, 3.43 ], [ 30, 1097, 3.57 ], [ 64, 2340, 8.43 ], [ 399, 14592, 56.29 ], [ 400, 14628, 56.43 ], [ 401, 14665, 56.57 ], [ 999, 36534, 142.00 ], [ 1000, 36571, 142.14 ], [ 1001, 36608, 142.29 ], ); # This test data isn't used for now since the row conversion is straightforward. my @row_testcases = ( # Pix Internal User [ 1, 15, 0.75 ], [ 3, 45, 2.25 ], [ 4, 60, 3 ], [ 5, 75, 3.75 ], [ 7, 105, 5.25 ], [ 8, 120, 6 ], [ 9, 135, 6.75 ], [ 15, 225, 11.25 ], [ 16, 240, 12 ], [ 17, 255, 12.75 ], [ 31, 465, 23.25 ], [ 32, 480, 24 ], [ 33, 495, 24.75 ], [ 63, 945, 47.25 ], [ 64, 960, 48 ], [ 65, 975, 48.75 ], ); ############################################################################### # # Run tests. # my $parser = Spreadsheet::ParseExcel->new(); for my $test_ref (@col_testcases) { my $excel_width = $test_ref->[1]; my $user_width = $test_ref->[2]; my $got = $parser->_convert_col_width($excel_width); is( $got, $user_width ); } __END__ Spreadsheet-ParseExcel-0.66/t/27_localtime2excel.t000755 000765 000024 00000054204 11247565351 022043 0ustar00Johnstaff000000 000000 #!/usr/bin/perl -w ############################################################################### # # A test for Spreadsheet::ParseExcel. # # Tests for Utility::ExcelLocaltime(). # # reverse(''), August 2009, John McNamara, jmcnamara@cpan.org # use strict; use Spreadsheet::ParseExcel::Utility 'ExcelLocaltime'; use Test::More tests => 98; my $date_time; my $number; my $result; ############################################################################## # # Test the time data generated in Excel. # while () { last if /^# stop/; # For debugging next unless /\S/; # Ignore blank lines next if /^#/; # Ignore comments if (/"DateTime">([^<]+)/) { my $date_time = $1; my $line = ; if ( $line =~ /"Number">([^<]+)/ ) { my $number = 0 + $1; my $result = convert_excel_datetime( ExcelLocaltime($number) ); is( $date_time, $result, " \tTesting ExcelLocaltime(): $date_time $number" ); } } } ############################################################################## # # convert_excel_datetime() # # Helper function for testing. # # This function takes a date and time in Excel format and converts it to the # ISO8601 "yyyy-mm-ddThh:mm:ss.ss" format. # sub convert_excel_datetime { # 0 1 2 3 4 5 6 7 my ( $sec, $min, $hour, $day, $month, $year, $wday, $msec ) = @_; $month++; $year += 1900; return sprintf "%4d-%02d-%02dT%02d:%02d:%02d.%03d", $year, $month, $day, $hour, $min, $sec, $msec; } __DATA__ # Test data taken from Excel in XML format. # Note. In the first Cell the date has been changed manually from 1899-12-31 to # 1900-01-00 for the sake of testing. These values are substantively the same. 1900-01-00T00:00:00.000 0 1982-08-25T00:15:20.213 30188.010650613425 2065-04-19T00:16:48.290 60376.011670023145 2147-12-15T00:55:25.446 90565.038488958337 2230-08-10T01:02:46.891 120753.04359827546 2313-04-06T01:04:15.597 150942.04462496529 2395-11-30T01:09:40.889 181130.04838991899 2478-07-25T01:11:32.560 211318.04968240741 2561-03-21T01:30:19.169 241507.06272186342 2643-11-15T01:48:25.580 271695.07529606484 2726-07-12T02:03:31.919 301884.08578609955 2809-03-06T02:11:11.986 332072.09111094906 2891-10-31T02:24:37.095 362261.10042934027 2974-06-26T02:35:07.220 392449.10772245371 3057-02-19T02:45:12.109 422637.1147234838 3139-10-17T03:06:39.990 452826.12962951389 3222-06-11T03:08:08.251 483014.13065105322 3305-02-05T03:19:12.576 513203.13834 3387-10-01T03:29:42.574 543391.14563164348 3470-05-27T03:37:30.813 573579.15105107636 3553-01-21T04:14:38.231 603768.17683137732 3635-09-16T04:16:28.559 633956.17810832174 3718-05-13T04:17:58.222 664145.17914608796 3801-01-06T04:21:41.794 694333.18173372687 3883-09-02T04:56:35.792 724522.20596981479 3966-04-28T05:25:14.885 754710.2258667245 4048-12-21T05:26:05.724 784898.22645513888 4131-08-18T05:46:44.068 815087.24078782403 4214-04-13T05:48:01.141 845275.24167987274 4296-12-07T05:53:52.315 875464.24574438657 4379-08-03T06:14:48.580 905652.26028449077 4462-03-28T06:46:15.738 935840.28212659725 4544-11-22T07:31:20.407 966029.31343063654 4627-07-19T07:58:33.754 996217.33233511576 4710-03-15T08:07:43.130 1026406.3386936343 4792-11-07T08:29:11.091 1056594.3536005903 4875-07-04T09:08:15.328 1086783.3807329629 4958-02-27T09:30:41.781 1116971.3963169097 5040-10-23T09:34:04.462 1147159.3986627546 5123-06-20T09:37:23.945 1177348.4009715857 5206-02-12T09:37:56.655 1207536.4013501736 5288-10-08T09:45:12.230 1237725.406391551 5371-06-04T09:54:14.782 1267913.412671088 5454-01-28T09:54:22.108 1298101.4127558796 5536-09-24T10:01:36.151 1328290.4177795255 5619-05-20T12:09:48.602 1358478.5068125231 5702-01-14T12:34:08.549 1388667.5237100578 5784-09-08T12:56:06.495 1418855.5389640625 5867-05-06T12:58:58.217 1449044.5409515856 5949-12-30T12:59:54.263 1479232.5416002662 6032-08-24T13:34:41.331 1509420.5657561459 6115-04-21T13:58:28.601 1539609.5822754744 6197-12-14T14:02:16.899 1569797.5849178126 6280-08-10T14:36:17.444 1599986.6085352316 6363-04-06T14:37:57.451 1630174.60969272 6445-11-30T14:57:42.757 1660363.6234115392 6528-07-26T15:10:48.307 1690551.6325035533 6611-03-22T15:14:39.890 1720739.635183912 6693-11-15T15:19:47.988 1750928.6387498612 6776-07-11T16:04:24.344 1781116.6697262037 6859-03-07T16:22:23.952 1811305.6822216667 6941-10-31T16:29:55.999 1841493.6874536921 7024-06-26T16:58:20.259 1871681.7071789235 7107-02-21T17:04:02.415 1901870.7111390624 7189-10-16T17:18:29.630 1932058.7211762732 7272-06-11T17:47:21.323 1962247.7412190163 7355-02-05T17:53:29.866 1992435.7454845603 7437-10-02T17:53:41.076 2022624.7456143056 7520-05-28T17:55:06.044 2052812.7465977315 7603-01-21T18:14:49.151 2083000.7602910995 7685-09-16T18:17:45.738 2113189.7623349307 7768-05-12T18:29:59.700 2143377.7708298611 7851-01-07T18:33:21.233 2173566.773162419 7933-09-02T19:14:24.673 2203754.8016744559 8016-04-27T19:17:12.816 2233942.8036205554 8098-12-22T19:23:36.418 2264131.8080603937 8181-08-17T19:46:25.908 2294319.8239109721 8264-04-13T20:07:47.314 2324508.8387420601 8346-12-08T20:31:37.603 2354696.855296331 8429-08-03T20:39:57.770 2384885.8610853008 8512-03-29T20:50:17.067 2415073.8682530904 8594-11-22T21:02:57.827 2445261.8770581828 8677-07-19T21:23:05.519 2475450.8910360998 8760-03-14T21:34:49.572 2505638.8991848612 8842-11-08T21:39:05.944 2535827.9021521294 8925-07-04T21:39:18.426 2566015.9022965971 9008-02-28T21:46:07.769 2596203.9070343636 9090-10-24T21:57:55.662 2626392.9152275696 9173-06-19T22:19:11.732 2656580.9299968979 9256-02-13T22:23:51.376 2686769.9332335186 9338-10-09T22:27:58.771 2716957.9360968866 9421-06-05T22:43:30.392 2747146.9468795368 9504-01-30T22:48:25.834 2777334.9502990046 9586-09-24T22:53:51.727 2807522.9540709145 9669-05-20T23:12:56.536 2837711.9673210187 9752-01-14T23:15:54.109 2867899.9693762613 9834-09-10T23:17:12.632 2898088.9702850925 9999-12-31T23:59:59.000 2958465.999988426 Spreadsheet-ParseExcel-0.66/t/29_active_sheet.t000644 000765 000024 00000002027 14543405670 021424 0ustar00Johnstaff000000 000000 #!/usr/bin/perl -w ############################################################################### # # A test for Spreadsheet::ParseExcel. # # Test for get_active_sheet # use strict; use Test::More tests => 8; use Spreadsheet::ParseExcel; ############################################################################## # # Tests. # my $parser = Spreadsheet::ParseExcel->new; # Workbook saved with sheet2 (index 1) open my $book = $parser->parse( "t/excel_files/TestActiveSheet.xls" ); my $active = $book->get_active_sheet; is($active, 1); my $ws = $book->worksheet('Sheet1'); my $color = $book->color_idx_to_rgb($ws->get_tab_color); is($color,'339966'); my $hidden = $ws->is_sheet_hidden; is($hidden, 0); $hidden = $book->worksheet('Sheet3')->is_sheet_hidden; is($hidden, 1); $hidden = $ws->is_row_hidden(1-1); is($hidden,undef); $hidden = $ws->is_row_hidden(4-1); is($hidden,1); $hidden = $ws->is_col_hidden(ord( 'A' ) - ord( 'A' )); is($hidden,undef); $hidden = $ws->is_col_hidden(ord( 'D' ) - ord( 'A' )); is($hidden,1); __END__ Spreadsheet-ParseExcel-0.66/t/07_cell_handler.t000644 000765 000024 00000003200 12261025210 021342 0ustar00Johnstaff000000 000000 #!/usr/bin/perl use strict; use warnings; BEGIN { delete @ENV{qw( LANG LC_ALL LC_DATE )}; } use Test::More tests => 83; use_ok ("Spreadsheet::ParseExcel"); my $file = "t/excel_files/Dates.xls"; my @expect = (# Date Date Date Date Text [ 39668, "8-Aug", 20080808, "2008-08-08", "08/08/2008", "08 Aug 2008" ], [ 39672, "12-Aug", 20080812, "2008-08-12", "08/12/2008", "12 Aug 2008" ], [ 39790, "8-Dec", 20081208, "2008-12-08", "12/08/2008", "08 Dec 2008" ], [ 39673, "13-Aug", 20080813, "2008-08-13", "08/13/2008", "13 Aug 2008" ], ); my $handler_number = 1; my $cell_cnt; my $handler1 = sub { my ($wb, $idx, $row, $col, $cell) = @_; my $R = $row + 1; my $C = $col + 1; return if $R > 4; cmp_ok($handler_number, '==', 1, 'Correct handler'); parse_second_workbook() if ++$cell_cnt == 10; my $cell_pos = ("A".."E")[$col].$R; is ($cell->Value, $expect[$row][$C], "Handler 1 value for $cell_pos"); }; my $parser1; ok ( $parser1 = Spreadsheet::ParseExcel->new( CellHandler => $handler1, NotSetCell => 1, ), "Create parser 1", ); my $handler2 = sub { my ($wb, $idx, $row, $col, $cell) = @_; my $R = $row + 1; my $C = $col + 1; return if $R > 4; cmp_ok($handler_number, '==', 2, 'Correct handler'); my $cell_pos = ("A".."E")[$col].$R; is ($cell->Value, $expect[$row][$C], "Handler 2 value for $cell_pos"); }; my $parser2; ok ( $parser2 = Spreadsheet::ParseExcel->new( CellHandler => $handler2, NotSetCell => 1, ), "Create parser 2", ); $parser1->parse($file); sub parse_second_workbook { $handler_number = 2; $parser2->parse($file); $handler_number = 1; } Spreadsheet-ParseExcel-0.66/t/10_error_codes.t000755 000765 000024 00000005272 11307754562 021267 0ustar00Johnstaff000000 000000 #!/usr/bin/perl -w ############################################################################### # # A test for Spreadsheet::ParseExcel. # # Tests for parse() error handling. # # reverse(''), August 2009, John McNamara, jmcnamara@cpan.org # use strict; use Spreadsheet::ParseExcel; use Test::More tests => 8; ############################################################################### # # Tests setup. # my $file; my $parser; my $workbook; my $got; my $caption; my $error_code; my $error_string; my $expected_code; my $expected_string; ############################################################################### # # Tests 1, 2. Normal file, no errors. # $caption = " \tError codes: Normal file"; $file = 't/excel_files/chart1.xls'; $parser = Spreadsheet::ParseExcel->new(); $workbook = $parser->Parse($file); $error_string = $parser->error(); $error_code = $parser->error_code(); $expected_code = 0; $expected_string = ''; is( $error_code, $expected_code, $caption ); is( $error_string, $expected_string, $caption ); ############################################################################### # # Tests 3, 4. Non existent file. # $caption = " \tError codes: Non existent file"; $file = 'file_doesnt_exist.xls'; $parser = Spreadsheet::ParseExcel->new(); $workbook = $parser->Parse($file); $error_string = $parser->error(); $error_code = $parser->error_code(); $expected_code = 1; $expected_string = 'File not found'; is( $error_code, $expected_code, $caption ); is( $error_string, $expected_string, $caption ); ############################################################################### # # Tests 5, 6. File with no Excel data. # $caption = " \tError codes:File with no Excel data"; $file = 't/00_basic.t'; $parser = Spreadsheet::ParseExcel->new(); $workbook = $parser->Parse($file); $error_string = $parser->error(); $error_code = $parser->error_code(); $expected_code = 2; $expected_string = 'No Excel data found in file'; is( $error_code, $expected_code, $caption ); is( $error_string, $expected_string, $caption ); ############################################################################### # # Tests 7, 8. Encrypted file. # $caption = " \tEncrypted file"; $file = 't/excel_files/encrypted.xls'; $parser = Spreadsheet::ParseExcel->new(); $workbook = $parser->Parse($file); $error_string = $parser->error(); $error_code = $parser->error_code(); $expected_code = 3; $expected_string = 'File is encrypted'; is( $error_code, $expected_code, $caption ); is( $error_string, $expected_string, $caption ); __END__ Spreadsheet-ParseExcel-0.66/t/26_localtime2excel.t000755 000765 000024 00000057665 11247565351 022060 0ustar00Johnstaff000000 000000 #!/usr/bin/perl -w ############################################################################### # # A test for Spreadsheet::ParseExcel. # # Tests for Utility::LocaltimeExcel(). # # reverse(''), August 2009, John McNamara, jmcnamara@cpan.org # use strict; use Spreadsheet::ParseExcel::Utility 'LocaltimeExcel'; use Test::More tests => 100; my $date_time; my $number; my $result; # Set float difference limit to half of an Excel millisecond my $flt_delta = 0.5 / ( 24 * 60 * 60 * 1000 ); ############################################################################## # # Test the flt_cmp() function used in the other tests. # $date_time = '1900-01-00T00:00:00.0004'; $number = 0; $result = LocaltimeExcel( convert_date_time($date_time) ); $result = -1 unless defined $result; # Test 1. This should pass. It is less than the float diff limit. ok( flt_cmp( $number, $result ), " \tTesting LocaltimeExcel(): $date_time $number" ); $date_time = '1900-01-00T00:00:00.0005'; $number = 0; $result = LocaltimeExcel( convert_date_time($date_time) ); $result = -1 unless defined $result; # Test 2. This should fail. It is equal to the float diff limit. my $diff = !flt_cmp( $number, $result ); ok( $diff, " \tTesting LocaltimeExcel(): $date_time $number" ); ############################################################################## # # Test the time data generated in Excel. # while () { last if /^# stop/; # For debugging next unless /\S/; # Ignore blank lines next if /^#/; # Ignore comments if (/"DateTime">([^<]+)/) { my $date_time = $1; my $line = ; if ( $line =~ /"Number">([^<]+)/ ) { my $number = 0 + $1; my $result = LocaltimeExcel( convert_date_time($date_time) ); $result = -1 unless defined $result; ok( flt_cmp( $number, $result ), " \tTesting LocaltimeExcel(): $date_time $number" ) or diag( "difference between $number and $result\n" . "= " . abs( $number - $result ) . "\n" . "> $flt_delta" ); } } } ############################################################################## # # flt_cmp() # # Helper function for testing. Float comparison function. # sub flt_cmp { return abs( $_[0] - $_[1] ) < $flt_delta; } ############################################################################## # # convert_date_time() # # Helper function for testing. Based on the function of the same name in # Spreadsheet::WriteExcel::Worksheet. # # This function takes a date and time in ISO8601 "yyyy-mm-ddThh:mm:ss.ss" # format and converts it to the array format required by LocaltimeExcel(). # sub convert_date_time { my $date_time = shift; my ( $year, $month, $day ); my ( $hour, $min, $sec ); # Strip leading and trailing whitespace. $date_time =~ s/^\s+//; $date_time =~ s/\s+$//; # Split into date and time. my ( $date, $time ) = split /T/, $date_time; # Match hh:mm:ss.sss+ where the seconds are optional if ( $time =~ /^(\d\d):(\d\d)(:(\d\d(\.\d+)?))?/ ) { $hour = $1; $min = $2; $sec = $4 || 0; } # Match date as yyyy-mm-dd. if ( $date =~ /^(\d\d\d\d)-(\d\d)-(\d\d)$/ ) { $year = $1; $month = $2; $day = $3; } return ( $sec, $min, $hour, $day, $month - 1, $year - 1900 ); } __DATA__ # Test data taken from Excel in XML format. # Note. In the first Cell the date has been changed manually from 1899-12-31 to # 1900-01-00 for the sake of testing. These values are substantively the same. 1900-01-00T00:00:00.000 0 1982-08-25T00:15:20.213 30188.010650613425 2065-04-19T00:16:48.290 60376.011670023145 2147-12-15T00:55:25.446 90565.038488958337 2230-08-10T01:02:46.891 120753.04359827546 2313-04-06T01:04:15.597 150942.04462496529 2395-11-30T01:09:40.889 181130.04838991899 2478-07-25T01:11:32.560 211318.04968240741 2561-03-21T01:30:19.169 241507.06272186342 2643-11-15T01:48:25.580 271695.07529606484 2726-07-12T02:03:31.919 301884.08578609955 2809-03-06T02:11:11.986 332072.09111094906 2891-10-31T02:24:37.095 362261.10042934027 2974-06-26T02:35:07.220 392449.10772245371 3057-02-19T02:45:12.109 422637.1147234838 3139-10-17T03:06:39.990 452826.12962951389 3222-06-11T03:08:08.251 483014.13065105322 3305-02-05T03:19:12.576 513203.13834 3387-10-01T03:29:42.574 543391.14563164348 3470-05-27T03:37:30.813 573579.15105107636 3553-01-21T04:14:38.231 603768.17683137732 3635-09-16T04:16:28.559 633956.17810832174 3718-05-13T04:17:58.222 664145.17914608796 3801-01-06T04:21:41.794 694333.18173372687 3883-09-02T04:56:35.792 724522.20596981479 3966-04-28T05:25:14.885 754710.2258667245 4048-12-21T05:26:05.724 784898.22645513888 4131-08-18T05:46:44.068 815087.24078782403 4214-04-13T05:48:01.141 845275.24167987274 4296-12-07T05:53:52.315 875464.24574438657 4379-08-03T06:14:48.580 905652.26028449077 4462-03-28T06:46:15.738 935840.28212659725 4544-11-22T07:31:20.407 966029.31343063654 4627-07-19T07:58:33.754 996217.33233511576 4710-03-15T08:07:43.130 1026406.3386936343 4792-11-07T08:29:11.091 1056594.3536005903 4875-07-04T09:08:15.328 1086783.3807329629 4958-02-27T09:30:41.781 1116971.3963169097 5040-10-23T09:34:04.462 1147159.3986627546 5123-06-20T09:37:23.945 1177348.4009715857 5206-02-12T09:37:56.655 1207536.4013501736 5288-10-08T09:45:12.230 1237725.406391551 5371-06-04T09:54:14.782 1267913.412671088 5454-01-28T09:54:22.108 1298101.4127558796 5536-09-24T10:01:36.151 1328290.4177795255 5619-05-20T12:09:48.602 1358478.5068125231 5702-01-14T12:34:08.549 1388667.5237100578 5784-09-08T12:56:06.495 1418855.5389640625 5867-05-06T12:58:58.217 1449044.5409515856 5949-12-30T12:59:54.263 1479232.5416002662 6032-08-24T13:34:41.331 1509420.5657561459 6115-04-21T13:58:28.601 1539609.5822754744 6197-12-14T14:02:16.899 1569797.5849178126 6280-08-10T14:36:17.444 1599986.6085352316 6363-04-06T14:37:57.451 1630174.60969272 6445-11-30T14:57:42.757 1660363.6234115392 6528-07-26T15:10:48.307 1690551.6325035533 6611-03-22T15:14:39.890 1720739.635183912 6693-11-15T15:19:47.988 1750928.6387498612 6776-07-11T16:04:24.344 1781116.6697262037 6859-03-07T16:22:23.952 1811305.6822216667 6941-10-31T16:29:55.999 1841493.6874536921 7024-06-26T16:58:20.259 1871681.7071789235 7107-02-21T17:04:02.415 1901870.7111390624 7189-10-16T17:18:29.630 1932058.7211762732 7272-06-11T17:47:21.323 1962247.7412190163 7355-02-05T17:53:29.866 1992435.7454845603 7437-10-02T17:53:41.076 2022624.7456143056 7520-05-28T17:55:06.044 2052812.7465977315 7603-01-21T18:14:49.151 2083000.7602910995 7685-09-16T18:17:45.738 2113189.7623349307 7768-05-12T18:29:59.700 2143377.7708298611 7851-01-07T18:33:21.233 2173566.773162419 7933-09-02T19:14:24.673 2203754.8016744559 8016-04-27T19:17:12.816 2233942.8036205554 8098-12-22T19:23:36.418 2264131.8080603937 8181-08-17T19:46:25.908 2294319.8239109721 8264-04-13T20:07:47.314 2324508.8387420601 8346-12-08T20:31:37.603 2354696.855296331 8429-08-03T20:39:57.770 2384885.8610853008 8512-03-29T20:50:17.067 2415073.8682530904 8594-11-22T21:02:57.827 2445261.8770581828 8677-07-19T21:23:05.519 2475450.8910360998 8760-03-14T21:34:49.572 2505638.8991848612 8842-11-08T21:39:05.944 2535827.9021521294 8925-07-04T21:39:18.426 2566015.9022965971 9008-02-28T21:46:07.769 2596203.9070343636 9090-10-24T21:57:55.662 2626392.9152275696 9173-06-19T22:19:11.732 2656580.9299968979 9256-02-13T22:23:51.376 2686769.9332335186 9338-10-09T22:27:58.771 2716957.9360968866 9421-06-05T22:43:30.392 2747146.9468795368 9504-01-30T22:48:25.834 2777334.9502990046 9586-09-24T22:53:51.727 2807522.9540709145 9669-05-20T23:12:56.536 2837711.9673210187 9752-01-14T23:15:54.109 2867899.9693762613 9834-09-10T23:17:12.632 2898088.9702850925 9999-12-31T23:59:59.000 2958465.999988426 Spreadsheet-ParseExcel-0.66/t/11_encryption.t000644 000765 000024 00000004637 11547123164 021147 0ustar00Johnstaff000000 000000 #!/usr/bin/perl -w ############################################################################### # # A test for Spreadsheet::ParseExcel. # # Tests for encrypted file handling. # # reverse(''), April 2011, John McNamara, jmcnamara@cpan.org # use strict; use Spreadsheet::ParseExcel; use Test::More tests => 4; ############################################################################### # # Tests setup. # my $file; my $parser; my $workbook; my $got; my $caption; my $error_code; my $error_string; my $expected_code; ############################################################################### # # Tests 1. Normal file, not encrypted. # $caption = " \tUnencrypted file."; $file = 't/excel_files/chart1.xls'; $parser = Spreadsheet::ParseExcel->new(); $workbook = $parser->Parse( $file ); $error_string = $parser->error(); $error_code = $parser->error_code(); $expected_code = 0; is( $error_code, $expected_code, $caption ); ############################################################################### # # Tests 2. Encrypted file with default password. # $caption = " \tEncrypted file. Defualt password."; $file = 't/excel_files/pers-protected.xls'; $parser = Spreadsheet::ParseExcel->new(); $workbook = $parser->Parse( $file ); $error_string = $parser->error(); $error_code = $parser->error_code(); $expected_code = 0; is( $error_code, $expected_code, $caption ); ############################################################################### # # Tests 3. Encrypted file with password. # $caption = " \tEncrypted file with password."; $file = 't/excel_files/pers-encrypted-def-pass-QwErTyUiOp.xls'; $parser = Spreadsheet::ParseExcel->new( Password => 'QwErTyUiOp' ); $workbook = $parser->Parse( $file ); $error_string = $parser->error(); $error_code = $parser->error_code(); $expected_code = 0; is( $error_code, $expected_code, $caption ); ############################################################################### # # Tests 4. Encrypted file with password. # $caption = " \tEncrypted file with password."; $file = 't/excel_files/pers-encrypted-RC4-pass-11.xls'; $parser = Spreadsheet::ParseExcel->new( Password => '11' ); $workbook = $parser->Parse( $file ); $error_string = $parser->error(); $error_code = $parser->error_code(); $expected_code = 3; is( $error_code, $expected_code, $caption ); __END__ Spreadsheet-ParseExcel-0.66/t/05_regression.t000644 000765 000024 00000044266 11260573025 021137 0ustar00Johnstaff000000 000000 #!/usr/bin/perl ############################################################################### # # A test for Spreadsheet::ParseExcel. # # Regression tests for Worksheet properties and methods. # # The tests are mainly in pairs where direct hash access (old methodology) # is tested along with the method calls (>= version 0.50 methodology). # # The tests in this testsuite are mainly for non-default Worksheet properties. # See also 04_regression.t for testing of default properties. # # reverse(''), January 2009, John McNamara, jmcnamara@cpan.org # use strict; use warnings; use Spreadsheet::ParseExcel; use Test::More tests => 76; ############################################################################### # # Tests setup. # my $file = 't/excel_files/worksheet_01.xls'; my $parser = Spreadsheet::ParseExcel->new(); my $workbook = $parser->Parse($file); my $worksheet; my $got_1; my $got_2; my $expected_1; my $expected_2; my $caption; ############################################################################### # # Test 1, 2 # $caption = "Test cell value"; $worksheet = $workbook->worksheet('Sheet2'); $expected_1 = 'This sheet has:'; $got_1 = $worksheet->{Cells}->[0]->[0]->value(); $got_2 = $worksheet->get_cell( 0, 0 )->value(); $caption = " \tWorksheet regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_1, $caption ); ############################################################################### # # Test 3, 4. # $caption = "Test worksheet name"; $worksheet = $workbook->worksheet('Sheet2'); $expected_1 = 'Sheet2'; $got_1 = $worksheet->{Name}; $got_2 = $worksheet->get_name(); $caption = " \tWorksheet regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_1, $caption ); ############################################################################### # # Test 5, 6. # $caption = "Test row range"; $worksheet = $workbook->worksheet('Sheet2'); $expected_1 = 0; $expected_2 = 35; $got_1 = ( $worksheet->row_range() )[0]; $got_2 = ( $worksheet->row_range() )[1]; $caption = " \tWorksheet regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_2, $caption ); ############################################################################### # # Test 7, 8. # $caption = "Test col range"; $worksheet = $workbook->worksheet('Sheet2'); $expected_1 = 0; $expected_2 = 9; $got_1 = ( $worksheet->col_range() )[0]; $got_2 = ( $worksheet->col_range() )[1]; $caption = " \tWorksheet regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_2, $caption ); ############################################################################### # # Test 9, 10. # $caption = "Test worksheet number"; $worksheet = $workbook->worksheet('Sheet2'); $expected_1 = 1; $got_1 = $worksheet->{_SheetNo}; $got_2 = $worksheet->sheet_num(); $caption = " \tWorksheet regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_1, $caption ); ############################################################################### # # Test 11, 12. # $caption = "Test default row height"; $worksheet = $workbook->worksheet('Sheet2'); $expected_1 = 21; $got_1 = $worksheet->{DefRowHeight}; $got_2 = $worksheet->get_default_row_height; $caption = " \tWorksheet regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_1, $caption ); ############################################################################### # # Test 13, 14. # $caption = "Test default column width"; $worksheet = $workbook->worksheet('Sheet2'); $expected_1 = 8.43; $got_1 = $worksheet->{DefColWidth}; $got_2 = $worksheet->get_default_col_width; $caption = " \tWorksheet regression: " . $caption; _is_float( $got_1, $expected_1, $caption ); _is_float( $got_2, $expected_1, $caption ); ############################################################################### # # Test 15, 16. # $caption = "Test row '3' height"; $worksheet = $workbook->worksheet('Sheet2'); $expected_1 = 48.75; $got_1 = $worksheet->{RowHeight}->[2]; $got_2 = ( $worksheet->get_row_heights() )[2]; $caption = " \tWorksheet regression: " . $caption; _is_float( $got_1, $expected_1, $caption ); _is_float( $got_2, $expected_1, $caption ); ############################################################################### # # Test 17, 18. # $caption = "Test column 'A' width"; $worksheet = $workbook->worksheet('Sheet2'); $expected_1 = 31; $got_1 = $worksheet->{ColWidth}->[0]; $got_2 = ( $worksheet->get_col_widths() )[0]; $caption = " \tWorksheet regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_1, $caption ); ############################################################################### # # Test 19, 20. # $caption = "Test landscape print setting"; $worksheet = $workbook->worksheet('Sheet2'); $expected_1 = 0; $got_1 = $worksheet->{Landscape}; $got_2 = $worksheet->is_portrait(); $caption = " \tWorksheet regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_1, $caption ); ############################################################################### # # Test 21, 22. # $caption = "Test print scale"; $worksheet = $workbook->worksheet('Sheet2'); $expected_1 = 75; $got_1 = $worksheet->{Scale}; $got_2 = $worksheet->get_print_scale(); $caption = " \tWorksheet regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_1, $caption ); ############################################################################### # # Test 23, 24. Note, use Sheet3 for counter example. # $caption = "Test print fit to page"; $worksheet = $workbook->worksheet('Sheet3'); $expected_1 = 1; $got_1 = $worksheet->{PageFit}; $expected_2 = '2x3'; $got_2 = join 'x', $worksheet->get_fit_to_pages(); $caption = " \tWorksheet regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_2, $caption ); ############################################################################### # # Test 25, 26. Note, use Sheet3 for counter example. # $caption = "Test print fit to page width"; $worksheet = $workbook->worksheet('Sheet3'); $expected_1 = 2; $got_1 = $worksheet->{FitWidth}; $expected_2 = 2; $got_2 = ( $worksheet->get_fit_to_pages() )[0]; $caption = " \tWorksheet regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_2, $caption ); ############################################################################### # # Test 27, 28. Note, use Sheet3 for counter example. # $caption = "Test print fit to page height"; $worksheet = $workbook->worksheet('Sheet3'); $expected_1 = 3; $got_1 = $worksheet->{FitHeight}; $expected_2 = 3; $got_2 = ( $worksheet->get_fit_to_pages() )[1]; $caption = " \tWorksheet regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_2, $caption ); ############################################################################### # # Test 29, 30. # $caption = "Test paper size"; $worksheet = $workbook->worksheet('Sheet2'); $expected_1 = 11; $got_1 = $worksheet->{PaperSize}; $got_2 = $worksheet->get_paper(); $caption = " \tWorksheet regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_1, $caption ); ############################################################################### # # Test 31, 32. # $caption = "Test user defined start page for printing"; $worksheet = $workbook->worksheet('Sheet2'); $expected_1 = 1; $got_1 = $worksheet->{UsePage}; $expected_2 = 2; $got_2 = $worksheet->get_start_page(); $caption = " \tWorksheet regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_2, $caption ); ############################################################################### # # Test 33, 34. # $caption = "Test user defined start page for printing"; $worksheet = $workbook->worksheet('Sheet2'); $expected_1 = 2; $got_1 = $worksheet->{PageStart}; $got_2 = $worksheet->get_start_page(); $caption = " \tWorksheet regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_1, $caption ); ############################################################################### # # Test 35, 36. # $caption = "Test left margin"; $worksheet = $workbook->worksheet('Sheet2'); $expected_1 = 1.2; $got_1 = $worksheet->{LeftMargin}; $got_2 = $worksheet->get_margin_left(); $caption = " \tWorksheet regression: " . $caption; _is_float( $got_1, $expected_1, $caption ); _is_float( $got_2, $expected_1, $caption ); ############################################################################### # # Test 37, 38. # $caption = "Test right margin"; $worksheet = $workbook->worksheet('Sheet2'); $expected_1 = 1.4; $got_1 = $worksheet->{RightMargin}; $got_2 = $worksheet->get_margin_right(); $caption = " \tWorksheet regression: " . $caption; _is_float( $got_1, $expected_1, $caption ); _is_float( $got_2, $expected_1, $caption ); ############################################################################### # # Test 39, 40. # $caption = "Test top margin"; $worksheet = $workbook->worksheet('Sheet2'); $expected_1 = 1.1; $got_1 = $worksheet->{TopMargin}; $got_2 = $worksheet->get_margin_top(); $caption = " \tWorksheet regression: " . $caption; _is_float( $got_1, $expected_1, $caption ); _is_float( $got_2, $expected_1, $caption ); ############################################################################### # # Test 41, 42. # $caption = "Test bottom margin"; $worksheet = $workbook->worksheet('Sheet2'); $expected_1 = 1.5; $got_1 = $worksheet->{BottomMargin}; $got_2 = $worksheet->get_margin_bottom(); $caption = " \tWorksheet regression: " . $caption; _is_float( $got_1, $expected_1, $caption ); _is_float( $got_2, $expected_1, $caption ); ############################################################################### # # Test 43, 44. # $caption = "Test header margin"; $worksheet = $workbook->worksheet('Sheet2'); $expected_1 = 0.5; $got_1 = $worksheet->{HeaderMargin}; $got_2 = $worksheet->get_margin_header(); $caption = " \tWorksheet regression: " . $caption; _is_float( $got_1, $expected_1, $caption ); _is_float( $got_2, $expected_1, $caption ); ############################################################################### # # Test 45, 46. # $caption = "Test footer margin"; $worksheet = $workbook->worksheet('Sheet2'); $expected_1 = 1.6; $got_1 = $worksheet->{FooterMargin}; $got_2 = $worksheet->get_margin_footer(); $caption = " \tWorksheet regression: " . $caption; _is_float( $got_1, $expected_1, $caption ); _is_float( $got_2, $expected_1, $caption ); ############################################################################### # # Test 47, 48. # $caption = "Test center horizontally"; $worksheet = $workbook->worksheet('Sheet2'); $expected_1 = 1; $got_1 = $worksheet->{HCenter}; $got_2 = $worksheet->is_centered_horizontally(); $caption = " \tWorksheet regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_1, $caption ); ############################################################################### # # Test 49, 50. # $caption = "Test center vertically"; $worksheet = $workbook->worksheet('Sheet2'); $expected_1 = 1; $got_1 = $worksheet->{VCenter}; $got_2 = $worksheet->is_centered_vertically(); $caption = " \tWorksheet regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_1, $caption ); ############################################################################### # # Test 51, 52. # $caption = "Test header"; $worksheet = $workbook->worksheet('Sheet2'); $expected_1 = '&CThis is the header'; $got_1 = $worksheet->{Header}; $got_2 = $worksheet->get_header(); $caption = " \tWorksheet regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_1, $caption ); ############################################################################### # # Test 53, 54. # $caption = "Test Footer"; $worksheet = $workbook->worksheet('Sheet2'); $expected_1 = '<his is the footer'; $got_1 = $worksheet->{Footer}; $got_2 = $worksheet->get_footer(); $caption = " \tWorksheet regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_1, $caption ); ############################################################################### # # Test 55, 56. # $caption = "Test print with gridlines"; $worksheet = $workbook->worksheet('Sheet2'); $expected_1 = 1; $got_1 = $worksheet->{PrintGrid}; $got_2 = $worksheet->is_print_gridlines(); $caption = " \tWorksheet regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_1, $caption ); ############################################################################### # # Test 57, 58. # $caption = "Test print with row and column headers"; $worksheet = $workbook->worksheet('Sheet2'); $expected_1 = 1; $got_1 = $worksheet->{PrintHeaders}; $got_2 = $worksheet->is_print_row_col_headers(); $caption = " \tWorksheet regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_1, $caption ); ############################################################################### # # Test 59, 60. # $caption = "Test print in black and white"; $worksheet = $workbook->worksheet('Sheet2'); $expected_1 = 1; $got_1 = $worksheet->{NoColor}; $got_2 = $worksheet->is_print_black_and_white(); $caption = " \tWorksheet regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_1, $caption ); ############################################################################### # # Test 61, 62. # $caption = "Test print in draft quality"; $worksheet = $workbook->worksheet('Sheet2'); $expected_1 = 1; $got_1 = $worksheet->{Draft}; $got_2 = $worksheet->is_print_draft(); $caption = " \tWorksheet regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_1, $caption ); ############################################################################### # # Test 63, 64. # $caption = "Test print comments"; $worksheet = $workbook->worksheet('Sheet2'); $expected_1 = 1; $got_1 = $worksheet->{Notes}; $got_2 = $worksheet->is_print_comments(); $caption = " \tWorksheet regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_1, $caption ); ############################################################################### # # Test 65, 66. # $caption = "Test print over then down"; $worksheet = $workbook->worksheet('Sheet2'); $expected_1 = 1; $got_1 = $worksheet->{LeftToRight}; $got_2 = $worksheet->get_print_order(); $caption = " \tWorksheet regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_1, $caption ); ############################################################################### # # Test 67, 68. # $caption = "Test horizontal page breaks"; $worksheet = $workbook->worksheet('Sheet2'); $expected_1 = [6, 20]; $got_1 = $worksheet->{HPageBreak}; $got_2 = $worksheet->get_h_pagebreaks(); $caption = " \tWorksheet regression: " . $caption; is_deeply( $got_1, $expected_1, $caption ); is_deeply( $got_2, $expected_1, $caption ); ############################################################################### # # Test 69, 70. # $caption = "Test vertical page breaks"; $worksheet = $workbook->worksheet('Sheet2'); $expected_1 = [2]; $got_1 = $worksheet->{VPageBreak}; $got_2 = $worksheet->get_v_pagebreaks(); $caption = " \tWorksheet regression: " . $caption; is_deeply( $got_1, $expected_1, $caption ); is_deeply( $got_2, $expected_1, $caption ); ############################################################################### # # Test 71, 72. # $caption = "Test merged areas"; $worksheet = $workbook->worksheet('Sheet2'); $expected_1 = [ [29, 1, 30, 4] ]; $got_1 = $worksheet->{MergedArea}; $got_2 = $worksheet->get_merged_areas(); $caption = " \tWorksheet regression: " . $caption; is_deeply( $got_1, $expected_1, $caption ); is_deeply( $got_2, $expected_1, $caption ); ############################################################################### # # Test 73, 74. # $caption = "Test hidden row 34"; $worksheet = $workbook->worksheet('Sheet2'); $expected_1 = 21; $got_1 = $worksheet->{RowHeight}->[33]; $got_2 = ( $worksheet->get_row_heights() )[33]; $caption = " \tWorksheet regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_1, $caption ); ############################################################################### # # Test 75, 76. # $caption = "Test column hidden 'A' width"; $worksheet = $workbook->worksheet('Sheet2'); $expected_1 = 10.71; $got_1 = $worksheet->{ColWidth}->[7]; $got_2 = ( $worksheet->get_col_widths() )[7]; $caption = " \tWorksheet regression: " . $caption; _is_float( $got_1, $expected_1, $caption ); _is_float( $got_2, $expected_1, $caption ); ############################################################################### # # _is_float() # # Helper function for float comparison. This is mainly to prevent failing tests # on 64bit systems with extended doubles where the 128bit precision is compared # against Excel's 64bit precision. # sub _is_float { my ( $got, $expected, $caption ) = @_; my $max = 1; $max = abs($got) if abs($got) > $max; $max = abs($expected) if abs($expected) > $max; if ( abs( $got - $expected ) <= 1e-15 * $max ) { ok( 1, $caption ); } else { is( $got, $expected, $caption ); } } __END__ Spreadsheet-ParseExcel-0.66/t/excel_files/000755 000765 000024 00000000000 14543415025 020536 5ustar00Johnstaff000000 000000 Spreadsheet-ParseExcel-0.66/t/20_number_format_default.t000644 000765 000024 00000010264 11247565351 023317 0ustar00Johnstaff000000 000000 #!/usr/bin/perl -w ############################################################################### # # A test for Spreadsheet::ParseExcel. # # Tests for default number format handling using FmtExcel(). See note below. # # reverse('�'), January 2009, John McNamara, jmcnamara@cpan.org # use strict; use Spreadsheet::ParseExcel::Utility 'ExcelFmt'; use Test::More tests => 47; ############################################################################### # # Test cases for default Excel formats. The hex "Index" number is the internal # index used by Excel. The tests are sorted by category rather than index. # my @testcases = ( # No, Index,Number, Expected, Format string, TODO note (if any). [ 1, 0x00, 1234.567, '1234.567', 'General' ], [ 2, 0x01, 1234.567, '1235', '0' ], [ 3, 0x02, 1234.567, '1234.57', '0.00' ], [ 4, 0x03, 1234.567, '1,235', '#,##0' ], [ 5, 0x04, 1234.567, '1,234.57', '#,##0.00' ], [ 6, 0x05, 1234.567, '$1,235', '($#,##0_);($#,##0)' ], [ 7, 0x05, -1234.567, '-$1,235', '($#,##0_);($#,##0)' ], [ 8, 0x06, 1234.567, '$1,235', '($#,##0_);[Red]($#,##0)' ], [ 9, 0x06, -1234.567, '-$1,235', '($#,##0_);[Red]($#,##0)' ], [ 10, 0x07, 1234.567, '$1,234.57', '($#,##0.00_);($#,##0.00)' ], [ 11, 0x07, -1234.567, '-$1,234.57', '($#,##0.00_);($#,##0.00)' ], [ 12, 0x08, 1234.567, '$1,234.57', '($#,##0.00_);[Red]($#,##0.00)' ], [ 13, 0x08, -1234.567, '-$1,234.57', '($#,##0.00_);[Red]($#,##0.00)' ], [ 14, 0x25, 1234.567, '1,235', '(#,##0_);(#,##0)' ], [ 15, 0x25, -1234.567, '-1,235', '(#,##0_);(#,##0)' ], [ 16, 0x26, 1234.567, '1,235', '(#,##0_);[Red](#,##0)' ], [ 17, 0x26, -1234.567, '-1,235', '(#,##0_);[Red](#,##0)' ], [ 18, 0x27, 1234.567, '1,234.57', '(#,##0.00_);(#,##0.00)' ], [ 19, 0x27, -1234.567, '-1,234.57', '(#,##0.00_);(#,##0.00)' ], [ 20, 0x28, 1234.567, '1,234.57', '(#,##0.00_);[Red](#,##0.00)' ], [ 21, 0x28, -1234.567, '-1,234.57', '(#,##0.00_);[Red](#,##0.00)' ], [ 22, 0x29, 1234.567, '1,235', '_(* #,##0_);_(* (#,##0);_(* "-"_);_(@_)' ], [ 23, 0x29, -1234.567, '-1,235', '_(* #,##0_);_(* (#,##0);_(* "-"_);_(@_)' ], [ 24, 0x2A, 1234.567, '$ 1,235', '_($* #,##0_);_($* (#,##0);_($* "-"_);_(@_)' ], [ 25, 0x2A, -1234.567, '-$ 1,235', '_($* #,##0_);_($* (#,##0);_($* "-"_);_(@_)' ], [ 26, 0x2B, 1234.567, '1,234.57', '_(* #,##0.00_);_(* (#,##0.00);_(* "-"??_);_(@_)' ], [ 27, 0x2B, -1234.567, '- 1,234.57', '_(* #,##0.00_);_(* (#,##0.00);_(* "-"??_);_(@_)', 'TODO: Minor difference.' ], [ 28, 0x2C, 1234.567, '$ 1,234.57', '_($* #,##0.00_);_($* (#,##0.00);_($* "-"??_);_(@_)' ], [ 29, 0x0E, 37653.521, '2/1/03', 'm/d/yy' ], [ 30, 0x0F, 37653.521, '1-Feb-03', 'd-mmm-yy' ], [ 31, 0x10, 37653.521, '1-Feb', 'd-mmm' ], [ 32, 0x11, 37653.521, 'Feb-03', 'mmm-yy' ], [ 33, 0x12, 37653.521, '12:30 PM', 'h:mm AM/PM' ], [ 34, 0x13, 37653.521, '12:30:14 PM', 'h:mm:ss AM/PM' ], [ 35, 0x14, 37653.521, '12:30', 'h:mm' ], [ 36, 0x15, 37653.521, '12:30:14', 'h:mm:ss' ], [ 37, 0x16, 37653.521, '2/1/03 12:30', 'm/d/yy h:mm' ], [ 38, 0x2D, 37653.521, '30:14', 'mm:ss' ], [ 39, 0x2E, 3.0141204, '72:20:20', '[h]:mm:ss'], [ 40, 0x2F, 37653.521, '30:14.4', 'mm:ss.0' ], [ 41, 0x30, 1234.567, '1.2E+3', '##0.0E+0' ], [ 42, 0x31, 1234.567, '1234.567', '@' ], [ 43, 0x09, 0.567, '57%', '0%' ], [ 44, 0x0A, 0.567, '56.70%', '0.00%' ], [ 45, 0x0B, 1234.567, '1.23E+03', '0.00E+00' ], [ 46, 0x0C, 0.75, '3/4', '# ?/?' ], [ 47, 0x0D, 0.3125, '5/16', '# ??/??' ], ); ############################################################################### # # Run tests. # for my $test_ref (@testcases) { my $number = $test_ref->[2]; my $expected = $test_ref->[3]; my $format = $test_ref->[4]; my $got = ExcelFmt( $format, $number ); local $TODO = $test_ref->[5] if defined $test_ref->[5]; is( $got, $expected, " \tFormat = $format" ); } __END__ Spreadsheet-ParseExcel-0.66/t/42_test95-97j-2.t000755 000765 000024 00000005275 11250061400 020647 0ustar00Johnstaff000000 000000 #!perl -w use strict; use Test::More tests => 66; use utf8; use Encode qw(encode); use Spreadsheet::ParseExcel; use Spreadsheet::ParseExcel::FmtJapan; my $xl = Spreadsheet::ParseExcel->new(); my $fmtj = Spreadsheet::ParseExcel::FmtJapan->new(encoding => 'sjis'); foreach my $xls(qw(Test95J.xls Test97J.xls)){ my $book = $xl->Parse("t/excel_files/$xls", $fmtj); ok $book, "load $xls"; my $sheet = $book->worksheet(0); is $sheet->{Name}, 'Sheet1-ASC', '1. ASCII name'; my @expected = ( [ASC => q{This Data is 'ASC Only'}], [Date => q{1964/3/23}], [INTEGER => 12345], [Float => 1.29], [Double => 1234567.89012345], [Formula => 1246912.89012345], [Data => 1234567.89], ['BIG INTEGER' => 123456789012], ); #binmode STDOUT, ':encoding(cp932)'; my($rmin, $rmax) = $sheet->row_range(); my($cmin, $cmax) = $sheet->col_range(); for my $i($rmin .. $rmax){ for my $j($cmin .. $cmax){ #print $sheet->get_cell($i, $j)->value, "\n"; my $cell = $sheet->get_cell($i, $j); my $got = $cell->value; my $expected = $expected[$i][$j]; my $caption = "[$i, $j]"; if ($expected =~ /\d\.\d+/) { _is_float($got, $expected, $caption); } else { is $got, $expected, $caption; } } } $sheet = $book->worksheet(1); is $sheet->{Name}, encode(cp932 => '漢字名'), '2. Kanji name'; @expected = ( [ASC => q{This Data is 'ASC Only'}], [encode(cp932 => '漢字も入る') => encode(cp932 => '漢字のデータ')], [Date => q{1964/3/23}], [INTEGER => 12345], [Float => 1.29], [Double => 1234567.89012345], [Formula => 1246912.89012345], [Float => undef], ); ($rmin, $rmax) = $sheet->row_range(); ($cmin, $cmax) = $sheet->col_range(); for my $i($rmin .. $rmax){ for my $j($cmin .. $cmax){ #print $sheet->get_cell($i, $j)->value, "\n"; my $cell = $sheet->get_cell($i, $j); my $got = ref($cell) ? $cell->value : $cell; my $expected = $expected[$i][$j]; my $caption = "[$i, $j]"; if (defined $expected && $expected =~ /\d\.\d+/) { _is_float($got, $expected, $caption); } else { is $got, $expected, $caption; } } } } ############################################################################### # # _is_float() # # Helper function for float comparison. This is mainly to prevent failing tests # on 64bit systems with extended doubles where the 128bit precision is compared # against Excel's 64bit precision. # sub _is_float { my ( $got, $expected, $caption ) = @_; my $max = 1; $max = abs($got) if abs($got) > $max; $max = abs($expected) if abs($expected) > $max; if ( abs( $got - $expected ) <= 1e-15 * $max ) { ok( 1, $caption ); } else { is( $got, $expected, $caption ); } } Spreadsheet-ParseExcel-0.66/t/03_regression.t000644 000765 000024 00000015140 11247565351 021132 0ustar00Johnstaff000000 000000 #!/usr/bin/perl ############################################################################### # # A test for Spreadsheet::ParseExcel. # # Regression tests for Workbook properties and methods. # # The testcases comprise tests direct hash access (old methodology) and method # calls (>= version 0.50 methodology). # # reverse(''), January 2009, John McNamara, jmcnamara@cpan.org # use strict; use warnings; use Spreadsheet::ParseExcel; use Test::More tests => 16; ############################################################################### # # Tests setup. # my $file = 't/excel_files/worksheet_01.xls'; my $parser = Spreadsheet::ParseExcel->new(); my $workbook = $parser->Parse($file); my @worksheets; my $worksheet; my $got; my $expected; my $caption; ############################################################################### # # Test 1 Test worksheets() method. # $caption = "Test worksheet()"; @worksheets = $workbook->worksheets(); $got = join ' ', map { $_->get_name } @worksheets; $expected = 'Sheet1 Sheet2 Sheet3'; $caption = " \tWorkbook regression: " . $caption; is( $got, $expected, $caption ); ############################################################################### # # Test 2 Test deprecated Worksheets property. # $caption = "Test worksheet()"; @worksheets = @{ $workbook->{Worksheet} }; $got = join ' ', map { $_->get_name } @worksheets; $expected = 'Sheet1 Sheet2 Sheet3'; $caption = " \tWorkbook regression: " . $caption; is( $got, $expected, $caption ); ############################################################################### # # Test 3 Test worksheet() method. # $caption = "Test worksheet()"; $worksheet = $workbook->worksheet(1); $got = $worksheet->get_name(); $expected = 'Sheet2'; $caption = " \tWorkbook regression: " . $caption; is( $got, $expected, $caption ); ############################################################################### # # Test 4 Test worksheet() method. # $caption = "Test worksheet()"; $worksheet = $workbook->worksheet('Sheet3'); $got = $worksheet->get_name(); $expected = 'Sheet3'; $caption = " \tWorkbook regression: " . $caption; is( $got, $expected, $caption ); ############################################################################### # # Test 5 Test deprecated Worksheet() method # $caption = "Test worksheet()"; $worksheet = $workbook->Worksheet('Sheet3'); $got = $worksheet->get_name(); $expected = 'Sheet3'; $caption = " \tWorkbook regression: " . $caption; is( $got, $expected, $caption ); ############################################################################### # # Test 6 Test worksheet_count() method. # $caption = "Test worksheet_count()"; $got = $workbook->worksheet_count(); $expected = 3; $caption = " \tWorkbook regression: " . $caption; is( $got, $expected, $caption ); ############################################################################### # # Test 7 Test deprecated SheetCount property. # $caption = "Test worksheet_count()"; $got = $workbook->{SheetCount}; $expected = 3; $caption = " \tWorkbook regression: " . $caption; is( $got, $expected, $caption ); ############################################################################### # # Test 8 Test get_filename() method. # $caption = "Test get_filename()"; $got = $workbook->get_filename(); $expected = $file; $caption = " \tWorkbook regression: " . $caption; is( $got, $expected, $caption ); ############################################################################### # # Test 9 Test deprecated File property. # $caption = "Test get_filename()"; $got = $workbook->{File}; $expected = $file; $caption = " \tWorkbook regression: " . $caption; is( $got, $expected, $caption ); ############################################################################### # # Test 10 Test get_filename() method on a filehandle. # my $fh; open $fh, '<', $file; binmode $fh; $workbook = $parser->Parse($fh); $caption = "Test get_filename()"; $got = $workbook->get_filename(); $expected = undef; $caption = " \tWorkbook regression: " . $caption; is( $got, $expected, $caption ); ############################################################################### # # Test 11 Test get_print_areas() method. # $caption = "Test get_print_areas()"; $worksheet = $workbook->worksheet(0); $got = $workbook->get_print_areas(); $expected = [ undef, [ [ 0, 0, 14, 2 ] ], [ [ 0, 1, 65535, 1 ], [ 3, 4, 7, 6 ] ] ]; $caption = " \tWorkbook regression: " . $caption; is_deeply( $got, $expected, $caption ); ############################################################################### # # Test 12 Test deprecated PrintArea property. # $caption = "Test get_print_areas()"; $worksheet = $workbook->worksheet(0); $got = $workbook->{PrintArea}; $expected = [ undef, [ [ 0, 0, 14, 2 ] ], [ [ 0, 1, 65535, 1 ], [ 3, 4, 7, 6 ] ] ]; $caption = " \tWorkbook regression: " . $caption; is_deeply( $got, $expected, $caption ); ############################################################################### # # Test 13 Test get_print_titles() method. # $caption = "Test get_print_titles()"; $worksheet = $workbook->worksheet(0); $got = $workbook->get_print_titles(); $expected = [ undef, { 'Row' => [ [ 0, 1 ] ], 'Column' => [ [ 0, 2 ] ], }, { 'Row' => [], 'Column' => [ [ 0, 7 ] ], } ]; $caption = " \tWorkbook regression: " . $caption; is_deeply( $got, $expected, $caption ); ############################################################################### # # Test 14 Test deprecated PrintArea property. # $caption = "Test get_print_titles()"; $worksheet = $workbook->worksheet(0); $got = $workbook->{PrintTitle}; $expected = [ undef, { 'Row' => [ [ 0, 1 ] ], 'Column' => [ [ 0, 2 ] ], }, { 'Row' => [], 'Column' => [ [ 0, 7 ] ], } ]; $caption = " \tWorkbook regression: " . $caption; is_deeply( $got, $expected, $caption ); ############################################################################### # # Test 15 Test using_1904_date() method. # $caption = "Test using_1904_date()"; $got = $workbook->using_1904_date(); $expected = 0; $caption = " \tWorkbook regression: " . $caption; is( $got, $expected, $caption ); ############################################################################### # # Test 16 Test using_1904_date() method. # $workbook = $parser->Parse('t/excel_files/Dates1904.xls'); # File change. $caption = "Test using_1904_date()"; $got = $workbook->using_1904_date(); $expected = 1; $caption = " \tWorkbook regression: " . $caption; is( $got, $expected, $caption ); __END__ Spreadsheet-ParseExcel-0.66/t/04_regression.t000644 000765 000024 00000041024 11260573025 021123 0ustar00Johnstaff000000 000000 #!/usr/bin/perl ############################################################################### # # A test for Spreadsheet::ParseExcel. # # Regression tests for Worksheet properties and methods. # # The tests are mainly in pairs where direct hash access (old methodology) # is tested along with the method calls (>= version 0.50 methodology). # # The tests in this testsuite are mainly for default Worksheet properties. # See also 05_regression.t for testing of non-default properties. # # reverse(''), January 2009, John McNamara, jmcnamara@cpan.org # use strict; use warnings; use Spreadsheet::ParseExcel; use Test::More tests => 72; ############################################################################### # # Tests setup. # my $file = 't/excel_files/worksheet_01.xls'; my $parser = Spreadsheet::ParseExcel->new(); my $workbook = $parser->Parse($file); my $worksheet; my $got_1; my $got_2; my $expected_1; my $expected_2; my $caption; ############################################################################### # # Test 1, 2 # $caption = "Test cell value"; $worksheet = $workbook->worksheet('Sheet1'); $expected_1 = 'This is a test workbook for worksheet regression'; $got_1 = $worksheet->{Cells}->[0]->[0]->value(); $got_2 = $worksheet->get_cell( 0, 0 )->value(); $caption = " \tWorksheet regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_1, $caption ); ############################################################################### # # Test 3, 4. # $caption = "Test worksheet name"; $worksheet = $workbook->worksheet('Sheet1'); $expected_1 = 'Sheet1'; $got_1 = $worksheet->{Name}; $got_2 = $worksheet->get_name(); $caption = " \tWorksheet regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_1, $caption ); ############################################################################### # # Test 5, 6. # $caption = "Test row range"; $worksheet = $workbook->worksheet('Sheet1'); $expected_1 = 0; $expected_2 = 1; $got_1 = ( $worksheet->row_range() )[0]; $got_2 = ( $worksheet->row_range() )[1]; $caption = " \tWorksheet regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_2, $caption ); ############################################################################### # # Test 7, 8. # $caption = "Test col range"; $worksheet = $workbook->worksheet('Sheet1'); $expected_1 = 0; $expected_2 = 0; $got_1 = ( $worksheet->col_range() )[0]; $got_2 = ( $worksheet->col_range() )[1]; $caption = " \tWorksheet regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_2, $caption ); ############################################################################### # # Test 9, 10. # $caption = "Test worksheet number"; $worksheet = $workbook->worksheet('Sheet1'); $expected_1 = 0; $got_1 = $worksheet->{_SheetNo}; $got_2 = $worksheet->sheet_num(); $caption = " \tWorksheet regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_1, $caption ); ############################################################################### # # Test 11, 12. # $caption = "Test default row height"; $worksheet = $workbook->worksheet('Sheet1'); $expected_1 = 12.75; $got_1 = $worksheet->{DefRowHeight}; $got_2 = $worksheet->get_default_row_height; $caption = " \tWorksheet regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_1, $caption ); ############################################################################### # # Test 13, 14. # $caption = "Test default column width"; $worksheet = $workbook->worksheet('Sheet1'); $expected_1 = 8.43; $got_1 = $worksheet->{DefColWidth}; $got_2 = $worksheet->get_default_col_width; $caption = " \tWorksheet regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_1, $caption ); ############################################################################### # # Test 15, 16. # $caption = "Test row '1' height"; $worksheet = $workbook->worksheet('Sheet1'); $expected_1 = 12.75; $got_1 = $worksheet->{RowHeight}->[0]; $got_2 = ( $worksheet->get_row_heights() )[0]; $caption = " \tWorksheet regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_1, $caption ); ############################################################################### # # Test 17, 18. # $caption = "Test column 'A' width"; $worksheet = $workbook->worksheet('Sheet1'); $expected_1 = undef; $got_1 = $worksheet->{ColWidth}->[0]; $got_2 = ( $worksheet->get_col_widths() )[0]; $caption = " \tWorksheet regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_1, $caption ); ############################################################################### # # Test 19, 20. # $caption = "Test landscape print setting"; $worksheet = $workbook->worksheet('Sheet1'); $expected_1 = 1; $got_1 = $worksheet->{Landscape}; $got_2 = $worksheet->is_portrait(); $caption = " \tWorksheet regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_1, $caption ); ############################################################################### # # Test 21, 22. # $caption = "Test print scale"; $worksheet = $workbook->worksheet('Sheet1'); $expected_1 = 100; $got_1 = $worksheet->{Scale}; $got_2 = $worksheet->get_print_scale(); $caption = " \tWorksheet regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_1, $caption ); ############################################################################### # # Test 23, 24. Note, use Sheet3 for counter example. # $caption = "Test print fit to page"; $worksheet = $workbook->worksheet('Sheet1'); $expected_1 = 0; $got_1 = $worksheet->{PageFit}; $got_2 = $worksheet->get_fit_to_pages(); $caption = " \tWorksheet regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_1, $caption ); ############################################################################### # # Test 25, 26. Note, use Sheet3 for counter example. # $caption = "Test print fit to page width"; $worksheet = $workbook->worksheet('Sheet1'); $expected_1 = 1; $got_1 = $worksheet->{FitWidth}; $expected_2 = 0; $got_2 = ( $worksheet->get_fit_to_pages() )[0]; $caption = " \tWorksheet regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_2, $caption ); ############################################################################### # # Test 27, 28. Note, use Sheet3 for counter example. # $caption = "Test print fit to page height"; $worksheet = $workbook->worksheet('Sheet1'); $expected_1 = 1; $got_1 = $worksheet->{FitHeight}; $expected_2 = 0; $got_2 = ( $worksheet->get_fit_to_pages() )[1]; $caption = " \tWorksheet regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_2, $caption ); ############################################################################### # # Test 29, 30. Note, use Sheet3 for counter example. # $caption = "Test paper size"; $worksheet = $workbook->worksheet('Sheet1'); $expected_1 = 9; $got_1 = $worksheet->{PaperSize}; $got_2 = $worksheet->get_paper(); $caption = " \tWorksheet regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_1, $caption ); ############################################################################### # # Test 31, 32. # $caption = "Test user defined start page for printing"; $worksheet = $workbook->worksheet('Sheet1'); $expected_1 = 0; $got_1 = $worksheet->{UsePage}; $got_2 = $worksheet->get_start_page(); $caption = " \tWorksheet regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_1, $caption ); ############################################################################### # # Test 33, 34. # $caption = "Test user defined start page for printing"; $worksheet = $workbook->worksheet('Sheet1'); $expected_1 = 1; $got_1 = $worksheet->{PageStart}; $expected_2 = 0; $got_2 = $worksheet->get_start_page(); $caption = " \tWorksheet regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_2, $caption ); ############################################################################### # # Test 35, 36. # $caption = "Test left margin"; $worksheet = $workbook->worksheet('Sheet1'); $expected_1 = undef; $got_1 = $worksheet->{LeftMargin}; $got_2 = $worksheet->get_margin_left(); $caption = " \tWorksheet regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_1, $caption ); ############################################################################### # # Test 37, 38. # $caption = "Test right margin"; $worksheet = $workbook->worksheet('Sheet1'); $expected_1 = undef; $got_1 = $worksheet->{RightMargin}; $got_2 = $worksheet->get_margin_right(); $caption = " \tWorksheet regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_1, $caption ); ############################################################################### # # Test 39, 40. # $caption = "Test top margin"; $worksheet = $workbook->worksheet('Sheet1'); $expected_1 = undef; $got_1 = $worksheet->{TopMargin}; $got_2 = $worksheet->get_margin_top(); $caption = " \tWorksheet regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_1, $caption ); ############################################################################### # # Test 41, 42. # $caption = "Test bottom margin"; $worksheet = $workbook->worksheet('Sheet1'); $expected_1 = undef; $got_1 = $worksheet->{BottomMargin}; $got_2 = $worksheet->get_margin_bottom(); $caption = " \tWorksheet regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_1, $caption ); ############################################################################### # # Test 43, 44. # $caption = "Test header margin"; $worksheet = $workbook->worksheet('Sheet1'); $expected_1 = 0.5; $got_1 = $worksheet->{HeaderMargin}; $got_2 = $worksheet->get_margin_header(); $caption = " \tWorksheet regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_1, $caption ); ############################################################################### # # Test 45, 46. # $caption = "Test footer margin"; $worksheet = $workbook->worksheet('Sheet1'); $expected_1 = 0.5; $got_1 = $worksheet->{FooterMargin}; $got_2 = $worksheet->get_margin_footer(); $caption = " \tWorksheet regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_1, $caption ); ############################################################################### # # Test 47, 48. # $caption = "Test center horizontally"; $worksheet = $workbook->worksheet('Sheet1'); $expected_1 = 0; $got_1 = $worksheet->{HCenter}; $got_2 = $worksheet->is_centered_horizontally(); $caption = " \tWorksheet regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_1, $caption ); ############################################################################### # # Test 49, 50. # $caption = "Test center vertically"; $worksheet = $workbook->worksheet('Sheet1'); $expected_1 = 0; $got_1 = $worksheet->{VCenter}; $got_2 = $worksheet->is_centered_vertically(); $caption = " \tWorksheet regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_1, $caption ); ############################################################################### # # Test 51, 52. # $caption = "Test header"; $worksheet = $workbook->worksheet('Sheet1'); $expected_1 = undef; $got_1 = $worksheet->{Header}; $got_2 = $worksheet->get_header(); $caption = " \tWorksheet regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_1, $caption ); ############################################################################### # # Test 53, 54. # $caption = "Test Footer"; $worksheet = $workbook->worksheet('Sheet1'); $expected_1 = undef; $got_1 = $worksheet->{Footer}; $got_2 = $worksheet->get_footer(); $caption = " \tWorksheet regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_1, $caption ); ############################################################################### # # Test 55, 56. # $caption = "Test print with gridlines"; $worksheet = $workbook->worksheet('Sheet1'); $expected_1 = 0; $got_1 = $worksheet->{PrintGrid}; $got_2 = $worksheet->is_print_gridlines(); $caption = " \tWorksheet regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_1, $caption ); ############################################################################### # # Test 57, 58. # $caption = "Test print with row and column headers"; $worksheet = $workbook->worksheet('Sheet1'); $expected_1 = 0; $got_1 = $worksheet->{PrintHeaders}; $got_2 = $worksheet->is_print_row_col_headers(); $caption = " \tWorksheet regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_1, $caption ); ############################################################################### # # Test 59, 60. # $caption = "Test print in black and white"; $worksheet = $workbook->worksheet('Sheet1'); $expected_1 = 0; $got_1 = $worksheet->{NoColor}; $got_2 = $worksheet->is_print_black_and_white(); $caption = " \tWorksheet regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_1, $caption ); ############################################################################### # # Test 61, 62. # $caption = "Test print in draft quality"; $worksheet = $workbook->worksheet('Sheet1'); $expected_1 = 0; $got_1 = $worksheet->{Draft}; $got_2 = $worksheet->is_print_draft(); $caption = " \tWorksheet regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_1, $caption ); ############################################################################### # # Test 63, 64. # $caption = "Test print comments"; $worksheet = $workbook->worksheet('Sheet1'); $expected_1 = 0; $got_1 = $worksheet->{Notes}; $got_2 = $worksheet->is_print_comments(); $caption = " \tWorksheet regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_1, $caption ); ############################################################################### # # Test 65, 66. # $caption = "Test print over then down"; $worksheet = $workbook->worksheet('Sheet1'); $expected_1 = 0; $got_1 = $worksheet->{LeftToRight}; $got_2 = $worksheet->get_print_order(); $caption = " \tWorksheet regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_1, $caption ); ############################################################################### # # Test 67, 68. # $caption = "Test horizontal page breaks"; $worksheet = $workbook->worksheet('Sheet1'); $expected_1 = undef; $got_1 = $worksheet->{HPageBreak}; $got_2 = $worksheet->get_h_pagebreaks(); $caption = " \tWorksheet regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_1, $caption ); ############################################################################### # # Test 69, 70. # $caption = "Test vertical page breaks"; $worksheet = $workbook->worksheet('Sheet1'); $expected_1 = undef; $got_1 = $worksheet->{VPageBreak}; $got_2 = $worksheet->get_v_pagebreaks(); $caption = " \tWorksheet regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_1, $caption ); ############################################################################### # # Test 71, 72. # $caption = "Test merged areas"; $worksheet = $workbook->worksheet('Sheet1'); $expected_1 = undef; $got_1 = $worksheet->{MergedArea}; $got_2 = $worksheet->get_merged_areas(); $caption = " \tWorksheet regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_1, $caption ); __END__ Spreadsheet-ParseExcel-0.66/t/43_test2000J.t000755 000765 000024 00000001752 11247565351 020360 0ustar00Johnstaff000000 000000 #!perl -w use strict; use Test::More tests => 22; use Spreadsheet::ParseExcel; use Spreadsheet::ParseExcel::FmtJapan; use utf8; my $xl = Spreadsheet::ParseExcel->new(); my $fmtj = Spreadsheet::ParseExcel::FmtJapan->new(); my $book = $xl->Parse("t/excel_files/Test2000J.xls", $fmtj); ok $book, "load Test2000J-Nengo.xls"; my $sheet = $book->worksheet(0); my @expected = ( ['This is a test file for Japanese format', '', ''], [qw(明治 明治33年11月21日 M33.12.21)], [qw(大正 大正9年11月22日 T3.12.22)], [qw(昭和 昭和5年11月23日 S5.12.23)], [qw(平成 平成12年11月24日 H12.12.24)], [qw(日付 2009年7月1日 7月1日)], [qw(時刻 12時23分45秒 12時23分)], ); my($rmin, $rmax) = $sheet->row_range(); my($cmin, $cmax) = $sheet->col_range(); #binmode STDOUT, ':encoding(cp932)'; for my $i($rmin .. $rmax){ for my $j($cmin .. $cmax){ #print $sheet->get_cell($i, $j)->value, "\n"; is $sheet->get_cell($i, $j)->value, $expected[$i][$j], "[$i, $j]"; } } Spreadsheet-ParseExcel-0.66/t/32_charts.t000644 000765 000024 00000006314 11247565351 020243 0ustar00Johnstaff000000 000000 #!/usr/bin/perl ############################################################################### # # A test for Spreadsheet::ParseExcel. # # Tests for the SST with long strings over 2 CONTINUE blocks. # # reverse(''), January 2009, John McNamara, jmcnamara@cpan.org # use strict; use warnings; use Spreadsheet::ParseExcel; use Test::More tests => 24; ############################################################################### # # Tests setup. # my $parser; my $workbook; my $worksheet; my $file; my $cell; my $sheetname; my $cell_value; my $expected; my $caption1; my $caption2; ############################################################################### # # Chart 1. # $file = 't/excel_files/chart1.xls'; $parser = Spreadsheet::ParseExcel->new(); $workbook = $parser->Parse($file); for my $index ( 0 .. 2 ) { $worksheet = $workbook->worksheet($index); $sheetname = $worksheet->{Name}; $cell = $worksheet->get_cell( 0, 0 ); $cell_value = $cell->value(); $expected = 'Sheet' . ( $index + 1 ); $caption1 = " \tFile = $file, Sheet name = $expected"; $caption2 = " \t + $file, Cell value = $expected"; is( $sheetname, $expected, $caption1 ); is( $cell_value, $expected, $caption2 ); } ############################################################################### # # Chart 2. # $file = 't/excel_files/chart2.xls'; $parser = Spreadsheet::ParseExcel->new(); $workbook = $parser->Parse($file); for my $index ( 0 .. 2 ) { $worksheet = $workbook->worksheet($index); $sheetname = $worksheet->{Name}; $cell = $worksheet->get_cell( 0, 0 ); $cell_value = $cell->value(); $expected = 'Sheet' . ( $index + 1 ); $caption1 = " \tFile = $file, Sheet name = $expected"; $caption2 = " \t + $file, Cell value = $expected"; is( $sheetname, $expected, $caption1 ); is( $cell_value, $expected, $caption2 ); } ############################################################################### # # Chart 3. # $file = 't/excel_files/chart3.xls'; $parser = Spreadsheet::ParseExcel->new(); $workbook = $parser->Parse($file); for my $index ( 0 .. 2 ) { $worksheet = $workbook->worksheet($index); $sheetname = $worksheet->{Name}; $cell = $worksheet->get_cell( 0, 0 ); $cell_value = $cell->value(); $expected = 'Sheet' . ( $index + 1 ); $caption1 = " \tFile = $file, Sheet name = $expected"; $caption2 = " \t + $file, Cell value = $expected"; is( $sheetname, $expected, $caption1 ); is( $cell_value, $expected, $caption2 ); } ############################################################################### # # Chart 4. # $file = 't/excel_files/chart4.xls'; $parser = Spreadsheet::ParseExcel->new(); $workbook = $parser->Parse($file); for my $index ( 0 .. 2 ) { $worksheet = $workbook->worksheet($index); $sheetname = $worksheet->{Name}; $cell = $worksheet->get_cell( 0, 0 ); $cell_value = $cell->value(); $expected = 'Sheet' . ( $index + 1 ); $caption1 = " \tFile = $file, Sheet name = $expected"; $caption2 = " \t + $file, Cell value = $expected"; is( $sheetname, $expected, $caption1 ); is( $cell_value, $expected, $caption2 ); } __END__ Spreadsheet-ParseExcel-0.66/t/25_decode_rk_numbers.t000755 000765 000024 00000016247 11247565351 022444 0ustar00Johnstaff000000 000000 #!/usr/bin/perl -w ############################################################################### # # A test for Spreadsheet::ParseExcel. # # Tests for RK number decoding. # # reverse(''), August 2009, John McNamara, jmcnamara@cpan.org # use strict; use Spreadsheet::ParseExcel; use Test::More tests => 184; ############################################################################### # # The RK numbers and decoded values were extracted from Excel workboooks. # my @testcases = ( # RK Number Decoded number # Test cases from examples in the MS docs. [ 0x3FF00000, 1 ], [ 0x405EC001, 1.23 ], [ 0x02F1853A, 12345678 ], [ 0x02F1853B, 123456.78 ], [ 0xBFF00000, -1 ], [ 0xC05EC001, -1.23 ], [ 0xFD0E7ACA, -12345678 ], [ 0xFD0E7ACB, -123456.78 ], # Some simple user generated cases. [ 0x3FF00000, 1 ], [ 0x40000000, 2 ], [ 0x40080000, 3 ], [ 0x40100000, 4 ], [ 0x40140000, 5 ], [ 0x40180000, 6 ], [ 0x401C0000, 7 ], [ 0x40200000, 8 ], [ 0x40220000, 9 ], [ 0x40240001, 0.1 ], [ 0x40340001, 0.2 ], [ 0x403E0001, 0.3 ], [ 0x40440001, 0.4 ], [ 0x3FE00000, 0.5 ], [ 0x404E0001, 0.6 ], [ 0x40518001, 0.7 ], [ 0x40540001, 0.8 ], [ 0x40568001, 0.9 ], [ 0x3FF00001, 0.01 ], [ 0x40000001, 0.02 ], [ 0x40080001, 0.03 ], [ 0x40100001, 0.04 ], [ 0x40140001, 0.05 ], [ 0x40180001, 0.06 ], [ 0x401C0001, 0.07 ], [ 0x40200001, 0.08 ], [ 0x40220001, 0.09 ], [ 0x3FE00001, 0.005 ], [ 0xBFF00000, -1 ], [ 0xC0000000, -2 ], [ 0xC0080000, -3 ], [ 0xC0100000, -4 ], [ 0xC0140000, -5 ], [ 0xC0180000, -6 ], [ 0xC01C0000, -7 ], [ 0xC0200000, -8 ], [ 0xC0220000, -9 ], [ 0xC0240001, -0.1 ], [ 0xC0340001, -0.2 ], [ 0xC03E0001, -0.3 ], [ 0xC0440001, -0.4 ], [ 0xBFE00000, -0.5 ], [ 0xC04E0001, -0.6 ], [ 0xC0518001, -0.7 ], [ 0xC0540001, -0.8 ], [ 0xC0568001, -0.9 ], [ 0xBFF00001, -0.01 ], [ 0xC0000001, -0.02 ], [ 0xC0080001, -0.03 ], [ 0xC0100001, -0.04 ], [ 0xC0140001, -0.05 ], [ 0xC0180001, -0.06 ], [ 0xC01C0001, -0.07 ], [ 0xC0200001, -0.08 ], [ 0xC0220001, -0.09 ], [ 0xBFE00001, -0.005 ], # Testcases generated from single bit RK numbers. [ 0x3FF00001, 0.01 ], [ 0x40000001, 0.02 ], [ 0x40100001, 0.04 ], [ 0x40200001, 0.08 ], [ 0x40300001, 0.16 ], [ 0x40400001, 0.32 ], [ 0x40500001, 0.64 ], [ 0x3FF00000, 1 ], [ 0x40600001, 1.28 ], [ 0x40000000, 2 ], [ 0x40700001, 2.56 ], [ 0x40100000, 4 ], [ 0x40800001, 5.12 ], [ 0x40200000, 8 ], [ 0x40900001, 10.24 ], [ 0x40300000, 16 ], [ 0x40A00001, 20.48 ], [ 0x40400000, 32 ], [ 0x40B00001, 40.96 ], [ 0x40500000, 64 ], [ 0x40C00001, 81.92 ], [ 0x40600000, 128 ], [ 0x40D00001, 163.84 ], [ 0x40700000, 256 ], [ 0x40E00001, 327.68 ], [ 0x40800000, 512 ], [ 0x40F00001, 655.36 ], [ 0x40900000, 1024 ], [ 0x41000001, 1310.72 ], [ 0x40A00000, 2048 ], [ 0x41100001, 2621.44 ], [ 0x40B00000, 4096 ], [ 0x41200001, 5242.88 ], [ 0x40C00000, 8192 ], [ 0x41300001, 10485.76 ], [ 0x40D00000, 16384 ], [ 0x41400001, 20971.52 ], [ 0x40E00000, 32768 ], [ 0x41500001, 41943.04 ], [ 0x40F00000, 65536 ], [ 0x41600001, 83886.08 ], [ 0x41000000, 131072 ], [ 0x41700001, 167772.16 ], [ 0x41100000, 262144 ], [ 0x41800001, 335544.32 ], [ 0x41200000, 524288 ], [ 0x41900001, 671088.64 ], [ 0x41300000, 1048576 ], [ 0x41A00001, 1342177.28 ], [ 0x41400000, 2097152 ], [ 0x41B00001, 2684354.56 ], [ 0x41500000, 4194304 ], [ 0x41600000, 8388608 ], [ 0x41700000, 16777216 ], [ 0x41800000, 33554432 ], [ 0x41900000, 67108864 ], [ 0x41A00000, 134217728 ], [ 0x41B00000, 268435456 ], [ 0xC0000001, -0.02 ], [ 0xC0000000, -2 ], [ 0xC1B00001, -2684354.56 ], [ 0xC1B80001, -4026531.84 ], [ 0xC1BC0001, -4697620.48 ], [ 0xC1BE0001, -5033164.8 ], [ 0xC1BF0001, -5200936.96 ], [ 0xC1BF8001, -5284823.04 ], [ 0xC1BFC001, -5326766.08 ], [ 0xC1BFE001, -5347737.6 ], [ 0xC1BFF001, -5358223.36 ], [ 0xC1BFF801, -5363466.24 ], [ 0xC1BFFC01, -5366087.68 ], [ 0xC1BFFE01, -5367398.4 ], [ 0xC1BFFF01, -5368053.76 ], [ 0xC1BFFF81, -5368381.44 ], [ 0xC1BFFFC1, -5368545.28 ], [ 0xC1BFFFE1, -5368627.2 ], [ 0xC1BFFFF1, -5368668.16 ], [ 0xC1BFFFF9, -5368688.64 ], [ 0xC1BFFFFD, -5368698.88 ], [ 0xC1547AE0, -5368704 ], [ 0x80000403, -5368706.56 ], [ 0x80000203, -5368707.84 ], [ 0x80000103, -5368708.48 ], [ 0x80000083, -5368708.8 ], [ 0x80000043, -5368708.96 ], [ 0x80000023, -5368709.04 ], [ 0x80000013, -5368709.08 ], [ 0x8000000B, -5368709.1 ], [ 0x80000007, -5368709.11 ], [ 0xC1B00000, -268435456 ], [ 0xC1B80000, -402653184 ], [ 0xC1BC0000, -469762048 ], [ 0xC1BE0000, -503316480 ], [ 0xC1BF0000, -520093696 ], [ 0xC1BF8000, -528482304 ], [ 0xC1BFC000, -532676608 ], [ 0xC1BFE000, -534773760 ], [ 0xC1BFF000, -535822336 ], [ 0xC1BFF800, -536346624 ], [ 0xC1BFFC00, -536608768 ], [ 0xC1BFFE00, -536739840 ], [ 0xC1BFFF00, -536805376 ], [ 0xC1BFFF80, -536838144 ], [ 0xC1BFFFC0, -536854528 ], [ 0xC1BFFFE0, -536862720 ], [ 0xC1BFFFF0, -536866816 ], [ 0xC1BFFFF8, -536868864 ], [ 0xC1BFFFFC, -536869888 ], [ 0x80000802, -536870400 ], [ 0x80000402, -536870656 ], [ 0x80000202, -536870784 ], [ 0x80000102, -536870848 ], [ 0x80000082, -536870880 ], [ 0x80000042, -536870896 ], [ 0x80000022, -536870904 ], [ 0x80000012, -536870908 ], [ 0x8000000A, -536870910 ], [ 0x80000006, -536870911 ], # Some Max RK type 2 ints. [ 0x7FFFFFFE, 536870911 ], [ 0x80000006, -536870911 ], ); ############################################################################### # # Run tests. # my $parser = Spreadsheet::ParseExcel->new(); for my $test_ref (@testcases) { my $rk_number = $test_ref->[0]; my $expected = $test_ref->[1]; my $got = Spreadsheet::ParseExcel::_decode_rk_number($rk_number); is( $got, $expected); } __END__ Spreadsheet-ParseExcel-0.66/t/92_meta.t000644 000765 000024 00000001163 11247565351 017710 0ustar00Johnstaff000000 000000 #!/usr/bin/perl # Test that our META.yml file matches the specification use strict; BEGIN { $| = 1; $^W = 1; } my @MODULES = ( 'Test::CPAN::Meta 0.12', ); # Don't run tests during end-user installs use Test::More; unless ( $ENV{AUTOMATED_TESTING} or $ENV{RELEASE_TESTING} ) { plan( skip_all => "Author tests not required for installation" ); } # Load the testing modules foreach my $MODULE ( @MODULES ) { eval "use $MODULE"; if ( $@ ) { $ENV{RELEASE_TESTING} ? die( "Failed to load required release-testing module $MODULE" ) : plan( skip_all => "$MODULE not available for testing" ); } } meta_yaml_ok(); 1; Spreadsheet-ParseExcel-0.66/t/06_regression.t000644 000765 000024 00000020315 14543405670 021134 0ustar00Johnstaff000000 000000 #!/usr/bin/perl ############################################################################### # # A test for Spreadsheet::ParseExcel. # # Regression tests for Cell properties and methods. # # The tests are mainly in pairs where direct hash access (old methodology) # is tested along with the method calls (>= version 0.50 methodology). # # reverse(''), January 2009, John McNamara, jmcnamara@cpan.org # use strict; use warnings; use Spreadsheet::ParseExcel; use Test::More tests => 32; ############################################################################### # # Tests setup. # my $file = 't/excel_files/worksheet_01.xls'; my $parser = Spreadsheet::ParseExcel->new(); my $workbook = $parser->Parse($file); my $worksheet = $workbook->worksheet('Sheet3'); my $cell; my $format; my $got_1; my $got_2; my $expected_1; my $expected_2; my $caption; ############################################################################### # # Test 1, 2. Unformatted cell value. # $caption = "Test unformatted cell value"; $cell = $worksheet->get_cell( 2, 1 ); $expected_1 = 1; $got_1 = $cell->value(); $got_2 = $cell->Value(); $caption = " \tCell regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_1, $caption ); ############################################################################### # # Test 3, 4. Unformatted cell value from a formatted cell. # $caption = "Test unformatted cell value from a formatted cell"; $cell = $worksheet->get_cell( 3, 1 ); $expected_1 = 40177; $got_1 = $cell->unformatted(); $got_2 = $cell->{Val}; $caption = " \tCell regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_1, $caption ); ############################################################################### # # Test 5, 6. Formatted cell value. # $caption = "Test formatted cell value"; $cell = $worksheet->get_cell( 3, 1 ); $expected_1 = '2009/12/30'; $got_1 = $cell->value(); $got_2 = $cell->Value; $caption = " \tCell regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_1, $caption ); ############################################################################### # # Test 7, 8. Cell format. # $caption = "Test cell format"; $cell = $worksheet->get_cell( 3, 1 ); $expected_1 = 170; $got_1 = $cell->get_format()->{FmtIdx}; $got_2 = $cell->{Format}->{FmtIdx};; $caption = " \tCell regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_1, $caption ); ############################################################################### # # Test 9. Cell format. # $caption = "Test cell format string"; $cell = $worksheet->get_cell( 2, 1 ); $expected_1 = 'General'; # TODO. Probably should be '' or 'general'. $got_1 = $workbook->{FmtClass}->FmtString( $cell, $workbook ); $caption = " \tCell regression: " . $caption; is( $got_1, $expected_1, $caption ); ############################################################################### # # Test 10. Cell format. # $caption = "Test cell format string"; $cell = $worksheet->get_cell( 3, 1 ); $expected_1 = 'yyyy/mm/dd'; $got_1 = $workbook->{FmtClass}->FmtString( $cell, $workbook ); $caption = " \tCell regression: " . $caption; is( $got_1, $expected_1, $caption ); ############################################################################### # # Test 11, 12. Cell type. # $caption = "Test cell type = Text"; $cell = $worksheet->get_cell( 2, 0 ); $expected_1 = 'Text'; $got_1 = $cell->type(); $got_2 = $cell->{Type}; $caption = " \tCell regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_1, $caption ); ############################################################################### # # Test 13, 14. Cell type. # $caption = "Test cell type = Numeric"; $cell = $worksheet->get_cell( 2, 1 ); $expected_1 = 'Numeric'; $got_1 = $cell->type(); $got_2 = $cell->{Type}; $caption = " \tCell regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_1, $caption ); ############################################################################### # # Test 15, 16. Cell type. # $caption = "Test cell type = Date"; $cell = $worksheet->get_cell( 3, 1 ); $expected_1 = 'Date'; $got_1 = $cell->type(); $got_2 = $cell->{Type}; $caption = " \tCell regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_1, $caption ); ############################################################################### # # Test 17, 18. Cell string encoding. # $caption = "Test cell encoding = Ascii"; $cell = $worksheet->get_cell( 5, 0 ); $expected_1 = 1; $expected_2 = undef; $got_1 = $cell->encoding(); $got_2 = $cell->{Code}; $caption = " \tCell regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_2, $caption ); ############################################################################### # # Test 19, 20. Cell string encoding. # $caption = "Test cell encoding = Unicode"; $cell = $worksheet->get_cell( 5, 1 ); $expected_1 = 2; $expected_2 = 'ucs2'; $got_1 = $cell->encoding(); $got_2 = $cell->{Code}; $caption = " \tCell regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_2, $caption ); ############################################################################### # # Test 21, 22. Cell string encoding. # # Switch file to get native encoding from Excel 5 file. $file = 't/excel_files/Test95J.xls'; $parser = Spreadsheet::ParseExcel->new(); $workbook = $parser->Parse($file); $worksheet = $workbook->worksheet(0); $caption = "Test cell encoding = Native"; $cell = $worksheet->get_cell( 1, 0 ); $expected_1 = 3; $expected_2 = '_native_'; $got_1 = $cell->encoding(); $got_2 = $cell->{Code}; $caption = " \tCell regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_2, $caption ); # Switch back to main test worksheet. $file = 't/excel_files/worksheet_01.xls'; $parser = Spreadsheet::ParseExcel->new(); $workbook = $parser->Parse($file); $worksheet = $workbook->worksheet('Sheet3'); ############################################################################### # # Test 23, 24. Cell is un-merged. # $caption = "Test cell is un-merged"; $cell = $worksheet->get_cell( 6, 0 ); $expected_1 = undef; $got_1 = $cell->is_merged(); $got_2 = $cell->{Merged}; $caption = " \tCell regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_1, $caption ); ############################################################################### # # Test 25, 26. Cell is merged. # $caption = "Test cell is merged"; $cell = $worksheet->get_cell( 7, 0 ); $expected_1 = 1; $got_1 = $cell->is_merged(); $got_2 = $cell->{Merged}; $caption = " \tCell regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_1, $caption ); ############################################################################### # # Test 27, 28. Cell is merged. # $caption = "Test cell is merged"; $cell = $worksheet->get_cell( 7, 1 ); $expected_1 = 1; $got_1 = $cell->is_merged(); $got_2 = $cell->{Merged}; $caption = " \tCell regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_1, $caption ); ############################################################################### # # Test 29, 30. Cell is merged. # $caption = "Test cell is merged"; $cell = $worksheet->get_cell( 7, 1 ); $expected_1 = 1; $got_1 = $cell->is_merged(); $got_2 = $cell->{Merged}; $caption = " \tCell regression: " . $caption; is( $got_1, $expected_1, $caption ); is( $got_2, $expected_1, $caption ); ############################################################################### # # Test 31, 32. Cell contains Rich Text. # $caption = "Test cell containing rich text"; $cell = $worksheet->get_cell( 8, 0 ); $expected_1 = [ 10, 14, 19 ]; $got_1 = $cell->get_rich_text(); $got_2 = $cell->{Rich}; $caption = " \tCell regression: " . $caption; # Just test the indices and not the font objects. $got_1 = [ map { $_->[0] } @$got_1 ]; $got_2 = [ map { $_->[0] } @$got_2 ]; is_deeply( $got_1, $expected_1, $caption ); is_deeply( $got_2, $expected_1, $caption ); __END__ Spreadsheet-ParseExcel-0.66/t/30_sst_01.t000644 000765 000024 00000040340 11247565351 020063 0ustar00Johnstaff000000 000000 #!/usr/bin/perl ############################################################################### # # A test for Spreadsheet::ParseExcel. # # Tests for the SST with long strings over 2 CONTINUE blocks. # # reverse(''), January 2009, John McNamara, jmcnamara@cpan.org # use strict; use warnings; use Spreadsheet::ParseExcel; use Test::More tests => 40; ############################################################################### # # Tests setup. # my $parser; my $workbook; my $worksheet; my $file; my $cell; my $row; my $col; my $got; my $expected; my $caption; my $smiley = chr 0x263a; my $long_string_15k = ( 'x' x ( 15000 - 1 ) ) . 'z'; my $long_string_16k = ( 'x' x ( 16000 - 1 ) ) . 'z'; my $long_string_24k = ( 'x' x ( 24000 - 1 ) ) . 'z'; my $long_string_31k = ( 'x' x ( 31000 - 1 ) ) . 'z'; ############################################################################### ############################################################################### # # File 1. # $file = 't/excel_files/long_string1.xls'; $parser = Spreadsheet::ParseExcel->new(); $workbook = $parser->Parse($file); $worksheet = $workbook->worksheet(0); ############################################################################### # # Test 1. # $row = 0; $col = 0; $cell = $worksheet->get_cell( $row, $col ); $expected = $smiley . $long_string_16k; $got = $cell->value(); $caption = " \tSST: File = $file, Row = $row, Col = $col"; is( $got, $expected, $caption ); ############################################################################### # # Test 2. # $row = 1; $col = 0; $cell = $worksheet->get_cell( $row, $col ); $expected = 'Foo'; $got = $cell->value(); $caption = " \tSST: File = $file, Row = $row, Col = $col"; is( $got, $expected, $caption ); ############################################################################### # # Test 3. # $row = 2; $col = 0; $cell = $worksheet->get_cell( $row, $col ); $expected = $smiley; $got = $cell->value(); $caption = " \tSST: File = $file, Row = $row, Col = $col"; is( $got, $expected, $caption ); ############################################################################### # # Test 4. # $row = 3; $col = 0; $cell = $worksheet->get_cell( $row, $col ); $expected = 'This is a test string'; $got = $cell->value(); $caption = " \tSST: File = $file, Row = $row, Col = $col"; is( $got, $expected, $caption ); ############################################################################### # # Test 5. # $row = 4; $col = 0; $cell = $worksheet->get_cell( $row, $col ); $expected = "Smiley $smiley"; $got = $cell->value(); $caption = " \tSST: File = $file, Row = $row, Col = $col"; is( $got, $expected, $caption ); ############################################################################### ############################################################################### # # File 2. # $file = 't/excel_files/long_string2.xls'; $parser = Spreadsheet::ParseExcel->new(); $workbook = $parser->Parse($file); $worksheet = $workbook->worksheet(0); ############################################################################### # # Test 6. # $row = 0; $col = 0; $cell = $worksheet->get_cell( $row, $col ); $expected = $long_string_16k . $smiley; $got = $cell->value(); $caption = " \tSST: File = $file, Row = $row, Col = $col"; is( $got, $expected, $caption ); ############################################################################### # # Test 7. # $row = 1; $col = 0; $cell = $worksheet->get_cell( $row, $col ); $expected = 'Foo'; $got = $cell->value(); $caption = " \tSST: File = $file, Row = $row, Col = $col"; is( $got, $expected, $caption ); ############################################################################### # # Test 8. # $row = 2; $col = 0; $cell = $worksheet->get_cell( $row, $col ); $expected = $smiley; $got = $cell->value(); $caption = " \tSST: File = $file, Row = $row, Col = $col"; is( $got, $expected, $caption ); ############################################################################### # # Test 9. # $row = 3; $col = 0; $cell = $worksheet->get_cell( $row, $col ); $expected = 'This is a test string'; $got = $cell->value(); $caption = " \tSST: File = $file, Row = $row, Col = $col"; is( $got, $expected, $caption ); ############################################################################### # # Test 10. # $row = 4; $col = 0; $cell = $worksheet->get_cell( $row, $col ); $expected = "Smiley $smiley"; $got = $cell->value(); $caption = " \tSST: File = $file, Row = $row, Col = $col"; is( $got, $expected, $caption ); ############################################################################### ############################################################################### # # File 3. # $file = 't/excel_files/long_string3.xls'; $parser = Spreadsheet::ParseExcel->new(); $workbook = $parser->Parse($file); $worksheet = $workbook->worksheet(0); ############################################################################### # # Test 11. # $row = 0; $col = 0; $cell = $worksheet->get_cell( $row, $col ); $expected = $smiley . $long_string_24k; $got = $cell->value(); $caption = " \tSST: File = $file, Row = $row, Col = $col"; is( $got, $expected, $caption ); ############################################################################### # # Test 12. # $row = 1; $col = 0; $cell = $worksheet->get_cell( $row, $col ); $expected = 'Foo'; $got = $cell->value(); $caption = " \tSST: File = $file, Row = $row, Col = $col"; is( $got, $expected, $caption ); ############################################################################### # # Test 13. # $row = 2; $col = 0; $cell = $worksheet->get_cell( $row, $col ); $expected = $smiley; $got = $cell->value(); $caption = " \tSST: File = $file, Row = $row, Col = $col"; is( $got, $expected, $caption ); ############################################################################### # # Test 14. # $row = 3; $col = 0; $cell = $worksheet->get_cell( $row, $col ); $expected = 'This is a test string'; $got = $cell->value(); $caption = " \tSST: File = $file, Row = $row, Col = $col"; is( $got, $expected, $caption ); ############################################################################### # # Test 15. # $row = 4; $col = 0; $cell = $worksheet->get_cell( $row, $col ); $expected = "Smiley $smiley"; $got = $cell->value(); $caption = " \tSST: File = $file, Row = $row, Col = $col"; is( $got, $expected, $caption ); ############################################################################### ############################################################################### # # File 4. # $file = 't/excel_files/long_string4.xls'; $parser = Spreadsheet::ParseExcel->new(); $workbook = $parser->Parse($file); $worksheet = $workbook->worksheet(0); ############################################################################### # # Test 16. # $row = 0; $col = 0; $cell = $worksheet->get_cell( $row, $col ); $expected = $long_string_24k . $smiley; $got = $cell->value(); $caption = " \tSST: File = $file, Row = $row, Col = $col"; is( $got, $expected, $caption ); ############################################################################### # # Test 17. # $row = 1; $col = 0; $cell = $worksheet->get_cell( $row, $col ); $expected = 'Foo'; $got = $cell->value(); $caption = " \tSST: File = $file, Row = $row, Col = $col"; is( $got, $expected, $caption ); ############################################################################### # # Test 18. # $row = 2; $col = 0; $cell = $worksheet->get_cell( $row, $col ); $expected = $smiley; $got = $cell->value(); $caption = " \tSST: File = $file, Row = $row, Col = $col"; is( $got, $expected, $caption ); ############################################################################### # # Test 19. # $row = 3; $col = 0; $cell = $worksheet->get_cell( $row, $col ); $expected = 'This is a test string'; $got = $cell->value(); $caption = " \tSST: File = $file, Row = $row, Col = $col"; is( $got, $expected, $caption ); ############################################################################### # # Test 20. # $row = 4; $col = 0; $cell = $worksheet->get_cell( $row, $col ); $expected = "Smiley $smiley"; $got = $cell->value(); $caption = " \tSST: File = $file, Row = $row, Col = $col"; is( $got, $expected, $caption ); ############################################################################### ############################################################################### # # File 5. # $file = 't/excel_files/long_string5.xls'; $parser = Spreadsheet::ParseExcel->new(); $workbook = $parser->Parse($file); $worksheet = $workbook->worksheet(0); ############################################################################### # # Test 21. # $row = 0; $col = 0; $cell = $worksheet->get_cell( $row, $col ); $expected = $smiley . $long_string_31k; $got = $cell->value(); $caption = " \tSST: File = $file, Row = $row, Col = $col"; is( $got, $expected, $caption ); ############################################################################### # # Test 22. # $row = 1; $col = 0; $cell = $worksheet->get_cell( $row, $col ); $expected = 'Foo'; $got = $cell->value(); $caption = " \tSST: File = $file, Row = $row, Col = $col"; is( $got, $expected, $caption ); ############################################################################### # # Test 23. # $row = 2; $col = 0; $cell = $worksheet->get_cell( $row, $col ); $expected = $smiley; $got = $cell->value(); $caption = " \tSST: File = $file, Row = $row, Col = $col"; is( $got, $expected, $caption ); ############################################################################### # # Test 24. # $row = 3; $col = 0; $cell = $worksheet->get_cell( $row, $col ); $expected = 'This is a test string'; $got = $cell->value(); $caption = " \tSST: File = $file, Row = $row, Col = $col"; is( $got, $expected, $caption ); ############################################################################### # # Test 25. # $row = 4; $col = 0; $cell = $worksheet->get_cell( $row, $col ); $expected = "Smiley $smiley"; $got = $cell->value(); $caption = " \tSST: File = $file, Row = $row, Col = $col"; is( $got, $expected, $caption ); ############################################################################### ############################################################################### # # File 6. # $file = 't/excel_files/long_string6.xls'; $parser = Spreadsheet::ParseExcel->new(); $workbook = $parser->Parse($file); $worksheet = $workbook->worksheet(0); ############################################################################### # # Test 26. # $row = 0; $col = 0; $cell = $worksheet->get_cell( $row, $col ); $expected = $long_string_31k . $smiley; $got = $cell->value(); $caption = " \tSST: File = $file, Row = $row, Col = $col"; is( $got, $expected, $caption ); ############################################################################### # # Test 27. # $row = 1; $col = 0; $cell = $worksheet->get_cell( $row, $col ); $expected = 'Foo'; $got = $cell->value(); $caption = " \tSST: File = $file, Row = $row, Col = $col"; is( $got, $expected, $caption ); ############################################################################### # # Test 28. # $row = 2; $col = 0; $cell = $worksheet->get_cell( $row, $col ); $expected = $smiley; $got = $cell->value(); $caption = " \tSST: File = $file, Row = $row, Col = $col"; is( $got, $expected, $caption ); ############################################################################### # # Test 29. # $row = 3; $col = 0; $cell = $worksheet->get_cell( $row, $col ); $expected = 'This is a test string'; $got = $cell->value(); $caption = " \tSST: File = $file, Row = $row, Col = $col"; is( $got, $expected, $caption ); ############################################################################### # # Test 30. # $row = 4; $col = 0; $cell = $worksheet->get_cell( $row, $col ); $expected = "Smiley $smiley"; $got = $cell->value(); $caption = " \tSST: File = $file, Row = $row, Col = $col"; is( $got, $expected, $caption ); ############################################################################### ############################################################################### # # File 7. # $file = 't/excel_files/long_string7.xls'; $parser = Spreadsheet::ParseExcel->new(); $workbook = $parser->Parse($file); $worksheet = $workbook->worksheet(0); ############################################################################### # # Test 31. # $row = 0; $col = 0; $cell = $worksheet->get_cell( $row, $col ); $expected = $long_string_15k . $smiley . $long_string_15k; $got = $cell->value(); $caption = " \tSST: File = $file, Row = $row, Col = $col"; is( $got, $expected, $caption ); ############################################################################### # # Test 32. # $row = 1; $col = 0; $cell = $worksheet->get_cell( $row, $col ); $expected = 'Foo'; $got = $cell->value(); $caption = " \tSST: File = $file, Row = $row, Col = $col"; is( $got, $expected, $caption ); ############################################################################### # # Test 33. # $row = 2; $col = 0; $cell = $worksheet->get_cell( $row, $col ); $expected = $smiley; $got = $cell->value(); $caption = " \tSST: File = $file, Row = $row, Col = $col"; is( $got, $expected, $caption ); ############################################################################### # # Test 34. # $row = 3; $col = 0; $cell = $worksheet->get_cell( $row, $col ); $expected = 'This is a test string'; $got = $cell->value(); $caption = " \tSST: File = $file, Row = $row, Col = $col"; is( $got, $expected, $caption ); ############################################################################### # # Test 35. # $row = 4; $col = 0; $cell = $worksheet->get_cell( $row, $col ); $expected = "Smiley $smiley"; $got = $cell->value(); $caption = " \tSST: File = $file, Row = $row, Col = $col"; is( $got, $expected, $caption ); ############################################################################### ############################################################################### # # File 8. # $file = 't/excel_files/long_string8.xls'; $parser = Spreadsheet::ParseExcel->new(); $workbook = $parser->Parse($file); $worksheet = $workbook->worksheet(0); ############################################################################### # # Test 36. # $row = 0; $col = 0; $cell = $worksheet->get_cell( $row, $col ); $expected = $smiley . $long_string_15k . $smiley . $long_string_15k . $smiley; $got = $cell->value(); $caption = " \tSST: File = $file, Row = $row, Col = $col"; is( $got, $expected, $caption ); ############################################################################### # # Test 37. # $row = 1; $col = 0; $cell = $worksheet->get_cell( $row, $col ); $expected = 'Foo'; $got = $cell->value(); $caption = " \tSST: File = $file, Row = $row, Col = $col"; is( $got, $expected, $caption ); ############################################################################### # # Test 38. # $row = 2; $col = 0; $cell = $worksheet->get_cell( $row, $col ); $expected = $smiley; $got = $cell->value(); $caption = " \tSST: File = $file, Row = $row, Col = $col"; is( $got, $expected, $caption ); ############################################################################### # # Test 39. # $row = 3; $col = 0; $cell = $worksheet->get_cell( $row, $col ); $expected = 'This is a test string'; $got = $cell->value(); $caption = " \tSST: File = $file, Row = $row, Col = $col"; is( $got, $expected, $caption ); ############################################################################### # # Test 40. # $row = 4; $col = 0; $cell = $worksheet->get_cell( $row, $col ); $expected = "Smiley $smiley"; $got = $cell->value(); $caption = " \tSST: File = $file, Row = $row, Col = $col"; is( $got, $expected, $caption ); Spreadsheet-ParseExcel-0.66/t/21_number_format_user.t000644 000765 000024 00000020737 14543405670 022657 0ustar00Johnstaff000000 000000 #!/usr/bin/perl -w ############################################################################### # # A test for Spreadsheet::ParseExcel. # # Tests for number format handling using FmtExcel(). See note below. # # reverse('�'), January 2009, John McNamara, jmcnamara@cpan.org # use strict; use Spreadsheet::ParseExcel::Utility qw( ExcelFmt LocaltimeExcel ); use Test::More tests => 146; my $is_1904 = 1; ############################################################################### # # Test cases for special cases or user supplied format issues. # my @testcases = ( # No, Number, Expected, Format string, Todo # Test for invalid 12-hour clock values. # http://rt.cpan.org/Public/Bug/Display.html?id=41192 [ 1, 0.01023148, '12:14:44 AM', 'hh:mm:ss AM/PM' ], [ 2, 0.01024306, '12:14:45 AM', 'hh:mm:ss AM/PM' ], [ 3, 0.01025463, '12:14:46 AM', 'hh:mm:ss AM/PM' ], # Tests for upper case formats from OpenOffice.org. # http://rt.cpan.org/Public/Bug/Display.html?id=20526 # http://rt.cpan.org/Public/Bug/Display.html?id=31206 # http://rt.cpan.org/Public/Bug/Display.html?id=40307 [ 4, 37653.521, '2/1/03', 'M/D/YY' ], [ 5, 37653.521, '02/01/2003', 'MM/DD/YYYY' ], [ 6, 37653.521, '01/02/2003', 'DD/MM/YYYY' ], [ 7, 37653.521, '20030201', 'YYYYMMDD' ], [ 8, 37653.521, '2003-02-01', 'YYYY-MM-DD' ], [ 9, 0.01023148, '12:14:44 AM', 'HH:MM:SS AM/PM' ], # Tests for overflow hours and minutes formats. [ 10, 0.4, '9:36:00', '[h]:mm:ss' ], [ 11, 1.4, '33:36:00', '[h]:mm:ss' ], [ 12, 2.4, '57:36:00', '[h]:mm:ss' ], [ 13, 0.6, '14:24:00', '[h]:mm:ss' ], [ 14, 1.6, '38:24:00', '[h]:mm:ss' ], [ 15, 2.6, '62:24:00', '[h]:mm:ss' ], [ 16, 0.4, 9, '[h]' ], [ 17, 1.4, 33, '[h]' ], [ 18, 2.4, 57, '[h]' ], [ 19, 0.4, 576, '[mm]' ], [ 20, 1.4, 2016, '[mm]' ], [ 21, 2.4, 3456, '[mm]' ], # Formats that don't overflow. Counter examples of the above. [ 22, 0.4, '9:36:00', 'h:mm:ss' ], [ 23, 1.4, '9:36:00', 'h:mm:ss' ], [ 24, 2.4, '9:36:00', 'h:mm:ss' ], [ 25, 0.6, '14:24:00', 'h:mm:ss' ], [ 26, 1.6, '14:24:00', 'h:mm:ss' ], [ 27, 2.6, '14:24:00', 'h:mm:ss' ], # Test for the examples in the Utility.pm docs. [ 28, 1234.567, '$1,234.57', '$#,##0.00' ], [ 29, 36892.521, '1 Jan 2001 12:30 PM', 'd mmm yyyy h:mm AM/PM' ], [ 30, LocaltimeExcel( 0, 0, 0, 1, 0, 101 ), '1 Jan 2001', 'd mmm yyyy' ], # Tests for locale in format string. # http://rt.cpan.org/Public/Bug/Display.html?id=43638 [ 31, 39814, '1/1/09', 'm/d/yy;@' ], [ 32, 39845, '2/1/09', 'm/d/yy;@' ], [ 33, 39814, 'Jan-09', '[$-409]mmm-yy' ], [ 34, 39845, 'Feb-09', '[$-409]mmm-yy' ], # Tests for three part format strings. # http://rt.cpan.org/Public/Bug/Display.html?id=45009 [ 35, 5, '5.00', '0.00;(0.0);0%' ], [ 36, 0, '0%', '0.00;(0.0);0%' ], [ 37, -3, '-3.0', '0.00;(0.0);0%' ], # Tests for ignoring of all dots except the first in format strings. # http://rt.cpan.org/Public/Bug/Display.html?id=45502 [ 38, 3.5008, '3.5008 oz.', '#.####\ \o\z.' ], [ 39, 3.5008, '3.5.0.0.8', '#.#.#.#.#' ], # Tests for rounding. # http://rt.cpan.org/Public/Bug/Display.html?id=45626 [ 40, 0.05, '0.1', '0.0' ], [ 41, 0.15, '0.2', '0.0' ], [ 42, 0.25, '0.3', '0.0' ], [ 43, 0.35, '0.4', '0.0' ], [ 44, 0.45, '0.5', '0.0' ], [ 45, 0.55, '0.6', '0.0' ], [ 46, 0.65, '0.7', '0.0' ], [ 47, 0.75, '0.8', '0.0' ], [ 48, 0.85, '0.9', '0.0' ], [ 49, 0.95, '1.0', '0.0' ], [ 50, 0.005, '0.01', '0.00' ], [ 51, 0.015, '0.02', '0.00' ], [ 52, 0.025, '0.03', '0.00' ], [ 53, 0.035, '0.04', '0.00' ], [ 54, 0.045, '0.05', '0.00' ], [ 55, 0.055, '0.06', '0.00' ], [ 56, 0.065, '0.07', '0.00' ], [ 57, 0.075, '0.08', '0.00' ], [ 58, 0.085, '0.09', '0.00' ], [ 59, 0.095,, '0.10', '0.00' ], [ 60, 0.0005, '0.001', '0.000' ], [ 61, 0.0015, '0.002', '0.000' ], [ 62, 0.0025, '0.003', '0.000' ], [ 63, 0.0035, '0.004', '0.000' ], [ 64, 0.0045, '0.005', '0.000' ], [ 65, 0.0055, '0.006', '0.000' ], [ 66, 0.0065, '0.007', '0.000' ], [ 67, 0.0075, '0.008', '0.000' ], [ 68, 0.0085, '0.009', '0.000' ], [ 69, 0.0095, '0.010', '0.000' ], [ 70, 0.0005, '0.0005', '0.0000' ], [ 71, 0.0015, '0.0015', '0.0000' ], [ 72, 0.0025, '0.0025', '0.0000' ], [ 73, 0.0035, '0.0035', '0.0000' ], [ 74, 0.0045, '0.0045', '0.0000' ], [ 75, 0.0055, '0.0055', '0.0000' ], [ 76, 0.0065, '0.0065', '0.0000' ], [ 77, 0.0075, '0.0075', '0.0000' ], [ 78, 0.0085, '0.0085', '0.0000' ], [ 79, 0.0095, '0.0095', '0.0000' ], # Tests for valid dates. # http://rt.cpan.org/Public/Bug/Display.html?id=48831 [ 80, 2958465, '31/12/9999', 'dd/mm/yyyy' ], [ 81, 2958466, '2958466', 'dd/mm/yyyy' ], [ 82, 4030433048023, '4030433048023', 'dd/mm/yyyy' ], [ 83, -1, '-1', 'dd/mm/yyyy' ], [ 84, 2957003, '31/12/9999', 'dd/mm/yyyy', undef, $is_1904 ], [ 85, 2957004, '2957004', 'dd/mm/yyyy', undef, $is_1904], # Tests for real names for days and months. [ 86, 36528, 'Mon', 'ddd' ], [ 87, 36529, 'Tue', 'ddd' ], [ 88, 36530, 'Wed', 'ddd' ], [ 89, 36531, 'Thu', 'ddd' ], [ 90, 36532, 'Fri', 'ddd' ], [ 91, 36533, 'Sat', 'ddd' ], [ 92, 36534, 'Sun', 'ddd' ], [ 93, 36535, 'Monday', 'dddd' ], [ 94, 36536, 'Tuesday', 'dddd' ], [ 95, 36537, 'Wednesday', 'dddd' ], [ 96, 36538, 'Thursday', 'dddd' ], [ 97, 36539, 'Friday', 'dddd' ], [ 98, 36540, 'Saturday', 'dddd' ], [ 99, 36541, 'Sunday', 'dddd' ], [ 100, 36526, 'Jan', 'mmm' ], [ 101, 36557, 'Feb', 'mmm' ], [ 102, 36586, 'Mar', 'mmm' ], [ 103, 36617, 'Apr', 'mmm' ], [ 104, 36647, 'May', 'mmm' ], [ 105, 36678, 'Jun', 'mmm' ], [ 106, 36708, 'Jul', 'mmm' ], [ 107, 36739, 'Aug', 'mmm' ], [ 108, 36770, 'Sep', 'mmm' ], [ 109, 36800, 'Oct', 'mmm' ], [ 110, 36831, 'Nov', 'mmm' ], [ 111, 36861, 'Dec', 'mmm' ], [ 112, 36526, 'January', 'mmmm' ], [ 113, 36557, 'February', 'mmmm' ], [ 114, 36586, 'March', 'mmmm' ], [ 115, 36617, 'April', 'mmmm' ], [ 116, 36647, 'May', 'mmmm' ], [ 117, 36678, 'June', 'mmmm' ], [ 118, 36708, 'July', 'mmmm' ], [ 119, 36739, 'August', 'mmmm' ], [ 120, 36770, 'September', 'mmmm' ], [ 121, 36800, 'October', 'mmmm' ], [ 122, 36831, 'November', 'mmmm' ], [ 123, 36861, 'December', 'mmmm' ], [ 124, 36526, 'J', 'mmmmm' ], [ 125, 36557, 'F', 'mmmmm' ], [ 126, 36586, 'M', 'mmmmm' ], [ 127, 36617, 'A', 'mmmmm' ], [ 128, 36647, 'M', 'mmmmm' ], [ 129, 36678, 'J', 'mmmmm' ], [ 130, 36708, 'J', 'mmmmm' ], [ 131, 36739, 'A', 'mmmmm' ], [ 132, 36770, 'S', 'mmmmm' ], [ 133, 36800, 'O', 'mmmmm' ], [ 134, 36831, 'N', 'mmmmm' ], [ 135, 36861, 'D', 'mmmmm' ], [ 136, 1, 'Sun', 'ddd' ], [ 137, 127, 'Sun', 'ddd' ], [ 138, 36898, 'Sun', 'ddd' ], [ 139, 2958103,'Sun', 'ddd' ], # http://rt.cpan.org/Public/Bug/Display.html?id=60547 [ 140, 27400, '$27,400.00', '[$$-409]#,##0.00' ], [ 141, 826331.94, '826,331.94 руб.', '#,##0.00\ [$руб.-419]' ], [ 142, 826331.94, '826,331.94 RUR', '#,##0.00\ [$RUR]' ], # http://rt.cpan.org/Public/Bug/Display.html?id=93142 [ 143, 41700.18, 'Sunday, March 02, 2014', 'dddd, mmmm dd, yyyy' ], [ 144, 41700.18, 'Sunday, March 02, 2014', '[$-F800]dddd, mmmm dd, yyyy' ], # http://rt.cpan.org/Ticket/Display.html?id=47072 [ 145, 39814, '1/1/2009 12:00 AM', 'm/d/yyyy h:mm AM/PM' ], [ 146, '39813.999999994212963', '1/1/2009 12:00 AM', 'm/d/yyyy h:mm AM/PM' ], ); ############################################################################### # # Run tests. # for my $test_ref (@testcases) { my $number = $test_ref->[1]; my $expected = $test_ref->[2]; my $format = $test_ref->[3]; my $is_1904 = $test_ref->[5]; my $got = ExcelFmt( $format, $number, $is_1904 ); local $TODO = $test_ref->[4] if defined $test_ref->[4]; is( $got, $expected, " \t$number\t+ '$format'\t= $got" ); } __END__ Spreadsheet-ParseExcel-0.66/t/23_number_format_time.t000644 000765 000024 00000052767 11247565351 022652 0ustar00Johnstaff000000 000000 #!/usr/bin/perl -w ############################################################################### # # A test for Spreadsheet::ParseExcel. # # Tests for time number format handling using FmtExcel(). # # reverse(''), January 2009, John McNamara, jmcnamara@cpan.org # use strict; use Spreadsheet::ParseExcel::Utility 'ExcelFmt'; use Test::More tests => 98; ############################################################################## # # Test the time data generated in Excel. # while () { last if /^# stop/; # For debugging next unless /\S/; # Ignore blank lines next if /^#/; # Ignore comments if (/"DateTime">([^<]+)/) { my $date_time = $1; $date_time =~ s/1899-12-31T//; my $line = ; if ($line =~ /"Number">([^<]+)/) { my $number = 0 + $1; my $result = ExcelFmt('hh:mm:ss.000', $number); is($result, $date_time, " \tTime: $date_time"); } } } __DATA__ # Test data taken from Excel in XML format. 1899-12-31T00:00:00.000 0 1899-12-31T00:15:20.213 1.0650613425925924E-2 1899-12-31T00:16:48.290 1.1670023148148148E-2 1899-12-31T00:55:25.446 3.8488958333333337E-2 1899-12-31T01:02:46.891 4.3598275462962965E-2 1899-12-31T01:04:15.597 4.4624965277777782E-2 1899-12-31T01:09:40.889 4.8389918981481483E-2 1899-12-31T01:11:32.560 4.9682407407407404E-2 1899-12-31T01:30:19.169 6.2721863425925936E-2 1899-12-31T01:48:25.580 7.5296064814814809E-2 1899-12-31T02:03:31.919 8.5786099537037031E-2 1899-12-31T02:11:11.986 9.1110949074074077E-2 1899-12-31T02:24:37.095 0.10042934027777778 1899-12-31T02:35:07.220 0.1077224537037037 1899-12-31T02:45:12.109 0.11472348379629631 1899-12-31T03:06:39.990 0.12962951388888888 1899-12-31T03:08:08.251 0.13065105324074075 1899-12-31T03:19:12.576 0.13833999999999999 1899-12-31T03:29:42.574 0.14563164351851851 1899-12-31T03:37:30.813 0.1510510763888889 1899-12-31T04:14:38.231 0.1768313773148148 1899-12-31T04:16:28.559 0.17810832175925925 1899-12-31T04:17:58.222 0.17914608796296297 1899-12-31T04:21:41.794 0.18173372685185185 1899-12-31T04:56:35.792 0.2059698148148148 1899-12-31T05:25:14.885 0.22586672453703704 1899-12-31T05:26:05.724 0.22645513888888891 1899-12-31T05:46:44.068 0.24078782407407406 1899-12-31T05:48:01.141 0.2416798726851852 1899-12-31T05:53:52.315 0.24574438657407408 1899-12-31T06:14:48.580 0.26028449074074073 1899-12-31T06:46:15.738 0.28212659722222222 1899-12-31T07:31:20.407 0.31343063657407405 1899-12-31T07:58:33.754 0.33233511574074076 1899-12-31T08:07:43.130 0.33869363425925925 1899-12-31T08:29:11.091 0.35360059027777774 1899-12-31T09:08:15.328 0.380732962962963 1899-12-31T09:30:41.781 0.39631690972222228 1899-12-31T09:34:04.462 0.39866275462962958 1899-12-31T09:37:23.945 0.40097158564814817 1899-12-31T09:37:56.655 0.40135017361111114 1899-12-31T09:45:12.230 0.40639155092592594 1899-12-31T09:54:14.782 0.41267108796296298 1899-12-31T09:54:22.108 0.41275587962962962 1899-12-31T10:01:36.151 0.41777952546296299 1899-12-31T12:09:48.602 0.50681252314814818 1899-12-31T12:34:08.549 0.52371005787037039 1899-12-31T12:56:06.495 0.53896406249999995 1899-12-31T12:58:58.217 0.54095158564814816 1899-12-31T12:59:54.263 0.54160026620370372 1899-12-31T13:34:41.331 0.56575614583333333 1899-12-31T13:58:28.601 0.58227547453703699 1899-12-31T14:02:16.899 0.58491781249999997 1899-12-31T14:36:17.444 0.60853523148148148 1899-12-31T14:37:57.451 0.60969271990740748 1899-12-31T14:57:42.757 0.6234115393518519 1899-12-31T15:10:48.307 0.6325035532407407 1899-12-31T15:14:39.890 0.63518391203703706 1899-12-31T15:19:47.988 0.63874986111111109 1899-12-31T16:04:24.344 0.66972620370370362 1899-12-31T16:22:23.952 0.68222166666666662 1899-12-31T16:29:55.999 0.6874536921296297 1899-12-31T16:58:20.259 0.70717892361111112 1899-12-31T17:04:02.415 0.71113906250000003 1899-12-31T17:18:29.630 0.72117627314814825 1899-12-31T17:47:21.323 0.74121901620370367 1899-12-31T17:53:29.866 0.74548456018518516 1899-12-31T17:53:41.076 0.74561430555555563 1899-12-31T17:55:06.044 0.74659773148148145 1899-12-31T18:14:49.151 0.760291099537037 1899-12-31T18:17:45.738 0.76233493055555546 1899-12-31T18:29:59.700 0.77082986111111118 1899-12-31T18:33:21.233 0.77316241898148153 1899-12-31T19:14:24.673 0.80167445601851861 1899-12-31T19:17:12.816 0.80362055555555545 1899-12-31T19:23:36.418 0.80806039351851855 1899-12-31T19:46:25.908 0.82391097222222232 1899-12-31T20:07:47.314 0.83874206018518516 1899-12-31T20:31:37.603 0.85529633101851854 1899-12-31T20:39:57.770 0.86108530092592594 1899-12-31T20:50:17.067 0.86825309027777775 1899-12-31T21:02:57.827 0.87705818287037041 1899-12-31T21:23:05.519 0.891036099537037 1899-12-31T21:34:49.572 0.89918486111111118 1899-12-31T21:39:05.944 0.90215212962962965 1899-12-31T21:39:18.426 0.90229659722222222 1899-12-31T21:46:07.769 0.90703436342592603 1899-12-31T21:57:55.662 0.91522756944444439 1899-12-31T22:19:11.732 0.92999689814814823 1899-12-31T22:23:51.376 0.93323351851851843 1899-12-31T22:27:58.771 0.93609688657407408 1899-12-31T22:43:30.392 0.94687953703703709 1899-12-31T22:48:25.834 0.95029900462962968 1899-12-31T22:53:51.727 0.95407091435185187 1899-12-31T23:12:56.536 0.96732101851851848 1899-12-31T23:15:54.109 0.96937626157407408 1899-12-31T23:17:12.632 0.97028509259259266 1899-12-31T23:59:59.999 0.99999998842592586 Spreadsheet-ParseExcel-0.66/t/46_save_parser.t000755 000765 000024 00000003533 14543405670 021300 0ustar00Johnstaff000000 000000 #!perl -w use strict; use Test::More; eval "use Spreadsheet::WriteExcel; 1;" or plan( skip_all => "Spreadsheet::ParseExcel::SaveParser requires Spreadsheet::WriteExcel" ); use utf8; use Encode qw(encode); plan(tests => 7); use_ok ('Spreadsheet::ParseExcel::SaveParser'); use_ok ('Spreadsheet::WriteExcel'); my $xl_base_name = 't/excel_files/46_save_parser.xls'; my $xl_base = Spreadsheet::WriteExcel->new($xl_base_name); # testing merged cells # first, we need to generate excel file with merged cells my $worksheet = $xl_base->add_worksheet(); my $format = $xl_base->add_format( border => 6, valign => 'vcenter', align => 'center', ); $worksheet->merge_range('A1:B2', 'V & H', $format); $worksheet->merge_range('E5:H8', 'V & H', $format); $worksheet->fit_to_pages(1, 1); $xl_base->close; # parse excel and write modified file my $xl_parser = Spreadsheet::ParseExcel::SaveParser->new; my $template = $xl_parser->Parse($xl_base_name); # test writing data to merged cell $template->worksheet (0)->AddCell (4, 4, 'V & H mod'); my $workbook; { local $^W = 0; $workbook = $template->SaveAs ($xl_base_name . '.mod.xls'); } $workbook->close; # parse modified file and check for merged cell my $template_mod = $xl_parser->Parse ($xl_base_name . '.mod.xls'); my $worksheet_mod = $template_mod->worksheet (0); my $merged_areas = $worksheet_mod->get_merged_areas; ok scalar @$merged_areas == 2, 'merged areas count'; my @fit = $worksheet_mod->get_fit_to_pages; is_deeply (\@fit, [1, 1], 'fix for fit to pages'); #use Data::Dumper; #warn Dumper $merged_areas; # RowHeight is_deeply $merged_areas->[0], [0, 0, 1, 1]; is_deeply $merged_areas->[1], [4, 4, 7, 7], 'overwritten merged cell position'; ok $worksheet_mod->Cell (4, 4)->value eq 'V & H mod', 'overwritten merged cell value'; unlink $xl_base_name; unlink $xl_base_name . '.mod.xls'; 1; Spreadsheet-ParseExcel-0.66/t/02_parse-dates.t000644 000765 000024 00000006750 11251562267 021166 0ustar00Johnstaff000000 000000 #!/usr/bin/perl use strict; use warnings; BEGIN { delete @ENV{qw( LANG LC_ALL LC_DATE )}; } use Test::More tests => 151; use_ok ("Spreadsheet::ParseExcel"); my $bk; ok ($bk = Spreadsheet::ParseExcel::Workbook->Parse ("t/excel_files/Dates.xls"), "Open/parse Dates.xls"); ok (my @ws = @{$bk->{Worksheet}}, "Book has sheets"); is (scalar @ws, 1, "But just one"); my $ws = $ws[0]; ok (my $cells = $ws->{Cells}, "Worksheet has cells"); is ($ws->{Name}, "DateTest", "Worksheet label"); is ($ws->{MinRow}, 0, "Row start"); is ($ws->{MinCol}, 0, "Col start"); is ($ws->{MaxRow}, 6, "Row count"); is ($ws->{MaxCol}, 4, "Col count"); my @expect = (# Date Date Date Date Text [ 39668, "8-Aug", 20080808, "2008-08-08", "08/08/2008", "08 Aug 2008" ], [ 39672, "12-Aug", 20080812, "2008-08-12", "08/12/2008", "12 Aug 2008" ], [ 39790, "8-Dec", 20081208, "2008-12-08", "12/08/2008", "08 Dec 2008" ], [ 39673, "13-Aug", 20080813, "2008-08-13", "08/13/2008", "13 Aug 2008" ], ); # non given, ISO, type 14, US broken, Text-default my @format = (undef, "yyyymmdd", undef, "mm/dd/yyyy", undef); my @col = ("A".."E"); foreach my $row (0 .. 3) { foreach my $col (0 .. 4) { my $R = $row + 1; my $C = $col + 1; my $cell = ("A".."E")[$col].$R; ok (my $wc = $ws->{Cells}[$row][$col], "Cell $cell"); is ($wc->{Val}, $expect[$row][$col == 4 ? 5 : 0], "Base value for $cell"); is ($wc->Value, $expect[$row][$C], "Formatted value for $cell"); is ($wc->{Type}, $col == 4 ? "Text" : "Date", "Cell $cell Type"); my $fmt = $wc->{Format}; my $fmtstr = $bk->{FormatStr}{$fmt->{FmtIdx}}; $fmtstr and $fmtstr =~ s/\\//g; is ($fmtstr, $format[$col], "Format string"); } } # Additional allignment tests is ($ws->{Cells}[0][$_]{Format}{AlignV}, 3, "$col[$_]1 v-aligned justified") for 1..3; is ($ws->{Cells}[1][$_]{Format}{AlignV}, 0, "$col[$_]2 v-aligned top") for 1..3; is ($ws->{Cells}[2][$_]{Format}{AlignV}, 1, "$col[$_]3 v-aligned center") for 1..3; is ($ws->{Cells}[3][$_]{Format}{AlignV}, 2, "$col[$_]4 v-aligned bottom") for 1..3; is ($ws->{Cells}[$_][0]{Format}{AlignH}, 0, "A$_ h-aligned -") for 1..3; is ($ws->{Cells}[$_][1]{Format}{AlignH}, 1, "B$_ h-aligned left") for 1..3; is ($ws->{Cells}[$_][2]{Format}{AlignH}, 2, "C$_ h-aligned center") for 1..3; is ($ws->{Cells}[$_][3]{Format}{AlignH}, 3, "D$_ h-aligned right") for 1..3; # Additional color tests is ($ws->{Cells}[0][$_]{Format}{Font}{Color}, 32767, "$col[$_]1 font color") for 0..3; is ($ws->{Cells}[0][ 4]{Format}{Font}{Color}, 18, "E1 font color"); my %expect = ( B7 => [ 1, 6, 39673, "ddd, dd mmm yyyy", "Wed, 13 Aug 2008" ], C7 => [ 2, 6, 39673, "m-d-yy", "8-13-08" ], ); # Test ddd, dd MM yyyy foreach my $cell ("B7", "C7") { my ($c, $r) = @{$expect{$cell}}[0,1]; ok (my $wc = $ws->{Cells}[$r][$c], "Cell $cell"); ok (my $fmt = $wc->{Format}, "Format $cell"); ok (my $fmtstr = $bk->{FormatStr}{$fmt->{FmtIdx}}, "FmtStr $cell"); $fmtstr and $fmtstr =~ s{\\}{}g; # Unescape for test $fmtstr and $fmtstr =~ s{/}{-}g and $expect{$cell}[4] =~ s{-}{/}g; # System locale's deate-sep is used :( is ($wc->{Val}, $expect{$cell}[2], "$cell value"); is ($fmtstr, $expect{$cell}[3], "$cell Format string"); is ($wc->Value, $expect{$cell}[4], "$cell formatted value"); } Spreadsheet-ParseExcel-0.66/t/28_int2col.t000755 000765 000024 00000001677 11247565351 020350 0ustar00Johnstaff000000 000000 #!/usr/bin/perl -w ############################################################################### # # A test for Spreadsheet::ParseExcel. # # Tests for Utility int2col() and col2int() functions.. # # reverse(''), August 2009, John McNamara, jmcnamara@cpan.org # use strict; use Spreadsheet::ParseExcel::Utility qw( int2col col2int ); use Test::More tests => 3; ############################################################################## # # Tests. # my $col = 'A'; my @got_col; my @got_int; my @expected_col; my @expected_int; for my $int ( 0 .. 255 ) { $expected_col[$int] = $col; $expected_int[$int] = $int; $got_col[$int] = int2col($int); $got_int[$int] = col2int($col); $col++; } # General tests for full column range. is_deeply( \@got_col, \@expected_col ); is_deeply( \@got_int, \@expected_int ); # Test for int2col in list context. RT 48967 my ($got) = int2col(27); my $expected = 'AB'; is($got, $expected); __END__ Spreadsheet-ParseExcel-0.66/t/45_oem-2.t000755 000765 000024 00000001640 11247565351 017702 0ustar00Johnstaff000000 000000 #!perl -w use strict; use Test::More tests => 14; use utf8; use Encode qw(encode); use Spreadsheet::ParseExcel; use Spreadsheet::ParseExcel::FmtJapan; my $xl = Spreadsheet::ParseExcel->new(); my $fmtj = Spreadsheet::ParseExcel::FmtJapan->new(Code => 'sjis'); my $book = $xl->Parse("t/excel_files/TestEncoding.xls", $fmtj); ok $book, "load TestEncoding.xls"; my $sheet = $book->worksheet(0); my @expected = ( ['This is a test file for Japanese encoding'], [qw(ローマ数字 Ⅰ Ⅱ)], [qw(丸数字 ① ②)], [qw(年号 ㍻ ㍼)], [qw(その他 ㈱ ~)], ); my($rmin, $rmax) = $sheet->row_range(); my($cmin, $cmax) = $sheet->col_range(); #binmode STDOUT, ':encoding(cp932)'; for my $i($rmin .. $rmax){ for my $j($cmin .. $cmax){ my $cell = $sheet->get_cell($i, $j); next unless $cell && $cell->value; #print $cell->value, "\n"; is $cell->value, encode(cp932 => $expected[$i][$j]), "[$i, $j]"; } } Spreadsheet-ParseExcel-0.66/t/90_pod.t000644 000765 000024 00000001206 11247565351 017540 0ustar00Johnstaff000000 000000 #!/usr/bin/perl # Test that the syntax of our POD documentation is valid use strict; BEGIN { $| = 1; $^W = 1; } my @MODULES = ( 'Pod::Simple 3.07', 'Test::Pod 1.26', ); # Don't run tests during end-user installs use Test::More; unless ( $ENV{AUTOMATED_TESTING} or $ENV{RELEASE_TESTING} ) { plan( skip_all => "Author tests not required for installation" ); } # Load the testing modules foreach my $MODULE ( @MODULES ) { eval "use $MODULE"; if ( $@ ) { $ENV{RELEASE_TESTING} ? die( "Failed to load required release-testing module $MODULE" ) : plan( skip_all => "$MODULE not available for testing" ); } } all_pod_files_ok(); 1; Spreadsheet-ParseExcel-0.66/t/47_hyperlinks.t000644 000765 000024 00000006600 14543405670 021152 0ustar00Johnstaff000000 000000 #!/usr/bin/perl -w ############################################################################### # # A test for Spreadsheet::ParseExcel. # # Test for get_active_sheet # use strict; use Test::More tests => 45; use Spreadsheet::ParseExcel; ############################################################################## # # Tests. # my $parser = Spreadsheet::ParseExcel->new; # Workbook saved with sheet2 (index 1) open my $book = $parser->parse( "t/excel_files/TestActiveSheet.xls" ); my $active = $book->get_active_sheet; is($active, 1, 'Correct sheet'); my $ws = $book->worksheet('Sheet2'); my %expect = ( A3 => { }, # Each entry adds 6 tests A6 => { desc => q(http://www.example.com), link => q(http://www.example.com/), }, B6 => { desc => q(http://www.example.com#foo), link => q(http://www.example.com/#foo), }, C6 => { desc => q(file:///c:\\nodir\\nofile.txt), link => q(file:///c:\\nodir\\nofile.txt), }, D6 => { desc => q(\\\\server\\quirks\\sometest.bat), link => q(file:///\\\\server\\quirks\\sometest.bat), }, E6 => { desc => q(TestActiveSheet.xls), rel => 1, link => q(TestActiveSheet.xls), }, F6 => { desc => q(Sheet2!A7), link => q(#Sheet2%21A7), }, A7 => { desc => q(www.example.com), link => q(http://www.example.com/), }, B7 => { desc => q(www.example.com#foo), link => q(http://www.example.com/#foo), }, C7 => { desc => q(c:\\nodir\\nofile.txt), link => q(file:///c:\\nodir\\nofile.txt), }, D7 => { desc => q(SMB Link Sometest.bat), link => q(file:///\\\\server\\quirks\\sometest.bat), }, E7 => { desc => q(Rel: TestActiveSheet.xls), rel => 1, link => q(TestActiveSheet.xls), }, F7 => { desc => q(mailto:fred@example.net), link => q(mailto:fred@example.net), }, A9 => { desc => q(file:///..\\..\\zipple.dat), link => q(../../zipple.dat), }, A10 => { desc => q(ftp://user:pass@example.net/pub/manuals/Excel.doc), link => q(ftp://user:pass@example.net/pub/manuals/Excel.doc), }, ); foreach my $t (sort keys %expect) { my $link = $expect{$t}{link}; my $desc = $expect{$t}{desc}; my $rel = $expect{$t}{rel}; if( $rel ) { $link = "file:///t/excel_files/$link"; } $t =~ m/^(.)(\d+)$/ or die; my $cell = $ws->get_cell( $2-1, (ord($1)-ord('A')) ); ok( defined $cell, "Cell $t defined" ); next unless defined $cell; my $hl = $cell->get_hyperlink; if( !defined $link ) { is( $hl, undef, "Cell $t should have no link" ); next; } ok( defined $hl->[0] && $hl->[0] eq $desc, "Cell $t description match" ); ok( defined $hl->[1] && $hl->[1] eq $link, "Cell $t link match" ); } __END__ Spreadsheet-ParseExcel-0.66/t/44_oem.t000755 000765 000024 00000001553 11247565351 017545 0ustar00Johnstaff000000 000000 #!perl -w use strict; use Test::More tests => 14; use Spreadsheet::ParseExcel; use Spreadsheet::ParseExcel::FmtJapan; use utf8; my $xl = Spreadsheet::ParseExcel->new(); my $fmtj = Spreadsheet::ParseExcel::FmtJapan->new(); my $book = $xl->Parse("t/excel_files/TestEncoding.xls", $fmtj); ok $book, "load TestEncoding.xls"; my $sheet = $book->worksheet(0); my @expected = ( ['This is a test file for Japanese encoding'], [qw(ローマ数字 Ⅰ Ⅱ)], [qw(丸数字 ① ②)], [qw(年号 ㍻ ㍼)], [qw(その他 ㈱ ~)], ); my($rmin, $rmax) = $sheet->row_range(); my($cmin, $cmax) = $sheet->col_range(); #binmode STDOUT, ':encoding(cp932)'; for my $i($rmin .. $rmax){ for my $j($cmin .. $cmax){ my $cell = $sheet->get_cell($i, $j); next unless $cell && $cell->value; #print $cell->value, "\n"; is $cell->value, $expected[$i][$j], "[$i, $j]"; } } Spreadsheet-ParseExcel-0.66/t/00_basic.t000644 000765 000024 00000001737 11247565351 020037 0ustar00Johnstaff000000 000000 #!/usr/bin/perl use strict; use warnings; use Test::More tests => 8; use_ok('Spreadsheet::ParseExcel'); use_ok('Spreadsheet::ParseExcel::Dump'); use_ok('Spreadsheet::ParseExcel::FmtDefault'); use_ok('Spreadsheet::ParseExcel::Utility'); eval "use Jcode"; my $no_jcode = $@; eval "use Unicode::Map"; my $no_unicode_map = $@; eval "use Spreadsheet::WriteExcel"; my $no_writeexcel = $@; SKIP: { skip "Need Jcode for additional tests", 1 if $no_jcode; use_ok('Spreadsheet::ParseExcel::FmtJapan'); } SKIP: { skip "Need Unicode::Map for additional tests", 1 if $no_unicode_map; use_ok('Spreadsheet::ParseExcel::FmtUnicode'); } SKIP: { skip "Need Jcode and Unicode::Map for additional tests", 1 if $no_jcode or $no_unicode_map; use_ok('Spreadsheet::ParseExcel::FmtJapan2'); } SKIP: { skip "Need Spreadsheet::WriteExcel for additional tests", 1 if $no_writeexcel; use_ok('Spreadsheet::ParseExcel::SaveParser'); } Spreadsheet-ParseExcel-0.66/t/91_minimumversion.t000644 000765 000024 00000001266 11247565351 022046 0ustar00Johnstaff000000 000000 #!/usr/bin/perl # Test that our declared minimum Perl version matches our syntax use strict; BEGIN { $| = 1; $^W = 1; } my @MODULES = ( 'Perl::MinimumVersion 1.20', 'Test::MinimumVersion 0.008', ); # Don't run tests during end-user installs use Test::More; unless ( $ENV{AUTOMATED_TESTING} or $ENV{RELEASE_TESTING} ) { plan( skip_all => "Author tests not required for installation" ); } # Load the testing modules foreach my $MODULE ( @MODULES ) { eval "use $MODULE"; if ( $@ ) { $ENV{RELEASE_TESTING} ? die( "Failed to load required release-testing module $MODULE" ) : plan( skip_all => "$MODULE not available for testing" ); } } all_minimum_version_from_metayml_ok(); 1; Spreadsheet-ParseExcel-0.66/t/excel_files/chart1.xls000644 000765 000024 00000035000 11247565351 022454 0ustar00Johnstaff000000 000000 ࡱ>   \pUsername Ba==Z7$8X@"1Arial1Arial1Arial1Arial1Arial1Arial+" "#,##0;\-" "#,##05" "#,##0;[Red]\-" "#,##07" "#,##0.00;\-" "#,##0.00A" "#,##0.00;[Red]\-" "#,##0.00e*0_-" "* #,##0_-;\-" "* #,##0_-;_-" "* "-"_-;_-@_-,)'_-* #,##0_-;\-* #,##0_-;_-* "-"_-;_-@_-u,8_-" "* #,##0.00_-;\-" "* #,##0.00_-;_-" "* "-"??_-;_-@_-4+/_-* #,##0.00_-;\-* #,##0.00_-;_-* "-"??_-;_-@_-                + ) , *  ` Sheet1h Sheet2 Chart1Sheet3a#Sheet1Sheet2Sheet3 C  q0CP0"q0+q0 :r*C JE*XZ0ELP`EE0| ĺ||Ir0BBR|,LS0dt00ȹ%4|^n00 00Ԣ00Ltb0Percent0],8\| 8Ν0X40ZT0_T0=l0~Pe0P~0~PH? 0H-=NJT0e0YT0L0YT0LNJT0»Ȼk0 $Ȇ0TдL=s00{=s0:04 @,PU @,w0 0\,00   s +  dMbP?_*+%"??NJUT0 ?@@@@@ <>@   $ ^  dMbP?_*+%"??NJUT0 ">@  " @??3` 8t"` 8t"Q312d 3QQ ;QQ3_4E4 3QQ ;QQ3_4E4D$% YM 3O&Q4$% YM 3O&Q4FAz 3O*E-3 b#M43*#M! M4523  O43"  3O% YM3OQ44444ee?@@@@@e> 12   a  dMbP?_*+%"??4UT0 ">@ Oh+'08@Th  Username  Username Microsoft Excel@g|՜.+,D՜.+,@ PXd lt| 1  Sheet1Sheet2Sheet3Chart1  WorksheetsCharts 6> _PID_GUIDAN{B5ED2352-746A-4564-89E3-55528E27DABB} Root Entry FWorkbookSummaryInformation( DocumentSummaryInformation8Spreadsheet-ParseExcel-0.66/t/excel_files/chart3.xls000644 000765 000024 00000035000 11247565351 022456 0ustar00Johnstaff000000 000000 ࡱ>   \pUsername Ba==Z7$8X@"1Arial1Arial1Arial1Arial1Arial1Arial+" "#,##0;\-" "#,##05" "#,##0;[Red]\-" "#,##07" "#,##0.00;\-" "#,##0.00A" "#,##0.00;[Red]\-" "#,##0.00e*0_-" "* #,##0_-;\-" "* #,##0_-;_-" "* "-"_-;_-@_-,)'_-* #,##0_-;\-* #,##0_-;_-* "-"_-;_-@_-u,8_-" "* #,##0.00_-;\-" "* #,##0.00_-;_-" "* "-"??_-;_-@_-4+/_-* #,##0.00_-;\-* #,##0.00_-;_-* "-"??_-;_-@_-                + ) , *  ` Sheet1h Sheet2 Chart1Sheet3a#Sheet1Sheet2Sheet3 XUh|@|=|||p0sp 41E*XZ041ELP`41E41E0chart3.xls| xHĺ||Ir0R|,,S0dt00ȹ%4|^n00 00Ԣ00,tb0TPercent0]x,\|8Ν0X40ZT0_T0=l0~Pe0P~0~PH? 0H-=NJT0e0YT0L0YT0LNJT0»Ȼk0 $Ȇ0Tl@=s00{=s0:04 P w08 00   s +  dMbP?_*+%"??NJUT0 ?@@@@@ <>@   $ ^  dMbP?_*+%"??NJUT0 ">@  " @??3` 8t"` 8t"Q312d 3QQ ;QQ3_4E4 3QQ ;QQ3_4E4D$% M 3O&Q4$% M 3O&Q4FAz 3O*E-3 b#M43*#M! M4523  O43"  3O% M3OQ44444ee?@@@@@e> 12   a  dMbP?_*+%"??4UT0 ">@ Oh+'08@Th  Username  Username Microsoft Excel@g|՜.+,D՜.+,@ PXd lt| 1  Sheet1Sheet2Sheet3Chart1  WorksheetsCharts 6> _PID_GUIDAN{B5ED2352-746A-4564-89E3-55528E27DABB} Root Entry FWorkbookSummaryInformation( DocumentSummaryInformation8Spreadsheet-ParseExcel-0.66/t/excel_files/chart2.xls000644 000765 000024 00000036000 11247565351 022456 0ustar00Johnstaff000000 000000 ࡱ>   \pUsername Ba==Z7$8X@"1Arial1Arial1Arial1Arial1Arial1Arial+" "#,##0;\-" "#,##05" "#,##0;[Red]\-" "#,##07" "#,##0.00;\-" "#,##0.00A" "#,##0.00;[Red]\-" "#,##0.00e*0_-" "* #,##0_-;\-" "* #,##0_-;_-" "* "-"_-;_-@_-,)'_-* #,##0_-;\-* #,##0_-;_-* "-"_-;_-@_-u,8_-" "* #,##0.00_-;\-" "* #,##0.00_-;_-" "* "-"??_-;_-@_-4+/_-* #,##0.00_-;\-* #,##0.00_-;_-* "-"??_-;_-@_-                + ) , *  ` Sheet1dSheet2Sheet3aZR3  @@  #Sheet1Sheet2Sheet3 095447-2390690856-1006hart2.xlsOwsOw4``w JHELL3Q-|X-|Y0t 1Y!  S0S0 0t 1Ir0BBt(D$|x4|$|LS0|t00|8|4|^n00 00Ԣ00Ltb0Percent0] and Sti0s\ PΝ0XL0ZT0_T0=l0~Pe0P~0~PH? 0H-=NJT0e0YT0L0@ |066~0BT0,6@6`u0(1T0`|06ZV0Z6 0Z    u  dMbP?_*+%"??NJUT0 ?@@@@@ <(  p  6NMM? ]`6  "??3` v` v`3d23 M NM4 3QQ ;QQ3_4E4 3QQ ;QQ3_4E4D $% M 3O&Q4$% M 3O&Q4FA ` 3OW 3 b#M43*#M! M4523  O43" Q 0-43OQ 0% M3OQ44444eee >@    Z  dMbP?_*+%"??UT0 ">@   M  dMbP?_*+%"??UT0 ">@ Oh+'08@Th  Username  Username Microsoft Excel@0_|՜.+,D՜.+, PXd lt| 3  Sheet1Sheet2Sheet3  Worksheets 6> _PID_GUIDAN{532909D5-5112-48CD-B5C2-DE618A524C05} Root Entry FWorkbookSummaryInformation( DocumentSummaryInformation8Spreadsheet-ParseExcel-0.66/t/excel_files/pers-encrypted-RC4-pass-11.xls000755 000765 000024 00000022000 11547123164 026001 0ustar00Johnstaff000000 000000 ࡱ>  Root Entry FNIn\WorkbookOle encryption  a[ô8 Cڟ[59C@mO o”HrESwI*\ܻ7#^`lρ-<\cjː,8WQKNaI>[/]iZTȽ<0IC Nܴv36&\MV̵?P dۥXռo,Կ z7nS}`XaOGE 2g6LLkYovʙ"*XY+.HU;EcثU~`R')v-FA)r2=IF\ .P(ME&`[88 C @mNhÑ鮍jv!ȯ߼,=Oëv6J @p֍"lsFqGp1Khn# /R@ttRĔ14ג­vg2aj y1-Âr3a Xq&1|1LQ= +3pQB1/n&N7jM_wiu z]/@F1r@k=D ~6|6Q{Zgg9V4#ծ[,q.7j")0$ОLc,&MD=r`ɉX;jlK}/VI[tp};r0ޭENbG+hm7eE_-{JPɁ@č1/Y=Pdi%ȼ,(>[E}L$Pk` k%>,ִ|!&i'&Pe4DMm@][JsOly~=j E65OΥ֭.h{c-k&6r0ӆ᩿\~)ҥ`2WZ.0ĸb5ZК 4̜>qۨ) dvoTT'yQXQb6Eި {6LF43o2f'9,h1{+VZޟE5-;o'cڇ$UNc|,"6ϩ&9FlR2-Inb$HA,(HmTc{wlbB;?6DAdaj2LF>b*~(E,Z֒(}< e1Z%:yNp(R$ɒŧ=C>@PZ+Oe>}f2Ia"GCP%u pՔǯʵl~ų2ϴzntiܛvyy Omh.!)|cޣݫSLnx3ac+D$u}d.{: LGNk;݆q}nejQٝOL8%dY_`D"NpH:;$Q2v˄xn^gs[*jVy8ۚ8|px#鵯jپt'DzJUWOaQlF ᝷ZA\V'* jZNt!G'Aa;6g( >uZ U7JOAa!fJv,V & vs!%hbMo;!BQod<,SJ6Ur2I5I;EpÞgj9  tH+u _ce7y0/I€\xϪ[D#k]<"F`"Hf*ww]Z+I(Sz/<2B944-7oN{/ S ]1Ѝ{cYQ^{T Yx a   TB0B޶<?7. 2` %`?$#/ _>*^+Qu/VM%bkLB^Fه2"T-UUEf  (&ɾъ7' <(^;$C*)QSM*lc{kәn YO%1DN$]kgg;F|Phĥ͈6+,{4 wy{`)ncv%&:.8KrG z[oS萄eN쐻~>" )'כX`*79p)[Yx@K dtvپ0|O7[H%*)복 oP{)OgLZגJ\*<<,P`])൚\O, ּq[ U3rjaRC]QǽC[ݙ4]F*K[DpgY&=)5^"Sad/RbjZRݠVjx(,_"zcYvҖD/ȨĮHv߷0bɪ8GF.@i}Iα[ 񉍔YrS /4![&p}qm޷"yBܫ;~V ,kEjib#X+)oHYs 1?͌{S,fcui7=ɥ{T1MX땺N$"|eE4J/TxXb$n&vawi ܼN맢tWSJu5%v|%y5K=dxOqSA5gt󍉃b!a C,n77]_lx''^%1i }jtv x'[_ts Nm:?? pj ԠJZ-]=D`}Ϋ@4e"xpGũ2WnȲo;׾L( ;߇oR%]٢&X &'/}&vjevh Zf|g 4lsªmLM%"O |֑5dN7"#.IJsH^c}F1[8m{ ZWa>ȀO&/_=7ɔ hK73@3oY#"v4 Zsݙaq pe҈6p X@cU} PFCc)} ;_~} EZV-H }m$1|Yׯ?٦ d0gb&&w bH׊sWH=/{j}Kn8ȟK\VԫS0g`мϜ}z LY3   ϿG)X I' sc @.4F>%Il_Md*M+ hz}F%h4Od6ڊuJ]'7ep.'&C%'809(3$(v)3dy8?"XULyٶɼ wV0Ӵo 4U$;)- 6t5985g>F!aoR]Z%I).n(g _P& jzHCѰJb   ] =J0)]  462͍DT{_k*>+JW4M8%GdV$<)"E +q*H:LA@r g<9_@Ԋ/80n * DocumentSummaryInformation8HCompObj h՜.+,0$ϸR='j݄,NjWQKN CM_7V]ٕiQT]_'+C  F Microsoft Office ExcelBiff8Excel.Sheet.89qSpreadsheet-ParseExcel-0.66/t/excel_files/Test95J.xls000755 000765 000024 00000033000 11247565351 022502 0ustar00Johnstaff000000 000000 ࡱ>  \pkawait B=x>G"8X@"1lr oSVbN1lr oSVbN1lr oSVbN1lr oSVbN1xlr oSVbN"\"#,##0;"\"\-#,##0"\"#,##0;[Red]"\"\-#,##0"\"#,##0.00;"\"\-#,##0.00!"\"#,##0.00;[Red]"\"\-#,##0.005*2_ "\"* #,##0_ ;_ "\"* \-#,##0_ ;_ "\"* "-"_ ;_ @_ ,))_ * #,##0_ ;_ * \-#,##0_ ;_ * "-"_ ;_ @_ =,:_ "\"* #,##0.00_ ;_ "\"* \-#,##0.00_ ;_ "\"* "-"??_ ;_ @_ 4+1_ * #,##0.00_ ;_ * \-#,##0.00_ ;_ * "-"??_ ;_ @_ \$#,##0_);\(\$#,##0\)\$#,##0_);[Red]\(\$#,##0\)\$#,##0.00_);\(\$#,##0.00\)# \$#,##0.00_);[Red]\(\$#,##0.00\) "Hippo2000:"@ "͔n:"\:@"Ɋ:"@                 & (       83ffff̙3f3fff3f3f33333f33333 Sheet1-ASC i   n  dMbP?_*+%QQM\\Lins\lp`!W0`%W0`N 4dhhpXXp ?4 *** qhhDLLName32=e_du01jj.dll L dL 2EPSON PM-800C" dMb?Mb?U} ` F8 ASCThis Data is 'ASC Only' Date~ @INTEGER~ @ Float~  `@Doublec!2AFormulac!3Aa i DDbd2!$=x>G"8X> "  !   dMbP?_*+%QQ"QMb?Mb?U} }  F8 ASCThis Data is 'ASC Only'  ̃f[^ Date~ @INTEGER~ @ Float~  `@Doublec!2AFormulac!3A[ DD Float2.!$6=x>G"8X> " Oh+'08@dt Kawai, Takanori (Hippo2000)kawaitTMicrosoft Excel@Ǻ"՜.+,08@ \d l {bhp  Sheet1-ASC ܰ Root Entryc:\Program files\MicrFo\VC98\B:\Bookopenssl-0.9.4\out32dll;C:\P iles\InstallShieldtaSummaryInformationional Editio(m;e:\UNIX6nhDocumentSummaryInformation8Spreadsheet-ParseExcel-0.66/t/excel_files/worksheet_01.xls000644 000765 000024 00000045000 11257774752 023616 0ustar00Johnstaff000000 000000 ࡱ> #" \p John McNamara Ba==[,%8X@"1Arial1Arial1Arial1Arial1Arial12@Arial Unicode MS1Arial""#,##0;\-""#,##0""#,##0;[Red]\-""#,##0""#,##0.00;\-""#,##0.00#""#,##0.00;[Red]\-""#,##0.005*0_-""* #,##0_-;\-""* #,##0_-;_-""* "-"_-;_-@_-,)'_-* #,##0_-;\-* #,##0_-;_-* "-"_-;_-@_-=,8_-""* #,##0.00_-;\-""* #,##0.00_-;_-""* "-"??_-;_-@_-4+/_-* #,##0.00_-;\-* #,##0.00_-;_-* "-"??_-;_-@_-+" "#,##0;\-" "#,##05" "#,##0;[Red]\-" "#,##07" "#,##0.00;\-" "#,##0.00A" "#,##0.00;[Red]\-" "#,##0.00e0_-" "* #,##0_-;\-" "* #,##0_-;_-" "* "-"_-;_-@_-u8_-" "* #,##0.00_-;\-" "* #,##0.00_-;_-" "* "-"??_-;_-@_- yyyy/mm/dd yyyy                + )    !  !  !        !0@@  0@  0 @  0@  0  0 " ` Sheet1Sheet2Sheet3,  ;* );;* );;  ;8750This is a test workbook for worksheet regression%The first sheet has default settings.This sheet has:First row and col dims changed. Changed default row and col dimsLandscape modeA5 Print scale Paper size Page start Top margin Bottom margin Left margin Right margin Header margin Footer margin Custom header Custom footer Print area $A$1:$C$151:2 Repeat rows Repear colsA:C GridlinesBlack and whiteDraftRow and col headingsCommentsAt end Cell errors Displayed Print orderOver then downHorizontal page breaksVertical page breaks Merged cells(This sheet had print to fit options set.&CThis is the header<his is the footerCentre HorizontallyCentre VerticallyNext row is hidden.Last rowNext col is hidden Last col.Unformatted valueFormatted date Same formatUnicode:&"oW[n0000Rich text bold and italic :  V  # 3 kcc  n  dMbP?_*+%MnMicrosoft Office Document Imag/ dLetterwidm" d??U  D>@7  $k  dMbP?_*+%&CThis is the header<his is the footer&333333?'ffffff?(?)?M\\shprint01\shprt144sideS 4KXXA4PRIV0''''h<\K\K}hSMTJXDell Printer 5100cn PSResolution600dpiInputSlot*UseFormTrayTableDuplexNonePageSizeA4PageRegionLeadingEdgeDLColorModeColorDLOutputMode600x600DLRGBCCorrectionStandardDLRGBBCorrectionDarkDLEngineScreenAutoSmoothingTrueDLTonerSaverFalseDLGrayBalanceTrueDLColorAjstCAOFFDLMSILeadingEdgeShortEdgeCollateFalseMediaTypeDefaultDLSlipSheetTrayOFFDLSlipSheetPrintFalseDLSubPaperSelectionPolicy0DLCustomPageSizeCorrectionTrueDLSkipFalseDLHalftoneModeTrueDFBF0040/#>B |$pL" K??U} } m } m } m } m $  @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @@@@@@@@@@@@@@@@    ,  -  ~ ?    ~ @  ~ [@  ~ ?  ~ ^@  ~ a@ ~ ? ~ d@  &  ' (~ ? )~ ?       ~ ? ~ ? ~ ? ~ ?      ! " # $ !BX*  @!`#@ * #+ X(>@<d 7   !#  dMbP?_*+%MnMicrosoft Office Document Imag/ dLetterwidm" a??U} }   , % .~ ? /~  @ 0~ @@ 1 2 1 3 "$" 4`>@ 7 Oh+'0HPh John McNamaraJohn McNamaraMicrosoft Excel@Z@YF @@?՜.+,0T PXd lt| ' Sheet1Sheet2Sheet3Sheet2!Print_AreaSheet3!Print_AreaSheet2!Print_TitlesSheet3!Print_Titles  Worksheets Named Ranges  !Root Entry FWorkbook#SummaryInformation(DocumentSummaryInformation8Spreadsheet-ParseExcel-0.66/t/excel_files/chart4.xls000644 000765 000024 00000041000 11247565351 022454 0ustar00Johnstaff000000 000000 ࡱ>   \pUsername Ba==Z7$8X@"1Arial1Arial1Arial1Arial1Arial1Arial1Arial1Arial+" "#,##0;\-" "#,##05" "#,##0;[Red]\-" "#,##07" "#,##0.00;\-" "#,##0.00A" "#,##0.00;[Red]\-" "#,##0.00e*0_-" "* #,##0_-;\-" "* #,##0_-;_-" "* "-"_-;_-@_-,)'_-* #,##0_-;\-* #,##0_-;_-* "-"_-;_-@_-u,8_-" "* #,##0.00_-;\-" "* #,##0.00_-;_-" "* "-"??_-;_-@_-4+/_-* #,##0.00_-;\-* #,##0.00_-;_-* "-"??_-;_-@_-                + ) , *  `= Sheet1Sheet2Sheet3aZR3  @@  #Sheet1Sheet2Sheet3 0h|@|=|||p0sp aE*XZ0aELP`aEaE0chart4.xls| xHĺ||Ir0R||S0dt00ȹ%4|^n00 00Ԣ00tb0Percent0] Q,Q\|p 8Ν0X40ZT0_T0=l0~Pe0P~0~PH? 0H-=NJT0e0YT0L0@|0x6x6~0BT0x6(x6Hu0(1T0H|0x6Z̻>0Zx6 0Z     dMbP?_*+%"??NJUT0 ?@@@@@ <8 (  p  6NMM? ]`6  "??3` v` v`3d23 M NM4 3QQ ;QQ3_4E4 3QQ ;QQ3_4E4D $% M 3O&Q4$% M 3O&Q4FA ` 3OW 3 b#M43*#M! M4523  O43" Q 0-43OQ 0% M3OQ44444ee?@@@@@e xp  6NMM?x -]`6  "??3` v` v`3d23 M NM4 3QQ ;QQ3_4E4 3QQ ;QQ3_4E4D $% M 3O&Q4$% M 3O&Q4FA ` 3OW 3 b#M43*#M! M4523  O43" Q 0-43OQ 0% M3OQ44444ee?@@@@@e >@     dMbP?_*+%"??UT0 ">@     dMbP?_*+%"??UT0 ">@ Oh+'08@Th  Username  Username Microsoft Excel@0_|՜.+,D՜.+, PXd lt| 3  Sheet1Sheet2Sheet3  Worksheets 6> _PID_GUIDAN{532909D5-5112-48CD-B5C2-DE618A524C05} Root Entry FWorkbook4SummaryInformation(DocumentSummaryInformation8Spreadsheet-ParseExcel-0.66/t/excel_files/TestEncoding.xls000755 000765 000024 00000033000 11247565351 023661 0ustar00Johnstaff000000 000000 ࡱ>  @\p John McNamara Ba==\:(#8X@"1 -3 000001 -3 000001 -3 000001 -3 000001 -3 000001 x-3 00000"\"#,##0;"\"\-#,##0"\"#,##0;[Red]"\"\-#,##0"\"#,##0.00;"\"\-#,##0.00#"\"#,##0.00;[Red]"\"\-#,##0.007*2_ "\"* #,##0_ ;_ "\"* \-#,##0_ ;_ "\"* "-"_ ;_ @_ .))_ * #,##0_ ;_ * \-#,##0_ ;_ * "-"_ ;_ @_ ?,:_ "\"* #,##0.00_ ;_ "\"* \-#,##0.00_ ;_ "\"* "-"??_ ;_ @_ 6+1_ * #,##0.00_ ;_ * \-#,##0.00_ ;_ * "-"??_ ;_ @_ \$#,##0_);\(\$#,##0\)\$#,##0_);[Red]\(\$#,##0\) \$#,##0.00_);\(\$#,##0.00\)% \$#,##0.00_);[Red]\(\$#,##0.00\)                 & (   " " `$Sheet1QQ`i )This is a test file for Japanese encoding`!a!8NpeW[`$a$t^S{3|3]0n0N12^000peW[5000r a @ R  dMbP?_*+%"Mb?Mb?U} }  }                 *P***>@ 5 Oh+'0@HXh GorofGorofMicrosoft Excel@븲?@ʤ@՜.+,0 PXd lt| 1 Sheet1  [NV[g Root Entry FvPWorkbookSummaryInformation(DocumentSummaryInformation8Spreadsheet-ParseExcel-0.66/t/excel_files/TestActiveSheet.xls000644 000765 000024 00000040000 14543405670 024331 0ustar00Johnstaff000000 000000 ࡱ>   \p Timothe Litt Ba==hZ],.8X@"1YArial1YArial1YArial1YArial1YArial1 YArial1$YArial"$"#,##0_);\("$"#,##0\)!"$"#,##0_);[Red]\("$"#,##0\)""$"#,##0.00_);\("$"#,##0.00\)'""$"#,##0.00_);[Red]\("$"#,##0.00\)7*2_("$"* #,##0_);_("$"* \(#,##0\);_("$"* "-"_);_(@_).))_(* #,##0_);_(* \(#,##0\);_(* "-"_);_(@_)?,:_("$"* #,##0.00_);_("$"* \(#,##0.00\);_("$"* "-"??_);_(@_)6+1_(* #,##0.00_);_(* \(#,##0.00\);_(* "-"??_);_(@_)                + ) , *    Q  `Sheet1J Sheet2Sheet3Sheet4">This workbook is saved with this sheet open in the second tab."get_active_sheet should return "1"Row 4 is hiddenColumn D is hiddenSheet 3 is hiddenhttp://www.example.comhttp://www.example.com#foo\\server\quirks\sometest.batwww.example.comwww.example.com#fooc:\nodir\nofile.txtSMB Link Sometest.batTestActiveSheet.xlsRel: TestActiveSheet.xls Sheet2!A7mailto:fred@example.netfile:///c:\nodir\nofile.txtfile:///..\..\zipple.dat1ftp://user:pass@example.net/pub/manuals/Excel.docf \ cc   m  dMbP?_*+%"??d U}     X(>@7bb9      dMbP?_*+%"??d U} $6} I} } m} m                  XdTT>@  7yK http://www.example.comyK Hhttp://www.example.com/yX;H,]ą'cyK http://www.example.com#fooyK Hhttp://www.example.com/yX;H,]ą'cfooyK file:///c:\nodir\nofile.txtFc:\nodir\nofile.txtyK \\server\quirks\sometest.bat\\server\quirks\sometest.batyK www.example.comyK Hhttp://www.example.com/yX;H,]ą'cyK www.example.com#fooyK Hhttp://www.example.com/yX;H,]ą'cfooyK c:\nodir\nofile.txtFc:\nodir\nofile.txtyK SMB Link Sometest.bat\\server\quirks\sometest.batyK TestActiveSheet.xlsF TQYMZX~K.XLS,&TestActiveSheet.xlsyK Rel: TestActiveSheet.xlsF TQYMZX~K.XLS,&TestActiveSheet.xlsPyK  Sheet2!A7 Sheet2!A7yK mailto:fred@example.netyK Hmailto:fred@example.netyX;H,]ą'cyK file:///..\..\zipple.datyK :../../zipple.datyX;H,]ą'c yK 2ftp://user:pass@example.net/pub/manuals/Excel.docyK |ftp://user:pass@example.net/pub/manuals/Excel.docyX;H,]ą'c   [  dMbP?_*+%"F??2U ">@7     dMbP?_*+%"??2U ">@7 Oh+'0@H`x Timothe LittTimothe LittMicrosoft Excel@$M74@w?՜.+,D՜.+,( PXd lt| ' Sheet1Sheet2Sheet3Sheet4  Worksheets 8@ _PID_HLINKSATo 2ftp://user:pass@example.net/pub/manuals/Excel.docC ../../zipple.dat# mailto:fred@example.netC^  Sheet2!A7~1 TestActiveSheet.xls~1TestActiveSheet.xlsF\\server\quirks\sometest.batrpc:\nodir\nofile.txt[http://www.example.com/fooh4http://www.example.com/F\\server\quirks\sometest.batrpc:\nodir\nofile.txt[http://www.example.com/fooh4http://www.example.com/ Root Entry FWorkbook SummaryInformation( DocumentSummaryInformation8Spreadsheet-ParseExcel-0.66/t/excel_files/Dates.xls000755 000765 000024 00000040000 11247565351 022331 0ustar00Johnstaff000000 000000 ࡱ>  ^@\p John McNamara Ba==<F!8X@"1,LettrGoth12 BT1,LettrGoth12 BT1,LettrGoth12 BT1,LettrGoth12 BT1,LettrGoth12 BT1,LettrGoth12 BT1,LettrGoth12 BT3" "\ #,##0;\-" "\ #,##0=" "\ #,##0;[Red]\-" "\ #,##0?" "\ #,##0.00;\-" "\ #,##0.00I"" "\ #,##0.00;[Red]\-" "\ #,##0.00q*6_-" "\ * #,##0_-;\-" "\ * #,##0_-;_-" "\ * "-"_-;_-@_-,)'_-* #,##0_-;\-* #,##0_-;_-* "-"_-;_-@_-,>_-" "\ * #,##0.00_-;\-" "\ * #,##0.00_-;_-" "\ * "-"??_-;_-@_-4+/_-* #,##0.00_-;\-* #,##0.00_-;_-* "-"??_-;_-@_- yyyymmdd mm\/dd\/yyyyddd\,\ dd\ mmm\ yyyy m/d/yy                + ) , *     ! " #      1 2 3        ` DateTest`i 08 Aug 2008 12 Aug 2008 08 Dec 2008 13 Aug 2008Locale settings on this PCShort: dd-MM-yyyyLong: ddd, dd MMM yyyyDefault format 0x0E * ^@ &  dMbP?_*+%,M \\dc242\Hold S odXXLetterPRIV0''''`4 \KhCbP`SMTJPDocuColor 242-252-260 PSResolution600dpiEFMMInUseFalseEFMMInsTypeNoneEFMMCoverPrintFrontEFMMTabShiftFalseEFColorModeEFColorModeDEFEFRGBOverrideEFRGBOverrideDEFEFRGBOtherWtPtEFRGBOtherWtPtDEFEFRGBOtherGammaEFRGBOtherGammaDEFEFRGBOtherPhosEFRGBOtherPhosDEFEFColorRendDictEFColorRendDictDEFEFRGBSepEFRGBSepDEFEFSimulationEFSimulationDEFEFSimSpeedEFSimSpeedDEFEFOutProfileEFOutProfileDEFEFSpotColorsEFSpotColorsDEFEFPureBlackEFPureBlackDEFEFBlkOvpCtrlEFBlkOvpCtrlDEFEFCompOverprintFalseEFKOnlyGrayCMYKEFKOnlyGrayCMYKDEFEFKOnlyGrayRGBEFKOnlyGrayRGBDEFEFSubstColorsFalseEFSeparationsFalseEFTrappingFalseEFSortCollateEFStaplerFalseEFOutputBinAutoSelectEFImageAlignFalseEFImageUnitInchesEFFoldFalseEFImageFlagFalseEFOffsetJobsEFOffsetJobsDEFEFPunchEdgeNoneEFPunchHoleTypeNoneEFFaceDownEFFaceDownDEFEFImageSmoothFalseEFBrightness00.00EFImageEnhanceEFImageEnhanceDEFEFCompressionNormalQualityEFCopierModeEFCopierModeDEFEFGlossAdjustFalseEFTextGfxQualNormalEFRasterFalseEFDuplexFalseEFUserRotate180FalseEFRIPBookletFalseEFBookCoverTrayEFBookCoverTrayDEFEFBookFrCoverNoneEFBookBkCoverNoneEFCopierBookletFalseEFCenteringMiddleEFBookletCreepFalseEFBookletReduceTrueEFManualDuplexFalseEFMediaTypeAnyInputSlotAutoSelectEFTrayAlignmentFalseEFSlipsheetFalseEFSlipsheetSizeLetterEFSlipsheetTrayTray5EFMediaInterlvFalseEFInterlvTrayTray5EFMedQualCoatd1EFMedQualCoatd1DEFEFMedQualCust1EFMediaQualityCustom1DEFEFMedQualCust2EFMedQualCust2DEFEFMedQualCust3EFMedQualCust3DEFEFMedQualCust4EFMedQualCust4DEFEFMedQualCust5EFMedQualCust5DEFEFMedQualHeavy1EFMedQualHeavy1DEFEFMedQualHeavy2EFMedQualHeavy2DEFEFMedQualPlainEFMedQualPlainDEFEFMedQualRcycldEFMedQualRcycldDEFEFPrintSizeEFPrintSizeDEFEFCreateMasterNoneEFUseMasterNoneEFPPTSlideFalseEFPrintMasterEFPrintMasterDEFPageSizeLetterPageRegionLeadingEdgeIIFE2IFE" dX??U} X@X@X@X@X@X@X@^@^@ ^@!^@ "_@_@_@_@ "m@m@m@m@ " _@ _@ _@ _@ " ## $ $ $ _@% _@& _@x0000*>@ 7 Oh+'0@H`t H.Merijn Brand H.M. BrandaMicrosoft Excel@S} @v ՜.+,0 PXp x  PROCURA B.V.eTe2  DateTest  Worksheets Root Entry Fp!WorkbookSSummaryInformation( DocumentSummaryInformation8Spreadsheet-ParseExcel-0.66/t/excel_files/long_string8.xls000644 000765 000024 00000157000 11247565351 023714 0ustar00Johnstaff000000 000000 ࡱ> ml  \pUsername Ba==x[J[8X@"1Arial1Arial1Arial1Arial+" "#,##0;\-" "#,##05" "#,##0;[Red]\-" "#,##07" "#,##0.00;\-" "#,##0.00A" "#,##0.00;[Red]\-" "#,##0.00e*0_-" "* #,##0_-;\-" "* #,##0_-;_-" "* "-"_-;_-@_-,)'_-* #,##0_-;\-* #,##0_-;_-* "-"_-;_-@_-u,8_-" "* #,##0.00_-;\-" "* #,##0.00_-;_-" "* "-"??_-;_-@_-4+/_-* #,##0.00_-;\-* #,##0.00_-;_-* "-"??_-;_-@_-                + ) , *  `Sheet1a Foo:&This is a test stringSmiley :&3u:&xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx< xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx< xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxz:&xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx< xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx< xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx< xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxz:& 095447-2390690856-1006ong_string8.xlssOw4``w )HELL3Q-|X-||Ⱦ|k<||0X-|h|$h|Ⱦ||Ⱦ|2|2|$|+%Ir0))x(D$|x4|$|)S0|t00|8|4|^n00 00Ԣ00)tb0`)Percent0] and S`tis\John McNXe0XZT00ZT0_T0=l0~Pe0P~0~PH? 0H-=NJT0e0YT0L0YT0LNJT0k0 $Ȇ0lDDC0<(c0G0D   F  dMbP?_*+%"??NJUT0G     P>@ Oh+'08@Th  Username  Username Microsoft Excel@iu՜.+,D՜.+, PXd lt| 1  Sheet1  Worksheets 6> _PID_GUIDAN{B5490379-D025-4931-9820-1895C909CFAD}  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcefghijkRoot Entry FWorkbookGSummaryInformation(\DocumentSummaryInformation8dSpreadsheet-ParseExcel-0.66/t/excel_files/long_string5.xls000644 000765 000024 00000136000 11247565351 023706 0ustar00Johnstaff000000 000000 ࡱ> \[  \pUsername Ba==x[J-8X@"1Arial1Arial1Arial1Arial+" "#,##0;\-" "#,##05" "#,##0;[Red]\-" "#,##07" "#,##0.00;\-" "#,##0.00A" "#,##0.00;[Red]\-" "#,##0.00e*0_-" "* #,##0_-;\-" "* #,##0_-;_-" "* "-"_-;_-@_-,)'_-* #,##0_-;\-* #,##0_-;_-* "-"_-;_-@_-u,8_-" "* #,##0.00_-;\-" "* #,##0.00_-;_-" "* "-"??_-;_-@_-4+/_-* #,##0.00_-;\-* #,##0.00_-;_-* "-"??_-;_-@_-                + ) , *  `eSheet1a Foo:&This is a test stringSmiley :&y:&xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx< xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx< xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx< xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx<xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxz C  q0CP0"q0+q0 :-$C )T_E-XZ0T_ELP`T_ET_E0| Kĺ||Ir0))R|,)S0dt00ȹ%4|^n00 00Ԣ00)tb0d)Percent0]`,\|`Xe0XZT00ZT0_T0=l0~Pe0P~0~PH? 0H-=NJT0e0YT0L0YT0LNJT0»Ȼk0 $Ȇ0TȻC0@(̻c0G0   !  dMbP?_*+%"??NJUT0     P>@ Oh+'08@Th  Username  Username Microsoft Excel@0u՜.+,D՜.+, PXd lt| 1  Sheet1  Worksheets 6> _PID_GUIDAN{770A2188-7A64-42CE-B76C-9F07410461EC}  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJLMNOPQRTUVWXYZRoot Entry FWorkbook"SummaryInformation(KDocumentSummaryInformation8SSpreadsheet-ParseExcel-0.66/t/excel_files/long_string4.xls000644 000765 000024 00000127000 11247565351 023705 0ustar00Johnstaff000000 000000 ࡱ> UT  \pUsername Ba==x[J8X@"1Arial1Arial1Arial1Arial+" "#,##0;\-" "#,##05" "#,##0;[Red]\-" "#,##07" "#,##0.00;\-" "#,##0.00A" "#,##0.00;[Red]\-" "#,##0.00e*0_-" "* #,##0_-;\-" "* #,##0_-;_-" "* "-"_-;_-@_-,)'_-* #,##0_-;\-* #,##0_-;_-* "-"_-;_-@_-u,8_-" "* #,##0.00_-;\-" "* #,##0.00_-;_-" "* "-"??_-;_-@_-4+/_-* #,##0.00_-;\-* #,##0.00_-;_-* "-"??_-;_-@_-                + ) , *  `܅Sheet1a Foo:&This is a test stringSmiley :&]xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx< xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx< xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx<ixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxz:& Ph|@|=|||p0sp )TEھ-XZ0TELP`TETE0long_string4.xls|  ĺ||Ir0))R|,)S0dt00ȹ%4|^n00 00Ԣ00)tb0`)Percent0]`,\|`Xe0XZT00ZT0_T0=l0~Pe0P~0~PH? 0H-=NJT0e0YT0L0YT0LNJT0»Ȼk0 $Ȇ0TDȻDC0<(̻c0G0D   Z  dMbP?_*+%"??NJUT0     P>@ Oh+'08@Th  Username  Username Microsoft Excel@ _PID_GUIDAN{3CEF595A-A1B2-4A8E-954C-BC8DC6F01417}  !"#$%&'()*+,-./0123456789:;<=>?@ABCEFGHIJKMNOPQRSRoot Entry FWorkbookSummaryInformation(DDocumentSummaryInformation8LSpreadsheet-ParseExcel-0.66/t/excel_files/long_string6.xls000644 000765 000024 00000143000 11247565351 023705 0ustar00Johnstaff000000 000000 ࡱ> a`  \pUsername Ba==wkI,8X@"1Arial1Arial1Arial1Arial+" "#,##0;\-" "#,##05" "#,##0;[Red]\-" "#,##07" "#,##0.00;\-" "#,##0.00A" "#,##0.00;[Red]\-" "#,##0.00e*0_-" "* #,##0_-;\-" "* #,##0_-;_-" "* "-"_-;_-@_-,)'_-* #,##0_-;\-* #,##0_-;_-* "-"_-;_-@_-u,8_-" "* #,##0.00_-;\-" "* #,##0.00_-;_-" "* "-"??_-;_-@_-4+/_-* #,##0.00_-;\-* #,##0.00_-;_-* "-"??_-;_-@_-                + ) , *  `rSheet1a Foo:&This is a test stringSmiley :&yxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx< xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx< xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx< xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx<xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxz:& C  q0CP0"q0+q0 :-TC JVrE-XZ0rELP`rErE0| ĺ||Ir0BVBVR|,LVS0dt00ȹ%4|^n00 00Ԣ00LVtb0UPercent0]0,h\|`Xe0XZT00ZT0_T0=l0~Pe0P~0~PH? 0H-=NJT0e0YT0L0YT0LNJT0»Ȼk0 $Ȇ0TȻC0T̻c0G0   .  dMbP?_*+%"??NJUT0     P>@ Oh+'08@Th  Username  Username Microsoft Excel@'4u՜.+,D՜.+, PXd lt| 1  Sheet1  Worksheets 6> _PID_GUIDAN{B9D10684-E99F-41BE-A938-C94605A14901}  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOQRSTUVWYZ[\]^_Root Entry FWorkbook/SummaryInformation(PDocumentSummaryInformation8XSpreadsheet-ParseExcel-0.66/t/excel_files/long_string7.xls000644 000765 000024 00000144000 11247565351 023707 0ustar00Johnstaff000000 000000 ࡱ> ba  \pUsername Ba==Y6#8X@"1Arial1Arial1Arial1Arial+" "#,##0;\-" "#,##05" "#,##0;[Red]\-" "#,##07" "#,##0.00;\-" "#,##0.00A" "#,##0.00;[Red]\-" "#,##0.00e*0_-" "* #,##0_-;\-" "* #,##0_-;_-" "* "-"_-;_-@_-,)'_-* #,##0_-;\-* #,##0_-;_-* "-"_-;_-@_-u,8_-" "* #,##0.00_-;\-" "* #,##0.00_-;_-" "* "-"??_-;_-@_-4+/_-* #,##0.00_-;\-* #,##0.00_-;_-* "-"??_-;_-@_-                + ) , *  `Sheet1a Foo:&This is a test stringSmiley :&1uxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx< xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx< xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxz:&xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx< xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx<xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxz h|@|=|||p0sp z`rھ-XZ0`rLP``r`r0long_string7.xls| Xĺ||Ir0rrR|,|S0dt00ȹ%4|^n00 00Ԣ00|tb0 Percent0]0X,hX\|`Xe0XZT00ZT0_T0=l0~Pe0P~0~PH? 0H-=NJT0e0YT0L0YT0LNJT0»Ȼk0 $Ȇ0T,MPjPȻ,MPC0<8LP̻c08LPG0,MPj   h*  dMbP?_*+%"??NJUT0     P>@ Oh+'08@Th  Username  Username Microsoft Excel@kfNu՜.+,D՜.+, PXd lt| 1  Sheet1  Worksheets 6> _PID_GUIDAN{267144A1-92DE-48AD-AB04-63967F85DE9D}  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPRSTUVWXZ[\]^_`Root Entry FWorkbookiSummaryInformation(QDocumentSummaryInformation8YSpreadsheet-ParseExcel-0.66/t/excel_files/long_string3.xls000644 000765 000024 00000120000 11247565351 023675 0ustar00Johnstaff000000 000000 ࡱ> NM  \pUsername Ba==J8X@"1Arial1Arial1Arial1Arial+" "#,##0;\-" "#,##05" "#,##0;[Red]\-" "#,##07" "#,##0.00;\-" "#,##0.00A" "#,##0.00;[Red]\-" "#,##0.00e*0_-" "* #,##0_-;\-" "* #,##0_-;_-" "* "-"_-;_-@_-,)'_-* #,##0_-;\-* #,##0_-;_-* "-"_-;_-@_-u,8_-" "* #,##0.00_-;\-" "* #,##0.00_-;_-" "* "-"??_-;_-@_-4+/_-* #,##0.00_-;\-* #,##0.00_-;_-* "-"??_-;_-@_-                + ) , *  `xSheet1a Foo:&This is a test stringSmiley :&]:&xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx< xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx< xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx< xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxz ؟h|@|=|||p0sp )ԍEھ-XZ0ԍELP`ԍEԍE0long_string3.xls| ĺ||Ir0))R|,)S0dt00ȹ%4|^n00 00Ԣ00)tb0`)Percent0]`,\|`Xe0XZT00ZT0_T0=l0~Pe0P~0~PH? 0H-=NJT0e0YT0L0YT0LNJT0»Ȼk0 $Ȇ0TDȻDC0<(̻c0G0D   xy  dMbP?_*+%"??NJUT0     P>@ Oh+'08@Th  Username  Username Microsoft Excel@Q3Ju՜.+,D՜.+, PXd lt| 1  Sheet1  Worksheets 6> _PID_GUIDAN{6BD243D6-755B-43CE-B872-B1189749B86D}  !"#$%&'()*+,-./0123456789:;<>?@ABCDFGHIJKLRoot Entry FWorkbookySummaryInformation(=DocumentSummaryInformation8ESpreadsheet-ParseExcel-0.66/t/excel_files/long_string2.xls000644 000765 000024 00000110000 11247565351 023673 0ustar00Johnstaff000000 000000 ࡱ> FE  \pUsername Ba==X5"8X@"1Arial1Arial1Arial1Arial+" "#,##0;\-" "#,##05" "#,##0;[Red]\-" "#,##07" "#,##0.00;\-" "#,##0.00A" "#,##0.00;[Red]\-" "#,##0.00e*0_-" "* #,##0_-;\-" "* #,##0_-;_-" "* "-"_-;_-@_-,)'_-* #,##0_-;\-* #,##0_-;_-* "-"_-;_-@_-u,8_-" "* #,##0.00_-;\-" "* #,##0.00_-;_-" "* "-"??_-;_-@_-4+/_-* #,##0.00_-;\-* #,##0.00_-;_-* "-"??_-;_-@_-                + ) , *  `vgSheet1a Foo:&This is a test stringSmiley :&>xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx< xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx<'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxz:& 0T0@ *@0H1.0o0$0ɍ0Ir0""0  0go,<S0|t00ange|D^n00 00Ԣ00<tb0̡Percent0]| `TT(||Xe0XZT00ZT0_T0=l0~Pe0P~0~PH? 0H-=NJT0e0YT0L0YT0LNJT0k0 $Ȇ0l$C0'c0'G0$   2hh  dMbP?_*+%"??NJUT0     P>@ Oh+'08@Th  Username  Username Microsoft Excel@:/Gs՜.+,D՜.+, PXd lt| 1  Sheet1  Worksheets 6> _PID_GUIDAN{741E731C-CA5A-4B79-9BE6-5FD5EE469ED6}  !"#$%&'()*+,-./012346789:;<>?@ABCDRoot Entry F`L>tWorkbook3iSummaryInformation(5DocumentSummaryInformation8=Spreadsheet-ParseExcel-0.66/t/excel_files/pers-encrypted-def-pass-QwErTyUiOp.xls000755 000765 000024 00000022000 11547123164 027716 0ustar00Johnstaff000000 000000 ࡱ>  Root Entry FphaWorkbookOle SummaryInformation( Oh+'0d08 D P\m@@VJZ՜.+,0HP X`hp x ' 123   /6eİO߃RZc{"=u'U^:N\\pfS_o '@ 2Lgӳyu%\ x$ۉ*-xqwAt-!Q0e{ &_&({R95wSR`k̳u`oOӂL#4UBa]=P09aɒʡμH=FZ@g'EdPE@wɍH"T`]1*J^J_~b`=AjRJ1a[l>A$xl>139d$xHvk@1ɧyhkGAL~]f1y`` 5gJIfP:3/4HD0d%Hєe$84dbn EEo!Ĕ,j=P_9ᅓ͌^D÷s!W 4A4/K-Zr-+ ;:_q:dvxH//+]`O n7)ygx4 md$hdEK> z5c?sw8e"8u;hHo5ܘ:;#XAB\_<u'8cDK=7vu#WJd@yC: 8<2xXQ @2[vБ jN]Vڒ-;;ƚq1..g}V)xT;.$F-=Kd(Ђ&5YSΙ w. )Z_={d~ % N+/la4"lnzt4\2U8> ?FF$6Rbɋ6b8!kH|N %!ܭ,5zCҭenuLsa_kpZSM"[V$w忬C0s$bɤkWцLP;9,H>Kw Ksk*?Ye6\3nŰO2$tO`9]#'nrN,#"Q2c%M6ͪ%z>b, _,R6RM wTټ6 =tܴcv;6zH)ZTj   2`ދh)o j[ T[h[H9&_w*͑+Pт|ʀ&M>%tk,3!qe; [Z{*SHK_Ah &.)hB*'o_H(2%!Y') -M* \Kߔ(TthD8.ZLL+$9<>Ԉ`Br4LQAA|~tT%k 3vNo]67I\^:h)J2~ư:RYD81rDeU#"Jm2"]w۝NXU%V+ίiEdºf8{anN40ꬃg *CDEJny ^oRpF6lױPVe;cJ LjҦ{mɾI5MqhG/w XnJ"j-[q ZXB]鐗[)c#tᢩ={Ct $Ӆ¾_&z{beM1sNΨR bLG([w/2LOaXC@CD1 `f$>m !"k/"uPkf I%0{h2raL"(;Xm`# O9lI+[K!B^q)F=I`n(>%.ѼDUOLqͿt@y@ H4caw*$p#Bgpقq-di-NǨ ϜpƃʲW(Z }y\3E,OLIۺ{):4| /|Ȭ#6DO< ;Կu\ZiKZioHQp˜A621vT+Gc|xC}qlLך~e |m]5uTS-3cryR%`:Q\v|UlINV+M>۫ȣ8P'iNf݀{tf!zYb^cC}っ{t >y4WR[M.iͦe%QL;P.=;B=h'4uRQU$(58QΚ]-ocC"hs W c%Bd 4j.D! 2ȾaC"p;xnHsEҵOߛwKm >L,2 6aBxMih\*ġ"#? :,{9T-Y S!(<DŽ-U} ֐ֳie} ## MeS} JW(ns`lhCgkY镄n\D &)F$DB% eDDV쿨|MǻٱG~EI8yC mџ;9 vפJB7D盷UqR7Q'oI_&Tf/X/WXwԄj@w#mpFd+QNIzf $-3IJ`G&%$N\tٽIl I.'|#y(vC'J/+-{8Y5X  <̡}~S#OҒ[2ͩCoCIJ3cC rӿ-LsK7`8FȰzt)>'/roK[a;0uڍ9Z\ywgxfY}#\\   (Ъ u- k(  <dBgx{a_*+S8C9<`%z%wRw<8 # -dC**\- ޵G& =h'bx\Q%()T)-XCơ""k!aIz=ޏ Vj\ MUeKLڱYh>*4M:`9zxw#Wv73߯' _$vg/e Ⱥ˚WͱD   Bvs4>*i~ ~k  _4v*w+j‚#)A:s%IU X zg O ؊uvdHzW.# j|>[&Vn :Z'7N>(5$ )2p\ژ˜"ӹKaV\=֠m"8&8Rc$3e8Uz-FJ<]>W+o 1&Y"b֢T4 ȂJAiuT@^3gVoKJajAK 0Y DocumentSummaryInformation8CompObjh F Microsoft Office ExcelBiff8Excel.Sheet.89qSpreadsheet-ParseExcel-0.66/t/excel_files/Test2000J.xls000755 000765 000024 00000033000 11247565351 022626 0ustar00Johnstaff000000 000000 ࡱ>  @\p John McNamara Ba==Z|)8X@"1 -3 000001 -3 000001 -3 000001 -3 000001 -3 000001 x-3 000001  -3 000001 $-3 00000"\"#,##0;"\"\-#,##0"\"#,##0;[Red]"\"\-#,##0"\"#,##0.00;"\"\-#,##0.00#"\"#,##0.00;[Red]"\"\-#,##0.007*2_ "\"* #,##0_ ;_ "\"* \-#,##0_ ;_ "\"* "-"_ ;_ @_ .))_ * #,##0_ ;_ * \-#,##0_ ;_ * "-"_ ;_ @_ ?,:_ "\"* #,##0.00_ ;_ "\"* \-#,##0.00_ ;_ "\"* "-"??_ ;_ @_ 6+1_ * #,##0.00_ ;_ * \-#,##0.00_ ;_ * "-"??_ ;_ @_ \$#,##0_);\(\$#,##0\)\$#,##0_);[Red]\(\$#,##0\) \$#,##0.00_);\(\$#,##0.00\)% \$#,##0.00_);[Red]\(\$#,##0.00\)                  & (    :  9    !  " 8      `Sheet1QQ`is^b50000fl5000'Yck500000-fT50000eN5000Bf;R5000'This is a test file for Japanese format 5 r @ @   dMbP?_*+%"Mb?Mb?U} }    `t@@v@ н@^@  @@ @@ `@`@ rq?rq?x$$$$$>@ 5 Oh+'0@HXh GorofGorofMicrosoft Excel@,V@5 ?>  \pUsername Ba==Z7$8X@"1Arial1Arial1Arial1Arial+" "#,##0;\-" "#,##05" "#,##0;[Red]\-" "#,##07" "#,##0.00;\-" "#,##0.00A" "#,##0.00;[Red]\-" "#,##0.00e*0_-" "* #,##0_-;\-" "* #,##0_-;_-" "* "-"_-;_-@_-,)'_-* #,##0_-;\-* #,##0_-;_-* "-"_-;_-@_-u,8_-" "* #,##0.00_-;\-" "* #,##0.00_-;_-" "* "-"??_-;_-@_-4+/_-* #,##0.00_-;\-* #,##0.00_-;_-* "-"??_-;_-@_-                + ) , *  `XSheet1a Foo:&This is a test stringSmiley :&>:&xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx< xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx<txxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxz 0T0@ 9@0H1.0o0$0ɍ0Ir0990  0go,9S0|t00ange|D^n00 00Ԣ009tb049Percent0]|0TTax0\XT0Xe0XZT00ZT0_T0=l0~Pe0P~0~PH? 0H-=NJT0e0YT0L0YT0LNJT0k0 $Ȇ0lC08,%c0,%G0   YAZ  dMbP?_*+%"??NJUT0     P>@ Oh+'08@Th  Username  Username Microsoft Excel@טs՜.+,D՜.+, PXd lt| 1  Sheet1  Worksheets 6> _PID_GUIDAN{A447B2C4-10ED-41D5-8CDC-141D92CB15AF}  !"#$%&'()*+,-/012345789:;<=Root Entry FPuWorkbookZSummaryInformation(.DocumentSummaryInformation86Spreadsheet-ParseExcel-0.66/t/excel_files/Dates1904.xls000644 000765 000024 00000033000 11247565351 022646 0ustar00Johnstaff000000 000000 ࡱ>  \p John McNamara Ba==hx78X@"1Arial1Arial1Arial1Arial"$"#,##0_);\("$"#,##0\)!"$"#,##0_);[Red]\("$"#,##0\)""$"#,##0.00_);\("$"#,##0.00\)'""$"#,##0.00_);[Red]\("$"#,##0.00\)7*2_("$"* #,##0_);_("$"* \(#,##0\);_("$"* "-"_);_(@_).))_(* #,##0_);_(* \(#,##0\);_(* "-"_);_(@_)?,:_("$"* #,##0.00_);_("$"* \(#,##0.00\);_("$"* "-"??_);_(@_)6+1_(* #,##0.00_);_(* \(#,##0.00\);_(* "-"??_);_(@_)$[$-409]dddd\,\ mmmm\ dd\,\ yyyyyyyy\-mm\-d\Thh:mm:ss.000                + ) , *      `Sheet1"cc  6  dMbP?_*+%"??yyU} m} $~  *DA>@7 Oh+'0@H`x John McNamaraJohn McNamaraMicrosoft Excel@$@r$՜.+,0 PXd lt| ' Sheet1  Worksheets Root Entry F   /6 lo8-3U8WILv}垭R8iKz8=/xFkSս\pqXB] B9/8A"i[:u=o$m7n3&wͻh K*ڼA{}*kW$]6j~@?K| c`B al=*Is"=dNCkLkpp^%@:""pʷX1ž#@O)f*OW_[1D(d#嬘7~0/1279d X04s ]1.(FZ믊@\ 0Gek@';6I K,]U+N-L]sD9ҁasCK룴`rDy3rf5`E׳7q#Oְ\_3L:4X"'ø/ʛ B;5|}ztG"Ѭ0\`0׺a0\jGunr,WБ:>lp F5߸\mD=v5}D>sm*zF=N;#XkW1ҍ&M D\wki׆#k,၂8xwǭ%s~Ԝ4;#!neX1E,euAn2C997^SuȗFc9=,t'(j1RGea~$p7|sIHWuw2dcj7@kj7Im gkݧl˃|!B=ԍo ߂ᘘ77!-$XEjRNvF6YyB5.N 9w`EjgI[ֹ@ \M*F6HP{:JIwwҗ-OZw Ǻb&Io}״{,JU1q!UnuXr,emx#ޅIHIt]9Z6O`7>N#6E a0,h+Vb1 Ny[+ȁވ8ʡPA! U4bQ6SU{~%ۈ1Ϸ\}H|&"CžIƽ7[2`㝅 >Ĝ]8HQ+n4ki"6LDS av<(vPh &PfȦwTDT PU5_sHS5Ê=zj_Ν>gyd "n,*+-[ml qc Nߞd[^XY^dž"*M,LՓT e} $"̜s1qU"x9}30 9U$:~̄8J#q$?GX|#5 &7ݙ!V"($앱ʿɁ}ٍh#2eZdW'd$˟f2Ϥӂn gNP)~A*V wK BF/'G^-;]פ*n oH/K\ )<=[Aӿk "񣻽ϼ^w 6k\u GVࡀqJj<,9P'jFRI-Cc2…P&u R0̕H Wm;)hAED>c,\a}A-@k1׎ZL>^]LDђ;z%_*/1 Oh+'08@Xp John McNamaraxJohn McNamaraxMicrosoft Excel@|y՜.+,D՜.+, PXd lt| 1  Sheet1  Worksheets 6> _PID_GUIDAN{2729D1DB-BC83-40E8-9533-1AC40A3BE9F6} Root Entry FWorkbookSummaryInformation(DocumentSummaryInformation8Spreadsheet-ParseExcel-0.66/t/excel_files/Test97J.xls000755 000765 000024 00000041000 11247565351 022503 0ustar00Johnstaff000000 000000 ࡱ>  Root Entry FP nWorkbook _VBA_PROJECT_CUR"  7VBA{  !"#$%&'()*+,-/0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\^_`abcdefgiklmnoprstvwxyz{} @ ~ @ ~  `@ c!2A !c!3AMb DD  ~ W4o  @5 Sheet1    dMbP?_*+%"Mb?Mb?U} 7E8Ⱥ     ~ @ ~ @ ~  `@ c!2A !c!3AMb DD   3>@  5 Sheet2 ThisWorkbookSheet1Sheet2_VBA_PROJECT. x# (SLSS<N0{00020819-0000-0000-C000-000000000046}8($HMExAttribute VB_Name = "ThisWorkbook" Bas0{00020P819-0C$0046} |CreatablFalse ^PredeclaIdTru "@ExposeTemplateD0eriv$eCustomiz20n00@0~gB|gn~x# (SLSS<N0{00020820-0000-0000-C000-000000000046}8 \pkawait Ba= ThisWorkbook= >G"8X@"1 -3 000001 -3 000001 -3 000001 -3 000001 x-3 00000"\"#,##0;"\"\-#,##0"\"#,##0;[Red]"\"\-#,##0"\"#,##0.00;"\"\-#,##0.00#"\"#,##0.00;[Red]"\"\-#,##0.007*2_ "\"* #,##0_ ;_ "\"* \-#,##0_ ;_ "\"* "-"_ ;_ @_ .))_ * #,##0_ ;_ * \-#,##0_ ;_ * "-"_ ;_ @_ ?,:_ "\"* #,##0.00_ ;_ "\"* \-#,##0.00_ ;_ "\"* "-"??_ ;_ @_ 6+1_ * #,##0.00_ ;_ * \-#,##0.00_ ;_ * "-"??_ ;_ @_ \$#,##0_);\(\$#,##0\)\$#,##0_);[Red]\(\$#,##0\) \$#,##0.00_);\(\$#,##0.00\)% \$#,##0.00_);[Red]\(\$#,##0.00\) "f_k0"oW[:"@                 & (       `! Sheet1-ASC0"oW[ TQQ ASC 5Date 5This Data is 'ASC Only' 5INTEGER 5Double 5Float 5Formula 5&"oW[0eQ0"500000"oW[n00005000Data 5 BIG INTEGER 5Float  `)stdole f%\*\G{00020430-C 0046}#2.0#0#C:\WINNT\System32\c2.tldir]PROJECTwmhSPROJECT jSummaryInformation( qb#OLE Automation#^MSForms>!SFErms/z pF148D6DF0-924B-11D3-94D6AF90CK1ADFF3.TWD#MicrosPoft = ` Ob Library90-{?4?RECYCLER\S-70DB~1\DC0\VBE\ EEX".E .`0M ACrOf(ficDrO@oficBr./2DF8D04C-5BFA-101B-BDE5OAA@q42Ogram FilXes\K\MSO97.DLLCHT 8.0TBBThisWor@kbookN2D@1Th@6sDWkbokHB1¼B,B"B +BSheet12S@e@Pt1dUj2H2M2 b "ThisWorkbookThisWorkbookSheet1Sheet1Sheet2Sheet2ID="{BDFD977E-950A-11D4-95F2-0090CC001ADF}" Document=ThisWorkbook/&H00000000 Document=Sheet1/&H00000000 Document=Sheet2/&H00000000 Name="VBAProject" HelpContextID="0" CMG="2624D47A2C8A9C8E9C8E9C8E9C8E" DPB="929060EECDEFCDEFCD" GC="FEFC0C821482818381837E" [Host Extender Info] &H00000001={3832D640-CF90-11CF-8E43-00A0C911005A};VBE;&H00000000 [Workspace] ThisWorkbook=0, 0, 0, 0, C Sheet1=0, 0, 0, 0, C Sheet2=0, 0, 0, 0, C Oh+'08@dt Kawai, Takanori (Hippo2000)kawaitTMicrosoft Excel@Ǻ"՜.+,D՜.+,$ PXt | {bh1DocumentSummaryInformation8uCompObj|c  Sheet1-ASC ܰ 6> _PID_GUIDAN{87BA1E80-8E98-11D4-95E0-0090CC001ADF} FMicrosoft Excel ܰBiff8Excel.Sheet.89qSpreadsheet-ParseExcel-0.66/t/excel_files/Test95.xls000755 000765 000024 00000034000 11247565351 022371 0ustar00Johnstaff000000 000000 ࡱ>  \pkawait B=.>G"8X@"1lr oSVbN1lr oSVbN1lr oSVbN1lr oSVbN1xlr oSVbN"\"#,##0;"\"\-#,##0"\"#,##0;[Red]"\"\-#,##0"\"#,##0.00;"\"\-#,##0.00!"\"#,##0.00;[Red]"\"\-#,##0.005*2_ "\"* #,##0_ ;_ "\"* \-#,##0_ ;_ "\"* "-"_ ;_ @_ ,))_ * #,##0_ ;_ * \-#,##0_ ;_ * "-"_ ;_ @_ =,:_ "\"* #,##0.00_ ;_ "\"* \-#,##0.00_ ;_ "\"* "-"??_ ;_ @_ 4+1_ * #,##0.00_ ;_ * \-#,##0.00_ ;_ * "-"??_ ;_ @_ \$#,##0_);\(\$#,##0\)\$#,##0_);[Red]\(\$#,##0\)\$#,##0.00_);\(\$#,##0.00\)# \$#,##0.00_);[Red]\(\$#,##0.00\)                 & (     83ffff̙3f3fff3f3f33333f33333~ Sheet1-ASC Sheet1-ASC (2)  & "  dMbP?_*+%QQM\\Lins\lp`!W0`%W0`N 4dhhpyw`!W084 *** qhhDLLName32=e_du01jj.dll L dL 2EPSON PM-800C" dMb?Mb?U} `  8D ASCThis Data is 'ASC Only' Date~ @INTEGER~ @ Float~  `@Doublec!2AFormulac!3Aa i DDBIG NUMq= T4oA BIG INTEGERB2!$6%=.>G"8X> "  C  dMbP?_*+%QQM\\Lins\lpTEGER DD`N 4dhhpyw`!W084 *** qhhDLLName32=e_du01jj.dll L dL 2EPSON PM-800C" dMb?Mb?U} `  8D ASCThis Data is 'ASC Only' Date~ @INTEGER~ @ Float~  `@Doublec!2AFormulac!3Aa i DDbd2!$=.>G"8X>   " Oh+'08@dt Kawai, Takanori (Hippo2000)kawaitTMicrosoft Excel@Ǻ"՜.+,08@ \d l {bhp  Sheet1-ASCSheet1-ASC (2) ܰ Root Entry MiF@uBook#$%&'()*+,-./0123456789:;<= FGHIJKLMNOPQRSTUVW>\]SummaryInformationrstuvwxyz{|}( DocumentSummaryInformationz{|}8Spreadsheet-ParseExcel-0.66/t/excel_files/pers-protected.xls000755 000765 000024 00000022000 11547123164 024224 0ustar00Johnstaff000000 000000 ࡱ>  Root Entry F>gcS\@Workbook!Ole SummaryInformation(Oh+'0P(0 <Hl@-՜.+,0HP X`hp x ' 123  F Microsoft Office Excel  /6J*I.ʃ:g?Yn^k{)pۀ(J*\Y'$/-B\pr{}K>*n'r!$N cJH& `8FytL1%>_fdQ\$ I{v&Ƃqرݴb,uUDBa5==bWl0nrŪ=۬W⃭@?g"VHCu1yb?-L&{vA1NōσE_NnxYۉ0s71ώh(a6IU9p$<` +1yh/ GҔN1/IkСC ¿NGK/? .Zl~tH PR<<ؘ~uQib;#s_I;9'<,D QRv}^wzw{logϥd񭶭;;LyfYĊA4~i~iH dxb>4~]g>*ajkVNEySC(Dy%khذKq"9th6ޱ79ۡfwʲe8T҆=jkGf¥˛\V2(љ>!sS9{qZ0W !dO3⍛&AALχT5lTip ȡ-@Vk*4P x0@1 n HIRC !Re+-*@t1+P`-g$\$'9~|dI$0=d!&W#ʷlGfX{ixWRUѻGCbcޖ.TNz} Ўy!H*`Rr|L& Dd ReaOhE⪐Ѱ-7nLz[(<[늻a_KVJgn<́3[:{]7iL٦_6ސo3eqX )\%b0ew<#+N?Ow1s!h#b%6*q~' h~w#^`E_5zayQ[nx;/k,LY"b}K#5{4X<`y+HCk=Xj3IlbpUՀhV8ɜ輁ý&NY3闯>ߡ HTI#vƂ%hypr6 xX\'. _!!!DKpVӏ龱L^OG*1USm)[52iFv8RKq/Acw򜇘,E e;"\oW&G#> 0ȡYZzDѪp2~K/,97Z]w׼ȄЦ" v0K 1dx<wCZ^I1da"N2;v ]"XǺ'֪ dHC0sú'n]cF3U3N} lfDt} %C } 79 R ܌~WcQ#)fK"WIuK)F00!}Ƙ݇+G#(*G?sҕ>7aF qZt]BL. vbPYz;(pj #ʲA,$=h/Z#w䷳;A펣#2w':wY6.kiozc;:v$z 0Ht!_HplҧS&!p&,>ٺ]4{0%q5W\MmCmͽYb& ![-|߽(Lz2PˁA6/RK]zkܾdT y350F𨡚|H_nX1lhע<0df)G0Q<]@^\(R+ cm(ŠܡX#GprCC%)r4m(URaQIrX$`,GŐU4> J@hr~?>}mEr˵ExjE{Wgbunx.h3x   YNv^kl  ɮ#'}<_{*2+DĂCЪ]@%dMZ_߇X߾ ϡ!')ޚYТ {js ]=Q&WPۡ'(.KY/Ӯ):Bw"ZTcLJpFYH4|lo,oUI*ԑί+q^ug>5g&_W_٫/ }me  p"dg+EV$U²DjG10 %t    8r¬  }{VTqfk1_b*E+&Y7lQ%.vG"C'%Ey'I* # {B_պ&Ԋ- '&#`(c1nAS)FQ^~s"IGcL5(cjUC"$,wb UsT >9lHk@OnR~> T`DA5>>gڽxem{ZT:'Q DocumentSummaryInformation8CompObjhBiff8Excel.Sheet.89q