From 19c60574bc3a1cc7a206403dba8633cf0767d91f Mon Sep 17 00:00:00 2001 From: Erik White Date: Thu, 18 Jan 2024 10:57:29 +0100 Subject: [PATCH 01/14] Switch nuget package to LTRData.DiscUtils --- .../RecursiveExtractor.Tests.csproj | 8 +++--- RecursiveExtractor/Extractors/DiscCommon.cs | 11 ++++---- RecursiveExtractor/RecursiveExtractor.csproj | 26 +++++++++---------- 3 files changed, 22 insertions(+), 23 deletions(-) diff --git a/RecursiveExtractor.Tests/RecursiveExtractor.Tests.csproj b/RecursiveExtractor.Tests/RecursiveExtractor.Tests.csproj index 8b24932b..b92c48ea 100644 --- a/RecursiveExtractor.Tests/RecursiveExtractor.Tests.csproj +++ b/RecursiveExtractor.Tests/RecursiveExtractor.Tests.csproj @@ -9,10 +9,10 @@ - - - - + + + + diff --git a/RecursiveExtractor/Extractors/DiscCommon.cs b/RecursiveExtractor/Extractors/DiscCommon.cs index 6f1fe4a8..d15c8fcf 100644 --- a/RecursiveExtractor/Extractors/DiscCommon.cs +++ b/RecursiveExtractor/Extractors/DiscCommon.cs @@ -1,10 +1,9 @@ using DiscUtils; using System; -using System.Collections.Concurrent; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.IO; using System.Linq; -using System.Threading.Tasks; namespace Microsoft.CST.RecursiveExtractor.Extractors { @@ -28,7 +27,7 @@ public static class DiscCommon /// public static async IAsyncEnumerable DumpLogicalVolumeAsync(LogicalVolumeInfo volume, string parentPath, ExtractorOptions options, ResourceGovernor governor, Extractor Context, FileEntry? parent = null, bool topLevel = true) { - DiscUtils.FileSystemInfo[]? fsInfos = null; + ReadOnlyCollection? fsInfos = null; try { fsInfos = FileSystemManager.DetectFileSystems(volume); @@ -38,7 +37,7 @@ public static async IAsyncEnumerable DumpLogicalVolumeAsync(LogicalVo Logger.Debug("Failed to get file systems from logical volume {0} Image {1} ({2}:{3})", volume.Identity, parentPath, e.GetType(), e.Message); } - foreach (var fsInfo in fsInfos ?? Array.Empty()) + foreach (var fsInfo in fsInfos ?? Enumerable.Empty()) { using var fs = fsInfo.Open(volume); var diskFiles = fs.GetFiles(fs.Root.FullName, "*.*", SearchOption.AllDirectories).ToList(); @@ -90,7 +89,7 @@ public static async IAsyncEnumerable DumpLogicalVolumeAsync(LogicalVo /// An enumerable of the contained File Entries. public static IEnumerable DumpLogicalVolume(LogicalVolumeInfo volume, string parentPath, ExtractorOptions options, ResourceGovernor governor, Extractor Context, FileEntry? parent = null, bool topLevel = true) { - DiscUtils.FileSystemInfo[]? fsInfos = null; + ReadOnlyCollection? fsInfos = null; try { fsInfos = FileSystemManager.DetectFileSystems(volume); @@ -100,7 +99,7 @@ public static IEnumerable DumpLogicalVolume(LogicalVolumeInfo volume, Logger.Debug("Failed to get file systems from logical volume {0} Image {1} ({2}:{3})", volume.Identity, parentPath, e.GetType(), e.Message); } - foreach (var fsInfo in fsInfos ?? Array.Empty()) + foreach (var fsInfo in fsInfos ?? Enumerable.Empty()) { using var fs = fsInfo.Open(volume); var diskFiles = fs.GetFiles(fs.Root.FullName, "*.*", SearchOption.AllDirectories).ToList(); diff --git a/RecursiveExtractor/RecursiveExtractor.csproj b/RecursiveExtractor/RecursiveExtractor.csproj index a1015211..9c15d060 100644 --- a/RecursiveExtractor/RecursiveExtractor.csproj +++ b/RecursiveExtractor/RecursiveExtractor.csproj @@ -25,19 +25,19 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + From 60c14d875ee8f2facc33fbbcebe2dc31bdad6c4a Mon Sep 17 00:00:00 2001 From: Erik White Date: Sat, 20 Jan 2024 15:27:36 +0100 Subject: [PATCH 02/14] Add regression test for corrupt WIM --- .../ExtractorTests/MiscTests.cs | 1 + .../TestDataArchives/TestDataCorruptWim.zip | Bin 0 -> 2017 bytes 2 files changed, 1 insertion(+) create mode 100644 RecursiveExtractor.Tests/TestData/TestDataArchives/TestDataCorruptWim.zip diff --git a/RecursiveExtractor.Tests/ExtractorTests/MiscTests.cs b/RecursiveExtractor.Tests/ExtractorTests/MiscTests.cs index b1d558e7..e375904a 100644 --- a/RecursiveExtractor.Tests/ExtractorTests/MiscTests.cs +++ b/RecursiveExtractor.Tests/ExtractorTests/MiscTests.cs @@ -49,6 +49,7 @@ public async Task ExtractFlatFileAsync(string fileName, bool requireTopLevelToBe [DataRow("TestDataCorrupt.tar", true, 1, 1)] [DataRow("TestDataCorrupt.tar.zip", false, 0, 2)] [DataRow("TestDataCorrupt.tar.zip", true, 0, 2)] + [DataRow("TestDataCorruptWim.zip", true, 0, 0)] public void ExtractCorruptArchive(string fileName, bool requireTopLevelToBeArchive, int expectedNumFailures, int expectedNumFiles) { var extractor = new Extractor(); diff --git a/RecursiveExtractor.Tests/TestData/TestDataArchives/TestDataCorruptWim.zip b/RecursiveExtractor.Tests/TestData/TestDataArchives/TestDataCorruptWim.zip new file mode 100644 index 0000000000000000000000000000000000000000..89235f2ab3c951b573440095511cfa2286a73d8d GIT binary patch literal 2017 zcmV<72OjuPO9KQH0000809$WVRbc2;Az23i0Gt;9022TJ090jjbVOlvVMA|na&>TY zE_Z2d?N~dA9aR`U2^d63SYpujG%AR>i72Z=i0mUT*hkn+b}`+#GiUD}nODx4b4_8f zt(`Wpw6Rd^ENrwCL$I+*V`C*E3MoV^1pWT=nz@_Z>n1V5!ijfh=Dhy@|NifPjLYkr zmzEi0-{HrO9%4JpU#~y&#+~nPK5@Lc`N5a^<3GPX#ONPmxt~7#?g{@8-q}}&{rC?j zCf*RLNz9KT#n*mX)kTtIU93ae_#Uup?|y*sF8cFedG|w909vs)>`a4{z2?ij$VN z>A1Gm_%Enf2JN;)rV3>g&$NK>^{7xOtX2j%l@M0*>yXM-*+3KJW{nZOqbplwys^bt zRYDK=qQd#jwlH3$u{5n3+5$Ed&L;#gPREojTCFlA4aXg;oF$71BvPs;rlZKRZUYyMmV6fmaP_Wl<2t!>J$Th zE@be+oRN2wL%6_yQqMLjOh0g4N&vi#9$O4#^%n~x7$ClJV&89Y1;slF>Xw`tPki)9F;=@8zxr!cjq@)E$ zpE~-~hAkS~idJ$X8YL@tz7ZqUk_#e@N>NB-MK1VI4FLeec}1^yx;4O45qs5GY5)sG z8!Ur=CG={cU-j{RWAYp6~e|5Y3D`Yba7J=`CVK%`xnF(EF#6$p3t4awv*d+lk zX7VU9&O0ZDro%ZJxCOi=1-Z}eHl^vX0L0fq8UWi%J27b+UdWnu@+}QVDR|i9>lKNx z$IvT<%ur8p#1TIZW79INre9g8ROUPIkTHtc)gR-WA2VaK3_1QQ;=UxW< zJm4hR9BH}n{Byw(L&)(l23@6w+i*?DM=le(B2x*~@9HXH6J5p&+wJ~kz&V?l8sQ~cm$s_D+a#4X3tkRT!gUDT1Soy$jB zj8#sqA#GvSSQHe_5V5?gEE8%rC5-~+dvAw^B6_;mw^5pg8kJekFNYx|ywo2+FqKOV zZWmH}viPLat!Z>UQKTZ3iAl&v4~l|sWG3rZ9qPP0Bc_IwoszH8NL-TgODxC~+FiAY zG3@GK7x7(>*Q<4a-Qin3go_9KD#c{TX(@eApxnheF$?96BAgeNT;Iig%rSug;I9q7 zhAnN7Q`QBgRY|Vx0!-S_U(rhHoT%1BsTF`IV3e-;+t#!-5)8OSW!I;5U$;UkPYoGG zRFc)@Ndh`@)-#(%I!%23?iWA;AT~>As9~r)K+6WQppnm z%1}_c8rY9%7y5KiPAM%A&V)CLn0Ajoc!g4zt714RR{>a8!@^e#>D!xfJ#cjU;LJCKve^NA;j549>Te%k1I7ORNOk>CB`Ac zrG~=W7|I_!;47eQAL?81+{jfM`m*d4R0wH@m30M}S}jm`KP_X4)UI^*KdxMl<|BdR zr;n@2q#dPFEr}3kdP0SO-8^D8<#mYqIM; zr^oQ%$?&LKm@6(H)xO;rxd-dcs!>%yN3~SjU6Zk9kShExEoCQ7hxuV?7Gbc7~_4N2@ z`0TGgF1&Z@g|%bv%>MHG#%Im@cXsbR&X!osG;}H10D9cOFJ4W!&oD3lk4J#R5q2K( z>xr?QaOdn`c0d2~(~s2dyZihL9zNF-V>{u_*}?3-d;7@0YWM%w0jt0j!DV`LdKix@wT-@<>+g8R|( zlzX0o{P@1Z;0u%rg0000809$WVRbc2;Az23i0Gt;9022TJ000000096X z000000000~Wpi{yVRT_bZ*p>VaC9zrX>CwT1qJ{B000310RTY&004>y00000K#tPU literal 0 HcmV?d00001 From 35358b59c62dab52d6d9d62e4e16c279009928de Mon Sep 17 00:00:00 2001 From: Erik White Date: Sat, 20 Jan 2024 15:55:16 +0100 Subject: [PATCH 03/14] Include WIM test file in output --- RecursiveExtractor.Tests/RecursiveExtractor.Tests.csproj | 3 +++ 1 file changed, 3 insertions(+) diff --git a/RecursiveExtractor.Tests/RecursiveExtractor.Tests.csproj b/RecursiveExtractor.Tests/RecursiveExtractor.Tests.csproj index b92c48ea..9dc08bf5 100644 --- a/RecursiveExtractor.Tests/RecursiveExtractor.Tests.csproj +++ b/RecursiveExtractor.Tests/RecursiveExtractor.Tests.csproj @@ -176,6 +176,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest From e5f8b329a353b9cd2b603cdfd986f5538c0bd5d8 Mon Sep 17 00:00:00 2001 From: Erik White Date: Sat, 20 Jan 2024 15:58:37 +0100 Subject: [PATCH 04/14] Add DMG test cases --- .../ExtractorTests/ExpectedNumFilesTests.cs | 3 ++- .../RecursiveExtractor.Tests.csproj | 3 +++ .../TestData/TestDataArchives/SharedDmg.zip | Bin 0 -> 50775 bytes 3 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 RecursiveExtractor.Tests/TestData/TestDataArchives/SharedDmg.zip diff --git a/RecursiveExtractor.Tests/ExtractorTests/ExpectedNumFilesTests.cs b/RecursiveExtractor.Tests/ExtractorTests/ExpectedNumFilesTests.cs index f8763dbb..0228aa5a 100644 --- a/RecursiveExtractor.Tests/ExtractorTests/ExpectedNumFilesTests.cs +++ b/RecursiveExtractor.Tests/ExtractorTests/ExpectedNumFilesTests.cs @@ -42,7 +42,8 @@ public static IEnumerable ArchiveData new object[] { "EmptyFile.txt", 1 }, new object[] { "TestDataArchivesNested.Zip", 54 }, new object[] { "UdfTest.iso", 3 }, - new object[] { "UdfTestWithMultiSystem.iso", 3 } + new object[] { "UdfTestWithMultiSystem.iso", 3 }, + new object[] { "SharedDmg.zip", 1 }, }; } } diff --git a/RecursiveExtractor.Tests/RecursiveExtractor.Tests.csproj b/RecursiveExtractor.Tests/RecursiveExtractor.Tests.csproj index 9dc08bf5..daad8d99 100644 --- a/RecursiveExtractor.Tests/RecursiveExtractor.Tests.csproj +++ b/RecursiveExtractor.Tests/RecursiveExtractor.Tests.csproj @@ -125,6 +125,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest diff --git a/RecursiveExtractor.Tests/TestData/TestDataArchives/SharedDmg.zip b/RecursiveExtractor.Tests/TestData/TestDataArchives/SharedDmg.zip new file mode 100644 index 0000000000000000000000000000000000000000..36a9268d380942cd1cd810764d471d3ea0c183b0 GIT binary patch literal 50775 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 literal 0 HcmV?d00001 From a53ce454b66a2a9c952a58a17891828e099320a5 Mon Sep 17 00:00:00 2001 From: Erik White Date: Wed, 24 Jan 2024 21:36:11 +0100 Subject: [PATCH 05/14] Update to latest DiscUtils with WIM fix --- .../RecursiveExtractor.Tests.csproj | 8 +++--- RecursiveExtractor/RecursiveExtractor.csproj | 26 +++++++++---------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/RecursiveExtractor.Tests/RecursiveExtractor.Tests.csproj b/RecursiveExtractor.Tests/RecursiveExtractor.Tests.csproj index daad8d99..b9c2c4e5 100644 --- a/RecursiveExtractor.Tests/RecursiveExtractor.Tests.csproj +++ b/RecursiveExtractor.Tests/RecursiveExtractor.Tests.csproj @@ -9,10 +9,10 @@ - - - - + + + + diff --git a/RecursiveExtractor/RecursiveExtractor.csproj b/RecursiveExtractor/RecursiveExtractor.csproj index 9c15d060..01a7ac1c 100644 --- a/RecursiveExtractor/RecursiveExtractor.csproj +++ b/RecursiveExtractor/RecursiveExtractor.csproj @@ -25,19 +25,19 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + From 992f694c18e990a31dfe8f9c8651daf60ced2a51 Mon Sep 17 00:00:00 2001 From: Erik White Date: Wed, 24 Jan 2024 22:46:34 +0100 Subject: [PATCH 06/14] Handle missing WIM image --- RecursiveExtractor/Extractors/WimExtractor.cs | 30 +++++++++++++++---- 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/RecursiveExtractor/Extractors/WimExtractor.cs b/RecursiveExtractor/Extractors/WimExtractor.cs index d4c2d477..5005e146 100644 --- a/RecursiveExtractor/Extractors/WimExtractor.cs +++ b/RecursiveExtractor/Extractors/WimExtractor.cs @@ -1,9 +1,6 @@ -using DiscUtils; -using System; -using System.Collections.Concurrent; +using System; using System.Collections.Generic; using System.IO; -using System.Linq; namespace Microsoft.CST.RecursiveExtractor.Extractors { @@ -107,8 +104,12 @@ public IEnumerable Extract(FileEntry fileEntry, ExtractorOptions opti { for (var i = 0; i < baseFile.ImageCount; i++) { - var image = baseFile.GetImage(i); - foreach (var file in image.GetFiles(image.Root.FullName, "*.*", SearchOption.AllDirectories)) + if (!TryGetImage(baseFile, i, out var image)) + { + continue; + } + + foreach (var file in image!.GetFiles(image.Root.FullName, "*.*", SearchOption.AllDirectories)) { Stream? stream = null; try @@ -151,5 +152,22 @@ public IEnumerable Extract(FileEntry fileEntry, ExtractorOptions opti } } } + + private bool TryGetImage(DiscUtils.Wim.WimFile wimFile, int index, out DiscUtils.Wim.WimFileSystem? image) + { + image = null; + + try + { + image = wimFile.GetImage(index); + } + catch (Exception e) + { + // Image may be corrupt or invalid + Logger.Debug(e, "Failed to retrieve WIM image with index {index}.", index); + } + + return image is not null; + } } } \ No newline at end of file From 6cb991a34bc75ef4405687b670f3cbb6ce81d15d Mon Sep 17 00:00:00 2001 From: Gabe Stocco <98900+gfs@users.noreply.github.com> Date: Thu, 25 Jan 2024 13:17:50 -0800 Subject: [PATCH 07/14] Update pipeline templates. --- Pipelines/recursive-extractor-pr.yml | 6 +++--- Pipelines/recursive-extractor-release.yml | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Pipelines/recursive-extractor-pr.yml b/Pipelines/recursive-extractor-pr.yml index 5e9f334f..45a6becf 100644 --- a/Pipelines/recursive-extractor-pr.yml +++ b/Pipelines/recursive-extractor-pr.yml @@ -13,7 +13,7 @@ resources: - repository: templates type: git name: SecurityEngineering/OSS-Tools-Pipeline-Templates - ref: refs/tags/v1.1.0 + ref: refs/tags/v1.1.1 variables: BuildConfiguration: 'Release' @@ -27,13 +27,13 @@ stages: parameters: jobName: 'lib_dotnet_test_windows' dotnetVersions: ['6.0.x','7.0.x','8.0.x'] - vmImage: 'oss-tools-win2022_1es-managed' + vmImage: 'win2022-image-base' projectPath: 'RecursiveExtractor.Tests/RecursiveExtractor.Tests.csproj' - template: dotnet-test-job.yml@templates parameters: jobName: 'cli_dotnet_test_windows' dotnetVersions: ['6.0.x','7.0.x','8.0.x'] - vmImage: 'oss-tools-win2022_1es-managed' + vmImage: 'win2022-image-base' projectPath: 'RecursiveExtractor.Cli.Tests/RecursiveExtractor.Cli.Tests.csproj' - stage: SDL diff --git a/Pipelines/recursive-extractor-release.yml b/Pipelines/recursive-extractor-release.yml index 65bf8aa1..f6cefe92 100644 --- a/Pipelines/recursive-extractor-release.yml +++ b/Pipelines/recursive-extractor-release.yml @@ -18,7 +18,7 @@ resources: - repository: templates type: git name: SecurityEngineering/OSS-Tools-Pipeline-Templates - ref: refs/tags/v1.1.0 + ref: refs/tags/v1.1.1 variables: BuildConfiguration: 'Release' @@ -32,13 +32,13 @@ stages: parameters: jobName: 'lib_dotnet_test_windows' dotnetVersions: ['6.0.x','7.0.x','8.0.x'] - vmImage: 'oss-tools-win2022_1es-managed' + vmImage: 'win2022-image-base' projectPath: 'RecursiveExtractor.Tests/RecursiveExtractor.Tests.csproj' - template: dotnet-test-job.yml@templates parameters: jobName: 'cli_dotnet_test_windows' dotnetVersions: ['6.0.x','7.0.x','8.0.x'] - vmImage: 'oss-tools-win2022_1es-managed' + vmImage: 'win2022-image-base' projectPath: 'RecursiveExtractor.Cli.Tests/RecursiveExtractor.Cli.Tests.csproj' - stage: SDL @@ -87,7 +87,7 @@ stages: displayName: Code Sign, Generate Hashes, Publish Public Releases pool: name: 'OSS-Tools-1ESPool' - vmImage: 'oss-tools-win2022_1es-managed' + vmImage: 'win2022-image-base' steps: - task: UseDotNet@2 # For ESRP. Do not use variable. inputs: From cff057a2b24f8afe2e84a344b23ab1d5f787c870 Mon Sep 17 00:00:00 2001 From: Gabe Stocco <98900+gfs@users.noreply.github.com> Date: Thu, 25 Jan 2024 14:17:44 -0800 Subject: [PATCH 08/14] Small error handling changes in WimExtractor. --- RecursiveExtractor/Extractors/WimExtractor.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/RecursiveExtractor/Extractors/WimExtractor.cs b/RecursiveExtractor/Extractors/WimExtractor.cs index 5005e146..eac9a08e 100644 --- a/RecursiveExtractor/Extractors/WimExtractor.cs +++ b/RecursiveExtractor/Extractors/WimExtractor.cs @@ -98,7 +98,7 @@ public IEnumerable Extract(FileEntry fileEntry, ExtractorOptions opti } catch (Exception e) { - Logger.Debug(e, "Failed to init WIM image."); + Logger.Debug(e, "Failed to init WIM image from {0}.", fileEntry.FullPath); } if (baseFile != null) { @@ -106,6 +106,7 @@ public IEnumerable Extract(FileEntry fileEntry, ExtractorOptions opti { if (!TryGetImage(baseFile, i, out var image)) { + Logger.Debug("Error reading image {0} from WIM {1}. Potentially malformed?", i, fileEntry.FullPath); continue; } @@ -145,9 +146,9 @@ public IEnumerable Extract(FileEntry fileEntry, ExtractorOptions opti } else { + fileEntry.EntryStatus = FileEntryStatus.FailedArchive; if (options.ExtractSelfOnFail) { - fileEntry.EntryStatus = FileEntryStatus.FailedArchive; yield return fileEntry; } } From 45a2dabd322fcaa1f0d5b3d33ba331c895363a97 Mon Sep 17 00:00:00 2001 From: Gabe Stocco <98900+gfs@users.noreply.github.com> Date: Thu, 25 Jan 2024 14:35:40 -0800 Subject: [PATCH 09/14] More descriptive error message for failure to read file from wim --- RecursiveExtractor/Extractors/WimExtractor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RecursiveExtractor/Extractors/WimExtractor.cs b/RecursiveExtractor/Extractors/WimExtractor.cs index eac9a08e..fe7fd3df 100644 --- a/RecursiveExtractor/Extractors/WimExtractor.cs +++ b/RecursiveExtractor/Extractors/WimExtractor.cs @@ -121,7 +121,7 @@ public IEnumerable Extract(FileEntry fileEntry, ExtractorOptions opti } catch (Exception e) { - Logger.Debug("Error reading {0} from WIM {1} ({2}:{3})", file, image.FriendlyName, e.GetType(), e.Message); + Logger.Debug("Error reading {0} from WIM image {1} in {2} ({3}:{4})", file, i, fileEntry.FullPath, e.GetType(), e.Message); } if (stream != null) { From e59e966816e5ed7ea30aff8c1e9b38c9f547ac5e Mon Sep 17 00:00:00 2001 From: Gabe Stocco <98900+gfs@users.noreply.github.com> Date: Thu, 25 Jan 2024 14:37:39 -0800 Subject: [PATCH 10/14] Update Dependencies (SharpCompress) --- .../RecursiveExtractor.Blazor.csproj | 4 ++-- .../RecursiveExtractor.Cli.Tests.csproj | 4 ++-- RecursiveExtractor.Tests/RecursiveExtractor.Tests.csproj | 4 ++-- RecursiveExtractor.sln | 8 ++++---- RecursiveExtractor/RecursiveExtractor.csproj | 2 +- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/RecursiveExtractor.Blazor/RecursiveExtractor.Blazor.csproj b/RecursiveExtractor.Blazor/RecursiveExtractor.Blazor.csproj index 6dc8a452..76442f27 100644 --- a/RecursiveExtractor.Blazor/RecursiveExtractor.Blazor.csproj +++ b/RecursiveExtractor.Blazor/RecursiveExtractor.Blazor.csproj @@ -7,8 +7,8 @@ - - + + diff --git a/RecursiveExtractor.Cli.Tests/RecursiveExtractor.Cli.Tests.csproj b/RecursiveExtractor.Cli.Tests/RecursiveExtractor.Cli.Tests.csproj index a3b22db1..732733ff 100644 --- a/RecursiveExtractor.Cli.Tests/RecursiveExtractor.Cli.Tests.csproj +++ b/RecursiveExtractor.Cli.Tests/RecursiveExtractor.Cli.Tests.csproj @@ -11,8 +11,8 @@ - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/RecursiveExtractor.Tests/RecursiveExtractor.Tests.csproj b/RecursiveExtractor.Tests/RecursiveExtractor.Tests.csproj index b9c2c4e5..e00a91c4 100644 --- a/RecursiveExtractor.Tests/RecursiveExtractor.Tests.csproj +++ b/RecursiveExtractor.Tests/RecursiveExtractor.Tests.csproj @@ -13,8 +13,8 @@ - - + + diff --git a/RecursiveExtractor.sln b/RecursiveExtractor.sln index 222c4cd9..8cd99673 100644 --- a/RecursiveExtractor.sln +++ b/RecursiveExtractor.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.30309.148 +# Visual Studio Version 17 +VisualStudioVersion = 17.8.34408.163 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RecursiveExtractor", "RecursiveExtractor\RecursiveExtractor.csproj", "{A7F7492B-60E0-468C-B267-BA60EC131E86}" EndProject @@ -15,9 +15,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RecursiveExtractor.Blazor", "RecursiveExtractor.Blazor\RecursiveExtractor.Blazor.csproj", "{18D0803C-052E-4338-9162-F2DB8F8E51E2}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RecursiveExtractor.Cli", "RecursiveExtractor.Cli\RecursiveExtractor.Cli.csproj", "{443B4E50-9AAF-436E-B3DF-644F782AF9B6}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RecursiveExtractor.Cli", "RecursiveExtractor.Cli\RecursiveExtractor.Cli.csproj", "{443B4E50-9AAF-436E-B3DF-644F782AF9B6}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RecursiveExtractor.Cli.Tests", "RecursiveExtractor.Cli.Tests\RecursiveExtractor.Cli.Tests.csproj", "{F37B314B-F641-4336-BCD6-BC5B85BEC5DB}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RecursiveExtractor.Cli.Tests", "RecursiveExtractor.Cli.Tests\RecursiveExtractor.Cli.Tests.csproj", "{F37B314B-F641-4336-BCD6-BC5B85BEC5DB}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/RecursiveExtractor/RecursiveExtractor.csproj b/RecursiveExtractor/RecursiveExtractor.csproj index 01a7ac1c..6a73cb28 100644 --- a/RecursiveExtractor/RecursiveExtractor.csproj +++ b/RecursiveExtractor/RecursiveExtractor.csproj @@ -42,7 +42,7 @@ - + From de92670cd39bfdae9e157bf99e26aad3e4554e93 Mon Sep 17 00:00:00 2001 From: Gabe Stocco <98900+gfs@users.noreply.github.com> Date: Thu, 25 Jan 2024 14:38:18 -0800 Subject: [PATCH 11/14] Remove unused Workflow Files --- .github/workflows/publish-code-coverage.yml | 26 ---------------- .../workflows/publish-wasm-to-gh-pages.yml | 31 ------------------- 2 files changed, 57 deletions(-) delete mode 100644 .github/workflows/publish-code-coverage.yml delete mode 100644 .github/workflows/publish-wasm-to-gh-pages.yml diff --git a/.github/workflows/publish-code-coverage.yml b/.github/workflows/publish-code-coverage.yml deleted file mode 100644 index 4f3b4d18..00000000 --- a/.github/workflows/publish-code-coverage.yml +++ /dev/null @@ -1,26 +0,0 @@ -name: Publish Code Coverage - -on: - push: - branches: [ main ] -jobs: - build: - - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - with: - fetch-depth: 0 - - name: Setup .NET Core - uses: actions/setup-dotnet@v1 - with: - dotnet-version: 3.1.301 - - name: Install dependencies - run: dotnet restore - - name: Test - run: dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=lcov /p:CoverletOutput=./coverage/lcov.info - - name: Coveralls - uses: coverallsapp/github-action@master - with: - github-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/publish-wasm-to-gh-pages.yml b/.github/workflows/publish-wasm-to-gh-pages.yml deleted file mode 100644 index 8a91180d..00000000 --- a/.github/workflows/publish-wasm-to-gh-pages.yml +++ /dev/null @@ -1,31 +0,0 @@ -name: Publish Blazor - -on: - push: - branches: [ main ] -jobs: - build: - - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - with: - fetch-depth: 0 - - name: Setup .NET Core - uses: actions/setup-dotnet@v1 - with: - dotnet-version: 8.0.x - # Include wasm-tools to optimize build - - name: wasm-tools - run: dotner workload install wasm-tools - - name: Install dependencies - run: dotnet restore - - name: Build - run: dotnet publish RecursiveExtractor.Blazor --configuration Release --no-restore -o blazorOut - - name: GitHub Pages action - uses: peaceiris/actions-gh-pages@v3 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - publish_branch: gh-pages - publish_dir: blazorOut/wwwroot From a73b0799f3b9d28ec8e01814cd2d5d2942c3680e Mon Sep 17 00:00:00 2001 From: Gabe Stocco <98900+gfs@users.noreply.github.com> Date: Thu, 25 Jan 2024 16:29:01 -0800 Subject: [PATCH 12/14] Implement DMG Extractor --- .../ExtractorTests/ExpectedNumFilesTests.cs | 5 +- .../ExtractorTests/MiniMagicTests.cs | 1 + .../RecursiveExtractor.Tests.csproj | 18 +++ .../TestDataArchives/HfsSampleUDCO.dmg | Bin 0 -> 58174 bytes .../TestData/TestDataArchives/SharedDmg.zip | Bin 50775 -> 0 bytes RecursiveExtractor/Extractor.cs | 1 + RecursiveExtractor/Extractors/DmgExtractor.cs | 107 ++++++++++++++++++ RecursiveExtractor/MiniMagic.cs | 20 ++++ RecursiveExtractor/RecursiveExtractor.csproj | 1 + 9 files changed, 151 insertions(+), 2 deletions(-) create mode 100644 RecursiveExtractor.Tests/TestData/TestDataArchives/HfsSampleUDCO.dmg delete mode 100644 RecursiveExtractor.Tests/TestData/TestDataArchives/SharedDmg.zip create mode 100644 RecursiveExtractor/Extractors/DmgExtractor.cs diff --git a/RecursiveExtractor.Tests/ExtractorTests/ExpectedNumFilesTests.cs b/RecursiveExtractor.Tests/ExtractorTests/ExpectedNumFilesTests.cs index 0228aa5a..0736deca 100644 --- a/RecursiveExtractor.Tests/ExtractorTests/ExpectedNumFilesTests.cs +++ b/RecursiveExtractor.Tests/ExtractorTests/ExpectedNumFilesTests.cs @@ -43,7 +43,7 @@ public static IEnumerable ArchiveData new object[] { "TestDataArchivesNested.Zip", 54 }, new object[] { "UdfTest.iso", 3 }, new object[] { "UdfTestWithMultiSystem.iso", 3 }, - new object[] { "SharedDmg.zip", 1 }, + new object[] { "HfsSampleUDCO.dmg", 2 } }; } } @@ -74,7 +74,8 @@ public static IEnumerable NoRecursionData new object[] { "TestData.wim", 3 }, new object[] { "EmptyFile.txt", 1 }, new object[] { "TestDataArchivesNested.Zip", 14 }, - new object[] { "UdfTestWithMultiSystem.iso", 3 } + new object[] { "UdfTestWithMultiSystem.iso", 3 }, + new object[] { "HfsSampleUDCO.dmg", 2 } }; } } diff --git a/RecursiveExtractor.Tests/ExtractorTests/MiniMagicTests.cs b/RecursiveExtractor.Tests/ExtractorTests/MiniMagicTests.cs index 361ae189..016ef133 100644 --- a/RecursiveExtractor.Tests/ExtractorTests/MiniMagicTests.cs +++ b/RecursiveExtractor.Tests/ExtractorTests/MiniMagicTests.cs @@ -23,6 +23,7 @@ public class MiniMagicTests : BaseExtractorTestClass [DataRow("TestData.vhdx", ArchiveFileType.VHDX)] [DataRow("TestData.wim", ArchiveFileType.WIM)] [DataRow("Empty.vmdk", ArchiveFileType.VMDK)] + [DataRow("HfsSampleUDCO.dmg", ArchiveFileType.DMG)] [DataRow("EmptyFile.txt", ArchiveFileType.UNKNOWN)] public void TestMiniMagic(string fileName, ArchiveFileType expectedArchiveFileType) { diff --git a/RecursiveExtractor.Tests/RecursiveExtractor.Tests.csproj b/RecursiveExtractor.Tests/RecursiveExtractor.Tests.csproj index e00a91c4..40033e43 100644 --- a/RecursiveExtractor.Tests/RecursiveExtractor.Tests.csproj +++ b/RecursiveExtractor.Tests/RecursiveExtractor.Tests.csproj @@ -110,6 +110,12 @@ PreserveNewest + + PreserveNewest + + + PreserveNewest + PreserveNewest @@ -122,9 +128,21 @@ PreserveNewest + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + PreserveNewest + + PreserveNewest + PreserveNewest diff --git a/RecursiveExtractor.Tests/TestData/TestDataArchives/HfsSampleUDCO.dmg b/RecursiveExtractor.Tests/TestData/TestDataArchives/HfsSampleUDCO.dmg new file mode 100644 index 0000000000000000000000000000000000000000..c80f517f2c29f6c298dafe50c967c37d29fe9f47 GIT binary patch literal 58174 zcmeI2du&tJ9mjvRFNvMF$u%(qH6`3e4Wxp^PJr+Vi5)x6g9IDm@R+7{PJ9U_ah%!C zi?+*gLJ5UVLZVaum?r2RniNGsrQ084n~H>{iv9uWx=u_Tl>lk~tQ%6Rtw@{3j<2up z!?_6w2`-@DRg`;Pzu)=Y&-vbS&b`;~L8qq$VA?Wm0Xy&da;DU9>{i)lw_4xyc6@l@ z-sQduFhk;E0c&InPX!?aG3Wyha!-aK0KLF(;>H2+4+%Vb1lk%tdb?#KFa&f^ZLhKe zz|`%VyS}-7b7st(pO_heBBD1N2n(eN-6vomXCar|fEp-ZsuN&^ZNy+SSuI{*rkw8- zf81O?(_r4f>|wlXnz~?H0E!bj2V5q^dWN~koErzP@pJMOJ(X`HtKR@G1!|>Trntrd z$l`9ZI{O)A@XX$f*t^Bp!x^y~X+Ut27}(Qh8v46(=$90s-=U%FO!I}FeL3uhP2>Rs zQxWA;)Q*yPUW0D2PbCujBMedT2>xH6}=NROVv%g<@ zFWK?14=Se$@56l0taEkqz=Gf&M_KDo;81x z1w8|=5G!<(mCX7{2fz&&AUWd@rEw2~kz5%E*AsOK^919As;R>Ja34mYz}l90pmP>} zO*NQE3ny9}i64C7=WAFiq>&9sx_sE3h`iYgdZ~o-G*|5T! zxNxU(Pa^U2mlEssll-Os+_(O+=6O=$v3!xxUH3x+ zb;aeyj+Hm)nKoeRi9O#yR;_70r2k97A4;zh_B;BkdG8<5Uv(7S&0Smg!((vHVO>Wo z+^$i>&m7i1hxIjwbt-7+a#+ukB5v~meeXO2^|-5!!s;Kb$you+pP8RB2bkv#XZ54H z1MoX|+f(@9ad(dXkpL1v0?!Nq7T{cyr}YD@vdp=f^7jPPUswPnGow4<|1=$9K6QQ$yfALzLBhc1H5yMV+3I8_RU@2&`sQ! zSqP(B3?rNohLQS)lf=NDHq$8Hm7}<%h~f^7LT7rED6~X9SI~2nkI}mfIz24_)0Sxq z*m>8NGo^-Ox5_@d)%vEl{W``ljOH*s@0 z$8sd_R1;`x_-NLmMDB~#}D*Gf}w%l-DO>VPv!QqhWfm^7u{Z$|FEx#8|)9o;+(ImvAxyB zl~vko&cVTc-ez8dL@2!7|!S%DXBYS{e-X#Ow1+b$$F;eUy(yhN3-u<&j9Vug;b%qBUZR zRFm%hzR`4zsV)$W29j+|ax0ol+BxI#XsCNA&c~$Iv?fLi2YT!6qjvjNd!0?pChb#J zF3;XTnAfnN*A(Y_;-O)l>j=c+e3Wa9MB?0jz9$k5aupqo`?;N*{bdc8?m#@CbQq+0 zA!1Ya!T#d`XYyzg{%8DaROW>coz7lWp|U|{S~O@)miP8H5A8YLo7qI27Y)>f^X0N@ z;7W#{y84(_R6>;$(ok4#v&WV^w#x-VDurA!$f!+ccMA>bZ1SK9;%ap(M^sc%WwplW zFQc4j6scR~v5URg=jU4ZK#;1u!WRvN1JN-~QMQw-UIwA>OEVTnRm_SbA_`q@B(=^= zhz2R4k4EBKn;&BIurbf5nguB-yBhZe zqVZ6iu8mxBl2&WoAL#Dq>6~7(3{sb8UO7caO)Yg*l{BWRgi7i|(S7k}W=?O?Tmc0n zT6dqjWmscQccoxy87MI>W=>zkl%ACOBM2&cisveX-Q265D4!Je=A{d}Rn}~?lCWCX zBg!i6v`X08P1L0i8)J2An#-<1N{LB2+QJrS$svtyk>mAg2-|sBsFw}o=E~G!gk7`n zy~_N$$)0|Lp;#YBHzU1#I-(X&Cl&IRr3-nFgt1oGN2IeN@ziEyAzN?JAhj9UzJ1iq zKi!)V;SLurTvNzL0!dP`E^8wqIakfWr1~?C#vQ48$)HW6QHG6>O^<_A*Ek?0Rf(j( zWVoV%^rYZbY^9_T8Hz~tje@~3p-LFM_Ox4f`jV2KrEoiV=^9cEg*#qY#9Y#RSKFL+ zl6=Bb8n{~|Pp*`#guE1v_b7FuG?276EXUwI0hT-T4Lr|jxI{pv}f zbFpYAw{7V{w@U*w&zq-4xsfF7%!EqlP0br4BM&i>M3U)gu6%Y46mOn1CvagCB84>4 zChv?6W$Z*!*R%YuSZfz2^hF3sR(PFF`lukh>mBTm#ih5s%l^S(?ym!LX+o=98WgQc ztui#wqLNvLlro8EM7UAlBif(N=HNneWR{^+=f zZ!xO1Q)|6Tm&s@0i+z1wU!mOGgH Ri*GFev14&;3;v`GWsY(kSq)P8Kglsno(nSfKAku3Hy#@gx zN(m)|(0dCll#mcYl7r9loOg`x`_7MVoIhuLXT0;rN@nI-Yuxi*^S ze|sF8ySB#^8`&AX!2jjklEz;T&i{Vy1x>h28gnj_M>nYz^!%R_aq+@WDNFZ7p_SUV zpg`Z6EK$^!F%N20(d4pNki3NpZhW`QF(WI*dhYv+N=O~hcSS;H1~d;+o0Y*tW}Mgh z?Rm}xB5{kn+fG1&2(5%^xW)qSHpsjENNe9DHZqA|ExcznbUM(fq1A^X=P0s25eXMh zq$G7vN)<*^3~zkR*?hTANnJW*977oG29-I-s}7K(LdapTI%9tJkZ=-<=ZM3-pV}9A zTR#6&BULP8@0mqY;fFP6uq@3YyaJmXnqO1#zGd2|(Z*_W2sK`v2mArQj z5lLC5QeIwm(FhFcJM-87-2PhJ1HWGF@c}7@Z>%saqmT-8OfcjqVV?T^(A6S*o_)S= zzh3=a=W)XtXg^SonMB_{pG?uX$Dagmja`{aO2~Hb>lx&ytOt8gR4B!rOL94VZTq*^ z2bb98zvI?p$&HJH!!O{(ry;HQz*L`yNTgZYg>&CnXDrp)<^*P#=2{e8tndx@x(EXq zM16!`-Y*09BoRN{y{8Ww={grr-X3?D$zO%ao&8Q=fvX1+BjM_;TP=GWJ+6O~K-9lF zc)D~L#C2R0^12u0bUjS4Q)R-k5PDbjMi&R2UeszjkQwAqK^Sz8V~xD48@|=ZAa_;` zF&wvp)kknFJWS&iCxt`c-~Z#7*wWYcrc9mOjNan_xVtRe@$5PSx9*vwH)$Pzcn~zdMIvw?_nK zEm?C+xgU+D%J;M*#dfF756_=lh#v2QbR1k2GpK9}?O`<9*AOBLwYq`J(#I#HF+(J3 zHo}lHMcT95&;c>jBx) z?=bfeI@H*o-~qw3qRHOj=1oOHplJsq_1d+l@@?|`oM`2h#iy5YDSKsklS7au{9$eu z@_Ft>)6+EgDQ0*5arkOiIos?|&70JLZaRpp6~o$who^a|$0`g6wl0xZQlK~l4=w27YTlsSoDmwlVQ zhBcs(yPjaWo0RwYtI(V0&ec{#fR8wU?QNUKWl*t>hBNOAnVzDM5c8Af(Ow;Oh65Nh zaR@k@=0Z+6?KG(|ETmoQn6)j?7u{68{%OR?viapNAA~4`lm~cT>fr7oB$!0FkPi9h z$&{h@yX$ImC)2^FFUW^{-i)ba+pP%omG21z>f!D>AfosnV;VWE-X$5m2atudQm|D+ zc&qNzDk43NK+k1V&KyxLEU!m^LAZ4g5=^|x8Vpt^%5*R)+pTkfwq$`^iw&yef1bde zm$8+aEzMK}6lQv2!)O>rO3@RmMR=|mE&hCYt#Vt*>}bz^f2F)wLlDG=n>=p5p}ExL zd>aG;ZgY3jIhVuJ;~`n*O+AH(e6fVA8d=Td@=t{_x4Xq9p*b?C4iM&%53e`l;=zo7 zZSJLxa3wUVgKhD7IJU;+R#9;>w#$98w!>|*PXCk`U&a3Hw7y4Gs5Z2q8q4XXcr_5L zn}4%EUHmpjc+Q~>$=!`5ViS#1@#ayX*5b%E!!{<3VisIa^?Hr`N0?{^4&yj-({LjC zNilL9Wh%|S{&`f5(vLFT2XzZ)0)ju+5H*!dlfFx8> zwtD_5L$r2bjU5`JjMZ@@;pWNJgAH!)(-l+=t_G^J>|{ zR0H?~HLKQ~?l|=jI4+d7&)lr)B^?Ab+{V@LQ9Q!=bBrWer6A27Embl|0@%OU_HijN zOtB7Btpj~|h4Lf*<6%AG*1-tZ-E~VHqaUc2Cz3Ps=g-Z%*iH_2EQ)bkY_Y;ykERrG z5uOW&7qpn|#_TmW&;B zFElDlSj<|yx>%|-#Lxi&@M<|6&kd-A2)b>MJ0pwmX`KP~{!g(Oj-b!0b}){^uNa+< z8n>v|BDcu=xE{M;1BT&Wms*#%NcSc~;i428%Hz#LE2pzF8(@qO%NwtE3xcl|2I8gSfBFl&1ya=Z=(8$; z>Hw&Irg<5kK)d(1$p@qG$5z~<-piGjife82w59v@2@}TLo1`)DT*u{eqVKns zsRItDhNSeifZrpgxxK?(gGrl|{%I zWwmK}CshoEH#c)Wr=j&0-P~63JRX~u57)bbrl@xE5hjY)`!@r&Kcj=Ng9-gD7Ylf1 zIH#1-m4^J}J*}-c$`A?h&h2(`;|q?b!H|kh-e*;YZVD0_Rmuh^z2+9zuz|wEYMHC8 zuBKa49F{;CmfWQNM|_fw(?}U<()P{_RWgUr@9Hg<#D1X^NTd14)i++a3&ncIiI)@A zxh$WE>FceghL!qDTNM+%Z0MtLAl+u;Fv#_)qEVg718^QKPE*IzUxYMhjhOe6C?I-W z&OzprgMRrM((-Rtzir9 zv|QW6eK{2%V{{W?p=+^)NdPO*$H1 z1+2Ap&{Y3v;uWR6Zpw_vm4X_c2o9)frAg-BA~g)RuV?2Pa1Hd5=lmt5y45!a)Ykpp ztS>YufzYeZwv~h$rOv!$SmnjKV`Z((D&nDhn4CsFUH{XtN##j#1&6ZD9PB;BJLF!X z4oLRueA1}vey{{%e;#wTVD8#TzyX<`z*tur^s0%RBJTNeiriNcB?NeICQTquL| z#?0V>!}({v)SKiQ98)&ZsY0o(uYKzCKpix~r!T53Q{~Y)5r3%h7-r0xW&feSiXG5) z5)o_wQ!FQYZSnDhR0w6TQwop^$!Oz;W&7*gf%=k`W~$ZB06r61qYG0rs~Jow9;s*ip6C^LP$D0Z<) zC@}0rVc^gKd8bi*p3C+mt{DUW5+JveSgn+5L`F^+_PO_y^8#r>F5!64udJz}frLZ* zR#wgU*mOk8Rnj^<+sUcu5Q(GG zgXTl<20HWN32FM!21gXbe6V+!Q3scqr!hjeel}Pkz&mb@wZ~zSx%0#ui~OX%L2-Qg zjtoY_l};J4ge!TYpD=%yhy0n%EcG2&u4u7c$Iuhu-#-f9&x989Q-1b5$^H zgb>1CGDili*36;(O^OCT_}dmg_AQ?%t?oYwx+rR08+x}j%4n#eKgTf4U}!2mNSbDD zArk2I;CcNd$C|4*@ag8(i9G=WhKkt+kNOT=>-QOV-y#0kxjVSkj>(m(zqsnI<6_;s zJG#|3M-1NI(%$rB(x7Hr!0R8p4>16K=xNBmB?ZOD-kUT0zmYHA$E~z;N=c^$BGU z8^R1rWMGh}zQzMEx-bIRQJW@PbGrUzH=>>MIcj063md>Zr*0c8yUSE4vtB6(#Wt); zm2*SBo`smtzXJr`!;?haM0F<%LdU3Q0pewj?>5B{aNS;JEa>;1F{LD51VLOhSSXQl4`JRpDO_B^Ao zi9GnB^>}MSWOuKkDX!h}&z{*kEnDsg;CrKiWG-orR;Kgk#B1qswCEGK_2H2m0I{aw zE)S=#ZAw+rCpHht=B+9HVi9eG0DNaPz0zxrk}2Nt&svNI*+GL zE4TP}Pfo|R7`s`K*16u4GklvhCy{u;fw7`RZ^Y{q`ku^J&4f*B{iopn?F6*S`Grxb zbB--ZQnX#0b(@jGnMIhrHz5|RG!&%my1k*jd;lwj8cr%XD5W0Us=Y;}<0o_&h5y_F z%=XXHh||pmvi#^L*8G?fM>4cXXdO17-2w%pNFHyT=aHUgh;r8^!j3|)VG)WYbHWL| zKJ{RJIj}zf9@mowj3wJ`j4c+z_F!G=x0H_p@$(iq1>U|u_`c34Y-`A6;3Pj=hpq^!G2qr0?`~gn zg?X?4w1P3nk&6^aTyo-xDuWPxM1cfH_wabCkJZ1QoW*{2hKCcs!p>5|^7?)gV%dZ5W z3b^@qLp>Z$!`J7UgTn2AjNU(T8EGP`GGEC3DA4sGu@I?5Lxu#69Xem?xN%@Z z=iLEa{o`y2{vG`G+Wh7D%kZe9Xu?%7sVKjHNj4fSEsR_wwS32atmml6FT8R{il;Ir zdeFVSB~61F4p9o-to`I)obmeiJlgKdmXPqupOH?cf^B=s+*I%shF8?p-y9b5!hIaLS zDP25#3Ar#9=))VfF3anhoH5Ip=G!~g2ybSpL;T_EM|4l;#oKAUiB+;*eWRQSaP3sI z8FOuuaS+-pktY3AAgWaA5s8LDcz<9Vte%Mh`tJnxP2!~8rN{qE3eZ2bz6<#LX$dZ| zrj#)#@V>J5Ww&|Bmct#WSudOPTC>k1G5jt2dut_J7?3nwPlWt_C~D?{_vzMbM@oAH zfsJ1u9v*=2=mj8HAln>If|OmVk~-)~kaEuLEIItseZJ+RS$g_f)@IULe?Dtop zOKP0TflZQ8YH9Uv-8?ix)%0#l+sI*4QEVeR*lG*R|5{s-0JUwf(Cj3UkLl zlbqmAV*dqhC{&ZL){;A>eh(W)jnz5UQu+n@=WR?+Bcwl0^-CMufI(PYVZulYVW#5Nah^=(d ztYZ-%<=$RS2WmD%WjW}m^SJR&G=HD{w)vCz=nLmgUsC&`=-19fF$+k@Y$XoaOme@F z%deRoZo83R1BW=~?klL)w|fYaK0*=Uli_M-g{a)}pcIYDX%ZKFnRBY_pforc7C zxus|&Ew%h1i~|Bw6{MQ;ITdv#`_w^HZ{1dZFz7CdUC~HWFS0P!tIXsJ^?!bdd@$Y_ zl07t8@xU-4JEmE2+C)I3-&UZ!!-n~LNFm@d&?un}_bJTEz-HS*M_y{n!q4To|K#;V zm!nfd-$b`HN}01XIRJv@MT{#r!~1io3&bB;PpAVXHlY4r=T`D zl*Jico2_TbfqNft(MNXckMc>SrJo_+6>kRJYSu2Dtz&MskXC!Nx>6#K*+T zE->!r(tUT24z|KbJCqm=OgqkZH&U;k1Xb5@JH)0SSH z?(WgIj{&^yWOf{*|8<_g37T?bna0Q@&~^@Qh&hY_n0F3GfRV=9czx`DiACU5ae&LC z^aKKUwW5s~SK@4=Bo-aS;+5rp*8d>p@^h#EV|ijq`Lu=#Fb%D7C2KeQM?Z)Ty8a)v zsKo}Uc9k)=_mn5C>Wz4~dKqSkU_syNFyKGqnmr}+EVE=AD_8u~s$qu`Mx;Eae_qAv zm&h|M`zttiOOZ1K(ZK&%8!BvVmLjOw=iHn|o>qFC@zGwg^{-&AQ(FP!=w_PKnnQe? zRO#ZXROz6~S)^ZF)9?7FAv)+qj+x(!*~U}Bz~$gGooRgFjM~)0(W)8Nv$onwp4N1~ zmR)$@+0A~bMRj5Yel2%Xjao#56n9_b*ciIb)}Df?l|#Y3X>|KvBzjg4q&30QUkbAI z5LvBXr4F}5w8|if?Y{)0oV)WlZKqF2b2&soO^ZKedK~19kC&q1XYf|DdR-*OIyw15g4s^kO?t`+5(4$Azju&%DR^K+0LZWRq5-~r*C~8wOzNZTzZ4R&=m^9 zzvB*j+)ZH-+x!Krt6g)Q`kMAs#-P2=IQd<_Slrw6T4bvRnU)K*Xd%~0RU`=dJ(zYt zQ{w`d=FEIoULP!r*&n&?h8i}dAVEdUaJmn;Gla&WUPucKuNDsw8sx-^W&*#_v;zcxVAV4@=& zRk=odQjRWPM%A*U9LYZ8wL5;rDRY=w`66pwNUEuJjuczL)b`cGx<;|3mXCgQVZGK> zl$Otl4qj$awKnd>T3)QKHiR5{c&VJQt)=o-UtpRIkW|zWXA3m+R^go53jE)ahURkK zTWn0Pu?Bj+4hlXhm^|AhYJcC%x#oR?k;j=`{|DZEp22fgFuALW>K%Mn4}E}?ZFBlT zjOU+eee1MEH__a@kEw3pq||!3DiI^Z`@}%#AjritCe2WOM`C}wouCqTCKeELyRpXd zuGe(kA#;)9#@ZspqG7yu*v@+4Lxp!}Wwlz|#V`F+I2@fgHB_OdUR@4Z-t>mkkFdGc z;5SDnCXnh)VjsYA|L9D4+?Aw-AG@huG(a(2rx6F0;ko{$-d={oJZsY~AY*bbuD zE0OmgmlZo#cc)keoolt>m@d`R?yWh~V~f)Fjdtm=-k$wUWOsbn+BU9TG}}IL;6w9- z+NE=L8AoT8c?`0X35Qc+u~E!QCMZqT5p?#R`KC(s(ZMSbDIY+)t;5Z~3-l&3y*qXPIIS7$GpyrTy z%QoAA`8fS@W1jGoSf#XBft1mIpMKGfkAk57zymWs7o%E}<{P~kgNF05&~j5ao?tuO z5i~osZU8Iq@T)O#)sxFDkyX!B=Y`jyb0nh-uv^QRZYXAGybRvj%GZ-s=(3{D>lQ}#O7zXThEhOZguAr&G%xMIOBegiXKX(Q}dwcvE zM`MjR!Casz%+xy!B^zXS>`e&)j_^a_O1AHU(yq%7STuBGNlk|wuF@zqN7iqorW>dF ziu?2SRY9x22w7-_-78{Bio3{L$nt}y?t}@_8 zahprsBXwo=3qW#0Qf@`Nsb@rq3Ai2_r9N7rU_q_@o4>55$#v#xB(Crn^}w?Jwe+Nf9xHWgejSm-)kW_)*|B-Xh-?HT{|;j)tB*`=;_#X!^Laue(K=MV1wcVhD zk69PVUHs7s-MLW=1+TXkwcT}aDPF=*oyN3X;aT&R#=6=72>$J8WFbnMNt;Q>AeAL8 zF%>2TE+Hn5YU$(`?vGMN9r0RcTuU8z(qGtNcv4;{1*KC*fjSU4F-aR>dE!!ND@oIa zH6nwIP8SAJ%}x|BdI+<@6Loc4qqf6X*`E0pd3OlTx?{h+aSq`Wf{IMq$*F2Fub0bz z9N74^0(Ov^T%R5k_ak#lL4LNH(wjA>;L|VTt9^uRdmMZxq}7$R>P2M{;40XXl4^O; z$p0r`E)*wmA+m7dD^pDpd5*o9#Exl5{O&4dzdTsH(*{{c?KDB;tQql#h1l8oIC=b_ zjLm|U#;}N=B*=2_pn}I8&IyR!pOt!%uaWW!-f>jWqDvPbsd9&Lse@~Jf)K?JYN#Q+ zBS1}4$J6AY@@aFxmgWE*{O)M#C{>3HjdI`yl@OofM=El7`=%ysMRUZ}jKbs_8VpkO z(|WbBqZx*34fW2YCYhq(q5uSOvI0v>7@ZfVRgQA#0A8K^95sN_=@q0PM^g}WvaP*6 zyhd8uCRdUB3Du5u%5=p$3$xGYqzo}G5bO(~O!|Bw_Xau=o};E#k58VeJZU1v{B4N) zqq}_f>EAp5(u@gy(+!^1rd#7))24IQ8E)7{Sf#!(H{O0>dGg1~ShGc~ss(>}s%@!k zKjwU2u~drKs%g8r`XgTA_pzttK}ZWpNgeeTcSq_E+B9K)|HqH2oashygTvmc z(bBW`R$rxTv`qcJ8zp@8Nod_8Y(=U&TmF$|zVei4ZWXM&&8l3X4;q6w5UbzcS1eMs z@owm=m%)_QqfHJ~dsFUU@w#i~)9sb08VO@zom#J*mU^SXsqd2qKd%m&9-TVK01~rH zU|dO8*{-f4ZV~gL&b485;_-W}^^2U7K;3Cu0Khz>sTz)T8`C$aFSCq-RVB!84xVI~ zhClTk6GkI zT`<skPnUK=bH|7MkOMc zg4F9Aa2eW8XE}Mgp6S;fM-_n1!El>yIG~@byw}{>ZZ-|=-)LWjr9~a~&l_Mh%h?7u z%|hMmE2e%(UFB24@~IhGDXYqXZ>U?ZC7pMdLJ7OvIXX0t|Jk>p1FglD_8yNT!rZ@3 zxh07JZK}q4#flxiYm4dNt;*#l!vm%pYU{_FOECgxiE28w+R}mO>2K(^{zc3P6MTgS zE|11#;%i)5Y9LipB{1Ym_30Abx-y4u>0qo|b3~D9SkrBd8ll^rQvzz z9C3T**{s1g6&74Wh822_e~iJbA_OIaz-1<0##xn`60Pr4vb|h5bG2<#U@%o16hj~1x1rVSN)yA_k&8a{kBDn_{v`ggA)ENYurRIR*6|YX3 zdZ%Pz_f%yI-w1Gm#oiSy-jV{=KI@;}ecI0M4_kkL z?RPBhihD8W4?Tq?wJ|SmJH!B;C9DNj3npWCzM67Lp-8!dVI;$(fEvGJJIV?|qZl?F zyktlD@$+Dx4Fyy4TUdB|FpT`Xe>m(zX%;AE;Rmf5D@7?H2pgrWX-T}I1eKG;gCriM zFuSJkJq?rrk7{U5`1aG(ndIUmK;ViU4`gM7UJO(6S=so!Dr7&CkFt+bzd0SKdpw5l zD0=3n#RAj4tPbA$PVe4dMhYdW2Cj@nN7sI5;Z+KhEd*~g?G_Q68>ypxOpBdUH% z62O1y81b3OL7wG%K@y)**v8XrOlL7GpPJmwbsiLyRh=7IiQ!9j1B*x@m~#4%q~rpd1QEw#j(rs+_hXDOBe^Pm2Ma!-^DzQK zMvFYkzT5cl*G4x`W~iEXXA@>ROflRaswm{V4~|${>BK+nXJXj}i53MvdgdkNrPB4| z33+8ZDM7BI=d04ES;be}IlL=B5R(pxrk1r@Ic3Nx|Ct{#o0Fyc+RF>&pAk~e^;$A! zPe1b&568FL)niOUu_yk>Sb@`bVZ6Kz&=BUEL)kYYospSA04YPFbsjnJ+ zQ<(KQHbtd&f>W=^hKL(P%DEabZ$BAi-ePnapGmrQXNz$TA{ zI-be4arR6y87I*2+k z+**QOBgMU_#vSMzK4@4}Z)afIA<2aHh?Z;sc^^9G_&omxUsJrpAklO_z zeSOc}qI?bPw&y%(o&ON2ceVDN({p#jcxyEyP@r--^Z)}L6Uy;CBLVKd zCKV~HV_LScv?n{^7A+@Yh%^I-+=_Y@gB-N!avkxgce3y4PCZHea5QyogDBcA9%sB= zbBo>2yg785OXOsuF)M8;s;3c}6A5p)1NB29nm*p-jZ=Fv&IByt-U&D|NJ+|x$4+yq z0o{8l7mXWovj`$MkUTatZNYK7rQCt(V3y2jAB=q7-Sbt=hOUFjf;*YD*a zYX39J!6g--S=JsoYqO%+9>F#HTso`q^CGR3)m=BCNWyPCEhx~xNB#MXJV(~7cz@5D zNYH+${O#l&kMOCn+@bLpH4WFeN5o^~K|f*`Rdn_4mc`*S9j!;cFl_SdbWKPtTRBqM zVo>?;;7voNO3Ex(c(q#4#=g<|9YpX4CIEu^W}U99T73p}iUo!wCefqbB7UE0!n}p7 za6zI7U z3S#7%TCdssc|x^zE^DZTP12K9EJ0Hh*<|dd#^&n%v4-BtiS`c;tS|)?PY=b*d7fyz z3hln?jZ*nTnzz|(fugeSVLf3KAs?8C$kpYq4Qy@IF;JFhWeW+LNku;*#wv*QrB(=J zuvg7KBG;t_j}xoFDQebNmBoxf@Gmmm_5-OwkF9!BH=oMwg7pd_-qbyMm0Oa~TVNa4 zdd`2yz;VlXhEMXVyXcgrnxtpGylIYlc1iBQ#fAY}2Pxnk%44~AZz|N=u%cx{ZUD?3Zm892;Ls_Jj@On*YPGF zqqRa;6{tqjEl)+}%N^)CoGv^)xo0hOCL#{`1`+u(P67z3Ha4V0(wh@C=V2ReNq0W- zcDqZxL$Ehpg!-LodH8~{Ox~O?$ZcD3bo&?@^UckWAQtRNlNPC@| z(_M$kG(zjs1tNlX4*}~>&3PCX_(%yR@8t?Oi`eo8F39XJdXRVC2kphTlwH~u(2SH1*+L^+s_3$woS^s0E} zd+w)VI}?tA^6t4V{V!iRn^*Bka16a13PP2w3t4iEauthnPtqr{<-oo7gob3@R!cQK zO{-0pyZ#A{N5nq3j!E|)%NTGg&WDSbcElxvsUM^P z+#jnzjd3Mg@qb0gyogXML|KjM|8%6(yXC_gzOOIq2P*M(r8LfbzS-_#3MJaK86`|n zNWKPeBtCyAZD{Pypy|vD*PVX-&H>@Gy1$Gz{5%-7n^5aDT5c)oZI$-@^F`-8LN9E zJ3~YIg*fw1=E>^FWlFPLN^IrS0DRd%A#=@MY-zulUAj>g6A`jbM1R#+zCXD+?GWCF zPpuPbTt@gw$iJUcnzopum{E{aw>SXvwj%;8D^q^zHiW9D!xnq^pc41mo3Y8_q^IV% z8$E(SjvzjnTMA6KT3KW)EO3{5b@(;vYMiH(qME?H?SJ^<_VIPp?A$9>P08XB24Y#> z>yM@i$xSVQ+tJRG5_d7tXHiBAI#QEF^Tu@I zaR1<;MyYy{R=m6@TigUrVom;#hpTAXR(=T~Zc+`Ek$ff$fKF&y$ocHK`dHE2PVoJz6g4&J%E*O-4nMoJ)Pu z&k1$s_|PmpVW)ss<@OCvbko?Iodw`j zq4LUZ=@?=NLMJ<0{B|SnqgmtN7Wr2ak_cv(@;M(D;Gg_FUi_KN!Muyt8k17iZQmYP z!K!eme*A;3{k7B#To=cHGxO(@rYbX|{Xp`pnx&?1svwD5`Xx2HU-k90n(md1YeQ^R z?zzIOGhDtgoU?D&uPT76)0jLV*+K!P;lBB)Y6;b^JhyF1AR*x^e;w&MxwXj|ri2Ig z6mkVwBhnlHns#{-dvg$guGm@H!JKJbXKKMh&Q=nmr(=rt7C4mDD8;_}g7r6kQ6MG( zw13HCXxMmbU_3gyk3S@Qc51fKd)9(J{PV)PJcx^c(JA`zUG}E=xBKwl^HG#GOL>2I^E2 zP`GAJYy(j`zGA%fG_WEyLOM@*T;@&Sy}}yrujc)cWM)~L=9dPacTZO+r=)Cyp(_uu z6}O|wLYr`&svI>17_yf??dbbhNd2VD;Dxv$hgQ*s)j(2E)OD5KZHmv^#HZY;E7i;W$_`t^B{72@Y&&TVFyFy^+#>%5z?~~5sXgOoO;ww9fy1!qrHeQGR{=6`|Z0=Q}0R*EV6G87`*VaD2D6~M6IC%Jv z>GFB*B9)xNzuzqV<|up(HvG3rwwZOUXgrtmH^F67&jPS!l<|oq&oUQ}L(SNukJbC| zvfEEKqdPrr0In5(+}np_}j0+#o2esF`?jU>;W}-(`&6i7s)(KGT9-7qNVIw2|!ywQ}9Fv36bHlZMvMLtj3* zESU1^(1uyuSZ45srdL>|(oBhyo2fd3tVEOUY0_7??bg>p+@FhxHyeN6JaLMN<@Vxk zcw0Pic}F?>bTyjD{dfzKCTBPPNZu25Sb1A{x3j%RUKs>i#f$kwf4gKe;8194y-!{k zu)>vHt@U?s;E>eSZ5*kG_VC`jK^4cm|1EdpLd&(dSow#BL!Kv9dd%>XEXzHUkLw8q zzRL+$!oNN3PHOG}j(Zz)JZfxGZ&YjzaCz;^?(659;7-c+ZI5&O)9}Ut+#lPoWF6#^ zW6k~S{+$!-u%fb+^3$(TuR4>R|LCMo&_3I2@CHjoGkHI;OA@^MC3@T0K;znIlwk9W zQQS4}J}*w6dOLu93bVK=v-gmftKuJU@qtNN75>vDqnWU~UoOz-CKzvjPaP!%=qr)<&R zqc&@rJb=*ycT$0IGo*I9m4?)*E}4k5mrDg0(cwgjInDgQo{|9uDND*?DxKAh~z z%}P|b)|hF>{~_TY@YngrMRwbFzKPn(Wy$dN*MW(JIhtrAqmb8rU--BDzxVqV8a$D$ z`o=O$F7dSPa`CwRNw%sUb3U$<*MT3m^|oruq<&THH~Fjszup`Az@OvN+UnzwIe$=6vUN$Q2IpcPaXp0@PJXeTCdN&hhm4)OP;Nvu?k#C6p(9sm@5) z1oOfMhu3FPSsqDbo}#5(F)3gz7x}9(Aku6NEUw545dQJcAk(+7AAm^tWzmoNGHf10 za{L8Nf5ri1Ld*MzvSi;#wL{9m{#T~NHlaAquPL?fKL~E}=IZ%*^;b;j5^`+5NM@Y>zQkL)MKmtn4P`hUTO?_P7dMO*l-cfF%j z%-wjbNF6OW{EFwUyu=vLp2dJ~gumxiynp^Rw(9p49|(~Y^H(hzB@4`kMXC~c?`~=f z|Ld@r5qWyT;Mru5fA%pvW+8qt@4XrgMvtEM4Ro0U4&E&4ubh|W{7^VGx(~Y*s%z+; zhed2Q-&-|px$zr_JM+%(H6aG5a<0@i&mi95B#s}|>}gZTIC7{s~9iJZ-$Yo!!f!1DPTzYa^_>hh{FxNzFH$+!{kz3!T*%dzvK+>LI3znf zY;xmfyXs*ftaCH$u9-;ao1%C57J(*?v65eD>jsj zw3_)zowQ=4UHr>!jk%bQT0?#_8scMW-z+%X9^lm%e{^XwgUu28Qul?qO!WosoKLM% zzATv5<l^w!_Xc zeUl4)Uv-lGP}cc#egMECKr@+^5plp~?V@;cn9du7U@|Yp;9pLA)v(=h{nW zU$=}ZabKK7ASm!}*x$ICwQ5A3e*B%utHdVerDF1-x8IGR$#>)3rQb2?2tOC;hp~Uo zErnyOEp2|>cZ=sHS(hvSVY^iJaUc|X^{u%W*44(Kjo_OV)pAh>Q=3^`|JgM8LdX?c zM=j^amnG~4#BcHs`#-W|88&N>=t_vmEya+YP2Sde(hLZCsnz{H*)3;jRaihn+n#g? z9L+j@&4ZSowvbTVOZtB0JK*s*(SMS@AV9+}Kfww$??l1c?|IfKv?nXN{Vo^wd#}hm zQBo|9=R2&=;GI(JM_j>Z?C>MZC&O<1#pvsx2^R&$rBwLqF;l7W-y5!&6|DX&c{Z!p zl#p?MHpy&z(`09LKPk7Br(07Z@QwFVzpeYlmv;|Jz~v__yqjaoT*W zLgHPM?;LE$zW*6lizt>SP6(P)7nFQ6h6WG5$`whgUuJW^le2RxQuW6uYq}#Bn@Z@7 zl70b4$&2qC8`2_cYiu4MjNdt)Uh;S#{O#>t7m(Y$NlwUlWZnC7CGU_Ut)H- zN)=IHpds_4ySKS1Ov?+xLJ>6zg~hvgc{;k$(8iJgGG0oDM+9mW@)P>?WpmXYnSFAcC*_ z4_b!~I>2|7;VDFJ!$A%n9=$*f7%J1~QNP`vjJaNwq+!oA$Fn=EH$&P<6{ye`kWtgq zb@121b^7IHVXOT_w2u?ZyTCa61;%>F=0?rjrlwM)$iTBn1SewGW?({lESta9Wc3T4 zk#e;W((ur%z1ZR9uX4uqSMcpqr{y2LErTANUm$ajp8n_Xf^jyr`VTc-`j-{w6E?n{I? z;1`4xpIGa0Yp?~UdqnHj5T|NQ?*(Y(EMY96Eqa>)p?0-2rH&mg53Hn`YFY3zz*629 zoWiE|O1oX6gqlfW2^ywBUpVv}{gqT*%?LNAlzIV4%>YKS>E~3Wj^nUHatc08~f%%T<;KXff5&4uSC5Fj3;*uE%v(8XT0C4W!^+DdNM_R-bj?vO?p*m zr+h$&D%Uz5PXqL^i2ZIWLZ-q?1Q}Ir~ zq8x@|LEKBr>HbXI?k4XHhHf;+RLfCS)XOOpnI4nF{Xie16_bnvE7ihTY~GKXYs_h% zb`hutAmXB+CmW1FM6}>XV2WLnd+p|PQ<5a`icTMOMh#B8@AUG#O5JKh#wfr2AUzwU z!G;njtF*mg4k5ND`vi=IF8epGVtCfrI(jvuULb9PjPS>z?XR)?P_iqcl~oV>zbPkO zhl(NHL7Qm~lVL55GzsR+EvtdkWVizeJV&TAo4Be)b4_6db!!l}*U4waiR`~QbfvE1^G|`=LeCiBj#h;)`Nyz=JjHjo56q99=q1J zQdjc5UC>*Rx__*T3b0wO6%mY`ZLJtCkJO!ef7Jg`3w!Cdn)b>yLywV|hhzp<>5-g|K@dVnFTGM1to1yeMTI_6w;)+4F|^r~h4edo zJet}OR7Mm*bg!xs^CyN7X&%vUP`akrBXj>ClVA7D45EUnEWgKSQOD;h4p7#BCL^eNjNIoQj}KY-4rB z-LVAOo}oxd_(H@UJ@3cVSUmiTDoXa5Xtn|T>NXuI>Fj#Y zp){c7zV7U^n!Qj??58>4JSJeNw%0Im_II;w<9o|3kNwVH$=vgGfEOhN0x42pvfZS* zBzOeJqRG%UYX&Bp<#(%ynJ#vec)+9Ly&*f_FE(ABXjlwRa%i7gtK6a%_^kACMZ|iE zRCj3Ufh!f4t{CZ@kzbP@=#s3nsw@gDL9h8IWK&9VDU^8NEBT+x0qw*=!NvoA}W7n5~B&(L&0&o%_4pA%I-ZBwRCu;|L?Ej8YJp<$9K6w z3U}IuWo2qm6gu|3v|ht~#wAOhbV^pE$iyC@Uv~&AW?)A-fgIP})d4e21VW%J{K83T zrnS7mVAEXXG(VofL(omu|0*eoOe;9Js^I8utgkZ8=LBhyPkGunR;S-=)RcSdqW@&b z6-b6;5wAK!Jz}21LZSPEI(%3I^97EiH)Ve)m9}CJ( zqz}okynzZpVk#gMrs<+?-zzoHnv|(J+0ZKZk5Kqlg>o_Sg>JV() z5PwujB+K{?DVdgCgYsK%cHQH9kagf@UCz2i#pf?|2>g=o7=a)C5bPGtM1<2A&)Wt_ z?apaiI!<(*=JD~}QF_>gs~y-vH6U86{T)pvm+8{r*SJq1qSVOQ#04_!m`EezS+R@i zRY~qnxn)=L`rb_WR02o}lf21%vm3ug9Rdvs@mB{*4#{>Dkd^7-%V}yBgH==sSa@!B z?FZKePB~kr;TzH}W$SknR0i<5l3OJJm=8iodW3F)(+_ssnD~v+1Y^Q=^N7f}m}mwT~qd$fc2ws=wmuqVcx`>a1NEz+6ZS-sv`!3t{dimwuLw0v(H{jBrYOZYM_Y3*b0J`R3bv zyza7T!z;C4SX_$@)!E_6oWN<~Rl7JWMO091U?fH}WWlir%_@|rw7F%9>uPJ;^(&0{ z?8)8|)pQPi#$v;rM~*}c>M-@D0Z}WRxJxLS1H!oDkW|YSe@UpY94QVcgcS}UszF2p zA5TgH`Jk3rx%n%|!xGH9FPWUQ9xQ=x*kYoY#P!o&-I5XV{*WvUc zoY$(PP3>0|E<5rf@?yZ7t{RPrxn?(BiX;QEH5gtZoVCgbb&*^O4oBe$A7uw3U=4jO z)=(i&24cMjBnF-`;TL{lX^YoyBgawk3qfX%@5mg0ssM2+b768vB#6~{>S7pgU)&dE z=A$*?_7W&oS^x+{9A(FZJ`z`&K;52Hsry1u9DAc;J5umrxnHCy1J^jUd6|%9j+?4? zbzf3w=CpjoPZ4PJE3+VN_gAOC8)jkntWX#rE@hcOjRJSQpM9Lq_rj|O^aE6~)}N)mbacBUc4`J}*tmBV z*EELfWabOf{nIr)*Z%1EpfL#P#cA4rmeyA+#b0#t>X0H3tA`q#7++K77j7z;`Z8^Y zrGdgxkS-G@4yE&1@`E%I3E)9d81|#D20vKjUE<(Tg$NfMbcvyV@~SHGpwC*fEtE^i|k}DXsWvVC%_T8%MtX1ONq|!Rf*N>3yT+w%JV` zBn{IY8wH8s_QaMerU>VSfsD^MQyuVwTIXhGXU|18L)8w6BtQIvu4je>g<~gPu1Vsu z_uC*5Nf@(h$7b+3gm(KJRYMwx*}FVQM5AqpF+d`uhJLBHxv$X!=Lqz%+dGPI>k|JF zyJRl#Izm&GwGRWrFbA4&e!dUbi{{JHrQ&9w78|mqDzcJRNKV7pV=P=xNQMD2+QT?J z4=1x4|LnGK^~8Rqm{&_-oHVz{|7baXR~MmBK=%H3l${qPjL2$X}Y9=Ce&z2hj3yBs*6CoKd02z{EhdH(SO7owyI8m-W3y?T!#xFW) z?iqdjC_FoG0jEv~m!=U@a)eLEpcLH*X-Ya{R|iUjHt~EWMW^;q0?c08E{&%|1t4tZ z>hTu&cv)iQ=cWf-AAvt>4w_GgMHN$9vFjycTu?5i_cz&gTi((IoC1BF) zowO9d<5Tt-+o3CtzuqgXbvY;!W}RqcDHLP=CR8o3B~;=cP`xRql4hbtLk_rd=@wws z`gtZMt*b(V?iRAO4C+6U^VJ#@9_iaj2ISPL6NZ)T`oXtOTf77p#5Y*IitKP;$S|eP zyUDI%vwub$w0UiXN*zd8FqhvoX{w-8deiLm*K^-%S0-PzT||L?Lc7uvEyacGXsa_swxu_a_s*_ z`io`Sxt%wsP!wu_cI~b+W}^-BL>zyx zmbNYLb2G56x_T#9|Lbt`e1V=bo+=5x^zL9l8KJkaa0@Yk--HYL%#+od`j2 zoVWWIyU6Q$Nf7eD)gq1@tw3D4etr(DDhFK89aRQE0o+Xy$Q=%JENZ%kg(_)+mDZag z&SA(DLsponBnxzO%gx6Rq$M+qz#gSG7R) z#hIMBkBTCBlR2KJgMb+-AX2t@%uG{3AwOb|c;>O+FN?Eua-Aa9SzkZ@m@+?7Nze+-zCHW^w!}GEio*>)qdU|N6@p?&?Tys^4#M%)Elrp`tekHzdMK zjr#9o&-uW>rzeuHA!{hiqaJY|W<^FUA9Y(5B4ziDEm|B6d_Q6zF8?c%L$p% zHry*iHa?zVpeR$5rXqzFmQY1wml8qG<@nOoaZ>b-mME?erQFFjcp%^d_?S2Z(_Uvx^;1Lgo49k+`V3tZQcOj zUSUZ#mLh)Gsp z69?%7CNrjqhk6+~e2|$lrB8=%DU_%)B%P|%60RJD--7A75?2blu{%~wrap@R|)Hg zSbeIV8Gq*McL@X|4>6bjfw$kB{g-C^)OPYBSR-<5EG?8hM%FS1+)Y%nRJqtA169QW z3D$8=u?Oz17BGw`3)d8*UUj)6+L=r@69J;9ky?^3iL z-v3mh=`rN4Q#>L!BC=F41bJ28xs$u*T3B0Tgj{9pv~kJS!{tk%C5dS4tYzB+%8~33 zULof+IP;MtCF)Roz>=D7RTVaWZ1cU~rM;zaXH)(POCr*yP2ohBCXa`0r6;E;+g28ADp-Juy5L=b>TxLTMCb_xlrn(dg6wV?umu? zpEr#2JAm0giE|86AGExR9Nkd|GJIkE4Qi)^BYI%Jb=7kVVNA}E2qBbU5DK)@XiF^Wm zin^&bZd-t*kjl%g&_Mtc+A~vbt7oOx&(+wkn%_5Gaq_m!p11Uxt=?>)JNT#DP0V21 zU))O1f^vx7bi~B+hLm#UjYd{b2PL0`Q41e#pC!qZVLa+$^EO{HcZiXrsY_w&_&Lk0~LRE z4|zdwrZo8O?7ptEq2AN!s&k=^=CXWqz-`}GS@rLe@tc&?F++K7;e_guaHNW7tn7t# zebD9k^q!WLHg*{WQD50r23cscu2iaH)Y)3$muQ-bK;k5ABw^UQdhx{TW@C6Fr5C#6 zyYbe)WY(Oi+;KdTl~H9r*+Rh|8LyXDLjxbIQ2S^-7eI^pGcR(Zys##GzVJ*`k_LsI zmBmm?{5LZ|z$`=Duqf*H?yKBy)`=FWU?SY|aZ}JBz`L48-(JKb+fwn;VePGdmc7BK zy^L^H#QtEtHPUvBxkk(0lL6<^P~V6wwuK9&s+TOABO-cTat~Lkrxslbkq5MDUgLQ1 zA3;8cXeq&CM3~QvOpZfV86A$!pYUIx-!6&-^Av*Wz8-PlXSGSY zl#}bv?J7b84z-IZ&0{M|-}v9yP+(5*Yd^GMqlF+S;nUTye=eN8vt{xr3YVE91Ws!H zR8T-iRZYB1wCG-d2nWalDWn0;tG`Z|M9+y!%(2IeDS7d4-P=ONQ-5sJ-WG=^4CqjB z%%V}N_3vI%jrbPwWqW&0W4;i~BG&HST_cyud9;ZO4d*&DEBT1KEvZ2#p$Mk+Pbh?M7HEIz;5q<|xZ0W?v zT#g8vA)%WQz*x@^{{7I-DpcuGdUXIy4B?f#bhR+)f4Z_*B^m;SW#~|eS+YclBOYdcP&mV$=wF}B8I{lbDn;nh zlN88EEhKaHsX%B=8Sq+hbDU~|{9_YN?@kL@rP*PAb#$2w;3M%;@NMGQ;1zr54!aSmV^n4`?FO&p(YP^S4o;Fl|^z{h^ru4wTc1RKY`nG z1Fse0h3riP0jzo1xT@#Ee7hTxnjf?f#9?|ozTAp8n*)V#i`9Z#-zTcql;&4uN)e)Vha8`_VGQ_x?+qURa!|wJi3WT- zTO{8uaruZ4R4Sl|xG`>_7L}@ZNioGFTb5Ev%&00N4Mm0)8f#~Ms(agaM`n3*XF%4FX@?zE+VRUS+(E>~MI^wZ2J742 z-9nsqmyBNkmz;B;xn%W_0IEQ;5LVzcBWZO&BtXjm4qYV7KHMI{mI3-TTlij>7_?~+ zYFDvr6ov{Hjp&yK8V&9B-ya2Y4davO`!2l!jcd=B<12BaE}G6Cl z*DJh{sxsX6V??K>O=C23jNe^8%M<>gOtb5%3&d%u>?BO$HQHI*oR(hoHb+b|AU&jks`wq>n} zg{5gxf;~^Mt%Q_SBbcjZ>CLbxaTMya|24}$yc;be&OIFcvh%Nm%m+cNDZMKfp!gcT z_|H6ZUyfa@D|2qg9H`x5!@k?V+^*^VDU3B}bai#31Q!7q5-~p(#7cg4(!ZJ6H2=3a z@SiJ0g^I6lnDOs41N(Ru%z<537*@0MCcD&nS05V(7deZR{$YH>N=>DVN7ZL1Pmkl{ zL0YGaHmuaN8@i~TD{U&l`L1%QivctGMd(A*uDCn&yf@#UTOCeTJ`Qiso3MpfxT$(K z8<>+nXFS_>?$!k61qj+h?OLIm1gKd=`Ohe*Nf2LG9M-eR{92D)Uo|~9Z{mQ0;mej5G=Gx5=?t6q3o4pdVtVS^*_l3B`!#d*wy63Bk-=cf~kMbf9g; zY;C0MM%tce77974m8c-39z~K!1WO#vmuvNmTyP_GYz1JA`dZ1q)@kNX7_!?Y=*1;r z49ipxsn8)lcD!BbO~cPSoHL;t3znE94x?=CO$j901HU6^Q->UD#;xS!tz$ zc&x3(%0CE}jjC7|SKo`Fq^gGNb#xH98_K8)V}w#V(ck4(wHuxep_u@;2Ju-wKUQh8 zjX9JFmc}Pxeg`vbqGYjNjbMeWKXP@=JT7={SQDxrbj{y5zwr0J1azm)S*k@(k~R~S zNC4=*s>drMq}i1hQ6LI~ZQN1P5T>{0`#~6Qv52!8`rz7#`0$n;hMUo^HZsW^p*i3q z6G>W4#Dq3KQ&|w6(N7oSWx&N7F5vX1VUKPPN(_0-A&D}T6O@WRco&N6$)&+e)pGrU z7vUg!d)@Kvbj;mQGR>Ns!k7%(B<-Y%gc%Xl7)pUx)Tl_J#8bIS!T3S00G_dN5Jcb& zmGJ2LlzdZiQIpnl!k*xvLYeB4aU=G!BWr#;P6>e8SV51rUcS6obcj4Ej2%fkFoF@R zjbC?UVBH}djp#Gf6ijyHs}g1mviq=+g~WU7s5aPh!;0K5TIC49{;SSqbp}f@I0MX) z5Ca3x@eeX;ERkx8i{oLu(EvV%hM1*$sl{9pdeQ_(7c2h2p2A}i1q!n0*g!n8OU+y8 zC<)}YK-E^)3V+q|BMY{a5~8aco)|$Tl{?%piX9ZxF+iS0=EbDSEmbP{gv(~0j(THN$ zj_WYrT9cBeHVT2t)BHqG7dS}V^w$#al)ZC+Wg!#;mGIvCg~v5e!7EOd;;2U`T@fk* z*)blb;CBjJs&~r|x2&f_c z7(v*OQQw6<=VnfrNUXsmRidxgZ=|^d_#k%d;VrNS1ug zLA}5J+R4seC`Yvuv)6^)RLn;DV4A`LrCSnExk@1a6$<=D#}|xnTp<^+UWV?rIs*fq%@*!j- zaJe7^eqnPN<&pr#;6r<95L2y7=fF^HUZN~erdo1A+Y@`VQt5KEOkprV7zyYh$vGh+ zh>z`^+{cLC-9o6tCoiZAb?F=$+4q-3;8K#^@Ap8cErI1E| zv^!f+9;=;$#i6|;S{TU@n*b9TxWPOYQlWf7C%sX-d#h!CAPxHSzBNGpJ4} z*V00FRK!93a#nM@HIshNtzpvOV|Y4JO8A_g*gpypF%-8F=lmIjk)*T#1qgXxKt?5I zLj)>v@Yw8%TG-%RZ@sVgvU|@F)(-h?8C(&`{7Dt!g22bD);wYnNTBW$8&`q}tXJC> z!W)-b*kNS1SEP)9&z|GU3BuP=`xmV&h2w&&qRA?<3F&W264A_=1=iq`35`o(LS)cM z9|_Hl9%C|-b3fyCvw3d;Vy0x6_gD+zzCOeh761A)&LcNA!(*}6Q|OC^-_JYt5OG+t zkCuJr=EYwp;Z{St)_HHt#sY^51nEG6b;CXa=TYysK_DuG?)t&*9exQi#V=nv;O|=e zJ;fHKiL0?VEZ!Uw*eo8bCS7?~FPj0I82=@`fzb1Jptl7AFXaiujZle9ger6EtB8M7 zOq;F$?D|zC`#Sb0JJdeej4e2N>nMEI8W5DXf$Vr0DB5 zCH!yQp#SDOLJpEhkKo_B$Z&nf#GecHHGcYt*b!ZWI%l0%1+>ipBMJ1i3H<=jX&&v$ z90pOsdjW$DuqP9>Qt*|(>tSb5fag~*9OsAI7v=zysX^lY7(1u9(Bx^b;6UK5nyw?8TT(a-lR zqg9m+^W$DRo!E+;A*(bODhQ{ze!dfejF69y@w00Yd} zd}dtK6pa#tb&DYwYuUQRe)q8;&SZx*Xe!q;BO8xR9DcBq$gLO5eB z|GQ`zi=Mmi;sEhhelgs8_C_tu;w&1E=I1PzYN@kPr=L=Np&hb8eH0xF>a4_a|vGvhpY_B6UT>z1B zJooI)tEJM)RdzR>&}nJ_v%V15PfhSoLXuMEHj#d4VHIn5pJld>U6P9oG6;gi$20-&}bLknC+%>qP&eCf}r zPD4JsVr&x*#!?X_iqqlR>JW0_V(*!Pyd)_VuLdi=nQ)ap^vV#7Ay`8EAkVmnU=%Er zL0laUM`No!A(A0qcn11sr{Lee$(cpZ6Mqyvkh|jxc811Ze`n8E6!wn4dL}NQ1P^@1 z=7|y)onp}C5;P&eqBhH)ZTEgi%o}YQ-R+|_9B#cGlyx>&8%ek;Di&bDS0%;z&(BeH zc_fELk@6A}71u`(9aE#vVpi}72O5byuUN_>`vJ1(wpH);m(IHwP;)u@OnD^R)XR`$ z6v^@fbv;Jc8#(YtI1h~AwTrKzdt(d?=~am~ly=aOQNM|u5SB|Oju+K-(aN0G(Zxy7M9IZ|V z1#Zj64uW*VDh$%r7r=-|M$cD^iRy=Txsl`J!k0h{Sq`?&5Z>SE5dZ6DJ#cKNIXgwv z&R-Z8+s+$D|&H?Jw7ZJM4c=tg+X4|~_>pzCjEr`ki zyVzp5#zeRnHg+OyF$y{Ow*2`XQ%JZ~$c_uM+KXRRWv89ijJQj2ZOnzy1GP#l8<|fA z6`5ji1H_+8u3)K-QckdI!OhNKGvm+U$sDnC&3#(SP}J64$K*blJxfo-O&_K~(5+`W z6?(75=a%!-MYj0~!lSvD8<%?#o_2h@()J5OG-%GOdxZin;a?>+0=+j_hn5}Cln%_} zNQXqI)fVmC?qx(yw4V0p(+ zk#j>2_L{|=S#TJ-w|mZN^c6P?gnVWI^6JNEk&BFx4gRw!j>E>W*&2O* zYo$a-{njwQc}NQ8i*Fa-Gs<_{38gNUqt-L#ELOx4GHxfi_jnZRJ(yKCs?&xYLML|V z31_S~2PJNeHP{Mf?it0&o;EgF75ug*&b6RAM86Ljer`fSlBO*}-Hy0zKL0kd{EBw= z4$=Xgrc?OI|E>i@Y^2+zDgH&Vf% zk`{=}W4#wTSUdpV_Q5~LhBDTzuz$&PmNuM^h?~1%xjX+mM5nJfTr=*R)dfiVb}W)& z$&#nuR)^Tk=U>UrwaX1(R(oN+S2;tE{-$?018(lz#M%MF5j9rWp|**-l(`-(ZYGv5 z?pPL@>sws8wNJBkpz?b`D>J_U!_A50t|wF)(FW=W)eVF&q_?B3j9WDnoihCN&^4*{kK@{ez2&mKUqzp-I9lNA#O)q z8T3=o3X>*e_n~3x_5^m{Fd%pL?^@Gq2Q9P7%S)|GUc38ru+T&>Ro%G)8Y77)J(VQF zx|Yqyms&$+6_;b~yky?_UrS=Q^Jdo>2DqD%_44pSw$*0LIYeuj$m#2%jKw%(U(;DR zQVYvaPo6wYV$jl$rUXWebM2cpXoo5!H8V9|5IjLGidzM9m;t0A-Prv)D zZJ&8UdH(vB&!bpWuadH&X?jYe!_bkZ!|ZaEEVEp;2lT6~4qU)REl%aBXNdrR6y+Rg z4*4CmMrzX3kPz0X1xFuo#^A>8L=)#h4l$(@^Ip3H+F26NosE@;@DqPEJ<+f9ilf^_ zZYawpXFG1`Ce~(6kI3~}j9y!c7577u_gB^rCL&K4U@bjLCfis^oD6`OE30gYswrjp z5GEN=mm)?$3PxRUASfVbU*-F_C4i&_K-zz_2(O9+n`lDDM=k$^yVm@KDTES|7r*>% zA>Fh$zlZXfy7wAUTd7+~aZJ7ua5hH~vlt@O#7k8V6k$s>cxU-Ulyz|eWfxn?2GzzQ zlG4q@qIe-tP>e5W#UsB=7|G~jsx&Fl{qY`LENx<~8-QgN5b1gPHj^7u$b93>DplGH zU3QVM{K^7-pru7e@n_3?Sz-c_x_2Caj(ZJC1P?*DBalW7W{A+H~WVtOZNLzKhh%oU^4;@gVV7o>zW1c8)N7nf}rZy4axa& zRX_$OH70Hz{+VC8KeT6;q~(x8{(Y1zJf#KJoz)X}CGob9n@ltmqEgSy4SOGe4X+4< z?Yci{7vB2eThd?HXuG@bcU}C)YDQ<>gQN~fyR`()!ygiBVbcw;-}!K}cqJ;6A)o?D zaq?ruD4?6=99!v;)A5N5m?4DWxa%OS3Uue$_AasLWT%3P+D_b_#rc}xG{tq~+g5~F zN|P&tEGuRsdGH%g%G)Zptm69b`Xayi`S>HhWv%A>-ze2hP-0X@DJ=<99_P`HJ<5L* zV3_p)z%Sxn1oG6b=I5Ck$Lf?}OC>7Q|3A0Ry>l;P@te~9BP_EMqX|v`LTzg|^LwOZ zBgp*AtF|Smw^A0AfU2zoLf*BmYj)A8=HXG7M#{91t{7I1Rj*Gwj&Hk3=Rzm8>1t$~ z?Hvz~Dj=HI)lcCkqyIdQf6mP?ZX>I9K1QJB z0I-fYx){aB?k20|f_EoTex||CTjq@`0bJ9MJH0TnJ0%(=+%WYH&*t3D-Lo6{k$EjX zC`o~!UT1gHlI_|}U{^p3m7~_+#wo^=O7K0-=9RN5B4|i68nv%)m!;{G&D*;iLXP9N zsl+SdGU+*(|MsPSiKG252zgci*qfcYleo*}z0{nse7W3h6z)QAV*s@+Xw7BfFc9kU z;--7$Kr&DVdy$DsTqrDVrZR}HKo`f>1kEg2K-YK|Li~$jnmj*j?3=_CbATWQW>m*b z!WX9~`c;bXK%(3`Sy>dPf*$x9t%KbvVYQoB$SR?z*$I+FAEQe}#>zc49)jd-aY`aY zD1v1WHLG6S(`2oCf4^mzxpA<&z$GiQ|3i9|9Day$hA+iM3bk%-k|`>_z8IP#8=zfD zNlzY}ekb~D2FnmqT;T9Eq@qaUV6TGr6f<)wuUVqW%+VS!LDHhkr9c7^;e-5r2-Ae2 zBvz5SrZMY2JQ5@7=+IEME?Z2s;qe$s)L_2E`8>;9t>aF7 z-d#S+evs_gNpp#`kq6-jK|5WRN7>{{rcRT`v}bjz(SMS<7~go1ARDfNgue-4$d$Nh?Re9$6)BC?<_$8;XfN%K_QDGBet-X zCU1r_&av}KdZFpP7-PV@{6>4{3d;qt&OR66>&+>MeZQEN*>_DPu7=zM>?~$0H`+P9zuap0s_P~Z*G|kX0GRO90zOrw zx5CT3W{`o`8#=x=QC!Paf4`+S1>V^gF&LE(Wc5 zpPe-KbYmFvII?4tmG+gT+$Y;@!?^_fn9Mz86hfeZ6 zwP>ILWjS-RnyS~K_~eKrtN_$kxkMmFEE&IQ90Z{?n3)=Q>8 zRKg7L{`1#NdA-v=q;l%9p7m>4`04MnafkIov-4b3Pg}k95oBmMR7SZP&>1}X$%WGQiR8+9g;$sR)0SD{5*v`U<_7Tsgp+`HH9400BN1#@k)32e%#8R{q!5t`o zJ>L3fID^Ci+JJq+p?Go@Kg0^z43XA|?zcnOwo$RMJhwMj9?s!d^LOn7*>sP^1~-JZ zD+@DR7)hY$2|=6H3o7hzfXISdO|nCyHMVNiO#IX-npbUS8*&H80i_BU>Aj^Ck6L81 z*dU}ecYGay8Sus5xBg(Fc zQQR5NkPi=`bZ^HwyW7^UB>9dspceeHhTkJE zCPt&swXegHMWgH_=16t!E~;}!dT810-weB&7qnnk{(qp*0xI5`=WiI(uP7f*A}16E zjNiYpu&;eRlTODJ#ob>OO}~9SVSie`d^?K`{j16{wPoVM&RyGqwUA2P=8nr#JY65> zY&gmMQ|#f~tLy7fKDY%5B=e*gm6GPkR_UtC1)413QXEoYS?qX;#N?^%pQDS2xI8Bv za8P@+C!`VkM#TRPr1CgR`5aS@F?-nsfz7faE#8=`)wXQQKN28YJFk@RtPg8TFxdY` zx3vr&1{iAU$;VAX=xrxU2wE*U&Y$x3%!9zK!7z2*2=VQPh0?FZ$JTTQ7qwH>IO&dR zjZyVEkqyY+i`GWCLnz>Ne+Ucb0E87z!aw)PD)egQ>Edyb6;&}5q}@|Ii>7^2hx$YJ zbhA?b9NXuHx84U;*&^pc9XKRhc)rSoM{UGC`0+RWIS_l*Fb7GUn8<~Yabi}AUHLy=zV_*6^EU)VBJ|}j!x*N7kS1@|YTt68AG?*Z-vukKvfVpF+{ zXq+?^+l!p}PQZkfN|RBM)F*{%%P=jMqB0q$di_M)(g2KLd2${}pwfA?L0b)bs7!%| zC4Y33AZCs!qFz8F0osqH`dk$1Hi`-KiAL53HYvBHVuCbd1hsWCnJb*#The-fXp1Nx zbn!IJCRu%BYh9QT}Q6pSWd|?YDF2|{9#ht0n>&z;T>Th*sS6Y!57In zs{Q8FQ(Gc|{8+HogQOU%6^FKY5&u0RTTaJU)(fTQvSthF|I*7S{VYY_KXh{h4xIP4 z4Lj$0#r=+FuS$4mou*(6#yw-@k-n&ya5>>|D9hA!Iy+dE&wFbqHUA>G?I?cA{Xx|C z4x(ft-$W}yO~cD6!9I`Ha{m#}Ux zY5*Si=Ty``zKSF`d82QaVNfwi?d8MRIr^Xf1(evmPM~gcAA!sPUkH#UJ5*N&lO)ZL zq>%6ldN|X#Ut@V(K11b#2QKy#m)QhqpN|O{to}Ci+5u@rz;Cq1=QNfL88dw7CpJl} zup#0!cBYx4D9lUoO&B6=iP}}%#)?}*3#Qr zlO4gp^7A&s^gPEoCc&tB{?k#m)UyOJ0p26fNpj4f4djtGq{IzjmTY8>@T`^%OO zP*xO_(FQ1Kl=LdAtNb{=uJ(U9t`})zy66|qo~7}x5H)7AHhdCKJ)ImsoHpxwlF1fh z)tJ!MPVz`s-kti5(2YNDghV}j@5(V@to0K)GHaz_5WjO2;ccnNva?p`>E~J_Qf1F}wY74Fg|3nU3>JYB! zX_%^yj*c??X~{TCo9$zbZRxYb-B?fELs7|y>6J6KWM-#Hr;x>)lzZR~i2rTn1Em@9 zLm*x}3uFxQM-b1UU7#Tq3|oP6`CDg56ry^}T*w~_#pcg-mIFN}PVyLtHOADCA(!sled7DD1YnE{pRkhZHJ z46CaG60-=|*=}RkQGKH&zfP_tE{vwKF>!X2AF=5U8xdIsYydwkATRe(O(vlchEqw4 z7|@jWEGVkmX=K(*8pqsxm5}%B$1;2+ZZx0S83(QFs*HF-s?$qbMMJE?@g?dlWIac3 zcaRM`>+KmV+UVby9hB1`Jd6-j}#i|S_4^77`?vpDuQrmC*Gd)Q#km8mwwXcRNYtdNWzZ8I^a@S8;gAxG z)ivJQ7x^?`>oXhE?~dpjFD#WZQ_j7!eQx;TO6Z?-TT0x^Dp^RLz5m>-?w^F^6qcr7 zTFU@jv=(SN{zsfEEmNTxHzG!PKY0NZtg$NcaOW%v^@4w|c*5+A$+|t<*$|bB+*zyY*S>6&) ze2nE`;pfLv5RRm|#Ts5MDCx4@t50+9wdO|YA5ap_#5-4h;cHHHo$}&TI&pAkH~Z~@ z7p^YinA2>hOLbAB@Ir_G)!te7)DgV>zC|lYafh~OaVYLyTuO_>!QCAW?iAMoMM^19 z^dJX!4({$!+}$~L`MvMWo80>s+?#Ya+1;6Bc4t4y>?Y4V^Zn+pFMeiX=KMDN&9vf0 z_0)Et2F|-ciHhzM&rekfJM>Oddm2zn*{!1L>1qFUUA_{PSG67L+k|MU+*<<6#9Z5q zW>g2Cf5*HNkKqILEm0AH!u6cfA&!fFWlp{b6=Uq8ql1Cr7c2#QV5SZ=gGrYQA$`@9 zF7mDD+lkryv*sW#3@>awcE}t>#L?1W&Z6*AIqLOWG6L+3dd|pOo(3mCn$neMrPG!z ztpa2In$7sfmeDb41fAkKreyz3odm$w^K)56f^~`}w_>l(<_K1_(ZZS5&-NXYl`$D@ zZ5#91%9B^KQCYh3G`)Sw2n@!ea|I&?@5q;HqV2z%B|N`;>{R=1E#t`+7-Nrf4QPBc zh8%A6)tJfM>Q1j!8}t_)vR~6$djkaZ7eBS)<0wa6&I$u#^r}#yN~e0as;-QzP`&5syha|jr@@nT_9?2mk)?!o z*L1|Eg|sfCks&Rv&12z&KH&tv`_yC77;B9cRu$yyjGYAN7{KSE>@%}%)FVo;d69hU zlV*!8?#wgNAI?)hD}ef<4w%ngLhyKsJMe=b7$OFX>{%aAT56eI{VJ zy@T(s{$!B~yzdDGynkt!7yh-ANJ9lj5bxnK-NvbVGjoc4drwecO(kPPnV-l(sY5|q z@{BAV*VHc!XOA8i!UetKZo>x$q0SI4unku+Pm2=mlT1(8gknel07XC?=LyO zl5bg7;9C(#*Fa?fKZ~>|>pjB)yHlal+f;`~w$!~_-@Tg)mbiVpTcSr0t1CV7OL8(& zQJTG9tnaU6L>qr0k7nc4Uy$yB?zCMKF&9N1J|Vb(oXFYwiuF8cvKrRLf?X{D;at6I zpqz(1)??KcRDiRortjidun`e=L&t)-;qj|X2|3Ls5ByM-{VpIpT*;h2&?y^zZ+ULmEmDCIlq1fA);^xGx&dnQs=#t z@NaQ=cR6@?evtKLbzr&JPKgTgX*@1zV{p)9s=lH4q%E_sZiCrrmdVhQH z-hWnp2@COgBBa>eHx6I7>WfktimG1(EFX6p#JKYTK59%d`*}-tq^2m!NViNaakumt zuirUkh~14bE+sr0RC-i;^k%1HQExfXXQL-4WriED^N{*iM(TD=qRCO0e|PnajJ-P2 z!i^A}3d>%8lJHhC2AfaT&s$ERf

SoD%4GH#{A#e-t~04tuy$l{K$W7NL>0QPzlj28v0;u8aX{N`^Z8bU z!KDyPgb`+x-fqxL_dPeKg&n4+58K|%(I#0;>HN$cY}~-M-0Wa46*&?A^@V$V2l;8Uc}nvSnkd|F&5S(z+^FS(bQxN_m~q${V89!<1pVBIx8Uq|*4Z zN@wwRxTSN9EI~IhIAJ8n8VasA^S!MCd2lrbQJ1hUqlumCWYqnE4eWGr9!?5!$#zSi zHyka?C6LMP-ShOi`*(cv2{p~z=llo`^#zwtE{_?`9g;N-x7##6t^P$HIxR|%OJDQ* z!{jF&x2VQJ$x>IcK~)&}C$n zek7?`swp`x-$)91@7|+V6&o?BU(;PsD6>1rPY+=Tqf^XIpOF$Kr7B#k>NXH~0ipx3 z)c^RjO8;v(Sx57ZpARMBC&S2a3&*GFc?E~p-Po>ICkiJ!$DV!S0I9+-+1Bem!oI!> zT<3!sYrCT*9V*+=8(lfk1^#c>rwjhSp$nnk`@kdsbN43UF>0emb`g<&>i8TI>fAlt z*BP~pSTvj(vYKX)$e-58`_^A@4uH6OnImPT?p5tK%bbqiZ;uLX&~*X6y58Qw;)F`= zJ($MF6NdgL9v+_x5(rmYomD4QN^)9%kQ5wYqgRw&wj@m59`-am0@Akl zhd6oO_qX_V=-cD76}kzHWW{p z)%h#81=CGJ6S>J6qAQQ(U=~r;%}j84C>x>WJeQ)kLhfAQaTC%M<)n2)IR| zX8OHkNEMv7eBnugrnaU$@A_e<_xxs&{|HNw`JiL8v5N z(1B8^<<%T@Z}lgw%Ji+X;_h6OYe?QdNk`;@NwbYe{A}}8Dl>JhXPrL|cjo=Xx-iK- zyH-hFimyuuko6DtDC$8Kidv^n)g>-fW2ySqGT~vS#)J*3?mwO ztZyNfI7}jR;!2{&jihwM=Vb0-wBA9~LKqf|3Y1v*Nlgw*#Ho>IqSLFvL?yG-dZHBv z?mu!Z7aT%}&D0aNIs4OW<~<*+tvQAH#oIjXJm9z2c1LcY3U;;e^0CoM0P^~9W$5wp z`mmeo?O`vMVd^g|IsM&`P%tkaQ%;Z!shDACru8RZc3NRQ?upFSSG*vJ-ffyc1K)dC zC+v(Q^1O0RzrFlo2duj?Go$q>o@eGMwG*johC8}rRIgA9EP}Bm)Py=M(LLqm!sh5m zH(KLfieZgWfr*k+r6?fCM$7p{Npg2Kz&tV4I$gXvckXguXcOiHEsv2-AJwz0NE>{S zx4xkH#c5vRid?W0t2mo5PAqemYO{HLG~6%tmzmE8uT^V@Etz~ih5=gB0R`w4I8nuy zZ*_h)>XPr+I}(foS>Te7@|BSLEcZ6Sd?l2=ChBi~-r;Wx`>t@wKmGlE;7XgH%QF!( z)H*&K4#OF&KW5UwdH`~YWlJhqOp%o7L}h6*0>cG+Q_~v{hXv356-tJb6rqFO2q`&& z%pZagS*mh;Q-{Ivuj2T7`)HZMhDJshd=8_+&328A;>q#VA<0c~Mf&II5iB4(vrmbs zy7De&8@cwr=KZwM7T@UNU#{#B3OatH+ZmX(-tNnF{xZQC@Fp%WwZ@QmfAp0y)G#^q z9)rQBii+Pmxgm~apz;q$IaSbo1Y3D2)CUi2NHA^K;>?*)$3KtgC0EX1r#+xjjiqmP zTx4wyuakRV*JtP=WACNna?!KQC4XPbBlo%J`Ky5WWM2027W1I*Dmtpetlx<~WlcRN zE(|1UHl8be3Fvp#?bjI?3 zRhGL-)XtB%^!o1$ZA-&YCCg<4;v|qJ-b7)rhc(=y&6inQH_it4+Ut&s`7-2grJawM7_#V3p|Ye zLsa=}lJfKcyK<{mK10%uk1H6XGF}5N1P&gcwRxRZvX`c+%1O)QKd!SzCI)uy%(r3@ z=&z2hIl2~h$o>_)C#*6rTf|u*9#8ocBIspF@5(gA{$x#O6FV-CrhW4~OX)JI>M+i+ zSi0ejE8eQdVb-Lrp#P8Kxglw;YQJJev4asJ5X)X{A0*OZJ}h94sIL2ZwvstlEm1J0 z|GV}VK_v`<<`MhM3J2er`Zlpur3Ng4Ml9$?65+?2u89Sp`&k8~?T7R8AFXdylB+8> zgJ=DWeVi|zS7P0mmNJU8c1HuJ&uzfZ=P&COTB92tITM0H&&`BIM~9d)HCX}{ZbooY z$={L8o-gS^+`kYHa>%i7XV51Y1*xzUgevrLnayfe+iofjqqUGDq?h{Toir1!U=<9XF+JR8zY4 zUm&eeS7di67U(XhcPhP5po?Rqiykck`*w;&QdYCo>Yk1~HD5I)$P`|6ZRIgM9@v&ns0Tb-`GB0t;6&Ou9d>1%Ke-RA?WWym{HnK;G!u z)R(JTej7H{uX>&&t%5T6_j6>iqJ?A6LbTH4SNz4U>Fz|Fk!`l$!eXs)Lzsk}{fpRA z6E9qzO`FQtd((P|rINuJFq_UPi)9UIQX&&}#DDPrJglcff#mmW6p&4H7iF5vbtvQX zV5E489#HfCWv+~Tm+<$vfsxf#=th21o{XxNC`>wJ!$)dt)5H`1?TVAmn~qoVp*E}q zJ&@P*6eB0YS>ZRHLgaX5ox$L7^Ud-SU^#96^@;A5xI|aW9dA-@c;;u)qe2!VSt5pF zQ{Ks@Kkc$Hqy+%uxNwq^Fiw{y>Up7su(f5A<-=G{na?XnO*oWSe^VK^xSLj@qRRCB z=TYgJwrdki7;4OH<4Z{SjA`jUb!9RRo5&n@zW78+LifkRQLsE)rjI>9=Gvr`Zso-x ztqY<4VF2+57UWP{g-iKJ0`GOfC_#8sDCP(;-`khE0VXKXn8hz9x%1iM-;_@qJA-VM zj`QqS{-Vf6u-gl)SP`s$5bDi;X$KVEXsbEkcdgIi-R--mxAgFBk}%W4z9U_}TslI} zdOGwk;Nve8N|;6Y_i@!*39d8ItKID^bcRohB2JlpsG25FR$hFcA}-t9(cla8Jbm0C z7tc|?UnqM{F-8cnIZ3_EmN&Z9+4w7Fe%fv0AijbwAJ+MMJXw#lDb{>dg_^K6I|KLc zAKty@kV3p{7vm@0^izh*%2-o$c>RG-U(sW7W~5%pmnk}b^e10dDs8dn2V6q~xaSBq zF#Qis^}RBNHbWiHVfqc@L6?L>=%C6AbXF$AdMY4Km9qM;5Qr&D)rYr3#Fl&#%4qfk zs`TX7ztqCATPk;;G8i$Es`Z#D3JI#ro1;u$iIa5Q%^9sB4BQ6x=p>gYv#k2o+Grb^ z?)bae-1gD~zETEBKD}a6HHjUlF$!pC&Su|S9K_ZVjM6WJXqTU@g*&<=(*(iIuKZZn=xbG~Cj&&`IM>AW#Xk01}dh-NneO{q-BwVJ_8X#6= z-R0An6B5Bj3rQ2=8V*5`nUGIRSzSK5^No-By2;+U82!TLUeQcnDo2r)ZJEz-P2h`< ze!Gw^L;26JLR8^4uy&{MyjX zgy7L+tkc5#Sv;GU(!Gb5^89+EGeEdZQW~p4&%JDXWjU-FzewOAjwPja12fb$CC1)0 z%L%PTKA!E=W{JP?zGkBSIZgF#O`t)18%aD+hgl>7ryeBFG~p>zYEtFDW8IMURZKSC zR(o+(%D#@gm}|&TfauNO`x)i=hXHv68|K5i{)}o_I@XEQ3dw3LTrV08C#IQWPCB`o zU=tk-5Z>=;`w(xgQA^m7G6uyP*Yjb>C|}vIVMD z8DqF&$P*veKS%%~;u{^#O506;ee!-XY%1o_2Gl~9nFMc3wTsBF4@OnyWhhqkp4{e6 z4+nG%%g8(`1Vi?*1vvN!Fi#(s;$Aw;+B+-~>!qE{2A@LMvobWkGfLA6M5E$yVObW5 z@3YIRd;?D4(H|y2lu#qlqEP70qjY`x7wIj#Uxh@r6Q}w;sz3^~CYyY;$)VrXSt=^< zUfJr^+>Mu;J+tzO6ht4ujfdH$HdR=xQB3jG6)a8=rjEBIQMt~)|8`{MzWyrhvcJ(I z8bG|m#&v-c6ZRK}mr&c(}*UoAP7L zv+`W4$OC3gKq)6_d3tM1o`^(04T-co5=)vfbF&4=)$1!V6GF8ckN;R7Y)Yw~FEaJe z{t{52UEm|~AxQzGd5zNkr4L=<-D*(uU)rk8=L-qOFA}C|wyqm25eP~BICqsAOnI1? zHkvnuqw*r*{%@FsWxLp_BL~H8k*<;$8_{0_vaRv^_a(Yay4e+?t41%#{2YGT{XOzo zd4mIiT{`pRUqYHWDY;mL)6MYC9390X%3$y6xEjp6JH}YYx7V)6u{Xl7JMmrA?<61Rr!oygEN=tg*`iZnmFZ13raAt z=qudUVIvi+q>)|Ng#sd@z=hfm!^*BI?BGmnx@nQq(Tdc_-Q{h3x;!;Vbk2MB@xvFN z`u1|sbuIdy@*PcfOcuU=*cV|aV)PW_hY*Mfku!W}Qyutls=P~X`M!lTo1;n`)52)( zzhjBisIUvQz=y<_P)GOdqRDFNWKNOE?-!~5WzGyuvHhkZsl-Yw^8#)W4*6DKZDj#^ zZ!HqqH;G77_xDq1vCWRg>HtDCPi&e38=oS5Mll|5KMweMD?ha&kENG>0YnQ`i|Q-fFzVa_p3PImx3hx1RD# zlrxW5=zWHw3f9V7e&LM;O2JuTp&e2QM{Tq>+G}{}0?3~J|BZAEO z)FS<&;6+wD4$Y1d`IvJIrC%mhZgef4#?1{ZIswe=^Ap-sQ%g(ohQOxES=MEmXcE(Q zje@1&NipLz9@v*9`cH@m!8X&NYWw6(`6&NQho)bKloapiAe1Jt?3}gi@$^lp^w~ph zeNNIZSg9SS4jJfek61VvN1tM9`b83rkeSMntbj2`LAr;%>nD=|6eBAw`KXXA^1b`s zBs~AwI`v28W~!edstEw)Lmm)eIE{#I@C14U5(Nt`z>_uBi8DNb5w&bNd`O<7K|m3+ zG2GwpeaP5Y_gnkZz}At{z>IBlTN*jZnB1DSvbhB0;{t^$tEDu4rUEWR_UF(2-fG_o zb)s~2G6`q;Bb1)fuw54Q8Vf1+k2S{8xE9|Gq6bI5degEP!F)&_OLDMza|7Y%_A3N;`etSPL!QU;ehBety+%9K$jRpl^tAaIxB|zLLjT&K|vX$cg zZ=;3$uznn($328m$7uM~L&#VprePHI}OAQlV?FH;Y*Z;1U{!g$6Wum2JZRN&yG~PRq zh5~Ap=G6uj1>CHG#9TK08Q1O*cdLL!S5Iv}$Qf`R`;HwURj8N(2hO?(b#=t;vZOb) z1RP3#97&v|r_pyH__hL^tyvyB^(b~~Xlv=BNLWx9~@>)7jFNKXk9v ziBT(V;F+#OJQN~t0eYSMIi^^6o zeJE|>);ulgpLmz$BzArQ00HBV#uGz8y60?SPt8cqp~5}&)4*PLuDAuJb zs^f6IQphshfk1$ukD4?B4_zrBOkJy0H439)u*Q5tyx^>_tg}Tm z8+M}!Kzf`7KKa-AZ}*fW97%bqqq@MZlpgO9zo`^-Zj%*ygzw53!eEY-M_90&^DIDzL3hODk9juF=#34d@Q6HmA2!)Bs=~XY`KwO#BO*((kE_1c zGOGHKuPZk!TSB+{D`)owk}>>`mq_6ruNuB3V9iDrMeIfz(b!@yO1DTOA0_})k8AlI zyw?x;G!&0h6XKMQfC$9k1XAdlMH;z0;e-W`$q(ec{vqALf88$~$bDTb9f%=3F*pQe z253Gw%a(}%9&~oxEq=RJy0%|_-Z9;AwW#OTZqjJd)h%z;^QpM>-El1Zdhn$=&1k1$ z2r>jH_p{n*VL|HdxTVpQ!y3|PO8u%Y3)1q+VWC6gll5&eYQ1U$AFD4DLQ4kH7hBfk zv%VG641a;ef#|Q!IGzlp*Uu|x%4YjHjM|B@49&s6U(%1g=T>#MOeBL?p=DNfAXXwf zE@;=UM;XPNElpT;gz_OT$BJ)DKz+JyA*l$ylL8vi@ab@b2)z4~T5f4)te8STeCso( z_1?9(!}HTsPM?Dow>`Ch>ly7XkwPbqHowd5lDkfsA}5e?_wrqLs_4ZL%|joqxYy zJGE(NZ);CMTI~&&fG_Q!OMd2cz=Lqw_@~`vDf4zXQ;w4`OJ&>~y7YC=?OJ|Xe#JYp z0V?jurJT_VqU-a5sDP7zYybJo91DFENBqD&;5hu)y;WJbR@q7E&)%vy*O%@Tl(VA1 zcDysB+u$Yg=})*p7BK|0)V2iSV!H$zW1Ux4bRoqc;-rcsXkXC6HwYMCFx??tksSY( z$oGF9y!$qm+aq5NirqJKAcx05hR}&|kQ$c%xtVt0LBf28^T{aSsftfE-r&9)TDFc9 zU3UtE^gJdYFSX$a4mH@{#XLhjX#Ck@=hd12MN`bU18f|*Uu$LLcjiWdoSrz)=F8&n z+t3c!_3GFn34ku&A`$=(@bzri_83Qi4_q9v{hB23KpYExEADvae*)n^PCk5}N5CQj zV6R8>?jOW;pu2ej53|U#rSBwS?sqK+?;R_|!5MO7Y8W}YnD>~6=wFAe;C9>>t_#D3 zy%1ApY#o02mp}N$?%HWcp-23PxSMr2G;sD2$cWhA^g`YT!d7W~<|6}+`P;{H^`Yu_ zYEa?8D>;9tTE}5w9`_yshJBT{em}MjgN~{NBDTcAd@#3;o9aO5>iW6t8B3t|qZbEk z#px^Z1mXm*CBUqm2aq8);Ik-Ab$k%asMuE^`Uo942g^Ig9ol7Hopg);399~ z)#3)g(_3w$fVQhSFT|}j7~}^%;4o|qaH#VH?$!dJ;kd0{8{r)=(7Js)qN&4D3`POC z-xq%vOCq{EBDoHH=+1*%->He;e-AkS(Y^^E34B=VfC>ZP=aGTP1jLXRd~O`p)d3w| zznu4Sgz<~}uH6@XIN1|}PxpZWE-=@`9uRr(0qub8aYuNk7jhVIe-e0s;158=AaA^4 z^AJ;WksN;ghscMcGUPgJ=)2gJEnK`6dWIN;BF}K!q3eNnfQJ*cjvFY)wGgQ74AFPi z)**U>+p(v)$0xSoe@f$n9EaoyX(Q*aiaR#WkX;WQcbbf1_q6MQwXS>G$nE}sGm^lg z4&(tc&mV{xE%dDOS%CWvDvn}LCo08La9Dt{2Q6|XH5RAm&tEi58cgbJ?|f&b`yfpz z#4E|S;hJWOp;42hRP3+bPyW0|%ZbJ4m1NJ>`!#uRw=CZNK+*ox>9PF5>H-75yS}mR z`MZm{>t%g^i}_K(0n0{;m7Bk+&FKLY;<{3Gy>z&`^2 z2>c`PkH9|y|6dWfpB`JS{X!Mt@~j<6PKV=ZZ*#FKDVazMMtAvwA1 z@>WvP8E<99-R4b45RU3ANnog*c}!?o)CST$7mOzPre~x1Z~rK~b>-YI81w%t1phkw zkH9|y{|Nje@Q=X%vjiIZFV&a=+s( zf(9=6ptTqGc`mvJW|hqwv!1{`y+W4X2FgvhYonCKJq04KOV+ww4912ZH|ww10XhS< zSQM+!ZzYIQqz>dQ0QLs{$6+FL_vMXcYG1)@!(H`$z@+{D@py&iIDQMaAah zPvf*{sBDyj^?&hNnTQF_PfuE#ytu^lAn*~NZVk{g3N$J`M#3{dY_ok}#7=)-@zP?> zM&SXxZfBfoJ!|UGZ>YZ{DgW=9Fs8cFa}>g7gikkp@hp|DTD{|1pn9YCsTdIS?A8A~ k>h1r&(zG^lwJ>Klcd$}dLdW<|<@2Xq;OYFb??0vg1?HJIU;qFB diff --git a/RecursiveExtractor/Extractor.cs b/RecursiveExtractor/Extractor.cs index 5373ff8c..290b554d 100644 --- a/RecursiveExtractor/Extractor.cs +++ b/RecursiveExtractor/Extractor.cs @@ -61,6 +61,7 @@ public void SetDefaultExtractors() SetExtractor(ArchiveFileType.VMDK, new VmdkExtractor(this)); SetExtractor(ArchiveFileType.XZ, new XzExtractor(this)); SetExtractor(ArchiveFileType.ZIP, new ZipExtractor(this)); + SetExtractor(ArchiveFileType.DMG, new DmgExtractor(this)); if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { SetExtractor(ArchiveFileType.WIM, new WimExtractor(this)); diff --git a/RecursiveExtractor/Extractors/DmgExtractor.cs b/RecursiveExtractor/Extractors/DmgExtractor.cs new file mode 100644 index 00000000..5710f465 --- /dev/null +++ b/RecursiveExtractor/Extractors/DmgExtractor.cs @@ -0,0 +1,107 @@ +using DiscUtils; +using DiscUtils.Dmg; +using DiscUtils.Streams; +using System; +using System.Collections.Generic; + +namespace Microsoft.CST.RecursiveExtractor.Extractors +{ + ///

+ /// The DMG image extractor implementation. + /// + public class DmgExtractor : AsyncExtractorInterface + { + /// + /// The constructor takes the Extractor context for recursion. + /// + /// The Extractor context. + public DmgExtractor(Extractor context) + { + Context = context; + } + private readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger(); + + internal Extractor Context { get; } + + /// + /// Extracts a DMG file + /// + /// + public async IAsyncEnumerable ExtractAsync(FileEntry fileEntry, ExtractorOptions options, ResourceGovernor governor, bool topLevel = true) + { + LogicalVolumeInfo[]? logicalVolumes = null; + Disk? disk = null; + + try + { + disk = new Disk(fileEntry.Content, Ownership.None); + var manager = new VolumeManager(disk); + logicalVolumes = manager.GetLogicalVolumes(); + } + catch (Exception e) + { + Logger.Debug("Error reading {0} disk at {1} ({2}:{3})", fileEntry.ArchiveType, fileEntry.FullPath, e.GetType(), e.Message); + } + if (logicalVolumes != null) + { + foreach (var volume in logicalVolumes) + { + await foreach (var entry in DiscCommon.DumpLogicalVolumeAsync(volume, fileEntry.FullPath, options, governor, Context, fileEntry, topLevel)) + { + yield return entry; + } + } + } + else + { + if (options.ExtractSelfOnFail) + { + fileEntry.EntryStatus = FileEntryStatus.FailedArchive; + yield return fileEntry; + } + } + disk?.Dispose(); + } + + /// + /// Extracts a DMG file + /// + /// + public IEnumerable Extract(FileEntry fileEntry, ExtractorOptions options, ResourceGovernor governor, bool topLevel = true) + { + LogicalVolumeInfo[]? logicalVolumes = null; + Disk? disk = null; + + try + { + disk = new Disk(fileEntry.Content, Ownership.None); + var manager = new VolumeManager(disk); + logicalVolumes = manager.GetLogicalVolumes(); + } + catch (Exception e) + { + Logger.Debug("Error reading {0} disk at {1} ({2}:{3})", fileEntry.ArchiveType, fileEntry.FullPath, e.GetType(), e.Message); + } + + if (logicalVolumes != null) + { + foreach (var volume in logicalVolumes) + { + foreach (var entry in DiscCommon.DumpLogicalVolume(volume, fileEntry.FullPath, options, governor, Context, fileEntry, topLevel)) + { + yield return entry; + } + } + } + else + { + if (options.ExtractSelfOnFail) + { + fileEntry.EntryStatus = FileEntryStatus.FailedArchive; + yield return fileEntry; + } + } + disk?.Dispose(); + } + } +} \ No newline at end of file diff --git a/RecursiveExtractor/MiniMagic.cs b/RecursiveExtractor/MiniMagic.cs index 0c1544b3..932ac5db 100644 --- a/RecursiveExtractor/MiniMagic.cs +++ b/RecursiveExtractor/MiniMagic.cs @@ -81,6 +81,10 @@ public enum ArchiveFileType /// VMDK, /// + /// A DMG disc image. + /// + DMG, + /// /// Unused. /// INVALID @@ -117,6 +121,22 @@ public static ArchiveFileType DetectFileType(Stream fileStream) } var initialPosition = fileStream.Position; var buffer = new byte[9]; + // DMG format uses the magic value 'koly' at the start of the 512 byte footer at the end of the file + // Due to compression used, needs to be first or can be misidentified as other formats + // https://newosxbook.com/DMG.html + if (fileStream.Length > 512) + { + var dmgFooterMagic = new byte[] { 0x6b, 0x6f, 0x6c, 0x79 }; + fileStream.Position = fileStream.Length - 0x200; // Footer position + fileStream.Read(buffer, 0, 4); + fileStream.Position = initialPosition; + + if (dmgFooterMagic.SequenceEqual(buffer[0..4])) + { + return ArchiveFileType.DMG; + } + } + if (fileStream.Length >= 9) { fileStream.Position = 0; diff --git a/RecursiveExtractor/RecursiveExtractor.csproj b/RecursiveExtractor/RecursiveExtractor.csproj index 6a73cb28..ecc1637d 100644 --- a/RecursiveExtractor/RecursiveExtractor.csproj +++ b/RecursiveExtractor/RecursiveExtractor.csproj @@ -27,6 +27,7 @@ + From 8490639aa1ded1b132d560f57db86f789118ca6d Mon Sep 17 00:00:00 2001 From: Gabe Stocco <98900+gfs@users.noreply.github.com> Date: Thu, 25 Jan 2024 16:43:24 -0800 Subject: [PATCH 13/14] Update README.md --- README.md | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index bea11e15..a23ced16 100644 --- a/README.md +++ b/README.md @@ -7,17 +7,18 @@ Recursive Extractor is a Cross-Platform [.NET Standard 2.0 Library](#library) an | | | | |-|-|-| | 7zip+ | ar | bzip2 | -| deb | gzip | iso | -| rar^ | tar | vhd | -| vhdx | vmdk | wim* | -| xzip | zip+ | | +| deb | dmg** | gzip | +| iso | rar^ | tar | +| vhd | vhdx | vmdk | +| wim* | xzip | zip+ |
Details
* Windows only
+ Encryption Supported
-^ Rar version 4 Encryption supported
+^ Encryption supported for Rar version 4 only
+** Limited support. Unencrypted HFS+ volumes with certain compression schemes.
# Variants @@ -25,9 +26,9 @@ Recursive Extractor is a Cross-Platform [.NET Standard 2.0 Library](#library) an ## Command Line ### Installing 1. Ensure you have the latest [.NET SDK](https://dotnet.microsoft.com/download). -2. run `dotnet tool install -g Microsoft.CST.RecursiveExtractor.Cli` +2. Run `dotnet tool install -g Microsoft.CST.RecursiveExtractor.Cli` -This adds `RecursiveExtractor` to your path so you can run it directly from the shell. +This adds `RecursiveExtractor` to your path so you can run it directly from your shell. ### Running Basic usage is: `RecursiveExtractor --input archive.ext --output outputDirectory` @@ -57,7 +58,7 @@ Run `RecursiveExtractor --help` for more details. ## .NET Standard Library -Recursive Extractor is available on NuGet as [Microsoft.CST.RecursiveExtractor](https://www.nuget.org/packages/Microsoft.CST.RecursiveExtractor/). Recursive Extractor targets netstandard2.0+ and the latest .NET, currently .NET 6.0 and .NET 7.0. +Recursive Extractor is available on NuGet as [Microsoft.CST.RecursiveExtractor](https://www.nuget.org/packages/Microsoft.CST.RecursiveExtractor/). Recursive Extractor targets netstandard2.0+ and the latest .NET, currently .NET 6.0, .NET 7.0 and .NET 8.0. ### Usage @@ -77,8 +78,7 @@ foreach(var file in extractor.Extract(path))
Extracting to Disk
-This code adapted from the Cli extracts the contents of given archive located at `options.Input` -to a directory located at `options.Output`, including extracting failed archives as themselves. +This code adapted from the Cli extracts the contents of given archive located at `options.Input` to a directory located at `options.Output`, including extracting failed archives as themselves. ```csharp using Microsoft.CST.RecursiveExtractor; @@ -166,12 +166,12 @@ catch(OverflowException) RecursiveExtractor protects against [ZipSlip](https://snyk.io/research/zip-slip-vulnerability), [Quines, and Zip Bombs](https://en.wikipedia.org/wiki/Zip_bomb). Calls to Extract will throw an `OverflowException` when a Quine or Zip bomb is detected and a `TimeOutException` if `EnableTiming` is set and the specified time period has elapsed before completion. -Otherwise, invalid files found while crawling will emit a logger message and be skipped. RecursiveExtractor uses NLog for logging. +Otherwise, invalid files found while crawling will emit a logger message and be skipped. You can also enable `ExtractSelfOnFail` to return the original archive file on an extraction failure. ## Notes on Enumeration ### Multiple Enumeration -You should not iterate the Enumeration returned from the `Extract` and `ExtractAsync` interfaces multiple times, if you need to do so, convert the Enumeration to the collection of your choice first. +You should not iterate the Enumeration returned from the `Extract` and `ExtractAsync` interfaces multiple times, if you need to do so, convert the Enumeration to an in memory collection first. ### Parallel Enumeration If you want to enumerate the output with parallelization you should use a batching mechanism, for example: @@ -208,7 +208,7 @@ while (moreAvailable) ``` ### Disposing During Enumeration -If you are working with a very large archive or in particularly constrained environment you can reduce memory/file handle usage for the Content streams in each FileEntry by disposing as you iterate. +If you are working with a very large archive or in particularly constrained environment you can reduce memory and file handle usage for the Content streams in each FileEntry by disposing as you iterate. ```csharp var results = extractor.Extract(path); @@ -217,7 +217,7 @@ foreach(var file in results) using var theStream = file.Content; // Do something with the stream. _ = theStream.ReadByte(); - // The stream is disposed here from the using statement +// The stream is disposed here by the using statement } ``` @@ -229,11 +229,11 @@ If you are having trouble parsing a specific archive of one of the supported for # Dependencies -Recursive Extractor uses a number of libraries to parse archives. +Recursive Extractor aims to provide a unified interface to extract arbitrary archives and relies on a number of libraries to parse the archives. * [SharpZipLib](https://github.com/icsharpcode/SharpZipLib) * [SharpCompress](https://github.com/adamhathcock/sharpcompress) -* [DiscUtils](https://github.com/discutils/discutils) +* [LTRData/DiscUtils](https://github.com/LTRData/discutils) # Contributing From 6ed0118a5b7575e21fd531617993ad950edca67c Mon Sep 17 00:00:00 2001 From: Erik White Date: Sun, 28 Jan 2024 00:58:50 +0100 Subject: [PATCH 14/14] Update DiscUtils with Path.Combine fix --- .../RecursiveExtractor.Tests.csproj | 8 +++--- RecursiveExtractor/RecursiveExtractor.csproj | 28 +++++++++---------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/RecursiveExtractor.Tests/RecursiveExtractor.Tests.csproj b/RecursiveExtractor.Tests/RecursiveExtractor.Tests.csproj index 40033e43..1ff5e559 100644 --- a/RecursiveExtractor.Tests/RecursiveExtractor.Tests.csproj +++ b/RecursiveExtractor.Tests/RecursiveExtractor.Tests.csproj @@ -9,10 +9,10 @@ - - - - + + + + diff --git a/RecursiveExtractor/RecursiveExtractor.csproj b/RecursiveExtractor/RecursiveExtractor.csproj index ecc1637d..dc710e4d 100644 --- a/RecursiveExtractor/RecursiveExtractor.csproj +++ b/RecursiveExtractor/RecursiveExtractor.csproj @@ -25,20 +25,20 @@ - - - - - - - - - - - - - - + + + + + + + + + + + + + +