Added GroundOverlayPanel

This commit is contained in:
Clemens 2022-01-18 21:30:22 +01:00
parent 9d368d7ee8
commit 135473b799
4 changed files with 281 additions and 60 deletions

View file

@ -0,0 +1,276 @@
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
// © 2022 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL)
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Threading.Tasks;
using System.Xml;
#if WINUI
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Media;
#elif UWP
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;
#else
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
#endif
namespace MapControl
{
public class GroundOverlayPanel : MapPanel
{
class LatLonBox : BoundingBox
{
public LatLonBox(double south, double west, double north, double east, double rotation)
: base(south, west, north, east)
{
Rotation = rotation;
}
public double Rotation { get; }
}
class ImageOverlay
{
public ImageOverlay(LatLonBox latLonBox, string imagePath, int zIndex)
{
LatLonBox = latLonBox;
ImagePath = imagePath;
ZIndex = zIndex;
}
public LatLonBox LatLonBox { get; }
public string ImagePath { get; }
public int ZIndex { get; }
public ImageSource ImageSource { get; set; }
}
public static readonly DependencyProperty KmlFileProperty = DependencyProperty.Register(
nameof(KmlFile), typeof(string), typeof(GroundOverlayPanel),
new PropertyMetadata(null, async (o, e) => await ((GroundOverlayPanel)o).KmlFilePropertyChanged((string)e.NewValue)));
public string KmlFile
{
get { return (string)GetValue(KmlFileProperty); }
set { SetValue(KmlFileProperty, value); }
}
private async Task KmlFilePropertyChanged(string path)
{
IEnumerable<ImageOverlay> imageOverlays = null;
if (!string.IsNullOrEmpty(path))
{
try
{
var ext = Path.GetExtension(path).ToLower();
if (ext == ".kmz")
{
imageOverlays = await ReadGroundOverlaysFromArchiveAsync(path);
}
else if (ext == ".kml")
{
imageOverlays = await ReadGroundOverlaysFromFileAsync(path);
}
}
catch (Exception ex)
{
Debug.WriteLine($"GroundOverlayPanel: {path}: {ex.Message}");
}
}
Children.Clear();
if (imageOverlays != null)
{
AddImageOverlays(imageOverlays);
}
}
private void AddImageOverlays(IEnumerable<ImageOverlay> imageOverlays)
{
foreach (var imageOverlay in imageOverlays.Where(i => i.ImageSource != null))
{
FrameworkElement overlay = new Image
{
Source = imageOverlay.ImageSource,
Stretch = Stretch.Fill,
UseLayoutRounding = false
};
if (imageOverlay.LatLonBox.Rotation != 0d)
{
overlay.RenderTransform = new RotateTransform { Angle = -imageOverlay.LatLonBox.Rotation };
overlay.RenderTransformOrigin = new Point(0.5, 0.5);
// additional Panel for map rotation, see MapPanel.ArrangeElementWithBoundingBox
var panel = new Grid { UseLayoutRounding = false };
panel.Children.Add(overlay);
overlay = panel;
}
SetBoundingBox(overlay, imageOverlay.LatLonBox);
Canvas.SetZIndex(overlay, imageOverlay.ZIndex);
Children.Add(overlay);
}
}
private static async Task<IEnumerable<ImageOverlay>> ReadGroundOverlaysFromArchiveAsync(string archiveFile)
{
using (var archive = await Task.Run(() => ZipFile.OpenRead(archiveFile)))
{
var docEntry = await Task.Run(() => archive.GetEntry("doc.kml") ?? archive.Entries.FirstOrDefault(e => e.Name.EndsWith(".kml")));
if (docEntry == null)
{
throw new ArgumentException("No KML entry found in " + archiveFile);
}
var imageOverlays = await Task.Run(() =>
{
var kmlDocument = new XmlDocument();
using (var docStream = docEntry.Open())
{
kmlDocument.Load(docStream);
}
return ReadGroundOverlays(kmlDocument).ToList();
});
foreach (var imageOverlay in imageOverlays)
{
var imageEntry = await Task.Run(() => archive.GetEntry(imageOverlay.ImagePath));
if (imageEntry != null)
{
using (var zipStream = imageEntry.Open())
using (var memoryStream = new MemoryStream())
{
await zipStream.CopyToAsync(memoryStream);
memoryStream.Seek(0, SeekOrigin.Begin);
imageOverlay.ImageSource = await ImageLoader.LoadImageAsync(memoryStream);
}
}
}
return imageOverlays;
}
}
private static async Task<IEnumerable<ImageOverlay>> ReadGroundOverlaysFromFileAsync(string docFile)
{
docFile = Path.GetFullPath(docFile);
var docUri = new Uri(docFile);
var imageOverlays = await Task.Run(() =>
{
var kmlDocument = new XmlDocument();
kmlDocument.Load(docFile);
return ReadGroundOverlays(kmlDocument).ToList();
});
foreach (var imageOverlay in imageOverlays)
{
imageOverlay.ImageSource = await ImageLoader.LoadImageAsync(new Uri(docUri, imageOverlay.ImagePath));
}
return imageOverlays;
}
private static IEnumerable<ImageOverlay> ReadGroundOverlays(XmlDocument kmlDocument)
{
foreach (XmlElement groundOverlayElement in kmlDocument.GetElementsByTagName("GroundOverlay"))
{
LatLonBox latLonBox = null;
string imagePath = null;
int zIndex = 0;
foreach (var childElement in groundOverlayElement.ChildNodes.OfType<XmlElement>())
{
switch (childElement.LocalName)
{
case "LatLonBox":
latLonBox = ReadLatLonBox(childElement);
break;
case "Icon":
imagePath = ReadImagePath(childElement);
break;
case "drawOrder":
int.TryParse(childElement.InnerText.Trim(), out zIndex);
break;
}
}
if (latLonBox != null && imagePath != null)
{
yield return new ImageOverlay(latLonBox, imagePath, zIndex);
}
}
}
private static string ReadImagePath(XmlElement element)
{
string href = null;
foreach (var childElement in element.ChildNodes.OfType<XmlElement>())
{
switch (childElement.LocalName)
{
case "href":
href = childElement.InnerText.Trim();
break;
}
}
return href;
}
private static LatLonBox ReadLatLonBox(XmlElement element)
{
double north = double.NaN;
double south = double.NaN;
double east = double.NaN;
double west = double.NaN;
double rotation = 0d;
foreach (var childElement in element.ChildNodes.OfType<XmlElement>())
{
switch (childElement.LocalName)
{
case "north":
double.TryParse(childElement.InnerText.Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out north);
break;
case "south":
double.TryParse(childElement.InnerText.Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out south);
break;
case "east":
double.TryParse(childElement.InnerText.Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out east);
break;
case "west":
double.TryParse(childElement.InnerText.Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out west);
break;
case "rotation":
double.TryParse(childElement.InnerText.Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out rotation);
break;
}
}
return !double.IsNaN(north) && !double.IsNaN(south) && !double.IsNaN(east) && !double.IsNaN(west)
? new LatLonBox(south, west, north, east, rotation)
: null;
}
}
}

View file

@ -77,6 +77,9 @@
<Compile Include="..\Shared\GnomonicProjection.cs"> <Compile Include="..\Shared\GnomonicProjection.cs">
<Link>GnomonicProjection.cs</Link> <Link>GnomonicProjection.cs</Link>
</Compile> </Compile>
<Compile Include="..\Shared\GroundOverlayPanel.cs">
<Link>GroundOverlayPanel.cs</Link>
</Compile>
<Compile Include="..\Shared\ImageFileCache.cs"> <Compile Include="..\Shared\ImageFileCache.cs">
<Link>ImageFileCache.cs</Link> <Link>ImageFileCache.cs</Link>
</Compile> </Compile>

View file

@ -33,6 +33,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup Condition="'$(TargetFramework)'=='net48' or '$(TargetFramework)'=='net462'"> <ItemGroup Condition="'$(TargetFramework)'=='net48' or '$(TargetFramework)'=='net462'">
<Reference Include="System.IO.Compression" />
<Reference Include="System.Net.Http" /> <Reference Include="System.Net.Http" />
<Reference Include="System.Runtime.Caching" /> <Reference Include="System.Runtime.Caching" />
</ItemGroup> </ItemGroup>

View file

@ -33,12 +33,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WpfApplication", "SampleApp
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MapProjections.UWP", "MapProjections\UWP\MapProjections.UWP.csproj", "{9EE69591-5EDC-45E3-893E-2F9A4B82D538}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MapProjections.UWP", "MapProjections\UWP\MapProjections.UWP.csproj", "{9EE69591-5EDC-45E3-893E-2F9A4B82D538}"
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "MapImages", "MapImages", "{2FDC8B91-FB95-4C57-8183-63587FBFE180}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MapImages.WPF", "MapImages\WPF\MapImages.WPF.csproj", "{52042F63-563A-45BB-9A08-A8635AAAB84C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MapImages.UWP", "MapImages\UWP\MapImages.UWP.csproj", "{BE08B7BC-8C89-4837-BCE7-EDDDABEAB372}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SQLiteCache", "SQLiteCache", "{96FD1258-1597-48A2-8D64-1ADAE13E886A}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SQLiteCache", "SQLiteCache", "{96FD1258-1597-48A2-8D64-1ADAE13E886A}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SQLiteCache.UWP", "SQLiteCache\UWP\SQLiteCache.UWP.csproj", "{56DFA7CF-F31D-45CE-9C36-DA8DBB8413B1}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SQLiteCache.UWP", "SQLiteCache\UWP\SQLiteCache.UWP.csproj", "{56DFA7CF-F31D-45CE-9C36-DA8DBB8413B1}"
@ -53,8 +47,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SQLiteCache.WinUI", "SQLite
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MapProjections.WinUI", "MapProjections\WinUI\MapProjections.WinUI.csproj", "{3572F71A-83FE-459D-8370-002CA28827FE}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MapProjections.WinUI", "MapProjections\WinUI\MapProjections.WinUI.csproj", "{3572F71A-83FE-459D-8370-002CA28827FE}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MapImages.WinUI", "MapImages\WinUI\MapImages.WinUI.csproj", "{1F9FBADF-65C0-453D-9B45-7A88044F807F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MBTiles.WinUI", "MBTiles\WinUI\MBTiles.WinUI.csproj", "{817D606F-A22D-485C-89CF-86062C8E97EF}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MBTiles.WinUI", "MBTiles\WinUI\MBTiles.WinUI.csproj", "{817D606F-A22D-485C-89CF-86062C8E97EF}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WinUiApp", "SampleApps\WinUiApp\WinUiApp.csproj", "{751EF297-7CF4-4879-BA8F-42661FA68668}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WinUiApp", "SampleApps\WinUiApp\WinUiApp.csproj", "{751EF297-7CF4-4879-BA8F-42661FA68668}"
@ -69,7 +61,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MapUiTools.WinUI", "MapUiTo
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MapUiTools.WPF", "MapUiTools\WPF\MapUiTools.WPF.csproj", "{12430DAE-DC53-4C37-95D5-B8923B5FD3D7}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MapUiTools.WPF", "MapUiTools\WPF\MapUiTools.WPF.csproj", "{12430DAE-DC53-4C37-95D5-B8923B5FD3D7}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Maps.WinUI", "SampleApps\Maps.WinUI\Maps.WinUI.csproj", "{780437BF-C773-448B-989E-6FB13A7B1F49}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Maps.WinUI", "SampleApps\Maps.WinUI\Maps.WinUI.csproj", "{780437BF-C773-448B-989E-6FB13A7B1F49}"
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -251,38 +243,6 @@ Global
{9EE69591-5EDC-45E3-893E-2F9A4B82D538}.Release|x64.Build.0 = Release|Any CPU {9EE69591-5EDC-45E3-893E-2F9A4B82D538}.Release|x64.Build.0 = Release|Any CPU
{9EE69591-5EDC-45E3-893E-2F9A4B82D538}.Release|x86.ActiveCfg = Release|Any CPU {9EE69591-5EDC-45E3-893E-2F9A4B82D538}.Release|x86.ActiveCfg = Release|Any CPU
{9EE69591-5EDC-45E3-893E-2F9A4B82D538}.Release|x86.Build.0 = Release|Any CPU {9EE69591-5EDC-45E3-893E-2F9A4B82D538}.Release|x86.Build.0 = Release|Any CPU
{52042F63-563A-45BB-9A08-A8635AAAB84C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{52042F63-563A-45BB-9A08-A8635AAAB84C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{52042F63-563A-45BB-9A08-A8635AAAB84C}.Debug|arm64.ActiveCfg = Debug|Any CPU
{52042F63-563A-45BB-9A08-A8635AAAB84C}.Debug|arm64.Build.0 = Debug|Any CPU
{52042F63-563A-45BB-9A08-A8635AAAB84C}.Debug|x64.ActiveCfg = Debug|Any CPU
{52042F63-563A-45BB-9A08-A8635AAAB84C}.Debug|x64.Build.0 = Debug|Any CPU
{52042F63-563A-45BB-9A08-A8635AAAB84C}.Debug|x86.ActiveCfg = Debug|Any CPU
{52042F63-563A-45BB-9A08-A8635AAAB84C}.Debug|x86.Build.0 = Debug|Any CPU
{52042F63-563A-45BB-9A08-A8635AAAB84C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{52042F63-563A-45BB-9A08-A8635AAAB84C}.Release|Any CPU.Build.0 = Release|Any CPU
{52042F63-563A-45BB-9A08-A8635AAAB84C}.Release|arm64.ActiveCfg = Release|Any CPU
{52042F63-563A-45BB-9A08-A8635AAAB84C}.Release|arm64.Build.0 = Release|Any CPU
{52042F63-563A-45BB-9A08-A8635AAAB84C}.Release|x64.ActiveCfg = Release|Any CPU
{52042F63-563A-45BB-9A08-A8635AAAB84C}.Release|x64.Build.0 = Release|Any CPU
{52042F63-563A-45BB-9A08-A8635AAAB84C}.Release|x86.ActiveCfg = Release|Any CPU
{52042F63-563A-45BB-9A08-A8635AAAB84C}.Release|x86.Build.0 = Release|Any CPU
{BE08B7BC-8C89-4837-BCE7-EDDDABEAB372}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BE08B7BC-8C89-4837-BCE7-EDDDABEAB372}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BE08B7BC-8C89-4837-BCE7-EDDDABEAB372}.Debug|arm64.ActiveCfg = Debug|Any CPU
{BE08B7BC-8C89-4837-BCE7-EDDDABEAB372}.Debug|arm64.Build.0 = Debug|Any CPU
{BE08B7BC-8C89-4837-BCE7-EDDDABEAB372}.Debug|x64.ActiveCfg = Debug|Any CPU
{BE08B7BC-8C89-4837-BCE7-EDDDABEAB372}.Debug|x64.Build.0 = Debug|Any CPU
{BE08B7BC-8C89-4837-BCE7-EDDDABEAB372}.Debug|x86.ActiveCfg = Debug|Any CPU
{BE08B7BC-8C89-4837-BCE7-EDDDABEAB372}.Debug|x86.Build.0 = Debug|Any CPU
{BE08B7BC-8C89-4837-BCE7-EDDDABEAB372}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BE08B7BC-8C89-4837-BCE7-EDDDABEAB372}.Release|Any CPU.Build.0 = Release|Any CPU
{BE08B7BC-8C89-4837-BCE7-EDDDABEAB372}.Release|arm64.ActiveCfg = Release|Any CPU
{BE08B7BC-8C89-4837-BCE7-EDDDABEAB372}.Release|arm64.Build.0 = Release|Any CPU
{BE08B7BC-8C89-4837-BCE7-EDDDABEAB372}.Release|x64.ActiveCfg = Release|Any CPU
{BE08B7BC-8C89-4837-BCE7-EDDDABEAB372}.Release|x64.Build.0 = Release|Any CPU
{BE08B7BC-8C89-4837-BCE7-EDDDABEAB372}.Release|x86.ActiveCfg = Release|Any CPU
{BE08B7BC-8C89-4837-BCE7-EDDDABEAB372}.Release|x86.Build.0 = Release|Any CPU
{56DFA7CF-F31D-45CE-9C36-DA8DBB8413B1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {56DFA7CF-F31D-45CE-9C36-DA8DBB8413B1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{56DFA7CF-F31D-45CE-9C36-DA8DBB8413B1}.Debug|Any CPU.Build.0 = Debug|Any CPU {56DFA7CF-F31D-45CE-9C36-DA8DBB8413B1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{56DFA7CF-F31D-45CE-9C36-DA8DBB8413B1}.Debug|arm64.ActiveCfg = Debug|Any CPU {56DFA7CF-F31D-45CE-9C36-DA8DBB8413B1}.Debug|arm64.ActiveCfg = Debug|Any CPU
@ -379,22 +339,6 @@ Global
{3572F71A-83FE-459D-8370-002CA28827FE}.Release|x64.Build.0 = Release|Any CPU {3572F71A-83FE-459D-8370-002CA28827FE}.Release|x64.Build.0 = Release|Any CPU
{3572F71A-83FE-459D-8370-002CA28827FE}.Release|x86.ActiveCfg = Release|Any CPU {3572F71A-83FE-459D-8370-002CA28827FE}.Release|x86.ActiveCfg = Release|Any CPU
{3572F71A-83FE-459D-8370-002CA28827FE}.Release|x86.Build.0 = Release|Any CPU {3572F71A-83FE-459D-8370-002CA28827FE}.Release|x86.Build.0 = Release|Any CPU
{1F9FBADF-65C0-453D-9B45-7A88044F807F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1F9FBADF-65C0-453D-9B45-7A88044F807F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1F9FBADF-65C0-453D-9B45-7A88044F807F}.Debug|arm64.ActiveCfg = Debug|Any CPU
{1F9FBADF-65C0-453D-9B45-7A88044F807F}.Debug|arm64.Build.0 = Debug|Any CPU
{1F9FBADF-65C0-453D-9B45-7A88044F807F}.Debug|x64.ActiveCfg = Debug|Any CPU
{1F9FBADF-65C0-453D-9B45-7A88044F807F}.Debug|x64.Build.0 = Debug|Any CPU
{1F9FBADF-65C0-453D-9B45-7A88044F807F}.Debug|x86.ActiveCfg = Debug|Any CPU
{1F9FBADF-65C0-453D-9B45-7A88044F807F}.Debug|x86.Build.0 = Debug|Any CPU
{1F9FBADF-65C0-453D-9B45-7A88044F807F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1F9FBADF-65C0-453D-9B45-7A88044F807F}.Release|Any CPU.Build.0 = Release|Any CPU
{1F9FBADF-65C0-453D-9B45-7A88044F807F}.Release|arm64.ActiveCfg = Release|Any CPU
{1F9FBADF-65C0-453D-9B45-7A88044F807F}.Release|arm64.Build.0 = Release|Any CPU
{1F9FBADF-65C0-453D-9B45-7A88044F807F}.Release|x64.ActiveCfg = Release|Any CPU
{1F9FBADF-65C0-453D-9B45-7A88044F807F}.Release|x64.Build.0 = Release|Any CPU
{1F9FBADF-65C0-453D-9B45-7A88044F807F}.Release|x86.ActiveCfg = Release|Any CPU
{1F9FBADF-65C0-453D-9B45-7A88044F807F}.Release|x86.Build.0 = Release|Any CPU
{817D606F-A22D-485C-89CF-86062C8E97EF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {817D606F-A22D-485C-89CF-86062C8E97EF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{817D606F-A22D-485C-89CF-86062C8E97EF}.Debug|Any CPU.Build.0 = Debug|Any CPU {817D606F-A22D-485C-89CF-86062C8E97EF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{817D606F-A22D-485C-89CF-86062C8E97EF}.Debug|arm64.ActiveCfg = Debug|Any CPU {817D606F-A22D-485C-89CF-86062C8E97EF}.Debug|arm64.ActiveCfg = Debug|Any CPU
@ -538,15 +482,12 @@ Global
{426C21C0-5F14-491F-BCD1-6D2993510420} = {7BC11E28-8D3B-4C5B-AC08-AB249CC95F6D} {426C21C0-5F14-491F-BCD1-6D2993510420} = {7BC11E28-8D3B-4C5B-AC08-AB249CC95F6D}
{F92DA93D-75DB-4308-A5F9-6B4C3908A675} = {8F2103C2-78AF-4810-8FB9-67572F50C8FC} {F92DA93D-75DB-4308-A5F9-6B4C3908A675} = {8F2103C2-78AF-4810-8FB9-67572F50C8FC}
{9EE69591-5EDC-45E3-893E-2F9A4B82D538} = {7BC11E28-8D3B-4C5B-AC08-AB249CC95F6D} {9EE69591-5EDC-45E3-893E-2F9A4B82D538} = {7BC11E28-8D3B-4C5B-AC08-AB249CC95F6D}
{52042F63-563A-45BB-9A08-A8635AAAB84C} = {2FDC8B91-FB95-4C57-8183-63587FBFE180}
{BE08B7BC-8C89-4837-BCE7-EDDDABEAB372} = {2FDC8B91-FB95-4C57-8183-63587FBFE180}
{56DFA7CF-F31D-45CE-9C36-DA8DBB8413B1} = {96FD1258-1597-48A2-8D64-1ADAE13E886A} {56DFA7CF-F31D-45CE-9C36-DA8DBB8413B1} = {96FD1258-1597-48A2-8D64-1ADAE13E886A}
{0109C2F0-BA2C-420F-B2CA-DB5B29B1A349} = {96FD1258-1597-48A2-8D64-1ADAE13E886A} {0109C2F0-BA2C-420F-B2CA-DB5B29B1A349} = {96FD1258-1597-48A2-8D64-1ADAE13E886A}
{ACA8E56C-0F82-4010-A83E-2DBFF5D16919} = {52AECE49-F314-4F76-98F2-FA800F07824B} {ACA8E56C-0F82-4010-A83E-2DBFF5D16919} = {52AECE49-F314-4F76-98F2-FA800F07824B}
{DFE09FD5-530D-48AB-8A46-4611F21BBBC3} = {261905DE-9653-4567-B498-1F46BEA2A4F3} {DFE09FD5-530D-48AB-8A46-4611F21BBBC3} = {261905DE-9653-4567-B498-1F46BEA2A4F3}
{E33FC359-F713-462C-8A8E-7EEA15E36BE1} = {96FD1258-1597-48A2-8D64-1ADAE13E886A} {E33FC359-F713-462C-8A8E-7EEA15E36BE1} = {96FD1258-1597-48A2-8D64-1ADAE13E886A}
{3572F71A-83FE-459D-8370-002CA28827FE} = {7BC11E28-8D3B-4C5B-AC08-AB249CC95F6D} {3572F71A-83FE-459D-8370-002CA28827FE} = {7BC11E28-8D3B-4C5B-AC08-AB249CC95F6D}
{1F9FBADF-65C0-453D-9B45-7A88044F807F} = {2FDC8B91-FB95-4C57-8183-63587FBFE180}
{817D606F-A22D-485C-89CF-86062C8E97EF} = {CEAD0EA1-A971-4F5F-9EAE-C72F75D1F737} {817D606F-A22D-485C-89CF-86062C8E97EF} = {CEAD0EA1-A971-4F5F-9EAE-C72F75D1F737}
{751EF297-7CF4-4879-BA8F-42661FA68668} = {8F2103C2-78AF-4810-8FB9-67572F50C8FC} {751EF297-7CF4-4879-BA8F-42661FA68668} = {8F2103C2-78AF-4810-8FB9-67572F50C8FC}
{AC8C7BE0-9E72-434B-8BF3-FAEFAC2E859C} = {8F2103C2-78AF-4810-8FB9-67572F50C8FC} {AC8C7BE0-9E72-434B-8BF3-FAEFAC2E859C} = {8F2103C2-78AF-4810-8FB9-67572F50C8FC}