From 6f432847bdaa67ead8bc91c253b911b7e1674db7 Mon Sep 17 00:00:00 2001 From: Arthit Suriyawongkul Date: Sat, 19 Sep 2026 09:19:44 +0100 Subject: [PATCH] Add ODS spreadsheet support Based on ODS support in spdx-java-spreadsheet-store Signed-off-by: Arthit Suriyawongkul --- .gitignore | 1 + README.md | 1 + .../java/org/spdx/tools/SpdxConverter.java | 8 +-- .../java/org/spdx/tools/SpdxToolsHelper.java | 6 +- src/main/java/org/spdx/tools/SpdxViewer.java | 8 +-- src/main/java/org/spdx/tools/Verify.java | 8 +-- .../org/spdx/tools/SpdxConverterTestV2.java | 53 +++++++++++++++++- src/test/java/org/spdx/tools/VerifyTest.java | 3 + testResources/SPDXSpreadsheetExample-v2.3.ods | Bin 0 -> 19769 bytes 9 files changed, 74 insertions(+), 14 deletions(-) create mode 100644 testResources/SPDXSpreadsheetExample-v2.3.ods diff --git a/.gitignore b/.gitignore index 5f18d50..ceb4641 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,4 @@ buildNumber.properties # IntelliJ IDE .idea +.DS_Store diff --git a/README.md b/README.md index 86186c7..a004a28 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,7 @@ The following converter tools support SPDX format: * Tag * RDF/XML +* ODS Spreadsheet * XLSX Spreadsheet * XLS Spreadsheet * JSON diff --git a/src/main/java/org/spdx/tools/SpdxConverter.java b/src/main/java/org/spdx/tools/SpdxConverter.java index b1876c9..6454d37 100644 --- a/src/main/java/org/spdx/tools/SpdxConverter.java +++ b/src/main/java/org/spdx/tools/SpdxConverter.java @@ -42,8 +42,8 @@ * Converts between various SPDX file types * arg[0] from file path * arg[1] to file path - * arg[2] from file type [RDFXML|RDFTTL|JSON|XLS|XLSX|YAML|TAG] - if not present, file type of the from file will be used - * arg[3] to file type [RDFXML|RDFTTL|JSON|XLS|XLSX|YAML|TAG] - if not present, file type of the to file will be used + * arg[2] from file type [RDFXML|RDFTTL|JSON|ODS|XLS|XLSX|YAML|TAG] - if not present, file type of the from file will be used + * arg[3] to file type [RDFXML|RDFTTL|JSON|ODS|XLS|XLSX|YAML|TAG] - if not present, file type of the to file will be used * arg[4] excludeLicenseDetails If present, listed license and listed exception properties will not be included in the output file * * the covert(...) methods can be called programmatically to convert files @@ -368,8 +368,8 @@ private static void usage() { System.out.println("SpdxConverter fromFilePath toFilePath [fromFileType] [toFileType]"); System.out.println("\tfromFilePath - File path of the file to convert from"); System.out.println("\ttoFilePath - output file"); - System.out.println("\t[fromFileType] - optional file type of the input file. One of JSON, XLS, XLSX, TAG, RDFXML, RDFTTL, YAML, XML or JSONLD. If not provided the file type will be determined by the file extension"); - System.out.println("\t[toFileType] - optional file type of the output file. One of JSON, XLS, XLSX, TAG, RDFXML, RDFTTL, YAML, XML or JSONLD. If not provided the file type will be determined by the file extension"); + System.out.println("\t[fromFileType] - optional file type of the input file. One of JSON, XLS, XLSX, ODS, TAG, RDFXML, RDFTTL, YAML, XML or JSONLD. If not provided the file type will be determined by the file extension"); + System.out.println("\t[toFileType] - optional file type of the output file. One of JSON, XLS, XLSX, ODS, TAG, RDFXML, RDFTTL, YAML, XML or JSONLD. If not provided the file type will be determined by the file extension"); System.out.println("\t[excludeLicenseDetails] - If present, listed license and listed exception properties will not be included in the output file"); } diff --git a/src/main/java/org/spdx/tools/SpdxToolsHelper.java b/src/main/java/org/spdx/tools/SpdxToolsHelper.java index 59ab84e..50d7529 100644 --- a/src/main/java/org/spdx/tools/SpdxToolsHelper.java +++ b/src/main/java/org/spdx/tools/SpdxToolsHelper.java @@ -62,7 +62,7 @@ public class SpdxToolsHelper { * Supported serialization file types */ public enum SerFileType { - JSON, RDFXML, XML, XLS, XLSX, YAML, TAG, RDFTTL, JSONLD + JSON, RDFXML, XML, ODS, XLS, XLSX, YAML, TAG, RDFTTL, JSONLD } static final String XML_INPUT_FACTORY_PROPERTY_KEY = "javax.xml.stream.XMLInputFactory"; @@ -77,6 +77,7 @@ public enum SerFileType { temp.put("rdf.xml", SerFileType.RDFXML); temp.put("rdf", SerFileType.RDFXML); temp.put("xml", SerFileType.XML); + temp.put("ods", SerFileType.ODS); temp.put("xls", SerFileType.XLS); temp.put("xlsx", SerFileType.XLSX); temp.put("yaml", SerFileType.YAML); @@ -115,6 +116,9 @@ public static ISerializableModelStore fileTypeToStore(SerFileType fileType) } case TAG : return new TagValueStore(new InMemSpdxStore()); + case ODS : + return new SpreadsheetStore(new InMemSpdxStore(), + SpreadsheetFormatType.ODS); case XLS : return new SpreadsheetStore(new InMemSpdxStore(), SpreadsheetFormatType.XLS); diff --git a/src/main/java/org/spdx/tools/SpdxViewer.java b/src/main/java/org/spdx/tools/SpdxViewer.java index 5316c4e..609cdb6 100644 --- a/src/main/java/org/spdx/tools/SpdxViewer.java +++ b/src/main/java/org/spdx/tools/SpdxViewer.java @@ -55,7 +55,7 @@ public class SpdxViewer { * * Main entry point for the SpdxViewer tool. * Delegates to {@link #run(String[])} and terminates the JVM with its exit status. - * @param args args[0] SPDX file path; args[1] [RDFXML|JSON|XLS|XLSX|YAML|TAG] an optional file type - if not present, file type of the to file will be used + * @param args args[0] SPDX file path; args[1] [RDFXML|JSON|ODS|XLS|XLSX|YAML|TAG] an optional file type - if not present, file type of the to file will be used */ public static void main(String[] args) { System.exit(run(args)); @@ -64,15 +64,15 @@ public static void main(String[] args) { /** * Runs the SpdxViewer command logic and reports results to standard * out/error. - * @param args args[0] SPDX file path; args[1] [RDFXML|JSON|XLS|XLSX|YAML|TAG] an optional file type - if not present, file type of the to file will be used + * @param args args[0] SPDX file path; args[1] [RDFXML|JSON|ODS|XLS|XLSX|YAML|TAG] an optional file type - if not present, file type of the to file will be used * @return process exit status, see {@link ExitCode} */ static int run(String[] args) { if (args.length < MIN_ARGS) { System.err - .println("Usage:\n SPDXViewer file [RDFXML|JSON|XLS|XLSX|YAML|TAG] \n" + .println("Usage:\n SPDXViewer file [RDFXML|JSON|ODS|XLS|XLSX|YAML|TAG] \n" + "where file is the file path to a valid SPDX file\n" - + "and [RDFXML|JSON|XLS|XLSX|YAML|TAG|JSONLD] is an optional file type\n" + + "and [RDFXML|JSON|ODS|XLS|XLSX|YAML|TAG|JSONLD] is an optional file type\n" + "if not present, file type of the to file will be used"); return ExitCode.USAGE_ERROR; } diff --git a/src/main/java/org/spdx/tools/Verify.java b/src/main/java/org/spdx/tools/Verify.java index 64056b7..dbfe847 100644 --- a/src/main/java/org/spdx/tools/Verify.java +++ b/src/main/java/org/spdx/tools/Verify.java @@ -71,7 +71,7 @@ public class Verify { /** * Main entry point for the Verify tool * - * @param args args[0] SPDX file path; args[1] [RDFXML|JSON|XLS|XLSX|YAML|TAG] an optional file type - if not present, file type of the to file will be used + * @param args args[0] SPDX file path; args[1] [RDFXML|JSON|ODS|XLS|XLSX|YAML|TAG] an optional file type - if not present, file type of the to file will be used */ public static void main(String[] args) { System.exit(run(args)); @@ -81,7 +81,7 @@ public static void main(String[] args) { * Runs the Verify command logic and reports results to standard out/error, * without terminating the JVM - allows the logic to be unit tested. * - * @param args args[0] SPDX file path; args[1] [RDFXML|JSON|XLS|XLSX|YAML|TAG] an optional file type - if not present, file type of the to file will be used + * @param args args[0] SPDX file path; args[1] [RDFXML|JSON|ODS|XLS|XLSX|YAML|TAG] an optional file type - if not present, file type of the to file will be used * @return process exit status, see {@link ExitCode} */ static int run(String[] args) { @@ -259,7 +259,7 @@ public static List verifyRDFFile(String filePath) throws SpdxVerificatio } public void usage() { - System.out.println("Verify filepath [RDFXML|JSON|XLS|XLSX|YAML|TAG|JSONLD]"); - System.out.println(" where filepath is a path to the SPDX file and [RDFXML|JSON|XLS|XLSX|YAML|TAG] is an optional file type - if not present, file type of the to file will be used"); + System.out.println("Verify filepath [RDFXML|JSON|ODS|XLS|XLSX|YAML|TAG|JSONLD]"); + System.out.println(" where filepath is a path to the SPDX file and [RDFXML|JSON|ODS|XLS|XLSX|YAML|TAG] is an optional file type - if not present, file type of the to file will be used"); } } diff --git a/src/test/java/org/spdx/tools/SpdxConverterTestV2.java b/src/test/java/org/spdx/tools/SpdxConverterTestV2.java index ce8402c..6ae0a8b 100644 --- a/src/test/java/org/spdx/tools/SpdxConverterTestV2.java +++ b/src/test/java/org/spdx/tools/SpdxConverterTestV2.java @@ -54,6 +54,9 @@ public class SpdxConverterTestV2 extends TestCase { static final String TEST_JSON_FILE_PATH = TEST_DIR + File.separator + "SPDXJSONExample-v2.3.spdx.json"; static final String TEST_WITH_EXCEPTION_FILE_PATH = TEST_DIR + File.separator + "SPDXJSONExample-v2.3-with-exception.spdx.json"; static final String TEST_RDF_FILE_PATH = TEST_DIR + File.separator + "SPDXRdfExample-v2.3.spdx.rdf"; + // Trailing empty rows removed from content.xml in the ODS spreadsheet, + // to avoid this bug https://github.com/spdx/spdx-java-spreadsheet-store/issues/109 + static final String TEST_SPREADSHEET_ODS_FILE_PATH = TEST_DIR + File.separator + "SPDXSpreadsheetExample-v2.3.ods"; static final String TEST_SPREADSHEET_XLS_FILE_PATH = TEST_DIR + File.separator + "SPDXSpreadsheetExample-v2.3.xls"; static final String TEST_SPREADSHEET_XLSX_FILE_PATH = TEST_DIR + File.separator + "SPDXSpreadsheetExample-v2.3.xlsx"; static final String TEST_TAG_FILE_PATH = TEST_DIR + File.separator + "SPDXTagExample-v2.3.spdx"; @@ -103,7 +106,7 @@ public static void deleteDirAndFiles(Path dirOrFile) { } } - // Supported file types: JSON, XLS, XLSX, TAG, RDFXML, YAML or XML + // Supported file types: JSON, ODS, XLS, XLSX, TAG, RDFXML, YAML or XML public void testXlsxToRDFXML() throws SpdxConverterException, InvalidSPDXAnalysisException, IOException, SpdxCompareException { String outFileName = "result.rdf.xml"; @@ -224,6 +227,30 @@ public void testXlsToRDFXML() throws SpdxConverterException, InvalidSPDXAnalysis comparer.compare(sourceDoc, resultDoc); assertFalse(comparer.isDifferenceFound()); } + + public void testOdsToRDFXML() throws SpdxConverterException, InvalidSPDXAnalysisException, IOException, SpdxCompareException { + String outFileName = "result.rdf.xml"; + Path outFilePath = tempDirPath.resolve(outFileName); + SpdxConverter.convert(TEST_SPREADSHEET_ODS_FILE_PATH, outFilePath.toString(), SerFileType.ODS, SerFileType.RDFXML); + File result = new File(outFilePath.toString()); + File source = new File(TEST_SPREADSHEET_ODS_FILE_PATH); + assertTrue(result.exists()); + SpdxDocument sourceDoc = SpdxToolsHelper.deserializeDocumentCompatV2(source, SerFileType.ODS); + SpdxDocument resultDoc = SpdxToolsHelper.deserializeDocumentCompatV2(result, SerFileType.RDFXML); + SpdxComparer comparer = new SpdxComparer(); + comparer.compare(sourceDoc, resultDoc); + assertFalse(comparer.isDifferenceFound()); + + // Try with no file types + Files.delete(outFilePath); + SpdxConverter.convert(TEST_SPREADSHEET_ODS_FILE_PATH, outFilePath.toString()); + result = new File(outFilePath.toString()); + assertTrue(result.exists()); + resultDoc = SpdxToolsHelper.deserializeDocumentCompatV2(result, SerFileType.RDFXML); + comparer = new SpdxComparer(); + comparer.compare(sourceDoc, resultDoc); + assertFalse(comparer.isDifferenceFound()); + } public void testJsonToXls() throws SpdxConverterException, InvalidSPDXAnalysisException, IOException, SpdxCompareException { String xmlFileName = "result.rdf.xls"; @@ -248,6 +275,30 @@ public void testJsonToXls() throws SpdxConverterException, InvalidSPDXAnalysisEx comparer.compare(sourceDoc, resultDoc); assertFalse(comparer.isDifferenceFound()); } + + public void testJsonToOds() throws SpdxConverterException, InvalidSPDXAnalysisException, IOException, SpdxCompareException { + String xmlFileName = "result.rdf.ods"; + Path outFilePath = tempDirPath.resolve(xmlFileName); + SpdxConverter.convert(TEST_JSON_FILE_PATH, outFilePath.toString(), SerFileType.JSON, SerFileType.ODS); + File result = new File(outFilePath.toString()); + File source = new File(TEST_JSON_FILE_PATH); + assertTrue(result.exists()); + SpdxDocument sourceDoc = SpdxToolsHelper.deserializeDocumentCompatV2(source, SerFileType.JSON); + SpdxDocument resultDoc = SpdxToolsHelper.deserializeDocumentCompatV2(result, SerFileType.ODS); + SpdxComparer comparer = new SpdxComparer(); + comparer.compare(sourceDoc, resultDoc); + assertFalse(comparer.isDifferenceFound()); + + // Try with no file types + Files.delete(outFilePath); + SpdxConverter.convert(TEST_JSON_FILE_PATH, outFilePath.toString()); + result = new File(outFilePath.toString()); + assertTrue(result.exists()); + resultDoc = SpdxToolsHelper.deserializeDocumentCompatV2(result, SerFileType.ODS); + comparer = new SpdxComparer(); + comparer.compare(sourceDoc, resultDoc); + assertFalse(comparer.isDifferenceFound()); + } public void testJsonToXlsx() throws SpdxConverterException, InvalidSPDXAnalysisException, IOException, SpdxCompareException { String xmlFileName = "result.rdf.xlsx"; diff --git a/src/test/java/org/spdx/tools/VerifyTest.java b/src/test/java/org/spdx/tools/VerifyTest.java index f2d03fe..8e33fc4 100644 --- a/src/test/java/org/spdx/tools/VerifyTest.java +++ b/src/test/java/org/spdx/tools/VerifyTest.java @@ -28,6 +28,7 @@ public class VerifyTest extends TestCase { static final String JSON_BAD_VERSION_FILE_PATH = TEST_DIR + File.separator + "SPDXJSONExample-wrongversion.spdx.json"; static final String TEST_V23_FIELDS_IN_V22_FILE = TEST_DIR + File.separator + "SPDXWrongVersion.spdx.json"; static final String TEST_RDF_FILE_PATH = TEST_DIR + File.separator + "SPDXRdfExample-v2.3.spdx.rdf"; + static final String TEST_SPREADSHEET_ODS_FILE_PATH = TEST_DIR + File.separator + "SPDXSpreadsheetExample-v2.3.ods"; static final String TEST_SPREADSHEET_XLS_FILE_PATH = TEST_DIR + File.separator + "SPDXSpreadsheetExample-v2.3.xls"; static final String TEST_SPREADSHEET_XLSX_FILE_PATH = TEST_DIR + File.separator + "SPDXSpreadsheetExample-v2.3.xlsx"; static final String TEST_TAG_FILE_PATH = TEST_DIR + File.separator + "SPDXTagExample-v2.3.spdx"; @@ -66,6 +67,8 @@ public void testVerifyRDFFile() throws SpdxVerificationException { public void testVerify() throws SpdxVerificationException { List result = Verify.verify(TEST_JSON_FILE_PATH, SerFileType.JSON); assertEquals(0, result.size()); + result = Verify.verify(TEST_SPREADSHEET_ODS_FILE_PATH, SerFileType.ODS); + assertEquals(0, result.size()); result = Verify.verify(TEST_SPREADSHEET_XLS_FILE_PATH, SerFileType.XLS); assertEquals(0, result.size()); result = Verify.verify(TEST_SPREADSHEET_XLSX_FILE_PATH, SerFileType.XLSX); diff --git a/testResources/SPDXSpreadsheetExample-v2.3.ods b/testResources/SPDXSpreadsheetExample-v2.3.ods new file mode 100644 index 0000000000000000000000000000000000000000..4b5280c6a1bf236804fb17b927932c8c2fc0f524 GIT binary patch literal 19769 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
    !fMa7_u?V0*gd4}`-dCMx|8O_8mB&8 zv#dT$@!QndyYggf(JrhVUCrs~nauAPi{iX!+9S`Wpg~u&8?&76V)xOiP}$v!X344w z7WLwsorVpwb%o98Ms2U-oFU$ofle-ts>1rogD%CP%Zg^PF7)tzr=J}aZnT5NHdvyf z-~?an#G;yb@Ntp47_h|pdyZ{zaEOQ$5L!x|*0}KV8Skf5Ed;`9ZLUMT_2D|~l0bsa z9bHXrB`ceXLPbOvJTV62Fq32b7%)JCuHf@Y{~I&%o4cA7;^|hdWQ-0Bz{qxP<7W>5 zigzz^eShE3$0zM4DzABgD@Q(vW;}u_e5R;WP*;hD7>jMSoMVn*Txy^)`%g_%(Rt4s zn9*35$M@$OQ;9~Y&QWl>di z`7u7Q4eCj4v+M+y5u9g1H!=GzUC$BSTjCx|kICroA8qt;AhV~yPjq7H>iY2$e68k+ zCiP!P9CNco!qP7)UZRcd1HeuO75ee=z{pxFJ&jwzS2}X4)fZuW)fJ7qkrlogng*xA z7qmk;f@jscl@~86!j&%3N~j2W6&f^XDu5a;*ND>{-^qMEIbt_@1IB>aZ`s5662cuX zNK%kPwkqyiPR8q_h)iPH{YR#vyvVMf`MksC=kQZMhq1^Uhbx}D60xh^zJUc^lZ5Fz z<&1nBhi-808L`Ym){BTT-Q@TD_e&x8Iw0tfz$j{I}c^S@8Nj>e`_2~)O#^aw#W z+`%T(tNe7JppF#dZI(H`EFtQkboc2<+uhL#stSeW=Q)c9)uK#0(Ty2b1~{V;^`(8v z%tn-?)-y0o>|=vgDF1J-R-Kq)(+h9N;3Dj zHuCtrFm$&=oT#74crAC{!R7vQ@=ZJQgSlVR=pt;*KV4w<9(&SwkFO$D^Zy=L_~){i zviWZt!@mrcwbTCacr>d5BJ!%m%K02+k7u;Uk=$1JSUzxPSdVFoj0yXRaFG@is6b#NJ#UhEz;Jc zByhVgHv1VhFT`yd?yMivBkMqL+b?3#I2=Bot?}{k;o;#SAtBAp&Hn!Wb#-;Y!NFNs zxJZ8Z+@&+uGiqE>?hnfr*KUtyw)y zO-&JV5<6{z3G)lVOxQFFv1{<4uCZJVWT3!?p?5RD0_sxflBHtJ}yaOFPo2>*~9 zzhb@rGcV`zu$?(fZ#L+i$m12`T7EX4uk#qQXW~ooIeiqpw1n)Hd}+x*?g+N*lWUY&?ecQ$E)fDpd3@qw;-1lM?@Rb^!9V?lA_`?IZAyP*6 z)PV|EZ`UhyM2SLGgL;|^8#NP2LSY7mf_69^mycBKb78X6trT5TI!pd8!&xW^r<{rA z9QhWXp%kD21t9cm{)O|VfHwC};q(~Q(c;MOCxZg!lgnDDZ%U&re^_oRGN@c1N%@;* zFj?rv9O*zHfaB`k(1-ie{7m#QAXj~DCe4nPBDROz3wXieuLkIV5#Bt$$Q9OckvLB7 zD&NF;Gh38T0R`fb;R){)GRBg4B0B!uY!K37oRN6l@4=C8Z<|n_(dsY=IEcI@QXxs7 zo7toj85e#`5Q?!`*%GL%e8YIP-~dNzPwIg*9;dhfU~X|w&-P$NHf$G9tXUvbc7UpW zUFA}`KdUKMD;b zO~DpKCo?t}vUz8Hy(xyBH#>7 zm$YJjykZjCC^-wH!JU3Wb*e1szAaVjpF~F)^<7Nln`8)1H(2>FZ{RmDzB83O)V{y} z;wVgCy<>Jf>fprn!Lx8e~rlvtuIBtz{QRhM!4#1)0 zPR((uZp~GM55!?#*f<&RUuF_EUZrg5ZXtkq(A2GI8L#0O?>mD_hTqMX-_D}0sT59R zI|!&;x_bDFJ;_glBoA=%o2bV?W2YbW@zcG$vw{gd^bg@(-VRrP=O}TJ`jU0?f$
      cj4|u(kp_2~xu`_aVQ!%+0 zSvw$&a+i4e%1A`n@4Wb^hA}yH`yfKL|ROqa&I4K0hy(c+_lD_oyb<} z%3b}#$6aY}zuvrEp}?6YS!rH-_#6#I`tw3w+Pgj6k3pIO#ZlvXOub1EG_IxHzq8 zQ3Gk!))C|XYUIkppl-tNbA9(8?{mG^_56PCeLvUz&vW1R`U!RdV9y~p6T#{B9XF=yQf6lPmF}>$8ok^!e;iDz4#<%C0T16Xox#SCNo_BHUv_kWvPOgVHznXTQ0QrR^HktU4xLf3^-Vz=1tRcO@ zrPhD;E)Z-ZwDS$jhSh)F6ZS`XMyna6Ad;n8W3* zlUj!e8?SQ(BLdDU{~)W6xCogy4R+_fnApJUdqU*N27h9K=haL|3SW4U*Fiv)w;eEW zn_Itt5^;tfA*mD?d zf3r(oFgWGgR$1x;)a>oelb?DgdarsUk*+K+2W&&%=@q3}lD&8wB1_@i~Fdt>$yANG-~$|G!j^Wnmy{p$>%9)Fa#QFxDCbt2!m{f9M{qX6EnEO?+lmlsQ8FX z5L?Gz@?2-7Zd$+3DdH_+d}!{l)edw+KlF+f;1cEtSd^8t9@^{$KmpZ?eP-tdEL~<6%@st zP?yfnn1>no+%Ck*R=UMKvnx3wMmA|v(2#E(nVTsT#2KOe9a~X_qR}0|5g@C5G|;l+ z#m6rEaS@?VLyKwml=SIUWdWU}v+jN&PYYvjdWL1Oaz>;ZvuI%ylgNkI_{rf!DZ3l> zlBwHzpVbh$A^u#hgM-8}bWCQ+b2hI7-Ml)HiCjEAb7EI6VZYTA9p~j1ijm3?7BO{k z3mXtvMYdtFeE@J%*;Wx5U>E5&Xc7`8>Ky$>NuC$%;MkH=h8V4fuuti@D!NMJNRp#^ zEs=6kw*)%9H6XTM6l!L=gf)wWiV5{_4oH-ug6cP%8YV`{?;~8oSir_k$p`rpR3qOX zs65de5incuW82r@T!g4~5nTLURSXd(~6Q%Y`>qfu-4!E36z( z2a#p|q)ZPoN2p#7sJr#jE#BBLU{ES2l#tG61&5O5RBPgdlh5!V++UmbicYaicxfm8 zyyn~xp6|;?<}uSf6$^Lc^0M||193D_K1#MPs~dgJQU{;SQ=d&-XcwF(SfvoI|6Ua1 zqicjO%qlqJk?zoU4Kh8s5+{yBET&_s<^_hdIkT=C_etrxgImqs-kHe<`6cBf)C{e2 zPkW=h%dZ;H=A!?Lju-x1Qb2-yQiKIYueMZA*r(u7t!3X(9 zxrntJTIlU4^yDiS`5=rII?0M6_Dw}}9d(6>K`Zv4MYf3wOGHD8OX${D3Rr=HpP_J5 zFqk#m5?YP@^&fs-TL$54G6S+sTd-x8;h5v-AlXHcP1wU&F?@HdPvB+>n#IzTg;knu zf1x7k{pmke6h&LU%NFgR=-oqRDI(fl>V*|h6lFtw?iME6{XOO`FineP#{>WiKP6Ld zyMI?^Vf6OKvFzm9URp4; z^V!KY11ifdWf#5}e@gY9^! zvm5rmQVw<4h1p-`mOPyzAF{ha&x~U(7twKgI*i4me~Oh>IoUBvfgHIqut(%$|8rweNH literal 0 HcmV?d00001