diff options
| author | Roy Ben Shabat <Roy.mail.net@gmail.com> | 2020-02-27 23:49:32 +0200 |
|---|---|---|
| committer | Roy Ben Shabat <Roy.mail.net@gmail.com> | 2020-02-27 23:49:32 +0200 |
| commit | 5f45be5bae69be7b7e916f02fb6d69b2db60e529 (patch) | |
| tree | 9aff84020b5eca21df7bf0a7b5439e073969cec1 /Software/Visual_Studio | |
| parent | 03970962af1bfbfc5c13109c3f0a465cf9a1dc29 (diff) | |
| download | Tango-5f45be5bae69be7b7e916f02fb6d69b2db60e529.tar.gz Tango-5f45be5bae69be7b7e916f02fb6d69b2db60e529.zip | |
Implemented Generic messages support!
Implemented custom external bridge request handlers.
Diffstat (limited to 'Software/Visual_Studio')
19 files changed, 757 insertions, 86 deletions
diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/App.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/App.xaml index 4ad5d146a..cfb949890 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/App.xaml +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/App.xaml @@ -4,6 +4,35 @@ <Application.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> + + + <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml"> + </ResourceDictionary> + <ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Primary/materialdesigncolor.lightblue.xaml"> + </ResourceDictionary> + <ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Accent/materialdesigncolor.yellow.xaml"> + </ResourceDictionary> + <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Button.xaml"> + </ResourceDictionary> + <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.CheckBox.xaml"> + </ResourceDictionary> + <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.ListBox.xaml"> + </ResourceDictionary> + <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.PopupBox.xaml"> + </ResourceDictionary> + <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.RadioButton.xaml"> + </ResourceDictionary> + <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.ToggleButton.xaml"> + </ResourceDictionary> + <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/materialdesigntheme.TextBlock.xaml"> + </ResourceDictionary> + <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/materialdesigntheme.Label.xaml"> + </ResourceDictionary> + <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/materialdesigntheme.Slider.xaml"> + </ResourceDictionary> + <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/materialdesigntheme.ProgressBar.xaml"/> + <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.ComboBox.xaml" /> + <ResourceDictionary Source="pack://application:,,,/Tango.FSE.Common;component/Resources/Converters.xaml" /> <ResourceDictionary Source="pack://application:,,,/Tango.FSE.Common;component/Resources/Colors.xaml" /> <ResourceDictionary Source="pack://application:,,,/Tango.FSE.Common;component/Resources/Fonts.xaml" /> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Tango.FSE.PPCConsole.csproj b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Tango.FSE.PPCConsole.csproj index 6bd5c2a77..9fc74f443 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Tango.FSE.PPCConsole.csproj +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Tango.FSE.PPCConsole.csproj @@ -119,6 +119,10 @@ <Project>{f441feee-322a-4943-b566-110e12fd3b72}</Project> <Name>Tango.BL</Name> </ProjectReference> + <ProjectReference Include="..\..\..\Tango.Console\Tango.Console.csproj"> + <Project>{199e8359-cad3-433d-9eed-2027652b24a4}</Project> + <Name>Tango.Console</Name> + </ProjectReference> <ProjectReference Include="..\..\..\Tango.Core\Tango.Core.csproj"> <Project>{a34ee0f0-649d-41c8-8489-b6f1cc6924ee}</Project> <Name>Tango.Core</Name> @@ -161,6 +165,10 @@ <Generator>MSBuild:Compile</Generator> <SubType>Designer</SubType> </Page> + <Page Include="Themes\Generic.xaml"> + <SubType>Designer</SubType> + <Generator>MSBuild:Compile</Generator> + </Page> <Page Include="Views\MainView.xaml"> <SubType>Designer</SubType> <Generator>MSBuild:Compile</Generator> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Themes/Generic.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Themes/Generic.xaml new file mode 100644 index 000000000..15f6b9b0b --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Themes/Generic.xaml @@ -0,0 +1,10 @@ +<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:local="clr-namespace:Tango.FSE.PPCConsole.Themes"> + + + <!--<ResourceDictionary.MergedDictionaries> + <ResourceDictionary Source="pack://application:,,,/Tango.Console;component/Resources/Converters.xaml" /> + </ResourceDictionary.MergedDictionaries>--> + +</ResourceDictionary>
\ No newline at end of file diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/ViewModels/MainViewVM.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/ViewModels/MainViewVM.cs index 8e1b4f920..97c55aba2 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/ViewModels/MainViewVM.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/ViewModels/MainViewVM.cs @@ -4,6 +4,7 @@ using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; +using Tango.Console; using Tango.FSE.Common; using Tango.FSE.Common.Navigation; using Tango.SharedUI.Helpers; @@ -12,6 +13,33 @@ namespace Tango.FSE.PPCConsole.ViewModels { public class MainViewVM : FSEViewModel { + public ConsoleControlVM ConsoleVM { get; set; } + + public MainViewVM() + { + ConsoleVM = new ConsoleControlVM(); + ConsoleVM.CommandExecuting += ConsoleVM_CommandExecuting; + ConsoleVM.Clear(); + } + + private async void ConsoleVM_CommandExecuting(object sender, ConsoleCommandExecutingEventArgs e) + { + await Task.Delay(1000); + try + { + var result = await MachineProvider.MachineOperator.SendGenericRequest<ConsoleCommandDTO, ConsoleCommandExecutionResult>(new ConsoleCommandDTO() + { + Command = e.Command.CommandText, + WorkingFolder = e.Command.WorkingFolder, + }); + e.Complete(result.Output, result.WorkingFolder); + } + catch (Exception ex) + { + e.Complete(ex.FlattenMessage(), e.Command.WorkingFolder); + } + } + public override void OnApplicationStarted() { InvokeUI(() => diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Views/MainView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Views/MainView.xaml index 174e2bde4..edc45ba93 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Views/MainView.xaml +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Views/MainView.xaml @@ -6,9 +6,20 @@ xmlns:global="clr-namespace:Tango.FSE.PPCConsole" xmlns:vm="clr-namespace:Tango.FSE.PPCConsole.ViewModels" xmlns:local="clr-namespace:Tango.FSE.PPCConsole.Views" + xmlns:console="clr-namespace:Tango.Console;assembly=Tango.Console" + xmlns:material="http://materialdesigninxaml.net/winfx/xaml/themes" mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800" d:DataContext="{d:DesignInstance Type=vm:MainViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.MainViewVM}"> <Grid> - <TextBlock FontSize="60" HorizontalAlignment="Center" VerticalAlignment="Center">PPC Console</TextBlock> + <DockPanel> + <TextBlock DockPanel.Dock="Top" Margin="10" HorizontalAlignment="Center" FontSize="30">PPC Console</TextBlock> + <console:ConsoleControl BorderBrush="{StaticResource FSE_BorderBrush}" Margin="10" DataContext="{Binding ConsoleVM}"> + <console:ConsoleControl.BusyTemplate> + <DataTemplate> + <ProgressBar Style="{StaticResource MaterialDesignCircularProgressBar}" IsIndeterminate="True" Width="16" Height="16" /> + </DataTemplate> + </console:ConsoleControl.BusyTemplate> + </console:ConsoleControl> + </DockPanel> </Grid> </UserControl> diff --git a/Software/Visual_Studio/Tango.Console/ConsoleControl.xaml b/Software/Visual_Studio/Tango.Console/ConsoleControl.xaml index fba10403a..6b0aaf8b6 100644 --- a/Software/Visual_Studio/Tango.Console/ConsoleControl.xaml +++ b/Software/Visual_Studio/Tango.Console/ConsoleControl.xaml @@ -35,11 +35,11 @@ <DataTemplate> <StackPanel Margin="0 0 0 10"> <StackPanel Orientation="Horizontal"> - <TextBlock> + <TextBlock VerticalAlignment="Center"> <Run Text="{Binding WorkingFolder}"></Run><Run Text=">"></Run> </TextBlock> - <StackPanel Margin="5 0 0 0" Orientation="Horizontal"> - <TextBox IsReadOnly="True" Cursor="Arrow" AcceptsReturn="True" Background="Transparent" BorderThickness="0" Foreground="{Binding ElementName=control,Path=Foreground}" CaretBrush="{Binding ElementName=control,Path=CaretBrush}" SelectionBrush="{Binding ElementName=control,Path=SelectionBrush}" Text="{Binding CommandText}"></TextBox> + <StackPanel VerticalAlignment="Center" Margin="5 0 0 0" Orientation="Horizontal"> + <TextBox VerticalAlignment="Center" IsReadOnly="True" Cursor="Arrow" AcceptsReturn="True" Background="Transparent" BorderThickness="0" Foreground="{Binding ElementName=control,Path=Foreground}" CaretBrush="{Binding ElementName=control,Path=CaretBrush}" SelectionBrush="{Binding ElementName=control,Path=SelectionBrush}" Text="{Binding CommandText}"></TextBox> </StackPanel> </StackPanel> diff --git a/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeReceiver.cs b/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeReceiver.cs index 679e665f0..400f58c77 100644 --- a/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeReceiver.cs +++ b/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeReceiver.cs @@ -59,6 +59,7 @@ namespace Tango.Integration.ExternalBridge public event EventHandler<ExternalBridgeReceiverLoginRequestEventArgs> LoginRequest; public event EventHandler<ColorProfileRequestEventArgs> ColorProfileRequest; public event EventHandler Disconnected; + public event EventHandler<ExternalBridgeReceiverRequestReceivedEventArgs> ReceiverRequestReceived; #endregion @@ -178,7 +179,14 @@ namespace Tango.Integration.ExternalBridge { if (IsLoggedIn) { - OnAnyRequest(container); + ExternalBridgeReceiverRequestReceivedEventArgs args = new ExternalBridgeReceiverRequestReceivedEventArgs(); + args.Container = container; + ReceiverRequestReceived?.Invoke(this, args); + + if (!args.Handled) + { + OnAnyRequest(container); + } } } } diff --git a/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeReceiverRequestReceivedEventArgs.cs b/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeReceiverRequestReceivedEventArgs.cs new file mode 100644 index 000000000..682de264c --- /dev/null +++ b/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeReceiverRequestReceivedEventArgs.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.PMR.Common; + +namespace Tango.Integration.ExternalBridge +{ + public class ExternalBridgeReceiverRequestReceivedEventArgs + { + public MessageContainer Container { get; set; } + public bool Handled { get; set; } + } +} diff --git a/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeRequestHandlerMethodAttribute.cs b/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeRequestHandlerMethodAttribute.cs new file mode 100644 index 000000000..c326c7dd7 --- /dev/null +++ b/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeRequestHandlerMethodAttribute.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.PMR.Common; + +namespace Tango.Integration.ExternalBridge +{ + [AttributeUsage(AttributeTargets.Method)] + public class ExternalBridgeRequestHandlerMethodAttribute : Attribute + { + public Type Type { get; set; } + + public ExternalBridgeRequestHandlerMethodAttribute(Type type) + { + Type = type; + } + } +} diff --git a/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeService.cs b/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeService.cs index 4395b5f41..ef98db11b 100644 --- a/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeService.cs +++ b/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeService.cs @@ -27,6 +27,8 @@ using Microsoft.AspNet.SignalR.Client; using Tango.Integration.ExternalBridge.Web; using Tango.Core.Threading; using System.Diagnostics; +using System.Reflection; +using Newtonsoft.Json; namespace Tango.Integration.ExternalBridge { @@ -41,6 +43,17 @@ namespace Tango.Integration.ExternalBridge private IHubProxy _proxy; private bool _isSignalRConnected; private System.Timers.Timer _signalrPingTimer; + private Dictionary<String, RequestHandler> _requestHandlers; + private static JsonSerializerSettings _genericMessageSettings = new JsonSerializerSettings() + { + TypeNameHandling = TypeNameHandling.All + }; + + private class RequestHandler + { + public IExternalBridgeRequestHandler Handler { get; set; } + public MethodInfo Method { get; set; } + } #region Events @@ -152,6 +165,8 @@ namespace Tango.Integration.ExternalBridge /// </summary> public ExternalBridgeService() { + _requestHandlers = new Dictionary<string, RequestHandler>(); + SignalRConfiguration = new ExternalBridgeSignalRConfiguration(); TcpTransportAdapterWriteMode = TcpTransportAdapterWriteMode.Interval; @@ -239,6 +254,7 @@ namespace Tango.Integration.ExternalBridge receiver.LoginRequest += Receiver_LoginRequest; receiver.ColorProfileRequest += Receiver_ColorProfileRequest; receiver.Disconnected += Receiver_Disconnected; + receiver.ReceiverRequestReceived += Receiver_ReceiverRequestReceived; _receivers.Add(receiver); await receiver.Connect(); } @@ -255,6 +271,7 @@ namespace Tango.Integration.ExternalBridge receiver.LoginRequest += Receiver_LoginRequest; receiver.ColorProfileRequest += Receiver_ColorProfileRequest; receiver.Disconnected += Receiver_Disconnected; + receiver.ReceiverRequestReceived += Receiver_ReceiverRequestReceived; _receivers.Add(receiver); await receiver.Connect(); } @@ -309,6 +326,7 @@ namespace Tango.Integration.ExternalBridge receiver.LoginRequest -= Receiver_LoginRequest; receiver.ColorProfileRequest -= Receiver_ColorProfileRequest; receiver.Disconnected -= Receiver_Disconnected; + receiver.ReceiverRequestReceived -= Receiver_ReceiverRequestReceived; _receivers.Remove(receiver); @@ -369,6 +387,62 @@ namespace Tango.Integration.ExternalBridge } } + private void Receiver_ReceiverRequestReceived(object sender, ExternalBridgeReceiverRequestReceivedEventArgs e) + { + if (e.Container.Type == MessageType.GenericRequest || _requestHandlers.ContainsKey(e.Container.Type.ToString())) + { + e.Handled = true; + + ThreadFactory.StartNew(() => + { + try + { + var message = MessageFactory.ExtractMessageFromContainer(e.Container); + + if (e.Container.Type != MessageType.GenericRequest) //Handle standard PMR messages. + { + var handler = _requestHandlers[e.Container.Type.ToString()]; + handler.Method.Invoke(handler.Handler, new object[] + { + message, + e.Container.Token, + sender, + }); + } + else //Handle GenericRequest with inner JSON formated generic message. + { + var genericType = (message as GenericRequest).Type; + + try + { + if (_requestHandlers.ContainsKey(genericType)) + { + var json = (message as GenericRequest).Data.ToStringUtf8(); + var innerMessage = JsonConvert.DeserializeObject(json, _genericMessageSettings); + + var handler = _requestHandlers[genericType]; + handler.Method.Invoke(handler.Handler, new object[] + { + innerMessage, + e.Container.Token, + sender, + }); + } + } + catch (Exception ex) + { + LogManager.Log(ex, $"Error invoking external bridge handler for request '{genericType}'."); + } + } + } + catch (Exception ex) + { + LogManager.Log(ex, $"An error occurred while trying or invoking an external bridge request handler for '{e.Container.Type}'."); + } + }); + } + } + #endregion #region Public Methods @@ -598,5 +672,33 @@ namespace Tango.Integration.ExternalBridge } #endregion + + #region Handlers Registration + + public void RegisterRequestHandler(IExternalBridgeRequestHandler handler) + { + foreach (var method in handler.GetType().GetMethods()) + { + var att = method.GetCustomAttribute<ExternalBridgeRequestHandlerMethodAttribute>(); + if (att != null) + { + _requestHandlers.Add(att.Type.Name, new RequestHandler() + { + Handler = handler, + Method = method + }); + } + } + } + + public void UnregisterRequestHandler(IExternalBridgeRequestHandler handler) + { + foreach (var h in _requestHandlers.Where(x => x.Value.Handler == handler).ToList()) + { + _requestHandlers.Remove(h.Key); + } + } + + #endregion } } diff --git a/Software/Visual_Studio/Tango.Integration/ExternalBridge/IExternalBridgeRequestHandler.cs b/Software/Visual_Studio/Tango.Integration/ExternalBridge/IExternalBridgeRequestHandler.cs new file mode 100644 index 000000000..fe9e9caee --- /dev/null +++ b/Software/Visual_Studio/Tango.Integration/ExternalBridge/IExternalBridgeRequestHandler.cs @@ -0,0 +1,14 @@ +using Google.Protobuf; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.Integration.ExternalBridge +{ + public interface IExternalBridgeRequestHandler + { + + } +} diff --git a/Software/Visual_Studio/Tango.Integration/ExternalBridge/IExternalBridgeService.cs b/Software/Visual_Studio/Tango.Integration/ExternalBridge/IExternalBridgeService.cs index 7ae09c11d..e2d7bea30 100644 --- a/Software/Visual_Studio/Tango.Integration/ExternalBridge/IExternalBridgeService.cs +++ b/Software/Visual_Studio/Tango.Integration/ExternalBridge/IExternalBridgeService.cs @@ -1,4 +1,5 @@ -using System; +using Google.Protobuf; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -83,5 +84,17 @@ namespace Tango.Integration.ExternalBridge /// Disconnects the current remote client session. /// </summary> void DisconnectFullControlSession(); + + /// <summary> + /// Registers the request handler. + /// </summary> + /// <param name="handler">The handler.</param> + void RegisterRequestHandler(IExternalBridgeRequestHandler handler); + + /// <summary> + /// Unregisters the request handler. + /// </summary> + /// <param name="handler">The handler.</param> + void UnregisterRequestHandler(IExternalBridgeRequestHandler handler); } } diff --git a/Software/Visual_Studio/Tango.Integration/Tango.Integration.csproj b/Software/Visual_Studio/Tango.Integration/Tango.Integration.csproj index e2c799cf6..04b2903ce 100644 --- a/Software/Visual_Studio/Tango.Integration/Tango.Integration.csproj +++ b/Software/Visual_Studio/Tango.Integration/Tango.Integration.csproj @@ -101,6 +101,9 @@ <Compile Include="ExternalBridge\ExternalBridgeClientConnectedEventArgs.cs" /> <Compile Include="ExternalBridge\ExternalBridgeReceiver.cs" /> <Compile Include="ExternalBridge\ExternalBridgeReceiverLoginRequestEventArgs.cs" /> + <Compile Include="ExternalBridge\ExternalBridgeReceiverRequestReceivedEventArgs.cs" /> + <Compile Include="ExternalBridge\ExternalBridgeRequestHandlerMethodAttribute.cs" /> + <Compile Include="ExternalBridge\IExternalBridgeRequestHandler.cs" /> <Compile Include="ExternalBridge\ExternalBridgeSignalRConfiguration.cs" /> <Compile Include="ExternalBridge\ExternalBridgeSignalRClient.cs" /> <Compile Include="ExternalBridge\Web\MachineInfo.cs" /> diff --git a/Software/Visual_Studio/Tango.PMR/Common/MessageType.cs b/Software/Visual_Studio/Tango.PMR/Common/MessageType.cs index d50803fed..bc6c46a56 100644 --- a/Software/Visual_Studio/Tango.PMR/Common/MessageType.cs +++ b/Software/Visual_Studio/Tango.PMR/Common/MessageType.cs @@ -22,7 +22,7 @@ namespace Tango.PMR.Common { static MessageTypeReflection() { byte[] descriptorData = global::System.Convert.FromBase64String( string.Concat( - "ChFNZXNzYWdlVHlwZS5wcm90bxIQVGFuZ28uUE1SLkNvbW1vbirvNgoLTWVz", + "ChFNZXNzYWdlVHlwZS5wcm90bxIQVGFuZ28uUE1SLkNvbW1vbiqaNwoLTWVz", "c2FnZVR5cGUSCAoETm9uZRAAEhEKDUVycm9yUmVzcG9uc2UQARIUChBDYWxj", "dWxhdGVSZXF1ZXN0EAMSFQoRQ2FsY3VsYXRlUmVzcG9uc2UQBBITCg9Qcm9n", "cmVzc1JlcXVlc3QQBRIUChBQcm9ncmVzc1Jlc3BvbnNlEAYSHAoYU3R1YkNh", @@ -101,85 +101,86 @@ namespace Tango.PMR.Common { "cXVlc3QQ8wcSIAobU3RvcEFwcGxpY2F0aW9uTG9nc1Jlc3BvbnNlEPQHEhgK", "E0NvbG9yUHJvZmlsZVJlcXVlc3QQ9QcSGQoUQ29sb3JQcm9maWxlUmVzcG9u", "c2UQ9gcSGAoTVXBkYXRlU3RhdHVzUmVxdWVzdBD3BxIZChRVcGRhdGVTdGF0", - "dXNSZXNwb25zZRD4BxIcChdTdGFydERpYWdub3N0aWNzUmVxdWVzdBDQDxId", - "ChhTdGFydERpYWdub3N0aWNzUmVzcG9uc2UQ0Q8SHAoXTW90b3JBYm9ydEhv", - "bWluZ1JlcXVlc3QQ0g8SHQoYTW90b3JBYm9ydEhvbWluZ1Jlc3BvbnNlENMP", - "EhcKEk1vdG9ySG9taW5nUmVxdWVzdBDUDxIYChNNb3RvckhvbWluZ1Jlc3Bv", - "bnNlENUPEhgKE01vdG9ySm9nZ2luZ1JlcXVlc3QQ1g8SGQoUTW90b3JKb2dn", - "aW5nUmVzcG9uc2UQ1w8SHQoYTW90b3JBYm9ydEpvZ2dpbmdSZXF1ZXN0ENgP", - "Eh4KGU1vdG9yQWJvcnRKb2dnaW5nUmVzcG9uc2UQ2Q8SIAobRGlzcGVuc2Vy", - "QWJvcnRIb21pbmdSZXF1ZXN0ENoPEiEKHERpc3BlbnNlckFib3J0SG9taW5n", - "UmVzcG9uc2UQ2w8SGwoWRGlzcGVuc2VySG9taW5nUmVxdWVzdBDcDxIcChdE", - "aXNwZW5zZXJIb21pbmdSZXNwb25zZRDdDxIcChdEaXNwZW5zZXJKb2dnaW5n", - "UmVxdWVzdBDeDxIdChhEaXNwZW5zZXJKb2dnaW5nUmVzcG9uc2UQ3w8SIQoc", - "RGlzcGVuc2VyQWJvcnRKb2dnaW5nUmVxdWVzdBDgDxIiCh1EaXNwZW5zZXJB", - "Ym9ydEpvZ2dpbmdSZXNwb25zZRDhDxIZChRTZXREaWdpdGFsT3V0UmVxdWVz", - "dBDiDxIaChVTZXREaWdpdGFsT3V0UmVzcG9uc2UQ4w8SGQoUVGhyZWFkSm9n", - "Z2luZ1JlcXVlc3QQ5A8SGgoVVGhyZWFkSm9nZ2luZ1Jlc3BvbnNlEOUPEh4K", - "GVRocmVhZEFib3J0Sm9nZ2luZ1JlcXVlc3QQ5g8SHwoaVGhyZWFkQWJvcnRK", - "b2dnaW5nUmVzcG9uc2UQ5w8SHQoYU2V0Q29tcG9uZW50VmFsdWVSZXF1ZXN0", - "EOgPEh4KGVNldENvbXBvbmVudFZhbHVlUmVzcG9uc2UQ6Q8SGAoTUmVzb2x2", - "ZUV2ZW50UmVxdWVzdBDqDxIZChRSZXNvbHZlRXZlbnRSZXNwb25zZRDrDxIb", - "ChZTdG9wRGlhZ25vc3RpY3NSZXF1ZXN0EOwPEhwKF1N0b3BEaWFnbm9zdGlj", - "c1Jlc3BvbnNlEO0PEiMKHlN0YXJ0RXZlbnRzTm90aWZpY2F0aW9uUmVxdWVz", - "dBDuDxIkCh9TdGFydEV2ZW50c05vdGlmaWNhdGlvblJlc3BvbnNlEO8PEiIK", - "HVN0b3BFdmVudHNOb3RpZmljYXRpb25SZXF1ZXN0EPAPEiMKHlN0b3BFdmVu", - "dHNOb3RpZmljYXRpb25SZXNwb25zZRDxDxIaChVTZXRIZWF0ZXJTdGF0ZVJl", - "cXVlc3QQ8g8SGwoWU2V0SGVhdGVyU3RhdGVSZXNwb25zZRDzDxIaChVTZXRC", - "bG93ZXJTdGF0ZVJlcXVlc3QQ9A8SGwoWU2V0Qmxvd2VyU3RhdGVSZXNwb25z", - "ZRD1DxIZChRTZXRWYWx2ZVN0YXRlUmVxdWVzdBD2DxIaChVTZXRWYWx2ZVN0", - "YXRlUmVzcG9uc2UQ9w8SIQocU3RhcnRDYXJ0cmlkZ2VzVXBkYXRlUmVxdWVz", - "dBD4DxIiCh1TdGFydENhcnRyaWRnZXNVcGRhdGVSZXNwb25zZRD5DxIgChtT", - "dG9wQ2FydHJpZGdlc1VwZGF0ZVJlcXVlc3QQ+g8SIQocU3RvcENhcnRyaWRn", - "ZXNVcGRhdGVSZXNwb25zZRD7DxIfChpDYXJ0cmlkZ2VWYWxpZGF0aW9uUmVx", - "dWVzdBD8DxIgChtDYXJ0cmlkZ2VWYWxpZGF0aW9uUmVzcG9uc2UQ/Q8SDwoK", - "Sm9iUmVxdWVzdBC4FxIQCgtKb2JSZXNwb25zZRC5FxIUCg9BYm9ydEpvYlJl", - "cXVlc3QQuhcSFQoQQWJvcnRKb2JSZXNwb25zZRC7FxIjCh5VcGxvYWRQcm9j", - "ZXNzUGFyYW1ldGVyc1JlcXVlc3QQvBcSJAofVXBsb2FkUHJvY2Vzc1BhcmFt", - "ZXRlcnNSZXNwb25zZRC9FxIWChFDdXJyZW50Sm9iUmVxdWVzdBC+FxIXChJD", - "dXJyZW50Sm9iUmVzcG9uc2UQvxcSHAoXUmVzdW1lQ3VycmVudEpvYlJlcXVl", - "c3QQwBcSHQoYUmVzdW1lQ3VycmVudEpvYlJlc3BvbnNlEMEXEhkKFFN0YXJ0", - "RGVidWdMb2dSZXF1ZXN0EKAfEhoKFVN0YXJ0RGVidWdMb2dSZXNwb25zZRCh", - "HxIYChNTdG9wRGVidWdMb2dSZXF1ZXN0EKIfEhkKFFN0b3BEZWJ1Z0xvZ1Jl", - "c3BvbnNlEKMfEh8KGlNldERlYnVnTG9nQ2F0ZWdvcnlSZXF1ZXN0EKQfEiAK", - "G1NldERlYnVnTG9nQ2F0ZWdvcnlSZXNwb25zZRClHxIhChxTZXR1cERlYnVn", - "RGlzcmlidXRvcnNSZXF1ZXN0EKYfEiIKHVNldHVwRGVidWdEaXNyaWJ1dG9y", - "c1Jlc3BvbnNlEKcfEicKIlVwbG9hZEhhcmR3YXJlQ29uZmlndXJhdGlvblJl", - "cXVlc3QQiCcSKAojVXBsb2FkSGFyZHdhcmVDb25maWd1cmF0aW9uUmVzcG9u", - "c2UQiScSFwoSU3lzdGVtUmVzZXRSZXF1ZXN0EIonEhgKE1N5c3RlbVJlc2V0", - "UmVzcG9uc2UQiycSFQoQS2VlcEFsaXZlUmVxdWVzdBDwLhIWChFLZWVwQWxp", - "dmVSZXNwb25zZRDxLhITCg5Db25uZWN0UmVxdWVzdBDyLhIUCg9Db25uZWN0", - "UmVzcG9uc2UQ8y4SFgoRRGlzY29ubmVjdFJlcXVlc3QQ9C4SFwoSRGlzY29u", - "bmVjdFJlc3BvbnNlEPUuEhYKEUZpbGVVcGxvYWRSZXF1ZXN0ENg2EhcKEkZp", - "bGVVcGxvYWRSZXNwb25zZRDZNhIbChZGaWxlQ2h1bmtVcGxvYWRSZXF1ZXN0", - "ENo2EhwKF0ZpbGVDaHVua1VwbG9hZFJlc3BvbnNlENs2EhoKFUV4ZWN1dGVQ", - "cm9jZXNzUmVxdWVzdBDcNhIbChZFeGVjdXRlUHJvY2Vzc1Jlc3BvbnNlEN02", - "EhcKEktpbGxQcm9jZXNzUmVxdWVzdBDeNhIYChNLaWxsUHJvY2Vzc1Jlc3Bv", - "bnNlEN82EhIKDUNyZWF0ZVJlcXVlc3QQ4DYSEwoOQ3JlYXRlUmVzcG9uc2UQ", - "4TYSEgoNRGVsZXRlUmVxdWVzdBDiNhITCg5EZWxldGVSZXNwb25zZRDjNhIa", - "ChVHZXRTdG9yYWdlSW5mb1JlcXVlc3QQ5DYSGwoWR2V0U3RvcmFnZUluZm9S", - "ZXNwb25zZRDlNhIUCg9HZXRGaWxlc1JlcXVlc3QQ5jYSFQoQR2V0RmlsZXNS", - "ZXNwb25zZRDnNhIYChNGaWxlRG93bmxvYWRSZXF1ZXN0EOg2EhkKFEZpbGVE", - "b3dubG9hZFJlc3BvbnNlEOk2Eh0KGEZpbGVDaHVua0Rvd25sb2FkUmVxdWVz", - "dBDqNhIeChlGaWxlQ2h1bmtEb3dubG9hZFJlc3BvbnNlEOs2EhsKFlZhbGlk", - "YXRlVmVyc2lvblJlcXVlc3QQ7DYSHAoXVmFsaWRhdGVWZXJzaW9uUmVzcG9u", - "c2UQ7TYSGwoWQWN0aXZhdGVWZXJzaW9uUmVxdWVzdBDuNhIcChdBY3RpdmF0", - "ZVZlcnNpb25SZXNwb25zZRDvNhIZChREaXNwZW5zZXJEYXRhUmVxdWVzdBDA", - "PhIaChVEaXNwZW5zZXJEYXRhUmVzcG9uc2UQwT4SHAoXTWlkVGFua0RhdGFT", - "ZXR1cFJlcXVlc3QQwj4SHQoYTWlkVGFua0RhdGFTZXR1cFJlc3BvbnNlEMM+", - "EiIKHU1hY2hpbmVDYWxpYnJhdGlvbkRhdGFSZXF1ZXN0EMQ+EiMKHk1hY2hp", - "bmVDYWxpYnJhdGlvbkRhdGFSZXNwb25zZRDFPhIkCh9TdGFydE1hY2hpbmVT", - "dGF0dXNVcGRhdGVSZXF1ZXN0EKhGEiUKIFN0YXJ0TWFjaGluZVN0YXR1c1Vw", - "ZGF0ZVJlc3BvbnNlEKlGEiMKHlN0b3BNYWNoaW5lU3RhdHVzVXBkYXRlUmVx", - "dWVzdBCqRhIkCh9TdG9wTWFjaGluZVN0YXR1c1VwZGF0ZVJlc3BvbnNlEKtG", - "EhoKFVN0YXJ0UG93ZXJEb3duUmVxdWVzdBCQThIbChZTdGFydFBvd2VyRG93", - "blJlc3BvbnNlEJFOEhoKFUFib3J0UG93ZXJEb3duUmVxdWVzdBCSThIbChZB", - "Ym9ydFBvd2VyRG93blJlc3BvbnNlEJNOEh4KGVN0YXJ0VGhyZWFkTG9hZGlu", - "Z1JlcXVlc3QQ+FUSHwoaU3RhcnRUaHJlYWRMb2FkaW5nUmVzcG9uc2UQ+VUS", - "IQocQ29udGludWVUaHJlYWRMb2FkaW5nUmVxdWVzdBD6VRIiCh1Db250aW51", - "ZVRocmVhZExvYWRpbmdSZXNwb25zZRD7VRIdChhTdG9wVGhyZWFkTG9hZGlu", - "Z1JlcXVlc3QQ/FUSHgoZU3RvcFRocmVhZExvYWRpbmdSZXNwb25zZRD9VUIc", - "Chpjb20udHdpbmUudGFuZ28ucG1yLmNvbW1vbmIGcHJvdG8z")); + "dXNSZXNwb25zZRD4BxITCg5HZW5lcmljUmVxdWVzdBD5BxIUCg9HZW5lcmlj", + "UmVzcG9uc2UQ+gcSHAoXU3RhcnREaWFnbm9zdGljc1JlcXVlc3QQ0A8SHQoY", + "U3RhcnREaWFnbm9zdGljc1Jlc3BvbnNlENEPEhwKF01vdG9yQWJvcnRIb21p", + "bmdSZXF1ZXN0ENIPEh0KGE1vdG9yQWJvcnRIb21pbmdSZXNwb25zZRDTDxIX", + "ChJNb3RvckhvbWluZ1JlcXVlc3QQ1A8SGAoTTW90b3JIb21pbmdSZXNwb25z", + "ZRDVDxIYChNNb3RvckpvZ2dpbmdSZXF1ZXN0ENYPEhkKFE1vdG9ySm9nZ2lu", + "Z1Jlc3BvbnNlENcPEh0KGE1vdG9yQWJvcnRKb2dnaW5nUmVxdWVzdBDYDxIe", + "ChlNb3RvckFib3J0Sm9nZ2luZ1Jlc3BvbnNlENkPEiAKG0Rpc3BlbnNlckFi", + "b3J0SG9taW5nUmVxdWVzdBDaDxIhChxEaXNwZW5zZXJBYm9ydEhvbWluZ1Jl", + "c3BvbnNlENsPEhsKFkRpc3BlbnNlckhvbWluZ1JlcXVlc3QQ3A8SHAoXRGlz", + "cGVuc2VySG9taW5nUmVzcG9uc2UQ3Q8SHAoXRGlzcGVuc2VySm9nZ2luZ1Jl", + "cXVlc3QQ3g8SHQoYRGlzcGVuc2VySm9nZ2luZ1Jlc3BvbnNlEN8PEiEKHERp", + "c3BlbnNlckFib3J0Sm9nZ2luZ1JlcXVlc3QQ4A8SIgodRGlzcGVuc2VyQWJv", + "cnRKb2dnaW5nUmVzcG9uc2UQ4Q8SGQoUU2V0RGlnaXRhbE91dFJlcXVlc3QQ", + "4g8SGgoVU2V0RGlnaXRhbE91dFJlc3BvbnNlEOMPEhkKFFRocmVhZEpvZ2dp", + "bmdSZXF1ZXN0EOQPEhoKFVRocmVhZEpvZ2dpbmdSZXNwb25zZRDlDxIeChlU", + "aHJlYWRBYm9ydEpvZ2dpbmdSZXF1ZXN0EOYPEh8KGlRocmVhZEFib3J0Sm9n", + "Z2luZ1Jlc3BvbnNlEOcPEh0KGFNldENvbXBvbmVudFZhbHVlUmVxdWVzdBDo", + "DxIeChlTZXRDb21wb25lbnRWYWx1ZVJlc3BvbnNlEOkPEhgKE1Jlc29sdmVF", + "dmVudFJlcXVlc3QQ6g8SGQoUUmVzb2x2ZUV2ZW50UmVzcG9uc2UQ6w8SGwoW", + "U3RvcERpYWdub3N0aWNzUmVxdWVzdBDsDxIcChdTdG9wRGlhZ25vc3RpY3NS", + "ZXNwb25zZRDtDxIjCh5TdGFydEV2ZW50c05vdGlmaWNhdGlvblJlcXVlc3QQ", + "7g8SJAofU3RhcnRFdmVudHNOb3RpZmljYXRpb25SZXNwb25zZRDvDxIiCh1T", + "dG9wRXZlbnRzTm90aWZpY2F0aW9uUmVxdWVzdBDwDxIjCh5TdG9wRXZlbnRz", + "Tm90aWZpY2F0aW9uUmVzcG9uc2UQ8Q8SGgoVU2V0SGVhdGVyU3RhdGVSZXF1", + "ZXN0EPIPEhsKFlNldEhlYXRlclN0YXRlUmVzcG9uc2UQ8w8SGgoVU2V0Qmxv", + "d2VyU3RhdGVSZXF1ZXN0EPQPEhsKFlNldEJsb3dlclN0YXRlUmVzcG9uc2UQ", + "9Q8SGQoUU2V0VmFsdmVTdGF0ZVJlcXVlc3QQ9g8SGgoVU2V0VmFsdmVTdGF0", + "ZVJlc3BvbnNlEPcPEiEKHFN0YXJ0Q2FydHJpZGdlc1VwZGF0ZVJlcXVlc3QQ", + "+A8SIgodU3RhcnRDYXJ0cmlkZ2VzVXBkYXRlUmVzcG9uc2UQ+Q8SIAobU3Rv", + "cENhcnRyaWRnZXNVcGRhdGVSZXF1ZXN0EPoPEiEKHFN0b3BDYXJ0cmlkZ2Vz", + "VXBkYXRlUmVzcG9uc2UQ+w8SHwoaQ2FydHJpZGdlVmFsaWRhdGlvblJlcXVl", + "c3QQ/A8SIAobQ2FydHJpZGdlVmFsaWRhdGlvblJlc3BvbnNlEP0PEg8KCkpv", + "YlJlcXVlc3QQuBcSEAoLSm9iUmVzcG9uc2UQuRcSFAoPQWJvcnRKb2JSZXF1", + "ZXN0ELoXEhUKEEFib3J0Sm9iUmVzcG9uc2UQuxcSIwoeVXBsb2FkUHJvY2Vz", + "c1BhcmFtZXRlcnNSZXF1ZXN0ELwXEiQKH1VwbG9hZFByb2Nlc3NQYXJhbWV0", + "ZXJzUmVzcG9uc2UQvRcSFgoRQ3VycmVudEpvYlJlcXVlc3QQvhcSFwoSQ3Vy", + "cmVudEpvYlJlc3BvbnNlEL8XEhwKF1Jlc3VtZUN1cnJlbnRKb2JSZXF1ZXN0", + "EMAXEh0KGFJlc3VtZUN1cnJlbnRKb2JSZXNwb25zZRDBFxIZChRTdGFydERl", + "YnVnTG9nUmVxdWVzdBCgHxIaChVTdGFydERlYnVnTG9nUmVzcG9uc2UQoR8S", + "GAoTU3RvcERlYnVnTG9nUmVxdWVzdBCiHxIZChRTdG9wRGVidWdMb2dSZXNw", + "b25zZRCjHxIfChpTZXREZWJ1Z0xvZ0NhdGVnb3J5UmVxdWVzdBCkHxIgChtT", + "ZXREZWJ1Z0xvZ0NhdGVnb3J5UmVzcG9uc2UQpR8SIQocU2V0dXBEZWJ1Z0Rp", + "c3JpYnV0b3JzUmVxdWVzdBCmHxIiCh1TZXR1cERlYnVnRGlzcmlidXRvcnNS", + "ZXNwb25zZRCnHxInCiJVcGxvYWRIYXJkd2FyZUNvbmZpZ3VyYXRpb25SZXF1", + "ZXN0EIgnEigKI1VwbG9hZEhhcmR3YXJlQ29uZmlndXJhdGlvblJlc3BvbnNl", + "EIknEhcKElN5c3RlbVJlc2V0UmVxdWVzdBCKJxIYChNTeXN0ZW1SZXNldFJl", + "c3BvbnNlEIsnEhUKEEtlZXBBbGl2ZVJlcXVlc3QQ8C4SFgoRS2VlcEFsaXZl", + "UmVzcG9uc2UQ8S4SEwoOQ29ubmVjdFJlcXVlc3QQ8i4SFAoPQ29ubmVjdFJl", + "c3BvbnNlEPMuEhYKEURpc2Nvbm5lY3RSZXF1ZXN0EPQuEhcKEkRpc2Nvbm5l", + "Y3RSZXNwb25zZRD1LhIWChFGaWxlVXBsb2FkUmVxdWVzdBDYNhIXChJGaWxl", + "VXBsb2FkUmVzcG9uc2UQ2TYSGwoWRmlsZUNodW5rVXBsb2FkUmVxdWVzdBDa", + "NhIcChdGaWxlQ2h1bmtVcGxvYWRSZXNwb25zZRDbNhIaChVFeGVjdXRlUHJv", + "Y2Vzc1JlcXVlc3QQ3DYSGwoWRXhlY3V0ZVByb2Nlc3NSZXNwb25zZRDdNhIX", + "ChJLaWxsUHJvY2Vzc1JlcXVlc3QQ3jYSGAoTS2lsbFByb2Nlc3NSZXNwb25z", + "ZRDfNhISCg1DcmVhdGVSZXF1ZXN0EOA2EhMKDkNyZWF0ZVJlc3BvbnNlEOE2", + "EhIKDURlbGV0ZVJlcXVlc3QQ4jYSEwoORGVsZXRlUmVzcG9uc2UQ4zYSGgoV", + "R2V0U3RvcmFnZUluZm9SZXF1ZXN0EOQ2EhsKFkdldFN0b3JhZ2VJbmZvUmVz", + "cG9uc2UQ5TYSFAoPR2V0RmlsZXNSZXF1ZXN0EOY2EhUKEEdldEZpbGVzUmVz", + "cG9uc2UQ5zYSGAoTRmlsZURvd25sb2FkUmVxdWVzdBDoNhIZChRGaWxlRG93", + "bmxvYWRSZXNwb25zZRDpNhIdChhGaWxlQ2h1bmtEb3dubG9hZFJlcXVlc3QQ", + "6jYSHgoZRmlsZUNodW5rRG93bmxvYWRSZXNwb25zZRDrNhIbChZWYWxpZGF0", + "ZVZlcnNpb25SZXF1ZXN0EOw2EhwKF1ZhbGlkYXRlVmVyc2lvblJlc3BvbnNl", + "EO02EhsKFkFjdGl2YXRlVmVyc2lvblJlcXVlc3QQ7jYSHAoXQWN0aXZhdGVW", + "ZXJzaW9uUmVzcG9uc2UQ7zYSGQoURGlzcGVuc2VyRGF0YVJlcXVlc3QQwD4S", + "GgoVRGlzcGVuc2VyRGF0YVJlc3BvbnNlEME+EhwKF01pZFRhbmtEYXRhU2V0", + "dXBSZXF1ZXN0EMI+Eh0KGE1pZFRhbmtEYXRhU2V0dXBSZXNwb25zZRDDPhIi", + "Ch1NYWNoaW5lQ2FsaWJyYXRpb25EYXRhUmVxdWVzdBDEPhIjCh5NYWNoaW5l", + "Q2FsaWJyYXRpb25EYXRhUmVzcG9uc2UQxT4SJAofU3RhcnRNYWNoaW5lU3Rh", + "dHVzVXBkYXRlUmVxdWVzdBCoRhIlCiBTdGFydE1hY2hpbmVTdGF0dXNVcGRh", + "dGVSZXNwb25zZRCpRhIjCh5TdG9wTWFjaGluZVN0YXR1c1VwZGF0ZVJlcXVl", + "c3QQqkYSJAofU3RvcE1hY2hpbmVTdGF0dXNVcGRhdGVSZXNwb25zZRCrRhIa", + "ChVTdGFydFBvd2VyRG93blJlcXVlc3QQkE4SGwoWU3RhcnRQb3dlckRvd25S", + "ZXNwb25zZRCRThIaChVBYm9ydFBvd2VyRG93blJlcXVlc3QQkk4SGwoWQWJv", + "cnRQb3dlckRvd25SZXNwb25zZRCTThIeChlTdGFydFRocmVhZExvYWRpbmdS", + "ZXF1ZXN0EPhVEh8KGlN0YXJ0VGhyZWFkTG9hZGluZ1Jlc3BvbnNlEPlVEiEK", + "HENvbnRpbnVlVGhyZWFkTG9hZGluZ1JlcXVlc3QQ+lUSIgodQ29udGludWVU", + "aHJlYWRMb2FkaW5nUmVzcG9uc2UQ+1USHQoYU3RvcFRocmVhZExvYWRpbmdS", + "ZXF1ZXN0EPxVEh4KGVN0b3BUaHJlYWRMb2FkaW5nUmVzcG9uc2UQ/VVCHAoa", + "Y29tLnR3aW5lLnRhbmdvLnBtci5jb21tb25iBnByb3RvMw==")); descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, new pbr::FileDescriptor[] { }, new pbr::GeneratedClrTypeInfo(new[] {typeof(global::Tango.PMR.Common.MessageType), }, null)); @@ -325,6 +326,8 @@ namespace Tango.PMR.Common { [pbr::OriginalName("ColorProfileResponse")] ColorProfileResponse = 1014, [pbr::OriginalName("UpdateStatusRequest")] UpdateStatusRequest = 1015, [pbr::OriginalName("UpdateStatusResponse")] UpdateStatusResponse = 1016, + [pbr::OriginalName("GenericRequest")] GenericRequest = 1017, + [pbr::OriginalName("GenericResponse")] GenericResponse = 1018, /// <summary> ///Diagnostics /// </summary> diff --git a/Software/Visual_Studio/Tango.PMR/Integration/GenericRequest.cs b/Software/Visual_Studio/Tango.PMR/Integration/GenericRequest.cs new file mode 100644 index 000000000..ff158a455 --- /dev/null +++ b/Software/Visual_Studio/Tango.PMR/Integration/GenericRequest.cs @@ -0,0 +1,187 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: GenericRequest.proto +#pragma warning disable 1591, 0612, 3021 +#region Designer generated code + +using pb = global::Google.Protobuf; +using pbc = global::Google.Protobuf.Collections; +using pbr = global::Google.Protobuf.Reflection; +using scg = global::System.Collections.Generic; +namespace Tango.PMR.Integration { + + /// <summary>Holder for reflection information generated from GenericRequest.proto</summary> + public static partial class GenericRequestReflection { + + #region Descriptor + /// <summary>File descriptor for GenericRequest.proto</summary> + public static pbr::FileDescriptor Descriptor { + get { return descriptor; } + } + private static pbr::FileDescriptor descriptor; + + static GenericRequestReflection() { + byte[] descriptorData = global::System.Convert.FromBase64String( + string.Concat( + "ChRHZW5lcmljUmVxdWVzdC5wcm90bxIVVGFuZ28uUE1SLkludGVncmF0aW9u", + "IiwKDkdlbmVyaWNSZXF1ZXN0EgwKBFR5cGUYASABKAkSDAoERGF0YRgCIAEo", + "DEIhCh9jb20udHdpbmUudGFuZ28ucG1yLmludGVncmF0aW9uYgZwcm90bzM=")); + descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, + new pbr::FileDescriptor[] { }, + new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] { + new pbr::GeneratedClrTypeInfo(typeof(global::Tango.PMR.Integration.GenericRequest), global::Tango.PMR.Integration.GenericRequest.Parser, new[]{ "Type", "Data" }, null, null, null) + })); + } + #endregion + + } + #region Messages + public sealed partial class GenericRequest : pb::IMessage<GenericRequest> { + private static readonly pb::MessageParser<GenericRequest> _parser = new pb::MessageParser<GenericRequest>(() => new GenericRequest()); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser<GenericRequest> Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::Tango.PMR.Integration.GenericRequestReflection.Descriptor.MessageTypes[0]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GenericRequest() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GenericRequest(GenericRequest other) : this() { + type_ = other.type_; + data_ = other.data_; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GenericRequest Clone() { + return new GenericRequest(this); + } + + /// <summary>Field number for the "Type" field.</summary> + public const int TypeFieldNumber = 1; + private string type_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Type { + get { return type_; } + set { + type_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// <summary>Field number for the "Data" field.</summary> + public const int DataFieldNumber = 2; + private pb::ByteString data_ = pb::ByteString.Empty; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pb::ByteString Data { + get { return data_; } + set { + data_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as GenericRequest); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(GenericRequest other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Type != other.Type) return false; + if (Data != other.Data) return false; + return true; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Type.Length != 0) hash ^= Type.GetHashCode(); + if (Data.Length != 0) hash ^= Data.GetHashCode(); + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Type.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Type); + } + if (Data.Length != 0) { + output.WriteRawTag(18); + output.WriteBytes(Data); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Type.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Type); + } + if (Data.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeBytesSize(Data); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(GenericRequest other) { + if (other == null) { + return; + } + if (other.Type.Length != 0) { + Type = other.Type; + } + if (other.Data.Length != 0) { + Data = other.Data; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + input.SkipLastField(); + break; + case 10: { + Type = input.ReadString(); + break; + } + case 18: { + Data = input.ReadBytes(); + break; + } + } + } + } + + } + + #endregion + +} + +#endregion Designer generated code diff --git a/Software/Visual_Studio/Tango.PMR/Integration/GenericResponse.cs b/Software/Visual_Studio/Tango.PMR/Integration/GenericResponse.cs new file mode 100644 index 000000000..9262b530a --- /dev/null +++ b/Software/Visual_Studio/Tango.PMR/Integration/GenericResponse.cs @@ -0,0 +1,159 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: GenericResponse.proto +#pragma warning disable 1591, 0612, 3021 +#region Designer generated code + +using pb = global::Google.Protobuf; +using pbc = global::Google.Protobuf.Collections; +using pbr = global::Google.Protobuf.Reflection; +using scg = global::System.Collections.Generic; +namespace Tango.PMR.Integration { + + /// <summary>Holder for reflection information generated from GenericResponse.proto</summary> + public static partial class GenericResponseReflection { + + #region Descriptor + /// <summary>File descriptor for GenericResponse.proto</summary> + public static pbr::FileDescriptor Descriptor { + get { return descriptor; } + } + private static pbr::FileDescriptor descriptor; + + static GenericResponseReflection() { + byte[] descriptorData = global::System.Convert.FromBase64String( + string.Concat( + "ChVHZW5lcmljUmVzcG9uc2UucHJvdG8SFVRhbmdvLlBNUi5JbnRlZ3JhdGlv", + "biIfCg9HZW5lcmljUmVzcG9uc2USDAoERGF0YRgCIAEoDEIhCh9jb20udHdp", + "bmUudGFuZ28ucG1yLmludGVncmF0aW9uYgZwcm90bzM=")); + descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, + new pbr::FileDescriptor[] { }, + new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] { + new pbr::GeneratedClrTypeInfo(typeof(global::Tango.PMR.Integration.GenericResponse), global::Tango.PMR.Integration.GenericResponse.Parser, new[]{ "Data" }, null, null, null) + })); + } + #endregion + + } + #region Messages + public sealed partial class GenericResponse : pb::IMessage<GenericResponse> { + private static readonly pb::MessageParser<GenericResponse> _parser = new pb::MessageParser<GenericResponse>(() => new GenericResponse()); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser<GenericResponse> Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::Tango.PMR.Integration.GenericResponseReflection.Descriptor.MessageTypes[0]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GenericResponse() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GenericResponse(GenericResponse other) : this() { + data_ = other.data_; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GenericResponse Clone() { + return new GenericResponse(this); + } + + /// <summary>Field number for the "Data" field.</summary> + public const int DataFieldNumber = 2; + private pb::ByteString data_ = pb::ByteString.Empty; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pb::ByteString Data { + get { return data_; } + set { + data_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as GenericResponse); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(GenericResponse other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Data != other.Data) return false; + return true; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Data.Length != 0) hash ^= Data.GetHashCode(); + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Data.Length != 0) { + output.WriteRawTag(18); + output.WriteBytes(Data); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Data.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeBytesSize(Data); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(GenericResponse other) { + if (other == null) { + return; + } + if (other.Data.Length != 0) { + Data = other.Data; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + input.SkipLastField(); + break; + case 18: { + Data = input.ReadBytes(); + break; + } + } + } + } + + } + + #endregion + +} + +#endregion Designer generated code diff --git a/Software/Visual_Studio/Tango.PMR/Tango.PMR.csproj b/Software/Visual_Studio/Tango.PMR/Tango.PMR.csproj index 3dd9d7f48..d7b2203dd 100644 --- a/Software/Visual_Studio/Tango.PMR/Tango.PMR.csproj +++ b/Software/Visual_Studio/Tango.PMR/Tango.PMR.csproj @@ -214,6 +214,8 @@ <Compile Include="Integration\ExternalBridgeLogoutRequest.cs" /> <Compile Include="Integration\ExternalBridgeLogoutResponse.cs" /> <Compile Include="Integration\ExternalBridgeUdpDiscoveryPacket.cs" /> + <Compile Include="Integration\GenericRequest.cs" /> + <Compile Include="Integration\GenericResponse.cs" /> <Compile Include="Integration\OverrideDataBaseRequest.cs" /> <Compile Include="Integration\OverrideDataBaseResponse.cs" /> <Compile Include="Integration\StartApplicationLogsRequest.cs" /> diff --git a/Software/Visual_Studio/Tango.Transport/ITransporter.cs b/Software/Visual_Studio/Tango.Transport/ITransporter.cs index 5576de0b2..bffcb0444 100644 --- a/Software/Visual_Studio/Tango.Transport/ITransporter.cs +++ b/Software/Visual_Studio/Tango.Transport/ITransporter.cs @@ -84,6 +84,26 @@ namespace Tango.Transport IObservable<TangoMessage<Response>> SendContinuousRequest<Request, Response>(TangoMessage<Request> request, TransportContinuousRequestConfig config = null) where Request : IMessage<Request> where Response : IMessage<Response>; /// <summary> + /// Sends a generic request of any type. + /// </summary> + /// <typeparam name="Request">The type of the request.</typeparam> + /// <typeparam name="Response">The type of the response.</typeparam> + /// <param name="request">The request.</param> + /// <param name="config">The configuration.</param> + /// <returns></returns> + Task<Response> SendGenericRequest<Request, Response>(Request request, TransportRequestConfig config = null) where Request : class where Response : class; + + /// <summary> + /// Sends a generic response. + /// </summary> + /// <typeparam name="Response">The type of the response.</typeparam> + /// <param name="response">The response.</param> + /// <param name="token">The request token.</param> + /// <param name="config">The response configuration.</param> + /// <returns></returns> + Task SendGenericResponse<Response>(Response response, String token, TransportResponseConfig config = null) where Response : class; + + /// <summary> /// Sends the response. /// </summary> /// <param name="container">The container.</param> diff --git a/Software/Visual_Studio/Tango.Transport/TransporterBase.cs b/Software/Visual_Studio/Tango.Transport/TransporterBase.cs index edd70f22f..e0f9d46dd 100644 --- a/Software/Visual_Studio/Tango.Transport/TransporterBase.cs +++ b/Software/Visual_Studio/Tango.Transport/TransporterBase.cs @@ -19,6 +19,8 @@ using Tango.PMR.Connection; using Tango.Core.Threading; using System.IO; using Tango.Core.ExtensionMethods; +using Tango.PMR.Integration; +using Newtonsoft.Json; namespace Tango.Transport { @@ -40,6 +42,10 @@ namespace Tango.Transport private ITransportAdapter _adapter; private Dictionary<String, PendingResponse> _pendingResponses; private DateTime _lastKeepAliveTime; + private static JsonSerializerSettings _genericMessageSettings = new JsonSerializerSettings() + { + TypeNameHandling = TypeNameHandling.All, + }; #region Events @@ -840,6 +846,39 @@ namespace Tango.Transport return subject.AsObservable(); } + /// <summary> + /// Sends a generic request of any type. + /// </summary> + /// <typeparam name="Request">The type of the request.</typeparam> + /// <typeparam name="Response">The type of the response.</typeparam> + /// <param name="request">The request.</param> + /// <param name="config">The configuration.</param> + /// <returns></returns> + public async Task<Response> SendGenericRequest<Request, Response>(Request request, TransportRequestConfig config = null) where Request : class where Response : class + { + GenericRequest genericRequest = new GenericRequest(); + genericRequest.Type = request.GetType().Name; + genericRequest.Data = ByteString.CopyFromUtf8(JsonConvert.SerializeObject(request, _genericMessageSettings)); + var response = await SendRequest<GenericRequest, GenericResponse>(genericRequest, config); + var responseObject = JsonConvert.DeserializeObject<Response>(response.Message.Data.ToStringUtf8()); + return responseObject; + } + + /// <summary> + /// Sends a generic response. + /// </summary> + /// <typeparam name="Response">The type of the response.</typeparam> + /// <param name="response">The response.</param> + /// <param name="token">The request token.</param> + /// <param name="config">The response configuration.</param> + /// <returns></returns> + public async Task SendGenericResponse<Response>(Response response, String token, TransportResponseConfig config = null) where Response : class + { + GenericResponse genericResponse = new GenericResponse(); + genericResponse.Data = ByteString.CopyFromUtf8(JsonConvert.SerializeObject(response, _genericMessageSettings)); + await SendResponse<GenericResponse>(genericResponse, token, config); + } + #endregion #region Public Response Methods |
