From b677eb8c92442e66e194b5b7a48ff34211e695e2 Mon Sep 17 00:00:00 2001 From: MITHUN KUMAR Date: Sat, 29 Nov 2025 09:14:43 +0000 Subject: [PATCH 1/2] Register property changed handler to react to date changes so the item can be moved and Unit test also created. --- Files.sln | 101 +++++++++++++++++ .../BulkConcurrentObservableCollection.cs | 103 ++++++++++++++++++ ...BulkConcurrentObservableCollectionTests.cs | 63 +++++++++++ .../Files.App.UnitTests.csproj | 18 +++ 4 files changed, 285 insertions(+) create mode 100644 Files.sln create mode 100644 tests/Files.App.UnitTests/BulkConcurrentObservableCollectionTests.cs create mode 100644 tests/Files.App.UnitTests/Files.App.UnitTests.csproj diff --git a/Files.sln b/Files.sln new file mode 100644 index 000000000000..b4d7405956ad --- /dev/null +++ b/Files.sln @@ -0,0 +1,101 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.2.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{0AB3BF05-4346-4AA6-1389-037BE0695223}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{827E0CD3-B72D-47B6-A68D-7590B98EB39B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Files.InteractionTests", "tests\Files.InteractionTests\Files.InteractionTests.csproj", "{9A20CF5B-549E-FB0A-4791-91CA4FFCCFFF}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Files.App.UITests", "tests\Files.App.UITests\Files.App.UITests.csproj", "{85D62465-0545-08C0-6135-FB568D81A323}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Files.Core.SourceGenerator", "src\Files.Core.SourceGenerator\Files.Core.SourceGenerator.csproj", "{7B50ED23-B535-E658-9542-00885ED406FA}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Files.Core.Storage", "src\Files.Core.Storage\Files.Core.Storage.csproj", "{0CD123D7-CAE3-0F58-73C0-8BF39753B788}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Files.App.Server", "src\Files.App.Server\Files.App.Server.csproj", "{A9FC40D5-7AA8-6EB5-C5A5-F5075045DBCC}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Files.App.Controls", "src\Files.App.Controls\Files.App.Controls.csproj", "{98A9E6D7-7C0E-1E78-8CE6-6E42C8A70B34}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Files.App.Storage", "src\Files.App.Storage\Files.App.Storage.csproj", "{C425951C-86B6-E4C0-724E-047E9A2C8599}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Files.App.CsWin32", "src\Files.App.CsWin32\Files.App.CsWin32.csproj", "{C1C83347-1524-3EBB-6B49-ECE025775668}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Files.App.BackgroundTasks", "src\Files.App.BackgroundTasks\Files.App.BackgroundTasks.csproj", "{F8B5749F-C6EA-8FE3-B03A-ACE02A8076A7}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Files.Shared", "src\Files.Shared\Files.Shared.csproj", "{6C01E445-3C11-C76F-CE47-0B9A775ACF0A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Files.App", "src\Files.App\Files.App.csproj", "{E6BD44A2-F200-6AC3-5A80-68727B1BE71B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {9A20CF5B-549E-FB0A-4791-91CA4FFCCFFF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9A20CF5B-549E-FB0A-4791-91CA4FFCCFFF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9A20CF5B-549E-FB0A-4791-91CA4FFCCFFF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9A20CF5B-549E-FB0A-4791-91CA4FFCCFFF}.Release|Any CPU.Build.0 = Release|Any CPU + {85D62465-0545-08C0-6135-FB568D81A323}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {85D62465-0545-08C0-6135-FB568D81A323}.Debug|Any CPU.Build.0 = Debug|Any CPU + {85D62465-0545-08C0-6135-FB568D81A323}.Release|Any CPU.ActiveCfg = Release|Any CPU + {85D62465-0545-08C0-6135-FB568D81A323}.Release|Any CPU.Build.0 = Release|Any CPU + {7B50ED23-B535-E658-9542-00885ED406FA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7B50ED23-B535-E658-9542-00885ED406FA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7B50ED23-B535-E658-9542-00885ED406FA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7B50ED23-B535-E658-9542-00885ED406FA}.Release|Any CPU.Build.0 = Release|Any CPU + {0CD123D7-CAE3-0F58-73C0-8BF39753B788}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0CD123D7-CAE3-0F58-73C0-8BF39753B788}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0CD123D7-CAE3-0F58-73C0-8BF39753B788}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0CD123D7-CAE3-0F58-73C0-8BF39753B788}.Release|Any CPU.Build.0 = Release|Any CPU + {A9FC40D5-7AA8-6EB5-C5A5-F5075045DBCC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A9FC40D5-7AA8-6EB5-C5A5-F5075045DBCC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A9FC40D5-7AA8-6EB5-C5A5-F5075045DBCC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A9FC40D5-7AA8-6EB5-C5A5-F5075045DBCC}.Release|Any CPU.Build.0 = Release|Any CPU + {98A9E6D7-7C0E-1E78-8CE6-6E42C8A70B34}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {98A9E6D7-7C0E-1E78-8CE6-6E42C8A70B34}.Debug|Any CPU.Build.0 = Debug|Any CPU + {98A9E6D7-7C0E-1E78-8CE6-6E42C8A70B34}.Release|Any CPU.ActiveCfg = Release|Any CPU + {98A9E6D7-7C0E-1E78-8CE6-6E42C8A70B34}.Release|Any CPU.Build.0 = Release|Any CPU + {C425951C-86B6-E4C0-724E-047E9A2C8599}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C425951C-86B6-E4C0-724E-047E9A2C8599}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C425951C-86B6-E4C0-724E-047E9A2C8599}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C425951C-86B6-E4C0-724E-047E9A2C8599}.Release|Any CPU.Build.0 = Release|Any CPU + {C1C83347-1524-3EBB-6B49-ECE025775668}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C1C83347-1524-3EBB-6B49-ECE025775668}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C1C83347-1524-3EBB-6B49-ECE025775668}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C1C83347-1524-3EBB-6B49-ECE025775668}.Release|Any CPU.Build.0 = Release|Any CPU + {F8B5749F-C6EA-8FE3-B03A-ACE02A8076A7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F8B5749F-C6EA-8FE3-B03A-ACE02A8076A7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F8B5749F-C6EA-8FE3-B03A-ACE02A8076A7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F8B5749F-C6EA-8FE3-B03A-ACE02A8076A7}.Release|Any CPU.Build.0 = Release|Any CPU + {6C01E445-3C11-C76F-CE47-0B9A775ACF0A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6C01E445-3C11-C76F-CE47-0B9A775ACF0A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6C01E445-3C11-C76F-CE47-0B9A775ACF0A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6C01E445-3C11-C76F-CE47-0B9A775ACF0A}.Release|Any CPU.Build.0 = Release|Any CPU + {E6BD44A2-F200-6AC3-5A80-68727B1BE71B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E6BD44A2-F200-6AC3-5A80-68727B1BE71B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E6BD44A2-F200-6AC3-5A80-68727B1BE71B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E6BD44A2-F200-6AC3-5A80-68727B1BE71B}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {9A20CF5B-549E-FB0A-4791-91CA4FFCCFFF} = {0AB3BF05-4346-4AA6-1389-037BE0695223} + {85D62465-0545-08C0-6135-FB568D81A323} = {0AB3BF05-4346-4AA6-1389-037BE0695223} + {7B50ED23-B535-E658-9542-00885ED406FA} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B} + {0CD123D7-CAE3-0F58-73C0-8BF39753B788} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B} + {A9FC40D5-7AA8-6EB5-C5A5-F5075045DBCC} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B} + {98A9E6D7-7C0E-1E78-8CE6-6E42C8A70B34} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B} + {C425951C-86B6-E4C0-724E-047E9A2C8599} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B} + {C1C83347-1524-3EBB-6B49-ECE025775668} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B} + {F8B5749F-C6EA-8FE3-B03A-ACE02A8076A7} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B} + {6C01E445-3C11-C76F-CE47-0B9A775ACF0A} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B} + {E6BD44A2-F200-6AC3-5A80-68727B1BE71B} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {8E21E423-8E7A-40CB-BE6B-5B2B56256E35} + EndGlobalSection +EndGlobal diff --git a/src/Files.App/Utils/Storage/Collection/BulkConcurrentObservableCollection.cs b/src/Files.App/Utils/Storage/Collection/BulkConcurrentObservableCollection.cs index 528f1e9a0b46..5545be75a3d6 100644 --- a/src/Files.App/Utils/Storage/Collection/BulkConcurrentObservableCollection.cs +++ b/src/Files.App/Utils/Storage/Collection/BulkConcurrentObservableCollection.cs @@ -2,12 +2,14 @@ // Licensed under the MIT License. using System.Collections.Specialized; +using System.Runtime.CompilerServices; namespace Files.App.Utils.Storage { [DebuggerTypeProxy(typeof(CollectionDebugView<>))] [DebuggerDisplay("Count = {Count}")] public class BulkConcurrentObservableCollection : INotifyCollectionChanged, INotifyPropertyChanged, ICollection, IList, ICollection, IList + where T : class { protected bool isBulkOperationStarted; private readonly object syncRoot = new object(); @@ -200,7 +202,10 @@ private void AddItemsToGroup(IEnumerable items, CancellationToken token = def GroupedCollection?.Add(group); GroupedCollection!.IsSorted = false; } + // Register property changed handler to react to date changes so the item can be moved + RegisterPropertyChanged(item); } + } private void RemoveItemsFromGroup(IEnumerable items) @@ -216,6 +221,100 @@ private void RemoveItemsFromGroup(IEnumerable items) if (group.Count == 0) GroupedCollection?.Remove(group); } + + // Unregister change handler when item is removed from groups/collection + UnregisterPropertyChanged(item); + } + } + + private readonly ConditionalWeakTable propertyChangedHandlers = new(); + + private void RegisterPropertyChanged(T item) + { + if (item is INotifyPropertyChanged notifier) + { + // avoid duplicate handler + if (propertyChangedHandlers.TryGetValue(item, out _)) + return; + + PropertyChangedEventHandler handler = (s, e) => + { + // React to date fields changing — move item between groups if needed + if (e.PropertyName is "ItemDateModifiedReal" or "ItemDateCreatedReal" or "ItemDateAccessedReal" or "ItemDateDeletedReal") + OnItemDatePropertyChanged((T)s); + }; + + propertyChangedHandlers.Add(item, handler); + notifier.PropertyChanged += handler; + } + } + + private void UnregisterPropertyChanged(T item) + { + if (item is INotifyPropertyChanged notifier) + { + if (propertyChangedHandlers.TryGetValue(item, out var handler)) + { + notifier.PropertyChanged -= handler; + propertyChangedHandlers.Remove(item); + } + } + } + + private void OnItemDatePropertyChanged(T item) + { + if (!IsGrouped || ItemGroupKeySelector is null) + return; + + var newKey = GetGroupKeyForItem(item); + if (newKey is null) + return; + + var oldKey = (item is IGroupableItem groupable) ? groupable.Key : null; + if (oldKey == newKey) + return; + + // Move item between groups under a lock to keep collection consistent + lock (syncRoot) + { + // remove from old group + if (!string.IsNullOrEmpty(oldKey)) + { + var oldGroup = GroupedCollection?.Where(x => x.Model.Key == oldKey).FirstOrDefault(); + if (oldGroup is not null && oldGroup.Contains(item)) + { + oldGroup.Remove(item); + if (oldGroup.Count == 0) + GroupedCollection?.Remove(oldGroup); + } + } + + // add to new group + var groups = GroupedCollection?.Where(x => x.Model.Key == newKey); + if (item is IGroupableItem gp) + gp.Key = newKey; + + if (groups is not null && groups.Any()) + { + var gp = groups.First(); + if (!gp.Contains(item)) + gp.Add(item); + gp.IsSorted = false; + } + else + { + var group = new GroupedCollection(newKey) + { + item + }; + + group.GetExtendedGroupHeaderInfo = GetExtendedGroupHeaderInfo; + if (GetGroupHeaderInfo is not null) + GetGroupHeaderInfo.Invoke(group); + + GroupedCollection?.Add(group); + GroupedCollection!.IsSorted = false; + } } } @@ -265,6 +364,10 @@ public void Clear() { lock (syncRoot) { + // Unregister handlers for all items before clearing + foreach (var it in collection.ToList()) + UnregisterPropertyChanged(it); + collection.Clear(); GroupedCollection?.Clear(); diff --git a/tests/Files.App.UnitTests/BulkConcurrentObservableCollectionTests.cs b/tests/Files.App.UnitTests/BulkConcurrentObservableCollectionTests.cs new file mode 100644 index 000000000000..726c4564b30a --- /dev/null +++ b/tests/Files.App.UnitTests/BulkConcurrentObservableCollectionTests.cs @@ -0,0 +1,63 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; + +namespace Files.App.UnitTests +{ + [TestClass] + public class BulkConcurrentObservableCollectionTests + { + private class TestItem : INotifyPropertyChanged, Utils.Storage.IGroupableItem + { + public string Key { get; set; } + + private DateTimeOffset _date; + public DateTimeOffset ItemDateModifiedReal + { + get => _date; + set + { + if (_date != value) + { + _date = value; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ItemDateModifiedReal))); + } + } + } + + public event PropertyChangedEventHandler? PropertyChanged; + + public override string ToString() => ItemDateModifiedReal.ToString(); + } + + [TestMethod] + public void When_ItemDateChanges_ItemMovesBetweenGroups() + { + // Group by logic: within 7 days = "Recent", else "Old" + var col = new Utils.Storage.BulkConcurrentObservableCollection(); + col.ItemGroupKeySelector = item => (DateTimeOffset.Now - item.ItemDateModifiedReal).TotalDays <= 7 ? "Recent" : "Old"; + + var recentItem = new TestItem { ItemDateModifiedReal = DateTimeOffset.Now.AddDays(-3) }; + var oldItem = new TestItem { ItemDateModifiedReal = DateTimeOffset.Now.AddDays(-400) }; + + col.Add(recentItem); + col.Add(oldItem); + + Assert.IsNotNull(col.GroupedCollection); + Assert.AreEqual(2, col.GroupedCollection.Count); + + // Now change recentItem date so it becomes old + recentItem.ItemDateModifiedReal = DateTimeOffset.Now.AddDays(-400); + + // It should have been moved to the old group + var recentGroup = col.GroupedCollection.FirstOrDefault(g => g.Model.Key == "Recent"); + var oldGroup = col.GroupedCollection.FirstOrDefault(g => g.Model.Key == "Old"); + + Assert.IsTrue(recentGroup == null || !recentGroup.Contains(recentItem), "recentItem should not be in recent group anymore"); + Assert.IsNotNull(oldGroup, "old group should exist"); + Assert.IsTrue(oldGroup.Contains(recentItem), "recentItem should be in old group now"); + } + } +} diff --git a/tests/Files.App.UnitTests/Files.App.UnitTests.csproj b/tests/Files.App.UnitTests/Files.App.UnitTests.csproj new file mode 100644 index 000000000000..e6c28f77e92d --- /dev/null +++ b/tests/Files.App.UnitTests/Files.App.UnitTests.csproj @@ -0,0 +1,18 @@ + + + + net9.0 + false + + + + + + + + + + + + + From c0b71474cd4771e02a1e93645eb080d68971ef35 Mon Sep 17 00:00:00 2001 From: MITHUN KUMAR Date: Mon, 1 Dec 2025 22:41:40 +0530 Subject: [PATCH 2/2] Delete Files.sln Removing unrelated changes. Signed-off-by: MITHUN KUMAR --- Files.sln | 101 ------------------------------------------------------ 1 file changed, 101 deletions(-) delete mode 100644 Files.sln diff --git a/Files.sln b/Files.sln deleted file mode 100644 index b4d7405956ad..000000000000 --- a/Files.sln +++ /dev/null @@ -1,101 +0,0 @@ -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.5.2.0 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{0AB3BF05-4346-4AA6-1389-037BE0695223}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{827E0CD3-B72D-47B6-A68D-7590B98EB39B}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Files.InteractionTests", "tests\Files.InteractionTests\Files.InteractionTests.csproj", "{9A20CF5B-549E-FB0A-4791-91CA4FFCCFFF}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Files.App.UITests", "tests\Files.App.UITests\Files.App.UITests.csproj", "{85D62465-0545-08C0-6135-FB568D81A323}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Files.Core.SourceGenerator", "src\Files.Core.SourceGenerator\Files.Core.SourceGenerator.csproj", "{7B50ED23-B535-E658-9542-00885ED406FA}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Files.Core.Storage", "src\Files.Core.Storage\Files.Core.Storage.csproj", "{0CD123D7-CAE3-0F58-73C0-8BF39753B788}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Files.App.Server", "src\Files.App.Server\Files.App.Server.csproj", "{A9FC40D5-7AA8-6EB5-C5A5-F5075045DBCC}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Files.App.Controls", "src\Files.App.Controls\Files.App.Controls.csproj", "{98A9E6D7-7C0E-1E78-8CE6-6E42C8A70B34}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Files.App.Storage", "src\Files.App.Storage\Files.App.Storage.csproj", "{C425951C-86B6-E4C0-724E-047E9A2C8599}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Files.App.CsWin32", "src\Files.App.CsWin32\Files.App.CsWin32.csproj", "{C1C83347-1524-3EBB-6B49-ECE025775668}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Files.App.BackgroundTasks", "src\Files.App.BackgroundTasks\Files.App.BackgroundTasks.csproj", "{F8B5749F-C6EA-8FE3-B03A-ACE02A8076A7}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Files.Shared", "src\Files.Shared\Files.Shared.csproj", "{6C01E445-3C11-C76F-CE47-0B9A775ACF0A}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Files.App", "src\Files.App\Files.App.csproj", "{E6BD44A2-F200-6AC3-5A80-68727B1BE71B}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {9A20CF5B-549E-FB0A-4791-91CA4FFCCFFF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9A20CF5B-549E-FB0A-4791-91CA4FFCCFFF}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9A20CF5B-549E-FB0A-4791-91CA4FFCCFFF}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9A20CF5B-549E-FB0A-4791-91CA4FFCCFFF}.Release|Any CPU.Build.0 = Release|Any CPU - {85D62465-0545-08C0-6135-FB568D81A323}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {85D62465-0545-08C0-6135-FB568D81A323}.Debug|Any CPU.Build.0 = Debug|Any CPU - {85D62465-0545-08C0-6135-FB568D81A323}.Release|Any CPU.ActiveCfg = Release|Any CPU - {85D62465-0545-08C0-6135-FB568D81A323}.Release|Any CPU.Build.0 = Release|Any CPU - {7B50ED23-B535-E658-9542-00885ED406FA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7B50ED23-B535-E658-9542-00885ED406FA}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7B50ED23-B535-E658-9542-00885ED406FA}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7B50ED23-B535-E658-9542-00885ED406FA}.Release|Any CPU.Build.0 = Release|Any CPU - {0CD123D7-CAE3-0F58-73C0-8BF39753B788}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0CD123D7-CAE3-0F58-73C0-8BF39753B788}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0CD123D7-CAE3-0F58-73C0-8BF39753B788}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0CD123D7-CAE3-0F58-73C0-8BF39753B788}.Release|Any CPU.Build.0 = Release|Any CPU - {A9FC40D5-7AA8-6EB5-C5A5-F5075045DBCC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A9FC40D5-7AA8-6EB5-C5A5-F5075045DBCC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A9FC40D5-7AA8-6EB5-C5A5-F5075045DBCC}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A9FC40D5-7AA8-6EB5-C5A5-F5075045DBCC}.Release|Any CPU.Build.0 = Release|Any CPU - {98A9E6D7-7C0E-1E78-8CE6-6E42C8A70B34}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {98A9E6D7-7C0E-1E78-8CE6-6E42C8A70B34}.Debug|Any CPU.Build.0 = Debug|Any CPU - {98A9E6D7-7C0E-1E78-8CE6-6E42C8A70B34}.Release|Any CPU.ActiveCfg = Release|Any CPU - {98A9E6D7-7C0E-1E78-8CE6-6E42C8A70B34}.Release|Any CPU.Build.0 = Release|Any CPU - {C425951C-86B6-E4C0-724E-047E9A2C8599}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C425951C-86B6-E4C0-724E-047E9A2C8599}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C425951C-86B6-E4C0-724E-047E9A2C8599}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C425951C-86B6-E4C0-724E-047E9A2C8599}.Release|Any CPU.Build.0 = Release|Any CPU - {C1C83347-1524-3EBB-6B49-ECE025775668}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C1C83347-1524-3EBB-6B49-ECE025775668}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C1C83347-1524-3EBB-6B49-ECE025775668}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C1C83347-1524-3EBB-6B49-ECE025775668}.Release|Any CPU.Build.0 = Release|Any CPU - {F8B5749F-C6EA-8FE3-B03A-ACE02A8076A7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F8B5749F-C6EA-8FE3-B03A-ACE02A8076A7}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F8B5749F-C6EA-8FE3-B03A-ACE02A8076A7}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F8B5749F-C6EA-8FE3-B03A-ACE02A8076A7}.Release|Any CPU.Build.0 = Release|Any CPU - {6C01E445-3C11-C76F-CE47-0B9A775ACF0A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6C01E445-3C11-C76F-CE47-0B9A775ACF0A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6C01E445-3C11-C76F-CE47-0B9A775ACF0A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6C01E445-3C11-C76F-CE47-0B9A775ACF0A}.Release|Any CPU.Build.0 = Release|Any CPU - {E6BD44A2-F200-6AC3-5A80-68727B1BE71B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E6BD44A2-F200-6AC3-5A80-68727B1BE71B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E6BD44A2-F200-6AC3-5A80-68727B1BE71B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E6BD44A2-F200-6AC3-5A80-68727B1BE71B}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {9A20CF5B-549E-FB0A-4791-91CA4FFCCFFF} = {0AB3BF05-4346-4AA6-1389-037BE0695223} - {85D62465-0545-08C0-6135-FB568D81A323} = {0AB3BF05-4346-4AA6-1389-037BE0695223} - {7B50ED23-B535-E658-9542-00885ED406FA} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B} - {0CD123D7-CAE3-0F58-73C0-8BF39753B788} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B} - {A9FC40D5-7AA8-6EB5-C5A5-F5075045DBCC} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B} - {98A9E6D7-7C0E-1E78-8CE6-6E42C8A70B34} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B} - {C425951C-86B6-E4C0-724E-047E9A2C8599} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B} - {C1C83347-1524-3EBB-6B49-ECE025775668} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B} - {F8B5749F-C6EA-8FE3-B03A-ACE02A8076A7} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B} - {6C01E445-3C11-C76F-CE47-0B9A775ACF0A} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B} - {E6BD44A2-F200-6AC3-5A80-68727B1BE71B} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B} - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {8E21E423-8E7A-40CB-BE6B-5B2B56256E35} - EndGlobalSection -EndGlobal