adds separate project for MAUI tests

This commit is contained in:
Sweekriti Satpathy 2021-06-09 17:27:16 -07:00
Родитель 0e927e578e
Коммит e23c1f83fc
9 изменённых файлов: 252 добавлений и 99 удалений

Просмотреть файл

@ -241,13 +241,13 @@ namespace MSBuild.Conversion.Project
{
itemGroup.RemoveChild(item);
}
else if (XamarinFacts.UnnecessaryXamItemIncludes.Contains(item.Include, StringComparer.OrdinalIgnoreCase))
else if (baselineProject.ProjectStyle is ProjectStyle.XamarinDroid || baselineProject.ProjectStyle is ProjectStyle.XamariniOS)
{
itemGroup.RemoveChild(item);
}
else if (XamarinFacts.UnnecessaryXamItemTypes.Contains(item.ItemType, StringComparer.OrdinalIgnoreCase))
{
itemGroup.RemoveChild(item);
if (XamarinFacts.UnnecessaryXamItemIncludes.Contains(item.Include, StringComparer.OrdinalIgnoreCase))
itemGroup.RemoveChild(item);
if (XamarinFacts.UnnecessaryXamItemTypes.Contains(item.ItemType, StringComparer.OrdinalIgnoreCase))
itemGroup.RemoveChild(item);
}
else
{
@ -519,7 +519,7 @@ namespace MSBuild.Conversion.Project
public static IProjectRootElement AddGenerateAssemblyInfoAsFalse(this IProjectRootElement projectRootElement, ProjectStyle projectStyle)
{
//Skip adding this for .NET MAUI conversion
if ((projectStyle == ProjectStyle.XamarinDroid) || (projectStyle == ProjectStyle.XamariniOS))
if ((projectStyle is ProjectStyle.XamarinDroid) || (projectStyle is ProjectStyle.XamariniOS))
return projectRootElement;
// Don't create a new prop group; put the desktop properties in the same group as where TFM is located

Просмотреть файл

@ -1,18 +1,40 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MauiSmoke.Tests.Utilities;
using Microsoft.Build.Construction;
using MSBuild.Abstractions;
using MSBuild.Conversion.Project;
using Xunit;
namespace Smoke.Tests.Utilities
namespace MauiSmoke.Tests
{
public class SharedTestLogic
public class MauiConversions : IClassFixture<SolutionPathFixture>, IClassFixture<MauiMSBuildFixture>
{
public void AssertConversionWorks(string projectToConvertPath, string projectBaselinePath, string targetTFM, bool forceWeb = false, bool keepTargetFramework = false)
private string SolutionPath => Environment.CurrentDirectory;
private string TestDataPath => Path.Combine(SolutionPath, "tests", "TestData");
private string GetXamarinAndroidProjectPath(string projectName) => Path.Combine(TestDataPath, projectName, $"{projectName}.csproj");
private string GetXamariniOSProjectPath(string projectName) => Path.Combine(TestDataPath, projectName, $"{projectName}.csproj");
public MauiConversions(SolutionPathFixture solutionPathFixture, MauiMSBuildFixture msBuildFixture)
{
msBuildFixture.MSBuildPathForXamarinProject();
solutionPathFixture.SetCurrentDirectory();
}
[Fact]
public void ConvertsXamarinFormsAndroidToMaui()
{
var projectToConvertPath = GetXamarinAndroidProjectPath("SmokeTests.XamarinForms.Android");
var projectBaselinePath = GetXamarinAndroidProjectPath("SmokeTests.XamarinForms.AndroidBaseline");
AssertConversionWorks(projectToConvertPath, projectBaselinePath, "net6.0-android");
}
private void AssertConversionWorks(string projectToConvertPath, string projectBaselinePath, string targetTFM, bool forceWeb = false, bool keepTargetFramework = false)
{
var (baselineRootElement, convertedRootElement) = GetRootElementsForComparison(projectToConvertPath, projectBaselinePath, targetTFM, forceWeb, keepTargetFramework);
AssertPropsEqual(baselineRootElement, convertedRootElement);
@ -100,6 +122,4 @@ namespace Smoke.Tests.Utilities
}
}
}
}

Просмотреть файл

@ -0,0 +1,26 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.6.1" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.Build" Version="$(MicrosoftBuildVersion)" ExcludeAssets="runtime" />
<PackageReference Include="System.Collections.Immutable" Version="$(SystemCollectionsImmutableVersion)" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\src\MSBuild.Abstractions\MSBuild.Abstractions.csproj" />
<ProjectReference Include="..\..\..\src\MSBuild.Conversion.Project\MSBuild.Conversion.Project.csproj" />
</ItemGroup>
</Project>

Просмотреть файл

@ -0,0 +1,43 @@
using System;
using System.IO;
using System.Linq;
using System.Threading;
using Microsoft.Build.Locator;
using MSBuild.Abstractions;
namespace MauiSmoke.Tests.Utilities
{
/// <summary>
/// This test fixture ensures that MSBuild is loaded from VS Install Directory
/// </summary>
///
public class MauiMSBuildFixture : IDisposable
{
private static int _registered = 0;
public void MSBuildPathForXamarinProject()
{
if (Interlocked.Exchange(ref _registered, 1) == 0)
{
//For Xamarin Project tests, default MSBuild instance resolved from VSINSTALLDIR Environment Variable
var vsinstalldir = Environment.GetEnvironmentVariable("VSINSTALLDIR");
if (!string.IsNullOrEmpty(vsinstalldir))
{
MSBuildHelpers.HookAssemblyResolveForMSBuild(Path.Combine(vsinstalldir, "MSBuild", "Current", "Bin"));
}
else
{
string vsPath = new VisualStudioLocator().GetLatestVisualStudioPath();
if (string.IsNullOrWhiteSpace(vsPath))
throw new Exception("Error locating VS Install Directory. Try setting Environment Variable VSINSTALLDIR.");
else
MSBuildHelpers.HookAssemblyResolveForMSBuild(Path.Combine(vsPath, "MSBuild", "Current", "Bin"));
}
}
}
public void Dispose()
{
}
}
}

Просмотреть файл

@ -0,0 +1,34 @@
using System;
using System.IO;
using System.Threading;
namespace MauiSmoke.Tests.Utilities
{
/// <summary>
/// This test fixture sets the <see cref="Environment.CurrentDirectory" /> to the try-convert solution's path.
/// </summary>
public class SolutionPathFixture : IDisposable
{
private static int _registered = 0;
private static string _currentDirectory;
public void SetCurrentDirectory()
{
if (Interlocked.Increment(ref _registered) == 1)
{
_currentDirectory = Environment.CurrentDirectory;
var solutionPath = Directory.GetParent(_currentDirectory).Parent.Parent.Parent.Parent.FullName;
Environment.CurrentDirectory = solutionPath;
}
}
public void Dispose()
{
if (Interlocked.Decrement(ref _registered) == 0)
{
Environment.CurrentDirectory = _currentDirectory;
_currentDirectory = null;
}
}
}
}

Просмотреть файл

@ -21,7 +21,6 @@ namespace SmokeTests
private string GetFSharpProjectPath(string projectName) => Path.Combine(TestDataPath, projectName, $"{projectName}.fsproj");
private string GetCSharpProjectPath(string projectName) => Path.Combine(TestDataPath, projectName, $"{projectName}.csproj");
private string GetVisualBasicProjectPath(string projectName) => Path.Combine(TestDataPath, projectName, $"{projectName}.vbproj");
private SharedTestLogic _testLogic => new SharedTestLogic();
public BasicSmokeTests(SolutionPathFixture solutionPathFixture, MSBuildFixture msBuildFixture)
{
@ -34,7 +33,7 @@ namespace SmokeTests
{
var projectToConvertPath = GetFSharpProjectPath("SmokeTests.LegacyFSharpConsole");
var projectBaselinePath = GetFSharpProjectPath("SmokeTests.FSharpConsoleCoreBaseline");
_testLogic.AssertConversionWorks(projectToConvertPath, projectBaselinePath, "netcoreapp3.1");
AssertConversionWorks(projectToConvertPath, projectBaselinePath, "netcoreapp3.1");
}
[Fact]
@ -42,7 +41,7 @@ namespace SmokeTests
{
var projectToConvertPath = GetFSharpProjectPath("SmokeTests.LegacyFSharpConsole");
var projectBaselinePath = GetFSharpProjectPath("SmokeTests.FSharpConsoleNet5Baseline");
_testLogic.AssertConversionWorks(projectToConvertPath, projectBaselinePath, "net5.0");
AssertConversionWorks(projectToConvertPath, projectBaselinePath, "net5.0");
}
[Fact]
@ -50,7 +49,7 @@ namespace SmokeTests
{
var projectToConvertPath = GetCSharpProjectPath("SmokeTests.WpfFramework");
var projectBaselinePath = GetCSharpProjectPath("SmokeTests.WpfCoreBaseline");
_testLogic.AssertConversionWorks(projectToConvertPath, projectBaselinePath, "netcoreapp3.1");
AssertConversionWorks(projectToConvertPath, projectBaselinePath, "netcoreapp3.1");
}
[Fact]
@ -58,7 +57,7 @@ namespace SmokeTests
{
var projectToConvertPath = GetCSharpProjectPath("SmokeTests.WpfFramework");
var projectBaselinePath = GetCSharpProjectPath("SmokeTests.WpfNet5Baseline");
_testLogic.AssertConversionWorks(projectToConvertPath, projectBaselinePath, "net5.0-windows");
AssertConversionWorks(projectToConvertPath, projectBaselinePath, "net5.0-windows");
}
[Fact]
@ -66,7 +65,7 @@ namespace SmokeTests
{
var projectToConvertPath = GetVisualBasicProjectPath("SmokeTests.WpfVbFramework");
var projectBaselinePath = GetVisualBasicProjectPath("SmokeTests.WpfVbNet5Baseline");
_testLogic.AssertConversionWorks(projectToConvertPath, projectBaselinePath, "net5.0-windows");
AssertConversionWorks(projectToConvertPath, projectBaselinePath, "net5.0-windows");
}
[Fact]
@ -74,7 +73,7 @@ namespace SmokeTests
{
var projectToConvertPath = GetVisualBasicProjectPath("SmokeTests.WinformsVbFramework");
var projectBaselinePath = GetVisualBasicProjectPath("SmokeTests.WinformsVbKeepTfm");
_testLogic.AssertConversionWorks(projectToConvertPath, projectBaselinePath, "testdata", keepTargetFramework: true);
AssertConversionWorks(projectToConvertPath, projectBaselinePath, "testdata", keepTargetFramework: true);
}
[Fact]
@ -82,7 +81,7 @@ namespace SmokeTests
{
var projectToConvertPath = GetCSharpProjectPath("SmokeTests.WinformsFramework");
var projectBaselinePath = GetCSharpProjectPath("SmokeTests.WinformsCoreBaseline");
_testLogic.AssertConversionWorks(projectToConvertPath, projectBaselinePath, "netcoreapp3.1");
AssertConversionWorks(projectToConvertPath, projectBaselinePath, "netcoreapp3.1");
}
[Fact]
@ -90,7 +89,7 @@ namespace SmokeTests
{
var projectToConvertPath = GetCSharpProjectPath("SmokeTests.WinformsFramework");
var projectBaselinePath = GetCSharpProjectPath("SmokeTests.WinformsNet5Baseline");
_testLogic.AssertConversionWorks(projectToConvertPath, projectBaselinePath, "net5.0-windows");
AssertConversionWorks(projectToConvertPath, projectBaselinePath, "net5.0-windows");
}
[Fact]
@ -98,7 +97,7 @@ namespace SmokeTests
{
var projectToConvertPath = GetCSharpProjectPath("SmokeTests.LegacyMSTest");
var projectBaselinePath = GetCSharpProjectPath("SmokeTests.MSTestCoreBaseline");
_testLogic.AssertConversionWorks(projectToConvertPath, projectBaselinePath, "netcoreapp3.1");
AssertConversionWorks(projectToConvertPath, projectBaselinePath, "netcoreapp3.1");
}
[Fact]
@ -106,7 +105,7 @@ namespace SmokeTests
{
var projectToConvertPath = GetVisualBasicProjectPath("SmokeTests.LegacyMSTestVB");
var projectBaselinePath = GetVisualBasicProjectPath("SmokeTests.MSTestVbNet5Baseline");
_testLogic.AssertConversionWorks(projectToConvertPath, projectBaselinePath, "net5.0-windows");
AssertConversionWorks(projectToConvertPath, projectBaselinePath, "net5.0-windows");
}
[Fact]
@ -114,7 +113,7 @@ namespace SmokeTests
{
var projectToConvertPath = GetCSharpProjectPath("SmokeTests.LegacyWebLibrary");
var projectBaselinePath = GetCSharpProjectPath("SmokeTests.WebLibraryNetFxBaseline");
_testLogic.AssertConversionWorks(projectToConvertPath, projectBaselinePath, "net472", true);
AssertConversionWorks(projectToConvertPath, projectBaselinePath, "net472", true);
}
[Fact]
@ -122,7 +121,95 @@ namespace SmokeTests
{
var projectToConvertPath = GetCSharpProjectPath("SmokeTests.LegacyWebLibrary");
var projectBaselinePath = GetCSharpProjectPath("SmokeTests.WebLibraryNet5Baseline");
_testLogic.AssertConversionWorks(projectToConvertPath, projectBaselinePath, "net5.0", true);
AssertConversionWorks(projectToConvertPath, projectBaselinePath, "net5.0", true);
}
private void AssertConversionWorks(string projectToConvertPath, string projectBaselinePath, string targetTFM, bool forceWeb = false, bool keepTargetFramework = false)
{
var (baselineRootElement, convertedRootElement) = GetRootElementsForComparison(projectToConvertPath, projectBaselinePath, targetTFM, forceWeb, keepTargetFramework);
AssertPropsEqual(baselineRootElement, convertedRootElement);
AssertItemsEqual(baselineRootElement, convertedRootElement);
}
private static (IProjectRootElement baselineRootElement, IProjectRootElement convertedRootElement) GetRootElementsForComparison(string projectToConvertPath, string projectBaselinePath, string targetTFM, bool forceWeb, bool keepTargetFramework)
{
var conversionLoader = new MSBuildConversionWorkspaceLoader(projectToConvertPath, MSBuildConversionWorkspaceType.Project);
var conversionWorkspace = conversionLoader.LoadWorkspace(projectToConvertPath, noBackup: true, targetTFM, keepTargetFramework, forceWeb);
var baselineLoader = new MSBuildConversionWorkspaceLoader(projectBaselinePath, MSBuildConversionWorkspaceType.Project);
var baselineRootElement = baselineLoader.GetRootElementFromProjectFile(projectBaselinePath);
var item = conversionWorkspace.WorkspaceItems.Single();
var converter = new Converter(item.UnconfiguredProject, item.SdkBaselineProject, item.ProjectRootElement, noBackup: false);
var convertedRootElement = converter.ConvertProjectFile();
return (baselineRootElement, convertedRootElement);
}
private void AssertPropsEqual(IProjectRootElement baselineRootElement, IProjectRootElement convertedRootElement)
{
Assert.Equal(baselineRootElement.Sdk, convertedRootElement.Sdk);
Assert.Equal(baselineRootElement.PropertyGroups.Count, convertedRootElement.PropertyGroups.Count);
var baselinePropGroups = new List<ProjectPropertyGroupElement>(baselineRootElement.PropertyGroups);
var convertedPropGroups = new List<ProjectPropertyGroupElement>(convertedRootElement.PropertyGroups);
if (baselinePropGroups.Count > 0)
{
for (var i = 0; i < baselinePropGroups.Count; i++)
{
var baselineProps = new List<ProjectPropertyElement>(baselinePropGroups[i].Properties);
var convertedProps = new List<ProjectPropertyElement>(convertedPropGroups[i].Properties);
Assert.Equal(baselineProps.Count, convertedProps.Count);
if (baselineProps.Count > 0)
{
for (var j = 0; j < baselineProps.Count; j++)
{
var baselineProp = baselineProps[j];
var convertedProp = convertedProps[j];
Assert.Equal(baselineProp.Name, convertedProp.Name);
Assert.Equal(baselineProp.Value, convertedProp.Value);
}
}
}
}
}
private void AssertItemsEqual(IProjectRootElement baselineRootElement, IProjectRootElement convertedRootElement)
{
Assert.Equal(baselineRootElement.Sdk, convertedRootElement.Sdk);
Assert.Equal(baselineRootElement.ItemGroups.Count, convertedRootElement.ItemGroups.Count);
var baselineItemGroups = new List<ProjectItemGroupElement>(baselineRootElement.ItemGroups);
var convertedItemGroups = new List<ProjectItemGroupElement>(convertedRootElement.ItemGroups);
if (baselineItemGroups.Count > 0)
{
for (var i = 0; i < baselineItemGroups.Count; i++)
{
var baselineItems = new List<ProjectItemElement>(baselineItemGroups[i].Items);
var convertedItems = new List<ProjectItemElement>(convertedItemGroups[i].Items);
// TODO: this was regressed at some point
// converted items will now have additional items
// Assert.Equal(baselineItems.Count, convertedItems.Count);
if (baselineItems.Count > 1)
{
for (var j = 0; j < baselineItems.Count; j++)
{
var baselineItem = baselineItems[j];
var convertedItem = convertedItems[j];
Assert.Equal(baselineItem.Include, convertedItem.Include);
Assert.Equal(baselineItem.Update, convertedItem.Update);
}
}
}
}
}
}
}

Просмотреть файл

@ -1,48 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Build.Construction;
using MSBuild.Abstractions;
using MSBuild.Conversion.Project;
using Smoke.Tests.Utilities;
using Xunit;
namespace Smoke.Tests
{
public class MauiSmokeTests : IClassFixture<SolutionPathFixture>, IClassFixture<MSBuildFixture>
{
private string SolutionPath => Environment.CurrentDirectory;
private string TestDataPath => Path.Combine(SolutionPath, "tests", "TestData");
private string GetXamarinAndroidProjectPath(string projectName) => Path.Combine(TestDataPath, projectName, $"{projectName}.csproj");
private string GetXamariniOSProjectPath(string projectName) => Path.Combine(TestDataPath, projectName, $"{projectName}.csproj");
private SharedTestLogic _testLogic => new SharedTestLogic();
public MauiSmokeTests(SolutionPathFixture solutionPathFixture, MSBuildFixture msBuildFixture)
{
msBuildFixture.MSBuildPathForXamarinProject();
solutionPathFixture.SetCurrentDirectory();
}
[Fact]
public void ConvertsXamarinFormsAndroidToMaui()
{
var projectToConvertPath = GetXamarinAndroidProjectPath("SmokeTests.XamarinForms.Android");
var projectBaselinePath = GetXamarinAndroidProjectPath("SmokeTests.XamarinForms.AndroidBaseline");
_testLogic.AssertConversionWorks(projectToConvertPath, projectBaselinePath, "net6.0-android");
}
[Fact]
public void ConvertsXamarinFormsiOSToMaui()
{
var projectToConvertPath = GetXamariniOSProjectPath("SmokeTests.XamarinForms.iOS");
var projectBaselinePath = GetXamariniOSProjectPath("SmokeTests.XamarinForms.iOSBaseline");
_testLogic.AssertConversionWorks(projectToConvertPath, projectBaselinePath, "net6.0-ios");
}
}
}

Просмотреть файл

@ -13,7 +13,6 @@ namespace Smoke.Tests.Utilities
public class MSBuildFixture : IDisposable
{
private static int _registered = 0;
public void RegisterInstance()
{
if (Interlocked.Exchange(ref _registered, 1) == 0)
@ -23,29 +22,6 @@ namespace Smoke.Tests.Utilities
MSBuildHelpers.HookAssemblyResolveForMSBuild(defaultInstance.MSBuildPath);
}
}
public void MSBuildPathForXamarinProject()
{
if (Interlocked.Exchange(ref _registered, 1) == 0)
{
//For Xamarin Project tests, default MSBuild instance resolved from VSINSTALLDIR Environment Variable
var vsinstalldir = Environment.GetEnvironmentVariable("VSINSTALLDIR");
if (!string.IsNullOrEmpty(vsinstalldir))
{
MSBuildHelpers.HookAssemblyResolveForMSBuild(Path.Combine(vsinstalldir, "MSBuild", "Current", "Bin"));
}
else
{
string vsPath = new VisualStudioLocator().GetLatestVisualStudioPath();
if (string.IsNullOrWhiteSpace(vsPath))
throw new Exception("Error locating VS Install Directory. Try setting Environment Variable VSINSTALLDIR.");
else
MSBuildHelpers.HookAssemblyResolveForMSBuild(Path.Combine(vsPath, "MSBuild", "Current", "Bin"));
}
}
}
public void Dispose()
{
}

Просмотреть файл

@ -25,6 +25,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Smoke.Tests", "tests\end-to
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MSBuild.Conversion.SDK", "src\MSBuild.Conversion.SDK\MSBuild.Conversion.SDK.csproj", "{B56755BA-7992-4D2C-98E4-86F1C75A19B2}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MauiSmoke.Tests", "tests\end-to-end\MauiSmoke.Tests\MauiSmoke.Tests.csproj", "{927AAC29-6B10-42BE-A7A7-222970F1EC09}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -143,6 +145,18 @@ Global
{B56755BA-7992-4D2C-98E4-86F1C75A19B2}.Release|x64.Build.0 = Release|Any CPU
{B56755BA-7992-4D2C-98E4-86F1C75A19B2}.Release|x86.ActiveCfg = Release|Any CPU
{B56755BA-7992-4D2C-98E4-86F1C75A19B2}.Release|x86.Build.0 = Release|Any CPU
{927AAC29-6B10-42BE-A7A7-222970F1EC09}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{927AAC29-6B10-42BE-A7A7-222970F1EC09}.Debug|Any CPU.Build.0 = Debug|Any CPU
{927AAC29-6B10-42BE-A7A7-222970F1EC09}.Debug|x64.ActiveCfg = Debug|Any CPU
{927AAC29-6B10-42BE-A7A7-222970F1EC09}.Debug|x64.Build.0 = Debug|Any CPU
{927AAC29-6B10-42BE-A7A7-222970F1EC09}.Debug|x86.ActiveCfg = Debug|Any CPU
{927AAC29-6B10-42BE-A7A7-222970F1EC09}.Debug|x86.Build.0 = Debug|Any CPU
{927AAC29-6B10-42BE-A7A7-222970F1EC09}.Release|Any CPU.ActiveCfg = Release|Any CPU
{927AAC29-6B10-42BE-A7A7-222970F1EC09}.Release|Any CPU.Build.0 = Release|Any CPU
{927AAC29-6B10-42BE-A7A7-222970F1EC09}.Release|x64.ActiveCfg = Release|Any CPU
{927AAC29-6B10-42BE-A7A7-222970F1EC09}.Release|x64.Build.0 = Release|Any CPU
{927AAC29-6B10-42BE-A7A7-222970F1EC09}.Release|x86.ActiveCfg = Release|Any CPU
{927AAC29-6B10-42BE-A7A7-222970F1EC09}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -157,6 +171,7 @@ Global
{A3DDB4B7-F48E-40FA-A638-B03EECB48255} = {8F861E7D-283E-46F9-9A6A-DBF1BE8BC978}
{26176B40-732E-425C-A5F8-70B738C4778A} = {8F861E7D-283E-46F9-9A6A-DBF1BE8BC978}
{B56755BA-7992-4D2C-98E4-86F1C75A19B2} = {FEF77564-1629-42D5-9183-18EF3C31AFE5}
{927AAC29-6B10-42BE-A7A7-222970F1EC09} = {8F861E7D-283E-46F9-9A6A-DBF1BE8BC978}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {68B47EDA-66C8-46F5-A57F-1129A8EF7F4F}