/// <summary>
        /// Runs the agent
        /// </summary>
        public void Run()
        {
            try
            {
                // Check we have an address to connect to.
                if (string.IsNullOrEmpty(ApplicationSettings.Default.XmrNetworkAddress))
                    throw new Exception("Empty XMR Network Address");

                // Get the Private Key
                AsymmetricCipherKeyPair rsaKey = _hardwareKey.getXmrKey();

                // Connect to XMR
                using (NetMQContext context = NetMQContext.Create())
                {
                    using (SubscriberSocket socket = context.CreateSubscriberSocket())
                    {
                        // Bind
                        socket.Connect(ApplicationSettings.Default.XmrNetworkAddress);
                        socket.Subscribe("H");
                        socket.Subscribe(_hardwareKey.Channel);

                        // Notify
                        _clientInfoForm.XmrSubscriberStatus = "Connected to " + ApplicationSettings.Default.XmrNetworkAddress;

                        while (!_forceStop)
                        {
                            lock (_locker)
                            {
                                try
                                {
                                    NetMQMessage message = socket.ReceiveMultipartMessage();
                                    
                                    // Update status
                                    _clientInfoForm.XmrSubscriberStatus = "Connected (" + ApplicationSettings.Default.XmrNetworkAddress + "), last activity: " + DateTime.Now.ToString();

                                    // Deal with heart beat
                                    if (message[0].ConvertToString() == "H")
                                    {
                                        LastHeartBeat = DateTime.Now;
                                        continue;
                                    }

                                    // Decrypt the message
                                    string opened = OpenSslInterop.decrypt(message[2].ConvertToString(), message[1].ConvertToString(), rsaKey.Private);

                                    // Decode into a JSON string
                                    PlayerAction action = JsonConvert.DeserializeObject<PlayerAction>(opened);

                                    // Make sure the TTL hasn't expired
                                    if (DateTime.Now > action.createdDt.AddSeconds(action.ttl))
                                    {
                                        Trace.WriteLine(new LogMessage("XmrSubscriber - Run", "Expired Message: " + action.action), LogType.Info.ToString());
                                        continue;
                                    }

                                    // Decide what to do with the message, probably raise events according to the type of message we have
                                    switch (action.action)
                                    {
                                        case "commandAction":

                                            // Create a schedule command out of the message
                                            Dictionary<string, string> obj = JsonConvert.DeserializeObject<Dictionary<string, string>>(opened);
                                            ScheduleCommand command = new ScheduleCommand();
                                            string code;
                                            obj.TryGetValue("commandCode", out code);
                                            command.Code = code;

                                            new Thread(new ThreadStart(command.Run)).Start();
                                            break;

                                        case "collectNow":
                                            OnCollectNowAction();
                                            break;

                                        case "screenShot":
                                            ScreenShot.TakeAndSend();
                                            break;

                                        default:
                                            Trace.WriteLine(new LogMessage("XmrSubscriber - Run", "Unknown Message: " + action.action), LogType.Info.ToString());
                                            break;
                                    }
                                }
                                catch (Exception ex)
                                {
                                    // Log this message, but dont abort the thread
                                    Trace.WriteLine(new LogMessage("XmrSubscriber - Run", "Exception in Run: " + ex.Message), LogType.Error.ToString());
                                    _clientInfoForm.XmrSubscriberStatus = "Error. " + ex.Message;
                                }
                            }
                        }
                    }
                }

                // Update status
                _clientInfoForm.XmrSubscriberStatus = "Not Running, last activity: " + LastHeartBeat.ToString();

                Trace.WriteLine(new LogMessage("XmrSubscriber - Run", "Subscriber Stopped"), LogType.Info.ToString());
            }
            catch (Exception e)
            {
                Trace.WriteLine(new LogMessage("XmrSubscriber - Run", "Unable to Subscribe to XMR: " + e.Message), LogType.Error.ToString());
                _clientInfoForm.XmrSubscriberStatus = e.Message;
            }
        }
        /// <summary>
        /// Loads the schedule from file.
        /// </summary>
        /// <returns></returns>
        private void LoadScheduleFromFile()
        {
            // Empty the current schedule collection
            _layoutSchedule.Clear();

            // Clear the list of commands
            _commands.Clear();

            // Get the schedule XML
            XmlDocument scheduleXml = GetScheduleXml();

            // Parse the schedule xml
            XmlNodeList nodes = scheduleXml["schedule"].ChildNodes;

            // Are there any nodes in the document
            if (nodes.Count == 0)
            {
                SetEmptySchedule();
                return;
            }

            // We have nodes, go through each one and add them to the layoutschedule collection
            foreach (XmlNode node in nodes)
            {
                LayoutSchedule temp = new LayoutSchedule();

                // Node name
                temp.NodeName = node.Name;

                if (temp.NodeName == "dependants")
                {
                    // Do nothing for now
                }
                else if (temp.NodeName == "command")
                {
                    // Try to get the command using the code
                    try
                    {
                        // Pull attributes from layout nodes
                        XmlAttributeCollection attributes = node.Attributes;

                        ScheduleCommand command = new ScheduleCommand();
                        command.Date = DateTime.Parse(attributes["date"].Value, CultureInfo.InvariantCulture);
                        command.Code = attributes["code"].Value;
                        command.ScheduleId = int.Parse(attributes["scheduleid"].Value);

                        // Add to the collection
                        _commands.Add(command);
                    }
                    catch (Exception e)
                    {
                        Trace.WriteLine(new LogMessage("ScheduleManager - LoadScheduleFromFile", e.Message), LogType.Error.ToString());
                    }
                }
                else
                {
                    // Pull attributes from layout nodes
                    XmlAttributeCollection attributes = node.Attributes;

                    // All nodes have file properties
                    temp.layoutFile = attributes["file"].Value;

                    // Replace the .xml extension with nothing
                    string replace = ".xml";
                    string layoutFile = temp.layoutFile.TrimEnd(replace.ToCharArray());

                    // Set these on the temp layoutschedule
                    temp.layoutFile = ApplicationSettings.Default.LibraryPath + @"\" + layoutFile + @".xlf";
                    temp.id = int.Parse(layoutFile);

                    // Get attributes that only exist on the default
                    if (temp.NodeName != "default")
                    {
                        // Priority flag
                        temp.Priority = (attributes["priority"].Value == "1") ? true : false;

                        // Get the fromdt,todt
                        temp.FromDt = DateTime.Parse(attributes["fromdt"].Value, CultureInfo.InvariantCulture);
                        temp.ToDt = DateTime.Parse(attributes["todt"].Value, CultureInfo.InvariantCulture);

                        // Pull out the scheduleid if there is one
                        string scheduleId = "";
                        if (attributes["scheduleid"] != null) scheduleId = attributes["scheduleid"].Value;

                        // Add it to the layout schedule
                        if (scheduleId != "") temp.scheduleid = int.Parse(scheduleId);

                        // Dependents
                        if (attributes["dependents"] != null)
                        {
                            foreach (string dependent in attributes["dependents"].Value.Split(','))
                            {
                                temp.Dependents.Add(dependent);
                            }
                        }
                    }

                    // Look for dependents nodes
                    foreach (XmlNode childNode in node.ChildNodes)
                    {
                        if (childNode.Name == "dependents")
                        {
                            foreach (XmlNode dependent in childNode.ChildNodes)
                            {
                                if (dependent.Name == "file")
                                {
                                    temp.Dependents.Add(dependent.InnerText);
                                }
                            }
                        }
                    }

                    _layoutSchedule.Add(temp);
                }
            }

            // Clean up
            nodes = null;
            scheduleXml = null;

            // We now have the saved XML contained in the _layoutSchedule object
        }