private static Dictionary <string, string> DecodeTickets()
        {
            Console.Write("Checking Title Keys validity against Nintendo CDN.");
            ConsoleUtils.PrintColorfulLine(ConsoleColor.Green, " This might take a while...");
            ConsoleUtils.PrintColorfulLine(
                ConsoleColor.Green,
                "Parsing only Games and Addon DLCs. Ticket count might decrease as we weed out invalid tickets.");

            Func <string, bool> gameOrDlc =
                titleId =>
                Nintendo3DSRelease.GetTitleType(titleId) == "Unknown Type" ||
                Nintendo3DSRelease.GetTitleType(titleId) == "Addon DLC" || Nintendo3DSRelease.GetTitleType(titleId) == "3DS Game";

            var ticketsDictionary = ParseDecTitleKeysBin();

            ticketsDictionary =
                new SortedDictionary <string, string>(
                    ticketsDictionary.Where(a => gameOrDlc(a.Key)).ToDictionary(a => a.Key, a => a.Value));

            var validKeys = new Dictionary <string, string>();

            var processedTickets = 0;
            var totalTickets     = ticketsDictionary.Count;

            foreach (var pair in ticketsDictionary)
            {
                var titleId  = pair.Key;
                var titleKey = pair.Value;

                var valid = CDNUtils.TitleKeyIsValid(titleId, titleKey);

                if (valid)
                {
                    validKeys[titleId] = titleKey;
                    const int TitleTypePad = 10;
                    Console.Write('\r' + Nintendo3DSRelease.GetTitleType(titleId).PadRight(TitleTypePad) + pair.Key + ": Valid | ");
                    ConsoleUtils.PrintColorful(ConsoleColor.Green, $"({++processedTickets}/{totalTickets} valid)");
                }
                else
                {
                    totalTickets--;
                }
            }

            Console.WriteLine();

            Console.Write("Found ");
            ConsoleUtils.PrintColorful(ConsoleColor.Green, ticketsDictionary.Count - totalTickets);
            Console.WriteLine(" invalid tickets. Searching through databases for the valid ones...");

            return(validKeys);
        }
        public static void Main(string[] args)
        {
            ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true;
            Console.OutputEncoding = Encoding.UTF8;
#if !DEBUG
            try
            {
#endif
            PrintProgramVersion();


            ProcessArgs(args);

            if (!File.Exists(Files.DecTitleKeysPath))
            {
                ConsoleUtils.PrintColorfulLine(
                    ConsoleColor.Red,
                    "decTitleKeys.bin not found! Get it from Decrypt9. Press any key to exit.");
                Console.ReadKey();
                Environment.Exit(1);
            }

            var decTitleKeysFile = File.ReadAllBytes(Files.DecTitleKeysPath);
            var computedHash     = BitConversion.BytesToHex(MD5.Create().ComputeHash(decTitleKeysFile));

            var shouldRecheck = false;

            if (!File.Exists(Files.DecTitleKeysMd5))
            {
                File.WriteAllText(Files.DecTitleKeysMd5, computedHash);
            }
            else
            {
                var savedHash = File.ReadAllText(Files.DecTitleKeysMd5);

                if (savedHash != computedHash)
                {
                    Console.WriteLine("Different decTitleKeys.bin found!");
                    Console.Write("Recheck titles? y/n: ");

                    var keyChosen = Console.ReadKey().Key;
                    if (keyChosen == ConsoleKey.Y)
                    {
                        shouldRecheck = true;
                        File.WriteAllText(Files.DecTitleKeysMd5, computedHash);
                    }
                }
            }

            if (args != null && args.Contains("-update"))
            {
                UpdateDependencies();
            }
            else
            {
                Files.CheckFor3dsDb();
                Files.CheckForGroovyCiaDb();
            }

            var tickets = new Dictionary <string, string>();

            if ((!File.Exists(Files.ValidTicketsPath) || new FileInfo(Files.ValidTicketsPath).Length == 0) || shouldRecheck)
            {
                Console.WriteLine("Decoding valid tickets...");
                tickets = DecodeTickets();
                var ticketsAsStrings = tickets.Select(ticket => ticket.Key + " " + ticket.Value).ToList();

                File.WriteAllText(Files.ValidTicketsPath, string.Join(Environment.NewLine, ticketsAsStrings));
                Console.WriteLine("Wrote valid tickets to ValidTickets.txt");
            }

            var parsedTickets = ParseTickets(tickets).ToArray();

            var titlesFound = ParseTicketsFromGroovyCiaDb(parsedTickets, Files.GroovyCiaPath);
            titlesFound = ParseTicketsFrom3DsDb(titlesFound);

            var longestTitleLength     = titlesFound.Max(a => a.Name.Length) + 2;
            var longestPublisherLength = titlesFound.Max(a => a.Publisher.Length) + 2;

            PrintNumberOfTicketsFound(titlesFound, parsedTickets);

            Console.WriteLine(PrintTitleLegend(longestTitleLength, longestPublisherLength));

            // titlesFound = titlesFound.OrderBy(r => Nintendo3DSRelease.GetTitleType(r.TitleId)).ThenBy(r => r.Name).ToList();
            foreach (var title in titlesFound)
            {
                var fullWidthExtraPadName      = GetFullWidthExtraPad(title.Name);
                var fullWidthExtraPadPublisher = GetFullWidthExtraPad(title.Publisher);

                Console.WriteLine(
                    $"{title.TitleId} {title.DecTitleKey} | {title.Name.PadRight(longestTitleLength - fullWidthExtraPadName)}{title.Publisher.PadRight(longestPublisherLength - fullWidthExtraPadPublisher)}{title.Region}");
            }

            Console.WriteLine(
                "\r\nTitles which 3dsdb or the GroovyCIA db couldn't find but we'll look up from the Nintendo CDN:");

            Console.WriteLine(PrintTitleLegend(longestTitleLength, longestPublisherLength));

            var remainingTitles = parsedTickets.Except(titlesFound).ToList();
            remainingTitles =
                LookUpRemainingTitles(remainingTitles, longestTitleLength, longestPublisherLength)
                .OrderBy(r => Nintendo3DSRelease.GetTitleType(r.TitleId))
                .ThenBy(r => r.Name)
                .ToList();

            WriteOutputToFile(longestTitleLength, longestPublisherLength, titlesFound, remainingTitles);
            WriteOutputToCsv(titlesFound, remainingTitles);

            Console.Write("Done! Tickets and titles exported to ");
            ConsoleUtils.PrintColorfulLine(ConsoleColor.Green, Files.OutputFile);

            Console.Write("Detailed info exported to ");
            ConsoleUtils.PrintColorfulLine(ConsoleColor.Green, Files.DetailedOutputFile);

            // #if !DEBUG
            Console.Write("Press any key to exit...");
            Console.ReadKey();
            // #endif
#if !DEBUG
        }

        catch (Exception ex)
        {
            ConsoleUtils.PrintColorfulLine(ConsoleColor.Red, "Fatal Error: " + ex.Message);

            Console.WriteLine(ex.StackTrace);
        }
#endif
        }