private static bool EvalAddPopularPasswordPattern(List <QePatternInstance>[] vPatterns,
                                                          char[] vPassword, int i, char[] vSub, double dblCostPerMod)
        {
            ulong uDictSize;

            if (!PopularPasswords.IsPopularPassword(vSub, out uDictSize))
            {
                return(false);
            }

            int n = vSub.Length;
            int d = HammingDistribution(vSub, 0, vPassword, i, n);

            double dblCost = Log2((double)uDictSize);

            // dblCost += log2(n binom d)
            int k = Math.Min(d, n - d);

            for (int j = n; j > (n - k); --j)
            {
                dblCost += Log2(j);
            }
            for (int j = k; j >= 2; --j)
            {
                dblCost -= Log2(j);
            }

            dblCost += dblCostPerMod * (double)d;

            vPatterns[i].Add(new QePatternInstance(i, n, PatternId.Dictionary,
                                                   dblCost));
            return(true);
        }
        private static void FindPopularPasswords(char[] password, List <QePatternInstance>[] patterns)
        {
            var passwordLength = password.Length;

            var lower = new char[passwordLength];
            var leet  = new char[passwordLength];

            for (var index = 0; index < passwordLength; ++index)
            {
                var character = password[index];

                lower[index] = char.ToLower(character);
                leet[index]  = char.ToLower(DecodeLeetChar(character));
            }

            var erased = default(char);

            Debug.Assert(erased == char.MinValue);

            var maximumLength = Math.Min(passwordLength, PopularPasswords.MaxLength);

            for (var subLength = maximumLength; subLength >= 3; --subLength)
            {
                if (!PopularPasswords.ContainsLength(subLength))
                {
                    continue;
                }

                var substring = new char[subLength];

                for (var index = 0; index <= (passwordLength - subLength); ++index)
                {
                    if (Array.IndexOf(lower, erased, index, subLength) >= 0)
                    {
                        continue;
                    }

                    Array.Copy(lower, index, substring, 0, subLength);
                    if (!EvalAddPopularPasswordPattern(patterns, password, index, substring, 0.0))
                    {
                        Array.Copy(leet, index, substring, 0, subLength);
                        if (EvalAddPopularPasswordPattern(patterns, password, index, substring, 1.5))
                        {
                            Array.Clear(lower, index, subLength);
                            Debug.Assert(lower[index] == erased);
                        }
                    }
                    else
                    {
                        Array.Clear(lower, index, subLength);
                        Debug.Assert(lower[index] == erased);
                    }
                }
            }
        }