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 {