diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..4af53c05c --- /dev/null +++ b/.editorconfig @@ -0,0 +1,4 @@ +[*.cs] + +# CS0162: Unreachable code detected +dotnet_diagnostic.CS0162.severity = none diff --git a/.gitignore b/.gitignore index d033613f3..9e80f1699 100644 --- a/.gitignore +++ b/.gitignore @@ -268,3 +268,6 @@ paket-files/ /_site/ /.sass-cache/ Gemfile.lock + +#nugetGenerated +/Build/PsiPackages/ \ No newline at end of file diff --git a/Applications/Test/Program.cs b/Applications/Test/Program.cs new file mode 100644 index 000000000..81c7169ad --- /dev/null +++ b/Applications/Test/Program.cs @@ -0,0 +1,91 @@ + +using Microsoft.Psi.Interop.Rendezvous; +using Microsoft.Psi; +using Microsoft.Psi.Media; +using Microsoft.Psi.Media_Interop; +using System.Net.Sockets; +using Microsoft.Psi.Interop.Transport; +using Microsoft.Psi.Interop.Serialization; + +namespace TestingConsole +{ + public class Program + { + /// + /// Provides serialization format for string type. + /// + public class PsiFormatString + { + /// + /// Gets the format for serializing and deserializing string values. + /// + /// A Format instance for string serialization. + public static Format GetFormat() + { + return new Format(WriteString, ReadSring); + } + + /// + /// Writes a string to a binary writer. + /// + /// The string to write. + /// The binary writer to write to. + public static void WriteString(string data, BinaryWriter writer) + { + writer.Write(data); + } + + /// + /// Reads a string from a binary reader. + /// + /// The binary reader to read from. + /// The deserialized string. + public static string ReadSring(BinaryReader reader) + { + return reader.ReadString(); + } + } + + static void proc(string message, DateTime dateTime) + { + Console.WriteLine($"{message} @{dateTime}"); + } + + static void Main(string[] args) + { + //RendezvousServer server = new RendezvousServer(13331); + //server.Start(); + //server.Rendezvous.ProcessAdded += (_, process) => + //{ + // Console.WriteLine($"Process added: {process.Name}"); + //}; + + Pipeline pipeline = Pipeline.Create(); + UdpSource udpSource = new UdpSource(pipeline, 15552, PsiFormatString.GetFormat()); + udpSource.OnMessageReceived += proc; + RendezvousClient client = new RendezvousClient("localhost", 13331); + client.Start(); + pipeline.RunAsync(); + //udpSource.Start((e)=>{ }); + //int i = 0; + //while (true) + //{ + // Console.WriteLine("Press"); + // Console.ReadLine(); + // client.Rendezvous.TryAddProcess(new Rendezvous.Process($"test{i++}")); + //} + + + Console.WriteLine("Press"); + Console.ReadLine(); + //List cameras = MediaCapture.GetAvailableCameras(); + //List CameraCaptureFormat = new List(); + + //var vals = MediaCapture.GetAvailableFormats(cameras.First()); + //foreach (CaptureFormat format in vals) + //{ + // CameraCaptureFormat.Add($"{format.nWidth}x{format.nHeight}@{format.nFrameRateNumerator}"); + //} + } + } +} diff --git a/Psi.sln b/Psi.sln index 952ed4d66..58f099f0b 100644 --- a/Psi.sln +++ b/Psi.sln @@ -259,324 +259,648 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SigmaApp", "Applications\Si EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SigmaComputeServer", "Applications\Sigma\SigmaComputeServer\SigmaComputeServer.csproj", "{365D836D-AD15-428C-96D1-6C4870525FEF}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Psi.Interop.Android", "Sources\Runtime\Microsoft.Psi.InteropAndroid\Microsoft.Psi.Interop.Android.csproj", "{DF585F32-54AA-4553-AF91-6BBD1732E147}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {04147400-0AB0-4F07-9975-D4B7E58150DB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {04147400-0AB0-4F07-9975-D4B7E58150DB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {04147400-0AB0-4F07-9975-D4B7E58150DB}.Debug|x64.ActiveCfg = Debug|Any CPU + {04147400-0AB0-4F07-9975-D4B7E58150DB}.Debug|x64.Build.0 = Debug|Any CPU {04147400-0AB0-4F07-9975-D4B7E58150DB}.Release|Any CPU.ActiveCfg = Release|Any CPU {04147400-0AB0-4F07-9975-D4B7E58150DB}.Release|Any CPU.Build.0 = Release|Any CPU + {04147400-0AB0-4F07-9975-D4B7E58150DB}.Release|x64.ActiveCfg = Release|Any CPU + {04147400-0AB0-4F07-9975-D4B7E58150DB}.Release|x64.Build.0 = Release|Any CPU {2CC39BCB-7798-474C-AC97-1C5F664101E2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {2CC39BCB-7798-474C-AC97-1C5F664101E2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2CC39BCB-7798-474C-AC97-1C5F664101E2}.Debug|x64.ActiveCfg = Debug|Any CPU + {2CC39BCB-7798-474C-AC97-1C5F664101E2}.Debug|x64.Build.0 = Debug|Any CPU {2CC39BCB-7798-474C-AC97-1C5F664101E2}.Release|Any CPU.ActiveCfg = Release|Any CPU {2CC39BCB-7798-474C-AC97-1C5F664101E2}.Release|Any CPU.Build.0 = Release|Any CPU + {2CC39BCB-7798-474C-AC97-1C5F664101E2}.Release|x64.ActiveCfg = Release|Any CPU + {2CC39BCB-7798-474C-AC97-1C5F664101E2}.Release|x64.Build.0 = Release|Any CPU {855FD8BE-6938-4784-B1EE-D90A8B5B2496}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {855FD8BE-6938-4784-B1EE-D90A8B5B2496}.Debug|Any CPU.Build.0 = Debug|Any CPU + {855FD8BE-6938-4784-B1EE-D90A8B5B2496}.Debug|x64.ActiveCfg = Debug|Any CPU + {855FD8BE-6938-4784-B1EE-D90A8B5B2496}.Debug|x64.Build.0 = Debug|Any CPU {855FD8BE-6938-4784-B1EE-D90A8B5B2496}.Release|Any CPU.ActiveCfg = Release|Any CPU {855FD8BE-6938-4784-B1EE-D90A8B5B2496}.Release|Any CPU.Build.0 = Release|Any CPU + {855FD8BE-6938-4784-B1EE-D90A8B5B2496}.Release|x64.ActiveCfg = Release|Any CPU + {855FD8BE-6938-4784-B1EE-D90A8B5B2496}.Release|x64.Build.0 = Release|Any CPU {9BF2E5EF-186A-4179-B753-AE11EE90E026}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {9BF2E5EF-186A-4179-B753-AE11EE90E026}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9BF2E5EF-186A-4179-B753-AE11EE90E026}.Debug|x64.ActiveCfg = Debug|Any CPU + {9BF2E5EF-186A-4179-B753-AE11EE90E026}.Debug|x64.Build.0 = Debug|Any CPU {9BF2E5EF-186A-4179-B753-AE11EE90E026}.Release|Any CPU.ActiveCfg = Release|Any CPU {9BF2E5EF-186A-4179-B753-AE11EE90E026}.Release|Any CPU.Build.0 = Release|Any CPU + {9BF2E5EF-186A-4179-B753-AE11EE90E026}.Release|x64.ActiveCfg = Release|Any CPU + {9BF2E5EF-186A-4179-B753-AE11EE90E026}.Release|x64.Build.0 = Release|Any CPU {AC5745DA-570C-4E57-9AE4-D1974F629428}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {AC5745DA-570C-4E57-9AE4-D1974F629428}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AC5745DA-570C-4E57-9AE4-D1974F629428}.Debug|x64.ActiveCfg = Debug|Any CPU + {AC5745DA-570C-4E57-9AE4-D1974F629428}.Debug|x64.Build.0 = Debug|Any CPU {AC5745DA-570C-4E57-9AE4-D1974F629428}.Release|Any CPU.ActiveCfg = Release|Any CPU {AC5745DA-570C-4E57-9AE4-D1974F629428}.Release|Any CPU.Build.0 = Release|Any CPU + {AC5745DA-570C-4E57-9AE4-D1974F629428}.Release|x64.ActiveCfg = Release|Any CPU + {AC5745DA-570C-4E57-9AE4-D1974F629428}.Release|x64.Build.0 = Release|Any CPU {C048E3FB-CDC4-4577-A40E-8C9B1B7CEDF1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C048E3FB-CDC4-4577-A40E-8C9B1B7CEDF1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C048E3FB-CDC4-4577-A40E-8C9B1B7CEDF1}.Debug|x64.ActiveCfg = Debug|Any CPU + {C048E3FB-CDC4-4577-A40E-8C9B1B7CEDF1}.Debug|x64.Build.0 = Debug|Any CPU {C048E3FB-CDC4-4577-A40E-8C9B1B7CEDF1}.Release|Any CPU.ActiveCfg = Release|Any CPU {C048E3FB-CDC4-4577-A40E-8C9B1B7CEDF1}.Release|Any CPU.Build.0 = Release|Any CPU + {C048E3FB-CDC4-4577-A40E-8C9B1B7CEDF1}.Release|x64.ActiveCfg = Release|Any CPU + {C048E3FB-CDC4-4577-A40E-8C9B1B7CEDF1}.Release|x64.Build.0 = Release|Any CPU {80C75A20-920A-4B30-B05E-970BE844456A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {80C75A20-920A-4B30-B05E-970BE844456A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {80C75A20-920A-4B30-B05E-970BE844456A}.Debug|x64.ActiveCfg = Debug|Any CPU + {80C75A20-920A-4B30-B05E-970BE844456A}.Debug|x64.Build.0 = Debug|Any CPU {80C75A20-920A-4B30-B05E-970BE844456A}.Release|Any CPU.ActiveCfg = Release|Any CPU {80C75A20-920A-4B30-B05E-970BE844456A}.Release|Any CPU.Build.0 = Release|Any CPU + {80C75A20-920A-4B30-B05E-970BE844456A}.Release|x64.ActiveCfg = Release|Any CPU + {80C75A20-920A-4B30-B05E-970BE844456A}.Release|x64.Build.0 = Release|Any CPU {3FB6CD31-0941-4372-9BDB-9E6830385DD4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3FB6CD31-0941-4372-9BDB-9E6830385DD4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3FB6CD31-0941-4372-9BDB-9E6830385DD4}.Debug|x64.ActiveCfg = Debug|Any CPU + {3FB6CD31-0941-4372-9BDB-9E6830385DD4}.Debug|x64.Build.0 = Debug|Any CPU {3FB6CD31-0941-4372-9BDB-9E6830385DD4}.Release|Any CPU.ActiveCfg = Release|Any CPU {3FB6CD31-0941-4372-9BDB-9E6830385DD4}.Release|Any CPU.Build.0 = Release|Any CPU + {3FB6CD31-0941-4372-9BDB-9E6830385DD4}.Release|x64.ActiveCfg = Release|Any CPU + {3FB6CD31-0941-4372-9BDB-9E6830385DD4}.Release|x64.Build.0 = Release|Any CPU {8AC7DE3C-DF3C-44A8-9E69-E1F21BF3E564}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {8AC7DE3C-DF3C-44A8-9E69-E1F21BF3E564}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8AC7DE3C-DF3C-44A8-9E69-E1F21BF3E564}.Debug|x64.ActiveCfg = Debug|Any CPU + {8AC7DE3C-DF3C-44A8-9E69-E1F21BF3E564}.Debug|x64.Build.0 = Debug|Any CPU {8AC7DE3C-DF3C-44A8-9E69-E1F21BF3E564}.Release|Any CPU.ActiveCfg = Release|Any CPU {8AC7DE3C-DF3C-44A8-9E69-E1F21BF3E564}.Release|Any CPU.Build.0 = Release|Any CPU + {8AC7DE3C-DF3C-44A8-9E69-E1F21BF3E564}.Release|x64.ActiveCfg = Release|Any CPU + {8AC7DE3C-DF3C-44A8-9E69-E1F21BF3E564}.Release|x64.Build.0 = Release|Any CPU {FFFD905A-1672-4920-B790-EEA6A961383C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {FFFD905A-1672-4920-B790-EEA6A961383C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FFFD905A-1672-4920-B790-EEA6A961383C}.Debug|x64.ActiveCfg = Debug|Any CPU + {FFFD905A-1672-4920-B790-EEA6A961383C}.Debug|x64.Build.0 = Debug|Any CPU {FFFD905A-1672-4920-B790-EEA6A961383C}.Release|Any CPU.ActiveCfg = Release|Any CPU {FFFD905A-1672-4920-B790-EEA6A961383C}.Release|Any CPU.Build.0 = Release|Any CPU + {FFFD905A-1672-4920-B790-EEA6A961383C}.Release|x64.ActiveCfg = Release|Any CPU + {FFFD905A-1672-4920-B790-EEA6A961383C}.Release|x64.Build.0 = Release|Any CPU {7D481D0D-75C2-4E9F-9FE3-43EB63403F2B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7D481D0D-75C2-4E9F-9FE3-43EB63403F2B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7D481D0D-75C2-4E9F-9FE3-43EB63403F2B}.Debug|x64.ActiveCfg = Debug|Any CPU + {7D481D0D-75C2-4E9F-9FE3-43EB63403F2B}.Debug|x64.Build.0 = Debug|Any CPU {7D481D0D-75C2-4E9F-9FE3-43EB63403F2B}.Release|Any CPU.ActiveCfg = Release|Any CPU {7D481D0D-75C2-4E9F-9FE3-43EB63403F2B}.Release|Any CPU.Build.0 = Release|Any CPU + {7D481D0D-75C2-4E9F-9FE3-43EB63403F2B}.Release|x64.ActiveCfg = Release|Any CPU + {7D481D0D-75C2-4E9F-9FE3-43EB63403F2B}.Release|x64.Build.0 = Release|Any CPU {191DF615-3D8F-45A3-B763-DD4A604A712A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {191DF615-3D8F-45A3-B763-DD4A604A712A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {191DF615-3D8F-45A3-B763-DD4A604A712A}.Debug|x64.ActiveCfg = Debug|Any CPU + {191DF615-3D8F-45A3-B763-DD4A604A712A}.Debug|x64.Build.0 = Debug|Any CPU {191DF615-3D8F-45A3-B763-DD4A604A712A}.Release|Any CPU.ActiveCfg = Release|Any CPU {191DF615-3D8F-45A3-B763-DD4A604A712A}.Release|Any CPU.Build.0 = Release|Any CPU + {191DF615-3D8F-45A3-B763-DD4A604A712A}.Release|x64.ActiveCfg = Release|Any CPU + {191DF615-3D8F-45A3-B763-DD4A604A712A}.Release|x64.Build.0 = Release|Any CPU {57B57050-5044-4EA9-AC08-030F49E69D62}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {57B57050-5044-4EA9-AC08-030F49E69D62}.Debug|Any CPU.Build.0 = Debug|Any CPU + {57B57050-5044-4EA9-AC08-030F49E69D62}.Debug|x64.ActiveCfg = Debug|Any CPU + {57B57050-5044-4EA9-AC08-030F49E69D62}.Debug|x64.Build.0 = Debug|Any CPU {57B57050-5044-4EA9-AC08-030F49E69D62}.Release|Any CPU.ActiveCfg = Release|Any CPU {57B57050-5044-4EA9-AC08-030F49E69D62}.Release|Any CPU.Build.0 = Release|Any CPU + {57B57050-5044-4EA9-AC08-030F49E69D62}.Release|x64.ActiveCfg = Release|Any CPU + {57B57050-5044-4EA9-AC08-030F49E69D62}.Release|x64.Build.0 = Release|Any CPU {F843DAFA-A02B-4B63-8985-6890E513312E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F843DAFA-A02B-4B63-8985-6890E513312E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F843DAFA-A02B-4B63-8985-6890E513312E}.Debug|x64.ActiveCfg = Debug|Any CPU + {F843DAFA-A02B-4B63-8985-6890E513312E}.Debug|x64.Build.0 = Debug|Any CPU {F843DAFA-A02B-4B63-8985-6890E513312E}.Release|Any CPU.ActiveCfg = Release|Any CPU {F843DAFA-A02B-4B63-8985-6890E513312E}.Release|Any CPU.Build.0 = Release|Any CPU + {F843DAFA-A02B-4B63-8985-6890E513312E}.Release|x64.ActiveCfg = Release|Any CPU + {F843DAFA-A02B-4B63-8985-6890E513312E}.Release|x64.Build.0 = Release|Any CPU {D9EB512A-9F4F-4D46-86F1-57065CCC933D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D9EB512A-9F4F-4D46-86F1-57065CCC933D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D9EB512A-9F4F-4D46-86F1-57065CCC933D}.Debug|x64.ActiveCfg = Debug|Any CPU + {D9EB512A-9F4F-4D46-86F1-57065CCC933D}.Debug|x64.Build.0 = Debug|Any CPU {D9EB512A-9F4F-4D46-86F1-57065CCC933D}.Release|Any CPU.ActiveCfg = Release|Any CPU {D9EB512A-9F4F-4D46-86F1-57065CCC933D}.Release|Any CPU.Build.0 = Release|Any CPU + {D9EB512A-9F4F-4D46-86F1-57065CCC933D}.Release|x64.ActiveCfg = Release|Any CPU + {D9EB512A-9F4F-4D46-86F1-57065CCC933D}.Release|x64.Build.0 = Release|Any CPU {91184A9B-5AB9-4715-B853-8E95E5065AA3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {91184A9B-5AB9-4715-B853-8E95E5065AA3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {91184A9B-5AB9-4715-B853-8E95E5065AA3}.Debug|x64.ActiveCfg = Debug|Any CPU + {91184A9B-5AB9-4715-B853-8E95E5065AA3}.Debug|x64.Build.0 = Debug|Any CPU {91184A9B-5AB9-4715-B853-8E95E5065AA3}.Release|Any CPU.ActiveCfg = Release|Any CPU {91184A9B-5AB9-4715-B853-8E95E5065AA3}.Release|Any CPU.Build.0 = Release|Any CPU + {91184A9B-5AB9-4715-B853-8E95E5065AA3}.Release|x64.ActiveCfg = Release|Any CPU + {91184A9B-5AB9-4715-B853-8E95E5065AA3}.Release|x64.Build.0 = Release|Any CPU {3A3F1C2C-A805-4EA2-B5AE-80371B565A15}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3A3F1C2C-A805-4EA2-B5AE-80371B565A15}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3A3F1C2C-A805-4EA2-B5AE-80371B565A15}.Debug|x64.ActiveCfg = Debug|Any CPU + {3A3F1C2C-A805-4EA2-B5AE-80371B565A15}.Debug|x64.Build.0 = Debug|Any CPU {3A3F1C2C-A805-4EA2-B5AE-80371B565A15}.Release|Any CPU.ActiveCfg = Release|Any CPU {3A3F1C2C-A805-4EA2-B5AE-80371B565A15}.Release|Any CPU.Build.0 = Release|Any CPU + {3A3F1C2C-A805-4EA2-B5AE-80371B565A15}.Release|x64.ActiveCfg = Release|Any CPU + {3A3F1C2C-A805-4EA2-B5AE-80371B565A15}.Release|x64.Build.0 = Release|Any CPU {84CE1FE5-8141-4C2A-AC30-21BDC87F5D0A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {84CE1FE5-8141-4C2A-AC30-21BDC87F5D0A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {84CE1FE5-8141-4C2A-AC30-21BDC87F5D0A}.Debug|x64.ActiveCfg = Debug|Any CPU + {84CE1FE5-8141-4C2A-AC30-21BDC87F5D0A}.Debug|x64.Build.0 = Debug|Any CPU {84CE1FE5-8141-4C2A-AC30-21BDC87F5D0A}.Release|Any CPU.ActiveCfg = Release|Any CPU {84CE1FE5-8141-4C2A-AC30-21BDC87F5D0A}.Release|Any CPU.Build.0 = Release|Any CPU + {84CE1FE5-8141-4C2A-AC30-21BDC87F5D0A}.Release|x64.ActiveCfg = Release|Any CPU + {84CE1FE5-8141-4C2A-AC30-21BDC87F5D0A}.Release|x64.Build.0 = Release|Any CPU {5348A94F-7B3A-4B42-8555-2A1491971090}.Debug|Any CPU.ActiveCfg = Debug|x64 {5348A94F-7B3A-4B42-8555-2A1491971090}.Debug|Any CPU.Build.0 = Debug|x64 + {5348A94F-7B3A-4B42-8555-2A1491971090}.Debug|x64.ActiveCfg = Debug|x64 + {5348A94F-7B3A-4B42-8555-2A1491971090}.Debug|x64.Build.0 = Debug|x64 {5348A94F-7B3A-4B42-8555-2A1491971090}.Release|Any CPU.ActiveCfg = Release|x64 {5348A94F-7B3A-4B42-8555-2A1491971090}.Release|Any CPU.Build.0 = Release|x64 + {5348A94F-7B3A-4B42-8555-2A1491971090}.Release|x64.ActiveCfg = Release|x64 + {5348A94F-7B3A-4B42-8555-2A1491971090}.Release|x64.Build.0 = Release|x64 {16B58AE0-0E00-46FB-B114-72600DF6A78A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {16B58AE0-0E00-46FB-B114-72600DF6A78A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {16B58AE0-0E00-46FB-B114-72600DF6A78A}.Debug|x64.ActiveCfg = Debug|Any CPU + {16B58AE0-0E00-46FB-B114-72600DF6A78A}.Debug|x64.Build.0 = Debug|Any CPU {16B58AE0-0E00-46FB-B114-72600DF6A78A}.Release|Any CPU.ActiveCfg = Release|Any CPU {16B58AE0-0E00-46FB-B114-72600DF6A78A}.Release|Any CPU.Build.0 = Release|Any CPU + {16B58AE0-0E00-46FB-B114-72600DF6A78A}.Release|x64.ActiveCfg = Release|Any CPU + {16B58AE0-0E00-46FB-B114-72600DF6A78A}.Release|x64.Build.0 = Release|Any CPU {02A92F0E-98F1-4B42-883A-761272BAC185}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {02A92F0E-98F1-4B42-883A-761272BAC185}.Debug|Any CPU.Build.0 = Debug|Any CPU + {02A92F0E-98F1-4B42-883A-761272BAC185}.Debug|x64.ActiveCfg = Debug|Any CPU + {02A92F0E-98F1-4B42-883A-761272BAC185}.Debug|x64.Build.0 = Debug|Any CPU {02A92F0E-98F1-4B42-883A-761272BAC185}.Release|Any CPU.ActiveCfg = Release|Any CPU {02A92F0E-98F1-4B42-883A-761272BAC185}.Release|Any CPU.Build.0 = Release|Any CPU + {02A92F0E-98F1-4B42-883A-761272BAC185}.Release|x64.ActiveCfg = Release|Any CPU + {02A92F0E-98F1-4B42-883A-761272BAC185}.Release|x64.Build.0 = Release|Any CPU {808E6F51-9810-4461-AF4E-EF42EE47C806}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {808E6F51-9810-4461-AF4E-EF42EE47C806}.Debug|Any CPU.Build.0 = Debug|Any CPU + {808E6F51-9810-4461-AF4E-EF42EE47C806}.Debug|x64.ActiveCfg = Debug|Any CPU + {808E6F51-9810-4461-AF4E-EF42EE47C806}.Debug|x64.Build.0 = Debug|Any CPU {808E6F51-9810-4461-AF4E-EF42EE47C806}.Release|Any CPU.ActiveCfg = Release|Any CPU {808E6F51-9810-4461-AF4E-EF42EE47C806}.Release|Any CPU.Build.0 = Release|Any CPU + {808E6F51-9810-4461-AF4E-EF42EE47C806}.Release|x64.ActiveCfg = Release|Any CPU + {808E6F51-9810-4461-AF4E-EF42EE47C806}.Release|x64.Build.0 = Release|Any CPU {7F967CC6-905A-4198-A667-F9953C8A2139}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7F967CC6-905A-4198-A667-F9953C8A2139}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7F967CC6-905A-4198-A667-F9953C8A2139}.Debug|x64.ActiveCfg = Debug|Any CPU + {7F967CC6-905A-4198-A667-F9953C8A2139}.Debug|x64.Build.0 = Debug|Any CPU {7F967CC6-905A-4198-A667-F9953C8A2139}.Release|Any CPU.ActiveCfg = Release|Any CPU {7F967CC6-905A-4198-A667-F9953C8A2139}.Release|Any CPU.Build.0 = Release|Any CPU + {7F967CC6-905A-4198-A667-F9953C8A2139}.Release|x64.ActiveCfg = Release|Any CPU + {7F967CC6-905A-4198-A667-F9953C8A2139}.Release|x64.Build.0 = Release|Any CPU {CFB5E6D3-C2FD-4D46-B8AC-7E39634E2CA9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {CFB5E6D3-C2FD-4D46-B8AC-7E39634E2CA9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CFB5E6D3-C2FD-4D46-B8AC-7E39634E2CA9}.Debug|x64.ActiveCfg = Debug|Any CPU + {CFB5E6D3-C2FD-4D46-B8AC-7E39634E2CA9}.Debug|x64.Build.0 = Debug|Any CPU {CFB5E6D3-C2FD-4D46-B8AC-7E39634E2CA9}.Release|Any CPU.ActiveCfg = Release|Any CPU {CFB5E6D3-C2FD-4D46-B8AC-7E39634E2CA9}.Release|Any CPU.Build.0 = Release|Any CPU + {CFB5E6D3-C2FD-4D46-B8AC-7E39634E2CA9}.Release|x64.ActiveCfg = Release|Any CPU + {CFB5E6D3-C2FD-4D46-B8AC-7E39634E2CA9}.Release|x64.Build.0 = Release|Any CPU {334726D9-6524-4318-82F1-4B72A1027E6E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {334726D9-6524-4318-82F1-4B72A1027E6E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {334726D9-6524-4318-82F1-4B72A1027E6E}.Debug|x64.ActiveCfg = Debug|Any CPU + {334726D9-6524-4318-82F1-4B72A1027E6E}.Debug|x64.Build.0 = Debug|Any CPU {334726D9-6524-4318-82F1-4B72A1027E6E}.Release|Any CPU.ActiveCfg = Release|Any CPU {334726D9-6524-4318-82F1-4B72A1027E6E}.Release|Any CPU.Build.0 = Release|Any CPU + {334726D9-6524-4318-82F1-4B72A1027E6E}.Release|x64.ActiveCfg = Release|Any CPU + {334726D9-6524-4318-82F1-4B72A1027E6E}.Release|x64.Build.0 = Release|Any CPU {2AE339CD-1D81-46F4-AA19-703EB0CF86FB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {2AE339CD-1D81-46F4-AA19-703EB0CF86FB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2AE339CD-1D81-46F4-AA19-703EB0CF86FB}.Debug|x64.ActiveCfg = Debug|Any CPU + {2AE339CD-1D81-46F4-AA19-703EB0CF86FB}.Debug|x64.Build.0 = Debug|Any CPU {2AE339CD-1D81-46F4-AA19-703EB0CF86FB}.Release|Any CPU.ActiveCfg = Release|Any CPU {2AE339CD-1D81-46F4-AA19-703EB0CF86FB}.Release|Any CPU.Build.0 = Release|Any CPU + {2AE339CD-1D81-46F4-AA19-703EB0CF86FB}.Release|x64.ActiveCfg = Release|Any CPU + {2AE339CD-1D81-46F4-AA19-703EB0CF86FB}.Release|x64.Build.0 = Release|Any CPU {BE4A63D6-8153-458C-AC0E-744C320AA521}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {BE4A63D6-8153-458C-AC0E-744C320AA521}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BE4A63D6-8153-458C-AC0E-744C320AA521}.Debug|x64.ActiveCfg = Debug|Any CPU + {BE4A63D6-8153-458C-AC0E-744C320AA521}.Debug|x64.Build.0 = Debug|Any CPU {BE4A63D6-8153-458C-AC0E-744C320AA521}.Release|Any CPU.ActiveCfg = Release|Any CPU {BE4A63D6-8153-458C-AC0E-744C320AA521}.Release|Any CPU.Build.0 = Release|Any CPU + {BE4A63D6-8153-458C-AC0E-744C320AA521}.Release|x64.ActiveCfg = Release|Any CPU + {BE4A63D6-8153-458C-AC0E-744C320AA521}.Release|x64.Build.0 = Release|Any CPU {E2810FAA-8EB3-4B3B-8667-C3C586137D28}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E2810FAA-8EB3-4B3B-8667-C3C586137D28}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E2810FAA-8EB3-4B3B-8667-C3C586137D28}.Debug|x64.ActiveCfg = Debug|Any CPU + {E2810FAA-8EB3-4B3B-8667-C3C586137D28}.Debug|x64.Build.0 = Debug|Any CPU {E2810FAA-8EB3-4B3B-8667-C3C586137D28}.Release|Any CPU.ActiveCfg = Release|Any CPU {E2810FAA-8EB3-4B3B-8667-C3C586137D28}.Release|Any CPU.Build.0 = Release|Any CPU + {E2810FAA-8EB3-4B3B-8667-C3C586137D28}.Release|x64.ActiveCfg = Release|Any CPU + {E2810FAA-8EB3-4B3B-8667-C3C586137D28}.Release|x64.Build.0 = Release|Any CPU {C8E18D2B-A445-42C4-B6C6-D6CAC51065DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C8E18D2B-A445-42C4-B6C6-D6CAC51065DC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C8E18D2B-A445-42C4-B6C6-D6CAC51065DC}.Debug|x64.ActiveCfg = Debug|Any CPU + {C8E18D2B-A445-42C4-B6C6-D6CAC51065DC}.Debug|x64.Build.0 = Debug|Any CPU {C8E18D2B-A445-42C4-B6C6-D6CAC51065DC}.Release|Any CPU.ActiveCfg = Release|Any CPU {C8E18D2B-A445-42C4-B6C6-D6CAC51065DC}.Release|Any CPU.Build.0 = Release|Any CPU + {C8E18D2B-A445-42C4-B6C6-D6CAC51065DC}.Release|x64.ActiveCfg = Release|Any CPU + {C8E18D2B-A445-42C4-B6C6-D6CAC51065DC}.Release|x64.Build.0 = Release|Any CPU {C52E282C-FA0A-4847-8D28-E9C4FDD8B729}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C52E282C-FA0A-4847-8D28-E9C4FDD8B729}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C52E282C-FA0A-4847-8D28-E9C4FDD8B729}.Debug|x64.ActiveCfg = Debug|Any CPU + {C52E282C-FA0A-4847-8D28-E9C4FDD8B729}.Debug|x64.Build.0 = Debug|Any CPU {C52E282C-FA0A-4847-8D28-E9C4FDD8B729}.Release|Any CPU.ActiveCfg = Release|Any CPU {C52E282C-FA0A-4847-8D28-E9C4FDD8B729}.Release|Any CPU.Build.0 = Release|Any CPU + {C52E282C-FA0A-4847-8D28-E9C4FDD8B729}.Release|x64.ActiveCfg = Release|Any CPU + {C52E282C-FA0A-4847-8D28-E9C4FDD8B729}.Release|x64.Build.0 = Release|Any CPU {C72AED47-F5FF-4B7B-BD11-62149542FB22}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C72AED47-F5FF-4B7B-BD11-62149542FB22}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C72AED47-F5FF-4B7B-BD11-62149542FB22}.Debug|x64.ActiveCfg = Debug|Any CPU + {C72AED47-F5FF-4B7B-BD11-62149542FB22}.Debug|x64.Build.0 = Debug|Any CPU {C72AED47-F5FF-4B7B-BD11-62149542FB22}.Release|Any CPU.ActiveCfg = Release|Any CPU {C72AED47-F5FF-4B7B-BD11-62149542FB22}.Release|Any CPU.Build.0 = Release|Any CPU + {C72AED47-F5FF-4B7B-BD11-62149542FB22}.Release|x64.ActiveCfg = Release|Any CPU + {C72AED47-F5FF-4B7B-BD11-62149542FB22}.Release|x64.Build.0 = Release|Any CPU {5600A9AF-934C-4225-B05D-F11DBC29E0FF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5600A9AF-934C-4225-B05D-F11DBC29E0FF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5600A9AF-934C-4225-B05D-F11DBC29E0FF}.Debug|x64.ActiveCfg = Debug|Any CPU + {5600A9AF-934C-4225-B05D-F11DBC29E0FF}.Debug|x64.Build.0 = Debug|Any CPU {5600A9AF-934C-4225-B05D-F11DBC29E0FF}.Release|Any CPU.ActiveCfg = Release|Any CPU {5600A9AF-934C-4225-B05D-F11DBC29E0FF}.Release|Any CPU.Build.0 = Release|Any CPU + {5600A9AF-934C-4225-B05D-F11DBC29E0FF}.Release|x64.ActiveCfg = Release|Any CPU + {5600A9AF-934C-4225-B05D-F11DBC29E0FF}.Release|x64.Build.0 = Release|Any CPU {D69636BA-CCE9-4A85-845E-A378A2B03D62}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D69636BA-CCE9-4A85-845E-A378A2B03D62}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D69636BA-CCE9-4A85-845E-A378A2B03D62}.Debug|x64.ActiveCfg = Debug|Any CPU + {D69636BA-CCE9-4A85-845E-A378A2B03D62}.Debug|x64.Build.0 = Debug|Any CPU {D69636BA-CCE9-4A85-845E-A378A2B03D62}.Release|Any CPU.ActiveCfg = Release|Any CPU {D69636BA-CCE9-4A85-845E-A378A2B03D62}.Release|Any CPU.Build.0 = Release|Any CPU + {D69636BA-CCE9-4A85-845E-A378A2B03D62}.Release|x64.ActiveCfg = Release|Any CPU + {D69636BA-CCE9-4A85-845E-A378A2B03D62}.Release|x64.Build.0 = Release|Any CPU {B7C52FC7-9678-442B-9B1E-F19F09B05606}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {B7C52FC7-9678-442B-9B1E-F19F09B05606}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B7C52FC7-9678-442B-9B1E-F19F09B05606}.Debug|x64.ActiveCfg = Debug|Any CPU + {B7C52FC7-9678-442B-9B1E-F19F09B05606}.Debug|x64.Build.0 = Debug|Any CPU {B7C52FC7-9678-442B-9B1E-F19F09B05606}.Release|Any CPU.ActiveCfg = Release|Any CPU {B7C52FC7-9678-442B-9B1E-F19F09B05606}.Release|Any CPU.Build.0 = Release|Any CPU + {B7C52FC7-9678-442B-9B1E-F19F09B05606}.Release|x64.ActiveCfg = Release|Any CPU + {B7C52FC7-9678-442B-9B1E-F19F09B05606}.Release|x64.Build.0 = Release|Any CPU {3F40EF71-126D-4D2B-84DB-37A574091B13}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3F40EF71-126D-4D2B-84DB-37A574091B13}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3F40EF71-126D-4D2B-84DB-37A574091B13}.Debug|x64.ActiveCfg = Debug|Any CPU + {3F40EF71-126D-4D2B-84DB-37A574091B13}.Debug|x64.Build.0 = Debug|Any CPU {3F40EF71-126D-4D2B-84DB-37A574091B13}.Release|Any CPU.ActiveCfg = Release|Any CPU {3F40EF71-126D-4D2B-84DB-37A574091B13}.Release|Any CPU.Build.0 = Release|Any CPU + {3F40EF71-126D-4D2B-84DB-37A574091B13}.Release|x64.ActiveCfg = Release|Any CPU + {3F40EF71-126D-4D2B-84DB-37A574091B13}.Release|x64.Build.0 = Release|Any CPU {B9F00634-88A1-40EF-9DAD-814A307AD81F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {B9F00634-88A1-40EF-9DAD-814A307AD81F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B9F00634-88A1-40EF-9DAD-814A307AD81F}.Debug|x64.ActiveCfg = Debug|Any CPU + {B9F00634-88A1-40EF-9DAD-814A307AD81F}.Debug|x64.Build.0 = Debug|Any CPU {B9F00634-88A1-40EF-9DAD-814A307AD81F}.Release|Any CPU.ActiveCfg = Release|Any CPU {B9F00634-88A1-40EF-9DAD-814A307AD81F}.Release|Any CPU.Build.0 = Release|Any CPU + {B9F00634-88A1-40EF-9DAD-814A307AD81F}.Release|x64.ActiveCfg = Release|Any CPU + {B9F00634-88A1-40EF-9DAD-814A307AD81F}.Release|x64.Build.0 = Release|Any CPU {BE194924-7162-405D-BF6E-E6086BAA12F1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {BE194924-7162-405D-BF6E-E6086BAA12F1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BE194924-7162-405D-BF6E-E6086BAA12F1}.Debug|x64.ActiveCfg = Debug|Any CPU + {BE194924-7162-405D-BF6E-E6086BAA12F1}.Debug|x64.Build.0 = Debug|Any CPU {BE194924-7162-405D-BF6E-E6086BAA12F1}.Release|Any CPU.ActiveCfg = Release|Any CPU {BE194924-7162-405D-BF6E-E6086BAA12F1}.Release|Any CPU.Build.0 = Release|Any CPU + {BE194924-7162-405D-BF6E-E6086BAA12F1}.Release|x64.ActiveCfg = Release|Any CPU + {BE194924-7162-405D-BF6E-E6086BAA12F1}.Release|x64.Build.0 = Release|Any CPU {4478A162-4FE9-4737-A630-3899DC5935C6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {4478A162-4FE9-4737-A630-3899DC5935C6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4478A162-4FE9-4737-A630-3899DC5935C6}.Debug|x64.ActiveCfg = Debug|Any CPU + {4478A162-4FE9-4737-A630-3899DC5935C6}.Debug|x64.Build.0 = Debug|Any CPU {4478A162-4FE9-4737-A630-3899DC5935C6}.Release|Any CPU.ActiveCfg = Release|Any CPU {4478A162-4FE9-4737-A630-3899DC5935C6}.Release|Any CPU.Build.0 = Release|Any CPU + {4478A162-4FE9-4737-A630-3899DC5935C6}.Release|x64.ActiveCfg = Release|Any CPU + {4478A162-4FE9-4737-A630-3899DC5935C6}.Release|x64.Build.0 = Release|Any CPU {7B73D864-9997-4637-8765-44C17FD09CE1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7B73D864-9997-4637-8765-44C17FD09CE1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7B73D864-9997-4637-8765-44C17FD09CE1}.Debug|x64.ActiveCfg = Debug|Any CPU + {7B73D864-9997-4637-8765-44C17FD09CE1}.Debug|x64.Build.0 = Debug|Any CPU {7B73D864-9997-4637-8765-44C17FD09CE1}.Release|Any CPU.ActiveCfg = Release|Any CPU {7B73D864-9997-4637-8765-44C17FD09CE1}.Release|Any CPU.Build.0 = Release|Any CPU + {7B73D864-9997-4637-8765-44C17FD09CE1}.Release|x64.ActiveCfg = Release|Any CPU + {7B73D864-9997-4637-8765-44C17FD09CE1}.Release|x64.Build.0 = Release|Any CPU {DAB8847B-DE0A-45E2-A7DA-30432A36525B}.Debug|Any CPU.ActiveCfg = Debug|x64 {DAB8847B-DE0A-45E2-A7DA-30432A36525B}.Debug|Any CPU.Build.0 = Debug|x64 + {DAB8847B-DE0A-45E2-A7DA-30432A36525B}.Debug|x64.ActiveCfg = Debug|x64 + {DAB8847B-DE0A-45E2-A7DA-30432A36525B}.Debug|x64.Build.0 = Debug|x64 {DAB8847B-DE0A-45E2-A7DA-30432A36525B}.Release|Any CPU.ActiveCfg = Release|x64 {DAB8847B-DE0A-45E2-A7DA-30432A36525B}.Release|Any CPU.Build.0 = Release|x64 + {DAB8847B-DE0A-45E2-A7DA-30432A36525B}.Release|x64.ActiveCfg = Release|x64 + {DAB8847B-DE0A-45E2-A7DA-30432A36525B}.Release|x64.Build.0 = Release|x64 {825B11E7-9BF3-43B7-9BCE-4309EE404AEE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {825B11E7-9BF3-43B7-9BCE-4309EE404AEE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {825B11E7-9BF3-43B7-9BCE-4309EE404AEE}.Debug|x64.ActiveCfg = Debug|Any CPU + {825B11E7-9BF3-43B7-9BCE-4309EE404AEE}.Debug|x64.Build.0 = Debug|Any CPU {825B11E7-9BF3-43B7-9BCE-4309EE404AEE}.Release|Any CPU.ActiveCfg = Release|Any CPU {825B11E7-9BF3-43B7-9BCE-4309EE404AEE}.Release|Any CPU.Build.0 = Release|Any CPU + {825B11E7-9BF3-43B7-9BCE-4309EE404AEE}.Release|x64.ActiveCfg = Release|Any CPU + {825B11E7-9BF3-43B7-9BCE-4309EE404AEE}.Release|x64.Build.0 = Release|Any CPU {896CE6A5-59AA-4F7B-90EB-562F47D3C49E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {896CE6A5-59AA-4F7B-90EB-562F47D3C49E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {896CE6A5-59AA-4F7B-90EB-562F47D3C49E}.Debug|x64.ActiveCfg = Debug|Any CPU + {896CE6A5-59AA-4F7B-90EB-562F47D3C49E}.Debug|x64.Build.0 = Debug|Any CPU {896CE6A5-59AA-4F7B-90EB-562F47D3C49E}.Release|Any CPU.ActiveCfg = Release|Any CPU {896CE6A5-59AA-4F7B-90EB-562F47D3C49E}.Release|Any CPU.Build.0 = Release|Any CPU + {896CE6A5-59AA-4F7B-90EB-562F47D3C49E}.Release|x64.ActiveCfg = Release|Any CPU + {896CE6A5-59AA-4F7B-90EB-562F47D3C49E}.Release|x64.Build.0 = Release|Any CPU {FE571017-BC81-4B70-A876-58A52CAB40B4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {FE571017-BC81-4B70-A876-58A52CAB40B4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FE571017-BC81-4B70-A876-58A52CAB40B4}.Debug|x64.ActiveCfg = Debug|Any CPU + {FE571017-BC81-4B70-A876-58A52CAB40B4}.Debug|x64.Build.0 = Debug|Any CPU {FE571017-BC81-4B70-A876-58A52CAB40B4}.Release|Any CPU.ActiveCfg = Release|Any CPU {FE571017-BC81-4B70-A876-58A52CAB40B4}.Release|Any CPU.Build.0 = Release|Any CPU + {FE571017-BC81-4B70-A876-58A52CAB40B4}.Release|x64.ActiveCfg = Release|Any CPU + {FE571017-BC81-4B70-A876-58A52CAB40B4}.Release|x64.Build.0 = Release|Any CPU {F1D041E0-DDB2-41B8-97EE-5539B10D91BE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F1D041E0-DDB2-41B8-97EE-5539B10D91BE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F1D041E0-DDB2-41B8-97EE-5539B10D91BE}.Debug|x64.ActiveCfg = Debug|Any CPU + {F1D041E0-DDB2-41B8-97EE-5539B10D91BE}.Debug|x64.Build.0 = Debug|Any CPU {F1D041E0-DDB2-41B8-97EE-5539B10D91BE}.Release|Any CPU.ActiveCfg = Release|Any CPU {F1D041E0-DDB2-41B8-97EE-5539B10D91BE}.Release|Any CPU.Build.0 = Release|Any CPU + {F1D041E0-DDB2-41B8-97EE-5539B10D91BE}.Release|x64.ActiveCfg = Release|Any CPU + {F1D041E0-DDB2-41B8-97EE-5539B10D91BE}.Release|x64.Build.0 = Release|Any CPU {6B572F54-0E2F-4223-8283-14B3BAB7534A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {6B572F54-0E2F-4223-8283-14B3BAB7534A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6B572F54-0E2F-4223-8283-14B3BAB7534A}.Debug|x64.ActiveCfg = Debug|Any CPU + {6B572F54-0E2F-4223-8283-14B3BAB7534A}.Debug|x64.Build.0 = Debug|Any CPU {6B572F54-0E2F-4223-8283-14B3BAB7534A}.Release|Any CPU.ActiveCfg = Release|Any CPU {6B572F54-0E2F-4223-8283-14B3BAB7534A}.Release|Any CPU.Build.0 = Release|Any CPU + {6B572F54-0E2F-4223-8283-14B3BAB7534A}.Release|x64.ActiveCfg = Release|Any CPU + {6B572F54-0E2F-4223-8283-14B3BAB7534A}.Release|x64.Build.0 = Release|Any CPU {084FB05C-4022-40FD-B00B-E3229B882F08}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {084FB05C-4022-40FD-B00B-E3229B882F08}.Debug|Any CPU.Build.0 = Debug|Any CPU + {084FB05C-4022-40FD-B00B-E3229B882F08}.Debug|x64.ActiveCfg = Debug|Any CPU + {084FB05C-4022-40FD-B00B-E3229B882F08}.Debug|x64.Build.0 = Debug|Any CPU {084FB05C-4022-40FD-B00B-E3229B882F08}.Release|Any CPU.ActiveCfg = Release|Any CPU {084FB05C-4022-40FD-B00B-E3229B882F08}.Release|Any CPU.Build.0 = Release|Any CPU + {084FB05C-4022-40FD-B00B-E3229B882F08}.Release|x64.ActiveCfg = Release|Any CPU + {084FB05C-4022-40FD-B00B-E3229B882F08}.Release|x64.Build.0 = Release|Any CPU {8D33307F-0E96-491A-9D31-9025709310F6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {8D33307F-0E96-491A-9D31-9025709310F6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8D33307F-0E96-491A-9D31-9025709310F6}.Debug|x64.ActiveCfg = Debug|Any CPU + {8D33307F-0E96-491A-9D31-9025709310F6}.Debug|x64.Build.0 = Debug|Any CPU {8D33307F-0E96-491A-9D31-9025709310F6}.Release|Any CPU.ActiveCfg = Release|Any CPU {8D33307F-0E96-491A-9D31-9025709310F6}.Release|Any CPU.Build.0 = Release|Any CPU + {8D33307F-0E96-491A-9D31-9025709310F6}.Release|x64.ActiveCfg = Release|Any CPU + {8D33307F-0E96-491A-9D31-9025709310F6}.Release|x64.Build.0 = Release|Any CPU {C91D0412-1BB2-40D2-8DCA-A48B6C5B7E67}.Debug|Any CPU.ActiveCfg = Debug|x64 {C91D0412-1BB2-40D2-8DCA-A48B6C5B7E67}.Debug|Any CPU.Build.0 = Debug|x64 + {C91D0412-1BB2-40D2-8DCA-A48B6C5B7E67}.Debug|x64.ActiveCfg = Debug|x64 + {C91D0412-1BB2-40D2-8DCA-A48B6C5B7E67}.Debug|x64.Build.0 = Debug|x64 {C91D0412-1BB2-40D2-8DCA-A48B6C5B7E67}.Release|Any CPU.ActiveCfg = Release|x64 {C91D0412-1BB2-40D2-8DCA-A48B6C5B7E67}.Release|Any CPU.Build.0 = Release|x64 + {C91D0412-1BB2-40D2-8DCA-A48B6C5B7E67}.Release|x64.ActiveCfg = Release|x64 + {C91D0412-1BB2-40D2-8DCA-A48B6C5B7E67}.Release|x64.Build.0 = Release|x64 {F31606FF-3737-45DC-8E89-6256AACD841F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F31606FF-3737-45DC-8E89-6256AACD841F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F31606FF-3737-45DC-8E89-6256AACD841F}.Debug|x64.ActiveCfg = Debug|Any CPU + {F31606FF-3737-45DC-8E89-6256AACD841F}.Debug|x64.Build.0 = Debug|Any CPU {F31606FF-3737-45DC-8E89-6256AACD841F}.Release|Any CPU.ActiveCfg = Release|Any CPU {F31606FF-3737-45DC-8E89-6256AACD841F}.Release|Any CPU.Build.0 = Release|Any CPU + {F31606FF-3737-45DC-8E89-6256AACD841F}.Release|x64.ActiveCfg = Release|Any CPU + {F31606FF-3737-45DC-8E89-6256AACD841F}.Release|x64.Build.0 = Release|Any CPU {5AC206E0-6B2E-4DBC-9B8A-74A47C907C6A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5AC206E0-6B2E-4DBC-9B8A-74A47C907C6A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5AC206E0-6B2E-4DBC-9B8A-74A47C907C6A}.Debug|x64.ActiveCfg = Debug|Any CPU + {5AC206E0-6B2E-4DBC-9B8A-74A47C907C6A}.Debug|x64.Build.0 = Debug|Any CPU {5AC206E0-6B2E-4DBC-9B8A-74A47C907C6A}.Release|Any CPU.ActiveCfg = Release|Any CPU {5AC206E0-6B2E-4DBC-9B8A-74A47C907C6A}.Release|Any CPU.Build.0 = Release|Any CPU + {5AC206E0-6B2E-4DBC-9B8A-74A47C907C6A}.Release|x64.ActiveCfg = Release|Any CPU + {5AC206E0-6B2E-4DBC-9B8A-74A47C907C6A}.Release|x64.Build.0 = Release|Any CPU {D18F494B-3639-4094-BD5E-BE8D81D5CD39}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D18F494B-3639-4094-BD5E-BE8D81D5CD39}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D18F494B-3639-4094-BD5E-BE8D81D5CD39}.Debug|x64.ActiveCfg = Debug|Any CPU + {D18F494B-3639-4094-BD5E-BE8D81D5CD39}.Debug|x64.Build.0 = Debug|Any CPU {D18F494B-3639-4094-BD5E-BE8D81D5CD39}.Release|Any CPU.ActiveCfg = Release|Any CPU {D18F494B-3639-4094-BD5E-BE8D81D5CD39}.Release|Any CPU.Build.0 = Release|Any CPU + {D18F494B-3639-4094-BD5E-BE8D81D5CD39}.Release|x64.ActiveCfg = Release|Any CPU + {D18F494B-3639-4094-BD5E-BE8D81D5CD39}.Release|x64.Build.0 = Release|Any CPU {CAE417E8-0E2D-499D-B11D-78A95155AF8A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {CAE417E8-0E2D-499D-B11D-78A95155AF8A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CAE417E8-0E2D-499D-B11D-78A95155AF8A}.Debug|x64.ActiveCfg = Debug|Any CPU + {CAE417E8-0E2D-499D-B11D-78A95155AF8A}.Debug|x64.Build.0 = Debug|Any CPU {CAE417E8-0E2D-499D-B11D-78A95155AF8A}.Release|Any CPU.ActiveCfg = Release|Any CPU {CAE417E8-0E2D-499D-B11D-78A95155AF8A}.Release|Any CPU.Build.0 = Release|Any CPU + {CAE417E8-0E2D-499D-B11D-78A95155AF8A}.Release|x64.ActiveCfg = Release|Any CPU + {CAE417E8-0E2D-499D-B11D-78A95155AF8A}.Release|x64.Build.0 = Release|Any CPU {D649D56B-777C-4246-8D59-C32749D94D39}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D649D56B-777C-4246-8D59-C32749D94D39}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D649D56B-777C-4246-8D59-C32749D94D39}.Debug|x64.ActiveCfg = Debug|Any CPU + {D649D56B-777C-4246-8D59-C32749D94D39}.Debug|x64.Build.0 = Debug|Any CPU {D649D56B-777C-4246-8D59-C32749D94D39}.Release|Any CPU.ActiveCfg = Release|Any CPU {D649D56B-777C-4246-8D59-C32749D94D39}.Release|Any CPU.Build.0 = Release|Any CPU + {D649D56B-777C-4246-8D59-C32749D94D39}.Release|x64.ActiveCfg = Release|Any CPU + {D649D56B-777C-4246-8D59-C32749D94D39}.Release|x64.Build.0 = Release|Any CPU {8B4F93E0-86D7-474C-8DD5-14E0AAD8BF91}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {8B4F93E0-86D7-474C-8DD5-14E0AAD8BF91}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8B4F93E0-86D7-474C-8DD5-14E0AAD8BF91}.Debug|x64.ActiveCfg = Debug|Any CPU + {8B4F93E0-86D7-474C-8DD5-14E0AAD8BF91}.Debug|x64.Build.0 = Debug|Any CPU {8B4F93E0-86D7-474C-8DD5-14E0AAD8BF91}.Release|Any CPU.ActiveCfg = Release|Any CPU {8B4F93E0-86D7-474C-8DD5-14E0AAD8BF91}.Release|Any CPU.Build.0 = Release|Any CPU + {8B4F93E0-86D7-474C-8DD5-14E0AAD8BF91}.Release|x64.ActiveCfg = Release|Any CPU + {8B4F93E0-86D7-474C-8DD5-14E0AAD8BF91}.Release|x64.Build.0 = Release|Any CPU {A0677BEA-ADB1-4950-89E6-89483D621A52}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {A0677BEA-ADB1-4950-89E6-89483D621A52}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A0677BEA-ADB1-4950-89E6-89483D621A52}.Debug|x64.ActiveCfg = Debug|Any CPU + {A0677BEA-ADB1-4950-89E6-89483D621A52}.Debug|x64.Build.0 = Debug|Any CPU {A0677BEA-ADB1-4950-89E6-89483D621A52}.Release|Any CPU.ActiveCfg = Release|Any CPU {A0677BEA-ADB1-4950-89E6-89483D621A52}.Release|Any CPU.Build.0 = Release|Any CPU + {A0677BEA-ADB1-4950-89E6-89483D621A52}.Release|x64.ActiveCfg = Release|Any CPU + {A0677BEA-ADB1-4950-89E6-89483D621A52}.Release|x64.Build.0 = Release|Any CPU {E0621435-AF35-4CFA-BE9E-3781AF6E161F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E0621435-AF35-4CFA-BE9E-3781AF6E161F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E0621435-AF35-4CFA-BE9E-3781AF6E161F}.Debug|x64.ActiveCfg = Debug|Any CPU + {E0621435-AF35-4CFA-BE9E-3781AF6E161F}.Debug|x64.Build.0 = Debug|Any CPU {E0621435-AF35-4CFA-BE9E-3781AF6E161F}.Release|Any CPU.ActiveCfg = Release|Any CPU {E0621435-AF35-4CFA-BE9E-3781AF6E161F}.Release|Any CPU.Build.0 = Release|Any CPU + {E0621435-AF35-4CFA-BE9E-3781AF6E161F}.Release|x64.ActiveCfg = Release|Any CPU + {E0621435-AF35-4CFA-BE9E-3781AF6E161F}.Release|x64.Build.0 = Release|Any CPU {C3114338-AD22-4EBC-85C3-EE06045CDD78}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C3114338-AD22-4EBC-85C3-EE06045CDD78}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C3114338-AD22-4EBC-85C3-EE06045CDD78}.Debug|x64.ActiveCfg = Debug|Any CPU + {C3114338-AD22-4EBC-85C3-EE06045CDD78}.Debug|x64.Build.0 = Debug|Any CPU {C3114338-AD22-4EBC-85C3-EE06045CDD78}.Release|Any CPU.ActiveCfg = Release|Any CPU {C3114338-AD22-4EBC-85C3-EE06045CDD78}.Release|Any CPU.Build.0 = Release|Any CPU + {C3114338-AD22-4EBC-85C3-EE06045CDD78}.Release|x64.ActiveCfg = Release|Any CPU + {C3114338-AD22-4EBC-85C3-EE06045CDD78}.Release|x64.Build.0 = Release|Any CPU {A1429F96-C7F8-49D8-ADB8-73A1A4DAA70F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {A1429F96-C7F8-49D8-ADB8-73A1A4DAA70F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A1429F96-C7F8-49D8-ADB8-73A1A4DAA70F}.Debug|x64.ActiveCfg = Debug|Any CPU + {A1429F96-C7F8-49D8-ADB8-73A1A4DAA70F}.Debug|x64.Build.0 = Debug|Any CPU {A1429F96-C7F8-49D8-ADB8-73A1A4DAA70F}.Release|Any CPU.ActiveCfg = Release|Any CPU {A1429F96-C7F8-49D8-ADB8-73A1A4DAA70F}.Release|Any CPU.Build.0 = Release|Any CPU + {A1429F96-C7F8-49D8-ADB8-73A1A4DAA70F}.Release|x64.ActiveCfg = Release|Any CPU + {A1429F96-C7F8-49D8-ADB8-73A1A4DAA70F}.Release|x64.Build.0 = Release|Any CPU {F50194C0-9561-40C7-B9CB-B977E3B3D76D}.Debug|Any CPU.ActiveCfg = Debug|ARM {F50194C0-9561-40C7-B9CB-B977E3B3D76D}.Debug|Any CPU.Build.0 = Debug|ARM + {F50194C0-9561-40C7-B9CB-B977E3B3D76D}.Debug|x64.ActiveCfg = Debug|x64 + {F50194C0-9561-40C7-B9CB-B977E3B3D76D}.Debug|x64.Build.0 = Debug|x64 {F50194C0-9561-40C7-B9CB-B977E3B3D76D}.Release|Any CPU.ActiveCfg = Release|ARM {F50194C0-9561-40C7-B9CB-B977E3B3D76D}.Release|Any CPU.Build.0 = Release|ARM + {F50194C0-9561-40C7-B9CB-B977E3B3D76D}.Release|x64.ActiveCfg = Release|x64 + {F50194C0-9561-40C7-B9CB-B977E3B3D76D}.Release|x64.Build.0 = Release|x64 {3434D5B2-B06F-4356-9E9B-90171CEF482B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3434D5B2-B06F-4356-9E9B-90171CEF482B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3434D5B2-B06F-4356-9E9B-90171CEF482B}.Debug|x64.ActiveCfg = Debug|Any CPU + {3434D5B2-B06F-4356-9E9B-90171CEF482B}.Debug|x64.Build.0 = Debug|Any CPU {3434D5B2-B06F-4356-9E9B-90171CEF482B}.Release|Any CPU.ActiveCfg = Release|Any CPU {3434D5B2-B06F-4356-9E9B-90171CEF482B}.Release|Any CPU.Build.0 = Release|Any CPU + {3434D5B2-B06F-4356-9E9B-90171CEF482B}.Release|x64.ActiveCfg = Release|Any CPU + {3434D5B2-B06F-4356-9E9B-90171CEF482B}.Release|x64.Build.0 = Release|Any CPU {ECD9E150-8104-4DA3-B807-A6A4392A67C6}.Debug|Any CPU.ActiveCfg = Debug|ARM {ECD9E150-8104-4DA3-B807-A6A4392A67C6}.Debug|Any CPU.Build.0 = Debug|ARM + {ECD9E150-8104-4DA3-B807-A6A4392A67C6}.Debug|x64.ActiveCfg = Debug|Win32 + {ECD9E150-8104-4DA3-B807-A6A4392A67C6}.Debug|x64.Build.0 = Debug|Win32 {ECD9E150-8104-4DA3-B807-A6A4392A67C6}.Release|Any CPU.ActiveCfg = Release|ARM {ECD9E150-8104-4DA3-B807-A6A4392A67C6}.Release|Any CPU.Build.0 = Release|ARM + {ECD9E150-8104-4DA3-B807-A6A4392A67C6}.Release|x64.ActiveCfg = Release|Win32 + {ECD9E150-8104-4DA3-B807-A6A4392A67C6}.Release|x64.Build.0 = Release|Win32 {BE95524A-F9C2-4D0D-8F7E-1C7019B5A114}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {BE95524A-F9C2-4D0D-8F7E-1C7019B5A114}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BE95524A-F9C2-4D0D-8F7E-1C7019B5A114}.Debug|x64.ActiveCfg = Debug|Any CPU + {BE95524A-F9C2-4D0D-8F7E-1C7019B5A114}.Debug|x64.Build.0 = Debug|Any CPU {BE95524A-F9C2-4D0D-8F7E-1C7019B5A114}.Release|Any CPU.ActiveCfg = Release|Any CPU {BE95524A-F9C2-4D0D-8F7E-1C7019B5A114}.Release|Any CPU.Build.0 = Release|Any CPU + {BE95524A-F9C2-4D0D-8F7E-1C7019B5A114}.Release|x64.ActiveCfg = Release|Any CPU + {BE95524A-F9C2-4D0D-8F7E-1C7019B5A114}.Release|x64.Build.0 = Release|Any CPU {74504D41-B716-4B0B-B265-ED2A91A2A5C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {74504D41-B716-4B0B-B265-ED2A91A2A5C2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {74504D41-B716-4B0B-B265-ED2A91A2A5C2}.Debug|x64.ActiveCfg = Debug|Any CPU + {74504D41-B716-4B0B-B265-ED2A91A2A5C2}.Debug|x64.Build.0 = Debug|Any CPU {74504D41-B716-4B0B-B265-ED2A91A2A5C2}.Release|Any CPU.ActiveCfg = Release|Any CPU {74504D41-B716-4B0B-B265-ED2A91A2A5C2}.Release|Any CPU.Build.0 = Release|Any CPU + {74504D41-B716-4B0B-B265-ED2A91A2A5C2}.Release|x64.ActiveCfg = Release|Any CPU + {74504D41-B716-4B0B-B265-ED2A91A2A5C2}.Release|x64.Build.0 = Release|Any CPU {D318834B-5A27-4EAC-B17D-A9BD7A2DCA0D}.Debug|Any CPU.ActiveCfg = Debug|ARM {D318834B-5A27-4EAC-B17D-A9BD7A2DCA0D}.Debug|Any CPU.Build.0 = Debug|ARM {D318834B-5A27-4EAC-B17D-A9BD7A2DCA0D}.Debug|Any CPU.Deploy.0 = Debug|ARM + {D318834B-5A27-4EAC-B17D-A9BD7A2DCA0D}.Debug|x64.ActiveCfg = Debug|ARM + {D318834B-5A27-4EAC-B17D-A9BD7A2DCA0D}.Debug|x64.Build.0 = Debug|ARM + {D318834B-5A27-4EAC-B17D-A9BD7A2DCA0D}.Debug|x64.Deploy.0 = Debug|ARM {D318834B-5A27-4EAC-B17D-A9BD7A2DCA0D}.Release|Any CPU.ActiveCfg = Release|ARM {D318834B-5A27-4EAC-B17D-A9BD7A2DCA0D}.Release|Any CPU.Build.0 = Release|ARM {D318834B-5A27-4EAC-B17D-A9BD7A2DCA0D}.Release|Any CPU.Deploy.0 = Release|ARM + {D318834B-5A27-4EAC-B17D-A9BD7A2DCA0D}.Release|x64.ActiveCfg = Release|ARM + {D318834B-5A27-4EAC-B17D-A9BD7A2DCA0D}.Release|x64.Build.0 = Release|ARM + {D318834B-5A27-4EAC-B17D-A9BD7A2DCA0D}.Release|x64.Deploy.0 = Release|ARM {272CEB19-2B5A-49BC-B8EA-CBC79AA87C37}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {272CEB19-2B5A-49BC-B8EA-CBC79AA87C37}.Debug|Any CPU.Build.0 = Debug|Any CPU + {272CEB19-2B5A-49BC-B8EA-CBC79AA87C37}.Debug|x64.ActiveCfg = Debug|Any CPU + {272CEB19-2B5A-49BC-B8EA-CBC79AA87C37}.Debug|x64.Build.0 = Debug|Any CPU {272CEB19-2B5A-49BC-B8EA-CBC79AA87C37}.Release|Any CPU.ActiveCfg = Release|Any CPU {272CEB19-2B5A-49BC-B8EA-CBC79AA87C37}.Release|Any CPU.Build.0 = Release|Any CPU + {272CEB19-2B5A-49BC-B8EA-CBC79AA87C37}.Release|x64.ActiveCfg = Release|Any CPU + {272CEB19-2B5A-49BC-B8EA-CBC79AA87C37}.Release|x64.Build.0 = Release|Any CPU {1C844B9E-A51C-483C-A045-7AB8F2012581}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {1C844B9E-A51C-483C-A045-7AB8F2012581}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1C844B9E-A51C-483C-A045-7AB8F2012581}.Debug|x64.ActiveCfg = Debug|Any CPU + {1C844B9E-A51C-483C-A045-7AB8F2012581}.Debug|x64.Build.0 = Debug|Any CPU {1C844B9E-A51C-483C-A045-7AB8F2012581}.Release|Any CPU.ActiveCfg = Release|Any CPU {1C844B9E-A51C-483C-A045-7AB8F2012581}.Release|Any CPU.Build.0 = Release|Any CPU + {1C844B9E-A51C-483C-A045-7AB8F2012581}.Release|x64.ActiveCfg = Release|Any CPU + {1C844B9E-A51C-483C-A045-7AB8F2012581}.Release|x64.Build.0 = Release|Any CPU {76E38559-0AF2-4AE3-BCE8-8653277A5B07}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {76E38559-0AF2-4AE3-BCE8-8653277A5B07}.Debug|Any CPU.Build.0 = Debug|Any CPU + {76E38559-0AF2-4AE3-BCE8-8653277A5B07}.Debug|x64.ActiveCfg = Debug|Any CPU + {76E38559-0AF2-4AE3-BCE8-8653277A5B07}.Debug|x64.Build.0 = Debug|Any CPU {76E38559-0AF2-4AE3-BCE8-8653277A5B07}.Release|Any CPU.ActiveCfg = Release|Any CPU {76E38559-0AF2-4AE3-BCE8-8653277A5B07}.Release|Any CPU.Build.0 = Release|Any CPU + {76E38559-0AF2-4AE3-BCE8-8653277A5B07}.Release|x64.ActiveCfg = Release|Any CPU + {76E38559-0AF2-4AE3-BCE8-8653277A5B07}.Release|x64.Build.0 = Release|Any CPU {41FBDC53-3167-4DEA-8B87-CFCCAFBCE7DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {41FBDC53-3167-4DEA-8B87-CFCCAFBCE7DD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {41FBDC53-3167-4DEA-8B87-CFCCAFBCE7DD}.Debug|x64.ActiveCfg = Debug|Any CPU + {41FBDC53-3167-4DEA-8B87-CFCCAFBCE7DD}.Debug|x64.Build.0 = Debug|Any CPU {41FBDC53-3167-4DEA-8B87-CFCCAFBCE7DD}.Release|Any CPU.ActiveCfg = Release|Any CPU {41FBDC53-3167-4DEA-8B87-CFCCAFBCE7DD}.Release|Any CPU.Build.0 = Release|Any CPU + {41FBDC53-3167-4DEA-8B87-CFCCAFBCE7DD}.Release|x64.ActiveCfg = Release|Any CPU + {41FBDC53-3167-4DEA-8B87-CFCCAFBCE7DD}.Release|x64.Build.0 = Release|Any CPU {860DC343-4022-4A6B-9053-8729DFBD5C96}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {860DC343-4022-4A6B-9053-8729DFBD5C96}.Debug|Any CPU.Build.0 = Debug|Any CPU + {860DC343-4022-4A6B-9053-8729DFBD5C96}.Debug|x64.ActiveCfg = Debug|Any CPU + {860DC343-4022-4A6B-9053-8729DFBD5C96}.Debug|x64.Build.0 = Debug|Any CPU {860DC343-4022-4A6B-9053-8729DFBD5C96}.Release|Any CPU.ActiveCfg = Release|Any CPU {860DC343-4022-4A6B-9053-8729DFBD5C96}.Release|Any CPU.Build.0 = Release|Any CPU + {860DC343-4022-4A6B-9053-8729DFBD5C96}.Release|x64.ActiveCfg = Release|Any CPU + {860DC343-4022-4A6B-9053-8729DFBD5C96}.Release|x64.Build.0 = Release|Any CPU {4C87BA2C-4EF4-447A-9409-4FD8CE9BC54D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4C87BA2C-4EF4-447A-9409-4FD8CE9BC54D}.Debug|x64.ActiveCfg = Debug|Any CPU {4C87BA2C-4EF4-447A-9409-4FD8CE9BC54D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4C87BA2C-4EF4-447A-9409-4FD8CE9BC54D}.Release|x64.ActiveCfg = Release|Any CPU {F2A56B74-FA18-4CD8-B686-61235A2DDB8C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F2A56B74-FA18-4CD8-B686-61235A2DDB8C}.Debug|x64.ActiveCfg = Debug|Any CPU {F2A56B74-FA18-4CD8-B686-61235A2DDB8C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F2A56B74-FA18-4CD8-B686-61235A2DDB8C}.Release|x64.ActiveCfg = Release|Any CPU {108D5CA8-8C44-4F7E-8C9F-02D6C1C6215F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {108D5CA8-8C44-4F7E-8C9F-02D6C1C6215F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {108D5CA8-8C44-4F7E-8C9F-02D6C1C6215F}.Debug|x64.ActiveCfg = Debug|Any CPU + {108D5CA8-8C44-4F7E-8C9F-02D6C1C6215F}.Debug|x64.Build.0 = Debug|Any CPU {108D5CA8-8C44-4F7E-8C9F-02D6C1C6215F}.Release|Any CPU.ActiveCfg = Release|Any CPU {108D5CA8-8C44-4F7E-8C9F-02D6C1C6215F}.Release|Any CPU.Build.0 = Release|Any CPU + {108D5CA8-8C44-4F7E-8C9F-02D6C1C6215F}.Release|x64.ActiveCfg = Release|Any CPU + {108D5CA8-8C44-4F7E-8C9F-02D6C1C6215F}.Release|x64.Build.0 = Release|Any CPU {1AFBBD50-CE3A-4792-BE84-15E897D281DD}.Debug|Any CPU.ActiveCfg = Debug|ARM {1AFBBD50-CE3A-4792-BE84-15E897D281DD}.Debug|Any CPU.Build.0 = Debug|ARM + {1AFBBD50-CE3A-4792-BE84-15E897D281DD}.Debug|x64.ActiveCfg = Debug|Win32 + {1AFBBD50-CE3A-4792-BE84-15E897D281DD}.Debug|x64.Build.0 = Debug|Win32 {1AFBBD50-CE3A-4792-BE84-15E897D281DD}.Release|Any CPU.ActiveCfg = Release|ARM {1AFBBD50-CE3A-4792-BE84-15E897D281DD}.Release|Any CPU.Build.0 = Release|ARM + {1AFBBD50-CE3A-4792-BE84-15E897D281DD}.Release|x64.ActiveCfg = Release|Win32 + {1AFBBD50-CE3A-4792-BE84-15E897D281DD}.Release|x64.Build.0 = Release|Win32 {632F209F-D0DD-4CE7-8975-C2D9F43EB964}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {632F209F-D0DD-4CE7-8975-C2D9F43EB964}.Debug|Any CPU.Build.0 = Debug|Any CPU + {632F209F-D0DD-4CE7-8975-C2D9F43EB964}.Debug|x64.ActiveCfg = Debug|Any CPU + {632F209F-D0DD-4CE7-8975-C2D9F43EB964}.Debug|x64.Build.0 = Debug|Any CPU {632F209F-D0DD-4CE7-8975-C2D9F43EB964}.Release|Any CPU.ActiveCfg = Release|Any CPU {632F209F-D0DD-4CE7-8975-C2D9F43EB964}.Release|Any CPU.Build.0 = Release|Any CPU + {632F209F-D0DD-4CE7-8975-C2D9F43EB964}.Release|x64.ActiveCfg = Release|Any CPU + {632F209F-D0DD-4CE7-8975-C2D9F43EB964}.Release|x64.Build.0 = Release|Any CPU {A94E45E7-5C81-4E7B-8500-F1C1B0DCB46E}.Debug|Any CPU.ActiveCfg = Debug|ARM {A94E45E7-5C81-4E7B-8500-F1C1B0DCB46E}.Debug|Any CPU.Build.0 = Debug|ARM + {A94E45E7-5C81-4E7B-8500-F1C1B0DCB46E}.Debug|x64.ActiveCfg = Debug|ARM + {A94E45E7-5C81-4E7B-8500-F1C1B0DCB46E}.Debug|x64.Build.0 = Debug|ARM {A94E45E7-5C81-4E7B-8500-F1C1B0DCB46E}.Release|Any CPU.ActiveCfg = Release|ARM {A94E45E7-5C81-4E7B-8500-F1C1B0DCB46E}.Release|Any CPU.Build.0 = Release|ARM + {A94E45E7-5C81-4E7B-8500-F1C1B0DCB46E}.Release|x64.ActiveCfg = Release|ARM + {A94E45E7-5C81-4E7B-8500-F1C1B0DCB46E}.Release|x64.Build.0 = Release|ARM {046DE977-8DFD-4847-A4D5-E65E3168E0CA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {046DE977-8DFD-4847-A4D5-E65E3168E0CA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {046DE977-8DFD-4847-A4D5-E65E3168E0CA}.Debug|x64.ActiveCfg = Debug|Any CPU + {046DE977-8DFD-4847-A4D5-E65E3168E0CA}.Debug|x64.Build.0 = Debug|Any CPU {046DE977-8DFD-4847-A4D5-E65E3168E0CA}.Release|Any CPU.ActiveCfg = Release|Any CPU {046DE977-8DFD-4847-A4D5-E65E3168E0CA}.Release|Any CPU.Build.0 = Release|Any CPU + {046DE977-8DFD-4847-A4D5-E65E3168E0CA}.Release|x64.ActiveCfg = Release|Any CPU + {046DE977-8DFD-4847-A4D5-E65E3168E0CA}.Release|x64.Build.0 = Release|Any CPU {82378A12-3492-457D-AF76-CBF08CCE9832}.Debug|Any CPU.ActiveCfg = Debug|ARM {82378A12-3492-457D-AF76-CBF08CCE9832}.Debug|Any CPU.Build.0 = Debug|ARM {82378A12-3492-457D-AF76-CBF08CCE9832}.Debug|Any CPU.Deploy.0 = Debug|ARM + {82378A12-3492-457D-AF76-CBF08CCE9832}.Debug|x64.ActiveCfg = Debug|ARM + {82378A12-3492-457D-AF76-CBF08CCE9832}.Debug|x64.Build.0 = Debug|ARM + {82378A12-3492-457D-AF76-CBF08CCE9832}.Debug|x64.Deploy.0 = Debug|ARM {82378A12-3492-457D-AF76-CBF08CCE9832}.Release|Any CPU.ActiveCfg = Release|ARM {82378A12-3492-457D-AF76-CBF08CCE9832}.Release|Any CPU.Build.0 = Release|ARM {82378A12-3492-457D-AF76-CBF08CCE9832}.Release|Any CPU.Deploy.0 = Release|ARM + {82378A12-3492-457D-AF76-CBF08CCE9832}.Release|x64.ActiveCfg = Release|ARM + {82378A12-3492-457D-AF76-CBF08CCE9832}.Release|x64.Build.0 = Release|ARM + {82378A12-3492-457D-AF76-CBF08CCE9832}.Release|x64.Deploy.0 = Release|ARM {365D836D-AD15-428C-96D1-6C4870525FEF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {365D836D-AD15-428C-96D1-6C4870525FEF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {365D836D-AD15-428C-96D1-6C4870525FEF}.Debug|x64.ActiveCfg = Debug|Any CPU + {365D836D-AD15-428C-96D1-6C4870525FEF}.Debug|x64.Build.0 = Debug|Any CPU {365D836D-AD15-428C-96D1-6C4870525FEF}.Release|Any CPU.ActiveCfg = Release|Any CPU {365D836D-AD15-428C-96D1-6C4870525FEF}.Release|Any CPU.Build.0 = Release|Any CPU + {365D836D-AD15-428C-96D1-6C4870525FEF}.Release|x64.ActiveCfg = Release|Any CPU + {365D836D-AD15-428C-96D1-6C4870525FEF}.Release|x64.Build.0 = Release|Any CPU + {DF585F32-54AA-4553-AF91-6BBD1732E147}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DF585F32-54AA-4553-AF91-6BBD1732E147}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DF585F32-54AA-4553-AF91-6BBD1732E147}.Debug|x64.ActiveCfg = Debug|Any CPU + {DF585F32-54AA-4553-AF91-6BBD1732E147}.Debug|x64.Build.0 = Debug|Any CPU + {DF585F32-54AA-4553-AF91-6BBD1732E147}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DF585F32-54AA-4553-AF91-6BBD1732E147}.Release|Any CPU.Build.0 = Release|Any CPU + {DF585F32-54AA-4553-AF91-6BBD1732E147}.Release|x64.ActiveCfg = Release|Any CPU + {DF585F32-54AA-4553-AF91-6BBD1732E147}.Release|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -689,6 +1013,7 @@ Global {046DE977-8DFD-4847-A4D5-E65E3168E0CA} = {82274752-96AB-49DA-8B51-BA8356319308} {82378A12-3492-457D-AF76-CBF08CCE9832} = {82274752-96AB-49DA-8B51-BA8356319308} {365D836D-AD15-428C-96D1-6C4870525FEF} = {82274752-96AB-49DA-8B51-BA8356319308} + {DF585F32-54AA-4553-AF91-6BBD1732E147} = {3F77CC04-2E58-452B-8107-0C93E7944D4E} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {EAF15EE9-DCC5-411B-A9E5-7C2F3D132331} diff --git a/Sources/Audio/Microsoft.Psi.Audio.Linux/Microsoft.Psi.Audio.Linux.csproj b/Sources/Audio/Microsoft.Psi.Audio.Linux/Microsoft.Psi.Audio.Linux.csproj index ede6f18d0..5a9a11e01 100644 --- a/Sources/Audio/Microsoft.Psi.Audio.Linux/Microsoft.Psi.Audio.Linux.csproj +++ b/Sources/Audio/Microsoft.Psi.Audio.Linux/Microsoft.Psi.Audio.Linux.csproj @@ -4,6 +4,7 @@ netstandard2.0 true Provides Linux-specific APIs and components for audio capture and playback. + $(SolutionDir)\Build\PsiPackages diff --git a/Sources/Audio/Microsoft.Psi.Audio.Windows/Microsoft.Psi.Audio.Windows.csproj b/Sources/Audio/Microsoft.Psi.Audio.Windows/Microsoft.Psi.Audio.Windows.csproj index ddbda099f..d31ebbf9b 100644 --- a/Sources/Audio/Microsoft.Psi.Audio.Windows/Microsoft.Psi.Audio.Windows.csproj +++ b/Sources/Audio/Microsoft.Psi.Audio.Windows/Microsoft.Psi.Audio.Windows.csproj @@ -4,6 +4,7 @@ Provides Windows-specific APIs and components for audio capture, processing and playback. true Microsoft.Psi.Audio + $(SolutionDir)\Build\PsiPackages true diff --git a/Sources/Audio/Microsoft.Psi.Audio/Microsoft.Psi.Audio.csproj b/Sources/Audio/Microsoft.Psi.Audio/Microsoft.Psi.Audio.csproj index 7c3fd0d51..1254cb989 100644 --- a/Sources/Audio/Microsoft.Psi.Audio/Microsoft.Psi.Audio.csproj +++ b/Sources/Audio/Microsoft.Psi.Audio/Microsoft.Psi.Audio.csproj @@ -4,6 +4,7 @@ netstandard2.0 Provides data structures and APIs for audio processing. true + $(SolutionDir)\Build\PsiPackages diff --git a/Sources/Calibration/Microsoft.Psi.Calibration/Microsoft.Psi.Calibration.csproj b/Sources/Calibration/Microsoft.Psi.Calibration/Microsoft.Psi.Calibration.csproj index 7de76a6f3..f09429a45 100644 --- a/Sources/Calibration/Microsoft.Psi.Calibration/Microsoft.Psi.Calibration.csproj +++ b/Sources/Calibration/Microsoft.Psi.Calibration/Microsoft.Psi.Calibration.csproj @@ -5,6 +5,7 @@ true Microsoft.Psi.Calibration Microsoft.Psi.Calibration + $(SolutionDir)\Build\PsiPackages bin\Release\netstandard2.0\Microsoft.Psi.Calibration.xml diff --git a/Sources/Data/Microsoft.Psi.Data/Microsoft.Psi.Data.csproj b/Sources/Data/Microsoft.Psi.Data/Microsoft.Psi.Data.csproj index e482e6aef..ca9f06b89 100644 --- a/Sources/Data/Microsoft.Psi.Data/Microsoft.Psi.Data.csproj +++ b/Sources/Data/Microsoft.Psi.Data/Microsoft.Psi.Data.csproj @@ -1,9 +1,10 @@ - + netstandard2.0 true Provides APIs for manipulating datasets. + $(SolutionDir)\Build\PsiPackages diff --git a/Sources/Devices/Microsoft.Psi.DeviceManagement/Microsoft.Psi.DeviceManagement.csproj b/Sources/Devices/Microsoft.Psi.DeviceManagement/Microsoft.Psi.DeviceManagement.csproj index 116b00ce9..d0ab771a8 100644 --- a/Sources/Devices/Microsoft.Psi.DeviceManagement/Microsoft.Psi.DeviceManagement.csproj +++ b/Sources/Devices/Microsoft.Psi.DeviceManagement/Microsoft.Psi.DeviceManagement.csproj @@ -4,6 +4,7 @@ netstandard2.0 Provides data structures that support enumerating devices. true + $(SolutionDir)\Build\PsiPackages diff --git a/Sources/Filters/Microsoft.Psi.Filters/Microsoft.Psi.Filters.csproj b/Sources/Filters/Microsoft.Psi.Filters/Microsoft.Psi.Filters.csproj index faa88e45a..07cc6608f 100644 --- a/Sources/Filters/Microsoft.Psi.Filters/Microsoft.Psi.Filters.csproj +++ b/Sources/Filters/Microsoft.Psi.Filters/Microsoft.Psi.Filters.csproj @@ -6,6 +6,7 @@ true true ..\..\..\Build\Microsoft.Psi.ruleset + $(SolutionDir)\Build\PsiPackages diff --git a/Sources/Imaging/Microsoft.Psi.Imaging.Linux/Microsoft.Psi.Imaging.Linux.csproj b/Sources/Imaging/Microsoft.Psi.Imaging.Linux/Microsoft.Psi.Imaging.Linux.csproj index d44512e58..54fe76cb5 100644 --- a/Sources/Imaging/Microsoft.Psi.Imaging.Linux/Microsoft.Psi.Imaging.Linux.csproj +++ b/Sources/Imaging/Microsoft.Psi.Imaging.Linux/Microsoft.Psi.Imaging.Linux.csproj @@ -4,6 +4,7 @@ netstandard2.0 true Provides Linux-specific components for encoding and decoding images. + $(SolutionDir)\Build\PsiPackages diff --git a/Sources/Imaging/Microsoft.Psi.Imaging.Windows/Microsoft.Psi.Imaging.Windows.csproj b/Sources/Imaging/Microsoft.Psi.Imaging.Windows/Microsoft.Psi.Imaging.Windows.csproj index ba3f5fa23..b4b860827 100644 --- a/Sources/Imaging/Microsoft.Psi.Imaging.Windows/Microsoft.Psi.Imaging.Windows.csproj +++ b/Sources/Imaging/Microsoft.Psi.Imaging.Windows/Microsoft.Psi.Imaging.Windows.csproj @@ -4,6 +4,7 @@ Provides Windows-specific components for encoding and decoding images. true Microsoft.Psi.Imaging + $(SolutionDir)\Build\PsiPackages bin\Release\net472\Microsoft.Psi.Imaging.Windows.xml diff --git a/Sources/Imaging/Microsoft.Psi.Imaging/Microsoft.Psi.Imaging.csproj b/Sources/Imaging/Microsoft.Psi.Imaging/Microsoft.Psi.Imaging.csproj index 14f23672a..820954d7b 100644 --- a/Sources/Imaging/Microsoft.Psi.Imaging/Microsoft.Psi.Imaging.csproj +++ b/Sources/Imaging/Microsoft.Psi.Imaging/Microsoft.Psi.Imaging.csproj @@ -4,6 +4,7 @@ netstandard2.0 Provides APIs and components for representing and manipulating images. true + $(SolutionDir)\Build\PsiPackages diff --git a/Sources/Integrations/CognitiveServices/Microsoft.Psi.CognitiveServices.Face/Microsoft.Psi.CognitiveServices.Face.csproj b/Sources/Integrations/CognitiveServices/Microsoft.Psi.CognitiveServices.Face/Microsoft.Psi.CognitiveServices.Face.csproj index 7cffa8594..76dd951fa 100644 --- a/Sources/Integrations/CognitiveServices/Microsoft.Psi.CognitiveServices.Face/Microsoft.Psi.CognitiveServices.Face.csproj +++ b/Sources/Integrations/CognitiveServices/Microsoft.Psi.CognitiveServices.Face/Microsoft.Psi.CognitiveServices.Face.csproj @@ -5,6 +5,7 @@ true ../../../../Build/Microsoft.Psi.ruleset Provides components for using Microsoft's Cognitive Services Face API. + $(SolutionDir)\Build\PsiPackages bin\Debug\netstandard2.0\Microsoft.Psi.CognitiveServices.Face.xml diff --git a/Sources/Integrations/CognitiveServices/Microsoft.Psi.CognitiveServices.Language.Windows/Microsoft.Psi.CognitiveServices.Language.Windows.csproj b/Sources/Integrations/CognitiveServices/Microsoft.Psi.CognitiveServices.Language.Windows/Microsoft.Psi.CognitiveServices.Language.Windows.csproj index c575be6b0..b828d1521 100644 --- a/Sources/Integrations/CognitiveServices/Microsoft.Psi.CognitiveServices.Language.Windows/Microsoft.Psi.CognitiveServices.Language.Windows.csproj +++ b/Sources/Integrations/CognitiveServices/Microsoft.Psi.CognitiveServices.Language.Windows/Microsoft.Psi.CognitiveServices.Language.Windows.csproj @@ -4,6 +4,7 @@ true Provides components for using Microsoft's Cognitive Services Language API. Microsoft.Psi.CognitiveServices.Language + $(SolutionDir)\Build\PsiPackages bin\Release\net472\Microsoft.Psi.CognitiveServices.Language.Windows.xml diff --git a/Sources/Integrations/CognitiveServices/Microsoft.Psi.CognitiveServices.Language/Microsoft.Psi.CognitiveServices.Language.csproj b/Sources/Integrations/CognitiveServices/Microsoft.Psi.CognitiveServices.Language/Microsoft.Psi.CognitiveServices.Language.csproj index 26772ce17..0a7319098 100644 --- a/Sources/Integrations/CognitiveServices/Microsoft.Psi.CognitiveServices.Language/Microsoft.Psi.CognitiveServices.Language.csproj +++ b/Sources/Integrations/CognitiveServices/Microsoft.Psi.CognitiveServices.Language/Microsoft.Psi.CognitiveServices.Language.csproj @@ -4,6 +4,7 @@ netstandard2.0 Provides components for using Microsoft's Cognitive Services Language Understanding Service (LUIS). true + $(SolutionDir)\Build\PsiPackages diff --git a/Sources/Integrations/CognitiveServices/Microsoft.Psi.CognitiveServices.Speech/Microsoft.Psi.CognitiveServices.Speech.csproj b/Sources/Integrations/CognitiveServices/Microsoft.Psi.CognitiveServices.Speech/Microsoft.Psi.CognitiveServices.Speech.csproj index 1fb3db79a..84ef863f1 100644 --- a/Sources/Integrations/CognitiveServices/Microsoft.Psi.CognitiveServices.Speech/Microsoft.Psi.CognitiveServices.Speech.csproj +++ b/Sources/Integrations/CognitiveServices/Microsoft.Psi.CognitiveServices.Speech/Microsoft.Psi.CognitiveServices.Speech.csproj @@ -4,6 +4,7 @@ netstandard2.0 Provides components for using Microsoft's Cognitive Services Speech API. true + $(SolutionDir)\Build\PsiPackages diff --git a/Sources/Integrations/CognitiveServices/Microsoft.Psi.CognitiveServices.Vision/Microsoft.Psi.CognitiveServices.Vision.csproj b/Sources/Integrations/CognitiveServices/Microsoft.Psi.CognitiveServices.Vision/Microsoft.Psi.CognitiveServices.Vision.csproj index 1f2b8f4cc..1a7947289 100644 --- a/Sources/Integrations/CognitiveServices/Microsoft.Psi.CognitiveServices.Vision/Microsoft.Psi.CognitiveServices.Vision.csproj +++ b/Sources/Integrations/CognitiveServices/Microsoft.Psi.CognitiveServices.Vision/Microsoft.Psi.CognitiveServices.Vision.csproj @@ -7,6 +7,7 @@ Library + $(SolutionDir)\Build\PsiPackages bin\Release\netstandard2.0\Microsoft.Psi.CognitiveServices.Vision.xml diff --git a/Sources/Integrations/Onnx/Microsoft.Psi.Onnx.Cpu/Microsoft.Psi.Onnx.Cpu.csproj b/Sources/Integrations/Onnx/Microsoft.Psi.Onnx.Cpu/Microsoft.Psi.Onnx.Cpu.csproj index 238738d91..3d40230ba 100644 --- a/Sources/Integrations/Onnx/Microsoft.Psi.Onnx.Cpu/Microsoft.Psi.Onnx.Cpu.csproj +++ b/Sources/Integrations/Onnx/Microsoft.Psi.Onnx.Cpu/Microsoft.Psi.Onnx.Cpu.csproj @@ -4,6 +4,7 @@ Provides components for running ONNX models. true Microsoft.Psi.Onnx + $(SolutionDir)\Build\PsiPackages bin\Release\netstandard2.0\Microsoft.Psi.Onnx.Cpu.xml diff --git a/Sources/Integrations/Onnx/Microsoft.Psi.Onnx.Gpu/Microsoft.Psi.Onnx.Gpu.csproj b/Sources/Integrations/Onnx/Microsoft.Psi.Onnx.Gpu/Microsoft.Psi.Onnx.Gpu.csproj index 4291ddf8a..a81b64221 100644 --- a/Sources/Integrations/Onnx/Microsoft.Psi.Onnx.Gpu/Microsoft.Psi.Onnx.Gpu.csproj +++ b/Sources/Integrations/Onnx/Microsoft.Psi.Onnx.Gpu/Microsoft.Psi.Onnx.Gpu.csproj @@ -4,6 +4,7 @@ Provides components for running ONNX models. true Microsoft.Psi.Onnx + $(SolutionDir)\Build\PsiPackages bin\Release\netstandard2.0\Microsoft.Psi.Onnx.Gpu.xml diff --git a/Sources/Integrations/Onnx/Microsoft.Psi.Onnx.ModelRunners.Cpu/Microsoft.Psi.Onnx.ModelRunners.Cpu.csproj b/Sources/Integrations/Onnx/Microsoft.Psi.Onnx.ModelRunners.Cpu/Microsoft.Psi.Onnx.ModelRunners.Cpu.csproj index 753390c42..dcaf954c5 100644 --- a/Sources/Integrations/Onnx/Microsoft.Psi.Onnx.ModelRunners.Cpu/Microsoft.Psi.Onnx.ModelRunners.Cpu.csproj +++ b/Sources/Integrations/Onnx/Microsoft.Psi.Onnx.ModelRunners.Cpu/Microsoft.Psi.Onnx.ModelRunners.Cpu.csproj @@ -8,6 +8,7 @@ true true true + $(SolutionDir)\Build\PsiPackages diff --git a/Sources/Integrations/Onnx/Microsoft.Psi.Onnx.ModelRunners.Gpu/Microsoft.Psi.Onnx.ModelRunners.Gpu.csproj b/Sources/Integrations/Onnx/Microsoft.Psi.Onnx.ModelRunners.Gpu/Microsoft.Psi.Onnx.ModelRunners.Gpu.csproj index 668540868..7fc18ca71 100644 --- a/Sources/Integrations/Onnx/Microsoft.Psi.Onnx.ModelRunners.Gpu/Microsoft.Psi.Onnx.ModelRunners.Gpu.csproj +++ b/Sources/Integrations/Onnx/Microsoft.Psi.Onnx.ModelRunners.Gpu/Microsoft.Psi.Onnx.ModelRunners.Gpu.csproj @@ -8,6 +8,7 @@ true true true + $(SolutionDir)\Build\PsiPackages diff --git a/Sources/Integrations/Onnx/Microsoft.Psi.Onnx.Visualization.Windows/Microsoft.Psi.Onnx.Visualization.Windows.csproj b/Sources/Integrations/Onnx/Microsoft.Psi.Onnx.Visualization.Windows/Microsoft.Psi.Onnx.Visualization.Windows.csproj index 552df04df..91d0be72b 100644 --- a/Sources/Integrations/Onnx/Microsoft.Psi.Onnx.Visualization.Windows/Microsoft.Psi.Onnx.Visualization.Windows.csproj +++ b/Sources/Integrations/Onnx/Microsoft.Psi.Onnx.Visualization.Windows/Microsoft.Psi.Onnx.Visualization.Windows.csproj @@ -4,6 +4,7 @@ net472 Microsoft.Psi.Onnx.Visualization Provides visualizers for ONNX model runner output types defined in Microsoft.Psi.Onnx.ModelRunners. + $(SolutionDir)\Build\PsiPackages diff --git a/Sources/Kinect/Microsoft.Psi.AzureKinect.Visualization/Microsoft.Psi.AzureKinect.Visualization.Windows.x64.csproj b/Sources/Kinect/Microsoft.Psi.AzureKinect.Visualization/Microsoft.Psi.AzureKinect.Visualization.Windows.x64.csproj index c78b0b2f4..529b7cc86 100644 --- a/Sources/Kinect/Microsoft.Psi.AzureKinect.Visualization/Microsoft.Psi.AzureKinect.Visualization.Windows.x64.csproj +++ b/Sources/Kinect/Microsoft.Psi.AzureKinect.Visualization/Microsoft.Psi.AzureKinect.Visualization.Windows.x64.csproj @@ -5,7 +5,8 @@ Microsoft.Psi.AzureKinect.Visualization x64 ../../../Build/Microsoft.Psi.ruleset - + $(SolutionDir)\Build\PsiPackages + DEBUG;TRACE bin\Debug\net472\Microsoft.Psi.AzureKinect.Visualization.Windows.x64.xml diff --git a/Sources/Kinect/Microsoft.Psi.AzureKinect.x64/Microsoft.Psi.AzureKinect.x64.csproj b/Sources/Kinect/Microsoft.Psi.AzureKinect.x64/Microsoft.Psi.AzureKinect.x64.csproj index cbf3743c2..44c5cd8e5 100644 --- a/Sources/Kinect/Microsoft.Psi.AzureKinect.x64/Microsoft.Psi.AzureKinect.x64.csproj +++ b/Sources/Kinect/Microsoft.Psi.AzureKinect.x64/Microsoft.Psi.AzureKinect.x64.csproj @@ -8,6 +8,7 @@ Microsoft.Psi.AzureKinect.x64.nuspec configuration=$(Configuration);version=$(Version) ../../../Build/Microsoft.Psi.ruleset + $(SolutionDir)\Build\PsiPackages x64 diff --git a/Sources/Kinect/Microsoft.Psi.Kinect.Face.Windows.x64/Microsoft.Psi.Kinect.Face.Windows.x64.csproj b/Sources/Kinect/Microsoft.Psi.Kinect.Face.Windows.x64/Microsoft.Psi.Kinect.Face.Windows.x64.csproj index 3645d4726..034f64de8 100644 --- a/Sources/Kinect/Microsoft.Psi.Kinect.Face.Windows.x64/Microsoft.Psi.Kinect.Face.Windows.x64.csproj +++ b/Sources/Kinect/Microsoft.Psi.Kinect.Face.Windows.x64/Microsoft.Psi.Kinect.Face.Windows.x64.csproj @@ -4,6 +4,7 @@ Provides APIs and components for using Microsoft Kinect Face APIs. true Microsoft.Psi.Kinect.Face + $(SolutionDir)\Build\PsiPackages true diff --git a/Sources/Kinect/Microsoft.Psi.Kinect.Visualization.Windows/Microsoft.Psi.Kinect.Visualization.Windows.csproj b/Sources/Kinect/Microsoft.Psi.Kinect.Visualization.Windows/Microsoft.Psi.Kinect.Visualization.Windows.csproj index a8e4000b3..037f9d8b0 100644 --- a/Sources/Kinect/Microsoft.Psi.Kinect.Visualization.Windows/Microsoft.Psi.Kinect.Visualization.Windows.csproj +++ b/Sources/Kinect/Microsoft.Psi.Kinect.Visualization.Windows/Microsoft.Psi.Kinect.Visualization.Windows.csproj @@ -6,7 +6,8 @@ AnyCPU ../../../Build/Microsoft.Psi.ruleset Provides visualizers for Kinect v2. - + $(SolutionDir)\Build\PsiPackages + DEBUG;TRACE bin\Debug\net472\Microsoft.Psi.Kinect.Visualization.Windows.xml diff --git a/Sources/Kinect/Microsoft.Psi.Kinect.Windows/Microsoft.Psi.Kinect.Windows.csproj b/Sources/Kinect/Microsoft.Psi.Kinect.Windows/Microsoft.Psi.Kinect.Windows.csproj index 80bc592ae..1044c7ec8 100644 --- a/Sources/Kinect/Microsoft.Psi.Kinect.Windows/Microsoft.Psi.Kinect.Windows.csproj +++ b/Sources/Kinect/Microsoft.Psi.Kinect.Windows/Microsoft.Psi.Kinect.Windows.csproj @@ -4,6 +4,7 @@ Provides APIs and components for using Microsoft Kinect sensor. true Microsoft.Psi.Kinect + $(SolutionDir)\Build\PsiPackages true diff --git a/Sources/Language/Microsoft.Psi.Language/Microsoft.Psi.Language.csproj b/Sources/Language/Microsoft.Psi.Language/Microsoft.Psi.Language.csproj index ee8444a80..fcb93d474 100644 --- a/Sources/Language/Microsoft.Psi.Language/Microsoft.Psi.Language.csproj +++ b/Sources/Language/Microsoft.Psi.Language/Microsoft.Psi.Language.csproj @@ -4,6 +4,7 @@ netstandard2.0 Provides data structures for natural language processing. true + $(SolutionDir)\Build\PsiPackages diff --git a/Sources/Media/Microsoft.Psi.Media.Linux/Microsoft.Psi.Media.Linux.csproj b/Sources/Media/Microsoft.Psi.Media.Linux/Microsoft.Psi.Media.Linux.csproj index 842ba428f..fae3d51be 100644 --- a/Sources/Media/Microsoft.Psi.Media.Linux/Microsoft.Psi.Media.Linux.csproj +++ b/Sources/Media/Microsoft.Psi.Media.Linux/Microsoft.Psi.Media.Linux.csproj @@ -9,6 +9,7 @@ true Microsoft.Psi.Media Provides Linux-specific APIs and components for audio-visual capture. + $(SolutionDir)\Build\PsiPackages diff --git a/Sources/Media/Microsoft.Psi.Media.Windows.x64/Microsoft.Psi.Media.Windows.x64.csproj b/Sources/Media/Microsoft.Psi.Media.Windows.x64/Microsoft.Psi.Media.Windows.x64.csproj index 45ecc6892..786f9e13d 100644 --- a/Sources/Media/Microsoft.Psi.Media.Windows.x64/Microsoft.Psi.Media.Windows.x64.csproj +++ b/Sources/Media/Microsoft.Psi.Media.Windows.x64/Microsoft.Psi.Media.Windows.x64.csproj @@ -4,6 +4,7 @@ true Microsoft.Psi.Media Provides Windows-specific APIs and components for audio-visual capture and processing. + $(SolutionDir)\Build\PsiPackages bin\Release\net472\Microsoft.Psi.Media.Windows.x64.xml diff --git a/Sources/Media/Microsoft.Psi.Media/Microsoft.Psi.Media.csproj b/Sources/Media/Microsoft.Psi.Media/Microsoft.Psi.Media.csproj index 99a41bb01..150448bd9 100644 --- a/Sources/Media/Microsoft.Psi.Media/Microsoft.Psi.Media.csproj +++ b/Sources/Media/Microsoft.Psi.Media/Microsoft.Psi.Media.csproj @@ -5,6 +5,7 @@ Provides data structures and APIs for audio-visual media processing. true Microsoft.Psi.Media + $(SolutionDir)\Build\PsiPackages diff --git a/Sources/MixedReality/HoloLens2ResearchMode/HoloLens2ResearchMode.vcxproj b/Sources/MixedReality/HoloLens2ResearchMode/HoloLens2ResearchMode.vcxproj index bf4cc56d8..b8f71a52b 100644 --- a/Sources/MixedReality/HoloLens2ResearchMode/HoloLens2ResearchMode.vcxproj +++ b/Sources/MixedReality/HoloLens2ResearchMode/HoloLens2ResearchMode.vcxproj @@ -1,6 +1,6 @@ - + true true @@ -161,13 +161,13 @@ - + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - + + \ No newline at end of file diff --git a/Sources/MixedReality/HoloLens2ResearchMode/packages.config b/Sources/MixedReality/HoloLens2ResearchMode/packages.config index 70bf1926d..1b8cfbd96 100644 --- a/Sources/MixedReality/HoloLens2ResearchMode/packages.config +++ b/Sources/MixedReality/HoloLens2ResearchMode/packages.config @@ -1,4 +1,4 @@  - + \ No newline at end of file diff --git a/Sources/MixedReality/HoloLensCapture/HoloLensCaptureApp/Package.appxmanifest b/Sources/MixedReality/HoloLensCapture/HoloLensCaptureApp/Package.appxmanifest index 3779d06d2..d51836e87 100644 --- a/Sources/MixedReality/HoloLensCapture/HoloLensCaptureApp/Package.appxmanifest +++ b/Sources/MixedReality/HoloLensCapture/HoloLensCaptureApp/Package.appxmanifest @@ -9,8 +9,8 @@ + Publisher="CN=AurélienM" + Version="1.0.2.0" /> diff --git a/Sources/MixedReality/Microsoft.Psi.MixedReality/Microsoft.Psi.MixedReality.csproj b/Sources/MixedReality/Microsoft.Psi.MixedReality/Microsoft.Psi.MixedReality.csproj index 7e72da776..3d63f907f 100644 --- a/Sources/MixedReality/Microsoft.Psi.MixedReality/Microsoft.Psi.MixedReality.csproj +++ b/Sources/MixedReality/Microsoft.Psi.MixedReality/Microsoft.Psi.MixedReality.csproj @@ -5,6 +5,7 @@ netstandard2.0 ../../../Build/Microsoft.Psi.ruleset true + $(SolutionDir)\Build\PsiPackages diff --git a/Sources/RealSense/Microsoft.Psi.RealSense_Interop.Windows.x64/packages.config b/Sources/RealSense/Microsoft.Psi.RealSense_Interop.Windows.x64/packages.config index 0f77b525b..750d2262e 100644 --- a/Sources/RealSense/Microsoft.Psi.RealSense_Interop.Windows.x64/packages.config +++ b/Sources/RealSense/Microsoft.Psi.RealSense_Interop.Windows.x64/packages.config @@ -1,4 +1,5 @@  - + + \ No newline at end of file diff --git a/Sources/Runtime/Microsoft.Psi.Interop/Microsoft.Psi.Interop.csproj b/Sources/Runtime/Microsoft.Psi.Interop/Microsoft.Psi.Interop.csproj index 04cc299fe..b1b43a6fd 100644 --- a/Sources/Runtime/Microsoft.Psi.Interop/Microsoft.Psi.Interop.csproj +++ b/Sources/Runtime/Microsoft.Psi.Interop/Microsoft.Psi.Interop.csproj @@ -4,6 +4,8 @@ netstandard2.0 true Provides APIs and components for interoperation with other data formats. + $(SolutionDir)\Build\PsiPackages + diff --git a/Sources/Runtime/Microsoft.Psi.Interop/Rendezvous/Operators.cs b/Sources/Runtime/Microsoft.Psi.Interop/Rendezvous/Operators.cs index 7a1608399..e8052c463 100644 --- a/Sources/Runtime/Microsoft.Psi.Interop/Rendezvous/Operators.cs +++ b/Sources/Runtime/Microsoft.Psi.Interop/Rendezvous/Operators.cs @@ -7,6 +7,7 @@ namespace Microsoft.Psi.Interop.Rendezvous using Microsoft.Psi.Interop.Serialization; using Microsoft.Psi.Interop.Transport; using Microsoft.Psi.Remoting; + using Microsoft.Psi.Serialization; /// /// Rendezvous related operators. @@ -70,6 +71,15 @@ public static Rendezvous.Endpoint ToRendezvousEndpoint(this NetMQWriter writer) public static Rendezvous.Endpoint ToRendezvousEndpoint(this RemoteClockExporter exporter, string host) => new Rendezvous.RemoteClockExporterEndpoint(host, exporter.Port); + /// + /// Create a rendezvous endpoint from a . + /// + /// from which to create endpoint. + /// Host address with which to create endpoint. + /// Rendezvous endpoint. + public static Rendezvous.Endpoint ToRendezvousEndpoint(this RemotePipelineClockExporter exporter, string host) + => new Rendezvous.RemotePipelineClockExporterEndpoint(host, exporter.Port); + /// /// Create a from a . /// @@ -106,9 +116,11 @@ public static Rendezvous.Endpoint ToRendezvousEndpoint(this RemoteExporter expor /// /// from which to create . /// The pipeline to add the component to. + /// Path for PsiStore. + /// Custom known serializers. /// . - public static RemoteImporter ToRemoteImporter(this Rendezvous.RemoteExporterEndpoint endpoint, Pipeline pipeline) - => new (pipeline, endpoint.Host, endpoint.Port); + public static RemoteImporter ToRemoteImporter(this Rendezvous.RemoteExporterEndpoint endpoint, Pipeline pipeline, string storePath, KnownSerializers knownSerializers) + => new (pipeline, storePath, endpoint.Host, endpoint.Port, knownSerializers); /// /// Create a from a . @@ -119,6 +131,15 @@ public static RemoteImporter ToRemoteImporter(this Rendezvous.RemoteExporterEndp public static RemoteClockImporter ToRemoteClockImporter(this Rendezvous.RemoteClockExporterEndpoint endpoint, Pipeline pipeline) => new (pipeline, endpoint.Host, endpoint.Port); + /// + /// Create a from a . + /// + /// from which to create . + /// The pipeline to add the component to. + /// . + public static RemotePipelineClockImporter ToRemotePipelineClockImporter(this Rendezvous.RemotePipelineClockExporterEndpoint endpoint, Pipeline pipeline) + => new (pipeline, endpoint.Host, endpoint.Port); + /// /// Writes a stream to a specified rendezvous process. /// diff --git a/Sources/Runtime/Microsoft.Psi.Interop/Rendezvous/Rendezvous.cs b/Sources/Runtime/Microsoft.Psi.Interop/Rendezvous/Rendezvous.cs index a910e257c..0e423250b 100644 --- a/Sources/Runtime/Microsoft.Psi.Interop/Rendezvous/Rendezvous.cs +++ b/Sources/Runtime/Microsoft.Psi.Interop/Rendezvous/Rendezvous.cs @@ -361,6 +361,42 @@ public override void AddStream(Stream stream) } } + /// + /// Represents a remote clock exporter endpoint providing clock information. + /// + /// + /// Endpoint does not provide any streams. Clock information is exchanged directly. + /// + public class RemotePipelineClockExporterEndpoint : Endpoint + { + /// + /// Initializes a new instance of the class. + /// + /// Host name used by the endpoint. + /// Port used by the endpoint. + public RemotePipelineClockExporterEndpoint(string host, int port) + { + this.Host = host; + this.Port = port; + } + + /// + /// Gets the endpoint host name. + /// + public string Host { get; private set; } + + /// + /// Gets the endpoint port. + /// + public int Port { get; private set; } + + /// + public override void AddStream(Stream stream) + { + throw new InvalidOperationException($"Cannot add streams to a {nameof(RemotePipelineClockExporterEndpoint)}"); + } + } + /// /// Represents an application process hosting endpoints. /// diff --git a/Sources/Runtime/Microsoft.Psi.Interop/Rendezvous/RendezvousRelay.cs b/Sources/Runtime/Microsoft.Psi.Interop/Rendezvous/RendezvousRelay.cs index 04ffc8197..32ab98fa4 100644 --- a/Sources/Runtime/Microsoft.Psi.Interop/Rendezvous/RendezvousRelay.cs +++ b/Sources/Runtime/Microsoft.Psi.Interop/Rendezvous/RendezvousRelay.cs @@ -69,6 +69,12 @@ protected static void WriteAddProcess(Rendezvous.Process process, BinaryWriter w writer.Write(remoteClockExporterEndpoint.Host); writer.Write(remoteClockExporterEndpoint.Port); } + else if (endpoint is Rendezvous.RemotePipelineClockExporterEndpoint remotePipelineClockExporterEndpoint) + { + writer.Write((byte)4); // RemotePipelineClockExporterEndpoint + writer.Write(remotePipelineClockExporterEndpoint.Host); + writer.Write(remotePipelineClockExporterEndpoint.Port); + } else { throw new ArgumentException($"Unknown type of Endpoint ({endpoint.GetType().Name})."); @@ -191,6 +197,11 @@ private static Rendezvous.Process ReadProcess(BinaryReader reader) port = reader.ReadInt32(); endpoint = new Rendezvous.RemoteClockExporterEndpoint(host, port); break; + case 4: // RemotePipelineClockExporerEndpoint + host = reader.ReadString(); + port = reader.ReadInt32(); + endpoint = new Rendezvous.RemotePipelineClockExporterEndpoint(host, port); + break; default: throw new Exception("Unknown type of Endpoint."); } diff --git a/Sources/Runtime/Microsoft.Psi.InteropAndroid/Microsoft.Psi.Interop.Android.csproj b/Sources/Runtime/Microsoft.Psi.InteropAndroid/Microsoft.Psi.Interop.Android.csproj new file mode 100644 index 000000000..9032dd930 --- /dev/null +++ b/Sources/Runtime/Microsoft.Psi.InteropAndroid/Microsoft.Psi.Interop.Android.csproj @@ -0,0 +1,48 @@ + + + + netstandard2.0 + False + Provides APIs and components for interoperation with other data formats. + + + + bin\Debug\netstandard2.0\Microsoft.Psi.Interop.xml + ../../../Build/Microsoft.Psi.ruleset + true + + + + + bin\Release\netstandard2.0\Microsoft.Psi.Interop.xml + ../../../Build/Microsoft.Psi.ruleset + true + + + + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers + + + + all + runtime; build; native; contentfiles; analyzers + + + + + + + + + diff --git a/Sources/Runtime/Microsoft.Psi.InteropAndroid/Readme.md b/Sources/Runtime/Microsoft.Psi.InteropAndroid/Readme.md new file mode 100644 index 000000000..197a6a9c2 --- /dev/null +++ b/Sources/Runtime/Microsoft.Psi.InteropAndroid/Readme.md @@ -0,0 +1,4 @@ +# Psi Interop Android + +Reduced version of `Microsoft.Psi.Interop` for using RendezVous system and TCPSource/Writer in Unity for Quest headset. +Should be used with Microsoft.Psi dll from this branch to be compatible. \ No newline at end of file diff --git a/Sources/Runtime/Microsoft.Psi.InteropAndroid/Rendezvous/Operators.cs b/Sources/Runtime/Microsoft.Psi.InteropAndroid/Rendezvous/Operators.cs new file mode 100644 index 000000000..8d350b410 --- /dev/null +++ b/Sources/Runtime/Microsoft.Psi.InteropAndroid/Rendezvous/Operators.cs @@ -0,0 +1,205 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +namespace Microsoft.Psi.Interop.Rendezvous +{ + using System; + using Microsoft.Psi.Interop.Serialization; + using Microsoft.Psi.Interop.Transport; + using Microsoft.Psi.Remoting; + using Microsoft.Psi.Serialization; + + /// + /// Rendezvous related operators. + /// + public static class Operators + { + /// + /// Create a rendezvous endpoint from a . + /// + /// Type of data stream. + /// from which to create endpoint. + /// Address with which to create endpoint. + /// The name of the rendezvous stream. + /// Rendezvous endpoint. + public static Rendezvous.Endpoint ToRendezvousEndpoint(this TcpWriter writer, string address, string streamName) + => new Rendezvous.TcpSourceEndpoint(address, writer.Port, new Rendezvous.Stream(streamName, typeof(T))); + + /// + /// Create a from a . + /// + /// Type of data stream. + /// from which to create . + /// The pipeline to add the component to. + /// The deserializer to use to deserialize messages. + /// An optional deallocator for the data. + /// An optional parameter indicating whether to use originating times received from the source over the network or to re-timestamp with the current pipeline time upon receiving. + /// An optional name for the TCP source component. + /// . + public static TcpSource ToTcpSource( + this Rendezvous.TcpSourceEndpoint endpoint, + Pipeline pipeline, + IFormatDeserializer deserializer, + Action deallocator = null, + bool useSourceOriginatingTimes = true, + string name = nameof(TcpSource)) + => new (pipeline, endpoint.Host, endpoint.Port, deserializer, deallocator, useSourceOriginatingTimes, name); + + /// + /// Create a rendezvous endpoint from a . + /// + /// Type of data stream. + /// from which to create endpoint. + /// Address with which to create endpoint. + /// The name of the rendezvous stream. + /// Rendezvous endpoint. + public static Rendezvous.Endpoint ToRendezvousEndpoint(this UdpWriter writer, string address, string streamName) + => new Rendezvous.UdpSourceEndpoint(address, writer.Port, new Rendezvous.Stream(streamName, typeof(T))); + + /// + /// Create a from a . + /// + /// Type of data stream. + /// from which to create. + /// The pipeline to add the component to. + /// The deserializer to use to deserialize messages. + /// An optional deallocator for the data. + /// An optional parameter indicating whether to use originating times received from the source over the network or to re-timestamp with the current pipeline time upon receiving. + /// An optional name for the UDP source component. + /// . + public static UdpSource ToUdpSource( + this Rendezvous.UdpSourceEndpoint endpoint, + Pipeline pipeline, + IFormatDeserializer deserializer, + Action deallocator = null, + bool useSourceOriginatingTimes = true, + string name = nameof(UdpSource)) + => new (pipeline, endpoint.Port, deserializer, deallocator, useSourceOriginatingTimes, name); + + /// + /// Create a rendezvous endpoint from a . + /// + /// from which to create endpoint. + /// Host address with which to create endpoint. + /// Rendezvous endpoint. + public static Rendezvous.Endpoint ToRendezvousEndpoint(this RemoteClockExporter exporter, string host) + => new Rendezvous.RemoteClockExporterEndpoint(host, exporter.Port); + + /// + /// Create a rendezvous endpoint from a . + /// + /// from which to create endpoint. + /// Host address with which to create endpoint. + /// Rendezvous endpoint. + public static Rendezvous.Endpoint ToRendezvousEndpoint(this RemotePipelineClockExporter exporter, string host) + => new Rendezvous.RemotePipelineClockExporterEndpoint(host, exporter.Port); + + /// + /// Create a rendezvous endpoint from a . + /// + /// from which to create endpoint. + /// Host name with which to create endpoint. + /// Rendezvous endpoint. + public static Rendezvous.Endpoint ToRendezvousEndpoint(this RemoteExporter exporter, string host) + { + // Each RemoteExporter is an endpoint emitting one or more streams. + var endpoint = new Rendezvous.RemoteExporterEndpoint(host, exporter.Port, exporter.TransportKind); + foreach (var m in exporter.Exporter.Metadata) + { + endpoint.AddStream(new Rendezvous.Stream(m.Name, m.TypeName)); + } + + return endpoint; + } + + /// + /// Create a from a . + /// + /// from which to create . + /// The pipeline to add the component to. + /// Path for PsiStore. + /// Custom known serializers. + /// . + public static RemoteImporter ToRemoteImporter(this Rendezvous.RemoteExporterEndpoint endpoint, Pipeline pipeline, string storePath, KnownSerializers knownSerializers) + => new (pipeline, storePath, endpoint.Host, endpoint.Port, knownSerializers, true); + + /// + /// Create a from a . + /// + /// from which to create . + /// The pipeline to add the component to. + /// . + public static RemoteImporter ToRemoteImporter(this Rendezvous.RemoteExporterEndpoint endpoint, Pipeline pipeline) + => new (pipeline, endpoint.Host, endpoint.Port); + + /// + /// Create a from a . + /// + /// from which to create . + /// The pipeline to add the component to. + /// . + public static RemoteClockImporter ToRemoteClockImporter(this Rendezvous.RemoteClockExporterEndpoint endpoint, Pipeline pipeline) + => new (pipeline, endpoint.Host, endpoint.Port); + + /// + /// Create a from a . + /// + /// from which to create . + /// The pipeline to add the component to. + /// . + public static RemotePipelineClockImporter ToRemotePipelineClockImporter(this Rendezvous.RemotePipelineClockExporterEndpoint endpoint, Pipeline pipeline) + => new (pipeline, endpoint.Host, endpoint.Port); + + /// + /// Writes a stream to a specified rendezvous process. + /// + /// The type of data in the stream. + /// The source stream to write. + /// The name under which to write the stream to the rendezvous process. + /// The rendezvous process. + /// The address to write the stream to. + /// The port to write the stream to. + /// The serializer to use when writing the stream. + /// An optional delivery policy. + public static void WriteToRendezvousProcess( + this IProducer source, + string streamName, + Rendezvous.Process rendezvousProcess, + string address, + int port, + IFormatSerializer serializer, + DeliveryPolicy deliveryPolicy = null) + { + var tcpWriter = new TcpWriter(source.Out.Pipeline, port, serializer); + source.PipeTo(tcpWriter, deliveryPolicy); + rendezvousProcess.AddEndpoint(tcpWriter.ToRendezvousEndpoint(address, streamName)); + } + + /// + /// Writes a stream to a specified rendezvous process via UDP. + /// + /// The type of data in the stream. + /// The source stream to write. + /// The name under which to write the stream to the rendezvous process. + /// The rendezvous process. + /// The address of this sender (used in the endpoint). + /// The destination UDP port. + /// Flag indicating whether the writer should broadcast messages. + /// The serializer to use when writing the stream. + /// An optional delivery policy. + public static void WriteToRendezvousProcess( + this IProducer source, + string streamName, + Rendezvous.Process rendezvousProcess, + string address, + int port, + bool isBroadcasting, + IFormatSerializer serializer, + DeliveryPolicy deliveryPolicy = null) + { + var udpWriter = new UdpWriter(source.Out.Pipeline, port, serializer, isBroadcasting); + source.PipeTo(udpWriter, deliveryPolicy); + rendezvousProcess.AddEndpoint(udpWriter.ToRendezvousEndpoint(address, streamName)); + } + } +} diff --git a/Sources/Runtime/Microsoft.Psi.InteropAndroid/Rendezvous/Readme.md b/Sources/Runtime/Microsoft.Psi.InteropAndroid/Rendezvous/Readme.md new file mode 100644 index 000000000..a2c561304 --- /dev/null +++ b/Sources/Runtime/Microsoft.Psi.InteropAndroid/Rendezvous/Readme.md @@ -0,0 +1,5 @@ +# Interop Rendezvous + +A distributed \psi system may have many separate pipelines running in separate processes, on separate machines, publishing and subscribing to streams being conveyed using various protocols. The rendezvous system allows each pipeline process to advertise its available streams and to discover those of other pipelines. This is accomplished by a centralized "rendezvous point" which maintains and relays endpoint connection and stream information. + +For more information, see [the Rendezvous System wiki page](https://github.com/microsoft/psi/wiki/Rendezvous-System). diff --git a/Sources/Runtime/Microsoft.Psi.InteropAndroid/Rendezvous/Rendezvous.cs b/Sources/Runtime/Microsoft.Psi.InteropAndroid/Rendezvous/Rendezvous.cs new file mode 100644 index 000000000..7aad97fa6 --- /dev/null +++ b/Sources/Runtime/Microsoft.Psi.InteropAndroid/Rendezvous/Rendezvous.cs @@ -0,0 +1,508 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +namespace Microsoft.Psi.Interop.Rendezvous +{ + using System; + using System.Collections.Concurrent; + using System.Collections.Generic; + using System.Linq; + using Microsoft.Psi.Remoting; + + /// + /// Component that maintains rendezvous information. + /// + public class Rendezvous + { + /// + /// A rendezvous may know about many processes, each with many endpoints, each with many streams. + /// + private readonly ConcurrentDictionary processes = new (); + + private EventHandler processAdded; + + /// + /// Event raised when processes are added. + /// + /// Includes processes added before subscription. + public event EventHandler ProcessAdded + { + add + { + // inform late-joining handler of currently added processes + foreach (var p in this.Processes) + { + value.Invoke(this, p); + } + + this.processAdded += value; + } + + remove + { + this.processAdded -= value; + } + } + + /// + /// Event raised when processes are removed. + /// + public event EventHandler ProcessRemoved; + + /// + /// Gets the currently known processes. + /// + public IEnumerable Processes + { + get + { + return this.processes.Values; + } + } + + /// + /// Try to add a new process, if not already present. + /// + /// Process to add. + /// A value indicating whether the process was added. + public bool TryAddProcess(Process process) + { + if (this.processes.TryAdd(process.Name, process)) + { + this.processAdded?.Invoke(this, process); + return true; + } + + return false; + } + + /// + /// Try to remove a process if present. + /// + /// Process to remove. + /// A value indicating whether the process was removed. + public bool TryRemoveProcess(Process process) + { + if (this.processes.TryRemove(process.Name, out _)) + { + this.ProcessRemoved?.Invoke(this, process); + return true; + } + + return false; + } + + /// + /// Try to remove a process if present. + /// + /// Name of process to remove. + /// A value indicating whether the process was removed. + public bool TryRemoveProcess(string processName) + { + if (this.TryGetProcess(processName, out Process process)) + { + return this.TryRemoveProcess(process); + } + + return false; + } + + /// + /// Try to get process by name. + /// + /// Process name. + /// Process or null if not found. + /// A value indicating whether named process found. + public bool TryGetProcess(string processName, out Process process) + { + return this.processes.TryGetValue(processName, out process); + } + + /// + /// Represents a remoted stream of data. + /// + public class Stream + { + /// + /// Initializes a new instance of the class. + /// + /// Stream name. + /// Type name of stream data. + public Stream(string streamName, string typeName) + { + this.StreamName = streamName; + this.TypeName = typeName; + } + + /// + /// Initializes a new instance of the class. + /// + /// Stream name. + /// Type of stream data. + public Stream(string streamName, Type type) + : this(streamName, type.AssemblyQualifiedName) + { + } + + /// + /// Gets the stream name. + /// + public string StreamName { get; private set; } + + /// + /// Gets the type name of the stream data. + /// + public string TypeName { get; private set; } + } + + /// + /// Represents an endpoint providing remoted data streams. + /// + public abstract class Endpoint + { + private readonly ConcurrentDictionary streams; + + /// + /// Initializes a new instance of the class. + /// + /// Endpoint streams. + public Endpoint(IEnumerable streams) + { + this.streams = new ConcurrentDictionary(streams.Select(s => new KeyValuePair(s.StreamName, s))); + } + + /// + /// Initializes a new instance of the class. + /// + public Endpoint() + : this(Enumerable.Empty()) + { + } + + /// + /// Gets the streams. + /// + public IEnumerable Streams + { + get { return this.streams.Values; } + } + + /// + /// Add new stream. + /// + /// Endpoint stream to add. + public virtual void AddStream(Stream stream) + { + this.streams.TryAdd(stream.StreamName, stream); + } + } + + /// + /// Represents a simple TCP source endpoint providing a single remoted data stream. + /// + public class TcpSourceEndpoint : Endpoint + { + /// + /// Initializes a new instance of the class. + /// + /// Host name used by the endpoint. + /// Port number used by the endpoint. + /// Endpoint stream. + public TcpSourceEndpoint(string host, int port, Stream stream = null) + : base(stream is null ? Enumerable.Empty() : new[] { stream }) + { + if (string.IsNullOrEmpty(host)) + { + throw new ArgumentException("Host must be not null or empty."); + } + + this.Host = host; + this.Port = port; + } + + /// + /// Gets the endpoint address. + /// + public string Host { get; private set; } + + /// + /// Gets the endpoint port number. + /// + public int Port { get; private set; } + + /// + /// Gets the stream (Tcp endpoints have only one). + /// + public Stream Stream => this.Streams.FirstOrDefault(); + + /// + public override void AddStream(Stream stream) + { + if (this.Streams.Count() > 0) + { + throw new InvalidOperationException($"Cannot add more than one stream to a single {nameof(TcpSourceEndpoint)}"); + } + + base.AddStream(stream); + } + } + + /// + /// Represents a simple UDP source endpoint providing a single remoted data stream. + /// + public class UdpSourceEndpoint : Endpoint + { + /// + /// Initializes a new instance of the class. + /// + /// Host name of the sender (informational — receivers bind on IPAddress.Any). + /// UDP port on which receivers should listen. + /// Endpoint stream. + public UdpSourceEndpoint(string host, int port, Stream stream = null) + : base(stream is null ? Enumerable.Empty() : new[] { stream }) + { + if (string.IsNullOrEmpty(host)) + { + throw new ArgumentException("Host must be not null or empty."); + } + + this.Host = host; + this.Port = port; + } + + /// + /// Gets the sender host name (informational — receivers bind on IPAddress.Any). + /// + public string Host { get; private set; } + + /// + /// Gets the UDP port on which receivers should listen. + /// + public int Port { get; private set; } + + /// + /// Gets the stream (UDP endpoints have only one). + /// + public Stream Stream => this.Streams.FirstOrDefault(); + + /// + public override void AddStream(Stream stream) + { + if (this.Streams.Count() > 0) + { + throw new InvalidOperationException($"Cannot add more than one stream to a single {nameof(UdpSourceEndpoint)}"); + } + + base.AddStream(stream); + } + } + + /// + /// Represents a NetMQ source endpoint providing remoted data streams. + /// + public class NetMQSourceEndpoint : Endpoint + { + /// + /// Initializes a new instance of the class. + /// + /// Address used by the endpoint. + /// Endpoint streams. + public NetMQSourceEndpoint(string address, IEnumerable streams) + : base(streams) + { + this.Address = address; + } + + /// + /// Initializes a new instance of the class. + /// + /// Address used by the endpoint. + public NetMQSourceEndpoint(string address) + : this(address, Enumerable.Empty()) + { + } + + /// + /// Gets the endpoint address. + /// + public string Address { get; private set; } + } + + /// + /// Represents a remote exporter endpoint providing remoted data streams. + /// + public class RemoteExporterEndpoint : Endpoint + { + /// + /// Initializes a new instance of the class. + /// + /// Host name used by the endpoint. + /// Port used by the endpoint. + /// Tranport kind used by the endpoint. + /// Endpoint streams. + public RemoteExporterEndpoint(string host, int port, TransportKind transport, IEnumerable streams) + : base(streams) + { + this.Host = host; + this.Port = port; + this.Transport = transport; + } + + /// + /// Initializes a new instance of the class. + /// + /// Host name used by the endpoint. + /// Port used by the endpoint. + /// Tranport kind used by the endpoint. + public RemoteExporterEndpoint(string host, int port, TransportKind transport) + : this(host, port, transport, Enumerable.Empty()) + { + } + + /// + /// Gets the endpoint host name. + /// + public string Host { get; private set; } + + /// + /// Gets the endpoint port. + /// + public int Port { get; private set; } + + /// + /// Gets the endpoint transport kind. + /// + public TransportKind Transport { get; private set; } + } + + /// + /// Represents a remote clock exporter endpoint providing clock information. + /// + /// + /// Endpoint does not provide any streams. Clock information is exchanged directly. + /// + public class RemoteClockExporterEndpoint : Endpoint + { + /// + /// Initializes a new instance of the class. + /// + /// Host name used by the endpoint. + /// Port used by the endpoint. + public RemoteClockExporterEndpoint(string host, int port) + { + this.Host = host; + this.Port = port; + } + + /// + /// Gets the endpoint host name. + /// + public string Host { get; private set; } + + /// + /// Gets the endpoint port. + /// + public int Port { get; private set; } + + /// + public override void AddStream(Stream stream) + { + throw new InvalidOperationException($"Cannot add streams to a {nameof(RemoteClockExporterEndpoint)}"); + } + } + + /// + /// Represents a remote clock exporter endpoint providing clock information. + /// + /// + /// Endpoint does not provide any streams. Clock information is exchanged directly. + /// + public class RemotePipelineClockExporterEndpoint : Endpoint + { + /// + /// Initializes a new instance of the class. + /// + /// Host name used by the endpoint. + /// Port used by the endpoint. + public RemotePipelineClockExporterEndpoint(string host, int port) + { + this.Host = host; + this.Port = port; + } + + /// + /// Gets the endpoint host name. + /// + public string Host { get; private set; } + + /// + /// Gets the endpoint port. + /// + public int Port { get; private set; } + + /// + public override void AddStream(Stream stream) + { + throw new InvalidOperationException($"Cannot add streams to a {nameof(RemotePipelineClockExporterEndpoint)}"); + } + } + + /// + /// Represents an application process hosting endpoints. + /// + public class Process + { + private readonly List endpoints; + + /// + /// Initializes a new instance of the class. + /// + /// Unique name by which to refer to the process. + /// Process endpoints. + /// Optional process version (allowing negotiation of client compatibility). + public Process(string name, IEnumerable endpoints, string version = null) + { + this.Name = name; + this.Version = version ?? string.Empty; + this.endpoints = endpoints.ToList(); + } + + /// + /// Initializes a new instance of the class. + /// + /// Unique name by which to refer to the process. + /// Optional process version (allowing negotiation of client compatibility). + public Process(string name, string version = null) + : this(name, Enumerable.Empty(), version) + { + } + + /// + /// Gets the process name. + /// + public string Name { get; private set; } + + /// + /// Gets the process version. + /// + public string Version { get; private set; } + + /// + /// Gets the endpoints. + /// + public IEnumerable Endpoints + { + get { return this.endpoints; } + } + + /// + /// Add new endpoint. + /// + /// Process endpoint to add. + public void AddEndpoint(Endpoint endpoint) + { + this.endpoints.Add(endpoint); + } + } + } +} diff --git a/Sources/Runtime/Microsoft.Psi.InteropAndroid/Rendezvous/RendezvousClient.cs b/Sources/Runtime/Microsoft.Psi.InteropAndroid/Rendezvous/RendezvousClient.cs new file mode 100644 index 000000000..58cb028cb --- /dev/null +++ b/Sources/Runtime/Microsoft.Psi.InteropAndroid/Rendezvous/RendezvousClient.cs @@ -0,0 +1,191 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +namespace Microsoft.Psi.Interop.Rendezvous +{ + using System; + using System.Diagnostics; + using System.IO; + using System.Net.Sockets; + using System.Threading; + + /// + /// Client which connects to a and relays information. + /// + public class RendezvousClient : RendezvousRelay, IDisposable + { + private readonly string serverAddress; + private readonly int port; + private readonly EventWaitHandle connected = new (false, EventResetMode.ManualReset); + + private TcpClient client; + private BinaryReader reader; + private BinaryWriter writer; + private bool active = false; + private string clientAddress = null; + + /// + /// Initializes a new instance of the class. + /// + /// TCP address to which to connect. + /// Optional TCP port to which to connect. + /// Optional rendezvous instance to relay. + public RendezvousClient(string serverAddress, int port = RendezvousServer.DefaultPort, Rendezvous rendezvous = null) + : base(rendezvous) + { + this.serverAddress = serverAddress; + this.port = port; + this.connected.Reset(); + } + + /// + /// Gets wait handle for server connection being established. + /// + /// This should be waited on prior to trusting the processes list. + public EventWaitHandle Connected => this.connected; + + /// + /// Gets a value indicating whether the client is active. + /// + public bool IsActive => this.active; + + /// + /// Gets the client address (available after connection established). + /// + public string ClientAddress => this.clientAddress; + + /// + /// Start rendezvous client (blocking until connection is established). + /// + public void Start() + { + if (this.active) + { + throw new Exception($"{nameof(RendezvousClient)} already started."); + } + + this.Rendezvous.ProcessAdded += this.ProcessAdded; + this.Rendezvous.ProcessRemoved += this.ProcessRemoved; + while (!this.active) + { + try + { + (this.client = new TcpClient()).Connect(this.serverAddress, this.port); + var stream = this.client.GetStream(); + this.reader = new BinaryReader(stream); + this.writer = new BinaryWriter(stream); + this.writer.Write(RendezvousServer.ProtocolVersion); + this.writer.Flush(); + this.active = true; + new Thread(new ThreadStart(this.ReadFromServer)) { IsBackground = true }.Start(); + } + catch (SocketException ex) + { + Trace.WriteLine($"Failed to connect to {nameof(RendezvousServer)} (retrying): {ex.Message}"); + } + } + } + + /// + /// Stop rendezvous client. + /// + public void Stop() + { + TryWriteDisconnect(this.writer); + this.Rendezvous.ProcessAdded -= this.ProcessAdded; + this.Rendezvous.ProcessRemoved -= this.ProcessRemoved; + this.active = false; + this.client?.Close(); + this.client?.Dispose(); + this.client = null; + this.reader?.Dispose(); + this.reader = null; + this.writer?.Dispose(); + this.writer = null; + } + + /// + public void Dispose() + { + this.Stop(); + this.connected.Dispose(); + } + + private void ReadFromServer() + { + try + { + var version = this.reader.ReadInt16(); + if (version != RendezvousServer.ProtocolVersion) + { + var ex = new IOException($"{nameof(RendezvousServer)} protocol mismatch ({version})"); + this.ServerError(ex); + throw ex; + } + + this.clientAddress = this.reader.ReadString(); + + // initialize processes before signaling connected + var count = this.reader.ReadInt32(); + for (var i = 0; i < count; i++) + { + if (!this.ReadProcessUpdate(this.reader)) + { + this.ServerError(new IOException($"{nameof(RendezvousServer)} disconnected.")); + } + } + + this.connected.Set(); + + do + { + if (!this.ReadProcessUpdate(this.reader)) + { + this.ServerError(new IOException($"{nameof(RendezvousServer)} disconnected.")); + } + } + while (this.active && this.client.Connected); + } + catch (Exception ex) + { + this.ServerError(ex); + this.connected.Reset(); + } + } + + private void NotifyServer(Rendezvous.Process process, Action action) + { + try + { + action(process, this.writer); + } + catch (Exception ex) + { + this.ServerError(ex); + } + } + + private void ProcessAdded(object sender, Rendezvous.Process process) + { + if (this.writer != null) + { + this.NotifyServer(process, WriteAddProcess); + } + } + + private void ProcessRemoved(object sender, Rendezvous.Process process) + { + if (this.writer != null) + { + this.NotifyServer(process, WriteRemoveProcess); + } + } + + private void ServerError(Exception ex) + { + Trace.WriteLine($"{nameof(RendezvousServer)} error: {ex.Message}"); + this.Stop(); + this.OnError(ex); + } + } +} diff --git a/Sources/Runtime/Microsoft.Psi.InteropAndroid/Rendezvous/RendezvousRelay.cs b/Sources/Runtime/Microsoft.Psi.InteropAndroid/Rendezvous/RendezvousRelay.cs new file mode 100644 index 000000000..d7fb6bfc7 --- /dev/null +++ b/Sources/Runtime/Microsoft.Psi.InteropAndroid/Rendezvous/RendezvousRelay.cs @@ -0,0 +1,236 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +namespace Microsoft.Psi.Interop.Rendezvous +{ + using System; + using System.IO; + using System.Linq; + using Microsoft.Psi.Remoting; + + /// + /// Base class for and . + /// + public abstract class RendezvousRelay + { + /// + /// Initializes a new instance of the class. + /// + /// Optional rendezvous instance to relay. + public RendezvousRelay(Rendezvous rendezvous = null) + { + this.Rendezvous = rendezvous ?? new Rendezvous(); + } + + /// + /// Event raised when errors occur. + /// + public event EventHandler Error; + + /// + /// Gets the underlying rendezvous. + /// + public Rendezvous Rendezvous { get; private set; } + + /// + /// Write update to add process. + /// + /// Process to add. + /// Writer to which to write update. + protected static void WriteAddProcess(Rendezvous.Process process, BinaryWriter writer) + { + writer.Write((byte)1); // add + writer.Write(process.Name); + writer.Write(process.Version); + writer.Write(process.Endpoints.Count()); + foreach (var endpoint in process.Endpoints) + { + if (endpoint is Rendezvous.TcpSourceEndpoint tcpEndpoint) + { + writer.Write((byte)0); // TcpEndpoint + writer.Write(tcpEndpoint.Host); + writer.Write(tcpEndpoint.Port); + } + else if (endpoint is Rendezvous.NetMQSourceEndpoint netMQEndpoint) + { + writer.Write((byte)1); // NetMQEndpoint + writer.Write(netMQEndpoint.Address); + } + else if (endpoint is Rendezvous.RemoteExporterEndpoint remoteExporterEndpoint) + { + writer.Write((byte)2); // RemoteExporterEndpoint + writer.Write(remoteExporterEndpoint.Host); + writer.Write(remoteExporterEndpoint.Port); + writer.Write((int)remoteExporterEndpoint.Transport); + } + else if (endpoint is Rendezvous.RemoteClockExporterEndpoint remoteClockExporterEndpoint) + { + writer.Write((byte)3); // RemoteClockExporterEndpoint + writer.Write(remoteClockExporterEndpoint.Host); + writer.Write(remoteClockExporterEndpoint.Port); + } + else if (endpoint is Rendezvous.RemotePipelineClockExporterEndpoint remotePipelineClockExporterEndpoint) + { + writer.Write((byte)4); // RemotePipelineClockExporterEndpoint + writer.Write(remotePipelineClockExporterEndpoint.Host); + writer.Write(remotePipelineClockExporterEndpoint.Port); + } + else if (endpoint is Rendezvous.UdpSourceEndpoint udpSourceEndpoint) + { + writer.Write((byte)5); // UdpSourceEndpoint + writer.Write(udpSourceEndpoint.Host); + writer.Write(udpSourceEndpoint.Port); + } + else + { + throw new ArgumentException($"Unknown type of Endpoint ({endpoint.GetType().Name})."); + } + + writer.Write(endpoint.Streams.Count()); + foreach (var stream in endpoint.Streams) + { + writer.Write(stream.StreamName); + writer.Write(stream.TypeName); + } + } + + writer.Flush(); + } + + /// + /// Write update to remove process. + /// + /// Process to remove. + /// Writer to which to write update. + protected static void WriteRemoveProcess(Rendezvous.Process process, BinaryWriter writer) + { + writer.Write((byte)2); // remove + writer.Write(process.Name); + writer.Flush(); + } + + /// + /// Write disconnection signal.. + /// + /// Writer to which to write disconnection signal. + protected static void TryWriteDisconnect(BinaryWriter writer) + { + try + { + writer?.Write((byte)0); // disconnect + writer?.Flush(); + } + catch + { + } + } + + /// + /// Raise error event. + /// + /// Underlying exception. + protected void OnError(Exception ex) + { + this.Error?.Invoke(this, ex); + } + + /// + /// Read process update record. + /// + /// Reader from which to read. + /// A value indicating whether an update was read, otherwise false indicated disconnection. + protected bool ReadProcessUpdate(BinaryReader reader) + { + try + { + switch (reader.ReadByte()) + { + case 0: // disconnect + return false; + case 1: // add process + var process = ReadProcess(reader); + this.Rendezvous.TryAddProcess(process); + return true; + case 2: // remove process + var name = reader.ReadString(); + this.Rendezvous.TryRemoveProcess(name); + return true; + default: + throw new Exception("Unexpected rendezvous action."); + } + } + catch (Exception ex) + { + this.OnError(ex); + return false; + } + } + + /// + /// Read process. + /// + /// Reader from which to deserialize. + /// Process. + private static Rendezvous.Process ReadProcess(BinaryReader reader) + { + var processName = reader.ReadString(); + var processVersion = reader.ReadString(); + var process = new Rendezvous.Process(processName, processVersion); + + // read endpoint info + var endpointCount = reader.ReadInt32(); + for (var i = 0; i < endpointCount; i++) + { + Rendezvous.Endpoint endpoint; + switch (reader.ReadByte()) + { + case 0: // TcpEndpoint + var address = reader.ReadString(); + var port = reader.ReadInt32(); + endpoint = new Rendezvous.TcpSourceEndpoint(address, port); + break; + case 1: // NetMQEndpoint + endpoint = new Rendezvous.NetMQSourceEndpoint(reader.ReadString()); + break; + case 2: // RemoteExporterEndpoint + var host = reader.ReadString(); + port = reader.ReadInt32(); + var transport = (TransportKind)reader.ReadInt32(); + endpoint = new Rendezvous.RemoteExporterEndpoint(host, port, transport); + break; + case 3: // RemoteClockExporerEndpoint + host = reader.ReadString(); + port = reader.ReadInt32(); + endpoint = new Rendezvous.RemoteClockExporterEndpoint(host, port); + break; + case 4: // RemotePipelineClockExporerEndpoint + host = reader.ReadString(); + port = reader.ReadInt32(); + endpoint = new Rendezvous.RemotePipelineClockExporterEndpoint(host, port); + break; + case 5: // UdpEndpoint + host = reader.ReadString(); + port = reader.ReadInt32(); + endpoint = new Rendezvous.UdpSourceEndpoint(host, port); + break; + + default: + throw new Exception("Unknown type of Endpoint."); + } + + // read stream info + var streamCount = reader.ReadInt32(); + for (var j = 0; j < streamCount; j++) + { + var name = reader.ReadString(); + var typeName = reader.ReadString(); + endpoint.AddStream(new Rendezvous.Stream(name, typeName)); + } + + process.AddEndpoint(endpoint); + } + + return process; + } + } +} diff --git a/Sources/Runtime/Microsoft.Psi.InteropAndroid/Rendezvous/RendezvousServer.cs b/Sources/Runtime/Microsoft.Psi.InteropAndroid/Rendezvous/RendezvousServer.cs new file mode 100644 index 000000000..38112f496 --- /dev/null +++ b/Sources/Runtime/Microsoft.Psi.InteropAndroid/Rendezvous/RendezvousServer.cs @@ -0,0 +1,208 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +namespace Microsoft.Psi.Interop.Rendezvous +{ + using System; + using System.Collections.Concurrent; + using System.Diagnostics; + using System.IO; + using System.Linq; + using System.Net; + using System.Net.Sockets; + using System.Threading; + + /// + /// Server which accepts one or more connections and relays information. + /// + public class RendezvousServer : RendezvousRelay, IDisposable + { + /// + /// Default TCP port on which to listen for clients. + /// + public const int DefaultPort = 13331; + + /// + /// Protocol version. + /// + internal const short ProtocolVersion = 2; + + private readonly int port; + private readonly ConcurrentDictionary writers = new (); + + private TcpListener listener; + private bool active = false; + private string serverAddress; + + /// + /// Initializes a new instance of the class. + /// + /// Optional TCP port on which to listen for clients. + /// Optional rendezvous instance to relay. + public RendezvousServer(int port = DefaultPort, Rendezvous rendezvous = null) + : base(rendezvous) + { + this.port = port; + } + + /// + /// Gets a value indicating whether the server is active. + /// + public bool IsActive => this.active; + + /// + /// Gets the server address (on which the most recent client connection was received). + /// + public string ServerAddress => this.serverAddress; + + /// + /// Start rendezvous client (blocking until connection is established). + /// + public void Start() + { + if (this.active) + { + throw new Exception($"{nameof(RendezvousServer)} already started."); + } + + this.Rendezvous.ProcessAdded += (_, process) => this.NotifyClients(process, WriteAddProcess); + this.Rendezvous.ProcessRemoved += (_, process) => this.NotifyClients(process, WriteRemoveProcess); + this.listener = new TcpListener(IPAddress.Any, this.port); + this.active = true; + new Thread(new ThreadStart(this.ListenForClients)) { IsBackground = true }.Start(); + } + + /// + /// Stop rendezvous client. + /// + public void Stop() + { + this.active = false; + + foreach (var writer in this.writers.Values) + { + TryWriteDisconnect(writer); + writer.Dispose(); + } + + this.listener?.Stop(); + this.listener = null; + } + + /// + public void Dispose() + { + this.Stop(); + } + + private void ListenForClients() + { + this.listener.Start(); + do + { + try + { + var client = this.listener.AcceptTcpClient(); + var remoteAddress = client.Client.RemoteEndPoint.ToString().Split(':')[0]; + var localAddress = client.Client.LocalEndPoint.ToString().Split(':')[0]; + var stream = client.GetStream(); + var reader = new BinaryReader(stream); + var version = reader.ReadInt16(); + if (version != ProtocolVersion) + { + var ex = new IOException($"{nameof(RendezvousClient)} protocol mismatch ({version})"); + this.ClientError(ex); + continue; + } + + var writer = new BinaryWriter(stream); + var guid = Guid.NewGuid(); + this.writers.TryAdd(guid, writer); + + writer.Write(ProtocolVersion); + writer.Write(remoteAddress); + writer.Write(this.Rendezvous.Processes.Count()); + writer.Flush(); + + // notify client of curent process info + foreach (var process in this.Rendezvous.Processes) + { + WriteAddProcess(process, writer); + } + + // set the server address to the address of the local endpoint from which the client was received + this.serverAddress = localAddress; + + new Thread(new ParameterizedThreadStart(this.ReadFromClient)) { IsBackground = true } + .Start(Tuple.Create(reader, guid)); + } + catch (Exception ex) + { + this.ClientError(ex); + } + } + while (this.active && this.listener != null); + } + + private void ReadFromClient(object param) + { + var tuple = param as Tuple; + var reader = tuple.Item1; + var guid = tuple.Item2; + try + { + do + { + if (!this.ReadProcessUpdate(reader)) + { + Trace.WriteLine($"{nameof(RendezvousClient)} disconnected."); + break; + } + } + while (this.active && this.listener != null); + } + catch (Exception ex) + { + this.ClientError(ex); + } + + reader.Dispose(); + if (this.writers.TryRemove(guid, out var writer)) + { + writer.Dispose(); + } + } + + private void NotifyClients(Rendezvous.Process process, Action action) + { + foreach (var kv in this.writers) + { + var writer = kv.Value; + try + { + if (writer.BaseStream.CanWrite) + { + action(process, writer); + } + } + catch (Exception ex) + { + this.ClientError(ex); + if (this.writers.TryRemove(kv.Key, out _)) + { + writer.Dispose(); + } + } + } + } + + private void ClientError(Exception ex) + { + Trace.WriteLine($"{nameof(RendezvousClient)} failed to connect: {ex.Message}"); + if (this.active) + { + this.OnError(ex); // note: only invoked on first error + } + } + } +} diff --git a/Sources/Runtime/Microsoft.Psi.InteropAndroid/Serialization/Format{T}.cs b/Sources/Runtime/Microsoft.Psi.InteropAndroid/Serialization/Format{T}.cs new file mode 100644 index 000000000..ae6b27e4d --- /dev/null +++ b/Sources/Runtime/Microsoft.Psi.InteropAndroid/Serialization/Format{T}.cs @@ -0,0 +1,88 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +namespace Microsoft.Psi.Interop.Serialization +{ + using System; + using System.IO; + using System.Text; + + /// + /// Helper class for making new formats (implementations of /. + /// + /// Type which is serialized/deserialized. + public class Format : IFormatSerializer, IFormatDeserializer, IDisposable + { + private readonly Func serialize; + private readonly Func deserialize; + private readonly MemoryStream memoryStream = null; + + /// + /// Initializes a new instance of the class. + /// + /// Serialization function. + /// Deserialization function. + public Format( + Func serializeFunc, + Func deserializeFunc) + { + this.serialize = serializeFunc; + this.deserialize = deserializeFunc; + } + + /// + /// Initializes a new instance of the class. + /// + /// Action to serialize using . + /// Function to deserialize using (also given raw payload, offset, length). + /// Serialization format. + public Format( + Action serializeAction, + Func deserializeFunc) + { + this.memoryStream = new MemoryStream(); + + this.serialize = (val, originatingTime) => + { + this.memoryStream.Position = 0; + using var writer = new BinaryWriter(this.memoryStream, Encoding.UTF8, true); + writer.Write(originatingTime.ToBinary()); + serializeAction(val, writer); + return (this.memoryStream.GetBuffer(), 0, (int)this.memoryStream.Position); + }; + + this.deserialize = (payload, offset, length) => + { + using var reader = new BinaryReader(new MemoryStream(payload, offset, length), Encoding.UTF8); + var originatingTime = DateTime.FromBinary(reader.ReadInt64()); + var val = deserializeFunc(reader, payload, offset, length); + return (val, originatingTime); + }; + } + + /// + /// Initializes a new instance of the class. + /// + /// Action to serialize using . + /// Function to deserialize using (also given raw payload, offset, length). + /// Serialization format. + public Format( + Action serializeAction, + Func deserializeFunc) + : this(serializeAction, (reader, _, _, _) => deserializeFunc(reader)) + { + } + + /// + public (byte[] Bytes, int Index, int Count) SerializeMessage(T message, DateTime originatingTime) + => this.serialize(message, originatingTime); + + /// + public (T Message, DateTime OriginatingTime) DeserializeMessage(byte[] payload, int index, int count) + => this.deserialize(payload, index, count); + + /// + public void Dispose() + => this.memoryStream?.Dispose(); + } +} diff --git a/Sources/Runtime/Microsoft.Psi.InteropAndroid/Serialization/IFormatDeserializer.cs b/Sources/Runtime/Microsoft.Psi.InteropAndroid/Serialization/IFormatDeserializer.cs new file mode 100644 index 000000000..2fc9cb0a9 --- /dev/null +++ b/Sources/Runtime/Microsoft.Psi.InteropAndroid/Serialization/IFormatDeserializer.cs @@ -0,0 +1,23 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +namespace Microsoft.Psi.Interop.Serialization +{ + using System; + + /// + /// Format deserializer interface. + /// + /// Type which is deserialized. + public interface IFormatDeserializer + { + /// + /// Deserialize single message and originating time stamp payload. + /// + /// Payload bytes. + /// Starting index of message data. + /// Number of bytes constituting message data. + /// Type of primitive or IEnumerable/ExpandoObject of primitive as well as originating time stamp. + (T Message, DateTime OriginatingTime) DeserializeMessage(byte[] payload, int index, int count); + } +} \ No newline at end of file diff --git a/Sources/Runtime/Microsoft.Psi.InteropAndroid/Serialization/IFormatSerializer.cs b/Sources/Runtime/Microsoft.Psi.InteropAndroid/Serialization/IFormatSerializer.cs new file mode 100644 index 000000000..0634d8db3 --- /dev/null +++ b/Sources/Runtime/Microsoft.Psi.InteropAndroid/Serialization/IFormatSerializer.cs @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +namespace Microsoft.Psi.Interop.Serialization +{ + using System; + + /// + /// Format serializer interface. + /// + /// Type which is deserialized. + public interface IFormatSerializer + { + /// + /// Serialize single message with originating time stamp. + /// + /// Message of type. + /// Originating time of message. + /// Serialized bytes, index and count. + (byte[] Bytes, int Index, int Count) SerializeMessage(T message, DateTime originatingTime); + } +} diff --git a/Sources/Runtime/Microsoft.Psi.InteropAndroid/Serialization/Readme.md b/Sources/Runtime/Microsoft.Psi.InteropAndroid/Serialization/Readme.md new file mode 100644 index 000000000..49c5be8d4 --- /dev/null +++ b/Sources/Runtime/Microsoft.Psi.InteropAndroid/Serialization/Readme.md @@ -0,0 +1,45 @@ +# Interop Serialization Interfaces + +Each [concrete format](../Format/Readme.md) is an implementation of several serialization interfaces. These interfaces are similar to `Microsoft.Psi.Serialization.ISerializer` but are specific to dynamic types and don't include cloning. An `IFormatSerializer` converts a message of any type, along with its originating time, to a simple `byte[]`, while an `IFormatDeserializer` reverses the process; taking a `byte[]` and returning a message and originating time. + +```csharp +public interface IFormatSerializer +{ + (byte[], int, int) SerializeMessage(dynamic message, DateTime originatingTime); +} + +public interface IFormatDeserializer +{ + (dynamic, DateTime) DeserializeMessage(byte[] payload, int index, int count); +} +``` + +Versions of these intended for persistent storage, where a sequence of messages are persisted together, are provided as well. + +```csharp +public interface IPersistentFormatSerializer +{ + dynamic PersistHeader(dynamic message, Stream stream); + + void PersistRecord(dynamic message, DateTime originatingTime, bool first, Stream stream, dynamic state); + + void PersistFooter(Stream stream, dynamic state); +} + +public interface IPersistentFormatDeserializer +{ + IEnumerable<(dynamic, DateTime)> DeserializeRecords(Stream stream); +} +``` + +`IPersistentFormatSerializer` writes a set of messages to a `Stream`. The header may be field names in the case of CSV, a simple array container in the case of JSON, etc. Similarly, the footer may close such constructs. The `PersistRecord` method is very similar to `SerializeMessage` above, but may include message framing or delimiting, such as `Environment.NewLine` delimiting records in CSV or a comma for JSON, or maybe a length-prefix for binary MessagePack. The `IPersistentFormatDeserializer` reverses the process; producing messages and timestamps from a previously serialized stream. + +Notice that messages lose their types at this point; generally becoming `dynamic` over `ExpandoObject` and primitives. This means that it may no longer be possible to reify as the original .NET types after serialization in this way (unlike with Psi Stores). + +Note also that, while `dynamic` may be any type, it is recommended that deserialization returns primitives or composites in the form of `ExpandoObject`. For example, the JSON implementation uses `Newtonsoft.Json.JsonConvert` under the covers but, rather than returning `JObject`, is careful to not expose dependencies on this library. + +## Note About `dynamic` and `ExpandoObject` + +A `dynamic` type may be *anything* in .NET and an `ExpandoObject` may have properties of *any* type. We are using these types to represent untyped values flowing through the system in various places above. + +Composite/structured values should be restricted to collections (arrays or `IEnumerable<_>`) of primitives or other composites or `ExpandoObject` of named properties of primitives or other composites. Any "shape" of data is representable this way. \ No newline at end of file diff --git a/Sources/Runtime/Microsoft.Psi.InteropAndroid/Transport/Readme.md b/Sources/Runtime/Microsoft.Psi.InteropAndroid/Transport/Readme.md new file mode 100644 index 000000000..ae0a50b4f --- /dev/null +++ b/Sources/Runtime/Microsoft.Psi.InteropAndroid/Transport/Readme.md @@ -0,0 +1,167 @@ +# Interop Transports + +Here we describe several ways of getting data in and out of Psi in order to interop with other languages and platforms. + +## Generic File Source/Writer Component + +The simplest transport is via the file system. This is most appropriate for offline/batch processing. A generic `FileWriter` component is provided that, when given an `IPersistentFormatSerializer`, will persist a message stream to disk. Similarly, a generic `FileSource` component is provided, taking an `IPersistentFormatDeserializer`, to reconstitute such a persisted file as a Psi stream. + +For example, a stream of messages of any type may be written using the `FileWriter`: + +```csharp +using (var p = Pipeline.Create()) +{ + var gen = Generators.Range(p, 0, 1000); + var sin = gen.Select(x => Math.Sin(x / 100.0)); + var writer = new FileWriter(p, "TestFile.json", JsonFormat.Instance); + sin.PipeTo(writer); + p.Run(); +} +``` + +This produces a JSON file containing something like: + +```json +[ + { + "originatingTime": "2018-11-12T22:48:58.3770983Z", + "message": 0.0 + }, + { + "originatingTime": "2018-11-12T22:48:58.3770984Z", + "message": 0.0099998333341666645 + }, + { + "originatingTime": "2018-11-12T22:48:58.3770985Z", + "message": 0.01999866669333308 + }, + ... +] +``` + +This may then be read back into a proper \\psi stream using a `FileSource`: + +```csharp +using (var p = Pipeline.Create()) +{ + var reader = new FileSource(p, "TestFile.json", JsonFormat.Instance); + reader.Do(Console.WriteLine); + p.Run(); +} +``` + +## Message Queue Components + +Message queues are most appropriate for live interop. Currently, only ZeroMQ is supported. In the future, Azure Storage Queue and/or Service Bus as well as Amazon SMQ may be supported. While the Psi `RemoteExporter`/`Importer` is an excellent, high performance means of remoting, it assumes .NET on both ends. To facilitate remoting to Python and others, we provide message queuing components. These components are `IConsumer` and simply push to a message queue or are `IProducer` and take messages from a queue. Given an `IFormatSerializer`/`Deserializer`, they handle packing/unpacking messages. + +### ZeroMQ/NetMQ + +An implementation for ZeroMQ (calleg NetMQ for .NET) is provided. These components are configured with a URI, a topic name and an `IFormatSerializer`. + +#### `NetMQWriter` + +A stream of messages of any type may be piped to a `NetMQWriter`. These will be serialized and sent to the queue for consumption outside of Psi. + +```csharp +using (var p = Pipeline.Create()) +{ + var gen = Generators.Range(p, 0, 1000); + var sin = gen.Select(x => Math.Sin(x / 100.0)); + var mq = new NetMQWriter(p, "sin-topic", "tcp://localhost:12345", JsonFormat.Instance); + sin.PipeTo(mq); + p.Run(); +} +``` + +This component uses the [NetMQ Pub/Sub](https://netmq.readthedocs.io/en/latest/pub-sub/) pattern, in which messages convey _topic_ information (much like ROS). Subscribers may then subscribe by topic name. + +The generic `NetMQWriter` component has a single `In` receiver which sends to the topic specified at construction. This is the most common case. To facilitate multiple topics over one channel, the `AddTopic(...)` method may be called; returning an additional `IReceiver` to which to pipe. + +```csharp + var cos = gen.Select(x => Math.Cos(x / 100.0)); + var topic = mq.AddTopic("cos-topic"); + cos.PipeTo(topic); +``` + +Alternatively, the non-generic `NetMQWriter` may be used, which has _no_ receivers. Each must be created with `AddTopic(...)`. + +```csharp +using (var p = Pipeline.Create()) +{ + var gen = Generators.Range(p, 0, 1000); + var sin = gen.Select(x => Math.Sin(x / 100.0)); + var cos = gen.Select(x => Math.Cos(x / 100.0)); + + var mq = new NetMQWriter(p, "sin-topic", "tcp://localhost:12345", JsonFormat.Instance); + sin.PipeTo(mq.AddTopic("sin-topic"); + cos.PipeTo(mq.AddTopic("cos-topic"); + + p.Run(); +} +``` + +Then from Python, for example, messages may be consumed using `pyzmq` with something like: + +```python +import zmq, json + +socket = zmq.Context().socket(zmq.SUB) +socket.connect("tcp://localhost:12345") +socket.setsockopt(zmq.SUBSCRIBE, '') # '' means all topics, otherwise 'sin-topic'/'cos-topic' + +while True: + [topic, message] = socket.recv_multipart() + j = json.loads(message) + print "Message: ", repr(j['message']) + print "Originating Time: ", repr(j['originatingTime']) +``` + +#### `NetMQSource` + +Psi may also consume message that have been produced from "outside." For example, the below Python code produces an infinite stream of random doubles: + +```python +import zmq, random, datetime, json + +context = zmq.Context() +socket = context.socket(zmq.PUB) +socket.bind('tcp://127.0.0.1:45678') + +while True: + payload = {} + payload['message'] = random.uniform(0, 1) + payload['originatingTime'] = datetime.datetime.utcnow().isoformat() + socket.send_multipart(['test-topic'.encode(), json.dumps(payload).encode('utf-8')]) +``` + +Notice that the [Pub/Sub](https://netmq.readthedocs.io/en/latest/pub-sub/) pattern is expected here as well; using `socket.send_multipart` with a topic name and the JSON-encoded data. Also notice that the schema must match that expected by the `JsonFormat` `IFormatDeserializer` described above: + +```json +{ "message": , "originatingTime":