Esempio n. 1
0
        static void Main(string[] args)
        {
            var tabledata = RowCollection.Create(exambledatalong);
            var header    = RowConf.Create(headerdata).PresetTH();

            tabledata.Import(0, header);
            tabledata.Settings.Border.Enabled            = true;
            tabledata.Settings.Border.HorizontalLineBody = BorderConf.HorizontalLineAlwaysOnFunc;

            using (var writer = new CoExHtmlWriter()
            {
                Title = "A fancy demo"
            })
            {
                CoEx.WriteTitleLarge("A fancy demo");
                CoEx.WriteLine();
                CoEx.WriteTable(tabledata);

                var target = Path.Combine(AppContext.BaseDirectory, "lastoutput.html");
                if (File.Exists(target))
                {
                    File.Delete(target);
                }

                writer.SaveAs(target);
                CoEx.WriteLine();
                CoEx.WriteLine("Output file: {0}", target);
            }

            CoEx.WriteLine();
            CoEx.PressAnyKey();
        }
Esempio n. 2
0
        protected static void DemoIntro()
        {
            CoEx.WriteTitleLarge("Welcome to PerrysNetConsole Demo Application");
            CoEx.WriteTitleLarge("Code & Concept by Christian Blechert");
            CoEx.WriteLine();

            CoEx.WriteLine("This is the introduction for a highlighted text");
            CoEx.WriteHl("Highlighted text");

            CoEx.WriteLine();
            CoEx.WriteLine("And here comes text highlighting in multiple columns");

            CoEx.WriteLine();
            CoEx.WriteHl("Highlighted text", "in multiple columns");

            CoEx.WriteLine();
            CoEx.WriteHl("0", "1", "2", "3", "4", "5", "6", "7", "8", "9");
            CoEx.WriteHl("10", "11", "12", "13", "14", "15", "16", "17", "18", "19");

            CoEx.WriteLine();
            CoEx.WriteHl("And what happens when the text is too long?", "The really really really really really really really really really really long text will be wrapped. Is this quite cool? Yes, it is. :-)");

            CoEx.WriteLine();
            CoEx.WriteLine();
            CoEx.WriteLine("Oh and normal text of couse, nevermind, go ahead!");
        }
Esempio n. 3
0
        static void Main(string[] args)
        {
            if (!(args.Length > 2 && args[0].StartsWith("http") && args[1].EndsWith(".json") && args[2].EndsWith(".html")))
            {
                CoEx.WriteLine("Usage: ForumParser.exe http(s)://... output.json output.html");
                return;
            }

            CoEx.ForcedBufferWidth = 135;

            /*
             * var url = @"https://forum.netcup.de/sonstiges/smalltalk/1051-das-l%C3%A4ngste-thema/";
             * var path = @"H:\laengstes.json";
             * var htmloutfile = @"H:\laengstes.html";
             */

            var forcecrawl  = args.Length > 3 && args[3] == "--force";
            var url         = args[0];
            var path        = args[1];
            var htmloutfile = args[2];

            if (File.Exists(path) == false || forcecrawl)
            {
                Crawl(url, path);
            }

            PrintStats(path, htmloutfile);
        }
Esempio n. 4
0
        protected static void DemoTimeout()
        {
            CoEx.WriteTitleLarge("Basic timeout");
            CoEx.WriteLine();

            CoEx.Timeout(3);
        }
Esempio n. 5
0
        protected static void DemoAlignment()
        {
            rc2.Settings.Align = delegate(RowConf me, int colindex, string s)
            {
                switch (colindex)
                {
                case 0: return(RowCollectionSettings.ALIGN.RIGHT);

                case 1: return(null);

                case 2: return(RowCollectionSettings.ALIGN.RIGHT);

                case 3: return(RowCollectionSettings.ALIGN.CENTER);

                default: return(RowCollectionSettings.ALIGN.LEFT);
                }
            };

            rc2.Settings.Border.HorizontalLineBody = delegate(RowConf r) { return(true); };

            CoEx.WriteTitleLarge("Tables - Chapter 5");
            CoEx.WriteLine();
            CoEx.WriteTitle("Column alignment");
            CoEx.WriteTable(rc2);
        }
Esempio n. 6
0
 protected static void BasicTableLongText()
 {
     CoEx.WriteTitleLarge("Tables - Chapter 2");
     CoEx.WriteLine();
     CoEx.WriteTitle("The basic table with long text");
     rc2.Import(0, header);
     CoEx.WriteTable(rc2);
 }
Esempio n. 7
0
        /// <summary>
        /// Show current setup
        /// </summary>
        /// <param name="config">Config</param>
        /// <param name="args">CMD Args</param>
        /// <param name="provider">Provider</param>
        /// <returns>Exit code</returns>
        private static int ShowInfo(Data.MailiasConfig config, Args args, Data.IProvider provider)
        {
            CoEx.WriteLine($"Used Provider: {config.Provider}");
            CoEx.WriteLine($"Mail Domain:   {config.MailDomain}");
            CoEx.WriteLine($"Alias Target:  {config.TargetAddress}");
            CoEx.WriteLine($"Prefix:        {config.Prefix}");
            CoEx.WriteLine($"Code Length:   {config.UniqeIdLength}");

            return(0);
        }
Esempio n. 8
0
        protected static void DemoProgressBarMessages()
        {
            Tuple <Message.LEVEL, string>[] states = new Tuple <Message.LEVEL, string>[]
            {
                new Tuple <Message.LEVEL, string>(Message.LEVEL.INFO, "Initialize"),
                new Tuple <Message.LEVEL, string>(Message.LEVEL.INFO, "This is a message on INFO level"),
                new Tuple <Message.LEVEL, string>(Message.LEVEL.DEBUG, "Debugging message"),
                new Tuple <Message.LEVEL, string>(Message.LEVEL.WARN, "Serious warning, be careful!"),
                new Tuple <Message.LEVEL, string>(Message.LEVEL.ERROR, "Fatal error, its too late to be careful..."),
                new Tuple <Message.LEVEL, string>(Message.LEVEL.SUCCESS, "Finally done with this demo!")
            };

            CoEx.WriteTitleLarge("Progress bar with status messages");
            CoEx.WriteLine();

            // Example without using() { }
            Progress prog = new Progress();

            prog.Start();

            int perc = 0;

            for (int i = 0; i < states.Length; i++)
            {
                // Post message
                prog.Message(states[i].Item1, states[i].Item2);

                // Increase by 20 percent in small steps
                if (states[i].Item1 == Message.LEVEL.DEBUG)
                {
                    prog.Message(Message.LEVEL.DEBUG, "Ooops, dont know how long this will take, please wait...");
                    prog.IsWaiting = true;
                    System.Threading.Thread.Sleep(20000);
                    prog.IsWaiting = false;
                }
                else
                {
                    for (int j = 0; j < 100 / states.Length; j++)
                    {
                        perc++;
                        prog.Update(perc);
                        System.Threading.Thread.Sleep(20);
                    }
                }

                // wait 2 seconds
                System.Threading.Thread.Sleep(2000);
            }

            prog.Update(100);
            prog.Stop();

            System.Threading.Thread.Sleep(2000);
        }
Esempio n. 9
0
        protected static void DemoScrolltext()
        {
            var width   = CoEx.WindowWidth;
            var height  = CoEx.WindowHeight;
            var bheight = CoEx.BufferHeight;

            CoEx.WindowHeight = 20;
            CoEx.BufferWidth  = CoEx.WindowWidth = 40;
            CoEx.BufferHeight = ScrollText.Length + (2 * CoEx.WindowHeight);

            ulong pos = CoEx.RealCursorY;

            for (int i = 0; i < CoEx.WindowHeight; i++)
            {
                CoEx.WriteLine();
            }

            foreach (var line in ScrollText)
            {
                var temp    = line;
                var istitle = temp.StartsWith(":");
                if (istitle)
                {
                    temp = temp.Substring(1);
                }
                var row = RowConf.Create(new string[] { temp }).SetAlignment(RowConf.ALIGNCENTER);
                if (istitle)
                {
                    row = row.PresetTitle();
                }
                CoEx.WriteColumns(row);
            }

            int length = (int)(CoEx.RealCursorY - pos);

            for (int i = 0; i < CoEx.WindowHeight; i++)
            {
                CoEx.WriteLine();
            }

            CoEx.Scroll(0, (int)(pos - CoEx.RealCursorY));

            for (int i = 0; i < length; i++)
            {
                CoEx.BufferViewportY++;
                System.Threading.Thread.Sleep(600);
            }

            System.Threading.Thread.Sleep(2000);

            CoEx.WindowWidth  = CoEx.BufferWidth = width;
            CoEx.WindowHeight = height;
            CoEx.BufferHeight = bheight;
        }
Esempio n. 10
0
        public static int Main(string[] args)
        {
            // Console output settings
            CoEx.ForcedBufferWidth = 100;

            // Load settings
            var config = LoadConfiguration();

            if (string.IsNullOrWhiteSpace(config.Provider))
            {
                CoEx.WriteLine($"No provider configured in '{GetConfigPath()}'");
                return(99);
            }

            // Load provider
            var provider = CreateProvider(config);

            if (provider == null)
            {
                CoEx.WriteLine("No valid provider was loaded.");
                return(99);
            }

            // Parse arguments
            int returnCode = 99;

            Parser.Default.ParseArguments <Args>(args).WithParsed(o =>
            {
                if (o.Info)
                {
                    // Show current info
                    returnCode = ShowInfo(config, o, provider);
                }
                if (!string.IsNullOrWhiteSpace(o.CreateName))
                {
                    // Create a new alias
                    returnCode = CreateAlias(config, o, provider).WaitForValue <int>();
                }
                if (!string.IsNullOrWhiteSpace(o.DeleteAlias))
                {
                    // Delete an existing alias
                    returnCode = DeleteAlias(config, o, provider).WaitForValue <int>();
                }
                else if (o.List)
                {
                    // List existing aliases
                    returnCode = ListAliases(config, o, provider).WaitForValue <int>();
                }
            });

            return(returnCode);
        }
Esempio n. 11
0
        protected static void DemoLoadIndicator()
        {
            CoEx.WriteTitleLarge("Loading indicator");
            CoEx.WriteLine();

            LoadIndicator indicator = new LoadIndicator()
            {
                Message = "Load the awesomeness"
            };

            indicator.Start();
            System.Threading.Thread.Sleep(5000);
            indicator.Stop();
        }
Esempio n. 12
0
        protected static void DemoBasicColumns()
        {
            CoEx.WriteTitleLarge("Basic column system, no custom column length, no custom formatting");
            CoEx.WriteLine();

            // loop both exampledata arrays
            foreach (var data in new string[][][] { exambledata, exambledatalong })
            {
                // print single row from one of the exampledata arrays
                foreach (var row in data)
                {
                    CoEx.WriteColumns(row); // print the row
                }
            }
        }
Esempio n. 13
0
        protected static void DemoProgressBar()
        {
            CoEx.WriteTitleLarge("Simple Progressbar");
            CoEx.WriteLine();

            // using() { } is optional, see Start(), Stop() and Clear()
            using (Progress simpr = new Progress())
            {
                simpr.Start();

                do
                {
                    simpr.Percentage += 0.20;
                    System.Threading.Thread.Sleep(5);
                }while (simpr.Percentage < 100);

                System.Threading.Thread.Sleep(1000);
            }
        }
Esempio n. 14
0
        protected static void DemoBasicTable()
        {
            CoEx.WriteTitleLarge("Tables - Chapter 1");
            CoEx.WriteLine();
            CoEx.WriteTitle("The basic table");
            rc1.Settings.StretchHorizontal = false;
            CoEx.WriteTable(rc1);
            rc1.Settings.StretchHorizontal = true;

            CoEx.WriteLine();
            CoEx.WriteTitle("The basic table with header, stretched to window width");
            rc1.Import(0, header);
            CoEx.WriteTable(rc1);

            CoEx.WriteLine();
            CoEx.WriteTitle("The basic table, border disabled");
            rc1.Settings.Border.Enabled = false; // override default
            CoEx.WriteTable(rc1);
        }
Esempio n. 15
0
        protected static void DemoTableSynchronized()
        {
            var length = RowCollection.Create().Import(rc1).Import(rc2).Length;

            rc1.Length = length;
            rc1.Settings.Border.Enabled            = true; // enable border again
            rc1.Settings.Border.HorizontalLineBody = BorderConf.HorizontalLineAfterHeaderFunc;
            rc2.Length = length;
            rc2.Settings.Border.Enabled = true;

            CoEx.WriteTitleLarge("Tables - Chapter 3");
            CoEx.WriteLine();
            CoEx.WriteTitle("Synchonize column length over multiple tables");
            CoEx.WriteLine();
            CoEx.WriteTitle("The basic table, border header-only");
            CoEx.WriteTable(rc1);
            CoEx.WriteLine();
            CoEx.WriteTitle("The basic table with long text");
            CoEx.WriteTable(rc2);
        }
Esempio n. 16
0
        public static void DemoGraph()
        {
            CoEx.WriteTitleLarge("Simple Graph");
            CoEx.WriteLine();

            var graph = new SimpleGraph()
            {
                Height = 10
            };

            var list = new List <double>()
            {
                2, 1, 8, 16, 42, 0, 50, 0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 0, 10, 20, 30, 40, 50, 40, 30, 20, 10
            };

            var i        = 0;
            var temp     = DateTime.Now.Date;
            var dateList = list.ToDictionary(key => temp.AddDays(i++).ToString("ddMMM"), value => value);

            graph.Draw(dateList /*.Select(v => v * 42).ToList()*/ /*.OrderBy(v => v).ToList()*/);
        }
Esempio n. 17
0
        /// <summary>
        /// List existing aliases
        /// </summary>
        /// <param name="config">Config</param>
        /// <param name="args">CMD Args</param>
        /// <param name="provider">Provider</param>
        /// <returns>Exit Code</returns>
        private static async Task <int> ListAliases(Data.MailiasConfig config, Args args, Data.IProvider provider)
        {
            // Table header
            var header = new string[] { "Source", "Targets" };

            // Convert the alias items into table rows
            var aliases = (await provider.GetAliases(config))
                          .Select(a => a.SourceAddress)
                          .ToList();

            if (aliases.Count > 0)
            {
                CoEx.WriteLine(string.Join(Environment.NewLine, aliases));
                return(0);
            }
            else
            {
                // no aliases found
                return(1);
            }
        }
Esempio n. 18
0
        protected static void DemoPrompt()
        {
            Prompt prompt = new Prompt()
            {
                AllowEmpty      = false,
                Prefix          = "Choose your choice",
                Default         = "okay",
                ValidateChoices = true,
                ChoicesText     = new Dictionary <string, string>()
                {
                    { "yes", "Yea, lets go" },
                    { "sure", "Sure, why not" },
                    { "okay", "Okay, go for it" },
                    { "yay", "Yay, kay, thx, bye" }
                }
            };

            CoEx.WriteTitleLarge("Welcome, lets get started with a basic prompt");
            CoEx.WriteLine();

            prompt.DoPrompt();
        }
Esempio n. 19
0
        /// <summary>
        /// Delete an existing alias
        /// </summary>
        /// <param name="config">Config</param>
        /// <param name="args">CMD Args</param>
        /// <param name="provider">Provider</param>
        /// <returns>Exit Code</returns>
        private static async Task <int> DeleteAlias(Data.MailiasConfig config, Args args, Data.IProvider provider)
        {
            var exists = (await provider.GetAliases(config))
                         .Any(alias => alias.SourceAddress == args.DeleteAlias);

            if (exists)
            {
                if (args.Force || YesNo("Really delete alias '" + args.DeleteAlias + "'?"))
                {
                    var result = await provider.DeleteAliasAddress(args.DeleteAlias);

                    if (result == Data.DeleteResult.Success)
                    {
                        return(0);
                    }

                    if (!args.Silent)
                    {
                        CoEx.WriteLine("Delete failed.");
                    }

                    return(1);
                }
                else
                {
                    return(0);
                }
            }
            else
            {
                if (!args.Silent)
                {
                    CoEx.WriteLine("Alias not found or didn't match the format of an alias which was created with this application.");
                }

                return(1);
            }
        }
Esempio n. 20
0
 /// <summary>
 /// The "Continue (Enter)" dialog
 /// </summary>
 private static void Continue()
 {
     CoEx.WriteLine();
     CoEx.PressAnyKey();
     CoEx.Clear();
 }
Esempio n. 21
0
        static void Main(string[] args)
        {
            /**
             * Console defaults
             */
            CoEx.WindowHeight = CoEx.WindowHeightMax - 10;
            CoEx.BufferHeight = 256;


            /**
             * Table defaults
             */
            RowCollection.DefaultSettings.Border.Enabled            = true;                                  // enable bordering
            RowCollection.DefaultSettings.Border.HorizontalLineBody = BorderConf.HorizontalLineAlwaysOnFunc; // line between the rows

            header = RowConf.Create(headerdata).PresetTH();
            rc1    = RowCollection.Create(exambledata);
            rc2    = RowCollection.Create(exambledatalong);


            /**
             * Demo parts
             */
            Continue();

            DemoLoadIndicator();
            CoEx.Clear();

            DemoGraph();
            Continue();
            CoEx.Clear();

            DemoProgressBar();
            CoEx.Clear();

            DemoTimeout();

            DemoScrolltext();
            CoEx.Clear();

            DemoProgressBarMessages();
            CoEx.Clear();

            DemoPrompt();
            CoEx.Clear();

            DemoIntro();
            Continue();

            DemoBasicColumns();
            Continue();

            DemoBasicTable();
            Continue();

            BasicTableLongText();
            Continue();

            DemoTableSynchronized();
            Continue();

            DemoConditionalStyles();
            Continue();

            DemoAlignment();


            /**
             * The End
             */
            CoEx.WriteLine();
            CoEx.WriteHl("Program finished.");
            CoEx.Confirm("Exit?");
        }
Esempio n. 22
0
        protected static void DemoConditionalStyles()
        {
            CoEx.WriteTitleLarge("Tables - Chapter 4");
            CoEx.WriteLine();
            CoEx.WriteTitle("Colorize cells by conditions");

            // colorize column by index
            rc1.Settings.Color = delegate(RowConf me, int colindex, string s)
            {
                var temp = new ColorScheme(null, ConsoleColor.Blue);
                switch (colindex)
                {
                case 0: temp.Background = ConsoleColor.Cyan; break;

                case 1: temp.Background = ConsoleColor.White; break;

                case 2: temp.Background = ConsoleColor.Magenta; break;

                case 3: temp.Background = ConsoleColor.Red; break;

                default: temp.Background = ConsoleColor.Gray; break;
                }
                return(temp);
            };

            // Highlight padding every second column
            rc1.Settings.IsHighlightPadding = delegate(RowConf me, int colindex, string s)
            {
                return((colindex % 2) == 0);
            };

            CoEx.WriteLine();
            CoEx.WriteTitle("Background color based on column index");
            CoEx.WriteTable(rc1);

            // if hours>10 is column 2 yellow and column 0 red
            rc2.Settings.Color = delegate(RowConf me, int colindex, string s)
            {
                double hours;
                bool   success = double.TryParse(me.Data[2], out hours);

                if (colindex == 2 && success && hours >= 10)
                {
                    return(new ColorScheme(ConsoleColor.Yellow, ConsoleColor.Blue));
                }
                else if (colindex == 0 && success && hours >= 10)
                {
                    return(new ColorScheme(ConsoleColor.Red, null));
                }
                else
                {
                    return(null);
                }
            };

            // highlight padding in column 0
            rc2.Settings.IsHighlightPadding = delegate(RowConf me, int colindex, string s)
            {
                return(colindex == 0);
            };

            CoEx.WriteLine();
            CoEx.WriteTitle("Background color based on hours value");
            CoEx.WriteTable(rc2);
        }
Esempio n. 23
0
        /// <summary>
        /// Create an alias
        /// </summary>
        /// <param name="config">Config</param>
        /// <param name="args">CMD Args</param>
        /// <param name="provider">Provider</param>
        /// <returns>Exit code</returns>
        private static async Task <int> CreateAlias(Data.MailiasConfig config, Args args, Data.IProvider provider)
        {
            // Create a new random id
            var chars   = "abcdefghijklmnopqrstuvwxyz0123456789";
            var builder = new StringBuilder();
            var random  = new Random();

            while (builder.Length < config.UniqeIdLength)
            {
                var index = random.Next(0, chars.Length - 1);
                builder.Append(chars[index]);
            }

            // Build the email address
            var prefix = string.IsNullOrWhiteSpace(config.Prefix) ? "" : config.Prefix + ".";
            var key    = builder.ToString();

            var mailAddress = $"{prefix}{args.CreateName}.{key}@{config.MailDomain}";

            // Check if the email address already exists
            var exists = (await provider.GetAliases(config))
                         .FirstOrDefault(a => a.SourceAddress.StartsWith($"{prefix}{args.CreateName}."));

            if (exists != null && args.Force == false)
            {
                if (!YesNo($"There is already an alias ({exists.SourceAddress}) with this name. Proceed?"))
                {
                    return(1);
                }
            }

            // Delete the existing alias
            if (exists != null && args.DeleteExisting)
            {
                if (args.Force || YesNo($"Dou you want do delete the existing alias '{exists.SourceAddress}', before creating a new one?"))
                {
                    var deleteExistingResult = await provider.DeleteAliasAddress(exists.SourceAddress);

                    if (deleteExistingResult != Data.DeleteResult.Success && !args.Silent)
                    {
                        CoEx.WriteLine("Deleting existing alias failed.");
                        return(1);
                    }
                }
            }

            // Create the new alias
            var result = await provider.CreateAlias(mailAddress, config.TargetAddress);

            if (result == Data.CreateResult.Success || result == Data.CreateResult.AlreadyExists)
            {
                CoEx.WriteLine(mailAddress);
                return(0);
            }
            else
            {
                if (!args.Silent)
                {
                    CoEx.WriteLine("Creation failed.");
                }

                return(1);
            }
        }
Esempio n. 24
0
        private static void PrintStats(string path, string htmloutfile)
        {
            using (var thread = Load(path))
                using (var writer = new CoExHtmlWriter()
                {
                    Title = "Das Längste"
                })
                {
                    CoEx.WriteTitleLarge($"Statistics for {thread.StartpageUrl}");
                    CoEx.WriteLine();

                    CoEx.WriteLine(new string[] {
                        "If you don't want to appear in this statistic, ",
                        "just add the keyword 'donottrack' to your signature."
                    });

                    CoEx.WriteLine();

                    //--> Filter functions
                    bool filteroptoutpost(ThreadPost post)
                    {
                        return((post?.User?.SignatureHtml?.RemoveHtml().Contains("donottrack", StringComparison.InvariantCultureIgnoreCase) ?? false) == false);
                    }

                    bool filteroptoutuser(ForumUser user)
                    {
                        return((user?.SignatureHtml?.RemoveHtml().Contains("donottrack", StringComparison.InvariantCultureIgnoreCase) ?? false) == false);
                    }

                    //--> Default filters
                    var cleanposts = thread.Posts.Where(v => filteroptoutpost(v));
                    var cleanusers = thread.Users.Users
                                     .Where(v => filteroptoutuser(v))
                                     .Intersect(cleanposts.Select(u => u.User).Distinct());

                    //--> Current status
                    var curstats = new string[][]
                    {
                        new string[] { "JSON file:", Path.GetFileName(path) },
                        new string[] { "JSON file size:", (new FileInfo(path)).Length.HumanBytes() },
                        new string[] { "Crawl date:", thread.CrawlTimestamp.ToString("yyyy-MM-dd HH:mm:ss") },
                        new string[] { "Post count:", cleanposts.Count().ToString("#,###") },
                        new string[] { "Users involved:", cleanusers.Count().ToString("#,###") },
                        new string[] { "Banned users:", cleanusers.Where(u => u.IsBanned).Count().ToString("#,###") },
                        new string[] { "Opt-Out users:", thread.Users.Users.Where(v => filteroptoutuser(v) == false).Count().ToString("#,##0") },
                        new string[] { "Total likes:", cleanposts.Sum(v => v.LikeCount).ToString("#,##0") },
                        new string[] { "Total dislikes:", cleanposts.Sum(v => v.DislikeCount).ToString("#,##0") },
                        new string[] { "Posts with likes:", cleanposts.Where(v => v.LikeCount > 0).Count().ToString("#,##0") },
                        new string[] { "Posts with dislikes:", cleanposts.Where(v => v.DislikeCount > 0).Count().ToString("#,##0") },
                        new string[] { "First post:", cleanposts.Min(v => v.Date).ToString("yyyy-MM-dd HH:mm:ss") },
                        new string[] { "Last post:", cleanposts.Max(v => v.Date).ToString("yyyy-MM-dd HH:mm:ss") },
                        new string[] { "Thread age:", (cleanposts.Max(v => v.Date) - cleanposts.Min(v => v.Date)).PrettyPrint() },
                        new string[] { "First user:"******"{v.Key.Username} ({v.Count()})").First() },
                        new string[] { "Newest user:"******"{v.Key.Username} ({v.Count()})").First() }
                    };

                    CoEx.WriteTitle("Current status");
                    CoEx.WriteTable(RowCollection.Create(curstats));
                    CoEx.WriteLine();

                    //--> User statistics
                    var userstats = cleanposts
                                    .Where(v => v.User != null)
                                    .GroupBy(v => v.User)
                                    .OrderByDescending(v => v.Count())
                                    .Take(30)
                                    .Select(v => new string[]
                    {
                        v.Key.Username,
                        v.Key.PostCount.ToString("#,###"),
                        v.Count().ToString("#,###"),
                        (100.0 * v.Count() / v.Key.PostCount).ToString("0.0") + "%",
                        (100.0 * v.Count() / cleanposts.Count()).ToString("0.0") + "%",
                        v.Min(j => j.Date).ToString("yyyy-MM-dd HH:mm"),
                        v.Max(j => j.Date).ToString("yyyy-MM-dd HH:mm"),
                        v.Key.MemberSince.ToString("yyyy-MM-dd")
                    })
                                    .Prepend(new string[]
                    {
                        "Username",
                        "All Posts",
                        "Thread Posts",
                        "User %",
                        "Thread %",
                        "First Post",
                        "Last Post",
                        "Member since"
                    });

                    var userrows = RowCollection.Create(userstats.ToArray());
                    userrows.Settings.Border.Enabled = true;

                    userrows.Settings.Align = (conf, colidx, s) =>
                    {
                        switch (colidx)
                        {
                        case 1:
                        case 2:
                        case 3:
                        case 4:
                            return(RowCollectionSettings.ALIGN.RIGHT);

                        default:
                            return(RowCollectionSettings.ALIGN.LEFT);
                        }
                    };

                    CoEx.WriteTitle("Statistics by user");
                    CoEx.WriteTable(userrows);
                    CoEx.WriteLine();


                    //--> User like statistics
                    var userlikes = cleanposts
                                    .Where(v => v.User != null)
                                    .GroupBy(v => v.User)
                                    .Where(v => v.Sum(j => j.LikeCount) > 0)
                                    .OrderByDescending(v => v.Sum(j => j.LikeCount))
                                    .Take(10)
                                    .Select(v => new string[]
                    {
                        v.Key.Username,
                        v.Sum(j => j.LikeCount).ToString("#,##0"),
                        v.Where(j => j.LikeCount > 0).Min(j => j.Date).ToString("yyyy-MM-dd HH:mm"),
                        v.Where(j => j.LikeCount > 0).Max(j => j.Date).ToString("yyyy-MM-dd HH:mm")
                    })
                                    .Prepend(new string[]
                    {
                        "Username",
                        "Likes",
                        "First like received",
                        "Last like received"
                    });

                    var userlikerows = RowCollection.Create(userlikes.ToArray());
                    userlikerows.Settings.Border.Enabled = true;

                    userlikerows.Settings.Align = (conf, colidx, s) =>
                    {
                        switch (colidx)
                        {
                        case 1:
                            return(RowCollectionSettings.ALIGN.RIGHT);

                        default:
                            return(RowCollectionSettings.ALIGN.LEFT);
                        }
                    };

                    CoEx.WriteTitle("Statistics by likes");
                    CoEx.WriteTable(userlikerows);
                    CoEx.WriteLine();


                    //--> User title statistics
                    var titlestats = cleanposts
                                     .Where(v => v.User != null)
                                     .GroupBy(v => v.User.Title)
                                     .OrderByDescending(v => v.Count())
                                     .Select(v => new string[]
                    {
                        v.Key,
                        v.Count().ToString("#,###"),
                        v.Min(j => j.Date).ToString("yyyy-MM-dd HH:mm"),
                        v.Max(j => j.Date).ToString("yyyy-MM-dd HH:mm")
                    })
                                     .Prepend(new string[]
                    {
                        "Title",
                        "Posts",
                        "First Post",
                        "Last Post"
                    });

                    var titlerows = RowCollection.Create(titlestats.ToArray());
                    titlerows.Settings.Border.Enabled = true;

                    titlerows.Settings.Align = (conf, colidx, s) =>
                    {
                        switch (colidx)
                        {
                        case 1:
                            return(RowCollectionSettings.ALIGN.RIGHT);

                        default:
                            return(RowCollectionSettings.ALIGN.LEFT);
                        }
                    };

                    CoEx.WriteTitle("Statistics by user title");
                    CoEx.WriteTable(titlerows);
                    CoEx.WriteLine();


                    //--> Post likes
                    var likeposts = cleanposts
                                    .Where(v => v.User != null)
                                    .OrderByDescending(v => v.LikeCount)
                                    .Take(10)
                                    .Select(v => new string[]
                    {
                        v.Date.ToString("yyyy-MM-dd"),
                        v.LikeCount.ToString("#,###"),
                        v.User.Username,
                        v.Url
                    })
                                    .Prepend(new string[]
                    {
                        "Date",
                        "Likes",
                        "Author",
                        "Post Url"
                    });

                    var likepostrows = RowCollection.Create(likeposts.ToArray());
                    likepostrows.Settings.Border.Enabled = true;

                    likepostrows.Settings.Align = (conf, colidx, s) =>
                    {
                        switch (colidx)
                        {
                        case 1:
                            return(RowCollectionSettings.ALIGN.RIGHT);

                        default:
                            return(RowCollectionSettings.ALIGN.LEFT);
                        }
                    };

                    CoEx.WriteTitle("Most liked posts");
                    CoEx.WriteTable(likepostrows);
                    CoEx.WriteLine();


                    //--> Year statistics
                    var yearmaxlength = cleanposts
                                        .GroupBy(v => v.Date.Year)
                                        .Select(v => v.Count().ToString().Length)
                                        .Max();

                    var yearstats = cleanposts
                                    .GroupBy(v => v.Date.Year)
                                    .Select(v => new string[]
                    {
                        v.Key.ToString(),
                        v.Min(j => j.Date).ToString("MM-dd HH:mm"),
                        v.Max(j => j.Date).ToString("MM-dd HH:mm"),
                        v.GroupBy(j => j.User).Count().ToString("#,###"),
                        v.Count().ToString("#,###"),
                        string.Join(", ", v.GroupBy(j => j.User).OrderByDescending(j => j.Count()).Take(3).Select(j => $"{j.Key?.Username??"Guest"} ({j.Count()})")),
                        v.Max(j => j.MessageHtml.RemoveHtml().Length).ToString("#,###")
                    })
                                    .Prepend(new string[]
                    {
                        "Year",
                        "First Post",
                        "Last Post",
                        "Active",
                        "Posts",
                        "Top Users",
                        "Largest Msg"
                    });

                    var yeargraphstats = cleanposts
                                         .GroupBy(v => v.Date.Year)
                                         .Select(v => new dynamic[]
                    {
                        v.Key.ToString(),
                        v.Count(),
                    })
                                         .OrderByDescending(v => (string)v[0])
                                         .Take((int)((CoEx.ForcedBufferWidth.Value - yearmaxlength - 4) / 2))
                                         .OrderBy(v => (string)v[0])
                                         .ToDictionary(key => (string)key[0], value => (double)value[1]);

                    var yearrows = RowCollection.Create(yearstats.ToArray());
                    yearrows.Settings.Border.Enabled = true;

                    yearrows.Settings.Align = (conf, colidx, s) =>
                    {
                        switch (colidx)
                        {
                        case 3:
                        case 4:
                        case 6:
                            return(RowCollectionSettings.ALIGN.RIGHT);

                        default:
                            return(RowCollectionSettings.ALIGN.LEFT);
                        }
                    };

                    CoEx.WriteTitle("Statistics by year");
                    var graph = new SimpleGraph()
                    {
                        Height = 15
                    };

                    graph.Draw(yeargraphstats);
                    CoEx.WriteLine();

                    CoEx.WriteTable(yearrows);
                    CoEx.WriteLine();

                    //--> Month statistics
                    var monthstats = cleanposts
                                     .GroupBy(v => v.Date.GetMonth())
                                     .Select(v => new string[]
                    {
                        v.Key.ToString("yyyy-MM"),
                        v.Min(j => j.Date).ToString("dd HH:mm"),
                        v.Max(j => j.Date).ToString("dd HH:mm"),
                        v.GroupBy(j => j.User).Count().ToString("#,###"),
                        v.Count().ToString("#,###"),
                        string.Join(", ", v.GroupBy(j => j.User).OrderByDescending(j => j.Count()).Take(3).Select(j => $"{j.Key?.Username??"Guest"} ({j.Count()})")),
                        v.Max(j => j.MessageHtml.RemoveHtml().Length).ToString("#,###")
                    })
                                     .Prepend(new string[]
                    {
                        "Month",
                        "First Post",
                        "Last Post",
                        "Active",
                        "Posts",
                        "Top Users",
                        "Largest Msg"
                    });

                    var monthmaxlength = cleanposts
                                         .GroupBy(v => v.Date.GetMonth())
                                         .Select(v => v.Count().ToString().Length)
                                         .Max();

                    var monthgraphstats = cleanposts
                                          .GroupBy(v => v.Date.GetMonth())
                                          .Select(v => new dynamic[]
                    {
                        v.Key.ToString("yyMM"),
                        v.Count(),
                    })
                                          .OrderByDescending(v => (string)v[0])
                                          .Take((int)((CoEx.ForcedBufferWidth.Value - monthmaxlength - 4) / 2))
                                          .OrderBy(v => (string)v[0])
                                          .ToDictionary(key => (string)key[0], value => (double)value[1]);

                    var monthrows = RowCollection.Create(monthstats.ToArray());
                    monthrows.Settings.Border.Enabled = true;

                    monthrows.Settings.Align = (conf, colidx, s) =>
                    {
                        switch (colidx)
                        {
                        case 3:
                        case 4:
                        case 6:
                            return(RowCollectionSettings.ALIGN.RIGHT);

                        default:
                            return(RowCollectionSettings.ALIGN.LEFT);
                        }
                    };

                    CoEx.WriteTitle("Statistics by month");

                    graph.Draw(monthgraphstats);
                    CoEx.WriteLine();

                    CoEx.WriteTable(monthrows);
                    CoEx.WriteLine();

                    writer.SaveAs(htmloutfile);
                }
        }