7.9
  
   …Þ358äÁç f    …<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html><head>
<title>403 Forbidden</title>
</head><body>
<h1>Forbidden</h1>
<p>You don't have permission to access this resource.</p>
<p>Additionally, a 403 Forbidden
error was encountered while trying to use an ErrorDocument to handle the request.</p>
</body></html>
  #   ‡ˆl–Ým_JJeJu@½p!¸ËŠbÑ¿ê„tM	¯Âè ?÷     ‡"""passlib.totp -- TOTP / RFC6238 / Google Authenticator utilities."""
#=============================================================================
# imports
#=============================================================================
from __future__ import absolute_import, division, print_function
from passlib.utils.compat import PY3
# core
import base64
import collections
import calendar
import json
import logging; log = logging.getLogger(__name__)
import math
import struct
import sys
import time as _time
import re
if PY3:
    from urllib.parse import urlparse, parse_qsl, quote, unquote
else:
    from urllib import quote, unquote
    from urlparse import urlparse, parse_qsl
from warnings import warn
# site
try:
    # TOTP encrypted keys only supported if cryptography (https://cryptography.io) is installed
    from cryptography.hazmat.backends import default_backend as _cg_default_backend
    import cryptography.hazmat.primitives.ciphers.algorithms
    import cryptography.hazmat.primitives.ciphers.modes
    from cryptography.hazmat.primitives import ciphers as _cg_ciphers
    del cryptography
except ImportError:
    log.debug("can't import 'cryptography' package, totp encryption disabled")
    _cg_ciphers = _cg_default_backend = None
# pkg
from passlib import exc
from passlib.exc import TokenError, MalformedTokenError, InvalidTokenError, UsedTokenError
from passlib.utils import (to_unicode, to_bytes, consteq,
                           getrandbytes, rng, SequenceMixin, xor_bytes, getrandstr)
from passlib.utils.binary import BASE64_CHARS, b32encode, b32decode
from passlib.utils.compat import (u, unicode, native_string_types, bascii_to_str, int_types, num_types,
                                  irange, byte_elem_value, UnicodeIO, suppress_cause)
from passlib.utils.decor import hybrid_method, memoized_property
from passlib.crypto.digest import lookup_hash, compile_hmac, pbkdf2_hmac
from passlib.hash import pbkdf2_sha256
# local
__all__ = [
    # frontend classes
    "AppWallet",
    "TOTP",

    # errors (defined in passlib.exc, but exposed here for convenience)
    "TokenError",
        "MalformedTokenError",
        "InvalidTokenError",
        "UsedTokenError",

    # internal helper classes
    "TotpToken",
    "TotpMatch",
]

#=============================================================================
# HACK: python < 2.7.4's urlparse() won't parse query strings unless the url scheme
#       is one of the schemes in the urlparse.uses_query list. 2.7 abandoned
#       this, and parses query if present, regardless of the scheme.
#       as a workaround for older versions, we add "otpauth" to the known list.
#       this was fixed by https://bugs.python.org/issue9374, in 2.7.4 release.
#=============================================================================
if sys.version_info < (2,7,4):
    from urlparse import uses_query
    if "otpauth" not in uses_query:
        uses_query.append("otpauth")
        log.debug("registered 'otpauth' scheme with urlparse.uses_query")
    del uses_query

#=============================================================================
# internal helpers
#=============================================================================

#-----------------------------------------------------------------------------
# token parsing / rendering helpers
#-----------------------------------------------------------------------------

#: regex used to clean whitespace from tokens & keys
_clean_re = re.compile(u(r"\s|[-=]"), re.U)

_chunk_sizes = [4,6,5]

def _get_group_size(klen):
    """
    helper for group_string() --
    calculates optimal size of grou