# Path: gw2copilot/utils.py
# def dict2js(varname, data):
#     """
#     Convert dict ``data`` to javascript source code for a javascript variable
#     named ``varname``.
# 
#     :param varname: name of the JS source variable
#     :type varname: str
#     :param data: dict to represent as an object
#     :type data: dict
#     :return: javascript source snippet
#     :rtype: str
#     """
#     return "var %s = %s;\n" % (
#         varname, json.dumps(data, sort_keys=True, indent=4)
#     )
# 
# def file_age(p):
#     """
#     Return the age of a file in seconds.
# 
#     :param p: path to the file
#     :type p: str
#     :return: file age in seconds
#     :rtype: float
#     """
#     return time.time() - os.stat(p).st_mtime
# 
# def extract_js_var(s, varname):
#     """
#     Given a string of javascript source code, extract the source of the given
#     variable name. Makes rather naive assumptions about correct formatting.
# 
#     :param s: original JS source string
#     :type s: str
#     :param varname: the variable name to get
#     :type v: str
#     :return: source of specified variable
#     :rtype: str
#     """
#     vname_re = re.compile('^var %s\s+=\s+{.*$' % varname)
#     src = ''
#     in_var = False
#     for line in s.split("\n"):
#         if not in_var and vname_re.match(line):
#             in_var = True
#             src += line + "\n"
#         elif in_var:
#             src += line + "\n"
#             if '};' in line:
#                 return src
#     raise Exception("Could not parse JS variable %s from source" % varname)
# 
# Path: gw2copilot/static_data.py

# 
# Path: gw2copilot/version.py
# VERSION = '0.1.0'
# 
# Path: gw2copilot/jsobj.py
# def read_js_object(code, use_unicode=False):
#     """Takes in code and returns a dictionary of assignments to object literals, e.g.
#         `var x = {y: 1, z: 2};`
#         returns {'x': {'y': 1, 'z': 2}}."""
#     def visit(node):
#         if isinstance(node, ast.Program):
#             d = {}
#             for child in node:
#                 if not isinstance(child, ast.VarStatement):
#                     raise ValueError("All statements should be var statements")
#                 key, val = visit(child)
#                 d[key] = val
#             return d
#         elif isinstance(node, ast.VarStatement):
#             return visit(node.children()[0])
#         elif isinstance(node, ast.VarDecl):
#             return visit(node.identifier), visit(node.initializer)
#         elif isinstance(node, ast.Object):
#             d = {}
#             for prop in node:
#                 key = visit(prop.left)
#                 value = visit(prop.right)
#                 d[key] = value
#             return d
#         elif isinstance(node, ast.BinOp):
#             # simple constant folding
#             if node.op == '+':
#                 if (isinstance(node.left, ast.String) and
#                         isinstance(node.right, ast.String)):
#                     return visit(node.left) + visit(node.right)
#                 elif (isinstance(node.left, ast.Number) and
#                         isinstance(node.right, ast.Number)):
#                     return visit(node.left) + visit(node.right)
#                 else:
#                     raise ValueError(
#                         'Cannot + on anything other than two literals')
#             else:
#                 raise ValueError("Cannot do operator '%s'" % node.op)
#         elif isinstance(node, ast.String):
#             s = node.value.strip('"').strip("'")
#             if use_unicode:
#                 us = s.decode('utf8')
#                 return unicodepoint.sub(unicode_replace, us)
#             else:
#                 return s
#         elif isinstance(node, ast.Array):
#             return [visit(x) for x in node]
#         elif isinstance(node, ast.Number):
#             try:
#                 i = int(node.value)
#                 if node.value == '%d' % i:
#                     return i
#             except Exception:
#                 pass
#             return float(node.value)
#         elif isinstance(node, ast.Boolean):
#             # properly handle boolean
#             if node.value.lower().startswith('t'):
#                 return True
#             return False
#         elif isinstance(node, ast.Null):
#             # properly handle null -> None
#             return None
#         elif isinstance(node, ast.Identifier):
#             return node.value
#         else:
#             raise Exception("Unhandled node: %r" % node)
#     return visit(Parser().parse(code))


import sys
import cStringIO
import logging
import requests
import os
import json
import urllib
import time
from base64 import b64encode
from PIL import Image
from StringIO import StringIO
from .utils import dict2js, file_age, extract_js_var
from .static_data import world_zones
from .version import VERSION
from .jsobj import read_js_object
            content += "// retrieved from %s\n" % url
            content += r.content
            self._cache_set('gw2timer', 'resource', content, extension='js',
                            raw=True)
        ##############
        # general.js #
        ##############
        url = 'https://raw.githubusercontent.com/Drant/GW2Timer/gh-pages/' \
              'data/general.js'
        cached = self._cache_get('gw2timer', 'general', extension='js',
                                 ttl=TTL_1DAY, raw=True)
        if cached is None:
            r = requests.get(url)
            if r.status_code != 200:
                logger.error("Error: GET %s returned status code %s", url,
                             r.status_code)
                return
            content = "// generated by gw2copilot %s at %s\n" % (
            VERSION, time.time())
            content += "// retrieved from %s\n" % url
            content += r.content
            self._cache_set('gw2timer', 'general', content, extension='js',
                            raw=True)
        ###########################
        # general.js travel paths #
        ###########################
        cached = self._cache_get('gw2timer', 'travel', extension='js',
                                 ttl=TTL_1DAY, raw=True)
        if cached is None:
            content = "// generated by gw2copilot %s at %s\n" % (

# Path: gw2copilot/utils.py
# def dict2js(varname, data):
#     """
#     Convert dict ``data`` to javascript source code for a javascript variable
#     named ``varname``.
# 
#     :param varname: name of the JS source variable
#     :type varname: str
#     :param data: dict to represent as an object
#     :type data: dict
#     :return: javascript source snippet
#     :rtype: str
#     """
#     return "var %s = %s;\n" % (
#         varname, json.dumps(data, sort_keys=True, indent=4)
#     )
# 
# def file_age(p):
#     """
#     Return the age of a file in seconds.
# 
#     :param p: path to the file
#     :type p: str
#     :return: file age in seconds
#     :rtype: float
#     """
#     return time.time() - os.stat(p).st_mtime
# 
# def extract_js_var(s, varname):
#     """
#     Given a string of javascript source code, extract the source of the given
#     variable name. Makes rather naive assumptions about correct formatting.
# 
#     :param s: original JS source string
#     :type s: str
#     :param varname: the variable name to get
#     :type v: str
#     :return: source of specified variable
#     :rtype: str
#     """
#     vname_re = re.compile('^var %s\s+=\s+{.*$' % varname)
#     src = ''
#     in_var = False
#     for line in s.split("\n"):
#         if not in_var and vname_re.match(line):
#             in_var = True
#             src += line + "\n"
#         elif in_var:
#             src += line + "\n"
#             if '};' in line:
#                 return src
#     raise Exception("Could not parse JS variable %s from source" % varname)
# 
# Path: gw2copilot/static_data.py

# 
# Path: gw2copilot/version.py
# VERSION = '0.1.0'
# 
# Path: gw2copilot/jsobj.py
# def read_js_object(code, use_unicode=False):
#     """Takes in code and returns a dictionary of assignments to object literals, e.g.
#         `var x = {y: 1, z: 2};`
#         returns {'x': {'y': 1, 'z': 2}}."""
#     def visit(node):
#         if isinstance(node, ast.Program):
#             d = {}
#             for child in node:
#                 if not isinstance(child, ast.VarStatement):
#                     raise ValueError("All statements should be var statements")
#                 key, val = visit(child)
#                 d[key] = val
#             return d
#         elif isinstance(node, ast.VarStatement):
#             return visit(node.children()[0])
#         elif isinstance(node, ast.VarDecl):
#             return visit(node.identifier), visit(node.initializer)
#         elif isinstance(node, ast.Object):
#             d = {}
#             for prop in node:
#                 key = visit(prop.left)
#                 value = visit(prop.right)
#                 d[key] = value
#             return d
#         elif isinstance(node, ast.BinOp):
#             # simple constant folding
#             if node.op == '+':
#                 if (isinstance(node.left, ast.String) and
#                         isinstance(node.right, ast.String)):
#                     return visit(node.left) + visit(node.right)
#                 elif (isinstance(node.left, ast.Number) and
#                         isinstance(node.right, ast.Number)):
#                     return visit(node.left) + visit(node.right)
#                 else:
#                     raise ValueError(
#                         'Cannot + on anything other than two literals')
#             else:
#                 raise ValueError("Cannot do operator '%s'" % node.op)
#         elif isinstance(node, ast.String):
#             s = node.value.strip('"').strip("'")
#             if use_unicode:
#                 us = s.decode('utf8')
#                 return unicodepoint.sub(unicode_replace, us)
#             else:
#                 return s
#         elif isinstance(node, ast.Array):
#             return [visit(x) for x in node]
#         elif isinstance(node, ast.Number):
#             try:
#                 i = int(node.value)
#                 if node.value == '%d' % i:
#                     return i
#             except Exception:
#                 pass
#             return float(node.value)
#         elif isinstance(node, ast.Boolean):
#             # properly handle boolean
#             if node.value.lower().startswith('t'):
#                 return True
#             return False
#         elif isinstance(node, ast.Null):
#             # properly handle null -> None
#             return None
#         elif isinstance(node, ast.Identifier):
#             return node.value
#         else:
#             raise Exception("Unhandled node: %r" % node)
#     return visit(Parser().parse(code))


# Path: gw2copilot/caching_api_client.py
import sys
import cStringIO
import logging
import requests
import os
import json
import urllib
import time
from base64 import b64encode
from PIL import Image
from StringIO import StringIO
from .utils import dict2js, file_age, extract_js_var
from .static_data import world_zones
from .version import VERSION
from .jsobj import read_js_object

            content += "// retrieved from %s\n" % url
            content += r.content
            self._cache_set('gw2timer', 'resource', content, extension='js',
                            raw=True)
        ##############
        # general.js #
        ##############
        url = 'https://raw.githubusercontent.com/Drant/GW2Timer/gh-pages/' \
              'data/general.js'
        cached = self._cache_get('gw2timer', 'general', extension='js',
                                 ttl=TTL_1DAY, raw=True)
        if cached is None:
            r = requests.get(url)
            if r.status_code != 200:
                logger.error("Error: GET %s returned status code %s", url,
                             r.status_code)
                return
            content = "// generated by gw2copilot %s at %s\n" % (
            VERSION, time.time())
            content += "// retrieved from %s\n" % url
            content += r.content
            self._cache_set('gw2timer', 'general', content, extension='js',
                            raw=True)
        ###########################
        # general.js travel paths #
        ###########################
        cached = self._cache_get('gw2timer', 'travel', extension='js',
                                 ttl=TTL_1DAY, raw=True)
        if cached is None:
            content = "// generated by gw2copilot %s at %s\n" % (

                VERSION, time.time())