From 38cfb67f62c46a17f126698d3fea5d517c45f332 Mon Sep 17 00:00:00 2001 From: "chris.watts90@outlook.com" Date: Sun, 25 Jun 2017 22:27:21 +0100 Subject: [PATCH] resharper tidying on a lot of files. start padding out history pages. update plugin extension points to use PluginDetails object to identify themselves. implemented last scanned id methods to get last id from real ir daemon code to show on Race Director Page --- RaceLapTimer/Helpers.Encrytion/Hash.cs | 3 +- .../Properties/AssemblyInfo.cs | 1 - .../Interfaces/ConfigurationSetting.cs | 7 +- .../Interfaces/IConfigFilePathProvider.cs | 8 +- RaceLapTimer/Interfaces/IContainerHelper.cs | 3 - RaceLapTimer/Interfaces/INotifierProvider.cs | 2 +- RaceLapTimer/Interfaces/IPluginInformation.cs | 7 + .../Interfaces/IPluginPathProvider.cs | 8 +- RaceLapTimer/Interfaces/ISystemControl.cs | 2 +- .../ISystemControlProviderFactory.cs | 2 +- .../Interfaces/ITransponderUtilityProvider.cs | 2 +- RaceLapTimer/Interfaces/IUserStorage.cs | 7 +- RaceLapTimer/Interfaces/Interfaces.csproj | 3 +- RaceLapTimer/Interfaces/PluginDetails.cs | 17 +++ .../Interfaces/Properties/AssemblyInfo.cs | 1 - RaceLapTimer/Interfaces/ProviderDetails.cs | 16 -- RaceLapTimer/Interfaces/RaceSession.cs | 4 - .../IdDaemonTransponderUtilityFactory.cs | 11 +- .../IrDaemonNotifier/IrDaemonCommunicator.cs | 137 ++++++++++++++++++ .../IrDaemonNotifier/IrDaemonController.cs | 7 +- .../IrDaemonControllerProviderFactory.cs | 2 +- .../IrDaemonNotifier/IrDaemonNotifier.cs | 32 +--- .../IrDaemonNotifier/IrDaemonNotifier.csproj | 2 + .../IrDaemonNotifierProviderFactory.cs | 7 +- .../IrDaemonTransponderUtilities.cs | 21 ++- .../Properties/AssemblyInfo.cs | 1 - RaceLapTimer/IrDaemonNotifier/Resources.cs | 9 ++ RaceLapTimer/NLogLogger/NLogLoggingService.cs | 2 +- .../NLogLogger/Properties/AssemblyInfo.cs | 1 - .../ApiControllers/LapTrackApiModule.cs | 6 +- .../ApiControllers/MonitorApiModule.cs | 7 +- .../ApiControllers/PilotApiModule.cs | 18 +-- .../ApiControllers/RaceSessionApiModule.cs | 14 +- .../ApiControllers/SatelliteApiModule.cs | 8 +- .../ApiControllers/SoundApiModule.cs | 3 +- .../ApiControllers/SystemApiModule.cs | 21 ++- .../{Helpers => Assists}/AsyncHelpers.cs | 36 +++-- .../AuthenticationBootstrapper.cs | 6 +- .../RaceLapTimer/ConfigFilePathProvider.cs | 4 - .../Notifications/NotificationManager.cs | 14 -- .../RaceLapTimer/Extensions/PluginLocator.cs | 4 - .../SystemControl/SystemControlManager.cs | 5 +- .../TransponderUtilityManager.cs | 4 +- RaceLapTimer/RaceLapTimer/IDbProvider.cs | 2 + .../RaceLapTimer/Modules/HistoryModule.cs | 10 +- .../RaceLapTimer/Modules/LoginModule.cs | 22 ++- .../RaceLapTimer/Modules/MonitorModule.cs | 13 +- .../RaceLapTimer/Modules/PilotModule.cs | 7 +- .../RaceLapTimer/Modules/PilotsModule.cs | 11 +- .../Modules/RaceDirectorModule.cs | 11 +- .../RaceLapTimer/Modules/SoundfileModule.cs | 6 +- .../RaceLapTimer/Modules/SystemModule.cs | 6 +- .../RaceLapTimer/Modules/UserModule.cs | 7 +- RaceLapTimer/RaceLapTimer/Program.cs | 13 +- .../RaceLapTimer/Properties/AssemblyInfo.cs | 1 - RaceLapTimer/RaceLapTimer/RaceLapTimer.csproj | 14 ++ RaceLapTimer/RaceLapTimer/TestProvider.cs | 29 +++- RaceLapTimer/RaceLapTimer/UserDatabase.cs | 13 +- .../www/Views/HistoryIndex.cshtml | 61 ++++++++ .../www/Views/RaceDirector.cshtml | 3 +- .../RaceLapTimer/www/Views/SystemIndex.cshtml | 6 + .../RaceLapTimer/www/js/LastScannedId.js | 4 + .../RaceLapTimer/www/js/RaceSessionObject.js | 5 +- .../RaceLapTimer/www/js/moment.min.js | 7 + .../RaceLapTimer/www/js/raceDirector.js | 16 +- .../RaceLapTimer/www/js/raceHistory.js | 31 ++++ .../Properties/AssemblyInfo.cs | 1 - .../UdpNotifier/Properties/AssemblyInfo.cs | 1 - .../UdpNotifier/UdpNotifierProvider.cs | 23 ++- .../UdpNotifier/UdpNotifierProviderFactory.cs | 6 +- 70 files changed, 517 insertions(+), 287 deletions(-) create mode 100644 RaceLapTimer/Interfaces/IPluginInformation.cs create mode 100644 RaceLapTimer/Interfaces/PluginDetails.cs delete mode 100644 RaceLapTimer/Interfaces/ProviderDetails.cs create mode 100644 RaceLapTimer/IrDaemonNotifier/IrDaemonCommunicator.cs create mode 100644 RaceLapTimer/IrDaemonNotifier/Resources.cs rename RaceLapTimer/RaceLapTimer/{Helpers => Assists}/AsyncHelpers.cs (78%) create mode 100644 RaceLapTimer/RaceLapTimer/www/Views/HistoryIndex.cshtml create mode 100644 RaceLapTimer/RaceLapTimer/www/Views/SystemIndex.cshtml create mode 100644 RaceLapTimer/RaceLapTimer/www/js/LastScannedId.js create mode 100644 RaceLapTimer/RaceLapTimer/www/js/moment.min.js create mode 100644 RaceLapTimer/RaceLapTimer/www/js/raceHistory.js diff --git a/RaceLapTimer/Helpers.Encrytion/Hash.cs b/RaceLapTimer/Helpers.Encrytion/Hash.cs index b41d056..f3317c5 100644 --- a/RaceLapTimer/Helpers.Encrytion/Hash.cs +++ b/RaceLapTimer/Helpers.Encrytion/Hash.cs @@ -1,5 +1,4 @@ -using System; -using System.Security.Cryptography; +using System.Security.Cryptography; using System.Text; namespace Helpers.Encryption diff --git a/RaceLapTimer/Helpers.Encrytion/Properties/AssemblyInfo.cs b/RaceLapTimer/Helpers.Encrytion/Properties/AssemblyInfo.cs index 7ba4948..f3b758b 100644 --- a/RaceLapTimer/Helpers.Encrytion/Properties/AssemblyInfo.cs +++ b/RaceLapTimer/Helpers.Encrytion/Properties/AssemblyInfo.cs @@ -1,5 +1,4 @@ using System.Reflection; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following diff --git a/RaceLapTimer/Interfaces/ConfigurationSetting.cs b/RaceLapTimer/Interfaces/ConfigurationSetting.cs index 751074c..f3a1f20 100644 --- a/RaceLapTimer/Interfaces/ConfigurationSetting.cs +++ b/RaceLapTimer/Interfaces/ConfigurationSetting.cs @@ -1,9 +1,4 @@ -using System; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Interfaces +namespace Interfaces { public class ConfigurationSetting { diff --git a/RaceLapTimer/Interfaces/IConfigFilePathProvider.cs b/RaceLapTimer/Interfaces/IConfigFilePathProvider.cs index 927be83..5c85cac 100644 --- a/RaceLapTimer/Interfaces/IConfigFilePathProvider.cs +++ b/RaceLapTimer/Interfaces/IConfigFilePathProvider.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Interfaces +namespace Interfaces { public interface IConfigFilePathProvider { diff --git a/RaceLapTimer/Interfaces/IContainerHelper.cs b/RaceLapTimer/Interfaces/IContainerHelper.cs index f04cff1..4d3309a 100644 --- a/RaceLapTimer/Interfaces/IContainerHelper.cs +++ b/RaceLapTimer/Interfaces/IContainerHelper.cs @@ -1,8 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Interfaces { diff --git a/RaceLapTimer/Interfaces/INotifierProvider.cs b/RaceLapTimer/Interfaces/INotifierProvider.cs index b252737..b58ad8a 100644 --- a/RaceLapTimer/Interfaces/INotifierProvider.cs +++ b/RaceLapTimer/Interfaces/INotifierProvider.cs @@ -1,6 +1,6 @@ namespace Interfaces { - public interface INotifierProvider + public interface INotifierProvider : IPluginInformation { string GetDisplayName(); void NotifyRaceStarted(NotificationEventArgs args); diff --git a/RaceLapTimer/Interfaces/IPluginInformation.cs b/RaceLapTimer/Interfaces/IPluginInformation.cs new file mode 100644 index 0000000..19c708a --- /dev/null +++ b/RaceLapTimer/Interfaces/IPluginInformation.cs @@ -0,0 +1,7 @@ +namespace Interfaces +{ + public interface IPluginInformation + { + PluginDetails GetPluginDetails(); + } +} diff --git a/RaceLapTimer/Interfaces/IPluginPathProvider.cs b/RaceLapTimer/Interfaces/IPluginPathProvider.cs index 0c73726..26862f8 100644 --- a/RaceLapTimer/Interfaces/IPluginPathProvider.cs +++ b/RaceLapTimer/Interfaces/IPluginPathProvider.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Interfaces +namespace Interfaces { public interface IPluginPathProvider { diff --git a/RaceLapTimer/Interfaces/ISystemControl.cs b/RaceLapTimer/Interfaces/ISystemControl.cs index 6ec0b46..8646feb 100644 --- a/RaceLapTimer/Interfaces/ISystemControl.cs +++ b/RaceLapTimer/Interfaces/ISystemControl.cs @@ -1,6 +1,6 @@ namespace Interfaces { - public interface ISystemControl + public interface ISystemControlProvider : IPluginInformation { void Shutdown(); } diff --git a/RaceLapTimer/Interfaces/ISystemControlProviderFactory.cs b/RaceLapTimer/Interfaces/ISystemControlProviderFactory.cs index 5d38bb5..2d49bc7 100644 --- a/RaceLapTimer/Interfaces/ISystemControlProviderFactory.cs +++ b/RaceLapTimer/Interfaces/ISystemControlProviderFactory.cs @@ -2,6 +2,6 @@ { public interface ISystemControlProviderFactory { - ISystemControl GetProvider(); + ISystemControlProvider GetProvider(); } } diff --git a/RaceLapTimer/Interfaces/ITransponderUtilityProvider.cs b/RaceLapTimer/Interfaces/ITransponderUtilityProvider.cs index 6da3120..9cc6db5 100644 --- a/RaceLapTimer/Interfaces/ITransponderUtilityProvider.cs +++ b/RaceLapTimer/Interfaces/ITransponderUtilityProvider.cs @@ -2,7 +2,7 @@ namespace Interfaces { - public interface ITransponderUtilityProvider + public interface ITransponderUtilityProvider : IPluginInformation { Task GetLastScannedIdAsync(); } diff --git a/RaceLapTimer/Interfaces/IUserStorage.cs b/RaceLapTimer/Interfaces/IUserStorage.cs index 7ec0aa5..52aea7e 100644 --- a/RaceLapTimer/Interfaces/IUserStorage.cs +++ b/RaceLapTimer/Interfaces/IUserStorage.cs @@ -1,9 +1,4 @@ -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Interfaces +namespace Interfaces { public interface IUserStorage { diff --git a/RaceLapTimer/Interfaces/Interfaces.csproj b/RaceLapTimer/Interfaces/Interfaces.csproj index 387ab44..3ff7cbe 100644 --- a/RaceLapTimer/Interfaces/Interfaces.csproj +++ b/RaceLapTimer/Interfaces/Interfaces.csproj @@ -43,6 +43,7 @@ + @@ -58,7 +59,7 @@ - + diff --git a/RaceLapTimer/Interfaces/PluginDetails.cs b/RaceLapTimer/Interfaces/PluginDetails.cs new file mode 100644 index 0000000..dac62db --- /dev/null +++ b/RaceLapTimer/Interfaces/PluginDetails.cs @@ -0,0 +1,17 @@ +namespace Interfaces +{ + public class PluginDetails + { + public PluginDetails(string pluginName, string pluginAuthor, string pluginDescription, string pluginVersion) + { + PluginName = pluginName; + PluginAuthor = pluginAuthor; + PluginDescription = pluginDescription; + PluginVersion = pluginVersion; + } + public string PluginName { get; } + public string PluginAuthor { get; } + public string PluginDescription { get; } + public string PluginVersion { get; } + } +} diff --git a/RaceLapTimer/Interfaces/Properties/AssemblyInfo.cs b/RaceLapTimer/Interfaces/Properties/AssemblyInfo.cs index 7ebd61f..db04b03 100644 --- a/RaceLapTimer/Interfaces/Properties/AssemblyInfo.cs +++ b/RaceLapTimer/Interfaces/Properties/AssemblyInfo.cs @@ -1,5 +1,4 @@ using System.Reflection; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following diff --git a/RaceLapTimer/Interfaces/ProviderDetails.cs b/RaceLapTimer/Interfaces/ProviderDetails.cs deleted file mode 100644 index 9f0af3a..0000000 --- a/RaceLapTimer/Interfaces/ProviderDetails.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Interfaces -{ - public class ProviderDetails - { - public string ProviderName { get; set; } - public string ProviderAuthor { get; set; } - public string ProviderDescription { get; set; } - - } -} diff --git a/RaceLapTimer/Interfaces/RaceSession.cs b/RaceLapTimer/Interfaces/RaceSession.cs index dd320f0..0b5e946 100644 --- a/RaceLapTimer/Interfaces/RaceSession.cs +++ b/RaceLapTimer/Interfaces/RaceSession.cs @@ -1,8 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Interfaces { diff --git a/RaceLapTimer/IrDaemonNotifier/IdDaemonTransponderUtilityFactory.cs b/RaceLapTimer/IrDaemonNotifier/IdDaemonTransponderUtilityFactory.cs index 266cb42..7ea6a99 100644 --- a/RaceLapTimer/IrDaemonNotifier/IdDaemonTransponderUtilityFactory.cs +++ b/RaceLapTimer/IrDaemonNotifier/IdDaemonTransponderUtilityFactory.cs @@ -2,11 +2,18 @@ namespace IrDaemonNotifier { - public class IdDaemonTransponderUtilityFactory : ITransponderUtilityProviderFactory + public class IrDaemonTransponderUtilityFactory : ITransponderUtilityProviderFactory { + private readonly ILoggerService _logger; + + public IrDaemonTransponderUtilityFactory(ILoggerService logger) + { + _logger = logger; + } + public ITransponderUtilityProvider GetProvider() { - return new IrDaemonTransponderUtilities(); + return new IrDaemonTransponderUtilities(_logger); } } } \ No newline at end of file diff --git a/RaceLapTimer/IrDaemonNotifier/IrDaemonCommunicator.cs b/RaceLapTimer/IrDaemonNotifier/IrDaemonCommunicator.cs new file mode 100644 index 0000000..8609a7e --- /dev/null +++ b/RaceLapTimer/IrDaemonNotifier/IrDaemonCommunicator.cs @@ -0,0 +1,137 @@ +using System.Net.Sockets; +using System.Text; +using Interfaces; + +namespace IrDaemonNotifier +{ + class IrDaemonCommunicator + { + private const string IRDAEMON_SERVER_IP = "192.168.1.65"; + private const int IRDAEMON_PORT_NO = 3006; + private const int IRDAEMON_PROPERTY_PORT_NO = 3007; + + private ILoggerService _logger; + + public IrDaemonCommunicator(ILoggerService logger) + { + _logger = logger; + } + + /// + /// Send a command to the IrDaemon endpoint + /// + /// string command name + //TODO: convert to use an enum value perhaps? "supported command" style? + public void SendCommand(string command) + { + var formattedCommand = FormatCommand(command); + + //---create a TCPClient object at the IP and port no.--- + var client = new TcpClient(IRDAEMON_SERVER_IP, IRDAEMON_PORT_NO); + var nwStream = client.GetStream(); + var bytesToSend = Encoding.ASCII.GetBytes(formattedCommand); + + //---send the text--- + _logger.Trace("Sending: {0}", formattedCommand); + nwStream.Write(bytesToSend, 0, bytesToSend.Length); + + //---read back the text--- + var bytesToRead = new byte[client.ReceiveBufferSize]; + var bytesRead = nwStream.Read(bytesToRead, 0, client.ReceiveBufferSize); + _logger.Trace("Received: {0}", Encoding.ASCII.GetString(bytesToRead, 0, bytesRead)); + client.Close(); + } + + /// + /// Get data from the IrDaemon for the requested property name + /// + /// type to convert property value to + /// The name of the property to request data for + /// the object returned from the ir daemon, converted to the Type T + public T RequestData(string command) + { + try + { + var formattedCommand = FormatCommand(command); + + //---create a TCPClient object at the IP and port no.--- + var client = new TcpClient(IRDAEMON_SERVER_IP, IRDAEMON_PROPERTY_PORT_NO); + var nwStream = client.GetStream(); + var bytesToSend = Encoding.ASCII.GetBytes(formattedCommand); + + //---send the text--- + _logger.Trace("Sending: {0}", formattedCommand); + nwStream.Write(bytesToSend, 0, bytesToSend.Length); + + //---read back the text--- + var bytesToRead = new byte[client.ReceiveBufferSize]; + var bytesRead = nwStream.Read(bytesToRead, 0, client.ReceiveBufferSize); + var stringResponse = Encoding.ASCII.GetString(bytesToRead, 0, bytesRead); + client.Close(); + stringResponse = StripFormatting(stringResponse); + _logger.Trace("Received: {0}", stringResponse); + + var strId = GetTokenIdString(stringResponse); + + try + { + return Convert(strId); + } + catch + { + return default(T); + } + } + catch (System.Exception ex) + { + _logger.Error(ex); + } + return default(T); + } + + /// + /// Format the command string for the ir daemon "protocol" + /// + /// command to format + /// formatted command + private string FormatCommand(string command) + { + return string.Format("#{0}#\n", command); + } + + /// + /// remove the formatting from the string + /// + /// string to remove formatting from + /// string with protocol formatting removed + private string StripFormatting(string data) + { + return data.Replace("#", "").Replace("\n", ""); + } + + private string GetTokenIdString(string data) + { + var bits = data.Split(' '); + if(bits.Length == 3) + return bits[1]; + return string.Empty; + } + + private T Convert(string data) + { + return (T)System.Convert.ChangeType(data, typeof(T)); + } + } + + internal class Commands + { + + public class Properties + { + public const string GetLastToken = "LAST_SCANNED_TOKEN"; + } + + public const string Shutdown = "SHUTDOWN"; + public const string Reset = "RESET"; + } +} diff --git a/RaceLapTimer/IrDaemonNotifier/IrDaemonController.cs b/RaceLapTimer/IrDaemonNotifier/IrDaemonController.cs index 83449e0..e44b282 100644 --- a/RaceLapTimer/IrDaemonNotifier/IrDaemonController.cs +++ b/RaceLapTimer/IrDaemonNotifier/IrDaemonController.cs @@ -3,11 +3,16 @@ using Interfaces; namespace IrDaemonNotifier { - public class IrDaemonController:ISystemControl + public class IrDaemonController:ISystemControlProvider { public void Shutdown() { Debug.WriteLine("test"); } + + public PluginDetails GetPluginDetails() + { + return Resources.Details; + } } } diff --git a/RaceLapTimer/IrDaemonNotifier/IrDaemonControllerProviderFactory.cs b/RaceLapTimer/IrDaemonNotifier/IrDaemonControllerProviderFactory.cs index d097ce5..e5ecb39 100644 --- a/RaceLapTimer/IrDaemonNotifier/IrDaemonControllerProviderFactory.cs +++ b/RaceLapTimer/IrDaemonNotifier/IrDaemonControllerProviderFactory.cs @@ -4,7 +4,7 @@ namespace IrDaemonNotifier { public class IrDaemonControllerProviderFactory : ISystemControlProviderFactory { - public ISystemControl GetProvider() + public ISystemControlProvider GetProvider() { return new IrDaemonController(); } diff --git a/RaceLapTimer/IrDaemonNotifier/IrDaemonNotifier.cs b/RaceLapTimer/IrDaemonNotifier/IrDaemonNotifier.cs index 71c8e06..86b1fd6 100644 --- a/RaceLapTimer/IrDaemonNotifier/IrDaemonNotifier.cs +++ b/RaceLapTimer/IrDaemonNotifier/IrDaemonNotifier.cs @@ -1,18 +1,10 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Net.Sockets; -using System.Text; -using System.Threading.Tasks; using Interfaces; namespace IrDaemonNotifier { public class IrDaemonNotifier : INotifierProvider { - private const int REMOTE_PORT_NO = 3006; - private const string REMOTE_SERVER_IP = "127.0.0.1"; - private readonly ILoggerService _logger; public IrDaemonNotifier(ILoggerService logger) @@ -25,32 +17,17 @@ namespace IrDaemonNotifier return "Ir Daemon Notifier"; } - public string GetNotifierType() + public PluginDetails GetPluginDetails() { - return nameof(IrDaemonNotifier); + return Resources.Details; } public void NotifyRaceStarted(NotificationEventArgs args) { try { - //---data to send to the server--- - var message = string.Format("#{0}#\n", "RESET"); - - //---create a TCPClient object at the IP and port no.--- - var client = new TcpClient(REMOTE_SERVER_IP, REMOTE_PORT_NO); - var nwStream = client.GetStream(); - var bytesToSend = Encoding.ASCII.GetBytes(message); - - //---send the text--- - _logger.Trace("Sending: {0}", message); - nwStream.Write(bytesToSend, 0, bytesToSend.Length); - - //---read back the text--- - var bytesToRead = new byte[client.ReceiveBufferSize]; - var bytesRead = nwStream.Read(bytesToRead, 0, client.ReceiveBufferSize); - _logger.Trace("Received: {0}", Encoding.ASCII.GetString(bytesToRead, 0, bytesRead)); - client.Close(); + var communicator = new IrDaemonCommunicator(_logger); + communicator.SendCommand(Commands.Reset); } catch (Exception ex) { @@ -73,5 +50,6 @@ namespace IrDaemonNotifier public void NotifyRaceFinished(NotificationEventArgs args) { } + } } diff --git a/RaceLapTimer/IrDaemonNotifier/IrDaemonNotifier.csproj b/RaceLapTimer/IrDaemonNotifier/IrDaemonNotifier.csproj index 8aa8f73..e8b9ad1 100644 --- a/RaceLapTimer/IrDaemonNotifier/IrDaemonNotifier.csproj +++ b/RaceLapTimer/IrDaemonNotifier/IrDaemonNotifier.csproj @@ -41,12 +41,14 @@ + + diff --git a/RaceLapTimer/IrDaemonNotifier/IrDaemonNotifierProviderFactory.cs b/RaceLapTimer/IrDaemonNotifier/IrDaemonNotifierProviderFactory.cs index 61e7a8f..5dc7af0 100644 --- a/RaceLapTimer/IrDaemonNotifier/IrDaemonNotifierProviderFactory.cs +++ b/RaceLapTimer/IrDaemonNotifier/IrDaemonNotifierProviderFactory.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Interfaces; +using Interfaces; namespace IrDaemonNotifier { diff --git a/RaceLapTimer/IrDaemonNotifier/IrDaemonTransponderUtilities.cs b/RaceLapTimer/IrDaemonNotifier/IrDaemonTransponderUtilities.cs index dfc255d..64079b8 100644 --- a/RaceLapTimer/IrDaemonNotifier/IrDaemonTransponderUtilities.cs +++ b/RaceLapTimer/IrDaemonNotifier/IrDaemonTransponderUtilities.cs @@ -5,9 +5,28 @@ namespace IrDaemonNotifier { public class IrDaemonTransponderUtilities : ITransponderUtilityProvider { + private readonly ILoggerService _logger; + + public IrDaemonTransponderUtilities(ILoggerService logger) + { + _logger = logger; + } + public Task GetLastScannedIdAsync() { - return Task.FromResult(-1); + return Task.Run(()=>GetLastId()); + } + + public PluginDetails GetPluginDetails() + { + return Resources.Details; + } + + private int GetLastId() + { + //TODO: implement caching here, network/request latency is mega, always exceeds 1second, this is too much + var communicator = new IrDaemonCommunicator(_logger); + return communicator.RequestData(Commands.Properties.GetLastToken); } } } \ No newline at end of file diff --git a/RaceLapTimer/IrDaemonNotifier/Properties/AssemblyInfo.cs b/RaceLapTimer/IrDaemonNotifier/Properties/AssemblyInfo.cs index e6374c5..2561a80 100644 --- a/RaceLapTimer/IrDaemonNotifier/Properties/AssemblyInfo.cs +++ b/RaceLapTimer/IrDaemonNotifier/Properties/AssemblyInfo.cs @@ -1,5 +1,4 @@ using System.Reflection; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following diff --git a/RaceLapTimer/IrDaemonNotifier/Resources.cs b/RaceLapTimer/IrDaemonNotifier/Resources.cs new file mode 100644 index 0000000..d21b61b --- /dev/null +++ b/RaceLapTimer/IrDaemonNotifier/Resources.cs @@ -0,0 +1,9 @@ +using Interfaces; + +namespace IrDaemonNotifier +{ + public static class Resources + { + public static readonly PluginDetails Details = new PluginDetails("IrDaemonNotifier", "Chris Watts", "IR Daemon Interface", "1.0.0.0"); + } +} \ No newline at end of file diff --git a/RaceLapTimer/NLogLogger/NLogLoggingService.cs b/RaceLapTimer/NLogLogger/NLogLoggingService.cs index 4c9eeac..254e623 100644 --- a/RaceLapTimer/NLogLogger/NLogLoggingService.cs +++ b/RaceLapTimer/NLogLogger/NLogLoggingService.cs @@ -9,7 +9,7 @@ namespace NLogLogger { public class NLogLoggingService : ILoggerService { - private readonly NLog.Logger _logger; + private readonly Logger _logger; public NLogLoggingService(IConfigFilePathProvider configFileFolder) { var cfgFilePath = Path.Combine(configFileFolder.GetPath, "NLogConfig.xml"); diff --git a/RaceLapTimer/NLogLogger/Properties/AssemblyInfo.cs b/RaceLapTimer/NLogLogger/Properties/AssemblyInfo.cs index 432b8f6..2b2ef68 100644 --- a/RaceLapTimer/NLogLogger/Properties/AssemblyInfo.cs +++ b/RaceLapTimer/NLogLogger/Properties/AssemblyInfo.cs @@ -1,5 +1,4 @@ using System.Reflection; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following diff --git a/RaceLapTimer/RaceLapTimer/ApiControllers/LapTrackApiModule.cs b/RaceLapTimer/RaceLapTimer/ApiControllers/LapTrackApiModule.cs index 8bb37dd..2ed5cbb 100644 --- a/RaceLapTimer/RaceLapTimer/ApiControllers/LapTrackApiModule.cs +++ b/RaceLapTimer/RaceLapTimer/ApiControllers/LapTrackApiModule.cs @@ -9,17 +9,17 @@ namespace RaceLapTimer.ApiControllers public LapTrackApiModule(IDbProvider provider) : base("/api/laptrack") { _dbProvider = provider; - Get["/create"] = args => LogLapTime(args); + Get["/create"] = args => LogLapTime(); } - private dynamic LogLapTime(dynamic args) + private dynamic LogLapTime() { var transponderToken = Convert.ToInt32(Request.Query["transponder_token"]); var lapTimeInMs = Convert.ToInt32(Request.Query["lap_time_in_ms"]); var log = new SatelliteLog { TransponderToken = transponderToken, - LapTimeMS = lapTimeInMs + LapTimeMs = lapTimeInMs }; _dbProvider.StoreTransponderLog(log); return HttpStatusCode.OK; diff --git a/RaceLapTimer/RaceLapTimer/ApiControllers/MonitorApiModule.cs b/RaceLapTimer/RaceLapTimer/ApiControllers/MonitorApiModule.cs index 177e329..86cb39c 100644 --- a/RaceLapTimer/RaceLapTimer/ApiControllers/MonitorApiModule.cs +++ b/RaceLapTimer/RaceLapTimer/ApiControllers/MonitorApiModule.cs @@ -1,5 +1,4 @@ -using System.Runtime.InteropServices; -using Nancy; +using Nancy; namespace RaceLapTimer.ApiControllers { @@ -10,10 +9,10 @@ namespace RaceLapTimer.ApiControllers { _provider = provider; - Get[""] = args => GetRootMonitorData(args); + Get[""] = args => GetRootMonitorData(); } - private dynamic GetRootMonitorData(dynamic args) + private dynamic GetRootMonitorData() { return Response.AsJson(new { data = _provider.GetRaceSessions(true)}); } diff --git a/RaceLapTimer/RaceLapTimer/ApiControllers/PilotApiModule.cs b/RaceLapTimer/RaceLapTimer/ApiControllers/PilotApiModule.cs index b88b4cc..ee7cdae 100644 --- a/RaceLapTimer/RaceLapTimer/ApiControllers/PilotApiModule.cs +++ b/RaceLapTimer/RaceLapTimer/ApiControllers/PilotApiModule.cs @@ -1,16 +1,14 @@ using System; using System.IO; using System.Linq; -using System.Web.Http; using Interfaces; using Nancy; using Nancy.Extensions; using Nancy.ModelBinding; -using Nancy.Responses; namespace RaceLapTimer.ApiControllers { - public class PilotApiModule:NancyModule + public class PilotApiModule : NancyModule { private readonly IDbProvider _provider; private readonly IRootPathProvider _rootPathProvider; @@ -21,8 +19,8 @@ namespace RaceLapTimer.ApiControllers _rootPathProvider = pathProvider; Get["/{id}"] = args => GetPilot(args); - Post["/edit"] = args => EditCreatePilot(args); - Post["/create"] = args => EditCreatePilot(args); + Post["/edit"] = args => EditCreatePilot(); + Post["/create"] = args => EditCreatePilot(); Get["/delete/{id}"] = args => DeletePilot(args); Post["/upload/{id}"] = args => UploadPicture(args); } @@ -41,13 +39,13 @@ namespace RaceLapTimer.ApiControllers } var file = Request.Files.First(); - + var newFileName = Guid.NewGuid(); - var generatedFileName = string.Format("{0}{1}",newFileName,Path.GetExtension(file.Name)); //0000-0000.....ext + var generatedFileName = string.Format("{0}{1}", newFileName, Path.GetExtension(file.Name)); //0000-0000.....ext var filename = Path.Combine(uploadDirectory, generatedFileName); - using (FileStream fileStream = new FileStream(filename, FileMode.Create)) + using (var fileStream = new FileStream(filename, FileMode.Create)) { file.Value.CopyTo(fileStream); fileStream.Flush(); @@ -66,7 +64,7 @@ namespace RaceLapTimer.ApiControllers private dynamic DeletePilot(dynamic args) { var res = _provider.DeletePilot(args.Id); - return Response.AsRedirect("/pilots"); + return Context.GetRedirect("/pilots"); } private dynamic GetPilot(dynamic args) @@ -75,7 +73,7 @@ namespace RaceLapTimer.ApiControllers return Response.AsJson(_provider.GetPilot(pilotId)); } - private dynamic EditCreatePilot(dynamic args) + private dynamic EditCreatePilot() { var pilotObject = this.Bind(); var resp = _provider.CreatePilot(pilotObject); diff --git a/RaceLapTimer/RaceLapTimer/ApiControllers/RaceSessionApiModule.cs b/RaceLapTimer/RaceLapTimer/ApiControllers/RaceSessionApiModule.cs index abf0f28..12f7ce6 100644 --- a/RaceLapTimer/RaceLapTimer/ApiControllers/RaceSessionApiModule.cs +++ b/RaceLapTimer/RaceLapTimer/ApiControllers/RaceSessionApiModule.cs @@ -1,10 +1,8 @@ using System; -using System.Collections.Generic; using Interfaces; using Nancy; using Nancy.Extensions; using Nancy.ModelBinding; -using Nancy.Responses; namespace RaceLapTimer.ApiControllers { @@ -19,8 +17,16 @@ namespace RaceLapTimer.ApiControllers _notifier = notifierManager; Get[""] = args => GetRaceSessions(); - Post["/create"] = args => CreateRaceSession(args); + Post["/create"] = args => CreateRaceSession(); Get["/historic"] = args => GetHistoricRaceSessions(); + Delete["/historic/{id}"] = args => DeleteHistoricRaceSession(args); + } + + private dynamic DeleteHistoricRaceSession(dynamic args) + { + int raceSessionId = args.Id; + var res = _provider.DeleteRaceSession(raceSessionId); + return Context.GetRedirect("/history"); } private dynamic GetHistoricRaceSessions() @@ -35,7 +41,7 @@ namespace RaceLapTimer.ApiControllers return Response.AsJson(new { data = sessions }); } - private dynamic CreateRaceSession(dynamic args) + private dynamic CreateRaceSession() { var session = this.Bind(); var res = _provider.CreateRaceSession(session); diff --git a/RaceLapTimer/RaceLapTimer/ApiControllers/SatelliteApiModule.cs b/RaceLapTimer/RaceLapTimer/ApiControllers/SatelliteApiModule.cs index 27bc244..8f70c77 100644 --- a/RaceLapTimer/RaceLapTimer/ApiControllers/SatelliteApiModule.cs +++ b/RaceLapTimer/RaceLapTimer/ApiControllers/SatelliteApiModule.cs @@ -10,17 +10,17 @@ namespace RaceLapTimer.ApiControllers { _provider = provider; - Get[""] = args => LogNewLapSatelliteTime(args); + Get[""] = args => LogNewLapSatelliteTime(); } - private dynamic LogNewLapSatelliteTime(dynamic args) + private dynamic LogNewLapSatelliteTime() { var transponderToken = Convert.ToInt32(Request.Query["transponder_token"]); var lapTimeMs = Convert.ToInt32(Request.Query["lap_time_in_ms"]); var logObj = new SatelliteLog { TransponderToken = transponderToken, - LapTimeMS = lapTimeMs + LapTimeMs = lapTimeMs }; _provider.StoreTransponderLog(logObj); return HttpStatusCode.OK; @@ -30,6 +30,6 @@ namespace RaceLapTimer.ApiControllers public class SatelliteLog { public int TransponderToken { get; set; } - public int LapTimeMS { get; set; } + public int LapTimeMs { get; set; } } } diff --git a/RaceLapTimer/RaceLapTimer/ApiControllers/SoundApiModule.cs b/RaceLapTimer/RaceLapTimer/ApiControllers/SoundApiModule.cs index e179ea7..7176649 100644 --- a/RaceLapTimer/RaceLapTimer/ApiControllers/SoundApiModule.cs +++ b/RaceLapTimer/RaceLapTimer/ApiControllers/SoundApiModule.cs @@ -1,5 +1,4 @@ -using System.Web.Http; -using Nancy; +using Nancy; namespace RaceLapTimer.ApiControllers { diff --git a/RaceLapTimer/RaceLapTimer/ApiControllers/SystemApiModule.cs b/RaceLapTimer/RaceLapTimer/ApiControllers/SystemApiModule.cs index 028608d..4d1b496 100644 --- a/RaceLapTimer/RaceLapTimer/ApiControllers/SystemApiModule.cs +++ b/RaceLapTimer/RaceLapTimer/ApiControllers/SystemApiModule.cs @@ -1,18 +1,20 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Threading.Tasks; +using System.Reflection; +using Interfaces; using Nancy; namespace RaceLapTimer.ApiControllers { public class SystemApiModule : NancyModule { - public SystemApiModule() : base("/api/system") + private readonly ITransponderUtilityManager _transponderManager; + + public SystemApiModule(ITransponderUtilityManager transponderManager) + : base("/api/system") { + _transponderManager = transponderManager; + Get["info"] = args => GetSystemInfo(); + Get["lasttoken"] = args => GetLastToken(); } private dynamic GetSystemInfo() @@ -23,6 +25,11 @@ namespace RaceLapTimer.ApiControllers Version = Assembly.GetEntryAssembly().GetName().Version.ToString() }); } + + private dynamic GetLastToken() + { + return Response.AsJson(new { Id=_transponderManager.GetLastScannedId()}); + } } public class SystemInfo diff --git a/RaceLapTimer/RaceLapTimer/Helpers/AsyncHelpers.cs b/RaceLapTimer/RaceLapTimer/Assists/AsyncHelpers.cs similarity index 78% rename from RaceLapTimer/RaceLapTimer/Helpers/AsyncHelpers.cs rename to RaceLapTimer/RaceLapTimer/Assists/AsyncHelpers.cs index 46ce6ae..9f7e373 100644 --- a/RaceLapTimer/RaceLapTimer/Helpers/AsyncHelpers.cs +++ b/RaceLapTimer/RaceLapTimer/Assists/AsyncHelpers.cs @@ -1,18 +1,16 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; using System.Threading; using System.Threading.Tasks; -namespace RaceLapTimer.Helpers +namespace RaceLapTimer.Assists { public static class AsyncHelpers { /// - /// Execute's an async Task method which has a void return value synchronously + /// method which has a void return value synchronously]]> /// - /// Task method to execute + /// method to execute]]> public static void RunSync(Func task) { var oldContext = SynchronizationContext.Current; @@ -40,10 +38,10 @@ namespace RaceLapTimer.Helpers } /// - /// Execute's an async Task method which has a T return type synchronously + /// method which has a T return type synchronously]]> /// /// Return Type - /// Task method to execute + /// method to execute]]> /// public static T RunSync(Func> task) { @@ -74,10 +72,10 @@ namespace RaceLapTimer.Helpers private class ExclusiveSynchronizationContext : SynchronizationContext { - private bool done; + private bool _done; public Exception InnerException { get; set; } - readonly AutoResetEvent workItemsWaiting = new AutoResetEvent(false); - readonly Queue> items = + readonly AutoResetEvent _workItemsWaiting = new AutoResetEvent(false); + readonly Queue> _items = new Queue>(); public override void Send(SendOrPostCallback d, object state) @@ -87,28 +85,28 @@ namespace RaceLapTimer.Helpers public override void Post(SendOrPostCallback d, object state) { - lock (items) + lock (_items) { - items.Enqueue(Tuple.Create(d, state)); + _items.Enqueue(Tuple.Create(d, state)); } - workItemsWaiting.Set(); + _workItemsWaiting.Set(); } public void EndMessageLoop() { - Post(_ => done = true, null); + Post(_ => _done = true, null); } public void BeginMessageLoop() { - while (!done) + while (!_done) { Tuple task = null; - lock (items) + lock (_items) { - if (items.Count > 0) + if (_items.Count > 0) { - task = items.Dequeue(); + task = _items.Dequeue(); } } if (task != null) @@ -121,7 +119,7 @@ namespace RaceLapTimer.Helpers } else { - workItemsWaiting.WaitOne(); + _workItemsWaiting.WaitOne(); } } } diff --git a/RaceLapTimer/RaceLapTimer/AuthenticationBootstrapper.cs b/RaceLapTimer/RaceLapTimer/AuthenticationBootstrapper.cs index bcc9b4b..d159351 100644 --- a/RaceLapTimer/RaceLapTimer/AuthenticationBootstrapper.cs +++ b/RaceLapTimer/RaceLapTimer/AuthenticationBootstrapper.cs @@ -29,8 +29,8 @@ namespace RaceLapTimer // Configure things for a wider purpose, non-requestcontroller based. container.Bind().To(); container.Bind().To(); - container.Bind().To(); container.Bind().To(); + container.Bind().To(); container.Bind().To().InSingletonScope(); //load dynamic plugins..: var cfgFilePath = Path.Combine(container.Get().GetPath, "NinjectConfig.xml"); @@ -41,8 +41,8 @@ namespace RaceLapTimer container.Bind().To().InSingletonScope(); container.Bind().To().InSingletonScope(); - var tM = container.Get(); - tM.GetLastScannedId(); + var tu = container.Get(); + var id = tu.GetLastScannedId(); } protected override void ConfigureRequestContainer(IKernel container, NancyContext context) diff --git a/RaceLapTimer/RaceLapTimer/ConfigFilePathProvider.cs b/RaceLapTimer/RaceLapTimer/ConfigFilePathProvider.cs index 56714be..4005d55 100644 --- a/RaceLapTimer/RaceLapTimer/ConfigFilePathProvider.cs +++ b/RaceLapTimer/RaceLapTimer/ConfigFilePathProvider.cs @@ -1,10 +1,6 @@ using System; -using System.Collections.Generic; using System.IO; -using System.Linq; using System.Reflection; -using System.Text; -using System.Threading.Tasks; using Interfaces; namespace RaceLapTimer diff --git a/RaceLapTimer/RaceLapTimer/Extensions/Notifications/NotificationManager.cs b/RaceLapTimer/RaceLapTimer/Extensions/Notifications/NotificationManager.cs index 050fa77..228d2e1 100644 --- a/RaceLapTimer/RaceLapTimer/Extensions/Notifications/NotificationManager.cs +++ b/RaceLapTimer/RaceLapTimer/Extensions/Notifications/NotificationManager.cs @@ -77,19 +77,5 @@ namespace RaceLapTimer.Extensions.Notifications Task.Factory.StartNew(() => provider.NotifyRaceFinished(args)); } } - - private bool IsAssembly(string extension) - { - var validAssemblyExts = new List - { - "dll", "exe" - }; - var ext = extension.Remove(0, 1); - if (validAssemblyExts.Contains(ext)) - { - return true; - } - return false; - } } } diff --git a/RaceLapTimer/RaceLapTimer/Extensions/PluginLocator.cs b/RaceLapTimer/RaceLapTimer/Extensions/PluginLocator.cs index c4ac91c..762f725 100644 --- a/RaceLapTimer/RaceLapTimer/Extensions/PluginLocator.cs +++ b/RaceLapTimer/RaceLapTimer/Extensions/PluginLocator.cs @@ -1,10 +1,8 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; -using System.Text; using System.Threading.Tasks; using Interfaces; @@ -50,7 +48,6 @@ namespace RaceLapTimer.Extensions discoveryList.Add(new DiscoveredPlugin { FilePath = file, - PluginType = pluginTypes.First(), TypeToBindTo = typeof(T), UniqueName = Path.GetFileNameWithoutExtension(file) }); @@ -110,7 +107,6 @@ namespace RaceLapTimer.Extensions private class DiscoveredPlugin { public string FilePath { get; set; } - public Type PluginType { get; set; } public Type TypeToBindTo { get; set; } public string UniqueName { get; set; } } diff --git a/RaceLapTimer/RaceLapTimer/Extensions/SystemControl/SystemControlManager.cs b/RaceLapTimer/RaceLapTimer/Extensions/SystemControl/SystemControlManager.cs index 59e2b57..693f121 100644 --- a/RaceLapTimer/RaceLapTimer/Extensions/SystemControl/SystemControlManager.cs +++ b/RaceLapTimer/RaceLapTimer/Extensions/SystemControl/SystemControlManager.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; using System.Threading.Tasks; using Interfaces; @@ -9,7 +8,7 @@ namespace RaceLapTimer.Extensions.SystemControl { class SystemControlManager : ISystemControlManager { - private List _providers; + private List _providers; private readonly ILoggerService _logger; public SystemControlManager(IPluginLocator locator, ILoggerService logger) @@ -23,7 +22,7 @@ namespace RaceLapTimer.Extensions.SystemControl try { var providerFactories = locator.Locate(); - _providers = new List(); + _providers = new List(); foreach (var factory in providerFactories) { _providers.Add(factory.GetProvider()); diff --git a/RaceLapTimer/RaceLapTimer/Extensions/TransponderUtilities/TransponderUtilityManager.cs b/RaceLapTimer/RaceLapTimer/Extensions/TransponderUtilities/TransponderUtilityManager.cs index afc2f23..6f8e6f9 100644 --- a/RaceLapTimer/RaceLapTimer/Extensions/TransponderUtilities/TransponderUtilityManager.cs +++ b/RaceLapTimer/RaceLapTimer/Extensions/TransponderUtilities/TransponderUtilityManager.cs @@ -1,10 +1,8 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; using Interfaces; -using RaceLapTimer.Helpers; +using RaceLapTimer.Assists; namespace RaceLapTimer.Extensions.TransponderUtilities { diff --git a/RaceLapTimer/RaceLapTimer/IDbProvider.cs b/RaceLapTimer/RaceLapTimer/IDbProvider.cs index 51d9dcd..9e7cf26 100644 --- a/RaceLapTimer/RaceLapTimer/IDbProvider.cs +++ b/RaceLapTimer/RaceLapTimer/IDbProvider.cs @@ -12,6 +12,8 @@ namespace RaceLapTimer bool StopRaceSession(RaceSession session); + bool DeleteRaceSession(int raceSessionId); + List GetPilotsList(); Pilot GetPilot(int pilotId); diff --git a/RaceLapTimer/RaceLapTimer/Modules/HistoryModule.cs b/RaceLapTimer/RaceLapTimer/Modules/HistoryModule.cs index 192b73a..3d9ceee 100644 --- a/RaceLapTimer/RaceLapTimer/Modules/HistoryModule.cs +++ b/RaceLapTimer/RaceLapTimer/Modules/HistoryModule.cs @@ -1,8 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Nancy; namespace RaceLapTimer.Modules @@ -11,12 +7,12 @@ namespace RaceLapTimer.Modules { public HistoryModule():base("/history") { - Get[""] = args => GetHistoryHomePage(args); + Get[""] = args => GetHistoryHomePage(); } - private dynamic GetHistoryHomePage(dynamic args) + private dynamic GetHistoryHomePage() { - throw new NotImplementedException(); + return View["HistoryIndex.cshtml"]; } } } diff --git a/RaceLapTimer/RaceLapTimer/Modules/LoginModule.cs b/RaceLapTimer/RaceLapTimer/Modules/LoginModule.cs index 0ab633f..dc51567 100644 --- a/RaceLapTimer/RaceLapTimer/Modules/LoginModule.cs +++ b/RaceLapTimer/RaceLapTimer/Modules/LoginModule.cs @@ -1,9 +1,5 @@ using System; -using System.Collections.Generic; using System.Dynamic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Nancy; using Nancy.Authentication.Forms; using Nancy.Extensions; @@ -14,35 +10,35 @@ namespace RaceLapTimer.Modules { public LoginModule() { - Get["/login"] = args => GetLoginPage(args); + Get["/login"] = args => GetLoginPage(); - Post["/login"] = args => PostLoginAttempt(args); + Post["/login"] = args => PostLoginAttempt(); Get["/logout"] = args => { return this.LogoutAndRedirect("~/"); }; } - private dynamic GetLoginPage(dynamic args) + private dynamic GetLoginPage() { dynamic model = new ExpandoObject(); - model.Errored = this.Request.Query.error.HasValue; + model.Errored = Request.Query.error.HasValue; return View["login", model]; } - private dynamic PostLoginAttempt(dynamic args) + private dynamic PostLoginAttempt() { - var userGuid = UserDatabase.ValidateUser((string)this.Request.Form.Username, - (string)this.Request.Form.Password); + var userGuid = UserDatabase.ValidateUser((string)Request.Form.Username, + (string)Request.Form.Password); if (userGuid == null) { - return this.Context.GetRedirect("~/login?error=true&username=" + (string)this.Request.Form.Username); + return Context.GetRedirect("~/login?error=true&username=" + (string)Request.Form.Username); } DateTime? expiry = null; - if (this.Request.Form.RememberMe.HasValue) + if (Request.Form.RememberMe.HasValue) { expiry = DateTime.Now.AddDays(7); } diff --git a/RaceLapTimer/RaceLapTimer/Modules/MonitorModule.cs b/RaceLapTimer/RaceLapTimer/Modules/MonitorModule.cs index 7af6355..f5ccdbe 100644 --- a/RaceLapTimer/RaceLapTimer/Modules/MonitorModule.cs +++ b/RaceLapTimer/RaceLapTimer/Modules/MonitorModule.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Nancy; +using Nancy; namespace RaceLapTimer.Modules { @@ -11,11 +6,11 @@ namespace RaceLapTimer.Modules { public MonitorModule() { - Get[""] = args => GetMonitorHomePage(args); - Get["/monitor"] = args => GetMonitorHomePage(args); + Get[""] = args => GetMonitorHomePage(); + Get["/monitor"] = args => GetMonitorHomePage(); } - private dynamic GetMonitorHomePage(dynamic args) + private dynamic GetMonitorHomePage() { return View["Monitor.cshtml"]; } diff --git a/RaceLapTimer/RaceLapTimer/Modules/PilotModule.cs b/RaceLapTimer/RaceLapTimer/Modules/PilotModule.cs index 6435161..16e4b03 100644 --- a/RaceLapTimer/RaceLapTimer/Modules/PilotModule.cs +++ b/RaceLapTimer/RaceLapTimer/Modules/PilotModule.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Nancy; +using Nancy; using Nancy.Security; namespace RaceLapTimer.Modules diff --git a/RaceLapTimer/RaceLapTimer/Modules/PilotsModule.cs b/RaceLapTimer/RaceLapTimer/Modules/PilotsModule.cs index 349ad98..633075a 100644 --- a/RaceLapTimer/RaceLapTimer/Modules/PilotsModule.cs +++ b/RaceLapTimer/RaceLapTimer/Modules/PilotsModule.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Nancy; +using Nancy; namespace RaceLapTimer.Modules { @@ -11,10 +6,10 @@ namespace RaceLapTimer.Modules { public PilotsModule() : base("/pilots") { - Get[""] = args => GetPilotsListHomePage(args); + Get[""] = args => GetPilotsListHomePage(); } - private dynamic GetPilotsListHomePage(dynamic args) + private dynamic GetPilotsListHomePage() { return View["Pilots.cshtml"]; } diff --git a/RaceLapTimer/RaceLapTimer/Modules/RaceDirectorModule.cs b/RaceLapTimer/RaceLapTimer/Modules/RaceDirectorModule.cs index 616e550..eea5911 100644 --- a/RaceLapTimer/RaceLapTimer/Modules/RaceDirectorModule.cs +++ b/RaceLapTimer/RaceLapTimer/Modules/RaceDirectorModule.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Nancy; +using Nancy; using Nancy.Security; namespace RaceLapTimer.Modules @@ -14,11 +9,11 @@ namespace RaceLapTimer.Modules { this.RequiresAuthentication(); - Get[""] = args => GetRaceDirectoryHomePage(args); + Get[""] = args => GetRaceDirectoryHomePage(); //API METHOD - Get["lapTimes"] } - private dynamic GetRaceDirectoryHomePage(dynamic args) + private dynamic GetRaceDirectoryHomePage() { return View["RaceDirector.cshtml"]; } diff --git a/RaceLapTimer/RaceLapTimer/Modules/SoundfileModule.cs b/RaceLapTimer/RaceLapTimer/Modules/SoundfileModule.cs index e7f49b1..fcb3369 100644 --- a/RaceLapTimer/RaceLapTimer/Modules/SoundfileModule.cs +++ b/RaceLapTimer/RaceLapTimer/Modules/SoundfileModule.cs @@ -1,14 +1,10 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Nancy; using Nancy.Security; namespace RaceLapTimer.Modules { - public class SoundfileModule:NancyModule + public class SoundfileModule : NancyModule { public SoundfileModule() : base("/soundfile") { diff --git a/RaceLapTimer/RaceLapTimer/Modules/SystemModule.cs b/RaceLapTimer/RaceLapTimer/Modules/SystemModule.cs index 5172474..434090f 100644 --- a/RaceLapTimer/RaceLapTimer/Modules/SystemModule.cs +++ b/RaceLapTimer/RaceLapTimer/Modules/SystemModule.cs @@ -1,8 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Nancy; using Nancy.Security; @@ -29,7 +25,7 @@ namespace RaceLapTimer.Modules //this will return system configuration settings home page. private dynamic GetSystemHomePage(dynamic args) { - throw new NotImplementedException(); + return View["SystemIndex.cshtml"]; } //system/pilot/create //api method diff --git a/RaceLapTimer/RaceLapTimer/Modules/UserModule.cs b/RaceLapTimer/RaceLapTimer/Modules/UserModule.cs index f279162..466ae61 100644 --- a/RaceLapTimer/RaceLapTimer/Modules/UserModule.cs +++ b/RaceLapTimer/RaceLapTimer/Modules/UserModule.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Nancy; +using Nancy; namespace RaceLapTimer.Modules { diff --git a/RaceLapTimer/RaceLapTimer/Program.cs b/RaceLapTimer/RaceLapTimer/Program.cs index ef7f795..c920de8 100644 --- a/RaceLapTimer/RaceLapTimer/Program.cs +++ b/RaceLapTimer/RaceLapTimer/Program.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.ServiceProcess; -using System.Text; -using System.Threading.Tasks; +using System.ServiceProcess; namespace RaceLapTimer { @@ -14,12 +9,12 @@ namespace RaceLapTimer /// static void Main() { - ServiceBase[] ServicesToRun; - ServicesToRun = new ServiceBase[] + ServiceBase[] servicesToRun; + servicesToRun = new ServiceBase[] { new RaceLapTimer() }; - ServiceBase.Run(ServicesToRun); + ServiceBase.Run(servicesToRun); } } } diff --git a/RaceLapTimer/RaceLapTimer/Properties/AssemblyInfo.cs b/RaceLapTimer/RaceLapTimer/Properties/AssemblyInfo.cs index 5de4411..40346e3 100644 --- a/RaceLapTimer/RaceLapTimer/Properties/AssemblyInfo.cs +++ b/RaceLapTimer/RaceLapTimer/Properties/AssemblyInfo.cs @@ -1,5 +1,4 @@ using System.Reflection; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following diff --git a/RaceLapTimer/RaceLapTimer/RaceLapTimer.csproj b/RaceLapTimer/RaceLapTimer/RaceLapTimer.csproj index 9fe1759..0e1115b 100644 --- a/RaceLapTimer/RaceLapTimer/RaceLapTimer.csproj +++ b/RaceLapTimer/RaceLapTimer/RaceLapTimer.csproj @@ -117,6 +117,7 @@ + @@ -166,6 +167,9 @@ Always + + Always + Always @@ -187,6 +191,7 @@ Always + @@ -222,6 +227,12 @@ + + Always + + + Always + Always @@ -229,6 +240,9 @@ Always + + Always + Always diff --git a/RaceLapTimer/RaceLapTimer/TestProvider.cs b/RaceLapTimer/RaceLapTimer/TestProvider.cs index a89ca43..9f6f17a 100644 --- a/RaceLapTimer/RaceLapTimer/TestProvider.cs +++ b/RaceLapTimer/RaceLapTimer/TestProvider.cs @@ -83,7 +83,7 @@ namespace RaceLapTimer Title = "TEST Session 3" }, #endregion - #region Session 3 + #region Session 4 new RaceSession { Active = false, @@ -96,8 +96,23 @@ namespace RaceLapTimer SatelliteCount = 1, TimePenaltyPerSatellite = 100, Title = "TEST Session 4" - } + }, #endregion + #region Session 5 + new RaceSession + { + Active = false, + CreatedAt = DateTime.UtcNow, + HotSeatEnabled = false, + Id = 4, + IdleTimeSeconds = 400, + Mode = RaceMode.STANDARD, + MaxLaps = 10, + SatelliteCount = 1, + TimePenaltyPerSatellite = 100, + Title = "TEST Session 4" + } + #endregion }; #endregion } @@ -129,6 +144,16 @@ namespace RaceLapTimer return true; } + public bool DeleteRaceSession(int sessionId) + { + if (_sessions.All(x => x.Id != sessionId)) + { + return false; + } + var session = _sessions.Find(x => x.Id == sessionId); + return _sessions.Remove(session); + } + public List GetPilotsList() { return _pilots; diff --git a/RaceLapTimer/RaceLapTimer/UserDatabase.cs b/RaceLapTimer/RaceLapTimer/UserDatabase.cs index 75037d1..107d2f1 100644 --- a/RaceLapTimer/RaceLapTimer/UserDatabase.cs +++ b/RaceLapTimer/RaceLapTimer/UserDatabase.cs @@ -1,9 +1,6 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; -using System.Text; -using System.Threading.Tasks; using Interfaces; using Nancy; using Nancy.Authentication.Forms; @@ -13,14 +10,14 @@ namespace RaceLapTimer { public class UserDatabase : IUserMapper { - private static List> users = new List>(); + private static List> _users = new List>(); private IUserStorage _storage; public UserDatabase(IUserStorage storage) { _storage = storage; - users.Add(new Tuple("admin", "password", new Guid("55E1E49E-B7E8-4EEA-8459-7A906AC4D4C0"))); - users.Add(new Tuple("user", "password", new Guid("56E1E49E-B7E8-4EEA-8459-7A906AC4D4C0"))); + _users.Add(new Tuple("admin", "password", new Guid("55E1E49E-B7E8-4EEA-8459-7A906AC4D4C0"))); + _users.Add(new Tuple("user", "password", new Guid("56E1E49E-B7E8-4EEA-8459-7A906AC4D4C0"))); } /// @@ -31,7 +28,7 @@ namespace RaceLapTimer /// public IUserIdentity GetUserFromIdentifier(Guid identifier, NancyContext context) { - var userRecord = users.FirstOrDefault(u => u.Item3 == identifier); + var userRecord = _users.FirstOrDefault(u => u.Item3 == identifier); return userRecord == null ? null : new NancyUser(userRecord.Item1); @@ -51,7 +48,7 @@ namespace RaceLapTimer pwHash = Helpers.Encryption.Hash.HashString(password); } - var userRecord = users.FirstOrDefault(u => u.Item1 == username && u.Item2 == password); + var userRecord = _users.FirstOrDefault(u => u.Item1 == username && u.Item2 == password); return userRecord?.Item3; } diff --git a/RaceLapTimer/RaceLapTimer/www/Views/HistoryIndex.cshtml b/RaceLapTimer/RaceLapTimer/www/Views/HistoryIndex.cshtml new file mode 100644 index 0000000..61209b5 --- /dev/null +++ b/RaceLapTimer/RaceLapTimer/www/Views/HistoryIndex.cshtml @@ -0,0 +1,61 @@ +@inherits Nancy.ViewEngines.Razor.NancyRazorViewBase +@{ + Layout = "razor-layout.cshtml"; + ViewBag.Title = "History"; +} +

@ViewBag.Title

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
SessionModePilots
June 16, 2017 19:07Race Name 1standard5 + + +
+

Race Information

+
+ + + + + + + + + + + + + + + + + +
Total LapsFastest LapFastest PilotAverage Lap Time
1230.0sa pilot35.0s
+
+
+ + + \ No newline at end of file diff --git a/RaceLapTimer/RaceLapTimer/www/Views/RaceDirector.cshtml b/RaceLapTimer/RaceLapTimer/www/Views/RaceDirector.cshtml index 685f107..a250408 100644 --- a/RaceLapTimer/RaceLapTimer/www/Views/RaceDirector.cshtml +++ b/RaceLapTimer/RaceLapTimer/www/Views/RaceDirector.cshtml @@ -7,7 +7,7 @@

@ViewBag.Title

Last Scanned Id

- +

Current Race

@@ -50,5 +50,6 @@ + \ No newline at end of file diff --git a/RaceLapTimer/RaceLapTimer/www/Views/SystemIndex.cshtml b/RaceLapTimer/RaceLapTimer/www/Views/SystemIndex.cshtml new file mode 100644 index 0000000..4f30dcc --- /dev/null +++ b/RaceLapTimer/RaceLapTimer/www/Views/SystemIndex.cshtml @@ -0,0 +1,6 @@ +@inherits Nancy.ViewEngines.Razor.NancyRazorViewBase +@{ + Layout = "razor-layout.cshtml"; + ViewBag.Title = "Pilots"; + ViewBag.CreateUserEndpoint = "/api/pilot/create"; +} diff --git a/RaceLapTimer/RaceLapTimer/www/js/LastScannedId.js b/RaceLapTimer/RaceLapTimer/www/js/LastScannedId.js new file mode 100644 index 0000000..2505fda --- /dev/null +++ b/RaceLapTimer/RaceLapTimer/www/js/LastScannedId.js @@ -0,0 +1,4 @@ +function LastScannedId(data) { + var self = this; + self.id = ko.observable(data.id); +} \ No newline at end of file diff --git a/RaceLapTimer/RaceLapTimer/www/js/RaceSessionObject.js b/RaceLapTimer/RaceLapTimer/www/js/RaceSessionObject.js index 4466bde..5c557ff 100644 --- a/RaceLapTimer/RaceLapTimer/www/js/RaceSessionObject.js +++ b/RaceLapTimer/RaceLapTimer/www/js/RaceSessionObject.js @@ -1,7 +1,10 @@ function RaceSession(data) { var self = this; self.id = ko.observable(data.id); - self.createdDate = ko.observable(data.createdDate); + self.createdAt = ko.observable(data.createdAt); + self.createdDate = ko.computed(function () { + return new moment(self.createdAt()).format("MMMM Do YYYY, HH:mm"); + }, self); self.updatedAt = ko.observable(data.updatedAt); self.title = ko.observable(data.title); self.active = ko.observable(data.active); diff --git a/RaceLapTimer/RaceLapTimer/www/js/moment.min.js b/RaceLapTimer/RaceLapTimer/www/js/moment.min.js new file mode 100644 index 0000000..770f8bc --- /dev/null +++ b/RaceLapTimer/RaceLapTimer/www/js/moment.min.js @@ -0,0 +1,7 @@ +//! moment.js +//! version : 2.18.1 +//! authors : Tim Wood, Iskren Chernev, Moment.js contributors +//! license : MIT +//! momentjs.com +!function(a,b){"object"==typeof exports&&"undefined"!=typeof module?module.exports=b():"function"==typeof define&&define.amd?define(b):a.moment=b()}(this,function(){"use strict";function a(){return sd.apply(null,arguments)}function b(a){sd=a}function c(a){return a instanceof Array||"[object Array]"===Object.prototype.toString.call(a)}function d(a){return null!=a&&"[object Object]"===Object.prototype.toString.call(a)}function e(a){var b;for(b in a)return!1;return!0}function f(a){return void 0===a}function g(a){return"number"==typeof a||"[object Number]"===Object.prototype.toString.call(a)}function h(a){return a instanceof Date||"[object Date]"===Object.prototype.toString.call(a)}function i(a,b){var c,d=[];for(c=0;c0)for(c=0;c0?"future":"past"];return z(c)?c(b):c.replace(/%s/i,b)}function J(a,b){var c=a.toLowerCase();Hd[c]=Hd[c+"s"]=Hd[b]=a}function K(a){return"string"==typeof a?Hd[a]||Hd[a.toLowerCase()]:void 0}function L(a){var b,c,d={};for(c in a)j(a,c)&&(b=K(c),b&&(d[b]=a[c]));return d}function M(a,b){Id[a]=b}function N(a){var b=[];for(var c in a)b.push({unit:c,priority:Id[c]});return b.sort(function(a,b){return a.priority-b.priority}),b}function O(b,c){return function(d){return null!=d?(Q(this,b,d),a.updateOffset(this,c),this):P(this,b)}}function P(a,b){return a.isValid()?a._d["get"+(a._isUTC?"UTC":"")+b]():NaN}function Q(a,b,c){a.isValid()&&a._d["set"+(a._isUTC?"UTC":"")+b](c)}function R(a){return a=K(a),z(this[a])?this[a]():this}function S(a,b){if("object"==typeof a){a=L(a);for(var c=N(a),d=0;d=0;return(f?c?"+":"":"-")+Math.pow(10,Math.max(0,e)).toString().substr(1)+d}function U(a,b,c,d){var e=d;"string"==typeof d&&(e=function(){return this[d]()}),a&&(Md[a]=e),b&&(Md[b[0]]=function(){return T(e.apply(this,arguments),b[1],b[2])}),c&&(Md[c]=function(){return this.localeData().ordinal(e.apply(this,arguments),a)})}function V(a){return a.match(/\[[\s\S]/)?a.replace(/^\[|\]$/g,""):a.replace(/\\/g,"")}function W(a){var b,c,d=a.match(Jd);for(b=0,c=d.length;b=0&&Kd.test(a);)a=a.replace(Kd,c),Kd.lastIndex=0,d-=1;return a}function Z(a,b,c){ce[a]=z(b)?b:function(a,d){return a&&c?c:b}}function $(a,b){return j(ce,a)?ce[a](b._strict,b._locale):new RegExp(_(a))}function _(a){return aa(a.replace("\\","").replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(a,b,c,d,e){return b||c||d||e}))}function aa(a){return a.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}function ba(a,b){var c,d=b;for("string"==typeof a&&(a=[a]),g(b)&&(d=function(a,c){c[b]=u(a)}),c=0;c=0&&isFinite(h.getFullYear())&&h.setFullYear(a),h}function ta(a){var b=new Date(Date.UTC.apply(null,arguments));return a<100&&a>=0&&isFinite(b.getUTCFullYear())&&b.setUTCFullYear(a),b}function ua(a,b,c){var d=7+b-c,e=(7+ta(a,0,d).getUTCDay()-b)%7;return-e+d-1}function va(a,b,c,d,e){var f,g,h=(7+c-d)%7,i=ua(a,d,e),j=1+7*(b-1)+h+i;return j<=0?(f=a-1,g=pa(f)+j):j>pa(a)?(f=a+1,g=j-pa(a)):(f=a,g=j),{year:f,dayOfYear:g}}function wa(a,b,c){var d,e,f=ua(a.year(),b,c),g=Math.floor((a.dayOfYear()-f-1)/7)+1;return g<1?(e=a.year()-1,d=g+xa(e,b,c)):g>xa(a.year(),b,c)?(d=g-xa(a.year(),b,c),e=a.year()+1):(e=a.year(),d=g),{week:d,year:e}}function xa(a,b,c){var d=ua(a,b,c),e=ua(a+1,b,c);return(pa(a)-d+e)/7}function ya(a){return wa(a,this._week.dow,this._week.doy).week}function za(){return this._week.dow}function Aa(){return this._week.doy}function Ba(a){var b=this.localeData().week(this);return null==a?b:this.add(7*(a-b),"d")}function Ca(a){var b=wa(this,1,4).week;return null==a?b:this.add(7*(a-b),"d")}function Da(a,b){return"string"!=typeof a?a:isNaN(a)?(a=b.weekdaysParse(a),"number"==typeof a?a:null):parseInt(a,10)}function Ea(a,b){return"string"==typeof a?b.weekdaysParse(a)%7||7:isNaN(a)?null:a}function Fa(a,b){return a?c(this._weekdays)?this._weekdays[a.day()]:this._weekdays[this._weekdays.isFormat.test(b)?"format":"standalone"][a.day()]:c(this._weekdays)?this._weekdays:this._weekdays.standalone}function Ga(a){return a?this._weekdaysShort[a.day()]:this._weekdaysShort}function Ha(a){return a?this._weekdaysMin[a.day()]:this._weekdaysMin}function Ia(a,b,c){var d,e,f,g=a.toLocaleLowerCase();if(!this._weekdaysParse)for(this._weekdaysParse=[],this._shortWeekdaysParse=[],this._minWeekdaysParse=[],d=0;d<7;++d)f=l([2e3,1]).day(d),this._minWeekdaysParse[d]=this.weekdaysMin(f,"").toLocaleLowerCase(),this._shortWeekdaysParse[d]=this.weekdaysShort(f,"").toLocaleLowerCase(),this._weekdaysParse[d]=this.weekdays(f,"").toLocaleLowerCase();return c?"dddd"===b?(e=ne.call(this._weekdaysParse,g),e!==-1?e:null):"ddd"===b?(e=ne.call(this._shortWeekdaysParse,g),e!==-1?e:null):(e=ne.call(this._minWeekdaysParse,g),e!==-1?e:null):"dddd"===b?(e=ne.call(this._weekdaysParse,g),e!==-1?e:(e=ne.call(this._shortWeekdaysParse,g),e!==-1?e:(e=ne.call(this._minWeekdaysParse,g),e!==-1?e:null))):"ddd"===b?(e=ne.call(this._shortWeekdaysParse,g),e!==-1?e:(e=ne.call(this._weekdaysParse,g),e!==-1?e:(e=ne.call(this._minWeekdaysParse,g),e!==-1?e:null))):(e=ne.call(this._minWeekdaysParse,g),e!==-1?e:(e=ne.call(this._weekdaysParse,g),e!==-1?e:(e=ne.call(this._shortWeekdaysParse,g),e!==-1?e:null)))}function Ja(a,b,c){var d,e,f;if(this._weekdaysParseExact)return Ia.call(this,a,b,c);for(this._weekdaysParse||(this._weekdaysParse=[],this._minWeekdaysParse=[],this._shortWeekdaysParse=[],this._fullWeekdaysParse=[]),d=0;d<7;d++){if(e=l([2e3,1]).day(d),c&&!this._fullWeekdaysParse[d]&&(this._fullWeekdaysParse[d]=new RegExp("^"+this.weekdays(e,"").replace(".",".?")+"$","i"),this._shortWeekdaysParse[d]=new RegExp("^"+this.weekdaysShort(e,"").replace(".",".?")+"$","i"),this._minWeekdaysParse[d]=new RegExp("^"+this.weekdaysMin(e,"").replace(".",".?")+"$","i")),this._weekdaysParse[d]||(f="^"+this.weekdays(e,"")+"|^"+this.weekdaysShort(e,"")+"|^"+this.weekdaysMin(e,""),this._weekdaysParse[d]=new RegExp(f.replace(".",""),"i")),c&&"dddd"===b&&this._fullWeekdaysParse[d].test(a))return d;if(c&&"ddd"===b&&this._shortWeekdaysParse[d].test(a))return d;if(c&&"dd"===b&&this._minWeekdaysParse[d].test(a))return d;if(!c&&this._weekdaysParse[d].test(a))return d}}function Ka(a){if(!this.isValid())return null!=a?this:NaN;var b=this._isUTC?this._d.getUTCDay():this._d.getDay();return null!=a?(a=Da(a,this.localeData()),this.add(a-b,"d")):b}function La(a){if(!this.isValid())return null!=a?this:NaN;var b=(this.day()+7-this.localeData()._week.dow)%7;return null==a?b:this.add(a-b,"d")}function Ma(a){if(!this.isValid())return null!=a?this:NaN;if(null!=a){var b=Ea(a,this.localeData());return this.day(this.day()%7?b:b-7)}return this.day()||7}function Na(a){return this._weekdaysParseExact?(j(this,"_weekdaysRegex")||Qa.call(this),a?this._weekdaysStrictRegex:this._weekdaysRegex):(j(this,"_weekdaysRegex")||(this._weekdaysRegex=ye),this._weekdaysStrictRegex&&a?this._weekdaysStrictRegex:this._weekdaysRegex)}function Oa(a){return this._weekdaysParseExact?(j(this,"_weekdaysRegex")||Qa.call(this),a?this._weekdaysShortStrictRegex:this._weekdaysShortRegex):(j(this,"_weekdaysShortRegex")||(this._weekdaysShortRegex=ze),this._weekdaysShortStrictRegex&&a?this._weekdaysShortStrictRegex:this._weekdaysShortRegex)}function Pa(a){return this._weekdaysParseExact?(j(this,"_weekdaysRegex")||Qa.call(this),a?this._weekdaysMinStrictRegex:this._weekdaysMinRegex):(j(this,"_weekdaysMinRegex")||(this._weekdaysMinRegex=Ae),this._weekdaysMinStrictRegex&&a?this._weekdaysMinStrictRegex:this._weekdaysMinRegex)}function Qa(){function a(a,b){return b.length-a.length}var b,c,d,e,f,g=[],h=[],i=[],j=[];for(b=0;b<7;b++)c=l([2e3,1]).day(b),d=this.weekdaysMin(c,""),e=this.weekdaysShort(c,""),f=this.weekdays(c,""),g.push(d),h.push(e),i.push(f),j.push(d),j.push(e),j.push(f);for(g.sort(a),h.sort(a),i.sort(a),j.sort(a),b=0;b<7;b++)h[b]=aa(h[b]),i[b]=aa(i[b]),j[b]=aa(j[b]);this._weekdaysRegex=new RegExp("^("+j.join("|")+")","i"),this._weekdaysShortRegex=this._weekdaysRegex,this._weekdaysMinRegex=this._weekdaysRegex,this._weekdaysStrictRegex=new RegExp("^("+i.join("|")+")","i"),this._weekdaysShortStrictRegex=new RegExp("^("+h.join("|")+")","i"),this._weekdaysMinStrictRegex=new RegExp("^("+g.join("|")+")","i")}function Ra(){return this.hours()%12||12}function Sa(){return this.hours()||24}function Ta(a,b){U(a,0,0,function(){return this.localeData().meridiem(this.hours(),this.minutes(),b)})}function Ua(a,b){return b._meridiemParse}function Va(a){return"p"===(a+"").toLowerCase().charAt(0)}function Wa(a,b,c){return a>11?c?"pm":"PM":c?"am":"AM"}function Xa(a){return a?a.toLowerCase().replace("_","-"):a}function Ya(a){for(var b,c,d,e,f=0;f0;){if(d=Za(e.slice(0,b).join("-")))return d;if(c&&c.length>=b&&v(e,c,!0)>=b-1)break;b--}f++}return null}function Za(a){var b=null;if(!Fe[a]&&"undefined"!=typeof module&&module&&module.exports)try{b=Be._abbr,require("./locale/"+a),$a(b)}catch(a){}return Fe[a]}function $a(a,b){var c;return a&&(c=f(b)?bb(a):_a(a,b),c&&(Be=c)),Be._abbr}function _a(a,b){if(null!==b){var c=Ee;if(b.abbr=a,null!=Fe[a])y("defineLocaleOverride","use moment.updateLocale(localeName, config) to change an existing locale. moment.defineLocale(localeName, config) should only be used for creating a new locale See http://momentjs.com/guides/#/warnings/define-locale/ for more info."),c=Fe[a]._config;else if(null!=b.parentLocale){if(null==Fe[b.parentLocale])return Ge[b.parentLocale]||(Ge[b.parentLocale]=[]),Ge[b.parentLocale].push({name:a,config:b}),null;c=Fe[b.parentLocale]._config}return Fe[a]=new C(B(c,b)),Ge[a]&&Ge[a].forEach(function(a){_a(a.name,a.config)}),$a(a),Fe[a]}return delete Fe[a],null}function ab(a,b){if(null!=b){var c,d=Ee;null!=Fe[a]&&(d=Fe[a]._config),b=B(d,b),c=new C(b),c.parentLocale=Fe[a],Fe[a]=c,$a(a)}else null!=Fe[a]&&(null!=Fe[a].parentLocale?Fe[a]=Fe[a].parentLocale:null!=Fe[a]&&delete Fe[a]);return Fe[a]}function bb(a){var b;if(a&&a._locale&&a._locale._abbr&&(a=a._locale._abbr),!a)return Be;if(!c(a)){if(b=Za(a))return b;a=[a]}return Ya(a)}function cb(){return Ad(Fe)}function db(a){var b,c=a._a;return c&&n(a).overflow===-2&&(b=c[fe]<0||c[fe]>11?fe:c[ge]<1||c[ge]>ea(c[ee],c[fe])?ge:c[he]<0||c[he]>24||24===c[he]&&(0!==c[ie]||0!==c[je]||0!==c[ke])?he:c[ie]<0||c[ie]>59?ie:c[je]<0||c[je]>59?je:c[ke]<0||c[ke]>999?ke:-1,n(a)._overflowDayOfYear&&(bge)&&(b=ge),n(a)._overflowWeeks&&b===-1&&(b=le),n(a)._overflowWeekday&&b===-1&&(b=me),n(a).overflow=b),a}function eb(a){var b,c,d,e,f,g,h=a._i,i=He.exec(h)||Ie.exec(h);if(i){for(n(a).iso=!0,b=0,c=Ke.length;b10?"YYYY ":"YY "),f="HH:mm"+(c[4]?":ss":""),c[1]){var l=new Date(c[2]),m=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"][l.getDay()];if(c[1].substr(0,3)!==m)return n(a).weekdayMismatch=!0,void(a._isValid=!1)}switch(c[5].length){case 2:0===i?h=" +0000":(i=k.indexOf(c[5][1].toUpperCase())-12,h=(i<0?" -":" +")+(""+i).replace(/^-?/,"0").match(/..$/)[0]+"00");break;case 4:h=j[c[5]];break;default:h=j[" GMT"]}c[5]=h,a._i=c.splice(1).join(""),g=" ZZ",a._f=d+e+f+g,lb(a),n(a).rfc2822=!0}else a._isValid=!1}function gb(b){var c=Me.exec(b._i);return null!==c?void(b._d=new Date(+c[1])):(eb(b),void(b._isValid===!1&&(delete b._isValid,fb(b),b._isValid===!1&&(delete b._isValid,a.createFromInputFallback(b)))))}function hb(a,b,c){return null!=a?a:null!=b?b:c}function ib(b){var c=new Date(a.now());return b._useUTC?[c.getUTCFullYear(),c.getUTCMonth(),c.getUTCDate()]:[c.getFullYear(),c.getMonth(),c.getDate()]}function jb(a){var b,c,d,e,f=[];if(!a._d){for(d=ib(a),a._w&&null==a._a[ge]&&null==a._a[fe]&&kb(a),null!=a._dayOfYear&&(e=hb(a._a[ee],d[ee]),(a._dayOfYear>pa(e)||0===a._dayOfYear)&&(n(a)._overflowDayOfYear=!0),c=ta(e,0,a._dayOfYear),a._a[fe]=c.getUTCMonth(),a._a[ge]=c.getUTCDate()),b=0;b<3&&null==a._a[b];++b)a._a[b]=f[b]=d[b];for(;b<7;b++)a._a[b]=f[b]=null==a._a[b]?2===b?1:0:a._a[b];24===a._a[he]&&0===a._a[ie]&&0===a._a[je]&&0===a._a[ke]&&(a._nextDay=!0,a._a[he]=0),a._d=(a._useUTC?ta:sa).apply(null,f),null!=a._tzm&&a._d.setUTCMinutes(a._d.getUTCMinutes()-a._tzm),a._nextDay&&(a._a[he]=24)}}function kb(a){var b,c,d,e,f,g,h,i;if(b=a._w,null!=b.GG||null!=b.W||null!=b.E)f=1,g=4,c=hb(b.GG,a._a[ee],wa(tb(),1,4).year),d=hb(b.W,1),e=hb(b.E,1),(e<1||e>7)&&(i=!0);else{f=a._locale._week.dow,g=a._locale._week.doy;var j=wa(tb(),f,g);c=hb(b.gg,a._a[ee],j.year),d=hb(b.w,j.week),null!=b.d?(e=b.d,(e<0||e>6)&&(i=!0)):null!=b.e?(e=b.e+f,(b.e<0||b.e>6)&&(i=!0)):e=f}d<1||d>xa(c,f,g)?n(a)._overflowWeeks=!0:null!=i?n(a)._overflowWeekday=!0:(h=va(c,d,e,f,g),a._a[ee]=h.year,a._dayOfYear=h.dayOfYear)}function lb(b){if(b._f===a.ISO_8601)return void eb(b);if(b._f===a.RFC_2822)return void fb(b);b._a=[],n(b).empty=!0;var c,d,e,f,g,h=""+b._i,i=h.length,j=0;for(e=Y(b._f,b._locale).match(Jd)||[],c=0;c0&&n(b).unusedInput.push(g),h=h.slice(h.indexOf(d)+d.length),j+=d.length),Md[f]?(d?n(b).empty=!1:n(b).unusedTokens.push(f),da(f,d,b)):b._strict&&!d&&n(b).unusedTokens.push(f);n(b).charsLeftOver=i-j,h.length>0&&n(b).unusedInput.push(h),b._a[he]<=12&&n(b).bigHour===!0&&b._a[he]>0&&(n(b).bigHour=void 0),n(b).parsedDateParts=b._a.slice(0),n(b).meridiem=b._meridiem,b._a[he]=mb(b._locale,b._a[he],b._meridiem),jb(b),db(b)}function mb(a,b,c){var d;return null==c?b:null!=a.meridiemHour?a.meridiemHour(b,c):null!=a.isPM?(d=a.isPM(c),d&&b<12&&(b+=12),d||12!==b||(b=0),b):b}function nb(a){var b,c,d,e,f;if(0===a._f.length)return n(a).invalidFormat=!0,void(a._d=new Date(NaN));for(e=0;ethis.clone().month(0).utcOffset()||this.utcOffset()>this.clone().month(5).utcOffset()}function Ob(){if(!f(this._isDSTShifted))return this._isDSTShifted;var a={};if(q(a,this),a=qb(a),a._a){var b=a._isUTC?l(a._a):tb(a._a);this._isDSTShifted=this.isValid()&&v(a._a,b.toArray())>0}else this._isDSTShifted=!1;return this._isDSTShifted}function Pb(){return!!this.isValid()&&!this._isUTC}function Qb(){return!!this.isValid()&&this._isUTC}function Rb(){return!!this.isValid()&&(this._isUTC&&0===this._offset)}function Sb(a,b){var c,d,e,f=a,h=null;return Bb(a)?f={ms:a._milliseconds,d:a._days,M:a._months}:g(a)?(f={},b?f[b]=a:f.milliseconds=a):(h=Te.exec(a))?(c="-"===h[1]?-1:1,f={y:0,d:u(h[ge])*c,h:u(h[he])*c,m:u(h[ie])*c,s:u(h[je])*c,ms:u(Cb(1e3*h[ke]))*c}):(h=Ue.exec(a))?(c="-"===h[1]?-1:1,f={y:Tb(h[2],c),M:Tb(h[3],c),w:Tb(h[4],c),d:Tb(h[5],c),h:Tb(h[6],c),m:Tb(h[7],c),s:Tb(h[8],c)}):null==f?f={}:"object"==typeof f&&("from"in f||"to"in f)&&(e=Vb(tb(f.from),tb(f.to)),f={},f.ms=e.milliseconds,f.M=e.months),d=new Ab(f),Bb(a)&&j(a,"_locale")&&(d._locale=a._locale),d}function Tb(a,b){var c=a&&parseFloat(a.replace(",","."));return(isNaN(c)?0:c)*b}function Ub(a,b){var c={milliseconds:0,months:0};return c.months=b.month()-a.month()+12*(b.year()-a.year()),a.clone().add(c.months,"M").isAfter(b)&&--c.months,c.milliseconds=+b-+a.clone().add(c.months,"M"),c}function Vb(a,b){var c;return a.isValid()&&b.isValid()?(b=Fb(b,a),a.isBefore(b)?c=Ub(a,b):(c=Ub(b,a),c.milliseconds=-c.milliseconds,c.months=-c.months),c):{milliseconds:0,months:0}}function Wb(a,b){return function(c,d){var e,f;return null===d||isNaN(+d)||(y(b,"moment()."+b+"(period, number) is deprecated. Please use moment()."+b+"(number, period). See http://momentjs.com/guides/#/warnings/add-inverted-param/ for more info."),f=c,c=d,d=f),c="string"==typeof c?+c:c,e=Sb(c,d),Xb(this,e,a),this}}function Xb(b,c,d,e){var f=c._milliseconds,g=Cb(c._days),h=Cb(c._months);b.isValid()&&(e=null==e||e,f&&b._d.setTime(b._d.valueOf()+f*d),g&&Q(b,"Date",P(b,"Date")+g*d),h&&ja(b,P(b,"Month")+h*d),e&&a.updateOffset(b,g||h))}function Yb(a,b){var c=a.diff(b,"days",!0);return c<-6?"sameElse":c<-1?"lastWeek":c<0?"lastDay":c<1?"sameDay":c<2?"nextDay":c<7?"nextWeek":"sameElse"}function Zb(b,c){var d=b||tb(),e=Fb(d,this).startOf("day"),f=a.calendarFormat(this,e)||"sameElse",g=c&&(z(c[f])?c[f].call(this,d):c[f]);return this.format(g||this.localeData().calendar(f,this,tb(d)))}function $b(){return new r(this)}function _b(a,b){var c=s(a)?a:tb(a);return!(!this.isValid()||!c.isValid())&&(b=K(f(b)?"millisecond":b),"millisecond"===b?this.valueOf()>c.valueOf():c.valueOf()9999?X(a,"YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]"):z(Date.prototype.toISOString)?this.toDate().toISOString():X(a,"YYYY-MM-DD[T]HH:mm:ss.SSS[Z]")}function jc(){if(!this.isValid())return"moment.invalid(/* "+this._i+" */)";var a="moment",b="";this.isLocal()||(a=0===this.utcOffset()?"moment.utc":"moment.parseZone",b="Z");var c="["+a+'("]',d=0<=this.year()&&this.year()<=9999?"YYYY":"YYYYYY",e="-MM-DD[T]HH:mm:ss.SSS",f=b+'[")]';return this.format(c+d+e+f)}function kc(b){b||(b=this.isUtc()?a.defaultFormatUtc:a.defaultFormat);var c=X(this,b);return this.localeData().postformat(c)}function lc(a,b){return this.isValid()&&(s(a)&&a.isValid()||tb(a).isValid())?Sb({to:this,from:a}).locale(this.locale()).humanize(!b):this.localeData().invalidDate()}function mc(a){return this.from(tb(),a)}function nc(a,b){return this.isValid()&&(s(a)&&a.isValid()||tb(a).isValid())?Sb({from:this,to:a}).locale(this.locale()).humanize(!b):this.localeData().invalidDate()}function oc(a){return this.to(tb(),a)}function pc(a){var b;return void 0===a?this._locale._abbr:(b=bb(a),null!=b&&(this._locale=b),this)}function qc(){return this._locale}function rc(a){switch(a=K(a)){case"year":this.month(0);case"quarter":case"month":this.date(1);case"week":case"isoWeek":case"day":case"date":this.hours(0);case"hour":this.minutes(0);case"minute":this.seconds(0);case"second":this.milliseconds(0)}return"week"===a&&this.weekday(0),"isoWeek"===a&&this.isoWeekday(1),"quarter"===a&&this.month(3*Math.floor(this.month()/3)),this}function sc(a){return a=K(a),void 0===a||"millisecond"===a?this:("date"===a&&(a="day"),this.startOf(a).add(1,"isoWeek"===a?"week":a).subtract(1,"ms"))}function tc(){return this._d.valueOf()-6e4*(this._offset||0)}function uc(){return Math.floor(this.valueOf()/1e3)}function vc(){return new Date(this.valueOf())}function wc(){var a=this;return[a.year(),a.month(),a.date(),a.hour(),a.minute(),a.second(),a.millisecond()]}function xc(){var a=this;return{years:a.year(),months:a.month(),date:a.date(),hours:a.hours(),minutes:a.minutes(),seconds:a.seconds(),milliseconds:a.milliseconds()}}function yc(){return this.isValid()?this.toISOString():null}function zc(){return o(this)}function Ac(){ +return k({},n(this))}function Bc(){return n(this).overflow}function Cc(){return{input:this._i,format:this._f,locale:this._locale,isUTC:this._isUTC,strict:this._strict}}function Dc(a,b){U(0,[a,a.length],0,b)}function Ec(a){return Ic.call(this,a,this.week(),this.weekday(),this.localeData()._week.dow,this.localeData()._week.doy)}function Fc(a){return Ic.call(this,a,this.isoWeek(),this.isoWeekday(),1,4)}function Gc(){return xa(this.year(),1,4)}function Hc(){var a=this.localeData()._week;return xa(this.year(),a.dow,a.doy)}function Ic(a,b,c,d,e){var f;return null==a?wa(this,d,e).year:(f=xa(a,d,e),b>f&&(b=f),Jc.call(this,a,b,c,d,e))}function Jc(a,b,c,d,e){var f=va(a,b,c,d,e),g=ta(f.year,0,f.dayOfYear);return this.year(g.getUTCFullYear()),this.month(g.getUTCMonth()),this.date(g.getUTCDate()),this}function Kc(a){return null==a?Math.ceil((this.month()+1)/3):this.month(3*(a-1)+this.month()%3)}function Lc(a){var b=Math.round((this.clone().startOf("day")-this.clone().startOf("year"))/864e5)+1;return null==a?b:this.add(a-b,"d")}function Mc(a,b){b[ke]=u(1e3*("0."+a))}function Nc(){return this._isUTC?"UTC":""}function Oc(){return this._isUTC?"Coordinated Universal Time":""}function Pc(a){return tb(1e3*a)}function Qc(){return tb.apply(null,arguments).parseZone()}function Rc(a){return a}function Sc(a,b,c,d){var e=bb(),f=l().set(d,b);return e[c](f,a)}function Tc(a,b,c){if(g(a)&&(b=a,a=void 0),a=a||"",null!=b)return Sc(a,b,c,"month");var d,e=[];for(d=0;d<12;d++)e[d]=Sc(a,d,c,"month");return e}function Uc(a,b,c,d){"boolean"==typeof a?(g(b)&&(c=b,b=void 0),b=b||""):(b=a,c=b,a=!1,g(b)&&(c=b,b=void 0),b=b||"");var e=bb(),f=a?e._week.dow:0;if(null!=c)return Sc(b,(c+f)%7,d,"day");var h,i=[];for(h=0;h<7;h++)i[h]=Sc(b,(h+f)%7,d,"day");return i}function Vc(a,b){return Tc(a,b,"months")}function Wc(a,b){return Tc(a,b,"monthsShort")}function Xc(a,b,c){return Uc(a,b,c,"weekdays")}function Yc(a,b,c){return Uc(a,b,c,"weekdaysShort")}function Zc(a,b,c){return Uc(a,b,c,"weekdaysMin")}function $c(){var a=this._data;return this._milliseconds=df(this._milliseconds),this._days=df(this._days),this._months=df(this._months),a.milliseconds=df(a.milliseconds),a.seconds=df(a.seconds),a.minutes=df(a.minutes),a.hours=df(a.hours),a.months=df(a.months),a.years=df(a.years),this}function _c(a,b,c,d){var e=Sb(b,c);return a._milliseconds+=d*e._milliseconds,a._days+=d*e._days,a._months+=d*e._months,a._bubble()}function ad(a,b){return _c(this,a,b,1)}function bd(a,b){return _c(this,a,b,-1)}function cd(a){return a<0?Math.floor(a):Math.ceil(a)}function dd(){var a,b,c,d,e,f=this._milliseconds,g=this._days,h=this._months,i=this._data;return f>=0&&g>=0&&h>=0||f<=0&&g<=0&&h<=0||(f+=864e5*cd(fd(h)+g),g=0,h=0),i.milliseconds=f%1e3,a=t(f/1e3),i.seconds=a%60,b=t(a/60),i.minutes=b%60,c=t(b/60),i.hours=c%24,g+=t(c/24),e=t(ed(g)),h+=e,g-=cd(fd(e)),d=t(h/12),h%=12,i.days=g,i.months=h,i.years=d,this}function ed(a){return 4800*a/146097}function fd(a){return 146097*a/4800}function gd(a){if(!this.isValid())return NaN;var b,c,d=this._milliseconds;if(a=K(a),"month"===a||"year"===a)return b=this._days+d/864e5,c=this._months+ed(b),"month"===a?c:c/12;switch(b=this._days+Math.round(fd(this._months)),a){case"week":return b/7+d/6048e5;case"day":return b+d/864e5;case"hour":return 24*b+d/36e5;case"minute":return 1440*b+d/6e4;case"second":return 86400*b+d/1e3;case"millisecond":return Math.floor(864e5*b)+d;default:throw new Error("Unknown unit "+a)}}function hd(){return this.isValid()?this._milliseconds+864e5*this._days+this._months%12*2592e6+31536e6*u(this._months/12):NaN}function id(a){return function(){return this.as(a)}}function jd(a){return a=K(a),this.isValid()?this[a+"s"]():NaN}function kd(a){return function(){return this.isValid()?this._data[a]:NaN}}function ld(){return t(this.days()/7)}function md(a,b,c,d,e){return e.relativeTime(b||1,!!c,a,d)}function nd(a,b,c){var d=Sb(a).abs(),e=uf(d.as("s")),f=uf(d.as("m")),g=uf(d.as("h")),h=uf(d.as("d")),i=uf(d.as("M")),j=uf(d.as("y")),k=e<=vf.ss&&["s",e]||e0,k[4]=c,md.apply(null,k)}function od(a){return void 0===a?uf:"function"==typeof a&&(uf=a,!0)}function pd(a,b){return void 0!==vf[a]&&(void 0===b?vf[a]:(vf[a]=b,"s"===a&&(vf.ss=b-1),!0))}function qd(a){if(!this.isValid())return this.localeData().invalidDate();var b=this.localeData(),c=nd(this,!a,b);return a&&(c=b.pastFuture(+this,c)),b.postformat(c)}function rd(){if(!this.isValid())return this.localeData().invalidDate();var a,b,c,d=wf(this._milliseconds)/1e3,e=wf(this._days),f=wf(this._months);a=t(d/60),b=t(a/60),d%=60,a%=60,c=t(f/12),f%=12;var g=c,h=f,i=e,j=b,k=a,l=d,m=this.asSeconds();return m?(m<0?"-":"")+"P"+(g?g+"Y":"")+(h?h+"M":"")+(i?i+"D":"")+(j||k||l?"T":"")+(j?j+"H":"")+(k?k+"M":"")+(l?l+"S":""):"P0D"}var sd,td;td=Array.prototype.some?Array.prototype.some:function(a){for(var b=Object(this),c=b.length>>>0,d=0;d68?1900:2e3)};var te=O("FullYear",!0);U("w",["ww",2],"wo","week"),U("W",["WW",2],"Wo","isoWeek"),J("week","w"),J("isoWeek","W"),M("week",5),M("isoWeek",5),Z("w",Sd),Z("ww",Sd,Od),Z("W",Sd),Z("WW",Sd,Od),ca(["w","ww","W","WW"],function(a,b,c,d){b[d.substr(0,1)]=u(a)});var ue={dow:0,doy:6};U("d",0,"do","day"),U("dd",0,0,function(a){return this.localeData().weekdaysMin(this,a)}),U("ddd",0,0,function(a){return this.localeData().weekdaysShort(this,a)}),U("dddd",0,0,function(a){return this.localeData().weekdays(this,a)}),U("e",0,0,"weekday"),U("E",0,0,"isoWeekday"),J("day","d"),J("weekday","e"),J("isoWeekday","E"),M("day",11),M("weekday",11),M("isoWeekday",11),Z("d",Sd),Z("e",Sd),Z("E",Sd),Z("dd",function(a,b){return b.weekdaysMinRegex(a)}),Z("ddd",function(a,b){return b.weekdaysShortRegex(a)}),Z("dddd",function(a,b){return b.weekdaysRegex(a)}),ca(["dd","ddd","dddd"],function(a,b,c,d){var e=c._locale.weekdaysParse(a,d,c._strict);null!=e?b.d=e:n(c).invalidWeekday=a}),ca(["d","e","E"],function(a,b,c,d){b[d]=u(a)});var ve="Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),we="Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),xe="Su_Mo_Tu_We_Th_Fr_Sa".split("_"),ye=be,ze=be,Ae=be;U("H",["HH",2],0,"hour"),U("h",["hh",2],0,Ra),U("k",["kk",2],0,Sa),U("hmm",0,0,function(){return""+Ra.apply(this)+T(this.minutes(),2)}),U("hmmss",0,0,function(){return""+Ra.apply(this)+T(this.minutes(),2)+T(this.seconds(),2)}),U("Hmm",0,0,function(){return""+this.hours()+T(this.minutes(),2)}),U("Hmmss",0,0,function(){return""+this.hours()+T(this.minutes(),2)+T(this.seconds(),2)}),Ta("a",!0),Ta("A",!1),J("hour","h"),M("hour",13),Z("a",Ua),Z("A",Ua),Z("H",Sd),Z("h",Sd),Z("k",Sd),Z("HH",Sd,Od),Z("hh",Sd,Od),Z("kk",Sd,Od),Z("hmm",Td),Z("hmmss",Ud),Z("Hmm",Td),Z("Hmmss",Ud),ba(["H","HH"],he),ba(["k","kk"],function(a,b,c){var d=u(a);b[he]=24===d?0:d}),ba(["a","A"],function(a,b,c){c._isPm=c._locale.isPM(a),c._meridiem=a}),ba(["h","hh"],function(a,b,c){b[he]=u(a),n(c).bigHour=!0}),ba("hmm",function(a,b,c){var d=a.length-2;b[he]=u(a.substr(0,d)),b[ie]=u(a.substr(d)),n(c).bigHour=!0}),ba("hmmss",function(a,b,c){var d=a.length-4,e=a.length-2;b[he]=u(a.substr(0,d)),b[ie]=u(a.substr(d,2)),b[je]=u(a.substr(e)),n(c).bigHour=!0}),ba("Hmm",function(a,b,c){var d=a.length-2;b[he]=u(a.substr(0,d)),b[ie]=u(a.substr(d))}),ba("Hmmss",function(a,b,c){var d=a.length-4,e=a.length-2;b[he]=u(a.substr(0,d)),b[ie]=u(a.substr(d,2)),b[je]=u(a.substr(e))});var Be,Ce=/[ap]\.?m?\.?/i,De=O("Hours",!0),Ee={calendar:Bd,longDateFormat:Cd,invalidDate:Dd,ordinal:Ed,dayOfMonthOrdinalParse:Fd,relativeTime:Gd,months:pe,monthsShort:qe,week:ue,weekdays:ve,weekdaysMin:xe,weekdaysShort:we,meridiemParse:Ce},Fe={},Ge={},He=/^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/,Ie=/^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/,Je=/Z|[+-]\d\d(?::?\d\d)?/,Ke=[["YYYYYY-MM-DD",/[+-]\d{6}-\d\d-\d\d/],["YYYY-MM-DD",/\d{4}-\d\d-\d\d/],["GGGG-[W]WW-E",/\d{4}-W\d\d-\d/],["GGGG-[W]WW",/\d{4}-W\d\d/,!1],["YYYY-DDD",/\d{4}-\d{3}/],["YYYY-MM",/\d{4}-\d\d/,!1],["YYYYYYMMDD",/[+-]\d{10}/],["YYYYMMDD",/\d{8}/],["GGGG[W]WWE",/\d{4}W\d{3}/],["GGGG[W]WW",/\d{4}W\d{2}/,!1],["YYYYDDD",/\d{7}/]],Le=[["HH:mm:ss.SSSS",/\d\d:\d\d:\d\d\.\d+/],["HH:mm:ss,SSSS",/\d\d:\d\d:\d\d,\d+/],["HH:mm:ss",/\d\d:\d\d:\d\d/],["HH:mm",/\d\d:\d\d/],["HHmmss.SSSS",/\d\d\d\d\d\d\.\d+/],["HHmmss,SSSS",/\d\d\d\d\d\d,\d+/],["HHmmss",/\d\d\d\d\d\d/],["HHmm",/\d\d\d\d/],["HH",/\d\d/]],Me=/^\/?Date\((\-?\d+)/i,Ne=/^((?:Mon|Tue|Wed|Thu|Fri|Sat|Sun),?\s)?(\d?\d\s(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(?:\d\d)?\d\d\s)(\d\d:\d\d)(\:\d\d)?(\s(?:UT|GMT|[ECMP][SD]T|[A-IK-Za-ik-z]|[+-]\d{4}))$/;a.createFromInputFallback=x("value provided is not in a recognized RFC2822 or ISO format. moment construction falls back to js Date(), which is not reliable across all browsers and versions. Non RFC2822/ISO date formats are discouraged and will be removed in an upcoming major release. Please refer to http://momentjs.com/guides/#/warnings/js-date/ for more info.",function(a){a._d=new Date(a._i+(a._useUTC?" UTC":""))}),a.ISO_8601=function(){},a.RFC_2822=function(){};var Oe=x("moment().min is deprecated, use moment.max instead. http://momentjs.com/guides/#/warnings/min-max/",function(){var a=tb.apply(null,arguments);return this.isValid()&&a.isValid()?athis?this:a:p()}),Qe=function(){return Date.now?Date.now():+new Date},Re=["year","quarter","month","week","day","hour","minute","second","millisecond"];Db("Z",":"),Db("ZZ",""),Z("Z",_d),Z("ZZ",_d),ba(["Z","ZZ"],function(a,b,c){c._useUTC=!0,c._tzm=Eb(_d,a)});var Se=/([\+\-]|\d\d)/gi;a.updateOffset=function(){};var Te=/^(\-)?(?:(\d*)[. ])?(\d+)\:(\d+)(?:\:(\d+)(\.\d*)?)?$/,Ue=/^(-)?P(?:(-?[0-9,.]*)Y)?(?:(-?[0-9,.]*)M)?(?:(-?[0-9,.]*)W)?(?:(-?[0-9,.]*)D)?(?:T(?:(-?[0-9,.]*)H)?(?:(-?[0-9,.]*)M)?(?:(-?[0-9,.]*)S)?)?$/;Sb.fn=Ab.prototype,Sb.invalid=zb;var Ve=Wb(1,"add"),We=Wb(-1,"subtract");a.defaultFormat="YYYY-MM-DDTHH:mm:ssZ",a.defaultFormatUtc="YYYY-MM-DDTHH:mm:ss[Z]";var Xe=x("moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.",function(a){return void 0===a?this.localeData():this.locale(a)});U(0,["gg",2],0,function(){return this.weekYear()%100}),U(0,["GG",2],0,function(){return this.isoWeekYear()%100}),Dc("gggg","weekYear"),Dc("ggggg","weekYear"),Dc("GGGG","isoWeekYear"),Dc("GGGGG","isoWeekYear"),J("weekYear","gg"),J("isoWeekYear","GG"),M("weekYear",1),M("isoWeekYear",1),Z("G",Zd),Z("g",Zd),Z("GG",Sd,Od),Z("gg",Sd,Od),Z("GGGG",Wd,Qd),Z("gggg",Wd,Qd),Z("GGGGG",Xd,Rd),Z("ggggg",Xd,Rd),ca(["gggg","ggggg","GGGG","GGGGG"],function(a,b,c,d){b[d.substr(0,2)]=u(a)}),ca(["gg","GG"],function(b,c,d,e){c[e]=a.parseTwoDigitYear(b)}),U("Q",0,"Qo","quarter"),J("quarter","Q"),M("quarter",7),Z("Q",Nd),ba("Q",function(a,b){b[fe]=3*(u(a)-1)}),U("D",["DD",2],"Do","date"),J("date","D"),M("date",9),Z("D",Sd),Z("DD",Sd,Od),Z("Do",function(a,b){return a?b._dayOfMonthOrdinalParse||b._ordinalParse:b._dayOfMonthOrdinalParseLenient}),ba(["D","DD"],ge),ba("Do",function(a,b){b[ge]=u(a.match(Sd)[0],10)});var Ye=O("Date",!0);U("DDD",["DDDD",3],"DDDo","dayOfYear"),J("dayOfYear","DDD"),M("dayOfYear",4),Z("DDD",Vd),Z("DDDD",Pd),ba(["DDD","DDDD"],function(a,b,c){c._dayOfYear=u(a)}),U("m",["mm",2],0,"minute"),J("minute","m"),M("minute",14),Z("m",Sd),Z("mm",Sd,Od),ba(["m","mm"],ie);var Ze=O("Minutes",!1);U("s",["ss",2],0,"second"),J("second","s"),M("second",15),Z("s",Sd),Z("ss",Sd,Od),ba(["s","ss"],je);var $e=O("Seconds",!1);U("S",0,0,function(){return~~(this.millisecond()/100)}),U(0,["SS",2],0,function(){return~~(this.millisecond()/10)}),U(0,["SSS",3],0,"millisecond"),U(0,["SSSS",4],0,function(){return 10*this.millisecond()}),U(0,["SSSSS",5],0,function(){return 100*this.millisecond()}),U(0,["SSSSSS",6],0,function(){return 1e3*this.millisecond()}),U(0,["SSSSSSS",7],0,function(){return 1e4*this.millisecond()}),U(0,["SSSSSSSS",8],0,function(){return 1e5*this.millisecond()}),U(0,["SSSSSSSSS",9],0,function(){return 1e6*this.millisecond()}),J("millisecond","ms"),M("millisecond",16),Z("S",Vd,Nd),Z("SS",Vd,Od),Z("SSS",Vd,Pd);var _e;for(_e="SSSS";_e.length<=9;_e+="S")Z(_e,Yd);for(_e="S";_e.length<=9;_e+="S")ba(_e,Mc);var af=O("Milliseconds",!1);U("z",0,0,"zoneAbbr"),U("zz",0,0,"zoneName");var bf=r.prototype;bf.add=Ve,bf.calendar=Zb,bf.clone=$b,bf.diff=fc,bf.endOf=sc,bf.format=kc,bf.from=lc,bf.fromNow=mc,bf.to=nc,bf.toNow=oc,bf.get=R,bf.invalidAt=Bc,bf.isAfter=_b,bf.isBefore=ac,bf.isBetween=bc,bf.isSame=cc,bf.isSameOrAfter=dc,bf.isSameOrBefore=ec,bf.isValid=zc,bf.lang=Xe,bf.locale=pc,bf.localeData=qc,bf.max=Pe,bf.min=Oe,bf.parsingFlags=Ac,bf.set=S,bf.startOf=rc,bf.subtract=We,bf.toArray=wc,bf.toObject=xc,bf.toDate=vc,bf.toISOString=ic,bf.inspect=jc,bf.toJSON=yc,bf.toString=hc,bf.unix=uc,bf.valueOf=tc,bf.creationData=Cc,bf.year=te,bf.isLeapYear=ra,bf.weekYear=Ec,bf.isoWeekYear=Fc,bf.quarter=bf.quarters=Kc,bf.month=ka,bf.daysInMonth=la,bf.week=bf.weeks=Ba,bf.isoWeek=bf.isoWeeks=Ca,bf.weeksInYear=Hc,bf.isoWeeksInYear=Gc,bf.date=Ye,bf.day=bf.days=Ka,bf.weekday=La,bf.isoWeekday=Ma,bf.dayOfYear=Lc,bf.hour=bf.hours=De,bf.minute=bf.minutes=Ze,bf.second=bf.seconds=$e,bf.millisecond=bf.milliseconds=af,bf.utcOffset=Hb,bf.utc=Jb,bf.local=Kb,bf.parseZone=Lb,bf.hasAlignedHourOffset=Mb,bf.isDST=Nb,bf.isLocal=Pb,bf.isUtcOffset=Qb,bf.isUtc=Rb,bf.isUTC=Rb,bf.zoneAbbr=Nc,bf.zoneName=Oc,bf.dates=x("dates accessor is deprecated. Use date instead.",Ye),bf.months=x("months accessor is deprecated. Use month instead",ka),bf.years=x("years accessor is deprecated. Use year instead",te),bf.zone=x("moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/",Ib),bf.isDSTShifted=x("isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information",Ob);var cf=C.prototype;cf.calendar=D,cf.longDateFormat=E,cf.invalidDate=F,cf.ordinal=G,cf.preparse=Rc,cf.postformat=Rc,cf.relativeTime=H,cf.pastFuture=I,cf.set=A,cf.months=fa,cf.monthsShort=ga,cf.monthsParse=ia,cf.monthsRegex=na,cf.monthsShortRegex=ma,cf.week=ya,cf.firstDayOfYear=Aa,cf.firstDayOfWeek=za,cf.weekdays=Fa,cf.weekdaysMin=Ha,cf.weekdaysShort=Ga,cf.weekdaysParse=Ja,cf.weekdaysRegex=Na,cf.weekdaysShortRegex=Oa,cf.weekdaysMinRegex=Pa,cf.isPM=Va,cf.meridiem=Wa,$a("en",{dayOfMonthOrdinalParse:/\d{1,2}(th|st|nd|rd)/,ordinal:function(a){var b=a%10,c=1===u(a%100/10)?"th":1===b?"st":2===b?"nd":3===b?"rd":"th";return a+c}}),a.lang=x("moment.lang is deprecated. Use moment.locale instead.",$a),a.langData=x("moment.langData is deprecated. Use moment.localeData instead.",bb);var df=Math.abs,ef=id("ms"),ff=id("s"),gf=id("m"),hf=id("h"),jf=id("d"),kf=id("w"),lf=id("M"),mf=id("y"),nf=kd("milliseconds"),of=kd("seconds"),pf=kd("minutes"),qf=kd("hours"),rf=kd("days"),sf=kd("months"),tf=kd("years"),uf=Math.round,vf={ss:44,s:45,m:45,h:22,d:26,M:11},wf=Math.abs,xf=Ab.prototype;return xf.isValid=yb,xf.abs=$c,xf.add=ad,xf.subtract=bd,xf.as=gd,xf.asMilliseconds=ef,xf.asSeconds=ff,xf.asMinutes=gf,xf.asHours=hf,xf.asDays=jf,xf.asWeeks=kf,xf.asMonths=lf,xf.asYears=mf,xf.valueOf=hd,xf._bubble=dd,xf.get=jd,xf.milliseconds=nf,xf.seconds=of,xf.minutes=pf,xf.hours=qf,xf.days=rf,xf.weeks=ld,xf.months=sf,xf.years=tf,xf.humanize=qd,xf.toISOString=rd,xf.toString=rd,xf.toJSON=rd,xf.locale=pc,xf.localeData=qc,xf.toIsoString=x("toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)",rd),xf.lang=Xe,U("X",0,0,"unix"),U("x",0,0,"valueOf"),Z("x",Zd),Z("X",ae),ba("X",function(a,b,c){c._d=new Date(1e3*parseFloat(a,10))}),ba("x",function(a,b,c){c._d=new Date(u(a))}),a.version="2.18.1",b(tb),a.fn=bf,a.min=vb,a.max=wb,a.now=Qe,a.utc=l,a.unix=Pc,a.months=Vc,a.isDate=h,a.locale=$a,a.invalid=p,a.duration=Sb,a.isMoment=s,a.weekdays=Xc,a.parseZone=Qc,a.localeData=bb,a.isDuration=Bb,a.monthsShort=Wc,a.weekdaysMin=Zc,a.defineLocale=_a,a.updateLocale=ab,a.locales=cb,a.weekdaysShort=Yc,a.normalizeUnits=K,a.relativeTimeRounding=od,a.relativeTimeThreshold=pd,a.calendarFormat=Yb,a.prototype=bf,a}); \ No newline at end of file diff --git a/RaceLapTimer/RaceLapTimer/www/js/raceDirector.js b/RaceLapTimer/RaceLapTimer/www/js/raceDirector.js index be9dfd9..e9a3524 100644 --- a/RaceLapTimer/RaceLapTimer/www/js/raceDirector.js +++ b/RaceLapTimer/RaceLapTimer/www/js/raceDirector.js @@ -2,13 +2,23 @@ "use strict"; var self = this; self.raceSession = ko.observable(new RaceSession({id:-1, createdDate:"", updatedAt:"", title:"", active:false, mode:0, maxLaps:0, deletedAt:"", satelliteCount:0,timePenaltyPerSatellite:0, hotSeatEnabled:true, idleTimeSeconds:50})); + self.lastId = ko.observable(new LastScannedId({id:-1})); //self.raceSessions = ko.observable(); //$.get("/api/monitor", {}, self.raceSession); - //self.tmrHandle = setTimeout(function () { - // self.getData(); - //}, 2000); + self.tmrHandle = setTimeout(function () { + self.getLastId(); + }, 2000); + self.getLastId = function() { + $.get("/api/system/lasttoken", {}, + function (data) { + self.lastId(new LastScannedId(data)); + }) + .always(function () { + self.tmrHandle = setTimeout(self.getLastId, 2000); + }); + }; //self.getData = function () { // $.get("/api/monitor", {}, self.raceSession) // .done(function () { diff --git a/RaceLapTimer/RaceLapTimer/www/js/raceHistory.js b/RaceLapTimer/RaceLapTimer/www/js/raceHistory.js new file mode 100644 index 0000000..f479ec2 --- /dev/null +++ b/RaceLapTimer/RaceLapTimer/www/js/raceHistory.js @@ -0,0 +1,31 @@ +function ViewModel() { + var self = this; + self.deletePilotUrl = "/api/racesession/historic/"; + self.sessions = ko.observableArray([]); + self.deleteSession = function (raceSession) { + $.ajax({ + type: "DELETE", + url: self.deletePilotUrl + raceSession.id() + }); + return false; + }; + $.getJSON("/api/racesession/historic", function (allData) { + var mappedSessions = $.map(allData.data, function (item) { return new RaceSession(item) }); + self.sessions(mappedSessions); + }); +}; +ko.applyBindings(new ViewModel()); +function toggleIcon(e) { + $(e.target) + .toggleClass("glyphicon-plus glyphicon-minus"); +} +$(".dataTable").on("hidden.bs.collapse", + function toggleIcon(e) { + $(e.target) + .toggleClass("glyphicon-plus glyphicon-minus"); + }); +$(".dataTable").on("shown.bs.collapse", + function toggleIcon(e) { + $(e.target) + .toggleClass("glyphicon-plus glyphicon-minus"); + }); \ No newline at end of file diff --git a/RaceLapTimer/RaceLapTimerHost/Properties/AssemblyInfo.cs b/RaceLapTimer/RaceLapTimerHost/Properties/AssemblyInfo.cs index 89ca102..455985e 100644 --- a/RaceLapTimer/RaceLapTimerHost/Properties/AssemblyInfo.cs +++ b/RaceLapTimer/RaceLapTimerHost/Properties/AssemblyInfo.cs @@ -1,5 +1,4 @@ using System.Reflection; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following diff --git a/RaceLapTimer/UdpNotifier/Properties/AssemblyInfo.cs b/RaceLapTimer/UdpNotifier/Properties/AssemblyInfo.cs index 052ae88..19c4eb0 100644 --- a/RaceLapTimer/UdpNotifier/Properties/AssemblyInfo.cs +++ b/RaceLapTimer/UdpNotifier/Properties/AssemblyInfo.cs @@ -1,5 +1,4 @@ using System.Reflection; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following diff --git a/RaceLapTimer/UdpNotifier/UdpNotifierProvider.cs b/RaceLapTimer/UdpNotifier/UdpNotifierProvider.cs index 61dc76e..5b4f65c 100644 --- a/RaceLapTimer/UdpNotifier/UdpNotifierProvider.cs +++ b/RaceLapTimer/UdpNotifier/UdpNotifierProvider.cs @@ -1,5 +1,4 @@ -using System; -using System.Net; +using System.Net; using System.Net.Sockets; using System.Text; using Interfaces; @@ -14,14 +13,15 @@ namespace UdpNotifier { _logger = logger; } + public string GetDisplayName() { return "UDP Notifier"; } - public string GetNotifierType() + public PluginDetails GetPluginDetails() { - return "UdpNotifierProvider"; + return new PluginDetails("UdpNotifier", "Chris Watts", "UDP Notification engine", "1.0.0.0"); } public void NotifyRaceStarted(NotificationEventArgs args) @@ -52,12 +52,25 @@ namespace UdpNotifier private void Send() { - var endpoint = new IPEndPoint(IPAddress.Parse("192.168.1.94"), 64000); + var endpoint = new IPEndPoint(IPAddress.Parse(GetLocalIp()), 0); var client = new UdpClient(endpoint); var ip = new IPEndPoint(IPAddress.Broadcast, 15000); var bytes = Encoding.ASCII.GetBytes("Foo"); client.Send(bytes, bytes.Length, ip); client.Close(); } + + private string GetLocalIp() + { + var host = Dns.GetHostEntry(Dns.GetHostName()); + foreach (var ip in host.AddressList) + { + if (ip.AddressFamily == AddressFamily.InterNetwork) + { + return ip.ToString(); + } + } + return "0.0.0.0"; + } } } \ No newline at end of file diff --git a/RaceLapTimer/UdpNotifier/UdpNotifierProviderFactory.cs b/RaceLapTimer/UdpNotifier/UdpNotifierProviderFactory.cs index c912a27..4948a8a 100644 --- a/RaceLapTimer/UdpNotifier/UdpNotifierProviderFactory.cs +++ b/RaceLapTimer/UdpNotifier/UdpNotifierProviderFactory.cs @@ -1,8 +1,4 @@ -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Interfaces; +using Interfaces; namespace UdpNotifier {