diff --git a/Dalamud.Injector/DalamudLauncher.cs b/Dalamud.Bootstrap/Bootstrapper.cs
similarity index 87%
rename from Dalamud.Injector/DalamudLauncher.cs
rename to Dalamud.Bootstrap/Bootstrapper.cs
index b2aca2bf3..26dd30c7b 100644
--- a/Dalamud.Injector/DalamudLauncher.cs
+++ b/Dalamud.Bootstrap/Bootstrapper.cs
@@ -5,16 +5,13 @@ using CoreHook.BinaryInjection.RemoteInjection;
using CoreHook.BinaryInjection.RemoteInjection.Configuration;
using CoreHook.IPC.Platform;
-namespace Dalamud.Injector
+namespace Dalamud.Bootstrap
{
- public sealed partial class DalamudLauncher
+ public sealed class Bootstrapper
{
- private readonly DalamudLauncherOptions m_options;
- }
+ private readonly BootstrapperOptions m_options;
- public sealed partial class DalamudLauncher
- {
- public DalamudLauncher(DalamudLauncherOptions options)
+ public Bootstrapper(BootstrapperOptions options)
{
m_options = options;
}
@@ -46,10 +43,17 @@ namespace Dalamud.Injector
// Acquire the process handle and read the command line
using var process = Process.Open(pid);
- var commandLines = process.ReadCommandLine();
-
- // ....
+ var arguments = process.ReadCommandLine();
+ // TODO:
+ // .... if arg1 exists
+ // DecodeSqexArg(arguments[1]);
+ // args = ParseArgument()
+ // FindArguments(args, "T")
+ // RemoveArgs(args, "T")
+ // AddArgs(args, "T", newTick)
+ // str = ToString()
+ // EncodeSqexArg(str, newKey)
process.Terminate();
@@ -90,7 +94,7 @@ namespace Dalamud.Injector
// Could not inject Dalamud for whatever reason; it could be process is not actually running, insufficient os privilege, or whatever the thing SE put in their game;
// Therefore there's not much we can do on this side; You have to trobleshoot by yourself somehow.
- throw new DalamudLauncherException(pid, message, ex);
+ throw new BootstrapException(pid, message, ex);
}
}
}
diff --git a/Dalamud.Injector/DalamudLauncherOptions.cs b/Dalamud.Bootstrap/BootstrapperOptions.cs
similarity index 83%
rename from Dalamud.Injector/DalamudLauncherOptions.cs
rename to Dalamud.Bootstrap/BootstrapperOptions.cs
index 27e39363a..52464a988 100644
--- a/Dalamud.Injector/DalamudLauncherOptions.cs
+++ b/Dalamud.Bootstrap/BootstrapperOptions.cs
@@ -1,11 +1,11 @@
using System;
using System.IO;
-namespace Dalamud.Injector
+namespace Dalamud.Bootstrap
{
- public sealed class DalamudLauncherOptions
+ public sealed class BootstrapperOptions
{
- public static DalamudLauncherOptions Default => new DalamudLauncherOptions
+ public static BootstrapperOptions Default => new BootstrapperOptions
{
RootDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Dalamud"),
BinaryDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Dalamud", "bin"),
diff --git a/Dalamud.Injector/Crypto/Blowfish.cs b/Dalamud.Bootstrap/Crypto/Blowfish.cs
similarity index 95%
rename from Dalamud.Injector/Crypto/Blowfish.cs
rename to Dalamud.Bootstrap/Crypto/Blowfish.cs
index 800fd0b19..2b3b41469 100644
--- a/Dalamud.Injector/Crypto/Blowfish.cs
+++ b/Dalamud.Bootstrap/Crypto/Blowfish.cs
@@ -1,15 +1,8 @@
using System;
-using System.Buffers.Binary;
using System.Runtime.CompilerServices;
-namespace Dalamud.Injector.Crypto
+namespace Dalamud.Bootstrap.Crypto
{
- ///
- /// A struct that implements Blowfish algorithm.
- ///
- ///
- ///
- ///
internal unsafe partial struct BlowfishState
{
// References:
@@ -369,12 +362,12 @@ namespace Dalamud.Injector.Crypto
}
}
- internal sealed partial class BlowfishLe
+ internal sealed partial class Blowfish
{
private BlowfishState m_state;
}
- internal sealed partial class BlowfishLe
+ internal sealed partial class Blowfish
{
///
/// Initializes a new instance of the Blowfish class.
@@ -384,12 +377,36 @@ namespace Dalamud.Injector.Crypto
///
/// A secret key used for blowfish. Key length must be between 32 and 448 bits.
/// Length of the key is either too short or too long.
- public BlowfishLe(ReadOnlySpan key)
+ public Blowfish(ReadOnlySpan key)
{
m_state = new BlowfishState(key);
}
- public unsafe void EncryptBlockUnsafe(byte* input, byte* output)
+ public void EncryptInPlace(Span buffer)
+ {
+ // TODO: this is shit
+ }
+
+ public void DecryptInPlace(Span buffer)
+ {
+ if (buffer.Length % 8 != 0)
+ {
+ throw new ArgumentException("TODO: buffer length", nameof(buffer));
+ }
+
+ unsafe
+ {
+ fixed (byte* pBuffer = buffer)
+ {
+ for (byte* it = pBuffer; it < pBuffer + buffer.Length; it += 8)
+ {
+ DecryptBlockInPlace(it, it);
+ }
+ }
+ }
+ }
+
+ private unsafe void EncryptBlockInPlace(byte* input, byte* output)
{
var inputBlock = (uint*)input;
var outputBlock = (uint*)output;
@@ -417,7 +434,7 @@ namespace Dalamud.Injector.Crypto
outputBlock[1] = xr;
}
- public unsafe void DecryptBlockUnsafe(byte* input, byte* output)
+ private unsafe void DecryptBlockInPlace(byte* input, byte* output)
{
var inputBlock = (uint*)input;
var outputBlock = (uint*)output;
diff --git a/Dalamud.Bootstrap/Dalamud.Bootstrap.csproj b/Dalamud.Bootstrap/Dalamud.Bootstrap.csproj
new file mode 100644
index 000000000..a28f10736
--- /dev/null
+++ b/Dalamud.Bootstrap/Dalamud.Bootstrap.csproj
@@ -0,0 +1,14 @@
+
+
+
+ netstandard2.1
+ preview
+ enable
+ true
+
+
+
+
+
+
+
diff --git a/Dalamud.Bootstrap/Exceptions.cs b/Dalamud.Bootstrap/Exceptions.cs
new file mode 100644
index 000000000..39602ab80
--- /dev/null
+++ b/Dalamud.Bootstrap/Exceptions.cs
@@ -0,0 +1,21 @@
+using System;
+
+namespace Dalamud.Bootstrap
+{
+ ///
+ /// An error that is thrown when bootstraping Dalamud failed.
+ ///
+ public class BootstrapException : Exception
+ {
+ internal BootstrapException() : base() { }
+
+ internal BootstrapException(string message) : base(message) { }
+
+ internal BootstrapException(string message, Exception innerException) : base(message, innerException) { }
+ }
+
+ public class NtException : BootstrapException
+ {
+
+ }
+}
diff --git a/Dalamud.Bootstrap/SqexArg/ArgumentBuilder.cs b/Dalamud.Bootstrap/SqexArg/ArgumentBuilder.cs
new file mode 100644
index 000000000..46b47f0c0
--- /dev/null
+++ b/Dalamud.Bootstrap/SqexArg/ArgumentBuilder.cs
@@ -0,0 +1,55 @@
+using System.Collections.Generic;
+using System.Text;
+
+namespace Dalamud.Bootstrap.SqexArg
+{
+ internal sealed class ArgumentBuilder
+ {
+ private readonly Dictionary m_dict;
+
+ public ArgumentBuilder()
+ {
+ m_dict = new Dictionary();
+ }
+
+ public ArgumentBuilder Add(string key, string value)
+ {
+ m_dict.Add(key, value);
+
+ return this;
+ }
+
+ public ArgumentBuilder Clear()
+ {
+ m_dict.Clear();
+
+ return this;
+ }
+
+ private static void Write(StringBuilder buffer, string key, string value)
+ {
+ var escapedKey = EscapeValue(key);
+ var escapedvalue = EscapeValue(value);
+
+ buffer.Append($" /{escapedKey} ={escapedvalue}");
+ }
+
+ private static string EscapeValue(string value)
+ {
+ // a single space character is represented as dobule spaces
+ return value.Replace(" ", " ");
+ }
+
+ public override string ToString()
+ {
+ var buffer = new StringBuilder(256);
+
+ foreach (var kv in m_dict)
+ {
+ Write(buffer, kv.Key, kv.Value);
+ }
+
+ return buffer.ToString();
+ }
+ }
+}
diff --git a/Dalamud.Bootstrap/SqexArg/ArgumentDecoder.cs b/Dalamud.Bootstrap/SqexArg/ArgumentDecoder.cs
new file mode 100644
index 000000000..1f181bd07
--- /dev/null
+++ b/Dalamud.Bootstrap/SqexArg/ArgumentDecoder.cs
@@ -0,0 +1,47 @@
+using System;
+
+namespace Dalamud.Bootstrap.SqexArg
+{
+ internal static class ArgumentDecoder
+ {
+ public static void Decode(ReadOnlySpan argument, uint key)
+ {
+ // 1. strip //**sqex003 and **//
+ // 2. extract checksum
+ // 3. deduce upper nibble key
+ // 4.
+
+ // //**c**//
+ if (argument.Length <= 9)
+ {
+ throw new ArgumentException(nameof(argument));
+ }
+
+ if (!argument.StartsWith("//**") || !argument.EndsWith("**//"))
+ {
+ throw new ArgumentException(nameof(argument));
+ }
+
+ var payload = argument[4..^5];
+ var checksum = argument[^5];
+
+ // undo url safe
+ //payload.re
+
+
+
+ // stuff
+
+ }
+
+ private static void DecodeUrlSafeBase64(ReadOnlySpan content)
+ {
+ var buffer = new byte[(content.Length / 3) * 4];
+ if (!Convert.TryFromBase64Chars(payload, buffer, out var _))
+ {
+ // TODO
+ }
+ }
+
+ }
+}
diff --git a/Dalamud.Injector/Process.cs b/Dalamud.Bootstrap/Windows/Process.cs
similarity index 89%
rename from Dalamud.Injector/Process.cs
rename to Dalamud.Bootstrap/Windows/Process.cs
index 89a894191..8c68d242e 100644
--- a/Dalamud.Injector/Process.cs
+++ b/Dalamud.Bootstrap/Windows/Process.cs
@@ -1,10 +1,10 @@
-using Dalamud.Injector.Windows;
+using Dalamud.Bootstrap.Windows;
using Microsoft.Win32.SafeHandles;
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
-namespace Dalamud.Injector
+namespace Dalamud.Bootstrap
{
///
/// TODO
@@ -12,10 +12,7 @@ namespace Dalamud.Injector
internal sealed partial class Process : IDisposable
{
private SafeProcessHandle m_handle;
- }
- internal sealed partial class Process
- {
///
/// Creates a process object that can be used to manipulate process's internal state.
///
@@ -35,6 +32,7 @@ namespace Dalamud.Injector
{
const PROCESS_ACCESS_RIGHT access = PROCESS_ACCESS_RIGHT.PROCESS_VM_OPERATION
| PROCESS_ACCESS_RIGHT.PROCESS_VM_READ
+ // | PROCESS_ACCESS_RIGHT.PROCESS_VM_WRITE // we don't need it for now
| PROCESS_ACCESS_RIGHT.PROCESS_QUERY_LIMITED_INFORMATION
| PROCESS_ACCESS_RIGHT.PROCESS_QUERY_INFORMATION
| PROCESS_ACCESS_RIGHT.PROCESS_CREATE_THREAD
@@ -77,7 +75,7 @@ namespace Dalamud.Injector
throw new Win32Exception();
}
- // this is okay as Span can't really be longer than int.Max
+ // this is okay as the length of the span can't be longer than int.Max
return (int)bytesRead;
}
}
@@ -108,13 +106,6 @@ namespace Dalamud.Injector
return buffer;
}
- private ref T ReadMemoryValue(IntPtr address, Span buffer) where T : unmanaged
- {
- ReadMemoryExact(address, buffer);
-
- return ref MemoryMarshal.AsRef(buffer);
- }
-
private T ReadMemoryValue(IntPtr address) where T : unmanaged
{
unsafe
@@ -123,7 +114,7 @@ namespace Dalamud.Injector
Span buffer = stackalloc byte[sizeof(T)];
ReadMemoryExact(address, buffer);
- // I reckon this is still far better than allocating on the heap when T is small enough.
+ // this is still far better than allocating the temporary buffer on the heap when sizeof(T) is small enough.
return MemoryMarshal.Read(buffer);
}
}
@@ -153,7 +144,7 @@ namespace Dalamud.Injector
var peb = ReadMemoryValue(pebAddr);
var procParam = ReadMemoryValue(peb.ProcessParameters);
- // Read the command line (utf16-like string)
+ // Read the command line (which is utf16-like string)
var commandLine = ReadMemoryExact(procParam.CommandLine.Buffer, procParam.CommandLine.Length);
return ParseCommandLine(commandLine);
}
@@ -168,6 +159,8 @@ namespace Dalamud.Injector
fixed (byte* pCommandLine = commandLine)
{
+ // TODO: maybe explain why we can't just call .Split(' ')
+ // https://docs.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-commandlinetoargvw
argv = Win32.CommandLineToArgvW(pCommandLine, &argc);
}
diff --git a/Dalamud.Injector/Windows/Win32.cs b/Dalamud.Bootstrap/Windows/Win32.cs
similarity index 99%
rename from Dalamud.Injector/Windows/Win32.cs
rename to Dalamud.Bootstrap/Windows/Win32.cs
index df3aa1f80..89a45f458 100644
--- a/Dalamud.Injector/Windows/Win32.cs
+++ b/Dalamud.Bootstrap/Windows/Win32.cs
@@ -2,7 +2,7 @@ using Microsoft.Win32.SafeHandles;
using System;
using System.Runtime.InteropServices;
-namespace Dalamud.Injector.Windows
+namespace Dalamud.Bootstrap.Windows
{
internal static unsafe class Win32
{
diff --git a/Dalamud.Injector/Dalamud.Injector.csproj b/Dalamud.Injector/Dalamud.Injector.csproj
index a894eecd4..16b8e1785 100644
--- a/Dalamud.Injector/Dalamud.Injector.csproj
+++ b/Dalamud.Injector/Dalamud.Injector.csproj
@@ -4,12 +4,11 @@
netcoreapp3.1
preview
enable
- true
-
+
diff --git a/Dalamud.Injector/DalamudLauncherException.cs b/Dalamud.Injector/DalamudLauncherException.cs
deleted file mode 100644
index c2597d95f..000000000
--- a/Dalamud.Injector/DalamudLauncherException.cs
+++ /dev/null
@@ -1,29 +0,0 @@
-using System;
-
-namespace Dalamud.Injector
-{
- ///
- /// An error that is thrown when injecting Dalamud into the process failed.
- ///
- public sealed partial class DalamudLauncherException : Exception
- {
- ///
- /// A target process id that was attempted to.
- ///
- public uint ProcessId { get; }
- }
-
- public sealed partial class DalamudLauncherException
- {
- public DalamudLauncherException() : base() { }
-
- public DalamudLauncherException(string message) : base(message) { }
-
- public DalamudLauncherException(string message, Exception inner) : base(message, inner) { }
-
- public DalamudLauncherException(uint pid, string message, Exception inner) : base(message, inner)
- {
- ProcessId = pid;
- }
- }
-}
diff --git a/Dalamud.Injector/Options.cs b/Dalamud.Injector/Options.cs
new file mode 100644
index 000000000..ab473cc63
--- /dev/null
+++ b/Dalamud.Injector/Options.cs
@@ -0,0 +1,33 @@
+using CommandLine;
+
+namespace Dalamud.Injector
+{
+ [Verb("inject")]
+ internal sealed class InjectOptions
+ {
+ [Option('p', "pid", Required = true, HelpText = "A target process id to inject.")]
+ public uint Pid { get; set; }
+
+ [Option("root", Required = false)]
+ public string? RootDirectory { get; set; }
+
+ [Option("bin", Required = false)]
+ public string? BinaryDirectory { get; set; }
+ }
+
+ [Verb("launch")]
+ internal sealed class LaunchOptions
+ {
+ [Value(0)]
+ public string ExecutablePath { get; set; } = null!;
+
+ [Value(1, Required = false)]
+ public string? CommandLine { get; set; }
+
+ [Option("root", Required = false)]
+ public string? RootDirectory { get; set; }
+
+ [Option("bin", Required = false)]
+ public string? BinaryDirectory { get; set; }
+ }
+}
diff --git a/Dalamud.Injector/Program.cs b/Dalamud.Injector/Program.cs
new file mode 100644
index 000000000..1a29af1d0
--- /dev/null
+++ b/Dalamud.Injector/Program.cs
@@ -0,0 +1,52 @@
+using System;
+using System.IO;
+using CommandLine;
+using Dalamud.Bootstrap;
+using static System.Environment;
+
+namespace Dalamud.Injector
+{
+ internal static class Program
+ {
+ private static void Main(string[] args)
+ {
+ Parser.Default.ParseArguments(args)
+ .WithParsed(Inject)
+ .WithParsed(Launch);
+ }
+
+ private static void Inject(InjectOptions options)
+ {
+ var binDirectory = options.BinaryDirectory ?? GetDefaultBinaryDirectory();
+ var rootDirectory = options.RootDirectory ?? GetDefaultRootDirectory();
+
+ var boot = new Bootstrapper(new BootstrapperOptions
+ {
+ BinaryDirectory = binDirectory,
+ RootDirectory = rootDirectory,
+ });
+
+ // ..
+ boot.Relaunch(options.Pid);
+ }
+
+ private static void Launch(LaunchOptions options)
+ {
+
+ }
+
+ private static string GetDefaultBinaryDirectory()
+ {
+ var root = GetDefaultRootDirectory();
+
+ return Path.Combine(root, "bin");
+ }
+
+ private static string GetDefaultRootDirectory()
+ {
+ var localApp = Environment.GetFolderPath(SpecialFolder.LocalApplicationData);
+
+ return Path.Combine(localApp, "Dalamud");
+ }
+ }
+}
diff --git a/Dalamud.Injector/Program/Options.cs b/Dalamud.Injector/Program/Options.cs
deleted file mode 100644
index a5a1b99f2..000000000
--- a/Dalamud.Injector/Program/Options.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-using System;
-using CommandLine;
-
-namespace Dalamud.Injector
-{
- [Verb("inject")]
- internal sealed class InjectOptions
- {
- [Option('p', "pid", Required = true, HelpText = "A target process id to inject.")]
- public uint Pid { get; set; }
-
- [Option("root", Required = true, HelpText = "")]
- public string RootDirectory { get; set; } = null!;
-
- [Option("bin", Required = true, HelpText = "")]
- public string BinaryDirectory { get; set; } = null!;
- }
-}
diff --git a/Dalamud.Injector/Program/Program.cs b/Dalamud.Injector/Program/Program.cs
deleted file mode 100644
index 4a00a37eb..000000000
--- a/Dalamud.Injector/Program/Program.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-using System;
-using CommandLine;
-using Dalamud.Injector.Windows;
-
-namespace Dalamud.Injector
-{
- internal static class Program
- {
- private static void Main(string[] args)
- {
- var shit = Process.Open(12732);
- var cmd = shit.ReadCommandLine();
- /*Parser.Default.ParseArguments(args)
- .WithParsed(opt =>
- {
-
- });*/
- }
- }
-}
diff --git a/Dalamud.Injector/Windows/NtException.cs b/Dalamud.Injector/Windows/NtException.cs
deleted file mode 100644
index 819dbec8a..000000000
--- a/Dalamud.Injector/Windows/NtException.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-using System;
-
-namespace Dalamud.Injector.Windows
-{
- ///
- /// An exception that is thrown when the function call to ntdll failed.
- ///
- internal sealed class NtException : Exception
- {
- private const string DefaultMessage = "TODO: NtStatus failed message goes here";
-
- public NtStatus Status { get; }
-
- public NtException(NtStatus status) : base(DefaultMessage)
- {
- Status = status;
- }
-
- public NtException(NtStatus status, string message) : base(message)
- {
- Status = status;
- }
- }
-}
diff --git a/Dalamud.Testing/Dalamud.Testing.csproj b/Dalamud.Testing/Dalamud.Testing.csproj
new file mode 100644
index 000000000..e6f67d320
--- /dev/null
+++ b/Dalamud.Testing/Dalamud.Testing.csproj
@@ -0,0 +1,23 @@
+
+
+
+ netcoreapp3.1
+ preview
+ true
+ false
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
diff --git a/Dalamud.Testing/UnitTest1.cs b/Dalamud.Testing/UnitTest1.cs
new file mode 100644
index 000000000..f7aab3d3f
--- /dev/null
+++ b/Dalamud.Testing/UnitTest1.cs
@@ -0,0 +1,14 @@
+using System;
+using Xunit;
+
+namespace Dalamud.Testing
+{
+ public class UnitTest1
+ {
+ [Fact]
+ public void Test1()
+ {
+
+ }
+ }
+}
diff --git a/Dalamud.sln b/Dalamud.sln
index 15a926f7f..83bb6fe78 100644
--- a/Dalamud.sln
+++ b/Dalamud.sln
@@ -39,6 +39,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CoreHook.IPC", "lib\CoreHoo
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CoreHook.Memory", "lib\CoreHook\src\CoreHook.Memory\CoreHook.Memory.csproj", "{ED4FFE13-5F83-42B9-8847-E7C4D7A988E8}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dalamud.Bootstrap", "Dalamud.Bootstrap\Dalamud.Bootstrap.csproj", "{19032128-E336-460F-B6E4-EAF6055589E5}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dalamud.Testing", "Dalamud.Testing\Dalamud.Testing.csproj", "{0A99A6B3-12E2-4197-A6F3-9211B6D4D824}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -217,6 +221,30 @@ Global
{ED4FFE13-5F83-42B9-8847-E7C4D7A988E8}.Release|x64.Build.0 = Release|Any CPU
{ED4FFE13-5F83-42B9-8847-E7C4D7A988E8}.Release|x86.ActiveCfg = Release|Any CPU
{ED4FFE13-5F83-42B9-8847-E7C4D7A988E8}.Release|x86.Build.0 = Release|Any CPU
+ {19032128-E336-460F-B6E4-EAF6055589E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {19032128-E336-460F-B6E4-EAF6055589E5}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {19032128-E336-460F-B6E4-EAF6055589E5}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {19032128-E336-460F-B6E4-EAF6055589E5}.Debug|x64.Build.0 = Debug|Any CPU
+ {19032128-E336-460F-B6E4-EAF6055589E5}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {19032128-E336-460F-B6E4-EAF6055589E5}.Debug|x86.Build.0 = Debug|Any CPU
+ {19032128-E336-460F-B6E4-EAF6055589E5}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {19032128-E336-460F-B6E4-EAF6055589E5}.Release|Any CPU.Build.0 = Release|Any CPU
+ {19032128-E336-460F-B6E4-EAF6055589E5}.Release|x64.ActiveCfg = Release|Any CPU
+ {19032128-E336-460F-B6E4-EAF6055589E5}.Release|x64.Build.0 = Release|Any CPU
+ {19032128-E336-460F-B6E4-EAF6055589E5}.Release|x86.ActiveCfg = Release|Any CPU
+ {19032128-E336-460F-B6E4-EAF6055589E5}.Release|x86.Build.0 = Release|Any CPU
+ {0A99A6B3-12E2-4197-A6F3-9211B6D4D824}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0A99A6B3-12E2-4197-A6F3-9211B6D4D824}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0A99A6B3-12E2-4197-A6F3-9211B6D4D824}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {0A99A6B3-12E2-4197-A6F3-9211B6D4D824}.Debug|x64.Build.0 = Debug|Any CPU
+ {0A99A6B3-12E2-4197-A6F3-9211B6D4D824}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {0A99A6B3-12E2-4197-A6F3-9211B6D4D824}.Debug|x86.Build.0 = Debug|Any CPU
+ {0A99A6B3-12E2-4197-A6F3-9211B6D4D824}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {0A99A6B3-12E2-4197-A6F3-9211B6D4D824}.Release|Any CPU.Build.0 = Release|Any CPU
+ {0A99A6B3-12E2-4197-A6F3-9211B6D4D824}.Release|x64.ActiveCfg = Release|Any CPU
+ {0A99A6B3-12E2-4197-A6F3-9211B6D4D824}.Release|x64.Build.0 = Release|Any CPU
+ {0A99A6B3-12E2-4197-A6F3-9211B6D4D824}.Release|x86.ActiveCfg = Release|Any CPU
+ {0A99A6B3-12E2-4197-A6F3-9211B6D4D824}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE