__  __    __   __  _____      _            _          _____ _          _ _ 
 |  \/  |   \ \ / / |  __ \    (_)          | |        / ____| |        | | |
 | \  / |_ __\ V /  | |__) | __ ___   ____ _| |_ ___  | (___ | |__   ___| | |
 | |\/| | '__|> <   |  ___/ '__| \ \ / / _` | __/ _ \  \___ \| '_ \ / _ \ | |
 | |  | | |_ / . \  | |   | |  | |\ V / (_| | ||  __/  ____) | | | |  __/ | |
 |_|  |_|_(_)_/ \_\ |_|   |_|  |_| \_/ \__,_|\__\___| |_____/|_| |_|\___V 2.1
 if you need WebShell for Seo everyday contact me on Telegram
 Telegram Address : @jackleet
        
        
For_More_Tools: Telegram: @jackleet | Bulk Smtp support mail sender | Business Mail Collector | Mail Bouncer All Mail | Bulk Office Mail Validator | Html Letter private



Upload:

Command:

www-data@216.73.216.10: ~ $
this.zxcvbnts = this.zxcvbnts || {};
this.zxcvbnts.core = (function (exports) {
    'use strict';

    const empty = obj => Object.keys(obj).length === 0;
    const extend = (listToExtend, list) => // eslint-disable-next-line prefer-spread
    listToExtend.push.apply(listToExtend, list);
    const translate = (string, chrMap) => {
      const tempArray = string.split('');
      return tempArray.map(char => chrMap[char] || char).join('');
    }; // mod implementation that works for negative numbers

    const sorted = matches => matches.sort((m1, m2) => m1.i - m2.i || m1.j - m2.j);
    const buildRankedDictionary = orderedList => {
      const result = {};
      let counter = 1; // rank starts at 1, not 0

      orderedList.forEach(word => {
        result[word] = counter;
        counter += 1;
      });
      return result;
    };

    var dateSplits = {
      4: [// for length-4 strings, eg 1191 or 9111, two ways to split:
      [1, 2], [2, 3] // 91 1 1
      ],
      5: [[1, 3], [2, 3], //  [2, 3], // 91 1 11    <- duplicate previous one
      [2, 4] // 91 11 1    <- New and must be added as bug fix
      ],
      6: [[1, 2], [2, 4], [4, 5] // 1991 1 1
      ],
      //  1111991
      7: [[1, 3], [2, 3], [4, 5], [4, 6] // 1991 11 1
      ],
      8: [[2, 4], [4, 6] // 1991 11 11
      ]
    };

    const DATE_MAX_YEAR = 2050;
    const DATE_MIN_YEAR = 1000;
    const DATE_SPLITS = dateSplits;
    const BRUTEFORCE_CARDINALITY = 10;
    const MIN_GUESSES_BEFORE_GROWING_SEQUENCE = 10000;
    const MIN_SUBMATCH_GUESSES_SINGLE_CHAR = 10;
    const MIN_SUBMATCH_GUESSES_MULTI_CHAR = 50;
    const MIN_YEAR_SPACE = 20; // \xbf-\xdf is a range for almost all special uppercase letter like Ä and so on

    const START_UPPER = /^[A-Z\xbf-\xdf][^A-Z\xbf-\xdf]+$/;
    const END_UPPER = /^[^A-Z\xbf-\xdf]+[A-Z\xbf-\xdf]$/; // \xdf-\xff is a range for almost all special lowercase letter like ä and so on

    const ALL_UPPER = /^[A-Z\xbf-\xdf]+$/;
    const ALL_UPPER_INVERTED = /^[^a-z\xdf-\xff]+$/;
    const ALL_LOWER = /^[a-z\xdf-\xff]+$/;
    const ALL_LOWER_INVERTED = /^[^A-Z\xbf-\xdf]+$/;
    const ONE_LOWER = /[a-z\xdf-\xff]/;
    const ONE_UPPER = /[A-Z\xbf-\xdf]/;
    const ALPHA_INVERTED = /[^A-Za-z\xbf-\xdf]/gi;
    const ALL_DIGIT = /^\d+$/;
    const REFERENCE_YEAR = new Date().getFullYear();
    const REGEXEN = {
      recentYear: /19\d\d|200\d|201\d|202\d/g
    };

    /*
     * -------------------------------------------------------------------------------
     *  date matching ----------------------------------------------------------------
     * -------------------------------------------------------------------------------
     */

    class MatchDate {
      /*
       * a "date" is recognized as:
       *   any 3-tuple that starts or ends with a 2- or 4-digit year,
       *   with 2 or 0 separator chars (1.1.91 or 1191),
       *   maybe zero-padded (01-01-91 vs 1-1-91),
       *   a month between 1 and 12,
       *   a day between 1 and 31.
       *
       * note: this isn't true date parsing in that "feb 31st" is allowed,
       * this doesn't check for leap years, etc.
       *
       * recipe:
       * start with regex to find maybe-dates, then attempt to map the integers
       * onto month-day-year to filter the maybe-dates into dates.
       * finally, remove matches that are substrings of other matches to reduce noise.
       *
       * note: instead of using a lazy or greedy regex to find many dates over the full string,
       * this uses a ^...$ regex against every substring of the password -- less performant but leads
       * to every possible date match.
       */
      match({
        password
      }) {
        const matches = [...this.getMatchesWithoutSeparator(password), ...this.getMatchesWithSeparator(password)];
        const filteredMatches = this.filterNoise(matches);
        return sorted(filteredMatches);
      }

      getMatchesWithSeparator(password) {
        const matches = [];
        const maybeDateWithSeparator = /^(\d{1,4})([\s/\\_.-])(\d{1,2})\2(\d{1,4})$/; // # dates with separators are between length 6 '1/1/91' and 10 '11/11/1991'

        for (let i = 0; i <= Math.abs(password.length - 6); i += 1) {
          for (let j = i + 5; j <= i + 9; j += 1) {
            if (j >= password.length) {
              break;
            }

            const token = password.slice(i, +j + 1 || 9e9);
            const regexMatch = maybeDateWithSeparator.exec(token);

            if (regexMatch != null) {
              const dmy = this.mapIntegersToDayMonthYear([parseInt(regexMatch[1], 10), parseInt(regexMatch[3], 10), parseInt(regexMatch[4], 10)]);

              if (dmy != null) {
                matches.push({
                  pattern: 'date',
                  token,
                  i,
                  j,
                  separator: regexMatch[2],
                  year: dmy.year,
                  month: dmy.month,
                  day: dmy.day
                });
              }
            }
          }
        }

        return matches;
      } // eslint-disable-next-line max-statements


      getMatchesWithoutSeparator(password) {
        const matches = [];
        const maybeDateNoSeparator = /^\d{4,8}$/;

        const metric = candidate => Math.abs(candidate.year - REFERENCE_YEAR); // # dates without separators are between length 4 '1191' and 8 '11111991'


        for (let i = 0; i <= Math.abs(password.length - 4); i += 1) {
          for (let j = i + 3; j <= i + 7; j += 1) {
            if (j >= password.length) {
              break;
            }

            const token = password.slice(i, +j + 1 || 9e9);

            if (maybeDateNoSeparator.exec(token)) {
              const candidates = [];
              const index = token.length;
              const splittedDates = DATE_SPLITS[index];
              splittedDates.forEach(([k, l]) => {
                const dmy = this.mapIntegersToDayMonthYear([parseInt(token.slice(0, k), 10), parseInt(token.slice(k, l), 10), parseInt(token.slice(l), 10)]);

                if (dmy != null) {
                  candidates.push(dmy);
                }
              });

              if (candidates.length > 0) {
                /*
                 * at this point: different possible dmy mappings for the same i,j substring.
                 * match the candidate date that likely takes the fewest guesses: a year closest
                 * to 2000.
                 * (scoring.REFERENCE_YEAR).
                 *
                 * ie, considering '111504', prefer 11-15-04 to 1-1-1504
                 * (interpreting '04' as 2004)
                 */
                let bestCandidate = candidates[0];
                let minDistance = metric(candidates[0]);
                candidates.slice(1).forEach(candidate => {
                  const distance = metric(candidate);

                  if (distance < minDistance) {
                    bestCandidate = candidate;
                    minDistance = distance;
                  }
                });
                matches.push({
                  pattern: 'date',
                  token,
                  i,
                  j,
                  separator: '',
                  year: bestCandidate.year,
                  month: bestCandidate.month,
                  day: bestCandidate.day
                });
              }
            }
          }
        }

        return matches;
      }
      /*
       * matches now contains all valid date strings in a way that is tricky to capture
       * with regexes only. while thorough, it will contain some unintuitive noise:
       *
       * '2015_06_04', in addition to matching 2015_06_04, will also contain
       * 5(!) other date matches: 15_06_04, 5_06_04, ..., even 2015 (matched as 5/1/2020)
       *
       * to reduce noise, remove date matches that are strict substrings of others
       */


      filterNoise(matches) {
        return matches.filter(match => {
          let isSubmatch = false;
          const matchesLength = matches.length;

          for (let o = 0; o < matchesLength; o += 1) {
            const otherMatch = matches[o];

            if (match !== otherMatch) {
              if (otherMatch.i <= match.i && otherMatch.j >= match.j) {
                isSubmatch = true;
                break;
              }
            }
          }

          return !isSubmatch;
        });
      }
      /*
       * given a 3-tuple, discard if:
       *   middle int is over 31 (for all dmy formats, years are never allowed in the middle)
       *   middle int is zero
       *   any int is over the max allowable year
       *   any int is over two digits but under the min allowable year
       *   2 integers are over 31, the max allowable day
       *   2 integers are zero
       *   all integers are over 12, the max allowable month
       */
      // eslint-disable-next-line complexity, max-statements


      mapIntegersToDayMonthYear(integers) {
        if (integers[1] > 31 || integers[1] <= 0) {
          return null;
        }

        let over12 = 0;
        let over31 = 0;
        let under1 = 0;

        for (let o = 0, len1 = integers.length; o < len1; o += 1) {
          const int = integers[o];

          if (int > 99 && int < DATE_MIN_YEAR || int > DATE_MAX_YEAR) {
            return null;
          }

          if (int > 31) {
            over31 += 1;
          }

          if (int > 12) {
            over12 += 1;
          }

          if (int <= 0) {
            under1 += 1;
          }
        }

        if (over31 >= 2 || over12 === 3 || under1 >= 2) {
          return null;
        }

        return this.getDayMonth(integers);
      } // eslint-disable-next-line max-statements


      getDayMonth(integers) {
        // first look for a four digit year: yyyy + daymonth or daymonth + yyyy
        const possibleYearSplits = [[integers[2], integers.slice(0, 2)], [integers[0], integers.slice(1, 3)] // year first
        ];
        const possibleYearSplitsLength = possibleYearSplits.length;

        for (let j = 0; j < possibleYearSplitsLength; j += 1) {
          const [y, rest] = possibleYearSplits[j];

          if (DATE_MIN_YEAR <= y && y <= DATE_MAX_YEAR) {
            const dm = this.mapIntegersToDayMonth(rest);

            if (dm != null) {
              return {
                year: y,
                month: dm.month,
                day: dm.day
              };
            }
            /*
             * for a candidate that includes a four-digit year,
             * when the remaining integers don't match to a day and month,
             * it is not a date.
             */


            return null;
          }
        } // given no four-digit year, two digit years are the most flexible int to match, so
        // try to parse a day-month out of integers[0..1] or integers[1..0]


        for (let k = 0; k < possibleYearSplitsLength; k += 1) {
          const [y, rest] = possibleYearSplits[k];
          const dm = this.mapIntegersToDayMonth(rest);

          if (dm != null) {
            return {
              year: this.twoToFourDigitYear(y),
              month: dm.month,
              day: dm.day
            };
          }
        }

        return null;
      }

      mapIntegersToDayMonth(integers) {
        const temp = [integers, integers.slice().reverse()];

        for (let i = 0; i < temp.length; i += 1) {
          const data = temp[i];
          const day = data[0];
          const month = data[1];

          if (day >= 1 && day <= 31 && month >= 1 && month <= 12) {
            return {
              day,
              month
            };
          }
        }

        return null;
      }

      twoToFourDigitYear(year) {
        if (year > 99) {
          return year;
        }

        if (year > 50) {
          // 87 -> 1987
          return year + 1900;
        } // 15 -> 2015


        return year + 2000;
      }

    }

    /**
     * This code is from https://github.com/ka-weihe/fastest-levenshtein
     * It was copied into this repo because it doesn't have an esm build which results in error for esm only project
     * TODO if sometimes in the future it will get a esm build we can remove this file and use the original again
     * https://github.com/ka-weihe/fastest-levenshtein/pull/18
     */
    const peq = new Uint32Array(0x10000);

    const myers_32 = (a, b) => {
      const n = a.length;
      const m = b.length;
      const lst = 1 << n - 1;
      let pv = -1;
      let mv = 0;
      let sc = n;
      let i = n;

      while (i--) {
        peq[a.charCodeAt(i)] |= 1 << i;
      }

      for (i = 0; i < m; i++) {
        let eq = peq[b.charCodeAt(i)];
        const xv = eq | mv;
        eq |= (eq & pv) + pv ^ pv;
        mv |= ~(eq | pv);
        pv &= eq;

        if (mv & lst) {
          sc++;
        }

        if (pv & lst) {
          sc--;
        }

        mv = mv << 1 | 1;
        pv = pv << 1 | ~(xv | mv);
        mv &= xv;
      }

      i = n;

      while (i--) {
        peq[a.charCodeAt(i)] = 0;
      }

      return sc;
    };

    const myers_x = (b, a) => {
      const n = a.length;
      const m = b.length;
      const mhc = [];
      const phc = [];
      const hsize = Math.ceil(n / 32);
      const vsize = Math.ceil(m / 32);

      for (let i = 0; i < hsize; i++) {
        phc[i] = -1;
        mhc[i] = 0;
      }

      let j = 0;

      for (; j < vsize - 1; j++) {
        let mv = 0;
        let pv = -1;
        const start = j * 32;
        const vlen = Math.min(32, m) + start;

        for (let k = start; k < vlen; k++) {
          peq[b.charCodeAt(k)] |= 1 << k;
        }

        for (let i = 0; i < n; i++) {
          const eq = peq[a.charCodeAt(i)];
          const pb = phc[i / 32 | 0] >>> i % 32 & 1;
          const mb = mhc[i / 32 | 0] >>> i % 32 & 1;
          const xv = eq | mv;
          const xh = ((eq | mb) & pv) + pv ^ pv | eq | mb;
          let ph = mv | ~(xh | pv);
          let mh = pv & xh;

          if (ph >>> 31 ^ pb) {
            phc[i / 32 | 0] ^= 1 << i % 32;
          }

          if (mh >>> 31 ^ mb) {
            mhc[i / 32 | 0] ^= 1 << i % 32;
          }

          ph = ph << 1 | pb;
          mh = mh << 1 | mb;
          pv = mh | ~(xv | ph);
          mv = ph & xv;
        }

        for (let k = start; k < vlen; k++) {
          peq[b.charCodeAt(k)] = 0;
        }
      }

      let mv = 0;
      let pv = -1;
      const start = j * 32;
      const vlen = Math.min(32, m - start) + start;

      for (let k = start; k < vlen; k++) {
        peq[b.charCodeAt(k)] |= 1 << k;
      }

      let score = m;

      for (let i = 0; i < n; i++) {
        const eq = peq[a.charCodeAt(i)];
        const pb = phc[i / 32 | 0] >>> i % 32 & 1;
        const mb = mhc[i / 32 | 0] >>> i % 32 & 1;
        const xv = eq | mv;
        const xh = ((eq | mb) & pv) + pv ^ pv | eq | mb;
        let ph = mv | ~(xh | pv);
        let mh = pv & xh;
        score += ph >>> m % 32 - 1 & 1;
        score -= mh >>> m % 32 - 1 & 1;

        if (ph >>> 31 ^ pb) {
          phc[i / 32 | 0] ^= 1 << i % 32;
        }

        if (mh >>> 31 ^ mb) {
          mhc[i / 32 | 0] ^= 1 << i % 32;
        }

        ph = ph << 1 | pb;
        mh = mh << 1 | mb;
        pv = mh | ~(xv | ph);
        mv = ph & xv;
      }

      for (let k = start; k < vlen; k++) {
        peq[b.charCodeAt(k)] = 0;
      }

      return score;
    };

    const distance = (a, b) => {
      if (a.length < b.length) {
        const tmp = b;
        b = a;
        a = tmp;
      }

      if (b.length === 0) {
        return a.length;
      }

      if (a.length <= 32) {
        return myers_32(a, b);
      }

      return myers_x(a, b);
    };

    const getUsedThreshold = (password, entry, threshold) => {
      const isPasswordToShort = password.length <= entry.length;
      const isThresholdLongerThanPassword = password.length <= threshold;
      const shouldUsePasswordLength = isPasswordToShort || isThresholdLongerThanPassword; // if password is too small use the password length divided by 4 while the threshold needs to be at least 1

      return shouldUsePasswordLength ? Math.ceil(password.length / 4) : threshold;
    };

    const findLevenshteinDistance = (password, rankedDictionary, threshold) => {
      let foundDistance = 0;
      const found = Object.keys(rankedDictionary).find(entry => {
        const usedThreshold = getUsedThreshold(password, entry, threshold);
        const foundEntryDistance = distance(password, entry);
        const isInThreshold = foundEntryDistance <= usedThreshold;

        if (isInThreshold) {
          foundDistance = foundEntryDistance;
        }

        return isInThreshold;
      });

      if (found) {
        return {
          levenshteinDistance: foundDistance,
          levenshteinDistanceEntry: found
        };
      }

      return {};
    };

    var l33tTable = {
      a: ['4', '@'],
      b: ['8'],
      c: ['(', '{', '[', '<'],
      e: ['3'],
      g: ['6', '9'],
      i: ['1', '!', '|'],
      l: ['1', '|', '7'],
      o: ['0'],
      s: ['$', '5'],
      t: ['+', '7'],
      x: ['%'],
      z: ['2']
    };

    var translationKeys = {
      warnings: {
        straightRow: 'straightRow',
        keyPattern: 'keyPattern',
        simpleRepeat: 'simpleRepeat',
        extendedRepeat: 'extendedRepeat',
        sequences: 'sequences',
        recentYears: 'recentYears',
        dates: 'dates',
        topTen: 'topTen',
        topHundred: 'topHundred',
        common: 'common',
        similarToCommon: 'similarToCommon',
        wordByItself: 'wordByItself',
        namesByThemselves: 'namesByThemselves',
        commonNames: 'commonNames',
        userInputs: 'userInputs',
        pwned: 'pwned'
      },
      suggestions: {
        l33t: 'l33t',
        reverseWords: 'reverseWords',
        allUppercase: 'allUppercase',
        capitalization: 'capitalization',
        dates: 'dates',
        recentYears: 'recentYears',
        associatedYears: 'associatedYears',
        sequences: 'sequences',
        repeated: 'repeated',
        longerKeyboardPattern: 'longerKeyboardPattern',
        anotherWord: 'anotherWord',
        useWords: 'useWords',
        noNeed: 'noNeed',
        pwned: 'pwned'
      },
      timeEstimation: {
        ltSecond: 'ltSecond',
        second: 'second',
        seconds: 'seconds',
        minute: 'minute',
        minutes: 'minutes',
        hour: 'hour',
        hours: 'hours',
        day: 'day',
        days: 'days',
        month: 'month',
        months: 'months',
        year: 'year',
        years: 'years',
        centuries: 'centuries'
      }
    };

    class Options {
      constructor() {
        this.matchers = {};
        this.l33tTable = l33tTable;
        this.dictionary = {
          userInputs: []
        };
        this.rankedDictionaries = {};
        this.translations = translationKeys;
        this.graphs = {};
        this.availableGraphs = [];
        this.useLevenshteinDistance = false;
        this.levenshteinThreshold = 2;
        this.setRankedDictionaries();
      }

      setOptions(options = {}) {
        if (options.l33tTable) {
          this.l33tTable = options.l33tTable;
        }

        if (options.dictionary) {
          this.dictionary = options.dictionary;
          this.setRankedDictionaries();
        }

        if (options.translations) {
          this.setTranslations(options.translations);
        }

        if (options.graphs) {
          this.graphs = options.graphs;
        }

        if (options.useLevenshteinDistance !== undefined) {
          this.useLevenshteinDistance = options.useLevenshteinDistance;
        }

        if (options.levenshteinThreshold !== undefined) {
          this.levenshteinThreshold = options.levenshteinThreshold;
        }
      }

      setTranslations(translations) {
        if (this.checkCustomTranslations(translations)) {
          this.translations = translations;
        } else {
          throw new Error('Invalid translations object fallback to keys');
        }
      }

      checkCustomTranslations(translations) {
        let valid = true;
        Object.keys(translationKeys).forEach(type => {
          if (type in translations) {
            const translationType = type;
            Object.keys(translationKeys[translationType]).forEach(key => {
              if (!(key in translations[translationType])) {
                valid = false;
              }
            });
          } else {
            valid = false;
          }
        });
        return valid;
      }

      setRankedDictionaries() {
        const rankedDictionaries = {};
        Object.keys(this.dictionary).forEach(name => {
          rankedDictionaries[name] = this.getRankedDictionary(name);
        });
        this.rankedDictionaries = rankedDictionaries;
      }

      getRankedDictionary(name) {
        const list = this.dictionary[name];

        if (name === 'userInputs') {
          const sanitizedInputs = [];
          list.forEach(input => {
            const inputType = typeof input;

            if (inputType === 'string' || inputType === 'number' || inputType === 'boolean') {
              sanitizedInputs.push(input.toString().toLowerCase());
            }
          });
          return buildRankedDictionary(sanitizedInputs);
        }

        return buildRankedDictionary(list);
      }

      extendUserInputsDictionary(dictionary) {
        if (this.dictionary.userInputs) {
          this.dictionary.userInputs = [...this.dictionary.userInputs, ...dictionary];
        } else {
          this.dictionary.userInputs = dictionary;
        }

        this.rankedDictionaries.userInputs = this.getRankedDictionary('userInputs');
      }

      addMatcher(name, matcher) {
        if (this.matchers[name]) {
          console.info(`Matcher ${name} already exists`);
        } else {
          this.matchers[name] = matcher;
        }
      }

    }
    const zxcvbnOptions = new Options();

    /*
     * -------------------------------------------------------------------------------
     *  Dictionary reverse matching --------------------------------------------------
     * -------------------------------------------------------------------------------
     */
    class MatchL33t$1 {
      constructor(defaultMatch) {
        this.defaultMatch = defaultMatch;
      }

      match({
        password
      }) {
        const passwordReversed = password.split('').reverse().join('');
        return this.defaultMatch({
          password: passwordReversed
        }).map(match => ({ ...match,
          token: match.token.split('').reverse().join(''),
          reversed: true,
          // map coordinates back to original string
          i: password.length - 1 - match.j,
          j: password.length - 1 - match.i
        }));
      }

    }

    /*
     * -------------------------------------------------------------------------------
     *  Dictionary l33t matching -----------------------------------------------------
     * -------------------------------------------------------------------------------
     */

    class MatchL33t {
      constructor(defaultMatch) {
        this.defaultMatch = defaultMatch;
      }

      match({
        password
      }) {
        const matches = [];
        const enumeratedSubs = this.enumerateL33tSubs(this.relevantL33tSubtable(password, zxcvbnOptions.l33tTable));

        for (let i = 0; i < enumeratedSubs.length; i += 1) {
          const sub = enumeratedSubs[i]; // corner case: password has no relevant subs.

          if (empty(sub)) {
            break;
          }

          const subbedPassword = translate(password, sub);
          const matchedDictionary = this.defaultMatch({
            password: subbedPassword
          });
          matchedDictionary.forEach(match => {
            const token = password.slice(match.i, +match.j + 1 || 9e9); // only return the matches that contain an actual substitution

            if (token.toLowerCase() !== match.matchedWord) {
              // subset of mappings in sub that are in use for this match
              const matchSub = {};
              Object.keys(sub).forEach(subbedChr => {
                const chr = sub[subbedChr];

                if (token.indexOf(subbedChr) !== -1) {
                  matchSub[subbedChr] = chr;
                }
              });
              const subDisplay = Object.keys(matchSub).map(k => `${k} -> ${matchSub[k]}`).join(', ');
              matches.push({ ...match,
                l33t: true,
                token,
                sub: matchSub,
                subDisplay
              });
            }
          });
        } // filter single-character l33t matches to reduce noise.
        // otherwise '1' matches 'i', '4' matches 'a', both very common English words
        // with low dictionary rank.


        return matches.filter(match => match.token.length > 1);
      } // makes a pruned copy of l33t_table that only includes password's possible substitutions


      relevantL33tSubtable(password, table) {
        const passwordChars = {};
        const subTable = {};
        password.split('').forEach(char => {
          passwordChars[char] = true;
        });
        Object.keys(table).forEach(letter => {
          const subs = table[letter];
          const relevantSubs = subs.filter(sub => sub in passwordChars);

          if (relevantSubs.length > 0) {
            subTable[letter] = relevantSubs;
          }
        });
        return subTable;
      } // returns the list of possible 1337 replacement dictionaries for a given password


      enumerateL33tSubs(table) {
        const tableKeys = Object.keys(table);
        const subs = this.getSubs(tableKeys, [[]], table); // convert from assoc lists to dicts

        return subs.map(sub => {
          const subDict = {};
          sub.forEach(([l33tChr, chr]) => {
            subDict[l33tChr] = chr;
          });
          return subDict;
        });
      }

      getSubs(keys, subs, table) {
        if (!keys.length) {
          return subs;
        }

        const firstKey = keys[0];
        const restKeys = keys.slice(1);
        const nextSubs = [];
        table[firstKey].forEach(l33tChr => {
          subs.forEach(sub => {
            let dupL33tIndex = -1;

            for (let i = 0; i < sub.length; i += 1) {
              if (sub[i][0] === l33tChr) {
                dupL33tIndex = i;
                break;
              }
            }

            if (dupL33tIndex === -1) {
              const subExtension = sub.concat([[l33tChr, firstKey]]);
              nextSubs.push(subExtension);
            } else {
              const subAlternative = sub.slice(0);
              subAlternative.splice(dupL33tIndex, 1);
              subAlternative.push([l33tChr, firstKey]);
              nextSubs.push(sub);
              nextSubs.push(subAlternative);
            }
          });
        });
        const newSubs = this.dedup(nextSubs);

        if (restKeys.length) {
          return this.getSubs(restKeys, newSubs, table);
        }

        return newSubs;
      }

      dedup(subs) {
        const deduped = [];
        const members = {};
        subs.forEach(sub => {
          const assoc = sub.map((k, index) => [k, index]);
          assoc.sort();
          const label = assoc.map(([k, v]) => `${k},${v}`).join('-');

          if (!(label in members)) {
            members[label] = true;
            deduped.push(sub);
          }
        });
        return deduped;
      }

    }

    class MatchDictionary {
      constructor() {
        this.l33t = new MatchL33t(this.defaultMatch);
        this.reverse = new MatchL33t$1(this.defaultMatch);
      }

      match({
        password
      }) {
        const matches = [...this.defaultMatch({
          password
        }), ...this.reverse.match({
          password
        }), ...this.l33t.match({
          password
        })];
        return sorted(matches);
      }

      defaultMatch({
        password
      }) {
        const matches = [];
        const passwordLength = password.length;
        const passwordLower = password.toLowerCase(); // eslint-disable-next-line complexity

        Object.keys(zxcvbnOptions.rankedDictionaries).forEach(dictionaryName => {
          const rankedDict = zxcvbnOptions.rankedDictionaries[dictionaryName];

          for (let i = 0; i < passwordLength; i += 1) {
            for (let j = i; j < passwordLength; j += 1) {
              const usedPassword = passwordLower.slice(i, +j + 1 || 9e9);
              const isInDictionary = (usedPassword in rankedDict);
              let foundLevenshteinDistance = {}; // only use levenshtein distance on full password to minimize the performance drop
              // and because otherwise there would be to many false positives

              const isFullPassword = i === 0 && j === passwordLength - 1;

              if (zxcvbnOptions.useLevenshteinDistance && isFullPassword && !isInDictionary) {
                foundLevenshteinDistance = findLevenshteinDistance(usedPassword, rankedDict, zxcvbnOptions.levenshteinThreshold);
              }

              const isLevenshteinMatch = Object.keys(foundLevenshteinDistance).length !== 0;

              if (isInDictionary || isLevenshteinMatch) {
                const usedRankPassword = isLevenshteinMatch ? foundLevenshteinDistance.levenshteinDistanceEntry : usedPassword;
                const rank = rankedDict[usedRankPassword];
                matches.push({
                  pattern: 'dictionary',
                  i,
                  j,
                  token: password.slice(i, +j + 1 || 9e9),
                  matchedWord: usedPassword,
                  rank,
                  dictionaryName: dictionaryName,
                  reversed: false,
                  l33t: false,
                  ...foundLevenshteinDistance
                });
              }
            }
          }
        });
        return matches;
      }

    }

    /*
     * -------------------------------------------------------------------------------
     *  regex matching ---------------------------------------------------------------
     * -------------------------------------------------------------------------------
     */

    class MatchRegex {
      match({
        password,
        regexes = REGEXEN
      }) {
        const matches = [];
        Object.keys(regexes).forEach(name => {
          const regex = regexes[name];
          regex.lastIndex = 0; // keeps regexMatch stateless

          const regexMatch = regex.exec(password);

          if (regexMatch) {
            const token = regexMatch[0];
            matches.push({
              pattern: 'regex',
              token,
              i: regexMatch.index,
              j: regexMatch.index + regexMatch[0].length - 1,
              regexName: name,
              regexMatch
            });
          }
        });
        return sorted(matches);
      }

    }

    var utils = {
      // binomial coefficients
      // src: http://blog.plover.com/math/choose.html
      nCk(n, k) {
        let count = n;

        if (k > count) {
          return 0;
        }

        if (k === 0) {
          return 1;
        }

        let coEff = 1;

        for (let i = 1; i <= k; i += 1) {
          coEff *= count;
          coEff /= i;
          count -= 1;
        }

        return coEff;
      },

      log10(n) {
        return Math.log(n) / Math.log(10); // IE doesn't support Math.log10 :(
      },

      log2(n) {
        return Math.log(n) / Math.log(2);
      },

      factorial(num) {
        let rval = 1;

        for (let i = 2; i <= num; i += 1) rval *= i;

        return rval;
      }

    };

    var bruteforceMatcher$1 = (({
      token
    }) => {
      let guesses = BRUTEFORCE_CARDINALITY ** token.length;

      if (guesses === Number.POSITIVE_INFINITY) {
        guesses = Number.MAX_VALUE;
      }

      let minGuesses; // small detail: make bruteforce matches at minimum one guess bigger than smallest allowed
      // submatch guesses, such that non-bruteforce submatches over the same [i..j] take precedence.

      if (token.length === 1) {
        minGuesses = MIN_SUBMATCH_GUESSES_SINGLE_CHAR + 1;
      } else {
        minGuesses = MIN_SUBMATCH_GUESSES_MULTI_CHAR + 1;
      }

      return Math.max(guesses, minGuesses);
    });

    var dateMatcher$1 = (({
      year,
      separator
    }) => {
      // base guesses: (year distance from REFERENCE_YEAR) * num_days * num_years
      const yearSpace = Math.max(Math.abs(year - REFERENCE_YEAR), MIN_YEAR_SPACE);
      let guesses = yearSpace * 365; // add factor of 4 for separator selection (one of ~4 choices)

      if (separator) {
        guesses *= 4;
      }

      return guesses;
    });

    const getVariations = cleanedWord => {
      const wordArray = cleanedWord.split('');
      const upperCaseCount = wordArray.filter(char => char.match(ONE_UPPER)).length;
      const lowerCaseCount = wordArray.filter(char => char.match(ONE_LOWER)).length;
      let variations = 0;
      const variationLength = Math.min(upperCaseCount, lowerCaseCount);

      for (let i = 1; i <= variationLength; i += 1) {
        variations += utils.nCk(upperCaseCount + lowerCaseCount, i);
      }

      return variations;
    };

    var uppercaseVariant = (word => {
      // clean words of non alpha characters to remove the reward effekt to capitalize the first letter https://github.com/dropbox/zxcvbn/issues/232
      const cleanedWord = word.replace(ALPHA_INVERTED, '');

      if (cleanedWord.match(ALL_LOWER_INVERTED) || cleanedWord.toLowerCase() === cleanedWord) {
        return 1;
      } // a capitalized word is the most common capitalization scheme,
      // so it only doubles the search space (uncapitalized + capitalized).
      // all caps and end-capitalized are common enough too, underestimate as 2x factor to be safe.


      const commonCases = [START_UPPER, END_UPPER, ALL_UPPER_INVERTED];
      const commonCasesLength = commonCases.length;

      for (let i = 0; i < commonCasesLength; i += 1) {
        const regex = commonCases[i];

        if (cleanedWord.match(regex)) {
          return 2;
        }
      } // otherwise calculate the number of ways to capitalize U+L uppercase+lowercase letters
      // with U uppercase letters or less. or, if there's more uppercase than lower (for eg. PASSwORD),
      // the number of ways to lowercase U+L letters with L lowercase letters or less.


      return getVariations(cleanedWord);
    });

    const getCounts = ({
      subs,
      subbed,
      token
    }) => {
      const unsubbed = subs[subbed]; // lower-case match.token before calculating: capitalization shouldn't affect l33t calc.

      const chrs = token.toLowerCase().split(''); // num of subbed chars

      const subbedCount = chrs.filter(char => char === subbed).length; // num of unsubbed chars

      const unsubbedCount = chrs.filter(char => char === unsubbed).length;
      return {
        subbedCount,
        unsubbedCount
      };
    };

    var l33tVariant = (({
      l33t,
      sub,
      token
    }) => {
      if (!l33t) {
        return 1;
      }

      let variations = 1;
      const subs = sub;
      Object.keys(subs).forEach(subbed => {
        const {
          subbedCount,
          unsubbedCount
        } = getCounts({
          subs,
          subbed,
          token
        });

        if (subbedCount === 0 || unsubbedCount === 0) {
          // for this sub, password is either fully subbed (444) or fully unsubbed (aaa)
          // treat that as doubling the space (attacker needs to try fully subbed chars in addition to
          // unsubbed.)
          variations *= 2;
        } else {
          // this case is similar to capitalization:
          // with aa44a, U = 3, S = 2, attacker needs to try unsubbed + one sub + two subs
          const p = Math.min(unsubbedCount, subbedCount);
          let possibilities = 0;

          for (let i = 1; i <= p; i += 1) {
            possibilities += utils.nCk(unsubbedCount + subbedCount, i);
          }

          variations *= possibilities;
        }
      });
      return variations;
    });

    var dictionaryMatcher$1 = (({
      rank,
      reversed,
      l33t,
      sub,
      token
    }) => {
      const baseGuesses = rank; // keep these as properties for display purposes

      const uppercaseVariations = uppercaseVariant(token);
      const l33tVariations = l33tVariant({
        l33t,
        sub,
        token
      });
      const reversedVariations = reversed && 2 || 1;
      const calculation = baseGuesses * uppercaseVariations * l33tVariations * reversedVariations;
      return {
        baseGuesses,
        uppercaseVariations,
        l33tVariations,
        calculation
      };
    });

    var regexMatcher$1 = (({
      regexName,
      regexMatch,
      token
    }) => {
      const charClassBases = {
        alphaLower: 26,
        alphaUpper: 26,
        alpha: 52,
        alphanumeric: 62,
        digits: 10,
        symbols: 33
      };

      if (regexName in charClassBases) {
        return charClassBases[regexName] ** token.length;
      } // TODO add more regex types for example special dates like 09.11
      // eslint-disable-next-line default-case


      switch (regexName) {
        case 'recentYear':
          // conservative estimate of year space: num years from REFERENCE_YEAR.
          // if year is close to REFERENCE_YEAR, estimate a year space of MIN_YEAR_SPACE.
          return Math.max(Math.abs(parseInt(regexMatch[0], 10) - REFERENCE_YEAR), MIN_YEAR_SPACE);
      }

      return 0;
    });

    var repeatMatcher$1 = (({
      baseGuesses,
      repeatCount
    }) => baseGuesses * repeatCount);

    var sequenceMatcher$1 = (({
      token,
      ascending
    }) => {
      const firstChr = token.charAt(0);
      let baseGuesses = 0;
      const startingPoints = ['a', 'A', 'z', 'Z', '0', '1', '9']; // lower guesses for obvious starting points

      if (startingPoints.includes(firstChr)) {
        baseGuesses = 4;
      } else if (firstChr.match(/\d/)) {
        baseGuesses = 10; // digits
      } else {
        // could give a higher base for uppercase,
        // assigning 26 to both upper and lower sequences is more conservative.
        baseGuesses = 26;
      } // need to try a descending sequence in addition to every ascending sequence ->
      // 2x guesses


      if (!ascending) {
        baseGuesses *= 2;
      }

      return baseGuesses * token.length;
    });

    const calcAverageDegree = graph => {
      let average = 0;
      Object.keys(graph).forEach(key => {
        const neighbors = graph[key];
        average += neighbors.filter(entry => !!entry).length;
      });
      average /= Object.entries(graph).length;
      return average;
    };

    const estimatePossiblePatterns = ({
      token,
      graph,
      turns
    }) => {
      const startingPosition = Object.keys(zxcvbnOptions.graphs[graph]).length;
      const averageDegree = calcAverageDegree(zxcvbnOptions.graphs[graph]);
      let guesses = 0;
      const tokenLength = token.length; // # estimate the number of possible patterns w/ tokenLength or less with turns or less.

      for (let i = 2; i <= tokenLength; i += 1) {
        const possibleTurns = Math.min(turns, i - 1);

        for (let j = 1; j <= possibleTurns; j += 1) {
          guesses += utils.nCk(i - 1, j - 1) * startingPosition * averageDegree ** j;
        }
      }

      return guesses;
    };

    var spatialMatcher$1 = (({
      graph,
      token,
      shiftedCount,
      turns
    }) => {
      let guesses = estimatePossiblePatterns({
        token,
        graph,
        turns
      }); // add extra guesses for shifted keys. (% instead of 5, A instead of a.)
      // math is similar to extra guesses of l33t substitutions in dictionary matches.

      if (shiftedCount) {
        const unShiftedCount = token.length - shiftedCount;

        if (shiftedCount === 0 || unShiftedCount === 0) {
          guesses *= 2;
        } else {
          let shiftedVariations = 0;

          for (let i = 1; i <= Math.min(shiftedCount, unShiftedCount); i += 1) {
            shiftedVariations += utils.nCk(shiftedCount + unShiftedCount, i);
          }

          guesses *= shiftedVariations;
        }
      }

      return Math.round(guesses);
    });

    const getMinGuesses = (match, password) => {
      let minGuesses = 1;

      if (match.token.length < password.length) {
        if (match.token.length === 1) {
          minGuesses = MIN_SUBMATCH_GUESSES_SINGLE_CHAR;
        } else {
          minGuesses = MIN_SUBMATCH_GUESSES_MULTI_CHAR;
        }
      }

      return minGuesses;
    };

    const matchers = {
      bruteforce: bruteforceMatcher$1,
      date: dateMatcher$1,
      dictionary: dictionaryMatcher$1,
      regex: regexMatcher$1,
      repeat: repeatMatcher$1,
      sequence: sequenceMatcher$1,
      spatial: spatialMatcher$1
    };

    const getScoring = (name, match) => {
      if (matchers[name]) {
        return matchers[name](match);
      }

      if (zxcvbnOptions.matchers[name] && 'scoring' in zxcvbnOptions.matchers[name]) {
        return zxcvbnOptions.matchers[name].scoring(match);
      }

      return 0;
    }; // ------------------------------------------------------------------------------
    // guess estimation -- one function per match pattern ---------------------------
    // ------------------------------------------------------------------------------


    var estimateGuesses = ((match, password) => {
      const extraData = {}; // a match's guess estimate doesn't change. cache it.

      if ('guesses' in match && match.guesses != null) {
        return match;
      }

      const minGuesses = getMinGuesses(match, password);
      const estimationResult = getScoring(match.pattern, match);
      let guesses = 0;

      if (typeof estimationResult === 'number') {
        guesses = estimationResult;
      } else if (match.pattern === 'dictionary') {
        guesses = estimationResult.calculation;
        extraData.baseGuesses = estimationResult.baseGuesses;
        extraData.uppercaseVariations = estimationResult.uppercaseVariations;
        extraData.l33tVariations = estimationResult.l33tVariations;
      }

      const matchGuesses = Math.max(guesses, minGuesses);
      return { ...match,
        ...extraData,
        guesses: matchGuesses,
        guessesLog10: utils.log10(matchGuesses)
      };
    });

    const scoringHelper = {
      password: '',
      optimal: {},
      excludeAdditive: false,

      fillArray(size, valueType) {
        const result = [];

        for (let i = 0; i < size; i += 1) {
          let value = [];

          if (valueType === 'object') {
            value = {};
          }

          result.push(value);
        }

        return result;
      },

      // helper: make bruteforce match objects spanning i to j, inclusive.
      makeBruteforceMatch(i, j) {
        return {
          pattern: 'bruteforce',
          token: this.password.slice(i, +j + 1 || 9e9),
          i,
          j
        };
      },

      // helper: considers whether a length-sequenceLength
      // sequence ending at match m is better (fewer guesses)
      // than previously encountered sequences, updating state if so.
      update(match, sequenceLength) {
        const k = match.j;
        const estimatedMatch = estimateGuesses(match, this.password);
        let pi = estimatedMatch.guesses;

        if (sequenceLength > 1) {
          // we're considering a length-sequenceLength sequence ending with match m:
          // obtain the product term in the minimization function by multiplying m's guesses
          // by the product of the length-(sequenceLength-1)
          // sequence ending just before m, at m.i - 1.
          pi *= this.optimal.pi[estimatedMatch.i - 1][sequenceLength - 1];
        } // calculate the minimization func


        let g = utils.factorial(sequenceLength) * pi;

        if (!this.excludeAdditive) {
          g += MIN_GUESSES_BEFORE_GROWING_SEQUENCE ** (sequenceLength - 1);
        } // update state if new best.
        // first see if any competing sequences covering this prefix,
        // with sequenceLength or fewer matches,
        // fare better than this sequence. if so, skip it and return.


        let shouldSkip = false;
        Object.keys(this.optimal.g[k]).forEach(competingPatternLength => {
          const competingMetricMatch = this.optimal.g[k][competingPatternLength];

          if (parseInt(competingPatternLength, 10) <= sequenceLength) {
            if (competingMetricMatch <= g) {
              shouldSkip = true;
            }
          }
        });

        if (!shouldSkip) {
          // this sequence might be part of the final optimal sequence.
          this.optimal.g[k][sequenceLength] = g;
          this.optimal.m[k][sequenceLength] = estimatedMatch;
          this.optimal.pi[k][sequenceLength] = pi;
        }
      },

      // helper: evaluate bruteforce matches ending at passwordCharIndex.
      bruteforceUpdate(passwordCharIndex) {
        // see if a single bruteforce match spanning the passwordCharIndex-prefix is optimal.
        let match = this.makeBruteforceMatch(0, passwordCharIndex);
        this.update(match, 1);

        for (let i = 1; i <= passwordCharIndex; i += 1) {
          // generate passwordCharIndex bruteforce matches, spanning from (i=1, j=passwordCharIndex) up to (i=passwordCharIndex, j=passwordCharIndex).
          // see if adding these new matches to any of the sequences in optimal[i-1]
          // leads to new bests.
          match = this.makeBruteforceMatch(i, passwordCharIndex);
          const tmp = this.optimal.m[i - 1]; // eslint-disable-next-line no-loop-func

          Object.keys(tmp).forEach(sequenceLength => {
            const lastMatch = tmp[sequenceLength]; // corner: an optimal sequence will never have two adjacent bruteforce matches.
            // it is strictly better to have a single bruteforce match spanning the same region:
            // same contribution to the guess product with a lower length.
            // --> safe to skip those cases.

            if (lastMatch.pattern !== 'bruteforce') {
              // try adding m to this length-sequenceLength sequence.
              this.update(match, parseInt(sequenceLength, 10) + 1);
            }
          });
        }
      },

      // helper: step backwards through optimal.m starting at the end,
      // constructing the final optimal match sequence.
      unwind(passwordLength) {
        const optimalMatchSequence = [];
        let k = passwordLength - 1; // find the final best sequence length and score

        let sequenceLength = 0; // eslint-disable-next-line no-loss-of-precision

        let g = 2e308;
        const temp = this.optimal.g[k]; // safety check for empty passwords

        if (temp) {
          Object.keys(temp).forEach(candidateSequenceLength => {
            const candidateMetricMatch = temp[candidateSequenceLength];

            if (candidateMetricMatch < g) {
              sequenceLength = parseInt(candidateSequenceLength, 10);
              g = candidateMetricMatch;
            }
          });
        }

        while (k >= 0) {
          const match = this.optimal.m[k][sequenceLength];
          optimalMatchSequence.unshift(match);
          k = match.i - 1;
          sequenceLength -= 1;
        }

        return optimalMatchSequence;
      }

    };
    var scoring = {
      // ------------------------------------------------------------------------------
      // search --- most guessable match sequence -------------------------------------
      // ------------------------------------------------------------------------------
      //
      // takes a sequence of overlapping matches, returns the non-overlapping sequence with
      // minimum guesses. the following is a O(l_max * (n + m)) dynamic programming algorithm
      // for a length-n password with m candidate matches. l_max is the maximum optimal
      // sequence length spanning each prefix of the password. In practice it rarely exceeds 5 and the
      // search terminates rapidly.
      //
      // the optimal "minimum guesses" sequence is here defined to be the sequence that
      // minimizes the following function:
      //
      //    g = sequenceLength! * Product(m.guesses for m in sequence) + D^(sequenceLength - 1)
      //
      // where sequenceLength is the length of the sequence.
      //
      // the factorial term is the number of ways to order sequenceLength patterns.
      //
      // the D^(sequenceLength-1) term is another length penalty, roughly capturing the idea that an
      // attacker will try lower-length sequences first before trying length-sequenceLength sequences.
      //
      // for example, consider a sequence that is date-repeat-dictionary.
      //  - an attacker would need to try other date-repeat-dictionary combinations,
      //    hence the product term.
      //  - an attacker would need to try repeat-date-dictionary, dictionary-repeat-date,
      //    ..., hence the factorial term.
      //  - an attacker would also likely try length-1 (dictionary) and length-2 (dictionary-date)
      //    sequences before length-3. assuming at minimum D guesses per pattern type,
      //    D^(sequenceLength-1) approximates Sum(D^i for i in [1..sequenceLength-1]
      //
      // ------------------------------------------------------------------------------
      mostGuessableMatchSequence(password, matches, excludeAdditive = false) {
        scoringHelper.password = password;
        scoringHelper.excludeAdditive = excludeAdditive;
        const passwordLength = password.length; // partition matches into sublists according to ending index j

        let matchesByCoordinateJ = scoringHelper.fillArray(passwordLength, 'array');
        matches.forEach(match => {
          matchesByCoordinateJ[match.j].push(match);
        }); // small detail: for deterministic output, sort each sublist by i.

        matchesByCoordinateJ = matchesByCoordinateJ.map(match => match.sort((m1, m2) => m1.i - m2.i));
        scoringHelper.optimal = {
          // optimal.m[k][sequenceLength] holds final match in the best length-sequenceLength
          // match sequence covering the
          // password prefix up to k, inclusive.
          // if there is no length-sequenceLength sequence that scores better (fewer guesses) than
          // a shorter match sequence spanning the same prefix,
          // optimal.m[k][sequenceLength] is undefined.
          m: scoringHelper.fillArray(passwordLength, 'object'),
          // same structure as optimal.m -- holds the product term Prod(m.guesses for m in sequence).
          // optimal.pi allows for fast (non-looping) updates to the minimization function.
          pi: scoringHelper.fillArray(passwordLength, 'object'),
          // same structure as optimal.m -- holds the overall metric.
          g: scoringHelper.fillArray(passwordLength, 'object')
        };

        for (let k = 0; k < passwordLength; k += 1) {
          matchesByCoordinateJ[k].forEach(match => {
            if (match.i > 0) {
              Object.keys(scoringHelper.optimal.m[match.i - 1]).forEach(sequenceLength => {
                scoringHelper.update(match, parseInt(sequenceLength, 10) + 1);
              });
            } else {
              scoringHelper.update(match, 1);
            }
          });
          scoringHelper.bruteforceUpdate(k);
        }

        const optimalMatchSequence = scoringHelper.unwind(passwordLength);
        const optimalSequenceLength = optimalMatchSequence.length;
        const guesses = this.getGuesses(password, optimalSequenceLength);
        return {
          password,
          guesses,
          guessesLog10: utils.log10(guesses),
          sequence: optimalMatchSequence
        };
      },

      getGuesses(password, optimalSequenceLength) {
        const passwordLength = password.length;
        let guesses = 0;

        if (password.length === 0) {
          guesses = 1;
        } else {
          guesses = scoringHelper.optimal.g[passwordLength - 1][optimalSequenceLength];
        }

        return guesses;
      }

    };

    /*
     *-------------------------------------------------------------------------------
     * repeats (aaa, abcabcabc) ------------------------------
     *-------------------------------------------------------------------------------
     */

    class MatchRepeat {
      // eslint-disable-next-line max-statements
      match({
        password,
        omniMatch
      }) {
        const matches = [];
        let lastIndex = 0;

        while (lastIndex < password.length) {
          const greedyMatch = this.getGreedyMatch(password, lastIndex);
          const lazyMatch = this.getLazyMatch(password, lastIndex);

          if (greedyMatch == null) {
            break;
          }

          const {
            match,
            baseToken
          } = this.setMatchToken(greedyMatch, lazyMatch);

          if (match) {
            const j = match.index + match[0].length - 1;
            const baseGuesses = this.getBaseGuesses(baseToken, omniMatch);
            matches.push(this.normalizeMatch(baseToken, j, match, baseGuesses));
            lastIndex = j + 1;
          }
        }

        const hasPromises = matches.some(match => {
          return match instanceof Promise;
        });

        if (hasPromises) {
          return Promise.all(matches);
        }

        return matches;
      } // eslint-disable-next-line max-params


      normalizeMatch(baseToken, j, match, baseGuesses) {
        const baseMatch = {
          pattern: 'repeat',
          i: match.index,
          j,
          token: match[0],
          baseToken,
          baseGuesses: 0,
          repeatCount: match[0].length / baseToken.length
        };

        if (baseGuesses instanceof Promise) {
          return baseGuesses.then(resolvedBaseGuesses => {
            return { ...baseMatch,
              baseGuesses: resolvedBaseGuesses
            };
          });
        }

        return { ...baseMatch,
          baseGuesses
        };
      }

      getGreedyMatch(password, lastIndex) {
        const greedy = /(.+)\1+/g;
        greedy.lastIndex = lastIndex;
        return greedy.exec(password);
      }

      getLazyMatch(password, lastIndex) {
        const lazy = /(.+?)\1+/g;
        lazy.lastIndex = lastIndex;
        return lazy.exec(password);
      }

      setMatchToken(greedyMatch, lazyMatch) {
        const lazyAnchored = /^(.+?)\1+$/;
        let match;
        let baseToken = '';

        if (lazyMatch && greedyMatch[0].length > lazyMatch[0].length) {
          // greedy beats lazy for 'aabaab'
          // greedy: [aabaab, aab]
          // lazy:   [aa,     a]
          match = greedyMatch; // greedy's repeated string might itself be repeated, eg.
          // aabaab in aabaabaabaab.
          // run an anchored lazy match on greedy's repeated string
          // to find the shortest repeated string

          const temp = lazyAnchored.exec(match[0]);

          if (temp) {
            baseToken = temp[1];
          }
        } else {
          // lazy beats greedy for 'aaaaa'
          // greedy: [aaaa,  aa]
          // lazy:   [aaaaa, a]
          match = lazyMatch;

          if (match) {
            baseToken = match[1];
          }
        }

        return {
          match,
          baseToken
        };
      }

      getBaseGuesses(baseToken, omniMatch) {
        const matches = omniMatch.match(baseToken);

        if (matches instanceof Promise) {
          return matches.then(resolvedMatches => {
            const baseAnalysis = scoring.mostGuessableMatchSequence(baseToken, resolvedMatches);
            return baseAnalysis.guesses;
          });
        }

        const baseAnalysis = scoring.mostGuessableMatchSequence(baseToken, matches);
        return baseAnalysis.guesses;
      }

    }

    /*
     *-------------------------------------------------------------------------------
     * sequences (abcdef) ------------------------------
     *-------------------------------------------------------------------------------
     */

    class MatchSequence {
      constructor() {
        this.MAX_DELTA = 5;
      } // eslint-disable-next-line max-statements


      match({
        password
      }) {
        /*
         * Identifies sequences by looking for repeated differences in unicode codepoint.
         * this allows skipping, such as 9753, and also matches some extended unicode sequences
         * such as Greek and Cyrillic alphabets.
         *
         * for example, consider the input 'abcdb975zy'
         *
         * password: a   b   c   d   b    9   7   5   z   y
         * index:    0   1   2   3   4    5   6   7   8   9
         * delta:      1   1   1  -2  -41  -2  -2  69   1
         *
         * expected result:
         * [(i, j, delta), ...] = [(0, 3, 1), (5, 7, -2), (8, 9, 1)]
         */
        const result = [];

        if (password.length === 1) {
          return [];
        }

        let i = 0;
        let lastDelta = null;
        const passwordLength = password.length;

        for (let k = 1; k < passwordLength; k += 1) {
          const delta = password.charCodeAt(k) - password.charCodeAt(k - 1);

          if (lastDelta == null) {
            lastDelta = delta;
          }

          if (delta !== lastDelta) {
            const j = k - 1;
            this.update({
              i,
              j,
              delta: lastDelta,
              password,
              result
            });
            i = j;
            lastDelta = delta;
          }
        }

        this.update({
          i,
          j: passwordLength - 1,
          delta: lastDelta,
          password,
          result
        });
        return result;
      }

      update({
        i,
        j,
        delta,
        password,
        result
      }) {
        if (j - i > 1 || Math.abs(delta) === 1) {
          const absoluteDelta = Math.abs(delta);

          if (absoluteDelta > 0 && absoluteDelta <= this.MAX_DELTA) {
            const token = password.slice(i, +j + 1 || 9e9);
            const {
              sequenceName,
              sequenceSpace
            } = this.getSequence(token);
            return result.push({
              pattern: 'sequence',
              i,
              j,
              token: password.slice(i, +j + 1 || 9e9),
              sequenceName,
              sequenceSpace,
              ascending: delta > 0
            });
          }
        }

        return null;
      }

      getSequence(token) {
        // TODO conservatively stick with roman alphabet size.
        //  (this could be improved)
        let sequenceName = 'unicode';
        let sequenceSpace = 26;

        if (ALL_LOWER.test(token)) {
          sequenceName = 'lower';
          sequenceSpace = 26;
        } else if (ALL_UPPER.test(token)) {
          sequenceName = 'upper';
          sequenceSpace = 26;
        } else if (ALL_DIGIT.test(token)) {
          sequenceName = 'digits';
          sequenceSpace = 10;
        }

        return {
          sequenceName,
          sequenceSpace
        };
      }

    }

    /*
     * ------------------------------------------------------------------------------
     * spatial match (qwerty/dvorak/keypad and so on) -----------------------------------------
     * ------------------------------------------------------------------------------
     */

    class MatchSpatial {
      constructor() {
        this.SHIFTED_RX = /[~!@#$%^&*()_+QWERTYUIOP{}|ASDFGHJKL:"ZXCVBNM<>?]/;
      }

      match({
        password
      }) {
        const matches = [];
        Object.keys(zxcvbnOptions.graphs).forEach(graphName => {
          const graph = zxcvbnOptions.graphs[graphName];
          extend(matches, this.helper(password, graph, graphName));
        });
        return sorted(matches);
      }

      checkIfShifted(graphName, password, index) {
        if (!graphName.includes('keypad') && // initial character is shifted
        this.SHIFTED_RX.test(password.charAt(index))) {
          return 1;
        }

        return 0;
      } // eslint-disable-next-line complexity, max-statements


      helper(password, graph, graphName) {
        let shiftedCount;
        const matches = [];
        let i = 0;
        const passwordLength = password.length;

        while (i < passwordLength - 1) {
          let j = i + 1;
          let lastDirection = 0;
          let turns = 0;
          shiftedCount = this.checkIfShifted(graphName, password, i); // eslint-disable-next-line no-constant-condition

          while (true) {
            const prevChar = password.charAt(j - 1);
            const adjacents = graph[prevChar] || [];
            let found = false;
            let foundDirection = -1;
            let curDirection = -1; // consider growing pattern by one character if j hasn't gone over the edge.

            if (j < passwordLength) {
              const curChar = password.charAt(j);
              const adjacentsLength = adjacents.length;

              for (let k = 0; k < adjacentsLength; k += 1) {
                const adjacent = adjacents[k];
                curDirection += 1; // eslint-disable-next-line max-depth

                if (adjacent) {
                  const adjacentIndex = adjacent.indexOf(curChar); // eslint-disable-next-line max-depth

                  if (adjacentIndex !== -1) {
                    found = true;
                    foundDirection = curDirection; // eslint-disable-next-line max-depth

                    if (adjacentIndex === 1) {
                      // # index 1 in the adjacency means the key is shifted,
                      // # 0 means unshifted: A vs a, % vs 5, etc.
                      // # for example, 'q' is adjacent to the entry '2@'.
                      // # @ is shifted w/ index 1, 2 is unshifted.
                      shiftedCount += 1;
                    } // eslint-disable-next-line max-depth


                    if (lastDirection !== foundDirection) {
                      // # adding a turn is correct even in the initial
                      // case when last_direction is null:
                      // # every spatial pattern starts with a turn.
                      turns += 1;
                      lastDirection = foundDirection;
                    }

                    break;
                  }
                }
              }
            } // if the current pattern continued, extend j and try to grow again


            if (found) {
              j += 1; // otherwise push the pattern discovered so far, if any...
            } else {
              // don't consider length 1 or 2 chains.
              if (j - i > 2) {
                matches.push({
                  pattern: 'spatial',
                  i,
                  j: j - 1,
                  token: password.slice(i, j),
                  graph: graphName,
                  turns,
                  shiftedCount
                });
              } // ...and then start a new search for the rest of the password.


              i = j;
              break;
            }
          }
        }

        return matches;
      }

    }

    class Matching {
      constructor() {
        this.matchers = {
          date: MatchDate,
          dictionary: MatchDictionary,
          regex: MatchRegex,
          // @ts-ignore => TODO resolve this type issue. This is because it is possible to be async
          repeat: MatchRepeat,
          sequence: MatchSequence,
          spatial: MatchSpatial
        };
      }

      match(password) {
        const matches = [];
        const promises = [];
        const matchers = [...Object.keys(this.matchers), ...Object.keys(zxcvbnOptions.matchers)];
        matchers.forEach(key => {
          if (!this.matchers[key] && !zxcvbnOptions.matchers[key]) {
            return;
          }

          const Matcher = this.matchers[key] ? this.matchers[key] : zxcvbnOptions.matchers[key].Matching;
          const usedMatcher = new Matcher();
          const result = usedMatcher.match({
            password,
            omniMatch: this
          });

          if (result instanceof Promise) {
            result.then(response => {
              extend(matches, response);
            });
            promises.push(result);
          } else {
            extend(matches, result);
          }
        });

        if (promises.length > 0) {
          return new Promise(resolve => {
            Promise.all(promises).then(() => {
              resolve(sorted(matches));
            });
          });
        }

        return sorted(matches);
      }

    }

    const SECOND = 1;
    const MINUTE = SECOND * 60;
    const HOUR = MINUTE * 60;
    const DAY = HOUR * 24;
    const MONTH = DAY * 31;
    const YEAR = MONTH * 12;
    const CENTURY = YEAR * 100;
    const times = {
      second: SECOND,
      minute: MINUTE,
      hour: HOUR,
      day: DAY,
      month: MONTH,
      year: YEAR,
      century: CENTURY
    };
    /*
     * -------------------------------------------------------------------------------
     *  Estimates time for an attacker ---------------------------------------------------------------
     * -------------------------------------------------------------------------------
     */

    class TimeEstimates {
      translate(displayStr, value) {
        let key = displayStr;

        if (value !== undefined && value !== 1) {
          key += 's';
        }

        const {
          timeEstimation
        } = zxcvbnOptions.translations;
        return timeEstimation[key].replace('{base}', `${value}`);
      }

      estimateAttackTimes(guesses) {
        const crackTimesSeconds = {
          onlineThrottling100PerHour: guesses / (100 / 3600),
          onlineNoThrottling10PerSecond: guesses / 10,
          offlineSlowHashing1e4PerSecond: guesses / 1e4,
          offlineFastHashing1e10PerSecond: guesses / 1e10
        };
        const crackTimesDisplay = {
          onlineThrottling100PerHour: '',
          onlineNoThrottling10PerSecond: '',
          offlineSlowHashing1e4PerSecond: '',
          offlineFastHashing1e10PerSecond: ''
        };
        Object.keys(crackTimesSeconds).forEach(scenario => {
          const seconds = crackTimesSeconds[scenario];
          crackTimesDisplay[scenario] = this.displayTime(seconds);
        });
        return {
          crackTimesSeconds,
          crackTimesDisplay,
          score: this.guessesToScore(guesses)
        };
      }

      guessesToScore(guesses) {
        const DELTA = 5;

        if (guesses < 1e3 + DELTA) {
          // risky password: "too guessable"
          return 0;
        }

        if (guesses < 1e6 + DELTA) {
          // modest protection from throttled online attacks: "very guessable"
          return 1;
        }

        if (guesses < 1e8 + DELTA) {
          // modest protection from unthrottled online attacks: "somewhat guessable"
          return 2;
        }

        if (guesses < 1e10 + DELTA) {
          // modest protection from offline attacks: "safely unguessable"
          // assuming a salted, slow hash function like bcrypt, scrypt, PBKDF2, argon, etc
          return 3;
        } // strong protection from offline attacks under same scenario: "very unguessable"


        return 4;
      }

      displayTime(seconds) {
        let displayStr = 'centuries';
        let base;
        const timeKeys = Object.keys(times);
        const foundIndex = timeKeys.findIndex(time => seconds < times[time]);

        if (foundIndex > -1) {
          displayStr = timeKeys[foundIndex - 1];

          if (foundIndex !== 0) {
            base = Math.round(seconds / times[displayStr]);
          } else {
            displayStr = 'ltSecond';
          }
        }

        return this.translate(displayStr, base);
      }

    }

    var bruteforceMatcher = (() => {
      return null;
    });

    var dateMatcher = (() => {
      return {
        warning: zxcvbnOptions.translations.warnings.dates,
        suggestions: [zxcvbnOptions.translations.suggestions.dates]
      };
    });

    const getDictionaryWarningPassword = (match, isSoleMatch) => {
      let warning = '';

      if (isSoleMatch && !match.l33t && !match.reversed) {
        if (match.rank <= 10) {
          warning = zxcvbnOptions.translations.warnings.topTen;
        } else if (match.rank <= 100) {
          warning = zxcvbnOptions.translations.warnings.topHundred;
        } else {
          warning = zxcvbnOptions.translations.warnings.common;
        }
      } else if (match.guessesLog10 <= 4) {
        warning = zxcvbnOptions.translations.warnings.similarToCommon;
      }

      return warning;
    };

    const getDictionaryWarningWikipedia = (match, isSoleMatch) => {
      let warning = '';

      if (isSoleMatch) {
        warning = zxcvbnOptions.translations.warnings.wordByItself;
      }

      return warning;
    };

    const getDictionaryWarningNames = (match, isSoleMatch) => {
      if (isSoleMatch) {
        return zxcvbnOptions.translations.warnings.namesByThemselves;
      }

      return zxcvbnOptions.translations.warnings.commonNames;
    };

    const getDictionaryWarning = (match, isSoleMatch) => {
      let warning = '';
      const dictName = match.dictionaryName;
      const isAName = dictName === 'lastnames' || dictName.toLowerCase().includes('firstnames');

      if (dictName === 'passwords') {
        warning = getDictionaryWarningPassword(match, isSoleMatch);
      } else if (dictName.includes('wikipedia')) {
        warning = getDictionaryWarningWikipedia(match, isSoleMatch);
      } else if (isAName) {
        warning = getDictionaryWarningNames(match, isSoleMatch);
      } else if (dictName === 'userInputs') {
        warning = zxcvbnOptions.translations.warnings.userInputs;
      }

      return warning;
    };

    var dictionaryMatcher = ((match, isSoleMatch) => {
      const warning = getDictionaryWarning(match, isSoleMatch);
      const suggestions = [];
      const word = match.token;

      if (word.match(START_UPPER)) {
        suggestions.push(zxcvbnOptions.translations.suggestions.capitalization);
      } else if (word.match(ALL_UPPER_INVERTED) && word.toLowerCase() !== word) {
        suggestions.push(zxcvbnOptions.translations.suggestions.allUppercase);
      }

      if (match.reversed && match.token.length >= 4) {
        suggestions.push(zxcvbnOptions.translations.suggestions.reverseWords);
      }

      if (match.l33t) {
        suggestions.push(zxcvbnOptions.translations.suggestions.l33t);
      }

      return {
        warning,
        suggestions
      };
    });

    var regexMatcher = (match => {
      if (match.regexName === 'recentYear') {
        return {
          warning: zxcvbnOptions.translations.warnings.recentYears,
          suggestions: [zxcvbnOptions.translations.suggestions.recentYears, zxcvbnOptions.translations.suggestions.associatedYears]
        };
      }

      return {
        warning: '',
        suggestions: []
      };
    });

    var repeatMatcher = (match => {
      let warning = zxcvbnOptions.translations.warnings.extendedRepeat;

      if (match.baseToken.length === 1) {
        warning = zxcvbnOptions.translations.warnings.simpleRepeat;
      }

      return {
        warning,
        suggestions: [zxcvbnOptions.translations.suggestions.repeated]
      };
    });

    var sequenceMatcher = (() => {
      return {
        warning: zxcvbnOptions.translations.warnings.sequences,
        suggestions: [zxcvbnOptions.translations.suggestions.sequences]
      };
    });

    var spatialMatcher = (match => {
      let warning = zxcvbnOptions.translations.warnings.keyPattern;

      if (match.turns === 1) {
        warning = zxcvbnOptions.translations.warnings.straightRow;
      }

      return {
        warning,
        suggestions: [zxcvbnOptions.translations.suggestions.longerKeyboardPattern]
      };
    });

    const defaultFeedback = {
      warning: '',
      suggestions: []
    };
    /*
     * -------------------------------------------------------------------------------
     *  Generate feedback ---------------------------------------------------------------
     * -------------------------------------------------------------------------------
     */

    class Feedback {
      constructor() {
        this.matchers = {
          bruteforce: bruteforceMatcher,
          date: dateMatcher,
          dictionary: dictionaryMatcher,
          regex: regexMatcher,
          repeat: repeatMatcher,
          sequence: sequenceMatcher,
          spatial: spatialMatcher
        };
        this.defaultFeedback = {
          warning: '',
          suggestions: []
        };
        this.setDefaultSuggestions();
      }

      setDefaultSuggestions() {
        this.defaultFeedback.suggestions.push(zxcvbnOptions.translations.suggestions.useWords, zxcvbnOptions.translations.suggestions.noNeed);
      }

      getFeedback(score, sequence) {
        if (sequence.length === 0) {
          return this.defaultFeedback;
        }

        if (score > 2) {
          return defaultFeedback;
        }

        const extraFeedback = zxcvbnOptions.translations.suggestions.anotherWord;
        const longestMatch = this.getLongestMatch(sequence);
        let feedback = this.getMatchFeedback(longestMatch, sequence.length === 1);

        if (feedback !== null && feedback !== undefined) {
          feedback.suggestions.unshift(extraFeedback);

          if (feedback.warning == null) {
            feedback.warning = '';
          }
        } else {
          feedback = {
            warning: '',
            suggestions: [extraFeedback]
          };
        }

        return feedback;
      }

      getLongestMatch(sequence) {
        let longestMatch = sequence[0];
        const slicedSequence = sequence.slice(1);
        slicedSequence.forEach(match => {
          if (match.token.length > longestMatch.token.length) {
            longestMatch = match;
          }
        });
        return longestMatch;
      }

      getMatchFeedback(match, isSoleMatch) {
        if (this.matchers[match.pattern]) {
          return this.matchers[match.pattern](match, isSoleMatch);
        }

        if (zxcvbnOptions.matchers[match.pattern] && 'feedback' in zxcvbnOptions.matchers[match.pattern]) {
          return zxcvbnOptions.matchers[match.pattern].feedback(match, isSoleMatch);
        }

        return defaultFeedback;
      }

    }

    /**
     * @link https://davidwalsh.name/javascript-debounce-function
     */
    var debounce = ((func, wait, isImmediate) => {
      let timeout;
      return function debounce(...args) {
        const context = this;

        const later = () => {
          timeout = undefined;

          if (!isImmediate) {
            func.apply(context, args);
          }
        };

        const shouldCallNow = isImmediate && !timeout;

        if (timeout !== undefined) {
          clearTimeout(timeout);
        }

        timeout = setTimeout(later, wait);

        if (shouldCallNow) {
          return func.apply(context, args);
        }

        return undefined;
      };
    });

    const time = () => new Date().getTime();

    const createReturnValue = (resolvedMatches, password, start) => {
      const feedback = new Feedback();
      const timeEstimates = new TimeEstimates();
      const matchSequence = scoring.mostGuessableMatchSequence(password, resolvedMatches);
      const calcTime = time() - start;
      const attackTimes = timeEstimates.estimateAttackTimes(matchSequence.guesses);
      return {
        calcTime,
        ...matchSequence,
        ...attackTimes,
        feedback: feedback.getFeedback(attackTimes.score, matchSequence.sequence)
      };
    };

    const main = (password, userInputs) => {
      if (userInputs) {
        zxcvbnOptions.extendUserInputsDictionary(userInputs);
      }

      const matching = new Matching();
      return matching.match(password);
    };

    const zxcvbn = (password, userInputs) => {
      const start = time();
      const matches = main(password, userInputs);

      if (matches instanceof Promise) {
        throw new Error('You are using a Promised matcher, please use `zxcvbnAsync` for it.');
      }

      return createReturnValue(matches, password, start);
    };
    const zxcvbnAsync = async (password, userInputs) => {
      const start = time();
      const matches = await main(password, userInputs);
      return createReturnValue(matches, password, start);
    };

    exports.debounce = debounce;
    exports.zxcvbn = zxcvbn;
    exports.zxcvbnAsync = zxcvbnAsync;
    exports.zxcvbnOptions = zxcvbnOptions;

    Object.defineProperty(exports, '__esModule', { value: true });

    return exports;

})({});
//# sourceMappingURL=zxcvbn-ts.js.map

Filemanager

Name Type Size Permission Actions
bootstrap Folder 0755
codemirror Folder 0755
jqplot Folder 0755
jquery Folder 0755
openlayers Folder 0755
js.cookie.js File 3.79 KB 0644
sprintf.js File 7.24 KB 0644
tracekit.js File 46.02 KB 0644
u2f-api-polyfill.js File 22.3 KB 0644
zxcvbn-ts.js File 75.44 KB 0644
zxcvbn-ts.js.map File 77.62 KB 0644
Filemanager