internal static bool TryParseLetterString(string s, PasswordStyles style, string name, int length, out Letter[] letters, out int value)
        {
            letters = null;
            value   = 0;
            if (s == null)
            {
                return(false);
            }

            // Check and remove flags
            bool allowSpecifier = style.HasFlag(PasswordStyles.AllowSpecifier);

            style &= ~PasswordStyles.FlagsMask;
            PasswordStyles specifier = PasswordStyles.AllowSpecifier;

            // Identify the specifier
            if (s.StartsWith("0B") || s.StartsWith("0b"))
            {
                specifier = PasswordStyles.Binary;
            }
            else if (s.StartsWith("0X") || s.StartsWith("0x"))
            {
                specifier = PasswordStyles.Hex;
            }
            // Don't mix up hex/binary numbers with decimal
            else if (style != PasswordStyles.Hex && style != PasswordStyles.Binary && IsOnlyDigits(s))
            {
                specifier = PasswordStyles.Value;
            }

            // Handle specifier or pure digits
            if (specifier == PasswordStyles.Value)
            {
                // Validate the decimal style
                if (style != PasswordStyles.Value && style != PasswordStyles.PasswordOrValue &&
                    style != PasswordStyles.None)
                {
                    return(false);
                }
                style = specifier;
            }
            else if (specifier != PasswordStyles.AllowSpecifier)
            {
                // Validate the specifier
                if (!allowSpecifier || (style != PasswordStyles.None && specifier != style))
                {
                    return(false);
                }
                style = specifier;
                s     = s.Substring(2);
            }
            else if (style == PasswordStyles.PasswordOrValue)
            {
                // We're not a value, set us to password style
                style = PasswordStyles.Password;
            }

            // No trailing whitespace
            if (s.Trim() != s)
            {
                return(false);
            }

            // Internal whitespace can be removed from binary
            if (style == PasswordStyles.Binary)
            {
                s = Regex.Replace(s, @"\s+", "");
            }
            if (style != PasswordStyles.Value)
            {
                // Make sure the length is correct
                if (s.Length != length * (style == PasswordStyles.Binary ? 4 : 1))
                {
                    return(false);
                }
                // Easymode shortcut
                if (length == 0)
                {
                    letters = Array.Empty <Letter>();
                    return(true);
                }
            }

            // Parse the string
            Letter[] newLetters = new Letter[length];
            switch (style)
            {
            case PasswordStyles.None:
            case PasswordStyles.Password:
            case PasswordStyles.Hex:
                for (int i = 0; i < length; i++)
                {
                    if (!TryParseLetter(s.Substring(i, 1), style, out newLetters[i]))
                    {
                        return(false);
                    }
                }
                break;

            case PasswordStyles.Binary:
                for (int i = 0; i < length; i++)
                {
                    if (!TryParseLetter(s.Substring(i * 4, 4), style, out newLetters[i]))
                    {
                        return(false);
                    }
                }
                break;

            case PasswordStyles.Value:
                if (!int.TryParse(s, out value))
                {
                    return(false);
                }
                letters = null;                 // Null signifies a value return
                break;

            default:
                return(false);
            }
            letters = newLetters;
            return(true);
        }
        internal static bool TryParseLetter(string s, PasswordStyles style, out Letter letter)
        {
            letter = new Letter();
            if (s == null || s.Length == 0)
            {
                return(false);
            }

            // Check and remove flags
            bool allowSpecifier = style.HasFlag(PasswordStyles.AllowSpecifier);

            style &= ~PasswordStyles.FlagsMask;
            PasswordStyles specifier = PasswordStyles.AllowSpecifier;

            // Identify the specifier
            if (s.StartsWith("0B") || s.StartsWith("0b"))
            {
                specifier = PasswordStyles.Binary;
            }
            else if (s.StartsWith("0X") || s.StartsWith("0x"))
            {
                specifier = PasswordStyles.Hex;
            }
            // Don't mix up hex/binary numbers with decimal
            else if (style != PasswordStyles.Hex && style != PasswordStyles.Binary && IsOnlyDigits(s))
            {
                specifier = PasswordStyles.Value;
            }

            // Handle specifier or pure digits
            if (specifier == PasswordStyles.Value)
            {
                // Validate the decimal style
                if (style != PasswordStyles.Value && style != PasswordStyles.PasswordOrValue &&
                    style != PasswordStyles.None)
                {
                    return(false);
                }
                style = specifier;
            }
            else if (specifier != PasswordStyles.AllowSpecifier)
            {
                // Validate the specifier
                if (!allowSpecifier || (style != PasswordStyles.None && specifier != style))
                {
                    return(false);
                }
                style = specifier;
                s     = s.Substring(2);
            }
            else if (style == PasswordStyles.PasswordOrValue)
            {
                // We're not a value, set us to password style
                style = PasswordStyles.Password;
            }

            char c;

            switch (style)
            {
            case PasswordStyles.None:
            case PasswordStyles.Password:
                c = s[0];
                if (s.Length != 1 || !Letter.IsValidChar(c))
                {
                    return(false);
                }
                letter = new Letter(c);
                return(true);

            case PasswordStyles.Hex:
                c = char.ToUpper(s[0]);
                if (s.Length != 1 || (!char.IsDigit(c) && c < 'A' && c > 'F'))
                {
                    return(false);
                }
                letter = new Letter(Convert.ToInt32(s, 16));
                return(true);

            case PasswordStyles.Binary:
                if (s.Length != 4)
                {
                    return(false);
                }
                for (int i = 0; i < 4; i++)
                {
                    if (s[i] != '0' && s[i] != '1')
                    {
                        return(false);
                    }
                }
                letter = new Letter(Convert.ToInt32(s, 2));
                return(true);

            case PasswordStyles.Value:
                if (!int.TryParse(s, out int value))
                {
                    return(false);
                }
                letter = new Letter(value);
                return(true);

            default:
                return(false);
            }
        }
        internal static Letter[] ParseLetterString(string s, PasswordStyles style, string name, int length, out int value)
        {
            value = 0;
            if (s == null)
            {
                throw new ArgumentNullException(nameof(s));
            }

            // Check and remove flags
            bool allowSpecifier = style.HasFlag(PasswordStyles.AllowSpecifier);

            style &= ~PasswordStyles.FlagsMask;
            PasswordStyles specifier = PasswordStyles.AllowSpecifier;

            // Identify the specifier
            if (s.StartsWith("0B") || s.StartsWith("0b"))
            {
                specifier = PasswordStyles.Binary;
            }
            else if (s.StartsWith("0X") || s.StartsWith("0x"))
            {
                specifier = PasswordStyles.Hex;
            }
            // Don't mix up hex/binary numbers with decimal
            else if (style != PasswordStyles.Hex && style != PasswordStyles.Binary && IsOnlyDigits(s))
            {
                specifier = PasswordStyles.Value;
            }

            // Handle specifier or pure digits
            if (specifier == PasswordStyles.Value)
            {
                // Validate the decimal style
                if (style != PasswordStyles.Value && style != PasswordStyles.PasswordOrValue &&
                    style != PasswordStyles.None)
                {
                    throw new ArgumentException($"{name} format as value does not match style!");
                }
                style = specifier;
            }
            else if (specifier != PasswordStyles.AllowSpecifier)
            {
                // Validate the specifier
                if (!allowSpecifier)
                {
                    throw new ArgumentException($"{name} format specifier is not allowed!");
                }
                if (style != PasswordStyles.None && specifier != style)
                {
                    throw new ArgumentException($"{name} format specifier does not match style!");
                }
                style = specifier;
                s     = s.Substring(2);
            }
            else if (style == PasswordStyles.PasswordOrValue)
            {
                // We're not a value, set us to password style
                style = PasswordStyles.Password;
            }

            // No trailing whitespace
            if (s.Trim() != s)
            {
                throw new Exception($"{name} string cannot have trailing whitespace, got \"{s}\"!");
            }

            // Internal whitespace can be removed from binary
            if (style == PasswordStyles.Binary)
            {
                s = Regex.Replace(s, @"\s+", "");
            }
            if (style != PasswordStyles.Value)
            {
                // Make sure the length is correct
                if (s.Length != length * (style == PasswordStyles.Binary ? 4 : 1))
                {
                    throw new ArgumentException($"{name} string must be {length} letters long, got {s.Length} letters!",
                                                nameof(s));
                }
                // Easymode shortcut
                if (length == 0)
                {
                    return(Array.Empty <Letter>());
                }
            }

            // Parse the string
            Letter[] letters = new Letter[length];
            switch (style)
            {
            case PasswordStyles.None:
            case PasswordStyles.Password:
                for (int i = 0; i < length; i++)
                {
                    letters[i] = new Letter(s[i]);
                }
                return(letters);

            case PasswordStyles.Hex:
                for (int i = 0; i < length; i++)
                {
                    letters[i] = new Letter(Convert.ToInt32(s.Substring(i, 1), 16));
                }
                return(letters);

            case PasswordStyles.Binary:
                for (int i = 0; i < length; i++)
                {
                    letters[i] = new Letter(Convert.ToInt32(s.Substring(i * 4, 4), 2));
                }
                return(letters);

            case PasswordStyles.Value:
                value = int.Parse(s);
                return(null);                // Null signifies a value return.

            default:
                throw new ArgumentException($"Invalid {name} Password Style {style}!");
            }
        }
        internal static Letter ParseLetter(string s, PasswordStyles style)
        {
            if (s == null)
            {
                throw new ArgumentNullException(nameof(s));
            }


            // Check and remove flags
            bool allowSpecifier = style.HasFlag(PasswordStyles.AllowSpecifier);

            style &= ~PasswordStyles.FlagsMask;
            PasswordStyles specifier = PasswordStyles.AllowSpecifier;

            // Identify the specifier
            if (s.StartsWith("0B") || s.StartsWith("0b"))
            {
                specifier = PasswordStyles.Binary;
            }
            else if (s.StartsWith("0X") || s.StartsWith("0x"))
            {
                specifier = PasswordStyles.Hex;
            }
            // Don't mix up hex/binary numbers with decimal
            else if (style != PasswordStyles.Hex && style != PasswordStyles.Binary && IsOnlyDigits(s))
            {
                specifier = PasswordStyles.Value;
            }

            // Handle specifier or pure digits
            if (specifier == PasswordStyles.Value)
            {
                // Validate the decimal style
                if (style != PasswordStyles.Value && style != PasswordStyles.PasswordOrValue &&
                    style != PasswordStyles.None)
                {
                    throw new ArgumentException($"Letter format as value does not match style!");
                }
                style = specifier;
            }
            else if (specifier != PasswordStyles.AllowSpecifier)
            {
                // Validate the specifier
                if (!allowSpecifier)
                {
                    throw new ArgumentException($"Letter format specifier is not allowed!");
                }
                if (style != PasswordStyles.None && specifier != style)
                {
                    throw new ArgumentException($"Letter format specifier does not match style!");
                }
                style = specifier;
                s     = s.Substring(2);
            }
            else if (style == PasswordStyles.PasswordOrValue)
            {
                // We're not a value, set us to password style
                style = PasswordStyles.Password;
            }

            switch (style)
            {
            case PasswordStyles.None:
            case PasswordStyles.Password:
                if (s.Length != 1)
                {
                    throw new ArgumentException($"Letter Password string must be one character long, got {s.Length}!");
                }
                return(new Letter(s[0]));

            case PasswordStyles.Hex:
                if (s.Length != 1)
                {
                    throw new ArgumentException($"Letter Hex string must be one character long, got {s.Length}!");
                }
                return(new Letter(Convert.ToInt32(s, 16)));

            case PasswordStyles.Binary:
                if (s.Length != 4)
                {
                    throw new ArgumentException($"Letter Binary string must be four characters long, got {s.Length}!");
                }
                return(new Letter(Convert.ToInt32(s, 2)));

            case PasswordStyles.Value:
                return(new Letter(int.Parse(s)));

            default:
                throw new ArgumentException($"Invalid Password Style {style}!");
            }
        }