diff --git a/Pepperdash Core/Pepperdash Core.suo b/Pepperdash Core/Pepperdash Core.suo index ad2f91d..9d55ea5 100644 Binary files a/Pepperdash Core/Pepperdash Core.suo and b/Pepperdash Core/Pepperdash Core.suo differ diff --git a/Pepperdash Core/Pepperdash Core/Comm/DynamicTCPClient.cs b/Pepperdash Core/Pepperdash Core/Comm/DynamicTCPClient.cs new file mode 100644 index 0000000..08b6ba8 --- /dev/null +++ b/Pepperdash Core/Pepperdash Core/Comm/DynamicTCPClient.cs @@ -0,0 +1,371 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using Crestron.SimplSharp; +using Crestron.SimplSharp.CrestronSockets; +using PepperDash.Core; + +namespace PepperDash.Core +{ + public class DynamicTcpClient : Device, ISocketStatus, IAutoReconnect + { + #region Events + + public event EventHandler BytesReceived; + + public event EventHandler TextReceived; + + public event EventHandler ConnectionChange; + + #endregion + + #region Properties & Variables + /// + /// Address of server + /// + public string Hostname { get; set; } + + /// + /// Port on server + /// + public int Port { get; set; } + + /// + /// S+ helper + /// + public ushort UPort + { + get { return Convert.ToUInt16(Port); } + set { Port = Convert.ToInt32(value); } + } + + /// + /// Bool to show whether the server requires a preshared key. This is used in the DynamicTCPServer class + /// + public bool RequiresPresharedKey { get; set; } + + /// + /// S+ helper for requires shared key bool + /// + public ushort uRequiresPresharedKey + { + set + { + if (value == 1) + RequiresPresharedKey = true; + else + RequiresPresharedKey = false; + } + } + + /// + /// SharedKey is sent for varification to the server. Shared key can be any text (255 char limit in SIMPL+ Module), but must match the Shared Key on the Server module + /// + public string SharedKey { get; set; } + + /// + /// flag to show the client is waiting for the server to send the shared key + /// + private bool WaitingForSharedKeyResponse { get; set; } + + /// + /// Defaults to 2000 + /// + public int BufferSize { get; set; } + + /// + /// Bool showing if socket is connected + /// + public bool IsConnected + { + get { return Client != null && Client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED; } + } + + /// + /// S+ helper for IsConnected + /// + public ushort UIsConnected + { + get { return (ushort)(IsConnected ? 1 : 0); } + } + + /// + /// Client socket status Read only + /// + public SocketStatus ClientStatus + { + get + { + if (Client == null) + return SocketStatus.SOCKET_STATUS_NO_CONNECT; + return Client.ClientStatus; + } + } + + /// + /// Contains the familiar Simpl analog status values. This drives the ConnectionChange event + /// and IsConnected would be true when this == 2. + /// + public ushort UStatus + { + get { return (ushort)ClientStatus; } + } + + /// + /// Status text shows the message associated with socket status + /// + public string ClientStatusText { get { return ClientStatus.ToString(); } } + + /// + /// bool to track if auto reconnect should be set on the socket + /// + public bool AutoReconnect { get; set; } + + /// + /// S+ helper for AutoReconnect + /// + public ushort UAutoReconnect + { + get { return (ushort)(AutoReconnect ? 1 : 0); } + set { AutoReconnect = value == 1; } + } + /// + /// Milliseconds to wait before attempting to reconnect. Defaults to 5000 + /// + public int AutoReconnectIntervalMs { get; set; } + + /// + /// Flag Set only when the disconnect method is called. + /// + bool DisconnectCalledByUser; + + /// + /// Connected bool + /// + public bool Connected + { + get { return Client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED; } + } + + CTimer RetryTimer; //private Timer for auto reconnect + + public SecureTCPClient Client; //Secure Client Class + + #endregion + + #region Constructors + + //Base class constructor + public DynamicTcpClient(string key, string address, int port, int bufferSize) + : base(key) + { + Hostname = address; + Port = port; + BufferSize = bufferSize; + AutoReconnectIntervalMs = 5000; + } + + //base class constructor + public DynamicTcpClient() + : base("Uninitialized SecureTcpClient") + { + CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); + AutoReconnectIntervalMs = 5000; + BufferSize = 2000; + } + #endregion + + #region Methods + /// + /// Just to help S+ set the key + /// + public void Initialize(string key) + { + Key = key; + } + + /// + /// Handles closing this up when the program shuts down + /// + void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType) + { + if (programEventType == eProgramStatusEventType.Stopping) + { + if (Client != null) + { + Debug.Console(1, this, "Program stopping. Closing connection"); + Client.DisconnectFromServer(); + Client.Dispose(); + } + } + } + + /// + /// Deactivate the client. Unregisters the socket status change event and returns true. + /// + /// + public override bool Deactivate() + { + if(Client != null) + Client.SocketStatusChange -= this.Client_SocketStatusChange; + return true; + } + + /// + /// Connect Method. Will return if already connected. Will write errors if missing address, port, or unique key/name. + /// + public void Connect() + { + if (IsConnected) + return; + + if (string.IsNullOrEmpty(Hostname)) + { + Debug.Console(1, Debug.ErrorLogLevel.Warning, "GenericSecureTcpClient '{0}': No address set", Key); + ErrorLog.Warn(string.Format("GenericSecureTcpClient '{0}': No address set", Key)); + return; + } + if (Port < 1 || Port > 65535) + { + Debug.Console(1, Debug.ErrorLogLevel.Warning, "GenericSecureTcpClient '{0}': Invalid port", Key); + ErrorLog.Warn(string.Format("GenericSecureTcpClient '{0}': Invalid port", Key)); + return; + } + if (string.IsNullOrEmpty(SharedKey) && RequiresPresharedKey) + { + Debug.Console(1, Debug.ErrorLogLevel.Warning, "GenericSecureTcpClient '{0}': No Shared Key set", Key); + ErrorLog.Warn(string.Format("GenericSecureTcpClient '{0}': No Shared Key set", Key)); + return; + } + Client = new SecureTCPClient(Hostname, Port, BufferSize); + Client.SocketStatusChange += Client_SocketStatusChange; + try + { + DisconnectCalledByUser = false; + if(RequiresPresharedKey) + WaitingForSharedKeyResponse = true; + SocketErrorCodes error = Client.ConnectToServer(); + } + catch (Exception ex) + { + CrestronConsole.PrintLine("Secure Client could not connect. Error: {0}", ex.Message); + } + } + + /// + /// Disconnect client. Does not dispose. + /// + public void Disconnect() + { + DisconnectCalledByUser = true; + Client.DisconnectFromServer(); + } + + /// + /// callback after connection made + /// + /// + void ConnectToServerCallback(object o) + { + Client.ConnectToServer(); + if (Client.ClientStatus != SocketStatus.SOCKET_STATUS_CONNECTED) + WaitAndTryReconnect(); + } + + /// + /// Called from Socket Status change if auto reconnect and socket disconnected (Not disconnected by user) + /// + void WaitAndTryReconnect() + { + Client.DisconnectFromServer(); + Debug.Console(2, "Attempting reconnect, status={0}", Client.ClientStatus); + RetryTimer = new CTimer(ConnectToServerCallback, AutoReconnectIntervalMs); + } + + /// + /// Receive callback + /// + /// + /// + void Receive(SecureTCPClient client, int numBytes) + { + if (numBytes > 0) + { + var bytes = client.IncomingDataBuffer.Take(numBytes).ToArray(); + var str = Encoding.GetEncoding(28591).GetString(bytes, 0, bytes.Length); + if (WaitingForSharedKeyResponse && RequiresPresharedKey) + { + if (str != (SharedKey + "\n")) + { + WaitingForSharedKeyResponse = false; + Client.DisconnectFromServer(); + CrestronConsole.PrintLine("Client {0} was disconnected from server because the server did not respond with a matching shared key after connection", Key); + ErrorLog.Error("Client {0} was disconnected from server because the server did not respond with a matching shared key after connection", Key); + return; + } + else + { + WaitingForSharedKeyResponse = false; + CrestronConsole.PrintLine("Client {0} successfully connected to the server and received the Shared Key. Ready for communication", Key); + } + } + else + { + var bytesHandler = BytesReceived; + if (bytesHandler != null) + bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes)); + var textHandler = TextReceived; + if (textHandler != null) + { + + textHandler(this, new GenericCommMethodReceiveTextArgs(str)); + } + } + } + Client.ReceiveDataAsync(Receive); + } + + /// + /// General send method + /// + public void SendText(string text) + { + var bytes = Encoding.GetEncoding(28591).GetBytes(text); + Client.SendData(bytes, bytes.Length); + } + + public void SendBytes(byte[] bytes) + { + Client.SendData(bytes, bytes.Length); + } + + /// + /// SocketStatusChange Callback + /// + /// + /// + void Client_SocketStatusChange(SecureTCPClient client, SocketStatus clientSocketStatus) + { + Debug.Console(2, this, "Socket status change {0} ({1})", clientSocketStatus, ClientStatusText); + if (client.ClientStatus != SocketStatus.SOCKET_STATUS_CONNECTED && !DisconnectCalledByUser && AutoReconnect) + WaitAndTryReconnect(); + + // Probably doesn't need to be a switch since all other cases were eliminated + switch (clientSocketStatus) + { + case SocketStatus.SOCKET_STATUS_CONNECTED: + Client.ReceiveDataAsync(Receive); + SendText(SharedKey + "\n"); + DisconnectCalledByUser = false; + break; + } + + var handler = ConnectionChange; + if (handler != null) + ConnectionChange(this, new GenericSocketStatusChageEventArgs(this)); + } + #endregion + } +} \ No newline at end of file diff --git a/Pepperdash Core/Pepperdash Core/Comm/DynamicTCPServer.cs b/Pepperdash Core/Pepperdash Core/Comm/DynamicTCPServer.cs index ae37704..7a9765d 100644 --- a/Pepperdash Core/Pepperdash Core/Comm/DynamicTCPServer.cs +++ b/Pepperdash Core/Pepperdash Core/Comm/DynamicTCPServer.cs @@ -157,8 +157,8 @@ namespace PepperDash.Core private bool ServerStopped { get; set; } - public SecureTCPServer SecureServer; - public TCPServer UnsecureServer; + SecureTCPServer SecureServer; + TCPServer UnsecureServer; #endregion @@ -231,9 +231,9 @@ namespace PepperDash.Core public void StopListening() { Debug.Console(2, "Stopping Listener"); - if (SecureServer != null && SecureServer.State == ServerState.SERVER_LISTENING) + if (SecureServer != null) SecureServer.Stop(); - if (UnsecureServer != null && UnsecureServer.State == ServerState.SERVER_LISTENING) + if (UnsecureServer != null) UnsecureServer.Stop(); ServerStopped = true; onServerStateChange(); @@ -242,10 +242,11 @@ namespace PepperDash.Core public void DisconnectAllClients() { Debug.Console(2, "Disconnecting All Clients"); - if (SecureServer != null && SecureServer.NumberOfClientsConnected > 0) + if (SecureServer != null) SecureServer.DisconnectAll(); - if (UnsecureServer != null && UnsecureServer.NumberOfClientsConnected > 0) + if (UnsecureServer != null) UnsecureServer.DisconnectAll(); + onConnectionChange(); onServerStateChange(); //State shows both listening and connected } @@ -343,7 +344,7 @@ namespace PepperDash.Core } mySecureTCPServer.ReceiveDataAsync(clientIndex, SecureReceivedCallback); if (mySecureTCPServer.State != ServerState.SERVER_LISTENING && MaxClients > 1 && !ServerStopped) - SecureServer.WaitForConnectionAsync(IPAddress.Any, SecureConnectCallback); + mySecureTCPServer.WaitForConnectionAsync(IPAddress.Any, SecureConnectCallback); } } @@ -351,23 +352,30 @@ namespace PepperDash.Core { if (myTCPServer.ClientConnected(clientIndex)) { - Debug.Console(2, "Connected to client at {0}", myTCPServer.GetAddressServerAcceptedConnectionFromForSpecificClient(clientIndex)); + if (RequiresPresharedKey) + { + byte[] b = Encoding.GetEncoding(28591).GetBytes(SharedKey + "\n"); + myTCPServer.SendDataAsync(clientIndex, b, b.Length, UnsecureSendDataAsyncCallback); + Debug.Console(2, "Sent Shared Key to client at {0}", myTCPServer.GetAddressServerAcceptedConnectionFromForSpecificClient(clientIndex)); + } myTCPServer.ReceiveDataAsync(clientIndex, UnsecureReceivedCallback); + if (myTCPServer.State != ServerState.SERVER_LISTENING && MaxClients > 1 && !ServerStopped) + myTCPServer.WaitForConnectionAsync(IPAddress.Any, UnsecureConnectCallback); } if (myTCPServer.State != ServerState.SERVER_LISTENING && MaxClients > 1 && !ServerStopped) - UnsecureServer.WaitForConnectionAsync(IPAddress.Any, UnsecureConnectCallback); + myTCPServer.WaitForConnectionAsync(IPAddress.Any, UnsecureConnectCallback); } #endregion #region Methods - Send/Receive Callbacks void SecureSendDataAsyncCallback(SecureTCPServer mySecureTCPServer, uint clientIndex, int numberOfBytesSent) { - + //Seems there is nothing to do here } void UnsecureSendDataAsyncCallback(TCPServer myTCPServer, uint clientIndex, int numberOfBytesSent) { - + //Seems there is nothing to do here } void SecureReceivedCallback(SecureTCPServer mySecureTCPServer, uint clientIndex, int numberOfBytesReceived) @@ -415,10 +423,32 @@ namespace PepperDash.Core string received = "Nothing"; byte[] bytes = myTCPServer.GetIncomingDataBufferForSpecificClient(clientIndex); received = System.Text.Encoding.GetEncoding(28591).GetString(bytes, 0, numberOfBytesReceived); - Debug.Console(2, "Unsecure Server Listening on Port: {0}, client IP: {1}, NumberOfBytesReceived: {2}, Received: {3}\r\n", - myTCPServer.PortNumber, myTCPServer.AddressServerAcceptedConnectionFrom, numberOfBytesReceived, received); - myTCPServer.ReceiveDataAsync(UnsecureReceivedCallback); - onTextReceived(received); + if (WaitingForSharedKey.Contains(clientIndex)) + { + received = received.Replace("\r", ""); + received = received.Replace("\n", ""); + if (received != SharedKey) + { + byte[] b = Encoding.GetEncoding(28591).GetBytes("Shared key did not match server. Disconnecting"); + Debug.Console(2, "Client at index {0} Shared key did not match the server, disconnecting client", clientIndex); + ErrorLog.Error("Client at index {0} Shared key did not match the server, disconnecting client", clientIndex); + myTCPServer.SendDataAsync(clientIndex, b, b.Length, null); + myTCPServer.Disconnect(clientIndex); + } + if (myTCPServer.NumberOfClientsConnected > 0) + myTCPServer.ReceiveDataAsync(UnsecureReceivedCallback); + WaitingForSharedKey.Remove(clientIndex); + byte[] skResponse = Encoding.GetEncoding(28591).GetBytes("Shared Key Match, Connected and ready for communication"); + myTCPServer.SendDataAsync(clientIndex, skResponse, skResponse.Length, null); + myTCPServer.ReceiveDataAsync(UnsecureReceivedCallback); + } + else + { + myTCPServer.ReceiveDataAsync(UnsecureReceivedCallback); + Debug.Console(2, "Secure Server Listening on Port: {0}, client IP: {1}, NumberOfBytesReceived: {2}, Received: {3}\r\n", + myTCPServer.PortNumber, myTCPServer.AddressServerAcceptedConnectionFrom, numberOfBytesReceived, received); + onTextReceived(received); + } } if (myTCPServer.GetServerSocketStatusForSpecificClient(clientIndex) == SocketStatus.SOCKET_STATUS_CONNECTED) myTCPServer.ReceiveDataAsync(clientIndex, UnsecureReceivedCallback); diff --git a/Pepperdash Core/Pepperdash Core/Comm/EventArgs.cs b/Pepperdash Core/Pepperdash Core/Comm/EventArgs.cs index 89a3131..5e87bd3 100644 --- a/Pepperdash Core/Pepperdash Core/Comm/EventArgs.cs +++ b/Pepperdash Core/Pepperdash Core/Comm/EventArgs.cs @@ -24,40 +24,40 @@ namespace PepperDash.Core } #endregion - #region DynamicTCPServerStateChangedEventArgs - public delegate void DynamicTCPServerStateChangedEventDelegate(object server); + //#region DynamicTCPServerStateChangedEventArgs + //public delegate void DynamicTCPServerStateChangedEventDelegate(object server); - public class DynamicTCPServerStateChangedEventArgs : EventArgs - { - public bool Secure { get; private set; } - public object Server { get; private set; } + //public class DynamicTCPServerStateChangedEventArgs : EventArgs + //{ + // public bool Secure { get; private set; } + // public object Server { get; private set; } - public DynamicTCPServerStateChangedEventArgs() { } + // public DynamicTCPServerStateChangedEventArgs() { } - public DynamicTCPServerStateChangedEventArgs(object server, bool secure) - { - Secure = secure; - Server = server; - } - } - #endregion + // public DynamicTCPServerStateChangedEventArgs(object server, bool secure) + // { + // Secure = secure; + // Server = server; + // } + //} + //#endregion - #region DynamicTCPServerSocketStatusChangeEventArgs - public delegate void DynamicTCPServerSocketStatusChangeEventDelegate(object server); + //#region DynamicTCPServerSocketStatusChangeEventArgs + //public delegate void DynamicTCPServerSocketStatusChangeEventDelegate(object server); - public class DynamicTCPServerSocketStatusChangeEventArgs : EventArgs - { - public bool Secure { get; private set; } - public object Server { get; private set; } + //public class DynamicTCPServerSocketStatusChangeEventArgs : EventArgs + //{ + // public bool Secure { get; private set; } + // public object Server { get; private set; } - public DynamicTCPServerSocketStatusChangeEventArgs() { } + // public DynamicTCPServerSocketStatusChangeEventArgs() { } - public DynamicTCPServerSocketStatusChangeEventArgs(object server, bool secure) - { - Secure = secure; - Server = server; - } - } - #endregion + // public DynamicTCPServerSocketStatusChangeEventArgs(object server, bool secure) + // { + // Secure = secure; + // Server = server; + // } + //} + //#endregion } \ No newline at end of file diff --git a/Pepperdash Core/Pepperdash Core/Comm/GenericSecureTcpClient.cs b/Pepperdash Core/Pepperdash Core/Comm/GenericSecureTcpClient.cs index 046794e..3177fcf 100644 --- a/Pepperdash Core/Pepperdash Core/Comm/GenericSecureTcpClient.cs +++ b/Pepperdash Core/Pepperdash Core/Comm/GenericSecureTcpClient.cs @@ -49,7 +49,7 @@ namespace PepperDash.Core /// /// S+ helper for requires shared key bool /// - public ushort uRequiresPresharedKey + public ushort URequiresPresharedKey { set { @@ -281,7 +281,8 @@ namespace PepperDash.Core { Client.DisconnectFromServer(); Debug.Console(2, "Attempting reconnect, status={0}", Client.ClientStatus); - RetryTimer = new CTimer(ConnectToServerCallback, AutoReconnectIntervalMs); + if(!DisconnectCalledByUser) + RetryTimer = new CTimer(ConnectToServerCallback, AutoReconnectIntervalMs); } /// diff --git a/Pepperdash Core/Pepperdash Core/Comm/GenericTcpIpClient.cs b/Pepperdash Core/Pepperdash Core/Comm/GenericTcpIpClient.cs index dfcce3c..0490824 100644 --- a/Pepperdash Core/Pepperdash Core/Comm/GenericTcpIpClient.cs +++ b/Pepperdash Core/Pepperdash Core/Comm/GenericTcpIpClient.cs @@ -256,7 +256,8 @@ namespace PepperDash.Core { Client.DisconnectFromServer(); Debug.Console(2, "Attempting reconnect, status={0}", Client.ClientStatus); - RetryTimer = new CTimer(o => { Client.ConnectToServerAsync(ConnectToServerCallback); }, AutoReconnectIntervalMs); + if(!DisconnectCalledByUser) + RetryTimer = new CTimer(o => { Client.ConnectToServerAsync(ConnectToServerCallback); }, AutoReconnectIntervalMs); } void Receive(TCPClient client, int numBytes) diff --git a/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj b/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj index 35fe004..8d0a646 100644 --- a/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj +++ b/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj @@ -64,7 +64,6 @@ - diff --git a/Pepperdash Core/Pepperdash Core/PepperDash_Core.projectinfo b/Pepperdash Core/Pepperdash Core/PepperDash_Core.projectinfo index fc99cb7..d6dad78 100644 Binary files a/Pepperdash Core/Pepperdash Core/PepperDash_Core.projectinfo and b/Pepperdash Core/Pepperdash Core/PepperDash_Core.projectinfo differ diff --git a/Pepperdash Core/Pepperdash Core/bin/PepperDash_Core.clz b/Pepperdash Core/Pepperdash Core/bin/PepperDash_Core.clz index bd9b0a0..a4084b6 100644 Binary files a/Pepperdash Core/Pepperdash Core/bin/PepperDash_Core.clz and b/Pepperdash Core/Pepperdash Core/bin/PepperDash_Core.clz differ diff --git a/Pepperdash Core/Pepperdash Core/bin/PepperDash_Core.config b/Pepperdash Core/Pepperdash Core/bin/PepperDash_Core.config index d5d11bf..2913c74 100644 --- a/Pepperdash Core/Pepperdash Core/bin/PepperDash_Core.config +++ b/Pepperdash Core/Pepperdash Core/bin/PepperDash_Core.config @@ -10,8 +10,8 @@ - 3/16/2017 4:29:50 PM - 1.0.6284.27894 + 3/17/2017 10:28:42 AM + 1.0.6285.17060 Crestron.SIMPLSharp, Version=2.0.52.0, Culture=neutral, PublicKeyToken=812d080f93e2de10 diff --git a/Pepperdash Core/Pepperdash Core/bin/PepperDash_Core.dll b/Pepperdash Core/Pepperdash Core/bin/PepperDash_Core.dll index ca06589..71a2449 100644 Binary files a/Pepperdash Core/Pepperdash Core/bin/PepperDash_Core.dll and b/Pepperdash Core/Pepperdash Core/bin/PepperDash_Core.dll differ diff --git a/Pepperdash Core/Pepperdash Core/bin/PepperDash_Core.pdb b/Pepperdash Core/Pepperdash Core/bin/PepperDash_Core.pdb index 16f1b46..e89f325 100644 Binary files a/Pepperdash Core/Pepperdash Core/bin/PepperDash_Core.pdb and b/Pepperdash Core/Pepperdash Core/bin/PepperDash_Core.pdb differ diff --git a/Pepperdash Core/Pepperdash Core/bin/manifest.info b/Pepperdash Core/Pepperdash Core/bin/manifest.info index fafb5ed..c4b0216 100644 --- a/Pepperdash Core/Pepperdash Core/bin/manifest.info +++ b/Pepperdash Core/Pepperdash Core/bin/manifest.info @@ -1,4 +1,4 @@ -MainAssembly=PepperDash_Core.dll:6f9c7beaa687813ff469ca17ed4a2b09 +MainAssembly=PepperDash_Core.dll:1cb57e7d4dc5c0e9b66ba4c496fb831f MainAssemblyMinFirmwareVersion=1.007.0017 MainAssemblyResource=SimplSharpData.dat:315526abf906cded47fb0c7510266a7e ü diff --git a/Pepperdash Core/Pepperdash Core/bin/manifest.ser b/Pepperdash Core/Pepperdash Core/bin/manifest.ser index 39ff880..3079acb 100644 Binary files a/Pepperdash Core/Pepperdash Core/bin/manifest.ser and b/Pepperdash Core/Pepperdash Core/bin/manifest.ser differ diff --git a/Pepperdash Core/Pepperdash Core/obj/Debug/PepperDash_Core.dll b/Pepperdash Core/Pepperdash Core/obj/Debug/PepperDash_Core.dll index 85fc698..3c782b2 100644 Binary files a/Pepperdash Core/Pepperdash Core/obj/Debug/PepperDash_Core.dll and b/Pepperdash Core/Pepperdash Core/obj/Debug/PepperDash_Core.dll differ diff --git a/Pepperdash Core/Pepperdash Core/obj/Debug/PepperDash_Core.pdb b/Pepperdash Core/Pepperdash Core/obj/Debug/PepperDash_Core.pdb index dc3f923..8b58d9d 100644 Binary files a/Pepperdash Core/Pepperdash Core/obj/Debug/PepperDash_Core.pdb and b/Pepperdash Core/Pepperdash Core/obj/Debug/PepperDash_Core.pdb differ