diff --git a/elevator/Elevator.Tests/Elevator.Tests/Elevator.Tests.csproj b/elevator/Elevator.Tests/Elevator.Tests/Elevator.Tests.csproj new file mode 100644 index 0000000..3e28147 --- /dev/null +++ b/elevator/Elevator.Tests/Elevator.Tests/Elevator.Tests.csproj @@ -0,0 +1,18 @@ + + + + net5.0 + + + + + + + + + + + + + + diff --git a/elevator/Elevator.Tests/Elevator.Tests/TestRunProgram.cs b/elevator/Elevator.Tests/Elevator.Tests/TestRunProgram.cs new file mode 100644 index 0000000..5a4235c --- /dev/null +++ b/elevator/Elevator.Tests/Elevator.Tests/TestRunProgram.cs @@ -0,0 +1,89 @@ +using Elevator.Domain; +using NUnit.Framework; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Elevator.Tests +{ + [TestFixture] + public class TestRunProgram + { + private List Floors { get; set; } + [SetUp] + public void SetUp() + { + Floors = new List() { + new Floor(0), + new Floor(1), + new Floor(2), + new Floor(3), + new Floor(4), + new Floor(5), + new Floor(6), + new Floor(7), + new Floor(8), + new Floor(9), + new Floor(10) + }; + } + + // Invalid Tests + [TestCase("-1", true, nameof(Floor))] + [TestCase("11", true, nameof(Floor))] + [TestCase("u", true, nameof(Floor))] + [TestCase("U", true, nameof(Floor))] + [TestCase("10 q", true, nameof(Direction))] + [TestCase("11 u", true, nameof(Floor))] + [TestCase("-2 u", true, nameof(Floor))] + [TestCase("10u", true, nameof(Floor))] + [TestCase("10u 30", true, nameof(Floor))] + [TestCase("3 party", true, nameof(Direction))] + // Valid internal button press + [TestCase("q", false, null)] + [TestCase("1", false, null)] + [TestCase("10", false, null)] + [TestCase("10", false, null)] + // Valid external button press + [TestCase("10 d", false, null)] + [TestCase("10 D", false, null)] + [TestCase("10 u", false, null)] + [TestCase("10 U", false, null)] + [TestCase("5 U", false, null)] + [TestCase("5 D", false, null)] + [TestCase(" 5 D ", false, null)] + public void TestProcessInput(string input, bool expectedError, string errorMessage) + { + var program = new RunProgram(); + var result = program.ProcessInput(input, Floors); + Assert.AreEqual(expectedError, result.HasError); + Assert.AreEqual(errorMessage, result.ErrorMessage); + } + + [Test] + public void TestFloorExternalButtonPress_5D() + { + var program = new RunProgram(); + var result = program.ProcessInput("5 d", Floors); + Assert.IsFalse(result.HasError); + Assert.True(Floors[5].DownButtonPressed); + } + + [Test] + public void TestFloorExternalButtonPress_5U() + { + var program = new RunProgram(); + var result = program.ProcessInput("5 u", Floors); + Assert.IsFalse(result.HasError); + Assert.True(Floors[5].UpButtonPressed); + } + + [Test] + public void TestFloorInternalButtonPress_5() + { + var program = new RunProgram(); + var result = program.ProcessInput("5", Floors); + Assert.IsFalse(result.HasError); + Assert.True(Floors[5].InternalButtonPress); + } + } +} diff --git a/elevator/Elevator/Elevator.Domain.Tests/Elevator.Domain.Tests.csproj b/elevator/Elevator/Elevator.Domain.Tests/Elevator.Domain.Tests.csproj new file mode 100644 index 0000000..aa539bf --- /dev/null +++ b/elevator/Elevator/Elevator.Domain.Tests/Elevator.Domain.Tests.csproj @@ -0,0 +1,17 @@ + + + + net5.0 + + + + + + + + + + + + + diff --git a/elevator/Elevator/Elevator.Domain.Tests/TestElevator.cs b/elevator/Elevator/Elevator.Domain.Tests/TestElevator.cs new file mode 100644 index 0000000..63bb573 --- /dev/null +++ b/elevator/Elevator/Elevator.Domain.Tests/TestElevator.cs @@ -0,0 +1,146 @@ +using NUnit.Framework; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Elevator.Domain.Tests +{ + [TestFixture] + public class TestElevator + { + private List Floors { get; set; } + [SetUp] + public void SetUp() + { + Floors = new List() { + new Floor(0), + new Floor(1), + new Floor(2), + new Floor(3), + new Floor(4), + new Floor(5), + new Floor(6), + new Floor(7), + new Floor(8), + new Floor(9), + new Floor(10) + }; + } + + [Test] + public async Task Test_DirectionChangeABottom() + { + var elevator = new Elevator(Floors, 0, Direction.Down); + await elevator.EvaulateFloors(); + Assert.AreEqual(Direction.Up, elevator.Direction); + } + + [Test] + public async Task Test_DirectionChangeATop() + { + var elevator = new Elevator(Floors, 10, Direction.Up); + await elevator.EvaulateFloors(); + Assert.AreEqual(Direction.Down, elevator.Direction); + } + + [TestCase(0, 1)] + [TestCase(1, 2)] + [TestCase(10, 10)] + public async Task Test_GoingUp(int currentFloor, int expected) + { + var elevator = new Elevator(Floors, currentFloor, Direction.Up); + await elevator.EvaulateFloors(); + Assert.AreEqual(expected, elevator.CurrentFloor); + } + + [TestCase(0, 0)] + [TestCase(2, 1)] + [TestCase(10, 9)] + public async Task Test_GoingDown(int currentFloor, int expected) + { + var elevator = new Elevator(Floors, currentFloor, Direction.Down); + await elevator.EvaulateFloors(); + Assert.AreEqual(expected, elevator.CurrentFloor); + } + + [Test] + public async Task Test_DownButtonPress_GoingDown() + { + Floors[3].ButtonPressed("d"); + var elevator = new Elevator(Floors, 3, Direction.Down); + await elevator.EvaulateFloors(); + Assert.AreEqual(false, Floors[3].DownButtonPressed); + } + + [Test] + public async Task Test_UpButtonPress_GoingDown() + { + Floors[3].ButtonPressed("u"); + var elevator = new Elevator(Floors, 3, Direction.Down); + await elevator.EvaulateFloors(); + Assert.AreEqual(true, Floors[3].UpButtonPressed); + } + + [Test] + public async Task Test_UpButtonPress_GoingUp() + { + Floors[3].ButtonPressed("u"); + var elevator = new Elevator(Floors, 3, Direction.Up); + await elevator.EvaulateFloors(); + Assert.AreEqual(false, Floors[3].UpButtonPressed); + } + + [Test] + public async Task Test_DownButtonPress_GoingUp() + { + Floors[3].ButtonPressed("d"); + var elevator = new Elevator(Floors, 3, Direction.Up); + await elevator.EvaulateFloors(); + Assert.AreEqual(true, Floors[3].DownButtonPressed); + } + + [Test] + public async Task Test_ButtonPressFromInside_GoingUp() + { + Floors[3].ButtonPressedFromElevator(); + var elevator = new Elevator(Floors, 3, Direction.Up); + await elevator.EvaulateFloors(); + Assert.AreEqual(false, Floors[3].InternalButtonPress); + } + + [Test] + public async Task Test_ButtonPressFromInside_GoingDown() + { + Floors[3].ButtonPressedFromElevator(); + var elevator = new Elevator(Floors, 3, Direction.Down); + await elevator.EvaulateFloors(); + Assert.AreEqual(false, Floors[3].InternalButtonPress); + } + + + [Test] + public async Task Test_CheckingWhileGoingUp() + { + Floors[3].ButtonPressed("u"); + var elevator = new Elevator(Floors, 2, Direction.Up); + + await elevator.EvaulateFloors(); + Assert.AreEqual(true, Floors[3].UpButtonPressed); + + await elevator.EvaulateFloors(); + Assert.AreEqual(false, Floors[3].UpButtonPressed); + + await elevator.EvaulateFloors(); + Assert.AreEqual(false, Floors[3].UpButtonPressed); + } + + [Test] + public async Task Test_StopLongestPath() + { + Floors[3].ButtonPressed("u"); + var elevator = new Elevator(Floors, 4, Direction.Up); + + await elevator.Stop(); + Assert.AreEqual(false, Floors[3].UpButtonPressed); + } + } +} diff --git a/elevator/Elevator/Elevator.Domain/Direction.cs b/elevator/Elevator/Elevator.Domain/Direction.cs new file mode 100644 index 0000000..3d69b89 --- /dev/null +++ b/elevator/Elevator/Elevator.Domain/Direction.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Elevator.Domain +{ + public enum Direction + { + Down = -1, + Stopped = 0, + Up = 1 + } +} diff --git a/elevator/Elevator/Elevator.Domain/Elevator.Domain.csproj b/elevator/Elevator/Elevator.Domain/Elevator.Domain.csproj new file mode 100644 index 0000000..f208d30 --- /dev/null +++ b/elevator/Elevator/Elevator.Domain/Elevator.Domain.csproj @@ -0,0 +1,7 @@ + + + + net5.0 + + + diff --git a/elevator/Elevator/Elevator.Domain/Elevator.cs b/elevator/Elevator/Elevator.Domain/Elevator.cs new file mode 100644 index 0000000..b1d0b11 --- /dev/null +++ b/elevator/Elevator/Elevator.Domain/Elevator.cs @@ -0,0 +1,159 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace Elevator.Domain +{ + public class Elevator + { + private readonly int MAX_LIMIT = 20; + + private ILogging Logging; + private List Floors; + + public int CurrentFloor { get; private set; } = 0; + public Direction Direction { get; set; } = Direction.Stopped; + + // TODO: When someone enters the elevator, increase this value + // When someone presses a button from the inside, decrease this value + // if max limit reach, dont stop at any external floor requests + public int Occupancy { get; private set; } = 0; + + public Elevator(List floors) + { + Logging = new Logging(); + Floors = floors; + } + + public Elevator(List floors, int currentFloor, Direction dir) + { + Logging = new Logging(); + Floors = floors; + CurrentFloor = currentFloor; + Direction = dir; + } + + public async Task EvaulateFloors() + { + Logging.Log($"Checking Floors, current: {CurrentFloor}"); + var opened = await CheckFloors(); + if (Direction == Direction.Up) + { + if (CurrentFloor == Floors.Count - 1) + { + Logging.LogWithTime("We reached the top; go down."); + Direction = Direction.Down; + return; + } + Logging.LogWithTime($"Passing Floor: {CurrentFloor}"); + CurrentFloor++; + } + if (Direction == Direction.Down) + { + if (CurrentFloor == 0) + { + Logging.LogWithTime($"We reached the Bottom; go down."); + Direction = Direction.Up; + return; + } + Logging.LogWithTime($"Passing Floor: {CurrentFloor}"); + CurrentFloor--; + } + // task sleeps for a second based on if it was open + await Task.Delay(3000); + } + + private async Task CheckFloors() + { + if (await CheckInternalButtonPress()) + { + return true; + } + + if (await CheckGoingUp()) + { + return true; + } + + if (await CheckGoingDown()) + { + return true; + } + return false; + } + + + private async Task StopElevatorForASecond() + { + Logging.LogWithTime($"Stopping at Floor: {CurrentFloor}"); + var currentState = this.Direction; + this.Direction = Direction.Stopped; + await Task.Delay(1000); + this.Direction = currentState; + } + + private async Task CheckGoingDown() + { + if (Floors.Any(f => f.Level == CurrentFloor && Direction == Direction.Down && f.DownButtonPressed)) + { + var f = Floors.First(f => f.Level == CurrentFloor && Direction == Direction.Down && f.DownButtonPressed); + await StopElevatorForASecond(); + f.ClearFloor(); + return true; + } + return false; + } + + private async Task CheckGoingUp() + { + if (Floors.Any(f => f.Level == CurrentFloor && Direction == Direction.Up && f.UpButtonPressed)) + { + var f = Floors.First(f => f.Level == CurrentFloor && Direction == Direction.Up && f.UpButtonPressed); + await StopElevatorForASecond(); + f.ClearFloor(); + return true; + } + return false; + } + + private async Task CheckInternalButtonPress() + { + if (Floors.Any(f => f.Level == CurrentFloor && f.InternalButtonPress)) + { + var f = Floors.First(f => f.Level == CurrentFloor && f.InternalButtonPress); + await StopElevatorForASecond(); + f.ClearFloor(); + return true; + } + return false; + } + + public async Task Stop() + { + Logging.LogWithTime("Elevator Stopping, checking all the floors"); + + // Everyone must get off of the elevator before it stops + while (Floors.Any(f => f.DownButtonPressed || f.UpButtonPressed || f.InternalButtonPress)) + { + await EvaulateFloors(); + } + Logging.LogWithTime("Elevator Stopped"); + this.CurrentFloor = 0; + this.Direction = Direction.Stopped; + this.Occupancy = 0; + } + + public async void Start(CancellationToken token) + { + Logging.Log("Elevator Started, Going UP!"); + Direction = Direction.Up; + while (!token.IsCancellationRequested) + { + await EvaulateFloors(); + } + Logging.Log("Elevator canceled"); + } + } +} diff --git a/elevator/Elevator/Elevator.Domain/Floor.cs b/elevator/Elevator/Elevator.Domain/Floor.cs new file mode 100644 index 0000000..d2a985f --- /dev/null +++ b/elevator/Elevator/Elevator.Domain/Floor.cs @@ -0,0 +1,61 @@ +using System; + +namespace Elevator.Domain +{ + public class Floor + { + private ILogging logging; + public int Level { get; set; } + public bool DownButtonPressed { get; private set; } + public bool UpButtonPressed { get; private set; } + public bool InternalButtonPress { get; private set; } + + public Floor(int location) + { + this.Level = location; + logging = new Logging(); + } + + private void GoDown() + { + logging.LogWithTime($"Level {Level} needs to go down"); + this.DownButtonPressed = true; + } + + private void GoUp() + { + logging.LogWithTime($"Level {Level} needs to go up"); + this.UpButtonPressed = true; + } + + public void ClearFloor() + { + DownButtonPressed = false; + UpButtonPressed = false; + InternalButtonPress = false; + } + + public void ButtonPressedFromElevator() + { + logging.LogWithTime($"Button Pressed from inside of the elevator for Level: {this.Level}"); + InternalButtonPress = true; + } + + public void ButtonPressed(string direction) + { + switch (direction.ToLowerInvariant()) + { + case "u": + GoUp(); + break; + case "d": + GoDown(); + break; + default: + Console.WriteLine("Congrats, you broke it!"); + return; + + } + } + } +} diff --git a/elevator/Elevator/Elevator.Domain/ILogging.cs b/elevator/Elevator/Elevator.Domain/ILogging.cs new file mode 100644 index 0000000..c672996 --- /dev/null +++ b/elevator/Elevator/Elevator.Domain/ILogging.cs @@ -0,0 +1,8 @@ +namespace Elevator.Domain +{ + public interface ILogging + { + void Log(string message); + void LogWithTime(string message); + } +} \ No newline at end of file diff --git a/elevator/Elevator/Elevator.Domain/Logging.cs b/elevator/Elevator/Elevator.Domain/Logging.cs new file mode 100644 index 0000000..17404dc --- /dev/null +++ b/elevator/Elevator/Elevator.Domain/Logging.cs @@ -0,0 +1,17 @@ +using System; + +namespace Elevator.Domain +{ + public class Logging : ILogging + { + public void Log(string message) + { + Console.WriteLine(message); + } + + public void LogWithTime(string message) + { + Console.WriteLine($"{DateTime.Now} - {message}"); + } + } +} diff --git a/elevator/Elevator/Elevator.sln b/elevator/Elevator/Elevator.sln new file mode 100644 index 0000000..2d04616 --- /dev/null +++ b/elevator/Elevator/Elevator.sln @@ -0,0 +1,43 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.31702.278 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elevator", "Evelator\Elevator.csproj", "{1C055870-224B-4A83-8B1C-BE48986A87FB}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elevator.Domain", "Elevator.Domain\Elevator.Domain.csproj", "{6346D5D8-14A8-4249-B73B-32DAE340289A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elevator.Domain.Tests", "Elevator.Domain.Tests\Elevator.Domain.Tests.csproj", "{0D082F2A-A620-4474-8E4B-254F627DBB82}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elevator.Tests", "..\Elevator.Tests\Elevator.Tests\Elevator.Tests.csproj", "{28E8A477-44A1-44D6-A0E8-4DF9781A76A3}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {1C055870-224B-4A83-8B1C-BE48986A87FB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1C055870-224B-4A83-8B1C-BE48986A87FB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1C055870-224B-4A83-8B1C-BE48986A87FB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1C055870-224B-4A83-8B1C-BE48986A87FB}.Release|Any CPU.Build.0 = Release|Any CPU + {6346D5D8-14A8-4249-B73B-32DAE340289A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6346D5D8-14A8-4249-B73B-32DAE340289A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6346D5D8-14A8-4249-B73B-32DAE340289A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6346D5D8-14A8-4249-B73B-32DAE340289A}.Release|Any CPU.Build.0 = Release|Any CPU + {0D082F2A-A620-4474-8E4B-254F627DBB82}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0D082F2A-A620-4474-8E4B-254F627DBB82}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0D082F2A-A620-4474-8E4B-254F627DBB82}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0D082F2A-A620-4474-8E4B-254F627DBB82}.Release|Any CPU.Build.0 = Release|Any CPU + {28E8A477-44A1-44D6-A0E8-4DF9781A76A3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {28E8A477-44A1-44D6-A0E8-4DF9781A76A3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {28E8A477-44A1-44D6-A0E8-4DF9781A76A3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {28E8A477-44A1-44D6-A0E8-4DF9781A76A3}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {987F774B-8EEE-4042-9CFD-484E4F63F3D8} + EndGlobalSection +EndGlobal diff --git a/elevator/Elevator/Evelator/Elevator.csproj b/elevator/Elevator/Evelator/Elevator.csproj new file mode 100644 index 0000000..a45ebf0 --- /dev/null +++ b/elevator/Elevator/Evelator/Elevator.csproj @@ -0,0 +1,12 @@ + + + + Exe + net5.0 + + + + + + + diff --git a/elevator/Elevator/Evelator/Program.cs b/elevator/Elevator/Evelator/Program.cs new file mode 100644 index 0000000..b59f838 --- /dev/null +++ b/elevator/Elevator/Evelator/Program.cs @@ -0,0 +1,18 @@ +using System.Threading.Tasks; + +namespace Elevator +{ + public class Program + { + public static void Main(string[] args) + { + MainAsync().Wait(); + } + + private static async Task MainAsync() + { + var run = new RunProgram(); + await run.Run(); + } + } +} diff --git a/elevator/Elevator/Evelator/RunProgram.cs b/elevator/Elevator/Evelator/RunProgram.cs new file mode 100644 index 0000000..5dc3791 --- /dev/null +++ b/elevator/Elevator/Evelator/RunProgram.cs @@ -0,0 +1,131 @@ +using Elevator.Domain; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace Elevator +{ + public class RunProgram + { + private ILogging logging; + private List floors { get; set; } + public RunProgram() + { + floors = CreateFloors(); + logging = new Logging(); + logging.Log("Enter a floor command: ie. (5 u = 5th floor, up button pressed)"); + logging.Log("Enter a elevator command: ie. (5 = stop at 5th floor)"); + } + + public async Task Run() + { + var input = ""; + var elevator = new Elevator.Domain.Elevator(floors); + CancellationTokenSource source = new CancellationTokenSource(); + await Task.Run(() => elevator.Start(source.Token)); + while (input.ToLowerInvariant() != "q") + { + input = Console.ReadLine().Trim(); + + ProcessInput(input, floors); + } + source.Cancel(); + await elevator.Stop(); + Console.ReadLine(); + } + + public TaskResult ProcessInput(string input, List floors) + { + input = input.Trim(); + if (input.Equals("q")) + { + return TaskResult.Success(); + } + if (!input.Contains(" ")) + { + if (IsFloorValid(input)) + { + var buttonPressedInside = floors.First(f => f.Level == int.Parse(input)); + buttonPressedInside.ButtonPressedFromElevator(); + } + else + { + logging.Log("Invalid Floor: 0 - 10 plz."); + return TaskResult.Error(nameof(Floor)); + } + } + else if (input.Contains(" ")) + { + try + { + var temp = input.Split(" "); + var floor = temp[0].Trim(); + var direction = temp[1].Trim(); + var result = IsValidInput(floor, direction); + if (!result.HasError) + { + var selectedFloor = floors.First(f => f.Level == int.Parse(floor)); + selectedFloor.ButtonPressed(direction); + } + else + { + return result; + } + } + catch (Exception ex) + { + return TaskResult.Error("Directions unclear"); + } + } + else + { + logging.Log("Follow directions plz"); + return TaskResult.Error("Directions unclear"); + } + return TaskResult.Success(); + } + + private TaskResult IsValidInput(string floor, string direction) + { + if (!IsFloorValid(floor)) + { + logging.Log("Invalid Floor: 0 - 10 plz."); + return TaskResult.Error(nameof(Floor)); + } + if (!ProcessDirection(direction)) + { + logging.Log("Invalid Direction: or plz."); + return TaskResult.Error(nameof(Direction)); + } + return TaskResult.Success(); + } + + private bool IsFloorValid(string floor) + { + return int.TryParse(floor, out var f) && (f >= 0 && f < 11); + } + private bool ProcessDirection(string direction) + { + return direction.ToLowerInvariant().Equals("u") || direction.ToLowerInvariant().Equals("d"); + } + + private List CreateFloors() + { + return new List() { + new Floor(0), + new Floor(1), + new Floor(2), + new Floor(3), + new Floor(4), + new Floor(5), + new Floor(6), + new Floor(7), + new Floor(8), + new Floor(9), + new Floor(10) + }; + } + } +} diff --git a/elevator/Elevator/Evelator/TaskResult.cs b/elevator/Elevator/Evelator/TaskResult.cs new file mode 100644 index 0000000..3a09055 --- /dev/null +++ b/elevator/Elevator/Evelator/TaskResult.cs @@ -0,0 +1,23 @@ +namespace Elevator +{ + public class TaskResult + { + public readonly bool HasError; + public readonly string ErrorMessage; + protected TaskResult(bool hasError, string errorMessage) + { + HasError = hasError; + ErrorMessage = errorMessage; + } + + public static TaskResult Error(string errorMesasge) + { + return new TaskResult(true, errorMesasge); + } + + public static TaskResult Success() + { + return new TaskResult(false, null); + } + } +}