public void StartListening()
        {
            if (GetServerStatus() == ServerStatus.Running)
            {
                return;
            }
            Debug.WriteLine("In StartListening");

            SetServerStatus(ServerStatus.Running);

            while (true)
            {
                try
                {
                    listener = new HttpListener();
                    listener.Prefixes.Add(prefs.LocalIP);
                    listener.Start();
                }
                catch (Exception e)
                {
                    var msg = e.Message;
                    Trace.WriteLine(msg);
                }

                Trace.WriteLine("Listening...");

                if (stopListening)
                {
                    Debug.WriteLine("Time to stop listening.");
                    listener.Stop();
                    break;
                }

                HttpListenerContext context;
                HttpListenerRequest request;

                try
                {
                    context = listener.GetContext();
                    request = context.Request;
                }
                catch (HttpListenerException e)
                {
                    var msg = e.Message + "\n\n";
                    msg += "Either run this application as administrator, which you'll have to do every time it's started, or enter the following command (all in one line and without quotes) in an elevated command prompt, which you'll only have to do once: \n\n";
                    msg += "'netsh http add urlacl url=http://LOCAL_IP:PORT/ user=COMPUTER_NAME\\WIN_ACCOUNT_NAME'\n\n";
                    msg += "Change LOCAL_IP and PORT to the local IP and port to listen on, and COMPUTER_NAME and WIN_ACCOUNT_NAME to the computer name and Windows account username.";
                    Trace.WriteLine(msg);
                    MessageBox.Show(msg);
                    return;
                }
                catch (InvalidOperationException e)
                {
                    var msg = e.Message;
                    Trace.WriteLine(msg);
                    MessageBox.Show(msg);
                    return;
                }

                if (stopListening)
                {
                    Debug.WriteLine("Time to stop listening.");
                    listener.Stop();
                    break;
                }

                HttpListenerResponse response = context.Response;
                if (request.InputStream != null)
                {
                    using (var reader = new StreamReader(request.InputStream, Encoding.UTF8))
                    {
                        var     content   = reader.ReadToEnd();
                        dynamic json      = JObject.Parse(content);
                        var     eventType = "";
                        try
                        {
                            eventType = json.issue_event_type_name.Value;
                            eventType = eventType.Replace("_", " ");
                            eventType = eventType.First().ToString().ToUpper() + eventType.Substring(1);
                            Trace.WriteLine("Issue event type name: " + eventType);

                            if (eventType == "Issue generic")
                            {
                                eventType = "Issue moved to '" + json.issue.fields.status.name.Value + "'";
                            }
                        }
                        catch (Exception ex)
                        {
                            var msg = ex.Message;
                            Trace.WriteLine(msg);

                            eventType = json.webhookEvent.Value;
                            Trace.WriteLine("Webhook event: " + eventType);
                            return;
                        }

                        JiraUser user   = new JiraUser();
                        dynamic  author = null;
                        try
                        {
                            author    = json.user;
                            user.Name = json.user.displayName.Value;
                            //prefs.BotName = user.Name + " (JIRA)";
                        }
                        catch (Exception ex)
                        {
                            var msg = ex.Message;
                            Trace.WriteLine(msg);

                            author    = json.comment.author;
                            user.Name = json.comment.author.displayName.Value;
                            //prefs.BotName = user.Name + " (JIRA)";
                        }

                        JiraIssue   issue   = new JiraIssue();
                        JiraComment comment = new JiraComment();
                        try
                        {
                            comment.Contents = json.comment.body.Value;
                            comment.Id       = json.comment.id.Value;

                            issue.Key         = json.issue.key.Value;
                            issue.Url         = prefs.JiraBaseURL + issue.Key + "?focusedCommentId=" + comment.Id;
                            issue.Type        = json.issue.fields.issuetype.name.Value;
                            issue.Summary     = json.issue.fields.summary.Value;
                            issue.Description = json.issue.fields.description.Value;
                            issue.Status      = json.issue.fields.status.name.Value;
                            issue.Resolution  = json.issue.fields.resolution.Value;
                            if (issue.Resolution == null)
                            {
                                issue.Resolution = "Unresolved";
                            }
                            issue.Reporter = new JiraUser
                            {
                                Name      = json.issue.fields.reporter.displayName.Value,
                                AvatarUrl = ((json.issue.fields.reporter.avatarUrls as IEnumerable <object>).First() as dynamic).Value.Value
                            };
                            if (json.issue.fields.assignee == null)
                            {
                                issue.Assignee = new JiraUser {
                                    Name = "*Unassigned*"
                                };
                            }
                            else
                            {
                                issue.Assignee = new JiraUser
                                {
                                    Name      = json.issue.fields.assignee.displayName.Value,
                                    AvatarUrl = ((json.issue.fields.assignee.avatarUrls as IEnumerable <object>).First() as dynamic).Value.Value
                                };
                            }
                            issue.UpdatedTimestamp = json.issue.fields.updated.Value;
                        }
                        catch (Exception ex)
                        {
                            var msg = ex.Message;
                            Trace.WriteLine(msg);

                            issue.Key         = json.issue.key.Value;
                            issue.Url         = prefs.JiraBaseURL + issue.Key;
                            issue.Type        = json.issue.fields.issuetype.name.Value;
                            issue.Summary     = json.issue.fields.summary.Value;
                            issue.Description = json.issue.fields.description.Value;
                            issue.Status      = json.issue.fields.status.name.Value;
                            issue.Resolution  = json.issue.fields.resolution.Value;
                            if (issue.Resolution == null)
                            {
                                issue.Resolution = "Unresolved";
                            }
                            issue.Reporter = new JiraUser
                            {
                                Name      = json.issue.fields.reporter.displayName.Value,
                                AvatarUrl = ((json.issue.fields.reporter.avatarUrls as IEnumerable <object>).First() as dynamic).Value.Value
                            };
                            if (json.issue.fields.assignee == null)
                            {
                                issue.Assignee = new JiraUser {
                                    Name = "*Unassigned*"
                                };
                            }
                            else
                            {
                                issue.Assignee = new JiraUser
                                {
                                    Name      = json.issue.fields.assignee.displayName.Value,
                                    AvatarUrl = ((json.issue.fields.assignee.avatarUrls as IEnumerable <object>).First() as dynamic).Value.Value
                                };
                            }
                            issue.UpdatedTimestamp = json.issue.fields.updated.Value;
                        }
                        if (issue.Description != null && issue.Description != "")
                        {
                            // Convert code tags
                            issue.Description = issue.Description.Replace("{{", "```\n");
                            issue.Description = issue.Description.Replace("}}", "\n```");
                            issue.Description = issue.Description.Replace("{code}\r\n", "```\n");
                            issue.Description = issue.Description.Replace("\r\n{code}", "\n```");

                            // Remove bold formatting
                            issue.Description = issue.Description.Replace("*", "");

                            // Trim length
                            if (issue.Description.Length > 250)
                            {
                                issue.Description = issue.Description.Substring(0, 250);

                                // Is there an odd number of code tags?
                                int numTags = Regex.Matches(issue.Description, "```").Count;
                                if (numTags % 2 != 0)
                                {
                                    // Close the last tag
                                    issue.Description += " ...\n```" + "\n([see full description](" + issue.Url + "))";
                                }
                                else
                                {
                                    issue.Description += " ... ([see full description](" + issue.Url + "))";
                                }
                            }
                        }
                        else
                        {
                            issue.Description = "*No description*";
                        }

                        try
                        {
                            user.AvatarUrl = ((author.avatarUrls as IEnumerable <object>).First() as dynamic).Value.Value;
                        }
                        catch (Exception ex)
                        {
                            var msg = ex.Message;
                            Trace.WriteLine(msg);
                        }

                        DiscordBot bot = new DiscordBot
                        {
                            Name      = prefs.BotName,
                            AvatarUrl = prefs.JiraIconURL
                        };

                        JiraIssueIcons issueIcons = new JiraIssueIcons
                        {
                            BugIconURL  = prefs.BugIconURL,
                            TaskIconURL = prefs.TaskIconURL,
                            EpicIconURL = prefs.EpicIconURL
                        };

                        Trace.WriteLine("Got webhook event '" + eventType + "' [" + issue.Summary + "]" + " by " + user.Name);

                        try
                        {
                            var discordMessage     = new DiscordHookMessage(bot, eventType, user, issue, issueIcons, comment);
                            var discordMessageJSON = JsonConvert.SerializeObject(discordMessage, Formatting.Indented);
                            var resp = client.PostAsync(prefs.DiscordURL, new StringContent(discordMessageJSON, Encoding.UTF8, "application/json")).Result;
                            Trace.WriteLine("Discord response code: " + resp.StatusCode);
                        }
                        catch (Exception ex)
                        {
                            var msg = ex.Message;
                            Trace.WriteLine(msg);
                            //MessageBox.Show(msg);
                        }
                    }
                }
                try
                {
                    using (var writer = new StreamWriter(response.OutputStream))
                    {
                        writer.Write("Hello world!");
                        writer.Close();
                    }

                    listener.Stop();
                }
                catch (IOException ex)
                {
                    var msg = ex.Message;
                    Trace.WriteLine(msg);
                }
                catch (ObjectDisposedException ex)
                {
                    var msg = ex.Message;
                    Trace.WriteLine(msg);
                }
            }
        }
        static void Main(string[] args)
        {
            using (var server = new HttpServer())
            {
                server.EndPoint         = new IPEndPoint(IPAddress.Parse(localIP), port);
                server.RequestReceived += (s, e) =>
                {
                    if (e.Request.InputStream != null)
                    {
                        using (var reader = new StreamReader(e.Request.InputStream, Encoding.UTF8))
                        {
                            var     content = reader.ReadToEnd();
                            dynamic json    = JObject.Parse(content);
                            var     ev      = "";
                            try
                            {
                                ev = json.issue_event_type_name.Value;
                                ev = ev.Replace("_", " ");
                                ev = ev.First().ToString().ToUpper() + ev.Substring(1);
                                Console.WriteLine("Issue event type name: " + ev);

                                if (ev == "Issue generic")
                                {
                                    ev = "Issue moved to '" + json.issue.fields.status.name.Value + "'";
                                }
                            }
                            catch (Exception ex)
                            {
                                var msg = ex.Message;
                                Console.WriteLine(msg);

                                ev = json.webhookEvent.Value;
                                Console.WriteLine("Webhook event: " + ev);
                                return;
                            }
                            var     authorName = "";
                            dynamic author     = null;
                            try
                            {
                                author     = json.user;
                                authorName = json.user.displayName.Value;
                                //botName = authorName + " (JIRA)";
                            }
                            catch (Exception ex)
                            {
                                var msg = ex.Message;
                                Console.WriteLine(msg);

                                author     = json.comment.author;
                                authorName = json.comment.author.displayName.Value;
                                //botName = authorName + " (JIRA)";
                            }
                            var link             = "";
                            var issueKey         = "";
                            var issueSummary     = "";
                            var issueDescription = "";
                            var commentContents  = "";
                            var commentId        = "";
                            try
                            {
                                commentContents = json.comment.body.Value;
                                commentId       = json.comment.id.Value;

                                issueKey         = json.issue.key.Value;
                                link             = jiraBaseURL + issueKey + "?focusedCommentId=" + commentId;
                                issueSummary     = json.issue.fields.summary.Value;
                                issueDescription = json.issue.fields.description.Value;
                            }
                            catch (Exception ex)
                            {
                                var msg = ex.Message;
                                Console.WriteLine(msg);

                                issueKey         = json.issue.key.Value;
                                link             = jiraBaseURL + issueKey;
                                issueSummary     = json.issue.fields.summary.Value;
                                issueDescription = json.issue.fields.description.Value;
                            }
                            if (issueDescription != "")
                            {
                                // Convert code tags
                                issueDescription = issueDescription.Replace("{{", "```\n");
                                issueDescription = issueDescription.Replace("}}", "\n```");
                                issueDescription = issueDescription.Replace("{code}\r\n", "```\n");
                                issueDescription = issueDescription.Replace("\r\n{code}", "\n```");

                                // Remove bold formatting
                                issueDescription = issueDescription.Replace("*", "");

                                // Trim length
                                if (issueDescription.Length > 250)
                                {
                                    issueDescription = issueDescription.Substring(0, 100);

                                    // Is there an odd number of code tags?
                                    int numTags = Regex.Matches(issueDescription, "```").Count;
                                    if (numTags % 2 != 0)
                                    {
                                        // Close the last tag
                                        issueDescription += " ...\n```" + "\n([see full description](" + link + "))";
                                    }
                                    else
                                    {
                                        issueDescription += " ... ([see full description](" + link + "))";
                                    }
                                }
                            }
                            var avatarUrl = ((author.avatarUrls as IEnumerable <object>).First() as dynamic).Value.Value;

                            Console.WriteLine("Got webhook event '" + ev + "' [" + issueSummary + "]" + " by " + authorName);

                            var discordMessage     = new DiscordHookMessage(botName, issueKey, issueSummary, issueDescription, ev, link, authorName, avatarUrl, commentContents, commentId);
                            var discordMessageJSON = JsonConvert.SerializeObject(discordMessage, Formatting.Indented);
                            var resp = client.PostAsync(discordURL, new StringContent(discordMessageJSON, Encoding.UTF8, "application/json")).Result;
                            Console.WriteLine("Discord response code: " + resp.StatusCode);
                        }
                    }
                    using (var writer = new StreamWriter(e.Response.OutputStream))
                    {
                        writer.Write("Hello world!");
                    }
                };

                server.Start();

                Console.WriteLine("Server started. Press any key to exit.");
                Console.ReadKey();
            }
        }