diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..a9c95e50b --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +src/pyqt5_tools/_version.py export-subst diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1a930f4f0..36da1b0b0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,8 +12,8 @@ env: PIP_NO_PYTHON_VERSION_WARNING: 1 jobs: - ci: - name: ${{ matrix.os.name }} ${{ matrix.python.name }}-${{ matrix.bitness.name }} ${{ matrix.qt.pyqt_version }} + build: + name: Build ${{ matrix.os.name }} ${{ matrix.python.name }}-${{ matrix.bitness.name }} ${{ matrix.qt.pyqt_version }} runs-on: ${{ matrix.os.runs-on }} container: ${{ format(matrix.os.container, matrix.python.docker) }} strategy: @@ -24,59 +24,51 @@ jobs: runs-on: ubuntu-latest python_platform: linux container: docker://python:{0}-buster - cibuildwheel_before: yum install mesa-libGL-devel - - name: Windows - runs-on: windows-latest - python_platform: win32 - vs_path: C:/Program Files (x86)/Microsoft Visual Studio/2019/Enterprise/VC/Auxiliary/Build/vcvars64.bat +# - name: Windows +# runs-on: windows-latest +# python_platform: win32 +# vs_path: C:/Program Files (x86)/Microsoft Visual Studio/2019/Enterprise/VC/Auxiliary/Build/vcvars64.bat # - name: macOS # runs-on: macos-latest # python_platform: darwin python: - - name: 3.5 - tox: py35 - action: 3.5 - docker: 3.5 - cibuildwheel: cp38 - - name: 3.6 - tox: py36 - action: 3.6 - docker: 3.6 - cibuildwheel: cp36 - - name: 3.7 - tox: py37 - action: 3.7 - docker: 3.7 - cibuildwheel: cp37 +# - name: 3.5 +# tox: py35 +# action: 3.5 +# docker: 3.5 +# - name: 3.6 +# tox: py36 +# action: 3.6 +# docker: 3.6 +# - name: 3.7 +# tox: py37 +# action: 3.7 +# docker: 3.7 - name: 3.8 tox: py38 action: 3.8 docker: 3.8 - cibuildwheel: cp38 - - name: 3.9 - tox: py39 - action: 3.9 - docker: 3.9 - cibuildwheel: cp39 +# - name: 3.9 +# tox: py39 +# action: 3.9 +# docker: 3.9 qt: - - pyqt_version: 5.14.0 - qt_version: 5.14.0 - - pyqt_version: 5.14.1 - qt_version: 5.14.1 +# - pyqt_version: 5.14.0 +# qt_version: 5.14.0 +# - pyqt_version: 5.14.1 +# qt_version: 5.14.1 - pyqt_version: 5.14.2 qt_version: 5.14.2 - - pyqt_version: 5.15.0 - qt_version: 5.15.0 +# - pyqt_version: 5.15.0 +# qt_version: 5.15.0 - pyqt_version: 5.15.1 qt_version: 5.15.1 bitness: - - name: x32 - action: x86 - cibuildwheel: '*32*' - ilammy: x86 +# - name: x32 +# action: x86 +# ilammy: x86 - name: x64 action: x64 - cibuildwheel: '*64*' ilammy: x64 exclude: - bitness: @@ -116,10 +108,10 @@ jobs: with: python-version: ${{ matrix.python.action }} architecture: ${{ matrix.bitness.action }} - - name: pip/setuptools/tox/cibuildwheel + - name: pip/setuptools/tox run: | - python -m pip install --upgrade pip setuptools - pip install tox cibuildwheel + python -m pip install --upgrade pip setuptools wheel + pip install tox pep517 - name: Report info shell: bash run: | @@ -129,48 +121,141 @@ jobs: pip list pip freeze --all python -c "import sysconfig; print('Py_ENABLE_SHARED -> {}'.format(sysconfig.get_config_var('Py_ENABLE_SHARED')))" -# - name: Install Linux Docker dependencies -# if: matrix.os.python_platform == 'linux' -# run: | -# apt-get update --yes -# apt-get install --yes docker.io -# - name: Build wheel -# run: | -# cibuildwheel --output-dir dist/ -# env: -# CIBW_BUILD: ${{ matrix.python.cibuildwheel }}-${{ matrix.bitness.cibuildwheel }} -# CIBW_MANYLINUX_X86_64_IMAGE: manylinux2014 -# CIBW_MANYLINUX_I686_IMAGE: manylinux2014 -# CIBW_BEFORE_BUILD: ${{ matrix.os.cibuildwheel_before }} -# CIBW_ENVIRONMENT: QT_VERSION=${{ matrix.qt.qt_version }} QT_COMPILER=${{ matrix.os.qt_compiler }} QT_ARCHITECTURE=${{ matrix.os.aqt_architecture }} PYQT_VERSION=${{ matrix.qt.pyqt_version }} - name: Install Linux build dependencies if: matrix.os.python_platform == 'linux' run: | apt-get update --yes - apt-get install --yes libgl1-mesa-dev - apt-get install --yes libdbus-1-3 libxkbcommon-x11-0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxcb-xinerama0 libxcb-xfixes0 - - name: Set up MSVC - uses: ilammy/msvc-dev-cmd@v1 - if: matrix.os.python_platform == 'win32' - with: - arch: ${{ matrix.bitness.ilammy }} + apt-get install --yes libgl1-mesa-dev libdbus-1-3 libxkbcommon-x11-0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxcb-xinerama0 libxcb-xfixes0 - name: Build wheel - # native shell for nmake... keep commands here simple i guess - run: | - mkdir -p dist/ - pip wheel -vvv --no-deps --wheel-dir dist/ --no-clean . - - name: Rename to manylinux2014 tag - if: matrix.os.python_platform == 'linux' - shell: python + shell: bash run: | - import pathlib - - dist = pathlib.Path.cwd() / 'dist' - [wheel] = dist.glob('*.whl') + python -m pep517.build --binary --out-dir dist/ . + - name: Archive individual wheel + uses: actions/upload-artifact@v1 + with: + name: ${{ matrix.qt.pyqt_version }} + path: dist/ + - name: Archive all wheels + uses: actions/upload-artifact@v1 + with: + name: all_wheels + path: dist/ + test: + name: Test ${{ matrix.os.name }} ${{ matrix.python.name }}-${{ matrix.bitness.name }} ${{ matrix.qt.pyqt_version }} + runs-on: ${{ matrix.os.runs-on }} + container: ${{ format(matrix.os.container, matrix.python.docker) }} + needs: + - build + strategy: + fail-fast: false + matrix: + os: + - name: Linux + runs-on: ubuntu-latest + python_platform: linux + container: docker://python:{0}-buster + - name: Windows + runs-on: windows-latest + python_platform: win32 + vs_path: C:/Program Files (x86)/Microsoft Visual Studio/2019/Enterprise/VC/Auxiliary/Build/vcvars64.bat +# - name: macOS +# runs-on: macos-latest +# python_platform: darwin + python: +# - name: 3.5 +# tox: py35 +# action: 3.5 +# docker: 3.5 +# - name: 3.6 +# tox: py36 +# action: 3.6 +# docker: 3.6 +# - name: 3.7 +# tox: py37 +# action: 3.7 +# docker: 3.7 + - name: 3.8 + tox: py38 + action: 3.8 + docker: 3.8 +# - name: 3.9 +# tox: py39 +# action: 3.9 +# docker: 3.9 + qt: +# - pyqt_version: 5.14.0 +# qt_version: 5.14.0 +# - pyqt_version: 5.14.1 +# qt_version: 5.14.1 + - pyqt_version: 5.14.2 + qt_version: 5.14.2 +# - pyqt_version: 5.15.0 +# qt_version: 5.15.0 + - pyqt_version: 5.15.1 + qt_version: 5.15.1 + bitness: +# - name: x32 +# action: x86 +# ilammy: x86 + - name: x64 + action: x64 + ilammy: x64 + exclude: + - bitness: + name: x32 + os: + name: Linux +# - bitness: +# name: x32 +# os: +# name: macOS + - python: + name: 3.9 + qt: + pyqt_version: 5.14.0 + - python: + name: 3.9 + qt: + pyqt_version: 5.14.1 + - python: + name: 3.9 + qt: + pyqt_version: 5.14.2 + - python: + name: 3.9 + qt: + pyqt_version: 5.15.0 + env: + QT_VERSION: ${{ matrix.qt.qt_version }} + PYQT_VERSION: ${{ matrix.qt.pyqt_version }} - # this is cheap... - retagged = wheel.parent / wheel.name.replace('linux', 'manylinux2014') - wheel.rename(retagged) + steps: + - name: Checkout + uses: actions/checkout@v1 + - name: Download + uses: actions/download-artifact@v1 + with: + name: ${{ matrix.qt.pyqt_version }} + path: dist/ + - name: Set up Python ${{ matrix.python.name }}-${{ matrix.bitness.name }} + if: matrix.os.python_platform != 'linux' + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python.action }} + architecture: ${{ matrix.bitness.action }} + - name: pip/setuptools/tox + run: | + python -m pip install --upgrade pip setuptools + pip install tox + - name: Report info + shell: bash + run: | + git show --quiet HEAD + python --version --version + pip --version + pip list + pip freeze --all + python -c "import sysconfig; print('Py_ENABLE_SHARED -> {}'.format(sysconfig.get_config_var('Py_ENABLE_SHARED')))" - name: Set WHEEL_PATH shell: python run: | @@ -182,51 +267,36 @@ jobs: dist = pathlib.Path.cwd() / 'dist' [wheel] = dist.glob('*.whl') - print('::set-env name=WHEEL_PATH::{}'.format(fspath(wheel))) - print('::set-env name=WHEEL_STEM::{}'.format(wheel.stem)) - - name: Archive individual wheel - uses: actions/upload-artifact@v1 - with: - name: ${{ env['WHEEL_STEM'] }} - path: dist - - name: Archive all wheels - uses: actions/upload-artifact@v1 - with: - name: pyqt5_tools-all_wheels - path: dist + with open(os.environ['GITHUB_ENV'], 'a') as github_env: + github_env.write('WHEEL_PATH={}\n'.format(fspath(wheel))) + github_env.write('WHEEL_STEM={}\n'.format(wheel.stem)) - name: Install Linux test dependencies if: matrix.os.python_platform == 'linux' run: | apt-get update --yes - apt-get install --yes libgl1-mesa-dev libxkbcommon-x11-0 xvfb - apt-get install --yes x11-utils libdbus-1-3 - # let's guess here... - # apt-get install --yes mesa-utils linux-generic xserver-xorg-core xserver-xorg xserver-xorg-video-all xserver-xorg-input-all libwayland-egl1-mesa + apt-get install --yes libgl1-mesa-dev libdbus-1-3 libxkbcommon-x11-0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxcb-xinerama0 libxcb-xfixes0 xvfb x11-utils + - name: Set up MSVC + uses: ilammy/msvc-dev-cmd@v1 + if: matrix.os.python_platform == 'win32' + with: + arch: ${{ matrix.bitness.ilammy }} - name: Test run: | tox -e ${{ matrix.python.tox }} --installpkg ${{ env['WHEEL_PATH'] }} -# - name: prep -# if: always() -# run: | -# apt install --yes xvfb -# Xvfb :1 -screen 0 1600x1200x24& -# - name: Setup tmate session -# if: always() -# uses: mxschmitt/action-tmate@v2 maybe_publish: name: Maybe Publish runs-on: ubuntu-latest container: docker://python:3.8-buster needs: - - ci + - test steps: - name: Checkout uses: actions/checkout@v1 - name: Download all wheels uses: actions/download-artifact@v1 with: - name: pyqt5_tools-all_wheels - path: dist + name: all_wheels + path: dist/ - name: Install Python packages run: | pip install --upgrade twine @@ -240,7 +310,8 @@ jobs: name: All runs-on: ubuntu-latest needs: - - ci + - build + - test - maybe_publish steps: - name: This diff --git a/README.rst b/README.rst index 7d4dd9cbd..03ccf8680 100644 --- a/README.rst +++ b/README.rst @@ -3,13 +3,16 @@ pyqt5-tools =========== -|PyPI| |Pythons| |AppVeyor| |GitHub| +|PyPI| |Pythons| |GitHub| The PyQt5 wheels do not provide tools such as Qt Designer that were included in the old binary installers. This package aims to provide those in a separate package which is useful for developers while the official PyQt5 wheels stay focused on fulfilling the dependencies of PyQt5 applications. +Both Windows and Linux are supported. Adjust paths etc accordingly if applying +the explanations below in Linux rather than Windows. macOS support is +incomplete but see `issue #12`_ if you want to discuss it. .. |PyPI| image:: https://img.shields.io/pypi/v/pyqt5-tools.svg :alt: PyPI version @@ -19,32 +22,27 @@ focused on fulfilling the dependencies of PyQt5 applications. :alt: supported Python versions :target: https://pypi.org/project/pyqt5-tools/ -.. |AppVeyor| image:: https://ci.appveyor.com/api/projects/status/g95n2ri0e479uvoe?svg=true - :alt: AppVeyor build status -.. _AppVeyor: https://ci.appveyor.com/project/KyleAltendorf/pyqt5-tools - .. |GitHub| image:: https://img.shields.io/github/last-commit/altendky/pyqt5-tools/master.svg :alt: source on GitHub :target: https://github.com/altendky/pyqt5-tools +.. _`issue #12`: https://github.com/altendky/pyqt5-tools/issues/12 + ------------ Installation ------------ .. code-block:: powershell - yourenv\Scripts\pip.exe install --pre pyqt5-tools~=5.11 + yourenv/Scripts/pip.exe install pyqt5-tools~=5.15 You will generally install pyqt5-tools using ``pip install``. In most cases you should be using virtualenv_ or venv_ to create isolated environments to install your dependencies in. The above command assumes an env in the -directory ``yourenv``. The ``--pre`` allows for the latest version to be -installed despite not being a full release version. You will have to -decide if this is a good option for you at any given point in time. The -``~=5.11`` specifies a `release compatible with`_ 5.11 which will be the -latest version of pyqt5-tools built for PyQt5_ 5.11. If you are using a -different PyQt5 version, specify it instead of 5.11. PyPI keeps a list of -`all available versions`_. +directory ``yourenv``. The ``~=5.15`` specifies a `release compatible with`_ +5.11 which will be the latest version of pyqt5-tools built for PyQt5_ 5.11. If +you are using a different PyQt5 version, specify it instead of 5.11. PyPI +keeps a list of `all available versions`_. .. _virtualenv: https://virtualenv.pypa.io/en/stable/ .. _venv: https://docs.python.org/3/library/venv.html @@ -52,12 +50,20 @@ different PyQt5 version, specify it instead of 5.11. PyPI keeps a list of .. _`release compatible with`: https://www.python.org/dev/peps/pep-0440/#compatible-release .. _`all available versions`: https://pypi.org/project/pyqt5-tools/#history +Note: + As of pyqt5-tools v2 the package has been broken down into three pieces. + The wrappers remain here but the plugins are located in pyqt5-plugins_ and + the applications are in qt5-applications_. + +.. _pyqt5-plugins: https://github.com/altendky/pyqt-plugins +.. _qt5-applications: https://github.com/altendky/qt-applications + ----- Usage ----- For each tool a script is created such that you get files like -``Scripts\designer.exe`` to launch the programs. Each one searches up the +``Scripts/designer.exe`` to launch the programs. Each one searches up the filesystem tree from your current working directory to find a ``.env`` file and loads it if found. If found the environment variable ``DOT_ENV_DIRECTORY`` will be set to the directory containing the ``.env`` @@ -75,7 +81,7 @@ These examples are `not` intended to be used as examples of good code. Designer ======== -There is a ``Scripts\pyqt5designer.exe`` entry point that will help fill out +There is a ``Scripts/pyqt5designer.exe`` entry point that will help fill out ``PYQTDESIGNERPATH`` from either command line arguments or a ``.env`` file. Unknown arguments are passed through to the original Qt Designer program. @@ -86,8 +92,8 @@ Unknown arguments are passed through to the original Qt Designer program. Options: -p, --widget-path DIRECTORY Paths to be combined with PYQTDESIGNERPATH --example-widget-path Include the path for the pyqt5-tools example - button (c:\users\sda\testenv\lib\site- - packages\pyqt5_tools) + button (c:/users/sda/testenv/lib/site- + packages/pyqt5_tools) --designer-help Pass through to get Designer's --help --test-exception-dialog Raise an exception to check the exception dialog functionality. @@ -96,7 +102,7 @@ Unknown arguments are passed through to the original Qt Designer program. --help Show this message and exit. If you want to use ``Form`` > ``View Code...`` from within Designer you can -run ``Scripts\pyqt5toolsinstalluic.exe`` and it will copy ``pyuic5.exe`` +run ``Scripts/pyqt5toolsinstalluic.exe`` and it will copy ``pyuic5.exe`` such that Designer will use it and show you generated Python code. ``pyqt5`` must already be installed or this script will be unable to find the original ``pyuic5.exe`` to copy. @@ -112,7 +118,7 @@ The QML plugin is also included. In the future a tool may be provided to handle copying of the plugin to each directory where it is needed. For now this must be done manually. -``site-packages\pyqt5_tools\Qt\bin\plugins\pyqt5qmlplugin.dll`` +``site-packages/pyqt5_tools/Qt/bin/plugins/pyqt5qmlplugin.dll`` QML Scene ========= diff --git a/build.py b/build.py deleted file mode 100755 index 0bb21ca43..000000000 --- a/build.py +++ /dev/null @@ -1,636 +0,0 @@ -#!/usr/bin/env python3 - -import decimal -import glob -import inspect -import io -import itertools -import os -import pathlib -import pip -import platform -import shlex -import shutil -import stat -import subprocess -import sys -import textwrap -import time -import zipfile - -import requests - - -class Results: - def __init__(self, console_scripts): - self.console_scripts = console_scripts - - -# http://stackoverflow.com/a/9728478/228539 -def list_files(startpath): - for root, dirs, files in os.walk(startpath): - level = root.replace(startpath, '').count(os.sep) - indent = ' ' * 4 * (level) - print('{}{}/'.format(indent, os.path.basename(root))) - subindent = ' ' * 4 * (level + 1) - for f in files: - print('{}{}'.format(subindent, f)) - - -def validate_pair(ob): - try: - if not (len(ob) == 2): - print("Unexpected result:", ob, file=sys.stderr) - raise ValueError - except: - return False - return True - - -def consume(iter): - try: - while True: next(iter) - except StopIteration: - pass - - -fspath = getattr(os, 'fspath', str) - - -def download(*args, **kwargs): - print('Downloading: {} {}'.format(args, kwargs)) - - hold_off = 30 - - for remaining_tries in reversed(range(5)): - result = requests.get(*args, **kwargs) - try: - result.raise_for_status() - except requests.HTTPError: - if remaining_tries > 0: - print('waiting {} seconds'.format(hold_off)) - time.sleep(hold_off) - hold_off *= 2 - print('Retrying: {} {}'.format(args, kwargs)) - - continue - - raise - - return result - - -def get_environment_from_batch_command(env_cmd, initial=None): - """ - Take a command (either a single command or list of arguments) - and return the environment created after running that command. - Note that if the command must be a batch file or .cmd file, or the - changes to the environment will not be captured. - - If initial is supplied, it is used as the initial environment passed - to the child process. - """ - if not isinstance(env_cmd, (list, tuple)): - env_cmd = [env_cmd] - # construct the command that will alter the environment - env_cmd = subprocess.list2cmdline(env_cmd) - # create a tag so we can tell in the output when the proc is done - tag = 'Done running command' - # construct a cmd.exe command to do accomplish this - cmd = 'cmd.exe /s /c "{env_cmd} && echo "{tag}" && set"'.format(**vars()) - # launch the process - proc = subprocess.run(cmd, stdout=subprocess.PIPE, env=initial, check=True) - # parse the output sent to stdout - lines = proc.stdout.decode().splitlines() - # consume whatever output occurs until the tag is reached - consume(itertools.takewhile(lambda l: tag not in l, lines)) - # define a way to handle each KEY=VALUE line - handle_line = lambda l: l.rstrip().split('=',1) - # parse key/values into pairs - pairs = map(handle_line, lines) - # make sure the pairs are valid - valid_pairs = filter(validate_pair, pairs) - # construct a dictionary of the pairs - result = dict(valid_pairs) - return result - - -# TODO: CAMPid 079079043724533410718467080456813604134316946765431341384014 -def report_and_check_call(command, *args, cwd=None, shell=False, **kwargs): - print('\nCalling:') - print(' Caller: {}'.format(callers_line_info())) - print(' CWD: {}'.format(repr(cwd))) - print(' As passed: {}'.format(repr(command))) - print(' Full: {}'.format( - ' '.join(shlex.quote(fspath(x)) for x in command), - )) - - if shell: - print(' {}'.format(repr(command))) - else: - for arg in command: - print(' {}'.format(repr(arg))) - - sys.stdout.flush() - return subprocess.run(command, *args, cwd=cwd, check=True, **kwargs) - - -# TODO: CAMPid 974597249731467124675t40136706803641679349342342 -# https://github.com/altendky/altendpy/issues/8 -def callers_line_info(): - here = inspect.currentframe() - caller = here.f_back - - if caller is None: - return None - - there = caller.f_back - info = inspect.getframeinfo(there) - - return 'File "{}", line {}, in {}'.format( - info.filename, - info.lineno, - info.function, - ) - - -def preferred_newlines(f): - if isinstance(f.newlines, str): - return f.newlines - return '\n' - - -def main(): - bits = int(platform.architecture()[0][0:2]) - python_major_minor = '{}{}'.format( - sys.version_info.major, - sys.version_info.minor - ) - # WARNING: The compiler for Python 3.4 is actually 10 but let's try 12 - # because that's what Qt offers - msvc_versions = { - '34': '12.0', - '35': '14.0', - '36': '14.0', - '37': '14.14', - '38': '14.14', - } - if bits == 32 and python_major_minor in ('35', '36'): - msvc_version = '14.14' - else: - msvc_version = msvc_versions[python_major_minor] - compiler_year = { - '10.0': '2010', - '11.0': '2012', - '12.0': '2013', - '14.0': '2015', - '14.1': '2017', - '14.14': '2017', - }[msvc_version] - if decimal.Decimal(msvc_version) >= 14.1: - vs_path = os.path.join( - 'C:/', - 'Program Files (x86)', - 'Microsoft Visual Studio', - compiler_year, - 'Community', - ) - else: - vs_path = os.path.join( - 'C:/', 'Program Files (x86)', 'Microsoft Visual Studio {}'.format( - msvc_version - ) - ) - - vcvarsall = os.path.join(vs_path, 'VC') - if decimal.Decimal(msvc_version) >= 14.1: - vcvarsall = os.path.join(vcvarsall, 'Auxiliary', 'Build') - vcvarsall = os.path.join(vcvarsall, 'vcvarsall.bat') - - os.environ = get_environment_from_batch_command( - [ - vcvarsall, - {32: 'x86', 64: 'x64'}[bits] - ], - initial=os.environ - ) - os.environ['VCINSTALLDIR'] = vs_path - print(' ---- os.environ:') - for k, v in os.environ.items(): - print(' {}: {}'.format(k, v)) - - compiler_name = 'msvc' - compiler_bits_string = {32: '', 64: '_64'}[bits] - - compiler_dir = ''.join((compiler_name, compiler_year, compiler_bits_string)) - - qt_path = os.environ['QT_BASE_PATH'] - qt_compiler_path = os.path.join(qt_path, compiler_dir) - qt_bin_path = os.path.join(qt_compiler_path, 'bin') - os.environ['PATH'] = os.pathsep.join((os.environ['PATH'], qt_bin_path)) - - with open('setup.cfg', 'w') as cfg: - plat_names = { - 32: 'win32', - 64: 'win_amd64' - } - try: - plat_name = plat_names[bits] - except KeyError: - raise Exception('Bit depth {bits} not recognized {}'.format(plat_names.keys())) - - python_tag = 'cp{major}{minor}'.format( - major=sys.version_info[0], - minor=sys.version_info[1], - ) - - cfg.write( -'''[bdist_wheel] -python-tag = {python_tag} -plat-name = {plat_name}'''.format(**locals())) - - build = os.environ.get('APPVEYOR_BUILD_FOLDER', os.getcwd()) - - destination = os.path.join(build, 'src', 'pyqt5_tools') - os.makedirs(destination, exist_ok=True) - examples_destination = os.path.join(destination, 'examples') - - build_id = os.environ.get('APPVEYOR_BUILD_ID', 'local') - with open(os.path.join(destination, 'build_id'), 'w') as f: - f.write(build_id + '\n') - - job_id = os.environ.get('APPVEYOR_JOB_ID', 'local') - with open(os.path.join(destination, 'job_id'), 'w') as f: - f.write(job_id + '\n') - - windeployqt_path = os.path.join(qt_bin_path, 'windeployqt.exe') - - application_paths = glob.glob(os.path.join(qt_bin_path, '*.exe')) - - application_names = [] - - destination_qt = os.path.join(destination, 'Qt') - destination_qt_bin = os.path.join(destination_qt, 'bin') - os.makedirs(destination_qt_bin, exist_ok=True) - - for application in application_paths: - application_path = os.path.join(qt_bin_path, application) - - print('\n\nChecking: {}'.format(os.path.basename(application))) - try: - output = subprocess.check_output( - [ - windeployqt_path, - application_path, - '--dry-run', - '--list', 'source', - ], - cwd=destination, - ) - except subprocess.CalledProcessError: - continue - - if b'WebEngine' in output: - print(' skipped') - continue - - shutil.copy(application_path, destination_qt_bin) - - report_and_check_call( - command=[ - windeployqt_path, - os.path.basename(application), - ], - cwd=destination_qt_bin, - ) - - application_names.append(pathlib.Path(application).stem) - - entry_point_function_names = { - application_name.replace('-', '_'): application_name - for application_name in application_names - } - - entry_points_py = pathlib.Path(destination)/'entrypoints.py' - with open(str(entry_points_py)) as f: - f.read() - newlines = preferred_newlines(f) - with open(str(entry_points_py), 'a', newline=newlines) as f: - for function_name, application_name in entry_point_function_names.items(): - f.write(textwrap.dedent('''\ - def {function_name}(): - load_dotenv() - return subprocess.call([str(here/'Qt'/'bin'/'{application_name}.exe'), *sys.argv[1:]]) - - - '''.format( - function_name=function_name, - application_name=application_name, - ))) - - console_scripts = [ - '{application_name} = pyqt5_tools.entrypoints:{function_name}'.format( - function_name=function_name, - application_name=application_name, - ) - for function_name, application_name in entry_point_function_names.items() - ] - - destination_plugins = os.path.join(destination_qt_bin, 'plugins') - - platform_path = os.path.join(destination_plugins, 'platforms') - os.makedirs(platform_path, exist_ok=True) - for platform_plugin in ('minimal',): - shutil.copy( - os.path.join( - os.environ['QT_BASE_PATH'], - compiler_dir, - 'plugins', - 'platforms', - 'q{}.dll'.format(platform_plugin), - ), - platform_path, - ) - - sysroot = os.path.join(build, 'sysroot') - os.makedirs(sysroot, exist_ok=True) - nmake = shutil.which('nmake') - - src = os.path.join(build, 'src') - native = os.path.join(sysroot, 'native') - os.makedirs(native, exist_ok=True) - - pyqt5_version = os.environ['PYQT5_VERSION'] - # sip_version = next( - # d.version - # for d in pip.utils.get_installed_distributions() - # if d.project_name == 'sip' - # ) - sip_version = { - '5.5.1': '4.17', - '5.6': '4.19', - '5.7.1': '4.19.8', - '5.8.2': '4.19.8', - '5.9': '4.19.8', - '5.9.2': '4.19.8', - '5.10': '4.19.8', - '5.10.1': '4.19.8', - '5.11.2': '4.19.13', - '5.11.3': '4.19.13', - '5.12': '4.19.14', - '5.12.1': '4.19.15', - '5.12.3': '4.19.18', - '5.13.0': '4.19.18', - '5.13.1': '4.19.19', - '5.13.2': '4.19.19', - }[pyqt5_version] - - sip_name = 'sip-{}'.format(sip_version) - if 'dev' in sip_version: - sip_url = ( - 'https://www.riverbankcomputing.com' - '/static/Downloads/sip/sip-{}.zip'.format(sip_version) - ) - else: - sip_url = ( - 'https://www.riverbankcomputing.com' - '/static/Downloads/sip/{}/{}.zip'.format( - sip_version, sip_name - ) - ) - - r = download(sip_url) - - z = zipfile.ZipFile(io.BytesIO(r.content)) - z.extractall(path=src) - sip = os.path.join(src, sip_name) - native_sip = sip + '-native' - shutil.copytree(os.path.join(src, sip_name), native_sip) - os.environ['CL'] = '/I"{}\\include\\python{}"'.format( - sysroot, - '.'.join(python_major_minor) - ) - - year = compiler_year - if year == '2013': - year = '2010' - - pyqt5_version_tuple = tuple(int(x) for x in pyqt5_version.split('.')) - - report_and_check_call( - command=[ - sys.executable, - 'configure.py', - ], - cwd=native_sip, - ) - report_and_check_call( - command=[ - nmake, - ], - cwd=native_sip, - env=os.environ, - ) - report_and_check_call( - command=[ - nmake, - 'install', - ], - cwd=native_sip, - env=os.environ, - ) - - sip_configure_extras = [] - if pyqt5_version_tuple >= (5, 11): - sip_configure_extras.append('--sip-module=PyQt5.sip') - - report_and_check_call( - command=[ - sys.executable, - 'configure.py', - '--no-tools', - *sip_configure_extras, - ], - cwd=sip, - ) - - report_and_check_call( - command=[ - nmake, - ], - cwd=sip, - env=os.environ, - ) - - report_and_check_call( - command=[ - nmake, - 'install', - ], - cwd=sip, - env=os.environ, - ) - - pyqt5_version_tuple = tuple(int(x) for x in pyqt5_version.split('.')) - if pyqt5_version_tuple >= (5, 13, 2): - pyqt5_name = 'PyQt5-{}'.format(pyqt5_version) - elif pyqt5_version_tuple >= (5, 6): - pyqt5_name = 'PyQt5_gpl-{}'.format(pyqt5_version) - else: - pyqt5_name = 'PyQt-gpl-{}'.format(pyqt5_version) - - pyqt5_url = ( - 'https://www.riverbankcomputing.com' - '/static/Downloads/PyQt5/{}/{}.zip' - ).format(pyqt5_version, pyqt5_name) - - r = download(pyqt5_url) - z = zipfile.ZipFile(io.BytesIO(r.content)) - z.extractall(path=src) - - pyqt5 = os.path.join(src, pyqt5_name) - - # TODO: make a patch for the lower versions as well - if pyqt5_version_tuple >= (5, 7): - if pyqt5_version_tuple >= (5, 11): - pluginloader_patch = '..\\..\\pluginloader.5.11.patch' - else: - pluginloader_patch = '..\\..\\pluginloader.patch' - - report_and_check_call( - command=['patch', '-p', '1', '-i', pluginloader_patch], - shell=True, # TODO: don't do this - cwd=pyqt5, - ) - - pyqt5_install = pathlib.Path(os.path.expandvars(sysroot))/'pyqt5-install' - - designer_plugin_path = pyqt5_install/'designer' - designer_plugin_path.mkdir(parents=True, exist_ok=True) - - qml_plugin_path = pyqt5_install/'qml' - qml_plugin_path.mkdir(parents=True, exist_ok=True) - - designer_pro = os.path.join(pyqt5, 'designer', 'designer.pro-in') - with open(designer_pro, 'a') as f: - f.write('\nDEFINES += PYTHON_LIB=\'"\\\\\\"@PYSHLIB@\\\\\\""\'\n') - command = [ - sys.executable, - 'configure.py', - '--no-tools', - '--no-qsci-api', - '--confirm-license', - '--enable=QtDesigner', - '--designer-plugindir={}'.format(designer_plugin_path), - '--enable=QtQml', - '--enable=QtQuick', - '--qml-plugindir={}'.format(qml_plugin_path), - '--verbose', - '--sip={}'.format(pathlib.Path(sys.executable).with_name('sip.exe')), - ] - - report_and_check_call( - command=command, - cwd=pyqt5, - env=os.environ, - ) - - sys.stderr.write('another stderr test from {}\n'.format(__file__)) - - report_and_check_call( - command=[ - nmake, - ], - cwd=pyqt5, - env=os.environ, - ) - report_and_check_call( - command=[ - nmake, - 'install', - ], - cwd=pyqt5, - env=os.environ, - ) - designer_plugin_path, = designer_plugin_path.glob('*') - designer_plugin_destination = os.path.join(destination_plugins, 'designer') - os.makedirs(fspath(designer_plugin_destination), exist_ok=True) - shutil.copy(fspath(designer_plugin_path), designer_plugin_destination) - - qml_plugin_path, = qml_plugin_path.glob('*') - qml_plugin_destination = os.path.join(destination_plugins) - os.makedirs(fspath(qml_plugin_destination), exist_ok=True) - shutil.copy(fspath(qml_plugin_path), qml_plugin_destination) - shutil.copy(fspath(qml_plugin_path), examples_destination) - - destination_qml = os.path.join(destination_qt, 'qml') - - qml_path = os.path.join(qt_compiler_path, 'qml') - - def ignore(directory, names): - names = set(names) - - def is_debug_dll(names, name): - base, extension = os.path.splitext(name) - - return ( - extension == '.dll' - and base[-1] == 'd' - and (base[:-1] + extension) in names - ) - - names = { - name - for name in names - if ( - name.endswith('.pdb') - or is_debug_dll(names=names, name=name) - ) - } - - return names - - shutil.copytree( - qml_path, - destination_qml, - ignore=ignore, - ) - - shutil.copy(os.path.join(pyqt5, 'LICENSE'), - os.path.join(destination, 'LICENSE.pyqt5')) - - # Since windeployqt doesn't actually work with --compiler-runtime, - # copy it ourselves - plat = {32: 'x86', 64: 'x64'}[bits] - redist_path = os.path.join(vs_path, 'VC', 'redist')\ - - if decimal.Decimal(msvc_version) >= 14.1: - redist_path = os.path.join(redist_path, 'MSVC') - hmm = os.listdir(redist_path) - print('redist_path:', redist_path) - print('hmm:', hmm) - picked = max(hmm, key=lambda x: x.split('.')) - print('picked:', picked) - redist_path = os.path.join(redist_path, picked) - - msvc_version_for_files = {'14.14': '14.1'}.get(msvc_version, msvc_version) - msvc_version_for_files = msvc_version_for_files.replace('.', '') - - redist_path = os.path.join( - redist_path, - plat, - 'Microsoft.VC{}.CRT'.format(msvc_version_for_files), - ) - - redist_files = os.listdir(redist_path) - - for file in redist_files: - dest = os.path.join(destination, file) - shutil.copyfile(os.path.join(redist_path, file), dest) - os.chmod(dest, stat.S_IWRITE) - - return Results(console_scripts=console_scripts) - - -if __name__ == '__main__': - sys.exit(main()) diff --git a/build_new.py b/build_new.py deleted file mode 100644 index 1c4c9563c..000000000 --- a/build_new.py +++ /dev/null @@ -1,1498 +0,0 @@ -import faulthandler -faulthandler.enable() - -import inspect -import itertools -import os -import pathlib -import platform -import shlex -import shutil -import subprocess -import sys -import tarfile -import tempfile -import textwrap -import traceback -import typing - -import attr -import hyperlink -import lddwrap -import requests -import setuptools.command.build_py - - -fspath = getattr(os, 'fspath', str) - - -class BuildPy(setuptools.command.build_py.build_py): - def build_packages(self): - super().build_packages() - - try: - [package_name] = ( - package - for package in self.distribution.packages - if '.' not in package - ) - - build_command = self.distribution.command_obj['build'] - - cwd = pathlib.Path.cwd() - print('::set-env name=BUILD_PATH::{}'.format(fspath(cwd))) - lib_path = cwd / build_command.build_lib - package_path = lib_path / package_name - - results = main( - package_path=package_path, - build_base_path=cwd / build_command.build_base, - ) - - if getattr(self.distribution, 'entry_points', None) is None: - self.distribution.entry_points = {} - console_scripts = self.distribution.entry_points.setdefault('console_scripts', []) - console_scripts.extend(results.console_scripts) - except: - # something apparently consumes tracebacks (not exception messages) - # for OSError at least. let's avoid that silliness. - traceback.print_exc() - raise - - -Collector = typing.Callable[ - [pathlib.Path, pathlib.Path], - typing.Iterable[pathlib.Path], -] - - -@attr.s(frozen=True) -class Results: - console_scripts = attr.ib() - - -@attr.s(frozen=True) -class Destinations: - package = attr.ib() - examples = attr.ib() - qt = attr.ib() - qt_bin = attr.ib() - qt_plugins = attr.ib() - qt_platforms = attr.ib() - - @classmethod - def build(cls, package_path): - qt = package_path / 'Qt' - qt_bin = qt / 'bin' - qt_plugins = qt_bin / 'plugins' - qt_platforms = qt_plugins / 'platforms' - - return cls( - package=package_path, - examples=package_path / 'examples', - qt=qt, - qt_bin=qt_bin, - qt_plugins=qt_plugins, - qt_platforms=qt_platforms, - ) - - def create_directories(self): - for path in [ - self.qt, - self.qt_bin, - self.qt_plugins, - self.qt_platforms, - ]: - path.mkdir(parents=True, exist_ok=True) - - -bits = int(platform.architecture()[0][0:2]) - -# platform_names = { -# 32: 'win32', -# 64: 'win_amd64' -# } -# try: -# platform_name = platform_names[bits] -# except KeyError: -# raise Exception( -# 'Bit depth {bits} not recognized {options}'.format( -# bits=bits, -# options=platform_names.keys(), -# ), -# ) - - -# @attr.s(frozen=True) -# class Application: -# original_path = attr.ib() -# relative_path = attr.ib() -# file_name = attr.ib() -# identifier = attr.ib() -# -# @classmethod -# def build(cls, path, relative_path): -# return cls( -# original_path=path, -# relative_path=relative_path, -# file_name=path.name, -# identifier=path.stem.replace('-', '_'), -# ) - - -T = typing.TypeVar('T') - - -@attr.s(frozen=True) -class FileCopyAction: - source = attr.ib() - destination = attr.ib() # including file name, relative - - @classmethod - def from_path( - cls: typing.Type[T], - source: pathlib.Path, - root: pathlib.Path, - ) -> T: - action = cls( - source=source, - destination=source.resolve().relative_to(root.resolve()), - ) - - return action - - @classmethod - def from_tree_path( - cls: typing.Type[T], - source: pathlib.Path, - root: pathlib.Path, - filter: typing.Callable[[pathlib.Path], bool] = lambda path: True, - ) -> typing.Set[T]: - actions = { - cls( - source=source, - destination=source.relative_to(root), - ) - for source in source.rglob('*') - if filter(source) - if source.is_file() - } - - return actions - - def linux_less_specific_so_target(self: T) -> T: - destination = self.destination - - if '.so.' in destination.name: - marker = '.so.' - index = destination.name.find(marker) - index = destination.name.find('.', index + len(marker)); - less_specific = destination.with_name(destination.name[:index]) - - if destination != less_specific: - return attr.evolve(self, destination=less_specific) - - return self - - def copy(self, destination_root: pathlib.Path) -> None: - destination = destination_root / self.destination - destination.parent.mkdir(parents=True, exist_ok=True) - - shutil.copy(src=fspath(self.source), dst=fspath(destination)) - - -# @attr.s(frozen=True) -# class DirectoryCopyAction: -# source = attr.ib() -# destination = attr.ib() # including target root directory name, relative -# -# def copy(self, destination_root: pathlib.Path) -> None: -# destination = destination_root / self.destination -# destination.mkdir(parents=True, exist_ok=True) -# -# shutil.copytree( -# src=self.source, -# dst=destination, -# dirs_exist_ok=True, -# ) - - -def create_script_function_name(path: pathlib.Path): - return path.stem.replace('-', '_') - - -def linuxdeployqt_substitute_list_source( - target, - translation_path, -) -> typing.List[pathlib.Path]: - paths = [ - dependency.path - for dependency in lddwrap.list_dependencies( - path=target, - ) - if dependency.path is not None - ] - - if any('libicu' in path.name for path in paths): - paths.extend(translation_path.glob('*.qm')) - - return paths - - -def linux_executable_copy_actions( - source_path: pathlib.Path, - reference_path: pathlib.Path, - translation_path: pathlib.Path, -) -> typing.Set[FileCopyAction]: - actions = { - FileCopyAction.from_path( - source=source_path, - root=reference_path, - ), - *( - FileCopyAction.from_path( - source=path, - root=reference_path, - ) - for path in filtered_relative_to( - base=reference_path, - paths=linuxdeployqt_substitute_list_source( - target=source_path, - translation_path=translation_path, - ), - ) - ), - } - - return actions - - -@attr.s(frozen=True) -class LinuxExecutable: - original_path = attr.ib() - relative_path = attr.ib() - executable_relative_path = attr.ib() - path_name = attr.ib() - script_function_name = attr.ib() - copy_actions = attr.ib() - - @classmethod - def from_path( - cls: typing.Type[T], - path: pathlib.Path, - reference_path: pathlib.Path, - translation_path: pathlib.Path, - ) -> T: - relative_path = path.resolve().relative_to(reference_path) - copy_actions = linux_executable_copy_actions( - source_path=path, - reference_path=reference_path, - translation_path=translation_path, - ) - - return cls( - original_path=path, - relative_path=relative_path, - executable_relative_path=relative_path, - path_name=path.name, - script_function_name=create_script_function_name(path=path), - copy_actions=copy_actions, - ) - - @classmethod - def list_from_directory( - cls: typing.Type[T], - directory: pathlib.Path, - reference_path: pathlib.Path, - translation_path: pathlib.Path, - ) -> typing.List[T]: - applications = [] - - for path in directory.iterdir(): - if not path.is_file() or path.suffix != '': - print('skipping: {}'.format(path)) - continue - - try: - application = cls.from_path( - path=path, - reference_path=reference_path, - translation_path=translation_path, - ) - except DependencyCollectionError: - print('failed: {}'.format(path)) - continue - - print('including: {}'.format(path)) - applications.append(application) - - return applications - - -def win32_executable_copy_actions( - source_path: pathlib.Path, - reference_path: pathlib.Path, - windeployqt: pathlib.Path, -) -> typing.Set[FileCopyAction]: - actions = { - FileCopyAction.from_path( - source=source_path, - root=reference_path, - ), - *( - FileCopyAction.from_path( - source=path, - root=reference_path, - ) - for path in filtered_relative_to( - base=reference_path, - paths=windeployqt_list_source( - target=source_path, - windeployqt=windeployqt, - ), - ) - ), - } - - return actions - - -@attr.s(frozen=True) -class Win32Executable: - original_path = attr.ib() - relative_path = attr.ib() - executable_relative_path = attr.ib() - path_name = attr.ib() - script_function_name = attr.ib() - copy_actions = attr.ib() - - @classmethod - def from_path( - cls: typing.Type[T], - path: pathlib.Path, - reference_path: pathlib.Path, - windeployqt: pathlib.Path, - ) -> T: - relative_path = path.resolve().relative_to(reference_path.resolve()) - copy_actions = win32_executable_copy_actions( - source_path=path, - reference_path=reference_path, - windeployqt=windeployqt, - ) - - return cls( - original_path=path, - relative_path=relative_path, - executable_relative_path=relative_path, - path_name=path.name, - script_function_name=create_script_function_name(path=path), - copy_actions=copy_actions, - ) - - @classmethod - def list_from_directory( - cls: typing.Type[T], - directory: pathlib.Path, - reference_path: pathlib.Path, - windeployqt: pathlib.Path, - ) -> typing.List[T]: - applications = [] - - for path in directory.iterdir(): - if not path.is_file() or path.suffix != '.exe': - print('skipping: {}'.format(path)) - continue - - try: - application = cls.from_path( - path=path, - reference_path=reference_path, - windeployqt=windeployqt - ) - except DependencyCollectionError: - print('failed: {}'.format(path)) - continue - - print('including: {}'.format(path)) - applications.append(application) - - return applications - - -def darwin_executable_copy_actions( - source_path: pathlib.Path, - reference_path: pathlib.Path, - # TODO: shouldn't need this once using a real lib to identify dependencies - lib_path: pathlib.Path, -) -> typing.Set[FileCopyAction]: - actions = { - FileCopyAction.from_path( - source=source_path, - root=reference_path, - ), - *FileCopyAction.from_tree_path( - source=lib_path, - root=reference_path, - ), - } - - return actions - - -@attr.s(frozen=True) -class DarwinExecutable: - # The single-file ones - - original_path = attr.ib() - relative_path = attr.ib() - executable_relative_path = attr.ib() - path_name = attr.ib() - script_function_name = attr.ib() - copy_actions = attr.ib() - - @classmethod - def from_path( - cls: typing.Type[T], - path: pathlib.Path, - reference_path: pathlib.Path, - lib_path: pathlib.Path, - ) -> T: - relative_path = path.resolve().relative_to(reference_path) - copy_actions = darwin_executable_copy_actions( - source_path=path, - reference_path=reference_path, - lib_path=lib_path, - ) - - return cls( - original_path=path, - relative_path=relative_path, - executable_relative_path=relative_path, - path_name=path.name, - script_function_name=create_script_function_name(path=path), - copy_actions=copy_actions, - ) - - @classmethod - def list_from_directory( - cls: typing.Type[T], - directory: pathlib.Path, - reference_path: pathlib.Path, - lib_path: pathlib.Path, - ) -> typing.List[T]: - applications = [] - - for path in directory.iterdir(): - if not path.is_file() or path.suffix != '': - print('skipping: {}'.format(path)) - continue - - try: - application = cls.from_path( - path=path, - reference_path=reference_path, - lib_path=lib_path, - ) - except DependencyCollectionError: - print('failed: {}'.format(path)) - continue - - print('including: {}'.format(path)) - applications.append(application) - - return applications - - -def darwin_dot_app_copy_actions( - source_path: pathlib.Path, - reference_path: pathlib.Path, - # TODO: doesn't seem like we should generally need this? but maybe? - lib_path: pathlib.Path, -) -> typing.Set[FileCopyAction]: - actions = { - FileCopyAction.from_tree_path( - source=source_path, - root=reference_path, - ), - *FileCopyAction.from_tree_path( - source=lib_path, - root=reference_path, - ), - } - - return actions - - -@attr.s(frozen=True) -class DarwinDotApp: - # The *.app directory-file ones - - original_path = attr.ib() - relative_path = attr.ib() - executable_relative_path = attr.ib() - path_name = attr.ib() - script_function_name = attr.ib() - copy_actions = attr.ib(factory=list) - - @classmethod - def from_path( - cls: typing.Type[T], - path: pathlib.Path, - reference_path: pathlib.Path, - lib_path: pathlib.Path, - ) -> T: - relative_path = path.resolve().relative_to(reference_path) - copy_actions = darwin_dot_app_copy_actions( - source_path=path, - reference_path=reference_path, - lib_path=lib_path, - ) - - return cls( - original_path=path, - relative_path=relative_path, - executable_relative_path=relative_path, - path_name=path.name, - script_function_name=create_script_function_name(path=path), - copy_actions=copy_actions, - ) - - @classmethod - def list_from_directory( - cls: typing.Type[T], - directory: pathlib.Path, - reference_path: pathlib.Path, - lib_path: pathlib.Path, - ) -> typing.List[T]: - applications = [] - - for path in directory.iterdir(): - if not path.is_file() or path.suffix != '.app': - continue - - try: - application = cls.from_path( - path=path, - reference_path=reference_path, - lib_path=lib_path, - ) - except DependencyCollectionError: - continue - - applications.append(application) - - return applications - - -AnyApplication = typing.Union[ - DarwinExecutable, - DarwinDotApp, - Win32Executable, -] - -application_types_by_platform = { # typing.Dict[str, typing.List[AnyApplication]] - 'linux': [LinuxExecutable], - 'win32': [Win32Executable], - 'darwin': [DarwinExecutable, DarwinDotApp], -} - - -@attr.s(frozen=True) -class QtPaths: - compiler = attr.ib() - bin = attr.ib() - lib = attr.ib() - translation = attr.ib() - qmake = attr.ib() - windeployqt = attr.ib() - applications = attr.ib() - platform_plugins = attr.ib() - - @classmethod - def build( - cls, - base, - version, - compiler, - platform_, - ): - compiler_path = base / version / compiler - bin_path = compiler_path / 'bin' - lib_path = compiler_path / 'lib' - translation_path = compiler_path / 'translations' - - windeployqt = bin_path / 'windeployqt.exe' - - # TODO: CAMPid 05470781340806731460631 - qmake_suffix = '' - extras = {} - if platform_ == 'linux': - extras['translation_path'] = translation_path - elif platform_ == 'win32': - qmake_suffix = '.exe' - extras['windeployqt'] = windeployqt - elif platform_ == 'darwin': - extras['lib_path'] = lib_path - - application_types = application_types_by_platform[platform_] - applications = list(itertools.chain.from_iterable( - application_type.list_from_directory( - directory=bin_path, - reference_path=compiler_path, - **extras, - ) - for application_type in application_types - )) - - return cls( - compiler=compiler_path, - bin=bin_path, - lib=lib_path, - translation=translation_path, - qmake=(bin_path / 'qmake').with_suffix(qmake_suffix), - windeployqt=windeployqt, - applications=applications, - platform_plugins=compiler_path / 'plugins' / 'platforms', - ) - - -def filtered_applications( - applications: typing.Iterable[AnyApplication], - filter: typing.Callable[[pathlib.Path], bool] = lambda path: True, -) -> typing.List[AnyApplication]: - results = [] - - for application in applications: - print('\n\nChecking: {}'.format(application.path_name)) - - if any( - filter(copy_action.destination) - for copy_action in application.copy_actions - ): - print(' skipped') - continue - - results.append(application) - - return results - - -def identify_preferred_newlines(f): - if isinstance(f.newlines, str): - return f.newlines - return '\n' - - -# TODO: CAMPid 974597249731467124675t40136706803641679349342342 -# https://github.com/altendky/altendpy/issues/8 -def callers_line_info(): - here = inspect.currentframe() - caller = here.f_back - - if caller is None: - return None - - there = caller.f_back - info = inspect.getframeinfo(there) - - return 'File "{}", line {}, in {}'.format( - info.filename, - info.lineno, - info.function, - ) - - -# TODO: CAMPid 079079043724533410718467080456813604134316946765431341384014 -def report_and_check_call(command, *args, cwd=None, shell=False, **kwargs): - command = [fspath(c) for c in command] - - print('\nCalling:') - print(' Caller: {}'.format(callers_line_info())) - print(' CWD: {}'.format(repr(cwd))) - print(' As passed: {}'.format(repr(command))) - print(' Full: {}'.format( - ' '.join(shlex.quote(fspath(x)) for x in command), - )) - - if shell: - print(' {}'.format(repr(command))) - else: - for arg in command: - print(' {}'.format(repr(arg))) - - sys.stdout.flush() - if cwd is not None: - cwd = fspath(cwd) - return subprocess.run(command, *args, cwd=cwd, check=True, **kwargs) - - -@attr.s(frozen=True) -class Configuration: - qt_version = attr.ib() - qt_path = attr.ib() - qt_architecture = attr.ib() - qt_compiler = attr.ib() - pyqt_version = attr.ib() - pyqt_source_path = attr.ib() - platform = attr.ib() - architecture = attr.ib() - build_path = attr.ib() - download_path = attr.ib() - package_path = attr.ib() - - @classmethod - def build(cls, environment, build_path, package_path): - platform = sys.platform - qt_version = environment['QT_VERSION'] - - if platform == 'linux': - qt_compiler = 'gcc_64' - qt_architecture = 'gcc_64' - elif platform == 'macos': - qt_compiler = 'clang_64' - qt_architecture = 'clang_64' - elif platform == 'win32': - # TODO: change the actual storage - - if tuple(int(s) for s in qt_version.split('.')) >= (5, 15): - year = '2019' - else: - year = '2017' - - qt_compiler = 'msvc{year}'.format(year=year) - qt_architecture = 'win{bits}_msvc{year}'.format( - year=year, - bits=bits, - ) - - if bits == 64: - qt_compiler += '_64' - qt_architecture += '_64' - - return cls( - qt_version=qt_version, - qt_path=build_path / 'qt', - qt_architecture=qt_architecture, - qt_compiler=qt_compiler, - pyqt_version=environment['PYQT_VERSION'], - pyqt_source_path=build_path / 'pyqt5', - platform=platform, - architecture=qt_architecture, - build_path=build_path, - download_path=build_path / 'downloads', - package_path=package_path, - ) - - def create_directories(self): - for path in [ - self.qt_path, - self.pyqt_source_path, - self.build_path, - self.download_path, - ]: - path.mkdir(parents=True, exist_ok=True) - - -# https://repl.it/@altendky/requests-stream-download-to-file-2 -default_chunk_size = 2 ** 24 - - -def download_base( - file, - method, - url, - *args, - chunk_size=default_chunk_size, - resume=True, - **kwargs -): - if resume: - headers = kwargs.get('headers', {}) - headers.setdefault('Range', 'bytes={}-'.format(file.tell())) - - response = requests.request( - method, - url, - *args, - stream=True, - **kwargs, - ) - response.raise_for_status() - - for chunk in response.iter_content(chunk_size=chunk_size): - file.write(chunk) - - -def get_down(file, url, *args, **kwargs): - return download_base( - file=file, - method='GET', - url=url, - *args, - **kwargs, - ) - - -def save_sdist(project, version, directory): - project_url = hyperlink.URL( - scheme='https', - host='pypi.org', - path=('pypi', project, version, 'json'), - ) - response = requests.get(project_url) - response.raise_for_status() - - urls = response.json()['urls'] - - [record] = ( - url - for url in urls - if url.get('packagetype') == 'sdist' - ) - - url = hyperlink.URL.from_text(record['url']) - - directory.mkdir(parents=True, exist_ok=True) - path = directory / url.path[-1] - - with path.open('wb') as file: - get_down(file=file, url=url) - - return path - - -# def save_linuxdeployqt(version, directory): -# url = hyperlink.URL( -# scheme='https', -# host='github.com', -# path=( -# 'probonopd', -# 'linuxdeployqt', -# 'releases', -# 'download', -# str(version), -# 'linuxdeployqt-{version}-x86_64.AppImage'.format(version=version), -# ), -# ) -# -# directory.mkdir(parents=True, exist_ok=True) -# path = directory / url.path[-1] -# -# with path.open('wb') as file: -# get_down(file=file, url=url) -# -# st = os.stat(path) -# path.chmod(st.st_mode | stat.S_IXUSR) -# -# return path - - -# def write_setup_cfg(directory): -# setup_cfg_path = directory / 'setup.cfg' -# -# python_tag = 'cp{major}{minor}'.format( -# major=sys.version_info[0], -# minor=sys.version_info[1], -# ) -# -# setup_cfg_path.write_text(textwrap.dedent('''\ -# [bdist_wheel] -# python-tag = {python_tag} -# plat-name = {platform_name} -# ''').format(python_tag=python_tag, platform_name=platform_name)) - - -@attr.s -class LinuxPlugin: - original_path = attr.ib() - relative_path = attr.ib() - copy_actions = attr.ib() - - @classmethod - def from_name( - cls: typing.Type[T], - name: str, - reference_path: pathlib.Path, - plugin_path: pathlib.Path, - translation_path: pathlib.Path, - ) -> T: - file_name = 'libq{}.so'.format(name) - path = plugin_path / file_name - - copy_actions = linux_executable_copy_actions( - source_path=path, - reference_path=reference_path, - translation_path=translation_path, - ) - - return cls( - original_path=path, - relative_path=path.relative_to(reference_path), - copy_actions=copy_actions, - ) - - -@attr.s -class Win32Plugin: - original_path = attr.ib() - relative_path = attr.ib() - copy_actions = attr.ib() - - @classmethod - def from_name( - cls: typing.Type[T], - name: str, - reference_path: pathlib.Path, - plugin_path: pathlib.Path, - windeployqt: pathlib.Path, - ) -> T: - file_name = 'q{}.dll'.format(name) - path = plugin_path / file_name - - copy_actions = win32_executable_copy_actions( - source_path=path, - reference_path=reference_path, - windeployqt=windeployqt, - ) - - return cls( - original_path=path, - relative_path=path.relative_to(reference_path), - copy_actions=copy_actions, - ) - - -@attr.s -class DarwinPlugin: - original_path = attr.ib() - relative_path = attr.ib() - copy_actions = attr.ib() - - @classmethod - def from_name( - cls: typing.Type[T], - name: str, - reference_path: pathlib.Path, - plugin_path: pathlib.Path, - lib_path: pathlib.Path, - ) -> T: - file_name = 'libq{}.dylib'.format(name) - path = plugin_path / file_name - - copy_actions = darwin_executable_copy_actions( - source_path=path, - reference_path=reference_path, - lib_path=lib_path, - ) - - return cls( - original_path=path, - relative_path=path.relative_to(reference_path), - copy_actions=copy_actions, - ) - - -def main(package_path, build_base_path): - print('before ---!!!', file=sys.stderr) - # TODO: uhhh.... i'm trying to use an existing directory i thought - build_base_path.mkdir(parents=True, exist_ok=True) - build_path = tempfile.mkdtemp( - prefix='pyqt5_tools-', - dir=fspath(build_base_path), - ) - print('after ---!!!', file=sys.stderr) - build_path = pathlib.Path(build_path) - - configuration = Configuration.build( - environment=os.environ, - build_path=build_path, - package_path=package_path, - ) - configuration.create_directories() - - return build(configuration=configuration) - - -def checkpoint(name): - print(' ----<==== {} ====>----'.format(name)) - - -def build(configuration: Configuration): - checkpoint('Install Qt') - install_qt(configuration=configuration) - - # application_filter = { - # 'win32': lambda path: path.suffix == '.exe', - # 'linux': lambda path: path.suffix == '', - # # TODO: darwin the .app is for directories but it still grabs files but not designer... - # # 'darwin': lambda path: path.suffix == '.app', - # 'darwin': lambda path: path.suffix == '', - # }[configuration.platform] - - checkpoint('Define Paths') - qt_paths = QtPaths.build( - base=configuration.qt_path, - version=configuration.qt_version, - compiler=configuration.qt_compiler, - platform_=configuration.platform, - ) - - destinations = Destinations.build(package_path=configuration.package_path) - - checkpoint('Create Directories') - destinations.create_directories() - - checkpoint('Select Applications') - applications = filtered_applications( - applications=qt_paths.applications, - filter=lambda path: ( - 'webengine' in fspath(path).casefold() - and path.suffix != '.qm' - ), - ) - - checkpoint('Define Plugins') - platform_plugin_names = { - 'linux': ['xcb', 'minimal'], - 'win32': ['minimal'], - 'darwin': ['cocoa'], - }[configuration.platform] - - platform_plugin_type = { - 'linux': LinuxPlugin, - 'win32': Win32Plugin, - 'darwin': DarwinPlugin, - }[configuration.platform] - - # TODO: CAMPid 05470781340806731460631 - extras = {} - if configuration.platform == 'linux': - extras['translation_path'] = qt_paths.translation - elif configuration.platform == 'win32': - extras['windeployqt'] = qt_paths.windeployqt - elif configuration.platform == 'darwin': - extras['lib_path'] = qt_paths.lib - - platform_plugins = [ - platform_plugin_type.from_name( - name=name, - plugin_path=qt_paths.platform_plugins, - reference_path=qt_paths.compiler, - **extras, - ) - for name in platform_plugin_names - ] - - checkpoint('Build Application And Platform Plugin Copy Actions') - copy_actions = { - *itertools.chain.from_iterable( - application.copy_actions - for application in applications - ), - *itertools.chain.from_iterable( - plugin.copy_actions - for plugin in platform_plugins - ), - } - - if configuration.platform == 'linux': - copy_actions = { - action.linux_less_specific_so_target() - for action in copy_actions - } - - checkpoint('Write Entry Points') - entry_points_py = destinations.package / 'entrypoints.py' - - console_scripts = write_entry_points( - entry_points_py=entry_points_py, - applications=applications, - ) - - checkpoint('Download PyQt5') - pyqt5_sdist_path = save_sdist( - project='PyQt5', - version=configuration.pyqt_version, - directory=configuration.download_path, - ) - - with tarfile.open(fspath(pyqt5_sdist_path)) as tar_file: - for member in tar_file.getmembers(): - member.name = pathlib.Path(*pathlib.Path(member.name).parts[1:]) - member.name = fspath(member.name) - tar_file.extract( - member=member, - path=fspath(configuration.pyqt_source_path), - ) - - checkpoint('Patch PyQt5') - patch_pyqt(configuration, qt_paths) - - checkpoint('Build PyQt5') - build_path = build_pyqt(configuration, qt_paths) - - checkpoint('Build PyQt5 Plugin Copy Actions') - all_copy_actions = { - destinations.qt: copy_actions, - destinations.package: set(), - } - - if configuration.platform == 'win32': - designer_plugin_path = ( - build_path / 'designer' / 'release' / 'pyqt5.dll' - ) - - relative_bin = destinations.qt_bin.relative_to(destinations.qt) - package_plugins = relative_bin / 'plugins' - package_plugins_designer = ( - package_plugins / 'designer' / designer_plugin_path.name - ) - - copy_actions.add(FileCopyAction( - source=designer_plugin_path, - destination=package_plugins_designer, - )) - - # huh? we need two copies at: - # bin/platforms/qwindows.dll - # plugins/platforms/qwindows.dll (or maybe this isn't required?) - qwindows_dll = qt_paths.compiler / 'plugins' / 'platforms' / 'qwindows.dll' - copy_actions.add(FileCopyAction( - source=designer_plugin_path, - destination=(destinations.qt_bin / 'platforms' / qwindows_dll.name).relative_to(destinations.qt), - )) - - qml_plugin = build_path / 'qmlscene' / 'release' / 'pyqt5qmlplugin.dll' - - copy_actions.add(FileCopyAction( - source=qml_plugin, - destination=package_plugins, - )) - - all_copy_actions[destinations.package].add(FileCopyAction( - source=qml_plugin, - destination=destinations.examples.relative_to( - destinations.package, - ), - )) - elif configuration.platform == 'linux': - designer_plugin_path = build_path / 'designer' / 'libpyqt5.so' - - package_plugins = destinations.qt / 'plugins' - package_plugins_designer = ( - package_plugins / 'designer' / designer_plugin_path.name - ) - - copy_actions.add(FileCopyAction( - source=designer_plugin_path, - destination=package_plugins_designer.relative_to(destinations.qt), - )) - - qml_plugin = ( - build_path / 'qmlscene' / 'libpyqt5qmlplugin.so' - ) - - copy_actions.add(FileCopyAction( - source=qml_plugin, - destination=package_plugins / qml_plugin.name, - )) - all_copy_actions[destinations.package].add(FileCopyAction( - source=qml_plugin, - destination=destinations.examples.relative_to( - destinations.package, - ) / qml_plugin.name, - )) - # elif configuration.platform == 'darwin': - # package_plugins = destinations.qt / 'plugins' - # package_plugins_designer = package_plugins / 'designer' - # - # # designer_plugin_path = build_path / 'designer' / 'libpyqt5.so' - # # shutil.copy( - # # designer_plugin_path, - # # package_plugins_designer, - # # ) - - checkpoint('Execute Copy Actions') - for reference, actions in all_copy_actions.items(): - for action in actions: - action.copy(destination_root=reference) - - checkpoint('Return Results') - return Results(console_scripts=console_scripts) - - -def filtered_relative_to( - base: pathlib.Path, - paths: typing.Iterable[pathlib.Path], -) -> typing.Generator[pathlib.Path, None, None]: - for path in paths: - try: - path.resolve().relative_to(base.resolve()) - except (ValueError, OSError): - print('filtering out: {}'.format(fspath(path))) - continue - - yield path - - -def linux_collect_dependencies( - source_base: pathlib.Path, - target: pathlib.Path, -) -> typing.Generator[pathlib.Path, None, None]: - yield from filtered_relative_to( - base=source_base, - paths=( - dependency.path.resolve() - for dependency in lddwrap.list_dependencies(path=target) - if dependency.path is not None - ), - ) - - -def darwin_collect_dependencies( - source_base: pathlib.Path, - target: pathlib.Path, - lib_path: pathlib.Path, -) -> typing.Generator[pathlib.Path, None, None]: - yield from filtered_relative_to( - base=source_base, - paths=( - dependency.resolve() - for dependency in lib_path.glob('*.framework') - ), - ) - - -class DependencyCollectionError(Exception): - pass - - -def windeployqt_list_source( - target: pathlib.Path, - windeployqt: pathlib.Path, -) -> typing.Iterable[pathlib.Path]: - try: - process = report_and_check_call( - command=[ - windeployqt, - '--dry-run', - '--list', 'source', - # '--compiler-runtime', - target, - ], - stdout=subprocess.PIPE, - # ugh, 3.5 - # encoding='utf-8', - ) - except subprocess.CalledProcessError as e: - raise DependencyCollectionError(target) from e - - paths = [ - pathlib.Path(line) - # re: .decode... ugh, 3.5 - for line in process.stdout.decode('utf-8').splitlines() - ] - - return paths - - -# def win32_collect_dependencies( -# source_base: pathlib.Path, -# target: pathlib.Path, -# windeployqt: pathlib.Path, -# ) -> typing.Generator[pathlib.Path, None, None]: -# yield from filtered_relative_to( -# base=source_base, -# paths=windeployqt_list_source( -# target=target, -# windeployqt=windeployqt, -# ), -# ) - - -def patch_pyqt(configuration, qt_paths): - # TODO: gee golly get this figured out properly and configured etc - patch_path = ( - pathlib.Path(__file__).parent - / 'pluginloader.{}.patch'.format(configuration.pyqt_version) - ) - - report_and_check_call( - command=[ - 'patch', - '-p', '1', - '-i', fspath(patch_path), - ], - cwd=fspath(configuration.pyqt_source_path), - ) - - -def build_pyqt(configuration, qt_paths): - sip_module_path = (configuration.pyqt_source_path / 'sip') - module_names = [ - path.name - for path in sip_module_path.iterdir() - if path.is_dir() - ] - report_and_check_call( - command=[ - 'sip-build', - '--confirm-license', - '--verbose', - '--no-make', - '--no-tools', - '--no-dbus-python', - # TODO: don't usually want this - # '--debug', - '--qmake', qt_paths.qmake, - *itertools.chain.from_iterable( - ['--disable', module] - for module in module_names - if module not in ( - {'QtCore'} # sip-build raises - | {'QtDesigner', 'QtQml'} # what we want... ? - | {'QtGui', 'QtQuick'} # indirect dependencies - ) - ), - ], - cwd=configuration.pyqt_source_path, - ) - if configuration.platform == 'win32': - command = ['nmake'] - env = {**os.environ, 'CL': '/MP'} - else: - available_cpus = os.cpu_count() - - command = ['make', '-j{}'.format(available_cpus)] - env = {**os.environ} - - build_path = configuration.pyqt_source_path / 'build' - - report_and_check_call( - command=command, - env=env, - cwd=fspath(build_path), - ) - - return build_path - - -def install_qt(configuration): - # report_and_check_call( - # command=[ - # sys.executable, - # '-m', 'pip', - # 'install', - # '--upgrade', - # 'git+https://github.com/miurahr/aqtinstall@8b983d0a655a3a4e83cc2c35c4910b37f9b01cea#egg=aqtinstall', - # ], - # ) - - report_and_check_call( - command=[ - # *( # TODO: 517 yada seemingly doesn't get the right PATH - # # on windows - # [ - # sys.executable, - # '-m', - # ] - # if configuration.platform == 'win32' - # else [] - # ), - sys.executable, - '-m', 'aqt', - 'install', - '--outputdir', configuration.qt_path.resolve(), - configuration.qt_version, - { - 'linux': 'linux', - 'win32': 'windows', - 'darwin': 'mac', - }[configuration.platform], - 'desktop', - configuration.architecture, - ], - ) - # if configuration.platform == 'linux': - # deployqt = save_linuxdeployqt(6, configuration.download_path) - # deployqt = deployqt.resolve() - # elif configuration.platform == 'win32': - # deployqt = pathlib.Path('windeployqt.exe') - # elif configuration.platform == 'darwin': - # deployqt = pathlib.Path('macdeployqt') - # else: - # raise Exception( - # 'Unsupported platform: {}'.format(configuration.platform), - # ) - # return deployqt - - -# def collect_dependencies( -# base, -# target, -# collector, -# ): -# yield from -# for application in targets: -# yield from collector -# shutil.copy(application.original_path, destinations.qt_bin) -# -# report_and_check_call( -# command=[ -# qt_paths.deployqt, -# '--compiler-runtime', -# application.file_name, -# ], -# cwd=destinations.qt_bin, -# ) -# return filtered_applications - - -def write_entry_points( - entry_points_py: pathlib.Path, - applications: typing.List[AnyApplication], -) -> typing.List[str]: - with entry_points_py.open(newline='') as f: - f.read() - newlines = identify_preferred_newlines(f) - with entry_points_py.open('a', newline=newlines) as f: - f.write(textwrap.dedent('''\ - - # ---- start of generated wrapper entry points - - ''')) - - for application in applications: - function_def = textwrap.dedent('''\ - def {function_name}(): - env = create_env(os.environ) - return subprocess.call( - [ - str(here/'Qt'/'{application}'), - *sys.argv[1:], - ], - env=env, - ) - - - ''') - function_def_formatted = function_def.format( - function_name=application.script_function_name, - application=fspath(application.executable_relative_path.as_posix()), - ) - f.write(function_def_formatted) - - f.write(textwrap.dedent('''\ - - # ---- end of generated wrapper entry points - - ''')) - - console_scripts = [ - '{application} = pyqt5_tools.entrypoints:{function_name}'.format( - function_name=application.script_function_name, - application=application.original_path.stem, - ) - for application in applications - ] - return console_scripts diff --git a/pluginloader.5.11.patch b/pluginloader.5.11.patch deleted file mode 100644 index 634f6a48f..000000000 --- a/pluginloader.5.11.patch +++ /dev/null @@ -1,876 +0,0 @@ -From c6b7762c19352d559b4c820ec8cb57003d1c4143 Mon Sep 17 00:00:00 2001 -From: Kyle Altendorf -Date: Fri, 20 Jul 2018 09:59:23 -0400 -Subject: [PATCH] Add sys.excepthook dialog to Designer plugin (5.11) - ---- - designer/excepthook.c | 500 ++++++++++++++++++++++++++++ - designer/excepthook.py | 170 ++++++++++ - designer/generate_module_literal.py | 35 ++ - designer/pluginloader.cpp | 108 ++++++ - 4 files changed, 813 insertions(+) - create mode 100644 designer/excepthook.c - create mode 100644 designer/excepthook.py - create mode 100644 designer/generate_module_literal.py - -diff --git a/designer/excepthook.c b/designer/excepthook.c -new file mode 100644 -index 0000000..6a575af ---- /dev/null -+++ b/designer/excepthook.c -@@ -0,0 +1,500 @@ -+const char * moduleName = "exceptiondialog"; -+ -+const char moduleCode[] = { -+ 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x66, 0x75, 0x6e, -+ 0x63, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x0d, 0x0a, 0x69, 0x6d, -+ 0x70, 0x6f, 0x72, 0x74, 0x20, 0x73, 0x79, 0x73, 0x0d, 0x0a, -+ 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x74, 0x72, 0x61, -+ 0x63, 0x65, 0x62, 0x61, 0x63, 0x6b, 0x0d, 0x0a, 0x0d, 0x0a, -+ 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x50, 0x79, 0x51, 0x74, 0x35, -+ 0x20, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x51, 0x74, -+ 0x43, 0x6f, 0x72, 0x65, 0x2c, 0x20, 0x51, 0x74, 0x57, 0x69, -+ 0x64, 0x67, 0x65, 0x74, 0x73, 0x0d, 0x0a, 0x0d, 0x0a, 0x51, -+ 0x74, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x71, 0x44, 0x65, 0x62, -+ 0x75, 0x67, 0x28, 0x27, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, -+ 0x69, 0x6e, 0x67, 0x20, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, -+ 0x20, 0x66, 0x6f, 0x72, 0x20, 0x65, 0x78, 0x63, 0x65, 0x70, -+ 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x64, 0x69, 0x61, 0x6c, 0x6f, -+ 0x67, 0x73, 0x27, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x64, 0x65, -+ 0x66, 0x20, 0x65, 0x78, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6f, -+ 0x6e, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, -+ 0x62, 0x6f, 0x78, 0x28, 0x65, 0x78, 0x63, 0x54, 0x79, 0x70, -+ 0x65, 0x3d, 0x4e, 0x6f, 0x6e, 0x65, 0x2c, 0x20, 0x65, 0x78, -+ 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x3d, 0x4e, 0x6f, 0x6e, -+ 0x65, 0x2c, 0x20, 0x74, 0x72, 0x61, 0x63, 0x65, 0x62, 0x61, -+ 0x63, 0x6b, 0x6f, 0x62, 0x6a, 0x3d, 0x4e, 0x6f, 0x6e, 0x65, -+ 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x65, -+ 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x3d, 0x20, 0x74, 0x72, -+ 0x61, 0x63, 0x65, 0x62, 0x61, 0x63, 0x6b, 0x2e, 0x66, 0x6f, -+ 0x72, 0x6d, 0x61, 0x74, 0x5f, 0x65, 0x78, 0x63, 0x65, 0x70, -+ 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x65, 0x78, 0x63, 0x54, 0x79, -+ 0x70, 0x65, 0x2c, 0x20, 0x65, 0x78, 0x63, 0x56, 0x61, 0x6c, -+ 0x75, 0x65, 0x2c, 0x20, 0x74, 0x72, 0x61, 0x63, 0x65, 0x62, -+ 0x61, 0x63, 0x6b, 0x6f, 0x62, 0x6a, 0x29, 0x0d, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, -+ 0x20, 0x3d, 0x20, 0x27, 0x27, 0x2e, 0x6a, 0x6f, 0x69, 0x6e, -+ 0x28, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x29, 0x0d, -+ 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x69, 0x61, -+ 0x6c, 0x6f, 0x67, 0x28, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, -+ 0x3d, 0x4e, 0x6f, 0x6e, 0x65, 0x2c, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x69, 0x74, 0x6c, -+ 0x65, 0x3d, 0x27, 0x45, 0x78, 0x63, 0x65, 0x70, 0x74, 0x69, -+ 0x6f, 0x6e, 0x27, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, -+ 0x65, 0x3d, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2c, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x69, 0x63, 0x6f, 0x6e, 0x3d, 0x51, 0x74, 0x57, 0x69, 0x64, -+ 0x67, 0x65, 0x74, 0x73, 0x2e, 0x51, 0x4d, 0x65, 0x73, 0x73, -+ 0x61, 0x67, 0x65, 0x42, 0x6f, 0x78, 0x2e, 0x43, 0x72, 0x69, -+ 0x74, 0x69, 0x63, 0x61, 0x6c, 0x2c, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x63, 0x6c, 0x61, -+ 0x73, 0x73, 0x20, 0x46, 0x69, 0x74, 0x74, 0x65, 0x64, 0x54, -+ 0x65, 0x78, 0x74, 0x42, 0x72, 0x6f, 0x77, 0x73, 0x65, 0x72, -+ 0x28, 0x51, 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, -+ 0x2e, 0x51, 0x54, 0x65, 0x78, 0x74, 0x42, 0x72, 0x6f, 0x77, -+ 0x73, 0x65, 0x72, 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, -+ 0x20, 0x64, 0x65, 0x66, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x48, -+ 0x69, 0x6e, 0x74, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x29, 0x3a, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x20, 0x3d, 0x20, -+ 0x73, 0x75, 0x70, 0x65, 0x72, 0x28, 0x29, 0x2e, 0x73, 0x69, -+ 0x7a, 0x65, 0x48, 0x69, 0x6e, 0x74, 0x28, 0x29, 0x0d, 0x0a, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x64, 0x65, 0x66, -+ 0x61, 0x75, 0x6c, 0x74, 0x2e, 0x69, 0x73, 0x56, 0x61, 0x6c, -+ 0x69, 0x64, 0x28, 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, -+ 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x64, 0x65, 0x66, 0x61, -+ 0x75, 0x6c, 0x74, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, -+ 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x3d, -+ 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x64, 0x6f, 0x63, 0x75, -+ 0x6d, 0x65, 0x6e, 0x74, 0x28, 0x29, 0x2e, 0x73, 0x69, 0x7a, -+ 0x65, 0x28, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x73, 0x6b, 0x74, -+ 0x6f, 0x70, 0x73, 0x20, 0x3d, 0x20, 0x51, 0x74, 0x57, 0x69, -+ 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x51, 0x41, 0x70, 0x70, -+ 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x64, -+ 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x28, 0x29, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x63, -+ 0x72, 0x65, 0x65, 0x6e, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, -+ 0x72, 0x20, 0x3d, 0x20, 0x64, 0x65, 0x73, 0x6b, 0x74, 0x6f, -+ 0x70, 0x73, 0x2e, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x4e, -+ 0x75, 0x6d, 0x62, 0x65, 0x72, 0x28, 0x73, 0x65, 0x6c, 0x66, -+ 0x2e, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x28, 0x29, 0x29, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x67, 0x65, 0x6f, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x20, 0x3d, -+ 0x20, 0x64, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x73, 0x2e, -+ 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x47, 0x65, 0x6f, 0x6d, -+ 0x65, 0x74, 0x72, 0x79, 0x28, 0x73, 0x63, 0x72, 0x65, 0x65, -+ 0x6e, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x29, 0x0d, -+ 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x69, 0x66, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, -+ 0x6e, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x2e, 0x77, 0x69, -+ 0x64, 0x74, 0x68, 0x28, 0x29, 0x20, 0x3d, 0x3d, 0x20, 0x30, -+ 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, -+ 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x2e, 0x73, -+ 0x65, 0x74, 0x57, 0x69, 0x64, 0x74, 0x68, 0x28, 0x67, 0x65, -+ 0x6f, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x77, 0x69, 0x64, -+ 0x74, 0x68, 0x28, 0x29, 0x20, 0x2a, 0x20, 0x30, 0x2e, 0x32, -+ 0x35, 0x29, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x69, 0x66, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, -+ 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x2e, 0x68, -+ 0x65, 0x69, 0x67, 0x68, 0x74, 0x28, 0x29, 0x20, 0x3d, 0x3d, -+ 0x20, 0x30, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, 0x63, -+ 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, -+ 0x2e, 0x73, 0x65, 0x74, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, -+ 0x28, 0x67, 0x65, 0x6f, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, -+ 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x28, 0x29, 0x20, 0x2a, -+ 0x20, 0x30, 0x2e, 0x34, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x63, 0x72, -+ 0x6f, 0x6c, 0x6c, 0x62, 0x61, 0x72, 0x5f, 0x77, 0x69, 0x64, -+ 0x74, 0x68, 0x20, 0x3d, 0x20, 0x51, 0x74, 0x57, 0x69, 0x64, -+ 0x67, 0x65, 0x74, 0x73, 0x2e, 0x51, 0x41, 0x70, 0x70, 0x6c, -+ 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x73, 0x74, -+ 0x79, 0x6c, 0x65, 0x28, 0x29, 0x2e, 0x70, 0x69, 0x78, 0x65, -+ 0x6c, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x28, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x51, 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, -+ 0x73, 0x2e, 0x51, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x2e, 0x50, -+ 0x4d, 0x5f, 0x53, 0x63, 0x72, 0x6f, 0x6c, 0x6c, 0x42, 0x61, -+ 0x72, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x74, 0x0d, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x0d, 0x0a, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x77, 0x69, 0x64, 0x74, 0x68, 0x20, 0x3d, 0x20, 0x73, 0x75, -+ 0x6d, 0x28, 0x28, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, 0x63, -+ 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, -+ 0x2e, 0x77, 0x69, 0x64, 0x74, 0x68, 0x28, 0x29, 0x2c, 0x0d, -+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x63, 0x6f, -+ 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x4d, 0x61, 0x72, 0x67, -+ 0x69, 0x6e, 0x73, 0x28, 0x29, 0x2e, 0x6c, 0x65, 0x66, 0x74, -+ 0x28, 0x29, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, -+ 0x66, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, -+ 0x4d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x73, 0x28, 0x29, 0x2e, -+ 0x72, 0x69, 0x67, 0x68, 0x74, 0x28, 0x29, 0x2c, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x73, 0x63, 0x72, 0x6f, 0x6c, 0x6c, 0x62, 0x61, -+ 0x72, 0x5f, 0x77, 0x69, 0x64, 0x74, 0x68, 0x2c, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, -+ 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x20, 0x3d, -+ 0x20, 0x73, 0x75, 0x6d, 0x28, 0x28, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x73, -+ 0x69, 0x7a, 0x65, 0x2e, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, -+ 0x28, 0x29, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, -+ 0x66, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, -+ 0x4d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x73, 0x28, 0x29, 0x2e, -+ 0x74, 0x6f, 0x70, 0x28, 0x29, 0x2c, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, -+ 0x6e, 0x74, 0x73, 0x4d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x73, -+ 0x28, 0x29, 0x2e, 0x62, 0x6f, 0x74, 0x74, 0x6f, 0x6d, 0x28, -+ 0x29, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x63, 0x72, 0x6f, -+ 0x6c, 0x6c, 0x62, 0x61, 0x72, 0x5f, 0x77, 0x69, 0x64, 0x74, -+ 0x68, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x29, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, -+ 0x72, 0x6e, 0x20, 0x51, 0x74, 0x43, 0x6f, 0x72, 0x65, 0x2e, -+ 0x51, 0x53, 0x69, 0x7a, 0x65, 0x28, 0x77, 0x69, 0x64, 0x74, -+ 0x68, 0x2c, 0x20, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x29, -+ 0x0d, 0x0a, 0x0d, 0x0a, 0x0d, 0x0a, 0x63, 0x6c, 0x61, 0x73, -+ 0x73, 0x20, 0x44, 0x69, 0x61, 0x6c, 0x6f, 0x67, 0x55, 0x69, -+ 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x66, -+ 0x20, 0x5f, 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x5f, 0x5f, 0x28, -+ 0x73, 0x65, 0x6c, 0x66, 0x2c, 0x20, 0x70, 0x61, 0x72, 0x65, -+ 0x6e, 0x74, 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x6c, -+ 0x61, 0x79, 0x6f, 0x75, 0x74, 0x20, 0x3d, 0x20, 0x51, 0x74, -+ 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x51, 0x47, -+ 0x72, 0x69, 0x64, 0x4c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x28, -+ 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x29, 0x0d, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, -+ 0x66, 0x2e, 0x69, 0x63, 0x6f, 0x6e, 0x20, 0x3d, 0x20, 0x51, -+ 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x51, -+ 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x28, 0x70, 0x61, 0x72, 0x65, -+ 0x6e, 0x74, 0x29, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x6d, 0x65, -+ 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x3d, 0x20, 0x46, 0x69, -+ 0x74, 0x74, 0x65, 0x64, 0x54, 0x65, 0x78, 0x74, 0x42, 0x72, -+ 0x6f, 0x77, 0x73, 0x65, 0x72, 0x28, 0x70, 0x61, 0x72, 0x65, -+ 0x6e, 0x74, 0x29, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x63, 0x6f, -+ 0x70, 0x79, 0x20, 0x3d, 0x20, 0x51, 0x74, 0x57, 0x69, 0x64, -+ 0x67, 0x65, 0x74, 0x73, 0x2e, 0x51, 0x50, 0x75, 0x73, 0x68, -+ 0x42, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x28, 0x70, 0x61, 0x72, -+ 0x65, 0x6e, 0x74, 0x29, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x62, -+ 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x73, 0x20, 0x3d, 0x20, 0x51, -+ 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x51, -+ 0x44, 0x69, 0x61, 0x6c, 0x6f, 0x67, 0x42, 0x75, 0x74, 0x74, -+ 0x6f, 0x6e, 0x42, 0x6f, 0x78, 0x28, 0x70, 0x61, 0x72, 0x65, -+ 0x6e, 0x74, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, -+ 0x63, 0x6f, 0x70, 0x79, 0x2e, 0x73, 0x65, 0x74, 0x54, 0x65, -+ 0x78, 0x74, 0x28, 0x27, 0x43, 0x6f, 0x70, 0x79, 0x20, 0x54, -+ 0x6f, 0x20, 0x43, 0x6c, 0x69, 0x70, 0x62, 0x6f, 0x61, 0x72, -+ 0x64, 0x27, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, -+ 0x6c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x2e, 0x61, 0x64, 0x64, -+ 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x28, 0x73, 0x65, 0x6c, -+ 0x66, 0x2e, 0x69, 0x63, 0x6f, 0x6e, 0x2c, 0x20, 0x30, 0x2c, -+ 0x20, 0x30, 0x29, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x6c, 0x61, -+ 0x79, 0x6f, 0x75, 0x74, 0x2e, 0x61, 0x64, 0x64, 0x57, 0x69, -+ 0x64, 0x67, 0x65, 0x74, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, -+ 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2c, 0x20, 0x30, -+ 0x2c, 0x20, 0x31, 0x2c, 0x20, 0x31, 0x2c, 0x20, 0x32, 0x29, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x6c, 0x61, 0x79, 0x6f, 0x75, -+ 0x74, 0x2e, 0x61, 0x64, 0x64, 0x57, 0x69, 0x64, 0x67, 0x65, -+ 0x74, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x63, 0x6f, 0x70, -+ 0x79, 0x2c, 0x20, 0x31, 0x2c, 0x20, 0x31, 0x29, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, -+ 0x6c, 0x66, 0x2e, 0x6c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x2e, -+ 0x61, 0x64, 0x64, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x28, -+ 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x62, 0x75, 0x74, 0x74, 0x6f, -+ 0x6e, 0x73, 0x2c, 0x20, 0x31, 0x2c, 0x20, 0x32, 0x29, 0x0d, -+ 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x6c, 0x61, 0x79, 0x6f, -+ 0x75, 0x74, 0x2e, 0x73, 0x65, 0x74, 0x41, 0x6c, 0x69, 0x67, -+ 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x28, 0x73, 0x65, 0x6c, 0x66, -+ 0x2e, 0x63, 0x6f, 0x70, 0x79, 0x2c, 0x20, 0x51, 0x74, 0x43, -+ 0x6f, 0x72, 0x65, 0x2e, 0x51, 0x74, 0x2e, 0x41, 0x6c, 0x69, -+ 0x67, 0x6e, 0x4c, 0x65, 0x66, 0x74, 0x29, 0x0d, 0x0a, 0x0d, -+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, -+ 0x65, 0x6c, 0x66, 0x2e, 0x6c, 0x61, 0x79, 0x6f, 0x75, 0x74, -+ 0x2e, 0x73, 0x65, 0x74, 0x52, 0x6f, 0x77, 0x53, 0x74, 0x72, -+ 0x65, 0x74, 0x63, 0x68, 0x28, 0x30, 0x2c, 0x20, 0x31, 0x29, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x6c, 0x61, 0x79, 0x6f, 0x75, -+ 0x74, 0x2e, 0x73, 0x65, 0x74, 0x43, 0x6f, 0x6c, 0x75, 0x6d, -+ 0x6e, 0x53, 0x74, 0x72, 0x65, 0x74, 0x63, 0x68, 0x28, 0x31, -+ 0x2c, 0x20, 0x31, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x0d, 0x0a, -+ 0x63, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x44, 0x69, 0x61, 0x6c, -+ 0x6f, 0x67, 0x28, 0x51, 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, -+ 0x74, 0x73, 0x2e, 0x51, 0x44, 0x69, 0x61, 0x6c, 0x6f, 0x67, -+ 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, -+ 0x66, 0x20, 0x5f, 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x5f, 0x5f, -+ 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2c, 0x20, 0x2a, 0x61, 0x72, -+ 0x67, 0x73, 0x2c, 0x20, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, -+ 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x3d, 0x46, 0x61, 0x6c, 0x73, -+ 0x65, 0x2c, 0x20, 0x2a, 0x2a, 0x6b, 0x77, 0x61, 0x72, 0x67, -+ 0x73, 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x73, 0x75, 0x70, 0x65, 0x72, 0x28, 0x29, -+ 0x2e, 0x5f, 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x5f, 0x5f, 0x28, -+ 0x2a, 0x61, 0x72, 0x67, 0x73, 0x2c, 0x20, 0x2a, 0x2a, 0x6b, -+ 0x77, 0x61, 0x72, 0x67, 0x73, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, -+ 0x6c, 0x66, 0x2e, 0x75, 0x69, 0x20, 0x3d, 0x20, 0x44, 0x69, -+ 0x61, 0x6c, 0x6f, 0x67, 0x55, 0x69, 0x28, 0x70, 0x61, 0x72, -+ 0x65, 0x6e, 0x74, 0x3d, 0x73, 0x65, 0x6c, 0x66, 0x29, 0x0d, -+ 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x75, 0x69, 0x2e, 0x62, -+ 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x73, 0x2e, 0x61, 0x63, 0x63, -+ 0x65, 0x70, 0x74, 0x65, 0x64, 0x2e, 0x63, 0x6f, 0x6e, 0x6e, -+ 0x65, 0x63, 0x74, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x61, -+ 0x63, 0x63, 0x65, 0x70, 0x74, 0x29, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, -+ 0x2e, 0x75, 0x69, 0x2e, 0x62, 0x75, 0x74, 0x74, 0x6f, 0x6e, -+ 0x73, 0x2e, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x65, 0x64, -+ 0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x28, 0x73, -+ 0x65, 0x6c, 0x66, 0x2e, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, -+ 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x75, 0x69, -+ 0x2e, 0x63, 0x6f, 0x70, 0x79, 0x2e, 0x63, 0x6c, 0x69, 0x63, -+ 0x6b, 0x65, 0x64, 0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, -+ 0x74, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x63, 0x6f, 0x70, -+ 0x79, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x73, -+ 0x65, 0x74, 0x4c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x28, 0x73, -+ 0x65, 0x6c, 0x66, 0x2e, 0x75, 0x69, 0x2e, 0x6c, 0x61, 0x79, -+ 0x6f, 0x75, 0x74, 0x29, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x62, 0x75, 0x74, 0x74, 0x6f, 0x6e, -+ 0x73, 0x20, 0x3d, 0x20, 0x51, 0x74, 0x57, 0x69, 0x64, 0x67, -+ 0x65, 0x74, 0x73, 0x2e, 0x51, 0x44, 0x69, 0x61, 0x6c, 0x6f, -+ 0x67, 0x42, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x42, 0x6f, 0x78, -+ 0x2e, 0x4f, 0x6b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x63, 0x61, 0x6e, 0x63, -+ 0x65, 0x6c, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x3a, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x62, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x73, 0x20, -+ 0x7c, 0x3d, 0x20, 0x51, 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, -+ 0x74, 0x73, 0x2e, 0x51, 0x44, 0x69, 0x61, 0x6c, 0x6f, 0x67, -+ 0x42, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x42, 0x6f, 0x78, 0x2e, -+ 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x0d, 0x0a, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, -+ 0x6c, 0x66, 0x2e, 0x75, 0x69, 0x2e, 0x62, 0x75, 0x74, 0x74, -+ 0x6f, 0x6e, 0x73, 0x2e, 0x73, 0x65, 0x74, 0x53, 0x74, 0x61, -+ 0x6e, 0x64, 0x61, 0x72, 0x64, 0x42, 0x75, 0x74, 0x74, 0x6f, -+ 0x6e, 0x73, 0x28, 0x62, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x73, -+ 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x65, -+ 0x78, 0x74, 0x20, 0x3d, 0x20, 0x4e, 0x6f, 0x6e, 0x65, 0x0d, -+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, -+ 0x65, 0x6c, 0x66, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x20, 0x3d, -+ 0x20, 0x4e, 0x6f, 0x6e, 0x65, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, -+ 0x66, 0x2e, 0x63, 0x61, 0x63, 0x68, 0x65, 0x64, 0x5f, 0x6d, -+ 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x5f, 0x73, 0x69, 0x7a, -+ 0x65, 0x20, 0x3d, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x6d, -+ 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x53, 0x69, 0x7a, 0x65, -+ 0x28, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x73, 0x6b, 0x74, 0x6f, -+ 0x70, 0x73, 0x20, 0x3d, 0x20, 0x51, 0x74, 0x57, 0x69, 0x64, -+ 0x67, 0x65, 0x74, 0x73, 0x2e, 0x51, 0x41, 0x70, 0x70, 0x6c, -+ 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x64, 0x65, -+ 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x28, 0x29, 0x0d, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x63, 0x72, -+ 0x65, 0x65, 0x6e, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, -+ 0x20, 0x3d, 0x20, 0x64, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, -+ 0x73, 0x2e, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x4e, 0x75, -+ 0x6d, 0x62, 0x65, 0x72, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, -+ 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x28, 0x29, 0x29, 0x0d, -+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x67, -+ 0x65, 0x6f, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x20, 0x3d, 0x20, -+ 0x64, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x73, 0x2e, 0x73, -+ 0x63, 0x72, 0x65, 0x65, 0x6e, 0x47, 0x65, 0x6f, 0x6d, 0x65, -+ 0x74, 0x72, 0x79, 0x28, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, -+ 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x29, 0x0d, 0x0a, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x73, 0x65, 0x74, 0x4d, 0x61, -+ 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x48, 0x65, 0x69, 0x67, 0x68, -+ 0x74, 0x28, 0x67, 0x65, 0x6f, 0x6d, 0x65, 0x74, 0x72, 0x79, -+ 0x2e, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x28, 0x29, 0x20, -+ 0x2a, 0x20, 0x30, 0x2e, 0x37, 0x29, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, -+ 0x2e, 0x73, 0x65, 0x74, 0x4d, 0x61, 0x78, 0x69, 0x6d, 0x75, -+ 0x6d, 0x57, 0x69, 0x64, 0x74, 0x68, 0x28, 0x67, 0x65, 0x6f, -+ 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x77, 0x69, 0x64, 0x74, -+ 0x68, 0x28, 0x29, 0x20, 0x2a, 0x20, 0x30, 0x2e, 0x37, 0x29, -+ 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, -+ 0x66, 0x20, 0x63, 0x6f, 0x70, 0x79, 0x28, 0x73, 0x65, 0x6c, -+ 0x66, 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x51, 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, -+ 0x74, 0x73, 0x2e, 0x51, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, -+ 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x63, 0x6c, 0x69, 0x70, -+ 0x62, 0x6f, 0x61, 0x72, 0x64, 0x28, 0x29, 0x2e, 0x73, 0x65, -+ 0x74, 0x54, 0x65, 0x78, 0x74, 0x28, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x75, 0x69, 0x2e, 0x6d, 0x65, -+ 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x74, 0x6f, 0x50, 0x6c, -+ 0x61, 0x69, 0x6e, 0x54, 0x65, 0x78, 0x74, 0x28, 0x29, 0x20, -+ 0x2b, 0x20, 0x27, 0x5c, 0x5c, 0x6e, 0x27, 0x0d, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x0d, 0x0a, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x66, 0x20, -+ 0x73, 0x65, 0x74, 0x5f, 0x74, 0x65, 0x78, 0x74, 0x28, 0x73, -+ 0x65, 0x6c, 0x66, 0x2c, 0x20, 0x74, 0x65, 0x78, 0x74, 0x29, -+ 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x75, 0x69, 0x2e, 0x6d, -+ 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x73, 0x65, 0x74, -+ 0x50, 0x6c, 0x61, 0x69, 0x6e, 0x54, 0x65, 0x78, 0x74, 0x28, -+ 0x74, 0x65, 0x78, 0x74, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, -+ 0x66, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x20, 0x3d, 0x20, 0x4e, -+ 0x6f, 0x6e, 0x65, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x65, -+ 0x78, 0x74, 0x20, 0x3d, 0x20, 0x74, 0x65, 0x78, 0x74, 0x0d, -+ 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x75, 0x69, 0x2e, 0x6d, -+ 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x73, 0x65, 0x74, -+ 0x4c, 0x69, 0x6e, 0x65, 0x57, 0x72, 0x61, 0x70, 0x4d, 0x6f, -+ 0x64, 0x65, 0x28, 0x51, 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, -+ 0x74, 0x73, 0x2e, 0x51, 0x54, 0x65, 0x78, 0x74, 0x45, 0x64, -+ 0x69, 0x74, 0x2e, 0x4e, 0x6f, 0x57, 0x72, 0x61, 0x70, 0x29, -+ 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, -+ 0x66, 0x20, 0x73, 0x65, 0x74, 0x5f, 0x68, 0x74, 0x6d, 0x6c, -+ 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2c, 0x20, 0x68, 0x74, 0x6d, -+ 0x6c, 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x75, 0x69, -+ 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x73, -+ 0x65, 0x74, 0x48, 0x74, 0x6d, 0x6c, 0x28, 0x68, 0x74, 0x6d, -+ 0x6c, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x68, -+ 0x74, 0x6d, 0x6c, 0x20, 0x3d, 0x20, 0x68, 0x74, 0x6d, 0x6c, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x65, 0x78, 0x74, 0x20, -+ 0x3d, 0x20, 0x4e, 0x6f, 0x6e, 0x65, 0x0d, 0x0a, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, -+ 0x6c, 0x66, 0x2e, 0x75, 0x69, 0x2e, 0x6d, 0x65, 0x73, 0x73, -+ 0x61, 0x67, 0x65, 0x2e, 0x73, 0x65, 0x74, 0x4c, 0x69, 0x6e, -+ 0x65, 0x57, 0x72, 0x61, 0x70, 0x4d, 0x6f, 0x64, 0x65, 0x28, -+ 0x51, 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, -+ 0x51, 0x54, 0x65, 0x78, 0x74, 0x45, 0x64, 0x69, 0x74, 0x2e, -+ 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x57, 0x69, 0x64, 0x74, -+ 0x68, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x64, 0x65, 0x66, 0x20, 0x73, 0x65, 0x74, 0x5f, 0x6d, 0x65, -+ 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x62, 0x6f, 0x78, 0x5f, -+ 0x69, 0x63, 0x6f, 0x6e, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2c, -+ 0x20, 0x69, 0x63, 0x6f, 0x6e, 0x29, 0x3a, 0x0d, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, -+ 0x66, 0x2e, 0x75, 0x69, 0x2e, 0x69, 0x63, 0x6f, 0x6e, 0x2e, -+ 0x73, 0x65, 0x74, 0x50, 0x69, 0x78, 0x6d, 0x61, 0x70, 0x28, -+ 0x51, 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, -+ 0x51, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x6f, -+ 0x78, 0x2e, 0x73, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, -+ 0x49, 0x63, 0x6f, 0x6e, 0x28, 0x69, 0x63, 0x6f, 0x6e, 0x29, -+ 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, -+ 0x65, 0x66, 0x20, 0x65, 0x78, 0x65, 0x63, 0x28, 0x73, 0x65, -+ 0x6c, 0x66, 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x51, 0x74, 0x43, 0x6f, 0x72, 0x65, -+ 0x2e, 0x51, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x2e, 0x73, 0x69, -+ 0x6e, 0x67, 0x6c, 0x65, 0x53, 0x68, 0x6f, 0x74, 0x28, 0x31, -+ 0x30, 0x2c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x6f, 0x6f, -+ 0x6c, 0x73, 0x2e, 0x70, 0x61, 0x72, 0x74, 0x69, 0x61, 0x6c, -+ 0x28, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, -+ 0x65, 0x6c, 0x66, 0x2e, 0x73, 0x65, 0x74, 0x4d, 0x61, 0x78, -+ 0x69, 0x6d, 0x75, 0x6d, 0x53, 0x69, 0x7a, 0x65, 0x2c, 0x0d, -+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, -+ 0x66, 0x2e, 0x63, 0x61, 0x63, 0x68, 0x65, 0x64, 0x5f, 0x6d, -+ 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x5f, 0x73, 0x69, 0x7a, -+ 0x65, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x29, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, -+ 0x72, 0x6e, 0x20, 0x73, 0x75, 0x70, 0x65, 0x72, 0x28, 0x29, -+ 0x2e, 0x65, 0x78, 0x65, 0x63, 0x28, 0x29, 0x0d, 0x0a, 0x0d, -+ 0x0a, 0x0d, 0x0a, 0x64, 0x65, 0x66, 0x20, 0x64, 0x69, 0x61, -+ 0x6c, 0x6f, 0x67, 0x28, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, -+ 0x2c, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2c, -+ 0x20, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x3d, 0x4e, 0x6f, 0x6e, -+ 0x65, 0x2c, 0x20, 0x69, 0x63, 0x6f, 0x6e, 0x3d, 0x4e, 0x6f, -+ 0x6e, 0x65, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x69, 0x63, 0x68, -+ 0x5f, 0x74, 0x65, 0x78, 0x74, 0x3d, 0x46, 0x61, 0x6c, 0x73, -+ 0x65, 0x2c, 0x20, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, -+ 0x61, 0x62, 0x6c, 0x65, 0x3d, 0x46, 0x61, 0x6c, 0x73, 0x65, -+ 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6f, -+ 0x78, 0x20, 0x3d, 0x20, 0x44, 0x69, 0x61, 0x6c, 0x6f, 0x67, -+ 0x28, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x3d, 0x70, 0x61, -+ 0x72, 0x65, 0x6e, 0x74, 0x2c, 0x20, 0x63, 0x61, 0x6e, 0x63, -+ 0x65, 0x6c, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x3d, 0x63, 0x61, -+ 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x29, -+ 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, -+ 0x20, 0x72, 0x69, 0x63, 0x68, 0x5f, 0x74, 0x65, 0x78, 0x74, -+ 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x62, 0x6f, 0x78, 0x2e, 0x73, 0x65, 0x74, 0x5f, 0x68, -+ 0x74, 0x6d, 0x6c, 0x28, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, -+ 0x65, 0x29, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, -+ 0x73, 0x65, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x62, 0x6f, 0x78, 0x2e, 0x73, 0x65, 0x74, -+ 0x5f, 0x74, 0x65, 0x78, 0x74, 0x28, 0x6d, 0x65, 0x73, 0x73, -+ 0x61, 0x67, 0x65, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x69, 0x66, 0x20, 0x69, 0x63, 0x6f, 0x6e, 0x20, -+ 0x69, 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x4e, 0x6f, 0x6e, -+ 0x65, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x62, 0x6f, 0x78, 0x2e, 0x73, 0x65, 0x74, 0x5f, -+ 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x62, 0x6f, -+ 0x78, 0x5f, 0x69, 0x63, 0x6f, 0x6e, 0x28, 0x69, 0x63, 0x6f, -+ 0x6e, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x69, 0x66, 0x20, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x20, 0x69, -+ 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x4e, 0x6f, 0x6e, 0x65, -+ 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x69, -+ 0x74, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0x51, 0x74, 0x57, 0x69, -+ 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x51, 0x41, 0x70, 0x70, -+ 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x69, -+ 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x28, 0x29, 0x2e, -+ 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, -+ 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x28, 0x29, 0x0d, 0x0a, 0x0d, -+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, -+ 0x66, 0x20, 0x6c, 0x65, 0x6e, 0x28, 0x70, 0x61, 0x72, 0x65, -+ 0x6e, 0x74, 0x5f, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x29, 0x20, -+ 0x3e, 0x20, 0x30, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x69, -+ 0x74, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0x27, 0x20, 0x2d, 0x20, -+ 0x27, 0x2e, 0x6a, 0x6f, 0x69, 0x6e, 0x28, 0x28, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x72, 0x65, -+ 0x6e, 0x74, 0x5f, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x2c, 0x0d, -+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x69, 0x74, -+ 0x6c, 0x65, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x0d, -+ 0x0a, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x62, 0x6f, 0x78, 0x2e, 0x73, 0x65, 0x74, -+ 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x54, 0x69, 0x74, 0x6c, -+ 0x65, 0x28, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x29, 0x0d, 0x0a, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, -+ 0x72, 0x6e, 0x20, 0x62, 0x6f, 0x78, 0x2e, 0x65, 0x78, 0x65, -+ 0x63, 0x28, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x51, 0x74, 0x43, -+ 0x6f, 0x72, 0x65, 0x2e, 0x71, 0x44, 0x65, 0x62, 0x75, 0x67, -+ 0x28, 0x27, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x20, -+ 0x73, 0x79, 0x73, 0x2e, 0x65, 0x78, 0x63, 0x65, 0x70, 0x74, -+ 0x68, 0x6f, 0x6f, 0x6b, 0x20, 0x74, 0x6f, 0x20, 0x70, 0x72, -+ 0x6f, 0x76, 0x69, 0x64, 0x65, 0x20, 0x64, 0x69, 0x61, 0x6c, -+ 0x6f, 0x67, 0x27, 0x29, 0x0d, 0x0a, 0x73, 0x79, 0x73, 0x2e, -+ 0x65, 0x78, 0x63, 0x65, 0x70, 0x74, 0x68, 0x6f, 0x6f, 0x6b, -+ 0x20, 0x3d, 0x20, 0x65, 0x78, 0x63, 0x65, 0x70, 0x74, 0x69, -+ 0x6f, 0x6e, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, -+ 0x5f, 0x62, 0x6f, 0x78, 0x0d, 0x0a, 0x00 -+}; -diff --git a/designer/excepthook.py b/designer/excepthook.py -new file mode 100644 -index 0000000..1c4aaa9 ---- /dev/null -+++ b/designer/excepthook.py -@@ -0,0 +1,170 @@ -+import functools -+import sys -+import traceback -+ -+from PyQt5 import QtCore, QtWidgets -+ -+QtCore.qDebug('Importing module for exception dialogs') -+ -+def exception_message_box(excType=None, excValue=None, tracebackobj=None): -+ message = traceback.format_exception(excType, excValue, tracebackobj) -+ message = ''.join(message) -+ -+ dialog( -+ parent=None, -+ title='Exception', -+ message=message, -+ icon=QtWidgets.QMessageBox.Critical, -+ ) -+ -+class FittedTextBrowser(QtWidgets.QTextBrowser): -+ def sizeHint(self): -+ default = super().sizeHint() -+ -+ if not default.isValid(): -+ return default -+ -+ document_size = self.document().size() -+ -+ desktops = QtWidgets.QApplication.desktop() -+ screen_number = desktops.screenNumber(self.parent()) -+ geometry = desktops.screenGeometry(screen_number) -+ -+ if document_size.width() == 0: -+ document_size.setWidth(geometry.width() * 0.25) -+ if document_size.height() == 0: -+ document_size.setHeight(geometry.height() * 0.4) -+ -+ scrollbar_width = QtWidgets.QApplication.style().pixelMetric( -+ QtWidgets.QStyle.PM_ScrollBarExtent -+ ) -+ -+ width = sum(( -+ document_size.width(), -+ self.contentsMargins().left(), -+ self.contentsMargins().right(), -+ scrollbar_width, -+ )) -+ -+ height = sum(( -+ document_size.height(), -+ self.contentsMargins().top(), -+ self.contentsMargins().bottom(), -+ scrollbar_width, -+ )) -+ -+ return QtCore.QSize(width, height) -+ -+ -+class DialogUi: -+ def __init__(self, parent): -+ self.layout = QtWidgets.QGridLayout(parent) -+ self.icon = QtWidgets.QLabel(parent) -+ self.message = FittedTextBrowser(parent) -+ self.copy = QtWidgets.QPushButton(parent) -+ self.buttons = QtWidgets.QDialogButtonBox(parent) -+ -+ self.copy.setText('Copy To Clipboard') -+ -+ self.layout.addWidget(self.icon, 0, 0) -+ self.layout.addWidget(self.message, 0, 1, 1, 2) -+ self.layout.addWidget(self.copy, 1, 1) -+ self.layout.addWidget(self.buttons, 1, 2) -+ -+ self.layout.setAlignment(self.copy, QtCore.Qt.AlignLeft) -+ -+ self.layout.setRowStretch(0, 1) -+ self.layout.setColumnStretch(1, 1) -+ -+ -+class Dialog(QtWidgets.QDialog): -+ def __init__(self, *args, cancellable=False, **kwargs): -+ super().__init__(*args, **kwargs) -+ -+ self.ui = DialogUi(parent=self) -+ -+ self.ui.buttons.accepted.connect(self.accept) -+ self.ui.buttons.rejected.connect(self.reject) -+ -+ self.ui.copy.clicked.connect(self.copy) -+ -+ self.setLayout(self.ui.layout) -+ buttons = QtWidgets.QDialogButtonBox.Ok -+ if cancellable: -+ buttons |= QtWidgets.QDialogButtonBox.Cancel -+ -+ self.ui.buttons.setStandardButtons(buttons) -+ -+ self.text = None -+ self.html = None -+ -+ self.cached_maximum_size = self.maximumSize() -+ -+ desktops = QtWidgets.QApplication.desktop() -+ screen_number = desktops.screenNumber(self.parent()) -+ geometry = desktops.screenGeometry(screen_number) -+ -+ self.setMaximumHeight(geometry.height() * 0.7) -+ self.setMaximumWidth(geometry.width() * 0.7) -+ -+ def copy(self): -+ QtWidgets.QApplication.clipboard().setText( -+ self.ui.message.toPlainText() + '\\n' -+ ) -+ -+ def set_text(self, text): -+ self.ui.message.setPlainText(text) -+ -+ self.html = None -+ self.text = text -+ -+ self.ui.message.setLineWrapMode(QtWidgets.QTextEdit.NoWrap) -+ -+ def set_html(self, html): -+ self.ui.message.setHtml(html) -+ -+ self.html = html -+ self.text = None -+ -+ self.ui.message.setLineWrapMode(QtWidgets.QTextEdit.WidgetWidth) -+ -+ def set_message_box_icon(self, icon): -+ self.ui.icon.setPixmap(QtWidgets.QMessageBox.standardIcon(icon)) -+ -+ def exec(self): -+ QtCore.QTimer.singleShot(10, functools.partial( -+ self.setMaximumSize, -+ self.cached_maximum_size, -+ )) -+ -+ return super().exec() -+ -+ -+def dialog(parent, message, title=None, icon=None, -+ rich_text=False, cancellable=False): -+ box = Dialog(parent=parent, cancellable=cancellable) -+ -+ if rich_text: -+ box.set_html(message) -+ else: -+ box.set_text(message) -+ -+ if icon is not None: -+ box.set_message_box_icon(icon) -+ -+ if title is not None: -+ parent_title = QtWidgets.QApplication.instance().applicationName() -+ -+ if len(parent_title) > 0: -+ title = ' - '.join(( -+ parent_title, -+ title, -+ )) -+ -+ -+ box.setWindowTitle(title) -+ -+ return box.exec() -+ -+QtCore.qDebug('Setting sys.excepthook to provide dialog') -+sys.excepthook = exception_message_box -diff --git a/designer/generate_module_literal.py b/designer/generate_module_literal.py -new file mode 100644 -index 0000000..cc6b4de ---- /dev/null -+++ b/designer/generate_module_literal.py -@@ -0,0 +1,35 @@ -+import os -+import itertools -+ -+ -+# https://repl.it/IwNE/4 -+def chunker(iterable, n): -+ "Collect data into fixed-length chunks or blocks except last due to lack of fill." -+ # chunker('ABCDEFG', 3) --> ABC DEF G" -+ -+ i = iter(iterable) -+ -+ while True: -+ t = tuple(next(i) for _ in range(n)) -+ -+ if len(t) > 0: -+ yield t -+ else: -+ break -+ -+ -+with open('excepthook.py', 'rb') as f: -+ raw = f.read() -+ -+with open('excepthook.c', 'w', newline='\n') as f: -+ f.write('const char * moduleName = "exceptiondialog";\n\n') -+ f.write('const char moduleCode[] = {\n') -+ -+ indent = ' ' * 4 -+ -+ chunks = chunker(itertools.chain(raw, b'\0'), 10) -+ lines = (', '.join('0x{:02x}'.format(b) for b in chunk) for chunk in chunks) -+ lines = (',\n'.join(indent + line for line in lines)) -+ for line in lines: -+ f.write(line) -+ f.write("\n};\n") -diff --git a/designer/pluginloader.cpp b/designer/pluginloader.cpp -index 3ca8b11..066fe34 100644 ---- a/designer/pluginloader.cpp -+++ b/designer/pluginloader.cpp -@@ -25,6 +25,7 @@ - - #include - -+#include - #include - #include - #include -@@ -36,6 +37,114 @@ - - #include "../qpy/QtDesigner/qpydesignercustomwidgetplugin.h" - -+#include "excepthook.c" -+ -+ -+void setupExceptHookDialog(void) -+{ -+ qDebug() << "Preparing to import module"; -+ qDebug() << PyBytes_AS_STRING(PyUnicode_AsEncodedString(PyObject_Str(PySys_GetObject("path")), "utf-8", "error 1?")); -+ // https://stackoverflow.com/a/42853449/228539 -+ PyObject *pyModule = PyModule_New(moduleName); -+ // Set properties on the new module object -+ PyModule_AddStringConstant(pyModule, "__file__", ""); -+ PyObject *localDict = PyModule_GetDict(pyModule); // Returns a borrowed reference: no need to Py_DECREF() it once we are done -+ PyObject *builtins = PyEval_GetBuiltins(); // Returns a borrowed reference: no need to Py_DECREF() it once we are done -+ PyDict_SetItemString(localDict, "__builtins__", builtins); -+ -+ qDebug() << "About to import module"; -+ -+ // Define code in the newly created module -+ PyObject *pyValue = PyRun_String(moduleCode, Py_file_input, localDict, localDict); -+ qDebug() << "Code just run"; -+ if (pyValue == NULL) -+ { -+ qDebug() << "An error occurred while importing the module"; -+ -+ char * full_backtrace = NULL; -+ -+ if (PyErr_Occurred() != NULL) { -+ qDebug() << "PyErr_Occurred() != NULL"; -+ PyObject *ptype, *pvalue, *ptraceback; -+ PyObject *pystr, *module_name, *pyth_module, *pyth_func; -+ char *str; -+ char *error_description; -+ -+ PyErr_Fetch(&ptype, &pvalue, &ptraceback); -+ qDebug() << "ptype == NULL : " << (ptype == NULL); -+ qDebug() << "pvalue == NULL : " << (pvalue == NULL); -+ qDebug() << "ptraceback == NULL : " << (ptraceback == NULL); -+ pystr = PyObject_Str(pvalue); -+ qDebug() << "pystr == NULL : " << (pystr == NULL); -+ pystr = PyUnicode_AsEncodedString(pystr, "utf-8", "error 1?"); -+ qDebug() << "pystr == NULL : " << (pystr == NULL); -+ str = PyBytes_AS_STRING(pystr); -+ qDebug() << "str == NULL : " << (str == NULL); -+ if (str != NULL) -+ { -+ qDebug() << "str: " << str; -+ } -+ Py_DECREF(pystr); -+ error_description = strdup(str); -+ qDebug() << "error_description == NULL : " << (error_description == NULL); -+ if (error_description != NULL) -+ { -+ qDebug() << "error_description: " << error_description; -+ } -+ -+ /* See if we can get a full traceback */ -+ module_name = PyUnicode_Decode("traceback", 9, "utf-8", "error 2?"); -+ pyth_module = PyImport_Import(module_name); -+ Py_DECREF(module_name); -+ -+ qDebug() << "pyth_module == NULL : " << (pyth_module == NULL); -+ if (pyth_module == NULL) { -+ full_backtrace = NULL; -+ return; -+ } -+ -+ pyth_func = PyObject_GetAttrString(pyth_module, "format_exception"); -+ if (pyth_func && PyCallable_Check(pyth_func)) -+ { -+ qDebug() << "pyth_func && PyCallable_Check(pyth_func)"; -+ PyObject *pyth_val; -+ -+ pyth_val = PyObject_CallFunctionObjArgs(pyth_func, ptype, pvalue, ptraceback, Py_None, Py_True, NULL); -+ qDebug() << "pyth_val == NULL : " << (pyth_val == NULL); -+ -+ pystr = PyObject_Str(pyth_val); -+ qDebug() << "pystr == NULL : " << (pystr == NULL); -+ -+ pystr = PyUnicode_AsEncodedString(pystr, "utf-8", "error 3?"); -+ qDebug() << "pystr == NULL : " << (pystr == NULL); -+ -+ str = PyBytes_AS_STRING(pystr); -+ qDebug() << "str == NULL : " << (str == NULL); -+ -+ Py_DECREF(pystr); -+ full_backtrace = strdup(str); -+ Py_DECREF(pyth_val); -+ } -+ } -+ -+ if (full_backtrace != NULL) -+ { -+ qDebug() << "About to print backtrace"; -+ qDebug() << full_backtrace; -+ } -+ else -+ { -+ qDebug() << "Backtrace was NULL"; -+ } -+ } -+ else -+ { -+ qDebug() << "About to decref"; -+ Py_DECREF(pyValue); -+ } -+ -+ qDebug() << "Done importing module"; -+} - - // Construct the collection of Python widgets. - PyCustomWidgets::PyCustomWidgets(QObject *parent) : QObject(parent), -@@ -140,6 +247,7 @@ PyCustomWidgets::PyCustomWidgets(QObject *parent) : QObject(parent), - PyGILState_STATE gil_state = PyGILState_Ensure(); - #endif - -+ setupExceptHookDialog(); - bool fatal = importPlugins(dir, plugins); - - #if defined(WITH_THREAD) --- -2.18.0 - diff --git a/pluginloader.5.14.0.patch b/pluginloader.5.14.0.patch deleted file mode 100644 index fc71f4a2d..000000000 --- a/pluginloader.5.14.0.patch +++ /dev/null @@ -1,858 +0,0 @@ -diff --git a/designer/excepthook.c b/designer/excepthook.c -new file mode 100644 -index 0000000..6a575af ---- /dev/null -+++ b/designer/excepthook.c -@@ -0,0 +1,500 @@ -+const char * moduleName = "exceptiondialog"; -+ -+const char moduleCode[] = { -+ 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x66, 0x75, 0x6e, -+ 0x63, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x0d, 0x0a, 0x69, 0x6d, -+ 0x70, 0x6f, 0x72, 0x74, 0x20, 0x73, 0x79, 0x73, 0x0d, 0x0a, -+ 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x74, 0x72, 0x61, -+ 0x63, 0x65, 0x62, 0x61, 0x63, 0x6b, 0x0d, 0x0a, 0x0d, 0x0a, -+ 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x50, 0x79, 0x51, 0x74, 0x35, -+ 0x20, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x51, 0x74, -+ 0x43, 0x6f, 0x72, 0x65, 0x2c, 0x20, 0x51, 0x74, 0x57, 0x69, -+ 0x64, 0x67, 0x65, 0x74, 0x73, 0x0d, 0x0a, 0x0d, 0x0a, 0x51, -+ 0x74, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x71, 0x44, 0x65, 0x62, -+ 0x75, 0x67, 0x28, 0x27, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, -+ 0x69, 0x6e, 0x67, 0x20, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, -+ 0x20, 0x66, 0x6f, 0x72, 0x20, 0x65, 0x78, 0x63, 0x65, 0x70, -+ 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x64, 0x69, 0x61, 0x6c, 0x6f, -+ 0x67, 0x73, 0x27, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x64, 0x65, -+ 0x66, 0x20, 0x65, 0x78, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6f, -+ 0x6e, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, -+ 0x62, 0x6f, 0x78, 0x28, 0x65, 0x78, 0x63, 0x54, 0x79, 0x70, -+ 0x65, 0x3d, 0x4e, 0x6f, 0x6e, 0x65, 0x2c, 0x20, 0x65, 0x78, -+ 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x3d, 0x4e, 0x6f, 0x6e, -+ 0x65, 0x2c, 0x20, 0x74, 0x72, 0x61, 0x63, 0x65, 0x62, 0x61, -+ 0x63, 0x6b, 0x6f, 0x62, 0x6a, 0x3d, 0x4e, 0x6f, 0x6e, 0x65, -+ 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x65, -+ 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x3d, 0x20, 0x74, 0x72, -+ 0x61, 0x63, 0x65, 0x62, 0x61, 0x63, 0x6b, 0x2e, 0x66, 0x6f, -+ 0x72, 0x6d, 0x61, 0x74, 0x5f, 0x65, 0x78, 0x63, 0x65, 0x70, -+ 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x65, 0x78, 0x63, 0x54, 0x79, -+ 0x70, 0x65, 0x2c, 0x20, 0x65, 0x78, 0x63, 0x56, 0x61, 0x6c, -+ 0x75, 0x65, 0x2c, 0x20, 0x74, 0x72, 0x61, 0x63, 0x65, 0x62, -+ 0x61, 0x63, 0x6b, 0x6f, 0x62, 0x6a, 0x29, 0x0d, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, -+ 0x20, 0x3d, 0x20, 0x27, 0x27, 0x2e, 0x6a, 0x6f, 0x69, 0x6e, -+ 0x28, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x29, 0x0d, -+ 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x69, 0x61, -+ 0x6c, 0x6f, 0x67, 0x28, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, -+ 0x3d, 0x4e, 0x6f, 0x6e, 0x65, 0x2c, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x69, 0x74, 0x6c, -+ 0x65, 0x3d, 0x27, 0x45, 0x78, 0x63, 0x65, 0x70, 0x74, 0x69, -+ 0x6f, 0x6e, 0x27, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, -+ 0x65, 0x3d, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2c, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x69, 0x63, 0x6f, 0x6e, 0x3d, 0x51, 0x74, 0x57, 0x69, 0x64, -+ 0x67, 0x65, 0x74, 0x73, 0x2e, 0x51, 0x4d, 0x65, 0x73, 0x73, -+ 0x61, 0x67, 0x65, 0x42, 0x6f, 0x78, 0x2e, 0x43, 0x72, 0x69, -+ 0x74, 0x69, 0x63, 0x61, 0x6c, 0x2c, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x63, 0x6c, 0x61, -+ 0x73, 0x73, 0x20, 0x46, 0x69, 0x74, 0x74, 0x65, 0x64, 0x54, -+ 0x65, 0x78, 0x74, 0x42, 0x72, 0x6f, 0x77, 0x73, 0x65, 0x72, -+ 0x28, 0x51, 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, -+ 0x2e, 0x51, 0x54, 0x65, 0x78, 0x74, 0x42, 0x72, 0x6f, 0x77, -+ 0x73, 0x65, 0x72, 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, -+ 0x20, 0x64, 0x65, 0x66, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x48, -+ 0x69, 0x6e, 0x74, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x29, 0x3a, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x20, 0x3d, 0x20, -+ 0x73, 0x75, 0x70, 0x65, 0x72, 0x28, 0x29, 0x2e, 0x73, 0x69, -+ 0x7a, 0x65, 0x48, 0x69, 0x6e, 0x74, 0x28, 0x29, 0x0d, 0x0a, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x64, 0x65, 0x66, -+ 0x61, 0x75, 0x6c, 0x74, 0x2e, 0x69, 0x73, 0x56, 0x61, 0x6c, -+ 0x69, 0x64, 0x28, 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, -+ 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x64, 0x65, 0x66, 0x61, -+ 0x75, 0x6c, 0x74, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, -+ 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x3d, -+ 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x64, 0x6f, 0x63, 0x75, -+ 0x6d, 0x65, 0x6e, 0x74, 0x28, 0x29, 0x2e, 0x73, 0x69, 0x7a, -+ 0x65, 0x28, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x73, 0x6b, 0x74, -+ 0x6f, 0x70, 0x73, 0x20, 0x3d, 0x20, 0x51, 0x74, 0x57, 0x69, -+ 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x51, 0x41, 0x70, 0x70, -+ 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x64, -+ 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x28, 0x29, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x63, -+ 0x72, 0x65, 0x65, 0x6e, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, -+ 0x72, 0x20, 0x3d, 0x20, 0x64, 0x65, 0x73, 0x6b, 0x74, 0x6f, -+ 0x70, 0x73, 0x2e, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x4e, -+ 0x75, 0x6d, 0x62, 0x65, 0x72, 0x28, 0x73, 0x65, 0x6c, 0x66, -+ 0x2e, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x28, 0x29, 0x29, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x67, 0x65, 0x6f, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x20, 0x3d, -+ 0x20, 0x64, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x73, 0x2e, -+ 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x47, 0x65, 0x6f, 0x6d, -+ 0x65, 0x74, 0x72, 0x79, 0x28, 0x73, 0x63, 0x72, 0x65, 0x65, -+ 0x6e, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x29, 0x0d, -+ 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x69, 0x66, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, -+ 0x6e, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x2e, 0x77, 0x69, -+ 0x64, 0x74, 0x68, 0x28, 0x29, 0x20, 0x3d, 0x3d, 0x20, 0x30, -+ 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, -+ 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x2e, 0x73, -+ 0x65, 0x74, 0x57, 0x69, 0x64, 0x74, 0x68, 0x28, 0x67, 0x65, -+ 0x6f, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x77, 0x69, 0x64, -+ 0x74, 0x68, 0x28, 0x29, 0x20, 0x2a, 0x20, 0x30, 0x2e, 0x32, -+ 0x35, 0x29, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x69, 0x66, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, -+ 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x2e, 0x68, -+ 0x65, 0x69, 0x67, 0x68, 0x74, 0x28, 0x29, 0x20, 0x3d, 0x3d, -+ 0x20, 0x30, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, 0x63, -+ 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, -+ 0x2e, 0x73, 0x65, 0x74, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, -+ 0x28, 0x67, 0x65, 0x6f, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, -+ 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x28, 0x29, 0x20, 0x2a, -+ 0x20, 0x30, 0x2e, 0x34, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x63, 0x72, -+ 0x6f, 0x6c, 0x6c, 0x62, 0x61, 0x72, 0x5f, 0x77, 0x69, 0x64, -+ 0x74, 0x68, 0x20, 0x3d, 0x20, 0x51, 0x74, 0x57, 0x69, 0x64, -+ 0x67, 0x65, 0x74, 0x73, 0x2e, 0x51, 0x41, 0x70, 0x70, 0x6c, -+ 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x73, 0x74, -+ 0x79, 0x6c, 0x65, 0x28, 0x29, 0x2e, 0x70, 0x69, 0x78, 0x65, -+ 0x6c, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x28, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x51, 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, -+ 0x73, 0x2e, 0x51, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x2e, 0x50, -+ 0x4d, 0x5f, 0x53, 0x63, 0x72, 0x6f, 0x6c, 0x6c, 0x42, 0x61, -+ 0x72, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x74, 0x0d, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x0d, 0x0a, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x77, 0x69, 0x64, 0x74, 0x68, 0x20, 0x3d, 0x20, 0x73, 0x75, -+ 0x6d, 0x28, 0x28, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, 0x63, -+ 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, -+ 0x2e, 0x77, 0x69, 0x64, 0x74, 0x68, 0x28, 0x29, 0x2c, 0x0d, -+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x63, 0x6f, -+ 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x4d, 0x61, 0x72, 0x67, -+ 0x69, 0x6e, 0x73, 0x28, 0x29, 0x2e, 0x6c, 0x65, 0x66, 0x74, -+ 0x28, 0x29, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, -+ 0x66, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, -+ 0x4d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x73, 0x28, 0x29, 0x2e, -+ 0x72, 0x69, 0x67, 0x68, 0x74, 0x28, 0x29, 0x2c, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x73, 0x63, 0x72, 0x6f, 0x6c, 0x6c, 0x62, 0x61, -+ 0x72, 0x5f, 0x77, 0x69, 0x64, 0x74, 0x68, 0x2c, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, -+ 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x20, 0x3d, -+ 0x20, 0x73, 0x75, 0x6d, 0x28, 0x28, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x73, -+ 0x69, 0x7a, 0x65, 0x2e, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, -+ 0x28, 0x29, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, -+ 0x66, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, -+ 0x4d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x73, 0x28, 0x29, 0x2e, -+ 0x74, 0x6f, 0x70, 0x28, 0x29, 0x2c, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, -+ 0x6e, 0x74, 0x73, 0x4d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x73, -+ 0x28, 0x29, 0x2e, 0x62, 0x6f, 0x74, 0x74, 0x6f, 0x6d, 0x28, -+ 0x29, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x63, 0x72, 0x6f, -+ 0x6c, 0x6c, 0x62, 0x61, 0x72, 0x5f, 0x77, 0x69, 0x64, 0x74, -+ 0x68, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x29, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, -+ 0x72, 0x6e, 0x20, 0x51, 0x74, 0x43, 0x6f, 0x72, 0x65, 0x2e, -+ 0x51, 0x53, 0x69, 0x7a, 0x65, 0x28, 0x77, 0x69, 0x64, 0x74, -+ 0x68, 0x2c, 0x20, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x29, -+ 0x0d, 0x0a, 0x0d, 0x0a, 0x0d, 0x0a, 0x63, 0x6c, 0x61, 0x73, -+ 0x73, 0x20, 0x44, 0x69, 0x61, 0x6c, 0x6f, 0x67, 0x55, 0x69, -+ 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x66, -+ 0x20, 0x5f, 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x5f, 0x5f, 0x28, -+ 0x73, 0x65, 0x6c, 0x66, 0x2c, 0x20, 0x70, 0x61, 0x72, 0x65, -+ 0x6e, 0x74, 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x6c, -+ 0x61, 0x79, 0x6f, 0x75, 0x74, 0x20, 0x3d, 0x20, 0x51, 0x74, -+ 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x51, 0x47, -+ 0x72, 0x69, 0x64, 0x4c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x28, -+ 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x29, 0x0d, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, -+ 0x66, 0x2e, 0x69, 0x63, 0x6f, 0x6e, 0x20, 0x3d, 0x20, 0x51, -+ 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x51, -+ 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x28, 0x70, 0x61, 0x72, 0x65, -+ 0x6e, 0x74, 0x29, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x6d, 0x65, -+ 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x3d, 0x20, 0x46, 0x69, -+ 0x74, 0x74, 0x65, 0x64, 0x54, 0x65, 0x78, 0x74, 0x42, 0x72, -+ 0x6f, 0x77, 0x73, 0x65, 0x72, 0x28, 0x70, 0x61, 0x72, 0x65, -+ 0x6e, 0x74, 0x29, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x63, 0x6f, -+ 0x70, 0x79, 0x20, 0x3d, 0x20, 0x51, 0x74, 0x57, 0x69, 0x64, -+ 0x67, 0x65, 0x74, 0x73, 0x2e, 0x51, 0x50, 0x75, 0x73, 0x68, -+ 0x42, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x28, 0x70, 0x61, 0x72, -+ 0x65, 0x6e, 0x74, 0x29, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x62, -+ 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x73, 0x20, 0x3d, 0x20, 0x51, -+ 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x51, -+ 0x44, 0x69, 0x61, 0x6c, 0x6f, 0x67, 0x42, 0x75, 0x74, 0x74, -+ 0x6f, 0x6e, 0x42, 0x6f, 0x78, 0x28, 0x70, 0x61, 0x72, 0x65, -+ 0x6e, 0x74, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, -+ 0x63, 0x6f, 0x70, 0x79, 0x2e, 0x73, 0x65, 0x74, 0x54, 0x65, -+ 0x78, 0x74, 0x28, 0x27, 0x43, 0x6f, 0x70, 0x79, 0x20, 0x54, -+ 0x6f, 0x20, 0x43, 0x6c, 0x69, 0x70, 0x62, 0x6f, 0x61, 0x72, -+ 0x64, 0x27, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, -+ 0x6c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x2e, 0x61, 0x64, 0x64, -+ 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x28, 0x73, 0x65, 0x6c, -+ 0x66, 0x2e, 0x69, 0x63, 0x6f, 0x6e, 0x2c, 0x20, 0x30, 0x2c, -+ 0x20, 0x30, 0x29, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x6c, 0x61, -+ 0x79, 0x6f, 0x75, 0x74, 0x2e, 0x61, 0x64, 0x64, 0x57, 0x69, -+ 0x64, 0x67, 0x65, 0x74, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, -+ 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2c, 0x20, 0x30, -+ 0x2c, 0x20, 0x31, 0x2c, 0x20, 0x31, 0x2c, 0x20, 0x32, 0x29, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x6c, 0x61, 0x79, 0x6f, 0x75, -+ 0x74, 0x2e, 0x61, 0x64, 0x64, 0x57, 0x69, 0x64, 0x67, 0x65, -+ 0x74, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x63, 0x6f, 0x70, -+ 0x79, 0x2c, 0x20, 0x31, 0x2c, 0x20, 0x31, 0x29, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, -+ 0x6c, 0x66, 0x2e, 0x6c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x2e, -+ 0x61, 0x64, 0x64, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x28, -+ 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x62, 0x75, 0x74, 0x74, 0x6f, -+ 0x6e, 0x73, 0x2c, 0x20, 0x31, 0x2c, 0x20, 0x32, 0x29, 0x0d, -+ 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x6c, 0x61, 0x79, 0x6f, -+ 0x75, 0x74, 0x2e, 0x73, 0x65, 0x74, 0x41, 0x6c, 0x69, 0x67, -+ 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x28, 0x73, 0x65, 0x6c, 0x66, -+ 0x2e, 0x63, 0x6f, 0x70, 0x79, 0x2c, 0x20, 0x51, 0x74, 0x43, -+ 0x6f, 0x72, 0x65, 0x2e, 0x51, 0x74, 0x2e, 0x41, 0x6c, 0x69, -+ 0x67, 0x6e, 0x4c, 0x65, 0x66, 0x74, 0x29, 0x0d, 0x0a, 0x0d, -+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, -+ 0x65, 0x6c, 0x66, 0x2e, 0x6c, 0x61, 0x79, 0x6f, 0x75, 0x74, -+ 0x2e, 0x73, 0x65, 0x74, 0x52, 0x6f, 0x77, 0x53, 0x74, 0x72, -+ 0x65, 0x74, 0x63, 0x68, 0x28, 0x30, 0x2c, 0x20, 0x31, 0x29, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x6c, 0x61, 0x79, 0x6f, 0x75, -+ 0x74, 0x2e, 0x73, 0x65, 0x74, 0x43, 0x6f, 0x6c, 0x75, 0x6d, -+ 0x6e, 0x53, 0x74, 0x72, 0x65, 0x74, 0x63, 0x68, 0x28, 0x31, -+ 0x2c, 0x20, 0x31, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x0d, 0x0a, -+ 0x63, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x44, 0x69, 0x61, 0x6c, -+ 0x6f, 0x67, 0x28, 0x51, 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, -+ 0x74, 0x73, 0x2e, 0x51, 0x44, 0x69, 0x61, 0x6c, 0x6f, 0x67, -+ 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, -+ 0x66, 0x20, 0x5f, 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x5f, 0x5f, -+ 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2c, 0x20, 0x2a, 0x61, 0x72, -+ 0x67, 0x73, 0x2c, 0x20, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, -+ 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x3d, 0x46, 0x61, 0x6c, 0x73, -+ 0x65, 0x2c, 0x20, 0x2a, 0x2a, 0x6b, 0x77, 0x61, 0x72, 0x67, -+ 0x73, 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x73, 0x75, 0x70, 0x65, 0x72, 0x28, 0x29, -+ 0x2e, 0x5f, 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x5f, 0x5f, 0x28, -+ 0x2a, 0x61, 0x72, 0x67, 0x73, 0x2c, 0x20, 0x2a, 0x2a, 0x6b, -+ 0x77, 0x61, 0x72, 0x67, 0x73, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, -+ 0x6c, 0x66, 0x2e, 0x75, 0x69, 0x20, 0x3d, 0x20, 0x44, 0x69, -+ 0x61, 0x6c, 0x6f, 0x67, 0x55, 0x69, 0x28, 0x70, 0x61, 0x72, -+ 0x65, 0x6e, 0x74, 0x3d, 0x73, 0x65, 0x6c, 0x66, 0x29, 0x0d, -+ 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x75, 0x69, 0x2e, 0x62, -+ 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x73, 0x2e, 0x61, 0x63, 0x63, -+ 0x65, 0x70, 0x74, 0x65, 0x64, 0x2e, 0x63, 0x6f, 0x6e, 0x6e, -+ 0x65, 0x63, 0x74, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x61, -+ 0x63, 0x63, 0x65, 0x70, 0x74, 0x29, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, -+ 0x2e, 0x75, 0x69, 0x2e, 0x62, 0x75, 0x74, 0x74, 0x6f, 0x6e, -+ 0x73, 0x2e, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x65, 0x64, -+ 0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x28, 0x73, -+ 0x65, 0x6c, 0x66, 0x2e, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, -+ 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x75, 0x69, -+ 0x2e, 0x63, 0x6f, 0x70, 0x79, 0x2e, 0x63, 0x6c, 0x69, 0x63, -+ 0x6b, 0x65, 0x64, 0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, -+ 0x74, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x63, 0x6f, 0x70, -+ 0x79, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x73, -+ 0x65, 0x74, 0x4c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x28, 0x73, -+ 0x65, 0x6c, 0x66, 0x2e, 0x75, 0x69, 0x2e, 0x6c, 0x61, 0x79, -+ 0x6f, 0x75, 0x74, 0x29, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x62, 0x75, 0x74, 0x74, 0x6f, 0x6e, -+ 0x73, 0x20, 0x3d, 0x20, 0x51, 0x74, 0x57, 0x69, 0x64, 0x67, -+ 0x65, 0x74, 0x73, 0x2e, 0x51, 0x44, 0x69, 0x61, 0x6c, 0x6f, -+ 0x67, 0x42, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x42, 0x6f, 0x78, -+ 0x2e, 0x4f, 0x6b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x63, 0x61, 0x6e, 0x63, -+ 0x65, 0x6c, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x3a, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x62, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x73, 0x20, -+ 0x7c, 0x3d, 0x20, 0x51, 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, -+ 0x74, 0x73, 0x2e, 0x51, 0x44, 0x69, 0x61, 0x6c, 0x6f, 0x67, -+ 0x42, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x42, 0x6f, 0x78, 0x2e, -+ 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x0d, 0x0a, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, -+ 0x6c, 0x66, 0x2e, 0x75, 0x69, 0x2e, 0x62, 0x75, 0x74, 0x74, -+ 0x6f, 0x6e, 0x73, 0x2e, 0x73, 0x65, 0x74, 0x53, 0x74, 0x61, -+ 0x6e, 0x64, 0x61, 0x72, 0x64, 0x42, 0x75, 0x74, 0x74, 0x6f, -+ 0x6e, 0x73, 0x28, 0x62, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x73, -+ 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x65, -+ 0x78, 0x74, 0x20, 0x3d, 0x20, 0x4e, 0x6f, 0x6e, 0x65, 0x0d, -+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, -+ 0x65, 0x6c, 0x66, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x20, 0x3d, -+ 0x20, 0x4e, 0x6f, 0x6e, 0x65, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, -+ 0x66, 0x2e, 0x63, 0x61, 0x63, 0x68, 0x65, 0x64, 0x5f, 0x6d, -+ 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x5f, 0x73, 0x69, 0x7a, -+ 0x65, 0x20, 0x3d, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x6d, -+ 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x53, 0x69, 0x7a, 0x65, -+ 0x28, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x73, 0x6b, 0x74, 0x6f, -+ 0x70, 0x73, 0x20, 0x3d, 0x20, 0x51, 0x74, 0x57, 0x69, 0x64, -+ 0x67, 0x65, 0x74, 0x73, 0x2e, 0x51, 0x41, 0x70, 0x70, 0x6c, -+ 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x64, 0x65, -+ 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x28, 0x29, 0x0d, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x63, 0x72, -+ 0x65, 0x65, 0x6e, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, -+ 0x20, 0x3d, 0x20, 0x64, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, -+ 0x73, 0x2e, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x4e, 0x75, -+ 0x6d, 0x62, 0x65, 0x72, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, -+ 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x28, 0x29, 0x29, 0x0d, -+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x67, -+ 0x65, 0x6f, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x20, 0x3d, 0x20, -+ 0x64, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x73, 0x2e, 0x73, -+ 0x63, 0x72, 0x65, 0x65, 0x6e, 0x47, 0x65, 0x6f, 0x6d, 0x65, -+ 0x74, 0x72, 0x79, 0x28, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, -+ 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x29, 0x0d, 0x0a, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x73, 0x65, 0x74, 0x4d, 0x61, -+ 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x48, 0x65, 0x69, 0x67, 0x68, -+ 0x74, 0x28, 0x67, 0x65, 0x6f, 0x6d, 0x65, 0x74, 0x72, 0x79, -+ 0x2e, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x28, 0x29, 0x20, -+ 0x2a, 0x20, 0x30, 0x2e, 0x37, 0x29, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, -+ 0x2e, 0x73, 0x65, 0x74, 0x4d, 0x61, 0x78, 0x69, 0x6d, 0x75, -+ 0x6d, 0x57, 0x69, 0x64, 0x74, 0x68, 0x28, 0x67, 0x65, 0x6f, -+ 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x77, 0x69, 0x64, 0x74, -+ 0x68, 0x28, 0x29, 0x20, 0x2a, 0x20, 0x30, 0x2e, 0x37, 0x29, -+ 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, -+ 0x66, 0x20, 0x63, 0x6f, 0x70, 0x79, 0x28, 0x73, 0x65, 0x6c, -+ 0x66, 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x51, 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, -+ 0x74, 0x73, 0x2e, 0x51, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, -+ 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x63, 0x6c, 0x69, 0x70, -+ 0x62, 0x6f, 0x61, 0x72, 0x64, 0x28, 0x29, 0x2e, 0x73, 0x65, -+ 0x74, 0x54, 0x65, 0x78, 0x74, 0x28, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x75, 0x69, 0x2e, 0x6d, 0x65, -+ 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x74, 0x6f, 0x50, 0x6c, -+ 0x61, 0x69, 0x6e, 0x54, 0x65, 0x78, 0x74, 0x28, 0x29, 0x20, -+ 0x2b, 0x20, 0x27, 0x5c, 0x5c, 0x6e, 0x27, 0x0d, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x0d, 0x0a, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x66, 0x20, -+ 0x73, 0x65, 0x74, 0x5f, 0x74, 0x65, 0x78, 0x74, 0x28, 0x73, -+ 0x65, 0x6c, 0x66, 0x2c, 0x20, 0x74, 0x65, 0x78, 0x74, 0x29, -+ 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x75, 0x69, 0x2e, 0x6d, -+ 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x73, 0x65, 0x74, -+ 0x50, 0x6c, 0x61, 0x69, 0x6e, 0x54, 0x65, 0x78, 0x74, 0x28, -+ 0x74, 0x65, 0x78, 0x74, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, -+ 0x66, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x20, 0x3d, 0x20, 0x4e, -+ 0x6f, 0x6e, 0x65, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x65, -+ 0x78, 0x74, 0x20, 0x3d, 0x20, 0x74, 0x65, 0x78, 0x74, 0x0d, -+ 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x75, 0x69, 0x2e, 0x6d, -+ 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x73, 0x65, 0x74, -+ 0x4c, 0x69, 0x6e, 0x65, 0x57, 0x72, 0x61, 0x70, 0x4d, 0x6f, -+ 0x64, 0x65, 0x28, 0x51, 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, -+ 0x74, 0x73, 0x2e, 0x51, 0x54, 0x65, 0x78, 0x74, 0x45, 0x64, -+ 0x69, 0x74, 0x2e, 0x4e, 0x6f, 0x57, 0x72, 0x61, 0x70, 0x29, -+ 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, -+ 0x66, 0x20, 0x73, 0x65, 0x74, 0x5f, 0x68, 0x74, 0x6d, 0x6c, -+ 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2c, 0x20, 0x68, 0x74, 0x6d, -+ 0x6c, 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x75, 0x69, -+ 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x73, -+ 0x65, 0x74, 0x48, 0x74, 0x6d, 0x6c, 0x28, 0x68, 0x74, 0x6d, -+ 0x6c, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x68, -+ 0x74, 0x6d, 0x6c, 0x20, 0x3d, 0x20, 0x68, 0x74, 0x6d, 0x6c, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x65, 0x78, 0x74, 0x20, -+ 0x3d, 0x20, 0x4e, 0x6f, 0x6e, 0x65, 0x0d, 0x0a, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, -+ 0x6c, 0x66, 0x2e, 0x75, 0x69, 0x2e, 0x6d, 0x65, 0x73, 0x73, -+ 0x61, 0x67, 0x65, 0x2e, 0x73, 0x65, 0x74, 0x4c, 0x69, 0x6e, -+ 0x65, 0x57, 0x72, 0x61, 0x70, 0x4d, 0x6f, 0x64, 0x65, 0x28, -+ 0x51, 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, -+ 0x51, 0x54, 0x65, 0x78, 0x74, 0x45, 0x64, 0x69, 0x74, 0x2e, -+ 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x57, 0x69, 0x64, 0x74, -+ 0x68, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x64, 0x65, 0x66, 0x20, 0x73, 0x65, 0x74, 0x5f, 0x6d, 0x65, -+ 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x62, 0x6f, 0x78, 0x5f, -+ 0x69, 0x63, 0x6f, 0x6e, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2c, -+ 0x20, 0x69, 0x63, 0x6f, 0x6e, 0x29, 0x3a, 0x0d, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, -+ 0x66, 0x2e, 0x75, 0x69, 0x2e, 0x69, 0x63, 0x6f, 0x6e, 0x2e, -+ 0x73, 0x65, 0x74, 0x50, 0x69, 0x78, 0x6d, 0x61, 0x70, 0x28, -+ 0x51, 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, -+ 0x51, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x6f, -+ 0x78, 0x2e, 0x73, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, -+ 0x49, 0x63, 0x6f, 0x6e, 0x28, 0x69, 0x63, 0x6f, 0x6e, 0x29, -+ 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, -+ 0x65, 0x66, 0x20, 0x65, 0x78, 0x65, 0x63, 0x28, 0x73, 0x65, -+ 0x6c, 0x66, 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x51, 0x74, 0x43, 0x6f, 0x72, 0x65, -+ 0x2e, 0x51, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x2e, 0x73, 0x69, -+ 0x6e, 0x67, 0x6c, 0x65, 0x53, 0x68, 0x6f, 0x74, 0x28, 0x31, -+ 0x30, 0x2c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x6f, 0x6f, -+ 0x6c, 0x73, 0x2e, 0x70, 0x61, 0x72, 0x74, 0x69, 0x61, 0x6c, -+ 0x28, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, -+ 0x65, 0x6c, 0x66, 0x2e, 0x73, 0x65, 0x74, 0x4d, 0x61, 0x78, -+ 0x69, 0x6d, 0x75, 0x6d, 0x53, 0x69, 0x7a, 0x65, 0x2c, 0x0d, -+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, -+ 0x66, 0x2e, 0x63, 0x61, 0x63, 0x68, 0x65, 0x64, 0x5f, 0x6d, -+ 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x5f, 0x73, 0x69, 0x7a, -+ 0x65, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x29, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, -+ 0x72, 0x6e, 0x20, 0x73, 0x75, 0x70, 0x65, 0x72, 0x28, 0x29, -+ 0x2e, 0x65, 0x78, 0x65, 0x63, 0x28, 0x29, 0x0d, 0x0a, 0x0d, -+ 0x0a, 0x0d, 0x0a, 0x64, 0x65, 0x66, 0x20, 0x64, 0x69, 0x61, -+ 0x6c, 0x6f, 0x67, 0x28, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, -+ 0x2c, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2c, -+ 0x20, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x3d, 0x4e, 0x6f, 0x6e, -+ 0x65, 0x2c, 0x20, 0x69, 0x63, 0x6f, 0x6e, 0x3d, 0x4e, 0x6f, -+ 0x6e, 0x65, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x69, 0x63, 0x68, -+ 0x5f, 0x74, 0x65, 0x78, 0x74, 0x3d, 0x46, 0x61, 0x6c, 0x73, -+ 0x65, 0x2c, 0x20, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, -+ 0x61, 0x62, 0x6c, 0x65, 0x3d, 0x46, 0x61, 0x6c, 0x73, 0x65, -+ 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6f, -+ 0x78, 0x20, 0x3d, 0x20, 0x44, 0x69, 0x61, 0x6c, 0x6f, 0x67, -+ 0x28, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x3d, 0x70, 0x61, -+ 0x72, 0x65, 0x6e, 0x74, 0x2c, 0x20, 0x63, 0x61, 0x6e, 0x63, -+ 0x65, 0x6c, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x3d, 0x63, 0x61, -+ 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x29, -+ 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, -+ 0x20, 0x72, 0x69, 0x63, 0x68, 0x5f, 0x74, 0x65, 0x78, 0x74, -+ 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x62, 0x6f, 0x78, 0x2e, 0x73, 0x65, 0x74, 0x5f, 0x68, -+ 0x74, 0x6d, 0x6c, 0x28, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, -+ 0x65, 0x29, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, -+ 0x73, 0x65, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x62, 0x6f, 0x78, 0x2e, 0x73, 0x65, 0x74, -+ 0x5f, 0x74, 0x65, 0x78, 0x74, 0x28, 0x6d, 0x65, 0x73, 0x73, -+ 0x61, 0x67, 0x65, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x69, 0x66, 0x20, 0x69, 0x63, 0x6f, 0x6e, 0x20, -+ 0x69, 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x4e, 0x6f, 0x6e, -+ 0x65, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x62, 0x6f, 0x78, 0x2e, 0x73, 0x65, 0x74, 0x5f, -+ 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x62, 0x6f, -+ 0x78, 0x5f, 0x69, 0x63, 0x6f, 0x6e, 0x28, 0x69, 0x63, 0x6f, -+ 0x6e, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x69, 0x66, 0x20, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x20, 0x69, -+ 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x4e, 0x6f, 0x6e, 0x65, -+ 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x69, -+ 0x74, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0x51, 0x74, 0x57, 0x69, -+ 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x51, 0x41, 0x70, 0x70, -+ 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x69, -+ 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x28, 0x29, 0x2e, -+ 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, -+ 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x28, 0x29, 0x0d, 0x0a, 0x0d, -+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, -+ 0x66, 0x20, 0x6c, 0x65, 0x6e, 0x28, 0x70, 0x61, 0x72, 0x65, -+ 0x6e, 0x74, 0x5f, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x29, 0x20, -+ 0x3e, 0x20, 0x30, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x69, -+ 0x74, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0x27, 0x20, 0x2d, 0x20, -+ 0x27, 0x2e, 0x6a, 0x6f, 0x69, 0x6e, 0x28, 0x28, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x72, 0x65, -+ 0x6e, 0x74, 0x5f, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x2c, 0x0d, -+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x69, 0x74, -+ 0x6c, 0x65, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x0d, -+ 0x0a, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x62, 0x6f, 0x78, 0x2e, 0x73, 0x65, 0x74, -+ 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x54, 0x69, 0x74, 0x6c, -+ 0x65, 0x28, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x29, 0x0d, 0x0a, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, -+ 0x72, 0x6e, 0x20, 0x62, 0x6f, 0x78, 0x2e, 0x65, 0x78, 0x65, -+ 0x63, 0x28, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x51, 0x74, 0x43, -+ 0x6f, 0x72, 0x65, 0x2e, 0x71, 0x44, 0x65, 0x62, 0x75, 0x67, -+ 0x28, 0x27, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x20, -+ 0x73, 0x79, 0x73, 0x2e, 0x65, 0x78, 0x63, 0x65, 0x70, 0x74, -+ 0x68, 0x6f, 0x6f, 0x6b, 0x20, 0x74, 0x6f, 0x20, 0x70, 0x72, -+ 0x6f, 0x76, 0x69, 0x64, 0x65, 0x20, 0x64, 0x69, 0x61, 0x6c, -+ 0x6f, 0x67, 0x27, 0x29, 0x0d, 0x0a, 0x73, 0x79, 0x73, 0x2e, -+ 0x65, 0x78, 0x63, 0x65, 0x70, 0x74, 0x68, 0x6f, 0x6f, 0x6b, -+ 0x20, 0x3d, 0x20, 0x65, 0x78, 0x63, 0x65, 0x70, 0x74, 0x69, -+ 0x6f, 0x6e, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, -+ 0x5f, 0x62, 0x6f, 0x78, 0x0d, 0x0a, 0x00 -+}; -diff --git a/designer/excepthook.py b/designer/excepthook.py -new file mode 100644 -index 0000000..1c4aaa9 ---- /dev/null -+++ b/designer/excepthook.py -@@ -0,0 +1,170 @@ -+import functools -+import sys -+import traceback -+ -+from PyQt5 import QtCore, QtWidgets -+ -+QtCore.qDebug('Importing module for exception dialogs') -+ -+def exception_message_box(excType=None, excValue=None, tracebackobj=None): -+ message = traceback.format_exception(excType, excValue, tracebackobj) -+ message = ''.join(message) -+ -+ dialog( -+ parent=None, -+ title='Exception', -+ message=message, -+ icon=QtWidgets.QMessageBox.Critical, -+ ) -+ -+class FittedTextBrowser(QtWidgets.QTextBrowser): -+ def sizeHint(self): -+ default = super().sizeHint() -+ -+ if not default.isValid(): -+ return default -+ -+ document_size = self.document().size() -+ -+ desktops = QtWidgets.QApplication.desktop() -+ screen_number = desktops.screenNumber(self.parent()) -+ geometry = desktops.screenGeometry(screen_number) -+ -+ if document_size.width() == 0: -+ document_size.setWidth(geometry.width() * 0.25) -+ if document_size.height() == 0: -+ document_size.setHeight(geometry.height() * 0.4) -+ -+ scrollbar_width = QtWidgets.QApplication.style().pixelMetric( -+ QtWidgets.QStyle.PM_ScrollBarExtent -+ ) -+ -+ width = sum(( -+ document_size.width(), -+ self.contentsMargins().left(), -+ self.contentsMargins().right(), -+ scrollbar_width, -+ )) -+ -+ height = sum(( -+ document_size.height(), -+ self.contentsMargins().top(), -+ self.contentsMargins().bottom(), -+ scrollbar_width, -+ )) -+ -+ return QtCore.QSize(width, height) -+ -+ -+class DialogUi: -+ def __init__(self, parent): -+ self.layout = QtWidgets.QGridLayout(parent) -+ self.icon = QtWidgets.QLabel(parent) -+ self.message = FittedTextBrowser(parent) -+ self.copy = QtWidgets.QPushButton(parent) -+ self.buttons = QtWidgets.QDialogButtonBox(parent) -+ -+ self.copy.setText('Copy To Clipboard') -+ -+ self.layout.addWidget(self.icon, 0, 0) -+ self.layout.addWidget(self.message, 0, 1, 1, 2) -+ self.layout.addWidget(self.copy, 1, 1) -+ self.layout.addWidget(self.buttons, 1, 2) -+ -+ self.layout.setAlignment(self.copy, QtCore.Qt.AlignLeft) -+ -+ self.layout.setRowStretch(0, 1) -+ self.layout.setColumnStretch(1, 1) -+ -+ -+class Dialog(QtWidgets.QDialog): -+ def __init__(self, *args, cancellable=False, **kwargs): -+ super().__init__(*args, **kwargs) -+ -+ self.ui = DialogUi(parent=self) -+ -+ self.ui.buttons.accepted.connect(self.accept) -+ self.ui.buttons.rejected.connect(self.reject) -+ -+ self.ui.copy.clicked.connect(self.copy) -+ -+ self.setLayout(self.ui.layout) -+ buttons = QtWidgets.QDialogButtonBox.Ok -+ if cancellable: -+ buttons |= QtWidgets.QDialogButtonBox.Cancel -+ -+ self.ui.buttons.setStandardButtons(buttons) -+ -+ self.text = None -+ self.html = None -+ -+ self.cached_maximum_size = self.maximumSize() -+ -+ desktops = QtWidgets.QApplication.desktop() -+ screen_number = desktops.screenNumber(self.parent()) -+ geometry = desktops.screenGeometry(screen_number) -+ -+ self.setMaximumHeight(geometry.height() * 0.7) -+ self.setMaximumWidth(geometry.width() * 0.7) -+ -+ def copy(self): -+ QtWidgets.QApplication.clipboard().setText( -+ self.ui.message.toPlainText() + '\\n' -+ ) -+ -+ def set_text(self, text): -+ self.ui.message.setPlainText(text) -+ -+ self.html = None -+ self.text = text -+ -+ self.ui.message.setLineWrapMode(QtWidgets.QTextEdit.NoWrap) -+ -+ def set_html(self, html): -+ self.ui.message.setHtml(html) -+ -+ self.html = html -+ self.text = None -+ -+ self.ui.message.setLineWrapMode(QtWidgets.QTextEdit.WidgetWidth) -+ -+ def set_message_box_icon(self, icon): -+ self.ui.icon.setPixmap(QtWidgets.QMessageBox.standardIcon(icon)) -+ -+ def exec(self): -+ QtCore.QTimer.singleShot(10, functools.partial( -+ self.setMaximumSize, -+ self.cached_maximum_size, -+ )) -+ -+ return super().exec() -+ -+ -+def dialog(parent, message, title=None, icon=None, -+ rich_text=False, cancellable=False): -+ box = Dialog(parent=parent, cancellable=cancellable) -+ -+ if rich_text: -+ box.set_html(message) -+ else: -+ box.set_text(message) -+ -+ if icon is not None: -+ box.set_message_box_icon(icon) -+ -+ if title is not None: -+ parent_title = QtWidgets.QApplication.instance().applicationName() -+ -+ if len(parent_title) > 0: -+ title = ' - '.join(( -+ parent_title, -+ title, -+ )) -+ -+ -+ box.setWindowTitle(title) -+ -+ return box.exec() -+ -+QtCore.qDebug('Setting sys.excepthook to provide dialog') -+sys.excepthook = exception_message_box -diff --git a/designer/generate_module_literal.py b/designer/generate_module_literal.py -new file mode 100644 -index 0000000..cc6b4de ---- /dev/null -+++ b/designer/generate_module_literal.py -@@ -0,0 +1,35 @@ -+import os -+import itertools -+ -+ -+# https://repl.it/IwNE/4 -+def chunker(iterable, n): -+ "Collect data into fixed-length chunks or blocks except last due to lack of fill." -+ # chunker('ABCDEFG', 3) --> ABC DEF G" -+ -+ i = iter(iterable) -+ -+ while True: -+ t = tuple(next(i) for _ in range(n)) -+ -+ if len(t) > 0: -+ yield t -+ else: -+ break -+ -+ -+with open('excepthook.py', 'rb') as f: -+ raw = f.read() -+ -+with open('excepthook.c', 'w', newline='\n') as f: -+ f.write('const char * moduleName = "exceptiondialog";\n\n') -+ f.write('const char moduleCode[] = {\n') -+ -+ indent = ' ' * 4 -+ -+ chunks = chunker(itertools.chain(raw, b'\0'), 10) -+ lines = (', '.join('0x{:02x}'.format(b) for b in chunk) for chunk in chunks) -+ lines = (',\n'.join(indent + line for line in lines)) -+ for line in lines: -+ f.write(line) -+ f.write("\n};\n") -diff --git a/designer/pluginloader.cpp b/designer/pluginloader.cpp -index 87a006c..958f0b5 100644 ---- a/designer/pluginloader.cpp -+++ b/designer/pluginloader.cpp -@@ -25,6 +25,7 @@ - - #include - -+#include - #include - #include - #include -@@ -36,6 +37,114 @@ - - #include "../qpy/QtDesigner/qpydesignercustomwidgetplugin.h" - -+#include "excepthook.c" -+ -+ -+void setupExceptHookDialog(void) -+{ -+ qDebug() << "Preparing to import module"; -+ qDebug() << PyBytes_AS_STRING(PyUnicode_AsEncodedString(PyObject_Str(PySys_GetObject("path")), "utf-8", "error 1?")); -+ // https://stackoverflow.com/a/42853449/228539 -+ PyObject *pyModule = PyModule_New(moduleName); -+ // Set properties on the new module object -+ PyModule_AddStringConstant(pyModule, "__file__", ""); -+ PyObject *localDict = PyModule_GetDict(pyModule); // Returns a borrowed reference: no need to Py_DECREF() it once we are done -+ PyObject *builtins = PyEval_GetBuiltins(); // Returns a borrowed reference: no need to Py_DECREF() it once we are done -+ PyDict_SetItemString(localDict, "__builtins__", builtins); -+ -+ qDebug() << "About to import module"; -+ -+ // Define code in the newly created module -+ PyObject *pyValue = PyRun_String(moduleCode, Py_file_input, localDict, localDict); -+ qDebug() << "Code just run"; -+ if (pyValue == NULL) -+ { -+ qDebug() << "An error occurred while importing the module"; -+ -+ char * full_backtrace = NULL; -+ -+ if (PyErr_Occurred() != NULL) { -+ qDebug() << "PyErr_Occurred() != NULL"; -+ PyObject *ptype, *pvalue, *ptraceback; -+ PyObject *pystr, *module_name, *pyth_module, *pyth_func; -+ char *str; -+ char *error_description; -+ -+ PyErr_Fetch(&ptype, &pvalue, &ptraceback); -+ qDebug() << "ptype == NULL : " << (ptype == NULL); -+ qDebug() << "pvalue == NULL : " << (pvalue == NULL); -+ qDebug() << "ptraceback == NULL : " << (ptraceback == NULL); -+ pystr = PyObject_Str(pvalue); -+ qDebug() << "pystr == NULL : " << (pystr == NULL); -+ pystr = PyUnicode_AsEncodedString(pystr, "utf-8", "error 1?"); -+ qDebug() << "pystr == NULL : " << (pystr == NULL); -+ str = PyBytes_AS_STRING(pystr); -+ qDebug() << "str == NULL : " << (str == NULL); -+ if (str != NULL) -+ { -+ qDebug() << "str: " << str; -+ } -+ Py_DECREF(pystr); -+ error_description = strdup(str); -+ qDebug() << "error_description == NULL : " << (error_description == NULL); -+ if (error_description != NULL) -+ { -+ qDebug() << "error_description: " << error_description; -+ } -+ -+ /* See if we can get a full traceback */ -+ module_name = PyUnicode_Decode("traceback", 9, "utf-8", "error 2?"); -+ pyth_module = PyImport_Import(module_name); -+ Py_DECREF(module_name); -+ -+ qDebug() << "pyth_module == NULL : " << (pyth_module == NULL); -+ if (pyth_module == NULL) { -+ full_backtrace = NULL; -+ return; -+ } -+ -+ pyth_func = PyObject_GetAttrString(pyth_module, "format_exception"); -+ if (pyth_func && PyCallable_Check(pyth_func)) -+ { -+ qDebug() << "pyth_func && PyCallable_Check(pyth_func)"; -+ PyObject *pyth_val; -+ -+ pyth_val = PyObject_CallFunctionObjArgs(pyth_func, ptype, pvalue, ptraceback, Py_None, Py_True, NULL); -+ qDebug() << "pyth_val == NULL : " << (pyth_val == NULL); -+ -+ pystr = PyObject_Str(pyth_val); -+ qDebug() << "pystr == NULL : " << (pystr == NULL); -+ -+ pystr = PyUnicode_AsEncodedString(pystr, "utf-8", "error 3?"); -+ qDebug() << "pystr == NULL : " << (pystr == NULL); -+ -+ str = PyBytes_AS_STRING(pystr); -+ qDebug() << "str == NULL : " << (str == NULL); -+ -+ Py_DECREF(pystr); -+ full_backtrace = strdup(str); -+ Py_DECREF(pyth_val); -+ } -+ } -+ -+ if (full_backtrace != NULL) -+ { -+ qDebug() << "About to print backtrace"; -+ qDebug() << full_backtrace; -+ } -+ else -+ { -+ qDebug() << "Backtrace was NULL"; -+ } -+ } -+ else -+ { -+ qDebug() << "About to decref"; -+ Py_DECREF(pyValue); -+ } -+ -+ qDebug() << "Done importing module"; -+} - - // Construct the collection of Python widgets. - PyCustomWidgets::PyCustomWidgets(QObject *parent) : QObject(parent), -@@ -140,6 +249,7 @@ PyCustomWidgets::PyCustomWidgets(QObject *parent) : QObject(parent), - PyGILState_STATE gil_state = PyGILState_Ensure(); - #endif - -+ setupExceptHookDialog(); - bool fatal = importPlugins(dir, plugins); - - #if defined(WITH_THREAD) diff --git a/pluginloader.5.14.1.patch b/pluginloader.5.14.1.patch deleted file mode 100644 index 0af856245..000000000 --- a/pluginloader.5.14.1.patch +++ /dev/null @@ -1,858 +0,0 @@ -diff --git a/designer/excepthook.c b/designer/excepthook.c -new file mode 100644 -index 0000000..6a575af ---- /dev/null -+++ b/designer/excepthook.c -@@ -0,0 +1,500 @@ -+const char * moduleName = "exceptiondialog"; -+ -+const char moduleCode[] = { -+ 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x66, 0x75, 0x6e, -+ 0x63, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x0d, 0x0a, 0x69, 0x6d, -+ 0x70, 0x6f, 0x72, 0x74, 0x20, 0x73, 0x79, 0x73, 0x0d, 0x0a, -+ 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x74, 0x72, 0x61, -+ 0x63, 0x65, 0x62, 0x61, 0x63, 0x6b, 0x0d, 0x0a, 0x0d, 0x0a, -+ 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x50, 0x79, 0x51, 0x74, 0x35, -+ 0x20, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x51, 0x74, -+ 0x43, 0x6f, 0x72, 0x65, 0x2c, 0x20, 0x51, 0x74, 0x57, 0x69, -+ 0x64, 0x67, 0x65, 0x74, 0x73, 0x0d, 0x0a, 0x0d, 0x0a, 0x51, -+ 0x74, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x71, 0x44, 0x65, 0x62, -+ 0x75, 0x67, 0x28, 0x27, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, -+ 0x69, 0x6e, 0x67, 0x20, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, -+ 0x20, 0x66, 0x6f, 0x72, 0x20, 0x65, 0x78, 0x63, 0x65, 0x70, -+ 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x64, 0x69, 0x61, 0x6c, 0x6f, -+ 0x67, 0x73, 0x27, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x64, 0x65, -+ 0x66, 0x20, 0x65, 0x78, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6f, -+ 0x6e, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, -+ 0x62, 0x6f, 0x78, 0x28, 0x65, 0x78, 0x63, 0x54, 0x79, 0x70, -+ 0x65, 0x3d, 0x4e, 0x6f, 0x6e, 0x65, 0x2c, 0x20, 0x65, 0x78, -+ 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x3d, 0x4e, 0x6f, 0x6e, -+ 0x65, 0x2c, 0x20, 0x74, 0x72, 0x61, 0x63, 0x65, 0x62, 0x61, -+ 0x63, 0x6b, 0x6f, 0x62, 0x6a, 0x3d, 0x4e, 0x6f, 0x6e, 0x65, -+ 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x65, -+ 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x3d, 0x20, 0x74, 0x72, -+ 0x61, 0x63, 0x65, 0x62, 0x61, 0x63, 0x6b, 0x2e, 0x66, 0x6f, -+ 0x72, 0x6d, 0x61, 0x74, 0x5f, 0x65, 0x78, 0x63, 0x65, 0x70, -+ 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x65, 0x78, 0x63, 0x54, 0x79, -+ 0x70, 0x65, 0x2c, 0x20, 0x65, 0x78, 0x63, 0x56, 0x61, 0x6c, -+ 0x75, 0x65, 0x2c, 0x20, 0x74, 0x72, 0x61, 0x63, 0x65, 0x62, -+ 0x61, 0x63, 0x6b, 0x6f, 0x62, 0x6a, 0x29, 0x0d, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, -+ 0x20, 0x3d, 0x20, 0x27, 0x27, 0x2e, 0x6a, 0x6f, 0x69, 0x6e, -+ 0x28, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x29, 0x0d, -+ 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x69, 0x61, -+ 0x6c, 0x6f, 0x67, 0x28, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, -+ 0x3d, 0x4e, 0x6f, 0x6e, 0x65, 0x2c, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x69, 0x74, 0x6c, -+ 0x65, 0x3d, 0x27, 0x45, 0x78, 0x63, 0x65, 0x70, 0x74, 0x69, -+ 0x6f, 0x6e, 0x27, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, -+ 0x65, 0x3d, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2c, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x69, 0x63, 0x6f, 0x6e, 0x3d, 0x51, 0x74, 0x57, 0x69, 0x64, -+ 0x67, 0x65, 0x74, 0x73, 0x2e, 0x51, 0x4d, 0x65, 0x73, 0x73, -+ 0x61, 0x67, 0x65, 0x42, 0x6f, 0x78, 0x2e, 0x43, 0x72, 0x69, -+ 0x74, 0x69, 0x63, 0x61, 0x6c, 0x2c, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x63, 0x6c, 0x61, -+ 0x73, 0x73, 0x20, 0x46, 0x69, 0x74, 0x74, 0x65, 0x64, 0x54, -+ 0x65, 0x78, 0x74, 0x42, 0x72, 0x6f, 0x77, 0x73, 0x65, 0x72, -+ 0x28, 0x51, 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, -+ 0x2e, 0x51, 0x54, 0x65, 0x78, 0x74, 0x42, 0x72, 0x6f, 0x77, -+ 0x73, 0x65, 0x72, 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, -+ 0x20, 0x64, 0x65, 0x66, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x48, -+ 0x69, 0x6e, 0x74, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x29, 0x3a, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x20, 0x3d, 0x20, -+ 0x73, 0x75, 0x70, 0x65, 0x72, 0x28, 0x29, 0x2e, 0x73, 0x69, -+ 0x7a, 0x65, 0x48, 0x69, 0x6e, 0x74, 0x28, 0x29, 0x0d, 0x0a, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x64, 0x65, 0x66, -+ 0x61, 0x75, 0x6c, 0x74, 0x2e, 0x69, 0x73, 0x56, 0x61, 0x6c, -+ 0x69, 0x64, 0x28, 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, -+ 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x64, 0x65, 0x66, 0x61, -+ 0x75, 0x6c, 0x74, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, -+ 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x3d, -+ 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x64, 0x6f, 0x63, 0x75, -+ 0x6d, 0x65, 0x6e, 0x74, 0x28, 0x29, 0x2e, 0x73, 0x69, 0x7a, -+ 0x65, 0x28, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x73, 0x6b, 0x74, -+ 0x6f, 0x70, 0x73, 0x20, 0x3d, 0x20, 0x51, 0x74, 0x57, 0x69, -+ 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x51, 0x41, 0x70, 0x70, -+ 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x64, -+ 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x28, 0x29, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x63, -+ 0x72, 0x65, 0x65, 0x6e, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, -+ 0x72, 0x20, 0x3d, 0x20, 0x64, 0x65, 0x73, 0x6b, 0x74, 0x6f, -+ 0x70, 0x73, 0x2e, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x4e, -+ 0x75, 0x6d, 0x62, 0x65, 0x72, 0x28, 0x73, 0x65, 0x6c, 0x66, -+ 0x2e, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x28, 0x29, 0x29, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x67, 0x65, 0x6f, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x20, 0x3d, -+ 0x20, 0x64, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x73, 0x2e, -+ 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x47, 0x65, 0x6f, 0x6d, -+ 0x65, 0x74, 0x72, 0x79, 0x28, 0x73, 0x63, 0x72, 0x65, 0x65, -+ 0x6e, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x29, 0x0d, -+ 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x69, 0x66, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, -+ 0x6e, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x2e, 0x77, 0x69, -+ 0x64, 0x74, 0x68, 0x28, 0x29, 0x20, 0x3d, 0x3d, 0x20, 0x30, -+ 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, -+ 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x2e, 0x73, -+ 0x65, 0x74, 0x57, 0x69, 0x64, 0x74, 0x68, 0x28, 0x67, 0x65, -+ 0x6f, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x77, 0x69, 0x64, -+ 0x74, 0x68, 0x28, 0x29, 0x20, 0x2a, 0x20, 0x30, 0x2e, 0x32, -+ 0x35, 0x29, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x69, 0x66, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, -+ 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x2e, 0x68, -+ 0x65, 0x69, 0x67, 0x68, 0x74, 0x28, 0x29, 0x20, 0x3d, 0x3d, -+ 0x20, 0x30, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, 0x63, -+ 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, -+ 0x2e, 0x73, 0x65, 0x74, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, -+ 0x28, 0x67, 0x65, 0x6f, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, -+ 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x28, 0x29, 0x20, 0x2a, -+ 0x20, 0x30, 0x2e, 0x34, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x63, 0x72, -+ 0x6f, 0x6c, 0x6c, 0x62, 0x61, 0x72, 0x5f, 0x77, 0x69, 0x64, -+ 0x74, 0x68, 0x20, 0x3d, 0x20, 0x51, 0x74, 0x57, 0x69, 0x64, -+ 0x67, 0x65, 0x74, 0x73, 0x2e, 0x51, 0x41, 0x70, 0x70, 0x6c, -+ 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x73, 0x74, -+ 0x79, 0x6c, 0x65, 0x28, 0x29, 0x2e, 0x70, 0x69, 0x78, 0x65, -+ 0x6c, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x28, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x51, 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, -+ 0x73, 0x2e, 0x51, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x2e, 0x50, -+ 0x4d, 0x5f, 0x53, 0x63, 0x72, 0x6f, 0x6c, 0x6c, 0x42, 0x61, -+ 0x72, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x74, 0x0d, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x0d, 0x0a, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x77, 0x69, 0x64, 0x74, 0x68, 0x20, 0x3d, 0x20, 0x73, 0x75, -+ 0x6d, 0x28, 0x28, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, 0x63, -+ 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, -+ 0x2e, 0x77, 0x69, 0x64, 0x74, 0x68, 0x28, 0x29, 0x2c, 0x0d, -+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x63, 0x6f, -+ 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x4d, 0x61, 0x72, 0x67, -+ 0x69, 0x6e, 0x73, 0x28, 0x29, 0x2e, 0x6c, 0x65, 0x66, 0x74, -+ 0x28, 0x29, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, -+ 0x66, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, -+ 0x4d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x73, 0x28, 0x29, 0x2e, -+ 0x72, 0x69, 0x67, 0x68, 0x74, 0x28, 0x29, 0x2c, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x73, 0x63, 0x72, 0x6f, 0x6c, 0x6c, 0x62, 0x61, -+ 0x72, 0x5f, 0x77, 0x69, 0x64, 0x74, 0x68, 0x2c, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, -+ 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x20, 0x3d, -+ 0x20, 0x73, 0x75, 0x6d, 0x28, 0x28, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x73, -+ 0x69, 0x7a, 0x65, 0x2e, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, -+ 0x28, 0x29, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, -+ 0x66, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, -+ 0x4d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x73, 0x28, 0x29, 0x2e, -+ 0x74, 0x6f, 0x70, 0x28, 0x29, 0x2c, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, -+ 0x6e, 0x74, 0x73, 0x4d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x73, -+ 0x28, 0x29, 0x2e, 0x62, 0x6f, 0x74, 0x74, 0x6f, 0x6d, 0x28, -+ 0x29, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x63, 0x72, 0x6f, -+ 0x6c, 0x6c, 0x62, 0x61, 0x72, 0x5f, 0x77, 0x69, 0x64, 0x74, -+ 0x68, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x29, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, -+ 0x72, 0x6e, 0x20, 0x51, 0x74, 0x43, 0x6f, 0x72, 0x65, 0x2e, -+ 0x51, 0x53, 0x69, 0x7a, 0x65, 0x28, 0x77, 0x69, 0x64, 0x74, -+ 0x68, 0x2c, 0x20, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x29, -+ 0x0d, 0x0a, 0x0d, 0x0a, 0x0d, 0x0a, 0x63, 0x6c, 0x61, 0x73, -+ 0x73, 0x20, 0x44, 0x69, 0x61, 0x6c, 0x6f, 0x67, 0x55, 0x69, -+ 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x66, -+ 0x20, 0x5f, 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x5f, 0x5f, 0x28, -+ 0x73, 0x65, 0x6c, 0x66, 0x2c, 0x20, 0x70, 0x61, 0x72, 0x65, -+ 0x6e, 0x74, 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x6c, -+ 0x61, 0x79, 0x6f, 0x75, 0x74, 0x20, 0x3d, 0x20, 0x51, 0x74, -+ 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x51, 0x47, -+ 0x72, 0x69, 0x64, 0x4c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x28, -+ 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x29, 0x0d, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, -+ 0x66, 0x2e, 0x69, 0x63, 0x6f, 0x6e, 0x20, 0x3d, 0x20, 0x51, -+ 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x51, -+ 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x28, 0x70, 0x61, 0x72, 0x65, -+ 0x6e, 0x74, 0x29, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x6d, 0x65, -+ 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x3d, 0x20, 0x46, 0x69, -+ 0x74, 0x74, 0x65, 0x64, 0x54, 0x65, 0x78, 0x74, 0x42, 0x72, -+ 0x6f, 0x77, 0x73, 0x65, 0x72, 0x28, 0x70, 0x61, 0x72, 0x65, -+ 0x6e, 0x74, 0x29, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x63, 0x6f, -+ 0x70, 0x79, 0x20, 0x3d, 0x20, 0x51, 0x74, 0x57, 0x69, 0x64, -+ 0x67, 0x65, 0x74, 0x73, 0x2e, 0x51, 0x50, 0x75, 0x73, 0x68, -+ 0x42, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x28, 0x70, 0x61, 0x72, -+ 0x65, 0x6e, 0x74, 0x29, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x62, -+ 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x73, 0x20, 0x3d, 0x20, 0x51, -+ 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x51, -+ 0x44, 0x69, 0x61, 0x6c, 0x6f, 0x67, 0x42, 0x75, 0x74, 0x74, -+ 0x6f, 0x6e, 0x42, 0x6f, 0x78, 0x28, 0x70, 0x61, 0x72, 0x65, -+ 0x6e, 0x74, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, -+ 0x63, 0x6f, 0x70, 0x79, 0x2e, 0x73, 0x65, 0x74, 0x54, 0x65, -+ 0x78, 0x74, 0x28, 0x27, 0x43, 0x6f, 0x70, 0x79, 0x20, 0x54, -+ 0x6f, 0x20, 0x43, 0x6c, 0x69, 0x70, 0x62, 0x6f, 0x61, 0x72, -+ 0x64, 0x27, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, -+ 0x6c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x2e, 0x61, 0x64, 0x64, -+ 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x28, 0x73, 0x65, 0x6c, -+ 0x66, 0x2e, 0x69, 0x63, 0x6f, 0x6e, 0x2c, 0x20, 0x30, 0x2c, -+ 0x20, 0x30, 0x29, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x6c, 0x61, -+ 0x79, 0x6f, 0x75, 0x74, 0x2e, 0x61, 0x64, 0x64, 0x57, 0x69, -+ 0x64, 0x67, 0x65, 0x74, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, -+ 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2c, 0x20, 0x30, -+ 0x2c, 0x20, 0x31, 0x2c, 0x20, 0x31, 0x2c, 0x20, 0x32, 0x29, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x6c, 0x61, 0x79, 0x6f, 0x75, -+ 0x74, 0x2e, 0x61, 0x64, 0x64, 0x57, 0x69, 0x64, 0x67, 0x65, -+ 0x74, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x63, 0x6f, 0x70, -+ 0x79, 0x2c, 0x20, 0x31, 0x2c, 0x20, 0x31, 0x29, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, -+ 0x6c, 0x66, 0x2e, 0x6c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x2e, -+ 0x61, 0x64, 0x64, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x28, -+ 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x62, 0x75, 0x74, 0x74, 0x6f, -+ 0x6e, 0x73, 0x2c, 0x20, 0x31, 0x2c, 0x20, 0x32, 0x29, 0x0d, -+ 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x6c, 0x61, 0x79, 0x6f, -+ 0x75, 0x74, 0x2e, 0x73, 0x65, 0x74, 0x41, 0x6c, 0x69, 0x67, -+ 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x28, 0x73, 0x65, 0x6c, 0x66, -+ 0x2e, 0x63, 0x6f, 0x70, 0x79, 0x2c, 0x20, 0x51, 0x74, 0x43, -+ 0x6f, 0x72, 0x65, 0x2e, 0x51, 0x74, 0x2e, 0x41, 0x6c, 0x69, -+ 0x67, 0x6e, 0x4c, 0x65, 0x66, 0x74, 0x29, 0x0d, 0x0a, 0x0d, -+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, -+ 0x65, 0x6c, 0x66, 0x2e, 0x6c, 0x61, 0x79, 0x6f, 0x75, 0x74, -+ 0x2e, 0x73, 0x65, 0x74, 0x52, 0x6f, 0x77, 0x53, 0x74, 0x72, -+ 0x65, 0x74, 0x63, 0x68, 0x28, 0x30, 0x2c, 0x20, 0x31, 0x29, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x6c, 0x61, 0x79, 0x6f, 0x75, -+ 0x74, 0x2e, 0x73, 0x65, 0x74, 0x43, 0x6f, 0x6c, 0x75, 0x6d, -+ 0x6e, 0x53, 0x74, 0x72, 0x65, 0x74, 0x63, 0x68, 0x28, 0x31, -+ 0x2c, 0x20, 0x31, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x0d, 0x0a, -+ 0x63, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x44, 0x69, 0x61, 0x6c, -+ 0x6f, 0x67, 0x28, 0x51, 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, -+ 0x74, 0x73, 0x2e, 0x51, 0x44, 0x69, 0x61, 0x6c, 0x6f, 0x67, -+ 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, -+ 0x66, 0x20, 0x5f, 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x5f, 0x5f, -+ 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2c, 0x20, 0x2a, 0x61, 0x72, -+ 0x67, 0x73, 0x2c, 0x20, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, -+ 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x3d, 0x46, 0x61, 0x6c, 0x73, -+ 0x65, 0x2c, 0x20, 0x2a, 0x2a, 0x6b, 0x77, 0x61, 0x72, 0x67, -+ 0x73, 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x73, 0x75, 0x70, 0x65, 0x72, 0x28, 0x29, -+ 0x2e, 0x5f, 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x5f, 0x5f, 0x28, -+ 0x2a, 0x61, 0x72, 0x67, 0x73, 0x2c, 0x20, 0x2a, 0x2a, 0x6b, -+ 0x77, 0x61, 0x72, 0x67, 0x73, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, -+ 0x6c, 0x66, 0x2e, 0x75, 0x69, 0x20, 0x3d, 0x20, 0x44, 0x69, -+ 0x61, 0x6c, 0x6f, 0x67, 0x55, 0x69, 0x28, 0x70, 0x61, 0x72, -+ 0x65, 0x6e, 0x74, 0x3d, 0x73, 0x65, 0x6c, 0x66, 0x29, 0x0d, -+ 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x75, 0x69, 0x2e, 0x62, -+ 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x73, 0x2e, 0x61, 0x63, 0x63, -+ 0x65, 0x70, 0x74, 0x65, 0x64, 0x2e, 0x63, 0x6f, 0x6e, 0x6e, -+ 0x65, 0x63, 0x74, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x61, -+ 0x63, 0x63, 0x65, 0x70, 0x74, 0x29, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, -+ 0x2e, 0x75, 0x69, 0x2e, 0x62, 0x75, 0x74, 0x74, 0x6f, 0x6e, -+ 0x73, 0x2e, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x65, 0x64, -+ 0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x28, 0x73, -+ 0x65, 0x6c, 0x66, 0x2e, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, -+ 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x75, 0x69, -+ 0x2e, 0x63, 0x6f, 0x70, 0x79, 0x2e, 0x63, 0x6c, 0x69, 0x63, -+ 0x6b, 0x65, 0x64, 0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, -+ 0x74, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x63, 0x6f, 0x70, -+ 0x79, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x73, -+ 0x65, 0x74, 0x4c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x28, 0x73, -+ 0x65, 0x6c, 0x66, 0x2e, 0x75, 0x69, 0x2e, 0x6c, 0x61, 0x79, -+ 0x6f, 0x75, 0x74, 0x29, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x62, 0x75, 0x74, 0x74, 0x6f, 0x6e, -+ 0x73, 0x20, 0x3d, 0x20, 0x51, 0x74, 0x57, 0x69, 0x64, 0x67, -+ 0x65, 0x74, 0x73, 0x2e, 0x51, 0x44, 0x69, 0x61, 0x6c, 0x6f, -+ 0x67, 0x42, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x42, 0x6f, 0x78, -+ 0x2e, 0x4f, 0x6b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x63, 0x61, 0x6e, 0x63, -+ 0x65, 0x6c, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x3a, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x62, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x73, 0x20, -+ 0x7c, 0x3d, 0x20, 0x51, 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, -+ 0x74, 0x73, 0x2e, 0x51, 0x44, 0x69, 0x61, 0x6c, 0x6f, 0x67, -+ 0x42, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x42, 0x6f, 0x78, 0x2e, -+ 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x0d, 0x0a, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, -+ 0x6c, 0x66, 0x2e, 0x75, 0x69, 0x2e, 0x62, 0x75, 0x74, 0x74, -+ 0x6f, 0x6e, 0x73, 0x2e, 0x73, 0x65, 0x74, 0x53, 0x74, 0x61, -+ 0x6e, 0x64, 0x61, 0x72, 0x64, 0x42, 0x75, 0x74, 0x74, 0x6f, -+ 0x6e, 0x73, 0x28, 0x62, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x73, -+ 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x65, -+ 0x78, 0x74, 0x20, 0x3d, 0x20, 0x4e, 0x6f, 0x6e, 0x65, 0x0d, -+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, -+ 0x65, 0x6c, 0x66, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x20, 0x3d, -+ 0x20, 0x4e, 0x6f, 0x6e, 0x65, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, -+ 0x66, 0x2e, 0x63, 0x61, 0x63, 0x68, 0x65, 0x64, 0x5f, 0x6d, -+ 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x5f, 0x73, 0x69, 0x7a, -+ 0x65, 0x20, 0x3d, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x6d, -+ 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x53, 0x69, 0x7a, 0x65, -+ 0x28, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x73, 0x6b, 0x74, 0x6f, -+ 0x70, 0x73, 0x20, 0x3d, 0x20, 0x51, 0x74, 0x57, 0x69, 0x64, -+ 0x67, 0x65, 0x74, 0x73, 0x2e, 0x51, 0x41, 0x70, 0x70, 0x6c, -+ 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x64, 0x65, -+ 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x28, 0x29, 0x0d, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x63, 0x72, -+ 0x65, 0x65, 0x6e, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, -+ 0x20, 0x3d, 0x20, 0x64, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, -+ 0x73, 0x2e, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x4e, 0x75, -+ 0x6d, 0x62, 0x65, 0x72, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, -+ 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x28, 0x29, 0x29, 0x0d, -+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x67, -+ 0x65, 0x6f, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x20, 0x3d, 0x20, -+ 0x64, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x73, 0x2e, 0x73, -+ 0x63, 0x72, 0x65, 0x65, 0x6e, 0x47, 0x65, 0x6f, 0x6d, 0x65, -+ 0x74, 0x72, 0x79, 0x28, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, -+ 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x29, 0x0d, 0x0a, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x73, 0x65, 0x74, 0x4d, 0x61, -+ 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x48, 0x65, 0x69, 0x67, 0x68, -+ 0x74, 0x28, 0x67, 0x65, 0x6f, 0x6d, 0x65, 0x74, 0x72, 0x79, -+ 0x2e, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x28, 0x29, 0x20, -+ 0x2a, 0x20, 0x30, 0x2e, 0x37, 0x29, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, -+ 0x2e, 0x73, 0x65, 0x74, 0x4d, 0x61, 0x78, 0x69, 0x6d, 0x75, -+ 0x6d, 0x57, 0x69, 0x64, 0x74, 0x68, 0x28, 0x67, 0x65, 0x6f, -+ 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x77, 0x69, 0x64, 0x74, -+ 0x68, 0x28, 0x29, 0x20, 0x2a, 0x20, 0x30, 0x2e, 0x37, 0x29, -+ 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, -+ 0x66, 0x20, 0x63, 0x6f, 0x70, 0x79, 0x28, 0x73, 0x65, 0x6c, -+ 0x66, 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x51, 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, -+ 0x74, 0x73, 0x2e, 0x51, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, -+ 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x63, 0x6c, 0x69, 0x70, -+ 0x62, 0x6f, 0x61, 0x72, 0x64, 0x28, 0x29, 0x2e, 0x73, 0x65, -+ 0x74, 0x54, 0x65, 0x78, 0x74, 0x28, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x75, 0x69, 0x2e, 0x6d, 0x65, -+ 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x74, 0x6f, 0x50, 0x6c, -+ 0x61, 0x69, 0x6e, 0x54, 0x65, 0x78, 0x74, 0x28, 0x29, 0x20, -+ 0x2b, 0x20, 0x27, 0x5c, 0x5c, 0x6e, 0x27, 0x0d, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x0d, 0x0a, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x66, 0x20, -+ 0x73, 0x65, 0x74, 0x5f, 0x74, 0x65, 0x78, 0x74, 0x28, 0x73, -+ 0x65, 0x6c, 0x66, 0x2c, 0x20, 0x74, 0x65, 0x78, 0x74, 0x29, -+ 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x75, 0x69, 0x2e, 0x6d, -+ 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x73, 0x65, 0x74, -+ 0x50, 0x6c, 0x61, 0x69, 0x6e, 0x54, 0x65, 0x78, 0x74, 0x28, -+ 0x74, 0x65, 0x78, 0x74, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, -+ 0x66, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x20, 0x3d, 0x20, 0x4e, -+ 0x6f, 0x6e, 0x65, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x65, -+ 0x78, 0x74, 0x20, 0x3d, 0x20, 0x74, 0x65, 0x78, 0x74, 0x0d, -+ 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x75, 0x69, 0x2e, 0x6d, -+ 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x73, 0x65, 0x74, -+ 0x4c, 0x69, 0x6e, 0x65, 0x57, 0x72, 0x61, 0x70, 0x4d, 0x6f, -+ 0x64, 0x65, 0x28, 0x51, 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, -+ 0x74, 0x73, 0x2e, 0x51, 0x54, 0x65, 0x78, 0x74, 0x45, 0x64, -+ 0x69, 0x74, 0x2e, 0x4e, 0x6f, 0x57, 0x72, 0x61, 0x70, 0x29, -+ 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, -+ 0x66, 0x20, 0x73, 0x65, 0x74, 0x5f, 0x68, 0x74, 0x6d, 0x6c, -+ 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2c, 0x20, 0x68, 0x74, 0x6d, -+ 0x6c, 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x75, 0x69, -+ 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x73, -+ 0x65, 0x74, 0x48, 0x74, 0x6d, 0x6c, 0x28, 0x68, 0x74, 0x6d, -+ 0x6c, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x68, -+ 0x74, 0x6d, 0x6c, 0x20, 0x3d, 0x20, 0x68, 0x74, 0x6d, 0x6c, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x65, 0x78, 0x74, 0x20, -+ 0x3d, 0x20, 0x4e, 0x6f, 0x6e, 0x65, 0x0d, 0x0a, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, -+ 0x6c, 0x66, 0x2e, 0x75, 0x69, 0x2e, 0x6d, 0x65, 0x73, 0x73, -+ 0x61, 0x67, 0x65, 0x2e, 0x73, 0x65, 0x74, 0x4c, 0x69, 0x6e, -+ 0x65, 0x57, 0x72, 0x61, 0x70, 0x4d, 0x6f, 0x64, 0x65, 0x28, -+ 0x51, 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, -+ 0x51, 0x54, 0x65, 0x78, 0x74, 0x45, 0x64, 0x69, 0x74, 0x2e, -+ 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x57, 0x69, 0x64, 0x74, -+ 0x68, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x64, 0x65, 0x66, 0x20, 0x73, 0x65, 0x74, 0x5f, 0x6d, 0x65, -+ 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x62, 0x6f, 0x78, 0x5f, -+ 0x69, 0x63, 0x6f, 0x6e, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2c, -+ 0x20, 0x69, 0x63, 0x6f, 0x6e, 0x29, 0x3a, 0x0d, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, -+ 0x66, 0x2e, 0x75, 0x69, 0x2e, 0x69, 0x63, 0x6f, 0x6e, 0x2e, -+ 0x73, 0x65, 0x74, 0x50, 0x69, 0x78, 0x6d, 0x61, 0x70, 0x28, -+ 0x51, 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, -+ 0x51, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x6f, -+ 0x78, 0x2e, 0x73, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, -+ 0x49, 0x63, 0x6f, 0x6e, 0x28, 0x69, 0x63, 0x6f, 0x6e, 0x29, -+ 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, -+ 0x65, 0x66, 0x20, 0x65, 0x78, 0x65, 0x63, 0x28, 0x73, 0x65, -+ 0x6c, 0x66, 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x51, 0x74, 0x43, 0x6f, 0x72, 0x65, -+ 0x2e, 0x51, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x2e, 0x73, 0x69, -+ 0x6e, 0x67, 0x6c, 0x65, 0x53, 0x68, 0x6f, 0x74, 0x28, 0x31, -+ 0x30, 0x2c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x6f, 0x6f, -+ 0x6c, 0x73, 0x2e, 0x70, 0x61, 0x72, 0x74, 0x69, 0x61, 0x6c, -+ 0x28, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, -+ 0x65, 0x6c, 0x66, 0x2e, 0x73, 0x65, 0x74, 0x4d, 0x61, 0x78, -+ 0x69, 0x6d, 0x75, 0x6d, 0x53, 0x69, 0x7a, 0x65, 0x2c, 0x0d, -+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, -+ 0x66, 0x2e, 0x63, 0x61, 0x63, 0x68, 0x65, 0x64, 0x5f, 0x6d, -+ 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x5f, 0x73, 0x69, 0x7a, -+ 0x65, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x29, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, -+ 0x72, 0x6e, 0x20, 0x73, 0x75, 0x70, 0x65, 0x72, 0x28, 0x29, -+ 0x2e, 0x65, 0x78, 0x65, 0x63, 0x28, 0x29, 0x0d, 0x0a, 0x0d, -+ 0x0a, 0x0d, 0x0a, 0x64, 0x65, 0x66, 0x20, 0x64, 0x69, 0x61, -+ 0x6c, 0x6f, 0x67, 0x28, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, -+ 0x2c, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2c, -+ 0x20, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x3d, 0x4e, 0x6f, 0x6e, -+ 0x65, 0x2c, 0x20, 0x69, 0x63, 0x6f, 0x6e, 0x3d, 0x4e, 0x6f, -+ 0x6e, 0x65, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x69, 0x63, 0x68, -+ 0x5f, 0x74, 0x65, 0x78, 0x74, 0x3d, 0x46, 0x61, 0x6c, 0x73, -+ 0x65, 0x2c, 0x20, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, -+ 0x61, 0x62, 0x6c, 0x65, 0x3d, 0x46, 0x61, 0x6c, 0x73, 0x65, -+ 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6f, -+ 0x78, 0x20, 0x3d, 0x20, 0x44, 0x69, 0x61, 0x6c, 0x6f, 0x67, -+ 0x28, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x3d, 0x70, 0x61, -+ 0x72, 0x65, 0x6e, 0x74, 0x2c, 0x20, 0x63, 0x61, 0x6e, 0x63, -+ 0x65, 0x6c, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x3d, 0x63, 0x61, -+ 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x29, -+ 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, -+ 0x20, 0x72, 0x69, 0x63, 0x68, 0x5f, 0x74, 0x65, 0x78, 0x74, -+ 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x62, 0x6f, 0x78, 0x2e, 0x73, 0x65, 0x74, 0x5f, 0x68, -+ 0x74, 0x6d, 0x6c, 0x28, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, -+ 0x65, 0x29, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, -+ 0x73, 0x65, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x62, 0x6f, 0x78, 0x2e, 0x73, 0x65, 0x74, -+ 0x5f, 0x74, 0x65, 0x78, 0x74, 0x28, 0x6d, 0x65, 0x73, 0x73, -+ 0x61, 0x67, 0x65, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x69, 0x66, 0x20, 0x69, 0x63, 0x6f, 0x6e, 0x20, -+ 0x69, 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x4e, 0x6f, 0x6e, -+ 0x65, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x62, 0x6f, 0x78, 0x2e, 0x73, 0x65, 0x74, 0x5f, -+ 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x62, 0x6f, -+ 0x78, 0x5f, 0x69, 0x63, 0x6f, 0x6e, 0x28, 0x69, 0x63, 0x6f, -+ 0x6e, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x69, 0x66, 0x20, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x20, 0x69, -+ 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x4e, 0x6f, 0x6e, 0x65, -+ 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x69, -+ 0x74, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0x51, 0x74, 0x57, 0x69, -+ 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x51, 0x41, 0x70, 0x70, -+ 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x69, -+ 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x28, 0x29, 0x2e, -+ 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, -+ 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x28, 0x29, 0x0d, 0x0a, 0x0d, -+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, -+ 0x66, 0x20, 0x6c, 0x65, 0x6e, 0x28, 0x70, 0x61, 0x72, 0x65, -+ 0x6e, 0x74, 0x5f, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x29, 0x20, -+ 0x3e, 0x20, 0x30, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x69, -+ 0x74, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0x27, 0x20, 0x2d, 0x20, -+ 0x27, 0x2e, 0x6a, 0x6f, 0x69, 0x6e, 0x28, 0x28, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x72, 0x65, -+ 0x6e, 0x74, 0x5f, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x2c, 0x0d, -+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x69, 0x74, -+ 0x6c, 0x65, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x0d, -+ 0x0a, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x62, 0x6f, 0x78, 0x2e, 0x73, 0x65, 0x74, -+ 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x54, 0x69, 0x74, 0x6c, -+ 0x65, 0x28, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x29, 0x0d, 0x0a, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, -+ 0x72, 0x6e, 0x20, 0x62, 0x6f, 0x78, 0x2e, 0x65, 0x78, 0x65, -+ 0x63, 0x28, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x51, 0x74, 0x43, -+ 0x6f, 0x72, 0x65, 0x2e, 0x71, 0x44, 0x65, 0x62, 0x75, 0x67, -+ 0x28, 0x27, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x20, -+ 0x73, 0x79, 0x73, 0x2e, 0x65, 0x78, 0x63, 0x65, 0x70, 0x74, -+ 0x68, 0x6f, 0x6f, 0x6b, 0x20, 0x74, 0x6f, 0x20, 0x70, 0x72, -+ 0x6f, 0x76, 0x69, 0x64, 0x65, 0x20, 0x64, 0x69, 0x61, 0x6c, -+ 0x6f, 0x67, 0x27, 0x29, 0x0d, 0x0a, 0x73, 0x79, 0x73, 0x2e, -+ 0x65, 0x78, 0x63, 0x65, 0x70, 0x74, 0x68, 0x6f, 0x6f, 0x6b, -+ 0x20, 0x3d, 0x20, 0x65, 0x78, 0x63, 0x65, 0x70, 0x74, 0x69, -+ 0x6f, 0x6e, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, -+ 0x5f, 0x62, 0x6f, 0x78, 0x0d, 0x0a, 0x00 -+}; -diff --git a/designer/excepthook.py b/designer/excepthook.py -new file mode 100644 -index 0000000..1c4aaa9 ---- /dev/null -+++ b/designer/excepthook.py -@@ -0,0 +1,170 @@ -+import functools -+import sys -+import traceback -+ -+from PyQt5 import QtCore, QtWidgets -+ -+QtCore.qDebug('Importing module for exception dialogs') -+ -+def exception_message_box(excType=None, excValue=None, tracebackobj=None): -+ message = traceback.format_exception(excType, excValue, tracebackobj) -+ message = ''.join(message) -+ -+ dialog( -+ parent=None, -+ title='Exception', -+ message=message, -+ icon=QtWidgets.QMessageBox.Critical, -+ ) -+ -+class FittedTextBrowser(QtWidgets.QTextBrowser): -+ def sizeHint(self): -+ default = super().sizeHint() -+ -+ if not default.isValid(): -+ return default -+ -+ document_size = self.document().size() -+ -+ desktops = QtWidgets.QApplication.desktop() -+ screen_number = desktops.screenNumber(self.parent()) -+ geometry = desktops.screenGeometry(screen_number) -+ -+ if document_size.width() == 0: -+ document_size.setWidth(geometry.width() * 0.25) -+ if document_size.height() == 0: -+ document_size.setHeight(geometry.height() * 0.4) -+ -+ scrollbar_width = QtWidgets.QApplication.style().pixelMetric( -+ QtWidgets.QStyle.PM_ScrollBarExtent -+ ) -+ -+ width = sum(( -+ document_size.width(), -+ self.contentsMargins().left(), -+ self.contentsMargins().right(), -+ scrollbar_width, -+ )) -+ -+ height = sum(( -+ document_size.height(), -+ self.contentsMargins().top(), -+ self.contentsMargins().bottom(), -+ scrollbar_width, -+ )) -+ -+ return QtCore.QSize(width, height) -+ -+ -+class DialogUi: -+ def __init__(self, parent): -+ self.layout = QtWidgets.QGridLayout(parent) -+ self.icon = QtWidgets.QLabel(parent) -+ self.message = FittedTextBrowser(parent) -+ self.copy = QtWidgets.QPushButton(parent) -+ self.buttons = QtWidgets.QDialogButtonBox(parent) -+ -+ self.copy.setText('Copy To Clipboard') -+ -+ self.layout.addWidget(self.icon, 0, 0) -+ self.layout.addWidget(self.message, 0, 1, 1, 2) -+ self.layout.addWidget(self.copy, 1, 1) -+ self.layout.addWidget(self.buttons, 1, 2) -+ -+ self.layout.setAlignment(self.copy, QtCore.Qt.AlignLeft) -+ -+ self.layout.setRowStretch(0, 1) -+ self.layout.setColumnStretch(1, 1) -+ -+ -+class Dialog(QtWidgets.QDialog): -+ def __init__(self, *args, cancellable=False, **kwargs): -+ super().__init__(*args, **kwargs) -+ -+ self.ui = DialogUi(parent=self) -+ -+ self.ui.buttons.accepted.connect(self.accept) -+ self.ui.buttons.rejected.connect(self.reject) -+ -+ self.ui.copy.clicked.connect(self.copy) -+ -+ self.setLayout(self.ui.layout) -+ buttons = QtWidgets.QDialogButtonBox.Ok -+ if cancellable: -+ buttons |= QtWidgets.QDialogButtonBox.Cancel -+ -+ self.ui.buttons.setStandardButtons(buttons) -+ -+ self.text = None -+ self.html = None -+ -+ self.cached_maximum_size = self.maximumSize() -+ -+ desktops = QtWidgets.QApplication.desktop() -+ screen_number = desktops.screenNumber(self.parent()) -+ geometry = desktops.screenGeometry(screen_number) -+ -+ self.setMaximumHeight(geometry.height() * 0.7) -+ self.setMaximumWidth(geometry.width() * 0.7) -+ -+ def copy(self): -+ QtWidgets.QApplication.clipboard().setText( -+ self.ui.message.toPlainText() + '\\n' -+ ) -+ -+ def set_text(self, text): -+ self.ui.message.setPlainText(text) -+ -+ self.html = None -+ self.text = text -+ -+ self.ui.message.setLineWrapMode(QtWidgets.QTextEdit.NoWrap) -+ -+ def set_html(self, html): -+ self.ui.message.setHtml(html) -+ -+ self.html = html -+ self.text = None -+ -+ self.ui.message.setLineWrapMode(QtWidgets.QTextEdit.WidgetWidth) -+ -+ def set_message_box_icon(self, icon): -+ self.ui.icon.setPixmap(QtWidgets.QMessageBox.standardIcon(icon)) -+ -+ def exec(self): -+ QtCore.QTimer.singleShot(10, functools.partial( -+ self.setMaximumSize, -+ self.cached_maximum_size, -+ )) -+ -+ return super().exec() -+ -+ -+def dialog(parent, message, title=None, icon=None, -+ rich_text=False, cancellable=False): -+ box = Dialog(parent=parent, cancellable=cancellable) -+ -+ if rich_text: -+ box.set_html(message) -+ else: -+ box.set_text(message) -+ -+ if icon is not None: -+ box.set_message_box_icon(icon) -+ -+ if title is not None: -+ parent_title = QtWidgets.QApplication.instance().applicationName() -+ -+ if len(parent_title) > 0: -+ title = ' - '.join(( -+ parent_title, -+ title, -+ )) -+ -+ -+ box.setWindowTitle(title) -+ -+ return box.exec() -+ -+QtCore.qDebug('Setting sys.excepthook to provide dialog') -+sys.excepthook = exception_message_box -diff --git a/designer/generate_module_literal.py b/designer/generate_module_literal.py -new file mode 100644 -index 0000000..cc6b4de ---- /dev/null -+++ b/designer/generate_module_literal.py -@@ -0,0 +1,35 @@ -+import os -+import itertools -+ -+ -+# https://repl.it/IwNE/4 -+def chunker(iterable, n): -+ "Collect data into fixed-length chunks or blocks except last due to lack of fill." -+ # chunker('ABCDEFG', 3) --> ABC DEF G" -+ -+ i = iter(iterable) -+ -+ while True: -+ t = tuple(next(i) for _ in range(n)) -+ -+ if len(t) > 0: -+ yield t -+ else: -+ break -+ -+ -+with open('excepthook.py', 'rb') as f: -+ raw = f.read() -+ -+with open('excepthook.c', 'w', newline='\n') as f: -+ f.write('const char * moduleName = "exceptiondialog";\n\n') -+ f.write('const char moduleCode[] = {\n') -+ -+ indent = ' ' * 4 -+ -+ chunks = chunker(itertools.chain(raw, b'\0'), 10) -+ lines = (', '.join('0x{:02x}'.format(b) for b in chunk) for chunk in chunks) -+ lines = (',\n'.join(indent + line for line in lines)) -+ for line in lines: -+ f.write(line) -+ f.write("\n};\n") -diff --git a/designer/pluginloader.cpp b/designer/pluginloader.cpp -index d4fb17a..d9f77ec 100644 ---- a/designer/pluginloader.cpp -+++ b/designer/pluginloader.cpp -@@ -25,6 +25,7 @@ - - #include - -+#include - #include - #include - #include -@@ -36,6 +37,114 @@ - - #include "../qpy/QtDesigner/qpydesignercustomwidgetplugin.h" - -+#include "excepthook.c" -+ -+ -+void setupExceptHookDialog(void) -+{ -+ qDebug() << "Preparing to import module"; -+ qDebug() << PyBytes_AS_STRING(PyUnicode_AsEncodedString(PyObject_Str(PySys_GetObject("path")), "utf-8", "error 1?")); -+ // https://stackoverflow.com/a/42853449/228539 -+ PyObject *pyModule = PyModule_New(moduleName); -+ // Set properties on the new module object -+ PyModule_AddStringConstant(pyModule, "__file__", ""); -+ PyObject *localDict = PyModule_GetDict(pyModule); // Returns a borrowed reference: no need to Py_DECREF() it once we are done -+ PyObject *builtins = PyEval_GetBuiltins(); // Returns a borrowed reference: no need to Py_DECREF() it once we are done -+ PyDict_SetItemString(localDict, "__builtins__", builtins); -+ -+ qDebug() << "About to import module"; -+ -+ // Define code in the newly created module -+ PyObject *pyValue = PyRun_String(moduleCode, Py_file_input, localDict, localDict); -+ qDebug() << "Code just run"; -+ if (pyValue == NULL) -+ { -+ qDebug() << "An error occurred while importing the module"; -+ -+ char * full_backtrace = NULL; -+ -+ if (PyErr_Occurred() != NULL) { -+ qDebug() << "PyErr_Occurred() != NULL"; -+ PyObject *ptype, *pvalue, *ptraceback; -+ PyObject *pystr, *module_name, *pyth_module, *pyth_func; -+ char *str; -+ char *error_description; -+ -+ PyErr_Fetch(&ptype, &pvalue, &ptraceback); -+ qDebug() << "ptype == NULL : " << (ptype == NULL); -+ qDebug() << "pvalue == NULL : " << (pvalue == NULL); -+ qDebug() << "ptraceback == NULL : " << (ptraceback == NULL); -+ pystr = PyObject_Str(pvalue); -+ qDebug() << "pystr == NULL : " << (pystr == NULL); -+ pystr = PyUnicode_AsEncodedString(pystr, "utf-8", "error 1?"); -+ qDebug() << "pystr == NULL : " << (pystr == NULL); -+ str = PyBytes_AS_STRING(pystr); -+ qDebug() << "str == NULL : " << (str == NULL); -+ if (str != NULL) -+ { -+ qDebug() << "str: " << str; -+ } -+ Py_DECREF(pystr); -+ error_description = strdup(str); -+ qDebug() << "error_description == NULL : " << (error_description == NULL); -+ if (error_description != NULL) -+ { -+ qDebug() << "error_description: " << error_description; -+ } -+ -+ /* See if we can get a full traceback */ -+ module_name = PyUnicode_Decode("traceback", 9, "utf-8", "error 2?"); -+ pyth_module = PyImport_Import(module_name); -+ Py_DECREF(module_name); -+ -+ qDebug() << "pyth_module == NULL : " << (pyth_module == NULL); -+ if (pyth_module == NULL) { -+ full_backtrace = NULL; -+ return; -+ } -+ -+ pyth_func = PyObject_GetAttrString(pyth_module, "format_exception"); -+ if (pyth_func && PyCallable_Check(pyth_func)) -+ { -+ qDebug() << "pyth_func && PyCallable_Check(pyth_func)"; -+ PyObject *pyth_val; -+ -+ pyth_val = PyObject_CallFunctionObjArgs(pyth_func, ptype, pvalue, ptraceback, Py_None, Py_True, NULL); -+ qDebug() << "pyth_val == NULL : " << (pyth_val == NULL); -+ -+ pystr = PyObject_Str(pyth_val); -+ qDebug() << "pystr == NULL : " << (pystr == NULL); -+ -+ pystr = PyUnicode_AsEncodedString(pystr, "utf-8", "error 3?"); -+ qDebug() << "pystr == NULL : " << (pystr == NULL); -+ -+ str = PyBytes_AS_STRING(pystr); -+ qDebug() << "str == NULL : " << (str == NULL); -+ -+ Py_DECREF(pystr); -+ full_backtrace = strdup(str); -+ Py_DECREF(pyth_val); -+ } -+ } -+ -+ if (full_backtrace != NULL) -+ { -+ qDebug() << "About to print backtrace"; -+ qDebug() << full_backtrace; -+ } -+ else -+ { -+ qDebug() << "Backtrace was NULL"; -+ } -+ } -+ else -+ { -+ qDebug() << "About to decref"; -+ Py_DECREF(pyValue); -+ } -+ -+ qDebug() << "Done importing module"; -+} - - // Construct the collection of Python widgets. - PyCustomWidgets::PyCustomWidgets(QObject *parent) : QObject(parent), -@@ -140,6 +249,7 @@ PyCustomWidgets::PyCustomWidgets(QObject *parent) : QObject(parent), - PyGILState_STATE gil_state = PyGILState_Ensure(); - #endif - -+ setupExceptHookDialog(); - bool fatal = importPlugins(dir, plugins); - - #if defined(WITH_THREAD) diff --git a/pluginloader.5.14.2.patch b/pluginloader.5.14.2.patch deleted file mode 100644 index 0af856245..000000000 --- a/pluginloader.5.14.2.patch +++ /dev/null @@ -1,858 +0,0 @@ -diff --git a/designer/excepthook.c b/designer/excepthook.c -new file mode 100644 -index 0000000..6a575af ---- /dev/null -+++ b/designer/excepthook.c -@@ -0,0 +1,500 @@ -+const char * moduleName = "exceptiondialog"; -+ -+const char moduleCode[] = { -+ 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x66, 0x75, 0x6e, -+ 0x63, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x0d, 0x0a, 0x69, 0x6d, -+ 0x70, 0x6f, 0x72, 0x74, 0x20, 0x73, 0x79, 0x73, 0x0d, 0x0a, -+ 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x74, 0x72, 0x61, -+ 0x63, 0x65, 0x62, 0x61, 0x63, 0x6b, 0x0d, 0x0a, 0x0d, 0x0a, -+ 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x50, 0x79, 0x51, 0x74, 0x35, -+ 0x20, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x51, 0x74, -+ 0x43, 0x6f, 0x72, 0x65, 0x2c, 0x20, 0x51, 0x74, 0x57, 0x69, -+ 0x64, 0x67, 0x65, 0x74, 0x73, 0x0d, 0x0a, 0x0d, 0x0a, 0x51, -+ 0x74, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x71, 0x44, 0x65, 0x62, -+ 0x75, 0x67, 0x28, 0x27, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, -+ 0x69, 0x6e, 0x67, 0x20, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, -+ 0x20, 0x66, 0x6f, 0x72, 0x20, 0x65, 0x78, 0x63, 0x65, 0x70, -+ 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x64, 0x69, 0x61, 0x6c, 0x6f, -+ 0x67, 0x73, 0x27, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x64, 0x65, -+ 0x66, 0x20, 0x65, 0x78, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6f, -+ 0x6e, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, -+ 0x62, 0x6f, 0x78, 0x28, 0x65, 0x78, 0x63, 0x54, 0x79, 0x70, -+ 0x65, 0x3d, 0x4e, 0x6f, 0x6e, 0x65, 0x2c, 0x20, 0x65, 0x78, -+ 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x3d, 0x4e, 0x6f, 0x6e, -+ 0x65, 0x2c, 0x20, 0x74, 0x72, 0x61, 0x63, 0x65, 0x62, 0x61, -+ 0x63, 0x6b, 0x6f, 0x62, 0x6a, 0x3d, 0x4e, 0x6f, 0x6e, 0x65, -+ 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x65, -+ 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x3d, 0x20, 0x74, 0x72, -+ 0x61, 0x63, 0x65, 0x62, 0x61, 0x63, 0x6b, 0x2e, 0x66, 0x6f, -+ 0x72, 0x6d, 0x61, 0x74, 0x5f, 0x65, 0x78, 0x63, 0x65, 0x70, -+ 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x65, 0x78, 0x63, 0x54, 0x79, -+ 0x70, 0x65, 0x2c, 0x20, 0x65, 0x78, 0x63, 0x56, 0x61, 0x6c, -+ 0x75, 0x65, 0x2c, 0x20, 0x74, 0x72, 0x61, 0x63, 0x65, 0x62, -+ 0x61, 0x63, 0x6b, 0x6f, 0x62, 0x6a, 0x29, 0x0d, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, -+ 0x20, 0x3d, 0x20, 0x27, 0x27, 0x2e, 0x6a, 0x6f, 0x69, 0x6e, -+ 0x28, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x29, 0x0d, -+ 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x69, 0x61, -+ 0x6c, 0x6f, 0x67, 0x28, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, -+ 0x3d, 0x4e, 0x6f, 0x6e, 0x65, 0x2c, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x69, 0x74, 0x6c, -+ 0x65, 0x3d, 0x27, 0x45, 0x78, 0x63, 0x65, 0x70, 0x74, 0x69, -+ 0x6f, 0x6e, 0x27, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, -+ 0x65, 0x3d, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2c, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x69, 0x63, 0x6f, 0x6e, 0x3d, 0x51, 0x74, 0x57, 0x69, 0x64, -+ 0x67, 0x65, 0x74, 0x73, 0x2e, 0x51, 0x4d, 0x65, 0x73, 0x73, -+ 0x61, 0x67, 0x65, 0x42, 0x6f, 0x78, 0x2e, 0x43, 0x72, 0x69, -+ 0x74, 0x69, 0x63, 0x61, 0x6c, 0x2c, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x63, 0x6c, 0x61, -+ 0x73, 0x73, 0x20, 0x46, 0x69, 0x74, 0x74, 0x65, 0x64, 0x54, -+ 0x65, 0x78, 0x74, 0x42, 0x72, 0x6f, 0x77, 0x73, 0x65, 0x72, -+ 0x28, 0x51, 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, -+ 0x2e, 0x51, 0x54, 0x65, 0x78, 0x74, 0x42, 0x72, 0x6f, 0x77, -+ 0x73, 0x65, 0x72, 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, -+ 0x20, 0x64, 0x65, 0x66, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x48, -+ 0x69, 0x6e, 0x74, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x29, 0x3a, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x20, 0x3d, 0x20, -+ 0x73, 0x75, 0x70, 0x65, 0x72, 0x28, 0x29, 0x2e, 0x73, 0x69, -+ 0x7a, 0x65, 0x48, 0x69, 0x6e, 0x74, 0x28, 0x29, 0x0d, 0x0a, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x64, 0x65, 0x66, -+ 0x61, 0x75, 0x6c, 0x74, 0x2e, 0x69, 0x73, 0x56, 0x61, 0x6c, -+ 0x69, 0x64, 0x28, 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, -+ 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x64, 0x65, 0x66, 0x61, -+ 0x75, 0x6c, 0x74, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, -+ 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x3d, -+ 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x64, 0x6f, 0x63, 0x75, -+ 0x6d, 0x65, 0x6e, 0x74, 0x28, 0x29, 0x2e, 0x73, 0x69, 0x7a, -+ 0x65, 0x28, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x73, 0x6b, 0x74, -+ 0x6f, 0x70, 0x73, 0x20, 0x3d, 0x20, 0x51, 0x74, 0x57, 0x69, -+ 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x51, 0x41, 0x70, 0x70, -+ 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x64, -+ 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x28, 0x29, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x63, -+ 0x72, 0x65, 0x65, 0x6e, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, -+ 0x72, 0x20, 0x3d, 0x20, 0x64, 0x65, 0x73, 0x6b, 0x74, 0x6f, -+ 0x70, 0x73, 0x2e, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x4e, -+ 0x75, 0x6d, 0x62, 0x65, 0x72, 0x28, 0x73, 0x65, 0x6c, 0x66, -+ 0x2e, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x28, 0x29, 0x29, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x67, 0x65, 0x6f, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x20, 0x3d, -+ 0x20, 0x64, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x73, 0x2e, -+ 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x47, 0x65, 0x6f, 0x6d, -+ 0x65, 0x74, 0x72, 0x79, 0x28, 0x73, 0x63, 0x72, 0x65, 0x65, -+ 0x6e, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x29, 0x0d, -+ 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x69, 0x66, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, -+ 0x6e, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x2e, 0x77, 0x69, -+ 0x64, 0x74, 0x68, 0x28, 0x29, 0x20, 0x3d, 0x3d, 0x20, 0x30, -+ 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, -+ 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x2e, 0x73, -+ 0x65, 0x74, 0x57, 0x69, 0x64, 0x74, 0x68, 0x28, 0x67, 0x65, -+ 0x6f, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x77, 0x69, 0x64, -+ 0x74, 0x68, 0x28, 0x29, 0x20, 0x2a, 0x20, 0x30, 0x2e, 0x32, -+ 0x35, 0x29, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x69, 0x66, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, -+ 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x2e, 0x68, -+ 0x65, 0x69, 0x67, 0x68, 0x74, 0x28, 0x29, 0x20, 0x3d, 0x3d, -+ 0x20, 0x30, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, 0x63, -+ 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, -+ 0x2e, 0x73, 0x65, 0x74, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, -+ 0x28, 0x67, 0x65, 0x6f, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, -+ 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x28, 0x29, 0x20, 0x2a, -+ 0x20, 0x30, 0x2e, 0x34, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x63, 0x72, -+ 0x6f, 0x6c, 0x6c, 0x62, 0x61, 0x72, 0x5f, 0x77, 0x69, 0x64, -+ 0x74, 0x68, 0x20, 0x3d, 0x20, 0x51, 0x74, 0x57, 0x69, 0x64, -+ 0x67, 0x65, 0x74, 0x73, 0x2e, 0x51, 0x41, 0x70, 0x70, 0x6c, -+ 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x73, 0x74, -+ 0x79, 0x6c, 0x65, 0x28, 0x29, 0x2e, 0x70, 0x69, 0x78, 0x65, -+ 0x6c, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x28, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x51, 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, -+ 0x73, 0x2e, 0x51, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x2e, 0x50, -+ 0x4d, 0x5f, 0x53, 0x63, 0x72, 0x6f, 0x6c, 0x6c, 0x42, 0x61, -+ 0x72, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x74, 0x0d, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x0d, 0x0a, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x77, 0x69, 0x64, 0x74, 0x68, 0x20, 0x3d, 0x20, 0x73, 0x75, -+ 0x6d, 0x28, 0x28, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, 0x63, -+ 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, -+ 0x2e, 0x77, 0x69, 0x64, 0x74, 0x68, 0x28, 0x29, 0x2c, 0x0d, -+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x63, 0x6f, -+ 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x4d, 0x61, 0x72, 0x67, -+ 0x69, 0x6e, 0x73, 0x28, 0x29, 0x2e, 0x6c, 0x65, 0x66, 0x74, -+ 0x28, 0x29, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, -+ 0x66, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, -+ 0x4d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x73, 0x28, 0x29, 0x2e, -+ 0x72, 0x69, 0x67, 0x68, 0x74, 0x28, 0x29, 0x2c, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x73, 0x63, 0x72, 0x6f, 0x6c, 0x6c, 0x62, 0x61, -+ 0x72, 0x5f, 0x77, 0x69, 0x64, 0x74, 0x68, 0x2c, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, -+ 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x20, 0x3d, -+ 0x20, 0x73, 0x75, 0x6d, 0x28, 0x28, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x73, -+ 0x69, 0x7a, 0x65, 0x2e, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, -+ 0x28, 0x29, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, -+ 0x66, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, -+ 0x4d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x73, 0x28, 0x29, 0x2e, -+ 0x74, 0x6f, 0x70, 0x28, 0x29, 0x2c, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, -+ 0x6e, 0x74, 0x73, 0x4d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x73, -+ 0x28, 0x29, 0x2e, 0x62, 0x6f, 0x74, 0x74, 0x6f, 0x6d, 0x28, -+ 0x29, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x63, 0x72, 0x6f, -+ 0x6c, 0x6c, 0x62, 0x61, 0x72, 0x5f, 0x77, 0x69, 0x64, 0x74, -+ 0x68, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x29, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, -+ 0x72, 0x6e, 0x20, 0x51, 0x74, 0x43, 0x6f, 0x72, 0x65, 0x2e, -+ 0x51, 0x53, 0x69, 0x7a, 0x65, 0x28, 0x77, 0x69, 0x64, 0x74, -+ 0x68, 0x2c, 0x20, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x29, -+ 0x0d, 0x0a, 0x0d, 0x0a, 0x0d, 0x0a, 0x63, 0x6c, 0x61, 0x73, -+ 0x73, 0x20, 0x44, 0x69, 0x61, 0x6c, 0x6f, 0x67, 0x55, 0x69, -+ 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x66, -+ 0x20, 0x5f, 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x5f, 0x5f, 0x28, -+ 0x73, 0x65, 0x6c, 0x66, 0x2c, 0x20, 0x70, 0x61, 0x72, 0x65, -+ 0x6e, 0x74, 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x6c, -+ 0x61, 0x79, 0x6f, 0x75, 0x74, 0x20, 0x3d, 0x20, 0x51, 0x74, -+ 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x51, 0x47, -+ 0x72, 0x69, 0x64, 0x4c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x28, -+ 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x29, 0x0d, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, -+ 0x66, 0x2e, 0x69, 0x63, 0x6f, 0x6e, 0x20, 0x3d, 0x20, 0x51, -+ 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x51, -+ 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x28, 0x70, 0x61, 0x72, 0x65, -+ 0x6e, 0x74, 0x29, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x6d, 0x65, -+ 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x3d, 0x20, 0x46, 0x69, -+ 0x74, 0x74, 0x65, 0x64, 0x54, 0x65, 0x78, 0x74, 0x42, 0x72, -+ 0x6f, 0x77, 0x73, 0x65, 0x72, 0x28, 0x70, 0x61, 0x72, 0x65, -+ 0x6e, 0x74, 0x29, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x63, 0x6f, -+ 0x70, 0x79, 0x20, 0x3d, 0x20, 0x51, 0x74, 0x57, 0x69, 0x64, -+ 0x67, 0x65, 0x74, 0x73, 0x2e, 0x51, 0x50, 0x75, 0x73, 0x68, -+ 0x42, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x28, 0x70, 0x61, 0x72, -+ 0x65, 0x6e, 0x74, 0x29, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x62, -+ 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x73, 0x20, 0x3d, 0x20, 0x51, -+ 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x51, -+ 0x44, 0x69, 0x61, 0x6c, 0x6f, 0x67, 0x42, 0x75, 0x74, 0x74, -+ 0x6f, 0x6e, 0x42, 0x6f, 0x78, 0x28, 0x70, 0x61, 0x72, 0x65, -+ 0x6e, 0x74, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, -+ 0x63, 0x6f, 0x70, 0x79, 0x2e, 0x73, 0x65, 0x74, 0x54, 0x65, -+ 0x78, 0x74, 0x28, 0x27, 0x43, 0x6f, 0x70, 0x79, 0x20, 0x54, -+ 0x6f, 0x20, 0x43, 0x6c, 0x69, 0x70, 0x62, 0x6f, 0x61, 0x72, -+ 0x64, 0x27, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, -+ 0x6c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x2e, 0x61, 0x64, 0x64, -+ 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x28, 0x73, 0x65, 0x6c, -+ 0x66, 0x2e, 0x69, 0x63, 0x6f, 0x6e, 0x2c, 0x20, 0x30, 0x2c, -+ 0x20, 0x30, 0x29, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x6c, 0x61, -+ 0x79, 0x6f, 0x75, 0x74, 0x2e, 0x61, 0x64, 0x64, 0x57, 0x69, -+ 0x64, 0x67, 0x65, 0x74, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, -+ 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2c, 0x20, 0x30, -+ 0x2c, 0x20, 0x31, 0x2c, 0x20, 0x31, 0x2c, 0x20, 0x32, 0x29, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x6c, 0x61, 0x79, 0x6f, 0x75, -+ 0x74, 0x2e, 0x61, 0x64, 0x64, 0x57, 0x69, 0x64, 0x67, 0x65, -+ 0x74, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x63, 0x6f, 0x70, -+ 0x79, 0x2c, 0x20, 0x31, 0x2c, 0x20, 0x31, 0x29, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, -+ 0x6c, 0x66, 0x2e, 0x6c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x2e, -+ 0x61, 0x64, 0x64, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x28, -+ 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x62, 0x75, 0x74, 0x74, 0x6f, -+ 0x6e, 0x73, 0x2c, 0x20, 0x31, 0x2c, 0x20, 0x32, 0x29, 0x0d, -+ 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x6c, 0x61, 0x79, 0x6f, -+ 0x75, 0x74, 0x2e, 0x73, 0x65, 0x74, 0x41, 0x6c, 0x69, 0x67, -+ 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x28, 0x73, 0x65, 0x6c, 0x66, -+ 0x2e, 0x63, 0x6f, 0x70, 0x79, 0x2c, 0x20, 0x51, 0x74, 0x43, -+ 0x6f, 0x72, 0x65, 0x2e, 0x51, 0x74, 0x2e, 0x41, 0x6c, 0x69, -+ 0x67, 0x6e, 0x4c, 0x65, 0x66, 0x74, 0x29, 0x0d, 0x0a, 0x0d, -+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, -+ 0x65, 0x6c, 0x66, 0x2e, 0x6c, 0x61, 0x79, 0x6f, 0x75, 0x74, -+ 0x2e, 0x73, 0x65, 0x74, 0x52, 0x6f, 0x77, 0x53, 0x74, 0x72, -+ 0x65, 0x74, 0x63, 0x68, 0x28, 0x30, 0x2c, 0x20, 0x31, 0x29, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x6c, 0x61, 0x79, 0x6f, 0x75, -+ 0x74, 0x2e, 0x73, 0x65, 0x74, 0x43, 0x6f, 0x6c, 0x75, 0x6d, -+ 0x6e, 0x53, 0x74, 0x72, 0x65, 0x74, 0x63, 0x68, 0x28, 0x31, -+ 0x2c, 0x20, 0x31, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x0d, 0x0a, -+ 0x63, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x44, 0x69, 0x61, 0x6c, -+ 0x6f, 0x67, 0x28, 0x51, 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, -+ 0x74, 0x73, 0x2e, 0x51, 0x44, 0x69, 0x61, 0x6c, 0x6f, 0x67, -+ 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, -+ 0x66, 0x20, 0x5f, 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x5f, 0x5f, -+ 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2c, 0x20, 0x2a, 0x61, 0x72, -+ 0x67, 0x73, 0x2c, 0x20, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, -+ 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x3d, 0x46, 0x61, 0x6c, 0x73, -+ 0x65, 0x2c, 0x20, 0x2a, 0x2a, 0x6b, 0x77, 0x61, 0x72, 0x67, -+ 0x73, 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x73, 0x75, 0x70, 0x65, 0x72, 0x28, 0x29, -+ 0x2e, 0x5f, 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x5f, 0x5f, 0x28, -+ 0x2a, 0x61, 0x72, 0x67, 0x73, 0x2c, 0x20, 0x2a, 0x2a, 0x6b, -+ 0x77, 0x61, 0x72, 0x67, 0x73, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, -+ 0x6c, 0x66, 0x2e, 0x75, 0x69, 0x20, 0x3d, 0x20, 0x44, 0x69, -+ 0x61, 0x6c, 0x6f, 0x67, 0x55, 0x69, 0x28, 0x70, 0x61, 0x72, -+ 0x65, 0x6e, 0x74, 0x3d, 0x73, 0x65, 0x6c, 0x66, 0x29, 0x0d, -+ 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x75, 0x69, 0x2e, 0x62, -+ 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x73, 0x2e, 0x61, 0x63, 0x63, -+ 0x65, 0x70, 0x74, 0x65, 0x64, 0x2e, 0x63, 0x6f, 0x6e, 0x6e, -+ 0x65, 0x63, 0x74, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x61, -+ 0x63, 0x63, 0x65, 0x70, 0x74, 0x29, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, -+ 0x2e, 0x75, 0x69, 0x2e, 0x62, 0x75, 0x74, 0x74, 0x6f, 0x6e, -+ 0x73, 0x2e, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x65, 0x64, -+ 0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x28, 0x73, -+ 0x65, 0x6c, 0x66, 0x2e, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, -+ 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x75, 0x69, -+ 0x2e, 0x63, 0x6f, 0x70, 0x79, 0x2e, 0x63, 0x6c, 0x69, 0x63, -+ 0x6b, 0x65, 0x64, 0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, -+ 0x74, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x63, 0x6f, 0x70, -+ 0x79, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x73, -+ 0x65, 0x74, 0x4c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x28, 0x73, -+ 0x65, 0x6c, 0x66, 0x2e, 0x75, 0x69, 0x2e, 0x6c, 0x61, 0x79, -+ 0x6f, 0x75, 0x74, 0x29, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x62, 0x75, 0x74, 0x74, 0x6f, 0x6e, -+ 0x73, 0x20, 0x3d, 0x20, 0x51, 0x74, 0x57, 0x69, 0x64, 0x67, -+ 0x65, 0x74, 0x73, 0x2e, 0x51, 0x44, 0x69, 0x61, 0x6c, 0x6f, -+ 0x67, 0x42, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x42, 0x6f, 0x78, -+ 0x2e, 0x4f, 0x6b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x63, 0x61, 0x6e, 0x63, -+ 0x65, 0x6c, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x3a, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x62, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x73, 0x20, -+ 0x7c, 0x3d, 0x20, 0x51, 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, -+ 0x74, 0x73, 0x2e, 0x51, 0x44, 0x69, 0x61, 0x6c, 0x6f, 0x67, -+ 0x42, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x42, 0x6f, 0x78, 0x2e, -+ 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x0d, 0x0a, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, -+ 0x6c, 0x66, 0x2e, 0x75, 0x69, 0x2e, 0x62, 0x75, 0x74, 0x74, -+ 0x6f, 0x6e, 0x73, 0x2e, 0x73, 0x65, 0x74, 0x53, 0x74, 0x61, -+ 0x6e, 0x64, 0x61, 0x72, 0x64, 0x42, 0x75, 0x74, 0x74, 0x6f, -+ 0x6e, 0x73, 0x28, 0x62, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x73, -+ 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x65, -+ 0x78, 0x74, 0x20, 0x3d, 0x20, 0x4e, 0x6f, 0x6e, 0x65, 0x0d, -+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, -+ 0x65, 0x6c, 0x66, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x20, 0x3d, -+ 0x20, 0x4e, 0x6f, 0x6e, 0x65, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, -+ 0x66, 0x2e, 0x63, 0x61, 0x63, 0x68, 0x65, 0x64, 0x5f, 0x6d, -+ 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x5f, 0x73, 0x69, 0x7a, -+ 0x65, 0x20, 0x3d, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x6d, -+ 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x53, 0x69, 0x7a, 0x65, -+ 0x28, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x73, 0x6b, 0x74, 0x6f, -+ 0x70, 0x73, 0x20, 0x3d, 0x20, 0x51, 0x74, 0x57, 0x69, 0x64, -+ 0x67, 0x65, 0x74, 0x73, 0x2e, 0x51, 0x41, 0x70, 0x70, 0x6c, -+ 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x64, 0x65, -+ 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x28, 0x29, 0x0d, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x63, 0x72, -+ 0x65, 0x65, 0x6e, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, -+ 0x20, 0x3d, 0x20, 0x64, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, -+ 0x73, 0x2e, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x4e, 0x75, -+ 0x6d, 0x62, 0x65, 0x72, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, -+ 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x28, 0x29, 0x29, 0x0d, -+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x67, -+ 0x65, 0x6f, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x20, 0x3d, 0x20, -+ 0x64, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x73, 0x2e, 0x73, -+ 0x63, 0x72, 0x65, 0x65, 0x6e, 0x47, 0x65, 0x6f, 0x6d, 0x65, -+ 0x74, 0x72, 0x79, 0x28, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, -+ 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x29, 0x0d, 0x0a, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x73, 0x65, 0x74, 0x4d, 0x61, -+ 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x48, 0x65, 0x69, 0x67, 0x68, -+ 0x74, 0x28, 0x67, 0x65, 0x6f, 0x6d, 0x65, 0x74, 0x72, 0x79, -+ 0x2e, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x28, 0x29, 0x20, -+ 0x2a, 0x20, 0x30, 0x2e, 0x37, 0x29, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, -+ 0x2e, 0x73, 0x65, 0x74, 0x4d, 0x61, 0x78, 0x69, 0x6d, 0x75, -+ 0x6d, 0x57, 0x69, 0x64, 0x74, 0x68, 0x28, 0x67, 0x65, 0x6f, -+ 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x77, 0x69, 0x64, 0x74, -+ 0x68, 0x28, 0x29, 0x20, 0x2a, 0x20, 0x30, 0x2e, 0x37, 0x29, -+ 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, -+ 0x66, 0x20, 0x63, 0x6f, 0x70, 0x79, 0x28, 0x73, 0x65, 0x6c, -+ 0x66, 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x51, 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, -+ 0x74, 0x73, 0x2e, 0x51, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, -+ 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x63, 0x6c, 0x69, 0x70, -+ 0x62, 0x6f, 0x61, 0x72, 0x64, 0x28, 0x29, 0x2e, 0x73, 0x65, -+ 0x74, 0x54, 0x65, 0x78, 0x74, 0x28, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x75, 0x69, 0x2e, 0x6d, 0x65, -+ 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x74, 0x6f, 0x50, 0x6c, -+ 0x61, 0x69, 0x6e, 0x54, 0x65, 0x78, 0x74, 0x28, 0x29, 0x20, -+ 0x2b, 0x20, 0x27, 0x5c, 0x5c, 0x6e, 0x27, 0x0d, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x0d, 0x0a, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x66, 0x20, -+ 0x73, 0x65, 0x74, 0x5f, 0x74, 0x65, 0x78, 0x74, 0x28, 0x73, -+ 0x65, 0x6c, 0x66, 0x2c, 0x20, 0x74, 0x65, 0x78, 0x74, 0x29, -+ 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x75, 0x69, 0x2e, 0x6d, -+ 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x73, 0x65, 0x74, -+ 0x50, 0x6c, 0x61, 0x69, 0x6e, 0x54, 0x65, 0x78, 0x74, 0x28, -+ 0x74, 0x65, 0x78, 0x74, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, -+ 0x66, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x20, 0x3d, 0x20, 0x4e, -+ 0x6f, 0x6e, 0x65, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x65, -+ 0x78, 0x74, 0x20, 0x3d, 0x20, 0x74, 0x65, 0x78, 0x74, 0x0d, -+ 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x75, 0x69, 0x2e, 0x6d, -+ 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x73, 0x65, 0x74, -+ 0x4c, 0x69, 0x6e, 0x65, 0x57, 0x72, 0x61, 0x70, 0x4d, 0x6f, -+ 0x64, 0x65, 0x28, 0x51, 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, -+ 0x74, 0x73, 0x2e, 0x51, 0x54, 0x65, 0x78, 0x74, 0x45, 0x64, -+ 0x69, 0x74, 0x2e, 0x4e, 0x6f, 0x57, 0x72, 0x61, 0x70, 0x29, -+ 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, -+ 0x66, 0x20, 0x73, 0x65, 0x74, 0x5f, 0x68, 0x74, 0x6d, 0x6c, -+ 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2c, 0x20, 0x68, 0x74, 0x6d, -+ 0x6c, 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x75, 0x69, -+ 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x73, -+ 0x65, 0x74, 0x48, 0x74, 0x6d, 0x6c, 0x28, 0x68, 0x74, 0x6d, -+ 0x6c, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x68, -+ 0x74, 0x6d, 0x6c, 0x20, 0x3d, 0x20, 0x68, 0x74, 0x6d, 0x6c, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x65, 0x78, 0x74, 0x20, -+ 0x3d, 0x20, 0x4e, 0x6f, 0x6e, 0x65, 0x0d, 0x0a, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, -+ 0x6c, 0x66, 0x2e, 0x75, 0x69, 0x2e, 0x6d, 0x65, 0x73, 0x73, -+ 0x61, 0x67, 0x65, 0x2e, 0x73, 0x65, 0x74, 0x4c, 0x69, 0x6e, -+ 0x65, 0x57, 0x72, 0x61, 0x70, 0x4d, 0x6f, 0x64, 0x65, 0x28, -+ 0x51, 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, -+ 0x51, 0x54, 0x65, 0x78, 0x74, 0x45, 0x64, 0x69, 0x74, 0x2e, -+ 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x57, 0x69, 0x64, 0x74, -+ 0x68, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x64, 0x65, 0x66, 0x20, 0x73, 0x65, 0x74, 0x5f, 0x6d, 0x65, -+ 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x62, 0x6f, 0x78, 0x5f, -+ 0x69, 0x63, 0x6f, 0x6e, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2c, -+ 0x20, 0x69, 0x63, 0x6f, 0x6e, 0x29, 0x3a, 0x0d, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, -+ 0x66, 0x2e, 0x75, 0x69, 0x2e, 0x69, 0x63, 0x6f, 0x6e, 0x2e, -+ 0x73, 0x65, 0x74, 0x50, 0x69, 0x78, 0x6d, 0x61, 0x70, 0x28, -+ 0x51, 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, -+ 0x51, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x6f, -+ 0x78, 0x2e, 0x73, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, -+ 0x49, 0x63, 0x6f, 0x6e, 0x28, 0x69, 0x63, 0x6f, 0x6e, 0x29, -+ 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, -+ 0x65, 0x66, 0x20, 0x65, 0x78, 0x65, 0x63, 0x28, 0x73, 0x65, -+ 0x6c, 0x66, 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x51, 0x74, 0x43, 0x6f, 0x72, 0x65, -+ 0x2e, 0x51, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x2e, 0x73, 0x69, -+ 0x6e, 0x67, 0x6c, 0x65, 0x53, 0x68, 0x6f, 0x74, 0x28, 0x31, -+ 0x30, 0x2c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x6f, 0x6f, -+ 0x6c, 0x73, 0x2e, 0x70, 0x61, 0x72, 0x74, 0x69, 0x61, 0x6c, -+ 0x28, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, -+ 0x65, 0x6c, 0x66, 0x2e, 0x73, 0x65, 0x74, 0x4d, 0x61, 0x78, -+ 0x69, 0x6d, 0x75, 0x6d, 0x53, 0x69, 0x7a, 0x65, 0x2c, 0x0d, -+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, -+ 0x66, 0x2e, 0x63, 0x61, 0x63, 0x68, 0x65, 0x64, 0x5f, 0x6d, -+ 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x5f, 0x73, 0x69, 0x7a, -+ 0x65, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x29, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, -+ 0x72, 0x6e, 0x20, 0x73, 0x75, 0x70, 0x65, 0x72, 0x28, 0x29, -+ 0x2e, 0x65, 0x78, 0x65, 0x63, 0x28, 0x29, 0x0d, 0x0a, 0x0d, -+ 0x0a, 0x0d, 0x0a, 0x64, 0x65, 0x66, 0x20, 0x64, 0x69, 0x61, -+ 0x6c, 0x6f, 0x67, 0x28, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, -+ 0x2c, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2c, -+ 0x20, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x3d, 0x4e, 0x6f, 0x6e, -+ 0x65, 0x2c, 0x20, 0x69, 0x63, 0x6f, 0x6e, 0x3d, 0x4e, 0x6f, -+ 0x6e, 0x65, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x69, 0x63, 0x68, -+ 0x5f, 0x74, 0x65, 0x78, 0x74, 0x3d, 0x46, 0x61, 0x6c, 0x73, -+ 0x65, 0x2c, 0x20, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, -+ 0x61, 0x62, 0x6c, 0x65, 0x3d, 0x46, 0x61, 0x6c, 0x73, 0x65, -+ 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6f, -+ 0x78, 0x20, 0x3d, 0x20, 0x44, 0x69, 0x61, 0x6c, 0x6f, 0x67, -+ 0x28, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x3d, 0x70, 0x61, -+ 0x72, 0x65, 0x6e, 0x74, 0x2c, 0x20, 0x63, 0x61, 0x6e, 0x63, -+ 0x65, 0x6c, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x3d, 0x63, 0x61, -+ 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x29, -+ 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, -+ 0x20, 0x72, 0x69, 0x63, 0x68, 0x5f, 0x74, 0x65, 0x78, 0x74, -+ 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x62, 0x6f, 0x78, 0x2e, 0x73, 0x65, 0x74, 0x5f, 0x68, -+ 0x74, 0x6d, 0x6c, 0x28, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, -+ 0x65, 0x29, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, -+ 0x73, 0x65, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x62, 0x6f, 0x78, 0x2e, 0x73, 0x65, 0x74, -+ 0x5f, 0x74, 0x65, 0x78, 0x74, 0x28, 0x6d, 0x65, 0x73, 0x73, -+ 0x61, 0x67, 0x65, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x69, 0x66, 0x20, 0x69, 0x63, 0x6f, 0x6e, 0x20, -+ 0x69, 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x4e, 0x6f, 0x6e, -+ 0x65, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x62, 0x6f, 0x78, 0x2e, 0x73, 0x65, 0x74, 0x5f, -+ 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x62, 0x6f, -+ 0x78, 0x5f, 0x69, 0x63, 0x6f, 0x6e, 0x28, 0x69, 0x63, 0x6f, -+ 0x6e, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x69, 0x66, 0x20, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x20, 0x69, -+ 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x4e, 0x6f, 0x6e, 0x65, -+ 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x69, -+ 0x74, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0x51, 0x74, 0x57, 0x69, -+ 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x51, 0x41, 0x70, 0x70, -+ 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x69, -+ 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x28, 0x29, 0x2e, -+ 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, -+ 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x28, 0x29, 0x0d, 0x0a, 0x0d, -+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, -+ 0x66, 0x20, 0x6c, 0x65, 0x6e, 0x28, 0x70, 0x61, 0x72, 0x65, -+ 0x6e, 0x74, 0x5f, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x29, 0x20, -+ 0x3e, 0x20, 0x30, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x69, -+ 0x74, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0x27, 0x20, 0x2d, 0x20, -+ 0x27, 0x2e, 0x6a, 0x6f, 0x69, 0x6e, 0x28, 0x28, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x72, 0x65, -+ 0x6e, 0x74, 0x5f, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x2c, 0x0d, -+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x69, 0x74, -+ 0x6c, 0x65, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x0d, -+ 0x0a, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x62, 0x6f, 0x78, 0x2e, 0x73, 0x65, 0x74, -+ 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x54, 0x69, 0x74, 0x6c, -+ 0x65, 0x28, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x29, 0x0d, 0x0a, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, -+ 0x72, 0x6e, 0x20, 0x62, 0x6f, 0x78, 0x2e, 0x65, 0x78, 0x65, -+ 0x63, 0x28, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x51, 0x74, 0x43, -+ 0x6f, 0x72, 0x65, 0x2e, 0x71, 0x44, 0x65, 0x62, 0x75, 0x67, -+ 0x28, 0x27, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x20, -+ 0x73, 0x79, 0x73, 0x2e, 0x65, 0x78, 0x63, 0x65, 0x70, 0x74, -+ 0x68, 0x6f, 0x6f, 0x6b, 0x20, 0x74, 0x6f, 0x20, 0x70, 0x72, -+ 0x6f, 0x76, 0x69, 0x64, 0x65, 0x20, 0x64, 0x69, 0x61, 0x6c, -+ 0x6f, 0x67, 0x27, 0x29, 0x0d, 0x0a, 0x73, 0x79, 0x73, 0x2e, -+ 0x65, 0x78, 0x63, 0x65, 0x70, 0x74, 0x68, 0x6f, 0x6f, 0x6b, -+ 0x20, 0x3d, 0x20, 0x65, 0x78, 0x63, 0x65, 0x70, 0x74, 0x69, -+ 0x6f, 0x6e, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, -+ 0x5f, 0x62, 0x6f, 0x78, 0x0d, 0x0a, 0x00 -+}; -diff --git a/designer/excepthook.py b/designer/excepthook.py -new file mode 100644 -index 0000000..1c4aaa9 ---- /dev/null -+++ b/designer/excepthook.py -@@ -0,0 +1,170 @@ -+import functools -+import sys -+import traceback -+ -+from PyQt5 import QtCore, QtWidgets -+ -+QtCore.qDebug('Importing module for exception dialogs') -+ -+def exception_message_box(excType=None, excValue=None, tracebackobj=None): -+ message = traceback.format_exception(excType, excValue, tracebackobj) -+ message = ''.join(message) -+ -+ dialog( -+ parent=None, -+ title='Exception', -+ message=message, -+ icon=QtWidgets.QMessageBox.Critical, -+ ) -+ -+class FittedTextBrowser(QtWidgets.QTextBrowser): -+ def sizeHint(self): -+ default = super().sizeHint() -+ -+ if not default.isValid(): -+ return default -+ -+ document_size = self.document().size() -+ -+ desktops = QtWidgets.QApplication.desktop() -+ screen_number = desktops.screenNumber(self.parent()) -+ geometry = desktops.screenGeometry(screen_number) -+ -+ if document_size.width() == 0: -+ document_size.setWidth(geometry.width() * 0.25) -+ if document_size.height() == 0: -+ document_size.setHeight(geometry.height() * 0.4) -+ -+ scrollbar_width = QtWidgets.QApplication.style().pixelMetric( -+ QtWidgets.QStyle.PM_ScrollBarExtent -+ ) -+ -+ width = sum(( -+ document_size.width(), -+ self.contentsMargins().left(), -+ self.contentsMargins().right(), -+ scrollbar_width, -+ )) -+ -+ height = sum(( -+ document_size.height(), -+ self.contentsMargins().top(), -+ self.contentsMargins().bottom(), -+ scrollbar_width, -+ )) -+ -+ return QtCore.QSize(width, height) -+ -+ -+class DialogUi: -+ def __init__(self, parent): -+ self.layout = QtWidgets.QGridLayout(parent) -+ self.icon = QtWidgets.QLabel(parent) -+ self.message = FittedTextBrowser(parent) -+ self.copy = QtWidgets.QPushButton(parent) -+ self.buttons = QtWidgets.QDialogButtonBox(parent) -+ -+ self.copy.setText('Copy To Clipboard') -+ -+ self.layout.addWidget(self.icon, 0, 0) -+ self.layout.addWidget(self.message, 0, 1, 1, 2) -+ self.layout.addWidget(self.copy, 1, 1) -+ self.layout.addWidget(self.buttons, 1, 2) -+ -+ self.layout.setAlignment(self.copy, QtCore.Qt.AlignLeft) -+ -+ self.layout.setRowStretch(0, 1) -+ self.layout.setColumnStretch(1, 1) -+ -+ -+class Dialog(QtWidgets.QDialog): -+ def __init__(self, *args, cancellable=False, **kwargs): -+ super().__init__(*args, **kwargs) -+ -+ self.ui = DialogUi(parent=self) -+ -+ self.ui.buttons.accepted.connect(self.accept) -+ self.ui.buttons.rejected.connect(self.reject) -+ -+ self.ui.copy.clicked.connect(self.copy) -+ -+ self.setLayout(self.ui.layout) -+ buttons = QtWidgets.QDialogButtonBox.Ok -+ if cancellable: -+ buttons |= QtWidgets.QDialogButtonBox.Cancel -+ -+ self.ui.buttons.setStandardButtons(buttons) -+ -+ self.text = None -+ self.html = None -+ -+ self.cached_maximum_size = self.maximumSize() -+ -+ desktops = QtWidgets.QApplication.desktop() -+ screen_number = desktops.screenNumber(self.parent()) -+ geometry = desktops.screenGeometry(screen_number) -+ -+ self.setMaximumHeight(geometry.height() * 0.7) -+ self.setMaximumWidth(geometry.width() * 0.7) -+ -+ def copy(self): -+ QtWidgets.QApplication.clipboard().setText( -+ self.ui.message.toPlainText() + '\\n' -+ ) -+ -+ def set_text(self, text): -+ self.ui.message.setPlainText(text) -+ -+ self.html = None -+ self.text = text -+ -+ self.ui.message.setLineWrapMode(QtWidgets.QTextEdit.NoWrap) -+ -+ def set_html(self, html): -+ self.ui.message.setHtml(html) -+ -+ self.html = html -+ self.text = None -+ -+ self.ui.message.setLineWrapMode(QtWidgets.QTextEdit.WidgetWidth) -+ -+ def set_message_box_icon(self, icon): -+ self.ui.icon.setPixmap(QtWidgets.QMessageBox.standardIcon(icon)) -+ -+ def exec(self): -+ QtCore.QTimer.singleShot(10, functools.partial( -+ self.setMaximumSize, -+ self.cached_maximum_size, -+ )) -+ -+ return super().exec() -+ -+ -+def dialog(parent, message, title=None, icon=None, -+ rich_text=False, cancellable=False): -+ box = Dialog(parent=parent, cancellable=cancellable) -+ -+ if rich_text: -+ box.set_html(message) -+ else: -+ box.set_text(message) -+ -+ if icon is not None: -+ box.set_message_box_icon(icon) -+ -+ if title is not None: -+ parent_title = QtWidgets.QApplication.instance().applicationName() -+ -+ if len(parent_title) > 0: -+ title = ' - '.join(( -+ parent_title, -+ title, -+ )) -+ -+ -+ box.setWindowTitle(title) -+ -+ return box.exec() -+ -+QtCore.qDebug('Setting sys.excepthook to provide dialog') -+sys.excepthook = exception_message_box -diff --git a/designer/generate_module_literal.py b/designer/generate_module_literal.py -new file mode 100644 -index 0000000..cc6b4de ---- /dev/null -+++ b/designer/generate_module_literal.py -@@ -0,0 +1,35 @@ -+import os -+import itertools -+ -+ -+# https://repl.it/IwNE/4 -+def chunker(iterable, n): -+ "Collect data into fixed-length chunks or blocks except last due to lack of fill." -+ # chunker('ABCDEFG', 3) --> ABC DEF G" -+ -+ i = iter(iterable) -+ -+ while True: -+ t = tuple(next(i) for _ in range(n)) -+ -+ if len(t) > 0: -+ yield t -+ else: -+ break -+ -+ -+with open('excepthook.py', 'rb') as f: -+ raw = f.read() -+ -+with open('excepthook.c', 'w', newline='\n') as f: -+ f.write('const char * moduleName = "exceptiondialog";\n\n') -+ f.write('const char moduleCode[] = {\n') -+ -+ indent = ' ' * 4 -+ -+ chunks = chunker(itertools.chain(raw, b'\0'), 10) -+ lines = (', '.join('0x{:02x}'.format(b) for b in chunk) for chunk in chunks) -+ lines = (',\n'.join(indent + line for line in lines)) -+ for line in lines: -+ f.write(line) -+ f.write("\n};\n") -diff --git a/designer/pluginloader.cpp b/designer/pluginloader.cpp -index d4fb17a..d9f77ec 100644 ---- a/designer/pluginloader.cpp -+++ b/designer/pluginloader.cpp -@@ -25,6 +25,7 @@ - - #include - -+#include - #include - #include - #include -@@ -36,6 +37,114 @@ - - #include "../qpy/QtDesigner/qpydesignercustomwidgetplugin.h" - -+#include "excepthook.c" -+ -+ -+void setupExceptHookDialog(void) -+{ -+ qDebug() << "Preparing to import module"; -+ qDebug() << PyBytes_AS_STRING(PyUnicode_AsEncodedString(PyObject_Str(PySys_GetObject("path")), "utf-8", "error 1?")); -+ // https://stackoverflow.com/a/42853449/228539 -+ PyObject *pyModule = PyModule_New(moduleName); -+ // Set properties on the new module object -+ PyModule_AddStringConstant(pyModule, "__file__", ""); -+ PyObject *localDict = PyModule_GetDict(pyModule); // Returns a borrowed reference: no need to Py_DECREF() it once we are done -+ PyObject *builtins = PyEval_GetBuiltins(); // Returns a borrowed reference: no need to Py_DECREF() it once we are done -+ PyDict_SetItemString(localDict, "__builtins__", builtins); -+ -+ qDebug() << "About to import module"; -+ -+ // Define code in the newly created module -+ PyObject *pyValue = PyRun_String(moduleCode, Py_file_input, localDict, localDict); -+ qDebug() << "Code just run"; -+ if (pyValue == NULL) -+ { -+ qDebug() << "An error occurred while importing the module"; -+ -+ char * full_backtrace = NULL; -+ -+ if (PyErr_Occurred() != NULL) { -+ qDebug() << "PyErr_Occurred() != NULL"; -+ PyObject *ptype, *pvalue, *ptraceback; -+ PyObject *pystr, *module_name, *pyth_module, *pyth_func; -+ char *str; -+ char *error_description; -+ -+ PyErr_Fetch(&ptype, &pvalue, &ptraceback); -+ qDebug() << "ptype == NULL : " << (ptype == NULL); -+ qDebug() << "pvalue == NULL : " << (pvalue == NULL); -+ qDebug() << "ptraceback == NULL : " << (ptraceback == NULL); -+ pystr = PyObject_Str(pvalue); -+ qDebug() << "pystr == NULL : " << (pystr == NULL); -+ pystr = PyUnicode_AsEncodedString(pystr, "utf-8", "error 1?"); -+ qDebug() << "pystr == NULL : " << (pystr == NULL); -+ str = PyBytes_AS_STRING(pystr); -+ qDebug() << "str == NULL : " << (str == NULL); -+ if (str != NULL) -+ { -+ qDebug() << "str: " << str; -+ } -+ Py_DECREF(pystr); -+ error_description = strdup(str); -+ qDebug() << "error_description == NULL : " << (error_description == NULL); -+ if (error_description != NULL) -+ { -+ qDebug() << "error_description: " << error_description; -+ } -+ -+ /* See if we can get a full traceback */ -+ module_name = PyUnicode_Decode("traceback", 9, "utf-8", "error 2?"); -+ pyth_module = PyImport_Import(module_name); -+ Py_DECREF(module_name); -+ -+ qDebug() << "pyth_module == NULL : " << (pyth_module == NULL); -+ if (pyth_module == NULL) { -+ full_backtrace = NULL; -+ return; -+ } -+ -+ pyth_func = PyObject_GetAttrString(pyth_module, "format_exception"); -+ if (pyth_func && PyCallable_Check(pyth_func)) -+ { -+ qDebug() << "pyth_func && PyCallable_Check(pyth_func)"; -+ PyObject *pyth_val; -+ -+ pyth_val = PyObject_CallFunctionObjArgs(pyth_func, ptype, pvalue, ptraceback, Py_None, Py_True, NULL); -+ qDebug() << "pyth_val == NULL : " << (pyth_val == NULL); -+ -+ pystr = PyObject_Str(pyth_val); -+ qDebug() << "pystr == NULL : " << (pystr == NULL); -+ -+ pystr = PyUnicode_AsEncodedString(pystr, "utf-8", "error 3?"); -+ qDebug() << "pystr == NULL : " << (pystr == NULL); -+ -+ str = PyBytes_AS_STRING(pystr); -+ qDebug() << "str == NULL : " << (str == NULL); -+ -+ Py_DECREF(pystr); -+ full_backtrace = strdup(str); -+ Py_DECREF(pyth_val); -+ } -+ } -+ -+ if (full_backtrace != NULL) -+ { -+ qDebug() << "About to print backtrace"; -+ qDebug() << full_backtrace; -+ } -+ else -+ { -+ qDebug() << "Backtrace was NULL"; -+ } -+ } -+ else -+ { -+ qDebug() << "About to decref"; -+ Py_DECREF(pyValue); -+ } -+ -+ qDebug() << "Done importing module"; -+} - - // Construct the collection of Python widgets. - PyCustomWidgets::PyCustomWidgets(QObject *parent) : QObject(parent), -@@ -140,6 +249,7 @@ PyCustomWidgets::PyCustomWidgets(QObject *parent) : QObject(parent), - PyGILState_STATE gil_state = PyGILState_Ensure(); - #endif - -+ setupExceptHookDialog(); - bool fatal = importPlugins(dir, plugins); - - #if defined(WITH_THREAD) diff --git a/pluginloader.5.15.0.patch b/pluginloader.5.15.0.patch deleted file mode 100644 index 0af856245..000000000 --- a/pluginloader.5.15.0.patch +++ /dev/null @@ -1,858 +0,0 @@ -diff --git a/designer/excepthook.c b/designer/excepthook.c -new file mode 100644 -index 0000000..6a575af ---- /dev/null -+++ b/designer/excepthook.c -@@ -0,0 +1,500 @@ -+const char * moduleName = "exceptiondialog"; -+ -+const char moduleCode[] = { -+ 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x66, 0x75, 0x6e, -+ 0x63, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x0d, 0x0a, 0x69, 0x6d, -+ 0x70, 0x6f, 0x72, 0x74, 0x20, 0x73, 0x79, 0x73, 0x0d, 0x0a, -+ 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x74, 0x72, 0x61, -+ 0x63, 0x65, 0x62, 0x61, 0x63, 0x6b, 0x0d, 0x0a, 0x0d, 0x0a, -+ 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x50, 0x79, 0x51, 0x74, 0x35, -+ 0x20, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x51, 0x74, -+ 0x43, 0x6f, 0x72, 0x65, 0x2c, 0x20, 0x51, 0x74, 0x57, 0x69, -+ 0x64, 0x67, 0x65, 0x74, 0x73, 0x0d, 0x0a, 0x0d, 0x0a, 0x51, -+ 0x74, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x71, 0x44, 0x65, 0x62, -+ 0x75, 0x67, 0x28, 0x27, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, -+ 0x69, 0x6e, 0x67, 0x20, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, -+ 0x20, 0x66, 0x6f, 0x72, 0x20, 0x65, 0x78, 0x63, 0x65, 0x70, -+ 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x64, 0x69, 0x61, 0x6c, 0x6f, -+ 0x67, 0x73, 0x27, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x64, 0x65, -+ 0x66, 0x20, 0x65, 0x78, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6f, -+ 0x6e, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, -+ 0x62, 0x6f, 0x78, 0x28, 0x65, 0x78, 0x63, 0x54, 0x79, 0x70, -+ 0x65, 0x3d, 0x4e, 0x6f, 0x6e, 0x65, 0x2c, 0x20, 0x65, 0x78, -+ 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x3d, 0x4e, 0x6f, 0x6e, -+ 0x65, 0x2c, 0x20, 0x74, 0x72, 0x61, 0x63, 0x65, 0x62, 0x61, -+ 0x63, 0x6b, 0x6f, 0x62, 0x6a, 0x3d, 0x4e, 0x6f, 0x6e, 0x65, -+ 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x65, -+ 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x3d, 0x20, 0x74, 0x72, -+ 0x61, 0x63, 0x65, 0x62, 0x61, 0x63, 0x6b, 0x2e, 0x66, 0x6f, -+ 0x72, 0x6d, 0x61, 0x74, 0x5f, 0x65, 0x78, 0x63, 0x65, 0x70, -+ 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x65, 0x78, 0x63, 0x54, 0x79, -+ 0x70, 0x65, 0x2c, 0x20, 0x65, 0x78, 0x63, 0x56, 0x61, 0x6c, -+ 0x75, 0x65, 0x2c, 0x20, 0x74, 0x72, 0x61, 0x63, 0x65, 0x62, -+ 0x61, 0x63, 0x6b, 0x6f, 0x62, 0x6a, 0x29, 0x0d, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, -+ 0x20, 0x3d, 0x20, 0x27, 0x27, 0x2e, 0x6a, 0x6f, 0x69, 0x6e, -+ 0x28, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x29, 0x0d, -+ 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x69, 0x61, -+ 0x6c, 0x6f, 0x67, 0x28, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, -+ 0x3d, 0x4e, 0x6f, 0x6e, 0x65, 0x2c, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x69, 0x74, 0x6c, -+ 0x65, 0x3d, 0x27, 0x45, 0x78, 0x63, 0x65, 0x70, 0x74, 0x69, -+ 0x6f, 0x6e, 0x27, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, -+ 0x65, 0x3d, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2c, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x69, 0x63, 0x6f, 0x6e, 0x3d, 0x51, 0x74, 0x57, 0x69, 0x64, -+ 0x67, 0x65, 0x74, 0x73, 0x2e, 0x51, 0x4d, 0x65, 0x73, 0x73, -+ 0x61, 0x67, 0x65, 0x42, 0x6f, 0x78, 0x2e, 0x43, 0x72, 0x69, -+ 0x74, 0x69, 0x63, 0x61, 0x6c, 0x2c, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x63, 0x6c, 0x61, -+ 0x73, 0x73, 0x20, 0x46, 0x69, 0x74, 0x74, 0x65, 0x64, 0x54, -+ 0x65, 0x78, 0x74, 0x42, 0x72, 0x6f, 0x77, 0x73, 0x65, 0x72, -+ 0x28, 0x51, 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, -+ 0x2e, 0x51, 0x54, 0x65, 0x78, 0x74, 0x42, 0x72, 0x6f, 0x77, -+ 0x73, 0x65, 0x72, 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, -+ 0x20, 0x64, 0x65, 0x66, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x48, -+ 0x69, 0x6e, 0x74, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x29, 0x3a, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x20, 0x3d, 0x20, -+ 0x73, 0x75, 0x70, 0x65, 0x72, 0x28, 0x29, 0x2e, 0x73, 0x69, -+ 0x7a, 0x65, 0x48, 0x69, 0x6e, 0x74, 0x28, 0x29, 0x0d, 0x0a, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x64, 0x65, 0x66, -+ 0x61, 0x75, 0x6c, 0x74, 0x2e, 0x69, 0x73, 0x56, 0x61, 0x6c, -+ 0x69, 0x64, 0x28, 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, -+ 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x64, 0x65, 0x66, 0x61, -+ 0x75, 0x6c, 0x74, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, -+ 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x3d, -+ 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x64, 0x6f, 0x63, 0x75, -+ 0x6d, 0x65, 0x6e, 0x74, 0x28, 0x29, 0x2e, 0x73, 0x69, 0x7a, -+ 0x65, 0x28, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x73, 0x6b, 0x74, -+ 0x6f, 0x70, 0x73, 0x20, 0x3d, 0x20, 0x51, 0x74, 0x57, 0x69, -+ 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x51, 0x41, 0x70, 0x70, -+ 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x64, -+ 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x28, 0x29, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x63, -+ 0x72, 0x65, 0x65, 0x6e, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, -+ 0x72, 0x20, 0x3d, 0x20, 0x64, 0x65, 0x73, 0x6b, 0x74, 0x6f, -+ 0x70, 0x73, 0x2e, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x4e, -+ 0x75, 0x6d, 0x62, 0x65, 0x72, 0x28, 0x73, 0x65, 0x6c, 0x66, -+ 0x2e, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x28, 0x29, 0x29, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x67, 0x65, 0x6f, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x20, 0x3d, -+ 0x20, 0x64, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x73, 0x2e, -+ 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x47, 0x65, 0x6f, 0x6d, -+ 0x65, 0x74, 0x72, 0x79, 0x28, 0x73, 0x63, 0x72, 0x65, 0x65, -+ 0x6e, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x29, 0x0d, -+ 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x69, 0x66, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, -+ 0x6e, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x2e, 0x77, 0x69, -+ 0x64, 0x74, 0x68, 0x28, 0x29, 0x20, 0x3d, 0x3d, 0x20, 0x30, -+ 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, -+ 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x2e, 0x73, -+ 0x65, 0x74, 0x57, 0x69, 0x64, 0x74, 0x68, 0x28, 0x67, 0x65, -+ 0x6f, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x77, 0x69, 0x64, -+ 0x74, 0x68, 0x28, 0x29, 0x20, 0x2a, 0x20, 0x30, 0x2e, 0x32, -+ 0x35, 0x29, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x69, 0x66, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, -+ 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x2e, 0x68, -+ 0x65, 0x69, 0x67, 0x68, 0x74, 0x28, 0x29, 0x20, 0x3d, 0x3d, -+ 0x20, 0x30, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, 0x63, -+ 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, -+ 0x2e, 0x73, 0x65, 0x74, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, -+ 0x28, 0x67, 0x65, 0x6f, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, -+ 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x28, 0x29, 0x20, 0x2a, -+ 0x20, 0x30, 0x2e, 0x34, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x63, 0x72, -+ 0x6f, 0x6c, 0x6c, 0x62, 0x61, 0x72, 0x5f, 0x77, 0x69, 0x64, -+ 0x74, 0x68, 0x20, 0x3d, 0x20, 0x51, 0x74, 0x57, 0x69, 0x64, -+ 0x67, 0x65, 0x74, 0x73, 0x2e, 0x51, 0x41, 0x70, 0x70, 0x6c, -+ 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x73, 0x74, -+ 0x79, 0x6c, 0x65, 0x28, 0x29, 0x2e, 0x70, 0x69, 0x78, 0x65, -+ 0x6c, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x28, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x51, 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, -+ 0x73, 0x2e, 0x51, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x2e, 0x50, -+ 0x4d, 0x5f, 0x53, 0x63, 0x72, 0x6f, 0x6c, 0x6c, 0x42, 0x61, -+ 0x72, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x74, 0x0d, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x0d, 0x0a, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x77, 0x69, 0x64, 0x74, 0x68, 0x20, 0x3d, 0x20, 0x73, 0x75, -+ 0x6d, 0x28, 0x28, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, 0x63, -+ 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, -+ 0x2e, 0x77, 0x69, 0x64, 0x74, 0x68, 0x28, 0x29, 0x2c, 0x0d, -+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x63, 0x6f, -+ 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x4d, 0x61, 0x72, 0x67, -+ 0x69, 0x6e, 0x73, 0x28, 0x29, 0x2e, 0x6c, 0x65, 0x66, 0x74, -+ 0x28, 0x29, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, -+ 0x66, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, -+ 0x4d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x73, 0x28, 0x29, 0x2e, -+ 0x72, 0x69, 0x67, 0x68, 0x74, 0x28, 0x29, 0x2c, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x73, 0x63, 0x72, 0x6f, 0x6c, 0x6c, 0x62, 0x61, -+ 0x72, 0x5f, 0x77, 0x69, 0x64, 0x74, 0x68, 0x2c, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, -+ 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x20, 0x3d, -+ 0x20, 0x73, 0x75, 0x6d, 0x28, 0x28, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x73, -+ 0x69, 0x7a, 0x65, 0x2e, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, -+ 0x28, 0x29, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, -+ 0x66, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, -+ 0x4d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x73, 0x28, 0x29, 0x2e, -+ 0x74, 0x6f, 0x70, 0x28, 0x29, 0x2c, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, -+ 0x6e, 0x74, 0x73, 0x4d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x73, -+ 0x28, 0x29, 0x2e, 0x62, 0x6f, 0x74, 0x74, 0x6f, 0x6d, 0x28, -+ 0x29, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x63, 0x72, 0x6f, -+ 0x6c, 0x6c, 0x62, 0x61, 0x72, 0x5f, 0x77, 0x69, 0x64, 0x74, -+ 0x68, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x29, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, -+ 0x72, 0x6e, 0x20, 0x51, 0x74, 0x43, 0x6f, 0x72, 0x65, 0x2e, -+ 0x51, 0x53, 0x69, 0x7a, 0x65, 0x28, 0x77, 0x69, 0x64, 0x74, -+ 0x68, 0x2c, 0x20, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x29, -+ 0x0d, 0x0a, 0x0d, 0x0a, 0x0d, 0x0a, 0x63, 0x6c, 0x61, 0x73, -+ 0x73, 0x20, 0x44, 0x69, 0x61, 0x6c, 0x6f, 0x67, 0x55, 0x69, -+ 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x66, -+ 0x20, 0x5f, 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x5f, 0x5f, 0x28, -+ 0x73, 0x65, 0x6c, 0x66, 0x2c, 0x20, 0x70, 0x61, 0x72, 0x65, -+ 0x6e, 0x74, 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x6c, -+ 0x61, 0x79, 0x6f, 0x75, 0x74, 0x20, 0x3d, 0x20, 0x51, 0x74, -+ 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x51, 0x47, -+ 0x72, 0x69, 0x64, 0x4c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x28, -+ 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x29, 0x0d, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, -+ 0x66, 0x2e, 0x69, 0x63, 0x6f, 0x6e, 0x20, 0x3d, 0x20, 0x51, -+ 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x51, -+ 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x28, 0x70, 0x61, 0x72, 0x65, -+ 0x6e, 0x74, 0x29, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x6d, 0x65, -+ 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x3d, 0x20, 0x46, 0x69, -+ 0x74, 0x74, 0x65, 0x64, 0x54, 0x65, 0x78, 0x74, 0x42, 0x72, -+ 0x6f, 0x77, 0x73, 0x65, 0x72, 0x28, 0x70, 0x61, 0x72, 0x65, -+ 0x6e, 0x74, 0x29, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x63, 0x6f, -+ 0x70, 0x79, 0x20, 0x3d, 0x20, 0x51, 0x74, 0x57, 0x69, 0x64, -+ 0x67, 0x65, 0x74, 0x73, 0x2e, 0x51, 0x50, 0x75, 0x73, 0x68, -+ 0x42, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x28, 0x70, 0x61, 0x72, -+ 0x65, 0x6e, 0x74, 0x29, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x62, -+ 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x73, 0x20, 0x3d, 0x20, 0x51, -+ 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x51, -+ 0x44, 0x69, 0x61, 0x6c, 0x6f, 0x67, 0x42, 0x75, 0x74, 0x74, -+ 0x6f, 0x6e, 0x42, 0x6f, 0x78, 0x28, 0x70, 0x61, 0x72, 0x65, -+ 0x6e, 0x74, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, -+ 0x63, 0x6f, 0x70, 0x79, 0x2e, 0x73, 0x65, 0x74, 0x54, 0x65, -+ 0x78, 0x74, 0x28, 0x27, 0x43, 0x6f, 0x70, 0x79, 0x20, 0x54, -+ 0x6f, 0x20, 0x43, 0x6c, 0x69, 0x70, 0x62, 0x6f, 0x61, 0x72, -+ 0x64, 0x27, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, -+ 0x6c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x2e, 0x61, 0x64, 0x64, -+ 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x28, 0x73, 0x65, 0x6c, -+ 0x66, 0x2e, 0x69, 0x63, 0x6f, 0x6e, 0x2c, 0x20, 0x30, 0x2c, -+ 0x20, 0x30, 0x29, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x6c, 0x61, -+ 0x79, 0x6f, 0x75, 0x74, 0x2e, 0x61, 0x64, 0x64, 0x57, 0x69, -+ 0x64, 0x67, 0x65, 0x74, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, -+ 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2c, 0x20, 0x30, -+ 0x2c, 0x20, 0x31, 0x2c, 0x20, 0x31, 0x2c, 0x20, 0x32, 0x29, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x6c, 0x61, 0x79, 0x6f, 0x75, -+ 0x74, 0x2e, 0x61, 0x64, 0x64, 0x57, 0x69, 0x64, 0x67, 0x65, -+ 0x74, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x63, 0x6f, 0x70, -+ 0x79, 0x2c, 0x20, 0x31, 0x2c, 0x20, 0x31, 0x29, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, -+ 0x6c, 0x66, 0x2e, 0x6c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x2e, -+ 0x61, 0x64, 0x64, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x28, -+ 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x62, 0x75, 0x74, 0x74, 0x6f, -+ 0x6e, 0x73, 0x2c, 0x20, 0x31, 0x2c, 0x20, 0x32, 0x29, 0x0d, -+ 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x6c, 0x61, 0x79, 0x6f, -+ 0x75, 0x74, 0x2e, 0x73, 0x65, 0x74, 0x41, 0x6c, 0x69, 0x67, -+ 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x28, 0x73, 0x65, 0x6c, 0x66, -+ 0x2e, 0x63, 0x6f, 0x70, 0x79, 0x2c, 0x20, 0x51, 0x74, 0x43, -+ 0x6f, 0x72, 0x65, 0x2e, 0x51, 0x74, 0x2e, 0x41, 0x6c, 0x69, -+ 0x67, 0x6e, 0x4c, 0x65, 0x66, 0x74, 0x29, 0x0d, 0x0a, 0x0d, -+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, -+ 0x65, 0x6c, 0x66, 0x2e, 0x6c, 0x61, 0x79, 0x6f, 0x75, 0x74, -+ 0x2e, 0x73, 0x65, 0x74, 0x52, 0x6f, 0x77, 0x53, 0x74, 0x72, -+ 0x65, 0x74, 0x63, 0x68, 0x28, 0x30, 0x2c, 0x20, 0x31, 0x29, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x6c, 0x61, 0x79, 0x6f, 0x75, -+ 0x74, 0x2e, 0x73, 0x65, 0x74, 0x43, 0x6f, 0x6c, 0x75, 0x6d, -+ 0x6e, 0x53, 0x74, 0x72, 0x65, 0x74, 0x63, 0x68, 0x28, 0x31, -+ 0x2c, 0x20, 0x31, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x0d, 0x0a, -+ 0x63, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x44, 0x69, 0x61, 0x6c, -+ 0x6f, 0x67, 0x28, 0x51, 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, -+ 0x74, 0x73, 0x2e, 0x51, 0x44, 0x69, 0x61, 0x6c, 0x6f, 0x67, -+ 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, -+ 0x66, 0x20, 0x5f, 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x5f, 0x5f, -+ 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2c, 0x20, 0x2a, 0x61, 0x72, -+ 0x67, 0x73, 0x2c, 0x20, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, -+ 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x3d, 0x46, 0x61, 0x6c, 0x73, -+ 0x65, 0x2c, 0x20, 0x2a, 0x2a, 0x6b, 0x77, 0x61, 0x72, 0x67, -+ 0x73, 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x73, 0x75, 0x70, 0x65, 0x72, 0x28, 0x29, -+ 0x2e, 0x5f, 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x5f, 0x5f, 0x28, -+ 0x2a, 0x61, 0x72, 0x67, 0x73, 0x2c, 0x20, 0x2a, 0x2a, 0x6b, -+ 0x77, 0x61, 0x72, 0x67, 0x73, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, -+ 0x6c, 0x66, 0x2e, 0x75, 0x69, 0x20, 0x3d, 0x20, 0x44, 0x69, -+ 0x61, 0x6c, 0x6f, 0x67, 0x55, 0x69, 0x28, 0x70, 0x61, 0x72, -+ 0x65, 0x6e, 0x74, 0x3d, 0x73, 0x65, 0x6c, 0x66, 0x29, 0x0d, -+ 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x75, 0x69, 0x2e, 0x62, -+ 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x73, 0x2e, 0x61, 0x63, 0x63, -+ 0x65, 0x70, 0x74, 0x65, 0x64, 0x2e, 0x63, 0x6f, 0x6e, 0x6e, -+ 0x65, 0x63, 0x74, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x61, -+ 0x63, 0x63, 0x65, 0x70, 0x74, 0x29, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, -+ 0x2e, 0x75, 0x69, 0x2e, 0x62, 0x75, 0x74, 0x74, 0x6f, 0x6e, -+ 0x73, 0x2e, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x65, 0x64, -+ 0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x28, 0x73, -+ 0x65, 0x6c, 0x66, 0x2e, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, -+ 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x75, 0x69, -+ 0x2e, 0x63, 0x6f, 0x70, 0x79, 0x2e, 0x63, 0x6c, 0x69, 0x63, -+ 0x6b, 0x65, 0x64, 0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, -+ 0x74, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x63, 0x6f, 0x70, -+ 0x79, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x73, -+ 0x65, 0x74, 0x4c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x28, 0x73, -+ 0x65, 0x6c, 0x66, 0x2e, 0x75, 0x69, 0x2e, 0x6c, 0x61, 0x79, -+ 0x6f, 0x75, 0x74, 0x29, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x62, 0x75, 0x74, 0x74, 0x6f, 0x6e, -+ 0x73, 0x20, 0x3d, 0x20, 0x51, 0x74, 0x57, 0x69, 0x64, 0x67, -+ 0x65, 0x74, 0x73, 0x2e, 0x51, 0x44, 0x69, 0x61, 0x6c, 0x6f, -+ 0x67, 0x42, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x42, 0x6f, 0x78, -+ 0x2e, 0x4f, 0x6b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x63, 0x61, 0x6e, 0x63, -+ 0x65, 0x6c, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x3a, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x62, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x73, 0x20, -+ 0x7c, 0x3d, 0x20, 0x51, 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, -+ 0x74, 0x73, 0x2e, 0x51, 0x44, 0x69, 0x61, 0x6c, 0x6f, 0x67, -+ 0x42, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x42, 0x6f, 0x78, 0x2e, -+ 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x0d, 0x0a, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, -+ 0x6c, 0x66, 0x2e, 0x75, 0x69, 0x2e, 0x62, 0x75, 0x74, 0x74, -+ 0x6f, 0x6e, 0x73, 0x2e, 0x73, 0x65, 0x74, 0x53, 0x74, 0x61, -+ 0x6e, 0x64, 0x61, 0x72, 0x64, 0x42, 0x75, 0x74, 0x74, 0x6f, -+ 0x6e, 0x73, 0x28, 0x62, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x73, -+ 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x65, -+ 0x78, 0x74, 0x20, 0x3d, 0x20, 0x4e, 0x6f, 0x6e, 0x65, 0x0d, -+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, -+ 0x65, 0x6c, 0x66, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x20, 0x3d, -+ 0x20, 0x4e, 0x6f, 0x6e, 0x65, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, -+ 0x66, 0x2e, 0x63, 0x61, 0x63, 0x68, 0x65, 0x64, 0x5f, 0x6d, -+ 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x5f, 0x73, 0x69, 0x7a, -+ 0x65, 0x20, 0x3d, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x6d, -+ 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x53, 0x69, 0x7a, 0x65, -+ 0x28, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x73, 0x6b, 0x74, 0x6f, -+ 0x70, 0x73, 0x20, 0x3d, 0x20, 0x51, 0x74, 0x57, 0x69, 0x64, -+ 0x67, 0x65, 0x74, 0x73, 0x2e, 0x51, 0x41, 0x70, 0x70, 0x6c, -+ 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x64, 0x65, -+ 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x28, 0x29, 0x0d, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x63, 0x72, -+ 0x65, 0x65, 0x6e, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, -+ 0x20, 0x3d, 0x20, 0x64, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, -+ 0x73, 0x2e, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x4e, 0x75, -+ 0x6d, 0x62, 0x65, 0x72, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, -+ 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x28, 0x29, 0x29, 0x0d, -+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x67, -+ 0x65, 0x6f, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x20, 0x3d, 0x20, -+ 0x64, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x73, 0x2e, 0x73, -+ 0x63, 0x72, 0x65, 0x65, 0x6e, 0x47, 0x65, 0x6f, 0x6d, 0x65, -+ 0x74, 0x72, 0x79, 0x28, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, -+ 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x29, 0x0d, 0x0a, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x73, 0x65, 0x74, 0x4d, 0x61, -+ 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x48, 0x65, 0x69, 0x67, 0x68, -+ 0x74, 0x28, 0x67, 0x65, 0x6f, 0x6d, 0x65, 0x74, 0x72, 0x79, -+ 0x2e, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x28, 0x29, 0x20, -+ 0x2a, 0x20, 0x30, 0x2e, 0x37, 0x29, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, -+ 0x2e, 0x73, 0x65, 0x74, 0x4d, 0x61, 0x78, 0x69, 0x6d, 0x75, -+ 0x6d, 0x57, 0x69, 0x64, 0x74, 0x68, 0x28, 0x67, 0x65, 0x6f, -+ 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x77, 0x69, 0x64, 0x74, -+ 0x68, 0x28, 0x29, 0x20, 0x2a, 0x20, 0x30, 0x2e, 0x37, 0x29, -+ 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, -+ 0x66, 0x20, 0x63, 0x6f, 0x70, 0x79, 0x28, 0x73, 0x65, 0x6c, -+ 0x66, 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x51, 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, -+ 0x74, 0x73, 0x2e, 0x51, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, -+ 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x63, 0x6c, 0x69, 0x70, -+ 0x62, 0x6f, 0x61, 0x72, 0x64, 0x28, 0x29, 0x2e, 0x73, 0x65, -+ 0x74, 0x54, 0x65, 0x78, 0x74, 0x28, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x75, 0x69, 0x2e, 0x6d, 0x65, -+ 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x74, 0x6f, 0x50, 0x6c, -+ 0x61, 0x69, 0x6e, 0x54, 0x65, 0x78, 0x74, 0x28, 0x29, 0x20, -+ 0x2b, 0x20, 0x27, 0x5c, 0x5c, 0x6e, 0x27, 0x0d, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x0d, 0x0a, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x66, 0x20, -+ 0x73, 0x65, 0x74, 0x5f, 0x74, 0x65, 0x78, 0x74, 0x28, 0x73, -+ 0x65, 0x6c, 0x66, 0x2c, 0x20, 0x74, 0x65, 0x78, 0x74, 0x29, -+ 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x75, 0x69, 0x2e, 0x6d, -+ 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x73, 0x65, 0x74, -+ 0x50, 0x6c, 0x61, 0x69, 0x6e, 0x54, 0x65, 0x78, 0x74, 0x28, -+ 0x74, 0x65, 0x78, 0x74, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, -+ 0x66, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x20, 0x3d, 0x20, 0x4e, -+ 0x6f, 0x6e, 0x65, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x65, -+ 0x78, 0x74, 0x20, 0x3d, 0x20, 0x74, 0x65, 0x78, 0x74, 0x0d, -+ 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x75, 0x69, 0x2e, 0x6d, -+ 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x73, 0x65, 0x74, -+ 0x4c, 0x69, 0x6e, 0x65, 0x57, 0x72, 0x61, 0x70, 0x4d, 0x6f, -+ 0x64, 0x65, 0x28, 0x51, 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, -+ 0x74, 0x73, 0x2e, 0x51, 0x54, 0x65, 0x78, 0x74, 0x45, 0x64, -+ 0x69, 0x74, 0x2e, 0x4e, 0x6f, 0x57, 0x72, 0x61, 0x70, 0x29, -+ 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, -+ 0x66, 0x20, 0x73, 0x65, 0x74, 0x5f, 0x68, 0x74, 0x6d, 0x6c, -+ 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2c, 0x20, 0x68, 0x74, 0x6d, -+ 0x6c, 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x75, 0x69, -+ 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x73, -+ 0x65, 0x74, 0x48, 0x74, 0x6d, 0x6c, 0x28, 0x68, 0x74, 0x6d, -+ 0x6c, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x68, -+ 0x74, 0x6d, 0x6c, 0x20, 0x3d, 0x20, 0x68, 0x74, 0x6d, 0x6c, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x65, 0x78, 0x74, 0x20, -+ 0x3d, 0x20, 0x4e, 0x6f, 0x6e, 0x65, 0x0d, 0x0a, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, -+ 0x6c, 0x66, 0x2e, 0x75, 0x69, 0x2e, 0x6d, 0x65, 0x73, 0x73, -+ 0x61, 0x67, 0x65, 0x2e, 0x73, 0x65, 0x74, 0x4c, 0x69, 0x6e, -+ 0x65, 0x57, 0x72, 0x61, 0x70, 0x4d, 0x6f, 0x64, 0x65, 0x28, -+ 0x51, 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, -+ 0x51, 0x54, 0x65, 0x78, 0x74, 0x45, 0x64, 0x69, 0x74, 0x2e, -+ 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x57, 0x69, 0x64, 0x74, -+ 0x68, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x64, 0x65, 0x66, 0x20, 0x73, 0x65, 0x74, 0x5f, 0x6d, 0x65, -+ 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x62, 0x6f, 0x78, 0x5f, -+ 0x69, 0x63, 0x6f, 0x6e, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2c, -+ 0x20, 0x69, 0x63, 0x6f, 0x6e, 0x29, 0x3a, 0x0d, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, -+ 0x66, 0x2e, 0x75, 0x69, 0x2e, 0x69, 0x63, 0x6f, 0x6e, 0x2e, -+ 0x73, 0x65, 0x74, 0x50, 0x69, 0x78, 0x6d, 0x61, 0x70, 0x28, -+ 0x51, 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, -+ 0x51, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x6f, -+ 0x78, 0x2e, 0x73, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, -+ 0x49, 0x63, 0x6f, 0x6e, 0x28, 0x69, 0x63, 0x6f, 0x6e, 0x29, -+ 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, -+ 0x65, 0x66, 0x20, 0x65, 0x78, 0x65, 0x63, 0x28, 0x73, 0x65, -+ 0x6c, 0x66, 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x51, 0x74, 0x43, 0x6f, 0x72, 0x65, -+ 0x2e, 0x51, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x2e, 0x73, 0x69, -+ 0x6e, 0x67, 0x6c, 0x65, 0x53, 0x68, 0x6f, 0x74, 0x28, 0x31, -+ 0x30, 0x2c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x6f, 0x6f, -+ 0x6c, 0x73, 0x2e, 0x70, 0x61, 0x72, 0x74, 0x69, 0x61, 0x6c, -+ 0x28, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, -+ 0x65, 0x6c, 0x66, 0x2e, 0x73, 0x65, 0x74, 0x4d, 0x61, 0x78, -+ 0x69, 0x6d, 0x75, 0x6d, 0x53, 0x69, 0x7a, 0x65, 0x2c, 0x0d, -+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, -+ 0x66, 0x2e, 0x63, 0x61, 0x63, 0x68, 0x65, 0x64, 0x5f, 0x6d, -+ 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x5f, 0x73, 0x69, 0x7a, -+ 0x65, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x29, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, -+ 0x72, 0x6e, 0x20, 0x73, 0x75, 0x70, 0x65, 0x72, 0x28, 0x29, -+ 0x2e, 0x65, 0x78, 0x65, 0x63, 0x28, 0x29, 0x0d, 0x0a, 0x0d, -+ 0x0a, 0x0d, 0x0a, 0x64, 0x65, 0x66, 0x20, 0x64, 0x69, 0x61, -+ 0x6c, 0x6f, 0x67, 0x28, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, -+ 0x2c, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2c, -+ 0x20, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x3d, 0x4e, 0x6f, 0x6e, -+ 0x65, 0x2c, 0x20, 0x69, 0x63, 0x6f, 0x6e, 0x3d, 0x4e, 0x6f, -+ 0x6e, 0x65, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x69, 0x63, 0x68, -+ 0x5f, 0x74, 0x65, 0x78, 0x74, 0x3d, 0x46, 0x61, 0x6c, 0x73, -+ 0x65, 0x2c, 0x20, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, -+ 0x61, 0x62, 0x6c, 0x65, 0x3d, 0x46, 0x61, 0x6c, 0x73, 0x65, -+ 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6f, -+ 0x78, 0x20, 0x3d, 0x20, 0x44, 0x69, 0x61, 0x6c, 0x6f, 0x67, -+ 0x28, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x3d, 0x70, 0x61, -+ 0x72, 0x65, 0x6e, 0x74, 0x2c, 0x20, 0x63, 0x61, 0x6e, 0x63, -+ 0x65, 0x6c, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x3d, 0x63, 0x61, -+ 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x29, -+ 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, -+ 0x20, 0x72, 0x69, 0x63, 0x68, 0x5f, 0x74, 0x65, 0x78, 0x74, -+ 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x62, 0x6f, 0x78, 0x2e, 0x73, 0x65, 0x74, 0x5f, 0x68, -+ 0x74, 0x6d, 0x6c, 0x28, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, -+ 0x65, 0x29, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, -+ 0x73, 0x65, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x62, 0x6f, 0x78, 0x2e, 0x73, 0x65, 0x74, -+ 0x5f, 0x74, 0x65, 0x78, 0x74, 0x28, 0x6d, 0x65, 0x73, 0x73, -+ 0x61, 0x67, 0x65, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x69, 0x66, 0x20, 0x69, 0x63, 0x6f, 0x6e, 0x20, -+ 0x69, 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x4e, 0x6f, 0x6e, -+ 0x65, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x62, 0x6f, 0x78, 0x2e, 0x73, 0x65, 0x74, 0x5f, -+ 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x62, 0x6f, -+ 0x78, 0x5f, 0x69, 0x63, 0x6f, 0x6e, 0x28, 0x69, 0x63, 0x6f, -+ 0x6e, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x69, 0x66, 0x20, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x20, 0x69, -+ 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x4e, 0x6f, 0x6e, 0x65, -+ 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x69, -+ 0x74, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0x51, 0x74, 0x57, 0x69, -+ 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x51, 0x41, 0x70, 0x70, -+ 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x69, -+ 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x28, 0x29, 0x2e, -+ 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, -+ 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x28, 0x29, 0x0d, 0x0a, 0x0d, -+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, -+ 0x66, 0x20, 0x6c, 0x65, 0x6e, 0x28, 0x70, 0x61, 0x72, 0x65, -+ 0x6e, 0x74, 0x5f, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x29, 0x20, -+ 0x3e, 0x20, 0x30, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x69, -+ 0x74, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0x27, 0x20, 0x2d, 0x20, -+ 0x27, 0x2e, 0x6a, 0x6f, 0x69, 0x6e, 0x28, 0x28, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x72, 0x65, -+ 0x6e, 0x74, 0x5f, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x2c, 0x0d, -+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x69, 0x74, -+ 0x6c, 0x65, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x0d, -+ 0x0a, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x62, 0x6f, 0x78, 0x2e, 0x73, 0x65, 0x74, -+ 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x54, 0x69, 0x74, 0x6c, -+ 0x65, 0x28, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x29, 0x0d, 0x0a, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, -+ 0x72, 0x6e, 0x20, 0x62, 0x6f, 0x78, 0x2e, 0x65, 0x78, 0x65, -+ 0x63, 0x28, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x51, 0x74, 0x43, -+ 0x6f, 0x72, 0x65, 0x2e, 0x71, 0x44, 0x65, 0x62, 0x75, 0x67, -+ 0x28, 0x27, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x20, -+ 0x73, 0x79, 0x73, 0x2e, 0x65, 0x78, 0x63, 0x65, 0x70, 0x74, -+ 0x68, 0x6f, 0x6f, 0x6b, 0x20, 0x74, 0x6f, 0x20, 0x70, 0x72, -+ 0x6f, 0x76, 0x69, 0x64, 0x65, 0x20, 0x64, 0x69, 0x61, 0x6c, -+ 0x6f, 0x67, 0x27, 0x29, 0x0d, 0x0a, 0x73, 0x79, 0x73, 0x2e, -+ 0x65, 0x78, 0x63, 0x65, 0x70, 0x74, 0x68, 0x6f, 0x6f, 0x6b, -+ 0x20, 0x3d, 0x20, 0x65, 0x78, 0x63, 0x65, 0x70, 0x74, 0x69, -+ 0x6f, 0x6e, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, -+ 0x5f, 0x62, 0x6f, 0x78, 0x0d, 0x0a, 0x00 -+}; -diff --git a/designer/excepthook.py b/designer/excepthook.py -new file mode 100644 -index 0000000..1c4aaa9 ---- /dev/null -+++ b/designer/excepthook.py -@@ -0,0 +1,170 @@ -+import functools -+import sys -+import traceback -+ -+from PyQt5 import QtCore, QtWidgets -+ -+QtCore.qDebug('Importing module for exception dialogs') -+ -+def exception_message_box(excType=None, excValue=None, tracebackobj=None): -+ message = traceback.format_exception(excType, excValue, tracebackobj) -+ message = ''.join(message) -+ -+ dialog( -+ parent=None, -+ title='Exception', -+ message=message, -+ icon=QtWidgets.QMessageBox.Critical, -+ ) -+ -+class FittedTextBrowser(QtWidgets.QTextBrowser): -+ def sizeHint(self): -+ default = super().sizeHint() -+ -+ if not default.isValid(): -+ return default -+ -+ document_size = self.document().size() -+ -+ desktops = QtWidgets.QApplication.desktop() -+ screen_number = desktops.screenNumber(self.parent()) -+ geometry = desktops.screenGeometry(screen_number) -+ -+ if document_size.width() == 0: -+ document_size.setWidth(geometry.width() * 0.25) -+ if document_size.height() == 0: -+ document_size.setHeight(geometry.height() * 0.4) -+ -+ scrollbar_width = QtWidgets.QApplication.style().pixelMetric( -+ QtWidgets.QStyle.PM_ScrollBarExtent -+ ) -+ -+ width = sum(( -+ document_size.width(), -+ self.contentsMargins().left(), -+ self.contentsMargins().right(), -+ scrollbar_width, -+ )) -+ -+ height = sum(( -+ document_size.height(), -+ self.contentsMargins().top(), -+ self.contentsMargins().bottom(), -+ scrollbar_width, -+ )) -+ -+ return QtCore.QSize(width, height) -+ -+ -+class DialogUi: -+ def __init__(self, parent): -+ self.layout = QtWidgets.QGridLayout(parent) -+ self.icon = QtWidgets.QLabel(parent) -+ self.message = FittedTextBrowser(parent) -+ self.copy = QtWidgets.QPushButton(parent) -+ self.buttons = QtWidgets.QDialogButtonBox(parent) -+ -+ self.copy.setText('Copy To Clipboard') -+ -+ self.layout.addWidget(self.icon, 0, 0) -+ self.layout.addWidget(self.message, 0, 1, 1, 2) -+ self.layout.addWidget(self.copy, 1, 1) -+ self.layout.addWidget(self.buttons, 1, 2) -+ -+ self.layout.setAlignment(self.copy, QtCore.Qt.AlignLeft) -+ -+ self.layout.setRowStretch(0, 1) -+ self.layout.setColumnStretch(1, 1) -+ -+ -+class Dialog(QtWidgets.QDialog): -+ def __init__(self, *args, cancellable=False, **kwargs): -+ super().__init__(*args, **kwargs) -+ -+ self.ui = DialogUi(parent=self) -+ -+ self.ui.buttons.accepted.connect(self.accept) -+ self.ui.buttons.rejected.connect(self.reject) -+ -+ self.ui.copy.clicked.connect(self.copy) -+ -+ self.setLayout(self.ui.layout) -+ buttons = QtWidgets.QDialogButtonBox.Ok -+ if cancellable: -+ buttons |= QtWidgets.QDialogButtonBox.Cancel -+ -+ self.ui.buttons.setStandardButtons(buttons) -+ -+ self.text = None -+ self.html = None -+ -+ self.cached_maximum_size = self.maximumSize() -+ -+ desktops = QtWidgets.QApplication.desktop() -+ screen_number = desktops.screenNumber(self.parent()) -+ geometry = desktops.screenGeometry(screen_number) -+ -+ self.setMaximumHeight(geometry.height() * 0.7) -+ self.setMaximumWidth(geometry.width() * 0.7) -+ -+ def copy(self): -+ QtWidgets.QApplication.clipboard().setText( -+ self.ui.message.toPlainText() + '\\n' -+ ) -+ -+ def set_text(self, text): -+ self.ui.message.setPlainText(text) -+ -+ self.html = None -+ self.text = text -+ -+ self.ui.message.setLineWrapMode(QtWidgets.QTextEdit.NoWrap) -+ -+ def set_html(self, html): -+ self.ui.message.setHtml(html) -+ -+ self.html = html -+ self.text = None -+ -+ self.ui.message.setLineWrapMode(QtWidgets.QTextEdit.WidgetWidth) -+ -+ def set_message_box_icon(self, icon): -+ self.ui.icon.setPixmap(QtWidgets.QMessageBox.standardIcon(icon)) -+ -+ def exec(self): -+ QtCore.QTimer.singleShot(10, functools.partial( -+ self.setMaximumSize, -+ self.cached_maximum_size, -+ )) -+ -+ return super().exec() -+ -+ -+def dialog(parent, message, title=None, icon=None, -+ rich_text=False, cancellable=False): -+ box = Dialog(parent=parent, cancellable=cancellable) -+ -+ if rich_text: -+ box.set_html(message) -+ else: -+ box.set_text(message) -+ -+ if icon is not None: -+ box.set_message_box_icon(icon) -+ -+ if title is not None: -+ parent_title = QtWidgets.QApplication.instance().applicationName() -+ -+ if len(parent_title) > 0: -+ title = ' - '.join(( -+ parent_title, -+ title, -+ )) -+ -+ -+ box.setWindowTitle(title) -+ -+ return box.exec() -+ -+QtCore.qDebug('Setting sys.excepthook to provide dialog') -+sys.excepthook = exception_message_box -diff --git a/designer/generate_module_literal.py b/designer/generate_module_literal.py -new file mode 100644 -index 0000000..cc6b4de ---- /dev/null -+++ b/designer/generate_module_literal.py -@@ -0,0 +1,35 @@ -+import os -+import itertools -+ -+ -+# https://repl.it/IwNE/4 -+def chunker(iterable, n): -+ "Collect data into fixed-length chunks or blocks except last due to lack of fill." -+ # chunker('ABCDEFG', 3) --> ABC DEF G" -+ -+ i = iter(iterable) -+ -+ while True: -+ t = tuple(next(i) for _ in range(n)) -+ -+ if len(t) > 0: -+ yield t -+ else: -+ break -+ -+ -+with open('excepthook.py', 'rb') as f: -+ raw = f.read() -+ -+with open('excepthook.c', 'w', newline='\n') as f: -+ f.write('const char * moduleName = "exceptiondialog";\n\n') -+ f.write('const char moduleCode[] = {\n') -+ -+ indent = ' ' * 4 -+ -+ chunks = chunker(itertools.chain(raw, b'\0'), 10) -+ lines = (', '.join('0x{:02x}'.format(b) for b in chunk) for chunk in chunks) -+ lines = (',\n'.join(indent + line for line in lines)) -+ for line in lines: -+ f.write(line) -+ f.write("\n};\n") -diff --git a/designer/pluginloader.cpp b/designer/pluginloader.cpp -index d4fb17a..d9f77ec 100644 ---- a/designer/pluginloader.cpp -+++ b/designer/pluginloader.cpp -@@ -25,6 +25,7 @@ - - #include - -+#include - #include - #include - #include -@@ -36,6 +37,114 @@ - - #include "../qpy/QtDesigner/qpydesignercustomwidgetplugin.h" - -+#include "excepthook.c" -+ -+ -+void setupExceptHookDialog(void) -+{ -+ qDebug() << "Preparing to import module"; -+ qDebug() << PyBytes_AS_STRING(PyUnicode_AsEncodedString(PyObject_Str(PySys_GetObject("path")), "utf-8", "error 1?")); -+ // https://stackoverflow.com/a/42853449/228539 -+ PyObject *pyModule = PyModule_New(moduleName); -+ // Set properties on the new module object -+ PyModule_AddStringConstant(pyModule, "__file__", ""); -+ PyObject *localDict = PyModule_GetDict(pyModule); // Returns a borrowed reference: no need to Py_DECREF() it once we are done -+ PyObject *builtins = PyEval_GetBuiltins(); // Returns a borrowed reference: no need to Py_DECREF() it once we are done -+ PyDict_SetItemString(localDict, "__builtins__", builtins); -+ -+ qDebug() << "About to import module"; -+ -+ // Define code in the newly created module -+ PyObject *pyValue = PyRun_String(moduleCode, Py_file_input, localDict, localDict); -+ qDebug() << "Code just run"; -+ if (pyValue == NULL) -+ { -+ qDebug() << "An error occurred while importing the module"; -+ -+ char * full_backtrace = NULL; -+ -+ if (PyErr_Occurred() != NULL) { -+ qDebug() << "PyErr_Occurred() != NULL"; -+ PyObject *ptype, *pvalue, *ptraceback; -+ PyObject *pystr, *module_name, *pyth_module, *pyth_func; -+ char *str; -+ char *error_description; -+ -+ PyErr_Fetch(&ptype, &pvalue, &ptraceback); -+ qDebug() << "ptype == NULL : " << (ptype == NULL); -+ qDebug() << "pvalue == NULL : " << (pvalue == NULL); -+ qDebug() << "ptraceback == NULL : " << (ptraceback == NULL); -+ pystr = PyObject_Str(pvalue); -+ qDebug() << "pystr == NULL : " << (pystr == NULL); -+ pystr = PyUnicode_AsEncodedString(pystr, "utf-8", "error 1?"); -+ qDebug() << "pystr == NULL : " << (pystr == NULL); -+ str = PyBytes_AS_STRING(pystr); -+ qDebug() << "str == NULL : " << (str == NULL); -+ if (str != NULL) -+ { -+ qDebug() << "str: " << str; -+ } -+ Py_DECREF(pystr); -+ error_description = strdup(str); -+ qDebug() << "error_description == NULL : " << (error_description == NULL); -+ if (error_description != NULL) -+ { -+ qDebug() << "error_description: " << error_description; -+ } -+ -+ /* See if we can get a full traceback */ -+ module_name = PyUnicode_Decode("traceback", 9, "utf-8", "error 2?"); -+ pyth_module = PyImport_Import(module_name); -+ Py_DECREF(module_name); -+ -+ qDebug() << "pyth_module == NULL : " << (pyth_module == NULL); -+ if (pyth_module == NULL) { -+ full_backtrace = NULL; -+ return; -+ } -+ -+ pyth_func = PyObject_GetAttrString(pyth_module, "format_exception"); -+ if (pyth_func && PyCallable_Check(pyth_func)) -+ { -+ qDebug() << "pyth_func && PyCallable_Check(pyth_func)"; -+ PyObject *pyth_val; -+ -+ pyth_val = PyObject_CallFunctionObjArgs(pyth_func, ptype, pvalue, ptraceback, Py_None, Py_True, NULL); -+ qDebug() << "pyth_val == NULL : " << (pyth_val == NULL); -+ -+ pystr = PyObject_Str(pyth_val); -+ qDebug() << "pystr == NULL : " << (pystr == NULL); -+ -+ pystr = PyUnicode_AsEncodedString(pystr, "utf-8", "error 3?"); -+ qDebug() << "pystr == NULL : " << (pystr == NULL); -+ -+ str = PyBytes_AS_STRING(pystr); -+ qDebug() << "str == NULL : " << (str == NULL); -+ -+ Py_DECREF(pystr); -+ full_backtrace = strdup(str); -+ Py_DECREF(pyth_val); -+ } -+ } -+ -+ if (full_backtrace != NULL) -+ { -+ qDebug() << "About to print backtrace"; -+ qDebug() << full_backtrace; -+ } -+ else -+ { -+ qDebug() << "Backtrace was NULL"; -+ } -+ } -+ else -+ { -+ qDebug() << "About to decref"; -+ Py_DECREF(pyValue); -+ } -+ -+ qDebug() << "Done importing module"; -+} - - // Construct the collection of Python widgets. - PyCustomWidgets::PyCustomWidgets(QObject *parent) : QObject(parent), -@@ -140,6 +249,7 @@ PyCustomWidgets::PyCustomWidgets(QObject *parent) : QObject(parent), - PyGILState_STATE gil_state = PyGILState_Ensure(); - #endif - -+ setupExceptHookDialog(); - bool fatal = importPlugins(dir, plugins); - - #if defined(WITH_THREAD) diff --git a/pluginloader.5.15.1.patch b/pluginloader.5.15.1.patch deleted file mode 100644 index 0af856245..000000000 --- a/pluginloader.5.15.1.patch +++ /dev/null @@ -1,858 +0,0 @@ -diff --git a/designer/excepthook.c b/designer/excepthook.c -new file mode 100644 -index 0000000..6a575af ---- /dev/null -+++ b/designer/excepthook.c -@@ -0,0 +1,500 @@ -+const char * moduleName = "exceptiondialog"; -+ -+const char moduleCode[] = { -+ 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x66, 0x75, 0x6e, -+ 0x63, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x0d, 0x0a, 0x69, 0x6d, -+ 0x70, 0x6f, 0x72, 0x74, 0x20, 0x73, 0x79, 0x73, 0x0d, 0x0a, -+ 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x74, 0x72, 0x61, -+ 0x63, 0x65, 0x62, 0x61, 0x63, 0x6b, 0x0d, 0x0a, 0x0d, 0x0a, -+ 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x50, 0x79, 0x51, 0x74, 0x35, -+ 0x20, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x51, 0x74, -+ 0x43, 0x6f, 0x72, 0x65, 0x2c, 0x20, 0x51, 0x74, 0x57, 0x69, -+ 0x64, 0x67, 0x65, 0x74, 0x73, 0x0d, 0x0a, 0x0d, 0x0a, 0x51, -+ 0x74, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x71, 0x44, 0x65, 0x62, -+ 0x75, 0x67, 0x28, 0x27, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, -+ 0x69, 0x6e, 0x67, 0x20, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, -+ 0x20, 0x66, 0x6f, 0x72, 0x20, 0x65, 0x78, 0x63, 0x65, 0x70, -+ 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x64, 0x69, 0x61, 0x6c, 0x6f, -+ 0x67, 0x73, 0x27, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x64, 0x65, -+ 0x66, 0x20, 0x65, 0x78, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6f, -+ 0x6e, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, -+ 0x62, 0x6f, 0x78, 0x28, 0x65, 0x78, 0x63, 0x54, 0x79, 0x70, -+ 0x65, 0x3d, 0x4e, 0x6f, 0x6e, 0x65, 0x2c, 0x20, 0x65, 0x78, -+ 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x3d, 0x4e, 0x6f, 0x6e, -+ 0x65, 0x2c, 0x20, 0x74, 0x72, 0x61, 0x63, 0x65, 0x62, 0x61, -+ 0x63, 0x6b, 0x6f, 0x62, 0x6a, 0x3d, 0x4e, 0x6f, 0x6e, 0x65, -+ 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x65, -+ 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x3d, 0x20, 0x74, 0x72, -+ 0x61, 0x63, 0x65, 0x62, 0x61, 0x63, 0x6b, 0x2e, 0x66, 0x6f, -+ 0x72, 0x6d, 0x61, 0x74, 0x5f, 0x65, 0x78, 0x63, 0x65, 0x70, -+ 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x65, 0x78, 0x63, 0x54, 0x79, -+ 0x70, 0x65, 0x2c, 0x20, 0x65, 0x78, 0x63, 0x56, 0x61, 0x6c, -+ 0x75, 0x65, 0x2c, 0x20, 0x74, 0x72, 0x61, 0x63, 0x65, 0x62, -+ 0x61, 0x63, 0x6b, 0x6f, 0x62, 0x6a, 0x29, 0x0d, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, -+ 0x20, 0x3d, 0x20, 0x27, 0x27, 0x2e, 0x6a, 0x6f, 0x69, 0x6e, -+ 0x28, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x29, 0x0d, -+ 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x69, 0x61, -+ 0x6c, 0x6f, 0x67, 0x28, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, -+ 0x3d, 0x4e, 0x6f, 0x6e, 0x65, 0x2c, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x69, 0x74, 0x6c, -+ 0x65, 0x3d, 0x27, 0x45, 0x78, 0x63, 0x65, 0x70, 0x74, 0x69, -+ 0x6f, 0x6e, 0x27, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, -+ 0x65, 0x3d, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2c, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x69, 0x63, 0x6f, 0x6e, 0x3d, 0x51, 0x74, 0x57, 0x69, 0x64, -+ 0x67, 0x65, 0x74, 0x73, 0x2e, 0x51, 0x4d, 0x65, 0x73, 0x73, -+ 0x61, 0x67, 0x65, 0x42, 0x6f, 0x78, 0x2e, 0x43, 0x72, 0x69, -+ 0x74, 0x69, 0x63, 0x61, 0x6c, 0x2c, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x63, 0x6c, 0x61, -+ 0x73, 0x73, 0x20, 0x46, 0x69, 0x74, 0x74, 0x65, 0x64, 0x54, -+ 0x65, 0x78, 0x74, 0x42, 0x72, 0x6f, 0x77, 0x73, 0x65, 0x72, -+ 0x28, 0x51, 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, -+ 0x2e, 0x51, 0x54, 0x65, 0x78, 0x74, 0x42, 0x72, 0x6f, 0x77, -+ 0x73, 0x65, 0x72, 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, -+ 0x20, 0x64, 0x65, 0x66, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x48, -+ 0x69, 0x6e, 0x74, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x29, 0x3a, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x20, 0x3d, 0x20, -+ 0x73, 0x75, 0x70, 0x65, 0x72, 0x28, 0x29, 0x2e, 0x73, 0x69, -+ 0x7a, 0x65, 0x48, 0x69, 0x6e, 0x74, 0x28, 0x29, 0x0d, 0x0a, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x64, 0x65, 0x66, -+ 0x61, 0x75, 0x6c, 0x74, 0x2e, 0x69, 0x73, 0x56, 0x61, 0x6c, -+ 0x69, 0x64, 0x28, 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, -+ 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x64, 0x65, 0x66, 0x61, -+ 0x75, 0x6c, 0x74, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, -+ 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x3d, -+ 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x64, 0x6f, 0x63, 0x75, -+ 0x6d, 0x65, 0x6e, 0x74, 0x28, 0x29, 0x2e, 0x73, 0x69, 0x7a, -+ 0x65, 0x28, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x73, 0x6b, 0x74, -+ 0x6f, 0x70, 0x73, 0x20, 0x3d, 0x20, 0x51, 0x74, 0x57, 0x69, -+ 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x51, 0x41, 0x70, 0x70, -+ 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x64, -+ 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x28, 0x29, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x63, -+ 0x72, 0x65, 0x65, 0x6e, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, -+ 0x72, 0x20, 0x3d, 0x20, 0x64, 0x65, 0x73, 0x6b, 0x74, 0x6f, -+ 0x70, 0x73, 0x2e, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x4e, -+ 0x75, 0x6d, 0x62, 0x65, 0x72, 0x28, 0x73, 0x65, 0x6c, 0x66, -+ 0x2e, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x28, 0x29, 0x29, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x67, 0x65, 0x6f, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x20, 0x3d, -+ 0x20, 0x64, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x73, 0x2e, -+ 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x47, 0x65, 0x6f, 0x6d, -+ 0x65, 0x74, 0x72, 0x79, 0x28, 0x73, 0x63, 0x72, 0x65, 0x65, -+ 0x6e, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x29, 0x0d, -+ 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x69, 0x66, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, -+ 0x6e, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x2e, 0x77, 0x69, -+ 0x64, 0x74, 0x68, 0x28, 0x29, 0x20, 0x3d, 0x3d, 0x20, 0x30, -+ 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, -+ 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x2e, 0x73, -+ 0x65, 0x74, 0x57, 0x69, 0x64, 0x74, 0x68, 0x28, 0x67, 0x65, -+ 0x6f, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x77, 0x69, 0x64, -+ 0x74, 0x68, 0x28, 0x29, 0x20, 0x2a, 0x20, 0x30, 0x2e, 0x32, -+ 0x35, 0x29, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x69, 0x66, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, -+ 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x2e, 0x68, -+ 0x65, 0x69, 0x67, 0x68, 0x74, 0x28, 0x29, 0x20, 0x3d, 0x3d, -+ 0x20, 0x30, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, 0x63, -+ 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, -+ 0x2e, 0x73, 0x65, 0x74, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, -+ 0x28, 0x67, 0x65, 0x6f, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, -+ 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x28, 0x29, 0x20, 0x2a, -+ 0x20, 0x30, 0x2e, 0x34, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x63, 0x72, -+ 0x6f, 0x6c, 0x6c, 0x62, 0x61, 0x72, 0x5f, 0x77, 0x69, 0x64, -+ 0x74, 0x68, 0x20, 0x3d, 0x20, 0x51, 0x74, 0x57, 0x69, 0x64, -+ 0x67, 0x65, 0x74, 0x73, 0x2e, 0x51, 0x41, 0x70, 0x70, 0x6c, -+ 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x73, 0x74, -+ 0x79, 0x6c, 0x65, 0x28, 0x29, 0x2e, 0x70, 0x69, 0x78, 0x65, -+ 0x6c, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x28, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x51, 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, -+ 0x73, 0x2e, 0x51, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x2e, 0x50, -+ 0x4d, 0x5f, 0x53, 0x63, 0x72, 0x6f, 0x6c, 0x6c, 0x42, 0x61, -+ 0x72, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x74, 0x0d, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x0d, 0x0a, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x77, 0x69, 0x64, 0x74, 0x68, 0x20, 0x3d, 0x20, 0x73, 0x75, -+ 0x6d, 0x28, 0x28, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, 0x63, -+ 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, -+ 0x2e, 0x77, 0x69, 0x64, 0x74, 0x68, 0x28, 0x29, 0x2c, 0x0d, -+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x63, 0x6f, -+ 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x4d, 0x61, 0x72, 0x67, -+ 0x69, 0x6e, 0x73, 0x28, 0x29, 0x2e, 0x6c, 0x65, 0x66, 0x74, -+ 0x28, 0x29, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, -+ 0x66, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, -+ 0x4d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x73, 0x28, 0x29, 0x2e, -+ 0x72, 0x69, 0x67, 0x68, 0x74, 0x28, 0x29, 0x2c, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x73, 0x63, 0x72, 0x6f, 0x6c, 0x6c, 0x62, 0x61, -+ 0x72, 0x5f, 0x77, 0x69, 0x64, 0x74, 0x68, 0x2c, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, -+ 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x20, 0x3d, -+ 0x20, 0x73, 0x75, 0x6d, 0x28, 0x28, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x73, -+ 0x69, 0x7a, 0x65, 0x2e, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, -+ 0x28, 0x29, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, -+ 0x66, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, -+ 0x4d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x73, 0x28, 0x29, 0x2e, -+ 0x74, 0x6f, 0x70, 0x28, 0x29, 0x2c, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, -+ 0x6e, 0x74, 0x73, 0x4d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x73, -+ 0x28, 0x29, 0x2e, 0x62, 0x6f, 0x74, 0x74, 0x6f, 0x6d, 0x28, -+ 0x29, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x63, 0x72, 0x6f, -+ 0x6c, 0x6c, 0x62, 0x61, 0x72, 0x5f, 0x77, 0x69, 0x64, 0x74, -+ 0x68, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x29, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, -+ 0x72, 0x6e, 0x20, 0x51, 0x74, 0x43, 0x6f, 0x72, 0x65, 0x2e, -+ 0x51, 0x53, 0x69, 0x7a, 0x65, 0x28, 0x77, 0x69, 0x64, 0x74, -+ 0x68, 0x2c, 0x20, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x29, -+ 0x0d, 0x0a, 0x0d, 0x0a, 0x0d, 0x0a, 0x63, 0x6c, 0x61, 0x73, -+ 0x73, 0x20, 0x44, 0x69, 0x61, 0x6c, 0x6f, 0x67, 0x55, 0x69, -+ 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x66, -+ 0x20, 0x5f, 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x5f, 0x5f, 0x28, -+ 0x73, 0x65, 0x6c, 0x66, 0x2c, 0x20, 0x70, 0x61, 0x72, 0x65, -+ 0x6e, 0x74, 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x6c, -+ 0x61, 0x79, 0x6f, 0x75, 0x74, 0x20, 0x3d, 0x20, 0x51, 0x74, -+ 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x51, 0x47, -+ 0x72, 0x69, 0x64, 0x4c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x28, -+ 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x29, 0x0d, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, -+ 0x66, 0x2e, 0x69, 0x63, 0x6f, 0x6e, 0x20, 0x3d, 0x20, 0x51, -+ 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x51, -+ 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x28, 0x70, 0x61, 0x72, 0x65, -+ 0x6e, 0x74, 0x29, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x6d, 0x65, -+ 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x3d, 0x20, 0x46, 0x69, -+ 0x74, 0x74, 0x65, 0x64, 0x54, 0x65, 0x78, 0x74, 0x42, 0x72, -+ 0x6f, 0x77, 0x73, 0x65, 0x72, 0x28, 0x70, 0x61, 0x72, 0x65, -+ 0x6e, 0x74, 0x29, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x63, 0x6f, -+ 0x70, 0x79, 0x20, 0x3d, 0x20, 0x51, 0x74, 0x57, 0x69, 0x64, -+ 0x67, 0x65, 0x74, 0x73, 0x2e, 0x51, 0x50, 0x75, 0x73, 0x68, -+ 0x42, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x28, 0x70, 0x61, 0x72, -+ 0x65, 0x6e, 0x74, 0x29, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x62, -+ 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x73, 0x20, 0x3d, 0x20, 0x51, -+ 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x51, -+ 0x44, 0x69, 0x61, 0x6c, 0x6f, 0x67, 0x42, 0x75, 0x74, 0x74, -+ 0x6f, 0x6e, 0x42, 0x6f, 0x78, 0x28, 0x70, 0x61, 0x72, 0x65, -+ 0x6e, 0x74, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, -+ 0x63, 0x6f, 0x70, 0x79, 0x2e, 0x73, 0x65, 0x74, 0x54, 0x65, -+ 0x78, 0x74, 0x28, 0x27, 0x43, 0x6f, 0x70, 0x79, 0x20, 0x54, -+ 0x6f, 0x20, 0x43, 0x6c, 0x69, 0x70, 0x62, 0x6f, 0x61, 0x72, -+ 0x64, 0x27, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, -+ 0x6c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x2e, 0x61, 0x64, 0x64, -+ 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x28, 0x73, 0x65, 0x6c, -+ 0x66, 0x2e, 0x69, 0x63, 0x6f, 0x6e, 0x2c, 0x20, 0x30, 0x2c, -+ 0x20, 0x30, 0x29, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x6c, 0x61, -+ 0x79, 0x6f, 0x75, 0x74, 0x2e, 0x61, 0x64, 0x64, 0x57, 0x69, -+ 0x64, 0x67, 0x65, 0x74, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, -+ 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2c, 0x20, 0x30, -+ 0x2c, 0x20, 0x31, 0x2c, 0x20, 0x31, 0x2c, 0x20, 0x32, 0x29, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x6c, 0x61, 0x79, 0x6f, 0x75, -+ 0x74, 0x2e, 0x61, 0x64, 0x64, 0x57, 0x69, 0x64, 0x67, 0x65, -+ 0x74, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x63, 0x6f, 0x70, -+ 0x79, 0x2c, 0x20, 0x31, 0x2c, 0x20, 0x31, 0x29, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, -+ 0x6c, 0x66, 0x2e, 0x6c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x2e, -+ 0x61, 0x64, 0x64, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x28, -+ 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x62, 0x75, 0x74, 0x74, 0x6f, -+ 0x6e, 0x73, 0x2c, 0x20, 0x31, 0x2c, 0x20, 0x32, 0x29, 0x0d, -+ 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x6c, 0x61, 0x79, 0x6f, -+ 0x75, 0x74, 0x2e, 0x73, 0x65, 0x74, 0x41, 0x6c, 0x69, 0x67, -+ 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x28, 0x73, 0x65, 0x6c, 0x66, -+ 0x2e, 0x63, 0x6f, 0x70, 0x79, 0x2c, 0x20, 0x51, 0x74, 0x43, -+ 0x6f, 0x72, 0x65, 0x2e, 0x51, 0x74, 0x2e, 0x41, 0x6c, 0x69, -+ 0x67, 0x6e, 0x4c, 0x65, 0x66, 0x74, 0x29, 0x0d, 0x0a, 0x0d, -+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, -+ 0x65, 0x6c, 0x66, 0x2e, 0x6c, 0x61, 0x79, 0x6f, 0x75, 0x74, -+ 0x2e, 0x73, 0x65, 0x74, 0x52, 0x6f, 0x77, 0x53, 0x74, 0x72, -+ 0x65, 0x74, 0x63, 0x68, 0x28, 0x30, 0x2c, 0x20, 0x31, 0x29, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x6c, 0x61, 0x79, 0x6f, 0x75, -+ 0x74, 0x2e, 0x73, 0x65, 0x74, 0x43, 0x6f, 0x6c, 0x75, 0x6d, -+ 0x6e, 0x53, 0x74, 0x72, 0x65, 0x74, 0x63, 0x68, 0x28, 0x31, -+ 0x2c, 0x20, 0x31, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x0d, 0x0a, -+ 0x63, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x44, 0x69, 0x61, 0x6c, -+ 0x6f, 0x67, 0x28, 0x51, 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, -+ 0x74, 0x73, 0x2e, 0x51, 0x44, 0x69, 0x61, 0x6c, 0x6f, 0x67, -+ 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, -+ 0x66, 0x20, 0x5f, 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x5f, 0x5f, -+ 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2c, 0x20, 0x2a, 0x61, 0x72, -+ 0x67, 0x73, 0x2c, 0x20, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, -+ 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x3d, 0x46, 0x61, 0x6c, 0x73, -+ 0x65, 0x2c, 0x20, 0x2a, 0x2a, 0x6b, 0x77, 0x61, 0x72, 0x67, -+ 0x73, 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x73, 0x75, 0x70, 0x65, 0x72, 0x28, 0x29, -+ 0x2e, 0x5f, 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x5f, 0x5f, 0x28, -+ 0x2a, 0x61, 0x72, 0x67, 0x73, 0x2c, 0x20, 0x2a, 0x2a, 0x6b, -+ 0x77, 0x61, 0x72, 0x67, 0x73, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, -+ 0x6c, 0x66, 0x2e, 0x75, 0x69, 0x20, 0x3d, 0x20, 0x44, 0x69, -+ 0x61, 0x6c, 0x6f, 0x67, 0x55, 0x69, 0x28, 0x70, 0x61, 0x72, -+ 0x65, 0x6e, 0x74, 0x3d, 0x73, 0x65, 0x6c, 0x66, 0x29, 0x0d, -+ 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x75, 0x69, 0x2e, 0x62, -+ 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x73, 0x2e, 0x61, 0x63, 0x63, -+ 0x65, 0x70, 0x74, 0x65, 0x64, 0x2e, 0x63, 0x6f, 0x6e, 0x6e, -+ 0x65, 0x63, 0x74, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x61, -+ 0x63, 0x63, 0x65, 0x70, 0x74, 0x29, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, -+ 0x2e, 0x75, 0x69, 0x2e, 0x62, 0x75, 0x74, 0x74, 0x6f, 0x6e, -+ 0x73, 0x2e, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x65, 0x64, -+ 0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x28, 0x73, -+ 0x65, 0x6c, 0x66, 0x2e, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, -+ 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x75, 0x69, -+ 0x2e, 0x63, 0x6f, 0x70, 0x79, 0x2e, 0x63, 0x6c, 0x69, 0x63, -+ 0x6b, 0x65, 0x64, 0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, -+ 0x74, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x63, 0x6f, 0x70, -+ 0x79, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x73, -+ 0x65, 0x74, 0x4c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x28, 0x73, -+ 0x65, 0x6c, 0x66, 0x2e, 0x75, 0x69, 0x2e, 0x6c, 0x61, 0x79, -+ 0x6f, 0x75, 0x74, 0x29, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x62, 0x75, 0x74, 0x74, 0x6f, 0x6e, -+ 0x73, 0x20, 0x3d, 0x20, 0x51, 0x74, 0x57, 0x69, 0x64, 0x67, -+ 0x65, 0x74, 0x73, 0x2e, 0x51, 0x44, 0x69, 0x61, 0x6c, 0x6f, -+ 0x67, 0x42, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x42, 0x6f, 0x78, -+ 0x2e, 0x4f, 0x6b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x63, 0x61, 0x6e, 0x63, -+ 0x65, 0x6c, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x3a, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x62, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x73, 0x20, -+ 0x7c, 0x3d, 0x20, 0x51, 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, -+ 0x74, 0x73, 0x2e, 0x51, 0x44, 0x69, 0x61, 0x6c, 0x6f, 0x67, -+ 0x42, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x42, 0x6f, 0x78, 0x2e, -+ 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x0d, 0x0a, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, -+ 0x6c, 0x66, 0x2e, 0x75, 0x69, 0x2e, 0x62, 0x75, 0x74, 0x74, -+ 0x6f, 0x6e, 0x73, 0x2e, 0x73, 0x65, 0x74, 0x53, 0x74, 0x61, -+ 0x6e, 0x64, 0x61, 0x72, 0x64, 0x42, 0x75, 0x74, 0x74, 0x6f, -+ 0x6e, 0x73, 0x28, 0x62, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x73, -+ 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x65, -+ 0x78, 0x74, 0x20, 0x3d, 0x20, 0x4e, 0x6f, 0x6e, 0x65, 0x0d, -+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, -+ 0x65, 0x6c, 0x66, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x20, 0x3d, -+ 0x20, 0x4e, 0x6f, 0x6e, 0x65, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, -+ 0x66, 0x2e, 0x63, 0x61, 0x63, 0x68, 0x65, 0x64, 0x5f, 0x6d, -+ 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x5f, 0x73, 0x69, 0x7a, -+ 0x65, 0x20, 0x3d, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x6d, -+ 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x53, 0x69, 0x7a, 0x65, -+ 0x28, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x73, 0x6b, 0x74, 0x6f, -+ 0x70, 0x73, 0x20, 0x3d, 0x20, 0x51, 0x74, 0x57, 0x69, 0x64, -+ 0x67, 0x65, 0x74, 0x73, 0x2e, 0x51, 0x41, 0x70, 0x70, 0x6c, -+ 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x64, 0x65, -+ 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x28, 0x29, 0x0d, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x63, 0x72, -+ 0x65, 0x65, 0x6e, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, -+ 0x20, 0x3d, 0x20, 0x64, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, -+ 0x73, 0x2e, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x4e, 0x75, -+ 0x6d, 0x62, 0x65, 0x72, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, -+ 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x28, 0x29, 0x29, 0x0d, -+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x67, -+ 0x65, 0x6f, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x20, 0x3d, 0x20, -+ 0x64, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x73, 0x2e, 0x73, -+ 0x63, 0x72, 0x65, 0x65, 0x6e, 0x47, 0x65, 0x6f, 0x6d, 0x65, -+ 0x74, 0x72, 0x79, 0x28, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, -+ 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x29, 0x0d, 0x0a, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x73, 0x65, 0x74, 0x4d, 0x61, -+ 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x48, 0x65, 0x69, 0x67, 0x68, -+ 0x74, 0x28, 0x67, 0x65, 0x6f, 0x6d, 0x65, 0x74, 0x72, 0x79, -+ 0x2e, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x28, 0x29, 0x20, -+ 0x2a, 0x20, 0x30, 0x2e, 0x37, 0x29, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, -+ 0x2e, 0x73, 0x65, 0x74, 0x4d, 0x61, 0x78, 0x69, 0x6d, 0x75, -+ 0x6d, 0x57, 0x69, 0x64, 0x74, 0x68, 0x28, 0x67, 0x65, 0x6f, -+ 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x77, 0x69, 0x64, 0x74, -+ 0x68, 0x28, 0x29, 0x20, 0x2a, 0x20, 0x30, 0x2e, 0x37, 0x29, -+ 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, -+ 0x66, 0x20, 0x63, 0x6f, 0x70, 0x79, 0x28, 0x73, 0x65, 0x6c, -+ 0x66, 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x51, 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, -+ 0x74, 0x73, 0x2e, 0x51, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, -+ 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x63, 0x6c, 0x69, 0x70, -+ 0x62, 0x6f, 0x61, 0x72, 0x64, 0x28, 0x29, 0x2e, 0x73, 0x65, -+ 0x74, 0x54, 0x65, 0x78, 0x74, 0x28, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x75, 0x69, 0x2e, 0x6d, 0x65, -+ 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x74, 0x6f, 0x50, 0x6c, -+ 0x61, 0x69, 0x6e, 0x54, 0x65, 0x78, 0x74, 0x28, 0x29, 0x20, -+ 0x2b, 0x20, 0x27, 0x5c, 0x5c, 0x6e, 0x27, 0x0d, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x0d, 0x0a, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x66, 0x20, -+ 0x73, 0x65, 0x74, 0x5f, 0x74, 0x65, 0x78, 0x74, 0x28, 0x73, -+ 0x65, 0x6c, 0x66, 0x2c, 0x20, 0x74, 0x65, 0x78, 0x74, 0x29, -+ 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x75, 0x69, 0x2e, 0x6d, -+ 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x73, 0x65, 0x74, -+ 0x50, 0x6c, 0x61, 0x69, 0x6e, 0x54, 0x65, 0x78, 0x74, 0x28, -+ 0x74, 0x65, 0x78, 0x74, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, -+ 0x66, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x20, 0x3d, 0x20, 0x4e, -+ 0x6f, 0x6e, 0x65, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x65, -+ 0x78, 0x74, 0x20, 0x3d, 0x20, 0x74, 0x65, 0x78, 0x74, 0x0d, -+ 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x75, 0x69, 0x2e, 0x6d, -+ 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x73, 0x65, 0x74, -+ 0x4c, 0x69, 0x6e, 0x65, 0x57, 0x72, 0x61, 0x70, 0x4d, 0x6f, -+ 0x64, 0x65, 0x28, 0x51, 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, -+ 0x74, 0x73, 0x2e, 0x51, 0x54, 0x65, 0x78, 0x74, 0x45, 0x64, -+ 0x69, 0x74, 0x2e, 0x4e, 0x6f, 0x57, 0x72, 0x61, 0x70, 0x29, -+ 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, -+ 0x66, 0x20, 0x73, 0x65, 0x74, 0x5f, 0x68, 0x74, 0x6d, 0x6c, -+ 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2c, 0x20, 0x68, 0x74, 0x6d, -+ 0x6c, 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x75, 0x69, -+ 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x73, -+ 0x65, 0x74, 0x48, 0x74, 0x6d, 0x6c, 0x28, 0x68, 0x74, 0x6d, -+ 0x6c, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x68, -+ 0x74, 0x6d, 0x6c, 0x20, 0x3d, 0x20, 0x68, 0x74, 0x6d, 0x6c, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x65, 0x78, 0x74, 0x20, -+ 0x3d, 0x20, 0x4e, 0x6f, 0x6e, 0x65, 0x0d, 0x0a, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, -+ 0x6c, 0x66, 0x2e, 0x75, 0x69, 0x2e, 0x6d, 0x65, 0x73, 0x73, -+ 0x61, 0x67, 0x65, 0x2e, 0x73, 0x65, 0x74, 0x4c, 0x69, 0x6e, -+ 0x65, 0x57, 0x72, 0x61, 0x70, 0x4d, 0x6f, 0x64, 0x65, 0x28, -+ 0x51, 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, -+ 0x51, 0x54, 0x65, 0x78, 0x74, 0x45, 0x64, 0x69, 0x74, 0x2e, -+ 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x57, 0x69, 0x64, 0x74, -+ 0x68, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x64, 0x65, 0x66, 0x20, 0x73, 0x65, 0x74, 0x5f, 0x6d, 0x65, -+ 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x62, 0x6f, 0x78, 0x5f, -+ 0x69, 0x63, 0x6f, 0x6e, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2c, -+ 0x20, 0x69, 0x63, 0x6f, 0x6e, 0x29, 0x3a, 0x0d, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, -+ 0x66, 0x2e, 0x75, 0x69, 0x2e, 0x69, 0x63, 0x6f, 0x6e, 0x2e, -+ 0x73, 0x65, 0x74, 0x50, 0x69, 0x78, 0x6d, 0x61, 0x70, 0x28, -+ 0x51, 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, -+ 0x51, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x6f, -+ 0x78, 0x2e, 0x73, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, -+ 0x49, 0x63, 0x6f, 0x6e, 0x28, 0x69, 0x63, 0x6f, 0x6e, 0x29, -+ 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, -+ 0x65, 0x66, 0x20, 0x65, 0x78, 0x65, 0x63, 0x28, 0x73, 0x65, -+ 0x6c, 0x66, 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x51, 0x74, 0x43, 0x6f, 0x72, 0x65, -+ 0x2e, 0x51, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x2e, 0x73, 0x69, -+ 0x6e, 0x67, 0x6c, 0x65, 0x53, 0x68, 0x6f, 0x74, 0x28, 0x31, -+ 0x30, 0x2c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x6f, 0x6f, -+ 0x6c, 0x73, 0x2e, 0x70, 0x61, 0x72, 0x74, 0x69, 0x61, 0x6c, -+ 0x28, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, -+ 0x65, 0x6c, 0x66, 0x2e, 0x73, 0x65, 0x74, 0x4d, 0x61, 0x78, -+ 0x69, 0x6d, 0x75, 0x6d, 0x53, 0x69, 0x7a, 0x65, 0x2c, 0x0d, -+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, -+ 0x66, 0x2e, 0x63, 0x61, 0x63, 0x68, 0x65, 0x64, 0x5f, 0x6d, -+ 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x5f, 0x73, 0x69, 0x7a, -+ 0x65, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x29, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, -+ 0x72, 0x6e, 0x20, 0x73, 0x75, 0x70, 0x65, 0x72, 0x28, 0x29, -+ 0x2e, 0x65, 0x78, 0x65, 0x63, 0x28, 0x29, 0x0d, 0x0a, 0x0d, -+ 0x0a, 0x0d, 0x0a, 0x64, 0x65, 0x66, 0x20, 0x64, 0x69, 0x61, -+ 0x6c, 0x6f, 0x67, 0x28, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, -+ 0x2c, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2c, -+ 0x20, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x3d, 0x4e, 0x6f, 0x6e, -+ 0x65, 0x2c, 0x20, 0x69, 0x63, 0x6f, 0x6e, 0x3d, 0x4e, 0x6f, -+ 0x6e, 0x65, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x69, 0x63, 0x68, -+ 0x5f, 0x74, 0x65, 0x78, 0x74, 0x3d, 0x46, 0x61, 0x6c, 0x73, -+ 0x65, 0x2c, 0x20, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, -+ 0x61, 0x62, 0x6c, 0x65, 0x3d, 0x46, 0x61, 0x6c, 0x73, 0x65, -+ 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6f, -+ 0x78, 0x20, 0x3d, 0x20, 0x44, 0x69, 0x61, 0x6c, 0x6f, 0x67, -+ 0x28, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x3d, 0x70, 0x61, -+ 0x72, 0x65, 0x6e, 0x74, 0x2c, 0x20, 0x63, 0x61, 0x6e, 0x63, -+ 0x65, 0x6c, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x3d, 0x63, 0x61, -+ 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x29, -+ 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, -+ 0x20, 0x72, 0x69, 0x63, 0x68, 0x5f, 0x74, 0x65, 0x78, 0x74, -+ 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x62, 0x6f, 0x78, 0x2e, 0x73, 0x65, 0x74, 0x5f, 0x68, -+ 0x74, 0x6d, 0x6c, 0x28, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, -+ 0x65, 0x29, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, -+ 0x73, 0x65, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x62, 0x6f, 0x78, 0x2e, 0x73, 0x65, 0x74, -+ 0x5f, 0x74, 0x65, 0x78, 0x74, 0x28, 0x6d, 0x65, 0x73, 0x73, -+ 0x61, 0x67, 0x65, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x69, 0x66, 0x20, 0x69, 0x63, 0x6f, 0x6e, 0x20, -+ 0x69, 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x4e, 0x6f, 0x6e, -+ 0x65, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x62, 0x6f, 0x78, 0x2e, 0x73, 0x65, 0x74, 0x5f, -+ 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x62, 0x6f, -+ 0x78, 0x5f, 0x69, 0x63, 0x6f, 0x6e, 0x28, 0x69, 0x63, 0x6f, -+ 0x6e, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x69, 0x66, 0x20, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x20, 0x69, -+ 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x4e, 0x6f, 0x6e, 0x65, -+ 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x69, -+ 0x74, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0x51, 0x74, 0x57, 0x69, -+ 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x51, 0x41, 0x70, 0x70, -+ 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x69, -+ 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x28, 0x29, 0x2e, -+ 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, -+ 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x28, 0x29, 0x0d, 0x0a, 0x0d, -+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, -+ 0x66, 0x20, 0x6c, 0x65, 0x6e, 0x28, 0x70, 0x61, 0x72, 0x65, -+ 0x6e, 0x74, 0x5f, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x29, 0x20, -+ 0x3e, 0x20, 0x30, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x69, -+ 0x74, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0x27, 0x20, 0x2d, 0x20, -+ 0x27, 0x2e, 0x6a, 0x6f, 0x69, 0x6e, 0x28, 0x28, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x72, 0x65, -+ 0x6e, 0x74, 0x5f, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x2c, 0x0d, -+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x69, 0x74, -+ 0x6c, 0x65, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x0d, -+ 0x0a, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x62, 0x6f, 0x78, 0x2e, 0x73, 0x65, 0x74, -+ 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x54, 0x69, 0x74, 0x6c, -+ 0x65, 0x28, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x29, 0x0d, 0x0a, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, -+ 0x72, 0x6e, 0x20, 0x62, 0x6f, 0x78, 0x2e, 0x65, 0x78, 0x65, -+ 0x63, 0x28, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x51, 0x74, 0x43, -+ 0x6f, 0x72, 0x65, 0x2e, 0x71, 0x44, 0x65, 0x62, 0x75, 0x67, -+ 0x28, 0x27, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x20, -+ 0x73, 0x79, 0x73, 0x2e, 0x65, 0x78, 0x63, 0x65, 0x70, 0x74, -+ 0x68, 0x6f, 0x6f, 0x6b, 0x20, 0x74, 0x6f, 0x20, 0x70, 0x72, -+ 0x6f, 0x76, 0x69, 0x64, 0x65, 0x20, 0x64, 0x69, 0x61, 0x6c, -+ 0x6f, 0x67, 0x27, 0x29, 0x0d, 0x0a, 0x73, 0x79, 0x73, 0x2e, -+ 0x65, 0x78, 0x63, 0x65, 0x70, 0x74, 0x68, 0x6f, 0x6f, 0x6b, -+ 0x20, 0x3d, 0x20, 0x65, 0x78, 0x63, 0x65, 0x70, 0x74, 0x69, -+ 0x6f, 0x6e, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, -+ 0x5f, 0x62, 0x6f, 0x78, 0x0d, 0x0a, 0x00 -+}; -diff --git a/designer/excepthook.py b/designer/excepthook.py -new file mode 100644 -index 0000000..1c4aaa9 ---- /dev/null -+++ b/designer/excepthook.py -@@ -0,0 +1,170 @@ -+import functools -+import sys -+import traceback -+ -+from PyQt5 import QtCore, QtWidgets -+ -+QtCore.qDebug('Importing module for exception dialogs') -+ -+def exception_message_box(excType=None, excValue=None, tracebackobj=None): -+ message = traceback.format_exception(excType, excValue, tracebackobj) -+ message = ''.join(message) -+ -+ dialog( -+ parent=None, -+ title='Exception', -+ message=message, -+ icon=QtWidgets.QMessageBox.Critical, -+ ) -+ -+class FittedTextBrowser(QtWidgets.QTextBrowser): -+ def sizeHint(self): -+ default = super().sizeHint() -+ -+ if not default.isValid(): -+ return default -+ -+ document_size = self.document().size() -+ -+ desktops = QtWidgets.QApplication.desktop() -+ screen_number = desktops.screenNumber(self.parent()) -+ geometry = desktops.screenGeometry(screen_number) -+ -+ if document_size.width() == 0: -+ document_size.setWidth(geometry.width() * 0.25) -+ if document_size.height() == 0: -+ document_size.setHeight(geometry.height() * 0.4) -+ -+ scrollbar_width = QtWidgets.QApplication.style().pixelMetric( -+ QtWidgets.QStyle.PM_ScrollBarExtent -+ ) -+ -+ width = sum(( -+ document_size.width(), -+ self.contentsMargins().left(), -+ self.contentsMargins().right(), -+ scrollbar_width, -+ )) -+ -+ height = sum(( -+ document_size.height(), -+ self.contentsMargins().top(), -+ self.contentsMargins().bottom(), -+ scrollbar_width, -+ )) -+ -+ return QtCore.QSize(width, height) -+ -+ -+class DialogUi: -+ def __init__(self, parent): -+ self.layout = QtWidgets.QGridLayout(parent) -+ self.icon = QtWidgets.QLabel(parent) -+ self.message = FittedTextBrowser(parent) -+ self.copy = QtWidgets.QPushButton(parent) -+ self.buttons = QtWidgets.QDialogButtonBox(parent) -+ -+ self.copy.setText('Copy To Clipboard') -+ -+ self.layout.addWidget(self.icon, 0, 0) -+ self.layout.addWidget(self.message, 0, 1, 1, 2) -+ self.layout.addWidget(self.copy, 1, 1) -+ self.layout.addWidget(self.buttons, 1, 2) -+ -+ self.layout.setAlignment(self.copy, QtCore.Qt.AlignLeft) -+ -+ self.layout.setRowStretch(0, 1) -+ self.layout.setColumnStretch(1, 1) -+ -+ -+class Dialog(QtWidgets.QDialog): -+ def __init__(self, *args, cancellable=False, **kwargs): -+ super().__init__(*args, **kwargs) -+ -+ self.ui = DialogUi(parent=self) -+ -+ self.ui.buttons.accepted.connect(self.accept) -+ self.ui.buttons.rejected.connect(self.reject) -+ -+ self.ui.copy.clicked.connect(self.copy) -+ -+ self.setLayout(self.ui.layout) -+ buttons = QtWidgets.QDialogButtonBox.Ok -+ if cancellable: -+ buttons |= QtWidgets.QDialogButtonBox.Cancel -+ -+ self.ui.buttons.setStandardButtons(buttons) -+ -+ self.text = None -+ self.html = None -+ -+ self.cached_maximum_size = self.maximumSize() -+ -+ desktops = QtWidgets.QApplication.desktop() -+ screen_number = desktops.screenNumber(self.parent()) -+ geometry = desktops.screenGeometry(screen_number) -+ -+ self.setMaximumHeight(geometry.height() * 0.7) -+ self.setMaximumWidth(geometry.width() * 0.7) -+ -+ def copy(self): -+ QtWidgets.QApplication.clipboard().setText( -+ self.ui.message.toPlainText() + '\\n' -+ ) -+ -+ def set_text(self, text): -+ self.ui.message.setPlainText(text) -+ -+ self.html = None -+ self.text = text -+ -+ self.ui.message.setLineWrapMode(QtWidgets.QTextEdit.NoWrap) -+ -+ def set_html(self, html): -+ self.ui.message.setHtml(html) -+ -+ self.html = html -+ self.text = None -+ -+ self.ui.message.setLineWrapMode(QtWidgets.QTextEdit.WidgetWidth) -+ -+ def set_message_box_icon(self, icon): -+ self.ui.icon.setPixmap(QtWidgets.QMessageBox.standardIcon(icon)) -+ -+ def exec(self): -+ QtCore.QTimer.singleShot(10, functools.partial( -+ self.setMaximumSize, -+ self.cached_maximum_size, -+ )) -+ -+ return super().exec() -+ -+ -+def dialog(parent, message, title=None, icon=None, -+ rich_text=False, cancellable=False): -+ box = Dialog(parent=parent, cancellable=cancellable) -+ -+ if rich_text: -+ box.set_html(message) -+ else: -+ box.set_text(message) -+ -+ if icon is not None: -+ box.set_message_box_icon(icon) -+ -+ if title is not None: -+ parent_title = QtWidgets.QApplication.instance().applicationName() -+ -+ if len(parent_title) > 0: -+ title = ' - '.join(( -+ parent_title, -+ title, -+ )) -+ -+ -+ box.setWindowTitle(title) -+ -+ return box.exec() -+ -+QtCore.qDebug('Setting sys.excepthook to provide dialog') -+sys.excepthook = exception_message_box -diff --git a/designer/generate_module_literal.py b/designer/generate_module_literal.py -new file mode 100644 -index 0000000..cc6b4de ---- /dev/null -+++ b/designer/generate_module_literal.py -@@ -0,0 +1,35 @@ -+import os -+import itertools -+ -+ -+# https://repl.it/IwNE/4 -+def chunker(iterable, n): -+ "Collect data into fixed-length chunks or blocks except last due to lack of fill." -+ # chunker('ABCDEFG', 3) --> ABC DEF G" -+ -+ i = iter(iterable) -+ -+ while True: -+ t = tuple(next(i) for _ in range(n)) -+ -+ if len(t) > 0: -+ yield t -+ else: -+ break -+ -+ -+with open('excepthook.py', 'rb') as f: -+ raw = f.read() -+ -+with open('excepthook.c', 'w', newline='\n') as f: -+ f.write('const char * moduleName = "exceptiondialog";\n\n') -+ f.write('const char moduleCode[] = {\n') -+ -+ indent = ' ' * 4 -+ -+ chunks = chunker(itertools.chain(raw, b'\0'), 10) -+ lines = (', '.join('0x{:02x}'.format(b) for b in chunk) for chunk in chunks) -+ lines = (',\n'.join(indent + line for line in lines)) -+ for line in lines: -+ f.write(line) -+ f.write("\n};\n") -diff --git a/designer/pluginloader.cpp b/designer/pluginloader.cpp -index d4fb17a..d9f77ec 100644 ---- a/designer/pluginloader.cpp -+++ b/designer/pluginloader.cpp -@@ -25,6 +25,7 @@ - - #include - -+#include - #include - #include - #include -@@ -36,6 +37,114 @@ - - #include "../qpy/QtDesigner/qpydesignercustomwidgetplugin.h" - -+#include "excepthook.c" -+ -+ -+void setupExceptHookDialog(void) -+{ -+ qDebug() << "Preparing to import module"; -+ qDebug() << PyBytes_AS_STRING(PyUnicode_AsEncodedString(PyObject_Str(PySys_GetObject("path")), "utf-8", "error 1?")); -+ // https://stackoverflow.com/a/42853449/228539 -+ PyObject *pyModule = PyModule_New(moduleName); -+ // Set properties on the new module object -+ PyModule_AddStringConstant(pyModule, "__file__", ""); -+ PyObject *localDict = PyModule_GetDict(pyModule); // Returns a borrowed reference: no need to Py_DECREF() it once we are done -+ PyObject *builtins = PyEval_GetBuiltins(); // Returns a borrowed reference: no need to Py_DECREF() it once we are done -+ PyDict_SetItemString(localDict, "__builtins__", builtins); -+ -+ qDebug() << "About to import module"; -+ -+ // Define code in the newly created module -+ PyObject *pyValue = PyRun_String(moduleCode, Py_file_input, localDict, localDict); -+ qDebug() << "Code just run"; -+ if (pyValue == NULL) -+ { -+ qDebug() << "An error occurred while importing the module"; -+ -+ char * full_backtrace = NULL; -+ -+ if (PyErr_Occurred() != NULL) { -+ qDebug() << "PyErr_Occurred() != NULL"; -+ PyObject *ptype, *pvalue, *ptraceback; -+ PyObject *pystr, *module_name, *pyth_module, *pyth_func; -+ char *str; -+ char *error_description; -+ -+ PyErr_Fetch(&ptype, &pvalue, &ptraceback); -+ qDebug() << "ptype == NULL : " << (ptype == NULL); -+ qDebug() << "pvalue == NULL : " << (pvalue == NULL); -+ qDebug() << "ptraceback == NULL : " << (ptraceback == NULL); -+ pystr = PyObject_Str(pvalue); -+ qDebug() << "pystr == NULL : " << (pystr == NULL); -+ pystr = PyUnicode_AsEncodedString(pystr, "utf-8", "error 1?"); -+ qDebug() << "pystr == NULL : " << (pystr == NULL); -+ str = PyBytes_AS_STRING(pystr); -+ qDebug() << "str == NULL : " << (str == NULL); -+ if (str != NULL) -+ { -+ qDebug() << "str: " << str; -+ } -+ Py_DECREF(pystr); -+ error_description = strdup(str); -+ qDebug() << "error_description == NULL : " << (error_description == NULL); -+ if (error_description != NULL) -+ { -+ qDebug() << "error_description: " << error_description; -+ } -+ -+ /* See if we can get a full traceback */ -+ module_name = PyUnicode_Decode("traceback", 9, "utf-8", "error 2?"); -+ pyth_module = PyImport_Import(module_name); -+ Py_DECREF(module_name); -+ -+ qDebug() << "pyth_module == NULL : " << (pyth_module == NULL); -+ if (pyth_module == NULL) { -+ full_backtrace = NULL; -+ return; -+ } -+ -+ pyth_func = PyObject_GetAttrString(pyth_module, "format_exception"); -+ if (pyth_func && PyCallable_Check(pyth_func)) -+ { -+ qDebug() << "pyth_func && PyCallable_Check(pyth_func)"; -+ PyObject *pyth_val; -+ -+ pyth_val = PyObject_CallFunctionObjArgs(pyth_func, ptype, pvalue, ptraceback, Py_None, Py_True, NULL); -+ qDebug() << "pyth_val == NULL : " << (pyth_val == NULL); -+ -+ pystr = PyObject_Str(pyth_val); -+ qDebug() << "pystr == NULL : " << (pystr == NULL); -+ -+ pystr = PyUnicode_AsEncodedString(pystr, "utf-8", "error 3?"); -+ qDebug() << "pystr == NULL : " << (pystr == NULL); -+ -+ str = PyBytes_AS_STRING(pystr); -+ qDebug() << "str == NULL : " << (str == NULL); -+ -+ Py_DECREF(pystr); -+ full_backtrace = strdup(str); -+ Py_DECREF(pyth_val); -+ } -+ } -+ -+ if (full_backtrace != NULL) -+ { -+ qDebug() << "About to print backtrace"; -+ qDebug() << full_backtrace; -+ } -+ else -+ { -+ qDebug() << "Backtrace was NULL"; -+ } -+ } -+ else -+ { -+ qDebug() << "About to decref"; -+ Py_DECREF(pyValue); -+ } -+ -+ qDebug() << "Done importing module"; -+} - - // Construct the collection of Python widgets. - PyCustomWidgets::PyCustomWidgets(QObject *parent) : QObject(parent), -@@ -140,6 +249,7 @@ PyCustomWidgets::PyCustomWidgets(QObject *parent) : QObject(parent), - PyGILState_STATE gil_state = PyGILState_Ensure(); - #endif - -+ setupExceptHookDialog(); - bool fatal = importPlugins(dir, plugins); - - #if defined(WITH_THREAD) diff --git a/pluginloader.patch b/pluginloader.patch deleted file mode 100644 index db045fd85..000000000 --- a/pluginloader.patch +++ /dev/null @@ -1,886 +0,0 @@ -From a29c39d6623b2060cd19fb33cdc8fc2ff2431553 Mon Sep 17 00:00:00 2001 -From: Kyle Altendorf -Date: Tue, 18 Jul 2017 08:40:17 -0700 -Subject: [PATCH] Add sys.excepthook dialog to Designer plugin - ---- - designer/excepthook.c | 500 ++++++++++++++++++++++++++++++++++++ - designer/excepthook.py | 170 ++++++++++++ - designer/generate_module_literal.py | 35 +++ - designer/pluginloader.cpp | 118 +++++++++ - 4 files changed, 823 insertions(+) - create mode 100644 designer/excepthook.c - create mode 100644 designer/excepthook.py - create mode 100644 designer/generate_module_literal.py - -diff --git a/designer/excepthook.c b/designer/excepthook.c -new file mode 100644 -index 0000000..6a575af ---- /dev/null -+++ b/designer/excepthook.c -@@ -0,0 +1,500 @@ -+const char * moduleName = "exceptiondialog"; -+ -+const char moduleCode[] = { -+ 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x66, 0x75, 0x6e, -+ 0x63, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x0d, 0x0a, 0x69, 0x6d, -+ 0x70, 0x6f, 0x72, 0x74, 0x20, 0x73, 0x79, 0x73, 0x0d, 0x0a, -+ 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x74, 0x72, 0x61, -+ 0x63, 0x65, 0x62, 0x61, 0x63, 0x6b, 0x0d, 0x0a, 0x0d, 0x0a, -+ 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x50, 0x79, 0x51, 0x74, 0x35, -+ 0x20, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x51, 0x74, -+ 0x43, 0x6f, 0x72, 0x65, 0x2c, 0x20, 0x51, 0x74, 0x57, 0x69, -+ 0x64, 0x67, 0x65, 0x74, 0x73, 0x0d, 0x0a, 0x0d, 0x0a, 0x51, -+ 0x74, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x71, 0x44, 0x65, 0x62, -+ 0x75, 0x67, 0x28, 0x27, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, -+ 0x69, 0x6e, 0x67, 0x20, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, -+ 0x20, 0x66, 0x6f, 0x72, 0x20, 0x65, 0x78, 0x63, 0x65, 0x70, -+ 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x64, 0x69, 0x61, 0x6c, 0x6f, -+ 0x67, 0x73, 0x27, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x64, 0x65, -+ 0x66, 0x20, 0x65, 0x78, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6f, -+ 0x6e, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, -+ 0x62, 0x6f, 0x78, 0x28, 0x65, 0x78, 0x63, 0x54, 0x79, 0x70, -+ 0x65, 0x3d, 0x4e, 0x6f, 0x6e, 0x65, 0x2c, 0x20, 0x65, 0x78, -+ 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x3d, 0x4e, 0x6f, 0x6e, -+ 0x65, 0x2c, 0x20, 0x74, 0x72, 0x61, 0x63, 0x65, 0x62, 0x61, -+ 0x63, 0x6b, 0x6f, 0x62, 0x6a, 0x3d, 0x4e, 0x6f, 0x6e, 0x65, -+ 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x65, -+ 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x3d, 0x20, 0x74, 0x72, -+ 0x61, 0x63, 0x65, 0x62, 0x61, 0x63, 0x6b, 0x2e, 0x66, 0x6f, -+ 0x72, 0x6d, 0x61, 0x74, 0x5f, 0x65, 0x78, 0x63, 0x65, 0x70, -+ 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x65, 0x78, 0x63, 0x54, 0x79, -+ 0x70, 0x65, 0x2c, 0x20, 0x65, 0x78, 0x63, 0x56, 0x61, 0x6c, -+ 0x75, 0x65, 0x2c, 0x20, 0x74, 0x72, 0x61, 0x63, 0x65, 0x62, -+ 0x61, 0x63, 0x6b, 0x6f, 0x62, 0x6a, 0x29, 0x0d, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, -+ 0x20, 0x3d, 0x20, 0x27, 0x27, 0x2e, 0x6a, 0x6f, 0x69, 0x6e, -+ 0x28, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x29, 0x0d, -+ 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x69, 0x61, -+ 0x6c, 0x6f, 0x67, 0x28, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, -+ 0x3d, 0x4e, 0x6f, 0x6e, 0x65, 0x2c, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x69, 0x74, 0x6c, -+ 0x65, 0x3d, 0x27, 0x45, 0x78, 0x63, 0x65, 0x70, 0x74, 0x69, -+ 0x6f, 0x6e, 0x27, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, -+ 0x65, 0x3d, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2c, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x69, 0x63, 0x6f, 0x6e, 0x3d, 0x51, 0x74, 0x57, 0x69, 0x64, -+ 0x67, 0x65, 0x74, 0x73, 0x2e, 0x51, 0x4d, 0x65, 0x73, 0x73, -+ 0x61, 0x67, 0x65, 0x42, 0x6f, 0x78, 0x2e, 0x43, 0x72, 0x69, -+ 0x74, 0x69, 0x63, 0x61, 0x6c, 0x2c, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x63, 0x6c, 0x61, -+ 0x73, 0x73, 0x20, 0x46, 0x69, 0x74, 0x74, 0x65, 0x64, 0x54, -+ 0x65, 0x78, 0x74, 0x42, 0x72, 0x6f, 0x77, 0x73, 0x65, 0x72, -+ 0x28, 0x51, 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, -+ 0x2e, 0x51, 0x54, 0x65, 0x78, 0x74, 0x42, 0x72, 0x6f, 0x77, -+ 0x73, 0x65, 0x72, 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, -+ 0x20, 0x64, 0x65, 0x66, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x48, -+ 0x69, 0x6e, 0x74, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x29, 0x3a, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x20, 0x3d, 0x20, -+ 0x73, 0x75, 0x70, 0x65, 0x72, 0x28, 0x29, 0x2e, 0x73, 0x69, -+ 0x7a, 0x65, 0x48, 0x69, 0x6e, 0x74, 0x28, 0x29, 0x0d, 0x0a, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x64, 0x65, 0x66, -+ 0x61, 0x75, 0x6c, 0x74, 0x2e, 0x69, 0x73, 0x56, 0x61, 0x6c, -+ 0x69, 0x64, 0x28, 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, -+ 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x64, 0x65, 0x66, 0x61, -+ 0x75, 0x6c, 0x74, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, -+ 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x3d, -+ 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x64, 0x6f, 0x63, 0x75, -+ 0x6d, 0x65, 0x6e, 0x74, 0x28, 0x29, 0x2e, 0x73, 0x69, 0x7a, -+ 0x65, 0x28, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x73, 0x6b, 0x74, -+ 0x6f, 0x70, 0x73, 0x20, 0x3d, 0x20, 0x51, 0x74, 0x57, 0x69, -+ 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x51, 0x41, 0x70, 0x70, -+ 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x64, -+ 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x28, 0x29, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x63, -+ 0x72, 0x65, 0x65, 0x6e, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, -+ 0x72, 0x20, 0x3d, 0x20, 0x64, 0x65, 0x73, 0x6b, 0x74, 0x6f, -+ 0x70, 0x73, 0x2e, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x4e, -+ 0x75, 0x6d, 0x62, 0x65, 0x72, 0x28, 0x73, 0x65, 0x6c, 0x66, -+ 0x2e, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x28, 0x29, 0x29, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x67, 0x65, 0x6f, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x20, 0x3d, -+ 0x20, 0x64, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x73, 0x2e, -+ 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x47, 0x65, 0x6f, 0x6d, -+ 0x65, 0x74, 0x72, 0x79, 0x28, 0x73, 0x63, 0x72, 0x65, 0x65, -+ 0x6e, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x29, 0x0d, -+ 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x69, 0x66, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, -+ 0x6e, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x2e, 0x77, 0x69, -+ 0x64, 0x74, 0x68, 0x28, 0x29, 0x20, 0x3d, 0x3d, 0x20, 0x30, -+ 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, -+ 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x2e, 0x73, -+ 0x65, 0x74, 0x57, 0x69, 0x64, 0x74, 0x68, 0x28, 0x67, 0x65, -+ 0x6f, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x77, 0x69, 0x64, -+ 0x74, 0x68, 0x28, 0x29, 0x20, 0x2a, 0x20, 0x30, 0x2e, 0x32, -+ 0x35, 0x29, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x69, 0x66, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, -+ 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x2e, 0x68, -+ 0x65, 0x69, 0x67, 0x68, 0x74, 0x28, 0x29, 0x20, 0x3d, 0x3d, -+ 0x20, 0x30, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, 0x63, -+ 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, -+ 0x2e, 0x73, 0x65, 0x74, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, -+ 0x28, 0x67, 0x65, 0x6f, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, -+ 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x28, 0x29, 0x20, 0x2a, -+ 0x20, 0x30, 0x2e, 0x34, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x63, 0x72, -+ 0x6f, 0x6c, 0x6c, 0x62, 0x61, 0x72, 0x5f, 0x77, 0x69, 0x64, -+ 0x74, 0x68, 0x20, 0x3d, 0x20, 0x51, 0x74, 0x57, 0x69, 0x64, -+ 0x67, 0x65, 0x74, 0x73, 0x2e, 0x51, 0x41, 0x70, 0x70, 0x6c, -+ 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x73, 0x74, -+ 0x79, 0x6c, 0x65, 0x28, 0x29, 0x2e, 0x70, 0x69, 0x78, 0x65, -+ 0x6c, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x28, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x51, 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, -+ 0x73, 0x2e, 0x51, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x2e, 0x50, -+ 0x4d, 0x5f, 0x53, 0x63, 0x72, 0x6f, 0x6c, 0x6c, 0x42, 0x61, -+ 0x72, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x74, 0x0d, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x0d, 0x0a, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x77, 0x69, 0x64, 0x74, 0x68, 0x20, 0x3d, 0x20, 0x73, 0x75, -+ 0x6d, 0x28, 0x28, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, 0x63, -+ 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, -+ 0x2e, 0x77, 0x69, 0x64, 0x74, 0x68, 0x28, 0x29, 0x2c, 0x0d, -+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x63, 0x6f, -+ 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x4d, 0x61, 0x72, 0x67, -+ 0x69, 0x6e, 0x73, 0x28, 0x29, 0x2e, 0x6c, 0x65, 0x66, 0x74, -+ 0x28, 0x29, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, -+ 0x66, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, -+ 0x4d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x73, 0x28, 0x29, 0x2e, -+ 0x72, 0x69, 0x67, 0x68, 0x74, 0x28, 0x29, 0x2c, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x73, 0x63, 0x72, 0x6f, 0x6c, 0x6c, 0x62, 0x61, -+ 0x72, 0x5f, 0x77, 0x69, 0x64, 0x74, 0x68, 0x2c, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, -+ 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x20, 0x3d, -+ 0x20, 0x73, 0x75, 0x6d, 0x28, 0x28, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x73, -+ 0x69, 0x7a, 0x65, 0x2e, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, -+ 0x28, 0x29, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, -+ 0x66, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, -+ 0x4d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x73, 0x28, 0x29, 0x2e, -+ 0x74, 0x6f, 0x70, 0x28, 0x29, 0x2c, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, -+ 0x6e, 0x74, 0x73, 0x4d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x73, -+ 0x28, 0x29, 0x2e, 0x62, 0x6f, 0x74, 0x74, 0x6f, 0x6d, 0x28, -+ 0x29, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x63, 0x72, 0x6f, -+ 0x6c, 0x6c, 0x62, 0x61, 0x72, 0x5f, 0x77, 0x69, 0x64, 0x74, -+ 0x68, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x29, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, -+ 0x72, 0x6e, 0x20, 0x51, 0x74, 0x43, 0x6f, 0x72, 0x65, 0x2e, -+ 0x51, 0x53, 0x69, 0x7a, 0x65, 0x28, 0x77, 0x69, 0x64, 0x74, -+ 0x68, 0x2c, 0x20, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x29, -+ 0x0d, 0x0a, 0x0d, 0x0a, 0x0d, 0x0a, 0x63, 0x6c, 0x61, 0x73, -+ 0x73, 0x20, 0x44, 0x69, 0x61, 0x6c, 0x6f, 0x67, 0x55, 0x69, -+ 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x66, -+ 0x20, 0x5f, 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x5f, 0x5f, 0x28, -+ 0x73, 0x65, 0x6c, 0x66, 0x2c, 0x20, 0x70, 0x61, 0x72, 0x65, -+ 0x6e, 0x74, 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x6c, -+ 0x61, 0x79, 0x6f, 0x75, 0x74, 0x20, 0x3d, 0x20, 0x51, 0x74, -+ 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x51, 0x47, -+ 0x72, 0x69, 0x64, 0x4c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x28, -+ 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x29, 0x0d, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, -+ 0x66, 0x2e, 0x69, 0x63, 0x6f, 0x6e, 0x20, 0x3d, 0x20, 0x51, -+ 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x51, -+ 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x28, 0x70, 0x61, 0x72, 0x65, -+ 0x6e, 0x74, 0x29, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x6d, 0x65, -+ 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x3d, 0x20, 0x46, 0x69, -+ 0x74, 0x74, 0x65, 0x64, 0x54, 0x65, 0x78, 0x74, 0x42, 0x72, -+ 0x6f, 0x77, 0x73, 0x65, 0x72, 0x28, 0x70, 0x61, 0x72, 0x65, -+ 0x6e, 0x74, 0x29, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x63, 0x6f, -+ 0x70, 0x79, 0x20, 0x3d, 0x20, 0x51, 0x74, 0x57, 0x69, 0x64, -+ 0x67, 0x65, 0x74, 0x73, 0x2e, 0x51, 0x50, 0x75, 0x73, 0x68, -+ 0x42, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x28, 0x70, 0x61, 0x72, -+ 0x65, 0x6e, 0x74, 0x29, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x62, -+ 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x73, 0x20, 0x3d, 0x20, 0x51, -+ 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x51, -+ 0x44, 0x69, 0x61, 0x6c, 0x6f, 0x67, 0x42, 0x75, 0x74, 0x74, -+ 0x6f, 0x6e, 0x42, 0x6f, 0x78, 0x28, 0x70, 0x61, 0x72, 0x65, -+ 0x6e, 0x74, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, -+ 0x63, 0x6f, 0x70, 0x79, 0x2e, 0x73, 0x65, 0x74, 0x54, 0x65, -+ 0x78, 0x74, 0x28, 0x27, 0x43, 0x6f, 0x70, 0x79, 0x20, 0x54, -+ 0x6f, 0x20, 0x43, 0x6c, 0x69, 0x70, 0x62, 0x6f, 0x61, 0x72, -+ 0x64, 0x27, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, -+ 0x6c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x2e, 0x61, 0x64, 0x64, -+ 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x28, 0x73, 0x65, 0x6c, -+ 0x66, 0x2e, 0x69, 0x63, 0x6f, 0x6e, 0x2c, 0x20, 0x30, 0x2c, -+ 0x20, 0x30, 0x29, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x6c, 0x61, -+ 0x79, 0x6f, 0x75, 0x74, 0x2e, 0x61, 0x64, 0x64, 0x57, 0x69, -+ 0x64, 0x67, 0x65, 0x74, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, -+ 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2c, 0x20, 0x30, -+ 0x2c, 0x20, 0x31, 0x2c, 0x20, 0x31, 0x2c, 0x20, 0x32, 0x29, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x6c, 0x61, 0x79, 0x6f, 0x75, -+ 0x74, 0x2e, 0x61, 0x64, 0x64, 0x57, 0x69, 0x64, 0x67, 0x65, -+ 0x74, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x63, 0x6f, 0x70, -+ 0x79, 0x2c, 0x20, 0x31, 0x2c, 0x20, 0x31, 0x29, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, -+ 0x6c, 0x66, 0x2e, 0x6c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x2e, -+ 0x61, 0x64, 0x64, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x28, -+ 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x62, 0x75, 0x74, 0x74, 0x6f, -+ 0x6e, 0x73, 0x2c, 0x20, 0x31, 0x2c, 0x20, 0x32, 0x29, 0x0d, -+ 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x6c, 0x61, 0x79, 0x6f, -+ 0x75, 0x74, 0x2e, 0x73, 0x65, 0x74, 0x41, 0x6c, 0x69, 0x67, -+ 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x28, 0x73, 0x65, 0x6c, 0x66, -+ 0x2e, 0x63, 0x6f, 0x70, 0x79, 0x2c, 0x20, 0x51, 0x74, 0x43, -+ 0x6f, 0x72, 0x65, 0x2e, 0x51, 0x74, 0x2e, 0x41, 0x6c, 0x69, -+ 0x67, 0x6e, 0x4c, 0x65, 0x66, 0x74, 0x29, 0x0d, 0x0a, 0x0d, -+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, -+ 0x65, 0x6c, 0x66, 0x2e, 0x6c, 0x61, 0x79, 0x6f, 0x75, 0x74, -+ 0x2e, 0x73, 0x65, 0x74, 0x52, 0x6f, 0x77, 0x53, 0x74, 0x72, -+ 0x65, 0x74, 0x63, 0x68, 0x28, 0x30, 0x2c, 0x20, 0x31, 0x29, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x6c, 0x61, 0x79, 0x6f, 0x75, -+ 0x74, 0x2e, 0x73, 0x65, 0x74, 0x43, 0x6f, 0x6c, 0x75, 0x6d, -+ 0x6e, 0x53, 0x74, 0x72, 0x65, 0x74, 0x63, 0x68, 0x28, 0x31, -+ 0x2c, 0x20, 0x31, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x0d, 0x0a, -+ 0x63, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x44, 0x69, 0x61, 0x6c, -+ 0x6f, 0x67, 0x28, 0x51, 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, -+ 0x74, 0x73, 0x2e, 0x51, 0x44, 0x69, 0x61, 0x6c, 0x6f, 0x67, -+ 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, -+ 0x66, 0x20, 0x5f, 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x5f, 0x5f, -+ 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2c, 0x20, 0x2a, 0x61, 0x72, -+ 0x67, 0x73, 0x2c, 0x20, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, -+ 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x3d, 0x46, 0x61, 0x6c, 0x73, -+ 0x65, 0x2c, 0x20, 0x2a, 0x2a, 0x6b, 0x77, 0x61, 0x72, 0x67, -+ 0x73, 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x73, 0x75, 0x70, 0x65, 0x72, 0x28, 0x29, -+ 0x2e, 0x5f, 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x5f, 0x5f, 0x28, -+ 0x2a, 0x61, 0x72, 0x67, 0x73, 0x2c, 0x20, 0x2a, 0x2a, 0x6b, -+ 0x77, 0x61, 0x72, 0x67, 0x73, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, -+ 0x6c, 0x66, 0x2e, 0x75, 0x69, 0x20, 0x3d, 0x20, 0x44, 0x69, -+ 0x61, 0x6c, 0x6f, 0x67, 0x55, 0x69, 0x28, 0x70, 0x61, 0x72, -+ 0x65, 0x6e, 0x74, 0x3d, 0x73, 0x65, 0x6c, 0x66, 0x29, 0x0d, -+ 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x75, 0x69, 0x2e, 0x62, -+ 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x73, 0x2e, 0x61, 0x63, 0x63, -+ 0x65, 0x70, 0x74, 0x65, 0x64, 0x2e, 0x63, 0x6f, 0x6e, 0x6e, -+ 0x65, 0x63, 0x74, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x61, -+ 0x63, 0x63, 0x65, 0x70, 0x74, 0x29, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, -+ 0x2e, 0x75, 0x69, 0x2e, 0x62, 0x75, 0x74, 0x74, 0x6f, 0x6e, -+ 0x73, 0x2e, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x65, 0x64, -+ 0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x28, 0x73, -+ 0x65, 0x6c, 0x66, 0x2e, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, -+ 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x75, 0x69, -+ 0x2e, 0x63, 0x6f, 0x70, 0x79, 0x2e, 0x63, 0x6c, 0x69, 0x63, -+ 0x6b, 0x65, 0x64, 0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, -+ 0x74, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x63, 0x6f, 0x70, -+ 0x79, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x73, -+ 0x65, 0x74, 0x4c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x28, 0x73, -+ 0x65, 0x6c, 0x66, 0x2e, 0x75, 0x69, 0x2e, 0x6c, 0x61, 0x79, -+ 0x6f, 0x75, 0x74, 0x29, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x62, 0x75, 0x74, 0x74, 0x6f, 0x6e, -+ 0x73, 0x20, 0x3d, 0x20, 0x51, 0x74, 0x57, 0x69, 0x64, 0x67, -+ 0x65, 0x74, 0x73, 0x2e, 0x51, 0x44, 0x69, 0x61, 0x6c, 0x6f, -+ 0x67, 0x42, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x42, 0x6f, 0x78, -+ 0x2e, 0x4f, 0x6b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x63, 0x61, 0x6e, 0x63, -+ 0x65, 0x6c, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x3a, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x62, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x73, 0x20, -+ 0x7c, 0x3d, 0x20, 0x51, 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, -+ 0x74, 0x73, 0x2e, 0x51, 0x44, 0x69, 0x61, 0x6c, 0x6f, 0x67, -+ 0x42, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x42, 0x6f, 0x78, 0x2e, -+ 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x0d, 0x0a, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, -+ 0x6c, 0x66, 0x2e, 0x75, 0x69, 0x2e, 0x62, 0x75, 0x74, 0x74, -+ 0x6f, 0x6e, 0x73, 0x2e, 0x73, 0x65, 0x74, 0x53, 0x74, 0x61, -+ 0x6e, 0x64, 0x61, 0x72, 0x64, 0x42, 0x75, 0x74, 0x74, 0x6f, -+ 0x6e, 0x73, 0x28, 0x62, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x73, -+ 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x65, -+ 0x78, 0x74, 0x20, 0x3d, 0x20, 0x4e, 0x6f, 0x6e, 0x65, 0x0d, -+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, -+ 0x65, 0x6c, 0x66, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x20, 0x3d, -+ 0x20, 0x4e, 0x6f, 0x6e, 0x65, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, -+ 0x66, 0x2e, 0x63, 0x61, 0x63, 0x68, 0x65, 0x64, 0x5f, 0x6d, -+ 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x5f, 0x73, 0x69, 0x7a, -+ 0x65, 0x20, 0x3d, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x6d, -+ 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x53, 0x69, 0x7a, 0x65, -+ 0x28, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x73, 0x6b, 0x74, 0x6f, -+ 0x70, 0x73, 0x20, 0x3d, 0x20, 0x51, 0x74, 0x57, 0x69, 0x64, -+ 0x67, 0x65, 0x74, 0x73, 0x2e, 0x51, 0x41, 0x70, 0x70, 0x6c, -+ 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x64, 0x65, -+ 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x28, 0x29, 0x0d, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x63, 0x72, -+ 0x65, 0x65, 0x6e, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, -+ 0x20, 0x3d, 0x20, 0x64, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, -+ 0x73, 0x2e, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x4e, 0x75, -+ 0x6d, 0x62, 0x65, 0x72, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, -+ 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x28, 0x29, 0x29, 0x0d, -+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x67, -+ 0x65, 0x6f, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x20, 0x3d, 0x20, -+ 0x64, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x73, 0x2e, 0x73, -+ 0x63, 0x72, 0x65, 0x65, 0x6e, 0x47, 0x65, 0x6f, 0x6d, 0x65, -+ 0x74, 0x72, 0x79, 0x28, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, -+ 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x29, 0x0d, 0x0a, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x73, 0x65, 0x74, 0x4d, 0x61, -+ 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x48, 0x65, 0x69, 0x67, 0x68, -+ 0x74, 0x28, 0x67, 0x65, 0x6f, 0x6d, 0x65, 0x74, 0x72, 0x79, -+ 0x2e, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x28, 0x29, 0x20, -+ 0x2a, 0x20, 0x30, 0x2e, 0x37, 0x29, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, -+ 0x2e, 0x73, 0x65, 0x74, 0x4d, 0x61, 0x78, 0x69, 0x6d, 0x75, -+ 0x6d, 0x57, 0x69, 0x64, 0x74, 0x68, 0x28, 0x67, 0x65, 0x6f, -+ 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x77, 0x69, 0x64, 0x74, -+ 0x68, 0x28, 0x29, 0x20, 0x2a, 0x20, 0x30, 0x2e, 0x37, 0x29, -+ 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, -+ 0x66, 0x20, 0x63, 0x6f, 0x70, 0x79, 0x28, 0x73, 0x65, 0x6c, -+ 0x66, 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x51, 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, -+ 0x74, 0x73, 0x2e, 0x51, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, -+ 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x63, 0x6c, 0x69, 0x70, -+ 0x62, 0x6f, 0x61, 0x72, 0x64, 0x28, 0x29, 0x2e, 0x73, 0x65, -+ 0x74, 0x54, 0x65, 0x78, 0x74, 0x28, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x75, 0x69, 0x2e, 0x6d, 0x65, -+ 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x74, 0x6f, 0x50, 0x6c, -+ 0x61, 0x69, 0x6e, 0x54, 0x65, 0x78, 0x74, 0x28, 0x29, 0x20, -+ 0x2b, 0x20, 0x27, 0x5c, 0x5c, 0x6e, 0x27, 0x0d, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x0d, 0x0a, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x66, 0x20, -+ 0x73, 0x65, 0x74, 0x5f, 0x74, 0x65, 0x78, 0x74, 0x28, 0x73, -+ 0x65, 0x6c, 0x66, 0x2c, 0x20, 0x74, 0x65, 0x78, 0x74, 0x29, -+ 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x75, 0x69, 0x2e, 0x6d, -+ 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x73, 0x65, 0x74, -+ 0x50, 0x6c, 0x61, 0x69, 0x6e, 0x54, 0x65, 0x78, 0x74, 0x28, -+ 0x74, 0x65, 0x78, 0x74, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, -+ 0x66, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x20, 0x3d, 0x20, 0x4e, -+ 0x6f, 0x6e, 0x65, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x65, -+ 0x78, 0x74, 0x20, 0x3d, 0x20, 0x74, 0x65, 0x78, 0x74, 0x0d, -+ 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x75, 0x69, 0x2e, 0x6d, -+ 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x73, 0x65, 0x74, -+ 0x4c, 0x69, 0x6e, 0x65, 0x57, 0x72, 0x61, 0x70, 0x4d, 0x6f, -+ 0x64, 0x65, 0x28, 0x51, 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, -+ 0x74, 0x73, 0x2e, 0x51, 0x54, 0x65, 0x78, 0x74, 0x45, 0x64, -+ 0x69, 0x74, 0x2e, 0x4e, 0x6f, 0x57, 0x72, 0x61, 0x70, 0x29, -+ 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, -+ 0x66, 0x20, 0x73, 0x65, 0x74, 0x5f, 0x68, 0x74, 0x6d, 0x6c, -+ 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2c, 0x20, 0x68, 0x74, 0x6d, -+ 0x6c, 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x75, 0x69, -+ 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x73, -+ 0x65, 0x74, 0x48, 0x74, 0x6d, 0x6c, 0x28, 0x68, 0x74, 0x6d, -+ 0x6c, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x68, -+ 0x74, 0x6d, 0x6c, 0x20, 0x3d, 0x20, 0x68, 0x74, 0x6d, 0x6c, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x65, 0x78, 0x74, 0x20, -+ 0x3d, 0x20, 0x4e, 0x6f, 0x6e, 0x65, 0x0d, 0x0a, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, -+ 0x6c, 0x66, 0x2e, 0x75, 0x69, 0x2e, 0x6d, 0x65, 0x73, 0x73, -+ 0x61, 0x67, 0x65, 0x2e, 0x73, 0x65, 0x74, 0x4c, 0x69, 0x6e, -+ 0x65, 0x57, 0x72, 0x61, 0x70, 0x4d, 0x6f, 0x64, 0x65, 0x28, -+ 0x51, 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, -+ 0x51, 0x54, 0x65, 0x78, 0x74, 0x45, 0x64, 0x69, 0x74, 0x2e, -+ 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x57, 0x69, 0x64, 0x74, -+ 0x68, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x64, 0x65, 0x66, 0x20, 0x73, 0x65, 0x74, 0x5f, 0x6d, 0x65, -+ 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x62, 0x6f, 0x78, 0x5f, -+ 0x69, 0x63, 0x6f, 0x6e, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2c, -+ 0x20, 0x69, 0x63, 0x6f, 0x6e, 0x29, 0x3a, 0x0d, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, -+ 0x66, 0x2e, 0x75, 0x69, 0x2e, 0x69, 0x63, 0x6f, 0x6e, 0x2e, -+ 0x73, 0x65, 0x74, 0x50, 0x69, 0x78, 0x6d, 0x61, 0x70, 0x28, -+ 0x51, 0x74, 0x57, 0x69, 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, -+ 0x51, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x6f, -+ 0x78, 0x2e, 0x73, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, -+ 0x49, 0x63, 0x6f, 0x6e, 0x28, 0x69, 0x63, 0x6f, 0x6e, 0x29, -+ 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, -+ 0x65, 0x66, 0x20, 0x65, 0x78, 0x65, 0x63, 0x28, 0x73, 0x65, -+ 0x6c, 0x66, 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x51, 0x74, 0x43, 0x6f, 0x72, 0x65, -+ 0x2e, 0x51, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x2e, 0x73, 0x69, -+ 0x6e, 0x67, 0x6c, 0x65, 0x53, 0x68, 0x6f, 0x74, 0x28, 0x31, -+ 0x30, 0x2c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x6f, 0x6f, -+ 0x6c, 0x73, 0x2e, 0x70, 0x61, 0x72, 0x74, 0x69, 0x61, 0x6c, -+ 0x28, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, -+ 0x65, 0x6c, 0x66, 0x2e, 0x73, 0x65, 0x74, 0x4d, 0x61, 0x78, -+ 0x69, 0x6d, 0x75, 0x6d, 0x53, 0x69, 0x7a, 0x65, 0x2c, 0x0d, -+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, -+ 0x66, 0x2e, 0x63, 0x61, 0x63, 0x68, 0x65, 0x64, 0x5f, 0x6d, -+ 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x5f, 0x73, 0x69, 0x7a, -+ 0x65, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x29, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, -+ 0x72, 0x6e, 0x20, 0x73, 0x75, 0x70, 0x65, 0x72, 0x28, 0x29, -+ 0x2e, 0x65, 0x78, 0x65, 0x63, 0x28, 0x29, 0x0d, 0x0a, 0x0d, -+ 0x0a, 0x0d, 0x0a, 0x64, 0x65, 0x66, 0x20, 0x64, 0x69, 0x61, -+ 0x6c, 0x6f, 0x67, 0x28, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, -+ 0x2c, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2c, -+ 0x20, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x3d, 0x4e, 0x6f, 0x6e, -+ 0x65, 0x2c, 0x20, 0x69, 0x63, 0x6f, 0x6e, 0x3d, 0x4e, 0x6f, -+ 0x6e, 0x65, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x69, 0x63, 0x68, -+ 0x5f, 0x74, 0x65, 0x78, 0x74, 0x3d, 0x46, 0x61, 0x6c, 0x73, -+ 0x65, 0x2c, 0x20, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, -+ 0x61, 0x62, 0x6c, 0x65, 0x3d, 0x46, 0x61, 0x6c, 0x73, 0x65, -+ 0x29, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6f, -+ 0x78, 0x20, 0x3d, 0x20, 0x44, 0x69, 0x61, 0x6c, 0x6f, 0x67, -+ 0x28, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x3d, 0x70, 0x61, -+ 0x72, 0x65, 0x6e, 0x74, 0x2c, 0x20, 0x63, 0x61, 0x6e, 0x63, -+ 0x65, 0x6c, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x3d, 0x63, 0x61, -+ 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x29, -+ 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, -+ 0x20, 0x72, 0x69, 0x63, 0x68, 0x5f, 0x74, 0x65, 0x78, 0x74, -+ 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x62, 0x6f, 0x78, 0x2e, 0x73, 0x65, 0x74, 0x5f, 0x68, -+ 0x74, 0x6d, 0x6c, 0x28, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, -+ 0x65, 0x29, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, -+ 0x73, 0x65, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x62, 0x6f, 0x78, 0x2e, 0x73, 0x65, 0x74, -+ 0x5f, 0x74, 0x65, 0x78, 0x74, 0x28, 0x6d, 0x65, 0x73, 0x73, -+ 0x61, 0x67, 0x65, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x69, 0x66, 0x20, 0x69, 0x63, 0x6f, 0x6e, 0x20, -+ 0x69, 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x4e, 0x6f, 0x6e, -+ 0x65, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x62, 0x6f, 0x78, 0x2e, 0x73, 0x65, 0x74, 0x5f, -+ 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x62, 0x6f, -+ 0x78, 0x5f, 0x69, 0x63, 0x6f, 0x6e, 0x28, 0x69, 0x63, 0x6f, -+ 0x6e, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x69, 0x66, 0x20, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x20, 0x69, -+ 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x4e, 0x6f, 0x6e, 0x65, -+ 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x69, -+ 0x74, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0x51, 0x74, 0x57, 0x69, -+ 0x64, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x51, 0x41, 0x70, 0x70, -+ 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x69, -+ 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x28, 0x29, 0x2e, -+ 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, -+ 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x28, 0x29, 0x0d, 0x0a, 0x0d, -+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, -+ 0x66, 0x20, 0x6c, 0x65, 0x6e, 0x28, 0x70, 0x61, 0x72, 0x65, -+ 0x6e, 0x74, 0x5f, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x29, 0x20, -+ 0x3e, 0x20, 0x30, 0x3a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x69, -+ 0x74, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0x27, 0x20, 0x2d, 0x20, -+ 0x27, 0x2e, 0x6a, 0x6f, 0x69, 0x6e, 0x28, 0x28, 0x0d, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x72, 0x65, -+ 0x6e, 0x74, 0x5f, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x2c, 0x0d, -+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x69, 0x74, -+ 0x6c, 0x65, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x0d, -+ 0x0a, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x62, 0x6f, 0x78, 0x2e, 0x73, 0x65, 0x74, -+ 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x54, 0x69, 0x74, 0x6c, -+ 0x65, 0x28, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x29, 0x0d, 0x0a, -+ 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, -+ 0x72, 0x6e, 0x20, 0x62, 0x6f, 0x78, 0x2e, 0x65, 0x78, 0x65, -+ 0x63, 0x28, 0x29, 0x0d, 0x0a, 0x0d, 0x0a, 0x51, 0x74, 0x43, -+ 0x6f, 0x72, 0x65, 0x2e, 0x71, 0x44, 0x65, 0x62, 0x75, 0x67, -+ 0x28, 0x27, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x20, -+ 0x73, 0x79, 0x73, 0x2e, 0x65, 0x78, 0x63, 0x65, 0x70, 0x74, -+ 0x68, 0x6f, 0x6f, 0x6b, 0x20, 0x74, 0x6f, 0x20, 0x70, 0x72, -+ 0x6f, 0x76, 0x69, 0x64, 0x65, 0x20, 0x64, 0x69, 0x61, 0x6c, -+ 0x6f, 0x67, 0x27, 0x29, 0x0d, 0x0a, 0x73, 0x79, 0x73, 0x2e, -+ 0x65, 0x78, 0x63, 0x65, 0x70, 0x74, 0x68, 0x6f, 0x6f, 0x6b, -+ 0x20, 0x3d, 0x20, 0x65, 0x78, 0x63, 0x65, 0x70, 0x74, 0x69, -+ 0x6f, 0x6e, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, -+ 0x5f, 0x62, 0x6f, 0x78, 0x0d, 0x0a, 0x00 -+}; -diff --git a/designer/excepthook.py b/designer/excepthook.py -new file mode 100644 -index 0000000..1c4aaa9 ---- /dev/null -+++ b/designer/excepthook.py -@@ -0,0 +1,170 @@ -+import functools -+import sys -+import traceback -+ -+from PyQt5 import QtCore, QtWidgets -+ -+QtCore.qDebug('Importing module for exception dialogs') -+ -+def exception_message_box(excType=None, excValue=None, tracebackobj=None): -+ message = traceback.format_exception(excType, excValue, tracebackobj) -+ message = ''.join(message) -+ -+ dialog( -+ parent=None, -+ title='Exception', -+ message=message, -+ icon=QtWidgets.QMessageBox.Critical, -+ ) -+ -+class FittedTextBrowser(QtWidgets.QTextBrowser): -+ def sizeHint(self): -+ default = super().sizeHint() -+ -+ if not default.isValid(): -+ return default -+ -+ document_size = self.document().size() -+ -+ desktops = QtWidgets.QApplication.desktop() -+ screen_number = desktops.screenNumber(self.parent()) -+ geometry = desktops.screenGeometry(screen_number) -+ -+ if document_size.width() == 0: -+ document_size.setWidth(geometry.width() * 0.25) -+ if document_size.height() == 0: -+ document_size.setHeight(geometry.height() * 0.4) -+ -+ scrollbar_width = QtWidgets.QApplication.style().pixelMetric( -+ QtWidgets.QStyle.PM_ScrollBarExtent -+ ) -+ -+ width = sum(( -+ document_size.width(), -+ self.contentsMargins().left(), -+ self.contentsMargins().right(), -+ scrollbar_width, -+ )) -+ -+ height = sum(( -+ document_size.height(), -+ self.contentsMargins().top(), -+ self.contentsMargins().bottom(), -+ scrollbar_width, -+ )) -+ -+ return QtCore.QSize(width, height) -+ -+ -+class DialogUi: -+ def __init__(self, parent): -+ self.layout = QtWidgets.QGridLayout(parent) -+ self.icon = QtWidgets.QLabel(parent) -+ self.message = FittedTextBrowser(parent) -+ self.copy = QtWidgets.QPushButton(parent) -+ self.buttons = QtWidgets.QDialogButtonBox(parent) -+ -+ self.copy.setText('Copy To Clipboard') -+ -+ self.layout.addWidget(self.icon, 0, 0) -+ self.layout.addWidget(self.message, 0, 1, 1, 2) -+ self.layout.addWidget(self.copy, 1, 1) -+ self.layout.addWidget(self.buttons, 1, 2) -+ -+ self.layout.setAlignment(self.copy, QtCore.Qt.AlignLeft) -+ -+ self.layout.setRowStretch(0, 1) -+ self.layout.setColumnStretch(1, 1) -+ -+ -+class Dialog(QtWidgets.QDialog): -+ def __init__(self, *args, cancellable=False, **kwargs): -+ super().__init__(*args, **kwargs) -+ -+ self.ui = DialogUi(parent=self) -+ -+ self.ui.buttons.accepted.connect(self.accept) -+ self.ui.buttons.rejected.connect(self.reject) -+ -+ self.ui.copy.clicked.connect(self.copy) -+ -+ self.setLayout(self.ui.layout) -+ buttons = QtWidgets.QDialogButtonBox.Ok -+ if cancellable: -+ buttons |= QtWidgets.QDialogButtonBox.Cancel -+ -+ self.ui.buttons.setStandardButtons(buttons) -+ -+ self.text = None -+ self.html = None -+ -+ self.cached_maximum_size = self.maximumSize() -+ -+ desktops = QtWidgets.QApplication.desktop() -+ screen_number = desktops.screenNumber(self.parent()) -+ geometry = desktops.screenGeometry(screen_number) -+ -+ self.setMaximumHeight(geometry.height() * 0.7) -+ self.setMaximumWidth(geometry.width() * 0.7) -+ -+ def copy(self): -+ QtWidgets.QApplication.clipboard().setText( -+ self.ui.message.toPlainText() + '\\n' -+ ) -+ -+ def set_text(self, text): -+ self.ui.message.setPlainText(text) -+ -+ self.html = None -+ self.text = text -+ -+ self.ui.message.setLineWrapMode(QtWidgets.QTextEdit.NoWrap) -+ -+ def set_html(self, html): -+ self.ui.message.setHtml(html) -+ -+ self.html = html -+ self.text = None -+ -+ self.ui.message.setLineWrapMode(QtWidgets.QTextEdit.WidgetWidth) -+ -+ def set_message_box_icon(self, icon): -+ self.ui.icon.setPixmap(QtWidgets.QMessageBox.standardIcon(icon)) -+ -+ def exec(self): -+ QtCore.QTimer.singleShot(10, functools.partial( -+ self.setMaximumSize, -+ self.cached_maximum_size, -+ )) -+ -+ return super().exec() -+ -+ -+def dialog(parent, message, title=None, icon=None, -+ rich_text=False, cancellable=False): -+ box = Dialog(parent=parent, cancellable=cancellable) -+ -+ if rich_text: -+ box.set_html(message) -+ else: -+ box.set_text(message) -+ -+ if icon is not None: -+ box.set_message_box_icon(icon) -+ -+ if title is not None: -+ parent_title = QtWidgets.QApplication.instance().applicationName() -+ -+ if len(parent_title) > 0: -+ title = ' - '.join(( -+ parent_title, -+ title, -+ )) -+ -+ -+ box.setWindowTitle(title) -+ -+ return box.exec() -+ -+QtCore.qDebug('Setting sys.excepthook to provide dialog') -+sys.excepthook = exception_message_box -diff --git a/designer/generate_module_literal.py b/designer/generate_module_literal.py -new file mode 100644 -index 0000000..cc6b4de ---- /dev/null -+++ b/designer/generate_module_literal.py -@@ -0,0 +1,35 @@ -+import os -+import itertools -+ -+ -+# https://repl.it/IwNE/4 -+def chunker(iterable, n): -+ "Collect data into fixed-length chunks or blocks except last due to lack of fill." -+ # chunker('ABCDEFG', 3) --> ABC DEF G" -+ -+ i = iter(iterable) -+ -+ while True: -+ t = tuple(next(i) for _ in range(n)) -+ -+ if len(t) > 0: -+ yield t -+ else: -+ break -+ -+ -+with open('excepthook.py', 'rb') as f: -+ raw = f.read() -+ -+with open('excepthook.c', 'w', newline='\n') as f: -+ f.write('const char * moduleName = "exceptiondialog";\n\n') -+ f.write('const char moduleCode[] = {\n') -+ -+ indent = ' ' * 4 -+ -+ chunks = chunker(itertools.chain(raw, b'\0'), 10) -+ lines = (', '.join('0x{:02x}'.format(b) for b in chunk) for chunk in chunks) -+ lines = (',\n'.join(indent + line for line in lines)) -+ for line in lines: -+ f.write(line) -+ f.write("\n};\n") -diff --git a/designer/pluginloader.cpp b/designer/pluginloader.cpp -index 771270d..c589b13 100644 ---- a/designer/pluginloader.cpp -+++ b/designer/pluginloader.cpp -@@ -25,6 +25,7 @@ - - #include - -+#include - #include - #include - #include -@@ -36,6 +37,114 @@ - - #include "../qpy/QtDesigner/qpydesignercustomwidgetplugin.h" - -+#include "excepthook.c" -+ -+ -+void setupExceptHookDialog(void) -+{ -+ qDebug() << "Preparing to import module"; -+ -+ // https://stackoverflow.com/a/42853449/228539 -+ PyObject *pyModule = PyModule_New(moduleName); -+ // Set properties on the new module object -+ PyModule_AddStringConstant(pyModule, "__file__", ""); -+ PyObject *localDict = PyModule_GetDict(pyModule); // Returns a borrowed reference: no need to Py_DECREF() it once we are done -+ PyObject *builtins = PyEval_GetBuiltins(); // Returns a borrowed reference: no need to Py_DECREF() it once we are done -+ PyDict_SetItemString(localDict, "__builtins__", builtins); -+ -+ qDebug() << "About to import module"; -+ -+ // Define code in the newly created module -+ PyObject *pyValue = PyRun_String(moduleCode, Py_file_input, localDict, localDict); -+ qDebug() << "Code just run"; -+ if (pyValue == NULL) -+ { -+ qDebug() << "An error occurred while importing the module"; -+ -+ char * full_backtrace = NULL; -+ -+ if (PyErr_Occurred() != NULL) { -+ qDebug() << "PyErr_Occurred() != NULL"; -+ PyObject *ptype, *pvalue, *ptraceback; -+ PyObject *pystr, *module_name, *pyth_module, *pyth_func; -+ char *str; -+ char *error_description; -+ -+ PyErr_Fetch(&ptype, &pvalue, &ptraceback); -+ qDebug() << "ptype == NULL : " << (ptype == NULL); -+ qDebug() << "pvalue == NULL : " << (pvalue == NULL); -+ qDebug() << "ptraceback == NULL : " << (ptraceback == NULL); -+ pystr = PyObject_Str(pvalue); -+ qDebug() << "pystr == NULL : " << (pystr == NULL); -+ pystr = PyUnicode_AsEncodedString(pystr, "utf-8", "error 1?"); -+ qDebug() << "pystr == NULL : " << (pystr == NULL); -+ str = PyBytes_AS_STRING(pystr); -+ qDebug() << "str == NULL : " << (str == NULL); -+ if (str != NULL) -+ { -+ qDebug() << "str: " << str; -+ } -+ Py_DECREF(pystr); -+ error_description = strdup(str); -+ qDebug() << "error_description == NULL : " << (error_description == NULL); -+ if (error_description != NULL) -+ { -+ qDebug() << "error_description: " << error_description; -+ } -+ -+ /* See if we can get a full traceback */ -+ module_name = PyUnicode_Decode("traceback", 9, "utf-8", "error 2?"); -+ pyth_module = PyImport_Import(module_name); -+ Py_DECREF(module_name); -+ -+ qDebug() << "pyth_module == NULL : " << (pyth_module == NULL); -+ if (pyth_module == NULL) { -+ full_backtrace = NULL; -+ return; -+ } -+ -+ pyth_func = PyObject_GetAttrString(pyth_module, "format_exception"); -+ if (pyth_func && PyCallable_Check(pyth_func)) -+ { -+ qDebug() << "pyth_func && PyCallable_Check(pyth_func)"; -+ PyObject *pyth_val; -+ -+ pyth_val = PyObject_CallFunctionObjArgs(pyth_func, ptype, pvalue, ptraceback, Py_None, Py_True, NULL); -+ qDebug() << "pyth_val == NULL : " << (pyth_val == NULL); -+ -+ pystr = PyObject_Str(pyth_val); -+ qDebug() << "pystr == NULL : " << (pystr == NULL); -+ -+ pystr = PyUnicode_AsEncodedString(pystr, "utf-8", "error 3?"); -+ qDebug() << "pystr == NULL : " << (pystr == NULL); -+ -+ str = PyBytes_AS_STRING(pystr); -+ qDebug() << "str == NULL : " << (str == NULL); -+ -+ Py_DECREF(pystr); -+ full_backtrace = strdup(str); -+ Py_DECREF(pyth_val); -+ } -+ } -+ -+ if (full_backtrace != NULL) -+ { -+ qDebug() << "About to print backtrace"; -+ qDebug() << full_backtrace; -+ } -+ else -+ { -+ qDebug() << "Backtrace was NULL"; -+ } -+ } -+ else -+ { -+ qDebug() << "About to decref"; -+ Py_DECREF(pyValue); -+ } -+ -+ qDebug() << "Done importing module"; -+} - - // Construct the collection of Python widgets. - PyCustomWidgets::PyCustomWidgets(QObject *parent) : QObject(parent), -@@ -127,6 +234,17 @@ PyCustomWidgets::PyCustomWidgets(QObject *parent) : QObject(parent), - return; - - Py_Initialize(); -+ -+ // Setup the excepthook dialog with the GIL held. -+#if defined(WITH_THREAD) -+ PyGILState_STATE gil_state = PyGILState_Ensure(); -+#endif -+ -+ setupExceptHookDialog(); -+ -+#if defined(WITH_THREAD) -+ PyGILState_Release(gil_state); -+#endif - } - - // Import the plugins with the GIL held. --- -2.13.0.windows.1 - diff --git a/pyproject.toml b/pyproject.toml index 512272339..1e8f10d36 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,4 +1,7 @@ [build-system] -requires = ["setuptools"] -backend-path = ["src/pep517", "."] -build-backend = "local_backend" +requires = [ + "setuptools ~= 50.3", + "versioneer-518 == 0.18", + "wheel ~= 0.35", +] +build-backend = "setuptools.build_meta" diff --git a/pyqt5.patch b/pyqt5.patch deleted file mode 100644 index c5ff473f2..000000000 --- a/pyqt5.patch +++ /dev/null @@ -1,120 +0,0 @@ -diff --git a/qmlscene/pluginloader.cpp b/qmlscene/pluginloader.cpp -index 635d31e..21b082a 100644 ---- a/qmlscene/pluginloader.cpp -+++ b/qmlscene/pluginloader.cpp -@@ -21,6 +21,7 @@ - */ - - -+#include - #include - - #include -@@ -218,6 +219,7 @@ void PyQt5QmlPlugin::registerTypes(const char *uri) - return; - - #ifdef WITH_THREAD -+ std::cerr << "pluginloader.cpp debug: PyQt5QmlPlugin::registerTypes(): PyGILState_Ensure()\n"; - PyGILState_STATE gil = PyGILState_Ensure(); - #endif - -@@ -225,6 +227,7 @@ void PyQt5QmlPlugin::registerTypes(const char *uri) - PyErr_Print(); - - #ifdef WITH_THREAD -+ std::cerr << "pluginloader.cpp debug: PyQt5QmlPlugin::registerTypes(): PyGILState_Release()\n"; - PyGILState_Release(gil); - #endif - } -@@ -234,9 +237,15 @@ void PyQt5QmlPlugin::registerTypes(const char *uri) - bool PyQt5QmlPlugin::callRegisterTypes(const QString &py_plugin, - const char *uri) - { -+ std::cerr << "pluginloader.cpp debug: PyQt5QmlPlugin::callRegisterTypes(): py_plugin.toLatin1().constData() - " << py_plugin.toLatin1().constData() << "\n"; -+ std::cerr << "pluginloader.cpp debug: PyQt5QmlPlugin::callRegisterTypes(): (void *) uri - " << (void *) uri << "\n"; -+ if (uri) { -+ std::cerr << "pluginloader.cpp debug: PyQt5QmlPlugin::callRegisterTypes(): uri - " << uri << "\n"; -+ } - // Import the plugin. - PyObject *plugin_mod = PyImport_ImportModule(py_plugin.toLatin1().data()); - -+ std::cerr << "pluginloader.cpp debug: PyQt5QmlPlugin::callRegisterTypes(): plugin_mod - " << plugin_mod << "\n"; - if (!plugin_mod) - return false; - -@@ -244,6 +253,7 @@ bool PyQt5QmlPlugin::callRegisterTypes(const QString &py_plugin, - // allow it to fiddle with the context. - PyObject *extension_plugin = getModuleAttr("PyQt5.QtQml", - "QQmlExtensionPlugin"); -+ std::cerr << "pluginloader.cpp debug: PyQt5QmlPlugin::callRegisterTypes(): extension_plugin - " << extension_plugin << "\n"; - - if (!extension_plugin) - { -@@ -268,9 +278,22 @@ bool PyQt5QmlPlugin::callRegisterTypes(const QString &py_plugin, - - if (!plugin_type) - { -+ const char * py_plugin_char_pointer = py_plugin.toLatin1().constData(); -+ std::cerr << "pluginloader.cpp debug: PyQt5QmlPlugin::callRegisterTypes(): (void *) py_plugin_char_pointer - " << (void *) py_plugin_char_pointer << "\n"; -+ std::cerr << "pluginloader.cpp debug: PyQt5QmlPlugin::callRegisterTypes(): py_plugin_char_pointer bytes -"; -+ int length = 0; -+ for (int i = 0; i < 100; i++) { -+ int b = py_plugin_char_pointer[i]; -+ std::cerr << " " << b; -+ if (b == 0) { -+ length = i; -+ break; -+ } -+ } -+ std::cerr << "pluginloader.cpp debug: PyQt5QmlPlugin::callRegisterTypes(): py_plugin_char_pointer 0 byte at index - " << length; - PyErr_Format(PyExc_AttributeError, - "%s does not contain an implementation of QQmlExtensionPlugin", -- py_plugin.toLatin1().constData()); -+ py_plugin_char_pointer); - - Py_DECREF(plugin_mod); - return false; -@@ -278,6 +301,7 @@ bool PyQt5QmlPlugin::callRegisterTypes(const QString &py_plugin, - - // Create the plugin instance. - PyObject *plugin_obj = PyObject_CallObject(plugin_type, NULL); -+ std::cerr << "pluginloader.cpp debug: PyQt5QmlPlugin::callRegisterTypes(): plugin_obj - " << plugin_obj << "\n"; - - Py_DECREF(plugin_mod); - -@@ -285,8 +309,10 @@ bool PyQt5QmlPlugin::callRegisterTypes(const QString &py_plugin, - return false; - - // Call registerTypes(). -+ std::cerr << "pluginloader.cpp debug: PyQt5QmlPlugin::callRegisterTypes(): about to call some registerTypes()\n"; - PyObject *res_obj = PyObject_CallMethod(plugin_obj, - const_cast("registerTypes"), const_cast("s"), uri); -+ std::cerr << "pluginloader.cpp debug: PyQt5QmlPlugin::callRegisterTypes(): just called some registerTypes()\n"; - - if (res_obj != Py_None) - { -@@ -295,6 +321,7 @@ bool PyQt5QmlPlugin::callRegisterTypes(const QString &py_plugin, - if (res_obj) - { - #if PY_MAJOR_VERSION >= 3 -+ std::cerr << "pluginloader.cpp debug: PyQt5QmlPlugin::callRegisterTypes(): res_obj - " << res_obj << "\n"; - PyErr_Format(PyExc_TypeError, - "unexpected result from registerTypes(): %S", res_obj); - #else -@@ -412,6 +439,16 @@ PyObject *PyQt5QmlPlugin::getModuleAttr(const char *module, const char *attr) - void PyQt5QmlPlugin::getSipAPI() - { - #if defined(SIP_USE_PYCAPSULE) -+ PyObject *mod = PyImport_ImportModule("PyQt5.sip"); -+ if (!mod) -+ { -+ PyErr_Print(); -+ return; -+ } -+ else -+ { -+ Py_DECREF(mod); -+ } - sip = (const sipAPIDef *)PyCapsule_Import("PyQt5.sip._C_API", 0); - #else - PyObject *c_api = getModuleAttr("PyQt5.sip", "_C_API"); diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 000000000..6fb995eb9 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,6 @@ +[versioneer] +VCS = git +style = pep440-post +versionfile_source = src/pyqt5_tools/_version.py +versionfile_build = pyqt5_tools/_version.py +tag_prefix = v diff --git a/setup.py b/setup.py index 528a0bbc9..c33142f82 100644 --- a/setup.py +++ b/setup.py @@ -1,70 +1,55 @@ import os -import pathlib -import sys -here = pathlib.Path(__file__).parent +import setuptools +import versioneer -sys.path.insert(0, here) -# TODO: yuck, put the build command in a separate project and -# build-requires it? -import build_new -sys.path.pop(0) -import setuptools -import vcversioner +class InvalidVersionError(Exception): + pass -version = vcversioner.find_version( - version_module_paths=['_version.py'], - vcs_args=['git', '--git-dir', '%(root)s/.git', 'describe', - '--tags', '--long', '--abbrev=999'], - ) -def pad_version(v): +def pad_version(v, segment_count=3): split = v.split('.') - return '.'.join(split + ['0'] * (3 - len(split))) + + if len(split) > segment_count: + raise InvalidVersionError('{} has more than three segments'.format(v)) + + return '.'.join(split + ['0'] * (segment_count - len(split))) + # TODO: really doesn't seem quite proper here and probably should come # in some other way? -os.environ.setdefault('PYQT_VERSION', '5.14.1') +pyqt_version = pad_version(os.environ.setdefault('PYQT_VERSION', '5.15.1')) +qt_version = pad_version(os.environ.setdefault('QT_VERSION', '5.15.1')) -version = '.'.join(( - pad_version(os.environ['PYQT_VERSION']), - version.version, -)) -# sys.stderr.write('another stderr test from {}\n'.format(__file__)) +pyqt5_tools_wrapper_version = versioneer.get_versions()['version'] +pyqt5_tools_version = '{}.{}'.format(pyqt_version, pyqt5_tools_wrapper_version) -with open('README.rst') as f: - readme = f.read() - -console_scripts = [ - 'pyqt5toolsinstalluic = pyqt5_tools.entrypoints:pyqt5toolsinstalluic', - 'pyqt5designer = pyqt5_tools.entrypoints:pyqt5designer', - 'pyqt5qmlscene = pyqt5_tools.entrypoints:pyqt5qmlscene', - 'pyqt5qmltestrunner = pyqt5_tools.entrypoints:pyqt5qmltestrunner', -] -# print('--- console_scripts') -# for console_script in console_scripts: -# print(' ' + repr(console_script)) +# such as: @ git+https://github.com/altendky/pyqt5-tools@just_plugins +# or empty when using a regular index +pyqt_plugins_url = ' @ git+https://github.com/altendky/pyqt5-tools@just_plugins' -# # TODO: do i really need this? seems like it could be specified to be -# # specific to whatever is running it without saying what that is -# # or that it would default to that -# build_new.write_setup_cfg(here) +if pyqt_plugins_url == '': + # When using ~=, don't pad because that affects allowed versions. The last + # segment is the one that is allowed to increase. + pyqt_plugins_wrapper_version = '0.1.0' + pyqt_plugins_version_specifier = '~={}.{}'.format( + pyqt_version, + pyqt_plugins_wrapper_version, + ) +else: + pyqt_plugins_version_specifier = '' -class Dist(setuptools.Distribution): - def has_ext_modules(self): - # Event if we don't have extension modules (e.g. on PyPy) we want to - # claim that we do so that wheels get properly tagged as Python - # specific. (thanks dstufft!) - return True +with open('README.rst') as f: + readme = f.read() setuptools.setup( - name="pyqt5-tools", - description="Tools to supplement the official PyQt5 wheels", + name="pyqt5_tools", + description="PyQt Designer and QML plugins", long_description=readme, long_description_content_type='text/x-rst', url='https://github.com/altendky/pyqt5-tools', @@ -75,9 +60,11 @@ def has_ext_modules(self): # complete classifier list: https://pypi.org/pypi?%3Aaction=list_classifiers 'Development Status :: 4 - Beta', 'Environment :: Win32 (MS Windows)', + 'Environment :: X11 Applications :: Qt', 'Intended Audience :: Developers', "License :: OSI Approved :: GNU General Public License v3 (GPLv3)", 'Operating System :: Microsoft :: Windows', + 'Operating System :: POSIX :: Linux', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', @@ -87,24 +74,26 @@ def has_ext_modules(self): 'Topic :: Software Development', 'Topic :: Utilities', ], - cmdclass={'build_py': build_new.BuildPy}, - distclass=Dist, packages=setuptools.find_packages('src'), package_dir={'': 'src'}, - version=version, + version=pyqt5_tools_version, include_package_data=True, python_requires=">=3.5", install_requires=[ 'click', + 'pyqt5=={}'.format(pyqt_version), + 'pyqt5-plugins{}{}'.format( + pyqt_plugins_version_specifier, + pyqt_plugins_url, + ), 'python-dotenv', - 'pyqt5=={}'.format(os.environ['PYQT_VERSION']), ], entry_points={ - 'console_scripts': console_scripts, - }, -# data_files=buildinfo.data_files() -# scripts=[ -# {scripts} -# 'pyqt5-tools/designer.exe' -# ] + 'console_scripts': [ + 'pyqttoolsinstalluic = pyqt5_tools.entrypoints:pyqttoolsinstalluic', + 'pyqtdesigner = pyqt5_tools.entrypoints:pyqtdesigner', + 'pyqtqmlscene = pyqt5_tools.entrypoints:pyqtqmlscene', + 'pyqtqmltestrunner = pyqt5_tools.entrypoints:pyqtqmltestrunner', + ] + } ) diff --git a/src/pep517/local_backend.py b/src/pep517/local_backend.py deleted file mode 100644 index 705da4410..000000000 --- a/src/pep517/local_backend.py +++ /dev/null @@ -1,72 +0,0 @@ -import os - -import setuptools.build_meta - - -build_wheel = setuptools.build_meta.build_wheel -build_sdist = setuptools.build_meta.build_sdist -prepare_metadata_for_build_wheel = ( - setuptools.build_meta.prepare_metadata_for_build_wheel -) -get_requires_for_build_sdist = ( - setuptools.build_meta.get_requires_for_build_sdist -) - - -requirements = { - 'attrs': '', - 'aqtinstall': '', - # != 0.10.0 for https://github.com/miurahr/py7zr/issues/252 - 'py7zr': '!= 0.10.0', - 'importlib-metadata': '', - 'hyperlink': '', - 'macholib': '', - 'pylddwrap': '', - 'PyQt-builder': '', - 'requests': '', - 'setuptools': '', - 'sip': '', - 'vcversioner': '', - 'wheel': '', -} - - -overrides = dict(sorted({ - (5, 14): { - 'PyQt-builder': '==1.3.1', - 'sip': '==5.2.0', - }, -}.items())) - - -def pick_overrides(version, overrides): - dicts = [] - - for v, d in overrides.items(): - if v == version[:len(v)]: - dicts.append(d) - - return dicts - - -def to_list(*dicts): - merged = {} - for d in dicts: - merged.update(d) - - return [ - package + more - for package, more in merged.items() - ] - - -def get_requires_for_build_wheel(config_settings=None): - # TODO: get this in via config_settings maybe - version = tuple(int(v) for v in os.environ['PYQT_VERSION'].split('.')) - - dicts = [ - requirements, - *pick_overrides(version=version, overrides=overrides), - ] - - return to_list(*dicts) diff --git a/src/pyqt5_tools/__init__.py b/src/pyqt5_tools/__init__.py index e69de29bb..e44e9d156 100644 --- a/src/pyqt5_tools/__init__.py +++ b/src/pyqt5_tools/__init__.py @@ -0,0 +1,3 @@ +from ._version import get_versions +__version__ = get_versions()['version'] +del get_versions diff --git a/src/pyqt5_tools/_version.py b/src/pyqt5_tools/_version.py new file mode 100644 index 000000000..f817ffd72 --- /dev/null +++ b/src/pyqt5_tools/_version.py @@ -0,0 +1,520 @@ + +# This file helps to compute a version number in source trees obtained from +# git-archive tarball (such as those provided by githubs download-from-tag +# feature). Distribution tarballs (built by setup.py sdist) and build +# directories (produced by setup.py build) will contain a much shorter file +# that just contains the computed version number. + +# This file is released into the public domain. Generated by +# versioneer-0.18 (https://github.com/warner/python-versioneer) + +"""Git implementation of _version.py.""" + +import errno +import os +import re +import subprocess +import sys + + +def get_keywords(): + """Get the keywords needed to look up the version information.""" + # these strings will be replaced by git during git-archive. + # setup.py/versioneer.py will grep for the variable names, so they must + # each be defined on a line of their own. _version.py will just call + # get_keywords(). + git_refnames = "$Format:%d$" + git_full = "$Format:%H$" + git_date = "$Format:%ci$" + keywords = {"refnames": git_refnames, "full": git_full, "date": git_date} + return keywords + + +class VersioneerConfig: + """Container for Versioneer configuration parameters.""" + + +def get_config(): + """Create, populate and return the VersioneerConfig() object.""" + # these strings are filled in when 'setup.py versioneer' creates + # _version.py + cfg = VersioneerConfig() + cfg.VCS = "git" + cfg.style = "pep440-post" + cfg.tag_prefix = "v" + cfg.parentdir_prefix = "None" + cfg.versionfile_source = "src/pyqt5_tools/_version.py" + cfg.verbose = False + return cfg + + +class NotThisMethod(Exception): + """Exception raised if a method is not valid for the current scenario.""" + + +LONG_VERSION_PY = {} +HANDLERS = {} + + +def register_vcs_handler(vcs, method): # decorator + """Decorator to mark a method as the handler for a particular VCS.""" + def decorate(f): + """Store f in HANDLERS[vcs][method].""" + if vcs not in HANDLERS: + HANDLERS[vcs] = {} + HANDLERS[vcs][method] = f + return f + return decorate + + +def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, + env=None): + """Call the given command(s).""" + assert isinstance(commands, list) + p = None + for c in commands: + try: + dispcmd = str([c] + args) + # remember shell=False, so use git.cmd on windows, not just git + p = subprocess.Popen([c] + args, cwd=cwd, env=env, + stdout=subprocess.PIPE, + stderr=(subprocess.PIPE if hide_stderr + else None)) + break + except EnvironmentError: + e = sys.exc_info()[1] + if e.errno == errno.ENOENT: + continue + if verbose: + print("unable to run %s" % dispcmd) + print(e) + return None, None + else: + if verbose: + print("unable to find command, tried %s" % (commands,)) + return None, None + stdout = p.communicate()[0].strip() + if sys.version_info[0] >= 3: + stdout = stdout.decode() + if p.returncode != 0: + if verbose: + print("unable to run %s (error)" % dispcmd) + print("stdout was %s" % stdout) + return None, p.returncode + return stdout, p.returncode + + +def versions_from_parentdir(parentdir_prefix, root, verbose): + """Try to determine the version from the parent directory name. + + Source tarballs conventionally unpack into a directory that includes both + the project name and a version string. We will also support searching up + two directory levels for an appropriately named parent directory + """ + rootdirs = [] + + for i in range(3): + dirname = os.path.basename(root) + if dirname.startswith(parentdir_prefix): + return {"version": dirname[len(parentdir_prefix):], + "full-revisionid": None, + "dirty": False, "error": None, "date": None} + else: + rootdirs.append(root) + root = os.path.dirname(root) # up a level + + if verbose: + print("Tried directories %s but none started with prefix %s" % + (str(rootdirs), parentdir_prefix)) + raise NotThisMethod("rootdir doesn't start with parentdir_prefix") + + +@register_vcs_handler("git", "get_keywords") +def git_get_keywords(versionfile_abs): + """Extract version information from the given file.""" + # the code embedded in _version.py can just fetch the value of these + # keywords. When used from setup.py, we don't want to import _version.py, + # so we do it with a regexp instead. This function is not used from + # _version.py. + keywords = {} + try: + f = open(versionfile_abs, "r") + for line in f.readlines(): + if line.strip().startswith("git_refnames ="): + mo = re.search(r'=\s*"(.*)"', line) + if mo: + keywords["refnames"] = mo.group(1) + if line.strip().startswith("git_full ="): + mo = re.search(r'=\s*"(.*)"', line) + if mo: + keywords["full"] = mo.group(1) + if line.strip().startswith("git_date ="): + mo = re.search(r'=\s*"(.*)"', line) + if mo: + keywords["date"] = mo.group(1) + f.close() + except EnvironmentError: + pass + return keywords + + +@register_vcs_handler("git", "keywords") +def git_versions_from_keywords(keywords, tag_prefix, verbose): + """Get version information from git keywords.""" + if not keywords: + raise NotThisMethod("no keywords at all, weird") + date = keywords.get("date") + if date is not None: + # git-2.2.0 added "%cI", which expands to an ISO-8601 -compliant + # datestamp. However we prefer "%ci" (which expands to an "ISO-8601 + # -like" string, which we must then edit to make compliant), because + # it's been around since git-1.5.3, and it's too difficult to + # discover which version we're using, or to work around using an + # older one. + date = date.strip().replace(" ", "T", 1).replace(" ", "", 1) + refnames = keywords["refnames"].strip() + if refnames.startswith("$Format"): + if verbose: + print("keywords are unexpanded, not using") + raise NotThisMethod("unexpanded keywords, not a git-archive tarball") + refs = set([r.strip() for r in refnames.strip("()").split(",")]) + # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of + # just "foo-1.0". If we see a "tag: " prefix, prefer those. + TAG = "tag: " + tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)]) + if not tags: + # Either we're using git < 1.8.3, or there really are no tags. We use + # a heuristic: assume all version tags have a digit. The old git %d + # expansion behaves like git log --decorate=short and strips out the + # refs/heads/ and refs/tags/ prefixes that would let us distinguish + # between branches and tags. By ignoring refnames without digits, we + # filter out many common branch names like "release" and + # "stabilization", as well as "HEAD" and "master". + tags = set([r for r in refs if re.search(r'\d', r)]) + if verbose: + print("discarding '%s', no digits" % ",".join(refs - tags)) + if verbose: + print("likely tags: %s" % ",".join(sorted(tags))) + for ref in sorted(tags): + # sorting will prefer e.g. "2.0" over "2.0rc1" + if ref.startswith(tag_prefix): + r = ref[len(tag_prefix):] + if verbose: + print("picking %s" % r) + return {"version": r, + "full-revisionid": keywords["full"].strip(), + "dirty": False, "error": None, + "date": date} + # no suitable tags, so version is "0+unknown", but full hex is still there + if verbose: + print("no suitable tags, using unknown + full revision id") + return {"version": "0+unknown", + "full-revisionid": keywords["full"].strip(), + "dirty": False, "error": "no suitable tags", "date": None} + + +@register_vcs_handler("git", "pieces_from_vcs") +def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): + """Get version from 'git describe' in the root of the source tree. + + This only gets called if the git-archive 'subst' keywords were *not* + expanded, and _version.py hasn't already been rewritten with a short + version string, meaning we're inside a checked out source tree. + """ + GITS = ["git"] + if sys.platform == "win32": + GITS = ["git.cmd", "git.exe"] + + out, rc = run_command(GITS, ["rev-parse", "--git-dir"], cwd=root, + hide_stderr=True) + if rc != 0: + if verbose: + print("Directory %s not under git control" % root) + raise NotThisMethod("'git rev-parse --git-dir' returned error") + + # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty] + # if there isn't one, this yields HEX[-dirty] (no NUM) + describe_out, rc = run_command(GITS, ["describe", "--tags", "--dirty", + "--always", "--long", + "--match", "%s*" % tag_prefix], + cwd=root) + # --long was added in git-1.5.5 + if describe_out is None: + raise NotThisMethod("'git describe' failed") + describe_out = describe_out.strip() + full_out, rc = run_command(GITS, ["rev-parse", "HEAD"], cwd=root) + if full_out is None: + raise NotThisMethod("'git rev-parse' failed") + full_out = full_out.strip() + + pieces = {} + pieces["long"] = full_out + pieces["short"] = full_out[:7] # maybe improved later + pieces["error"] = None + + # parse describe_out. It will be like TAG-NUM-gHEX[-dirty] or HEX[-dirty] + # TAG might have hyphens. + git_describe = describe_out + + # look for -dirty suffix + dirty = git_describe.endswith("-dirty") + pieces["dirty"] = dirty + if dirty: + git_describe = git_describe[:git_describe.rindex("-dirty")] + + # now we have TAG-NUM-gHEX or HEX + + if "-" in git_describe: + # TAG-NUM-gHEX + mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe) + if not mo: + # unparseable. Maybe git-describe is misbehaving? + pieces["error"] = ("unable to parse git-describe output: '%s'" + % describe_out) + return pieces + + # tag + full_tag = mo.group(1) + if not full_tag.startswith(tag_prefix): + if verbose: + fmt = "tag '%s' doesn't start with prefix '%s'" + print(fmt % (full_tag, tag_prefix)) + pieces["error"] = ("tag '%s' doesn't start with prefix '%s'" + % (full_tag, tag_prefix)) + return pieces + pieces["closest-tag"] = full_tag[len(tag_prefix):] + + # distance: number of commits since tag + pieces["distance"] = int(mo.group(2)) + + # commit: short hex revision ID + pieces["short"] = mo.group(3) + + else: + # HEX: no tags + pieces["closest-tag"] = None + count_out, rc = run_command(GITS, ["rev-list", "HEAD", "--count"], + cwd=root) + pieces["distance"] = int(count_out) # total number of commits + + # commit date: see ISO-8601 comment in git_versions_from_keywords() + date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"], + cwd=root)[0].strip() + pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1) + + return pieces + + +def plus_or_dot(pieces): + """Return a + if we don't already have one, else return a .""" + if "+" in pieces.get("closest-tag", ""): + return "." + return "+" + + +def render_pep440(pieces): + """Build up version string, with post-release "local version identifier". + + Our goal: TAG[+DISTANCE.gHEX[.dirty]] . Note that if you + get a tagged build and then dirty it, you'll get TAG+0.gHEX.dirty + + Exceptions: + 1: no tags. git_describe was just HEX. 0+untagged.DISTANCE.gHEX[.dirty] + """ + if pieces["closest-tag"]: + rendered = pieces["closest-tag"] + if pieces["distance"] or pieces["dirty"]: + rendered += plus_or_dot(pieces) + rendered += "%d.g%s" % (pieces["distance"], pieces["short"]) + if pieces["dirty"]: + rendered += ".dirty" + else: + # exception #1 + rendered = "0+untagged.%d.g%s" % (pieces["distance"], + pieces["short"]) + if pieces["dirty"]: + rendered += ".dirty" + return rendered + + +def render_pep440_pre(pieces): + """TAG[.post.devDISTANCE] -- No -dirty. + + Exceptions: + 1: no tags. 0.post.devDISTANCE + """ + if pieces["closest-tag"]: + rendered = pieces["closest-tag"] + if pieces["distance"]: + rendered += ".post.dev%d" % pieces["distance"] + else: + # exception #1 + rendered = "0.post.dev%d" % pieces["distance"] + return rendered + + +def render_pep440_post(pieces): + """TAG[.postDISTANCE[.dev0]+gHEX] . + + The ".dev0" means dirty. Note that .dev0 sorts backwards + (a dirty tree will appear "older" than the corresponding clean one), + but you shouldn't be releasing software with -dirty anyways. + + Exceptions: + 1: no tags. 0.postDISTANCE[.dev0] + """ + if pieces["closest-tag"]: + rendered = pieces["closest-tag"] + if pieces["distance"] or pieces["dirty"]: + rendered += ".post%d" % pieces["distance"] + if pieces["dirty"]: + rendered += ".dev0" + rendered += plus_or_dot(pieces) + rendered += "g%s" % pieces["short"] + else: + # exception #1 + rendered = "0.post%d" % pieces["distance"] + if pieces["dirty"]: + rendered += ".dev0" + rendered += "+g%s" % pieces["short"] + return rendered + + +def render_pep440_old(pieces): + """TAG[.postDISTANCE[.dev0]] . + + The ".dev0" means dirty. + + Eexceptions: + 1: no tags. 0.postDISTANCE[.dev0] + """ + if pieces["closest-tag"]: + rendered = pieces["closest-tag"] + if pieces["distance"] or pieces["dirty"]: + rendered += ".post%d" % pieces["distance"] + if pieces["dirty"]: + rendered += ".dev0" + else: + # exception #1 + rendered = "0.post%d" % pieces["distance"] + if pieces["dirty"]: + rendered += ".dev0" + return rendered + + +def render_git_describe(pieces): + """TAG[-DISTANCE-gHEX][-dirty]. + + Like 'git describe --tags --dirty --always'. + + Exceptions: + 1: no tags. HEX[-dirty] (note: no 'g' prefix) + """ + if pieces["closest-tag"]: + rendered = pieces["closest-tag"] + if pieces["distance"]: + rendered += "-%d-g%s" % (pieces["distance"], pieces["short"]) + else: + # exception #1 + rendered = pieces["short"] + if pieces["dirty"]: + rendered += "-dirty" + return rendered + + +def render_git_describe_long(pieces): + """TAG-DISTANCE-gHEX[-dirty]. + + Like 'git describe --tags --dirty --always -long'. + The distance/hash is unconditional. + + Exceptions: + 1: no tags. HEX[-dirty] (note: no 'g' prefix) + """ + if pieces["closest-tag"]: + rendered = pieces["closest-tag"] + rendered += "-%d-g%s" % (pieces["distance"], pieces["short"]) + else: + # exception #1 + rendered = pieces["short"] + if pieces["dirty"]: + rendered += "-dirty" + return rendered + + +def render(pieces, style): + """Render the given version pieces into the requested style.""" + if pieces["error"]: + return {"version": "unknown", + "full-revisionid": pieces.get("long"), + "dirty": None, + "error": pieces["error"], + "date": None} + + if not style or style == "default": + style = "pep440" # the default + + if style == "pep440": + rendered = render_pep440(pieces) + elif style == "pep440-pre": + rendered = render_pep440_pre(pieces) + elif style == "pep440-post": + rendered = render_pep440_post(pieces) + elif style == "pep440-old": + rendered = render_pep440_old(pieces) + elif style == "git-describe": + rendered = render_git_describe(pieces) + elif style == "git-describe-long": + rendered = render_git_describe_long(pieces) + else: + raise ValueError("unknown style '%s'" % style) + + return {"version": rendered, "full-revisionid": pieces["long"], + "dirty": pieces["dirty"], "error": None, + "date": pieces.get("date")} + + +def get_versions(): + """Get version information or return default if unable to do so.""" + # I am in _version.py, which lives at ROOT/VERSIONFILE_SOURCE. If we have + # __file__, we can work backwards from there to the root. Some + # py2exe/bbfreeze/non-CPython implementations don't do __file__, in which + # case we can only use expanded keywords. + + cfg = get_config() + verbose = cfg.verbose + + try: + return git_versions_from_keywords(get_keywords(), cfg.tag_prefix, + verbose) + except NotThisMethod: + pass + + try: + root = os.path.realpath(__file__) + # versionfile_source is the relative path from the top of the source + # tree (where the .git directory might live) to this file. Invert + # this to find the root from __file__. + for i in cfg.versionfile_source.split('/'): + root = os.path.dirname(root) + except NameError: + return {"version": "0+unknown", "full-revisionid": None, + "dirty": None, + "error": "unable to find root of source tree", + "date": None} + + try: + pieces = git_pieces_from_vcs(cfg.tag_prefix, root, verbose) + return render(pieces, cfg.style) + except NotThisMethod: + pass + + try: + if cfg.parentdir_prefix: + return versions_from_parentdir(cfg.parentdir_prefix, root, verbose) + except NotThisMethod: + pass + + return {"version": "0+unknown", "full-revisionid": None, + "dirty": None, + "error": "unable to compute version", "date": None} diff --git a/src/pyqt5_tools/entrypoints.py b/src/pyqt5_tools/entrypoints.py index ca0bf39a3..bf6cfccbf 100644 --- a/src/pyqt5_tools/entrypoints.py +++ b/src/pyqt5_tools/entrypoints.py @@ -7,25 +7,24 @@ import click import dotenv +import qt5_applications import PyQt5 -import pyqt5_tools.badplugin -import pyqt5_tools.examplebuttonplugin -import pyqt5_tools.examples -import pyqt5_tools.examples.exampleqmlitem -import pyqt5_tools.tests.testbutton - - -fspath = getattr(os, 'fspath', str) +import pyqt5_plugins.utilities +import pyqt5_plugins.badplugin +import pyqt5_plugins.examplebuttonplugin +import pyqt5_plugins.examples +import pyqt5_plugins.examples.exampleqmlitem +import pyqt5_plugins.tests.testbutton here = pathlib.Path(__file__).parent bin = here/'Qt'/'bin' example_path = str( - pathlib.Path(pyqt5_tools.examplebuttonplugin.__file__).parent, + pathlib.Path(pyqt5_plugins.examplebuttonplugin.__file__).parent, ) bad_path = str( - pathlib.Path(pyqt5_tools.badplugin.__file__).parent, + pathlib.Path(pyqt5_plugins.badplugin.__file__).parent, ) pyqt5_root = pathlib.Path(PyQt5.__file__).parent @@ -37,7 +36,20 @@ }[sys.platform] -def pyqt5toolsinstalluic(): +def load_dotenv(): + env_path = dotenv.find_dotenv(usecwd=True) + + if len(env_path) == 0: + return + + os.environ['DOT_ENV_DIRECTORY'] = pyqt5_plugins.utilities.fspath( + pathlib.Path(env_path).parent, + ) + os.environ['SITE_PACKAGES'] = sysconfig.get_path('platlib') + dotenv.load_dotenv(dotenv_path=env_path, interpolate=True, override=True) + + +def pyqttoolsinstalluic(): destination = bin/'bin' destination.mkdir(parents=True, exist_ok=True) there = pathlib.Path(sys.executable).parent @@ -48,76 +60,6 @@ def pyqt5toolsinstalluic(): ) -def load_dotenv(): - env_path = dotenv.find_dotenv(usecwd=True) - if len(env_path) > 0: - os.environ['DOT_ENV_DIRECTORY'] = str(pathlib.Path(env_path).parent) - os.environ['SITE_PACKAGES'] = sysconfig.get_path('platlib') - dotenv.load_dotenv(dotenv_path=env_path, override=True) - - -def create_env(reference): - # TODO: uck, mutating - load_dotenv() - - env = dict(reference) - - env.update(add_to_env_var_path_list( - env=env, - name='QT_PLUGIN_PATH', - before=[], - after=[fspath(here / 'Qt' / 'plugins')], - )) - # TODO: maybe also - # PyQt5.QtCore.QLibraryInfo.location( - # PyQt5.QtCore.QLibraryInfo.PluginsPath, - # ) - - if sys.platform == 'linux': - env.update(add_to_env_var_path_list( - env=env, - name='LD_LIBRARY_PATH', - before=[''], - after=[sysconfig.get_config_var('LIBDIR')], - )) - - return env - - -def add_to_env_var_path_list(env, name, before, after): - return { - name: os.pathsep.join(( - *before, - env.get(name, ''), - *after - )) - } - - -def mutate_env_for_paths(env): - env.update(add_to_env_var_path_list( - env=env, - name='PYTHONPATH', - before=sys.path, - after=[''], - )) - env.update(add_to_env_var_path_list( - env=env, - name='PATH', - before=sys.path, - after=[''], - )) - - -def print_environment_variables(env, *variables): - for name in variables: - value = env.get(name) - if value is None: - print('{} is not set'.format(name)) - else: - print('{}: {}'.format(name, value)) - - qt_debug_plugins_option = click.option( '--qt-debug-plugins/--no-qt-debug-plugins', help='Set QT_DEBUG_PLUGINS=1', @@ -157,7 +99,7 @@ def print_environment_variables(env, *variables): is_flag=True, ) @qt_debug_plugins_option -def pyqt5designer( +def pyqtdesigner( ctx, widget_paths, designer_help, @@ -165,7 +107,9 @@ def pyqt5designer( test_exception_dialog, qt_debug_plugins ): - env = create_env(os.environ) + # here for now at least since it still mutates + load_dotenv() + env = pyqt5_plugins.utilities.create_env(reference=os.environ) extras = [] widget_paths = list(widget_paths) @@ -179,35 +123,23 @@ def pyqt5designer( if test_exception_dialog: widget_paths.append(bad_path) - vars_to_print = [ - 'PYQTDESIGNERPATH', - 'PYTHONPATH', - 'PATH', - 'QT_DEBUG_PLUGINS', - 'QT_PLUGIN_PATH', - pyqt5_tools.tests.testbutton.test_path_env_var, - ] - - if sys.platform == 'linux': - vars_to_print.append('LD_LIBRARY_PATH') - vars_to_print.append('DISPLAY') - - env.update(add_to_env_var_path_list( + env.update(pyqt5_plugins.utilities.add_to_env_var_path_list( env=env, name='PYQTDESIGNERPATH', before=widget_paths, after=[''], )) - mutate_env_for_paths(env) - if qt_debug_plugins: env['QT_DEBUG_PLUGINS'] = '1' - print_environment_variables(env, *vars_to_print) + pyqt5_plugins.utilities.print_environment_variables( + env, + *pyqt5_plugins.utilities.diagnostic_variables_to_print, + ) command = [ - str(bin / maybe_extension('designer')), + pyqt5_plugins.utilities.fspath(qt5_applications.application_path('designer')), *extras, *ctx.args, ] @@ -225,15 +157,6 @@ def pyqt5designer( ) -def mutate_qml_path(env, paths): - env.update(add_to_env_var_path_list( - env=env, - name='QML2_IMPORT_PATH', - before=[*paths, fspath(pyqt5_root/'Qt'/'qml')], - after=[''], - )) - - @click.command( context_settings={ 'ignore_unknown_options': True, @@ -253,48 +176,39 @@ def mutate_qml_path(env, paths): help='Run the pyqt5-tools QML example', is_flag=True, ) -def pyqt5qmlscene( +def pyqtqmlscene( ctx, qml2_import_paths, qmlscene_help, qt_debug_plugins, run_qml_example, ): - env = create_env(os.environ) + # here for now at least since it still mutates + load_dotenv() + env = pyqt5_plugins.utilities.create_env(os.environ) extras = [] if qmlscene_help: extras.append('--help') if run_qml_example: - qml2_import_paths = qml2_import_paths + (fspath(here),) - extras.append(fspath( - pathlib.Path(pyqt5_tools.examples.__file__).parent/'qmlapp.qml' + qml2_import_paths = qml2_import_paths + (pyqt5_plugins.utilities.fspath(here),) + extras.append(pyqt5_plugins.utilities.fspath( + pathlib.Path(pyqt5_plugins.examples.__file__).parent / 'qmlapp.qml' )) - mutate_qml_path(env, paths=qml2_import_paths) - mutate_env_for_paths(env) + pyqt5_plugins.utilities.mutate_qml_path(env, paths=qml2_import_paths) if qt_debug_plugins: env['QT_DEBUG_PLUGINS'] = '1' - vars_to_print = [ - 'QML2_IMPORT_PATH', - 'PYTHONPATH', - 'PATH', - 'QT_DEBUG_PLUGINS', - 'QT_PLUGIN_PATH', - pyqt5_tools.examples.exampleqmlitem.test_path_env_var, - ] - - if sys.platform == 'linux': - vars_to_print.append('LD_LIBRARY_PATH') - vars_to_print.append('DISPLAY') - - print_environment_variables(env, *vars_to_print) + pyqt5_plugins.utilities.print_environment_variables( + env, + *pyqt5_plugins.utilities.diagnostic_variables_to_print, + ) command = [ - str(bin / maybe_extension('qmlscene')), + pyqt5_plugins.utilities.fspath(qt5_applications.application_path('qmlscene')), *extras, *ctx.args, ] @@ -321,64 +235,44 @@ def pyqt5qmlscene( help='Test the pyqt5-tools QML example', is_flag=True, ) -def pyqt5qmltestrunner( +def pyqtqmltestrunner( ctx, qml2_import_paths, qmltestrunner_help, qt_debug_plugins, test_qml_example, ): - env = create_env(os.environ) + # here for now at least since it still mutates + load_dotenv() + env = pyqt5_plugins.utilities.create_env(os.environ) extras = [] if qmltestrunner_help: extras.append('--help') if test_qml_example: - qml2_import_paths = qml2_import_paths + (fspath(here),) + qml2_import_paths = qml2_import_paths + (pyqt5_plugins.utilities.fspath(here),) extras.extend([ '-input', - fspath( - pathlib.Path(pyqt5_tools.examples.__file__).parent/'qmltest.qml' + pyqt5_plugins.utilities.fspath( + pathlib.Path(pyqt5_plugins.examples.__file__).parent / 'qmltest.qml' ), ]) - mutate_qml_path(env, paths=qml2_import_paths) - mutate_env_for_paths(env) + pyqt5_plugins.utilities.mutate_qml_path(env, paths=qml2_import_paths) if qt_debug_plugins: env['QT_DEBUG_PLUGINS'] = '1' - vars_to_print = [ - 'QML2_IMPORT_PATH', - 'PYTHONPATH', - 'PATH', - 'QT_DEBUG_PLUGINS', - 'QT_PLUGIN_PATH', - pyqt5_tools.examples.exampleqmlitem.test_path_env_var, - ] - - if sys.platform == 'linux': - vars_to_print.append('LD_LIBRARY_PATH') - vars_to_print.append('DISPLAY') - - print_environment_variables(env, *vars_to_print) + pyqt5_plugins.utilities.print_environment_variables( + env, + *pyqt5_plugins.utilities.diagnostic_variables_to_print, + ) command = [ - str(bin / maybe_extension('qmltestrunner')), + pyqt5_plugins.utilities.fspath(qt5_applications.application_path('qmltestrunner')), *extras, *ctx.args, ] return subprocess.call(command, env=env) - - -# def designer(): -# env = create_env(os.environ) -# return subprocess.call( -# [ -# str(here/'Qt'/'bin'/'designer.exe'), -# *sys.argv[1:], -# ], -# env=env, -# ) diff --git a/src/pyqt5_tools/examplebutton.py b/src/pyqt5_tools/examplebutton.py deleted file mode 100644 index 818f50809..000000000 --- a/src/pyqt5_tools/examplebutton.py +++ /dev/null @@ -1,8 +0,0 @@ -from PyQt5 import QtWidgets - - -class ExampleButton(QtWidgets.QPushButton): - def __init__(self, parent): - super().__init__(parent) - - self.setText('pyqt5-tools Example Button') diff --git a/src/pyqt5_tools/examplebuttonplugin.py b/src/pyqt5_tools/examplebuttonplugin.py deleted file mode 100644 index 0cc5abf67..000000000 --- a/src/pyqt5_tools/examplebuttonplugin.py +++ /dev/null @@ -1,45 +0,0 @@ -from PyQt5 import QtGui, QtDesigner - -import pyqt5_tools.examplebutton - - -class ExampleButtonPlugin(QtDesigner.QPyDesignerCustomWidgetPlugin): - # https://wiki.python.org/moin/PyQt/Using_Python_Custom_Widgets_in_Qt_Designer - - def __init__(self, parent=None): - super().__init__(parent=parent) - - self.initialized = False - - def initialize(self, core): - if self.initialized: - return - - self.initialized = True - - def isInitialized(self): - return self.initialized - - def createWidget(self, parent): - return pyqt5_tools.examplebutton.ExampleButton(parent) - - def name(self): - return pyqt5_tools.examplebutton.ExampleButton.__name__ - - def group(self): - return 'pyqt5-tools' - - def icon(self): - return QtGui.QIcon() - - def toolTip(self): - return 'pyqt5-tools Example Button Tool Tip' - - def whatsThis(self): - return 'pyqt5-tools Example Button What\'s this' - - def isContainer(self): - return False - - def includeFile(self): - return 'pyqt5_tools.examplebutton' diff --git a/src/pyqt5_tools/examples/exampleqmlitemplugin.py b/src/pyqt5_tools/examples/exampleqmlitemplugin.py index dc6badd92..b48f062f3 100644 --- a/src/pyqt5_tools/examples/exampleqmlitemplugin.py +++ b/src/pyqt5_tools/examples/exampleqmlitemplugin.py @@ -8,7 +8,7 @@ sys.stderr.write('exampleqmlitemplugin.py debug: : just imported QtQml\n') sys.stderr.flush() -import pyqt5_tools.examples.exampleqmlitem +import pyqt5_plugins.examples.exampleqmlitem sys.stderr.write('exampleqmlitemplugin.py debug: : just imported pyqt5_tools.examples.exampleqmlitem\n') sys.stderr.flush() @@ -19,7 +19,7 @@ def registerTypes(self, uri): sys.stderr.flush() try: QtQml.qmlRegisterType( - pyqt5_tools.examples.exampleqmlitem.ExampleQmlItem, + pyqt5_plugins.examples.exampleqmlitem.ExampleQmlItem, 'examples', 1, 0, diff --git a/src/pyqt5_tools/tests/test_entrypoints.py b/src/pyqt5_tools/tests/test_entrypoints.py index d7ebfe2ad..fe697c675 100644 --- a/src/pyqt5_tools/tests/test_entrypoints.py +++ b/src/pyqt5_tools/tests/test_entrypoints.py @@ -1,156 +1,119 @@ import os import pathlib import subprocess -import sys import pytest +import qt5_applications -import pyqt5_tools.entrypoints -import pyqt5_tools.tests.testbutton -import pyqt5_tools.tests.testbuttonplugin -import pyqt5_tools.examples.exampleqmlitem +import pyqt5_plugins.entrypoints +import pyqt5_plugins.examples.exampleqmlitem +import pyqt5_plugins.tests.testbutton +import pyqt5_plugins.tests.testbuttonplugin +import pyqt5_plugins.utilities fspath = getattr(os, 'fspath', str) -def test_designer_creates_test_widget(tmp_path): - env = dict(os.environ) +vars_to_print = [ + *pyqt5_plugins.utilities.diagnostic_variables_to_print, + pyqt5_plugins.examples.exampleqmlitem.test_path_env_var, + pyqt5_plugins.tests.testbutton.test_path_env_var, +] + + +@pytest.fixture(name='environment') +def environment_fixture(): + environment = pyqt5_plugins.utilities.create_env(os.environ) + pyqt5_plugins.utilities.mutate_qml_path(environment, paths=qml2_import_paths) + environment['QT_DEBUG_PLUGINS'] = '1' + + return environment + + +def test_designer_creates_test_widget(tmp_path, environment): file_path = tmp_path/'tigger' - env[pyqt5_tools.tests.testbutton.test_path_env_var] = fspath(file_path) + environment[pyqt5_plugins.tests.testbutton.test_path_env_var] = fspath(file_path) widget_plugin_path = pathlib.Path( - pyqt5_tools.tests.testbuttonplugin.__file__, + pyqt5_plugins.tests.testbuttonplugin.__file__, ).parent + environment.update(pyqt5_plugins.utilities.add_to_env_var_path_list( + env=environment, + name='PYQTDESIGNERPATH', + before=[fspath(widget_plugin_path)], + after=[''], + )) + + pyqt5_plugins.utilities.print_environment_variables(environment, *vars_to_print) + with pytest.raises(subprocess.TimeoutExpired): subprocess.run( - [ - fspath( - pathlib.Path(sys.executable).with_name('pyqt5designer'), - ), - '--widget-path', fspath(widget_plugin_path), - '--qt-debug-plugins', - ], + [fspath(qt5_applications.application_path('designer'))], check=True, - env=env, - timeout=90, + env=environment, + timeout=20, ) assert ( - file_path.read_bytes() - == pyqt5_tools.tests.testbutton.test_file_contents + file_path.read_bytes() + == pyqt5_plugins.tests.testbutton.test_file_contents ) -def test_qmlscene_paints_test_item(tmp_path): - env = dict(os.environ) +qml2_import_paths = (pyqt5_plugins.utilities.fspath(pyqt5_plugins.root),) + + +def test_qmlscene_paints_test_item(tmp_path, environment): file_path = tmp_path/'eeyore' - env[pyqt5_tools.examples.exampleqmlitem.test_path_env_var] = fspath(file_path) + environment[pyqt5_plugins.examples.exampleqmlitem.test_path_env_var] = fspath(file_path) + + qml_example_path = pyqt5_plugins.utilities.fspath( + pathlib.Path(pyqt5_plugins.examples.__file__).parent / 'qmlapp.qml' + ) + + pyqt5_plugins.utilities.print_environment_variables(environment, *vars_to_print) with pytest.raises(subprocess.TimeoutExpired): subprocess.run( [ - fspath( - pathlib.Path(sys.executable).with_name('pyqt5qmlscene'), - ), - '--run-qml-example', - '--qt-debug-plugins', + fspath(qt5_applications.application_path('qmlscene')), + fspath(qml_example_path), ], check=True, - env=env, - timeout=10, + env=environment, + timeout=20, ) assert ( - file_path.read_bytes() - == pyqt5_tools.examples.exampleqmlitem.test_file_contents + file_path.read_bytes() + == pyqt5_plugins.examples.exampleqmlitem.test_file_contents ) -def test_qmltestrunner_paints_test_item(tmp_path): - env = dict(os.environ) +def test_qmltestrunner_paints_test_item(tmp_path, environment): file_path = tmp_path/'piglet' - env[pyqt5_tools.examples.exampleqmlitem.test_path_env_var] = fspath(file_path) + environment[pyqt5_plugins.examples.exampleqmlitem.test_path_env_var] = fspath(file_path) + + qml_test_path = pyqt5_plugins.utilities.fspath( + pathlib.Path(pyqt5_plugins.examples.__file__).parent / 'qmltest.qml' + ) + + pyqt5_plugins.utilities.print_environment_variables(environment, *vars_to_print) subprocess.run( [ - fspath( - pathlib.Path(sys.executable).with_name('pyqt5qmltestrunner'), - ), - '--test-qml-example', - '--qt-debug-plugins', + fspath(qt5_applications.application_path('qmltestrunner')), + '-input', + qml_test_path, ], check=True, - env=env, - timeout=10, + env=environment, + timeout=20, ) assert ( - file_path.read_bytes() - == pyqt5_tools.examples.exampleqmlitem.test_file_contents + file_path.read_bytes() + == pyqt5_plugins.examples.exampleqmlitem.test_file_contents ) - - -# @pytest.mark.skipif(sys.platform != 'linux', reason='only linux has ldd') -# def test_debug_ldd_qmlscene(): -# qmlscene = pyqt5_tools.entrypoints.bin / 'qmlscene' -# -# subprocess.run(['ldd', qmlscene], check=True) -# -# -# def test_debug_pip_freeze(): -# subprocess.run( -# [ -# sys.executable, -# '-m', 'pip', -# 'freeze', -# ], -# check=True, -# ) -# -# -# def test_debug_pyqt5_sip_path(): -# subprocess.run( -# [ -# sys.executable, -# '-c', -# 'import PyQt5.sip; print(PyQt5.sip)', -# ], -# check=True, -# ) -# -# -# def test_debug_cwd(): -# print('cwd:', pathlib.Path.cwd()) -# -# -# def test_debug_directory_contents(): -# cwd = pathlib.Path.cwd() -# for path in cwd.iterdir(): -# print(' {} {}'.format( -# 'd' if path.is_dir() else 'f', -# path.relative_to(cwd), -# )) -# -# -# def test_debug_sys_path_contents(): -# files = set() -# directories = set() -# -# for string_path in sys.path: -# maybe_directory = pathlib.Path(string_path) -# if maybe_directory.is_dir(): -# directory = maybe_directory -# for path in directory.iterdir(): -# if path.is_dir(): -# directories.add(path) -# elif path.suffix == '.py' and path.is_file(): -# files.add(path) -# -# for paths in [files, directories]: -# for path in sorted(paths): -# print(' {} {}'.format( -# 'd' if path.is_dir() else 'f', -# path.resolve(), -# )) diff --git a/src/pyqt5_tools/tests/testbutton.py b/src/pyqt5_tools/tests/testbutton.py deleted file mode 100644 index 462fc668d..000000000 --- a/src/pyqt5_tools/tests/testbutton.py +++ /dev/null @@ -1,26 +0,0 @@ -import os -import pathlib - -from PyQt5 import QtWidgets - - -test_path_env_var = 'PYQT5TOOLS_TEST_PATH' -test_file_contents = b'heffalump' -write_for_test = test_path_env_var in os.environ - - -class TestButton(QtWidgets.QPushButton): - def __init__(self, parent): - global write_for_test - - super().__init__(parent) - - self.setText('pyqt5-tools Test Button') - - if write_for_test: - write_for_test = False - - path = pathlib.Path(os.environ[test_path_env_var]) - path.parent.mkdir(parents=True, exist_ok=True) - with path.open('ab') as f: - f.write(test_file_contents) diff --git a/src/pyqt5_tools/tests/testbuttonplugin.py b/src/pyqt5_tools/tests/testbuttonplugin.py deleted file mode 100644 index 06ff54f9b..000000000 --- a/src/pyqt5_tools/tests/testbuttonplugin.py +++ /dev/null @@ -1,45 +0,0 @@ -from PyQt5 import QtGui, QtDesigner - -import pyqt5_tools.tests.testbutton - - -class TestButtonPlugin(QtDesigner.QPyDesignerCustomWidgetPlugin): - # https://wiki.python.org/moin/PyQt/Using_Python_Custom_Widgets_in_Qt_Designer - - def __init__(self, parent=None): - super().__init__(parent=parent) - - self.initialized = False - - def initialize(self, core): - if self.initialized: - return - - self.initialized = True - - def isInitialized(self): - return self.initialized - - def createWidget(self, parent): - return pyqt5_tools.tests.testbutton.TestButton(parent) - - def name(self): - return pyqt5_tools.tests.testbutton.TestButton.__name__ - - def group(self): - return 'pyqt5-tools' - - def icon(self): - return QtGui.QIcon() - - def toolTip(self): - return 'pyqt5-tools Test Button Tool Tip' - - def whatsThis(self): - return 'pyqt5-tools Test Button What\'s this' - - def isContainer(self): - return False - - def includeFile(self): - return 'pyqt5_tools.tests.testbutton' diff --git a/tox.ini b/tox.ini index 99796bd92..ca506817d 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] minversion=3.1 -envlist = py{36,38} +envlist = py{35,36,37,38,39} [testenv] deps=