{"version":3,"file":"vendors-dc3e9b93.f584a1446b2fc034d810.bundle.js","mappings":"AAAA","sources":["webpack://lernplattform-admin-frontend/../common/node_modules/@zxcvbn-ts/core/dist/helper.esm.js","webpack://lernplattform-admin-frontend/../common/node_modules/@zxcvbn-ts/core/dist/data/l33tTable.esm.js","webpack://lernplattform-admin-frontend/../common/node_modules/@zxcvbn-ts/core/dist/data/adjacencyGraphs.esm.js","webpack://lernplattform-admin-frontend/../common/node_modules/@zxcvbn-ts/core/dist/data/translationKeys.esm.js","webpack://lernplattform-admin-frontend/../common/node_modules/@zxcvbn-ts/core/dist/Options.esm.js","webpack://lernplattform-admin-frontend/../common/node_modules/@zxcvbn-ts/core/dist/scoring/utils.esm.js","webpack://lernplattform-admin-frontend/../common/node_modules/@zxcvbn-ts/core/dist/data/const.esm.js","webpack://lernplattform-admin-frontend/../common/node_modules/@zxcvbn-ts/core/dist/data/dateSplits.esm.js","webpack://lernplattform-admin-frontend/../common/node_modules/@zxcvbn-ts/core/dist/scoring/guesses/bruteforce.esm.js","webpack://lernplattform-admin-frontend/../common/node_modules/@zxcvbn-ts/core/dist/scoring/guesses/date.esm.js","webpack://lernplattform-admin-frontend/../common/node_modules/@zxcvbn-ts/core/dist/scoring/variant/uppercase.esm.js","webpack://lernplattform-admin-frontend/../common/node_modules/@zxcvbn-ts/core/dist/scoring/variant/l33t.esm.js","webpack://lernplattform-admin-frontend/../common/node_modules/@zxcvbn-ts/core/dist/scoring/guesses/dictionary.esm.js","webpack://lernplattform-admin-frontend/../common/node_modules/@zxcvbn-ts/core/dist/scoring/guesses/regex.esm.js","webpack://lernplattform-admin-frontend/../common/node_modules/@zxcvbn-ts/core/dist/scoring/guesses/repeat.esm.js","webpack://lernplattform-admin-frontend/../common/node_modules/@zxcvbn-ts/core/dist/scoring/guesses/sequence.esm.js","webpack://lernplattform-admin-frontend/../common/node_modules/@zxcvbn-ts/core/dist/scoring/guesses/spatial.esm.js","webpack://lernplattform-admin-frontend/../common/node_modules/@zxcvbn-ts/core/dist/scoring/estimate.esm.js","webpack://lernplattform-admin-frontend/../common/node_modules/@zxcvbn-ts/core/dist/scoring.esm.js","webpack://lernplattform-admin-frontend/../common/node_modules/@zxcvbn-ts/core/dist/matching/Dictionary.esm.js","webpack://lernplattform-admin-frontend/../common/node_modules/@zxcvbn-ts/core/dist/matching/L33t.esm.js","webpack://lernplattform-admin-frontend/../common/node_modules/@zxcvbn-ts/core/dist/matching/DictionaryReverse.esm.js","webpack://lernplattform-admin-frontend/../common/node_modules/@zxcvbn-ts/core/dist/matching/Spatial.esm.js","webpack://lernplattform-admin-frontend/../common/node_modules/@zxcvbn-ts/core/dist/matching/Repeat.esm.js","webpack://lernplattform-admin-frontend/../common/node_modules/@zxcvbn-ts/core/dist/matching/Sequence.esm.js","webpack://lernplattform-admin-frontend/../common/node_modules/@zxcvbn-ts/core/dist/matching/Regex.esm.js","webpack://lernplattform-admin-frontend/../common/node_modules/@zxcvbn-ts/core/dist/matching/Date.esm.js","webpack://lernplattform-admin-frontend/../common/node_modules/@zxcvbn-ts/core/dist/Matching.esm.js","webpack://lernplattform-admin-frontend/../common/node_modules/@zxcvbn-ts/core/dist/TimeEstimates.esm.js","webpack://lernplattform-admin-frontend/../common/node_modules/@zxcvbn-ts/core/dist/Feedback.esm.js","webpack://lernplattform-admin-frontend/../common/node_modules/@zxcvbn-ts/core/dist/index.esm.js","webpack://lernplattform-admin-frontend/../common/node_modules/w3c-keyname/index.cjs"],"sourcesContent":["const empty = obj => Object.keys(obj).length === 0;\nconst extend = (listToExtend, list) => // eslint-disable-next-line prefer-spread\nlistToExtend.push.apply(listToExtend, list);\nconst translate = (string, chrMap) => {\n  const tempArray = string.split('');\n  return tempArray.map(char => chrMap[char] || char).join('');\n}; // mod implementation that works for negative numbers\n\nconst sorted = matches => matches.sort((m1, m2) => m1.i - m2.i || m1.j - m2.j);\nconst buildRankedDictionary = orderedList => {\n  const result = {};\n  let counter = 1; // rank starts at 1, not 0\n\n  orderedList.forEach(word => {\n    result[word] = counter;\n    counter += 1;\n  });\n  return result;\n};\n\nexport { buildRankedDictionary, empty, extend, sorted, translate };\n//# sourceMappingURL=helper.esm.js.map\n","var l33tTable = {\n  a: ['4', '@'],\n  b: ['8'],\n  c: ['(', '{', '[', '<'],\n  e: ['3'],\n  g: ['6', '9'],\n  i: ['1', '!', '|'],\n  l: ['1', '|', '7'],\n  o: ['0'],\n  s: ['$', '5'],\n  t: ['+', '7'],\n  x: ['%'],\n  z: ['2']\n};\n\nexport default l33tTable;\n//# sourceMappingURL=l33tTable.esm.js.map\n","var graphs = {\n  azerty: {\n    '0': ['ç9', null, null, ')°', 'pP', 'oO'],\n    '1': ['²~', null, null, 'é2', 'aA', null],\n    '2': ['&1', null, null, '\"3', 'zZ', 'aA'],\n    '3': ['é2', null, null, \"'4\", 'eE', 'zZ'],\n    '4': ['\"3', null, null, '(5', 'rR', 'eE'],\n    '5': [\"'4\", null, null, '-6', 'tT', 'rR'],\n    '6': ['(5', null, null, 'è7', 'yY', 'tT'],\n    '7': ['-6', null, null, '_8', 'uU', 'yY'],\n    '8': ['è7', null, null, 'ç9', 'iI', 'uU'],\n    '9': ['_8', null, null, 'à0', 'oO', 'iI'],\n    '²': [null, null, null, '&1', null, null],\n    '~': [null, null, null, '&1', null, null],\n    '&': ['²~', null, null, 'é2', 'aA', null],\n    'é': ['&1', null, null, '\"3', 'zZ', 'aA'],\n    '\"': ['pP', ')°', '+=', '$£', 'ù%', 'mM'],\n    \"'\": ['\"3', null, null, '(5', 'rR', 'eE'],\n    '(': [\"'4\", null, null, '-6', 'tT', 'rR'],\n    '-': ['(5', null, null, 'è7', 'yY', 'tT'],\n    'è': ['-6', null, null, '_8', 'uU', 'yY'],\n    '_': ['è7', null, null, 'ç9', 'iI', 'uU'],\n    'ç': ['_8', null, null, 'à0', 'oO', 'iI'],\n    'à': ['ç9', null, null, ')°', 'pP', 'oO'],\n    ')': ['à0', null, null, '+=', '^\"', 'pP'],\n    '°': ['à0', null, null, '+=', '^\"', 'pP'],\n    '+': [')°', null, null, null, '$£', '^\"'],\n    '=': [')°', null, null, null, '$£', '^\"'],\n    'a': [null, '&1', 'é2', 'zZ', 'qQ', null],\n    'A': [null, '&1', 'é2', 'zZ', 'qQ', null],\n    'z': ['aA', 'é2', '\"3', 'eE', 'sS', 'qQ'],\n    'Z': ['aA', 'é2', '\"3', 'eE', 'sS', 'qQ'],\n    'e': ['zZ', '\"3', \"'4\", 'rR', 'dD', 'sS'],\n    'E': ['zZ', '\"3', \"'4\", 'rR', 'dD', 'sS'],\n    'r': ['eE', \"'4\", '(5', 'tT', 'fF', 'dD'],\n    'R': ['eE', \"'4\", '(5', 'tT', 'fF', 'dD'],\n    't': ['rR', '(5', '-6', 'yY', 'gG', 'fF'],\n    'T': ['rR', '(5', '-6', 'yY', 'gG', 'fF'],\n    'y': ['tT', '-6', 'è7', 'uU', 'hH', 'gG'],\n    'Y': ['tT', '-6', 'è7', 'uU', 'hH', 'gG'],\n    'u': ['yY', 'è7', '_8', 'iI', 'jJ', 'hH'],\n    'U': ['yY', 'è7', '_8', 'iI', 'jJ', 'hH'],\n    'i': ['uU', '_8', 'ç9', 'oO', 'kK', 'jJ'],\n    'I': ['uU', '_8', 'ç9', 'oO', 'kK', 'jJ'],\n    'o': ['iI', 'ç9', 'à0', 'pP', 'lL', 'kK'],\n    'O': ['iI', 'ç9', 'à0', 'pP', 'lL', 'kK'],\n    'p': ['oO', 'à0', ')°', '^\"', 'mM', 'lL'],\n    'P': ['oO', 'à0', ')°', '^\"', 'mM', 'lL'],\n    '^': ['pP', ')°', '+=', '$£', 'ù%', 'mM'],\n    '$': ['^\"', '+=', null, null, '*µ', 'ù%'],\n    '£': ['^\"', '+=', null, null, '*µ', 'ù%'],\n    'q': [null, 'aA', 'zZ', 'sS', 'wW', '<>'],\n    'Q': [null, 'aA', 'zZ', 'sS', 'wW', '<>'],\n    's': ['qQ', 'zZ', 'eE', 'dD', 'xX', 'wW'],\n    'S': ['qQ', 'zZ', 'eE', 'dD', 'xX', 'wW'],\n    'd': ['sS', 'eE', 'rR', 'fF', 'cC', 'xX'],\n    'D': ['sS', 'eE', 'rR', 'fF', 'cC', 'xX'],\n    'f': ['dD', 'rR', 'tT', 'gG', 'vV', 'cC'],\n    'F': ['dD', 'rR', 'tT', 'gG', 'vV', 'cC'],\n    'g': ['fF', 'tT', 'yY', 'hH', 'bB', 'vV'],\n    'G': ['fF', 'tT', 'yY', 'hH', 'bB', 'vV'],\n    'h': ['gG', 'yY', 'uU', 'jJ', 'nN', 'bB'],\n    'H': ['gG', 'yY', 'uU', 'jJ', 'nN', 'bB'],\n    'j': ['hH', 'uU', 'iI', 'kK', ',?', 'nN'],\n    'J': ['hH', 'uU', 'iI', 'kK', ',?', 'nN'],\n    'k': ['jJ', 'iI', 'oO', 'lL', ';.', ',?'],\n    'K': ['jJ', 'iI', 'oO', 'lL', ';.', ',?'],\n    'l': ['kK', 'oO', 'pP', 'mM', ':/', ';.'],\n    'L': ['kK', 'oO', 'pP', 'mM', ':/', ';.'],\n    'm': ['lL', 'pP', '^\"', 'ù%', '!§', ':/'],\n    'M': ['lL', 'pP', '^\"', 'ù%', '!§', ':/'],\n    'ù': ['mM', '^\"', '$£', '*µ', null, '!§'],\n    '%': ['mM', '^\"', '$£', '*µ', null, '!§'],\n    '*': ['ù%', '$£', null, null, null, null],\n    'µ': ['ù%', '$£', null, null, null, null],\n    '<': [null, null, 'qQ', 'wW', null, null],\n    '>': [null, null, 'qQ', 'wW', null, null],\n    'w': ['<>', 'qQ', 'sS', 'xX', null, null],\n    'W': ['<>', 'qQ', 'sS', 'xX', null, null],\n    'x': ['wW', 'sS', 'dD', 'cC', null, null],\n    'X': ['wW', 'sS', 'dD', 'cC', null, null],\n    'c': ['xX', 'dD', 'fF', 'vV', null, null],\n    'C': ['xX', 'dD', 'fF', 'vV', null, null],\n    'v': ['cC', 'fF', 'gG', 'bB', null, null],\n    'V': ['cC', 'fF', 'gG', 'bB', null, null],\n    'b': ['vV', 'gG', 'hH', 'nN', null, null],\n    'B': ['vV', 'gG', 'hH', 'nN', null, null],\n    'n': ['bB', 'hH', 'jJ', ',?', null, null],\n    'N': ['bB', 'hH', 'jJ', ',?', null, null],\n    ',': ['nN', 'jJ', 'kK', ';.', null, null],\n    '?': ['nN', 'jJ', 'kK', ';.', null, null],\n    ';': [',?', 'kK', 'lL', ':/', null, null],\n    '.': [',?', 'kK', 'lL', ':/', null, null],\n    ':': [';.', 'lL', 'mM', '!§', null, null],\n    '/': [';.', 'lL', 'mM', '!§', null, null],\n    '!': [':/', 'mM', 'ù%', null, null, null],\n    '§': [':/', 'mM', 'ù%', null, null, null]\n  },\n  dvorak: {\n    '0': ['9(', null, null, '[{', 'lL', 'rR'],\n    '1': ['`~', null, null, '2@', '\\'\"', null],\n    '2': ['1!', null, null, '3#', ',<', '\\'\"'],\n    '3': ['2@', null, null, '4$', '.>', ',<'],\n    '4': ['3#', null, null, '5%', 'pP', '.>'],\n    '5': ['4$', null, null, '6^', 'yY', 'pP'],\n    '6': ['5%', null, null, '7&', 'fF', 'yY'],\n    '7': ['6^', null, null, '8*', 'gG', 'fF'],\n    '8': ['7&', null, null, '9(', 'cC', 'gG'],\n    '9': ['8*', null, null, '0)', 'rR', 'cC'],\n    '`': [null, null, null, '1!', null, null],\n    '~': [null, null, null, '1!', null, null],\n    '!': ['`~', null, null, '2@', '\\'\"', null],\n    '@': ['1!', null, null, '3#', ',<', '\\'\"'],\n    '#': ['2@', null, null, '4$', '.>', ',<'],\n    '$': ['3#', null, null, '5%', 'pP', '.>'],\n    '%': ['4$', null, null, '6^', 'yY', 'pP'],\n    '^': ['5%', null, null, '7&', 'fF', 'yY'],\n    '&': ['6^', null, null, '8*', 'gG', 'fF'],\n    '*': ['7&', null, null, '9(', 'cC', 'gG'],\n    '(': ['8*', null, null, '0)', 'rR', 'cC'],\n    ')': ['9(', null, null, '[{', 'lL', 'rR'],\n    '[': ['0)', null, null, ']}', '/?', 'lL'],\n    '{': ['0)', null, null, ']}', '/?', 'lL'],\n    ']': ['[{', null, null, null, '=+', '/?'],\n    '}': ['[{', null, null, null, '=+', '/?'],\n    \"'\": [null, '1!', '2@', ',<', 'aA', null],\n    '\"': [null, '1!', '2@', ',<', 'aA', null],\n    ',': ['\\'\"', '2@', '3#', '.>', 'oO', 'aA'],\n    '<': ['\\'\"', '2@', '3#', '.>', 'oO', 'aA'],\n    '.': [',<', '3#', '4$', 'pP', 'eE', 'oO'],\n    '>': [',<', '3#', '4$', 'pP', 'eE', 'oO'],\n    'p': ['.>', '4$', '5%', 'yY', 'uU', 'eE'],\n    'P': ['.>', '4$', '5%', 'yY', 'uU', 'eE'],\n    'y': ['pP', '5%', '6^', 'fF', 'iI', 'uU'],\n    'Y': ['pP', '5%', '6^', 'fF', 'iI', 'uU'],\n    'f': ['yY', '6^', '7&', 'gG', 'dD', 'iI'],\n    'F': ['yY', '6^', '7&', 'gG', 'dD', 'iI'],\n    'g': ['fF', '7&', '8*', 'cC', 'hH', 'dD'],\n    'G': ['fF', '7&', '8*', 'cC', 'hH', 'dD'],\n    'c': ['gG', '8*', '9(', 'rR', 'tT', 'hH'],\n    'C': ['gG', '8*', '9(', 'rR', 'tT', 'hH'],\n    'r': ['cC', '9(', '0)', 'lL', 'nN', 'tT'],\n    'R': ['cC', '9(', '0)', 'lL', 'nN', 'tT'],\n    'l': ['rR', '0)', '[{', '/?', 'sS', 'nN'],\n    'L': ['rR', '0)', '[{', '/?', 'sS', 'nN'],\n    '/': ['lL', '[{', ']}', '=+', '-_', 'sS'],\n    '?': ['lL', '[{', ']}', '=+', '-_', 'sS'],\n    '=': ['/?', ']}', null, '|', null, '-_'],\n    '+': ['/?', ']}', null, '|', null, '-_'],\n    '|': ['=+', null, null, null, null, null],\n    'a': [null, '\\'\"', ',<', 'oO', ';:', null],\n    'A': [null, '\\'\"', ',<', 'oO', ';:', null],\n    'o': ['aA', ',<', '.>', 'eE', 'qQ', ';:'],\n    'O': ['aA', ',<', '.>', 'eE', 'qQ', ';:'],\n    'e': ['oO', '.>', 'pP', 'uU', 'jJ', 'qQ'],\n    'E': ['oO', '.>', 'pP', 'uU', 'jJ', 'qQ'],\n    'u': ['eE', 'pP', 'yY', 'iI', 'kK', 'jJ'],\n    'U': ['eE', 'pP', 'yY', 'iI', 'kK', 'jJ'],\n    'i': ['uU', 'yY', 'fF', 'dD', 'xX', 'kK'],\n    'I': ['uU', 'yY', 'fF', 'dD', 'xX', 'kK'],\n    'd': ['iI', 'fF', 'gG', 'hH', 'bB', 'xX'],\n    'D': ['iI', 'fF', 'gG', 'hH', 'bB', 'xX'],\n    'h': ['dD', 'gG', 'cC', 'tT', 'mM', 'bB'],\n    'H': ['dD', 'gG', 'cC', 'tT', 'mM', 'bB'],\n    't': ['hH', 'cC', 'rR', 'nN', 'wW', 'mM'],\n    'T': ['hH', 'cC', 'rR', 'nN', 'wW', 'mM'],\n    'n': ['tT', 'rR', 'lL', 'sS', 'vV', 'wW'],\n    'N': ['tT', 'rR', 'lL', 'sS', 'vV', 'wW'],\n    's': ['nN', 'lL', '/?', '-_', 'zZ', 'vV'],\n    'S': ['nN', 'lL', '/?', '-_', 'zZ', 'vV'],\n    '-': ['sS', '/?', '=+', null, null, 'zZ'],\n    '_': ['sS', '/?', '=+', null, null, 'zZ'],\n    ';': [null, 'aA', 'oO', 'qQ', null, null],\n    ':': [null, 'aA', 'oO', 'qQ', null, null],\n    'q': [';:', 'oO', 'eE', 'jJ', null, null],\n    'Q': [';:', 'oO', 'eE', 'jJ', null, null],\n    'j': ['qQ', 'eE', 'uU', 'kK', null, null],\n    'J': ['qQ', 'eE', 'uU', 'kK', null, null],\n    'k': ['jJ', 'uU', 'iI', 'xX', null, null],\n    'K': ['jJ', 'uU', 'iI', 'xX', null, null],\n    'x': ['kK', 'iI', 'dD', 'bB', null, null],\n    'X': ['kK', 'iI', 'dD', 'bB', null, null],\n    'b': ['xX', 'dD', 'hH', 'mM', null, null],\n    'B': ['xX', 'dD', 'hH', 'mM', null, null],\n    'm': ['bB', 'hH', 'tT', 'wW', null, null],\n    'M': ['bB', 'hH', 'tT', 'wW', null, null],\n    'w': ['mM', 'tT', 'nN', 'vV', null, null],\n    'W': ['mM', 'tT', 'nN', 'vV', null, null],\n    'v': ['wW', 'nN', 'sS', 'zZ', null, null],\n    'V': ['wW', 'nN', 'sS', 'zZ', null, null],\n    'z': ['vV', 'sS', '-_', null, null, null],\n    'Z': ['vV', 'sS', '-_', null, null, null]\n  },\n  keypad: {\n    '0': [null, '1', '2', '3', '.', null, null, null],\n    '1': [null, null, '4', '5', '2', '0', null, null],\n    '2': ['1', '4', '5', '6', '3', '.', '0', null],\n    '3': ['2', '5', '6', null, null, null, '.', '0'],\n    '4': [null, null, '7', '8', '5', '2', '1', null],\n    '5': ['4', '7', '8', '9', '6', '3', '2', '1'],\n    '6': ['5', '8', '9', '+', null, null, '3', '2'],\n    '7': [null, null, null, '/', '8', '5', '4', null],\n    '8': ['7', null, '/', '*', '9', '6', '5', '4'],\n    '9': ['8', '/', '*', '-', '+', null, '6', '5'],\n    '/': [null, null, null, null, '*', '9', '8', '7'],\n    '*': ['/', null, null, null, '-', '+', '9', '8'],\n    '-': ['*', null, null, null, null, null, '+', '9'],\n    '+': ['9', '*', '-', null, null, null, null, '6'],\n    '.': ['0', '2', '3', null, null, null, null, null]\n  },\n  keypadMac: {\n    '0': [null, '1', '2', '3', '.', null, null, null],\n    '1': [null, null, '4', '5', '2', '0', null, null],\n    '2': ['1', '4', '5', '6', '3', '.', '0', null],\n    '3': ['2', '5', '6', '+', null, null, '.', '0'],\n    '4': [null, null, '7', '8', '5', '2', '1', null],\n    '5': ['4', '7', '8', '9', '6', '3', '2', '1'],\n    '6': ['5', '8', '9', '-', '+', null, '3', '2'],\n    '7': [null, null, null, '=', '8', '5', '4', null],\n    '8': ['7', null, '=', '/', '9', '6', '5', '4'],\n    '9': ['8', '=', '/', '*', '-', '+', '6', '5'],\n    '=': [null, null, null, null, '/', '9', '8', '7'],\n    '/': ['=', null, null, null, '*', '-', '9', '8'],\n    '*': ['/', null, null, null, null, null, '-', '9'],\n    '-': ['9', '/', '*', null, null, null, '+', '6'],\n    '+': ['6', '9', '-', null, null, null, null, '3'],\n    '.': ['0', '2', '3', null, null, null, null, null]\n  },\n  qwerty: {\n    '0': ['9(', null, null, '-_', 'pP', 'oO'],\n    '1': ['`~', null, null, '2@', 'qQ', null],\n    '2': ['1!', null, null, '3#', 'wW', 'qQ'],\n    '3': ['2@', null, null, '4$', 'eE', 'wW'],\n    '4': ['3#', null, null, '5%', 'rR', 'eE'],\n    '5': ['4$', null, null, '6^', 'tT', 'rR'],\n    '6': ['5%', null, null, '7&', 'yY', 'tT'],\n    '7': ['6^', null, null, '8*', 'uU', 'yY'],\n    '8': ['7&', null, null, '9(', 'iI', 'uU'],\n    '9': ['8*', null, null, '0)', 'oO', 'iI'],\n    '`': [null, null, null, '1!', null, null],\n    '~': [null, null, null, '1!', null, null],\n    '!': ['`~', null, null, '2@', 'qQ', null],\n    '@': ['1!', null, null, '3#', 'wW', 'qQ'],\n    '#': ['2@', null, null, '4$', 'eE', 'wW'],\n    '$': ['3#', null, null, '5%', 'rR', 'eE'],\n    '%': ['4$', null, null, '6^', 'tT', 'rR'],\n    '^': ['5%', null, null, '7&', 'yY', 'tT'],\n    '&': ['6^', null, null, '8*', 'uU', 'yY'],\n    '*': ['7&', null, null, '9(', 'iI', 'uU'],\n    '(': ['8*', null, null, '0)', 'oO', 'iI'],\n    ')': ['9(', null, null, '-_', 'pP', 'oO'],\n    '-': ['0)', null, null, '=+', '[{', 'pP'],\n    '_': ['0)', null, null, '=+', '[{', 'pP'],\n    '=': ['-_', null, null, null, ']}', '[{'],\n    '+': ['-_', null, null, null, ']}', '[{'],\n    'q': [null, '1!', '2@', 'wW', 'aA', null],\n    'Q': [null, '1!', '2@', 'wW', 'aA', null],\n    'w': ['qQ', '2@', '3#', 'eE', 'sS', 'aA'],\n    'W': ['qQ', '2@', '3#', 'eE', 'sS', 'aA'],\n    'e': ['wW', '3#', '4$', 'rR', 'dD', 'sS'],\n    'E': ['wW', '3#', '4$', 'rR', 'dD', 'sS'],\n    'r': ['eE', '4$', '5%', 'tT', 'fF', 'dD'],\n    'R': ['eE', '4$', '5%', 'tT', 'fF', 'dD'],\n    't': ['rR', '5%', '6^', 'yY', 'gG', 'fF'],\n    'T': ['rR', '5%', '6^', 'yY', 'gG', 'fF'],\n    'y': ['tT', '6^', '7&', 'uU', 'hH', 'gG'],\n    'Y': ['tT', '6^', '7&', 'uU', 'hH', 'gG'],\n    'u': ['yY', '7&', '8*', 'iI', 'jJ', 'hH'],\n    'U': ['yY', '7&', '8*', 'iI', 'jJ', 'hH'],\n    'i': ['uU', '8*', '9(', 'oO', 'kK', 'jJ'],\n    'I': ['uU', '8*', '9(', 'oO', 'kK', 'jJ'],\n    'o': ['iI', '9(', '0)', 'pP', 'lL', 'kK'],\n    'O': ['iI', '9(', '0)', 'pP', 'lL', 'kK'],\n    'p': ['oO', '0)', '-_', '[{', ';:', 'lL'],\n    'P': ['oO', '0)', '-_', '[{', ';:', 'lL'],\n    '[': ['pP', '-_', '=+', ']}', '\\'\"', ';:'],\n    '{': ['pP', '-_', '=+', ']}', '\\'\"', ';:'],\n    ']': ['[{', '=+', null, '|', null, '\\'\"'],\n    '}': ['[{', '=+', null, '|', null, '\\'\"'],\n    '|': [']}', null, null, null, null, null],\n    'a': [null, 'qQ', 'wW', 'sS', 'zZ', null],\n    'A': [null, 'qQ', 'wW', 'sS', 'zZ', null],\n    's': ['aA', 'wW', 'eE', 'dD', 'xX', 'zZ'],\n    'S': ['aA', 'wW', 'eE', 'dD', 'xX', 'zZ'],\n    'd': ['sS', 'eE', 'rR', 'fF', 'cC', 'xX'],\n    'D': ['sS', 'eE', 'rR', 'fF', 'cC', 'xX'],\n    'f': ['dD', 'rR', 'tT', 'gG', 'vV', 'cC'],\n    'F': ['dD', 'rR', 'tT', 'gG', 'vV', 'cC'],\n    'g': ['fF', 'tT', 'yY', 'hH', 'bB', 'vV'],\n    'G': ['fF', 'tT', 'yY', 'hH', 'bB', 'vV'],\n    'h': ['gG', 'yY', 'uU', 'jJ', 'nN', 'bB'],\n    'H': ['gG', 'yY', 'uU', 'jJ', 'nN', 'bB'],\n    'j': ['hH', 'uU', 'iI', 'kK', 'mM', 'nN'],\n    'J': ['hH', 'uU', 'iI', 'kK', 'mM', 'nN'],\n    'k': ['jJ', 'iI', 'oO', 'lL', ',<', 'mM'],\n    'K': ['jJ', 'iI', 'oO', 'lL', ',<', 'mM'],\n    'l': ['kK', 'oO', 'pP', ';:', '.>', ',<'],\n    'L': ['kK', 'oO', 'pP', ';:', '.>', ',<'],\n    ';': ['lL', 'pP', '[{', '\\'\"', '/?', '.>'],\n    ':': ['lL', 'pP', '[{', '\\'\"', '/?', '.>'],\n    \"'\": [';:', '[{', ']}', null, null, '/?'],\n    '\"': [';:', '[{', ']}', null, null, '/?'],\n    'z': [null, 'aA', 'sS', 'xX', null, null],\n    'Z': [null, 'aA', 'sS', 'xX', null, null],\n    'x': ['zZ', 'sS', 'dD', 'cC', null, null],\n    'X': ['zZ', 'sS', 'dD', 'cC', null, null],\n    'c': ['xX', 'dD', 'fF', 'vV', null, null],\n    'C': ['xX', 'dD', 'fF', 'vV', null, null],\n    'v': ['cC', 'fF', 'gG', 'bB', null, null],\n    'V': ['cC', 'fF', 'gG', 'bB', null, null],\n    'b': ['vV', 'gG', 'hH', 'nN', null, null],\n    'B': ['vV', 'gG', 'hH', 'nN', null, null],\n    'n': ['bB', 'hH', 'jJ', 'mM', null, null],\n    'N': ['bB', 'hH', 'jJ', 'mM', null, null],\n    'm': ['nN', 'jJ', 'kK', ',<', null, null],\n    'M': ['nN', 'jJ', 'kK', ',<', null, null],\n    ',': ['mM', 'kK', 'lL', '.>', null, null],\n    '<': ['mM', 'kK', 'lL', '.>', null, null],\n    '.': [',<', 'lL', ';:', '/?', null, null],\n    '>': [',<', 'lL', ';:', '/?', null, null],\n    '/': ['.>', ';:', '\\'\"', null, null, null],\n    '?': ['.>', ';:', '\\'\"', null, null, null]\n  },\n  qwertz: {\n    '0': ['9)', null, null, 'ß?', 'pP', 'oO'],\n    '1': ['^°', null, null, '2\"', 'qQ', null],\n    '2': ['1!', null, null, '3§', 'wW', 'qQ'],\n    '3': ['2\"', null, null, '4$', 'eE', 'wW'],\n    '4': ['3§', null, null, '5%', 'rR', 'eE'],\n    '5': ['4$', null, null, '6&', 'tT', 'rR'],\n    '6': ['5%', null, null, '7/', 'zZ', 'tT'],\n    '7': ['6&', null, null, '8(', 'uU', 'zZ'],\n    '8': ['7/', null, null, '9)', 'iI', 'uU'],\n    '9': ['8(', null, null, '0=', 'oO', 'iI'],\n    '^': [null, null, null, '1!', null, null],\n    '°': [null, null, null, '1!', null, null],\n    '!': ['^°', null, null, '2\"', 'qQ', null],\n    '\"': ['1!', null, null, '3§', 'wW', 'qQ'],\n    '§': ['2\"', null, null, '4$', 'eE', 'wW'],\n    '$': ['3§', null, null, '5%', 'rR', 'eE'],\n    '%': ['4$', null, null, '6&', 'tT', 'rR'],\n    '&': ['5%', null, null, '7/', 'zZ', 'tT'],\n    '/': ['6&', null, null, '8(', 'uU', 'zZ'],\n    '(': ['7/', null, null, '9)', 'iI', 'uU'],\n    ')': ['8(', null, null, '0=', 'oO', 'iI'],\n    '=': ['9)', null, null, 'ß?', 'pP', 'oO'],\n    'ß': ['0=', null, null, '´`', 'üÜ', 'pP'],\n    '?': ['0=', null, null, '´`', 'üÜ', 'pP'],\n    '´': ['ß?', null, null, null, '+*', 'üÜ'],\n    '`': ['ß?', null, null, null, '+*', 'üÜ'],\n    'q': [null, '1!', '2\"', 'wW', 'aA', null],\n    'Q': [null, '1!', '2\"', 'wW', 'aA', null],\n    'w': ['qQ', '2\"', '3§', 'eE', 'sS', 'aA'],\n    'W': ['qQ', '2\"', '3§', 'eE', 'sS', 'aA'],\n    'e': ['wW', '3§', '4$', 'rR', 'dD', 'sS'],\n    'E': ['wW', '3§', '4$', 'rR', 'dD', 'sS'],\n    'r': ['eE', '4$', '5%', 'tT', 'fF', 'dD'],\n    'R': ['eE', '4$', '5%', 'tT', 'fF', 'dD'],\n    't': ['rR', '5%', '6&', 'zZ', 'gG', 'fF'],\n    'T': ['rR', '5%', '6&', 'zZ', 'gG', 'fF'],\n    'z': ['tT', '6&', '7/', 'uU', 'hH', 'gG'],\n    'Z': ['tT', '6&', '7/', 'uU', 'hH', 'gG'],\n    'u': ['zZ', '7/', '8(', 'iI', 'jJ', 'hH'],\n    'U': ['zZ', '7/', '8(', 'iI', 'jJ', 'hH'],\n    'i': ['uU', '8(', '9)', 'oO', 'kK', 'jJ'],\n    'I': ['uU', '8(', '9)', 'oO', 'kK', 'jJ'],\n    'o': ['iI', '9)', '0=', 'pP', 'lL', 'kK'],\n    'O': ['iI', '9)', '0=', 'pP', 'lL', 'kK'],\n    'p': ['oO', '0=', 'ß?', 'üÜ', 'öÖ', 'lL'],\n    'P': ['oO', '0=', 'ß?', 'üÜ', 'öÖ', 'lL'],\n    'ü': ['pP', 'ß?', '´`', '+*', 'äÄ', 'öÖ'],\n    'Ü': ['pP', 'ß?', '´`', '+*', 'äÄ', 'öÖ'],\n    '+': ['üÜ', '´`', null, null, \"#'\", 'äÄ'],\n    '*': ['üÜ', '´`', null, null, \"#'\", 'äÄ'],\n    'a': [null, 'qQ', 'wW', 'sS', 'yY', '<>'],\n    'A': [null, 'qQ', 'wW', 'sS', 'yY', '<>'],\n    's': ['aA', 'wW', 'eE', 'dD', 'xX', 'yY'],\n    'S': ['aA', 'wW', 'eE', 'dD', 'xX', 'yY'],\n    'd': ['sS', 'eE', 'rR', 'fF', 'cC', 'xX'],\n    'D': ['sS', 'eE', 'rR', 'fF', 'cC', 'xX'],\n    'f': ['dD', 'rR', 'tT', 'gG', 'vV', 'cC'],\n    'F': ['dD', 'rR', 'tT', 'gG', 'vV', 'cC'],\n    'g': ['fF', 'tT', 'zZ', 'hH', 'bB', 'vV'],\n    'G': ['fF', 'tT', 'zZ', 'hH', 'bB', 'vV'],\n    'h': ['gG', 'zZ', 'uU', 'jJ', 'nN', 'bB'],\n    'H': ['gG', 'zZ', 'uU', 'jJ', 'nN', 'bB'],\n    'j': ['hH', 'uU', 'iI', 'kK', 'mM', 'nN'],\n    'J': ['hH', 'uU', 'iI', 'kK', 'mM', 'nN'],\n    'k': ['jJ', 'iI', 'oO', 'lL', ',;', 'mM'],\n    'K': ['jJ', 'iI', 'oO', 'lL', ',;', 'mM'],\n    'l': ['kK', 'oO', 'pP', 'öÖ', '.:', ',;'],\n    'L': ['kK', 'oO', 'pP', 'öÖ', '.:', ',;'],\n    'ö': ['lL', 'pP', 'üÜ', 'äÄ', '-_', '.:'],\n    'Ö': ['lL', 'pP', 'üÜ', 'äÄ', '-_', '.:'],\n    'ä': ['öÖ', 'üÜ', '+*', \"#'\", null, '-_'],\n    'Ä': ['öÖ', 'üÜ', '+*', \"#'\", null, '-_'],\n    '#': ['äÄ', '+*', null, null, null, null],\n    \"'\": ['äÄ', '+*', null, null, null, null],\n    '<': [null, null, 'aA', 'yY', null, null],\n    '>': [null, null, 'aA', 'yY', null, null],\n    'y': ['<>', 'aA', 'sS', 'xX', null, null],\n    'Y': ['<>', 'aA', 'sS', 'xX', null, null],\n    'x': ['yY', 'sS', 'dD', 'cC', null, null],\n    'X': ['yY', 'sS', 'dD', 'cC', null, null],\n    'c': ['xX', 'dD', 'fF', 'vV', null, null],\n    'C': ['xX', 'dD', 'fF', 'vV', null, null],\n    'v': ['cC', 'fF', 'gG', 'bB', null, null],\n    'V': ['cC', 'fF', 'gG', 'bB', null, null],\n    'b': ['vV', 'gG', 'hH', 'nN', null, null],\n    'B': ['vV', 'gG', 'hH', 'nN', null, null],\n    'n': ['bB', 'hH', 'jJ', 'mM', null, null],\n    'N': ['bB', 'hH', 'jJ', 'mM', null, null],\n    'm': ['nN', 'jJ', 'kK', ',;', null, null],\n    'M': ['nN', 'jJ', 'kK', ',;', null, null],\n    ',': ['mM', 'kK', 'lL', '.:', null, null],\n    ';': ['mM', 'kK', 'lL', '.:', null, null],\n    '.': [',;', 'lL', 'öÖ', '-_', null, null],\n    ':': [',;', 'lL', 'öÖ', '-_', null, null],\n    '-': ['.:', 'öÖ', 'äÄ', null, null, null],\n    '_': ['.:', 'öÖ', 'äÄ', null, null, null]\n  }\n};\n\nexport default graphs;\n//# sourceMappingURL=adjacencyGraphs.esm.js.map\n","var translationKeys = {\n  warnings: {\n    straightRow: \"straightRow\",\n    keyPattern: \"keyPattern\",\n    simpleRepeat: \"simpleRepeat\",\n    extendedRepeat: \"extendedRepeat\",\n    sequences: \"sequences\",\n    recentYears: \"recentYears\",\n    dates: \"dates\",\n    topTen: \"topTen\",\n    topHundred: \"topHundred\",\n    common: \"common\",\n    similarToCommon: \"similarToCommon\",\n    wordByItself: \"wordByItself\",\n    namesByThemselves: \"namesByThemselves\",\n    commonNames: \"commonNames\"\n  },\n  suggestions: {\n    l33t: \"l33t\",\n    reverseWords: \"reverseWords\",\n    allUppercase: \"allUppercase\",\n    capitalization: \"capitalization\",\n    dates: \"dates\",\n    recentYears: \"recentYears\",\n    associatedYears: \"associatedYears\",\n    sequences: \"sequences\",\n    repeated: \"repeated\",\n    longerKeyboardPattern: \"longerKeyboardPattern\",\n    anotherWord: \"anotherWord\",\n    useWords: \"useWords\",\n    noNeed: \"noNeed\"\n  },\n  timeEstimation: {\n    ltSecond: \"ltSecond\",\n    second: \"second\",\n    seconds: \"seconds\",\n    minute: \"minute\",\n    minutes: \"minutes\",\n    hour: \"hour\",\n    hours: \"hours\",\n    day: \"day\",\n    days: \"days\",\n    month: \"month\",\n    months: \"months\",\n    year: \"year\",\n    years: \"years\",\n    centuries: \"centuries\"\n  }\n};\n\nexport default translationKeys;\n//# sourceMappingURL=translationKeys.esm.js.map\n","import { buildRankedDictionary } from './helper.esm.js';\nimport l33tTable from './data/l33tTable.esm.js';\nimport graphs from './data/adjacencyGraphs.esm.js';\nimport translationKeys from './data/translationKeys.esm.js';\n\nclass Options {\n  constructor() {\n    this.dictionary = {\n      userInput: []\n    };\n    this.availableGraphs = [];\n  }\n\n  setOptions(options = {}) {\n    if (options.l33tTable) {\n      this.l33tTable = options.l33tTable;\n    } else if (!this.l33tTable) {\n      this.l33tTable = l33tTable;\n    }\n\n    if (options.dictionary) {\n      this.dictionary = options.dictionary;\n    }\n\n    if (options.translations) {\n      this.setTranslations(options.translations);\n    } else if (!this.translations) {\n      this.setTranslations(translationKeys);\n    }\n\n    if (options.graphs) {\n      this.setAdjacencyGraphs(options.graphs);\n    } else if (!this.graphs) {\n      this.setAdjacencyGraphs(graphs);\n    }\n\n    this.setRankedDictionaries();\n  }\n\n  setTranslations(translations) {\n    if (this.checkCustomTranslations(translations)) {\n      this.translations = translations;\n    } else {\n      throw new Error('Invalid translations object fallback to keys');\n    }\n  }\n\n  checkCustomTranslations(translations) {\n    let valid = true;\n    Object.keys(translationKeys).forEach(type => {\n      if (type in translations) {\n        Object.keys(translationKeys[type]).forEach(key => {\n          if (!(key in translations[type])) {\n            valid = false;\n          }\n        });\n      } else {\n        valid = false;\n      }\n    });\n    return valid;\n  }\n\n  setRankedDictionaries() {\n    const rankedDictionaries = {};\n    Object.keys(this.dictionary).forEach(name => {\n      const list = this.dictionary[name];\n\n      if (name === 'userInputs') {\n        const sanitizedInputs = [];\n        list.forEach(input => {\n          const inputType = typeof input;\n\n          if (inputType === 'string' || inputType === 'number' || inputType === 'boolean') {\n            sanitizedInputs.push(input.toString().toLowerCase());\n          }\n        });\n        rankedDictionaries[name] = buildRankedDictionary(sanitizedInputs);\n      } else {\n        rankedDictionaries[name] = buildRankedDictionary(list);\n      }\n    });\n    this.rankedDictionaries = rankedDictionaries;\n  }\n\n  setAdjacencyGraphs(adjacencyGraphs) {\n    if (adjacencyGraphs) {\n      this.graphs = adjacencyGraphs;\n      this.availableGraphs = Object.keys(adjacencyGraphs);\n    }\n  }\n\n}\n\nvar Options$1 = new Options();\n\nexport default Options$1;\n//# sourceMappingURL=Options.esm.js.map\n","var utils = {\n  // binomial coefficients\n  // src: http://blog.plover.com/math/choose.html\n  nCk(n, k) {\n    let count = n;\n\n    if (k > count) {\n      return 0;\n    }\n\n    if (k === 0) {\n      return 1;\n    }\n\n    let coEff = 1;\n\n    for (let i = 1; i <= k; i += 1) {\n      coEff *= count;\n      coEff /= i;\n      count -= 1;\n    }\n\n    return coEff;\n  },\n\n  log10(n) {\n    return Math.log(n) / Math.log(10); // IE doesn't support Math.log10 :(\n  },\n\n  log2(n) {\n    return Math.log(n) / Math.log(2);\n  },\n\n  factorial(num) {\n    let rval = 1;\n\n    for (let i = 2; i <= num; i += 1) rval *= i;\n\n    return rval;\n  }\n\n};\n\nexport default utils;\n//# sourceMappingURL=utils.esm.js.map\n","import dateSplits from './dateSplits.esm.js';\n\nconst DATE_MAX_YEAR = 2050;\nconst DATE_MIN_YEAR = 1000;\nconst DATE_SPLITS = dateSplits;\nconst BRUTEFORCE_CARDINALITY = 10;\nconst MIN_GUESSES_BEFORE_GROWING_SEQUENCE = 10000;\nconst MIN_SUBMATCH_GUESSES_SINGLE_CHAR = 10;\nconst MIN_SUBMATCH_GUESSES_MULTI_CHAR = 50;\nconst MIN_YEAR_SPACE = 20; // \\xbf-\\xdf is a range for almost all special uppercase letter like Ä and so on\n\nconst START_UPPER = /^[A-Z\\xbf-\\xdf][^A-Z\\xbf-\\xdf]+$/;\nconst 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\n\nconst ALL_UPPER = /^[A-Z\\xbf-\\xdf]+$/;\nconst ALL_UPPER_INVERTED = /^[^a-z\\xdf-\\xff]+$/;\nconst ALL_LOWER = /^[a-z\\xdf-\\xff]+$/;\nconst ALL_LOWER_INVERTED = /^[^A-Z\\xbf-\\xdf]+$/;\nconst ONE_UPPER = /[a-z\\xdf-\\xff]/;\nconst ONE_LOWER = /[A-Z\\xbf-\\xdf]/;\nconst ALPHA_INVERTED = /[^A-Za-z\\xbf-\\xdf]/gi;\nconst ALL_DIGIT = /^\\d+$/;\nconst REFERENCE_YEAR = new Date().getFullYear();\nconst REGEXEN = {\n  recentYear: /19\\d\\d|200\\d|201\\d|202\\d/g\n};\n\nexport { ALL_DIGIT, ALL_LOWER, ALL_LOWER_INVERTED, ALL_UPPER, ALL_UPPER_INVERTED, ALPHA_INVERTED, BRUTEFORCE_CARDINALITY, DATE_MAX_YEAR, DATE_MIN_YEAR, DATE_SPLITS, END_UPPER, MIN_GUESSES_BEFORE_GROWING_SEQUENCE, MIN_SUBMATCH_GUESSES_MULTI_CHAR, MIN_SUBMATCH_GUESSES_SINGLE_CHAR, MIN_YEAR_SPACE, ONE_LOWER, ONE_UPPER, REFERENCE_YEAR, REGEXEN, START_UPPER };\n//# sourceMappingURL=const.esm.js.map\n","var dateSplits = {\n  4: [[1, 2], [2, 3]],\n  5: [[1, 3], [2, 3]],\n  6: [[1, 2], [2, 4], [4, 5]],\n  7: [[1, 3], [2, 3], [4, 5], [4, 6]],\n  8: [[2, 4], [4, 6]]\n};\n\nexport default dateSplits;\n//# sourceMappingURL=dateSplits.esm.js.map\n","import { BRUTEFORCE_CARDINALITY, MIN_SUBMATCH_GUESSES_SINGLE_CHAR, MIN_SUBMATCH_GUESSES_MULTI_CHAR } from '../../data/const.esm.js';\n\nvar bruteforceGuesses = (({\n  token\n}) => {\n  let guesses = BRUTEFORCE_CARDINALITY ** token.length;\n\n  if (guesses === Number.POSITIVE_INFINITY) {\n    guesses = Number.MAX_VALUE;\n  }\n\n  let minGuesses; // small detail: make bruteforce matches at minimum one guess bigger than smallest allowed\n  // submatch guesses, such that non-bruteforce submatches over the same [i..j] take precedence.\n\n  if (token.length === 1) {\n    minGuesses = MIN_SUBMATCH_GUESSES_SINGLE_CHAR + 1;\n  } else {\n    minGuesses = MIN_SUBMATCH_GUESSES_MULTI_CHAR + 1;\n  }\n\n  return Math.max(guesses, minGuesses);\n});\n\nexport default bruteforceGuesses;\n//# sourceMappingURL=bruteforce.esm.js.map\n","import { REFERENCE_YEAR, MIN_YEAR_SPACE } from '../../data/const.esm.js';\n\nvar dateGuesses = (({\n  year,\n  separator\n}) => {\n  // base guesses: (year distance from REFERENCE_YEAR) * num_days * num_years\n  const yearSpace = Math.max(Math.abs(year - REFERENCE_YEAR), MIN_YEAR_SPACE);\n  let guesses = yearSpace * 365; // add factor of 4 for separator selection (one of ~4 choices)\n\n  if (separator) {\n    guesses *= 4;\n  }\n\n  return guesses;\n});\n\nexport default dateGuesses;\n//# sourceMappingURL=date.esm.js.map\n","import utils from '../utils.esm.js';\nimport { ALPHA_INVERTED, ALL_LOWER_INVERTED, ONE_UPPER, ONE_LOWER, START_UPPER, END_UPPER, ALL_UPPER_INVERTED } from '../../data/const.esm.js';\n\nvar uppercaseVariant = (word => {\n  // clean words of non alpha characters to remove the reward effekt to capitalize the first letter https://github.com/dropbox/zxcvbn/issues/232\n  const cleanedWord = word.replace(ALPHA_INVERTED, '');\n\n  if (cleanedWord.match(ALL_LOWER_INVERTED) || cleanedWord.toLowerCase() === cleanedWord) {\n    return 1;\n  } // a capitalized word is the most common capitalization scheme,\n  // so it only doubles the search space (uncapitalized + capitalized).\n  // allcaps and end-capitalized are common enough too, underestimate as 2x factor to be safe.\n\n\n  const commonCases = [START_UPPER, END_UPPER, ALL_UPPER_INVERTED];\n  const commonCasesLength = commonCases.length;\n\n  for (let i = 0; i < commonCasesLength; i += 1) {\n    const regex = commonCases[i];\n\n    if (cleanedWord.match(regex)) {\n      return 2;\n    }\n  } // otherwise calculate the number of ways to capitalize U+L uppercase+lowercase letters\n  // with U uppercase letters or less. or, if there's more uppercase than lower (for eg. PASSwORD),\n  // the number of ways to lowercase U+L letters with L lowercase letters or less.\n\n\n  const wordArray = cleanedWord.split('');\n  const upperCaseCount = wordArray.filter(char => char.match(ONE_UPPER)).length;\n  const lowerCaseCount = wordArray.filter(char => char.match(ONE_LOWER)).length;\n  let variations = 0;\n  const variationLength = Math.min(upperCaseCount, lowerCaseCount);\n\n  for (let i = 1; i <= variationLength; i += 1) {\n    variations += utils.nCk(upperCaseCount + lowerCaseCount, i);\n  }\n\n  return variations;\n});\n\nexport default uppercaseVariant;\n//# sourceMappingURL=uppercase.esm.js.map\n","import utils from '../utils.esm.js';\n\nvar l33tVariant = (({\n  l33t,\n  sub,\n  token\n}) => {\n  if (!l33t) {\n    return 1;\n  }\n\n  let variations = 1;\n  const subs = sub;\n  Object.keys(subs).forEach(subbed => {\n    const unsubbed = subs[subbed]; // lower-case match.token before calculating: capitalization shouldn't affect l33t calc.\n\n    const chrs = token.toLowerCase().split(''); // num of subbed chars\n\n    const subbedCount = chrs.filter(char => char === subbed).length; // num of unsubbed chars\n\n    const unsubbedCount = chrs.filter(char => char === unsubbed).length;\n\n    if (subbedCount === 0 || unsubbedCount === 0) {\n      // for this sub, password is either fully subbed (444) or fully unsubbed (aaa)\n      // treat that as doubling the space (attacker needs to try fully subbed chars in addition to\n      // unsubbed.)\n      variations *= 2;\n    } else {\n      // this case is similar to capitalization:\n      // with aa44a, U = 3, S = 2, attacker needs to try unsubbed + one sub + two subs\n      const p = Math.min(unsubbedCount, subbedCount);\n      let possibilities = 0;\n\n      for (let i = 1; i <= p; i += 1) {\n        possibilities += utils.nCk(unsubbedCount + subbedCount, i);\n      }\n\n      variations *= possibilities;\n    }\n  });\n  return variations;\n});\n\nexport default l33tVariant;\n//# sourceMappingURL=l33t.esm.js.map\n","import uppercaseVariant from '../variant/uppercase.esm.js';\nimport l33tVariant from '../variant/l33t.esm.js';\n\nvar dictionaryGuesses = (({\n  rank,\n  reversed,\n  l33t,\n  sub,\n  token\n}) => {\n  const baseGuesses = rank; // keep these as properties for display purposes\n\n  const uppercaseVariations = uppercaseVariant(token);\n  const l33tVariations = l33tVariant({\n    l33t,\n    sub,\n    token\n  });\n  const reversedVariations = reversed && 2 || 1;\n  const calculation = baseGuesses * uppercaseVariations * l33tVariations * reversedVariations;\n  return {\n    baseGuesses,\n    uppercaseVariations,\n    l33tVariations,\n    calculation\n  };\n});\n\nexport default dictionaryGuesses;\n//# sourceMappingURL=dictionary.esm.js.map\n","import { REFERENCE_YEAR, MIN_YEAR_SPACE } from '../../data/const.esm.js';\n\nvar regexGuesses = (({\n  regexName,\n  regexMatch,\n  token\n}) => {\n  const charClassBases = {\n    alphaLower: 26,\n    alphaUpper: 26,\n    alpha: 52,\n    alphanumeric: 62,\n    digits: 10,\n    symbols: 33\n  };\n\n  if (regexName in charClassBases) {\n    return charClassBases[regexName] ** token.length;\n  } // TODO add more regex types for example special dates like 09.11\n  // eslint-disable-next-line default-case\n\n\n  switch (regexName) {\n    case 'recentYear':\n      // conservative estimate of year space: num years from REFERENCE_YEAR.\n      // if year is close to REFERENCE_YEAR, estimate a year space of MIN_YEAR_SPACE.\n      return Math.max(Math.abs(parseInt(regexMatch[0], 10) - REFERENCE_YEAR), MIN_YEAR_SPACE);\n  }\n\n  return 0;\n});\n\nexport default regexGuesses;\n//# sourceMappingURL=regex.esm.js.map\n","var repeatGuesses = (({\n  baseGuesses,\n  repeatCount\n}) => baseGuesses * repeatCount);\n\nexport default repeatGuesses;\n//# sourceMappingURL=repeat.esm.js.map\n","var sequenceGuesses = (({\n  token,\n  ascending\n}) => {\n  const firstChr = token.charAt(0);\n  let baseGuesses = 0;\n  const startingPoints = ['a', 'A', 'z', 'Z', '0', '1', '9']; // lower guesses for obvious starting points\n\n  if (startingPoints.includes(firstChr)) {\n    baseGuesses = 4;\n  } else if (firstChr.match(/\\d/)) {\n    baseGuesses = 10; // digits\n  } else {\n    // could give a higher base for uppercase,\n    // assigning 26 to both upper and lower sequences is more conservative.\n    baseGuesses = 26;\n  } // need to try a descending sequence in addition to every ascending sequence ->\n  // 2x guesses\n\n\n  if (!ascending) {\n    baseGuesses *= 2;\n  }\n\n  return baseGuesses * token.length;\n});\n\nexport default sequenceGuesses;\n//# sourceMappingURL=sequence.esm.js.map\n","import Options from '../../Options.esm.js';\nimport utils from '../utils.esm.js';\n\nconst calcAverageDegree = graph => {\n  let average = 0;\n  Object.keys(graph).forEach(key => {\n    const neighbors = graph[key];\n    average += neighbors.filter(entry => !!entry).length;\n  });\n  average /= Object.entries(graph).length;\n  return average;\n};\n\nvar spatialGuesses = (({\n  graph,\n  token,\n  shiftedCount,\n  turns\n}) => {\n  const startingPosition = calcAverageDegree(Options.graphs[graph]);\n  const averageDegree = Object.keys(Options.graphs[graph]).length;\n  let guesses = 0;\n  const tokenLength = token.length; // # estimate the number of possible patterns w/ tokenLength or less with turns or less.\n\n  for (let i = 2; i <= tokenLength; i += 1) {\n    const possibleTurns = Math.min(turns, i - 1);\n\n    for (let j = 1; j <= possibleTurns; j += 1) {\n      guesses += utils.nCk(i - 1, j - 1) * startingPosition * averageDegree ** j;\n    }\n  } // add extra guesses for shifted keys. (% instead of 5, A instead of a.)\n  // math is similar to extra guesses of l33t substitutions in dictionary matches.\n\n\n  if (shiftedCount) {\n    const unShiftedCount = token.length - shiftedCount;\n\n    if (shiftedCount === 0 || unShiftedCount === 0) {\n      guesses *= 2;\n    } else {\n      let shiftedVariations = 0;\n\n      for (let i = 1; i <= Math.min(shiftedCount, unShiftedCount); i += 1) {\n        shiftedVariations += utils.nCk(shiftedCount + unShiftedCount, i);\n      }\n\n      guesses *= shiftedVariations;\n    }\n  }\n\n  return Math.round(guesses);\n});\n\nexport default spatialGuesses;\n//# sourceMappingURL=spatial.esm.js.map\n","import utils from './utils.esm.js';\nimport { MIN_SUBMATCH_GUESSES_SINGLE_CHAR, MIN_SUBMATCH_GUESSES_MULTI_CHAR } from '../data/const.esm.js';\nimport bruteforceGuesses from './guesses/bruteforce.esm.js';\nimport dateGuesses from './guesses/date.esm.js';\nimport dictionaryGuesses from './guesses/dictionary.esm.js';\nimport regexGuesses from './guesses/regex.esm.js';\nimport repeatGuesses from './guesses/repeat.esm.js';\nimport sequenceGuesses from './guesses/sequence.esm.js';\nimport spatialGuesses from './guesses/spatial.esm.js';\n\n// guess estimation -- one function per match pattern ---------------------------\n// ------------------------------------------------------------------------------\n\nvar estimateGuesses = ((match, password) => {\n  const extraData = {}; // a match's guess estimate doesn't change. cache it.\n\n  if ('guesses' in match && match.guesses != null) {\n    return match;\n  }\n\n  let minGuesses = 1;\n\n  if (match.token.length < password.length) {\n    if (match.token.length === 1) {\n      minGuesses = MIN_SUBMATCH_GUESSES_SINGLE_CHAR;\n    } else {\n      minGuesses = MIN_SUBMATCH_GUESSES_MULTI_CHAR;\n    }\n  }\n\n  const estimationFunctions = {\n    bruteforce: bruteforceGuesses,\n    dictionary: dictionaryGuesses,\n    spatial: spatialGuesses,\n    repeat: repeatGuesses,\n    sequence: sequenceGuesses,\n    regex: regexGuesses,\n    date: dateGuesses\n  }; // @ts-ignore\n\n  const estimationResult = estimationFunctions[match.pattern](match);\n  let guesses = 0;\n\n  if (match.pattern === 'dictionary') {\n    // @ts-ignore\n    guesses = estimationResult.calculation; // @ts-ignore\n\n    extraData.baseGuesses = estimationResult.baseGuesses; // @ts-ignore\n\n    extraData.uppercaseVariations = estimationResult.uppercaseVariations; // @ts-ignore\n\n    extraData.l33tVariations = estimationResult.l33tVariations;\n  } else {\n    guesses = estimationResult;\n  }\n\n  const matchGuesses = Math.max(guesses, minGuesses);\n  return { ...match,\n    ...extraData,\n    guesses: matchGuesses,\n    guessesLog10: utils.log10(matchGuesses)\n  };\n});\n\nexport default estimateGuesses;\n//# sourceMappingURL=estimate.esm.js.map\n","import utils from './scoring/utils.esm.js';\nimport { MIN_GUESSES_BEFORE_GROWING_SEQUENCE } from './data/const.esm.js';\nimport estimateGuesses from './scoring/estimate.esm.js';\n\nconst scoringHelper = {\n  password: '',\n  optimal: {},\n  excludeAdditive: false,\n\n  fillArray(size, valueType) {\n    const result = [];\n\n    for (let i = 0; i < size; i += 1) {\n      let value = [];\n\n      if (valueType === 'object') {\n        value = {};\n      }\n\n      result.push(value);\n    }\n\n    return result;\n  },\n\n  // helper: make bruteforce match objects spanning i to j, inclusive.\n  makeBruteforceMatch(i, j) {\n    return {\n      pattern: 'bruteforce',\n      token: this.password.slice(i, +j + 1 || 9e9),\n      i,\n      j\n    };\n  },\n\n  // helper: considers whether a length-sequenceLength\n  // sequence ending at match m is better (fewer guesses)\n  // than previously encountered sequences, updating state if so.\n  update(match, sequenceLength) {\n    const k = match.j;\n    const estimatedMatch = estimateGuesses(match, this.password);\n    let pi = estimatedMatch.guesses;\n\n    if (sequenceLength > 1) {\n      // we're considering a length-sequenceLength sequence ending with match m:\n      // obtain the product term in the minimization function by multiplying m's guesses\n      // by the product of the length-(sequenceLength-1)\n      // sequence ending just before m, at m.i - 1.\n      pi *= this.optimal.pi[estimatedMatch.i - 1][sequenceLength - 1];\n    } // calculate the minimization func\n\n\n    let g = utils.factorial(sequenceLength) * pi;\n\n    if (!this.excludeAdditive) {\n      g += MIN_GUESSES_BEFORE_GROWING_SEQUENCE ** (sequenceLength - 1);\n    } // update state if new best.\n    // first see if any competing sequences covering this prefix,\n    // with sequenceLength or fewer matches,\n    // fare better than this sequence. if so, skip it and return.\n\n\n    let shouldSkip = false;\n    Object.keys(this.optimal.g[k]).forEach(competingPatternLength => {\n      const competingMetricMatch = this.optimal.g[k][competingPatternLength];\n\n      if (parseInt(competingPatternLength, 10) <= sequenceLength) {\n        if (competingMetricMatch <= g) {\n          shouldSkip = true;\n        }\n      }\n    });\n\n    if (!shouldSkip) {\n      // this sequence might be part of the final optimal sequence.\n      this.optimal.g[k][sequenceLength] = g;\n      this.optimal.m[k][sequenceLength] = estimatedMatch;\n      this.optimal.pi[k][sequenceLength] = pi;\n    }\n  },\n\n  // helper: evaluate bruteforce matches ending at passwordCharIndex.\n  bruteforceUpdate(passwordCharIndex) {\n    // see if a single bruteforce match spanning the passwordCharIndex-prefix is optimal.\n    let match = this.makeBruteforceMatch(0, passwordCharIndex);\n    this.update(match, 1);\n\n    for (let i = 1; i <= passwordCharIndex; i += 1) {\n      // generate passwordCharIndex bruteforce matches, spanning from (i=1, j=passwordCharIndex) up to (i=passwordCharIndex, j=passwordCharIndex).\n      // see if adding these new matches to any of the sequences in optimal[i-1]\n      // leads to new bests.\n      match = this.makeBruteforceMatch(i, passwordCharIndex);\n      const tmp = this.optimal.m[i - 1]; // eslint-disable-next-line no-loop-func\n\n      Object.keys(tmp).forEach(sequenceLength => {\n        const lastMatch = tmp[sequenceLength]; // corner: an optimal sequence will never have two adjacent bruteforce matches.\n        // it is strictly better to have a single bruteforce match spanning the same region:\n        // same contribution to the guess product with a lower length.\n        // --> safe to skip those cases.\n\n        if (lastMatch.pattern !== 'bruteforce') {\n          // try adding m to this length-sequenceLength sequence.\n          this.update(match, parseInt(sequenceLength, 10) + 1);\n        }\n      });\n    }\n  },\n\n  // helper: step backwards through optimal.m starting at the end,\n  // constructing the final optimal match sequence.\n  unwind(passwordLength) {\n    const optimalMatchSequence = [];\n    let k = passwordLength - 1; // find the final best sequence length and score\n\n    let sequenceLength = 0;\n    let g = 2e308;\n    const temp = this.optimal.g[k];\n    Object.keys(this.optimal.g[k]).forEach(candidateSequenceLength => {\n      const candidateMetricMatch = temp[candidateSequenceLength];\n\n      if (candidateMetricMatch < g) {\n        sequenceLength = parseInt(candidateSequenceLength, 10);\n        g = candidateMetricMatch;\n      }\n    });\n\n    while (k >= 0) {\n      const match = this.optimal.m[k][sequenceLength];\n      optimalMatchSequence.unshift(match);\n      k = match.i - 1;\n      sequenceLength -= 1;\n    }\n\n    return optimalMatchSequence;\n  }\n\n};\nvar scoring = {\n  // ------------------------------------------------------------------------------\n  // search --- most guessable match sequence -------------------------------------\n  // ------------------------------------------------------------------------------\n  //\n  // takes a sequence of overlapping matches, returns the non-overlapping sequence with\n  // minimum guesses. the following is a O(l_max * (n + m)) dynamic programming algorithm\n  // for a length-n password with m candidate matches. l_max is the maximum optimal\n  // sequence length spanning each prefix of the password. In practice it rarely exceeds 5 and the\n  // search terminates rapidly.\n  //\n  // the optimal \"minimum guesses\" sequence is here defined to be the sequence that\n  // minimizes the following function:\n  //\n  //    g = sequenceLength! * Product(m.guesses for m in sequence) + D^(sequenceLength - 1)\n  //\n  // where sequenceLength is the length of the sequence.\n  //\n  // the factorial term is the number of ways to order sequenceLength patterns.\n  //\n  // the D^(sequenceLength-1) term is another length penalty, roughly capturing the idea that an\n  // attacker will try lower-length sequences first before trying length-sequenceLength sequences.\n  //\n  // for example, consider a sequence that is date-repeat-dictionary.\n  //  - an attacker would need to try other date-repeat-dictionary combinations,\n  //    hence the product term.\n  //  - an attacker would need to try repeat-date-dictionary, dictionary-repeat-date,\n  //    ..., hence the factorial term.\n  //  - an attacker would also likely try length-1 (dictionary) and length-2 (dictionary-date)\n  //    sequences before length-3. assuming at minimum D guesses per pattern type,\n  //    D^(sequenceLength-1) approximates Sum(D^i for i in [1..sequenceLength-1]\n  //\n  // ------------------------------------------------------------------------------\n  mostGuessableMatchSequence(password, matches, excludeAdditive = false) {\n    scoringHelper.password = password;\n    scoringHelper.excludeAdditive = excludeAdditive;\n    const passwordLength = password.length; // partition matches into sublists according to ending index j\n\n    let matchesByCoordinateJ = scoringHelper.fillArray(passwordLength, 'array');\n    matches.forEach(match => {\n      matchesByCoordinateJ[match.j].push(match);\n    }); // small detail: for deterministic output, sort each sublist by i.\n\n    matchesByCoordinateJ = matchesByCoordinateJ.map(match => match.sort((m1, m2) => m1.i - m2.i));\n    scoringHelper.optimal = {\n      // optimal.m[k][sequenceLength] holds final match in the best length-sequenceLength\n      // match sequence covering the\n      // password prefix up to k, inclusive.\n      // if there is no length-sequenceLength sequence that scores better (fewer guesses) than\n      // a shorter match sequence spanning the same prefix,\n      // optimal.m[k][sequenceLength] is undefined.\n      m: scoringHelper.fillArray(passwordLength, 'object'),\n      // same structure as optimal.m -- holds the product term Prod(m.guesses for m in sequence).\n      // optimal.pi allows for fast (non-looping) updates to the minimization function.\n      pi: scoringHelper.fillArray(passwordLength, 'object'),\n      // same structure as optimal.m -- holds the overall metric.\n      g: scoringHelper.fillArray(passwordLength, 'object')\n    };\n\n    for (let k = 0; k < passwordLength; k += 1) {\n      matchesByCoordinateJ[k].forEach(match => {\n        if (match.i > 0) {\n          Object.keys(scoringHelper.optimal.m[match.i - 1]).forEach(sequenceLength => {\n            scoringHelper.update(match, parseInt(sequenceLength, 10) + 1);\n          });\n        } else {\n          scoringHelper.update(match, 1);\n        }\n      });\n      scoringHelper.bruteforceUpdate(k);\n    }\n\n    const optimalMatchSequence = scoringHelper.unwind(passwordLength);\n    const optimalSequenceLength = optimalMatchSequence.length;\n    let guesses = 0;\n\n    if (password.length === 0) {\n      guesses = 1;\n    } else {\n      guesses = scoringHelper.optimal.g[passwordLength - 1][optimalSequenceLength];\n    }\n\n    return {\n      password,\n      guesses,\n      guessesLog10: utils.log10(guesses),\n      sequence: optimalMatchSequence\n    };\n  }\n\n};\n\nexport default scoring;\n//# sourceMappingURL=scoring.esm.js.map\n","import { sorted } from '../helper.esm.js';\nimport Options from '../Options.esm.js';\n\nclass MatchDictionary {\n  constructor() {\n    this.rankedDictionaries = {};\n    this.rankedDictionaries = Options.rankedDictionaries;\n  }\n\n  match({\n    password\n  }) {\n    // rankedDictionaries variable is for unit testing purposes\n    const matches = [];\n    const passwordLength = password.length;\n    const passwordLower = password.toLowerCase();\n    Object.keys(this.rankedDictionaries).forEach( // @ts-ignore\n    dictionaryName => {\n      const rankedDict = this.rankedDictionaries[dictionaryName];\n\n      for (let i = 0; i < passwordLength; i += 1) {\n        for (let j = i; j < passwordLength; j += 1) {\n          if (passwordLower.slice(i, +j + 1 || 9e9) in rankedDict) {\n            const word = passwordLower.slice(i, +j + 1 || 9e9);\n            const rank = rankedDict[word]; // @ts-ignore\n\n            matches.push({\n              pattern: 'dictionary',\n              i,\n              j,\n              token: password.slice(i, +j + 1 || 9e9),\n              matchedWord: word,\n              rank,\n              dictionaryName,\n              reversed: false,\n              l33t: false\n            });\n          }\n        }\n      }\n    });\n    return sorted(matches);\n  }\n\n}\n\nexport default MatchDictionary;\n//# sourceMappingURL=Dictionary.esm.js.map\n","import { empty, translate, sorted } from '../helper.esm.js';\nimport Options from '../Options.esm.js';\nimport MatchDictionary from './Dictionary.esm.js';\n\n/*\n * -------------------------------------------------------------------------------\n *  date matching ----------------------------------------------------------------\n * -------------------------------------------------------------------------------\n */\n\nclass MatchL33t {\n  constructor() {\n    this.MatchDictionary = new MatchDictionary();\n  }\n\n  match({\n    password\n  }) {\n    const matches = [];\n    const enumeratedSubs = this.enumerateL33tSubs(this.relevantL33tSubtable(password, Options.l33tTable));\n\n    for (let i = 0; i < enumeratedSubs.length; i += 1) {\n      const sub = enumeratedSubs[i]; // corner case: password has no relevant subs.\n\n      if (empty(sub)) {\n        break;\n      }\n\n      const subbedPassword = translate(password, sub);\n      const matchedDictionary = this.MatchDictionary.match({\n        password: subbedPassword\n      });\n      matchedDictionary.forEach(match => {\n        const token = password.slice(match.i, +match.j + 1 || 9e9); // only return the matches that contain an actual substitution\n\n        if (token.toLowerCase() !== match.matchedWord) {\n          // subset of mappings in sub that are in use for this match\n          const matchSub = {};\n          Object.keys(sub).forEach(subbedChr => {\n            // @ts-ignore\n            const chr = sub[subbedChr];\n\n            if (token.indexOf(subbedChr) !== -1) {\n              matchSub[subbedChr] = chr;\n            }\n          });\n          const subDisplay = Object.keys(matchSub).map(k => `${k} -> ${matchSub[k]}`).join(', ');\n          matches.push({ ...match,\n            l33t: true,\n            token,\n            sub: matchSub,\n            subDisplay\n          });\n        }\n      });\n    } // filter single-character l33t matches to reduce noise.\n    // otherwise '1' matches 'i', '4' matches 'a', both very common English words\n    // with low dictionary rank.\n\n\n    return sorted(matches.filter(match => match.token.length > 1));\n  } // makes a pruned copy of l33t_table that only includes password's possible substitutions\n\n\n  relevantL33tSubtable(password, table) {\n    const passwordChars = {};\n    const subTable = {};\n    password.split('').forEach(char => {\n      passwordChars[char] = true;\n    });\n    Object.keys(table).forEach(letter => {\n      const subs = table[letter];\n      const relevantSubs = subs.filter(sub => sub in passwordChars);\n\n      if (relevantSubs.length > 0) {\n        subTable[letter] = relevantSubs;\n      }\n    });\n    return subTable;\n  } // returns the list of possible 1337 replacement dictionaries for a given password\n  // TODO set correct table type\n\n\n  enumerateL33tSubs(table) {\n    const tableKeys = Object.keys(table);\n    const subs = this.getSubs(tableKeys, [[]], table); // convert from assoc lists to dicts\n\n    return subs.map(sub => {\n      const subDict = {};\n      sub.forEach(([l33tChr, chr]) => {\n        subDict[l33tChr] = chr;\n      });\n      return subDict;\n    });\n  }\n\n  getSubs(keys, subs, table) {\n    if (!keys.length) {\n      return subs;\n    }\n\n    const firstKey = keys[0];\n    const restKeys = keys.slice(1);\n    const nextSubs = [];\n    table[firstKey].forEach(l33tChr => {\n      subs.forEach(sub => {\n        let dupL33tIndex = -1;\n\n        for (let i = 0; i < sub.length; i += 1) {\n          if (sub[i][0] === l33tChr) {\n            dupL33tIndex = i;\n            break;\n          }\n        }\n\n        if (dupL33tIndex === -1) {\n          // @ts-ignore\n          const subExtension = sub.concat([[l33tChr, firstKey]]);\n          nextSubs.push(subExtension);\n        } else {\n          const subAlternative = sub.slice(0);\n          subAlternative.splice(dupL33tIndex, 1); // @ts-ignore\n\n          subAlternative.push([l33tChr, firstKey]);\n          nextSubs.push(sub);\n          nextSubs.push(subAlternative);\n        }\n      });\n    });\n    const newSubs = this.dedup(nextSubs);\n\n    if (restKeys.length) {\n      return this.getSubs(restKeys, newSubs, table);\n    }\n\n    return newSubs;\n  }\n\n  dedup(subs) {\n    const deduped = [];\n    const members = {};\n    subs.forEach(sub => {\n      const assoc = sub.map((k, index) => [k, index]);\n      assoc.sort();\n      const label = assoc.map(([k, v]) => `${k},${v}`); // @ts-ignore\n\n      if (!(label in members)) {\n        // @ts-ignore\n        members[label] = true;\n        deduped.push(sub);\n      }\n    });\n    return deduped;\n  }\n\n}\n\nexport default MatchL33t;\n//# sourceMappingURL=L33t.esm.js.map\n","import { sorted } from '../helper.esm.js';\nimport MatchDictionary from './Dictionary.esm.js';\n\n/*\n * -------------------------------------------------------------------------------\n *  Dictionary reverse ----------------------------------------------------------------\n * -------------------------------------------------------------------------------\n */\n\nclass MatchDictionaryReverse {\n  constructor() {\n    this.MatchDictionary = new MatchDictionary();\n  }\n\n  match({\n    password\n  }) {\n    const passwordReversed = password.split('').reverse().join('');\n    const matches = this.MatchDictionary.match({\n      password: passwordReversed\n    }).map(match => ({ ...match,\n      token: match.token.split('').reverse().join(''),\n      reversed: true,\n      // map coordinates back to original string\n      i: password.length - 1 - match.j,\n      j: password.length - 1 - match.i\n    }));\n    return sorted(matches);\n  }\n\n}\n\nexport default MatchDictionaryReverse;\n//# sourceMappingURL=DictionaryReverse.esm.js.map\n","import { extend, sorted } from '../helper.esm.js';\nimport Options from '../Options.esm.js';\n\n/*\n * ------------------------------------------------------------------------------\n * spatial match (qwerty/dvorak/keypad and so on) -----------------------------------------\n * ------------------------------------------------------------------------------\n */\n\nclass MatchSpatial {\n  constructor() {\n    this.SHIFTED_RX = /[~!@#$%^&*()_+QWERTYUIOP{}|ASDFGHJKL:\"ZXCVBNM<>?]/;\n  }\n\n  match({\n    password\n  }) {\n    const matches = [];\n    Object.keys(Options.graphs).forEach(graphName => {\n      const graph = Options.graphs[graphName];\n      extend(matches, this.helper(password, graph, graphName));\n    });\n    return sorted(matches);\n  }\n\n  helper(password, graph, graphName) {\n    let shiftedCount;\n    const matches = [];\n    let i = 0;\n    const passwordLength = password.length;\n\n    while (i < passwordLength - 1) {\n      let j = i + 1;\n      let lastDirection = 0;\n      let turns = 0;\n\n      if (!graphName.includes('keypad') && this.SHIFTED_RX.test(password.charAt(i))) {\n        // initial character is shifted\n        shiftedCount = 1;\n      } else {\n        shiftedCount = 0;\n      } // eslint-disable-next-line no-constant-condition\n\n\n      while (true) {\n        const prevChar = password.charAt(j - 1);\n        const adjacents = graph[prevChar] || [];\n        let found = false;\n        let foundDirection = -1;\n        let curDirection = -1; // consider growing pattern by one character if j hasn't gone over the edge.\n\n        if (j < passwordLength) {\n          const curChar = password.charAt(j);\n          const adjacentsLength = adjacents.length;\n\n          for (let k = 0; k < adjacentsLength; k += 1) {\n            const adjacent = adjacents[k];\n            curDirection += 1;\n\n            if (adjacent) {\n              const adjacentIndex = adjacent.indexOf(curChar);\n\n              if (adjacentIndex !== -1) {\n                found = true;\n                foundDirection = curDirection;\n\n                if (adjacentIndex === 1) {\n                  // # index 1 in the adjacency means the key is shifted,\n                  // # 0 means unshifted: A vs a, % vs 5, etc.\n                  // # for example, 'q' is adjacent to the entry '2@'.\n                  // # @ is shifted w/ index 1, 2 is unshifted.\n                  shiftedCount += 1;\n                }\n\n                if (lastDirection !== foundDirection) {\n                  // # adding a turn is correct even in the initial\n                  // case when last_direction is null:\n                  // # every spatial pattern starts with a turn.\n                  turns += 1;\n                  lastDirection = foundDirection;\n                }\n\n                break;\n              }\n            }\n          }\n        } // if the current pattern continued, extend j and try to grow again\n\n\n        if (found) {\n          j += 1; // otherwise push the pattern discovered so far, if any...\n        } else {\n          // don't consider length 1 or 2 chains.\n          if (j - i > 2) {\n            // @ts-ignore\n            matches.push({\n              pattern: 'spatial',\n              i,\n              j: j - 1,\n              token: password.slice(i, j),\n              graph: graphName,\n              turns,\n              shiftedCount\n            });\n          } // ...and then start a new search for the rest of the password.\n\n\n          i = j;\n          break;\n        }\n      }\n    }\n\n    return matches;\n  }\n\n}\n\nexport default MatchSpatial;\n//# sourceMappingURL=Spatial.esm.js.map\n","import scoring from '../scoring.esm.js';\n\n/*\n *-------------------------------------------------------------------------------\n * repeats (aaa, abcabcabc) ------------------------------\n *-------------------------------------------------------------------------------\n */\n\nclass MatchRepeat {\n  match({\n    password,\n    omniMatch\n  }) {\n    const matches = [];\n    const greedy = /(.+)\\1+/g;\n    const lazy = /(.+?)\\1+/g;\n    const lazyAnchored = /^(.+?)\\1+$/;\n    let lastIndex = 0;\n\n    while (lastIndex < password.length) {\n      let match;\n      let baseToken = '';\n      greedy.lastIndex = lastIndex;\n      lazy.lastIndex = lastIndex;\n      const greedyMatch = greedy.exec(password);\n      const lazyMatch = lazy.exec(password);\n\n      if (greedyMatch == null) {\n        break;\n      }\n\n      if (lazyMatch && greedyMatch[0].length > lazyMatch[0].length) {\n        // greedy beats lazy for 'aabaab'\n        // greedy: [aabaab, aab]\n        // lazy:   [aa,     a]\n        match = greedyMatch; // greedy's repeated string might itself be repeated, eg.\n        // aabaab in aabaabaabaab.\n        // run an anchored lazy match on greedy's repeated string\n        // to find the shortest repeated string\n\n        const temp = lazyAnchored.exec(match[0]);\n\n        if (temp) {\n          baseToken = temp[1];\n        }\n      } else {\n        // lazy beats greedy for 'aaaaa'\n        // greedy: [aaaa,  aa]\n        // lazy:   [aaaaa, a]\n        match = lazyMatch;\n\n        if (match) {\n          baseToken = match[1];\n        }\n      }\n\n      if (match) {\n        const j = match.index + match[0].length - 1;\n        const baseAnalysis = scoring.mostGuessableMatchSequence(baseToken, omniMatch.match(baseToken));\n        const baseGuesses = baseAnalysis.guesses; // @ts-ignore\n\n        matches.push({\n          pattern: 'repeat',\n          i: match.index,\n          j,\n          token: match[0],\n          baseToken,\n          baseGuesses,\n          repeatCount: match[0].length / baseToken.length\n        });\n        lastIndex = j + 1;\n      }\n    }\n\n    return matches;\n  }\n\n}\n\nexport default MatchRepeat;\n//# sourceMappingURL=Repeat.esm.js.map\n","import { ALL_LOWER, ALL_UPPER, ALL_DIGIT } from '../data/const.esm.js';\n\n/*\n *-------------------------------------------------------------------------------\n * sequences (abcdef) ------------------------------\n *-------------------------------------------------------------------------------\n */\n\nclass MatchSequence {\n  constructor() {\n    this.MAX_DELTA = 5;\n  }\n\n  match({\n    password\n  }) {\n    /*\n     * Identifies sequences by looking for repeated differences in unicode codepoint.\n     * this allows skipping, such as 9753, and also matches some extended unicode sequences\n     * such as Greek and Cyrillic alphabets.\n     *\n     * for example, consider the input 'abcdb975zy'\n     *\n     * password: a   b   c   d   b    9   7   5   z   y\n     * index:    0   1   2   3   4    5   6   7   8   9\n     * delta:      1   1   1  -2  -41  -2  -2  69   1\n     *\n     * expected result:\n     * [(i, j, delta), ...] = [(0, 3, 1), (5, 7, -2), (8, 9, 1)]\n     */\n    const result = [];\n\n    if (password.length === 1) {\n      return [];\n    }\n\n    let i = 0;\n    let lastDelta = null;\n    const passwordLength = password.length;\n\n    for (let k = 1; k < passwordLength; k += 1) {\n      const delta = password.charCodeAt(k) - password.charCodeAt(k - 1);\n\n      if (lastDelta == null) {\n        lastDelta = delta;\n      }\n\n      if (delta !== lastDelta) {\n        const j = k - 1;\n        this.update({\n          i,\n          j,\n          delta: lastDelta,\n          password,\n          result\n        });\n        i = j;\n        lastDelta = delta;\n      }\n    }\n\n    this.update({\n      i,\n      j: passwordLength - 1,\n      delta: lastDelta,\n      password,\n      result\n    });\n    return result;\n  }\n\n  update({\n    i,\n    j,\n    delta,\n    password,\n    result\n  }) {\n    if (j - i > 1 || Math.abs(delta) === 1) {\n      const absoluteDelta = Math.abs(delta);\n\n      if (absoluteDelta > 0 && absoluteDelta <= this.MAX_DELTA) {\n        const token = password.slice(i, +j + 1 || 9e9); // TODO conservatively stick with roman alphabet size.\n        //  (this could be improved)\n\n        let sequenceName = 'unicode';\n        let sequenceSpace = 26;\n\n        if (ALL_LOWER.test(token)) {\n          sequenceName = 'lower';\n          sequenceSpace = 26;\n        } else if (ALL_UPPER.test(token)) {\n          sequenceName = 'upper';\n          sequenceSpace = 26;\n        } else if (ALL_DIGIT.test(token)) {\n          sequenceName = 'digits';\n          sequenceSpace = 10;\n        }\n\n        return result.push({\n          pattern: 'sequence',\n          i,\n          j,\n          token: password.slice(i, +j + 1 || 9e9),\n          sequenceName,\n          sequenceSpace,\n          ascending: delta > 0\n        });\n      }\n    }\n\n    return null;\n  }\n\n}\n\nexport default MatchSequence;\n//# sourceMappingURL=Sequence.esm.js.map\n","import { sorted } from '../helper.esm.js';\nimport { REGEXEN } from '../data/const.esm.js';\n\n/*\n * -------------------------------------------------------------------------------\n *  regex matching ---------------------------------------------------------------\n * -------------------------------------------------------------------------------\n */\n\nclass MatchRegex {\n  match({\n    password,\n    regexes = REGEXEN\n  }) {\n    const matches = []; // @ts-ignore\n\n    Object.keys(regexes).forEach(name => {\n      const regex = regexes[name];\n      regex.lastIndex = 0; // keeps regexMatch stateless\n\n      const regexMatch = regex.exec(password);\n\n      if (regexMatch) {\n        const token = regexMatch[0]; // @ts-ignore\n\n        matches.push({\n          pattern: 'regex',\n          token,\n          i: regexMatch.index,\n          j: regexMatch.index + regexMatch[0].length - 1,\n          regexName: name,\n          regexMatch\n        });\n      }\n    });\n    return sorted(matches);\n  }\n\n}\n\nexport default MatchRegex;\n//# sourceMappingURL=Regex.esm.js.map\n","import { sorted } from '../helper.esm.js';\nimport { REFERENCE_YEAR, DATE_MIN_YEAR, DATE_MAX_YEAR, DATE_SPLITS } from '../data/const.esm.js';\n\n/*\n * -------------------------------------------------------------------------------\n *  date matching ----------------------------------------------------------------\n * -------------------------------------------------------------------------------\n */\n\nclass MatchDate {\n  match({\n    password\n  }) {\n    /*\n     * a \"date\" is recognized as:\n     *   any 3-tuple that starts or ends with a 2- or 4-digit year,\n     *   with 2 or 0 separator chars (1.1.91 or 1191),\n     *   maybe zero-padded (01-01-91 vs 1-1-91),\n     *   a month between 1 and 12,\n     *   a day between 1 and 31.\n     *\n     * note: this isn't true date parsing in that \"feb 31st\" is allowed,\n     * this doesn't check for leap years, etc.\n     *\n     * recipe:\n     * start with regex to find maybe-dates, then attempt to map the integers\n     * onto month-day-year to filter the maybe-dates into dates.\n     * finally, remove matches that are substrings of other matches to reduce noise.\n     *\n     * note: instead of using a lazy or greedy regex to find many dates over the full string,\n     * this uses a ^...$ regex against every substring of the password -- less performant but leads\n     * to every possible date match.\n     */\n    const metric = candidate => Math.abs(candidate.year - REFERENCE_YEAR);\n\n    const matches = [];\n    const maybeDateNoSeparator = /^\\d{4,8}$/;\n    const maybeDateWithSeparator = /^(\\d{1,4})([\\s/\\\\_.-])(\\d{1,2})\\2(\\d{1,4})$/; // # dates without separators are between length 4 '1191' and 8 '11111991'\n\n    for (let i = 0; i <= Math.abs(password.length - 4); i += 1) {\n      for (let j = i + 3; j <= i + 7; j += 1) {\n        if (j >= password.length) {\n          break;\n        }\n\n        const token = password.slice(i, +j + 1 || 9e9);\n\n        if (maybeDateNoSeparator.exec(token)) {\n          const candidates = [];\n          const index = token.length;\n          const splittedDates = DATE_SPLITS[index]; // @ts-ignore\n\n          splittedDates.forEach(([k, l]) => {\n            const dmy = this.mapIntegersToDayMonthYear([parseInt(token.slice(0, k), 10), parseInt(token.slice(k, l), 10), parseInt(token.slice(l), 10)]);\n\n            if (dmy != null) {\n              candidates.push(dmy);\n            }\n          });\n\n          if (candidates.length > 0) {\n            /*\n             * at this point: different possible dmy mappings for the same i,j substring.\n             * match the candidate date that likely takes the fewest guesses: a year closest\n             * to 2000.\n             * (scoring.REFERENCE_YEAR).\n             *\n             * ie, considering '111504', prefer 11-15-04 to 1-1-1504\n             * (interpreting '04' as 2004)\n             */\n            let bestCandidate = candidates[0];\n            let minDistance = metric(candidates[0]);\n            candidates.slice(1).forEach(candidate => {\n              const distance = metric(candidate);\n\n              if (distance < minDistance) {\n                bestCandidate = candidate;\n                minDistance = distance;\n              }\n            }); // @ts-ignore\n\n            matches.push({\n              pattern: 'date',\n              token,\n              i,\n              j,\n              separator: '',\n              year: bestCandidate.year,\n              month: bestCandidate.month,\n              day: bestCandidate.day\n            });\n          }\n        }\n      }\n    } // # dates with separators are between length 6 '1/1/91' and 10 '11/11/1991'\n\n\n    for (let i = 0; i <= Math.abs(password.length - 6); i += 1) {\n      for (let j = i + 5; j <= i + 9; j += 1) {\n        if (j >= password.length) {\n          break;\n        }\n\n        const token = password.slice(i, +j + 1 || 9e9);\n        const regexMatch = maybeDateWithSeparator.exec(token);\n\n        if (regexMatch != null) {\n          const dmy = this.mapIntegersToDayMonthYear([parseInt(regexMatch[1], 10), parseInt(regexMatch[3], 10), parseInt(regexMatch[4], 10)]);\n\n          if (dmy != null) {\n            matches.push({\n              pattern: 'date',\n              token,\n              i,\n              j,\n              separator: regexMatch[2],\n              // @ts-ignore\n              year: dmy.year,\n              month: dmy.month,\n              day: dmy.day\n            });\n          }\n        }\n      }\n    }\n    /*\n     * matches now contains all valid date strings in a way that is tricky to capture\n     * with regexes only. while thorough, it will contain some unintuitive noise:\n     *\n     * '2015_06_04', in addition to matching 2015_06_04, will also contain\n     * 5(!) other date matches: 15_06_04, 5_06_04, ..., even 2015 (matched as 5/1/2020)\n     *\n     * to reduce noise, remove date matches that are strict substrings of others\n     */\n\n\n    const filteredMatches = matches.filter(match => {\n      let isSubmatch = false;\n      const matchesLength = matches.length;\n\n      for (let o = 0; o < matchesLength; o += 1) {\n        const otherMatch = matches[o];\n\n        if (match !== otherMatch) {\n          if (otherMatch.i <= match.i && otherMatch.j >= match.j) {\n            isSubmatch = true;\n            break;\n          }\n        }\n      }\n\n      return !isSubmatch;\n    });\n    return sorted(filteredMatches);\n  }\n\n  mapIntegersToDayMonthYear(integers) {\n    /*\n     * given a 3-tuple, discard if:\n     *   middle int is over 31 (for all dmy formats, years are never allowed in the middle)\n     *   middle int is zero\n     *   any int is over the max allowable year\n     *   any int is over two digits but under the min allowable year\n     *   2 integers are over 31, the max allowable day\n     *   2 integers are zero\n     *   all integers are over 12, the max allowable month\n     */\n    if (integers[1] > 31 || integers[1] <= 0) {\n      return null;\n    }\n\n    let over12 = 0;\n    let over31 = 0;\n    let under1 = 0;\n\n    for (let o = 0, len1 = integers.length; o < len1; o += 1) {\n      const int = integers[o];\n\n      if (int > 99 && int < DATE_MIN_YEAR || int > DATE_MAX_YEAR) {\n        return null;\n      }\n\n      if (int > 31) {\n        over31 += 1;\n      }\n\n      if (int > 12) {\n        over12 += 1;\n      }\n\n      if (int <= 0) {\n        under1 += 1;\n      }\n    }\n\n    if (over31 >= 2 || over12 === 3 || under1 >= 2) {\n      return null;\n    } // first look for a four digit year: yyyy + daymonth or daymonth + yyyy\n\n\n    const possibleYearSplits = [[integers[2], integers.slice(0, 2)], [integers[0], integers.slice(1, 3)]];\n    const possibleYearSplitsLength = possibleYearSplits.length;\n\n    for (let j = 0; j < possibleYearSplitsLength; j += 1) {\n      const [y, rest] = possibleYearSplits[j];\n\n      if (DATE_MIN_YEAR <= y && y <= DATE_MAX_YEAR) {\n        // @ts-ignore\n        const dm = this.mapIntegersToDayMonth(rest);\n\n        if (dm != null) {\n          return {\n            year: y,\n            month: dm.month,\n            day: dm.day\n          };\n        }\n        /*\n         * for a candidate that includes a four-digit year,\n         * when the remaining integers don't match to a day and month,\n         * it is not a date.\n         */\n\n\n        return null;\n      }\n    } // given no four-digit year, two digit years are the most flexible int to match, so\n    // try to parse a day-month out of integers[0..1] or integers[1..0]\n\n\n    for (let k = 0; k < possibleYearSplitsLength; k += 1) {\n      const [y, rest] = possibleYearSplits[k]; // @ts-ignore\n\n      const dm = this.mapIntegersToDayMonth(rest);\n\n      if (dm != null) {\n        return {\n          // @ts-ignore\n          year: this.twoToFourDigitYear(y),\n          month: dm.month,\n          day: dm.day\n        };\n      }\n    }\n\n    return null;\n  }\n\n  mapIntegersToDayMonth(integers) {\n    const temp = [integers, integers.slice().reverse()];\n\n    for (let i = 0; i < temp.length; i += 1) {\n      const data = temp[i];\n      const day = data[0];\n      const month = data[1];\n\n      if (day >= 1 && day <= 31 && month >= 1 && month <= 12) {\n        return {\n          day,\n          month\n        };\n      }\n    }\n\n    return null;\n  }\n\n  twoToFourDigitYear(year) {\n    if (year > 99) {\n      return year;\n    }\n\n    if (year > 50) {\n      // 87 -> 1987\n      return year + 1900;\n    } // 15 -> 2015\n\n\n    return year + 2000;\n  }\n\n}\n\nexport default MatchDate;\n//# sourceMappingURL=Date.esm.js.map\n","import { extend, sorted } from './helper.esm.js';\nimport MatchDictionary from './matching/Dictionary.esm.js';\nimport MatchL33t from './matching/L33t.esm.js';\nimport MatchDictionaryReverse from './matching/DictionaryReverse.esm.js';\nimport MatchSpatial from './matching/Spatial.esm.js';\nimport MatchRepeat from './matching/Repeat.esm.js';\nimport MatchSequence from './matching/Sequence.esm.js';\nimport MatchRegex from './matching/Regex.esm.js';\nimport MatchDate from './matching/Date.esm.js';\n\n/*\n * -------------------------------------------------------------------------------\n *  Omnimatch combine matchers ---------------------------------------------------------------\n * -------------------------------------------------------------------------------\n */\n\nclass Matching {\n  constructor() {\n    this.matchers = [MatchDictionary, MatchDictionaryReverse, MatchL33t, MatchSpatial, MatchRepeat, MatchSequence, MatchRegex, MatchDate];\n    this.options = {};\n  }\n\n  match(password) {\n    const matches = [];\n    this.matchers.forEach(Entry => {\n      const matcher = new Entry();\n      extend(matches, matcher.match({\n        password,\n        omniMatch: this\n      }));\n    });\n    return sorted(matches);\n  }\n\n}\n\nexport default Matching;\n//# sourceMappingURL=Matching.esm.js.map\n","import Options from './Options.esm.js';\n\n/*\n * -------------------------------------------------------------------------------\n *  Estimates time for an attacker ---------------------------------------------------------------\n * -------------------------------------------------------------------------------\n */\n\nclass TimeEstimates {\n  translate(displayStr, value, displayNum) {\n    let key = displayStr;\n\n    if (displayNum != null && displayNum !== 1) {\n      key += 's';\n    }\n\n    return Options.translations.timeEstimation[key].replace('{base}', value);\n  }\n\n  estimateAttackTimes(guesses) {\n    const crackTimesSeconds = {\n      onlineThrottling100PerHour: guesses / (100 / 3600),\n      onlineNoThrottling10PerSecond: guesses / 10,\n      offlineSlowHashing1e4PerSecond: guesses / 1e4,\n      offlineFastHashing1e10PerSecond: guesses / 1e10\n    };\n    const crackTimesDisplay = {};\n    Object.keys(crackTimesSeconds).forEach(scenario => {\n      const seconds = crackTimesSeconds[scenario];\n      crackTimesDisplay[scenario] = this.displayTime(seconds);\n    });\n    return {\n      crackTimesSeconds,\n      crackTimesDisplay,\n      score: this.guessesToScore(guesses)\n    };\n  }\n\n  guessesToScore(guesses) {\n    const DELTA = 5;\n\n    if (guesses < 1e3 + DELTA) {\n      // risky password: \"too guessable\"\n      return 0;\n    }\n\n    if (guesses < 1e6 + DELTA) {\n      // modest protection from throttled online attacks: \"very guessable\"\n      return 1;\n    }\n\n    if (guesses < 1e8 + DELTA) {\n      // modest protection from unthrottled online attacks: \"somewhat guessable\"\n      return 2;\n    }\n\n    if (guesses < 1e10 + DELTA) {\n      // modest protection from offline attacks: \"safely unguessable\"\n      // assuming a salted, slow hash function like bcrypt, scrypt, PBKDF2, argon, etc\n      return 3;\n    } // strong protection from offline attacks under same scenario: \"very unguessable\"\n\n\n    return 4;\n  }\n\n  displayTime(seconds) {\n    const minute = 60;\n    const hour = minute * 60;\n    const day = hour * 24;\n    const month = day * 31;\n    const year = month * 12;\n    const century = year * 100;\n    let displayNum = null;\n    let displayStr = 'centuries';\n    let base;\n\n    if (seconds < 1) {\n      displayNum = null;\n      displayStr = 'ltSecond';\n    } else if (seconds < minute) {\n      base = Math.round(seconds);\n      displayNum = base;\n      displayStr = 'second';\n    } else if (seconds < hour) {\n      base = Math.round(seconds / minute);\n      displayNum = base;\n      displayStr = 'minute';\n    } else if (seconds < day) {\n      base = Math.round(seconds / hour);\n      displayNum = base;\n      displayStr = 'hour';\n    } else if (seconds < month) {\n      base = Math.round(seconds / day);\n      displayNum = base;\n      displayStr = 'day';\n    } else if (seconds < year) {\n      base = Math.round(seconds / month);\n      displayNum = base;\n      displayStr = 'month';\n    } else if (seconds < century) {\n      base = Math.round(seconds / year);\n      displayNum = base;\n      displayStr = 'year';\n    }\n\n    return this.translate(displayStr, base, displayNum);\n  }\n\n}\n\nexport default TimeEstimates;\n//# sourceMappingURL=TimeEstimates.esm.js.map\n","import Options from './Options.esm.js';\nimport { START_UPPER, ALL_UPPER_INVERTED } from './data/const.esm.js';\n\n/*\n * -------------------------------------------------------------------------------\n *  Generate feedback ---------------------------------------------------------------\n * -------------------------------------------------------------------------------\n */\n\nclass Feedback {\n  constructor() {\n    this.defaultFeedback = {\n      warning: '',\n      suggestions: []\n    };\n    this.setDefaultSuggestions();\n  }\n\n  setDefaultSuggestions() {\n    this.defaultFeedback.suggestions.push(Options.translations.suggestions.useWords, Options.translations.suggestions.noNeed);\n  }\n\n  getFeedback(score, sequence) {\n    if (sequence.length === 0) {\n      return this.defaultFeedback;\n    }\n\n    if (score > 2) {\n      return {\n        warning: '',\n        suggestions: []\n      };\n    }\n\n    let longestMatch = sequence[0];\n    const slicedSequence = sequence.slice(1);\n    slicedSequence.forEach(match => {\n      if (match.token.length > longestMatch.token.length) {\n        longestMatch = match;\n      }\n    });\n    let feedback = this.getMatchFeedback(longestMatch, sequence.length === 1);\n    const extraFeedback = Options.translations.suggestions.anotherWord;\n\n    if (feedback !== null && feedback !== undefined) {\n      feedback.suggestions.unshift(extraFeedback);\n\n      if (feedback.warning == null) {\n        feedback.warning = '';\n      }\n    } else {\n      feedback = {\n        warning: '',\n        suggestions: [extraFeedback]\n      };\n    }\n\n    return feedback;\n  }\n\n  getMatchFeedback(match, isSoleMatch) {\n    let warning;\n\n    switch (match.pattern) {\n      case 'dictionary':\n        return this.getDictionaryMatchFeedback(match, isSoleMatch);\n\n      case 'spatial':\n        warning = Options.translations.warnings.keyPattern;\n\n        if (match.turns === 1) {\n          warning = Options.translations.warnings.straightRow;\n        }\n\n        return {\n          warning,\n          suggestions: [Options.translations.suggestions.longerKeyboardPattern]\n        };\n\n      case 'repeat':\n        warning = Options.translations.warnings.extendedRepeat;\n\n        if (match.baseToken.length === 1) {\n          warning = Options.translations.warnings.simpleRepeat;\n        }\n\n        return {\n          warning,\n          suggestions: [Options.translations.suggestions.repeated]\n        };\n\n      case 'sequence':\n        return {\n          warning: Options.translations.warnings.sequences,\n          suggestions: [Options.translations.suggestions.sequences]\n        };\n\n      case 'regex':\n        if (match.regexName === 'recentYear') {\n          return {\n            warning: Options.translations.warnings.recentYears,\n            suggestions: [Options.translations.suggestions.recentYears, Options.translations.suggestions.associatedYears]\n          };\n        }\n\n        break;\n\n      case 'date':\n        return {\n          warning: Options.translations.warnings.dates,\n          suggestions: [Options.translations.suggestions.dates]\n        };\n\n      default:\n        return {\n          warning: '',\n          suggestions: []\n        };\n    }\n\n    return {\n      warning: '',\n      suggestions: []\n    };\n  }\n\n  getDictionaryMatchFeedback(match, isSoleMatch) {\n    let warning = '';\n    const suggestions = [];\n    const word = match.token;\n    const dictName = match.dictionaryName;\n\n    if (dictName === 'passwords') {\n      if (isSoleMatch && !match.l33t && !match.reversed) {\n        if (match.rank <= 10) {\n          warning = Options.translations.warnings.topTen;\n        } else if (match.rank <= 100) {\n          warning = Options.translations.warnings.topHundred;\n        } else {\n          warning = Options.translations.warnings.common;\n        }\n      } else if (match.guessesLog10 <= 4) {\n        warning = Options.translations.warnings.similarToCommon;\n      }\n    } else if (dictName.includes('wikipedia')) {\n      if (isSoleMatch) {\n        warning = Options.translations.warnings.wordByItself;\n      }\n    } else if (dictName === 'lastnames' || dictName.toLowerCase().includes('firstnames')) {\n      if (isSoleMatch) {\n        warning = Options.translations.warnings.namesByThemselves;\n      } else {\n        warning = Options.translations.warnings.commonNames;\n      }\n    }\n\n    if (word.match(START_UPPER)) {\n      suggestions.push(Options.translations.suggestions.capitalization);\n    } else if (word.match(ALL_UPPER_INVERTED) && word.toLowerCase() !== word) {\n      suggestions.push(Options.translations.suggestions.allUppercase);\n    }\n\n    if (match.reversed && match.token.length >= 4) {\n      suggestions.push(Options.translations.suggestions.reverseWords);\n    }\n\n    if (match.l33t) {\n      suggestions.push(Options.translations.suggestions.l33t);\n    }\n\n    return {\n      warning,\n      suggestions\n    };\n  }\n\n}\n\nexport default Feedback;\n//# sourceMappingURL=Feedback.esm.js.map\n","import Options from './Options.esm.js';\nimport scoring from './scoring.esm.js';\nimport Matching from './Matching.esm.js';\nimport TimeEstimates from './TimeEstimates.esm.js';\nimport Feedback from './Feedback.esm.js';\n\nconst time = () => new Date().getTime();\n\nvar index = ((password, options = {}) => {\n  Options.setOptions(options);\n  const feedback = new Feedback();\n  const matching = new Matching();\n  const timeEstimates = new TimeEstimates();\n  const start = time();\n  const matches = matching.match(password);\n  const matchSequence = scoring.mostGuessableMatchSequence(password, matches);\n  const calcTime = time() - start;\n  const attackTimes = timeEstimates.estimateAttackTimes(matchSequence.guesses);\n  return {\n    calcTime,\n    ...matchSequence,\n    ...attackTimes,\n    // @ts-ignore\n    feedback: feedback.getFeedback(attackTimes.score, matchSequence.sequence)\n  };\n});\n\nexport default index;\n//# sourceMappingURL=index.esm.js.map\n","'use strict';\n\nObject.defineProperty(exports, '__esModule', { value: true });\n\nvar base = {\n  8: \"Backspace\",\n  9: \"Tab\",\n  10: \"Enter\",\n  12: \"NumLock\",\n  13: \"Enter\",\n  16: \"Shift\",\n  17: \"Control\",\n  18: \"Alt\",\n  20: \"CapsLock\",\n  27: \"Escape\",\n  32: \" \",\n  33: \"PageUp\",\n  34: \"PageDown\",\n  35: \"End\",\n  36: \"Home\",\n  37: \"ArrowLeft\",\n  38: \"ArrowUp\",\n  39: \"ArrowRight\",\n  40: \"ArrowDown\",\n  44: \"PrintScreen\",\n  45: \"Insert\",\n  46: \"Delete\",\n  59: \";\",\n  61: \"=\",\n  91: \"Meta\",\n  92: \"Meta\",\n  106: \"*\",\n  107: \"+\",\n  108: \",\",\n  109: \"-\",\n  110: \".\",\n  111: \"/\",\n  144: \"NumLock\",\n  145: \"ScrollLock\",\n  160: \"Shift\",\n  161: \"Shift\",\n  162: \"Control\",\n  163: \"Control\",\n  164: \"Alt\",\n  165: \"Alt\",\n  173: \"-\",\n  186: \";\",\n  187: \"=\",\n  188: \",\",\n  189: \"-\",\n  190: \".\",\n  191: \"/\",\n  192: \"`\",\n  219: \"[\",\n  220: \"\\\\\",\n  221: \"]\",\n  222: \"'\"\n};\n\nvar shift = {\n  48: \")\",\n  49: \"!\",\n  50: \"@\",\n  51: \"#\",\n  52: \"$\",\n  53: \"%\",\n  54: \"^\",\n  55: \"&\",\n  56: \"*\",\n  57: \"(\",\n  59: \":\",\n  61: \"+\",\n  173: \"_\",\n  186: \":\",\n  187: \"+\",\n  188: \"<\",\n  189: \"_\",\n  190: \">\",\n  191: \"?\",\n  192: \"~\",\n  219: \"{\",\n  220: \"|\",\n  221: \"}\",\n  222: \"\\\"\"\n};\n\nvar mac = typeof navigator != \"undefined\" && /Mac/.test(navigator.platform);\nvar ie = typeof navigator != \"undefined\" && /MSIE \\d|Trident\\/(?:[7-9]|\\d{2,})\\..*rv:(\\d+)/.exec(navigator.userAgent);\n\n// Fill in the digit keys\nfor (var i = 0; i < 10; i++) base[48 + i] = base[96 + i] = String(i);\n\n// The function keys\nfor (var i = 1; i <= 24; i++) base[i + 111] = \"F\" + i;\n\n// And the alphabetic keys\nfor (var i = 65; i <= 90; i++) {\n  base[i] = String.fromCharCode(i + 32);\n  shift[i] = String.fromCharCode(i);\n}\n\n// For each code that doesn't have a shift-equivalent, copy the base name\nfor (var code in base) if (!shift.hasOwnProperty(code)) shift[code] = base[code];\n\nfunction keyName(event) {\n  // On macOS, keys held with Shift and Cmd don't reflect the effect of Shift in `.key`.\n  // On IE, shift effect is never included in `.key`.\n  var ignoreKey = mac && event.metaKey && event.shiftKey && !event.ctrlKey && !event.altKey ||\n      ie && event.shiftKey && event.key && event.key.length == 1 ||\n      event.key == \"Unidentified\";\n  var name = (!ignoreKey && event.key) ||\n    (event.shiftKey ? shift : base)[event.keyCode] ||\n    event.key || \"Unidentified\";\n  // Edge sometimes produces wrong names (Issue #3)\n  if (name == \"Esc\") name = \"Escape\";\n  if (name == \"Del\") name = \"Delete\";\n  // https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/8860571/\n  if (name == \"Left\") name = \"ArrowLeft\";\n  if (name == \"Up\") name = \"ArrowUp\";\n  if (name == \"Right\") name = \"ArrowRight\";\n  if (name == \"Down\") name = \"ArrowDown\";\n  return name\n}\n\nexports.base = base;\nexports.keyName = keyName;\nexports.shift = shift;\n"],"names":[],"sourceRoot":""}