diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..1e2a4f69f --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +src/pyqtwrappers/_version.py export-subst diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1a930f4f0..c1120301a 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,7 +24,6 @@ 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 @@ -33,50 +32,43 @@ jobs: # 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,26 +121,11 @@ 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 + 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: Set up MSVC uses: ilammy/msvc-dev-cmd@v1 if: matrix.os.python_platform == 'win32' @@ -158,7 +135,7 @@ jobs: # native shell for nmake... keep commands here simple i guess run: | mkdir -p dist/ - pip wheel -vvv --no-deps --wheel-dir dist/ --no-clean . + python -m pep517.build --binary --out-dir dist/ . - name: Rename to manylinux2014 tag if: matrix.os.python_platform == 'linux' shell: python @@ -171,6 +148,132 @@ jobs: # this is cheap... retagged = wheel.parent / wheel.name.replace('linux', 'manylinux2014') wheel.rename(retagged) + - name: Archive individual wheel + uses: actions/upload-artifact@v1 + with: + name: ${{ matrix.os.name }} ${{ matrix.python.name }}-${{ matrix.bitness.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 }} + + steps: + - name: Checkout + uses: actions/checkout@v1 + - name: Download + uses: actions/download-artifact@v1 + with: + name: ${{ matrix.os.name }} ${{ matrix.python.name }}-${{ matrix.bitness.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 +285,31 @@ 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: 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 +323,8 @@ jobs: name: All runs-on: ubuntu-latest needs: - - ci + - build + - test - maybe_publish steps: - name: This diff --git a/MANIFEST.in b/MANIFEST.in index 4f099a1a4..513fddcdf 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1 +1,3 @@ -recursive-include src/pyqt5_tools * +recursive-include src/pyqtplugins * +include versioneer.py +include src/pyqtwrappers/_version.py 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..9662cd451 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,56 @@ +[metadata] +name = pyqtwrappers +description = PyQt Designer and QML plugins" +version = attr: local_backend.version +long_description = file: README.rst +long_description_content_type = text/x-rst +url = https://github.com/altendky/pyqt5-tools +author = Kyle Altendorf +author_email = sda@fstab.net +license = GPLv3 +classifiers = + # 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 + Programming Language :: Python :: 3.7 + Programming Language :: Python :: 3.8 + Programming Language :: Python :: 3.9 + Topic :: Software Development + Topic :: Utilities +install_requires = + click + pyqtplugins @ git+https://github.com/altendky/pyqt5-tools@just_plugins + qttools @ git+https://github.com/altendky/pyqt5-tools@just_applications + +[options] +include_package_data = True +python_requires = >=3.5 +package_dir= + =src +packages=find: + +[options.entry_points] +console_scripts = + pyqttoolsinstalluic = pyqtwrappers.entrypoints:pyqttoolsinstalluic + pyqtdesigner = pyqtwrappers.entrypoints:pyqtdesigner + pyqtqmlscene = pyqtwrappers.entrypoints:pyqtqmlscene + pyqtqmltestrunner = pyqtwrappers.entrypoints:pyqtqmltestrunner + +[options.packages.find] +where=src + +[versioneer] +VCS = git +style = pep440-post +versionfile_source = src/pyqtwrappers/_version.py +versionfile_build = pyqtwrappers/_version.py +tag_prefix = v + diff --git a/setup.py b/setup.py index 528a0bbc9..c19a5c85e 100644 --- a/setup.py +++ b/setup.py @@ -1,110 +1,31 @@ import os -import pathlib -import sys - -here = pathlib.Path(__file__).parent - -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 - -version = vcversioner.find_version( - version_module_paths=['_version.py'], - vcs_args=['git', '--git-dir', '%(root)s/.git', 'describe', - '--tags', '--long', '--abbrev=999'], - ) +import versioneer -def pad_version(v): - split = v.split('.') - return '.'.join(split + ['0'] * (3 - 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') +os.environ.setdefault('PYQT_VERSION', '5.15.1') +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__)) - -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', -] +def pad_version(v): + split = v.split('.') + return '.'.join(split + ['0'] * (3 - len(split))) -# print('--- console_scripts') -# for console_script in console_scripts: -# print(' ' + repr(console_script)) -# # 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) +def calculate_version(): + version = versioneer.get_versions()['version'] + version = '.'.join(( + pad_version(os.environ['PYQT_VERSION']), + version, + )) -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 + return version setuptools.setup( - name="pyqt5-tools", - description="Tools to supplement the official PyQt5 wheels", - long_description=readme, - long_description_content_type='text/x-rst', - url='https://github.com/altendky/pyqt5-tools', - author="Kyle Altendorf", - author_email='sda@fstab.net', - license='GPLv3', - classifiers=[ - # complete classifier list: https://pypi.org/pypi?%3Aaction=list_classifiers - 'Development Status :: 4 - Beta', - 'Environment :: Win32 (MS Windows)', - 'Intended Audience :: Developers', - "License :: OSI Approved :: GNU General Public License v3 (GPLv3)", - 'Operating System :: Microsoft :: Windows', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.5', - 'Programming Language :: Python :: 3.6', - 'Programming Language :: Python :: 3.7', - 'Programming Language :: Python :: 3.8', - 'Programming Language :: Python :: 3.9', - 'Topic :: Software Development', - 'Topic :: Utilities', - ], - cmdclass={'build_py': build_new.BuildPy}, - distclass=Dist, - packages=setuptools.find_packages('src'), - package_dir={'': 'src'}, - version=version, - include_package_data=True, - python_requires=">=3.5", - install_requires=[ - 'click', - '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' -# ] + version=calculate_version(), ) diff --git a/src/pep517/local_backend.py b/src/pep517/local_backend.py index 705da4410..c579de9d9 100644 --- a/src/pep517/local_backend.py +++ b/src/pep517/local_backend.py @@ -1,6 +1,7 @@ import os import setuptools.build_meta +import versioneer build_wheel = setuptools.build_meta.build_wheel @@ -11,62 +12,40 @@ get_requires_for_build_sdist = ( setuptools.build_meta.get_requires_for_build_sdist ) +get_requires_for_build_wheel = ( + setuptools.build_meta.get_requires_for_build_wheel +) -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) +# # TODO: really doesn't seem quite proper here and probably should come +# # in some other way? +# os.environ.setdefault('PYQT_VERSION', '5.15.1') +# os.environ.setdefault('QT_VERSION', '5.15.1') +# +# +# def pad_version(v): +# split = v.split('.') +# return '.'.join(split + ['0'] * (3 - len(split))) +# +# +# def calculate_version(): +# version = versioneer.get_versions()['version'] +# +# version = '.'.join(( +# pad_version(os.environ['PYQT_VERSION']), +# version, +# )) +# +# return version + + +# version = calculate_version() +# pyqt_version = os.environ['PYQT_VERSION'] +# qt_version = os.environ['QT_VERSION'] +# +# install_requires = [ +# 'click', +# 'pyqt5=={}'.format(os.environ['PYQT_VERSION']), +# 'pyqtplugins @ git+https://github.com/altendky/pyqt5-tools@just_plugins', +# 'qttools @ git+https://github.com/altendky/pyqt5-tools@just_applications', +# ], diff --git a/src/pyqt5_tools/entrypoints.py b/src/pyqt5_tools/entrypoints.py deleted file mode 100644 index ca0bf39a3..000000000 --- a/src/pyqt5_tools/entrypoints.py +++ /dev/null @@ -1,384 +0,0 @@ -import os -import pathlib -import shutil -import subprocess -import sys -import sysconfig - -import click -import dotenv - -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) - - -here = pathlib.Path(__file__).parent -bin = here/'Qt'/'bin' -example_path = str( - pathlib.Path(pyqt5_tools.examplebuttonplugin.__file__).parent, -) -bad_path = str( - pathlib.Path(pyqt5_tools.badplugin.__file__).parent, -) - -pyqt5_root = pathlib.Path(PyQt5.__file__).parent - -maybe_extension = { - 'linux': lambda name: name, - 'win32': lambda name: '{}.exe'.format(name), - 'darwin': lambda name: name, -}[sys.platform] - - -def pyqt5toolsinstalluic(): - destination = bin/'bin' - destination.mkdir(parents=True, exist_ok=True) - there = pathlib.Path(sys.executable).parent - - shutil.copy( - src=str(there / maybe_extension('pyuic5')), - dst=str(destination/maybe_extension('uic')), - ) - - -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', -) - - -@click.command( - context_settings={ - 'ignore_unknown_options': True, - 'allow_extra_args': True, - }, -) -@click.pass_context -@click.option( - '--widget-path', - '-p', - 'widget_paths', - help='Paths to be combined with PYQTDESIGNERPATH', - type=click.Path(exists=True, file_okay=False, resolve_path=True), - multiple=True, -) -@click.option( - '--example-widget-path', - help='Include the path for the pyqt5-tools example button ({})'.format( - example_path, - ), - is_flag=True, -) -@click.option( - '--designer-help', - help='Pass through to get Designer\'s --help', - is_flag=True, -) -@click.option( - '--test-exception-dialog', - help='Raise an exception to check the exception dialog functionality.', - is_flag=True, -) -@qt_debug_plugins_option -def pyqt5designer( - ctx, - widget_paths, - designer_help, - example_widget_path, - test_exception_dialog, - qt_debug_plugins -): - env = create_env(os.environ) - - extras = [] - widget_paths = list(widget_paths) - - if designer_help: - extras.append('--help') - - if example_widget_path: - widget_paths.append(example_path) - - 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=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) - - command = [ - str(bin / maybe_extension('designer')), - *extras, - *ctx.args, - ] - - return subprocess.call(command, env=env) - - -qml2_import_path_option = click.option( - '--qml2-import-path', - '-p', - 'qml2_import_paths', - help='Paths to be combined with QML2_IMPORT_PATH', - type=click.Path(exists=True, file_okay=False, resolve_path=True), - multiple=True, -) - - -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, - 'allow_extra_args': True, - }, -) -@click.pass_context -@qml2_import_path_option -@click.option( - '--qmlscene-help', - help='Pass through to get QML scene\'s --help', - is_flag=True, -) -@qt_debug_plugins_option -@click.option( - '--run-qml-example', - help='Run the pyqt5-tools QML example', - is_flag=True, -) -def pyqt5qmlscene( - ctx, - qml2_import_paths, - qmlscene_help, - qt_debug_plugins, - run_qml_example, -): - env = 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' - )) - - mutate_qml_path(env, paths=qml2_import_paths) - mutate_env_for_paths(env) - - 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) - - command = [ - str(bin / maybe_extension('qmlscene')), - *extras, - *ctx.args, - ] - - return subprocess.call(command, env=env) - - -@click.command( - context_settings={ - 'ignore_unknown_options': True, - 'allow_extra_args': True, - }, -) -@click.pass_context -@qml2_import_path_option -@click.option( - '--qmltestrunner-help', - help='Pass through to get QML test runner\'s --help', - is_flag=True, -) -@qt_debug_plugins_option -@click.option( - '--test-qml-example', - help='Test the pyqt5-tools QML example', - is_flag=True, -) -def pyqt5qmltestrunner( - ctx, - qml2_import_paths, - qmltestrunner_help, - qt_debug_plugins, - test_qml_example, -): - env = create_env(os.environ) - extras = [] - - if qmltestrunner_help: - extras.append('--help') - - if test_qml_example: - qml2_import_paths = qml2_import_paths + (fspath(here),) - extras.extend([ - '-input', - fspath( - pathlib.Path(pyqt5_tools.examples.__file__).parent/'qmltest.qml' - ), - ]) - - mutate_qml_path(env, paths=qml2_import_paths) - mutate_env_for_paths(env) - - 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) - - command = [ - str(bin / maybe_extension('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/tests/test_entrypoints.py b/src/pyqt5_tools/tests/test_entrypoints.py deleted file mode 100644 index d7ebfe2ad..000000000 --- a/src/pyqt5_tools/tests/test_entrypoints.py +++ /dev/null @@ -1,156 +0,0 @@ -import os -import pathlib -import subprocess -import sys - -import pytest - -import pyqt5_tools.entrypoints -import pyqt5_tools.tests.testbutton -import pyqt5_tools.tests.testbuttonplugin -import pyqt5_tools.examples.exampleqmlitem - - -fspath = getattr(os, 'fspath', str) - - -def test_designer_creates_test_widget(tmp_path): - env = dict(os.environ) - file_path = tmp_path/'tigger' - env[pyqt5_tools.tests.testbutton.test_path_env_var] = fspath(file_path) - - widget_plugin_path = pathlib.Path( - pyqt5_tools.tests.testbuttonplugin.__file__, - ).parent - - with pytest.raises(subprocess.TimeoutExpired): - subprocess.run( - [ - fspath( - pathlib.Path(sys.executable).with_name('pyqt5designer'), - ), - '--widget-path', fspath(widget_plugin_path), - '--qt-debug-plugins', - ], - check=True, - env=env, - timeout=90, - ) - - assert ( - file_path.read_bytes() - == pyqt5_tools.tests.testbutton.test_file_contents - ) - - -def test_qmlscene_paints_test_item(tmp_path): - env = dict(os.environ) - file_path = tmp_path/'eeyore' - env[pyqt5_tools.examples.exampleqmlitem.test_path_env_var] = fspath(file_path) - - with pytest.raises(subprocess.TimeoutExpired): - subprocess.run( - [ - fspath( - pathlib.Path(sys.executable).with_name('pyqt5qmlscene'), - ), - '--run-qml-example', - '--qt-debug-plugins', - ], - check=True, - env=env, - timeout=10, - ) - - assert ( - file_path.read_bytes() - == pyqt5_tools.examples.exampleqmlitem.test_file_contents - ) - - -def test_qmltestrunner_paints_test_item(tmp_path): - env = dict(os.environ) - file_path = tmp_path/'piglet' - env[pyqt5_tools.examples.exampleqmlitem.test_path_env_var] = fspath(file_path) - - subprocess.run( - [ - fspath( - pathlib.Path(sys.executable).with_name('pyqt5qmltestrunner'), - ), - '--test-qml-example', - '--qt-debug-plugins', - ], - check=True, - env=env, - timeout=10, - ) - - assert ( - file_path.read_bytes() - == pyqt5_tools.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/src/pyqt5_tools/__init__.py b/src/pyqtwrappers/__init__.py similarity index 100% rename from src/pyqt5_tools/__init__.py rename to src/pyqtwrappers/__init__.py diff --git a/src/pyqtwrappers/_version.py b/src/pyqtwrappers/_version.py new file mode 100644 index 000000000..264dc4fd0 --- /dev/null +++ b/src/pyqtwrappers/_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/pyqtwrappers/_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/badplugin/__init__.py b/src/pyqtwrappers/badplugin/__init__.py similarity index 100% rename from src/pyqt5_tools/badplugin/__init__.py rename to src/pyqtwrappers/badplugin/__init__.py diff --git a/src/pyqt5_tools/badplugin/badwidgetplugin.py b/src/pyqtwrappers/badplugin/badwidgetplugin.py similarity index 100% rename from src/pyqt5_tools/badplugin/badwidgetplugin.py rename to src/pyqtwrappers/badplugin/badwidgetplugin.py diff --git a/src/pyqtwrappers/entrypoints.py b/src/pyqtwrappers/entrypoints.py new file mode 100644 index 000000000..3c322914e --- /dev/null +++ b/src/pyqtwrappers/entrypoints.py @@ -0,0 +1,254 @@ +import os +import pathlib +import shutil +import subprocess +import sys + +import click +import qttools + +import pyqtplugins.utilities +import pyqtplugins.badplugin +import pyqtplugins.examplebuttonplugin +import pyqtplugins.examples +import pyqtplugins.examples.exampleqmlitem +import pyqtplugins.tests.testbutton + + +here = pathlib.Path(__file__).parent +bin = here/'Qt'/'bin' +example_path = str( + pathlib.Path(pyqtplugins.examplebuttonplugin.__file__).parent, +) +bad_path = str( + pathlib.Path(pyqtplugins.badplugin.__file__).parent, +) + +maybe_extension = { + 'linux': lambda name: name, + 'win32': lambda name: '{}.exe'.format(name), + 'darwin': lambda name: name, +}[sys.platform] + + +def pyqttoolsinstalluic(): + destination = bin/'bin' + destination.mkdir(parents=True, exist_ok=True) + there = pathlib.Path(sys.executable).parent + + shutil.copy( + src=str(there / maybe_extension('pyuic5')), + dst=str(destination/maybe_extension('uic')), + ) + + +qt_debug_plugins_option = click.option( + '--qt-debug-plugins/--no-qt-debug-plugins', + help='Set QT_DEBUG_PLUGINS=1', +) + + +@click.command( + context_settings={ + 'ignore_unknown_options': True, + 'allow_extra_args': True, + }, +) +@click.pass_context +@click.option( + '--widget-path', + '-p', + 'widget_paths', + help='Paths to be combined with PYQTDESIGNERPATH', + type=click.Path(exists=True, file_okay=False, resolve_path=True), + multiple=True, +) +@click.option( + '--example-widget-path', + help='Include the path for the pyqt5-tools example button ({})'.format( + example_path, + ), + is_flag=True, +) +@click.option( + '--designer-help', + help='Pass through to get Designer\'s --help', + is_flag=True, +) +@click.option( + '--test-exception-dialog', + help='Raise an exception to check the exception dialog functionality.', + is_flag=True, +) +@qt_debug_plugins_option +def pyqtdesigner( + ctx, + widget_paths, + designer_help, + example_widget_path, + test_exception_dialog, + qt_debug_plugins +): + env = pyqtplugins.utilities.create_env(reference=os.environ) + + extras = [] + widget_paths = list(widget_paths) + + if designer_help: + extras.append('--help') + + if example_widget_path: + widget_paths.append(example_path) + + if test_exception_dialog: + widget_paths.append(bad_path) + + env.update(pyqtplugins.utilities.add_to_env_var_path_list( + env=env, + name='PYQTDESIGNERPATH', + before=widget_paths, + after=[''], + )) + + if qt_debug_plugins: + env['QT_DEBUG_PLUGINS'] = '1' + + pyqtplugins.utilities.print_environment_variables( + env, + *pyqtplugins.utilities.diagnostic_variables_to_print, + ) + + command = [ + pyqtplugins.utilities.fspath(qttools.application_path('designer')), + *extras, + *ctx.args, + ] + + return subprocess.call(command, env=env) + + +qml2_import_path_option = click.option( + '--qml2-import-path', + '-p', + 'qml2_import_paths', + help='Paths to be combined with QML2_IMPORT_PATH', + type=click.Path(exists=True, file_okay=False, resolve_path=True), + multiple=True, +) + + +@click.command( + context_settings={ + 'ignore_unknown_options': True, + 'allow_extra_args': True, + }, +) +@click.pass_context +@qml2_import_path_option +@click.option( + '--qmlscene-help', + help='Pass through to get QML scene\'s --help', + is_flag=True, +) +@qt_debug_plugins_option +@click.option( + '--run-qml-example', + help='Run the pyqt5-tools QML example', + is_flag=True, +) +def pyqtqmlscene( + ctx, + qml2_import_paths, + qmlscene_help, + qt_debug_plugins, + run_qml_example, +): + env = pyqtplugins.utilities.create_env(os.environ) + extras = [] + + if qmlscene_help: + extras.append('--help') + + if run_qml_example: + qml2_import_paths = qml2_import_paths + (pyqtplugins.utilities.fspath(here),) + extras.append(pyqtplugins.utilities.fspath( + pathlib.Path(pyqtplugins.examples.__file__).parent / 'qmlapp.qml' + )) + + pyqtplugins.utilities.mutate_qml_path(env, paths=qml2_import_paths) + + if qt_debug_plugins: + env['QT_DEBUG_PLUGINS'] = '1' + + pyqtplugins.utilities.print_environment_variables( + env, + *pyqtplugins.utilities.diagnostic_variables_to_print, + ) + + command = [ + pyqtplugins.utilities.fspath(qttools.application_path('qmlscene')), + *extras, + *ctx.args, + ] + + return subprocess.call(command, env=env) + + +@click.command( + context_settings={ + 'ignore_unknown_options': True, + 'allow_extra_args': True, + }, +) +@click.pass_context +@qml2_import_path_option +@click.option( + '--qmltestrunner-help', + help='Pass through to get QML test runner\'s --help', + is_flag=True, +) +@qt_debug_plugins_option +@click.option( + '--test-qml-example', + help='Test the pyqt5-tools QML example', + is_flag=True, +) +def pyqtqmltestrunner( + ctx, + qml2_import_paths, + qmltestrunner_help, + qt_debug_plugins, + test_qml_example, +): + env = pyqtplugins.utilities.create_env(os.environ) + extras = [] + + if qmltestrunner_help: + extras.append('--help') + + if test_qml_example: + qml2_import_paths = qml2_import_paths + (pyqtplugins.utilities.fspath(here),) + extras.extend([ + '-input', + pyqtplugins.utilities.fspath( + pathlib.Path(pyqtplugins.examples.__file__).parent / 'qmltest.qml' + ), + ]) + + pyqtplugins.utilities.mutate_qml_path(env, paths=qml2_import_paths) + + if qt_debug_plugins: + env['QT_DEBUG_PLUGINS'] = '1' + + pyqtplugins.utilities.print_environment_variables( + env, + *pyqtplugins.utilities.diagnostic_variables_to_print, + ) + + command = [ + pyqtplugins.utilities.fspath(qttools.application_path('qmltestrunner')), + *extras, + *ctx.args, + ] + + return subprocess.call(command, env=env) diff --git a/src/pyqt5_tools/examples/__init__.py b/src/pyqtwrappers/examples/__init__.py similarity index 100% rename from src/pyqt5_tools/examples/__init__.py rename to src/pyqtwrappers/examples/__init__.py diff --git a/src/pyqt5_tools/examples/exampleqmlitem.py b/src/pyqtwrappers/examples/exampleqmlitem.py similarity index 100% rename from src/pyqt5_tools/examples/exampleqmlitem.py rename to src/pyqtwrappers/examples/exampleqmlitem.py diff --git a/src/pyqt5_tools/examples/exampleqmlitemplugin.py b/src/pyqtwrappers/examples/exampleqmlitemplugin.py similarity index 90% rename from src/pyqt5_tools/examples/exampleqmlitemplugin.py rename to src/pyqtwrappers/examples/exampleqmlitemplugin.py index dc6badd92..f871c5f74 100644 --- a/src/pyqt5_tools/examples/exampleqmlitemplugin.py +++ b/src/pyqtwrappers/examples/exampleqmlitemplugin.py @@ -8,8 +8,8 @@ sys.stderr.write('exampleqmlitemplugin.py debug: : just imported QtQml\n') sys.stderr.flush() -import pyqt5_tools.examples.exampleqmlitem -sys.stderr.write('exampleqmlitemplugin.py debug: : just imported pyqt5_tools.examples.exampleqmlitem\n') +import pyqtplugins.examples.exampleqmlitem +sys.stderr.write('exampleqmlitemplugin.py debug: : just imported pyqtplugins.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, + pyqtplugins.examples.exampleqmlitem.ExampleQmlItem, 'examples', 1, 0, diff --git a/src/pyqt5_tools/examples/qmlapp.qml b/src/pyqtwrappers/examples/qmlapp.qml similarity index 100% rename from src/pyqt5_tools/examples/qmlapp.qml rename to src/pyqtwrappers/examples/qmlapp.qml diff --git a/src/pyqt5_tools/examples/qmldir b/src/pyqtwrappers/examples/qmldir similarity index 100% rename from src/pyqt5_tools/examples/qmldir rename to src/pyqtwrappers/examples/qmldir diff --git a/src/pyqt5_tools/examples/qmltest.qml b/src/pyqtwrappers/examples/qmltest.qml similarity index 100% rename from src/pyqt5_tools/examples/qmltest.qml rename to src/pyqtwrappers/examples/qmltest.qml diff --git a/src/pyqt5_tools/tests/__init__.py b/src/pyqtwrappers/tests/__init__.py similarity index 100% rename from src/pyqt5_tools/tests/__init__.py rename to src/pyqtwrappers/tests/__init__.py diff --git a/src/pyqtwrappers/tests/test_entrypoints.py b/src/pyqtwrappers/tests/test_entrypoints.py new file mode 100644 index 000000000..0a31b1dd9 --- /dev/null +++ b/src/pyqtwrappers/tests/test_entrypoints.py @@ -0,0 +1,119 @@ +import os +import pathlib +import subprocess + +import pytest +import qttools + +import pyqtplugins.entrypoints +import pyqtplugins.examples.exampleqmlitem +import pyqtplugins.tests.testbutton +import pyqtplugins.tests.testbuttonplugin +import pyqtplugins.utilities + + +fspath = getattr(os, 'fspath', str) + + +vars_to_print = [ + *pyqtplugins.utilities.diagnostic_variables_to_print, + pyqtplugins.examples.exampleqmlitem.test_path_env_var, + pyqtplugins.tests.testbutton.test_path_env_var, +] + + +@pytest.fixture(name='environment') +def environment_fixture(): + environment = pyqtplugins.utilities.create_env(os.environ) + pyqtplugins.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' + environment[pyqtplugins.tests.testbutton.test_path_env_var] = fspath(file_path) + + widget_plugin_path = pathlib.Path( + pyqtplugins.tests.testbuttonplugin.__file__, + ).parent + + environment.update(pyqtplugins.utilities.add_to_env_var_path_list( + env=environment, + name='PYQTDESIGNERPATH', + before=[fspath(widget_plugin_path)], + after=[''], + )) + + pyqtplugins.utilities.print_environment_variables(environment, *vars_to_print) + + with pytest.raises(subprocess.TimeoutExpired): + subprocess.run( + [fspath(qttools.application_path('designer'))], + check=True, + env=environment, + timeout=20, + ) + + assert ( + file_path.read_bytes() + == pyqtplugins.tests.testbutton.test_file_contents + ) + + +qml2_import_paths = (pyqtplugins.utilities.fspath(pyqtplugins.root),) + + +def test_qmlscene_paints_test_item(tmp_path, environment): + file_path = tmp_path/'eeyore' + environment[pyqtplugins.examples.exampleqmlitem.test_path_env_var] = fspath(file_path) + + qml_example_path = pyqtplugins.utilities.fspath( + pathlib.Path(pyqtplugins.examples.__file__).parent / 'qmlapp.qml' + ) + + pyqtplugins.utilities.print_environment_variables(environment, *vars_to_print) + + with pytest.raises(subprocess.TimeoutExpired): + subprocess.run( + [ + fspath(qttools.application_path('qmlscene')), + fspath(qml_example_path), + ], + check=True, + env=environment, + timeout=20, + ) + + assert ( + file_path.read_bytes() + == pyqtplugins.examples.exampleqmlitem.test_file_contents + ) + + +def test_qmltestrunner_paints_test_item(tmp_path, environment): + file_path = tmp_path/'piglet' + environment[pyqtplugins.examples.exampleqmlitem.test_path_env_var] = fspath(file_path) + + qml_test_path = pyqtplugins.utilities.fspath( + pathlib.Path(pyqtplugins.examples.__file__).parent / 'qmltest.qml' + ) + + pyqtplugins.utilities.print_environment_variables(environment, *vars_to_print) + + subprocess.run( + [ + fspath(qttools.application_path('qmltestrunner')), + '-input', + qml_test_path, + ], + check=True, + env=environment, + timeout=20, + ) + + assert ( + file_path.read_bytes() + == pyqtplugins.examples.exampleqmlitem.test_file_contents + ) diff --git a/tox.ini b/tox.ini index 99796bd92..200a75c4c 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= @@ -11,4 +11,4 @@ deps= commands= {envbindir}/pip freeze {envbindir}/python -c 'import PyQt5.sip; print(PyQt5.sip)' - {envbindir}/pytest --capture=no pyqt5_tools.tests --pyargs + {envbindir}/pytest --capture=no pyqtplugins.tests --pyargs