From 1375a418f9fdde904e9a326c28f6f0957e9015a3 Mon Sep 17 00:00:00 2001 From: Michael Becker Date: Sun, 20 Sep 2020 01:13:11 -0400 Subject: [PATCH] preliminary SLOOOW plugin for reading blockchain databases --- .../Editors/Blockchain/BlockchainEditor.glade | 108 ++++++++++++++++++ ...lEditor.Content.PlatformIndependent.csproj | 1 + .../BlockchainEditor.cs | 81 +++++++++++++ .../Properties/AssemblyInfo.cs | 46 ++++++++ ...or.Plugins.Blockchain.UserInterface.csproj | 60 ++++++++++ .../Associations/BitcoinBlockchain.uexml | 22 ++++ .../BitcoinBlockchainDataFormat.cs | 98 ++++++++++++++++ .../Bitcoin/ObjectModels/BitcoinBlock.cs | 27 +++++ .../ObjectModels/BitcoinBlockTransaction.cs | 20 ++++ .../BitcoinBlockchainObjectModel.cs | 36 ++++++ .../Block.cs | 8 ++ .../BlockTransaction.cs | 8 ++ .../Properties/AssemblyInfo.cs | 26 +++++ .../UniversalEditor.Plugins.Blockchain.csproj | 58 ++++++++++ UniversalEditor.sln | 14 +++ 15 files changed, 613 insertions(+) create mode 100644 Content/UniversalEditor.Content.PlatformIndependent/Editors/Blockchain/BlockchainEditor.glade create mode 100644 Plugins.UserInterface/UniversalEditor.Plugins.Blockchain.UserInterface/BlockchainEditor.cs create mode 100644 Plugins.UserInterface/UniversalEditor.Plugins.Blockchain.UserInterface/Properties/AssemblyInfo.cs create mode 100644 Plugins.UserInterface/UniversalEditor.Plugins.Blockchain.UserInterface/UniversalEditor.Plugins.Blockchain.UserInterface.csproj create mode 100644 Plugins/UniversalEditor.Plugins.Blockchain/Associations/BitcoinBlockchain.uexml create mode 100644 Plugins/UniversalEditor.Plugins.Blockchain/Bitcoin/DataFormats/BitcoinBlockchainDataFormat.cs create mode 100644 Plugins/UniversalEditor.Plugins.Blockchain/Bitcoin/ObjectModels/BitcoinBlock.cs create mode 100644 Plugins/UniversalEditor.Plugins.Blockchain/Bitcoin/ObjectModels/BitcoinBlockTransaction.cs create mode 100644 Plugins/UniversalEditor.Plugins.Blockchain/Bitcoin/ObjectModels/BitcoinBlockchainObjectModel.cs create mode 100644 Plugins/UniversalEditor.Plugins.Blockchain/Block.cs create mode 100644 Plugins/UniversalEditor.Plugins.Blockchain/BlockTransaction.cs create mode 100644 Plugins/UniversalEditor.Plugins.Blockchain/Properties/AssemblyInfo.cs create mode 100644 Plugins/UniversalEditor.Plugins.Blockchain/UniversalEditor.Plugins.Blockchain.csproj diff --git a/Content/UniversalEditor.Content.PlatformIndependent/Editors/Blockchain/BlockchainEditor.glade b/Content/UniversalEditor.Content.PlatformIndependent/Editors/Blockchain/BlockchainEditor.glade new file mode 100644 index 00000000..7461d537 --- /dev/null +++ b/Content/UniversalEditor.Content.PlatformIndependent/Editors/Blockchain/BlockchainEditor.glade @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + False + + + + + + True + False + vertical + + + True + True + in + + + True + True + tm + + + + + + True + Version + True + True + + + + 0 + + + + + + + True + Previous Block Hash + True + True + + + + 1 + + + + + + + True + Merkel Root + True + True + + + + 2 + + + + + + + True + Timestamp + True + True + + + + 3 + + + + + + + + + True + True + 0 + + + + + + diff --git a/Content/UniversalEditor.Content.PlatformIndependent/UniversalEditor.Content.PlatformIndependent.csproj b/Content/UniversalEditor.Content.PlatformIndependent/UniversalEditor.Content.PlatformIndependent.csproj index 2328f4b6..46268237 100644 --- a/Content/UniversalEditor.Content.PlatformIndependent/UniversalEditor.Content.PlatformIndependent.csproj +++ b/Content/UniversalEditor.Content.PlatformIndependent/UniversalEditor.Content.PlatformIndependent.csproj @@ -308,6 +308,7 @@ + diff --git a/Plugins.UserInterface/UniversalEditor.Plugins.Blockchain.UserInterface/BlockchainEditor.cs b/Plugins.UserInterface/UniversalEditor.Plugins.Blockchain.UserInterface/BlockchainEditor.cs new file mode 100644 index 00000000..13fa0b73 --- /dev/null +++ b/Plugins.UserInterface/UniversalEditor.Plugins.Blockchain.UserInterface/BlockchainEditor.cs @@ -0,0 +1,81 @@ +// +// MyClass.cs +// +// Author: +// Michael Becker +// +// Copyright (c) 2020 Mike Becker's Software +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +using System; +using MBS.Framework.UserInterface; +using MBS.Framework.UserInterface.Controls.ListView; +using UniversalEditor.Plugins.Blockchain.Bitcoin.ObjectModels; +using UniversalEditor.UserInterface; + +namespace UniversalEditor.Plugins.Blockchain.UserInterface +{ + [ContainerLayout("~/Editors/Blockchain/BlockchainEditor.glade")] + public class BlockchainEditor : Editor + { + private ListViewControl tv; + + private static EditorReference _er = null; + public override EditorReference MakeReference() + { + if (_er == null) + { + _er = base.MakeReference(); + _er.SupportedObjectModels.Add(typeof(BitcoinBlockchainObjectModel)); + } + return _er; + } + + protected override void OnCreated(EventArgs e) + { + base.OnCreated(e); + OnObjectModelChanged(e); + } + + protected override void OnObjectModelChanged(EventArgs e) + { + base.OnObjectModelChanged(e); + + BitcoinBlockchainObjectModel bc = (ObjectModel as BitcoinBlockchainObjectModel); + if (bc == null) return; + + if (!IsCreated) return; + + for (int i = 0; i < Math.Min(6500, bc.Blocks.Count); i++) + { + tv.Model.Rows.Add(new TreeModelRow(new TreeModelRowColumn[] + { + new TreeModelRowColumn(tv.Model.Columns[0], bc.Blocks[i].Version.ToString()), + new TreeModelRowColumn(tv.Model.Columns[1], bc.Blocks[i].PreviousBlockHash.ToString()), + new TreeModelRowColumn(tv.Model.Columns[2], bc.Blocks[i].MerkelRoot.ToString()), + new TreeModelRowColumn(tv.Model.Columns[3], bc.Blocks[i].Timestamp.ToString()) + })); + } + } + + public override void UpdateSelections() + { + } + + protected override Selection CreateSelectionInternal(object content) + { + return null; + } + } +} diff --git a/Plugins.UserInterface/UniversalEditor.Plugins.Blockchain.UserInterface/Properties/AssemblyInfo.cs b/Plugins.UserInterface/UniversalEditor.Plugins.Blockchain.UserInterface/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..3eedb02b --- /dev/null +++ b/Plugins.UserInterface/UniversalEditor.Plugins.Blockchain.UserInterface/Properties/AssemblyInfo.cs @@ -0,0 +1,46 @@ +// +// AssemblyInfo.cs +// +// Author: +// Michael Becker +// +// Copyright (c) 2020 Mike Becker's Software +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +using System.Reflection; +using System.Runtime.CompilerServices; + +// Information about this assembly is defined by the following attributes. +// Change them to the values specific to your project. + +[assembly: AssemblyTitle("UniversalEditor.Plugins.Blockchain.UserInterface")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Mike Becker's Software")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("Mike Becker's Software")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". +// The form "{Major}.{Minor}.*" will automatically update the build and revision, +// and "{Major}.{Minor}.{Build}.*" will update just the revision. + +[assembly: AssemblyVersion("1.0.*")] + +// The following attributes are used to specify the signing key for the assembly, +// if desired. See the Mono documentation for more information about signing. + +//[assembly: AssemblyDelaySign(false)] +//[assembly: AssemblyKeyFile("")] diff --git a/Plugins.UserInterface/UniversalEditor.Plugins.Blockchain.UserInterface/UniversalEditor.Plugins.Blockchain.UserInterface.csproj b/Plugins.UserInterface/UniversalEditor.Plugins.Blockchain.UserInterface/UniversalEditor.Plugins.Blockchain.UserInterface.csproj new file mode 100644 index 00000000..9f67233d --- /dev/null +++ b/Plugins.UserInterface/UniversalEditor.Plugins.Blockchain.UserInterface/UniversalEditor.Plugins.Blockchain.UserInterface.csproj @@ -0,0 +1,60 @@ + + + + Debug + AnyCPU + {B6E600F5-E5BC-4DC2-8B41-7B11EB0A11B3} + Library + UniversalEditor.Plugins.Blockchain.UserInterface + UniversalEditor.Plugins.Blockchain.UserInterface + v4.7 + 4.0.2019.12 + + + true + full + false + ..\..\Output\Debug\Plugins + DEBUG; + prompt + 4 + false + + + true + ..\..\Output\Release\Plugins + prompt + 4 + false + + + + + + + + + + + {2D4737E6-6D95-408A-90DB-8DFF38147E85} + UniversalEditor.Core + + + {30467E5C-05BC-4856-AADC-13906EF4CADD} + UniversalEditor.Essential + + + {8622EBC4-8E20-476E-B284-33D472081F5C} + UniversalEditor.UserInterface + + + {00266B21-35C9-4A7F-A6BA-D54D7FDCC25C} + MBS.Framework + + + {29E1C1BB-3EA5-4062-B62F-85EEC703FE07} + MBS.Framework.UserInterface + + + + \ No newline at end of file diff --git a/Plugins/UniversalEditor.Plugins.Blockchain/Associations/BitcoinBlockchain.uexml b/Plugins/UniversalEditor.Plugins.Blockchain/Associations/BitcoinBlockchain.uexml new file mode 100644 index 00000000..a66ed7bc --- /dev/null +++ b/Plugins/UniversalEditor.Plugins.Blockchain/Associations/BitcoinBlockchain.uexml @@ -0,0 +1,22 @@ + + + + + + + + + F9BEB4D9 + + + + + + + + + + + + + \ No newline at end of file diff --git a/Plugins/UniversalEditor.Plugins.Blockchain/Bitcoin/DataFormats/BitcoinBlockchainDataFormat.cs b/Plugins/UniversalEditor.Plugins.Blockchain/Bitcoin/DataFormats/BitcoinBlockchainDataFormat.cs new file mode 100644 index 00000000..bcab7c9b --- /dev/null +++ b/Plugins/UniversalEditor.Plugins.Blockchain/Bitcoin/DataFormats/BitcoinBlockchainDataFormat.cs @@ -0,0 +1,98 @@ +using System; +using UniversalEditor.IO; +using UniversalEditor.Plugins.Blockchain.Bitcoin.ObjectModels; + +namespace UniversalEditor.Plugins.Blockchain.Bitcoin.DataFormats +{ + public class BitcoinBlockchainDataFormat : DataFormat + { + private static DataFormatReference _dfr = null; + protected override DataFormatReference MakeReferenceInternal() + { + if (_dfr == null) + { + _dfr = base.MakeReferenceInternal(); + _dfr.Capabilities.Add(typeof(BitcoinBlockchainObjectModel), DataFormatCapabilities.All); + } + return _dfr; + } + + public int HashLength { get; set; } = 32; + + private readonly DateTime UNIX_EPOCH = new DateTime(1970, 01, 01, 00, 00, 00); + + protected override void LoadInternal(ref ObjectModel objectModel) + { + BitcoinBlockchainObjectModel blockchain = (objectModel as BitcoinBlockchainObjectModel); + if (blockchain == null) + throw new ObjectModelNotSupportedException(); + + Reader reader = Accessor.Reader; + + while (!reader.EndOfStream) + { + uint signature = reader.ReadUInt32(); + if (signature != 0xD9B4BEF9) + throw new InvalidDataFormatException("file does not begin with 0xD9B4BEF9"); + + BitcoinBlock block = new BitcoinBlock(); + uint datasize = reader.ReadUInt32(); + block.Version = reader.ReadUInt32(); + block.PreviousBlockHash = reader.ReadBytes(HashLength); + block.MerkelRoot = reader.ReadBytes(HashLength); + uint timestamp = reader.ReadUInt32(); + block.Timestamp = UNIX_EPOCH.AddSeconds(timestamp); + block.Bits = reader.ReadUInt32(); + block.Nonce = reader.ReadUInt32(); + ulong transactionCount = ReadCompactNumber(reader); + for (ulong i = 0; i < transactionCount; i++) + { + BitcoinBlockTransaction transaction = new BitcoinBlockTransaction(); + uint transactionVersion = reader.ReadUInt32(); + ulong inputs = ReadCompactNumber(reader); + for (ulong j = 0; j < inputs; j++) + { + byte[] previousOutput = reader.ReadBytes(HashLength); + uint previousOutput2 = reader.ReadUInt32(); + ulong scriptLength = ReadCompactNumber(reader); + byte[] scriptData = reader.ReadBytes(scriptLength); + uint sequence = reader.ReadUInt32(); + } + byte outputs = reader.ReadByte(); + for (int j = 0; j < outputs; j++) + { + ulong output_c = reader.ReadUInt64(); + ulong publicKeyScriptLength = ReadCompactNumber(reader); + transaction.PublicKeyScript = reader.ReadBytes(publicKeyScriptLength); + } + uint locktime = reader.ReadUInt32(); + block.Transactions.Add(transaction); + } + blockchain.Blocks.Add(block); + } + } + + private ulong ReadCompactNumber(Reader reader) + { + byte num = reader.ReadByte(); + if (num == 0xFD) + { + return reader.ReadUInt16(); + } + else if (num == 0xFE) + { + return reader.ReadUInt32(); + } + else if (num == 0xFF) + { + return reader.ReadUInt64(); + } + return num; + } + + protected override void SaveInternal(ObjectModel objectModel) + { + throw new NotImplementedException(); + } + } +} diff --git a/Plugins/UniversalEditor.Plugins.Blockchain/Bitcoin/ObjectModels/BitcoinBlock.cs b/Plugins/UniversalEditor.Plugins.Blockchain/Bitcoin/ObjectModels/BitcoinBlock.cs new file mode 100644 index 00000000..9f84b555 --- /dev/null +++ b/Plugins/UniversalEditor.Plugins.Blockchain/Bitcoin/ObjectModels/BitcoinBlock.cs @@ -0,0 +1,27 @@ +using System; +namespace UniversalEditor.Plugins.Blockchain.Bitcoin.ObjectModels +{ + public class BitcoinBlock : Block + { + public class BitcoinBlockCollection + : System.Collections.ObjectModel.Collection + { + + } + + public uint Version { get; internal set; } + public byte[] PreviousBlockHash { get; set; } + public byte[] MerkelRoot { get; set; } + public DateTime Timestamp { get; set; } + public uint Bits { get; set; } + public uint Nonce { get; set; } + public BitcoinBlockTransaction.BitcoinBlockTransactionCollection Transactions { get; } = new BitcoinBlockTransaction.BitcoinBlockTransactionCollection(); + + public override object Clone() + { + BitcoinBlock clone = new BitcoinBlock(); + clone.Version = Version; + return clone; + } + } +} diff --git a/Plugins/UniversalEditor.Plugins.Blockchain/Bitcoin/ObjectModels/BitcoinBlockTransaction.cs b/Plugins/UniversalEditor.Plugins.Blockchain/Bitcoin/ObjectModels/BitcoinBlockTransaction.cs new file mode 100644 index 00000000..d38b1022 --- /dev/null +++ b/Plugins/UniversalEditor.Plugins.Blockchain/Bitcoin/ObjectModels/BitcoinBlockTransaction.cs @@ -0,0 +1,20 @@ +using System; +namespace UniversalEditor.Plugins.Blockchain.Bitcoin.ObjectModels +{ + public class BitcoinBlockTransaction : BlockTransaction + { + public byte[] PublicKeyScript { get; set; } + + public class BitcoinBlockTransactionCollection + : System.Collections.ObjectModel.Collection + { + + } + + public override object Clone() + { + BitcoinBlockTransaction clone = new BitcoinBlockTransaction(); + return clone; + } + } +} diff --git a/Plugins/UniversalEditor.Plugins.Blockchain/Bitcoin/ObjectModels/BitcoinBlockchainObjectModel.cs b/Plugins/UniversalEditor.Plugins.Blockchain/Bitcoin/ObjectModels/BitcoinBlockchainObjectModel.cs new file mode 100644 index 00000000..56557640 --- /dev/null +++ b/Plugins/UniversalEditor.Plugins.Blockchain/Bitcoin/ObjectModels/BitcoinBlockchainObjectModel.cs @@ -0,0 +1,36 @@ +using System; +namespace UniversalEditor.Plugins.Blockchain.Bitcoin.ObjectModels +{ + public class BitcoinBlockchainObjectModel : ObjectModel + { + private static ObjectModelReference _omr = null; + protected override ObjectModelReference MakeReferenceInternal() + { + if (_omr == null) + { + _omr = base.MakeReferenceInternal(); + _omr.Path = new string[] { "Blockchain", "Bitcoin" }; + } + return _omr; + } + + public BitcoinBlock.BitcoinBlockCollection Blocks { get; } = new BitcoinBlock.BitcoinBlockCollection(); + + public override void Clear() + { + Blocks.Clear(); + } + + public override void CopyTo(ObjectModel where) + { + BitcoinBlockchainObjectModel clone = (where as BitcoinBlockchainObjectModel); + if (clone == null) + throw new ObjectModelNotSupportedException(); + + for (int i = 0; i < Blocks.Count;i++) + { + clone.Blocks.Add(Blocks[i].Clone() as BitcoinBlock); + } + } + } +} diff --git a/Plugins/UniversalEditor.Plugins.Blockchain/Block.cs b/Plugins/UniversalEditor.Plugins.Blockchain/Block.cs new file mode 100644 index 00000000..52b5d1a6 --- /dev/null +++ b/Plugins/UniversalEditor.Plugins.Blockchain/Block.cs @@ -0,0 +1,8 @@ +using System; +namespace UniversalEditor.Plugins.Blockchain +{ + public abstract class Block : ICloneable + { + public abstract object Clone(); + } +} diff --git a/Plugins/UniversalEditor.Plugins.Blockchain/BlockTransaction.cs b/Plugins/UniversalEditor.Plugins.Blockchain/BlockTransaction.cs new file mode 100644 index 00000000..aa6f8f38 --- /dev/null +++ b/Plugins/UniversalEditor.Plugins.Blockchain/BlockTransaction.cs @@ -0,0 +1,8 @@ +using System; +namespace UniversalEditor.Plugins.Blockchain +{ + public abstract class BlockTransaction : ICloneable + { + public abstract object Clone(); + } +} diff --git a/Plugins/UniversalEditor.Plugins.Blockchain/Properties/AssemblyInfo.cs b/Plugins/UniversalEditor.Plugins.Blockchain/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..197fe9ee --- /dev/null +++ b/Plugins/UniversalEditor.Plugins.Blockchain/Properties/AssemblyInfo.cs @@ -0,0 +1,26 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// Information about this assembly is defined by the following attributes. +// Change them to the values specific to your project. + +[assembly: AssemblyTitle("UniversalEditor.Plugins.Blockchain")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Mike Becker's Software")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("Mike Becker's Software")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". +// The form "{Major}.{Minor}.*" will automatically update the build and revision, +// and "{Major}.{Minor}.{Build}.*" will update just the revision. + +[assembly: AssemblyVersion("1.0.*")] + +// The following attributes are used to specify the signing key for the assembly, +// if desired. See the Mono documentation for more information about signing. + +//[assembly: AssemblyDelaySign(false)] +//[assembly: AssemblyKeyFile("")] diff --git a/Plugins/UniversalEditor.Plugins.Blockchain/UniversalEditor.Plugins.Blockchain.csproj b/Plugins/UniversalEditor.Plugins.Blockchain/UniversalEditor.Plugins.Blockchain.csproj new file mode 100644 index 00000000..cfb14715 --- /dev/null +++ b/Plugins/UniversalEditor.Plugins.Blockchain/UniversalEditor.Plugins.Blockchain.csproj @@ -0,0 +1,58 @@ + + + + Debug + AnyCPU + {C54F6BCD-60CD-4603-B0C9-CD0864455CB1} + Library + UniversalEditor.Plugins.Blockchain + UniversalEditor.Plugins.Blockchain + v4.7 + 4.0.2019.12 + + + true + full + false + ..\..\Output\Debug\Plugins + DEBUG; + prompt + 4 + false + + + true + ..\..\Output\Release\Plugins + prompt + 4 + false + + + + + + + + + + + + + + + + + + + + + + {2D4737E6-6D95-408A-90DB-8DFF38147E85} + UniversalEditor.Core + + + + + + + \ No newline at end of file diff --git a/UniversalEditor.sln b/UniversalEditor.sln index 3dfe42a5..9aca83d0 100644 --- a/UniversalEditor.sln +++ b/UniversalEditor.sln @@ -201,6 +201,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Content", "Content", "{63E2 EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MBS.Framework.UserInterface.Content.PlatformIndependent", "..\MBS.Framework.UserInterface\Content\MBS.Framework.UserInterface.Content.PlatformIndependent\MBS.Framework.UserInterface.Content.PlatformIndependent.csproj", "{FAE48F29-DB35-4CD6-8A55-6C1FDDFBE6AF}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UniversalEditor.Plugins.Blockchain", "Plugins\UniversalEditor.Plugins.Blockchain\UniversalEditor.Plugins.Blockchain.csproj", "{C54F6BCD-60CD-4603-B0C9-CD0864455CB1}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UniversalEditor.Plugins.Blockchain.UserInterface", "Plugins.UserInterface\UniversalEditor.Plugins.Blockchain.UserInterface\UniversalEditor.Plugins.Blockchain.UserInterface.csproj", "{B6E600F5-E5BC-4DC2-8B41-7B11EB0A11B3}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -577,6 +581,14 @@ Global {FAE48F29-DB35-4CD6-8A55-6C1FDDFBE6AF}.Debug|Any CPU.Build.0 = Debug|Any CPU {FAE48F29-DB35-4CD6-8A55-6C1FDDFBE6AF}.Release|Any CPU.ActiveCfg = Release|Any CPU {FAE48F29-DB35-4CD6-8A55-6C1FDDFBE6AF}.Release|Any CPU.Build.0 = Release|Any CPU + {C54F6BCD-60CD-4603-B0C9-CD0864455CB1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C54F6BCD-60CD-4603-B0C9-CD0864455CB1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C54F6BCD-60CD-4603-B0C9-CD0864455CB1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C54F6BCD-60CD-4603-B0C9-CD0864455CB1}.Release|Any CPU.Build.0 = Release|Any CPU + {B6E600F5-E5BC-4DC2-8B41-7B11EB0A11B3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B6E600F5-E5BC-4DC2-8B41-7B11EB0A11B3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B6E600F5-E5BC-4DC2-8B41-7B11EB0A11B3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B6E600F5-E5BC-4DC2-8B41-7B11EB0A11B3}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {6F0AB1AF-E1A1-4D19-B19C-05BBB15C94B2} = {05D15661-E684-4EC9-8FBD-C014BA433CC5} @@ -671,6 +683,8 @@ Global {D1FB19C4-025E-4D4A-8532-4196AFCC8813} = {5E4765D1-3959-4433-8E9C-992E26D7BE62} {63E2F10F-27A6-4BAA-BF4A-4422D0934E91} = {20F315E0-52AE-479F-AF43-3402482C1FC8} {FAE48F29-DB35-4CD6-8A55-6C1FDDFBE6AF} = {63E2F10F-27A6-4BAA-BF4A-4422D0934E91} + {C54F6BCD-60CD-4603-B0C9-CD0864455CB1} = {2ED32D16-6C06-4450-909A-40D32DA67FB4} + {B6E600F5-E5BC-4DC2-8B41-7B11EB0A11B3} = {7B535D74-5496-4802-B809-89ED88274A91} EndGlobalSection GlobalSection(MonoDevelopProperties) = preSolution Policies = $0