From 7e81c67f77ecf3c3989cf63775191fadc918bd37 Mon Sep 17 00:00:00 2001 From: HLWeil Date: Wed, 16 Oct 2024 13:05:24 +0200 Subject: [PATCH 01/30] add basic FileSystemHelper functions for .NET --- Directory.Packages.props | 3 ++ src/ARCtrl/ARCtrl.fsproj | 6 ++- src/ARCtrl/ContractIO/FileSystemHelper.fs | 51 +++++++++++++++++++++++ src/ARCtrl/Xlsx.fs | 27 +++++++----- 4 files changed, 75 insertions(+), 12 deletions(-) create mode 100644 src/ARCtrl/ContractIO/FileSystemHelper.fs diff --git a/Directory.Packages.props b/Directory.Packages.props index 11ea1005..86a64c52 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -11,6 +11,9 @@ + + + diff --git a/src/ARCtrl/ARCtrl.fsproj b/src/ARCtrl/ARCtrl.fsproj index db129baf..22589698 100644 --- a/src/ARCtrl/ARCtrl.fsproj +++ b/src/ARCtrl/ARCtrl.fsproj @@ -8,6 +8,8 @@ + + @@ -47,11 +49,10 @@ - - + @@ -61,6 +62,7 @@ + diff --git a/src/ARCtrl/ContractIO/FileSystemHelper.fs b/src/ARCtrl/ContractIO/FileSystemHelper.fs new file mode 100644 index 00000000..95312ebf --- /dev/null +++ b/src/ARCtrl/ContractIO/FileSystemHelper.fs @@ -0,0 +1,51 @@ +module ARCtrl.FileSystemHelper + +open FsSpreadsheet + +#if !FABLE_COMPILER +open FsSpreadsheet.Net +#endif + +let directoryExists path = + System.IO.Directory.Exists path + +let createDirectory path = + System.IO.Directory.CreateDirectory path |> ignore + +let ensureDirectory path = + if not <| directoryExists path then + createDirectory path + +let fileExists path = + System.IO.File.Exists path + +let getSubDirectories path = + System.IO.Directory.GetDirectories path + +let getSubFiles path = + System.IO.Directory.GetFiles path + +let getAllFilePaths path = + let rec allFiles dirs = + if Seq.isEmpty dirs then Seq.empty else + seq { yield! dirs |> Seq.collect getSubFiles + yield! dirs |> Seq.collect getSubDirectories |> allFiles } + allFiles [path] + +let readFileText path : string = + System.IO.File.ReadAllText path + +let readFileBinary path : byte [] = + System.IO.File.ReadAllBytes path + +let readFileXlsx path : FsWorkbook = + FsWorkbook.fromXlsxFile path + +let writeFileText path text = + System.IO.File.WriteAllText(path, text) + +let writeFileBinary path (bytes : byte []) = + System.IO.File.WriteAllBytes(path,bytes) + +let writeFileXlsx path (wb : FsWorkbook) = + FsWorkbook.toXlsxFile path wb \ No newline at end of file diff --git a/src/ARCtrl/Xlsx.fs b/src/ARCtrl/Xlsx.fs index b31092c4..18036136 100644 --- a/src/ARCtrl/Xlsx.fs +++ b/src/ARCtrl/Xlsx.fs @@ -1,37 +1,44 @@ -namespace ARCtrl +namespace ARCtrl +namespace ARCtrl open Thoth.Json.Core open ARCtrl.Spreadsheet open Fable.Core open FsSpreadsheet +#if !FABLE_COMPILER +open FsSpreadsheet.Net +#endif + module XlsxHelper = [] type DatamapXlsx() = member _.fromFsWorkbook (fswb: FsWorkbook) = DataMap.fromFsWorkbook fswb member _.toFsWorkbook (datamap: DataMap) = DataMap.toFsWorkbook datamap + member _.fromXlsxFile (path: string) = FsWorkbook.fromXlsxFile path |> DataMap.fromFsWorkbook + member _.toXlsxFile (path: string, datamap: DataMap) = DataMap.toFsWorkbook datamap |> FsWorkbook.toXlsxFile path [] type AssayXlsx() = member _.fromFsWorkbook (fswb: FsWorkbook) = ArcAssay.fromFsWorkbook fswb member _.toFsWorkbook (assay: ArcAssay) = ArcAssay.toFsWorkbook assay + member _.fromXlsxFile (path: string) = FsWorkbook.fromXlsxFile path |> ArcAssay.fromFsWorkbook + member _.toXlsxFile (path: string, assay: ArcAssay) = ArcAssay.toFsWorkbook assay |> FsWorkbook.toXlsxFile path [] type StudyXlsx() = member _.fromFsWorkbook (fswb: FsWorkbook) = ArcStudy.fromFsWorkbook fswb member _.toFsWorkbook (study: ArcStudy, ?assays: ResizeArray) = ArcStudy.toFsWorkbook(study,?assays=Option.map List.ofSeq assays) + member _.fromXlsxFile (path: string) = FsWorkbook.fromXlsxFile path |> ArcStudy.fromFsWorkbook + member _.toXlsxFile (path: string, study: ArcStudy, ?assays: ResizeArray) = ArcStudy.toFsWorkbook(study,?assays=Option.map List.ofSeq assays) |> FsWorkbook.toXlsxFile path + [] type InvestigationXlsx() = member _.fromFsWorkbook (fswb: FsWorkbook) = ArcInvestigation.fromFsWorkbook fswb - member _.toFsWorkbook (investigation: ArcInvestigation) = ArcInvestigation.toFsWorkbook(investigation) - -open XlsxHelper + member _.toFsWorkbook (investigation: ArcInvestigation) = ArcInvestigation.toFsWorkbook(investigation) + member _.fromXlsxFile (path: string) = FsWorkbook.fromXlsxFile path |> ArcInvestigation.fromFsWorkbook + member _.toXlsxFile (path: string, investigation: ArcInvestigation) = ArcInvestigation.toFsWorkbook(investigation) |> FsWorkbook.toXlsxFile path -[] -type XlsxController = - static member Datamap = DatamapXlsx() - static member Assay = AssayXlsx() - static member Study = StudyXlsx() - static member Investigation = InvestigationXlsx() \ No newline at end of file +open XlsxHelper \ No newline at end of file From fcc2756ee96813286b65d89ef01f12938907192b Mon Sep 17 00:00:00 2001 From: HLWeil Date: Wed, 16 Oct 2024 13:05:43 +0200 Subject: [PATCH 02/30] add simple contractIO functions --- src/ARCtrl/ARCtrl.fsproj | 5 ++- src/ARCtrl/ContractIO/ContractIO.fs | 61 +++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 2 deletions(-) create mode 100644 src/ARCtrl/ContractIO/ContractIO.fs diff --git a/src/ARCtrl/ARCtrl.fsproj b/src/ARCtrl/ARCtrl.fsproj index 22589698..3595042c 100644 --- a/src/ARCtrl/ARCtrl.fsproj +++ b/src/ARCtrl/ARCtrl.fsproj @@ -51,13 +51,14 @@ - + + - + diff --git a/src/ARCtrl/ContractIO/ContractIO.fs b/src/ARCtrl/ContractIO/ContractIO.fs new file mode 100644 index 00000000..9ef39afd --- /dev/null +++ b/src/ARCtrl/ContractIO/ContractIO.fs @@ -0,0 +1,61 @@ +module ARCtrl.Contract + +open ARCtrl +open ARCtrl.Contract +open FsSpreadsheet + +let fulfillReadContract basePath (c : Contract) = + match c.DTOType with + | Some DTOType.ISA_Assay + | Some DTOType.ISA_Investigation + | Some DTOType.ISA_Study + | Some DTOType.ISA_Datamap -> + let path = ArcPathHelper.combine basePath c.Path + let wb = FileSystemHelper.readFileXlsx path |> box |> DTO.Spreadsheet + Ok {c with DTO = Some wb} + | Some DTOType.PlainText -> + let path = ArcPathHelper.combine basePath c.Path + let text = FileSystemHelper.readFileText path |> DTO.Text + Ok {c with DTO = Some text} + | _ -> + Error (sprintf "Contract %s is not an ISA contract" c.Path) + +let fulfillWriteContract basePath (c : Contract) = + match c.DTO with + | Some (DTO.Spreadsheet wb) -> + let path = ArcPathHelper.combine basePath c.Path + FileSystemHelper.ensureDirectory path + FileSystemHelper.writeFileXlsx path (wb :?> FsWorkbook) + Ok () + | Some (DTO.Text t) -> + let path = ArcPathHelper.combine basePath c.Path + FileSystemHelper.ensureDirectory path + FileSystemHelper.writeFileText path t + Ok () + | None -> + let path = ArcPathHelper.combine basePath c.Path + FileSystemHelper.ensureDirectory path + FileSystemHelper.writeFileText path "" + Ok () + | _ -> + Error (sprintf "Contract %s is not an ISA contract" c.Path) + +let fulfillUpdateContract basePath (c : Contract) = + match c.DTO with + | Some (DTO.Spreadsheet wb) -> + let path = ArcPathHelper.combine basePath c.Path + FileSystemHelper.ensureDirectory path + FileSystemHelper.writeFileXlsx path (wb :?> FsWorkbook) + Ok () + | Some (DTO.Text t) -> + let path = ArcPathHelper.combine basePath c.Path + FileSystemHelper.ensureDirectory path + FileSystemHelper.writeFileText path t + Ok () + | None -> + let path = ArcPathHelper.combine basePath c.Path + FileSystemHelper.ensureDirectory path + FileSystemHelper.writeFileText path "" + Ok () + | _ -> + Error (sprintf "Contract %s is not an ISA contract" c.Path) \ No newline at end of file From 68cb0cb68fa0da6931e79f4fe77d23041b56f2c5 Mon Sep 17 00:00:00 2001 From: HLWeil Date: Wed, 16 Oct 2024 17:20:46 +0200 Subject: [PATCH 03/30] small fix to xlsx controller --- src/ARCtrl/Xlsx.fs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/ARCtrl/Xlsx.fs b/src/ARCtrl/Xlsx.fs index 18036136..1426c7a9 100644 --- a/src/ARCtrl/Xlsx.fs +++ b/src/ARCtrl/Xlsx.fs @@ -41,4 +41,11 @@ module XlsxHelper = member _.fromXlsxFile (path: string) = FsWorkbook.fromXlsxFile path |> ArcInvestigation.fromFsWorkbook member _.toXlsxFile (path: string, investigation: ArcInvestigation) = ArcInvestigation.toFsWorkbook(investigation) |> FsWorkbook.toXlsxFile path -open XlsxHelper \ No newline at end of file +open XlsxHelper + +[] +type XlsxController = + static member Datamap = DatamapXlsx() + static member Assay = AssayXlsx() + static member Study = StudyXlsx() + static member Investigation = InvestigationXlsx() \ No newline at end of file From 98b1b991da14d4cfd6214edc2fd04358267378a3 Mon Sep 17 00:00:00 2001 From: Heinrich Lukas Weil Date: Tue, 29 Oct 2024 15:07:04 +0100 Subject: [PATCH 04/30] add testObjects from ARCtrl.IO --- tests/TestingUtils/TestObjects.IO.fs | 4 + .../ARC_SimpleARC/.arc/.gitkeep | 0 .../ARC_SimpleARC/assays/.gitkeep | 0 .../assays/measurement1/README.md | 0 .../assays/measurement1/dataset/.gitkeep | 0 .../dataset/proteomics_result.csv | 0 .../assays/measurement1/dataset/sample1.raw | 0 .../assays/measurement1/dataset/sample2.raw | 0 .../assays/measurement1/dataset/sample3.raw | 0 .../assays/measurement1/dataset/sample4.raw | 0 .../assays/measurement1/dataset/sample5.raw | 0 .../assays/measurement1/dataset/sample6.raw | 0 .../assays/measurement1/dataset/sample7.raw | 0 .../assays/measurement1/dataset/table.csv | 651 ++++++++++++++++++ .../assays/measurement1/isa.assay.xlsx | Bin 0 -> 23306 bytes .../assays/measurement1/isa.dataset.xlsx | Bin 0 -> 11653 bytes .../assays/measurement1/protocols/.gitkeep | 0 .../protocols/extractionProtocol.txt | 3 + .../ARC_SimpleARC/isa.investigation.xlsx | Bin 0 -> 12526 bytes .../ARC_SimpleARC/runs/.gitkeep | 0 .../ARC_SimpleARC/studies/.gitkeep | 0 .../studies/experiment1_material/README.md | 0 .../experiment1_material/isa.study.xlsx | Bin 0 -> 21370 bytes .../experiment1_material/protocols/.gitkeep | 0 .../experiment1_material/resources/.gitkeep | 0 ...1_e36ca6b8-19ba-4504-aa82-d4781765873d.png | Bin 0 -> 1087 bytes ...2_714ca2b7-22b7-4f69-b83d-9165f624da25.png | Bin 0 -> 1080 bytes ...3_66fac760-acc7-4ed4-ba21-2cb67fa36e4d.png | Bin 0 -> 1073 bytes ...4_cba5f40c-fc05-44d6-a589-b0e3dafaeefe.png | Bin 0 -> 1054 bytes ...5_84c37b60-2342-4226-a36c-4b8dfe84ebe9.png | Bin 0 -> 1079 bytes ...6_208df064-4b1c-4da0-a1f8-6412e1fb2284.png | Bin 0 -> 1078 bytes .../ARC_SimpleARC/workflows/.gitkeep | 0 .../TestObjects.IO/Contracts/TestReadMe.txt | 1 + .../Contracts/TestWorkbook.xlsx | Bin 0 -> 8487 bytes .../Path_findSubPaths/File1.txt | 0 .../Path_findSubPaths/File2.csv | 0 .../Path_findSubPaths/SubFolder/File3.xlsx | 0 .../SubFolder/SubSubFolder/File4 | 0 .../{Library.fs => TestingUtils.fs} | 0 tests/TestingUtils/TestingUtils.fsproj | 3 +- 40 files changed, 661 insertions(+), 1 deletion(-) create mode 100644 tests/TestingUtils/TestObjects.IO.fs create mode 100644 tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/.arc/.gitkeep create mode 100644 tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/.gitkeep create mode 100644 tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/README.md create mode 100644 tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/dataset/.gitkeep create mode 100644 tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/dataset/proteomics_result.csv create mode 100644 tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/dataset/sample1.raw create mode 100644 tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/dataset/sample2.raw create mode 100644 tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/dataset/sample3.raw create mode 100644 tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/dataset/sample4.raw create mode 100644 tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/dataset/sample5.raw create mode 100644 tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/dataset/sample6.raw create mode 100644 tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/dataset/sample7.raw create mode 100644 tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/dataset/table.csv create mode 100644 tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/isa.assay.xlsx create mode 100644 tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/isa.dataset.xlsx create mode 100644 tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/protocols/.gitkeep create mode 100644 tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/protocols/extractionProtocol.txt create mode 100644 tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/isa.investigation.xlsx create mode 100644 tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/runs/.gitkeep create mode 100644 tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/studies/.gitkeep create mode 100644 tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/studies/experiment1_material/README.md create mode 100644 tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/studies/experiment1_material/isa.study.xlsx create mode 100644 tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/studies/experiment1_material/protocols/.gitkeep create mode 100644 tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/studies/experiment1_material/resources/.gitkeep create mode 100644 tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/studies/experiment1_material/resources/Sample1_e36ca6b8-19ba-4504-aa82-d4781765873d.png create mode 100644 tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/studies/experiment1_material/resources/Sample2_714ca2b7-22b7-4f69-b83d-9165f624da25.png create mode 100644 tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/studies/experiment1_material/resources/Sample3_66fac760-acc7-4ed4-ba21-2cb67fa36e4d.png create mode 100644 tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/studies/experiment1_material/resources/Sample4_cba5f40c-fc05-44d6-a589-b0e3dafaeefe.png create mode 100644 tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/studies/experiment1_material/resources/Sample5_84c37b60-2342-4226-a36c-4b8dfe84ebe9.png create mode 100644 tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/studies/experiment1_material/resources/Sample6_208df064-4b1c-4da0-a1f8-6412e1fb2284.png create mode 100644 tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/workflows/.gitkeep create mode 100644 tests/TestingUtils/TestObjects.IO/Contracts/TestReadMe.txt create mode 100644 tests/TestingUtils/TestObjects.IO/Contracts/TestWorkbook.xlsx create mode 100644 tests/TestingUtils/TestObjects.IO/Path_findSubPaths/File1.txt create mode 100644 tests/TestingUtils/TestObjects.IO/Path_findSubPaths/File2.csv create mode 100644 tests/TestingUtils/TestObjects.IO/Path_findSubPaths/SubFolder/File3.xlsx create mode 100644 tests/TestingUtils/TestObjects.IO/Path_findSubPaths/SubFolder/SubSubFolder/File4 rename tests/TestingUtils/{Library.fs => TestingUtils.fs} (100%) diff --git a/tests/TestingUtils/TestObjects.IO.fs b/tests/TestingUtils/TestObjects.IO.fs new file mode 100644 index 00000000..17a84371 --- /dev/null +++ b/tests/TestingUtils/TestObjects.IO.fs @@ -0,0 +1,4 @@ +module TestObjects.IO + +let testInputFolder = System.IO.Path.Combine(__SOURCE_DIRECTORY__,@"TestObjects/Contracts") +let testOutputFolder = System.IO.Path.Combine(__SOURCE_DIRECTORY__,@"TestResults/Contracts") \ No newline at end of file diff --git a/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/.arc/.gitkeep b/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/.arc/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/.gitkeep b/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/README.md b/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/README.md new file mode 100644 index 00000000..e69de29b diff --git a/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/dataset/.gitkeep b/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/dataset/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/dataset/proteomics_result.csv b/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/dataset/proteomics_result.csv new file mode 100644 index 00000000..e69de29b diff --git a/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/dataset/sample1.raw b/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/dataset/sample1.raw new file mode 100644 index 00000000..e69de29b diff --git a/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/dataset/sample2.raw b/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/dataset/sample2.raw new file mode 100644 index 00000000..e69de29b diff --git a/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/dataset/sample3.raw b/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/dataset/sample3.raw new file mode 100644 index 00000000..e69de29b diff --git a/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/dataset/sample4.raw b/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/dataset/sample4.raw new file mode 100644 index 00000000..e69de29b diff --git a/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/dataset/sample5.raw b/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/dataset/sample5.raw new file mode 100644 index 00000000..e69de29b diff --git a/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/dataset/sample6.raw b/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/dataset/sample6.raw new file mode 100644 index 00000000..e69de29b diff --git a/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/dataset/sample7.raw b/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/dataset/sample7.raw new file mode 100644 index 00000000..e69de29b diff --git a/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/dataset/table.csv b/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/dataset/table.csv new file mode 100644 index 00000000..a3c13b45 --- /dev/null +++ b/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/dataset/table.csv @@ -0,0 +1,651 @@ +Index,value_1,quant_1,value_2,quant_2,value_3,quant_3,value_4,quant_4,value_5,quant_5,value_6,quant_6 +0,20.60917636,2.366800063,31.76575111,2.51972112,31.239141,2.994118452,38.54463269,2.235910104,26.74437584,3.351820025,18.87709616,3.408542256 +1,20.2667511,3.45287336,10.44136185,3.04179784,24.76736657,2.912656477,36.16958385,3.430737189,24.20981945,3.122776939,-5.253242754,2.186538738 +2,17.36828141,3.73863731,25.9790139,3.498130345,28.59307579,3.049276271,39.80151617,2.05657019,13.29576986,3.752299254,31.94888467,3.28870028 +3,9.917464634,3.41392671,22.41344542,3.811982726,27.02827473,2.871323801,27.91095666,3.401721228,31.75968784,3.099053447,22.38381643,2.944344071 +4,41.79881325,3.479405118,27.03382081,3.496490729,16.14388422,2.811865235,45.12616701,3.004925209,43.44154067,3.512141495,13.92163384,3.265526505 +5,17.14758253,2.286495209,33.79567127,2.848821097,29.53447225,3.594532936,41.29957184,3.208352043,18.97964211,2.943254771,7.00021151,3.023056376 +6,39.36514967,2.623481095,43.34430733,3.253270352,37.65244428,3.340323609,15.02595487,3.174360915,59.08649438,3.116179827,32.12707181,3.128946216 +7,24.67531734,3.005013639,21.14050562,2.909298401,27.58292887,3.076099914,25.44390985,2.409556765,24.41151962,3.80626409,34.54725553,3.632621756 +8,24.36182152,3.188425192,24.96747128,3.491500103,36.83422896,3.653180394,28.5746082,3.036992103,22.66157764,2.908729803,36.05784788,1.696238827 +9,8.17927182,3.152130596,6.865294845,2.739631151,28.26505134,2.672745865,32.78770943,3.04109728,24.51318045,3.405063636,47.01077115,2.836521016 +10,23.89515294,3.061123404,18.68652245,2.455147043,46.97485465,3.68918597,26.88184583,3.358516996,24.70883965,3.448101321,25.28267201,2.277448641 +11,19.23462713,3.178167021,42.25565794,3.544084566,5.496309228,2.40837214,19.26703661,3.665371223,15.46755864,2.933841019,35.49115953,3.39372516 +12,29.2464254,3.009975576,32.23685962,2.482772452,21.89530136,3.218307613,4.223189095,2.770498673,20.16137388,2.692457687,42.99818546,3.643681991 +13,21.92369808,3.447973514,11.59162699,3.480650329,33.96074837,2.95468097,19.57986705,3.766877677,41.12660294,3.427034792,21.62259742,3.443194242 +14,15.96474227,3.061203691,23.06283077,3.42444171,25.98426886,3.576125139,21.49532558,2.224421571,16.28495731,2.972966931,13.2045675,2.700833556 +15,25.24765674,3.554892466,32.56730516,3.622277772,36.53095697,3.228979032,28.31952741,3.184153175,39.41000706,2.983383051,23.43532653,1.420588925 +16,24.81316281,3.490788584,16.67112529,3.191237197,24.12307012,3.96816438,45.98150201,3.235178562,22.57703174,2.711702377,27.44075624,3.513032992 +17,44.08286738,3.296324853,18.88658857,3.322930292,31.38405354,3.816661909,32.82428929,3.430822911,26.80402725,3.415673275,25.13325396,3.413904541 +18,23.85666276,3.128851776,32.22763419,2.796953488,45.17888136,2.756213389,23.53408123,3.294350412,30.5549607,3.450311441,36.13674601,3.013595846 +19,34.51145393,3.206745385,41.50326891,2.810570405,24.80342829,3.360357476,12.10297986,3.552163786,28.30342187,3.521498551,14.3955304,1.440841411 +20,22.10854005,3.33854044,17.60659316,3.424198717,34.15457895,2.157162526,34.50498387,3.123786212,23.43427294,3.082016061,13.6249119,2.782179131 +21,34.44765198,3.596613648,38.87198488,3.438231695,36.46154941,3.249408847,22.95215379,2.510152553,21.83809641,3.394245845,40.94563426,3.025732545 +22,36.63022387,3.342592993,30.39640632,3.783198972,19.3636592,3.096327448,11.91082904,3.496797366,21.38293085,3.171900024,39.08628238,3.795622852 +23,27.07855567,3.812380691,29.81001463,3.442106021,24.2599697,3.400543914,32.57173186,3.376729351,34.720929,2.450155236,32.95509159,2.951217781 +24,22.22450547,2.517942833,26.18650541,2.703049593,17.47141535,2.888110621,16.94781063,3.220523464,28.08883401,3.589119865,20.19751678,3.468856947 +25,33.72343818,3.40174576,36.4584919,3.002611613,17.03641428,3.917758498,18.21973668,3.800800816,35.31534639,2.747726586,33.30657157,3.206567311 +26,5.968099441,3.564184284,12.08788366,3.098450762,7.836571927,3.036421686,34.10008403,2.597896214,43.63721942,3.046321677,35.00081181,3.078246621 +27,25.10825562,3.464433432,10.11000141,3.488205519,21.47266954,2.904994286,12.40850104,3.788932017,21.18601112,3.89148464,6.737994176,3.140522503 +28,18.09333759,3.091071068,8.746817871,3.920155065,23.83582285,2.822370744,18.86604924,2.98091841,23.35955583,2.706377418,24.52094976,3.22691115 +29,32.46633105,2.96197856,39.91942193,3.540263057,30.88271643,3.167635665,25.90363595,3.293508694,28.87080505,2.599489549,24.63950169,2.641400212 +30,16.42492898,2.478240228,27.54774241,3.288378368,30.0514856,3.39623439,24.46778634,3.322674114,16.11623232,3.16791363,23.45238495,3.07292471 +31,28.65125637,2.730139646,15.42732978,3.132744456,19.20841752,3.31213107,27.70768989,2.702571278,30.94306601,3.711177291,33.11773628,2.907266827 +32,24.37799414,3.20804831,29.56041526,-0.139610586,35.55479845,2.561175589,34.8445276,3.128937581,35.35928363,3.273098852,17.78099675,1.905911827 +33,10.62230927,3.57999766,32.77317909,3.021654271,16.3030726,2.45668172,48.46767452,3.073207712,21.01321527,3.446959753,32.77150279,3.682618207 +34,12.91389117,3.140340926,15.80994609,2.611820081,42.25851995,2.329097582,31.67511374,2.346430502,20.76910847,2.948779825,33.22470367,2.164800454 +35,27.86699924,3.266887331,26.19448085,3.507437752,32.9002868,3.435957211,27.49728144,3.590400923,16.09384527,3.651085597,29.38498699,3.135808778 +36,16.88605519,3.033284474,41.64243863,3.137665504,31.76601668,2.716378366,29.70541284,3.217272992,45.74884088,3.543674858,36.65948256,3.612869186 +37,15.0610888,3.185101951,37.17574998,3.469305554,33.52091805,3.811023275,29.66945732,3.135192666,42.38030763,2.874206516,15.66452908,0.907097635 +38,39.97363659,3.161315695,16.91937791,2.919056752,9.462822931,3.050492712,15.88427824,3.518612497,34.20252776,3.493428981,14.16181464,3.226026909 +39,41.02812418,2.7732624,15.49724184,3.339399641,25.10294484,3.172906446,22.19257601,3.211969462,6.408272032,3.377294413,20.46460527,3.452143893 +40,30.32795224,3.164217484,28.62777628,3.265322128,9.782081539,3.137228273,38.40777842,2.566254383,-2.222074486,2.923678288,26.84180022,3.523434988 +41,14.36828159,3.185506125,32.07611361,3.093838885,40.63067086,3.501549851,9.876755777,2.945255426,36.11385625,3.477409392,35.80878946,2.687730366 +42,13.58762729,2.157281252,25.68178319,3.231361083,13.21044936,3.42830451,46.72279919,3.295394239,27.192841,2.58739696,14.91534661,3.398582762 +43,23.60292601,3.334716637,20.82039889,2.953515827,22.9105469,1.818206004,11.6841137,3.940747875,34.83013908,3.682339562,8.413412527,2.471014773 +44,11.60949513,3.370558791,7.901267537,2.867029199,13.21794599,3.02310825,26.55403753,3.766376009,30.28063738,3.639710454,18.77319768,2.132998026 +45,30.85285523,3.885913232,17.8196691,3.30602411,36.31386084,2.614818494,25.61119166,2.830339215,21.63804018,3.371687267,37.37272672,2.922609494 +46,22.18392142,2.907889902,42.7494121,3.241511504,11.36263677,3.14685158,10.51442268,1.956598932,26.33190565,3.578230526,-2.141454626,3.236098167 +47,31.39044542,3.292671329,29.36012387,3.013594008,19.52291834,3.721420879,10.94551141,2.564235116,27.8600769,2.812409683,18.82904191,3.220421478 +48,34.18387858,2.971870442,11.33280692,3.047066451,20.22455315,2.470675753,3.86911054,3.413816634,23.17444279,4.002321378,21.67512609,3.270079298 +49,17.51376691,3.525339312,29.10956717,3.209998305,18.14863463,3.203169991,19.47956295,3.499029799,2.485149349,3.257298875,44.70375408,3.136744084 +50,42.42865019,1.540684066,33.8419035,3.858634073,20.85350494,3.642711487,38.91303268,2.905148645,22.86078214,3.568857086,28.96181033,3.23001123 +51,19.36794077,3.510032185,10.56607062,3.553945851,-3.400625654,2.794294148,14.20105364,3.129057971,30.52039566,3.593830626,25.33870781, +52,27.85046482,3.093063513,22.4250409,3.701695639,20.51736138,3.339693961,24.36326823,3.280961733,17.01715142,3.365392568,25.34764749,3.070516736 +53,30.51969923,3.575569491,10.05280118,3.508819867,27.33943807,3.268660906,27.0037118,2.920648215,29.34444463,2.800734318,27.79686163,3.04729657 +54,34.01123534,3.39749369,21.4975815,1.837559879,20.9064718,1.884919731,42.1166379,2.883840013,31.90331739,3.335654809,15.94613387,2.898350014 +55,24.75862805,3.770533208,19.08595675,3.362855987,16.04172404,3.681986875,22.31341188,2.291727097,22.71995232,3.166936989,25.42921429,3.47937379 +56,29.86505997,3.501184957,27.4337937,3.706565484,28.83529093,2.796550164,26.09004881,3.861491003,22.08929576,2.752441598,17.51996755,3.554385189 +57,21.08232857,3.445537308,17.63939421,3.271286888,12.99554996,3.269942836,29.69342553,3.422760002,24.43867487,2.40741653,23.81017339,3.027190552 +58,17.1029576,3.213781085,32.60447497,2.716184911,22.59376774,2.870465518,36.17899884,2.909668345,20.01299958,2.927544236,25.10559119,3.826869463 +59,22.32883761,3.584126606,26.05486915,2.333320991,17.78441137,2.623281348,32.54735663,3.705331891,10.09909231,2.752045112,22.30082692,4.021415767 +60,32.76898208,3.352249563,41.10462878,3.717344173,26.38394648,3.317274171,15.67387751,3.194911881,17.86938352,2.905417086,50.12142555,3.247573133 +61,18.69777835,3.574280553,37.88201959,3.541130165,19.83565935,3.414324578,11.04490751,3.39202963,25.36342315,3.253182652,31.13244214,2.693308235 +62,31.65590501,3.803208003,17.91775204,2.612998241,22.55830883,2.896363422,26.52554715,2.891798487,29.12644247,3.340520554,32.7946059,2.918472108 +63,55.58123391,2.965266062,19.35970269,3.513107761,21.77432336,3.391086834,17.8002179,3.419493978,14.63714829,3.640885564,25.1614804,3.652331427 +64,25.01026891,3.701483808,23.87938665,2.939226952,19.0968907,3.565067647,22.89629056,3.39513402,29.88378715,2.355854918,15.00457138,3.429584102 +65,5.541910485,3.034133974,6.067723937,2.417872207,30.14403817,2.697180798,34.56588943,2.944901485,19.4229206,3.347017044,29.69311883,3.236455561 +66,8.878693753,1.830625309,30.7969996,1.778576904,33.22868979,2.770629669,13.95994477,2.5889993,21.51138252,3.638111362,21.69364556,3.08938999 +67,8.158890153,2.153402867,21.64560939,3.254702695,7.14881748,2.790254661,26.71711154,3.679392896,26.08281361,3.057542532,35.94978606,1.9467741 +68,20.84193703,2.042390774,23.12299877,2.924316467,20.89042974,3.449086877,16.60938663,3.129120972,27.90615562,3.090946753,12.19128311,3.264470879 +69,16.62975972,3.767697064,18.42726701,3.625192968,28.75164921,3.248840087,5.809141676,3.207880413,16.21913062,3.70183613,42.97111803,3.347393035 +70,13.21465726,3.676384008,24.41065395,3.60183844,12.90733091,2.316367248,23.22902159,3.797453311,10.01356323,3.293962574,17.14881318,3.459056851 +71,48.93734814,3.831540259,28.54415522,3.371278403,20.14529152,2.946665933,29.34453418,2.885115502,18.65676189,3.917805496,28.23536782,3.192338736 +72,21.5024017,3.006506534,20.21176795,3.387970073,18.65687998,3.401270517,21.30060422,3.525986777,18.42981393,3.363400669,5.269352283,3.340326043 +73,25.47655492,2.170559177,27.42840046,3.13794708,19.698687,3.545437051,20.08386568,2.894437853,28.70924651,3.549228237,28.312648,3.382378154 +74,23.50187384,2.143679994,11.86503655,3.377638807,15.17880729,3.1225233,25.60926437,1.22596116,34.95649141,-0.116205259,42.60320676,3.204020654 +75,34.35647513,3.947585961,4.809771484,2.320587819,7.316102932,2.987661833,24.01539056,2.728887261,23.08151627,3.511693075,17.19109236,3.623727734 +76,34.35199655,3.056287878,18.67208887,3.536497778,17.87047182,3.669793918,22.95778864,2.744522014,34.75115211,2.468096137,12.73883719,3.504360394 +77,1.277389077,3.337901228,5.854837443,2.810635167,26.62508279,3.157204571,23.1991535,2.664286525,19.94160236,3.235739589,15.05863456,1.704330146 +78,19.64269442,2.417420044,34.41701929,2.263432484,20.33169191,2.91432843,-0.504042904,3.698565542,17.06264298,3.285165651,31.64781799,3.29224399 +79,24.04819577,3.71968903,14.43911577,3.480233975,9.082470836,3.361430519,19.72054596,3.028300961,40.637734,3.716599185,13.94643836,3.088554276 +80,30.87618417,3.513415768,48.90242783,2.946697503,10.81318001,2.575466693,18.8643803,3.565768575,19.01313852,3.300520505,18.00031699,2.908207717 +81,31.74307692,2.85966603,17.849893,1.820422674,29.11110336,3.53379798,18.88630705,3.204467305,34.6249848,3.006722523,9.855693887,0.307434882 +82,21.47268496,3.327725354,21.38926124,3.192453546,20.85628761,3.390815969,27.01702401,3.505878295,36.74052889,2.929690747,26.19348735,2.965470512 +83,29.58396029,3.253829595,33.9998407,2.403011333,2.461359989,3.078383167,13.04232143,3.80142497,43.31192922,3.600856611,22.98020073,1.762847788 +84,49.53219987,3.589484496,31.55240084,3.326486889,14.74300569,3.383008258,11.28273189,3.445568537,14.39345614,3.658884901,38.17347017,2.613454207 +85,6.345090711,3.305939744,23.21774335,3.118580546,22.16150615,2.880603437,30.62740871,3.249576445,38.38915209,2.932028899,30.14143115,4.050907151 +86,25.39438148,3.680233409,29.573543,2.664007736,32.46201458,2.758818888,0.644816513,3.288220611,17.85197257,3.386105851,38.25558579,3.103160353 +87,21.65390026,2.727848312,35.15953701,1.486911657,46.84487637,3.814977623,24.5958357,2.988231718,7.880048155,3.150297663,27.87425785,3.031657446 +88,19.40787789,3.505987959,31.22690977,3.033019865,32.16181539,2.591114063,25.40815407,3.258928576,38.46772637,0.160645238,24.35784036,3.402630918 +89,10.96123932,3.567149729,34.87452194,3.678833523,32.1877465,2.948726641,17.77535497,3.69932098,15.57803022,3.164251985,10.67294142,3.214284079 +90,37.98258121,3.442685822,15.68722468,3.221651571,4.402378487,2.262586417,25.42332068,2.899679357,16.51350434,3.238277462,25.88209593,3.159873275 +91,23.63358866,3.315103044,4.170493808,3.366863786,29.1958225,3.32587226,29.45288032,3.294642693,33.35036346,3.268589525,23.06350264,3.052510522 +92,32.43437604,3.069192389,29.85867935,3.587778679,18.51421424,2.263797321,13.24275424,2.642966176,34.73120595,3.156435827,14.77024206,3.438244198 +93,13.57200481,3.184953602,29.36165657,2.421686504,20.7801454,3.679586378,27.02150807,3.192606517,31.81515369,2.603905124,18.10955642,3.546010526 +94,12.20807648,2.895005057,22.7468016,3.440772329,22.00941392,3.00290596,18.4736933,3.286690842,26.1998786,3.010173175,8.50123469,3.4098389 +95,21.7221715,4.018341577,43.16366439,3.475610642,24.89785282,3.420440794,15.85504971,3.417513842,25.2518724,2.519896743,29.32216486,2.879881301 +96,39.2536373,3.484099735,18.28541377,2.728736436,24.28838073,3.543253533,11.13692596,3.29856621,17.8840347,3.74325959,25.13675483,3.472216892 +97,33.61909403,2.972481293,-0.079765796,3.49836324,39.75597953,2.593172554,29.21823086,3.114021582,22.80051627,2.697837411,30.20057566,3.14383623 +98,36.60141335,3.570571932,33.3777238,3.393186654,31.00863541,3.143445812,24.4708575,3.413595907,23.24674891,2.295827469,33.48985978,3.762395731 +99,27.1131471,3.11448183,0.900252012,3.542852483,22.89471154,3.066611276,35.88995756,2.788942952,23.64688433,2.899318933,34.08908804,2.908666513 +100,13.21208126,3.56848401,22.3554019,3.053973786,30.16866757,3.266910328,21.61997084,2.868045396,41.90856517,3.506809873,27.26543472,3.221754334 +101,25.6218394,2.708188439,10.69132021,3.041757846,27.61685823,3.423819219,23.64393162,2.703601764,51.94916746,3.358445147,10.73129652,3.053520072 +102,4.917668519,2.885129643,20.83649093,2.675513331,36.26304155,3.19762989,11.60318979,3.42520383,19.6624868,3.733162463,27.09874025,2.633095903 +103,27.36896005,3.247580455,35.25392512,3.286095256,11.03079801,3.552332973,26.01288162,3.379992738,15.3744042,2.993287208,15.43251024,3.353558005 +104,14.04303551,2.500084656,38.03556582,2.832677887,22.66496238,3.318094601,41.53709198,3.494390704,11.94068328,3.545669865,24.81391197,3.592785209 +105,34.94213243,3.073151793,48.04995425,3.05304031,-3.180032651,3.421779897,39.7618239,3.049364514,36.70016308,3.221203414,31.66867063, +106,41.50117924,3.259588305,21.60689642,3.093773882,25.96173165,2.525153838,34.71806032,1.545739111,21.41118496,2.657883129,20.37738089,3.275175868 +107,13.82178792,3.492215617,34.71559883,3.685152316,15.83294595,3.031747306,17.43431298,3.58070361,20.73080233,2.705600218,28.70584745,2.724675513 +108,48.57687237,3.462175283,23.51127356,3.633797827,29.08520266,3.104155636,16.61647226,2.961725879,8.899226136,3.408460657,32.14293096,3.555714908 +109,30.16027183,2.505651863,17.54848412,2.220443576,4.811633068,3.405055324,35.31050973,3.172669383,3.270110679,3.45161973,28.6387453,2.512141629 +110,26.60058223,2.847711046,23.48076989,2.811155201,18.70113488,2.870224378,7.261866901,3.066338987,7.320230589,3.157600657,27.3124109,3.402795217 +111,16.82448426,3.385828067,29.35465831,3.355136087,18.2323699,3.347909224,27.63210873,3.677352607,27.95836275,3.38244515,28.965912,3.062712515 +112,35.76826303,3.434530919,38.96432097,3.569394835,31.23696546,3.267537631,26.37895637,3.070465938,16.08363521,3.167987881,36.11250526,3.168632271 +113,20.54182743,3.304133297,33.15516786,3.035491143,15.85469671,1.093386382,22.36554426,3.311692268,46.40792951,3.412960737,24.43576993,3.45944396 +114,17.74887859,3.450323927,32.38111421,3.40129489,21.91951667,2.816410925,22.75584751,3.155432431,8.934002857,3.226600474,22.43144244,3.51044261 +115,18.14819838,3.435735704,-1.107614914,2.175382402,18.32940441,3.172299107,35.92073809,3.490674579,43.2035167,3.598221748,25.31755265,3.630315895 +116,45.57612771,-0.141069363,35.31105066,2.836373286,27.39412699,3.167715581,28.66030167,3.909912862,37.60624857,3.179071228,28.73968177,2.376640259 +117,24.87735765,,15.14347544,1.950296836,20.13925588,2.519173541,22.2710023,3.264474646,24.15005472,3.07180586,41.40236131,3.587854747 +118,31.16878771,3.121855841,17.85326194,3.023420602,24.77748309,0.169424759,11.64528819,3.751109036,33.54494755,3.171412463,26.6287325,3.432306372 +119,22.09074746,3.755723105,27.02569104,3.204178962,31.03765562,2.585908408,25.51322254,3.342522362,43.82428348,3.23194553,41.00267685,2.918596426 +120,11.36968376,2.598811417,27.0985425,3.492613904,8.432109862,3.221973148,21.29323848,3.650675154,17.33855313,3.450373367,42.11242562,3.450431076 +121,24.75341347,2.794165109,4.381416229,3.815939312,37.58797251,3.63557802,22.89369173,3.436145345,14.82198564,3.698147428,32.08095552,3.673414757 +122,19.78142015,3.242984755,0.540861624,2.800577602,18.67071466,3.264781255,44.29639094,2.865647669,34.6439801,2.703090807,-5.013606373,2.992684313 +123,22.29470407,3.291657709,26.8910728,3.181682885,20.72131035,2.435754342,7.532795454,2.574783125,20.20598392,2.76000685,20.33096284,3.291347725 +124,19.69167488,2.937485458,33.61670737,3.455365135,23.06696242,2.651116564,6.76423913,3.59081116,27.78687836,3.609118268,4.803566774,3.09424999 +125,13.19688529,2.352768882,31.90219923,1.617523602,26.48074938,3.56336749,27.40431698,2.950296498,26.86972406,3.373409904,19.45791096,3.374469275 +126,24.69128206,2.561419854,41.11704268,3.699385438,19.0359262,2.874164234,23.16015361,3.354455038,16.04743326,1.744662277,44.38534585,3.419291154 +127,31.68611461,,27.86303118,3.611706749,34.26716994,3.37086045,27.05927928,2.732727745,32.12645869,3.530044096,35.39819355,3.71269598 +128,32.3833726,2.903983382,17.66483999,3.692647175,35.5350708,2.8363572,29.55925408,2.850400558,39.31175723,3.155968458,28.37685011,2.825764669 +129,1.979640257,3.076833082,24.10310884,3.091264162,37.72078056,3.502627614,21.78992434,2.381860777,34.3992151,3.064917573,42.9898471,3.789473119 +130,37.46823293,3.65829805,42.65606923,3.564002903,62.88416834,3.3231614,35.77011192,3.116254041,27.91095465,2.492477661,29.22321763, +131,24.78790273,3.8431349,30.97881938,3.369712291,31.53360084,3.25578569,24.93003825,2.549182644,47.03077058,2.748823836,28.47601024,3.439855062 +132,22.91670281,3.473966044,46.26411537,2.870768811,8.621419461,3.214822782,49.51521718,3.297202359,18.30613838,,30.973301,2.779903577 +133,27.0851482,2.906389077,33.75177511,3.385292952,13.6951479,3.378991491,22.95595697,3.625566422,7.383625279,3.477281775,29.15976549,2.96290361 +134,31.4074827,3.114078474,21.05574634,2.244574465,21.64836299,3.76266112,27.47933614,2.548865951,15.75308465,,16.80797225,3.179889221 +135,15.72400474,3.14996192,35.30213061,3.138003826,36.43789198,3.671874918,18.01740052,3.337930513,13.38457998,3.361252371,22.48896224,3.532298388 +136,12.36671051,2.233530239,18.94881387,2.724848662,18.74918841,2.828118283,17.02091138,2.001635397,22.26687223,3.739934635,27.6546925,3.567692031 +137,25.79358378,2.647639362,25.52865379,3.643589464,25.24022144,3.238447386,32.96710559,3.590160418,26.99957784,3.607873299,32.71239651,2.650185322 +138,27.08428812,3.084349417,6.845461401,3.096486234,16.79231783,3.228472071,16.16743584,2.652129534,21.10000767,3.430343878,59.84982042,3.699586773 +139,24.45881177,2.979769567,12.06705406,3.504094892,18.93148987,3.15918119,23.9345161,3.643513052,15.43768567,3.172337609,15.10662878,2.950986894 +140,15.03507494,2.940447019,17.32620315,2.883983777,38.3442887,3.402276131,15.68806625,2.881445898,12.15429231,3.582825286,4.478656775,3.34477925 +141,22.32299335,3.322653244,22.53257972,3.678470234,21.05272196,3.379236572,45.1343692,2.835447236,33.3481551,3.08363217,30.53835499,3.770424456 +142,46.74156486,3.294704092,12.68024627,3.079556533,14.85857651,2.349346648,30.25180192,3.637358321,47.06146033,3.487364033,34.82418799,3.343662557 +143,0.049896863,2.918365687,23.23614952,3.310791877,10.28697679,3.082429107,33.74776868,3.411129916,32.60488341,3.151810909,25.08287336,3.652656332 +144,21.501268,2.349316674,36.35257824,3.749022686,17.57677646,2.682274141,13.95551379,3.504807844,24.82827931,3.287764837,10.19299058,2.850839466 +145,-6.574914752,3.439919468,24.60753805,2.730964246,15.18055961,3.178620863,29.0904636,3.652697724,24.91324887,3.421869149,42.15238988,3.220370509 +146,28.63120583,2.267631092,20.36936429,2.839359743,32.06373484,3.114302278,33.15022351,1.922092509,25.95141932,3.244368764,27.0125713,3.549104219 +147,40.36899337,2.67268464,6.831623354,2.931468405,32.1244601,2.791091365,37.88378525,3.08221806,22.77355598,2.940786801,10.82404166,3.299580137 +148,28.7968647,2.861630809,29.31440875,3.569395417,23.51006069,1.043819954,4.075100784,3.42474823,21.42684123,2.833069405,29.82334136,3.229070894 +149,28.4809215,2.906885445,20.47903989,3.162630964,31.92018468,3.226973487,27.42238456,3.216886778,7.346777662,3.289115434,38.13978643,3.741632946 +150,15.68267136,3.773587728,10.16502096,3.874664326,16.08656166,3.667887562,32.72588348,3.485941802,23.92847864,2.436640553,13.47738343,3.557719789 +151,17.38880891,2.662636447,12.32550131,2.087059484,21.58778077,3.859338403,6.752131387,1.85661326,16.10896497,2.98570223,31.19202537,2.992699143 +152,34.76321044,3.279123149,18.37384534,3.043721697,20.95933382,3.408380823,29.31749829,3.613607337,30.4164032,2.409088267,54.4302037,3.182968261 +153,34.01931495,3.172853439,31.39672983,3.308109724,32.17977734,3.45020793,40.69847207,3.343400881,22.09039366,3.220239015,50.08982634,2.968677901 +154,31.76960278,3.490379365,24.70134301,3.017579129,38.31596462,3.181030383,41.4545346,3.211254251,5.029064465,3.404600667,18.13634379,3.562957941 +155,29.88183433,3.087215903,25.37194617,1.96033124,32.15392556,3.024798372,39.32030009,2.836704951,28.8674779,2.547576453,20.50219079,2.737931996 +156,17.99642978,3.345904549,14.15880202,3.452196681,14.8414791,3.867592046,36.84126044,2.715047589,13.28173055,3.102237092,26.0316108,2.821809657 +157,34.89501499,3.253459978,36.96491025,3.514484622,4.376304002,3.518711058,35.09162402,-2.785522826,-7.529314522,2.495717855,24.81747943,3.185569688 +158,7.682622337,3.258167688,36.75904328,3.244488006,47.67496324,3.572845255,24.21574227,2.866467736,39.73517361,1.742910186,30.59440415,1.491548734 +159,-4.466460683,3.027964669,21.35225464,3.96122275,26.67749122,3.474758,28.80036165,3.194955922,23.95817229,3.233186214,19.60732169,2.995296233 +160,23.35120111,3.260862049,27.39702176,3.299986619,29.57229168,3.33075929,39.51092507,1.75824373,24.95500319,3.492970435,27.19740688,3.14830121 +161,28.4969954,3.023584346,12.9086867,3.413357049,24.69161596,3.520940482,25.65609866,3.338540746,37.66072088,3.256191682,-2.90375211,3.395557724 +162,20.1467634,3.110012265,34.88258771,3.31703613,22.44846448,2.474680853,31.67821921,3.646365067,37.09701916,2.411182594,26.95259078,3.188977364 +163,46.46466707,3.547116644,29.911743,2.908936023,29.94353681,2.729512505,25.80055716,3.281768509,2.453231246,3.531962477,24.47804895,2.52080202 +164,43.01305235,2.897297931,18.50591874,2.117703468,21.43703028,3.189847114,29.65117763,2.753285621,7.503503036,3.032352964,47.60516383,3.599503114 +165,33.57502371,3.070205503,18.14660444,3.054242531,32.66451656,3.048633251,26.26342008,3.426773089,12.18688155,3.151373683,24.69281652,3.655966373 +166,22.80441374,,23.91740204,3.659706141,35.82450485,3.26996112,30.73174139,3.162708625,48.86083066,3.467814488,32.94313286,3.282428488 +167,11.19371937,2.691050167,17.44522716,3.472913663,21.2811646,3.408549786,17.57239632,3.539723932,20.65003711,3.026553144,18.04212354,3.697630088 +168,21.27225019,2.393682309,25.61055708,3.292621961,41.71806512,3.550705386,4.879435923,3.781255208,10.70368744,2.987935379,41.81880605,3.595667092 +169,42.7047958,3.321307271,25.63877479,2.30441839,11.33223731,3.256400614,15.9419476,2.367565937,35.20374997,3.28856977,22.73672975,3.345519473 +170,28.27167383,3.301239335,24.90488698,3.288955881,20.03071766,3.732200514,28.93481171,3.043859495,42.78922182,2.693865339,36.40325211,3.73928117 +171,40.74303857,3.227734221,23.37973984,2.516952228,13.76360948,2.764299414,30.04275589,3.425986098,13.51119069,2.357964189,10.27954109,3.139052133 +172,23.42789567,1.89014849,39.00942313,3.184171066,13.9738096,3.499479076,25.12769505,3.225688796,39.49245992,3.391512875,40.81124601,3.06576041 +173,29.89971866,2.487063511,31.58057966,3.063745951,17.81724057,3.042979087,23.40616979,3.208035658,22.74515983,3.597698566,30.65953889,3.369162877 +174,22.45082543,,30.97762179,3.161690799,30.96300249,3.300690304,26.37159092,3.086778419,33.23479215,-4.591944823,27.61353648,2.790623809 +175,23.07066319,3.331191969,14.58081104,2.936665711,28.00968205,3.463688356,19.29303919,3.54125822,10.23181225,3.165682183,39.05679004,2.555936985 +176,37.8118852,3.239883768,5.987148853,3.557779013,22.26629711,3.417003596,33.35767603,3.325811544,16.29018421,2.856063823,25.40568842,3.286325011 +177,12.56855609,2.47002412,32.58198386,3.386317045,7.422280508,2.985195462,23.17733337,3.812537854,32.40983723,3.104521274,36.36316192,2.838042445 +178,21.16674845,3.15274575,8.192956971,3.000381591,33.95763633,3.288105063,44.29399334,2.924474391,23.66784858,3.251493208,41.76576699,2.859066175 +179,37.64967314,2.973980305,39.81264443,2.699145216,24.52050859,3.349277117,29.15805454,2.303911391,10.99981565,1.887854977,28.43428019,3.106765839 +180,21.74181928,3.138201583,12.57912614,3.703586145,23.32573672,3.362328155,26.09980043,3.292858493,29.64264602,3.376196493,35.1677648,3.45484655 +181,39.40029638,3.2525859,11.42609528,3.162748742,41.40513808,3.255858588,13.67465026,3.167125661,4.363229881,1.717338495,32.81044228,3.468702253 +182,8.452653368,2.761894327,10.21976929,3.610969875,22.58649515,2.626612022,40.88664413,3.50711242,30.4475003,3.862773961,34.85117497,2.870784107 +183,27.54718171,2.750304762,26.98666088,3.293931793,7.100314018,3.468176445,44.90621163,3.510851292,19.88952645,3.042640659,13.67059271,3.394763756 +184,9.596587529,3.411541672,39.66646486,3.7630868,22.95624434,3.44210021,18.91003253,-0.535054401,23.89974643,3.354313953,26.62986326,2.802709161 +185,7.761691483,3.505801395,7.252559086,2.96974827,12.54836944,3.899763212,26.72680903,2.739636094,4.193936379,3.299697446,25.85210306,3.645074882 +186,37.18205094,3.776898124,22.45521219,1.974859212,34.72722055,3.922180262,22.80525088,3.23608073,32.84651255,3.222790205,46.70374367,3.316520803 +187,39.44367782,3.154481475,36.19787817,3.809552592,18.23058826,2.854601674,26.96559753,3.420109494,35.45682401,2.779196564,24.57494736,3.402924787 +188,24.46518114,3.58158575,8.509483147,3.101645668,-1.506363529,2.649715958,10.51935153,2.907904979,35.25621896,3.25343566,24.95647027,2.052979763 +189,38.65199032,3.576345046,22.26315724,3.129717123,22.06242432,3.553142459,25.90703352,2.928531174,25.48540498,3.793372109,43.74643183,3.623328967 +190,15.12746075,3.706116015,20.84705869,2.806563794,39.12864681,3.119456619,23.81156055,3.670910998,26.86758943,3.310179196,12.59322874,3.181888551 +191,35.91330718,2.439533265,41.88869496,3.752042904,17.01983719,3.598875373,20.29977074,3.837405798,5.488147087,1.501368503,32.0440531,1.878507145 +192,29.05935204,3.04669124,30.01734973,3.366606688,15.70170491,3.009069109,33.55991366,2.958751108,27.08075334,3.120144088,5.955708307,2.568386735 +193,18.25730398,2.769239933,16.09299121,3.234407656,20.96683763,3.200571458,23.76276384,2.416857,5.449754088,3.309017366,17.36490159,3.142221432 +194,21.62628778,,20.98900008,3.365872646,32.5078305,2.904806797,26.99065042,3.273163417,20.79716404,2.688703619,46.62646424,3.098594548 +195,29.93236532,3.282915982,39.67285318,3.354138696,30.70443776,3.569713901,32.05815548,2.244855089,11.92737808,2.938463281,31.0981971,2.739987524 +196,12.67987284,3.359266131,18.9475175,3.512642088,12.64158318,2.773999345,31.08056301,3.01268272,34.45459485,3.3268936,33.43007546,2.134714417 +197,41.22608896,2.977491923,33.76611859,3.584139081,22.88750911,3.475023604,10.12836782,1.371540936,3.251413049,3.349522971,17.65455484,3.295431012 +198,25.75090031,3.717113498,32.45014345,3.096221977,28.49151421,2.975070765,23.32074596,3.611451286,14.75777358,3.682781194,24.4432094,3.110918966 +199,1.127539924,3.267892896,29.7476573,3.540627994,22.58356709,1.987253065,29.3966133,3.435039801,44.66379155,2.694451338,11.17735585,3.21120557 +200,32.69102821,3.10867042,13.85600816,3.514556811,28.54183112,3.46661816,20.57553057,3.425419939,33.19766634,3.434777484,27.04839718,3.652070972 +201,18.52503071,3.511333456,30.71207015,3.309551352,31.2689462,2.848443859,17.83916157,3.219493248,29.27074975,2.908194436,11.33318946,2.994691979 +202,23.29149024,0.552107939,18.99105356,1.86923791,19.93040201,3.129754197,35.49354332,3.480337698,9.559754369,3.086798158,22.35307969,2.701912292 +203,37.44818863,3.272910902,31.75516697,3.600620991,29.06120263,2.280445461,13.4418833,3.348504486,10.59844259,1.932603616,15.97221281,3.161971826 +204,6.585303521,3.042174167,16.99116201,2.906848062,16.34464283,3.556107888,22.48106417,3.534870477,21.0384416,2.803056359,29.22246503,3.26155232 +205,12.21622831,1.174703462,17.13773647,2.877904112,30.55213387,2.700438971,14.03807816,3.485227643,34.1151979,3.116144612,23.96761669,2.564900787 +206,36.71702919,2.640333168,15.24662109,3.36368394,19.81767604,3.303113007,30.65001273,3.314104075,17.72937175,3.252943045,37.72388429,2.983574209 +207,27.70046067,2.844275679,29.07733525,3.096092757,30.27112876,3.68825863,3.005182762,3.419982284,47.12181774,2.745865584,46.56714376,3.038632247 +208,14.83506775,3.004854783,42.63161134,3.617372105,29.01830536,3.534219302,17.30755664,3.164775825,27.52165182,3.470782668,26.76867707,2.315903944 +209,23.34423849,3.558513073,17.19291564,3.23457073,32.89438417,3.575601624,21.88891121,3.452168622,19.80118033,2.832357662,22.91276654,3.830442164 +210,26.50821129,3.83415156,27.22541182,3.720364156,23.87393315,2.722417681,8.158533282,3.525954559,29.54373905,2.139721506,34.03752703,3.172502608 +211,23.70961041,3.557038819,10.99504409,2.677876637,35.22012727,3.185109952,24.57250421,3.371695699,8.008443714,2.381906177,8.129412772,1.588762088 +212,39.58584593,3.463464411,22.60983526,3.486660491,42.97442948,3.668114911,26.55974445,1.882215484,17.29281712,3.52399999,11.41087351,2.931991337 +213,25.21376979,3.631731983,24.71464521,2.651930958,29.9765435,3.812197965,24.79296792,2.540740978,26.76983534,3.32966384,35.06358643,3.339578713 +214,24.78490576,3.27754614,25.65526564,3.276871177,23.45507032,3.296620521,36.78041112,2.616651593,33.33558881,3.390381784,23.95751701,2.896656128 +215,38.99510937,3.440754005,33.5450901,3.189032848,45.52433902,2.593417549,18.2684362,3.238763247,22.83309899,3.061154441,29.88241837,3.234283083 +216,28.97882197,3.442921057,12.81870604,3.387781696,41.27067005,3.55803394,-1.831383809,3.093733942,9.761148415,2.82927486,45.73101603,3.100571748 +217,21.62510221,2.858874876,11.1267233,3.174838065,22.9910967,3.092819474,26.74732496,3.480902694,19.66978493,3.463687395,39.82319601,3.147064881 +218,17.82057117,3.329484377,32.49716003,3.72985772,23.12332889,3.281121249,15.99537351,3.700320154,10.12274356,2.509443106,32.68852715,2.992978082 +219,27.69044882,3.351624672,22.9128759,2.230104237,10.32884237,3.075276372,41.78265896,3.041853927,36.03060026,3.317221486,27.87554978, +220,20.25944473,3.736687175,9.394550749,3.235804061,17.09568101,3.367888284,43.55241,3.425376073,37.06777143,3.307973472,29.53532548,2.970737431 +221,18.69389895,3.233720288,25.66937844,3.296054955,19.77987982,3.211141059,22.0625192,2.376688467,36.24646484,3.334594983,28.75631759,3.048237762 +222,24.09897886,3.418220971,21.90309884,3.238635852,33.99245481,2.89738569,12.26104965,2.935165794,32.34848147,3.142302847,25.85625248,3.203418349 +223,21.74322543,3.394706608,28.12313451,2.420224566,25.40490368,3.204511809,21.82832932,2.469599427,22.68612655,3.272873976,50.8798661,2.908038064 +224,20.41753092,3.136174369,34.6470719,3.474878166,22.81715407,2.558181248,20.71185606,3.159594778,19.87534833,3.059362101,22.94186175,2.894103932 +225,20.0869439,3.149985437,18.3774802,1.974613366,28.80729038,2.729917626,18.32435454,3.713817571,31.07371945,2.986159299,24.73476316,3.264609439 +226,39.77259933,3.540652352,32.2008481,3.303070074,27.65627088,2.372898429,15.4319384,2.463052162,32.9263056,2.425966558,12.42423425,3.81310548 +227,23.13294011,2.791343872,10.02333226,3.752700309,16.73759083,3.692304858,14.04088697,3.637727244,27.20346408,3.383539434,30.9931381,3.362295155 +228,4.23451442,3.053658218,25.05032184,3.012938069,12.35146336,3.704435496,19.36622245,3.121081021,39.06843053,3.763136653,16.9935182,2.440324634 +229,30.61451995,2.27493869,11.56790607,3.256016249,36.36251973,3.351969784,46.41888884,3.479820484,11.75486836,3.138292723,27.07453969,3.132823026 +230,37.64218647,3.354131024,18.55905703,3.644056647,16.03619044,2.572070169,14.05995267,2.812499383,48.99034958,2.709094269,40.11079062,3.340372217 +231,36.00877851,2.914915852,26.83989382,3.355070449,30.30046354,2.488983895,19.86798646,2.892606874,19.32501213,3.289839464,38.77075409,3.340907089 +232,33.72807891,3.468363751,35.72242376,3.029779584,20.44378318,2.625007674,16.55158442,2.653401698,26.12966338,2.933078045,25.97117695,3.079760539 +233,17.77764702,3.922347886,24.74234128,3.467533074,29.30049954,2.305357977,27.94977129,3.854419762,20.14022246,3.615246078,19.35732151,2.971370057 +234,27.41165489,1.113280425,31.12646894,3.397520214,31.42333986,2.873947697,29.74607811,,48.77571989,3.050088935,26.7896602, +235,35.48489973,3.757427045,32.39187045,3.325587187,26.19184114,3.596702298,3.332198048,3.397833016,24.55844375,3.593529883,44.68379355,3.212562141 +236,22.52305586,3.604493131,19.76105805,3.689267255,16.90218148,0.791352029,9.784914203,3.320907933,44.42378735,2.834947097,21.49886786,3.190354096 +237,23.41347503,3.468350545,25.30988727,3.66386939,31.88825421,3.397597303,25.81627419,3.040883025,8.058957677,4.035143187,41.6856466,3.189789835 +238,26.30681731,2.480509967,44.93242059,3.162158867,25.66639164,3.703918145,28.12518951,3.173028418,23.4466601,3.334734483,19.93607493,3.214882511 +239,11.40314092,2.761892457,29.93223979,3.157208142,24.88797505,3.34239092,6.623920168,3.437646048,23.15521821,3.922744533,30.2517873,3.816262614 +240,40.33664528,3.330282964,27.66152161,2.947589818,30.65050426,1.63451551,34.59367056,3.001716666,28.09144402,2.932700879,17.81759912,3.115242134 +241,22.45543162,3.268012074,22.28351702,3.308447224,38.63748371,3.728371894,37.30907591,3.530986563,29.68929219,3.356052854,31.61166786,3.703187782 +242,11.61154626,3.74998599,27.76124311,2.832885177,16.18296999,2.960671147,10.89007875,3.179464442,26.72618442,3.480741875,19.16182122,2.655500324 +243,27.38752251,3.132126839,16.69781483,3.257284662,37.06623735,2.672475903,31.87398041,1.559311496,28.60114835,3.085696183,41.00957886,3.354486471 +244,30.41588631,3.056681108,32.19502727,3.11420339,25.03834896,1.96591355,9.967241497,3.600609264,22.22495273,2.276188719,26.8911491,3.225317151 +245,6.894352639,3.752254367,33.33239932,1.998960923,30.07044535,2.475018887,38.11982851,3.207401319,32.98130786,3.296572467,11.71072404,3.389437722 +246,20.24785588,3.25729385,24.08100678,3.230300338,36.64929768,3.407240204,22.65369498,3.710198995,26.0225569,3.291726441,51.00320439,2.0608419 +247,13.90453027,2.93891455,15.78331398,3.141768867,1.620925062,3.188130895,13.28173467,3.461557309,34.84527183,3.604628491,22.23564255,3.254881099 +248,24.96806647,3.72955798,27.99553139,3.621085729,34.84713094,2.810719479,31.75254741,2.482206863,24.69442706,2.430334099,38.83437227,1.485227804 +249,23.22007454,3.882357337,23.17923061,3.067557566,29.07167114,3.689767291,34.91211803,3.246924218,18.96659155,3.572979749,27.69154538,2.864774161 +250,18.29387498,2.951868168,33.50278952,3.158701637,16.94605907,2.723607876,24.94503769,3.361135941,16.08590415,3.481702964,46.79276691,2.938824462 +251,20.92319904,2.805933882,29.8767667,2.768659512,19.18594038,3.229398009,12.79647911,3.309293991,22.1794518,3.38881771,13.82885302,3.432477395 +252,14.83518853,3.436571085,19.76667502,2.865794953,23.01720756,3.107507348,22.53379501,3.373894438,17.97522627,2.583692668,14.68262458,3.652630602 +253,42.32392565,2.999248164,30.84094506,3.468881527,26.2867217,3.29618827,18.42776887,3.663252187,16.24482055,3.73163649,25.29950769,3.746840506 +254,29.81307582,3.41084464,9.021067445,3.29600838,27.61051893,0.028561229,26.6287809,3.677399847,25.41410068,3.363267689,36.12120859,2.996504021 +255,20.3898354,2.653898861,30.35822009,3.321104671,20.80915285,3.471421277,22.84438209,3.435035357,22.63439778,3.15273451,28.99910079,3.204240756 +256,27.9314534,3.726352739,30.51281864,3.592993789,10.96320625,3.523831709,20.86692467,3.401978665,24.03981666,3.383164481,34.45257856,3.202337049 +257,15.04205349,3.518368231,8.459093244,3.531781304,29.99282646,3.590832082,49.2723363,3.450240259,23.91054138,3.527473,27.80022785,3.40276902 +258,32.73182075,3.65286129,28.87323905,2.255795303,6.526190105,3.39261471,26.32474814,3.316351231,22.21218074,3.095293526,19.68452958,2.634405585 +259,1.129849022,2.483809565,23.20541881,3.495869381,26.8523549,3.467622123,28.36170424,2.876018967,19.1696402,2.939832418,23.4724869,3.071255321 +260,21.12655148,2.543907413,23.83818921,2.538657292,30.42194014,3.383198773,34.49538,3.728900393,30.52265201,3.076124419,29.88171806,3.322190975 +261,23.03898759,3.660781238,18.99587831,3.252865693,47.19998643,2.93194527,16.52835759,2.841326055,17.19315763,3.5508893,30.21833191,3.257485624 +262,21.06101819,2.991274751,7.156966485,2.951483184,46.89258798,3.520999482,1.526310501,3.477577101,28.16205659,3.795294767,28.75886934,3.26967867 +263,45.39011599,3.802803294,20.99841601,3.45193855,20.74491014,3.13577203,17.56017579,3.588044645,7.337882572,2.364976271,33.02974613,3.550892578 +264,2.058357607,3.080603577,29.69303305,2.77281849,41.09260427,3.877038599,24.48215471,3.431841023,25.07906123,2.015989776,31.74906441,2.765506279 +265,21.07079526,2.775912755,12.17948939,2.58029236,14.41439414,3.196133238,9.336433572,3.42457759,34.94109538,3.290476723,21.32160537,2.538437282 +266,21.67205098,3.321046111,56.52027824,2.763195564,34.25611763,2.446187217,27.04766383,3.18581087,42.6800762,3.04777527,23.40295868,3.21660116 +267,33.70012121,3.363370463,28.06158013,2.648673787,20.89434698,2.862579339,37.85610942,3.563471755,26.93279089,3.133741554,15.81762995,2.727409497 +268,26.62718559,3.745539186,28.30652588,2.648371957,24.40855786,2.308998506,32.21981213,3.344632523,33.4016606,2.970490799,15.46311838,3.570939172 +269,17.96304029,2.301759033,28.72457307,3.02618862,20.5131906,3.291102346,31.16580059,3.274662779,24.39001806,3.289999825,17.93969111,2.285770064 +270,6.764324725,3.044745799,6.676982624,3.417455237,20.7204288,3.13030711,10.016103,2.662132027,44.40220343,3.494272673,32.2856915,2.475696559 +271,35.53814546,2.984904365,22.86146596,3.29263813,39.71219323,3.096650997,13.13019706,3.79183224,26.1598791,2.877614672,36.92762364,3.539713833 +272,27.78901345,2.900894292,20.99998758,-1.447578956,32.16699461,2.589181748,25.64383739,3.625869659,28.04458486,3.832100898,20.78792142,3.089106371 +273,30.17168161,3.764466311,24.24200479,2.929713312,5.062358063,3.510287677,13.40646763,2.576536523,21.97771732,2.802845782,14.9645243,2.554965444 +274,14.52388211,3.443779178,33.27476349,2.970449677,37.87157215,3.551898448,25.2337439,3.13081693,32.99718668,3.533582411,31.97443885,3.522090092 +275,20.46263975,3.121772874,40.51141341,3.464987506,13.62090641,3.712184919,29.88836188,3.146955386,23.36397092,3.700195166,-2.353582088,2.37250696 +276,33.03351221,3.554094685,13.06167562,2.972055951,14.88175721,3.107632018,27.65601476,3.148919369,18.34334057,3.414242865,21.49585556,2.677225389 +277,39.46467951,3.221951528,38.27140056,3.284308254,18.29735265,3.510603205,26.86505661,3.091055577,18.78742436,3.220788719,16.37443936,2.850966633 +278,10.50522212,3.344627999,34.8776137,3.016858657,20.21637613,3.110260705,15.80958098,3.554436152,23.36156149,4.005108532,21.81637171,2.904099471 +279,30.47608978,3.664714388,32.73444286,3.49912963,23.87382024,3.130361698,20.09984507,2.352818289,17.44636048,3.229218093,14.92052196,3.295296231 +280,43.75541981,3.543905206,38.46295859,0.797057438,17.49275914,3.178311418,22.69888948,2.276976609,10.7624542,3.586364372,34.52358771,2.479521363 +281,21.57237021,2.382988084,8.062565427,3.190288875,19.49214095,3.521473233,16.70062264,2.434905086,18.97792642,3.776972134,47.33858297,3.222086019 +282,13.61974776,3.637997417,31.09780403,2.851028687,24.83103929,3.187641956,21.75040711,2.665553633,20.941403,3.261994388,31.83205143,3.707352508 +283,38.07380663,2.88914877,19.09218864,3.167702508,16.42169231,2.972842249,49.16745011,3.461335527,21.14940063,3.663599268,38.54061804,3.304014119 +284,21.07835296,3.096899319,33.61746141,2.988032599,24.58392254,3.383053623,19.0891209,2.159776643,34.07053109,3.320836198,30.06572457,2.617303814 +285,18.66690833,3.59389249,28.09012048,3.233231163,14.05058119,3.303896729,3.769077625,3.489114649,43.47621912,3.574186381,10.72503152,3.02287306 +286,16.18135468,2.779849808,14.81319946,3.256937512,21.66011957,3.479865492,33.0837188,3.136503696,32.2060883,2.123069764,19.99603124,3.36112455 +287,19.27816027,3.426367607,36.49738842,2.720345331,31.30798339,3.577603234,4.972160068,2.910353938,28.03006492,3.808359686,17.68159902,2.241039412 +288,16.42032839,3.066886386,17.79543586,2.844132551,-1.945502173,3.251623522,28.66096619,3.465321207,12.73401098,3.440256629,22.4640623,3.164051766 +289,39.42820682,2.557820247,41.88252716,3.512688854,21.11013274,3.756140699,23.03559625,3.557928408,11.74586511,3.144287709,18.61665831,3.852459619 +290,28.57748456,3.778374944,30.42393225,2.565087655,33.72942554,3.348251377,34.4249719,3.517815057,17.97748166,2.873882217,4.891759325,3.550113741 +291,17.77505063,3.497849261,28.30467755,3.283116697,25.13437354,3.315807997,28.22421151,2.866922048,28.11532447,3.476217639,19.96549198,2.230443134 +292,27.18538,2.80153008,14.93165192,2.669654766,35.15784835,2.79628299,14.6949392,2.744447523,16.3143178,3.414302786,27.36250621,3.273202441 +293,26.97069938,3.250984793,21.19138048,3.416066097,13.31634943,1.374569788,34.36455738,3.009223238,28.08675579,3.011437225,31.92609979,2.530986651 +294,31.10818124,3.326173958,26.5426017,3.132994346,28.49982159,3.390713435,20.73169444,3.149341845,20.20540739,3.444554861,14.64118354,2.872445996 +295,34.96542533,2.717252248,9.770535975,3.737308086,31.8679033,3.189607107,29.41758557,1.092322743,18.11246813,3.822881019,33.76141874,2.58295566 +296,36.50074048,1.948851715,23.24442008,3.076323022,20.19878959,3.330034033,41.79309882,3.671689373,41.81841378,3.163895925,13.37637357,2.994381874 +297,19.89065104,2.257636991,35.14849092,3.568712957,26.26246991,2.789282605,13.68176383,2.035743523,22.35560758,3.28785846,24.92041072,3.812310572 +298,23.10755525,2.880393971,29.06268896,3.034663605,20.66994347,2.431071705,33.20529348,2.0323121,17.71693189,3.587842665,27.89727245,3.621106269 +299,19.04106854,2.942083766,11.10764083,3.145801106,24.15091492,2.329279471,26.35348634,2.476768508,20.25251083,,26.26515796,3.108942873 +300,13.83225368,3.427818335,22.23422059,3.743698543,22.86847402,3.609855203,26.12290504,2.904024682,8.435886208,3.71907935,27.48804056,2.910871612 +301,19.37758692,3.483952444,35.33906466,2.966801212,14.28748599,3.230724072,15.78750897,2.858028131,22.49066484,3.525115109,15.92744495,2.690331576 +302,10.82543481,3.34922073,14.14162974,3.332630717,39.94787096,3.141489834,15.05538172,3.296223271,47.88906466,3.393176607,40.71835541,2.390783666 +303,25.59696827,3.580540096,25.24670488,3.320033307,26.32158312,3.401236413,28.4853844,3.550726479,28.0854902,3.335356272,24.16409305,2.616381968 +304,41.61659005,3.215741433,20.68122133,3.066555564,21.04778399,3.497480052,37.30401796,3.252309198,26.0244623,3.4693109,32.2745326,3.402551046 +305,26.67958544,3.64161623,22.81651371,3.077611097,41.640256,3.441585817,42.38495621,3.46638961,8.047074886,3.106254965,42.59691537,3.014630969 +306,14.70127505,3.27030029,8.884029778,2.585974263,23.72620082,3.1865253,24.73597338,3.630588972,38.10991036,3.583328617,36.98441186,2.977588139 +307,12.87273724,3.277115431,39.01599498,3.792328155,28.34927057,2.897730975,23.43852175,2.841839786,42.24439782,2.942529101,15.7400759,2.537336305 +308,20.82020697,3.361975008,25.49307231,3.48513178,36.08297832,3.363578118,27.43383402,3.456197331,23.20248261,3.432802587,3.754336847,3.040066677 +309,11.48985319,2.478055601,44.36092564,3.177631577,20.92058755,3.830055412,41.06472181,3.519731833,24.36431212,3.665487196,33.00621304,3.148052187 +310,8.748592802,3.207241376,13.64487211,3.030427518,25.69477298,3.732127576,6.658739172,3.633209334,31.67473013,3.349644412,9.930649706,3.32564077 +311,21.16632682,3.523953827,34.89229461,3.455503766,18.82686189,3.350446467,23.34499477,2.989497763,59.16153923,3.613203089,19.39747961,3.528653336 +312,28.9976339,3.697456336,23.72029009,3.064008499,17.81951192,3.097593223,31.77885581,3.597206256,23.43533911,2.979317681,30.09412899,3.453641175 +313,42.24006353,3.309843526,35.42201047,3.815961391,31.39789055,2.969490551,9.059163165,3.150731138,18.77193042,3.133563902,23.82025083,3.756411939 +314,14.18310836,3.307439542,19.81742481,3.013019868,31.21979113,3.33721501,33.20600822,3.385156542,8.056796524,3.725404953,26.36737279,3.153528216 +315,10.42119612,2.849646783,3.693910042,2.812819201,28.36856918,3.060366335,34.21301381,3.544923623,31.35051534,2.727900225,20.58958725,2.799691209 +316,41.45442894,3.498786757,34.1457811,3.111450211,4.612065252,1.700260796,12.66997981,3.559308367,20.37627903,3.394384774,32.37885994,2.976573132 +317,24.55989242,3.162593429,12.24659828,3.263834793,21.4538837,3.452202324,31.74565824,3.516436955,24.65602414,3.283728429,20.18971932,3.544579378 +318,24.00629031,2.737120288,28.83418856,2.785627642,42.96089009,2.952308598,26.62150871,3.693343707,38.92569197,3.02671313,39.11698713,3.822278498 +319,16.56472716,3.045830561,8.989394118,3.247821061,32.26899455,2.468102193,31.04717737,2.91478113,13.80581737,3.336122035,19.06602628,3.264793699 +320,9.088381547,3.354045257,9.211001729,3.641685365,22.01881418,2.547563235,15.5499052,3.026556827,11.18326635,2.604864717,44.7765241,2.921473099 +321,7.539406075,2.950681824,32.34545264,3.760644943,21.61688569,3.48705504,10.97755931,1.939633492,24.21986277,3.311294251,8.557041132,3.411125009 +322,37.3874278,3.17548839,36.88742064,3.342438209,34.59628228,3.006512662,58.35936238,3.583159766,29.28751973,3.588325823,9.002444274,3.444863746 +323,27.95772521,3.407473441,29.72388503,2.937518856,26.02044141,3.195786802,24.71720903,3.585265461,34.63776382,3.172673086,32.27929369,2.767287521 +324,18.15245214,1.302548329,30.71829634,2.560794346,34.93864418,3.128716753,8.220564182,3.12327992,22.41162055,2.996433948,28.06715656,3.425223713 +325,25.60032772,2.023478253,31.21129909,3.343836267,32.62396222,2.921553656,22.9136304,2.706477792,25.27275686,3.51679026,37.00422319,3.132420781 +326,25.27437522,2.954672728,15.04915405,3.382606492,18.05012215,3.049828274,46.79882129,3.450238181,37.29061283,3.074518558,26.86577223,3.31012247 +327,22.75801235,3.032983527,41.26988526,2.943919249,30.81916602,3.015047837,24.09174891,3.602172998,34.03623096,1.104444676,29.24014023,1.984958931 +328,27.64003222,3.595996699,27.10962481,3.646829494,32.75378786,2.861016506,17.57078335,3.101312309,21.43578759,3.997308675,32.40726756,3.431712323 +329,33.58598732,3.28017276,32.5211054,3.578094096,19.65381258,3.342564348,36.26274705,3.467237625,34.84840014,2.355333499,11.48419246,3.41815383 +330,38.33162131,3.651827547,33.97137985,3.263853849,18.34008592,3.263117612,37.78733453,3.086276709,29.38608179,3.064813293,20.04510853,3.144880687 +331,40.43066047,2.670154533,20.51186521,2.972505219,40.883614,3.61232119,16.31475488,2.8027658,4.845853277,3.449094742,22.73956181,3.651652734 +332,29.27648123,3.156566057,24.83867484,3.099665191,26.88033581,3.714434376,23.36751719,3.560628642,55.04583486,3.33331146,20.64260403,3.092061166 +333,24.29680249,3.461214648,40.01237867,3.57882556,19.92428087,2.768370366,24.63487521,3.617119527,15.73431011,3.047965588,32.38836589,2.847093504 +334,21.35598666,3.134413161,21.39753727,2.586764887,35.28801784,3.662292978,34.07624299,3.884667248,25.26837076,3.610377761,16.0788532,3.529257723 +335,19.58222573,2.977783291,42.38044636,2.690006898,23.66252469,3.501751647,34.84534332,3.038124529,15.97194307,3.229235219,30.96026014,3.300032358 +336,28.86825655,3.655509803,28.13070953,3.05708181,22.13863713,3.620964533,10.41483724,3.025736382,20.65966507,3.69588093,25.43530471,2.897264 +337,33.28615311,3.021140897,32.74594021,3.505096801,21.06207386,3.594895037,21.75382316,2.814597492,35.51604481,1.435492319,42.58257042,2.684434963 +338,27.81562286,1.466588334,46.44288509,2.651846545,33.72733013,3.36000562,32.20620305,-0.797491637,37.78147919,2.442408601,31.58017638,3.023621358 +339,24.41629417,3.629757007,15.44817273,2.569273013,27.57523923,2.561009498,30.5960358,3.647088888,18.10820729,3.081249798,27.41566777,3.429506955 +340,20.96404786,3.656910597,24.22351424,3.186379091,27.0596176,2.622071542,12.70245257,2.497372507,10.46042099,3.255256445,41.37917699,3.29283345 +341,19.95176949,2.158811473,27.07303912,3.575203948,11.11147403,2.768371797,16.03860158,3.253484309,26.27869927,2.939695459,17.80603567,3.065312302 +342,29.16028458,3.451585113,49.38866229,3.551755864,21.26368774,3.149151465,26.72870282,3.247615015,21.08985794,3.539714715,46.01736077,3.626711428 +343,27.8289226,3.583857303,23.83744913,3.090274693,14.54089898,3.170954905,27.60303167,3.634493609,3.195713102,3.753905822,14.38062148,3.24489909 +344,41.35662766,2.895706324,39.18198291,3.294964306,34.50316829,3.323797455,31.22978231,3.341568596,15.58436545,2.713810757,37.23494032,3.65489069 +345,41.74541517,3.672693203,17.43863264,3.89176299,37.52271151,2.537422591,21.89414537,3.258388344,37.53359787,1.804422579,22.25789654,3.50241529 +346,31.23395032,3.31799746,18.34975518,3.317566528,12.23308302,3.665307721,43.59108559,3.42569841,23.98965066,2.806454175,31.81799162,3.524261439 +347,20.56123096,2.066785081,16.44860628,2.517940752,37.56291513,2.551884399,23.29676201,3.935010559,6.645898794,3.357032092,14.37149205,3.602015489 +348,21.18592494,3.004350493,26.08189708,2.848785428,24.25071303,3.512020109,34.44163597,3.727148665,28.44046239,3.046714849,18.67087639,3.501323008 +349,22.68804948,3.310886414,25.75232652,3.578587747,33.07267509,3.587303957,15.64096871,2.986563871,31.88908142,3.37197698,12.42339917,2.809050788 +350,41.14595983,3.260456026,27.1616523,2.495465695,24.76150105,3.861249434,4.421850863,2.830836314,32.69584262,3.264306997,18.46290577,1.730520463 +351,30.71103234,0.148211102,20.31204235,2.766056586,32.34246487,2.816875314,11.10590037,2.989516032,21.86743135,3.227361425,45.49603457,3.354362091 +352,35.97066941,3.076502493,28.02293603,3.812614406,23.51398212,2.805839276,26.01381029,3.285039588,21.81113624,3.243976842,28.11015625,3.327427542 +353,35.51674249,3.084697488,25.02743788,3.511384994,23.06086178,3.123877277,16.42464457,2.483002573,24.74570927,3.268113734,20.76497776,3.455796672 +354,13.24397163,3.374314055,32.08511796,3.349478176,22.28434425,3.111658093,41.06376912,3.148828539,34.82042055,3.367862478,24.01628121,2.84751969 +355,33.56511871,2.900811517,11.04685106,3.405671972,42.96461498,3.357579249,14.23042538,2.470307793,32.60938777,2.932785176,19.42127461,3.319740628 +356,32.21860434,3.622875043,24.216265,3.820268634,15.91407639,2.70695322,21.43805812,2.91225188,16.73653674,3.415866518,40.44190622,3.043526353 +357,29.07255195,2.466803258,38.5515348,2.67637374,22.48776982,3.698054639,46.42905173,2.917852488,22.2334323,3.142037496,36.5042127,2.700533766 +358,32.36464001,2.935235056,26.81194514,3.044880938,8.043484973,2.667208076,25.82366009,3.217112203,25.84020717,3.38986542,31.77394664,3.524640893 +359,34.01193809,3.192451608,34.50196755,3.792640518,32.52995136,3.483773962,37.9908872,3.345113572,10.45462025,3.522381947,35.61262731,3.319777755 +360,28.15631316,3.028372413,40.67408847,3.601329996,28.17252146,3.089164756,13.20519094,3.39017716,27.02735619,3.156398705,20.28539834,3.372699085 +361,13.97475201,3.395230978,6.644813607,3.086918651,35.85787446,2.792826899,40.97708805,2.771175975,22.66439789,3.386151334,41.24677677,3.26997156 +362,19.14333123,2.968917878,26.14265901,3.490017265,10.95072584,3.29739337,30.11550916,3.242298246,27.67409799,3.562397553,16.46434877,2.476449787 +363,21.41825994,3.339876574,29.34983288,3.365159302,23.16699592,3.74724531,27.76106931,3.342966743,31.8602927,3.110964729,33.47687183,3.421879962 +364,20.64631288,3.417122824,21.96925713,2.92360504,12.62098025,3.318017409,34.40296762,2.552123445,25.00185983,3.830939897,8.647831441,3.229539358 +365,28.23108368,1.838294084,29.56015679,3.063879586,-2.860175653,2.828716486,21.09968132,3.708757325,16.46984764,3.181926821,18.17257087,1.722742961 +366,18.74842846,2.435287785,44.55252913,3.606928517,35.64239623,3.511818776,20.40194717,2.351147835,27.8964687,2.233131095,23.91403688,2.507764296 +367,35.08413655,3.187909745,21.2380856,3.521012875,17.64598033,,26.89547221,3.324918111,24.55186793,3.321516317,12.56462455,2.736702474 +368,18.79290948,3.15491565,20.68589598,3.021730443,12.77046917,3.635096231,28.46978618,3.403362717,42.61941386,3.738181512,11.31858865,2.994090419 +369,25.20870648,3.76095472,23.9804201,3.429932404,25.83253245,3.462697631,25.05312678,3.188004959,24.99360971,2.903257609,34.08622119,3.470493956 +370,3.100569321,3.515865706,39.81983484,3.346512285,52.77255744,2.092479962,29.18087145,3.482755801,27.0090446,2.728975793,25.33406443,3.369584404 +371,42.22883909,3.20389075,-3.204891524,2.677937969,24.34621144,3.097728874,26.58838715,3.348370114,24.78726768,3.126027451,19.5924117,3.48672567 +372,13.64290767,3.185912436,31.77430953,3.036498625,31.15680748,3.24396279,39.76493459,3.267869258,20.67875363,2.426446638,21.54667578,2.18557958 +373,12.20671783,3.208828546,10.08934775,3.690412632,20.0648663,3.68592971,11.74747765,3.433382775,34.74026447,3.069242286,25.33063261,3.844321392 +374,24.79817539,2.830500874,22.26817034,2.91752192,33.70320583,3.067098643,14.81504568,3.488654563,8.543579795,3.671657039,9.861814585,2.69302012 +375,25.38196367,3.382983654,30.38052096,3.503898986,23.26735242,2.165540455,9.456581644,3.619708929,7.97396698,2.404912464,24.39051447,3.334017632 +376,35.48821099,3.439347321,24.7651034,2.861196514,30.15005755,3.419979916,17.13402814,2.853524864,32.1696889,3.020158948,18.62929863,3.106491056 +377,18.17449213,3.436953782,19.39419041,3.125533006,23.66429691,3.304217914,26.8355663,3.330698819,49.17134428,3.494037484,20.33961308,3.109915101 +378,29.21795625,3.579955417,38.56463778,3.807478454,25.03859406,3.18842096,21.18102726,2.641809788,39.22107166,3.838250126,40.16103736,3.552414925 +379,29.44301457,3.753689399,26.29445335,3.61639467,27.34194846,3.018589342,31.25391201,3.443714473,4.379137737,3.26139047,27.24528192,3.653218778 +380,40.38884075,3.987186325,30.99878482,3.770647234,9.186005451,3.644232746,31.43080549,3.711747139,21.2357588,2.991038709,37.8315326,3.919159243 +381,26.13358339,3.319040665,20.49707111,3.048952163,7.752586964,2.714007986,12.87613485,3.070027263,30.87128587,2.970347768,12.36725789,3.488497729 +382,28.12730056,3.308754282,28.6313514,3.150955694,16.80381557,3.206488378,8.035639115,3.181587603,15.14749649,3.437680593,25.02236279,2.243591262 +383,23.66672277,3.321529914,39.01550775,2.704615229,8.059499161,3.168264171,23.82478982,3.494452951,30.07535141,3.501230635,6.892996515,3.303150065 +384,35.97758127,3.412740565,9.119671761,2.557025486,29.15426322,3.718856896,44.35749157,3.33565142,23.32797063,3.305332026,33.85768814,2.953062471 +385,35.17680932,3.23196015,43.40888158,3.297448208,24.43325235,3.3765563,35.5609804,3.493481848,16.02466802,3.064697037,35.52871143,3.254135966 +386,22.84824478,2.344723614,32.7794764,3.526468454,28.89406506,3.585961014,32.74156917,3.839985298,44.21968804,2.527612563,24.06748991,3.056209578 +387,17.23609236,3.40289924,44.77473311,3.567624743,30.16390191,2.525634006,31.55962372,3.194221718,30.86854334,3.457242676,33.67391914,3.84281862 +388,17.89337939,3.578247709,31.64329871,3.231152201,21.47431077,2.916604005,32.85898945,3.407498337,20.43220886,3.112957141,52.21248016,3.335810996 +389,-0.574510413,3.253437892,5.487938273,3.426731379,27.17627177,0.762718639,22.02300681,2.821223923,23.36454363,3.793125326,24.76871544,2.062350349 +390,14.0901199,3.425247518,46.42653629,3.486735991,26.87247227,2.874798528,5.614016858,3.424281556,24.05689781,3.081344703,22.66636627,3.51804674 +391,36.61510404,2.017497592,24.26097643,3.085514962,24.48690174,3.419688157,30.16860276,3.444267521,25.361698,4.007234679,22.08617008,3.419527736 +392,6.354172673,3.558768314,26.09619879,1.884696886,24.76493646,3.204139942,24.03071798,2.685682235,20.16574167,3.588517151,22.68910694,3.190077328 +393,21.78384206,2.604078539,17.26566363,2.340517128,36.87156715,2.795679131,28.15081989,3.119073964,23.09502323,3.610626266,38.20389767,2.927163109 +394,20.43062352,3.29929702,17.32144715,2.914010395,20.87398877,3.458986493,24.56073673,3.461113689,26.5906725,3.563676436,31.49261947,3.463719817 +395,23.03148,3.544162395,34.37273229,3.11932429,34.99078733,3.136373831,30.32156684,2.987588337,16.94226972,3.791150168,17.99996648,-4.24820402 +396,34.68299898,2.982413516,18.91562255,3.918006552,27.36598173,3.019543535,26.43231652,3.391872663,30.003055,3.154072426,25.72798958,1.246807193 +397,30.38829269,2.995866023,18.91853841,2.938847743,27.93654898,2.587443106,13.30263261,3.548818082,13.37965634,3.755687093,32.63068269,2.766003353 +398,11.57366825,3.063325141,29.93092025,3.728734687,28.99804973,3.178195961,14.65158328,3.500436064,17.21071948,3.031749351,19.22090298,3.24869347 +399,33.19854647,3.800143858,14.83844208,3.326131345,20.74922887,3.402165309,21.75159476,3.228962281,31.68297457,3.372819471,8.176210229,3.142348942 +400,37.68844566,3.802403219,18.98503525,3.397095379,30.66321472,2.988269177,14.86763062,3.423751484,13.80173002,3.264421742,26.3038287,2.881601688 +401,23.48545427,3.326029993,21.44316291,2.429945969,37.41295924,2.749548798,20.61535395,2.699453903,37.07450397,3.417192555,13.36869651,3.86048603 +402,27.45343489,3.489298018,28.90562662,2.888661737,32.80752468,,26.70346905,3.592641753,12.88745647,3.219849699,19.39922194,2.036168432 +403,23.94053044,3.204468836,37.05242683,3.841286025,17.96742122,3.237231064,19.15305327,3.080462095,28.21072962,3.169438474,21.33616226,3.285732349 +404,27.84819663,3.459708799,31.18567876,2.890926122,37.52886191,2.978893565,14.00251902,3.56055484,23.20115001,2.298952209,29.16486851,2.780784317 +405,32.56092062,3.590384678,19.32208622,3.024258918,20.80660165,2.892636566,22.26615755,3.552890787,2.89026183,3.725731119,17.75144514,3.614184604 +406,28.50874755,3.234879597,2.144240347,0.155215082,26.37834555,2.540878638,26.70302619,2.979280916,4.397637936,3.10259417,25.65217455,2.846981558 +407,20.603465,3.249296194,27.80022673,3.690178415,15.57846247,3.352580126,25.24488112,3.118562012,25.96542581,3.274884861,19.86576653,3.650857907 +408,52.85836521,3.764565666,40.21665629,2.208047576,40.39151697,3.427349329,32.23456593,2.157722157,17.30871969,3.145115283,38.17813132,3.661452936 +409,11.54834514,2.406328963,26.08914724,3.128287354,17.60835601,2.899617994,18.77808557,3.365221683,31.17195839,3.483821232,36.61300751,3.13391017 +410,15.25203239,3.413577289,20.93333305,3.153369983,38.3336785,3.12446392,40.39466157,3.578529524,17.70675616,2.677368902,5.508153684,3.636904998 +411,32.39699293,3.378281337,13.69421952,3.527003955,16.24462747,2.533478523,27.23075574,3.451033364,30.44869779,3.221752328,31.964472,3.541022421 +412,34.54248273,3.027387203,11.84480111,3.003313079,43.10432697,3.398085473,9.824732477,3.368362265,26.96116939,3.932645675,31.87164385,3.811085281 +413,38.01852576,3.029077915,21.57331732,3.577093693,16.96802322,3.190444641,35.36275597,3.012469188,15.33756214,3.312206751,20.88002318,3.704395805 +414,23.55876962,2.446501437,29.92074849,3.440687397,26.87617194,2.274865348,18.46314281,2.959692413,34.30857362,3.310078013,4.507561753,3.375893581 +415,24.37411378,3.243484434,30.83117473,3.405665486,12.681989,3.262699753,29.51022518,3.390003109,13.02873672,3.347277952,23.99403247,3.30472701 +416,13.818032,3.569223846,25.23543388,2.143731263,39.16056666,3.460922519,18.47569111,3.444328584,38.44901351,3.039170681,13.2418113,2.45479954 +417,16.55927835,3.345340262,23.62775346,2.892957212,12.31826255,2.045403455,32.92044827,3.148667407,35.11069727,2.984969417,27.09551561,3.189558235 +418,30.03660545,2.849625474,26.51996934,3.554343786,16.80737156,3.516817861,27.96724477,3.412855017,31.07729965,3.159629806,37.41091803,3.541174259 +419,7.554954456,3.580011923,14.36782339,3.198865684,28.20481776,2.311156002,27.28450352,3.332945301,19.12021338,3.790757474,-3.382838538,3.35389144 +420,12.28294782,3.76595863,28.17007384,3.704527524,24.20295345,3.542048461,10.44340827,3.381382288,19.1139266,3.582304967,15.10776033,3.414978933 +421,12.96804981,3.21771816,41.74364811,3.02363205,20.73410506,2.68200391,28.55777555,2.940158298,27.59584907,3.154024045,19.51622988,3.322909951 +422,7.154749273,3.082206492,27.2004372,1.903623087,13.11558743,3.817229469,10.85142541,2.875004764,32.03547931,3.51938953,19.59058491,3.389248284 +423,30.62828455,3.07581911,17.94565896,3.777852657,21.45175132,1.783396675,23.80442267,3.289730071,30.29168909,3.705385073,42.59237418,2.969257186 +424,24.40741233,2.828565349,27.95630641,2.749451486,19.47830729,3.286764382,6.884636989,3.382742465,36.06398412,3.725243039,22.81332016,2.805329682 +425,25.4905446,3.135776024,21.45052043,3.726837582,19.04519447,2.360261091,40.99218601,3.474101629,37.81429639,2.538846145,27.11500606,3.593895236 +426,10.88354021,2.7313372,28.41056305,2.638717421,18.14493008,3.377434813,11.29713088,3.873470063,28.59782933,3.281539186,35.35851065,2.562514709 +427,19.26151931,3.506869337,14.55530553,3.228415962,23.48048166,3.481508724,24.7149357,3.219169077,14.57486603,3.126871164,34.09415276,2.572621428 +428,29.76623136,3.845542758,14.48445794,3.409720948,29.54898439,3.540069591,40.18918243,3.41254205,14.35423169,3.799130689,37.36792911,3.102514444 +429,33.49774111,3.181010666,10.57641505,2.800627136,7.04185144,3.29883185,19.70299102,2.992827515,25.5294096,3.025368421,0.534108143,2.986630179 +430,22.84926016,2.467724537,26.09813721,3.521951673,34.93939405,3.201550982,9.982672588,2.510801052,22.80622561,2.953816659,41.96686635,3.23192119 +431,33.16169714,3.123215165,28.6964236,3.811432501,23.73407578,3.362649645,37.57794518,2.948021184,24.48704082,2.839951448,13.0969944,2.861313486 +432,18.25239888,3.909046407,28.32926334,2.59405625,45.82689354,2.959149754,17.03522758,3.4114825,26.76510325,3.196523343,35.66709883,1.907550423 +433,18.57077061,3.244649861,16.33317091,3.213588089,34.97209436,3.104119228,17.60880088,3.517754758,26.82830317,2.859661972,30.53844009,3.284307305 +434,28.95639427,3.284259967,20.35862836,2.841855896,25.36669992,2.600995795,14.69626551,3.221970598,27.82412036,3.273292553,33.24325568,3.147946494 +435,28.23195395,3.379850887,37.36755586,2.858765262,20.45023868,2.480077501,41.76328165,2.65554321,28.57457613,2.334312973,22.71129988,3.33189838 +436,16.6871276,1.828786835,22.80927226,3.74867569,8.602285617,2.62160352,27.41502566,2.387475584,37.36651666,3.306587348,38.22006752,3.544289741 +437,17.0477973,2.061729869,30.69885244,2.442781519,32.09528452,3.260532309,6.011539155,3.092795045,42.3217877,3.301466102,18.82667985,3.479506657 +438,14.24071461,3.595924079,10.84134728,3.236010889,23.43811222,3.539273362,12.61069144,2.921696697,18.18807284,3.396670854,6.78090339,3.524840218 +439,19.937524,3.953354824,19.37263826,2.885165496,24.3272591,2.969656698,36.20922135,3.876752316,38.36313951,2.098476251,14.5431273,3.098852633 +440,20.95050004,3.878543382,28.91146636,,29.95425976,2.948407855,27.12922865,3.482134854,16.06771411,3.631180311,20.14345362,3.283927811 +441,28.27309816,3.054650586,32.36071578,3.336491991,20.26967831,3.493973143,26.49805876,2.828248666,24.32273606,3.317524766,27.84923979,3.620621524 +442,32.28822298,3.255471275,39.00546215,3.248678473,44.76258483,3.656720262,31.95037552,3.133456831,46.13701267,3.554944918,10.46843778,2.065675371 +443,31.30411486,3.459450726,27.15759753,3.578074142,7.09001012,2.039895051,23.25865001,3.287256204,26.77287968,3.675344862,29.48180396,3.492470967 +444,8.533756501,3.056312179,34.88550589,3.579576898,28.95466194,3.445223187,41.6870877,3.282580594,29.10668414,2.680186115,20.95999962,2.407785624 +445,31.9660669,3.096793861,26.94552941,3.34905694,38.17841969,2.955530019,9.497422262,3.125335724,28.9445719,3.234366096,33.16766691,3.273754387 +446,13.85770351,2.28434917,17.20731769,3.247778656,12.50067878,3.630772763,29.41253722,2.948120881,18.14427647,2.760411834,47.71825173,3.477486694 +447,29.87980851,3.787935198,32.55258801,3.209275346,35.32012064,3.204457696,38.97646841,3.27025826,21.91098842,3.299056115,38.88184147,3.274428203 +448,42.29557994,3.662331442,19.66946213,3.091432208,36.80240851,3.024374414,22.41520022,3.487640271,21.15488492,2.883720054,34.28285004,3.373469859 +449,32.45870154,3.039709194,24.77941063,3.562232288,28.98535082,3.788790541,32.53406644,3.647656464,18.61887428,3.300323912,24.08632827,3.198497689 +450,29.30058866,3.545681429,19.23983712,3.555766545,29.29894423,3.579054004,28.95337493,3.182257685,19.84941146,3.553266283,8.201771666,2.72661531 +451,12.13252814,3.345137529,29.79851885,3.109956956,22.34997088,3.43516459,28.60942737,3.461729062,22.3454705,2.840511118,33.74792108,3.156699902 +452,31.39264995,2.832903461,18.56203972,3.455023922,28.46626389,3.871522696,22.18231578,3.393312725,27.2042023,3.391734545,9.678495684,3.582016558 +453,31.76902329,3.021271092,1.621859195,3.421804848,13.77953601,2.225329174,12.59470398,3.144510959,19.46386639,2.8984156,23.09189214,3.115908651 +454,28.12406138,3.497484899,34.39831727,3.748792613,14.44281669,3.570394885,27.07809879,3.537262786,19.13434486,2.939106144,20.32460403,3.623122448 +455,35.91540501,3.630303571,21.33797206,2.884072455,12.5931601,3.168084242,18.55048342,0.646962221,17.28158461,3.477944918,32.74087867,3.932171401 +456,43.08299869,3.396292387,31.75688145,3.836976904,26.98753015,1.522778933,26.21356369,2.440079387,11.02042558,1.065537137,27.29464021,2.558383712 +457,33.06477321,3.156199939,33.49429837,2.740007604,25.95804122,3.03959221,18.75257729,2.989765381,29.00820333,3.662927897,12.07566199,3.775429191 +458,26.08100047,3.426355553,4.912191348,3.436570572,9.476246132,3.798824281,23.40635364,3.161509011,24.56334574,2.815393721,38.92867448,3.135643171 +459,35.46139317,1.085209759,34.65134009,3.390658427,9.615329035,2.78020221,27.12713758,3.14062559,28.77615058,3.394785139,32.10314134,3.185907428 +460,14.56135595,2.973061504,28.87032208,3.671653291,21.1871591,3.748008706,20.7896541,3.536570925,32.30331696,3.09542595,8.404592649,3.224781517 +461,26.49907926,2.816516119,47.87229216,3.324619771,34.21455113,3.320983495,8.055192528,2.688451436,27.02511073,2.914737978,15.65076855,3.797645819 +462,28.35988519,3.436069285,39.05852051,3.091807575,7.818850369,2.290324988,19.86807266,1.226352218,24.68563151,3.037762723,21.44335315,3.269356823 +463,28.08963038,3.021463108,23.56639978,3.101568561,14.61774856,3.039803367,33.9017808,1.606728971,26.75355319,3.143468428,20.8999657,3.426950836 +464,36.37896225,3.368873232,5.219240282,3.075962654,62.67465833,3.652004823,28.54515609,3.422380364,16.79747132,3.219874036,18.44440143,3.700451799 +465,24.97691012,2.873313307,23.35207935,3.658720114,20.77110296,3.747328347,31.5363537,3.32405356,9.574845871,3.20044909,32.14567639,2.595859038 +466,14.04281639,2.947736952,14.69828546,3.100755094,38.79166452,2.375781155,29.96647011,3.005673501,14.99688806,3.176562857,33.68251771,3.569587048 +467,6.240550551,3.280492597,27.53777476,2.960490455,9.2197053,3.41718195,21.12613291,3.671012318,27.95726839,3.737145325,25.32153866,3.006895543 +468,40.10496149,1.351901193,26.96530208,3.263705353,14.32457302,3.53675421,17.23059951,3.633446672,18.2720823,3.810013451,26.51745142,2.932850186 +469,24.11123904,3.019833206,24.47519763,3.370129437,24.50152845,3.091638012,21.67683655,2.125310697,33.39276377,3.280801865,24.5262983,3.237553469 +470,23.90385554,3.142848937,18.96728815,2.620425093,2.811398389,2.261151688,23.1196808,2.835740748,24.59781842,3.482267412,18.35836049,3.345551705 +471,32.9303291,3.355565883,37.61257611,2.710351129,46.11555211,3.624910431,13.15222084,2.628928828,47.42955641,3.327814624,20.68959916,3.705332572 +472,15.66271959,3.435618396,15.48675118,1.463317181,51.92937427,3.115642597,26.73010604,2.036374134,2.516850341,3.514485518,13.37842595, +473,13.92028586,3.821473872,19.06957568,2.927141308,37.01725535,3.413614185,16.44106887,2.78983288,32.43438276,1.803295761,31.41640414,3.104779002 +474,28.67732711,3.055809555,21.25814945,3.283431244,27.03221964,3.762250969,33.38675633,3.094653339,27.52992028,2.946627088,20.13006069,3.300251014 +475,39.77366083,2.970152376,18.77127755,3.206260573,32.12383965,3.394792084,24.85468279,3.37484828,16.01513699,3.14978626,38.11907115,3.063056076 +476,29.74751542,3.527662451,38.24835021,2.842492481,26.84216474,3.242096903,17.47441324,2.569258345,31.32402727,2.827962569,9.100959942,3.521119884 +477,23.24586872,3.78193676,17.83885016,3.564251613,21.25583437,3.350271937,28.63315272,2.73207795,21.01510713,3.671722349,8.591084008,2.907682105 +478,22.19530817,3.208540999,40.40549637,3.171592261,12.92857608,3.232934834,28.80579655,3.715754591,18.40338414,3.574593455,25.07757713,3.022209688 +479,41.87161606,3.060043342,21.13219306,3.19375855,31.36233438,3.83405429,11.48547974,3.354187463,25.29148418,3.320656949,27.08105533,3.317094651 +480,16.56210766,3.541238324,27.39698539,3.240474639,10.72753722,3.44649707,27.02578143,2.59522954,26.01409531,3.354971363,52.80942069,2.751916183 +481,41.46654991,2.08505444,53.57294794,3.481074005,23.02324078,2.785929034,20.4082724,3.095284347,18.51250143,3.507487363,18.48832638,3.070933721 +482,25.87385803,2.948007549,25.76123618,3.202354644,21.31533681,3.193324406,18.25458982,2.772195526,8.367859401,2.639507739,29.51018368,3.284219125 +483,25.0355976,3.299081931,17.55901993,1.871347776,34.62740496,2.445208838,7.599394961,2.880127184,16.10436801,3.400120134,28.04695631,3.035985735 +484,21.60806406,2.604924115,35.1303899,3.306529503,8.310237436,3.486037103,13.46307151,2.963913227,31.0611284,1.72646988,3.394114868,3.226798366 +485,38.29950999,3.067834777,18.17337575,2.884840768,17.57281176,3.534922444,37.54822564,2.985376012,33.94068281,2.730957479,33.7725797,3.386793295 +486,42.48573357,3.675741992,29.96909606,3.613344896,17.89680726,2.634439192,27.04955303,2.904353067,1.513574906,3.695283872,24.85478807,3.398071113 +487,14.32053113,3.634384054,40.07026679,3.232618641,31.61178742,2.911831571,36.33481836,3.653454853,24.84866535,3.587263637,30.48183392,3.734849141 +488,32.02327529,3.501602767,33.11246485,3.322797626,7.765809863,3.276161103,14.24390791,3.518532327,25.33463199,3.316674856,37.86174156,2.728178237 +489,40.91133334,3.530286241,29.22743942,2.939304245,21.59182615,2.490444547,7.517589463,,31.68090139,3.317471188,25.37193424,3.613116706 +490,14.11108449,2.392471656,31.16448646,3.62852685,28.4759152,2.647553589,7.883628652,3.605729562,23.56509874,3.250250744,17.86841313,2.377375425 +491,19.29959743,3.663824527,35.16475666,2.897787703,5.719605518,3.424084421,22.30933488,3.59870865,26.24265565,3.01124815,13.49156011,2.912654414 +492,13.63291936,3.221036444,14.6300802,3.282167616,46.19332579,2.624720796,13.54631036,3.195694691,15.71744731,1.280661825,27.05441076,3.231226173 +493,24.00301947,3.418358722,39.97869983,3.320717703,25.36594604,3.490349198,28.23135494,3.484216318,28.50387829,3.44005041,21.15798979,3.026232472 +494,20.32374864,2.992992777,21.52481253,3.12704772,10.41562683,3.619714134,22.76266695,3.643281068,19.50005868,1.683236738,42.49056684,3.790989654 +495,21.41979592,3.498555407,34.19530598,2.129441415,25.66272474,2.49042286,27.04273996,3.44737187,19.69261194,3.685045035,11.23166314,3.435894022 +496,14.49168211,2.892244501,20.95651723,3.421228497,27.154678,3.154995986,15.14077528,3.051183697,26.54311719,3.543268656,14.94024254,3.332616615 +497,36.97748014,3.5155828,49.93394565,3.497073236,37.26331957,2.764821777,32.38517881,2.864513604,14.37138908,2.62781942,5.871879361,3.079506727 +498,14.60633234,2.690794404,29.63618127,3.066496786,23.23640888,3.342308875,14.56359678,2.539921769,26.19301381,3.216305981,25.982689,3.126756138 +499,11.88261821,3.151652151,20.79456037,3.341852636,20.23213522,2.978022695,31.80229668,2.785794707,15.6599317,1.177755212,20.86958124,2.943728913 +500,26.19405401,3.567961613,14.25892043,2.538898597,36.99080645,3.833457818,17.43579838,2.861260352,11.25766319,2.976958385,33.43534606,3.133684803 +501,29.90377506,2.578154339,4.482677111,2.170757244,28.4112966,3.248064324,29.30819746,3.091209372,40.66805532,3.5508739,33.85151804,3.711387191 +502,27.0948767,3.343464803,25.8822552,3.618902713,28.69253907,3.62312151,26.31231189,3.32016274,26.00004624,2.910402657,26.17445911,3.775876834 +503,44.78593335,2.696598567,20.18040877,3.130920496,12.64788818,3.26853825,23.57494658,3.52434179,35.23295631,3.229092815,35.51605575,3.34327712 +504,14.83553947,1.542822845,24.70173697,2.792608997,32.02959506,3.197003297,20.49602687,2.667455788,15.90619137,3.848189087,19.07977509,2.552187671 +505,31.96531798,3.140510258,25.56558847,2.825279356,15.67890983,3.104320777,27.18369525,3.369333508,26.02057539,2.598327662,28.01200737,3.32157862 +506,35.86466311,1.799293891,18.48037494,3.115377682,17.4085372,2.013894607,19.6521144,2.942312843,13.52932151,3.040528211,21.56852373,2.419889787 +507,21.8588379,3.210076285,33.67798012,3.43827268,17.06712856,3.165567848,12.38543335,3.061090032,18.10945557,2.862820361,14.22163252,3.081671118 +508,12.29812792,3.371701024,43.70111406,2.960539465,30.26556058,2.876772419,34.88821681,3.279387797,27.01252395,3.201149389,32.38551045,3.28283257 +509,19.08151612,3.009971439,26.08555961,3.600140126,22.9852793,2.177771456,30.14807211,3.565218011,35.52071466,2.998368624,4.804965274,2.777838015 +510,9.876570653,3.212930401,30.49595154,3.392490165,19.1250296,2.863307386,30.52090923,3.139193011,22.302165,3.386161481,23.29472647,2.383047036 +511,7.218711163,2.82047858,14.99632925,3.5275525,19.79030709,2.76541145,25.08982923,3.594452278,22.38135823,3.845975687,15.51624305,2.929072939 +512,29.41001493,3.075133381,15.95632042,3.176376927,20.20679435,3.848740473,16.39183554,2.787240619,39.06340648,3.042222523,19.11940993,3.92335259 +513,38.22504221,3.470266417,11.34263561,3.08483464,14.29668,2.688500594,26.62376548,3.3861495,27.06641055,2.819453123,14.27079233,3.142610668 +514,24.0976677,3.47888404,24.68181089,3.054984166,16.06383319,3.118716261,24.32445685,3.631689152,25.4420651,2.734271231,28.09239009,1.542104876 +515,12.11830954,3.423499706,18.04096491,3.125330151,36.44664495,3.701920152,18.04011187,3.125126931,25.62708434,3.62930703,53.9351913,3.467120819 +516,29.86711677,2.731752219,26.69464527,2.249422191,22.91611631,3.139960025,31.14846208,3.236133271,24.65742617,3.348000702,13.22150361,3.009622449 +517,47.72003911,3.384649048,20.71486342,3.176192882,47.12315568,3.055309309,21.1426369,3.085314888,19.18410177,3.325144327,55.26184652,2.705423478 +518,17.02377995,2.815333154,19.21251753,3.314227923,34.86621037,3.260109713,22.53807215,3.019781669,15.90093782,2.047169582,35.68225191,3.410698739 +519,19.57307341,2.855209046,15.91496713,2.823694328,6.178064588,3.310891568,63.03693297,3.566073969,23.50759227,3.510897502,21.37963728,3.252420815 +520,44.11147529,2.496252474,33.36074438,3.579767361,38.58944805,3.743751981,23.26878392,2.075417377,33.13495737,3.412492676,42.36683435,3.09431859 +521,20.55941027,2.92548193,18.43037361,3.322346817,26.47270812,3.102623668,37.09131308,2.656222845,38.90770329,3.484570475,26.24427255,2.817089074 +522,17.5199055,3.404919853,21.88291631,3.384570784,13.75271812,3.689727295,21.82747518,1.92132338,30.70178582,3.458425617,20.15430385,3.075592004 +523,18.41539858,3.554847313,49.90226905,3.50468559,40.21185661,3.097093001,25.39803875,2.358387962,14.70044414,3.436715026,12.35835179,3.808148436 +524,36.36981537,3.251364828,38.85955181,3.876572052,21.28075097,3.164932847,22.8740113,3.207946547,30.70810185,3.259299049,24.63539168,3.168183063 +525,20.56099602,3.927441582,32.85889413,3.139671867,35.97116626,3.222335806,11.98328952,3.150632827,13.15805924,3.317424423,12.92578526,3.310359134 +526,37.73187378,3.012665622,22.44170855,2.808419872,24.77655788,2.274321227,25.60783075,2.37314341,17.73916872,2.086963896,28.64702868,3.318016636 +527,19.09631534,2.891356346,7.113530155,2.776426442,26.43079571,3.331379728,8.313554676,3.571196135,24.64779243,3.20601982,22.03203697,2.637967567 +528,23.91089862,3.272959876,24.44641594,3.198707697,18.4595573,3.610045168,9.151541132,3.644386494,31.57186074,3.505452808,24.04832154,3.277552879 +529,14.15421793,3.202238394,15.57361542,0.042018378,22.22875454,3.378864685,33.57588654,2.892269502,13.62678898,3.300227671,12.43587412,3.077150671 +530,27.08341141,3.291862304,11.06453559,3.267975509,26.13081838,3.565088653,20.58970107,3.53155331,17.09871837,2.975707906,57.54149977,1.930263187 +531,41.93490958,3.563077314,25.95523278,3.308317202,19.15386569,2.699338223,18.16189027,3.797976643,32.84881801,2.704794598,30.62878054,3.4635976 +532,12.97026181,3.036684343,9.824135282,2.617698798,36.0114921,3.247307046,14.57966766,4.047819685,28.19378316,3.222604821,46.79732908,3.629563308 +533,24.61116709,2.924375632,6.942916888,2.704136644,39.65173017,2.961399482,32.79758847,2.823131163,36.08203834,2.592314755,29.14959123,3.576453199 +534,38.88088224,2.856793629,19.5436505,3.146460618,14.09536189,1.88287747,22.70468882,3.513329633,30.22701586,3.691434916,15.8356562,2.900061759 +535,27.13654215,3.250757855,19.17029203,2.898171192,11.09199003,2.951576708,19.1096873,2.57817155,28.93030531,3.366143482,23.95025475,3.4606646 +536,32.22189221,3.190871607,27.43403961,3.786991832,25.04625205,3.672858816,33.22550299,2.832336283,31.55635187,3.727598647,41.8444125,3.746589017 +537,31.95818351,3.232128042,23.37253659,3.41015317,28.44257865,3.370819119,25.23436047,1.731995811,30.81995355,3.239830966,13.68327639,3.399102733 +538,37.35044277,3.042161812,16.90772848,3.669358723,9.016415578,3.385621977,40.01990379,3.224193529,22.87578842,3.808215404,25.89878781,3.424853564 +539,18.31009893,2.857596902,13.27279458,3.421184003,44.48321275,2.161577793,36.67400966,3.445898117,25.16860563,3.040305272,13.80133501,2.402414287 +540,37.73402576,3.689219202,3.578591716,2.704081083,42.66525224,3.403164488,23.53332989,2.848787961,32.42755997,3.447971397,40.60940916,3.13942259 +541,40.45452708,2.889584161,33.310752,2.905833643,33.74744626,3.51901474,19.95562963,3.451503525,22.25099499,2.453468339,37.00953305,3.008609391 +542,34.97621041,3.133440647,18.52473987,2.90652317,7.116508546,3.892139128,23.22959091,3.691541768,35.06437946,3.301955666,18.77587853,2.82859574 +543,41.76091179,2.678518982,33.16173077,3.612483436,19.63814691,3.277146296,24.71030541,3.205286969,39.80228745,3.559885889,16.62140509,3.482394945 +544,27.27913294,3.585040954,19.04473441,3.169159079,28.74504893,3.224950679,28.78169907,2.81894693,28.51371418,2.048071739,30.2978492,3.274271249 +545,35.3565368,3.208818318,18.29146926,3.382144827,35.74522735,3.329245926,15.9824159,0.225551461,23.45485271,3.445988532,30.67648506,3.258539392 +546,31.57646711,3.321660715,5.904400151,3.539304263,38.31367785,2.202788432,17.36888702,3.423578799,29.69634985,3.172475721,46.22763037,3.769713405 +547,34.40159103,3.310057129,26.95451189,2.914171752,15.72356492,2.880257385,34.61324878,3.015763672,23.91307288,3.116447605,29.8154902,2.892743563 +548,14.61044073,2.897636848,13.15882706,3.151835272,24.92212532,2.825730158,17.40919556,3.1306623,28.98543404,3.830616787,29.1949542,3.643757409 +549,32.90017674,3.15833312,6.482371407,3.348652526,28.49557582,3.058291571,31.2458735,2.198077866,20.59626873,2.816336885,23.62185386,3.765141416 +550,24.72983773,3.129677776,19.45576396,3.680225848,39.49987689,2.77629817,6.240362965,3.414336313,13.22936003,3.300875596,40.66736728,3.288096372 +551,24.39940621,2.522019506,41.64076718,3.435440493,52.94154094,3.272555196,29.50251507,2.969168768,13.23990496,3.726461523,32.76052391,3.954633203 +552,28.09817223,3.332012483,28.31211479,3.17075579,30.30980128,3.025124379,28.25162578,3.490025362,18.83068878,2.797411416,28.93568646,2.780753685 +553,26.32306565,3.080516873,10.76908953,3.071233051,27.69638178,2.905789856,25.86711749,3.578583871,22.44832199,3.412340825,19.76297351,2.419224151 +554,36.29852247,3.10542367,32.23215351,2.956210795,28.66250109,3.406023732,28.64521687,2.274881136,17.82645911,3.671486723,17.40001876, +555,30.68757428,3.111086267,21.15461532,3.105378708,28.84882215,3.154458208,7.668246379,3.558577588,46.09449,2.71966345,16.26892586,3.759027878 +556,12.84287886,2.690835936,28.39393352,3.656965535,14.44103011,3.45324663,36.44811145,3.197897866,15.8403325,3.382002051,50.08964928,3.554433042 +557,10.98951316,3.830990485,29.99423907,2.949466988,32.75625197,3.481132208,19.91571467,3.215303075,20.18656287,2.918898178,30.21629085,3.4584798 +558,16.46160395,3.320366615,11.22983693,3.122732995,22.16653122,3.040496888,43.82018282,2.887488341,24.01296648,3.479998792,37.90638468,3.103405997 +559,34.15761981,3.208515918,-2.266506548,3.128875994,29.51113557,3.153678892,26.07652696,3.199817369,30.29979074,2.450740734,12.68389318,3.72637838 +560,37.54569785,3.162824609,21.93733137,0.773059867,20.45736335,3.137284201,17.96261262,,30.72229101,2.881320031,1.838313562,2.753359863 +561,27.75948587,3.360300137,39.11825966,3.109627259,28.5277989,2.731368999,18.80272662,3.059750187,42.45068181,3.22935804,21.09640027,2.925710988 +562,29.24160211,2.003576034,45.15315005,3.2735845,18.60453811,3.028640123,36.93483401,3.126703505,26.93618303,3.089994693,26.66847738,2.361899252 +563,21.29203221,3.254550533,22.4620405,3.578462306,8.980715258,3.16296174,24.82082822,2.853688868,37.58773152,3.548787413,33.89376276,3.189366447 +564,20.03942409,3.026564366,41.20433236,3.331456755,38.11938873,3.150769782,23.3479176,3.182031229,12.36264726,3.347915012,45.07274865,2.8073888 +565,26.30222778,3.276402701,33.7248939,3.102956297,8.872750395,3.38854641,29.4807075,3.549542561,41.40598738,2.391590031,14.07426337,3.498738974 +566,21.58111137,2.674938887,18.14474033,1.453679969,19.29225098,3.293614882,20.04901742,3.32210465,37.8555973,3.277064099,17.29356662,2.763028966 +567,18.61238236,3.509965247,27.33657453,3.087239563,12.38700815,3.678602119,46.67196006,3.612601954,23.72311192,3.301362202,23.96966733,3.220430951 +568,32.29436972,3.321917905,24.99014887,2.874463819,46.13754405,3.019343706,29.34857215,2.932926091,30.51202908,3.716118061,37.82703292,3.361166362 +569,2.541818364,3.688084883,43.45427291,3.104396919,21.55642473,3.61219023,12.28409033,3.159212753,39.4330443,3.253533271,23.97222039,3.769212624 +570,20.33986732,3.291559577,47.19023825,3.569308517,31.78723336,3.391684696,25.67186665,3.782711865,23.25246448,3.256636433,39.30044117,3.096039296 +571,13.29653941,3.623203192,33.85200792,3.759058459,38.02650058,2.950511122,40.72037697,2.749704684,39.85498618,3.246631465,20.24396004,3.402540792 +572,4.084691994,2.61999943,28.40999552,3.601864507,12.23984346,3.782520706,40.82282911,3.377819663,29.7396209,3.550026534,31.67719913,1.909736932 +573,17.91956923,3.200025555,11.41349841,3.896183168,23.17635452,3.672817317,13.99207789,3.251624688,20.91158703,1.638833692,36.99454816,3.109618616 +574,16.64803465,2.011181705,38.34789046,3.546388629,22.56781873,3.023940717,30.35776885,2.459730033,6.127871111,3.066249809,21.36694799,3.26614244 +575,19.97557832,3.381618174,14.55033062,3.476111222,16.71761752,3.375355548,20.85442962,3.254093372,29.48792223,2.539221713,31.00169264,3.292117206 +576,31.745873,3.799426938,31.57903964,2.462253526,26.7015203,3.029481195,33.2334204,3.283574105,17.27455421,2.972739257,32.36598032,3.28057084 +577,37.11539805,3.319257864,16.89039812,3.751182689,19.72037126,2.98182031,23.27162066,3.114010852,14.67411673,3.446386608,22.76390336,2.520869826 +578,11.10911025,3.014045779,25.55682656,3.22522409,16.22373653,,33.47616727,3.482165159,33.52443119,3.18713342,12.85125063,3.264561571 +579,31.44400246,1.945794711,24.24139785,3.494967201,20.41519601,2.476483283,24.61868896,3.043998871,18.4283557,3.586680396,24.94222906,3.414516877 +580,24.55030963,2.408674749,30.52906885,3.586618862,33.93823276,3.1944252,32.07180916,3.177512402,38.70126722,3.358235341,32.75010186,2.625996328 +581,20.07250856,2.961881349,31.24256867,3.051356045,33.76523239,3.554179025,16.64391479,3.320101921,38.17894159,2.519645486,26.32476782,3.299999162 +582,3.076677963,3.398384402,21.29953739,2.954445942,37.89510763,3.129725695,23.24786692,3.214749377,37.75013104,2.911660353,13.625504,3.290345918 +583,27.36071096,3.436730148,34.5266439,3.500508687,37.43215098,3.860767498,32.97891932,3.143895222,25.78902881,4.009861434,19.57950462,2.244042942 +584,45.23091954,3.183592601,1.874577429,3.502535245,31.75903975,3.63036582,34.38056688,3.733550003,35.11229092,3.238901401,24.76517026,3.044637115 +585,13.86789262,3.320779828,33.03323471,2.658019926,28.69241093,1.857012957,22.04462833,3.220259983,24.92805711,2.801034481,12.04209129,3.328305432 +586,7.408167915,3.773538178,24.54266401,3.182035626,17.84382613,3.350508396,30.69937448,3.44659141,29.41144672,3.544853114,20.81142426,2.517017657 +587,21.55551176,2.73045827,30.23698908,3.159371874,25.57636206,3.481440454,7.249325236,3.539864173,19.17436737,3.13616679,16.13309886,2.645180832 +588,26.84439791,3.657973413,30.598724,2.786649369,23.50649287,2.427501314,34.65342388,3.466747493,13.0183176,3.499658447,22.87635128,2.629806922 +589,13.78434214,2.444750682,29.70088448,2.578828151,22.07861832,2.244988082,35.87741515,3.618414328,18.60278412,3.365173658,13.06001784,2.995097125 +590,34.64426542,3.679313041,-4.186185039,3.78675752,9.729301415,3.644506498,26.38298411,3.286801794,46.25403626,3.567649179,34.74606194,2.440510634 +591,45.96866243,3.324783197,20.09085658,2.969382144,30.37301604,3.448852504,53.61535029,2.453178113,41.59725849,3.212625591,38.83532483,3.616808894 +592,13.94999174,2.993182625,16.01986162,2.742002278,34.63361849,3.552755804,17.50074553,2.27886709,28.99720636,2.871304114,15.78419631,3.584094079 +593,30.60040795,3.677904641,36.52116467,2.998288618,16.95420825,3.401843934,10.90354207,3.048133916,28.7645682,3.157939168,20.95650675,3.435842908 +594,26.26699944,2.781301169,14.8047067,3.182696275,12.28926229,3.671760853,15.35147503,2.669184387,33.68476358,2.789708946,29.32491639,3.145343 +595,41.00315343,3.365322579,25.48784554,2.69945541,16.51711858,3.17179131,54.02581911,3.254992006,33.02488647,2.103567191,13.95834731,2.053178146 +596,36.03806892,3.149336166,11.48643544,3.346378188,15.96518259,0.616488953,38.5351855,3.299888129,26.47818456,2.744351256,34.19932306,2.67280854 +597,13.14713484,3.599593762,22.48466921,3.671706615,39.76221011,3.021051163,17.01381284,3.25577541,19.68240273,3.239829119,25.60372295,2.550969555 +598,47.19085728,2.596564963,33.37881255,3.19997515,20.87411708,3.660377452,39.57520188,2.650020833,29.78450331,2.589776093,35.55294582,3.029833683 +599,48.0010945,3.053639458,21.66622568,3.292330948,22.97555183,2.971759132,21.49173003,2.440191581,32.49338899,,30.57110899,3.304995759 +600,18.90366649,3.043934817,13.05115506,3.667032554,19.67291787,3.513750538,32.63499982,1.124328952,34.43456961,2.574438526,20.37977939,3.905157811 +601,22.20702921,3.351655793,14.69709076,3.510765991,17.3153932,2.838261323,40.31957053,3.039997323,28.67021869,3.429062813,21.48631335,3.10591669 +602,31.47254284,3.005413335,18.90264548,2.499824829,16.30107163,3.256523431,27.80074068,3.392740883,36.19430884,2.422607495,11.607274,3.437204754 +603,31.55142819,0.164856524,-11.77716525,3.317460971,15.87242234,3.94446718,11.67224776,3.188942413,16.66086538,3.750868311,41.58730912,3.290119009 +604,27.19297864,3.489709321,28.49955361,3.260325965,27.41288846,3.612469274,38.70696442,2.921644998,30.97796058,2.906236824,12.78298011,2.721488804 +605,44.14084724,2.842416559,23.92836348,3.082777462,32.8584129,3.339461838,20.06029663,3.24823734,29.54891201,3.408578127,21.29230903,3.589435169 +606,20.71049486,2.881351149,23.26805372,3.371483684,23.3820533,3.567264806,37.1240862,3.02923798,15.42566311,3.685234291,24.84109344,3.137285778 +607,24.80783735,2.957656336,21.75807451,3.689808351,34.15061329,3.588124731,-6.164146535,2.82095294,27.35907799,3.138747365,22.88990405,2.634615976 +608,19.39858697,3.58786797,14.01656711,2.120462645,32.93255487,3.51068042,29.00830758,2.412422505,32.71821246,3.428644048,30.17269216,3.749263926 +609,33.40374973,3.126845449,21.55583722,3.338930877,41.16505268,3.63206813,10.15763079,2.967305355,12.05467451,2.103174689,28.75439432,2.833045301 +610,8.494695971,2.046496117,33.00355941,3.055409861,28.72027546,3.404486475,16.37115431,3.175282983,29.13270879,3.816751122,16.61680335,2.25279676 +611,33.24783663,2.744576082,12.26263455,3.193905538,59.97315324,2.981455249,22.87459074,3.102790456,23.40175103,2.146657682,29.16511283,3.291096072 +612,19.00434558,3.161396822,34.76454895,3.367135471,30.45499914,3.167593597,28.72135283,3.460543341,12.4455523,3.520584821,20.81145614,3.451735804 +613,22.71509725,2.967940079,24.70833566,3.72623034,20.10061249,3.264248408,16.96060754,3.373638014,12.91579789,2.628930027,7.343938175,0.27083831 +614,25.84422091,3.5596581,10.38354628,2.937588479,10.54612597,2.739059697,21.46766634,3.107666362,18.39533588,3.458367291,22.68905065,3.526117911 +615,21.27011182,3.307239799,39.10227912,2.833905976,27.2334117,3.419848624,30.77481426,3.200952254,18.94788465,3.032122426,9.301339931,3.205396374 +616,27.38523718,2.521763694,29.21681384,2.616533903,41.3331806,3.158193232,12.37971762,3.724535939,41.72294362,2.125020217,2.55938581,3.170087696 +617,6.054300885,3.790320837,5.615607463,3.456418952,19.24080804,3.139110916,47.99141133,3.1810589,39.00848928,3.13078911,35.47553716,3.118643421 +618,30.11393116,3.393158934,29.0190691,3.293707687,23.47907841,2.766266913,21.83750752,2.766330597,25.15956715,2.090200814,40.04893018,3.069090015 +619,29.55991081,3.23817965,24.95051098,3.215566955,25.13607442,3.004162896,29.95360914,3.767274083,25.38557115,2.800024234,50.95915735,1.240551625 +620,24.75754217,0.823281996,19.49405703,1.825228149,11.43444947,2.615277647,19.13744037,2.837617252,34.53412115,3.685770077,10.90204954,2.75890733 +621,18.40332776,2.805835336,20.26723553,2.59731902,19.55348947,2.917861137,18.14834903,3.007298554,31.01708448,2.484858661,29.67872147,2.994514828 +622,38.87120924,3.398359283,18.9535837,3.536295396,20.71746492,3.374860415,28.37020674,3.392023103,30.43197258,3.563956864,19.15138633,3.326246347 +623,15.99436784,3.360623232,32.46652075,3.39397553,24.38662541,3.110670168,42.26169891,2.946526145,13.80986408,3.339191983,15.40099644,3.508387597 +624,28.04867251,3.390324544,25.86772619,2.813840397,35.81370846,3.660168544,11.87826858,2.794505303,29.51610385,3.188843632,25.73264927,3.014024252 +625,24.70621826,2.431877438,35.84101623,3.345541541,31.73142281,3.676944107,55.46320087,3.399294053,29.49243972,2.909698766,24.70706833,2.790664665 +626,25.53904573,3.580105366,31.97458385,2.617590352,4.782935521,2.827708264,20.22538157,3.615987124,31.87675486,3.755285805,23.99523927,3.539062061 +627,9.794206367,3.378109232,22.68736382,3.620926951,40.92309274,3.269081371,15.83001915,3.131115699,27.15127157,,15.06986063,2.682756915 +628,36.43699223,2.569998863,8.035244375,1.87409156,23.7977607,3.558979534,38.0201771,2.55351282,18.89879564,2.586158876,37.76881405,3.612166711 +629,35.53257462,3.185965627,12.32770932,3.194867573,44.6344174,3.836558473,30.1264104,3.068977277,34.82745496,2.904566651,24.03232605,3.555904976 +630,45.86098551,3.537259073,14.49966125,3.60761717,12.4168893,2.744681601,31.27834453,3.775938661,32.22325341,3.74739984,-1.655230445,3.422653976 +631,24.93043907,3.358074538,36.96503846,2.892185293,27.35319004,2.450396199,26.75099018,3.202211355,22.22285584,3.041003963,38.37179285,3.218550009 +632,28.18796809,3.410138881,16.62144181,3.512450588,25.93694224,3.389645837,37.01182886,3.209367476,13.56372118,3.237671065,22.34480172,3.543609558 +633,28.50906805,3.454260877,17.56092583,2.687738993,31.86376397,3.361142544,6.911017107,2.995439302,19.3475635,3.680860624,22.60557688,3.554207525 +634,8.565587039,2.859398529,41.63731952,3.128538393,29.20536466,2.672904663,15.58071455,2.601144662,14.09142292,2.986168613,32.28227953,3.209638497 +635,22.8144289,3.323891712,23.67635332,3.66078453,20.52686232,3.20768163,37.37686834,1.9228897,21.10603374,3.232129373,27.03696167,3.423598475 +636,42.02105397,3.847560841,35.16238696,3.324280462,24.82941741,3.010081946,34.20140801,3.46956938,36.83814929,3.296344881,32.1555639, +637,21.65252695,3.510209153,24.01785389,2.915232274,29.63351293,3.218799271,32.59007409,3.503033635,50.52843629,3.225233139,17.98438535,3.279595655 +638,33.61057494,3.360273299,35.39183615,2.697277538,45.14297206,2.818646897,14.71162704,3.167616449,28.98564895,3.097669806,18.39724277,1.895690267 +639,8.986729157,3.633603491,20.20444489,2.3639856,22.78075422,2.387972363,20.39407602,3.014666587,20.99550793,3.522169637,13.22151018,2.820777605 +640,26.04388498,3.047819572,26.94778353,3.318978607,26.87316713,2.904179864,17.99489188,3.05780454,9.994356295,3.555040924,21.0636342,3.631553024 +641,13.66489268,2.241534893,11.87675968,3.081872969,10.61055641,3.22111009,17.04390526,3.009555656,9.929109301,2.421775034,38.04597011,3.735849491 +642,0.227477655,3.665380451,11.85479823,2.881393609,25.48210941,2.320781302,19.09237051,3.414120959,15.53216749,3.00701668,21.48518387,3.014355546 +643,28.84329541,3.262321759,15.48247005,3.381469635,48.25186504,3.563421385,20.69151353,3.481916788,22.5140777,3.364717514,48.54853688,3.872733971 +644,22.9101483,3.506731772,26.53590928,3.14187258,21.69303904,2.942887433,38.02649761,3.570866155,18.93768871,3.317950621,30.67397161,3.124105456 +645,19.03924333,2.7768907,32.80418442,2.906555344,20.91214053,2.473092387,12.44662605,3.00882532,14.76572913,3.35773326,18.3837132,2.91568892 +646,44.86229531,3.766400162,26.208271,,24.15669926,3.037709133,36.76886678,3.55157144,27.74084481,3.53617545,16.90585889,3.266487366 +647,35.58583126,3.134700073,45.58488046,3.402653878,19.06132555,3.653057855,21.05336696,1.645478244,22.08999446,1.869484636,29.57672586,2.650152993 +648,29.94578296,3.446863021,12.90734681,3.288247379,31.54228566,2.989306085,27.37228363,2.896655462,35.02338259,2.934621237,31.09946889,3.49278768 +649,31.38659328,3.203424551,16.87265736,2.578808923,35.78911068,3.093270761,37.80114073,2.56989144,23.47371678,3.83269139,15.24880583,2.497219828 diff --git a/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/isa.assay.xlsx b/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/isa.assay.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..3c215d71a19ee8b33487ca56cda313e378c36f5d GIT binary patch literal 23306 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 PpA>@zus%8y4B`O*%7**% literal 0 HcmV?d00001 diff --git a/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/isa.dataset.xlsx b/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/isa.dataset.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..f1d2278cd612048d0cde8f7dcace2703c017be99 GIT binary patch literal 11653 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 X2??4y{@6u^1i%LEfl&TYbO8Pb@5Umf literal 0 HcmV?d00001 diff --git a/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/protocols/.gitkeep b/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/protocols/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/protocols/extractionProtocol.txt b/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/protocols/extractionProtocol.txt new file mode 100644 index 00000000..41de6e75 --- /dev/null +++ b/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/protocols/extractionProtocol.txt @@ -0,0 +1,3 @@ +- centrifuge again +- discard the supernate +- solve the pellet in buffer chemical X \ No newline at end of file diff --git a/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/isa.investigation.xlsx b/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/isa.investigation.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..f6c25d350161b4e64d8fa6d54741950cc67ff4ed GIT binary patch literal 12526 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 literal 0 HcmV?d00001 diff --git a/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/runs/.gitkeep b/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/runs/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/studies/.gitkeep b/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/studies/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/studies/experiment1_material/README.md b/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/studies/experiment1_material/README.md new file mode 100644 index 00000000..e69de29b diff --git a/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/studies/experiment1_material/isa.study.xlsx b/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/studies/experiment1_material/isa.study.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..321ce557a271d9a3a64d348125a0ac5cdca1e483 GIT binary patch literal 21370 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 literal 0 HcmV?d00001 diff --git a/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/studies/experiment1_material/protocols/.gitkeep b/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/studies/experiment1_material/protocols/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/studies/experiment1_material/resources/.gitkeep b/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/studies/experiment1_material/resources/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/studies/experiment1_material/resources/Sample1_e36ca6b8-19ba-4504-aa82-d4781765873d.png b/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/studies/experiment1_material/resources/Sample1_e36ca6b8-19ba-4504-aa82-d4781765873d.png new file mode 100644 index 0000000000000000000000000000000000000000..369be75620578ca911f5c370f0e4baa2fa042ba7 GIT binary patch literal 1087 zcmeAS@N?(olHy`uVBq!ia0y~yU^W3^MxX$LD`(U#1_l;3PZ!6KiaBrZCg$BX;9-4m zN8$Var+FKAU3t7jmafs*)OvThyrb;xMUE5R+Zs=)`u#KfSiiLOA2q%w{5B1XD;Vcr zVlNS$>k(fa|6$(Ky%&FP`_;Is+iKFU*;S9U+pTo=cQXHE=6|3OcVPJ!#@MfVRv)Jw zuif#+YR|u_nm=;=)$je)658({Y5dd3ULd0X<;mqAc6oE(^*{f)Va5?RQ$~bE3+?B( zHF;R6)T$((cGeZ%a5(>w!@mQ}7G2`|xaaE~?egwvQR?)*@zA_bq5c7*%u(+Dob%l} zl}b*$T!4B^HqM?ZT}-e9mzdgo?Xte zF>!yD$HBQtR5ugJ(p{fkn%q^=-6qTbTK2RS7m`8#cCyQ7-;z8QueHj1U8i{Rn-8-s zCfI*q=zG-quf{5NqfFf6J(8Cz-fyn+M(8@U`}4~cT5{^<(%L@SYL||Lx~m|0-Ew}O zv{dj$rK>8-*3LWbjL_y(Z`a$ontg>|jPjGy6({)Mp`CGN`OCJ?N3Oo(T5M){MH49m z=Ke6*s<*`N_}58q4|S+pwaC^9vwvcjI}o_%Lc71Z&h%*1d@c%-A0# zF9SUGa$Q$_yhA>BGa~SRea@VvsX0kN`Kp~yCTD6DYDn}(ufEor%9$D^At)U3U#tts zvKjuDBeq4%XgR*_`9>jgq(GWi6LojP&B=zg4ncay?;9dH{p=4DE@98wE3y+W>-CjZ zHY1rf*MGI=vBNLlJgl7ecJl$Ga5%JlGRsP7smHs#Cmu<(I*5>Yaen#L71!)l&IYcZ zZ1F+>DNN<{+m60TNN(uz-!9zW z9(w$+iQRU;CM1a|{;O}6S8LU{wj(8=dvpEe)z`g0Hq&g@;=K7Oh&*8O?DDNQ$4f4& zKK{I9^XqNgNI|o&W|rHZw8C45cIMUiAbWqZf4n79K>e6vw_x=PmtVJjH+|Q6-+OQS zRsJinS0-M$e?>Un`by$YSfXdLTgv}pRsAaAdd7mV&)28QUfc>Q89ZJ6T-G@yGywn( C$^R(; literal 0 HcmV?d00001 diff --git a/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/studies/experiment1_material/resources/Sample2_714ca2b7-22b7-4f69-b83d-9165f624da25.png b/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/studies/experiment1_material/resources/Sample2_714ca2b7-22b7-4f69-b83d-9165f624da25.png new file mode 100644 index 0000000000000000000000000000000000000000..bf110501c2fe8dc89542fe28c91492d2b41ad9ff GIT binary patch literal 1080 zcmeAS@N?(olHy`uVBq!ia0y~yU^W3^MxX$LD`(U#Am_iQi(^Q|oVRxaC*5-3VF}2a z@cVvI{)8)e1t!XzhwCONe0tU##WSxgB&a-kp5pZR^{F*64?1Ss1la#z=)c5TbxQt2 zXpK_++q#3b(|)^szx|8-m)ODLE<@jrlgwY6`9EmHN~~L6XmhV_%FA`f`_>=H{L4~s#8+;Gd`*M< z%R?o$zG6!bd!{KXPUA#a-}?Q^<@Nsh^#bO*8Qt$ZY5aANy<&>qpY*C-QhgcjM{ZXv zD*Wv95boO6msPi-yQR;o`^m*D*^Xp-h;40-?30t;D6Uz%{IA8l(Xz?|hWVlzsAR+ph^*xE^ieZ&c3vN2ah?FR(S zD;Ly#V3b?R{rSt6i|pcepNeu=z{4eR%e=Z$rAJr3W=Fq&WHIfQSgbfR!YYZi%U_!> zQWspORI2oft*dEA9RtFfJy$Q!wx4_9{FJ%_h0V5K6_NZSV0+i?rDutJ&hblWr~bwx zX*zS|@>+kv&E~KqGm%?AH(Yn@84f$_=U4?h=CnGuF z*sGUkOZmS3uk)}!SdwnbDpNR_{S~|XgTP$|(f;yx)hF%}zW)t5*0f(`Hom>4f93Av z>&B1P=iBQeC9Ak#|H~^j+@06KBzO)vEv{RBUIq~!Otw$?e`wiF++Vi;f!*oa#lLg^ yGS`aNs{A$od*nG^Z3Nr}4*oxx_r03`>qz`x$yp*Dzs_9;6$zfMelF{r5}E*;BNej% literal 0 HcmV?d00001 diff --git a/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/studies/experiment1_material/resources/Sample3_66fac760-acc7-4ed4-ba21-2cb67fa36e4d.png b/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/studies/experiment1_material/resources/Sample3_66fac760-acc7-4ed4-ba21-2cb67fa36e4d.png new file mode 100644 index 0000000000000000000000000000000000000000..dfa265d24d10ab0da0e4c0075c166b8c12626a55 GIT binary patch literal 1073 zcmeAS@N?(olHy`uVBq!ia0y~yU^W3^MxX$LD`(U#Am@jti(^Q|oVRzg^X?e%uspbv z@V@@^-h3F5 zd0&_Rll6D?cbqS}|DrDXzr%f3dC&j8_8;du%ZJ^0()jBjd&LyJ3&H;y*8kG6`>5P^ zyMO=PN1XT1?^xe%W1jz&rQnFK+zR=c2KSdv#kO~!@l0-!eI4pECyUAAksALMe!ByU zOBU{)$Hra6xY4pV3(4{iOTU(wsLeaxyD{&Opn2tjx(|$UOS%7d&ude2X;{nOsGRr7 z;qL=x8!z#FGv>)9E`Pq_&hbKIQ+Lj5+qkoTdfgMw2OYC*0_=Y<^j~VdRu$FT{axkQ zk*|e`2N1@_el78tG%v*GM((2&o4R*v<7PJ?%-{9uWos`-Z2QK@^E3ByB7)~ag#YE_ zj>518j(N$YdWlGOKlFZ)xkLph%Z?zUwyLab!Rl(KeKdxGN zAnEF#7xvyh#%8a@pZD#zwxD?ROW~}{x`xD<^Hr(0-{^mHMhYIas;JtQ!q--7isND< zt@!$OoMism%>O|nHe>Db+s|wg=gI25;xsFpV|Shb;f^m?E*qAa2d<5>u-|JDYlIX) z!T$ZHWw)EFF(rMy+4`uK3(0+pLGiftL*ZN%i(bovWqL@uqWlkAwZHQ1s1iN$5Gg@i zi1)v|n{PJ%%H6`r$3JhcymPde2gyL7hZjffpP+VcT~eu@`29$v2#k7>S(>$X-^Ndh z2eXG(rE1lgRnLjr3f6$0su>2Eq<<^FJS+Jq5o3rzbdJq3CHKi zYajVrv_|Pb8z++7_bZo|_I_OH$Jl=NN8^u!>=je={)kseDY!*%nz9;M;jyY&dd`VS zlJT+EJ|9dpuT!Y|z$mwrJNB!|mOY&hU-{2NcF5Z0;csuenIP1!>}@H_jWGJlmCLFA z&T}U|sa{+hbw!WA5fKu*USw(*g>3lhb2_kVRX&c7)}3ficbnN4^1-Hu3j?pLXWWbgWU^X7MQ+;orgzhTLVF#F5(%i(4SWsUPr z@jnUug0iUriz=JU;SB ztL?mpU5YWI4BX@bYg^gg&g5^YEp=>2qUE--WsA3|)}L-iGF*Pma?zX_D|adT%ILKz z=Y4Yc`+(WTOMKU>Oo@g6KOCBGgJkZ7DF5xr?>t)qWmhAadm+?+`coeF?xce|3#5{p zmXmYl@6umFkFMrwjWJl?nbpq$~_)8sPzG*(_m~9ha|AV3bQfpY%u2`nX zznsUE&uo%wMp%C9Rp!={m&zXP%H3!qiR1xcTi@Kahx+HrTxPsHG!4lUy8M+>I z$Gqj4keq$-^3BkmqZ5vAeah7F%0&thyH3frbJxq-c3xN{k=y;T;&H@}KSF&wPBMRO z=Kr7(o3Up3RWq;5U1x7@kw3ioy~aa?U&X4d?w8*Cbx5ltt9jY;*9s_7v-VY4q~Dq~ zF>A^4RzxsJy?$wP^2S8X|5b+Dl|QX0D{ex_{d$%8*7es#us`Fl@n0+sdZSP>E# zYnLaU`?W-Zh)KzOEp%$r)54c)I$ztaD0e0syb{5)J?W literal 0 HcmV?d00001 diff --git a/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/studies/experiment1_material/resources/Sample6_208df064-4b1c-4da0-a1f8-6412e1fb2284.png b/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/studies/experiment1_material/resources/Sample6_208df064-4b1c-4da0-a1f8-6412e1fb2284.png new file mode 100644 index 0000000000000000000000000000000000000000..e5c5c41104abfb92556f47f476d45beed79be215 GIT binary patch literal 1078 zcmeAS@N?(olHy`uVBq!ia0y~yU^W3^MxX$LD`(U#Am^{Ai(^Q|oVRzg^X?e%usqo7 z_`d%1Jq6dv7E?TKMK8EvW@7g@B1QfY2aBci6_eycxz&dj&Jllf;e{|AlO13SLb?}UmO0Y@jcY7E&o`#r?$N#bWV+!{$5)PxCx0H<}F*f`m8~D z&sHT%Q-=2YM;iYeWUrW_cPG&QviMz%)eVR9A36Mcz-;3sp0|4W%d}&^!gnqHSYFB@ zQzy*+iCz9d;I0q7U$->B%}?9&HMZxT975b6)c>-_(G&7}LYNDF_{yA+uW4|9c__nn zuf%c7P7Rx+)a=`j4ly995B7f?^29J~_U+#8ed-$(=UrDs(kEgYyIYuXV`6!<%%kpe zA_#2-!nV54wj~P(rW~m{RoioA8&&XE*xE1VdfVz50&j_(KbL*zp?RS~{Rc+5rQG*p{Z9u^ zz2|=SZ$y;jU4OmbB1i^`*uKs8$cdKO6+0<4@T)Gug}{Ia-!NHPT)b`f<;kxnJw({m zSvBjN)f~HuOjn=(zZI9Mx*)~Os(E>T+waBvijBJG$;*t08K0|{8$51gGHORu&A!Hg zB!2z!CSS$KTYaI&(pi&cvms>excU2=TQ6bFiS4;^6Df4^7A;TQ;gI95ar$QG>UOh( z2!9^_x@GoONj?3<2O0tM?jJ|e)AllRrK+FY@fiw1n;)I5uc8Qk?W*m^Iyxq*!@EJ v<^GrI`^sJ%{sc=ltW~S*0>b}ZxB4i4yVoFg$=QwSpaQ|u)z4*}Q$iB}5E2N? literal 0 HcmV?d00001 diff --git a/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/workflows/.gitkeep b/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/workflows/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/tests/TestingUtils/TestObjects.IO/Contracts/TestReadMe.txt b/tests/TestingUtils/TestObjects.IO/Contracts/TestReadMe.txt new file mode 100644 index 00000000..793aa682 --- /dev/null +++ b/tests/TestingUtils/TestObjects.IO/Contracts/TestReadMe.txt @@ -0,0 +1 @@ +This is a test \ No newline at end of file diff --git a/tests/TestingUtils/TestObjects.IO/Contracts/TestWorkbook.xlsx b/tests/TestingUtils/TestObjects.IO/Contracts/TestWorkbook.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..dfc1e460c78052691836244bcd1bbdf4a0d81b81 GIT binary patch literal 8487 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 literal 0 HcmV?d00001 diff --git a/tests/TestingUtils/TestObjects.IO/Path_findSubPaths/File1.txt b/tests/TestingUtils/TestObjects.IO/Path_findSubPaths/File1.txt new file mode 100644 index 00000000..e69de29b diff --git a/tests/TestingUtils/TestObjects.IO/Path_findSubPaths/File2.csv b/tests/TestingUtils/TestObjects.IO/Path_findSubPaths/File2.csv new file mode 100644 index 00000000..e69de29b diff --git a/tests/TestingUtils/TestObjects.IO/Path_findSubPaths/SubFolder/File3.xlsx b/tests/TestingUtils/TestObjects.IO/Path_findSubPaths/SubFolder/File3.xlsx new file mode 100644 index 00000000..e69de29b diff --git a/tests/TestingUtils/TestObjects.IO/Path_findSubPaths/SubFolder/SubSubFolder/File4 b/tests/TestingUtils/TestObjects.IO/Path_findSubPaths/SubFolder/SubSubFolder/File4 new file mode 100644 index 00000000..e69de29b diff --git a/tests/TestingUtils/Library.fs b/tests/TestingUtils/TestingUtils.fs similarity index 100% rename from tests/TestingUtils/Library.fs rename to tests/TestingUtils/TestingUtils.fs diff --git a/tests/TestingUtils/TestingUtils.fsproj b/tests/TestingUtils/TestingUtils.fsproj index 70dbba96..104e825d 100644 --- a/tests/TestingUtils/TestingUtils.fsproj +++ b/tests/TestingUtils/TestingUtils.fsproj @@ -33,7 +33,8 @@ - + + From 778eec27325e646cbaffc895525e4e8614fc6823 Mon Sep 17 00:00:00 2001 From: Heinrich Lukas Weil Date: Tue, 29 Oct 2024 15:09:05 +0100 Subject: [PATCH 05/30] add top level ARC IO functions --- src/ARCtrl/ARC.fs | 24 ++++++++++++++++++++ src/ARCtrl/ContractIO/ContractIO.fs | 35 ++++++++++++++++++++++++++++- 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/src/ARCtrl/ARC.fs b/src/ARCtrl/ARC.fs index 4f8b4bc8..1ceed3c9 100644 --- a/src/ARCtrl/ARC.fs +++ b/src/ARCtrl/ARC.fs @@ -88,6 +88,30 @@ type ARC(?isa : ArcInvestigation, ?cwl : unit, ?fs : FileSystem.FileSystem) = with get() = _fs and set(fs) = _fs <- fs + member this.Write(arcPath) = + this.GetWriteContracts() + |> fullfillWriteContractBatch arcPath + + member this.Update(arcPath) = + this.GetUpdateContracts() + |> fullfillWriteContractBatch arcPath + + static member load (arcPath : string) = + let paths = FileSystemHelper.getAllFilePaths arcPath + let arc = ARC.fromFilePaths (paths |> Seq.toArray) + + let contracts = arc.GetReadContracts() + + let fulFilledContracts = + contracts + |> fullfillReadContractBatch arcPath + + match fulFilledContracts with + | Ok c -> + arc.SetISAFromContracts(c) + Ok arc + | Error e -> Error e + member this.RemoveAssay(assayIdentifier: string) = let isa = match this.ISA with diff --git a/src/ARCtrl/ContractIO/ContractIO.fs b/src/ARCtrl/ContractIO/ContractIO.fs index 9ef39afd..50a171b4 100644 --- a/src/ARCtrl/ContractIO/ContractIO.fs +++ b/src/ARCtrl/ContractIO/ContractIO.fs @@ -20,6 +20,17 @@ let fulfillReadContract basePath (c : Contract) = | _ -> Error (sprintf "Contract %s is not an ISA contract" c.Path) +let fullfillReadContractBatch basePath (cs : Contract []) : Result= + cs + |> Array.map (fulfillReadContract basePath) + |> Array.fold (fun acc cr -> + match acc, cr with + | Ok acc, Ok cr -> Ok (Array.append acc [|cr|]) + | Error e, Ok _ -> Error e + | Error acc, Error e -> Error (Array.append acc [|e|]) + | Ok _, Error e -> Error [|e|] + ) (Ok [||]) + let fulfillWriteContract basePath (c : Contract) = match c.DTO with | Some (DTO.Spreadsheet wb) -> @@ -40,6 +51,17 @@ let fulfillWriteContract basePath (c : Contract) = | _ -> Error (sprintf "Contract %s is not an ISA contract" c.Path) +let fullfillWriteContractBatch basePath (cs : Contract []) : Result= + cs + |> Array.map (fulfillWriteContract basePath) + |> Array.fold (fun acc cr -> + match acc, cr with + | Ok (), Ok _ -> Ok () + | Error e, Ok _ -> Error e + | Error acc, Error e -> Error (Array.append acc [|e|]) + | Ok _, Error e -> Error [|e|] + ) (Ok ()) + let fulfillUpdateContract basePath (c : Contract) = match c.DTO with | Some (DTO.Spreadsheet wb) -> @@ -58,4 +80,15 @@ let fulfillUpdateContract basePath (c : Contract) = FileSystemHelper.writeFileText path "" Ok () | _ -> - Error (sprintf "Contract %s is not an ISA contract" c.Path) \ No newline at end of file + Error (sprintf "Contract %s is not an ISA contract" c.Path) + +let fullfillUpdateContractBatch basePath (cs : Contract []) : Result= + cs + |> Array.map (fulfillUpdateContract basePath) + |> Array.fold (fun acc cr -> + match acc, cr with + | Ok (), Ok _ -> Ok () + | Error e, Ok _ -> Error e + | Error acc, Error e -> Error (Array.append acc [|e|]) + | Ok _, Error e -> Error [|e|] + ) (Ok ()) \ No newline at end of file From 45964a73069c7f3ff971a8f42de49988f4295298 Mon Sep 17 00:00:00 2001 From: Heinrich Lukas Weil Date: Tue, 29 Oct 2024 15:27:14 +0100 Subject: [PATCH 06/30] add IO tests from ARCtrl.IO --- tests/ARCtrl/ARCtrl.Tests.fs | 146 +++++++++++++++++++++++++ tests/ARCtrl/ARCtrl.Tests.fsproj | 2 + tests/ARCtrl/ContractIO.Tests.fs | 104 ++++++++++++++++++ tests/ARCtrl/FileSystemHelper.Tests.fs | 29 +++++ tests/ARCtrl/Main.fs | 2 + tests/TestingUtils/TestObjects.IO.fs | 9 +- 6 files changed, 291 insertions(+), 1 deletion(-) create mode 100644 tests/ARCtrl/ContractIO.Tests.fs create mode 100644 tests/ARCtrl/FileSystemHelper.Tests.fs diff --git a/tests/ARCtrl/ARCtrl.Tests.fs b/tests/ARCtrl/ARCtrl.Tests.fs index 1ae71f6b..5f2880fe 100644 --- a/tests/ARCtrl/ARCtrl.Tests.fs +++ b/tests/ARCtrl/ARCtrl.Tests.fs @@ -942,6 +942,150 @@ let tests_RenameStudy = testList "RenameStudy" [ ] + +let tests_load = + + testList "Load" [ + testCase "simpleARC" (fun () -> + let p = TestObjects.IO.testSimpleARC + let result = ARC.load(p) + let result = Expect.wantOk result "ARC should load correctly" + + Expect.isSome result.ISA "Should contain an ISA part" + Expect.isNone result.CWL "Should not contain a CWL part" + + let isa = result.ISA.Value + Expect.equal isa.StudyCount 1 "Should contain 1 study" + Expect.equal isa.AssayCount 1 "Should contain 1 assay" + Expect.equal isa.RegisteredStudies.Count 1 "Should contain 1 registered study" + + let s = isa.Studies.[0] + Expect.equal s.RegisteredAssayCount 1 "Should contain 1 registered assay" + Expect.equal s.TableCount 3 "Study should contain 3 tables" + + let a = s.RegisteredAssays.[0] + Expect.equal a.TableCount 4 "Assay should contain 4 tables" + + ) + ] + + +let tests_write = + + testList "Write" [ + testCase "empty" (fun () -> + let p = ArcPathHelper.combine TestObjects.IO.testResultsFolder "ARC_Write_Empty" + let a = ARC() + Expect.wantOk (a.Write(p)) "ARC should write correctly" + + let expectedPaths = + [ + "/isa.investigation.xlsx"; + "/assays/.gitkeep"; + "/studies/.gitkeep"; + "/runs/.gitkeep"; + "/workflows/.gitkeep" + ] + |> List.sort + + + let paths = + FileSystemHelper.getAllFilePaths p + |> Seq.sort + + Expect.sequenceEqual paths expectedPaths "Files were not created correctly." + ) + testCase "SimpleARC" (fun () -> + let p = ArcPathHelper.combine TestObjects.IO.testResultsFolder "ARC_Write_SimpleARC" + let arc = ARC() + + let i = ArcInvestigation("MyInvestigation") + let studyName = "MyStudy" + let s = ArcStudy(studyName) + i.AddRegisteredStudy(s) + let assayName = "MyAssay" + let a = ArcAssay(assayName) + s.AddRegisteredAssay(a) + arc.ISA <- Some i + arc.UpdateFileSystem() + Expect.wantOk (arc.Write(p)) "ARC should write correctly" + + let expectedPaths = + [ + "/isa.investigation.xlsx"; + "/studies/.gitkeep"; + $"/studies/{studyName}/isa.study.xlsx" + $"/studies/{studyName}/README.md" + $"/studies/{studyName}/protocols/.gitkeep"; + $"/studies/{studyName}/resources/.gitkeep"; + "/assays/.gitkeep"; + $"/assays/{assayName}/isa.assay.xlsx" + $"/assays/{assayName}/README.md" + $"/assays/{assayName}/protocols/.gitkeep" + $"/assays/{assayName}/dataset/.gitkeep" + "/runs/.gitkeep"; + "/workflows/.gitkeep" + ] + |> List.sort + + + let paths = + FileSystemHelper.getAllFilePaths p + |> Seq.sort + + Expect.sequenceEqual paths expectedPaths "Files were not created correctly." + ) + testCase "LoadSimpleARCAndAddAssay" (fun () -> + let p = ArcPathHelper.combine TestObjects.IO.testResultsFolder "ARC_Write_SimpleARC" + let arc = Expect.wantOk (ARC.load(p)) "ARC should load correctly" + + let i = arc.ISA.Value + + let existingStudyName = "MyStudy" + let existingAssayName = "MyAssay" + + let assayName = "YourAssay" + i.InitAssay(assayName) |> ignore + arc.ISA <- Some i + + arc.UpdateFileSystem() + Expect.wantOk (arc.Write(p)) "ARC should write correctly" + + let expectedPaths = + [ + "/isa.investigation.xlsx"; + "/studies/.gitkeep"; + $"/studies/{existingStudyName}/isa.study.xlsx" + $"/studies/{existingStudyName}/README.md" + $"/studies/{existingStudyName}/protocols/.gitkeep"; + $"/studies/{existingStudyName}/resources/.gitkeep"; + "/assays/.gitkeep"; + $"/assays/{existingAssayName}/isa.assay.xlsx" + $"/assays/{existingAssayName}/README.md" + $"/assays/{existingAssayName}/protocols/.gitkeep" + $"/assays/{existingAssayName}/dataset/.gitkeep" + $"/assays/{assayName}/isa.assay.xlsx" + $"/assays/{assayName}/README.md" + $"/assays/{assayName}/protocols/.gitkeep" + $"/assays/{assayName}/dataset/.gitkeep" + "/runs/.gitkeep"; + "/workflows/.gitkeep" + ] + |> List.sort + + + let paths = + FileSystemHelper.getAllFilePaths p + |> Seq.sort + + Expect.sequenceEqual paths expectedPaths "Files were not created correctly." + ) + |> testSequenced + ] + + + + let main = testList "ARCtrl" [ tests_create tests_fromFilePaths @@ -953,6 +1097,8 @@ let main = testList "ARCtrl" [ tests_RenameAssay tests_RenameStudy payload_file_filters + tests_load + tests_write ] diff --git a/tests/ARCtrl/ARCtrl.Tests.fsproj b/tests/ARCtrl/ARCtrl.Tests.fsproj index d9cf9eab..81e8b6a2 100644 --- a/tests/ARCtrl/ARCtrl.Tests.fsproj +++ b/tests/ARCtrl/ARCtrl.Tests.fsproj @@ -6,6 +6,8 @@ false + + diff --git a/tests/ARCtrl/ContractIO.Tests.fs b/tests/ARCtrl/ContractIO.Tests.fs new file mode 100644 index 00000000..41fb4096 --- /dev/null +++ b/tests/ARCtrl/ContractIO.Tests.fs @@ -0,0 +1,104 @@ +module ARCtrl.ContractIO.Tests + +open TestingUtils +open ARCtrl +open ARCtrl.Contract +open ARCtrl.FileSystemHelper +open FsSpreadsheet +open FsSpreadsheet.Net +let testRead = + + testList "Read" [ + testCase "TextFile" (fun () -> + let fileName = "TestReadMe.txt" + let contract = Contract.createRead(fileName,DTOType.PlainText) + let dto = DTO.Text "This is a test" + let expected = + {contract with DTO = Some dto} + let result = fulfillReadContract TestObjects.IO.testInputFolder contract + let resultContract = Expect.wantOk result "Contract was not fulfilled correctly" + Expect.equal resultContract expected $"Text was not read correctly" + ) + testCase "XLSXFile" (fun () -> + let fileName = "TestWorkbook.xlsx" + let contract = Contract.createRead(fileName,DTOType.ISA_Study) + let result = fulfillReadContract TestObjects.IO.testInputFolder contract + let resultContract = Expect.wantOk result "Contract was not fulfilled correctly" + let dto = Expect.wantSome resultContract.DTO "DTO was not read correctly" + Expect.isTrue dto.isSpreadsheet "DTO was not read correctly" + let wb = dto.AsSpreadsheet() :?> FsSpreadsheet.FsWorkbook + let ws = Expect.wantSome (wb.TryGetWorksheetByName "TestSheet") "Workbook does not contain worksheet" + let row1 = Expect.wantSome (ws.TryGetRowValuesAt 1) "Worksheet does not contain row 1" + let row1AsInts = row1 |> Seq.map (string >> int) + let expected = [1;2;3] + Expect.sequenceEqual row1AsInts expected "Worksheet does not contain correct values" + let row2 = Expect.wantSome (ws.TryGetRowValuesAt 2) "Worksheet does not contain row 2" + let expected = ["A";"B";"C"] |> Seq.map box + Expect.sequenceEqual row2 expected "Worksheet does not contain correct values" + ) + ] + + +let testWrite = + + testList "Write" [ + testCase "TextFileEmpty" (fun () -> + let fileName = "TestEmpty.txt" + let contract = Contract.createCreate(fileName,DTOType.PlainText) + + Expect.wantOk (fulfillWriteContract TestObjects.IO.testOutputFolder contract) "Contract was not fulfilled correctly" + + let filePath = ArcPathHelper.combine TestObjects.IO.testOutputFolder fileName + Expect.isTrue (System.IO.File.Exists filePath) $"File {filePath} was not created" + Expect.equal (FileSystemHelper.readFileText filePath) "" $"File {filePath} was not empty" + ) + testCase "TextFile" (fun () -> + + let testText = "This is a test" + let fileName = "TestReadMe.txt" + let dto = DTO.Text testText + let contract = Contract.createCreate(fileName,DTOType.PlainText,dto) + + Expect.wantOk (fulfillWriteContract TestObjects.IO.testOutputFolder contract) "Contract was not fulfilled correctly" + + let filePath = ArcPathHelper.combine TestObjects.IO.testOutputFolder fileName + Expect.isTrue (System.IO.File.Exists filePath) $"File {filePath} was not created" + Expect.equal (FileSystemHelper.readFileText filePath) testText $"File {filePath} was not empty" + ) + testCase "XLSXFile" (fun () -> + + let worksheetName = "TestSheet" + let testWB = new FsWorkbook() + let testSheet = testWB.InitWorksheet (worksheetName) + testSheet.Row(1).Item(1).Value <- "A1" + testSheet.Row(1).Item(2).Value <- "B1" + testSheet.Row(1).Item(3).Value <- "C1" + let fileName = "TestWorkbook.xlsx" + let dto = DTO.Spreadsheet testWB + let contract = Contract.createCreate(fileName,DTOType.ISA_Assay,dto) + + Expect.wantOk (fulfillWriteContract TestObjects.IO.testOutputFolder contract) "Contract was not fulfilled correctly" + + let filePath = ArcPathHelper.combine TestObjects.IO.testOutputFolder fileName + + let wb = FsWorkbook.fromXlsxFile filePath + let ws = Expect.wantSome (wb.TryGetWorksheetByName worksheetName) "Workbook does not contain worksheet" + let row1 = Expect.wantSome (ws.TryGetRowValuesAt 1) "Worksheet does not contain row 1" + let expected = ["A1";"B1";"C1"] |> Seq.map box + Expect.sequenceEqual row1 expected "Worksheet does not contain correct values" + ) + ] + +let testExecute = + + testList "Write" [ + testCase "Implement" (fun () -> + Expect.isTrue false "ImplementTest" + ) + ] + +let main = + testList "ContractTests" [ + testRead + testWrite + ] \ No newline at end of file diff --git a/tests/ARCtrl/FileSystemHelper.Tests.fs b/tests/ARCtrl/FileSystemHelper.Tests.fs new file mode 100644 index 00000000..ccaec88d --- /dev/null +++ b/tests/ARCtrl/FileSystemHelper.Tests.fs @@ -0,0 +1,29 @@ +module ARCtrl.FileSystemHelper.Tests + +open TestingUtils +open ARCtrl +open System.Text.Json + + +let getAllFilePaths = + + testList "GetAllFilePaths" [ + testCase "simple" (fun () -> + let p = TestObjects.IO.testSubPathsFolder + let result = FileSystemHelper.getAllFilePaths p + let expected = + [ + "/File1.txt" + "/File2.csv" + "/SubFolder/File3.xlsx" + "/SubFolder/SubSubFolder/File4" + ] + Expect.sequenceEqual result expected "File Paths were not found correctly." + + ) + ] + +let main = + testList "PathTests" [ + getAllFilePaths + ] diff --git a/tests/ARCtrl/Main.fs b/tests/ARCtrl/Main.fs index d6ee9af7..1d5f138e 100644 --- a/tests/ARCtrl/Main.fs +++ b/tests/ARCtrl/Main.fs @@ -3,6 +3,8 @@ module ARCtrl.ARC.Tests open Fable.Pyxpecto let all = testSequenced <| testList "ARCtrl" [ + ARCtrl.ContractIO.Tests.main + ARCtrl.FileSystemHelper.Tests.main ARCtrl.Contracts.Tests.main ARCtrl.WebRequest.Tests.main ARCtrl.SemVer.Tests.main diff --git a/tests/TestingUtils/TestObjects.IO.fs b/tests/TestingUtils/TestObjects.IO.fs index 17a84371..8f7ce96d 100644 --- a/tests/TestingUtils/TestObjects.IO.fs +++ b/tests/TestingUtils/TestObjects.IO.fs @@ -1,4 +1,11 @@ module TestObjects.IO +let testResultsFolder = System.IO.Path.Combine(__SOURCE_DIRECTORY__,@"TestResults") + let testInputFolder = System.IO.Path.Combine(__SOURCE_DIRECTORY__,@"TestObjects/Contracts") -let testOutputFolder = System.IO.Path.Combine(__SOURCE_DIRECTORY__,@"TestResults/Contracts") \ No newline at end of file +let testOutputFolder = System.IO.Path.Combine(__SOURCE_DIRECTORY__,@"TestResults/Contracts") + +let testSubPathsFolder = System.IO.Path.Combine(__SOURCE_DIRECTORY__,@"TestObjects/Path_findSubPaths") + +let testSimpleARC = System.IO.Path.Combine(__SOURCE_DIRECTORY__,@"TestObjects/SimpleARC") +let testSimpleARC_Output = System.IO.Path.Combine(__SOURCE_DIRECTORY__,@"TestResults/SimpleARC") \ No newline at end of file From d9b6f9ef69c9b5ab028da3445a2fd337b0db4ccc Mon Sep 17 00:00:00 2001 From: Heinrich Lukas Weil Date: Tue, 29 Oct 2024 16:42:00 +0100 Subject: [PATCH 07/30] rename testARC folder --- .../{ARC_SimpleARC => SimpleARC}/.arc/.gitkeep | 0 .../{ARC_SimpleARC => SimpleARC}/assays/.gitkeep | 0 .../assays/measurement1/README.md | 0 .../assays/measurement1/dataset/.gitkeep | 0 .../measurement1/dataset/proteomics_result.csv | 0 .../assays/measurement1/dataset/sample1.raw | 0 .../assays/measurement1/dataset/sample2.raw | 0 .../assays/measurement1/dataset/sample3.raw | 0 .../assays/measurement1/dataset/sample4.raw | 0 .../assays/measurement1/dataset/sample5.raw | 0 .../assays/measurement1/dataset/sample6.raw | 0 .../assays/measurement1/dataset/sample7.raw | 0 .../assays/measurement1/dataset/table.csv | 0 .../assays/measurement1/isa.assay.xlsx | Bin .../assays/measurement1/isa.dataset.xlsx | Bin .../assays/measurement1/protocols/.gitkeep | 0 .../measurement1/protocols/extractionProtocol.txt | 0 .../isa.investigation.xlsx | Bin .../{ARC_SimpleARC => SimpleARC}/runs/.gitkeep | 0 .../{ARC_SimpleARC => SimpleARC}/studies/.gitkeep | 0 .../studies/experiment1_material/README.md | 0 .../studies/experiment1_material/isa.study.xlsx | Bin .../studies/experiment1_material/protocols/.gitkeep | 0 .../studies/experiment1_material/resources/.gitkeep | 0 ...Sample1_e36ca6b8-19ba-4504-aa82-d4781765873d.png | Bin ...Sample2_714ca2b7-22b7-4f69-b83d-9165f624da25.png | Bin ...Sample3_66fac760-acc7-4ed4-ba21-2cb67fa36e4d.png | Bin ...Sample4_cba5f40c-fc05-44d6-a589-b0e3dafaeefe.png | Bin ...Sample5_84c37b60-2342-4226-a36c-4b8dfe84ebe9.png | Bin ...Sample6_208df064-4b1c-4da0-a1f8-6412e1fb2284.png | Bin .../{ARC_SimpleARC => SimpleARC}/workflows/.gitkeep | 0 31 files changed, 0 insertions(+), 0 deletions(-) rename tests/TestingUtils/TestObjects.IO/{ARC_SimpleARC => SimpleARC}/.arc/.gitkeep (100%) rename tests/TestingUtils/TestObjects.IO/{ARC_SimpleARC => SimpleARC}/assays/.gitkeep (100%) rename tests/TestingUtils/TestObjects.IO/{ARC_SimpleARC => SimpleARC}/assays/measurement1/README.md (100%) rename tests/TestingUtils/TestObjects.IO/{ARC_SimpleARC => SimpleARC}/assays/measurement1/dataset/.gitkeep (100%) rename tests/TestingUtils/TestObjects.IO/{ARC_SimpleARC => SimpleARC}/assays/measurement1/dataset/proteomics_result.csv (100%) rename tests/TestingUtils/TestObjects.IO/{ARC_SimpleARC => SimpleARC}/assays/measurement1/dataset/sample1.raw (100%) rename tests/TestingUtils/TestObjects.IO/{ARC_SimpleARC => SimpleARC}/assays/measurement1/dataset/sample2.raw (100%) rename tests/TestingUtils/TestObjects.IO/{ARC_SimpleARC => SimpleARC}/assays/measurement1/dataset/sample3.raw (100%) rename tests/TestingUtils/TestObjects.IO/{ARC_SimpleARC => SimpleARC}/assays/measurement1/dataset/sample4.raw (100%) rename tests/TestingUtils/TestObjects.IO/{ARC_SimpleARC => SimpleARC}/assays/measurement1/dataset/sample5.raw (100%) rename tests/TestingUtils/TestObjects.IO/{ARC_SimpleARC => SimpleARC}/assays/measurement1/dataset/sample6.raw (100%) rename tests/TestingUtils/TestObjects.IO/{ARC_SimpleARC => SimpleARC}/assays/measurement1/dataset/sample7.raw (100%) rename tests/TestingUtils/TestObjects.IO/{ARC_SimpleARC => SimpleARC}/assays/measurement1/dataset/table.csv (100%) rename tests/TestingUtils/TestObjects.IO/{ARC_SimpleARC => SimpleARC}/assays/measurement1/isa.assay.xlsx (100%) rename tests/TestingUtils/TestObjects.IO/{ARC_SimpleARC => SimpleARC}/assays/measurement1/isa.dataset.xlsx (100%) rename tests/TestingUtils/TestObjects.IO/{ARC_SimpleARC => SimpleARC}/assays/measurement1/protocols/.gitkeep (100%) rename tests/TestingUtils/TestObjects.IO/{ARC_SimpleARC => SimpleARC}/assays/measurement1/protocols/extractionProtocol.txt (100%) rename tests/TestingUtils/TestObjects.IO/{ARC_SimpleARC => SimpleARC}/isa.investigation.xlsx (100%) rename tests/TestingUtils/TestObjects.IO/{ARC_SimpleARC => SimpleARC}/runs/.gitkeep (100%) rename tests/TestingUtils/TestObjects.IO/{ARC_SimpleARC => SimpleARC}/studies/.gitkeep (100%) rename tests/TestingUtils/TestObjects.IO/{ARC_SimpleARC => SimpleARC}/studies/experiment1_material/README.md (100%) rename tests/TestingUtils/TestObjects.IO/{ARC_SimpleARC => SimpleARC}/studies/experiment1_material/isa.study.xlsx (100%) rename tests/TestingUtils/TestObjects.IO/{ARC_SimpleARC => SimpleARC}/studies/experiment1_material/protocols/.gitkeep (100%) rename tests/TestingUtils/TestObjects.IO/{ARC_SimpleARC => SimpleARC}/studies/experiment1_material/resources/.gitkeep (100%) rename tests/TestingUtils/TestObjects.IO/{ARC_SimpleARC => SimpleARC}/studies/experiment1_material/resources/Sample1_e36ca6b8-19ba-4504-aa82-d4781765873d.png (100%) rename tests/TestingUtils/TestObjects.IO/{ARC_SimpleARC => SimpleARC}/studies/experiment1_material/resources/Sample2_714ca2b7-22b7-4f69-b83d-9165f624da25.png (100%) rename tests/TestingUtils/TestObjects.IO/{ARC_SimpleARC => SimpleARC}/studies/experiment1_material/resources/Sample3_66fac760-acc7-4ed4-ba21-2cb67fa36e4d.png (100%) rename tests/TestingUtils/TestObjects.IO/{ARC_SimpleARC => SimpleARC}/studies/experiment1_material/resources/Sample4_cba5f40c-fc05-44d6-a589-b0e3dafaeefe.png (100%) rename tests/TestingUtils/TestObjects.IO/{ARC_SimpleARC => SimpleARC}/studies/experiment1_material/resources/Sample5_84c37b60-2342-4226-a36c-4b8dfe84ebe9.png (100%) rename tests/TestingUtils/TestObjects.IO/{ARC_SimpleARC => SimpleARC}/studies/experiment1_material/resources/Sample6_208df064-4b1c-4da0-a1f8-6412e1fb2284.png (100%) rename tests/TestingUtils/TestObjects.IO/{ARC_SimpleARC => SimpleARC}/workflows/.gitkeep (100%) diff --git a/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/.arc/.gitkeep b/tests/TestingUtils/TestObjects.IO/SimpleARC/.arc/.gitkeep similarity index 100% rename from tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/.arc/.gitkeep rename to tests/TestingUtils/TestObjects.IO/SimpleARC/.arc/.gitkeep diff --git a/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/.gitkeep b/tests/TestingUtils/TestObjects.IO/SimpleARC/assays/.gitkeep similarity index 100% rename from tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/.gitkeep rename to tests/TestingUtils/TestObjects.IO/SimpleARC/assays/.gitkeep diff --git a/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/README.md b/tests/TestingUtils/TestObjects.IO/SimpleARC/assays/measurement1/README.md similarity index 100% rename from tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/README.md rename to tests/TestingUtils/TestObjects.IO/SimpleARC/assays/measurement1/README.md diff --git a/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/dataset/.gitkeep b/tests/TestingUtils/TestObjects.IO/SimpleARC/assays/measurement1/dataset/.gitkeep similarity index 100% rename from tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/dataset/.gitkeep rename to tests/TestingUtils/TestObjects.IO/SimpleARC/assays/measurement1/dataset/.gitkeep diff --git a/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/dataset/proteomics_result.csv b/tests/TestingUtils/TestObjects.IO/SimpleARC/assays/measurement1/dataset/proteomics_result.csv similarity index 100% rename from tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/dataset/proteomics_result.csv rename to tests/TestingUtils/TestObjects.IO/SimpleARC/assays/measurement1/dataset/proteomics_result.csv diff --git a/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/dataset/sample1.raw b/tests/TestingUtils/TestObjects.IO/SimpleARC/assays/measurement1/dataset/sample1.raw similarity index 100% rename from tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/dataset/sample1.raw rename to tests/TestingUtils/TestObjects.IO/SimpleARC/assays/measurement1/dataset/sample1.raw diff --git a/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/dataset/sample2.raw b/tests/TestingUtils/TestObjects.IO/SimpleARC/assays/measurement1/dataset/sample2.raw similarity index 100% rename from tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/dataset/sample2.raw rename to tests/TestingUtils/TestObjects.IO/SimpleARC/assays/measurement1/dataset/sample2.raw diff --git a/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/dataset/sample3.raw b/tests/TestingUtils/TestObjects.IO/SimpleARC/assays/measurement1/dataset/sample3.raw similarity index 100% rename from tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/dataset/sample3.raw rename to tests/TestingUtils/TestObjects.IO/SimpleARC/assays/measurement1/dataset/sample3.raw diff --git a/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/dataset/sample4.raw b/tests/TestingUtils/TestObjects.IO/SimpleARC/assays/measurement1/dataset/sample4.raw similarity index 100% rename from tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/dataset/sample4.raw rename to tests/TestingUtils/TestObjects.IO/SimpleARC/assays/measurement1/dataset/sample4.raw diff --git a/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/dataset/sample5.raw b/tests/TestingUtils/TestObjects.IO/SimpleARC/assays/measurement1/dataset/sample5.raw similarity index 100% rename from tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/dataset/sample5.raw rename to tests/TestingUtils/TestObjects.IO/SimpleARC/assays/measurement1/dataset/sample5.raw diff --git a/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/dataset/sample6.raw b/tests/TestingUtils/TestObjects.IO/SimpleARC/assays/measurement1/dataset/sample6.raw similarity index 100% rename from tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/dataset/sample6.raw rename to tests/TestingUtils/TestObjects.IO/SimpleARC/assays/measurement1/dataset/sample6.raw diff --git a/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/dataset/sample7.raw b/tests/TestingUtils/TestObjects.IO/SimpleARC/assays/measurement1/dataset/sample7.raw similarity index 100% rename from tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/dataset/sample7.raw rename to tests/TestingUtils/TestObjects.IO/SimpleARC/assays/measurement1/dataset/sample7.raw diff --git a/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/dataset/table.csv b/tests/TestingUtils/TestObjects.IO/SimpleARC/assays/measurement1/dataset/table.csv similarity index 100% rename from tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/dataset/table.csv rename to tests/TestingUtils/TestObjects.IO/SimpleARC/assays/measurement1/dataset/table.csv diff --git a/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/isa.assay.xlsx b/tests/TestingUtils/TestObjects.IO/SimpleARC/assays/measurement1/isa.assay.xlsx similarity index 100% rename from tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/isa.assay.xlsx rename to tests/TestingUtils/TestObjects.IO/SimpleARC/assays/measurement1/isa.assay.xlsx diff --git a/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/isa.dataset.xlsx b/tests/TestingUtils/TestObjects.IO/SimpleARC/assays/measurement1/isa.dataset.xlsx similarity index 100% rename from tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/isa.dataset.xlsx rename to tests/TestingUtils/TestObjects.IO/SimpleARC/assays/measurement1/isa.dataset.xlsx diff --git a/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/protocols/.gitkeep b/tests/TestingUtils/TestObjects.IO/SimpleARC/assays/measurement1/protocols/.gitkeep similarity index 100% rename from tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/protocols/.gitkeep rename to tests/TestingUtils/TestObjects.IO/SimpleARC/assays/measurement1/protocols/.gitkeep diff --git a/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/protocols/extractionProtocol.txt b/tests/TestingUtils/TestObjects.IO/SimpleARC/assays/measurement1/protocols/extractionProtocol.txt similarity index 100% rename from tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/assays/measurement1/protocols/extractionProtocol.txt rename to tests/TestingUtils/TestObjects.IO/SimpleARC/assays/measurement1/protocols/extractionProtocol.txt diff --git a/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/isa.investigation.xlsx b/tests/TestingUtils/TestObjects.IO/SimpleARC/isa.investigation.xlsx similarity index 100% rename from tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/isa.investigation.xlsx rename to tests/TestingUtils/TestObjects.IO/SimpleARC/isa.investigation.xlsx diff --git a/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/runs/.gitkeep b/tests/TestingUtils/TestObjects.IO/SimpleARC/runs/.gitkeep similarity index 100% rename from tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/runs/.gitkeep rename to tests/TestingUtils/TestObjects.IO/SimpleARC/runs/.gitkeep diff --git a/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/studies/.gitkeep b/tests/TestingUtils/TestObjects.IO/SimpleARC/studies/.gitkeep similarity index 100% rename from tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/studies/.gitkeep rename to tests/TestingUtils/TestObjects.IO/SimpleARC/studies/.gitkeep diff --git a/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/studies/experiment1_material/README.md b/tests/TestingUtils/TestObjects.IO/SimpleARC/studies/experiment1_material/README.md similarity index 100% rename from tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/studies/experiment1_material/README.md rename to tests/TestingUtils/TestObjects.IO/SimpleARC/studies/experiment1_material/README.md diff --git a/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/studies/experiment1_material/isa.study.xlsx b/tests/TestingUtils/TestObjects.IO/SimpleARC/studies/experiment1_material/isa.study.xlsx similarity index 100% rename from tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/studies/experiment1_material/isa.study.xlsx rename to tests/TestingUtils/TestObjects.IO/SimpleARC/studies/experiment1_material/isa.study.xlsx diff --git a/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/studies/experiment1_material/protocols/.gitkeep b/tests/TestingUtils/TestObjects.IO/SimpleARC/studies/experiment1_material/protocols/.gitkeep similarity index 100% rename from tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/studies/experiment1_material/protocols/.gitkeep rename to tests/TestingUtils/TestObjects.IO/SimpleARC/studies/experiment1_material/protocols/.gitkeep diff --git a/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/studies/experiment1_material/resources/.gitkeep b/tests/TestingUtils/TestObjects.IO/SimpleARC/studies/experiment1_material/resources/.gitkeep similarity index 100% rename from tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/studies/experiment1_material/resources/.gitkeep rename to tests/TestingUtils/TestObjects.IO/SimpleARC/studies/experiment1_material/resources/.gitkeep diff --git a/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/studies/experiment1_material/resources/Sample1_e36ca6b8-19ba-4504-aa82-d4781765873d.png b/tests/TestingUtils/TestObjects.IO/SimpleARC/studies/experiment1_material/resources/Sample1_e36ca6b8-19ba-4504-aa82-d4781765873d.png similarity index 100% rename from tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/studies/experiment1_material/resources/Sample1_e36ca6b8-19ba-4504-aa82-d4781765873d.png rename to tests/TestingUtils/TestObjects.IO/SimpleARC/studies/experiment1_material/resources/Sample1_e36ca6b8-19ba-4504-aa82-d4781765873d.png diff --git a/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/studies/experiment1_material/resources/Sample2_714ca2b7-22b7-4f69-b83d-9165f624da25.png b/tests/TestingUtils/TestObjects.IO/SimpleARC/studies/experiment1_material/resources/Sample2_714ca2b7-22b7-4f69-b83d-9165f624da25.png similarity index 100% rename from tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/studies/experiment1_material/resources/Sample2_714ca2b7-22b7-4f69-b83d-9165f624da25.png rename to tests/TestingUtils/TestObjects.IO/SimpleARC/studies/experiment1_material/resources/Sample2_714ca2b7-22b7-4f69-b83d-9165f624da25.png diff --git a/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/studies/experiment1_material/resources/Sample3_66fac760-acc7-4ed4-ba21-2cb67fa36e4d.png b/tests/TestingUtils/TestObjects.IO/SimpleARC/studies/experiment1_material/resources/Sample3_66fac760-acc7-4ed4-ba21-2cb67fa36e4d.png similarity index 100% rename from tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/studies/experiment1_material/resources/Sample3_66fac760-acc7-4ed4-ba21-2cb67fa36e4d.png rename to tests/TestingUtils/TestObjects.IO/SimpleARC/studies/experiment1_material/resources/Sample3_66fac760-acc7-4ed4-ba21-2cb67fa36e4d.png diff --git a/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/studies/experiment1_material/resources/Sample4_cba5f40c-fc05-44d6-a589-b0e3dafaeefe.png b/tests/TestingUtils/TestObjects.IO/SimpleARC/studies/experiment1_material/resources/Sample4_cba5f40c-fc05-44d6-a589-b0e3dafaeefe.png similarity index 100% rename from tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/studies/experiment1_material/resources/Sample4_cba5f40c-fc05-44d6-a589-b0e3dafaeefe.png rename to tests/TestingUtils/TestObjects.IO/SimpleARC/studies/experiment1_material/resources/Sample4_cba5f40c-fc05-44d6-a589-b0e3dafaeefe.png diff --git a/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/studies/experiment1_material/resources/Sample5_84c37b60-2342-4226-a36c-4b8dfe84ebe9.png b/tests/TestingUtils/TestObjects.IO/SimpleARC/studies/experiment1_material/resources/Sample5_84c37b60-2342-4226-a36c-4b8dfe84ebe9.png similarity index 100% rename from tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/studies/experiment1_material/resources/Sample5_84c37b60-2342-4226-a36c-4b8dfe84ebe9.png rename to tests/TestingUtils/TestObjects.IO/SimpleARC/studies/experiment1_material/resources/Sample5_84c37b60-2342-4226-a36c-4b8dfe84ebe9.png diff --git a/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/studies/experiment1_material/resources/Sample6_208df064-4b1c-4da0-a1f8-6412e1fb2284.png b/tests/TestingUtils/TestObjects.IO/SimpleARC/studies/experiment1_material/resources/Sample6_208df064-4b1c-4da0-a1f8-6412e1fb2284.png similarity index 100% rename from tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/studies/experiment1_material/resources/Sample6_208df064-4b1c-4da0-a1f8-6412e1fb2284.png rename to tests/TestingUtils/TestObjects.IO/SimpleARC/studies/experiment1_material/resources/Sample6_208df064-4b1c-4da0-a1f8-6412e1fb2284.png diff --git a/tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/workflows/.gitkeep b/tests/TestingUtils/TestObjects.IO/SimpleARC/workflows/.gitkeep similarity index 100% rename from tests/TestingUtils/TestObjects.IO/ARC_SimpleARC/workflows/.gitkeep rename to tests/TestingUtils/TestObjects.IO/SimpleARC/workflows/.gitkeep From c27fdbf0548a3c036935d80ecd7f80591fc899c6 Mon Sep 17 00:00:00 2001 From: Heinrich Lukas Weil Date: Tue, 29 Oct 2024 17:01:53 +0100 Subject: [PATCH 08/30] add simple FileSystemHelper tests and small fixes --- src/ARCtrl/ContractIO/ContractIO.fs | 12 +++--- tests/ARCtrl/ARCtrl.Tests.fs | 15 ++++++-- tests/ARCtrl/ContractIO.Tests.fs | 32 +++++++++------- tests/ARCtrl/FileSystemHelper.Tests.fs | 37 +++++++++++++++++++ tests/TestingUtils/TestObjects.IO.fs | 17 ++++++--- .../TestObjects.IO/SimpleText.txt | 1 + 6 files changed, 85 insertions(+), 29 deletions(-) create mode 100644 tests/TestingUtils/TestObjects.IO/SimpleText.txt diff --git a/src/ARCtrl/ContractIO/ContractIO.fs b/src/ARCtrl/ContractIO/ContractIO.fs index 50a171b4..9f9db392 100644 --- a/src/ARCtrl/ContractIO/ContractIO.fs +++ b/src/ARCtrl/ContractIO/ContractIO.fs @@ -35,17 +35,17 @@ let fulfillWriteContract basePath (c : Contract) = match c.DTO with | Some (DTO.Spreadsheet wb) -> let path = ArcPathHelper.combine basePath c.Path - FileSystemHelper.ensureDirectory path + FileSystemHelper.ensureDirectory basePath FileSystemHelper.writeFileXlsx path (wb :?> FsWorkbook) Ok () | Some (DTO.Text t) -> let path = ArcPathHelper.combine basePath c.Path - FileSystemHelper.ensureDirectory path + FileSystemHelper.ensureDirectory basePath FileSystemHelper.writeFileText path t Ok () | None -> let path = ArcPathHelper.combine basePath c.Path - FileSystemHelper.ensureDirectory path + FileSystemHelper.ensureDirectory basePath FileSystemHelper.writeFileText path "" Ok () | _ -> @@ -66,17 +66,17 @@ let fulfillUpdateContract basePath (c : Contract) = match c.DTO with | Some (DTO.Spreadsheet wb) -> let path = ArcPathHelper.combine basePath c.Path - FileSystemHelper.ensureDirectory path + FileSystemHelper.ensureDirectory basePath FileSystemHelper.writeFileXlsx path (wb :?> FsWorkbook) Ok () | Some (DTO.Text t) -> let path = ArcPathHelper.combine basePath c.Path - FileSystemHelper.ensureDirectory path + FileSystemHelper.ensureDirectory basePath FileSystemHelper.writeFileText path t Ok () | None -> let path = ArcPathHelper.combine basePath c.Path - FileSystemHelper.ensureDirectory path + FileSystemHelper.ensureDirectory basePath FileSystemHelper.writeFileText path "" Ok () | _ -> diff --git a/tests/ARCtrl/ARCtrl.Tests.fs b/tests/ARCtrl/ARCtrl.Tests.fs index 5f2880fe..7708bb55 100644 --- a/tests/ARCtrl/ARCtrl.Tests.fs +++ b/tests/ARCtrl/ARCtrl.Tests.fs @@ -946,7 +946,7 @@ let tests_RenameStudy = testList "RenameStudy" [ let tests_load = testList "Load" [ - testCase "simpleARC" (fun () -> + ftestCase "simpleARC" (fun () -> let p = TestObjects.IO.testSimpleARC let result = ARC.load(p) let result = Expect.wantOk result "ARC should load correctly" @@ -973,9 +973,12 @@ let tests_load = let tests_write = testList "Write" [ - testCase "empty" (fun () -> + ftestCase "empty" (fun () -> let p = ArcPathHelper.combine TestObjects.IO.testResultsFolder "ARC_Write_Empty" let a = ARC() + + FileSystemHelper.ensureDirectory p + Expect.wantOk (a.Write(p)) "ARC should write correctly" let expectedPaths = @@ -995,10 +998,12 @@ let tests_write = Expect.sequenceEqual paths expectedPaths "Files were not created correctly." ) - testCase "SimpleARC" (fun () -> + ftestCase "SimpleARC" (fun () -> let p = ArcPathHelper.combine TestObjects.IO.testResultsFolder "ARC_Write_SimpleARC" let arc = ARC() + FileSystemHelper.ensureDirectory p + let i = ArcInvestigation("MyInvestigation") let studyName = "MyStudy" let s = ArcStudy(studyName) @@ -1035,10 +1040,12 @@ let tests_write = Expect.sequenceEqual paths expectedPaths "Files were not created correctly." ) - testCase "LoadSimpleARCAndAddAssay" (fun () -> + ftestCase "LoadSimpleARCAndAddAssay" (fun () -> let p = ArcPathHelper.combine TestObjects.IO.testResultsFolder "ARC_Write_SimpleARC" let arc = Expect.wantOk (ARC.load(p)) "ARC should load correctly" + FileSystemHelper.ensureDirectory p + let i = arc.ISA.Value let existingStudyName = "MyStudy" diff --git a/tests/ARCtrl/ContractIO.Tests.fs b/tests/ARCtrl/ContractIO.Tests.fs index 41fb4096..12bb3ad3 100644 --- a/tests/ARCtrl/ContractIO.Tests.fs +++ b/tests/ARCtrl/ContractIO.Tests.fs @@ -9,20 +9,20 @@ open FsSpreadsheet.Net let testRead = testList "Read" [ - testCase "TextFile" (fun () -> + ftestCase "TextFile" (fun () -> let fileName = "TestReadMe.txt" let contract = Contract.createRead(fileName,DTOType.PlainText) let dto = DTO.Text "This is a test" let expected = {contract with DTO = Some dto} - let result = fulfillReadContract TestObjects.IO.testInputFolder contract + let result = fulfillReadContract TestObjects.IO.testContractsFolder contract let resultContract = Expect.wantOk result "Contract was not fulfilled correctly" Expect.equal resultContract expected $"Text was not read correctly" ) - testCase "XLSXFile" (fun () -> + ftestCase "XLSXFile" (fun () -> let fileName = "TestWorkbook.xlsx" let contract = Contract.createRead(fileName,DTOType.ISA_Study) - let result = fulfillReadContract TestObjects.IO.testInputFolder contract + let result = fulfillReadContract TestObjects.IO.testContractsFolder contract let resultContract = Expect.wantOk result "Contract was not fulfilled correctly" let dto = Expect.wantSome resultContract.DTO "DTO was not read correctly" Expect.isTrue dto.isSpreadsheet "DTO was not read correctly" @@ -42,30 +42,34 @@ let testRead = let testWrite = testList "Write" [ - testCase "TextFileEmpty" (fun () -> + ftestCase "TextFileEmpty" (fun () -> let fileName = "TestEmpty.txt" let contract = Contract.createCreate(fileName,DTOType.PlainText) - Expect.wantOk (fulfillWriteContract TestObjects.IO.testOutputFolder contract) "Contract was not fulfilled correctly" + FileSystemHelper.ensureDirectory TestObjects.IO.testResultsFolder - let filePath = ArcPathHelper.combine TestObjects.IO.testOutputFolder fileName + Expect.wantOk (fulfillWriteContract TestObjects.IO.testResultsFolder contract) "Contract was not fulfilled correctly" + + let filePath = ArcPathHelper.combine TestObjects.IO.testResultsFolder fileName Expect.isTrue (System.IO.File.Exists filePath) $"File {filePath} was not created" Expect.equal (FileSystemHelper.readFileText filePath) "" $"File {filePath} was not empty" ) - testCase "TextFile" (fun () -> + ftestCase "TextFile" (fun () -> let testText = "This is a test" let fileName = "TestReadMe.txt" let dto = DTO.Text testText let contract = Contract.createCreate(fileName,DTOType.PlainText,dto) - Expect.wantOk (fulfillWriteContract TestObjects.IO.testOutputFolder contract) "Contract was not fulfilled correctly" + FileSystemHelper.ensureDirectory TestObjects.IO.testResultsFolder + + Expect.wantOk (fulfillWriteContract TestObjects.IO.testResultsFolder contract) "Contract was not fulfilled correctly" - let filePath = ArcPathHelper.combine TestObjects.IO.testOutputFolder fileName + let filePath = ArcPathHelper.combine TestObjects.IO.testResultsFolder fileName Expect.isTrue (System.IO.File.Exists filePath) $"File {filePath} was not created" Expect.equal (FileSystemHelper.readFileText filePath) testText $"File {filePath} was not empty" ) - testCase "XLSXFile" (fun () -> + ftestCase "XLSXFile" (fun () -> let worksheetName = "TestSheet" let testWB = new FsWorkbook() @@ -77,9 +81,11 @@ let testWrite = let dto = DTO.Spreadsheet testWB let contract = Contract.createCreate(fileName,DTOType.ISA_Assay,dto) - Expect.wantOk (fulfillWriteContract TestObjects.IO.testOutputFolder contract) "Contract was not fulfilled correctly" + FileSystemHelper.ensureDirectory TestObjects.IO.testResultsFolder + + Expect.wantOk (fulfillWriteContract TestObjects.IO.testResultsFolder contract) "Contract was not fulfilled correctly" - let filePath = ArcPathHelper.combine TestObjects.IO.testOutputFolder fileName + let filePath = ArcPathHelper.combine TestObjects.IO.testResultsFolder fileName let wb = FsWorkbook.fromXlsxFile filePath let ws = Expect.wantSome (wb.TryGetWorksheetByName worksheetName) "Workbook does not contain worksheet" diff --git a/tests/ARCtrl/FileSystemHelper.Tests.fs b/tests/ARCtrl/FileSystemHelper.Tests.fs index ccaec88d..d8678c5c 100644 --- a/tests/ARCtrl/FileSystemHelper.Tests.fs +++ b/tests/ARCtrl/FileSystemHelper.Tests.fs @@ -5,6 +5,41 @@ open ARCtrl open System.Text.Json +let readFileText = + testList "ReadText" [ + ftestCase "simple" (fun () -> + let p = TestObjects.IO.simpleTextFilePath + let result = FileSystemHelper.readFileText p + let expected = "Hello" + Expect.equal result expected "Text was not read correctly." + ) + ] + +let writeFileText = + testList "WriteText" [ + ftestCase "simple" (fun () -> + ARCtrl.FileSystemHelper.ensureDirectory TestObjects.IO.testResultsFolder + let p = ArcPathHelper.combine TestObjects.IO.testResultsFolder "SimpleText.txt" + let t = "Hello" + printfn "write to %s" p + FileSystemHelper.writeFileText p t + let result = FileSystemHelper.readFileText p + let expected = "Hello" + Expect.equal result expected "Text was not read correctly." + ) + ftestCase "SubDirectoryWithEnsureDir" (fun () -> + let subDir = ArcPathHelper.combine TestObjects.IO.testResultsFolder "SubFolder" + let p = ArcPathHelper.combine subDir "SimpleText.txt" + let t = "Hello" + printfn "write to %s" p + FileSystemHelper.ensureDirectory subDir + FileSystemHelper.writeFileText p t + let result = FileSystemHelper.readFileText p + let expected = "Hello" + Expect.equal result expected "Text was not read correctly." + ) + ] + let getAllFilePaths = testList "GetAllFilePaths" [ @@ -25,5 +60,7 @@ let getAllFilePaths = let main = testList "PathTests" [ + readFileText + writeFileText getAllFilePaths ] diff --git a/tests/TestingUtils/TestObjects.IO.fs b/tests/TestingUtils/TestObjects.IO.fs index 8f7ce96d..28ce2c06 100644 --- a/tests/TestingUtils/TestObjects.IO.fs +++ b/tests/TestingUtils/TestObjects.IO.fs @@ -1,11 +1,16 @@ module TestObjects.IO -let testResultsFolder = System.IO.Path.Combine(__SOURCE_DIRECTORY__,@"TestResults") +open ARCtrl.ArcPathHelper -let testInputFolder = System.IO.Path.Combine(__SOURCE_DIRECTORY__,@"TestObjects/Contracts") -let testOutputFolder = System.IO.Path.Combine(__SOURCE_DIRECTORY__,@"TestResults/Contracts") +let testObjectsBaseFolder = combine __SOURCE_DIRECTORY__ "TestObjects.IO" +let testResultsFolder = combine __SOURCE_DIRECTORY__ "TestResults" -let testSubPathsFolder = System.IO.Path.Combine(__SOURCE_DIRECTORY__,@"TestObjects/Path_findSubPaths") +let testContractsFolder = combine testObjectsBaseFolder "Contracts" -let testSimpleARC = System.IO.Path.Combine(__SOURCE_DIRECTORY__,@"TestObjects/SimpleARC") -let testSimpleARC_Output = System.IO.Path.Combine(__SOURCE_DIRECTORY__,@"TestResults/SimpleARC") \ No newline at end of file +let testSubPathsFolder = combine testObjectsBaseFolder "Path_findSubPaths" + +let testSimpleARC = combine testObjectsBaseFolder "SimpleARC" +let testSimpleARC_Output = combine testResultsFolder "TestResults/SimpleARC" + + +let simpleTextFilePath = combine testObjectsBaseFolder "SimpleText.txt" \ No newline at end of file diff --git a/tests/TestingUtils/TestObjects.IO/SimpleText.txt b/tests/TestingUtils/TestObjects.IO/SimpleText.txt new file mode 100644 index 00000000..5ab2f8a4 --- /dev/null +++ b/tests/TestingUtils/TestObjects.IO/SimpleText.txt @@ -0,0 +1 @@ +Hello \ No newline at end of file From 83f8473073bdb5edbb7140897bb1a03ffcd1af9a Mon Sep 17 00:00:00 2001 From: Heinrich Lukas Weil Date: Wed, 30 Oct 2024 14:31:29 +0100 Subject: [PATCH 09/30] fix IO tests for .NET --- build/BasicTasks.fs | 1 + src/ARCtrl/ContractIO/ContractIO.fs | 14 ++++---- src/ARCtrl/ContractIO/FileSystemHelper.fs | 24 +++++++++++-- tests/ARCtrl/ARCtrl.Tests.fs | 33 ++++++++++++------ tests/TestingUtils/TestObjects.IO.fs | 6 +++- .../assays/measurement1/isa.datamap.xlsx | Bin 0 -> 12852 bytes .../assays/measurement1/isa.dataset.xlsx | Bin 11653 -> 0 bytes 7 files changed, 58 insertions(+), 20 deletions(-) create mode 100644 tests/TestingUtils/TestObjects.IO/SimpleARC/assays/measurement1/isa.datamap.xlsx delete mode 100644 tests/TestingUtils/TestObjects.IO/SimpleARC/assays/measurement1/isa.dataset.xlsx diff --git a/build/BasicTasks.fs b/build/BasicTasks.fs index aa5ee777..8a114dd6 100644 --- a/build/BasicTasks.fs +++ b/build/BasicTasks.fs @@ -152,6 +152,7 @@ let clean = BuildTask.create "Clean" [] { ++ "src/**/obj" ++ "tests/**/bin" ++ "tests/**/obj" + ++ "tests/TestingUtils/TestResults" ++ "dist" ++ ProjectInfo.netPkgDir |> Shell.cleanDirs diff --git a/src/ARCtrl/ContractIO/ContractIO.fs b/src/ARCtrl/ContractIO/ContractIO.fs index 9f9db392..365605fd 100644 --- a/src/ARCtrl/ContractIO/ContractIO.fs +++ b/src/ARCtrl/ContractIO/ContractIO.fs @@ -31,21 +31,21 @@ let fullfillReadContractBatch basePath (cs : Contract []) : Result Error [|e|] ) (Ok [||]) -let fulfillWriteContract basePath (c : Contract) = +let fulfillWriteContract basePath (c : Contract) = match c.DTO with | Some (DTO.Spreadsheet wb) -> let path = ArcPathHelper.combine basePath c.Path - FileSystemHelper.ensureDirectory basePath + FileSystemHelper.ensureDirectoryOfFile path FileSystemHelper.writeFileXlsx path (wb :?> FsWorkbook) Ok () | Some (DTO.Text t) -> let path = ArcPathHelper.combine basePath c.Path - FileSystemHelper.ensureDirectory basePath + FileSystemHelper.ensureDirectoryOfFile path FileSystemHelper.writeFileText path t Ok () | None -> let path = ArcPathHelper.combine basePath c.Path - FileSystemHelper.ensureDirectory basePath + FileSystemHelper.ensureDirectoryOfFile path FileSystemHelper.writeFileText path "" Ok () | _ -> @@ -66,17 +66,17 @@ let fulfillUpdateContract basePath (c : Contract) = match c.DTO with | Some (DTO.Spreadsheet wb) -> let path = ArcPathHelper.combine basePath c.Path - FileSystemHelper.ensureDirectory basePath + FileSystemHelper.ensureDirectoryOfFile path FileSystemHelper.writeFileXlsx path (wb :?> FsWorkbook) Ok () | Some (DTO.Text t) -> let path = ArcPathHelper.combine basePath c.Path - FileSystemHelper.ensureDirectory basePath + FileSystemHelper.ensureDirectoryOfFile path FileSystemHelper.writeFileText path t Ok () | None -> let path = ArcPathHelper.combine basePath c.Path - FileSystemHelper.ensureDirectory basePath + FileSystemHelper.ensureDirectoryOfFile path FileSystemHelper.writeFileText path "" Ok () | _ -> diff --git a/src/ARCtrl/ContractIO/FileSystemHelper.fs b/src/ARCtrl/ContractIO/FileSystemHelper.fs index 95312ebf..d33df441 100644 --- a/src/ARCtrl/ContractIO/FileSystemHelper.fs +++ b/src/ARCtrl/ContractIO/FileSystemHelper.fs @@ -16,6 +16,10 @@ let ensureDirectory path = if not <| directoryExists path then createDirectory path +let ensureDirectoryOfFile (filePath : string) = + let file = new System.IO.FileInfo(filePath); + file.Directory.Create() + let fileExists path = System.IO.File.Exists path @@ -25,12 +29,25 @@ let getSubDirectories path = let getSubFiles path = System.IO.Directory.GetFiles path -let getAllFilePaths path = +/// Return the absolute path relative to the directoryPath +let makeRelative directoryPath (path : string) = + if directoryPath = "." || directoryPath = "/" || directoryPath = "" then path + else + if path.StartsWith(directoryPath) then + path.Substring(directoryPath.Length) + else path + +let standardizeSlashes (path : string) = + path.Replace("\\","/") + +let getAllFilePaths (directoryPath : string) = let rec allFiles dirs = if Seq.isEmpty dirs then Seq.empty else seq { yield! dirs |> Seq.collect getSubFiles yield! dirs |> Seq.collect getSubDirectories |> allFiles } - allFiles [path] + + allFiles [directoryPath] |> Seq.toArray + |> Array.map (makeRelative directoryPath >> standardizeSlashes) let readFileText path : string = System.IO.File.ReadAllText path @@ -41,6 +58,9 @@ let readFileBinary path : byte [] = let readFileXlsx path : FsWorkbook = FsWorkbook.fromXlsxFile path +let renameFileOrDirectory oldPath newPath = + System.IO.File.Move(oldPath, newPath) + let writeFileText path text = System.IO.File.WriteAllText(path, text) diff --git a/tests/ARCtrl/ARCtrl.Tests.fs b/tests/ARCtrl/ARCtrl.Tests.fs index 7708bb55..f247e5b2 100644 --- a/tests/ARCtrl/ARCtrl.Tests.fs +++ b/tests/ARCtrl/ARCtrl.Tests.fs @@ -977,8 +977,6 @@ let tests_write = let p = ArcPathHelper.combine TestObjects.IO.testResultsFolder "ARC_Write_Empty" let a = ARC() - FileSystemHelper.ensureDirectory p - Expect.wantOk (a.Write(p)) "ARC should write correctly" let expectedPaths = @@ -1002,8 +1000,6 @@ let tests_write = let p = ArcPathHelper.combine TestObjects.IO.testResultsFolder "ARC_Write_SimpleARC" let arc = ARC() - FileSystemHelper.ensureDirectory p - let i = ArcInvestigation("MyInvestigation") let studyName = "MyStudy" let s = ArcStudy(studyName) @@ -1040,16 +1036,15 @@ let tests_write = Expect.sequenceEqual paths expectedPaths "Files were not created correctly." ) + // This test reads a preexisting assay with data and everything, data content is not copied though but just the ftestCase "LoadSimpleARCAndAddAssay" (fun () -> - let p = ArcPathHelper.combine TestObjects.IO.testResultsFolder "ARC_Write_SimpleARC" - let arc = Expect.wantOk (ARC.load(p)) "ARC should load correctly" - - FileSystemHelper.ensureDirectory p + let p = ArcPathHelper.combine TestObjects.IO.testResultsFolder "ARC_Write_SimpleARCWithAssay" + let arc = Expect.wantOk (ARC.load(TestObjects.IO.testSimpleARC)) "ARC should load correctly" let i = arc.ISA.Value - let existingStudyName = "MyStudy" - let existingAssayName = "MyAssay" + let existingStudyName = "experiment1_material" + let existingAssayName = "measurement1" let assayName = "YourAssay" i.InitAssay(assayName) |> ignore @@ -1066,11 +1061,29 @@ let tests_write = $"/studies/{existingStudyName}/README.md" $"/studies/{existingStudyName}/protocols/.gitkeep"; $"/studies/{existingStudyName}/resources/.gitkeep"; + $"/studies/{existingStudyName}/resources/Sample5_84c37b60-2342-4226-a36c-4b8dfe84ebe9.png" + $"/studies/{existingStudyName}/resources/Sample6_208df064-4b1c-4da0-a1f8-6412e1fb2284.png" + $"/studies/{existingStudyName}/resources/Sample1_e36ca6b8-19ba-4504-aa82-d4781765873d.png" + $"/studies/{existingStudyName}/resources/Sample2_714ca2b7-22b7-4f69-b83d-9165f624da25.png" + $"/studies/{existingStudyName}/resources/Sample3_66fac760-acc7-4ed4-ba21-2cb67fa36e4d.png" + $"/studies/{existingStudyName}/resources/Sample4_cba5f40c-fc05-44d6-a589-b0e3dafaeefe.png" "/assays/.gitkeep"; + $"/.arc/.gitkeep" $"/assays/{existingAssayName}/isa.assay.xlsx" $"/assays/{existingAssayName}/README.md" + $"/assays/{existingAssayName}/isa.datamap.xlsx" $"/assays/{existingAssayName}/protocols/.gitkeep" + $"/assays/{existingAssayName}/protocols/extractionProtocol.txt" $"/assays/{existingAssayName}/dataset/.gitkeep" + $"/assays/{existingAssayName}/dataset/table.csv" + $"/assays/{existingAssayName}/dataset/proteomics_result.csv" + $"/assays/{existingAssayName}/dataset/sample1.raw" + $"/assays/{existingAssayName}/dataset/sample2.raw" + $"/assays/{existingAssayName}/dataset/sample3.raw" + $"/assays/{existingAssayName}/dataset/sample4.raw" + $"/assays/{existingAssayName}/dataset/sample5.raw" + $"/assays/{existingAssayName}/dataset/sample6.raw" + $"/assays/{existingAssayName}/dataset/sample7.raw" $"/assays/{assayName}/isa.assay.xlsx" $"/assays/{assayName}/README.md" $"/assays/{assayName}/protocols/.gitkeep" diff --git a/tests/TestingUtils/TestObjects.IO.fs b/tests/TestingUtils/TestObjects.IO.fs index 28ce2c06..fdc846a8 100644 --- a/tests/TestingUtils/TestObjects.IO.fs +++ b/tests/TestingUtils/TestObjects.IO.fs @@ -3,7 +3,11 @@ module TestObjects.IO open ARCtrl.ArcPathHelper let testObjectsBaseFolder = combine __SOURCE_DIRECTORY__ "TestObjects.IO" -let testResultsFolder = combine __SOURCE_DIRECTORY__ "TestResults" + +let testResultsFolder = + #if !FABLE_COMPILER + combineMany [| __SOURCE_DIRECTORY__;"TestResults";"NET"|] + #endif let testContractsFolder = combine testObjectsBaseFolder "Contracts" diff --git a/tests/TestingUtils/TestObjects.IO/SimpleARC/assays/measurement1/isa.datamap.xlsx b/tests/TestingUtils/TestObjects.IO/SimpleARC/assays/measurement1/isa.datamap.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..650743901cce503e468884dbb71b02695473eb45 GIT binary patch literal 12852 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 X3IaI4@JDt;0%!th>8?K-Jiz||pma=W literal 0 HcmV?d00001 diff --git a/tests/TestingUtils/TestObjects.IO/SimpleARC/assays/measurement1/isa.dataset.xlsx b/tests/TestingUtils/TestObjects.IO/SimpleARC/assays/measurement1/isa.dataset.xlsx deleted file mode 100644 index f1d2278cd612048d0cde8f7dcace2703c017be99..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11653 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 X2??4y{@6u^1i%LEfl&TYbO8Pb@5Umf From 2693e40a5173a287792a2b2ce41ba60319d24420 Mon Sep 17 00:00:00 2001 From: Heinrich Lukas Weil Date: Wed, 30 Oct 2024 15:36:32 +0100 Subject: [PATCH 10/30] finish up NET implementation of top level ARC IO --- src/ARCtrl/ARC.fs | 52 ++-- src/ARCtrl/ContractIO/ContractIO.fs | 160 ++++++------ src/ARCtrl/ContractIO/FileSystemHelper.fs | 15 +- tests/ARCtrl/ARCtrl.Tests.fs | 294 ++++++++++++++++++++-- tests/ARCtrl/ContractIO.Tests.fs | 10 +- tests/ARCtrl/FileSystemHelper.Tests.fs | 6 +- 6 files changed, 410 insertions(+), 127 deletions(-) diff --git a/src/ARCtrl/ARC.fs b/src/ARCtrl/ARC.fs index 1ceed3c9..57e4b104 100644 --- a/src/ARCtrl/ARC.fs +++ b/src/ARCtrl/ARC.fs @@ -90,11 +90,11 @@ type ARC(?isa : ArcInvestigation, ?cwl : unit, ?fs : FileSystem.FileSystem) = member this.Write(arcPath) = this.GetWriteContracts() - |> fullfillWriteContractBatch arcPath + |> fullFillContractBatch arcPath member this.Update(arcPath) = this.GetUpdateContracts() - |> fullfillWriteContractBatch arcPath + |> fullFillContractBatch arcPath static member load (arcPath : string) = let paths = FileSystemHelper.getAllFilePaths arcPath @@ -104,7 +104,7 @@ type ARC(?isa : ArcInvestigation, ?cwl : unit, ?fs : FileSystem.FileSystem) = let fulFilledContracts = contracts - |> fullfillReadContractBatch arcPath + |> fullFillContractBatch arcPath match fulFilledContracts with | Ok c -> @@ -112,7 +112,7 @@ type ARC(?isa : ArcInvestigation, ?cwl : unit, ?fs : FileSystem.FileSystem) = Ok arc | Error e -> Error e - member this.RemoveAssay(assayIdentifier: string) = + member this.GetAssayRemoveContracts(assayIdentifier: string) = let isa = match this.ISA with | Some i when i.AssayIdentifiers |> Seq.contains assayIdentifier -> i @@ -125,15 +125,18 @@ type ARC(?isa : ArcInvestigation, ?cwl : unit, ?fs : FileSystem.FileSystem) = let assayFolderPath = getAssayFolderPath(assayIdentifier) let filteredPaths = paths |> Array.filter (fun p -> p.StartsWith(assayFolderPath) |> not) this.SetFilePaths(filteredPaths) - [ + [| assay.ToDeleteContract() isa.ToUpdateContract() for s in studies do s.ToUpdateContract() - ] - |> ResizeArray + |] + + member this.RemoveAssay(arcPath : string, assayIdentifier: string) = + this.GetAssayRemoveContracts(assayIdentifier) + |> fullFillContractBatch arcPath - member this.RenameAssay(oldAssayIdentifier: string, newAssayIdentifier: string) = + member this.GetAssayRenameContracts(oldAssayIdentifier: string, newAssayIdentifier: string) = let isa = match this.ISA with | Some i when i.AssayIdentifiers |> Seq.contains oldAssayIdentifier -> i @@ -146,13 +149,16 @@ type ARC(?isa : ArcInvestigation, ?cwl : unit, ?fs : FileSystem.FileSystem) = let newAssayFolderPath = getAssayFolderPath(newAssayIdentifier) let renamedPaths = paths |> Array.map (fun p -> p.Replace(oldAssayFolderPath,newAssayFolderPath)) this.SetFilePaths(renamedPaths) - [ + [| yield Contract.createRename(oldAssayFolderPath,newAssayFolderPath) yield! this.GetUpdateContracts() - ] - |> ResizeArray + |] + + member this.RenameAssay(arcPath : string, oldAssayIdentifier: string, newAssayIdentifier: string) = + this.GetAssayRenameContracts(oldAssayIdentifier,newAssayIdentifier) + |> fullFillContractBatch arcPath - member this.RemoveStudy(studyIdentifier: string) = + member this.GetStudyRemoveContracts(studyIdentifier: string) = let isa = match this.ISA with | Some i -> i @@ -162,13 +168,16 @@ type ARC(?isa : ArcInvestigation, ?cwl : unit, ?fs : FileSystem.FileSystem) = let studyFolderPath = getStudyFolderPath(studyIdentifier) let filteredPaths = paths |> Array.filter (fun p -> p.StartsWith(studyFolderPath) |> not) this.SetFilePaths(filteredPaths) - [ + [| Contract.createDelete(studyFolderPath) // isa.GetStudy(studyIdentifier).ToDeleteContract() isa.ToUpdateContract() - ] - |> ResizeArray + |] + + member this.RemoveStudy(arcPath : string, studyIdentifier: string) = + this.GetStudyRemoveContracts(studyIdentifier) + |> fullFillContractBatch arcPath - member this.RenameStudy(oldStudyIdentifier: string, newStudyIdentifier: string) = + member this.GetStudyRenameContracts(oldStudyIdentifier: string, newStudyIdentifier: string) = let isa = match this.ISA with | Some i when i.StudyIdentifiers |> Seq.contains oldStudyIdentifier -> i @@ -181,11 +190,14 @@ type ARC(?isa : ArcInvestigation, ?cwl : unit, ?fs : FileSystem.FileSystem) = let newStudyFolderPath = getStudyFolderPath(newStudyIdentifier) let renamedPaths = paths |> Array.map (fun p -> p.Replace(oldStudyFolderPath,newStudyFolderPath)) this.SetFilePaths(renamedPaths) - [ + [| yield Contract.createRename(oldStudyFolderPath,newStudyFolderPath) yield! this.GetUpdateContracts() - ] - |> ResizeArray + |] + + member this.RenameStudy(arcPath : string, oldStudyIdentifier: string, newStudyIdentifier: string) = + this.GetStudyRenameContracts(oldStudyIdentifier,newStudyIdentifier) + |> fullFillContractBatch arcPath //static member updateISA (isa : ISA.Investigation) (arc : ARC) : ARC = // raise (System.NotImplementedException()) @@ -268,7 +280,7 @@ type ARC(?isa : ArcInvestigation, ?cwl : unit, ?fs : FileSystem.FileSystem) = // fs <- Some newFS // to-do: function that returns read contracts based on a list of paths. - member this.GetReadContracts () = + member this.GetReadContracts () : Contract [] = _fs.Tree.ToFilePaths() |> Array.choose Contract.ARC.tryISAReadContractFromPath /// diff --git a/src/ARCtrl/ContractIO/ContractIO.fs b/src/ARCtrl/ContractIO/ContractIO.fs index 365605fd..a3f5fd6e 100644 --- a/src/ARCtrl/ContractIO/ContractIO.fs +++ b/src/ARCtrl/ContractIO/ContractIO.fs @@ -5,24 +5,27 @@ open ARCtrl.Contract open FsSpreadsheet let fulfillReadContract basePath (c : Contract) = - match c.DTOType with - | Some DTOType.ISA_Assay - | Some DTOType.ISA_Investigation - | Some DTOType.ISA_Study - | Some DTOType.ISA_Datamap -> - let path = ArcPathHelper.combine basePath c.Path - let wb = FileSystemHelper.readFileXlsx path |> box |> DTO.Spreadsheet - Ok {c with DTO = Some wb} - | Some DTOType.PlainText -> - let path = ArcPathHelper.combine basePath c.Path - let text = FileSystemHelper.readFileText path |> DTO.Text - Ok {c with DTO = Some text} - | _ -> - Error (sprintf "Contract %s is not an ISA contract" c.Path) + try + match c.DTOType with + | Some DTOType.ISA_Assay + | Some DTOType.ISA_Investigation + | Some DTOType.ISA_Study + | Some DTOType.ISA_Datamap -> + let path = ArcPathHelper.combine basePath c.Path + let wb = FileSystemHelper.readFileXlsx path |> box |> DTO.Spreadsheet + Ok {c with DTO = Some wb} + | Some DTOType.PlainText -> + let path = ArcPathHelper.combine basePath c.Path + let text = FileSystemHelper.readFileText path |> DTO.Text + Ok {c with DTO = Some text} + | _ -> + Error (sprintf "Contract %s is not an ISA contract" c.Path) + with + | e -> Error (sprintf "Error reading contract %s: %s" c.Path e.Message) -let fullfillReadContractBatch basePath (cs : Contract []) : Result= +let fullfillContractBatchBy contractF basePath (cs : Contract []) : Result= cs - |> Array.map (fulfillReadContract basePath) + |> Array.map (contractF basePath) |> Array.fold (fun acc cr -> match acc, cr with | Ok acc, Ok cr -> Ok (Array.append acc [|cr|]) @@ -31,64 +34,77 @@ let fullfillReadContractBatch basePath (cs : Contract []) : Result Error [|e|] ) (Ok [||]) -let fulfillWriteContract basePath (c : Contract) = - match c.DTO with - | Some (DTO.Spreadsheet wb) -> - let path = ArcPathHelper.combine basePath c.Path - FileSystemHelper.ensureDirectoryOfFile path - FileSystemHelper.writeFileXlsx path (wb :?> FsWorkbook) - Ok () - | Some (DTO.Text t) -> - let path = ArcPathHelper.combine basePath c.Path - FileSystemHelper.ensureDirectoryOfFile path - FileSystemHelper.writeFileText path t - Ok () - | None -> - let path = ArcPathHelper.combine basePath c.Path - FileSystemHelper.ensureDirectoryOfFile path - FileSystemHelper.writeFileText path "" - Ok () - | _ -> - Error (sprintf "Contract %s is not an ISA contract" c.Path) - -let fullfillWriteContractBatch basePath (cs : Contract []) : Result= - cs - |> Array.map (fulfillWriteContract basePath) - |> Array.fold (fun acc cr -> - match acc, cr with - | Ok (), Ok _ -> Ok () - | Error e, Ok _ -> Error e - | Error acc, Error e -> Error (Array.append acc [|e|]) - | Ok _, Error e -> Error [|e|] - ) (Ok ()) +let fulfillWriteContract basePath (c : Contract) = + try + match c.DTO with + | Some (DTO.Spreadsheet wb) -> + let path = ArcPathHelper.combine basePath c.Path + FileSystemHelper.ensureDirectoryOfFile path + FileSystemHelper.writeFileXlsx path (wb :?> FsWorkbook) + Ok (c) + | Some (DTO.Text t) -> + let path = ArcPathHelper.combine basePath c.Path + FileSystemHelper.ensureDirectoryOfFile path + FileSystemHelper.writeFileText path t + Ok (c) + | None -> + let path = ArcPathHelper.combine basePath c.Path + FileSystemHelper.ensureDirectoryOfFile path + FileSystemHelper.writeFileText path "" + Ok (c) + | _ -> + Error (sprintf "Contract %s is not an ISA contract" c.Path) + with + | e -> Error (sprintf "Error writing contract %s: %s" c.Path e.Message) let fulfillUpdateContract basePath (c : Contract) = + try + match c.DTO with + | Some (DTO.Spreadsheet wb) -> + let path = ArcPathHelper.combine basePath c.Path + FileSystemHelper.ensureDirectoryOfFile path + FileSystemHelper.writeFileXlsx path (wb :?> FsWorkbook) + Ok (c) + | Some (DTO.Text t) -> + let path = ArcPathHelper.combine basePath c.Path + FileSystemHelper.ensureDirectoryOfFile path + FileSystemHelper.writeFileText path t + Ok (c) + | None -> + let path = ArcPathHelper.combine basePath c.Path + FileSystemHelper.ensureDirectoryOfFile path + FileSystemHelper.writeFileText path "" + Ok (c) + | _ -> + Error (sprintf "Contract %s is not an ISA contract" c.Path) + with + | e -> Error (sprintf "Error updating contract %s: %s" c.Path e.Message) + +let fullfillRenameContract basePath (c : Contract) = match c.DTO with - | Some (DTO.Spreadsheet wb) -> - let path = ArcPathHelper.combine basePath c.Path - FileSystemHelper.ensureDirectoryOfFile path - FileSystemHelper.writeFileXlsx path (wb :?> FsWorkbook) - Ok () + | Some (DTO.Text t) when t = c.Path -> + Error (sprintf "Rename Contract %s old and new Path are the same" c.Path) | Some (DTO.Text t) -> - let path = ArcPathHelper.combine basePath c.Path - FileSystemHelper.ensureDirectoryOfFile path - FileSystemHelper.writeFileText path t - Ok () - | None -> - let path = ArcPathHelper.combine basePath c.Path - FileSystemHelper.ensureDirectoryOfFile path - FileSystemHelper.writeFileText path "" - Ok () - | _ -> - Error (sprintf "Contract %s is not an ISA contract" c.Path) + let newPath = ArcPathHelper.combine basePath t + let oldPath = ArcPathHelper.combine basePath c.Path + FileSystemHelper.renameFileOrDirectory oldPath newPath + Ok (c) + | _ -> Error (sprintf "Rename Contract %s does not contain new Path" c.Path) + -let fullfillUpdateContractBatch basePath (cs : Contract []) : Result= - cs - |> Array.map (fulfillUpdateContract basePath) - |> Array.fold (fun acc cr -> - match acc, cr with - | Ok (), Ok _ -> Ok () - | Error e, Ok _ -> Error e - | Error acc, Error e -> Error (Array.append acc [|e|]) - | Ok _, Error e -> Error [|e|] - ) (Ok ()) \ No newline at end of file +let fullfillDeleteContract basePath (c : Contract) = + let path = ArcPathHelper.combine basePath c.Path + FileSystemHelper.deleteFileOrDirectory path + Ok (c) + +let fullFillContract basePath (c : Contract) = + match c.Operation with + | Operation.READ -> fulfillReadContract basePath c + | Operation.CREATE -> fulfillWriteContract basePath c + | Operation.UPDATE -> fulfillUpdateContract basePath c + | Operation.DELETE -> fullfillDeleteContract basePath c + | Operation.RENAME -> fullfillRenameContract basePath c + | _ -> Error (sprintf "Operation %A not supported" c.Operation) + +let fullFillContractBatch basePath (cs : Contract []) = + fullfillContractBatchBy fullFillContract basePath cs \ No newline at end of file diff --git a/src/ARCtrl/ContractIO/FileSystemHelper.fs b/src/ARCtrl/ContractIO/FileSystemHelper.fs index d33df441..e86367e2 100644 --- a/src/ARCtrl/ContractIO/FileSystemHelper.fs +++ b/src/ARCtrl/ContractIO/FileSystemHelper.fs @@ -59,7 +59,11 @@ let readFileXlsx path : FsWorkbook = FsWorkbook.fromXlsxFile path let renameFileOrDirectory oldPath newPath = - System.IO.File.Move(oldPath, newPath) + if fileExists oldPath then + System.IO.File.Move(oldPath, newPath) + elif directoryExists oldPath then + System.IO.Directory.Move(oldPath, newPath) + else () let writeFileText path text = System.IO.File.WriteAllText(path, text) @@ -68,4 +72,11 @@ let writeFileBinary path (bytes : byte []) = System.IO.File.WriteAllBytes(path,bytes) let writeFileXlsx path (wb : FsWorkbook) = - FsWorkbook.toXlsxFile path wb \ No newline at end of file + FsWorkbook.toXlsxFile path wb + +let deleteFileOrDirectory path = + if fileExists path then + System.IO.File.Delete path + elif directoryExists path then + System.IO.Directory.Delete(path, true) + else () \ No newline at end of file diff --git a/tests/ARCtrl/ARCtrl.Tests.fs b/tests/ARCtrl/ARCtrl.Tests.fs index f247e5b2..ce4733b4 100644 --- a/tests/ARCtrl/ARCtrl.Tests.fs +++ b/tests/ARCtrl/ARCtrl.Tests.fs @@ -92,7 +92,7 @@ let private tests_read_contracts = testList "read_contracts" [ Expect.equal assay1.TableCount 1 "assay 1 should have read one table" ) - testCase "StudyAssayOnlyRegistered" (fun () -> // set to pending, until performance issues in Study.fromFsWorkbook is resolved. + testCase "GetStudyRemoveContractsOnlyRegistered" (fun () -> // set to pending, until performance issues in Study.fromFsWorkbook is resolved. let arc = ARC() arc.SetISAFromContracts([| SimpleISA.Investigation.investigationReadContract @@ -724,7 +724,7 @@ let private ``payload_file_filters`` = } ] -let private tests_RemoveAssay = testList "RemoveAssay" [ +let private tests_GetAssayRemoveContracts = testList "GetAssayRemoveContracts" [ ptestCase "not registered, fsworkbook equal" <| fun _ -> let arc = ARC() let i = ArcInvestigation.init("My Investigation") @@ -732,7 +732,7 @@ let private tests_RemoveAssay = testList "RemoveAssay" [ let assayIdentifier = "My Assay" i.InitAssay(assayIdentifier) |> ignore Expect.equal i.AssayCount 1 "ensure assay count" - let actual = arc.RemoveAssay(assayIdentifier) + let actual = arc.GetAssayRemoveContracts(assayIdentifier) let expected = [ Contract.createDelete (ArcPathHelper.getAssayFolderPath assayIdentifier) i.ToUpdateContract() @@ -745,7 +745,7 @@ let private tests_RemoveAssay = testList "RemoveAssay" [ let assayIdentifier = "My Assay" i.InitAssay(assayIdentifier) |> ignore Expect.equal i.AssayCount 1 "ensure assay count" - let actual = arc.RemoveAssay(assayIdentifier) + let actual = arc.GetAssayRemoveContracts(assayIdentifier) Expect.hasLength actual 2 "contract count" Expect.equal actual.[0].Path (ArcPathHelper.getAssayFolderPath assayIdentifier) "assay contract path" Expect.equal actual.[0].Operation DELETE "assay contract cmd" @@ -767,7 +767,7 @@ let private tests_RemoveAssay = testList "RemoveAssay" [ Expect.equal i.AssayCount 1 "ensure assay count" Expect.equal i.StudyCount 2 "ensure study count" Expect.hasLength a.StudiesRegisteredIn 2 "ensure studies registered in - count" - let actual = arc.RemoveAssay(assayIdentifier) + let actual = arc.GetAssayRemoveContracts(assayIdentifier) Expect.hasLength actual 4 "contract count" Expect.equal actual.[0].Path (ArcPathHelper.getAssayFolderPath assayIdentifier) "assay contract path" Expect.equal actual.[0].Operation DELETE "assay contract cmd" @@ -779,14 +779,14 @@ let private tests_RemoveAssay = testList "RemoveAssay" [ Expect.equal actual.[3].Operation UPDATE "study 2 contract cmd" ] -let tests_RenameAssay = testList "RenameAssay" [ +let tests_GetAssayRenameContracts = testList "GetAssayRenameContracts" [ testCase "not existing" <| fun _ -> let i = ArcInvestigation("MyInvestigation") i.InitAssay("OtherAssayName") |> ignore let arc = ARC(isa = i) let assayMoveF = - fun () -> arc.RenameAssay("MyOldAssay","MyNewAssay") |> ignore + fun () -> arc.GetAssayRenameContracts("MyOldAssay","MyNewAssay") |> ignore Expect.throws assayMoveF "Should fail as arc does not contan assay with given name" testCase "Basic" <| fun _ -> @@ -794,7 +794,7 @@ let tests_RenameAssay = testList "RenameAssay" [ i.InitAssay("MyOldAssay") |> ignore let arc = ARC(isa = i) arc.GetWriteContracts() |> ignore - let contracts = arc.RenameAssay("MyOldAssay","MyNewAssay") + let contracts = arc.GetAssayRenameContracts("MyOldAssay","MyNewAssay") Expect.hasLength contracts 2 "Contract count is wrong" let renameContract = contracts.[0] Expect.equal renameContract.Operation Operation.RENAME "Rename contract operation" @@ -816,7 +816,7 @@ let tests_RenameAssay = testList "RenameAssay" [ i.InitAssay("MyOldAssay") |> ignore let arc = ARC(isa = i) arc.GetWriteContracts() |> ignore - let contracts = arc.RenameAssay("MyOldAssay","MyNewAssay") + let contracts = arc.GetAssayRenameContracts("MyOldAssay","MyNewAssay") Expect.hasLength contracts 2 "Contract count is wrong" let renameContract = contracts.[0] Expect.equal renameContract.Operation Operation.RENAME "Rename contract operation" @@ -838,7 +838,7 @@ let tests_RenameAssay = testList "RenameAssay" [ s.InitRegisteredAssay("MyOldAssay") |> ignore let arc = ARC(isa = i) arc.GetWriteContracts() |> ignore - let contracts = arc.RenameAssay("MyOldAssay","MyNewAssay") + let contracts = arc.GetAssayRenameContracts("MyOldAssay","MyNewAssay") Expect.hasLength contracts 3 "Contract count is wrong" // Rename contract let renameContract = contracts.[0] @@ -871,14 +871,14 @@ let tests_RenameAssay = testList "RenameAssay" [ open ARCtrl.Spreadsheet -let tests_RenameStudy = testList "RenameStudy" [ +let tests_GetStudyRenameContracts = testList "GetStudyRenameContracts" [ testCase "not existing" <| fun _ -> let i = ArcInvestigation("MyInvestigation") i.InitStudy("OtherStudyName") |> ignore let arc = ARC(isa = i) let studyMoveF = - fun () -> arc.RenameStudy("MyOldStudy","MyNewStudy") |> ignore + fun () -> arc.GetStudyRenameContracts("MyOldStudy","MyNewStudy") |> ignore Expect.throws studyMoveF "Should fail as arc does not contan study with given name" testCase "Basic" <| fun _ -> @@ -886,7 +886,7 @@ let tests_RenameStudy = testList "RenameStudy" [ i.InitStudy("MyOldStudy") |> ignore let arc = ARC(isa = i) arc.GetWriteContracts() |> ignore - let contracts = arc.RenameStudy("MyOldStudy","MyNewStudy") + let contracts = arc.GetStudyRenameContracts("MyOldStudy","MyNewStudy") Expect.hasLength contracts 2 "Contract count is wrong" // Rename contract let renameContract = contracts.[0] @@ -910,7 +910,7 @@ let tests_RenameStudy = testList "RenameStudy" [ i.RegisterStudy("MyOldStudy") |> ignore let arc = ARC(isa = i) arc.GetWriteContracts() |> ignore - let contracts = arc.RenameStudy("MyOldStudy","MyNewStudy") + let contracts = arc.GetStudyRenameContracts("MyOldStudy","MyNewStudy") Expect.hasLength contracts 3 "Contract count is wrong" // Rename contract let renameContract = contracts.[0] @@ -946,10 +946,10 @@ let tests_RenameStudy = testList "RenameStudy" [ let tests_load = testList "Load" [ - ftestCase "simpleARC" (fun () -> + testCase "simpleARC" (fun () -> let p = TestObjects.IO.testSimpleARC let result = ARC.load(p) - let result = Expect.wantOk result "ARC should load correctly" + let result = Expect.wantOk result "ARC should load successfully" Expect.isSome result.ISA "Should contain an ISA part" Expect.isNone result.CWL "Should not contain a CWL part" @@ -973,11 +973,11 @@ let tests_load = let tests_write = testList "Write" [ - ftestCase "empty" (fun () -> + testCase "empty" (fun () -> let p = ArcPathHelper.combine TestObjects.IO.testResultsFolder "ARC_Write_Empty" let a = ARC() - Expect.wantOk (a.Write(p)) "ARC should write correctly" + Expect.wantOk (a.Write(p)) "ARC should write successfully" |> ignore let expectedPaths = [ @@ -996,7 +996,7 @@ let tests_write = Expect.sequenceEqual paths expectedPaths "Files were not created correctly." ) - ftestCase "SimpleARC" (fun () -> + testCase "SimpleARC" (fun () -> let p = ArcPathHelper.combine TestObjects.IO.testResultsFolder "ARC_Write_SimpleARC" let arc = ARC() @@ -1009,7 +1009,7 @@ let tests_write = s.AddRegisteredAssay(a) arc.ISA <- Some i arc.UpdateFileSystem() - Expect.wantOk (arc.Write(p)) "ARC should write correctly" + Expect.wantOk (arc.Write(p)) "ARC should write successfully" |> ignore let expectedPaths = [ @@ -1037,7 +1037,7 @@ let tests_write = Expect.sequenceEqual paths expectedPaths "Files were not created correctly." ) // This test reads a preexisting assay with data and everything, data content is not copied though but just the - ftestCase "LoadSimpleARCAndAddAssay" (fun () -> + testCase "LoadSimpleARCAndAddAssay" (fun () -> let p = ArcPathHelper.combine TestObjects.IO.testResultsFolder "ARC_Write_SimpleARCWithAssay" let arc = Expect.wantOk (ARC.load(TestObjects.IO.testSimpleARC)) "ARC should load correctly" @@ -1051,7 +1051,7 @@ let tests_write = arc.ISA <- Some i arc.UpdateFileSystem() - Expect.wantOk (arc.Write(p)) "ARC should write correctly" + Expect.wantOk (arc.Write(p)) "ARC should write successfully" |> ignore let expectedPaths = [ @@ -1103,6 +1103,245 @@ let tests_write = |> testSequenced ] +let tests_Update = + testList "Update" [ + testCase "AddedAssay" (fun () -> + let p = ArcPathHelper.combine TestObjects.IO.testResultsFolder "ARC_Update_AddedAssay" + let arc = ARC() + + // setup arc + let i = ArcInvestigation("MyInvestigation") + let studyName = "MyStudy" + let s = ArcStudy(studyName) + i.AddRegisteredStudy(s) + let assayName = "MyAssay" + let a = ArcAssay(assayName) + s.AddRegisteredAssay(a) + arc.ISA <- Some i + arc.UpdateFileSystem() + Expect.wantOk (arc.Write(p)) "ARC should write successfully" |> ignore + + // add assay + let newAssayName = "MyNewAssay" + i.InitAssay(newAssayName) |> ignore + arc.ISA <- Some i + arc.UpdateFileSystem() + Expect.wantOk (arc.Update(p)) "ARC should update successfully" |> ignore + + let expectedPaths = + [ + "/isa.investigation.xlsx"; + "/studies/.gitkeep"; + $"/studies/{studyName}/isa.study.xlsx" + $"/studies/{studyName}/README.md" + $"/studies/{studyName}/protocols/.gitkeep"; + $"/studies/{studyName}/resources/.gitkeep"; + "/assays/.gitkeep"; + $"/assays/{assayName}/isa.assay.xlsx" + $"/assays/{assayName}/README.md" + $"/assays/{assayName}/protocols/.gitkeep" + $"/assays/{assayName}/dataset/.gitkeep" + $"/assays/{newAssayName}/isa.assay.xlsx" + $"/assays/{newAssayName}/README.md" + $"/assays/{newAssayName}/protocols/.gitkeep" + $"/assays/{newAssayName}/dataset/.gitkeep" + "/runs/.gitkeep"; + "/workflows/.gitkeep" + ] + |> List.sort + + let paths = + FileSystemHelper.getAllFilePaths p + |> Seq.sort + + Expect.sequenceEqual paths expectedPaths "Files were not created correctly." + ) + + + ] + +let tests_renameAssay = + testList "RenameAssay" [ + testCase "SimpleARC" (fun () -> + let p = ArcPathHelper.combine TestObjects.IO.testResultsFolder "ARC_RenameAssay_SimpleARC" + let arc = ARC() + + // setup arc + let i = ArcInvestigation("MyInvestigation") + let studyName = "MyStudy" + let s = ArcStudy(studyName) + i.AddRegisteredStudy(s) + let assayName = "MyAssay" + let a = ArcAssay(assayName) + s.AddRegisteredAssay(a) + arc.ISA <- Some i + arc.UpdateFileSystem() + Expect.wantOk (arc.Write(p)) "ARC should write successfully" |> ignore + + // rename assay + let newAssayName = "MyNewAssay" + Expect.wantOk (arc.RenameAssay(p,assayName, newAssayName)) "Assay should be renamed successfully" |> ignore + + let expectedPaths = + [ + "/isa.investigation.xlsx"; + "/studies/.gitkeep"; + $"/studies/{studyName}/isa.study.xlsx" + $"/studies/{studyName}/README.md" + $"/studies/{studyName}/protocols/.gitkeep"; + $"/studies/{studyName}/resources/.gitkeep"; + "/assays/.gitkeep"; + $"/assays/{newAssayName}/isa.assay.xlsx" + $"/assays/{newAssayName}/README.md" + $"/assays/{newAssayName}/protocols/.gitkeep" + $"/assays/{newAssayName}/dataset/.gitkeep" + "/runs/.gitkeep"; + "/workflows/.gitkeep" + ] + |> List.sort + + let paths = + FileSystemHelper.getAllFilePaths p + |> Seq.sort + + Expect.sequenceEqual paths expectedPaths "Files were not created correctly." + ) + ] + +let tests_RenameStudy = + testList "RenameStudy" [ + testCase "SimpleARC" (fun () -> + let p = ArcPathHelper.combine TestObjects.IO.testResultsFolder "ARC_RenameStudy_SimpleARC" + let arc = ARC() + + // setup arc + let i = ArcInvestigation("MyInvestigation") + let studyName = "MyStudy" + let s = ArcStudy(studyName) + i.AddRegisteredStudy(s) + let assayName = "MyAssay" + let a = ArcAssay(assayName) + s.AddRegisteredAssay(a) + arc.ISA <- Some i + arc.UpdateFileSystem() + Expect.wantOk (arc.Write(p)) "ARC should write successfully" |> ignore + + // rename study + let newStudyName = "MyNewStudy" + Expect.wantOk (arc.RenameStudy(p,studyName, newStudyName)) "Study should be renamed successfully" |> ignore + + let expectedPaths = + [ + "/isa.investigation.xlsx"; + "/studies/.gitkeep"; + $"/studies/{newStudyName}/isa.study.xlsx" + $"/studies/{newStudyName}/README.md" + $"/studies/{newStudyName}/protocols/.gitkeep"; + $"/studies/{newStudyName}/resources/.gitkeep"; + "/assays/.gitkeep"; + $"/assays/{assayName}/isa.assay.xlsx" + $"/assays/{assayName}/README.md" + $"/assays/{assayName}/protocols/.gitkeep" + $"/assays/{assayName}/dataset/.gitkeep" + "/runs/.gitkeep"; + "/workflows/.gitkeep" + ] + |> List.sort + + let paths = + FileSystemHelper.getAllFilePaths p + |> Seq.sort + + Expect.sequenceEqual paths expectedPaths "Files were not created correctly." + + ) + ] + +let tests_RemoveAssay = + testList "RemoveAssay" [ + testCase "SimpleARC" (fun () -> + let p = ArcPathHelper.combine TestObjects.IO.testResultsFolder "ARC_RemoveAssay_SimpleARC" + let arc = ARC() + + // setup arc + let i = ArcInvestigation("MyInvestigation") + let studyName = "MyStudy" + let s = ArcStudy(studyName) + i.AddRegisteredStudy(s) + let assayName = "MyAssay" + let a = ArcAssay(assayName) + s.AddRegisteredAssay(a) + arc.ISA <- Some i + arc.UpdateFileSystem() + Expect.wantOk (arc.Write(p)) "ARC should write successfully" |> ignore + + // remove assay + Expect.wantOk (arc.RemoveAssay(p,assayName)) "Assay should be removed successfully" |> ignore + + let expectedPaths = + [ + "/isa.investigation.xlsx"; + "/studies/.gitkeep"; + $"/studies/{studyName}/isa.study.xlsx" + $"/studies/{studyName}/README.md" + $"/studies/{studyName}/protocols/.gitkeep"; + $"/studies/{studyName}/resources/.gitkeep"; + "/assays/.gitkeep"; + "/runs/.gitkeep"; + "/workflows/.gitkeep" + ] + |> List.sort + + let paths = + FileSystemHelper.getAllFilePaths p + |> Seq.sort + + Expect.sequenceEqual paths expectedPaths "Files were not created correctly." + ) + ] + +let tests_RemoveStudy = + testList "RemoveStudy" [ + testCase "SimpleARC" (fun () -> + let p = ArcPathHelper.combine TestObjects.IO.testResultsFolder "ARC_RemoveStudy_SimpleARC" + let arc = ARC() + + // setup arc + let i = ArcInvestigation("MyInvestigation") + let studyName = "MyStudy" + let s = ArcStudy(studyName) + i.AddRegisteredStudy(s) + let assayName = "MyAssay" + let a = ArcAssay(assayName) + s.AddRegisteredAssay(a) + arc.ISA <- Some i + arc.UpdateFileSystem() + Expect.wantOk (arc.Write(p)) "ARC should write successfully" |> ignore + + // remove study + Expect.wantOk (arc.RemoveStudy(p,studyName)) "Study should be removed successfully" |> ignore + + let expectedPaths = + [ + "/isa.investigation.xlsx"; + "/studies/.gitkeep"; + "/assays/.gitkeep"; + $"/assays/{assayName}/isa.assay.xlsx" + $"/assays/{assayName}/README.md" + $"/assays/{assayName}/protocols/.gitkeep" + $"/assays/{assayName}/dataset/.gitkeep" + "/runs/.gitkeep"; + "/workflows/.gitkeep" + ] + |> List.sort + + let paths = + FileSystemHelper.getAllFilePaths p + |> Seq.sort + + Expect.sequenceEqual paths expectedPaths "Files were not created correctly." + ) + ] @@ -1113,12 +1352,17 @@ let main = testList "ARCtrl" [ tests_read_contracts tests_writeContracts tests_updateContracts - tests_RemoveAssay - tests_RenameAssay - tests_RenameStudy + tests_GetAssayRemoveContracts + tests_GetAssayRenameContracts + tests_GetStudyRenameContracts payload_file_filters tests_load tests_write + tests_Update + tests_renameAssay + tests_RenameStudy + tests_RemoveAssay + tests_RemoveStudy ] diff --git a/tests/ARCtrl/ContractIO.Tests.fs b/tests/ARCtrl/ContractIO.Tests.fs index 12bb3ad3..b1c58c45 100644 --- a/tests/ARCtrl/ContractIO.Tests.fs +++ b/tests/ARCtrl/ContractIO.Tests.fs @@ -9,7 +9,7 @@ open FsSpreadsheet.Net let testRead = testList "Read" [ - ftestCase "TextFile" (fun () -> + testCase "TextFile" (fun () -> let fileName = "TestReadMe.txt" let contract = Contract.createRead(fileName,DTOType.PlainText) let dto = DTO.Text "This is a test" @@ -19,7 +19,7 @@ let testRead = let resultContract = Expect.wantOk result "Contract was not fulfilled correctly" Expect.equal resultContract expected $"Text was not read correctly" ) - ftestCase "XLSXFile" (fun () -> + testCase "XLSXFile" (fun () -> let fileName = "TestWorkbook.xlsx" let contract = Contract.createRead(fileName,DTOType.ISA_Study) let result = fulfillReadContract TestObjects.IO.testContractsFolder contract @@ -42,7 +42,7 @@ let testRead = let testWrite = testList "Write" [ - ftestCase "TextFileEmpty" (fun () -> + testCase "TextFileEmpty" (fun () -> let fileName = "TestEmpty.txt" let contract = Contract.createCreate(fileName,DTOType.PlainText) @@ -54,7 +54,7 @@ let testWrite = Expect.isTrue (System.IO.File.Exists filePath) $"File {filePath} was not created" Expect.equal (FileSystemHelper.readFileText filePath) "" $"File {filePath} was not empty" ) - ftestCase "TextFile" (fun () -> + testCase "TextFile" (fun () -> let testText = "This is a test" let fileName = "TestReadMe.txt" @@ -69,7 +69,7 @@ let testWrite = Expect.isTrue (System.IO.File.Exists filePath) $"File {filePath} was not created" Expect.equal (FileSystemHelper.readFileText filePath) testText $"File {filePath} was not empty" ) - ftestCase "XLSXFile" (fun () -> + testCase "XLSXFile" (fun () -> let worksheetName = "TestSheet" let testWB = new FsWorkbook() diff --git a/tests/ARCtrl/FileSystemHelper.Tests.fs b/tests/ARCtrl/FileSystemHelper.Tests.fs index d8678c5c..8ca90ac7 100644 --- a/tests/ARCtrl/FileSystemHelper.Tests.fs +++ b/tests/ARCtrl/FileSystemHelper.Tests.fs @@ -7,7 +7,7 @@ open System.Text.Json let readFileText = testList "ReadText" [ - ftestCase "simple" (fun () -> + testCase "simple" (fun () -> let p = TestObjects.IO.simpleTextFilePath let result = FileSystemHelper.readFileText p let expected = "Hello" @@ -17,7 +17,7 @@ let readFileText = let writeFileText = testList "WriteText" [ - ftestCase "simple" (fun () -> + testCase "simple" (fun () -> ARCtrl.FileSystemHelper.ensureDirectory TestObjects.IO.testResultsFolder let p = ArcPathHelper.combine TestObjects.IO.testResultsFolder "SimpleText.txt" let t = "Hello" @@ -27,7 +27,7 @@ let writeFileText = let expected = "Hello" Expect.equal result expected "Text was not read correctly." ) - ftestCase "SubDirectoryWithEnsureDir" (fun () -> + testCase "SubDirectoryWithEnsureDir" (fun () -> let subDir = ArcPathHelper.combine TestObjects.IO.testResultsFolder "SubFolder" let p = ArcPathHelper.combine subDir "SimpleText.txt" let t = "Hello" From 1d1558ec6464989a8cdd872135a23aaccef50711 Mon Sep 17 00:00:00 2001 From: Heinrich Lukas Weil Date: Fri, 1 Nov 2024 22:37:02 +0100 Subject: [PATCH 11/30] start working on async arcIO --- Directory.Packages.props | 1 + src/ARCtrl/ARCtrl.Javascript.fsproj | 15 ++-- src/ARCtrl/ARCtrl.Python.fsproj | 5 +- src/ARCtrl/ARCtrl.fsproj | 3 +- src/ARCtrl/ContractIO/ContractIO.fs | 66 +++++++++------- src/ARCtrl/ContractIO/FileSystemHelper.fs | 2 - src/ARCtrl/ContractIO/FileSystemHelper.js.fs | 80 ++++++++++++++++++++ src/ARCtrl/ContractIO/FileSystemHelper.py.fs | 80 ++++++++++++++++++++ src/ARCtrl/CrossAsync.fs | 25 ++++++ src/ARCtrl/WebRequest/WebRequest.Node.fs | 2 - tests/TestingUtils/TestObjects.IO.fs | 6 ++ 11 files changed, 245 insertions(+), 40 deletions(-) create mode 100644 src/ARCtrl/ContractIO/FileSystemHelper.js.fs create mode 100644 src/ARCtrl/ContractIO/FileSystemHelper.py.fs create mode 100644 src/ARCtrl/CrossAsync.fs diff --git a/Directory.Packages.props b/Directory.Packages.props index 86a64c52..8a405628 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -19,6 +19,7 @@ + diff --git a/src/ARCtrl/ARCtrl.Javascript.fsproj b/src/ARCtrl/ARCtrl.Javascript.fsproj index 9a197d64..4e464de5 100644 --- a/src/ARCtrl/ARCtrl.Javascript.fsproj +++ b/src/ARCtrl/ARCtrl.Javascript.fsproj @@ -9,6 +9,8 @@ + + @@ -51,8 +53,9 @@ - - + + + @@ -61,9 +64,11 @@ - - - + + + + + diff --git a/src/ARCtrl/ARCtrl.Python.fsproj b/src/ARCtrl/ARCtrl.Python.fsproj index 72204129..58d07b35 100644 --- a/src/ARCtrl/ARCtrl.Python.fsproj +++ b/src/ARCtrl/ARCtrl.Python.fsproj @@ -9,6 +9,7 @@ + @@ -52,7 +53,9 @@ - + + + diff --git a/src/ARCtrl/ARCtrl.fsproj b/src/ARCtrl/ARCtrl.fsproj index 3595042c..5bf53f9f 100644 --- a/src/ARCtrl/ARCtrl.fsproj +++ b/src/ARCtrl/ARCtrl.fsproj @@ -51,7 +51,8 @@ - + + diff --git a/src/ARCtrl/ContractIO/ContractIO.fs b/src/ARCtrl/ContractIO/ContractIO.fs index a3f5fd6e..f7520758 100644 --- a/src/ARCtrl/ContractIO/ContractIO.fs +++ b/src/ARCtrl/ContractIO/ContractIO.fs @@ -4,37 +4,45 @@ open ARCtrl open ARCtrl.Contract open FsSpreadsheet -let fulfillReadContract basePath (c : Contract) = - try - match c.DTOType with - | Some DTOType.ISA_Assay - | Some DTOType.ISA_Investigation - | Some DTOType.ISA_Study - | Some DTOType.ISA_Datamap -> - let path = ArcPathHelper.combine basePath c.Path - let wb = FileSystemHelper.readFileXlsx path |> box |> DTO.Spreadsheet - Ok {c with DTO = Some wb} - | Some DTOType.PlainText -> - let path = ArcPathHelper.combine basePath c.Path - let text = FileSystemHelper.readFileText path |> DTO.Text - Ok {c with DTO = Some text} - | _ -> - Error (sprintf "Contract %s is not an ISA contract" c.Path) - with - | e -> Error (sprintf "Error reading contract %s: %s" c.Path e.Message) +let fulfillReadContract basePath (c : Async) = + async { + let! c = c + try + match c.DTOType with + | Some DTOType.ISA_Assay + | Some DTOType.ISA_Investigation + | Some DTOType.ISA_Study + | Some DTOType.ISA_Datamap -> + let path = ArcPathHelper.combine basePath c.Path + let wb = FileSystemHelper.readFileXlsx path |> box |> DTO.Spreadsheet + return Ok {c with DTO = Some wb} + | Some DTOType.PlainText -> + let path = ArcPathHelper.combine basePath c.Path + let text = FileSystemHelper.readFileText path |> DTO.Text + return Ok {c with DTO = Some text} + | _ -> + return Error (sprintf "Contract %s is not an ISA contract" c.Path) + with + | e -> return Error (sprintf "Error reading contract %s: %s" c.Path e.Message) + } -let fullfillContractBatchBy contractF basePath (cs : Contract []) : Result= - cs - |> Array.map (contractF basePath) - |> Array.fold (fun acc cr -> - match acc, cr with - | Ok acc, Ok cr -> Ok (Array.append acc [|cr|]) - | Error e, Ok _ -> Error e - | Error acc, Error e -> Error (Array.append acc [|e|]) - | Ok _, Error e -> Error [|e|] - ) (Ok [||]) +let fullfillContractBatchBy contractF basePath (cs : (Async) []) : Async> = + async { + let! cs = Async.Sequential cs + let res = + cs + |> Array.map (contractF basePath) + |> Array.fold (fun acc cr -> + match acc, cr with + | Ok acc, Ok cr -> Ok (Array.append acc [|cr|]) + | Error e, Ok _ -> Error e + | Error acc, Error e -> Error (Array.append acc [|e|]) + | Ok _, Error e -> Error [|e|] + ) (Ok [||]) + return res + } -let fulfillWriteContract basePath (c : Contract) = +let fulfillWriteContract basePath (c : Async) = try match c.DTO with | Some (DTO.Spreadsheet wb) -> diff --git a/src/ARCtrl/ContractIO/FileSystemHelper.fs b/src/ARCtrl/ContractIO/FileSystemHelper.fs index e86367e2..ccb1c7c7 100644 --- a/src/ARCtrl/ContractIO/FileSystemHelper.fs +++ b/src/ARCtrl/ContractIO/FileSystemHelper.fs @@ -2,9 +2,7 @@ module ARCtrl.FileSystemHelper open FsSpreadsheet -#if !FABLE_COMPILER open FsSpreadsheet.Net -#endif let directoryExists path = System.IO.Directory.Exists path diff --git a/src/ARCtrl/ContractIO/FileSystemHelper.js.fs b/src/ARCtrl/ContractIO/FileSystemHelper.js.fs new file mode 100644 index 00000000..fe63bba9 --- /dev/null +++ b/src/ARCtrl/ContractIO/FileSystemHelper.js.fs @@ -0,0 +1,80 @@ +module ARCtrl.FileSystemHelper + +open FsSpreadsheet + +open FsSpreadsheet.Js + +let directoryExists path = + System.IO.Directory.Exists path + +let createDirectory path = + System.IO.Directory.CreateDirectory path |> ignore + +let ensureDirectory path = + if not <| directoryExists path then + createDirectory path + +let ensureDirectoryOfFile (filePath : string) = + let file = new System.IO.FileInfo(filePath); + file.Directory.Create() + +let fileExists path = + System.IO.File.Exists path + +let getSubDirectories path = + System.IO.Directory.GetDirectories path + +let getSubFiles path = + System.IO.Directory.GetFiles path + +/// Return the absolute path relative to the directoryPath +let makeRelative directoryPath (path : string) = + if directoryPath = "." || directoryPath = "/" || directoryPath = "" then path + else + if path.StartsWith(directoryPath) then + path.Substring(directoryPath.Length) + else path + +let standardizeSlashes (path : string) = + path.Replace("\\","/") + +let getAllFilePaths (directoryPath : string) = + let rec allFiles dirs = + if Seq.isEmpty dirs then Seq.empty else + seq { yield! dirs |> Seq.collect getSubFiles + yield! dirs |> Seq.collect getSubDirectories |> allFiles } + + allFiles [directoryPath] |> Seq.toArray + |> Array.map (makeRelative directoryPath >> standardizeSlashes) + +let readFileText path : string = + System.IO.File.ReadAllText path + +let readFileBinary path : byte [] = + System.IO.File.ReadAllBytes path + +let readFileXlsx path : FsWorkbook = + FsWorkbook.fromXlsxFile path + +let renameFileOrDirectory oldPath newPath = + if fileExists oldPath then + System.IO.File.Move(oldPath, newPath) + elif directoryExists oldPath then + System.IO.Directory.Move(oldPath, newPath) + else () + +let writeFileText path text = + System.IO.File.WriteAllText(path, text) + +let writeFileBinary path (bytes : byte []) = + System.IO.File.WriteAllBytes(path,bytes) + +let writeFileXlsx path (wb : FsWorkbook) = + FsWorkbook.toXlsxFile path wb + +let deleteFileOrDirectory path = + if fileExists path then + System.IO.File.Delete path + elif directoryExists path then + System.IO.Directory.Delete(path, true) + else () \ No newline at end of file diff --git a/src/ARCtrl/ContractIO/FileSystemHelper.py.fs b/src/ARCtrl/ContractIO/FileSystemHelper.py.fs new file mode 100644 index 00000000..ccb1c7c7 --- /dev/null +++ b/src/ARCtrl/ContractIO/FileSystemHelper.py.fs @@ -0,0 +1,80 @@ +module ARCtrl.FileSystemHelper + +open FsSpreadsheet + +open FsSpreadsheet.Net + +let directoryExists path = + System.IO.Directory.Exists path + +let createDirectory path = + System.IO.Directory.CreateDirectory path |> ignore + +let ensureDirectory path = + if not <| directoryExists path then + createDirectory path + +let ensureDirectoryOfFile (filePath : string) = + let file = new System.IO.FileInfo(filePath); + file.Directory.Create() + +let fileExists path = + System.IO.File.Exists path + +let getSubDirectories path = + System.IO.Directory.GetDirectories path + +let getSubFiles path = + System.IO.Directory.GetFiles path + +/// Return the absolute path relative to the directoryPath +let makeRelative directoryPath (path : string) = + if directoryPath = "." || directoryPath = "/" || directoryPath = "" then path + else + if path.StartsWith(directoryPath) then + path.Substring(directoryPath.Length) + else path + +let standardizeSlashes (path : string) = + path.Replace("\\","/") + +let getAllFilePaths (directoryPath : string) = + let rec allFiles dirs = + if Seq.isEmpty dirs then Seq.empty else + seq { yield! dirs |> Seq.collect getSubFiles + yield! dirs |> Seq.collect getSubDirectories |> allFiles } + + allFiles [directoryPath] |> Seq.toArray + |> Array.map (makeRelative directoryPath >> standardizeSlashes) + +let readFileText path : string = + System.IO.File.ReadAllText path + +let readFileBinary path : byte [] = + System.IO.File.ReadAllBytes path + +let readFileXlsx path : FsWorkbook = + FsWorkbook.fromXlsxFile path + +let renameFileOrDirectory oldPath newPath = + if fileExists oldPath then + System.IO.File.Move(oldPath, newPath) + elif directoryExists oldPath then + System.IO.Directory.Move(oldPath, newPath) + else () + +let writeFileText path text = + System.IO.File.WriteAllText(path, text) + +let writeFileBinary path (bytes : byte []) = + System.IO.File.WriteAllBytes(path,bytes) + +let writeFileXlsx path (wb : FsWorkbook) = + FsWorkbook.toXlsxFile path wb + +let deleteFileOrDirectory path = + if fileExists path then + System.IO.File.Delete path + elif directoryExists path then + System.IO.Directory.Delete(path, true) + else () \ No newline at end of file diff --git a/src/ARCtrl/CrossAsync.fs b/src/ARCtrl/CrossAsync.fs new file mode 100644 index 00000000..7cc55c3b --- /dev/null +++ b/src/ARCtrl/CrossAsync.fs @@ -0,0 +1,25 @@ +module ARCtrl.CrossAsync + +open Fable.Core + +// We need the `<'T>` here as it allows to mark the function/variable inline for better output. +let inline crossAsync<'T> = +#if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT + promise +#else + async +#endif + +type CrossAsync<'T> = +#if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT + JS.Promise<'T> +#else + Async<'T> +#endif + +let sequential = + #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT + Promise.all + #else + Async.Sequential + #endif diff --git a/src/ARCtrl/WebRequest/WebRequest.Node.fs b/src/ARCtrl/WebRequest/WebRequest.Node.fs index 6886c2eb..09d1d86d 100644 --- a/src/ARCtrl/WebRequest/WebRequest.Node.fs +++ b/src/ARCtrl/WebRequest/WebRequest.Node.fs @@ -1,6 +1,5 @@ module ARCtrl.WebRequestHelpers.NodeJs -#if FABLE_COMPILER_JAVASCRIPT open Fable.Core open Fable.SimpleHttp @@ -28,4 +27,3 @@ let downloadFile url = txt ) |> Async.AwaitPromise -#endif \ No newline at end of file diff --git a/tests/TestingUtils/TestObjects.IO.fs b/tests/TestingUtils/TestObjects.IO.fs index fdc846a8..28544d91 100644 --- a/tests/TestingUtils/TestObjects.IO.fs +++ b/tests/TestingUtils/TestObjects.IO.fs @@ -8,6 +8,12 @@ let testResultsFolder = #if !FABLE_COMPILER combineMany [| __SOURCE_DIRECTORY__;"TestResults";"NET"|] #endif + #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT + combineMany [| __SOURCE_DIRECTORY__;"TestResults";"js"|] + #endif + #if FABLE_COMPILER_PYTHON + combineMany [| __SOURCE_DIRECTORY__;"TestResults";"py"|] + #endif let testContractsFolder = combine testObjectsBaseFolder "Contracts" From eb10eaab35398c3f8f95716b3113283c98ab31b3 Mon Sep 17 00:00:00 2001 From: HLWeil Date: Mon, 18 Nov 2024 17:54:53 +0100 Subject: [PATCH 12/30] continue working on async IO --- src/ARCtrl/ContractIO/ContractIO.fs | 191 ++++++++++++++++------------ 1 file changed, 109 insertions(+), 82 deletions(-) diff --git a/src/ARCtrl/ContractIO/ContractIO.fs b/src/ARCtrl/ContractIO/ContractIO.fs index f7520758..492131cf 100644 --- a/src/ARCtrl/ContractIO/ContractIO.fs +++ b/src/ARCtrl/ContractIO/ContractIO.fs @@ -26,93 +26,120 @@ let fulfillReadContract basePath (c : Async) = | e -> return Error (sprintf "Error reading contract %s: %s" c.Path e.Message) } -let fullfillContractBatchBy contractF basePath (cs : (Async) []) : Async> = - async { - let! cs = Async.Sequential cs - let res = - cs - |> Array.map (contractF basePath) - |> Array.fold (fun acc cr -> - match acc, cr with - | Ok acc, Ok cr -> Ok (Array.append acc [|cr|]) - | Error e, Ok _ -> Error e - | Error acc, Error e -> Error (Array.append acc [|e|]) - | Ok _, Error e -> Error [|e|] - ) (Ok [||]) - return res - } +let fullfillContractBatchBy + (contractF : string -> Async -> Async>) + (basePath : string) + (cs : (Async) []) + : Async> = + async { + let! seq = + cs + |> Array.map (contractF basePath) + |> CrossAsync.sequential + let res = + seq + |> Array.fold (fun acc cr -> + match acc, cr with + | Ok acc, Ok cr -> Ok (Array.append acc [|cr|]) + | Error e, Ok _ -> Error e + | Error acc, Error e -> Error (Array.append acc [|e|]) + | Ok _, Error e -> Error [|e|] + + ) (Ok [||]) + return res + } let fulfillWriteContract basePath (c : Async) = - try - match c.DTO with - | Some (DTO.Spreadsheet wb) -> - let path = ArcPathHelper.combine basePath c.Path - FileSystemHelper.ensureDirectoryOfFile path - FileSystemHelper.writeFileXlsx path (wb :?> FsWorkbook) - Ok (c) - | Some (DTO.Text t) -> - let path = ArcPathHelper.combine basePath c.Path - FileSystemHelper.ensureDirectoryOfFile path - FileSystemHelper.writeFileText path t - Ok (c) - | None -> - let path = ArcPathHelper.combine basePath c.Path - FileSystemHelper.ensureDirectoryOfFile path - FileSystemHelper.writeFileText path "" - Ok (c) - | _ -> - Error (sprintf "Contract %s is not an ISA contract" c.Path) - with - | e -> Error (sprintf "Error writing contract %s: %s" c.Path e.Message) + async { + let! c = c + try + match c.DTO with + | Some (DTO.Spreadsheet wb) -> + let path = ArcPathHelper.combine basePath c.Path + FileSystemHelper.ensureDirectoryOfFile path + FileSystemHelper.writeFileXlsx path (wb :?> FsWorkbook) + return Ok (c) + | Some (DTO.Text t) -> + let path = ArcPathHelper.combine basePath c.Path + FileSystemHelper.ensureDirectoryOfFile path + FileSystemHelper.writeFileText path t + return Ok (c) + | None -> + let path = ArcPathHelper.combine basePath c.Path + FileSystemHelper.ensureDirectoryOfFile path + FileSystemHelper.writeFileText path "" + return Ok (c) + | _ -> + return Error (sprintf "Contract %s is not an ISA contract" c.Path) + with + | e -> return Error (sprintf "Error writing contract %s: %s" c.Path e.Message) + } -let fulfillUpdateContract basePath (c : Contract) = - try - match c.DTO with - | Some (DTO.Spreadsheet wb) -> - let path = ArcPathHelper.combine basePath c.Path - FileSystemHelper.ensureDirectoryOfFile path - FileSystemHelper.writeFileXlsx path (wb :?> FsWorkbook) - Ok (c) - | Some (DTO.Text t) -> - let path = ArcPathHelper.combine basePath c.Path - FileSystemHelper.ensureDirectoryOfFile path - FileSystemHelper.writeFileText path t - Ok (c) - | None -> - let path = ArcPathHelper.combine basePath c.Path - FileSystemHelper.ensureDirectoryOfFile path - FileSystemHelper.writeFileText path "" - Ok (c) - | _ -> - Error (sprintf "Contract %s is not an ISA contract" c.Path) - with - | e -> Error (sprintf "Error updating contract %s: %s" c.Path e.Message) +let fulfillUpdateContract basePath (c : Async) = + async { + let! c = c + try + match c.DTO with + | Some (DTO.Spreadsheet wb) -> + let path = ArcPathHelper.combine basePath c.Path + FileSystemHelper.ensureDirectoryOfFile path + FileSystemHelper.writeFileXlsx path (wb :?> FsWorkbook) + return Ok (c) + | Some (DTO.Text t) -> + let path = ArcPathHelper.combine basePath c.Path + FileSystemHelper.ensureDirectoryOfFile path + FileSystemHelper.writeFileText path t + return Ok (c) + | None -> + let path = ArcPathHelper.combine basePath c.Path + FileSystemHelper.ensureDirectoryOfFile path + FileSystemHelper.writeFileText path "" + return Ok (c) + | _ -> + return Error (sprintf "Contract %s is not an ISA contract" c.Path) + with + | e -> return Error (sprintf "Error updating contract %s: %s" c.Path e.Message) + } -let fullfillRenameContract basePath (c : Contract) = - match c.DTO with - | Some (DTO.Text t) when t = c.Path -> - Error (sprintf "Rename Contract %s old and new Path are the same" c.Path) - | Some (DTO.Text t) -> - let newPath = ArcPathHelper.combine basePath t - let oldPath = ArcPathHelper.combine basePath c.Path - FileSystemHelper.renameFileOrDirectory oldPath newPath - Ok (c) - | _ -> Error (sprintf "Rename Contract %s does not contain new Path" c.Path) - +let fullfillRenameContract basePath (c : Async) = + async { + let! c = c + try + match c.DTO with + | Some (DTO.Text t) when t = c.Path -> + return Error (sprintf "Rename Contract %s old and new Path are the same" c.Path) + | Some (DTO.Text t) -> + let newPath = ArcPathHelper.combine basePath t + let oldPath = ArcPathHelper.combine basePath c.Path + FileSystemHelper.renameFileOrDirectory oldPath newPath + return Ok (c) + | _ -> return Error (sprintf "Rename Contract %s does not contain new Path" c.Path) + with + | e -> return Error (sprintf "Error renaming contract %s: %s" c.Path e.Message) + } -let fullfillDeleteContract basePath (c : Contract) = - let path = ArcPathHelper.combine basePath c.Path - FileSystemHelper.deleteFileOrDirectory path - Ok (c) +let fullfillDeleteContract basePath (c : Async) = + async { + let! c = c + try + let path = ArcPathHelper.combine basePath c.Path + FileSystemHelper.deleteFileOrDirectory path + return Ok (c) + with + | e -> return Error (sprintf "Error deleting contract %s: %s" c.Path e.Message) + } -let fullFillContract basePath (c : Contract) = - match c.Operation with - | Operation.READ -> fulfillReadContract basePath c - | Operation.CREATE -> fulfillWriteContract basePath c - | Operation.UPDATE -> fulfillUpdateContract basePath c - | Operation.DELETE -> fullfillDeleteContract basePath c - | Operation.RENAME -> fullfillRenameContract basePath c - | _ -> Error (sprintf "Operation %A not supported" c.Operation) +let fullFillContract basePath (c : Async) = + async { + let! cSync = c + match cSync.Operation with + | Operation.READ -> return! fulfillReadContract basePath c + | Operation.CREATE -> return! fulfillWriteContract basePath c + | Operation.UPDATE -> return! fulfillUpdateContract basePath c + | Operation.DELETE -> return! fullfillDeleteContract basePath c + | Operation.RENAME -> return! fullfillRenameContract basePath c + | _ -> return Error (sprintf "Operation %A not supported" cSync.Operation) + } -let fullFillContractBatch basePath (cs : Contract []) = +let fullFillContractBatch basePath (cs : (Async) []) = fullfillContractBatchBy fullFillContract basePath cs \ No newline at end of file From a4a991a6da568adcd837f4fba4965ef442f0f588 Mon Sep 17 00:00:00 2001 From: HLWeil Date: Wed, 20 Nov 2024 18:21:46 +0100 Subject: [PATCH 13/30] switch all file system access to async/promise functionality --- src/ARCtrl/ARC.fs | 59 +++--- src/ARCtrl/ContractIO/ContractIO.fs | 98 +++++----- src/ARCtrl/ContractIO/FileSystemHelper.fs | 182 +++++++++++------- src/ARCtrl/CrossAsync.fs | 6 + src/ARCtrl/Template.Web.fs | 6 +- tests/ARCtrl/ARCtrl.Tests.fs | 151 +++++++++------ tests/ARCtrl/ContractIO.Tests.fs | 54 +++--- tests/ARCtrl/FileSystemHelper.Tests.fs | 36 ++-- tests/ARCtrl/Template.Tests.fs | 6 +- tests/Json/Validation/JsonSchemaValidation.fs | 2 +- 10 files changed, 357 insertions(+), 243 deletions(-) diff --git a/src/ARCtrl/ARC.fs b/src/ARCtrl/ARC.fs index 57e4b104..80d0a7ff 100644 --- a/src/ARCtrl/ARC.fs +++ b/src/ARCtrl/ARC.fs @@ -9,6 +9,7 @@ open ARCtrl.Spreadsheet open FsSpreadsheet open Fable.Core open ARCtrl.ArcPathHelper +open CrossAsync module ARCAux = @@ -88,29 +89,36 @@ type ARC(?isa : ArcInvestigation, ?cwl : unit, ?fs : FileSystem.FileSystem) = with get() = _fs and set(fs) = _fs <- fs - member this.Write(arcPath) = + member this.WriteAsync(arcPath) = this.GetWriteContracts() - |> fullFillContractBatch arcPath + |> fullFillContractBatchAsync arcPath - member this.Update(arcPath) = + member this.UpdateAsync(arcPath) = this.GetUpdateContracts() - |> fullFillContractBatch arcPath + |> fullFillContractBatchAsync arcPath - static member load (arcPath : string) = - let paths = FileSystemHelper.getAllFilePaths arcPath - let arc = ARC.fromFilePaths (paths |> Seq.toArray) + static member loadAsync (arcPath : string) = + crossAsync { - let contracts = arc.GetReadContracts() + let! paths = FileSystemHelper.getAllFilePathsAsync arcPath + let arc = ARC.fromFilePaths (paths |> Seq.toArray) - let fulFilledContracts = - contracts - |> fullFillContractBatch arcPath + let contracts = arc.GetReadContracts() + + + + let! fulFilledContracts = + contracts + |> fullFillContractBatchAsync arcPath - match fulFilledContracts with - | Ok c -> - arc.SetISAFromContracts(c) - Ok arc - | Error e -> Error e + match fulFilledContracts with + | Ok c -> + arc.SetISAFromContracts(c) + return Ok arc + | Error e -> return Error e + } + + member this.GetAssayRemoveContracts(assayIdentifier: string) = let isa = @@ -132,9 +140,9 @@ type ARC(?isa : ArcInvestigation, ?cwl : unit, ?fs : FileSystem.FileSystem) = s.ToUpdateContract() |] - member this.RemoveAssay(arcPath : string, assayIdentifier: string) = + member this.RemoveAssayAsync(arcPath : string, assayIdentifier: string) = this.GetAssayRemoveContracts(assayIdentifier) - |> fullFillContractBatch arcPath + |> fullFillContractBatchAsync arcPath member this.GetAssayRenameContracts(oldAssayIdentifier: string, newAssayIdentifier: string) = let isa = @@ -154,9 +162,9 @@ type ARC(?isa : ArcInvestigation, ?cwl : unit, ?fs : FileSystem.FileSystem) = yield! this.GetUpdateContracts() |] - member this.RenameAssay(arcPath : string, oldAssayIdentifier: string, newAssayIdentifier: string) = + member this.RenameAssayAsync(arcPath : string, oldAssayIdentifier: string, newAssayIdentifier: string) = this.GetAssayRenameContracts(oldAssayIdentifier,newAssayIdentifier) - |> fullFillContractBatch arcPath + |> fullFillContractBatchAsync arcPath member this.GetStudyRemoveContracts(studyIdentifier: string) = let isa = @@ -173,9 +181,9 @@ type ARC(?isa : ArcInvestigation, ?cwl : unit, ?fs : FileSystem.FileSystem) = isa.ToUpdateContract() |] - member this.RemoveStudy(arcPath : string, studyIdentifier: string) = + member this.RemoveStudyAsync(arcPath : string, studyIdentifier: string) = this.GetStudyRemoveContracts(studyIdentifier) - |> fullFillContractBatch arcPath + |> fullFillContractBatchAsync arcPath member this.GetStudyRenameContracts(oldStudyIdentifier: string, newStudyIdentifier: string) = let isa = @@ -195,9 +203,9 @@ type ARC(?isa : ArcInvestigation, ?cwl : unit, ?fs : FileSystem.FileSystem) = yield! this.GetUpdateContracts() |] - member this.RenameStudy(arcPath : string, oldStudyIdentifier: string, newStudyIdentifier: string) = + member this.RenameStudyAsync(arcPath : string, oldStudyIdentifier: string, newStudyIdentifier: string) = this.GetStudyRenameContracts(oldStudyIdentifier,newStudyIdentifier) - |> fullFillContractBatch arcPath + |> fullFillContractBatchAsync arcPath //static member updateISA (isa : ISA.Investigation) (arc : ARC) : ARC = // raise (System.NotImplementedException()) @@ -281,7 +289,8 @@ type ARC(?isa : ArcInvestigation, ?cwl : unit, ?fs : FileSystem.FileSystem) = // to-do: function that returns read contracts based on a list of paths. member this.GetReadContracts () : Contract [] = - _fs.Tree.ToFilePaths() |> Array.choose Contract.ARC.tryISAReadContractFromPath + _fs.Tree.ToFilePaths() + |> Array.choose Contract.ARC.tryISAReadContractFromPath /// /// This function creates the ARC-model from fullfilled READ contracts. The necessary READ contracts can be created with `ARC.getReadContracts`. diff --git a/src/ARCtrl/ContractIO/ContractIO.fs b/src/ARCtrl/ContractIO/ContractIO.fs index 492131cf..9c871c23 100644 --- a/src/ARCtrl/ContractIO/ContractIO.fs +++ b/src/ARCtrl/ContractIO/ContractIO.fs @@ -3,10 +3,11 @@ module ARCtrl.Contract open ARCtrl open ARCtrl.Contract open FsSpreadsheet +open CrossAsync -let fulfillReadContract basePath (c : Async) = - async { - let! c = c + +let fulfillReadContractAsync basePath (c : Contract) = + crossAsync { try match c.DTOType with | Some DTOType.ISA_Assay @@ -14,24 +15,26 @@ let fulfillReadContract basePath (c : Async) = | Some DTOType.ISA_Study | Some DTOType.ISA_Datamap -> let path = ArcPathHelper.combine basePath c.Path - let wb = FileSystemHelper.readFileXlsx path |> box |> DTO.Spreadsheet - return Ok {c with DTO = Some wb} + let! wb = FileSystemHelper.readFileXlsxAsync path + let dto = wb |> box |> DTO.Spreadsheet + return Ok {c with DTO = Some dto} | Some DTOType.PlainText -> let path = ArcPathHelper.combine basePath c.Path - let text = FileSystemHelper.readFileText path |> DTO.Text - return Ok {c with DTO = Some text} + let! text = FileSystemHelper.readFileTextAsync path + let dto = text |> DTO.Text + return Ok {c with DTO = Some dto} | _ -> return Error (sprintf "Contract %s is not an ISA contract" c.Path) with | e -> return Error (sprintf "Error reading contract %s: %s" c.Path e.Message) } -let fullfillContractBatchBy - (contractF : string -> Async -> Async>) +let fullfillContractBatchAsyncBy + (contractF : string -> Contract -> CrossAsync>) (basePath : string) - (cs : (Async) []) - : Async> = - async { + (cs : (Contract) []) + : CrossAsync> = + crossAsync { let! seq = cs |> Array.map (contractF basePath) @@ -49,25 +52,24 @@ let fullfillContractBatchBy return res } -let fulfillWriteContract basePath (c : Async) = - async { - let! c = c +let fulfillWriteContractAsync basePath (c : Contract) = + crossAsync { try match c.DTO with | Some (DTO.Spreadsheet wb) -> let path = ArcPathHelper.combine basePath c.Path - FileSystemHelper.ensureDirectoryOfFile path - FileSystemHelper.writeFileXlsx path (wb :?> FsWorkbook) + do! FileSystemHelper.ensureDirectoryOfFileAsync path + do! FileSystemHelper.writeFileXlsxAsync path (wb :?> FsWorkbook) return Ok (c) | Some (DTO.Text t) -> let path = ArcPathHelper.combine basePath c.Path - FileSystemHelper.ensureDirectoryOfFile path - FileSystemHelper.writeFileText path t + do! FileSystemHelper.ensureDirectoryOfFileAsync path + do! FileSystemHelper.writeFileTextAsync path t return Ok (c) | None -> let path = ArcPathHelper.combine basePath c.Path - FileSystemHelper.ensureDirectoryOfFile path - FileSystemHelper.writeFileText path "" + do! FileSystemHelper.ensureDirectoryOfFileAsync path + do! FileSystemHelper.writeFileTextAsync path "" return Ok (c) | _ -> return Error (sprintf "Contract %s is not an ISA contract" c.Path) @@ -75,25 +77,24 @@ let fulfillWriteContract basePath (c : Async) = | e -> return Error (sprintf "Error writing contract %s: %s" c.Path e.Message) } -let fulfillUpdateContract basePath (c : Async) = - async { - let! c = c +let fulfillUpdateContractAsync basePath (c : Contract) = + crossAsync { try match c.DTO with | Some (DTO.Spreadsheet wb) -> let path = ArcPathHelper.combine basePath c.Path - FileSystemHelper.ensureDirectoryOfFile path - FileSystemHelper.writeFileXlsx path (wb :?> FsWorkbook) + do! FileSystemHelper.ensureDirectoryOfFileAsync path + do! FileSystemHelper.writeFileXlsxAsync path (wb :?> FsWorkbook) return Ok (c) | Some (DTO.Text t) -> let path = ArcPathHelper.combine basePath c.Path - FileSystemHelper.ensureDirectoryOfFile path - FileSystemHelper.writeFileText path t + do! FileSystemHelper.ensureDirectoryOfFileAsync path + do! FileSystemHelper.writeFileTextAsync path t return Ok (c) | None -> let path = ArcPathHelper.combine basePath c.Path - FileSystemHelper.ensureDirectoryOfFile path - FileSystemHelper.writeFileText path "" + do! FileSystemHelper.ensureDirectoryOfFileAsync path + do! FileSystemHelper.writeFileTextAsync path "" return Ok (c) | _ -> return Error (sprintf "Contract %s is not an ISA contract" c.Path) @@ -101,9 +102,8 @@ let fulfillUpdateContract basePath (c : Async) = | e -> return Error (sprintf "Error updating contract %s: %s" c.Path e.Message) } -let fullfillRenameContract basePath (c : Async) = - async { - let! c = c +let fullfillRenameContractAsync basePath (c : Contract) = + crossAsync { try match c.DTO with | Some (DTO.Text t) when t = c.Path -> @@ -111,35 +111,33 @@ let fullfillRenameContract basePath (c : Async) = | Some (DTO.Text t) -> let newPath = ArcPathHelper.combine basePath t let oldPath = ArcPathHelper.combine basePath c.Path - FileSystemHelper.renameFileOrDirectory oldPath newPath + do! FileSystemHelper.renameFileOrDirectoryAsync oldPath newPath return Ok (c) | _ -> return Error (sprintf "Rename Contract %s does not contain new Path" c.Path) with | e -> return Error (sprintf "Error renaming contract %s: %s" c.Path e.Message) } -let fullfillDeleteContract basePath (c : Async) = - async { - let! c = c +let fullfillDeleteContractAsync basePath (c : Contract) = + crossAsync { try let path = ArcPathHelper.combine basePath c.Path - FileSystemHelper.deleteFileOrDirectory path + do! FileSystemHelper.deleteFileOrDirectoryAsync path return Ok (c) with | e -> return Error (sprintf "Error deleting contract %s: %s" c.Path e.Message) } -let fullFillContract basePath (c : Async) = - async { - let! cSync = c - match cSync.Operation with - | Operation.READ -> return! fulfillReadContract basePath c - | Operation.CREATE -> return! fulfillWriteContract basePath c - | Operation.UPDATE -> return! fulfillUpdateContract basePath c - | Operation.DELETE -> return! fullfillDeleteContract basePath c - | Operation.RENAME -> return! fullfillRenameContract basePath c - | _ -> return Error (sprintf "Operation %A not supported" cSync.Operation) +let fullFillContract basePath (c : Contract) = + crossAsync { + match c.Operation with + | Operation.READ -> return! fulfillReadContractAsync basePath c + | Operation.CREATE -> return! fulfillWriteContractAsync basePath c + | Operation.UPDATE -> return! fulfillUpdateContractAsync basePath c + | Operation.DELETE -> return! fullfillDeleteContractAsync basePath c + | Operation.RENAME -> return! fullfillRenameContractAsync basePath c + | _ -> return Error (sprintf "Operation %A not supported" c.Operation) } -let fullFillContractBatch basePath (cs : (Async) []) = - fullfillContractBatchBy fullFillContract basePath cs \ No newline at end of file +let fullFillContractBatchAsync basePath (cs : Contract []) = + fullfillContractBatchAsyncBy fullFillContract basePath cs \ No newline at end of file diff --git a/src/ARCtrl/ContractIO/FileSystemHelper.fs b/src/ARCtrl/ContractIO/FileSystemHelper.fs index ccb1c7c7..969195e9 100644 --- a/src/ARCtrl/ContractIO/FileSystemHelper.fs +++ b/src/ARCtrl/ContractIO/FileSystemHelper.fs @@ -1,80 +1,132 @@ module ARCtrl.FileSystemHelper open FsSpreadsheet - +open CrossAsync open FsSpreadsheet.Net -let directoryExists path = - System.IO.Directory.Exists path - -let createDirectory path = - System.IO.Directory.CreateDirectory path |> ignore - -let ensureDirectory path = - if not <| directoryExists path then - createDirectory path - -let ensureDirectoryOfFile (filePath : string) = - let file = new System.IO.FileInfo(filePath); - file.Directory.Create() - -let fileExists path = - System.IO.File.Exists path - -let getSubDirectories path = - System.IO.Directory.GetDirectories path - -let getSubFiles path = - System.IO.Directory.GetFiles path +let directoryExistsAsync path = + crossAsync { + return System.IO.Directory.Exists path + } + +let createDirectoryAsync path = + crossAsync { + System.IO.Directory.CreateDirectory path |> ignore + } + +let ensureDirectoryAsync path = + crossAsync { + let! exists = directoryExistsAsync path + if not <| exists then + return! createDirectoryAsync path + } + +let ensureDirectoryOfFileAsync (filePath : string) = + crossAsync { + let file = new System.IO.FileInfo(filePath); + file.Directory.Create() + } + +let fileExistsAsync path = + crossAsync { + return System.IO.File.Exists path + } + +let getSubDirectoriesAsync path = + crossAsync { + return System.IO.Directory.GetDirectories path + } + +let getSubFilesAsync path = + crossAsync { + return System.IO.Directory.GetFiles path + } /// Return the absolute path relative to the directoryPath -let makeRelative directoryPath (path : string) = - if directoryPath = "." || directoryPath = "/" || directoryPath = "" then path +let makeRelative directoryPath (path : string) = + if directoryPath = "." || directoryPath = "/" || directoryPath = "" then + path else if path.StartsWith(directoryPath) then path.Substring(directoryPath.Length) else path + + let standardizeSlashes (path : string) = path.Replace("\\","/") -let getAllFilePaths (directoryPath : string) = - let rec allFiles dirs = - if Seq.isEmpty dirs then Seq.empty else - seq { yield! dirs |> Seq.collect getSubFiles - yield! dirs |> Seq.collect getSubDirectories |> allFiles } - - allFiles [directoryPath] |> Seq.toArray - |> Array.map (makeRelative directoryPath >> standardizeSlashes) - -let readFileText path : string = - System.IO.File.ReadAllText path - -let readFileBinary path : byte [] = - System.IO.File.ReadAllBytes path - -let readFileXlsx path : FsWorkbook = - FsWorkbook.fromXlsxFile path - -let renameFileOrDirectory oldPath newPath = - if fileExists oldPath then - System.IO.File.Move(oldPath, newPath) - elif directoryExists oldPath then - System.IO.Directory.Move(oldPath, newPath) - else () - -let writeFileText path text = - System.IO.File.WriteAllText(path, text) - -let writeFileBinary path (bytes : byte []) = - System.IO.File.WriteAllBytes(path,bytes) - -let writeFileXlsx path (wb : FsWorkbook) = - FsWorkbook.toXlsxFile path wb - -let deleteFileOrDirectory path = - if fileExists path then - System.IO.File.Delete path - elif directoryExists path then - System.IO.Directory.Delete(path, true) - else () \ No newline at end of file +let getAllFilePathsAsync (directoryPath : string) = + crossAsync { + let rec allFiles (dirs : string seq) : CrossAsync = + crossAsync { + if Seq.isEmpty dirs then + return Seq.empty + else + + let! subFiles = dirs |> Seq.map getSubFilesAsync |> CrossAsync.sequential + let subFiles = subFiles |> Seq.concat + let! subDirs = dirs |> Seq.map getSubDirectoriesAsync |> CrossAsync.sequential + let! subDirContents = subDirs |> Seq.map allFiles |> CrossAsync.sequential + let subDirContents = subDirContents |> Seq.concat + return subFiles |> Seq.append subDirContents + } + let! allFiles = allFiles [directoryPath] + let allFilesRelative = + allFiles + |> Seq.toArray + |> Array.map (makeRelative directoryPath >> standardizeSlashes) + return allFilesRelative + } + +let readFileTextAsync path : Async = + crossAsync { + return System.IO.File.ReadAllText path + } + +let readFileBinaryAsync path : Async = + crossAsync { + return System.IO.File.ReadAllBytes path + } + +let readFileXlsxAsync path : Async = + crossAsync { + return FsWorkbook.fromXlsxFile path + } + +let renameFileOrDirectoryAsync oldPath newPath = + crossAsync { + let! fileExists = fileExistsAsync oldPath + let! directoryExists = directoryExistsAsync oldPath + if fileExists then + System.IO.File.Move(oldPath, newPath) + elif directoryExists then + System.IO.Directory.Move(oldPath, newPath) + else () + } + +let writeFileTextAsync path text = + crossAsync { + System.IO.File.WriteAllText(path, text) + } + +let writeFileBinaryAsync path (bytes : byte []) = + crossAsync { + System.IO.File.WriteAllBytes(path, bytes) + } + +let writeFileXlsxAsync path (wb : FsWorkbook) = + crossAsync { + FsWorkbook.toXlsxFile path wb + } + +let deleteFileOrDirectoryAsync path = + crossAsync { + let! fileExists = fileExistsAsync path + let! directoryExists = directoryExistsAsync path + if fileExists then + System.IO.File.Delete path + elif directoryExists then + System.IO.Directory.Delete(path, true) + else () + } \ No newline at end of file diff --git a/src/ARCtrl/CrossAsync.fs b/src/ARCtrl/CrossAsync.fs index 7cc55c3b..cfb6803c 100644 --- a/src/ARCtrl/CrossAsync.fs +++ b/src/ARCtrl/CrossAsync.fs @@ -23,3 +23,9 @@ let sequential = #else Async.Sequential #endif + +let map f v = + crossAsync { + let! v = v + return f v + } \ No newline at end of file diff --git a/src/ARCtrl/Template.Web.fs b/src/ARCtrl/Template.Web.fs index 0999877b..f7437b20 100644 --- a/src/ARCtrl/Template.Web.fs +++ b/src/ARCtrl/Template.Web.fs @@ -1,14 +1,14 @@ -module ARCtrl.Template.Web +module ARCtrl.Template.Web open ARCtrl open Fable.Core - +open CrossAsync let getTemplates(url: string option) = let defaultURL = @"https://github.com/nfdi4plants/Swate-templates/releases/download/latest/templates_v2.0.0.json" let url = defaultArg url defaultURL - async { + crossAsync { let! jsonString = ARCtrl.WebRequest.downloadFile url let mapResult = Json.Templates.fromJsonString jsonString return mapResult diff --git a/tests/ARCtrl/ARCtrl.Tests.fs b/tests/ARCtrl/ARCtrl.Tests.fs index ce4733b4..14db5194 100644 --- a/tests/ARCtrl/ARCtrl.Tests.fs +++ b/tests/ARCtrl/ARCtrl.Tests.fs @@ -9,6 +9,7 @@ open ARCtrl.Contract open ARCtrl.Spreadsheet open ARCtrl.Helper open FsSpreadsheet +open CrossAsync let tests_create = testList "create" [ testCase "empty" <| fun _ -> @@ -946,9 +947,9 @@ let tests_GetStudyRenameContracts = testList "GetStudyRenameContracts" [ let tests_load = testList "Load" [ - testCase "simpleARC" (fun () -> + testCaseAsync "simpleARC" (crossAsync { let p = TestObjects.IO.testSimpleARC - let result = ARC.load(p) + let! result = ARC.loadAsync(p) let result = Expect.wantOk result "ARC should load successfully" Expect.isSome result.ISA "Should contain an ISA part" @@ -965,6 +966,7 @@ let tests_load = let a = s.RegisteredAssays.[0] Expect.equal a.TableCount 4 "Assay should contain 4 tables" + } ) ] @@ -973,11 +975,13 @@ let tests_load = let tests_write = testList "Write" [ - testCase "empty" (fun () -> + testCaseAsync "empty" (crossAsync { let p = ArcPathHelper.combine TestObjects.IO.testResultsFolder "ARC_Write_Empty" let a = ARC() - Expect.wantOk (a.Write(p)) "ARC should write successfully" |> ignore + let! result = a.WriteAsync(p) + + Expect.wantOk result "ARC should write successfully" |> ignore let expectedPaths = [ @@ -990,13 +994,13 @@ let tests_write = |> List.sort - let paths = - FileSystemHelper.getAllFilePaths p - |> Seq.sort + let! paths = + FileSystemHelper.getAllFilePathsAsync p + |> map Seq.sort - Expect.sequenceEqual paths expectedPaths "Files were not created correctly." - ) - testCase "SimpleARC" (fun () -> + Expect.sequenceEqual paths expectedPaths "Files were not created correctly." + }) + testCaseAsync "SimpleARC" (crossAsync { let p = ArcPathHelper.combine TestObjects.IO.testResultsFolder "ARC_Write_SimpleARC" let arc = ARC() @@ -1009,7 +1013,9 @@ let tests_write = s.AddRegisteredAssay(a) arc.ISA <- Some i arc.UpdateFileSystem() - Expect.wantOk (arc.Write(p)) "ARC should write successfully" |> ignore + + let! result = arc.WriteAsync(p) + Expect.wantOk result "ARC should write successfully" |> ignore let expectedPaths = [ @@ -1030,16 +1036,18 @@ let tests_write = |> List.sort - let paths = - FileSystemHelper.getAllFilePaths p - |> Seq.sort + let! paths = + FileSystemHelper.getAllFilePathsAsync p + |> map Seq.sort Expect.sequenceEqual paths expectedPaths "Files were not created correctly." - ) + }) // This test reads a preexisting assay with data and everything, data content is not copied though but just the - testCase "LoadSimpleARCAndAddAssay" (fun () -> + testCaseAsync "LoadSimpleARCAndAddAssay" (crossAsync { let p = ArcPathHelper.combine TestObjects.IO.testResultsFolder "ARC_Write_SimpleARCWithAssay" - let arc = Expect.wantOk (ARC.load(TestObjects.IO.testSimpleARC)) "ARC should load correctly" + + let! readResult = ARC.loadAsync(TestObjects.IO.testSimpleARC) + let arc = Expect.wantOk readResult "ARC should load correctly" let i = arc.ISA.Value @@ -1051,7 +1059,10 @@ let tests_write = arc.ISA <- Some i arc.UpdateFileSystem() - Expect.wantOk (arc.Write(p)) "ARC should write successfully" |> ignore + + let! writeResult = arc.WriteAsync(p) + + Expect.wantOk writeResult "ARC should write successfully" |> ignore let expectedPaths = [ @@ -1094,18 +1105,18 @@ let tests_write = |> List.sort - let paths = - FileSystemHelper.getAllFilePaths p - |> Seq.sort + let! paths = + FileSystemHelper.getAllFilePathsAsync p + |> map Seq.sort Expect.sequenceEqual paths expectedPaths "Files were not created correctly." - ) + }) |> testSequenced ] let tests_Update = testList "Update" [ - testCase "AddedAssay" (fun () -> + testCaseAsync "AddedAssay" (crossAsync { let p = ArcPathHelper.combine TestObjects.IO.testResultsFolder "ARC_Update_AddedAssay" let arc = ARC() @@ -1119,14 +1130,20 @@ let tests_Update = s.AddRegisteredAssay(a) arc.ISA <- Some i arc.UpdateFileSystem() - Expect.wantOk (arc.Write(p)) "ARC should write successfully" |> ignore + + let! writeResult = arc.WriteAsync(p) + + Expect.wantOk writeResult "ARC should write successfully" |> ignore // add assay let newAssayName = "MyNewAssay" i.InitAssay(newAssayName) |> ignore arc.ISA <- Some i arc.UpdateFileSystem() - Expect.wantOk (arc.Update(p)) "ARC should update successfully" |> ignore + + let! updateResult = arc.UpdateAsync(p) + + Expect.wantOk updateResult "ARC should update successfully" |> ignore let expectedPaths = [ @@ -1150,19 +1167,19 @@ let tests_Update = ] |> List.sort - let paths = - FileSystemHelper.getAllFilePaths p - |> Seq.sort + let! paths = + FileSystemHelper.getAllFilePathsAsync p + |> map Seq.sort Expect.sequenceEqual paths expectedPaths "Files were not created correctly." - ) + }) ] let tests_renameAssay = testList "RenameAssay" [ - testCase "SimpleARC" (fun () -> + testCaseAsync "SimpleARC" (crossAsync { let p = ArcPathHelper.combine TestObjects.IO.testResultsFolder "ARC_RenameAssay_SimpleARC" let arc = ARC() @@ -1176,11 +1193,16 @@ let tests_renameAssay = s.AddRegisteredAssay(a) arc.ISA <- Some i arc.UpdateFileSystem() - Expect.wantOk (arc.Write(p)) "ARC should write successfully" |> ignore + + let! updateResult = arc.WriteAsync(p) + + Expect.wantOk updateResult "ARC should write successfully" |> ignore // rename assay let newAssayName = "MyNewAssay" - Expect.wantOk (arc.RenameAssay(p,assayName, newAssayName)) "Assay should be renamed successfully" |> ignore + + let! renameResult = arc.RenameAssayAsync(p,assayName, newAssayName) + Expect.wantOk renameResult "Assay should be renamed successfully" |> ignore let expectedPaths = [ @@ -1200,17 +1222,17 @@ let tests_renameAssay = ] |> List.sort - let paths = - FileSystemHelper.getAllFilePaths p - |> Seq.sort + let! paths = + FileSystemHelper.getAllFilePathsAsync p + |> map Seq.sort Expect.sequenceEqual paths expectedPaths "Files were not created correctly." - ) + }) ] let tests_RenameStudy = testList "RenameStudy" [ - testCase "SimpleARC" (fun () -> + testCaseAsync "SimpleARC" (crossAsync { let p = ArcPathHelper.combine TestObjects.IO.testResultsFolder "ARC_RenameStudy_SimpleARC" let arc = ARC() @@ -1224,11 +1246,16 @@ let tests_RenameStudy = s.AddRegisteredAssay(a) arc.ISA <- Some i arc.UpdateFileSystem() - Expect.wantOk (arc.Write(p)) "ARC should write successfully" |> ignore + + let! writeResult = arc.WriteAsync(p) + + Expect.wantOk writeResult "ARC should write successfully" |> ignore // rename study let newStudyName = "MyNewStudy" - Expect.wantOk (arc.RenameStudy(p,studyName, newStudyName)) "Study should be renamed successfully" |> ignore + + let! renameResult = arc.RenameStudyAsync(p,studyName, newStudyName) + Expect.wantOk renameResult "Study should be renamed successfully" |> ignore let expectedPaths = [ @@ -1248,18 +1275,18 @@ let tests_RenameStudy = ] |> List.sort - let paths = - FileSystemHelper.getAllFilePaths p - |> Seq.sort + let! paths = + FileSystemHelper.getAllFilePathsAsync p + |> map Seq.sort Expect.sequenceEqual paths expectedPaths "Files were not created correctly." - ) + }) ] let tests_RemoveAssay = testList "RemoveAssay" [ - testCase "SimpleARC" (fun () -> + testCaseAsync "SimpleARC" (crossAsync { let p = ArcPathHelper.combine TestObjects.IO.testResultsFolder "ARC_RemoveAssay_SimpleARC" let arc = ARC() @@ -1273,10 +1300,15 @@ let tests_RemoveAssay = s.AddRegisteredAssay(a) arc.ISA <- Some i arc.UpdateFileSystem() - Expect.wantOk (arc.Write(p)) "ARC should write successfully" |> ignore + + let! writeResult = arc.WriteAsync(p) + + Expect.wantOk writeResult "ARC should write successfully" |> ignore // remove assay - Expect.wantOk (arc.RemoveAssay(p,assayName)) "Assay should be removed successfully" |> ignore + + let! removeResult = arc.RemoveAssayAsync(p,assayName) + Expect.wantOk removeResult "Assay should be removed successfully" |> ignore let expectedPaths = [ @@ -1292,17 +1324,17 @@ let tests_RemoveAssay = ] |> List.sort - let paths = - FileSystemHelper.getAllFilePaths p - |> Seq.sort + let! paths = + FileSystemHelper.getAllFilePathsAsync p + |> map Seq.sort Expect.sequenceEqual paths expectedPaths "Files were not created correctly." - ) + }) ] let tests_RemoveStudy = testList "RemoveStudy" [ - testCase "SimpleARC" (fun () -> + testCaseAsync "SimpleARC" (crossAsync { let p = ArcPathHelper.combine TestObjects.IO.testResultsFolder "ARC_RemoveStudy_SimpleARC" let arc = ARC() @@ -1316,10 +1348,15 @@ let tests_RemoveStudy = s.AddRegisteredAssay(a) arc.ISA <- Some i arc.UpdateFileSystem() - Expect.wantOk (arc.Write(p)) "ARC should write successfully" |> ignore + + let! writeResult = arc.WriteAsync(p) + + Expect.wantOk writeResult "ARC should write successfully" |> ignore // remove study - Expect.wantOk (arc.RemoveStudy(p,studyName)) "Study should be removed successfully" |> ignore + + let! removeResult = arc.RemoveStudyAsync(p,studyName) + Expect.wantOk removeResult "Study should be removed successfully" |> ignore let expectedPaths = [ @@ -1335,12 +1372,12 @@ let tests_RemoveStudy = ] |> List.sort - let paths = - FileSystemHelper.getAllFilePaths p - |> Seq.sort + let! paths = + FileSystemHelper.getAllFilePathsAsync p + |> map Seq.sort Expect.sequenceEqual paths expectedPaths "Files were not created correctly." - ) + }) ] diff --git a/tests/ARCtrl/ContractIO.Tests.fs b/tests/ARCtrl/ContractIO.Tests.fs index b1c58c45..4248d1d5 100644 --- a/tests/ARCtrl/ContractIO.Tests.fs +++ b/tests/ARCtrl/ContractIO.Tests.fs @@ -6,23 +6,25 @@ open ARCtrl.Contract open ARCtrl.FileSystemHelper open FsSpreadsheet open FsSpreadsheet.Net +open CrossAsync + let testRead = testList "Read" [ - testCase "TextFile" (fun () -> + testCaseAsync "TextFile" (crossAsync { let fileName = "TestReadMe.txt" let contract = Contract.createRead(fileName,DTOType.PlainText) let dto = DTO.Text "This is a test" let expected = {contract with DTO = Some dto} - let result = fulfillReadContract TestObjects.IO.testContractsFolder contract + let! result = fulfillReadContractAsync TestObjects.IO.testContractsFolder contract let resultContract = Expect.wantOk result "Contract was not fulfilled correctly" Expect.equal resultContract expected $"Text was not read correctly" - ) - testCase "XLSXFile" (fun () -> + }) + testCaseAsync "XLSXFile" (crossAsync { let fileName = "TestWorkbook.xlsx" let contract = Contract.createRead(fileName,DTOType.ISA_Study) - let result = fulfillReadContract TestObjects.IO.testContractsFolder contract + let! result = fulfillReadContractAsync TestObjects.IO.testContractsFolder contract let resultContract = Expect.wantOk result "Contract was not fulfilled correctly" let dto = Expect.wantSome resultContract.DTO "DTO was not read correctly" Expect.isTrue dto.isSpreadsheet "DTO was not read correctly" @@ -35,41 +37,47 @@ let testRead = let row2 = Expect.wantSome (ws.TryGetRowValuesAt 2) "Worksheet does not contain row 2" let expected = ["A";"B";"C"] |> Seq.map box Expect.sequenceEqual row2 expected "Worksheet does not contain correct values" - ) + }) ] let testWrite = testList "Write" [ - testCase "TextFileEmpty" (fun () -> + testCaseAsync "TextFileEmpty" (crossAsync { let fileName = "TestEmpty.txt" let contract = Contract.createCreate(fileName,DTOType.PlainText) - FileSystemHelper.ensureDirectory TestObjects.IO.testResultsFolder + do! FileSystemHelper.ensureDirectoryAsync TestObjects.IO.testResultsFolder - Expect.wantOk (fulfillWriteContract TestObjects.IO.testResultsFolder contract) "Contract was not fulfilled correctly" + let! resultContract = fulfillWriteContractAsync TestObjects.IO.testResultsFolder contract + + Expect.isOk resultContract "Contract was not fulfilled correctly" let filePath = ArcPathHelper.combine TestObjects.IO.testResultsFolder fileName Expect.isTrue (System.IO.File.Exists filePath) $"File {filePath} was not created" - Expect.equal (FileSystemHelper.readFileText filePath) "" $"File {filePath} was not empty" - ) - testCase "TextFile" (fun () -> - + let! resultText = FileSystemHelper.readFileTextAsync filePath + Expect.equal resultText "" $"File {filePath} was not empty" + }) + testCaseAsync "TextFile" (crossAsync { let testText = "This is a test" let fileName = "TestReadMe.txt" let dto = DTO.Text testText let contract = Contract.createCreate(fileName,DTOType.PlainText,dto) - FileSystemHelper.ensureDirectory TestObjects.IO.testResultsFolder + do! FileSystemHelper.ensureDirectoryAsync TestObjects.IO.testResultsFolder - Expect.wantOk (fulfillWriteContract TestObjects.IO.testResultsFolder contract) "Contract was not fulfilled correctly" + let! resultContract = fulfillWriteContractAsync TestObjects.IO.testResultsFolder contract + + Expect.isOk resultContract "Contract was not fulfilled correctly" let filePath = ArcPathHelper.combine TestObjects.IO.testResultsFolder fileName Expect.isTrue (System.IO.File.Exists filePath) $"File {filePath} was not created" - Expect.equal (FileSystemHelper.readFileText filePath) testText $"File {filePath} was not empty" - ) - testCase "XLSXFile" (fun () -> + + let! resultText = FileSystemHelper.readFileTextAsync filePath + Expect.equal resultText testText $"File {filePath} was not empty" + }) + testCaseAsync "XLSXFile" (crossAsync { let worksheetName = "TestSheet" let testWB = new FsWorkbook() @@ -81,18 +89,20 @@ let testWrite = let dto = DTO.Spreadsheet testWB let contract = Contract.createCreate(fileName,DTOType.ISA_Assay,dto) - FileSystemHelper.ensureDirectory TestObjects.IO.testResultsFolder + do! FileSystemHelper.ensureDirectoryAsync TestObjects.IO.testResultsFolder - Expect.wantOk (fulfillWriteContract TestObjects.IO.testResultsFolder contract) "Contract was not fulfilled correctly" + let! resultContract = fulfillWriteContractAsync TestObjects.IO.testResultsFolder contract + + Expect.isOk resultContract "Contract was not fulfilled correctly" let filePath = ArcPathHelper.combine TestObjects.IO.testResultsFolder fileName - let wb = FsWorkbook.fromXlsxFile filePath + let! wb = FileSystemHelper.readFileXlsxAsync filePath let ws = Expect.wantSome (wb.TryGetWorksheetByName worksheetName) "Workbook does not contain worksheet" let row1 = Expect.wantSome (ws.TryGetRowValuesAt 1) "Worksheet does not contain row 1" let expected = ["A1";"B1";"C1"] |> Seq.map box Expect.sequenceEqual row1 expected "Worksheet does not contain correct values" - ) + }) ] let testExecute = diff --git a/tests/ARCtrl/FileSystemHelper.Tests.fs b/tests/ARCtrl/FileSystemHelper.Tests.fs index 8ca90ac7..24c92cbc 100644 --- a/tests/ARCtrl/FileSystemHelper.Tests.fs +++ b/tests/ARCtrl/FileSystemHelper.Tests.fs @@ -3,49 +3,51 @@ module ARCtrl.FileSystemHelper.Tests open TestingUtils open ARCtrl open System.Text.Json - +open CrossAsync let readFileText = testList "ReadText" [ - testCase "simple" (fun () -> + testCaseAsync "simple" (crossAsync { let p = TestObjects.IO.simpleTextFilePath - let result = FileSystemHelper.readFileText p + let! result = FileSystemHelper.readFileTextAsync p let expected = "Hello" Expect.equal result expected "Text was not read correctly." - ) + }) ] let writeFileText = testList "WriteText" [ - testCase "simple" (fun () -> - ARCtrl.FileSystemHelper.ensureDirectory TestObjects.IO.testResultsFolder + testCaseAsync "simple" (crossAsync { + do! ARCtrl.FileSystemHelper.ensureDirectoryAsync TestObjects.IO.testResultsFolder let p = ArcPathHelper.combine TestObjects.IO.testResultsFolder "SimpleText.txt" let t = "Hello" printfn "write to %s" p - FileSystemHelper.writeFileText p t - let result = FileSystemHelper.readFileText p + do! FileSystemHelper.writeFileTextAsync p t + let! result = FileSystemHelper.readFileTextAsync p let expected = "Hello" Expect.equal result expected "Text was not read correctly." - ) - testCase "SubDirectoryWithEnsureDir" (fun () -> + }) + testCaseAsync "SubDirectoryWithEnsureDir" (crossAsync { let subDir = ArcPathHelper.combine TestObjects.IO.testResultsFolder "SubFolder" let p = ArcPathHelper.combine subDir "SimpleText.txt" let t = "Hello" printfn "write to %s" p - FileSystemHelper.ensureDirectory subDir - FileSystemHelper.writeFileText p t - let result = FileSystemHelper.readFileText p + do! FileSystemHelper.ensureDirectoryAsync subDir + do! FileSystemHelper.writeFileTextAsync p t + let! result = FileSystemHelper.readFileTextAsync p let expected = "Hello" Expect.equal result expected "Text was not read correctly." - ) + }) ] let getAllFilePaths = testList "GetAllFilePaths" [ - testCase "simple" (fun () -> + testCaseAsync "simple" (crossAsync { let p = TestObjects.IO.testSubPathsFolder - let result = FileSystemHelper.getAllFilePaths p + let! result = + FileSystemHelper.getAllFilePathsAsync p + |> map Seq.sort let expected = [ "/File1.txt" @@ -55,7 +57,7 @@ let getAllFilePaths = ] Expect.sequenceEqual result expected "File Paths were not found correctly." - ) + }) ] let main = diff --git a/tests/ARCtrl/Template.Tests.fs b/tests/ARCtrl/Template.Tests.fs index fda07bf7..3e7e062f 100644 --- a/tests/ARCtrl/Template.Tests.fs +++ b/tests/ARCtrl/Template.Tests.fs @@ -1,15 +1,15 @@ -module ARCtrl.Template.Tests +module ARCtrl.Template.Tests open Thoth.Json.Core open ARCtrl.Json open ARCtrl - +open CrossAsync open TestingUtils let private tests_Web = testList "Web" [ - testCaseAsync "getTemplates" <| async { + testCaseAsync "getTemplates" <| crossAsync { let! templatesMap = ARCtrl.Template.Web.getTemplates(None) Expect.isTrue (templatesMap.Length > 0) "Count > 0" } diff --git a/tests/Json/Validation/JsonSchemaValidation.fs b/tests/Json/Validation/JsonSchemaValidation.fs index e9905a07..ef7b5eab 100644 --- a/tests/Json/Validation/JsonSchemaValidation.fs +++ b/tests/Json/Validation/JsonSchemaValidation.fs @@ -1,4 +1,4 @@ -namespace ARCtrl.Json +namespace ARCtrl.Json From cca43e8158f96de22ecfb668320f0ebfeb5ee7d4 Mon Sep 17 00:00:00 2001 From: Heinrich Lukas Weil Date: Thu, 21 Nov 2024 17:12:08 +0100 Subject: [PATCH 14/30] add first wip version of js file system access --- ARCtrl.JS.sln | 235 +++++++++++++++++++ src/ARCtrl/ARCtrl.Javascript.fsproj | 7 +- src/ARCtrl/ContractIO/FileSystemHelper.fs | 92 ++++++-- src/ARCtrl/ContractIO/FileSystemHelper.js.fs | 80 ------- src/ARCtrl/ContractIO/FilesSystem.js | 95 ++++++++ src/ARCtrl/Template.Web.fs | 2 +- src/ARCtrl/Xlsx.fs | 11 +- tests/ARCtrl/FileSystemHelper.Tests.fs | 1 - 8 files changed, 415 insertions(+), 108 deletions(-) create mode 100644 ARCtrl.JS.sln delete mode 100644 src/ARCtrl/ContractIO/FileSystemHelper.js.fs create mode 100644 src/ARCtrl/ContractIO/FilesSystem.js diff --git a/ARCtrl.JS.sln b/ARCtrl.JS.sln new file mode 100644 index 00000000..0dd2832c --- /dev/null +++ b/ARCtrl.JS.sln @@ -0,0 +1,235 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31903.59 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{326188FB-2CC0-4610-A082-708885BF47AA}" + ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig + .gitignore = .gitignore + .github\workflows\build-test.yml = .github\workflows\build-test.yml + build.cmd = build.cmd + build.sh = build.sh + Directory.Packages.props = Directory.Packages.props + .config\dotnet-tools.json = .config\dotnet-tools.json + global.json = global.json + package.json = package.json + pyproject.toml = pyproject.toml + README.md = README.md + RELEASE_NOTES.md = RELEASE_NOTES.md + setup.cmd = setup.cmd + EndProjectSection +EndProject +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "ARCtrl.CWL", "src\CWL\ARCtrl.CWL.fsproj", "{1CD34A01-D19A-441F-8F3D-6EF69D9DDA8D}" +EndProject +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "ARCtrl.FileSystem", "src\FileSystem\ARCtrl.FileSystem.fsproj", "{F47E23C3-8415-4725-9E85-57271694DEB3}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{6DA2330B-D407-4FB1-AF05-B0184034EC44}" + ProjectSection(SolutionItems) = preProject + src\ARCtrl\ARCtrl.fsproj = src\ARCtrl\ARCtrl.fsproj + src\ARCtrl\ARCtrl.Python.fsproj = src\ARCtrl\ARCtrl.Python.fsproj + src\Package.Metadata.props = src\Package.Metadata.props + EndProjectSection +EndProject +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "Build", "build\Build.fsproj", "{5EAFB0CD-1168-4FCA-AA61-E96AD6C85819}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{64B34A6E-318D-4E6E-9262-CE52C9B85A38}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "JavaScript", "JavaScript", "{913222CA-261F-49CB-A823-CC7C335F964A}" + ProjectSection(SolutionItems) = preProject + tests\JavaScript\CompositeCell.js = tests\JavaScript\CompositeCell.js + tests\JavaScript\CompositeHeader.js = tests\JavaScript\CompositeHeader.js + tests\JavaScript\JsonController.js = tests\JavaScript\JsonController.js + tests\JavaScript\Main.js = tests\JavaScript\Main.js + tests\JavaScript\Person.js = tests\JavaScript\Person.js + tests\JavaScript\Template.Web.js = tests\JavaScript\Template.Web.js + tests\JavaScript\XlsxController.js = tests\JavaScript\XlsxController.js + EndProjectSection +EndProject +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "ARCtrl.JavaScript", "src\ARCtrl\ARCtrl.JavaScript.fsproj", "{9BE5D83D-EA90-4382-A132-174FD158227F}" +EndProject +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "ARCtrl.Tests", "tests\ARCtrl\ARCtrl.Tests.fsproj", "{801247D5-7EE5-49C8-AB26-F822A415BA49}" +EndProject +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "ARCtrl.Contract", "src\Contract\ARCtrl.Contract.fsproj", "{1945EE8A-F105-43A9-91C9-8C4422B9873E}" +EndProject +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "TestingUtils", "tests\TestingUtils\TestingUtils.fsproj", "{AA011593-6603-4E16-A7B0-0ED3862511DE}" +EndProject +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "Speedtest", "tests\Speedtest\Speedtest.fsproj", "{6EFC7E7D-840E-4506-ADBC-37130A21D1C0}" +EndProject +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "ARCtrl.Json", "src\Json\ARCtrl.Json.fsproj", "{6DCF93BA-A918-42A0-BAD7-A11B72ADFFE6}" +EndProject +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "ARCtrl.Spreadsheet", "src\Spreadsheet\ARCtrl.Spreadsheet.fsproj", "{74EF1B45-C7B7-4281-BDDB-7A653F9F935E}" +EndProject +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "ARCtrl.Core", "src\Core\ARCtrl.Core.fsproj", "{FDA13C07-2E22-49D5-A317-7A68DC359894}" +EndProject +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "ARCtrl.Core.Tests", "tests\Core\ARCtrl.Core.Tests.fsproj", "{EDC4FB2B-40CF-4AFD-90C7-CF88C2745789}" +EndProject +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "ARCtrl.Json.Tests", "tests\Json\ARCtrl.Json.Tests.fsproj", "{9E1FF103-B5BD-44B6-B839-0E1FED2C49EC}" +EndProject +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "ARCtrl.Spreadsheet.Tests", "tests\Spreadsheet\ARCtrl.Spreadsheet.Tests.fsproj", "{03F4E6D0-CFE7-44A6-994B-778B3DF6532C}" +EndProject +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "ARCtrl.FileSystem.Tests", "tests\FileSystem\ARCtrl.FileSystem.Tests.fsproj", "{704935A5-68F2-4070-8A55-AFF8F66ACAD6}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Python", "Python", "{501F6D1E-6300-4CA4-8E61-3523BCF4D533}" + ProjectSection(SolutionItems) = preProject + tests\Python\test_index.py = tests\Python\test_index.py + tests\Python\test_JsonController.py = tests\Python\test_JsonController.py + tests\Python\test_OntologyAnnotation.py = tests\Python\test_OntologyAnnotation.py + tests\Python\test_XlsxController.py = tests\Python\test_XlsxController.py + EndProjectSection +EndProject +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "ARCtrl.ValidationPackages", "src\ValidationPackages\ARCtrl.ValidationPackages.fsproj", "{0C35D768-BF55-4BD9-B915-35125CED65A0}" +EndProject +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "ARCtrl.Yaml", "src\Yaml\ARCtrl.Yaml.fsproj", "{4CC3AAC2-030B-4B2E-A386-9C1F68E42238}" +EndProject +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "ARCtrl.ValidationPackages.Tests", "tests\ValidationPackages\ARCtrl.ValidationPackages.Tests.fsproj", "{1CA11165-4B70-41D2-A846-50374E85385E}" +EndProject +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "ARCtrl.Yaml.Tests", "tests\Yaml\ARCtrl.Yaml.Tests.fsproj", "{5810EF87-4F85-4B4C-98E3-833AE914C628}" +EndProject +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "ARCtrl.Contract.Tests", "tests\Contract\ARCtrl.Contract.Tests.fsproj", "{D10D12C7-B877-423B-867D-161D99E673C9}" +EndProject +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "ARCtrl.CWL.Tests", "tests\CWL\ARCtrl.CWL.Tests.fsproj", "{0F2188D3-144C-41BF-89F6-AA85883AE0D3}" +EndProject +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "ARCtrl.ROCrate", "src\ROCrate\ARCtrl.ROCrate.fsproj", "{658BF141-B4B5-4B90-891D-AC36A3FD7574}" +EndProject +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "ARCtrl.ROCrate.Tests", "tests\ROCrate\ARCtrl.ROCrate.Tests.fsproj", "{212A1C64-02FC-465A-B0FA-F69735F37ACC}" +EndProject +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "All.Tests", "tests\All\All.Tests.fsproj", "{243ACD5F-10AD-4BE6-9932-829667BE2053}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {1CD34A01-D19A-441F-8F3D-6EF69D9DDA8D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1CD34A01-D19A-441F-8F3D-6EF69D9DDA8D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1CD34A01-D19A-441F-8F3D-6EF69D9DDA8D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1CD34A01-D19A-441F-8F3D-6EF69D9DDA8D}.Release|Any CPU.Build.0 = Release|Any CPU + {F47E23C3-8415-4725-9E85-57271694DEB3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F47E23C3-8415-4725-9E85-57271694DEB3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F47E23C3-8415-4725-9E85-57271694DEB3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F47E23C3-8415-4725-9E85-57271694DEB3}.Release|Any CPU.Build.0 = Release|Any CPU + {5EAFB0CD-1168-4FCA-AA61-E96AD6C85819}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5EAFB0CD-1168-4FCA-AA61-E96AD6C85819}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5EAFB0CD-1168-4FCA-AA61-E96AD6C85819}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5EAFB0CD-1168-4FCA-AA61-E96AD6C85819}.Release|Any CPU.Build.0 = Release|Any CPU + {9BE5D83D-EA90-4382-A132-174FD158227F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9BE5D83D-EA90-4382-A132-174FD158227F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9BE5D83D-EA90-4382-A132-174FD158227F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9BE5D83D-EA90-4382-A132-174FD158227F}.Release|Any CPU.Build.0 = Release|Any CPU + {801247D5-7EE5-49C8-AB26-F822A415BA49}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {801247D5-7EE5-49C8-AB26-F822A415BA49}.Debug|Any CPU.Build.0 = Debug|Any CPU + {801247D5-7EE5-49C8-AB26-F822A415BA49}.Release|Any CPU.ActiveCfg = Release|Any CPU + {801247D5-7EE5-49C8-AB26-F822A415BA49}.Release|Any CPU.Build.0 = Release|Any CPU + {1945EE8A-F105-43A9-91C9-8C4422B9873E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1945EE8A-F105-43A9-91C9-8C4422B9873E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1945EE8A-F105-43A9-91C9-8C4422B9873E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1945EE8A-F105-43A9-91C9-8C4422B9873E}.Release|Any CPU.Build.0 = Release|Any CPU + {AA011593-6603-4E16-A7B0-0ED3862511DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AA011593-6603-4E16-A7B0-0ED3862511DE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AA011593-6603-4E16-A7B0-0ED3862511DE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AA011593-6603-4E16-A7B0-0ED3862511DE}.Release|Any CPU.Build.0 = Release|Any CPU + {6EFC7E7D-840E-4506-ADBC-37130A21D1C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6EFC7E7D-840E-4506-ADBC-37130A21D1C0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6EFC7E7D-840E-4506-ADBC-37130A21D1C0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6EFC7E7D-840E-4506-ADBC-37130A21D1C0}.Release|Any CPU.Build.0 = Release|Any CPU + {6DCF93BA-A918-42A0-BAD7-A11B72ADFFE6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6DCF93BA-A918-42A0-BAD7-A11B72ADFFE6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6DCF93BA-A918-42A0-BAD7-A11B72ADFFE6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6DCF93BA-A918-42A0-BAD7-A11B72ADFFE6}.Release|Any CPU.Build.0 = Release|Any CPU + {74EF1B45-C7B7-4281-BDDB-7A653F9F935E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {74EF1B45-C7B7-4281-BDDB-7A653F9F935E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {74EF1B45-C7B7-4281-BDDB-7A653F9F935E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {74EF1B45-C7B7-4281-BDDB-7A653F9F935E}.Release|Any CPU.Build.0 = Release|Any CPU + {FDA13C07-2E22-49D5-A317-7A68DC359894}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FDA13C07-2E22-49D5-A317-7A68DC359894}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FDA13C07-2E22-49D5-A317-7A68DC359894}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FDA13C07-2E22-49D5-A317-7A68DC359894}.Release|Any CPU.Build.0 = Release|Any CPU + {EDC4FB2B-40CF-4AFD-90C7-CF88C2745789}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EDC4FB2B-40CF-4AFD-90C7-CF88C2745789}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EDC4FB2B-40CF-4AFD-90C7-CF88C2745789}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EDC4FB2B-40CF-4AFD-90C7-CF88C2745789}.Release|Any CPU.Build.0 = Release|Any CPU + {9E1FF103-B5BD-44B6-B839-0E1FED2C49EC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9E1FF103-B5BD-44B6-B839-0E1FED2C49EC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9E1FF103-B5BD-44B6-B839-0E1FED2C49EC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9E1FF103-B5BD-44B6-B839-0E1FED2C49EC}.Release|Any CPU.Build.0 = Release|Any CPU + {03F4E6D0-CFE7-44A6-994B-778B3DF6532C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {03F4E6D0-CFE7-44A6-994B-778B3DF6532C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {03F4E6D0-CFE7-44A6-994B-778B3DF6532C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {03F4E6D0-CFE7-44A6-994B-778B3DF6532C}.Release|Any CPU.Build.0 = Release|Any CPU + {704935A5-68F2-4070-8A55-AFF8F66ACAD6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {704935A5-68F2-4070-8A55-AFF8F66ACAD6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {704935A5-68F2-4070-8A55-AFF8F66ACAD6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {704935A5-68F2-4070-8A55-AFF8F66ACAD6}.Release|Any CPU.Build.0 = Release|Any CPU + {0C35D768-BF55-4BD9-B915-35125CED65A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0C35D768-BF55-4BD9-B915-35125CED65A0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0C35D768-BF55-4BD9-B915-35125CED65A0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0C35D768-BF55-4BD9-B915-35125CED65A0}.Release|Any CPU.Build.0 = Release|Any CPU + {4CC3AAC2-030B-4B2E-A386-9C1F68E42238}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4CC3AAC2-030B-4B2E-A386-9C1F68E42238}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4CC3AAC2-030B-4B2E-A386-9C1F68E42238}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4CC3AAC2-030B-4B2E-A386-9C1F68E42238}.Release|Any CPU.Build.0 = Release|Any CPU + {1CA11165-4B70-41D2-A846-50374E85385E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1CA11165-4B70-41D2-A846-50374E85385E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1CA11165-4B70-41D2-A846-50374E85385E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1CA11165-4B70-41D2-A846-50374E85385E}.Release|Any CPU.Build.0 = Release|Any CPU + {5810EF87-4F85-4B4C-98E3-833AE914C628}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5810EF87-4F85-4B4C-98E3-833AE914C628}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5810EF87-4F85-4B4C-98E3-833AE914C628}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5810EF87-4F85-4B4C-98E3-833AE914C628}.Release|Any CPU.Build.0 = Release|Any CPU + {D10D12C7-B877-423B-867D-161D99E673C9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D10D12C7-B877-423B-867D-161D99E673C9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D10D12C7-B877-423B-867D-161D99E673C9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D10D12C7-B877-423B-867D-161D99E673C9}.Release|Any CPU.Build.0 = Release|Any CPU + {0F2188D3-144C-41BF-89F6-AA85883AE0D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0F2188D3-144C-41BF-89F6-AA85883AE0D3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0F2188D3-144C-41BF-89F6-AA85883AE0D3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0F2188D3-144C-41BF-89F6-AA85883AE0D3}.Release|Any CPU.Build.0 = Release|Any CPU + {658BF141-B4B5-4B90-891D-AC36A3FD7574}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {658BF141-B4B5-4B90-891D-AC36A3FD7574}.Debug|Any CPU.Build.0 = Debug|Any CPU + {658BF141-B4B5-4B90-891D-AC36A3FD7574}.Release|Any CPU.ActiveCfg = Release|Any CPU + {658BF141-B4B5-4B90-891D-AC36A3FD7574}.Release|Any CPU.Build.0 = Release|Any CPU + {212A1C64-02FC-465A-B0FA-F69735F37ACC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {212A1C64-02FC-465A-B0FA-F69735F37ACC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {212A1C64-02FC-465A-B0FA-F69735F37ACC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {212A1C64-02FC-465A-B0FA-F69735F37ACC}.Release|Any CPU.Build.0 = Release|Any CPU + {243ACD5F-10AD-4BE6-9932-829667BE2053}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {243ACD5F-10AD-4BE6-9932-829667BE2053}.Debug|Any CPU.Build.0 = Debug|Any CPU + {243ACD5F-10AD-4BE6-9932-829667BE2053}.Release|Any CPU.ActiveCfg = Release|Any CPU + {243ACD5F-10AD-4BE6-9932-829667BE2053}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {1CD34A01-D19A-441F-8F3D-6EF69D9DDA8D} = {6DA2330B-D407-4FB1-AF05-B0184034EC44} + {F47E23C3-8415-4725-9E85-57271694DEB3} = {6DA2330B-D407-4FB1-AF05-B0184034EC44} + {913222CA-261F-49CB-A823-CC7C335F964A} = {64B34A6E-318D-4E6E-9262-CE52C9B85A38} + {9BE5D83D-EA90-4382-A132-174FD158227F} = {6DA2330B-D407-4FB1-AF05-B0184034EC44} + {801247D5-7EE5-49C8-AB26-F822A415BA49} = {64B34A6E-318D-4E6E-9262-CE52C9B85A38} + {1945EE8A-F105-43A9-91C9-8C4422B9873E} = {6DA2330B-D407-4FB1-AF05-B0184034EC44} + {AA011593-6603-4E16-A7B0-0ED3862511DE} = {64B34A6E-318D-4E6E-9262-CE52C9B85A38} + {6EFC7E7D-840E-4506-ADBC-37130A21D1C0} = {64B34A6E-318D-4E6E-9262-CE52C9B85A38} + {6DCF93BA-A918-42A0-BAD7-A11B72ADFFE6} = {6DA2330B-D407-4FB1-AF05-B0184034EC44} + {74EF1B45-C7B7-4281-BDDB-7A653F9F935E} = {6DA2330B-D407-4FB1-AF05-B0184034EC44} + {FDA13C07-2E22-49D5-A317-7A68DC359894} = {6DA2330B-D407-4FB1-AF05-B0184034EC44} + {EDC4FB2B-40CF-4AFD-90C7-CF88C2745789} = {64B34A6E-318D-4E6E-9262-CE52C9B85A38} + {9E1FF103-B5BD-44B6-B839-0E1FED2C49EC} = {64B34A6E-318D-4E6E-9262-CE52C9B85A38} + {03F4E6D0-CFE7-44A6-994B-778B3DF6532C} = {64B34A6E-318D-4E6E-9262-CE52C9B85A38} + {704935A5-68F2-4070-8A55-AFF8F66ACAD6} = {64B34A6E-318D-4E6E-9262-CE52C9B85A38} + {501F6D1E-6300-4CA4-8E61-3523BCF4D533} = {64B34A6E-318D-4E6E-9262-CE52C9B85A38} + {0C35D768-BF55-4BD9-B915-35125CED65A0} = {6DA2330B-D407-4FB1-AF05-B0184034EC44} + {4CC3AAC2-030B-4B2E-A386-9C1F68E42238} = {6DA2330B-D407-4FB1-AF05-B0184034EC44} + {1CA11165-4B70-41D2-A846-50374E85385E} = {64B34A6E-318D-4E6E-9262-CE52C9B85A38} + {5810EF87-4F85-4B4C-98E3-833AE914C628} = {64B34A6E-318D-4E6E-9262-CE52C9B85A38} + {D10D12C7-B877-423B-867D-161D99E673C9} = {64B34A6E-318D-4E6E-9262-CE52C9B85A38} + {0F2188D3-144C-41BF-89F6-AA85883AE0D3} = {64B34A6E-318D-4E6E-9262-CE52C9B85A38} + {658BF141-B4B5-4B90-891D-AC36A3FD7574} = {6DA2330B-D407-4FB1-AF05-B0184034EC44} + {212A1C64-02FC-465A-B0FA-F69735F37ACC} = {64B34A6E-318D-4E6E-9262-CE52C9B85A38} + {243ACD5F-10AD-4BE6-9932-829667BE2053} = {64B34A6E-318D-4E6E-9262-CE52C9B85A38} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {1E354DE6-99BA-421E-9EF8-E808B855A85F} + EndGlobalSection +EndGlobal diff --git a/src/ARCtrl/ARCtrl.Javascript.fsproj b/src/ARCtrl/ARCtrl.Javascript.fsproj index 4e464de5..6d8061e8 100644 --- a/src/ARCtrl/ARCtrl.Javascript.fsproj +++ b/src/ARCtrl/ARCtrl.Javascript.fsproj @@ -8,8 +8,7 @@ - - + @@ -50,11 +49,13 @@ + - + + diff --git a/src/ARCtrl/ContractIO/FileSystemHelper.fs b/src/ARCtrl/ContractIO/FileSystemHelper.fs index 969195e9..0e9c6201 100644 --- a/src/ARCtrl/ContractIO/FileSystemHelper.fs +++ b/src/ARCtrl/ContractIO/FileSystemHelper.fs @@ -1,49 +1,94 @@ module ARCtrl.FileSystemHelper open FsSpreadsheet + open CrossAsync +open Fable.Core +open Fable + +#if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT +open Fable.Core.JsInterop +open FsSpreadsheet.Js +#endif +#if !FABLE_COMPILER open FsSpreadsheet.Net +#endif -let directoryExistsAsync path = +let directoryExistsAsync (path : string) : CrossAsync = + #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT + import "directoryExists" "./FileSystem.js" + #endif + #if !FABLE_COMPILER crossAsync { return System.IO.Directory.Exists path } + #endif -let createDirectoryAsync path = +let createDirectoryAsync (path : string) : CrossAsync = + #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT + import "createDirectory" "./FileSystem.js" + #endif + #if !FABLE_COMPILER crossAsync { System.IO.Directory.CreateDirectory path |> ignore } + #endif -let ensureDirectoryAsync path = +let ensureDirectoryAsync (path : string) : CrossAsync = + #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT + import "ensureDirectory" "./FileSystem.js" + #endif + #if !FABLE_COMPILER crossAsync { let! exists = directoryExistsAsync path if not <| exists then return! createDirectoryAsync path } + #endif -let ensureDirectoryOfFileAsync (filePath : string) = +let ensureDirectoryOfFileAsync (filePath : string) : CrossAsync = + #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT + import "ensureDirectoryOfFile" "./FileSystem.js" + #endif + #if !FABLE_COMPILER crossAsync { let file = new System.IO.FileInfo(filePath); file.Directory.Create() } + #endif -let fileExistsAsync path = +let fileExistsAsync (path : string) : CrossAsync = + #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT + import "fileExists" "./FileSystem.js" + #endif + #if !FABLE_COMPILER crossAsync { return System.IO.File.Exists path } + #endif -let getSubDirectoriesAsync path = +let getSubDirectoriesAsync (path : string) : CrossAsync = + #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT + import "getSubDirectories" "./FileSystem.js" + #endif + #if !FABLE_COMPILER crossAsync { return System.IO.Directory.GetDirectories path } + #endif -let getSubFilesAsync path = +let getSubFilesAsync (path : string) : CrossAsync = + #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT + import "getSubFiles" "./FileSystem.js" + #endif + #if !FABLE_COMPILER crossAsync { return System.IO.Directory.GetFiles path } + #endif /// Return the absolute path relative to the directoryPath -let makeRelative directoryPath (path : string) = +let makeRelative directoryPath (path : string) : string = if directoryPath = "." || directoryPath = "/" || directoryPath = "" then path else @@ -53,10 +98,10 @@ let makeRelative directoryPath (path : string) = -let standardizeSlashes (path : string) = +let standardizeSlashes (path : string) : string = path.Replace("\\","/") -let getAllFilePathsAsync (directoryPath : string) = +let getAllFilePathsAsync (directoryPath : string) : CrossAsync = crossAsync { let rec allFiles (dirs : string seq) : CrossAsync = crossAsync { @@ -79,22 +124,26 @@ let getAllFilePathsAsync (directoryPath : string) = return allFilesRelative } -let readFileTextAsync path : Async = +let readFileTextAsync (path : string) : CrossAsync = crossAsync { return System.IO.File.ReadAllText path } -let readFileBinaryAsync path : Async = +let readFileBinaryAsync (path : string) : CrossAsync = crossAsync { return System.IO.File.ReadAllBytes path } -let readFileXlsxAsync path : Async = +let readFileXlsxAsync (path : string) : CrossAsync = + #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT + FsWorkbook.fromXlsxFile path + #else crossAsync { return FsWorkbook.fromXlsxFile path } + #endif -let renameFileOrDirectoryAsync oldPath newPath = +let renameFileOrDirectoryAsync oldPath newPath : CrossAsync = crossAsync { let! fileExists = fileExistsAsync oldPath let! directoryExists = directoryExistsAsync oldPath @@ -105,22 +154,27 @@ let renameFileOrDirectoryAsync oldPath newPath = else () } -let writeFileTextAsync path text = +let writeFileTextAsync (path : string) text : CrossAsync = crossAsync { System.IO.File.WriteAllText(path, text) } -let writeFileBinaryAsync path (bytes : byte []) = +let writeFileBinaryAsync (path : string) (bytes : byte []) : CrossAsync = crossAsync { System.IO.File.WriteAllBytes(path, bytes) } -let writeFileXlsxAsync path (wb : FsWorkbook) = +let writeFileXlsxAsync (path : string) (wb : FsWorkbook) : CrossAsync = + #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT + FsWorkbook.toXlsxFile path wb + #else crossAsync { - FsWorkbook.toXlsxFile path wb + return FsWorkbook.toXlsxFile path wb } + #endif + -let deleteFileOrDirectoryAsync path = +let deleteFileOrDirectoryAsync (path : string) : CrossAsync = crossAsync { let! fileExists = fileExistsAsync path let! directoryExists = directoryExistsAsync path diff --git a/src/ARCtrl/ContractIO/FileSystemHelper.js.fs b/src/ARCtrl/ContractIO/FileSystemHelper.js.fs deleted file mode 100644 index fe63bba9..00000000 --- a/src/ARCtrl/ContractIO/FileSystemHelper.js.fs +++ /dev/null @@ -1,80 +0,0 @@ -module ARCtrl.FileSystemHelper - -open FsSpreadsheet - -open FsSpreadsheet.Js - -let directoryExists path = - System.IO.Directory.Exists path - -let createDirectory path = - System.IO.Directory.CreateDirectory path |> ignore - -let ensureDirectory path = - if not <| directoryExists path then - createDirectory path - -let ensureDirectoryOfFile (filePath : string) = - let file = new System.IO.FileInfo(filePath); - file.Directory.Create() - -let fileExists path = - System.IO.File.Exists path - -let getSubDirectories path = - System.IO.Directory.GetDirectories path - -let getSubFiles path = - System.IO.Directory.GetFiles path - -/// Return the absolute path relative to the directoryPath -let makeRelative directoryPath (path : string) = - if directoryPath = "." || directoryPath = "/" || directoryPath = "" then path - else - if path.StartsWith(directoryPath) then - path.Substring(directoryPath.Length) - else path - -let standardizeSlashes (path : string) = - path.Replace("\\","/") - -let getAllFilePaths (directoryPath : string) = - let rec allFiles dirs = - if Seq.isEmpty dirs then Seq.empty else - seq { yield! dirs |> Seq.collect getSubFiles - yield! dirs |> Seq.collect getSubDirectories |> allFiles } - - allFiles [directoryPath] |> Seq.toArray - |> Array.map (makeRelative directoryPath >> standardizeSlashes) - -let readFileText path : string = - System.IO.File.ReadAllText path - -let readFileBinary path : byte [] = - System.IO.File.ReadAllBytes path - -let readFileXlsx path : FsWorkbook = - FsWorkbook.fromXlsxFile path - -let renameFileOrDirectory oldPath newPath = - if fileExists oldPath then - System.IO.File.Move(oldPath, newPath) - elif directoryExists oldPath then - System.IO.Directory.Move(oldPath, newPath) - else () - -let writeFileText path text = - System.IO.File.WriteAllText(path, text) - -let writeFileBinary path (bytes : byte []) = - System.IO.File.WriteAllBytes(path,bytes) - -let writeFileXlsx path (wb : FsWorkbook) = - FsWorkbook.toXlsxFile path wb - -let deleteFileOrDirectory path = - if fileExists path then - System.IO.File.Delete path - elif directoryExists path then - System.IO.Directory.Delete(path, true) - else () \ No newline at end of file diff --git a/src/ARCtrl/ContractIO/FilesSystem.js b/src/ARCtrl/ContractIO/FilesSystem.js new file mode 100644 index 00000000..956f0340 --- /dev/null +++ b/src/ARCtrl/ContractIO/FilesSystem.js @@ -0,0 +1,95 @@ +const fs = require('fs/promises'); +const pathModule = require('path'); +const fsSync = require('fs'); // For synchronous checks like `existsSync` + +// Check if a directory exists +async function directoryExists(path) { + try { + const stats = await fs.stat(path); + return stats.isDirectory(); + } catch (err) { + if (err.code === 'ENOENT') return false; + throw err; + } +} + +// Create a directory +async function createDirectory(path) { + await fs.mkdir(path, { recursive: true }); +} + +// Ensure a directory exists +async function ensureDirectory(path) { + if (!(await directoryExists(path))) { + await createDirectory(path); + } +} + +// Ensure the directory for a file exists +async function ensureDirectoryOfFile(filePath) { + const dir = pathModule.dirname(filePath); + await ensureDirectory(dir); +} + +// Check if a file exists +async function fileExists(path) { + try { + const stats = await fs.stat(path); + return stats.isFile(); + } catch (err) { + if (err.code === 'ENOENT') return false; + throw err; + } +} + +// Get subdirectories in a directory +async function getSubDirectories(path) { + const entries = await fs.readdir(path, { withFileTypes: true }); + return entries.filter(entry => entry.isDirectory()).map(entry => entry.name); +} + +// Get files in a directory +async function getSubFiles(path) { + const entries = await fs.readdir(path, { withFileTypes: true }); + return entries.filter(entry => entry.isFile()).map(entry => entry.name); +} + +// Move a file +async function moveFile(oldPath, newPath) { + await fs.rename(oldPath, newPath); +} + +// Move a directory +async function moveDirectory(oldPath, newPath) { + await fs.rename(oldPath, newPath); +} + +// Delete a file +async function deleteFile(path) { + await fs.unlink(path); +} + +// Delete a directory (and its contents) +async function deleteDirectory(path) { + await fs.rm(path, { recursive: true, force: true }); +} + +// Read file as text +async function readFileText(path) { + return await fs.readFile(path, 'utf-8'); +} + +// Read file as binary +async function readFileBinary(path) { + return await fs.readFile(path); +} + +// Write text to a file +async function writeFileText(path, text) { + await fs.writeFile(path, text, 'utf-8'); +} + +// Write binary data to a file +async function writeFileBinary(path, bytes) { + await fs.writeFile(path, bytes); +} \ No newline at end of file diff --git a/src/ARCtrl/Template.Web.fs b/src/ARCtrl/Template.Web.fs index f7437b20..ab01afdb 100644 --- a/src/ARCtrl/Template.Web.fs +++ b/src/ARCtrl/Template.Web.fs @@ -8,7 +8,7 @@ let getTemplates(url: string option) = let defaultURL = @"https://github.com/nfdi4plants/Swate-templates/releases/download/latest/templates_v2.0.0.json" let url = defaultArg url defaultURL - crossAsync { + async { let! jsonString = ARCtrl.WebRequest.downloadFile url let mapResult = Json.Templates.fromJsonString jsonString return mapResult diff --git a/src/ARCtrl/Xlsx.fs b/src/ARCtrl/Xlsx.fs index 1426c7a9..b9a4476e 100644 --- a/src/ARCtrl/Xlsx.fs +++ b/src/ARCtrl/Xlsx.fs @@ -9,6 +9,9 @@ open FsSpreadsheet #if !FABLE_COMPILER open FsSpreadsheet.Net #endif +#if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT +open FsSpreadsheet.Js +#endif module XlsxHelper = @@ -16,21 +19,21 @@ module XlsxHelper = type DatamapXlsx() = member _.fromFsWorkbook (fswb: FsWorkbook) = DataMap.fromFsWorkbook fswb member _.toFsWorkbook (datamap: DataMap) = DataMap.toFsWorkbook datamap - member _.fromXlsxFile (path: string) = FsWorkbook.fromXlsxFile path |> DataMap.fromFsWorkbook + //member _.fromXlsxFile (path: string) = FsWorkbook.fromXlsxFile path |> DataMap.fromFsWorkbook member _.toXlsxFile (path: string, datamap: DataMap) = DataMap.toFsWorkbook datamap |> FsWorkbook.toXlsxFile path [] type AssayXlsx() = member _.fromFsWorkbook (fswb: FsWorkbook) = ArcAssay.fromFsWorkbook fswb member _.toFsWorkbook (assay: ArcAssay) = ArcAssay.toFsWorkbook assay - member _.fromXlsxFile (path: string) = FsWorkbook.fromXlsxFile path |> ArcAssay.fromFsWorkbook + //member _.fromXlsxFile (path: string) = FsWorkbook.fromXlsxFile path |> ArcAssay.fromFsWorkbook member _.toXlsxFile (path: string, assay: ArcAssay) = ArcAssay.toFsWorkbook assay |> FsWorkbook.toXlsxFile path [] type StudyXlsx() = member _.fromFsWorkbook (fswb: FsWorkbook) = ArcStudy.fromFsWorkbook fswb member _.toFsWorkbook (study: ArcStudy, ?assays: ResizeArray) = ArcStudy.toFsWorkbook(study,?assays=Option.map List.ofSeq assays) - member _.fromXlsxFile (path: string) = FsWorkbook.fromXlsxFile path |> ArcStudy.fromFsWorkbook + //member _.fromXlsxFile (path: string) = FsWorkbook.fromXlsxFile path |> ArcStudy.fromFsWorkbook member _.toXlsxFile (path: string, study: ArcStudy, ?assays: ResizeArray) = ArcStudy.toFsWorkbook(study,?assays=Option.map List.ofSeq assays) |> FsWorkbook.toXlsxFile path @@ -38,7 +41,7 @@ module XlsxHelper = type InvestigationXlsx() = member _.fromFsWorkbook (fswb: FsWorkbook) = ArcInvestigation.fromFsWorkbook fswb member _.toFsWorkbook (investigation: ArcInvestigation) = ArcInvestigation.toFsWorkbook(investigation) - member _.fromXlsxFile (path: string) = FsWorkbook.fromXlsxFile path |> ArcInvestigation.fromFsWorkbook + //member _.fromXlsxFile (path: string) = FsWorkbook.fromXlsxFile path |> ArcInvestigation.fromFsWorkbook member _.toXlsxFile (path: string, investigation: ArcInvestigation) = ArcInvestigation.toFsWorkbook(investigation) |> FsWorkbook.toXlsxFile path open XlsxHelper diff --git a/tests/ARCtrl/FileSystemHelper.Tests.fs b/tests/ARCtrl/FileSystemHelper.Tests.fs index 24c92cbc..420223af 100644 --- a/tests/ARCtrl/FileSystemHelper.Tests.fs +++ b/tests/ARCtrl/FileSystemHelper.Tests.fs @@ -2,7 +2,6 @@ module ARCtrl.FileSystemHelper.Tests open TestingUtils open ARCtrl -open System.Text.Json open CrossAsync let readFileText = From a5c195bbac29df77ad7d0a5bba17a81108a8b3ba Mon Sep 17 00:00:00 2001 From: HLWeil Date: Mon, 25 Nov 2024 16:00:45 +0100 Subject: [PATCH 15/30] some cleanup for js fs IO --- src/ARCtrl/ARCtrl.Javascript.fsproj | 4 +- src/ARCtrl/ContractIO/FileSystemHelper.fs | 157 +++++++++++++------ src/ARCtrl/ContractIO/FileSystemHelper.py.fs | 80 ---------- 3 files changed, 113 insertions(+), 128 deletions(-) delete mode 100644 src/ARCtrl/ContractIO/FileSystemHelper.py.fs diff --git a/src/ARCtrl/ARCtrl.Javascript.fsproj b/src/ARCtrl/ARCtrl.Javascript.fsproj index 6d8061e8..28df7640 100644 --- a/src/ARCtrl/ARCtrl.Javascript.fsproj +++ b/src/ARCtrl/ARCtrl.Javascript.fsproj @@ -53,8 +53,8 @@ - - + + diff --git a/src/ARCtrl/ContractIO/FileSystemHelper.fs b/src/ARCtrl/ContractIO/FileSystemHelper.fs index 0e9c6201..520489d8 100644 --- a/src/ARCtrl/ContractIO/FileSystemHelper.fs +++ b/src/ARCtrl/ContractIO/FileSystemHelper.fs @@ -1,6 +1,7 @@ module ARCtrl.FileSystemHelper open FsSpreadsheet +open CrossAsync open CrossAsync open Fable.Core @@ -87,8 +88,109 @@ let getSubFilesAsync (path : string) : CrossAsync = } #endif +let readFileTextAsync (path : string) : CrossAsync = + #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT + import "readFileText" "./FileSystem.js" + #endif + #if !FABLE_COMPILER + crossAsync { + return System.IO.File.ReadAllText path + } + #endif + +let readFileBinaryAsync (path : string) : CrossAsync = + #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT + import "readFileBinary" "./FileSystem.js" + #endif + #if !FABLE_COMPILER + crossAsync { + return System.IO.File.ReadAllBytes path + } + #endif + +let readFileXlsxAsync (path : string) : CrossAsync = + #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT + FsWorkbook.fromXlsxFile path + #else + crossAsync { + return FsWorkbook.fromXlsxFile path + } + #endif + + +let moveFileAsync oldPath newPath = + #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT + import "moveFile" "./FileSystem.js" + #endif + #if !FABLE_COMPILER + crossAsync { + System.IO.File.Move(oldPath, newPath) + } + #endif + +let moveDirectoryAsync oldPath newPath = + #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT + import "moveDirectory" "./FileSystem.js" + #endif + #if !FABLE_COMPILER + crossAsync { + System.IO.Directory.Move(oldPath, newPath) + } + #endif + +let deleteFileAsync path = + #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT + import "deleteFile" "./FileSystem.js" + #endif + #if !FABLE_COMPILER + crossAsync { + System.IO.File.Delete path + } + #endif + +let deleteDirectoryAsync path = + #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT + import "deleteDirectory" "./FileSystem.js" + #endif + #if !FABLE_COMPILER + crossAsync { + System.IO.Directory.Delete(path, true) + } + #endif + + +let writeFileTextAsync path text = + #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT + import "writeFileText" "./FileSystem.js" + #endif + #if !FABLE_COMPILER + crossAsync { + System.IO.File.WriteAllText(path, text) + } + #endif + +let writeFileBinaryAsync path (bytes : byte []) = + #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT + import "writeFileBinary" "./FileSystem.js" + #endif + #if !FABLE_COMPILER + crossAsync { + System.IO.File.WriteAllBytes(path, bytes) + } + #endif + +let writeFileXlsxAsync path (wb : FsWorkbook) = + #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT + FsWorkbook.toXlsxFile path wb + #else + crossAsync { + FsWorkbook.toXlsxFile path wb + } + #endif + + /// Return the absolute path relative to the directoryPath -let makeRelative directoryPath (path : string) : string = +let makeRelative directoryPath (path : string) = if directoryPath = "." || directoryPath = "/" || directoryPath = "" then path else @@ -98,10 +200,10 @@ let makeRelative directoryPath (path : string) : string = -let standardizeSlashes (path : string) : string = +let standardizeSlashes (path : string) = path.Replace("\\","/") -let getAllFilePathsAsync (directoryPath : string) : CrossAsync = +let getAllFilePathsAsync (directoryPath : string) = crossAsync { let rec allFiles (dirs : string seq) : CrossAsync = crossAsync { @@ -124,63 +226,26 @@ let getAllFilePathsAsync (directoryPath : string) : CrossAsync = return allFilesRelative } -let readFileTextAsync (path : string) : CrossAsync = - crossAsync { - return System.IO.File.ReadAllText path - } - -let readFileBinaryAsync (path : string) : CrossAsync = - crossAsync { - return System.IO.File.ReadAllBytes path - } - -let readFileXlsxAsync (path : string) : CrossAsync = - #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT - FsWorkbook.fromXlsxFile path - #else - crossAsync { - return FsWorkbook.fromXlsxFile path - } - #endif -let renameFileOrDirectoryAsync oldPath newPath : CrossAsync = +let renameFileOrDirectoryAsync oldPath newPath = crossAsync { let! fileExists = fileExistsAsync oldPath let! directoryExists = directoryExistsAsync oldPath if fileExists then - System.IO.File.Move(oldPath, newPath) + return! moveFileAsync oldPath newPath elif directoryExists then - System.IO.Directory.Move(oldPath, newPath) + return! moveDirectoryAsync oldPath newPath else () } -let writeFileTextAsync (path : string) text : CrossAsync = - crossAsync { - System.IO.File.WriteAllText(path, text) - } - -let writeFileBinaryAsync (path : string) (bytes : byte []) : CrossAsync = - crossAsync { - System.IO.File.WriteAllBytes(path, bytes) - } - -let writeFileXlsxAsync (path : string) (wb : FsWorkbook) : CrossAsync = - #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT - FsWorkbook.toXlsxFile path wb - #else - crossAsync { - return FsWorkbook.toXlsxFile path wb - } - #endif - -let deleteFileOrDirectoryAsync (path : string) : CrossAsync = +let deleteFileOrDirectoryAsync path = crossAsync { let! fileExists = fileExistsAsync path let! directoryExists = directoryExistsAsync path if fileExists then - System.IO.File.Delete path + return! deleteFileAsync path elif directoryExists then - System.IO.Directory.Delete(path, true) + return! deleteDirectoryAsync path else () } \ No newline at end of file diff --git a/src/ARCtrl/ContractIO/FileSystemHelper.py.fs b/src/ARCtrl/ContractIO/FileSystemHelper.py.fs deleted file mode 100644 index ccb1c7c7..00000000 --- a/src/ARCtrl/ContractIO/FileSystemHelper.py.fs +++ /dev/null @@ -1,80 +0,0 @@ -module ARCtrl.FileSystemHelper - -open FsSpreadsheet - -open FsSpreadsheet.Net - -let directoryExists path = - System.IO.Directory.Exists path - -let createDirectory path = - System.IO.Directory.CreateDirectory path |> ignore - -let ensureDirectory path = - if not <| directoryExists path then - createDirectory path - -let ensureDirectoryOfFile (filePath : string) = - let file = new System.IO.FileInfo(filePath); - file.Directory.Create() - -let fileExists path = - System.IO.File.Exists path - -let getSubDirectories path = - System.IO.Directory.GetDirectories path - -let getSubFiles path = - System.IO.Directory.GetFiles path - -/// Return the absolute path relative to the directoryPath -let makeRelative directoryPath (path : string) = - if directoryPath = "." || directoryPath = "/" || directoryPath = "" then path - else - if path.StartsWith(directoryPath) then - path.Substring(directoryPath.Length) - else path - -let standardizeSlashes (path : string) = - path.Replace("\\","/") - -let getAllFilePaths (directoryPath : string) = - let rec allFiles dirs = - if Seq.isEmpty dirs then Seq.empty else - seq { yield! dirs |> Seq.collect getSubFiles - yield! dirs |> Seq.collect getSubDirectories |> allFiles } - - allFiles [directoryPath] |> Seq.toArray - |> Array.map (makeRelative directoryPath >> standardizeSlashes) - -let readFileText path : string = - System.IO.File.ReadAllText path - -let readFileBinary path : byte [] = - System.IO.File.ReadAllBytes path - -let readFileXlsx path : FsWorkbook = - FsWorkbook.fromXlsxFile path - -let renameFileOrDirectory oldPath newPath = - if fileExists oldPath then - System.IO.File.Move(oldPath, newPath) - elif directoryExists oldPath then - System.IO.Directory.Move(oldPath, newPath) - else () - -let writeFileText path text = - System.IO.File.WriteAllText(path, text) - -let writeFileBinary path (bytes : byte []) = - System.IO.File.WriteAllBytes(path,bytes) - -let writeFileXlsx path (wb : FsWorkbook) = - FsWorkbook.toXlsxFile path wb - -let deleteFileOrDirectory path = - if fileExists path then - System.IO.File.Delete path - elif directoryExists path then - System.IO.Directory.Delete(path, true) - else () \ No newline at end of file From e72c01e93e8640ba589ac93896927d4705078968 Mon Sep 17 00:00:00 2001 From: Heinrich Lukas Weil Date: Thu, 21 Nov 2024 23:42:56 +0100 Subject: [PATCH 16/30] some more fixes for js file io --- src/ARCtrl/CrossAsync.fs | 9 ++++++++- tests/ARCtrl/ARCtrl.Tests.fs | 18 +++++++++--------- tests/ARCtrl/ContractIO.Tests.fs | 17 +++++++++-------- tests/ARCtrl/FileSystemHelper.Tests.fs | 8 ++++---- tests/ARCtrl/Template.Tests.fs | 2 +- tests/CWL/ARCtrl.CWL.Tests.fsproj | 1 - tests/Json/ARCtrl.Json.Tests.fsproj | 1 - tests/TestingUtils/TestingUtils.fs | 12 +++++++++++- tests/TestingUtils/TestingUtils.fsproj | 2 +- 9 files changed, 43 insertions(+), 27 deletions(-) diff --git a/src/ARCtrl/CrossAsync.fs b/src/ARCtrl/CrossAsync.fs index cfb6803c..8bac33f3 100644 --- a/src/ARCtrl/CrossAsync.fs +++ b/src/ARCtrl/CrossAsync.fs @@ -28,4 +28,11 @@ let map f v = crossAsync { let! v = v return f v - } \ No newline at end of file + } + +let asAsync (v:CrossAsync<'T>) = + #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT + Async.AwaitPromise v + #else + v + #endif \ No newline at end of file diff --git a/tests/ARCtrl/ARCtrl.Tests.fs b/tests/ARCtrl/ARCtrl.Tests.fs index 14db5194..5beb8e13 100644 --- a/tests/ARCtrl/ARCtrl.Tests.fs +++ b/tests/ARCtrl/ARCtrl.Tests.fs @@ -947,7 +947,7 @@ let tests_GetStudyRenameContracts = testList "GetStudyRenameContracts" [ let tests_load = testList "Load" [ - testCaseAsync "simpleARC" (crossAsync { + testCaseCrossAsync "simpleARC" (crossAsync { let p = TestObjects.IO.testSimpleARC let! result = ARC.loadAsync(p) let result = Expect.wantOk result "ARC should load successfully" @@ -975,7 +975,7 @@ let tests_load = let tests_write = testList "Write" [ - testCaseAsync "empty" (crossAsync { + testCaseCrossAsync "empty" (crossAsync { let p = ArcPathHelper.combine TestObjects.IO.testResultsFolder "ARC_Write_Empty" let a = ARC() @@ -1000,7 +1000,7 @@ let tests_write = Expect.sequenceEqual paths expectedPaths "Files were not created correctly." }) - testCaseAsync "SimpleARC" (crossAsync { + testCaseCrossAsync "SimpleARC" (crossAsync { let p = ArcPathHelper.combine TestObjects.IO.testResultsFolder "ARC_Write_SimpleARC" let arc = ARC() @@ -1043,7 +1043,7 @@ let tests_write = Expect.sequenceEqual paths expectedPaths "Files were not created correctly." }) // This test reads a preexisting assay with data and everything, data content is not copied though but just the - testCaseAsync "LoadSimpleARCAndAddAssay" (crossAsync { + testCaseCrossAsync "LoadSimpleARCAndAddAssay" (crossAsync { let p = ArcPathHelper.combine TestObjects.IO.testResultsFolder "ARC_Write_SimpleARCWithAssay" let! readResult = ARC.loadAsync(TestObjects.IO.testSimpleARC) @@ -1116,7 +1116,7 @@ let tests_write = let tests_Update = testList "Update" [ - testCaseAsync "AddedAssay" (crossAsync { + testCaseCrossAsync "AddedAssay" (crossAsync { let p = ArcPathHelper.combine TestObjects.IO.testResultsFolder "ARC_Update_AddedAssay" let arc = ARC() @@ -1179,7 +1179,7 @@ let tests_Update = let tests_renameAssay = testList "RenameAssay" [ - testCaseAsync "SimpleARC" (crossAsync { + testCaseCrossAsync "SimpleARC" (crossAsync { let p = ArcPathHelper.combine TestObjects.IO.testResultsFolder "ARC_RenameAssay_SimpleARC" let arc = ARC() @@ -1232,7 +1232,7 @@ let tests_renameAssay = let tests_RenameStudy = testList "RenameStudy" [ - testCaseAsync "SimpleARC" (crossAsync { + testCaseCrossAsync "SimpleARC" (crossAsync { let p = ArcPathHelper.combine TestObjects.IO.testResultsFolder "ARC_RenameStudy_SimpleARC" let arc = ARC() @@ -1286,7 +1286,7 @@ let tests_RenameStudy = let tests_RemoveAssay = testList "RemoveAssay" [ - testCaseAsync "SimpleARC" (crossAsync { + testCaseCrossAsync "SimpleARC" (crossAsync { let p = ArcPathHelper.combine TestObjects.IO.testResultsFolder "ARC_RemoveAssay_SimpleARC" let arc = ARC() @@ -1334,7 +1334,7 @@ let tests_RemoveAssay = let tests_RemoveStudy = testList "RemoveStudy" [ - testCaseAsync "SimpleARC" (crossAsync { + testCaseCrossAsync "SimpleARC" (crossAsync { let p = ArcPathHelper.combine TestObjects.IO.testResultsFolder "ARC_RemoveStudy_SimpleARC" let arc = ARC() diff --git a/tests/ARCtrl/ContractIO.Tests.fs b/tests/ARCtrl/ContractIO.Tests.fs index 4248d1d5..52e0cc13 100644 --- a/tests/ARCtrl/ContractIO.Tests.fs +++ b/tests/ARCtrl/ContractIO.Tests.fs @@ -5,13 +5,12 @@ open ARCtrl open ARCtrl.Contract open ARCtrl.FileSystemHelper open FsSpreadsheet -open FsSpreadsheet.Net open CrossAsync let testRead = testList "Read" [ - testCaseAsync "TextFile" (crossAsync { + testCaseCrossAsync "TextFile" (crossAsync { let fileName = "TestReadMe.txt" let contract = Contract.createRead(fileName,DTOType.PlainText) let dto = DTO.Text "This is a test" @@ -21,7 +20,7 @@ let testRead = let resultContract = Expect.wantOk result "Contract was not fulfilled correctly" Expect.equal resultContract expected $"Text was not read correctly" }) - testCaseAsync "XLSXFile" (crossAsync { + testCaseCrossAsync "XLSXFile" (crossAsync { let fileName = "TestWorkbook.xlsx" let contract = Contract.createRead(fileName,DTOType.ISA_Study) let! result = fulfillReadContractAsync TestObjects.IO.testContractsFolder contract @@ -44,7 +43,7 @@ let testRead = let testWrite = testList "Write" [ - testCaseAsync "TextFileEmpty" (crossAsync { + testCaseCrossAsync "TextFileEmpty" (crossAsync { let fileName = "TestEmpty.txt" let contract = Contract.createCreate(fileName,DTOType.PlainText) @@ -55,11 +54,12 @@ let testWrite = Expect.isOk resultContract "Contract was not fulfilled correctly" let filePath = ArcPathHelper.combine TestObjects.IO.testResultsFolder fileName - Expect.isTrue (System.IO.File.Exists filePath) $"File {filePath} was not created" + let! fileExists = FileSystemHelper.fileExistsAsync filePath + Expect.isTrue fileExists $"File {filePath} was not created" let! resultText = FileSystemHelper.readFileTextAsync filePath Expect.equal resultText "" $"File {filePath} was not empty" }) - testCaseAsync "TextFile" (crossAsync { + testCaseCrossAsync "TextFile" (crossAsync { let testText = "This is a test" let fileName = "TestReadMe.txt" let dto = DTO.Text testText @@ -72,12 +72,13 @@ let testWrite = Expect.isOk resultContract "Contract was not fulfilled correctly" let filePath = ArcPathHelper.combine TestObjects.IO.testResultsFolder fileName - Expect.isTrue (System.IO.File.Exists filePath) $"File {filePath} was not created" + let! fileExists = FileSystemHelper.fileExistsAsync filePath + Expect.isTrue fileExists $"File {filePath} was not created" let! resultText = FileSystemHelper.readFileTextAsync filePath Expect.equal resultText testText $"File {filePath} was not empty" }) - testCaseAsync "XLSXFile" (crossAsync { + testCaseCrossAsync "XLSXFile" (crossAsync { let worksheetName = "TestSheet" let testWB = new FsWorkbook() diff --git a/tests/ARCtrl/FileSystemHelper.Tests.fs b/tests/ARCtrl/FileSystemHelper.Tests.fs index 420223af..77d348e2 100644 --- a/tests/ARCtrl/FileSystemHelper.Tests.fs +++ b/tests/ARCtrl/FileSystemHelper.Tests.fs @@ -6,7 +6,7 @@ open CrossAsync let readFileText = testList "ReadText" [ - testCaseAsync "simple" (crossAsync { + testCaseCrossAsync "simple" (crossAsync { let p = TestObjects.IO.simpleTextFilePath let! result = FileSystemHelper.readFileTextAsync p let expected = "Hello" @@ -16,7 +16,7 @@ let readFileText = let writeFileText = testList "WriteText" [ - testCaseAsync "simple" (crossAsync { + testCaseCrossAsync "simple" (crossAsync { do! ARCtrl.FileSystemHelper.ensureDirectoryAsync TestObjects.IO.testResultsFolder let p = ArcPathHelper.combine TestObjects.IO.testResultsFolder "SimpleText.txt" let t = "Hello" @@ -26,7 +26,7 @@ let writeFileText = let expected = "Hello" Expect.equal result expected "Text was not read correctly." }) - testCaseAsync "SubDirectoryWithEnsureDir" (crossAsync { + testCaseCrossAsync "SubDirectoryWithEnsureDir" (crossAsync { let subDir = ArcPathHelper.combine TestObjects.IO.testResultsFolder "SubFolder" let p = ArcPathHelper.combine subDir "SimpleText.txt" let t = "Hello" @@ -42,7 +42,7 @@ let writeFileText = let getAllFilePaths = testList "GetAllFilePaths" [ - testCaseAsync "simple" (crossAsync { + testCaseCrossAsync "simple" (crossAsync { let p = TestObjects.IO.testSubPathsFolder let! result = FileSystemHelper.getAllFilePathsAsync p diff --git a/tests/ARCtrl/Template.Tests.fs b/tests/ARCtrl/Template.Tests.fs index 3e7e062f..f5078cb2 100644 --- a/tests/ARCtrl/Template.Tests.fs +++ b/tests/ARCtrl/Template.Tests.fs @@ -9,7 +9,7 @@ open CrossAsync open TestingUtils let private tests_Web = testList "Web" [ - testCaseAsync "getTemplates" <| crossAsync { + testCaseAsync "getTemplates" <| async { let! templatesMap = ARCtrl.Template.Web.getTemplates(None) Expect.isTrue (templatesMap.Length > 0) "Count > 0" } diff --git a/tests/CWL/ARCtrl.CWL.Tests.fsproj b/tests/CWL/ARCtrl.CWL.Tests.fsproj index 495bc135..26b6824f 100644 --- a/tests/CWL/ARCtrl.CWL.Tests.fsproj +++ b/tests/CWL/ARCtrl.CWL.Tests.fsproj @@ -16,7 +16,6 @@ - \ No newline at end of file diff --git a/tests/Json/ARCtrl.Json.Tests.fsproj b/tests/Json/ARCtrl.Json.Tests.fsproj index 2800691e..fa5116c4 100644 --- a/tests/Json/ARCtrl.Json.Tests.fsproj +++ b/tests/Json/ARCtrl.Json.Tests.fsproj @@ -43,7 +43,6 @@ - diff --git a/tests/TestingUtils/TestingUtils.fs b/tests/TestingUtils/TestingUtils.fs index fec190fe..5fe9af64 100644 --- a/tests/TestingUtils/TestingUtils.fs +++ b/tests/TestingUtils/TestingUtils.fs @@ -241,6 +241,8 @@ module Expect = [] module Test = + open CrossAsync + let test = test let testAsync = testAsync let testSequenced = testSequenced @@ -248,10 +250,18 @@ module Test = let testCase = testCase let ptestCase = ptestCase let ftestCase = ftestCase + + + let testCaseCrossAsync (text : string) (ca : CrossAsync) = + testCaseAsync text (asAsync ca) + let ptestCaseCrossAsync (text : string) (ca : CrossAsync) = + ptestCaseAsync text (asAsync ca) + let ftestCaseCrossAsync (text : string) (ca : CrossAsync) = + ftestCaseAsync text (asAsync ca) + let testCaseAsync = testCaseAsync let ptestCaseAsync = ptestCaseAsync let ftestCaseAsync = ftestCaseAsync - let testList = testList let ftestList = ftestList \ No newline at end of file diff --git a/tests/TestingUtils/TestingUtils.fsproj b/tests/TestingUtils/TestingUtils.fsproj index 104e825d..642b6a6b 100644 --- a/tests/TestingUtils/TestingUtils.fsproj +++ b/tests/TestingUtils/TestingUtils.fsproj @@ -41,7 +41,7 @@ - + From 7bc9e5aa2c75e325f2ec0946e68c58cb703007ea Mon Sep 17 00:00:00 2001 From: Heinrich Lukas Weil Date: Thu, 21 Nov 2024 23:55:57 +0100 Subject: [PATCH 17/30] add exceljs requirement and fix fileysystem helper file name --- src/ARCtrl/ARCtrl.Javascript.fsproj | 5 ++++- src/ARCtrl/ContractIO/{FilesSystem.js => FileSystem.js} | 0 2 files changed, 4 insertions(+), 1 deletion(-) rename src/ARCtrl/ContractIO/{FilesSystem.js => FileSystem.js} (100%) diff --git a/src/ARCtrl/ARCtrl.Javascript.fsproj b/src/ARCtrl/ARCtrl.Javascript.fsproj index 28df7640..ce644ee1 100644 --- a/src/ARCtrl/ARCtrl.Javascript.fsproj +++ b/src/ARCtrl/ARCtrl.Javascript.fsproj @@ -54,7 +54,7 @@ - + @@ -76,6 +76,9 @@ + + + \ No newline at end of file diff --git a/src/ARCtrl/ContractIO/FilesSystem.js b/src/ARCtrl/ContractIO/FileSystem.js similarity index 100% rename from src/ARCtrl/ContractIO/FilesSystem.js rename to src/ARCtrl/ContractIO/FileSystem.js From 1929830192327704f2e72b250f61678b66ce16a0 Mon Sep 17 00:00:00 2001 From: HLWeil Date: Fri, 22 Nov 2024 16:42:28 +0100 Subject: [PATCH 18/30] further fixes for js file io --- package-lock.json | 1421 +++++++++++++++++++-- package.json | 1 + src/ARCtrl/ARCtrl.Javascript.fsproj | 7 +- src/ARCtrl/ContractIO/FileSystem.js | 48 +- src/ARCtrl/ContractIO/FileSystemHelper.fs | 47 +- tests/ARCtrl/FileSystemHelper.Tests.fs | 30 + tests/TestingUtils/TestingUtils.fsproj | 2 +- 7 files changed, 1425 insertions(+), 131 deletions(-) diff --git a/package-lock.json b/package-lock.json index ffe1d638..646a45da 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,6 +6,7 @@ "packages": { "": { "dependencies": { + "@nfdi4plants/exceljs": "^0.3.0", "fable-library": "^1.1.1", "isomorphic-fetch": "^3.0.0", "jsonschema": "^1.4.1" @@ -441,18 +442,62 @@ "node": ">=12" } }, + "node_modules/@fast-csv/format": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/@fast-csv/format/-/format-4.3.5.tgz", + "integrity": "sha512-8iRn6QF3I8Ak78lNAa+Gdl5MJJBM5vRHivFtMRUWINdevNo00K7OXxS2PshawLKTejVwieIlPmK5YlLu6w4u8A==", + "dependencies": { + "@types/node": "^14.0.1", + "lodash.escaperegexp": "^4.1.2", + "lodash.isboolean": "^3.0.3", + "lodash.isequal": "^4.5.0", + "lodash.isfunction": "^3.0.9", + "lodash.isnil": "^4.0.0" + } + }, + "node_modules/@fast-csv/parse": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/@fast-csv/parse/-/parse-4.3.6.tgz", + "integrity": "sha512-uRsLYksqpbDmWaSmzvJcuApSEe38+6NQZBUsuAyMZKqHxH0g1wcJgsKUvN3WC8tewaqFjBMMGrkHmC+T7k8LvA==", + "dependencies": { + "@types/node": "^14.0.1", + "lodash.escaperegexp": "^4.1.2", + "lodash.groupby": "^4.6.0", + "lodash.isfunction": "^3.0.9", + "lodash.isnil": "^4.0.0", + "lodash.isundefined": "^3.0.1", + "lodash.uniq": "^4.5.0" + } + }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.4.15", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", "dev": true }, + "node_modules/@nfdi4plants/exceljs": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@nfdi4plants/exceljs/-/exceljs-0.3.0.tgz", + "integrity": "sha512-/IvHS3ozGyZ2jG1pYpMoUn2vz+GMzkdo8zUnhsfnn2175ajnjlQKQi7qVhp8Kgpvt/FtthcysrloOjlttbyJQQ==", + "dependencies": { + "archiver": "^5.0.0", + "dayjs": "^1.8.34", + "fast-csv": "^4.3.1", + "jszip": "^3.10.1", + "readable-stream": "^3.6.0", + "saxes": "^5.0.1", + "tmp": "^0.2.0", + "unzipper": "^0.10.11", + "uuid": "^8.3.0" + }, + "engines": { + "node": ">=8.3.0" + } + }, "node_modules/@types/node": { "version": "14.18.63", "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.63.tgz", - "integrity": "sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ==", - "dev": true, - "optional": true + "integrity": "sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ==" }, "node_modules/@types/sinonjs__fake-timers": { "version": "8.1.1", @@ -695,6 +740,70 @@ } ] }, + "node_modules/archiver": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/archiver/-/archiver-5.3.2.tgz", + "integrity": "sha512-+25nxyyznAXF7Nef3y0EbBeqmGZgeN/BxHX29Rs39djAfaFalmQ89SE6CWyDCHzGL0yt/ycBtNOmGTW0FyGWNw==", + "dependencies": { + "archiver-utils": "^2.1.0", + "async": "^3.2.4", + "buffer-crc32": "^0.2.1", + "readable-stream": "^3.6.0", + "readdir-glob": "^1.1.2", + "tar-stream": "^2.2.0", + "zip-stream": "^4.1.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/archiver-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-2.1.0.tgz", + "integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==", + "dependencies": { + "glob": "^7.1.4", + "graceful-fs": "^4.2.0", + "lazystream": "^1.0.0", + "lodash.defaults": "^4.2.0", + "lodash.difference": "^4.5.0", + "lodash.flatten": "^4.4.0", + "lodash.isplainobject": "^4.0.6", + "lodash.union": "^4.6.0", + "normalize-path": "^3.0.0", + "readable-stream": "^2.0.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/archiver-utils/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/archiver-utils/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/archiver-utils/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -731,8 +840,7 @@ "node_modules/async": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", - "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==", - "dev": true + "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==" }, "node_modules/asynckit": { "version": "0.4.0", @@ -767,14 +875,12 @@ "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "node_modules/base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true, "funding": [ { "type": "github", @@ -799,6 +905,26 @@ "tweetnacl": "^0.14.3" } }, + "node_modules/big-integer": { + "version": "1.6.52", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz", + "integrity": "sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/binary": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz", + "integrity": "sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==", + "dependencies": { + "buffers": "~0.1.1", + "chainsaw": "~0.1.0" + }, + "engines": { + "node": "*" + } + }, "node_modules/binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", @@ -808,17 +934,31 @@ "node": ">=8" } }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, "node_modules/blob-util": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/blob-util/-/blob-util-2.0.2.tgz", "integrity": "sha512-T7JQa+zsXXEa6/8ZhHcQEW1UFfVM49Ts65uBkFL6fz2QmrElqmbajIDJvuA0tEhRe5eIjpV9ZF+0RfZR9voJFQ==", "dev": true }, + "node_modules/bluebird": { + "version": "3.4.7", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz", + "integrity": "sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==" + }, "node_modules/brace-expansion": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, "dependencies": { "balanced-match": "^1.0.0" } @@ -845,7 +985,6 @@ "version": "5.7.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "dev": true, "funding": [ { "type": "github", @@ -869,11 +1008,26 @@ "version": "0.2.13", "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", - "dev": true, "engines": { "node": "*" } }, + "node_modules/buffer-indexof-polyfill": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz", + "integrity": "sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/buffers": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", + "integrity": "sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==", + "engines": { + "node": ">=0.2.0" + } + }, "node_modules/cachedir": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.4.0.tgz", @@ -915,6 +1069,17 @@ "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", "dev": true }, + "node_modules/chainsaw": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz", + "integrity": "sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==", + "dependencies": { + "traverse": ">=0.3.0 <0.4" + }, + "engines": { + "node": "*" + } + }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -1111,11 +1276,52 @@ "node": ">=4.0.0" } }, + "node_modules/compress-commons": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-4.1.2.tgz", + "integrity": "sha512-D3uMHtGc/fcO1Gt1/L7i1e33VOvD4A9hfQLP+6ewd+BvG/gQ84Yh4oftEhAdjSMgBgwGL+jsppT7JYNpo6MHHg==", + "dependencies": { + "buffer-crc32": "^0.2.13", + "crc32-stream": "^4.0.2", + "normalize-path": "^3.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">= 10" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, + "node_modules/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/crc32-stream": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-4.0.3.tgz", + "integrity": "sha512-NT7w2JVU7DFroFdYkeq8cywxrgjPHWkdX1wjpRQXPX5Asews3tA+Ght6lddQO5Mkumffp3X7GEqku3epj2toIw==", + "dependencies": { + "crc-32": "^1.2.0", + "readable-stream": "^3.4.0" + }, + "engines": { + "node": ">= 10" + } }, "node_modules/cross-spawn": { "version": "7.0.3", @@ -1225,8 +1431,7 @@ "node_modules/dayjs": { "version": "1.11.10", "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.10.tgz", - "integrity": "sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==", - "dev": true + "integrity": "sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==" }, "node_modules/debug": { "version": "4.3.4", @@ -1295,6 +1500,41 @@ "node": ">=0.3.1" } }, + "node_modules/duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==", + "dependencies": { + "readable-stream": "^2.0.2" + } + }, + "node_modules/duplexer2/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/duplexer2/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/duplexer2/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", @@ -1315,7 +1555,6 @@ "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, "dependencies": { "once": "^1.4.0" } @@ -1478,6 +1717,18 @@ "resolved": "https://registry.npmjs.org/fable-library/-/fable-library-1.1.1.tgz", "integrity": "sha512-tGJqNcPMDfDps2rklbzN9PDOSpzbDXqjHcT7FdP6LEOX2Fe0dj7UWnCzpBWdSCstd3HLPwFVC7DYvReiWtobIQ==" }, + "node_modules/fast-csv": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/fast-csv/-/fast-csv-4.3.6.tgz", + "integrity": "sha512-2RNSpuwwsJGP0frGsOmTb9oUF+VkFSM4SyLTDgwf2ciHWTarN0lQTC+F2f/t5J9QjW+c65VFIAAu85GsvMIusw==", + "dependencies": { + "@fast-csv/format": "4.3.5", + "@fast-csv/parse": "4.3.6" + }, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/fd-slicer": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", @@ -1571,6 +1822,11 @@ "node": ">= 0.12" } }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" + }, "node_modules/fs-extra": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", @@ -1589,8 +1845,7 @@ "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" }, "node_modules/fsevents": { "version": "2.3.2", @@ -1606,6 +1861,44 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, + "node_modules/fstream": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", + "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", + "deprecated": "This package is no longer supported.", + "dependencies": { + "graceful-fs": "^4.1.2", + "inherits": "~2.0.0", + "mkdirp": ">=0.5 0", + "rimraf": "2" + }, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/fstream/node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/fstream/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -1676,7 +1969,6 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "dev": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -1708,7 +2000,6 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -1718,7 +2009,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -1756,8 +2046,7 @@ "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" }, "node_modules/has-flag": { "version": "4.0.0", @@ -1852,7 +2141,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true, "funding": [ { "type": "github", @@ -1868,6 +2156,11 @@ } ] }, + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==" + }, "node_modules/indent-string": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", @@ -1881,7 +2174,6 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -1890,8 +2182,7 @@ "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "node_modules/ini": { "version": "2.0.0", @@ -2029,6 +2320,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -2115,6 +2411,44 @@ "verror": "1.10.0" } }, + "node_modules/jszip": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", + "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", + "dependencies": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "setimmediate": "^1.0.5" + } + }, + "node_modules/jszip/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/jszip/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/jszip/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/lazy-ass": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/lazy-ass/-/lazy-ass-1.6.0.tgz", @@ -2124,6 +2458,57 @@ "node": "> 0.8" } }, + "node_modules/lazystream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", + "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", + "dependencies": { + "readable-stream": "^2.0.5" + }, + "engines": { + "node": ">= 0.6.3" + } + }, + "node_modules/lazystream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/lazystream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/lazystream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "dependencies": { + "immediate": "~3.0.5" + } + }, + "node_modules/listenercount": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz", + "integrity": "sha512-3mk/Zag0+IJxeDrxSgaDPy4zZ3w05PRZeJNnlWhzFz5OkX49J4krc+A8X2d2M69vGMBEX0uyl8M+W+8gH+kBqQ==" + }, "node_modules/listr2": { "version": "3.14.0", "resolved": "https://registry.npmjs.org/listr2/-/listr2-3.14.0.tgz", @@ -2172,12 +2557,77 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, + "node_modules/lodash.defaults": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==" + }, + "node_modules/lodash.difference": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", + "integrity": "sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==" + }, + "node_modules/lodash.escaperegexp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz", + "integrity": "sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw==" + }, + "node_modules/lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==" + }, + "node_modules/lodash.groupby": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.groupby/-/lodash.groupby-4.6.0.tgz", + "integrity": "sha512-5dcWxm23+VAoz+awKmBaiBvzox8+RqMgFhi7UvX9DHZr2HdxHXM/Wrf8cfKpsW37RNrvtPn6hSwNqurSILbmJw==" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" + }, + "node_modules/lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==" + }, + "node_modules/lodash.isfunction": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz", + "integrity": "sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw==" + }, + "node_modules/lodash.isnil": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/lodash.isnil/-/lodash.isnil-4.0.0.tgz", + "integrity": "sha512-up2Mzq3545mwVnMhTDMdfoG1OurpA/s5t88JmQX809eH3C8491iu2sfKhTfhQtKY78oPNhiaHJUpT/dUDAAtng==" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" + }, + "node_modules/lodash.isundefined": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash.isundefined/-/lodash.isundefined-3.0.1.tgz", + "integrity": "sha512-MXB1is3s899/cD8jheYYE2V9qTHwKvt+npCwpD+1Sxm3Q3cECXCiYHjeHWXNwr6Q0SOBPrYUDxendrO6goVTEA==" + }, "node_modules/lodash.once": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", "dev": true }, + "node_modules/lodash.union": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", + "integrity": "sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==" + }, + "node_modules/lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==" + }, "node_modules/log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -2319,7 +2769,6 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -2420,7 +2869,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -2450,7 +2898,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, "dependencies": { "wrappy": "1" } @@ -2521,6 +2968,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -2534,7 +2986,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -2654,6 +3105,11 @@ "node": ">= 0.6.0" } }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, "node_modules/proxy-from-env": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.0.0.tgz", @@ -2715,6 +3171,38 @@ "safe-buffer": "^5.1.0" } }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdir-glob": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz", + "integrity": "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==", + "dependencies": { + "minimatch": "^5.1.0" + } + }, + "node_modules/readdir-glob/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -2774,7 +3262,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, "dependencies": { "glob": "^7.1.3" }, @@ -2814,7 +3301,6 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, "funding": [ { "type": "github", @@ -2836,6 +3322,17 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, + "node_modules/saxes": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", + "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/semver": { "version": "7.5.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", @@ -2875,6 +3372,11 @@ "node": ">= 0.4" } }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==" + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -2964,6 +3466,14 @@ "node": ">=0.10.0" } }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, "node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -3026,6 +3536,21 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/throttleit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz", @@ -3042,7 +3567,6 @@ "version": "0.2.1", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", - "dev": true, "dependencies": { "rimraf": "^3.0.0" }, @@ -3091,6 +3615,14 @@ "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" }, + "node_modules/traverse": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz", + "integrity": "sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ==", + "engines": { + "node": "*" + } + }, "node_modules/tslib": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", @@ -3151,21 +3683,69 @@ "node": ">=8" } }, - "node_modules/url-parse": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", - "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", - "dev": true, + "node_modules/unzipper": { + "version": "0.10.14", + "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.14.tgz", + "integrity": "sha512-ti4wZj+0bQTiX2KmKWuwj7lhV+2n//uXEotUmGuQqrbVZSEGFMbI68+c6JCQ8aAmUWYvtHEz2A8K6wXvueR/6g==", "dependencies": { - "querystringify": "^2.1.1", + "big-integer": "^1.6.17", + "binary": "~0.3.0", + "bluebird": "~3.4.1", + "buffer-indexof-polyfill": "~1.0.0", + "duplexer2": "~0.1.4", + "fstream": "^1.0.12", + "graceful-fs": "^4.2.2", + "listenercount": "~1.0.1", + "readable-stream": "~2.3.6", + "setimmediate": "~1.0.4" + } + }, + "node_modules/unzipper/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/unzipper/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/unzipper/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dev": true, + "dependencies": { + "querystringify": "^2.1.1", "requires-port": "^1.0.0" } }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, "node_modules/uuid": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true, "bin": { "uuid": "dist/bin/uuid" } @@ -3326,8 +3906,12 @@ "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==" }, "node_modules/y18n": { "version": "5.0.8", @@ -3407,6 +3991,79 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zip-stream": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.1.tgz", + "integrity": "sha512-9qv4rlDiopXg4E69k+vMHjNN63YFMe9sZMrdlvKnCjlCRWeCBswPPMPUfx+ipsAWq1LXHe70RcbaHdJJpS6hyQ==", + "dependencies": { + "archiver-utils": "^3.0.4", + "compress-commons": "^4.1.2", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/zip-stream/node_modules/archiver-utils": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-3.0.4.tgz", + "integrity": "sha512-KVgf4XQVrTjhyWmx6cte4RxonPLR9onExufI1jhvw/MQ4BB6IsZD5gT8Lq+u/+pRkWna/6JoHpiQioaqFP5Rzw==", + "dependencies": { + "glob": "^7.2.3", + "graceful-fs": "^4.2.0", + "lazystream": "^1.0.0", + "lodash.defaults": "^4.2.0", + "lodash.difference": "^4.5.0", + "lodash.flatten": "^4.4.0", + "lodash.isplainobject": "^4.0.6", + "lodash.union": "^4.6.0", + "normalize-path": "^3.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/zip-stream/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/zip-stream/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/zip-stream/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } } }, "dependencies": { @@ -3624,18 +4281,59 @@ "dev": true, "optional": true }, + "@fast-csv/format": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/@fast-csv/format/-/format-4.3.5.tgz", + "integrity": "sha512-8iRn6QF3I8Ak78lNAa+Gdl5MJJBM5vRHivFtMRUWINdevNo00K7OXxS2PshawLKTejVwieIlPmK5YlLu6w4u8A==", + "requires": { + "@types/node": "^14.0.1", + "lodash.escaperegexp": "^4.1.2", + "lodash.isboolean": "^3.0.3", + "lodash.isequal": "^4.5.0", + "lodash.isfunction": "^3.0.9", + "lodash.isnil": "^4.0.0" + } + }, + "@fast-csv/parse": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/@fast-csv/parse/-/parse-4.3.6.tgz", + "integrity": "sha512-uRsLYksqpbDmWaSmzvJcuApSEe38+6NQZBUsuAyMZKqHxH0g1wcJgsKUvN3WC8tewaqFjBMMGrkHmC+T7k8LvA==", + "requires": { + "@types/node": "^14.0.1", + "lodash.escaperegexp": "^4.1.2", + "lodash.groupby": "^4.6.0", + "lodash.isfunction": "^3.0.9", + "lodash.isnil": "^4.0.0", + "lodash.isundefined": "^3.0.1", + "lodash.uniq": "^4.5.0" + } + }, "@jridgewell/sourcemap-codec": { "version": "1.4.15", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", "dev": true }, + "@nfdi4plants/exceljs": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@nfdi4plants/exceljs/-/exceljs-0.3.0.tgz", + "integrity": "sha512-/IvHS3ozGyZ2jG1pYpMoUn2vz+GMzkdo8zUnhsfnn2175ajnjlQKQi7qVhp8Kgpvt/FtthcysrloOjlttbyJQQ==", + "requires": { + "archiver": "^5.0.0", + "dayjs": "^1.8.34", + "fast-csv": "^4.3.1", + "jszip": "^3.10.1", + "readable-stream": "^3.6.0", + "saxes": "^5.0.1", + "tmp": "^0.2.0", + "unzipper": "^0.10.11", + "uuid": "^8.3.0" + } + }, "@types/node": { "version": "14.18.63", "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.63.tgz", - "integrity": "sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ==", - "dev": true, - "optional": true + "integrity": "sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ==" }, "@types/sinonjs__fake-timers": { "version": "8.1.1", @@ -3831,6 +4529,66 @@ "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==", "dev": true }, + "archiver": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/archiver/-/archiver-5.3.2.tgz", + "integrity": "sha512-+25nxyyznAXF7Nef3y0EbBeqmGZgeN/BxHX29Rs39djAfaFalmQ89SE6CWyDCHzGL0yt/ycBtNOmGTW0FyGWNw==", + "requires": { + "archiver-utils": "^2.1.0", + "async": "^3.2.4", + "buffer-crc32": "^0.2.1", + "readable-stream": "^3.6.0", + "readdir-glob": "^1.1.2", + "tar-stream": "^2.2.0", + "zip-stream": "^4.1.0" + } + }, + "archiver-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-2.1.0.tgz", + "integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==", + "requires": { + "glob": "^7.1.4", + "graceful-fs": "^4.2.0", + "lazystream": "^1.0.0", + "lodash.defaults": "^4.2.0", + "lodash.difference": "^4.5.0", + "lodash.flatten": "^4.4.0", + "lodash.isplainobject": "^4.0.6", + "lodash.union": "^4.6.0", + "normalize-path": "^3.0.0", + "readable-stream": "^2.0.0" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, "argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -3861,8 +4619,7 @@ "async": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", - "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==", - "dev": true + "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==" }, "asynckit": { "version": "0.4.0", @@ -3891,14 +4648,12 @@ "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" }, "bcrypt-pbkdf": { "version": "1.0.2", @@ -3909,23 +4664,51 @@ "tweetnacl": "^0.14.3" } }, + "big-integer": { + "version": "1.6.52", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz", + "integrity": "sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==" + }, + "binary": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz", + "integrity": "sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==", + "requires": { + "buffers": "~0.1.1", + "chainsaw": "~0.1.0" + } + }, "binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", "dev": true }, + "bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "requires": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, "blob-util": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/blob-util/-/blob-util-2.0.2.tgz", "integrity": "sha512-T7JQa+zsXXEa6/8ZhHcQEW1UFfVM49Ts65uBkFL6fz2QmrElqmbajIDJvuA0tEhRe5eIjpV9ZF+0RfZR9voJFQ==", "dev": true }, + "bluebird": { + "version": "3.4.7", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz", + "integrity": "sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==" + }, "brace-expansion": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, "requires": { "balanced-match": "^1.0.0" } @@ -3949,7 +4732,6 @@ "version": "5.7.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "dev": true, "requires": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" @@ -3958,8 +4740,17 @@ "buffer-crc32": { "version": "0.2.13", "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", - "dev": true + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==" + }, + "buffer-indexof-polyfill": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz", + "integrity": "sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==" + }, + "buffers": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", + "integrity": "sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==" }, "cachedir": { "version": "2.4.0", @@ -3990,6 +4781,14 @@ "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", "dev": true }, + "chainsaw": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz", + "integrity": "sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==", + "requires": { + "traverse": ">=0.3.0 <0.4" + } + }, "chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -4127,11 +4926,40 @@ "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==", "dev": true }, + "compress-commons": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-4.1.2.tgz", + "integrity": "sha512-D3uMHtGc/fcO1Gt1/L7i1e33VOvD4A9hfQLP+6ewd+BvG/gQ84Yh4oftEhAdjSMgBgwGL+jsppT7JYNpo6MHHg==", + "requires": { + "buffer-crc32": "^0.2.13", + "crc32-stream": "^4.0.2", + "normalize-path": "^3.0.0", + "readable-stream": "^3.6.0" + } + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, + "crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==" + }, + "crc32-stream": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-4.0.3.tgz", + "integrity": "sha512-NT7w2JVU7DFroFdYkeq8cywxrgjPHWkdX1wjpRQXPX5Asews3tA+Ght6lddQO5Mkumffp3X7GEqku3epj2toIw==", + "requires": { + "crc-32": "^1.2.0", + "readable-stream": "^3.4.0" + } }, "cross-spawn": { "version": "7.0.3", @@ -4230,8 +5058,7 @@ "dayjs": { "version": "1.11.10", "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.10.tgz", - "integrity": "sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==", - "dev": true + "integrity": "sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==" }, "debug": { "version": "4.3.4", @@ -4279,6 +5106,43 @@ "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", "dev": true }, + "duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==", + "requires": { + "readable-stream": "^2.0.2" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, "ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", @@ -4299,7 +5163,6 @@ "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, "requires": { "once": "^1.4.0" } @@ -4423,6 +5286,15 @@ "resolved": "https://registry.npmjs.org/fable-library/-/fable-library-1.1.1.tgz", "integrity": "sha512-tGJqNcPMDfDps2rklbzN9PDOSpzbDXqjHcT7FdP6LEOX2Fe0dj7UWnCzpBWdSCstd3HLPwFVC7DYvReiWtobIQ==" }, + "fast-csv": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/fast-csv/-/fast-csv-4.3.6.tgz", + "integrity": "sha512-2RNSpuwwsJGP0frGsOmTb9oUF+VkFSM4SyLTDgwf2ciHWTarN0lQTC+F2f/t5J9QjW+c65VFIAAu85GsvMIusw==", + "requires": { + "@fast-csv/format": "4.3.5", + "@fast-csv/parse": "4.3.6" + } + }, "fd-slicer": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", @@ -4491,6 +5363,11 @@ "mime-types": "^2.1.12" } }, + "fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" + }, "fs-extra": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", @@ -4506,8 +5383,7 @@ "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" }, "fsevents": { "version": "2.3.2", @@ -4516,6 +5392,35 @@ "dev": true, "optional": true }, + "fstream": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", + "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", + "requires": { + "graceful-fs": "^4.1.2", + "inherits": "~2.0.0", + "mkdirp": ">=0.5 0", + "rimraf": "2" + }, + "dependencies": { + "mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "requires": { + "minimist": "^1.2.6" + } + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "requires": { + "glob": "^7.1.3" + } + } + } + }, "function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -4571,7 +5476,6 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -4585,7 +5489,6 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -4595,7 +5498,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, "requires": { "brace-expansion": "^1.1.7" } @@ -4632,8 +5534,7 @@ "graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" }, "has-flag": { "version": "4.0.0", @@ -4697,8 +5598,12 @@ "ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" + }, + "immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==" }, "indent-string": { "version": "4.0.0", @@ -4710,7 +5615,6 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, "requires": { "once": "^1.3.0", "wrappy": "1" @@ -4719,8 +5623,7 @@ "inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "ini": { "version": "2.0.0", @@ -4813,6 +5716,11 @@ "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", "dev": true }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -4888,12 +5796,102 @@ "verror": "1.10.0" } }, + "jszip": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", + "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", + "requires": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "setimmediate": "^1.0.5" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, "lazy-ass": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/lazy-ass/-/lazy-ass-1.6.0.tgz", "integrity": "sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw==", "dev": true }, + "lazystream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", + "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", + "requires": { + "readable-stream": "^2.0.5" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "requires": { + "immediate": "~3.0.5" + } + }, + "listenercount": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz", + "integrity": "sha512-3mk/Zag0+IJxeDrxSgaDPy4zZ3w05PRZeJNnlWhzFz5OkX49J4krc+A8X2d2M69vGMBEX0uyl8M+W+8gH+kBqQ==" + }, "listr2": { "version": "3.14.0", "resolved": "https://registry.npmjs.org/listr2/-/listr2-3.14.0.tgz", @@ -4925,12 +5923,77 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, + "lodash.defaults": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==" + }, + "lodash.difference": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", + "integrity": "sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==" + }, + "lodash.escaperegexp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz", + "integrity": "sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw==" + }, + "lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==" + }, + "lodash.groupby": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.groupby/-/lodash.groupby-4.6.0.tgz", + "integrity": "sha512-5dcWxm23+VAoz+awKmBaiBvzox8+RqMgFhi7UvX9DHZr2HdxHXM/Wrf8cfKpsW37RNrvtPn6hSwNqurSILbmJw==" + }, + "lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" + }, + "lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==" + }, + "lodash.isfunction": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz", + "integrity": "sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw==" + }, + "lodash.isnil": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/lodash.isnil/-/lodash.isnil-4.0.0.tgz", + "integrity": "sha512-up2Mzq3545mwVnMhTDMdfoG1OurpA/s5t88JmQX809eH3C8491iu2sfKhTfhQtKY78oPNhiaHJUpT/dUDAAtng==" + }, + "lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" + }, + "lodash.isundefined": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash.isundefined/-/lodash.isundefined-3.0.1.tgz", + "integrity": "sha512-MXB1is3s899/cD8jheYYE2V9qTHwKvt+npCwpD+1Sxm3Q3cECXCiYHjeHWXNwr6Q0SOBPrYUDxendrO6goVTEA==" + }, "lodash.once": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", "dev": true }, + "lodash.union": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", + "integrity": "sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==" + }, + "lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==" + }, "log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -5034,8 +6097,7 @@ "minimist": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==" }, "mkdirp": { "version": "3.0.1", @@ -5095,8 +6157,7 @@ "normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" }, "npm-run-path": { "version": "4.0.1", @@ -5117,7 +6178,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, "requires": { "wrappy": "1" } @@ -5164,6 +6224,11 @@ "aggregate-error": "^3.0.0" } }, + "pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" + }, "path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -5173,8 +6238,7 @@ "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" }, "path-key": { "version": "3.1.1", @@ -5243,6 +6307,11 @@ "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", "dev": true }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, "proxy-from-env": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.0.0.tgz", @@ -5295,6 +6364,34 @@ "safe-buffer": "^5.1.0" } }, + "readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "readdir-glob": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz", + "integrity": "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==", + "requires": { + "minimatch": "^5.1.0" + }, + "dependencies": { + "minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, "readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -5345,7 +6442,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, "requires": { "glob": "^7.1.3" } @@ -5371,8 +6467,7 @@ "safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" }, "safer-buffer": { "version": "2.1.2", @@ -5380,6 +6475,14 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, + "saxes": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", + "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", + "requires": { + "xmlchars": "^2.2.0" + } + }, "semver": { "version": "7.5.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", @@ -5410,6 +6513,11 @@ "has-property-descriptors": "^1.0.0" } }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==" + }, "shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -5476,6 +6584,14 @@ "tweetnacl": "~0.14.0" } }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "requires": { + "safe-buffer": "~5.2.0" + } + }, "string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -5517,6 +6633,18 @@ "has-flag": "^4.0.0" } }, + "tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "requires": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + } + }, "throttleit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz", @@ -5533,7 +6661,6 @@ "version": "0.2.1", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", - "dev": true, "requires": { "rimraf": "^3.0.0" } @@ -5572,6 +6699,11 @@ "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" }, + "traverse": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz", + "integrity": "sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ==" + }, "tslib": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", @@ -5617,6 +6749,52 @@ "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", "dev": true }, + "unzipper": { + "version": "0.10.14", + "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.14.tgz", + "integrity": "sha512-ti4wZj+0bQTiX2KmKWuwj7lhV+2n//uXEotUmGuQqrbVZSEGFMbI68+c6JCQ8aAmUWYvtHEz2A8K6wXvueR/6g==", + "requires": { + "big-integer": "^1.6.17", + "binary": "~0.3.0", + "bluebird": "~3.4.1", + "buffer-indexof-polyfill": "~1.0.0", + "duplexer2": "~0.1.4", + "fstream": "^1.0.12", + "graceful-fs": "^4.2.2", + "listenercount": "~1.0.1", + "readable-stream": "~2.3.6", + "setimmediate": "~1.0.4" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, "url-parse": { "version": "1.5.10", "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", @@ -5627,11 +6805,15 @@ "requires-port": "^1.0.0" } }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, "uuid": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" }, "verror": { "version": "1.10.0", @@ -5725,8 +6907,12 @@ "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==" }, "y18n": { "version": "5.0.8", @@ -5788,6 +6974,65 @@ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true + }, + "zip-stream": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.1.tgz", + "integrity": "sha512-9qv4rlDiopXg4E69k+vMHjNN63YFMe9sZMrdlvKnCjlCRWeCBswPPMPUfx+ipsAWq1LXHe70RcbaHdJJpS6hyQ==", + "requires": { + "archiver-utils": "^3.0.4", + "compress-commons": "^4.1.2", + "readable-stream": "^3.6.0" + }, + "dependencies": { + "archiver-utils": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-3.0.4.tgz", + "integrity": "sha512-KVgf4XQVrTjhyWmx6cte4RxonPLR9onExufI1jhvw/MQ4BB6IsZD5gT8Lq+u/+pRkWna/6JoHpiQioaqFP5Rzw==", + "requires": { + "glob": "^7.2.3", + "graceful-fs": "^4.2.0", + "lazystream": "^1.0.0", + "lodash.defaults": "^4.2.0", + "lodash.difference": "^4.5.0", + "lodash.flatten": "^4.4.0", + "lodash.isplainobject": "^4.0.6", + "lodash.union": "^4.6.0", + "normalize-path": "^3.0.0", + "readable-stream": "^3.6.0" + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "requires": { + "brace-expansion": "^1.1.7" + } + } + } } } } diff --git a/package.json b/package.json index 21d11725..572e3b20 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "Kevin Frey (https://github.com/Freymaurer)" ], "dependencies": { + "@nfdi4plants/exceljs": "^0.3.0", "fable-library": "^1.1.1", "isomorphic-fetch": "^3.0.0", "jsonschema": "^1.4.1" diff --git a/src/ARCtrl/ARCtrl.Javascript.fsproj b/src/ARCtrl/ARCtrl.Javascript.fsproj index ce644ee1..ec77a70a 100644 --- a/src/ARCtrl/ARCtrl.Javascript.fsproj +++ b/src/ARCtrl/ARCtrl.Javascript.fsproj @@ -54,7 +54,7 @@ - + @@ -64,6 +64,11 @@ + + + diff --git a/src/ARCtrl/ContractIO/FileSystem.js b/src/ARCtrl/ContractIO/FileSystem.js index 956f0340..974e034f 100644 --- a/src/ARCtrl/ContractIO/FileSystem.js +++ b/src/ARCtrl/ContractIO/FileSystem.js @@ -1,9 +1,11 @@ -const fs = require('fs/promises'); -const pathModule = require('path'); -const fsSync = require('fs'); // For synchronous checks like `existsSync` +// const fs = require('fs/promises'); +// const pathModule = require('path'); + +import fs from 'fs/promises' +import * as pathModule from 'path' // Check if a directory exists -async function directoryExists(path) { +export async function directoryExists(path) { try { const stats = await fs.stat(path); return stats.isDirectory(); @@ -14,25 +16,25 @@ async function directoryExists(path) { } // Create a directory -async function createDirectory(path) { +export async function createDirectory(path) { await fs.mkdir(path, { recursive: true }); } // Ensure a directory exists -async function ensureDirectory(path) { +export async function ensureDirectory(path) { if (!(await directoryExists(path))) { await createDirectory(path); } } // Ensure the directory for a file exists -async function ensureDirectoryOfFile(filePath) { +export async function ensureDirectoryOfFile(filePath) { const dir = pathModule.dirname(filePath); await ensureDirectory(dir); } // Check if a file exists -async function fileExists(path) { +export async function fileExists(path) { try { const stats = await fs.stat(path); return stats.isFile(); @@ -42,54 +44,54 @@ async function fileExists(path) { } } -// Get subdirectories in a directory -async function getSubDirectories(path) { +// Get subdirectories in a directory combined with the input path +export async function getSubDirectories(path) { const entries = await fs.readdir(path, { withFileTypes: true }); - return entries.filter(entry => entry.isDirectory()).map(entry => entry.name); + return entries.filter(entry => entry.isDirectory()).map(entry => pathModule.join(path, entry.name)); } -// Get files in a directory -async function getSubFiles(path) { +// write a function which returns the path of all files in a directory combined with the input path +export async function getSubFiles(path) { const entries = await fs.readdir(path, { withFileTypes: true }); - return entries.filter(entry => entry.isFile()).map(entry => entry.name); -} + return entries.filter(entry => entry.isFile()).map(entry => pathModule.join(path, entry.name)); + } // Move a file -async function moveFile(oldPath, newPath) { +export async function moveFile(oldPath, newPath) { await fs.rename(oldPath, newPath); } // Move a directory -async function moveDirectory(oldPath, newPath) { +export async function moveDirectory(oldPath, newPath) { await fs.rename(oldPath, newPath); } // Delete a file -async function deleteFile(path) { +export async function deleteFile(path) { await fs.unlink(path); } // Delete a directory (and its contents) -async function deleteDirectory(path) { +export async function deleteDirectory(path) { await fs.rm(path, { recursive: true, force: true }); } // Read file as text -async function readFileText(path) { +export async function readFileText(path) { return await fs.readFile(path, 'utf-8'); } // Read file as binary -async function readFileBinary(path) { +export async function readFileBinary(path) { return await fs.readFile(path); } // Write text to a file -async function writeFileText(path, text) { +export async function writeFileText(path, text) { await fs.writeFile(path, text, 'utf-8'); } // Write binary data to a file -async function writeFileBinary(path, bytes) { +export async function writeFileBinary(path, bytes) { await fs.writeFile(path, bytes); } \ No newline at end of file diff --git a/src/ARCtrl/ContractIO/FileSystemHelper.fs b/src/ARCtrl/ContractIO/FileSystemHelper.fs index 520489d8..9276cb29 100644 --- a/src/ARCtrl/ContractIO/FileSystemHelper.fs +++ b/src/ARCtrl/ContractIO/FileSystemHelper.fs @@ -68,25 +68,7 @@ let fileExistsAsync (path : string) : CrossAsync = } #endif -let getSubDirectoriesAsync (path : string) : CrossAsync = - #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT - import "getSubDirectories" "./FileSystem.js" - #endif - #if !FABLE_COMPILER - crossAsync { - return System.IO.Directory.GetDirectories path - } - #endif -let getSubFilesAsync (path : string) : CrossAsync = - #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT - import "getSubFiles" "./FileSystem.js" - #endif - #if !FABLE_COMPILER - crossAsync { - return System.IO.Directory.GetFiles path - } - #endif let readFileTextAsync (path : string) : CrossAsync = #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT @@ -203,6 +185,35 @@ let makeRelative directoryPath (path : string) = let standardizeSlashes (path : string) = path.Replace("\\","/") +let getSubDirectoriesAsync (path : string) : CrossAsync = + #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT + let f : string -> CrossAsync = import "getSubDirectories" "./FileSystem.js" + crossAsync { + let! paths = f path + return paths |> Array.map (standardizeSlashes >> makeRelative path) + } + #endif + #if !FABLE_COMPILER + crossAsync { + return System.IO.Directory.GetDirectories path + } + #endif + +let getSubFilesAsync (path : string) : CrossAsync = + #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT + let f : string -> CrossAsync = import "getSubFiles" "./FileSystem.js" + crossAsync { + let! paths = f path + return paths |> Array.map (standardizeSlashes >> makeRelative path) + } + #endif + #if !FABLE_COMPILER + crossAsync { + return System.IO.Directory.GetFiles path + } + #endif + + let getAllFilePathsAsync (directoryPath : string) = crossAsync { let rec allFiles (dirs : string seq) : CrossAsync = diff --git a/tests/ARCtrl/FileSystemHelper.Tests.fs b/tests/ARCtrl/FileSystemHelper.Tests.fs index 77d348e2..787cd271 100644 --- a/tests/ARCtrl/FileSystemHelper.Tests.fs +++ b/tests/ARCtrl/FileSystemHelper.Tests.fs @@ -39,6 +39,34 @@ let writeFileText = }) ] +let getSubFiles = + testList "GetSubFiles" [ + testCaseCrossAsync "simple" (crossAsync { + let p = TestObjects.IO.testSubPathsFolder + let! result = FileSystemHelper.getSubFilesAsync p + let expected = + [ + $"{TestObjects.IO.testSubPathsFolder}/File1.txt" |> FileSystemHelper.standardizeSlashes + $"{TestObjects.IO.testSubPathsFolder}/File2.csv" |> FileSystemHelper.standardizeSlashes + ] + Expect.sequenceEqual result expected "Files were not found correctly." + }) + ] + +let getSubDirectories = + testList "GetSubDirectories" [ + testCaseCrossAsync "simple" (crossAsync { + let p = TestObjects.IO.testSubPathsFolder + let! result = FileSystemHelper.getSubDirectoriesAsync p + let expected = + [ + $"{TestObjects.IO.testSubPathsFolder}/SubFolder" |> FileSystemHelper.standardizeSlashes + ] + Expect.sequenceEqual result expected "Directories were not found correctly." + }) + ] + + let getAllFilePaths = testList "GetAllFilePaths" [ @@ -63,5 +91,7 @@ let main = testList "PathTests" [ readFileText writeFileText + getSubFiles + getSubDirectories getAllFilePaths ] diff --git a/tests/TestingUtils/TestingUtils.fsproj b/tests/TestingUtils/TestingUtils.fsproj index 642b6a6b..ec0911a9 100644 --- a/tests/TestingUtils/TestingUtils.fsproj +++ b/tests/TestingUtils/TestingUtils.fsproj @@ -41,7 +41,7 @@ - + From 02384d88f648ae0c6a8a79ea1b0ff1f3c5bf03c8 Mon Sep 17 00:00:00 2001 From: HLWeil Date: Mon, 25 Nov 2024 15:54:19 +0100 Subject: [PATCH 19/30] fix tests for dotnet again --- src/ARCtrl/ContractIO/FileSystemHelper.fs | 12 ++++++++---- tests/ARCtrl/FileSystemHelper.Tests.fs | 10 ++++++---- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/ARCtrl/ContractIO/FileSystemHelper.fs b/src/ARCtrl/ContractIO/FileSystemHelper.fs index 9276cb29..e3147012 100644 --- a/src/ARCtrl/ContractIO/FileSystemHelper.fs +++ b/src/ARCtrl/ContractIO/FileSystemHelper.fs @@ -190,12 +190,13 @@ let getSubDirectoriesAsync (path : string) : CrossAsync = let f : string -> CrossAsync = import "getSubDirectories" "./FileSystem.js" crossAsync { let! paths = f path - return paths |> Array.map (standardizeSlashes >> makeRelative path) + return paths // |> Array.map (standardizeSlashes >> makeRelative path) } #endif #if !FABLE_COMPILER crossAsync { - return System.IO.Directory.GetDirectories path + let paths = System.IO.Directory.GetDirectories path + return paths |> Array.map (standardizeSlashes) } #endif @@ -204,17 +205,20 @@ let getSubFilesAsync (path : string) : CrossAsync = let f : string -> CrossAsync = import "getSubFiles" "./FileSystem.js" crossAsync { let! paths = f path - return paths |> Array.map (standardizeSlashes >> makeRelative path) + return paths // |> Array.map (standardizeSlashes >> makeRelative path) } #endif #if !FABLE_COMPILER crossAsync { - return System.IO.Directory.GetFiles path + let paths = System.IO.Directory.GetFiles path + return paths |> Array.map (standardizeSlashes) + //return System.IO.Directory.GetFiles path } #endif let getAllFilePathsAsync (directoryPath : string) = + let directoryPath = standardizeSlashes directoryPath crossAsync { let rec allFiles (dirs : string seq) : CrossAsync = crossAsync { diff --git a/tests/ARCtrl/FileSystemHelper.Tests.fs b/tests/ARCtrl/FileSystemHelper.Tests.fs index 787cd271..9c984073 100644 --- a/tests/ARCtrl/FileSystemHelper.Tests.fs +++ b/tests/ARCtrl/FileSystemHelper.Tests.fs @@ -43,6 +43,7 @@ let getSubFiles = testList "GetSubFiles" [ testCaseCrossAsync "simple" (crossAsync { let p = TestObjects.IO.testSubPathsFolder + printfn "getSubFiles %s" p let! result = FileSystemHelper.getSubFilesAsync p let expected = [ @@ -57,6 +58,7 @@ let getSubDirectories = testList "GetSubDirectories" [ testCaseCrossAsync "simple" (crossAsync { let p = TestObjects.IO.testSubPathsFolder + printfn "getSubDirectories %s" p let! result = FileSystemHelper.getSubDirectoriesAsync p let expected = [ @@ -77,10 +79,10 @@ let getAllFilePaths = |> map Seq.sort let expected = [ - "/File1.txt" - "/File2.csv" - "/SubFolder/File3.xlsx" - "/SubFolder/SubSubFolder/File4" + $"/File1.txt" + $"/File2.csv" + $"/SubFolder/File3.xlsx" |> FileSystemHelper.standardizeSlashes + $"/SubFolder/SubSubFolder/File4" |> FileSystemHelper.standardizeSlashes ] Expect.sequenceEqual result expected "File Paths were not found correctly." From 24786403c5f7a88a91c4a7f9967341615ffba78c Mon Sep 17 00:00:00 2001 From: HLWeil Date: Mon, 25 Nov 2024 16:19:32 +0100 Subject: [PATCH 20/30] fix js base level IO tests --- src/ARCtrl/ContractIO/FileSystemHelper.fs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ARCtrl/ContractIO/FileSystemHelper.fs b/src/ARCtrl/ContractIO/FileSystemHelper.fs index e3147012..49ac1c0c 100644 --- a/src/ARCtrl/ContractIO/FileSystemHelper.fs +++ b/src/ARCtrl/ContractIO/FileSystemHelper.fs @@ -190,7 +190,7 @@ let getSubDirectoriesAsync (path : string) : CrossAsync = let f : string -> CrossAsync = import "getSubDirectories" "./FileSystem.js" crossAsync { let! paths = f path - return paths // |> Array.map (standardizeSlashes >> makeRelative path) + return paths |> Array.map standardizeSlashes } #endif #if !FABLE_COMPILER @@ -205,7 +205,7 @@ let getSubFilesAsync (path : string) : CrossAsync = let f : string -> CrossAsync = import "getSubFiles" "./FileSystem.js" crossAsync { let! paths = f path - return paths // |> Array.map (standardizeSlashes >> makeRelative path) + return paths |> Array.map standardizeSlashes } #endif #if !FABLE_COMPILER From 4dd085a3bb3aaf626771e68d1b648565d8cf086e Mon Sep 17 00:00:00 2001 From: HLWeil Date: Tue, 26 Nov 2024 13:51:51 +0100 Subject: [PATCH 21/30] fix js io helpers aganst basic tests --- src/ARCtrl/ContractIO/ContractIO.fs | 17 ++++++---- tests/ARCtrl/ContractIO.Tests.fs | 14 ++++---- tests/ARCtrl/FileSystemHelper.Tests.fs | 32 ++++++++++++++++++ tests/TestingUtils/TestObjects.IO.fs | 3 +- .../TestObjects.IO/TestWorkbook.xlsx | Bin 0 -> 8487 bytes 5 files changed, 51 insertions(+), 15 deletions(-) create mode 100644 tests/TestingUtils/TestObjects.IO/TestWorkbook.xlsx diff --git a/src/ARCtrl/ContractIO/ContractIO.fs b/src/ARCtrl/ContractIO/ContractIO.fs index 9c871c23..98d7f95d 100644 --- a/src/ARCtrl/ContractIO/ContractIO.fs +++ b/src/ARCtrl/ContractIO/ContractIO.fs @@ -7,6 +7,7 @@ open CrossAsync let fulfillReadContractAsync basePath (c : Contract) = + try crossAsync { try match c.DTOType with @@ -24,10 +25,12 @@ let fulfillReadContractAsync basePath (c : Contract) = let dto = text |> DTO.Text return Ok {c with DTO = Some dto} | _ -> - return Error (sprintf "Contract %s is not an ISA contract" c.Path) + return Error (sprintf "Contract %s is neither an ISA nor a freetext contract" c.Path) with | e -> return Error (sprintf "Error reading contract %s: %s" c.Path e.Message) } + with + | e -> failwithf "Read contract failed unexpectedly for path %s: %s" c.Path e.Message let fullfillContractBatchAsyncBy (contractF : string -> Contract -> CrossAsync>) @@ -56,17 +59,17 @@ let fulfillWriteContractAsync basePath (c : Contract) = crossAsync { try match c.DTO with - | Some (DTO.Spreadsheet wb) -> - let path = ArcPathHelper.combine basePath c.Path - do! FileSystemHelper.ensureDirectoryOfFileAsync path - do! FileSystemHelper.writeFileXlsxAsync path (wb :?> FsWorkbook) - return Ok (c) | Some (DTO.Text t) -> let path = ArcPathHelper.combine basePath c.Path do! FileSystemHelper.ensureDirectoryOfFileAsync path do! FileSystemHelper.writeFileTextAsync path t return Ok (c) - | None -> + | Some (DTO.Spreadsheet wb) -> + let path = ArcPathHelper.combine basePath c.Path + do! FileSystemHelper.ensureDirectoryOfFileAsync path + do! FileSystemHelper.writeFileXlsxAsync path (wb :?> FsWorkbook) + return Ok (c) + | None -> let path = ArcPathHelper.combine basePath c.Path do! FileSystemHelper.ensureDirectoryOfFileAsync path do! FileSystemHelper.writeFileTextAsync path "" diff --git a/tests/ARCtrl/ContractIO.Tests.fs b/tests/ARCtrl/ContractIO.Tests.fs index 52e0cc13..3abb3632 100644 --- a/tests/ARCtrl/ContractIO.Tests.fs +++ b/tests/ARCtrl/ContractIO.Tests.fs @@ -63,7 +63,7 @@ let testWrite = let testText = "This is a test" let fileName = "TestReadMe.txt" let dto = DTO.Text testText - let contract = Contract.createCreate(fileName,DTOType.PlainText,dto) + let contract = Contract.createCreate(fileName,DTOType.PlainText, dto) do! FileSystemHelper.ensureDirectoryAsync TestObjects.IO.testResultsFolder @@ -106,13 +106,13 @@ let testWrite = }) ] -let testExecute = +//let testExecute = - testList "Write" [ - testCase "Implement" (fun () -> - Expect.isTrue false "ImplementTest" - ) - ] +// testList "Write" [ +// testCase "Implement" (fun () -> +// Expect.isTrue false "ImplementTest" +// ) +// ] let main = testList "ContractTests" [ diff --git a/tests/ARCtrl/FileSystemHelper.Tests.fs b/tests/ARCtrl/FileSystemHelper.Tests.fs index 9c984073..0dddfc76 100644 --- a/tests/ARCtrl/FileSystemHelper.Tests.fs +++ b/tests/ARCtrl/FileSystemHelper.Tests.fs @@ -39,6 +39,36 @@ let writeFileText = }) ] +let readFileXlsx = + testList "ReadWorkbook" [ + testCaseCrossAsync "simple" (crossAsync { + let p = TestObjects.IO.simpleWorkbookPath + let! result = FileSystemHelper.readFileXlsxAsync p + let ws = Expect.wantSome (result.TryGetWorksheetByName "TestSheet") "Workbook does not contain worksheet" + let row1 = Expect.wantSome (ws.TryGetRowValuesAt 1) "Worksheet does not contain row 1" + let row1AsInts = row1 |> Seq.map (string >> int) + let expected = [1;2;3] + Expect.sequenceEqual row1AsInts expected "Worksheet does not contain correct values" + let row2 = Expect.wantSome (ws.TryGetRowValuesAt 2) "Worksheet does not contain row 2" + let expected = ["A";"B";"C"] |> Seq.map box + Expect.sequenceEqual row2 expected "Worksheet does not contain correct values" + + }) + ] + +let writeFileXlsx = + testList "WriteWorkbook" [ + testCaseCrossAsync "simple" (crossAsync { + do! ARCtrl.FileSystemHelper.ensureDirectoryAsync TestObjects.IO.testResultsFolder + let p = ArcPathHelper.combine TestObjects.IO.testResultsFolder "Workbook.xlsx" + let wb = TestObjects.Spreadsheet.Investigation.BII_I_1.fullInvestigation + do! FileSystemHelper.writeFileXlsxAsync p wb + let! result = FileSystemHelper.readFileXlsxAsync p + Expect.workBookEqual wb result "Workbook was not read correctly." + }) + ] + + let getSubFiles = testList "GetSubFiles" [ testCaseCrossAsync "simple" (crossAsync { @@ -93,6 +123,8 @@ let main = testList "PathTests" [ readFileText writeFileText + readFileXlsx + writeFileXlsx getSubFiles getSubDirectories getAllFilePaths diff --git a/tests/TestingUtils/TestObjects.IO.fs b/tests/TestingUtils/TestObjects.IO.fs index 28544d91..23c3b93f 100644 --- a/tests/TestingUtils/TestObjects.IO.fs +++ b/tests/TestingUtils/TestObjects.IO.fs @@ -23,4 +23,5 @@ let testSimpleARC = combine testObjectsBaseFolder "SimpleARC" let testSimpleARC_Output = combine testResultsFolder "TestResults/SimpleARC" -let simpleTextFilePath = combine testObjectsBaseFolder "SimpleText.txt" \ No newline at end of file +let simpleTextFilePath = combine testObjectsBaseFolder "SimpleText.txt" +let simpleWorkbookPath = combine testObjectsBaseFolder "TestWorkbook.xlsx" \ No newline at end of file diff --git a/tests/TestingUtils/TestObjects.IO/TestWorkbook.xlsx b/tests/TestingUtils/TestObjects.IO/TestWorkbook.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..dfc1e460c78052691836244bcd1bbdf4a0d81b81 GIT binary patch literal 8487 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 literal 0 HcmV?d00001 From c20e8c1cc99ace2c8730fc803aa33b96b011d591 Mon Sep 17 00:00:00 2001 From: HLWeil Date: Wed, 27 Nov 2024 18:45:42 +0100 Subject: [PATCH 22/30] add preliminary promise catch mechanic for js io tests --- src/ARCtrl/ContractIO/ContractIO.fs | 17 ++++---- src/ARCtrl/ContractIO/FileSystem.js | 7 +++- src/ARCtrl/CrossAsync.fs | 29 +++++++++++++- tests/ARCtrl/ARCtrl.Tests.fsproj | 1 + tests/ARCtrl/ContractIO.Tests.fs | 55 +++++++++++++++++++++++--- tests/ARCtrl/CrossAsync.Tests.fs | 24 +++++++++++ tests/ARCtrl/FileSystemHelper.Tests.fs | 48 ++++++++++++++++++++++ tests/TestingUtils/TestingUtils.fs | 6 ++- 8 files changed, 171 insertions(+), 16 deletions(-) create mode 100644 tests/ARCtrl/CrossAsync.Tests.fs diff --git a/src/ARCtrl/ContractIO/ContractIO.fs b/src/ARCtrl/ContractIO/ContractIO.fs index 98d7f95d..3da01759 100644 --- a/src/ARCtrl/ContractIO/ContractIO.fs +++ b/src/ARCtrl/ContractIO/ContractIO.fs @@ -7,7 +7,6 @@ open CrossAsync let fulfillReadContractAsync basePath (c : Contract) = - try crossAsync { try match c.DTOType with @@ -29,8 +28,7 @@ let fulfillReadContractAsync basePath (c : Contract) = with | e -> return Error (sprintf "Error reading contract %s: %s" c.Path e.Message) } - with - | e -> failwithf "Read contract failed unexpectedly for path %s: %s" c.Path e.Message + |> catchWith (fun e -> Error (sprintf "Error reading contract %s: %s" c.Path e.Message)) let fullfillContractBatchAsyncBy (contractF : string -> Contract -> CrossAsync>) @@ -79,20 +77,21 @@ let fulfillWriteContractAsync basePath (c : Contract) = with | e -> return Error (sprintf "Error writing contract %s: %s" c.Path e.Message) } + |> catchWith (fun e -> Error (sprintf "Error writing contract %s: %s" c.Path e.Message)) let fulfillUpdateContractAsync basePath (c : Contract) = crossAsync { try match c.DTO with - | Some (DTO.Spreadsheet wb) -> + | Some (DTO.Text t) -> let path = ArcPathHelper.combine basePath c.Path do! FileSystemHelper.ensureDirectoryOfFileAsync path - do! FileSystemHelper.writeFileXlsxAsync path (wb :?> FsWorkbook) + do! FileSystemHelper.writeFileTextAsync path t return Ok (c) - | Some (DTO.Text t) -> + | Some (DTO.Spreadsheet wb) -> let path = ArcPathHelper.combine basePath c.Path do! FileSystemHelper.ensureDirectoryOfFileAsync path - do! FileSystemHelper.writeFileTextAsync path t + do! FileSystemHelper.writeFileXlsxAsync path (wb :?> FsWorkbook) return Ok (c) | None -> let path = ArcPathHelper.combine basePath c.Path @@ -104,6 +103,7 @@ let fulfillUpdateContractAsync basePath (c : Contract) = with | e -> return Error (sprintf "Error updating contract %s: %s" c.Path e.Message) } + |> catchWith (fun e -> Error (sprintf "Error updating contract %s: %s" c.Path e.Message)) let fullfillRenameContractAsync basePath (c : Contract) = crossAsync { @@ -120,6 +120,7 @@ let fullfillRenameContractAsync basePath (c : Contract) = with | e -> return Error (sprintf "Error renaming contract %s: %s" c.Path e.Message) } + |> catchWith (fun e -> Error (sprintf "Error renaming contract %s: %s" c.Path e.Message)) let fullfillDeleteContractAsync basePath (c : Contract) = crossAsync { @@ -130,6 +131,7 @@ let fullfillDeleteContractAsync basePath (c : Contract) = with | e -> return Error (sprintf "Error deleting contract %s: %s" c.Path e.Message) } + |> catchWith (fun e -> Error (sprintf "Error deleting contract %s: %s" c.Path e.Message)) let fullFillContract basePath (c : Contract) = crossAsync { @@ -141,6 +143,7 @@ let fullFillContract basePath (c : Contract) = | Operation.RENAME -> return! fullfillRenameContractAsync basePath c | _ -> return Error (sprintf "Operation %A not supported" c.Operation) } + |> catchWith (fun e -> Error (sprintf "Error fulfilling contract %s: %s" c.Path e.Message)) let fullFillContractBatchAsync basePath (cs : Contract []) = fullfillContractBatchAsyncBy fullFillContract basePath cs \ No newline at end of file diff --git a/src/ARCtrl/ContractIO/FileSystem.js b/src/ARCtrl/ContractIO/FileSystem.js index 974e034f..02e51559 100644 --- a/src/ARCtrl/ContractIO/FileSystem.js +++ b/src/ARCtrl/ContractIO/FileSystem.js @@ -68,7 +68,12 @@ export async function moveDirectory(oldPath, newPath) { // Delete a file export async function deleteFile(path) { - await fs.unlink(path); + try { + await fs.unlink(path); + } + catch (err) { + if (err.code !== 'ENOENT') throw err; + } } // Delete a directory (and its contents) diff --git a/src/ARCtrl/CrossAsync.fs b/src/ARCtrl/CrossAsync.fs index 8bac33f3..2119a69f 100644 --- a/src/ARCtrl/CrossAsync.fs +++ b/src/ARCtrl/CrossAsync.fs @@ -2,6 +2,7 @@ module ARCtrl.CrossAsync open Fable.Core + // We need the `<'T>` here as it allows to mark the function/variable inline for better output. let inline crossAsync<'T> = #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT @@ -35,4 +36,30 @@ let asAsync (v:CrossAsync<'T>) = Async.AwaitPromise v #else v - #endif \ No newline at end of file + #endif + +let catchWith (f : exn -> 'T) (p : CrossAsync<'T>) : CrossAsync<'T> = + #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT + Promise.catch f p + #else + async { + let! r = Async.Catch p + match r with + | Choice1Of2 x -> return x + | Choice2Of2 e -> return f e + } + #endif + +let catchAsResult (p : CrossAsync<'T>) : CrossAsync>= + #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT + p + |> Promise.map (fun x -> Ok x) + |> Promise.catch (fun e -> Error (e.ToString())) + #else + async { + let! r = Async.Catch p + match r with + | Choice1Of2 x -> return Ok x + | Choice2Of2 e -> return Error (e.ToString()) + } + #endif diff --git a/tests/ARCtrl/ARCtrl.Tests.fsproj b/tests/ARCtrl/ARCtrl.Tests.fsproj index 81e8b6a2..b09ddedc 100644 --- a/tests/ARCtrl/ARCtrl.Tests.fsproj +++ b/tests/ARCtrl/ARCtrl.Tests.fsproj @@ -6,6 +6,7 @@ false + diff --git a/tests/ARCtrl/ContractIO.Tests.fs b/tests/ARCtrl/ContractIO.Tests.fs index 3abb3632..760dc4ac 100644 --- a/tests/ARCtrl/ContractIO.Tests.fs +++ b/tests/ARCtrl/ContractIO.Tests.fs @@ -106,16 +106,59 @@ let testWrite = }) ] -//let testExecute = +let testRename = -// testList "Write" [ -// testCase "Implement" (fun () -> -// Expect.isTrue false "ImplementTest" -// ) -// ] + testList "Rename" [ + testCaseCrossAsync "Text" (crossAsync { + let oldFileName = "TestOld.txt" + let newFileName = "TestNew.txt" + let content = "This is a test" + let oldPath = ArcPathHelper.combine TestObjects.IO.testResultsFolder oldFileName + let newPath = ArcPathHelper.combine TestObjects.IO.testResultsFolder newFileName + do! FileSystemHelper.writeFileTextAsync oldPath content + + let contract = Contract.createRename(oldFileName,newFileName) + + let! resultContract = fullfillRenameContractAsync TestObjects.IO.testResultsFolder contract + + Expect.isOk resultContract "Contract was not fulfilled correctly" + + let! oldFileExists = FileSystemHelper.fileExistsAsync oldPath + Expect.isFalse oldFileExists $"File {oldPath} was not deleted" + + let! newFileExists = FileSystemHelper.fileExistsAsync newPath + Expect.isTrue newFileExists $"File {newPath} was not created" + }) + ] + +let testRemove = + + testList "Remove" [ + testCaseCrossAsync "Text" (crossAsync { + let fileName = "TestRemove.txt" + let content = "This is a test" + let filePath = ArcPathHelper.combine TestObjects.IO.testResultsFolder fileName + do! FileSystemHelper.writeFileTextAsync filePath content + + let! fileExistsBeforeDelete = FileSystemHelper.fileExistsAsync filePath + Expect.isTrue fileExistsBeforeDelete $"File {filePath} was not created" + + let contract = Contract.createDelete(fileName) + + let! resultContract = fullfillDeleteContractAsync TestObjects.IO.testResultsFolder contract + + Expect.isOk resultContract "Contract was not fulfilled correctly" + + let! fileExistsAferDelete = FileSystemHelper.fileExistsAsync filePath + Expect.isFalse fileExistsAferDelete $"File {filePath} was not deleted" + }) + ] let main = testList "ContractTests" [ testRead testWrite + testRename + testRemove + ] \ No newline at end of file diff --git a/tests/ARCtrl/CrossAsync.Tests.fs b/tests/ARCtrl/CrossAsync.Tests.fs new file mode 100644 index 00000000..19b204a4 --- /dev/null +++ b/tests/ARCtrl/CrossAsync.Tests.fs @@ -0,0 +1,24 @@ +module ARCtrl.CrossAsync.Tests + +open TestingUtils +open ARCtrl +open CrossAsync + +let catchWith = + testList "CatchWith" [ + testCaseCrossAsync "simple" (crossAsync { + let internalAsync = + crossAsync { + failwith "This is an error" + return "Just strolling around" + } + |> catchWith (fun e -> "Caught error") + let! internalResult = internalAsync + Expect.equal internalResult "Caught error" "Error was not caught" + }) + ] + +let main = + testList "CrossAsyncTests" [ + catchWith + ] diff --git a/tests/ARCtrl/FileSystemHelper.Tests.fs b/tests/ARCtrl/FileSystemHelper.Tests.fs index 0dddfc76..9b996c9d 100644 --- a/tests/ARCtrl/FileSystemHelper.Tests.fs +++ b/tests/ARCtrl/FileSystemHelper.Tests.fs @@ -3,6 +3,51 @@ module ARCtrl.FileSystemHelper.Tests open TestingUtils open ARCtrl open CrossAsync +open ARCtrl.ArcPathHelper + +let fileExists = + testList "FileExists" [ + testCaseCrossAsync "simple" (crossAsync { + let p = TestObjects.IO.simpleTextFilePath + let! result = FileSystemHelper.fileExistsAsync p + Expect.isTrue result "File does not exist." + }) + testCaseCrossAsync "nonExisting" (crossAsync { + let p = "bdlieihawdbawndfefnsefsfnse.dawd" + let! result = FileSystemHelper.fileExistsAsync p + Expect.isFalse result "File exists." + }) + ] + +let directoryExists = + testList "DirectoryExists" [ + testCaseCrossAsync "simple" (crossAsync { + let p = TestObjects.IO.testObjectsBaseFolder + let! result = FileSystemHelper.directoryExistsAsync p + Expect.isTrue result "Directory does not exist." + }) + testCaseCrossAsync "nonExisting" (crossAsync { + let p = "bdlieihawdbawndfefnsefsfnse" + let! result = FileSystemHelper.directoryExistsAsync p + Expect.isFalse result "Directory exists." + }) + ] + +let ensureDirectoryOfFile = + testList "EnsureDirectoryOfFile" [ + testCaseCrossAsync "simple" (crossAsync { + let directoryPath = combine TestObjects.IO.testResultsFolder "EnsuredDirectory" + let filePath = combine directoryPath "EnsuredFile.txt" + + let! directoryExistsBefore = FileSystemHelper.directoryExistsAsync directoryPath + Expect.isFalse directoryExistsBefore "Directory should not exist before." + + do! FileSystemHelper.ensureDirectoryOfFileAsync filePath + + let! directoryExistsAfter = FileSystemHelper.directoryExistsAsync directoryPath + Expect.isTrue directoryExistsAfter "Directory should exist after." + }) + ] let readFileText = testList "ReadText" [ @@ -121,6 +166,9 @@ let getAllFilePaths = let main = testList "PathTests" [ + fileExists + directoryExists + ensureDirectoryOfFile readFileText writeFileText readFileXlsx diff --git a/tests/TestingUtils/TestingUtils.fs b/tests/TestingUtils/TestingUtils.fs index 5fe9af64..3e94a069 100644 --- a/tests/TestingUtils/TestingUtils.fs +++ b/tests/TestingUtils/TestingUtils.fs @@ -253,7 +253,11 @@ module Test = let testCaseCrossAsync (text : string) (ca : CrossAsync) = - testCaseAsync text (asAsync ca) + ca + |> catchWith (fun exn -> failwithf "%s" exn.Message) + |> asAsync + |> testCaseAsync text + let ptestCaseCrossAsync (text : string) (ca : CrossAsync) = ptestCaseAsync text (asAsync ca) let ftestCaseCrossAsync (text : string) (ca : CrossAsync) = From 2b754f5ad5494bd3a3e052503f882bc96e5ad58f Mon Sep 17 00:00:00 2001 From: HLWeil Date: Thu, 28 Nov 2024 11:31:27 +0100 Subject: [PATCH 23/30] finish up first working version of javascript arc io --- Directory.Packages.props | 8 ++--- build/TestTasks.fs | 12 ++++--- src/ARCtrl/ContractIO/ContractIO.fs | 7 ++-- src/ARCtrl/ContractIO/FileSystemHelper.fs | 6 ++-- src/ARCtrl/CrossAsync.fs | 17 +++++++-- tests/ARCtrl/ContractIO.Tests.fs | 4 +-- tests/ARCtrl/FileSystemHelper.Tests.fs | 42 +++++++++++++++++++++-- tests/ARCtrl/Main.fs | 3 +- tests/All/Main.fs | 5 ++- 9 files changed, 78 insertions(+), 26 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 8a405628..fd29366c 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -10,10 +10,10 @@ - - - - + + + + diff --git a/build/TestTasks.fs b/build/TestTasks.fs index 3c3cbd1c..ef55b74f 100644 --- a/build/TestTasks.fs +++ b/build/TestTasks.fs @@ -20,7 +20,7 @@ module RunTests = run npx $"cypress run --component -P {path}" "" } - let runTestsJsNative = BuildTask.createFn "runTestsJSNative" [clean; build] (fun tp -> + let runTestsJsNative = BuildTask.createFn "runTestsJSNative" [clean] (fun tp -> if tp.Context.Arguments |> List.exists (fun a -> a.ToLower() = skipTestsFlag.ToLower()) |> not then Trace.traceImportant "Start native JavaScript tests" for path in ProjectInfo.jsTestProjects do @@ -32,10 +32,12 @@ module RunTests = Trace.traceImportant "Skipping JavaScript tests" ) - let runTestsJs = BuildTask.createFn "runTestsJS" [clean; build] (fun tp -> + let runTestsJs = BuildTask.createFn "runTestsJS" [clean] (fun tp -> if tp.Context.Arguments |> List.exists (fun a -> a.ToLower() = skipTestsFlag.ToLower()) |> not then Trace.traceImportant "Start Js tests" for path in ProjectInfo.testProjects do + // Setup test results directory after clean + System.IO.Directory.CreateDirectory(@".\tests\TestingUtils\TestResults\js") |> ignore // transpile js files from fsharp code run dotnet $"fable {path} -o {path}/js --nocache" "" // run mocha in target path to execute tests @@ -45,7 +47,7 @@ module RunTests = Trace.traceImportant "Skipping Js tests" ) - let runTestsPyNative = BuildTask.createFn "runTestsPyNative" [clean; build] (fun tp -> + let runTestsPyNative = BuildTask.createFn "runTestsPyNative" [clean] (fun tp -> if tp.Context.Arguments |> List.exists (fun a -> a.ToLower() = skipTestsFlag.ToLower()) |> not then Trace.traceImportant "Start native Python tests" for path in ProjectInfo.pyTestProjects do @@ -57,10 +59,12 @@ module RunTests = Trace.traceImportant "Skipping Python tests" ) - let runTestsPy = BuildTask.createFn "runTestsPy" [clean; build] (fun tp -> + let runTestsPy = BuildTask.createFn "runTestsPy" [clean] (fun tp -> if tp.Context.Arguments |> List.exists (fun a -> a.ToLower() = skipTestsFlag.ToLower()) |> not then Trace.traceImportant "Start Python tests" for path in ProjectInfo.testProjects do + // Setup test results directory after clean + System.IO.Directory.CreateDirectory(@".\tests\TestingUtils\TestResults\py") |> ignore //transpile py files from fsharp code run dotnet $"fable {path} -o {path}/py --lang python --nocache" "" // run pyxpecto in target path to execute tests in python diff --git a/src/ARCtrl/ContractIO/ContractIO.fs b/src/ARCtrl/ContractIO/ContractIO.fs index 3da01759..30236dd8 100644 --- a/src/ARCtrl/ContractIO/ContractIO.fs +++ b/src/ARCtrl/ContractIO/ContractIO.fs @@ -33,13 +33,12 @@ let fulfillReadContractAsync basePath (c : Contract) = let fullfillContractBatchAsyncBy (contractF : string -> Contract -> CrossAsync>) (basePath : string) - (cs : (Contract) []) + (cs : Contract []) : CrossAsync> = crossAsync { let! seq = - cs - |> Array.map (contractF basePath) - |> CrossAsync.sequential + cs + |> CrossAsync.startSequential (contractF basePath) let res = seq |> Array.fold (fun acc cr -> diff --git a/src/ARCtrl/ContractIO/FileSystemHelper.fs b/src/ARCtrl/ContractIO/FileSystemHelper.fs index 49ac1c0c..eb01b1c4 100644 --- a/src/ARCtrl/ContractIO/FileSystemHelper.fs +++ b/src/ARCtrl/ContractIO/FileSystemHelper.fs @@ -226,10 +226,10 @@ let getAllFilePathsAsync (directoryPath : string) = return Seq.empty else - let! subFiles = dirs |> Seq.map getSubFilesAsync |> CrossAsync.sequential + let! subFiles = dirs |> Seq.map getSubFilesAsync |> CrossAsync.all let subFiles = subFiles |> Seq.concat - let! subDirs = dirs |> Seq.map getSubDirectoriesAsync |> CrossAsync.sequential - let! subDirContents = subDirs |> Seq.map allFiles |> CrossAsync.sequential + let! subDirs = dirs |> Seq.map getSubDirectoriesAsync |> CrossAsync.all + let! subDirContents = subDirs |> Seq.map allFiles |> CrossAsync.all let subDirContents = subDirContents |> Seq.concat return subFiles |> Seq.append subDirContents } diff --git a/src/ARCtrl/CrossAsync.fs b/src/ARCtrl/CrossAsync.fs index 2119a69f..ae1896b0 100644 --- a/src/ARCtrl/CrossAsync.fs +++ b/src/ARCtrl/CrossAsync.fs @@ -18,11 +18,22 @@ type CrossAsync<'T> = Async<'T> #endif -let sequential = +let startSequential (starterF : 'T -> CrossAsync<'U>) (tasks : 'T seq) : CrossAsync<'U []> = + let rec loop (en : System.Collections.Generic.IEnumerator<'T>) = + crossAsync { + if en.MoveNext() then + let! r = starterF en.Current + let! following = loop en + return Array.append [|r|] following + else return [||] + } + loop (tasks.GetEnumerator()) + +let all (tasks : CrossAsync<'T> seq) : CrossAsync<'T []> = #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT - Promise.all + Promise.all tasks #else - Async.Sequential + Async.Sequential tasks #endif let map f v = diff --git a/tests/ARCtrl/ContractIO.Tests.fs b/tests/ARCtrl/ContractIO.Tests.fs index 760dc4ac..63f916b4 100644 --- a/tests/ARCtrl/ContractIO.Tests.fs +++ b/tests/ARCtrl/ContractIO.Tests.fs @@ -110,8 +110,8 @@ let testRename = testList "Rename" [ testCaseCrossAsync "Text" (crossAsync { - let oldFileName = "TestOld.txt" - let newFileName = "TestNew.txt" + let oldFileName = "ContractTestOld.txt" + let newFileName = "ContractTestNew.txt" let content = "This is a test" let oldPath = ArcPathHelper.combine TestObjects.IO.testResultsFolder oldFileName let newPath = ArcPathHelper.combine TestObjects.IO.testResultsFolder newFileName diff --git a/tests/ARCtrl/FileSystemHelper.Tests.fs b/tests/ARCtrl/FileSystemHelper.Tests.fs index 9b996c9d..77ea86d6 100644 --- a/tests/ARCtrl/FileSystemHelper.Tests.fs +++ b/tests/ARCtrl/FileSystemHelper.Tests.fs @@ -113,7 +113,6 @@ let writeFileXlsx = }) ] - let getSubFiles = testList "GetSubFiles" [ testCaseCrossAsync "simple" (crossAsync { @@ -143,7 +142,6 @@ let getSubDirectories = }) ] - let getAllFilePaths = testList "GetAllFilePaths" [ @@ -164,6 +162,45 @@ let getAllFilePaths = }) ] +let rename = + testList "Rename" [ + testCaseCrossAsync "simpleFile" (crossAsync { + let oldFileName = "OldFile.txt" + let newFileName = "NewFile.txt" + let oldFilePath = ArcPathHelper.combine TestObjects.IO.testResultsFolder oldFileName + let newFilePath = ArcPathHelper.combine TestObjects.IO.testResultsFolder newFileName + let text = "Hello" + + do! FileSystemHelper.writeFileTextAsync oldFilePath text + do! FileSystemHelper.renameFileOrDirectoryAsync oldFilePath newFilePath + + let! oldFileExists = FileSystemHelper.fileExistsAsync oldFilePath + Expect.isFalse oldFileExists "Old file still exists." + let! result = FileSystemHelper.fileExistsAsync newFilePath + Expect.isTrue result "File does not exist." + }) + testCaseCrossAsync "simpleFolder" (crossAsync { + let oldFolderName = "OldFolder" + let newFolderName = "NewFolder" + let oldFolderPath = ArcPathHelper.combine TestObjects.IO.testResultsFolder oldFolderName + let newFolderPath = ArcPathHelper.combine TestObjects.IO.testResultsFolder newFolderName + let oldFilePath = ArcPathHelper.combine oldFolderPath "File.txt" + let newFilePath = ArcPathHelper.combine newFolderPath "File.txt" + let text = "Hello" + do! FileSystemHelper.ensureDirectoryAsync oldFolderPath + do! FileSystemHelper.writeFileTextAsync oldFilePath text + do! FileSystemHelper.renameFileOrDirectoryAsync oldFolderPath newFolderPath + + let! oldFolderExists = FileSystemHelper.directoryExistsAsync oldFolderPath + Expect.isFalse oldFolderExists "Old folder still exists." + let! newFolderExists = FileSystemHelper.directoryExistsAsync newFolderPath + Expect.isTrue newFolderExists "Folder does not exist." + let! result = FileSystemHelper.readFileTextAsync newFilePath + Expect.equal result text "Text was not read correctly." + + }) + ] + let main = testList "PathTests" [ fileExists @@ -176,4 +213,5 @@ let main = getSubFiles getSubDirectories getAllFilePaths + rename ] diff --git a/tests/ARCtrl/Main.fs b/tests/ARCtrl/Main.fs index 1d5f138e..d307941d 100644 --- a/tests/ARCtrl/Main.fs +++ b/tests/ARCtrl/Main.fs @@ -3,8 +3,9 @@ module ARCtrl.ARC.Tests open Fable.Pyxpecto let all = testSequenced <| testList "ARCtrl" [ - ARCtrl.ContractIO.Tests.main + ARCtrl.CrossAsync.Tests.main ARCtrl.FileSystemHelper.Tests.main + ARCtrl.ContractIO.Tests.main ARCtrl.Contracts.Tests.main ARCtrl.WebRequest.Tests.main ARCtrl.SemVer.Tests.main diff --git a/tests/All/Main.fs b/tests/All/Main.fs index 105f41d3..b3d9ab75 100644 --- a/tests/All/Main.fs +++ b/tests/All/Main.fs @@ -2,18 +2,17 @@ module Main.Tests open Fable.Pyxpecto -let all = testList "All" [ - +let all = testList "All" [ ARCtrl.Core.Tests.all ARCtrl.Json.Tests.all ARCtrl.Spreadsheet.Tests.all ARCtrl.FileSystem.Tests.all - ARCtrl.ARC.Tests.all ARCtrl.Yaml.Tests.all ARCtrl.ValidationPackages.Tests.all ARCtrl.Contract.Tests.all ARCtrl.ROCrate.Tests.all ARCtrl.CWL.Tests.all + ARCtrl.ARC.Tests.all ] [] From a6438eb834fee7724a364a2cf46d5361fbb23ce3 Mon Sep 17 00:00:00 2001 From: HLWeil Date: Thu, 28 Nov 2024 14:51:19 +0100 Subject: [PATCH 24/30] start working on python arc IO --- ARCtrl.Py.sln | 235 ++++++++++++++++++++++ poetry.lock | 13 +- pyproject.toml | 1 + src/ARCtrl/ARCtrl.Python.fsproj | 12 +- src/ARCtrl/ContractIO/FileSystem.py | 77 +++++++ src/ARCtrl/ContractIO/FileSystemHelper.fs | 60 +++++- src/ARCtrl/Xlsx.fs | 10 +- 7 files changed, 397 insertions(+), 11 deletions(-) create mode 100644 ARCtrl.Py.sln create mode 100644 src/ARCtrl/ContractIO/FileSystem.py diff --git a/ARCtrl.Py.sln b/ARCtrl.Py.sln new file mode 100644 index 00000000..7531e136 --- /dev/null +++ b/ARCtrl.Py.sln @@ -0,0 +1,235 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31903.59 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{326188FB-2CC0-4610-A082-708885BF47AA}" + ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig + .gitignore = .gitignore + .github\workflows\build-test.yml = .github\workflows\build-test.yml + build.cmd = build.cmd + build.sh = build.sh + Directory.Packages.props = Directory.Packages.props + .config\dotnet-tools.json = .config\dotnet-tools.json + global.json = global.json + package.json = package.json + pyproject.toml = pyproject.toml + README.md = README.md + RELEASE_NOTES.md = RELEASE_NOTES.md + setup.cmd = setup.cmd + EndProjectSection +EndProject +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "ARCtrl.CWL", "src\CWL\ARCtrl.CWL.fsproj", "{1CD34A01-D19A-441F-8F3D-6EF69D9DDA8D}" +EndProject +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "ARCtrl.FileSystem", "src\FileSystem\ARCtrl.FileSystem.fsproj", "{F47E23C3-8415-4725-9E85-57271694DEB3}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{6DA2330B-D407-4FB1-AF05-B0184034EC44}" + ProjectSection(SolutionItems) = preProject + src\ARCtrl\ARCtrl.fsproj = src\ARCtrl\ARCtrl.fsproj + src\ARCtrl\ARCtrl.Javascript.fsproj = src\ARCtrl\ARCtrl.Javascript.fsproj + src\Package.Metadata.props = src\Package.Metadata.props + EndProjectSection +EndProject +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "Build", "build\Build.fsproj", "{5EAFB0CD-1168-4FCA-AA61-E96AD6C85819}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{64B34A6E-318D-4E6E-9262-CE52C9B85A38}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "JavaScript", "JavaScript", "{913222CA-261F-49CB-A823-CC7C335F964A}" + ProjectSection(SolutionItems) = preProject + tests\JavaScript\CompositeCell.js = tests\JavaScript\CompositeCell.js + tests\JavaScript\CompositeHeader.js = tests\JavaScript\CompositeHeader.js + tests\JavaScript\JsonController.js = tests\JavaScript\JsonController.js + tests\JavaScript\Main.js = tests\JavaScript\Main.js + tests\JavaScript\Person.js = tests\JavaScript\Person.js + tests\JavaScript\Template.Web.js = tests\JavaScript\Template.Web.js + tests\JavaScript\XlsxController.js = tests\JavaScript\XlsxController.js + EndProjectSection +EndProject +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "ARCtrl.Python", "src\ARCtrl\ARCtrl.Python.fsproj", "{9BE5D83D-EA90-4382-A132-174FD158227F}" +EndProject +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "ARCtrl.Tests", "tests\ARCtrl\ARCtrl.Tests.fsproj", "{801247D5-7EE5-49C8-AB26-F822A415BA49}" +EndProject +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "ARCtrl.Contract", "src\Contract\ARCtrl.Contract.fsproj", "{1945EE8A-F105-43A9-91C9-8C4422B9873E}" +EndProject +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "TestingUtils", "tests\TestingUtils\TestingUtils.fsproj", "{AA011593-6603-4E16-A7B0-0ED3862511DE}" +EndProject +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "Speedtest", "tests\Speedtest\Speedtest.fsproj", "{6EFC7E7D-840E-4506-ADBC-37130A21D1C0}" +EndProject +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "ARCtrl.Json", "src\Json\ARCtrl.Json.fsproj", "{6DCF93BA-A918-42A0-BAD7-A11B72ADFFE6}" +EndProject +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "ARCtrl.Spreadsheet", "src\Spreadsheet\ARCtrl.Spreadsheet.fsproj", "{74EF1B45-C7B7-4281-BDDB-7A653F9F935E}" +EndProject +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "ARCtrl.Core", "src\Core\ARCtrl.Core.fsproj", "{FDA13C07-2E22-49D5-A317-7A68DC359894}" +EndProject +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "ARCtrl.Core.Tests", "tests\Core\ARCtrl.Core.Tests.fsproj", "{EDC4FB2B-40CF-4AFD-90C7-CF88C2745789}" +EndProject +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "ARCtrl.Json.Tests", "tests\Json\ARCtrl.Json.Tests.fsproj", "{9E1FF103-B5BD-44B6-B839-0E1FED2C49EC}" +EndProject +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "ARCtrl.Spreadsheet.Tests", "tests\Spreadsheet\ARCtrl.Spreadsheet.Tests.fsproj", "{03F4E6D0-CFE7-44A6-994B-778B3DF6532C}" +EndProject +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "ARCtrl.FileSystem.Tests", "tests\FileSystem\ARCtrl.FileSystem.Tests.fsproj", "{704935A5-68F2-4070-8A55-AFF8F66ACAD6}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Python", "Python", "{501F6D1E-6300-4CA4-8E61-3523BCF4D533}" + ProjectSection(SolutionItems) = preProject + tests\Python\test_index.py = tests\Python\test_index.py + tests\Python\test_JsonController.py = tests\Python\test_JsonController.py + tests\Python\test_OntologyAnnotation.py = tests\Python\test_OntologyAnnotation.py + tests\Python\test_XlsxController.py = tests\Python\test_XlsxController.py + EndProjectSection +EndProject +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "ARCtrl.ValidationPackages", "src\ValidationPackages\ARCtrl.ValidationPackages.fsproj", "{0C35D768-BF55-4BD9-B915-35125CED65A0}" +EndProject +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "ARCtrl.Yaml", "src\Yaml\ARCtrl.Yaml.fsproj", "{4CC3AAC2-030B-4B2E-A386-9C1F68E42238}" +EndProject +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "ARCtrl.ValidationPackages.Tests", "tests\ValidationPackages\ARCtrl.ValidationPackages.Tests.fsproj", "{1CA11165-4B70-41D2-A846-50374E85385E}" +EndProject +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "ARCtrl.Yaml.Tests", "tests\Yaml\ARCtrl.Yaml.Tests.fsproj", "{5810EF87-4F85-4B4C-98E3-833AE914C628}" +EndProject +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "ARCtrl.Contract.Tests", "tests\Contract\ARCtrl.Contract.Tests.fsproj", "{D10D12C7-B877-423B-867D-161D99E673C9}" +EndProject +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "ARCtrl.CWL.Tests", "tests\CWL\ARCtrl.CWL.Tests.fsproj", "{0F2188D3-144C-41BF-89F6-AA85883AE0D3}" +EndProject +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "ARCtrl.ROCrate", "src\ROCrate\ARCtrl.ROCrate.fsproj", "{658BF141-B4B5-4B90-891D-AC36A3FD7574}" +EndProject +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "ARCtrl.ROCrate.Tests", "tests\ROCrate\ARCtrl.ROCrate.Tests.fsproj", "{212A1C64-02FC-465A-B0FA-F69735F37ACC}" +EndProject +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "All.Tests", "tests\All\All.Tests.fsproj", "{243ACD5F-10AD-4BE6-9932-829667BE2053}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {1CD34A01-D19A-441F-8F3D-6EF69D9DDA8D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1CD34A01-D19A-441F-8F3D-6EF69D9DDA8D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1CD34A01-D19A-441F-8F3D-6EF69D9DDA8D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1CD34A01-D19A-441F-8F3D-6EF69D9DDA8D}.Release|Any CPU.Build.0 = Release|Any CPU + {F47E23C3-8415-4725-9E85-57271694DEB3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F47E23C3-8415-4725-9E85-57271694DEB3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F47E23C3-8415-4725-9E85-57271694DEB3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F47E23C3-8415-4725-9E85-57271694DEB3}.Release|Any CPU.Build.0 = Release|Any CPU + {5EAFB0CD-1168-4FCA-AA61-E96AD6C85819}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5EAFB0CD-1168-4FCA-AA61-E96AD6C85819}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5EAFB0CD-1168-4FCA-AA61-E96AD6C85819}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5EAFB0CD-1168-4FCA-AA61-E96AD6C85819}.Release|Any CPU.Build.0 = Release|Any CPU + {9BE5D83D-EA90-4382-A132-174FD158227F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9BE5D83D-EA90-4382-A132-174FD158227F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9BE5D83D-EA90-4382-A132-174FD158227F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9BE5D83D-EA90-4382-A132-174FD158227F}.Release|Any CPU.Build.0 = Release|Any CPU + {801247D5-7EE5-49C8-AB26-F822A415BA49}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {801247D5-7EE5-49C8-AB26-F822A415BA49}.Debug|Any CPU.Build.0 = Debug|Any CPU + {801247D5-7EE5-49C8-AB26-F822A415BA49}.Release|Any CPU.ActiveCfg = Release|Any CPU + {801247D5-7EE5-49C8-AB26-F822A415BA49}.Release|Any CPU.Build.0 = Release|Any CPU + {1945EE8A-F105-43A9-91C9-8C4422B9873E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1945EE8A-F105-43A9-91C9-8C4422B9873E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1945EE8A-F105-43A9-91C9-8C4422B9873E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1945EE8A-F105-43A9-91C9-8C4422B9873E}.Release|Any CPU.Build.0 = Release|Any CPU + {AA011593-6603-4E16-A7B0-0ED3862511DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AA011593-6603-4E16-A7B0-0ED3862511DE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AA011593-6603-4E16-A7B0-0ED3862511DE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AA011593-6603-4E16-A7B0-0ED3862511DE}.Release|Any CPU.Build.0 = Release|Any CPU + {6EFC7E7D-840E-4506-ADBC-37130A21D1C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6EFC7E7D-840E-4506-ADBC-37130A21D1C0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6EFC7E7D-840E-4506-ADBC-37130A21D1C0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6EFC7E7D-840E-4506-ADBC-37130A21D1C0}.Release|Any CPU.Build.0 = Release|Any CPU + {6DCF93BA-A918-42A0-BAD7-A11B72ADFFE6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6DCF93BA-A918-42A0-BAD7-A11B72ADFFE6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6DCF93BA-A918-42A0-BAD7-A11B72ADFFE6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6DCF93BA-A918-42A0-BAD7-A11B72ADFFE6}.Release|Any CPU.Build.0 = Release|Any CPU + {74EF1B45-C7B7-4281-BDDB-7A653F9F935E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {74EF1B45-C7B7-4281-BDDB-7A653F9F935E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {74EF1B45-C7B7-4281-BDDB-7A653F9F935E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {74EF1B45-C7B7-4281-BDDB-7A653F9F935E}.Release|Any CPU.Build.0 = Release|Any CPU + {FDA13C07-2E22-49D5-A317-7A68DC359894}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FDA13C07-2E22-49D5-A317-7A68DC359894}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FDA13C07-2E22-49D5-A317-7A68DC359894}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FDA13C07-2E22-49D5-A317-7A68DC359894}.Release|Any CPU.Build.0 = Release|Any CPU + {EDC4FB2B-40CF-4AFD-90C7-CF88C2745789}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EDC4FB2B-40CF-4AFD-90C7-CF88C2745789}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EDC4FB2B-40CF-4AFD-90C7-CF88C2745789}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EDC4FB2B-40CF-4AFD-90C7-CF88C2745789}.Release|Any CPU.Build.0 = Release|Any CPU + {9E1FF103-B5BD-44B6-B839-0E1FED2C49EC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9E1FF103-B5BD-44B6-B839-0E1FED2C49EC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9E1FF103-B5BD-44B6-B839-0E1FED2C49EC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9E1FF103-B5BD-44B6-B839-0E1FED2C49EC}.Release|Any CPU.Build.0 = Release|Any CPU + {03F4E6D0-CFE7-44A6-994B-778B3DF6532C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {03F4E6D0-CFE7-44A6-994B-778B3DF6532C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {03F4E6D0-CFE7-44A6-994B-778B3DF6532C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {03F4E6D0-CFE7-44A6-994B-778B3DF6532C}.Release|Any CPU.Build.0 = Release|Any CPU + {704935A5-68F2-4070-8A55-AFF8F66ACAD6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {704935A5-68F2-4070-8A55-AFF8F66ACAD6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {704935A5-68F2-4070-8A55-AFF8F66ACAD6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {704935A5-68F2-4070-8A55-AFF8F66ACAD6}.Release|Any CPU.Build.0 = Release|Any CPU + {0C35D768-BF55-4BD9-B915-35125CED65A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0C35D768-BF55-4BD9-B915-35125CED65A0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0C35D768-BF55-4BD9-B915-35125CED65A0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0C35D768-BF55-4BD9-B915-35125CED65A0}.Release|Any CPU.Build.0 = Release|Any CPU + {4CC3AAC2-030B-4B2E-A386-9C1F68E42238}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4CC3AAC2-030B-4B2E-A386-9C1F68E42238}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4CC3AAC2-030B-4B2E-A386-9C1F68E42238}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4CC3AAC2-030B-4B2E-A386-9C1F68E42238}.Release|Any CPU.Build.0 = Release|Any CPU + {1CA11165-4B70-41D2-A846-50374E85385E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1CA11165-4B70-41D2-A846-50374E85385E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1CA11165-4B70-41D2-A846-50374E85385E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1CA11165-4B70-41D2-A846-50374E85385E}.Release|Any CPU.Build.0 = Release|Any CPU + {5810EF87-4F85-4B4C-98E3-833AE914C628}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5810EF87-4F85-4B4C-98E3-833AE914C628}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5810EF87-4F85-4B4C-98E3-833AE914C628}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5810EF87-4F85-4B4C-98E3-833AE914C628}.Release|Any CPU.Build.0 = Release|Any CPU + {D10D12C7-B877-423B-867D-161D99E673C9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D10D12C7-B877-423B-867D-161D99E673C9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D10D12C7-B877-423B-867D-161D99E673C9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D10D12C7-B877-423B-867D-161D99E673C9}.Release|Any CPU.Build.0 = Release|Any CPU + {0F2188D3-144C-41BF-89F6-AA85883AE0D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0F2188D3-144C-41BF-89F6-AA85883AE0D3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0F2188D3-144C-41BF-89F6-AA85883AE0D3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0F2188D3-144C-41BF-89F6-AA85883AE0D3}.Release|Any CPU.Build.0 = Release|Any CPU + {658BF141-B4B5-4B90-891D-AC36A3FD7574}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {658BF141-B4B5-4B90-891D-AC36A3FD7574}.Debug|Any CPU.Build.0 = Debug|Any CPU + {658BF141-B4B5-4B90-891D-AC36A3FD7574}.Release|Any CPU.ActiveCfg = Release|Any CPU + {658BF141-B4B5-4B90-891D-AC36A3FD7574}.Release|Any CPU.Build.0 = Release|Any CPU + {212A1C64-02FC-465A-B0FA-F69735F37ACC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {212A1C64-02FC-465A-B0FA-F69735F37ACC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {212A1C64-02FC-465A-B0FA-F69735F37ACC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {212A1C64-02FC-465A-B0FA-F69735F37ACC}.Release|Any CPU.Build.0 = Release|Any CPU + {243ACD5F-10AD-4BE6-9932-829667BE2053}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {243ACD5F-10AD-4BE6-9932-829667BE2053}.Debug|Any CPU.Build.0 = Debug|Any CPU + {243ACD5F-10AD-4BE6-9932-829667BE2053}.Release|Any CPU.ActiveCfg = Release|Any CPU + {243ACD5F-10AD-4BE6-9932-829667BE2053}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {1CD34A01-D19A-441F-8F3D-6EF69D9DDA8D} = {6DA2330B-D407-4FB1-AF05-B0184034EC44} + {F47E23C3-8415-4725-9E85-57271694DEB3} = {6DA2330B-D407-4FB1-AF05-B0184034EC44} + {913222CA-261F-49CB-A823-CC7C335F964A} = {64B34A6E-318D-4E6E-9262-CE52C9B85A38} + {9BE5D83D-EA90-4382-A132-174FD158227F} = {6DA2330B-D407-4FB1-AF05-B0184034EC44} + {801247D5-7EE5-49C8-AB26-F822A415BA49} = {64B34A6E-318D-4E6E-9262-CE52C9B85A38} + {1945EE8A-F105-43A9-91C9-8C4422B9873E} = {6DA2330B-D407-4FB1-AF05-B0184034EC44} + {AA011593-6603-4E16-A7B0-0ED3862511DE} = {64B34A6E-318D-4E6E-9262-CE52C9B85A38} + {6EFC7E7D-840E-4506-ADBC-37130A21D1C0} = {64B34A6E-318D-4E6E-9262-CE52C9B85A38} + {6DCF93BA-A918-42A0-BAD7-A11B72ADFFE6} = {6DA2330B-D407-4FB1-AF05-B0184034EC44} + {74EF1B45-C7B7-4281-BDDB-7A653F9F935E} = {6DA2330B-D407-4FB1-AF05-B0184034EC44} + {FDA13C07-2E22-49D5-A317-7A68DC359894} = {6DA2330B-D407-4FB1-AF05-B0184034EC44} + {EDC4FB2B-40CF-4AFD-90C7-CF88C2745789} = {64B34A6E-318D-4E6E-9262-CE52C9B85A38} + {9E1FF103-B5BD-44B6-B839-0E1FED2C49EC} = {64B34A6E-318D-4E6E-9262-CE52C9B85A38} + {03F4E6D0-CFE7-44A6-994B-778B3DF6532C} = {64B34A6E-318D-4E6E-9262-CE52C9B85A38} + {704935A5-68F2-4070-8A55-AFF8F66ACAD6} = {64B34A6E-318D-4E6E-9262-CE52C9B85A38} + {501F6D1E-6300-4CA4-8E61-3523BCF4D533} = {64B34A6E-318D-4E6E-9262-CE52C9B85A38} + {0C35D768-BF55-4BD9-B915-35125CED65A0} = {6DA2330B-D407-4FB1-AF05-B0184034EC44} + {4CC3AAC2-030B-4B2E-A386-9C1F68E42238} = {6DA2330B-D407-4FB1-AF05-B0184034EC44} + {1CA11165-4B70-41D2-A846-50374E85385E} = {64B34A6E-318D-4E6E-9262-CE52C9B85A38} + {5810EF87-4F85-4B4C-98E3-833AE914C628} = {64B34A6E-318D-4E6E-9262-CE52C9B85A38} + {D10D12C7-B877-423B-867D-161D99E673C9} = {64B34A6E-318D-4E6E-9262-CE52C9B85A38} + {0F2188D3-144C-41BF-89F6-AA85883AE0D3} = {64B34A6E-318D-4E6E-9262-CE52C9B85A38} + {658BF141-B4B5-4B90-891D-AC36A3FD7574} = {6DA2330B-D407-4FB1-AF05-B0184034EC44} + {212A1C64-02FC-465A-B0FA-F69735F37ACC} = {64B34A6E-318D-4E6E-9262-CE52C9B85A38} + {243ACD5F-10AD-4BE6-9932-829667BE2053} = {64B34A6E-318D-4E6E-9262-CE52C9B85A38} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {1E354DE6-99BA-421E-9EF8-E808B855A85F} + EndGlobalSection +EndGlobal diff --git a/poetry.lock b/poetry.lock index bedc9a0f..77bc899f 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,5 +1,16 @@ # This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. +[[package]] +name = "aiofiles" +version = "24.1.0" +description = "File support for asyncio." +optional = false +python-versions = ">=3.8" +files = [ + {file = "aiofiles-24.1.0-py3-none-any.whl", hash = "sha256:b4ec55f4195e3eb5d7abd1bf7e061763e864dd4954231fb8539a0ef8bb8260e5"}, + {file = "aiofiles-24.1.0.tar.gz", hash = "sha256:22a075c9e5a3810f0c2e48f3008c94d68c65d763b9b03857924c99e57355166c"}, +] + [[package]] name = "certifi" version = "2024.8.30" @@ -275,4 +286,4 @@ zstd = ["zstandard (>=0.18.0)"] [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "794df1a08e3d6aad021d482d5d891ea8dbd0bb232c9d74c4d0c1993ac38eb6d8" +content-hash = "4d75da032ba7d5f24863c5b3f0a367a56f8aed3cdf69763bb553fa4c13b22ab5" diff --git a/pyproject.toml b/pyproject.toml index 098e809a..7ba31285 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,6 +11,7 @@ keywords = ["arc", "annotated research context", "isa", "research data", "multi [tool.poetry.dependencies] python = "^3.10" requests = ">= 2.28.1, <3.0.0" +aiofiles = "^24.1.0" [tool.poetry.group.dev.dependencies] pytest = "^8.1.1" diff --git a/src/ARCtrl/ARCtrl.Python.fsproj b/src/ARCtrl/ARCtrl.Python.fsproj index 58d07b35..b8d8edee 100644 --- a/src/ARCtrl/ARCtrl.Python.fsproj +++ b/src/ARCtrl/ARCtrl.Python.fsproj @@ -9,6 +9,8 @@ + + @@ -48,14 +50,13 @@ - - + - - - + + + @@ -66,6 +67,7 @@ + diff --git a/src/ARCtrl/ContractIO/FileSystem.py b/src/ARCtrl/ContractIO/FileSystem.py new file mode 100644 index 00000000..26131aeb --- /dev/null +++ b/src/ARCtrl/ContractIO/FileSystem.py @@ -0,0 +1,77 @@ +import asyncio +import os +import shutil +from pathlib import Path +import aiofiles + +# Check if a directory exists +async def directory_exists(path): + return Path(path).is_dir() + +# Create a directory +async def create_directory(path): + Path(path).mkdir(parents=True, exist_ok=True) + +# Ensure a directory exists +async def ensure_directory(path): + if not await directory_exists(path): + await create_directory(path) + +# Ensure the directory for a file exists +async def ensure_directory_of_file(file_path): + dir_path = Path(file_path).parent + await ensure_directory(dir_path) + +# Check if a file exists +async def file_exists(path): + return Path(path).is_file() + +# Get subdirectories in a directory combined with the input path +async def get_subdirectories(path): + return [str(entry) for entry in Path(path).iterdir() if entry.is_dir()] + +# Get the path of all files in a directory combined with the input path +async def get_subfiles(path): + return [str(entry) for entry in Path(path).iterdir() if entry.is_file()] + +# Move a file +async def move_file(old_path, new_path): + shutil.move(old_path, new_path) + +# Move a directory +async def move_directory(old_path, new_path): + shutil.move(old_path, new_path) + +# Delete a file +async def delete_file(path): + try: + os.remove(path) + except FileNotFoundError: + pass + +# Delete a directory (and its contents) +async def delete_directory(path): + shutil.rmtree(path, ignore_errors=True) + +# Read file as text +async def read_file_text(path): + async with aiofiles.open(path, mode='r', encoding='utf-8') as f: + return await f.read() + +# Read file as binary +async def read_file_binary(path): + async with aiofiles.open(path, mode='rb') as f: + return await f.read() + +# Write text to a file +async def write_file_text(path, text): + async with aiofiles.open(path, mode='w', encoding='utf-8') as f: + await f.write(text) + +# Write binary data to a file +async def write_file_binary(path, bytes_data): + async with aiofiles.open(path, mode='wb') as f: + await f.write(bytes_data) + +# Example usage +# asyncio.run(ensure_directory('test_dir')) diff --git a/src/ARCtrl/ContractIO/FileSystemHelper.fs b/src/ARCtrl/ContractIO/FileSystemHelper.fs index eb01b1c4..e0868cb5 100644 --- a/src/ARCtrl/ContractIO/FileSystemHelper.fs +++ b/src/ARCtrl/ContractIO/FileSystemHelper.fs @@ -1,8 +1,6 @@ module ARCtrl.FileSystemHelper open FsSpreadsheet -open CrossAsync - open CrossAsync open Fable.Core open Fable @@ -11,6 +9,11 @@ open Fable open Fable.Core.JsInterop open FsSpreadsheet.Js #endif +#if FABLE_COMPILER_PYTHON +open FsSpreadsheet.Py +open Fable.Core.PyInterop +#endif + #if !FABLE_COMPILER open FsSpreadsheet.Net #endif @@ -19,6 +22,9 @@ let directoryExistsAsync (path : string) : CrossAsync = #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT import "directoryExists" "./FileSystem.js" #endif + #if FABLE_COMPILER_PYTHON + import "directoryExists" "./FileSystem.py" + #endif #if !FABLE_COMPILER crossAsync { return System.IO.Directory.Exists path @@ -29,6 +35,9 @@ let createDirectoryAsync (path : string) : CrossAsync = #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT import "createDirectory" "./FileSystem.js" #endif + #if FABLE_COMPILER_PYTHON + import "createDirectory" "./FileSystem.py" + #endif #if !FABLE_COMPILER crossAsync { System.IO.Directory.CreateDirectory path |> ignore @@ -39,6 +48,9 @@ let ensureDirectoryAsync (path : string) : CrossAsync = #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT import "ensureDirectory" "./FileSystem.js" #endif + #if FABLE_COMPILER_PYTHON + import "ensureDirectory" "./FileSystem.py" + #endif #if !FABLE_COMPILER crossAsync { let! exists = directoryExistsAsync path @@ -51,6 +63,9 @@ let ensureDirectoryOfFileAsync (filePath : string) : CrossAsync = #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT import "ensureDirectoryOfFile" "./FileSystem.js" #endif + #if FABLE_COMPILER_PYTHON + import "ensureDirectoryOfFile" "./FileSystem.py" + #endif #if !FABLE_COMPILER crossAsync { let file = new System.IO.FileInfo(filePath); @@ -62,6 +77,9 @@ let fileExistsAsync (path : string) : CrossAsync = #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT import "fileExists" "./FileSystem.js" #endif + #if FABLE_COMPILER_PYTHON + import "fileExists" "./FileSystem.py" + #endif #if !FABLE_COMPILER crossAsync { return System.IO.File.Exists path @@ -74,6 +92,9 @@ let readFileTextAsync (path : string) : CrossAsync = #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT import "readFileText" "./FileSystem.js" #endif + #if FABLE_COMPILER_PYTHON + import "readFileText" "./FileSystem.py" + #endif #if !FABLE_COMPILER crossAsync { return System.IO.File.ReadAllText path @@ -84,6 +105,9 @@ let readFileBinaryAsync (path : string) : CrossAsync = #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT import "readFileBinary" "./FileSystem.js" #endif + #if FABLE_COMPILER_PYTHON + import "readFileBinary" "./FileSystem.py" + #endif #if !FABLE_COMPILER crossAsync { return System.IO.File.ReadAllBytes path @@ -104,6 +128,9 @@ let moveFileAsync oldPath newPath = #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT import "moveFile" "./FileSystem.js" #endif + #if FABLE_COMPILER_PYTHON + import "moveFile" "./FileSystem.py" + #endif #if !FABLE_COMPILER crossAsync { System.IO.File.Move(oldPath, newPath) @@ -114,6 +141,9 @@ let moveDirectoryAsync oldPath newPath = #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT import "moveDirectory" "./FileSystem.js" #endif + #if FABLE_COMPILER_PYTHON + import "moveDirectory" "./FileSystem.py" + #endif #if !FABLE_COMPILER crossAsync { System.IO.Directory.Move(oldPath, newPath) @@ -124,6 +154,9 @@ let deleteFileAsync path = #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT import "deleteFile" "./FileSystem.js" #endif + #if FABLE_COMPILER_PYTHON + import "deleteFile" "./FileSystem.py" + #endif #if !FABLE_COMPILER crossAsync { System.IO.File.Delete path @@ -134,6 +167,9 @@ let deleteDirectoryAsync path = #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT import "deleteDirectory" "./FileSystem.js" #endif + #if FABLE_COMPILER_PYTHON + import "deleteDirectory" "./FileSystem.py" + #endif #if !FABLE_COMPILER crossAsync { System.IO.Directory.Delete(path, true) @@ -145,6 +181,9 @@ let writeFileTextAsync path text = #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT import "writeFileText" "./FileSystem.js" #endif + #if FABLE_COMPILER_PYTHON + import "writeFileText" "./FileSystem.py" + #endif #if !FABLE_COMPILER crossAsync { System.IO.File.WriteAllText(path, text) @@ -155,6 +194,9 @@ let writeFileBinaryAsync path (bytes : byte []) = #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT import "writeFileBinary" "./FileSystem.js" #endif + #if FABLE_COMPILER_PYTHON + import "writeFileBinary" "./FileSystem.py" + #endif #if !FABLE_COMPILER crossAsync { System.IO.File.WriteAllBytes(path, bytes) @@ -193,6 +235,13 @@ let getSubDirectoriesAsync (path : string) : CrossAsync = return paths |> Array.map standardizeSlashes } #endif + #if FABLE_COMPILER_PYTHON + let f : string -> CrossAsync = import "getSubDirectories" "./FileSystem.py" + crossAsync { + let! paths = f path + return paths |> Array.map standardizeSlashes + } + #endif #if !FABLE_COMPILER crossAsync { let paths = System.IO.Directory.GetDirectories path @@ -208,6 +257,13 @@ let getSubFilesAsync (path : string) : CrossAsync = return paths |> Array.map standardizeSlashes } #endif + #if FABLE_COMPILER_PYTHON + let f : string -> CrossAsync = import "getSubFiles" "./FileSystem.py" + crossAsync { + let! paths = f path + return paths |> Array.map standardizeSlashes + } + #endif #if !FABLE_COMPILER crossAsync { let paths = System.IO.Directory.GetFiles path diff --git a/src/ARCtrl/Xlsx.fs b/src/ARCtrl/Xlsx.fs index b9a4476e..092edb8e 100644 --- a/src/ARCtrl/Xlsx.fs +++ b/src/ARCtrl/Xlsx.fs @@ -6,12 +6,16 @@ open ARCtrl.Spreadsheet open Fable.Core open FsSpreadsheet -#if !FABLE_COMPILER -open FsSpreadsheet.Net -#endif #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT open FsSpreadsheet.Js #endif +#if FABLE_COMPILER_PYTHON +open FsSpreadsheet.Py +#endif +#if !FABLE_COMPILER +open FsSpreadsheet.Net +#endif + module XlsxHelper = From ac29af603dc48be54c1e3e62f720a3e574cc1e2e Mon Sep 17 00:00:00 2001 From: HLWeil Date: Fri, 29 Nov 2024 17:14:15 +0100 Subject: [PATCH 25/30] finish up first version python arc io --- Directory.Packages.props | 8 +- poetry.lock | 76 +++++++++++++++---- pyproject.toml | 2 +- src/ARCtrl/ARCtrl.Python.fsproj | 8 +- src/ARCtrl/ContractIO/FileSystemHelper.fs | 73 +++++++++++++----- .../{FileSystem.py => file_system.py} | 53 +++++++------ 6 files changed, 151 insertions(+), 69 deletions(-) rename src/ARCtrl/ContractIO/{FileSystem.py => file_system.py} (51%) diff --git a/Directory.Packages.props b/Directory.Packages.props index fd29366c..77d02835 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -10,10 +10,10 @@ - - - - + + + + diff --git a/poetry.lock b/poetry.lock index 77bc899f..dfac0798 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,15 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. - -[[package]] -name = "aiofiles" -version = "24.1.0" -description = "File support for asyncio." -optional = false -python-versions = ">=3.8" -files = [ - {file = "aiofiles-24.1.0-py3-none-any.whl", hash = "sha256:b4ec55f4195e3eb5d7abd1bf7e061763e864dd4954231fb8539a0ef8bb8260e5"}, - {file = "aiofiles-24.1.0.tar.gz", hash = "sha256:22a075c9e5a3810f0c2e48f3008c94d68c65d763b9b03857924c99e57355166c"}, -] +# This file is automatically @generated by Poetry 1.8.4 and should not be changed by hand. [[package]] name = "certifi" @@ -147,6 +136,17 @@ files = [ {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] +[[package]] +name = "et-xmlfile" +version = "2.0.0" +description = "An implementation of lxml.xmlfile for the standard library" +optional = false +python-versions = ">=3.8" +files = [ + {file = "et_xmlfile-2.0.0-py3-none-any.whl", hash = "sha256:7a91720bc756843502c3b7504c77b8fe44217c85c537d85037f0f536151b2caa"}, + {file = "et_xmlfile-2.0.0.tar.gz", hash = "sha256:dab3f4764309081ce75662649be815c4c9081e88f0837825f90fd28317d4da54"}, +] + [[package]] name = "exceptiongroup" version = "1.2.2" @@ -186,6 +186,20 @@ files = [ {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, ] +[[package]] +name = "openpyxl" +version = "3.1.5" +description = "A Python library to read/write Excel 2010 xlsx/xlsm files" +optional = false +python-versions = ">=3.8" +files = [ + {file = "openpyxl-3.1.5-py2.py3-none-any.whl", hash = "sha256:5282c12b107bffeef825f4617dc029afaf41d0ea60823bbb665ef3079dc79de2"}, + {file = "openpyxl-3.1.5.tar.gz", hash = "sha256:cf0e3cf56142039133628b5acffe8ef0c12bc902d2aadd3e0fe5878dc08d1050"}, +] + +[package.dependencies] +et-xmlfile = "*" + [[package]] name = "packaging" version = "24.2" @@ -257,13 +271,43 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] [[package]] name = "tomli" -version = "2.1.0" +version = "2.2.1" description = "A lil' TOML parser" optional = false python-versions = ">=3.8" files = [ - {file = "tomli-2.1.0-py3-none-any.whl", hash = "sha256:a5c57c3d1c56f5ccdf89f6523458f60ef716e210fc47c4cfb188c5ba473e0391"}, - {file = "tomli-2.1.0.tar.gz", hash = "sha256:3f646cae2aec94e17d04973e4249548320197cfabdf130015d023de4b74d8ab8"}, + {file = "tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249"}, + {file = "tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8"}, + {file = "tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff"}, + {file = "tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b"}, + {file = "tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea"}, + {file = "tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e"}, + {file = "tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98"}, + {file = "tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4"}, + {file = "tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7"}, + {file = "tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744"}, + {file = "tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec"}, + {file = "tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69"}, + {file = "tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc"}, + {file = "tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff"}, ] [[package]] @@ -286,4 +330,4 @@ zstd = ["zstandard (>=0.18.0)"] [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "4d75da032ba7d5f24863c5b3f0a367a56f8aed3cdf69763bb553fa4c13b22ab5" +content-hash = "85c34f0b500bd5d4a5e72bdbd410408a5b65e2d65ea2ce79d2f7f0e9bf0e08ad" diff --git a/pyproject.toml b/pyproject.toml index 7ba31285..a2908a7d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,7 +11,7 @@ keywords = ["arc", "annotated research context", "isa", "research data", "multi [tool.poetry.dependencies] python = "^3.10" requests = ">= 2.28.1, <3.0.0" -aiofiles = "^24.1.0" +openpyxl = "^3.1.5" [tool.poetry.group.dev.dependencies] pytest = "^8.1.1" diff --git a/src/ARCtrl/ARCtrl.Python.fsproj b/src/ARCtrl/ARCtrl.Python.fsproj index b8d8edee..1859409e 100644 --- a/src/ARCtrl/ARCtrl.Python.fsproj +++ b/src/ARCtrl/ARCtrl.Python.fsproj @@ -11,7 +11,7 @@ - + @@ -54,7 +54,7 @@ - + @@ -66,8 +66,8 @@ - - + + diff --git a/src/ARCtrl/ContractIO/FileSystemHelper.fs b/src/ARCtrl/ContractIO/FileSystemHelper.fs index e0868cb5..d5efbf26 100644 --- a/src/ARCtrl/ContractIO/FileSystemHelper.fs +++ b/src/ARCtrl/ContractIO/FileSystemHelper.fs @@ -23,7 +23,10 @@ let directoryExistsAsync (path : string) : CrossAsync = import "directoryExists" "./FileSystem.js" #endif #if FABLE_COMPILER_PYTHON - import "directoryExists" "./FileSystem.py" + let f : string -> bool = import "directoryExists" "./file_system.py" + crossAsync { + return f path + } #endif #if !FABLE_COMPILER crossAsync { @@ -36,7 +39,10 @@ let createDirectoryAsync (path : string) : CrossAsync = import "createDirectory" "./FileSystem.js" #endif #if FABLE_COMPILER_PYTHON - import "createDirectory" "./FileSystem.py" + let f : string -> unit =import "createDirectory" "./file_system.py" + crossAsync { + f path + } #endif #if !FABLE_COMPILER crossAsync { @@ -49,7 +55,10 @@ let ensureDirectoryAsync (path : string) : CrossAsync = import "ensureDirectory" "./FileSystem.js" #endif #if FABLE_COMPILER_PYTHON - import "ensureDirectory" "./FileSystem.py" + let f : string -> unit = import "ensureDirectory" "./file_system.py" + crossAsync { + f path + } #endif #if !FABLE_COMPILER crossAsync { @@ -64,7 +73,10 @@ let ensureDirectoryOfFileAsync (filePath : string) : CrossAsync = import "ensureDirectoryOfFile" "./FileSystem.js" #endif #if FABLE_COMPILER_PYTHON - import "ensureDirectoryOfFile" "./FileSystem.py" + let f : string -> unit = import "ensureDirectoryOfFile" "./file_system.py" + crossAsync { + f filePath + } #endif #if !FABLE_COMPILER crossAsync { @@ -78,7 +90,10 @@ let fileExistsAsync (path : string) : CrossAsync = import "fileExists" "./FileSystem.js" #endif #if FABLE_COMPILER_PYTHON - import "fileExists" "./FileSystem.py" + let f : string -> bool = import "fileExists" "./file_system.py" + crossAsync { + return f path + } #endif #if !FABLE_COMPILER crossAsync { @@ -93,7 +108,10 @@ let readFileTextAsync (path : string) : CrossAsync = import "readFileText" "./FileSystem.js" #endif #if FABLE_COMPILER_PYTHON - import "readFileText" "./FileSystem.py" + let f : string -> string = import "readFileText" "./file_system.py" + crossAsync { + return f path + } #endif #if !FABLE_COMPILER crossAsync { @@ -106,7 +124,10 @@ let readFileBinaryAsync (path : string) : CrossAsync = import "readFileBinary" "./FileSystem.js" #endif #if FABLE_COMPILER_PYTHON - import "readFileBinary" "./FileSystem.py" + let f : string -> byte [] = import "readFileBinary" "./file_system.py" + crossAsync { + return f path + } #endif #if !FABLE_COMPILER crossAsync { @@ -129,7 +150,10 @@ let moveFileAsync oldPath newPath = import "moveFile" "./FileSystem.js" #endif #if FABLE_COMPILER_PYTHON - import "moveFile" "./FileSystem.py" + let f : string * string -> unit = import "moveFile" "./file_system.py" + crossAsync { + f (oldPath,newPath) + } #endif #if !FABLE_COMPILER crossAsync { @@ -142,7 +166,10 @@ let moveDirectoryAsync oldPath newPath = import "moveDirectory" "./FileSystem.js" #endif #if FABLE_COMPILER_PYTHON - import "moveDirectory" "./FileSystem.py" + let f : string * string -> unit = import "moveDirectory" "./file_system.py" + crossAsync { + f (oldPath,newPath) + } #endif #if !FABLE_COMPILER crossAsync { @@ -155,7 +182,10 @@ let deleteFileAsync path = import "deleteFile" "./FileSystem.js" #endif #if FABLE_COMPILER_PYTHON - import "deleteFile" "./FileSystem.py" + let f : string -> unit = import "deleteFile" "./file_system.py" + crossAsync { + f path + } #endif #if !FABLE_COMPILER crossAsync { @@ -168,7 +198,10 @@ let deleteDirectoryAsync path = import "deleteDirectory" "./FileSystem.js" #endif #if FABLE_COMPILER_PYTHON - import "deleteDirectory" "./FileSystem.py" + let f : string -> unit =import "deleteDirectory" "./file_system.py" + crossAsync { + f path + } #endif #if !FABLE_COMPILER crossAsync { @@ -182,7 +215,10 @@ let writeFileTextAsync path text = import "writeFileText" "./FileSystem.js" #endif #if FABLE_COMPILER_PYTHON - import "writeFileText" "./FileSystem.py" + let f : string * string -> unit = import "writeFileText" "./file_system.py" + crossAsync { + f(path,text) + } #endif #if !FABLE_COMPILER crossAsync { @@ -195,7 +231,10 @@ let writeFileBinaryAsync path (bytes : byte []) = import "writeFileBinary" "./FileSystem.js" #endif #if FABLE_COMPILER_PYTHON - import "writeFileBinary" "./FileSystem.py" + let f : string * byte [] -> unit = import "writeFileBinary" "./file_system.py" + crossAsync { + f (path,bytes) + } #endif #if !FABLE_COMPILER crossAsync { @@ -236,9 +275,9 @@ let getSubDirectoriesAsync (path : string) : CrossAsync = } #endif #if FABLE_COMPILER_PYTHON - let f : string -> CrossAsync = import "getSubDirectories" "./FileSystem.py" + let f : string -> string [] = import "getSubDirectories" "./file_system.py" crossAsync { - let! paths = f path + let paths = f path return paths |> Array.map standardizeSlashes } #endif @@ -258,9 +297,9 @@ let getSubFilesAsync (path : string) : CrossAsync = } #endif #if FABLE_COMPILER_PYTHON - let f : string -> CrossAsync = import "getSubFiles" "./FileSystem.py" + let f : string -> string [] = import "getSubFiles" "./file_system.py" crossAsync { - let! paths = f path + let paths = f path return paths |> Array.map standardizeSlashes } #endif diff --git a/src/ARCtrl/ContractIO/FileSystem.py b/src/ARCtrl/ContractIO/file_system.py similarity index 51% rename from src/ARCtrl/ContractIO/FileSystem.py rename to src/ARCtrl/ContractIO/file_system.py index 26131aeb..743d2c3e 100644 --- a/src/ARCtrl/ContractIO/FileSystem.py +++ b/src/ARCtrl/ContractIO/file_system.py @@ -2,76 +2,75 @@ import os import shutil from pathlib import Path -import aiofiles # Check if a directory exists -async def directory_exists(path): +def directory_exists(path): return Path(path).is_dir() # Create a directory -async def create_directory(path): +def create_directory(path): Path(path).mkdir(parents=True, exist_ok=True) # Ensure a directory exists -async def ensure_directory(path): - if not await directory_exists(path): - await create_directory(path) +def ensure_directory(path): + if not directory_exists(path): + create_directory(path) # Ensure the directory for a file exists -async def ensure_directory_of_file(file_path): +def ensure_directory_of_file(file_path): dir_path = Path(file_path).parent - await ensure_directory(dir_path) + ensure_directory(dir_path) # Check if a file exists -async def file_exists(path): +def file_exists(path): return Path(path).is_file() # Get subdirectories in a directory combined with the input path -async def get_subdirectories(path): +def get_sub_directories(path): return [str(entry) for entry in Path(path).iterdir() if entry.is_dir()] # Get the path of all files in a directory combined with the input path -async def get_subfiles(path): +def get_sub_files(path): return [str(entry) for entry in Path(path).iterdir() if entry.is_file()] # Move a file -async def move_file(old_path, new_path): +def move_file(old_path, new_path): shutil.move(old_path, new_path) # Move a directory -async def move_directory(old_path, new_path): +def move_directory(old_path, new_path): shutil.move(old_path, new_path) # Delete a file -async def delete_file(path): +def delete_file(path): try: os.remove(path) except FileNotFoundError: pass # Delete a directory (and its contents) -async def delete_directory(path): +def delete_directory(path): shutil.rmtree(path, ignore_errors=True) # Read file as text -async def read_file_text(path): - async with aiofiles.open(path, mode='r', encoding='utf-8') as f: - return await f.read() +def read_file_text(path): + with open(path, 'r', encoding='utf-8') as f: + return f.read() # Read file as binary -async def read_file_binary(path): - async with aiofiles.open(path, mode='rb') as f: - return await f.read() +def read_file_binary(path): + with open(path, 'rb') as f: + return f.read() # Write text to a file -async def write_file_text(path, text): - async with aiofiles.open(path, mode='w', encoding='utf-8') as f: - await f.write(text) +def write_file_text(path, text): + with open(path, 'w', encoding='utf-8') as f: + f.write(text) # Write binary data to a file -async def write_file_binary(path, bytes_data): - async with aiofiles.open(path, mode='wb') as f: - await f.write(bytes_data) +def write_file_binary(path, bytes_data): + with open(path, 'wb') as f: + f.write(bytes_data) # Example usage # asyncio.run(ensure_directory('test_dir')) From 8c6d20d3a84775caf7b4b5411a8faa7b0fd53f21 Mon Sep 17 00:00:00 2001 From: HLWeil Date: Tue, 3 Dec 2024 11:15:14 +0100 Subject: [PATCH 26/30] finish up python io --- .config/dotnet-tools.json | 5 +- build/BasicTasks.fs | 2 + src/ARCtrl/ContractIO/FileSystemHelper.fs | 69 ++++++++++++----------- 3 files changed, 42 insertions(+), 34 deletions(-) diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index c630af3e..73d85048 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -3,10 +3,11 @@ "isRoot": true, "tools": { "fable": { - "version": "4.22.0", + "version": "4.24.0", "commands": [ "fable" - ] + ], + "rollForward": false } } } \ No newline at end of file diff --git a/build/BasicTasks.fs b/build/BasicTasks.fs index 8a114dd6..b42ef388 100644 --- a/build/BasicTasks.fs +++ b/build/BasicTasks.fs @@ -153,6 +153,8 @@ let clean = BuildTask.create "Clean" [] { ++ "tests/**/bin" ++ "tests/**/obj" ++ "tests/TestingUtils/TestResults" + ++ "tests/**/py" + ++ "tests/**/js" ++ "dist" ++ ProjectInfo.netPkgDir |> Shell.cleanDirs diff --git a/src/ARCtrl/ContractIO/FileSystemHelper.fs b/src/ARCtrl/ContractIO/FileSystemHelper.fs index d5efbf26..3449bdc0 100644 --- a/src/ARCtrl/ContractIO/FileSystemHelper.fs +++ b/src/ARCtrl/ContractIO/FileSystemHelper.fs @@ -8,22 +8,29 @@ open Fable #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT open Fable.Core.JsInterop open FsSpreadsheet.Js + #endif #if FABLE_COMPILER_PYTHON open FsSpreadsheet.Py open Fable.Core.PyInterop + +importAll "shutil" +importAll "os" +import "Path" "pathlib" + #endif #if !FABLE_COMPILER open FsSpreadsheet.Net #endif + let directoryExistsAsync (path : string) : CrossAsync = #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT - import "directoryExists" "./FileSystem.js" + import "directoryExists" "${outdir}/FileSystem.js" #endif #if FABLE_COMPILER_PYTHON - let f : string -> bool = import "directoryExists" "./file_system.py" + let f (path : string) : bool = emitPyExpr (path) "Path(path).is_dir()" crossAsync { return f path } @@ -39,7 +46,7 @@ let createDirectoryAsync (path : string) : CrossAsync = import "createDirectory" "./FileSystem.js" #endif #if FABLE_COMPILER_PYTHON - let f : string -> unit =import "createDirectory" "./file_system.py" + let f (path : string) : unit = emitPyExpr (path) "Path(path).mkdir(parents=True, exist_ok=True)" crossAsync { f path } @@ -53,17 +60,10 @@ let createDirectoryAsync (path : string) : CrossAsync = let ensureDirectoryAsync (path : string) : CrossAsync = #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT import "ensureDirectory" "./FileSystem.js" - #endif - #if FABLE_COMPILER_PYTHON - let f : string -> unit = import "ensureDirectory" "./file_system.py" - crossAsync { - f path - } - #endif - #if !FABLE_COMPILER + #else crossAsync { let! exists = directoryExistsAsync path - if not <| exists then + if not exists then return! createDirectoryAsync path } #endif @@ -73,9 +73,9 @@ let ensureDirectoryOfFileAsync (filePath : string) : CrossAsync = import "ensureDirectoryOfFile" "./FileSystem.js" #endif #if FABLE_COMPILER_PYTHON - let f : string -> unit = import "ensureDirectoryOfFile" "./file_system.py" + let f (path : string) : string = emitPyExpr (path) "Path(file_path).parent" crossAsync { - f filePath + return! ensureDirectoryAsync(f filePath) } #endif #if !FABLE_COMPILER @@ -90,7 +90,7 @@ let fileExistsAsync (path : string) : CrossAsync = import "fileExists" "./FileSystem.js" #endif #if FABLE_COMPILER_PYTHON - let f : string -> bool = import "fileExists" "./file_system.py" + let f (path : string) : bool = emitPyExpr (path) "Path(path).is_file()" crossAsync { return f path } @@ -108,7 +108,7 @@ let readFileTextAsync (path : string) : CrossAsync = import "readFileText" "./FileSystem.js" #endif #if FABLE_COMPILER_PYTHON - let f : string -> string = import "readFileText" "./file_system.py" + let f (path : string) : string = emitPyStatement (path) "with open(path, 'r', encoding='utf-8') as f: return f.read()" crossAsync { return f path } @@ -124,7 +124,7 @@ let readFileBinaryAsync (path : string) : CrossAsync = import "readFileBinary" "./FileSystem.js" #endif #if FABLE_COMPILER_PYTHON - let f : string -> byte [] = import "readFileBinary" "./file_system.py" + let f (path : string) : byte [] = emitPyStatement (path) "with open(path, 'rb') as f: return f.read()" crossAsync { return f path } @@ -144,15 +144,16 @@ let readFileXlsxAsync (path : string) : CrossAsync = } #endif - let moveFileAsync oldPath newPath = #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT import "moveFile" "./FileSystem.js" #endif #if FABLE_COMPILER_PYTHON - let f : string * string -> unit = import "moveFile" "./file_system.py" + let f (oldPath : string) (newPath : string) : unit = + // import "moveFile" "${outDir}/src/ARCtrl/ContractIO/file_system.py" + emitPyStatement (oldPath,newPath) "shutil.move($0, $1)" crossAsync { - f (oldPath,newPath) + f oldPath newPath } #endif #if !FABLE_COMPILER @@ -166,10 +167,7 @@ let moveDirectoryAsync oldPath newPath = import "moveDirectory" "./FileSystem.js" #endif #if FABLE_COMPILER_PYTHON - let f : string * string -> unit = import "moveDirectory" "./file_system.py" - crossAsync { - f (oldPath,newPath) - } + moveFileAsync oldPath newPath #endif #if !FABLE_COMPILER crossAsync { @@ -182,7 +180,10 @@ let deleteFileAsync path = import "deleteFile" "./FileSystem.js" #endif #if FABLE_COMPILER_PYTHON - let f : string -> unit = import "deleteFile" "./file_system.py" + let f (path : string) : unit = emitPyStatement (path) """try: + os.remove(path) + except FileNotFoundError: + pass""" crossAsync { f path } @@ -198,7 +199,7 @@ let deleteDirectoryAsync path = import "deleteDirectory" "./FileSystem.js" #endif #if FABLE_COMPILER_PYTHON - let f : string -> unit =import "deleteDirectory" "./file_system.py" + let f (path : string) : unit = emitPyStatement (path) "shutil.rmtree(path, ignore_errors=True)" crossAsync { f path } @@ -215,9 +216,10 @@ let writeFileTextAsync path text = import "writeFileText" "./FileSystem.js" #endif #if FABLE_COMPILER_PYTHON - let f : string * string -> unit = import "writeFileText" "./file_system.py" + let f (path :string) (text : string) : unit = + emitPyStatement (path,text) "with open($0, 'w') as f: f.write($1)" crossAsync { - f(path,text) + f path text } #endif #if !FABLE_COMPILER @@ -231,9 +233,11 @@ let writeFileBinaryAsync path (bytes : byte []) = import "writeFileBinary" "./FileSystem.js" #endif #if FABLE_COMPILER_PYTHON - let f : string * byte [] -> unit = import "writeFileBinary" "./file_system.py" + let f (path :string) (bytes : byte []) : unit = + // let f : (string * byte []) -> unit = import "writeFileBinary" "${outDir}/src/ARCtrl/ContractIO/file_system.py" + emitPyStatement (path,bytes) "with open($0, 'wb') as f: f.write($1)" crossAsync { - f (path,bytes) + f path bytes } #endif #if !FABLE_COMPILER @@ -275,7 +279,8 @@ let getSubDirectoriesAsync (path : string) : CrossAsync = } #endif #if FABLE_COMPILER_PYTHON - let f : string -> string [] = import "getSubDirectories" "./file_system.py" + + let f (path : string) : string [] = emitPyExpr (path) "[str(entry) for entry in Path(path).iterdir() if entry.is_dir()]" crossAsync { let paths = f path return paths |> Array.map standardizeSlashes @@ -297,7 +302,7 @@ let getSubFilesAsync (path : string) : CrossAsync = } #endif #if FABLE_COMPILER_PYTHON - let f : string -> string [] = import "getSubFiles" "./file_system.py" + let f (path : string) : string [] = emitPyExpr (path) "[str(entry) for entry in Path(path).iterdir() if entry.is_file()]" crossAsync { let paths = f path return paths |> Array.map standardizeSlashes From 5c1f99ea046ee6634da97423ba35356e5dc92b23 Mon Sep 17 00:00:00 2001 From: HLWeil Date: Tue, 3 Dec 2024 13:03:31 +0100 Subject: [PATCH 27/30] finish up basic cross language IO and tests --- build/BasicTasks.fs | 2 ++ build/PackageTasks.fs | 2 ++ build/ProjectInfo.fs | 3 +++ build/TestTasks.fs | 4 +++ src/ARCtrl/ContractIO/FileSystemHelper.fs | 32 +++++++++++------------ tests/JavaScript/CompositeCell.js | 2 +- tests/JavaScript/CompositeHeader.js | 2 +- 7 files changed, 28 insertions(+), 19 deletions(-) diff --git a/build/BasicTasks.fs b/build/BasicTasks.fs index b42ef388..e2aa4d27 100644 --- a/build/BasicTasks.fs +++ b/build/BasicTasks.fs @@ -155,6 +155,8 @@ let clean = BuildTask.create "Clean" [] { ++ "tests/TestingUtils/TestResults" ++ "tests/**/py" ++ "tests/**/js" + ++ "tests/Javascript/ARCtrl" + ++ "tests/Python/ARCtrl" ++ "dist" ++ ProjectInfo.netPkgDir |> Shell.cleanDirs diff --git a/build/PackageTasks.fs b/build/PackageTasks.fs index 3a5cd4c4..b7c2de33 100644 --- a/build/PackageTasks.fs +++ b/build/PackageTasks.fs @@ -71,6 +71,8 @@ module BundleJs = "" // "fable-library.**/**" |> Fake.IO.File.writeString false $"{ProjectInfo.npmPkgDir}/fable_modules/.npmignore" + System.IO.File.Copy(ProjectInfo.jsHelperFilePath, $"{ProjectInfo.npmPkgDir}/FileSystem.js", true) |> ignore + Fake.JavaScript.Npm.exec "pack" (fun o -> { o with WorkingDirectory = ProjectInfo.npmPkgDir diff --git a/build/ProjectInfo.fs b/build/ProjectInfo.fs index d2ea6afb..cf0aa003 100644 --- a/build/ProjectInfo.fs +++ b/build/ProjectInfo.fs @@ -32,6 +32,9 @@ let pyTestProjects = "tests/Python" ] +let jsHelperFileName = "FileSystem.js" +let jsHelperFilePath = "src/ARCtrl/ContractIO/" + jsHelperFileName + let solutionFile = $"{project}.sln" let configuration = "Release" diff --git a/build/TestTasks.fs b/build/TestTasks.fs index ef55b74f..2c159ce7 100644 --- a/build/TestTasks.fs +++ b/build/TestTasks.fs @@ -26,6 +26,7 @@ module RunTests = for path in ProjectInfo.jsTestProjects do // transpile library for native access run dotnet $"fable src/ARCtrl/ARCtrl.Javascript.fsproj -o {path}/ARCtrl --nocache" "" + System.IO.File.Copy(jsHelperFilePath, $"{path}/ARCtrl/{jsHelperFileName}") |> ignore GenerateIndexJs.ARCtrl_generate($"{path}/ARCtrl") run npx $"mocha {path} --timeout 20000" "" else @@ -40,6 +41,8 @@ module RunTests = System.IO.Directory.CreateDirectory(@".\tests\TestingUtils\TestResults\js") |> ignore // transpile js files from fsharp code run dotnet $"fable {path} -o {path}/js --nocache" "" + + System.IO.File.Copy(jsHelperFilePath, $"{path}/js/{jsHelperFileName}") |> ignore // run mocha in target path to execute tests // "--timeout 20000" is used, because json schema validation takes a bit of time. run node $"{path}/js/Main.js" "" @@ -102,6 +105,7 @@ module RunTests = run python $"{p}/py/main.py" "" // transpile js files from fsharp code run dotnet $"fable {p} -o {p}/js" "" + System.IO.File.Copy(jsHelperFilePath, $"{p}/js/{jsHelperFileName}") |> ignore // run mocha in target path to execute tests // "--timeout 20000" is used, because json schema validation takes a bit of time. run node $"{p}/js/Main.js" "" diff --git a/src/ARCtrl/ContractIO/FileSystemHelper.fs b/src/ARCtrl/ContractIO/FileSystemHelper.fs index 3449bdc0..87c45a28 100644 --- a/src/ARCtrl/ContractIO/FileSystemHelper.fs +++ b/src/ARCtrl/ContractIO/FileSystemHelper.fs @@ -8,7 +8,6 @@ open Fable #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT open Fable.Core.JsInterop open FsSpreadsheet.Js - #endif #if FABLE_COMPILER_PYTHON open FsSpreadsheet.Py @@ -24,10 +23,9 @@ import "Path" "pathlib" open FsSpreadsheet.Net #endif - let directoryExistsAsync (path : string) : CrossAsync = #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT - import "directoryExists" "${outdir}/FileSystem.js" + import "directoryExists" "${outDir}/FileSystem.js" #endif #if FABLE_COMPILER_PYTHON let f (path : string) : bool = emitPyExpr (path) "Path(path).is_dir()" @@ -43,7 +41,7 @@ let directoryExistsAsync (path : string) : CrossAsync = let createDirectoryAsync (path : string) : CrossAsync = #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT - import "createDirectory" "./FileSystem.js" + import "createDirectory" "${outDir}/FileSystem.js" #endif #if FABLE_COMPILER_PYTHON let f (path : string) : unit = emitPyExpr (path) "Path(path).mkdir(parents=True, exist_ok=True)" @@ -59,7 +57,7 @@ let createDirectoryAsync (path : string) : CrossAsync = let ensureDirectoryAsync (path : string) : CrossAsync = #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT - import "ensureDirectory" "./FileSystem.js" + import "ensureDirectory" "${outDir}/FileSystem.js" #else crossAsync { let! exists = directoryExistsAsync path @@ -70,7 +68,7 @@ let ensureDirectoryAsync (path : string) : CrossAsync = let ensureDirectoryOfFileAsync (filePath : string) : CrossAsync = #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT - import "ensureDirectoryOfFile" "./FileSystem.js" + import "ensureDirectoryOfFile" "${outDir}/FileSystem.js" #endif #if FABLE_COMPILER_PYTHON let f (path : string) : string = emitPyExpr (path) "Path(file_path).parent" @@ -87,7 +85,7 @@ let ensureDirectoryOfFileAsync (filePath : string) : CrossAsync = let fileExistsAsync (path : string) : CrossAsync = #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT - import "fileExists" "./FileSystem.js" + import "fileExists" "${outDir}/FileSystem.js" #endif #if FABLE_COMPILER_PYTHON let f (path : string) : bool = emitPyExpr (path) "Path(path).is_file()" @@ -105,7 +103,7 @@ let fileExistsAsync (path : string) : CrossAsync = let readFileTextAsync (path : string) : CrossAsync = #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT - import "readFileText" "./FileSystem.js" + import "readFileText" "${outDir}/FileSystem.js" #endif #if FABLE_COMPILER_PYTHON let f (path : string) : string = emitPyStatement (path) "with open(path, 'r', encoding='utf-8') as f: return f.read()" @@ -121,7 +119,7 @@ let readFileTextAsync (path : string) : CrossAsync = let readFileBinaryAsync (path : string) : CrossAsync = #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT - import "readFileBinary" "./FileSystem.js" + import "readFileBinary" "${outDir}/FileSystem.js" #endif #if FABLE_COMPILER_PYTHON let f (path : string) : byte [] = emitPyStatement (path) "with open(path, 'rb') as f: return f.read()" @@ -146,7 +144,7 @@ let readFileXlsxAsync (path : string) : CrossAsync = let moveFileAsync oldPath newPath = #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT - import "moveFile" "./FileSystem.js" + import "moveFile" "${outDir}/FileSystem.js" #endif #if FABLE_COMPILER_PYTHON let f (oldPath : string) (newPath : string) : unit = @@ -164,7 +162,7 @@ let moveFileAsync oldPath newPath = let moveDirectoryAsync oldPath newPath = #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT - import "moveDirectory" "./FileSystem.js" + import "moveDirectory" "${outDir}/FileSystem.js" #endif #if FABLE_COMPILER_PYTHON moveFileAsync oldPath newPath @@ -177,7 +175,7 @@ let moveDirectoryAsync oldPath newPath = let deleteFileAsync path = #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT - import "deleteFile" "./FileSystem.js" + import "deleteFile" "${outDir}/FileSystem.js" #endif #if FABLE_COMPILER_PYTHON let f (path : string) : unit = emitPyStatement (path) """try: @@ -196,7 +194,7 @@ let deleteFileAsync path = let deleteDirectoryAsync path = #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT - import "deleteDirectory" "./FileSystem.js" + import "deleteDirectory" "${outDir}/FileSystem.js" #endif #if FABLE_COMPILER_PYTHON let f (path : string) : unit = emitPyStatement (path) "shutil.rmtree(path, ignore_errors=True)" @@ -213,7 +211,7 @@ let deleteDirectoryAsync path = let writeFileTextAsync path text = #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT - import "writeFileText" "./FileSystem.js" + import "writeFileText" "${outDir}/FileSystem.js" #endif #if FABLE_COMPILER_PYTHON let f (path :string) (text : string) : unit = @@ -230,7 +228,7 @@ let writeFileTextAsync path text = let writeFileBinaryAsync path (bytes : byte []) = #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT - import "writeFileBinary" "./FileSystem.js" + import "writeFileBinary" "${outDir}/FileSystem.js" #endif #if FABLE_COMPILER_PYTHON let f (path :string) (bytes : byte []) : unit = @@ -272,7 +270,7 @@ let standardizeSlashes (path : string) = let getSubDirectoriesAsync (path : string) : CrossAsync = #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT - let f : string -> CrossAsync = import "getSubDirectories" "./FileSystem.js" + let f : string -> CrossAsync = import "getSubDirectories" "${outDir}/FileSystem.js" crossAsync { let! paths = f path return paths |> Array.map standardizeSlashes @@ -295,7 +293,7 @@ let getSubDirectoriesAsync (path : string) : CrossAsync = let getSubFilesAsync (path : string) : CrossAsync = #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT - let f : string -> CrossAsync = import "getSubFiles" "./FileSystem.js" + let f : string -> CrossAsync = import "getSubFiles" "${outDir}/FileSystem.js" crossAsync { let! paths = f path return paths |> Array.map standardizeSlashes diff --git a/tests/JavaScript/CompositeCell.js b/tests/JavaScript/CompositeCell.js index 9dfad312..335f5f4e 100644 --- a/tests/JavaScript/CompositeCell.js +++ b/tests/JavaScript/CompositeCell.js @@ -1,7 +1,7 @@ import { equal, deepEqual, notEqual } from 'assert'; import { CompositeCell } from "./ARCtrl/index.js" import { OntologyAnnotation } from './ARCtrl/index.js'; -import { assertEqual } from './ARCtrl/fable_modules/fable-library-js.4.22.0/Util.js'; +import { assertEqual } from './ARCtrl/fable_modules/fable-library-js.4.24.0/Util.js'; describe('CompositeCell', function () { it('Primary Constructor', function() { diff --git a/tests/JavaScript/CompositeHeader.js b/tests/JavaScript/CompositeHeader.js index a939881c..5437baf2 100644 --- a/tests/JavaScript/CompositeHeader.js +++ b/tests/JavaScript/CompositeHeader.js @@ -1,7 +1,7 @@ import { equal, deepEqual, notEqual } from 'assert'; import { CompositeHeader, IOType } from "./ARCtrl/index.js" import { OntologyAnnotation } from './ARCtrl/index.js'; -import { assertEqual } from './ARCtrl/fable_modules/fable-library-js.4.22.0/Util.js'; +import { assertEqual } from './ARCtrl/fable_modules/fable-library-js.4.24.0/Util.js'; function tests_IOType() { describe('IOType', function () { From 94714ba4e9c0d19ddb7524d9bdc6c56b804a60a4 Mon Sep 17 00:00:00 2001 From: HLWeil Date: Tue, 3 Dec 2024 13:17:25 +0100 Subject: [PATCH 28/30] add level synchronous IO functions for dotnet and python --- src/ARCtrl/ARC.fs | 57 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 54 insertions(+), 3 deletions(-) diff --git a/src/ARCtrl/ARC.fs b/src/ARCtrl/ARC.fs index 80d0a7ff..cf138fd1 100644 --- a/src/ARCtrl/ARC.fs +++ b/src/ARCtrl/ARC.fs @@ -116,9 +116,7 @@ type ARC(?isa : ArcInvestigation, ?cwl : unit, ?fs : FileSystem.FileSystem) = arc.SetISAFromContracts(c) return Ok arc | Error e -> return Error e - } - - + } member this.GetAssayRemoveContracts(assayIdentifier: string) = let isa = @@ -207,6 +205,59 @@ type ARC(?isa : ArcInvestigation, ?cwl : unit, ?fs : FileSystem.FileSystem) = this.GetStudyRenameContracts(oldStudyIdentifier,newStudyIdentifier) |> fullFillContractBatchAsync arcPath + + #if FABLE_COMPILER_PYTHON || !FABLE_COMPILER + member this.Write(arcPath) = + match Async.RunSynchronously (this.WriteAsync(arcPath)) with + | Ok _ -> () + | Error errors -> + let appended = errors |> Array.map (fun e -> e.ToString()) |> String.concat "\n" + failwithf "Could not write ARC, failed with the following errors %s" appended + + member this.Update(arcPath) = + match Async.RunSynchronously (this.UpdateAsync(arcPath)) with + | Ok _ -> () + | Error errors -> + let appended = errors |> Array.map (fun e -> e.ToString()) |> String.concat "\n" + failwithf "Could not update ARC, failed with the following errors %s" appended + + member this.RemoveAssay(arcPath, assayIdentifier) = + match Async.RunSynchronously (this.RemoveAssayAsync(arcPath, assayIdentifier)) with + | Ok _ -> () + | Error errors -> + let appended = errors |> Array.map (fun e -> e.ToString()) |> String.concat "\n" + failwithf "Could not remove assay, failed with the following errors %s" appended + + member this.RenameAssay(arcPath, oldAssayIdentifier, newAssayIdentifier) = + match Async.RunSynchronously (this.RenameAssayAsync(arcPath, oldAssayIdentifier, newAssayIdentifier)) with + | Ok _ -> () + | Error errors -> + let appended = errors |> Array.map (fun e -> e.ToString()) |> String.concat "\n" + failwithf "Could not rename assay, failed with the following errors %s" appended + + member this.RemoveStudy(arcPath, studyIdentifier) = + match Async.RunSynchronously (this.RemoveStudyAsync(arcPath, studyIdentifier)) with + | Ok _ -> () + | Error errors -> + let appended = errors |> Array.map (fun e -> e.ToString()) |> String.concat "\n" + failwithf "Could not remove study, failed with the following errors %s" appended + + member this.RenameStudy(arcPath, oldStudyIdentifier, newStudyIdentifier) = + match Async.RunSynchronously (this.RenameStudyAsync(arcPath, oldStudyIdentifier, newStudyIdentifier)) with + | Ok _ -> () + | Error errors -> + let appended = errors |> Array.map (fun e -> e.ToString()) |> String.concat "\n" + failwithf "Could not rename study, failed with the following errors %s" appended + + static member load (arcPath) = + match Async.RunSynchronously (ARC.loadAsync arcPath) with + | Ok arc -> arc + | Error errors -> + let appended = errors |> Array.map (fun e -> e.ToString()) |> String.concat "\n" + failwithf "Could not load ARC, failed with the following errors %s" appended + #endif + + //static member updateISA (isa : ISA.Investigation) (arc : ARC) : ARC = // raise (System.NotImplementedException()) From ce001afc2acafa9e9de3413df87c7771b7927fd8 Mon Sep 17 00:00:00 2001 From: HLWeil Date: Wed, 4 Dec 2024 14:03:41 +0100 Subject: [PATCH 29/30] fix test file path handling for js in linux --- build/TestTasks.fs | 4 ++-- src/ARCtrl/ContractIO/FileSystemHelper.fs | 7 +++++++ tests/ARCtrl/FileSystemHelper.Tests.fs | 6 +++--- tests/TestingUtils/TestObjects.IO.fs | 16 ++++++++++++---- tests/TestingUtils/TestingUtils.fs | 11 ++++++++++- 5 files changed, 34 insertions(+), 10 deletions(-) diff --git a/build/TestTasks.fs b/build/TestTasks.fs index 2c159ce7..6f4eb765 100644 --- a/build/TestTasks.fs +++ b/build/TestTasks.fs @@ -38,7 +38,7 @@ module RunTests = Trace.traceImportant "Start Js tests" for path in ProjectInfo.testProjects do // Setup test results directory after clean - System.IO.Directory.CreateDirectory(@".\tests\TestingUtils\TestResults\js") |> ignore + System.IO.Directory.CreateDirectory("./tests/TestingUtils/TestResults/js") |> ignore // transpile js files from fsharp code run dotnet $"fable {path} -o {path}/js --nocache" "" @@ -67,7 +67,7 @@ module RunTests = Trace.traceImportant "Start Python tests" for path in ProjectInfo.testProjects do // Setup test results directory after clean - System.IO.Directory.CreateDirectory(@".\tests\TestingUtils\TestResults\py") |> ignore + System.IO.Directory.CreateDirectory("./tests/TestingUtils/TestResults/py") |> ignore //transpile py files from fsharp code run dotnet $"fable {path} -o {path}/py --lang python --nocache" "" // run pyxpecto in target path to execute tests in python diff --git a/src/ARCtrl/ContractIO/FileSystemHelper.fs b/src/ARCtrl/ContractIO/FileSystemHelper.fs index 87c45a28..cb950c65 100644 --- a/src/ARCtrl/ContractIO/FileSystemHelper.fs +++ b/src/ARCtrl/ContractIO/FileSystemHelper.fs @@ -254,11 +254,18 @@ let writeFileXlsxAsync path (wb : FsWorkbook) = #endif +let trim (path : string) = + if path.StartsWith("./") then + path.Replace("./","").Trim('/') + else path.Trim('/') + /// Return the absolute path relative to the directoryPath let makeRelative directoryPath (path : string) = if directoryPath = "." || directoryPath = "/" || directoryPath = "" then path else + let directoryPath = trim directoryPath + let path = trim path if path.StartsWith(directoryPath) then path.Substring(directoryPath.Length) else path diff --git a/tests/ARCtrl/FileSystemHelper.Tests.fs b/tests/ARCtrl/FileSystemHelper.Tests.fs index 77ea86d6..30273f7b 100644 --- a/tests/ARCtrl/FileSystemHelper.Tests.fs +++ b/tests/ARCtrl/FileSystemHelper.Tests.fs @@ -124,7 +124,7 @@ let getSubFiles = $"{TestObjects.IO.testSubPathsFolder}/File1.txt" |> FileSystemHelper.standardizeSlashes $"{TestObjects.IO.testSubPathsFolder}/File2.csv" |> FileSystemHelper.standardizeSlashes ] - Expect.sequenceEqual result expected "Files were not found correctly." + Expect.pathSequenceEqual result expected "Files were not found correctly." }) ] @@ -138,7 +138,7 @@ let getSubDirectories = [ $"{TestObjects.IO.testSubPathsFolder}/SubFolder" |> FileSystemHelper.standardizeSlashes ] - Expect.sequenceEqual result expected "Directories were not found correctly." + Expect.pathSequenceEqual result expected "Directories were not found correctly." }) ] @@ -157,7 +157,7 @@ let getAllFilePaths = $"/SubFolder/File3.xlsx" |> FileSystemHelper.standardizeSlashes $"/SubFolder/SubSubFolder/File4" |> FileSystemHelper.standardizeSlashes ] - Expect.sequenceEqual result expected "File Paths were not found correctly." + Expect.pathSequenceEqual result expected "File Paths were not found correctly." }) ] diff --git a/tests/TestingUtils/TestObjects.IO.fs b/tests/TestingUtils/TestObjects.IO.fs index 23c3b93f..1048c566 100644 --- a/tests/TestingUtils/TestObjects.IO.fs +++ b/tests/TestingUtils/TestObjects.IO.fs @@ -2,17 +2,25 @@ module TestObjects.IO open ARCtrl.ArcPathHelper -let testObjectsBaseFolder = combine __SOURCE_DIRECTORY__ "TestObjects.IO" +let testBaseFolder = + #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT + "./tests/TestingUtils" + #else + //"../TestingUtils" + __SOURCE_DIRECTORY__ + #endif + +let testObjectsBaseFolder = combine testBaseFolder "TestObjects.IO" let testResultsFolder = #if !FABLE_COMPILER - combineMany [| __SOURCE_DIRECTORY__;"TestResults";"NET"|] + combineMany [| testBaseFolder;"TestResults";"NET"|] #endif #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT - combineMany [| __SOURCE_DIRECTORY__;"TestResults";"js"|] + combineMany [| testBaseFolder;"TestResults";"js"|] #endif #if FABLE_COMPILER_PYTHON - combineMany [| __SOURCE_DIRECTORY__;"TestResults";"py"|] + combineMany [| testBaseFolder;"TestResults";"py"|] #endif let testContractsFolder = combine testObjectsBaseFolder "Contracts" diff --git a/tests/TestingUtils/TestingUtils.fs b/tests/TestingUtils/TestingUtils.fs index 3e94a069..0d943348 100644 --- a/tests/TestingUtils/TestingUtils.fs +++ b/tests/TestingUtils/TestingUtils.fs @@ -34,6 +34,10 @@ module Utils = Seq.mapi2 (fun i s p -> i,s,p) s1 s2 |> Seq.find (function |_,Some s,Some p when s=p -> false |_-> true) + let trim (path : string) = + if path.StartsWith("./") then + path.Replace("./","").Trim('/') + else path.Trim('/') module Result = @@ -96,6 +100,7 @@ module Expect = let inline equal actual expected message = Expect.equal actual expected message let notEqual actual expected message = Expect.notEqual actual expected message + /// Trims whitespace and normalizes lineendings to "\n" let trimEqual (actual: string) (expected: string) message = let a = actual.Trim().Replace("\r\n", "\n") @@ -193,7 +198,11 @@ module Expect = failwithf "%s. Sequence actual longer than expected, at pos %i found item %O." message i a - + let pathSequenceEqual actual expected message = + let actual = actual |> Seq.map trim + let expected = expected |> Seq.map trim + sequenceEqual actual expected message + let workSheetEqual (actual : FsWorksheet) (expected : FsWorksheet) message = let f (ws : FsWorksheet) = ws.RescanRows() From 39340475d8c08859f9f7179811a7cef1a677aea8 Mon Sep 17 00:00:00 2001 From: HLWeil Date: Wed, 4 Dec 2024 15:25:09 +0100 Subject: [PATCH 30/30] remove second namespace definition in xlsx controller file --- src/ARCtrl/Xlsx.fs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ARCtrl/Xlsx.fs b/src/ARCtrl/Xlsx.fs index 092edb8e..5cdaf91e 100644 --- a/src/ARCtrl/Xlsx.fs +++ b/src/ARCtrl/Xlsx.fs @@ -1,5 +1,4 @@ namespace ARCtrl -namespace ARCtrl open Thoth.Json.Core open ARCtrl.Spreadsheet