#!/usr/bin/env python3

# compressor.py
from subprocess import Popen, PIPE

def compress(value):
    """Compresses a byte array with the xz binary"""

    process = Popen(["xz", "--compress", "--force"], stdin=PIPE, stdout=PIPE)
    return process.communicate(value)[0]

def decompress(value):
    """Decompresses a byte array with the xz binary"""

    process = Popen(["xz", "--decompress", "--stdout", "--force"],
                    stdin=PIPE, stdout=PIPE)
    return process.communicate(value)[0]

def compress_file(path):
    """Compress the file at 'path' with the xz binary"""

    process = Popen(["xz", "--compress", "--force", "--stdout", path], stdout=PIPE)
    return process.communicate()[0]

# compressor.py

import os
import sys
from optparse import OptionParser
from sys import argv
import base64
import json
from io import BytesIO

from os.path import basename
from errno import EPIPE
import lzma

def load():
    ppds_compressed = base64.b64decode(ppds_compressed_b64)
    ppds_decompressed = decompress(ppds_compressed)
    ppds = json.loads(ppds_decompressed.decode(encoding='ASCII'))
    return ppds

def ls():
    binary_name = basename(argv[0])
    ppds = load()
    for key, value in ppds.items():
        if key == 'ARCHIVE': continue
        for ppd in value[2]:
            try:
                print(ppd.replace('"', '"' + binary_name + ':', 1))
            except IOError as e:
                # Errors like broken pipes (program which takes the standard
                # output terminates before this program terminates) should not
                # generate a traceback.
                if e.errno == EPIPE: exit(0)
                raise

def cat(ppd):
    # Ignore driver's name, take only PPD's
    ppd = ppd.split(":")[-1]
    # Remove also the index
    ppd = "0/" + ppd[ppd.find("/")+1:]

    # Object for streaming decompression
    decompressor = lzma.LZMADecompressor()
    # size for one decompression i.e. ~20MB
    size = 20000000

    ppds = load()
    ppds['ARCHIVE'] = base64.b64decode(ppds['ARCHIVE'].encode('ASCII'))
    ppdtext=bytearray()

    if ppd in ppds:
        start = ppds[ppd][0]
        length = ppds[ppd][1]

        text = BytesIO(decompressor.decompress(ppds['ARCHIVE'],size))
        for i in range(int(start/size)):
            text = BytesIO(decompressor.decompress(ppds['ARCHIVE'],size))
        text.seek(start%size)

        if((size-(start%size)) < length):
            ppdtext.extend(text.read())
            length = length - (size-(start%size))
            text = BytesIO(decompressor.decompress(ppds['ARCHIVE'],size))
            while(size < length):
                ppdtext.extend(text.read())
                length = length - size
                text = BytesIO(decompressor.decompress(ppds['ARCHIVE'],size))
            ppdtext.extend(text.read(length))
        else:
            ppdtext.extend(text.read(length))
        
        return ppdtext

def main():
    usage = "usage: %prog list\n" \
            "       %prog cat URI"
    version = "%prog 1.1.1\n" \
              "Copyright (c) 2013 Vitor Baptista.\n" \
              "This is free software; see the source for copying conditions.\n" \
              "There is NO warranty; not even for MERCHANTABILITY or\n" \
              "FITNESS FOR A PARTICULAR PURPOSE."
    parser = OptionParser(usage=usage,
                          version=version)
    (options, args) = parser.parse_args()

    if len(args) == 0 or len(args) > 2:
        parser.error("incorrect number of arguments")

    if args[0].lower() == 'list':
        ls()
    elif args[0].lower() == 'cat':
        if not len(args) == 2:
            parser.error("incorrect number of arguments")
        ppd = cat(args[1])
        if not ppd:
            parser.error("Printer '%s' does not have default driver!" % args[1])
        try:
            # avoid any assumption of encoding or system locale; just print the
            # bytes of the PPD as they are
            if sys.version_info.major < 3:
                sys.stdout.write(ppd)
            else:
                sys.stdout.buffer.write(ppd)
        except IOError as e:
            # Errors like broken pipes (program which takes the standard output
            # terminates before this program terminates) should not generate a
            # traceback.
            if e.errno == EPIPE: exit(0)
            raise
    else:
        parser.error("argument " + args[0] + " invalid")

# PPDs Archive
ppds_compressed_b64 = b"/Td6WFoAAATm1rRGBMDmaOmfASEBFgAAAAAAAAXGVTLgT+g0Xl0APYiCAxIiFj8XAv6uZb5HAuwiApdddccExweZ3Y/R4r1BsinlSUdAfwAyaEnnbvMNk6S2186Jk4mzE8GSz4+yAR48p0/Ld5PzZ1UKqR+GLFadg7q2XSQRnsMPP6zYNV8vWdXeWBRYyQKe6dYLfnz9k1fhMqwAZHNW/8r6irgVLktbWQqbvEArflddRQYxZS6sHMK+WZ4/glV2ScG4KiS81rBXkmym2LGkYmmG2AQm8jzqAaTxfTlyNxYEUUih9eYtu8WqAVOrsnFfWQ6bVm7HX6AaKH5wVfk3SMKR8t9C2Ji7fn9vaVatSXlidhkvA5YtXv8vYGvy2wz4gBeKUR8sdmKBco9L4kzELfojr3PDFpZvU3YUf8VHlfW0Jxk1QIsFwIu3Zf3MgT7iUvBLow08i8KZYGzE8cnxlE7TFmf0LbTViQppVyFO7MfMYv7O5sz6iSlp/e+hWXaKryUsAAhC4awHPrO5kJXYOWeJ8QNUA/mOGXi31OL4VrVY61QfTW7/vcK5be2LBrQCja8TdAgdQqojGjz0t0onywo1xU6Msxow9OoMOHsKjzfXmp+4l6xH6LSrlKy/5KS40F5QVhHte2+wkgc4zMWof76/0Z7s1D6iwPqCa3Xc6IWzX/LtG0LkrSNbpLnrsgMSC3oLMnlf7vIV4vfMLs/sgfTroCoDeVlmr4D9lsq62lUrmDncD/F0CBmb5a8Ovt+nMiHe3oD3H1bURzb/QF5KHpkLxR3u2Y3iHjqN/+2N2ApajneP0Zq7APd2X5jSmAFZ3rhLm+Ay/XltelEpdHyNfbu0j0AHSbHJNWLLtheXve/rzf//KW34wYztNoaGl5CbgQQIEFkcw3YussnWzTBFMfvUUEKKBFWQbIQZlOqKqm0/6WuZNrz45AszPCbfQi+BSdva06dxwqD65qFWJ/laQh+QsZZhPw82S4CdfY7d4lNZgqf9rXcUXyrOcD6r7bJ7LV+2AnKy+3CRPKCjmE0BApVtmgNXLftQDMceMS1HwjP7weldYZQaqwa7+Mgn2heEpiC++aqsUqnioOjDcRvwGL2yJB2jJzv6NMF9JH/5TpVJhpho5iG/IFT8k9Lfvqjvi10s+uUgFDM8isVBrr+/u6BFZoQaMvkwF8V56WM1YF5By3dOTv9o+TYc2iZKs5Hd+kcDfm2N9DXCRigmVxhL0E6qCOukA9bH6z27J1sVYsaG8ZflP7X8JbojiKc19/2h/V4lY9ZyEWE56OSmgSKy7W2KYh4cSfpMkzHSSBn1Yh4x2+CjMnissR5k4QXBgtvUjLlut+gtWhVZIqHC/JvmLl/K6z8eQQMNpBIBMxnkN8ecwaDknu6mB2RpVyjtF/pSfkoDIMbDojV6h9dkF6Z0we+D3wQpH5OG2ODiSmxfpWb26tIKJB+DPObrvY7JGnti6VfamTxTHOkFk6Kno8JEsxEzqzeJU2ojAAhEMBeF1paBGJRihM1GPFKQmE+VY+0Md8lAbmZhfEdvhwAf2Sw8rPNA4uA50jQTWsRuJnrpnKviL4T+u6jGnQU+cAQGpnmq76BmBMAhVu0yJiWEPobPF7QIFSDdgVxp4/iusFhA5rBKIzTYfEtDYb/dCSFNFvWdgtV44cH2Iz2FChrVfMqsFjku5z727siwGA9Ru730Z1KXuPIRTQvqjgZHJ3xxktdGPcXLZSuJmGkukOc8NX+VQ3EBMT6Q9ScnwAzFxbWc/+ieHpv3A8U3hF0CjWl4Hq28k47d9U0TQIsfXlR7x0As/NCJSPMdhsAVL13XJPSm3gJCpUd/zItqRq11UIfXCdJ/09qS7Aa9Q6WDdpCKsnJJYZDVzsWXMyOzTTlwBuSRrbjJzm/zvLnodGzbPRA+8OV15ElGEK/j/R+dpM3RcxTOqQSSUVSFCv14zEtLyz8RJQWOyuyl754PLQH+B76m+PWhyWfmUPKCPDPaz/W8piabP48CFtguGakaXxE0PLj7NtTn2fGr0yhPTAAo45R/bOHZL3QkSrFzfGqiKELdWhoHMg6/UR8vptwTHRXQym7fBw2ULf3bLqebkl0Zan2ZhKiD08L+xMgie1Ku4tXV/LdgVK6ZgvKx7rtiw4/+ZVVPt2lyfmxLs9NIAzzR5uw3CsW+bzavQhCmg5ZXJOaegaw08c7SE62g19J/0VJtKYx11ff0uOi2awz1tu0RdEgjpED1M3rxCq5slVDV5+3Yh/w33wPsmm8/1ECw1q7XRAg7/c4mFqorrhWbN5ZfAIm1WCtURD9kqQhrPlpKO4J9DqTiqtLb0LY8+ZvuBHI8/qZnMQGhVNQLtU73W5EcYmastSuKff6mxvcTGtf3oLqvH4LdasNu9wUQuuppvzcUnvH/o4Ob37Y5GGfF43mrH04/a0/7Gp4FMu40MyxYrIa+Nw5tjVboR9oeCVWG327DiomrUhOIAmliVAPYWWqm1s4cdiLHnE8usqPES5Va4wcp7QQmoy/d2gcmUK+iWp0R5ceCrhwR0Xd3rfQ6Lp6PmrQb96XXLKVM1E3j2g0WK7UGkjnOmO0ujoAupF9VfGgJKoUSlxsU51p3A9F/lnm8ZnUY3AtgXgS/Yaf6pSMtGsz45ipB/vgc/h0bAdaERAUJy/ndjBb5kYnS2UqVRQoTVb0R61nCx93U2D1cSx3zwsFy4P0b1vOc5stCmLFXcP1HqFF0r+IV+3CJFJssZDbwQJpuQeJvgwhnMFBaCcX7NbNfXqLdaeTgTK2MquV24BIOkZY7JqdjaouUJQXI3jeyz3ITsO84WPvRGRDqD5WXZ/TTsCC4DBiqDjFXPpnrKFUJ6t0cKPpp4SkQQ903aYryOEvOBMhOJOSi724zOX2eVGKTJIJ1S0MWHGsNg/7hJgyDWMCYHmNGrN9An4JV2HnihTa+XKAukb7wDWm4UNpPQ6dgReFCtzcn261Jmh9ZykouKIeQyObPxeLbtqZMdqa8iD83VPQOowdiaq7O3yPfxVi4rVmCQFNPjn+h8o34i3LFsRc9mxC6TwrJ2+89bjQXFe2IUBPuFO9mxVZBNoq/F+BRxo0dTKABvPhWjjdSxCbfuUGoNXxmavt5nAzQ1jCma8KCEDb58EYmkRw+BEaiu+bFaQJPMiChJTduwVumT/OGuTRQdcAr5mDxNjHuogqvLqn0d3EjBrF15yRiHSGGJjtrHplpwwztjOMBvUDDlfsCpsv/qv60qzoGEEU6wrGEiTblyAhec7TlA0GXLhSuvx6TZpHmrq5F+xRzwspbQZbrrjboR7SZ6j+8L3P9G66pNa1TkKvl1wIK5ltvTAJ98CkE9l9ofhkXLIZb+sJPPVRQJEqmVJJZ3Q5rViuDIvFup0K7QAi+6LKOZl36O5ziuKZdNWgVrYF+x89Sm2+hdzJgUXBDX7h46TipwdPukNG0/hC7arFY+zF2RXen5WNNjigecUNWt4YzA0IXVyhtUBOgULQq9+2Z+SqTAz9HMFRTcHFK/Uaa1yZTKZFX2k3PQvHsfI6tzfNkKqt6LsOnHLt06D2XF940c6LINSJSD0Gkdn2iDrPGvqyanuZVSn6Krb8zMaxqxqx50Wka2s5B4eif5fv3EWP7JZxdxxcIwTLnugo13b8GxaaK48S15RL2E1z7Er3PByDEl4G4paR0gOPIb9V6OwvxsVJ3RyytmhpItOLZYp5AxfYLKKJQcZiGR8oVOMSvBzNRS6zYph1KKI9kx0j2lUL5v1KB/DSBtvnHa0iBBMuw3RiOa+xQ2Q86LDIl4CJjfT63lO8P89A1g0eAP+5iAHr97UOBK7eAS+N3yOZmSY2DAb9HQSFR/oPgza/E5PrXDMwP9BPXQebbKJzRi/YjrrXnkOntUDk8GLmAcdpqChPIPSRZJz0RXd7BOtQBdbsyfYZwWfqp+ObWtaJrXsk4kukGp1uILr+fWpaJo19o/j6a0SMWVLJhua3F5jrexb9GGHo9hTCRiXeCSFATO4JFGXLGdHu3xONU9WPzL7rYMBU1TsqFYA8J3IFNC3mV64HG+s03VYCSgB+4RpxbNt10GLijxItZ5WAMUevglacV+jaSxTHdYNmVglnn7rwsbKCyqrKJYwpeu4Hcpq/I4jzUTOpTaZZ3AhcQVDH2x+y9Jkf3RVq833PYTh8nB+9M3C+/iH/YIynMfe7trXAHF4zAl2TgVSJY/L5Cw/MykgDZ5G2raiYG2cLWUQMUQq48RD3WT1zsvVSjaDQXQm3pdmPqIU9FUVMNM7k9koBZWOquP4QMHC1FEVGh4ibHFXmuC7pG9nTjQAS2u1kbvglgsx84oFdP/MFMTTaxY+Gp76AHW2PImXJHjdxd5nHeWH6t0q+ghcBhtn2EtfkEP2Bn6USmE3gKTGxf2tbdyTx/nDrhLxiqmPYgVASsXoKvRTwqvut406CUY5SdtX9UKWbnssn7KiLs6VJ0oL4USd+fsRR8JdyWQlUZlmM+bRQ9ft6bgROTZSy4os+pEwwdVtKsGISp156KleuHif2P5zWXwVlx660zUgzsJpgi82GId2zVvb8fDgWJYEdT9S3tVL0E326EEm/fmK1fMeO9u9zeocQbinkzei6dduAtK95gWgV4pxx4VeMerlAJbtzjJqVajPI3wsGDbYv1mpZryxg2nH+/My+XrZ3KSW2S+xeLbeHnFZZTxfNOEFnGZ+7oXCeO8vxgfJsAxltejdWpD0eIhIgw4bk87YTpjuhG1KV+boc5jX+kRb+rW08aitntFN2hOFjf1CFKFU7ve9fJYQKRHAlS390ZoV+mlig8pNkJ0klzyNI2QolKL/MvzWOIQUd+YH19Ctrl73u5yEudg/dmsc5APCrdX9qm2ezk2s7axh7yMNv+JZrf/MwkK4Urudli5Lhc5fNrw748IQba7FbnbISLdQ9qQjvP1s7Qm6SpELkXWwf+hI6KzF0OuNxS9Xmz99wlQNWiniQkj+vgi433bwhRlhfWiDWvGLK5BNAT+wSb3E+yITYr7ZchsHbIZOlqgCJyWuQAHvzGi59J0xweL8HCYG32CWdFAdI7JSs/9dr3y6TCNk9qM9JsFsnDrc6l/ALpwa8/Azia+gFUDwegrxbvAbQqPHaMHOynjnjeyqkhkDkgJl2LLTNH7MUUS63yc6RBDWhXjs04XUv3wLIGpaIBxQgQ9xLxkC5G7Nm3AQzKY3CQRv4/jo+ylSSSGpJIYczefcZA0VBeduXAM4YwcynFDHMphe5JBPh+D1GuK9y5nqpOWuo+OL1TWSLmMkV15inQ/MrJ/+xVQR1rkp7o0wYZ7Ez74Z64kI7omwEffZpclhvSWCB/z2eISC9vEP1r/PsfdITyWubbAaOea7AkHWLgxGA4V3/xSJuJ2XsvAFFHeYoT4oCX0WB9FO91dphAODTt88gifa6PKpNn27ue70lGhMF+rI6SlqChx3sPMJQlFwe0TjPVVnJfz5MCDGRtpJEvRFi5KW5lQFVHU9vdjGc93pFWy2wGcqWzM1+FtFMc/T3y82GrxHE0QFsZ3aH9NHTO8NDaW5E942NtKfwaaYG1TJ/IhYxoH1VqsmaT6gdhnXxnrfknsEyomdL2O5ls5Nc5mgKCWi64xj6M3YwUMUo8t5RxRUhUPq4b2xjBQsGhipFhTGBT3WSXS527LQzAW8maKno2BzQUnF3hfBbio48tKuhxrTGHIDPE/kcJBSqBpyn/A8jXhwTCfwRNkCM901jWbyJL9I7Fv9zXiSdy+EGjfXVdRmPyP80FJ0xJvaurafARgktZDLsigemUar+iWsuauDvplOmxIYi2PQ0GrsdolTSb085HO3qJDoKkyJmX4Tc/iy7U1a0jHbNiADc2nlF9fs3oOAY2HINDzXyzAWITn0nun5GoPQvM0SgJUwfaliT662Qd5O1dpajRKHA1/fPl4K8kXuxYTcJYlcsC45UPTUqFj7CPVbKqRC816JiGlHU0d2PmgWI795Mp6o9qYQgvtn16unkHK29f25gQxMkIPTdtXVAd0a/6q3m6usMjL5XeXsI0AMGa7wsv1JZ76Kght5BCHW1SwzsoecZR3l5BSQBgKUZ7K67ofoGMu3G2P9uCD+YBTZGRFxcCq/L1ocmEG1xa4aUOkJdDcBiH0YYfMPQyVjNJ7URLk+PUSv4aV+6Ni1tVOfVerT+U22h6zkpIeNnne+LaYSUQoMEjt/Ze0HSjqyRNuhs7aqrJ5udWL9eJvJd0U/anxw2xcWX9nYcWRLA9lfoZWaNxb0f14F1kc2HutFkCxO/i8RMPOYQOmYrMhqGLmIoDxd8jn7BIDXcIQV7XP5YWmKhvZNB4CH2VtWx624JYvCq/2OREqJUNW/mDxD4xBtcZ05MPpe5/lB0PEpsW33aS1AnR1kAI0FLMq04gAkQFUBod1PWJU/iIpWNKGWtYZfQMeW/qTn+8NQCte79mf3vESiHGgdcu4DuVzjAYY8in6kqkWnRbBh0QdgnRy2PEHtzfWNf/k2fzjXFUKiwBm2qML4vOgxbpMqrG7llLZeU7qPfLYg5IzJSNnxagPzDTSA1e031VqJsjXC3Lbv8J1maNpUP2Zzwv9q/poN4quKm3VZ2NL1i3xPo2kibFuJhn1bvz7S8m90QWf87RMyzxyPzvnnH9gVXtX2sI4SIDZl6eJiENaK1jv6Q9oBfWo8FGIKypCF+4I1wvPf5EZyeuNx2xsb8OS9iSgANC98GpQVRAoKsctomgED6ojKYD54YY/siHdmfJguleX3EEtPpCaoltBQLy96ehffRxqA9fStLBXKq0Fi6sWae/CTPr//WFD60cFlIYJRWCG0Yzm4OlWBOvfbQKRmAfJ7g3XXrZu4MLxYortn+3ohoJ/C7lavOBekr05AR9/JUu1ZJv2o6nm+SzEwZzx/YnBcOjDo3FPh+52Ftu95+tc+hU/ihJNdXgi601eTwxo2WVIUKv0JdbnMfZ8fC+dLLfWOsbJ/LxcARcUMNoCOxgc86Q5kQGtNHWfdw6CUp00lq6jmmp1jYuFEGKWmcA8EGweMzytldHnTNnjCErXUbJibSRcCn+98P4Xnol4oOdl5Ke6VIymdl4tk3uVlixnqypZCsQa0TS+MKLkcyuqYFYLGyS11RwvWorqypKvfj5krltfXn9rk0hdOJp0PTljOv/y8Z7rk9T5anAVmVfiwslVKlb352khfUMctFuexcCO9qmZYnOX5WK+/lcmONg57hpX+WnjUZ0pa0gkpJMhPp8lstHlRm54NIzLkgKZzkuVjYdS4y6IRG6cdHk5q2tCuPeWDgtV6HKsodtaKDPc0UFPUHWemZDig387Tmog17isme+WxqOx4jnnpOgCNhsoUBPH38nUWooFvaWRVK/ih0oNb3aFQd7rRMWl8ZlIRhGKBiLzGScMt9Sss9NMkp9PE1ikPpbDit5UEwOCe+kYGeOHec9/x4bYudytVKoNhWDMHVr6OadKuCE8WO6aZ4uY/JhFeXQ+lZsCCAXTvN0ShdW4AOBA37sPCG+MK45YRcYRpGlS+CVny54Y3m/oJqS47ju8t/hPqxH+yZOHn057gtJL0gHBQiVPUjS8F0NL5eLUxbJGTGZROxzeAv6+C+A4+gDkN4RLU17EP3Wg0E0QCYYWePqToy7ql7ugviJGrKRHG/xe6TaroMPNDIlV1fBOBGazhPK6LfMWvnTRPRRb0jXfZD4J53LRvm1xECgP74okVZHiaq83LuCqEEnjDLjjl3kOwOzrgvyM05fk2KglCqw7pofN7CBcMe2BnKUFltugb12Rjsyyja/19NFtHIT9OHcEdveXLkW+riC6VXfdSsy+0MJLL9eZKidm23ETC3RfYOSSn33trIfoOQnj2CEia9iutb1GVFMIdCTATdeSW9timdpIr4LauKuVgNlK1zhNOZ6v+JccpmbL2jQzBqzBBiMi/99HxJ6phUo3t0OXzi3FIdn/QX8hIne06cce9SLyRGEbPPnEzV3gYoM9raRMWlPhP4oNeSjhvXXCaPgolWUiyIrdq0U2S5zkWfPOWsZ9MNijdtvR6uMnA7UxyKk2wzREIEcWL2tumBKdwPjRAnVW3a3wYBfDR+Qx+YCHZ0t8SaWZVLsFCLor9hJd1e1WnGgocX8qdEnV3nL5NclXysoVvjBf1M2yQJfmlX9vi4KGtwif8W5NFTd0D4fVJUfFdDgxMpDIAef9meVSYKpHLm79UKXe7wYzRFwLmKX5k47+TK7v0fWuTZn7dxAGzpANXvhmvGrLqXE9JYRlrC0vDE45jAxZtILUhSQaX0rpHrjUlI5Bt1QVuIk6Rv1gmm44OqlRapA7nrGVpxheRq31t6mx7pO/+VqJbDeGwcO6bj6RAfohzok+z7gj80P45swg7yNXMjIR9ckrijKfJ4C9BLu0Qv+on2bR2OzB1ki5pMThDaK6l5z8HbxSlvQ6wdeUyPWH3xKd9GkDohistrLTWXLxyPRuxsrfgTB4Zuz32vN5gbrBg84iito7Sw+d3ccxUFeorg2719ab3A4AeLBYsh9M7tgRLqNmGENjshMZuzbFu0gKbLb18EgtiNKznTT5XT9aWgiHTTCC0Jfbyn6/36F3z7Vbk2793zv6IhaQj941+MuENlwpaHCRM4hDG6DqM6EBAeBqB8SkIMEstoPoh190S+LLBaOIE6KyQjaL5f0r/YNSmJStJxqsia8zm9fTdUQV+vJwtF1xk/js0TZIKcSMr/72PmgFYzOgbtw/nN6mFGBTe77xt4p9g3wGphAM2oIP6uCXmmK5p+RQpcqVL7+ysVPikXZq+fghz98Xo7ghzVovoAEBNAVXPGMX0IEVR9jgAXrbrGtwXobnnLRV6CK9hmp7zilyu9rwhovJEqoiPnIXF3taJ8rl91j9phSdF+gmSPFjXJZYECzT0XbiBy+OU9i6kG+abOCKYNa0yKH0QEWm8h/q10eiqMb/UwHiqf6BKvS/j0iJWigXovMrrkV/KKsO53BepZnmAtlj2yv+DVlTH+bdYKdXPFsmWbBPYsvCiLYQfBU5GvVgUCTsFmVDGsFWii7rG7qHEwZomrIsSyv6YCsry1LIRcmDUBiwX0ePegd/3OvgQIWhTVQSo4jCeQy6rU5Iqfxb4d9l16NCgzkiHJv961WNuprjX658HJHmrHZhyGxt2WL+GkxGDsQMPCboQes6QINi07VE+XqAjY1L1z43iUMqANRpjjiwlqVX3ZaxYzV6V81DPilZs0KaADZjMEBKjXmluLY3euwmibBWUFQST28HoW8XZiCrfEZe1XqOwKMXF/Bs+NSGnv2T4Z/APk3aNhA51z8Q/2aHqjU6SML35upKqWkhBBsN8vP0IO9IvTe5RIzAKXK3pqplIZsa8vyG1zAZK7ElIdvcHAj3ZIfxOWMwc/haJKZs5w876ePNxWTwVyzNHmxJFrc3aquuOK/0/jJlb78Jhs7byIgOFkOVZ3g7G8Xob7H6yKpIuFhBny4kOIMS0ZVB2SrvJuGRBaz7OkfGZLOmi9FmxApKaIKFaVJl/H/rE+lz4GMh6ZfWGACD4e0cAIw46XAp48JVdn10wK81SrayZOMl/g50EzZKld/sB3SWA7Qz/i4dOOl4OPFrFSPYI0YYx2QideNMBDiHiysUPa0EDxWLP3OL9mmo3I3QJInV7fccLvmvdlopp73JBIu4HBUR6DLQN9+TxpHA7OmuV81u7cZ6sAkzf7g7SAE/KlHDgODQNMfmLYvdzAwt9BfYralyUdlM3Tze93vOLxxcnMD1BIPlC1CiMI9ATTRcLnaeZNrG11zt8Ir+nrW6ovHTgp1oUeOjeA9Xg5+8+G/hj2kFZXSSNL+1moJxh2R1XnWN7Ze8v0ko2yYPfRD3LZ9VvHJsxaUUhXjSKe6ObEWPkPPeqEVIhOo5tx7iGCIbWzO/UuFL1haKxArQX4NxYiC9IR3do3Po5FEMK2NQ49W1VS4R4ielWKAakrvfGymE4btDuUWkzy+JWxwNH+xpeZn0puAM3j5S1sY2Cv5DN8OkixydTvvPh9vylPE0gR/SNavBCzKclh65xjJ00O1KNcC0vHnGdDPBZY4nGk3gJE6o61zDsUDYCXDrYrcDWJIsJoa49KLQRLG6+PsNtpDXDIdrhwE6q/tvRdJkQQKUpxldTGRNlbnggewC0gv+rHL44xI9KpL9dblPK0S8m0Xm/Qych5ydZS9bbmPjAZskcRrX+MMhI41uZJ5ITsgT0pDaYl109nfVRFsi4Qev52K7orxBNp1FAW8VOcoe1kJjiAPgzwCRUD2fZxaQHWeFMnr/E/utWfen/1UhQknlcpxgYM1jXWM+7OX1TP5uqqgmiDH8q6ungZoeUtzkaKQZY6QJU5tovYAGqpEic6uJu91KwfJZqpEGALRm1csBu/UBFVrE2ELMrN7hHKJtomaOclM3QD0PnBti8jqkSAqK3R/In+kK8WZGHdIw3GJJUm7qsumTlK+MzXPDNsbxsomn4Ab1KX342Tiyqsr1quo+c7zwUbgqDPJljWvgiKlXM8EV3+TIqNvuCpmZ6beDsqCxja/+4x7IJPOHal+Ejn9puwibcmVhSanDnnDAwhpZTjJxXtsvMxWOv5rZhsvFvkx7WmeuxdRdVvux+uYl3dqFSmgyBbV3K39B+zohBohgeo+YsIeEIKmM8GLNmEGHb0EBgP40+5CMbMo07TSBxCvh8zVeuu9Pyms2aycA3V3GFQAAqrgZ06vd0h2NBBO7mWKnoru9UrOWVjg1rhGjNn4WRnRrwhJcO1oS3+9/vRod6ExMLhoo8e5Lh/oKxTpsSkph76KvHWnTXtqXxVoQ8fNLXzbp7KhCMmapKRzTGWXZi/XMWamgQgen7dAApt5eKBCaxcWir++3WZjG9019yM4xdNMwnGy849Se1eDweUZyMCcM14X5UNNK1xmVSnRWZ5ZTjGW+TztnUsMi3uz6bERn2u7xm78VU9eT1Mi5h/O6noXHMWXtLlyM2hrBRGcM2YEmuLz5NAUdenCmKAEQZVy/fDKxfj7qYn4QZB/EJCIYDBQJ0cu+6q2xeiqmqyCtbMdS12roq7gn1r/+YU5IhSmNC+jKdh/i+F1XvmNjzjAiHTyTRyqCxaBsjfzuN6qucTYHLG0vIeW33bwUsIZNO3CdEuG7v8sdDwD52DBfPR0G1xpOcMWREGWH+scZF7jDdefDJfqqLJNNnHDrLu+fKwHd1OzlRAT7oj19yj1z5AeD3zX5v4rzQ3XJlTeJUWrLh05YcymateXLx4QdS4Mb5mIEGt8XRKd01gB2gbwBMCc/j6RZxMAdh5sLOyl8QVBpaZ7iFnVZEPVyGyrMAbdaOKnIrU5YLXwdGFM6OcoJthGdG8N8F/UnQfPKfcm1Rh1JvnfBz5wFDXl4g3Lt16a+JbNZQB/Audk8Iru8OkYhfBajOa5KcObreP1Gv9NAli3eJjvA6cYbl+6568yLLdiWtFlfGabjpB3Mgu2szTParcjokGLnxiY5BCgzilnsosxeitgt0sB+1P+flPs2uGZeyb41IN6h2CukJyMt8MQFz5jd5Y5C8xD2ndt3Q0J/D1mYw5zlnrs13+3FiTHGj+neNds+oBYl38f/xQtP1iPKgIO8UHGpFPZxAHbqGi4OgO5eQeZUJh9b3yug8cVnS0SeiJNRU2Rd/Wc+2akM8aHudN8yPQDkOY9MKLkr4rMtoVVjxyMNyBsEEfnayuME18lJi0PoMRTpUhIWKoo1fiAdM7oPd1Yty2/PgYAt5SIT+VKKMB4ie57+weR6JGNoOPeyClTnGRpnC98k9l+ngRHzhWvuv/HI0HCHl+1xPMrtargZDpkcI1MqyeCaeLeS5fYxgXjbiQLUDKClyuQJxdcNI0pyEXKnADZWskHzpun/tbEzVJyCeMyZ5NF57XovURj5PvE31ZQ7fC/KfUqP6E2GgNCexR9MQoBQnJGACxILq0J/qAAQjQArxM5hTkhzPp5rbffquXgL25SYZWLZXwfOu7a8dpiwQ78v32yMLz6zdHmT4+3wpUO5V+GFaQnIJC7YZ5nkh2Yrn49jax6HEEk1gyUCXE7CSBdipTgSZsaY6MUKhQybzKa1gitLDAzAmb8cRLP42p1/1n/4QbhK4Hpx4OxsADmzmRnJT5EBTp7Q+Z0GVo5bAcBnfmtpo7lNrRUuVAbXOvOa4sE2AX0Iin5dHOxEtA6T+Ob5fd4Xl0PuCHXNcgL4rrW4tAMh8i8aZQxkH26N6XBHzSlsWa36W5fWZbvH5qhJJ498k9g56381qDqDnrKSmZVryvQyMfBO5FVwh21YD85QYSJK/U88jcHsqf0EWk4Kb2AqcRvWpO0IsjAdCdMYMMEo7ao0OozTzV5dFiIlAySDw1/x67cTTz7ALE8X/QcpURPfiMaVRRXt1T7srSxYVPBv0T1KlHvuergMDgqtW7ZFrS1fKTbueB9egZw3O7NStmraUxVzkOROOS+2rBp+AJqOf2adPI8BOi6s2FogH2SbYYxGUM56/kBoCqzMpznOn7wb/xUmFuJMGlVZrDODH3r1hm6x0261NpxLh3LLcoj/6taakSq2ggLcbSxhgK2UYg/GUCV2PzrMkkZ/cXdsw4ESEVc75SMCA1M8+RwnpTF5D2vLPRlHeCMxTJMm0EkFIEtjlsaA0DQv5BJaOn6oLeksEreX0WQZ/W+DdWJK7bqGVVI4kDPLdLpzy4FV9MkYbIdpLmuA8I8zukFjR2U3KTX+qYZS6ZYdxSTzgNljukCiG6sKVqwn0DiMxaiweGiF8tDFRPxj45HfNTLWPte9FxLzPB/zfrkbjMt26tFYqGQECs8PnUpMyeCgi5kCPHRmps5bzSZZNAid5Rd6v0LGTwEUbFEwOH+IIAaoJ6nlsEe/79lvMTlbbhyPVOnqZUwg3iVei3CLEuNJxhRYNnstiaTy93zqcSRc1RdBuqKsR6q2ARV9OBZ7sJFg89K8JzpyWlQUYoBxSK1e7RGQCnxw15d/WbptRXa0xRjmsmUF74iEkye2KU04WyP7rTLN38JgqPsrDTkT3zXD9pfPZnZYtEJnInQiMew8lhaf0NNHXk+giDtn9viBLIyacrj7uDZsHJpHkYFBMwNRNWhoELPapz/QZJqEGerRI+y4fembTleLd6YepF+1jVUMo/l8irt9RwlkBnIz0uQmfHhUB0Sg6lYI/l9AAm8CxyFnrWN7m8t+gixLbEd+rZM7OdJpwNIwi8vEDN/dCEvpGw1967cYWbxHcSaxr60NhOwmd9hr5SS/eEAwyeLarB/E216HDJrRlkVXjzjQzBS9vgyJvJkLtuB8rXmS29VYPPKO/XLH4DHjWa6VuUAZlVBWfAFlQGxbm1b0LiWcA/2piUymVdC8fAy7zFG4x49nqdf40PZBLUWMmEosOUJrx0hnO9XlxLq2NEde9Z3O55CBL0SeFj48tdfZdiNNF3qnYAdZEIZbvqHqo6xoCyQuszADfmLESVelyGW84w2/3fB0uWbkhafFtBd2YZ0UmM/0fHnUp/JD1d0lYR6xd1ar5FDco53vf6lHaPqswj0oYSBQC5ch2TDCLNrm8CAxF2ISKZPATV8qDJaNglsWrMh8yMGtnmO06xtjK1Xa1w6LZN1o0jd8yMBTpPKvPzMvrAyYGGVQn+OmU7kgmBNMuO22Ctg4ItGx1AiuXoQzcViF4OwRO2/w+2Dk8AW7b/+SM9wxMbm4XWyNqvARlXqk/dHCzYBFxJvqPQoUiC8GcTJHjo5lUTyR9owSUk//+wzTHGq79JAYFMrnB1IW+25UgS933T6MfX2yhjHNeKy8aQl8XlUT0x1aDBBNl1aKWpFZLTIeg/WFdKtmfV7ZR9LSDRuWXU0tDIJZyl1T02cEtVpjZBXD2zI2Xkat1PmbbvBZwlplXUNnTJw9xadZD3++wGiD1zXLxVx0zAHVTZz4VFe/oTOZWhLMVO9vdPZfLemGNHHE+TNbeznGWJ1qIbHwt4/fw7BztRTPH/FKFqGz31I+PPFSF6Fgz4l8k2tOMGd3BNnZQTyJBB024FLJObj6OdNJPSg+5Bor0VdADU9Yny7Hq9z+deg7NgxvIZkcEmIHYJSj7MkJgPsEuIz6/6dqkPuvhoVvNtJuuOq4cIUKBbVVll49q/r9EI2KZkk9XITAHsne6Kz9JKQ4wcG0ld8FiTa0CfBo2Dz3AQ0vsuFnbVYcByt5VtW5Tz8rTH3+Gdd9jRLOD/HEe59gWESbyG6Q1pLGQiGfX3QyW+nVc3VMRG9cUtL6KTLpSTwPSv+2Y/X5g3KUXqQVM2BT5sB1vxrWveqYxDbBe2egJfdz5XlGz6gxJ2iHqrvvCLSEj5Zr+bI7tkLCC0ys/1D/PsUiGiZHQHoZMVMPDZ9suBSIYbZUj34/02nv/pzbrWUCfUv5B2vcMBesgMDE+NI4QcJGiiP6lHHx/4lgOr3RUKjkDsv3f1clwH/7aixczTag/qnl12YC2Mozc217ofhW20wyYUB8UegRYA06YkNsyGdiV8pLYOZ0Qa6l4g2EBeB+Wu6cYst0zGKftpWJwIh7xHppKIvyMWhFZJPsNdN4Mv/apBJ6Legn2rv5IldZ0Ne/CmYiBUtigk/cEJ6WYcHgxetVDQswltR3hlcryRq29EohPk4EpQXNrHqVsLe8cmtrCd166jw67oKVJSuJwJCcZ47ua/Lgdgs/DO9xe13luiwrQYivCrBxyJio8SmbDTWtOLVdm+PLOIE2EVj/7njNwS7OXa5b3k247jjBkfe/BvKQkp7VtqViInIQxkdQU21y7kHXVx9rXeLRzk9Ss5fqvpM9KH459Bskc9lEGsMWg6LqoBvnqEuRDfUUjn2fD36RVfcJ9qcJmDuIx1BMQBsCQ2ddfjOwCtd6e04ZYpMrJL5pqgI9ANXb11ik39CKj46YTXNGMX2WasMf7aHoJhMo2gb1UzU+2dPPq2FzWtKZsy76ECSbDlQoo6ZmULyQrAZfKPAz3yKDXdkbNMQ7nmm/eSCPJTbmvnrLAJ2uLgO8F8y7AYM7TrU1hFQOzywkc/ZkhV77na1+CcWURRuRRwf1VZKn5sZdX3P/5cTAGln7NEtib0dZnyj+lenfbsPds3Rcjl8HdU1NLRRGAV0eb+g6DFY8pcisZnViPs3C9EMPm+cbKqeW5HhZTVV49Rn2OD54OSiNFfFpHeMW5b8AgLCgq6imRaxvukaP9j/EWbQR2flC3632eIVAazr4eLVnqfnup8w34aACGgC7TbjNQsRSWMzGH+w60PDyCZN4yZD8alDMiRHfGhHpmsD8Aoy30nz6R8xZDO2VnGqjjG+Evrk6zcApnWKqoDYnQaFa+46sxxZjgpbTF2AwIhr/lfcDxcWxzAtzTGczH2m64HpoaMtthq/+O7Nap7S0bmCglmtZRoV2tz2LvGnD02nHdYGqqa888HxmQM5cwYYjcavboHoBcYxXDXf7N1D3pBICeFW6IXyX1U0dZZHH/VMNCaeDpyRFxUjFVRykePJbcbHfS8Q8VXgkS/q2hyyRrZMKggJfnrTbpdLW7aCJERfSexVgvohTXiooaRVafgDVwWrSzCp7lStEjXxrg1rKWkrM7fdwoyOTZ31Gy+06SlgaKgP9m7GSRHS5Dn/WQuS+LFNrhAgueZxcSyLzHgiQ3k5Ms6UFOV4zoFWPnKFvVdNajWFwFu5017IENfDEAa+sL3iNu/iAPNvMEMfi4fmrL0KXcgFnV/cLZKfThAO8eH8twRhyFy744sL/IKtmzG0hE8JT08UaYUnJkNt5T5/ISk6UVU7/t8mvQCoqC8NCjzH0ESDHtCJk//kNWpOQQQxu4XNvjFVZtVCFUIsCsii7XSp7bsPXz9jazMpn+agdMnb822p6h2B5c87D7TiVnUt2veZ++ViTwiKrVOtypUhvK0p8IeWopeKOk0eOQ5L6JoRZN+telMAH/hoAnDL1T0LDnDU0KfTfz0TBE9mNWlJu5UwCjERTkC7GRxUJeYyuNIcSBGUSnK7D/MgMbbOis9fnR8qZJUrQYH7E440rkCanw8q+qsaVOg4CEFHW4t3JIZJMtiK6fbyr5CTLYlX2Q8JuGNZpWy30VapEMUmx+cXTuIdn99wokBI5dT6lN0T004tjeDbM5Y6v7Ep5u7ax4l+KdSQKrKpri820XmS7sSx+2GWPYY2eDDY3K47s9ASR94z9KYt27uU6lsnwNUI3CpIH0jk8i+y60yLvl/OqrLFj/ugoRj3ARr6Sej4Jj74jvl+3cAbwdiIbvG+Owu0Jg+Ny0i/vrPi3CmpwZjsFgrRU1SXGZgllZRjB7dWORhCqNFZeQp0nZ7Y6a/BUbbTFIWIU+hP0tXADMdBtcsdclAvlPheBt3z4iYx4Xa3//52XPw7uu3bFJmlbagVnLjO0F60ZV1WvP9mYwzrNGq47J1ms2BCfLLCAs43pLLfR6ZDsA6xWg0uydmOmAbDhCwk8gLli8qqgAYQuCxa/kTW9s9+Bpg+S5RVn3FFVufpDoxVoyqHpn4pFx2VlUBS/uD7B4mijRlaBlI2eBIiAUpvh4GpdErFYTYJLKBY1lGKGG0zC5KEtFwW4ciBfPwc229LaQE2p0eWn1Q6m1GNRKp4TsIeUri2YcpQp/kUOFLjlU3PbPOQF8u6hyeOJD3ttwb8T38xCapoYvcO5Ln+VzXPJNFqItBeXeWclreTYQhjUIuA1sKpZz6kkFCF7jckLPzH01ETCehiV/TCUnloevnG2j9DMDNZQydVwxaiCqVRtqQUYksvwkcz0IqxGj9H2GzW24s8vYMH23VCS6V2vEBckramGYSHx/Atgr3QNp9B4yhXJyuDZQxp9RnP2FBcKZcIZtsA/SJvpKPVud4Pa58r/rNHtv7lsEO4KAqhP+Xw9XIX3o45/GmurWymFOUzkHVxmkGh0rtUeC8waqLodQ8dexW6QYuqJGZKJcBQm9s57nW1Gy0aVWeUQAVkP9plKY1WW0yXFyRmLN1zv0dElG7P0oIOjH/T52nKhIUS2/VG5qehAZ292D8/caTuI55dtiaT1aDyN34FiaFFI9dmam6GBCeMww48wREQxuxqm1jj4gOGUPcGCvEaW08ul8LDyENpS4yU57QUXT/xEgBJbDsJU1LV0pCQDzn6FsuQDgy60BCxJhCISxd2llAO1QGD3dipa3aH7b80qGA67rCHfg/wJtqUG/xNqwDnuOjl4dU7C+SvkTyGorxwZ1rfDfcVHVoPXdmGJHjdNMtey2bmLycQZKpRJtcKpf7DTAhX7+O90vVwsr6onOBO/mFkIvw53TQCsrYE6Zg9v/SIlZ84NqZUDESMzhp6XGPieznmlN5Afb+4FkMotvUr7B2dT5veodivxBxcPVT1bwC/9vkNsDK6x9t9PTM9l9pTCm1D+UFJ5L9vTOM9K4GHJAXasSm0XqkL6VxWfL8hnQ1CJ1TrJMFP6rJCkZ/6xaDdR7tiwuuJwDnsNpyNEO9CWONhbTZ/yCoeR9cZz2abusWPtFLaVbD98pt44ctGSVveO51qOP9iRbUXJusdqruKfwjP+IOAmoq3T5OmEs26UvAJYpX3Gig3MG0d/cGDVFt1vPk3hQW6Aj/m9BPXdpcsSRbJc25FL+kOLg1WiRWRTbb1oU+s69d2JB36plb1rzH8Yr3Bmhe/fdS6ZqLIRP4Z9J39fn8muvhdtmYhYXliWYbnjCrkSyN0m00TT9pBgz47QuGwCgzuPsCF00IHiz4Vt9im9MnSl1B1gqqgzZM7LC3SnRPrRZZc8YPqD9djFBYuInESKSYq+x13xYaR3XrB1XkX9RR1oANqRyj0CfwrHmoF2Nsn8akENNWmdGmydmcOA35UPsaYV+3cEdt8XRjPN2Uw4wwpgI7tkMpgP+tHgpNpFyQ+agsexkh0LlUWPiC3ZkPQrK/Bu73e0znuhsdpCeF8vIMdx3HnBraxqciQ2vXEzHxZQKmQ/QAAAACHiMtNozUjyQABgmnpnwEADLQsQLHEZ/sCAAAAAARZWg=="

if __name__ == "__main__":
    try:
        main()
    except KeyboardInterrupt:
        # We don't want a KeyboardInterrupt throwing a
        # traceback into stdout.
        pass
