From 11591db5b975313b51e4c930804972ad1b7bd37c Mon Sep 17 00:00:00 2001 From: Matthew Leibowitz Date: Sun, 30 May 2021 07:03:53 +0200 Subject: [PATCH] Add .NET Interactive Support (#1710) --- nuget/SkiaSharp.nuspec | 3 + .../ColorRenderer.cs | 33 +++++++ ...SkiaSharpDotNetInteractiveAssemblyInfo.cs} | 6 +- .../RasterRenderer.cs | 48 ++++++++++ .../SkiaSharp.DotNet.Interactive.csproj | 43 +++++++++ .../SkiaSharpKernelExtension.cs | 27 ++++++ .../SkiaSharp.Workbooks.csproj | 17 ---- .../SkiaSharpRepresentationProvider.cs | 92 ------------------- .../SkiaWorkbooksIntegration.cs | 12 --- source/SkiaSharpSource.Linux.sln | 9 ++ source/SkiaSharpSource.Mac.sln | 9 ++ source/SkiaSharpSource.Windows.sln | 9 ++ source/SkiaSharpSource.sln | 9 ++ 13 files changed, 193 insertions(+), 124 deletions(-) create mode 100644 source/SkiaSharp.DotNet.Interactive/ColorRenderer.cs rename source/{SkiaSharp.Workbooks/Properties/SkiaSharpWorkbooksAssemblyInfo.cs => SkiaSharp.DotNet.Interactive/Properties/SkiaSharpDotNetInteractiveAssemblyInfo.cs} (59%) create mode 100644 source/SkiaSharp.DotNet.Interactive/RasterRenderer.cs create mode 100644 source/SkiaSharp.DotNet.Interactive/SkiaSharp.DotNet.Interactive.csproj create mode 100644 source/SkiaSharp.DotNet.Interactive/SkiaSharpKernelExtension.cs delete mode 100644 source/SkiaSharp.Workbooks/SkiaSharp.Workbooks.csproj delete mode 100644 source/SkiaSharp.Workbooks/SkiaSharpRepresentationProvider.cs delete mode 100644 source/SkiaSharp.Workbooks/SkiaWorkbooksIntegration.cs diff --git a/nuget/SkiaSharp.nuspec b/nuget/SkiaSharp.nuspec index e617b28853..8d7b362c09 100644 --- a/nuget/SkiaSharp.nuspec +++ b/nuget/SkiaSharp.nuspec @@ -139,6 +139,9 @@ Please visit https://go.microsoft.com/fwlink/?linkid=868517 to view the release + + + diff --git a/source/SkiaSharp.DotNet.Interactive/ColorRenderer.cs b/source/SkiaSharp.DotNet.Interactive/ColorRenderer.cs new file mode 100644 index 0000000000..7649d0a572 --- /dev/null +++ b/source/SkiaSharp.DotNet.Interactive/ColorRenderer.cs @@ -0,0 +1,33 @@ +using Microsoft.AspNetCore.Html; + +using static Microsoft.DotNet.Interactive.Formatting.PocketViewTags; + +namespace SkiaSharp.DotNet.Interactive +{ + public static class ColorRenderer + { + public static IHtmlContent Render(this SKColor color) + { + var colorString = color.Alpha == 255 + ? $"rgb({color.Red},{color.Green},{color.Blue})" + : $"rgba({color.Red},{color.Green},{color.Blue},{color.Alpha / 255.0:0.0##})"; + + return GetHtml(colorString); + } + + public static IHtmlContent Render(this SKColorF color) => + ((SKColor)color).Render(); + + private static IHtmlContent GetHtml(string colorString) => + div( + span[style: + $"width: 2em; " + + $"background: {colorString}; " + + $"display: inline-block; " + + $"border: 1px solid black; "]( + new HtmlString(" ")), + span( + new HtmlString(" "), + colorString)); + } +} diff --git a/source/SkiaSharp.Workbooks/Properties/SkiaSharpWorkbooksAssemblyInfo.cs b/source/SkiaSharp.DotNet.Interactive/Properties/SkiaSharpDotNetInteractiveAssemblyInfo.cs similarity index 59% rename from source/SkiaSharp.Workbooks/Properties/SkiaSharpWorkbooksAssemblyInfo.cs rename to source/SkiaSharp.DotNet.Interactive/Properties/SkiaSharpDotNetInteractiveAssemblyInfo.cs index e463d53151..2670231495 100644 --- a/source/SkiaSharp.Workbooks/Properties/SkiaSharpWorkbooksAssemblyInfo.cs +++ b/source/SkiaSharp.DotNet.Interactive/Properties/SkiaSharpDotNetInteractiveAssemblyInfo.cs @@ -2,10 +2,10 @@ using System.Reflection; using System.Resources; -[assembly: AssemblyTitle("SkiaSharp.Workbooks")] -[assembly: AssemblyDescription("SkiaSharp.Workbooks adds functionality for SkiaSharp to Xamarin.Workbooks.")] +[assembly: AssemblyTitle("SkiaSharp.DotNet.Interactive")] +[assembly: AssemblyDescription("SkiaSharp.DotNet.Interactive adds functionality for SkiaSharp to .NET Interactive notebooks.")] [assembly: AssemblyCompany("Microsoft Corporation")] -[assembly: AssemblyProduct("SkiaSharp.Workbooks")] +[assembly: AssemblyProduct("SkiaSharp.DotNet.Interactive")] [assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")] [assembly: NeutralResourcesLanguage("en")] diff --git a/source/SkiaSharp.DotNet.Interactive/RasterRenderer.cs b/source/SkiaSharp.DotNet.Interactive/RasterRenderer.cs new file mode 100644 index 0000000000..a5954022a2 --- /dev/null +++ b/source/SkiaSharp.DotNet.Interactive/RasterRenderer.cs @@ -0,0 +1,48 @@ +using System; +using Microsoft.AspNetCore.Html; + +using static Microsoft.DotNet.Interactive.Formatting.PocketViewTags; + +namespace SkiaSharp.DotNet.Interactive +{ + public static class RasterRenderer + { + public static IHtmlContent Render(this SKBitmap bitmap) + { + using var image = SKImage.FromBitmap(bitmap); + return Render(image); + } + + public static IHtmlContent Render(this SKPixmap pixmap) + { + using var image = SKImage.FromPixels(pixmap); + return Render(image); + } + + public static IHtmlContent Render(this SKPicture picture) + { + using var image = SKImage.FromPicture(picture, picture.CullRect.Size.ToSizeI()); + return Render(image); + } + + public static IHtmlContent Render(this SKSurface surface) + { + using var image = surface.Snapshot(); + return Render(image); + } + + public static IHtmlContent Render(this SKImage image) + { + using var data = image.Encode(SKEncodedImageFormat.Png, 100); + return GetHtml(data); + } + + private static IHtmlContent GetHtml(SKData data) + { + var base64 = Convert.ToBase64String(data.AsSpan()); + + return div( + img[src: "data:image/png;base64," + base64]); + } + } +} diff --git a/source/SkiaSharp.DotNet.Interactive/SkiaSharp.DotNet.Interactive.csproj b/source/SkiaSharp.DotNet.Interactive/SkiaSharp.DotNet.Interactive.csproj new file mode 100644 index 0000000000..09a0ae697b --- /dev/null +++ b/source/SkiaSharp.DotNet.Interactive/SkiaSharp.DotNet.Interactive.csproj @@ -0,0 +1,43 @@ + + + + netstandard2.1 + SkiaSharp.DotNet.Interactive + SkiaSharp.DotNet.Interactive + + false + SkiaSharp + interactive-extensions\dotnet + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/SkiaSharp.DotNet.Interactive/SkiaSharpKernelExtension.cs b/source/SkiaSharp.DotNet.Interactive/SkiaSharpKernelExtension.cs new file mode 100644 index 0000000000..bdc28cf0a4 --- /dev/null +++ b/source/SkiaSharp.DotNet.Interactive/SkiaSharpKernelExtension.cs @@ -0,0 +1,27 @@ +using System.Threading.Tasks; +using Microsoft.DotNet.Interactive; +using Microsoft.DotNet.Interactive.Formatting; + +namespace SkiaSharp.DotNet.Interactive +{ + public class SkiaSharpKernelExtension : IKernelExtension + { + public Task OnLoadAsync(Kernel kernel) + { + // colors + Formatter.Register((color, writer) => writer.Write(color.Render()), "text/html"); + Formatter.Register((color, writer) => writer.Write(color.Render()), "text/html"); + + // "images" + Formatter.Register((bmp, writer) => writer.Write(bmp.Render()), "text/html"); + Formatter.Register((pix, writer) => writer.Write(pix.Render()), "text/html"); + Formatter.Register((pic, writer) => writer.Write(pic.Render()), "text/html"); + Formatter.Register((surface, writer) => writer.Write(surface.Render()), "text/html"); + Formatter.Register((img, writer) => writer.Write(img.Render()), "text/html"); + + // TODO: colorspaces and other things + + return Task.CompletedTask; + } + } +} diff --git a/source/SkiaSharp.Workbooks/SkiaSharp.Workbooks.csproj b/source/SkiaSharp.Workbooks/SkiaSharp.Workbooks.csproj deleted file mode 100644 index fecacdf772..0000000000 --- a/source/SkiaSharp.Workbooks/SkiaSharp.Workbooks.csproj +++ /dev/null @@ -1,17 +0,0 @@ - - - netstandard2.0 - SkiaSharp.Workbooks - SkiaSharp.Workbooks - - false - SkiaSharp - xamarin.interactive - - - - - - - - \ No newline at end of file diff --git a/source/SkiaSharp.Workbooks/SkiaSharpRepresentationProvider.cs b/source/SkiaSharp.Workbooks/SkiaSharpRepresentationProvider.cs deleted file mode 100644 index 0a90e2af25..0000000000 --- a/source/SkiaSharp.Workbooks/SkiaSharpRepresentationProvider.cs +++ /dev/null @@ -1,92 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; - -using Xamarin.Interactive.Logging; -using Xamarin.Interactive.Representations; -using Xamarin.Interactive.Representations.Reflection; -using Xamarin.Interactive.Serialization; - -namespace SkiaSharp.Workbooks -{ - sealed class SkiaSharpRepresentationProvider : RepresentationProvider - { - public override IEnumerable ProvideRepresentations (object obj) - { - yield return ProvideSingleRepresentation (obj); - } - - public override bool TryConvertFromRepresentation ( - IRepresentedType representedType, - object [] representations, - out object represented) - { - represented = null; - - Color color; - if (TryFindMatchingRepresentation ( - representedType, - representations, - out color)) { - represented = new SKColor ( - (byte)(color.Red * 255), - (byte)(color.Green * 255), - (byte)(color.Blue * 255), - (byte)(color.Alpha * 255)); - return true; - } - return base.TryConvertFromRepresentation (representedType, representations, out represented); - } - - ISerializableObject ProvideSingleRepresentation (object obj) - { - try { - var bitmap = obj as SKBitmap; - if (bitmap != null) - return SKImageToRepresentationImage (SKImage.FromBitmap (bitmap)); - - var image = obj as SKImage; - if (image != null) - return SKImageToRepresentationImage (image); - - var surface = obj as SKSurface; - if (surface != null) - return SKImageToRepresentationImage (surface.Snapshot ()); - - var pixmap = obj as SKPixmap; - if (pixmap != null) - return ImageFromSKData ( - pixmap.Encode (SKEncodedImageFormat.Png, 85), - pixmap.Width, - pixmap.Height); - - if (obj is SKColor) { - var color = (SKColor)obj; - return new Color (color.Red / 255.0, color.Green / 255.0, color.Blue / 255.0, color.Alpha / 255.0); - } - - return null; - } catch (Exception e) { - Log.Error ( - nameof (SkiaSharpRepresentationProvider), - $"Error while trying to provide representation for {obj.GetType ()}.", - e); - return null; - } - } - - ISerializableObject SKImageToRepresentationImage (SKImage image) - => ImageFromSKData (image.Encode (), image.Width, image.Height); - - ISerializableObject ImageFromSKData (SKData data, int width, int height) - { - byte [] pngData; - using (var ms = new MemoryStream ()) { - data.SaveTo (ms); - pngData = ms.ToArray (); - } - - return new Image (ImageFormat.Png, pngData, width, height); - } - } -} diff --git a/source/SkiaSharp.Workbooks/SkiaWorkbooksIntegration.cs b/source/SkiaSharp.Workbooks/SkiaWorkbooksIntegration.cs deleted file mode 100644 index f96d41aaf9..0000000000 --- a/source/SkiaSharp.Workbooks/SkiaWorkbooksIntegration.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Xamarin.Interactive; - -[assembly: AgentIntegration (typeof (SkiaSharp.Workbooks.SkiaWorkbooksIntegration))] - -namespace SkiaSharp.Workbooks -{ - sealed class SkiaWorkbooksIntegration : IAgentIntegration - { - public void IntegrateWith (IAgent agent) - => agent.RepresentationManager.AddProvider (new SkiaSharpRepresentationProvider ()); - } -} diff --git a/source/SkiaSharpSource.Linux.sln b/source/SkiaSharpSource.Linux.sln index 7c5e956f1e..81475cacaa 100644 --- a/source/SkiaSharpSource.Linux.sln +++ b/source/SkiaSharpSource.Linux.sln @@ -47,6 +47,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SkiaSharp.Views.Uno.Wasm", EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SkiaSharp.Views.Uno.Reference", "SkiaSharp.Views.Uno\SkiaSharp.Views.Uno.Reference\SkiaSharp.Views.Uno.Reference.csproj", "{D5C7D157-609E-4D64-8E42-C1DB0FAA86EB}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SkiaSharp.DotNet.Interactive", "SkiaSharp.DotNet.Interactive", "{E0EDA875-C25F-4727-BB98-6EF7BBAFEB4B}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SkiaSharp.DotNet.Interactive", "SkiaSharp.DotNet.Interactive\SkiaSharp.DotNet.Interactive.csproj", "{03A0F2E5-345D-4FA2-B1F8-45D2D7EEA3EB}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -113,6 +117,10 @@ Global {D5C7D157-609E-4D64-8E42-C1DB0FAA86EB}.Debug|Any CPU.Build.0 = Debug|Any CPU {D5C7D157-609E-4D64-8E42-C1DB0FAA86EB}.Release|Any CPU.ActiveCfg = Release|Any CPU {D5C7D157-609E-4D64-8E42-C1DB0FAA86EB}.Release|Any CPU.Build.0 = Release|Any CPU + {03A0F2E5-345D-4FA2-B1F8-45D2D7EEA3EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {03A0F2E5-345D-4FA2-B1F8-45D2D7EEA3EB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {03A0F2E5-345D-4FA2-B1F8-45D2D7EEA3EB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {03A0F2E5-345D-4FA2-B1F8-45D2D7EEA3EB}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -133,6 +141,7 @@ Global {4606F63B-F0B1-418E-8B45-844361E17EB1} = {66A0800A-CA70-4AC2-88B7-8E7C4CA7C914} {08599A28-FADE-43B5-95A0-BDCB22B97D3A} = {00C9099A-BE4F-40D0-9401-295618368370} {D5C7D157-609E-4D64-8E42-C1DB0FAA86EB} = {00C9099A-BE4F-40D0-9401-295618368370} + {03A0F2E5-345D-4FA2-B1F8-45D2D7EEA3EB} = {E0EDA875-C25F-4727-BB98-6EF7BBAFEB4B} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {B4229170-607D-4886-9990-8FD5D86220B9} diff --git a/source/SkiaSharpSource.Mac.sln b/source/SkiaSharpSource.Mac.sln index 16c007c82b..485be2761d 100644 --- a/source/SkiaSharpSource.Mac.sln +++ b/source/SkiaSharpSource.Mac.sln @@ -85,6 +85,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SkiaSharp.Views.Uno.Wasm", EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SkiaSharp.Views.Uno.Reference", "SkiaSharp.Views.Uno\SkiaSharp.Views.Uno.Reference\SkiaSharp.Views.Uno.Reference.csproj", "{D5C7D157-609E-4D64-8E42-C1DB0FAA86EB}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SkiaSharp.DotNet.Interactive", "SkiaSharp.DotNet.Interactive\SkiaSharp.DotNet.Interactive.csproj", "{A23C2451-BBCE-4309-B80F-CEE482A140C7}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SkiaSharp.DotNet.Interactive", "SkiaSharp.DotNet.Interactive", "{A54F6AE5-2921-4C68-846A-25D38F1C2E7E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -227,6 +231,10 @@ Global {D5C7D157-609E-4D64-8E42-C1DB0FAA86EB}.Debug|Any CPU.Build.0 = Debug|Any CPU {D5C7D157-609E-4D64-8E42-C1DB0FAA86EB}.Release|Any CPU.ActiveCfg = Release|Any CPU {D5C7D157-609E-4D64-8E42-C1DB0FAA86EB}.Release|Any CPU.Build.0 = Release|Any CPU + {A23C2451-BBCE-4309-B80F-CEE482A140C7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A23C2451-BBCE-4309-B80F-CEE482A140C7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A23C2451-BBCE-4309-B80F-CEE482A140C7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A23C2451-BBCE-4309-B80F-CEE482A140C7}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -266,6 +274,7 @@ Global {E0FF9BFF-2253-4486-A8E2-94312D09D056} = {E53351EA-FE40-47D2-B388-4A75DA6CCD71} {242213FA-1F0E-40BB-A9B2-6FEE82B5D216} = {E53351EA-FE40-47D2-B388-4A75DA6CCD71} {D5C7D157-609E-4D64-8E42-C1DB0FAA86EB} = {E53351EA-FE40-47D2-B388-4A75DA6CCD71} + {A23C2451-BBCE-4309-B80F-CEE482A140C7} = {A54F6AE5-2921-4C68-846A-25D38F1C2E7E} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {4B8BED07-EA83-4BC1-B3BB-6B8EBC54C25F} diff --git a/source/SkiaSharpSource.Windows.sln b/source/SkiaSharpSource.Windows.sln index 8e463eebe4..ae4b82ce48 100644 --- a/source/SkiaSharpSource.Windows.sln +++ b/source/SkiaSharpSource.Windows.sln @@ -73,6 +73,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SkiaSharp.Views.WinUI", "Sk EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SkiaSharp.Views.WinUI", "SkiaSharp.Views.WinUI", "{32AE56A0-F3E1-4721-9BED-B1F609DEA8E8}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SkiaSharp.DotNet.Interactive", "SkiaSharp.DotNet.Interactive", "{B7F572BF-AD3F-4AC8-A654-3ED241E3ECA4}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SkiaSharp.DotNet.Interactive", "SkiaSharp.DotNet.Interactive\SkiaSharp.DotNet.Interactive.csproj", "{73185ECB-5A38-447C-95CF-D32D6784B97D}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -187,6 +191,10 @@ Global {F50AE765-D9B9-4025-88A8-E8B080D5D624}.Debug|Any CPU.Build.0 = Debug|Any CPU {F50AE765-D9B9-4025-88A8-E8B080D5D624}.Release|Any CPU.ActiveCfg = Release|Any CPU {F50AE765-D9B9-4025-88A8-E8B080D5D624}.Release|Any CPU.Build.0 = Release|Any CPU + {73185ECB-5A38-447C-95CF-D32D6784B97D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {73185ECB-5A38-447C-95CF-D32D6784B97D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {73185ECB-5A38-447C-95CF-D32D6784B97D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {73185ECB-5A38-447C-95CF-D32D6784B97D}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -219,6 +227,7 @@ Global {F675A841-ECDB-4571-8AA3-7D4642FD57DB} = {E53351EA-FE40-47D2-B388-4A75DA6CCD71} {D5C7D157-609E-4D64-8E42-C1DB0FAA86EB} = {E53351EA-FE40-47D2-B388-4A75DA6CCD71} {F50AE765-D9B9-4025-88A8-E8B080D5D624} = {32AE56A0-F3E1-4721-9BED-B1F609DEA8E8} + {73185ECB-5A38-447C-95CF-D32D6784B97D} = {B7F572BF-AD3F-4AC8-A654-3ED241E3ECA4} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {63A8C36E-4917-46DB-9AAD-522B8EC00C23} diff --git a/source/SkiaSharpSource.sln b/source/SkiaSharpSource.sln index af4848986d..f6247ca81f 100644 --- a/source/SkiaSharpSource.sln +++ b/source/SkiaSharpSource.sln @@ -109,6 +109,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SkiaSharp.Views.WinUI", "Sk EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SkiaSharp.Views.WinUI", "SkiaSharp.Views.WinUI\SkiaSharp.Views.WinUI\SkiaSharp.Views.WinUI.csproj", "{02CA4107-1FC6-4676-B284-9981694A450E}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SkiaSharp.DotNet.Interactive", "SkiaSharp.DotNet.Interactive", "{94767AFC-EB2B-41ED-BFEF-93EF33EEEBCF}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SkiaSharp.DotNet.Interactive", "SkiaSharp.DotNet.Interactive\SkiaSharp.DotNet.Interactive.csproj", "{D213D614-2F31-450C-B6FA-294754C4DCD4}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -295,6 +299,10 @@ Global {02CA4107-1FC6-4676-B284-9981694A450E}.Debug|Any CPU.Build.0 = Debug|Any CPU {02CA4107-1FC6-4676-B284-9981694A450E}.Release|Any CPU.ActiveCfg = Release|Any CPU {02CA4107-1FC6-4676-B284-9981694A450E}.Release|Any CPU.Build.0 = Release|Any CPU + {D213D614-2F31-450C-B6FA-294754C4DCD4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D213D614-2F31-450C-B6FA-294754C4DCD4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D213D614-2F31-450C-B6FA-294754C4DCD4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D213D614-2F31-450C-B6FA-294754C4DCD4}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -345,6 +353,7 @@ Global {047C460D-7470-418C-AF2C-30620A1AF61C} = {E53351EA-FE40-47D2-B388-4A75DA6CCD71} {D5C7D157-609E-4D64-8E42-C1DB0FAA86EB} = {E53351EA-FE40-47D2-B388-4A75DA6CCD71} {02CA4107-1FC6-4676-B284-9981694A450E} = {6430EC5F-EDA1-4202-AB7B-22ED0496E016} + {D213D614-2F31-450C-B6FA-294754C4DCD4} = {94767AFC-EB2B-41ED-BFEF-93EF33EEEBCF} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {67EACD19-0CEA-4127-9842-549AA6FB84C9}