diff --git a/DocumentService.Application/Common/DTOs/SwissQrCodeExtractionResult.cs b/DocumentService.Application/Common/DTOs/SwissQrCodeExtractionResult.cs index ff6e7ab..dab4c65 100644 --- a/DocumentService.Application/Common/DTOs/SwissQrCodeExtractionResult.cs +++ b/DocumentService.Application/Common/DTOs/SwissQrCodeExtractionResult.cs @@ -32,6 +32,10 @@ namespace DocumentService.Application.Common.DTOs; /// } /// public record SwissQrCodeExtractionResult( +#if NET SwissQrBillDto Bill, - IReadOnlyList RawLines -); +#else + object? Bill, +#endif + IEnumerable RawLines +); \ No newline at end of file diff --git a/DocumentService.Application/DocumentService.Application.csproj b/DocumentService.Application/DocumentService.Application.csproj index 30daa7c..4995a70 100644 --- a/DocumentService.Application/DocumentService.Application.csproj +++ b/DocumentService.Application/DocumentService.Application.csproj @@ -52,10 +52,8 @@ - - diff --git a/DocumentService.Application/ExtractZugferd/ExtractZugferdCommand.cs b/DocumentService.Application/ExtractZugferd/ExtractZugferdCommand.cs index ae5de70..a152173 100644 --- a/DocumentService.Application/ExtractZugferd/ExtractZugferdCommand.cs +++ b/DocumentService.Application/ExtractZugferd/ExtractZugferdCommand.cs @@ -18,6 +18,7 @@ public record ExtractZugferdCommand : IRequest public required Stream PdfStream { get; init; } } +#if NET /// /// Handler for ExtractZugferdCommand. /// Extracts ZUGFeRD XML from PDF and returns XML content @@ -77,6 +78,7 @@ public class ExtractZugferdCommandHandler( }; } } +#endif /// /// Validator for ExtractZugferdCommand. diff --git a/DocumentService.Client/Clients/PdfAttachmentClient.cs b/DocumentService.Client/Clients/PdfAttachmentClient.cs index 21bb9f5..b6be48f 100644 --- a/DocumentService.Client/Clients/PdfAttachmentClient.cs +++ b/DocumentService.Client/Clients/PdfAttachmentClient.cs @@ -1,3 +1,4 @@ +using DocumentService.Application.Common.DTOs; using DocumentService.Client.Interfaces; using DocumentService.Client.Models.Requests; using Microsoft.Extensions.Logging; diff --git a/DocumentService.Client/Clients/PdfValidationClient.cs b/DocumentService.Client/Clients/PdfValidationClient.cs index bb2a179..06efa87 100644 --- a/DocumentService.Client/Clients/PdfValidationClient.cs +++ b/DocumentService.Client/Clients/PdfValidationClient.cs @@ -1,3 +1,4 @@ +using DocumentService.Application.Common.DTOs; using DocumentService.Client.Interfaces; using DocumentService.Client.Models.Requests; using Microsoft.Extensions.Logging; diff --git a/DocumentService.Client/Clients/SwissQrCodeClient.cs b/DocumentService.Client/Clients/SwissQrCodeClient.cs index ada933d..8454ba8 100644 --- a/DocumentService.Client/Clients/SwissQrCodeClient.cs +++ b/DocumentService.Client/Clients/SwissQrCodeClient.cs @@ -1,3 +1,4 @@ +using DocumentService.Application.Common.DTOs; using DocumentService.Client.Interfaces; using DocumentService.Client.Models.Requests; using Microsoft.Extensions.Logging; diff --git a/DocumentService.Client/Clients/ZugferdClient.cs b/DocumentService.Client/Clients/ZugferdClient.cs index b7f1589..190adef 100644 --- a/DocumentService.Client/Clients/ZugferdClient.cs +++ b/DocumentService.Client/Clients/ZugferdClient.cs @@ -1,3 +1,5 @@ +using DocumentService.Application.Common.DTOs; +using DocumentService.Application.ExtractZugferd; using DocumentService.Client.Interfaces; using DocumentService.Client.Models.Requests; using Microsoft.Extensions.Logging; diff --git a/DocumentService.Client/Interfaces/IPdfAttachmentClient.cs b/DocumentService.Client/Interfaces/IPdfAttachmentClient.cs index aeecee6..b6e6b0a 100644 --- a/DocumentService.Client/Interfaces/IPdfAttachmentClient.cs +++ b/DocumentService.Client/Interfaces/IPdfAttachmentClient.cs @@ -1,3 +1,4 @@ +using DocumentService.Application.Common.DTOs; using DocumentService.Client.Models.Requests; namespace DocumentService.Client.Interfaces; @@ -60,30 +61,4 @@ public interface IPdfAttachmentClient /// Modified PDF as stream [Obsolete("API endpoint not implemented yet")] Task AddAttachmentsAsync(byte[] pdfBytes, List attachments, CancellationToken cancellationToken = default); -} - -/// -/// DTO for attachment check result -/// -public record AttachmentCheckResult -{ - /// Whether the document contains any embedded file attachments. - public bool HasAttachments { get; init; } - /// Number of embedded file attachments found. - public int AttachmentCount { get; init; } - /// Metadata for each attachment found in the document. - public List Attachments { get; init; } = new(); -} - -/// -/// DTO for attachment metadata -/// -public record AttachmentMetadata -{ - /// Name of the embedded file. - public string FileName { get; init; } = string.Empty; - /// MIME type of the embedded file (e.g. "application/xml"), or null if unknown. - public string? MimeType { get; init; } - /// Size of the embedded file in bytes. - public long Size { get; init; } -} +} \ No newline at end of file diff --git a/DocumentService.Client/Interfaces/IPdfValidationClient.cs b/DocumentService.Client/Interfaces/IPdfValidationClient.cs index fa1cd98..d447242 100644 --- a/DocumentService.Client/Interfaces/IPdfValidationClient.cs +++ b/DocumentService.Client/Interfaces/IPdfValidationClient.cs @@ -1,3 +1,5 @@ +using DocumentService.Application.Common.DTOs; + namespace DocumentService.Client.Interfaces; /// @@ -36,40 +38,4 @@ public interface IPdfValidationClient /// Cancellation token /// PDF/A validation result with conformance level and errors Task ValidatePdfAAsync(byte[] pdfBytes, CancellationToken cancellationToken = default); -} - -/// -/// DTO for PDF validation result -/// -public record PdfValidationResult -{ - /// Total number of pages in the document. - public int PageCount { get; init; } - /// File size in bytes. - public long FileSizeBytes { get; init; } - /// PDF specification version (e.g. "1.7"). - public string PdfVersion { get; init; } = string.Empty; - /// Whether the document is password-protected. - public bool IsEncrypted { get; init; } - /// Whether the document contains embedded file attachments. - public bool HasAttachments { get; init; } - /// Number of embedded file attachments. - public int AttachmentCount { get; init; } -} - -/// -/// DTO for PDF/A validation result -/// -public record PdfAValidationResult -{ - /// Whether the document is fully PDF/A conformant. - public bool IsValid { get; init; } - /// Detected PDF/A conformance level (e.g. "PDF/A-3b"), or null if not a PDF/A document. - public string? PdfAVersion { get; init; } - /// Total number of pages in the document. - public int PageCount { get; init; } - /// List of conformance errors found during validation. - public List Errors { get; init; } = new(); - /// List of conformance warnings found during validation. - public List Warnings { get; init; } = new(); -} +} \ No newline at end of file diff --git a/DocumentService.Client/Interfaces/ISwissQrCodeClient.cs b/DocumentService.Client/Interfaces/ISwissQrCodeClient.cs index 28bcfaf..f604c50 100644 --- a/DocumentService.Client/Interfaces/ISwissQrCodeClient.cs +++ b/DocumentService.Client/Interfaces/ISwissQrCodeClient.cs @@ -1,3 +1,5 @@ +using DocumentService.Application.Common.DTOs; + namespace DocumentService.Client.Interfaces; /// @@ -24,13 +26,3 @@ public interface ISwissQrCodeClient Task ExtractSwissQrCodeAsync(byte[] pdfBytes, bool raw = false, CancellationToken cancellationToken = default); } -/// -/// DTO for Swiss QR Code extraction result -/// -public record SwissQrCodeExtractionResult -{ - /// Parsed Swiss QR bill object. null when raw=true was requested. - public object? Bill { get; init; } - /// Raw QR code text lines. Populated when raw=true was requested. - public List RawLines { get; init; } = new(); -} diff --git a/DocumentService.Client/Interfaces/IZugferdClient.cs b/DocumentService.Client/Interfaces/IZugferdClient.cs index bbc827d..c6735cd 100644 --- a/DocumentService.Client/Interfaces/IZugferdClient.cs +++ b/DocumentService.Client/Interfaces/IZugferdClient.cs @@ -1,3 +1,6 @@ +using DocumentService.Application.Common.DTOs; +using DocumentService.Application.ExtractZugferd; + namespace DocumentService.Client.Interfaces; /// @@ -53,27 +56,3 @@ public interface IZugferdClient /// Structured ZUGFeRD extraction result Task ExtractZugferdAsResultAsync(byte[] pdfBytes, CancellationToken cancellationToken = default); } - -/// DTO for ZUGFeRD detection result -public record ZugferdCheckResult -{ - /// Whether the document contains a ZUGFeRD XML attachment. - public bool HasZugferd { get; init; } - /// Detected ZUGFeRD version (e.g. "2.1"), or null if not present. - public string? Version { get; init; } - /// ZUGFeRD profile name (e.g. "EN 16931"), or null if not present. - public string? Profile { get; init; } -} - -/// DTO for ZUGFeRD extraction result -public record ZugferdExtractionResult -{ - /// File name of the extracted XML attachment (e.g. "factur-x.xml"). - public string FileName { get; init; } = string.Empty; - /// Full XML content of the ZUGFeRD attachment. - public string XmlContent { get; init; } = string.Empty; - /// ZUGFeRD version (e.g. "2.1"), or null if not detected. - public string? Version { get; init; } - /// ZUGFeRD profile name (e.g. "EN 16931"), or null if not detected. - public string? Profile { get; init; } -} diff --git a/DocumentService.Tests/DocumentService.Tests.csproj b/DocumentService.Tests/DocumentService.Tests.csproj index f343f00..b07be78 100644 --- a/DocumentService.Tests/DocumentService.Tests.csproj +++ b/DocumentService.Tests/DocumentService.Tests.csproj @@ -41,11 +41,11 @@ - - - - + + + + diff --git a/DocumentService.Tests/Unit/Client/PdfAttachmentClientTests.cs b/DocumentService.Tests/Unit/Client/PdfAttachmentClientTests.cs index 81c9d65..b923fc7 100644 --- a/DocumentService.Tests/Unit/Client/PdfAttachmentClientTests.cs +++ b/DocumentService.Tests/Unit/Client/PdfAttachmentClientTests.cs @@ -1,3 +1,4 @@ +using DocumentService.Application.Common.DTOs; using DocumentService.Client.Clients; using DocumentService.Client.Interfaces; using DocumentService.Client.Models.Requests; @@ -63,7 +64,7 @@ public class PdfAttachmentClientTests { HasAttachments = true, AttachmentCount = 1, - Attachments = new List + Attachments = new List { new() { FileName = "factur-x.xml", MimeType = "application/xml", Size = 512 } } @@ -85,7 +86,7 @@ public class PdfAttachmentClientTests public async Task CheckAttachmentsAsync_Stream_PdfWithNoAttachments_ReturnsFalse() { // Arrange - var expected = new AttachmentCheckResult { HasAttachments = false, AttachmentCount = 0 }; + var expected = new AttachmentCheckResult { HasAttachments = false, AttachmentCount = 0, Attachments = [] }; var (client, _) = BuildJson(expected); // Act diff --git a/DocumentService.Tests/Unit/Client/PdfOperationsClientTests.cs b/DocumentService.Tests/Unit/Client/PdfOperationsClientTests.cs index 9288c15..17aa54b 100644 --- a/DocumentService.Tests/Unit/Client/PdfOperationsClientTests.cs +++ b/DocumentService.Tests/Unit/Client/PdfOperationsClientTests.cs @@ -2,6 +2,7 @@ using DocumentService.Client.Clients; using DocumentService.Client.Interfaces; using DocumentService.Client.Models.Requests; using DocumentService.Client.Models.ValueObjects; +using DocumentService.Domain.Models.ValueObjects; using FluentAssertions; using Microsoft.Extensions.Logging.Abstractions; using System.Net; diff --git a/DocumentService.Tests/Unit/Client/PdfValidationClientTests.cs b/DocumentService.Tests/Unit/Client/PdfValidationClientTests.cs index 761bfa0..5b5d8d6 100644 --- a/DocumentService.Tests/Unit/Client/PdfValidationClientTests.cs +++ b/DocumentService.Tests/Unit/Client/PdfValidationClientTests.cs @@ -1,3 +1,4 @@ +using DocumentService.Application.Common.DTOs; using DocumentService.Client.Clients; using DocumentService.Client.Interfaces; using FluentAssertions; @@ -32,7 +33,7 @@ public class PdfValidationClientTests [Fact] public async Task ValidatePdfAsync_Stream_SendsMultipartPost() { - var expected = new PdfValidationResult { PageCount = 3, PdfVersion = "1.7", FileSizeBytes = 2048, IsEncrypted = false }; + var expected = new PdfValidationResult(PageCount: 3, FileSizeBytes: 2048, FileSizeMB: 0, PdfVersion: "1.7", HasAttachments: false, AttachmentCount: 0, IsEncrypted: false); var (client, handler) = Build(expected); var result = await client.ValidatePdfAsync(new MemoryStream(FakePdfBytes())); @@ -49,7 +50,7 @@ public class PdfValidationClientTests [Fact] public async Task ValidatePdfAsync_Stream_EncryptedPdf_DeserializesIsEncryptedTrue() { - var expected = new PdfValidationResult { PageCount = 1, IsEncrypted = true, PdfVersion = "1.6" }; + var expected = new PdfValidationResult(PageCount: 1, FileSizeBytes: 0, FileSizeMB: 0, PdfVersion: "1.6", HasAttachments: false, AttachmentCount: 0, IsEncrypted: true); var (client, _) = Build(expected); var result = await client.ValidatePdfAsync(new MemoryStream(FakePdfBytes())); @@ -89,7 +90,7 @@ public class PdfValidationClientTests [Fact] public async Task ValidatePdfAsync_Bytes_SendsJsonWithBase64() { - var expected = new PdfValidationResult { PageCount = 1, IsEncrypted = false, HasAttachments = true, AttachmentCount = 2 }; + var expected = new PdfValidationResult(PageCount: 1, FileSizeBytes: 0, FileSizeMB: 0, PdfVersion: "", HasAttachments: true, AttachmentCount: 2, IsEncrypted: false); var (client, handler) = Build(expected); var result = await client.ValidatePdfAsync(FakePdfBytes()); diff --git a/DocumentService.Tests/Unit/Client/SwissQrCodeClientTests.cs b/DocumentService.Tests/Unit/Client/SwissQrCodeClientTests.cs index d252a29..06cf15d 100644 --- a/DocumentService.Tests/Unit/Client/SwissQrCodeClientTests.cs +++ b/DocumentService.Tests/Unit/Client/SwissQrCodeClientTests.cs @@ -1,3 +1,4 @@ +using DocumentService.Application.Common.DTOs; using DocumentService.Client.Clients; using DocumentService.Client.Interfaces; using FluentAssertions; @@ -14,7 +15,7 @@ namespace DocumentService.Tests.Unit.Client; /// public class SwissQrCodeClientTests { - // ?? helpers ????????????????????????????????????????????????????????????? + // ?? helpers ???????????????????????????????????????????????????????????? private static (SwissQrCodeClient client, MockHttpMessageHandler handler) Build(T body) { @@ -26,13 +27,23 @@ public class SwissQrCodeClientTests private static byte[] FakePdfBytes() => "fake-pdf-content"u8.ToArray(); - // ?? ExtractSwissQrCodeAsync (Stream) — parsed Bill ??????????????????????? + // ?? ExtractSwissQrCodeAsync (Stream) — parsed Bill ?????????????????????? [Fact] public async Task ExtractSwissQrCodeAsync_Stream_ParsedMode_SendsMultipartToCorrectEndpoint() { // Arrange - var expected = new SwissQrCodeExtractionResult { Bill = new { Iban = "CH93-0076-2011-6238-5295-7" } }; + var expected = new SwissQrCodeExtractionResult( + Bill: new SwissQrBillDto + { + Version = "V2_0", + Currency = "CHF", + Account = "CH9300762011623852957", + Creditor = new AddressDto { Name = "Test AG", Town = "Bern", CountryCode = "CH", Type = "S", PostalCode = "3000" }, + ReferenceType = "NON" + }, + RawLines: [] + ); var (client, handler) = Build(expected); // Act @@ -48,7 +59,7 @@ public class SwissQrCodeClientTests public async Task ExtractSwissQrCodeAsync_Stream_RawMode_SendsRawFlagInUrl() { // Arrange - var expected = new SwissQrCodeExtractionResult { RawLines = new List { "SPC", "0200", "1" } }; + var expected = new SwissQrCodeExtractionResult(Bill: null, RawLines: ["SPC", "0200", "1"]); var (client, handler) = Build(expected); // Act @@ -59,13 +70,13 @@ public class SwissQrCodeClientTests handler.LastRequest!.RequestUri!.PathAndQuery.Should().Be("/api/pdf/qr-code/extract-swiss?raw=True"); } - // ?? ExtractSwissQrCodeAsync (byte[]) ????????????????????????????????????? + // ?? ExtractSwissQrCodeAsync (byte[]) ???????????????????????????????????? [Fact] public async Task ExtractSwissQrCodeAsync_Bytes_SendsJsonWithBase64() { // Arrange - var expected = new SwissQrCodeExtractionResult(); + var expected = new SwissQrCodeExtractionResult(Bill: null, RawLines: []); var (client, handler) = Build(expected); // Act @@ -83,7 +94,7 @@ public class SwissQrCodeClientTests public async Task ExtractSwissQrCodeAsync_Bytes_RawMode_IncludesRawFlagInUrl() { // Arrange - var expected = new SwissQrCodeExtractionResult { RawLines = new List { "SPC" } }; + var expected = new SwissQrCodeExtractionResult(Bill: null, RawLines: ["SPC"]); var (client, handler) = Build(expected); // Act @@ -93,7 +104,7 @@ public class SwissQrCodeClientTests handler.LastRequest!.RequestUri!.PathAndQuery.Should().Be("/api/pdf/qr-code/extract-swiss?raw=True"); } - // ?? HTTP error propagation ??????????????????????????????????????????????? + // ?? HTTP error propagation ?????????????????????????????????????????????? [Fact] public async Task ExtractSwissQrCodeAsync_WhenApiReturns404_ThrowsHttpRequestException() diff --git a/DocumentService.Tests/Unit/Client/ZugferdClientTests.cs b/DocumentService.Tests/Unit/Client/ZugferdClientTests.cs index cc852c0..f1ec9b8 100644 --- a/DocumentService.Tests/Unit/Client/ZugferdClientTests.cs +++ b/DocumentService.Tests/Unit/Client/ZugferdClientTests.cs @@ -1,3 +1,5 @@ +using DocumentService.Application.Common.DTOs; +using DocumentService.Application.ExtractZugferd; using DocumentService.Client.Clients; using DocumentService.Client.Interfaces; using FluentAssertions; @@ -41,7 +43,7 @@ public class ZugferdClientTests public async Task HasZugferdAsync_Stream_WhenZugferdPresent_ReturnsTrue() { // Arrange - var expected = new ZugferdCheckResult { HasZugferd = true, Version = "2.1", Profile = "EN 16931" }; + var expected = new ZugferdCheckResult { HasZugferd = true, ZugferdFileName = "factur-x.xml" }; var (client, handler) = BuildJson(expected); // Act @@ -49,8 +51,6 @@ public class ZugferdClientTests // Assert result.HasZugferd.Should().BeTrue(); - result.Version.Should().Be("2.1"); - result.Profile.Should().Be("EN 16931"); handler.LastRequest!.RequestUri!.PathAndQuery.Should().Be("/api/pdf/zugferd/has-zugferd"); handler.LastRequest.Content.Should().BeOfType(); } @@ -67,7 +67,7 @@ public class ZugferdClientTests // Assert result.HasZugferd.Should().BeFalse(); - result.Version.Should().BeNull(); + result.ZugferdFileName.Should().BeNull(); } // ?? HasZugferdAsync (byte[]) ????????????????????????????????????????????? @@ -149,8 +149,6 @@ public class ZugferdClientTests { FileName = "factur-x.xml", XmlContent = "", - Version = "2.1", - Profile = "EN 16931" }; var (client, handler) = BuildJson(expected); @@ -160,7 +158,6 @@ public class ZugferdClientTests // Assert result.FileName.Should().Be("factur-x.xml"); result.XmlContent.Should().Be(""); - result.Version.Should().Be("2.1"); handler.LastRequest!.RequestUri!.PathAndQuery.Should().Be("/api/pdf/zugferd/extract?asFile=false"); } diff --git a/DocumentService.sln b/DocumentService.sln index e6213b1..e029e76 100644 --- a/DocumentService.sln +++ b/DocumentService.sln @@ -3,8 +3,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.14.37328.6 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DocumentService.Tests", "DocumentOperator.Tests\DocumentService.Tests.csproj", "{32D2E997-3DA7-4061-8A50-DBB34BBC3E5A}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{3F9E8D8E-1234-4567-89AB-CDEF01234567}" ProjectSection(SolutionItems) = preProject AGENTS.md = AGENTS.md @@ -40,16 +38,14 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DocumentService.Application EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DocumentService.Domain", "DocumentService.Domain\DocumentService.Domain.csproj", "{2F2C937F-3732-4E6C-9720-FAB62DC33C63}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DocumentService.Tests", "DocumentService.Tests\DocumentService.Tests.csproj", "{ECD5BC60-7009-4099-7193-526FDC6E8D99}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {32D2E997-3DA7-4061-8A50-DBB34BBC3E5A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {32D2E997-3DA7-4061-8A50-DBB34BBC3E5A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {32D2E997-3DA7-4061-8A50-DBB34BBC3E5A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {32D2E997-3DA7-4061-8A50-DBB34BBC3E5A}.Release|Any CPU.Build.0 = Release|Any CPU {626E2002-8EC1-4FF9-A9A6-51D5809E26FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {626E2002-8EC1-4FF9-A9A6-51D5809E26FC}.Debug|Any CPU.Build.0 = Debug|Any CPU {626E2002-8EC1-4FF9-A9A6-51D5809E26FC}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -70,12 +66,15 @@ Global {2F2C937F-3732-4E6C-9720-FAB62DC33C63}.Debug|Any CPU.Build.0 = Debug|Any CPU {2F2C937F-3732-4E6C-9720-FAB62DC33C63}.Release|Any CPU.ActiveCfg = Release|Any CPU {2F2C937F-3732-4E6C-9720-FAB62DC33C63}.Release|Any CPU.Build.0 = Release|Any CPU + {ECD5BC60-7009-4099-7193-526FDC6E8D99}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {ECD5BC60-7009-4099-7193-526FDC6E8D99}.Debug|Any CPU.Build.0 = Debug|Any CPU + {ECD5BC60-7009-4099-7193-526FDC6E8D99}.Release|Any CPU.ActiveCfg = Release|Any CPU + {ECD5BC60-7009-4099-7193-526FDC6E8D99}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {32D2E997-3DA7-4061-8A50-DBB34BBC3E5A} = {D64772B8-6213-4031-8064-2567F1E724F6} {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} = {3F9E8D8E-1234-4567-89AB-CDEF01234567} {0B80DDC4-A13C-4C5F-8520-AA2F3650E884} = {2B18D2F8-40C1-4CA0-99AB-7F98F254FEB8} {62E8F4B3-EA49-41D2-8843-0636EB4421BB} = {2B18D2F8-40C1-4CA0-99AB-7F98F254FEB8} @@ -85,6 +84,7 @@ Global {A5AB3D2B-D4A8-1BE2-CACE-B5DBF9A40E51} = {9BACC18A-5C6D-4678-A43C-A19907AE9CF3} {459EDCC5-240E-A2BC-1330-B5B2326B679C} = {0B80DDC4-A13C-4C5F-8520-AA2F3650E884} {2F2C937F-3732-4E6C-9720-FAB62DC33C63} = {0B80DDC4-A13C-4C5F-8520-AA2F3650E884} + {ECD5BC60-7009-4099-7193-526FDC6E8D99} = {D64772B8-6213-4031-8064-2567F1E724F6} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {832CA90A-06D6-4312-9B35-16CC665EB37C}