diff --git a/src/FieldElementSubsystems.Test/Point/Baseline4R2/CommandingAndReversingTests.cs b/src/FieldElementSubsystems.Test/Point/Baseline4R2/CommandingAndReversingTests.cs index 3677c8f..676058c 100644 --- a/src/FieldElementSubsystems.Test/Point/Baseline4R2/CommandingAndReversingTests.cs +++ b/src/FieldElementSubsystems.Test/Point/Baseline4R2/CommandingAndReversingTests.cs @@ -3,7 +3,9 @@ using EulynxLive.FieldElementSubsystems.Interfaces; using EulynxLive.Messages.Baseline4R2; using EulynxLive.Point; +using EulynxLive.Point.Hubs; +using Microsoft.AspNetCore.SignalR; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; @@ -70,10 +72,12 @@ private static (EulynxLive.Point.Point point, Task pointTask, List recei var connection = new PointToInterlockingConnection(Mock.Of>(), configuration, CancellationToken.None); - var point = new EulynxLive.Point.Point(Mock.Of>(), configuration, connection, connectionProvider.Object, () => Task.CompletedTask); + var mockHubContext = new Mock>(); + mockHubContext.Setup(x => x.Clients.All.SendCoreAsync(It.IsAny(), It.IsAny(), It.IsAny())).Returns(Task.CompletedTask); + var point = new EulynxLive.Point.Point(Mock.Of>(), configuration, connection, connectionProvider.Object, mockHubContext.Object); if (simulateTimeouts) { - point.EnableTimeoutLeft(); - point.EnableTimeoutRight(); + point.EnableTimeoutLeft(true); + point.EnableTimeoutRight(true); } async Task SimulatePoint() diff --git a/src/FieldElementSubsystems.Test/Point/Baseline4R2/ReportStatusTests.cs b/src/FieldElementSubsystems.Test/Point/Baseline4R2/ReportStatusTests.cs index 3b9e4d7..b0a750e 100644 --- a/src/FieldElementSubsystems.Test/Point/Baseline4R2/ReportStatusTests.cs +++ b/src/FieldElementSubsystems.Test/Point/Baseline4R2/ReportStatusTests.cs @@ -3,7 +3,9 @@ using EulynxLive.FieldElementSubsystems.Interfaces; using EulynxLive.Messages.Baseline4R2; using EulynxLive.Point; +using EulynxLive.Point.Hubs; +using Microsoft.AspNetCore.SignalR; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; @@ -57,7 +59,9 @@ private static (EulynxLive.Point.Point point, Task, List receivedBytes) var connection = new PointToInterlockingConnection(Mock.Of>(), configuration, CancellationToken.None); connection.Connect(mockConnection.Object); - var point = new EulynxLive.Point.Point(Mock.Of>(), configuration, connection, connectionProvider.Object, () => Task.CompletedTask); + var mockHubContext = new Mock>(); + mockHubContext.Setup(x => x.Clients.All.SendCoreAsync(It.IsAny(), It.IsAny(), It.IsAny())).Returns(Task.CompletedTask); + var point = new EulynxLive.Point.Point(Mock.Of>(), configuration, connection, connectionProvider.Object, mockHubContext.Object); async Task SimulatePoint() { diff --git a/src/FieldElementSubsystems.Test/Point/PointServiceTest.cs b/src/FieldElementSubsystems.Test/Point/PointServiceTest.cs new file mode 100644 index 0000000..d1476a4 --- /dev/null +++ b/src/FieldElementSubsystems.Test/Point/PointServiceTest.cs @@ -0,0 +1,240 @@ +using EulynxLive.FieldElementSubsystems.Interfaces; +using EulynxLive.Point; +using EulynxLive.Point.Proto; +using EulynxLive.Point.Services; + +using Google.Protobuf; +using Google.Protobuf.WellKnownTypes; + +using Grpc.Core; + +using Moq; + +namespace FieldElementSubsystems.Test; + +public class PointServiceTest() +{ + [Fact] + public void TestReset() + { + // Arrange + var point = new Mock(); + var pointService = new PointService(point.Object); + + // Act + pointService.Reset(new Empty(), Mock.Of()); + + // Assert + point.Verify(x => x.Reset(), Times.Once); + } + + [Fact] + public void TestScheduleTimeoutRight() + { + // Arrange + var point = new Mock(); + var pointService = new PointService(point.Object); + + // Act + pointService.ScheduleTimeoutRight(new EnableMovementFailedMessage() { EnableMovementFailed = true }, Mock.Of()); + + // Assert + point.Verify(x => x.EnableTimeoutRight(true), Times.Once); + } + + [Fact] + public void TestScheduleTimeoutLeft() + { + // Arrange + var point = new Mock(); + var pointService = new PointService(point.Object); + + // Act + pointService.ScheduleTimeoutLeft(new EnableMovementFailedMessage() { EnableMovementFailed = true }, Mock.Of()); + + // Assert + point.Verify(x => x.EnableTimeoutLeft(true), Times.Once); + } + + [Fact] + public async Task TestSetAbilityToMove() + { + // Arrange + var point = new Mock(); + var pointService = new PointService(point.Object); + + // Act + await pointService.SetAbilityToMove(new AbilityToMoveMessage() { Ability = AbilityToMove.AbleToMove }, Mock.Of()); + + // Assert + point.Verify(x => x.SetAbilityToMove(It.IsAny()), Times.Once); + } + + [Fact] + public async Task TestSendSciMessage() + { + // Arrange + var point = new Mock(); + var pointService = new PointService(point.Object); + + // Act + await pointService.SendSciMessage(new SciMessage() { Message = ByteString.CopyFrom(new byte[] { 0x01 }) }, Mock.Of()); + + // Assert + point.Verify(x => x.SendSciMessage(It.IsAny()), Times.Once); + } + + [Fact] + public async Task TestOverrideSciMessage() + { + // Arrange + var point = new Mock(); + point.Setup(x => x.Connection.OverrideNextSciMessage(It.IsAny())) + .Returns(Task.FromResult(0)); + var pointService = new PointService(point.Object); + + // Act + await pointService.OverrideSciMessage(new SciMessage() { Message = ByteString.CopyFrom(new byte[] { 0x01 }) }, Mock.Of()); + + // Assert + point.Verify(x => x.Connection.OverrideNextSciMessage(It.IsAny()), Times.Once); + } + + [Fact] + public void TestSchedulePreventLeftEndPosition() + { + // Arrange + var point = new Mock(); + var pointService = new PointService(point.Object); + + // Act + pointService.SchedulePreventLeftEndPosition(new PreventedPositionMessage() { Position = PreventedPosition.SetNoEndPosition, DegradedPosition = true }, Mock.Of()); + + // Assert + point.Verify(x => x.PreventLeftEndPosition(It.IsAny()), Times.Once); + } + + [Fact] + public void TestSchedulePreventRightEndPosition() + { + // Arrange + var point = new Mock(); + var pointService = new PointService(point.Object); + + // Act + pointService.SchedulePreventRightEndPosition(new PreventedPositionMessage() { Position = PreventedPosition.SetNoEndPosition, DegradedPosition = true }, Mock.Of()); + + // Assert + point.Verify(x => x.PreventRightEndPosition(It.IsAny()), Times.Once); + } + + [Fact] + public async Task TestPutIntoTrailedPosition() + { + // Arrange + var point = new Mock(); + point.Setup(x => x.ConnectionProtocol) + .Returns(EulynxLive.FieldElementSubsystems.Configuration.ConnectionProtocol.EulynxBaseline4R1); + point.Setup(x => x.PointState) + .Returns(new GenericPointState(LastCommandedPointPosition: null, + PointPosition: GenericPointPosition.Left, + DegradedPointPosition: GenericDegradedPointPosition.NotApplicable, + AbilityToMove: GenericAbilityToMove.AbleToMove + )); + var pointService = new PointService(point.Object); + + // Act + await pointService.PutIntoTrailedPosition(new DegradedPositionMessage() { DegradedPosition = true }, Mock.Of()); + + // Assert + point.Verify(x => x.PutIntoUnintendedPosition(It.IsAny()), Times.Once); + } + + [Fact] + public async Task TestPutIntoTrailedPositionThrowsIfNotSupported() + { + // Arrange + var point = new Mock(); + point.Setup(x => x.ConnectionProtocol) + .Returns(EulynxLive.FieldElementSubsystems.Configuration.ConnectionProtocol.EulynxBaseline4R2); + point.Setup(x => x.PointState) + .Returns(new GenericPointState(LastCommandedPointPosition: null, + PointPosition: GenericPointPosition.Left, + DegradedPointPosition: GenericDegradedPointPosition.NotApplicable, + AbilityToMove: GenericAbilityToMove.AbleToMove + )); + var pointService = new PointService(point.Object); + + // Assert + await Assert.ThrowsAsync(() => pointService.PutIntoTrailedPosition(new DegradedPositionMessage() { DegradedPosition = true }, Mock.Of())); + } + + [Fact] + public async Task TestPutIntoUnintendedPosition() + { + // Arrange + var point = new Mock(); + point.Setup(x => x.ConnectionProtocol) + .Returns(EulynxLive.FieldElementSubsystems.Configuration.ConnectionProtocol.EulynxBaseline4R2); + var pointService = new PointService(point.Object); + + // Act + await pointService.PutIntoUnintendedPosition(new DegradedPositionMessage() { DegradedPosition = true }, Mock.Of()); + + // Assert + point.Verify(x => x.PutIntoUnintendedPosition(It.IsAny()), Times.Once); + } + + [Fact] + public async Task TestPutIntoUnintendedPositionThrowsIfNotSupported() + { + // Arrange + var point = new Mock(); + point.Setup(x => x.ConnectionProtocol) + .Returns(EulynxLive.FieldElementSubsystems.Configuration.ConnectionProtocol.EulynxBaseline4R1); + var pointService = new PointService(point.Object); + + // Assert + await Assert.ThrowsAsync(() => pointService.PutIntoUnintendedPosition(new DegradedPositionMessage() { DegradedPosition = true }, Mock.Of())); + } + + [Fact] + public async Task TestGetDegradedPointPosition() + { + // Arrange + var point = new Mock(); + point.Setup(x => x.PointState) + .Returns(new GenericPointState(LastCommandedPointPosition: null, + PointPosition: GenericPointPosition.Left, + DegradedPointPosition: GenericDegradedPointPosition.NotApplicable, + AbilityToMove: GenericAbilityToMove.AbleToMove + )); + var pointService = new PointService(point.Object); + + // Act + var result = await pointService.GetDegradedPointPosition(new Empty(), Mock.Of()); + + // Assert + Assert.Equal(PointDegradedPosition.NotApplicable, result.Position); + } + + [Fact] + public async Task TestGetPointPosition() + { + // Arrange + var point = new Mock(); + point.Setup(x => x.PointState) + .Returns(new GenericPointState(LastCommandedPointPosition: null, + PointPosition: GenericPointPosition.Left, + DegradedPointPosition: GenericDegradedPointPosition.NotApplicable, + AbilityToMove: GenericAbilityToMove.AbleToMove + )); + var pointService = new PointService(point.Object); + + // Act + var result = await pointService.GetPointPosition(new Empty(), Mock.Of()); + + // Assert + Assert.Equal(PointPosition.Left, result.Position); + } +} diff --git a/src/FieldElementSubsystems.Test/Point/PointTest.cs b/src/FieldElementSubsystems.Test/Point/PointTest.cs index f3f6c2e..691ee9a 100644 --- a/src/FieldElementSubsystems.Test/Point/PointTest.cs +++ b/src/FieldElementSubsystems.Test/Point/PointTest.cs @@ -7,6 +7,8 @@ using EulynxLive.Point.Proto; using Google.Protobuf; using EulynxLive.Point; +using EulynxLive.Point.Hubs; +using Microsoft.AspNetCore.SignalR; namespace FieldElementSubsystems.Test; @@ -36,7 +38,9 @@ private static (EulynxLive.Point.Point, Func simulatePoint, Mock()!; var mockConnection = CreateDefaultMockConnection(config); - var point = new EulynxLive.Point.Point(Mock.Of>(), configuration, mockConnection.Object, Mock.Of(), () => Task.CompletedTask); + var mockHubContext = new Mock>(); + mockHubContext.Setup(x => x.Clients.All.SendCoreAsync(It.IsAny(), It.IsAny(), It.IsAny())).Returns(Task.CompletedTask); + var point = new EulynxLive.Point.Point(Mock.Of>(), configuration, mockConnection.Object, Mock.Of(), mockHubContext.Object); async Task SimulatePoint() { @@ -93,7 +97,7 @@ public async Task Test_TimeoutLeft() .SetupSequence(m => m.ReceiveMovePointCommand(It.IsAny())) .Returns(() => { - point.EnableTimeoutLeft(); + point.EnableTimeoutLeft(true); return Task.FromResult(GenericPointPosition.Left); }) .Returns(() => @@ -121,7 +125,7 @@ public async Task Test_TimeoutRight() .SetupSequence(m => m.ReceiveMovePointCommand(It.IsAny())) .Returns(() => { - point.EnableTimeoutRight(); + point.EnableTimeoutRight(true); return Task.FromResult(GenericPointPosition.Right); }) .Returns(() => @@ -334,7 +338,7 @@ public async Task Test_PutIntoUnintendedPosition(bool simulatedDegradedPosition, { DegradedPosition = simulatedDegradedPosition }; - await point.PutIntoUnintendedPosition(message); + point.PutIntoUnintendedPosition(message); cancel.Cancel(); return await new TaskCompletionSource().Task; diff --git a/src/FieldElementSubsystems/Connections/EulynxBaseline4R1/PointToInterlockingConnection.cs b/src/FieldElementSubsystems/Connections/EulynxBaseline4R1/PointToInterlockingConnection.cs index 1bce76c..24f776c 100644 --- a/src/FieldElementSubsystems/Connections/EulynxBaseline4R1/PointToInterlockingConnection.cs +++ b/src/FieldElementSubsystems/Connections/EulynxBaseline4R1/PointToInterlockingConnection.cs @@ -4,6 +4,7 @@ using EulynxLive.FieldElementSubsystems.Configuration; using Grpc.Core; using EulynxLive.Messages.Baseline4R1; +using System.Threading.Channels; namespace EulynxLive.FieldElementSubsystems.Connections.EulynxBaseline4R1; @@ -14,6 +15,9 @@ public class PointToInterlockingConnection : IPointToInterlockingConnection private readonly string _localId; private readonly string _remoteId; public PointConfiguration Configuration { get; } + + private readonly Channel _overrideMessages; + public CancellationToken TimeoutToken => _timeout.Token; public IConnection? CurrentConnection { get; private set; } @@ -37,6 +41,7 @@ public PointToInterlockingConnection( _localId = config.LocalId; _remoteId = config.RemoteId; Configuration = config; + _overrideMessages = Channel.CreateUnbounded(); } public void Connect(IConnection connection) @@ -108,13 +113,13 @@ public async Task ReceiveMovePointCommand(CancellationToke private async Task SendMessage(Message message) { - if (CurrentConnection == null) throw new InvalidOperationException("Connection is null. Did you call Connect()?"); - await CurrentConnection.SendAsync(message.ToByteArray()); + await SendMessage(message.ToByteArray()); } private async Task SendMessage(byte[] message) { if (CurrentConnection == null) throw new InvalidOperationException("Connection is null. Did you call Connect()?"); + if (_overrideMessages.Reader.TryRead(out var overrideMessage)) message = overrideMessage; await CurrentConnection.SendAsync(message); } @@ -142,6 +147,11 @@ public async Task SendSciMessage(byte[] message) await SendMessage(message); } + public async Task OverrideNextSciMessage(byte[] message) + { + await _overrideMessages.Writer.WriteAsync(message); + } + public async Task SendAbilityToMove(GenericPointState pointState) { var abilityToMove = new AbilityToMove(pointState); diff --git a/src/FieldElementSubsystems/Connections/EulynxBaseline4R2/PointToInterlockingConnection.cs b/src/FieldElementSubsystems/Connections/EulynxBaseline4R2/PointToInterlockingConnection.cs index 5a24831..1ee35c9 100644 --- a/src/FieldElementSubsystems/Connections/EulynxBaseline4R2/PointToInterlockingConnection.cs +++ b/src/FieldElementSubsystems/Connections/EulynxBaseline4R2/PointToInterlockingConnection.cs @@ -4,6 +4,7 @@ using EulynxLive.FieldElementSubsystems.Configuration; using Grpc.Core; using EulynxLive.Messages.Baseline4R2; +using System.Threading.Channels; namespace EulynxLive.FieldElementSubsystems.Connections.EulynxBaseline4R2; @@ -13,6 +14,9 @@ public class PointToInterlockingConnection : IPointToInterlockingConnection private readonly string _localId; private readonly string _remoteId; public PointConfiguration Configuration { get; } + + private readonly Channel _overrideMessages; + public CancellationToken TimeoutToken => _timeout.Token; public IConnection? CurrentConnection { get; private set; } @@ -36,6 +40,7 @@ public PointToInterlockingConnection( _localId = config.LocalId; _remoteId = config.RemoteId; Configuration = config; + _overrideMessages = Channel.CreateUnbounded(); } public void Connect(IConnection connection) @@ -107,13 +112,13 @@ public async Task ReceiveMovePointCommand(CancellationToke private async Task SendMessage(Message message) { - if (CurrentConnection == null) throw new InvalidOperationException("Connection is null. Did you call Connect()?"); - await CurrentConnection.SendAsync(message.ToByteArray()); + await SendMessage(message.ToByteArray()); } private async Task SendMessage(byte[] message) { if (CurrentConnection == null) throw new InvalidOperationException("Connection is null. Did you call Connect()?"); + if (_overrideMessages.Reader.TryRead(out var overrideMessage)) message = overrideMessage; await CurrentConnection.SendAsync(message); } @@ -141,6 +146,11 @@ public async Task SendSciMessage(byte[] message) await SendMessage(message); } + public async Task OverrideNextSciMessage(byte[] message) + { + await _overrideMessages.Writer.WriteAsync(message); + } + public async Task SendAbilityToMove(GenericPointState pointState) { var abilityToMove = new AbilityToMove(pointState); diff --git a/src/FieldElementSubsystems/Interfaces/IPointToInterlockingConnection.cs b/src/FieldElementSubsystems/Interfaces/IPointToInterlockingConnection.cs index f0962cd..6bb59f9 100644 --- a/src/FieldElementSubsystems/Interfaces/IPointToInterlockingConnection.cs +++ b/src/FieldElementSubsystems/Interfaces/IPointToInterlockingConnection.cs @@ -9,7 +9,8 @@ public interface IPointToInterlockingConnection { void Connect(IConnection connection); Task SendPointPosition(GenericPointState state); - Task SendSciMessage(byte[] state); + Task SendSciMessage(byte[] message); + Task OverrideNextSciMessage(byte[] message); Task SendTimeoutMessage(); Task InitializeConnection(GenericPointState state, bool observeAbilityToMove, CancellationToken cancellationToken); Task ReceiveMovePointCommand(CancellationToken stoppingToken); diff --git a/src/LevelCrossing/rasta-levelcrossing-web/public/index.html b/src/LevelCrossing/rasta-levelcrossing-web/public/index.html index d9309f0..094ed1b 100644 --- a/src/LevelCrossing/rasta-levelcrossing-web/public/index.html +++ b/src/LevelCrossing/rasta-levelcrossing-web/public/index.html @@ -6,7 +6,7 @@ - RaSTA Point + Point diff --git a/src/LevelCrossing/rasta-levelcrossing-web/public/manifest.json b/src/LevelCrossing/rasta-levelcrossing-web/public/manifest.json index ca1854d..d7716a1 100644 --- a/src/LevelCrossing/rasta-levelcrossing-web/public/manifest.json +++ b/src/LevelCrossing/rasta-levelcrossing-web/public/manifest.json @@ -1,6 +1,6 @@ { "short_name": "Point", - "name": "RaSTA Point", + "name": "Point", "start_url": ".", "display": "standalone", "theme_color": "#000000", diff --git a/src/Point/Connections/ConnectionFactory.cs b/src/Point/Connections/ConnectionFactory.cs index c993c8e..a862b32 100644 --- a/src/Point/Connections/ConnectionFactory.cs +++ b/src/Point/Connections/ConnectionFactory.cs @@ -19,12 +19,12 @@ public IPointToInterlockingConnection CreateConnection(IServiceProvider x) { var connectionProtocol = _configuration.GetSection("ConnectionSettings").Get()?.ConnectionProtocol; switch (connectionProtocol){ case ConnectionProtocol.EulynxBaseline4R1: - return ActivatorUtilities.CreateInstance(x, _configuration); + return ActivatorUtilities.CreateInstance(x, _configuration, CancellationToken.None); case ConnectionProtocol.EulynxBaseline4R2: - return ActivatorUtilities.CreateInstance(x, _configuration); + return ActivatorUtilities.CreateInstance(x, _configuration, CancellationToken.None); case null: _logger.LogWarning($"No connection protocol specified. Using EulynxBaseline4R2."); - return ActivatorUtilities.CreateInstance(x, _configuration); + return ActivatorUtilities.CreateInstance(x, _configuration, CancellationToken.None); default: throw new NotImplementedException($"Unknown connection protocol {connectionProtocol}."); } diff --git a/src/Point/Hubs/StatusHub.cs b/src/Point/Hubs/StatusHub.cs new file mode 100644 index 0000000..3ce5c7c --- /dev/null +++ b/src/Point/Hubs/StatusHub.cs @@ -0,0 +1,7 @@ +using Microsoft.AspNetCore.SignalR; + +namespace EulynxLive.Point.Hubs; + +public class StatusHub : Hub +{ +} diff --git a/src/Point/IPoint.cs b/src/Point/IPoint.cs new file mode 100644 index 0000000..3e93262 --- /dev/null +++ b/src/Point/IPoint.cs @@ -0,0 +1,21 @@ +using EulynxLive.FieldElementSubsystems.Configuration; +using EulynxLive.FieldElementSubsystems.Interfaces; +using EulynxLive.Point.Proto; + +namespace EulynxLive.Point +{ + public interface IPoint { + ConnectionProtocol? ConnectionProtocol { get; } + IPointToInterlockingConnection Connection { get; } + GenericPointState PointState { get; } + + void EnableTimeoutLeft(bool enableMovementFailed); + void EnableTimeoutRight(bool enableMovementFailed); + void PreventLeftEndPosition(PreventedPositionMessage request); + void PreventRightEndPosition(PreventedPositionMessage request); + Task PutIntoUnintendedPosition(DegradedPositionMessage request); + void Reset(); + Task SendSciMessage(SciMessage request); + Task SetAbilityToMove(AbilityToMoveMessage request); + } +} diff --git a/src/Point/Point.cs b/src/Point/Point.cs index f2e97ca..c3b404d 100644 --- a/src/Point/Point.cs +++ b/src/Point/Point.cs @@ -1,39 +1,50 @@ using EulynxLive.FieldElementSubsystems.Configuration; using EulynxLive.FieldElementSubsystems.Interfaces; +using EulynxLive.Point.Hubs; using EulynxLive.Point.Proto; using Grpc.Core; +using Microsoft.AspNetCore.SignalR; + +using PropertyChanged.SourceGenerator; + +using System.ComponentModel; using System.Net.WebSockets; +using System.Reactive; using System.Reactive.Linq; using System.Runtime.CompilerServices; -using System.Text; -using System.Text.Json; namespace EulynxLive.Point { - - public class Point : BackgroundService + public partial class Point : BackgroundService, IPoint { - public bool AllPointMachinesCrucial { get; } - public GenericPointState PointState { get; private set; } public IPointToInterlockingConnection Connection { get; } + public bool AllPointMachinesCrucial { get; } + public bool ObserveAbilityToMove { get; } + public ConnectionProtocol? ConnectionProtocol => _config.ConnectionProtocol; + + [Notify] + private GenericPointState _pointState; + [Notify] + private SimulatedPointState _simulatedPointState; + [Notify] + private bool _initialized; + private readonly ILogger _logger; private readonly IConnectionProvider _connectionProvider; - private readonly Func _simulateTimeout; private readonly PointConfiguration _config; - private readonly List _webSockets; - private bool _initialized; - private SimulatedPointState _simulatedPointState; - public Point(ILogger logger, IConfiguration configuration, IPointToInterlockingConnection connection, IConnectionProvider connectionProvider, Func simulateTimeout) + public Point(ILogger logger, IConfiguration configuration, IPointToInterlockingConnection connection, IConnectionProvider connectionProvider, IHubContext statusHub) { + Connection = connection; + _connectionProvider = connectionProvider; _logger = logger; - _simulateTimeout = simulateTimeout; _config = configuration.GetSection("PointSettings").Get() ?? throw new Exception("No configuration provided"); AllPointMachinesCrucial = _config.AllPointMachinesCrucial; + ObserveAbilityToMove = _config.ObserveAbilityToMove; // Validate the configuration. if (_config.InitialLastCommandedPointPosition == null && _config.InitialPointPosition != GenericPointPosition.NoEndPosition) @@ -51,15 +62,13 @@ public Point(ILogger logger, IConfiguration configuration, IPointToInterl throw new InvalidOperationException("If the ability to move is observed, the initial ability to move must be set."); } - _webSockets = new List(); - var initialPointPosition = ( _config.InitialLastCommandedPointPosition == GenericPointPosition.Left && _config.InitialPointPosition == GenericPointPosition.Right || _config.InitialLastCommandedPointPosition == GenericPointPosition.Right && _config.InitialPointPosition == GenericPointPosition.Left) ? GenericPointPosition.UnintendedPosition : _config.InitialPointPosition; - PointState = new GenericPointState + _pointState = new GenericPointState ( LastCommandedPointPosition: _config.InitialLastCommandedPointPosition, DegradedPointPosition: RespectAllPointMachinesCrucial(_config.InitialDegradedPointPosition), @@ -75,33 +84,11 @@ public Point(ILogger logger, IConfiguration configuration, IPointToInterl SimulateTimeoutLeft: false, SimulateTimeoutRight: false ); - Connection = connection; - _connectionProvider = connectionProvider; - } - - public async Task HandleWebSocket(WebSocket webSocket) - { - _webSockets.Add(webSocket); - try - { - await UpdateWebClient(webSocket); - while (true) - { - byte[] messageBuffer = new byte[1024]; - var buffer = new ArraySegment(messageBuffer); - var result = await webSocket.ReceiveAsync(buffer, CancellationToken.None); - if (result.CloseStatus.HasValue) - { - break; - } - } - } - catch (WebSocketException) - { - // Do nothing, the WebSocket has died. - } - _webSockets.Remove(webSocket); + Observable.FromEventPattern(h => PropertyChanged += h, h => PropertyChanged -= h) + .Select(x => Unit.Default) + .Merge(Observable.Interval(TimeSpan.FromSeconds(1)).Select(x => Unit.Default)) + .Subscribe(x => statusHub.Clients.All.SendAsync("ReceiveStatus", _initialized, PointState, SimulatedPointState, new { AllPointMachinesCrucial, ObserveAbilityToMove, _config.ConnectionProtocol })); } public async Task SendSciMessage(SciMessage message) @@ -110,33 +97,27 @@ public async Task SendSciMessage(SciMessage message) await Connection.SendSciMessage(message.Message.ToByteArray()); } - private async Task SendTimeoutMessage() - { - _logger.LogInformation("Timeout"); - await Connection.SendTimeoutMessage(); - } - /// /// Sets the timeout flag for the next move left command. /// - public void EnableTimeoutLeft() + public void EnableTimeoutLeft(bool enableMovementFailed) { _logger.LogInformation("Timeout on next move left command enabled."); _simulatedPointState = _simulatedPointState with { - SimulateTimeoutLeft = true + SimulateTimeoutLeft = enableMovementFailed }; } /// /// Sets the timeout flag for the next move right command. /// - public void EnableTimeoutRight() + public void EnableTimeoutRight(bool enableMovementFailed) { _logger.LogInformation("Timeout on next move right command enabled."); _simulatedPointState = _simulatedPointState with { - SimulateTimeoutRight = true + SimulateTimeoutRight = enableMovementFailed }; } @@ -161,7 +142,9 @@ public async Task SetAbilityToMove(AbilityToMoveMessage abilityToMoveMessage) } }; - await Connection.SendAbilityToMove(PointState); + if (_initialized) { + await Connection.SendAbilityToMove(PointState); + } } /// @@ -183,7 +166,10 @@ public async Task PutIntoUnintendedPosition(DegradedPositionMessage simulatedPos var notDegradedPosition = AllPointMachinesCrucial ? GenericDegradedPointPosition.NotApplicable : GenericDegradedPointPosition.NotDegraded; var degradedPosition = PointState.PointPosition == GenericPointPosition.Left ? GenericDegradedPointPosition.DegradedLeft : GenericDegradedPointPosition.DegradedRight; SetPointState(GenericPointPosition.UnintendedPosition, simulatedPositionMessage.DegradedPosition ? degradedPosition : notDegradedPosition); - await UpdateConnectedWebClients(); + + if (_initialized) { + await Connection.SendPointPosition(PointState); + } } /// @@ -260,7 +246,7 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken) _logger.LogTrace("Connecting..."); var conn = _connectionProvider.Connect(Connection.Configuration, stoppingToken); Connection.Connect(conn); - await Reset(); + Reset(); try { var success = await Connection.InitializeConnection(PointState, _config.ObserveAbilityToMove, stoppingToken); @@ -268,7 +254,6 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken) { throw new Exception("Unable to initialize connection"); } - await UpdateConnectedWebClients(); _initialized = true; await AllMovePointCommands(stoppingToken) @@ -281,18 +266,18 @@ await AllMovePointCommands(stoppingToken) { // TODO: Since this is gRPC-specific, catch and re-throw this in the GrpcConnectionProvider _logger.LogWarning("Could not communicate with remote endpoint."); - await Reset(); + Reset(); await Task.Delay(1000, stoppingToken); } catch (OperationCanceledException) { - await Reset(); + Reset(); return; } catch (Exception ex) { _logger.LogWarning(ex, "Exception during simulation."); - await Reset(); + Reset(); await Task.Delay(1000, stoppingToken); } } @@ -312,6 +297,8 @@ private async Task HandleCommandedPointPosition(GenericPointPosition commandedPo // Make a copy of the current state, so that it is not modified while the point is moving. var simulatedState = _simulatedPointState; + PointState = PointState with { LastCommandedPointPosition = commandedPointPosition }; + if (_config.ObserveAbilityToMove && PointState.AbilityToMove == GenericAbilityToMove.UnableToMove) { _logger.LogInformation("Point is unable to move."); @@ -333,7 +320,6 @@ private async Task HandleCommandedPointPosition(GenericPointPosition commandedPo { SetPointState(GenericPointPosition.NoEndPosition, RespectAllPointMachinesCrucial(PointState.DegradedPointPosition)); await Connection.SendPointPosition(PointState); - await UpdateConnectedWebClients(); } try @@ -348,16 +334,14 @@ private async Task HandleCommandedPointPosition(GenericPointPosition commandedPo if (ShouldSimulateTimeout(commandedPointPosition, simulatedState)) { - await SendTimeoutMessage(); - await _simulateTimeout(); + _logger.LogInformation("Timeout"); + await Connection.SendTimeoutMessage(); } else { var (newPointPosition, newDegradedPointPosition) = HandlePreventedPointPosition(commandedPointPosition, simulatedState); SetPointState(newPointPosition, RespectAllPointMachinesCrucial(newDegradedPointPosition)); - await UpdateConnectedWebClients(); - _logger.LogInformation("End position reached."); await Connection.SendPointPosition(PointState); } @@ -427,42 +411,10 @@ private bool ShouldSimulateTimeout(GenericPointPosition commandedPointPosition, throw new ArgumentException("Invalid commanded position", nameof(commandedPosition)); } - public async Task Reset() + public void Reset() { _logger.LogInformation("Resetting point."); _initialized = false; - await UpdateConnectedWebClients(); - } - - private async Task UpdateConnectedWebClients() - { - try - { - var tasks = _webSockets.Select(UpdateWebClient); - await Task.WhenAll(tasks); - } - catch (Exception) - { - // Some client likely has an issue, ignore - } - } - - private async Task UpdateWebClient(WebSocket webSocket) - { - var positions = new Dictionary { - {GenericPointPosition.Right, "right"}, - {GenericPointPosition.Left, "left"}, - {GenericPointPosition.NoEndPosition, "noEndPosition"}, - {GenericPointPosition.UnintendedPosition, "unintendedPosition"}, - }; - var options = new JsonSerializerOptions { WriteIndented = true }; - var serializedState = JsonSerializer.Serialize(new - { - initialized = _initialized, - position = positions[PointState.PointPosition] - }, options); - var serializedStateBytes = Encoding.UTF8.GetBytes(serializedState); - await webSocket.SendAsync(serializedStateBytes, WebSocketMessageType.Text, true, CancellationToken.None); } } } diff --git a/src/Point/Point.csproj b/src/Point/Point.csproj index 2ef837f..61b4bf4 100644 --- a/src/Point/Point.csproj +++ b/src/Point/Point.csproj @@ -23,6 +23,10 @@ runtime; build; native; contentfiles; analyzers; buildtransitive + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + diff --git a/src/Point/Services/PointService.cs b/src/Point/Services/PointService.cs index 1c8d31d..745f0f6 100644 --- a/src/Point/Services/PointService.cs +++ b/src/Point/Services/PointService.cs @@ -9,28 +9,29 @@ namespace EulynxLive.Point.Services { public class PointService : PointBase { - private readonly Point _point; + private readonly IPoint _point; - public PointService(Point point) + public PointService(IPoint point) { _point = point; } - public override async Task Reset(Empty request, ServerCallContext context) + public override Task Reset(Empty request, ServerCallContext context) { - await _point.Reset(); - return new Empty(); + // TODO: We have to disconnect here! + _point.Reset(); + return Task.FromResult(new Empty()); } - public override Task ScheduleTimeoutRight(Empty request, ServerCallContext context) + public override Task ScheduleTimeoutRight(EnableMovementFailedMessage request, ServerCallContext context) { - _point.EnableTimeoutRight(); + _point.EnableTimeoutRight(request.EnableMovementFailed); return Task.FromResult(new Empty()); } - public override Task ScheduleTimeoutLeft(Empty request, ServerCallContext context) + public override Task ScheduleTimeoutLeft(EnableMovementFailedMessage request, ServerCallContext context) { - _point.EnableTimeoutLeft(); + _point.EnableTimeoutLeft(request.EnableMovementFailed); return Task.FromResult(new Empty()); } @@ -46,9 +47,10 @@ public override async Task SendSciMessage(SciMessage request, ServerCallC return new Empty(); } - public override Task OverrideSciMessage(SciMessage request, ServerCallContext context) + public override async Task OverrideSciMessage(SciMessage request, ServerCallContext context) { - throw new NotImplementedException(); + await _point.Connection.OverrideNextSciMessage(request.Message.ToByteArray()); + return new Empty(); } public override Task SchedulePreventLeftEndPosition(PreventedPositionMessage request, ServerCallContext context) @@ -65,7 +67,7 @@ override public Task SchedulePreventRightEndPosition(PreventedPositionMes public override async Task PutIntoTrailedPosition(DegradedPositionMessage request, ServerCallContext context) { - if (_point.Connection.Configuration.ConnectionProtocol != ConnectionProtocol.EulynxBaseline4R1) + if (_point.ConnectionProtocol != ConnectionProtocol.EulynxBaseline4R1) throw new RpcException(new Status(StatusCode.InvalidArgument, "Only supported for EulynxBaseline4R1")); await _point.PutIntoUnintendedPosition(request); @@ -74,7 +76,7 @@ public override async Task PutIntoTrailedPosition(DegradedPositionMessage public override async Task PutIntoUnintendedPosition(DegradedPositionMessage request, ServerCallContext context) { - if (_point.Connection.Configuration.ConnectionProtocol != ConnectionProtocol.EulynxBaseline4R2) + if (_point.ConnectionProtocol != ConnectionProtocol.EulynxBaseline4R2) throw new RpcException(new Status(StatusCode.InvalidArgument, "Only supported for EulynxBaseline4R2")); await _point.PutIntoUnintendedPosition(request); diff --git a/src/Point/Startup.cs b/src/Point/Startup.cs index 4d773d3..a54dc4e 100644 --- a/src/Point/Startup.cs +++ b/src/Point/Startup.cs @@ -1,6 +1,8 @@ using Microsoft.AspNetCore.SpaServices.ReactDevelopmentServer; using EulynxLive.Point.Services; using EulynxLive.Point.Connections; +using EulynxLive.Point.Hubs; +using System.Text.Json.Serialization; namespace EulynxLive.Point { @@ -16,10 +18,16 @@ public Startup(IConfiguration configuration) // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { + // TODO: Add switch mappings for better usability + // https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-8.0#switch-mappings services.AddControllersWithViews(); + services.AddSignalR() + .AddJsonProtocol(options => options.PayloadSerializerOptions.Converters.Add(new JsonStringEnumConverter())); services.AddGrpc(); services.AddGrpcReflection(); + services.AddTransient(); + services.AddTransient(); services.AddSingleton(x => x.GetRequiredService().CreateConnection(x)); // In production, the React files will be served from this directory @@ -30,11 +38,7 @@ public void ConfigureServices(IServiceCollection services) try { - services.AddSingleton(x => - { - var simulateTimout = async () => await Task.Delay(new Random().Next(1, 5) * 1000); - return ActivatorUtilities.CreateInstance(x, simulateTimout); - }); + services.AddSingleton(); } catch (Exception e) { @@ -42,6 +46,7 @@ public void ConfigureServices(IServiceCollection services) Environment.Exit(1); } + services.AddSingleton(x => x.GetRequiredService()); _ = services.AddHostedService(provider => provider.GetRequiredService()); } @@ -61,18 +66,15 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) app.UseSpaStaticFiles(); app.UseRouting(); - - // For live updating the Signal UI. - app.UseWebSockets(); - // Sends the websockets to the Simulator. - app.UseMiddleware(); - app.UseGrpcWeb(); + app.UseEndpoints(endpoints => { endpoints.MapGrpcService().EnableGrpcWeb(); endpoints.MapGrpcReflectionService(); + + endpoints.MapHub("/status"); }); app.UseSpa(spa => diff --git a/src/Point/WebsocketDispatcherMiddleware.cs b/src/Point/WebsocketDispatcherMiddleware.cs deleted file mode 100644 index a54807a..0000000 --- a/src/Point/WebsocketDispatcherMiddleware.cs +++ /dev/null @@ -1,38 +0,0 @@ -using Microsoft.AspNetCore.Http; -using System.Net.WebSockets; -using System.Threading.Tasks; - -namespace EulynxLive.Point -{ - public class WebsocketDispatcherMiddleware - { - private readonly RequestDelegate _next; - - public WebsocketDispatcherMiddleware(RequestDelegate next) - { - _next = next; - } - - public async Task InvokeAsync(HttpContext context, Point simulator) - { - if (context.Request.Path == "/ws") - { - if (context.WebSockets.IsWebSocketRequest) - { - using (WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync()) - { - await simulator.HandleWebSocket(webSocket); - } - } - else - { - context.Response.StatusCode = 400; - } - } - else - { - await _next(context); - } - } - } -} diff --git a/src/Point/appsettings.Development.json b/src/Point/appsettings.Development.json index cbf447c..dfa1321 100644 --- a/src/Point/appsettings.Development.json +++ b/src/Point/appsettings.Development.json @@ -1,7 +1,7 @@ { "Logging": { "LogLevel": { - "Default": "Trace", + "Default": "Information", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" } @@ -12,6 +12,6 @@ "LocalRastaId": 100, "RemoteId": "INTERLOCKING", "RemoteEndpoint": "http://localhost:50051", - "AllPointMachinesCrucial": true + "ObserveAbilityToMove": true } } diff --git a/src/Point/appsettings.json b/src/Point/appsettings.json index b944f06..74e2852 100644 --- a/src/Point/appsettings.json +++ b/src/Point/appsettings.json @@ -1,7 +1,7 @@ { "Logging": { "LogLevel": { - "Default": "Trace", + "Default": "Information", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" } @@ -10,11 +10,12 @@ "PointSettings": { "SimulatedTransitioningTimeSeconds": 0, "ObserveAbilityToMove": false, - "AllPointMachinesCrucial": true, - "InitialLastCommandedPointPosition": "null", - "InitialPointPosition": "NoEndPosition", + "AllPointMachinesCrucial": false, + "InitialLastCommandedPointPosition": "Left", + "InitialPointPosition": "Left", "InitialDegradedPointPosition": "NotApplicable", - "InitialAbilityToMove": "AbleToMove" + "InitialAbilityToMove": "AbleToMove", + "ConnectionProtocol": "EulynxBaseline4R1" }, "Kestrel": { "EndPoints": { diff --git a/src/Point/rasta-point-web/package-lock.json b/src/Point/rasta-point-web/package-lock.json index 228963f..8f3f74f 100644 --- a/src/Point/rasta-point-web/package-lock.json +++ b/src/Point/rasta-point-web/package-lock.json @@ -8,18 +8,34 @@ "name": "rasta-point-web", "version": "0.1.0", "dependencies": { - "@types/node": "^16.11.64", - "@types/react": "^17.0.50", - "@types/react-dom": "^17.0.17", + "@types/lodash": "^4.14.202", + "@types/node": "^16.18.68", + "@types/react": "^17.0.73", + "@types/react-dom": "^17.0.25", "google-protobuf": "^3.18.0-rc.1", "grpc-web": "^1.2.1", + "lodash": "^4.17.21", "react": "^17.0.2", "react-dom": "^17.0.2", - "typescript": "^4.8.4" + "react-signalr": "^0.2.18", + "typescript": "^4.9.5" }, "devDependencies": { "@types/google-protobuf": "^3.15.12", - "react-scripts": "^5.0.1" + "react-scripts": "^5.0.1", + "tailwindcss": "^3.3.6" + } + }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/@ampproject/remapping": { @@ -3211,6 +3227,18 @@ "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==", "dev": true }, + "node_modules/@microsoft/signalr": { + "version": "7.0.14", + "resolved": "https://registry.npmjs.org/@microsoft/signalr/-/signalr-7.0.14.tgz", + "integrity": "sha512-dnS7gSJF5LxByZwJaj82+F1K755ya7ttPT+JnSeCBef3sL8p8FBkHePXphK8NSuOquIb7vsphXWa28A+L2SPpw==", + "dependencies": { + "abort-controller": "^3.0.0", + "eventsource": "^2.0.2", + "fetch-cookie": "^2.0.3", + "node-fetch": "^2.6.7", + "ws": "^7.4.5" + } + }, "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": { "version": "5.1.1-v1", "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", @@ -3436,6 +3464,11 @@ "@sinonjs/commons": "^1.7.0" } }, + "node_modules/@socket.io/component-emitter": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", + "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==" + }, "node_modules/@surma/rollup-plugin-off-main-thread": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz", @@ -3766,6 +3799,19 @@ "@types/node": "*" } }, + "node_modules/@types/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==" + }, + "node_modules/@types/cors": { + "version": "2.8.17", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz", + "integrity": "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/eslint": { "version": "8.4.7", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.7.tgz", @@ -3881,6 +3927,11 @@ "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "dev": true }, + "node_modules/@types/lodash": { + "version": "4.14.202", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.202.tgz", + "integrity": "sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ==" + }, "node_modules/@types/mime": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", @@ -3888,9 +3939,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "16.18.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.0.tgz", - "integrity": "sha512-LqYqYzYvnbCaQfLAwRt0zboqnsViwhZm+vjaMSqcfN36vulAg7Pt0T83q4WZO2YOBw3XdyHi8cQ88H22zmULOA==" + "version": "16.18.68", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.68.tgz", + "integrity": "sha512-sG3hPIQwJLoewrN7cr0dwEy+yF5nD4D/4FxtQpFciRD/xwUzgD+G05uxZHv5mhfXo4F9Jkp13jjn0CC2q325sg==" }, "node_modules/@types/parse-json": { "version": "4.0.0", @@ -3928,9 +3979,9 @@ "dev": true }, "node_modules/@types/react": { - "version": "17.0.50", - "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.50.tgz", - "integrity": "sha512-ZCBHzpDb5skMnc1zFXAXnL3l1FAdi+xZvwxK+PkglMmBrwjpp9nKaWuEvrGnSifCJmBFGxZOOFuwC6KH/s0NuA==", + "version": "17.0.73", + "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.73.tgz", + "integrity": "sha512-6AcjgPIVsXTIsFDgsGW0iQhvg0xb2vt2qAWgXyncnVNRaW9ZXTTwAh7RQoh7PzK1AhjPoGDvUBkdAREih9n5oQ==", "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -3938,9 +3989,9 @@ } }, "node_modules/@types/react-dom": { - "version": "17.0.17", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.17.tgz", - "integrity": "sha512-VjnqEmqGnasQKV0CWLevqMTXBYG9GbwuE6x3VetERLh0cq2LTptFE73MrQi2S7GkKXCf2GgwItB/melLnxfnsg==", + "version": "17.0.25", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.25.tgz", + "integrity": "sha512-urx7A7UxkZQmThYA4So0NelOVjx3V4rNFVJwp0WZlbIK5eM4rNJDiN3R/E9ix0MBh6kAEojk/9YL+Te6D9zHNA==", "dependencies": { "@types/react": "^17" } @@ -4426,11 +4477,21 @@ "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", "dev": true }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, "node_modules/accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "dev": true, "dependencies": { "mime-types": "~2.1.34", "negotiator": "0.6.3" @@ -4491,29 +4552,6 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/acorn-node": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz", - "integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==", - "dev": true, - "dependencies": { - "acorn": "^7.0.0", - "acorn-walk": "^7.0.0", - "xtend": "^4.0.2" - } - }, - "node_modules/acorn-node/node_modules/acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/acorn-walk": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", @@ -4669,6 +4707,12 @@ "node": ">=4" } }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true + }, "node_modules/anymatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", @@ -5168,6 +5212,14 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "node_modules/base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "engines": { + "node": "^4.5.0 || >= 5.9" + } + }, "node_modules/batch": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", @@ -5869,6 +5921,18 @@ "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", "dev": true }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/cosmiconfig": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.0.tgz", @@ -6340,7 +6404,6 @@ "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, "dependencies": { "ms": "2.1.2" }, @@ -6417,15 +6480,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/defined": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.1.tgz", - "integrity": "sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -6501,23 +6555,6 @@ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, - "node_modules/detective": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/detective/-/detective-5.2.1.tgz", - "integrity": "sha512-v9XE1zRnz1wRtgurGu0Bs8uHKFSTdteYZNbIPFVhUZ39L/S79ppMpdmVOZAnoz1jfEFodc48n6MX483Xo3t1yw==", - "dev": true, - "dependencies": { - "acorn-node": "^1.8.2", - "defined": "^1.0.0", - "minimist": "^1.2.6" - }, - "bin": { - "detective": "bin/detective.js" - }, - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/didyoumean": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", @@ -6770,6 +6807,94 @@ "node": ">= 0.8" } }, + "node_modules/engine.io": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.4.tgz", + "integrity": "sha512-KdVSDKhVKyOi+r5uEabrDLZw2qXStVvCsEB/LN3mw4WFi6Gx50jTyuxYVCwAAC0U46FdnzP/ScKRBTXb/NiEOg==", + "dependencies": { + "@types/cookie": "^0.4.1", + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.4.1", + "cors": "~2.8.5", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.11.0" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/engine.io-client": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.3.tgz", + "integrity": "sha512-9Z0qLB0NIisTRt1DZ/8U2k12RJn8yls/nXMZLn+/N8hANT3TcYjKFKcwbw5zFQiN4NTde3TSY9zb79e1ij6j9Q==", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.11.0", + "xmlhttprequest-ssl": "~2.0.0" + } + }, + "node_modules/engine.io-client/node_modules/ws": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", + "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/engine.io-parser": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.1.tgz", + "integrity": "sha512-9JktcM3u18nU9N2Lz3bWeBgxVgOKpw7yhRaoxQA3FUDZzzw+9WlA6p4G4u0RixNkg14fH7EfEc/RhpurtiROTQ==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/engine.io/node_modules/cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/engine.io/node_modules/ws": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", + "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/enhanced-resolve": { "version": "5.10.0", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz", @@ -7720,6 +7845,14 @@ "node": ">= 0.6" } }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "engines": { + "node": ">=6" + } + }, "node_modules/eventemitter3": { "version": "4.0.7", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", @@ -7735,6 +7868,14 @@ "node": ">=0.8.x" } }, + "node_modules/eventsource": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-2.0.2.tgz", + "integrity": "sha512-IzUmBGPR3+oUG9dUeXynyNmf91/3zUSJg1lCktzKw47OXuhco54U3r9B7O4XX+Rb1Itm9OZ2b0RkTs10bICOxA==", + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/execa": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", @@ -7872,9 +8013,9 @@ "dev": true }, "node_modules/fast-glob": { - "version": "3.2.12", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", - "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", "dev": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -7941,6 +8082,15 @@ "bser": "2.1.1" } }, + "node_modules/fetch-cookie": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fetch-cookie/-/fetch-cookie-2.1.0.tgz", + "integrity": "sha512-39+cZRbWfbibmj22R2Jy6dmTbAWC+oqun1f1FzQaNurkPDUP4C38jpeZbiXCR88RKRVDp8UcDrbFXkNhN+NjYg==", + "dependencies": { + "set-cookie-parser": "^2.4.8", + "tough-cookie": "^4.0.0" + } + }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -8382,10 +8532,13 @@ } }, "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/function.prototype.name": { "version": "1.1.5", @@ -8712,6 +8865,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", @@ -8721,6 +8886,11 @@ "he": "bin/he" } }, + "node_modules/hermes-channel": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/hermes-channel/-/hermes-channel-2.1.2.tgz", + "integrity": "sha512-PVH+X8/S9J6XItQgIRLlsrwXUmb/v13wxvcZgqohnnlUZZOEWbWZ07bLsuQ9dEMnNpT9APvBuVV50W5QmDt4pA==" + }, "node_modules/hoopy": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz", @@ -9213,12 +9383,12 @@ } }, "node_modules/is-core-module": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", - "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", "dev": true, "dependencies": { - "has": "^1.0.3" + "hasown": "^2.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -11647,6 +11817,20 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "node_modules/jiti": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz", + "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==", + "dev": true, + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/js-cookie": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-2.2.1.tgz", + "integrity": "sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==" + }, "node_modules/js-sdsl": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.5.tgz", @@ -11864,9 +12048,9 @@ } }, "node_modules/lilconfig": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.6.tgz", - "integrity": "sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", "dev": true, "engines": { "node": ">=10" @@ -11919,8 +12103,7 @@ "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, "node_modules/lodash.debounce": { "version": "4.0.8", @@ -12112,7 +12295,6 @@ "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, "engines": { "node": ">= 0.6" } @@ -12121,7 +12303,6 @@ "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, "dependencies": { "mime-db": "1.52.0" }, @@ -12252,8 +12433,7 @@ "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/multicast-dns": { "version": "7.2.5", @@ -12268,11 +12448,28 @@ "multicast-dns": "cli.js" } }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dev": true, + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, "node_modules/nanoid": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -12290,7 +12487,6 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "dev": true, "engines": { "node": ">= 0.6" } @@ -12311,6 +12507,44 @@ "tslib": "^2.0.3" } }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-fetch/node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/node-fetch/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/node-fetch/node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/node-forge": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", @@ -12950,9 +13184,9 @@ } }, "node_modules/postcss": { - "version": "8.4.18", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.18.tgz", - "integrity": "sha512-Wi8mWhncLJm11GATDaQKobXSNEYGUHeQLiQqDFG1qQ5UTDPTEvKw0Xt5NsTpktGTwLps3ByrWsBrG0rB8YQ9oA==", + "version": "8.4.32", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.32.tgz", + "integrity": "sha512-D/kj5JNu6oo2EIy+XL/26JEDTlIbB8hw85G8StOE6L74RQAVVP5rej6wxCNqyMbR4RkPfqvezVbPw81Ngd6Kcw==", "dev": true, "funding": [ { @@ -12962,10 +13196,14 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ], "dependencies": { - "nanoid": "^3.3.4", + "nanoid": "^3.3.7", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" }, @@ -13367,9 +13605,9 @@ } }, "node_modules/postcss-import": { - "version": "14.1.0", - "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-14.1.0.tgz", - "integrity": "sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw==", + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", "dev": true, "dependencies": { "postcss-value-parser": "^4.0.0", @@ -13377,7 +13615,7 @@ "resolve": "^1.1.7" }, "engines": { - "node": ">=10.0.0" + "node": ">=14.0.0" }, "peerDependencies": { "postcss": "^8.0.0" @@ -13393,9 +13631,9 @@ } }, "node_modules/postcss-js": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.0.tgz", - "integrity": "sha512-77QESFBwgX4irogGVPgQ5s07vLvFqWr228qZY+w6lW599cRlK/HmnlivnnVUxkjHnCu4J16PDMHcH+e+2HbvTQ==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", + "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", "dev": true, "dependencies": { "camelcase-css": "^2.0.1" @@ -13408,7 +13646,7 @@ "url": "https://opencollective.com/postcss/" }, "peerDependencies": { - "postcss": "^8.3.3" + "postcss": "^8.4.21" } }, "node_modules/postcss-lab-function": { @@ -13431,6 +13669,59 @@ "postcss": "^8.2" } }, + "node_modules/postcss-load-config": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", + "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "lilconfig": "^3.0.0", + "yaml": "^2.3.4" + }, + "engines": { + "node": ">= 14" + }, + "peerDependencies": { + "postcss": ">=8.0.9", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/postcss-load-config/node_modules/lilconfig": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.0.0.tgz", + "integrity": "sha512-K2U4W2Ff5ibV7j7ydLr+zLAkIg5JJ4lPn1Ltsdt+Tz/IjQ8buJ55pZAxoP34lqIiwtF9iAvtLv3JGv7CAyAg+g==", + "dev": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/postcss-load-config/node_modules/yaml": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz", + "integrity": "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==", + "dev": true, + "engines": { + "node": ">= 14" + } + }, "node_modules/postcss-loader": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-6.2.1.tgz", @@ -13635,12 +13926,12 @@ } }, "node_modules/postcss-nested": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.0.tgz", - "integrity": "sha512-0DkamqrPcmkBDsLn+vQDIrtkSbNkv5AD/M322ySo9kqFkCIYklym2xEmWkwo+Y3/qZo34tzEPNUw4y7yMCdv5w==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz", + "integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==", "dev": true, "dependencies": { - "postcss-selector-parser": "^6.0.10" + "postcss-selector-parser": "^6.0.11" }, "engines": { "node": ">=12.0" @@ -14053,9 +14344,9 @@ } }, "node_modules/postcss-selector-parser": { - "version": "6.0.10", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", - "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", + "version": "6.0.13", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz", + "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==", "dev": true, "dependencies": { "cssesc": "^3.0.0", @@ -14367,14 +14658,12 @@ "node_modules/psl": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", - "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", - "dev": true + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==" }, "node_modules/punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true, "engines": { "node": ">=6" } @@ -14407,8 +14696,7 @@ "node_modules/querystringify": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", - "dev": true + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" }, "node_modules/queue-microtask": { "version": "1.2.3", @@ -14430,18 +14718,6 @@ } ] }, - "node_modules/quick-lru": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", - "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/raf": { "version": "3.4.1", "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz", @@ -14767,6 +15043,22 @@ } } }, + "node_modules/react-signalr": { + "version": "0.2.18", + "resolved": "https://registry.npmjs.org/react-signalr/-/react-signalr-0.2.18.tgz", + "integrity": "sha512-iu3mMRUqc2ruLkab7e+yEj6dgYYwRhENNYfz2/AXc3wBVSVU8nlNw5IXOpGdrIII4XtRwVsMtResL8pU3ph3EA==", + "dependencies": { + "@microsoft/signalr": "^7.0.10", + "hermes-channel": "^2.1.2", + "js-cookie": "^2.2.1", + "socket.io": "^4.2.0", + "socket.io-client": "^4.2.0", + "uuid": "^8.3.2" + }, + "peerDependencies": { + "react": ">=16.13" + } + }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -15061,16 +15353,15 @@ "node_modules/requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", - "dev": true + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" }, "node_modules/resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", "dev": true, "dependencies": { - "is-core-module": "^2.9.0", + "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, @@ -15597,6 +15888,11 @@ "node": ">= 0.8.0" } }, + "node_modules/set-cookie-parser": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.6.0.tgz", + "integrity": "sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==" + }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", @@ -15668,6 +15964,77 @@ "node": ">=8" } }, + "node_modules/socket.io": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.2.tgz", + "integrity": "sha512-bvKVS29/I5fl2FGLNHuXlQaUH/BlzX1IN6S+NKLNZpBsPZIDH+90eQmCs2Railn4YUiww4SzUedJ6+uzwFnKLw==", + "dependencies": { + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "cors": "~2.8.5", + "debug": "~4.3.2", + "engine.io": "~6.5.2", + "socket.io-adapter": "~2.5.2", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/socket.io-adapter": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.2.tgz", + "integrity": "sha512-87C3LO/NOMc+eMcpcxUBebGjkpMDkNBS9tf7KJqcDsmL936EChtVva71Dw2q4tQcuVC+hAUy4an2NO/sYXmwRA==", + "dependencies": { + "ws": "~8.11.0" + } + }, + "node_modules/socket.io-adapter/node_modules/ws": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", + "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/socket.io-client": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.2.tgz", + "integrity": "sha512-vtA0uD4ibrYD793SOIAwlo8cj6haOeMHrGvwPxJsxH7CeIksqJ+3Zc06RvWTIFgiSqx4A3sOnTXpfAEE2Zyz6w==", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.2", + "engine.io-client": "~6.5.2", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-parser": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", + "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/sockjs": { "version": "0.3.24", "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", @@ -16039,6 +16406,71 @@ "postcss": "^8.2.15" } }, + "node_modules/sucrase": { + "version": "3.34.0", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.34.0.tgz", + "integrity": "sha512-70/LQEZ07TEcxiU2dz51FKaE6hCTWC6vr7FOk3Gr0U60C3shtAN+H+BFr9XlYe5xqf3RA8nrc+VIwzCfnxuXJw==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "glob": "7.1.6", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/sucrase/node_modules/@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/sucrase/node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/sucrase/node_modules/glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -16137,79 +16569,40 @@ "dev": true }, "node_modules/tailwindcss": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.2.1.tgz", - "integrity": "sha512-Uw+GVSxp5CM48krnjHObqoOwlCt5Qo6nw1jlCRwfGy68dSYb/LwS9ZFidYGRiM+w6rMawkZiu1mEMAsHYAfoLg==", + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.6.tgz", + "integrity": "sha512-AKjF7qbbLvLaPieoKeTjG1+FyNZT6KaJMJPFeQyLfIp7l82ggH1fbHJSsYIvnbTFQOlkh+gBYpyby5GT1LIdLw==", "dev": true, "dependencies": { + "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", "chokidar": "^3.5.3", - "color-name": "^1.1.4", - "detective": "^5.2.1", "didyoumean": "^1.2.2", "dlv": "^1.1.3", - "fast-glob": "^3.2.12", + "fast-glob": "^3.3.0", "glob-parent": "^6.0.2", "is-glob": "^4.0.3", - "lilconfig": "^2.0.6", + "jiti": "^1.19.1", + "lilconfig": "^2.1.0", "micromatch": "^4.0.5", "normalize-path": "^3.0.0", "object-hash": "^3.0.0", "picocolors": "^1.0.0", - "postcss": "^8.4.17", - "postcss-import": "^14.1.0", - "postcss-js": "^4.0.0", - "postcss-load-config": "^3.1.4", - "postcss-nested": "6.0.0", - "postcss-selector-parser": "^6.0.10", - "postcss-value-parser": "^4.2.0", - "quick-lru": "^5.1.1", - "resolve": "^1.22.1" + "postcss": "^8.4.23", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.1", + "postcss-nested": "^6.0.1", + "postcss-selector-parser": "^6.0.11", + "resolve": "^1.22.2", + "sucrase": "^3.32.0" }, "bin": { "tailwind": "lib/cli.js", "tailwindcss": "lib/cli.js" }, "engines": { - "node": ">=12.13.0" - }, - "peerDependencies": { - "postcss": "^8.0.9" - } - }, - "node_modules/tailwindcss/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/tailwindcss/node_modules/postcss-load-config": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.4.tgz", - "integrity": "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==", - "dev": true, - "dependencies": { - "lilconfig": "^2.0.5", - "yaml": "^1.10.2" - }, - "engines": { - "node": ">= 10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - "peerDependencies": { - "postcss": ">=8.0.9", - "ts-node": ">=9.0.0" - }, - "peerDependenciesMeta": { - "postcss": { - "optional": true - }, - "ts-node": { - "optional": true - } + "node": ">=14.0.0" } }, "node_modules/tapable": { @@ -16354,6 +16747,27 @@ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dev": true, + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dev": true, + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/throat": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/throat/-/throat-6.0.1.tgz", @@ -16406,7 +16820,6 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.2.tgz", "integrity": "sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ==", - "dev": true, "dependencies": { "psl": "^1.1.33", "punycode": "^2.1.1", @@ -16421,7 +16834,6 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", - "dev": true, "engines": { "node": ">= 4.0.0" } @@ -16444,6 +16856,12 @@ "integrity": "sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==", "dev": true }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", + "dev": true + }, "node_modules/tsconfig-paths": { "version": "3.14.1", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", @@ -16560,9 +16978,9 @@ } }, "node_modules/typescript": { - "version": "4.8.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", - "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==", + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -16711,7 +17129,6 @@ "version": "1.5.10", "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", - "dev": true, "dependencies": { "querystringify": "^2.1.1", "requires-port": "^1.0.0" @@ -16752,7 +17169,6 @@ "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true, "bin": { "uuid": "dist/bin/uuid" } @@ -16775,7 +17191,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", - "dev": true, "engines": { "node": ">= 0.8" } @@ -17672,7 +18087,6 @@ "version": "7.5.9", "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", - "dev": true, "engines": { "node": ">=8.3.0" }, @@ -17701,13 +18115,12 @@ "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", "dev": true }, - "node_modules/xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "dev": true, + "node_modules/xmlhttprequest-ssl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz", + "integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==", "engines": { - "node": ">=0.4" + "node": ">=0.4.0" } }, "node_modules/y18n": { @@ -17775,6 +18188,12 @@ } }, "dependencies": { + "@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "dev": true + }, "@ampproject/remapping": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", @@ -19993,6 +20412,18 @@ "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==", "dev": true }, + "@microsoft/signalr": { + "version": "7.0.14", + "resolved": "https://registry.npmjs.org/@microsoft/signalr/-/signalr-7.0.14.tgz", + "integrity": "sha512-dnS7gSJF5LxByZwJaj82+F1K755ya7ttPT+JnSeCBef3sL8p8FBkHePXphK8NSuOquIb7vsphXWa28A+L2SPpw==", + "requires": { + "abort-controller": "^3.0.0", + "eventsource": "^2.0.2", + "fetch-cookie": "^2.0.3", + "node-fetch": "^2.6.7", + "ws": "^7.4.5" + } + }, "@nicolo-ribaudo/eslint-scope-5-internals": { "version": "5.1.1-v1", "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", @@ -20146,6 +20577,11 @@ "@sinonjs/commons": "^1.7.0" } }, + "@socket.io/component-emitter": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", + "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==" + }, "@surma/rollup-plugin-off-main-thread": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz", @@ -20372,6 +20808,19 @@ "@types/node": "*" } }, + "@types/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==" + }, + "@types/cors": { + "version": "2.8.17", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz", + "integrity": "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==", + "requires": { + "@types/node": "*" + } + }, "@types/eslint": { "version": "8.4.7", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.7.tgz", @@ -20487,6 +20936,11 @@ "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "dev": true }, + "@types/lodash": { + "version": "4.14.202", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.202.tgz", + "integrity": "sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ==" + }, "@types/mime": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", @@ -20494,9 +20948,9 @@ "dev": true }, "@types/node": { - "version": "16.18.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.0.tgz", - "integrity": "sha512-LqYqYzYvnbCaQfLAwRt0zboqnsViwhZm+vjaMSqcfN36vulAg7Pt0T83q4WZO2YOBw3XdyHi8cQ88H22zmULOA==" + "version": "16.18.68", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.68.tgz", + "integrity": "sha512-sG3hPIQwJLoewrN7cr0dwEy+yF5nD4D/4FxtQpFciRD/xwUzgD+G05uxZHv5mhfXo4F9Jkp13jjn0CC2q325sg==" }, "@types/parse-json": { "version": "4.0.0", @@ -20534,9 +20988,9 @@ "dev": true }, "@types/react": { - "version": "17.0.50", - "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.50.tgz", - "integrity": "sha512-ZCBHzpDb5skMnc1zFXAXnL3l1FAdi+xZvwxK+PkglMmBrwjpp9nKaWuEvrGnSifCJmBFGxZOOFuwC6KH/s0NuA==", + "version": "17.0.73", + "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.73.tgz", + "integrity": "sha512-6AcjgPIVsXTIsFDgsGW0iQhvg0xb2vt2qAWgXyncnVNRaW9ZXTTwAh7RQoh7PzK1AhjPoGDvUBkdAREih9n5oQ==", "requires": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -20544,9 +20998,9 @@ } }, "@types/react-dom": { - "version": "17.0.17", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.17.tgz", - "integrity": "sha512-VjnqEmqGnasQKV0CWLevqMTXBYG9GbwuE6x3VetERLh0cq2LTptFE73MrQi2S7GkKXCf2GgwItB/melLnxfnsg==", + "version": "17.0.25", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.25.tgz", + "integrity": "sha512-urx7A7UxkZQmThYA4So0NelOVjx3V4rNFVJwp0WZlbIK5eM4rNJDiN3R/E9ix0MBh6kAEojk/9YL+Te6D9zHNA==", "requires": { "@types/react": "^17" } @@ -20929,11 +21383,18 @@ "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", "dev": true }, + "abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "requires": { + "event-target-shim": "^5.0.0" + } + }, "accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "dev": true, "requires": { "mime-types": "~2.1.34", "negotiator": "0.6.3" @@ -20977,25 +21438,6 @@ "dev": true, "requires": {} }, - "acorn-node": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz", - "integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==", - "dev": true, - "requires": { - "acorn": "^7.0.0", - "acorn-walk": "^7.0.0", - "xtend": "^4.0.2" - }, - "dependencies": { - "acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true - } - } - }, "acorn-walk": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", @@ -21105,6 +21547,12 @@ "color-convert": "^1.9.0" } }, + "any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true + }, "anymatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", @@ -21484,6 +21932,11 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==" + }, "batch": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", @@ -22025,6 +22478,15 @@ "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", "dev": true }, + "cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "requires": { + "object-assign": "^4", + "vary": "^1" + } + }, "cosmiconfig": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.0.tgz", @@ -22355,7 +22817,6 @@ "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, "requires": { "ms": "2.1.2" } @@ -22409,12 +22870,6 @@ "object-keys": "^1.1.1" } }, - "defined": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.1.tgz", - "integrity": "sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==", - "dev": true - }, "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -22472,17 +22927,6 @@ } } }, - "detective": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/detective/-/detective-5.2.1.tgz", - "integrity": "sha512-v9XE1zRnz1wRtgurGu0Bs8uHKFSTdteYZNbIPFVhUZ39L/S79ppMpdmVOZAnoz1jfEFodc48n6MX483Xo3t1yw==", - "dev": true, - "requires": { - "acorn-node": "^1.8.2", - "defined": "^1.0.0", - "minimist": "^1.2.6" - } - }, "didyoumean": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", @@ -22684,6 +23128,61 @@ "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", "dev": true }, + "engine.io": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.4.tgz", + "integrity": "sha512-KdVSDKhVKyOi+r5uEabrDLZw2qXStVvCsEB/LN3mw4WFi6Gx50jTyuxYVCwAAC0U46FdnzP/ScKRBTXb/NiEOg==", + "requires": { + "@types/cookie": "^0.4.1", + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.4.1", + "cors": "~2.8.5", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.11.0" + }, + "dependencies": { + "cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==" + }, + "ws": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", + "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", + "requires": {} + } + } + }, + "engine.io-client": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.3.tgz", + "integrity": "sha512-9Z0qLB0NIisTRt1DZ/8U2k12RJn8yls/nXMZLn+/N8hANT3TcYjKFKcwbw5zFQiN4NTde3TSY9zb79e1ij6j9Q==", + "requires": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.11.0", + "xmlhttprequest-ssl": "~2.0.0" + }, + "dependencies": { + "ws": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", + "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", + "requires": {} + } + } + }, + "engine.io-parser": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.1.tgz", + "integrity": "sha512-9JktcM3u18nU9N2Lz3bWeBgxVgOKpw7yhRaoxQA3FUDZzzw+9WlA6p4G4u0RixNkg14fH7EfEc/RhpurtiROTQ==" + }, "enhanced-resolve": { "version": "5.10.0", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz", @@ -23385,6 +23884,11 @@ "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", "dev": true }, + "event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==" + }, "eventemitter3": { "version": "4.0.7", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", @@ -23397,6 +23901,11 @@ "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", "dev": true }, + "eventsource": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-2.0.2.tgz", + "integrity": "sha512-IzUmBGPR3+oUG9dUeXynyNmf91/3zUSJg1lCktzKw47OXuhco54U3r9B7O4XX+Rb1Itm9OZ2b0RkTs10bICOxA==" + }, "execa": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", @@ -23507,9 +24016,9 @@ "dev": true }, "fast-glob": { - "version": "3.2.12", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", - "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", "dev": true, "requires": { "@nodelib/fs.stat": "^2.0.2", @@ -23569,6 +24078,15 @@ "bser": "2.1.1" } }, + "fetch-cookie": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fetch-cookie/-/fetch-cookie-2.1.0.tgz", + "integrity": "sha512-39+cZRbWfbibmj22R2Jy6dmTbAWC+oqun1f1FzQaNurkPDUP4C38jpeZbiXCR88RKRVDp8UcDrbFXkNhN+NjYg==", + "requires": { + "set-cookie-parser": "^2.4.8", + "tough-cookie": "^4.0.0" + } + }, "file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -23881,9 +24399,9 @@ "optional": true }, "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "dev": true }, "function.prototype.name": { @@ -24123,12 +24641,26 @@ "has-symbols": "^1.0.2" } }, + "hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "dev": true, + "requires": { + "function-bind": "^1.1.2" + } + }, "he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true }, + "hermes-channel": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/hermes-channel/-/hermes-channel-2.1.2.tgz", + "integrity": "sha512-PVH+X8/S9J6XItQgIRLlsrwXUmb/v13wxvcZgqohnnlUZZOEWbWZ07bLsuQ9dEMnNpT9APvBuVV50W5QmDt4pA==" + }, "hoopy": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz", @@ -24497,12 +25029,12 @@ "dev": true }, "is-core-module": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", - "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", "dev": true, "requires": { - "has": "^1.0.3" + "hasown": "^2.0.0" } }, "is-date-object": { @@ -26302,6 +26834,17 @@ } } }, + "jiti": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz", + "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==", + "dev": true + }, + "js-cookie": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-2.2.1.tgz", + "integrity": "sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==" + }, "js-sdsl": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.5.tgz", @@ -26470,9 +27013,9 @@ } }, "lilconfig": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.6.tgz", - "integrity": "sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", "dev": true }, "lines-and-columns": { @@ -26510,8 +27053,7 @@ "lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, "lodash.debounce": { "version": "4.0.8", @@ -26668,14 +27210,12 @@ "mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" }, "mime-types": { "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, "requires": { "mime-db": "1.52.0" } @@ -26769,8 +27309,7 @@ "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "multicast-dns": { "version": "7.2.5", @@ -26782,10 +27321,21 @@ "thunky": "^1.0.2" } }, + "mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dev": true, + "requires": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, "nanoid": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", "dev": true }, "natural-compare": { @@ -26797,8 +27347,7 @@ "negotiator": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "dev": true + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" }, "neo-async": { "version": "2.6.2", @@ -26816,6 +27365,35 @@ "tslib": "^2.0.3" } }, + "node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "requires": { + "whatwg-url": "^5.0.0" + }, + "dependencies": { + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + } + } + }, "node-forge": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", @@ -27285,12 +27863,12 @@ } }, "postcss": { - "version": "8.4.18", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.18.tgz", - "integrity": "sha512-Wi8mWhncLJm11GATDaQKobXSNEYGUHeQLiQqDFG1qQ5UTDPTEvKw0Xt5NsTpktGTwLps3ByrWsBrG0rB8YQ9oA==", + "version": "8.4.32", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.32.tgz", + "integrity": "sha512-D/kj5JNu6oo2EIy+XL/26JEDTlIbB8hw85G8StOE6L74RQAVVP5rej6wxCNqyMbR4RkPfqvezVbPw81Ngd6Kcw==", "dev": true, "requires": { - "nanoid": "^3.3.4", + "nanoid": "^3.3.7", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" } @@ -27511,9 +28089,9 @@ } }, "postcss-import": { - "version": "14.1.0", - "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-14.1.0.tgz", - "integrity": "sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw==", + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", "dev": true, "requires": { "postcss-value-parser": "^4.0.0", @@ -27529,9 +28107,9 @@ "requires": {} }, "postcss-js": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.0.tgz", - "integrity": "sha512-77QESFBwgX4irogGVPgQ5s07vLvFqWr228qZY+w6lW599cRlK/HmnlivnnVUxkjHnCu4J16PDMHcH+e+2HbvTQ==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", + "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", "dev": true, "requires": { "camelcase-css": "^2.0.1" @@ -27547,6 +28125,30 @@ "postcss-value-parser": "^4.2.0" } }, + "postcss-load-config": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", + "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", + "dev": true, + "requires": { + "lilconfig": "^3.0.0", + "yaml": "^2.3.4" + }, + "dependencies": { + "lilconfig": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.0.0.tgz", + "integrity": "sha512-K2U4W2Ff5ibV7j7ydLr+zLAkIg5JJ4lPn1Ltsdt+Tz/IjQ8buJ55pZAxoP34lqIiwtF9iAvtLv3JGv7CAyAg+g==", + "dev": true + }, + "yaml": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz", + "integrity": "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==", + "dev": true + } + } + }, "postcss-loader": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-6.2.1.tgz", @@ -27671,12 +28273,12 @@ } }, "postcss-nested": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.0.tgz", - "integrity": "sha512-0DkamqrPcmkBDsLn+vQDIrtkSbNkv5AD/M322ySo9kqFkCIYklym2xEmWkwo+Y3/qZo34tzEPNUw4y7yMCdv5w==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz", + "integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==", "dev": true, "requires": { - "postcss-selector-parser": "^6.0.10" + "postcss-selector-parser": "^6.0.11" } }, "postcss-nesting": { @@ -27924,9 +28526,9 @@ } }, "postcss-selector-parser": { - "version": "6.0.10", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", - "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", + "version": "6.0.13", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz", + "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==", "dev": true, "requires": { "cssesc": "^3.0.0", @@ -28165,14 +28767,12 @@ "psl": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", - "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", - "dev": true + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==" }, "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" }, "q": { "version": "1.5.1", @@ -28192,8 +28792,7 @@ "querystringify": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", - "dev": true + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" }, "queue-microtask": { "version": "1.2.3", @@ -28201,12 +28800,6 @@ "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", "dev": true }, - "quick-lru": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", - "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", - "dev": true - }, "raf": { "version": "3.4.1", "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz", @@ -28462,6 +29055,19 @@ "workbox-webpack-plugin": "^6.4.1" } }, + "react-signalr": { + "version": "0.2.18", + "resolved": "https://registry.npmjs.org/react-signalr/-/react-signalr-0.2.18.tgz", + "integrity": "sha512-iu3mMRUqc2ruLkab7e+yEj6dgYYwRhENNYfz2/AXc3wBVSVU8nlNw5IXOpGdrIII4XtRwVsMtResL8pU3ph3EA==", + "requires": { + "@microsoft/signalr": "^7.0.10", + "hermes-channel": "^2.1.2", + "js-cookie": "^2.2.1", + "socket.io": "^4.2.0", + "socket.io-client": "^4.2.0", + "uuid": "^8.3.2" + } + }, "read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -28693,16 +29299,15 @@ "requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", - "dev": true + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" }, "resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", "dev": true, "requires": { - "is-core-module": "^2.9.0", + "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" } @@ -29086,6 +29691,11 @@ "send": "0.18.0" } }, + "set-cookie-parser": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.6.0.tgz", + "integrity": "sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==" + }, "setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", @@ -29142,6 +29752,56 @@ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true }, + "socket.io": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.2.tgz", + "integrity": "sha512-bvKVS29/I5fl2FGLNHuXlQaUH/BlzX1IN6S+NKLNZpBsPZIDH+90eQmCs2Railn4YUiww4SzUedJ6+uzwFnKLw==", + "requires": { + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "cors": "~2.8.5", + "debug": "~4.3.2", + "engine.io": "~6.5.2", + "socket.io-adapter": "~2.5.2", + "socket.io-parser": "~4.2.4" + } + }, + "socket.io-adapter": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.2.tgz", + "integrity": "sha512-87C3LO/NOMc+eMcpcxUBebGjkpMDkNBS9tf7KJqcDsmL936EChtVva71Dw2q4tQcuVC+hAUy4an2NO/sYXmwRA==", + "requires": { + "ws": "~8.11.0" + }, + "dependencies": { + "ws": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", + "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", + "requires": {} + } + } + }, + "socket.io-client": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.2.tgz", + "integrity": "sha512-vtA0uD4ibrYD793SOIAwlo8cj6haOeMHrGvwPxJsxH7CeIksqJ+3Zc06RvWTIFgiSqx4A3sOnTXpfAEE2Zyz6w==", + "requires": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.2", + "engine.io-client": "~6.5.2", + "socket.io-parser": "~4.2.4" + } + }, + "socket.io-parser": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", + "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", + "requires": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + } + }, "sockjs": { "version": "0.3.24", "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", @@ -29425,6 +30085,54 @@ "postcss-selector-parser": "^6.0.4" } }, + "sucrase": { + "version": "3.34.0", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.34.0.tgz", + "integrity": "sha512-70/LQEZ07TEcxiU2dz51FKaE6hCTWC6vr7FOk3Gr0U60C3shtAN+H+BFr9XlYe5xqf3RA8nrc+VIwzCfnxuXJw==", + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "glob": "7.1.6", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "ts-interface-checker": "^0.1.9" + }, + "dependencies": { + "@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } + } + }, "supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -29501,52 +30209,33 @@ "dev": true }, "tailwindcss": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.2.1.tgz", - "integrity": "sha512-Uw+GVSxp5CM48krnjHObqoOwlCt5Qo6nw1jlCRwfGy68dSYb/LwS9ZFidYGRiM+w6rMawkZiu1mEMAsHYAfoLg==", + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.6.tgz", + "integrity": "sha512-AKjF7qbbLvLaPieoKeTjG1+FyNZT6KaJMJPFeQyLfIp7l82ggH1fbHJSsYIvnbTFQOlkh+gBYpyby5GT1LIdLw==", "dev": true, "requires": { + "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", "chokidar": "^3.5.3", - "color-name": "^1.1.4", - "detective": "^5.2.1", "didyoumean": "^1.2.2", "dlv": "^1.1.3", - "fast-glob": "^3.2.12", + "fast-glob": "^3.3.0", "glob-parent": "^6.0.2", "is-glob": "^4.0.3", - "lilconfig": "^2.0.6", + "jiti": "^1.19.1", + "lilconfig": "^2.1.0", "micromatch": "^4.0.5", "normalize-path": "^3.0.0", "object-hash": "^3.0.0", "picocolors": "^1.0.0", - "postcss": "^8.4.17", - "postcss-import": "^14.1.0", - "postcss-js": "^4.0.0", - "postcss-load-config": "^3.1.4", - "postcss-nested": "6.0.0", - "postcss-selector-parser": "^6.0.10", - "postcss-value-parser": "^4.2.0", - "quick-lru": "^5.1.1", - "resolve": "^1.22.1" - }, - "dependencies": { - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "postcss-load-config": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.4.tgz", - "integrity": "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==", - "dev": true, - "requires": { - "lilconfig": "^2.0.5", - "yaml": "^1.10.2" - } - } + "postcss": "^8.4.23", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.1", + "postcss-nested": "^6.0.1", + "postcss-selector-parser": "^6.0.11", + "resolve": "^1.22.2", + "sucrase": "^3.32.0" } }, "tapable": { @@ -29641,6 +30330,24 @@ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, + "thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dev": true, + "requires": { + "any-promise": "^1.0.0" + } + }, + "thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dev": true, + "requires": { + "thenify": ">= 3.1.0 < 4" + } + }, "throat": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/throat/-/throat-6.0.1.tgz", @@ -29684,7 +30391,6 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.2.tgz", "integrity": "sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ==", - "dev": true, "requires": { "psl": "^1.1.33", "punycode": "^2.1.1", @@ -29695,8 +30401,7 @@ "universalify": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", - "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", - "dev": true + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==" } } }, @@ -29715,6 +30420,12 @@ "integrity": "sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==", "dev": true }, + "ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", + "dev": true + }, "tsconfig-paths": { "version": "3.14.1", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", @@ -29808,9 +30519,9 @@ } }, "typescript": { - "version": "4.8.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", - "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==" + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==" }, "unbox-primitive": { "version": "1.0.2", @@ -29908,7 +30619,6 @@ "version": "1.5.10", "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", - "dev": true, "requires": { "querystringify": "^2.1.1", "requires-port": "^1.0.0" @@ -29945,8 +30655,7 @@ "uuid": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" }, "v8-to-istanbul": { "version": "8.1.1", @@ -29962,8 +30671,7 @@ "vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", - "dev": true + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" }, "w3c-hr-time": { "version": "1.0.2", @@ -30690,7 +31398,6 @@ "version": "7.5.9", "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", - "dev": true, "requires": {} }, "xml-name-validator": { @@ -30705,11 +31412,10 @@ "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", "dev": true }, - "xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "dev": true + "xmlhttprequest-ssl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz", + "integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==" }, "y18n": { "version": "5.0.8", diff --git a/src/Point/rasta-point-web/package.json b/src/Point/rasta-point-web/package.json index c1cb86b..dd654ff 100644 --- a/src/Point/rasta-point-web/package.json +++ b/src/Point/rasta-point-web/package.json @@ -4,18 +4,22 @@ "homepage": "./", "private": true, "dependencies": { - "@types/node": "^16.11.64", - "@types/react": "^17.0.50", - "@types/react-dom": "^17.0.17", + "@types/lodash": "^4.14.202", + "@types/node": "^16.18.68", + "@types/react": "^17.0.73", + "@types/react-dom": "^17.0.25", "google-protobuf": "^3.18.0-rc.1", "grpc-web": "^1.2.1", + "lodash": "^4.17.21", "react": "^17.0.2", "react-dom": "^17.0.2", - "typescript": "^4.8.4" + "react-signalr": "^0.2.18", + "typescript": "^4.9.5" }, "devDependencies": { "@types/google-protobuf": "^3.15.12", - "react-scripts": "^5.0.1" + "react-scripts": "^5.0.1", + "tailwindcss": "^3.3.6" }, "scripts": { "start": "react-scripts start", diff --git a/src/Point/rasta-point-web/public/index.html b/src/Point/rasta-point-web/public/index.html index d9309f0..718f69a 100644 --- a/src/Point/rasta-point-web/public/index.html +++ b/src/Point/rasta-point-web/public/index.html @@ -6,7 +6,7 @@ - RaSTA Point + Point - +
- diff --git a/src/Point/rasta-point-web/public/manifest.json b/src/Point/rasta-point-web/public/manifest.json index ca1854d..d7716a1 100644 --- a/src/Point/rasta-point-web/public/manifest.json +++ b/src/Point/rasta-point-web/public/manifest.json @@ -1,6 +1,6 @@ { "short_name": "Point", - "name": "RaSTA Point", + "name": "Point", "start_url": ".", "display": "standalone", "theme_color": "#000000", diff --git a/src/Point/rasta-point-web/src/App.css b/src/Point/rasta-point-web/src/App.css index 76ade83..07141d8 100644 --- a/src/Point/rasta-point-web/src/App.css +++ b/src/Point/rasta-point-web/src/App.css @@ -2,10 +2,3 @@ html, body { width: 100vw; height: 100vh; } - -.container { - display: flex; - justify-content: center; - align-items: center; - height:100vh; -} \ No newline at end of file diff --git a/src/Point/rasta-point-web/src/App.tsx b/src/Point/rasta-point-web/src/App.tsx index 004cc0d..b4cec3f 100644 --- a/src/Point/rasta-point-web/src/App.tsx +++ b/src/Point/rasta-point-web/src/App.tsx @@ -1,12 +1,52 @@ +import { useState } from 'react'; import './App.css'; import Point from './Point'; +import { createSignalRContext } from 'react-signalr'; + +const { Provider, useSignalREffect } = createSignalRContext(); + +export type PointState = { + 'lastCommandedPointPosition': string, + 'pointPosition': string, + 'degradedPointPosition': string, + 'abilityToMove': string +}; + +export type SimulatedPointState = { + "preventedPositionLeft": string, + "preventedPositionRight": string, + "degradedPositionLeft": boolean, + "degradedPositionRight": boolean, + "simulateTimeoutLeft": boolean, + "simulateTimeoutRight": boolean +}; + +export type SimulatorConfiguration = { + observeAbilityToMove: boolean, + allPointMachinesCrucial: boolean, + connectionProtocol: 'EulynxBaseline4R1' | 'EulynxBaseline4R2', +}; function App() { - return ( -
- -
- ); + const [initialized, setInitialized] = useState(false); + const [pointState, setPointState] = useState(null); + const [simulatedPointState, setSimulatedPointState] = useState(null); + const [simulatorConfiguration, setSimulatorConfiguration] = useState(null); + + useSignalREffect("ReceiveStatus", (initialized: boolean, pointState: PointState, simulatedPointState: SimulatedPointState, simulatorConfiguration: SimulatorConfiguration) => { + setInitialized(initialized); + setPointState(pointState); + setSimulatedPointState(simulatedPointState); + setSimulatorConfiguration(simulatorConfiguration); + }, []); + + return ( +
+ + + +
+ ); } export default App; diff --git a/src/Point/rasta-point-web/src/Point.css b/src/Point/rasta-point-web/src/Point.css index d7437c6..e69de29 100644 --- a/src/Point/rasta-point-web/src/Point.css +++ b/src/Point/rasta-point-web/src/Point.css @@ -1,2 +0,0 @@ -.point { -} diff --git a/src/Point/rasta-point-web/src/Point.tsx b/src/Point/rasta-point-web/src/Point.tsx index 6a75383..1b2cc9d 100644 --- a/src/Point/rasta-point-web/src/Point.tsx +++ b/src/Point/rasta-point-web/src/Point.tsx @@ -1,151 +1,226 @@ -import React, { Component } from 'react'; +import React, { useState } from 'react'; +import _uniqueId from 'lodash/uniqueId'; import './Point.css'; import * as google_protobuf_empty_pb from 'google-protobuf/google/protobuf/empty_pb'; -import { SimulatorState } from './SimulatorState'; import { PointClient } from './proto/PointServiceClientPb'; -import { PreventedPosition, AbilityToMoveMessage, AbilityToMove, PreventedPositionMessage, DegradedPositionMessage } from './proto/point_pb'; +import { PreventedPosition, AbilityToMoveMessage, AbilityToMove, PreventedPositionMessage, DegradedPositionMessage, EnableMovementFailedMessage } from './proto/point_pb'; +import { PointState, SimulatedPointState, SimulatorConfiguration } from './App'; -interface PointState { - webSocket: WebSocket | null, - connected: boolean; - position: string; +type PointProps = { initialized: boolean, pointState: PointState | null, simulatedPointState: SimulatedPointState | null, simulatorConfiguration: SimulatorConfiguration | null }; + +function Toggle({ active, label, disabled, onChange }: { active: boolean, disabled?: boolean, onChange?: (active: boolean) => void, label: string }) { + const [id] = useState(_uniqueId('prefix-')); + return ( +
+
+ onChange?.(!active)} disabled={disabled} /> + {/* console.log('test')} /> */} + +
+
{label}
+
+ ) } -class Point extends Component<{}, PointState> { - constructor(p: {}) { - super(p); - this.state = { - webSocket: null, - connected: false, - position: '', - }; - } - - componentDidMount() { - var loc = window.location, new_uri; - if (loc.protocol === "https:") { - new_uri = "wss:"; - } else { - new_uri = "ws:"; - } - new_uri += "//" + loc.host; - if (loc.pathname.endsWith('/')) { - new_uri += loc.pathname + "ws"; - } else { - new_uri += loc.pathname + "/ws"; - } - const ws = new WebSocket(new_uri); - this.setState({ - webSocket: ws, - }) - ws.onopen = (event) => { - console.log("connected"); - } - ws.onerror = (error) => { - console.error(error); - } - ws.onmessage = (event) => { - this.receiveMessage(event); - }; - } - - componentWillUnmount() { - if (this.state.webSocket) { - this.state.webSocket.close(); - this.setState({ - webSocket: null, - }) - } - } +function ButtonGroup({ items }: { items: { active: boolean, label: string, disabled?: boolean, onClick?: (index: number) => void }[] }) { + const activeClassName = "btn bg-slate-50 dark:bg-slate-900 border-slate-200 dark:border-slate-700 text-indigo-500 rounded-none first:rounded-l last:rounded-r"; + const defaultClassName = "btn bg-white dark:bg-slate-800 border-slate-200 dark:border-slate-700 text-slate-600 dark:text-slate-300 rounded-none first:rounded-l last:rounded-r"; + const enabledClassName = " hover:bg-slate-50 dark:hover:bg-slate-900"; + const disabledClassName = " cursor-auto"; - private receiveMessage(event: MessageEvent): any { - if (typeof event.data !== 'string') { - return; - } - const state = JSON.parse(event.data) as SimulatorState; - this.showPointState(state); - } - - private showPointState(state: SimulatorState) { - this.setState({ - connected: state.initialized ?? false, - position: state.position, - }); - } - - render() { + return ( +
+
+
+ {items.map((item, index) => ( + + ))} +
+
+
+ ) +} + +function Point(props: PointProps) { + const sendCommand = async (sender: (client: PointClient) => Promise) => { const url = window.location.protocol + '//' + window.location.host + (window.location.pathname.endsWith('/') ? window.location.pathname.slice(0, -1) : window.location.pathname); const client = new PointClient(url); + try { + await sender(client) + } catch (e) { + alert(e); + } + }; + + const unintendedLabel = props.simulatorConfiguration?.connectionProtocol === 'EulynxBaseline4R1' ? 'Trailed' : 'Unintended'; + + return ( +
+

Point Simulator

+ +
+ +
+

Simulator Configuration

+
{props.simulatorConfiguration?.connectionProtocol ?? 'Loading...'}
+ + +
+ +
+

Point State

+
+
+ Electronic Interlocking Connection +
+
{props.initialized ? 'connected' : 'disconnected'}
+
+ +
+
+ End Position +
+ sendCommand(async (client) => { + if (props.simulatorConfiguration?.connectionProtocol === 'EulynxBaseline4R1') { + await client.putIntoTrailedPosition(new DegradedPositionMessage().setDegradedposition(false), null); + } else if (props.simulatorConfiguration?.connectionProtocol === 'EulynxBaseline4R2') { + await client.putIntoUnintendedPosition(new DegradedPositionMessage().setDegradedposition(false), null); + } + }) + }, + { label: 'Right', active: props.pointState?.pointPosition === 'Right' ?? false, disabled: true }, + ]} /> +
+ +
+
+ Degraded Point Position +
+ +
+ +
+
+ Last Commanded Point Position +
+ +
+ + {props.simulatorConfiguration?.observeAbilityToMove && ( +
+
+ Ability to Move +
+ sendCommand((client) => client.setAbilityToMove(new AbilityToMoveMessage().setAbility(AbilityToMove.ABLE_TO_MOVE), null)) }, + { label: 'Unable to Move', active: props.pointState?.abilityToMove === 'UnableToMove' ?? false, onClick: () => sendCommand((client) => client.setAbilityToMove(new AbilityToMoveMessage().setAbility(AbilityToMove.UNABLE_TO_MOVE), null)) }, + ]} /> +
+ )} +
+ +
+

Simulate Irregularities

+ +
+
+ Prevent left end position +
+ + sendCommand((client) => client.scheduleTimeoutLeft(new EnableMovementFailedMessage().setEnablemovementfailed(enable), null))} /> + + sendCommand((client) => client.schedulePreventLeftEndPosition(new PreventedPositionMessage().setPosition(PreventedPosition.DONOTPREVENT).setDegradedposition(props.simulatedPointState?.degradedPositionLeft ?? false), null)) + }, + { + label: unintendedLabel, active: props.simulatedPointState?.preventedPositionLeft === 'SetUnintendedOrTrailed' ?? false, + onClick: () => sendCommand((client) => client.schedulePreventLeftEndPosition(new PreventedPositionMessage().setPosition(PreventedPosition.SETUNINTENDEDORTRAILED).setDegradedposition(props.simulatedPointState?.degradedPositionLeft ?? false), null)) + }, + { + label: 'No End Position', active: props.simulatedPointState?.preventedPositionLeft === 'SetNoEndPosition' ?? false, + onClick: () => sendCommand((client) => client.schedulePreventLeftEndPosition(new PreventedPositionMessage().setPosition(PreventedPosition.SETNOENDPOSITION).setDegradedposition(props.simulatedPointState?.degradedPositionLeft ?? false), null)) + }, + ]} /> + + sendCommand((client) => client.schedulePreventLeftEndPosition(new PreventedPositionMessage().setDegradedposition(enable).setPosition({ + 'DoNotPrevent': PreventedPosition.DONOTPREVENT, + 'SetUnintendedOrTrailed': PreventedPosition.SETUNINTENDEDORTRAILED, + 'SetNoEndPosition': PreventedPosition.SETNOENDPOSITION, + 'none': null + }[props.simulatedPointState?.preventedPositionLeft ?? 'none'] ?? PreventedPosition.DONOTPREVENT), null))} + /> +
+ +
+
+ Prevent right end position +
+ + sendCommand((client) => client.scheduleTimeoutRight(new EnableMovementFailedMessage().setEnablemovementfailed(enable), null))} /> + + sendCommand((client) => client.schedulePreventRightEndPosition(new PreventedPositionMessage().setPosition(PreventedPosition.DONOTPREVENT).setDegradedposition(props.simulatedPointState?.degradedPositionRight ?? false), null)) + }, + { + label: unintendedLabel, active: props.simulatedPointState?.preventedPositionRight === 'SetUnintendedOrTrailed' ?? false, + onClick: () => sendCommand((client) => client.schedulePreventRightEndPosition(new PreventedPositionMessage().setPosition(PreventedPosition.SETUNINTENDEDORTRAILED).setDegradedposition(props.simulatedPointState?.degradedPositionRight ?? false), null)) + }, + { + label: 'No End Position', active: props.simulatedPointState?.preventedPositionRight === 'SetNoEndPosition' ?? false, + onClick: () => sendCommand((client) => client.schedulePreventRightEndPosition(new PreventedPositionMessage().setPosition(PreventedPosition.SETNOENDPOSITION).setDegradedposition(props.simulatedPointState?.degradedPositionRight ?? false), null)) + }, + ]} /> + + sendCommand((client) => client.schedulePreventRightEndPosition(new PreventedPositionMessage().setDegradedposition(enable).setPosition({ + 'DoNotPrevent': PreventedPosition.DONOTPREVENT, + 'SetUnintendedOrTrailed': PreventedPosition.SETUNINTENDEDORTRAILED, + 'SetNoEndPosition': PreventedPosition.SETNOENDPOSITION, + 'none': null + }[props.simulatedPointState?.preventedPositionRight ?? 'none'] ?? PreventedPosition.DONOTPREVENT), null))} + /> +
+ +
+
+ Connectivity +
+ +
+
- return ( -
-

EULYNX Point Simulator

-

Connection to Interlocking

-

{this.state.connected ? 'connected' : 'disconnected'}

-

Position

-

{this.state.position}

- - -

- - -

- - -

- - -

- - -

-
- ); - } + +
+ ); } export default Point; diff --git a/src/Point/rasta-point-web/src/SimulatorState.ts b/src/Point/rasta-point-web/src/SimulatorState.ts deleted file mode 100644 index 9ba1f0f..0000000 --- a/src/Point/rasta-point-web/src/SimulatorState.ts +++ /dev/null @@ -1,5 +0,0 @@ -export interface SimulatorState -{ - initialized: boolean; - position: string; -}; diff --git a/src/Point/rasta-point-web/src/index.css b/src/Point/rasta-point-web/src/index.css index a41a98c..09f5c86 100644 --- a/src/Point/rasta-point-web/src/index.css +++ b/src/Point/rasta-point-web/src/index.css @@ -1,9 +1,124 @@ -body { - margin: 0; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', - 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', - sans-serif; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - background-color: #eee; +@tailwind base; +@tailwind components; +@tailwind utilities; + + +/* Switch element */ + +.form-switch{ + position: relative; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; + width: 44px; + } + + .form-switch label{ + display: block; + height: 1.5rem; + cursor: pointer; + overflow: hidden; + border-radius: 9999px; + } + + .form-switch label > span:first-child{ + position: absolute; + display: block; + border-radius: 9999px; + width: 20px; + height: 20px; + top: 2px; + left: 2px; + right: 50%; + transition: all .15s ease-out; + } + + .form-switch input[type="checkbox"]:checked + label{ + --tw-bg-opacity: 1; + background-color: rgb(99 102 241 / var(--tw-bg-opacity)); + } + + .form-switch input[type="checkbox"]:checked + label > span:first-child { + left: 22px; + } + + .form-switch input[type="checkbox"]:disabled + label{ + cursor: not-allowed; + } + + .form-switch input[type="checkbox"]:disabled:not(:checked) + label { + border-width: 1px; + --tw-border-opacity: 1; + border-color: rgb(226 232 240 / var(--tw-border-opacity)); + --tw-bg-opacity: 1; + background-color: rgb(241 245 249 / var(--tw-bg-opacity)); + } + + :is(.dark .form-switch input[type="checkbox"]:disabled + label){ + --tw-border-opacity: 1; + border-color: rgb(51 65 85 / var(--tw-border-opacity)); + background-color: rgb(51 65 85 / 0.2); + } + + .form-switch input[type="checkbox"]:disabled + label > span:first-child{ + --tw-bg-opacity: 1; + background-color: rgb(148 163 184 / var(--tw-bg-opacity)); + } + + :is(.dark .form-switch input[type="checkbox"]:disabled + label > span:first-child){ + --tw-bg-opacity: 1; + background-color: rgb(71 85 105 / var(--tw-bg-opacity)); + } + +/* Buttons */ + +.btn, +.btn-lg, +.btn-sm, +.btn-xs{ + display: inline-flex; + align-items: center; + justify-content: center; + border-width: 1px; + border-color: transparent; + font-size: 0.875rem; + line-height: 1.5715; + font-weight: 500; + line-height: 1.25rem; + --tw-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05); + --tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); + transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, -webkit-backdrop-filter; + transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter; + transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter, -webkit-backdrop-filter; + transition-duration: 150ms; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); +} + +.btn{ + padding-left: 0.75rem; + padding-right: 0.75rem; + padding-top: 0.5rem; + padding-bottom: 0.5rem; +} + +.btn-lg{ + padding-left: 1rem; + padding-right: 1rem; + padding-top: 0.75rem; + padding-bottom: 0.75rem; +} + +.btn-sm{ + padding-left: 0.5rem; + padding-right: 0.5rem; + padding-top: 0.25rem; + padding-bottom: 0.25rem; +} + +.btn-xs{ + padding-left: 0.5rem; + padding-right: 0.5rem; + padding-top: 0.125rem; + padding-bottom: 0.125rem; } diff --git a/src/Point/rasta-point-web/src/proto/PointServiceClientPb.ts b/src/Point/rasta-point-web/src/proto/PointServiceClientPb.ts index 08a2f7d..0715350 100644 --- a/src/Point/rasta-point-web/src/proto/PointServiceClientPb.ts +++ b/src/Point/rasta-point-web/src/proto/PointServiceClientPb.ts @@ -430,26 +430,26 @@ export class PointClient { methodDescriptorScheduleTimeoutRight = new grpcWeb.MethodDescriptor( '/point.Point/ScheduleTimeoutRight', grpcWeb.MethodType.UNARY, + point_pb.EnableMovementFailedMessage, google_protobuf_empty_pb.Empty, - google_protobuf_empty_pb.Empty, - (request: google_protobuf_empty_pb.Empty) => { + (request: point_pb.EnableMovementFailedMessage) => { return request.serializeBinary(); }, google_protobuf_empty_pb.Empty.deserializeBinary ); scheduleTimeoutRight( - request: google_protobuf_empty_pb.Empty, + request: point_pb.EnableMovementFailedMessage, metadata?: grpcWeb.Metadata | null): Promise; scheduleTimeoutRight( - request: google_protobuf_empty_pb.Empty, + request: point_pb.EnableMovementFailedMessage, metadata: grpcWeb.Metadata | null, callback: (err: grpcWeb.RpcError, response: google_protobuf_empty_pb.Empty) => void): grpcWeb.ClientReadableStream; scheduleTimeoutRight( - request: google_protobuf_empty_pb.Empty, + request: point_pb.EnableMovementFailedMessage, metadata?: grpcWeb.Metadata | null, callback?: (err: grpcWeb.RpcError, response: google_protobuf_empty_pb.Empty) => void) { @@ -473,26 +473,26 @@ export class PointClient { methodDescriptorScheduleTimeoutLeft = new grpcWeb.MethodDescriptor( '/point.Point/ScheduleTimeoutLeft', grpcWeb.MethodType.UNARY, + point_pb.EnableMovementFailedMessage, google_protobuf_empty_pb.Empty, - google_protobuf_empty_pb.Empty, - (request: google_protobuf_empty_pb.Empty) => { + (request: point_pb.EnableMovementFailedMessage) => { return request.serializeBinary(); }, google_protobuf_empty_pb.Empty.deserializeBinary ); scheduleTimeoutLeft( - request: google_protobuf_empty_pb.Empty, + request: point_pb.EnableMovementFailedMessage, metadata?: grpcWeb.Metadata | null): Promise; scheduleTimeoutLeft( - request: google_protobuf_empty_pb.Empty, + request: point_pb.EnableMovementFailedMessage, metadata: grpcWeb.Metadata | null, callback: (err: grpcWeb.RpcError, response: google_protobuf_empty_pb.Empty) => void): grpcWeb.ClientReadableStream; scheduleTimeoutLeft( - request: google_protobuf_empty_pb.Empty, + request: point_pb.EnableMovementFailedMessage, metadata?: grpcWeb.Metadata | null, callback?: (err: grpcWeb.RpcError, response: google_protobuf_empty_pb.Empty) => void) { diff --git a/src/Point/rasta-point-web/src/proto/point_pb.d.ts b/src/Point/rasta-point-web/src/proto/point_pb.d.ts index 120e837..5aaff10 100644 --- a/src/Point/rasta-point-web/src/proto/point_pb.d.ts +++ b/src/Point/rasta-point-web/src/proto/point_pb.d.ts @@ -81,6 +81,24 @@ export namespace DegradedPositionMessage { } } +export class EnableMovementFailedMessage extends jspb.Message { + getEnablemovementfailed(): boolean; + setEnablemovementfailed(value: boolean): EnableMovementFailedMessage; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): EnableMovementFailedMessage.AsObject; + static toObject(includeInstance: boolean, msg: EnableMovementFailedMessage): EnableMovementFailedMessage.AsObject; + static serializeBinaryToWriter(message: EnableMovementFailedMessage, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): EnableMovementFailedMessage; + static deserializeBinaryFromReader(message: EnableMovementFailedMessage, reader: jspb.BinaryReader): EnableMovementFailedMessage; +} + +export namespace EnableMovementFailedMessage { + export type AsObject = { + enablemovementfailed: boolean, + } +} + export class PointPositionMessage extends jspb.Message { getPosition(): PointPosition; setPosition(value: PointPosition): PointPositionMessage; diff --git a/src/Point/rasta-point-web/src/proto/point_pb.js b/src/Point/rasta-point-web/src/proto/point_pb.js index fa2e879..8242a32 100644 --- a/src/Point/rasta-point-web/src/proto/point_pb.js +++ b/src/Point/rasta-point-web/src/proto/point_pb.js @@ -26,6 +26,7 @@ goog.object.extend(proto, google_protobuf_empty_pb); goog.exportSymbol('proto.point.AbilityToMove', null, global); goog.exportSymbol('proto.point.AbilityToMoveMessage', null, global); goog.exportSymbol('proto.point.DegradedPositionMessage', null, global); +goog.exportSymbol('proto.point.EnableMovementFailedMessage', null, global); goog.exportSymbol('proto.point.PointDegradedPosition', null, global); goog.exportSymbol('proto.point.PointDegradedPositionMessage', null, global); goog.exportSymbol('proto.point.PointPosition', null, global); @@ -117,6 +118,27 @@ if (goog.DEBUG && !COMPILED) { */ proto.point.DegradedPositionMessage.displayName = 'proto.point.DegradedPositionMessage'; } +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.point.EnableMovementFailedMessage = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.point.EnableMovementFailedMessage, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.point.EnableMovementFailedMessage.displayName = 'proto.point.EnableMovementFailedMessage'; +} /** * Generated by JsPbCodeGenerator. * @param {Array=} opt_data Optional initial data array, typically from a @@ -736,6 +758,136 @@ proto.point.DegradedPositionMessage.prototype.setDegradedposition = function(val +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.point.EnableMovementFailedMessage.prototype.toObject = function(opt_includeInstance) { + return proto.point.EnableMovementFailedMessage.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.point.EnableMovementFailedMessage} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.point.EnableMovementFailedMessage.toObject = function(includeInstance, msg) { + var f, obj = { + enablemovementfailed: jspb.Message.getBooleanFieldWithDefault(msg, 1, false) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.point.EnableMovementFailedMessage} + */ +proto.point.EnableMovementFailedMessage.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.point.EnableMovementFailedMessage; + return proto.point.EnableMovementFailedMessage.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.point.EnableMovementFailedMessage} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.point.EnableMovementFailedMessage} + */ +proto.point.EnableMovementFailedMessage.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {boolean} */ (reader.readBool()); + msg.setEnablemovementfailed(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.point.EnableMovementFailedMessage.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.point.EnableMovementFailedMessage.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.point.EnableMovementFailedMessage} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.point.EnableMovementFailedMessage.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getEnablemovementfailed(); + if (f) { + writer.writeBool( + 1, + f + ); + } +}; + + +/** + * optional bool enableMovementFailed = 1; + * @return {boolean} + */ +proto.point.EnableMovementFailedMessage.prototype.getEnablemovementfailed = function() { + return /** @type {boolean} */ (jspb.Message.getBooleanFieldWithDefault(this, 1, false)); +}; + + +/** + * @param {boolean} value + * @return {!proto.point.EnableMovementFailedMessage} returns this + */ +proto.point.EnableMovementFailedMessage.prototype.setEnablemovementfailed = function(value) { + return jspb.Message.setProto3BooleanField(this, 1, value); +}; + + + + + if (jspb.Message.GENERATE_TO_OBJECT) { /** * Creates an object representation of this proto. diff --git a/src/Point/rasta-point-web/tailwind.config.js b/src/Point/rasta-point-web/tailwind.config.js new file mode 100644 index 0000000..c0958ec --- /dev/null +++ b/src/Point/rasta-point-web/tailwind.config.js @@ -0,0 +1,11 @@ +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: [ + "./src/**/*.{js,jsx,ts,tsx}", + ], + theme: { + extend: {}, + }, + plugins: [], +} + diff --git a/src/ProtobufInterfaces/proto/point.proto b/src/ProtobufInterfaces/proto/point.proto index 767f08c..d182c83 100644 --- a/src/ProtobufInterfaces/proto/point.proto +++ b/src/ProtobufInterfaces/proto/point.proto @@ -38,8 +38,8 @@ service Point { rpc SchedulePreventRightEndPosition (PreventedPositionMessage) returns (google.protobuf.Empty) {} rpc SchedulePreventLeftEndPosition (PreventedPositionMessage) returns (google.protobuf.Empty) {} - rpc ScheduleTimeoutRight (google.protobuf.Empty) returns (google.protobuf.Empty) {} - rpc ScheduleTimeoutLeft (google.protobuf.Empty) returns (google.protobuf.Empty) {} + rpc ScheduleTimeoutRight (EnableMovementFailedMessage) returns (google.protobuf.Empty) {} + rpc ScheduleTimeoutLeft (EnableMovementFailedMessage) returns (google.protobuf.Empty) {} rpc Reset (google.protobuf.Empty) returns (google.protobuf.Empty) {} } @@ -49,7 +49,7 @@ enum AbilityToMove { UNABLE_TO_MOVE = 1; } -message AbilityToMoveMessage{ +message AbilityToMoveMessage { AbilityToMove ability = 1; } @@ -66,6 +66,10 @@ message DegradedPositionMessage { bool degradedPosition = 1; } +message EnableMovementFailedMessage { + bool enableMovementFailed = 1; +} + message PointPositionMessage { PointPosition position = 1; }