# Path: exactonline/http.py
# class HTTPError(request.HTTPError):
#     """
#     Override the original HTTPError, drop the fp and add a response and
#     add request method and data.
#     """
#     def __init__(self, url, code, msg, hdrs, response, reqmethod, reqdata):
#         request.HTTPError.__init__(self, url, code, msg, hdrs, None)
#         self.url = url
#         self.response = response        # in
#         self.reqmethod = reqmethod
#         self.reqdata = reqdata or ''    # out
# 
#     @staticmethod
#     def clean_and_trim(value):
#         if not isinstance(value, str):
#             value = value.decode('utf-8', 'replace')
#         value = value[0:1023] + ('', '...')[len(value) > 1023]
#         value = ''.join(
#             ('?', i)[0x20 <= ord(i) <= 0x7F or i in '\t\n\r'] for i in value)
#         return value
# 
#     def get_content_type(self):
#         try:
#             # self.hdrs is a ???
#             type_ = str(self.hdrs.type)
#         except AttributeError:
#             # self.hdrs is a HTTPMessage
#             type_ = '|'.join(
#                 i[1] for i in self.hdrs.items()
#                 if i[0].lower() == 'content-type')
#         return type_
# 
#     def format_req(self):
#         return '%s %s\nContent-Length: %s\n\n%s' % (
#             self.reqmethod, self.url, len(self.reqdata),
#             self.clean_and_trim(self.reqdata))
# 
#     def format_resp(self):
#         return '<RESP> %s %s\nContent-Type: %s\nContent-Length: %s\n\n%s' % (
#             self.code, self.msg, self.get_content_type(), len(self.response),
#             self.clean_and_trim(self.response))
# 
#     def __str__(self):
#         return (
#             'HTTPError: %(msg)s%(sep)s\n%(out)s%(sep)s\n%(in)s%(sep)s' % {
#                 'msg': self.msg, 'out': self.format_req(),
#                 'in': self.format_resp(), 'sep': '\n' + ('-' * 71)})


from time import time
from ..http import HTTPError
    > Use your refresh token to get a new access token before it
    > expires. If you make an API call with an expired access token, your
    > call will be rejected with response code 401 and reason
    >
    > **Do not request a new access token too early**
    > You should only request a new token right before it expires. You
    > can only request a new access token 9 minutes and 30 seconds after
    > you received it. If you request an access token before the 9 minutes
    > and 30 seconds have passed, your call will be rejected with response
    > code 401 and reason Access Token not expired.

    Apparently waiting for a 401 is frowned upon. So instead we'll wait
    until there are fewer than 30 seconds left and then ask for a new
    token.

    If we still get a 401, we'll _also_ do a token refresh and hope that the
    disagreement between us and the server gets resolved.
    """
    def rest(self, request):
        # Check how much time we have left, and refresh token 30 seconds before
        # it expires.
        have_fresh_token = False
        token_expiry = self.storage.get_access_expiry()
        time_left_before_expiry = (token_expiry - time())
        if time_left_before_expiry < 30:
            self.refresh_token()
            have_fresh_token = True

        try:
            decoded = super(Autorefresh, self).rest(request)

# Path: exactonline/http.py
# class HTTPError(request.HTTPError):
#     """
#     Override the original HTTPError, drop the fp and add a response and
#     add request method and data.
#     """
#     def __init__(self, url, code, msg, hdrs, response, reqmethod, reqdata):
#         request.HTTPError.__init__(self, url, code, msg, hdrs, None)
#         self.url = url
#         self.response = response        # in
#         self.reqmethod = reqmethod
#         self.reqdata = reqdata or ''    # out
# 
#     @staticmethod
#     def clean_and_trim(value):
#         if not isinstance(value, str):
#             value = value.decode('utf-8', 'replace')
#         value = value[0:1023] + ('', '...')[len(value) > 1023]
#         value = ''.join(
#             ('?', i)[0x20 <= ord(i) <= 0x7F or i in '\t\n\r'] for i in value)
#         return value
# 
#     def get_content_type(self):
#         try:
#             # self.hdrs is a ???
#             type_ = str(self.hdrs.type)
#         except AttributeError:
#             # self.hdrs is a HTTPMessage
#             type_ = '|'.join(
#                 i[1] for i in self.hdrs.items()
#                 if i[0].lower() == 'content-type')
#         return type_
# 
#     def format_req(self):
#         return '%s %s\nContent-Length: %s\n\n%s' % (
#             self.reqmethod, self.url, len(self.reqdata),
#             self.clean_and_trim(self.reqdata))
# 
#     def format_resp(self):
#         return '<RESP> %s %s\nContent-Type: %s\nContent-Length: %s\n\n%s' % (
#             self.code, self.msg, self.get_content_type(), len(self.response),
#             self.clean_and_trim(self.response))
# 
#     def __str__(self):
#         return (
#             'HTTPError: %(msg)s%(sep)s\n%(out)s%(sep)s\n%(in)s%(sep)s' % {
#                 'msg': self.msg, 'out': self.format_req(),
#                 'in': self.format_resp(), 'sep': '\n' + ('-' * 71)})


# Path: exactonline/api/autorefresh.py
from time import time
from ..http import HTTPError

    > Use your refresh token to get a new access token before it
    > expires. If you make an API call with an expired access token, your
    > call will be rejected with response code 401 and reason
    >
    > **Do not request a new access token too early**
    > You should only request a new token right before it expires. You
    > can only request a new access token 9 minutes and 30 seconds after
    > you received it. If you request an access token before the 9 minutes
    > and 30 seconds have passed, your call will be rejected with response
    > code 401 and reason Access Token not expired.

    Apparently waiting for a 401 is frowned upon. So instead we'll wait
    until there are fewer than 30 seconds left and then ask for a new
    token.

    If we still get a 401, we'll _also_ do a token refresh and hope that the
    disagreement between us and the server gets resolved.
    """
    def rest(self, request):
        # Check how much time we have left, and refresh token 30 seconds before
        # it expires.
        have_fresh_token = False
        token_expiry = self.storage.get_access_expiry()
        time_left_before_expiry = (token_expiry - time())
        if time_left_before_expiry < 30:
            self.refresh_token()
            have_fresh_token = True

        try:
            decoded = super(Autorefresh, self).rest(request)

        except HTTPError as e: