public override string ToString()
        {
            string retVal = "{";

            retVal += "AuthenticationKey = " + AuthenticationKey +
                      Environment.NewLine;
            retVal += "Balance = " + Balance + Environment.NewLine;
            retVal += "DelegatedWithdrawalCapability = " + DelegatedWithdrawalCapability +
                      Environment.NewLine;
            retVal += "ReceivedEvents = " + ReceivedEvents.ByteArryToString() +
                      Environment.NewLine;
            retVal += "SentEvents = " + SentEvents.ByteArryToString() +
                      Environment.NewLine;
            retVal += "SequenceNumber = " + SequenceNumber + Environment.NewLine;
            retVal += "}";
            return(retVal);
        }
        private static void SyncThread()
        {
            try
            {
                running = 1;

                UpdateDiscardList();                // make sure the list is up to date

                while (historylist.Count != 0)      // while stuff to send
                {
                    HistoryQueueEntry hqe = null;

                    if (historylist.TryDequeue(out hqe))        // next history event...
                    {
                        HistoryEntry first = hqe.HistoryEntry;

                        historyevent.Reset();
                        Action <string> logger = hqe.Logger;

                        List <HistoryEntry> hl = new List <HistoryEntry>()
                        {
                            first
                        };

                        if (holdEvents.Contains(first.EntryType) || (first.EntryType == JournalTypeEnum.Location && first.IsDocked))
                        {
                            System.Diagnostics.Debug.WriteLine("EDSM Holding for another event");

                            if (historylist.IsEmpty)
                            {
                                historyevent.WaitOne(20000); // Wait up to 20 seconds for another entry to come through
                            }
                        }

                        while (hl.Count < maxEventsPerMessage && historylist.TryPeek(out hqe)) // Leave event in queue if commander changes
                        {
                            HistoryEntry he = hqe.HistoryEntry;

                            if (he == null || he.Commander != first.Commander)
                            {
                                break;
                            }

                            historylist.TryDequeue(out hqe);
                            historyevent.Reset();

                            // now we have an updated discard list,

                            if (hqe.HistoryEntry != null && discardEvents.Contains(hqe.HistoryEntry.EntryType.ToString()))
                            {
                                System.Diagnostics.Debug.WriteLine("EDSM Discarding in sync " + hqe.HistoryEntry.EventSummary);
                                continue;
                            }

                            hl.Add(he);

                            if ((holdEvents.Contains(he.EntryType) || (he.EntryType == JournalTypeEnum.Location && he.IsDocked)) && historylist.IsEmpty)
                            {
                                historyevent.WaitOne(20000); // Wait up to 20 seconds for another entry to come through
                            }

                            if (Exit)
                            {
                                return;
                            }
                        }

                        int    sendretries    = 5;
                        int    waittime       = 30000;
                        string firstdiscovery = "";

                        while (sendretries > 0 && !SendToEDSM(hl, first.Commander, out string errmsg, out firstdiscovery))
                        {
                            logger?.Invoke($"Error sending EDSM events {errmsg}");
                            System.Diagnostics.Trace.WriteLine($"Error sending EDSM events {errmsg}");
                            exitevent.WaitOne(waittime); // Wait and retry
                            if (Exit)
                            {
                                return;
                            }
                            sendretries--;
                            waittime *= 2; // Double back-off time, up to 8 minutes between tries or 15.5 minutes total
                        }

                        if (sendretries == 0)
                        {
                            logger?.Invoke("Unable to send events - giving up");
                            System.Diagnostics.Trace.WriteLine("Unable to send events - giving up");
                        }
                        else
                        {
                            SentEvents?.Invoke(hl.Count, firstdiscovery);       // finished sending everything, tell..
                            if (hl.Count >= 5)
                            {
                                logger?.Invoke($"Sent {hl.Count} Events to EDSM");
                            }
                        }
                    }

                    // Wait at least N between messages
                    exitevent.WaitOne(100);

                    if (Exit)
                    {
                        return;
                    }

                    if (historylist.IsEmpty)
                    {
                        historyevent.WaitOne(120000);       // wait for another event keeping the thread open.. Note stop also sets this
                    }
                    if (Exit)
                    {
                        return;
                    }
                }
            }
            catch (Exception ex)
            {
                System.Diagnostics.Trace.WriteLine("Exception ex:" + ex.Message);
            }
            finally
            {
                running = 0;
            }
        }