├── .coveragerc ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── LICENSE ├── README.rst ├── example ├── credentials.json.example └── example.py ├── lastpass ├── __init__.py ├── account.py ├── blob.py ├── chunk.py ├── exceptions.py ├── fetcher.py ├── parser.py ├── session.py ├── vault.py └── version.py ├── requirements.txt ├── setup.py ├── tests ├── __init__.py ├── test_account.py ├── test_blob.py ├── test_chunk.py ├── test_data.py ├── test_fetcher.py ├── test_http.py ├── test_parser.py ├── test_session.py └── test_vault.py └── tox.ini /.coveragerc: -------------------------------------------------------------------------------- 1 | [run] 2 | source = 3 | . 4 | 5 | omit = 6 | venv/* 7 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | strategy: 13 | max-parallel: 4 14 | matrix: 15 | python-version: [2.7, 3.6, 3.7, 3.8] 16 | 17 | steps: 18 | - uses: actions/checkout@v2 19 | - name: Set up Python ${{ matrix.python-version }} 20 | uses: actions/setup-python@v1 21 | with: 22 | python-version: ${{ matrix.python-version }} 23 | - name: Install dependencies 24 | run: | 25 | python -m pip install --upgrade pip 26 | pip install -r requirements.txt 27 | pip install codecov 28 | - name: Test 29 | run: | 30 | nosetests --with-coverage --cover-package=lastpass 31 | - name: Upload Code Coverage 32 | run: | 33 | codecov 34 | env: 35 | CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} 36 | 37 | lint: 38 | runs-on: ubuntu-latest 39 | strategy: 40 | max-parallel: 2 41 | matrix: 42 | python-version: [2.7, 3.8] 43 | 44 | steps: 45 | - uses: actions/checkout@v2 46 | - name: Set up Python ${{ matrix.python-version }} 47 | uses: actions/setup-python@v1 48 | with: 49 | python-version: ${{ matrix.python-version }} 50 | - name: Install dependencies 51 | run: | 52 | pip install pep8 53 | - name: Lint 54 | run: | 55 | pep8 --repeat --show-source --exclude=.venv,.tox,dist,docs,build,lastpass_python.egg-info,.git --ignore=E501,E731 . 56 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | .coverage 3 | example/credentials.json 4 | 5 | *.egg-info/ 6 | dist/ 7 | .tox 8 | 9 | .python-version 10 | .idea/ 11 | .venv/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Dmitry Yakimenko 4 | Copyright (c) 2014 konomae 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | this software and associated documentation files (the "Software"), to deal in 8 | the Software without restriction, including without limitation the rights to 9 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 | the Software, and to permit persons to whom the Software is furnished to do so, 11 | subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | LastPass Python API 2 | =================== 3 | 4 | .. image:: https://github.com/konomae/lastpass-python/workflows/CI/badge.svg 5 | :target: https://github.com/konomae/lastpass-python/actions 6 | 7 | .. image:: https://codecov.io/gh/konomae/lastpass-python/branch/master/graph/badge.svg 8 | :target: https://codecov.io/gh/konomae/lastpass-python 9 | 10 | :Original: `lastpass-ruby `_ 11 | 12 | **This is unofficial LastPass API** 13 | 14 | 15 | Install 16 | ------- 17 | 18 | .. code-block:: bash 19 | 20 | $ pip install lastpass-python 21 | 22 | 23 | Example 24 | ------- 25 | 26 | .. code-block:: python 27 | 28 | # coding: utf-8 29 | import lastpass 30 | 31 | vault = lastpass.Vault.open_remote(username, password) 32 | for i in vault.accounts: 33 | print(i.id, i.username, i.password, i.url) 34 | 35 | 36 | 37 | Testing 38 | ------- 39 | 40 | Install test dependencies 41 | 42 | .. code-block:: bash 43 | 44 | $ pip install -r requirements.txt 45 | 46 | Run tests with 47 | 48 | .. code-block:: bash 49 | 50 | $ nosetests 51 | 52 | or test all environments and pep8 with tox 53 | 54 | .. code-block:: bash 55 | 56 | $ tox 57 | 58 | 59 | Releasing 60 | --------- 61 | 62 | .. code-block:: bash 63 | 64 | $ pip install twine 65 | $ python setup.py sdist 66 | $ twine upload dist/* 67 | 68 | 69 | License 70 | ------- 71 | 72 | `The MIT License `_ 73 | 74 | -------------------------------------------------------------------------------- /example/credentials.json.example: -------------------------------------------------------------------------------- 1 | { 2 | "username": "account@example.com", 3 | "password": "correct horse battery staple" 4 | } -------------------------------------------------------------------------------- /example/example.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding: utf-8 3 | from __future__ import print_function 4 | 5 | import json 6 | import os 7 | from lastpass import ( 8 | Vault, 9 | LastPassIncorrectYubikeyPasswordError, 10 | LastPassIncorrectGoogleAuthenticatorCodeError 11 | ) 12 | 13 | DEVICE_ID = "example.py" 14 | 15 | 16 | with open(os.path.join(os.path.dirname(__file__), 'credentials.json')) as f: 17 | credentials = json.load(f) 18 | username = credentials['username'] 19 | password = credentials['password'] 20 | 21 | try: 22 | # First try without a multifactor password 23 | vault = Vault.open_remote(username, password, None, DEVICE_ID) 24 | except LastPassIncorrectGoogleAuthenticatorCodeError as e: 25 | # Get the code 26 | multifactor_password = input('Enter Google Authenticator code:') 27 | 28 | # And now retry with the code 29 | vault = Vault.open_remote(username, password, multifactor_password, DEVICE_ID) 30 | except LastPassIncorrectYubikeyPasswordError as e: 31 | # Get the code 32 | multifactor_password = input('Enter Yubikey password:') 33 | 34 | # And now retry with the code 35 | vault = Vault.open_remote(username, password, multifactor_password, DEVICE_ID) 36 | 37 | 38 | for index, i in enumerate(vault.accounts): 39 | print("{} {} {} {} {} {} {} {}".format(index + 1, i.id, i.name, i.username, i.password, i.url, i.group, i.notes)) 40 | -------------------------------------------------------------------------------- /lastpass/__init__.py: -------------------------------------------------------------------------------- 1 | from .vault import Vault 2 | from .exceptions import * 3 | from .version import * 4 | -------------------------------------------------------------------------------- /lastpass/account.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | class Account(object): 3 | def __init__(self, id, name, username, password, url, group, notes=None): 4 | self.id = id 5 | self.name = name 6 | self.username = username 7 | self.password = password 8 | self.url = url 9 | self.group = group 10 | self.notes = notes 11 | -------------------------------------------------------------------------------- /lastpass/blob.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | class Blob(object): 3 | def __init__(self, bytes, key_iteration_count): 4 | self.bytes = bytes 5 | self.key_iteration_count = key_iteration_count 6 | 7 | def encryption_key(self, username, password): 8 | from . import fetcher 9 | return fetcher.make_key(username, password, self.key_iteration_count) 10 | 11 | def __eq__(self, other): 12 | return self.bytes == other.bytes and self.key_iteration_count == other.key_iteration_count 13 | -------------------------------------------------------------------------------- /lastpass/chunk.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | class Chunk(object): 3 | def __init__(self, id, payload): 4 | self.id = id 5 | self.payload = payload 6 | 7 | def __eq__(self, other): 8 | return self.id == other.id and self.payload == other.payload 9 | -------------------------------------------------------------------------------- /lastpass/exceptions.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | 4 | class Error(Exception): 5 | """Base class for all errors, should not be raised""" 6 | pass 7 | 8 | 9 | # 10 | # Generic errors 11 | # 12 | 13 | class NetworkError(Error): 14 | """Something went wrong with the network""" 15 | pass 16 | 17 | 18 | class InvalidResponseError(Error): 19 | """Server responded with something we don't understand""" 20 | pass 21 | 22 | 23 | class UnknownResponseSchemaError(Error): 24 | """Server responded with XML we don't understand""" 25 | pass 26 | 27 | 28 | # 29 | # LastPass returned errors 30 | # 31 | 32 | class LastPassUnknownUsernameError(Error): 33 | """LastPass error: unknown username""" 34 | pass 35 | 36 | 37 | class LastPassInvalidPasswordError(Error): 38 | """LastPass error: invalid password""" 39 | pass 40 | 41 | 42 | class LastPassIncorrectGoogleAuthenticatorCodeError(Error): 43 | """LastPass error: missing or incorrect Google Authenticator code""" 44 | pass 45 | 46 | 47 | class LastPassIncorrectYubikeyPasswordError(Error): 48 | """LastPass error: missing or incorrect Yubikey password""" 49 | pass 50 | 51 | 52 | class LastPassUnknownError(Error): 53 | """LastPass error we don't know about""" 54 | pass 55 | -------------------------------------------------------------------------------- /lastpass/fetcher.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import hashlib 3 | from base64 import b64decode 4 | from binascii import hexlify 5 | import requests 6 | from xml.etree import ElementTree as etree 7 | from . import blob 8 | from .version import __version__ 9 | from .exceptions import ( 10 | NetworkError, 11 | InvalidResponseError, 12 | UnknownResponseSchemaError, 13 | LastPassUnknownUsernameError, 14 | LastPassInvalidPasswordError, 15 | LastPassIncorrectGoogleAuthenticatorCodeError, 16 | LastPassIncorrectYubikeyPasswordError, 17 | LastPassUnknownError 18 | ) 19 | from .session import Session 20 | 21 | 22 | http = requests 23 | headers = {'user-agent': 'lastpass-python/{}'.format(__version__)} 24 | 25 | 26 | def login(username, password, multifactor_password=None, client_id=None): 27 | key_iteration_count = request_iteration_count(username) 28 | return request_login(username, password, key_iteration_count, multifactor_password, client_id) 29 | 30 | 31 | def logout(session, web_client=http): 32 | # type: (Session, requests) -> None 33 | response = web_client.get( 34 | 'https://lastpass.com/logout.php?mobile=1', 35 | cookies={'PHPSESSID': session.id} 36 | ) 37 | 38 | if response.status_code != requests.codes.ok: 39 | raise NetworkError() 40 | 41 | 42 | def fetch(session, web_client=http): 43 | response = web_client.get('https://lastpass.com/getaccts.php?mobile=1&b64=1&hash=0.0&hasplugin=3.0.23&requestsrc=android', 44 | cookies={'PHPSESSID': session.id}) 45 | 46 | if response.status_code != requests.codes.ok: 47 | raise NetworkError() 48 | 49 | return blob.Blob(decode_blob(response.content), session.key_iteration_count) 50 | 51 | 52 | def request_iteration_count(username, web_client=http): 53 | response = web_client.post('https://lastpass.com/iterations.php', 54 | data={'email': username}, 55 | headers=headers) 56 | if response.status_code != requests.codes.ok: 57 | raise NetworkError() 58 | 59 | try: 60 | count = int(response.content) 61 | except: 62 | raise InvalidResponseError('Key iteration count is invalid') 63 | 64 | if count > 0: 65 | return count 66 | raise InvalidResponseError('Key iteration count is not positive') 67 | 68 | 69 | def request_login(username, password, key_iteration_count, multifactor_password=None, client_id=None, web_client=http): 70 | body = { 71 | 'method': 'mobile', 72 | 'web': 1, 73 | 'xml': 1, 74 | 'username': username, 75 | 'hash': make_hash(username, password, key_iteration_count), 76 | 'iterations': key_iteration_count, 77 | } 78 | 79 | if multifactor_password: 80 | body['otp'] = multifactor_password 81 | 82 | if client_id: 83 | body['imei'] = client_id 84 | 85 | response = web_client.post('https://lastpass.com/login.php', 86 | data=body, 87 | headers=headers) 88 | 89 | if response.status_code != requests.codes.ok: 90 | raise NetworkError() 91 | 92 | try: 93 | parsed_response = etree.fromstring(response.content) 94 | except etree.ParseError: 95 | parsed_response = None 96 | 97 | if parsed_response is None: 98 | raise InvalidResponseError() 99 | 100 | session = create_session(parsed_response, key_iteration_count) 101 | if not session: 102 | raise login_error(parsed_response) 103 | return session 104 | 105 | 106 | def create_session(parsed_response, key_iteration_count): 107 | if parsed_response.tag == 'ok': 108 | session_id = parsed_response.attrib.get('sessionid') 109 | if isinstance(session_id, str): 110 | return Session(session_id, key_iteration_count) 111 | 112 | 113 | def login_error(parsed_response): 114 | error = None if parsed_response.tag != 'response' else parsed_response.find('error') 115 | if error is None or len(error.attrib) == 0: 116 | raise UnknownResponseSchemaError() 117 | 118 | exceptions = { 119 | "unknownemail": LastPassUnknownUsernameError, 120 | "unknownpassword": LastPassInvalidPasswordError, 121 | "googleauthrequired": LastPassIncorrectGoogleAuthenticatorCodeError, 122 | "googleauthfailed": LastPassIncorrectGoogleAuthenticatorCodeError, 123 | "yubikeyrestricted": LastPassIncorrectYubikeyPasswordError, 124 | } 125 | 126 | cause = error.attrib.get('cause') 127 | message = error.attrib.get('message') 128 | 129 | if cause: 130 | return exceptions.get(cause, LastPassUnknownError)(message or cause) 131 | return InvalidResponseError(message) 132 | 133 | 134 | def decode_blob(blob): 135 | return b64decode(blob) 136 | 137 | 138 | def make_key(username, password, key_iteration_count): 139 | # type: (str, str, int) -> bytes 140 | if key_iteration_count == 1: 141 | return hashlib.sha256(username.encode('utf-8') + password.encode('utf-8')).digest() 142 | else: 143 | return hashlib.pbkdf2_hmac('sha256', password.encode('utf-8'), username.encode('utf-8'), key_iteration_count, 32) 144 | 145 | 146 | def make_hash(username, password, key_iteration_count): 147 | # type: (str, str, int) -> bytes 148 | if key_iteration_count == 1: 149 | return bytearray(hashlib.sha256(hexlify(make_key(username, password, 1)) + password.encode('utf-8')).hexdigest(), 'ascii') 150 | else: 151 | return hexlify(hashlib.pbkdf2_hmac( 152 | 'sha256', 153 | make_key(username, password, key_iteration_count), 154 | password.encode('utf-8'), 155 | 1, 156 | 32 157 | )) 158 | -------------------------------------------------------------------------------- /lastpass/parser.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from base64 import b64decode 3 | import binascii 4 | import codecs 5 | from io import BytesIO 6 | import struct 7 | import re 8 | 9 | from Crypto.Cipher import AES, PKCS1_OAEP 10 | from Crypto.Util import number 11 | from Crypto.PublicKey import RSA 12 | 13 | from .account import Account 14 | from .chunk import Chunk 15 | 16 | 17 | # Secure note types that contain account-like information 18 | ALLOWED_SECURE_NOTE_TYPES = [ 19 | b"Server", 20 | b"Email Account", 21 | b"Database", 22 | b"Instant Messenger", 23 | ] 24 | 25 | 26 | def extract_chunks(blob): 27 | """Splits the blob into chucks grouped by kind.""" 28 | chunks = [] 29 | stream = BytesIO(blob.bytes) 30 | current_pos = stream.tell() 31 | stream.seek(0, 2) 32 | length = stream.tell() 33 | stream.seek(current_pos, 0) 34 | while stream.tell() < length: 35 | chunks.append(read_chunk(stream)) 36 | 37 | return chunks 38 | 39 | 40 | def parse_ACCT(chunk, encryption_key): 41 | """ 42 | Parses an account chunk, decrypts and creates an Account object. 43 | May return nil when the chunk does not represent an account. 44 | All secure notes are ACCTs but not all of them strore account 45 | information. 46 | """ 47 | # TODO: Make a test case that covers secure note account 48 | 49 | io = BytesIO(chunk.payload) 50 | id = read_item(io) 51 | name = decode_aes256_plain_auto(read_item(io), encryption_key) 52 | group = decode_aes256_plain_auto(read_item(io), encryption_key) 53 | url = decode_hex(read_item(io)) 54 | notes = decode_aes256_plain_auto(read_item(io), encryption_key) 55 | skip_item(io, 2) 56 | username = decode_aes256_plain_auto(read_item(io), encryption_key) 57 | password = decode_aes256_plain_auto(read_item(io), encryption_key) 58 | skip_item(io, 2) 59 | secure_note = read_item(io) 60 | 61 | # Parse secure note 62 | if secure_note == b'1': 63 | parsed = parse_secure_note_server(notes) 64 | 65 | if parsed.get('type') in ALLOWED_SECURE_NOTE_TYPES: 66 | url = parsed.get('url', url) 67 | username = parsed.get('username', username) 68 | password = parsed.get('password', password) 69 | 70 | return Account(id, name, username, password, url, group, notes) 71 | 72 | 73 | def parse_PRIK(chunk, encryption_key): 74 | """Parse PRIK chunk which contains private RSA key""" 75 | decrypted = decode_aes256('cbc', 76 | encryption_key[:16], 77 | decode_hex(chunk.payload), 78 | encryption_key) 79 | 80 | hex_key = re.match(br'^LastPassPrivateKey<(?P.*)>LastPassPrivateKey$', decrypted).group('hex_key') 81 | rsa_key = RSA.importKey(decode_hex(hex_key)) 82 | 83 | rsa_key.dmp1 = rsa_key.d % (rsa_key.p - 1) 84 | rsa_key.dmq1 = rsa_key.d % (rsa_key.q - 1) 85 | rsa_key.iqmp = number.inverse(rsa_key.q, rsa_key.p) 86 | 87 | return rsa_key 88 | 89 | 90 | def parse_SHAR(chunk, encryption_key, rsa_key): 91 | # TODO: Fake some data and make a test 92 | io = BytesIO(chunk.payload) 93 | id = read_item(io) 94 | encrypted_key = decode_hex(read_item(io)) 95 | encrypted_name = read_item(io) 96 | skip_item(io, 2) 97 | key = read_item(io) 98 | 99 | # Shared folder encryption key might come already in pre-decrypted form, 100 | # where it's only AES encrypted with the regular encryption key. 101 | # When the key is blank, then there's a RSA encrypted key, which has to 102 | # be decrypted first before use. 103 | if not key: 104 | key = decode_hex(PKCS1_OAEP.new(rsa_key).decrypt(encrypted_key)) 105 | else: 106 | key = decode_hex(decode_aes256_plain_auto(key, encryption_key)) 107 | 108 | name = decode_aes256_base64_auto(encrypted_name, key) 109 | 110 | # TODO: Return an object, not a dict 111 | return {'id': id, 'name': name, 'encryption_key': key} 112 | 113 | 114 | def parse_secure_note_server(notes): 115 | info = {} 116 | 117 | for i in notes.split(b'\n'): 118 | if not i: # blank line 119 | continue 120 | 121 | if b':' not in i: # there is no `:` if generic note 122 | continue 123 | 124 | # Split only once so that strings like "Hostname:host.example.com:80" 125 | # get interpreted correctly 126 | key, value = i.split(b':', 1) 127 | if key == b'NoteType': 128 | info['type'] = value 129 | elif key == b'Hostname': 130 | info['url'] = value 131 | elif key == b'Username': 132 | info['username'] = value 133 | elif key == b'Password': 134 | info['password'] = value 135 | 136 | return info 137 | 138 | 139 | def read_chunk(stream): 140 | """Reads one chunk from a stream and creates a Chunk object with the data read.""" 141 | # LastPass blob chunk is made up of 4-byte ID, 142 | # big endian 4-byte size and payload of that size. 143 | # 144 | # Example: 145 | # 0000: "IDID" 146 | # 0004: 4 147 | # 0008: 0xDE 0xAD 0xBE 0xEF 148 | # 000C: --- Next chunk --- 149 | return Chunk(read_id(stream), read_payload(stream, read_size(stream))) 150 | 151 | 152 | def read_item(stream): 153 | """Reads an item from a stream and returns it as a string of bytes.""" 154 | # An item in an itemized chunk is made up of the 155 | # big endian size and the payload of that size. 156 | # 157 | # Example: 158 | # 0000: 4 159 | # 0004: 0xDE 0xAD 0xBE 0xEF 160 | # 0008: --- Next item --- 161 | return read_payload(stream, read_size(stream)) 162 | 163 | 164 | def skip_item(stream, times=1): 165 | """Skips an item in a stream.""" 166 | for i in range(times): 167 | read_item(stream) 168 | 169 | 170 | def read_id(stream): 171 | """Reads a chunk ID from a stream.""" 172 | return stream.read(4) 173 | 174 | 175 | def read_size(stream): 176 | """Reads a chunk or an item ID.""" 177 | return read_uint32(stream) 178 | 179 | 180 | def read_payload(stream, size): 181 | """Reads a payload of a given size from a stream.""" 182 | return stream.read(size) 183 | 184 | 185 | def read_uint32(stream): 186 | """Reads an unsigned 32 bit integer from a stream.""" 187 | return struct.unpack('>I', stream.read(4))[0] 188 | 189 | 190 | def decode_hex(data): 191 | """Decodes a hex encoded string into raw bytes.""" 192 | try: 193 | return codecs.decode(data, 'hex_codec') 194 | except binascii.Error: 195 | raise TypeError() 196 | 197 | 198 | def decode_base64(data): 199 | """Decodes a base64 encoded string into raw bytes.""" 200 | return b64decode(data) 201 | 202 | 203 | def decode_aes256_plain_auto(data, encryption_key): 204 | """Guesses AES cipher (EBC or CBD) from the length of the plain data.""" 205 | assert isinstance(data, bytes) 206 | length = len(data) 207 | 208 | if length == 0: 209 | return b'' 210 | elif data[0] == b'!'[0] and length % 16 == 1 and length > 32: 211 | return decode_aes256_cbc_plain(data, encryption_key) 212 | else: 213 | return decode_aes256_ecb_plain(data, encryption_key) 214 | 215 | 216 | def decode_aes256_base64_auto(data, encryption_key): 217 | """Guesses AES cipher (EBC or CBD) from the length of the base64 encoded data.""" 218 | assert isinstance(data, bytes) 219 | length = len(data) 220 | 221 | if length == 0: 222 | return b'' 223 | elif data[0] == b'!'[0]: 224 | return decode_aes256_cbc_base64(data, encryption_key) 225 | else: 226 | return decode_aes256_ecb_base64(data, encryption_key) 227 | 228 | 229 | def decode_aes256_ecb_plain(data, encryption_key): 230 | """Decrypts AES-256 ECB bytes.""" 231 | if not data: 232 | return b'' 233 | else: 234 | return decode_aes256('ecb', '', data, encryption_key) 235 | 236 | 237 | def decode_aes256_ecb_base64(data, encryption_key): 238 | """Decrypts base64 encoded AES-256 ECB bytes.""" 239 | return decode_aes256_ecb_plain(decode_base64(data), encryption_key) 240 | 241 | 242 | def decode_aes256_cbc_plain(data, encryption_key): 243 | """Decrypts AES-256 CBC bytes.""" 244 | if not data: 245 | return b'' 246 | else: 247 | # LastPass AES-256/CBC encryted string starts with an "!". 248 | # Next 16 bytes are the IV for the cipher. 249 | # And the rest is the encrypted payload. 250 | return decode_aes256('cbc', data[1:17], data[17:], encryption_key) 251 | 252 | 253 | def decode_aes256_cbc_base64(data, encryption_key): 254 | """Decrypts base64 encoded AES-256 CBC bytes.""" 255 | if not data: 256 | return b'' 257 | else: 258 | # LastPass AES-256/CBC/base64 encryted string starts with an "!". 259 | # Next 24 bytes are the base64 encoded IV for the cipher. 260 | # Then comes the "|". 261 | # And the rest is the base64 encoded encrypted payload. 262 | return decode_aes256( 263 | 'cbc', 264 | decode_base64(data[1:25]), 265 | decode_base64(data[26:]), 266 | encryption_key) 267 | 268 | 269 | def decode_aes256(cipher, iv, data, encryption_key): 270 | """ 271 | Decrypt AES-256 bytes. 272 | Allowed ciphers are: :ecb, :cbc. 273 | If for :ecb iv is not used and should be set to "". 274 | """ 275 | if cipher == 'cbc': 276 | aes = AES.new(encryption_key, AES.MODE_CBC, iv) 277 | elif cipher == 'ecb': 278 | aes = AES.new(encryption_key, AES.MODE_ECB) 279 | else: 280 | raise ValueError('Unknown AES mode') 281 | d = aes.decrypt(data) 282 | # http://passingcuriosity.com/2009/aes-encryption-in-python-with-m2crypto/ 283 | unpad = lambda s: s[0:-ord(d[-1:])] 284 | return unpad(d) 285 | -------------------------------------------------------------------------------- /lastpass/session.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | class Session(object): 3 | def __init__(self, id, key_iteration_count): 4 | self.id = id 5 | self.key_iteration_count = key_iteration_count 6 | 7 | def __eq__(self, other): 8 | return self.id == other.id and self.key_iteration_count == other.key_iteration_count 9 | -------------------------------------------------------------------------------- /lastpass/vault.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from . import fetcher 3 | from . import parser 4 | from .exceptions import InvalidResponseError 5 | 6 | 7 | class Vault(object): 8 | @classmethod 9 | def open_remote(cls, username, password, multifactor_password=None, client_id=None): 10 | """Fetches a blob from the server and creates a vault""" 11 | blob = cls.fetch_blob(username, password, multifactor_password, client_id) 12 | return cls.open(blob, username, password) 13 | 14 | @classmethod 15 | def open_local(cls, blob_filename, username, password): 16 | """Creates a vault from a locally stored blob""" 17 | # TODO: read the blob here 18 | raise NotImplementedError() 19 | 20 | @classmethod 21 | def open(cls, blob, username, password): 22 | """Creates a vault from a blob object""" 23 | return cls(blob, blob.encryption_key(username, password)) 24 | 25 | @classmethod 26 | def fetch_blob(cls, username, password, multifactor_password=None, client_id=None): 27 | """Just fetches the blob, could be used to store it locally""" 28 | session = fetcher.login(username, password, multifactor_password, client_id) 29 | blob = fetcher.fetch(session) 30 | fetcher.logout(session) 31 | 32 | return blob 33 | 34 | def __init__(self, blob, encryption_key): 35 | """This more of an internal method, use one of the static constructors instead""" 36 | chunks = parser.extract_chunks(blob) 37 | 38 | if not self.is_complete(chunks): 39 | raise InvalidResponseError('Blob is truncated') 40 | 41 | self.accounts = self.parse_accounts(chunks, encryption_key) 42 | 43 | def is_complete(self, chunks): 44 | return len(chunks) > 0 and chunks[-1].id == b'ENDM' and chunks[-1].payload == b'OK' 45 | 46 | def parse_accounts(self, chunks, encryption_key): 47 | accounts = [] 48 | 49 | key = encryption_key 50 | rsa_private_key = None 51 | 52 | for i in chunks: 53 | if i.id == b'ACCT': 54 | # TODO: Put shared folder name as group in the account 55 | account = parser.parse_ACCT(i, key) 56 | if account: 57 | accounts.append(account) 58 | elif i.id == b'PRIK': 59 | rsa_private_key = parser.parse_PRIK(i, encryption_key) 60 | elif i.id == b'SHAR': 61 | # After SHAR chunk all the folliwing accounts are enrypted with a new key 62 | key = parser.parse_SHAR(i, encryption_key, rsa_private_key)['encryption_key'] 63 | 64 | return accounts 65 | -------------------------------------------------------------------------------- /lastpass/version.py: -------------------------------------------------------------------------------- 1 | __version__ = '0.3.2' 2 | 3 | # lastpass-ruby's version 4 | VERSION = '1.5.0' 5 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | requests>=1.2.1,<=3.0.0 2 | pycryptodome>=3.4 3 | mock==2.0.0 4 | tox==2.9.1 5 | nose==1.3.7 6 | coverage==4.4.1 7 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | 3 | 4 | def get_version(): 5 | import re 6 | with open('lastpass/version.py', 'r') as f: 7 | for line in f: 8 | m = re.match(r'__version__ = [\'"]([^\'"]*)[\'"]', line) 9 | if m: 10 | return m.group(1) 11 | raise RuntimeError('Cannot find version information') 12 | 13 | 14 | setup( 15 | name='lastpass-python', 16 | version=get_version(), 17 | description='Read only access to the online LastPass vault (unofficial)', 18 | long_description=open('README.rst').read(), 19 | license='MIT', 20 | author='konomae', 21 | author_email='konomae@users.noreply.github.com', 22 | url='https://github.com/konomae/lastpass-python', 23 | packages=['lastpass'], 24 | install_requires=[ 25 | "requests>=1.2.1,<=3.0.0", 26 | "pycryptodome>=3.4", 27 | ], 28 | classifiers=[ 29 | 'Development Status :: 3 - Alpha', 30 | 'License :: OSI Approved :: MIT License', 31 | 'Intended Audience :: Developers', 32 | 'Programming Language :: Python', 33 | 'Programming Language :: Python :: 2', 34 | 'Programming Language :: Python :: 2.7', 35 | 'Programming Language :: Python :: 3', 36 | 'Programming Language :: Python :: 3.6', 37 | 'Programming Language :: Python :: Implementation :: CPython', 38 | ], 39 | ) 40 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konomae/lastpass-python/41af73adecda1fbf48b83e53ed198e128e505405/tests/__init__.py -------------------------------------------------------------------------------- /tests/test_account.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | from lastpass.account import Account 4 | 5 | 6 | class AccountTestCase(unittest.TestCase): 7 | def setUp(self): 8 | self.id = 'id' 9 | self.name = 'name' 10 | self.username = 'username' 11 | self.password = 'password' 12 | self.url = 'url' 13 | self.group = 'group' 14 | self.notes = 'notes' 15 | self.account = Account(self.id, self.name, self.username, self.password, self.url, self.group, self.notes) 16 | 17 | def test_id_returns_the_correct_value(self): 18 | self.assertEqual(self.account.id, self.id) 19 | 20 | def test_name_returns_the_correct_value(self): 21 | self.assertEqual(self.account.name, self.name) 22 | 23 | def test_username_returns_the_correct_value(self): 24 | self.assertEqual(self.account.username, self.username) 25 | 26 | def test_password_returns_the_correct_value(self): 27 | self.assertEqual(self.account.password, self.password) 28 | 29 | def test_url_returns_the_correct_value(self): 30 | self.assertEqual(self.account.url, self.url) 31 | 32 | def test_group_returns_the_correct_value(self): 33 | self.assertEqual(self.account.group, self.group) 34 | 35 | def test_notes_returns_the_correct_value(self): 36 | self.assertEqual(self.account.notes, self.notes) 37 | -------------------------------------------------------------------------------- /tests/test_blob.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from base64 import b64decode 3 | import unittest 4 | from lastpass.blob import Blob 5 | 6 | 7 | class BlobTestCase(unittest.TestCase): 8 | def setUp(self): 9 | self.bytes = b64decode('TFBBVgAAAAMxMjJQUkVNAAAACjE0MTQ5') 10 | self.key_iteration_count = 500 11 | self.username = 'postlass@gmail.com' 12 | self.password = 'pl1234567890' 13 | self.encryption_key = b64decode('OfOUvVnQzB4v49sNh4+PdwIFb9Fr5+jVfWRTf+E2Ghg=') 14 | 15 | self.blob = Blob(self.bytes, self.key_iteration_count) 16 | 17 | def test_bytes_returns_the_correct_value(self): 18 | self.assertEqual(self.blob.bytes, self.bytes) 19 | 20 | def test_key_iteration_count_returns_the_correct_value(self): 21 | self.assertEqual(self.blob.key_iteration_count, self.key_iteration_count) 22 | 23 | def test_encryption_key_returns_the_correct_value(self): 24 | self.assertEqual(self.blob.encryption_key(self.username, self.password), self.encryption_key) 25 | -------------------------------------------------------------------------------- /tests/test_chunk.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | from lastpass.chunk import Chunk 4 | 5 | 6 | class ChunkTestCase(unittest.TestCase): 7 | def setUp(self): 8 | self.id = 'IDID' 9 | self.payload = 'Payload' 10 | 11 | self.chunk = Chunk(self.id, self.payload) 12 | 13 | def test_id_returns_the_correct_value(self): 14 | self.assertEqual(self.chunk.id, self.id) 15 | 16 | def test_payload_returns_the_correct_value(self): 17 | self.assertEqual(self.chunk.payload, self.payload) 18 | -------------------------------------------------------------------------------- /tests/test_data.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from base64 import b64decode 3 | from lastpass.account import Account 4 | 5 | TEST_CHUNK_IDS = [ 6 | b'LPAV', b'ATVR', b'ENCU', b'CBCU', b'BBTE', b'IPTE', b'WMTE', b'ANTE', b'DOTE', b'FETE', b'FUTE', 7 | b'SYTE', b'WOTE', b'TATE', b'WPTE', b'SPMT', b'NMAC', b'ACCT', b'EQDN', b'URUL', b'ENDM', 8 | ] 9 | 10 | TEST_BLOB = b64decode( 11 | "TFBBVgAAAAMxMThBVFZSAAAAAzEwMkVOQ1UAAABGITExVkVjWFVnelFramxranB2" + 12 | "VGZyR3c9PXxYUklhVVdQYlQzRXdRQlZCRUYxZUJTTDI3bWZ1cVViZmFCV3JCYnd5" + 13 | "WFdFPUNCQ1UAAAABMUJCVEUAAAAMLTYyMTY5OTY2MDAwSVBURQAAAAwtNjIxNjk5" + 14 | "NjYwMDBXTVRFAAAADC02MjE2OTk2NjAwMEFOVEUAAAAMLTYyMTY5OTY2MDAwRE9U" + 15 | "RQAAAAwtNjIxNjk5NjYwMDBGRVRFAAAADC02MjE2OTk2NjAwMEZVVEUAAAAMLTYy" + 16 | "MTY5OTY2MDAwU1lURQAAAAwtNjIxNjk5NjYwMDBXT1RFAAAADC02MjE2OTk2NjAw" + 17 | "MFRBVEUAAAAMLTYyMTY5OTY2MDAwV1BURQAAAAEwU1BNVAAAAC0AAAABMAAAAAEw" + 18 | "AAAAATAAAAABMAAAAAEwAAAAATEAAAABMQAAAAEwAAAAATBOTUFDAAAAAzEwMEFD" + 19 | "Q1QAAAGTAAAACjE4NzI3NDU1OTYAAAAxIaUvQYPzwlMtRTrZEYftBU9068UlQ6rL" + 20 | "OxmAxj8la1TXtePO6A6dOgmDalfC+dPq0gAAACEhP6C+06QXUEo+rzP1CV2Y8gRR" + 21 | "6lSnhVSaB3/FJPgnYLgAAABENjg3NDc0NzAzYTJmMmY2ZTY5NjU2ZTZmNzcyZTZl" + 22 | "NjU3NDJmNmQ2NTYxNjc2MTZlMmU2NzcyNjU2NTZlNjg2ZjZjNzQAAAAAAAAAATAA" + 23 | "AAAAAAAAISGrnmjbXckUV+TJvuuFaiAU055QL+iRpTOLUdEfvpR55gAAADEh02Ki" + 24 | "+p/VUgFlLbZKaV0AYtpeGsQ7Jmt+R+BRdoWkwGsXHm5blPx/YYVdf8Y9TwE7AAAA" + 25 | "ATAAAAABMAAAAAEwAAAAATAAAAABMAAAAAEwAAAAAAAAAAoxODcyNzQ1NTk2AAAA" + 26 | "AAAAAAAAAAAAAAAAATAAAAABMAAAAAAAAAAAAAAAATAAAAABMAAAAAAAAAABMQAA" + 27 | "AAEwAAAAAAAAAAAAAAAKMTM3MzA3NzEwNEFDQ1QAAAGJAAAACjE4NzI3NDU2MDYA" + 28 | "AAAhIWzPDPU9FrsGRopvmOi6uvOYkcGqaqKCFprsL3G1f0FvAAAAISGG5zXlgJ5y" + 29 | "J8fZnAWd/SNb9l/aujeXOtTHTAvQ8RuCnQAAAEo2ODc0NzQ3MDNhMmYyZjYyNjU2" + 30 | "MzY4NzQ2NTZjNjE3MjJlNjI2OTdhMmY3NDcyNjk3Mzc0Njk2MTZlMmU2MjYxNzI3" + 31 | "MjZmNzc3MwAAAAAAAAABMAAAAAAAAAAxIRTPYYC8d7Rvc+NXYokX3soC70wrzjEa" + 32 | "xvytac7xJbd1K/dHU8ee7HU7u5bfNVWVuQAAACEhVq89o7tYpBLCvQO7dtjasGG7" + 33 | "Osin9SvtokRlhNmpDVoAAAABMAAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAAAAAA" + 34 | "AAAACjE4NzI3NDU2MDYAAAAAAAAAAAAAAAAAAAABMAAAAAEwAAAAAAAAAAAAAAAB" + 35 | "MQAAAAEwAAAAAAAAAAExAAAAATAAAAAAAAAAAAAAAAoxMzczMDc3MTA0QUNDVAAA" + 36 | "AXUAAAAKMTg3Mjc0NTYxNgAAACEhO9e0HHKHemPXY7gLp1P722/WU9ZSQYjnTWU1" + 37 | "CEJgA3AAAAAhIQM9xNKiBFE1UVQVYaoW6IcvoVSjbGGtS7qj1PplR/2hAAAANjY4" + 38 | "NzQ3NDcwM2EyZjJmNzM2MzY4NzU3Mzc0NjU3MjJlNmU2MTZkNjUyZjYxNzM2ODc0" + 39 | "NmY2ZQAAAAAAAAABMAAAAAAAAAAhIZtIAgu1kRxJC7aqw4H8RXiOC2E4NuRse0fN" + 40 | "/IrFIYVUAAAAMSE9LwFmsD73HSRtgqo5wSX7aJposOOm2hqPIpzFvJwrJlNN1C+2" + 41 | "gbo3ml+YhjkN5pIAAAABMAAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAAAAAAAAAA" + 42 | "CjE4NzI3NDU2MTYAAAAAAAAAAAAAAAAAAAABMAAAAAEwAAAAAAAAAAAAAAABMgAA" + 43 | "AAEwAAAAAAAAAAExAAAAATAAAAAAAAAAAAAAAAoxMzczMDc3MTA0QUNDVAAAAWsA" + 44 | "AAAKMTg3Mjc0NTYyNgAAACEhXQIttPj6P/25RK3pzV85x1XMTwsb1HMPjCr8RLnn" + 45 | "QOQAAAAhIQ14pX3pzuwOXfczG4+vhm1epPlgA2LtCJRV7Y/knBJ4AAAALDY4NzQ3" + 46 | "NDcwM2EyZjJmNzI3NTZlNmY2YzY2NmY2ZTJlNmY3MjY3MmY3NDY1AAAAAAAAAAEw" + 47 | "AAAAAAAAADEhbZ6cUQzOVkgsFB0d73mOTCJ9efy3VFBEsb0ekhyJcNcUjAPjh774" + 48 | "+BbjywxUsco1AAAAISGD3mOMS0xWcEKRLKimTZQwwpqoMUKCjU/a/brYZbGFhwAA" + 49 | "AAEwAAAAATAAAAABMAAAAAEwAAAAATAAAAABMAAAAAAAAAAKMTg3Mjc0NTYyNgAA" + 50 | "AAAAAAAAAAAAAAAAAAEwAAAAATAAAAAAAAAAAAAAAAEzAAAAATAAAAAAAAAAATEA" + 51 | "AAABMAAAAAAAAAAAAAAACjEzNzMwNzcxMDRBQ0NUAAABdwAAAAoxODcyNzQ1NjM2" + 52 | "AAAAISEb4m77GfIOvO6fYzktw4aSDOxy8gpxjuR2oD6imAeoiAAAACEh5kDr0YH/" + 53 | "YfHah6DgyCpwbVul9y9CBylEcXENkY8LUYoAAABINjg3NDc0NzAzYTJmMmY2ODY5" + 54 | "NmU3NDdhNzA3MjZmNjg2MTczNmI2MTJlNjI2OTdhMmY3NzYxNjQ2NTJlNjY2OTcz" + 55 | "Njg2NTcyAAAAAAAAAAEwAAAAAAAAACEh2LKP6v5jYlQ6/0yaS4D+u2fLAxJS1BYE" + 56 | "ebH/nwnm+NEAAAAhIbGahlE1a7dDksJcUScFfpGDWVbh6eA2FL5ZQiQJe3SOAAAA" + 57 | "ATAAAAABMAAAAAEwAAAAATAAAAABMAAAAAEwAAAAAAAAAAoxODcyNzQ1NjM2AAAA" + 58 | "AAAAAAAAAAAAAAAAATAAAAABMAAAAAAAAAAAAAAAATQAAAABMAAAAAAAAAABMQAA" + 59 | "AAEwAAAAAAAAAAAAAAAKMTM3MzA3NzEwNEFDQ1QAAAFJAAAACjE4NzI3NDU2NDYA" + 60 | "AAAhIddUR3tvwQP0CiQGZ5nIN5AOu41QtVQQkiLlDXgC67C6AAAAAAAAADw2ODc0" + 61 | "NzQ3MDNhMmYyZjczNjM2ODc1NmM3NDdhNjg2NTYxNmU2NTc5MmU2ZjcyNjcyZjYx" + 62 | "NzI3NjY5NjQAAAAAAAAAATAAAAAAAAAAISEgjlPSKxJIaxzS4LtJ0h/WuXA+SzFk" + 63 | "+xq3PIoHE01ujQAAACEhLoYYeDLOwdf2vewKK49rZ9zDR2iTxjzB5ci5L7LdIewA" + 64 | "AAABMAAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAAAAAAAAAACjE4NzI3NDU2NDYA" + 65 | "AAAAAAAAAAAAAAAAAAABMAAAAAEwAAAAAAAAAAAAAAAAAAAAATAAAAAAAAAAATEA" + 66 | "AAABMAAAAAAAAAAAAAAACjEzNzMwNzcxMDRBQ0NUAAABcQAAAAoxODcyNzQ1NjU2" + 67 | "AAAAMSE6dpn4QFzEtGAOF0pnukMsy7MxHQkCHkPBc2WfDpPBNd+mqJoIUr4xn9Os" + 68 | "JLw6JHwAAAAhIa6Z2iLXCdY1FusJuahlVQ12V3AQ1xtx907dhrnLNb2RAAAAMjY4" + 69 | "NzQ3NDcwM2EyZjJmNzM3NDcyNjU2OTYzNjgyZTYzNmY2ZDJmNzI2MTZkNmY2ZTYx" + 70 | "AAAAAAAAAAEwAAAAAAAAACEhFjUkwX6BtmttaI8Xjeh7A4hfdzheEDvQl6ERKI/j" + 71 | "rFMAAAAhIY41/x6H8yJBXBKtRQWNLWdH1RhXe4tsalNPqFtVEFs2AAAAATAAAAAB" + 72 | "MAAAAAEwAAAAATAAAAABMAAAAAEwAAAAAAAAAAoxODcyNzQ1NjU2AAAAAAAAAAAA" + 73 | "AAAAAAAAATAAAAABMAAAAAAAAAAAAAAAATUAAAABMAAAAAAAAAABMQAAAAEwAAAA" + 74 | "AAAAAAAAAAAKMTM3MzA3NzEwNEFDQ1QAAAFnAAAACjE4NzI3NDU2NjYAAAAhIbaO" + 75 | "iTkfVFko62wOMqoFlk31KC/H4OafgmPG3Aq9Ovg1AAAAISEI9XR+O3ru13RyvgXP" + 76 | "IxvtUDWxbbN+9XewE/4vBxaSwQAAACg2ODc0NzQ3MDNhMmYyZjYzNmY2ZTZlMmU2" + 77 | "ZTY1NzQyZjZjNjU2NDYxAAAAAAAAAAEwAAAAAAAAADEhLVUiK630YW+SH5XRQHQ/" + 78 | "CTRgla8u9KY0uCtV9pw9jqppQaA8EEWIbUUxKdE9ZanFAAAAISGtYcBXZ53fKC4W" + 79 | "W7zFZ8OzVP8HE2SX0EBle6AWtVic4wAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAA" + 80 | "AAABMAAAAAAAAAAKMTg3Mjc0NTY2NgAAAAAAAAAAAAAAAAAAAAEwAAAAATAAAAAA" + 81 | "AAAAAAAAAAE2AAAAATAAAAAAAAAAATEAAAABMAAAAAAAAAAAAAAACjEzNzMwNzcx" + 82 | "MDRBQ0NUAAABgQAAAAoxODcyNzQ1Njc2AAAAMSHLwsXqutzkzUtQO/qEkwAFxlzV" + 83 | "5P54THEqk12GeVRbGvasMv6m7w78Y5YKy7F0VUIAAAAhIZgyLh1/l1Zon+Sgd+3A" + 84 | "BJ6hc2K6KzI24AwxcC7/LCTyAAAAMjY4NzQ3NDcwM2EyZjJmNjM2ZjZlNzI2Zjc5" + 85 | "MmU2MjY5N2EyZjdhNjE2MzY4NjU3Mjc5AAAAAAAAAAEwAAAAAAAAACEhbhLO4orM" + 86 | "Ku6oUkegA3ItB77rckAc3sQwE5t0R7q8xHQAAAAxId+80ASeTkbv+0oDEV7dfe1n" + 87 | "oEKmVoutR6C50RUTR4s/s5fQdAt/NjqkKJ8GObagtQAAAAEwAAAAATAAAAABMAAA" + 88 | "AAEwAAAAATAAAAABMAAAAAAAAAAKMTg3Mjc0NTY3NgAAAAAAAAAAAAAAAAAAAAEw" + 89 | "AAAAATAAAAAAAAAAAAAAAAE3AAAAATAAAAAAAAAAATEAAAABMAAAAAAAAAAAAAAA" + 90 | "CjEzNzMwNzcxMDRBQ0NUAAABSwAAAAoxODcyNzQ1Njg2AAAAISGeWePdN9riofiB" + 91 | "vPXaNOxmNQTL7EkUxBTlR9ODSHHv+wAAAAAAAAAuNjg3NDc0NzAzYTJmMmY2YjY5" + 92 | "Njg2ZTJlNmY3MjY3MmY2MzYxNmU2NDY5NjM2NQAAAAAAAAABMAAAAAAAAAAxIZla" + 93 | "rXv+gtjIVVR/6cC9sytjKe+IjvJL2ezKP3oxEeCJOiJITo86/Furu374noD7rQAA" + 94 | "ACEhWuB+ckZ0FcvD2FXotyKjwHPIFI5a+Yy7Sct/whk+tccAAAABMAAAAAEwAAAA" + 95 | "ATAAAAABMAAAAAEwAAAAATAAAAAAAAAACjE4NzI3NDU2ODYAAAAAAAAAAAAAAAAA" + 96 | "AAABMAAAAAEwAAAAAAAAAAAAAAAAAAAAATAAAAAAAAAAATEAAAABMAAAAAAAAAAA" + 97 | "AAAACjEzNzMwNzcxMDRBQ0NUAAABbwAAAAoxODcyNzQ1Njk2AAAAISHFwj2xbX71" + 98 | "uPcF5SZ4bl5e0MIImDPxZqEE0t1T7j+sUQAAACEh+gZl1yfJkchbuZ3oaPGjwUNR" + 99 | "k/np5HlQaqidnepJnvkAAAAwNjg3NDc0NzAzYTJmMmY2NzZjNmY3NjY1NzIyZTZl" + 100 | "NjE2ZDY1MmY2YTY1NzI2MTY0AAAAAAAAAAEwAAAAAAAAACEhWejYIS8GCFp/GkGH" + 101 | "wGdTNj/WPIkshtOCZXUuRjcBDN4AAAAxIWYXzKArUH5hAhqE+bbZvOp9cz6/mUEt" + 102 | "Yw/n0eKACZQKC4RjdZEEXA4UllYuX3c0NwAAAAEwAAAAATAAAAABMAAAAAEwAAAA" + 103 | "ATAAAAABMAAAAAAAAAAKMTg3Mjc0NTY5NgAAAAAAAAAAAAAAAAAAAAEwAAAAATAA" + 104 | "AAAAAAAAAAAAAAE4AAAAATAAAAAAAAAAATEAAAABMAAAAAAAAAAAAAAACjEzNzMw" + 105 | "NzcxMDRBQ0NUAAABcQAAAAoxODcyNzQ1NzA2AAAAISGorY0SSNF696WwYJcxsdFw" + 106 | "D6m2A6ZCkFFzx3v2MBnvEwAAACEhpa8+NWZoYBtoIXi7dUGa+JQbki+uG+vuHPpp" + 107 | "iYEcHxcAAAAyNjg3NDc0NzAzYTJmMmY2ZDYxNzk2NTcyNzQyZTZlNjE2ZDY1MmY2" + 108 | "YTY1NzI2ZjZkNzkAAAAAAAAAATAAAAAAAAAAMSF908guDN8hOUdYwC3tYSpo4PFf" + 109 | "yxNyzfmvW8k83zWY9Hd+QbbHHSjE5XTWAaxisfkAAAAhIdTFya25L9w4T6NH3aRm" + 110 | "P2aMRNqVXhk+91WWKPElSpseAAAAATAAAAABMAAAAAEwAAAAATAAAAABMAAAAAEw" + 111 | "AAAAAAAAAAoxODcyNzQ1NzA2AAAAAAAAAAAAAAAAAAAAATAAAAABMAAAAAAAAAAA" + 112 | "AAAAATkAAAABMAAAAAAAAAABMQAAAAEwAAAAAAAAAAAAAAAKMTM3MzA3NzEwNEFD" + 113 | "Q1QAAAFHAAAACjE4NzI3NDU3MTYAAAAhIXmUu59nSkkwpim5xZUX/B42qd4Z3H3l" + 114 | "8ZKDSxxZfqL5AAAAAAAAADo2ODc0NzQ3MDNhMmYyZjczNjE2ZTY2NmY3MjY0Nzc3" + 115 | "NTZlNzM2MzY4MmU2ZjcyNjcyZjYxNmM2NTZiAAAAAAAAAAEwAAAAAAAAACEhlYwT" + 116 | "HOBJy4TB4DjN4cgm/uH6ktEhYOEC33fQK/6Ew9cAAAAhIS2ehBFomoqThSf9tLV6" + 117 | "mlsBKPU9HimyVJ1apJAuBr8qAAAAATAAAAABMAAAAAEwAAAAATAAAAABMAAAAAEw" + 118 | "AAAAAAAAAAoxODcyNzQ1NzE2AAAAAAAAAAAAAAAAAAAAATAAAAABMAAAAAAAAAAA" + 119 | "AAAAAAAAAAEwAAAAAAAAAAExAAAAATAAAAAAAAAAAAAAAAoxMzczMDc3MTA0QUND" + 120 | "VAAAAYAAAAAKMTg3Mjc0NTcyNgAAACEhGMiPj9rwna8pqHwjeIpTwp+YcOs5ihke" + 121 | "WGiMXBl1edMAAAAhIQAztK0yhhOnVcnIDeqfN4VELzpZqrmq5u4XU7HCgvZXAAAA" + 122 | "QDY4NzQ3NDcwM2EyZjJmNmM2NTY4NmU2NTcyMmU2MjY5N2EyZjczNzQ2MTZlNmM2" + 123 | "NTc5MmU2NDZmNmY2YzY1NzkAAAAAAAAAATAAAAAAAAAAMSGlEEN0n+XAbvFb0tvd" + 124 | "UmIIsbeS1pGdnDEXHeH/d+0DZAJlNMgAYUWmVf39dp+1HTsAAAAhIemJWGnMPw2k" + 125 | "juEmHhbeEMtY67afvWj1PfccOzEPBQs8AAAAATAAAAABMAAAAAEwAAAAATAAAAAB" + 126 | "MAAAAAEwAAAAAAAAAAoxODcyNzQ1NzI2AAAAAAAAAAAAAAAAAAAAATAAAAABMAAA" + 127 | "AAAAAAAAAAAAAjEwAAAAATAAAAAAAAAAATEAAAABMAAAAAAAAAAAAAAACjEzNzMw" + 128 | "NzcxMDRBQ0NUAAABcAAAAAoxODcyNzQ1NzM2AAAAISGs1uDBvUMCJm1J1x+5iNEE" + 129 | "i/i+XX0B9Yf2tadKy+U3+AAAACEhG1dTn17o1/ymRQgpn2oI+xZ36+3H3N6eXgRK" + 130 | "hcadeWQAAAAwNjg3NDc0NzAzYTJmMmY3MjZmNmM2NjczNmY2ZTJlNmU2NTc0MmY2" + 131 | "YTYxNjQ2NTZlAAAAAAAAAAEwAAAAAAAAACEhg9tVLX+90vps5qXkR0alKpJq7Obq" + 132 | "E/jOwi2q6vNmy90AAAAxIWSApHuog5j4KelzaTNUloHzZX/yl1csGWvDr94aN+TN" + 133 | "kIX0wbfFFD/3sLrIm3zo9wAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAAAAABMAAA" + 134 | "AAAAAAAKMTg3Mjc0NTczNgAAAAAAAAAAAAAAAAAAAAEwAAAAATAAAAAAAAAAAAAA" + 135 | "AAIxMQAAAAEwAAAAAAAAAAExAAAAATAAAAAAAAAAAAAAAAoxMzczMDc3MTA0QUND" + 136 | "VAAAAX4AAAAKMTg3Mjc0NTc0NgAAACEhyxtMnSycw7Agyf8otQJ4l3+dBGGxmiwv" + 137 | "hPQBVbIZChUAAAAhIeCFWsm5ZAR1oSKwDvuq968uKEWrG8yeHg/z+DjB+LSJAAAA" + 138 | "PjY4NzQ3NDcwM2EyZjJmNjY2MTY4NjU3OTJlNmU2MTZkNjUyZjZhNmY2ZTVmNjE2" + 139 | "ZTZiNzU2ZTY0Njk2ZTY3AAAAAAAAAAEwAAAAAAAAADEhnoNgy2MYpZqChvAvuUK6" + 140 | "CBUyZW+13hF920UkRWeztghueq9SQpgflbmcJRZNHPH/AAAAISGSz84xg3A6AJQF" + 141 | "9IYAiRWm+6aAo+Elx7nHUnTOSJClvwAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAA" + 142 | "AAABMAAAAAAAAAAKMTg3Mjc0NTc0NgAAAAAAAAAAAAAAAAAAAAEwAAAAATAAAAAA" + 143 | "AAAAAAAAAAIxMgAAAAEwAAAAAAAAAAExAAAAATAAAAAAAAAAAAAAAAoxMzczMDc3" + 144 | "MTA0QUNDVAAAAYwAAAAKMTg3Mjc0NTc1NgAAADEhGIdprJWxd/VPfw+rLbbq2U9E" + 145 | "OJ8fmmafAUinE9mJh2Piw0Dt5wC1NRLcrpnUCPxtAAAAISG53FZfu7sXpOcq9n83" + 146 | "vL85SAKSnrEO1I12DwMNs/sV6gAAADw2ODc0NzQ3MDNhMmYyZjc0NzI2NTc1NzQ2" + 147 | "NTZjNmI2OTY1Njg2ZTJlNmY3MjY3MmY2ZDYxNzI2MzZmNzMAAAAAAAAAATAAAAAA" + 148 | "AAAAMSF67pO4h3QqKy9FFhKpxihsjI9MG0b4ANOsekIBuXdvBg0usIZqRskzySD9" + 149 | "m3sqM/cAAAAhIV16dEXwW0dpTkKFa2SMXToJBWjH6g6WcNdSUtOv6JUUAAAAATAA" + 150 | "AAABMAAAAAEwAAAAATAAAAABMAAAAAEwAAAAAAAAAAoxODcyNzQ1NzU2AAAAAAAA" + 151 | "AAAAAAAAAAAAATAAAAABMAAAAAAAAAAAAAAAAjEzAAAAATAAAAAAAAAAATEAAAAB" + 152 | "MAAAAAAAAAAAAAAACjEzNzMwNzcxMDRBQ0NUAAABYgAAAAoxODcyNzQ1NzY2AAAA" + 153 | "ISE2rzBtquT4KbKDNIgBZcTpY5Wqq0OFt+65lvoBOqTuCQAAACEhRMvVlJen73am" + 154 | "EgLBa3i4+mb7Er3+PWfNPVkXOBD46JAAAAAyNjg3NDc0NzAzYTJmMmY2YzY1NjY2" + 155 | "NjZjNjU3MjJlNjk2ZTY2NmYyZjYzNjg2MTc5NjEAAAAAAAAAATAAAAAAAAAAISFk" + 156 | "bW//Ga0ZSLaQuduBTr2wQg3994ZlVS23PLrmoTC/IQAAACEhmeVc7QeEZez1ql1p" + 157 | "gi8xykwV4BZKzF7E0onW2oAOvgwAAAABMAAAAAEwAAAAATAAAAABMAAAAAEwAAAA" + 158 | "ATAAAAAAAAAACjE4NzI3NDU3NjYAAAAAAAAAAAAAAAAAAAABMAAAAAEwAAAAAAAA" + 159 | "AAAAAAACMTQAAAABMAAAAAAAAAABMQAAAAEwAAAAAAAAAAAAAAAKMTM3MzA3NzEw" + 160 | "NEFDQ1QAAAFNAAAACjE4NzI3NDU3NzYAAAAhIZ/uatMIc0Y2ZF+LbZUuisLpWNE7" + 161 | "sEOLNUl14Yec8qqCAAAAAAAAAEA2ODc0NzQ3MDNhMmYyZjYyNzI2MTZiNzU3Mzc3" + 162 | "Njk2YzZjNjk2MTZkNzM2ZjZlMmU2MzZmNmQyZjYyNzI2NTc0AAAAAAAAAAEwAAAA" + 163 | "AAAAACEhiZ6UHPLcSrKVLRzKlOuAhhPGr5H39GJ17j2ZdmtBWkcAAAAhIYsZHdIB" + 164 | "gMIwDgqGpbmG2mrwHeHlnqCYo4d+ev8txvTiAAAAATAAAAABMAAAAAEwAAAAATAA" + 165 | "AAABMAAAAAEwAAAAAAAAAAoxODcyNzQ1Nzc2AAAAAAAAAAAAAAAAAAAAATAAAAAB" + 166 | "MAAAAAAAAAAAAAAAAAAAAAEwAAAAAAAAAAExAAAAATAAAAAAAAAAAAAAAAoxMzcz" + 167 | "MDc3MTA0QUNDVAAAAZwAAAAKMTg3Mjc0NTc4NgAAADEhmciPQ/oX/XcoxHJBR5XZ" + 168 | "aSif1w2DU56kUZIjGmyYlank2qlK0S3IUcNQwAGo6W4FAAAAISHbIP/rAq2WzcM7" + 169 | "qfes+H2rd6xRVwiZfDsa4npC5QhAqgAAAEw2ODc0NzQ3MDNhMmYyZjZiNzU2ZTdh" + 170 | "NjU2ZjZiNzU2ZTY1NzY2MTJlNjk2ZTY2NmYyZjczNjg2MTc3NmU1ZjZjNjE2ZTY3" + 171 | "NmY3MzY4AAAAAAAAAAEwAAAAAAAAADEh1rZcvQLPDGfwFLS9m+xB8pkTT2s8R8hS" + 172 | "+KkGHNkBlUuvWijoE8o/d4SZjG4aeKMXAAAAISFBViTLvTjoM4/4f47d4Eazeh4i" + 173 | "qBE9UaeH/bEV2nbxnQAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAAAAABMAAAAAAA" + 174 | "AAAKMTg3Mjc0NTc4NgAAAAAAAAAAAAAAAAAAAAEwAAAAATAAAAAAAAAAAAAAAAIx" + 175 | "NQAAAAEwAAAAAAAAAAExAAAAATAAAAAAAAAAAAAAAAoxMzczMDc3MTA0QUNDVAAA" + 176 | "AUEAAAAKMTg3Mjc0NTc5NgAAACEh9+j0st/9S+BQB2EEkgeDi2QaltidD5q7jC4D" + 177 | "kHPkQZMAAAAAAAAANDY4NzQ3NDcwM2EyZjJmNjM3MjZmNmY2YjczMmU2MzZmNmQy" + 178 | "ZjczNjE2ZTY0NzI2OTZlNjUAAAAAAAAAATAAAAAAAAAAISEw8Nau8j29pJuVu1Yn" + 179 | "+5rgPeNeRWEuQwmgf9vGzA6vmAAAACEhFBedhEe9UqyYRjmWZYflGqQvkTcxFcN/" + 180 | "QlM4e48oZ6AAAAABMAAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAAAAAAAAAACjE4" + 181 | "NzI3NDU3OTYAAAAAAAAAAAAAAAAAAAABMAAAAAEwAAAAAAAAAAAAAAAAAAAAATAA" + 182 | "AAAAAAAAATEAAAABMAAAAAAAAAAAAAAACjEzNzMwNzcxMDRBQ0NUAAABgAAAAAox" + 183 | "ODcyNzQ1ODA2AAAAISHgFLmEN8n3CujAwhp9Ovukvkz5V7+CmIjkOi+dkxKuNgAA" + 184 | "ACEh9OBhtr31mJFvWcbHNMCAd44KqzXIvgLiHPE+sbY6z/AAAAAwNjg3NDc0NzAz" + 185 | "YTJmMmY2YjY1NmQ2ZDY1NzIyZTZmNzI2NzJmNjg2OTZjNzQ2ZjZlAAAAAAAAAAEw" + 186 | "AAAAAAAAADEhrP3NRn7628agNyO/QQZxNF5s6kRH2lhndFMFxVX/8pkTkIcPGcTA" + 187 | "lYRjrVWDBu7JAAAAMSE32B39KTGTPxbh2PkQqhbi75qsIfRgD4zPw96Sq5ckf7ER" + 188 | "pv1ra7omvV0wVbeBV84AAAABMAAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAAAAAA" + 189 | "AAAACjE4NzI3NDU4MDYAAAAAAAAAAAAAAAAAAAABMAAAAAEwAAAAAAAAAAAAAAAC" + 190 | "MTYAAAABMAAAAAAAAAABMQAAAAEwAAAAAAAAAAAAAAAKMTM3MzA3NzEwNEFDQ1QA" + 191 | "AAGYAAAACjE4NzI3NDU4MTYAAAAxIaZRSACBHI6LWMPcUbL9BDPJBA6ezXxodjYX" + 192 | "eeQnS5jHd3JWW5yQ5juFLioSS+0vcgAAACEhTbCYIRlc8Vp5a6MnPhZwN61RXsZ1" + 193 | "RLLrB/lPKTSvlyoAAABINjg3NDc0NzAzYTJmMmY3NDcyNmY2ZDcwNjI2NTcyNmU2" + 194 | "ODYxNzI2NDJlNjM2ZjZkMmY3NDcyNjU2MTJlNjg2OTcyNzQ2ODY1AAAAAAAAAAEw" + 195 | "AAAAAAAAADEhM3Y9D0SUShS0/StfAeN5ZCCxs0NxNSnI5HkKJsrVy/Z3XpgPuBDJ" + 196 | "MTOCczoM5/qhAAAAISHrEm5JWCe27yo+OyGBv2YsDhh1XGM7OdB+wYRBmc2uaAAA" + 197 | "AAEwAAAAATAAAAABMAAAAAEwAAAAATAAAAABMAAAAAAAAAAKMTg3Mjc0NTgxNgAA" + 198 | "AAAAAAAAAAAAAAAAAAEwAAAAATAAAAAAAAAAAAAAAAIxNwAAAAEwAAAAAAAAAAEx" + 199 | "AAAAATAAAAAAAAAAAAAAAAoxMzczMDc3MTA0QUNDVAAAAZQAAAAKMTg3Mjc0NTgy" + 200 | "NgAAADEhIimFHCGaaVBOe0mBxijAWbsc5rn5jkSsmIoJBV8i+zCrFKH/tC4ZCtly" + 201 | "gczOpZj9AAAAISFAbpg8zACxOEHkUeKFepaecFumI2KadyBznEhWmnlFIQAAADQ2" + 202 | "ODc0NzQ3MDNhMmYyZjc1NmM2YzcyNjk2MzY4MmU2OTZlNjY2ZjJmNjM2MTcyNmM2" + 203 | "NTY1AAAAAAAAAAEwAAAAAAAAADEhUIKf99JmmX098GrUfxHr6/NLv8WU9UEGlZ1W" + 204 | "KCd/08iqfS/2MqwUXoYCZ/3K+eEGAAAAMSGVA3zC9wpvKaAdTWTDyqVQiwQ35Ov8" + 205 | "em8JA1fpb1gZNLB3JKLRxt7WHl85Eb2KxqAAAAABMAAAAAEwAAAAATAAAAABMAAA" + 206 | "AAEwAAAAATAAAAAAAAAACjE4NzI3NDU4MjYAAAAAAAAAAAAAAAAAAAABMAAAAAEw" + 207 | "AAAAAAAAAAAAAAACMTgAAAABMAAAAAAAAAABMQAAAAEwAAAAAAAAAAAAAAAKMTM3" + 208 | "MzA3NzEwNEFDQ1QAAAFwAAAACjE4NzI3NDU4MzYAAAAhIcJw1qL5OWA5gHmfeSRP" + 209 | "a1u2OacvtgC0gN2nqh2lP2TYAAAAISHVhEe8XadXg2zF535/xOvaMJqaxuT/L7D1" + 210 | "10cxoVuVIgAAAEA2ODc0NzQ3MDNhMmYyZjcyNjk3MDcwNjk2ZTJlNmU2MTZkNjUy" + 211 | "ZjYyNmY2ZTY5NzQ2MTVmNjg2OTYzNmI2YzY1AAAAAAAAAAEwAAAAAAAAACEhvzjc" + 212 | "4db86CZmTzxTpe3n4EK7H2Gvg7PnKaxv8khTx+AAAAAhIUoEgdRme2H4ahRTxfzR" + 213 | "KTYV2+BySfdStWnvP2zsvUfvAAAAATAAAAABMAAAAAEwAAAAATAAAAABMAAAAAEw" + 214 | "AAAAAAAAAAoxODcyNzQ1ODM2AAAAAAAAAAAAAAAAAAAAATAAAAABMAAAAAAAAAAA" + 215 | "AAAAAjE5AAAAATAAAAAAAAAAATEAAAABMAAAAAAAAAAAAAAACjEzNzMwNzcxMDRB" + 216 | "Q0NUAAABsgAAAAoxODcyNzQ1ODU2AAAAMSHIhRWCbYpBTEn7oVMBuJH8u78b40Z2" + 217 | "tw7qPSpOi/los3O+MN+ckeyBRQafSSmO49YAAAAhIdcAclA642w11ibw/3sVFWLi" + 218 | "brQ+UvzSwVlhBlYuDQdnAAAAYjY4NzQ3NDcwM2EyZjJmNjE3NTY2NjQ2NTcyNjg2" + 219 | "MTcyNzI3NTZlNmY2YzY2NzM2NDZmNzQ3NDY5NzIyZTY5NmU2NjZmMmY2NjY1NmM2" + 220 | "OTYzNjk2MTVmNzQ2ZjcyNzA2ODc5AAAAAAAAAAEwAAAAAAAAADEh9TfrO+Fwvhby" + 221 | "J/AXH2f1Lm+2FgRR8otkUz6ofiY8IZKuGzfcnpVgTxFtVha8Gki1AAAAISHKG4L5" + 222 | "CqgDQtGSNcLF+0wgd6ggfqryIT4aW4ZzbJOSXwAAAAEwAAAAATAAAAABMAAAAAEw" + 223 | "AAAAATAAAAABMAAAAAAAAAAKMTg3Mjc0NTg1NgAAAAAAAAAAAAAAAAAAAAEwAAAA" + 224 | "ATAAAAAAAAAAAAAAAAIyMAAAAAEwAAAAAAAAAAExAAAAATAAAAAAAAAAAAAAAAox" + 225 | "MzczMDc3MTA0QUNDVAAAAXgAAAAKMTg3Mjc0NTg2NgAAACEhQE1Ye79tC4KS/FAz" + 226 | "PyHjDV6xuCpJuqa7nNDJxmEc7k4AAAAhIQNekQjGv4ewrI6iEdRe63wx7oygqQVx" + 227 | "UsQ3A4+otWeXAAAAODY4NzQ3NDcwM2EyZjJmNmM2ZjYzNmI2ZDYxNmU2Yzc5NmU2" + 228 | "MzY4MmU2ZTY1NzQyZjYxNmM2MjYxAAAAAAAAAAEwAAAAAAAAADEhplJ5oQspBCJX" + 229 | "J96eppbg1dhBqk64ImC0Le9niB0AJRuhUWGuCwqQs7++dir4ogYkAAAAISEgTMF5" + 230 | "pv4GQ1KpVSr2rShvLkSaBHvzFvo/hVdjNqR6zQAAAAEwAAAAATAAAAABMAAAAAEw" + 231 | "AAAAATAAAAABMAAAAAAAAAAKMTg3Mjc0NTg2NgAAAAAAAAAAAAAAAAAAAAEwAAAA" + 232 | "ATAAAAAAAAAAAAAAAAIyMQAAAAEwAAAAAAAAAAExAAAAATAAAAAAAAAAAAAAAAox" + 233 | "MzczMDc3MTA0QUNDVAAAAZoAAAAKMTg3Mjc0NTg3NgAAADEhRMdg8/tq4PEVYWVK" + 234 | "wMo0WEN3Yur3AX7lun+Kn7eS5aFf3GzaAAJIOpniDbupf1oZAAAAISEvuWGKizfq" + 235 | "8zJybfTlt7GGaybp50DqxCCwIw4kC/GULwAAAEo2ODc0NzQ3MDNhMmYyZjYzNjE3" + 236 | "MjcyNmY2YzZjNzM2MzY4NmQ2OTc0NzQyZTYzNmY2ZDJmNzc2OTZjNmM3OTJlNjU2" + 237 | "ZDYxNzI2NAAAAAAAAAABMAAAAAAAAAAxIRGwGqXCb3tWMdTM0MevrA7izlSGq7R7" + 238 | "QdHxlBvyX+sTKwF8q/U4bgaBfGOjdYKnWwAAACEhgPjXbuVA+QuUToPd/VpkP+v/" + 239 | "B4yv4WrA1lbhDiQlYUYAAAABMAAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAAAAAA" + 240 | "AAAACjE4NzI3NDU4NzYAAAAAAAAAAAAAAAAAAAABMAAAAAEwAAAAAAAAAAAAAAAC" + 241 | "MjIAAAABMAAAAAAAAAABMQAAAAEwAAAAAAAAAAAAAAAKMTM3MzA3NzEwNEFDQ1QA" + 242 | "AAGIAAAACjE4NzI3NDU4ODYAAAAxIVR6nvORUDTzLM2ccDbg4X5xWSwcd7lWUkpz" + 243 | "TQkzgdvtshGthLiBgr9KWDPGkk70qQAAACEhQV3F6awFZJ/iHgqhmCccSxPo87Lp" + 244 | "zYADyrvDzVm3iMoAAAA4Njg3NDc0NzAzYTJmMmY2NjY1Njk2YzJlNmU2NTc0MmY2" + 245 | "ZTYxNzQ2MTczNjg2MTVmNjg2Zjc3NjUAAAAAAAAAATAAAAAAAAAAMSGifN07AIi3" + 246 | "wSxPhnXERybIV55e1BewQMDTczO6f+UEM5JD3LHBg9x+i8rjjaWrOzEAAAAhIQdz" + 247 | "q3+v8HjcJKUc7xb9+6NSLWKo+w7sTAPbF8hMm3Y+AAAAATAAAAABMAAAAAEwAAAA" + 248 | "ATAAAAABMAAAAAEwAAAAAAAAAAoxODcyNzQ1ODg2AAAAAAAAAAAAAAAAAAAAATAA" + 249 | "AAABMAAAAAAAAAAAAAAAAjIzAAAAATAAAAAAAAAAATEAAAABMAAAAAAAAAAAAAAA" + 250 | "CjEzNzMwNzcxMDRBQ0NUAAABUwAAAAoxODcyNzQ1ODk2AAAAISHcbMpS37UtrNiw" + 251 | "y7aZoDB2jKY5VKeJbF73QFU4lJskdAAAAAAAAABGNjg3NDc0NzAzYTJmMmY2NzZj" + 252 | "NjU2MTczNmY2ZTZhNjE2Yjc1NjI2Zjc3NzM2YjY5MmU2MjY5N2EyZjYxNzU2Nzc1" + 253 | "NzM3NAAAAAAAAAABMAAAAAAAAAAhIeeo3o1u8KJySEwNzY1v008/rDUxNBMjjVdz" + 254 | "j7FSbCYfAAAAISH6pvRafbbMtp1AI7hJ0fjdVPajOsrRFVqhqo1diIgbHAAAAAEw" + 255 | "AAAAATAAAAABMAAAAAEwAAAAATAAAAABMAAAAAAAAAAKMTg3Mjc0NTg5NgAAAAAA" + 256 | "AAAAAAAAAAAAAAEwAAAAATAAAAAAAAAAAAAAAAAAAAABMAAAAAAAAAABMQAAAAEw" + 257 | "AAAAAAAAAAAAAAAKMTM3MzA3NzEwNEFDQ1QAAAGeAAAACjE4NzI3NDU5MDYAAAAx" + 258 | "IW61eKunz6Xb4Arymj5hAv9f56jTEJlVZPSBinxGShzXBas3bTjIGRhbkTekskND" + 259 | "RwAAACEhz+hKrf51+vOL+g8fvuyJSPKCcx73WEAB1dUn8u+kBXsAAABONjg3NDc0" + 260 | "NzAzYTJmMmY3NzY5NmM2YjY5NmU3MzZmNmU2YzY1NjE2ZTZlNmY2ZTJlNmU2MTZk" + 261 | "NjUyZjYyNzU2NDJlNzc2OTZjNmM2ZDczAAAAAAAAAAEwAAAAAAAAADEhhnDGWano" + 262 | "GhnwVsEjnH5YvPW55hjLi+5m8VPp873jbrOMVe4eSgMOMdz6R81V2Y6lAAAAISGP" + 263 | "ckyidKNfVX0l6wB/sUr+zDonEkt8ph94HsaXXsHLLgAAAAEwAAAAATAAAAABMAAA" + 264 | "AAEwAAAAATAAAAABMAAAAAAAAAAKMTg3Mjc0NTkwNgAAAAAAAAAAAAAAAAAAAAEw" + 265 | "AAAAATAAAAAAAAAAAAAAAAIyNAAAAAEwAAAAAAAAAAExAAAAATAAAAAAAAAAAAAA" + 266 | "AAoxMzczMDc3MTA0QUNDVAAAAX4AAAAKMTg3Mjc0NTkxNgAAACEhIxXNy4pUbU8z" + 267 | "w0LfG59qS38wa8sY0Ho/iV07I/hdHZ0AAAAhIdKPEper6levT1HDFcjEeXaeY8sv" + 268 | "CTU43zixIgF49gXIAAAALjY4NzQ3NDcwM2EyZjJmNzA3MjY5NjM2NTJlNjk2ZTY2" + 269 | "NmYyZjc1NzI2MjYxNmUAAAAAAAAAATAAAAAAAAAAMSHZiSutgWI+cIm313+M9xet" + 270 | "6yzJPYpF8/h32rZnfM5qUO0bCsZXenRPqGSpX5pFAokAAAAxIah32aDNd/L41Lzh" + 271 | "lLgFmiKL36FNdW4J7QoODBtBEo+haSrtiEFNuJYTZfNdEDCSaQAAAAEwAAAAATAA" + 272 | "AAABMAAAAAEwAAAAATAAAAABMAAAAAAAAAAKMTg3Mjc0NTkxNgAAAAAAAAAAAAAA" + 273 | "AAAAAAEwAAAAATAAAAAAAAAAAAAAAAIyNQAAAAEwAAAAAAAAAAExAAAAATAAAAAA" + 274 | "AAAAAAAAAAoxMzczMDc3MTA0QUNDVAAAAVkAAAAKMTg3Mjc0NTkyNgAAACEhnHKG" + 275 | "ExBpHQpFwzERx1pvpUw9wGGmzdCy5I5JPO+LdhEAAAAAAAAATDY4NzQ3NDcwM2Ey" + 276 | "ZjJmNzA2MTc1NjM2NTZiNzQ3NTcyNjM2Zjc0NzQ2NTJlNmY3MjY3MmY2YjYxNjQ2" + 277 | "OTZlNWY2NzY5NjI3MzZmNmUAAAAAAAAAATAAAAAAAAAAISGAcKkcAZQQeQBS77Zg" + 278 | "d7KT4ox6vPScCpFCAqfGxyF0DQAAACEhF7CaZZbafKaUhk+fNE+xLweUfV16+9zP" + 279 | "HBSM2UBsWrcAAAABMAAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAAAAAAAAAACjE4" + 280 | "NzI3NDU5MjYAAAAAAAAAAAAAAAAAAAABMAAAAAEwAAAAAAAAAAAAAAAAAAAAATAA" + 281 | "AAAAAAAAATEAAAABMAAAAAAAAAAAAAAACjEzNzMwNzcxMDRBQ0NUAAABeAAAAAox" + 282 | "ODcyNzQ1OTM2AAAAMSG9wsGHAKAy1+C0KCxALbmYvKff3uz/VwB612HaOw2F+alp" + 283 | "I80cRPAODmEmIru4GmwAAAAhIZWsd0ncx3rwoCcZ9NeSOyye3O6BLsNk4noPSdkf" + 284 | "bpaHAAAAODY4NzQ3NDcwM2EyZjJmNzI3NTZlNzQ2NTJlNjM2ZjZkMmY2MzYxNmQ3" + 285 | "Mjc5NmUyZTY4NjE2ZTY1AAAAAAAAAAEwAAAAAAAAACEhLMHRM5rsCrQu2F3GOVWA" + 286 | "Z2UFCixVGpdq83tnFrIk0h8AAAAhIe44XrrijvblrbT5iPzLMxWLud83cuXoy6mt" + 287 | "toZDlJF+AAAAATAAAAABMAAAAAEwAAAAATAAAAABMAAAAAEwAAAAAAAAAAoxODcy" + 288 | "NzQ1OTM2AAAAAAAAAAAAAAAAAAAAATAAAAABMAAAAAAAAAAAAAAAAjI2AAAAATAA" + 289 | "AAAAAAAAATEAAAABMAAAAAAAAAAAAAAACjEzNzMwNzcxMDRBQ0NUAAABigAAAAox" + 290 | "ODcyNzQ1OTQ2AAAAISF2yEkIfLl7Ajsf0YVp4pdwfLPebMHUjD5t1Z8zoxjeagAA" + 291 | "ACEhspchm7eXxpyy6CNinAtGNPThM5RFe/sVdNQ19pTXl0gAAAA6Njg3NDc0NzAz" + 292 | "YTJmMmY2Yjc1NmM2MTczNmI2YzY1Njk2ZTJlNjk2ZTY2NmYyZjZlNzk2MTczNjk2" + 293 | "MQAAAAAAAAABMAAAAAAAAAAxIS9HwLQWni0TBZMqQKmFdZ2oSvtDRFsTdqFe8P8c" + 294 | "Yk7NQJBt4lyYLnB63twUAeWEJwAAADEhvQVarcMhBEuu0ForhuAX8DIMl7CQfmDB" + 295 | "io/lvJPciLI6MJixWK9Tn6vOBMuLhSpJAAAAATAAAAABMAAAAAEwAAAAATAAAAAB" + 296 | "MAAAAAEwAAAAAAAAAAoxODcyNzQ1OTQ2AAAAAAAAAAAAAAAAAAAAATAAAAABMAAA" + 297 | "AAAAAAAAAAAAAjI3AAAAATAAAAAAAAAAATEAAAABMAAAAAAAAAAAAAAACjEzNzMw" + 298 | "NzcxMDRBQ0NUAAABggAAAAoxODcyNzQ1OTU2AAAAISEsQ5H+p6k+/lE3UtzgktRL" + 299 | "NuBOZ78szV04ZQhWqaLAcAAAACEh+4RkoGkaAOREFTBbkr+7j2kcFXdoUX9epm6e" + 300 | "hbaHxjcAAABCNjg3NDc0NzAzYTJmMmY3MzYzNjg2MTY1NjY2NTcyMmU2OTZlNjY2" + 301 | "ZjJmNmM2NTczNmM2OTY1MmU2MjZmNjc2MTZlAAAAAAAAAAEwAAAAAAAAADEh2FnB" + 302 | "pIHlJoXCCjBDYMPnFTgD93rhg/45CQphpCA7aeErTY6zBvwn+rTo4lVGsrrdAAAA" + 303 | "ISGRjWDv3wjtjdP4P9Z5WO/HQ8XJ5oCPMXEn1raT5ls97gAAAAEwAAAAATAAAAAB" + 304 | "MAAAAAEwAAAAATAAAAABMAAAAAAAAAAKMTg3Mjc0NTk1NgAAAAAAAAAAAAAAAAAA" + 305 | "AAEwAAAAATAAAAAAAAAAAAAAAAIyOAAAAAEwAAAAAAAAAAExAAAAATAAAAAAAAAA" + 306 | "AAAAAAoxMzczMDc3MTA0QUNDVAAAAXYAAAAKMTg3Mjc0NTk2NgAAACEhUYoAXo4M" + 307 | "zWu+MmrXMigKluN9UJtOrOA4WXbIWy/PbdIAAAAhIZxV+QFIyL1YG6PLx+ZnjL3p" + 308 | "tMq1wYU6g/7sr8or8Si7AAAARjY4NzQ3NDcwM2EyZjJmNmU2MTY0NjU3MjcyNjU2" + 309 | "ZDcwNjU2YzJlNmU2NTc0MmY2Nzc3NjU2ZTVmNzM2MzY4NmQ2OTY0NzQAAAAAAAAA" + 310 | "ATAAAAAAAAAAISHKTNAq4v2W12jAahJnG0LAIACiJA+7gyVNYN92upz3JAAAACEh" + 311 | "p5i1vp06RA/WhfZObM4wV3KcVliYGzHw/V4rlU0TosEAAAABMAAAAAEwAAAAATAA" + 312 | "AAABMAAAAAEwAAAAATAAAAAAAAAACjE4NzI3NDU5NjYAAAAAAAAAAAAAAAAAAAAB" + 313 | "MAAAAAEwAAAAAAAAAAAAAAACMjkAAAABMAAAAAAAAAABMQAAAAEwAAAAAAAAAAAA" + 314 | "AAAKMTM3MzA3NzEwNEFDQ1QAAAF8AAAACjE4NzI3NDU5NzYAAAAxId4VFZGCTWXr" + 315 | "j4xQXFpk8tcZsy3E6RGp9NbLrg9ZwQar9jrZv7ID1hwJsYXayPzdFAAAACEhF54x" + 316 | "UhH8yMXvFHi6ZCFmLAbB2lggCDQqIknhi8HM+1sAAAA8Njg3NDc0NzAzYTJmMmY2" + 317 | "NDZmNmY2YzY1NzkyZTY5NmU2NjZmMmY2MTZjNjU2YjVmNzA2MTcyNmI2NTcyAAAA" + 318 | "AAAAAAEwAAAAAAAAACEhAt8Mu6ecm7T+rGwHWfz68rIDJl24ac3ZH2QsNiYtcIEA" + 319 | "AAAhIQUx5F972yrpW+f9iPemLRfzZmEXTeddYh5FYgIIhoNqAAAAATAAAAABMAAA" + 320 | "AAEwAAAAATAAAAABMAAAAAEwAAAAAAAAAAoxODcyNzQ1OTc2AAAAAAAAAAAAAAAA" + 321 | "AAAAATAAAAABMAAAAAAAAAAAAAAAAjMwAAAAATAAAAAAAAAAATEAAAABMAAAAAAA" + 322 | "AAAAAAAACjEzNzMwNzcxMDRBQ0NUAAABkgAAAAoxODcyNzQ1OTg2AAAAMSFctg/x" + 323 | "qezfr1hwKzUCtxWN0TjN8ANA9ZbZUERX+/qLHJQup7o0Mj5XcpIpmAl0aWsAAAAh" + 324 | "IcGbzhx5ScC7b55/yvXtxwi/yG5gx4vg2bz6w9Q6G02qAAAAQjY4NzQ3NDcwM2Ey" + 325 | "ZjJmNmE2ZjY4NmU3MzJlNmU2MTZkNjUyZjYzNmY2Yzc1NmQ2Mjc1NzMyZTY0NmY2" + 326 | "ZjZjNjU3OQAAAAAAAAABMAAAAAAAAAAxIWLfo4j24vstNR/p8NYSrP+xHOy05DNx" + 327 | "vaB97a1r5gRApXnVDtAZzsOriidjgsXORwAAACEhzO+TfzZsgaSKkwVOPRk1m1WN" + 328 | "OzkviDjC0bj/je3cKg4AAAABMAAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAAAAAA" + 329 | "AAAACjE4NzI3NDU5ODYAAAAAAAAAAAAAAAAAAAABMAAAAAEwAAAAAAAAAAAAAAAC" + 330 | "MzEAAAABMAAAAAAAAAABMQAAAAEwAAAAAAAAAAAAAAAKMTM3MzA3NzEwNEFDQ1QA" + 331 | "AAF+AAAACjE4NzI3NDU5OTYAAAAxIUYf7M6iePmYVtOOdv0B9Mozb8cKmIFSbYwM" + 332 | "NOneeTpPEaP3TZIO2pkg0ga6SS2K4gAAACEhdi67SeZgy7Wr/mNaggGVaOnI0NcW" + 333 | "u6n/jJqMqL63lUQAAAAuNjg3NDc0NzAzYTJmMmY2MjYxNzU2MzY4MmU2ZjcyNjcy" + 334 | "ZjZkNjE3MjZjNjk2ZQAAAAAAAAABMAAAAAAAAAAhIWNxIegSHbcqsTw0CCV3gULh" + 335 | "V6Y2LRi6Vun+cbxazWq8AAAAMSEBSbLQTX2NKTwu+0TZNUwagKnHCMTHnw+Q3PCZ" + 336 | "t3CSOU9MPeEXl2a50drLEiRSIZAAAAABMAAAAAEwAAAAATAAAAABMAAAAAEwAAAA" + 337 | "ATAAAAAAAAAACjE4NzI3NDU5OTYAAAAAAAAAAAAAAAAAAAABMAAAAAEwAAAAAAAA" + 338 | "AAAAAAACMzIAAAABMAAAAAAAAAABMQAAAAEwAAAAAAAAAAAAAAAKMTM3MzA3NzEw" + 339 | "NEFDQ1QAAAFgAAAACjE4NzI3NDYwMDYAAAAhIUcBac23/F98Pwy/FSWJMGfEQVEr" + 340 | "Vmz8uJiW0ndhsHbVAAAAISGqxjmXDgHposEvOwIzXMM/wIPTaXmE6K2LMu+WvRBC" + 341 | "awAAADA2ODc0NzQ3MDNhMmYyZjY0NzU2Mjc1NzE3NTY1MmU2MzZmNmQyZjZhNjE2" + 342 | "MzY1NzkAAAAAAAAAATAAAAAAAAAAISEaL/HykudSEtIvCV4IZLmGVpRjO42P4prW" + 343 | "+BrhJwbCTwAAACEhGQIAi2dOCY+71CfKKLrelcbyGQX5X9LuaLYUMy9DihUAAAAB" + 344 | "MAAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAAAAAAAAAACjE4NzI3NDYwMDYAAAAA" + 345 | "AAAAAAAAAAAAAAABMAAAAAEwAAAAAAAAAAAAAAACMzMAAAABMAAAAAAAAAABMQAA" + 346 | "AAEwAAAAAAAAAAAAAAAKMTM3MzA3NzEwNEFDQ1QAAAFiAAAACjE4NzI3NDYwMTYA" + 347 | "AAAhId82S/9iRPDUriavRfqNVUhEGZOX08ECOnuaojPykIKAAAAAISHqqFJGu5eh" + 348 | "qOtr4bEHV5mficeDT2fVkf+LDCKWMCeZ9gAAADI2ODc0NzQ3MDNhMmYyZjczNjM2" + 349 | "ODY5NmU2ZTY1NzIyZTZmNzI2NzJmNzA3MjY5NjM2NQAAAAAAAAABMAAAAAAAAAAh" + 350 | "IS7XEzV9BA7EJEAwHlBxchTS64GqXT79huR1/o3vIMaCAAAAISH6Rh1DDkPHs0Sv" + 351 | "wmSkzoS/D23FFui7SeNffUnMuO4AIgAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAA" + 352 | "AAABMAAAAAAAAAAKMTg3Mjc0NjAxNgAAAAAAAAAAAAAAAAAAAAEwAAAAATAAAAAA" + 353 | "AAAAAAAAAAIzNAAAAAEwAAAAAAAAAAExAAAAATAAAAAAAAAAAAAAAAoxMzczMDc3" + 354 | "MTA0QUNDVAAAAVsAAAAKMTg3Mjc0NjAyNgAAACEhKzg8FWTtLVnsx/q5hLxbOkcn" + 355 | "e/ypclJgm7BN3p/zsFYAAAAAAAAAPjY4NzQ3NDcwM2EyZjJmNzQ2ZjcyNzAyZTZl" + 356 | "NjU3NDJmNzM2ODc5NjE2ZTZlNjUyZTczNmQ2OTc0Njg2MTZkAAAAAAAAAAEwAAAA" + 357 | "AAAAADEhQX/IAe7mSCwFyHIFWT4ckp2VqD4KkkfvzvzEJFwXI7ZNmH1SvZqvFziL" + 358 | "U0Rkp7AGAAAAISFh6Ou1peyH/2balpLVMvjQNUPtJZo69s4hmcCl/S1m4AAAAAEw" + 359 | "AAAAATAAAAABMAAAAAEwAAAAATAAAAABMAAAAAAAAAAKMTg3Mjc0NjAyNgAAAAAA" + 360 | "AAAAAAAAAAAAAAEwAAAAATAAAAAAAAAAAAAAAAAAAAABMAAAAAAAAAABMQAAAAEw" + 361 | "AAAAAAAAAAAAAAAKMTM3MzA3NzEwNEFDQ1QAAAFXAAAACjE4NzI3NDYwMzYAAAAh" + 362 | "Id0gI+Cr9oVISRJI+WSG5zK2nLbTZxYUnR66RF1Gh4JaAAAAAAAAADo2ODc0NzQ3" + 363 | "MDNhMmYyZjZkNjE2ZTc0NjUyZTYzNmY2ZDJmNjM2MTY5NjU1ZjczNzQ3MjY1Njk2" + 364 | "MzY4AAAAAAAAAAEwAAAAAAAAACEh/QMWW3D0w5CeocXshs+ucAWyxwmiNchiwYoB" + 365 | "6V2oOYwAAAAxIaPEUHR/4e325btZoD4F/PY9/iqT6+NTy1QlFn8sOJuO73XOru8a" + 366 | "NRxNP5JVdjNeKgAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAAAAABMAAAAAAAAAAK" + 367 | "MTg3Mjc0NjAzNgAAAAAAAAAAAAAAAAAAAAEwAAAAATAAAAAAAAAAAAAAAAAAAAAB" + 368 | "MAAAAAAAAAABMQAAAAEwAAAAAAAAAAAAAAAKMTM3MzA3NzEwNEFDQ1QAAAGaAAAA" + 369 | "CjE4NzI3NDYwNDYAAAAhIe3ccgsU8mUbkDYOwQv4NJ4OAyqU8VZJOTiUd+USdVtL" + 370 | "AAAAISHPfxoXKRXWeeBvuKovJYvHIZJFiD2AXNY1IZ5bbqZ7nAAAAEo2ODc0NzQ3" + 371 | "MDNhMmYyZjczNzc2MTZlNjk2MTc3NzM2YjY5MmU2ZjcyNjcyZjc3NjU2ZTY0NjU2" + 372 | "YzZjNWY2NzYxNzk2YzZmNzI2NAAAAAAAAAABMAAAAAAAAABBIfQUgwe7+CAYi4L3" + 373 | "v5Nqd3882yA1x4DsP9MHnoIuxZfMwL30DWyVMZgRdIyz+pzoUB3BuTmpyT27+iem" + 374 | "J9TCvw4AAAAhIUczUTh5lR8H7Ktgpuqs1gxES8B9t200WVcR7Qpp9PCnAAAAATAA" + 375 | "AAABMAAAAAEwAAAAATAAAAABMAAAAAEwAAAAAAAAAAoxODcyNzQ2MDQ2AAAAAAAA" + 376 | "AAAAAAAAAAAAATAAAAABMAAAAAAAAAAAAAAAAjM1AAAAATAAAAAAAAAAATEAAAAB" + 377 | "MAAAAAAAAAAAAAAACjEzNzMwNzcxMDRBQ0NUAAABTQAAAAoxODcyNzQ2MDU2AAAA" + 378 | "ISFois9KEuC2s4n6+S4iIfxoPyaICVq5eAnmVnRt+IjEVQAAAAAAAABANjg3NDc0" + 379 | "NzAzYTJmMmY3MjZmNmM2NjczNmY2ZTJlNjM2ZjZkMmY3NzY5NmM2Yzc5NWY2MjYx" + 380 | "NzI3NDY1NmM2YwAAAAAAAAABMAAAAAAAAAAhIUUANM5pwqxsxpSIR12nl8MIEH2d" + 381 | "gzPDjs3akFpSViFaAAAAISHnnvsbor3lJDmegn0727nV7i+T4xwr4mHPdpMD+AoS" + 382 | "qAAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAAAAABMAAAAAAAAAAKMTg3Mjc0NjA1" + 383 | "NgAAAAAAAAAAAAAAAAAAAAEwAAAAATAAAAAAAAAAAAAAAAAAAAABMAAAAAAAAAAB" + 384 | "MQAAAAEwAAAAAAAAAAAAAAAKMTM3MzA3NzEwNEFDQ1QAAAFyAAAACjE4NzI3NDYw" + 385 | "NjYAAAAhIT3aUadIp7a4npcPewKyUNmM571IfUBI3HonHGqhFvKDAAAAISEtgPTq" + 386 | "ASDU7nJMFiBIQgmLNLs2Rf73uAyvCojBZznxMQAAAEI2ODc0NzQ3MDNhMmYyZjYz" + 387 | "NmY2YzZjNjk2ZTczNzI2NTY5NjM2ODY1NmMyZTZlNjU3NDJmNzk2MTczNmQ2OTZl" + 388 | "NjUAAAAAAAAAATAAAAAAAAAAISHyXlSAi4MAqz/VfXdgBn05h52/TMidVmsXbiye" + 389 | "ePviSgAAACEhm1pnAzRXD1lZ7E5w8u4hWlA6ZfoAEn0OgnG4i0P7NZAAAAABMAAA" + 390 | "AAEwAAAAATAAAAABMAAAAAEwAAAAATAAAAAAAAAACjE4NzI3NDYwNjYAAAAAAAAA" + 391 | "AAAAAAAAAAABMAAAAAEwAAAAAAAAAAAAAAACMzYAAAABMAAAAAAAAAABMQAAAAEw" + 392 | "AAAAAAAAAAAAAAAKMTM3MzA3NzEwNEFDQ1QAAAGIAAAACjE4NzI3NDYwNzYAAAAh" + 393 | "IS6Zh5Ri+NYQTzg3DUClYCs8WHCYJMcSRjqAbtxJpiFaAAAAISE/FW6hUIGfpHVy" + 394 | "OjQ5Y3oexM/pbESQXSzZSs7DEx45ZQAAAEg2ODc0NzQ3MDNhMmYyZjY0NjU2MzZi" + 395 | "NmY3NzJlNmU2NTc0MmY3MjZmNmY3MzY1NzY2NTZjNzQyZTZiNzM2ODZjNjU3MjY5" + 396 | "NmUAAAAAAAAAATAAAAAAAAAAMSGo7CEeh4bG90RwATzYPM3JH6U5RXJKMy6sZ5vL" + 397 | "AHjrnWjSX2AMDegxFFxZA2euXssAAAAhIRQ4hn15n/NJMhOAfXcwQfD838qSTiMW" + 398 | "3Jm9L8n03FEyAAAAATAAAAABMAAAAAEwAAAAATAAAAABMAAAAAEwAAAAAAAAAAox" + 399 | "ODcyNzQ2MDc2AAAAAAAAAAAAAAAAAAAAATAAAAABMAAAAAAAAAAAAAAAAjM3AAAA" + 400 | "ATAAAAAAAAAAATEAAAABMAAAAAAAAAAAAAAACjEzNzMwNzcxMDRBQ0NUAAABgQAA" + 401 | "AAoxODcyNzQ2MDg2AAAAISGzuJy2/x0bzTTo5NZNRwqUmrQuRlFd3dF4BICxsjwi" + 402 | "WgAAAAAAAABkNjg3NDc0NzAzYTJmMmY2MzZmNmU3MzY5NjQ2OTZlNjU2ODY1Njk2" + 403 | "NDY1NmU3MjY1Njk2MzY4MmU2ZTYxNmQ2NTJmNmU2MTZkNjUyZTYzNjg3MjY5NzM3" + 404 | "NDY5NjE2ZTczNjU2ZQAAAAAAAAABMAAAAAAAAAAxIRr+9XJWPmE4/AG7+Pb0Ks8N" + 405 | "D8/7aC18pUrAyp9kbODPMms0fFnL/yZA/ad2xfS50wAAACEhYu5vWJSOS+ui86sl" + 406 | "CfaoQ8oUxXGQGr6z+15FToZdk0AAAAABMAAAAAEwAAAAATAAAAABMAAAAAEwAAAA" + 407 | "ATAAAAAAAAAACjE4NzI3NDYwODYAAAAAAAAAAAAAAAAAAAABMAAAAAEwAAAAAAAA" + 408 | "AAAAAAAAAAAAATAAAAAAAAAAATEAAAABMAAAAAAAAAAAAAAACjEzNzMwNzcxMDRB" + 409 | "Q0NUAAABYAAAAAoxODcyNzQ2MDk2AAAAISHDPPYOG+t5Z2olWjktpv9ONj9GtSrB" + 410 | "zhEzPN4E3dORUAAAACEhNno60cEl6iYI5QvcGwalaVlou8ciQkyDcXScg6X5MtMA" + 411 | "AAAwNjg3NDc0NzAzYTJmMmY2MjZmNjc2OTczNjk2MzY4MmU2ZTY1NzQyZjZjNmY3" + 412 | "MjY5AAAAAAAAAAEwAAAAAAAAACEhA0cQrJycpr3/lFSJ8mRaVxxYFqaEq8SWeeGH" + 413 | "kL0zA7oAAAAhIcq2yHDSlHc9T8KKsjYWPpHNaR/F9Gix38FLEuNHnJ+gAAAAATAA" + 414 | "AAABMAAAAAEwAAAAATAAAAABMAAAAAEwAAAAAAAAAAoxODcyNzQ2MDk2AAAAAAAA" + 415 | "AAAAAAAAAAAAATAAAAABMAAAAAAAAAAAAAAAAjM4AAAAATAAAAAAAAAAATEAAAAB" + 416 | "MAAAAAAAAAAAAAAACjEzNzMwNzcxMDRBQ0NUAAABTQAAAAoxODcyNzQ2MTA2AAAA" + 417 | "ISERFSfjI3TjPMa0kTR1GR50OjZ/EiLvDiqW6CDzyuUuVQAAAAAAAAAwNjg3NDc0" + 418 | "NzAzYTJmMmY2ODY1NzI3YTZmNjcyZTZlNjE2ZDY1MmY2Yzc1Njk2NzY5AAAAAAAA" + 419 | "AAEwAAAAAAAAADEhJE3xkPvg7pMNLEHaUJwff5QT6ZLrXAqHIIOhJ+/xjI5ZMR3K" + 420 | "gWdPoqRKWTI1hTuOAAAAISHg5oGEGzA/npjXns+NvIuIx80syiLBG8+IVOjQkcaw" + 421 | "MwAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAAAAABMAAAAAAAAAAKMTg3Mjc0NjEw" + 422 | "NgAAAAAAAAAAAAAAAAAAAAEwAAAAATAAAAAAAAAAAAAAAAAAAAABMAAAAAAAAAAB" + 423 | "MQAAAAEwAAAAAAAAAAAAAAAKMTM3MzA3NzEwNEFDQ1QAAAF8AAAACjE4NzI3NDYx" + 424 | "MTYAAAAxIR+rniCxFedvT5iPsV+wriz/eUGqUDjSUVvgWx++Ie8SpuixV2oLJek3" + 425 | "5QlsXpUpdAAAACEhA/oyqcYV/FLwZ/bwWmpw411m0Yw7xEIrSlTD84jBzdcAAAAs" + 426 | "Njg3NDc0NzAzYTJmMmY2ZDYxNmU2ZTJlNjM2ZjZkMmY2MzY1NjM2OTZjNjUAAAAA" + 427 | "AAAAATAAAAAAAAAAMSHTlqBR1p5KTloaXsqfkCtKXfnnkhBud6vb2lrKt9TgHbzz" + 428 | "FmisdDtXdPOayMyjIA8AAAAhIRa8RGSt4sHV3kBWgWtmzffe0eQY13rGXh+aTQqu" + 429 | "QlTbAAAAATAAAAABMAAAAAEwAAAAATAAAAABMAAAAAEwAAAAAAAAAAoxODcyNzQ2" + 430 | "MTE2AAAAAAAAAAAAAAAAAAAAATAAAAABMAAAAAAAAAAAAAAAAjM5AAAAATAAAAAA" + 431 | "AAAAATEAAAABMAAAAAAAAAAAAAAACjEzNzMwNzcxMDRBQ0NUAAABgAAAAAoxODcy" + 432 | "NzQ2MTI2AAAAMSF5MfDk4jYK0etH9leG6MO7EBSFlr5N29bfk2aH8WOf6PW1E82G" + 433 | "hVy6jyldOud6wakAAAAhIRs3CcQDvzx4kT89JGnOSoLaYkQOJ5wcH07foV8Zl8w7" + 434 | "AAAAMDY4NzQ3NDcwM2EyZjJmNjQ2ZjZmNmM2NTc5MmU2ZTYxNmQ2NTJmNjU3NzYx" + 435 | "NmM2NAAAAAAAAAABMAAAAAAAAAAxISBUh/zVQKwBdHsI1zLcz9/V686lIrsDg1Y4" + 436 | "oL21SljpYgGYgXUJomOI9PUnjj/F2QAAACEhWopo9RqMg0T6LeHA1ouIoR6s9uBn" + 437 | "T4GdUb+8LyOSuloAAAABMAAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAAAAAAAAAA" + 438 | "CjE4NzI3NDYxMjYAAAAAAAAAAAAAAAAAAAABMAAAAAEwAAAAAAAAAAAAAAACNDAA" + 439 | "AAABMAAAAAAAAAABMQAAAAEwAAAAAAAAAAAAAAAKMTM3MzA3NzEwNEFDQ1QAAAGq" + 440 | "AAAACjE4NzI3NDYxMzYAAAAxIbMZ3DBnzDDDh7eUUesvL3gFnLLJWDwDKJdWk4iL" + 441 | "2AcmCOXZEjAM6AOis0Dy0CZM5AAAACEhXk0HduCrtiALdG21CCdcDsw5WD09Vzlt" + 442 | "HgBKPVjPbFkAAABaNjg3NDc0NzAzYTJmMmY2MjYxNmM2OTczNzQ3MjY1NzI2OTZk" + 443 | "NjM2MzZjNzU3MjY1MmU2MzZmNmQyZjZhNjE3MTc1NjE2ZTVmNzc2OTZjNmI2OTZl" + 444 | "NzM2ZjZlAAAAAAAAAAEwAAAAAAAAACEhiUn0XC5CEOI/x/ZPf8pnfBwCHVDWN6MP" + 445 | "klIaKSK9+mYAAAAxIa1LGBP4wk8fbn9CjFbeYzwIZoX1Kgry55/SKi8vjhoSTBwK" + 446 | "jKasZIdygJMhODEVqQAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAAAAABMAAAAAAA" + 447 | "AAAKMTg3Mjc0NjEzNgAAAAAAAAAAAAAAAAAAAAEwAAAAATAAAAAAAAAAAAAAAAI0" + 448 | "MQAAAAEwAAAAAAAAAAExAAAAATAAAAAAAAAAAAAAAAoxMzczMDc3MTA0QUNDVAAA" + 449 | "AV8AAAAKMTg3Mjc0NjE0NgAAADEhK3mh+y52pwKRaNPCkf2itmwOWCf+ihpxwkYY" + 450 | "qRWmQUFJFaYVfWEqjf+rjkOLupx2AAAAAAAAADI2ODc0NzQ3MDNhMmYyZjcwNmY3" + 451 | "NTcyNmY3MzJlNmU2NTc0MmY2YTY1NzI2NTZkNjk2NQAAAAAAAAABMAAAAAAAAAAh" + 452 | "IQz4rm0x0oifUs7U79kkwk2KZZ7RWw76GLZfZM2jFDmoAAAAMSHuKArDA7E6S7MY" + 453 | "7YYjW5oENQti+8AhNRIRmvm3ZJoDH/8AzsjP7VwZCeCNXDi5+rkAAAABMAAAAAEw" + 454 | "AAAAATAAAAABMAAAAAEwAAAAATAAAAAAAAAACjE4NzI3NDYxNDYAAAAAAAAAAAAA" + 455 | "AAAAAAABMAAAAAEwAAAAAAAAAAAAAAAAAAAAATAAAAAAAAAAATEAAAABMAAAAAAA" + 456 | "AAAAAAAACjEzNzMwNzcxMDRBQ0NUAAABogAAAAoxODcyNzQ2MTU2AAAAMSG7//UM" + 457 | "gswtSfMRaL+bnmoiL1VNggfiqWrW+ydbIPxULtrvGgel1i/fIsxZ+tKbGy0AAAAh" + 458 | "IcjhBXk5Y2nNSIor79shd7xmBDaO7Xdnuc7SWo0fv+3IAAAAQjY4NzQ3NDcwM2Ey" + 459 | "ZjJmNmI2NTZjNjU3MjJlNjk2ZTY2NmYyZjZlNjk2YjY5NzQ2MTJlNmM2OTZlNjQ2" + 460 | "NzcyNjU2ZQAAAAAAAAABMAAAAAAAAAAxIRQAwLVE2YVFMOZJftKR4ERR1jI111VM" + 461 | "xOHVfymc1Nb/VMfvKPcugRyFnToJ5FXt8gAAADEho+zPg8+KNDX5ZyozfI+foxnd" + 462 | "4M1wfV5XyqO+3iPgbMGSgB/EuAqVCf9vPY8fgDf5AAAAATAAAAABMAAAAAEwAAAA" + 463 | "ATAAAAABMAAAAAEwAAAAAAAAAAoxODcyNzQ2MTU2AAAAAAAAAAAAAAAAAAAAATAA" + 464 | "AAABMAAAAAAAAAAAAAAAAjQyAAAAATAAAAAAAAAAATEAAAABMAAAAAAAAAAAAAAA" + 465 | "CjEzNzMwNzcxMDRBQ0NUAAABggAAAAoxODcyNzQ2MTY2AAAAISGrWq0AxhTXoiug" + 466 | "tHw2J/31Ec04r0hpJUGvooLiOV5ghgAAACEhdEJ1EZw4nIA/bIaL5Fb/urcMoAf8" + 467 | "4uRmjnvkNZf61dMAAABCNjg3NDc0NzAzYTJmMmY2YTYxNzM2YjZmNmM3MzZiNjky" + 468 | "ZTYzNmY2ZDJmNjM2ZjZlNmU2NTcyNWY2ZjcyNzQ2OTdhAAAAAAAAAAEwAAAAAAAA" + 469 | "ADEhL1bEVgVPSRUz8DcNcIByBGss/2eixkW0Y/nqgKrSdYG0kMFd0Pfb9iNu5h4R" + 470 | "wSnmAAAAISEi4LXgtoJUiILwN9uVsPNumBtSrq8CrPXhhCPqY+LZpgAAAAEwAAAA" + 471 | "ATAAAAABMAAAAAEwAAAAATAAAAABMAAAAAAAAAAKMTg3Mjc0NjE2NgAAAAAAAAAA" + 472 | "AAAAAAAAAAEwAAAAATAAAAAAAAAAAAAAAAI0MwAAAAEwAAAAAAAAAAExAAAAATAA" + 473 | "AAAAAAAAAAAAAAoxMzczMDc3MTA0QUNDVAAAAYIAAAAKMTg3Mjc0NjE3NgAAADEh" + 474 | "qTunGI7LVuA6smQ5NUl/QAdp0BpFBZ86DxXcu9GIPjulrbfm7D8rbLlK+hyrrPUR" + 475 | "AAAAISF/eCndbZ7sty8Fk5GacdtCSAoe4UlUJmeA0+bfRhWb1QAAAEI2ODc0NzQ3" + 476 | "MDNhMmYyZjYzNjg2MTZkNzA2YzY5NmUyZTZmNzI2NzJmNmM3NTY1NWY3MzYzNjg3" + 477 | "MjZmNjU2NDY1NzIAAAAAAAAAATAAAAAAAAAAISHlHxpgVAUJAiECPC2RJ6/cJl8w" + 478 | "VbPqsL9MINg0d2HcvAAAACEhcNCDj79e3CRAemHtbExcOM0yS/eiXvyLs58RfTHV" + 479 | "4c8AAAABMAAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAAAAAAAAAACjE4NzI3NDYx" + 480 | "NzYAAAAAAAAAAAAAAAAAAAABMAAAAAEwAAAAAAAAAAAAAAACNDQAAAABMAAAAAAA" + 481 | "AAABMQAAAAEwAAAAAAAAAAAAAAAKMTM3MzA3NzEwNEFDQ1QAAAGAAAAACjE4NzI3" + 482 | "NDYxODYAAAAhIQwGNLfZsRLpZCmV9LYbZUQipCsK0h/iwz/F0sdXGljHAAAAISEy" + 483 | "nfcjxV48zNP1YQL0G+fczKb9WYYKN/yvim5CoVQWgAAAAEA2ODc0NzQ3MDNhMmYy" + 484 | "ZjY0NmY2ZTZlNjU2YzZjNzk2MTY0NjE2ZDczMmU2MzZmNmQyZjczNjE2ZTc0Njk2" + 485 | "ZTZmAAAAAAAAAAEwAAAAAAAAACEhr5OqXVgwE4Cm5pJ7dBbJ/5MR+odlcYi68jT8" + 486 | "/d2ZqPwAAAAxIcqzbJKVdtdhP57PWMymBWVaLF/3OhGnBpRaGd3m9MtBhwbJDRuQ" + 487 | "znGbA3QzZTT6EwAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAAAAABMAAAAAAAAAAK" + 488 | "MTg3Mjc0NjE4NgAAAAAAAAAAAAAAAAAAAAEwAAAAATAAAAAAAAAAAAAAAAI0NQAA" + 489 | "AAEwAAAAAAAAAAExAAAAATAAAAAAAAAAAAAAAAoxMzczMDc3MTA0QUNDVAAAAZAA" + 490 | "AAAKMTg3Mjc0NjE5NgAAADEh11IPQ+cUTTBgD145Il6mGe6388poazsKm27r2rgQ" + 491 | "2I2rPR+vvH822BmmHqieiS77AAAAISFBRBjsh6QoJPEAikbmliMNGIJOiKXD0POg" + 492 | "XU28iLWtPgAAAEA2ODc0NzQ3MDNhMmYyZjZjNjE3MjZiNjk2ZTYzNmY2ZTczNjk2" + 493 | "NDY5NmU2NTJlNmY3MjY3MmY2YzY1NmY2YzYxAAAAAAAAAAEwAAAAAAAAADEhOp67" + 494 | "pjeKjn3jZvND4y6Spl+0Uf5sfT4uT/6XdU7EQjL1mIc4KFKITq9u8bZyMfbvAAAA" + 495 | "ISFDKO6UmiN55Vz/Z1nE9wgMIggkRFLSfoEWtOFxBxm4gQAAAAEwAAAAATAAAAAB" + 496 | "MAAAAAEwAAAAATAAAAABMAAAAAAAAAAKMTg3Mjc0NjE5NgAAAAAAAAAAAAAAAAAA" + 497 | "AAEwAAAAATAAAAAAAAAAAAAAAAI0NgAAAAEwAAAAAAAAAAExAAAAATAAAAAAAAAA" + 498 | "AAAAAAoxMzczMDc3MTA0QUNDVAAAAWgAAAAKMTg3Mjc0NjIwNgAAACEhivEANkoW" + 499 | "2ebUjJQ1zqte5o5Lm+n7/0diEkqe0IF0gwoAAAAhIaBuyDnnjdcSg6CpOio1F0EY" + 500 | "hTlnREYYRBn23/oNcYWtAAAAODY4NzQ3NDcwM2EyZjJmNzI3NTZlNzQ2NTZkNmY2" + 501 | "NTZlMmU2ZTYxNmQ2NTJmNzA2OTY1NzI3MjY1AAAAAAAAAAEwAAAAAAAAACEhTp3L" + 502 | "/Io2JJhFs4xZauBDMM7CDOZN9aEWbzO20rKqcW8AAAAhIRazdF90kyS1RTrapUfd" + 503 | "ZCIG5h767SrwDO1O0cv+qh4HAAAAATAAAAABMAAAAAEwAAAAATAAAAABMAAAAAEw" + 504 | "AAAAAAAAAAoxODcyNzQ2MjA2AAAAAAAAAAAAAAAAAAAAATAAAAABMAAAAAAAAAAA" + 505 | "AAAAAjQ3AAAAATAAAAAAAAAAATEAAAABMAAAAAAAAAAAAAAACjEzNzMwNzcxMDRB" + 506 | "Q0NUAAABbgAAAAoxODcyNzQ2MjE2AAAAISFKhsuIHlq9ZK8qj7V6l34zT2Y4SaW7" + 507 | "e8vrBQg4wUmt2QAAACEhZP+ucMFHVfuqhnkbse0AdEl+gwiMAaFzNIQ7E2Azp4gA" + 508 | "AAAuNjg3NDc0NzAzYTJmMmY2ZDZmNmY3MjY1MmU2OTZlNjY2ZjJmNzA2NTYxNzI2" + 509 | "YwAAAAAAAAABMAAAAAAAAAAhIfSeNtDnxF+rrgC2lqoAp5fOEYzeZoWC22pGjnLR" + 510 | "jvflAAAAMSFGQQA1zXOD46JDl7KlJOOdNKqvf4zUEAAvCvSzYil4PoZEmpEhzORM" + 511 | "82wjFD8ycXcAAAABMAAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAAAAAAAAAACjE4" + 512 | "NzI3NDYyMTYAAAAAAAAAAAAAAAAAAAABMAAAAAEwAAAAAAAAAAAAAAACNDgAAAAB" + 513 | "MAAAAAAAAAABMQAAAAEwAAAAAAAAAAAAAAAKMTM3MzA3NzEwNEFDQ1QAAAGWAAAA" + 514 | "CjE4NzI3NDYyMjYAAAAhIfzsPBb9zw+znGr4dJ9oi+K9Kasa6HGl9KeaNzyjZnDz" + 515 | "AAAAISHOX7VYz7NdFBpwqA5SWOlwVYg9QsxgzCQ1Pg+rnoHQDQAAAEY2ODc0NzQ3" + 516 | "MDNhMmYyZjYxNzI2ZDczNzQ3MjZmNmU2NzY4NjE2MzZiNjU3NDc0MmU2ZTYxNmQ2" + 517 | "NTJmNmE2MTY1NjQ2NTZlAAAAAAAAAAEwAAAAAAAAADEhQ6EOU47TD4aNTeAqrKvn" + 518 | "0meY9qJPPxBR9Plfn/uN1Kp6ZWDuYWM0XNNG2U+suAY9AAAAMSGnFX55n8slGEuC" + 519 | "4VixBBjncWn4DCOckmOZlXbMJGojAdxm6ItEBUkXZRfoJqCrSg8AAAABMAAAAAEw" + 520 | "AAAAATAAAAABMAAAAAEwAAAAATAAAAAAAAAACjE4NzI3NDYyMjYAAAAAAAAAAAAA" + 521 | "AAAAAAABMAAAAAEwAAAAAAAAAAAAAAACNDkAAAABMAAAAAAAAAABMQAAAAEwAAAA" + 522 | "AAAAAAAAAAAKMTM3MzA3NzEwNEFDQ1QAAAGYAAAACjE4NzI3NDYyMzYAAAAhIZ6M" + 523 | "UDsd3cxd81PLuLGbefM0evo6JDhjC3mFemUTexW4AAAAISF1SZY7/6ii9QquiGk3" + 524 | "ZSBSKy06zeI7hfepQ2HlEObtCwAAAFg2ODc0NzQ3MDNhMmYyZjczNjM2ODc1NmM2" + 525 | "OTczNzQ2ZDY1NzQ3YTJlNjk2ZTY2NmYyZjY1NzM3MDY1NzI2MTZlN2E2MTVmNjM3" + 526 | "NTZkNmQ2NTcyNjE3NDYxAAAAAAAAAAEwAAAAAAAAADEh3UA8lPeFoYOCGcoMqpad" + 527 | "cfn91UaHAZ84jzzrluB/tUsNlkOKGYEEnYogobIeyY2IAAAAISFvuhLWcLczKxUv" + 528 | "TPzCREpwVZhz5JnBiHgtFQXHzbE4bgAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAA" + 529 | "AAABMAAAAAAAAAAKMTg3Mjc0NjIzNgAAAAAAAAAAAAAAAAAAAAEwAAAAATAAAAAA" + 530 | "AAAAAAAAAAI1MAAAAAEwAAAAAAAAAAExAAAAATAAAAAAAAAAAAAAAAoxMzczMDc3" + 531 | "MTA0QUNDVAAAAXoAAAAKMTg3Mjc0NjI0NgAAADEh+6+5E2dpwHAahj8HhghS7Tiz" + 532 | "atIe+K/38mBeat2wIGuLBl1QBuzlAz/HAM4wJs5RAAAAISFMXZCT5hUyeLF6c73d" + 533 | "GIBFhIv2JElNHRLU9FDwTiQ8UQAAADo2ODc0NzQ3MDNhMmYyZjYyNjU2NTcyNmQ2" + 534 | "OTZjNmM3MzJlNmU2NTc0MmY2NDYxNmU2OTY1NmM2YzY1AAAAAAAAAAEwAAAAAAAA" + 535 | "ACEh+k828kKLO01oMkW/DYji9UXLzE0LYCbqda1NZZmdmeEAAAAhIYBS4wjSMEDX" + 536 | "JoA5/5rvJe/qiAlVSCl3yvKpwgo23eFQAAAAATAAAAABMAAAAAEwAAAAATAAAAAB" + 537 | "MAAAAAEwAAAAAAAAAAoxODcyNzQ2MjQ2AAAAAAAAAAAAAAAAAAAAATAAAAABMAAA" + 538 | "AAAAAAAAAAAAAjUxAAAAATAAAAAAAAAAATEAAAABMAAAAAAAAAAAAAAACjEzNzMw" + 539 | "NzcxMDRBQ0NUAAABUQAAAAoxODcyNzQ2MjU2AAAAISGW8+9kctjuPK6X5L9r6zOm" + 540 | "lgpvvX6j0/2UR5ve7qyW3gAAAAAAAAA0Njg3NDc0NzAzYTJmMmY2NDZmNzU2NzZj" + 541 | "NjE3MzJlNmU2MTZkNjUyZjcwNmY3Mjc0NjU3MgAAAAAAAAABMAAAAAAAAAAxIaiv" + 542 | "pvk7dppj/nPolImh7AFR2kx4cANrGRYyAvIbeHY/KwTYM5Ck0O8Gkm1jdNxSXAAA" + 543 | "ACEhiCOqIxGHXnB0Zoey+TP+gUovtRZQ3lU79xhLzCoOx8sAAAABMAAAAAEwAAAA" + 544 | "ATAAAAABMAAAAAEwAAAAATAAAAAAAAAACjE4NzI3NDYyNTYAAAAAAAAAAAAAAAAA" + 545 | "AAABMAAAAAEwAAAAAAAAAAAAAAAAAAAAATAAAAAAAAAAATEAAAABMAAAAAAAAAAA" + 546 | "AAAACjEzNzMwNzcxMDRBQ0NUAAABdgAAAAoxODcyNzQ2MjY2AAAAISFv+mMv2B/U" + 547 | "Q2BdUUHBjU6866hJAgc67yKhuMoAJxXRuAAAACEhPaLJhgtFmmyF33KXEcUfCIxW" + 548 | "BEBAZqgl4Eerx0wE0JEAAABGNjg3NDc0NzAzYTJmMmY2NDZmNmU2ZTY1NmM2Yzc5" + 549 | "MmU2MzZmNmQyZjc0Nzk3MjY5NzE3NTY1NWY2YzYxNmU2NzZmNzM2OAAAAAAAAAAB" + 550 | "MAAAAAAAAAAhISydgPK/e1rJplm2wN1+4yTz56+EKDmsbiq+1uYcN027AAAAISFe" + 551 | "8CoPyaC3aS0wEwpXrZGKWIo4hlZb7bje85a6dzyf9AAAAAEwAAAAATAAAAABMAAA" + 552 | "AAEwAAAAATAAAAABMAAAAAAAAAAKMTg3Mjc0NjI2NgAAAAAAAAAAAAAAAAAAAAEw" + 553 | "AAAAATAAAAAAAAAAAAAAAAI1MgAAAAEwAAAAAAAAAAExAAAAATAAAAAAAAAAAAAA" + 554 | "AAoxMzczMDc3MTA0QUNDVAAAAW4AAAAKMTg3Mjc0NjI3NgAAACEh3LwiezAkEUR+" + 555 | "j9usrYMiyyqeOYR+6PKzYRBlE22FfpoAAAAhIbBjmikiDf/gGMftxTr1uY4XR21R" + 556 | "8UObVLnnhgIC+EkYAAAALjY4NzQ3NDcwM2EyZjJmNzM2MzY4NmY2NTZlMmU2OTZl" + 557 | "NjY2ZjJmNmQ2MTYzNzkAAAAAAAAAATAAAAAAAAAAMSECrpe5ZtQ6RB3CYz5V5hE9" + 558 | "KVKEIRn1Fh4c3hW4CAXQ8n10k8lnIXisyEMn+PH+8M0AAAAhIX1mKNsOAMrhn7cl" + 559 | "E9XBmVfkUMzcrLY7PWyDTGi46Zy9AAAAATAAAAABMAAAAAEwAAAAATAAAAABMAAA" + 560 | "AAEwAAAAAAAAAAoxODcyNzQ2Mjc2AAAAAAAAAAAAAAAAAAAAATAAAAABMAAAAAAA" + 561 | "AAAAAAAAAjUzAAAAATAAAAAAAAAAATEAAAABMAAAAAAAAAAAAAAACjEzNzMwNzcx" + 562 | "MDRBQ0NUAAABfQAAAAoxODcyNzQ2Mjg2AAAAMSH+Pt5lvMdF2sZltKJuzRxWW5+R" + 563 | "518B7+oeoX1pCk8Re1OAImuUvARJ06aoSsH2PQ8AAAAAAAAAQDY4NzQ3NDcwM2Ey" + 564 | "ZjJmNzM2MzY4NzU3MDcwNjUyZTYzNmY2ZDJmNzI2ZjczNjU3NDc0NjEyZTc5NzU2" + 565 | "ZTY0NzQAAAAAAAAAATAAAAAAAAAAMSF51wnU/8MQL0M2I1KRg/VRXoBm7EyuAPdz" + 566 | "gicb+jPMj5uCqLGkO6yw71F7EmHYF44AAAAxIfcdgP77/uyU/+FuliVhRDQVup3h" + 567 | "CwNBTKpcjksC8vg4nXW3n9PBJZ9csWw9ric9mAAAAAEwAAAAATAAAAABMAAAAAEw" + 568 | "AAAAATAAAAABMAAAAAAAAAAKMTg3Mjc0NjI4NgAAAAAAAAAAAAAAAAAAAAEwAAAA" + 569 | "ATAAAAAAAAAAAAAAAAAAAAABMAAAAAAAAAABMQAAAAEwAAAAAAAAAAAAAAAKMTM3" + 570 | "MzA3NzEwNEFDQ1QAAAGAAAAACjE4NzI3NDYyOTYAAAAhIf9jc91gmE4zEOM45EtG" + 571 | "NTDZfJysY54eXl4Mm4gZ62F0AAAAISEThT3gw6D9nq7lbUehPOGZZScqeBBopIzr" + 572 | "N314io+HsQAAADA2ODc0NzQ3MDNhMmYyZjY2NjU2OTZjMmU2MzZmNmQyZjY5NzM2" + 573 | "MTYyNjU2YzZjNjUAAAAAAAAAATAAAAAAAAAAMSGTi2pOr8iisupbXnGcstLDjTmy" + 574 | "hL1dMh/GZfOwI1ROZNnm5739s4BimxGSa2YqNC0AAAAxIb7ncD0hULxm09sIMeZy" + 575 | "7OGBYtVHu3nRKdnhSO4ORH+g5ekRiuRrR5lZ6o6tCI2lkAAAAAEwAAAAATAAAAAB" + 576 | "MAAAAAEwAAAAATAAAAABMAAAAAAAAAAKMTg3Mjc0NjI5NgAAAAAAAAAAAAAAAAAA" + 577 | "AAEwAAAAATAAAAAAAAAAAAAAAAI1NAAAAAEwAAAAAAAAAAExAAAAATAAAAAAAAAA" + 578 | "AAAAAAoxMzczMDc3MTA0QUNDVAAAAV8AAAAKMTg3Mjc0NjMwNgAAADEhk8jUgvJn" + 579 | "090+fAf6MJBipK6AxFQ+ZDheQzDCeoivsc3jv0i/62miiB80RDF6UMoiAAAAAAAA" + 580 | "ADI2ODc0NzQ3MDNhMmYyZjZkNjM2YjY1NmU3YTY5NjUyZTZlNjU3NDJmN2E2MTcy" + 581 | "Njk2MQAAAAAAAAABMAAAAAAAAAAxIeRkk2vH0Asii+9greWOFnT9Yh7byhKdRIJH" + 582 | "7Nt60VYt5m0Gd/0f0g3WPmxMNUCw5wAAACEhOkJc3e9C9dwhnAu0zVVBeOo3gBwu" + 583 | "D0s9clIUYV9kvskAAAABMAAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAAAAAAAAAA" + 584 | "CjE4NzI3NDYzMDYAAAAAAAAAAAAAAAAAAAABMAAAAAEwAAAAAAAAAAAAAAAAAAAA" + 585 | "ATAAAAAAAAAAATEAAAABMAAAAAAAAAAAAAAACjEzNzMwNzcxMDRBQ0NUAAABpAAA" + 586 | "AAoxODcyNzQ2MzE2AAAAMSHqrjdVh7SyJdm/i/QdveoHr0EmFm2dKysPmxUwIyz8" + 587 | "dStajfUR8UuecrJkDpcfE2gAAAAhIagNh8jpaaAgHvWQ6dIp/TinfIRiAtdNKzli" + 588 | "A2Qcjj8PAAAARDY4NzQ3NDcwM2EyZjJmNzc2ODY5NzQ2NTZiNmM2ZjYzNmI2ZjJl" + 589 | "NmU2MTZkNjUyZjZjNjE2MzY1NzkyZTY0NjE3MjY1AAAAAAAAAAEwAAAAAAAAADEh" + 590 | "+gQF+NEN0o11e4QQcvHmVAzzlAL8378JeJHYiLx5oys3Hux8rm8V5Wmefw29sAN0" + 591 | "AAAAMSFdcr3phRXBfJNB7mcqyGcxhq7Oa8Y0tBuseTXMXpDn+PEN2E2AxmmtG4Go" + 592 | "lkrOmqsAAAABMAAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAAAAAAAAAACjE4NzI3" + 593 | "NDYzMTYAAAAAAAAAAAAAAAAAAAABMAAAAAEwAAAAAAAAAAAAAAACNTUAAAABMAAA" + 594 | "AAAAAAABMQAAAAEwAAAAAAAAAAAAAAAKMTM3MzA3NzEwNEFDQ1QAAAF2AAAACjE4" + 595 | "NzI3NDYzMjYAAAAxIVK90J3XMPZAFuRp6Osn5EkFu3jHT8XBpNzVESLLl2QuyGkx" + 596 | "H1eaoWtQu9znoH8d3AAAACEhDKRI7S5YTtlSsgQOM56/q4NWLlvLw0s+eCACoUqy" + 597 | "2HAAAAA2Njg3NDc0NzAzYTJmMmY2ZjZiNzU2ZTY1NzY2MTJlNjI2OTdhMmY2YzY5" + 598 | "NzM2MTZlNjQ3MjZmAAAAAAAAAAEwAAAAAAAAACEhoAKmn3YZpzOlVaWh7DH41IL7" + 599 | "Fscmahm5cou/nr1YDMEAAAAhIVsDiiobgbm4IusJeTIpJYqUGTXar5OsoExjFCHt" + 600 | "CVMqAAAAATAAAAABMAAAAAEwAAAAATAAAAABMAAAAAEwAAAAAAAAAAoxODcyNzQ2" + 601 | "MzI2AAAAAAAAAAAAAAAAAAAAATAAAAABMAAAAAAAAAAAAAAAAjU2AAAAATAAAAAA" + 602 | "AAAAATEAAAABMAAAAAAAAAAAAAAACjEzNzMwNzcxMDRBQ0NUAAABoAAAAAoxODcy" + 603 | "NzQ2MzM2AAAAMSFU6SKNW6QfLGsMUOh6SDiCJTkLkqgooMJjQnu67ggENVvCNJXY" + 604 | "/k4PLO0EVYe0F9sAAAAhISu0qI6/0edzHljLC2LY6IZyC+C5uih4/NzmxnMysCXU" + 605 | "AAAAQDY4NzQ3NDcwM2EyZjJmNzM2MTc1NjU3MjZiNzU3NjYxNmM2OTczMmU2OTZl" + 606 | "NjY2ZjJmNjI3MjYxNzg3NDZmNmUAAAAAAAAAATAAAAAAAAAAMSF90O1BZfKqUWt3" + 607 | "0H6m9sQGvHoaO21DvtTQ/DglAFnIXHltZ528s1EoRElwxNHj3pAAAAAxIRwmpCAn" + 608 | "PcbgJdgmONJ/3yan8wqRNxwva6eTfvfYJ6VyO/T1GR9ytQ/4YuKIRcFXWQAAAAEw" + 609 | "AAAAATAAAAABMAAAAAEwAAAAATAAAAABMAAAAAAAAAAKMTg3Mjc0NjMzNgAAAAAA" + 610 | "AAAAAAAAAAAAAAEwAAAAATAAAAAAAAAAAAAAAAI1NwAAAAEwAAAAAAAAAAExAAAA" + 611 | "ATAAAAAAAAAAAAAAAAoxMzczMDc3MTA0QUNDVAAAAT8AAAAKMTg3Mjc0NjM0NgAA" + 612 | "ACEhWHIlbPdrg1cxYw12zp/pT4NXK1251UvT7sQAxZvDRJ4AAAAAAAAAMjY4NzQ3" + 613 | "NDcwM2EyZjJmNzM3MDY5NmU2YjYxMmU2OTZlNjY2ZjJmNmI2NTZlNjQ3MjYxAAAA" + 614 | "AAAAAAEwAAAAAAAAACEhopsZrJCftw32PVUKDFNPeDazeyR+x3g9tdOF4i8EtlgA" + 615 | "AAAhIW5MiA5bQIegxeMVVVvSIxIJMhw8jl2VOkFR5dMNk6moAAAAATAAAAABMAAA" + 616 | "AAEwAAAAATAAAAABMAAAAAEwAAAAAAAAAAoxODcyNzQ2MzQ2AAAAAAAAAAAAAAAA" + 617 | "AAAAATAAAAABMAAAAAAAAAAAAAAAAAAAAAEwAAAAAAAAAAExAAAAATAAAAAAAAAA" + 618 | "AAAAAAoxMzczMDc3MTA0QUNDVAAAAWwAAAAKMTg3Mjc0NjM2NgAAACEhgaOpYMbJ" + 619 | "z03Hg74f+VxVhArquOV7s3SrsaPlKKKBzHQAAAAhIT8AG2KA6BljbGz6JB1c4W+Q" + 620 | "pevHAnl3Ry04T6OhydrRAAAAPDY4NzQ3NDcwM2EyZjJmNzA2Zjc1NzI2ZjZkNjk3" + 621 | "NDY4NjE2ZDJlNmU2MTZkNjUyZjY1NjY3MjYxNjk2ZQAAAAAAAAABMAAAAAAAAAAh" + 622 | "Ifjbyraq5+KMagWUJNytVJ90ZmAsh+s/Y68K4tgv6iTcAAAAISGCFBhinuNKk5m7" + 623 | "TWJ6ZQyYoPFljt89RKIGbm3FE6PkMAAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAA" + 624 | "AAABMAAAAAAAAAAKMTg3Mjc0NjM2NgAAAAAAAAAAAAAAAAAAAAEwAAAAATAAAAAA" + 625 | "AAAAAAAAAAI1OAAAAAEwAAAAAAAAAAExAAAAATAAAAAAAAAAAAAAAAoxMzczMDc3" + 626 | "MTA1QUNDVAAAAVEAAAAKMTg3Mjc0NjM3NgAAACEhT0031xQ/fE7hclg1kZbaqDXV" + 627 | "+R82hh/wuo/aBkRlm0UAAAAAAAAARDY4NzQ3NDcwM2EyZjJmNjg2NTY5NjQ2NTZl" + 628 | "NzI2NTY5NjM2ODJlNmU2NTc0MmY3Mjc5NjE2ZTZlNWY2ODYxNzk2NTczAAAAAAAA" + 629 | "AAEwAAAAAAAAACEhPWUFEFPqutbf6MAvc7Fc8T77ELjBjqTS3fmYd3HDcAEAAAAh" + 630 | "IaoV06azgsaZ1IP71foi65sfmwkZyDultYjBzSZohFDnAAAAATAAAAABMAAAAAEw" + 631 | "AAAAATAAAAABMAAAAAEwAAAAAAAAAAoxODcyNzQ2Mzc2AAAAAAAAAAAAAAAAAAAA" + 632 | "ATAAAAABMAAAAAAAAAAAAAAAAAAAAAEwAAAAAAAAAAExAAAAATAAAAAAAAAAAAAA" + 633 | "AAoxMzczMDc3MTA1QUNDVAAAAX4AAAAKMTg3Mjc0NjM4NgAAACEh6nj/Gqvp52rR" + 634 | "VczHT/rehNK9VjgvEUqxNY8IQO/4sV4AAAAhIbSNbyYuKDi8vFWoN+OBdCneJ4at" + 635 | "SJpmSP3p6ohJ94JZAAAAPjY4NzQ3NDcwM2EyZjJmNmY2YjY1NjU2NjY1NjQ2MTZk" + 636 | "NmY3MjY1MmU2MjY5N2EyZjY3Njk2Zjc2NjE2ZTY5AAAAAAAAAAEwAAAAAAAAADEh" + 637 | "lbQt9/ORxb2Nat6AYieI7rj2BrxlZhomVvMexifb73pKu5ZHHmBP9y2Ob/zIbq6L" + 638 | "AAAAISE5UbIwhatj9gc5xyOl54RdobqcmIg22iqS/zpI51KItQAAAAEwAAAAATAA" + 639 | "AAABMAAAAAEwAAAAATAAAAABMAAAAAAAAAAKMTg3Mjc0NjM4NgAAAAAAAAAAAAAA" + 640 | "AAAAAAEwAAAAATAAAAAAAAAAAAAAAAI1OQAAAAEwAAAAAAAAAAExAAAAATAAAAAA" + 641 | "AAAAAAAAAAoxMzczMDc3MTA1QUNDVAAAAX4AAAAKMTg3Mjc0NjM5NgAAADEh26zB" + 642 | "cIcYY7x6GqCqvOsF1DDLdYD0jt9NqwrScomHZ4byJtmyK1+DPlbhkhRiAEilAAAA" + 643 | "ISHx5jHsfYubswaeDNgl2qloJBpWGJf87m+TT5O3zRbBnAAAAD42ODc0NzQ3MDNh" + 644 | "MmYyZjY0Njk2MzZiNjk2MjZmNzM2MzZmMmU2MjY5N2EyZjdhNjE2MzY4NjE3MjY5" + 645 | "NjE2OAAAAAAAAAABMAAAAAAAAAAhIQuOoAGzVTssrRbtg4dyDiTcHUtsx1sWDTPc" + 646 | "IAXoRsT3AAAAISGHCH8TUm702itAbe82iWvFjdwCZj0HkPIfclWbW6417wAAAAEw" + 647 | "AAAAATAAAAABMAAAAAEwAAAAATAAAAABMAAAAAAAAAAKMTg3Mjc0NjM5NgAAAAAA" + 648 | "AAAAAAAAAAAAAAEwAAAAATAAAAAAAAAAAAAAAAI2MAAAAAEwAAAAAAAAAAExAAAA" + 649 | "ATAAAAAAAAAAAAAAAAoxMzczMDc3MTA1QUNDVAAAAXYAAAAKMTg3Mjc0NjQwNgAA" + 650 | "ACEhN5YTsEv5p9MjV/B5nPNetm726M1lsqCX/graNnGXTPcAAAAhIdhvOYLMAhx0" + 651 | "DQGNdnyD5aPZxzJMrR0FMFvh4zMhiKyRAAAARjY4NzQ3NDcwM2EyZjJmNmI3NTZl" + 652 | "N2E2NTZkNzU3MjYxN2E2OTZiMmU2ZTY1NzQyZjZhNmY2ODZlNmU3OTJlNmI2ZjYz" + 653 | "NjgAAAAAAAAAATAAAAAAAAAAISFWU2xUQyWpi3pEUBjFSthhtWWORIsnZ4BadLkX" + 654 | "3baQnAAAACEhzQVeTO7cJfirtx5qIX393cLNYdYW1ytORG01QWfWcR0AAAABMAAA" + 655 | "AAEwAAAAATAAAAABMAAAAAEwAAAAATAAAAAAAAAACjE4NzI3NDY0MDYAAAAAAAAA" + 656 | "AAAAAAAAAAABMAAAAAEwAAAAAAAAAAAAAAACNjEAAAABMAAAAAAAAAABMQAAAAEw" + 657 | "AAAAAAAAAAAAAAAKMTM3MzA3NzEwNUFDQ1QAAAGKAAAACjE4NzI3NDY0MTYAAAAx" + 658 | "IY8zvMfWHSRx1+G5SwVzbgOlMZZk8MZHRyaddVbzwSt89lsGOij4defG9Rw1nNSP" + 659 | "SgAAACEhpnF0CCVu/s1ReU/UcClvoIRdm6ls8iiCPfTP/iq2Ta8AAABKNjg3NDc0" + 660 | "NzAzYTJmMmY2ODYxNzI3MjY5NzMyZTZlNjE2ZDY1MmY3MjZmNzM2MTZjNjk2ZTY0" + 661 | "NWY2ZDYxNzI3MTc1NjE3MjY0NzQAAAAAAAAAATAAAAAAAAAAISFcwR2UwzK5wXYW" + 662 | "nn5wBqvAxTkROjU1KEhRWXgZ8QPgGwAAACEhwt+Z3UwKxRVtjiBu2aV2B3rp4zQb" + 663 | "UkpRb9Xnolie6VYAAAABMAAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAAAAAAAAAA" + 664 | "CjE4NzI3NDY0MTYAAAAAAAAAAAAAAAAAAAABMAAAAAEwAAAAAAAAAAAAAAACNjIA" + 665 | "AAABMAAAAAAAAAABMQAAAAEwAAAAAAAAAAAAAAAKMTM3MzA3NzEwNUFDQ1QAAAGQ" + 666 | "AAAACjE4NzI3NDY0MjYAAAAxIcau1MQfKYFvcyd43jYAKADsjGg4JaIuQxxMOeUf" + 667 | "Pkk7ekC7rPOMgUcUmQeqOEAvmQAAACEhVnhVvy+q5BoBlgG28yZj00hgUrpwNk08" + 668 | "mezvGgs6P+AAAABQNjg3NDc0NzAzYTJmMmY3Mjc1NmU2ZjZjNjY3MzY0NmY3NDc0" + 669 | "Njk3MjJlNmU2MTZkNjUyZjZlNjk2MzZiNmM2MTc1NzM1ZjY4NjE3OTY1NzMAAAAA" + 670 | "AAAAATAAAAAAAAAAISE4S+TZaeEgkoSQJuGyZewfdFtZ7J0KUPB/P1CQ8GueegAA" + 671 | "ACEhwVO2MK+u2tRq3d6ZeCYfy8vtsw0SRpGTZPRbWXkeWIkAAAABMAAAAAEwAAAA" + 672 | "ATAAAAABMAAAAAEwAAAAATAAAAAAAAAACjE4NzI3NDY0MjYAAAAAAAAAAAAAAAAA" + 673 | "AAABMAAAAAEwAAAAAAAAAAAAAAACNjMAAAABMAAAAAAAAAABMQAAAAEwAAAAAAAA" + 674 | "AAAAAAAKMTM3MzA3NzEwNUFDQ1QAAAFzAAAACjE4NzI3NDY0MzYAAAAxIV4H0EZb" + 675 | "dEL/QdJXHUFuOc36ZRh+VU5XmQGsLEtCHxX4x4wMloS0H3D8GYesBb2e9AAAAAAA" + 676 | "AABGNjg3NDc0NzAzYTJmMmY2ZjcyNjU2OTZjNmM3OTJlNjk2ZTY2NmYyZjY0NjE2" + 677 | "ODZjNjk2MTVmNjQ2ZjZlNmU2NTZjNmM3OQAAAAAAAAABMAAAAAAAAAAxIbLAZeQ0" + 678 | "4zfYy6ocJ3420t18WDcoQ/8v4mNJrUEt4AtzgF+rwA0JflHE9t6HwcurYwAAACEh" + 679 | "9lh/HLXHkvlHFXil5zSnsrpW6kX2fU9jiv1sX/Ue0OwAAAABMAAAAAEwAAAAATAA" + 680 | "AAABMAAAAAEwAAAAATAAAAAAAAAACjE4NzI3NDY0MzYAAAAAAAAAAAAAAAAAAAAB" + 681 | "MAAAAAEwAAAAAAAAAAAAAAAAAAAAATAAAAAAAAAAATEAAAABMAAAAAAAAAAAAAAA" + 682 | "CjEzNzMwNzcxMDVBQ0NUAAABiAAAAAoxODcyNzQ2NDQ2AAAAMSGrKahsenlFqPnV" + 683 | "lmjW6pNI+96JYSUiHraJXyF4lQjs6di7u4n8AiUtFFhBSNakJNAAAAAhIadyuMaD" + 684 | "CSh17uwbG2oGp2HezHnQls4i4MDEaXtgrEbyAAAAODY4NzQ3NDcwM2EyZjJmNzI2" + 685 | "MTc0NjgyZTZlNjU3NDJmNmM2NTY5NjY1ZjY4NjU3MjZkNjE2ZTZlAAAAAAAAAAEw" + 686 | "AAAAAAAAADEhBIgUGgVVgTQHqOTicVtkCMPL0FOI4VPaZmQbpjcwF/iRn21B3fCz" + 687 | "Fsp357ehcwyaAAAAISGqE6XJGWnYtxkNfUOR6tNp+IvkccEdIGHgTJjHH0yOiQAA" + 688 | "AAEwAAAAATAAAAABMAAAAAEwAAAAATAAAAABMAAAAAAAAAAKMTg3Mjc0NjQ0NgAA" + 689 | "AAAAAAAAAAAAAAAAAAEwAAAAATAAAAAAAAAAAAAAAAI2NAAAAAEwAAAAAAAAAAEx" + 690 | "AAAAATAAAAAAAAAAAAAAAAoxMzczMDc3MTA1QUNDVAAAAYoAAAAKMTg3Mjc0NjQ1" + 691 | "NgAAACEhZkA4xoPDy4bgy7ZKfe9aIRdJqTNU8wxcgChdxW/d83sAAAAhISHBtvN1" + 692 | "YUsZY0IIE6gwJCCFgzY5CIEG4qeoYTO3y6cZAAAAOjY4NzQ3NDcwM2EyZjJmNzM2" + 693 | "MzY4NmQ2OTY0NzQ2ZDY1NzI3NDdhMmU2ZTYxNmQ2NTJmNmI2OTcyNjEAAAAAAAAA" + 694 | "ATAAAAAAAAAAMSEhCDNKrrqp9guf4Uiwgt7n2M+zBHHY18NCymJ5zy2S5jZ1B51J" + 695 | "GbxzrA2+dY3YgNQAAAAxIQDSGhz+Uj/7Q5AQqV3ZxpSYSwUWn6V1dtLHnjq2OIbj" + 696 | "WbuB+XvIhjCAPEjuJ4GWkAAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAAAAABMAAA" + 697 | "AAAAAAAKMTg3Mjc0NjQ1NgAAAAAAAAAAAAAAAAAAAAEwAAAAATAAAAAAAAAAAAAA" + 698 | "AAI2NQAAAAEwAAAAAAAAAAExAAAAATAAAAAAAAAAAAAAAAoxMzczMDc3MTA1QUND" + 699 | "VAAAAX4AAAAKMTg3Mjc0NjQ2NgAAACEhvQQWSEN4Q9F6DpAZmDYR7rGt6hdb5jAm" + 700 | "aNYuzrNJwJQAAAAhIescncg6gMVW7n9v/IR3uVnhg11QsWmjt13ZLWN3tk0iAAAA" + 701 | "LjY4NzQ3NDcwM2EyZjJmNmQ2ZjZmNzI2NTJlNjI2OTdhMmY2MTZlNjk2MjYxNmMA" + 702 | "AAAAAAAAATAAAAAAAAAAQSHEjDC/J8AM/5+IcD6QL8IYiUd2+zCWE/r4BygYvKt+" + 703 | "AvhWz0Mk/jtAk3MJKfkK2NTd5H0XiGeFKIaZ+R51HEPNAAAAISFQImWVvnLxb4ww" + 704 | "7plDgbfhWgWm000webb6iCd0ANjnqwAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAA" + 705 | "AAABMAAAAAAAAAAKMTg3Mjc0NjQ2NgAAAAAAAAAAAAAAAAAAAAEwAAAAATAAAAAA" + 706 | "AAAAAAAAAAI2NgAAAAEwAAAAAAAAAAExAAAAATAAAAAAAAAAAAAAAAoxMzczMDc3" + 707 | "MTA1QUNDVAAAAWYAAAAKMTg3Mjc0NjQ3NgAAACEh1UMRSOR6rSnNpoBrQ8dcU6Id" + 708 | "ZvFAlwGyF776j2iIePEAAAAhIRJ+Is82ejxYBD89T1xLgFdLJdYkfmOFDw8kpn4h" + 709 | "SnM0AAAANjY4NzQ3NDcwM2EyZjJmNmM2NTc1NzM2MzY4NmI2NTJlNjM2ZjZkMmY2" + 710 | "NDYxNzA2ODZlNjU3OQAAAAAAAAABMAAAAAAAAAAhIRRhvc0h1K1Ia5XM2NL/2uv6" + 711 | "nJs9xzw4EgEdgPO/jqNHAAAAISF4UBbivLN4vGOEJNMoNp06C+tk7/r9qUQ3llPO" + 712 | "k6iyBQAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAAAAABMAAAAAAAAAAKMTg3Mjc0" + 713 | "NjQ3NgAAAAAAAAAAAAAAAAAAAAEwAAAAATAAAAAAAAAAAAAAAAI2NwAAAAEwAAAA" + 714 | "AAAAAAExAAAAATAAAAAAAAAAAAAAAAoxMzczMDc3MTA1QUNDVAAAAV4AAAAKMTg3" + 715 | "Mjc0NjQ4NgAAACEhNDsGOVJdXNVJJYTl5KraHxdsxIog6NQuymajYSXkeVgAAAAh" + 716 | "IU6tnMOtDTKlxZkrL4ocYAfFhgTDV3/UHNld+ie9LHeoAAAALjY4NzQ3NDcwM2Ey" + 717 | "ZjJmNjM3MjZmNmU2OTZlMmU2ZTY1NzQyZjYzNzk3MjY5NmMAAAAAAAAAATAAAAAA" + 718 | "AAAAISHB6qFDZ5CLTuSTEZkt2lKxSYkWwXiSFXBEUC92WRowHwAAACEhpMuL0lvS" + 719 | "xLjDtwYHXcluFCm6zxL+5lsRZAGKMyVtuDoAAAABMAAAAAEwAAAAATAAAAABMAAA" + 720 | "AAEwAAAAATAAAAAAAAAACjE4NzI3NDY0ODYAAAAAAAAAAAAAAAAAAAABMAAAAAEw" + 721 | "AAAAAAAAAAAAAAACNjgAAAABMAAAAAAAAAABMQAAAAEwAAAAAAAAAAAAAAAKMTM3" + 722 | "MzA3NzEwNUFDQ1QAAAF6AAAACjE4NzI3NDY0OTYAAAAxIQaQDPg3JmzYujNUhwdk" + 723 | "x8uKsB5E2YxKXSNVgX/j/T4kN+bsKxoE173N7N3UuW3vBwAAACEhmoKCnmzdmcBm" + 724 | "OwfLFHBQS51W+53P246QhgIUXrQUbnEAAAA6Njg3NDc0NzAzYTJmMmY3Mzc0NjU3" + 725 | "NTYyNjU3MjJlNjM2ZjZkMmY2MTZjNjk1ZjY3Njk2MjczNmY2ZQAAAAAAAAABMAAA" + 726 | "AAAAAAAhIdAikrlhzlhz8r33P2Stw/Zn4RXVv0sE5DnGbY2/Y7PEAAAAISHsr7jL" + 727 | "jaATZw6veoWRfmHiBNFbZjhKWRpc1qCMLI/djQAAAAEwAAAAATAAAAABMAAAAAEw" + 728 | "AAAAATAAAAABMAAAAAAAAAAKMTg3Mjc0NjQ5NgAAAAAAAAAAAAAAAAAAAAEwAAAA" + 729 | "ATAAAAAAAAAAAAAAAAI2OQAAAAEwAAAAAAAAAAExAAAAATAAAAAAAAAAAAAAAAox" + 730 | "MzczMDc3MTA1QUNDVAAAAYIAAAAKMTg3Mjc0NjUwNgAAADEhdj8sGtoiaRhR2ukP" + 731 | "VM2EqRlS8rw7vOnAN6HKek9LJEqzPlEPyzNlsQpwJF8Ruu17AAAAISG1AUGnPJRu" + 732 | "ZwhuOzelbQFTZl0ekVmENixE18fpdRWkYAAAAEI2ODc0NzQ3MDNhMmYyZjZiNjU3" + 733 | "Mjc0N2E2ZDYxNmU2ZTJlNjI2OTdhMmY2YTYxNzk2NDZmNmU1ZjZiNzU2ZTdhNjUA" + 734 | "AAAAAAAAATAAAAAAAAAAISHKnHE7GVST7ukUNNcWxUiMhlcljy/X31n5OCqVdODb" + 735 | "EwAAACEhcDIPTXpUMoxulC2fHPNr0eqUHvzEdpEYPi6IaJ/W4koAAAABMAAAAAEw" + 736 | "AAAAATAAAAABMAAAAAEwAAAAATAAAAAAAAAACjE4NzI3NDY1MDYAAAAAAAAAAAAA" + 737 | "AAAAAAABMAAAAAEwAAAAAAAAAAAAAAACNzAAAAABMAAAAAAAAAABMQAAAAEwAAAA" + 738 | "AAAAAAAAAAAKMTM3MzA3NzEwNUFDQ1QAAAGeAAAACjE4NzI3NDY1MTYAAAAxISbs" + 739 | "q/LHUzxe9WZcGips3Wth3v8SZPEwH/MmwWCGTo7HXG7uexsrRHSkzHVWDNGWjQAA" + 740 | "ACEh1xU+wdTpc+Kv1M61y33JISYaZZOZQuFEhrXnkd3lknkAAABONjg3NDc0NzAz" + 741 | "YTJmMmY2Nzc1NzQ2YjZmNzc3MzZiNjk3MjYxNzUyZTZmNzI2NzJmNjQ2ZjcyNjEy" + 742 | "ZTc3Njk2YzZjNjk2MTZkNzM2ZjZlAAAAAAAAAAEwAAAAAAAAADEhdk7n/+SQFAL7" + 743 | "2dz2bep6hKa+1RxqVtMMOjNn0KVgFaWyEhY9F6+BzhRjqtApGET7AAAAISEJsfL0" + 744 | "LEAMyrJ+JDZQ8sMmZ3aQtZpUCSF2aZzIC/uiIAAAAAEwAAAAATAAAAABMAAAAAEw" + 745 | "AAAAATAAAAABMAAAAAAAAAAKMTg3Mjc0NjUxNgAAAAAAAAAAAAAAAAAAAAEwAAAA" + 746 | "ATAAAAAAAAAAAAAAAAI3MQAAAAEwAAAAAAAAAAExAAAAATAAAAAAAAAAAAAAAAox" + 747 | "MzczMDc3MTA1QUNDVAAAAYQAAAAKMTg3Mjc0NjUyNgAAACEhCH2dW2TvT05XAoqC" + 748 | "i5GtSXCKhtCLcIp2oEhtK6NaBAoAAAAhIZC18+hzJxeUCkBwWy75C1pYz2+OOLZ0" + 749 | "K2ctNl1Vo2GcAAAARDY4NzQ3NDcwM2EyZjJmNjI3NTYzNmI3MjY5NjQ2NzY1MmU2" + 750 | "ZTY1NzQyZjZjNjE3NTcyNjU3NDc0NjEyZTc2NjU3NTZkAAAAAAAAAAEwAAAAAAAA" + 751 | "ADEhMz3QU9XsQ9YRGZf5WndY4i6M65cZp/dXdPPfkYRjhECB8OwbPozZZr3GAlL0" + 752 | "mniTAAAAISH35JWqSpN0G/ryr8wN4cm8JQx39xSv/WwDd481RWMLZgAAAAEwAAAA" + 753 | "ATAAAAABMAAAAAEwAAAAATAAAAABMAAAAAAAAAAKMTg3Mjc0NjUyNgAAAAAAAAAA" + 754 | "AAAAAAAAAAEwAAAAATAAAAAAAAAAAAAAAAI3MgAAAAEwAAAAAAAAAAExAAAAATAA" + 755 | "AAAAAAAAAAAAAAoxMzczMDc3MTA1QUNDVAAAAVsAAAAKMTg3Mjc0NjUzNgAAACEh" + 756 | "rZAymsLlKg8EmVqRzZuf4n9Bc3Ag/O28MQFRuYjaZzUAAAAAAAAAPjY4NzQ3NDcw" + 757 | "M2EyZjJmNjM3NTZkNmQ2OTZlNjc3Mzc3NjU2ODZlNjU3MjJlNjI2OTdhMmY2MTcw" + 758 | "NzI2OTZjAAAAAAAAAAEwAAAAAAAAADEhywe4mNI06dhIJhx68RLj2Zzj3gYbi3cR" + 759 | "U+fBf9RkIRW5OTGWRxfC5rIepNfY5gXtAAAAISFwTCUl/eIsU0NqyrhI+E3HLMDP" + 760 | "GqBohKWb3ALCab+K4QAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAAAAABMAAAAAAA" + 761 | "AAAKMTg3Mjc0NjUzNgAAAAAAAAAAAAAAAAAAAAEwAAAAATAAAAAAAAAAAAAAAAAA" + 762 | "AAABMAAAAAAAAAABMQAAAAEwAAAAAAAAAAAAAAAKMTM3MzA3NzEwNUFDQ1QAAAFN" + 763 | "AAAACjE4NzI3NDY1NDYAAAAhIZohkZeduize24bhEB34LGC5MKD8ZKivHChDMSnI" + 764 | "CbE7AAAAAAAAAEA2ODc0NzQ3MDNhMmYyZjY3NzI2MTY0NzkyZTYyNjk3YTJmNmQ2" + 765 | "ZjY4NjE2ZDZkNjU2NDVmNjI3MjYxNmI3NTczAAAAAAAAAAEwAAAAAAAAACEhUIgb" + 766 | "cpIZAQJxF9rxK6XtDWFiyR84IBR7vlpBHx7fmkoAAAAhIR9DUEY85kTttQlzgFgZ" + 767 | "qcnAKW1FNA76tVl2q/o0p+6DAAAAATAAAAABMAAAAAEwAAAAATAAAAABMAAAAAEw" + 768 | "AAAAAAAAAAoxODcyNzQ2NTQ2AAAAAAAAAAAAAAAAAAAAATAAAAABMAAAAAAAAAAA" + 769 | "AAAAAAAAAAEwAAAAAAAAAAExAAAAATAAAAAAAAAAAAAAAAoxMzczMDc3MTA1QUND" + 770 | "VAAAAXwAAAAKMTg3Mjc0NjU1NgAAADEhruEMVK972nEfSiAWnnvmpgnBiONiM3JT" + 771 | "g29++iaGwyaR5x7D2C7/+0G/WrTGvV04AAAAISFEPu/XMRbV0DBbJiFUs3C0/nm2" + 772 | "pYJT8tu+Ho+QdOAtDgAAADw2ODc0NzQ3MDNhMmYyZjY3NmY3NDc0NmM2OTY1NjIy" + 773 | "ZTZlNjE2ZDY1MmY2NTZjNjk3MzYxNjI2NTc0NjgAAAAAAAAAATAAAAAAAAAAISF9" + 774 | "4WILdSHxrR6qzEEMy07FURJnAp770+ppyJM/KG4wqwAAACEhwEs7wyKYcIJ05lS8" + 775 | "+gIWX7uWA8yMhCFlBxrdl/LAWmAAAAABMAAAAAEwAAAAATAAAAABMAAAAAEwAAAA" + 776 | "ATAAAAAAAAAACjE4NzI3NDY1NTYAAAAAAAAAAAAAAAAAAAABMAAAAAEwAAAAAAAA" + 777 | "AAAAAAACNzMAAAABMAAAAAAAAAABMQAAAAEwAAAAAAAAAAAAAAAKMTM3MzA3NzEw" + 778 | "NUFDQ1QAAAF4AAAACjE4NzI3NDY1NjYAAAAhISrRosN67ZDNH2xyB3d4ywdJaAD8" + 779 | "s34SagHcl2TGk150AAAAISF8S/LT9cg1/b0QErA5SPznZmnshsvfjePbLpTKHVRQ" + 780 | "aAAAADg2ODc0NzQ3MDNhMmYyZjY0NjE2MzY4Njc2OTczNmM2MTczNmY2ZTJlNmY3" + 781 | "MjY3MmY2MTZjNzY2MQAAAAAAAAABMAAAAAAAAAAxIakkKSxfhSFpGH0hU7sjoZJ/" + 782 | "JEk2XFuvU26H15BZYZC5K22lBRKNp2MROQkzTr5RHwAAACEhk1UjSMVmdD40Ilkw" + 783 | "TFe6iEXFZ0HFU/kV14EOVGGOko4AAAABMAAAAAEwAAAAATAAAAABMAAAAAEwAAAA" + 784 | "ATAAAAAAAAAACjE4NzI3NDY1NjYAAAAAAAAAAAAAAAAAAAABMAAAAAEwAAAAAAAA" + 785 | "AAAAAAACNzQAAAABMAAAAAAAAAABMQAAAAEwAAAAAAAAAAAAAAAKMTM3MzA3NzEw" + 786 | "NUFDQ1QAAAGeAAAACjE4NzI3NDY1NzYAAAAhIWV5XeJcLDDr88ffAGB3fAMXUDTZ" + 787 | "H5VxZ9+jaKHbwOSLAAAAISFC0s+hSulEiuF//bbQ/+5tz+1k2aV2H2ZYLakrwvqN" + 788 | "gAAAAD42ODc0NzQ3MDNhMmYyZjcyNjk2MzY1MmU2OTZlNjY2ZjJmNjc2OTZmNzY2" + 789 | "MTZlNmU3OTVmNjU2MjY1NzI3NAAAAAAAAAABMAAAAAAAAABBISrH3GQCdKEtSu3j" + 790 | "8JGQAmt0bb3N5rMndYdPdpZ04dB3P0PjBqyAW6cGg/ycoNJlIRI6iykCa+aiJB1w" + 791 | "JiomzcwAAAAxIYi6OcqI1uilWb3yE6T/lSyJZfZGoZM2GTaPK2u7OvuCA4BbdZvh" + 792 | "XytlitWmRYsFigAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAAAAABMAAAAAAAAAAK" + 793 | "MTg3Mjc0NjU3NgAAAAAAAAAAAAAAAAAAAAEwAAAAATAAAAAAAAAAAAAAAAI3NQAA" + 794 | "AAEwAAAAAAAAAAExAAAAATAAAAAAAAAAAAAAAAoxMzczMDc3MTA1QUNDVAAAAWMA" + 795 | "AAAKMTg3Mjc0NjU4NgAAACEhPxthU1wxY1Vfg9FtdzPeaM16ul3vD9ewKUwi0LYx" + 796 | "P4YAAAAAAAAARjY4NzQ3NDcwM2EyZjJmNjc2YzZmNzY2NTcyNmQ2MzZiNjU2ZTdh" + 797 | "Njk2NTJlNjk2ZTY2NmYyZjZiNjE3NDY1NmM3OTZlNmUAAAAAAAAAATAAAAAAAAAA" + 798 | "MSG7r/Ki2TpMoKgYPY6hvy4pkYnySbIRetT2uKIOT0Y08ldKqJpFHpvtZ+jjw7RY" + 799 | "QWIAAAAhIS8zsOjIHPVGtEMzb496ThecPslNg9xnysv7txkZNvrWAAAAATAAAAAB" + 800 | "MAAAAAEwAAAAATAAAAABMAAAAAEwAAAAAAAAAAoxODcyNzQ2NTg2AAAAAAAAAAAA" + 801 | "AAAAAAAAATAAAAABMAAAAAAAAAAAAAAAAAAAAAEwAAAAAAAAAAExAAAAATAAAAAA" + 802 | "AAAAAAAAAAoxMzczMDc3MTA1QUNDVAAAAWQAAAAKMTg3Mjc0NjU5NgAAACEhEbPb" + 803 | "uJsF57lzoIq6F2FKQhgRRAHvN0KIcSuzs8n/jpYAAAAhIekaX0ey4afkTz5BHXGv" + 804 | "A2UOsZh8CYt56eKNR1hLPyJvAAAANDY4NzQ3NDcwM2EyZjJmNzM2OTcwNjU3MzJl" + 805 | "NjM2ZjZkMmY2YTZmNjU3OTJlNmQ2NTc0N2EAAAAAAAAAATAAAAAAAAAAISFFsZHh" + 806 | "NE2jfzflVu2rCoI9yYXShSD22+bIYCqX1bJn2AAAACEhmFKfi0Y4UQ4dVKQLnZWw" + 807 | "LfrmyXG44I9R2KD/547mCsoAAAABMAAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAA" + 808 | "AAAAAAAACjE4NzI3NDY1OTYAAAAAAAAAAAAAAAAAAAABMAAAAAEwAAAAAAAAAAAA" + 809 | "AAACNzYAAAABMAAAAAAAAAABMQAAAAEwAAAAAAAAAAAAAAAKMTM3MzA3NzEwNUFD" + 810 | "Q1QAAAFoAAAACjE4NzI3NDY2MDYAAAAhIUHNGYLU9wBDjFH4cQd5wpL8cvIG1uJF" + 811 | "Z47PcbT4zNJYAAAAISHUq0bIfBWiDXXoroCW6B3zQk0zfiBsrIi+A0CQZQ0HnAAA" + 812 | "ADg2ODc0NzQ3MDNhMmYyZjYyNjU3MjZlNjk2NTcyMmU2ZjcyNjcyZjY3NjE2NzY1" + 813 | "NWY2ODYxNjE2NwAAAAAAAAABMAAAAAAAAAAhIcqK9nXa9CORzJLL17L0HQCur+St" + 814 | "+FnhL4oQAfk9z5uiAAAAISGcPvE/fXdL9HU69fCNLk6kmu4L/Hb7N/K9584AVe+o" + 815 | "qQAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAAAAABMAAAAAAAAAAKMTg3Mjc0NjYw" + 816 | "NgAAAAAAAAAAAAAAAAAAAAEwAAAAATAAAAAAAAAAAAAAAAI3NwAAAAEwAAAAAAAA" + 817 | "AAExAAAAATAAAAAAAAAAAAAAAAoxMzczMDc3MTA1RVFETgAAACUAAAABMQAAABw2" + 818 | "MTZkNjU3MjY5NzQ3MjYxNjQ2NTJlNjM2ZjZkRVFETgAAACkAAAABMQAAACA3NDY0" + 819 | "NjE2ZDY1NzI2OTc0NzI2MTY0NjUyZTYzNmY2ZEVRRE4AAAArAAAAATIAAAAiNjI2" + 820 | "MTZlNmI2ZjY2NjE2ZDY1NzI2OTYzNjEyZTYzNmY2ZEVRRE4AAAAZAAAAATIAAAAQ" + 821 | "NjI2ZjY2NjEyZTYzNmY2ZEVRRE4AAAAZAAAAATIAAAAQNmQ2MjZlNjEyZTYzNmY2" + 822 | "ZEVRRE4AAAAdAAAAATIAAAAUNzU3MzY1NjM2NjZmMmU2MzZmNmRFUUROAAAAHQAA" + 823 | "AAEzAAAAFDczNzA3MjY5NmU3NDJlNjM2ZjZkRVFETgAAACMAAAABMwAAABo3Mzcw" + 824 | "NzI2OTZlNzQ3MDYzNzMyZTYzNmY2ZEVRRE4AAAAdAAAAATMAAAAUNmU2NTc4NzQ2" + 825 | "NTZjMmU2MzZmNmRFUUROAAAAHwAAAAE0AAAAFjc5NmY3NTc0NzU2MjY1MmU2MzZm" + 826 | "NmRFUUROAAAAHQAAAAE0AAAAFDY3NmY2ZjY3NmM2NTJlNjM2ZjZkRVFETgAAABsA" + 827 | "AAABNQAAABI2MTcwNzA2YzY1MmU2MzZmNmRFUUROAAAAHQAAAAE1AAAAFDY5NjM2" + 828 | "YzZmNzU2NDJlNjM2ZjZkRVFETgAAACUAAAABNgAAABw3NzY1NmM2YzczNjY2MTcy" + 829 | "Njc2ZjJlNjM2ZjZkRVFETgAAABUAAAABNgAAAAw3NzY2MmU2MzZmNmRFUUROAAAA" + 830 | "LwAAAAE3AAAAJjczNmY3NTc0Njg2NTcyNmU2MzZmNmQ3MDYxNmU3OTJlNjM2ZjZk" + 831 | "RVFETgAAACUAAAABNwAAABw3MzZmNzU3NDY4NjU3MjZlNjM2ZjJlNjM2ZjZkRVFE" + 832 | "TgAAACwAAAACMTIAAAAiNjE2MzYzNmY3NTZlNzQ2ZjZlNmM2OTZlNjUyZTYzNmY2" + 833 | "ZEVRRE4AAAAaAAAAAjEyAAAAEDYzNjk3NDY5MmU2MzZmNmRFUUROAAAAIgAAAAIx" + 834 | "MgAAABg2MzY5NzQ2OTYyNjE2ZTZiMmU2MzZmNmRFUUROAAAAJAAAAAIxMgAAABo2" + 835 | "MzY5NzQ2OTYzNjE3MjY0NzMyZTYzNmY2ZEVRRE4AAAAaAAAAAjIyAAAAEDYzNmU2" + 836 | "NTc0MmU2MzZmNmRFUUROAAAAHgAAAAIyMgAAABQ2MzZlNjU3NDc0NzYyZTYzNmY2" + 837 | "ZEVRRE4AAAAYAAAAAjIyAAAADjYzNmY2ZDJlNjM2ZjZkRVFETgAAACIAAAACMjIA" + 838 | "AAAYNjQ2Zjc3NmU2YzZmNjE2NDJlNjM2ZjZkRVFETgAAABoAAAACMjIAAAAQNmU2" + 839 | "NTc3NzMyZTYzNmY2ZEVRRE4AAAAeAAAAAjIyAAAAFDczNjU2MTcyNjM2ODJlNjM2" + 840 | "ZjZkRVFETgAAAB4AAAACMjIAAAAUNzU3MDZjNmY2MTY0MmU2MzZmNmRFUUROAAAA" + 841 | "LgAAAAIzMgAAACQ2MjYxNmU2MTZlNjE3MjY1NzA3NTYyNmM2OTYzMmU2MzZmNmRF" + 842 | "UUROAAAAGAAAAAIzMgAAAA42NzYxNzAyZTYzNmY2ZEVRRE4AAAAgAAAAAjMyAAAA" + 843 | "FjZmNmM2NDZlNjE3Njc5MmU2MzZmNmRFUUROAAAAJAAAAAIzMgAAABo3MDY5NzA2" + 844 | "NTcyNmM2OTZkNjUyZTYzNmY2ZEVRRE4AAAAaAAAAAjQyAAAAEDYyNjk2ZTY3MmU2" + 845 | "MzZmNmRFUUROAAAAIAAAAAI0MgAAABY2ODZmNzQ2ZDYxNjk2YzJlNjM2ZjZkRVFE" + 846 | "TgAAABoAAAACNDIAAAAQNmM2OTc2NjUyZTYzNmY2ZEVRRE4AAAAkAAAAAjQyAAAA" + 847 | "GjZkNjk2MzcyNmY3MzZmNjY3NDJlNjM2ZjZkRVFETgAAABgAAAACNDIAAAAONmQ3" + 848 | "MzZlMmU2MzZmNmRFUUROAAAAIgAAAAI0MgAAABg3MDYxNzM3MzcwNmY3Mjc0MmU2" + 849 | "ZTY1NzRFUUROAAAAHAAAAAI1MgAAABI3NTYxMzI2NzZmMmU2MzZmNmRFUUROAAAA" + 850 | "GAAAAAI1MgAAAA43NTYxNmMyZTYzNmY2ZEVRRE4AAAAeAAAAAjUyAAAAFDc1NmU2" + 851 | "OTc0NjU2NDJlNjM2ZjZkRVFETgAAACIAAAACODIAAAAYNmY3NjY1NzI3NDc1NzI2" + 852 | "NTJlNjM2ZjZkRVFETgAAABwAAAACODIAAAASNzk2MTY4NmY2ZjJlNjM2ZjZkRVFE" + 853 | "TgAAACQAAAACOTIAAAAaN2E2ZjZlNjU2MTZjNjE3MjZkMmU2MzZmNmRFUUROAAAA" + 854 | "IgAAAAI5MgAAABg3YTZmNmU2NTZjNjE2MjczMmU2MzZmNmRFUUROAAAAGwAAAAM4" + 855 | "NDIAAAAQNjE3NjZmNmUyZTYzNmY2ZEVRRE4AAAAjAAAAAzg0MgAAABg3OTZmNzU3" + 856 | "MjYxNzY2ZjZlMmU2MzZmNmRFUUROAAAALAAAAAQxNDc0AAAAIDMxMzgzMDMwNjM2" + 857 | "ZjZlNzQ2MTYzNzQ3MzJlNjM2ZjZkRVFETgAAACoAAAAEMTQ3NAAAAB4zODMwMzA2" + 858 | "MzZmNmU3NDYxNjM3NDczMmU2MzZmNmRFUUROAAAAIAAAAAQyMDAwAAAAFDYxNmQ2" + 859 | "MTdhNmY2ZTJlNjM2ZjZkRVFETgAAACQAAAAEMjAwMAAAABg2MTZkNjE3YTZmNmUy" + 860 | "ZTYzNmYyZTc1NmJFUUROAAAAMgAAAAQyMDEwAAAAJjY1Nzg3MDcyNjU3MzczMmQ3" + 861 | "MzYzNzI2OTcwNzQ3MzJlNjM2ZjZkRVFETgAAACoAAAAEMjAxMAAAAB42ZDY1NjQ2" + 862 | "MzZmNjg2NTYxNmM3NDY4MmU2MzZmNmRFUUROAAAAGgAAAAQyMDEyAAAADjYzNmY3" + 863 | "ODJlNjM2ZjZkRVFETgAAABoAAAAEMjAxMgAAAA42MzZmNzgyZTZlNjU3NEVRRE4A" + 864 | "AAAqAAAABDIwMTIAAAAeNjM2Zjc4NjI3NTczNjk2ZTY1NzM3MzJlNjM2ZjZkRVFE" + 865 | "TgAAADIAAAAEMjAyMgAAACY2ZDc5NmU2ZjcyNzQ2ZjZlNjE2MzYzNmY3NTZlNzQy" + 866 | "ZTYzNmY2ZEVRRE4AAAAgAAAABDIwMjIAAAAUNmU2ZjcyNzQ2ZjZlMmU2MzZmNmRF" + 867 | "UUROAAAAIgAAAAQyMDMyAAAAFjc2NjU3MjY5N2E2ZjZlMmU2MzZmNmRFUUROAAAA" + 868 | "IgAAAAQyMDMyAAAAFjc2NjU3MjY5N2E2ZjZlMmU2ZTY1NzRFUUROAAAAIgAAAAQy" + 869 | "MDQyAAAAFjZjNmY2NzZkNjU2OTZlMmU2MzZmNmRFUUROAAAAHAAAAAQyMDQyAAAA" + 870 | "EDZjNmY2NzZkNjUyZTY5NmVFUUROAAAAIgAAAAQyMDUyAAAAFjcyNjE2Yjc1NzQ2" + 871 | "NTZlMmU2MzZmNmRFUUROAAAAGgAAAAQyMDUyAAAADjYyNzU3OTJlNjM2ZjZkRVFE" + 872 | "TgAAACQAAAAEMjA2MgAAABg3MzY5NzI2OTc1NzM3ODZkMmU2MzZmNmRFUUROAAAA" + 873 | "IAAAAAQyMDYyAAAAFDczNjk3MjY5NzU3MzJlNjM2ZjZkRVFETgAAABgAAAAEMjA3" + 874 | "MgAAAAw2NTYxMmU2MzZmNmRFUUROAAAAIAAAAAQyMDcyAAAAFDZmNzI2OTY3Njk2" + 875 | "ZTJlNjM2ZjZkRVFETgAAACYAAAAEMjA3MgAAABo3MDZjNjE3OTM0NjY3MjY1NjUy" + 876 | "ZTYzNmY2ZEVRRE4AAAA0AAAABDIwNzIAAAAoNzQ2OTYyNjU3MjY5NzU2ZDYxNmM2" + 877 | "YzY5NjE2ZTYzNjUyZTYzNmY2ZFVSVUwAAAAoAAAAGjY3NmY2ZjY3NmM2NTJlNjM2" + 878 | "ZjZkMmY2MTJmAAAAATAAAAABMFVSVUwAAAAkAAAAFjZjNmY2NzZkNjU2OTZlMmU2" + 879 | "MzZmNmQAAAABMQAAAAEwVVJVTAAAADoAAAAsNzM2OTc0NjU3MzJlNjc2ZjZmNjc2" + 880 | "YzY1MmU2MzZmNmQyZjczNjk3NDY1MmYAAAABMAAAAAEwVVJVTAAAACIAAAAUNzc2" + 881 | "NTY1NjI2Yzc5MmU2MzZmNmQAAAABMQAAAAEwVVJVTAAAABwAAAAONzc2OTc4MmU2" + 882 | "MzZmNmQAAAABMQAAAAEwVVJVTAAAAB4AAAAQNzc2NTYyNzMyZTYzNmY2ZAAAAAEx" + 883 | "AAAAATBVUlVMAAAAKAAAABo2ODZmNmQ2NTczNzQ2NTYxNjQyZTYzNmY2ZAAAAAEx" + 884 | "AAAAATBVUlVMAAAAKAAAABo3NzZmNzI2NDcwNzI2NTczNzMyZTYzNmY2ZAAAAAEx" + 885 | "AAAAATBVUlVMAAAAIAAAABI2YTY5NmQ2NDZmMmU2MzZmNmQAAAABMQAAAAEwVVJV" + 886 | "TAAAACgAAAAaNzc2NTYyNzM3NDYxNzI3NDczMmU2MzZmNmQAAAABMQAAAAEwVVJV" + 887 | "TAAAACgAAAAaNzM2ZTYxNzA3MDYxNjc2NTczMmU2MzZmNmQAAAABMQAAAAEwVVJV" + 888 | "TAAAACwAAAAeNjM2YzZmNzU2NDYxNjM2MzY1NzM3MzJlNmU2NTc0AAAAATEAAAAB" + 889 | "MFVSVUwAAAAkAAAAFjc3NjU2MjZlNmY2NDY1MmU2MzZmNmQAAAABMQAAAAEwVVJV" + 890 | "TAAAACwAAAAeNmY2ZTZkNjk2MzcyNmY3MzZmNjY3NDJlNjM2ZjZkAAAAATEAAAAB" + 891 | "MFVSVUwAAAAoAAAAGjY4NjU3MjZmNmI3NTYxNzA3MDJlNjM2ZjZkAAAAATEAAAAB" + 892 | "MFVSVUwAAAAaAAAADDZlNmY3NjJlNzI3NQAAAAExAAAAATBFTkRNAAAAAk9L") 893 | 894 | TEST_ENCRYPTION_KEY = b64decode("p8utF7ZB8yD06SrtrD4hsdvEOiBU1Y19cr2dhG9DWZg=") 895 | TEST_KEY_ITERATION_COUNT = 5000 896 | 897 | TEST_ACCOUNTS = [ 898 | Account(b"1872745596", b"Muller, Morar and Wisoky", b"branson_cormier", b"8jgLCzQSkB2rTZ1OtF9sNGpc", b"http://nienow.net/meagan.greenholt", b"three"), 899 | Account(b"1872745606", b"goyette.net", b"kris_quigley@baileyjewe.biz", b"S5@3^wPv!6JsFj", b"http://bechtelar.biz/tristian.barrows", b"four"), 900 | Account(b"1872745616", b"Ward Inc", b"angela_emard", b"zp8N@KoWyS0IYu7VR$dvBF!t", b"http://schuster.name/ashton", b"one"), 901 | Account(b"1872745626", b"stehr.com", b"bailee_marvin@mohrlegros.net", b"cupiditate", b"http://runolfon.org/te", b"three"), 902 | Account(b"1872745636", b"kiehn.biz", b"freda", b"et", b"http://hintzprohaska.biz/wade.fisher", b"one"), 903 | Account(b"1872745646", b"Jacobs and Sons", b"johnnie.hand", b"gzyl6714", b"http://schultzheaney.org/arvid", b""), 904 | Account(b"1872745656", b"Larkin, Kautzer and Wiegand", b"hilton", b"zguovmdr8703", b"http://streich.com/ramona", b"one"), 905 | Account(b"1872745666", b"Conn Inc", b"malvina_paucek@nikolausveum.net", b"numquam", b"http://conn.net/leda", b"four"), 906 | Account(b"1872745676", b"Block, Sanford and Connelly", b"marilie_wolff", b"zKcy?U*aCGS^gf@Z", b"http://conroy.biz/zachery", b"two"), 907 | Account(b"1872745686", b"gradyrenner.org", b"oswald@ryan.info", b"ojgwad28", b"http://kihn.org/candice", b""), 908 | Account(b"1872745696", b"lesch.net", b"nicholas", b"Pkc72Lmr1qwI%sNV^d4@GtX", b"http://glover.name/jerad", b"two"), 909 | Account(b"1872745706", b"sipes.biz", b"kaitlyn.bernier@reichel.net", b"in", b"http://mayert.name/jeromy", b"two"), 910 | Account(b"1872745716", b"Hintz-Herman", b"prince.moriette", b"0hebvIS@s^BwMc", b"http://sanfordwunsch.org/alek", b""), 911 | Account(b"1872745726", b"Hammes-Kassulke", b"brooke@gloverhintz.net", b"paokcs08", b"http://lehner.biz/stanley.dooley", b"four"), 912 | Account(b"1872745736", b"hermann.com", b"jasper_dickens", b"Ppj2b!rIMLu*@ElTCZU", b"http://rolfson.net/jaden", b"one"), 913 | Account(b"1872745746", b"Veum and Sons", b"marquise@quitzonbrown.com", b"owsg728", b"http://fahey.name/jon_ankunding", b"one"), 914 | Account(b"1872745756", b"Balistreri, Emard and Mayert", b"verona@willmswhite.info", b"wnydas6714", b"http://treutelkiehn.org/marcos", b"two"), 915 | Account(b"1872745766", b"lindkeler.net", b"ed", b"quia", b"http://leffler.info/chaya", b"one"), 916 | Account(b"1872745776", b"nikolaus.biz", b"leonard", b"oW9fdvJLkp#%I", b"http://brakuswilliamson.com/bret", b""), 917 | Account(b"1872745786", b"bartonherzog.net", b"dock@vonrueden.net", b"beatae", b"http://kunzeokuneva.info/shawn_langosh", b"three"), 918 | Account(b"1872745796", b"howe.org", b"chad@walker.biz", b"zexfir7951", b"http://crooks.com/sandrine", b""), 919 | Account(b"1872745806", b"shields.info", b"modesto@kunzenicolas.com", b"*JDSdp@VyR8f5FOALW", b"http://kemmer.org/hilton", b"three"), 920 | Account(b"1872745816", b"kihnabernathy.com", b"mafalda.treutel@gislason.name", b"hwuoxizq18", b"http://trompbernhard.com/trea.hirthe", b"two"), 921 | Account(b"1872745826", b"Gislason and Sons", b"torrey@kshlerin.info", b"OfZrTFAIq?Uyl9X$", b"http://ullrich.info/carlee", b"four"), 922 | Account(b"1872745836", b"simonis.com", b"marco.cronin", b"upokmxct57", b"http://rippin.name/bonita_hickle", b"four"), 923 | Account(b"1872745856", b"Howell, Beer and Yundt", b"raegan@cruickshankgreenholt.org", b"dHPFrtOjieum4L", b"http://aufderharrunolfsdottir.info/felicia_torphy", b"two"), 924 | Account(b"1872745866", b"Gottlieb-Ernser", b"ivory.moore@paucek.com", b"fugit", b"http://lockmanlynch.net/alba", b"four"), 925 | Account(b"1872745876", b"Emmerich and Sons", b"lacey.bernier@hansenboyer.com", b"aqzkolu6021", b"http://carrollschmitt.com/willy.emard", b"three"), 926 | Account(b"1872745886", b"Gerlach, Kirlin and Roberts", b"maiya@bayergusikowski.org", b"nhit3214", b"http://feil.net/natasha_howe", b"one"), 927 | Account(b"1872745896", b"ryan.net", b"rubie@fahey.org", b"aihw^uFgXnC%R", b"http://gleasonjakubowski.biz/august", b""), 928 | Account(b"1872745906", b"Jewess, Wolf and Volkman", b"kristin_blanda@howekuhlman.biz", b"nacro5213", b"http://wilkinsonleannon.name/bud.willms", b"two"), 929 | Account(b"1872745916", b"Ritchie Group", b"nathen_ortiz@turner.biz", b"XfmN@G%ebsK1Jc$q", b"http://price.info/urban", b"two"), 930 | Account(b"1872745926", b"wiegand.info", b"lavon_greenholt", b"fzedpuq30", b"http://paucekturcotte.org/kadin_gibson", b""), 931 | Account(b"1872745936", b"Rohan, Schneider and Daniel", b"zella.effertz", b"wksei21", b"http://runte.com/camryn.hane", b"one"), 932 | Account(b"1872745946", b"boyle.name", b"gennaro_goldner@kovacek.biz", b"eaJD#Kb6UAis@M*8jhILk", b"http://kulasklein.info/nyasia", b"four"), 933 | Account(b"1872745956", b"Pouros-Funk", b"maudie@fahey.org", b"wahkvms6871", b"http://schaefer.info/leslie.bogan", b"three"), 934 | Account(b"1872745966", b"Parisian-Legros", b"holly", b"et", b"http://naderrempel.net/gwen_schmidt", b"four"), 935 | Account(b"1872745976", b"Rosenbaum-Schulist", b"jordy.krajcik", b"xqzflsy843", b"http://dooley.info/alek_parker", b"four"), 936 | Account(b"1872745986", b"christiansen.info", b"phoebe@larson.info", b"bilvs07", b"http://johns.name/columbus.dooley", b"two"), 937 | Account(b"1872745996", b"Hauck, Thiel and VonRueden", b"leif", b"QVx?JvZ46e1FBmsAi", b"http://bauch.org/marlin", b"one"), 938 | Account(b"1872746006", b"Sipes and Sons", b"leland", b"ecgs1758", b"http://dubuque.com/jacey", b"one"), 939 | Account(b"1872746016", b"Osinski LLC", b"rhoda", b"nhwo705", b"http://schinner.org/price", b"four"), 940 | Account(b"1872746026", b"daniel.name", b"santina@wiegand.net", b"dolorem", b"http://torp.net/shyanne.smitham", b""), 941 | Account(b"1872746036", b"darekutch.name", b"ali", b"U*kgl8u1p#QO9xWNnEd0b3", b"http://mante.com/caie_streich", b""), 942 | Account(b"1872746046", b"grimes.com", b"eunice_satterfield@baileymante.net", b"ipsam", b"http://swaniawski.org/wendell_gaylord", b"three"), 943 | Account(b"1872746056", b"conn.name", b"sandrine", b"rv%XVjo#2Id?@4L", b"http://rolfson.com/willy_bartell", b""), 944 | Account(b"1872746066", b"Kozey-Spinka", b"brando.kshlerin", b"consequatur", b"http://collinsreichel.net/yasmine", b"three"), 945 | Account(b"1872746076", b"Daugherty LLC", b"horacio_schulist@davis.net", b"sbxzn64", b"http://deckow.net/roosevelt.kshlerin", b"four"), 946 | Account(b"1872746086", b"Lubowitz LLC", b"maxine@ebertmckenzie.biz", b"qrcl02", b"http://considineheidenreich.name/name.christiansen", b""), 947 | Account(b"1872746096", b"mante.name", b"jayne", b"xnekizj90", b"http://bogisich.net/lori", b"four"), 948 | Account(b"1872746106", b"Mante LLC", b"antonio.turner@sauertorphy.com", b"ckomnf175", b"http://herzog.name/luigi", b""), 949 | Account(b"1872746116", b"Greenholt-Hodkiewicz", b"moriah@mccullough.org", b"udaxo7451", b"http://mann.com/cecile", b"three"), 950 | Account(b"1872746126", b"Rosenbaum, Sipes and Leffler", b"keshaun@schroeder.info", b"recusandae", b"http://dooley.name/ewald", b"two"), 951 | Account(b"1872746136", b"Fadel, Ferry and Kohler", b"sister", b"sUxoLNhl8Kty*Ve76b45G", b"http://balistrerimcclure.com/jaquan_wilkinson", b"two"), 952 | Account(b"1872746146", b"Schaden-Rosenbaum", b"godfrey", b"oDVcsx*m!0Rb@NjSyqdGIl", b"http://pouros.net/jeremie", b""), 953 | Account(b"1872746156", b"Monahan, Reinger and McKenzie", b"christophe.kub@luettgen.name", b"fLqj&e$TyNo8gd7!", b"http://keler.info/nikita.lindgren", b"four"), 954 | Account(b"1872746166", b"bednar.info", b"roselyn@hickle.com", b"*2tiEP&Ic7dT", b"http://jaskolski.com/conner_ortiz", b"two"), 955 | Account(b"1872746176", b"Jewess, Wolf and Feil", b"hal", b"doloribus", b"http://champlin.org/lue_schroeder", b"three"), 956 | Account(b"1872746186", b"Kunze-Hettinger", b"camilla_pagac", b"elpbzT08Dvo6NyQF3wPEr", b"http://donnellyadams.com/santino", b"one"), 957 | Account(b"1872746196", b"Jacobs, Toy and Schultz", b"billy_boehm@will.biz", b"g5X*hRwlmcL6ZM", b"http://larkinconsidine.org/leola", b"one"), 958 | Account(b"1872746206", b"sanford.com", b"joy@abbott.org", b"rfolun872", b"http://runtemoen.name/pierre", b"three"), 959 | Account(b"1872746216", b"upton.net", b"susana.gaylord", b"WR4KxbU^@$Vpi%QH9Mv#T", b"http://moore.info/pearl", b"three"), 960 | Account(b"1872746226", b"wiegand.biz", b"ashleigh_gutmann", b"t7C&j!Ox21oha5sX*f", b"http://armstronghackett.name/jaeden", b"three"), 961 | Account(b"1872746236", b"schneider.net", b"eunice.sauer@ledner.org", b"U%EFVGnxw2fQ^t*", b"http://schulistmetz.info/esperanza_cummerata", b"two"), 962 | Account(b"1872746246", b"Swift-Stoltenberg", b"katelin_rempel", b"labore", b"http://beermills.net/danielle", b"two"), 963 | Account(b"1872746256", b"Heathcote Group", b"hope.waters@parisianbruen.info", b"EhG7zBTb8OseI", b"http://douglas.name/porter", b""), 964 | Account(b"1872746266", b"hilpert.com", b"phyllis.lemke", b"est", b"http://donnelly.com/tyrique_langosh", b"one"), 965 | Account(b"1872746276", b"daviswolff.name", b"martine@ryan.com", b"incidunt", b"http://schoen.info/macy", b"one"), 966 | Account(b"1872746286", b"Bahringer, Prohaska and Mills", b"merritt_reilly@lynch.info", b"dyX^xZ3HTKsqFIMeA", b"http://schuppe.com/rosetta.yundt", b""), 967 | Account(b"1872746296", b"ledner.name", b"billie.lueilwitz@kertzmann.org", b"Zi5K6tXh91mJG3EnjBD4r", b"http://feil.com/isabelle", b"four"), 968 | Account(b"1872746306", b"jerdecormier.com", b"renee.towne@ruecker.net", b"vuzoskg85", b"http://mckenzie.net/zaria", b""), 969 | Account(b"1872746316", b"harbervandervort.org", b"elta_haag@okuneva.net", b"2?GVri70HkKceU*m#CZ3x", b"http://whiteklocko.name/lacey.dare", b"one"), 970 | Account(b"1872746326", b"gulgowskimann.org", b"chaz_brakus", b"explicabo", b"http://okuneva.biz/lisandro", b"two"), 971 | Account(b"1872746336", b"padbergconn.info", b"lenore@ullrich.net", b"ORrNKnhuqd7xeULa^YDk", b"http://sauerkuvalis.info/braxton", b"one"), 972 | Account(b"1872746346", b"davis.com", b"margarett", b"debitis", b"http://spinka.info/kendra", b""), 973 | Account(b"1872746366", b"Gerlach Inc", b"krystel_boyer", b"qui", b"http://pouromitham.name/efrain", b"three"), 974 | Account(b"1872746376", b"cummerata.net", b"rudy.flatley", b"mzqvakic527", b"http://heidenreich.net/ryann_hayes", b""), 975 | Account(b"1872746386", b"schowalter.name", b"hyman.satterfield", b"pjts564", b"http://okeefedamore.biz/giovani", b"one"), 976 | Account(b"1872746396", b"McLaughlin-Fadel", b"fanny_sporer", b"kyti64", b"http://dickibosco.biz/zachariah", b"four"), 977 | Account(b"1872746406", b"Gerlach-Nienow", b"treva.block", b"csnxhldi893", b"http://kunzemurazik.net/johnny.koch", b"two"), 978 | Account(b"1872746416", b"O'Reilly-Trantow", b"grayson", b"non", b"http://harris.name/rosalind_marquardt", b"three"), 979 | Account(b"1872746426", b"Larkin-Konopelski", b"josianne_walker", b"bwms78", b"http://runolfsdottir.name/nicklaus_hayes", b"two"), 980 | Account(b"1872746436", b"Swaniawski, Will and Gaylord", b"jeramie.ohara@nader.org", b"quia", b"http://oreilly.info/dahlia_donnelly", b""), 981 | Account(b"1872746446", b"emmerichgaylord.name", b"diana@hansenbeahan.net", b"omnis", b"http://rath.net/leif_hermann", b"three"), 982 | Account(b"1872746456", b"armstrong.org", b"genesis@rosenbaumlueilwitz.biz", b"zHeu%^kxj9Y0Qr4@m*3!ov", b"http://schmidtmertz.name/kira", b"one"), 983 | Account(b"1872746466", b"Waelchi Group", b"trace.heaney@heidenreichbernier.com", b"whljnru03", b"http://moore.biz/anibal", b"two"), 984 | Account(b"1872746476", b"fahey.org", b"ward_okuneva", b"qjnz18", b"http://leuschke.com/daphney", b"two"), 985 | Account(b"1872746486", b"koelpin.info", b"dylan.klocko", b"vdjlot364", b"http://cronin.net/cyril", b"three"), 986 | Account(b"1872746496", b"Murphy-Breitenberg", b"marcia_kreiger", b"dacyz723", b"http://steuber.com/ali_gibson", b"three"), 987 | Account(b"1872746506", b"andersondicki.org", b"ceasar@lind.com", b"nvymdsk14", b"http://kertzmann.biz/jaydon_kunze", b"four"), 988 | Account(b"1872746516", b"watersreichel.net", b"adella_price@beahanblock.biz", b"maiores", b"http://gutkowskirau.org/dora.williamson", b"four"), 989 | Account(b"1872746526", b"torphy.biz", b"osborne_hackett@davis.org", b"wkdcu1265", b"http://buckridge.net/lauretta.veum", b"four"), 990 | Account(b"1872746536", b"Moen-Hermiston", b"hildegard@hahn.com", b"zbag942", b"http://cummingswehner.biz/april", b""), 991 | Account(b"1872746546", b"Gaylord-Lowe", b"jerrell", b"quasi", b"http://grady.biz/mohammed_brakus", b""), 992 | Account(b"1872746556", b"Bechtelar, Wyman and Thompson", b"shanie@batz.biz", b"vel", b"http://gottlieb.name/elisabeth", b"four"), 993 | Account(b"1872746566", b"jacobs.info", b"lon_champlin@cristlittel.name", b"aut", b"http://dachgislason.org/alva", b"two"), 994 | Account(b"1872746576", b"ankunding.com", b"reina_runolfon@altenwerthhilll.net", b"@g&aWsoTeJEFhHK5wr#4", b"http://rice.info/giovanny_ebert", b"two"), 995 | Account(b"1872746586", b"Okuneva-Schmitt", b"esperanza@kshlerin.com", b"djwhba31", b"http://glovermckenzie.info/katelynn", b""), 996 | Account(b"1872746596", b"jones.name", b"elvera", b"ewoqt49", b"http://sipes.com/joey.metz", b"two"), 997 | Account(b"1872746606", b"Tromp-Roob", b"brisa.mcdermott", b"vcnkg254", b"http://bernier.org/gage_haag", b"three"), 998 | ] 999 | -------------------------------------------------------------------------------- /tests/test_fetcher.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from base64 import b64decode 3 | import unittest 4 | import mock 5 | import lastpass 6 | from lastpass.blob import Blob 7 | from lastpass import fetcher 8 | from lastpass.session import Session 9 | 10 | 11 | class FetcherTestCase(unittest.TestCase): 12 | def setUp(self): 13 | self.username = 'username' 14 | self.password = 'password' 15 | self.key_iteration_count = 5000 16 | 17 | self.hash = b'7880a04588cfab954aa1a2da98fd9c0d2c6eba4c53e36a94510e6dbf30759256' 18 | self.session_id = '53ru,Hb713QnEVM5zWZ16jMvxS0' 19 | self.session = Session(self.session_id, self.key_iteration_count) 20 | 21 | self.blob_response = 'TFBBVgAAAAMxMjJQUkVNAAAACjE0MTQ5' 22 | self.blob_bytes = b64decode(self.blob_response) 23 | self.blob = Blob(self.blob_bytes, self.key_iteration_count) 24 | 25 | self.login_post_data = {'method': 'mobile', 26 | 'web': 1, 27 | 'xml': 1, 28 | 'username': self.username, 29 | 'hash': self.hash, 30 | 'iterations': self.key_iteration_count} 31 | 32 | self.device_id = '492378378052455' 33 | self.login_post_data_with_device_id = self.login_post_data.copy() 34 | self.login_post_data_with_device_id.update({'imei': self.device_id}) 35 | 36 | self.google_authenticator_code = '12345' 37 | self.yubikey_password = 'emdbwzemyisymdnevznyqhqnklaqheaxszzvtnxjrmkb' 38 | 39 | self.login_post_data_with_google_authenticator_code = self.login_post_data.copy() 40 | self.login_post_data_with_google_authenticator_code['otp'] = self.google_authenticator_code 41 | 42 | self.login_post_data_with_yubikey_password = self.login_post_data.copy() 43 | self.login_post_data_with_yubikey_password['otp'] = self.yubikey_password 44 | 45 | def test_logout_makes_a_get_request(self): 46 | m = mock.Mock() 47 | m.get.return_value = self._http_ok('') 48 | fetcher.logout(self.session, m) 49 | m.get.assert_called_with( 50 | 'https://lastpass.com/logout.php?mobile=1', 51 | cookies={'PHPSESSID': self.session_id} 52 | ) 53 | 54 | def test_logout_raises_an_exception_on_HTTP_error(self): 55 | m = mock.Mock() 56 | m.post.return_value = self._http_error() 57 | self.assertRaises(lastpass.NetworkError, fetcher.logout, self.session, m) 58 | 59 | def test_request_iteration_count_makes_a_post_request(self): 60 | m = mock.Mock() 61 | m.post.return_value = self._http_ok(str(self.key_iteration_count)) 62 | fetcher.request_iteration_count(self.username, m) 63 | m.post.assert_called_with('https://lastpass.com/iterations.php', 64 | data={'email': self.username}, 65 | headers=fetcher.headers) 66 | 67 | def test_request_iteration_count_returns_key_iteration_count(self): 68 | m = mock.Mock() 69 | m.post.return_value = self._http_ok(str(self.key_iteration_count)) 70 | self.assertEqual(fetcher.request_iteration_count(self.username, m), self.key_iteration_count) 71 | 72 | def test_request_iteration_count_raises_an_exception_on_http_error(self): 73 | m = mock.Mock() 74 | m.post.return_value = self._http_error() 75 | self.assertRaises(lastpass.NetworkError, fetcher.request_iteration_count, self.username, m) 76 | 77 | def test_request_iteration_count_raises_an_exception_on_invalid_key_iteration_count(self): 78 | m = mock.Mock() 79 | m.post.return_value = self._http_ok('not a number') 80 | self.assertRaises(lastpass.InvalidResponseError, fetcher.request_iteration_count, self.username, m) 81 | 82 | def test_request_iteration_count_raises_an_exception_on_zero_key_iteration_cont(self): 83 | m = mock.Mock() 84 | m.post.return_value = self._http_ok('0') 85 | self.assertRaises(lastpass.InvalidResponseError, fetcher.request_iteration_count, self.username, m) 86 | 87 | def test_request_iteration_count_raises_an_exception_on_negative_key_iteration_cont(self): 88 | m = mock.Mock() 89 | m.post.return_value = self._http_ok('-1') 90 | self.assertRaises(lastpass.InvalidResponseError, fetcher.request_iteration_count, self.username, m) 91 | 92 | def test_request_login_makes_a_post_request(self): 93 | self._verify_request_login_post_request(None, None, self.login_post_data) 94 | 95 | def test_request_login_makes_a_post_request_with_device_id(self): 96 | self._verify_request_login_post_request(None, self.device_id, self.login_post_data_with_device_id) 97 | 98 | def test_request_login_makes_a_post_request_with_google_authenticator_code(self): 99 | self._verify_request_login_post_request(self.google_authenticator_code, 100 | None, 101 | self.login_post_data_with_google_authenticator_code) 102 | 103 | def test_request_login_makes_a_post_request_with_yubikey_password(self): 104 | self._verify_request_login_post_request(self.yubikey_password, 105 | None, 106 | self.login_post_data_with_yubikey_password) 107 | 108 | def test_request_login_returns_a_session(self): 109 | self.assertEqual(self._request_login_with_xml(''.format(self.session_id)), self.session) 110 | 111 | def test_request_login_raises_an_exception_on_http_error(self): 112 | self.assertRaises(lastpass.NetworkError, self._request_login_with_error) 113 | 114 | def test_request_login_raises_an_exception_when_response_is_not_a_hash(self): 115 | self.assertRaises(lastpass.InvalidResponseError, self._request_login_with_ok, 'not a hash') 116 | 117 | def test_request_login_raises_an_exception_on_unknown_response_schema_1(self): 118 | self.assertRaises(lastpass.UnknownResponseSchemaError, self._request_login_with_xml, '') 119 | 120 | def test_request_login_raises_an_exception_on_unknown_response_schema_2(self): 121 | self.assertRaises(lastpass.UnknownResponseSchemaError, self._request_login_with_xml, '') 122 | 123 | def test_request_login_raises_an_exception_on_unknown_response_schema_3(self): 124 | self.assertRaises(lastpass.UnknownResponseSchemaError, 125 | self._request_login_with_xml, '') 126 | 127 | def test_request_login_raises_an_exception_on_unknown_username(self): 128 | self.assertRaises(lastpass.LastPassUnknownUsernameError, 129 | self._request_login_with_lastpass_error, 'unknownemail') 130 | 131 | def test_request_login_raises_an_exception_on_invalid_password(self): 132 | self.assertRaises(lastpass.LastPassInvalidPasswordError, 133 | self._request_login_with_lastpass_error, 'unknownpassword') 134 | 135 | def test_request_login_raises_an_exception_on_missing_google_authenticator_code(self): 136 | message = 'Google Authenticator authentication required! ' \ 137 | 'Upgrade your browser extension so you can enter it.' 138 | self.assertRaises(lastpass.LastPassIncorrectGoogleAuthenticatorCodeError, 139 | self._request_login_with_lastpass_error, 'googleauthrequired', message) 140 | 141 | def test_request_login_raises_an_exception_on_incorrect_google_authenticator_code(self): 142 | message = 'Google Authenticator authentication failed!' 143 | self.assertRaises(lastpass.LastPassIncorrectGoogleAuthenticatorCodeError, 144 | self._request_login_with_lastpass_error, 'googleauthfailed', message) 145 | 146 | def test_request_login_raises_an_exception_on_missing_or_incorrect_yubikey_password(self): 147 | message = 'Your account settings have restricted you from logging in ' \ 148 | 'from mobile devices that do not support YubiKey authentication.' 149 | self.assertRaises(lastpass.LastPassIncorrectYubikeyPasswordError, 150 | self._request_login_with_lastpass_error, 'yubikeyrestricted', message) 151 | 152 | def test_request_login_raises_an_exception_on_unknown_lastpass_error_without_a_message(self): 153 | cause = 'Unknown cause' 154 | self.assertRaises(lastpass.LastPassUnknownError, 155 | self._request_login_with_lastpass_error, cause) 156 | 157 | def test_fetch_makes_a_get_request(self): 158 | m = mock.Mock() 159 | m.get.return_value = self._http_ok(self.blob_response) 160 | fetcher.fetch(self.session, m) 161 | m.get.assert_called_with('https://lastpass.com/getaccts.php?mobile=1&b64=1&hash=0.0&hasplugin=3.0.23&requestsrc=android', 162 | cookies={'PHPSESSID': self.session_id}) 163 | 164 | def test_fetch_returns_a_blob(self): 165 | m = mock.Mock() 166 | m.get.return_value = self._http_ok(self.blob_response) 167 | self.assertEqual(fetcher.fetch(self.session, m), self.blob) 168 | 169 | def test_fetch_raises_exception_on_http_error(self): 170 | m = mock.Mock() 171 | m.get.return_value = self._http_error() 172 | self.assertRaises(lastpass.NetworkError, fetcher.fetch, self.session, m) 173 | 174 | def test_make_key_generates_correct_keys(self): 175 | keys = [ 176 | (1, b64decode('C/Bh2SGWxI8JDu54DbbpV8J9wa6pKbesIb9MAXkeF3Y=')), 177 | (5, b64decode('pE9goazSCRqnWwcixWM4NHJjWMvB5T15dMhe6ug1pZg=')), 178 | (10, b64decode('n9S0SyJdrMegeBHtkxUx8Lzc7wI6aGl+y3/udGmVey8=')), 179 | (50, b64decode('GwI8/kNy1NjIfe3Z0VAZfF78938UVuCi6xAL3MJBux0=')), 180 | (100, b64decode('piGdSULeHMWiBS3QJNM46M5PIYwQXA6cNS10pLB3Xf8=')), 181 | (500, b64decode('OfOUvVnQzB4v49sNh4+PdwIFb9Fr5+jVfWRTf+E2Ghg=')), 182 | (1000, b64decode('z7CdwlIkbu0XvcB7oQIpnlqwNGemdrGTBmDKnL9taPg=')), 183 | ] 184 | 185 | for iterations, key in keys: 186 | self.assertEqual(key, fetcher.make_key('postlass@gmail.com', 'pl1234567890', iterations)) 187 | 188 | def test_make_hash(self): 189 | hashes = [ 190 | (1, b'a1943cfbb75e37b129bbf78b9baeab4ae6dd08225776397f66b8e0c7a913a055'), 191 | (5, b'a95849e029a7791cfc4503eed9ec96ab8675c4a7c4e82b00553ddd179b3d8445'), 192 | (10, b'0da0b44f5e6b7306f14e92de6d629446370d05afeb1dc07cfcbe25f169170c16'), 193 | (50, b'1d5bc0d636da4ad469cefe56c42c2ff71589facb9c83f08fcf7711a7891cc159'), 194 | (100, b'82fc12024acb618878ba231a9948c49c6f46e30b5a09c11d87f6d3338babacb5'), 195 | (500, b'3139861ae962801b59fc41ff7eeb11f84ca56d810ab490f0d8c89d9d9ab07aa6'), 196 | (1000, b'03161354566c396fcd624a424164160e890e96b4b5fa6d942fc6377ab613513b'), 197 | ] 198 | 199 | for iterations, hash in hashes: 200 | self.assertEqual(hash, fetcher.make_hash('postlass@gmail.com', 'pl1234567890', iterations)) 201 | 202 | def _verify_request_login_post_request(self, multifactor_password, device_id, post_data): 203 | m = mock.Mock() 204 | m.post.return_value = self._http_ok(''.format(self.session_id)) 205 | fetcher.request_login(self.username, self.password, self.key_iteration_count, multifactor_password, device_id, m) 206 | m.post.assert_called_with('https://lastpass.com/login.php', 207 | data=post_data, 208 | headers=fetcher.headers) 209 | 210 | @staticmethod 211 | def _mock_response(code, body): 212 | m = mock.Mock() 213 | m.status_code = code 214 | m.content = body 215 | return m 216 | 217 | def _http_ok(self, body): 218 | return self._mock_response(200, body) 219 | 220 | def _http_error(self, body=''): 221 | return self._mock_response(404, body) 222 | 223 | @staticmethod 224 | def _lastpass_error(cause, message): 225 | if message: 226 | return ''.format(cause, message) 227 | return ''.format(cause) 228 | 229 | def _request_login_with_lastpass_error(self, cause, message=None): 230 | return self._request_login_with_xml(self._lastpass_error(cause, message)) 231 | 232 | def _request_login_with_xml(self, text): 233 | return self._request_login_with_ok(text) 234 | 235 | def _request_login_with_ok(self, response): 236 | return self._request_login_with_response(self._http_ok(response)) 237 | 238 | def _request_login_with_error(self): 239 | return self._request_login_with_response(self._http_error()) 240 | 241 | def _request_login_with_response(self, response): 242 | m = mock.Mock() 243 | m.post.return_value = response 244 | return fetcher.request_login(self.username, self.password, self.key_iteration_count, None, None, m) 245 | -------------------------------------------------------------------------------- /tests/test_http.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | import requests 4 | from lastpass import fetcher 5 | 6 | 7 | class HttpTestCase(unittest.TestCase): 8 | def setUp(self): 9 | pass 10 | 11 | def test_can_set_the_proxy_options(self): 12 | self.assertIsNotNone(fetcher.http) 13 | fetcher.http = requests.session() 14 | fetcher.http.proxies = { 15 | 'http': 'http://ffazbear:itsme@proxy.fazbearentertainment.com:1987', 16 | 'https': 'https://ffazbear:itsme@proxy.fazbearentertainment.com:1987', 17 | } 18 | 19 | self.assertEqual( 20 | fetcher.http.proxies['https'], 21 | 'https://ffazbear:itsme@proxy.fazbearentertainment.com:1987' 22 | ) 23 | -------------------------------------------------------------------------------- /tests/test_parser.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from base64 import b64decode 3 | import codecs 4 | import unittest 5 | from io import BytesIO 6 | from lastpass.blob import Blob 7 | from lastpass.chunk import Chunk 8 | from lastpass import parser 9 | from tests.test_data import TEST_BLOB, TEST_ACCOUNTS, TEST_ENCRYPTION_KEY 10 | 11 | 12 | class ParserTestCase(unittest.TestCase): 13 | def setUp(self): 14 | self.key_iteration_count = 5000 15 | self.blob = Blob(TEST_BLOB, self.key_iteration_count) 16 | self.padding = 'BEEFFACE' 17 | self.encryption_key = b64decode('OfOUvVnQzB4v49sNh4+PdwIFb9Fr5+jVfWRTf+E2Ghg=') 18 | self.encoded_rsa_key = ("98F3F5518AE7C03EBBF195A616361619033509FB1FFA0408E883B7C5E80381F8" + 19 | "C8A343925DDA78FB06A14324BEC77EAF63290D381F54763A2793FE25C3247FC0" + 20 | "29022687F453426DE96A9FB34CEB55C02764FB41E5E1619226FE47FA7EA40B41" + 21 | "0973132F7AB2DE2D7F08C181C7D56BBF92CD4D44BC7DEE4253DEC36C77D28E30" + 22 | "6F41B8BB26B0EDB97BADCEE912D3671C22339036FC064F5AF60D3545D47B8263" + 23 | "6BBA1896ECDCF5EBE99A1061EFB8FBBD6C3500EA06A28BB8863F413702D9C05B" + 24 | "9A54120F1BEFA0D98A48E82622A36DBD79772B5E4AD957045DC2B97311983592" + 25 | "A357037DDA172C284B4FEC7DF8962A11B42079D6F943C8F9C0FEDFEA0C43A362" + 26 | "B550E217715FD82D9F3BB168A006B0880B1F3660076158FE8CF6B706CF2FEAA1" + 27 | "A731D1F68B1BC20E7ADE15097D2CD84606B4B0756DFE25DAF110D62841F44265" + 28 | "73A676B904972B31AD7B02093C536341E1DA943F1AFF88DF2005BD04C6897FB6" + 29 | "F9E307DA1C2BD219AB39F911FF90C6B1EA658C72C67C1EADC36CD5202654B4E1" + 30 | "99A88F13DCE1148CC04F81485896627BB1DB5C73969520CC66652492383930E3" + 31 | "3AFD57BE171F4BA25016EC9C3662F5B054101E381565433E46CB9FD517B59AE8" + 32 | "A5CE7D11005282E551E9DCAA1996763E41B49677F906F122AAB76E852F35B31F" + 33 | "397B70949D5F6C8DAA244AF16E9D48E0801E5C6D3FCEAFD2C3E157968B3E796C" + 34 | "87E1F3FFF86B62FE5263D1A597E3906BF697C019F1F543D7BB1E11B08837B47F" + 35 | "4528E4B47EB77508CFC0581B2A005383D0A238EA5BDE2E2602E0D2408B139735" + 36 | "F4BAF8D6CF260BBC81833A85F14C5746AC6081B878486F5A4BD23B821F3F5F6B" + 37 | "DAC8A9B57E25E24EDB8D701F01AE142D63A8A7D0F1CC8FAFF5F0320551CEB29B" + 38 | "DB6907C57E38602927AD7240003FEB238AC5437FE4BAD11BB5038CA74D539523" + 39 | "A167B8EBB1210608EB7DA53B4155D05B87D21848E58905EFA550EA5A51E0A68D" + 40 | "5FF0F9E0CC0D5105DD98BE9E2C41362794A71A573CCA87B57147115B86FC8A6B" + 41 | "B1778CED1920787271C75D69C5D63CD798915BF8F9877808F841F9269B2EA809" + 42 | "0E11F6C89FDB537F341142CA29BAC761E1CF9D58FFB0C44A26E5EF7FA14142C8" + 43 | "A84BC9304A221D5F961DB41B5925B06823A12A6F8950E47325021A747A02A28F" + 44 | "DAE65997EBDF5D2BDBCA7C8D689AE186A9FE85A170B76EE92595C9E33639C993" + 45 | "07C377FA4DA975E191810E993CDC0A33EE494B0EE8A1B6A9408285012967C17A" + 46 | "8CB5EE8E7973CF9186A98000FE00F1CC76420089C6BDCE9E39D403C320DF1135" + 47 | "1597FF8B231689389CCE12844289FEFE468BFCAEE9A2CFB1A8DD066AEC974DA9" + 48 | "C8530C9A17593E25DC89934E056B178329C4BBF7113657677AB25EE66A1E1D92" + 49 | "F62154B2451B37727F05B3AC0F2501F7A95845C9BE210D411028C27A9AD4B0E8" + 50 | "31A6C46D26883A8AA2D1E2BD3E8E122A6FC21CECB7AE2B91C6FCFA793C5CAFF6" + 51 | "53C6670D914A29EAD81CD5C29FFB048C81CC80EDD693B4D8091B2D5DE88EA042" + 52 | "11AC551F406B713278BD14667E437C610953D6186C2986BA60361C2013395E8E" + 53 | "A9D14CD00EC5C61147BE03D8965B5376DF32E2C3740128398E0D47900C888FD0" + 54 | "D1F7D583808AFBC0712806E11462B37815C20692FB38E61CC0B1AAF66A854982" + 55 | "6A1F5FFFF2436B0B9F9EDFF4F5B59B362AA1D25A4E3C398EB18445483F8419BD" + 56 | "1511A5177E9C4B7034375A2D91B95153535E6CD5F023F4EED0E15B5415A3B7A7" + 57 | "7E390AA698DF00F4FD897B0454C00959AF0CB54B272DE63968815B971C44B273" + 58 | "6AC737FAE6A19F544907833F13C6F424D30E3B85054A4402EC94079C1473C20B" + 59 | "E4C1B33525486BB098EF960082DB4DF5FE9CAF71681B03CB2D4BE7382FF0C03F" + 60 | "18144DE554256591773DC3F381116955233FDA7223D71C402E558783F221E25A" + 61 | "94FECD350654A9CD8EE8C39E4B1CFBA0D5FD46891527F2D0FC9EA61584A76D59" + 62 | "99719811B2BAFC99769E6911733ED389A731C327CB5D7BB6D79CE030D3285586" + 63 | "C6681FC8C110EFE30CEE883FFEF5FB511B4421863E2A15F8CDCFA7B84B931121" + 64 | "5B23093DE3B5E7F4CFCCE60BE7857B7442B8FCC3E43C46C4BFA3E9ABD2F479F6" + 65 | "BD8D3F3D36C0FAC1F4D72FBE96C644AB56F73CAF956D5544B2EB9C589ED30FF3" + 66 | "0BB03D09DB455764EF4A33C24F93170A98A21455826390B13A8F338A820EC08D" + 67 | "6E9F562282C2F815BB57CE511AB6B0DE75EFA63F28C6D0B25298CDAAC76742D5" + 68 | "353B26B77C1533B4DFE2D95F3E89315C0D806A90FCDFDC31CE04A9E29937680D" + 69 | "32D8B503352388109C1F5F41E8496302E13A61917F70A9AA3C5ECDBD88163E3C" + 70 | "F0580C5EB1382BB66194AC0983BAA16B4D220756F4B7E3DDFFC5BF343FA7E31D" + 71 | "14FED4409AD0FE9BBE01AF79DA4852253CBF166FDCA90E894B5267A502F73347" + 72 | "06F8C767EC861324CC7734352D76DB007E25105E7994CF91D79532221316F4DE" + 73 | "56BAE4351D3E3C6549FBFEF13BBE2636071794AD9EC3787B4A71E5438B86C358" + 74 | "65ECF2EA5980318F82D8B113C0EC8FEE41C243E0A1A09F373A0CF546FA18E1EC" + 75 | "7DB4842A6B8B03D115654222B87DA6034EFDE2224DBD23AB104BF3723856C03D" + 76 | "B639BA073F2CC8E4AB05BAADDB5DEACC1874F4D6F86B95710019114DACBFE48F" + 77 | "EF2AE2DF27356B5C17948B26A41FD1A8F07E8068E176F995910C373886DB47D2" + 78 | "6C2FE5CD97AAF1829EBC1EEBA4D88343A322E810385138F51F0E5149183699C4" + 79 | "05E49ED13C2889A22742893A52567B0F7D4A3BC9F4DC6D29F713AA7FB4EF6B13" + 80 | "5F92F598404A80E7D6515CE234AFA68A4B562AF203162C60D578F0D00E302958" + 81 | "174E1A712FD449D257C6AA5F56E4DBD0363573931463BC910858AF1EC40C1F4A" + 82 | "7BE27DE8E170D4AACF6C34B0CDE15190FD81FA5676136A4D73E2AA4BBFBB8E7C" + 83 | "1178EF47362188D9288E822B10BBF2C8BE075A5BD1D3E1F08108BA8C4E6FB173" + 84 | "DCECB5771E9D8AE4CD776EA3409DF30FA2252D3C3769AF12177F4A1929DC8E74" + 85 | "D5AEAC94CF94EEBA0E9AC012C57B40A8BB57530C25846B841005767B9AABE436" + 86 | "D4590977FDDA519B9B284CF8B8922A0E8B659ECE3745A95800EE1B3DDD33E0FF" + 87 | "230C0528BC7A4CB80604411E59E08775A42C634E93BA9C77D015659AC912F436" + 88 | "94F774E94050E4B3BF84290368D5AFD7F043BDCA3BD0CC8C0E267069B6F1386A" + 89 | "E1D9C8B5512AAAA292FDA9CA07E27BAF983E1E25A11732797425F2BB396B302E" + 90 | "0782BA183D4BC1F682365774520EAC8A321C7A0BD08027021EA0063D471E0AD1" + 91 | "E1469AD803C311D3FBF50B5538265D4262B6716D90E89A8C906D08533D650000" + 92 | "6BF1B8ABAAFE1CA3AFDD1A19ACABE5B86A804D36AE27163CAF390FD266D5FFEF" + 93 | "FC7CE6FEF9458E4AF0C4108E32EFD11C19751B1D9883E803F7C2E1A5786F3385" + 94 | "1A7CA3772ECD7CB0E9782A7D30E0A9FD09EED361B774A277C618C995FD7F7634" + 95 | "E7DB3834690B58DDFF6B721157D0EC02") 96 | self.rsa_key_encryption_key = b64decode('v4uHomAR0tAXC3fA5Nfq7DjyJxuvYErMSCcZIWZKjpM=') 97 | 98 | self.chunks = parser.extract_chunks(self.blob) 99 | self.accounts = [parser.parse_ACCT(i, TEST_ENCRYPTION_KEY) for i in self.chunks if i.id == b'ACCT'] 100 | 101 | def test_extract_chunks_returns_chunks_as_a_list(self): 102 | self.assertIsInstance(self.chunks, list) 103 | 104 | def test_extract_chunks_all_values_are_instance_of_chunk(self): 105 | self.assertListEqual(list(set([type(v) for v in self.chunks])), [Chunk]) 106 | 107 | def test_parse_ACCT_parses_account(self): 108 | self.assertListEqual([a.id for a in self.accounts], [a.id for a in TEST_ACCOUNTS]) 109 | 110 | def test_parse_PRIK_parses_private_key(self): 111 | chunk = Chunk(b'PRIK', self.encoded_rsa_key) 112 | rsa_key = parser.parse_PRIK(chunk, self.rsa_key_encryption_key) 113 | 114 | from Crypto.PublicKey.RSA import RsaKey 115 | self.assertIsInstance(rsa_key, RsaKey) 116 | 117 | self.assertEqual(str(rsa_key.n), ("26119467519435514320618523953258926539081857789201" + 118 | "11592360794055150234493177840791445076164320959092" + 119 | "33977645519805962686071307052774013402170389235283" + 120 | "48398581900094955608774421569689169697285847986479" + 121 | "82303230642077254435741682688235176460351551099267" + 122 | "22581481667367599195203736002065084704013295528661" + 123 | "76687143747593851140122182044652173598693510643390" + 124 | "47711449981712845835960707676646864765530616733341" + 125 | "58401920829305659156984748726238485655720031774127" + 126 | "01900577710668575227691993026576480667273922300137" + 127 | "80405264300989392980537603337301835174777026188388" + 128 | "93147718435999645840214854231168704372464234421315" + 129 | "01138217872658041")) 130 | self.assertEqual(str(rsa_key.e), '65537') 131 | self.assertEqual(str(rsa_key.d), ("20217010678828834626882766446083366137418639853408" + 132 | "07494174069610076841252047428625473158347002598408" + 133 | "18346644251082549844764624454370315666751565294997" + 134 | "10533208173186395672159239558808345075823110774221" + 135 | "61501075434955107584446470508660844962452555542861" + 136 | "72030926355197158923586674949673551608716945271868" + 137 | "18816984671497443384191412119383687600754285611808" + 138 | "23265620694961977962255376280640334543711420731809" + 139 | "16169692928898605559361322123131373948352054888316" + 140 | "99068010065680008419210277574874665723796199239285" + 141 | "78432149273871356528827780412288057677598714485872" + 142 | "23380715275000339748138416696881866569449168516354" + 143 | "08203050733598637")) 144 | self.assertEqual(str(rsa_key.p), ("17745924258106322606344019888040076543466707208121" + 145 | "93651272762195900747632457567234817364256394944312" + 146 | "33791510564351470780224344194760390006214095043405" + 147 | "42496712265086317539172843039592265661675784866722" + 148 | "91261262550895476526939878375016658686669778355984" + 149 | "43725100552628219407700007375820870959681331890216" + 150 | "873285999")) 151 | self.assertEqual(str(rsa_key.q), ("14718572636476888213359534581670909910031809536407" + 152 | "40164297606657861988206326322941728093846078102409" + 153 | "77115817405984843964689092056948880068086594283588" + 154 | "67786990898525462713620707076259988063113810297786" + 155 | "62342502396556461808879680749106840152602791951788" + 156 | "07295572399572445909627940220804206538364578785262" + 157 | "498615959")) 158 | self.assertEqual(str(rsa_key.dmp1), ("11323089471614997519408698592522878386531994069" + 159 | "33541387540978328974191124807026398192741826901" + 160 | "86286081197790519393403018396347119829946883285" + 161 | "08800265628051101161010033119239372833462468119" + 162 | "90625594353955836736745514688525978377008530625" + 163 | "69694172942783772849726563761756732407513441791" + 164 | "680438851248236159711158591")) 165 | self.assertEqual(str(rsa_key.dmq1), ("12614892732210916138126631634839174964470249502" + 166 | "72370951196981338360130575847987543477227082933" + 167 | "41184913630399067613236576233063778305668453307" + 168 | "65828324726545238243590265660986543730618177968" + 169 | "24851190055502445616363498122584261892788460430" + 170 | "15963041982287770355559480659540210015737708509" + 171 | "273864533597668007301940253")) 172 | self.assertEqual(str(rsa_key.iqmp), ("12662716333617943892704787530332782239196594580" + 173 | "72960727418453194230165281227127897455330083723" + 174 | "88895713617946267318745745224382578970891647971" + 175 | "94015463887039228876036602797561671319853126600" + 176 | "52663805817336717151173320411542486382434841161" + 177 | "62999647203566877832873138065626190040996517274" + 178 | "418161068665712298519808863")) 179 | 180 | def test_parse_secure_note_server_returns_parsed_values(self): 181 | type = b'type' 182 | url = b'url' 183 | username = b'username' 184 | password = b'password' 185 | notes = 'NoteType:{}\nHostname:{}\nUsername:{}\nPassword:{}'.format(type.decode(), url.decode(), username.decode(), password.decode()).encode() 186 | 187 | result = parser.parse_secure_note_server(notes) 188 | self.assertTrue(isinstance(result, dict)) 189 | self.assertDictEqual(result, { 190 | 'type': type, 191 | 'url': url, 192 | 'username': username, 193 | 'password': password, 194 | }) 195 | 196 | def test_parse_secure_note_server_returns_empty_dict_if_empty_str(self): 197 | notes = b'' 198 | result = parser.parse_secure_note_server(notes) 199 | 200 | self.assertTrue(isinstance(result, dict)) 201 | self.assertDictEqual(result, {}) 202 | 203 | def test_read_chunk_returns_a_chunk(self): 204 | io = BytesIO(codecs.decode('4142434400000004DEADBEEF' + self.padding, 'hex_codec')) 205 | self.assertEqual(parser.read_chunk(io), Chunk(b'ABCD', codecs.decode('DEADBEEF', 'hex_codec'))) 206 | self.assertEqual(io.tell(), 12) 207 | 208 | def test_read_item_returns_an_item(self): 209 | io = BytesIO(codecs.decode('00000004DEADBEEF' + self.padding, 'hex_codec')) 210 | self.assertEqual(parser.read_item(io), codecs.decode('DEADBEEF', 'hex_codec')) 211 | self.assertEqual(io.tell(), 8) 212 | 213 | def test_skip_item_skips_an_empty_item(self): 214 | io = BytesIO(codecs.decode('00000000' + self.padding, 'hex_codec')) 215 | parser.skip_item(io) 216 | self.assertEqual(io.tell(), 4) 217 | 218 | def test_skip_item_skips_a_non_empty_item(self): 219 | io = BytesIO(codecs.decode('00000004DEADBEEF' + self.padding, 'hex_codec')) 220 | parser.skip_item(io) 221 | self.assertEqual(io.tell(), 8) 222 | 223 | def test_read_id_returns_an_id(self): 224 | io = BytesIO(('ABCD' + self.padding).encode()) 225 | self.assertEqual(parser.read_id(io), b'ABCD') 226 | self.assertEqual(io.tell(), 4) 227 | 228 | def test_read_size_returns_a_size(self): 229 | io = BytesIO(codecs.decode('DEADBEEF' + self.padding, 'hex_codec')) 230 | self.assertEqual(parser.read_size(io), 0xDEADBEEF) 231 | self.assertEqual(io.tell(), 4) 232 | 233 | def test_read_payload_returns_a_payload(self): 234 | io = BytesIO(codecs.decode('FEEDDEADBEEF' + self.padding, 'hex_codec')) 235 | self.assertEqual(parser.read_payload(io, 6), codecs.decode('FEEDDEADBEEF', 'hex_codec')) 236 | self.assertEqual(io.tell(), 6) 237 | 238 | def test_read_uint32_returns_a_number(self): 239 | io = BytesIO(codecs.decode('DEADBEEF' + self.padding, 'hex_codec')) 240 | self.assertEqual(parser.read_size(io), 0xDEADBEEF) 241 | self.assertEqual(io.tell(), 4) 242 | 243 | def test_decode_hex_decodes_hex(self): 244 | self.assertEqual(parser.decode_hex(''), b'') 245 | self.assertEqual(parser.decode_hex('00ff'), b'\x00\xFF') 246 | self.assertEqual(parser.decode_hex('00010203040506070809'), b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09') 247 | self.assertEqual(parser.decode_hex('000102030405060708090a0b0c0d0e0f'), b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F') 248 | self.assertEqual(parser.decode_hex('8af633933e96a3c3550c2734bd814195'), b'\x8A\xF6\x33\x93\x3E\x96\xA3\xC3\x55\x0C\x27\x34\xBD\x81\x41\x95') 249 | 250 | def test_decode_hex_raises_exception_on_odd_length(self): 251 | self.assertRaises(TypeError, parser.decode_hex, '0') 252 | 253 | def test_decode_hex_raises_exception_on_invalid_characters(self): 254 | self.assertRaises(TypeError, parser.decode_hex, 'xz') 255 | 256 | def test_decode_base64_decodes_base64(self): 257 | self.assertEqual(parser.decode_base64(''), b'') 258 | self.assertEqual(parser.decode_base64('YQ=='), b'a') 259 | self.assertEqual(parser.decode_base64('YWI='), b'ab') 260 | self.assertEqual(parser.decode_base64('YWJj'), b'abc') 261 | self.assertEqual(parser.decode_base64('YWJjZA=='), b'abcd') 262 | 263 | def test_decode_aes256_plain_auto_decodes_a_blank_string(self): 264 | self.assertEqual(parser.decode_aes256_plain_auto(b'', self.encryption_key), b'') 265 | 266 | def test_decode_aes256_plain_auto_decodes_ecb_plain_string(self): 267 | self.assertEqual(parser.decode_aes256_plain_auto( 268 | b64decode('BNhd3Q3ZVODxk9c0C788NUPTIfYnZuxXfkghtMJ8jVM='), self.encryption_key), 269 | b'All your base are belong to us') 270 | 271 | def test_decode_aes256_plain_auto_decodes_cbc_plain_string(self): 272 | self.assertEqual(parser.decode_aes256_plain_auto( 273 | b64decode('IcokDWmjOkKtLpZehWKL6666Uj6fNXPpX6lLWlou+1Lrwb+D3ymP6BAwd6C0TB3hSA=='), self.encryption_key), 274 | b'All your base are belong to us') 275 | 276 | def test_decode_aes256_base64_auto_decodes_a_blank_string(self): 277 | self.assertEqual(parser.decode_aes256_base64_auto(b'', self.encryption_key), b'') 278 | 279 | def test_decode_aes256_base64_auto_decodes_ecb_base64_string(self): 280 | self.assertEqual(parser.decode_aes256_base64_auto( 281 | b'BNhd3Q3ZVODxk9c0C788NUPTIfYnZuxXfkghtMJ8jVM=', self.encryption_key), 282 | b'All your base are belong to us') 283 | 284 | def test_decode_aes256_base64_auto_decodes_cbc_base64_string(self): 285 | self.assertEqual(parser.decode_aes256_base64_auto( 286 | b'!YFuiAVZgOD2K+s6y8yaMOw==|TZ1+if9ofqRKTatyUaOnfudletslMJ/RZyUwJuR/+aI=', self.encryption_key), 287 | b'All your base are belong to us') 288 | 289 | def test_decode_aes256_ecb_plain_decodes_a_blank_string(self): 290 | self.assertEqual(parser.decode_aes256_ecb_plain( 291 | b64decode(''), self.encryption_key), 292 | b'') 293 | 294 | def test_decode_aes256_ecb_plain_decodes_a_short_string(self): 295 | self.assertEqual(parser.decode_aes256_ecb_plain( 296 | b64decode('8mHxIA8rul6eq72a/Gq2iw=='), self.encryption_key), 297 | b'0123456789') 298 | 299 | def test_decode_aes256_ecb_plain_decodes_a_long_string(self): 300 | self.assertEqual(parser.decode_aes256_ecb_plain( 301 | b64decode('BNhd3Q3ZVODxk9c0C788NUPTIfYnZuxXfkghtMJ8jVM='), self.encryption_key), 302 | b'All your base are belong to us') 303 | 304 | def test_decode_aes256_ecb_base64_decodes_a_blank_string(self): 305 | self.assertEqual(parser.decode_aes256_ecb_base64( 306 | '', self.encryption_key), 307 | b'') 308 | 309 | def test_decode_aes256_ecb_base64_decodes_a_short_string(self): 310 | self.assertEqual(parser.decode_aes256_ecb_base64( 311 | '8mHxIA8rul6eq72a/Gq2iw==', self.encryption_key), 312 | b'0123456789') 313 | 314 | def test_decode_aes256_ecb_base64_decodes_a_long_string(self): 315 | self.assertEqual(parser.decode_aes256_ecb_base64( 316 | 'BNhd3Q3ZVODxk9c0C788NUPTIfYnZuxXfkghtMJ8jVM=', self.encryption_key), 317 | b'All your base are belong to us') 318 | 319 | def test_decode_aes256_cbc_plain_decodes_a_blank_string(self): 320 | self.assertEqual(parser.decode_aes256_cbc_plain( 321 | b64decode(''), self.encryption_key), 322 | b'') 323 | 324 | def test_decode_aes256_cbc_plain_decodes_a_short_string(self): 325 | self.assertEqual(parser.decode_aes256_cbc_plain( 326 | b64decode('IQ+hiIy0vGG4srsHmXChe3ehWc/rYPnfiyqOG8h78DdX'), self.encryption_key), 327 | b'0123456789') 328 | 329 | def test_decode_aes256_cbc_plain_decodes_a_long_string(self): 330 | self.assertEqual(parser.decode_aes256_cbc_plain( 331 | b64decode('IcokDWmjOkKtLpZehWKL6666Uj6fNXPpX6lLWlou+1Lrwb+D3ymP6BAwd6C0TB3hSA=='), self.encryption_key), 332 | b'All your base are belong to us') 333 | 334 | def test_decode_aes256_cbc_base64_decodes_a_blank_string(self): 335 | self.assertEqual(parser.decode_aes256_cbc_base64( 336 | '', self.encryption_key), 337 | b'') 338 | 339 | def test_decode_aes256_cbc_base64_decodes_a_short_string(self): 340 | self.assertEqual(parser.decode_aes256_cbc_base64( 341 | '!6TZb9bbrqpocMaNgFjrhjw==|f7RcJ7UowesqGk+um+P5ug==', self.encryption_key), 342 | b'0123456789') 343 | 344 | def test_decode_aes256_cbc_base64_decodes_a_long_string(self): 345 | self.assertEqual(parser.decode_aes256_cbc_base64( 346 | '!YFuiAVZgOD2K+s6y8yaMOw==|TZ1+if9ofqRKTatyUaOnfudletslMJ/RZyUwJuR/+aI=', self.encryption_key), 347 | b'All your base are belong to us') 348 | -------------------------------------------------------------------------------- /tests/test_session.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | from lastpass.session import Session 4 | 5 | 6 | class SessionTestCase(unittest.TestCase): 7 | def setUp(self): 8 | self.id = '53ru,Hb713QnEVM5zWZ16jMvxS0' 9 | self.key_iteration_count = 5000 10 | 11 | self.session = Session(self.id, self.key_iteration_count) 12 | 13 | def test_id_returns_the_correct_value(self): 14 | self.assertEqual(self.session.id, self.id) 15 | 16 | def test_key_iteration_count_returns_the_correct_value(self): 17 | self.assertEqual(self.session.key_iteration_count, self.key_iteration_count) 18 | -------------------------------------------------------------------------------- /tests/test_vault.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | import struct 5 | 6 | from lastpass import InvalidResponseError 7 | from lastpass.blob import Blob 8 | from lastpass.vault import Vault 9 | from tests.test_data import TEST_BLOB, TEST_KEY_ITERATION_COUNT, TEST_ENCRYPTION_KEY, TEST_ACCOUNTS 10 | 11 | 12 | class VaultTestCase(unittest.TestCase): 13 | def setUp(self): 14 | self.vault = Vault(Blob(TEST_BLOB, TEST_KEY_ITERATION_COUNT), TEST_ENCRYPTION_KEY) 15 | 16 | def test_init_raises_an_exception_on_truncated_blob(self): 17 | for i in [1, 2, 3, 4, 5, 10, 100, 1000]: 18 | blob = Blob(TEST_BLOB[:-i], TEST_KEY_ITERATION_COUNT) 19 | with self.assertRaises(Exception) as context: 20 | Vault(blob, TEST_ENCRYPTION_KEY) 21 | 22 | self.assertIn(type(context.exception), [InvalidResponseError, struct.error]) 23 | # self.assertEqual(context.exception.message, 'Blob is truncated') 24 | 25 | def test_accounts_type_is_collect(self): 26 | self.assertIsInstance(self.vault.accounts, list) 27 | 28 | def test_accounts_have_correct_ids(self): 29 | self.assertListEqual([a.id for a in self.vault.accounts], [a.id for a in TEST_ACCOUNTS]) 30 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | # Tox (http://tox.testrun.org/) is a tool for running tests in 2 | # multiple virtualenvs. This configuration file will run the 3 | # test suite on all supported python versions. To use it, "pip 4 | # install tox" and then run "tox" from this directory. 5 | 6 | [tox] 7 | envlist = py27, py38, pep8 8 | 9 | [testenv] 10 | commands = pip install -r requirements.txt 11 | nosetests --with-coverage --cover-package=lastpass 12 | 13 | [testenv:pep8] 14 | deps = pep8 15 | commands = pep8 --repeat --show-source --exclude=.venv,.tox,dist,docs,build,*.egg,.git --ignore=E501,E731 . 16 | --------------------------------------------------------------------------------